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);
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);
}
}
}

View 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 *);

View 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;

View 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)

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 = 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);

View 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;

View 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 \