From 8b5f6ac98253724c14744a705217f946b4e3cd93 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Fri, 9 Feb 2024 15:55:47 +0100 Subject: [PATCH 1/7] tests: fix duplicates in bgp_vrf_route_leak_basic Test functions were duplicated by mistakes. They were identical. Fixes: 8af61c8a34 ("topotests: test leak from the default vrf") Signed-off-by: Louis Scalbert --- .../test_bgp-vrf-route-leak-basic.py | 143 ------------------ 1 file changed, 143 deletions(-) diff --git a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py index ef813e9541..6f8fd2db82 100644 --- a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py +++ b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py @@ -214,149 +214,6 @@ def test_vrf_route_leak_eva(): assert result, "BGP VRF EVA check failed:\n{}".format(diff) -def test_vrf_route_leak_donna(): - logger.info("Ensure that routes are leaked back and forth") - tgen = get_topogen() - # Don't run this test if we have any failure. - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - r1 = tgen.gears["r1"] - - # Test DONNA VRF. - expect = { - "10.0.0.0/24": [ - { - "protocol": "connected", - } - ], - "10.0.1.0/24": [ - { - "protocol": "bgp", - "selected": True, - "nexthops": [ - { - "fib": True, - "interfaceName": "EVA", - "vrf": "EVA", - "active": True, - }, - ], - }, - ], - "10.0.2.0/24": [{"protocol": "connected"}], - "10.0.3.0/24": [ - { - "protocol": "bgp", - "selected": True, - "nexthops": [ - { - "fib": True, - "interfaceName": "EVA", - "vrf": "EVA", - "active": True, - }, - ], - }, - ], - "10.0.4.0/24": [ - { - "protocol": "bgp", - "selected": True, - "nexthops": [ - { - "fib": True, - "interfaceName": "lo", - "vrf": "default", - "active": True, - }, - ], - }, - ], - "172.16.101.0/24": [ - { - "protocol": "bgp", - "nexthops": [ - { - "interfaceIndex": 0, - "interfaceName": "unknown", - "vrf": "Unknown", - }, - ], - }, - ], - } - - test_func = partial( - topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect - ) - result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) - assert result, "BGP VRF DONNA check failed:\n{}".format(diff) - - -def test_vrf_route_leak_eva(): - logger.info("Ensure that routes are leaked back and forth") - tgen = get_topogen() - # Don't run this test if we have any failure. - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - r1 = tgen.gears["r1"] - - # Test EVA VRF. - expect = { - "10.0.0.0/24": [ - { - "protocol": "bgp", - "selected": True, - "nexthops": [ - { - "fib": True, - "interfaceName": "DONNA", - "vrf": "DONNA", - "active": True, - }, - ], - }, - ], - "10.0.1.0/24": [ - { - "protocol": "connected", - } - ], - "10.0.2.0/24": [ - { - "protocol": "bgp", - "selected": True, - "nexthops": [ - { - "fib": True, - "interfaceName": "DONNA", - "vrf": "DONNA", - "active": True, - }, - ], - }, - ], - "10.0.3.0/24": [ - { - "protocol": "connected", - } - ], - "172.16.101.0/24": [ - { - "protocol": "bgp", - "nexthops": [ - { - "interfaceIndex": 0, - "interfaceName": "unknown", - "vrf": "Unknown", - }, - ], - }, - ], - } - def test_vrf_route_leak_default(): logger.info("Ensure that routes are leaked back and forth") From 71e74df14ec98e141a220593cdab7517cc47274d Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Wed, 14 Feb 2024 16:32:13 +0100 Subject: [PATCH 2/7] tests: add source_addr in check_ping Allow specifying a source_addr in check_ping library function. Signed-off-by: Louis Scalbert --- tests/topotests/lib/checkping.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/topotests/lib/checkping.py b/tests/topotests/lib/checkping.py index aaa6164dd4..5500807fab 100644 --- a/tests/topotests/lib/checkping.py +++ b/tests/topotests/lib/checkping.py @@ -8,7 +8,7 @@ from lib.topolog import logger from lib import topotest -def check_ping(name, dest_addr, expect_connected, count, wait): +def check_ping(name, dest_addr, expect_connected, count, wait, source_addr=None): """ Assert that ping to dest_addr is expected * 'name': the router to set the ping from @@ -18,9 +18,13 @@ def check_ping(name, dest_addr, expect_connected, count, wait): * 'wait': how long ping should wait to receive all replies """ - def _check(name, dest_addr, match): + def _check(name, dest_addr, source_addr, match): tgen = get_topogen() - output = tgen.gears[name].run("ping {} -c 1 -w 1".format(dest_addr)) + cmd = "ping {}".format(dest_addr) + if source_addr: + cmd += " -I {}".format(source_addr) + cmd += " -c 1 -w 1" + output = tgen.gears[name].run(cmd) logger.info(output) if match not in output: return "ping fail" @@ -28,6 +32,6 @@ def check_ping(name, dest_addr, expect_connected, count, wait): match = ", {} packet loss".format("0%" if expect_connected else "100%") logger.info("[+] check {} {} {}".format(name, dest_addr, match)) tgen = get_topogen() - func = functools.partial(_check, name, dest_addr, match) + func = functools.partial(_check, name, dest_addr, source_addr, match) success, result = topotest.run_and_expect(func, None, count=count, wait=wait) assert result is None, "Failed" From c102adde305f6cc823134235bad9ad9ede31318d Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Wed, 14 Feb 2024 16:35:51 +0100 Subject: [PATCH 3/7] tests: use check_ping in bgp_vrf_route_leak_basic Use check_ping in bgp_vrf_route_leak_basic Signed-off-by: Louis Scalbert --- .../test_bgp-vrf-route-leak-basic.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py index 6f8fd2db82..1915717ac5 100644 --- a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py +++ b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py @@ -24,7 +24,7 @@ sys.path.append(os.path.join(CWD, "../")) from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger - +from lib.checkping import check_ping pytestmark = [pytest.mark.bgpd] @@ -278,8 +278,7 @@ def test_ping(): r1 = tgen.gears["r1"] logger.info("Ping from default to DONNA") - output = r1.run("ping -c 4 -w 4 -I 10.0.4.1 10.0.0.1") - assert " 0% packet loss" in output, "Ping default->DONNA FAILED" + check_ping("r1", "10.0.0.1", True, 10, 0.5, source_addr="10.0.4.1") def test_memory_leak(): From b45c5cd959ecf859aa11673ab83d169b76988ba2 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Tue, 26 Apr 2022 16:57:45 +0200 Subject: [PATCH 4/7] bgpd: update route leak when vrf state changes Locally leaked routes remain active after the nexthop VRF interface goes down. Update route leaking when the loopback or a VRF interface state change is received from zebra. Signed-off-by: Louis Scalbert --- bgpd/bgp_attr.c | 12 ++++++++++++ bgpd/bgp_attr.h | 1 + bgpd/bgp_mplsvpn.c | 12 +++++++++++- bgpd/bgp_route.c | 6 ++++++ bgpd/bgp_zebra.c | 16 ++++++++++++++++ 5 files changed, 46 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index edfbc6c835..0dec8ea4e4 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2347,6 +2347,12 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, return BGP_ATTR_PARSE_WITHDRAW; } attr->nh_ifindex = peer->nexthop.ifp->ifindex; + if (if_is_operative(peer->nexthop.ifp)) + SET_FLAG(attr->nh_flags, + BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(attr->nh_flags, + BGP_ATTR_NH_IF_OPERSTATE); } break; case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: @@ -2364,6 +2370,12 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, return BGP_ATTR_PARSE_WITHDRAW; } attr->nh_ifindex = peer->nexthop.ifp->ifindex; + if (if_is_operative(peer->nexthop.ifp)) + SET_FLAG(attr->nh_flags, + BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(attr->nh_flags, + BGP_ATTR_NH_IF_OPERSTATE); } if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index d78f04c6dd..4b6270408e 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -158,6 +158,7 @@ struct attr { uint8_t nh_flags; #define BGP_ATTR_NH_VALID 0x01 +#define BGP_ATTR_NH_IF_OPERSTATE 0x02 /* Path origin attribute */ uint8_t origin; diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index cd5cf5be54..91bc3b1a88 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -2093,8 +2093,9 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ struct bgp_path_info *bpi; int origin_local = 0; struct bgp *src_vrf; - struct interface *ifp; + struct interface *ifp = NULL; char rd_buf[RD_ADDRSTRLEN]; + int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) { @@ -2260,6 +2261,15 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ break; } + if (!ifp && static_attr.nh_ifindex) + ifp = if_lookup_by_index(static_attr.nh_ifindex, + src_vrf->vrf_id); + + if (ifp && if_is_operative(ifp)) + SET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); + /* * route map handling */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f0c5de074d..b6a000b138 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -8569,6 +8569,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, afi_t afi; route_map_result_t ret; struct bgp_redist *red; + struct interface *ifp; if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) || bgp->peer_self == NULL) @@ -8628,6 +8629,11 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, } attr.nh_type = nhtype; attr.nh_ifindex = ifindex; + ifp = if_lookup_by_index(ifindex, bgp->vrf_id); + if (ifp && if_is_operative(ifp)) + SET_FLAG(attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); attr.med = metric; attr.distance = distance; diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 1172514e52..54b792af29 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -235,6 +235,14 @@ static int bgp_ifp_up(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_up(ifp); + if (bgp_get_default() && if_is_loopback(ifp)) { + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } @@ -282,6 +290,14 @@ static int bgp_ifp_down(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_down(ifp); + if (bgp_get_default() && if_is_loopback(ifp)) { + vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } From 5709e89f6c6a11154b8c89664a49d4d239b4fc8c Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Fri, 9 Feb 2024 15:47:40 +0100 Subject: [PATCH 5/7] tests: check route leak after changing vrf state Check that local route leaks are set to "inactive" when the VRF interface is shutdown and, conversely, that they are set to "active" when the VRF interface is unshut. Signed-off-by: Louis Scalbert --- .../test_bgp-vrf-route-leak-basic.py | 111 +++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py index 1915717ac5..4df799a5fd 100644 --- a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py +++ b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py @@ -214,7 +214,6 @@ def test_vrf_route_leak_eva(): assert result, "BGP VRF EVA check failed:\n{}".format(diff) - def test_vrf_route_leak_default(): logger.info("Ensure that routes are leaked back and forth") tgen = get_topogen() @@ -281,6 +280,116 @@ def test_ping(): check_ping("r1", "10.0.0.1", True, 10, 0.5, source_addr="10.0.4.1") +def test_vrf_route_leak_donna_after_eva_down(): + logger.info("Ensure that route states change after EVA interface goes down") + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + """ +configure +interface EVA + shutdown +""" + ) + + # Test DONNA VRF. + expect = { + "10.0.1.0/24": [ + { + "protocol": "bgp", + "selected": None, + "nexthops": [ + { + "fib": None, + "interfaceName": "EVA", + "vrf": "EVA", + "active": None, + }, + ], + }, + ], + "10.0.3.0/24": [ + { + "protocol": "bgp", + "selected": None, + "nexthops": [ + { + "fib": None, + "interfaceName": "EVA", + "vrf": "EVA", + "active": None, + }, + ], + }, + ], + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect + ) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + + +def test_vrf_route_leak_donna_after_eva_up(): + logger.info("Ensure that route states change after EVA interface goes up") + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + """ +configure +interface EVA + no shutdown +""" + ) + + # Test DONNA VRF. + expect = { + "10.0.1.0/24": [ + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "EVA", + "vrf": "EVA", + "active": True, + }, + ], + }, + ], + "10.0.3.0/24": [ + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "EVA", + "vrf": "EVA", + "active": True, + }, + ], + }, + ], + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect + ) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() From 94d12dc490d7c4109828e7d4421e7ae0d84c3448 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Fri, 9 Feb 2024 16:28:23 +0100 Subject: [PATCH 6/7] bgpd: update route leak when vrf appears If the VRF is not yet created and a BGP instance is created for the VRF, dependent leaked routes are inactive, which is normal. However, when the VRF interface appears, they remains inactive. Update route leak when a VRF interface appears. Note that routes to a deleted VRF are already removed by zebra. Signed-off-by: Louis Scalbert --- bgpd/bgp_zebra.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 54b792af29..0304c4383f 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -3160,6 +3160,15 @@ static int bgp_ifp_create(struct interface *ifp) bgp_update_interface_nbrs(bgp, ifp, ifp); hook_call(bgp_vrf_status_changed, bgp, ifp); + + if (bgp_get_default() && if_is_loopback(ifp)) { + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } From 1262ee66ad43e76f98133f1c53842fd9021a4dd5 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Fri, 9 Feb 2024 16:28:18 +0100 Subject: [PATCH 7/7] tests: check route leak update after vrf creation and deletion Ensure that a locally leaked route is updated after a VRF (dis)appears. Signed-off-by: Louis Scalbert --- .../bgp_vrf_route_leak_basic/r1/bgpd.conf | 6 +- .../test_bgp-vrf-route-leak-basic.py | 106 +++++++++++++++++- 2 files changed, 107 insertions(+), 5 deletions(-) diff --git a/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf b/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf index f52f56b0e0..397f7938d2 100644 --- a/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf +++ b/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf @@ -12,7 +12,7 @@ router bgp 99 vrf DONNA address-family ipv4 unicast redistribute connected import vrf EVA - import vrf NOTEXISTING + import vrf ZITA import vrf default ! ! @@ -21,10 +21,10 @@ router bgp 99 vrf EVA address-family ipv4 unicast redistribute connected import vrf DONNA - import vrf NOTEXISTING + import vrf ZITA ! ! -router bgp 99 vrf NOTEXISTING +router bgp 99 vrf ZITA no bgp ebgp-requires-policy no bgp network import-check address-family ipv4 unicast diff --git a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py index 4df799a5fd..013ddfece9 100644 --- a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py +++ b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py @@ -126,11 +126,13 @@ def test_vrf_route_leak_donna(): "172.16.101.0/24": [ { "protocol": "bgp", + "selected": None, "nexthops": [ { - "interfaceIndex": 0, + "fib": None, "interfaceName": "unknown", "vrf": "Unknown", + "active": None, }, ], }, @@ -196,11 +198,13 @@ def test_vrf_route_leak_eva(): "172.16.101.0/24": [ { "protocol": "bgp", + "selected": None, "nexthops": [ { - "interfaceIndex": 0, + "fib": None, "interfaceName": "unknown", "vrf": "Unknown", + "active": None, }, ], }, @@ -390,6 +394,104 @@ interface EVA assert result, "BGP VRF DONNA check failed:\n{}".format(diff) +def test_vrf_route_leak_donna_add_vrf_zita(): + logger.info("Add VRF ZITA and ensure that the route from VRF ZITA is updated") + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r1.cmd("ip link add ZITA type vrf table 1003") + + # Test DONNA VRF. + expect = { + "172.16.101.0/24": [ + { + "protocol": "bgp", + "selected": None, + "nexthops": [ + { + "fib": None, + "interfaceName": "ZITA", + "vrf": "ZITA", + "active": None, + }, + ], + }, + ], + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect + ) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + + +def test_vrf_route_leak_donna_set_zita_up(): + logger.info("Set VRF ZITA up and ensure that the route from VRF ZITA is updated") + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + """ +configure +interface ZITA + no shutdown +""" + ) + + # Test DONNA VRF. + expect = { + "172.16.101.0/24": [ + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "ZITA", + "vrf": "ZITA", + "active": True, + }, + ], + }, + ], + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect + ) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + + +def test_vrf_route_leak_donna_delete_vrf_zita(): + logger.info("Delete VRF ZITA and ensure that the route from VRF ZITA is deleted") + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r1.cmd("ip link delete ZITA") + + # Test DONNA VRF. + expect = { + "172.16.101.0/24": None, + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect + ) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen()