diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index ecb78c1ce403..54197c5920d3 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -1052,6 +1052,7 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn, struct bgp_path_info *bpi_ultimate; struct bgp *bgp_nexthop; struct bgp_table *table; + struct interface *ifp; bool nh_valid; bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi); @@ -1062,6 +1063,15 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn, else bgp_nexthop = bgp_orig; + /* The nexthop is invalid if its VRF does not exist */ + if (bgp_nexthop->vrf_id == VRF_UNKNOWN) + return false; + + /* The nexthop is invalid if its VRF interface is down*/ + ifp = if_get_vrf_loopback(bgp_nexthop->vrf_id); + if (ifp && !if_is_up(ifp)) + return false; + /* * No nexthop tracking for redistributed routes, for * EVPN-imported routes that get leaked, or for routes @@ -1126,8 +1136,8 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, struct bgp_path_info *bpi; struct bgp_path_info *new; struct bgp_path_info_extra *extra; - struct bgp_path_info *parent = source_bpi; struct bgp_labels bgp_labels = {}; + struct bgp *bgp_nexthop; bool labelssame; uint8_t i; @@ -1159,8 +1169,7 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, * match parent */ for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { - if (bpi->extra && bpi->extra->vrfleak && - bpi->extra->vrfleak->parent == parent) + if (bpi->extra && bpi->extra->vrfleak && bpi->extra->vrfleak->parent == source_bpi) break; } @@ -1174,6 +1183,16 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, labelssame = bgp_path_info_labels_same(bpi, bgp_labels.label, bgp_labels.num_labels); + bgp_nexthop = bpi->extra->vrfleak->bgp_orig ?: bgp_orig; + if (bgp_nexthop->vrf_id == VRF_UNKNOWN) { + if (debug) { + zlog_debug("%s: ->%s(s_flags: 0x%x b_flags: 0x%x): %pFX: Found route, origin VRF does not exist, not leaking", + __func__, to_bgp->name_pretty, source_bpi->flags, + bpi->flags, p); + } + return NULL; + } + if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED) && CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { if (debug) { @@ -1185,9 +1204,11 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, return NULL; } - if (attrhash_cmp(bpi->attr, new_attr) && labelssame - && !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { - + if (attrhash_cmp(bpi->attr, new_attr) && labelssame && + !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && + leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi, source_bpi, bpi, + bgp_orig, p, + debug) == !!CHECK_FLAG(bpi->flags, BGP_PATH_VALID)) { bgp_attr_unintern(&new_attr); if (debug) zlog_debug( @@ -1274,6 +1295,14 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, return NULL; } + if (bgp_orig->vrf_id == VRF_UNKNOWN) { + if (debug) { + zlog_debug("%s: ->%s(s_flags: 0x%x): %pFX: New route, origin VRF does not exist, not leaking", + __func__, to_bgp->name_pretty, source_bpi->flags, p); + } + return NULL; + } + new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0, to_bgp->peer_self, new_attr, bn); @@ -1297,9 +1326,8 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, if (bgp_labels.num_labels) new->extra->labels = bgp_labels_intern(&bgp_labels); - new->extra->vrfleak->parent = bgp_path_info_lock(parent); - bgp_dest_lock_node( - (struct bgp_dest *)parent->net); + new->extra->vrfleak->parent = bgp_path_info_lock(source_bpi); + bgp_dest_lock_node((struct bgp_dest *)source_bpi->net); new->extra->vrfleak->bgp_orig = bgp_lock(bgp_orig); diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py index be3e07929a0f..59cfc4ea0896 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py @@ -78,6 +78,13 @@ def setup_module(mod): "tcpdump -nni r1-eth0 -s 0 -w {} &".format(pcap_file), stdout=None ) + tgen.net["r2"].cmd( + """ +ip link add vrf1 type vrf table 10 +ip link set vrf1 up +""" + ) + for rname, router in tgen.routers().items(): logger.info("Loading router %s" % rname) router.load_frr_config( diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf index d3ababde3a81..e3f8b242a142 100644 --- a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf @@ -1,3 +1,7 @@ +vrf DONNA + ip route 172.16.3.0/24 10.0.0.254 +exit-vrf +! int dummy0 ip address 10.0.4.1/24 no shut @@ -28,6 +32,9 @@ ip router-id 10.0.4.1 ! router bgp 99 no bgp ebgp-requires-policy + ! 10.0.4.254 peer session will not be established + ! it is there just to activate the ipv4 vpn table + neighbor 10.0.4.254 remote-as external address-family ipv4 unicast redistribute connected rd vpn export 10.0.4.1:1 @@ -36,11 +43,14 @@ router bgp 99 export vpn import vpn ! + address-family ipv4 vpn + neighbor 10.0.4.254 activate ! router bgp 99 vrf DONNA no bgp ebgp-requires-policy address-family ipv4 unicast redistribute connected + network 172.16.3.0/24 label vpn export 101 rd vpn export 10.0.4.1:1 rt vpn export 10.0.4.1:101 diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_add_zita.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_add_zita.json new file mode 100644 index 000000000000..c7ff2f4f8064 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_add_zita.json @@ -0,0 +1,155 @@ +{ + "routerId": "10.0.4.1", + "localAS": 99, + "routes": { + "routeDistinguishers": { + "10.0.4.1:1": { + "10.0.0.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.1.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.2.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.4.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.101.0/24": [ + { + "valid": null, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "ZITA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + } + } +} + diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_del_donna_prefix.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_del_donna_prefix.json new file mode 100644 index 000000000000..1797d7858232 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_del_donna_prefix.json @@ -0,0 +1,103 @@ +{ + "routerId": "10.0.4.1", + "localAS": 99, + "routes": { + "routeDistinguishers": { + "10.0.4.1:1": { + "10.0.0.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.1.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.2.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.4.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": null, + "172.16.101.0/24": null + } + } + } +} + diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_eva_down.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_eva_down.json new file mode 100644 index 000000000000..4b0eaaa052a3 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_eva_down.json @@ -0,0 +1,120 @@ +{ + "routerId": "10.0.4.1", + "localAS": 99, + "routes": { + "routeDistinguishers": { + "10.0.4.1:1": { + "10.0.0.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.1.0/24": [ + { + "valid": null, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.2.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.3.0/24": [ + { + "valid": null, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.4.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.101.0/24": null + } + } + } +} + diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_init.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_init.json new file mode 100644 index 000000000000..de18bc84638f --- /dev/null +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_init.json @@ -0,0 +1,120 @@ +{ + "routerId": "10.0.4.1", + "localAS": 99, + "routes": { + "routeDistinguishers": { + "10.0.4.1:1": { + "10.0.0.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.1.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.2.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.4.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.101.0/24": null + } + } + } +} + diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_zita_up.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_zita_up.json new file mode 100644 index 000000000000..0c249e241ee5 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_zita_up.json @@ -0,0 +1,137 @@ +{ + "routerId": "10.0.4.1", + "localAS": 99, + "routes": { + "routeDistinguishers": { + "10.0.4.1:1": { + "10.0.0.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.1.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.2.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.4.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.101.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "ZITA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + } + } +} + diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py b/tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py index a44f07b5600e..67e53cb0ccdd 100644 --- a/tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py @@ -13,6 +13,7 @@ Test basic VPNv4 route leaking """ +import json import os import sys from functools import partial @@ -60,6 +61,22 @@ def teardown_module(mod): tgen.stop_topology() +def test_bgp_convergence(): + 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"] + + json_file = "{}/{}/show_bgp_ipv4_vpn_init.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + + def test_vrf_route_leak_donna(): logger.info("Ensure that routes are leaked back and forth") tgen = get_topogen() @@ -119,20 +136,20 @@ def test_vrf_route_leak_donna(): ], }, ], - "172.16.101.0/24": [ + "172.16.3.0/24": [ { - "protocol": "bgp", - "selected": None, + "protocol": "static", + "selected": True, "nexthops": [ { - "fib": None, - "interfaceName": "unknown", - "vrf": "Unknown", - "active": None, - }, + "fib": True, + "interfaceName": "dummy1", + "active": True, + } ], }, ], + "172.16.101.0/24": None, } test_func = partial( @@ -191,20 +208,21 @@ def test_vrf_route_leak_eva(): "protocol": "connected", } ], - "172.16.101.0/24": [ + "172.16.3.0/24": [ { "protocol": "bgp", - "selected": None, + "selected": True, "nexthops": [ { - "fib": None, - "interfaceName": "unknown", - "vrf": "Unknown", - "active": None, - }, + "fib": True, + "interfaceName": "DONNA", + "vrf": "DONNA", + "active": True, + } ], }, ], + "172.16.101.0/24": None, } test_func = partial( @@ -258,6 +276,20 @@ def test_vrf_route_leak_default(): "protocol": "connected", } ], + "172.16.3.0/24": [ + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "DONNA", + "vrf": "DONNA", + "active": True, + } + ], + }, + ], } test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect) @@ -298,34 +330,8 @@ def test_vrf_route_leak_donna_after_eva_down(): # 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, - }, - ], - }, - ], + "10.0.1.0/24": None, + "10.0.3.0/24": None, } test_func = partial( @@ -349,6 +355,14 @@ def check_vrf_table(router, vrf, expect): result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_eva_down.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table 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") @@ -404,6 +418,14 @@ def test_vrf_route_leak_donna_after_eva_up(): result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_init.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table 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") @@ -417,20 +439,7 @@ def test_vrf_route_leak_donna_add_vrf_zita(): # Test DONNA VRF. expect = { - "172.16.101.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "ZITA", - "vrf": "ZITA", - "active": None, - }, - ], - }, - ], + "172.16.101.0/24": None, } test_func = partial( @@ -439,6 +448,14 @@ def test_vrf_route_leak_donna_add_vrf_zita(): result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_add_zita.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table 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") @@ -480,6 +497,14 @@ def test_vrf_route_leak_donna_set_zita_up(): result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_zita_up.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table 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") @@ -502,6 +527,101 @@ def test_vrf_route_leak_donna_delete_vrf_zita(): result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_init.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + + +def test_vrf_route_leak_default_delete_prefix(): + logger.info( + "Remove BGP static prefix 172.16.3.0/24 from VRF DONNA and ensure that the route is deleted on default" + ) + 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 +router bgp 99 vrf DONNA + address-family ipv4 unicast + no network 172.16.3.0/24 +""" + ) + + # Test default VRF. + expect = { + "172.16.3.0/24": None, + } + + test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP VRF default check failed:\n{}".format(diff) + + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_del_donna_prefix.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + + +def test_vrf_route_leak_default_prefix_back(): + logger.info( + "Set back BGP static prefix 172.16.3.0/24 to VRF DONNA and ensure that the route is set on default" + ) + 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 +router bgp 99 vrf DONNA + address-family ipv4 unicast + network 172.16.3.0/24 +""" + ) + + # Test default VRF. + expect = { + "172.16.3.0/24": [ + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "DONNA", + "vrf": "DONNA", + "active": True, + } + ], + }, + ], + } + + test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP VRF default check failed:\n{}".format(diff) + + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_init.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + def test_memory_leak(): "Run the memory leak test and report results." 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 6d4b436bccf9..3bc36862bf76 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 @@ -123,20 +123,7 @@ def test_vrf_route_leak_donna(): ], }, ], - "172.16.101.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "unknown", - "vrf": "Unknown", - "active": None, - }, - ], - }, - ], + "172.16.101.0/24": None, } test_func = partial( @@ -195,20 +182,7 @@ def test_vrf_route_leak_eva(): "protocol": "connected", } ], - "172.16.101.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "unknown", - "vrf": "Unknown", - "active": None, - }, - ], - }, - ], + "172.16.101.0/24": None, } test_func = partial( @@ -302,34 +276,8 @@ def test_vrf_route_leak_donna_after_eva_down(): # 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, - }, - ], - }, - ], + "10.0.1.0/24": None, + "10.0.3.0/24": None, } test_func = partial( @@ -421,20 +369,7 @@ def test_vrf_route_leak_donna_add_vrf_zita(): # Test DONNA VRF. expect = { - "172.16.101.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "ZITA", - "vrf": "ZITA", - "active": None, - }, - ], - }, - ], + "172.16.101.0/24": None, } test_func = partial(