diff options
| author | Russ White <russ@riw.us> | 2021-09-21 11:36:53 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-09-21 11:36:53 -0400 | 
| commit | 2075387e77c06218eebcee597664f09c3724781e (patch) | |
| tree | 0d0015c2c72193f336ab68f75d2244849c39d634 /bgpd | |
| parent | 48f23c8879754262b359fb7cc1a9cdf43ed574a7 (diff) | |
| parent | 242302ffb2edebd250a7ab10533ba08e0babc59d (diff) | |
Merge pull request #9546 from proelbtn/add-support-for-perfix-sid-type-5
Add support for Prefix-SID (Type 5)
Diffstat (limited to 'bgpd')
| -rw-r--r-- | bgpd/bgp_attr.c | 247 | ||||
| -rw-r--r-- | bgpd/bgp_attr.h | 23 | ||||
| -rw-r--r-- | bgpd/bgp_mplsvpn.c | 101 | ||||
| -rw-r--r-- | bgpd/bgp_mplsvpn.h | 2 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 65 | ||||
| -rw-r--r-- | bgpd/bgp_route.h | 10 | ||||
| -rw-r--r-- | bgpd/bgp_zebra.c | 5 | ||||
| -rw-r--r-- | bgpd/bgpd.h | 1 | ||||
| -rw-r--r-- | bgpd/rfapi/rfapi_vty.c | 12 | 
9 files changed, 398 insertions, 68 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index eeb0ac5c6a..7de7a6628f 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -530,6 +530,12 @@ static uint32_t srv6_l3vpn_hash_key_make(const void *p)  	key = jhash(&l3vpn->sid, 16, key);  	key = jhash_1word(l3vpn->sid_flags, key);  	key = jhash_1word(l3vpn->endpoint_behavior, key); +	key = jhash_1word(l3vpn->loc_block_len, key); +	key = jhash_1word(l3vpn->loc_node_len, key); +	key = jhash_1word(l3vpn->func_len, key); +	key = jhash_1word(l3vpn->arg_len, key); +	key = jhash_1word(l3vpn->transposition_len, key); +	key = jhash_1word(l3vpn->transposition_offset, key);  	return key;  } @@ -540,7 +546,13 @@ static bool srv6_l3vpn_hash_cmp(const void *p1, const void *p2)  	return sid_same(&l3vpn1->sid, &l3vpn2->sid)  	       && l3vpn1->sid_flags == l3vpn2->sid_flags -	       && l3vpn1->endpoint_behavior == l3vpn2->endpoint_behavior; +	       && l3vpn1->endpoint_behavior == l3vpn2->endpoint_behavior +	       && l3vpn1->loc_block_len == l3vpn2->loc_block_len +	       && l3vpn1->loc_node_len == l3vpn2->loc_node_len +	       && l3vpn1->func_len == l3vpn2->func_len +	       && l3vpn1->arg_len == l3vpn2->arg_len +	       && l3vpn1->transposition_len == l3vpn2->transposition_len +	       && l3vpn1->transposition_offset == l3vpn2->transposition_offset;  }  static bool srv6_l3vpn_same(const struct bgp_attr_srv6_l3vpn *h1, @@ -2533,6 +2545,172 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */  	return 0;  } + +/* SRv6 Service Data Sub-Sub-TLV attribute + * draft-ietf-bess-srv6-services-07 + */ +static bgp_attr_parse_ret_t +bgp_attr_srv6_service_data(struct bgp_attr_parser_args *args) +{ +	struct peer *const peer = args->peer; +	struct attr *const attr = args->attr; +	uint8_t type, loc_block_len, loc_node_len, func_len, arg_len, +		transposition_len, transposition_offset; +	uint16_t length; +	size_t headersz = sizeof(type) + sizeof(length); + +	if (STREAM_READABLE(peer->curr) < headersz) { +		flog_err( +			EC_BGP_ATTR_LEN, +			"Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)", +			headersz, STREAM_READABLE(peer->curr)); +		return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, +					  args->total); +	} + +	type = stream_getc(peer->curr); +	length = stream_getw(peer->curr); + +	if (STREAM_READABLE(peer->curr) < length) { +		flog_err( +			EC_BGP_ATTR_LEN, +			"Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)", +			length, STREAM_READABLE(peer->curr)); +		return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, +					  args->total); +	} + +	if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE) { +		loc_block_len = stream_getc(peer->curr); +		loc_node_len = stream_getc(peer->curr); +		func_len = stream_getc(peer->curr); +		arg_len = stream_getc(peer->curr); +		transposition_len = stream_getc(peer->curr); +		transposition_offset = stream_getc(peer->curr); + +		/* Log SRv6 Service Data Sub-Sub-TLV */ +		if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) { +			zlog_debug( +				"%s: srv6-l3-srv-data loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u, transposition-len=%u, transposition-offset=%u", +				__func__, loc_block_len, loc_node_len, func_len, +				arg_len, transposition_len, +				transposition_offset); +		} + +		attr->srv6_l3vpn->loc_block_len = loc_block_len; +		attr->srv6_l3vpn->loc_node_len = loc_node_len; +		attr->srv6_l3vpn->func_len = func_len; +		attr->srv6_l3vpn->arg_len = arg_len; +		attr->srv6_l3vpn->transposition_len = transposition_len; +		attr->srv6_l3vpn->transposition_offset = transposition_offset; +	} + +	else { +		if (bgp_debug_update(peer, NULL, NULL, 1)) +			zlog_debug( +				"%s attr SRv6 Service Data Sub-Sub-TLV sub-sub-type=%u is not supported, skipped", +				peer->host, type); + +		stream_forward_getp(peer->curr, length); +	} + +	return BGP_ATTR_PARSE_PROCEED; +} + +/* SRv6 Service Sub-TLV attribute + * draft-ietf-bess-srv6-services-07 + */ +static bgp_attr_parse_ret_t +bgp_attr_srv6_service(struct bgp_attr_parser_args *args) +{ +	struct peer *const peer = args->peer; +	struct attr *const attr = args->attr; +	struct in6_addr ipv6_sid; +	uint8_t type, sid_flags; +	uint16_t length, endpoint_behavior; +	size_t headersz = sizeof(type) + sizeof(length); +	bgp_attr_parse_ret_t err; +	char buf[BUFSIZ]; + +	if (STREAM_READABLE(peer->curr) < headersz) { +		flog_err( +			EC_BGP_ATTR_LEN, +			"Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)", +			headersz, STREAM_READABLE(peer->curr)); +		return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, +					  args->total); +	} + +	type = stream_getc(peer->curr); +	length = stream_getw(peer->curr); + +	if (STREAM_READABLE(peer->curr) < length) { +		flog_err( +			EC_BGP_ATTR_LEN, +			"Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)", +			length, STREAM_READABLE(peer->curr)); +		return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, +					  args->total); +	} + +	if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO) { +		stream_getc(peer->curr); +		stream_get(&ipv6_sid, peer->curr, sizeof(ipv6_sid)); +		sid_flags = stream_getc(peer->curr); +		endpoint_behavior = stream_getw(peer->curr); +		stream_getc(peer->curr); + +		/* Log SRv6 Service Sub-TLV */ +		if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) { +			inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf)); +			zlog_debug( +				"%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x", +				__func__, buf, sid_flags, endpoint_behavior); +		} + +		/* Configure from Info */ +		if (attr->srv6_l3vpn) { +			flog_err(EC_BGP_ATTRIBUTE_REPEATED, +				 "Prefix SID SRv6 L3VPN field repeated"); +			return bgp_attr_malformed( +				args, BGP_NOTIFY_UPDATE_MAL_ATTR, args->total); +		} +		attr->srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN, +					   sizeof(struct bgp_attr_srv6_l3vpn)); +		sid_copy(&attr->srv6_l3vpn->sid, &ipv6_sid); +		attr->srv6_l3vpn->sid_flags = sid_flags; +		attr->srv6_l3vpn->endpoint_behavior = endpoint_behavior; +		attr->srv6_l3vpn->loc_block_len = 0; +		attr->srv6_l3vpn->loc_node_len = 0; +		attr->srv6_l3vpn->func_len = 0; +		attr->srv6_l3vpn->arg_len = 0; +		attr->srv6_l3vpn->transposition_len = 0; +		attr->srv6_l3vpn->transposition_offset = 0; + +		// Sub-Sub-TLV found +		if (length > BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH) { +			err = bgp_attr_srv6_service_data(args); + +			if (err != BGP_ATTR_PARSE_PROCEED) +				return err; +		} + +		attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn); +	} + +	/* Placeholder code for unsupported type */ +	else { +		if (bgp_debug_update(peer, NULL, NULL, 1)) +			zlog_debug( +				"%s attr SRv6 Service Sub-TLV sub-type=%u is not supported, skipped", +				peer->host, type); + +		stream_forward_getp(peer->curr, length); +	} + +	return BGP_ATTR_PARSE_PROCEED; +} +  /*   * Read an individual SID value returning how much data we have read   * Returns 0 if there was an error that needs to be passed up the stack @@ -2548,7 +2726,6 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,  	uint32_t srgb_range;  	int srgb_count;  	uint8_t sid_type, sid_flags; -	uint16_t endpoint_behavior;  	char buf[BUFSIZ];  	if (type == BGP_PREFIX_SID_LABEL_INDEX) { @@ -2703,45 +2880,20 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,  	/* Placeholder code for the SRv6 L3 Service type */  	else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE) { -		if (STREAM_READABLE(peer->curr) < length -		    || length != BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH) { -			flog_err(EC_BGP_ATTR_LEN, -				 "Prefix SID SRv6 L3-Service length is %hu instead of %u", -				 length, BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH); +		if (STREAM_READABLE(peer->curr) < length) { +			flog_err( +				EC_BGP_ATTR_LEN, +				"Prefix SID SRv6 L3-Service length is %hu, but only %zu bytes remain", +				length, STREAM_READABLE(peer->curr));  			return bgp_attr_malformed(args,  				 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,  				 args->total);  		} -		/* Parse L3-SERVICE Sub-TLV */ -		stream_getc(peer->curr);               /* reserved  */ -		stream_get(&ipv6_sid, peer->curr, -			   sizeof(ipv6_sid)); /* sid_value */ -		sid_flags = stream_getc(peer->curr);   /* sid_flags */ -		endpoint_behavior = stream_getw(peer->curr); /* endpoint */ -		stream_getc(peer->curr);               /* reserved  */ - -		/* Log L3-SERVICE Sub-TLV */ -		if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) { -			inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf)); -			zlog_debug( -				"%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x", -				__func__, buf, sid_flags, endpoint_behavior); -		} +		/* ignore reserved */ +		stream_getc(peer->curr); -		/* Configure from Info */ -		if (attr->srv6_l3vpn) { -			flog_err(EC_BGP_ATTRIBUTE_REPEATED, -				 "Prefix SID SRv6 L3VPN field repeated"); -			return bgp_attr_malformed( -				args, BGP_NOTIFY_UPDATE_MAL_ATTR, args->total); -		} -		attr->srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN, -					   sizeof(struct bgp_attr_srv6_l3vpn)); -		attr->srv6_l3vpn->sid_flags = sid_flags; -		attr->srv6_l3vpn->endpoint_behavior = endpoint_behavior; -		sid_copy(&attr->srv6_l3vpn->sid, &ipv6_sid); -		attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn); +		return bgp_attr_srv6_service(args);  	}  	/* Placeholder code for Unsupported TLV */ @@ -4123,18 +4275,39 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,  	/* SRv6 Service Information Attribute. */  	if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_MPLS_VPN) {  		if (attr->srv6_l3vpn) { +			uint8_t subtlv_len = +				BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH +				+ BGP_ATTR_MIN_LEN +				+ BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH; +			uint8_t tlv_len = subtlv_len + BGP_ATTR_MIN_LEN + 1; +			uint8_t attr_len = tlv_len + BGP_ATTR_MIN_LEN;  			stream_putc(s, BGP_ATTR_FLAG_OPTIONAL  					       | BGP_ATTR_FLAG_TRANS);  			stream_putc(s, BGP_ATTR_PREFIX_SID); -			stream_putc(s, 24);     /* tlv len */ +			stream_putc(s, attr_len);  			stream_putc(s, BGP_PREFIX_SID_SRV6_L3_SERVICE); -			stream_putw(s, 21);     /* sub-tlv len */ +			stream_putw(s, tlv_len); +			stream_putc(s, 0); /* reserved */ +			stream_putc(s, BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO); +			stream_putw(s, subtlv_len);  			stream_putc(s, 0);      /* reserved */  			stream_put(s, &attr->srv6_l3vpn->sid,  				   sizeof(attr->srv6_l3vpn->sid)); /* sid */  			stream_putc(s, 0);      /* sid_flags */  			stream_putw(s, 0xffff); /* endpoint */  			stream_putc(s, 0);      /* reserved */ +			stream_putc( +				s, +				BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE); +			stream_putw( +				s, +				BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH); +			stream_putc(s, attr->srv6_l3vpn->loc_block_len); +			stream_putc(s, attr->srv6_l3vpn->loc_node_len); +			stream_putc(s, attr->srv6_l3vpn->func_len); +			stream_putc(s, attr->srv6_l3vpn->arg_len); +			stream_putc(s, attr->srv6_l3vpn->transposition_len); +			stream_putc(s, attr->srv6_l3vpn->transposition_offset);  		} else if (attr->srv6_vpn) {  			stream_putc(s, BGP_ATTR_FLAG_OPTIONAL  					       | BGP_ATTR_FLAG_TRANS); diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 6c49cf509f..3573c2ae03 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -71,7 +71,22 @@  #define BGP_PREFIX_SID_IPV6_LENGTH            19  #define BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH  6  #define BGP_PREFIX_SID_VPN_SID_LENGTH         19 -#define BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH 21 + +/* SRv6 Service Sub-TLV types */ +#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO 1 +#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH 21 + +/* SRv6 Service Data Sub-Sub-TLV types */ +#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE 1 +#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH 6 + +/* SRv6 SID Structure default values */ +#define BGP_PREFIX_SID_SRV6_LOCATOR_BLOCK_LENGTH 40 +#define BGP_PREFIX_SID_SRV6_LOCATOR_NODE_LENGTH 24 +#define BGP_PREFIX_SID_SRV6_FUNCTION_LENGTH 16 +#define BGP_PREFIX_SID_SRV6_ARGUMENT_LENGTH 0 +#define BGP_PREFIX_SID_SRV6_TRANSPOSITION_LENGTH 16 +#define BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET 64  #define BGP_ATTR_NH_AFI(afi, attr) \  	((afi != AFI_L2VPN) ? afi : \ @@ -136,6 +151,12 @@ struct bgp_attr_srv6_l3vpn {  	uint8_t sid_flags;  	uint16_t endpoint_behavior;  	struct in6_addr sid; +	uint8_t loc_block_len; +	uint8_t loc_node_len; +	uint8_t func_len; +	uint8_t arg_len; +	uint8_t transposition_len; +	uint8_t transposition_offset;  };  /* BGP core attribute structure. */ diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index b0bab02fb8..659029b04c 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -522,13 +522,14 @@ static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid)   * if index != 0: try to allocate as index-mode   * else: try to allocate as auto-mode   */ -static bool alloc_new_sid(struct bgp *bgp, uint32_t index, -			  struct in6_addr *sid) +static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index, +			      struct in6_addr *sid)  {  	struct listnode *node;  	struct prefix_ipv6 *chunk;  	struct in6_addr sid_buf;  	bool alloced = false; +	int label;  	if (!bgp || !sid)  		return false; @@ -536,7 +537,8 @@ static bool alloc_new_sid(struct bgp *bgp, uint32_t index,  	for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) {  		sid_buf = chunk->prefix;  		if (index != 0) { -			sid_buf.s6_addr[15] = index; +			label = index << 12; +			transpose_sid(&sid_buf, label, 64, 16);  			if (sid_exist(bgp, &sid_buf))  				return false;  			alloced = true; @@ -544,9 +546,8 @@ static bool alloc_new_sid(struct bgp *bgp, uint32_t index,  		}  		for (size_t i = 1; i < 255; i++) { -			sid_buf.s6_addr[15] = (i & 0xff00) >> 8; -			sid_buf.s6_addr[14] = (i & 0x00ff); - +			label = i << 12; +			transpose_sid(&sid_buf, label, 64, 16);  			if (sid_exist(bgp, &sid_buf))  				continue;  			alloced = true; @@ -555,20 +556,19 @@ static bool alloc_new_sid(struct bgp *bgp, uint32_t index,  	}  	if (!alloced) -		return false; +		return 0;  	sid_register(bgp, &sid_buf, bgp->srv6_locator_name);  	*sid = sid_buf; -	return true; +	return label;  }  void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)  {  	int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); -	bool alloced = false;  	char buf[256];  	struct in6_addr *sid; -	uint32_t tovpn_sid_index = 0; +	uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;  	bool tovpn_sid_auto = false;  	if (debug) @@ -602,8 +602,9 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)  	}  	sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr)); -	alloced = alloc_new_sid(bgp_vpn, tovpn_sid_index, sid); -	if (!alloced) { +	tovpn_sid_transpose_label = +		alloc_new_sid(bgp_vpn, tovpn_sid_index, sid); +	if (tovpn_sid_transpose_label == 0) {  		zlog_debug("%s: not allocated new sid for vrf %s: afi %s",  			   __func__, bgp_vrf->name_pretty, afi2str(afi));  		return; @@ -615,9 +616,22 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)  			   __func__, buf, bgp_vrf->name_pretty,  			   afi2str(afi));  	} +	bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label = +		tovpn_sid_transpose_label;  	bgp_vrf->vpn_policy[afi].tovpn_sid = sid;  } +void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset, +		   uint8_t len) +{ +	for (uint8_t idx = 0; idx < len; idx++) { +		uint8_t tidx = offset + idx; +		sid->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8)); +		if (label >> (19 - idx) & 0x1) +			sid->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8); +	} +} +  static bool ecom_intersect(struct ecommunity *e1, struct ecommunity *e2)  {  	uint32_t i, j; @@ -710,7 +724,7 @@ static void setsids(struct bgp_path_info *bpi,  	extra = bgp_path_info_extra_get(bpi);  	for (i = 0; i < num_sids; i++) -		memcpy(&extra->sid[i], &sid[i], sizeof(struct in6_addr)); +		memcpy(&extra->sid[i].sid, &sid[i], sizeof(struct in6_addr));  	extra->num_sids = num_sids;  } @@ -738,6 +752,7 @@ leak_update(struct bgp *bgp, /* destination bgp instance */  	struct bgp_path_info *bpi;  	struct bgp_path_info *bpi_ultimate;  	struct bgp_path_info *new; +	struct bgp_path_info_extra *extra;  	uint32_t num_sids = 0;  	if (new_attr->srv6_l3vpn || new_attr->srv6_vpn) @@ -824,10 +839,31 @@ leak_update(struct bgp *bgp, /* destination bgp instance */  		 * rewrite sid  		 */  		if (num_sids) { -			if (new_attr->srv6_l3vpn) +			if (new_attr->srv6_l3vpn) {  				setsids(bpi, &new_attr->srv6_l3vpn->sid,  					num_sids); -			else if (new_attr->srv6_vpn) + +				extra = bgp_path_info_extra_get(bpi); + +				extra->sid[0].loc_block_len = +					new_attr->srv6_l3vpn->loc_block_len; +				extra->sid[0].loc_node_len = +					new_attr->srv6_l3vpn->loc_node_len; +				extra->sid[0].func_len = +					new_attr->srv6_l3vpn->func_len; +				extra->sid[0].arg_len = +					new_attr->srv6_l3vpn->arg_len; + +				if (new_attr->srv6_l3vpn->transposition_len +				    != 0) +					transpose_sid( +						&extra->sid[0].sid, +						decode_label(label), +						new_attr->srv6_l3vpn +							->transposition_offset, +						new_attr->srv6_l3vpn +							->transposition_len); +			} else if (new_attr->srv6_vpn)  				setsids(bpi, &new_attr->srv6_vpn->sid,  					num_sids);  		} else @@ -910,9 +946,26 @@ leak_update(struct bgp *bgp, /* destination bgp instance */  	 * rewrite sid  	 */  	if (num_sids) { -		if (new_attr->srv6_l3vpn) +		if (new_attr->srv6_l3vpn) {  			setsids(new, &new_attr->srv6_l3vpn->sid, num_sids); -		else if (new_attr->srv6_vpn) + +			extra = bgp_path_info_extra_get(new); + +			extra->sid[0].loc_block_len = +				new_attr->srv6_l3vpn->loc_block_len; +			extra->sid[0].loc_node_len = +				new_attr->srv6_l3vpn->loc_node_len; +			extra->sid[0].func_len = new_attr->srv6_l3vpn->func_len; +			extra->sid[0].arg_len = new_attr->srv6_l3vpn->arg_len; + +			if (new_attr->srv6_l3vpn->transposition_len != 0) +				transpose_sid(&extra->sid[0].sid, +					      decode_label(label), +					      new_attr->srv6_l3vpn +						      ->transposition_offset, +					      new_attr->srv6_l3vpn +						      ->transposition_len); +		} else if (new_attr->srv6_vpn)  			setsids(new, &new_attr->srv6_vpn->sid, num_sids);  	} else  		unsetsids(new); @@ -1186,10 +1239,24 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn,	    /* to */  	/* Set SID for SRv6 VPN */  	if (bgp_vrf->vpn_policy[afi].tovpn_sid) { +		encode_label(bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label, +			     &label);  		static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,  				sizeof(struct bgp_attr_srv6_l3vpn));  		static_attr.srv6_l3vpn->sid_flags = 0x00;  		static_attr.srv6_l3vpn->endpoint_behavior = 0xffff; +		static_attr.srv6_l3vpn->loc_block_len = +			BGP_PREFIX_SID_SRV6_LOCATOR_BLOCK_LENGTH; +		static_attr.srv6_l3vpn->loc_node_len = +			BGP_PREFIX_SID_SRV6_LOCATOR_NODE_LENGTH; +		static_attr.srv6_l3vpn->func_len = +			BGP_PREFIX_SID_SRV6_FUNCTION_LENGTH; +		static_attr.srv6_l3vpn->arg_len = +			BGP_PREFIX_SID_SRV6_ARGUMENT_LENGTH; +		static_attr.srv6_l3vpn->transposition_len = +			BGP_PREFIX_SID_SRV6_TRANSPOSITION_LENGTH; +		static_attr.srv6_l3vpn->transposition_offset = +			BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET;  		memcpy(&static_attr.srv6_l3vpn->sid,  		       bgp_vrf->vpn_policy[afi].tovpn_sid,  		       sizeof(static_attr.srv6_l3vpn->sid)); diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index b0e0f74f77..b0d586223f 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -81,6 +81,8 @@ extern void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi);  extern void vpn_leak_zebra_vrf_sid_withdraw(struct bgp *bgp, afi_t afi);  extern int vpn_leak_label_callback(mpls_label_t label, void *lblid, bool alloc);  extern void ensure_vrf_tovpn_sid(struct bgp *vpn, struct bgp *vrf, afi_t afi); +extern void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset, +			  uint8_t size);  extern void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,  				afi_t afi, safi_t safi);  void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp, diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 5a16fecc26..647ad55306 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4042,15 +4042,48 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,  		/* Update SRv6 SID */  		if (attr->srv6_l3vpn) {  			extra = bgp_path_info_extra_get(pi); -			if (sid_diff(&extra->sid[0], &attr->srv6_l3vpn->sid)) { -				sid_copy(&extra->sid[0], +			if (sid_diff(&extra->sid[0].sid, +				     &attr->srv6_l3vpn->sid)) { +				sid_copy(&extra->sid[0].sid,  					 &attr->srv6_l3vpn->sid);  				extra->num_sids = 1; + +				extra->sid[0].loc_block_len = 0; +				extra->sid[0].loc_node_len = 0; +				extra->sid[0].func_len = 0; +				extra->sid[0].arg_len = 0; + +				if (attr->srv6_l3vpn->loc_block_len != 0) { +					extra->sid[0].loc_block_len = +						attr->srv6_l3vpn->loc_block_len; +					extra->sid[0].loc_node_len = +						attr->srv6_l3vpn->loc_node_len; +					extra->sid[0].func_len = +						attr->srv6_l3vpn->func_len; +					extra->sid[0].arg_len = +						attr->srv6_l3vpn->arg_len; +				} + +				/* +				 * draft-ietf-bess-srv6-services-07 +				 * The part of SRv6 SID may be encoded as MPLS +				 * Label for the efficient packing. +				 */ +				if (attr->srv6_l3vpn->transposition_len != 0) +					transpose_sid( +						&extra->sid[0].sid, +						decode_label(label), +						attr->srv6_l3vpn +							->transposition_offset, +						attr->srv6_l3vpn +							->transposition_len);  			}  		} else if (attr->srv6_vpn) {  			extra = bgp_path_info_extra_get(pi); -			if (sid_diff(&extra->sid[0], &attr->srv6_vpn->sid)) { -				sid_copy(&extra->sid[0], &attr->srv6_vpn->sid); +			if (sid_diff(&extra->sid[0].sid, +				     &attr->srv6_vpn->sid)) { +				sid_copy(&extra->sid[0].sid, +					 &attr->srv6_vpn->sid);  				extra->num_sids = 1;  			}  		} @@ -4231,10 +4264,28 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,  	if (safi == SAFI_MPLS_VPN) {  		extra = bgp_path_info_extra_get(new);  		if (attr->srv6_l3vpn) { -			sid_copy(&extra->sid[0], &attr->srv6_l3vpn->sid); +			sid_copy(&extra->sid[0].sid, &attr->srv6_l3vpn->sid);  			extra->num_sids = 1; + +			extra->sid[0].loc_block_len = +				attr->srv6_l3vpn->loc_block_len; +			extra->sid[0].loc_node_len = +				attr->srv6_l3vpn->loc_node_len; +			extra->sid[0].func_len = attr->srv6_l3vpn->func_len; +			extra->sid[0].arg_len = attr->srv6_l3vpn->arg_len; + +			/* +			 * draft-ietf-bess-srv6-services-07 +			 * The part of SRv6 SID may be encoded as MPLS Label for +			 * the efficient packing. +			 */ +			if (attr->srv6_l3vpn->transposition_len != 0) +				transpose_sid( +					&extra->sid[0].sid, decode_label(label), +					attr->srv6_l3vpn->transposition_offset, +					attr->srv6_l3vpn->transposition_len);  		} else if (attr->srv6_vpn) { -			sid_copy(&extra->sid[0], &attr->srv6_vpn->sid); +			sid_copy(&extra->sid[0].sid, &attr->srv6_vpn->sid);  			extra->num_sids = 1;  		}  	} @@ -10450,7 +10501,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,  	/* Remote SID */  	if (path->extra && path->extra->num_sids > 0 && safi != SAFI_EVPN) { -		inet_ntop(AF_INET6, &path->extra->sid, buf, sizeof(buf)); +		inet_ntop(AF_INET6, &path->extra->sid[0].sid, buf, sizeof(buf));  		if (json_paths)  			json_object_string_add(json_path, "remoteSid", buf);  		else diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index d052a3f408..7609f7196d 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -145,6 +145,14 @@ struct bgp_path_mh_info {  	struct bgp_path_evpn_nh_info *nh_info;  }; +struct bgp_sid_info { +	struct in6_addr sid; +	uint8_t loc_block_len; +	uint8_t loc_node_len; +	uint8_t func_len; +	uint8_t arg_len; +}; +  /* Ancillary information to struct bgp_path_info,   * used for uncommonly used data (aggregation, MPLS, etc.)   * and lazily allocated to save memory. @@ -168,7 +176,7 @@ struct bgp_path_info_extra {  #define BGP_EVPN_MACIP_TYPE_SVI_IP (1 << 0)  	/* SRv6 SID(s) for SRv6-VPN */ -	struct in6_addr sid[BGP_MAX_SIDS]; +	struct bgp_sid_info sid[BGP_MAX_SIDS];  	uint32_t num_sids;  #ifdef ENABLE_BGP_VNC diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index b367b393d9..e8ca544c23 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1451,11 +1451,10 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,  		api_nh->weight = nh_weight; -		if (mpinfo->extra -		    && !sid_zero(&mpinfo->extra->sid[0]) +		if (mpinfo->extra && !sid_zero(&mpinfo->extra->sid[0].sid)  		    && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {  			has_valid_sid = 1; -			memcpy(&api_nh->seg6_segs, &mpinfo->extra->sid[0], +			memcpy(&api_nh->seg6_segs, &mpinfo->extra->sid[0].sid,  			       sizeof(api_nh->seg6_segs));  		} diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 13b530a613..5e1eacbb9e 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -241,6 +241,7 @@ struct vpn_policy {  	 */  	uint32_t tovpn_sid_index; /* unset => set to 0 */  	struct in6_addr *tovpn_sid; +	uint32_t tovpn_sid_transpose_label;  	struct in6_addr *tovpn_zebra_vrf_sid_last_sent;  }; diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 45ef7230b5..6762c2b4a2 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -435,8 +435,16 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p,  			char buf[BUFSIZ];  			vty_out(vty, " sid=%s", -				inet_ntop(AF_INET6, &bpi->extra->sid[0], buf, -					  sizeof(buf))); +				inet_ntop(AF_INET6, &bpi->extra->sid[0].sid, +					  buf, sizeof(buf))); + +			if (bpi->extra->sid[0].loc_block_len != 0) { +				vty_out(vty, " sid_structure=[%d,%d,%d,%d]", +					bpi->extra->sid[0].loc_block_len, +					bpi->extra->sid[0].loc_node_len, +					bpi->extra->sid[0].func_len, +					bpi->extra->sid[0].arg_len); +			}  		}  	}  | 
