summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_addpath.h6
-rw-r--r--bgpd/bgp_fsm.c2
-rw-r--r--bgpd/bgp_open.c88
-rw-r--r--bgpd/bgp_open.h2
-rw-r--r--bgpd/bgp_packet.c126
-rw-r--r--bgpd/bgp_updgrp.c7
-rw-r--r--bgpd/bgp_updgrp_adv.c34
-rw-r--r--bgpd/bgp_vty.c203
-rw-r--r--bgpd/bgpd.c5
-rw-r--r--bgpd/bgpd.h13
10 files changed, 481 insertions, 5 deletions
diff --git a/bgpd/bgp_addpath.h b/bgpd/bgp_addpath.h
index d562000e30..b19e63c946 100644
--- a/bgpd/bgp_addpath.h
+++ b/bgpd/bgp_addpath.h
@@ -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);
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 234dbb0715..657c7e22d7 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -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) {
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],
diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h
index 34f4b7619e..a01e49ceba 100644
--- a/bgpd/bgp_open.h
+++ b/bgpd/bgp_open.h
@@ -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
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 203201d2c1..da352a8441 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1462,6 +1462,49 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
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. */
bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
@@ -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;
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index d13515af6f..c522865eba 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -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],
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 7ecebe3020..cc039e3e11 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -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);
}
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 31524e2221..efc71bc8a7 100644
--- a/bgpd/bgp_vty.c
+++ b/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);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 8fc52652a2..e7712f0f3e 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -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. */
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 0f69095323..cf333e07cc 100644
--- a/bgpd/bgpd.h
+++ b/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);