diff options
| -rw-r--r-- | bgpd/bgp_zebra.c | 22 | ||||
| -rw-r--r-- | tests/topotests/bgp_table_map/r1/frr.conf | 22 | ||||
| -rw-r--r-- | tests/topotests/bgp_table_map/r2/frr.conf | 18 | ||||
| -rw-r--r-- | tests/topotests/bgp_table_map/test_bgp_table_map.py | 129 | 
4 files changed, 186 insertions, 5 deletions
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 8e8616c155..a963c9bd42 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1674,11 +1674,23 @@ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi)  	for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest))  		for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)  			if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && -			    (pi->type == ZEBRA_ROUTE_BGP -			     && (pi->sub_type == BGP_ROUTE_NORMAL -				 || pi->sub_type == BGP_ROUTE_IMPORTED))) -				bgp_zebra_route_install(dest, pi, bgp, true, -							NULL, false); +			    (pi->type == ZEBRA_ROUTE_BGP && (pi->sub_type == BGP_ROUTE_NORMAL || +							     pi->sub_type == BGP_ROUTE_IMPORTED))) { +				bool is_add = true; + +				if (bgp->table_map[afi][safi].name) { +					struct attr local_attr = *pi->attr; +					struct bgp_path_info local_info = *pi; + +					local_info.attr = &local_attr; + +					is_add = bgp_table_map_apply(bgp->table_map[afi][safi].map, +								     bgp_dest_get_prefix(dest), +								     &local_info); +				} + +				bgp_zebra_route_install(dest, pi, bgp, is_add, NULL, false); +			}  }  /* Announce routes of any bgp subtype of a table to zebra */ diff --git a/tests/topotests/bgp_table_map/r1/frr.conf b/tests/topotests/bgp_table_map/r1/frr.conf new file mode 100644 index 0000000000..f74440c384 --- /dev/null +++ b/tests/topotests/bgp_table_map/r1/frr.conf @@ -0,0 +1,22 @@ +! +int r1-eth0 + ip address 10.255.0.1/24 +! +access-list AccList seq 5 permit 10.0.0.1/32 +! +route-map TableMap permit 10 + match ip address AccList +exit +! +router bgp 65001 + bgp router-id 10.255.0.1 + no bgp ebgp-requires-policy + neighbor 10.255.0.2 remote-as external + neighbor 10.255.0.2 timers 1 3 + neighbor 10.255.0.2 timers connect 1 + ! + address-family ipv4 unicast +  table-map TableMap + exit-address-family +exit +! diff --git a/tests/topotests/bgp_table_map/r2/frr.conf b/tests/topotests/bgp_table_map/r2/frr.conf new file mode 100644 index 0000000000..4523fe49ea --- /dev/null +++ b/tests/topotests/bgp_table_map/r2/frr.conf @@ -0,0 +1,18 @@ +! +int r2-eth0 + ip address 10.255.0.2/24 +! +router bgp 65002 + bgp router-id 10.255.0.2 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 10.255.0.1 remote-as external + neighbor 10.255.0.1 timers 1 3 + neighbor 10.255.0.1 timers connect 1 + ! + address-family ipv4 unicast +  network 10.0.0.1/32 +  network 10.0.0.2/32 + exit-address-family +exit +! diff --git a/tests/topotests/bgp_table_map/test_bgp_table_map.py b/tests/topotests/bgp_table_map/test_bgp_table_map.py new file mode 100644 index 0000000000..b10680f741 --- /dev/null +++ b/tests/topotests/bgp_table_map/test_bgp_table_map.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +import functools, json, os, pytest, re, sys + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +from lib import topotest +from lib.topogen import Topogen, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): +    topodef = {"s1": ("r1", "r2")} +    tgen = Topogen(topodef, mod.__name__) +    tgen.start_topology() + +    router_list = tgen.routers() + +    for _, (rname, router) in enumerate(router_list.items(), 1): +        router.load_frr_config( +            os.path.join(CWD, "{}/frr.conf".format(rname)) +        ) + +    tgen.start_router() + + +def teardown_module(mod): +    tgen = get_topogen() +    tgen.stop_topology() + + +def test_bgp_table_map(): +    tgen = get_topogen() + +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    r1 = tgen.gears["r1"] + +    def _bgp_converge(): +        output = json.loads( +            r1.vtysh_cmd( "show bgp ipv4 unicast summary json") +        ) +        expected = { +            "peers": { +                "10.255.0.2": { +                    "remoteAs": 65002, +                    "state": "Established", +                    "peerState": "OK", +                }, +            }, +            "totalPeers": 1, +        } + +        return topotest.json_cmp(output, expected) + +    test_func = functools.partial( +        _bgp_converge, +    ) +    _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) +    assert result is None, "Can't converge initial state" + +    def _bgp_with_table_map(): +        output = json.loads(r1.vtysh_cmd("show ip fib json")) +        expected = { +            "10.0.0.1/32": [], +            "10.0.0.2/32": None, +        } + +        return topotest.json_cmp(output, expected) + +    test_func = functools.partial( +        _bgp_with_table_map, +    ) +    _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) +    assert result is None, "Should contain only one of two shared networks" + +    # +    # Unset table-map +    # +    r1.vtysh_cmd( +        """ +        configure terminal +          router bgp 65001 +            address-family ipv4 unicast +              no table-map TableMap +    """ +    ) + +    def _bgp_without_table_map(): +        output = json.loads(r1.vtysh_cmd("show ip fib json")) +        expected = { +            "10.0.0.1/32": [], +            "10.0.0.2/32": [], +        } + +        return topotest.json_cmp(output, expected) + +    test_func = functools.partial( +        _bgp_without_table_map, +    ) +    _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) +    assert result is None, "Shouldn't contain both shared routes" + +    # +    # Reset table-map +    # +    r1.vtysh_cmd( +        """ +        configure terminal +          router bgp 65001 +            address-family ipv4 unicast +              table-map TableMap +        """ +    ) + +    test_func = functools.partial( +        _bgp_with_table_map, +    ) +    _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) +    assert result is None, "Should contain only one of two shared networks" + + +if __name__ == "__main__": +    args = ["-s"] + sys.argv[1:] +    sys.exit(pytest.main(args))  | 
