]> git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py
tests: remove legacy Topo class (fixes many pylint errors)
[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 from lib.micronet_compat import Topo
79
80 pytestmark = [pytest.mark.bgpd]
81
82
83 #Global variables
84 PES = ['PE1', 'PE2']
85 HOSTS = ['host1', 'host2']
86 PE_SUFFIX = {'PE1': '1', 'PE2': '2'}
87 HOST_SUFFIX = {'host1': '1', 'host2': '2'}
88 TRIGGERS = ["base", "no_rt5", "no_rt2"]
89
90
91 def build_topo(tgen):
92 # This function only purpose is to define allocation and relationship
93 # between routers and add links.
94
95 # Create routers
96 for pe in PES:
97 tgen.add_router(pe)
98 for host in HOSTS:
99 tgen.add_router(host)
100
101 krel = platform.release()
102 logger.info('Kernel version ' + krel)
103
104 #Add links
105 tgen.add_link(tgen.gears['PE1'], tgen.gears['PE2'], 'PE1-eth0', 'PE2-eth0')
106 tgen.add_link(tgen.gears['PE1'], tgen.gears['host1'], 'PE1-eth1', 'host1-eth0')
107 tgen.add_link(tgen.gears['PE2'], tgen.gears['host2'], 'PE2-eth1', 'host2-eth0')
108
109
110 def setup_module(mod):
111 "Sets up the pytest environment"
112
113 testsuite_run_time = time.asctime(time.localtime(time.time()))
114 logger.info("Testsuite start time: {}".format(testsuite_run_time))
115 logger.info("=" * 40)
116
117 logger.info("Running setup_module to create topology")
118
119 # This function initiates the topology build with Topogen...
120 tgen = Topogen(build_topo, mod.__name__)
121 # ... and here it calls Mininet initialization functions.
122
123 kernelv = platform.release()
124 if topotest.version_cmp(kernelv, "4.15") < 0:
125 logger.info("For EVPN, kernel version should be minimum 4.15. Kernel present {}".format(kernelv))
126 return
127
128 if topotest.version_cmp(kernelv, '4.15') == 0:
129 l3mdev_accept = 1
130 logger.info('setting net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept))
131 else:
132 l3mdev_accept = 0
133
134 # Starting topology, create tmp files which are loaded to routers
135 # to start deamons and then start routers
136 tgen.start_topology()
137
138 # Configure MAC address for hosts as these MACs are advertised with EVPN type-2 routes
139 for name in tgen.gears:
140 if name not in HOSTS:
141 continue
142 host = tgen.net[name]
143
144 host_mac = "1a:2b:3c:4d:5e:6{}".format(HOST_SUFFIX[name])
145 host.cmd_raises("ip link set dev {}-eth0 down".format(name))
146 host.cmd_raises("ip link set dev {0}-eth0 address {1}".format(name, host_mac))
147 host.cmd_raises("ip link set dev {}-eth0 up".format(name))
148
149 # Configure PE VxLAN and Bridge interfaces
150 for name in tgen.gears:
151 if name not in PES:
152 continue
153 pe = tgen.net[name]
154
155 vtep_ip = "10.100.0.{}".format(PE_SUFFIX[name])
156 bridge_ip = "50.0.1.{}/24".format(PE_SUFFIX[name])
157 bridge_ipv6 = "50:0:1::{}/48".format(PE_SUFFIX[name])
158
159 pe.cmd_raises("ip link add vrf-blue type vrf table 10")
160 pe.cmd_raises("ip link set dev vrf-blue up")
161 pe.cmd_raises(
162 "ip link add vxlan100 type vxlan id 100 dstport 4789 local {}".format(
163 vtep_ip
164 )
165 )
166 pe.cmd_raises("ip link add name br100 type bridge stp_state 0")
167 pe.cmd_raises("ip link set dev vxlan100 master br100")
168 pe.cmd_raises("ip link set dev {}-eth1 master br100".format(name))
169 pe.cmd_raises("ip addr add {} dev br100".format(bridge_ip))
170 pe.cmd_raises("ip link set up dev br100")
171 pe.cmd_raises("ip link set up dev vxlan100")
172 pe.cmd_raises("ip link set up dev {}-eth1".format(name))
173 pe.cmd_raises("ip link set dev br100 master vrf-blue")
174 pe.cmd_raises("ip -6 addr add {} dev br100".format(bridge_ipv6))
175
176 pe.cmd_raises(
177 "ip link add vxlan1000 type vxlan id 1000 dstport 4789 local {}".format(
178 vtep_ip
179 )
180 )
181 pe.cmd_raises("ip link add name br1000 type bridge stp_state 0")
182 pe.cmd_raises("ip link set dev vxlan1000 master br100")
183 pe.cmd_raises("ip link set up dev br1000")
184 pe.cmd_raises("ip link set up dev vxlan1000")
185 pe.cmd_raises("ip link set dev br1000 master vrf-blue")
186
187 pe.cmd_raises("sysctl -w net.ipv4.ip_forward=1")
188 pe.cmd_raises("sysctl -w net.ipv6.conf.all.forwarding=1")
189 pe.cmd_raises("sysctl -w net.ipv4.udp_l3mdev_accept={}".format(l3mdev_accept))
190 pe.cmd_raises("sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept))
191
192 # For all registred routers, load the zebra configuration file
193 for (name, router) in tgen.routers().items():
194 router.load_config(
195 TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(name))
196 )
197 router.load_config(
198 TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(name))
199 )
200
201 # After loading the configurations, this function loads configured daemons.
202 tgen.start_router()
203
204 logger.info("Running setup_module() done")
205
206
207 def teardown_module(mod):
208 """Teardown the pytest environment"""
209
210 logger.info("Running teardown_module to delete topology")
211
212 tgen = get_topogen()
213
214 # Stop toplogy and Remove tmp files
215 tgen.stop_topology()
216
217 logger.info(
218 "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
219 )
220 logger.info("=" * 40)
221
222
223 def evpn_gateway_ip_show_op_check(trigger=" "):
224 """
225 This function checks CLI O/P for commands mentioned in show_commands for a given trigger
226 :param trigger: Should be a trigger present in TRIGGERS
227 :return: Returns a tuple (result: None for success, retmsg: Log message to be printed on failure)
228 """
229 tgen = get_topogen()
230
231 if trigger not in TRIGGERS:
232 return "Unexpected trigger", "Unexpected trigger {}".format(trigger)
233
234 show_commands = {'bgp_vni_routes': 'show bgp l2vpn evpn route vni 100 json',
235 'bgp_vrf_ipv4' : 'show bgp vrf vrf-blue ipv4 json',
236 'bgp_vrf_ipv6' : 'show bgp vrf vrf-blue ipv6 json',
237 'zebra_vrf_ipv4': 'show ip route vrf vrf-blue json',
238 'zebra_vrf_ipv6': 'show ipv6 route vrf vrf-blue json'}
239
240 for (name, pe) in tgen.gears.items():
241 if name not in PES:
242 continue
243
244 for (cmd_key, command) in show_commands.items():
245 expected_op_file = "{0}/{1}/{2}_{3}.json".format(CWD, name, cmd_key, trigger)
246 expected_op = json.loads(open(expected_op_file).read())
247
248 test_func = partial(topotest.router_json_cmp, pe, command, expected_op)
249 ret, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
250 assertmsg = '"{0}" JSON output mismatch for {1}'.format(name, command)
251 if result is not None:
252 return result, assertmsg
253
254 return None, "Pass"
255
256
257 def test_evpn_gateway_ip_basic_topo(request):
258 """
259 Tets EVPN overlay index gateway IP functionality. VErify show O/Ps on PE1 and PE2
260 """
261
262 tgen = get_topogen()
263 tc_name = request.node.name
264 write_test_header(tc_name)
265
266 kernelv = platform.release()
267 if topotest.version_cmp(kernelv, "4.15") < 0:
268 logger.info("For EVPN, kernel version should be minimum 4.15")
269 write_test_footer(tc_name)
270 return
271
272 if tgen.routers_have_failure():
273 pytest.skip(tgen.errors)
274
275 step("Check O/Ps for EVPN gateway IP overlay Index functionality at PE1 and PE2")
276
277 result, assertmsg = evpn_gateway_ip_show_op_check("base")
278
279 if result is not None:
280 generate_support_bundle()
281 assert result is None, assertmsg
282
283 write_test_footer(tc_name)
284
285
286 def test_evpn_gateway_ip_flap_rt5(request):
287 """
288 Withdraw EVPN type-5 routes and check O/Ps at PE1 and PE2
289 """
290 tgen = get_topogen()
291 tc_name = request.node.name
292 write_test_header(tc_name)
293
294 kernelv = platform.release()
295 if topotest.version_cmp(kernelv, "4.15") < 0:
296 logger.info("For EVPN, kernel version should be minimum 4.15")
297 write_test_footer(tc_name)
298 return
299
300 if tgen.routers_have_failure():
301 pytest.skip(tgen.errors)
302
303 h1 = tgen.gears['host1']
304
305 step("Withdraw type-5 routes")
306
307 h1.run('vtysh -c "config t" \
308 -c "router bgp 111" \
309 -c "address-family ipv4" \
310 -c "no network 100.0.0.21/32"')
311 h1.run('vtysh -c "config t" \
312 -c "router bgp 111" \
313 -c "address-family ipv6" \
314 -c "no network 100::21/128"')
315
316 result, assertmsg = evpn_gateway_ip_show_op_check("no_rt5")
317 if result is not None:
318 generate_support_bundle()
319 assert result is None, assertmsg
320
321 step("Advertise type-5 routes again")
322
323 h1.run('vtysh -c "config t" \
324 -c "router bgp 111" \
325 -c "address-family ipv4" \
326 -c "network 100.0.0.21/32"')
327 h1.run('vtysh -c "config t" \
328 -c "router bgp 111" \
329 -c "address-family ipv6" \
330 -c "network 100::21/128"')
331
332 result, assertmsg = evpn_gateway_ip_show_op_check("base")
333 if result is not None:
334 generate_support_bundle()
335
336 assert result is None, assertmsg
337
338 write_test_footer(tc_name)
339
340
341 def test_evpn_gateway_ip_flap_rt2(request):
342 """
343 Withdraw EVPN type-2 routes and check O/Ps at PE1 and PE2
344 """
345 tgen = get_topogen()
346 tc_name = request.node.name
347 write_test_header(tc_name)
348
349 kernelv = platform.release()
350 if topotest.version_cmp(kernelv, "4.15") < 0:
351 logger.info("For EVPN, kernel version should be minimum 4.15")
352 write_test_footer(tc_name)
353 return
354
355 if tgen.routers_have_failure():
356 pytest.skip(tgen.errors)
357
358
359 step("Shut down VxLAN interface at PE1 which results in withdraw of type-2 routes")
360
361 pe1 = tgen.net["PE1"]
362
363 pe1.cmd_raises("ip link set dev vxlan100 down")
364
365 result, assertmsg = evpn_gateway_ip_show_op_check("no_rt2")
366 if result is not None:
367 generate_support_bundle()
368 assert result is None, assertmsg
369
370 step("Bring up VxLAN interface at PE1 and advertise type-2 routes again")
371
372 pe1.cmd_raises("ip link set dev vxlan100 up")
373
374 result, assertmsg = evpn_gateway_ip_show_op_check("base")
375 if result is not None:
376 generate_support_bundle()
377 assert result is None, assertmsg
378
379 write_test_footer(tc_name)
380
381
382 def test_memory_leak():
383 """Run the memory leak test and report results"""
384 tgen = get_topogen()
385 if not tgen.is_memleak_enabled():
386 pytest.skip("Memory leak test/report is disabled")
387
388 tgen.report_memory_leaks()
389
390 if __name__ == "__main__":
391 args = ["-s"] + sys.argv[1:]
392 sys.exit(pytest.main(args))