diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 80f807a1a0..92e7ee5668 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -581,6 +581,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, bool new_proxy; bool new_origin, exist_origin; struct bgp_path_info *bpi_ultimate; + struct peer *peer_new, *peer_exist; *paths_eq = 0; @@ -1397,16 +1398,25 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } /* locally configured routes to advertise do not have su_remote */ - if (new->peer->su_remote == NULL) { + if (new->sub_type == BGP_ROUTE_IMPORTED) { + bpi_ultimate = bgp_get_imported_bpi_ultimate(new); + peer_new = bpi_ultimate->peer; + } else if (new->peer->su_remote == NULL) { *reason = bgp_path_selection_local_configured; return 0; - } - if (exist->peer->su_remote == NULL) { + } else + peer_new = new->peer; + + if (exist->sub_type == BGP_ROUTE_IMPORTED) { + bpi_ultimate = bgp_get_imported_bpi_ultimate(exist); + peer_exist = bpi_ultimate->peer; + } else if (exist->peer->su_remote == NULL) { *reason = bgp_path_selection_local_configured; return 1; - } + } else + peer_exist = exist->peer; - ret = sockunion_cmp(new->peer->su_remote, exist->peer->su_remote); + ret = sockunion_cmp(peer_new->su_remote, peer_exist->su_remote); if (ret == 1) { *reason = bgp_path_selection_neighbor_ip; diff --git a/tests/topotests/bgp_vpnv4_ebgp/r1/bgp_ipv4_routes.json b/tests/topotests/bgp_vpnv4_ebgp/r1/bgp_ipv4_routes.json new file mode 100644 index 0000000000..184ab312b6 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_ebgp/r1/bgp_ipv4_routes.json @@ -0,0 +1,49 @@ +{ + "vrfName": "vrf1", + "localAS": 65500, + "routes": + { + "172.31.0.10/32": [ + { + "prefix": "172.31.0.10", + "prefixLen": 32, + "network": "172.31.0.10\/32", + "nhVrfName": "default", + "nexthops": [ + { + "ip": "192.168.0.3", + "afi": "ipv4", + "used": true + } + ] + }, + { + "prefix": "172.31.0.10", + "prefixLen": 32, + "network": "172.31.0.10\/32", + "nhVrfName": "default", + "nexthops": [ + { + "ip": "192.168.0.2", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.31.0.1/32": [ + { + "prefix": "172.31.0.1", + "prefixLen": 32, + "network": "172.31.0.1\/32", + "nexthops": [ + { + "ip": "0.0.0.0", + "afi": "ipv4", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_vpnv4_ebgp/r1/bgpd.conf b/tests/topotests/bgp_vpnv4_ebgp/r1/bgpd.conf index 2eebe5e6dd..0249279c65 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/r1/bgpd.conf +++ b/tests/topotests/bgp_vpnv4_ebgp/r1/bgpd.conf @@ -1,16 +1,19 @@ router bgp 65500 - bgp router-id 1.1.1.1 + bgp router-id 192.0.2.1 no bgp ebgp-requires-policy - neighbor 10.125.0.2 remote-as 65501 + neighbor 192.168.0.2 remote-as 65501 + neighbor 192.168.0.3 remote-as 65501 address-family ipv4 unicast - no neighbor 10.125.0.2 activate + no neighbor 192.168.0.3 activate + no neighbor 192.168.0.2 activate exit-address-family address-family ipv4 vpn - neighbor 10.125.0.2 activate + neighbor 192.168.0.2 activate + neighbor 192.168.0.3 activate exit-address-family ! router bgp 65500 vrf vrf1 - bgp router-id 1.1.1.1 + bgp router-id 192.0.2.1 address-family ipv4 unicast redistribute connected label vpn export 101 diff --git a/tests/topotests/bgp_vpnv4_ebgp/r1/ipv4_routes.json b/tests/topotests/bgp_vpnv4_ebgp/r1/ipv4_routes.json index da7d281833..79b020af76 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/r1/ipv4_routes.json +++ b/tests/topotests/bgp_vpnv4_ebgp/r1/ipv4_routes.json @@ -1,8 +1,8 @@ { - "10.200.0.0/24": [ + "172.31.0.10/32": [ { - "prefix": "10.200.0.0/24", - "prefixLen": 24, + "prefix": "172.31.0.10/32", + "prefixLen": 32, "protocol": "bgp", "vrfName": "vrf1", "selected": true, @@ -13,7 +13,19 @@ { "flags": 3, "fib": true, - "ip": "10.125.0.2", + "ip": "192.168.0.2", + "afi": "ipv4", + "interfaceName": "r1-eth0", + "vrf": "default", + "active": true, + "labels":[ + 102 + ] + }, + { + "flags": 3, + "fib": true, + "ip": "192.168.0.3", "afi": "ipv4", "interfaceName": "r1-eth0", "vrf": "default", @@ -25,10 +37,10 @@ ] } ], - "10.201.0.0/24": [ + "172.31.0.1/32": [ { - "prefix": "10.201.0.0/24", - "prefixLen": 24, + "prefix": "172.31.0.1/32", + "prefixLen": 32, "protocol": "connected", "vrfName": "vrf1", "selected": true, diff --git a/tests/topotests/bgp_vpnv4_ebgp/r1/zebra.conf b/tests/topotests/bgp_vpnv4_ebgp/r1/zebra.conf index e9ae4e9831..f626e448a7 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/r1/zebra.conf +++ b/tests/topotests/bgp_vpnv4_ebgp/r1/zebra.conf @@ -1,7 +1,7 @@ log stdout interface r1-eth1 vrf vrf1 - ip address 10.201.0.1/24 + ip address 172.31.0.1/32 ! interface r1-eth0 - ip address 10.125.0.1/24 + ip address 192.168.0.1/24 ! diff --git a/tests/topotests/bgp_vpnv4_ebgp/r2/bgp_ipv4_routes.json b/tests/topotests/bgp_vpnv4_ebgp/r2/bgp_ipv4_routes.json index 19797dd561..1fc3a4b89c 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/r2/bgp_ipv4_routes.json +++ b/tests/topotests/bgp_vpnv4_ebgp/r2/bgp_ipv4_routes.json @@ -3,28 +3,28 @@ "localAS": 65501, "routes": { - "10.201.0.0/24": [ + "172.31.0.1/32": [ { - "prefix": "10.201.0.0", - "prefixLen": 24, - "network": "10.201.0.0\/24", + "prefix": "172.31.0.1", + "prefixLen": 32, + "network": "172.31.0.1\/32", "nhVrfName": "default", "nexthops": [ { - "ip": "10.125.0.1", + "ip": "192.168.0.1", "afi": "ipv4", "used": true } ] } ], - "10.200.0.0/24": [ + "172.31.0.10/32": [ { "valid": true, "bestpath": true, - "prefix": "10.200.0.0", - "prefixLen": 24, - "network": "10.200.0.0\/24", + "prefix": "172.31.0.10", + "prefixLen": 32, + "network": "172.31.0.10\/32", "nexthops": [ { "ip": "0.0.0.0", diff --git a/tests/topotests/bgp_vpnv4_ebgp/r2/bgpd.conf b/tests/topotests/bgp_vpnv4_ebgp/r2/bgpd.conf index e38c99d69c..e873469d79 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/r2/bgpd.conf +++ b/tests/topotests/bgp_vpnv4_ebgp/r2/bgpd.conf @@ -1,16 +1,16 @@ router bgp 65501 - bgp router-id 2.2.2.2 + bgp router-id 192.0.2.2 no bgp ebgp-requires-policy - neighbor 10.125.0.1 remote-as 65500 + neighbor 192.168.0.1 remote-as 65500 address-family ipv4 unicast - no neighbor 10.125.0.1 activate + no neighbor 192.168.0.1 activate exit-address-family address-family ipv4 vpn - neighbor 10.125.0.1 activate + neighbor 192.168.0.1 activate exit-address-family ! router bgp 65501 vrf vrf1 - bgp router-id 2.2.2.2 + bgp router-id 192.0.2.2 address-family ipv4 unicast redistribute connected label vpn export 102 diff --git a/tests/topotests/bgp_vpnv4_ebgp/r2/zebra.conf b/tests/topotests/bgp_vpnv4_ebgp/r2/zebra.conf index 6c433aef2b..bbc524065d 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/r2/zebra.conf +++ b/tests/topotests/bgp_vpnv4_ebgp/r2/zebra.conf @@ -1,7 +1,7 @@ log stdout interface r2-eth1 vrf vrf1 - ip address 10.200.0.2/24 + ip address 172.31.0.10/32 ! interface r2-eth0 - ip address 10.125.0.2/24 + ip address 192.168.0.2/24 ! diff --git a/tests/topotests/bgp_vpnv4_ebgp/r3/bgp_ipv4_routes.json b/tests/topotests/bgp_vpnv4_ebgp/r3/bgp_ipv4_routes.json new file mode 100644 index 0000000000..19797dd561 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_ebgp/r3/bgp_ipv4_routes.json @@ -0,0 +1,38 @@ +{ + "vrfName": "vrf1", + "localAS": 65501, + "routes": + { + "10.201.0.0/24": [ + { + "prefix": "10.201.0.0", + "prefixLen": 24, + "network": "10.201.0.0\/24", + "nhVrfName": "default", + "nexthops": [ + { + "ip": "10.125.0.1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.200.0.0/24": [ + { + "valid": true, + "bestpath": true, + "prefix": "10.200.0.0", + "prefixLen": 24, + "network": "10.200.0.0\/24", + "nexthops": [ + { + "ip": "0.0.0.0", + "afi": "ipv4", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_vpnv4_ebgp/r3/bgpd.conf b/tests/topotests/bgp_vpnv4_ebgp/r3/bgpd.conf new file mode 100644 index 0000000000..a327638c69 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_ebgp/r3/bgpd.conf @@ -0,0 +1,25 @@ +router bgp 65501 + bgp router-id 192.0.2.3 + no bgp ebgp-requires-policy + neighbor 192.168.0.1 remote-as 65500 + address-family ipv4 unicast + no neighbor 192.168.0.1 activate + exit-address-family + address-family ipv4 vpn + neighbor 192.168.0.1 activate + exit-address-family +! +router bgp 65502 vrf vrf1 + bgp router-id 192.0.2.3 + address-family ipv4 unicast + redistribute connected + label vpn export 102 + rd vpn export 444:3 + rt vpn both 52:100 + export vpn + import vpn + exit-address-family +! +interface r3-eth0 + mpls bgp forwarding +! diff --git a/tests/topotests/bgp_vpnv4_ebgp/r3/zebra.conf b/tests/topotests/bgp_vpnv4_ebgp/r3/zebra.conf new file mode 100644 index 0000000000..4412c04a2b --- /dev/null +++ b/tests/topotests/bgp_vpnv4_ebgp/r3/zebra.conf @@ -0,0 +1,7 @@ +log stdout +interface r3-eth1 vrf vrf1 + ip address 172.31.0.10/32 +! +interface r3-eth0 + ip address 192.168.0.3/24 +! diff --git a/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py b/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py index 342bad20ab..61e1163c18 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py +++ b/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py @@ -40,10 +40,12 @@ def build_topo(tgen): # Create 2 routers. tgen.add_router("r1") tgen.add_router("r2") + tgen.add_router("r3") switch = tgen.add_switch("s1") switch.add_link(tgen.gears["r1"]) switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) switch = tgen.add_switch("s2") switch.add_link(tgen.gears["r1"]) @@ -51,27 +53,38 @@ def build_topo(tgen): switch = tgen.add_switch("s3") switch.add_link(tgen.gears["r2"]) + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r3"]) + + def _populate_iface(): tgen = get_topogen() cmds_list = [ - 'ip link add vrf1 type vrf table 10', - 'echo 100000 > /proc/sys/net/mpls/platform_labels', - 'ip link set dev vrf1 up', - 'ip link set dev {0}-eth1 master vrf1', - 'echo 1 > /proc/sys/net/mpls/conf/{0}-eth0/input', + "ip link add vrf1 type vrf table 10", + "echo 100000 > /proc/sys/net/mpls/platform_labels", + "ip link set dev vrf1 up", + "ip link set dev {0}-eth1 master vrf1", + "echo 1 > /proc/sys/net/mpls/conf/{0}-eth0/input", ] for cmd in cmds_list: - input = cmd.format('r1', '1', '2') - logger.info('input: ' + cmd) - output = tgen.net['r1'].cmd(cmd.format('r1', '1', '2')) - logger.info('output: ' + output) + input = cmd.format("r1") + logger.info("input: " + cmd) + output = tgen.net["r1"].cmd(cmd.format("r1")) + logger.info("output: " + output) for cmd in cmds_list: - input = cmd.format('r2', '2', '1') - logger.info('input: ' + cmd) - output = tgen.net['r2'].cmd(cmd.format('r2', '2', '1')) - logger.info('output: ' + output) + input = cmd.format("r2") + logger.info("input: " + cmd) + output = tgen.net["r2"].cmd(cmd.format("r2")) + logger.info("output: " + output) + + for cmd in cmds_list: + input = cmd.format("r3") + logger.info("input: " + cmd) + output = tgen.net["r3"].cmd(cmd.format("r3")) + logger.info("output: " + output) + def setup_module(mod): "Sets up the pytest environment" @@ -109,13 +122,13 @@ def test_protocols_convergence(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - router = tgen.gears['r1'] + router = tgen.gears["r1"] logger.info("Dump some context for r1") router.vtysh_cmd("show bgp ipv4 vpn") router.vtysh_cmd("show bgp summary") router.vtysh_cmd("show bgp vrf vrf1 ipv4") router.vtysh_cmd("show running-config") - router = tgen.gears['r2'] + router = tgen.gears["r2"] logger.info("Dump some context for r2") router.vtysh_cmd("show bgp ipv4 vpn") router.vtysh_cmd("show bgp summary") @@ -124,11 +137,11 @@ def test_protocols_convergence(): # Check IPv4 routing tables on r1 logger.info("Checking IPv4 routes for convergence on r1") - router = tgen.gears['r1'] + router = tgen.gears["r1"] json_file = "{}/{}/ipv4_routes.json".format(CWD, router.name) if not os.path.isfile(json_file): logger.info("skipping file {}".format(json_file)) - assert 0, 'ipv4_routes.json file not found' + assert 0, "ipv4_routes.json file not found" return expected = json.loads(open(json_file).read()) @@ -142,12 +155,12 @@ def test_protocols_convergence(): assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg - # Check BGP IPv4 routing tables on r2 not installed - logger.info("Checking BGP IPv4 routes for convergence on r2") - router = tgen.gears['r2'] + # Check BGP IPv4 routing tables on r1 + logger.info("Checking BGP IPv4 routes for convergence on r1") + router = tgen.gears["r1"] json_file = "{}/{}/bgp_ipv4_routes.json".format(CWD, router.name) if not os.path.isfile(json_file): - assert 0, 'bgp_ipv4_routes.json file not found' + assert 0, "bgp_ipv4_routes.json file not found" expected = json.loads(open(json_file).read()) test_func = partial( @@ -159,7 +172,48 @@ def test_protocols_convergence(): _, result = topotest.run_and_expect(test_func, None, count=40, wait=2) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg - + + # Check BGP IPv4 imported entry is not detected as local + # "selectionReason": "Locally configured route" + donna = tgen.gears["r1"].vtysh_cmd( + "show bgp vrf vrf1 ipv4 172.31.0.10/32 json", isjson=True + ) + routes = donna["paths"] + selectionReasonFound = False + for route in routes: + if "bestpath" not in route.keys(): + continue + if "selectionReason" not in route["bestpath"].keys(): + continue + + if "Locally configured route" == route["bestpath"]["selectionReason"]: + assert 0, "imported prefix has wrong reason detected" + + selectionReasonFound = True + + if not selectionReasonFound: + assertmsg = '"{}" imported prefix has wrong reason detected'.format(router.name) + assert False, assertmsg + + # Check BGP IPv4 routing tables on r2 not installed + logger.info("Checking BGP IPv4 routes for convergence on r2") + router = tgen.gears["r2"] + json_file = "{}/{}/bgp_ipv4_routes.json".format(CWD, router.name) + if not os.path.isfile(json_file): + assert 0, "bgp_ipv4_routes.json file not found" + + expected = json.loads(open(json_file).read()) + test_func = partial( + topotest.router_json_cmp, + router, + "show bgp vrf vrf1 ipv4 json", + expected, + ) + _, result = topotest.run_and_expect(test_func, None, count=40, wait=2) + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen()