mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 06:50:17 +00:00
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:
parent
cd7851d99e
commit
72f0e06824
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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],
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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],
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
203
bgpd/bgp_vty.c
203
bgpd/bgp_vty.c
@ -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);
|
||||
|
@ -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. */
|
||||
|
13
bgpd/bgpd.h
13
bgpd/bgpd.h
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user