Skip to content

Commit

Permalink
bgpd: Implement Paths-Limit capability
Browse files Browse the repository at this point in the history
  • Loading branch information
ton31337 committed Feb 7, 2024
1 parent 9008b05 commit d5b1141
Show file tree
Hide file tree
Showing 10 changed files with 481 additions and 5 deletions.
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
126 changes: 126 additions & 0 deletions bgpd/bgp_packet.c
Original file line number Diff line number Diff line change
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 @@ -3169,6 +3212,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 @@ -3722,6 +3844,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

0 comments on commit d5b1141

Please sign in to comment.