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>
This commit is contained in:
Donatas Abraitis 2024-01-23 20:33:18 +02:00
parent cd7851d99e
commit 72f0e06824
10 changed files with 481 additions and 5 deletions

View File

@ -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);

View File

@ -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) {

View File

@ -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],

View File

@ -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
@ -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

View File

@ -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. */
@ -3170,6 +3213,85 @@ ignore:
}
}
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)
@ -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;

View File

@ -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;
@ -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);
@ -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],

View File

@ -97,13 +97,19 @@ subgrp_announce_addpath_best_selected(struct bgp_dest *dest,
enum bgp_path_selection_reason reason;
char pfx_buf[PREFIX2STR_BUFFER] = {};
int paths_eq = 0;
int best_path_count = 0;
struct list *list = list_new();
struct bgp_path_info *pi = NULL;
uint16_t paths_count = 0;
uint16_t paths_limit = peer->addpath_paths_limit[afi][safi].receive;
if (peer->addpath_type[afi][safi] == BGP_ADDPATH_BEST_SELECTED) {
while (best_path_count++ <
peer->addpath_best_selected[afi][safi]) {
paths_limit =
paths_limit
? MIN(paths_limit,
peer->addpath_best_selected[afi][safi])
: peer->addpath_best_selected[afi][safi];
while (paths_count++ < paths_limit) {
struct bgp_path_info *exist = NULL;
for (pi = bgp_dest_get_bgp_path_info(dest); pi;
@ -139,8 +145,26 @@ subgrp_announce_addpath_best_selected(struct bgp_dest *dest,
subgroup_process_announce_selected(
subgrp, NULL, dest, afi, safi, id);
} else {
subgroup_process_announce_selected(subgrp, pi, dest,
afi, safi, id);
/* No Paths-Limit involved */
if (!paths_limit) {
subgroup_process_announce_selected(subgrp, pi,
dest, afi,
safi, id);
continue;
}
/* If we have Paths-Limit capability, we MUST
* not send more than the number of paths expected
* by the peer.
*/
if (paths_count++ < paths_limit)
subgroup_process_announce_selected(subgrp, pi,
dest, afi,
safi, id);
else
subgroup_process_announce_selected(subgrp, NULL,
dest, afi,
safi, id);
}
}

View File

@ -9198,6 +9198,63 @@ DEFPY(
return CMD_SUCCESS;
}
DEFPY (neighbor_addpath_paths_limit,
neighbor_addpath_paths_limit_cmd,
"neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor addpath-rx-paths-limit (1-65535)$paths_limit",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Paths Limit for Addpath to receive from the peer\n"
"Maximum number of paths\n")
{
struct peer *peer;
afi_t afi = bgp_node_afi(vty);
safi_t safi = bgp_node_safi(vty);
int ret;
peer = peer_and_group_lookup_vty(vty, neighbor);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
ret = peer_af_flag_set_vty(vty, neighbor, afi, safi,
PEER_FLAG_ADDPATH_RX_PATHS_LIMIT);
peer->addpath_paths_limit[afi][safi].send = paths_limit;
bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_PATHS_LIMIT,
CAPABILITY_ACTION_SET);
return ret;
}
DEFPY (no_neighbor_addpath_paths_limit,
no_neighbor_addpath_paths_limit_cmd,
"no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor addpath-rx-paths-limit [(1-65535)]",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Paths Limit for Addpath to receive from the peer\n"
"Maximum number of paths\n")
{
struct peer *peer;
afi_t afi = bgp_node_afi(vty);
safi_t safi = bgp_node_safi(vty);
int ret;
peer = peer_and_group_lookup_vty(vty, neighbor);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
ret = peer_af_flag_unset_vty(vty, neighbor, afi, safi,
PEER_FLAG_ADDPATH_RX_PATHS_LIMIT);
peer->addpath_paths_limit[afi][safi].send = 0;
bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_PATHS_LIMIT,
CAPABILITY_ACTION_UNSET);
return ret;
}
DEFPY(
no_neighbor_aspath_loop_detection,
no_neighbor_aspath_loop_detection_cmd,
@ -14146,6 +14203,86 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
json_add);
}
/* Paths-Limit */
if (CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_RCV) ||
CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_ADV)) {
json_object *json_add = NULL;
const char *print_store;
json_add = json_object_new_object();
FOREACH_AFI_SAFI (afi, safi) {
json_object *json_sub = NULL;
json_sub = json_object_new_object();
print_store = get_afi_safi_str(afi, safi,
true);
if (CHECK_FLAG(p->af_cap[afi][safi],
PEER_CAP_PATHS_LIMIT_AF_ADV) ||
CHECK_FLAG(p->af_cap[afi][safi],
PEER_CAP_PATHS_LIMIT_AF_RCV)) {
if (CHECK_FLAG(p->af_cap[afi][safi],
PEER_CAP_PATHS_LIMIT_AF_ADV) &&
CHECK_FLAG(p->af_cap[afi][safi],
PEER_CAP_PATHS_LIMIT_AF_RCV)) {
json_object_boolean_true_add(
json_sub,
"advertisedAndReceived");
json_object_int_add(
json_sub,
"advertisedPathsLimit",
p->addpath_paths_limit
[afi][safi]
.send);
json_object_int_add(
json_sub,
"receivedPathsLimit",
p->addpath_paths_limit
[afi][safi]
.receive);
} else if (CHECK_FLAG(p->af_cap[afi]
[safi],
PEER_CAP_PATHS_LIMIT_AF_ADV)) {
json_object_boolean_true_add(
json_sub,
"advertised");
json_object_int_add(
json_sub,
"advertisedPathsLimit",
p->addpath_paths_limit
[afi][safi]
.send);
} else if (CHECK_FLAG(p->af_cap[afi]
[safi],
PEER_CAP_PATHS_LIMIT_AF_RCV)) {
json_object_boolean_true_add(
json_sub,
"received");
json_object_int_add(
json_sub,
"receivedPathsLimit",
p->addpath_paths_limit
[afi][safi]
.receive);
}
}
if (CHECK_FLAG(p->af_cap[afi][safi],
PEER_CAP_PATHS_LIMIT_AF_ADV) ||
CHECK_FLAG(p->af_cap[afi][safi],
PEER_CAP_PATHS_LIMIT_AF_RCV))
json_object_object_add(json_add,
print_store,
json_sub);
else
json_object_free(json_sub);
}
json_object_object_add(json_cap, "pathsLimit",
json_add);
}
/* Dynamic */
if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) ||
CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) {
@ -14599,6 +14736,47 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
}
}
/* Paths-Limit */
if (CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_RCV) ||
CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_ADV)) {
vty_out(vty, " Paths-Limit:\n");
FOREACH_AFI_SAFI (afi, safi) {
if (CHECK_FLAG(p->af_cap[afi][safi],
PEER_CAP_PATHS_LIMIT_AF_ADV) ||
CHECK_FLAG(p->af_cap[afi][safi],
PEER_CAP_PATHS_LIMIT_AF_RCV)) {
vty_out(vty, " %s: ",
get_afi_safi_str(afi,
safi,
false));
if (CHECK_FLAG(p->af_cap[afi][safi],
PEER_CAP_PATHS_LIMIT_AF_ADV))
vty_out(vty,
"advertised (%u)",
p->addpath_paths_limit
[afi][safi]
.send);
if (CHECK_FLAG(p->af_cap[afi][safi],
PEER_CAP_PATHS_LIMIT_AF_RCV))
vty_out(vty,
"%sreceived (%u)",
CHECK_FLAG(p->af_cap[afi]
[safi],
PEER_CAP_PATHS_LIMIT_AF_ADV)
? " and "
: "",
p->addpath_paths_limit
[afi][safi]
.receive);
vty_out(vty, "\n");
}
}
}
/* Dynamic */
if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) ||
CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) {
@ -18383,6 +18561,11 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DISABLE_ADDPATH_RX))
vty_out(vty, " neighbor %s disable-addpath-rx\n", addr);
if (CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_ADDPATH_RX_PATHS_LIMIT))
vty_out(vty, " neighbor %s addpath-rx-paths-limit %u\n", addr,
peer->addpath_paths_limit[afi][safi].send);
/* ORF capability. */
if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM)
|| peergroup_af_flag_check(peer, afi, safi,
@ -20544,6 +20727,26 @@ void bgp_vty_init(void)
install_element(BGP_VPNV6_NODE,
&no_neighbor_addpath_tx_bestpath_per_as_cmd);
/* "neighbor addpath-rx-paths-limit" commands.*/
install_element(BGP_NODE, &neighbor_addpath_paths_limit_cmd);
install_element(BGP_NODE, &no_neighbor_addpath_paths_limit_cmd);
install_element(BGP_IPV4_NODE, &neighbor_addpath_paths_limit_cmd);
install_element(BGP_IPV4_NODE, &no_neighbor_addpath_paths_limit_cmd);
install_element(BGP_IPV4M_NODE, &neighbor_addpath_paths_limit_cmd);
install_element(BGP_IPV4M_NODE, &no_neighbor_addpath_paths_limit_cmd);
install_element(BGP_IPV4L_NODE, &neighbor_addpath_paths_limit_cmd);
install_element(BGP_IPV4L_NODE, &no_neighbor_addpath_paths_limit_cmd);
install_element(BGP_IPV6_NODE, &neighbor_addpath_paths_limit_cmd);
install_element(BGP_IPV6_NODE, &no_neighbor_addpath_paths_limit_cmd);
install_element(BGP_IPV6M_NODE, &neighbor_addpath_paths_limit_cmd);
install_element(BGP_IPV6M_NODE, &no_neighbor_addpath_paths_limit_cmd);
install_element(BGP_IPV6L_NODE, &neighbor_addpath_paths_limit_cmd);
install_element(BGP_IPV6L_NODE, &no_neighbor_addpath_paths_limit_cmd);
install_element(BGP_VPNV4_NODE, &neighbor_addpath_paths_limit_cmd);
install_element(BGP_VPNV4_NODE, &no_neighbor_addpath_paths_limit_cmd);
install_element(BGP_VPNV6_NODE, &neighbor_addpath_paths_limit_cmd);
install_element(BGP_VPNV6_NODE, &no_neighbor_addpath_paths_limit_cmd);
/* "neighbor sender-as-path-loop-detection" commands. */
install_element(BGP_NODE, &neighbor_aspath_loop_detection_cmd);
install_element(BGP_NODE, &no_neighbor_aspath_loop_detection_cmd);

View File

@ -1527,6 +1527,8 @@ struct peer *peer_new(struct bgp *bgp)
PEER_FLAG_SEND_LARGE_COMMUNITY);
peer->addpath_type[afi][safi] = BGP_ADDPATH_NONE;
peer->addpath_best_selected[afi][safi] = 0;
peer->addpath_paths_limit[afi][safi].receive = 0;
peer->addpath_paths_limit[afi][safi].send = 0;
peer->soo[afi][safi] = NULL;
}
@ -1620,6 +1622,8 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
peer_dst->weight[afi][safi] = peer_src->weight[afi][safi];
peer_dst->addpath_type[afi][safi] =
peer_src->addpath_type[afi][safi];
peer_dst->addpath_paths_limit[afi][safi] =
peer_src->addpath_paths_limit[afi][safi];
}
for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) {
@ -4614,6 +4618,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] = {
{PEER_FLAG_SOO, 0, peer_change_reset},
{PEER_FLAG_ACCEPT_OWN, 0, peer_change_reset},
{PEER_FLAG_SEND_EXT_COMMUNITY_RPKI, 1, peer_change_reset_out},
{PEER_FLAG_ADDPATH_RX_PATHS_LIMIT, 0, peer_change_none},
{0, 0, 0}};
/* Proper action set. */

View File

@ -1140,6 +1140,11 @@ struct llgr_info {
uint8_t flags;
};
struct addpath_paths_limit {
uint16_t send;
uint16_t receive;
};
struct peer_connection {
struct peer *peer;
@ -1333,6 +1338,8 @@ struct peer {
#define PEER_CAP_ROLE_RCV (1ULL << 26) /* role received */
#define PEER_CAP_SOFT_VERSION_ADV (1ULL << 27)
#define PEER_CAP_SOFT_VERSION_RCV (1ULL << 28)
#define PEER_CAP_PATHS_LIMIT_ADV (1U << 29)
#define PEER_CAP_PATHS_LIMIT_RCV (1U << 30)
/* Capability flags (reset in bgp_stop) */
uint32_t af_cap[AFI_MAX][SAFI_MAX];
@ -1351,6 +1358,8 @@ struct peer {
#define PEER_CAP_ENHE_AF_NEGO (1U << 14) /* Extended nexthop afi/safi negotiated */
#define PEER_CAP_LLGR_AF_ADV (1U << 15)
#define PEER_CAP_LLGR_AF_RCV (1U << 16)
#define PEER_CAP_PATHS_LIMIT_AF_ADV (1U << 17)
#define PEER_CAP_PATHS_LIMIT_AF_RCV (1U << 18)
/* Global configuration flags. */
/*
@ -1528,6 +1537,7 @@ struct peer {
#define PEER_FLAG_DISABLE_ADDPATH_RX (1ULL << 27)
#define PEER_FLAG_SOO (1ULL << 28)
#define PEER_FLAG_SEND_EXT_COMMUNITY_RPKI (1ULL << 29)
#define PEER_FLAG_ADDPATH_RX_PATHS_LIMIT (1ULL << 30)
#define PEER_FLAG_ACCEPT_OWN (1ULL << 63)
enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];
@ -1845,6 +1855,9 @@ struct peer {
/* Add-Path Best selected paths number to advertise */
uint8_t addpath_best_selected[AFI_MAX][SAFI_MAX];
/* Add-Path Paths-Limit */
struct addpath_paths_limit addpath_paths_limit[AFI_MAX][SAFI_MAX];
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(peer);