]> git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[mirror_frr.git] / tests / topotests / bgp_evpn_overlay_index_gateway / test_bgp_evpn_overlay_index_gateway.py
1 #!/usr/bin/env python
2 #
3 # Copyright (c) 2020 by VMware, Inc. ("VMware")
4 # Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF")
5 # in this file.
6 #
7 # Permission to use, copy, modify, and/or distribute this software
8 # for any purpose with or without fee is hereby granted, provided
9 # that the above copyright notice and this permission notice appear
10 # in all copies.
11 #
12 # THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
13 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
15 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
16 # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
17 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
18 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
19 # OF THIS SOFTWARE.
20 #
21
22 """
23 test_bgp_evpn_overlay_index_gateway.py: Test EVPN gateway IP overlay index functionality
24 Following functionality is covered:
25
26 +--------+ BGP +--------+ BGP +--------+ +--------+
27 SN1 | | IPv4/v6 | | EVPN | | | |
28 ======+ Host1 +---------+ PE1 +------+ PE2 +------+ Host2 +
29 | | | | | | | |
30 +--------+ +--------+ +--------+ +--------+
31
32 Host1 is connected to PE1 and host2 is connected to PE2
33 Host1 and PE1 have IPv4/v6 BGP sessions.
34 PE1 and PE2 gave EVPN session.
35 Host1 advertises IPv4/v6 prefixes to PE1.
36 PE1 advertises these prefixes to PE2 as EVPN type-5 routes.
37 Gateway IP for these EVPN type-5 routes is host1 IP.
38 Host1 MAC/IP is advertised by PE1 as EVPN type-2 route
39
40 Following testcases are covered:
41 TC_1:
42 Check BGP and zebra states for above topology at PE1 and PE2.
43
44 TC_2:
45 Stop advertising prefixes from host1. It should withdraw type-5 routes. Check states at PE1 and PE2
46 Advertise the prefixes again. Check states.
47
48 TC_3:
49 Shut down VxLAN interface at PE1. This should withdraw type-2 routes. Check states at PE1 and PE2.
50 Enable VxLAN interface again. Check states.
51 """
52
53 import os
54 import sys
55 import json
56 from functools import partial
57 import pytest
58 import time
59 import platform
60
61 # Current Working Directory
62 CWD = os.path.dirname(os.path.realpath(__file__))
63 sys.path.append(os.path.join(CWD, "../"))
64
65 # pylint: disable=C0413
66 # Import topogen and topotest helpers
67 from lib import topotest
68 from lib.topogen import Topogen, TopoRouter, get_topogen
69 from lib.topolog import logger
70 from lib.common_config import (
71 step,
72 write_test_header,
73 write_test_footer,
74 generate_support_bundle,
75 )
76
77 # Required to instantiate the topology builder class.
78
79 pytestmark = [pytest.mark.bgpd]
80
81
82 # Global variables
83 PES = ["PE1", "PE2"]
84 HOSTS = ["host1", "host2"]
85 PE_SUFFIX = {"PE1": "1", "PE2": "2"}
86 HOST_SUFFIX = {"host1": "1", "host2": "2"}
87 TRIGGERS = ["base", "no_rt5", "no_rt2"]
88
89
90 def build_topo(tgen):
91 # This function only purpose is to define allocation and relationship
92 # between routers and add links.
93
94 # Create routers
95 for pe in PES:
96 tgen.add_router(pe)
97 for host in HOSTS:
98 tgen.add_router(host)
99
100 krel = platform.release()
101 logger.info("Kernel version " + krel)
102
103 # Add links
104 tgen.add_link(tgen.gears["PE1"], tgen.gears["PE2"], "PE1-eth0", "PE2-eth0")
105 tgen.add_link(tgen.gears["PE1"], tgen.gears["host1"], "PE1-eth1", "host1-eth0")
106 tgen.add_link(tgen.gears["PE2"], tgen.gears["host2"], "PE2-eth1", "host2-eth0")
107
108
109 def setup_module(mod):
110 "Sets up the pytest environment"
111
112 testsuite_run_time = time.asctime(time.localtime(time.time()))
113 logger.info("Testsuite start time: {}".format(testsuite_run_time))
114 logger.info("=" * 40)
115
116 logger.info("Running setup_module to create topology")
117
118 # This function initiates the topology build with Topogen...
119 tgen = Topogen(build_topo, mod.__name__)
120 # ... and here it calls Mininet initialization functions.
121
122 kernelv = platform.release()
123 if topotest.version_cmp(kernelv, "4.15") < 0:
124 logger.info(
125 "For EVPN, kernel version should be minimum 4.15. Kernel present {}".format(
126 kernelv
127 )
128 )
129 return
130
131 if topotest.version_cmp(kernelv, "4.15") == 0:
132 l3mdev_accept = 1
133 logger.info("setting net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept))
134 else:
135 l3mdev_accept = 0
136
137 # Starting topology, create tmp files which are loaded to routers
138 # to start daemons and then start routers
139 tgen.start_topology()
140
141 # Configure MAC address for hosts as these MACs are advertised with EVPN type-2 routes
142 for name in tgen.gears:
143 if name not in HOSTS:
144 continue
145 host = tgen.net[name]
146
147 host_mac = "1a:2b:3c:4d:5e:6{}".format(HOST_SUFFIX[name])
148 host.cmd_raises("ip link set dev {}-eth0 down".format(name))
149 host.cmd_raises("ip link set dev {0}-eth0 address {1}".format(name, host_mac))
150 host.cmd_raises("ip link set dev {}-eth0 up".format(name))
151
152 # Configure PE VxLAN and Bridge interfaces
153 for name in tgen.gears:
154 if name not in PES:
155 continue
156 pe = tgen.net[name]
157
158 vtep_ip = "10.100.0.{}".format(PE_SUFFIX[name])
159 bridge_ip = "50.0.1.{}/24".format(PE_SUFFIX[name])
160 bridge_ipv6 = "50:0:1::{}/48".format(PE_SUFFIX[name])
161
162 pe.cmd_raises("ip link add vrf-blue type vrf table 10")
163 pe.cmd_raises("ip link set dev vrf-blue up")
164 pe.cmd_raises(
165 "ip link add vxlan100 type vxlan id 100 dstport 4789 local {}".format(
166 vtep_ip
167 )
168 )
169 pe.cmd_raises("ip link add name br100 type bridge stp_state 0")
170 pe.cmd_raises("ip link set dev vxlan100 master br100")
171 pe.cmd_raises("ip link set dev {}-eth1 master br100".format(name))
172 pe.cmd_raises("ip addr add {} dev br100".format(bridge_ip))
173 pe.cmd_raises("ip link set up dev br100")
174 pe.cmd_raises("ip link set up dev vxlan100")
175 pe.cmd_raises("ip link set up dev {}-eth1".format(name))
176 pe.cmd_raises("ip link set dev br100 master vrf-blue")
177 pe.cmd_raises("ip -6 addr add {} dev br100".format(bridge_ipv6))
178
179 pe.cmd_raises(
180 "ip link add vxlan1000 type vxlan id 1000 dstport 4789 local {}".format(
181 vtep_ip
182 )
183 )
184 pe.cmd_raises("ip link add name br1000 type bridge stp_state 0")
185 pe.cmd_raises("ip link set dev vxlan1000 master br100")
186 pe.cmd_raises("ip link set up dev br1000")
187 pe.cmd_raises("ip link set up dev vxlan1000")
188 pe.cmd_raises("ip link set dev br1000 master vrf-blue")
189
190 pe.cmd_raises("sysctl -w net.ipv4.ip_forward=1")
191 pe.cmd_raises("sysctl -w net.ipv6.conf.all.forwarding=1")
192 pe.cmd_raises("sysctl -w net.ipv4.udp_l3mdev_accept={}".format(l3mdev_accept))
193 pe.cmd_raises("sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept))
194
195 # For all registered routers, load the zebra configuration file
196 for (name, router) in tgen.routers().items():
197 router.load_config(
198 TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(name))
199 )
200 router.load_config(
201 TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(name))
202 )
203
204 # After loading the configurations, this function loads configured daemons.
205 tgen.start_router()
206
207 logger.info("Running setup_module() done")
208
209 time.sleep(10)
210
211
212 def teardown_module(mod):
213 """Teardown the pytest environment"""
214
215 logger.info("Running teardown_module to delete topology")
216
217 tgen = get_topogen()
218
219 # Stop toplogy and Remove tmp files
220 tgen.stop_topology()
221
222 logger.info(
223 "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
224 )
225 logger.info("=" * 40)
226
227
228 def evpn_gateway_ip_show_op_check(trigger=" "):
229 """
230 This function checks CLI O/P for commands mentioned in show_commands for a given trigger
231 :param trigger: Should be a trigger present in TRIGGERS
232 :return: Returns a tuple (result: None for success, retmsg: Log message to be printed on failure)
233 """
234 tgen = get_topogen()
235
236 if trigger not in TRIGGERS:
237 return "Unexpected trigger", "Unexpected trigger {}".format(trigger)
238
239 show_commands = {
240 "bgp_vni_routes": "show bgp l2vpn evpn route vni 100 json",
241 "bgp_vrf_ipv4": "show bgp vrf vrf-blue ipv4 json",
242 "bgp_vrf_ipv6": "show bgp vrf vrf-blue ipv6 json",
243 "zebra_vrf_ipv4": "show ip route vrf vrf-blue json",
244 "zebra_vrf_ipv6": "show ipv6 route vrf vrf-blue json",
245 }
246
247 for (name, pe) in tgen.gears.items():
248 if name not in PES:
249 continue
250
251 for (cmd_key, command) in show_commands.items():
252 expected_op_file = "{0}/{1}/{2}_{3}.json".format(
253 CWD, name, cmd_key, trigger
254 )
255 expected_op = json.loads(open(expected_op_file).read())
256
257 test_func = partial(topotest.router_json_cmp, pe, command, expected_op)
258 ret, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
259 assertmsg = '"{0}" JSON output mismatch for {1}'.format(name, command)
260 if result is not None:
261 return result, assertmsg
262
263 return None, "Pass"
264
265
266 def test_evpn_gateway_ip_basic_topo(request):
267 """
268 Tets EVPN overlay index gateway IP functionality. VErify show O/Ps on PE1 and PE2
269 """
270
271 tgen = get_topogen()
272 tc_name = request.node.name
273 write_test_header(tc_name)
274
275 # Temporarily Disabled
276 tgen.set_error(
277 "%s: Failing under new micronet framework, please debug and re-enable", tc_name
278 )
279
280 kernelv = platform.release()
281 if topotest.version_cmp(kernelv, "4.15") < 0:
282 logger.info("For EVPN, kernel version should be minimum 4.15")
283 write_test_footer(tc_name)
284 return
285
286 if tgen.routers_have_failure():
287 pytest.skip(tgen.errors)
288
289 step("Check O/Ps for EVPN gateway IP overlay Index functionality at PE1 and PE2")
290
291 result, assertmsg = evpn_gateway_ip_show_op_check("base")
292
293 if result is not None:
294 generate_support_bundle()
295 assert result is None, assertmsg
296
297 write_test_footer(tc_name)
298
299
300 def test_evpn_gateway_ip_flap_rt5(request):
301 """
302 Withdraw EVPN type-5 routes and check O/Ps at PE1 and PE2
303 """
304 tgen = get_topogen()
305 tc_name = request.node.name
306 write_test_header(tc_name)
307
308 kernelv = platform.release()
309 if topotest.version_cmp(kernelv, "4.15") < 0:
310 logger.info("For EVPN, kernel version should be minimum 4.15")
311 write_test_footer(tc_name)
312 return
313
314 if tgen.routers_have_failure():
315 pytest.skip(tgen.errors)
316
317 h1 = tgen.gears["host1"]
318
319 step("Withdraw type-5 routes")
320
321 h1.run(
322 'vtysh -c "config t" \
323 -c "router bgp 111" \
324 -c "address-family ipv4" \
325 -c "no network 100.0.0.21/32"'
326 )
327 h1.run(
328 'vtysh -c "config t" \
329 -c "router bgp 111" \
330 -c "address-family ipv6" \
331 -c "no network 100::21/128"'
332 )
333
334 result, assertmsg = evpn_gateway_ip_show_op_check("no_rt5")
335 if result is not None:
336 generate_support_bundle()
337 assert result is None, assertmsg
338
339 step("Advertise type-5 routes again")
340
341 h1.run(
342 'vtysh -c "config t" \
343 -c "router bgp 111" \
344 -c "address-family ipv4" \
345 -c "network 100.0.0.21/32"'
346 )
347 h1.run(
348 'vtysh -c "config t" \
349 -c "router bgp 111" \
350 -c "address-family ipv6" \
351 -c "network 100::21/128"'
352 )
353
354 result, assertmsg = evpn_gateway_ip_show_op_check("base")
355 if result is not None:
356 generate_support_bundle()
357
358 assert result is None, assertmsg
359
360 write_test_footer(tc_name)
361
362
363 def test_evpn_gateway_ip_flap_rt2(request):
364 """
365 Withdraw EVPN type-2 routes and check O/Ps at PE1 and PE2
366 """
367 tgen = get_topogen()
368 tc_name = request.node.name
369 write_test_header(tc_name)
370
371 kernelv = platform.release()
372 if topotest.version_cmp(kernelv, "4.15") < 0:
373 logger.info("For EVPN, kernel version should be minimum 4.15")
374 write_test_footer(tc_name)
375 return
376
377 if tgen.routers_have_failure():
378 pytest.skip(tgen.errors)
379
380 step("Shut down VxLAN interface at PE1 which results in withdraw of type-2 routes")
381
382 pe1 = tgen.net["PE1"]
383
384 pe1.cmd_raises("ip link set dev vxlan100 down")
385
386 result, assertmsg = evpn_gateway_ip_show_op_check("no_rt2")
387 if result is not None:
388 generate_support_bundle()
389 assert result is None, assertmsg
390
391 step("Bring up VxLAN interface at PE1 and advertise type-2 routes again")
392
393 pe1.cmd_raises("ip link set dev vxlan100 up")
394
395 result, assertmsg = evpn_gateway_ip_show_op_check("base")
396 if result is not None:
397 generate_support_bundle()
398 assert result is None, assertmsg
399
400 write_test_footer(tc_name)
401
402
403 def test_memory_leak():
404 """Run the memory leak test and report results"""
405 tgen = get_topogen()
406 if not tgen.is_memleak_enabled():
407 pytest.skip("Memory leak test/report is disabled")
408
409 tgen.report_memory_leaks()
410
411
412 if __name__ == "__main__":
413 args = ["-s"] + sys.argv[1:]
414 sys.exit(pytest.main(args))