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 <lynne@voltanet.io>
This commit is contained in:
lynne 2020-08-12 19:15:24 -04:00
parent ee7d41a437
commit 955357174f
7 changed files with 222 additions and 15 deletions

View File

@ -468,6 +468,10 @@ lde_dispatch_parent(struct thread *thread)
iface = if_lookup_name(ldeconf, kif->ifname); iface = if_lookup_name(ldeconf, kif->ifname);
if (iface) { if (iface) {
if_update_info(iface, kif); 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; break;
} }
@ -786,7 +790,6 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
kr.remote_label = fnh->remote_label; kr.remote_label = fnh->remote_label;
kr.route_type = fnh->route_type; kr.route_type = fnh->route_type;
kr.route_instance = fnh->route_instance; kr.route_instance = fnh->route_instance;
lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr, lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
sizeof(kr)); sizeof(kr));
break; 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) if (strcmp(af_conf->acl_label_expnull_for, filter_name) == 0)
lde_change_expnull_for_filter(af); 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);
}
}
}

View File

@ -193,6 +193,9 @@ void lde_change_allocate_filter(int);
void lde_change_advertise_filter(int); void lde_change_advertise_filter(int);
void lde_change_accept_filter(int); void lde_change_accept_filter(int);
void lde_change_expnull_for_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, struct lde_addr *lde_address_find(struct lde_nbr *, int,
union ldpd_addr *); union ldpd_addr *);

View File

@ -404,10 +404,15 @@ lde_kernel_update(struct fec *fec)
* if LDP configured on interface or a static route * if LDP configured on interface or a static route
* clear flag else treat fec as a connected route * clear flag else treat fec as a connected route
*/ */
iface = if_lookup(ldeconf,fnh->ifindex); if (ldeconf->flags & F_LDPD_ENABLED) {
if (iface || fnh->route_type == ZEBRA_ROUTE_STATIC) iface = if_lookup(ldeconf,fnh->ifindex);
fnh->flags &=~F_FEC_NH_NO_LDP; if (fnh->flags & F_FEC_NH_CONNECTED ||
else 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; fnh->flags |= F_FEC_NH_NO_LDP;
} else { } else {
lde_send_delete_klabel(fn, fnh); lde_send_delete_klabel(fn, fnh);
@ -437,6 +442,10 @@ lde_kernel_update(struct fec *fec)
lde_send_labelmapping(ln, fn, 1); 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) { LIST_FOREACH(fnh, &fn->nexthops, entry) {
lde_send_change_klabel(fn, fnh); 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->flags &= ~F_FEC_NH_DEFER;
} }
fnh->remote_label = map->label; fnh->remote_label = map->label;
lde_send_change_klabel(fn, fnh); if (fn->local_label != NO_LABEL)
lde_send_change_klabel(fn, fnh);
break; break;
case FEC_TYPE_PWID: case FEC_TYPE_PWID:
pw = (struct l2vpn_pw *) fn->data; pw = (struct l2vpn_pw *) fn->data;

View File

@ -616,6 +616,8 @@ DEFPY (ldp_show_mpls_ldp_binding,
"Show detailed information\n" "Show detailed information\n"
JSON_STR) JSON_STR)
{ {
if (!(ldpd_conf->flags & F_LDPD_ENABLED))
return CMD_SUCCESS;
if (!local_label_str) if (!local_label_str)
local_label = NO_LABEL; local_label = NO_LABEL;
if (!remote_label_str) if (!remote_label_str)

View 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_ipv4 = 0;
int reset_nbrs = 0; int reset_nbrs = 0;
int update_sockets = 0; int update_sockets = 0;
int change_ldp_disabled = 0;
/* update timers */ /* update timers */
if (af_conf->keepalive != xa->keepalive) { 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)) != (xa->flags & F_LDPD_AF_ALLOCHOSTONLY))
change_host_label = 1; 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; af_conf->flags = xa->flags;
/* update the transport address */ /* 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); lde_change_egress_label(af);
if (change_host_label) if (change_host_label)
lde_change_allocate_filter(af); lde_change_allocate_filter(af);
if (change_ldp_disabled)
lde_route_update_release_all(af);
break; break;
case PROC_LDP_ENGINE: case PROC_LDP_ENGINE:
if (stop_init_backoff) if (stop_init_backoff)
@ -1434,13 +1443,22 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)
struct iface *iface, *itmp, *xi; struct iface *iface, *itmp, *xi;
RB_FOREACH_SAFE(iface, iface_head, &conf->iface_tree, itmp) { 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) { if (if_lookup_name(xconf, iface->name) == NULL) {
switch (ldpd_process) { switch (ldpd_process) {
case PROC_LDP_ENGINE: case PROC_LDP_ENGINE:
ldpe_if_exit(iface); ldpe_if_exit(iface);
break; break;
case PROC_LDE_ENGINE: 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: case PROC_MAIN:
break; break;
} }
@ -1468,6 +1486,29 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)
continue; 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 */ /* update existing interfaces */
merge_iface_af(&iface->ipv4, &xi->ipv4); merge_iface_af(&iface->ipv4, &xi->ipv4);
merge_iface_af(&iface->ipv6, &xi->ipv6); merge_iface_af(&iface->ipv6, &xi->ipv6);

View File

@ -614,10 +614,8 @@ ldpe_dispatch_lde(struct thread *thread)
map = imsg.data; map = imsg.data;
nbr = nbr_find_peerid(imsg.hdr.peerid); nbr = nbr_find_peerid(imsg.hdr.peerid);
if (nbr == NULL) { if (nbr == NULL)
log_debug("ldpe_dispatch_lde: cannot find neighbor");
break; break;
}
if (nbr->state != NBR_STA_OPER) if (nbr->state != NBR_STA_OPER)
break; break;
@ -641,10 +639,8 @@ ldpe_dispatch_lde(struct thread *thread)
case IMSG_REQUEST_ADD_END: case IMSG_REQUEST_ADD_END:
case IMSG_WITHDRAW_ADD_END: case IMSG_WITHDRAW_ADD_END:
nbr = nbr_find_peerid(imsg.hdr.peerid); nbr = nbr_find_peerid(imsg.hdr.peerid);
if (nbr == NULL) { if (nbr == NULL)
log_debug("ldpe_dispatch_lde: cannot find neighbor");
break; break;
}
if (nbr->state != NBR_STA_OPER) if (nbr->state != NBR_STA_OPER)
break; break;

View File

@ -72,8 +72,7 @@ extern "C" {
/* Maximum # labels that can be pushed. */ /* Maximum # labels that can be pushed. */
#define MPLS_MAX_LABELS 16 #define MPLS_MAX_LABELS 16
#define IS_MPLS_RESERVED_LABEL(label) \ #define IS_MPLS_RESERVED_LABEL(label) (label <= MPLS_LABEL_RESERVED_MAX)
(label >= MPLS_LABEL_RESERVED_MIN && label <= MPLS_LABEL_RESERVED_MAX)
#define IS_MPLS_UNRESERVED_LABEL(label) \ #define IS_MPLS_UNRESERVED_LABEL(label) \
(label >= MPLS_LABEL_UNRESERVED_MIN \ (label >= MPLS_LABEL_UNRESERVED_MIN \