]> git.proxmox.com Git - mirror_frr.git/commitdiff
ldpd: implement RFC 5919 (LDP End-of-LIB)
authorRenato Westphal <renato@opensourcerouting.org>
Fri, 3 Mar 2017 20:50:22 +0000 (17:50 -0300)
committerRenato Westphal <renato@opensourcerouting.org>
Fri, 3 Mar 2017 20:50:22 +0000 (17:50 -0300)
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
ldpd/init.c
ldpd/labelmapping.c
ldpd/lde.c
ldpd/lde.h
ldpd/ldp.h
ldpd/ldpe.h
ldpd/log.c
ldpd/neighbor.c
ldpd/notification.c

index 13104b4ee608257c675f173c5cf855b4b93db784..bc3a69edc7c032b57d7004be409ae769c9731a5e 100644 (file)
@@ -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));
+}
index 55b890ac70a40c47652190d45fbc5bef675065b8..75acfd7d504f40f936279428e0f1303fc3eceed5 100644 (file)
@@ -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)
 {
index 2392dbf6d00dfe6ed3e6da5c153198471e640cd8..e64f18dfc94a3d3d39df68136d01c7468b8c730f 100644 (file)
@@ -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);
index b3af1bbaa4de91a49ae20f82ef4d5e61b99922f1..a2b51dad32a31eb1f783c2aa46629337d0e4e627 100644 (file)
@@ -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);
index ffdadf8be9d23c272670e2c804ea9471c0b43b51..0a42ab40765873c4b01cdf095f081b79762eeb2a 100644 (file)
 #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
 
index 24512989def3fbc6e16cee4bb62e2dcda6761487..2bd0568d68a73639492bb96897069de6a2ac2d70 100644 (file)
@@ -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 *);
index 5ad8ca0caf378f0eb849362b809e356a9824ac61..b30604db0d1a1b55db11517509e98efb77355688 100644 (file)
@@ -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:
index d24ceb1229dcee6519b932c7127a7ba6e97646c4..077d472850059129c9b9fc6d33f64ebd3edf97f8 100644 (file)
@@ -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)));
 }
index 69d4ab8028d50683bc372313aba6fd21b2238f7f..393994ed5f72686990055cd99c131b46384693e5 100644 (file)
@@ -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);
 }