From b53f7b86efe5fdd6692fc9033e032881c4357139 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 01/18] ldpd: replace hand-rolled 'for' loop with specialized macro No intentional functional change. Original author: Kenneth R Westerback Signed-off-by: Renato Westphal --- ldpd/control.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ldpd/control.c b/ldpd/control.c index 8a2280be07..0bfe0abc9d 100644 --- a/ldpd/control.c +++ b/ldpd/control.c @@ -148,9 +148,10 @@ control_connbyfd(int fd) { struct ctl_conn *c; - for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd; - c = TAILQ_NEXT(c, entry)) - ; /* nothing */ + TAILQ_FOREACH(c, &ctl_conns, entry) { + if (c->iev.ibuf.fd == fd) + break; + } return (c); } @@ -160,9 +161,10 @@ control_connbypid(pid_t pid) { struct ctl_conn *c; - for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.pid != pid; - c = TAILQ_NEXT(c, entry)) - ; /* nothing */ + TAILQ_FOREACH(c, &ctl_conns, entry) { + if (c->iev.ibuf.pid == pid) + break; + } return (c); } From 05aac414e69068748a8e6d6f7e3b0bdb74677039 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 02/18] ldpd: minor tweaks Signed-off-by: Renato Westphal --- ldpd/labelmapping.c | 6 +++--- ldpd/lde.c | 6 +++--- ldpd/lde.h | 3 ++- ldpd/lde_lib.c | 6 +++--- ldpd/ldp.h | 1 + ldpd/ldpe.c | 3 +-- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c index 62f2a620d2..15861cfd9a 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -423,14 +423,14 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) ldpe_imsg_compose_lde(imsg_type, nbr->peerid, 0, &me->map, sizeof(struct map)); -next: + next: TAILQ_REMOVE(&mh, me, entry); free(me); } return (0); -err: + err: mapping_list_clr(&mh); return (-1); @@ -562,7 +562,7 @@ gen_fec_tlv(struct ibuf *buf, struct map *map) break; case MAP_TYPE_PWID: if (map->flags & F_MAP_PW_ID) - pw_len += PW_STATUS_TLV_LEN; + pw_len += FEC_PWID_SIZE; if (map->flags & F_MAP_PW_IFMTU) pw_len += FEC_SUBTLV_IFMTU_SIZE; diff --git a/ldpd/lde.c b/ldpd/lde.c index 1323ba3d02..6ac0f07daf 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -37,7 +37,7 @@ static void lde_shutdown(void); static int lde_dispatch_imsg(struct thread *); static int lde_dispatch_parent(struct thread *); -static __inline int lde_nbr_compare(struct lde_nbr *, +static __inline int lde_nbr_compare(struct lde_nbr *, struct lde_nbr *); static struct lde_nbr *lde_nbr_new(uint32_t, struct lde_nbr *); static void lde_nbr_del(struct lde_nbr *); @@ -1044,7 +1044,7 @@ lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label) } void -lde_send_notification(uint32_t peerid, uint32_t status_code, uint32_t msg_id, +lde_send_notification(struct lde_nbr *ln, uint32_t status_code, uint32_t msg_id, uint16_t msg_type) { struct notify_msg nm; @@ -1055,7 +1055,7 @@ lde_send_notification(uint32_t peerid, uint32_t status_code, uint32_t msg_id, nm.msg_id = msg_id; nm.msg_type = msg_type; - lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0, + lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm, sizeof(nm)); } diff --git a/ldpd/lde.h b/ldpd/lde.h index e0e9873d5c..b3fa2d469b 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -147,7 +147,8 @@ void lde_send_labelwithdraw(struct lde_nbr *, struct fec_node *, void lde_send_labelwithdraw_all(struct fec_node *, uint32_t); void lde_send_labelrelease(struct lde_nbr *, struct fec_node *, uint32_t); -void lde_send_notification(uint32_t, uint32_t, uint32_t, uint16_t); +void lde_send_notification(struct lde_nbr *, uint32_t, uint32_t, + uint16_t); struct lde_nbr *lde_nbr_find_by_lsrid(struct in_addr); struct lde_nbr *lde_nbr_find_by_addr(int, union ldpd_addr *); struct lde_map *lde_map_add(struct lde_nbr *, struct fec_node *, int); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index 234d373fbb..6ec88a19bd 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -561,7 +561,7 @@ lde_check_request(struct map *map, struct lde_nbr *ln) fn = (struct fec_node *)fec_find(&ft, &fec); if (fn == NULL || LIST_EMPTY(&fn->nexthops)) { /* LRq.5: send No Route notification */ - lde_send_notification(ln->peerid, S_NO_ROUTE, map->msg_id, + lde_send_notification(ln, S_NO_ROUTE, map->msg_id, htons(MSG_TYPE_LABELREQUEST)); return; } @@ -575,8 +575,8 @@ lde_check_request(struct map *map, struct lde_nbr *ln) continue; /* LRq.4: send Loop Detected notification */ - lde_send_notification(ln->peerid, S_LOOP_DETECTED, - map->msg_id, htons(MSG_TYPE_LABELREQUEST)); + lde_send_notification(ln, S_LOOP_DETECTED, map->msg_id, + htons(MSG_TYPE_LABELREQUEST)); return; default: break; diff --git a/ldpd/ldp.h b/ldpd/ldp.h index c421cddc38..c068e22918 100644 --- a/ldpd/ldp.h +++ b/ldpd/ldp.h @@ -242,6 +242,7 @@ struct address_list_tlv { #define FEC_ELM_WCARD_LEN 1 #define FEC_ELM_PREFIX_MIN_LEN 4 #define FEC_PWID_ELM_MIN_LEN 8 +#define FEC_PWID_SIZE 4 #define MAP_TYPE_WILDCARD 0x01 #define MAP_TYPE_PREFIX 0x02 diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 7dcc8fbe16..bea26a6610 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -791,8 +791,7 @@ ldpe_iface_af_ctl(struct ctl_conn *c, int af, unsigned int idx) continue; ictl = if_to_ctl(ia); - imsg_compose_event(&c->iev, - IMSG_CTL_SHOW_INTERFACE, + imsg_compose_event(&c->iev, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, ictl, sizeof(struct ctl_iface)); } } From adbdf4653f3a408900c6be58fbdf497c0439a84e Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 03/18] ldpd: kill send_notification_nbr() Be more clever and trigger the PDU SENT event inside send_notification() when tcp->nbr is set. This way we can eliminate send_notification_nbr() and always use send_notification() instead. Signed-off-by: Renato Westphal --- ldpd/address.c | 2 +- ldpd/init.c | 2 +- ldpd/labelmapping.c | 12 ++++++------ ldpd/ldpe.h | 4 +--- ldpd/notification.c | 20 +++++++------------- ldpd/packet.c | 6 +++--- 6 files changed, 19 insertions(+), 27 deletions(-) diff --git a/ldpd/address.c b/ldpd/address.c index 1c4c116f21..0bb4e048eb 100644 --- a/ldpd/address.c +++ b/ldpd/address.c @@ -177,7 +177,7 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len) return (0); break; default: - send_notification_nbr(nbr, S_UNSUP_ADDR, msg.id, msg.type); + send_notification(nbr->tcp, S_UNSUP_ADDR, msg.id, msg.type); return (-1); } buf += sizeof(alt); diff --git a/ldpd/init.c b/ldpd/init.c index ed6b53c02d..030bff2f51 100644 --- a/ldpd/init.c +++ b/ldpd/init.c @@ -118,7 +118,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len) return (-1); default: if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) - send_notification_nbr(nbr, S_UNKNOWN_TLV, + send_notification(nbr->tcp, S_UNKNOWN_TLV, msg.id, msg.type); /* ignore unknown tlv */ break; diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c index 15861cfd9a..34cc1f83a2 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -163,7 +163,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) memcpy(&ft, buf, sizeof(ft)); if (ntohs(ft.type) != TLV_TYPE_FEC) { - send_notification_nbr(nbr, S_MISS_MSG, msg.id, msg.type); + send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type); return (-1); } feclen = ntohs(ft.length); @@ -187,7 +187,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) !(map.flags & F_MAP_PW_ID) && type != MSG_TYPE_LABELWITHDRAW && type != MSG_TYPE_LABELRELEASE) { - send_notification_nbr(nbr, S_MISS_MSG, msg.id, + send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type); return (-1); } @@ -341,7 +341,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) break; default: if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) - send_notification_nbr(nbr, S_UNKNOWN_TLV, + send_notification(nbr->tcp, S_UNKNOWN_TLV, msg.id, msg.type); /* ignore unknown tlv */ break; @@ -462,7 +462,7 @@ tlv_decode_label(struct nbr *nbr, struct ldp_msg *msg, char *buf, memcpy(<, buf, sizeof(lt)); if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) { - send_notification_nbr(nbr, S_MISS_MSG, msg->id, msg->type); + send_notification(nbr->tcp, S_MISS_MSG, msg->id, msg->type); return (-1); } @@ -642,7 +642,7 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf, map->fec.prefix.af = AF_INET6; break; default: - send_notification_nbr(nbr, S_UNSUP_ADDR, msg->id, + send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id, msg->type); return (-1); } @@ -753,7 +753,7 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf, return (off); default: - send_notification_nbr(nbr, S_UNKNOWN_FEC, msg->id, msg->type); + send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type); break; } diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index 052439df88..d79c9a82ca 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -166,9 +166,7 @@ int recv_keepalive(struct nbr *, char *, uint16_t); /* notification.c */ void send_notification_full(struct tcp_conn *, struct notify_msg *); -void send_notification(uint32_t, struct tcp_conn *, uint32_t, - uint16_t); -void send_notification_nbr(struct nbr *, uint32_t, uint32_t, uint16_t); +void send_notification(struct tcp_conn *, uint32_t, uint32_t, uint16_t); int recv_notification(struct nbr *, char *, uint16_t); int gen_status_tlv(struct ibuf *, uint32_t, uint32_t, uint16_t); diff --git a/ldpd/notification.c b/ldpd/notification.c index d306361d5c..f70af76bad 100644 --- a/ldpd/notification.c +++ b/ldpd/notification.c @@ -63,17 +63,19 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm) return; } - if (tcp->nbr) + if (tcp->nbr) { debug_msg_send("notification: lsr-id %s status %s%s", inet_ntoa(tcp->nbr->id), status_code_name(nm->status_code), (nm->status_code & STATUS_FATAL) ? " (fatal)" : ""); + nbr_fsm(tcp->nbr, NBR_EVT_PDU_SENT); + } evbuf_enqueue(&tcp->wbuf, buf); } /* send a notification without optional tlvs */ void -send_notification(uint32_t status_code, struct tcp_conn *tcp, uint32_t msg_id, +send_notification(struct tcp_conn *tcp, uint32_t status_code, uint32_t msg_id, uint16_t msg_type) { struct notify_msg nm; @@ -86,14 +88,6 @@ send_notification(uint32_t status_code, struct tcp_conn *tcp, uint32_t msg_id, send_notification_full(tcp, &nm); } -void -send_notification_nbr(struct nbr *nbr, uint32_t status_code, uint32_t msg_id, - uint16_t msg_type) -{ - send_notification(status_code, nbr->tcp, msg_id, msg_type); - nbr_fsm(nbr, NBR_EVT_PDU_SENT); -} - int recv_notification(struct nbr *nbr, char *buf, uint16_t len) { @@ -172,7 +166,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) break; default: if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) - send_notification_nbr(nbr, S_UNKNOWN_TLV, + send_notification(nbr->tcp, S_UNKNOWN_TLV, msg.id, msg.type); /* ignore unknown tlv */ break; @@ -183,7 +177,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) if (nm.status_code == S_PW_STATUS) { if (!(nm.flags & (F_NOTIF_PW_STATUS|F_NOTIF_FEC))) { - send_notification_nbr(nbr, S_MISS_MSG, + send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type); return (-1); } @@ -192,7 +186,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) case MAP_TYPE_PWID: break; default: - send_notification_nbr(nbr, S_BAD_TLV_VAL, + send_notification(nbr->tcp, S_BAD_TLV_VAL, msg.id, msg.type); return (-1); } diff --git a/ldpd/packet.c b/ldpd/packet.c index b085cac055..653f67b8c2 100644 --- a/ldpd/packet.c +++ b/ldpd/packet.c @@ -564,7 +564,7 @@ session_read(struct thread *thread) log_debug("%s: unknown LDP message from nbr %s", __func__, inet_ntoa(nbr->id)); if (!(ntohs(msg->type) & UNKNOWN_FLAG)) - send_notification_nbr(nbr, + send_notification(nbr->tcp, S_UNKNOWN_MSG, msg->id, msg->type); /* ignore the message */ ret = 0; @@ -632,7 +632,7 @@ session_shutdown(struct nbr *nbr, uint32_t status, uint32_t msg_id, case NBR_STA_OPER: log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); - send_notification_nbr(nbr, status, msg_id, msg_type); + send_notification(nbr->tcp, status, msg_id, msg_type); nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); break; @@ -788,7 +788,7 @@ pending_conn_timeout(struct thread *thread) * notification message reliably. */ tcp = tcp_new(pconn->fd, NULL); - send_notification(S_NO_HELLO, tcp, 0, 0); + send_notification(tcp, S_NO_HELLO, 0, 0); msgbuf_write(&tcp->wbuf.wbuf); pending_conn_del(pconn); From 8afbd8942ae56af31c0bcbf741b4ef11f2b8f229 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 04/18] ldpd: provide more detailed output when logging notification messages Signed-off-by: Renato Westphal --- ldpd/notification.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ldpd/notification.c b/ldpd/notification.c index f70af76bad..d435bc8845 100644 --- a/ldpd/notification.c +++ b/ldpd/notification.c @@ -67,6 +67,12 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm) debug_msg_send("notification: lsr-id %s status %s%s", inet_ntoa(tcp->nbr->id), status_code_name(nm->status_code), (nm->status_code & STATUS_FATAL) ? " (fatal)" : ""); + if (nm->flags & F_NOTIF_FEC) + debug_msg_send("notification: fec %s", + log_map(&nm->fec)); + if (nm->flags & F_NOTIF_PW_STATUS) + debug_msg_send("notification: pw-status %s", + (nm->pw_status) ? "not forwarding" : "forwarding"); nbr_fsm(tcp->nbr, NBR_EVT_PDU_SENT); } @@ -195,6 +201,11 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) debug_msg_recv("notification: lsr-id %s: %s%s", inet_ntoa(nbr->id), status_code_name(ntohl(st.status_code)), (st.status_code & htonl(STATUS_FATAL)) ? " (fatal)" : ""); + if (nm.flags & F_NOTIF_FEC) + debug_msg_recv("notification: fec %s", log_map(&nm.fec)); + if (nm.flags & F_NOTIF_PW_STATUS) + debug_msg_recv("notification: pw-status %s", + (nm.pw_status) ? "not forwarding" : "forwarding"); if (st.status_code & htonl(STATUS_FATAL)) { if (nbr->state == NBR_STA_OPENSENT) From faf757937f8a38f96cfd732068588830e0a998b5 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 05/18] ldpd: create helper functions to log sent/received messages Signed-off-by: Renato Westphal --- ldpd/address.c | 17 ++++++++++++----- ldpd/labelmapping.c | 16 ++++++++++------ ldpd/ldp_debug.h | 8 ++++++++ ldpd/notification.c | 40 +++++++++++++++++++++++----------------- 4 files changed, 53 insertions(+), 28 deletions(-) diff --git a/ldpd/address.c b/ldpd/address.c index 0bb4e048eb..cb2f505f7b 100644 --- a/ldpd/address.c +++ b/ldpd/address.c @@ -30,6 +30,8 @@ static int gen_address_list_tlv(struct ibuf *, uint16_t, int, struct if_addr_head *, unsigned int); static void address_list_add(struct if_addr_head *, struct if_addr *); static void address_list_clr(struct if_addr_head *); +static void log_msg_address(int, uint16_t, struct nbr *, int, + union ldpd_addr *); static void send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list, @@ -92,9 +94,7 @@ send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list, } while ((if_addr = LIST_FIRST(addr_list)) != NULL) { - debug_msg_send("%s: lsr-id %s address %s", - msg_name(msg_type), inet_ntoa(nbr->id), - log_addr(af, &if_addr->addr)); + log_msg_address(1, msg_type, nbr, af, &if_addr->addr); LIST_REMOVE(if_addr, entry); free(if_addr); @@ -223,8 +223,7 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len) fatalx("recv_address: unknown af"); } - debug_msg_recv("%s: lsr-id %s address %s", msg_name(msg_type), - inet_ntoa(nbr->id), log_addr(lde_addr.af, &lde_addr.addr)); + log_msg_address(0, msg_type, nbr, lde_addr.af, &lde_addr.addr); ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr, sizeof(lde_addr)); @@ -292,3 +291,11 @@ address_list_clr(struct if_addr_head *addr_list) free(if_addr); } } + +static void +log_msg_address(int out, uint16_t msg_type, struct nbr *nbr, int af, + union ldpd_addr *addr) +{ + debug_msg(out, "%s: lsr-id %s, address %s", msg_name(msg_type), + inet_ntoa(nbr->id), log_addr(af, addr)); +} diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c index 34cc1f83a2..d9f71fdf6b 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -31,6 +31,7 @@ static int gen_label_tlv(struct ibuf *, uint32_t); static int tlv_decode_label(struct nbr *, struct ldp_msg *, char *, uint16_t, uint32_t *); static int gen_reqid_tlv(struct ibuf *, uint32_t); +static void log_msg_mapping(int, uint16_t, struct nbr *, struct map *); static void enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size) @@ -124,9 +125,7 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh) return; } - debug_msg_send("%s: lsr-id %s fec %s label %s", msg_name(type), - inet_ntoa(nbr->id), log_map(&me->map), - log_label(me->map.label)); + log_msg_mapping(1, type, nbr, &me->map); TAILQ_REMOVE(mh, me, entry); free(me); @@ -396,9 +395,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) if (me->map.flags & F_MAP_REQ_ID) me->map.requestid = reqid; - debug_msg_recv("%s: lsr-id %s fec %s label %s", msg_name(type), - inet_ntoa(nbr->id), log_map(&me->map), - log_label(me->map.label)); + log_msg_mapping(0, type, nbr, &me->map); switch (type) { case MSG_TYPE_LABELMAPPING: @@ -759,3 +756,10 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf, return (-1); } + +static void +log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map) +{ + debug_msg(out, "%s: lsr-id %s, fec %s, label %s", msg_name(msg_type), + inet_ntoa(nbr->id), log_map(map), log_label(map->label)); +} diff --git a/ldpd/ldp_debug.h b/ldpd/ldp_debug.h index aa0cd47e7b..f944851b6e 100644 --- a/ldpd/ldp_debug.h +++ b/ldpd/ldp_debug.h @@ -104,6 +104,14 @@ do { \ log_debug("msg[out]: " emsg, __VA_ARGS__); \ } while (0) +#define debug_msg(out, emsg, ...) \ +do { \ + if (out) \ + debug_msg_send(emsg, __VA_ARGS__); \ + else \ + debug_msg_recv(emsg, __VA_ARGS__); \ +} while (0) + #define debug_kalive_recv(emsg, ...) \ do { \ if (LDP_DEBUG(msg, MSG_RECV_ALL)) \ diff --git a/ldpd/notification.c b/ldpd/notification.c index d435bc8845..d573925314 100644 --- a/ldpd/notification.c +++ b/ldpd/notification.c @@ -24,6 +24,8 @@ #include "ldpe.h" #include "ldp_debug.h" +static void log_msg_notification(int, struct nbr *, struct notify_msg *); + void send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm) { @@ -64,15 +66,7 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm) } if (tcp->nbr) { - debug_msg_send("notification: lsr-id %s status %s%s", - inet_ntoa(tcp->nbr->id), status_code_name(nm->status_code), - (nm->status_code & STATUS_FATAL) ? " (fatal)" : ""); - if (nm->flags & F_NOTIF_FEC) - debug_msg_send("notification: fec %s", - log_map(&nm->fec)); - if (nm->flags & F_NOTIF_PW_STATUS) - debug_msg_send("notification: pw-status %s", - (nm->pw_status) ? "not forwarding" : "forwarding"); + log_msg_notification(1, tcp->nbr, nm); nbr_fsm(tcp->nbr, NBR_EVT_PDU_SENT); } @@ -198,14 +192,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) } } - debug_msg_recv("notification: lsr-id %s: %s%s", inet_ntoa(nbr->id), - status_code_name(ntohl(st.status_code)), - (st.status_code & htonl(STATUS_FATAL)) ? " (fatal)" : ""); - if (nm.flags & F_NOTIF_FEC) - debug_msg_recv("notification: fec %s", log_map(&nm.fec)); - if (nm.flags & F_NOTIF_PW_STATUS) - debug_msg_recv("notification: pw-status %s", - (nm.pw_status) ? "not forwarding" : "forwarding"); + log_msg_notification(0, nbr, &nm); if (st.status_code & htonl(STATUS_FATAL)) { if (nbr->state == NBR_STA_OPENSENT) @@ -241,3 +228,22 @@ gen_status_tlv(struct ibuf *buf, uint32_t status_code, uint32_t msg_id, return (ibuf_add(buf, &st, STATUS_SIZE)); } + +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"); +} From a33df200732c7d7470fa9060a70ab59e2076932e Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 06/18] ldpd: send correct status code on error condition The Unknown TLV status code is reserved for cases where we don't know how to process a given TLV and its Unknown TLV bit is not set. In the case of Address Messages, the Address List TLV is mandatory and should appear before any optional TLV in the message. If that doesn't happen the correct status notification to send is "Missing Message Parameters" (non-fatal error). Also, add a missing htons when creating an Address List TLV. Since the value of TLV_TYPE_ADDRLIST is 0x0101 this missing htons wasn't noticed earlier. Signed-off-by: Renato Westphal --- ldpd/address.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ldpd/address.c b/ldpd/address.c index cb2f505f7b..25c03b811b 100644 --- a/ldpd/address.c +++ b/ldpd/address.c @@ -162,7 +162,7 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len) return (-1); } if (ntohs(alt.type) != TLV_TYPE_ADDRLIST) { - session_shutdown(nbr, S_UNKNOWN_TLV, msg.id, msg.type); + send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type); return (-1); } switch (ntohs(alt.family)) { @@ -242,7 +242,7 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af, int err = 0; memset(&alt, 0, sizeof(alt)); - alt.type = TLV_TYPE_ADDRLIST; + alt.type = htons(TLV_TYPE_ADDRLIST); alt.length = htons(size - TLV_HDR_SIZE); switch (af) { From 357db52712f04401a2fde1369b24b3e46e151ecb Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 07/18] ldpd: the PW Status is an unknown TLV Without this fix, any LDP speaker that doesn't implement RFC 4447 will shut down the session upon receipt of a PWid Label Mapping (unless the use of the PW-Status TLV is disabled via configuration). Signed-off-by: Renato Westphal --- ldpd/ldp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldpd/ldp.h b/ldpd/ldp.h index c068e22918..88bfa3a822 100644 --- a/ldpd/ldp.h +++ b/ldpd/ldp.h @@ -92,7 +92,7 @@ #define TLV_TYPE_FRSESSION 0x0502 #define TLV_TYPE_LABELREQUEST 0x0600 /* RFC 4447 */ -#define TLV_TYPE_PW_STATUS 0x096A +#define TLV_TYPE_PW_STATUS 0x896A #define TLV_TYPE_PW_IF_PARAM 0x096B #define TLV_TYPE_PW_GROUP_ID 0x096C /* RFC 7552 */ From be8e0d318815395a49632f8c6546be1f96c17557 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 08/18] ldpd: fix processing of Label Withdraw messages Whenever we receive a Label Withdraw message with an optional Label TLV, we should check if this label matches the label previously received from this neighbor for this FEC. If they don't match then we shouldn't uninstall the previous label from the kernel. This fixes a misinterpretation from the "Receive Label Withdraw" algorithm described in the A.1.5 section of RFC 5036. Also, simplify the check of pending withdraws in lde_check_release() and lde_check_release_wcard(). Signed-off-by: Renato Westphal --- ldpd/lde_lib.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index 6ec88a19bd..02730189a8 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -624,8 +624,7 @@ lde_check_release(struct map *map, struct lde_nbr *ln) /* LRl.3: first check if we have a pending withdraw running */ lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); - if (lw && (map->label == NO_LABEL || - (lw->label != NO_LABEL && map->label == lw->label))) { + if (lw && (map->label == NO_LABEL || map->label == lw->label)) { /* LRl.4: delete record of outstanding label withdraw */ lde_wdraw_del(ln, lw); } @@ -654,8 +653,7 @@ lde_check_release_wcard(struct map *map, struct lde_nbr *ln) /* LRl.3: first check if we have a pending withdraw running */ lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); - if (lw && (map->label == NO_LABEL || - (lw->label != NO_LABEL && map->label == lw->label))) { + if (lw && (map->label == NO_LABEL || map->label == lw->label)) { /* LRl.4: delete record of outstanding lbl withdraw */ lde_wdraw_del(ln, lw); } @@ -707,6 +705,9 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln) default: break; } + if (map->label != NO_LABEL && map->label != fnh->remote_label) + continue; + lde_send_delete_klabel(fn, fnh); fnh->remote_label = NO_LABEL; } @@ -751,6 +752,10 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) default: break; } + if (map->label != NO_LABEL && map->label != + fnh->remote_label) + continue; + lde_send_delete_klabel(fn, fnh); fnh->remote_label = NO_LABEL; } From 0bcc2916a08dfb762d8a5775e6b01a4885c8936a Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 09/18] ldpd: implement support for PWid group wildcards This was missing from our original RFC 4447 VPLS implementation. Now ldpd understands group wildcards as mandated by the RFC, but we still don't send them ourselves. I can't see any case in which sending a group wildcard would be useful, but nonetheless this patch provides a function called lde_send_labelwithdraw_pwid_wcard() which is ready to be used in the future anytime we feel like it might be useful. Signed-off-by: Renato Westphal --- ldpd/l2vpn.c | 71 +++++++++++++++++++++++++++++++++++++++++++++----- ldpd/lde.c | 68 ++++++++++++++++++++++++++--------------------- ldpd/lde.h | 16 +++++++++--- ldpd/lde_lib.c | 56 ++++++++++++++++++++++++++++++++------- ldpd/log.c | 6 ++--- 5 files changed, 165 insertions(+), 52 deletions(-) diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c index 792608d425..ad3e8199c9 100644 --- a/ldpd/l2vpn.c +++ b/ldpd/l2vpn.c @@ -330,7 +330,7 @@ l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map) st.status_code = S_WRONG_CBIT; st.msg_id = map->msg_id; st.msg_type = htons(MSG_TYPE_LABELMAPPING); - lde_send_labelwithdraw(ln, fn, NO_LABEL, &st); + lde_send_labelwithdraw(ln, fn, NULL, &st); pw->flags &= ~F_PW_CWORD; lde_send_labelmapping(ln, fn, 1); @@ -353,7 +353,7 @@ l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map) } void -l2vpn_send_pw_status(uint32_t peerid, uint32_t status, struct fec *fec) +l2vpn_send_pw_status(struct lde_nbr *ln, uint32_t status, struct fec *fec) { struct notify_msg nm; @@ -364,8 +364,27 @@ l2vpn_send_pw_status(uint32_t peerid, uint32_t status, struct fec *fec) lde_fec2map(fec, &nm.fec); nm.flags |= F_NOTIF_FEC; - lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0, - &nm, sizeof(nm)); + lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm, + sizeof(nm)); +} + +void +l2vpn_send_pw_status_wcard(struct lde_nbr *ln, uint32_t status, + uint16_t pw_type, uint32_t group_id) +{ + struct notify_msg nm; + + memset(&nm, 0, sizeof(nm)); + nm.status_code = S_PW_STATUS; + nm.pw_status = status; + nm.flags |= F_NOTIF_PW_STATUS; + nm.fec.type = MAP_TYPE_PWID; + nm.fec.fec.pwid.type = pw_type; + nm.fec.fec.pwid.group_id = group_id; + nm.flags |= F_NOTIF_FEC; + + lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm, + sizeof(nm)); } void @@ -376,9 +395,10 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm) struct fec_nh *fnh; struct l2vpn_pw *pw; - /* TODO group wildcard */ - if (!(nm->fec.flags & F_MAP_PW_ID)) + if (!(nm->fec.flags & F_MAP_PW_ID)) { + l2vpn_recv_pw_status_wcard(ln, nm); return; + } lde_map2fec(&nm->fec, ln->id, &fec); fn = (struct fec_node *)fec_find(&ft, &fec); @@ -406,6 +426,45 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm) lde_send_delete_klabel(fn, fnh); } +/* RFC4447 PWid group wildcard */ +void +l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm) +{ + struct fec *f; + struct fec_node *fn; + struct fec_nh *fnh; + struct l2vpn_pw *pw; + + RB_FOREACH(f, fec_tree, &ft) { + fn = (struct fec_node *)f; + if (fn->fec.type != FEC_TYPE_PWID) + continue; + if (fn->fec.u.pwid.type != nm->fec.fec.pwid.type) + continue; + + pw = (struct l2vpn_pw *) fn->data; + if (pw == NULL) + continue; + if (pw->remote_group != nm->fec.fec.pwid.group_id) + continue; + + fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, + 0, 0); + if (fnh == NULL) + continue; + + /* remote status didn't change */ + if (pw->remote_status == nm->pw_status) + continue; + pw->remote_status = nm->pw_status; + + if (l2vpn_pw_ok(pw, fnh)) + lde_send_change_klabel(fn, fnh); + else + lde_send_delete_klabel(fn, fnh); + } +} + void l2vpn_sync_pws(int af, union ldpd_addr *addr) { diff --git a/ldpd/lde.c b/ldpd/lde.c index 6ac0f07daf..3041c44bdc 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -259,16 +259,10 @@ lde_dispatch_imsg(struct thread *thread) lde_check_request(&map, ln); break; case IMSG_LABEL_RELEASE: - if (map.type == MAP_TYPE_WILDCARD) - lde_check_release_wcard(&map, ln); - else - lde_check_release(&map, ln); + lde_check_release(&map, ln); break; case IMSG_LABEL_WITHDRAW: - if (map.type == MAP_TYPE_WILDCARD) - lde_check_withdraw_wcard(&map, ln); - else - lde_check_withdraw(&map, ln); + lde_check_withdraw(&map, ln); break; case IMSG_LABEL_ABORT: /* not necessary */ @@ -929,8 +923,8 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) } void -lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label, - struct status_tlv *st) +lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, + struct map *wcard, struct status_tlv *st) { struct lde_wdraw *lw; struct map map; @@ -959,11 +953,8 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label, break; } map.label = fn->local_label; - } else { - memset(&map, 0, sizeof(map)); - map.type = MAP_TYPE_WILDCARD; - map.label = label; - } + } else + memcpy(&map, wcard, sizeof(map)); if (st) { map.st.status_code = st->status_code; @@ -984,8 +975,13 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label, lw = lde_wdraw_add(ln, fn); lw->label = map.label; } else { + struct lde_map *me; + RB_FOREACH(f, fec_tree, &ft) { fn = (struct fec_node *)f; + me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec); + if (lde_wildcard_apply(wcard, &fn->fec, me) == 0) + continue; lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); @@ -997,16 +993,34 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label, } void -lde_send_labelwithdraw_all(struct fec_node *fn, uint32_t label) +lde_send_labelwithdraw_wcard(struct lde_nbr *ln, uint32_t label) { - struct lde_nbr *ln; + struct map wcard; - RB_FOREACH(ln, nbr_tree, &lde_nbrs) - lde_send_labelwithdraw(ln, fn, label, NULL); + memset(&wcard, 0, sizeof(wcard)); + wcard.type = MAP_TYPE_WILDCARD; + wcard.label = label; + lde_send_labelwithdraw(ln, NULL, &wcard, NULL); } void -lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label) +lde_send_labelwithdraw_pwid_wcard(struct lde_nbr *ln, uint16_t pw_type, + uint32_t group_id) +{ + struct map wcard; + + memset(&wcard, 0, sizeof(wcard)); + wcard.type = MAP_TYPE_PWID; + wcard.fec.pwid.type = pw_type; + wcard.fec.pwid.group_id = group_id; + /* we can not append a Label TLV when using PWid group wildcards. */ + wcard.label = NO_LABEL; + lde_send_labelwithdraw(ln, NULL, &wcard, NULL); +} + +void +lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, + struct map *wcard, uint32_t label) { struct map map; struct l2vpn_pw *pw; @@ -1032,10 +1046,8 @@ lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label) map.flags |= F_MAP_PW_CWORD; break; } - } else { - memset(&map, 0, sizeof(map)); - map.type = MAP_TYPE_WILDCARD; - } + } else + memcpy(&map, wcard, sizeof(map)); map.label = label; lde_imsg_compose_ldpe(IMSG_RELEASE_ADD, ln->peerid, 0, @@ -1352,13 +1364,11 @@ lde_change_egress_label(int af) /* explicitly withdraw all null labels */ RB_FOREACH(ln, nbr_tree, &lde_nbrs) { - lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IMPLNULL, NULL); + lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IMPLNULL); if (ln->v4_enabled) - lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IPV4NULL, - NULL); + lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV4NULL); if (ln->v6_enabled) - lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IPV6NULL, - NULL); + lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV6NULL); } /* update label of connected routes */ diff --git a/ldpd/lde.h b/ldpd/lde.h index b3fa2d469b..367ba254db 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -143,10 +143,12 @@ void lde_map2fec(struct map *, struct in_addr, struct fec *); void lde_send_labelmapping(struct lde_nbr *, struct fec_node *, int); void lde_send_labelwithdraw(struct lde_nbr *, struct fec_node *, - uint32_t, struct status_tlv *); -void lde_send_labelwithdraw_all(struct fec_node *, uint32_t); -void lde_send_labelrelease(struct lde_nbr *, struct fec_node *, + struct map *, struct status_tlv *); +void lde_send_labelwithdraw_wcard(struct lde_nbr *, uint32_t); +void lde_send_labelwithdraw_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); struct lde_nbr *lde_nbr_find_by_lsrid(struct in_addr); @@ -183,6 +185,8 @@ void lde_check_release(struct map *, struct lde_nbr *); void lde_check_release_wcard(struct map *, struct lde_nbr *); void lde_check_withdraw(struct map *, struct lde_nbr *); void lde_check_withdraw_wcard(struct map *, struct lde_nbr *); +int lde_wildcard_apply(struct map *, struct fec *, + struct lde_map *); int lde_gc_timer(struct thread *); void lde_gc_start_timer(void); void lde_gc_stop_timer(void); @@ -205,8 +209,12 @@ void l2vpn_pw_reset(struct l2vpn_pw *); int l2vpn_pw_ok(struct l2vpn_pw *, struct fec_nh *); int l2vpn_pw_negotiate(struct lde_nbr *, struct fec_node *, struct map *); -void l2vpn_send_pw_status(uint32_t, uint32_t, struct fec *); +void l2vpn_send_pw_status(struct lde_nbr *, uint32_t, struct fec *); +void l2vpn_send_pw_status_wcard(struct lde_nbr *, uint32_t, + uint16_t, uint32_t); void l2vpn_recv_pw_status(struct lde_nbr *, struct notify_msg *); +void l2vpn_recv_pw_status_wcard(struct lde_nbr *, + struct notify_msg *); void l2vpn_sync_pws(int, union ldpd_addr *); void l2vpn_pw_ctl(pid_t); void l2vpn_binding_ctl(pid_t); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index 02730189a8..c37a9e9660 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -374,7 +374,8 @@ lde_kernel_update(struct fec *fec) } if (LIST_EMPTY(&fn->nexthops)) { - lde_send_labelwithdraw_all(fn, NO_LABEL); + RB_FOREACH(ln, nbr_tree, &lde_nbrs) + lde_send_labelwithdraw(ln, fn, NULL, NULL); fn->local_label = NO_LABEL; fn->data = NULL; } else { @@ -478,7 +479,7 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln) /* LMp.10 */ if (me->map.label != map->label && lre == NULL) { /* LMp.10a */ - lde_send_labelrelease(ln, fn, me->map.label); + lde_send_labelrelease(ln, fn, NULL, me->map.label); /* * Can not use lde_nbr_find_by_addr() because there's @@ -612,9 +613,12 @@ lde_check_release(struct map *map, struct lde_nbr *ln) struct lde_wdraw *lw; struct lde_map *me; - /* TODO group wildcard */ - if (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID)) + /* wildcard label release */ + if (map->type == MAP_TYPE_WILDCARD || + (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))) { + lde_check_release_wcard(map, ln); return; + } lde_map2fec(map, ln->id, &fec); fn = (struct fec_node *)fec_find(&ft, &fec); @@ -650,6 +654,11 @@ lde_check_release_wcard(struct map *map, struct lde_nbr *ln) RB_FOREACH(f, fec_tree, &ft) { fn = (struct fec_node *)f; + me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec); + + /* LRl.1: does FEC match a known FEC? */ + if (lde_wildcard_apply(map, &fn->fec, me) == 0) + continue; /* LRl.3: first check if we have a pending withdraw running */ lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); @@ -659,7 +668,6 @@ lde_check_release_wcard(struct map *map, struct lde_nbr *ln) } /* LRl.6: check sent map list and remove it if available */ - me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec); if (me && (map->label == NO_LABEL || map->label == me->map.label)) lde_map_del(ln, me, 1); @@ -680,9 +688,12 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln) struct lde_map *me; struct l2vpn_pw *pw; - /* TODO group wildcard */ - if (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID)) + /* wildcard label withdraw */ + if (map->type == MAP_TYPE_WILDCARD || + (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))) { + lde_check_withdraw_wcard(map, ln); return; + } lde_map2fec(map, ln->id, &fec); fn = (struct fec_node *)fec_find(&ft, &fec); @@ -713,7 +724,7 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln) } /* LWd.2: send label release */ - lde_send_labelrelease(ln, fn, map->label); + lde_send_labelrelease(ln, fn, NULL, map->label); /* LWd.3: check previously received label mapping */ me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); @@ -731,10 +742,14 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) struct lde_map *me; /* LWd.2: send label release */ - lde_send_labelrelease(ln, NULL, map->label); + lde_send_labelrelease(ln, NULL, map, map->label); RB_FOREACH(f, fec_tree, &ft) { fn = (struct fec_node *)f; + me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); + + if (lde_wildcard_apply(map, &fn->fec, me) == 0) + continue; /* LWd.1: remove label from forwarding/switching use */ LIST_FOREACH(fnh, &fn->nexthops, entry) { @@ -761,7 +776,6 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) } /* LWd.3: check previously received label mapping */ - me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); if (me && (map->label == NO_LABEL || map->label == me->map.label)) /* @@ -772,6 +786,28 @@ 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_PWID: + /* RFC4447 pw-id group wildcard */ + if (fec->type != FEC_TYPE_PWID) + return (0); + if (fec->u.pwid.type != wcard->fec.pwid.type) + return (0); + if (me == NULL || (me->map.fec.pwid.group_id != + wcard->fec.pwid.group_id)) + return (0); + return (1); + default: + fatalx("lde_wildcard_apply: unexpected fec type"); + } +} + /* gabage collector timer: timer to remove dead entries from the LIB */ /* ARGSUSED */ diff --git a/ldpd/log.c b/ldpd/log.c index 77efdb4714..661fe04b19 100644 --- a/ldpd/log.c +++ b/ldpd/log.c @@ -313,7 +313,7 @@ log_hello_src(const struct hello_source *src) const char * log_map(const struct map *map) { - static char buf[64]; + static char buf[128]; switch (map->type) { case MAP_TYPE_WILDCARD: @@ -327,8 +327,8 @@ log_map(const struct map *map) return ("???"); break; case MAP_TYPE_PWID: - if (snprintf(buf, sizeof(buf), "pwid %u (%s)", - map->fec.pwid.pwid, + if (snprintf(buf, sizeof(buf), "pw-id %u group-id %u (%s)", + map->fec.pwid.pwid, map->fec.pwid.group_id, pw_type_name(map->fec.pwid.type)) == -1) return ("???"); break; From 8819fc38a0610e5828b7cc65fbbfc42e6ea1cc6a Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 10/18] ldpd: implement RFC 5561 (LDP Capabilities) This patch per-se doesn't introduce any useful functionality, but prepares the ground for new enhancements to ldpd (i.e. implementation of new RFCs that make use of LDP capabilities). Signed-off-by: Renato Westphal --- ldpd/init.c | 152 ++++++++++++++++++++++++++++++++++++++++++-- ldpd/labelmapping.c | 8 ++- ldpd/ldp.h | 18 ++++++ ldpd/ldpd.h | 6 ++ ldpd/ldpe.h | 5 ++ ldpd/log.c | 4 ++ ldpd/notification.c | 55 +++++++++++++++- ldpd/packet.c | 13 ++-- 8 files changed, 241 insertions(+), 20 deletions(-) diff --git a/ldpd/init.c b/ldpd/init.c index 030bff2f51..4b3eab270d 100644 --- a/ldpd/init.c +++ b/ldpd/init.c @@ -24,6 +24,7 @@ #include "ldp_debug.h" static int gen_init_prms_tlv(struct ibuf *, struct nbr *); +static int gen_cap_dynamic_tlv(struct ibuf *); void send_init(struct nbr *nbr) @@ -34,15 +35,16 @@ send_init(struct nbr *nbr) debug_msg_send("initialization: lsr-id %s", inet_ntoa(nbr->id)); - size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE; + size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE + + CAP_TLV_DYNAMIC_SIZE; if ((buf = ibuf_open(size)) == NULL) fatal(__func__); err |= gen_ldp_hdr(buf, size); size -= LDP_HDR_SIZE; err |= gen_msg_hdr(buf, MSG_TYPE_INIT, size); - size -= LDP_MSG_SIZE; err |= gen_init_prms_tlv(buf, nbr); + err |= gen_cap_dynamic_tlv(buf); if (err) { ibuf_free(buf); return; @@ -57,6 +59,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len) struct ldp_msg msg; struct sess_prms_tlv sess; uint16_t max_pdu_len; + int caps_rcvd = 0; debug_msg_recv("initialization: lsr-id %s", inet_ntoa(nbr->id)); @@ -93,6 +96,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len) /* Optional Parameters */ while (len > 0) { struct tlv tlv; + uint16_t tlv_type; uint16_t tlv_len; if (len < sizeof(tlv)) { @@ -101,6 +105,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len) } memcpy(&tlv, buf, TLV_HDR_SIZE); + tlv_type = ntohs(tlv.type); tlv_len = ntohs(tlv.length); if (tlv_len + TLV_HDR_SIZE > len) { session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); @@ -109,17 +114,42 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len) buf += TLV_HDR_SIZE; len -= TLV_HDR_SIZE; - switch (ntohs(tlv.type)) { + /* + * RFC 5561 - Section 6: + * "The S-bit of a Capability Parameter in an Initialization + * message MUST be 1 and SHOULD be ignored on receipt". + */ + switch (tlv_type) { case TLV_TYPE_ATMSESSIONPAR: session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type); return (-1); case TLV_TYPE_FRSESSION: session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type); return (-1); + case TLV_TYPE_DYNAMIC_CAP: + if (tlv_len != CAP_TLV_DYNAMIC_LEN) { + session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, + msg.type); + return (-1); + } + + if (caps_rcvd & F_CAP_TLV_RCVD_DYNAMIC) { + session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, + msg.type); + return (-1); + } + caps_rcvd |= F_CAP_TLV_RCVD_DYNAMIC; + + nbr->flags |= F_NBR_CAP_DYNAMIC; + + log_debug("%s: lsr-id %s announced the Dynamic " + "Capability Announcement capability", __func__, + inet_ntoa(nbr->id)); + break; default: if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) - send_notification(nbr->tcp, S_UNKNOWN_TLV, - msg.id, msg.type); + send_notification_rtlvs(nbr, S_UNSSUPORTDCAP, + msg.id, msg.type, tlv_type, tlv_len, buf); /* ignore unknown tlv */ break; } @@ -145,6 +175,104 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len) return (0); } +void +send_capability(struct nbr *nbr, uint16_t capability, int enable) +{ + struct ibuf *buf; + uint16_t size; + int err = 0; + + log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); + + size = LDP_HDR_SIZE + LDP_MSG_SIZE + CAP_TLV_DYNAMIC_SIZE; + if ((buf = ibuf_open(size)) == NULL) + fatal(__func__); + + err |= gen_ldp_hdr(buf, size); + size -= LDP_HDR_SIZE; + err |= gen_msg_hdr(buf, MSG_TYPE_CAPABILITY, size); + + switch (capability) { + case TLV_TYPE_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; + + 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; + + 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_DYNAMIC_CAP: + /* + * RFC 5561 - Section 9: + * "An LDP speaker that receives a Capability message + * from a peer that includes the Dynamic Capability + * Announcement Parameter SHOULD silently ignore the + * parameter and process any other Capability Parameters + * in the message". + */ + /* FALLTHROUGH */ + default: + if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) + send_notification_rtlvs(nbr, S_UNSSUPORTDCAP, + msg.id, msg.type, tlv_type, tlv_len, buf); + /* ignore unknown tlv */ + break; + } + buf += tlv_len; + len -= tlv_len; + } + + nbr_fsm(nbr, NBR_EVT_PDU_RCVD); + + return (0); +} + static int gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr) { @@ -163,3 +291,17 @@ gen_init_prms_tlv(struct ibuf *buf, struct nbr *nbr) return (ibuf_add(buf, &parms, SESS_PRMS_SIZE)); } + +static int +gen_cap_dynamic_tlv(struct ibuf *buf) +{ + struct capability_tlv cap; + + memset(&cap, 0, sizeof(cap)); + cap.type = htons(TLV_TYPE_DYNAMIC_CAP); + cap.length = htons(CAP_TLV_DYNAMIC_LEN); + /* the S-bit is always 1 for the Dynamic Capability Announcement */ + cap.reserved = STATE_BIT; + + return (ibuf_add(buf, &cap, CAP_TLV_DYNAMIC_SIZE)); +} diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c index d9f71fdf6b..e35f01b136 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -238,6 +238,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) /* Optional Parameters */ while (len > 0) { struct tlv tlv; + uint16_t tlv_type; uint16_t tlv_len; uint32_t reqbuf, labelbuf, statusbuf; @@ -247,6 +248,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) } memcpy(&tlv, buf, TLV_HDR_SIZE); + tlv_type = ntohs(tlv.type); tlv_len = ntohs(tlv.length); if (tlv_len + TLV_HDR_SIZE > len) { session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); @@ -255,7 +257,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) buf += TLV_HDR_SIZE; len -= TLV_HDR_SIZE; - switch (ntohs(tlv.type)) { + switch (tlv_type) { case TLV_TYPE_LABELREQUEST: switch (type) { case MSG_TYPE_LABELMAPPING: @@ -340,8 +342,8 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) break; default: if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) - send_notification(nbr->tcp, S_UNKNOWN_TLV, - msg.id, msg.type); + send_notification_rtlvs(nbr, S_UNKNOWN_TLV, + msg.id, msg.type, tlv_type, tlv_len, buf); /* ignore unknown tlv */ break; } diff --git a/ldpd/ldp.h b/ldpd/ldp.h index 88bfa3a822..75cc2cc15a 100644 --- a/ldpd/ldp.h +++ b/ldpd/ldp.h @@ -63,6 +63,7 @@ #define MSG_TYPE_HELLO 0x0100 #define MSG_TYPE_INIT 0x0200 #define MSG_TYPE_KEEPALIVE 0x0201 +#define MSG_TYPE_CAPABILITY 0x0202 /* RFC 5561 */ #define MSG_TYPE_ADDR 0x0300 #define MSG_TYPE_ADDRWITHDRAW 0x0301 #define MSG_TYPE_LABELMAPPING 0x0400 @@ -95,6 +96,9 @@ #define TLV_TYPE_PW_STATUS 0x896A #define TLV_TYPE_PW_IF_PARAM 0x096B #define TLV_TYPE_PW_GROUP_ID 0x096C +/* RFC 5561 */ +#define TLV_TYPE_RETURNED_TLVS 0x8304 +#define TLV_TYPE_DYNAMIC_CAP 0x8506 /* RFC 7552 */ #define TLV_TYPE_DUALSTACK 0x8701 @@ -196,6 +200,8 @@ struct hello_prms_opt16_tlv { #define S_UNASSIGN_TAI 0x00000029 #define S_MISCONF_ERR 0x0000002A #define S_WITHDRAW_MTHD 0x0000002B +/* RFC 5561 */ +#define S_UNSSUPORTDCAP 0x0000002E /* RFC 7552 */ #define S_TRANS_MISMTCH 0x80000032 #define S_DS_NONCMPLNCE 0x80000033 @@ -227,6 +233,18 @@ struct status_tlv { #define STATUS_TLV_LEN 10 #define STATUS_FATAL 0x80000000 +struct capability_tlv { + uint16_t type; + uint16_t length; + uint8_t reserved; +}; +#define STATE_BIT 0x80 + +#define F_CAP_TLV_RCVD_DYNAMIC 0x01 + +#define CAP_TLV_DYNAMIC_SIZE 5 +#define CAP_TLV_DYNAMIC_LEN 1 + #define AF_IPV4 0x1 #define AF_IPV6 0x2 diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index ff3af19db4..43743cca84 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -244,10 +244,16 @@ struct notify_msg { uint16_t msg_type; /* network byte order */ uint32_t pw_status; struct map fec; + struct { + uint16_t type; + uint16_t length; + char *data; + } rtlvs; uint8_t flags; }; #define F_NOTIF_PW_STATUS 0x01 /* pseudowire status tlv present */ #define F_NOTIF_FEC 0x02 /* fec tlv present */ +#define F_NOTIF_RETURNED_TLVS 0x04 /* returned tlvs present */ struct if_addr { LIST_ENTRY(if_addr) entry; diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index d79c9a82ca..ce1b700228 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -111,6 +111,7 @@ struct nbr { int flags; }; #define F_NBR_GTSM_NEGOTIATED 0x01 +#define F_NBR_CAP_DYNAMIC 0x02 RB_HEAD(nbr_id_head, nbr); RB_PROTOTYPE(nbr_id_head, nbr, id_tree, nbr_id_compare) @@ -159,6 +160,8 @@ void recv_hello(struct in_addr, struct ldp_msg *, int, union ldpd_addr *, /* init.c */ void send_init(struct nbr *); int recv_init(struct nbr *, char *, uint16_t); +void send_capability(struct nbr *, uint16_t, int); +int recv_capability(struct nbr *, char *, uint16_t); /* keepalive.c */ void send_keepalive(struct nbr *); @@ -167,6 +170,8 @@ int recv_keepalive(struct nbr *, char *, uint16_t); /* notification.c */ void send_notification_full(struct tcp_conn *, struct notify_msg *); void send_notification(struct tcp_conn *, uint32_t, uint32_t, uint16_t); +void send_notification_rtlvs(struct nbr *, uint32_t, uint32_t, uint16_t, + uint16_t, uint16_t, char *); int recv_notification(struct nbr *, char *, uint16_t); int gen_status_tlv(struct ibuf *, uint32_t, uint32_t, uint16_t); diff --git a/ldpd/log.c b/ldpd/log.c index 661fe04b19..a02210efe4 100644 --- a/ldpd/log.c +++ b/ldpd/log.c @@ -464,6 +464,8 @@ msg_name(uint16_t msg) return ("initialization"); case MSG_TYPE_KEEPALIVE: return ("keepalive"); + case MSG_TYPE_CAPABILITY: + return ("capability"); case MSG_TYPE_ADDR: return ("address"); case MSG_TYPE_ADDRWITHDRAW: @@ -557,6 +559,8 @@ status_code_name(uint32_t status) return ("Generic Misconfiguration Error"); case S_WITHDRAW_MTHD: return ("Label Withdraw PW Status Method"); + case S_UNSSUPORTDCAP: + return ("Unsupported Capability"); case S_TRANS_MISMTCH: return ("Transport Connection Mismatch"); case S_DS_NONCMPLNCE: diff --git a/ldpd/notification.c b/ldpd/notification.c index d573925314..69d4ab8028 100644 --- a/ldpd/notification.c +++ b/ldpd/notification.c @@ -24,6 +24,7 @@ #include "ldpe.h" #include "ldp_debug.h" +static int gen_returned_tlvs(struct ibuf *, uint16_t, uint16_t, char *); static void log_msg_notification(int, struct nbr *, struct notify_msg *); void @@ -47,6 +48,8 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm) break; } } + if (nm->flags & F_NOTIF_RETURNED_TLVS) + size += TLV_HDR_SIZE * 2 + nm->rtlvs.length; if ((buf = ibuf_open(size)) == NULL) fatal(__func__); @@ -60,6 +63,9 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm) err |= gen_pw_status_tlv(buf, nm->pw_status); if (nm->flags & F_NOTIF_FEC) err |= gen_fec_tlv(buf, &nm->fec); + if (nm->flags & F_NOTIF_RETURNED_TLVS) + err |= gen_returned_tlvs(buf, nm->rtlvs.type, nm->rtlvs.length, + nm->rtlvs.data); if (err) { ibuf_free(buf); return; @@ -88,6 +94,27 @@ send_notification(struct tcp_conn *tcp, uint32_t status_code, uint32_t msg_id, send_notification_full(tcp, &nm); } +void +send_notification_rtlvs(struct nbr *nbr, uint32_t status_code, uint32_t msg_id, + uint16_t msg_type, uint16_t tlv_type, uint16_t tlv_len, char *tlv_data) +{ + struct notify_msg nm; + + memset(&nm, 0, sizeof(nm)); + nm.status_code = status_code; + nm.msg_id = msg_id; + nm.msg_type = msg_type; + /* do not append the given TLV if it's too big (shouldn't happen) */ + if (tlv_len < 1024) { + nm.rtlvs.type = tlv_type; + nm.rtlvs.length = tlv_len; + nm.rtlvs.data = tlv_data; + nm.flags |= F_NOTIF_RETURNED_TLVS; + } + + send_notification_full(nbr->tcp, &nm); +} + int recv_notification(struct nbr *nbr, char *buf, uint16_t len) { @@ -120,6 +147,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) /* Optional Parameters */ while (len > 0) { struct tlv tlv; + uint16_t tlv_type; uint16_t tlv_len; if (len < sizeof(tlv)) { @@ -128,6 +156,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) } memcpy(&tlv, buf, TLV_HDR_SIZE); + tlv_type = ntohs(tlv.type); tlv_len = ntohs(tlv.length); if (tlv_len + TLV_HDR_SIZE > len) { session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); @@ -136,7 +165,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) buf += TLV_HDR_SIZE; len -= TLV_HDR_SIZE; - switch (ntohs(tlv.type)) { + switch (tlv_type) { case TLV_TYPE_EXTSTATUS: case TLV_TYPE_RETURNEDPDU: case TLV_TYPE_RETURNEDMSG: @@ -166,8 +195,8 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) break; default: if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) - send_notification(nbr->tcp, S_UNKNOWN_TLV, - msg.id, msg.type); + send_notification_rtlvs(nbr, S_UNKNOWN_TLV, + msg.id, msg.type, tlv_type, tlv_len, buf); /* ignore unknown tlv */ break; } @@ -229,6 +258,26 @@ gen_status_tlv(struct ibuf *buf, uint32_t status_code, uint32_t msg_id, return (ibuf_add(buf, &st, STATUS_SIZE)); } +static int +gen_returned_tlvs(struct ibuf *buf, uint16_t type, uint16_t length, + char *tlv_data) +{ + struct tlv rtlvs; + struct tlv tlv; + int err; + + rtlvs.type = htons(TLV_TYPE_RETURNED_TLVS); + rtlvs.length = htons(length + TLV_HDR_SIZE); + tlv.type = htons(type); + tlv.length = htons(length); + + err = ibuf_add(buf, &rtlvs, sizeof(rtlvs)); + err |= ibuf_add(buf, &tlv, sizeof(tlv)); + err |= ibuf_add(buf, tlv_data, length); + + return (err); +} + void log_msg_notification(int out, struct nbr *nbr, struct notify_msg *nm) { diff --git a/ldpd/packet.c b/ldpd/packet.c index 653f67b8c2..a7be0f6b42 100644 --- a/ldpd/packet.c +++ b/ldpd/packet.c @@ -519,13 +519,7 @@ session_read(struct thread *thread) return (0); } break; - case MSG_TYPE_ADDR: - case MSG_TYPE_ADDRWITHDRAW: - case MSG_TYPE_LABELMAPPING: - case MSG_TYPE_LABELREQUEST: - case MSG_TYPE_LABELWITHDRAW: - case MSG_TYPE_LABELRELEASE: - case MSG_TYPE_LABELABORTREQ: + default: if (nbr->state != NBR_STA_OPER) { session_shutdown(nbr, S_SHUTDOWN, msg->id, msg->type); @@ -533,8 +527,6 @@ session_read(struct thread *thread) return (0); } break; - default: - break; } /* switch LDP packet type */ @@ -548,6 +540,9 @@ session_read(struct thread *thread) case MSG_TYPE_KEEPALIVE: ret = recv_keepalive(nbr, pdu, msg_size); break; + case MSG_TYPE_CAPABILITY: + ret = recv_capability(nbr, pdu, msg_size); + break; case MSG_TYPE_ADDR: case MSG_TYPE_ADDRWITHDRAW: ret = recv_address(nbr, pdu, msg_size); From d4afb81972d9666d730445fa81090d711fc0d54f Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 11/18] ldpd: implement RFC 5918 (Typed Wildcard FEC) Signed-off-by: Renato Westphal --- ldpd/init.c | 68 ++++++++++++++++++++++++- ldpd/labelmapping.c | 120 +++++++++++++++++++++++++++++++++++++++++++- ldpd/lde.c | 14 ++++++ ldpd/lde.h | 3 ++ ldpd/lde_lib.c | 56 +++++++++++++++++++++ ldpd/ldp.h | 8 +++ ldpd/ldpd.h | 6 +++ ldpd/ldpe.h | 1 + ldpd/log.c | 17 +++++++ 9 files changed, 290 insertions(+), 3 deletions(-) diff --git a/ldpd/init.c b/ldpd/init.c index 4b3eab270d..13104b4ee6 100644 --- a/ldpd/init.c +++ b/ldpd/init.c @@ -25,6 +25,7 @@ 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); void send_init(struct nbr *nbr) @@ -36,7 +37,7 @@ send_init(struct nbr *nbr) debug_msg_send("initialization: lsr-id %s", inet_ntoa(nbr->id)); size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE + - CAP_TLV_DYNAMIC_SIZE; + CAP_TLV_DYNAMIC_SIZE + CAP_TLV_TWCARD_SIZE; if ((buf = ibuf_open(size)) == NULL) fatal(__func__); @@ -45,6 +46,7 @@ send_init(struct nbr *nbr) err |= gen_msg_hdr(buf, MSG_TYPE_INIT, size); err |= gen_init_prms_tlv(buf, nbr); err |= gen_cap_dynamic_tlv(buf); + err |= gen_cap_twcard_tlv(buf, 1); if (err) { ibuf_free(buf); return; @@ -146,6 +148,25 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len) "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; default: if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) send_notification_rtlvs(nbr, S_UNSSUPORTDCAP, @@ -193,6 +214,9 @@ send_capability(struct nbr *nbr, uint16_t capability, int enable) 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_DYNAMIC_CAP: /* * RFC 5561 - Section 9: @@ -218,6 +242,8 @@ 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)); @@ -230,6 +256,7 @@ recv_capability(struct nbr *nbr, char *buf, uint16_t len) 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); @@ -247,6 +274,31 @@ recv_capability(struct nbr *nbr, char *buf, uint16_t len) 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_DYNAMIC_CAP: /* * RFC 5561 - Section 9: @@ -305,3 +357,17 @@ gen_cap_dynamic_tlv(struct ibuf *buf) 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)); +} diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c index e35f01b136..4559ae628b 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -90,6 +90,16 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh) if (me->map.flags & F_MAP_PW_STATUS) msg_size += PW_STATUS_TLV_SIZE; break; + case MAP_TYPE_TYPED_WCARD: + msg_size += FEC_ELM_TWCARD_MIN_LEN; + switch (me->map.fec.twcard.type) { + case MAP_TYPE_PREFIX: + msg_size += sizeof(uint16_t); + break; + default: + fatalx("send_labelmessage: unexpected fec type"); + } + break; } if (me->map.label != NO_LABEL) msg_size += LABEL_TLV_SIZE; @@ -208,6 +218,24 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) } } + /* + * RFC 5561 - Section 4: + * "An LDP implementation that supports the Typed Wildcard + * FEC Element MUST support its use in Label Request, Label + * Withdraw, and Label Release messages". + */ + if (map.type == MAP_TYPE_TYPED_WCARD) { + switch (type) { + case MSG_TYPE_LABELMAPPING: + case MSG_TYPE_LABELABORTREQ: + session_shutdown(nbr, S_UNKNOWN_FEC, msg.id, + msg.type); + goto err; + default: + break; + } + } + /* * LDP supports the use of multiple FEC Elements per * FEC for the Label Mapping message only. @@ -524,7 +552,7 @@ gen_fec_tlv(struct ibuf *buf, struct map *map) { struct tlv ft; uint16_t family, len, pw_type, ifmtu; - uint8_t pw_len = 0; + uint8_t pw_len = 0, twcard_len; uint32_t group_id, pwid; int err = 0; @@ -594,6 +622,43 @@ gen_fec_tlv(struct ibuf *buf, struct map *map) err |= ibuf_add(buf, &ifmtu, sizeof(uint16_t)); } break; + case MAP_TYPE_TYPED_WCARD: + len = FEC_ELM_TWCARD_MIN_LEN; + switch (map->fec.twcard.type) { + case MAP_TYPE_PREFIX: + 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; + default: + fatalx("gen_fec_tlv: unexpected fec type"); + } + break; default: break; } @@ -606,7 +671,7 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf, uint16_t len, struct map *map) { uint16_t off = 0; - uint8_t pw_len; + uint8_t pw_len, twcard_len; map->type = *buf; off += sizeof(uint8_t); @@ -750,6 +815,57 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf, 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; + default: + send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, + msg->type); + return (-1); + } + return (off); default: send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type); diff --git a/ldpd/lde.c b/ldpd/lde.c index 3041c44bdc..948a4468cd 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -1003,6 +1003,20 @@ lde_send_labelwithdraw_wcard(struct lde_nbr *ln, uint32_t label) lde_send_labelwithdraw(ln, NULL, &wcard, NULL); } +void +lde_send_labelwithdraw_twcard_prefix(struct lde_nbr *ln, uint16_t af, + uint32_t label) +{ + struct map wcard; + + memset(&wcard, 0, sizeof(wcard)); + wcard.type = MAP_TYPE_TYPED_WCARD; + wcard.fec.twcard.type = MAP_TYPE_PREFIX; + wcard.fec.twcard.u.prefix_af = af; + wcard.label = label; + lde_send_labelwithdraw(ln, NULL, &wcard, NULL); +} + void lde_send_labelwithdraw_pwid_wcard(struct lde_nbr *ln, uint16_t pw_type, uint32_t group_id) diff --git a/ldpd/lde.h b/ldpd/lde.h index 367ba254db..148e583466 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -145,6 +145,8 @@ void lde_send_labelmapping(struct lde_nbr *, struct fec_node *, void lde_send_labelwithdraw(struct lde_nbr *, struct fec_node *, struct map *, struct status_tlv *); void lde_send_labelwithdraw_wcard(struct lde_nbr *, uint32_t); +void lde_send_labelwithdraw_twcard_prefix(struct lde_nbr *, + uint16_t, uint32_t); void lde_send_labelwithdraw_pwid_wcard(struct lde_nbr *, uint16_t, uint32_t); void lde_send_labelrelease(struct lde_nbr *, struct fec_node *, @@ -181,6 +183,7 @@ void lde_kernel_remove(struct fec *, int, union ldpd_addr *, void lde_kernel_update(struct fec *); void lde_check_mapping(struct map *, struct lde_nbr *); void lde_check_request(struct map *, struct lde_nbr *); +void lde_check_request_wcard(struct map *, struct lde_nbr *); void lde_check_release(struct map *, struct lde_nbr *); void lde_check_release_wcard(struct map *, struct lde_nbr *); void lde_check_withdraw(struct map *, struct lde_nbr *); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index c37a9e9660..71ab05f04d 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -555,6 +555,12 @@ lde_check_request(struct map *map, struct lde_nbr *ln) struct fec_node *fn; struct fec_nh *fnh; + /* wildcard label request */ + if (map->type == MAP_TYPE_TYPED_WCARD) { + lde_check_request_wcard(map, ln); + return; + } + /* LRq.1: skip loop detection (not necessary) */ /* LRq.2: is there a next hop for fec? */ @@ -605,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 lde_check_release(struct map *map, struct lde_nbr *ln) { @@ -615,6 +655,7 @@ lde_check_release(struct map *map, struct lde_nbr *ln) /* wildcard label release */ if (map->type == MAP_TYPE_WILDCARD || + map->type == MAP_TYPE_TYPED_WCARD || (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))) { lde_check_release_wcard(map, ln); return; @@ -690,6 +731,7 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln) /* wildcard label withdraw */ if (map->type == MAP_TYPE_WILDCARD || + map->type == MAP_TYPE_TYPED_WCARD || (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))) { lde_check_withdraw_wcard(map, ln); return; @@ -793,6 +835,20 @@ lde_wildcard_apply(struct map *wcard, struct fec *fec, struct lde_map *me) 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); + default: + fatalx("lde_wildcard_apply: unexpected fec type"); + } + break; case MAP_TYPE_PWID: /* RFC4447 pw-id group wildcard */ if (fec->type != FEC_TYPE_PWID) diff --git a/ldpd/ldp.h b/ldpd/ldp.h index 75cc2cc15a..2edf0475c9 100644 --- a/ldpd/ldp.h +++ b/ldpd/ldp.h @@ -99,6 +99,8 @@ /* RFC 5561 */ #define TLV_TYPE_RETURNED_TLVS 0x8304 #define TLV_TYPE_DYNAMIC_CAP 0x8506 +/* RFC 5918 */ +#define TLV_TYPE_TWCARD_CAP 0x850B /* RFC 7552 */ #define TLV_TYPE_DUALSTACK 0x8701 @@ -241,10 +243,14 @@ struct capability_tlv { #define STATE_BIT 0x80 #define F_CAP_TLV_RCVD_DYNAMIC 0x01 +#define F_CAP_TLV_RCVD_TWCARD 0x02 #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 AF_IPV4 0x1 #define AF_IPV6 0x2 @@ -261,9 +267,11 @@ struct address_list_tlv { #define FEC_ELM_PREFIX_MIN_LEN 4 #define FEC_PWID_ELM_MIN_LEN 8 #define FEC_PWID_SIZE 4 +#define FEC_ELM_TWCARD_MIN_LEN 3 #define MAP_TYPE_WILDCARD 0x01 #define MAP_TYPE_PREFIX 0x02 +#define MAP_TYPE_TYPED_WCARD 0x05 #define MAP_TYPE_PWID 0x80 #define MAP_TYPE_GENPWID 0x81 diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 43743cca84..36594e54ec 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -220,6 +220,12 @@ struct map { uint32_t group_id; uint16_t ifmtu; } pwid; + struct { + uint8_t type; + union { + uint16_t prefix_af; + } u; + } twcard; } fec; struct { uint32_t status_code; diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index ce1b700228..24512989de 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -112,6 +112,7 @@ struct nbr { }; #define F_NBR_GTSM_NEGOTIATED 0x01 #define F_NBR_CAP_DYNAMIC 0x02 +#define F_NBR_CAP_TWCARD 0x04 RB_HEAD(nbr_id_head, nbr); RB_PROTOTYPE(nbr_id_head, nbr, id_tree, nbr_id_compare) diff --git a/ldpd/log.c b/ldpd/log.c index a02210efe4..0e85daea29 100644 --- a/ldpd/log.c +++ b/ldpd/log.c @@ -332,6 +332,23 @@ log_map(const struct map *map) pw_type_name(map->fec.pwid.type)) == -1) return ("???"); break; + case MAP_TYPE_TYPED_WCARD: + if (snprintf(buf, sizeof(buf), "typed wildcard") < 0) + return ("???"); + switch (map->fec.twcard.type) { + case MAP_TYPE_PREFIX: + if (snprintf(buf + strlen(buf), sizeof(buf) - + strlen(buf), " (prefix, address-family %s)", + af_name(map->fec.twcard.u.prefix_af)) < 0) + return ("???"); + break; + default: + if (snprintf(buf + strlen(buf), sizeof(buf) - + strlen(buf), " (unknown type)") < 0) + return ("???"); + break; + } + break; default: return ("???"); } From aba50a83ea59e20bb23929f817560625153a0e25 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 12/18] ldpd: implement RFC 6667 (Typed Wildcard FEC for PWid) Signed-off-by: Renato Westphal --- ldpd/l2vpn.c | 23 +++++++++++++++++------ ldpd/labelmapping.c | 23 +++++++++++++++++++++++ ldpd/lde.c | 14 ++++++++++++++ ldpd/lde.h | 2 ++ ldpd/lde_lib.c | 7 +++++++ ldpd/ldp.h | 3 +++ ldpd/ldpd.h | 1 + ldpd/log.c | 8 ++++++++ 8 files changed, 75 insertions(+), 6 deletions(-) diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c index ad3e8199c9..8e17ccb258 100644 --- a/ldpd/l2vpn.c +++ b/ldpd/l2vpn.c @@ -395,7 +395,8 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm) struct fec_nh *fnh; struct l2vpn_pw *pw; - if (!(nm->fec.flags & F_MAP_PW_ID)) { + if (nm->fec.type == MAP_TYPE_TYPED_WCARD || + !(nm->fec.flags & F_MAP_PW_ID)) { l2vpn_recv_pw_status_wcard(ln, nm); return; } @@ -417,7 +418,6 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm) /* remote status didn't change */ if (pw->remote_status == nm->pw_status) return; - pw->remote_status = nm->pw_status; if (l2vpn_pw_ok(pw, fnh)) @@ -434,19 +434,30 @@ l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm) 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; - if (fn->fec.u.pwid.type != nm->fec.fec.pwid.type) - continue; pw = (struct l2vpn_pw *) fn->data; if (pw == NULL) continue; - if (pw->remote_group != nm->fec.fec.pwid.group_id) - 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); diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c index 4559ae628b..55b890ac70 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -94,6 +94,7 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh) msg_size += FEC_ELM_TWCARD_MIN_LEN; switch (me->map.fec.twcard.type) { case MAP_TYPE_PREFIX: + case MAP_TYPE_PWID: msg_size += sizeof(uint16_t); break; default: @@ -626,6 +627,7 @@ gen_fec_tlv(struct ibuf *buf, struct map *map) 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: @@ -655,6 +657,12 @@ gen_fec_tlv(struct ibuf *buf, struct map *map) 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"); } @@ -860,6 +868,21 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf, 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); diff --git a/ldpd/lde.c b/ldpd/lde.c index 948a4468cd..2392dbf6d0 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -1017,6 +1017,20 @@ lde_send_labelwithdraw_twcard_prefix(struct lde_nbr *ln, uint16_t af, 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) diff --git a/ldpd/lde.h b/ldpd/lde.h index 148e583466..b3af1bbaa4 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -147,6 +147,8 @@ void lde_send_labelwithdraw(struct lde_nbr *, struct fec_node *, void lde_send_labelwithdraw_wcard(struct lde_nbr *, uint32_t); void lde_send_labelwithdraw_twcard_prefix(struct lde_nbr *, uint16_t, uint32_t); +void lde_send_labelwithdraw_twcard_pwid(struct lde_nbr *, uint16_t, + uint32_t); void lde_send_labelwithdraw_pwid_wcard(struct lde_nbr *, uint16_t, uint32_t); void lde_send_labelrelease(struct lde_nbr *, struct fec_node *, diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index 71ab05f04d..4444a1e1ac 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -845,6 +845,13 @@ lde_wildcard_apply(struct map *wcard, struct fec *fec, struct lde_map *me) 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"); } diff --git a/ldpd/ldp.h b/ldpd/ldp.h index 2edf0475c9..ffdadf8be9 100644 --- a/ldpd/ldp.h +++ b/ldpd/ldp.h @@ -278,8 +278,11 @@ struct address_list_tlv { #define CONTROL_WORD_FLAG 0x8000 #define PW_TYPE_ETHERNET_TAGGED 0x0004 #define PW_TYPE_ETHERNET 0x0005 +#define PW_TYPE_WILDCARD 0x7FFF #define DEFAULT_PW_TYPE PW_TYPE_ETHERNET +#define PW_TWCARD_RESERVED_BIT 0x8000 + /* RFC 4447 Sub-TLV record */ struct subtlv { uint8_t type; diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 36594e54ec..7d12c66cee 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -224,6 +224,7 @@ struct map { uint8_t type; union { uint16_t prefix_af; + uint16_t pw_type; } u; } twcard; } fec; diff --git a/ldpd/log.c b/ldpd/log.c index 0e85daea29..5ad8ca0caf 100644 --- a/ldpd/log.c +++ b/ldpd/log.c @@ -342,6 +342,12 @@ log_map(const struct map *map) 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) @@ -598,6 +604,8 @@ pw_type_name(uint16_t pw_type) return ("Eth Tagged"); case PW_TYPE_ETHERNET: return ("Ethernet"); + case PW_TYPE_WILDCARD: + return ("Wildcard"); default: snprintf(buf, sizeof(buf), "[%0x]", pw_type); return (buf); From 257799cdb69707f7bea43b118c9787458d1d81ba Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 13/18] ldpd: implement RFC 5919 (LDP End-of-LIB) Signed-off-by: Renato Westphal --- ldpd/init.c | 67 ++++++++++++++++++++++++++++++++++++++++- ldpd/labelmapping.c | 72 ++++++++++++++++++++++++++------------------- ldpd/lde.c | 40 +++++++++++++++++++++++++ ldpd/lde.h | 3 ++ ldpd/ldp.h | 8 +++++ ldpd/ldpe.h | 2 ++ ldpd/log.c | 2 ++ ldpd/neighbor.c | 1 + ldpd/notification.c | 40 +++++++++++++++++-------- 9 files changed, 192 insertions(+), 43 deletions(-) diff --git a/ldpd/init.c b/ldpd/init.c index 13104b4ee6..bc3a69edc7 100644 --- a/ldpd/init.c +++ b/ldpd/init.c @@ -26,6 +26,7 @@ static int gen_init_prms_tlv(struct ibuf *, struct nbr *); static int gen_cap_dynamic_tlv(struct ibuf *); static int gen_cap_twcard_tlv(struct ibuf *, int); +static int gen_cap_unotif_tlv(struct ibuf *, int); void send_init(struct nbr *nbr) @@ -37,7 +38,7 @@ send_init(struct nbr *nbr) debug_msg_send("initialization: lsr-id %s", inet_ntoa(nbr->id)); size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE + - CAP_TLV_DYNAMIC_SIZE + CAP_TLV_TWCARD_SIZE; + CAP_TLV_DYNAMIC_SIZE + CAP_TLV_TWCARD_SIZE + CAP_TLV_UNOTIF_SIZE; if ((buf = ibuf_open(size)) == NULL) fatal(__func__); @@ -47,6 +48,7 @@ send_init(struct nbr *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) { ibuf_free(buf); return; @@ -167,6 +169,26 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len) log_debug("%s: lsr-id %s announced the Typed Wildcard " "FEC capability", __func__, inet_ntoa(nbr->id)); break; + case TLV_TYPE_UNOTIF_CAP: + if (tlv_len != CAP_TLV_UNOTIF_LEN) { + session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, + msg.type); + return (-1); + } + + if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) { + session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, + msg.type); + return (-1); + } + caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF; + + nbr->flags |= F_NBR_CAP_UNOTIF; + + log_debug("%s: lsr-id %s announced the Unrecognized " + "Notification capability", __func__, + inet_ntoa(nbr->id)); + break; default: if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) send_notification_rtlvs(nbr, S_UNSSUPORTDCAP, @@ -217,6 +239,9 @@ send_capability(struct nbr *nbr, uint16_t capability, int enable) 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: @@ -299,6 +324,32 @@ recv_capability(struct nbr *nbr, char *buf, uint16_t len) "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: @@ -371,3 +422,17 @@ gen_cap_twcard_tlv(struct ibuf *buf, int enable) return (ibuf_add(buf, &cap, CAP_TLV_TWCARD_SIZE)); } + +static int +gen_cap_unotif_tlv(struct ibuf *buf, int enable) +{ + struct capability_tlv cap; + + memset(&cap, 0, sizeof(cap)); + cap.type = htons(TLV_TYPE_UNOTIF_CAP); + cap.length = htons(CAP_TLV_UNOTIF_LEN); + if (enable) + cap.reserved = STATE_BIT; + + return (ibuf_add(buf, &cap, CAP_TLV_UNOTIF_SIZE)); +} diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c index 55b890ac70..75acfd7d50 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -72,36 +72,8 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh) } /* calculate size */ - msg_size = LDP_MSG_SIZE + TLV_HDR_SIZE; - switch (me->map.type) { - case MAP_TYPE_WILDCARD: - msg_size += FEC_ELM_WCARD_LEN; - break; - case MAP_TYPE_PREFIX: - msg_size += FEC_ELM_PREFIX_MIN_LEN + - PREFIX_SIZE(me->map.fec.prefix.prefixlen); - break; - case MAP_TYPE_PWID: - msg_size += FEC_PWID_ELM_MIN_LEN; - if (me->map.flags & F_MAP_PW_ID) - msg_size += PW_STATUS_TLV_LEN; - if (me->map.flags & F_MAP_PW_IFMTU) - msg_size += FEC_SUBTLV_IFMTU_SIZE; - if (me->map.flags & F_MAP_PW_STATUS) - msg_size += PW_STATUS_TLV_SIZE; - break; - case MAP_TYPE_TYPED_WCARD: - msg_size += FEC_ELM_TWCARD_MIN_LEN; - switch (me->map.fec.twcard.type) { - case MAP_TYPE_PREFIX: - case MAP_TYPE_PWID: - msg_size += sizeof(uint16_t); - break; - default: - fatalx("send_labelmessage: unexpected fec type"); - } - break; - } + msg_size = LDP_MSG_SIZE; + msg_size += len_fec_tlv(&me->map); if (me->map.label != NO_LABEL) msg_size += LABEL_TLV_SIZE; if (me->map.flags & F_MAP_REQ_ID) @@ -548,6 +520,46 @@ gen_pw_status_tlv(struct ibuf *buf, uint32_t status) return (ibuf_add(buf, &st, sizeof(st))); } +uint16_t +len_fec_tlv(struct map *map) +{ + uint16_t len = TLV_HDR_SIZE; + + switch (map->type) { + case MAP_TYPE_WILDCARD: + len += FEC_ELM_WCARD_LEN; + break; + case MAP_TYPE_PREFIX: + len += FEC_ELM_PREFIX_MIN_LEN + + PREFIX_SIZE(map->fec.prefix.prefixlen); + break; + case MAP_TYPE_PWID: + len += FEC_PWID_ELM_MIN_LEN; + if (map->flags & F_MAP_PW_ID) + len += PW_STATUS_TLV_LEN; + if (map->flags & F_MAP_PW_IFMTU) + len += FEC_SUBTLV_IFMTU_SIZE; + if (map->flags & F_MAP_PW_STATUS) + len += PW_STATUS_TLV_SIZE; + break; + case MAP_TYPE_TYPED_WCARD: + len += FEC_ELM_TWCARD_MIN_LEN; + switch (map->fec.twcard.type) { + case MAP_TYPE_PREFIX: + case MAP_TYPE_PWID: + len += sizeof(uint16_t); + break; + default: + fatalx("len_fec_tlv: unexpected fec type"); + } + break; + default: + fatalx("len_fec_tlv: unexpected fec type"); + } + + return (len); +} + int gen_fec_tlv(struct ibuf *buf, struct map *map) { diff --git a/ldpd/lde.c b/ldpd/lde.c index 2392dbf6d0..e64f18dfc9 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -319,6 +319,13 @@ lde_dispatch_imsg(struct thread *thread) case S_PW_STATUS: l2vpn_recv_pw_status(ln, &nm); break; + case S_ENDOFLIB: + /* + * Do nothing for now. Should be useful in + * the future when we implement LDP-IGP + * Synchronization (RFC 5443) and Graceful + * Restart (RFC 3478). + */ default: break; } @@ -1099,6 +1106,38 @@ lde_send_notification(struct lde_nbr *ln, uint32_t status_code, uint32_t msg_id, &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)); +} + static __inline int lde_nbr_compare(struct lde_nbr *a, struct lde_nbr *b) { @@ -1116,6 +1155,7 @@ lde_nbr_new(uint32_t peerid, struct lde_nbr *new) ln->id = new->id; ln->v4_enabled = new->v4_enabled; ln->v6_enabled = new->v6_enabled; + ln->flags = new->flags; ln->peerid = peerid; fec_init(&ln->recv_map); fec_init(&ln->sent_map); diff --git a/ldpd/lde.h b/ldpd/lde.h index b3af1bbaa4..a2b51dad32 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -90,6 +90,7 @@ struct lde_nbr { struct in_addr id; int v4_enabled; /* announce/process v4 msgs */ int v6_enabled; /* announce/process v6 msgs */ + int flags; /* capabilities */ struct fec_tree recv_req; struct fec_tree sent_req; struct fec_tree recv_map; @@ -155,6 +156,8 @@ void lde_send_labelrelease(struct lde_nbr *, struct fec_node *, struct map *, uint32_t); void lde_send_notification(struct lde_nbr *, uint32_t, uint32_t, uint16_t); +void lde_send_notification_eol_prefix(struct lde_nbr *, int); +void lde_send_notification_eol_pwid(struct lde_nbr *, uint16_t); struct lde_nbr *lde_nbr_find_by_lsrid(struct in_addr); struct lde_nbr *lde_nbr_find_by_addr(int, union ldpd_addr *); struct lde_map *lde_map_add(struct lde_nbr *, struct fec_node *, int); diff --git a/ldpd/ldp.h b/ldpd/ldp.h index ffdadf8be9..0a42ab4076 100644 --- a/ldpd/ldp.h +++ b/ldpd/ldp.h @@ -101,6 +101,8 @@ #define TLV_TYPE_DYNAMIC_CAP 0x8506 /* RFC 5918 */ #define TLV_TYPE_TWCARD_CAP 0x850B +/* RFC 5919 */ +#define TLV_TYPE_UNOTIF_CAP 0x8603 /* RFC 7552 */ #define TLV_TYPE_DUALSTACK 0x8701 @@ -204,6 +206,8 @@ struct hello_prms_opt16_tlv { #define S_WITHDRAW_MTHD 0x0000002B /* RFC 5561 */ #define S_UNSSUPORTDCAP 0x0000002E +/* RFC 5919 */ +#define S_ENDOFLIB 0x0000002F /* RFC 7552 */ #define S_TRANS_MISMTCH 0x80000032 #define S_DS_NONCMPLNCE 0x80000033 @@ -244,6 +248,7 @@ struct capability_tlv { #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 @@ -251,6 +256,9 @@ struct capability_tlv { #define CAP_TLV_TWCARD_SIZE 5 #define CAP_TLV_TWCARD_LEN 1 +#define CAP_TLV_UNOTIF_SIZE 5 +#define CAP_TLV_UNOTIF_LEN 1 + #define AF_IPV4 0x1 #define AF_IPV6 0x2 diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index 24512989de..2bd0568d68 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -113,6 +113,7 @@ struct nbr { #define F_NBR_GTSM_NEGOTIATED 0x01 #define F_NBR_CAP_DYNAMIC 0x02 #define F_NBR_CAP_TWCARD 0x04 +#define F_NBR_CAP_UNOTIF 0x08 RB_HEAD(nbr_id_head, nbr); RB_PROTOTYPE(nbr_id_head, nbr, id_tree, nbr_id_compare) @@ -186,6 +187,7 @@ int recv_address(struct nbr *, char *, uint16_t); void send_labelmessage(struct nbr *, uint16_t, struct mapping_head *); int recv_labelmessage(struct nbr *, char *, uint16_t, uint16_t); int gen_pw_status_tlv(struct ibuf *, uint32_t); +uint16_t len_fec_tlv(struct map *); int gen_fec_tlv(struct ibuf *, struct map *); int tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *, uint16_t, struct map *); diff --git a/ldpd/log.c b/ldpd/log.c index 5ad8ca0caf..b30604db0d 100644 --- a/ldpd/log.c +++ b/ldpd/log.c @@ -584,6 +584,8 @@ status_code_name(uint32_t status) return ("Label Withdraw PW Status Method"); case S_UNSSUPORTDCAP: return ("Unsupported Capability"); + case S_ENDOFLIB: + return ("End-of-LIB"); case S_TRANS_MISMTCH: return ("Transport Connection Mismatch"); case S_DS_NONCMPLNCE: diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c index d24ceb1229..077d472850 100644 --- a/ldpd/neighbor.c +++ b/ldpd/neighbor.c @@ -744,6 +744,7 @@ nbr_act_session_operational(struct nbr *nbr) lde_nbr.id = nbr->id; lde_nbr.v4_enabled = nbr->v4_enabled; lde_nbr.v6_enabled = nbr->v6_enabled; + lde_nbr.flags = nbr->flags; return (ldpe_imsg_compose_lde(IMSG_NEIGHBOR_UP, nbr->peerid, 0, &lde_nbr, sizeof(lde_nbr))); } diff --git a/ldpd/notification.c b/ldpd/notification.c index 69d4ab8028..393994ed5f 100644 --- a/ldpd/notification.c +++ b/ldpd/notification.c @@ -38,16 +38,8 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm) size = LDP_HDR_SIZE + LDP_MSG_SIZE + STATUS_SIZE; if (nm->flags & F_NOTIF_PW_STATUS) size += PW_STATUS_TLV_SIZE; - if (nm->flags & F_NOTIF_FEC) { - size += TLV_HDR_SIZE; - switch (nm->fec.type) { - case MAP_TYPE_PWID: - size += FEC_PWID_ELM_MIN_LEN; - if (nm->fec.flags & F_MAP_PW_ID) - size += sizeof(uint32_t); - break; - } - } + if (nm->flags & F_NOTIF_FEC) + size += len_fec_tlv(&nm->fec); if (nm->flags & F_NOTIF_RETURNED_TLVS) size += TLV_HDR_SIZE * 2 + nm->rtlvs.length; @@ -204,7 +196,9 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) len -= tlv_len; } - if (nm.status_code == S_PW_STATUS) { + /* sanity checks */ + switch (nm.status_code) { + case S_PW_STATUS: if (!(nm.flags & (F_NOTIF_PW_STATUS|F_NOTIF_FEC))) { send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type); @@ -219,6 +213,21 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) msg.id, msg.type); return (-1); } + break; + case S_ENDOFLIB: + if (!(nm.flags & F_NOTIF_FEC)) { + send_notification(nbr->tcp, S_MISS_MSG, + msg.id, msg.type); + return (-1); + } + if (nm.fec.type != MAP_TYPE_TYPED_WCARD) { + send_notification(nbr->tcp, S_BAD_TLV_VAL, + msg.id, msg.type); + return (-1); + } + break; + default: + break; } log_msg_notification(0, nbr, &nm); @@ -231,9 +240,16 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) return (-1); } - if (nm.status_code == S_PW_STATUS) + /* lde needs to know about a few notification messages */ + switch (nm.status_code) { + case S_PW_STATUS: + case S_ENDOFLIB: ldpe_imsg_compose_lde(IMSG_NOTIFICATION, nbr->peerid, 0, &nm, sizeof(nm)); + break; + default: + break; + } return (0); } From fd1cf443e92a7dc5b9ed7efe11223af7f22f2437 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 14/18] ldpd: fix parsing of optional tlvs in address messages We were aborting the session upon receipt of MAC Address Withdrawal messages. Now make the parser aware that optional TLVs are possible in address messages. Signed-off-by: Renato Westphal --- ldpd/address.c | 73 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 14 deletions(-) diff --git a/ldpd/address.c b/ldpd/address.c index 25c03b811b..f4fc21311a 100644 --- a/ldpd/address.c +++ b/ldpd/address.c @@ -142,11 +142,24 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len) { struct ldp_msg msg; uint16_t msg_type; - struct address_list_tlv alt; enum imsg_type type; + struct address_list_tlv alt; + uint16_t alt_len; + uint16_t alt_family; struct lde_addr lde_addr; memcpy(&msg, buf, sizeof(msg)); + msg_type = ntohs(msg.type); + switch (msg_type) { + case MSG_TYPE_ADDR: + type = IMSG_ADDRESS_ADD; + break; + case MSG_TYPE_ADDRWITHDRAW: + type = IMSG_ADDRESS_DEL; + break; + default: + fatalx("recv_address: unexpected msg type"); + } buf += LDP_MSG_SIZE; len -= LDP_MSG_SIZE; @@ -155,9 +168,10 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len) session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type); return (-1); } - memcpy(&alt, buf, sizeof(alt)); - if (ntohs(alt.length) != len - TLV_HDR_SIZE) { + alt_len = ntohs(alt.length); + alt_family = ntohs(alt.family); + if (alt_len > len - TLV_HDR_SIZE) { session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); return (-1); } @@ -165,7 +179,7 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len) send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type); return (-1); } - switch (ntohs(alt.family)) { + switch (alt_family) { case AF_IPV4: if (!nbr->v4_enabled) /* just ignore the message */ @@ -180,19 +194,15 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len) send_notification(nbr->tcp, S_UNSUP_ADDR, msg.id, msg.type); return (-1); } + alt_len -= sizeof(alt.family); buf += sizeof(alt); len -= sizeof(alt); - msg_type = ntohs(msg.type); - if (msg_type == MSG_TYPE_ADDR) - type = IMSG_ADDRESS_ADD; - else - type = IMSG_ADDRESS_DEL; - - while (len > 0) { - switch (ntohs(alt.family)) { + /* Process all received addresses */ + while (alt_len > 0) { + switch (alt_family) { case AF_IPV4: - if (len < sizeof(struct in_addr)) { + if (alt_len < sizeof(struct in_addr)) { session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); return (-1); @@ -204,9 +214,10 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len) buf += sizeof(struct in_addr); len -= sizeof(struct in_addr); + alt_len -= sizeof(struct in_addr); break; case AF_IPV6: - if (len < sizeof(struct in6_addr)) { + if (alt_len < sizeof(struct in6_addr)) { session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); return (-1); @@ -218,6 +229,7 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len) buf += sizeof(struct in6_addr); len -= sizeof(struct in6_addr); + alt_len -= sizeof(struct in6_addr); break; default: fatalx("recv_address: unknown af"); @@ -229,6 +241,39 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len) 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); } From 26519d8c02d9b88631fc8322c35c638bcbc8c2e2 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 15/18] ldpd: send VPLS MAC withdrawals RFC 4762 says that MAC address withdrawal messages can be used to improve convergence time in VPLS networks. This patch makes ldpd send MAC withdrawals whenever a non-pseudowire interface pertaining to a VPLS goes down. The processing of received MAC withdrawals will be implemented later. Signed-off-by: Renato Westphal --- ldpd/address.c | 79 +++++++++++++++++++++++++++++++++++++++++++----- ldpd/l2vpn.c | 27 +++++++++++++++++ ldpd/lde.h | 1 + ldpd/ldp.h | 1 + ldpd/ldp_zebra.c | 2 ++ ldpd/ldpd.h | 3 ++ ldpd/ldpe.c | 21 ++++++++++--- ldpd/ldpe.h | 1 + 8 files changed, 123 insertions(+), 12 deletions(-) diff --git a/ldpd/address.c b/ldpd/address.c index f4fc21311a..ad23ca690b 100644 --- a/ldpd/address.c +++ b/ldpd/address.c @@ -26,12 +26,14 @@ static void send_address(struct nbr *, int, struct if_addr_head *, unsigned int, int); -static int gen_address_list_tlv(struct ibuf *, uint16_t, int, - struct if_addr_head *, unsigned int); +static int gen_address_list_tlv(struct ibuf *, int, struct if_addr_head *, + unsigned int); +static int gen_mac_list_tlv(struct ibuf *, uint8_t *); static void address_list_add(struct if_addr_head *, struct if_addr *); static void address_list_clr(struct if_addr_head *); static void log_msg_address(int, uint16_t, struct nbr *, int, union ldpd_addr *); +static void log_msg_mac_withdrawal(int, struct nbr *, uint8_t *); static void send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list, @@ -85,8 +87,7 @@ send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list, size -= LDP_HDR_SIZE; err |= gen_msg_hdr(buf, msg_type, size); size -= LDP_MSG_SIZE; - err |= gen_address_list_tlv(buf, size, af, addr_list, - tlv_addr_count); + err |= gen_address_list_tlv(buf, af, addr_list, tlv_addr_count); if (err) { address_list_clr(addr_list); ibuf_free(buf); @@ -137,6 +138,40 @@ send_address_all(struct nbr *nbr, int af) send_address(nbr, af, &addr_list, addr_count, 0); } +void +send_mac_withdrawal(struct nbr *nbr, struct map *fec, uint8_t *mac) +{ + struct ibuf *buf; + uint16_t size; + int err; + + size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE + len_fec_tlv(fec) + + TLV_HDR_SIZE; + if (mac) + size += ETHER_ADDR_LEN; + + if ((buf = ibuf_open(size)) == NULL) + fatal(__func__); + + err = gen_ldp_hdr(buf, size); + size -= LDP_HDR_SIZE; + err |= gen_msg_hdr(buf, MSG_TYPE_ADDRWITHDRAW, size); + size -= LDP_MSG_SIZE; + err |= gen_address_list_tlv(buf, AF_INET, NULL, 0); + err |= gen_fec_tlv(buf, fec); + err |= gen_mac_list_tlv(buf, mac); + if (err) { + ibuf_free(buf); + return; + } + + log_msg_mac_withdrawal(1, nbr, mac); + + evbuf_enqueue(&nbr->tcp->wbuf, buf); + + nbr_fsm(nbr, NBR_EVT_PDU_SENT); +} + int recv_address(struct nbr *nbr, char *buf, uint16_t len) { @@ -278,8 +313,8 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len) } static int -gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af, - struct if_addr_head *addr_list, unsigned int tlv_addr_count) +gen_address_list_tlv(struct ibuf *buf, int af, struct if_addr_head *addr_list, + unsigned int tlv_addr_count) { struct address_list_tlv alt; uint16_t addr_size; @@ -288,7 +323,6 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af, memset(&alt, 0, sizeof(alt)); alt.type = htons(TLV_TYPE_ADDRLIST); - alt.length = htons(size - TLV_HDR_SIZE); switch (af) { case AF_INET: @@ -302,8 +336,12 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af, default: fatalx("gen_address_list_tlv: unknown af"); } + alt.length = htons(sizeof(alt.family) + addr_size * tlv_addr_count); err |= ibuf_add(buf, &alt, sizeof(alt)); + if (addr_list == NULL) + return (err); + LIST_FOREACH(if_addr, addr_list, entry) { err |= ibuf_add(buf, &if_addr->addr, addr_size); if (--tlv_addr_count == 0) @@ -313,6 +351,23 @@ gen_address_list_tlv(struct ibuf *buf, uint16_t size, int af, return (err); } +static int +gen_mac_list_tlv(struct ibuf *buf, uint8_t *mac) +{ + struct tlv tlv; + int err; + + memset(&tlv, 0, sizeof(tlv)); + tlv.type = htons(TLV_TYPE_MAC_LIST); + if (mac) + tlv.length = htons(ETHER_ADDR_LEN); + err = ibuf_add(buf, &tlv, sizeof(tlv)); + if (mac) + err |= ibuf_add(buf, mac, ETHER_ADDR_LEN); + + return (err); +} + static void address_list_add(struct if_addr_head *addr_list, struct if_addr *if_addr) { @@ -344,3 +399,13 @@ log_msg_address(int out, uint16_t msg_type, struct nbr *nbr, int af, debug_msg(out, "%s: lsr-id %s, address %s", msg_name(msg_type), inet_ntoa(nbr->id), log_addr(af, addr)); } + +static void +log_msg_mac_withdrawal(int out, struct nbr *nbr, uint8_t *mac) +{ + char buf[ETHER_ADDR_STRLEN]; + + debug_msg(out, "mac withdrawal: lsr-id %s, mac %s", inet_ntoa(nbr->id), + (mac) ? prefix_mac2str((struct ethaddr *)mac, buf, sizeof(buf)) : + "wildcard"); +} diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c index 8e17ccb258..3f4e21e685 100644 --- a/ldpd/l2vpn.c +++ b/ldpd/l2vpn.c @@ -152,6 +152,33 @@ l2vpn_if_find_name(struct l2vpn *l2vpn, const char *ifname) return (RB_FIND(l2vpn_if_head, &l2vpn->if_tree, &lif)); } +void +l2vpn_if_update(struct l2vpn_if *lif) +{ + struct l2vpn *l2vpn = lif->l2vpn; + struct l2vpn_pw *pw; + struct map fec; + struct nbr *nbr; + + if ((lif->flags & IFF_UP) && (lif->flags & IFF_RUNNING)) + return; + + RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) { + nbr = nbr_find_ldpid(pw->lsr_id.s_addr); + if (nbr == NULL) + continue; + + memset(&fec, 0, sizeof(fec)); + fec.type = MAP_TYPE_PWID; + fec.fec.pwid.type = l2vpn->pw_type; + fec.fec.pwid.group_id = 0; + fec.flags |= F_MAP_PW_ID; + fec.fec.pwid.pwid = pw->pwid; + + send_mac_withdrawal(nbr, &fec, lif->mac); + } +} + static __inline int l2vpn_pw_compare(struct l2vpn_pw *a, struct l2vpn_pw *b) { diff --git a/ldpd/lde.h b/ldpd/lde.h index a2b51dad32..b5bcb42c8b 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -208,6 +208,7 @@ void l2vpn_exit(struct l2vpn *); struct l2vpn_if *l2vpn_if_new(struct l2vpn *, struct kif *); struct l2vpn_if *l2vpn_if_find(struct l2vpn *, unsigned int); struct l2vpn_if *l2vpn_if_find_name(struct l2vpn *, const char *); +void l2vpn_if_update(struct l2vpn_if *); struct l2vpn_pw *l2vpn_pw_new(struct l2vpn *, struct kif *); struct l2vpn_pw *l2vpn_pw_find(struct l2vpn *, unsigned int); struct l2vpn_pw *l2vpn_pw_find_name(struct l2vpn *, const char *); diff --git a/ldpd/ldp.h b/ldpd/ldp.h index 0a42ab4076..c2b64d20c6 100644 --- a/ldpd/ldp.h +++ b/ldpd/ldp.h @@ -93,6 +93,7 @@ #define TLV_TYPE_FRSESSION 0x0502 #define TLV_TYPE_LABELREQUEST 0x0600 /* RFC 4447 */ +#define TLV_TYPE_MAC_LIST 0x8404 #define TLV_TYPE_PW_STATUS 0x896A #define TLV_TYPE_PW_IF_PARAM 0x096B #define TLV_TYPE_PW_GROUP_ID 0x096C diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index 12954b91af..c41a0dbd91 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -65,6 +65,8 @@ ifp2kif(struct interface *ifp, struct kif *kif) strlcpy(kif->ifname, ifp->name, sizeof(kif->ifname)); kif->ifindex = ifp->ifindex; kif->flags = ifp->flags; + if (ifp->ll_type == ZEBRA_LLT_ETHER) + memcpy(kif->mac, ifp->hw_addr, ETHER_ADDR_LEN); } static void diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 7d12c66cee..0a7e1177bc 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -27,6 +27,7 @@ #include "imsg.h" #include "thread.h" #include "qobj.h" +#include "prefix.h" #include "filter.h" #include "ldp.h" @@ -350,6 +351,7 @@ struct l2vpn_if { char ifname[IF_NAMESIZE]; unsigned int ifindex; uint16_t flags; + uint8_t mac[ETHER_ADDR_LEN]; QOBJ_FIELDS }; RB_HEAD(l2vpn_if_head, l2vpn_if); @@ -519,6 +521,7 @@ struct kif { char ifname[IF_NAMESIZE]; unsigned short ifindex; int flags; + uint8_t mac[ETHER_ADDR_LEN]; int mtu; }; diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index bea26a6610..93454cf27e 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -251,8 +251,8 @@ ldpe_dispatch_main(struct thread *thread) struct iface *niface; struct tnbr *ntnbr; struct nbr_params *nnbrp; - static struct l2vpn *nl2vpn; - struct l2vpn_if *nlif; + static struct l2vpn *l2vpn, *nl2vpn; + struct l2vpn_if *lif = NULL, *nlif; struct l2vpn_pw *npw; struct imsg imsg; int fd = THREAD_FD(thread); @@ -292,11 +292,22 @@ ldpe_dispatch_main(struct thread *thread) kif = imsg.data; iface = if_lookup_name(leconf, kif->ifname); - if (!iface) + if (iface) { + if_update_info(iface, kif); + if_update(iface, AF_UNSPEC); break; + } - if_update_info(iface, kif); - if_update(iface, AF_UNSPEC); + RB_FOREACH(l2vpn, l2vpn_head, &leconf->l2vpn_tree) { + lif = l2vpn_if_find_name(l2vpn, kif->ifname); + if (lif) { + lif->flags = kif->flags; + memcpy(lif->mac, kif->mac, + sizeof(lif->mac)); + l2vpn_if_update(lif); + break; + } + } break; case IMSG_NEWADDR: if (imsg.hdr.len != IMSG_HEADER_SIZE + diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index 2bd0568d68..22b75eb008 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -180,6 +180,7 @@ int gen_status_tlv(struct ibuf *, uint32_t, uint32_t, uint16_t); /* address.c */ void send_address_single(struct nbr *, struct if_addr *, int); void send_address_all(struct nbr *, int); +void send_mac_withdrawal(struct nbr *, struct map *, uint8_t *); int recv_address(struct nbr *, char *, uint16_t); /* labelmapping.c */ From 236c69359ec99e3683c1e0d92fd0262e1d350b95 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 16/18] ldpd: remove unnecessary memcpy's Signed-off-by: Renato Westphal --- ldpd/lde.c | 69 ++++++++++++++++++++++++++++------------------------- ldpd/ldpe.c | 26 ++++++++++---------- 2 files changed, 51 insertions(+), 44 deletions(-) diff --git a/ldpd/lde.c b/ldpd/lde.c index e64f18dfc9..08339c720a 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -205,9 +205,9 @@ lde_dispatch_imsg(struct thread *thread) struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; struct lde_nbr *ln; - struct map map; - struct lde_addr lde_addr; - struct notify_msg nm; + struct map *map; + struct lde_addr *lde_addr; + struct notify_msg *nm; ssize_t n; int shut = 0; @@ -240,9 +240,10 @@ lde_dispatch_imsg(struct thread *thread) case IMSG_LABEL_RELEASE: case IMSG_LABEL_WITHDRAW: case IMSG_LABEL_ABORT: - if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(map)) + if (imsg.hdr.len - IMSG_HEADER_SIZE != + sizeof(struct map)) fatalx("lde_dispatch_imsg: wrong imsg len"); - memcpy(&map, imsg.data, sizeof(map)); + map = imsg.data; ln = lde_nbr_find(imsg.hdr.peerid); if (ln == NULL) { @@ -253,16 +254,16 @@ lde_dispatch_imsg(struct thread *thread) switch (imsg.hdr.type) { case IMSG_LABEL_MAPPING: - lde_check_mapping(&map, ln); + lde_check_mapping(map, ln); break; case IMSG_LABEL_REQUEST: - lde_check_request(&map, ln); + lde_check_request(map, ln); break; case IMSG_LABEL_RELEASE: - lde_check_release(&map, ln); + lde_check_release(map, ln); break; case IMSG_LABEL_WITHDRAW: - lde_check_withdraw(&map, ln); + lde_check_withdraw(map, ln); break; case IMSG_LABEL_ABORT: /* not necessary */ @@ -270,9 +271,10 @@ lde_dispatch_imsg(struct thread *thread) } break; case IMSG_ADDRESS_ADD: - if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lde_addr)) + if (imsg.hdr.len - IMSG_HEADER_SIZE != + sizeof(struct lde_addr)) fatalx("lde_dispatch_imsg: wrong imsg len"); - memcpy(&lde_addr, imsg.data, sizeof(lde_addr)); + lde_addr = imsg.data; ln = lde_nbr_find(imsg.hdr.peerid); if (ln == NULL) { @@ -280,16 +282,17 @@ lde_dispatch_imsg(struct thread *thread) __func__); break; } - if (lde_address_add(ln, &lde_addr) < 0) { + if (lde_address_add(ln, lde_addr) < 0) { log_debug("%s: cannot add address %s, it " "already exists", __func__, - log_addr(lde_addr.af, &lde_addr.addr)); + log_addr(lde_addr->af, &lde_addr->addr)); } break; case IMSG_ADDRESS_DEL: - if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lde_addr)) + if (imsg.hdr.len - IMSG_HEADER_SIZE != + sizeof(struct lde_addr)) fatalx("lde_dispatch_imsg: wrong imsg len"); - memcpy(&lde_addr, imsg.data, sizeof(lde_addr)); + lde_addr = imsg.data; ln = lde_nbr_find(imsg.hdr.peerid); if (ln == NULL) { @@ -297,16 +300,17 @@ lde_dispatch_imsg(struct thread *thread) __func__); break; } - if (lde_address_del(ln, &lde_addr) < 0) { + if (lde_address_del(ln, lde_addr) < 0) { log_debug("%s: cannot delete address %s, it " "does not exist", __func__, - log_addr(lde_addr.af, &lde_addr.addr)); + log_addr(lde_addr->af, &lde_addr->addr)); } break; case IMSG_NOTIFICATION: - if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(nm)) + if (imsg.hdr.len - IMSG_HEADER_SIZE != + sizeof(struct notify_msg)) fatalx("lde_dispatch_imsg: wrong imsg len"); - memcpy(&nm, imsg.data, sizeof(nm)); + nm = imsg.data; ln = lde_nbr_find(imsg.hdr.peerid); if (ln == NULL) { @@ -315,9 +319,9 @@ lde_dispatch_imsg(struct thread *thread) break; } - switch (nm.status_code) { + switch (nm->status_code) { case S_PW_STATUS: - l2vpn_recv_pw_status(ln, &nm); + l2vpn_recv_pw_status(ln, nm); break; case S_ENDOFLIB: /* @@ -392,7 +396,7 @@ lde_dispatch_parent(struct thread *thread) struct l2vpn_if *nlif; struct l2vpn_pw *npw; struct imsg imsg; - struct kroute kr; + struct kroute *kr; int fd = THREAD_FD(thread); struct imsgev *iev = THREAD_ARG(thread); struct imsgbuf *ibuf = &iev->ibuf; @@ -416,22 +420,23 @@ lde_dispatch_parent(struct thread *thread) switch (imsg.hdr.type) { case IMSG_NETWORK_ADD: case IMSG_NETWORK_UPDATE: - if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(kr)) { + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(struct kroute)) { log_warnx("%s: wrong imsg len", __func__); break; } - memcpy(&kr, imsg.data, sizeof(kr)); + kr = imsg.data; - switch (kr.af) { + switch (kr->af) { case AF_INET: fec.type = FEC_TYPE_IPV4; - fec.u.ipv4.prefix = kr.prefix.v4; - fec.u.ipv4.prefixlen = kr.prefixlen; + fec.u.ipv4.prefix = kr->prefix.v4; + fec.u.ipv4.prefixlen = kr->prefixlen; break; case AF_INET6: fec.type = FEC_TYPE_IPV6; - fec.u.ipv6.prefix = kr.prefix.v6; - fec.u.ipv6.prefixlen = kr.prefixlen; + fec.u.ipv6.prefix = kr->prefix.v6; + fec.u.ipv6.prefixlen = kr->prefixlen; break; default: fatalx("lde_dispatch_parent: unknown af"); @@ -439,9 +444,9 @@ lde_dispatch_parent(struct thread *thread) switch (imsg.hdr.type) { case IMSG_NETWORK_ADD: - lde_kernel_insert(&fec, kr.af, &kr.nexthop, - kr.ifindex, kr.priority, - kr.flags & F_CONNECTED, NULL); + lde_kernel_insert(&fec, kr->af, &kr->nexthop, + kr->ifindex, kr->priority, + kr->flags & F_CONNECTED, NULL); break; case IMSG_NETWORK_UPDATE: lde_kernel_update(&fec); diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 93454cf27e..3bb84e92a9 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -540,10 +540,10 @@ ldpe_dispatch_lde(struct thread *thread) struct imsgev *iev = THREAD_ARG(thread); struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; - struct map map; - struct notify_msg nm; + struct map *map; + struct notify_msg *nm; + struct nbr *nbr; int n, shut = 0; - struct nbr *nbr = NULL; iev->ev_read = NULL; @@ -563,9 +563,10 @@ ldpe_dispatch_lde(struct thread *thread) case IMSG_RELEASE_ADD: case IMSG_REQUEST_ADD: case IMSG_WITHDRAW_ADD: - if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(map)) + if (imsg.hdr.len - IMSG_HEADER_SIZE != + sizeof(struct map)) fatalx("invalid size of map request"); - memcpy(&map, imsg.data, sizeof(map)); + map = imsg.data; nbr = nbr_find_peerid(imsg.hdr.peerid); if (nbr == NULL) { @@ -578,16 +579,16 @@ ldpe_dispatch_lde(struct thread *thread) switch (imsg.hdr.type) { case IMSG_MAPPING_ADD: - mapping_list_add(&nbr->mapping_list, &map); + mapping_list_add(&nbr->mapping_list, map); break; case IMSG_RELEASE_ADD: - mapping_list_add(&nbr->release_list, &map); + mapping_list_add(&nbr->release_list, map); break; case IMSG_REQUEST_ADD: - mapping_list_add(&nbr->request_list, &map); + mapping_list_add(&nbr->request_list, map); break; case IMSG_WITHDRAW_ADD: - mapping_list_add(&nbr->withdraw_list, &map); + mapping_list_add(&nbr->withdraw_list, map); break; } break; @@ -624,9 +625,10 @@ ldpe_dispatch_lde(struct thread *thread) } break; case IMSG_NOTIFICATION_SEND: - if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(nm)) + if (imsg.hdr.len - IMSG_HEADER_SIZE != + sizeof(struct notify_msg)) fatalx("invalid size of OE request"); - memcpy(&nm, imsg.data, sizeof(nm)); + nm = imsg.data; nbr = nbr_find_peerid(imsg.hdr.peerid); if (nbr == NULL) { @@ -637,7 +639,7 @@ ldpe_dispatch_lde(struct thread *thread) if (nbr->state != NBR_STA_OPER) break; - send_notification_full(nbr->tcp, &nm); + send_notification_full(nbr->tcp, nm); break; case IMSG_CTL_END: case IMSG_CTL_SHOW_LIB: From 235b275392e0c29067301a2d8e04aecb625f339b Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 17/18] ldpd: always check if the received labels are valid We were doing some sanity checks only for labels of Label Mapping messages. Now do the same checks for labels of Label Release and Label Withdraw messages as well. While here, plug a small memleak in the error path of recv_labelmessage(). Signed-off-by: Renato Westphal --- ldpd/labelmapping.c | 88 ++++++++++++++------------------------------- 1 file changed, 27 insertions(+), 61 deletions(-) diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c index 75acfd7d50..e8ce7fbdf5 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -28,8 +28,6 @@ static void enqueue_pdu(struct nbr *, struct ibuf *, uint16_t); static int gen_label_tlv(struct ibuf *, uint32_t); -static int tlv_decode_label(struct nbr *, struct ldp_msg *, char *, - uint16_t, uint32_t *); static int gen_reqid_tlv(struct ibuf *, uint32_t); static void log_msg_mapping(int, uint16_t, struct nbr *, struct map *); @@ -128,7 +126,8 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) uint32_t label = NO_LABEL, reqid = 0; uint32_t pw_status = 0; uint8_t flags = 0; - int feclen, lbllen, tlen; + int feclen, tlen; + uint16_t current_tlv = 1; struct mapping_entry *me; struct mapping_head mh; struct map map; @@ -171,7 +170,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) type != MSG_TYPE_LABELRELEASE) { send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type); - return (-1); + goto err; } /* @@ -226,16 +225,6 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) feclen -= tlen; } while (feclen > 0); - /* Mandatory Label TLV */ - if (type == MSG_TYPE_LABELMAPPING) { - lbllen = tlv_decode_label(nbr, &msg, buf, len, &label); - if (lbllen == -1) - goto err; - - buf += lbllen; - len -= lbllen; - } - /* Optional Parameters */ while (len > 0) { struct tlv tlv; @@ -258,6 +247,17 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) buf += TLV_HDR_SIZE; len -= TLV_HDR_SIZE; + /* + * For Label Mapping messages the Label TLV is mandatory and + * should appear right after the FEC TLV. + */ + if (current_tlv == 1 && type == MSG_TYPE_LABELMAPPING && + !(tlv_type & TLV_TYPE_GENERICLABEL)) { + send_notification(nbr->tcp, S_MISS_MSG, msg.id, + msg.type); + goto err; + } + switch (tlv_type) { case TLV_TYPE_LABELREQUEST: switch (type) { @@ -284,6 +284,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) break; case TLV_TYPE_GENERICLABEL: switch (type) { + case MSG_TYPE_LABELMAPPING: case MSG_TYPE_LABELWITHDRAW: case MSG_TYPE_LABELRELEASE: if (tlv_len != LABEL_TLV_LEN) { @@ -294,6 +295,16 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) memcpy(&labelbuf, buf, sizeof(labelbuf)); label = ntohl(labelbuf); + /* do not accept invalid labels */ + if (label > MPLS_LABEL_MAX || + (label <= MPLS_LABEL_RESERVED_MAX && + label != MPLS_LABEL_IPV4NULL && + label != MPLS_LABEL_IPV6NULL && + label != MPLS_LABEL_IMPLNULL)) { + session_shutdown(nbr, S_BAD_TLV_VAL, + msg.id, msg.type); + goto err; + } break; default: /* ignore */ @@ -303,6 +314,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) case TLV_TYPE_ATMLABEL: case TLV_TYPE_FRLABEL: switch (type) { + case MSG_TYPE_LABELMAPPING: case MSG_TYPE_LABELWITHDRAW: case MSG_TYPE_LABELRELEASE: /* unsupported */ @@ -350,6 +362,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) } buf += tlv_len; len -= tlv_len; + current_tlv++; } /* notify lde about the received message. */ @@ -449,53 +462,6 @@ gen_label_tlv(struct ibuf *buf, uint32_t label) return (ibuf_add(buf, <, 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(<, buf, sizeof(lt)); - - if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) { - send_notification(nbr->tcp, S_MISS_MSG, msg->id, msg->type); - return (-1); - } - - switch (htons(lt.type)) { - case TLV_TYPE_GENERICLABEL: - if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_SIZE) { - session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, - msg->type); - return (-1); - } - - *label = ntohl(lt.label); - if (*label > MPLS_LABEL_MAX || - (*label <= MPLS_LABEL_RESERVED_MAX && - *label != MPLS_LABEL_IPV4NULL && - *label != MPLS_LABEL_IPV6NULL && - *label != MPLS_LABEL_IMPLNULL)) { - session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, - msg->type); - return (-1); - } - break; - case TLV_TYPE_ATMLABEL: - case TLV_TYPE_FRLABEL: - default: - /* unsupported */ - session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, msg->type); - return (-1); - } - - return (sizeof(lt)); -} - static int gen_reqid_tlv(struct ibuf *buf, uint32_t reqid) { From ffdc293b9dc0ed746a31fcf20765c2d5e85e9c70 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 3 Mar 2017 17:50:22 -0300 Subject: [PATCH 18/18] ldpd: add missing htonl and ntohl in PF_KEY code Signed-off-by: Renato Westphal --- ldpd/pfkey.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ldpd/pfkey.c b/ldpd/pfkey.c index 29f763e6a6..88a778cccc 100644 --- a/ldpd/pfkey.c +++ b/ldpd/pfkey.c @@ -131,7 +131,7 @@ pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir, sa.sadb_sa_exttype = SADB_EXT_SA; sa.sadb_sa_len = sizeof(sa) / 8; sa.sadb_sa_replay = 0; - sa.sadb_sa_spi = spi; + sa.sadb_sa_spi = htonl(spi); sa.sadb_sa_state = SADB_SASTATE_MATURE; break; } @@ -280,7 +280,7 @@ pfkey_read(int sd, struct sadb_msg *h) } static int -pfkey_reply(int sd, uint32_t *spip) +pfkey_reply(int sd, uint32_t *spi) { struct sadb_msg hdr, *msg; struct sadb_ext *ext; @@ -317,7 +317,7 @@ pfkey_reply(int sd, uint32_t *spip) } if (hdr.sadb_msg_type == SADB_GETSPI) { - if (spip == NULL) { + if (spi == NULL) { explicit_bzero(data, len); free(data); return (0); @@ -331,7 +331,7 @@ pfkey_reply(int sd, uint32_t *spip) ext->sadb_ext_len * PFKEY2_CHUNK)) { if (ext->sadb_ext_type == SADB_EXT_SA) { sa = (struct sadb_sa *) ext; - *spip = sa->sadb_sa_spi; + *spi = ntohl(sa->sadb_sa_spi); break; } }