Merge pull request #249 from opensourcerouting/ldpd-rfcs

ldpd: implement new RFCs and other assorted enhancements
This commit is contained in:
Donald Sharp 2017-03-04 21:04:46 -05:00 committed by GitHub
commit e4e41e3277
19 changed files with 1304 additions and 300 deletions

View File

@ -26,10 +26,14 @@
static void send_address(struct nbr *, int, struct if_addr_head *, static void send_address(struct nbr *, int, struct if_addr_head *,
unsigned int, int); unsigned int, int);
static int gen_address_list_tlv(struct ibuf *, uint16_t, int, static int gen_address_list_tlv(struct ibuf *, int, struct if_addr_head *,
struct if_addr_head *, unsigned int); 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_add(struct if_addr_head *, struct if_addr *);
static void address_list_clr(struct if_addr_head *); 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 static void
send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list, 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; size -= LDP_HDR_SIZE;
err |= gen_msg_hdr(buf, msg_type, size); err |= gen_msg_hdr(buf, msg_type, size);
size -= LDP_MSG_SIZE; size -= LDP_MSG_SIZE;
err |= gen_address_list_tlv(buf, size, af, addr_list, err |= gen_address_list_tlv(buf, af, addr_list, tlv_addr_count);
tlv_addr_count);
if (err) { if (err) {
address_list_clr(addr_list); address_list_clr(addr_list);
ibuf_free(buf); 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) { while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
debug_msg_send("%s: lsr-id %s address %s", log_msg_address(1, msg_type, nbr, af, &if_addr->addr);
msg_name(msg_type), inet_ntoa(nbr->id),
log_addr(af, &if_addr->addr));
LIST_REMOVE(if_addr, entry); LIST_REMOVE(if_addr, entry);
free(if_addr); free(if_addr);
@ -137,16 +138,63 @@ send_address_all(struct nbr *nbr, int af)
send_address(nbr, af, &addr_list, addr_count, 0); 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 int
recv_address(struct nbr *nbr, char *buf, uint16_t len) recv_address(struct nbr *nbr, char *buf, uint16_t len)
{ {
struct ldp_msg msg; struct ldp_msg msg;
uint16_t msg_type; uint16_t msg_type;
struct address_list_tlv alt;
enum imsg_type type; enum imsg_type type;
struct address_list_tlv alt;
uint16_t alt_len;
uint16_t alt_family;
struct lde_addr lde_addr; struct lde_addr lde_addr;
memcpy(&msg, buf, sizeof(msg)); 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; buf += LDP_MSG_SIZE;
len -= 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); session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
return (-1); return (-1);
} }
memcpy(&alt, buf, sizeof(alt)); 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); session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
return (-1); return (-1);
} }
if (ntohs(alt.type) != TLV_TYPE_ADDRLIST) { 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); return (-1);
} }
switch (ntohs(alt.family)) { switch (alt_family) {
case AF_IPV4: case AF_IPV4:
if (!nbr->v4_enabled) if (!nbr->v4_enabled)
/* just ignore the message */ /* just ignore the message */
@ -177,22 +226,18 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
return (0); return (0);
break; break;
default: 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); return (-1);
} }
alt_len -= sizeof(alt.family);
buf += sizeof(alt); buf += sizeof(alt);
len -= sizeof(alt); len -= sizeof(alt);
msg_type = ntohs(msg.type); /* Process all received addresses */
if (msg_type == MSG_TYPE_ADDR) while (alt_len > 0) {
type = IMSG_ADDRESS_ADD; switch (alt_family) {
else
type = IMSG_ADDRESS_DEL;
while (len > 0) {
switch (ntohs(alt.family)) {
case AF_IPV4: 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, session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
msg.type); msg.type);
return (-1); return (-1);
@ -204,9 +249,10 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
buf += sizeof(struct in_addr); buf += sizeof(struct in_addr);
len -= sizeof(struct in_addr); len -= sizeof(struct in_addr);
alt_len -= sizeof(struct in_addr);
break; break;
case AF_IPV6: 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, session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
msg.type); msg.type);
return (-1); return (-1);
@ -218,24 +264,57 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
buf += sizeof(struct in6_addr); buf += sizeof(struct in6_addr);
len -= sizeof(struct in6_addr); len -= sizeof(struct in6_addr);
alt_len -= sizeof(struct in6_addr);
break; break;
default: default:
fatalx("recv_address: unknown af"); fatalx("recv_address: unknown af");
} }
debug_msg_recv("%s: lsr-id %s address %s", msg_name(msg_type), log_msg_address(0, msg_type, nbr, lde_addr.af, &lde_addr.addr);
inet_ntoa(nbr->id), log_addr(lde_addr.af, &lde_addr.addr));
ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr, ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr,
sizeof(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); return (0);
} }
static int static int
gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af, gen_address_list_tlv(struct ibuf *buf, int af, struct if_addr_head *addr_list,
struct if_addr_head *addr_list, unsigned int tlv_addr_count) unsigned int tlv_addr_count)
{ {
struct address_list_tlv alt; struct address_list_tlv alt;
uint16_t addr_size; uint16_t addr_size;
@ -243,8 +322,7 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
int err = 0; int err = 0;
memset(&alt, 0, sizeof(alt)); memset(&alt, 0, sizeof(alt));
alt.type = TLV_TYPE_ADDRLIST; alt.type = htons(TLV_TYPE_ADDRLIST);
alt.length = htons(size - TLV_HDR_SIZE);
switch (af) { switch (af) {
case AF_INET: case AF_INET:
@ -258,8 +336,12 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
default: default:
fatalx("gen_address_list_tlv: unknown af"); 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)); err |= ibuf_add(buf, &alt, sizeof(alt));
if (addr_list == NULL)
return (err);
LIST_FOREACH(if_addr, addr_list, entry) { LIST_FOREACH(if_addr, addr_list, entry) {
err |= ibuf_add(buf, &if_addr->addr, addr_size); err |= ibuf_add(buf, &if_addr->addr, addr_size);
if (--tlv_addr_count == 0) if (--tlv_addr_count == 0)
@ -269,6 +351,23 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af,
return (err); 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 static void
address_list_add(struct if_addr_head *addr_list, struct if_addr *if_addr) 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); 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");
}

View File

@ -148,9 +148,10 @@ control_connbyfd(int fd)
{ {
struct ctl_conn *c; struct ctl_conn *c;
for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd; TAILQ_FOREACH(c, &ctl_conns, entry) {
c = TAILQ_NEXT(c, entry)) if (c->iev.ibuf.fd == fd)
; /* nothing */ break;
}
return (c); return (c);
} }
@ -160,9 +161,10 @@ control_connbypid(pid_t pid)
{ {
struct ctl_conn *c; struct ctl_conn *c;
for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.pid != pid; TAILQ_FOREACH(c, &ctl_conns, entry) {
c = TAILQ_NEXT(c, entry)) if (c->iev.ibuf.pid == pid)
; /* nothing */ break;
}
return (c); return (c);
} }

View File

@ -24,6 +24,9 @@
#include "ldp_debug.h" #include "ldp_debug.h"
static int gen_init_prms_tlv(struct ibuf *, struct nbr *); 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 void
send_init(struct nbr *nbr) 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)); 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) if ((buf = ibuf_open(size)) == NULL)
fatal(__func__); fatal(__func__);
err |= gen_ldp_hdr(buf, size); err |= gen_ldp_hdr(buf, size);
size -= LDP_HDR_SIZE; size -= LDP_HDR_SIZE;
err |= gen_msg_hdr(buf, MSG_TYPE_INIT, size); err |= gen_msg_hdr(buf, MSG_TYPE_INIT, size);
size -= LDP_MSG_SIZE;
err |= gen_init_prms_tlv(buf, nbr); 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) { if (err) {
ibuf_free(buf); ibuf_free(buf);
return; return;
@ -57,6 +63,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
struct ldp_msg msg; struct ldp_msg msg;
struct sess_prms_tlv sess; struct sess_prms_tlv sess;
uint16_t max_pdu_len; uint16_t max_pdu_len;
int caps_rcvd = 0;
debug_msg_recv("initialization: lsr-id %s", inet_ntoa(nbr->id)); 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 */ /* Optional Parameters */
while (len > 0) { while (len > 0) {
struct tlv tlv; struct tlv tlv;
uint16_t tlv_type;
uint16_t tlv_len; uint16_t tlv_len;
if (len < sizeof(tlv)) { if (len < sizeof(tlv)) {
@ -101,6 +109,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
} }
memcpy(&tlv, buf, TLV_HDR_SIZE); memcpy(&tlv, buf, TLV_HDR_SIZE);
tlv_type = ntohs(tlv.type);
tlv_len = ntohs(tlv.length); tlv_len = ntohs(tlv.length);
if (tlv_len + TLV_HDR_SIZE > len) { if (tlv_len + TLV_HDR_SIZE > len) {
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 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; buf += TLV_HDR_SIZE;
len -= 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: case TLV_TYPE_ATMSESSIONPAR:
session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type); session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
return (-1); return (-1);
case TLV_TYPE_FRSESSION: case TLV_TYPE_FRSESSION:
session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type); session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type);
return (-1); 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: default:
if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
send_notification_nbr(nbr, S_UNKNOWN_TLV, send_notification_rtlvs(nbr, S_UNSSUPORTDCAP,
msg.id, msg.type); msg.id, msg.type, tlv_type, tlv_len, buf);
/* ignore unknown tlv */ /* ignore unknown tlv */
break; break;
} }
@ -145,6 +218,164 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
return (0); 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 static int
gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr) 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)); 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));
}

View File

@ -152,6 +152,33 @@ l2vpn_if_find_name(struct l2vpn *l2vpn, const char *ifname)
return (RB_FIND(l2vpn_if_head, &l2vpn->if_tree, &lif)); 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 static __inline int
l2vpn_pw_compare(struct l2vpn_pw *a, struct l2vpn_pw *b) 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.status_code = S_WRONG_CBIT;
st.msg_id = map->msg_id; st.msg_id = map->msg_id;
st.msg_type = htons(MSG_TYPE_LABELMAPPING); 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; pw->flags &= ~F_PW_CWORD;
lde_send_labelmapping(ln, fn, 1); 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 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; 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); lde_fec2map(fec, &nm.fec);
nm.flags |= F_NOTIF_FEC; nm.flags |= F_NOTIF_FEC;
lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0, lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm,
&nm, sizeof(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 void
@ -376,9 +422,11 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
struct fec_nh *fnh; struct fec_nh *fnh;
struct l2vpn_pw *pw; struct l2vpn_pw *pw;
/* TODO group wildcard */ if (nm->fec.type == MAP_TYPE_TYPED_WCARD ||
if (!(nm->fec.flags & F_MAP_PW_ID)) !(nm->fec.flags & F_MAP_PW_ID)) {
l2vpn_recv_pw_status_wcard(ln, nm);
return; return;
}
lde_map2fec(&nm->fec, ln->id, &fec); lde_map2fec(&nm->fec, ln->id, &fec);
fn = (struct fec_node *)fec_find(&ft, &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 */ /* remote status didn't change */
if (pw->remote_status == nm->pw_status) if (pw->remote_status == nm->pw_status)
return; return;
pw->remote_status = nm->pw_status; pw->remote_status = nm->pw_status;
if (l2vpn_pw_ok(pw, fnh)) 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); 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 void
l2vpn_sync_pws(int af, union ldpd_addr *addr) l2vpn_sync_pws(int af, union ldpd_addr *addr)
{ {

View File

@ -28,9 +28,8 @@
static void enqueue_pdu(struct nbr *, struct ibuf *, uint16_t); static void enqueue_pdu(struct nbr *, struct ibuf *, uint16_t);
static int gen_label_tlv(struct ibuf *, uint32_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 int gen_reqid_tlv(struct ibuf *, uint32_t);
static void log_msg_mapping(int, uint16_t, struct nbr *, struct map *);
static void static void
enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size) 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 */ /* calculate size */
msg_size = LDP_MSG_SIZE + TLV_HDR_SIZE; msg_size = LDP_MSG_SIZE;
switch (me->map.type) { msg_size += len_fec_tlv(&me->map);
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;
}
if (me->map.label != NO_LABEL) if (me->map.label != NO_LABEL)
msg_size += LABEL_TLV_SIZE; msg_size += LABEL_TLV_SIZE;
if (me->map.flags & F_MAP_REQ_ID) 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; return;
} }
debug_msg_send("%s: lsr-id %s fec %s label %s", msg_name(type), log_msg_mapping(1, type, nbr, &me->map);
inet_ntoa(nbr->id), log_map(&me->map),
log_label(me->map.label));
TAILQ_REMOVE(mh, me, entry); TAILQ_REMOVE(mh, me, entry);
free(me); 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 label = NO_LABEL, reqid = 0;
uint32_t pw_status = 0; uint32_t pw_status = 0;
uint8_t flags = 0; uint8_t flags = 0;
int feclen, lbllen, tlen; int feclen, tlen;
uint16_t current_tlv = 1;
struct mapping_entry *me; struct mapping_entry *me;
struct mapping_head mh; struct mapping_head mh;
struct map map; 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)); memcpy(&ft, buf, sizeof(ft));
if (ntohs(ft.type) != TLV_TYPE_FEC) { 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); return (-1);
} }
feclen = ntohs(ft.length); 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) && !(map.flags & F_MAP_PW_ID) &&
type != MSG_TYPE_LABELWITHDRAW && type != MSG_TYPE_LABELWITHDRAW &&
type != MSG_TYPE_LABELRELEASE) { type != MSG_TYPE_LABELRELEASE) {
send_notification_nbr(nbr, S_MISS_MSG, msg.id, send_notification(nbr->tcp, S_MISS_MSG, msg.id,
msg.type); msg.type);
return (-1); goto err;
} }
/* /*
@ -209,6 +190,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 * LDP supports the use of multiple FEC Elements per
* FEC for the Label Mapping message only. * 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; feclen -= tlen;
} while (feclen > 0); } 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 */ /* Optional Parameters */
while (len > 0) { while (len > 0) {
struct tlv tlv; struct tlv tlv;
uint16_t tlv_type;
uint16_t tlv_len; uint16_t tlv_len;
uint32_t reqbuf, labelbuf, statusbuf; 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); memcpy(&tlv, buf, TLV_HDR_SIZE);
tlv_type = ntohs(tlv.type);
tlv_len = ntohs(tlv.length); tlv_len = ntohs(tlv.length);
if (tlv_len + TLV_HDR_SIZE > len) { if (tlv_len + TLV_HDR_SIZE > len) {
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 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; buf += TLV_HDR_SIZE;
len -= 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: case TLV_TYPE_LABELREQUEST:
switch (type) { switch (type) {
case MSG_TYPE_LABELMAPPING: case MSG_TYPE_LABELMAPPING:
@ -282,6 +284,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
break; break;
case TLV_TYPE_GENERICLABEL: case TLV_TYPE_GENERICLABEL:
switch (type) { switch (type) {
case MSG_TYPE_LABELMAPPING:
case MSG_TYPE_LABELWITHDRAW: case MSG_TYPE_LABELWITHDRAW:
case MSG_TYPE_LABELRELEASE: case MSG_TYPE_LABELRELEASE:
if (tlv_len != LABEL_TLV_LEN) { 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)); memcpy(&labelbuf, buf, sizeof(labelbuf));
label = ntohl(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; break;
default: default:
/* ignore */ /* 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_ATMLABEL:
case TLV_TYPE_FRLABEL: case TLV_TYPE_FRLABEL:
switch (type) { switch (type) {
case MSG_TYPE_LABELMAPPING:
case MSG_TYPE_LABELWITHDRAW: case MSG_TYPE_LABELWITHDRAW:
case MSG_TYPE_LABELRELEASE: case MSG_TYPE_LABELRELEASE:
/* unsupported */ /* unsupported */
@ -341,13 +355,14 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
break; break;
default: default:
if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
send_notification_nbr(nbr, S_UNKNOWN_TLV, send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
msg.id, msg.type); msg.id, msg.type, tlv_type, tlv_len, buf);
/* ignore unknown tlv */ /* ignore unknown tlv */
break; break;
} }
buf += tlv_len; buf += tlv_len;
len -= tlv_len; len -= tlv_len;
current_tlv++;
} }
/* notify lde about the received message. */ /* 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) if (me->map.flags & F_MAP_REQ_ID)
me->map.requestid = reqid; me->map.requestid = reqid;
debug_msg_recv("%s: lsr-id %s fec %s label %s", msg_name(type), log_msg_mapping(0, type, nbr, &me->map);
inet_ntoa(nbr->id), log_map(&me->map),
log_label(me->map.label));
switch (type) { switch (type) {
case MSG_TYPE_LABELMAPPING: 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, ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map,
sizeof(struct map)); sizeof(struct map));
next: next:
TAILQ_REMOVE(&mh, me, entry); TAILQ_REMOVE(&mh, me, entry);
free(me); free(me);
} }
return (0); return (0);
err: err:
mapping_list_clr(&mh); mapping_list_clr(&mh);
return (-1); return (-1);
@ -449,53 +462,6 @@ gen_label_tlv(struct ibuf *buf, uint32_t label)
return (ibuf_add(buf, &lt, sizeof(lt))); return (ibuf_add(buf, &lt, sizeof(lt)));
} }
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 static int
gen_reqid_tlv(struct ibuf *buf, uint32_t reqid) gen_reqid_tlv(struct ibuf *buf, uint32_t reqid)
{ {
@ -520,12 +486,52 @@ gen_pw_status_tlv(struct ibuf *buf, uint32_t status)
return (ibuf_add(buf, &st, sizeof(st))); 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 int
gen_fec_tlv(struct ibuf *buf, struct map *map) gen_fec_tlv(struct ibuf *buf, struct map *map)
{ {
struct tlv ft; struct tlv ft;
uint16_t family, len, pw_type, ifmtu; uint16_t family, len, pw_type, ifmtu;
uint8_t pw_len = 0; uint8_t pw_len = 0, twcard_len;
uint32_t group_id, pwid; uint32_t group_id, pwid;
int err = 0; int err = 0;
@ -562,7 +568,7 @@ gen_fec_tlv(struct ibuf *buf, struct map *map)
break; break;
case MAP_TYPE_PWID: case MAP_TYPE_PWID:
if (map->flags & F_MAP_PW_ID) 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) if (map->flags & F_MAP_PW_IFMTU)
pw_len += FEC_SUBTLV_IFMTU_SIZE; 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)); err |= ibuf_add(buf, &ifmtu, sizeof(uint16_t));
} }
break; 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: default:
break; 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 len, struct map *map)
{ {
uint16_t off = 0; uint16_t off = 0;
uint8_t pw_len; uint8_t pw_len, twcard_len;
map->type = *buf; map->type = *buf;
off += sizeof(uint8_t); 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; map->fec.prefix.af = AF_INET6;
break; break;
default: default:
send_notification_nbr(nbr, S_UNSUP_ADDR, msg->id, send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id,
msg->type); msg->type);
return (-1); return (-1);
} }
@ -751,11 +801,84 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf,
pw_len -= stlv.length; pw_len -= stlv.length;
} }
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); return (off);
default: default:
send_notification_nbr(nbr, S_UNKNOWN_FEC, msg->id, msg->type); send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type);
break; break;
} }
return (-1); 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));
}

View File

@ -37,7 +37,7 @@
static void lde_shutdown(void); static void lde_shutdown(void);
static int lde_dispatch_imsg(struct thread *); static int lde_dispatch_imsg(struct thread *);
static int lde_dispatch_parent(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 *); struct lde_nbr *);
static struct lde_nbr *lde_nbr_new(uint32_t, struct lde_nbr *); static struct lde_nbr *lde_nbr_new(uint32_t, struct lde_nbr *);
static void lde_nbr_del(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 imsgbuf *ibuf = &iev->ibuf;
struct imsg imsg; struct imsg imsg;
struct lde_nbr *ln; struct lde_nbr *ln;
struct map map; struct map *map;
struct lde_addr lde_addr; struct lde_addr *lde_addr;
struct notify_msg nm; struct notify_msg *nm;
ssize_t n; ssize_t n;
int shut = 0; int shut = 0;
@ -240,9 +240,10 @@ lde_dispatch_imsg(struct thread *thread)
case IMSG_LABEL_RELEASE: case IMSG_LABEL_RELEASE:
case IMSG_LABEL_WITHDRAW: case IMSG_LABEL_WITHDRAW:
case IMSG_LABEL_ABORT: 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"); fatalx("lde_dispatch_imsg: wrong imsg len");
memcpy(&map, imsg.data, sizeof(map)); map = imsg.data;
ln = lde_nbr_find(imsg.hdr.peerid); ln = lde_nbr_find(imsg.hdr.peerid);
if (ln == NULL) { if (ln == NULL) {
@ -253,22 +254,16 @@ lde_dispatch_imsg(struct thread *thread)
switch (imsg.hdr.type) { switch (imsg.hdr.type) {
case IMSG_LABEL_MAPPING: case IMSG_LABEL_MAPPING:
lde_check_mapping(&map, ln); lde_check_mapping(map, ln);
break; break;
case IMSG_LABEL_REQUEST: case IMSG_LABEL_REQUEST:
lde_check_request(&map, ln); lde_check_request(map, ln);
break; break;
case IMSG_LABEL_RELEASE: case IMSG_LABEL_RELEASE:
if (map.type == MAP_TYPE_WILDCARD) lde_check_release(map, ln);
lde_check_release_wcard(&map, ln);
else
lde_check_release(&map, ln);
break; break;
case IMSG_LABEL_WITHDRAW: case IMSG_LABEL_WITHDRAW:
if (map.type == MAP_TYPE_WILDCARD) lde_check_withdraw(map, ln);
lde_check_withdraw_wcard(&map, ln);
else
lde_check_withdraw(&map, ln);
break; break;
case IMSG_LABEL_ABORT: case IMSG_LABEL_ABORT:
/* not necessary */ /* not necessary */
@ -276,9 +271,10 @@ lde_dispatch_imsg(struct thread *thread)
} }
break; break;
case IMSG_ADDRESS_ADD: 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"); 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); ln = lde_nbr_find(imsg.hdr.peerid);
if (ln == NULL) { if (ln == NULL) {
@ -286,16 +282,17 @@ lde_dispatch_imsg(struct thread *thread)
__func__); __func__);
break; 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 " log_debug("%s: cannot add address %s, it "
"already exists", __func__, "already exists", __func__,
log_addr(lde_addr.af, &lde_addr.addr)); log_addr(lde_addr->af, &lde_addr->addr));
} }
break; break;
case IMSG_ADDRESS_DEL: 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"); 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); ln = lde_nbr_find(imsg.hdr.peerid);
if (ln == NULL) { if (ln == NULL) {
@ -303,16 +300,17 @@ lde_dispatch_imsg(struct thread *thread)
__func__); __func__);
break; 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 " log_debug("%s: cannot delete address %s, it "
"does not exist", __func__, "does not exist", __func__,
log_addr(lde_addr.af, &lde_addr.addr)); log_addr(lde_addr->af, &lde_addr->addr));
} }
break; break;
case IMSG_NOTIFICATION: 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"); fatalx("lde_dispatch_imsg: wrong imsg len");
memcpy(&nm, imsg.data, sizeof(nm)); nm = imsg.data;
ln = lde_nbr_find(imsg.hdr.peerid); ln = lde_nbr_find(imsg.hdr.peerid);
if (ln == NULL) { if (ln == NULL) {
@ -321,10 +319,17 @@ lde_dispatch_imsg(struct thread *thread)
break; break;
} }
switch (nm.status_code) { switch (nm->status_code) {
case S_PW_STATUS: case S_PW_STATUS:
l2vpn_recv_pw_status(ln, &nm); l2vpn_recv_pw_status(ln, nm);
break; 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: default:
break; break;
} }
@ -391,7 +396,7 @@ lde_dispatch_parent(struct thread *thread)
struct l2vpn_if *nlif; struct l2vpn_if *nlif;
struct l2vpn_pw *npw; struct l2vpn_pw *npw;
struct imsg imsg; struct imsg imsg;
struct kroute kr; struct kroute *kr;
int fd = THREAD_FD(thread); int fd = THREAD_FD(thread);
struct imsgev *iev = THREAD_ARG(thread); struct imsgev *iev = THREAD_ARG(thread);
struct imsgbuf *ibuf = &iev->ibuf; struct imsgbuf *ibuf = &iev->ibuf;
@ -415,22 +420,23 @@ lde_dispatch_parent(struct thread *thread)
switch (imsg.hdr.type) { switch (imsg.hdr.type) {
case IMSG_NETWORK_ADD: case IMSG_NETWORK_ADD:
case IMSG_NETWORK_UPDATE: 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__); log_warnx("%s: wrong imsg len", __func__);
break; break;
} }
memcpy(&kr, imsg.data, sizeof(kr)); kr = imsg.data;
switch (kr.af) { switch (kr->af) {
case AF_INET: case AF_INET:
fec.type = FEC_TYPE_IPV4; fec.type = FEC_TYPE_IPV4;
fec.u.ipv4.prefix = kr.prefix.v4; fec.u.ipv4.prefix = kr->prefix.v4;
fec.u.ipv4.prefixlen = kr.prefixlen; fec.u.ipv4.prefixlen = kr->prefixlen;
break; break;
case AF_INET6: case AF_INET6:
fec.type = FEC_TYPE_IPV6; fec.type = FEC_TYPE_IPV6;
fec.u.ipv6.prefix = kr.prefix.v6; fec.u.ipv6.prefix = kr->prefix.v6;
fec.u.ipv6.prefixlen = kr.prefixlen; fec.u.ipv6.prefixlen = kr->prefixlen;
break; break;
default: default:
fatalx("lde_dispatch_parent: unknown af"); fatalx("lde_dispatch_parent: unknown af");
@ -438,9 +444,9 @@ lde_dispatch_parent(struct thread *thread)
switch (imsg.hdr.type) { switch (imsg.hdr.type) {
case IMSG_NETWORK_ADD: case IMSG_NETWORK_ADD:
lde_kernel_insert(&fec, kr.af, &kr.nexthop, lde_kernel_insert(&fec, kr->af, &kr->nexthop,
kr.ifindex, kr.priority, kr->ifindex, kr->priority,
kr.flags & F_CONNECTED, NULL); kr->flags & F_CONNECTED, NULL);
break; break;
case IMSG_NETWORK_UPDATE: case IMSG_NETWORK_UPDATE:
lde_kernel_update(&fec); lde_kernel_update(&fec);
@ -929,8 +935,8 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
} }
void void
lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label, lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn,
struct status_tlv *st) struct map *wcard, struct status_tlv *st)
{ {
struct lde_wdraw *lw; struct lde_wdraw *lw;
struct map map; struct map map;
@ -959,11 +965,8 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label,
break; break;
} }
map.label = fn->local_label; map.label = fn->local_label;
} else { } else
memset(&map, 0, sizeof(map)); memcpy(&map, wcard, sizeof(map));
map.type = MAP_TYPE_WILDCARD;
map.label = label;
}
if (st) { if (st) {
map.st.status_code = st->status_code; 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 = lde_wdraw_add(ln, fn);
lw->label = map.label; lw->label = map.label;
} else { } else {
struct lde_map *me;
RB_FOREACH(f, fec_tree, &ft) { RB_FOREACH(f, fec_tree, &ft) {
fn = (struct fec_node *)f; 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, lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw,
&fn->fec); &fn->fec);
@ -997,16 +1005,62 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label,
} }
void 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) memset(&wcard, 0, sizeof(wcard));
lde_send_labelwithdraw(ln, fn, label, NULL); wcard.type = MAP_TYPE_WILDCARD;
wcard.label = label;
lde_send_labelwithdraw(ln, NULL, &wcard, NULL);
} }
void void
lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label) 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_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 map map;
struct l2vpn_pw *pw; 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; map.flags |= F_MAP_PW_CWORD;
break; break;
} }
} else { } else
memset(&map, 0, sizeof(map)); memcpy(&map, wcard, sizeof(map));
map.type = MAP_TYPE_WILDCARD;
}
map.label = label; map.label = label;
lde_imsg_compose_ldpe(IMSG_RELEASE_ADD, ln->peerid, 0, 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 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) uint16_t msg_type)
{ {
struct notify_msg nm; 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_id = msg_id;
nm.msg_type = msg_type; 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)); &nm, sizeof(nm));
} }
@ -1076,6 +1160,7 @@ lde_nbr_new(uint32_t peerid, struct lde_nbr *new)
ln->id = new->id; ln->id = new->id;
ln->v4_enabled = new->v4_enabled; ln->v4_enabled = new->v4_enabled;
ln->v6_enabled = new->v6_enabled; ln->v6_enabled = new->v6_enabled;
ln->flags = new->flags;
ln->peerid = peerid; ln->peerid = peerid;
fec_init(&ln->recv_map); fec_init(&ln->recv_map);
fec_init(&ln->sent_map); fec_init(&ln->sent_map);
@ -1352,13 +1437,11 @@ lde_change_egress_label(int af)
/* explicitly withdraw all null labels */ /* explicitly withdraw all null labels */
RB_FOREACH(ln, nbr_tree, &lde_nbrs) { 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) if (ln->v4_enabled)
lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IPV4NULL, lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV4NULL);
NULL);
if (ln->v6_enabled) if (ln->v6_enabled)
lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IPV6NULL, lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV6NULL);
NULL);
} }
/* update label of connected routes */ /* update label of connected routes */

View File

@ -90,6 +90,7 @@ struct lde_nbr {
struct in_addr id; struct in_addr id;
int v4_enabled; /* announce/process v4 msgs */ int v4_enabled; /* announce/process v4 msgs */
int v6_enabled; /* announce/process v6 msgs */ int v6_enabled; /* announce/process v6 msgs */
int flags; /* capabilities */
struct fec_tree recv_req; struct fec_tree recv_req;
struct fec_tree sent_req; struct fec_tree sent_req;
struct fec_tree recv_map; 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 *, void lde_send_labelmapping(struct lde_nbr *, struct fec_node *,
int); int);
void lde_send_labelwithdraw(struct lde_nbr *, struct fec_node *, void lde_send_labelwithdraw(struct lde_nbr *, struct fec_node *,
uint32_t, struct status_tlv *); struct map *, struct status_tlv *);
void lde_send_labelwithdraw_all(struct fec_node *, uint32_t); void lde_send_labelwithdraw_wcard(struct lde_nbr *, uint32_t);
void lde_send_labelrelease(struct lde_nbr *, struct fec_node *, 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); uint32_t);
void lde_send_notification(uint32_t, uint32_t, uint32_t, uint16_t); void lde_send_labelwithdraw_pwid_wcard(struct lde_nbr *, uint16_t,
uint32_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_lsrid(struct in_addr);
struct lde_nbr *lde_nbr_find_by_addr(int, union ldpd_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); 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_kernel_update(struct fec *);
void lde_check_mapping(struct map *, struct lde_nbr *); void lde_check_mapping(struct map *, struct lde_nbr *);
void lde_check_request(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(struct map *, struct lde_nbr *);
void lde_check_release_wcard(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(struct map *, struct lde_nbr *);
void lde_check_withdraw_wcard(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 *); int lde_gc_timer(struct thread *);
void lde_gc_start_timer(void); void lde_gc_start_timer(void);
void lde_gc_stop_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_new(struct l2vpn *, struct kif *);
struct l2vpn_if *l2vpn_if_find(struct l2vpn *, unsigned int); struct l2vpn_if *l2vpn_if_find(struct l2vpn *, unsigned int);
struct l2vpn_if *l2vpn_if_find_name(struct l2vpn *, const char *); 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_new(struct l2vpn *, struct kif *);
struct l2vpn_pw *l2vpn_pw_find(struct l2vpn *, unsigned int); struct l2vpn_pw *l2vpn_pw_find(struct l2vpn *, unsigned int);
struct l2vpn_pw *l2vpn_pw_find_name(struct l2vpn *, const char *); 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_ok(struct l2vpn_pw *, struct fec_nh *);
int l2vpn_pw_negotiate(struct lde_nbr *, struct fec_node *, int l2vpn_pw_negotiate(struct lde_nbr *, struct fec_node *,
struct map *); 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(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_sync_pws(int, union ldpd_addr *);
void l2vpn_pw_ctl(pid_t); void l2vpn_pw_ctl(pid_t);
void l2vpn_binding_ctl(pid_t); void l2vpn_binding_ctl(pid_t);

View File

@ -374,7 +374,8 @@ lde_kernel_update(struct fec *fec)
} }
if (LIST_EMPTY(&fn->nexthops)) { 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->local_label = NO_LABEL;
fn->data = NULL; fn->data = NULL;
} else { } else {
@ -478,7 +479,7 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
/* LMp.10 */ /* LMp.10 */
if (me->map.label != map->label && lre == NULL) { if (me->map.label != map->label && lre == NULL) {
/* LMp.10a */ /* 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 * 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_node *fn;
struct fec_nh *fnh; 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.1: skip loop detection (not necessary) */
/* LRq.2: is there a next hop for fec? */ /* 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); fn = (struct fec_node *)fec_find(&ft, &fec);
if (fn == NULL || LIST_EMPTY(&fn->nexthops)) { if (fn == NULL || LIST_EMPTY(&fn->nexthops)) {
/* LRq.5: send No Route notification */ /* 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)); htons(MSG_TYPE_LABELREQUEST));
return; return;
} }
@ -575,8 +582,8 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
continue; continue;
/* LRq.4: send Loop Detected notification */ /* LRq.4: send Loop Detected notification */
lde_send_notification(ln->peerid, S_LOOP_DETECTED, lde_send_notification(ln, S_LOOP_DETECTED, map->msg_id,
map->msg_id, htons(MSG_TYPE_LABELREQUEST)); htons(MSG_TYPE_LABELREQUEST));
return; return;
default: default:
break; break;
@ -604,6 +611,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 void
lde_check_release(struct map *map, struct lde_nbr *ln) lde_check_release(struct map *map, struct lde_nbr *ln)
{ {
@ -612,9 +653,13 @@ lde_check_release(struct map *map, struct lde_nbr *ln)
struct lde_wdraw *lw; struct lde_wdraw *lw;
struct lde_map *me; struct lde_map *me;
/* TODO group wildcard */ /* wildcard label release */
if (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID)) 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; return;
}
lde_map2fec(map, ln->id, &fec); lde_map2fec(map, ln->id, &fec);
fn = (struct fec_node *)fec_find(&ft, &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 */ /* LRl.3: first check if we have a pending withdraw running */
lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
if (lw && (map->label == NO_LABEL || if (lw && (map->label == NO_LABEL || map->label == lw->label)) {
(lw->label != NO_LABEL && map->label == lw->label))) {
/* LRl.4: delete record of outstanding label withdraw */ /* LRl.4: delete record of outstanding label withdraw */
lde_wdraw_del(ln, lw); 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) { RB_FOREACH(f, fec_tree, &ft) {
fn = (struct fec_node *)f; 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 */ /* LRl.3: first check if we have a pending withdraw running */
lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
if (lw && (map->label == NO_LABEL || if (lw && (map->label == NO_LABEL || map->label == lw->label)) {
(lw->label != NO_LABEL && map->label == lw->label))) {
/* LRl.4: delete record of outstanding lbl withdraw */ /* LRl.4: delete record of outstanding lbl withdraw */
lde_wdraw_del(ln, lw); lde_wdraw_del(ln, lw);
} }
/* LRl.6: check sent map list and remove it if available */ /* LRl.6: check sent map list and remove it if available */
me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
if (me && if (me &&
(map->label == NO_LABEL || map->label == me->map.label)) (map->label == NO_LABEL || map->label == me->map.label))
lde_map_del(ln, me, 1); 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 lde_map *me;
struct l2vpn_pw *pw; struct l2vpn_pw *pw;
/* TODO group wildcard */ /* wildcard label withdraw */
if (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID)) 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; return;
}
lde_map2fec(map, ln->id, &fec); lde_map2fec(map, ln->id, &fec);
fn = (struct fec_node *)fec_find(&ft, &fec); fn = (struct fec_node *)fec_find(&ft, &fec);
@ -707,12 +758,15 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
default: default:
break; break;
} }
if (map->label != NO_LABEL && map->label != fnh->remote_label)
continue;
lde_send_delete_klabel(fn, fnh); lde_send_delete_klabel(fn, fnh);
fnh->remote_label = NO_LABEL; fnh->remote_label = NO_LABEL;
} }
/* LWd.2: send label release */ /* 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 */ /* LWd.3: check previously received label mapping */
me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); 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; struct lde_map *me;
/* LWd.2: send label release */ /* 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) { RB_FOREACH(f, fec_tree, &ft) {
fn = (struct fec_node *)f; 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 */ /* LWd.1: remove label from forwarding/switching use */
LIST_FOREACH(fnh, &fn->nexthops, entry) { LIST_FOREACH(fnh, &fn->nexthops, entry) {
@ -751,12 +809,15 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
default: default:
break; break;
} }
if (map->label != NO_LABEL && map->label !=
fnh->remote_label)
continue;
lde_send_delete_klabel(fn, fnh); lde_send_delete_klabel(fn, fnh);
fnh->remote_label = NO_LABEL; fnh->remote_label = NO_LABEL;
} }
/* LWd.3: check previously received label mapping */ /* LWd.3: check previously received label mapping */
me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
if (me && (map->label == NO_LABEL || if (me && (map->label == NO_LABEL ||
map->label == me->map.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 */ /* gabage collector timer: timer to remove dead entries from the LIB */
/* ARGSUSED */ /* ARGSUSED */

View File

@ -63,6 +63,7 @@
#define MSG_TYPE_HELLO 0x0100 #define MSG_TYPE_HELLO 0x0100
#define MSG_TYPE_INIT 0x0200 #define MSG_TYPE_INIT 0x0200
#define MSG_TYPE_KEEPALIVE 0x0201 #define MSG_TYPE_KEEPALIVE 0x0201
#define MSG_TYPE_CAPABILITY 0x0202 /* RFC 5561 */
#define MSG_TYPE_ADDR 0x0300 #define MSG_TYPE_ADDR 0x0300
#define MSG_TYPE_ADDRWITHDRAW 0x0301 #define MSG_TYPE_ADDRWITHDRAW 0x0301
#define MSG_TYPE_LABELMAPPING 0x0400 #define MSG_TYPE_LABELMAPPING 0x0400
@ -92,9 +93,17 @@
#define TLV_TYPE_FRSESSION 0x0502 #define TLV_TYPE_FRSESSION 0x0502
#define TLV_TYPE_LABELREQUEST 0x0600 #define TLV_TYPE_LABELREQUEST 0x0600
/* RFC 4447 */ /* 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_IF_PARAM 0x096B
#define TLV_TYPE_PW_GROUP_ID 0x096C #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 */ /* RFC 7552 */
#define TLV_TYPE_DUALSTACK 0x8701 #define TLV_TYPE_DUALSTACK 0x8701
@ -196,6 +205,10 @@ struct hello_prms_opt16_tlv {
#define S_UNASSIGN_TAI 0x00000029 #define S_UNASSIGN_TAI 0x00000029
#define S_MISCONF_ERR 0x0000002A #define S_MISCONF_ERR 0x0000002A
#define S_WITHDRAW_MTHD 0x0000002B #define S_WITHDRAW_MTHD 0x0000002B
/* RFC 5561 */
#define S_UNSSUPORTDCAP 0x0000002E
/* RFC 5919 */
#define S_ENDOFLIB 0x0000002F
/* RFC 7552 */ /* RFC 7552 */
#define S_TRANS_MISMTCH 0x80000032 #define S_TRANS_MISMTCH 0x80000032
#define S_DS_NONCMPLNCE 0x80000033 #define S_DS_NONCMPLNCE 0x80000033
@ -227,6 +240,26 @@ struct status_tlv {
#define STATUS_TLV_LEN 10 #define STATUS_TLV_LEN 10
#define STATUS_FATAL 0x80000000 #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_IPV4 0x1
#define AF_IPV6 0x2 #define AF_IPV6 0x2
@ -242,17 +275,23 @@ struct address_list_tlv {
#define FEC_ELM_WCARD_LEN 1 #define FEC_ELM_WCARD_LEN 1
#define FEC_ELM_PREFIX_MIN_LEN 4 #define FEC_ELM_PREFIX_MIN_LEN 4
#define FEC_PWID_ELM_MIN_LEN 8 #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_WILDCARD 0x01
#define MAP_TYPE_PREFIX 0x02 #define MAP_TYPE_PREFIX 0x02
#define MAP_TYPE_TYPED_WCARD 0x05
#define MAP_TYPE_PWID 0x80 #define MAP_TYPE_PWID 0x80
#define MAP_TYPE_GENPWID 0x81 #define MAP_TYPE_GENPWID 0x81
#define CONTROL_WORD_FLAG 0x8000 #define CONTROL_WORD_FLAG 0x8000
#define PW_TYPE_ETHERNET_TAGGED 0x0004 #define PW_TYPE_ETHERNET_TAGGED 0x0004
#define PW_TYPE_ETHERNET 0x0005 #define PW_TYPE_ETHERNET 0x0005
#define PW_TYPE_WILDCARD 0x7FFF
#define DEFAULT_PW_TYPE PW_TYPE_ETHERNET #define DEFAULT_PW_TYPE PW_TYPE_ETHERNET
#define PW_TWCARD_RESERVED_BIT 0x8000
/* RFC 4447 Sub-TLV record */ /* RFC 4447 Sub-TLV record */
struct subtlv { struct subtlv {
uint8_t type; uint8_t type;

View File

@ -104,6 +104,14 @@ do { \
log_debug("msg[out]: " emsg, __VA_ARGS__); \ log_debug("msg[out]: " emsg, __VA_ARGS__); \
} while (0) } 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, ...) \ #define debug_kalive_recv(emsg, ...) \
do { \ do { \
if (LDP_DEBUG(msg, MSG_RECV_ALL)) \ if (LDP_DEBUG(msg, MSG_RECV_ALL)) \

View File

@ -65,6 +65,8 @@ ifp2kif(struct interface *ifp, struct kif *kif)
strlcpy(kif->ifname, ifp->name, sizeof(kif->ifname)); strlcpy(kif->ifname, ifp->name, sizeof(kif->ifname));
kif->ifindex = ifp->ifindex; kif->ifindex = ifp->ifindex;
kif->flags = ifp->flags; kif->flags = ifp->flags;
if (ifp->ll_type == ZEBRA_LLT_ETHER)
memcpy(kif->mac, ifp->hw_addr, ETHER_ADDR_LEN);
} }
static void static void

View File

@ -27,6 +27,7 @@
#include "imsg.h" #include "imsg.h"
#include "thread.h" #include "thread.h"
#include "qobj.h" #include "qobj.h"
#include "prefix.h"
#include "filter.h" #include "filter.h"
#include "ldp.h" #include "ldp.h"
@ -220,6 +221,13 @@ struct map {
uint32_t group_id; uint32_t group_id;
uint16_t ifmtu; uint16_t ifmtu;
} pwid; } pwid;
struct {
uint8_t type;
union {
uint16_t prefix_af;
uint16_t pw_type;
} u;
} twcard;
} fec; } fec;
struct { struct {
uint32_t status_code; uint32_t status_code;
@ -244,10 +252,16 @@ struct notify_msg {
uint16_t msg_type; /* network byte order */ uint16_t msg_type; /* network byte order */
uint32_t pw_status; uint32_t pw_status;
struct map fec; struct map fec;
struct {
uint16_t type;
uint16_t length;
char *data;
} rtlvs;
uint8_t flags; uint8_t flags;
}; };
#define F_NOTIF_PW_STATUS 0x01 /* pseudowire status tlv present */ #define F_NOTIF_PW_STATUS 0x01 /* pseudowire status tlv present */
#define F_NOTIF_FEC 0x02 /* fec tlv present */ #define F_NOTIF_FEC 0x02 /* fec tlv present */
#define F_NOTIF_RETURNED_TLVS 0x04 /* returned tlvs present */
struct if_addr { struct if_addr {
LIST_ENTRY(if_addr) entry; LIST_ENTRY(if_addr) entry;
@ -337,6 +351,7 @@ struct l2vpn_if {
char ifname[IF_NAMESIZE]; char ifname[IF_NAMESIZE];
unsigned int ifindex; unsigned int ifindex;
uint16_t flags; uint16_t flags;
uint8_t mac[ETHER_ADDR_LEN];
QOBJ_FIELDS QOBJ_FIELDS
}; };
RB_HEAD(l2vpn_if_head, l2vpn_if); RB_HEAD(l2vpn_if_head, l2vpn_if);
@ -506,6 +521,7 @@ struct kif {
char ifname[IF_NAMESIZE]; char ifname[IF_NAMESIZE];
unsigned short ifindex; unsigned short ifindex;
int flags; int flags;
uint8_t mac[ETHER_ADDR_LEN];
int mtu; int mtu;
}; };

View File

@ -251,8 +251,8 @@ ldpe_dispatch_main(struct thread *thread)
struct iface *niface; struct iface *niface;
struct tnbr *ntnbr; struct tnbr *ntnbr;
struct nbr_params *nnbrp; struct nbr_params *nnbrp;
static struct l2vpn *nl2vpn; static struct l2vpn *l2vpn, *nl2vpn;
struct l2vpn_if *nlif; struct l2vpn_if *lif = NULL, *nlif;
struct l2vpn_pw *npw; struct l2vpn_pw *npw;
struct imsg imsg; struct imsg imsg;
int fd = THREAD_FD(thread); int fd = THREAD_FD(thread);
@ -292,11 +292,22 @@ ldpe_dispatch_main(struct thread *thread)
kif = imsg.data; kif = imsg.data;
iface = if_lookup_name(leconf, kif->ifname); iface = if_lookup_name(leconf, kif->ifname);
if (!iface) if (iface) {
if_update_info(iface, kif);
if_update(iface, AF_UNSPEC);
break; break;
}
if_update_info(iface, kif); RB_FOREACH(l2vpn, l2vpn_head, &leconf->l2vpn_tree) {
if_update(iface, AF_UNSPEC); 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; break;
case IMSG_NEWADDR: case IMSG_NEWADDR:
if (imsg.hdr.len != IMSG_HEADER_SIZE + if (imsg.hdr.len != IMSG_HEADER_SIZE +
@ -529,10 +540,10 @@ ldpe_dispatch_lde(struct thread *thread)
struct imsgev *iev = THREAD_ARG(thread); struct imsgev *iev = THREAD_ARG(thread);
struct imsgbuf *ibuf = &iev->ibuf; struct imsgbuf *ibuf = &iev->ibuf;
struct imsg imsg; struct imsg imsg;
struct map map; struct map *map;
struct notify_msg nm; struct notify_msg *nm;
struct nbr *nbr;
int n, shut = 0; int n, shut = 0;
struct nbr *nbr = NULL;
iev->ev_read = NULL; iev->ev_read = NULL;
@ -552,9 +563,10 @@ ldpe_dispatch_lde(struct thread *thread)
case IMSG_RELEASE_ADD: case IMSG_RELEASE_ADD:
case IMSG_REQUEST_ADD: case IMSG_REQUEST_ADD:
case IMSG_WITHDRAW_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"); fatalx("invalid size of map request");
memcpy(&map, imsg.data, sizeof(map)); map = imsg.data;
nbr = nbr_find_peerid(imsg.hdr.peerid); nbr = nbr_find_peerid(imsg.hdr.peerid);
if (nbr == NULL) { if (nbr == NULL) {
@ -567,16 +579,16 @@ ldpe_dispatch_lde(struct thread *thread)
switch (imsg.hdr.type) { switch (imsg.hdr.type) {
case IMSG_MAPPING_ADD: case IMSG_MAPPING_ADD:
mapping_list_add(&nbr->mapping_list, &map); mapping_list_add(&nbr->mapping_list, map);
break; break;
case IMSG_RELEASE_ADD: case IMSG_RELEASE_ADD:
mapping_list_add(&nbr->release_list, &map); mapping_list_add(&nbr->release_list, map);
break; break;
case IMSG_REQUEST_ADD: case IMSG_REQUEST_ADD:
mapping_list_add(&nbr->request_list, &map); mapping_list_add(&nbr->request_list, map);
break; break;
case IMSG_WITHDRAW_ADD: case IMSG_WITHDRAW_ADD:
mapping_list_add(&nbr->withdraw_list, &map); mapping_list_add(&nbr->withdraw_list, map);
break; break;
} }
break; break;
@ -613,9 +625,10 @@ ldpe_dispatch_lde(struct thread *thread)
} }
break; break;
case IMSG_NOTIFICATION_SEND: 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"); fatalx("invalid size of OE request");
memcpy(&nm, imsg.data, sizeof(nm)); nm = imsg.data;
nbr = nbr_find_peerid(imsg.hdr.peerid); nbr = nbr_find_peerid(imsg.hdr.peerid);
if (nbr == NULL) { if (nbr == NULL) {
@ -626,7 +639,7 @@ ldpe_dispatch_lde(struct thread *thread)
if (nbr->state != NBR_STA_OPER) if (nbr->state != NBR_STA_OPER)
break; break;
send_notification_full(nbr->tcp, &nm); send_notification_full(nbr->tcp, nm);
break; break;
case IMSG_CTL_END: case IMSG_CTL_END:
case IMSG_CTL_SHOW_LIB: case IMSG_CTL_SHOW_LIB:
@ -791,8 +804,7 @@ ldpe_iface_af_ctl(struct ctl_conn *c, int af, unsigned int idx)
continue; continue;
ictl = if_to_ctl(ia); ictl = if_to_ctl(ia);
imsg_compose_event(&c->iev, imsg_compose_event(&c->iev, IMSG_CTL_SHOW_INTERFACE,
IMSG_CTL_SHOW_INTERFACE,
0, 0, -1, ictl, sizeof(struct ctl_iface)); 0, 0, -1, ictl, sizeof(struct ctl_iface));
} }
} }

View File

@ -111,6 +111,9 @@ struct nbr {
int flags; int flags;
}; };
#define F_NBR_GTSM_NEGOTIATED 0x01 #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_HEAD(nbr_id_head, nbr);
RB_PROTOTYPE(nbr_id_head, nbr, id_tree, nbr_id_compare) 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 */ /* init.c */
void send_init(struct nbr *); void send_init(struct nbr *);
int recv_init(struct nbr *, char *, uint16_t); 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 */ /* keepalive.c */
void send_keepalive(struct nbr *); void send_keepalive(struct nbr *);
@ -166,15 +171,16 @@ int recv_keepalive(struct nbr *, char *, uint16_t);
/* notification.c */ /* notification.c */
void send_notification_full(struct tcp_conn *, struct notify_msg *); void send_notification_full(struct tcp_conn *, struct notify_msg *);
void send_notification(uint32_t, struct tcp_conn *, uint32_t, void send_notification(struct tcp_conn *, uint32_t, uint32_t, uint16_t);
uint16_t); void send_notification_rtlvs(struct nbr *, uint32_t, uint32_t, uint16_t,
void send_notification_nbr(struct nbr *, uint32_t, uint32_t, uint16_t); uint16_t, uint16_t, char *);
int recv_notification(struct nbr *, char *, uint16_t); int recv_notification(struct nbr *, char *, uint16_t);
int gen_status_tlv(struct ibuf *, uint32_t, uint32_t, uint16_t); int gen_status_tlv(struct ibuf *, uint32_t, uint32_t, uint16_t);
/* address.c */ /* address.c */
void send_address_single(struct nbr *, struct if_addr *, int); void send_address_single(struct nbr *, struct if_addr *, int);
void send_address_all(struct nbr *, 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); int recv_address(struct nbr *, char *, uint16_t);
/* labelmapping.c */ /* labelmapping.c */
@ -182,6 +188,7 @@ int recv_address(struct nbr *, char *, uint16_t);
void send_labelmessage(struct nbr *, uint16_t, struct mapping_head *); void send_labelmessage(struct nbr *, uint16_t, struct mapping_head *);
int recv_labelmessage(struct nbr *, char *, uint16_t, uint16_t); int recv_labelmessage(struct nbr *, char *, uint16_t, uint16_t);
int gen_pw_status_tlv(struct ibuf *, uint32_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 gen_fec_tlv(struct ibuf *, struct map *);
int tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *, int tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *,
uint16_t, struct map *); uint16_t, struct map *);

View File

@ -313,7 +313,7 @@ log_hello_src(const struct hello_source *src)
const char * const char *
log_map(const struct map *map) log_map(const struct map *map)
{ {
static char buf[64]; static char buf[128];
switch (map->type) { switch (map->type) {
case MAP_TYPE_WILDCARD: case MAP_TYPE_WILDCARD:
@ -327,11 +327,34 @@ log_map(const struct map *map)
return ("???"); return ("???");
break; break;
case MAP_TYPE_PWID: case MAP_TYPE_PWID:
if (snprintf(buf, sizeof(buf), "pwid %u (%s)", if (snprintf(buf, sizeof(buf), "pw-id %u group-id %u (%s)",
map->fec.pwid.pwid, map->fec.pwid.pwid, map->fec.pwid.group_id,
pw_type_name(map->fec.pwid.type)) == -1) pw_type_name(map->fec.pwid.type)) == -1)
return ("???"); return ("???");
break; 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: default:
return ("???"); return ("???");
} }
@ -464,6 +487,8 @@ msg_name(uint16_t msg)
return ("initialization"); return ("initialization");
case MSG_TYPE_KEEPALIVE: case MSG_TYPE_KEEPALIVE:
return ("keepalive"); return ("keepalive");
case MSG_TYPE_CAPABILITY:
return ("capability");
case MSG_TYPE_ADDR: case MSG_TYPE_ADDR:
return ("address"); return ("address");
case MSG_TYPE_ADDRWITHDRAW: case MSG_TYPE_ADDRWITHDRAW:
@ -557,6 +582,10 @@ status_code_name(uint32_t status)
return ("Generic Misconfiguration Error"); return ("Generic Misconfiguration Error");
case S_WITHDRAW_MTHD: case S_WITHDRAW_MTHD:
return ("Label Withdraw PW Status Method"); return ("Label Withdraw PW Status Method");
case S_UNSSUPORTDCAP:
return ("Unsupported Capability");
case S_ENDOFLIB:
return ("End-of-LIB");
case S_TRANS_MISMTCH: case S_TRANS_MISMTCH:
return ("Transport Connection Mismatch"); return ("Transport Connection Mismatch");
case S_DS_NONCMPLNCE: case S_DS_NONCMPLNCE:
@ -577,6 +606,8 @@ pw_type_name(uint16_t pw_type)
return ("Eth Tagged"); return ("Eth Tagged");
case PW_TYPE_ETHERNET: case PW_TYPE_ETHERNET:
return ("Ethernet"); return ("Ethernet");
case PW_TYPE_WILDCARD:
return ("Wildcard");
default: default:
snprintf(buf, sizeof(buf), "[%0x]", pw_type); snprintf(buf, sizeof(buf), "[%0x]", pw_type);
return (buf); return (buf);

View File

@ -744,6 +744,7 @@ nbr_act_session_operational(struct nbr *nbr)
lde_nbr.id = nbr->id; lde_nbr.id = nbr->id;
lde_nbr.v4_enabled = nbr->v4_enabled; lde_nbr.v4_enabled = nbr->v4_enabled;
lde_nbr.v6_enabled = nbr->v6_enabled; lde_nbr.v6_enabled = nbr->v6_enabled;
lde_nbr.flags = nbr->flags;
return (ldpe_imsg_compose_lde(IMSG_NEIGHBOR_UP, nbr->peerid, 0, return (ldpe_imsg_compose_lde(IMSG_NEIGHBOR_UP, nbr->peerid, 0,
&lde_nbr, sizeof(lde_nbr))); &lde_nbr, sizeof(lde_nbr)));
} }

View File

@ -24,6 +24,9 @@
#include "ldpe.h" #include "ldpe.h"
#include "ldp_debug.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 void
send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm) 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; size = LDP_HDR_SIZE + LDP_MSG_SIZE + STATUS_SIZE;
if (nm->flags & F_NOTIF_PW_STATUS) if (nm->flags & F_NOTIF_PW_STATUS)
size += PW_STATUS_TLV_SIZE; size += PW_STATUS_TLV_SIZE;
if (nm->flags & F_NOTIF_FEC) { if (nm->flags & F_NOTIF_FEC)
size += TLV_HDR_SIZE; size += len_fec_tlv(&nm->fec);
switch (nm->fec.type) { if (nm->flags & F_NOTIF_RETURNED_TLVS)
case MAP_TYPE_PWID: size += TLV_HDR_SIZE * 2 + nm->rtlvs.length;
size += FEC_PWID_ELM_MIN_LEN;
if (nm->fec.flags & F_MAP_PW_ID)
size += sizeof(uint32_t);
break;
}
}
if ((buf = ibuf_open(size)) == NULL) if ((buf = ibuf_open(size)) == NULL)
fatal(__func__); 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); err |= gen_pw_status_tlv(buf, nm->pw_status);
if (nm->flags & F_NOTIF_FEC) if (nm->flags & F_NOTIF_FEC)
err |= gen_fec_tlv(buf, &nm->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) { if (err) {
ibuf_free(buf); ibuf_free(buf);
return; return;
} }
if (tcp->nbr) if (tcp->nbr) {
debug_msg_send("notification: lsr-id %s status %s%s", log_msg_notification(1, tcp->nbr, nm);
inet_ntoa(tcp->nbr->id), status_code_name(nm->status_code), nbr_fsm(tcp->nbr, NBR_EVT_PDU_SENT);
(nm->status_code & STATUS_FATAL) ? " (fatal)" : ""); }
evbuf_enqueue(&tcp->wbuf, buf); evbuf_enqueue(&tcp->wbuf, buf);
} }
/* send a notification without optional tlvs */ /* send a notification without optional tlvs */
void 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) uint16_t msg_type)
{ {
struct notify_msg nm; struct notify_msg nm;
@ -87,11 +87,24 @@ send_notification(uint32_t status_code, struct tcp_conn *tcp, uint32_t msg_id,
} }
void void
send_notification_nbr(struct nbr *nbr, uint32_t status_code, uint32_t msg_id, send_notification_rtlvs(struct nbr *nbr, uint32_t status_code, uint32_t msg_id,
uint16_t msg_type) 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); struct notify_msg nm;
nbr_fsm(nbr, NBR_EVT_PDU_SENT);
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 int
@ -126,6 +139,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
/* Optional Parameters */ /* Optional Parameters */
while (len > 0) { while (len > 0) {
struct tlv tlv; struct tlv tlv;
uint16_t tlv_type;
uint16_t tlv_len; uint16_t tlv_len;
if (len < sizeof(tlv)) { if (len < sizeof(tlv)) {
@ -134,6 +148,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
} }
memcpy(&tlv, buf, TLV_HDR_SIZE); memcpy(&tlv, buf, TLV_HDR_SIZE);
tlv_type = ntohs(tlv.type);
tlv_len = ntohs(tlv.length); tlv_len = ntohs(tlv.length);
if (tlv_len + TLV_HDR_SIZE > len) { if (tlv_len + TLV_HDR_SIZE > len) {
session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); 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; buf += TLV_HDR_SIZE;
len -= TLV_HDR_SIZE; len -= TLV_HDR_SIZE;
switch (ntohs(tlv.type)) { switch (tlv_type) {
case TLV_TYPE_EXTSTATUS: case TLV_TYPE_EXTSTATUS:
case TLV_TYPE_RETURNEDPDU: case TLV_TYPE_RETURNEDPDU:
case TLV_TYPE_RETURNEDMSG: case TLV_TYPE_RETURNEDMSG:
@ -172,8 +187,8 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
break; break;
default: default:
if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
send_notification_nbr(nbr, S_UNKNOWN_TLV, send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
msg.id, msg.type); msg.id, msg.type, tlv_type, tlv_len, buf);
/* ignore unknown tlv */ /* ignore unknown tlv */
break; break;
} }
@ -181,9 +196,11 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
len -= tlv_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))) { 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); msg.id, msg.type);
return (-1); return (-1);
} }
@ -192,15 +209,28 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
case MAP_TYPE_PWID: case MAP_TYPE_PWID:
break; break;
default: default:
send_notification_nbr(nbr, S_BAD_TLV_VAL, send_notification(nbr->tcp, S_BAD_TLV_VAL,
msg.id, msg.type); msg.id, msg.type);
return (-1); 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), log_msg_notification(0, nbr, &nm);
status_code_name(ntohl(st.status_code)),
(st.status_code & htonl(STATUS_FATAL)) ? " (fatal)" : "");
if (st.status_code & htonl(STATUS_FATAL)) { if (st.status_code & htonl(STATUS_FATAL)) {
if (nbr->state == NBR_STA_OPENSENT) if (nbr->state == NBR_STA_OPENSENT)
@ -210,9 +240,16 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
return (-1); 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, ldpe_imsg_compose_lde(IMSG_NOTIFICATION, nbr->peerid, 0,
&nm, sizeof(nm)); &nm, sizeof(nm));
break;
default:
break;
}
return (0); 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)); 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");
}

View File

@ -519,13 +519,7 @@ session_read(struct thread *thread)
return (0); return (0);
} }
break; break;
case MSG_TYPE_ADDR: default:
case MSG_TYPE_ADDRWITHDRAW:
case MSG_TYPE_LABELMAPPING:
case MSG_TYPE_LABELREQUEST:
case MSG_TYPE_LABELWITHDRAW:
case MSG_TYPE_LABELRELEASE:
case MSG_TYPE_LABELABORTREQ:
if (nbr->state != NBR_STA_OPER) { if (nbr->state != NBR_STA_OPER) {
session_shutdown(nbr, S_SHUTDOWN, session_shutdown(nbr, S_SHUTDOWN,
msg->id, msg->type); msg->id, msg->type);
@ -533,8 +527,6 @@ session_read(struct thread *thread)
return (0); return (0);
} }
break; break;
default:
break;
} }
/* switch LDP packet type */ /* switch LDP packet type */
@ -548,6 +540,9 @@ session_read(struct thread *thread)
case MSG_TYPE_KEEPALIVE: case MSG_TYPE_KEEPALIVE:
ret = recv_keepalive(nbr, pdu, msg_size); ret = recv_keepalive(nbr, pdu, msg_size);
break; break;
case MSG_TYPE_CAPABILITY:
ret = recv_capability(nbr, pdu, msg_size);
break;
case MSG_TYPE_ADDR: case MSG_TYPE_ADDR:
case MSG_TYPE_ADDRWITHDRAW: case MSG_TYPE_ADDRWITHDRAW:
ret = recv_address(nbr, pdu, msg_size); 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", log_debug("%s: unknown LDP message from nbr %s",
__func__, inet_ntoa(nbr->id)); __func__, inet_ntoa(nbr->id));
if (!(ntohs(msg->type) & UNKNOWN_FLAG)) if (!(ntohs(msg->type) & UNKNOWN_FLAG))
send_notification_nbr(nbr, send_notification(nbr->tcp,
S_UNKNOWN_MSG, msg->id, msg->type); S_UNKNOWN_MSG, msg->id, msg->type);
/* ignore the message */ /* ignore the message */
ret = 0; ret = 0;
@ -632,7 +627,7 @@ session_shutdown(struct nbr *nbr, uint32_t status, uint32_t msg_id,
case NBR_STA_OPER: case NBR_STA_OPER:
log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); 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); nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
break; break;
@ -788,7 +783,7 @@ pending_conn_timeout(struct thread *thread)
* notification message reliably. * notification message reliably.
*/ */
tcp = tcp_new(pconn->fd, NULL); 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); msgbuf_write(&tcp->wbuf.wbuf);
pending_conn_del(pconn); pending_conn_del(pconn);

View File

@ -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_exttype = SADB_EXT_SA;
sa.sadb_sa_len = sizeof(sa) / 8; sa.sadb_sa_len = sizeof(sa) / 8;
sa.sadb_sa_replay = 0; sa.sadb_sa_replay = 0;
sa.sadb_sa_spi = spi; sa.sadb_sa_spi = htonl(spi);
sa.sadb_sa_state = SADB_SASTATE_MATURE; sa.sadb_sa_state = SADB_SASTATE_MATURE;
break; break;
} }
@ -280,7 +280,7 @@ pfkey_read(int sd, struct sadb_msg *h)
} }
static int static int
pfkey_reply(int sd, uint32_t *spip) pfkey_reply(int sd, uint32_t *spi)
{ {
struct sadb_msg hdr, *msg; struct sadb_msg hdr, *msg;
struct sadb_ext *ext; struct sadb_ext *ext;
@ -317,7 +317,7 @@ pfkey_reply(int sd, uint32_t *spip)
} }
if (hdr.sadb_msg_type == SADB_GETSPI) { if (hdr.sadb_msg_type == SADB_GETSPI) {
if (spip == NULL) { if (spi == NULL) {
explicit_bzero(data, len); explicit_bzero(data, len);
free(data); free(data);
return (0); return (0);
@ -331,7 +331,7 @@ pfkey_reply(int sd, uint32_t *spip)
ext->sadb_ext_len * PFKEY2_CHUNK)) { ext->sadb_ext_len * PFKEY2_CHUNK)) {
if (ext->sadb_ext_type == SADB_EXT_SA) { if (ext->sadb_ext_type == SADB_EXT_SA) {
sa = (struct sadb_sa *) ext; sa = (struct sadb_sa *) ext;
*spip = sa->sadb_sa_spi; *spi = ntohl(sa->sadb_sa_spi);
break; break;
} }
} }