diff options
| author | Anton Degtyarev <adeg47@gmail.com> | 2018-11-14 06:14:04 +0300 | 
|---|---|---|
| committer | Anton Degtyarev <adeg47@gmail.com> | 2018-12-20 15:28:52 +0300 | 
| commit | 57592a53b5c02094f915a8444d40d2361d31e972 (patch) | |
| tree | 4948c69d7951e9dc0008e110f9d7d489a8c3f742 /bgpd | |
| parent | f944fe9b004be9c6076f2fed3004a85fc284cad1 (diff) | |
bgpd, zebra: auto assign labels from label pool to regular prefixes in BGP labeled unicast
This commit is the last missing piece to complete BGP LU support in bgpd. To this moment, bgpd (and zebra) supported auto label assignment only for prefixes leaked from VRFs to vpn and for MPLS SR prefixes. This adds auto label assignment to other routes types in bgpd. The following enhancements have been made:
* bgp_route.c:bgp_process_main_one() now sets implicit-null local_label to all local, aggregate and redistributed routes.
* bgp_route.c:bgp_process_main_one() now will request a label from the label pool for any prefix that loses the label for some reason (for example, when the static label assignment config is removed)
* bgp_label.c:bgp_reg_dereg_for_label() now requests labels from label pool for routes which have no associated label index
* zebra_mpls.c:zebra_mpls_fec_register() now expects both label and label_index from the calling function, one of which must be set to MPLS_INVALID_LABEL or MPLS_INVALID_LABEL_INDEX, based on this it will decide how to register the provided FEC.
Signed-off-by: Anton Degtyarev <anton@cumulusnetworks.com>
Diffstat (limited to 'bgpd')
| -rw-r--r-- | bgpd/bgp_label.c | 137 | ||||
| -rw-r--r-- | bgpd/bgp_label.h | 8 | ||||
| -rw-r--r-- | bgpd/bgp_labelpool.h | 1 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 22 | 
4 files changed, 149 insertions, 19 deletions
diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index dcaaea6868..a219c407da 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -120,20 +120,141 @@ mpls_label_t bgp_adv_label(struct bgp_node *rn, struct bgp_path_info *pi,  	return rn->local_label;  } +/** + * This is passed as the callback function to bgp_labelpool.c:bgp_lp_get() + * by bgp_reg_dereg_for_label() when a label needs to be obtained from + * label pool. + * Note that it will reject the allocated label if a label index is found, + * because the label index supposes predictable labels + */ +int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid, +			       bool allocated) +{ +	struct bgp_path_info *pi = (struct bgp_path_info *)labelid; +	struct bgp_node *rn = (struct bgp_node *)pi->net; +	char addr[PREFIX_STRLEN]; + +	prefix2str(&rn->p, addr, PREFIX_STRLEN); + +	if (BGP_DEBUG(labelpool, LABELPOOL)) +		zlog_debug("%s: FEC %s label=%u, allocated=%d", __func__, addr, +			   new_label, allocated); + +	if (!allocated) { +		/* +		 * previously-allocated label is now invalid +		 */ +		if (pi->attr->label_index == MPLS_INVALID_LABEL_INDEX +		    && pi->attr->label != MPLS_LABEL_NONE +		    && CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) { +			bgp_unregister_for_label(rn); +			label_ntop(MPLS_LABEL_IMPLICIT_NULL, 1, +				   &rn->local_label); +			bgp_set_valid_label(&rn->local_label); +		} +		return 0; +	} + +	/* +	 * label index is assigned, this should be handled by SR-related code, +	 * so retry FEC registration and then reject label allocation for +	 * it to be released to label pool +	 */ +	if (pi->attr->label_index != MPLS_INVALID_LABEL_INDEX) { +		flog_err( +			EC_BGP_LABEL, +			"%s: FEC %s Rejecting allocated label %u as Label Index is %u", +			__func__, addr, new_label, pi->attr->label_index); + +		bgp_register_for_label(pi->net, pi); + +		return -1; +	} + +	if (pi->attr->label != MPLS_INVALID_LABEL) { +		if (new_label == pi->attr->label) { +			/* already have same label, accept but do nothing */ +			return 0; +		} +		/* Shouldn't happen: different label allocation */ +		flog_err(EC_BGP_LABEL, +			 "%s: %s had label %u but got new assignment %u", +			 __func__, addr, pi->attr->label, new_label); +		/* continue means use new one */ +	} + +	label_ntop(new_label, 1, &rn->local_label); +	bgp_set_valid_label(&rn->local_label); + +	/* +	 * Get back to registering the FEC +	 */ +	bgp_register_for_label(pi->net, pi); + +	return 0; +} +  void bgp_reg_dereg_for_label(struct bgp_node *rn, struct bgp_path_info *pi, -			     int reg) +			     bool reg)  { +	bool with_label_index = false;  	struct stream *s;  	struct prefix *p; +	mpls_label_t *local_label;  	int command;  	uint16_t flags = 0;  	size_t flags_pos = 0; +	char addr[PREFIX_STRLEN]; + +	p = &(rn->p); +	local_label = &(rn->local_label); +	/* this prevents the loop when we're called by +	 * bgp_reg_for_label_callback() +	 */ +	bool have_label_to_reg = bgp_is_valid_label(local_label) +			&& label_pton(local_label) != MPLS_LABEL_IMPLICIT_NULL; + +	if (reg) { +		assert(pi); +		/* +		 * Determine if we will let zebra should derive label from +		 * label index instead of bgpd requesting from label pool +		 */ +		if (CHECK_FLAG(pi->attr->flag, +			    ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) +			&& pi->attr->label_index != BGP_INVALID_LABEL_INDEX) { +			with_label_index = true; +		} else { +			/* +			 * If no label index was provided -- assume any label +			 * from label pool will do. This means that label index +			 * always takes precedence over auto-assigned labels. +			 */ +			if (!have_label_to_reg) { +				if (BGP_DEBUG(labelpool, LABELPOOL)) { +					prefix2str(p, addr, PREFIX_STRLEN); +					zlog_debug("%s: Requesting label from LP for %s", +						 __func__, addr); +				} +				/* bgp_reg_for_label_callback() will call back +				 * __func__ when it gets a label from the pool. +				 * This means we'll never register FECs without +				 * valid labels. +				 */ +				bgp_lp_get(LP_TYPE_BGP_LU, pi, +				    bgp_reg_for_label_callback); +				return; +			} +		} +	}  	/* Check socket. */  	if (!zclient || zclient->sock < 0)  		return; -	p = &(rn->p); +	/* If the route node has a local_label assigned or the +	 * path node has an MPLS SR label index allowing zebra to +	 * derive the label, proceed with registration. */  	s = zclient->obuf;  	stream_reset(s);  	command = (reg) ? ZEBRA_FEC_REGISTER : ZEBRA_FEC_UNREGISTER; @@ -143,12 +264,12 @@ void bgp_reg_dereg_for_label(struct bgp_node *rn, struct bgp_path_info *pi,  	stream_putw(s, PREFIX_FAMILY(p));  	stream_put_prefix(s, p);  	if (reg) { -		assert(pi); -		if (pi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) { -			if (pi->attr->label_index != BGP_INVALID_LABEL_INDEX) { -				flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX; -				stream_putl(s, pi->attr->label_index); -			} +		if (have_label_to_reg) { +			flags |= ZEBRA_FEC_REGISTER_LABEL; +			stream_putl(s, label_pton(local_label)); +		} else if (with_label_index) { +			flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX; +			stream_putl(s, pi->attr->label_index);  		}  		SET_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);  	} else diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h index b0fc07e547..89bc9aabb0 100644 --- a/bgpd/bgp_label.h +++ b/bgpd/bgp_label.h @@ -30,8 +30,10 @@ struct bgp_node;  struct bgp_path_info;  struct peer; +extern int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid, +				    bool allocated);  extern void bgp_reg_dereg_for_label(struct bgp_node *rn, -				    struct bgp_path_info *pi, int reg); +				    struct bgp_path_info *pi, bool reg);  extern int bgp_parse_fec_update(void);  extern mpls_label_t bgp_adv_label(struct bgp_node *rn, struct bgp_path_info *pi,  				  struct peer *to, afi_t afi, safi_t safi); @@ -87,12 +89,12 @@ static inline void bgp_unset_valid_label(mpls_label_t *label)  static inline void bgp_register_for_label(struct bgp_node *rn,  					  struct bgp_path_info *pi)  { -	bgp_reg_dereg_for_label(rn, pi, 1); +	bgp_reg_dereg_for_label(rn, pi, true);  }  static inline void bgp_unregister_for_label(struct bgp_node *rn)  { -	bgp_reg_dereg_for_label(rn, NULL, 0); +	bgp_reg_dereg_for_label(rn, NULL, false);  }  /* Label stream to value */ diff --git a/bgpd/bgp_labelpool.h b/bgpd/bgp_labelpool.h index fa35cde0e1..0507e65489 100644 --- a/bgpd/bgp_labelpool.h +++ b/bgpd/bgp_labelpool.h @@ -29,6 +29,7 @@   * Types used in bgp_lp_get for debug tracking; add more as needed   */  #define LP_TYPE_VRF	0x00000001 +#define LP_TYPE_BGP_LU	0x00000002  struct labelpool {  	struct skiplist		*ledger;	/* all requests */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 23002fb74c..2c361bef4d 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2265,20 +2265,26 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,  	/* Do we need to allocate or free labels?  	 * Right now, since we only deal with per-prefix labels, it is not -	 * necessary to do this upon changes to best path except if the label -	 * index changes +	 * necessary to do this upon changes to best path. Exceptions: +	 * - label index has changed -> recalculate resulting label +	 * - path_info sub_type changed -> switch to/from implicit-null +	 * - no valid label (due to removed static label binding) -> get new one  	 */  	if (bgp->allocate_mpls_labels[afi][safi]) {  		if (new_select) {  			if (!old_select  			    || bgp_label_index_differs(new_select, old_select) -			    || new_select->sub_type != old_select->sub_type) { +			    || new_select->sub_type != old_select->sub_type +			    || !bgp_is_valid_label(&rn->local_label)) { +				/* Enforced penultimate hop popping: +				 * implicit-null for local routes, aggregate +				 * and redistributed routes +				 */  				if (new_select->sub_type == BGP_ROUTE_STATIC -				    && new_select->attr->flag -					       & ATTR_FLAG_BIT( -							 BGP_ATTR_PREFIX_SID) -				    && new_select->attr->label_index -					       != BGP_INVALID_LABEL_INDEX) { +				    || new_select->sub_type +						== BGP_ROUTE_AGGREGATE +				    || new_select->sub_type +						== BGP_ROUTE_REDISTRIBUTE) {  					if (CHECK_FLAG(  						    rn->flags,  						    BGP_NODE_REGISTERED_FOR_LABEL))  | 
