]> git.puffer.fish Git - mirror/frr.git/commitdiff
ldpd: Fix issue when starting up LDP with no configuration. 6971/head
authorlynne <lynne@voltanet.io>
Wed, 12 Aug 2020 23:15:24 +0000 (19:15 -0400)
committerlynne <lynne@voltanet.io>
Fri, 4 Sep 2020 13:24:47 +0000 (09:24 -0400)
LDP would mark all routes as learned on a non-ldp interface.  Then
when LDP was configured the labels were not updated correctly.  This
commit fixes issues 6841 and 6842.

Signed-off-by: Lynne Morrison <lynne@voltanet.io>
ldpd/lde.c
ldpd/lde.h
ldpd/lde_lib.c
ldpd/ldp_vty_cmds.c
ldpd/ldpd.c
ldpd/ldpe.c
lib/mpls.h

index 734c1ea230ea85161abb60471fa076474ad91c03..df64f908ead135277384567ab8fab4c70619eec8 100644 (file)
@@ -468,6 +468,10 @@ lde_dispatch_parent(struct thread *thread)
                        iface = if_lookup_name(ldeconf, kif->ifname);
                        if (iface) {
                                if_update_info(iface, kif);
+
+                               /* if up see if any labels need to be updated */
+                               if (kif->operative)
+                                       lde_route_update(iface, AF_UNSPEC);
                                break;
                        }
 
@@ -786,7 +790,6 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
                kr.remote_label = fnh->remote_label;
                kr.route_type = fnh->route_type;
                kr.route_instance = fnh->route_instance;
-
                lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
                    sizeof(kr));
                break;
@@ -2271,3 +2274,156 @@ lde_check_filter_af(int af, struct ldpd_af_conf *af_conf,
        if (strcmp(af_conf->acl_label_expnull_for, filter_name) == 0)
                lde_change_expnull_for_filter(af);
 }
+
+void lde_route_update(struct iface *iface, int af)
+{
+       struct fec      *f;
+       struct fec_node *fn;
+       struct fec_nh   *fnh;
+       struct lde_nbr  *ln;
+
+       /* update label of non-connected routes */
+       log_debug("update labels for interface %s", iface->name);
+       RB_FOREACH(f, fec_tree, &ft) {
+               fn = (struct fec_node *)f;
+               if (IS_MPLS_UNRESERVED_LABEL(fn->local_label))
+                       continue;
+
+               switch (af) {
+               case AF_INET:
+                       if (fn->fec.type != FEC_TYPE_IPV4)
+                               continue;
+                       break;
+               case AF_INET6:
+                       if (fn->fec.type != FEC_TYPE_IPV6)
+                               continue;
+                       break;
+               default:
+                       /* unspecified so process both address families */
+                       break;
+               }
+
+               LIST_FOREACH(fnh, &fn->nexthops, entry) {
+                       /*
+                        * If connected leave existing label. If LDP
+                        * configured on interface or a static route
+                        * may need new label. If no LDP configured
+                        * treat fec as a connected route
+                        */
+                       if (fnh->flags & F_FEC_NH_CONNECTED)
+                               break;
+
+                       if (fnh->ifindex != iface->ifindex)
+                               continue;
+
+                       fnh->flags &= ~F_FEC_NH_NO_LDP;
+                       if (IS_MPLS_RESERVED_LABEL(fn->local_label)) {
+                               fn->local_label = NO_LABEL;
+                               fn->local_label = lde_update_label(fn);
+                               if (fn->local_label != NO_LABEL)
+                                       RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+                                               lde_send_labelmapping(
+                                                   ln, fn, 0);
+                       }
+                       break;
+               }
+       }
+       RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+               lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid,
+                   0, NULL, 0);
+}
+
+void lde_route_update_release(struct iface *iface, int af)
+{
+       struct lde_nbr  *ln;
+       struct fec      *f;
+       struct fec_node *fn;
+       struct fec_nh   *fnh;
+
+       /* update label of interfaces no longer running LDP */
+       log_debug("release all labels for interface %s af %s", iface->name,
+           af == AF_INET ? "ipv4" : "ipv6");
+       RB_FOREACH(f, fec_tree, &ft) {
+               fn = (struct fec_node *)f;
+
+               switch (af) {
+               case AF_INET:
+                       if (fn->fec.type != FEC_TYPE_IPV4)
+                               continue;
+                       break;
+               case AF_INET6:
+                       if (fn->fec.type != FEC_TYPE_IPV6)
+                               continue;
+                       break;
+               default:
+                       fatalx("lde_route_update_release: unknown af");
+               }
+
+               if (fn->local_label == NO_LABEL)
+                       continue;
+
+               LIST_FOREACH(fnh, &fn->nexthops, entry) {
+                       /*
+                        * If connected leave existing label. If LDP
+                        * removed from interface may need new label
+                        * and would be treated as a connected route
+                        */
+                       if (fnh->flags & F_FEC_NH_CONNECTED)
+                               break;
+
+                       if (fnh->ifindex != iface->ifindex)
+                               continue;
+
+                       fnh->flags |= F_FEC_NH_NO_LDP;
+                       RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+                               lde_send_labelwithdraw(ln, fn, NULL, NULL);
+                       lde_free_label(fn->local_label);
+                       fn->local_label = NO_LABEL;
+                       fn->local_label = lde_update_label(fn);
+                       if (fn->local_label != NO_LABEL)
+                               RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+                                       lde_send_labelmapping(ln, fn, 0);
+                       break;
+               }
+       }
+       RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+               lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid,
+                   0, NULL, 0);
+}
+
+void lde_route_update_release_all(int af)
+{
+       struct lde_nbr  *ln;
+       struct fec      *f;
+       struct fec_node *fn;
+       struct fec_nh   *fnh;
+
+       /* remove labels from all interfaces as LDP is no longer running for
+        * this address family
+        */
+       log_debug("release all labels for address family %s",
+           af == AF_INET ? "ipv4" : "ipv6");
+       RB_FOREACH(f, fec_tree, &ft) {
+               fn = (struct fec_node *)f;
+               switch (af) {
+               case AF_INET:
+                       if (fn->fec.type != FEC_TYPE_IPV4)
+                               continue;
+                       break;
+               case AF_INET6:
+                       if (fn->fec.type != FEC_TYPE_IPV6)
+                               continue;
+                       break;
+               default:
+                       fatalx("lde_route_update_release: unknown af");
+               }
+
+               RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+                       lde_send_labelwithdraw(ln, fn, NULL, NULL);
+
+               LIST_FOREACH(fnh, &fn->nexthops, entry) {
+                       fnh->flags |= F_FEC_NH_NO_LDP;
+                       lde_send_delete_klabel(fn, fnh);
+               }
+       }
+}
index 9e6db3a90b1259917a651c7d62b2034ed30eb010..660aeafb34bf309f5a851252dd9252275c3144d2 100644 (file)
@@ -193,6 +193,9 @@ void                 lde_change_allocate_filter(int);
 void            lde_change_advertise_filter(int);
 void            lde_change_accept_filter(int);
 void            lde_change_expnull_for_filter(int);
+void            lde_route_update(struct iface *, int);
+void            lde_route_update_release(struct iface *, int);
+void            lde_route_update_release_all(int);
 struct lde_addr        *lde_address_find(struct lde_nbr *, int,
                    union ldpd_addr *);
 
index 11d85b7449b209bda827108f4675c2a1f786556c..bed276c7b1ec3b887d849dff7153bfebbb1446bb 100644 (file)
@@ -404,10 +404,15 @@ lde_kernel_update(struct fec *fec)
                         * 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
+                       if (ldeconf->flags & F_LDPD_ENABLED) {
+                               iface = if_lookup(ldeconf,fnh->ifindex);
+                               if (fnh->flags & F_FEC_NH_CONNECTED ||
+                                   iface ||
+                                   fnh->route_type == ZEBRA_ROUTE_STATIC)
+                                       fnh->flags &=~F_FEC_NH_NO_LDP;
+                               else
+                                       fnh->flags |= F_FEC_NH_NO_LDP;
+                       } else
                                fnh->flags |= F_FEC_NH_NO_LDP;
                } else {
                        lde_send_delete_klabel(fn, fnh);
@@ -437,6 +442,10 @@ lde_kernel_update(struct fec *fec)
                                lde_send_labelmapping(ln, fn, 1);
        }
 
+       /* if no label created yet then don't try to program labeled route */
+       if (fn->local_label == NO_LABEL)
+               return;
+
        LIST_FOREACH(fnh, &fn->nexthops, entry) {
                lde_send_change_klabel(fn, fnh);
 
@@ -567,7 +576,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln, int rcvd_label_mapping)
                                fnh->flags &= ~F_FEC_NH_DEFER;
                        }
                        fnh->remote_label = map->label;
-                       lde_send_change_klabel(fn, fnh);
+                       if (fn->local_label != NO_LABEL)
+                               lde_send_change_klabel(fn, fnh);
                        break;
                case FEC_TYPE_PWID:
                        pw = (struct l2vpn_pw *) fn->data;
index fc84c7f76b9333390c4e22c8741839257e2c585b..53a384fe5521b17f72fd3b88a9ee2b4bd60e77ec 100644 (file)
@@ -616,6 +616,8 @@ DEFPY  (ldp_show_mpls_ldp_binding,
        "Show detailed information\n"
        JSON_STR)
 {
+       if (!(ldpd_conf->flags & F_LDPD_ENABLED))
+               return CMD_SUCCESS;
        if (!local_label_str)
                local_label = NO_LABEL;
        if (!remote_label_str)
index 927c3a3c0398b6bd52a89096f8766edc18cedda4..dca379e4ebafb977e099c5dbd5b710b4e30a7585 100644 (file)
@@ -1329,6 +1329,7 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
        int              reset_nbrs_ipv4 = 0;
        int              reset_nbrs = 0;
        int              update_sockets = 0;
+       int              change_ldp_disabled = 0;
 
        /* update timers */
        if (af_conf->keepalive != xa->keepalive) {
@@ -1362,6 +1363,11 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
            != (xa->flags & F_LDPD_AF_ALLOCHOSTONLY))
                change_host_label = 1;
 
+       /* disabling LDP for address family */
+       if ((af_conf->flags & F_LDPD_AF_ENABLED) &&
+           !(xa->flags & F_LDPD_AF_ENABLED))
+               change_ldp_disabled = 1;
+
        af_conf->flags = xa->flags;
 
        /* update the transport address */
@@ -1409,6 +1415,9 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
                        lde_change_egress_label(af);
                if (change_host_label)
                        lde_change_allocate_filter(af);
+               if (change_ldp_disabled)
+                       lde_route_update_release_all(af);
+
                break;
        case PROC_LDP_ENGINE:
                if (stop_init_backoff)
@@ -1434,13 +1443,22 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)
        struct iface            *iface, *itmp, *xi;
 
        RB_FOREACH_SAFE(iface, iface_head, &conf->iface_tree, itmp) {
-               /* find deleted interfaces */
+               /* find deleted interfaces, which occurs when LDP is removed
+                * for all address families
+                */
                if (if_lookup_name(xconf, iface->name) == NULL) {
                        switch (ldpd_process) {
                        case PROC_LDP_ENGINE:
                                ldpe_if_exit(iface);
                                break;
                        case PROC_LDE_ENGINE:
+                               if (iface->ipv4.enabled)
+                                       lde_route_update_release(iface,
+                                           AF_INET);
+                               if (iface->ipv6.enabled)
+                                       lde_route_update_release(iface,
+                                           AF_INET6);
+                               break;
                        case PROC_MAIN:
                                break;
                        }
@@ -1468,6 +1486,29 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)
                        continue;
                }
 
+               /* update labels when adding or removing ldp on an
+                * interface
+                */
+               if (ldpd_process == PROC_LDE_ENGINE) {
+                       /* if we are removing lpd config for an address
+                        * family on an interface then advertise routes
+                        * learned over this interface as if they were
+                        * connected routes
+                        */
+                       if (iface->ipv4.enabled && !xi->ipv4.enabled)
+                               lde_route_update_release(iface, AF_INET);
+                       if (iface->ipv6.enabled && !xi->ipv6.enabled)
+                               lde_route_update_release(iface, AF_INET6);
+
+                       /* if we are adding lpd config for an address
+                        * family on an interface then add proper labels
+                        */
+                       if (!iface->ipv4.enabled && xi->ipv4.enabled)
+                               lde_route_update(iface, AF_INET);
+                       if (!iface->ipv6.enabled && xi->ipv6.enabled)
+                               lde_route_update(iface, AF_INET6);
+               }
+
                /* update existing interfaces */
                merge_iface_af(&iface->ipv4, &xi->ipv4);
                merge_iface_af(&iface->ipv6, &xi->ipv6);
index 655313bf163b0bdf41229a8b87f4d60ecc0d5253..9078e711fbbb19742acbe4256b59e30ce1161774 100644 (file)
@@ -614,10 +614,8 @@ ldpe_dispatch_lde(struct thread *thread)
                        map = imsg.data;
 
                        nbr = nbr_find_peerid(imsg.hdr.peerid);
-                       if (nbr == NULL) {
-                               log_debug("ldpe_dispatch_lde: cannot find neighbor");
+                       if (nbr == NULL)
                                break;
-                       }
                        if (nbr->state != NBR_STA_OPER)
                                break;
 
@@ -641,10 +639,8 @@ ldpe_dispatch_lde(struct thread *thread)
                case IMSG_REQUEST_ADD_END:
                case IMSG_WITHDRAW_ADD_END:
                        nbr = nbr_find_peerid(imsg.hdr.peerid);
-                       if (nbr == NULL) {
-                               log_debug("ldpe_dispatch_lde: cannot find neighbor");
+                       if (nbr == NULL)
                                break;
-                       }
                        if (nbr->state != NBR_STA_OPER)
                                break;
 
index 8922a3666427105521495b1967b464ca049a0373..74bd7aae3e159a3e8e6182548e84247b35da8e03 100644 (file)
@@ -72,8 +72,7 @@ extern "C" {
 /* Maximum # labels that can be pushed. */
 #define MPLS_MAX_LABELS                    16
 
-#define IS_MPLS_RESERVED_LABEL(label)                                          \
-       (label >= MPLS_LABEL_RESERVED_MIN && label <= MPLS_LABEL_RESERVED_MAX)
+#define IS_MPLS_RESERVED_LABEL(label) (label <= MPLS_LABEL_RESERVED_MAX)
 
 #define IS_MPLS_UNRESERVED_LABEL(label)                                        \
        (label >= MPLS_LABEL_UNRESERVED_MIN                                    \