Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bgpd: Implement Paths-Limit capability #15273

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bgpd/bgp_addpath.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ struct bgp_addpath_capability {
uint8_t flags;
};

struct bgp_paths_limit_capability {
uint16_t afi;
uint8_t safi;
uint16_t paths_limit;
};

#define BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE 1

void bgp_addpath_init_bgp_data(struct bgp_addpath_bgp_data *d);
Expand Down
2 changes: 2 additions & 0 deletions bgpd/bgp_fsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,8 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
peer->afc_recv[afi][safi] = from_peer->afc_recv[afi][safi];
peer->orf_plist[afi][safi] = from_peer->orf_plist[afi][safi];
peer->llgr[afi][safi] = from_peer->llgr[afi][safi];
peer->addpath_paths_limit[afi][safi] =
from_peer->addpath_paths_limit[afi][safi];
}

if (bgp_getsockname(peer) < 0) {
Expand Down
88 changes: 88 additions & 0 deletions bgpd/bgp_open.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
};

Expand All @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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],
Expand Down
2 changes: 2 additions & 0 deletions bgpd/bgp_open.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ struct graceful_restart_af {
#define CAPABILITY_CODE_ENHE 5 /* Extended Next Hop Encoding */
#define CAPABILITY_CODE_EXT_MESSAGE 6 /* Extended Message Support */
#define CAPABILITY_CODE_ROLE 9 /* Role Capability */
#define CAPABILITY_CODE_PATHS_LIMIT 76 /* Paths Limit Capability */

/* Capability Length */
#define CAPABILITY_CODE_MP_LEN 4
Expand All @@ -61,6 +62,7 @@ struct graceful_restart_af {
#define CAPABILITY_CODE_RESTART_LEN 2 /* Receiving only case */
#define CAPABILITY_CODE_AS4_LEN 4
#define CAPABILITY_CODE_ADDPATH_LEN 4
#define CAPABILITY_CODE_PATHS_LIMIT_LEN 5
#define CAPABILITY_CODE_ENHE_LEN 6 /* NRLI AFI = 2, SAFI = 2, Nexthop AFI = 2 */
#define CAPABILITY_CODE_MIN_FQDN_LEN 2
#define CAPABILITY_CODE_ENHANCED_LEN 0
Expand Down
128 changes: 127 additions & 1 deletion bgpd/bgp_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1224,7 +1224,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
if (!peer_established(peer->connection))
return;

if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) &&
if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) ||
!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV))
return;

Expand Down Expand Up @@ -1461,6 +1461,49 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
capability, iana_afi2str(pkt_afi),
iana_safi2str(pkt_safi));

break;
case CAPABILITY_CODE_PATHS_LIMIT:
SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_ADV);

FOREACH_AFI_SAFI (afi, safi) {
if (!peer->afc[afi][safi])
continue;

addpath_afi_safi_count++;
}

stream_putc(s, action);
stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT);
stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT_LEN *
addpath_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);

if (bgp_debug_neighbor_events(peer))
zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s, limit: %u",
peer,
action == CAPABILITY_ACTION_SET
? "Advertising"
: "Removing",
capability, iana_afi2str(pkt_afi),
iana_safi2str(pkt_safi),
peer->addpath_paths_limit[afi][safi]
.send);
}

break;
case CAPABILITY_CODE_ORF:
/* Convert AFI, SAFI to values for packet. */
Expand Down Expand Up @@ -3170,6 +3213,85 @@ static void bgp_dynamic_capability_addpath(uint8_t *pnt, int action,
}
}

static void bgp_dynamic_capability_paths_limit(uint8_t *pnt, int action,
struct capability_header *hdr,
struct peer *peer)
{
uint8_t *data = pnt + 3;
uint8_t *end = data + hdr->length;
size_t len = end - data;
afi_t afi;
safi_t safi;

if (action == CAPABILITY_ACTION_SET) {
if (len % CAPABILITY_CODE_PATHS_LIMIT_LEN) {
flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH,
"Paths-Limit: Received invalid length %zu, non-multiple of %d",
len, CAPABILITY_CODE_PATHS_LIMIT_LEN);
return;
}

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");
goto ignore;
}

SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV);

while (data + CAPABILITY_CODE_PATHS_LIMIT_LEN <= end) {
afi_t afi;
safi_t safi;
iana_afi_t pkt_afi;
iana_safi_t pkt_safi;
struct bgp_paths_limit_capability bpl = {};

memcpy(&bpl, data, sizeof(bpl));
pkt_afi = ntohs(bpl.afi);
pkt_safi = safi_int2iana(bpl.safi);

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),
bpl.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));
goto ignore;
} 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));
goto ignore;
}

SET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_PATHS_LIMIT_AF_RCV);
peer->addpath_paths_limit[afi][safi].receive =
bpl.paths_limit;
ignore:
data += CAPABILITY_CODE_PATHS_LIMIT_LEN;
}
} else {
FOREACH_AFI_SAFI (afi, safi)
UNSET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_PATHS_LIMIT_AF_RCV);

UNSET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV);
}
}

static void bgp_dynamic_capability_orf(uint8_t *pnt, int action,
struct capability_header *hdr,
struct peer *peer)
Expand Down Expand Up @@ -3723,6 +3845,10 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
case CAPABILITY_CODE_ADDPATH:
bgp_dynamic_capability_addpath(pnt, action, hdr, peer);
break;
case CAPABILITY_CODE_PATHS_LIMIT:
bgp_dynamic_capability_paths_limit(pnt, action, hdr,
peer);
break;
case CAPABILITY_CODE_ORF:
bgp_dynamic_capability_orf(pnt, action, hdr, peer);
break;
Expand Down
7 changes: 7 additions & 0 deletions bgpd/bgp_updgrp.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi,
dst->addpath_type[afi][safi] = src->addpath_type[afi][safi];
dst->addpath_best_selected[afi][safi] =
src->addpath_best_selected[afi][safi];
dst->addpath_paths_limit[afi][safi] =
src->addpath_paths_limit[afi][safi];
dst->local_as = src->local_as;
dst->change_local_as = src->change_local_as;
dst->shared_network = src->shared_network;
Expand Down Expand Up @@ -348,6 +350,8 @@ static unsigned int updgrp_hash_key_make(const void *p)
key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key);
key = jhash_1word((uint32_t)peer->addpath_type[afi][safi], key);
key = jhash_1word(peer->addpath_best_selected[afi][safi], key);
key = jhash_1word(peer->addpath_paths_limit[afi][safi].receive, key);
key = jhash_1word(peer->addpath_paths_limit[afi][safi].send, key);
key = jhash_1word((peer->cap & PEER_UPDGRP_CAP_FLAGS), key);
key = jhash_1word((peer->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS),
key);
Expand Down Expand Up @@ -461,6 +465,9 @@ static unsigned int updgrp_hash_key_make(const void *p)
PEER_UPDGRP_AF_CAP_FLAGS),
peer->v_routeadv, peer->change_local_as,
peer->as_path_loop_detection);
zlog_debug("%pBP Update Group Hash: addpath paths-limit: (send %u, receive %u)",
peer, peer->addpath_paths_limit[afi][safi].send,
peer->addpath_paths_limit[afi][safi].receive);
zlog_debug(
"%pBP Update Group Hash: max packet size: %u pmax_out: %u Peer Group: %s rmap out: %s",
peer, peer->max_packet_size, peer->pmax_out[afi][safi],
Expand Down
Loading
Loading