]> git.proxmox.com Git - mirror_frr.git/blobdiff - ldpd/lde_lib.c
Merge pull request #6243 from pguibert6WIND/flowspec_some_regression_seen
[mirror_frr.git] / ldpd / lde_lib.c
index eb1a6d94349bb0c42de9148945c67ad9d2091866..71fb0c7bf285350482bdde8f3d833c2223f4733d 100644 (file)
@@ -20,6 +20,7 @@
 #include <zebra.h>
 
 #include "ldpd.h"
+#include "ldpe.h"
 #include "lde.h"
 #include "log.h"
 
@@ -266,6 +267,9 @@ fec_add(struct fec *fec)
        RB_INIT(lde_map_head, &fn->downstream);
        LIST_INIT(&fn->nexthops);
 
+       if (fec->type == FEC_TYPE_PWID)
+               fn->pw_remote_status = PW_FORWARDING;
+
        if (fec_insert(&ft, &fn->fec))
                log_warnx("failed to add %s to ft tree",
                    log_fec(&fn->fec));
@@ -325,6 +329,7 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
 {
        struct fec_node         *fn;
        struct fec_nh           *fnh;
+       struct iface            *iface;
 
        fn = (struct fec_node *)fec_find(&ft, fec);
        if (fn == NULL)
@@ -333,9 +338,21 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
                fn->data = data;
 
        fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance);
-       if (fnh == NULL)
+       if (fnh == NULL) {
                fnh = fec_nh_add(fn, af, nexthop, ifindex, route_type,
                    route_instance);
+               /*
+                * Ordered Control: if not a connected route and not a route
+                * learned over an interface not running LDP and not a PW
+                * then mark to wait until we receive labelmap msg before
+                * installing in kernel and sending to peer
+                */
+               iface = if_lookup(ldeconf, ifindex);
+               if ((ldeconf->flags & F_LDPD_ORDERED_CONTROL) &&
+                   !connected && iface != NULL && fec->type != FEC_TYPE_PWID)
+                       fnh->flags |= F_FEC_NH_DEFER;
+       }
+
        fnh->flags |= F_FEC_NH_NEW;
        if (connected)
                fnh->flags |= F_FEC_NH_CONNECTED;
@@ -374,15 +391,25 @@ lde_kernel_update(struct fec *fec)
        struct fec_nh           *fnh, *safe;
        struct lde_nbr          *ln;
        struct lde_map          *me;
+       struct iface            *iface;
 
        fn = (struct fec_node *)fec_find(&ft, fec);
        if (fn == NULL)
                return;
 
        LIST_FOREACH_SAFE(fnh, &fn->nexthops, entry, safe) {
-               if (fnh->flags & F_FEC_NH_NEW)
+               if (fnh->flags & F_FEC_NH_NEW) {
                        fnh->flags &= ~F_FEC_NH_NEW;
-               else {
+                       /*
+                        * if LDP configured on interface or a static route
+                        * clear flag else treat fec as a connected route
+                        */
+                       iface = if_lookup(ldeconf,fnh->ifindex);
+                       if (iface || fnh->route_type == ZEBRA_ROUTE_STATIC)
+                               fnh->flags &=~F_FEC_NH_NO_LDP;
+                       else
+                               fnh->flags |= F_FEC_NH_NO_LDP;
+               } else {
                        lde_send_delete_klabel(fn, fnh);
                        fec_nh_del(fnh);
                }
@@ -431,13 +458,13 @@ lde_kernel_update(struct fec *fec)
                        me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
                        if (me)
                                /* FEC.5 */
-                               lde_check_mapping(&me->map, ln);
+                               lde_check_mapping(&me->map, ln, 0);
                }
        }
 }
 
 void
-lde_check_mapping(struct map *map, struct lde_nbr *ln)
+lde_check_mapping(struct map *map, struct lde_nbr *ln, int rcvd_label_mapping)
 {
        struct fec               fec;
        struct fec_node         *fn;
@@ -445,6 +472,7 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
        struct lde_req          *lre;
        struct lde_map          *me;
        struct l2vpn_pw         *pw;
+       bool                     send_map = false;
 
        lde_map2fec(map, ln->id, &fec);
 
@@ -482,8 +510,12 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
                lde_req_del(ln, lre, 1);
 
        /* RFC 4447 control word and status tlv negotiation */
-       if (map->type == MAP_TYPE_PWID && l2vpn_pw_negotiate(ln, fn, map))
+       if (map->type == MAP_TYPE_PWID && l2vpn_pw_negotiate(ln, fn, map)) {
+               if (rcvd_label_mapping && map->flags & F_MAP_PW_STATUS)
+                       fn->pw_remote_status = map->pw_status;
+
                return;
+       }
 
        /*
         * LMp.3 - LMp.8: loop detection - unnecessary for frame-mode
@@ -525,6 +557,15 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
                        if (!lde_address_find(ln, fnh->af, &fnh->nexthop))
                                continue;
 
+                       /*
+                        * Ordered Control: labelmap msg received from
+                        * NH so clear flag and send labelmap msg to
+                        * peer
+                        */
+                       if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) {
+                               send_map = true;
+                               fnh->flags &= ~F_FEC_NH_DEFER;
+                       }
                        fnh->remote_label = map->label;
                        lde_send_change_klabel(fn, fnh);
                        break;
@@ -536,8 +577,10 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
                        pw->remote_group = map->fec.pwid.group_id;
                        if (map->flags & F_MAP_PW_IFMTU)
                                pw->remote_mtu = map->fec.pwid.ifmtu;
-                       if (map->flags & F_MAP_PW_STATUS)
+                       if (rcvd_label_mapping && map->flags & F_MAP_PW_STATUS) {
                                pw->remote_status = map->pw_status;
+                               fn->pw_remote_status = map->pw_status;
+                       }
                        else
                                pw->remote_status = PW_FORWARDING;
                        fnh->remote_label = map->label;
@@ -558,6 +601,15 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
         * loop detection. LMp.28 - LMp.30 are unnecessary because we are
         * merging capable.
         */
+
+       /*
+        * Ordered Control: just received a labelmap for this fec from NH so
+        * need to send labelmap to all peers
+        * LMp.20 - LMp21 Execute procedure to send Label Mapping
+        */
+       if (send_map && fn->local_label != NO_LABEL)
+               RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+                       lde_send_labelmapping(ln, fn, 1);
 }
 
 void
@@ -757,6 +809,7 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
        struct fec_nh           *fnh;
        struct lde_map          *me;
        struct l2vpn_pw         *pw;
+       struct lde_nbr          *lnbr;
 
        /* wildcard label withdraw */
        if (map->type == MAP_TYPE_WILDCARD ||
@@ -803,6 +856,26 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
        if (me && (map->label == NO_LABEL || map->label == me->map.label))
                /* LWd.4: remove record of previously received lbl mapping */
                lde_map_del(ln, me, 0);
+
+       /* Ordered Control: additional withdraw steps */
+       if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) {
+               /* LWd.8: for each neighbor other that src of withdraw msg */
+               RB_FOREACH(lnbr, nbr_tree, &lde_nbrs) {
+                       if (ln->peerid == lnbr->peerid)
+                               continue;
+
+                       /* LWd.9: check if previously sent a label mapping */
+                       me = (struct lde_map *)fec_find(&lnbr->sent_map,
+                           &fn->fec);
+                       /*
+                        * LWd.10: does label sent to peer "map" to withdraw
+                        * label
+                        */
+                       if (me)
+                               /* LWd.11: send label withdraw */
+                               lde_send_labelwithdraw(lnbr, fn, NULL, NULL);
+               }
+       }
 }
 
 void
@@ -813,6 +886,7 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
        struct fec_nh   *fnh;
        struct lde_map  *me;
        struct l2vpn_pw *pw;
+       struct lde_nbr  *lnbr;
 
        /* LWd.2: send label release */
        lde_send_labelrelease(ln, NULL, map, map->label);
@@ -859,6 +933,26 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
                         * label mapping
                         */
                        lde_map_del(ln, me, 0);
+
+               /* Ordered Control: additional withdraw steps */
+               if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) {
+                       /* LWd.8: for each neighbor other that src of withdraw msg */
+                       RB_FOREACH(lnbr, nbr_tree, &lde_nbrs) {
+                               if (ln->peerid == lnbr->peerid)
+                                       continue;
+
+                               /* LWd.9: check if previously sent a label mapping */
+                               me = (struct lde_map *)fec_find(&lnbr->sent_map,
+                                       &fn->fec);
+                               /*
+                                * LWd.10: does label sent to peer "map" to withdraw
+                                * label
+                                */
+                               if (me)
+                                       /* LWd.11: send label withdraw */
+                                       lde_send_labelwithdraw(lnbr, fn, NULL, NULL);
+                       }
+               }
        }
 }