]> git.puffer.fish Git - matthieu/frr.git/commitdiff
ldpd: implement support for PWid group wildcards
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)
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 <renato@opensourcerouting.org>
ldpd/l2vpn.c
ldpd/lde.c
ldpd/lde.h
ldpd/lde_lib.c
ldpd/log.c

index 792608d4259677565310c2b13cbe8276d8e3d3e5..ad3e8199c98b0ef51cc4fb39dfbc76054a78455c 100644 (file)
@@ -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)
 {
index 6ac0f07dafc9a2e1873a9052ebadc81f27d4866f..3041c44bdc8799dc66c9d40af5f197ca9abcff55 100644 (file)
@@ -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 */
index b3fa2d469b56fd59f760ec46185fb5b93aea9615..367ba254db4fd002d75d0342ce2eb1984c8f42db 100644 (file)
@@ -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);
index 02730189a8ac0ed234ab156b80a42e2e9e675f0c..c37a9e9660e31d29a6d104668371ed78f309c01d 100644 (file)
@@ -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 */
index 77efdb47140c19fe7dacde80a0bf68a0570e8f74..661fe04b1964d6a29eb436e631976186e9b171c5 100644 (file)
@@ -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;