diff options
| author | lynne <lynne@voltanet.io> | 2020-08-12 19:15:24 -0400 | 
|---|---|---|
| committer | lynne <lynne@voltanet.io> | 2020-09-04 09:24:47 -0400 | 
| commit | 955357174f5eae2e28f0ce58a4dc55f530ce87c6 (patch) | |
| tree | 3478b02cf06fc3e1f3cdf08e1412a76e84fb97f3 | |
| parent | ee7d41a4373a1598eb1accb98d3ff2f334fceb81 (diff) | |
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>
| -rw-r--r-- | ldpd/lde.c | 158 | ||||
| -rw-r--r-- | ldpd/lde.h | 3 | ||||
| -rw-r--r-- | ldpd/lde_lib.c | 20 | ||||
| -rw-r--r-- | ldpd/ldp_vty_cmds.c | 2 | ||||
| -rw-r--r-- | ldpd/ldpd.c | 43 | ||||
| -rw-r--r-- | ldpd/ldpe.c | 8 | ||||
| -rw-r--r-- | 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                                    \  | 
