diff options
| author | Donatas Abraitis <donatas@opensourcerouting.org> | 2024-01-23 20:33:18 +0200 | 
|---|---|---|
| committer | Donatas Abraitis <donatas@opensourcerouting.org> | 2024-02-13 17:07:15 +0200 | 
| commit | 72f0e06824c237238121b96c45845a57e5cfb59f (patch) | |
| tree | da03f17d7a62f1ce8aff9ab1838e250f208b1649 /bgpd/bgp_open.c | |
| parent | cd7851d99e65059f3f236bc9f5c562f0b24f1922 (diff) | |
bgpd: Implement Paths-Limit capability
https://datatracker.ietf.org/doc/html/draft-abraitis-idr-addpath-paths-limit
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
Diffstat (limited to 'bgpd/bgp_open.c')
| -rw-r--r-- | bgpd/bgp_open.c | 88 | 
1 files changed, 88 insertions, 0 deletions
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 43a59e2448..aa1d81362b 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -42,6 +42,7 @@ const struct message capcode_str[] = {  	{ CAPABILITY_CODE_LLGR, "Long-lived BGP Graceful Restart" },  	{ CAPABILITY_CODE_ROLE, "Role" },  	{ CAPABILITY_CODE_SOFT_VERSION, "Software Version" }, +	{ CAPABILITY_CODE_PATHS_LIMIT, "Paths-Limit" },  	{ 0 }  }; @@ -61,6 +62,7 @@ static const size_t cap_minsizes[] = {  		[CAPABILITY_CODE_LLGR] = CAPABILITY_CODE_LLGR_LEN,  		[CAPABILITY_CODE_ROLE] = CAPABILITY_CODE_ROLE_LEN,  		[CAPABILITY_CODE_SOFT_VERSION] = CAPABILITY_CODE_SOFT_VERSION_LEN, +		[CAPABILITY_CODE_PATHS_LIMIT] = CAPABILITY_CODE_PATHS_LIMIT_LEN,  };  /* value the capability must be a multiple of. @@ -83,6 +85,7 @@ static const size_t cap_modsizes[] = {  		[CAPABILITY_CODE_LLGR] = 1,  		[CAPABILITY_CODE_ROLE] = 1,  		[CAPABILITY_CODE_SOFT_VERSION] = 1, +		[CAPABILITY_CODE_PATHS_LIMIT] = 5,  };  /* BGP-4 Multiprotocol Extentions lead us to the complex world. We can @@ -739,6 +742,62 @@ static int bgp_capability_addpath(struct peer *peer,  	return 0;  } +static int bgp_capability_paths_limit(struct peer *peer, +				      struct capability_header *hdr) +{ +	struct stream *s = BGP_INPUT(peer); +	size_t end = stream_get_getp(s) + hdr->length; + +	if (hdr->length % CAPABILITY_CODE_PATHS_LIMIT_LEN) { +		flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, +			  "Paths-Limit: Received invalid length %d, non-multiple of %d", +			  hdr->length, CAPABILITY_CODE_PATHS_LIMIT_LEN); +		return -1; +	} + +	if (!CHECK_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV)) { +		flog_warn(EC_BGP_CAPABILITY_INVALID_DATA, +			  "Paths-Limit: Received Paths-Limit capability without Add-Path capability"); +		return -1; +	} + +	SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV); + +	while (stream_get_getp(s) + CAPABILITY_CODE_PATHS_LIMIT_LEN <= end) { +		afi_t afi; +		safi_t safi; +		iana_afi_t pkt_afi = stream_getw(s); +		iana_safi_t pkt_safi = stream_getc(s); +		uint16_t paths_limit = stream_getw(s); + +		if (bgp_debug_neighbor_events(peer)) +			zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s limit: %u", +				   peer->host, +				   lookup_msg(capcode_str, hdr->code, NULL), +				   iana_afi2str(pkt_afi), +				   iana_safi2str(pkt_safi), paths_limit); + +		if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { +			if (bgp_debug_neighbor_events(peer)) +				zlog_debug("%s Addr-family %s/%s(afi/safi) not supported. Ignore the Paths-Limit capability for this AFI/SAFI", +					   peer->host, iana_afi2str(pkt_afi), +					   iana_safi2str(pkt_safi)); +			continue; +		} else if (!peer->afc[afi][safi]) { +			if (bgp_debug_neighbor_events(peer)) +				zlog_debug("%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Paths-Limit capability for this AFI/SAFI", +					   peer->host, iana_afi2str(pkt_afi), +					   iana_safi2str(pkt_safi)); +			continue; +		} + +		SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_PATHS_LIMIT_AF_RCV); +		peer->addpath_paths_limit[afi][safi].receive = paths_limit; +	} + +	return 0; +} +  static int bgp_capability_enhe(struct peer *peer, struct capability_header *hdr)  {  	struct stream *s = BGP_INPUT(peer); @@ -1012,6 +1071,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length,  		case CAPABILITY_CODE_EXT_MESSAGE:  		case CAPABILITY_CODE_ROLE:  		case CAPABILITY_CODE_SOFT_VERSION: +		case CAPABILITY_CODE_PATHS_LIMIT:  			/* Check length. */  			if (caphdr.length < cap_minsizes[caphdr.code]) {  				zlog_info( @@ -1113,6 +1173,9 @@ static int bgp_capability_parse(struct peer *peer, size_t length,  		case CAPABILITY_CODE_SOFT_VERSION:  			ret = bgp_capability_software_version(peer, &caphdr);  			break; +		case CAPABILITY_CODE_PATHS_LIMIT: +			ret = bgp_capability_paths_limit(peer, &caphdr); +			break;  		default:  			if (caphdr.code > 128) {  				/* We don't send Notification for unknown vendor @@ -1874,6 +1937,31 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer,  		}  	} +	/* Paths-Limit capability */ +	SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_ADV); +	stream_putc(s, BGP_OPEN_OPT_CAP); +	ext_opt_params ? stream_putw(s, (CAPABILITY_CODE_PATHS_LIMIT_LEN * +					 afi_safi_count) + +						2) +		       : stream_putc(s, (CAPABILITY_CODE_PATHS_LIMIT_LEN * +					 afi_safi_count) + +						2); +	stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT); +	stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT_LEN * afi_safi_count); + +	FOREACH_AFI_SAFI (afi, safi) { +		if (!peer->afc[afi][safi]) +			continue; + +		bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); + +		stream_putw(s, pkt_afi); +		stream_putc(s, pkt_safi); +		stream_putw(s, peer->addpath_paths_limit[afi][safi].send); + +		SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_PATHS_LIMIT_AF_ADV); +	} +  	/* ORF capability. */  	FOREACH_AFI_SAFI (afi, safi) {  		if (CHECK_FLAG(peer->af_flags[afi][safi],  | 
