summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_updgrp.c16
-rw-r--r--tests/topotests/bgp_nexthop_ipv6/r1/show_bgp_ipv6_step1.json64
-rw-r--r--tests/topotests/bgp_nexthop_ipv6/r2/show_bgp_ipv6_step1.json64
-rw-r--r--tests/topotests/bgp_nexthop_ipv6/r5/show_bgp_ipv6_step1.json16
-rw-r--r--tests/topotests/bgp_nexthop_ipv6/r6/show_bgp_ipv6_step1.json64
-rw-r--r--tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf5
-rw-r--r--tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py98
-rw-r--r--tests/topotests/bgp_route_server_client/exabgp.env53
-rw-r--r--tests/topotests/bgp_route_server_client/r1/show_bgp_ipv6_step1.json95
-rw-r--r--tests/topotests/bgp_route_server_client/r1/show_bgp_ipv6_step2.json113
-rw-r--r--tests/topotests/bgp_route_server_client/r2/bgpd.conf10
-rw-r--r--tests/topotests/bgp_route_server_client/r2/show_bgp_ipv6_step1.json208
-rw-r--r--tests/topotests/bgp_route_server_client/r2/show_bgp_ipv6_step2.json208
-rw-r--r--tests/topotests/bgp_route_server_client/r2/show_bgp_ipv6_summary.json6
-rw-r--r--tests/topotests/bgp_route_server_client/r3/bgpd.conf1
-rw-r--r--tests/topotests/bgp_route_server_client/r3/show_bgp_ipv6_step1.json84
-rw-r--r--tests/topotests/bgp_route_server_client/r3/show_bgp_ipv6_step2.json96
-rw-r--r--tests/topotests/bgp_route_server_client/r4/bgpd.conf13
-rw-r--r--tests/topotests/bgp_route_server_client/r4/show_bgp_ipv6_step1.json95
-rw-r--r--tests/topotests/bgp_route_server_client/r4/show_bgp_ipv6_step2.json113
-rw-r--r--tests/topotests/bgp_route_server_client/r4/zebra.conf7
-rw-r--r--tests/topotests/bgp_route_server_client/r5/exabgp.cfg16
-rw-r--r--tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py296
-rw-r--r--zebra/interface.c14
24 files changed, 1654 insertions, 101 deletions
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index 90c43b938f..ef03606707 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -455,6 +455,10 @@ static unsigned int updgrp_hash_key_make(const void *p)
key = jhash_1word(jhash(soo_str, strlen(soo_str), SEED1), key);
}
+ if (afi == AFI_IP6 &&
+ (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)))
+ key = jhash(&peer->nexthop.v6_global, IPV6_MAX_BYTELEN, key);
+
/*
* ANY NEW ITEMS THAT ARE ADDED TO THE key, ENSURE DEBUG
* STATEMENT STAYS UP TO DATE
@@ -521,6 +525,12 @@ static unsigned int updgrp_hash_key_make(const void *p)
peer->soo[afi][safi]
? ecommunity_str(peer->soo[afi][safi])
: "(NONE)");
+ zlog_debug("%pBP Update Group Hash: IPv6 nexthop-local unchanged: %d IPv6 global %pI6",
+ peer,
+ afi == AFI_IP6 && (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)),
+ &peer->nexthop.v6_global);
+
zlog_debug("%pBP Update Group Hash key: %u", peer, key);
}
return key;
@@ -655,6 +665,12 @@ static bool updgrp_hash_cmp(const void *p1, const void *p2)
!sockunion_same(&pe1->connection->su, &pe2->connection->su))
return false;
+ if (afi == AFI_IP6 &&
+ (CHECK_FLAG(flags1, PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) ||
+ CHECK_FLAG(flags2, PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)) &&
+ !IPV6_ADDR_SAME(&pe1->nexthop.v6_global, &pe2->nexthop.v6_global))
+ return false;
+
return true;
}
diff --git a/tests/topotests/bgp_nexthop_ipv6/r1/show_bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_ipv6/r1/show_bgp_ipv6_step1.json
index 9923edb348..f468ae1b3e 100644
--- a/tests/topotests/bgp_nexthop_ipv6/r1/show_bgp_ipv6_step1.json
+++ b/tests/topotests/bgp_nexthop_ipv6/r1/show_bgp_ipv6_step1.json
@@ -22,7 +22,13 @@
"ip": "fd00:0:2::2",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r2:eth-sw",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -48,7 +54,13 @@
"ip": "fd00:0:2::4",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r4:eth-sw",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -61,7 +73,13 @@
"ip": "fd00:0:3::5",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:rr:eth-sw",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -74,7 +92,13 @@
"ip": "fd00:0:4::6",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:rr:eth-sw",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -100,7 +124,13 @@
"ip": "fd00:0:2::2",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r2:eth-sw",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -126,7 +156,13 @@
"ip": "fd00:0:2::4",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r4:eth-sw",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -139,7 +175,13 @@
"ip": "fd00:0:3::5",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:rr:eth-sw",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -152,7 +194,13 @@
"ip": "fd00:0:4::6",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:rr:eth-sw",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
diff --git a/tests/topotests/bgp_nexthop_ipv6/r2/show_bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_ipv6/r2/show_bgp_ipv6_step1.json
index bb2efa16d9..824db383a9 100644
--- a/tests/topotests/bgp_nexthop_ipv6/r2/show_bgp_ipv6_step1.json
+++ b/tests/topotests/bgp_nexthop_ipv6/r2/show_bgp_ipv6_step1.json
@@ -9,7 +9,13 @@
"ip": "fd00:0:2::1",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r1:eth-sw",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -48,7 +54,13 @@
"ip": "fd00:0:2::4",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r4:eth-sw",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -61,7 +73,13 @@
"ip": "fd00:0:3::5",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:rr:eth-sw",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -74,7 +92,13 @@
"ip": "fd00:0:4::6",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:rr:eth-sw",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -87,7 +111,13 @@
"ip": "fd00:0:2::1",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r1:eth-sw",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -126,7 +156,13 @@
"ip": "fd00:0:2::4",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r4:eth-sw",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -139,7 +175,13 @@
"ip": "fd00:0:3::5",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:rr:eth-sw",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -152,7 +194,13 @@
"ip": "fd00:0:4::6",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:rr:eth-sw",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
diff --git a/tests/topotests/bgp_nexthop_ipv6/r5/show_bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_ipv6/r5/show_bgp_ipv6_step1.json
index d0875474ae..88e3efb617 100644
--- a/tests/topotests/bgp_nexthop_ipv6/r5/show_bgp_ipv6_step1.json
+++ b/tests/topotests/bgp_nexthop_ipv6/r5/show_bgp_ipv6_step1.json
@@ -47,13 +47,7 @@
"ip": "fd00:0:3::9",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global"
- },
- {
- "ip": "link-local:rr:eth-r5",
- "hostname": "rr",
- "afi": "ipv6",
- "scope": "link-local",
+ "scope": "global",
"used": true
}
]
@@ -155,13 +149,7 @@
"ip": "fd00:0:3::9",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global"
- },
- {
- "ip": "link-local:rr:eth-r5",
- "hostname": "rr",
- "afi": "ipv6",
- "scope": "link-local",
+ "scope": "global",
"used": true
}
]
diff --git a/tests/topotests/bgp_nexthop_ipv6/r6/show_bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_ipv6/r6/show_bgp_ipv6_step1.json
index cd48dd4697..1407eca359 100644
--- a/tests/topotests/bgp_nexthop_ipv6/r6/show_bgp_ipv6_step1.json
+++ b/tests/topotests/bgp_nexthop_ipv6/r6/show_bgp_ipv6_step1.json
@@ -9,7 +9,13 @@
"ip": "fd00:0:2::1",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:rr:eth-r6",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -22,7 +28,13 @@
"ip": "fd00:0:2::2",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:rr:eth-r6",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -48,7 +60,13 @@
"ip": "fd00:0:2::4",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:rr:eth-r6",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -61,7 +79,13 @@
"ip": "fd00:0:3::5",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:rr:eth-r6",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -87,7 +111,13 @@
"ip": "fd00:0:2::1",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:rr:eth-r6",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -100,7 +130,13 @@
"ip": "fd00:0:2::2",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:rr:eth-r6",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -126,7 +162,13 @@
"ip": "fd00:0:2::4",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:rr:eth-r6",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
@@ -139,7 +181,13 @@
"ip": "fd00:0:3::5",
"hostname": "rr",
"afi": "ipv6",
- "scope": "global",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:rr:eth-r6",
+ "hostname": "rr",
+ "afi": "ipv6",
+ "scope": "link-local",
"used": true
}
]
diff --git a/tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf
index 6dcded1525..705ae78b8e 100644
--- a/tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf
+++ b/tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf
@@ -19,12 +19,17 @@ router bgp 65000
neighbor fd00:0:4::6 route-reflector-client
address-family ipv6 unicast
neighbor fd00:0:2::1 route-reflector-client
+ neighbor fd00:0:2::1 nexthop-local unchanged
neighbor fd00:0:2::1 activate
neighbor fd00:0:2::2 route-reflector-client
+ neighbor fd00:0:2::2 nexthop-local unchanged
neighbor fd00:0:2::2 activate
neighbor fd00:0:2::3 route-reflector-client
+ neighbor fd00:0:2::3 nexthop-local unchanged
neighbor fd00:0:2::3 activate
neighbor fd00:0:2::4 nexthop-local unchanged
neighbor fd00:0:2::4 activate
+ neighbor fd00:0:3::5 nexthop-local unchanged
neighbor fd00:0:3::5 activate
+ neighbor fd00:0:4::6 nexthop-local unchanged
neighbor fd00:0:4::6 activate
diff --git a/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py b/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py
index 24d71f5622..e478139eb1 100644
--- a/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py
+++ b/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py
@@ -165,6 +165,21 @@ def replace_link_local(expected, cache):
nexthop["ip"] = ip
+def check_rr_sub_group(expected):
+ tgen = get_topogen()
+
+ rr = tgen.gears["rr"]
+
+ output = json.loads(rr.vtysh_cmd("show bgp update-groups json"))
+ actual = [
+ subgroup["peers"]
+ for entry in output.get("default", {}).values()
+ for subgroup in entry["subGroup"]
+ ]
+
+ return topotest.json_cmp(actual, expected)
+
+
def teardown_module(_mod):
"Teardown the pytest environment"
tgen = get_topogen()
@@ -222,6 +237,19 @@ def test_bgp_ipv6_table_step1():
assertmsg = "{}: BGP IPv6 Nexthop failure".format(router.name)
assert res is None, assertmsg
+ # check rr sub-groups
+ expected = [
+ ["fd00:0:2::1", "fd00:0:2::2"],
+ ["fd00:0:2::3"],
+ ["fd00:0:2::4"],
+ ["fd00:0:3::5"],
+ ["fd00:0:4::6"],
+ ]
+
+ test_func = partial(check_rr_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_ipv6_table_step2():
tgen = get_topogen()
@@ -236,7 +264,12 @@ def test_bgp_ipv6_table_step2():
configure terminal
router bgp 65000
address-family ipv6 unicast
+ no neighbor fd00:0:2::1 nexthop-local unchanged
+ no neighbor fd00:0:2::2 nexthop-local unchanged
+ no neighbor fd00:0:2::3 nexthop-local unchanged
no neighbor fd00:0:2::4 nexthop-local unchanged
+ no neighbor fd00:0:3::5 nexthop-local unchanged
+ no neighbor fd00:0:4::6 nexthop-local unchanged
"""
)
@@ -257,6 +290,71 @@ router bgp 65000
assertmsg = "{}: BGP IPv6 Nexthop failure".format(router.name)
assert res is None, assertmsg
+ # check rr sub-groups
+ expected = [
+ ["fd00:0:2::1", "fd00:0:2::2"],
+ ["fd00:0:2::3"],
+ ["fd00:0:3::5", "fd00:0:2::4"],
+ ["fd00:0:4::6"],
+ ]
+
+ test_func = partial(check_rr_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_ipv6_table_step3():
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ rr = tgen.gears["rr"]
+ rr.vtysh_cmd(
+ """
+configure terminal
+router bgp 65000
+ address-family ipv6 unicast
+ neighbor fd00:0:2::1 nexthop-local unchanged
+ neighbor fd00:0:2::2 nexthop-local unchanged
+ neighbor fd00:0:2::3 nexthop-local unchanged
+ neighbor fd00:0:2::4 nexthop-local unchanged
+ neighbor fd00:0:3::5 nexthop-local unchanged
+ neighbor fd00:0:4::6 nexthop-local unchanged
+"""
+ )
+
+ router_list = tgen.routers().values()
+ for router in router_list:
+ # 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,
+ "show bgp ipv6 unicast json",
+ expected,
+ )
+ _, res = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = "{}: BGP IPv6 Nexthop failure".format(router.name)
+ assert res is None, assertmsg
+
+ # check rr sub-groups
+ expected = [
+ ["fd00:0:2::1", "fd00:0:2::2"],
+ ["fd00:0:2::3"],
+ ["fd00:0:2::4"],
+ ["fd00:0:3::5"],
+ ["fd00:0:4::6"],
+ ]
+
+ test_func = partial(check_rr_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:]
diff --git a/tests/topotests/bgp_route_server_client/exabgp.env b/tests/topotests/bgp_route_server_client/exabgp.env
new file mode 100644
index 0000000000..28e642360a
--- /dev/null
+++ b/tests/topotests/bgp_route_server_client/exabgp.env
@@ -0,0 +1,53 @@
+[exabgp.api]
+encoder = text
+highres = false
+respawn = false
+socket = ''
+
+[exabgp.bgp]
+openwait = 60
+
+[exabgp.cache]
+attributes = true
+nexthops = true
+
+[exabgp.daemon]
+daemonize = true
+pid = '/var/run/exabgp/exabgp.pid'
+user = 'exabgp'
+##daemonize = false
+
+[exabgp.log]
+all = false
+configuration = true
+daemon = true
+destination = '/var/log/exabgp.log'
+enable = true
+level = INFO
+message = false
+network = true
+packets = false
+parser = false
+processes = true
+reactor = true
+rib = false
+routes = false
+short = false
+timers = false
+
+[exabgp.pdb]
+enable = false
+
+[exabgp.profile]
+enable = false
+file = ''
+
+[exabgp.reactor]
+speed = 1.0
+
+[exabgp.tcp]
+acl = false
+bind = ''
+delay = 0
+once = false
+port = 179
diff --git a/tests/topotests/bgp_route_server_client/r1/show_bgp_ipv6_step1.json b/tests/topotests/bgp_route_server_client/r1/show_bgp_ipv6_step1.json
new file mode 100644
index 0000000000..387d7b3374
--- /dev/null
+++ b/tests/topotests/bgp_route_server_client/r1/show_bgp_ipv6_step1.json
@@ -0,0 +1,95 @@
+{
+ "routerId": "10.10.10.1",
+ "localAS": 65001,
+ "routes": {
+ "2001:db8:1::/64": [
+ {
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ },
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::4",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:3::/64": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:3::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::1/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::3/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:3::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::4/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::3",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::5/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::4",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bgp_route_server_client/r1/show_bgp_ipv6_step2.json b/tests/topotests/bgp_route_server_client/r1/show_bgp_ipv6_step2.json
new file mode 100644
index 0000000000..f9e68b8977
--- /dev/null
+++ b/tests/topotests/bgp_route_server_client/r1/show_bgp_ipv6_step2.json
@@ -0,0 +1,113 @@
+{
+ "routerId": "10.10.10.1",
+ "localAS": 65001,
+ "routes": {
+ "2001:db8:1::/64": [
+ {
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ },
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::4",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:3::/64": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:3::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r2:r2-eth0",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::1/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::3/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:3::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r2:r2-eth0",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::4/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::3",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r4:r4-eth0",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::5/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::4",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bgp_route_server_client/r2/bgpd.conf b/tests/topotests/bgp_route_server_client/r2/bgpd.conf
index 3b0a24b8ba..19607660f9 100644
--- a/tests/topotests/bgp_route_server_client/r2/bgpd.conf
+++ b/tests/topotests/bgp_route_server_client/r2/bgpd.conf
@@ -4,14 +4,24 @@ router bgp 65000 view RS
neighbor 2001:db8:1::2 remote-as external
neighbor 2001:db8:1::2 timers 3 10
neighbor 2001:db8:1::2 timers connect 5
+ neighbor 2001:db8:1::3 remote-as external
+ neighbor 2001:db8:1::3 timers 3 10
+ neighbor 2001:db8:1::3 timers connect 5
+ neighbor 2001:db8:1::4 remote-as external
+ neighbor 2001:db8:1::4 timers 3 10
+ neighbor 2001:db8:1::4 timers connect 5
neighbor 2001:db8:3::2 remote-as external
neighbor 2001:db8:3::2 timers 3 10
neighbor 2001:db8:3::2 timers connect 5
address-family ipv6 unicast
redistribute connected
neighbor 2001:db8:1::2 activate
+ neighbor 2001:db8:1::3 activate
+ neighbor 2001:db8:1::4 activate
neighbor 2001:db8:3::2 activate
neighbor 2001:db8:1::2 route-server-client
+ neighbor 2001:db8:1::3 route-server-client
+ neighbor 2001:db8:1::4 route-server-client
neighbor 2001:db8:3::2 route-server-client
exit-address-family
!
diff --git a/tests/topotests/bgp_route_server_client/r2/show_bgp_ipv6_step1.json b/tests/topotests/bgp_route_server_client/r2/show_bgp_ipv6_step1.json
new file mode 100644
index 0000000000..c2f31f8c32
--- /dev/null
+++ b/tests/topotests/bgp_route_server_client/r2/show_bgp_ipv6_step1.json
@@ -0,0 +1,208 @@
+{
+ "routerId": "10.10.10.2",
+ "localAS": 65000,
+ "routes": {
+ "2001:db8:1::/64": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::4",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ },
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::2",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r1:r1-eth0",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ },
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::3",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r4:r4-eth0",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:3::/64": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:3::2",
+ "hostname": "r3",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r3:r3-eth0",
+ "hostname": "r3",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::1/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::2",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r1:r1-eth0",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ },
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::3",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r4:r4-eth0",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::3/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:3::2",
+ "hostname": "r3",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r3:r3-eth0",
+ "hostname": "r3",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::4/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::3",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r4:r4-eth0",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ },
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::2",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r1:r1-eth0",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::5/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::4",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ },
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::2",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r1:r1-eth0",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ },
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::3",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r4:r4-eth0",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bgp_route_server_client/r2/show_bgp_ipv6_step2.json b/tests/topotests/bgp_route_server_client/r2/show_bgp_ipv6_step2.json
new file mode 100644
index 0000000000..c2f31f8c32
--- /dev/null
+++ b/tests/topotests/bgp_route_server_client/r2/show_bgp_ipv6_step2.json
@@ -0,0 +1,208 @@
+{
+ "routerId": "10.10.10.2",
+ "localAS": 65000,
+ "routes": {
+ "2001:db8:1::/64": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::4",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ },
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::2",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r1:r1-eth0",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ },
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::3",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r4:r4-eth0",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:3::/64": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:3::2",
+ "hostname": "r3",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r3:r3-eth0",
+ "hostname": "r3",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::1/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::2",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r1:r1-eth0",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ },
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::3",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r4:r4-eth0",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::3/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:3::2",
+ "hostname": "r3",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r3:r3-eth0",
+ "hostname": "r3",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::4/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::3",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r4:r4-eth0",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ },
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::2",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r1:r1-eth0",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::5/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::4",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ },
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::2",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r1:r1-eth0",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ },
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::3",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r4:r4-eth0",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bgp_route_server_client/r2/show_bgp_ipv6_summary.json b/tests/topotests/bgp_route_server_client/r2/show_bgp_ipv6_summary.json
new file mode 100644
index 0000000000..8a42a11c47
--- /dev/null
+++ b/tests/topotests/bgp_route_server_client/r2/show_bgp_ipv6_summary.json
@@ -0,0 +1,6 @@
+{
+ "ipv6Unicast": {
+ "failedPeers": 0,
+ "totalPeers": 4
+ }
+}
diff --git a/tests/topotests/bgp_route_server_client/r3/bgpd.conf b/tests/topotests/bgp_route_server_client/r3/bgpd.conf
index 60a5ffc559..f7daba87fa 100644
--- a/tests/topotests/bgp_route_server_client/r3/bgpd.conf
+++ b/tests/topotests/bgp_route_server_client/r3/bgpd.conf
@@ -2,6 +2,7 @@
router bgp 65003
bgp router-id 10.10.10.3
no bgp ebgp-requires-policy
+ no bgp enforce-first-as
neighbor 2001:db8:3::1 remote-as external
neighbor 2001:db8:3::1 timers 3 10
neighbor 2001:db8:3::1 timers connect 5
diff --git a/tests/topotests/bgp_route_server_client/r3/show_bgp_ipv6_step1.json b/tests/topotests/bgp_route_server_client/r3/show_bgp_ipv6_step1.json
new file mode 100644
index 0000000000..bf8d74801d
--- /dev/null
+++ b/tests/topotests/bgp_route_server_client/r3/show_bgp_ipv6_step1.json
@@ -0,0 +1,84 @@
+{
+ "routerId": "10.10.10.3",
+ "localAS": 65003,
+ "routes": {
+ "2001:db8:1::/64": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::4",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:3::/64": [
+ {
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r3",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::1/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::3/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r3",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::4/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::3",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::5/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::4",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bgp_route_server_client/r3/show_bgp_ipv6_step2.json b/tests/topotests/bgp_route_server_client/r3/show_bgp_ipv6_step2.json
new file mode 100644
index 0000000000..31c1eb7816
--- /dev/null
+++ b/tests/topotests/bgp_route_server_client/r3/show_bgp_ipv6_step2.json
@@ -0,0 +1,96 @@
+{
+ "routerId": "10.10.10.3",
+ "localAS": 65003,
+ "routes": {
+ "2001:db8:1::/64": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::4",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:3::/64": [
+ {
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r3",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::1/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r2:r2-eth1",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::3/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r3",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::4/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::3",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r2:r2-eth1",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::5/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::4",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bgp_route_server_client/r4/bgpd.conf b/tests/topotests/bgp_route_server_client/r4/bgpd.conf
new file mode 100644
index 0000000000..c907d7284e
--- /dev/null
+++ b/tests/topotests/bgp_route_server_client/r4/bgpd.conf
@@ -0,0 +1,13 @@
+!
+router bgp 65004
+ bgp router-id 10.10.10.4
+ no bgp ebgp-requires-policy
+ no bgp enforce-first-as
+ neighbor 2001:db8:1::1 remote-as external
+ neighbor 2001:db8:1::1 timers 3 10
+ neighbor 2001:db8:1::1 timers connect 5
+ address-family ipv6 unicast
+ redistribute connected
+ neighbor 2001:db8:1::1 activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_route_server_client/r4/show_bgp_ipv6_step1.json b/tests/topotests/bgp_route_server_client/r4/show_bgp_ipv6_step1.json
new file mode 100644
index 0000000000..5c090d9cf9
--- /dev/null
+++ b/tests/topotests/bgp_route_server_client/r4/show_bgp_ipv6_step1.json
@@ -0,0 +1,95 @@
+{
+ "routerId": "10.10.10.4",
+ "localAS": 65004,
+ "routes": {
+ "2001:db8:1::/64": [
+ {
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ },
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::4",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:3::/64": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:3::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::1/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::3/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:3::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::4/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::5/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::4",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bgp_route_server_client/r4/show_bgp_ipv6_step2.json b/tests/topotests/bgp_route_server_client/r4/show_bgp_ipv6_step2.json
new file mode 100644
index 0000000000..01db18e926
--- /dev/null
+++ b/tests/topotests/bgp_route_server_client/r4/show_bgp_ipv6_step2.json
@@ -0,0 +1,113 @@
+{
+ "routerId": "10.10.10.4",
+ "localAS": 65004,
+ "routes": {
+ "2001:db8:1::/64": [
+ {
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ },
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::4",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:3::/64": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:3::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r2:r2-eth0",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::1/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r1:r1-eth0",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::3/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:3::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global"
+ },
+ {
+ "ip": "link-local:r2:r2-eth0",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "link-local",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::4/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r4",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:f::5/128": [
+ {
+ "nexthops": [
+ {
+ "ip": "2001:db8:1::4",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bgp_route_server_client/r4/zebra.conf b/tests/topotests/bgp_route_server_client/r4/zebra.conf
new file mode 100644
index 0000000000..849884045d
--- /dev/null
+++ b/tests/topotests/bgp_route_server_client/r4/zebra.conf
@@ -0,0 +1,7 @@
+!
+int lo
+ ipv6 address 2001:db8:f::4/128
+!
+int r4-eth0
+ ipv6 address 2001:db8:1::3/64
+!
diff --git a/tests/topotests/bgp_route_server_client/r5/exabgp.cfg b/tests/topotests/bgp_route_server_client/r5/exabgp.cfg
new file mode 100644
index 0000000000..b151f16caa
--- /dev/null
+++ b/tests/topotests/bgp_route_server_client/r5/exabgp.cfg
@@ -0,0 +1,16 @@
+neighbor 2001:db8:1::1{
+ router-id 10.10.10.5;
+ local-address 2001:db8:1::4;
+ local-as 65005;
+ peer-as 65000;
+
+ family {
+ ipv6 unicast;
+ }
+
+ static {
+ route 2001:db8:1::0/64 next-hop 2001:db8:1::4;
+ route 2001:db8:f::5/128 next-hop 2001:db8:1::4;
+ }
+ hold-time 10;
+}
diff --git a/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py
index 29d9842d59..a6334918df 100644
--- a/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py
+++ b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py
@@ -13,6 +13,7 @@ import os
import sys
import json
import pytest
+from functools import partial
import functools
pytestmark = [pytest.mark.bgpd]
@@ -26,16 +27,49 @@ from lib.topogen import Topogen, TopoRouter, get_topogen
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"])
+
+ sw2 = tgen.add_switch("s2")
+ sw2.add_link(tgen.gears["r2"])
+ sw2.add_link(tgen.gears["r3"])
- switch = tgen.add_switch("s2")
- switch.add_link(tgen.gears["r2"])
- switch.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):
@@ -54,73 +88,225 @@ 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 test_bgp_route_server_client():
+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"
+
+ 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"]
r2 = tgen.gears["r2"]
+ ref_file = "{}/{}/show_bgp_ipv6_summary.json".format(CWD, r2.name)
+ expected = json.loads(open(ref_file).read())
+
+ test_func = partial(
+ topotest.router_json_cmp,
+ r2,
+ "show bgp view RS ipv6 summary json",
+ expected,
+ )
+ _, res = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = "{}: BGP convergence failed".format(r2.name)
+ assert res is None, assertmsg
+
+
+def test_bgp_route_server_client_step1():
+ tgen = get_topogen()
+
+ 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
- def _bgp_converge(router):
- output = json.loads(router.vtysh_cmd("show bgp ipv6 unicast summary json"))
- expected = {"peers": {"2001:db8:1::1": {"state": "Established", "pfxRcd": 2}}}
- return topotest.json_cmp(output, expected)
+ # 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(_bgp_converge, r1)
+ 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, "Cannot see BGP sessions to be up"
+ assert result is None, "Peer group split failed"
- def _bgp_prefix_received(router):
- output = json.loads(router.vtysh_cmd("show bgp 2001:db8:f::3/128 json"))
- expected = {
- "prefix": "2001:db8:f::3/128",
- "paths": [{"nexthops": [{"ip": "2001:db8:3::2"}]}],
- }
- return topotest.json_cmp(output, expected)
- test_func = functools.partial(_bgp_prefix_received, r1)
+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":
+ # 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_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,
+ 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, "Cannot see BGP GUA next hop from r3 in r1"
-
- def _bgp_single_next_hop(router):
- output = json.loads(router.vtysh_cmd("show bgp 2001:db8:f::3/128 json"))
- return len(output["paths"][0]["nexthops"])
-
- assert (
- _bgp_single_next_hop(r1) == 1
- ), "Not ONLY one Next Hop received for 2001:db8:f::3/128"
-
- def _bgp_gua_lla_next_hop(router):
- output = json.loads(router.vtysh_cmd("show bgp view RS 2001:db8:f::3/128 json"))
- expected = {
- "prefix": "2001:db8:f::3/128",
- "paths": [
- {
- "nexthops": [
- {
- "ip": "2001:db8:3::2",
- "hostname": "r3",
- "afi": "ipv6",
- "scope": "global",
- },
- {"hostname": "r3", "afi": "ipv6", "scope": "link-local"},
- ]
- }
- ],
- }
- return topotest.json_cmp(output, expected)
-
- test_func = functools.partial(_bgp_gua_lla_next_hop, r2)
+ 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, "Cannot see BGP LLA next hop from r3 in r2"
+ assert result is None, "Peer group split failed"
if __name__ == "__main__":
diff --git a/zebra/interface.c b/zebra/interface.c
index d146004781..f1f1b17209 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -1999,10 +1999,9 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx)
!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
/* Add interface notification from kernel */
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- "RTM_NEWLINK ADD for %s(%u) vrf_id %u type %d sl_type %d master %u",
- name, ifindex, vrf_id, zif_type,
- zif_slave_type, master_ifindex);
+ zlog_debug("RTM_NEWLINK ADD for %s(%u) vrf_id %u type %d sl_type %d master %u flags 0x%llx",
+ name, ifindex, vrf_id, zif_type, zif_slave_type,
+ master_ifindex, (unsigned long long)flags);
if (ifp == NULL) {
/* unknown interface */
@@ -2087,10 +2086,9 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx)
/* Interface update. */
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- "RTM_NEWLINK update for %s(%u) sl_type %d master %u",
- name, ifp->ifindex, zif_slave_type,
- master_ifindex);
+ zlog_debug("RTM_NEWLINK update for %s(%u) sl_type %d master %u flags 0x%llx",
+ name, ifp->ifindex, zif_slave_type, master_ifindex,
+ (unsigned long long)flags);
set_ifindex(ifp, ifindex, zns);
ifp->mtu6 = ifp->mtu = mtu;