summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ldpd/address.c175
-rw-r--r--ldpd/control.c14
-rw-r--r--ldpd/init.c283
-rw-r--r--ldpd/l2vpn.c111
-rw-r--r--ldpd/labelmapping.c319
-rw-r--r--ldpd/lde.c207
-rw-r--r--ldpd/lde.h28
-rw-r--r--ldpd/lde_lib.c138
-rw-r--r--ldpd/ldp.h41
-rw-r--r--ldpd/ldp_debug.h8
-rw-r--r--ldpd/ldp_zebra.c2
-rw-r--r--ldpd/ldpd.h16
-rw-r--r--ldpd/ldpe.c50
-rw-r--r--ldpd/ldpe.h13
-rw-r--r--ldpd/log.c37
-rw-r--r--ldpd/neighbor.c1
-rw-r--r--ldpd/notification.c134
-rw-r--r--ldpd/packet.c19
-rw-r--r--ldpd/pfkey.c8
19 files changed, 1304 insertions, 300 deletions
diff --git a/ldpd/address.c b/ldpd/address.c
index 1c4c116f21..ad23ca690b 100644
--- a/ldpd/address.c
+++ b/ldpd/address.c
@@ -26,10 +26,14 @@
static void send_address(struct nbr *, int, struct if_addr_head *,
unsigned int, int);
-static int gen_address_list_tlv(struct ibuf *, uint16_t, int,
- struct if_addr_head *, unsigned int);
+static int gen_address_list_tlv(struct ibuf *, int, struct if_addr_head *,
+ unsigned int);
+static int gen_mac_list_tlv(struct ibuf *, uint8_t *);
static void address_list_add(struct if_addr_head *, struct if_addr *);
static void address_list_clr(struct if_addr_head *);
+static void log_msg_address(int, uint16_t, struct nbr *, int,
+ union ldpd_addr *);
+static void log_msg_mac_withdrawal(int, struct nbr *, uint8_t *);
static void
send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
@@ -83,8 +87,7 @@ send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
size -= LDP_HDR_SIZE;
err |= gen_msg_hdr(buf, msg_type, size);
size -= LDP_MSG_SIZE;
- err |= gen_address_list_tlv(buf, size, af, addr_list,
- tlv_addr_count);
+ err |= gen_address_list_tlv(buf, af, addr_list, tlv_addr_count);
if (err) {
address_list_clr(addr_list);
ibuf_free(buf);
@@ -92,9 +95,7 @@ send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
}
while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
- debug_msg_send("%s: lsr-id %s address %s",
- msg_name(msg_type), inet_ntoa(nbr->id),
- log_addr(af, &if_addr->addr));
+ log_msg_address(1, msg_type, nbr, af, &if_addr->addr);
LIST_REMOVE(if_addr, entry);
free(if_addr);
@@ -137,16 +138,63 @@ send_address_all(struct nbr *nbr, int af)
send_address(nbr, af, &addr_list, addr_count, 0);
}
+void
+send_mac_withdrawal(struct nbr *nbr, struct map *fec, uint8_t *mac)
+{
+ struct ibuf *buf;
+ uint16_t size;
+ int err;
+
+ size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE + len_fec_tlv(fec) +
+ TLV_HDR_SIZE;
+ if (mac)
+ size += ETHER_ADDR_LEN;
+
+ if ((buf = ibuf_open(size)) == NULL)
+ fatal(__func__);
+
+ err = gen_ldp_hdr(buf, size);
+ size -= LDP_HDR_SIZE;
+ err |= gen_msg_hdr(buf, MSG_TYPE_ADDRWITHDRAW, size);
+ size -= LDP_MSG_SIZE;
+ err |= gen_address_list_tlv(buf, AF_INET, NULL, 0);
+ err |= gen_fec_tlv(buf, fec);
+ err |= gen_mac_list_tlv(buf, mac);
+ if (err) {
+ ibuf_free(buf);
+ return;
+ }
+
+ log_msg_mac_withdrawal(1, nbr, mac);
+
+ evbuf_enqueue(&nbr->tcp->wbuf, buf);
+
+ nbr_fsm(nbr, NBR_EVT_PDU_SENT);
+}
+
int
recv_address(struct nbr *nbr, char *buf, uint16_t len)
{
struct ldp_msg msg;
uint16_t msg_type;
- struct address_list_tlv alt;
enum imsg_type type;
+ struct address_list_tlv alt;
+ uint16_t alt_len;
+ uint16_t alt_family;
struct lde_addr lde_addr;
memcpy(&msg, buf, sizeof(msg));
+ msg_type = ntohs(msg.type);
+ switch (msg_type) {
+ case MSG_TYPE_ADDR:
+ type = IMSG_ADDRESS_ADD;
+ break;
+ case MSG_TYPE_ADDRWITHDRAW:
+ type = IMSG_ADDRESS_DEL;
+ break;
+ default:
+ fatalx("recv_address: unexpected msg type");
+ }
buf += LDP_MSG_SIZE;
len -= LDP_MSG_SIZE;
@@ -155,17 +203,18 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
return (-1);
}
-
memcpy(&alt, buf, sizeof(alt));
- if (ntohs(alt.length) != len - TLV_HDR_SIZE) {
+ alt_len = ntohs(alt.length);
+ alt_family = ntohs(alt.family);
+ if (alt_len > len - TLV_HDR_SIZE) {
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
return (-1);
}
if (ntohs(alt.type) != TLV_TYPE_ADDRLIST) {
- session_shutdown(nbr, S_UNKNOWN_TLV, msg.id, msg.type);
+ send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
return (-1);
}
- switch (ntohs(alt.family)) {
+ switch (alt_family) {
case AF_IPV4:
if (!nbr->v4_enabled)
/* just ignore the message */
@@ -177,22 +226,18 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
return (0);
break;
default:
- send_notification_nbr(nbr, S_UNSUP_ADDR, msg.id, msg.type);
+ send_notification(nbr->tcp, S_UNSUP_ADDR, msg.id, msg.type);
return (-1);
}
+ alt_len -= sizeof(alt.family);
buf += sizeof(alt);
len -= sizeof(alt);
- msg_type = ntohs(msg.type);
- if (msg_type == MSG_TYPE_ADDR)
- type = IMSG_ADDRESS_ADD;
- else
- type = IMSG_ADDRESS_DEL;
-
- while (len > 0) {
- switch (ntohs(alt.family)) {
+ /* Process all received addresses */
+ while (alt_len > 0) {
+ switch (alt_family) {
case AF_IPV4:
- if (len < sizeof(struct in_addr)) {
+ if (alt_len < sizeof(struct in_addr)) {
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
msg.type);
return (-1);
@@ -204,9 +249,10 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
buf += sizeof(struct in_addr);
len -= sizeof(struct in_addr);
+ alt_len -= sizeof(struct in_addr);
break;
case AF_IPV6:
- if (len < sizeof(struct in6_addr)) {
+ if (alt_len < sizeof(struct in6_addr)) {
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
msg.type);
return (-1);
@@ -218,24 +264,57 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
buf += sizeof(struct in6_addr);
len -= sizeof(struct in6_addr);
+ alt_len -= sizeof(struct in6_addr);
break;
default:
fatalx("recv_address: unknown af");
}
- debug_msg_recv("%s: lsr-id %s address %s", msg_name(msg_type),
- inet_ntoa(nbr->id), log_addr(lde_addr.af, &lde_addr.addr));
+ log_msg_address(0, msg_type, nbr, lde_addr.af, &lde_addr.addr);
ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr,
sizeof(lde_addr));
}
+ /* Optional Parameters */
+ while (len > 0) {
+ struct tlv tlv;
+ uint16_t tlv_type;
+ uint16_t tlv_len;
+
+ if (len < sizeof(tlv)) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+ return (-1);
+ }
+
+ memcpy(&tlv, buf, TLV_HDR_SIZE);
+ tlv_type = ntohs(tlv.type);
+ tlv_len = ntohs(tlv.length);
+ if (tlv_len + TLV_HDR_SIZE > len) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+ return (-1);
+ }
+ buf += TLV_HDR_SIZE;
+ len -= TLV_HDR_SIZE;
+
+ switch (tlv_type) {
+ default:
+ if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
+ send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
+ msg.id, msg.type, tlv_type, tlv_len, buf);
+ /* ignore unknown tlv */
+ break;
+ }
+ buf += tlv_len;
+ len -= tlv_len;
+ }
+
return (0);
}
static int
-gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
- struct if_addr_head *addr_list, unsigned int tlv_addr_count)
+gen_address_list_tlv(struct ibuf *buf, int af, struct if_addr_head *addr_list,
+ unsigned int tlv_addr_count)
{
struct address_list_tlv alt;
uint16_t addr_size;
@@ -243,8 +322,7 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
int err = 0;
memset(&alt, 0, sizeof(alt));
- alt.type = TLV_TYPE_ADDRLIST;
- alt.length = htons(size - TLV_HDR_SIZE);
+ alt.type = htons(TLV_TYPE_ADDRLIST);
switch (af) {
case AF_INET:
@@ -258,8 +336,12 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
default:
fatalx("gen_address_list_tlv: unknown af");
}
+ alt.length = htons(sizeof(alt.family) + addr_size * tlv_addr_count);
err |= ibuf_add(buf, &alt, sizeof(alt));
+ if (addr_list == NULL)
+ return (err);
+
LIST_FOREACH(if_addr, addr_list, entry) {
err |= ibuf_add(buf, &if_addr->addr, addr_size);
if (--tlv_addr_count == 0)
@@ -269,6 +351,23 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
return (err);
}
+static int
+gen_mac_list_tlv(struct ibuf *buf, uint8_t *mac)
+{
+ struct tlv tlv;
+ int err;
+
+ memset(&tlv, 0, sizeof(tlv));
+ tlv.type = htons(TLV_TYPE_MAC_LIST);
+ if (mac)
+ tlv.length = htons(ETHER_ADDR_LEN);
+ err = ibuf_add(buf, &tlv, sizeof(tlv));
+ if (mac)
+ err |= ibuf_add(buf, mac, ETHER_ADDR_LEN);
+
+ return (err);
+}
+
static void
address_list_add(struct if_addr_head *addr_list, struct if_addr *if_addr)
{
@@ -292,3 +391,21 @@ address_list_clr(struct if_addr_head *addr_list)
free(if_addr);
}
}
+
+static void
+log_msg_address(int out, uint16_t msg_type, struct nbr *nbr, int af,
+ union ldpd_addr *addr)
+{
+ debug_msg(out, "%s: lsr-id %s, address %s", msg_name(msg_type),
+ inet_ntoa(nbr->id), log_addr(af, addr));
+}
+
+static void
+log_msg_mac_withdrawal(int out, struct nbr *nbr, uint8_t *mac)
+{
+ char buf[ETHER_ADDR_STRLEN];
+
+ debug_msg(out, "mac withdrawal: lsr-id %s, mac %s", inet_ntoa(nbr->id),
+ (mac) ? prefix_mac2str((struct ethaddr *)mac, buf, sizeof(buf)) :
+ "wildcard");
+}
diff --git a/ldpd/control.c b/ldpd/control.c
index 8a2280be07..0bfe0abc9d 100644
--- a/ldpd/control.c
+++ b/ldpd/control.c
@@ -148,9 +148,10 @@ control_connbyfd(int fd)
{
struct ctl_conn *c;
- for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd;
- c = TAILQ_NEXT(c, entry))
- ; /* nothing */
+ TAILQ_FOREACH(c, &ctl_conns, entry) {
+ if (c->iev.ibuf.fd == fd)
+ break;
+ }
return (c);
}
@@ -160,9 +161,10 @@ control_connbypid(pid_t pid)
{
struct ctl_conn *c;
- for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.pid != pid;
- c = TAILQ_NEXT(c, entry))
- ; /* nothing */
+ TAILQ_FOREACH(c, &ctl_conns, entry) {
+ if (c->iev.ibuf.pid == pid)
+ break;
+ }
return (c);
}
diff --git a/ldpd/init.c b/ldpd/init.c
index ed6b53c02d..bc3a69edc7 100644
--- a/ldpd/init.c
+++ b/ldpd/init.c
@@ -24,6 +24,9 @@
#include "ldp_debug.h"
static int gen_init_prms_tlv(struct ibuf *, struct nbr *);
+static int gen_cap_dynamic_tlv(struct ibuf *);
+static int gen_cap_twcard_tlv(struct ibuf *, int);
+static int gen_cap_unotif_tlv(struct ibuf *, int);
void
send_init(struct nbr *nbr)
@@ -34,15 +37,18 @@ send_init(struct nbr *nbr)
debug_msg_send("initialization: lsr-id %s", inet_ntoa(nbr->id));
- size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE;
+ size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE +
+ CAP_TLV_DYNAMIC_SIZE + CAP_TLV_TWCARD_SIZE + CAP_TLV_UNOTIF_SIZE;
if ((buf = ibuf_open(size)) == NULL)
fatal(__func__);
err |= gen_ldp_hdr(buf, size);
size -= LDP_HDR_SIZE;
err |= gen_msg_hdr(buf, MSG_TYPE_INIT, size);
- size -= LDP_MSG_SIZE;
err |= gen_init_prms_tlv(buf, nbr);
+ err |= gen_cap_dynamic_tlv(buf);
+ err |= gen_cap_twcard_tlv(buf, 1);
+ err |= gen_cap_unotif_tlv(buf, 1);
if (err) {
ibuf_free(buf);
return;
@@ -57,6 +63,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
struct ldp_msg msg;
struct sess_prms_tlv sess;
uint16_t max_pdu_len;
+ int caps_rcvd = 0;
debug_msg_recv("initialization: lsr-id %s", inet_ntoa(nbr->id));
@@ -93,6 +100,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
/* Optional Parameters */
while (len > 0) {
struct tlv tlv;
+ uint16_t tlv_type;
uint16_t tlv_len;
if (len < sizeof(tlv)) {
@@ -101,6 +109,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
}
memcpy(&tlv, buf, TLV_HDR_SIZE);
+ tlv_type = ntohs(tlv.type);
tlv_len = ntohs(tlv.length);
if (tlv_len + TLV_HDR_SIZE > len) {
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
@@ -109,17 +118,81 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
buf += TLV_HDR_SIZE;
len -= TLV_HDR_SIZE;
- switch (ntohs(tlv.type)) {
+ /*
+ * RFC 5561 - Section 6:
+ * "The S-bit of a Capability Parameter in an Initialization
+ * message MUST be 1 and SHOULD be ignored on receipt".
+ */
+ switch (tlv_type) {
case TLV_TYPE_ATMSESSIONPAR:
session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
return (-1);
case TLV_TYPE_FRSESSION:
session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
return (-1);
+ case TLV_TYPE_DYNAMIC_CAP:
+ if (tlv_len != CAP_TLV_DYNAMIC_LEN) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
+ msg.type);
+ return (-1);
+ }
+
+ if (caps_rcvd & F_CAP_TLV_RCVD_DYNAMIC) {
+ session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
+ msg.type);
+ return (-1);
+ }
+ caps_rcvd |= F_CAP_TLV_RCVD_DYNAMIC;
+
+ nbr->flags |= F_NBR_CAP_DYNAMIC;
+
+ log_debug("%s: lsr-id %s announced the Dynamic "
+ "Capability Announcement capability", __func__,
+ inet_ntoa(nbr->id));
+ break;
+ case TLV_TYPE_TWCARD_CAP:
+ if (tlv_len != CAP_TLV_TWCARD_LEN) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
+ msg.type);
+ return (-1);
+ }
+
+ if (caps_rcvd & F_CAP_TLV_RCVD_TWCARD) {
+ session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
+ msg.type);
+ return (-1);
+ }
+ caps_rcvd |= F_CAP_TLV_RCVD_TWCARD;
+
+ nbr->flags |= F_NBR_CAP_TWCARD;
+
+ log_debug("%s: lsr-id %s announced the Typed Wildcard "
+ "FEC capability", __func__, inet_ntoa(nbr->id));
+ break;
+ case TLV_TYPE_UNOTIF_CAP:
+ if (tlv_len != CAP_TLV_UNOTIF_LEN) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
+ msg.type);
+ return (-1);
+ }
+
+ if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) {
+ session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
+ msg.type);
+ return (-1);
+ }
+ caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF;
+
+ nbr->flags |= F_NBR_CAP_UNOTIF;
+
+ log_debug("%s: lsr-id %s announced the Unrecognized "
+ "Notification capability", __func__,
+ inet_ntoa(nbr->id));
+ break;
default:
if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
- send_notification_nbr(nbr, S_UNKNOWN_TLV,
- msg.id, msg.type);
+ send_notification_rtlvs(nbr, S_UNSSUPORTDCAP,
+ msg.id, msg.type, tlv_type, tlv_len, buf);
/* ignore unknown tlv */
break;
}
@@ -145,6 +218,164 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
return (0);
}
+void
+send_capability(struct nbr *nbr, uint16_t capability, int enable)
+{
+ struct ibuf *buf;
+ uint16_t size;
+ int err = 0;
+
+ log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
+
+ size = LDP_HDR_SIZE + LDP_MSG_SIZE + CAP_TLV_DYNAMIC_SIZE;
+ if ((buf = ibuf_open(size)) == NULL)
+ fatal(__func__);
+
+ err |= gen_ldp_hdr(buf, size);
+ size -= LDP_HDR_SIZE;
+ err |= gen_msg_hdr(buf, MSG_TYPE_CAPABILITY, size);
+
+ switch (capability) {
+ case TLV_TYPE_TWCARD_CAP:
+ err |= gen_cap_twcard_tlv(buf, enable);
+ break;
+ case TLV_TYPE_UNOTIF_CAP:
+ err |= gen_cap_unotif_tlv(buf, enable);
+ break;
+ case TLV_TYPE_DYNAMIC_CAP:
+ /*
+ * RFC 5561 - Section 9:
+ * "An LDP speaker MUST NOT include the Dynamic Capability
+ * Announcement Parameter in Capability messages sent to
+ * its peers".
+ */
+ /* FALLTHROUGH */
+ default:
+ fatalx("send_capability: unsupported capability");
+ }
+
+ if (err) {
+ ibuf_free(buf);
+ return;
+ }
+
+ evbuf_enqueue(&nbr->tcp->wbuf, buf);
+ nbr_fsm(nbr, NBR_EVT_PDU_SENT);
+}
+
+int
+recv_capability(struct nbr *nbr, char *buf, uint16_t len)
+{
+ struct ldp_msg msg;
+ int enable = 0;
+ int caps_rcvd = 0;
+
+ log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
+
+ memcpy(&msg, buf, sizeof(msg));
+ buf += LDP_MSG_SIZE;
+ len -= LDP_MSG_SIZE;
+
+ /* Optional Parameters */
+ while (len > 0) {
+ struct tlv tlv;
+ uint16_t tlv_type;
+ uint16_t tlv_len;
+ uint8_t reserved;
+
+ if (len < sizeof(tlv)) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+ return (-1);
+ }
+
+ memcpy(&tlv, buf, TLV_HDR_SIZE);
+ tlv_type = ntohs(tlv.type);
+ tlv_len = ntohs(tlv.length);
+ if (tlv_len + TLV_HDR_SIZE > len) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+ return (-1);
+ }
+ buf += TLV_HDR_SIZE;
+ len -= TLV_HDR_SIZE;
+
+ switch (tlv_type) {
+ case TLV_TYPE_TWCARD_CAP:
+ if (tlv_len != CAP_TLV_TWCARD_LEN) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
+ msg.type);
+ return (-1);
+ }
+
+ if (caps_rcvd & F_CAP_TLV_RCVD_TWCARD) {
+ session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
+ msg.type);
+ return (-1);
+ }
+ caps_rcvd |= F_CAP_TLV_RCVD_TWCARD;
+
+ memcpy(&reserved, buf, sizeof(reserved));
+ enable = reserved & STATE_BIT;
+ if (enable)
+ nbr->flags |= F_NBR_CAP_TWCARD;
+ else
+ nbr->flags &= ~F_NBR_CAP_TWCARD;
+
+ log_debug("%s: lsr-id %s %s the Typed Wildcard FEC "
+ "capability", __func__, inet_ntoa(nbr->id),
+ (enable) ? "announced" : "withdrew");
+ break;
+ case TLV_TYPE_UNOTIF_CAP:
+ if (tlv_len != CAP_TLV_UNOTIF_LEN) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
+ msg.type);
+ return (-1);
+ }
+
+ if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) {
+ session_shutdown(nbr, S_BAD_TLV_VAL, msg.id,
+ msg.type);
+ return (-1);
+ }
+ caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF;
+
+ memcpy(&reserved, buf, sizeof(reserved));
+ enable = reserved & STATE_BIT;
+ if (enable)
+ nbr->flags |= F_NBR_CAP_UNOTIF;
+ else
+ nbr->flags &= ~F_NBR_CAP_UNOTIF;
+
+ log_debug("%s: lsr-id %s %s the Unrecognized "
+ "Notification capability", __func__,
+ inet_ntoa(nbr->id), (enable) ? "announced" :
+ "withdrew");
+ break;
+ case TLV_TYPE_DYNAMIC_CAP:
+ /*
+ * RFC 5561 - Section 9:
+ * "An LDP speaker that receives a Capability message
+ * from a peer that includes the Dynamic Capability
+ * Announcement Parameter SHOULD silently ignore the
+ * parameter and process any other Capability Parameters
+ * in the message".
+ */
+ /* FALLTHROUGH */
+ default:
+ if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
+ send_notification_rtlvs(nbr, S_UNSSUPORTDCAP,
+ msg.id, msg.type, tlv_type, tlv_len, buf);
+ /* ignore unknown tlv */
+ break;
+ }
+ buf += tlv_len;
+ len -= tlv_len;
+ }
+
+ nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
+
+ return (0);
+}
+
static int
gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr)
{
@@ -163,3 +394,45 @@ gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr)
return (ibuf_add(buf, &parms, SESS_PRMS_SIZE));
}
+
+static int
+gen_cap_dynamic_tlv(struct ibuf *buf)
+{
+ struct capability_tlv cap;
+
+ memset(&cap, 0, sizeof(cap));
+ cap.type = htons(TLV_TYPE_DYNAMIC_CAP);
+ cap.length = htons(CAP_TLV_DYNAMIC_LEN);
+ /* the S-bit is always 1 for the Dynamic Capability Announcement */
+ cap.reserved = STATE_BIT;
+
+ return (ibuf_add(buf, &cap, CAP_TLV_DYNAMIC_SIZE));
+}
+
+static int
+gen_cap_twcard_tlv(struct ibuf *buf, int enable)
+{
+ struct capability_tlv cap;
+
+ memset(&cap, 0, sizeof(cap));
+ cap.type = htons(TLV_TYPE_TWCARD_CAP);
+ cap.length = htons(CAP_TLV_TWCARD_LEN);
+ if (enable)
+ cap.reserved = STATE_BIT;
+
+ return (ibuf_add(buf, &cap, CAP_TLV_TWCARD_SIZE));
+}
+
+static int
+gen_cap_unotif_tlv(struct ibuf *buf, int enable)
+{
+ struct capability_tlv cap;
+
+ memset(&cap, 0, sizeof(cap));
+ cap.type = htons(TLV_TYPE_UNOTIF_CAP);
+ cap.length = htons(CAP_TLV_UNOTIF_LEN);
+ if (enable)
+ cap.reserved = STATE_BIT;
+
+ return (ibuf_add(buf, &cap, CAP_TLV_UNOTIF_SIZE));
+}
diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c
index 792608d425..3f4e21e685 100644
--- a/ldpd/l2vpn.c
+++ b/ldpd/l2vpn.c
@@ -152,6 +152,33 @@ l2vpn_if_find_name(struct l2vpn *l2vpn, const char *ifname)
return (RB_FIND(l2vpn_if_head, &l2vpn->if_tree, &lif));
}
+void
+l2vpn_if_update(struct l2vpn_if *lif)
+{
+ struct l2vpn *l2vpn = lif->l2vpn;
+ struct l2vpn_pw *pw;
+ struct map fec;
+ struct nbr *nbr;
+
+ if ((lif->flags & IFF_UP) && (lif->flags & IFF_RUNNING))
+ return;
+
+ RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) {
+ nbr = nbr_find_ldpid(pw->lsr_id.s_addr);
+ if (nbr == NULL)
+ continue;
+
+ memset(&fec, 0, sizeof(fec));
+ fec.type = MAP_TYPE_PWID;
+ fec.fec.pwid.type = l2vpn->pw_type;
+ fec.fec.pwid.group_id = 0;
+ fec.flags |= F_MAP_PW_ID;
+ fec.fec.pwid.pwid = pw->pwid;
+
+ send_mac_withdrawal(nbr, &fec, lif->mac);
+ }
+}
+
static __inline int
l2vpn_pw_compare(struct l2vpn_pw *a, struct l2vpn_pw *b)
{
@@ -330,7 +357,7 @@ l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map)
st.status_code = S_WRONG_CBIT;
st.msg_id = map->msg_id;
st.msg_type = htons(MSG_TYPE_LABELMAPPING);
- lde_send_labelwithdraw(ln, fn, NO_LABEL, &st);
+ lde_send_labelwithdraw(ln, fn, NULL, &st);
pw->flags &= ~F_PW_CWORD;
lde_send_labelmapping(ln, fn, 1);
@@ -353,7 +380,7 @@ l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map)
}
void
-l2vpn_send_pw_status(uint32_t peerid, uint32_t status, struct fec *fec)
+l2vpn_send_pw_status(struct lde_nbr *ln, uint32_t status, struct fec *fec)
{
struct notify_msg nm;
@@ -364,8 +391,27 @@ l2vpn_send_pw_status(uint32_t peerid, uint32_t status, struct fec *fec)
lde_fec2map(fec, &nm.fec);
nm.flags |= F_NOTIF_FEC;
- lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0,
- &nm, sizeof(nm));
+ lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm,
+ sizeof(nm));
+}
+
+void
+l2vpn_send_pw_status_wcard(struct lde_nbr *ln, uint32_t status,
+ uint16_t pw_type, uint32_t group_id)
+{
+ struct notify_msg nm;
+
+ memset(&nm, 0, sizeof(nm));
+ nm.status_code = S_PW_STATUS;
+ nm.pw_status = status;
+ nm.flags |= F_NOTIF_PW_STATUS;
+ nm.fec.type = MAP_TYPE_PWID;
+ nm.fec.fec.pwid.type = pw_type;
+ nm.fec.fec.pwid.group_id = group_id;
+ nm.flags |= F_NOTIF_FEC;
+
+ lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm,
+ sizeof(nm));
}
void
@@ -376,9 +422,11 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
struct fec_nh *fnh;
struct l2vpn_pw *pw;
- /* TODO group wildcard */
- if (!(nm->fec.flags & F_MAP_PW_ID))
+ if (nm->fec.type == MAP_TYPE_TYPED_WCARD ||
+ !(nm->fec.flags & F_MAP_PW_ID)) {
+ l2vpn_recv_pw_status_wcard(ln, nm);
return;
+ }
lde_map2fec(&nm->fec, ln->id, &fec);
fn = (struct fec_node *)fec_find(&ft, &fec);
@@ -397,7 +445,6 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
/* remote status didn't change */
if (pw->remote_status == nm->pw_status)
return;
-
pw->remote_status = nm->pw_status;
if (l2vpn_pw_ok(pw, fnh))
@@ -406,6 +453,56 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
lde_send_delete_klabel(fn, fnh);
}
+/* RFC4447 PWid group wildcard */
+void
+l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm)
+{
+ struct fec *f;
+ struct fec_node *fn;
+ struct fec_nh *fnh;
+ struct l2vpn_pw *pw;
+ struct map *wcard = &nm->fec;
+
+ RB_FOREACH(f, fec_tree, &ft) {
+ fn = (struct fec_node *)f;
+ if (fn->fec.type != FEC_TYPE_PWID)
+ continue;
+
+ pw = (struct l2vpn_pw *) fn->data;
+ if (pw == NULL)
+ continue;
+
+ switch (wcard->type) {
+ case MAP_TYPE_TYPED_WCARD:
+ if (wcard->fec.twcard.u.pw_type != PW_TYPE_WILDCARD &&
+ wcard->fec.twcard.u.pw_type != fn->fec.u.pwid.type)
+ continue;
+ break;
+ case MAP_TYPE_PWID:
+ if (wcard->fec.pwid.type != fn->fec.u.pwid.type)
+ continue;
+ if (wcard->fec.pwid.group_id != pw->remote_group)
+ continue;
+ break;
+ }
+
+ fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id,
+ 0, 0);
+ if (fnh == NULL)
+ continue;
+
+ /* remote status didn't change */
+ if (pw->remote_status == nm->pw_status)
+ continue;
+ pw->remote_status = nm->pw_status;
+
+ if (l2vpn_pw_ok(pw, fnh))
+ lde_send_change_klabel(fn, fnh);
+ else
+ lde_send_delete_klabel(fn, fnh);
+ }
+}
+
void
l2vpn_sync_pws(int af, union ldpd_addr *addr)
{
diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c
index 62f2a620d2..e8ce7fbdf5 100644
--- a/ldpd/labelmapping.c
+++ b/ldpd/labelmapping.c
@@ -28,9 +28,8 @@
static void enqueue_pdu(struct nbr *, struct ibuf *, uint16_t);
static int gen_label_tlv(struct ibuf *, uint32_t);
-static int tlv_decode_label(struct nbr *, struct ldp_msg *, char *,
- uint16_t, uint32_t *);
static int gen_reqid_tlv(struct ibuf *, uint32_t);
+static void log_msg_mapping(int, uint16_t, struct nbr *, struct map *);
static void
enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size)
@@ -71,25 +70,8 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)
}
/* calculate size */
- msg_size = LDP_MSG_SIZE + TLV_HDR_SIZE;
- switch (me->map.type) {
- case MAP_TYPE_WILDCARD:
- msg_size += FEC_ELM_WCARD_LEN;
- break;
- case MAP_TYPE_PREFIX:
- msg_size += FEC_ELM_PREFIX_MIN_LEN +
- PREFIX_SIZE(me->map.fec.prefix.prefixlen);
- break;
- case MAP_TYPE_PWID:
- msg_size += FEC_PWID_ELM_MIN_LEN;
- if (me->map.flags & F_MAP_PW_ID)
- msg_size += PW_STATUS_TLV_LEN;
- if (me->map.flags & F_MAP_PW_IFMTU)
- msg_size += FEC_SUBTLV_IFMTU_SIZE;
- if (me->map.flags & F_MAP_PW_STATUS)
- msg_size += PW_STATUS_TLV_SIZE;
- break;
- }
+ msg_size = LDP_MSG_SIZE;
+ msg_size += len_fec_tlv(&me->map);
if (me->map.label != NO_LABEL)
msg_size += LABEL_TLV_SIZE;
if (me->map.flags & F_MAP_REQ_ID)
@@ -124,9 +106,7 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)
return;
}
- debug_msg_send("%s: lsr-id %s fec %s label %s", msg_name(type),
- inet_ntoa(nbr->id), log_map(&me->map),
- log_label(me->map.label));
+ log_msg_mapping(1, type, nbr, &me->map);
TAILQ_REMOVE(mh, me, entry);
free(me);
@@ -146,7 +126,8 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
uint32_t label = NO_LABEL, reqid = 0;
uint32_t pw_status = 0;
uint8_t flags = 0;
- int feclen, lbllen, tlen;
+ int feclen, tlen;
+ uint16_t current_tlv = 1;
struct mapping_entry *me;
struct mapping_head mh;
struct map map;
@@ -163,7 +144,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
memcpy(&ft, buf, sizeof(ft));
if (ntohs(ft.type) != TLV_TYPE_FEC) {
- send_notification_nbr(nbr, S_MISS_MSG, msg.id, msg.type);
+ send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
return (-1);
}
feclen = ntohs(ft.length);
@@ -187,9 +168,9 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
!(map.flags & F_MAP_PW_ID) &&
type != MSG_TYPE_LABELWITHDRAW &&
type != MSG_TYPE_LABELRELEASE) {
- send_notification_nbr(nbr, S_MISS_MSG, msg.id,
+ send_notification(nbr->tcp, S_MISS_MSG, msg.id,
msg.type);
- return (-1);
+ goto err;
}
/*
@@ -210,6 +191,24 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
}
/*
+ * RFC 5561 - Section 4:
+ * "An LDP implementation that supports the Typed Wildcard
+ * FEC Element MUST support its use in Label Request, Label
+ * Withdraw, and Label Release messages".
+ */
+ if (map.type == MAP_TYPE_TYPED_WCARD) {
+ switch (type) {
+ case MSG_TYPE_LABELMAPPING:
+ case MSG_TYPE_LABELABORTREQ:
+ session_shutdown(nbr, S_UNKNOWN_FEC, msg.id,
+ msg.type);
+ goto err;
+ default:
+ break;
+ }
+ }
+
+ /*
* LDP supports the use of multiple FEC Elements per
* FEC for the Label Mapping message only.
*/
@@ -226,19 +225,10 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
feclen -= tlen;
} while (feclen > 0);
- /* Mandatory Label TLV */
- if (type == MSG_TYPE_LABELMAPPING) {
- lbllen = tlv_decode_label(nbr, &msg, buf, len, &label);
- if (lbllen == -1)
- goto err;
-
- buf += lbllen;
- len -= lbllen;
- }
-
/* Optional Parameters */
while (len > 0) {
struct tlv tlv;
+ uint16_t tlv_type;
uint16_t tlv_len;
uint32_t reqbuf, labelbuf, statusbuf;
@@ -248,6 +238,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
}
memcpy(&tlv, buf, TLV_HDR_SIZE);
+ tlv_type = ntohs(tlv.type);
tlv_len = ntohs(tlv.length);
if (tlv_len + TLV_HDR_SIZE > len) {
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
@@ -256,7 +247,18 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
buf += TLV_HDR_SIZE;
len -= TLV_HDR_SIZE;
- switch (ntohs(tlv.type)) {
+ /*
+ * For Label Mapping messages the Label TLV is mandatory and
+ * should appear right after the FEC TLV.
+ */
+ if (current_tlv == 1 && type == MSG_TYPE_LABELMAPPING &&
+ !(tlv_type & TLV_TYPE_GENERICLABEL)) {
+ send_notification(nbr->tcp, S_MISS_MSG, msg.id,
+ msg.type);
+ goto err;
+ }
+
+ switch (tlv_type) {
case TLV_TYPE_LABELREQUEST:
switch (type) {
case MSG_TYPE_LABELMAPPING:
@@ -282,6 +284,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
break;
case TLV_TYPE_GENERICLABEL:
switch (type) {
+ case MSG_TYPE_LABELMAPPING:
case MSG_TYPE_LABELWITHDRAW:
case MSG_TYPE_LABELRELEASE:
if (tlv_len != LABEL_TLV_LEN) {
@@ -292,6 +295,16 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
memcpy(&labelbuf, buf, sizeof(labelbuf));
label = ntohl(labelbuf);
+ /* do not accept invalid labels */
+ if (label > MPLS_LABEL_MAX ||
+ (label <= MPLS_LABEL_RESERVED_MAX &&
+ label != MPLS_LABEL_IPV4NULL &&
+ label != MPLS_LABEL_IPV6NULL &&
+ label != MPLS_LABEL_IMPLNULL)) {
+ session_shutdown(nbr, S_BAD_TLV_VAL,
+ msg.id, msg.type);
+ goto err;
+ }
break;
default:
/* ignore */
@@ -301,6 +314,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
case TLV_TYPE_ATMLABEL:
case TLV_TYPE_FRLABEL:
switch (type) {
+ case MSG_TYPE_LABELMAPPING:
case MSG_TYPE_LABELWITHDRAW:
case MSG_TYPE_LABELRELEASE:
/* unsupported */
@@ -341,13 +355,14 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
break;
default:
if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
- send_notification_nbr(nbr, S_UNKNOWN_TLV,
- msg.id, msg.type);
+ send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
+ msg.id, msg.type, tlv_type, tlv_len, buf);
/* ignore unknown tlv */
break;
}
buf += tlv_len;
len -= tlv_len;
+ current_tlv++;
}
/* notify lde about the received message. */
@@ -396,9 +411,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
if (me->map.flags & F_MAP_REQ_ID)
me->map.requestid = reqid;
- debug_msg_recv("%s: lsr-id %s fec %s label %s", msg_name(type),
- inet_ntoa(nbr->id), log_map(&me->map),
- log_label(me->map.label));
+ log_msg_mapping(0, type, nbr, &me->map);
switch (type) {
case MSG_TYPE_LABELMAPPING:
@@ -423,14 +436,14 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map,
sizeof(struct map));
-next:
+ next:
TAILQ_REMOVE(&mh, me, entry);
free(me);
}
return (0);
-err:
+ err:
mapping_list_clr(&mh);
return (-1);
@@ -450,53 +463,6 @@ gen_label_tlv(struct ibuf *buf, uint32_t label)
}
static int
-tlv_decode_label(struct nbr *nbr, struct ldp_msg *msg, char *buf,
- uint16_t len, uint32_t *label)
-{
- struct label_tlv lt;
-
- if (len < sizeof(lt)) {
- session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type);
- return (-1);
- }
- memcpy(&lt, buf, sizeof(lt));
-
- if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) {
- send_notification_nbr(nbr, S_MISS_MSG, msg->id, msg->type);
- return (-1);
- }
-
- switch (htons(lt.type)) {
- case TLV_TYPE_GENERICLABEL:
- if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_SIZE) {
- session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
- msg->type);
- return (-1);
- }
-
- *label = ntohl(lt.label);
- if (*label > MPLS_LABEL_MAX ||
- (*label <= MPLS_LABEL_RESERVED_MAX &&
- *label != MPLS_LABEL_IPV4NULL &&
- *label != MPLS_LABEL_IPV6NULL &&
- *label != MPLS_LABEL_IMPLNULL)) {
- session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
- msg->type);
- return (-1);
- }
- break;
- case TLV_TYPE_ATMLABEL:
- case TLV_TYPE_FRLABEL:
- default:
- /* unsupported */
- session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, msg->type);
- return (-1);
- }
-
- return (sizeof(lt));
-}
-
-static int
gen_reqid_tlv(struct ibuf *buf, uint32_t reqid)
{
struct reqid_tlv rt;
@@ -520,12 +486,52 @@ gen_pw_status_tlv(struct ibuf *buf, uint32_t status)
return (ibuf_add(buf, &st, sizeof(st)));
}
+uint16_t
+len_fec_tlv(struct map *map)
+{
+ uint16_t len = TLV_HDR_SIZE;
+
+ switch (map->type) {
+ case MAP_TYPE_WILDCARD:
+ len += FEC_ELM_WCARD_LEN;
+ break;
+ case MAP_TYPE_PREFIX:
+ len += FEC_ELM_PREFIX_MIN_LEN +
+ PREFIX_SIZE(map->fec.prefix.prefixlen);
+ break;
+ case MAP_TYPE_PWID:
+ len += FEC_PWID_ELM_MIN_LEN;
+ if (map->flags & F_MAP_PW_ID)
+ len += PW_STATUS_TLV_LEN;
+ if (map->flags & F_MAP_PW_IFMTU)
+ len += FEC_SUBTLV_IFMTU_SIZE;
+ if (map->flags & F_MAP_PW_STATUS)
+ len += PW_STATUS_TLV_SIZE;
+ break;
+ case MAP_TYPE_TYPED_WCARD:
+ len += FEC_ELM_TWCARD_MIN_LEN;
+ switch (map->fec.twcard.type) {
+ case MAP_TYPE_PREFIX:
+ case MAP_TYPE_PWID:
+ len += sizeof(uint16_t);
+ break;
+ default:
+ fatalx("len_fec_tlv: unexpected fec type");
+ }
+ break;
+ default:
+ fatalx("len_fec_tlv: unexpected fec type");
+ }
+
+ return (len);
+}
+
int
gen_fec_tlv(struct ibuf *buf, struct map *map)
{
struct tlv ft;
uint16_t family, len, pw_type, ifmtu;
- uint8_t pw_len = 0;
+ uint8_t pw_len = 0, twcard_len;
uint32_t group_id, pwid;
int err = 0;
@@ -562,7 +568,7 @@ gen_fec_tlv(struct ibuf *buf, struct map *map)
break;
case MAP_TYPE_PWID:
if (map->flags & F_MAP_PW_ID)
- pw_len += PW_STATUS_TLV_LEN;
+ pw_len += FEC_PWID_SIZE;
if (map->flags & F_MAP_PW_IFMTU)
pw_len += FEC_SUBTLV_IFMTU_SIZE;
@@ -595,6 +601,50 @@ gen_fec_tlv(struct ibuf *buf, struct map *map)
err |= ibuf_add(buf, &ifmtu, sizeof(uint16_t));
}
break;
+ case MAP_TYPE_TYPED_WCARD:
+ len = FEC_ELM_TWCARD_MIN_LEN;
+ switch (map->fec.twcard.type) {
+ case MAP_TYPE_PREFIX:
+ case MAP_TYPE_PWID:
+ len += sizeof(uint16_t);
+ break;
+ default:
+ fatalx("gen_fec_tlv: unexpected fec type");
+ }
+ ft.length = htons(len);
+ err |= ibuf_add(buf, &ft, sizeof(ft));
+ err |= ibuf_add(buf, &map->type, sizeof(uint8_t));
+ err |= ibuf_add(buf, &map->fec.twcard.type, sizeof(uint8_t));
+
+ switch (map->fec.twcard.type) {
+ case MAP_TYPE_PREFIX:
+ twcard_len = sizeof(uint16_t);
+ err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
+
+ switch (map->fec.twcard.u.prefix_af) {
+ case AF_INET:
+ family = htons(AF_IPV4);
+ break;
+ case AF_INET6:
+ family = htons(AF_IPV6);
+ break;
+ default:
+ fatalx("gen_fec_tlv: unknown af");
+ break;
+ }
+
+ err |= ibuf_add(buf, &family, sizeof(uint16_t));
+ break;
+ case MAP_TYPE_PWID:
+ twcard_len = sizeof(uint16_t);
+ err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t));
+ pw_type = htons(map->fec.twcard.u.pw_type);
+ err |= ibuf_add(buf, &pw_type, sizeof(uint16_t));
+ break;
+ default:
+ fatalx("gen_fec_tlv: unexpected fec type");
+ }
+ break;
default:
break;
}
@@ -607,7 +657,7 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
uint16_t len, struct map *map)
{
uint16_t off = 0;
- uint8_t pw_len;
+ uint8_t pw_len, twcard_len;
map->type = *buf;
off += sizeof(uint8_t);
@@ -642,7 +692,7 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
map->fec.prefix.af = AF_INET6;
break;
default:
- send_notification_nbr(nbr, S_UNSUP_ADDR, msg->id,
+ send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id,
msg->type);
return (-1);
}
@@ -752,10 +802,83 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
}
return (off);
+ case MAP_TYPE_TYPED_WCARD:
+ if (len < FEC_ELM_TWCARD_MIN_LEN) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
+ msg->type);
+ return (-1);
+ }
+
+ memcpy(&map->fec.twcard.type, buf + off, sizeof(uint8_t));
+ off += sizeof(uint8_t);
+ memcpy(&twcard_len, buf + off, sizeof(uint8_t));
+ off += sizeof(uint8_t);
+ if (len != FEC_ELM_TWCARD_MIN_LEN + twcard_len) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
+ msg->type);
+ return (-1);
+ }
+
+ switch (map->fec.twcard.type) {
+ case MAP_TYPE_PREFIX:
+ if (twcard_len != sizeof(uint16_t)) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
+ msg->type);
+ return (-1);
+ }
+
+ memcpy(&map->fec.twcard.u.prefix_af, buf + off,
+ sizeof(uint16_t));
+ map->fec.twcard.u.prefix_af =
+ ntohs(map->fec.twcard.u.prefix_af);
+ off += sizeof(uint16_t);
+
+ switch (map->fec.twcard.u.prefix_af) {
+ case AF_IPV4:
+ map->fec.twcard.u.prefix_af = AF_INET;
+ break;
+ case AF_IPV6:
+ map->fec.twcard.u.prefix_af = AF_INET6;
+ break;
+ default:
+ session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
+ msg->type);
+ return (-1);
+ }
+ break;
+ case MAP_TYPE_PWID:
+ if (twcard_len != sizeof(uint16_t)) {
+ session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
+ msg->type);
+ return (-1);
+ }
+
+ memcpy(&map->fec.twcard.u.pw_type, buf + off,
+ sizeof(uint16_t));
+ map->fec.twcard.u.pw_type =
+ ntohs(map->fec.twcard.u.pw_type);
+ /* ignore the reserved bit as per RFC 6667 */
+ map->fec.twcard.u.pw_type &= ~PW_TWCARD_RESERVED_BIT;
+ off += sizeof(uint16_t);
+ break;
+ default:
+ send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id,
+ msg->type);
+ return (-1);
+ }
+
+ return (off);
default:
- send_notification_nbr(nbr, S_UNKNOWN_FEC, msg->id, msg->type);
+ send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type);
break;
}
return (-1);
}
+
+static void
+log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map)
+{
+ debug_msg(out, "%s: lsr-id %s, fec %s, label %s", msg_name(msg_type),
+ inet_ntoa(nbr->id), log_map(map), log_label(map->label));
+}
diff --git a/ldpd/lde.c b/ldpd/lde.c
index 1323ba3d02..08339c720a 100644
--- a/ldpd/lde.c
+++ b/ldpd/lde.c
@@ -37,7 +37,7 @@
static void lde_shutdown(void);
static int lde_dispatch_imsg(struct thread *);
static int lde_dispatch_parent(struct thread *);
-static __inline int lde_nbr_compare(struct lde_nbr *,
+static __inline int lde_nbr_compare(struct lde_nbr *,
struct lde_nbr *);
static struct lde_nbr *lde_nbr_new(uint32_t, struct lde_nbr *);
static void lde_nbr_del(struct lde_nbr *);
@@ -205,9 +205,9 @@ lde_dispatch_imsg(struct thread *thread)
struct imsgbuf *ibuf = &iev->ibuf;
struct imsg imsg;
struct lde_nbr *ln;
- struct map map;
- struct lde_addr lde_addr;
- struct notify_msg nm;
+ struct map *map;
+ struct lde_addr *lde_addr;
+ struct notify_msg *nm;
ssize_t n;
int shut = 0;
@@ -240,9 +240,10 @@ lde_dispatch_imsg(struct thread *thread)
case IMSG_LABEL_RELEASE:
case IMSG_LABEL_WITHDRAW:
case IMSG_LABEL_ABORT:
- if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(map))
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct map))
fatalx("lde_dispatch_imsg: wrong imsg len");
- memcpy(&map, imsg.data, sizeof(map));
+ map = imsg.data;
ln = lde_nbr_find(imsg.hdr.peerid);
if (ln == NULL) {
@@ -253,22 +254,16 @@ lde_dispatch_imsg(struct thread *thread)
switch (imsg.hdr.type) {
case IMSG_LABEL_MAPPING:
- lde_check_mapping(&map, ln);
+ lde_check_mapping(map, ln);
break;
case IMSG_LABEL_REQUEST:
- lde_check_request(&map, ln);
+ lde_check_request(map, ln);
break;
case IMSG_LABEL_RELEASE:
- if (map.type == MAP_TYPE_WILDCARD)
- lde_check_release_wcard(&map, ln);
- else
- lde_check_release(&map, ln);
+ lde_check_release(map, ln);
break;
case IMSG_LABEL_WITHDRAW:
- if (map.type == MAP_TYPE_WILDCARD)
- lde_check_withdraw_wcard(&map, ln);
- else
- lde_check_withdraw(&map, ln);
+ lde_check_withdraw(map, ln);
break;
case IMSG_LABEL_ABORT:
/* not necessary */
@@ -276,9 +271,10 @@ lde_dispatch_imsg(struct thread *thread)
}
break;
case IMSG_ADDRESS_ADD:
- if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lde_addr))
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct lde_addr))
fatalx("lde_dispatch_imsg: wrong imsg len");
- memcpy(&lde_addr, imsg.data, sizeof(lde_addr));
+ lde_addr = imsg.data;
ln = lde_nbr_find(imsg.hdr.peerid);
if (ln == NULL) {
@@ -286,16 +282,17 @@ lde_dispatch_imsg(struct thread *thread)
__func__);
break;
}
- if (lde_address_add(ln, &lde_addr) < 0) {
+ if (lde_address_add(ln, lde_addr) < 0) {
log_debug("%s: cannot add address %s, it "
"already exists", __func__,
- log_addr(lde_addr.af, &lde_addr.addr));
+ log_addr(lde_addr->af, &lde_addr->addr));
}
break;
case IMSG_ADDRESS_DEL:
- if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lde_addr))
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct lde_addr))
fatalx("lde_dispatch_imsg: wrong imsg len");
- memcpy(&lde_addr, imsg.data, sizeof(lde_addr));
+ lde_addr = imsg.data;
ln = lde_nbr_find(imsg.hdr.peerid);
if (ln == NULL) {
@@ -303,16 +300,17 @@ lde_dispatch_imsg(struct thread *thread)
__func__);
break;
}
- if (lde_address_del(ln, &lde_addr) < 0) {
+ if (lde_address_del(ln, lde_addr) < 0) {
log_debug("%s: cannot delete address %s, it "
"does not exist", __func__,
- log_addr(lde_addr.af, &lde_addr.addr));
+ log_addr(lde_addr->af, &lde_addr->addr));
}
break;
case IMSG_NOTIFICATION:
- if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(nm))
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct notify_msg))
fatalx("lde_dispatch_imsg: wrong imsg len");
- memcpy(&nm, imsg.data, sizeof(nm));
+ nm = imsg.data;
ln = lde_nbr_find(imsg.hdr.peerid);
if (ln == NULL) {
@@ -321,10 +319,17 @@ lde_dispatch_imsg(struct thread *thread)
break;
}
- switch (nm.status_code) {
+ switch (nm->status_code) {
case S_PW_STATUS:
- l2vpn_recv_pw_status(ln, &nm);
+ l2vpn_recv_pw_status(ln, nm);
break;
+ case S_ENDOFLIB:
+ /*
+ * Do nothing for now. Should be useful in
+ * the future when we implement LDP-IGP
+ * Synchronization (RFC 5443) and Graceful
+ * Restart (RFC 3478).
+ */
default:
break;
}
@@ -391,7 +396,7 @@ lde_dispatch_parent(struct thread *thread)
struct l2vpn_if *nlif;
struct l2vpn_pw *npw;
struct imsg imsg;
- struct kroute kr;
+ struct kroute *kr;
int fd = THREAD_FD(thread);
struct imsgev *iev = THREAD_ARG(thread);
struct imsgbuf *ibuf = &iev->ibuf;
@@ -415,22 +420,23 @@ lde_dispatch_parent(struct thread *thread)
switch (imsg.hdr.type) {
case IMSG_NETWORK_ADD:
case IMSG_NETWORK_UPDATE:
- if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(kr)) {
+ if (imsg.hdr.len != IMSG_HEADER_SIZE +
+ sizeof(struct kroute)) {
log_warnx("%s: wrong imsg len", __func__);
break;
}
- memcpy(&kr, imsg.data, sizeof(kr));
+ kr = imsg.data;
- switch (kr.af) {
+ switch (kr->af) {
case AF_INET:
fec.type = FEC_TYPE_IPV4;
- fec.u.ipv4.prefix = kr.prefix.v4;
- fec.u.ipv4.prefixlen = kr.prefixlen;
+ fec.u.ipv4.prefix = kr->prefix.v4;
+ fec.u.ipv4.prefixlen = kr->prefixlen;
break;
case AF_INET6:
fec.type = FEC_TYPE_IPV6;
- fec.u.ipv6.prefix = kr.prefix.v6;
- fec.u.ipv6.prefixlen = kr.prefixlen;
+ fec.u.ipv6.prefix = kr->prefix.v6;
+ fec.u.ipv6.prefixlen = kr->prefixlen;
break;
default:
fatalx("lde_dispatch_parent: unknown af");
@@ -438,9 +444,9 @@ lde_dispatch_parent(struct thread *thread)
switch (imsg.hdr.type) {
case IMSG_NETWORK_ADD:
- lde_kernel_insert(&fec, kr.af, &kr.nexthop,
- kr.ifindex, kr.priority,
- kr.flags & F_CONNECTED, NULL);
+ lde_kernel_insert(&fec, kr->af, &kr->nexthop,
+ kr->ifindex, kr->priority,
+ kr->flags & F_CONNECTED, NULL);
break;
case IMSG_NETWORK_UPDATE:
lde_kernel_update(&fec);
@@ -929,8 +935,8 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
}
void
-lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label,
- struct status_tlv *st)
+lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn,
+ struct map *wcard, struct status_tlv *st)
{
struct lde_wdraw *lw;
struct map map;
@@ -959,11 +965,8 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label,
break;
}
map.label = fn->local_label;
- } else {
- memset(&map, 0, sizeof(map));
- map.type = MAP_TYPE_WILDCARD;
- map.label = label;
- }
+ } else
+ memcpy(&map, wcard, sizeof(map));
if (st) {
map.st.status_code = st->status_code;
@@ -984,8 +987,13 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label,
lw = lde_wdraw_add(ln, fn);
lw->label = map.label;
} else {
+ struct lde_map *me;
+
RB_FOREACH(f, fec_tree, &ft) {
fn = (struct fec_node *)f;
+ me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
+ if (lde_wildcard_apply(wcard, &fn->fec, me) == 0)
+ continue;
lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw,
&fn->fec);
@@ -997,16 +1005,62 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label,
}
void
-lde_send_labelwithdraw_all(struct fec_node *fn, uint32_t label)
+lde_send_labelwithdraw_wcard(struct lde_nbr *ln, uint32_t label)
{
- struct lde_nbr *ln;
+ struct map wcard;
- RB_FOREACH(ln, nbr_tree, &lde_nbrs)
- lde_send_labelwithdraw(ln, fn, label, NULL);
+ memset(&wcard, 0, sizeof(wcard));
+ wcard.type = MAP_TYPE_WILDCARD;
+ wcard.label = label;
+ lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
+}
+
+void
+lde_send_labelwithdraw_twcard_prefix(struct lde_nbr *ln, uint16_t af,
+ uint32_t label)
+{
+ struct map wcard;
+
+ memset(&wcard, 0, sizeof(wcard));
+ wcard.type = MAP_TYPE_TYPED_WCARD;
+ wcard.fec.twcard.type = MAP_TYPE_PREFIX;
+ wcard.fec.twcard.u.prefix_af = af;
+ wcard.label = label;
+ lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
}
void
-lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label)
+lde_send_labelwithdraw_twcard_pwid(struct lde_nbr *ln, uint16_t pw_type,
+ uint32_t label)
+{
+ struct map wcard;
+
+ memset(&wcard, 0, sizeof(wcard));
+ wcard.type = MAP_TYPE_TYPED_WCARD;
+ wcard.fec.twcard.type = MAP_TYPE_PWID;
+ wcard.fec.twcard.u.pw_type = pw_type;
+ wcard.label = label;
+ lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
+}
+
+void
+lde_send_labelwithdraw_pwid_wcard(struct lde_nbr *ln, uint16_t pw_type,
+ uint32_t group_id)
+{
+ struct map wcard;
+
+ memset(&wcard, 0, sizeof(wcard));
+ wcard.type = MAP_TYPE_PWID;
+ wcard.fec.pwid.type = pw_type;
+ wcard.fec.pwid.group_id = group_id;
+ /* we can not append a Label TLV when using PWid group wildcards. */
+ wcard.label = NO_LABEL;
+ lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
+}
+
+void
+lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn,
+ struct map *wcard, uint32_t label)
{
struct map map;
struct l2vpn_pw *pw;
@@ -1032,10 +1086,8 @@ lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label)
map.flags |= F_MAP_PW_CWORD;
break;
}
- } else {
- memset(&map, 0, sizeof(map));
- map.type = MAP_TYPE_WILDCARD;
- }
+ } else
+ memcpy(&map, wcard, sizeof(map));
map.label = label;
lde_imsg_compose_ldpe(IMSG_RELEASE_ADD, ln->peerid, 0,
@@ -1044,7 +1096,7 @@ lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label)
}
void
-lde_send_notification(uint32_t peerid, uint32_t status_code, uint32_t msg_id,
+lde_send_notification(struct lde_nbr *ln, uint32_t status_code, uint32_t msg_id,
uint16_t msg_type)
{
struct notify_msg nm;
@@ -1055,7 +1107,39 @@ lde_send_notification(uint32_t peerid, uint32_t status_code, uint32_t msg_id,
nm.msg_id = msg_id;
nm.msg_type = msg_type;
- lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0,
+ lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0,
+ &nm, sizeof(nm));
+}
+
+void
+lde_send_notification_eol_prefix(struct lde_nbr *ln, int af)
+{
+ struct notify_msg nm;
+
+ memset(&nm, 0, sizeof(nm));
+ nm.status_code = S_ENDOFLIB;
+ nm.fec.type = MAP_TYPE_TYPED_WCARD;
+ nm.fec.fec.twcard.type = MAP_TYPE_PREFIX;
+ nm.fec.fec.twcard.u.prefix_af = af;
+ nm.flags |= F_NOTIF_FEC;
+
+ lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0,
+ &nm, sizeof(nm));
+}
+
+void
+lde_send_notification_eol_pwid(struct lde_nbr *ln, uint16_t pw_type)
+{
+ struct notify_msg nm;
+
+ memset(&nm, 0, sizeof(nm));
+ nm.status_code = S_ENDOFLIB;
+ nm.fec.type = MAP_TYPE_TYPED_WCARD;
+ nm.fec.fec.twcard.type = MAP_TYPE_PWID;
+ nm.fec.fec.twcard.u.pw_type = pw_type;
+ nm.flags |= F_NOTIF_FEC;
+
+ lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0,
&nm, sizeof(nm));
}
@@ -1076,6 +1160,7 @@ lde_nbr_new(uint32_t peerid, struct lde_nbr *new)
ln->id = new->id;
ln->v4_enabled = new->v4_enabled;
ln->v6_enabled = new->v6_enabled;
+ ln->flags = new->flags;
ln->peerid = peerid;
fec_init(&ln->recv_map);
fec_init(&ln->sent_map);
@@ -1352,13 +1437,11 @@ lde_change_egress_label(int af)
/* explicitly withdraw all null labels */
RB_FOREACH(ln, nbr_tree, &lde_nbrs) {
- lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IMPLNULL, NULL);
+ lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IMPLNULL);
if (ln->v4_enabled)
- lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IPV4NULL,
- NULL);
+ lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV4NULL);
if (ln->v6_enabled)
- lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IPV6NULL,
- NULL);
+ lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV6NULL);
}
/* update label of connected routes */
diff --git a/ldpd/lde.h b/ldpd/lde.h
index e0e9873d5c..b5bcb42c8b 100644
--- a/ldpd/lde.h
+++ b/ldpd/lde.h
@@ -90,6 +90,7 @@ struct lde_nbr {
struct in_addr id;
int v4_enabled; /* announce/process v4 msgs */
int v6_enabled; /* announce/process v6 msgs */
+ int flags; /* capabilities */
struct fec_tree recv_req;
struct fec_tree sent_req;
struct fec_tree recv_map;
@@ -143,11 +144,20 @@ void lde_map2fec(struct map *, struct in_addr, struct fec *);
void lde_send_labelmapping(struct lde_nbr *, struct fec_node *,
int);
void lde_send_labelwithdraw(struct lde_nbr *, struct fec_node *,
- uint32_t, struct status_tlv *);
-void lde_send_labelwithdraw_all(struct fec_node *, uint32_t);
-void lde_send_labelrelease(struct lde_nbr *, struct fec_node *,
+ struct map *, struct status_tlv *);
+void lde_send_labelwithdraw_wcard(struct lde_nbr *, uint32_t);
+void lde_send_labelwithdraw_twcard_prefix(struct lde_nbr *,
+ uint16_t, uint32_t);
+void lde_send_labelwithdraw_twcard_pwid(struct lde_nbr *, uint16_t,
+ uint32_t);
+void lde_send_labelwithdraw_pwid_wcard(struct lde_nbr *, uint16_t,
uint32_t);
-void lde_send_notification(uint32_t, uint32_t, uint32_t, uint16_t);
+void lde_send_labelrelease(struct lde_nbr *, struct fec_node *,
+ struct map *, uint32_t);
+void lde_send_notification(struct lde_nbr *, uint32_t, uint32_t,
+ uint16_t);
+void lde_send_notification_eol_prefix(struct lde_nbr *, int);
+void lde_send_notification_eol_pwid(struct lde_nbr *, uint16_t);
struct lde_nbr *lde_nbr_find_by_lsrid(struct in_addr);
struct lde_nbr *lde_nbr_find_by_addr(int, union ldpd_addr *);
struct lde_map *lde_map_add(struct lde_nbr *, struct fec_node *, int);
@@ -178,10 +188,13 @@ void lde_kernel_remove(struct fec *, int, union ldpd_addr *,
void lde_kernel_update(struct fec *);
void lde_check_mapping(struct map *, struct lde_nbr *);
void lde_check_request(struct map *, struct lde_nbr *);
+void lde_check_request_wcard(struct map *, struct lde_nbr *);
void lde_check_release(struct map *, struct lde_nbr *);
void lde_check_release_wcard(struct map *, struct lde_nbr *);
void lde_check_withdraw(struct map *, struct lde_nbr *);
void lde_check_withdraw_wcard(struct map *, struct lde_nbr *);
+int lde_wildcard_apply(struct map *, struct fec *,
+ struct lde_map *);
int lde_gc_timer(struct thread *);
void lde_gc_start_timer(void);
void lde_gc_stop_timer(void);
@@ -195,6 +208,7 @@ void l2vpn_exit(struct l2vpn *);
struct l2vpn_if *l2vpn_if_new(struct l2vpn *, struct kif *);
struct l2vpn_if *l2vpn_if_find(struct l2vpn *, unsigned int);
struct l2vpn_if *l2vpn_if_find_name(struct l2vpn *, const char *);
+void l2vpn_if_update(struct l2vpn_if *);
struct l2vpn_pw *l2vpn_pw_new(struct l2vpn *, struct kif *);
struct l2vpn_pw *l2vpn_pw_find(struct l2vpn *, unsigned int);
struct l2vpn_pw *l2vpn_pw_find_name(struct l2vpn *, const char *);
@@ -204,8 +218,12 @@ void l2vpn_pw_reset(struct l2vpn_pw *);
int l2vpn_pw_ok(struct l2vpn_pw *, struct fec_nh *);
int l2vpn_pw_negotiate(struct lde_nbr *, struct fec_node *,
struct map *);
-void l2vpn_send_pw_status(uint32_t, uint32_t, struct fec *);
+void l2vpn_send_pw_status(struct lde_nbr *, uint32_t, struct fec *);
+void l2vpn_send_pw_status_wcard(struct lde_nbr *, uint32_t,
+ uint16_t, uint32_t);
void l2vpn_recv_pw_status(struct lde_nbr *, struct notify_msg *);
+void l2vpn_recv_pw_status_wcard(struct lde_nbr *,
+ struct notify_msg *);
void l2vpn_sync_pws(int, union ldpd_addr *);
void l2vpn_pw_ctl(pid_t);
void l2vpn_binding_ctl(pid_t);
diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c
index 234d373fbb..4444a1e1ac 100644
--- a/ldpd/lde_lib.c
+++ b/ldpd/lde_lib.c
@@ -374,7 +374,8 @@ lde_kernel_update(struct fec *fec)
}
if (LIST_EMPTY(&fn->nexthops)) {
- lde_send_labelwithdraw_all(fn, NO_LABEL);
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelwithdraw(ln, fn, NULL, NULL);
fn->local_label = NO_LABEL;
fn->data = NULL;
} else {
@@ -478,7 +479,7 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
/* LMp.10 */
if (me->map.label != map->label && lre == NULL) {
/* LMp.10a */
- lde_send_labelrelease(ln, fn, me->map.label);
+ lde_send_labelrelease(ln, fn, NULL, me->map.label);
/*
* Can not use lde_nbr_find_by_addr() because there's
@@ -554,6 +555,12 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
struct fec_node *fn;
struct fec_nh *fnh;
+ /* wildcard label request */
+ if (map->type == MAP_TYPE_TYPED_WCARD) {
+ lde_check_request_wcard(map, ln);
+ return;
+ }
+
/* LRq.1: skip loop detection (not necessary) */
/* LRq.2: is there a next hop for fec? */
@@ -561,7 +568,7 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
fn = (struct fec_node *)fec_find(&ft, &fec);
if (fn == NULL || LIST_EMPTY(&fn->nexthops)) {
/* LRq.5: send No Route notification */
- lde_send_notification(ln->peerid, S_NO_ROUTE, map->msg_id,
+ lde_send_notification(ln, S_NO_ROUTE, map->msg_id,
htons(MSG_TYPE_LABELREQUEST));
return;
}
@@ -575,8 +582,8 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
continue;
/* LRq.4: send Loop Detected notification */
- lde_send_notification(ln->peerid, S_LOOP_DETECTED,
- map->msg_id, htons(MSG_TYPE_LABELREQUEST));
+ lde_send_notification(ln, S_LOOP_DETECTED, map->msg_id,
+ htons(MSG_TYPE_LABELREQUEST));
return;
default:
break;
@@ -605,6 +612,40 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
}
void
+lde_check_request_wcard(struct map *map, struct lde_nbr *ln)
+{
+ struct fec *f;
+ struct fec_node *fn;
+ struct lde_req *lre;
+
+ RB_FOREACH(f, fec_tree, &ft) {
+ fn = (struct fec_node *)f;
+
+ /* only a typed wildcard is possible here */
+ if (lde_wildcard_apply(map, &fn->fec, NULL) == 0)
+ continue;
+
+ /* LRq.2: is there a next hop for fec? */
+ if (LIST_EMPTY(&fn->nexthops))
+ continue;
+
+ /* LRq.6: first check if we have a pending request running */
+ lre = (struct lde_req *)fec_find(&ln->recv_req, &fn->fec);
+ if (lre != NULL)
+ /* LRq.7: duplicate request */
+ continue;
+
+ /* LRq.8: record label request */
+ lre = lde_req_add(ln, &fn->fec, 0);
+ if (lre != NULL)
+ lre->msg_id = ntohl(map->msg_id);
+
+ /* LRq.9: perform LSR label distribution */
+ lde_send_labelmapping(ln, fn, 1);
+ }
+}
+
+void
lde_check_release(struct map *map, struct lde_nbr *ln)
{
struct fec fec;
@@ -612,9 +653,13 @@ lde_check_release(struct map *map, struct lde_nbr *ln)
struct lde_wdraw *lw;
struct lde_map *me;
- /* TODO group wildcard */
- if (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))
+ /* wildcard label release */
+ if (map->type == MAP_TYPE_WILDCARD ||
+ map->type == MAP_TYPE_TYPED_WCARD ||
+ (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))) {
+ lde_check_release_wcard(map, ln);
return;
+ }
lde_map2fec(map, ln->id, &fec);
fn = (struct fec_node *)fec_find(&ft, &fec);
@@ -624,8 +669,7 @@ lde_check_release(struct map *map, struct lde_nbr *ln)
/* LRl.3: first check if we have a pending withdraw running */
lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
- if (lw && (map->label == NO_LABEL ||
- (lw->label != NO_LABEL && map->label == lw->label))) {
+ if (lw && (map->label == NO_LABEL || map->label == lw->label)) {
/* LRl.4: delete record of outstanding label withdraw */
lde_wdraw_del(ln, lw);
}
@@ -651,17 +695,20 @@ lde_check_release_wcard(struct map *map, struct lde_nbr *ln)
RB_FOREACH(f, fec_tree, &ft) {
fn = (struct fec_node *)f;
+ me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
+
+ /* LRl.1: does FEC match a known FEC? */
+ if (lde_wildcard_apply(map, &fn->fec, me) == 0)
+ continue;
/* LRl.3: first check if we have a pending withdraw running */
lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
- if (lw && (map->label == NO_LABEL ||
- (lw->label != NO_LABEL && map->label == lw->label))) {
+ if (lw && (map->label == NO_LABEL || map->label == lw->label)) {
/* LRl.4: delete record of outstanding lbl withdraw */
lde_wdraw_del(ln, lw);
}
/* LRl.6: check sent map list and remove it if available */
- me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
if (me &&
(map->label == NO_LABEL || map->label == me->map.label))
lde_map_del(ln, me, 1);
@@ -682,9 +729,13 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
struct lde_map *me;
struct l2vpn_pw *pw;
- /* TODO group wildcard */
- if (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))
+ /* wildcard label withdraw */
+ if (map->type == MAP_TYPE_WILDCARD ||
+ map->type == MAP_TYPE_TYPED_WCARD ||
+ (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))) {
+ lde_check_withdraw_wcard(map, ln);
return;
+ }
lde_map2fec(map, ln->id, &fec);
fn = (struct fec_node *)fec_find(&ft, &fec);
@@ -707,12 +758,15 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
default:
break;
}
+ if (map->label != NO_LABEL && map->label != fnh->remote_label)
+ continue;
+
lde_send_delete_klabel(fn, fnh);
fnh->remote_label = NO_LABEL;
}
/* LWd.2: send label release */
- lde_send_labelrelease(ln, fn, map->label);
+ lde_send_labelrelease(ln, fn, NULL, map->label);
/* LWd.3: check previously received label mapping */
me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
@@ -730,10 +784,14 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
struct lde_map *me;
/* LWd.2: send label release */
- lde_send_labelrelease(ln, NULL, map->label);
+ lde_send_labelrelease(ln, NULL, map, map->label);
RB_FOREACH(f, fec_tree, &ft) {
fn = (struct fec_node *)f;
+ me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
+
+ if (lde_wildcard_apply(map, &fn->fec, me) == 0)
+ continue;
/* LWd.1: remove label from forwarding/switching use */
LIST_FOREACH(fnh, &fn->nexthops, entry) {
@@ -751,12 +809,15 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
default:
break;
}
+ if (map->label != NO_LABEL && map->label !=
+ fnh->remote_label)
+ continue;
+
lde_send_delete_klabel(fn, fnh);
fnh->remote_label = NO_LABEL;
}
/* LWd.3: check previously received label mapping */
- me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
if (me && (map->label == NO_LABEL ||
map->label == me->map.label))
/*
@@ -767,6 +828,49 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
}
}
+int
+lde_wildcard_apply(struct map *wcard, struct fec *fec, struct lde_map *me)
+{
+ switch (wcard->type) {
+ case MAP_TYPE_WILDCARD:
+ /* full wildcard */
+ return (1);
+ case MAP_TYPE_TYPED_WCARD:
+ switch (wcard->fec.twcard.type) {
+ case MAP_TYPE_PREFIX:
+ if (wcard->fec.twcard.u.prefix_af == AF_INET &&
+ fec->type != FEC_TYPE_IPV4)
+ return (0);
+ if (wcard->fec.twcard.u.prefix_af == AF_INET6 &&
+ fec->type != FEC_TYPE_IPV6)
+ return (0);
+ return (1);
+ case MAP_TYPE_PWID:
+ if (fec->type != FEC_TYPE_PWID)
+ return (0);
+ if (wcard->fec.twcard.u.pw_type != PW_TYPE_WILDCARD &&
+ wcard->fec.twcard.u.pw_type != fec->u.pwid.type)
+ return (0);
+ return (1);
+ default:
+ fatalx("lde_wildcard_apply: unexpected fec type");
+ }
+ break;
+ case MAP_TYPE_PWID:
+ /* RFC4447 pw-id group wildcard */
+ if (fec->type != FEC_TYPE_PWID)
+ return (0);
+ if (fec->u.pwid.type != wcard->fec.pwid.type)
+ return (0);
+ if (me == NULL || (me->map.fec.pwid.group_id !=
+ wcard->fec.pwid.group_id))
+ return (0);
+ return (1);
+ default:
+ fatalx("lde_wildcard_apply: unexpected fec type");
+ }
+}
+
/* gabage collector timer: timer to remove dead entries from the LIB */
/* ARGSUSED */
diff --git a/ldpd/ldp.h b/ldpd/ldp.h
index c421cddc38..c2b64d20c6 100644
--- a/ldpd/ldp.h
+++ b/ldpd/ldp.h
@@ -63,6 +63,7 @@
#define MSG_TYPE_HELLO 0x0100
#define MSG_TYPE_INIT 0x0200
#define MSG_TYPE_KEEPALIVE 0x0201
+#define MSG_TYPE_CAPABILITY 0x0202 /* RFC 5561 */
#define MSG_TYPE_ADDR 0x0300
#define MSG_TYPE_ADDRWITHDRAW 0x0301
#define MSG_TYPE_LABELMAPPING 0x0400
@@ -92,9 +93,17 @@
#define TLV_TYPE_FRSESSION 0x0502
#define TLV_TYPE_LABELREQUEST 0x0600
/* RFC 4447 */
-#define TLV_TYPE_PW_STATUS 0x096A
+#define TLV_TYPE_MAC_LIST 0x8404
+#define TLV_TYPE_PW_STATUS 0x896A
#define TLV_TYPE_PW_IF_PARAM 0x096B
#define TLV_TYPE_PW_GROUP_ID 0x096C
+/* RFC 5561 */
+#define TLV_TYPE_RETURNED_TLVS 0x8304
+#define TLV_TYPE_DYNAMIC_CAP 0x8506
+/* RFC 5918 */
+#define TLV_TYPE_TWCARD_CAP 0x850B
+/* RFC 5919 */
+#define TLV_TYPE_UNOTIF_CAP 0x8603
/* RFC 7552 */
#define TLV_TYPE_DUALSTACK 0x8701
@@ -196,6 +205,10 @@ struct hello_prms_opt16_tlv {
#define S_UNASSIGN_TAI 0x00000029
#define S_MISCONF_ERR 0x0000002A
#define S_WITHDRAW_MTHD 0x0000002B
+/* RFC 5561 */
+#define S_UNSSUPORTDCAP 0x0000002E
+/* RFC 5919 */
+#define S_ENDOFLIB 0x0000002F
/* RFC 7552 */
#define S_TRANS_MISMTCH 0x80000032
#define S_DS_NONCMPLNCE 0x80000033
@@ -227,6 +240,26 @@ struct status_tlv {
#define STATUS_TLV_LEN 10
#define STATUS_FATAL 0x80000000
+struct capability_tlv {
+ uint16_t type;
+ uint16_t length;
+ uint8_t reserved;
+};
+#define STATE_BIT 0x80
+
+#define F_CAP_TLV_RCVD_DYNAMIC 0x01
+#define F_CAP_TLV_RCVD_TWCARD 0x02
+#define F_CAP_TLV_RCVD_UNOTIF 0x04
+
+#define CAP_TLV_DYNAMIC_SIZE 5
+#define CAP_TLV_DYNAMIC_LEN 1
+
+#define CAP_TLV_TWCARD_SIZE 5
+#define CAP_TLV_TWCARD_LEN 1
+
+#define CAP_TLV_UNOTIF_SIZE 5
+#define CAP_TLV_UNOTIF_LEN 1
+
#define AF_IPV4 0x1
#define AF_IPV6 0x2
@@ -242,17 +275,23 @@ struct address_list_tlv {
#define FEC_ELM_WCARD_LEN 1
#define FEC_ELM_PREFIX_MIN_LEN 4
#define FEC_PWID_ELM_MIN_LEN 8
+#define FEC_PWID_SIZE 4
+#define FEC_ELM_TWCARD_MIN_LEN 3
#define MAP_TYPE_WILDCARD 0x01
#define MAP_TYPE_PREFIX 0x02
+#define MAP_TYPE_TYPED_WCARD 0x05
#define MAP_TYPE_PWID 0x80
#define MAP_TYPE_GENPWID 0x81
#define CONTROL_WORD_FLAG 0x8000
#define PW_TYPE_ETHERNET_TAGGED 0x0004
#define PW_TYPE_ETHERNET 0x0005
+#define PW_TYPE_WILDCARD 0x7FFF
#define DEFAULT_PW_TYPE PW_TYPE_ETHERNET
+#define PW_TWCARD_RESERVED_BIT 0x8000
+
/* RFC 4447 Sub-TLV record */
struct subtlv {
uint8_t type;
diff --git a/ldpd/ldp_debug.h b/ldpd/ldp_debug.h
index aa0cd47e7b..f944851b6e 100644
--- a/ldpd/ldp_debug.h
+++ b/ldpd/ldp_debug.h
@@ -104,6 +104,14 @@ do { \
log_debug("msg[out]: " emsg, __VA_ARGS__); \
} while (0)
+#define debug_msg(out, emsg, ...) \
+do { \
+ if (out) \
+ debug_msg_send(emsg, __VA_ARGS__); \
+ else \
+ debug_msg_recv(emsg, __VA_ARGS__); \
+} while (0)
+
#define debug_kalive_recv(emsg, ...) \
do { \
if (LDP_DEBUG(msg, MSG_RECV_ALL)) \
diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c
index 12954b91af..c41a0dbd91 100644
--- a/ldpd/ldp_zebra.c
+++ b/ldpd/ldp_zebra.c
@@ -65,6 +65,8 @@ ifp2kif(struct interface *ifp, struct kif *kif)
strlcpy(kif->ifname, ifp->name, sizeof(kif->ifname));
kif->ifindex = ifp->ifindex;
kif->flags = ifp->flags;
+ if (ifp->ll_type == ZEBRA_LLT_ETHER)
+ memcpy(kif->mac, ifp->hw_addr, ETHER_ADDR_LEN);
}
static void
diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h
index ff3af19db4..0a7e1177bc 100644
--- a/ldpd/ldpd.h
+++ b/ldpd/ldpd.h
@@ -27,6 +27,7 @@
#include "imsg.h"
#include "thread.h"
#include "qobj.h"
+#include "prefix.h"
#include "filter.h"
#include "ldp.h"
@@ -220,6 +221,13 @@ struct map {
uint32_t group_id;
uint16_t ifmtu;
} pwid;
+ struct {
+ uint8_t type;
+ union {
+ uint16_t prefix_af;
+ uint16_t pw_type;
+ } u;
+ } twcard;
} fec;
struct {
uint32_t status_code;
@@ -244,10 +252,16 @@ struct notify_msg {
uint16_t msg_type; /* network byte order */
uint32_t pw_status;
struct map fec;
+ struct {
+ uint16_t type;
+ uint16_t length;
+ char *data;
+ } rtlvs;
uint8_t flags;
};
#define F_NOTIF_PW_STATUS 0x01 /* pseudowire status tlv present */
#define F_NOTIF_FEC 0x02 /* fec tlv present */
+#define F_NOTIF_RETURNED_TLVS 0x04 /* returned tlvs present */
struct if_addr {
LIST_ENTRY(if_addr) entry;
@@ -337,6 +351,7 @@ struct l2vpn_if {
char ifname[IF_NAMESIZE];
unsigned int ifindex;
uint16_t flags;
+ uint8_t mac[ETHER_ADDR_LEN];
QOBJ_FIELDS
};
RB_HEAD(l2vpn_if_head, l2vpn_if);
@@ -506,6 +521,7 @@ struct kif {
char ifname[IF_NAMESIZE];
unsigned short ifindex;
int flags;
+ uint8_t mac[ETHER_ADDR_LEN];
int mtu;
};
diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c
index 7dcc8fbe16..3bb84e92a9 100644
--- a/ldpd/ldpe.c
+++ b/ldpd/ldpe.c
@@ -251,8 +251,8 @@ ldpe_dispatch_main(struct thread *thread)
struct iface *niface;
struct tnbr *ntnbr;
struct nbr_params *nnbrp;
- static struct l2vpn *nl2vpn;
- struct l2vpn_if *nlif;
+ static struct l2vpn *l2vpn, *nl2vpn;
+ struct l2vpn_if *lif = NULL, *nlif;
struct l2vpn_pw *npw;
struct imsg imsg;
int fd = THREAD_FD(thread);
@@ -292,11 +292,22 @@ ldpe_dispatch_main(struct thread *thread)
kif = imsg.data;
iface = if_lookup_name(leconf, kif->ifname);
- if (!iface)
+ if (iface) {
+ if_update_info(iface, kif);
+ if_update(iface, AF_UNSPEC);
break;
+ }
- if_update_info(iface, kif);
- if_update(iface, AF_UNSPEC);
+ RB_FOREACH(l2vpn, l2vpn_head, &leconf->l2vpn_tree) {
+ lif = l2vpn_if_find_name(l2vpn, kif->ifname);
+ if (lif) {
+ lif->flags = kif->flags;
+ memcpy(lif->mac, kif->mac,
+ sizeof(lif->mac));
+ l2vpn_if_update(lif);
+ break;
+ }
+ }
break;
case IMSG_NEWADDR:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
@@ -529,10 +540,10 @@ ldpe_dispatch_lde(struct thread *thread)
struct imsgev *iev = THREAD_ARG(thread);
struct imsgbuf *ibuf = &iev->ibuf;
struct imsg imsg;
- struct map map;
- struct notify_msg nm;
+ struct map *map;
+ struct notify_msg *nm;
+ struct nbr *nbr;
int n, shut = 0;
- struct nbr *nbr = NULL;
iev->ev_read = NULL;
@@ -552,9 +563,10 @@ ldpe_dispatch_lde(struct thread *thread)
case IMSG_RELEASE_ADD:
case IMSG_REQUEST_ADD:
case IMSG_WITHDRAW_ADD:
- if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(map))
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct map))
fatalx("invalid size of map request");
- memcpy(&map, imsg.data, sizeof(map));
+ map = imsg.data;
nbr = nbr_find_peerid(imsg.hdr.peerid);
if (nbr == NULL) {
@@ -567,16 +579,16 @@ ldpe_dispatch_lde(struct thread *thread)
switch (imsg.hdr.type) {
case IMSG_MAPPING_ADD:
- mapping_list_add(&nbr->mapping_list, &map);
+ mapping_list_add(&nbr->mapping_list, map);
break;
case IMSG_RELEASE_ADD:
- mapping_list_add(&nbr->release_list, &map);
+ mapping_list_add(&nbr->release_list, map);
break;
case IMSG_REQUEST_ADD:
- mapping_list_add(&nbr->request_list, &map);
+ mapping_list_add(&nbr->request_list, map);
break;
case IMSG_WITHDRAW_ADD:
- mapping_list_add(&nbr->withdraw_list, &map);
+ mapping_list_add(&nbr->withdraw_list, map);
break;
}
break;
@@ -613,9 +625,10 @@ ldpe_dispatch_lde(struct thread *thread)
}
break;
case IMSG_NOTIFICATION_SEND:
- if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(nm))
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct notify_msg))
fatalx("invalid size of OE request");
- memcpy(&nm, imsg.data, sizeof(nm));
+ nm = imsg.data;
nbr = nbr_find_peerid(imsg.hdr.peerid);
if (nbr == NULL) {
@@ -626,7 +639,7 @@ ldpe_dispatch_lde(struct thread *thread)
if (nbr->state != NBR_STA_OPER)
break;
- send_notification_full(nbr->tcp, &nm);
+ send_notification_full(nbr->tcp, nm);
break;
case IMSG_CTL_END:
case IMSG_CTL_SHOW_LIB:
@@ -791,8 +804,7 @@ ldpe_iface_af_ctl(struct ctl_conn *c, int af, unsigned int idx)
continue;
ictl = if_to_ctl(ia);
- imsg_compose_event(&c->iev,
- IMSG_CTL_SHOW_INTERFACE,
+ imsg_compose_event(&c->iev, IMSG_CTL_SHOW_INTERFACE,
0, 0, -1, ictl, sizeof(struct ctl_iface));
}
}
diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h
index 052439df88..22b75eb008 100644
--- a/ldpd/ldpe.h
+++ b/ldpd/ldpe.h
@@ -111,6 +111,9 @@ struct nbr {
int flags;
};
#define F_NBR_GTSM_NEGOTIATED 0x01
+#define F_NBR_CAP_DYNAMIC 0x02
+#define F_NBR_CAP_TWCARD 0x04
+#define F_NBR_CAP_UNOTIF 0x08
RB_HEAD(nbr_id_head, nbr);
RB_PROTOTYPE(nbr_id_head, nbr, id_tree, nbr_id_compare)
@@ -159,6 +162,8 @@ void recv_hello(struct in_addr, struct ldp_msg *, int, union ldpd_addr *,
/* init.c */
void send_init(struct nbr *);
int recv_init(struct nbr *, char *, uint16_t);
+void send_capability(struct nbr *, uint16_t, int);
+int recv_capability(struct nbr *, char *, uint16_t);
/* keepalive.c */
void send_keepalive(struct nbr *);
@@ -166,15 +171,16 @@ int recv_keepalive(struct nbr *, char *, uint16_t);
/* notification.c */
void send_notification_full(struct tcp_conn *, struct notify_msg *);
-void send_notification(uint32_t, struct tcp_conn *, uint32_t,
- uint16_t);
-void send_notification_nbr(struct nbr *, uint32_t, uint32_t, uint16_t);
+void send_notification(struct tcp_conn *, uint32_t, uint32_t, uint16_t);
+void send_notification_rtlvs(struct nbr *, uint32_t, uint32_t, uint16_t,
+ uint16_t, uint16_t, char *);
int recv_notification(struct nbr *, char *, uint16_t);
int gen_status_tlv(struct ibuf *, uint32_t, uint32_t, uint16_t);
/* address.c */
void send_address_single(struct nbr *, struct if_addr *, int);
void send_address_all(struct nbr *, int);
+void send_mac_withdrawal(struct nbr *, struct map *, uint8_t *);
int recv_address(struct nbr *, char *, uint16_t);
/* labelmapping.c */
@@ -182,6 +188,7 @@ int recv_address(struct nbr *, char *, uint16_t);
void send_labelmessage(struct nbr *, uint16_t, struct mapping_head *);
int recv_labelmessage(struct nbr *, char *, uint16_t, uint16_t);
int gen_pw_status_tlv(struct ibuf *, uint32_t);
+uint16_t len_fec_tlv(struct map *);
int gen_fec_tlv(struct ibuf *, struct map *);
int tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *,
uint16_t, struct map *);
diff --git a/ldpd/log.c b/ldpd/log.c
index 77efdb4714..b30604db0d 100644
--- a/ldpd/log.c
+++ b/ldpd/log.c
@@ -313,7 +313,7 @@ log_hello_src(const struct hello_source *src)
const char *
log_map(const struct map *map)
{
- static char buf[64];
+ static char buf[128];
switch (map->type) {
case MAP_TYPE_WILDCARD:
@@ -327,11 +327,34 @@ log_map(const struct map *map)
return ("???");
break;
case MAP_TYPE_PWID:
- if (snprintf(buf, sizeof(buf), "pwid %u (%s)",
- map->fec.pwid.pwid,
+ if (snprintf(buf, sizeof(buf), "pw-id %u group-id %u (%s)",
+ map->fec.pwid.pwid, map->fec.pwid.group_id,
pw_type_name(map->fec.pwid.type)) == -1)
return ("???");
break;
+ case MAP_TYPE_TYPED_WCARD:
+ if (snprintf(buf, sizeof(buf), "typed wildcard") < 0)
+ return ("???");
+ switch (map->fec.twcard.type) {
+ case MAP_TYPE_PREFIX:
+ if (snprintf(buf + strlen(buf), sizeof(buf) -
+ strlen(buf), " (prefix, address-family %s)",
+ af_name(map->fec.twcard.u.prefix_af)) < 0)
+ return ("???");
+ break;
+ case MAP_TYPE_PWID:
+ if (snprintf(buf + strlen(buf), sizeof(buf) -
+ strlen(buf), " (pwid, type %s)",
+ pw_type_name(map->fec.twcard.u.pw_type)) < 0)
+ return ("???");
+ break;
+ default:
+ if (snprintf(buf + strlen(buf), sizeof(buf) -
+ strlen(buf), " (unknown type)") < 0)
+ return ("???");
+ break;
+ }
+ break;
default:
return ("???");
}
@@ -464,6 +487,8 @@ msg_name(uint16_t msg)
return ("initialization");
case MSG_TYPE_KEEPALIVE:
return ("keepalive");
+ case MSG_TYPE_CAPABILITY:
+ return ("capability");
case MSG_TYPE_ADDR:
return ("address");
case MSG_TYPE_ADDRWITHDRAW:
@@ -557,6 +582,10 @@ status_code_name(uint32_t status)
return ("Generic Misconfiguration Error");
case S_WITHDRAW_MTHD:
return ("Label Withdraw PW Status Method");
+ case S_UNSSUPORTDCAP:
+ return ("Unsupported Capability");
+ case S_ENDOFLIB:
+ return ("End-of-LIB");
case S_TRANS_MISMTCH:
return ("Transport Connection Mismatch");
case S_DS_NONCMPLNCE:
@@ -577,6 +606,8 @@ pw_type_name(uint16_t pw_type)
return ("Eth Tagged");
case PW_TYPE_ETHERNET:
return ("Ethernet");
+ case PW_TYPE_WILDCARD:
+ return ("Wildcard");
default:
snprintf(buf, sizeof(buf), "[%0x]", pw_type);
return (buf);
diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c
index d24ceb1229..077d472850 100644
--- a/ldpd/neighbor.c
+++ b/ldpd/neighbor.c
@@ -744,6 +744,7 @@ nbr_act_session_operational(struct nbr *nbr)
lde_nbr.id = nbr->id;
lde_nbr.v4_enabled = nbr->v4_enabled;
lde_nbr.v6_enabled = nbr->v6_enabled;
+ lde_nbr.flags = nbr->flags;
return (ldpe_imsg_compose_lde(IMSG_NEIGHBOR_UP, nbr->peerid, 0,
&lde_nbr, sizeof(lde_nbr)));
}
diff --git a/ldpd/notification.c b/ldpd/notification.c
index d306361d5c..393994ed5f 100644
--- a/ldpd/notification.c
+++ b/ldpd/notification.c
@@ -24,6 +24,9 @@
#include "ldpe.h"
#include "ldp_debug.h"
+static int gen_returned_tlvs(struct ibuf *, uint16_t, uint16_t, char *);
+static void log_msg_notification(int, struct nbr *, struct notify_msg *);
+
void
send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm)
{
@@ -35,16 +38,10 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm)
size = LDP_HDR_SIZE + LDP_MSG_SIZE + STATUS_SIZE;
if (nm->flags & F_NOTIF_PW_STATUS)
size += PW_STATUS_TLV_SIZE;
- if (nm->flags & F_NOTIF_FEC) {
- size += TLV_HDR_SIZE;
- switch (nm->fec.type) {
- case MAP_TYPE_PWID:
- size += FEC_PWID_ELM_MIN_LEN;
- if (nm->fec.flags & F_MAP_PW_ID)
- size += sizeof(uint32_t);
- break;
- }
- }
+ if (nm->flags & F_NOTIF_FEC)
+ size += len_fec_tlv(&nm->fec);
+ if (nm->flags & F_NOTIF_RETURNED_TLVS)
+ size += TLV_HDR_SIZE * 2 + nm->rtlvs.length;
if ((buf = ibuf_open(size)) == NULL)
fatal(__func__);
@@ -58,22 +55,25 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm)
err |= gen_pw_status_tlv(buf, nm->pw_status);
if (nm->flags & F_NOTIF_FEC)
err |= gen_fec_tlv(buf, &nm->fec);
+ if (nm->flags & F_NOTIF_RETURNED_TLVS)
+ err |= gen_returned_tlvs(buf, nm->rtlvs.type, nm->rtlvs.length,
+ nm->rtlvs.data);
if (err) {
ibuf_free(buf);
return;
}
- if (tcp->nbr)
- debug_msg_send("notification: lsr-id %s status %s%s",
- inet_ntoa(tcp->nbr->id), status_code_name(nm->status_code),
- (nm->status_code & STATUS_FATAL) ? " (fatal)" : "");
+ if (tcp->nbr) {
+ log_msg_notification(1, tcp->nbr, nm);
+ nbr_fsm(tcp->nbr, NBR_EVT_PDU_SENT);
+ }
evbuf_enqueue(&tcp->wbuf, buf);
}
/* send a notification without optional tlvs */
void
-send_notification(uint32_t status_code, struct tcp_conn *tcp, uint32_t msg_id,
+send_notification(struct tcp_conn *tcp, uint32_t status_code, uint32_t msg_id,
uint16_t msg_type)
{
struct notify_msg nm;
@@ -87,11 +87,24 @@ send_notification(uint32_t status_code, struct tcp_conn *tcp, uint32_t msg_id,
}
void
-send_notification_nbr(struct nbr *nbr, uint32_t status_code, uint32_t msg_id,
- uint16_t msg_type)
+send_notification_rtlvs(struct nbr *nbr, uint32_t status_code, uint32_t msg_id,
+ uint16_t msg_type, uint16_t tlv_type, uint16_t tlv_len, char *tlv_data)
{
- send_notification(status_code, nbr->tcp, msg_id, msg_type);
- nbr_fsm(nbr, NBR_EVT_PDU_SENT);
+ struct notify_msg nm;
+
+ memset(&nm, 0, sizeof(nm));
+ nm.status_code = status_code;
+ nm.msg_id = msg_id;
+ nm.msg_type = msg_type;
+ /* do not append the given TLV if it's too big (shouldn't happen) */
+ if (tlv_len < 1024) {
+ nm.rtlvs.type = tlv_type;
+ nm.rtlvs.length = tlv_len;
+ nm.rtlvs.data = tlv_data;
+ nm.flags |= F_NOTIF_RETURNED_TLVS;
+ }
+
+ send_notification_full(nbr->tcp, &nm);
}
int
@@ -126,6 +139,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
/* Optional Parameters */
while (len > 0) {
struct tlv tlv;
+ uint16_t tlv_type;
uint16_t tlv_len;
if (len < sizeof(tlv)) {
@@ -134,6 +148,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
}
memcpy(&tlv, buf, TLV_HDR_SIZE);
+ tlv_type = ntohs(tlv.type);
tlv_len = ntohs(tlv.length);
if (tlv_len + TLV_HDR_SIZE > len) {
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
@@ -142,7 +157,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
buf += TLV_HDR_SIZE;
len -= TLV_HDR_SIZE;
- switch (ntohs(tlv.type)) {
+ switch (tlv_type) {
case TLV_TYPE_EXTSTATUS:
case TLV_TYPE_RETURNEDPDU:
case TLV_TYPE_RETURNEDMSG:
@@ -172,8 +187,8 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
break;
default:
if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
- send_notification_nbr(nbr, S_UNKNOWN_TLV,
- msg.id, msg.type);
+ send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
+ msg.id, msg.type, tlv_type, tlv_len, buf);
/* ignore unknown tlv */
break;
}
@@ -181,9 +196,11 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
len -= tlv_len;
}
- if (nm.status_code == S_PW_STATUS) {
+ /* sanity checks */
+ switch (nm.status_code) {
+ case S_PW_STATUS:
if (!(nm.flags & (F_NOTIF_PW_STATUS|F_NOTIF_FEC))) {
- send_notification_nbr(nbr, S_MISS_MSG,
+ send_notification(nbr->tcp, S_MISS_MSG,
msg.id, msg.type);
return (-1);
}
@@ -192,15 +209,28 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
case MAP_TYPE_PWID:
break;
default:
- send_notification_nbr(nbr, S_BAD_TLV_VAL,
+ send_notification(nbr->tcp, S_BAD_TLV_VAL,
+ msg.id, msg.type);
+ return (-1);
+ }
+ break;
+ case S_ENDOFLIB:
+ if (!(nm.flags & F_NOTIF_FEC)) {
+ send_notification(nbr->tcp, S_MISS_MSG,
msg.id, msg.type);
return (-1);
}
+ if (nm.fec.type != MAP_TYPE_TYPED_WCARD) {
+ send_notification(nbr->tcp, S_BAD_TLV_VAL,
+ msg.id, msg.type);
+ return (-1);
+ }
+ break;
+ default:
+ break;
}
- debug_msg_recv("notification: lsr-id %s: %s%s", inet_ntoa(nbr->id),
- status_code_name(ntohl(st.status_code)),
- (st.status_code & htonl(STATUS_FATAL)) ? " (fatal)" : "");
+ log_msg_notification(0, nbr, &nm);
if (st.status_code & htonl(STATUS_FATAL)) {
if (nbr->state == NBR_STA_OPENSENT)
@@ -210,9 +240,16 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
return (-1);
}
- if (nm.status_code == S_PW_STATUS)
+ /* lde needs to know about a few notification messages */
+ switch (nm.status_code) {
+ case S_PW_STATUS:
+ case S_ENDOFLIB:
ldpe_imsg_compose_lde(IMSG_NOTIFICATION, nbr->peerid, 0,
&nm, sizeof(nm));
+ break;
+ default:
+ break;
+ }
return (0);
}
@@ -236,3 +273,42 @@ gen_status_tlv(struct ibuf *buf, uint32_t status_code, uint32_t msg_id,
return (ibuf_add(buf, &st, STATUS_SIZE));
}
+
+static int
+gen_returned_tlvs(struct ibuf *buf, uint16_t type, uint16_t length,
+ char *tlv_data)
+{
+ struct tlv rtlvs;
+ struct tlv tlv;
+ int err;
+
+ rtlvs.type = htons(TLV_TYPE_RETURNED_TLVS);
+ rtlvs.length = htons(length + TLV_HDR_SIZE);
+ tlv.type = htons(type);
+ tlv.length = htons(length);
+
+ err = ibuf_add(buf, &rtlvs, sizeof(rtlvs));
+ err |= ibuf_add(buf, &tlv, sizeof(tlv));
+ err |= ibuf_add(buf, tlv_data, length);
+
+ return (err);
+}
+
+void
+log_msg_notification(int out, struct nbr *nbr, struct notify_msg *nm)
+{
+ if (nm->status_code & STATUS_FATAL) {
+ debug_msg(out, "notification: lsr-id %s, status %s "
+ "(fatal error)", inet_ntoa(nbr->id),
+ status_code_name(nm->status_code));
+ return;
+ }
+
+ debug_msg(out, "notification: lsr-id %s, status %s",
+ inet_ntoa(nbr->id), status_code_name(nm->status_code));
+ if (nm->flags & F_NOTIF_FEC)
+ debug_msg(out, "notification: fec %s", log_map(&nm->fec));
+ if (nm->flags & F_NOTIF_PW_STATUS)
+ debug_msg(out, "notification: pw-status %s",
+ (nm->pw_status) ? "not forwarding" : "forwarding");
+}
diff --git a/ldpd/packet.c b/ldpd/packet.c
index b085cac055..a7be0f6b42 100644
--- a/ldpd/packet.c
+++ b/ldpd/packet.c
@@ -519,13 +519,7 @@ session_read(struct thread *thread)
return (0);
}
break;
- case MSG_TYPE_ADDR:
- case MSG_TYPE_ADDRWITHDRAW:
- case MSG_TYPE_LABELMAPPING:
- case MSG_TYPE_LABELREQUEST:
- case MSG_TYPE_LABELWITHDRAW:
- case MSG_TYPE_LABELRELEASE:
- case MSG_TYPE_LABELABORTREQ:
+ default:
if (nbr->state != NBR_STA_OPER) {
session_shutdown(nbr, S_SHUTDOWN,
msg->id, msg->type);
@@ -533,8 +527,6 @@ session_read(struct thread *thread)
return (0);
}
break;
- default:
- break;
}
/* switch LDP packet type */
@@ -548,6 +540,9 @@ session_read(struct thread *thread)
case MSG_TYPE_KEEPALIVE:
ret = recv_keepalive(nbr, pdu, msg_size);
break;
+ case MSG_TYPE_CAPABILITY:
+ ret = recv_capability(nbr, pdu, msg_size);
+ break;
case MSG_TYPE_ADDR:
case MSG_TYPE_ADDRWITHDRAW:
ret = recv_address(nbr, pdu, msg_size);
@@ -564,7 +559,7 @@ session_read(struct thread *thread)
log_debug("%s: unknown LDP message from nbr %s",
__func__, inet_ntoa(nbr->id));
if (!(ntohs(msg->type) & UNKNOWN_FLAG))
- send_notification_nbr(nbr,
+ send_notification(nbr->tcp,
S_UNKNOWN_MSG, msg->id, msg->type);
/* ignore the message */
ret = 0;
@@ -632,7 +627,7 @@ session_shutdown(struct nbr *nbr, uint32_t status, uint32_t msg_id,
case NBR_STA_OPER:
log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
- send_notification_nbr(nbr, status, msg_id, msg_type);
+ send_notification(nbr->tcp, status, msg_id, msg_type);
nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
break;
@@ -788,7 +783,7 @@ pending_conn_timeout(struct thread *thread)
* notification message reliably.
*/
tcp = tcp_new(pconn->fd, NULL);
- send_notification(S_NO_HELLO, tcp, 0, 0);
+ send_notification(tcp, S_NO_HELLO, 0, 0);
msgbuf_write(&tcp->wbuf.wbuf);
pending_conn_del(pconn);
diff --git a/ldpd/pfkey.c b/ldpd/pfkey.c
index 29f763e6a6..88a778cccc 100644
--- a/ldpd/pfkey.c
+++ b/ldpd/pfkey.c
@@ -131,7 +131,7 @@ pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
sa.sadb_sa_exttype = SADB_EXT_SA;
sa.sadb_sa_len = sizeof(sa) / 8;
sa.sadb_sa_replay = 0;
- sa.sadb_sa_spi = spi;
+ sa.sadb_sa_spi = htonl(spi);
sa.sadb_sa_state = SADB_SASTATE_MATURE;
break;
}
@@ -280,7 +280,7 @@ pfkey_read(int sd, struct sadb_msg *h)
}
static int
-pfkey_reply(int sd, uint32_t *spip)
+pfkey_reply(int sd, uint32_t *spi)
{
struct sadb_msg hdr, *msg;
struct sadb_ext *ext;
@@ -317,7 +317,7 @@ pfkey_reply(int sd, uint32_t *spip)
}
if (hdr.sadb_msg_type == SADB_GETSPI) {
- if (spip == NULL) {
+ if (spi == NULL) {
explicit_bzero(data, len);
free(data);
return (0);
@@ -331,7 +331,7 @@ pfkey_reply(int sd, uint32_t *spip)
ext->sadb_ext_len * PFKEY2_CHUNK)) {
if (ext->sadb_ext_type == SADB_EXT_SA) {
sa = (struct sadb_sa *) ext;
- *spip = sa->sadb_sa_spi;
+ *spi = ntohl(sa->sadb_sa_spi);
break;
}
}