Merge pull request #13728 from opensourcerouting/fix/addpath_drop_non_best_addpaths

bgpd: Implement neighbor X addpath-tx-best-selected command
This commit is contained in:
Russ White 2023-06-20 09:20:36 -04:00 committed by GitHub
commit 4d9fb376c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 478 additions and 36 deletions

View File

@ -25,7 +25,14 @@ static const struct bgp_addpath_strategy_names strat_names[BGP_ADDPATH_MAX] = {
.human_description = "Advertise bestpath per AS via addpath", .human_description = "Advertise bestpath per AS via addpath",
.type_json_name = "addpathTxBestpathPerAS", .type_json_name = "addpathTxBestpathPerAS",
.id_json_name = "addpathTxIdBestPerAS" .id_json_name = "addpathTxIdBestPerAS"
} },
{
.config_name = "addpath-tx-best-selected",
.human_name = "Best-Selected",
.human_description = "Advertise best N selected paths via addpath",
.type_json_name = "addpathTxBestSelectedPaths",
.id_json_name = "addpathTxIdBestSelected"
},
}; };
static const struct bgp_addpath_strategy_names unknown_names = { static const struct bgp_addpath_strategy_names unknown_names = {
@ -161,6 +168,8 @@ bool bgp_addpath_tx_path(enum bgp_addpath_strat strat, struct bgp_path_info *pi)
return true; return true;
else else
return false; return false;
case BGP_ADDPATH_BEST_SELECTED:
return true;
case BGP_ADDPATH_MAX: case BGP_ADDPATH_MAX:
return false; return false;
} }
@ -356,7 +365,8 @@ void bgp_addpath_type_changed(struct bgp *bgp)
* change take effect. * change take effect.
*/ */
void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi, void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
enum bgp_addpath_strat addpath_type) enum bgp_addpath_strat addpath_type,
uint8_t paths)
{ {
struct bgp *bgp = peer->bgp; struct bgp *bgp = peer->bgp;
enum bgp_addpath_strat old_type; enum bgp_addpath_strat old_type;
@ -367,6 +377,8 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
if (safi == SAFI_LABELED_UNICAST) if (safi == SAFI_LABELED_UNICAST)
safi = SAFI_UNICAST; safi = SAFI_UNICAST;
peer->addpath_best_selected[afi][safi] = paths;
old_type = peer->addpath_type[afi][safi]; old_type = peer->addpath_type[afi][safi];
if (addpath_type == old_type) if (addpath_type == old_type)
return; return;
@ -411,10 +423,9 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
tmp_peer)) { tmp_peer)) {
if (tmp_peer->addpath_type[afi][safi] == if (tmp_peer->addpath_type[afi][safi] ==
old_type) { old_type) {
bgp_addpath_set_peer_type(tmp_peer, bgp_addpath_set_peer_type(
afi, tmp_peer, afi, safi,
safi, addpath_type, paths);
addpath_type);
} }
} }
} }

View File

@ -50,7 +50,8 @@ bool bgp_addpath_tx_path(enum bgp_addpath_strat strat,
* Change the type of addpath used for a peer. * Change the type of addpath used for a peer.
*/ */
void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi, void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
enum bgp_addpath_strat addpath_type); enum bgp_addpath_strat addpath_type,
uint8_t paths);
void bgp_addpath_update_ids(struct bgp *bgp, struct bgp_dest *dest, afi_t afi, void bgp_addpath_update_ids(struct bgp *bgp, struct bgp_dest *dest, afi_t afi,
safi_t safi); safi_t safi);

View File

@ -12,6 +12,7 @@
enum bgp_addpath_strat { enum bgp_addpath_strat {
BGP_ADDPATH_ALL = 0, BGP_ADDPATH_ALL = 0,
BGP_ADDPATH_BEST_PER_AS, BGP_ADDPATH_BEST_PER_AS,
BGP_ADDPATH_BEST_SELECTED,
BGP_ADDPATH_MAX, BGP_ADDPATH_MAX,
BGP_ADDPATH_NONE, BGP_ADDPATH_NONE,
}; };

View File

@ -579,11 +579,11 @@ struct bgp_path_info *bgp_get_imported_bpi_ultimate(struct bgp_path_info *info)
/* Compare two bgp route entity. If 'new' is preferable over 'exist' return 1. /* Compare two bgp route entity. If 'new' is preferable over 'exist' return 1.
*/ */
static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
struct bgp_path_info *exist, int *paths_eq, struct bgp_path_info *exist, int *paths_eq,
struct bgp_maxpaths_cfg *mpath_cfg, int debug, struct bgp_maxpaths_cfg *mpath_cfg, int debug,
char *pfx_buf, afi_t afi, safi_t safi, char *pfx_buf, afi_t afi, safi_t safi,
enum bgp_path_selection_reason *reason) enum bgp_path_selection_reason *reason)
{ {
const struct prefix *new_p; const struct prefix *new_p;
struct attr *newattr, *existattr; struct attr *newattr, *existattr;

View File

@ -910,6 +910,11 @@ extern void bgp_path_info_add_with_caller(const char *caller,
struct bgp_dest *dest, struct bgp_dest *dest,
struct bgp_path_info *pi); struct bgp_path_info *pi);
extern void bgp_aggregate_free(struct bgp_aggregate *aggregate); extern void bgp_aggregate_free(struct bgp_aggregate *aggregate);
extern int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
struct bgp_path_info *exist, int *paths_eq,
struct bgp_maxpaths_cfg *mpath_cfg, int debug,
char *pfx_buf, afi_t afi, safi_t safi,
enum bgp_path_selection_reason *reason);
#define bgp_path_info_add(A, B) \ #define bgp_path_info_add(A, B) \
bgp_path_info_add_with_caller(__func__, (A), (B)) bgp_path_info_add_with_caller(__func__, (A), (B))
#define bgp_path_info_free(B) bgp_path_info_free_with_caller(__func__, (B)) #define bgp_path_info_free(B) bgp_path_info_free_with_caller(__func__, (B))

View File

@ -142,6 +142,8 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi,
dst->afc_nego[afi][safi] = src->afc_nego[afi][safi]; dst->afc_nego[afi][safi] = src->afc_nego[afi][safi];
dst->orf_plist[afi][safi] = src->orf_plist[afi][safi]; dst->orf_plist[afi][safi] = src->orf_plist[afi][safi];
dst->addpath_type[afi][safi] = src->addpath_type[afi][safi]; dst->addpath_type[afi][safi] = src->addpath_type[afi][safi];
dst->addpath_best_selected[afi][safi] =
src->addpath_best_selected[afi][safi];
dst->local_as = src->local_as; dst->local_as = src->local_as;
dst->change_local_as = src->change_local_as; dst->change_local_as = src->change_local_as;
dst->shared_network = src->shared_network; dst->shared_network = src->shared_network;
@ -307,6 +309,7 @@ static void *updgrp_hash_alloc(void *p)
* 16. Local-as should match, if configured. * 16. Local-as should match, if configured.
* 17. maximum-prefix-out * 17. maximum-prefix-out
* 18. Local-role should also match, if configured. * 18. Local-role should also match, if configured.
* 19. Add-Path best selected paths count should match as well
* ) * )
*/ */
static unsigned int updgrp_hash_key_make(const void *p) static unsigned int updgrp_hash_key_make(const void *p)
@ -340,6 +343,7 @@ static unsigned int updgrp_hash_key_make(const void *p)
key = jhash_1word((peer->flags & PEER_UPDGRP_FLAGS), key); key = jhash_1word((peer->flags & PEER_UPDGRP_FLAGS), key);
key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key); key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key);
key = jhash_1word((uint32_t)peer->addpath_type[afi][safi], 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->cap & PEER_UPDGRP_CAP_FLAGS), 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 = jhash_1word((peer->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS),
key); key);

View File

@ -87,6 +87,67 @@ static void adj_free(struct bgp_adj_out *adj)
XFREE(MTYPE_BGP_ADJ_OUT, adj); XFREE(MTYPE_BGP_ADJ_OUT, adj);
} }
static void
subgrp_announce_addpath_best_selected(struct bgp_dest *dest,
struct update_subgroup *subgrp)
{
afi_t afi = SUBGRP_AFI(subgrp);
safi_t safi = SUBGRP_SAFI(subgrp);
struct peer *peer = SUBGRP_PEER(subgrp);
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;
if (peer->addpath_type[afi][safi] == BGP_ADDPATH_BEST_SELECTED) {
while (best_path_count++ <
peer->addpath_best_selected[afi][safi]) {
struct bgp_path_info *exist = NULL;
for (pi = bgp_dest_get_bgp_path_info(dest); pi;
pi = pi->next) {
if (listnode_lookup(list, pi))
continue;
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
continue;
if (bgp_path_info_cmp(peer->bgp, pi, exist,
&paths_eq, NULL, 0,
pfx_buf, afi, safi,
&reason))
exist = pi;
}
if (exist)
listnode_add(list, exist);
}
}
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
uint32_t id = bgp_addpath_id_for_peer(peer, afi, safi,
&pi->tx_addpath);
if (peer->addpath_type[afi][safi] ==
BGP_ADDPATH_BEST_SELECTED) {
if (listnode_lookup(list, pi))
subgroup_process_announce_selected(
subgrp, pi, dest, afi, safi, id);
else
subgroup_process_announce_selected(
subgrp, NULL, dest, afi, safi, id);
} else {
subgroup_process_announce_selected(subgrp, pi, dest,
afi, safi, id);
}
}
if (list)
list_delete(&list);
}
static void subgrp_withdraw_stale_addpath(struct updwalk_context *ctx, static void subgrp_withdraw_stale_addpath(struct updwalk_context *ctx,
struct update_subgroup *subgrp) struct update_subgroup *subgrp)
{ {
@ -125,7 +186,6 @@ static int group_announce_route_walkcb(struct update_group *updgrp, void *arg)
{ {
struct updwalk_context *ctx = arg; struct updwalk_context *ctx = arg;
struct update_subgroup *subgrp; struct update_subgroup *subgrp;
struct bgp_path_info *pi;
afi_t afi; afi_t afi;
safi_t safi; safi_t safi;
struct peer *peer; struct peer *peer;
@ -143,7 +203,6 @@ static int group_announce_route_walkcb(struct update_group *updgrp, void *arg)
bgp_dest_to_rnode(ctx->dest)); bgp_dest_to_rnode(ctx->dest));
UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) { UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
/* /*
* Skip the subgroups that have coalesce timer running. We will * Skip the subgroups that have coalesce timer running. We will
* walk the entire prefix table for those subgroups when the * walk the entire prefix table for those subgroups when the
@ -155,19 +214,8 @@ static int group_announce_route_walkcb(struct update_group *updgrp, void *arg)
if (addpath_capable) { if (addpath_capable) {
subgrp_withdraw_stale_addpath(ctx, subgrp); subgrp_withdraw_stale_addpath(ctx, subgrp);
for (pi = bgp_dest_get_bgp_path_info(ctx->dest); subgrp_announce_addpath_best_selected(ctx->dest,
pi; pi = pi->next) { subgrp);
/* Skip the bestpath for now */
if (pi == ctx->pi)
continue;
subgroup_process_announce_selected(
subgrp, pi, ctx->dest, afi,
safi,
bgp_addpath_id_for_peer(
peer, afi, safi,
&pi->tx_addpath));
}
/* Process the bestpath last so the "show [ip] /* Process the bestpath last so the "show [ip]
* bgp neighbor x.x.x.x advertised" * bgp neighbor x.x.x.x advertised"
@ -689,6 +737,10 @@ void subgroup_announce_table(struct update_subgroup *subgrp,
SET_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING); SET_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING);
for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
if (addpath_capable)
subgrp_announce_addpath_best_selected(dest, subgrp);
for (ri = bgp_dest_get_bgp_path_info(dest); ri; ri = ri->next) { for (ri = bgp_dest_get_bgp_path_info(dest); ri; ri = ri->next) {
if (!bgp_check_selected(ri, peer, addpath_capable, afi, if (!bgp_check_selected(ri, peer, addpath_capable, afi,
@ -706,10 +758,12 @@ void subgroup_announce_table(struct update_subgroup *subgrp,
is_default_prefix(bgp_dest_get_prefix(dest))) is_default_prefix(bgp_dest_get_prefix(dest)))
break; break;
subgroup_process_announce_selected( if (CHECK_FLAG(ri->flags, BGP_PATH_SELECTED))
subgrp, ri, dest, afi, safi_rib, subgroup_process_announce_selected(
bgp_addpath_id_for_peer(peer, afi, safi_rib, subgrp, ri, dest, afi, safi_rib,
&ri->tx_addpath)); bgp_addpath_id_for_peer(
peer, afi, safi_rib,
&ri->tx_addpath));
} }
} }
UNSET_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING); UNSET_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING);

View File

@ -8803,7 +8803,7 @@ DEFUN (neighbor_addpath_tx_all_paths,
return CMD_WARNING_CONFIG_FAILED; return CMD_WARNING_CONFIG_FAILED;
bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty), bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty),
BGP_ADDPATH_ALL); BGP_ADDPATH_ALL, 0);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -8836,7 +8836,7 @@ DEFUN (no_neighbor_addpath_tx_all_paths,
} }
bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty), bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty),
BGP_ADDPATH_NONE); BGP_ADDPATH_NONE, 0);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -8847,6 +8847,45 @@ ALIAS_HIDDEN(no_neighbor_addpath_tx_all_paths,
NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
"Use addpath to advertise all paths to a neighbor\n") "Use addpath to advertise all paths to a neighbor\n")
DEFPY (neighbor_addpath_tx_best_selected_paths,
neighbor_addpath_tx_best_selected_paths_cmd,
"neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor addpath-tx-best-selected (1-6)$paths",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Use addpath to advertise best selected paths to a neighbor\n"
"The number of best paths\n")
{
struct peer *peer;
peer = peer_and_group_lookup_vty(vty, neighbor);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty),
BGP_ADDPATH_BEST_SELECTED, paths);
return CMD_SUCCESS;
}
DEFPY (no_neighbor_addpath_tx_best_selected_paths,
no_neighbor_addpath_tx_best_selected_paths_cmd,
"no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor addpath-tx-best-selected [(1-6)]",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Use addpath to advertise best selected paths to a neighbor\n"
"The number of best paths\n")
{
struct peer *peer;
peer = peer_and_group_lookup_vty(vty, neighbor);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty),
BGP_ADDPATH_BEST_SELECTED, 0);
return CMD_SUCCESS;
}
DEFUN (neighbor_addpath_tx_bestpath_per_as, DEFUN (neighbor_addpath_tx_bestpath_per_as,
neighbor_addpath_tx_bestpath_per_as_cmd, neighbor_addpath_tx_bestpath_per_as_cmd,
"neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS", "neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS",
@ -8862,7 +8901,7 @@ DEFUN (neighbor_addpath_tx_bestpath_per_as,
return CMD_WARNING_CONFIG_FAILED; return CMD_WARNING_CONFIG_FAILED;
bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty), bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty),
BGP_ADDPATH_BEST_PER_AS); BGP_ADDPATH_BEST_PER_AS, 0);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -8896,7 +8935,7 @@ DEFUN (no_neighbor_addpath_tx_bestpath_per_as,
} }
bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty), bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty),
BGP_ADDPATH_NONE); BGP_ADDPATH_NONE, 0);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -17942,6 +17981,13 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
" neighbor %s addpath-tx-bestpath-per-AS\n", " neighbor %s addpath-tx-bestpath-per-AS\n",
addr); addr);
break; break;
case BGP_ADDPATH_BEST_SELECTED:
if (peer->addpath_best_selected[afi][safi])
vty_out(vty,
" neighbor %s addpath-tx-best-selected %u\n",
addr,
peer->addpath_best_selected[afi][safi]);
break;
case BGP_ADDPATH_MAX: case BGP_ADDPATH_MAX:
case BGP_ADDPATH_NONE: case BGP_ADDPATH_NONE:
break; break;
@ -19987,6 +20033,40 @@ void bgp_vty_init(void)
install_element(BGP_VPNV6_NODE, &neighbor_addpath_tx_all_paths_cmd); install_element(BGP_VPNV6_NODE, &neighbor_addpath_tx_all_paths_cmd);
install_element(BGP_VPNV6_NODE, &no_neighbor_addpath_tx_all_paths_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
/* "neighbor addpath-tx-best-selected" commands.*/
install_element(BGP_IPV4_NODE,
&neighbor_addpath_tx_best_selected_paths_cmd);
install_element(BGP_IPV4_NODE,
&no_neighbor_addpath_tx_best_selected_paths_cmd);
install_element(BGP_IPV4M_NODE,
&neighbor_addpath_tx_best_selected_paths_cmd);
install_element(BGP_IPV4M_NODE,
&no_neighbor_addpath_tx_best_selected_paths_cmd);
install_element(BGP_IPV4L_NODE,
&neighbor_addpath_tx_best_selected_paths_cmd);
install_element(BGP_IPV4L_NODE,
&no_neighbor_addpath_tx_best_selected_paths_cmd);
install_element(BGP_IPV6_NODE,
&neighbor_addpath_tx_best_selected_paths_cmd);
install_element(BGP_IPV6_NODE,
&no_neighbor_addpath_tx_best_selected_paths_cmd);
install_element(BGP_IPV6M_NODE,
&neighbor_addpath_tx_best_selected_paths_cmd);
install_element(BGP_IPV6M_NODE,
&no_neighbor_addpath_tx_best_selected_paths_cmd);
install_element(BGP_IPV6L_NODE,
&neighbor_addpath_tx_best_selected_paths_cmd);
install_element(BGP_IPV6L_NODE,
&no_neighbor_addpath_tx_best_selected_paths_cmd);
install_element(BGP_VPNV4_NODE,
&neighbor_addpath_tx_best_selected_paths_cmd);
install_element(BGP_VPNV4_NODE,
&no_neighbor_addpath_tx_best_selected_paths_cmd);
install_element(BGP_VPNV6_NODE,
&neighbor_addpath_tx_best_selected_paths_cmd);
install_element(BGP_VPNV6_NODE,
&no_neighbor_addpath_tx_best_selected_paths_cmd);
/* "neighbor addpath-tx-bestpath-per-AS" commands.*/ /* "neighbor addpath-tx-bestpath-per-AS" commands.*/
install_element(BGP_NODE, install_element(BGP_NODE,
&neighbor_addpath_tx_bestpath_per_as_hidden_cmd); &neighbor_addpath_tx_bestpath_per_as_hidden_cmd);

View File

@ -1182,7 +1182,7 @@ static void peer_free(struct peer *peer)
bgp_peer_remove_bfd_config(peer); bgp_peer_remove_bfd_config(peer);
FOREACH_AFI_SAFI (afi, safi) FOREACH_AFI_SAFI (afi, safi)
bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_NONE); bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_NONE, 0);
if (peer->change_local_as_pretty) if (peer->change_local_as_pretty)
XFREE(MTYPE_BGP, peer->change_local_as_pretty); XFREE(MTYPE_BGP, peer->change_local_as_pretty);
@ -1397,6 +1397,7 @@ struct peer *peer_new(struct bgp *bgp)
SET_FLAG(peer->af_flags_invert[afi][safi], SET_FLAG(peer->af_flags_invert[afi][safi],
PEER_FLAG_SEND_LARGE_COMMUNITY); PEER_FLAG_SEND_LARGE_COMMUNITY);
peer->addpath_type[afi][safi] = BGP_ADDPATH_NONE; peer->addpath_type[afi][safi] = BGP_ADDPATH_NONE;
peer->addpath_best_selected[afi][safi] = 0;
peer->soo[afi][safi] = NULL; peer->soo[afi][safi] = NULL;
} }

View File

@ -1799,6 +1799,9 @@ struct peer {
#define BGP_MAX_SOFT_VERSION 64 #define BGP_MAX_SOFT_VERSION 64
char *soft_version; char *soft_version;
/* Add-Path Best selected paths number to advertise */
uint8_t addpath_best_selected[AFI_MAX][SAFI_MAX];
QOBJ_FIELDS; QOBJ_FIELDS;
}; };
DECLARE_QOBJ_TYPE(peer); DECLARE_QOBJ_TYPE(peer);

View File

@ -1669,6 +1669,10 @@ Configuring Peers
Configure BGP to send best known paths to neighbor in order to preserve multi Configure BGP to send best known paths to neighbor in order to preserve multi
path capabilities inside a network. path capabilities inside a network.
.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-best-selected (1-6)
Configure BGP to calculate and send N best known paths to the neighbor.
.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> disable-addpath-rx .. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> disable-addpath-rx
Do not accept additional paths from this neighbor. Do not accept additional paths from this neighbor.

View File

@ -0,0 +1,7 @@
!
router bgp 65001
timers bgp 3 10
no bgp ebgp-requires-policy
neighbor 192.168.1.2 remote-as external
neighbor 192.168.1.2 timers connect 5
!

View File

@ -0,0 +1,4 @@
!
int r1-eth0
ip address 192.168.1.1/24
!

View File

@ -0,0 +1,28 @@
router bgp 65002
timers bgp 3 10
no bgp ebgp-requires-policy
neighbor 192.168.1.1 remote-as external
neighbor 192.168.1.1 remote-as external
neighbor 192.168.7.7 remote-as external
neighbor 192.168.7.7 timers connect 5
neighbor 192.168.2.3 remote-as external
neighbor 192.168.2.3 timers connect 5
neighbor 192.168.2.3 weight 3
neighbor 192.168.2.4 remote-as external
neighbor 192.168.2.4 timers connect 5
neighbor 192.168.2.4 weight 4
neighbor 192.168.2.5 remote-as external
neighbor 192.168.2.5 timers connect 5
neighbor 192.168.2.5 weight 5
neighbor 192.168.2.6 remote-as external
neighbor 192.168.2.6 timers connect 5
neighbor 192.168.2.6 weight 6
address-family ipv4 unicast
neighbor 192.168.1.1 addpath-tx-best-selected 1
neighbor 192.168.1.1 prefix-list announce out
neighbor 192.168.7.7 addpath-tx-best-selected 2
neighbor 192.168.7.7 prefix-list announce out
exit-address-family
!
ip prefix-list announce seq 5 permit 172.16.16.254/32
!

View File

@ -0,0 +1,10 @@
!
int r2-eth0
ip address 192.168.1.2/24
!
int r2-eth1
ip address 192.168.2.2/24
!
int r2-eth2
ip address 192.168.7.2/24
!

View File

@ -0,0 +1,9 @@
router bgp 65003
timers bgp 3 10
no bgp ebgp-requires-policy
neighbor 192.168.2.2 remote-as external
neighbor 192.168.2.2 timers connect 5
address-family ipv4 unicast
redistribute connected
exit-address-family
!

View File

@ -0,0 +1,7 @@
!
int lo
ip address 172.16.16.254/32
!
int r3-eth0
ip address 192.168.2.3/24
!

View File

@ -0,0 +1,9 @@
router bgp 65004
timers bgp 3 10
no bgp ebgp-requires-policy
neighbor 192.168.2.2 remote-as external
neighbor 192.168.2.2 timers connect 5
address-family ipv4 unicast
redistribute connected
exit-address-family
!

View File

@ -0,0 +1,7 @@
!
int lo
ip address 172.16.16.254/32
!
int r4-eth0
ip address 192.168.2.4/24
!

View File

@ -0,0 +1,9 @@
router bgp 65005
timers 3 10
no bgp ebgp-requires-policy
neighbor 192.168.2.2 remote-as external
neighbor 192.168.2.2 timers connect 5
address-family ipv4 unicast
redistribute connected
exit-address-family
!

View File

@ -0,0 +1,7 @@
!
int lo
ip address 172.16.16.254/32
!
int r5-eth0
ip address 192.168.2.5/24
!

View File

@ -0,0 +1,9 @@
router bgp 65006
timers 3 10
no bgp ebgp-requires-policy
neighbor 192.168.2.2 remote-as external
neighbor 192.168.2.2 timers connect 5
address-family ipv4 unicast
redistribute connected
exit-address-family
!

View File

@ -0,0 +1,7 @@
!
int lo
ip address 172.16.16.254/32
!
int r6-eth0
ip address 192.168.2.6/24
!

View File

@ -0,0 +1,7 @@
!
router bgp 65007
timers bgp 3 10
no bgp ebgp-requires-policy
neighbor 192.168.7.2 remote-as external
neighbor 192.168.7.2 timers connect 5
!

View File

@ -0,0 +1,4 @@
!
int r7-eth0
ip address 192.168.7.7/24
!

View File

@ -0,0 +1,154 @@
#!/usr/bin/env python
# SPDX-License-Identifier: ISC
# Copyright (c) 2023 by
# Donatas Abraitis <donatas@opensourcerouting.org>
#
"""
Test if Add-Path best selected paths are announced per neighbor.
"""
import os
import sys
import json
import pytest
import functools
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
pytestmark = [pytest.mark.bgpd]
def build_topo(tgen):
for routern in range(1, 8):
tgen.add_router("r{}".format(routern))
switch = tgen.add_switch("s1")
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r2"])
switch = tgen.add_switch("s2")
switch.add_link(tgen.gears["r2"])
switch.add_link(tgen.gears["r3"])
switch.add_link(tgen.gears["r4"])
switch.add_link(tgen.gears["r5"])
switch.add_link(tgen.gears["r6"])
switch = tgen.add_switch("s3")
switch.add_link(tgen.gears["r7"])
switch.add_link(tgen.gears["r2"])
def setup_module(mod):
tgen = Topogen(build_topo, mod.__name__)
tgen.start_topology()
router_list = tgen.routers()
for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
router.load_config(
TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
)
tgen.start_router()
def teardown_module(mod):
tgen = get_topogen()
tgen.stop_topology()
def test_bgp_addpath_best_selected():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
r2 = tgen.gears["r2"]
def check_bgp_advertised_routes_to_r1():
output = json.loads(
r2.vtysh_cmd(
"show bgp ipv4 neighbors 192.168.1.1 advertised-routes detail json"
)
)
expected = {
"advertisedRoutes": {
"172.16.16.254/32": {
"paths": [
{
"aspath": {
"string": "65005",
}
},
{
"aspath": {
"string": "65006",
}
},
]
}
},
"totalPrefixCounter": 2,
}
return topotest.json_cmp(output, expected)
test_func = functools.partial(check_bgp_advertised_routes_to_r1)
success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert (
result is None
), "Received more/less Add-Path best paths, but should be only 1+1 (real best path)"
def check_bgp_advertised_routes_to_r7():
output = json.loads(
r2.vtysh_cmd(
"show bgp ipv4 neighbors 192.168.7.7 advertised-routes detail json"
)
)
expected = {
"advertisedRoutes": {
"172.16.16.254/32": {
"paths": [
{
"aspath": {
"string": "65004",
}
},
{
"aspath": {
"string": "65005",
}
},
{
"aspath": {
"string": "65006",
}
},
]
}
},
"totalPrefixCounter": 3,
}
return topotest.json_cmp(output, expected)
test_func = functools.partial(check_bgp_advertised_routes_to_r7)
success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert (
result is None
), "Received more/less Add-Path best paths, but should be only 2+1 (real best path)"
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))