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