2 # SPDX-License-Identifier: ISC
4 # Copyright (c) 2022, University of Rome Tor Vergata
5 # Authored by Carmine Scarpitta <carmine.scarpitta@uniroma2.it>
15 CWD
= os
.path
.dirname(os
.path
.realpath(__file__
))
16 sys
.path
.append(os
.path
.join(CWD
, "../"))
18 # pylint: disable=C0413
19 # Import topogen and topotest helpers
20 from lib
import topotest
21 from lib
.topogen
import Topogen
, TopoRouter
, get_topogen
22 from lib
.topolog
import logger
23 from lib
.common_config
import required_linux_kernel_version
25 pytestmark
= [pytest
.mark
.bgpd
]
31 tgen
.add_router("ce1")
32 tgen
.add_router("ce2")
33 tgen
.add_router("ce3")
34 tgen
.add_router("ce4")
35 tgen
.add_router("ce5")
36 tgen
.add_router("ce6")
38 tgen
.add_link(tgen
.gears
["r1"], tgen
.gears
["r2"], "eth0", "eth0")
39 tgen
.add_link(tgen
.gears
["ce1"], tgen
.gears
["r1"], "eth0", "eth1")
40 tgen
.add_link(tgen
.gears
["ce2"], tgen
.gears
["r2"], "eth0", "eth1")
41 tgen
.add_link(tgen
.gears
["ce3"], tgen
.gears
["r1"], "eth0", "eth2")
42 tgen
.add_link(tgen
.gears
["ce4"], tgen
.gears
["r2"], "eth0", "eth2")
43 tgen
.add_link(tgen
.gears
["ce5"], tgen
.gears
["r1"], "eth0", "eth3")
44 tgen
.add_link(tgen
.gears
["ce6"], tgen
.gears
["r2"], "eth0", "eth3")
47 def setup_module(mod
):
48 result
= required_linux_kernel_version("5.14")
49 if result
is not True:
50 pytest
.skip("Kernel requirements are not met")
52 tgen
= Topogen(build_topo
, mod
.__name
__)
54 for rname
, router
in tgen
.routers().items():
55 router
.run("/bin/bash {}/{}/setup.sh".format(CWD
, rname
))
57 TopoRouter
.RD_ZEBRA
, os
.path
.join(CWD
, "{}/zebra.conf".format(rname
))
60 TopoRouter
.RD_BGP
, os
.path
.join(CWD
, "{}/bgpd.conf".format(rname
))
63 tgen
.gears
["r1"].run("sysctl net.vrf.strict_mode=1")
64 tgen
.gears
["r1"].run("ip link add vrf10 type vrf table 10")
65 tgen
.gears
["r1"].run("ip link set vrf10 up")
66 tgen
.gears
["r1"].run("ip link add vrf20 type vrf table 20")
67 tgen
.gears
["r1"].run("ip link set vrf20 up")
68 tgen
.gears
["r1"].run("ip link set eth1 master vrf10")
69 tgen
.gears
["r1"].run("ip link set eth2 master vrf10")
70 tgen
.gears
["r1"].run("ip link set eth3 master vrf20")
72 tgen
.gears
["r2"].run("sysctl net.vrf.strict_mode=1")
73 tgen
.gears
["r2"].run("ip link add vrf10 type vrf table 10")
74 tgen
.gears
["r2"].run("ip link set vrf10 up")
75 tgen
.gears
["r2"].run("ip link add vrf20 type vrf table 20")
76 tgen
.gears
["r2"].run("ip link set vrf20 up")
77 tgen
.gears
["r2"].run("ip link set eth1 master vrf10")
78 tgen
.gears
["r2"].run("ip link set eth2 master vrf20")
79 tgen
.gears
["r2"].run("ip link set eth3 master vrf20")
83 def teardown_module(mod
):
88 def open_json_file(filename
):
90 with
open(filename
, "r") as f
:
93 assert False, "Could not read file {}".format(filename
)
96 def check_ping4(name
, dest_addr
, expect_connected
):
97 def _check(name
, dest_addr
, match
):
99 output
= tgen
.gears
[name
].run("ping {} -c 1 -w 1".format(dest_addr
))
101 assert match
in output
, "ping fail"
103 match
= ", {} packet loss".format("0%" if expect_connected
else "100%")
104 logger
.info("[+] check {} {} {}".format(name
, dest_addr
, match
))
106 func
= functools
.partial(_check
, name
, dest_addr
, match
)
107 success
, result
= topotest
.run_and_expect(func
, None, count
=10, wait
=0.5)
108 assert result
is None, "Failed"
111 def check_ping6(name
, dest_addr
, expect_connected
):
112 def _check(name
, dest_addr
, match
):
114 output
= tgen
.gears
[name
].run("ping6 {} -c 1 -w 1".format(dest_addr
))
116 if match
not in output
:
119 match
= "{} packet loss".format("0%" if expect_connected
else "100%")
120 logger
.info("[+] check {} {} {}".format(name
, dest_addr
, match
))
122 func
= functools
.partial(_check
, name
, dest_addr
, match
)
123 success
, result
= topotest
.run_and_expect(func
, None, count
=10, wait
=1)
124 assert result
is None, "Failed"
127 def check_rib(name
, cmd
, expected_file
):
128 def _check(name
, dest_addr
, match
):
129 logger
.info("polling")
131 router
= tgen
.gears
[name
]
132 output
= json
.loads(router
.vtysh_cmd(cmd
))
133 expected
= open_json_file("{}/{}".format(CWD
, expected_file
))
134 return topotest
.json_cmp(output
, expected
)
136 logger
.info('[+] check {} "{}" {}'.format(name
, cmd
, expected_file
))
138 func
= functools
.partial(_check
, name
, cmd
, expected_file
)
139 success
, result
= topotest
.run_and_expect(func
, None, count
=10, wait
=0.5)
140 assert result
is None, "Failed"
144 check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib.json")
145 check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib.json")
146 check_rib("r1", "show ip route vrf vrf10 json", "r1/vrf10v4_rib.json")
147 check_rib("r1", "show ip route vrf vrf20 json", "r1/vrf20v4_rib.json")
148 check_rib("r2", "show ip route vrf vrf10 json", "r2/vrf10v4_rib.json")
149 check_rib("r2", "show ip route vrf vrf20 json", "r2/vrf20v4_rib.json")
150 check_rib("ce1", "show ip route json", "ce1/ip_rib.json")
151 check_rib("ce2", "show ip route json", "ce2/ip_rib.json")
152 check_rib("ce3", "show ip route json", "ce3/ip_rib.json")
153 check_rib("ce4", "show ip route json", "ce4/ip_rib.json")
154 check_rib("ce5", "show ip route json", "ce5/ip_rib.json")
155 check_rib("ce6", "show ip route json", "ce6/ip_rib.json")
157 check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib.json")
158 check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib.json")
159 check_rib("r1", "show ipv6 route vrf vrf10 json", "r1/vrf10v6_rib.json")
160 check_rib("r1", "show ipv6 route vrf vrf20 json", "r1/vrf20v6_rib.json")
161 check_rib("r2", "show ipv6 route vrf vrf10 json", "r2/vrf10v6_rib.json")
162 check_rib("r2", "show ipv6 route vrf vrf20 json", "r2/vrf20v6_rib.json")
163 check_rib("ce1", "show ipv6 route json", "ce1/ipv6_rib.json")
164 check_rib("ce2", "show ipv6 route json", "ce2/ipv6_rib.json")
165 check_rib("ce3", "show ipv6 route json", "ce3/ipv6_rib.json")
166 check_rib("ce4", "show ipv6 route json", "ce4/ipv6_rib.json")
167 check_rib("ce5", "show ipv6 route json", "ce5/ipv6_rib.json")
168 check_rib("ce6", "show ipv6 route json", "ce6/ipv6_rib.json")
172 check_ping4("ce1", "192.168.2.2", True)
173 check_ping4("ce1", "192.168.3.2", True)
174 check_ping4("ce1", "192.168.4.2", False)
175 check_ping4("ce1", "192.168.5.2", False)
176 check_ping4("ce1", "192.168.6.2", False)
177 check_ping4("ce4", "192.168.1.2", False)
178 check_ping4("ce4", "192.168.2.2", False)
179 check_ping4("ce4", "192.168.3.2", False)
180 check_ping4("ce4", "192.168.5.2", True)
181 check_ping4("ce4", "192.168.6.2", True)
183 check_ping6("ce1", "2001:2::2", True)
184 check_ping6("ce1", "2001:3::2", True)
185 check_ping6("ce1", "2001:4::2", False)
186 check_ping6("ce1", "2001:5::2", False)
187 check_ping6("ce1", "2001:6::2", False)
188 check_ping6("ce4", "2001:1::2", False)
189 check_ping6("ce4", "2001:2::2", False)
190 check_ping6("ce4", "2001:3::2", False)
191 check_ping6("ce4", "2001:5::2", True)
192 check_ping6("ce4", "2001:6::2", True)
195 def test_bgp_sid_vpn_export_disable():
196 check_ping4("ce1", "192.168.2.2", True)
197 check_ping6("ce1", "2001:2::2", True)
198 get_topogen().gears
["r1"].vtysh_cmd(
201 router bgp 1 vrf vrf10
203 no sid vpn per-vrf export
207 "r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_sid_vpn_export_disabled.json"
210 "r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_sid_vpn_export_disabled.json"
213 "r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_sid_vpn_export_disabled.json"
216 "r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_sid_vpn_export_disabled.json"
218 check_ping4("ce1", "192.168.2.2", False)
219 check_ping6("ce1", "2001:2::2", False)
222 def test_bgp_sid_vpn_export_reenable():
223 check_ping4("ce1", "192.168.2.2", False)
224 check_ping6("ce1", "2001:2::2", False)
225 get_topogen().gears
["r1"].vtysh_cmd(
228 router bgp 1 vrf vrf10
230 sid vpn per-vrf export auto
234 "r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_sid_vpn_export_reenabled.json"
237 "r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_sid_vpn_export_reenabled.json"
240 "r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_sid_vpn_export_reenabled.json"
243 "r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_sid_vpn_export_reenabled.json"
245 check_ping4("ce1", "192.168.2.2", True)
246 check_ping6("ce1", "2001:2::2", True)
249 def test_locator_delete():
250 check_ping4("ce1", "192.168.2.2", True)
251 check_ping6("ce1", "2001:2::2", True)
252 get_topogen().gears
["r1"].vtysh_cmd(
261 check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_locator_deleted.json")
262 check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_deleted.json")
263 check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json")
264 check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json")
265 check_ping4("ce1", "192.168.2.2", False)
266 check_ping6("ce1", "2001:2::2", False)
269 def test_locator_recreate():
270 check_ping4("ce1", "192.168.2.2", False)
271 check_ping6("ce1", "2001:2::2", False)
272 get_topogen().gears
["r1"].vtysh_cmd(
279 prefix 2001:db8:1:1::/64
282 check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_locator_recreated.json")
283 check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_recreated.json")
284 check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json")
285 check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json")
286 check_ping4("ce1", "192.168.2.2", True)
287 check_ping6("ce1", "2001:2::2", True)
290 def test_bgp_locator_unset():
291 check_ping4("ce1", "192.168.2.2", True)
292 check_ping6("ce1", "2001:2::2", True)
293 get_topogen().gears
["r1"].vtysh_cmd(
301 check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_locator_deleted.json")
302 check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_deleted.json")
303 check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json")
304 check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json")
305 check_ping4("ce1", "192.168.2.2", False)
306 check_ping6("ce1", "2001:2::2", False)
309 def test_bgp_locator_reset():
310 check_ping4("ce1", "192.168.2.2", False)
311 check_ping6("ce1", "2001:2::2", False)
312 get_topogen().gears
["r1"].vtysh_cmd(
320 check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_locator_recreated.json")
321 check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_recreated.json")
322 check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json")
323 check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json")
324 check_ping4("ce1", "192.168.2.2", True)
325 check_ping6("ce1", "2001:2::2", True)
328 def test_bgp_srv6_unset():
329 check_ping4("ce1", "192.168.2.2", True)
330 check_ping6("ce1", "2001:2::2", True)
331 get_topogen().gears
["r1"].vtysh_cmd(
335 no segment-routing srv6
338 check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_locator_deleted.json")
339 check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_deleted.json")
340 check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json")
341 check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json")
342 check_ping4("ce1", "192.168.2.2", False)
343 check_ping6("ce1", "2001:2::2", False)
346 def test_bgp_srv6_reset():
347 check_ping4("ce1", "192.168.2.2", False)
348 check_ping6("ce1", "2001:2::2", False)
349 get_topogen().gears
["r1"].vtysh_cmd(
357 check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_locator_recreated.json")
358 check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_recreated.json")
359 check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json")
360 check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json")
361 check_ping4("ce1", "192.168.2.2", True)
362 check_ping6("ce1", "2001:2::2", True)
365 if __name__
== "__main__":
366 args
= ["-s"] + sys
.argv
[1:]
367 sys
.exit(pytest
.main(args
))