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.
---
 l2vpn.c   | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 lde.c     | 71 ++++++++++++++++++++++++++++++++++++---------------------------
 lde.h     | 16 ++++++++++----
 lde_lib.c | 57 +++++++++++++++++++++++++++++++++++++++++---------
 logmsg.c  |  6 +++---
 5 files changed, 167 insertions(+), 54 deletions(-)

diff --git a/l2vpn.c b/l2vpn.c
index 22c9874..e79caa8 100644
--- a/l2vpn.c
+++ b/l2vpn.c
@@ -282,7 +282,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);
@@ -305,7 +305,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;
 
@@ -316,8 +316,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
@@ -328,9 +347,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);
@@ -349,7 +369,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))
@@ -358,6 +377,44 @@ 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);
+               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/lde.c b/lde.c
index 8e82523..fe44aa6 100644
--- a/lde.c
+++ b/lde.c
@@ -253,16 +253,10 @@ lde_dispatch_imsg(int fd, short event, void *bula)
                                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 */
@@ -820,8 +814,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;
@@ -850,11 +844,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;
@@ -875,8 +866,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);
@@ -888,16 +884,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;
@@ -923,10 +937,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,
@@ -1235,15 +1247,14 @@ lde_change_egress_label(int af, int was_implicit)
        RB_FOREACH(ln, nbr_tree, &lde_nbrs) {
                /* explicit withdraw */
                if (was_implicit)
-                       lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IMPLNULL,
-                           NULL);
+                       lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IMPLNULL);
                else {
                        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);
                }
 
                /* advertise new label of connected prefixes */
diff --git a/lde.h b/lde.h
index 881a4d0..2fcb614 100644
--- a/lde.h
+++ b/lde.h
@@ -134,10 +134,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);
@@ -174,6 +176,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 *);
 void            lde_gc_timer(int, short, void *);
 void            lde_gc_start_timer(void);
 void            lde_gc_stop_timer(void);
@@ -194,8 +198,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/lde_lib.c b/lde_lib.c
index 8d0e974..6a3ac7e 100644
--- a/lde_lib.c
+++ b/lde_lib.c
@@ -386,6 +386,7 @@ lde_kernel_remove(struct fec *fec, int af, union ldpd_addr 
*nexthop,
 {
        struct fec_node         *fn;
        struct fec_nh           *fnh;
+       struct lde_nbr          *ln;
 
        fn = (struct fec_node *)fec_find(&ft, fec);
        if (fn == NULL)
@@ -402,7 +403,8 @@ lde_kernel_remove(struct fec *fec, int af, union ldpd_addr 
*nexthop,
        lde_send_delete_klabel(fn, fnh);
        fec_nh_del(fnh);
        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;
                if (fn->fec.type == FEC_TYPE_PWID)
                        fn->data = NULL;
@@ -446,7 +448,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
@@ -580,9 +582,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);
@@ -618,6 +623,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);
@@ -627,7 +637,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);
@@ -648,9 +657,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);
@@ -681,7 +693,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);
@@ -699,10 +711,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) {
@@ -729,7 +745,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))
                        /*
@@ -740,6 +755,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/logmsg.c b/logmsg.c
index 0778672..2999446 100644
--- a/logmsg.c
+++ b/logmsg.c
@@ -154,7 +154,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:
@@ -168,8 +168,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;
-- 
1.9.1

Reply via email to