def build_topo(tgen):
- for routern in range(1, 4):
+ """
+ All peers are FRR BGP peers except r5 that is a exabgp peer.
+ Exabgp does not send any IPv6 Link-Local nexthop
+
+ r2 is a route-server view RS AS 65000
+ Other routers rX has AS 6500X
+
+ +---+
+ | r3|
+ +---+
+ |
+ 2001:db8:3::0/64
+ |
+ eth1
+ +---+
+ |r2 |
+ +---+
+ eth0
+ |
+ 2001:db8:1::0/64
+ / | \
+ +---+ +---+ +---+
+ | r1| | r4| |r5 |
+ +---+ +---+ +---+
+ """
+
+ for routern in range(1, 5):
tgen.add_router("r{}".format(routern))
- switch = tgen.add_switch("s1")
- switch.add_link(tgen.gears["r1"])
- switch.add_link(tgen.gears["r2"])
+ sw1 = tgen.add_switch("s1")
+ sw1.add_link(tgen.gears["r1"])
+ sw1.add_link(tgen.gears["r2"])
+ sw1.add_link(tgen.gears["r4"])
- switch = tgen.add_switch("s2")
- switch.add_link(tgen.gears["r2"])
- switch.add_link(tgen.gears["r3"])
+ sw2 = tgen.add_switch("s2")
+ sw2.add_link(tgen.gears["r2"])
+ sw2.add_link(tgen.gears["r3"])
+
+ ## Add iBGP ExaBGP neighbor
+ peer_ip = "2001:db8:1::4" ## peer
+ peer_route = "via 2001:db8:1::1" ## router
+ r5 = tgen.add_exabgp_peer("r5", ip=peer_ip, defaultRoute=peer_route)
+ sw1.add_link(r5)
def setup_module(mod):
tgen.start_router()
+ # Start r5 exabgp peer
+ r5 = tgen.gears["r5"]
+ r5.start(os.path.join(CWD, "r5"), os.path.join(CWD, "exabgp.env"))
+
def teardown_module(mod):
tgen = get_topogen()
tgen.stop_topology()
+def get_link_local(rname, ifname, cache):
+ ip = cache.get(rname, {}).get(ifname)
+ if ip:
+ return ip
+
+ tgen = get_topogen()
+ out = tgen.gears[rname].vtysh_cmd("show interface %s json" % ifname, isjson=True)
+ for address in out[ifname]["ipAddresses"]:
+ if not address["address"].startswith("fe80::"):
+ continue
+ ip = address["address"].split("/")[0]
+ cache.setdefault(rname, {})[ifname] = ip
+ return ip
+
+
+def replace_link_local(expected, cache):
+ for prefix, prefix_infos in expected.get("routes", {}).items():
+ for prefix_info in prefix_infos:
+ for nexthop in prefix_info.get("nexthops", []):
+ ip = nexthop.get("ip", "")
+ if not ip.startswith("link-local:"):
+ continue
+ rname = ip.split(":")[1]
+ ifname = ip.split(":")[2]
+ ip = get_link_local(rname, ifname, cache)
+ nexthop["ip"] = ip
+
+
+def check_r2_sub_group(expected):
+ tgen = get_topogen()
+
+ r2 = tgen.gears["r2"]
+
+ output = json.loads(r2.vtysh_cmd("show bgp view RS update-groups json"))
+ actual = [
+ subgroup["peers"]
+ for entry in output.get("RS", {}).values()
+ for subgroup in entry["subGroup"]
+ ]
+
+ return topotest.json_cmp(actual, expected)
+
+
def test_converge_protocols():
"Wait for protocol convergence"
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
+ global link_local_cache
+ link_local_cache = {}
+ router_list = tgen.routers().values()
+ for router in router_list:
+ if router.name == "r2":
+ # route-server
+ cmd = "show bgp view RS ipv6 unicast json"
+ else:
+ cmd = "show bgp ipv6 unicast json"
+
+ # router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name)
+ ref_file = "{}/{}/show_bgp_ipv6_step1.json".format(CWD, router.name)
+ expected = json.loads(open(ref_file).read())
+ replace_link_local(expected, link_local_cache)
+
+ test_func = partial(
+ topotest.router_json_cmp,
+ router,
+ cmd,
+ expected,
+ )
+ _, res = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = "{}: BGP IPv6 table failure".format(router.name)
+ assert res is None, assertmsg
+
+ # check r2 sub-groups
+ expected = [["2001:db8:1::4"], ["2001:db8:1::3", "2001:db8:1::2", "2001:db8:3::2"]]
+
+ test_func = functools.partial(check_r2_sub_group, expected)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Peer group split failed"
+
+
+def test_bgp_route_server_client_step2():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r2 = tgen.gears["r2"]
+ r2.vtysh_cmd(
+ """
+configure terminal
+router bgp 65000 view RS
+ address-family ipv6 unicast
+ neighbor 2001:db8:1::2 nexthop-local unchanged
+ neighbor 2001:db8:1::3 nexthop-local unchanged
+ neighbor 2001:db8:1::4 nexthop-local unchanged
+ neighbor 2001:db8:3::2 nexthop-local unchanged
+"""
+ )
+
router_list = tgen.routers().values()
for router in router_list:
if router.name == "r2":
cmd = "show bgp ipv6 unicast json"
# router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name)
- ref_file = "{}/{}/show_bgp_ipv6.json".format(CWD, router.name)
+ ref_file = "{}/{}/show_bgp_ipv6_step2.json".format(CWD, router.name)
expected = json.loads(open(ref_file).read())
+ replace_link_local(expected, link_local_cache)
test_func = partial(
topotest.router_json_cmp,
assertmsg = "{}: BGP IPv6 table failure".format(router.name)
assert res is None, assertmsg
+ # check r2 sub-groups
+ expected = [
+ ["2001:db8:1::4"],
+ ["2001:db8:1::3", "2001:db8:1::2"],
+ ["2001:db8:3::2"],
+ ]
+
+ test_func = functools.partial(check_r2_sub_group, expected)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Peer group split failed"
+
+
+def test_bgp_route_server_client_step3():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r2 = tgen.gears["r2"]
+ r2.vtysh_cmd(
+ """
+configure terminal
+router bgp 65000 view RS
+ address-family ipv6 unicast
+ no neighbor 2001:db8:1::2 nexthop-local unchanged
+ no neighbor 2001:db8:1::3 nexthop-local unchanged
+ no neighbor 2001:db8:1::4 nexthop-local unchanged
+ no neighbor 2001:db8:3::2 nexthop-local unchanged
+"""
+ )
+
+ global link_local_cache
+ link_local_cache = {}
+ router_list = tgen.routers().values()
+ for router in router_list:
+ if router.name == "r2":
+ # route-server
+ cmd = "show bgp view RS ipv6 unicast json"
+ else:
+ cmd = "show bgp ipv6 unicast json"
+
+ # router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name)
+ ref_file = "{}/{}/show_bgp_ipv6_step1.json".format(CWD, router.name)
+ expected = json.loads(open(ref_file).read())
+ replace_link_local(expected, link_local_cache)
+
+ test_func = partial(
+ topotest.router_json_cmp,
+ router,
+ cmd,
+ expected,
+ )
+ _, res = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = "{}: BGP IPv6 table failure".format(router.name)
+ assert res is None, assertmsg
+
+ # check r2 sub-groups
+ expected = [["2001:db8:1::4"], ["2001:db8:1::3", "2001:db8:1::2", "2001:db8:3::2"]]
+
+ test_func = functools.partial(check_r2_sub_group, expected)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Peer group split failed"
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]