diff options
author | Renato Westphal <renato@opensourcerouting.org> | 2017-03-03 21:50:22 +0100 |
---|---|---|
committer | Renato Westphal <renato@opensourcerouting.org> | 2017-03-03 21:50:22 +0100 |
commit | 257799cdb69707f7bea43b118c9787458d1d81ba (patch) | |
tree | f3ded89e87ac55271d14630c5918ea48116cd4a0 /ldpd | |
parent | ldpd: implement RFC 6667 (Typed Wildcard FEC for PWid) (diff) | |
download | frr-257799cdb69707f7bea43b118c9787458d1d81ba.tar.xz frr-257799cdb69707f7bea43b118c9787458d1d81ba.zip |
ldpd: implement RFC 5919 (LDP End-of-LIB)
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
Diffstat (limited to 'ldpd')
-rw-r--r-- | ldpd/init.c | 67 | ||||
-rw-r--r-- | ldpd/labelmapping.c | 72 | ||||
-rw-r--r-- | ldpd/lde.c | 40 | ||||
-rw-r--r-- | ldpd/lde.h | 3 | ||||
-rw-r--r-- | ldpd/ldp.h | 8 | ||||
-rw-r--r-- | ldpd/ldpe.h | 2 | ||||
-rw-r--r-- | ldpd/log.c | 2 | ||||
-rw-r--r-- | ldpd/neighbor.c | 1 | ||||
-rw-r--r-- | ldpd/notification.c | 40 |
9 files changed, 192 insertions, 43 deletions
diff --git a/ldpd/init.c b/ldpd/init.c index 13104b4ee..bc3a69edc 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 55b890ac7..75acfd7d5 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 2392dbf6d..e64f18dfc 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 b3af1bbaa..a2b51dad3 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 ffdadf8be..0a42ab407 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 24512989d..2bd0568d6 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 5ad8ca0ca..b30604db0 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 d24ceb122..077d47285 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 69d4ab802..393994ed5 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); } |