---
 init.c         |  68 +++++++++++++++++++++++++++++++-
 labelmapping.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 lde.c          |  14 +++++++
 lde.h          |   3 ++
 lde_lib.c      |  56 +++++++++++++++++++++++++++
 ldp.h          |   8 ++++
 ldpd.8         |   9 +++++
 ldpd.h         |   6 +++
 ldpe.h         |   1 +
 logmsg.c       |  17 ++++++++
 10 files changed, 299 insertions(+), 3 deletions(-)

diff --git a/init.c b/init.c
index cc45443..2cc89b8 100644
--- a/init.c
+++ b/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);
 
 void
 send_init(struct nbr *nbr)
@@ -37,7 +38,7 @@ send_init(struct nbr *nbr)
        log_debug("%s: lsr-id %s", __func__, 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__);
 
@@ -46,6 +47,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;
@@ -147,6 +149,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,
@@ -194,6 +215,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:
@@ -219,6 +243,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));
 
@@ -231,6 +257,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);
@@ -248,6 +275,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:
@@ -306,3 +358,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/labelmapping.c b/labelmapping.c
index 867d9f9..b0e7131 100644
--- a/labelmapping.c
+++ b/labelmapping.c
@@ -93,6 +93,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;
@@ -212,6 +222,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.
                 */
@@ -527,7 +555,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;
 
@@ -597,6 +625,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;
        }
@@ -609,7 +674,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);
@@ -754,6 +819,57 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, 
char *buf,
                }
 
                return (off);
+       case MAP_TYPE_TYPED_WCARD:
+               if (len < FEC_ELM_TWCARD_MIN_LEN) {
+                       session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
+                           msg->type);
+                       return (-1);
+               }
+
+               memcpy(&map->fec.twcard.type, buf + off, sizeof(uint8_t));
+               off += sizeof(uint8_t);
+               memcpy(&twcard_len, buf + off, sizeof(uint8_t));
+               off += sizeof(uint8_t);
+               if (len != FEC_ELM_TWCARD_MIN_LEN + twcard_len) {
+                       session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
+                           msg->type);
+                       return (-1);
+               }
+
+               switch (map->fec.twcard.type) {
+               case MAP_TYPE_PREFIX:
+                       if (twcard_len != sizeof(uint16_t)) {
+                               session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
+                                   msg->type);
+                               return (-1);
+                       }
+
+                       memcpy(&map->fec.twcard.u.prefix_af, buf + off,
+                           sizeof(uint16_t));
+                       map->fec.twcard.u.prefix_af =
+                           ntohs(map->fec.twcard.u.prefix_af);
+                       off += sizeof(uint16_t);
+
+                       switch (map->fec.twcard.u.prefix_af) {
+                       case AF_IPV4:
+                               map->fec.twcard.u.prefix_af = AF_INET;
+                               break;
+                       case AF_IPV6:
+                               map->fec.twcard.u.prefix_af = AF_INET6;
+                               break;
+                       default:
+                               session_shutdown(nbr, S_BAD_TLV_VAL, msg->id,
+                                   msg->type);
+                               return (-1);
+                       }
+                       break;
+               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);
                break;
diff --git a/lde.c b/lde.c
index fe44aa6..cc8459d 100644
--- a/lde.c
+++ b/lde.c
@@ -895,6 +895,20 @@ lde_send_labelwithdraw_wcard(struct lde_nbr *ln, uint32_t 
label)
 }
 
 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/lde.h b/lde.h
index 2fcb614..23cdaae 100644
--- a/lde.h
+++ b/lde.h
@@ -136,6 +136,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 *,
@@ -172,6 +174,7 @@ void                 lde_kernel_remove(struct fec *, int, 
union ldpd_addr *,
                    uint8_t);
 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/lde_lib.c b/lde_lib.c
index 6a3ac7e..e111cba 100644
--- a/lde_lib.c
+++ b/lde_lib.c
@@ -524,6 +524,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? */
@@ -575,6 +581,40 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
 }
 
 void
+lde_check_request_wcard(struct map *map, struct lde_nbr *ln)
+{
+       struct fec      *f;
+       struct fec_node *fn;
+       struct lde_req  *lre;
+
+       RB_FOREACH(f, fec_tree, &ft) {
+               fn = (struct fec_node *)f;
+
+               /* only a typed wildcard is possible here */
+               if (lde_wildcard_apply(map, &fn->fec, NULL) == 0)
+                       continue;
+
+               /* LRq.2: is there a next hop for fec? */
+               if (LIST_EMPTY(&fn->nexthops))
+                       continue;
+
+               /* LRq.6: first check if we have a pending request running */
+               lre = (struct lde_req *)fec_find(&ln->recv_req, &fn->fec);
+               if (lre != NULL)
+                       /* LRq.7: duplicate request */
+                       continue;
+
+               /* LRq.8: record label request */
+               lre = lde_req_add(ln, &fn->fec, 0);
+               if (lre != NULL)
+                       lre->msg_id = ntohl(map->msg_id);
+
+               /* LRq.9: perform LSR label distribution */
+               lde_send_labelmapping(ln, fn, 1);
+       }
+}
+
+void
 lde_check_release(struct map *map, struct lde_nbr *ln)
 {
        struct fec               fec;
@@ -584,6 +624,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;
@@ -659,6 +700,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;
@@ -762,6 +804,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/ldp.h b/ldp.h
index f73c8d1..71cd9de 100644
--- a/ldp.h
+++ b/ldp.h
@@ -101,6 +101,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
 
@@ -243,10 +245,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
 
@@ -263,9 +269,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.8 b/ldpd.8
index 27efbe3..cebc222 100644
--- a/ldpd.8
+++ b/ldpd.8
@@ -143,6 +143,15 @@ socket used for communication with
 .Re
 .Pp
 .Rs
+.%A R. Asati
+.%A I. Minei
+.%A B. Thomas
+.%D August 2010
+.%R RFC 5918
+.%T Label Distribution Protocol (LDP) 'Typed Wildcard' Forward Equivalence 
Class (FEC)
+.Re
+.Pp
+.Rs
 .%A C. Pignataro
 .%A R. Asati
 .%D August 2012
diff --git a/ldpd.h b/ldpd.h
index 9b9c620..1eccef5 100644
--- a/ldpd.h
+++ b/ldpd.h
@@ -204,6 +204,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/ldpe.h b/ldpe.h
index 5d279ca..76adb09 100644
--- a/ldpe.h
+++ b/ldpe.h
@@ -105,6 +105,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/logmsg.c b/logmsg.c
index 4c279ef..98cbadf 100644
--- a/logmsg.c
+++ b/logmsg.c
@@ -173,6 +173,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 ("???");
        }
-- 
1.9.1

Reply via email to