diff --git a/bgpd/bgp_addpath.c b/bgpd/bgp_addpath.c index 7f746541ff..de4b4a48af 100644 --- a/bgpd/bgp_addpath.c +++ b/bgpd/bgp_addpath.c @@ -25,7 +25,14 @@ static const struct bgp_addpath_strategy_names strat_names[BGP_ADDPATH_MAX] = { .human_description = "Advertise bestpath per AS via addpath", .type_json_name = "addpathTxBestpathPerAS", .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 = { @@ -161,6 +168,8 @@ bool bgp_addpath_tx_path(enum bgp_addpath_strat strat, struct bgp_path_info *pi) return true; else return false; + case BGP_ADDPATH_BEST_SELECTED: + return true; case BGP_ADDPATH_MAX: return false; } @@ -356,7 +365,8 @@ void bgp_addpath_type_changed(struct bgp *bgp) * change take effect. */ 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; 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) safi = SAFI_UNICAST; + peer->addpath_best_selected[afi][safi] = paths; + old_type = peer->addpath_type[afi][safi]; if (addpath_type == old_type) return; @@ -411,10 +423,9 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi, tmp_peer)) { if (tmp_peer->addpath_type[afi][safi] == old_type) { - bgp_addpath_set_peer_type(tmp_peer, - afi, - safi, - addpath_type); + bgp_addpath_set_peer_type( + tmp_peer, afi, safi, + addpath_type, paths); } } } diff --git a/bgpd/bgp_addpath.h b/bgpd/bgp_addpath.h index 909a9710c4..2b91d450bc 100644 --- a/bgpd/bgp_addpath.h +++ b/bgpd/bgp_addpath.h @@ -50,7 +50,8 @@ bool bgp_addpath_tx_path(enum bgp_addpath_strat strat, * Change the type of addpath used for a peer. */ 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, safi_t safi); diff --git a/bgpd/bgp_addpath_types.h b/bgpd/bgp_addpath_types.h index 3de9546a6d..8e32b0444a 100644 --- a/bgpd/bgp_addpath_types.h +++ b/bgpd/bgp_addpath_types.h @@ -12,6 +12,7 @@ enum bgp_addpath_strat { BGP_ADDPATH_ALL = 0, BGP_ADDPATH_BEST_PER_AS, + BGP_ADDPATH_BEST_SELECTED, BGP_ADDPATH_MAX, BGP_ADDPATH_NONE, }; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 35b8223644..0b821acfae 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -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. */ -static 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) +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) { const struct prefix *new_p; struct attr *newattr, *existattr; diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index d4837d3f53..ccfd9d00d8 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -910,6 +910,11 @@ extern void bgp_path_info_add_with_caller(const char *caller, struct bgp_dest *dest, struct bgp_path_info *pi); 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) \ bgp_path_info_add_with_caller(__func__, (A), (B)) #define bgp_path_info_free(B) bgp_path_info_free_with_caller(__func__, (B)) diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index a642be935d..0fe6180bea 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -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->orf_plist[afi][safi] = src->orf_plist[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->change_local_as = src->change_local_as; dst->shared_network = src->shared_network; @@ -307,6 +309,7 @@ static void *updgrp_hash_alloc(void *p) * 16. Local-as should match, if configured. * 17. maximum-prefix-out * 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) @@ -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((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->cap & PEER_UPDGRP_CAP_FLAGS), key); key = jhash_1word((peer->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS), key); diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index b412fa6b20..68fd11a042 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -87,6 +87,67 @@ static void adj_free(struct 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, 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 update_subgroup *subgrp; - struct bgp_path_info *pi; afi_t afi; safi_t safi; 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)); UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) { - /* * Skip the subgroups that have coalesce timer running. We will * 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) { subgrp_withdraw_stale_addpath(ctx, subgrp); - for (pi = bgp_dest_get_bgp_path_info(ctx->dest); - pi; pi = pi->next) { - /* 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)); - } + subgrp_announce_addpath_best_selected(ctx->dest, + subgrp); /* Process the bestpath last so the "show [ip] * 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); 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) { 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))) break; - subgroup_process_announce_selected( - subgrp, ri, dest, afi, safi_rib, - bgp_addpath_id_for_peer(peer, afi, safi_rib, - &ri->tx_addpath)); + if (CHECK_FLAG(ri->flags, BGP_PATH_SELECTED)) + subgroup_process_announce_selected( + subgrp, ri, dest, afi, safi_rib, + bgp_addpath_id_for_peer( + peer, afi, safi_rib, + &ri->tx_addpath)); } } UNSET_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 66fb7ae77a..d03398c802 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -8803,7 +8803,7 @@ DEFUN (neighbor_addpath_tx_all_paths, return CMD_WARNING_CONFIG_FAILED; bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty), - BGP_ADDPATH_ALL); + BGP_ADDPATH_ALL, 0); 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_NONE); + BGP_ADDPATH_NONE, 0); return CMD_SUCCESS; } @@ -8847,6 +8847,45 @@ ALIAS_HIDDEN(no_neighbor_addpath_tx_all_paths, NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "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 $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 $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, neighbor_addpath_tx_bestpath_per_as_cmd, "neighbor addpath-tx-bestpath-per-AS", @@ -8862,7 +8901,7 @@ DEFUN (neighbor_addpath_tx_bestpath_per_as, return CMD_WARNING_CONFIG_FAILED; 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; } @@ -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_NONE); + BGP_ADDPATH_NONE, 0); 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", addr); 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_NONE: 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, &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.*/ install_element(BGP_NODE, &neighbor_addpath_tx_bestpath_per_as_hidden_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 6a8e194298..27d9c49efb 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1182,7 +1182,7 @@ static void peer_free(struct peer *peer) bgp_peer_remove_bfd_config(peer); 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) 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], PEER_FLAG_SEND_LARGE_COMMUNITY); peer->addpath_type[afi][safi] = BGP_ADDPATH_NONE; + peer->addpath_best_selected[afi][safi] = 0; peer->soo[afi][safi] = NULL; } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 658bb5a58e..95bc07d167 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1799,6 +1799,9 @@ struct peer { #define BGP_MAX_SOFT_VERSION 64 char *soft_version; + /* Add-Path Best selected paths number to advertise */ + uint8_t addpath_best_selected[AFI_MAX][SAFI_MAX]; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(peer); diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 29d437b396..ff8ff5a96c 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1669,6 +1669,10 @@ Configuring Peers Configure BGP to send best known paths to neighbor in order to preserve multi path capabilities inside a network. +.. clicmd:: neighbor addpath-tx-best-selected (1-6) + + Configure BGP to calculate and send N best known paths to the neighbor. + .. clicmd:: neighbor disable-addpath-rx Do not accept additional paths from this neighbor. diff --git a/tests/topotests/bgp_addpath_best_selected/__init__.py b/tests/topotests/bgp_addpath_best_selected/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_addpath_best_selected/r1/bgpd.conf b/tests/topotests/bgp_addpath_best_selected/r1/bgpd.conf new file mode 100644 index 0000000000..ba10f7bcc0 --- /dev/null +++ b/tests/topotests/bgp_addpath_best_selected/r1/bgpd.conf @@ -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 +! diff --git a/tests/topotests/bgp_addpath_best_selected/r1/zebra.conf b/tests/topotests/bgp_addpath_best_selected/r1/zebra.conf new file mode 100644 index 0000000000..b29940f46a --- /dev/null +++ b/tests/topotests/bgp_addpath_best_selected/r1/zebra.conf @@ -0,0 +1,4 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! diff --git a/tests/topotests/bgp_addpath_best_selected/r2/bgpd.conf b/tests/topotests/bgp_addpath_best_selected/r2/bgpd.conf new file mode 100644 index 0000000000..0c13824323 --- /dev/null +++ b/tests/topotests/bgp_addpath_best_selected/r2/bgpd.conf @@ -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 +! diff --git a/tests/topotests/bgp_addpath_best_selected/r2/zebra.conf b/tests/topotests/bgp_addpath_best_selected/r2/zebra.conf new file mode 100644 index 0000000000..90587d25d4 --- /dev/null +++ b/tests/topotests/bgp_addpath_best_selected/r2/zebra.conf @@ -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 +! diff --git a/tests/topotests/bgp_addpath_best_selected/r3/bgpd.conf b/tests/topotests/bgp_addpath_best_selected/r3/bgpd.conf new file mode 100644 index 0000000000..98eb2e1711 --- /dev/null +++ b/tests/topotests/bgp_addpath_best_selected/r3/bgpd.conf @@ -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 +! diff --git a/tests/topotests/bgp_addpath_best_selected/r3/zebra.conf b/tests/topotests/bgp_addpath_best_selected/r3/zebra.conf new file mode 100644 index 0000000000..417a4844a5 --- /dev/null +++ b/tests/topotests/bgp_addpath_best_selected/r3/zebra.conf @@ -0,0 +1,7 @@ +! +int lo + ip address 172.16.16.254/32 +! +int r3-eth0 + ip address 192.168.2.3/24 +! diff --git a/tests/topotests/bgp_addpath_best_selected/r4/bgpd.conf b/tests/topotests/bgp_addpath_best_selected/r4/bgpd.conf new file mode 100644 index 0000000000..68245c4a21 --- /dev/null +++ b/tests/topotests/bgp_addpath_best_selected/r4/bgpd.conf @@ -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 +! diff --git a/tests/topotests/bgp_addpath_best_selected/r4/zebra.conf b/tests/topotests/bgp_addpath_best_selected/r4/zebra.conf new file mode 100644 index 0000000000..241e38693c --- /dev/null +++ b/tests/topotests/bgp_addpath_best_selected/r4/zebra.conf @@ -0,0 +1,7 @@ +! +int lo + ip address 172.16.16.254/32 +! +int r4-eth0 + ip address 192.168.2.4/24 +! diff --git a/tests/topotests/bgp_addpath_best_selected/r5/bgpd.conf b/tests/topotests/bgp_addpath_best_selected/r5/bgpd.conf new file mode 100644 index 0000000000..0396cc07b4 --- /dev/null +++ b/tests/topotests/bgp_addpath_best_selected/r5/bgpd.conf @@ -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 +! diff --git a/tests/topotests/bgp_addpath_best_selected/r5/zebra.conf b/tests/topotests/bgp_addpath_best_selected/r5/zebra.conf new file mode 100644 index 0000000000..203d229f27 --- /dev/null +++ b/tests/topotests/bgp_addpath_best_selected/r5/zebra.conf @@ -0,0 +1,7 @@ +! +int lo + ip address 172.16.16.254/32 +! +int r5-eth0 + ip address 192.168.2.5/24 +! diff --git a/tests/topotests/bgp_addpath_best_selected/r6/bgpd.conf b/tests/topotests/bgp_addpath_best_selected/r6/bgpd.conf new file mode 100644 index 0000000000..d9e77b66d6 --- /dev/null +++ b/tests/topotests/bgp_addpath_best_selected/r6/bgpd.conf @@ -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 +! diff --git a/tests/topotests/bgp_addpath_best_selected/r6/zebra.conf b/tests/topotests/bgp_addpath_best_selected/r6/zebra.conf new file mode 100644 index 0000000000..894dd30579 --- /dev/null +++ b/tests/topotests/bgp_addpath_best_selected/r6/zebra.conf @@ -0,0 +1,7 @@ +! +int lo + ip address 172.16.16.254/32 +! +int r6-eth0 + ip address 192.168.2.6/24 +! diff --git a/tests/topotests/bgp_addpath_best_selected/r7/bgpd.conf b/tests/topotests/bgp_addpath_best_selected/r7/bgpd.conf new file mode 100644 index 0000000000..090846a458 --- /dev/null +++ b/tests/topotests/bgp_addpath_best_selected/r7/bgpd.conf @@ -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 +! diff --git a/tests/topotests/bgp_addpath_best_selected/r7/zebra.conf b/tests/topotests/bgp_addpath_best_selected/r7/zebra.conf new file mode 100644 index 0000000000..55c70bab8b --- /dev/null +++ b/tests/topotests/bgp_addpath_best_selected/r7/zebra.conf @@ -0,0 +1,4 @@ +! +int r7-eth0 + ip address 192.168.7.7/24 +! diff --git a/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py b/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py new file mode 100644 index 0000000000..dfd538f1c6 --- /dev/null +++ b/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2023 by +# Donatas Abraitis +# + +""" +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))