From db731ec6390dd54acbfabbc6654ae9485973cbda Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 7 Jun 2023 22:11:00 +0300 Subject: [PATCH 1/3] doc: Add `neighbor addpath-tx-best-selected` command Signed-off-by: Donatas Abraitis --- doc/user/bgp.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index f045ca239e..7737101947 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. From 0ec8b2d86983fce00875b3d8f8c966955ee11346 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 7 Jun 2023 22:11:32 +0300 Subject: [PATCH 2/3] tests: Test `neighbor X addpath-tx-best-selected` command Signed-off-by: Donatas Abraitis --- .../bgp_addpath_best_selected/__init__.py | 0 .../bgp_addpath_best_selected/r1/bgpd.conf | 7 + .../bgp_addpath_best_selected/r1/zebra.conf | 4 + .../bgp_addpath_best_selected/r2/bgpd.conf | 28 ++++ .../bgp_addpath_best_selected/r2/zebra.conf | 10 ++ .../bgp_addpath_best_selected/r3/bgpd.conf | 9 + .../bgp_addpath_best_selected/r3/zebra.conf | 7 + .../bgp_addpath_best_selected/r4/bgpd.conf | 9 + .../bgp_addpath_best_selected/r4/zebra.conf | 7 + .../bgp_addpath_best_selected/r5/bgpd.conf | 9 + .../bgp_addpath_best_selected/r5/zebra.conf | 7 + .../bgp_addpath_best_selected/r6/bgpd.conf | 9 + .../bgp_addpath_best_selected/r6/zebra.conf | 7 + .../bgp_addpath_best_selected/r7/bgpd.conf | 7 + .../bgp_addpath_best_selected/r7/zebra.conf | 4 + .../test_bgp_addpath_best_selected.py | 154 ++++++++++++++++++ 16 files changed, 278 insertions(+) create mode 100644 tests/topotests/bgp_addpath_best_selected/__init__.py create mode 100644 tests/topotests/bgp_addpath_best_selected/r1/bgpd.conf create mode 100644 tests/topotests/bgp_addpath_best_selected/r1/zebra.conf create mode 100644 tests/topotests/bgp_addpath_best_selected/r2/bgpd.conf create mode 100644 tests/topotests/bgp_addpath_best_selected/r2/zebra.conf create mode 100644 tests/topotests/bgp_addpath_best_selected/r3/bgpd.conf create mode 100644 tests/topotests/bgp_addpath_best_selected/r3/zebra.conf create mode 100644 tests/topotests/bgp_addpath_best_selected/r4/bgpd.conf create mode 100644 tests/topotests/bgp_addpath_best_selected/r4/zebra.conf create mode 100644 tests/topotests/bgp_addpath_best_selected/r5/bgpd.conf create mode 100644 tests/topotests/bgp_addpath_best_selected/r5/zebra.conf create mode 100644 tests/topotests/bgp_addpath_best_selected/r6/bgpd.conf create mode 100644 tests/topotests/bgp_addpath_best_selected/r6/zebra.conf create mode 100644 tests/topotests/bgp_addpath_best_selected/r7/bgpd.conf create mode 100644 tests/topotests/bgp_addpath_best_selected/r7/zebra.conf create mode 100644 tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py 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)) From 78981a80c7457b96e73c108280577d4cbb8aee03 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 7 Jun 2023 22:15:43 +0300 Subject: [PATCH 3/3] 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 --- bgpd/bgp_addpath.c | 23 +++++++--- bgpd/bgp_addpath.h | 3 +- bgpd/bgp_addpath_types.h | 1 + bgpd/bgp_route.c | 10 ++--- bgpd/bgp_route.h | 5 +++ bgpd/bgp_updgrp.c | 4 ++ bgpd/bgp_updgrp_adv.c | 92 +++++++++++++++++++++++++++++++--------- bgpd/bgp_vty.c | 88 ++++++++++++++++++++++++++++++++++++-- bgpd/bgpd.c | 3 +- bgpd/bgpd.h | 3 ++ 10 files changed, 196 insertions(+), 36 deletions(-) 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 7b7a7ad207..67a02249c8 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -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; diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 9bd9e48e22..311d181f90 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -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)) diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index 0b1e54916a..5cb081ba61 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 33617811cf..eea5280410 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" @@ -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); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 04bdba1345..b524df2a1d 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -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 $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", @@ -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); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 99c6a46e7c..5ce5abae4b 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -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; } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 9cb1d51088..3da867a441 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -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);