mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
bgpd: Implement neighbor X addpath-tx-best-selected
command
When using `addpath-tx-all` BGP announces all known paths instead of announcing only an arbitrary number of best paths. With this new command we can send N best paths to the neighbor. That means, we send the best path, then send the second best path excluding the previous one, and so on. In other words, we run best path selection algorithm N times before we finish. Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
This commit is contained in:
parent
0ec8b2d869
commit
78981a80c7
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -556,11 +556,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;
|
||||
|
|
|
@ -886,6 +886,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))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
@ -686,6 +734,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,
|
||||
|
@ -703,10 +755,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);
|
||||
|
|
|
@ -8783,7 +8783,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;
|
||||
}
|
||||
|
||||
|
@ -8816,7 +8816,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;
|
||||
}
|
||||
|
@ -8827,6 +8827,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 <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,
|
||||
neighbor_addpath_tx_bestpath_per_as_cmd,
|
||||
"neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS",
|
||||
|
@ -8842,7 +8881,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;
|
||||
}
|
||||
|
@ -8876,7 +8915,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;
|
||||
}
|
||||
|
@ -17917,6 +17956,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;
|
||||
|
@ -19919,6 +19965,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);
|
||||
|
|
|
@ -1183,7 +1183,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);
|
||||
|
@ -1398,6 +1398,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1790,6 +1790,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);
|
||||
|
|
Loading…
Reference in a new issue