From 955357174f5eae2e28f0ce58a4dc55f530ce87c6 Mon Sep 17 00:00:00 2001 From: lynne Date: Wed, 12 Aug 2020 19:15:24 -0400 Subject: [PATCH] ldpd: Fix issue when starting up LDP with no configuration. 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 --- ldpd/lde.c | 158 +++++++++++++++++++++++++++++++++++++++++++- ldpd/lde.h | 3 + ldpd/lde_lib.c | 20 ++++-- ldpd/ldp_vty_cmds.c | 2 + ldpd/ldpd.c | 43 +++++++++++- ldpd/ldpe.c | 8 +-- lib/mpls.h | 3 +- 7 files changed, 222 insertions(+), 15 deletions(-) diff --git a/ldpd/lde.c b/ldpd/lde.c index 734c1ea230..df64f908ea 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -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); + } + } +} diff --git a/ldpd/lde.h b/ldpd/lde.h index 9e6db3a90b..660aeafb34 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -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 *); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index 11d85b7449..bed276c7b1 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -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; diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c index fc84c7f76b..53a384fe55 100644 --- a/ldpd/ldp_vty_cmds.c +++ b/ldpd/ldp_vty_cmds.c @@ -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) diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 927c3a3c03..dca379e4eb 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -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); diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 655313bf16..9078e711fb 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -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; diff --git a/lib/mpls.h b/lib/mpls.h index 8922a36664..74bd7aae3e 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -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 \ -- 2.39.5