]>
Commit | Line | Data |
---|---|---|
1b66072c | 1 | #!/usr/bin/env python |
acddc0ed | 2 | # SPDX-License-Identifier: ISC |
1b66072c KK |
3 | |
4 | # | |
5 | # Copyright (c) 2020 by VMware, Inc. ("VMware") | |
6 | # Used Copyright (c) 2018 by Network Device Education Foundation, | |
7 | # Inc. ("NetDEF") in this file. | |
8 | # | |
1b66072c KK |
9 | |
10 | """ | |
11 | Following tests are covered to test EVPN-Type5 functionality: | |
1b66072c KK |
12 | 1. In absence of an overlay index all IP-Prefixes(RT-5) |
13 | are advertised with default values for below parameters: | |
14 | --> Ethernet Tag ID = GW IP address = ESI=0 | |
15 | 2. EVPN CLI output and JSON format validation. | |
16 | 3. RT verification(auto) | |
17 | """ | |
18 | ||
19 | import os | |
1b66072c | 20 | import sys |
1b66072c KK |
21 | import time |
22 | import pytest | |
23 | import platform | |
24 | from copy import deepcopy | |
1b66072c KK |
25 | |
26 | ||
27 | # Save the Current Working Directory to find configuration files. | |
28 | CWD = os.path.dirname(os.path.realpath(__file__)) | |
29 | sys.path.append(os.path.join(CWD, "../")) | |
30 | sys.path.append(os.path.join(CWD, "../lib/")) | |
31 | ||
32 | # Required to instantiate the topology builder class. | |
33 | ||
34 | # pylint: disable=C0413 | |
35 | # Import topogen and topotest helpers | |
36 | from lib.topotest import version_cmp | |
37 | from lib.topogen import Topogen, get_topogen | |
1b66072c KK |
38 | |
39 | from lib.common_config import ( | |
40 | start_topology, | |
41 | write_test_header, | |
42 | check_address_types, | |
43 | write_test_footer, | |
44 | reset_config_on_routers, | |
45 | verify_rib, | |
46 | step, | |
1b66072c KK |
47 | create_static_routes, |
48 | create_vrf_cfg, | |
1b66072c KK |
49 | check_router_status, |
50 | configure_vxlan, | |
51 | configure_brctl, | |
1b66072c | 52 | verify_vrf_vni, |
701a0192 | 53 | verify_cli_json, |
1b66072c KK |
54 | ) |
55 | ||
56 | from lib.topolog import logger | |
57 | from lib.bgp import ( | |
58 | verify_bgp_convergence, | |
59 | create_router_bgp, | |
1b66072c | 60 | verify_attributes_for_evpn_routes, |
1b66072c | 61 | ) |
4953ca97 | 62 | from lib.topojson import build_config_from_json |
1b66072c | 63 | |
6a1e8951 | 64 | |
e82b531d | 65 | pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] |
1b66072c KK |
66 | |
67 | # Reading the data from JSON File for topology creation | |
68 | # Global variables | |
69 | TCPDUMP_FILE = "evpn_log.txt" | |
1b66072c KK |
70 | NETWORK1_1 = {"ipv4": "10.1.1.1/32", "ipv6": "10::1/128"} |
71 | NETWORK1_2 = {"ipv4": "40.1.1.1/32", "ipv6": "40::1/128"} | |
72 | NETWORK1_3 = {"ipv4": "40.1.1.2/32", "ipv6": "40::2/128"} | |
73 | NETWORK1_4 = {"ipv4": "40.1.1.3/32", "ipv6": "40::3/128"} | |
74 | NETWORK2_1 = {"ipv4": "20.1.1.1/32", "ipv6": "20::1/128"} | |
75 | NETWORK3_1 = {"ipv4": "30.1.1.1/32", "ipv6": "30::1/128"} | |
76 | NETWORK4_1 = {"ipv4": "100.1.1.1/32 ", "ipv6": "100::100/128"} | |
77 | NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"} | |
78 | VNI_1 = 75100 | |
79 | VNI_2 = 75200 | |
80 | VNI_3 = 75300 | |
81 | MAC_1 = "00:80:48:ba:d1:00" | |
82 | MAC_2 = "00:80:48:ba:d1:01" | |
83 | MAC_3 = "00:80:48:ba:d1:02" | |
84 | BRCTL_1 = "br100" | |
85 | BRCTL_2 = "br200" | |
86 | BRCTL_3 = "br300" | |
87 | VXLAN_1 = "vxlan75100" | |
88 | VXLAN_2 = "vxlan75200" | |
89 | VXLAN_3 = "vxlan75300" | |
90 | BRIDGE_INTF1 = "120.0.0.1" | |
91 | BRIDGE_INTF2 = "120.0.0.2" | |
92 | BRIDGE_INTF3 = "120.0.0.3" | |
93 | MULTICAST_MAC1 = "01:00:5e:00:52:02" | |
94 | ||
95 | VXLAN = { | |
96 | "vxlan_name": [VXLAN_1, VXLAN_2, VXLAN_3], | |
97 | "vxlan_id": [75100, 75200, 75300], | |
98 | "dstport": 4789, | |
99 | "local_addr": {"e1": BRIDGE_INTF1, "d1": BRIDGE_INTF2, "d2": BRIDGE_INTF3}, | |
100 | "learning": "no", | |
101 | } | |
102 | BRCTL = { | |
103 | "brctl_name": [BRCTL_1, BRCTL_2, BRCTL_3], | |
104 | "addvxlan": [VXLAN_1, VXLAN_2, VXLAN_3], | |
105 | "vrf": ["RED", "BLUE", "GREEN"], | |
106 | "stp": [0, 0, 0], | |
107 | } | |
108 | ||
109 | ||
1b66072c KK |
110 | def setup_module(mod): |
111 | """ | |
112 | Sets up the pytest environment | |
113 | ||
114 | * `mod`: module name | |
115 | """ | |
116 | ||
1b66072c KK |
117 | testsuite_run_time = time.asctime(time.localtime(time.time())) |
118 | logger.info("Testsuite start time: {}".format(testsuite_run_time)) | |
119 | logger.info("=" * 40) | |
120 | ||
121 | logger.info("Running setup_module to create topology") | |
122 | ||
123 | # This function initiates the topology build with Topogen... | |
e82b531d CH |
124 | json_file = "{}/evpn_type5_chaos_topo1.json".format(CWD) |
125 | tgen = Topogen(json_file, mod.__name__) | |
126 | global topo | |
127 | topo = tgen.json_topo | |
1b66072c KK |
128 | # ... and here it calls Mininet initialization functions. |
129 | ||
130 | # Starting topology, create tmp files which are loaded to routers | |
d60a3f0e | 131 | # to start daemons and then start routers |
1b66072c KK |
132 | start_topology(tgen) |
133 | ||
134 | # Creating configuration from JSON | |
135 | build_config_from_json(tgen, topo) | |
136 | ||
701a0192 | 137 | if version_cmp(platform.release(), "4.19") < 0: |
138 | error_msg = ( | |
139 | 'EVPN tests will not run (have kernel "{}", ' | |
140 | "but it requires >= 4.19)".format(platform.release()) | |
141 | ) | |
1b66072c KK |
142 | pytest.skip(error_msg) |
143 | ||
144 | global BGP_CONVERGENCE | |
145 | global ADDR_TYPES | |
146 | ADDR_TYPES = check_address_types() | |
147 | ||
148 | BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) | |
149 | assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format( | |
150 | BGP_CONVERGENCE | |
151 | ) | |
152 | ||
153 | logger.info("Pre-requisite config for testsuite") | |
154 | prerequisite_config_for_test_suite(tgen) | |
155 | ||
156 | logger.info("Running setup_module() done") | |
157 | ||
158 | ||
159 | def teardown_module(): | |
160 | """Teardown the pytest environment""" | |
161 | ||
162 | logger.info("Running teardown_module to delete topology") | |
163 | ||
164 | tgen = get_topogen() | |
165 | ||
166 | # Stop toplogy and Remove tmp files | |
167 | tgen.stop_topology() | |
168 | ||
169 | logger.info( | |
170 | "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) | |
171 | ) | |
172 | logger.info("=" * 40) | |
173 | ||
174 | ||
175 | ##################################################### | |
176 | # | |
177 | # Testcases | |
178 | # | |
179 | ##################################################### | |
180 | ||
181 | ||
182 | def prerequisite_config_for_test_suite(tgen): | |
183 | """ | |
184 | API to do prerequisite config for testsuite | |
185 | ||
186 | parameters: | |
187 | ----------- | |
188 | * `tgen`: topogen object | |
189 | """ | |
190 | ||
191 | step("Configure vxlan, bridge interface") | |
192 | for dut in ["e1", "d1", "d2"]: | |
193 | step("[DUT: ]Configure vxlan") | |
194 | vxlan_input = { | |
195 | dut: { | |
196 | "vxlan": [ | |
197 | { | |
198 | "vxlan_name": VXLAN["vxlan_name"], | |
199 | "vxlan_id": VXLAN["vxlan_id"], | |
200 | "dstport": VXLAN["dstport"], | |
201 | "local_addr": VXLAN["local_addr"][dut], | |
202 | "learning": VXLAN["learning"], | |
203 | } | |
204 | ] | |
205 | } | |
206 | } | |
207 | ||
208 | result = configure_vxlan(tgen, vxlan_input) | |
d7d21c3a | 209 | assert result is True, "Testcase :Failed \n Error: {}".format(result) |
1b66072c KK |
210 | |
211 | step("Configure bridge interface") | |
212 | brctl_input = { | |
213 | dut: { | |
214 | "brctl": [ | |
215 | { | |
216 | "brctl_name": BRCTL["brctl_name"], | |
217 | "addvxlan": BRCTL["addvxlan"], | |
218 | "vrf": BRCTL["vrf"], | |
219 | "stp": BRCTL["stp"], | |
220 | } | |
221 | ] | |
222 | } | |
223 | } | |
224 | result = configure_brctl(tgen, topo, brctl_input) | |
d7d21c3a | 225 | assert result is True, "Testcase :Failed \n Error: {}".format(result) |
1b66072c KK |
226 | |
227 | step("Configure default routes") | |
228 | add_default_routes(tgen) | |
229 | ||
230 | ||
231 | def add_default_routes(tgen): | |
232 | """ | |
233 | API to do prerequisite config for testsuite | |
234 | ||
235 | parameters: | |
236 | ----------- | |
237 | * `tgen`: topogen object | |
238 | """ | |
239 | ||
240 | step("Add default routes..") | |
241 | ||
242 | default_routes = { | |
243 | "e1": { | |
244 | "static_routes": [ | |
245 | { | |
246 | "network": "{}/32".format(VXLAN["local_addr"]["d1"]), | |
247 | "next_hop": topo["routers"]["d1"]["links"]["e1-link1"][ | |
248 | "ipv4" | |
249 | ].split("/")[0], | |
250 | }, | |
251 | { | |
252 | "network": "{}/32".format(VXLAN["local_addr"]["d2"]), | |
253 | "next_hop": topo["routers"]["d2"]["links"]["e1-link1"][ | |
254 | "ipv4" | |
255 | ].split("/")[0], | |
256 | }, | |
257 | ] | |
258 | }, | |
259 | "d1": { | |
260 | "static_routes": [ | |
261 | { | |
262 | "network": "{}/32".format(VXLAN["local_addr"]["e1"]), | |
263 | "next_hop": topo["routers"]["e1"]["links"]["d1-link1"][ | |
264 | "ipv4" | |
265 | ].split("/")[0], | |
266 | }, | |
267 | { | |
268 | "network": "{}/32".format(VXLAN["local_addr"]["d2"]), | |
269 | "next_hop": topo["routers"]["e1"]["links"]["d1-link1"][ | |
270 | "ipv4" | |
271 | ].split("/")[0], | |
272 | }, | |
273 | ] | |
274 | }, | |
275 | "d2": { | |
276 | "static_routes": [ | |
277 | { | |
278 | "network": "{}/32".format(VXLAN["local_addr"]["d1"]), | |
279 | "next_hop": topo["routers"]["e1"]["links"]["d2-link1"][ | |
280 | "ipv4" | |
281 | ].split("/")[0], | |
282 | }, | |
283 | { | |
284 | "network": "{}/32".format(VXLAN["local_addr"]["e1"]), | |
285 | "next_hop": topo["routers"]["e1"]["links"]["d2-link1"][ | |
286 | "ipv4" | |
287 | ].split("/")[0], | |
288 | }, | |
289 | ] | |
290 | }, | |
291 | } | |
292 | ||
293 | result = create_static_routes(tgen, default_routes) | |
d7d21c3a | 294 | assert result is True, "Testcase :Failed \n Error: {}".format(result) |
1b66072c KK |
295 | |
296 | ||
297 | def test_verify_overlay_index_p1(request): | |
298 | """ | |
299 | In absence of an overlay index all IP-Prefixes(RT-5) | |
300 | are advertised with default values for below parameters: | |
301 | --> Ethernet Tag ID = GW IP address = ESI=0 | |
302 | """ | |
303 | ||
304 | tgen = get_topogen() | |
305 | tc_name = request.node.name | |
306 | write_test_header(tc_name) | |
307 | check_router_status(tgen) | |
308 | reset_config_on_routers(tgen) | |
309 | add_default_routes(tgen) | |
310 | ||
311 | if tgen.routers_have_failure(): | |
312 | pytest.skip(tgen.errors) | |
313 | ||
314 | step("Following steps are taken care in base config:") | |
315 | step( | |
316 | "Configure BGP neighborship for both address families" | |
317 | "(IPv4 & IPv6) between Edge-1 and VFN routers(R1 and R2)" | |
318 | ) | |
319 | step( | |
320 | "Advertise prefixes from VNF routers R1 and R2 in associated " | |
321 | "VRFs for both address-family." | |
322 | ) | |
323 | step("Advertise VRF routes as in EVPN address family from Edge-1 " "router.") | |
324 | ||
325 | for addr_type in ADDR_TYPES: | |
326 | input_dict_1 = { | |
327 | "r1": { | |
328 | "static_routes": [ | |
329 | { | |
330 | "network": NETWORK1_1[addr_type], | |
331 | "next_hop": NEXT_HOP_IP[addr_type], | |
332 | "vrf": "RED", | |
333 | } | |
334 | ] | |
335 | }, | |
336 | "r2": { | |
337 | "static_routes": [ | |
338 | { | |
339 | "network": NETWORK2_1[addr_type], | |
340 | "next_hop": NEXT_HOP_IP[addr_type], | |
341 | "vrf": "BLUE", | |
342 | }, | |
343 | { | |
344 | "network": NETWORK3_1[addr_type], | |
345 | "next_hop": NEXT_HOP_IP[addr_type], | |
346 | "vrf": "GREEN", | |
701a0192 | 347 | }, |
1b66072c | 348 | ] |
701a0192 | 349 | }, |
1b66072c KK |
350 | } |
351 | ||
352 | result = create_static_routes(tgen, input_dict_1) | |
353 | assert result is True, "Testcase {} : Failed \n Error: {}".format( | |
354 | tc_name, result | |
355 | ) | |
356 | ||
357 | step("Verify: Prefixes are received in all VRFs on Edge-1 router.") | |
358 | ||
359 | for addr_type in ADDR_TYPES: | |
360 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
361 | result = verify_rib(tgen, addr_type, "e1", input_routes) | |
362 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
363 | tc_name, result | |
364 | ) | |
365 | ||
366 | for addr_type in ADDR_TYPES: | |
367 | input_routes = {key: topo["routers"][key] for key in ["r2"]} | |
368 | result = verify_rib(tgen, addr_type, "e1", input_routes) | |
369 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
370 | tc_name, result | |
371 | ) | |
372 | ||
373 | step( | |
374 | "Verify that EVPN routes, received on DCG-1 and DCG-2 do not " | |
375 | "carry any overlay index and these indexes are set to default " | |
376 | "value=0. " | |
377 | ) | |
378 | ||
379 | for addr_type in ADDR_TYPES: | |
380 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
381 | ||
382 | result = verify_attributes_for_evpn_routes( | |
383 | tgen, topo, "d1", input_routes, ethTag=0 | |
384 | ) | |
385 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
386 | tc_name, result | |
387 | ) | |
388 | ||
389 | result = verify_attributes_for_evpn_routes( | |
390 | tgen, topo, "d2", input_routes, ethTag=0 | |
391 | ) | |
392 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
393 | tc_name, result | |
394 | ) | |
395 | ||
396 | write_test_footer(tc_name) | |
397 | ||
398 | ||
399 | def test_evpn_cli_json_available_p1(request): | |
400 | """ | |
401 | EVPN CLI output and JSON format validation. | |
402 | """ | |
403 | ||
404 | tgen = get_topogen() | |
405 | tc_name = request.node.name | |
406 | write_test_header(tc_name) | |
407 | check_router_status(tgen) | |
408 | reset_config_on_routers(tgen) | |
409 | add_default_routes(tgen) | |
410 | ||
411 | if tgen.routers_have_failure(): | |
412 | pytest.skip(tgen.errors) | |
413 | ||
414 | step("Need to verify below CLIs and associated JSON format " "outputs:") | |
415 | ||
416 | input_dict = { | |
417 | "e1": { | |
418 | "cli": [ | |
419 | "show evpn vni detail", | |
420 | "show bgp l2vpn evpn all overlay", | |
701a0192 | 421 | "show bgp l2vpn evpn vni", |
1b66072c KK |
422 | ] |
423 | } | |
424 | } | |
425 | ||
426 | result = verify_cli_json(tgen, input_dict) | |
427 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
428 | ||
429 | write_test_footer(tc_name) | |
430 | ||
431 | ||
432 | def test_RT_verification_auto_p0(request): | |
433 | """ | |
434 | RT verification(auto) | |
435 | """ | |
436 | ||
437 | tgen = get_topogen() | |
438 | tc_name = request.node.name | |
439 | write_test_header(tc_name) | |
440 | check_router_status(tgen) | |
441 | reset_config_on_routers(tgen) | |
442 | add_default_routes(tgen) | |
443 | ||
444 | if tgen.routers_have_failure(): | |
445 | pytest.skip(tgen.errors) | |
446 | ||
447 | step( | |
448 | "Advertise overlapping prefixes from VNFs R1 and R2 in all VRFs " | |
449 | "RED, GREEN and BLUE 100.1.1.1/32 and 100::100/128" | |
450 | ) | |
451 | ||
452 | for addr_type in ADDR_TYPES: | |
453 | input_dict_1 = { | |
454 | "r1": { | |
455 | "static_routes": [ | |
456 | { | |
457 | "network": NETWORK4_1[addr_type], | |
458 | "next_hop": NEXT_HOP_IP[addr_type], | |
459 | "vrf": "RED", | |
460 | } | |
461 | ] | |
462 | }, | |
463 | "r2": { | |
464 | "static_routes": [ | |
465 | { | |
466 | "network": NETWORK4_1[addr_type], | |
467 | "next_hop": NEXT_HOP_IP[addr_type], | |
468 | "vrf": "BLUE", | |
469 | }, | |
470 | { | |
471 | "network": NETWORK4_1[addr_type], | |
472 | "next_hop": NEXT_HOP_IP[addr_type], | |
473 | "vrf": "GREEN", | |
701a0192 | 474 | }, |
1b66072c | 475 | ] |
701a0192 | 476 | }, |
1b66072c KK |
477 | } |
478 | ||
479 | result = create_static_routes(tgen, input_dict_1) | |
480 | assert result is True, "Testcase {} : Failed \n Error: {}".format( | |
481 | tc_name, result | |
482 | ) | |
483 | ||
484 | step( | |
485 | "Verify that Edge-1 receives same prefixes in all 3 VRFs via " | |
486 | "corresponding next-hop in associated VRF sh bgp vrf all" | |
487 | ) | |
488 | ||
489 | for addr_type in ADDR_TYPES: | |
490 | input_routes = { | |
491 | "r1": { | |
492 | "static_routes": [ | |
493 | { | |
494 | "network": NETWORK4_1[addr_type], | |
495 | "next_hop": NEXT_HOP_IP[addr_type], | |
496 | "vrf": "RED", | |
497 | } | |
498 | ] | |
499 | }, | |
500 | "r2": { | |
501 | "static_routes": [ | |
502 | { | |
503 | "network": NETWORK4_1[addr_type], | |
504 | "next_hop": NEXT_HOP_IP[addr_type], | |
505 | "vrf": "BLUE", | |
506 | }, | |
507 | { | |
508 | "network": NETWORK4_1[addr_type], | |
509 | "next_hop": NEXT_HOP_IP[addr_type], | |
510 | "vrf": "GREEN", | |
511 | }, | |
512 | ] | |
513 | }, | |
514 | } | |
515 | ||
516 | result = verify_rib(tgen, addr_type, "e1", input_routes) | |
517 | assert result is True, "Testcase {} : Failed \n Error: {}".format( | |
518 | tc_name, result | |
519 | ) | |
520 | ||
521 | step( | |
522 | "Configure 4-byte local AS number on Edge-1 and establish EVPN " | |
523 | "neighborship with DCG-1 & DCG-2." | |
524 | ) | |
525 | ||
526 | topo_local = deepcopy(topo) | |
527 | ||
528 | step("Delete BGP config for vrf RED.") | |
529 | ||
530 | input_dict_vni = { | |
531 | "e1": { | |
532 | "vrfs": [ | |
533 | {"name": "RED", "no_vni": VNI_1}, | |
534 | {"name": "BLUE", "no_vni": VNI_2}, | |
535 | {"name": "GREEN", "no_vni": VNI_3}, | |
536 | ] | |
537 | } | |
538 | } | |
539 | result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni) | |
540 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
541 | ||
542 | input_dict_2 = {} | |
543 | for dut in ["e1"]: | |
544 | temp = {dut: {"bgp": []}} | |
545 | input_dict_2.update(temp) | |
546 | ||
547 | INDEX = [0, 1, 2, 3] | |
548 | VRFS = ["RED", "BLUE", "GREEN", None] | |
549 | AS_NUM = [100, 100, 100, 100] | |
550 | ||
551 | for index, vrf, as_num in zip(INDEX, VRFS, AS_NUM): | |
552 | topo_local["routers"][dut]["bgp"][index]["local_as"] = 4294967293 | |
553 | if vrf: | |
554 | temp[dut]["bgp"].append( | |
555 | {"local_as": as_num, "vrf": vrf, "delete": True} | |
556 | ) | |
557 | else: | |
558 | temp[dut]["bgp"].append({"local_as": as_num, "delete": True}) | |
559 | ||
560 | result = create_router_bgp(tgen, topo, input_dict_2) | |
561 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
562 | ||
563 | result = create_router_bgp(tgen, topo_local["routers"]) | |
564 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
565 | ||
566 | input_dict_vni = { | |
567 | "e1": { | |
568 | "vrfs": [ | |
569 | {"name": "RED", "vni": VNI_1}, | |
570 | {"name": "BLUE", "vni": VNI_2}, | |
571 | {"name": "GREEN", "vni": VNI_3}, | |
572 | ] | |
573 | } | |
574 | } | |
575 | result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni) | |
576 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
577 | ||
578 | step( | |
579 | "Verify that all overlapping prefixes across different VRFs are " | |
580 | "advertised in EVPN with unique RD value(auto derived)." | |
581 | ) | |
582 | step( | |
583 | "Verify that FRR uses only the lower 2 bytes of ASN+VNI for auto " | |
584 | "derived RT value." | |
585 | ) | |
586 | ||
587 | for addr_type in ADDR_TYPES: | |
588 | input_routes_1 = { | |
589 | "r1": {"static_routes": [{"network": NETWORK4_1[addr_type], "vrf": "RED"}]} | |
590 | } | |
591 | input_routes_2 = { | |
592 | "r2": {"static_routes": [{"network": NETWORK4_1[addr_type], "vrf": "BLUE"}]} | |
593 | } | |
594 | input_routes_3 = { | |
595 | "r2": { | |
596 | "static_routes": [{"network": NETWORK4_1[addr_type], "vrf": "GREEN"}] | |
597 | } | |
598 | } | |
599 | ||
600 | result = verify_attributes_for_evpn_routes( | |
601 | tgen, topo, "e1", input_routes_1, rd="auto", rd_peer="e1" | |
602 | ) | |
603 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
604 | tc_name, result | |
605 | ) | |
606 | ||
607 | result = verify_attributes_for_evpn_routes( | |
608 | tgen, topo, "e1", input_routes_1, rt="auto", rt_peer="e1" | |
609 | ) | |
610 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
611 | tc_name, result | |
612 | ) | |
613 | ||
614 | result = verify_attributes_for_evpn_routes( | |
615 | tgen, topo, "e1", input_routes_2, rd="auto", rd_peer="e1" | |
616 | ) | |
617 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
618 | tc_name, result | |
619 | ) | |
620 | ||
621 | result = verify_attributes_for_evpn_routes( | |
622 | tgen, topo, "e1", input_routes_2, rt="auto", rt_peer="e1" | |
623 | ) | |
624 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
625 | tc_name, result | |
626 | ) | |
627 | ||
628 | result = verify_attributes_for_evpn_routes( | |
629 | tgen, topo, "e1", input_routes_3, rd="auto", rd_peer="e1" | |
630 | ) | |
631 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
632 | tc_name, result | |
633 | ) | |
634 | ||
635 | result = verify_attributes_for_evpn_routes( | |
636 | tgen, topo, "e1", input_routes_3, rt="auto", rt_peer="e1" | |
637 | ) | |
638 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
639 | tc_name, result | |
640 | ) | |
641 | ||
642 | step( | |
643 | "Verify that DCG-1(iBGP peer) automatically imports the prefixes" | |
644 | " from EVPN address-family to respective VRFs." | |
645 | ) | |
646 | step( | |
647 | "Verify if DCG-2(eBGP peer) automatically imports the prefixes " | |
648 | "from EVPN address-family to respective VRFs or not." | |
649 | ) | |
650 | ||
651 | for addr_type in ADDR_TYPES: | |
652 | input_routes = { | |
653 | "r1": { | |
654 | "static_routes": [ | |
655 | { | |
656 | "network": NETWORK4_1[addr_type], | |
657 | "next_hop": NEXT_HOP_IP[addr_type], | |
658 | "vrf": "RED", | |
659 | } | |
660 | ] | |
661 | }, | |
662 | "r2": { | |
663 | "static_routes": [ | |
664 | { | |
665 | "network": NETWORK4_1[addr_type], | |
666 | "next_hop": NEXT_HOP_IP[addr_type], | |
667 | "vrf": "BLUE", | |
668 | }, | |
669 | { | |
670 | "network": NETWORK4_1[addr_type], | |
671 | "next_hop": NEXT_HOP_IP[addr_type], | |
672 | "vrf": "GREEN", | |
673 | }, | |
674 | ] | |
675 | }, | |
676 | } | |
677 | ||
678 | result = verify_rib(tgen, addr_type, "d1", input_routes) | |
679 | assert result is True, "Testcase {} : Failed \n Error: {}".format( | |
680 | tc_name, result | |
681 | ) | |
682 | ||
683 | result = verify_rib(tgen, addr_type, "d2", input_routes) | |
684 | assert result is True, "Testcase {} : Failed \n Error: {}".format( | |
685 | tc_name, result | |
686 | ) | |
687 | ||
688 | step( | |
689 | "Change the VNI number for all 3 VRFs on Edge-1 as:" | |
690 | "RED : 75400, GREEN: 75500, BLUE: 75600" | |
691 | ) | |
692 | ||
693 | input_dict_vni = { | |
694 | "e1": { | |
695 | "vrfs": [ | |
696 | {"name": "RED", "no_vni": VNI_1}, | |
697 | {"name": "BLUE", "no_vni": VNI_2}, | |
698 | {"name": "GREEN", "no_vni": VNI_3}, | |
699 | ] | |
700 | } | |
701 | } | |
702 | result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni) | |
703 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
704 | ||
705 | input_dict_vni = { | |
706 | "e1": { | |
707 | "vrfs": [ | |
708 | {"name": "RED", "vni": 75400}, | |
709 | {"name": "BLUE", "vni": 75500}, | |
710 | {"name": "GREEN", "vni": 75600}, | |
711 | ] | |
712 | } | |
713 | } | |
714 | result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni) | |
715 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
716 | ||
717 | step("Delete configured vxlan") | |
718 | dut = "e1" | |
719 | vxlan_input = { | |
720 | dut: { | |
721 | "vxlan": [ | |
722 | { | |
723 | "vxlan_name": VXLAN["vxlan_name"], | |
724 | "vxlan_id": VXLAN["vxlan_id"], | |
725 | "dstport": VXLAN["dstport"], | |
726 | "local_addr": VXLAN["local_addr"][dut], | |
727 | "learning": VXLAN["learning"], | |
728 | "delete": True, | |
729 | } | |
730 | ] | |
731 | } | |
732 | } | |
733 | ||
734 | result = configure_vxlan(tgen, vxlan_input) | |
735 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
736 | ||
737 | step("Configured vxlan") | |
738 | VXLAN["vxlan_id"] = [75400, 75500, 75600] | |
739 | vxlan_input = { | |
740 | dut: { | |
741 | "vxlan": [ | |
742 | { | |
743 | "vxlan_name": VXLAN["vxlan_name"], | |
744 | "vxlan_id": VXLAN["vxlan_id"], | |
745 | "dstport": VXLAN["dstport"], | |
746 | "local_addr": VXLAN["local_addr"][dut], | |
747 | "learning": VXLAN["learning"], | |
748 | } | |
749 | ] | |
750 | } | |
751 | } | |
752 | ||
753 | result = configure_vxlan(tgen, vxlan_input) | |
754 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
755 | ||
756 | step("Configure bridge interface") | |
757 | brctl_input = { | |
758 | dut: { | |
759 | "brctl": [ | |
760 | { | |
761 | "brctl_name": BRCTL["brctl_name"], | |
762 | "addvxlan": BRCTL["addvxlan"], | |
763 | "vrf": BRCTL["vrf"], | |
764 | "stp": BRCTL["stp"], | |
765 | } | |
766 | ] | |
767 | } | |
768 | } | |
769 | result = configure_brctl(tgen, topo, brctl_input) | |
770 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
771 | ||
772 | step( | |
773 | "Verify on Edge-1 that auto derived RT value has changed for " | |
774 | "each VRF based on VNI number.." | |
775 | ) | |
776 | ||
777 | input_dict = { | |
778 | "e1": { | |
779 | "vrfs": [ | |
780 | {"RED": {"vni": 75400}}, | |
781 | {"BLUE": {"vni": 75500}}, | |
782 | {"GREEN": {"vni": 75600}}, | |
783 | ] | |
784 | } | |
785 | } | |
786 | ||
787 | result = verify_vrf_vni(tgen, input_dict) | |
788 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
789 | ||
790 | step( | |
791 | "Verify on Edge-1 that auto derived RT value has changed for " | |
792 | "each VRF based on VNI number." | |
793 | ) | |
794 | ||
795 | for addr_type in ADDR_TYPES: | |
796 | input_routes = { | |
797 | "r1": {"static_routes": [{"network": NETWORK4_1[addr_type], "vrf": "RED"}]} | |
798 | } | |
799 | ||
800 | result = verify_attributes_for_evpn_routes( | |
801 | tgen, topo, "e1", input_routes, rt="auto", rt_peer="e1" | |
802 | ) | |
803 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
804 | tc_name, result | |
805 | ) | |
806 | ||
807 | step( | |
808 | "Verify on DCG-2 that prefixes are not imported from EVPN " | |
809 | "address-family to VRFs as RT values are different on sending(" | |
810 | "edge-1) and receiving(DCG-2) end." | |
811 | ) | |
812 | ||
813 | for addr_type in ADDR_TYPES: | |
814 | input_routes = { | |
815 | "r1": {"static_routes": [{"network": NETWORK4_1[addr_type], "vrf": "RED"}]} | |
816 | } | |
817 | ||
818 | result = verify_rib(tgen, addr_type, "d2", input_routes, expected=False) | |
db726bb8 KK |
819 | assert result is not True, ( |
820 | "Testcase {} : Failed \n " | |
821 | "Expected: Routes should not be present in {} RIB \n " | |
822 | "Found: {}".format(tc_name, "d2", result) | |
823 | ) | |
1b66072c KK |
824 | |
825 | step( | |
826 | "Revert back to original VNI number for all 3 VRFs on Edge-1 " | |
827 | "as: RED : 75100, GREEN: 75200, BLUE: 75300" | |
828 | ) | |
829 | ||
830 | input_dict_vni = { | |
831 | "e1": { | |
832 | "vrfs": [ | |
833 | {"name": "RED", "no_vni": 75400}, | |
834 | {"name": "BLUE", "no_vni": 75500}, | |
835 | {"name": "GREEN", "no_vni": 75600}, | |
836 | ] | |
837 | } | |
838 | } | |
839 | result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni) | |
840 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
841 | ||
842 | input_dict_vni = { | |
843 | "e1": { | |
844 | "vrfs": [ | |
845 | {"name": "RED", "vni": VNI_1}, | |
846 | {"name": "BLUE", "vni": VNI_2}, | |
847 | {"name": "GREEN", "vni": VNI_3}, | |
848 | ] | |
849 | } | |
850 | } | |
851 | result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni) | |
852 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
853 | ||
854 | step("Delete configured vxlan") | |
855 | dut = "e1" | |
856 | vxlan_input = { | |
857 | dut: { | |
858 | "vxlan": [ | |
859 | { | |
860 | "vxlan_name": VXLAN["vxlan_name"], | |
861 | "vxlan_id": VXLAN["vxlan_id"], | |
862 | "dstport": VXLAN["dstport"], | |
863 | "local_addr": VXLAN["local_addr"][dut], | |
864 | "learning": VXLAN["learning"], | |
865 | "delete": True, | |
866 | } | |
867 | ] | |
868 | } | |
869 | } | |
870 | result = configure_vxlan(tgen, vxlan_input) | |
871 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
872 | ||
873 | step("Configured vxlan") | |
874 | VXLAN["vxlan_id"] = [75100, 75200, 75300] | |
875 | vxlan_input = { | |
876 | dut: { | |
877 | "vxlan": [ | |
878 | { | |
879 | "vxlan_name": VXLAN["vxlan_name"], | |
880 | "vxlan_id": VXLAN["vxlan_id"], | |
881 | "dstport": VXLAN["dstport"], | |
882 | "local_addr": VXLAN["local_addr"][dut], | |
883 | "learning": VXLAN["learning"], | |
884 | } | |
885 | ] | |
886 | } | |
887 | } | |
888 | result = configure_vxlan(tgen, vxlan_input) | |
889 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
890 | ||
891 | step("Configure bridge interface") | |
892 | brctl_input = { | |
893 | dut: { | |
894 | "brctl": [ | |
895 | { | |
896 | "brctl_name": BRCTL["brctl_name"], | |
897 | "addvxlan": BRCTL["addvxlan"], | |
898 | "vrf": BRCTL["vrf"], | |
899 | "stp": BRCTL["stp"], | |
900 | } | |
901 | ] | |
902 | } | |
903 | } | |
904 | result = configure_brctl(tgen, topo, brctl_input) | |
905 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
906 | ||
907 | step( | |
908 | "Verify on Edge-1 that auto derived RT value has changed for " | |
909 | "each VRF based on VNI number." | |
910 | ) | |
911 | step( | |
912 | "Verify that DCG-1(iBGP peer) automatically imports the prefixes" | |
913 | " from EVPN address-family to respective VRFs." | |
914 | ) | |
915 | ||
916 | for addr_type in ADDR_TYPES: | |
917 | input_routes = { | |
918 | "r1": {"static_routes": [{"network": NETWORK4_1[addr_type], "vrf": "RED"}]} | |
919 | } | |
920 | ||
921 | result = verify_attributes_for_evpn_routes( | |
922 | tgen, topo, "e1", input_routes, rt="auto", rt_peer="e1" | |
923 | ) | |
924 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
925 | tc_name, result | |
926 | ) | |
927 | ||
928 | result = verify_rib(tgen, addr_type, "d1", input_routes) | |
929 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
930 | tc_name, result | |
931 | ) | |
932 | ||
933 | step("Test with smaller VNI numbers (1-75000)") | |
934 | ||
935 | input_dict_vni = {"e1": {"vrfs": [{"name": "RED", "no_vni": VNI_1}]}} | |
936 | result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni) | |
937 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
938 | ||
939 | input_dict_vni = {"e1": {"vrfs": [{"name": "RED", "vni": 111}]}} | |
940 | result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni) | |
941 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
942 | ||
943 | step( | |
944 | "Verify that DCG-2 receives EVPN prefixes along with auto " | |
945 | "derived RT values(based on smaller VNI numbers)" | |
946 | ) | |
947 | ||
948 | for addr_type in ADDR_TYPES: | |
949 | input_routes_1 = { | |
950 | "r1": {"static_routes": [{"network": NETWORK4_1[addr_type], "vrf": "RED"}]} | |
951 | } | |
952 | ||
953 | result = verify_attributes_for_evpn_routes( | |
954 | tgen, topo, "d2", input_routes_1, rt="auto", rt_peer="e1", expected=False | |
955 | ) | |
db726bb8 KK |
956 | assert result is not True, ( |
957 | "Testcase {} : Failed \n " | |
244f2df0 | 958 | "Expected: Malformed Auto-RT value should not be accepted in {} \n " |
db726bb8 | 959 | "Found: {}".format(tc_name, "d2", result) |
d7d21c3a | 960 | ) |
1b66072c KK |
961 | |
962 | step("Configure VNI number more than boundary limit (16777215)") | |
963 | ||
964 | input_dict_vni = {"e1": {"vrfs": [{"name": "RED", "no_vni": 111}]}} | |
965 | result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni) | |
966 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
967 | ||
968 | input_dict_vni = {"e1": {"vrfs": [{"name": "RED", "vni": 16777215}]}} | |
969 | result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni) | |
970 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
971 | ||
972 | step("CLI error for malformed VNI.") | |
973 | input_dict = { | |
974 | "e1": { | |
975 | "vrfs": [{"RED": {"vni": 16777215, "routerMac": "None", "state": "Down"}}] | |
976 | } | |
977 | } | |
978 | ||
979 | result = verify_vrf_vni(tgen, input_dict) | |
980 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
981 | ||
982 | for addr_type in ADDR_TYPES: | |
983 | input_routes_1 = { | |
984 | "r1": {"static_routes": [{"network": NETWORK4_1[addr_type], "vrf": "RED"}]} | |
985 | } | |
986 | ||
987 | result = verify_attributes_for_evpn_routes( | |
988 | tgen, topo, "d2", input_routes_1, rt="auto", rt_peer="e1", expected=False | |
989 | ) | |
db726bb8 KK |
990 | assert result is not True, ( |
991 | "Testcase {} : Failed \n " | |
244f2df0 | 992 | "Expected: Malformed Auto-RT value should not be accepted in {} \n " |
db726bb8 | 993 | "Found: {}".format(tc_name, "d2", result) |
d7d21c3a | 994 | ) |
1b66072c KK |
995 | |
996 | step("Un-configure VNI number more than boundary limit (16777215)") | |
997 | ||
998 | input_dict_vni = {"e1": {"vrfs": [{"name": "RED", "no_vni": 16777215}]}} | |
999 | result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni) | |
1000 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
1001 | ||
1002 | write_test_footer(tc_name) | |
1003 | ||
1004 | ||
1005 | if __name__ == "__main__": | |
1006 | args = ["-s"] + sys.argv[1:] | |
1007 | sys.exit(pytest.main(args)) |