]>
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: | |
12 | ||
13 | 1. RD verification (manual/auto). | |
14 | 2. RT verification(manual) | |
15 | 3. In an active/standby EVPN implementation, if active DCG goes down, | |
11761ab0 | 16 | secondary takes over. |
1b66072c | 17 | 4. EVPN routes are advertised/withdrawn, based on VNFs |
11761ab0 | 18 | advertising/withdrawing IP prefixes. |
1b66072c KK |
19 | 5. Route-map operations for EVPN address family. |
20 | 6. BGP attributes for EVPN address-family. | |
21 | """ | |
22 | ||
23 | import os | |
1b66072c KK |
24 | import sys |
25 | import json | |
26 | import time | |
27 | import pytest | |
28 | import platform | |
29 | from copy import deepcopy | |
1b66072c KK |
30 | |
31 | ||
32 | # Save the Current Working Directory to find configuration files. | |
33 | CWD = os.path.dirname(os.path.realpath(__file__)) | |
34 | sys.path.append(os.path.join(CWD, "../")) | |
35 | sys.path.append(os.path.join(CWD, "../lib/")) | |
36 | ||
37 | # Required to instantiate the topology builder class. | |
38 | ||
39 | # pylint: disable=C0413 | |
40 | # Import topogen and topotest helpers | |
41 | from lib.topotest import version_cmp | |
42 | from lib.topogen import Topogen, get_topogen | |
1b66072c KK |
43 | |
44 | from lib.common_config import ( | |
45 | start_topology, | |
46 | write_test_header, | |
47 | check_address_types, | |
48 | write_test_footer, | |
49 | reset_config_on_routers, | |
50 | verify_rib, | |
51 | step, | |
52 | create_route_maps, | |
1b66072c | 53 | create_static_routes, |
1b66072c KK |
54 | create_vrf_cfg, |
55 | check_router_status, | |
56 | apply_raw_config, | |
57 | configure_vxlan, | |
58 | configure_brctl, | |
701a0192 | 59 | create_interface_in_kernel, |
cbeda33d | 60 | kill_router_daemons, |
ac6ef90b | 61 | start_router_daemons, |
1b66072c KK |
62 | ) |
63 | ||
64 | from lib.topolog import logger | |
65 | from lib.bgp import ( | |
66 | verify_bgp_convergence, | |
67 | create_router_bgp, | |
1b66072c KK |
68 | verify_best_path_as_per_bgp_attribute, |
69 | verify_attributes_for_evpn_routes, | |
701a0192 | 70 | verify_evpn_routes, |
1b66072c KK |
71 | ) |
72 | from lib.topojson import build_topo_from_json, build_config_from_json | |
73 | ||
6a1e8951 DS |
74 | pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] |
75 | ||
1b66072c KK |
76 | # Global variables |
77 | NETWORK1_1 = {"ipv4": "10.1.1.1/32", "ipv6": "10::1/128"} | |
78 | NETWORK1_2 = {"ipv4": "40.1.1.1/32", "ipv6": "40::1/128"} | |
79 | NETWORK1_3 = {"ipv4": "40.1.1.2/32", "ipv6": "40::2/128"} | |
80 | NETWORK1_4 = {"ipv4": "40.1.1.3/32", "ipv6": "40::3/128"} | |
81 | NETWORK2_1 = {"ipv4": "20.1.1.1/32", "ipv6": "20::1/128"} | |
82 | NETWORK3_1 = {"ipv4": "30.1.1.1/32", "ipv6": "30::1/128"} | |
83 | NETWORK4_1 = {"ipv4": "100.1.1.1/32 ", "ipv6": "100::100/128"} | |
84 | NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"} | |
85 | VNI_1 = 75100 | |
86 | VNI_2 = 75200 | |
87 | VNI_3 = 75300 | |
88 | MAC_1 = "00:80:48:ba:d1:00" | |
89 | MAC_2 = "00:80:48:ba:d1:01" | |
90 | MAC_3 = "00:80:48:ba:d1:02" | |
91 | BRCTL_1 = "br100" | |
92 | BRCTL_2 = "br200" | |
93 | BRCTL_3 = "br300" | |
94 | VXLAN_1 = "vxlan75100" | |
95 | VXLAN_2 = "vxlan75200" | |
96 | VXLAN_3 = "vxlan75300" | |
97 | BRIDGE_INTF1 = "120.0.0.1" | |
98 | BRIDGE_INTF2 = "120.0.0.2" | |
99 | BRIDGE_INTF3 = "120.0.0.3" | |
100 | ||
101 | VXLAN = { | |
102 | "vxlan_name": [VXLAN_1, VXLAN_2, VXLAN_3], | |
103 | "vxlan_id": [75100, 75200, 75300], | |
104 | "dstport": 4789, | |
105 | "local_addr": {"e1": BRIDGE_INTF1, "d1": BRIDGE_INTF2, "d2": BRIDGE_INTF3}, | |
106 | "learning": "no", | |
107 | } | |
108 | BRCTL = { | |
109 | "brctl_name": [BRCTL_1, BRCTL_2, BRCTL_3], | |
110 | "addvxlan": [VXLAN_1, VXLAN_2, VXLAN_3], | |
111 | "vrf": ["RED", "BLUE", "GREEN"], | |
112 | "stp": [0, 0, 0], | |
113 | } | |
114 | ||
115 | ||
1b66072c KK |
116 | def setup_module(mod): |
117 | """ | |
118 | Sets up the pytest environment | |
119 | ||
120 | * `mod`: module name | |
121 | """ | |
122 | ||
123 | global topo | |
124 | testsuite_run_time = time.asctime(time.localtime(time.time())) | |
125 | logger.info("Testsuite start time: {}".format(testsuite_run_time)) | |
126 | logger.info("=" * 40) | |
127 | ||
128 | logger.info("Running setup_module to create topology") | |
129 | ||
130 | # This function initiates the topology build with Topogen... | |
dc4c450f KK |
131 | json_file = "{}/evpn_type5_topo1.json".format(CWD) |
132 | tgen = Topogen(json_file, mod.__name__) | |
133 | topo = tgen.json_topo | |
134 | ||
1b66072c KK |
135 | # ... and here it calls Mininet initialization functions. |
136 | ||
137 | # Starting topology, create tmp files which are loaded to routers | |
d60a3f0e | 138 | # to start daemons and then start routers |
1b66072c KK |
139 | start_topology(tgen) |
140 | ||
141 | # Creating configuration from JSON | |
142 | build_config_from_json(tgen, topo) | |
143 | ||
701a0192 | 144 | if version_cmp(platform.release(), "4.19") < 0: |
145 | error_msg = ( | |
146 | 'EVPN tests will not run (have kernel "{}", ' | |
147 | "but it requires >= 4.19)".format(platform.release()) | |
148 | ) | |
1b66072c KK |
149 | pytest.skip(error_msg) |
150 | ||
151 | global BGP_CONVERGENCE | |
152 | global ADDR_TYPES | |
153 | ADDR_TYPES = check_address_types() | |
154 | ||
155 | BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) | |
156 | assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format( | |
157 | BGP_CONVERGENCE | |
158 | ) | |
159 | ||
160 | logger.info("Pre-requisite config for testsuite") | |
161 | prerequisite_config_for_test_suite(tgen) | |
162 | ||
163 | logger.info("Running setup_module() done") | |
164 | ||
165 | ||
166 | def teardown_module(): | |
167 | """Teardown the pytest environment""" | |
168 | ||
169 | logger.info("Running teardown_module to delete topology") | |
170 | ||
171 | tgen = get_topogen() | |
172 | ||
173 | # Stop toplogy and Remove tmp files | |
174 | tgen.stop_topology() | |
175 | ||
176 | logger.info( | |
177 | "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) | |
178 | ) | |
179 | logger.info("=" * 40) | |
180 | ||
181 | ||
182 | ##################################################### | |
183 | # | |
184 | # Testcases | |
185 | # | |
186 | ##################################################### | |
187 | ||
188 | ||
189 | def prerequisite_config_for_test_suite(tgen): | |
190 | """ | |
191 | API to do prerequisite config for testsuite | |
192 | ||
193 | parameters: | |
194 | ----------- | |
195 | * `tgen`: topogen object | |
196 | """ | |
197 | ||
198 | step("Configure vxlan, bridge interface") | |
199 | for dut in ["e1", "d1", "d2"]: | |
200 | step("[DUT: ]Configure vxlan") | |
201 | vxlan_input = { | |
202 | dut: { | |
203 | "vxlan": [ | |
204 | { | |
205 | "vxlan_name": VXLAN["vxlan_name"], | |
206 | "vxlan_id": VXLAN["vxlan_id"], | |
207 | "dstport": VXLAN["dstport"], | |
208 | "local_addr": VXLAN["local_addr"][dut], | |
209 | "learning": VXLAN["learning"], | |
210 | } | |
211 | ] | |
212 | } | |
213 | } | |
214 | ||
215 | result = configure_vxlan(tgen, vxlan_input) | |
d7d21c3a | 216 | assert result is True, "Testcase :Failed \n Error: {}".format(result) |
1b66072c KK |
217 | |
218 | step("Configure bridge interface") | |
219 | brctl_input = { | |
220 | dut: { | |
221 | "brctl": [ | |
222 | { | |
223 | "brctl_name": BRCTL["brctl_name"], | |
224 | "addvxlan": BRCTL["addvxlan"], | |
225 | "vrf": BRCTL["vrf"], | |
226 | "stp": BRCTL["stp"], | |
227 | } | |
228 | ] | |
229 | } | |
230 | } | |
231 | result = configure_brctl(tgen, topo, brctl_input) | |
d7d21c3a | 232 | assert result is True, "Testcase :Failed \n Error: {}".format(result) |
1b66072c KK |
233 | |
234 | step("Configure default routes") | |
235 | add_default_routes(tgen) | |
236 | ||
237 | ||
238 | def add_default_routes(tgen): | |
239 | """ | |
240 | API to do prerequisite config for testsuite | |
241 | ||
242 | parameters: | |
243 | ----------- | |
244 | * `tgen`: topogen object | |
245 | """ | |
246 | ||
247 | step("Add default routes..") | |
248 | ||
249 | default_routes = { | |
250 | "e1": { | |
251 | "static_routes": [ | |
252 | { | |
253 | "network": "{}/32".format(VXLAN["local_addr"]["d1"]), | |
254 | "next_hop": topo["routers"]["d1"]["links"]["e1-link1"][ | |
255 | "ipv4" | |
256 | ].split("/")[0], | |
257 | }, | |
258 | { | |
259 | "network": "{}/32".format(VXLAN["local_addr"]["d2"]), | |
260 | "next_hop": topo["routers"]["d2"]["links"]["e1-link1"][ | |
261 | "ipv4" | |
262 | ].split("/")[0], | |
263 | }, | |
264 | ] | |
265 | }, | |
266 | "d1": { | |
267 | "static_routes": [ | |
268 | { | |
269 | "network": "{}/32".format(VXLAN["local_addr"]["e1"]), | |
270 | "next_hop": topo["routers"]["e1"]["links"]["d1-link1"][ | |
271 | "ipv4" | |
272 | ].split("/")[0], | |
273 | }, | |
274 | { | |
275 | "network": "{}/32".format(VXLAN["local_addr"]["d2"]), | |
276 | "next_hop": topo["routers"]["e1"]["links"]["d1-link1"][ | |
277 | "ipv4" | |
278 | ].split("/")[0], | |
279 | }, | |
280 | ] | |
281 | }, | |
282 | "d2": { | |
283 | "static_routes": [ | |
284 | { | |
285 | "network": "{}/32".format(VXLAN["local_addr"]["d1"]), | |
286 | "next_hop": topo["routers"]["e1"]["links"]["d2-link1"][ | |
287 | "ipv4" | |
288 | ].split("/")[0], | |
289 | }, | |
290 | { | |
291 | "network": "{}/32".format(VXLAN["local_addr"]["e1"]), | |
292 | "next_hop": topo["routers"]["e1"]["links"]["d2-link1"][ | |
293 | "ipv4" | |
294 | ].split("/")[0], | |
295 | }, | |
296 | ] | |
297 | }, | |
298 | } | |
299 | ||
300 | result = create_static_routes(tgen, default_routes) | |
d7d21c3a | 301 | assert result is True, "Testcase :Failed \n Error: {}".format(result) |
1b66072c KK |
302 | |
303 | ||
304 | def test_RD_verification_manual_and_auto_p0(request): | |
305 | """ | |
306 | RD verification (manual/auto). | |
307 | """ | |
308 | ||
309 | tgen = get_topogen() | |
310 | tc_name = request.node.name | |
311 | write_test_header(tc_name) | |
312 | check_router_status(tgen) | |
313 | reset_config_on_routers(tgen) | |
314 | add_default_routes(tgen) | |
315 | ||
316 | if tgen.routers_have_failure(): | |
317 | pytest.skip(tgen.errors) | |
318 | ||
319 | step( | |
320 | "Advertise prefixes from VNF routers R1 and R2 in associated " | |
321 | "VRFs for both address-family." | |
322 | ) | |
323 | step( | |
324 | "Advertise vrf RED's routes in EVPN address family from Edge-1 router" | |
325 | ", without manual configuration of RD." | |
326 | ) | |
327 | ||
328 | for addr_type in ADDR_TYPES: | |
329 | input_dict_1 = { | |
330 | "r1": { | |
331 | "static_routes": [ | |
332 | { | |
333 | "network": NETWORK1_1[addr_type], | |
334 | "next_hop": NEXT_HOP_IP[addr_type], | |
335 | "vrf": "RED", | |
336 | } | |
337 | ] | |
338 | }, | |
339 | "r2": { | |
340 | "static_routes": [ | |
341 | { | |
342 | "network": NETWORK2_1[addr_type], | |
343 | "next_hop": NEXT_HOP_IP[addr_type], | |
344 | "vrf": "BLUE", | |
345 | }, | |
346 | { | |
347 | "network": NETWORK3_1[addr_type], | |
348 | "next_hop": NEXT_HOP_IP[addr_type], | |
349 | "vrf": "GREEN", | |
701a0192 | 350 | }, |
1b66072c | 351 | ] |
701a0192 | 352 | }, |
1b66072c KK |
353 | } |
354 | ||
355 | result = create_static_routes(tgen, input_dict_1) | |
356 | assert result is True, "Testcase {} : Failed \n Error: {}".format( | |
357 | tc_name, result | |
358 | ) | |
359 | ||
360 | step("Verify on DCG-1 and DCG-2:") | |
361 | step("EVPN route for 10.1.1.1/32 has auto-assigned RD value.") | |
362 | ||
363 | for dut in ["d1", "d2"]: | |
364 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
365 | result = verify_attributes_for_evpn_routes( | |
366 | tgen, topo, dut, input_routes, rd="auto", rd_peer="e1" | |
367 | ) | |
2055cbee DS |
368 | assert result is True, "Testcase {} on {} :Failed \n Error: {}".format( |
369 | tc_name, dut, result | |
1b66072c KK |
370 | ) |
371 | ||
372 | step( | |
373 | "Configure RD for vrf RED manually as 50.50.50.50:50 and " | |
374 | "advertise vrf RED's routes in EVPN address family from " | |
375 | "Edge-1 router." | |
376 | ) | |
377 | ||
378 | input_dict_rd = { | |
379 | "e1": { | |
380 | "bgp": [ | |
381 | { | |
382 | "local_as": "100", | |
383 | "vrf": "RED", | |
384 | "address_family": {"l2vpn": {"evpn": {"rd": "50.50.50.50:50"}}}, | |
385 | } | |
386 | ] | |
387 | } | |
388 | } | |
389 | ||
390 | result = create_router_bgp(tgen, topo, input_dict_rd) | |
391 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
392 | ||
393 | step("EVPN route for vrf RED has RD value as 50.50.50.50:50") | |
394 | for dut in ["d1", "d2"]: | |
395 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
396 | result = verify_attributes_for_evpn_routes( | |
397 | tgen, topo, dut, input_routes, rd="50.50.50.50:50" | |
398 | ) | |
2055cbee DS |
399 | assert result is True, "Testcase {} on {} :Failed \n Error: {}".format( |
400 | tc_name, dut, result | |
1b66072c KK |
401 | ) |
402 | ||
403 | step( | |
404 | "Configure RD for vrf RED manually as 100.100.100.100:100 and " | |
405 | "advertise vrf RED's routes in EVPN address family from Edge-1 " | |
406 | "router." | |
407 | ) | |
408 | input_dict_rd = { | |
409 | "e1": { | |
410 | "bgp": [ | |
411 | { | |
412 | "local_as": "100", | |
413 | "vrf": "RED", | |
414 | "address_family": { | |
415 | "l2vpn": {"evpn": {"rd": "100.100.100.100:100"}} | |
701a0192 | 416 | }, |
1b66072c KK |
417 | } |
418 | ] | |
419 | } | |
420 | } | |
421 | ||
422 | result = create_router_bgp(tgen, topo, input_dict_rd) | |
423 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
424 | ||
425 | step( | |
426 | "EVPN route for vrf RED is overridden with RD value as " "100.100.100.100:100." | |
427 | ) | |
428 | ||
429 | for dut in ["d1", "d2"]: | |
430 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
431 | result = verify_attributes_for_evpn_routes( | |
432 | tgen, topo, dut, input_routes, rd="100.100.100.100:100" | |
433 | ) | |
2055cbee DS |
434 | assert result is True, "Testcase {} on {} :Failed \n Error: {}".format( |
435 | tc_name, dut, result | |
1b66072c KK |
436 | ) |
437 | ||
438 | step( | |
439 | "Configure RD for vrf BLUE manually same as vrf RED " | |
440 | "(100.100.100.100:100) and advertise vrf RED and BLUE's routes " | |
441 | "in EVPN address family from Edge-1 router." | |
442 | ) | |
443 | ||
444 | input_dict_rd = { | |
445 | "e1": { | |
446 | "bgp": [ | |
447 | { | |
448 | "local_as": "100", | |
449 | "vrf": "BLUE", | |
450 | "address_family": { | |
451 | "l2vpn": {"evpn": {"rd": "100.100.100.100:100"}} | |
452 | }, | |
453 | } | |
454 | ] | |
455 | } | |
456 | } | |
457 | ||
458 | result = create_router_bgp(tgen, topo, input_dict_rd) | |
459 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
460 | ||
461 | step( | |
462 | "Delete manually configured RD and advertise vrf RED's routes " | |
463 | "in EVPN address family from Edge-1 router." | |
464 | ) | |
465 | ||
466 | input_dict_rd = { | |
467 | "e1": { | |
468 | "bgp": [ | |
469 | { | |
470 | "local_as": "100", | |
471 | "vrf": "RED", | |
472 | "address_family": { | |
473 | "l2vpn": {"evpn": {"no rd": "100.100.100.100:100"}} | |
474 | }, | |
475 | } | |
476 | ] | |
477 | } | |
478 | } | |
479 | ||
480 | result = create_router_bgp(tgen, topo, input_dict_rd) | |
481 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
482 | ||
483 | step( | |
484 | "Configure same RD value for vrf GREEN, as auto generated RD " | |
485 | "value for vrf RED on Edge-1 router." | |
486 | ) | |
487 | ||
488 | input_dict_rd = { | |
489 | "e1": { | |
490 | "bgp": [ | |
491 | { | |
492 | "local_as": "100", | |
493 | "vrf": "GREEN", | |
494 | "address_family": {"l2vpn": {"evpn": {"rd": "10.0.0.33:1"}}}, | |
495 | } | |
496 | ] | |
497 | } | |
498 | } | |
499 | ||
500 | result = create_router_bgp(tgen, topo, input_dict_rd) | |
501 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
502 | ||
503 | step("Delete auto configured RD value from vrf RED in EVPN " "address family.") | |
504 | ||
505 | input_dict_rd = { | |
506 | "e1": { | |
507 | "bgp": [ | |
508 | { | |
509 | "local_as": "100", | |
510 | "vrf": "GREEN", | |
511 | "address_family": {"l2vpn": {"evpn": {"no rd": "10.0.0.33:1"}}}, | |
512 | } | |
513 | ] | |
514 | } | |
515 | } | |
516 | ||
517 | result = create_router_bgp(tgen, topo, input_dict_rd) | |
518 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
519 | ||
520 | step("Configure RD value as 100.100.100:100") | |
521 | ||
522 | input_dict_rd = { | |
523 | "e1": { | |
524 | "bgp": [ | |
525 | { | |
526 | "local_as": "100", | |
527 | "vrf": "GREEN", | |
528 | "address_family": {"l2vpn": {"evpn": {"rd": "100.100.100:100"}}}, | |
529 | } | |
530 | ] | |
531 | } | |
532 | } | |
533 | ||
534 | result = create_router_bgp(tgen, topo, input_dict_rd) | |
535 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
536 | ||
537 | write_test_footer(tc_name) | |
538 | ||
539 | ||
540 | def test_RT_verification_manual_p0(request): | |
541 | """ | |
542 | RT verification(manual) | |
543 | """ | |
544 | ||
545 | tgen = get_topogen() | |
546 | tc_name = request.node.name | |
547 | write_test_header(tc_name) | |
548 | check_router_status(tgen) | |
549 | reset_config_on_routers(tgen) | |
550 | add_default_routes(tgen) | |
551 | ||
552 | if tgen.routers_have_failure(): | |
553 | pytest.skip(tgen.errors) | |
554 | ||
555 | step( | |
556 | "Advertise prefixes from VNF routers R1 and R2 in associated " | |
557 | "VRFs for both address-family." | |
558 | ) | |
559 | step("Advertise VRF routes as in EVPN address family from Edge-1 " "router.") | |
560 | ||
561 | for addr_type in ADDR_TYPES: | |
562 | input_dict_1 = { | |
563 | "r1": { | |
564 | "static_routes": [ | |
565 | { | |
566 | "network": NETWORK1_1[addr_type], | |
567 | "next_hop": NEXT_HOP_IP[addr_type], | |
568 | "vrf": "RED", | |
569 | } | |
570 | ] | |
571 | }, | |
572 | "r2": { | |
573 | "static_routes": [ | |
574 | { | |
575 | "network": NETWORK2_1[addr_type], | |
576 | "next_hop": NEXT_HOP_IP[addr_type], | |
577 | "vrf": "BLUE", | |
578 | }, | |
579 | { | |
580 | "network": NETWORK3_1[addr_type], | |
581 | "next_hop": NEXT_HOP_IP[addr_type], | |
582 | "vrf": "GREEN", | |
701a0192 | 583 | }, |
1b66072c | 584 | ] |
701a0192 | 585 | }, |
1b66072c KK |
586 | } |
587 | ||
588 | result = create_static_routes(tgen, input_dict_1) | |
589 | assert result is True, "Testcase {} : Failed \n Error: {}".format( | |
590 | tc_name, result | |
591 | ) | |
592 | ||
593 | step( | |
594 | "Configure RT for vrf RED manually as export 100:100 " | |
595 | "and advertise vrf RED's routes in EVPN address family" | |
596 | " from Edge-1 router." | |
597 | ) | |
598 | ||
599 | input_dict_rt = { | |
600 | "e1": { | |
601 | "bgp": [ | |
602 | { | |
603 | "local_as": "100", | |
604 | "vrf": "RED", | |
605 | "address_family": { | |
606 | "ipv4": { | |
607 | "unicast": {"neighbor": {"r1": {"dest_link": {"e1": {}}}}} | |
608 | }, | |
609 | "ipv6": { | |
610 | "unicast": {"neighbor": {"r1": {"dest_link": {"e1": {}}}}} | |
611 | }, | |
612 | "l2vpn": { | |
613 | "evpn": {"route-target": {"export": [{"value": "100:100"}]}} | |
614 | }, | |
701a0192 | 615 | }, |
1b66072c KK |
616 | } |
617 | ] | |
618 | } | |
619 | } | |
620 | ||
621 | result = create_router_bgp(tgen, topo, input_dict_rt) | |
622 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
623 | ||
624 | step( | |
625 | "Verify on dcg-1 and dcg-2, EVPN route for 10.1.1.1/32" | |
626 | " and 10::1/128 have RT value as 100:100." | |
627 | ) | |
628 | ||
629 | for dut in ["d1", "d2"]: | |
630 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
631 | result = verify_attributes_for_evpn_routes( | |
632 | tgen, topo, dut, input_routes, rt="100:100" | |
633 | ) | |
2055cbee DS |
634 | assert result is True, "Testcase {} on {} :Failed \n Error: {}".format( |
635 | tc_name, dut, result | |
1b66072c KK |
636 | ) |
637 | ||
638 | step( | |
639 | "Configure RT for vrf RED manually as export 500:500 and" | |
640 | " advertise vrf RED's routes in EVPN address family from" | |
641 | " e1 router." | |
642 | ) | |
643 | ||
644 | input_dict_rt = { | |
645 | "e1": { | |
646 | "bgp": [ | |
647 | { | |
648 | "local_as": "100", | |
649 | "vrf": "RED", | |
650 | "address_family": { | |
651 | "l2vpn": { | |
652 | "evpn": {"route-target": {"export": [{"value": "500:500"}]}} | |
653 | } | |
654 | }, | |
655 | } | |
656 | ] | |
657 | } | |
658 | } | |
659 | ||
660 | result = create_router_bgp(tgen, topo, input_dict_rt) | |
661 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
662 | ||
663 | step( | |
664 | "Verify on dcg-1 and dcg-2, EVPN route for 10.1.1.1/32" | |
665 | " and 10::1/128 have RT value as 500:500." | |
666 | ) | |
667 | ||
668 | for dut in ["d1", "d2"]: | |
669 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
670 | result = verify_attributes_for_evpn_routes( | |
671 | tgen, topo, dut, input_routes, rt=["100:100", "500:500"] | |
672 | ) | |
2055cbee DS |
673 | assert result is True, "Testcase {} on {} :Failed \n Error: {}".format( |
674 | tc_name, dut, result | |
1b66072c KK |
675 | ) |
676 | ||
677 | step( | |
678 | "Import RT value 100:100 and 500:500 in vrf BLUE manually on" | |
679 | " peer router DCG-1 and DCG-2." | |
680 | ) | |
681 | ||
682 | input_dict_rt = { | |
683 | "d1": { | |
684 | "bgp": [ | |
685 | { | |
686 | "local_as": "100", | |
687 | "vrf": "BLUE", | |
688 | "address_family": { | |
689 | "l2vpn": { | |
690 | "evpn": { | |
691 | "route-target": { | |
692 | "import": [ | |
693 | {"value": "100:100"}, | |
694 | {"value": "500:500"}, | |
695 | ] | |
696 | } | |
697 | } | |
698 | } | |
699 | }, | |
700 | } | |
701 | ] | |
702 | }, | |
703 | "d2": { | |
704 | "bgp": [ | |
705 | { | |
706 | "local_as": "200", | |
707 | "vrf": "BLUE", | |
708 | "address_family": { | |
709 | "l2vpn": { | |
710 | "evpn": { | |
711 | "route-target": { | |
712 | "import": [ | |
713 | {"value": "100:100"}, | |
714 | {"value": "500:500"}, | |
715 | ] | |
716 | } | |
717 | } | |
718 | } | |
719 | }, | |
720 | } | |
721 | ] | |
722 | }, | |
723 | } | |
724 | ||
725 | result = create_router_bgp(tgen, topo, input_dict_rt) | |
726 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
727 | ||
728 | step( | |
729 | "EVPN route for 10.1.1.1/32 and 10::1 should be installed " | |
730 | "in vrf BLUE on DCG-1 and DCG-2 and further advertised to " | |
731 | "VNF router." | |
732 | ) | |
733 | ||
734 | for addr_type in ADDR_TYPES: | |
735 | input_routes = { | |
736 | "r1": { | |
737 | "static_routes": [{"network": [NETWORK1_1[addr_type]], "vrf": "BLUE"}] | |
738 | } | |
739 | } | |
740 | result = verify_rib(tgen, addr_type, "d1", input_routes) | |
741 | assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) | |
742 | ||
743 | result = verify_rib(tgen, addr_type, "d2", input_routes) | |
744 | assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) | |
745 | ||
746 | step( | |
747 | "Delete import RT value 500:500 in vrf BLUE manually on " | |
748 | "peer router DCG-1 and DCG-2." | |
749 | ) | |
750 | ||
751 | input_dict_rt = { | |
752 | "d1": { | |
753 | "bgp": [ | |
754 | { | |
755 | "local_as": "100", | |
756 | "vrf": "BLUE", | |
757 | "address_family": { | |
758 | "l2vpn": { | |
759 | "evpn": { | |
760 | "route-target": { | |
761 | "import": [{"value": "500:500", "delete": True}] | |
762 | } | |
763 | } | |
764 | } | |
765 | }, | |
766 | } | |
767 | ] | |
768 | }, | |
769 | "d2": { | |
770 | "bgp": [ | |
771 | { | |
772 | "local_as": "200", | |
773 | "vrf": "BLUE", | |
774 | "address_family": { | |
775 | "l2vpn": { | |
776 | "evpn": { | |
777 | "route-target": { | |
778 | "import": [{"value": "500:500", "delete": True}] | |
779 | } | |
780 | } | |
781 | } | |
782 | }, | |
783 | } | |
784 | ] | |
785 | }, | |
786 | } | |
787 | ||
788 | result = create_router_bgp(tgen, topo, input_dict_rt) | |
789 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
790 | ||
791 | for dut in ["d1", "d2"]: | |
792 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
793 | result = verify_attributes_for_evpn_routes( | |
794 | tgen, topo, dut, input_routes, rt=["100:100", "500:500"] | |
795 | ) | |
2055cbee DS |
796 | assert result is True, "Testcase {} on {} :Failed \n Error: {}".format( |
797 | tc_name, dut, result | |
1b66072c KK |
798 | ) |
799 | ||
800 | step("Delete RT export value 100:100 for vrf RED on Edge-1") | |
801 | ||
802 | input_dict_rt = { | |
803 | "e1": { | |
804 | "bgp": [ | |
805 | { | |
806 | "local_as": "100", | |
807 | "vrf": "RED", | |
808 | "address_family": { | |
809 | "l2vpn": { | |
810 | "evpn": { | |
811 | "route-target": { | |
812 | "export": [{"value": "100:100", "delete": True}] | |
813 | } | |
814 | } | |
815 | } | |
816 | }, | |
817 | } | |
818 | ] | |
819 | } | |
820 | } | |
821 | ||
822 | result = create_router_bgp(tgen, topo, input_dict_rt) | |
823 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
824 | ||
825 | step( | |
826 | "EVPN route for 10.1.1.1/32 and 10::1 should be withdrawn " | |
827 | "from vrf BLUE on DCG-1,DCG-2 and VNF router." | |
828 | ) | |
829 | ||
830 | for addr_type in ADDR_TYPES: | |
831 | input_routes = { | |
832 | "r1": { | |
833 | "static_routes": [{"network": [NETWORK1_1[addr_type]], "vrf": "BLUE"}] | |
834 | } | |
835 | } | |
836 | result = verify_rib(tgen, addr_type, "d1", input_routes, expected=False) | |
837 | assert result is not True, ( | |
db726bb8 KK |
838 | "Testcase {} : Failed \n " |
839 | "Expected: Routes should not be present in {} RIB \n " | |
840 | "Found: {}".format(tc_name, "d1", result) | |
1b66072c | 841 | ) |
1b66072c KK |
842 | |
843 | result = verify_rib(tgen, addr_type, "d2", input_routes, expected=False) | |
844 | assert result is not True, ( | |
db726bb8 KK |
845 | "Testcase {} : Failed \n " |
846 | "Expected: Routes should not be present in {} RIB \n " | |
847 | "Found: {}".format(tc_name, "d2", result) | |
1b66072c | 848 | ) |
1b66072c KK |
849 | |
850 | step( | |
851 | "Configure RT value as 100:100000010000010000101010 to check " | |
852 | "the boundary value." | |
853 | ) | |
854 | ||
855 | input_dict_rt = { | |
856 | "e1": { | |
857 | "bgp": [ | |
858 | { | |
859 | "local_as": "100", | |
860 | "vrf": "RED", | |
861 | "address_family": { | |
862 | "l2vpn": { | |
863 | "evpn": { | |
864 | "route-target": { | |
865 | "export": [ | |
866 | {"value": "100:100000010000010000101010"} | |
867 | ] | |
868 | } | |
869 | } | |
870 | } | |
871 | }, | |
872 | } | |
873 | ] | |
874 | } | |
875 | } | |
876 | ||
877 | result = create_router_bgp(tgen, topo, input_dict_rt) | |
878 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
879 | ||
880 | step( | |
881 | "CLI error: RT value: 100:100000010000010000101010 should not " "be configured" | |
882 | ) | |
883 | ||
884 | dut = "e1" | |
885 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
886 | result = verify_attributes_for_evpn_routes( | |
887 | tgen, topo, dut, input_routes, rt="100:100000010000010000101010", expected=False | |
888 | ) | |
889 | assert result is not True, ( | |
db726bb8 | 890 | "Testcase {} : Failed \n " |
244f2df0 | 891 | "Expected: RT value out of boundary error in {} \n " |
db726bb8 | 892 | "Found: {}".format(tc_name, dut, result) |
1b66072c | 893 | ) |
1b66072c KK |
894 | |
895 | write_test_footer(tc_name) | |
896 | ||
897 | ||
898 | def test_active_standby_evpn_implementation_p1(request): | |
899 | """ | |
900 | In an active/standby EVPN implementation, if active DCG goes down, | |
901 | secondary takes over. | |
902 | """ | |
903 | ||
904 | tgen = get_topogen() | |
905 | tc_name = request.node.name | |
906 | write_test_header(tc_name) | |
907 | check_router_status(tgen) | |
908 | reset_config_on_routers(tgen) | |
909 | add_default_routes(tgen) | |
910 | ||
911 | if tgen.routers_have_failure(): | |
912 | pytest.skip(tgen.errors) | |
913 | ||
914 | step( | |
915 | "Taken care in base config: Configure BGP neighborship for both " | |
916 | "address families(IPv4 & IPv6) between DCG-1/DCG-2 and VFN routers" | |
917 | "(R3 and R4)." | |
918 | ) | |
919 | ||
920 | step( | |
921 | "BGP neighborships come up within defined VRFs. Please use below " | |
922 | "command: sh bgp vrf all summary" | |
923 | ) | |
924 | ||
925 | result = verify_bgp_convergence(tgen, topo, "d1") | |
926 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
927 | ||
928 | result = verify_bgp_convergence(tgen, topo, "d2") | |
929 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
930 | ||
931 | step( | |
932 | "Advertise prefixes from VNF routers R3 and R4 in associated " | |
933 | "VRFs for both address-families." | |
934 | ) | |
935 | ||
936 | for addr_type in ADDR_TYPES: | |
937 | input_dict_1 = { | |
938 | "r3": { | |
939 | "static_routes": [ | |
940 | { | |
941 | "network": NETWORK1_2[addr_type], | |
942 | "next_hop": NEXT_HOP_IP[addr_type], | |
943 | "vrf": "RED", | |
944 | } | |
945 | ] | |
946 | }, | |
947 | "r4": { | |
948 | "static_routes": [ | |
949 | { | |
950 | "network": NETWORK1_3[addr_type], | |
951 | "next_hop": NEXT_HOP_IP[addr_type], | |
952 | "vrf": "BLUE", | |
953 | }, | |
954 | { | |
955 | "network": NETWORK1_4[addr_type], | |
956 | "next_hop": NEXT_HOP_IP[addr_type], | |
957 | "vrf": "GREEN", | |
701a0192 | 958 | }, |
1b66072c | 959 | ] |
701a0192 | 960 | }, |
1b66072c KK |
961 | } |
962 | ||
963 | result = create_static_routes(tgen, input_dict_1) | |
964 | assert result is True, "Testcase {} : Failed \n Error: {}".format( | |
965 | tc_name, result | |
966 | ) | |
967 | ||
968 | step( | |
969 | "Redistribute static in (IPv4 and IPv6) address-family " | |
970 | "on Edge-1 for all VRFs." | |
971 | ) | |
972 | ||
973 | input_dict_2 = {} | |
974 | for dut in ["r3", "r4"]: | |
975 | temp = {dut: {"bgp": []}} | |
976 | input_dict_2.update(temp) | |
977 | ||
978 | if dut == "r3": | |
979 | VRFS = ["RED"] | |
980 | AS_NUM = [3] | |
981 | if dut == "r4": | |
982 | VRFS = ["BLUE", "GREEN"] | |
983 | AS_NUM = [4, 4] | |
984 | ||
985 | for vrf, as_num in zip(VRFS, AS_NUM): | |
986 | temp[dut]["bgp"].append( | |
987 | { | |
988 | "local_as": as_num, | |
989 | "vrf": vrf, | |
990 | "address_family": { | |
991 | "ipv4": { | |
992 | "unicast": {"redistribute": [{"redist_type": "static"}]} | |
993 | }, | |
994 | "ipv6": { | |
995 | "unicast": {"redistribute": [{"redist_type": "static"}]} | |
996 | }, | |
997 | }, | |
998 | } | |
999 | ) | |
1000 | ||
1001 | result = create_router_bgp(tgen, topo, input_dict_2) | |
1002 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
1003 | ||
1004 | step("Prefixes are received in respective VRFs on DCG-1/DCG-2.") | |
1005 | ||
1006 | for addr_type in ADDR_TYPES: | |
1007 | input_routes = { | |
1008 | "r3": { | |
1009 | "static_routes": [ | |
1010 | { | |
1011 | "network": NETWORK1_2[addr_type], | |
1012 | "next_hop": NEXT_HOP_IP[addr_type], | |
1013 | "vrf": "RED", | |
1014 | } | |
1015 | ] | |
1016 | }, | |
1017 | "r4": { | |
1018 | "static_routes": [ | |
1019 | { | |
1020 | "network": NETWORK1_3[addr_type], | |
1021 | "next_hop": NEXT_HOP_IP[addr_type], | |
1022 | "vrf": "BLUE", | |
1023 | }, | |
1024 | { | |
1025 | "network": NETWORK1_4[addr_type], | |
1026 | "next_hop": NEXT_HOP_IP[addr_type], | |
1027 | "vrf": "GREEN", | |
1028 | }, | |
1029 | ] | |
1030 | }, | |
1031 | } | |
1032 | ||
1033 | result = verify_rib(tgen, addr_type, "d1", input_routes) | |
1034 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
1035 | tc_name, result | |
1036 | ) | |
1037 | ||
1038 | result = verify_rib(tgen, addr_type, "d2", input_routes) | |
1039 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
1040 | tc_name, result | |
1041 | ) | |
1042 | ||
1043 | step( | |
1044 | "Taken care in base config: Advertise VRF routes in EVPN " | |
1045 | "address-family from DCG-1 and DCG-2 router." | |
1046 | ) | |
1047 | ||
1048 | step("Verify on Edge-1 that EVPN routes are installed via next-hop " "as DCG-2.") | |
1049 | ||
1050 | for addr_type in ADDR_TYPES: | |
1051 | input_routes = { | |
1052 | "r3": { | |
1053 | "static_routes": [ | |
1054 | { | |
1055 | "network": NETWORK1_2[addr_type], | |
1056 | "next_hop": NEXT_HOP_IP[addr_type], | |
1057 | "vrf": "RED", | |
1058 | } | |
1059 | ] | |
1060 | }, | |
1061 | "r4": { | |
1062 | "static_routes": [ | |
1063 | { | |
1064 | "network": NETWORK1_3[addr_type], | |
1065 | "next_hop": NEXT_HOP_IP[addr_type], | |
1066 | "vrf": "BLUE", | |
1067 | }, | |
1068 | { | |
1069 | "network": NETWORK1_4[addr_type], | |
1070 | "next_hop": NEXT_HOP_IP[addr_type], | |
1071 | "vrf": "GREEN", | |
1072 | }, | |
1073 | ] | |
1074 | }, | |
1075 | } | |
1076 | ||
1077 | if addr_type == "ipv4": | |
1078 | result = verify_rib( | |
1079 | tgen, addr_type, "e1", input_routes, next_hop=BRIDGE_INTF2 | |
1080 | ) | |
1081 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
1082 | tc_name, result | |
1083 | ) | |
1084 | else: | |
1085 | result = verify_rib(tgen, addr_type, "e1", input_routes) | |
1086 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
1087 | tc_name, result | |
1088 | ) | |
1089 | ||
1090 | step( | |
1091 | "Configure 'next-hop self' on DCG-1 for peer Edge-1 in EVPN " "address-family." | |
1092 | ) | |
1093 | ||
1094 | input_dict_3 = { | |
1095 | "d1": { | |
1096 | "bgp": [ | |
1097 | { | |
1098 | "local_as": "100", | |
1099 | "address_family": { | |
1100 | "l2vpn": { | |
1101 | "evpn": { | |
1102 | "neighbor": { | |
1103 | "e1": { | |
1104 | "ipv4": {"d1-link1": {"next_hop_self": True}} | |
1105 | } | |
1106 | } | |
1107 | } | |
1108 | } | |
1109 | }, | |
1110 | } | |
1111 | ] | |
1112 | } | |
1113 | } | |
1114 | ||
1115 | result = create_router_bgp(tgen, topo, input_dict_3) | |
1116 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
1117 | ||
1118 | logger.info( | |
1119 | "Creating route-map so ipv6 glpbal ip wpuld be preferred " "as next-hop" | |
1120 | ) | |
1121 | ||
1122 | step( | |
1123 | "Verify on Edge-1 that EVPN routes are now preferred via " | |
1124 | "next-hop as DCG-1(iBGP) due to shortest AS-Path." | |
1125 | ) | |
1126 | ||
1127 | for addr_type in ADDR_TYPES: | |
1128 | ||
1129 | logger.info("Verifying only ipv4 routes") | |
1130 | if addr_type != "ipv4": | |
1131 | continue | |
1132 | ||
1133 | input_routes = { | |
1134 | "r3": { | |
1135 | "static_routes": [ | |
1136 | { | |
1137 | "network": NETWORK1_2[addr_type], | |
1138 | "next_hop": NEXT_HOP_IP[addr_type], | |
1139 | "vrf": "RED", | |
1140 | } | |
1141 | ] | |
1142 | }, | |
1143 | "r4": { | |
1144 | "static_routes": [ | |
1145 | { | |
1146 | "network": NETWORK1_3[addr_type], | |
1147 | "next_hop": NEXT_HOP_IP[addr_type], | |
1148 | "vrf": "BLUE", | |
1149 | }, | |
1150 | { | |
1151 | "network": NETWORK1_4[addr_type], | |
1152 | "next_hop": NEXT_HOP_IP[addr_type], | |
1153 | "vrf": "GREEN", | |
1154 | }, | |
1155 | ] | |
1156 | }, | |
1157 | } | |
1158 | ||
1159 | next_hop = topo["routers"]["d1"]["links"]["e1-link1"]["ipv4"].split("/")[0] | |
1160 | ||
1161 | result = verify_rib(tgen, addr_type, "e1", input_routes, next_hop=next_hop) | |
1162 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
1163 | tc_name, result | |
1164 | ) | |
1165 | ||
1166 | write_test_footer(tc_name) | |
1167 | ||
1168 | ||
1169 | def test_evpn_routes_from_VNFs_p1(request): | |
1170 | """ | |
1171 | EVPN routes are advertised/withdrawn, based on VNFs | |
1172 | advertising/withdrawing IP prefixes. | |
1173 | """ | |
1174 | ||
1175 | tgen = get_topogen() | |
1176 | tc_name = request.node.name | |
1177 | write_test_header(tc_name) | |
1178 | check_router_status(tgen) | |
1179 | reset_config_on_routers(tgen) | |
1180 | add_default_routes(tgen) | |
1181 | ||
1182 | if tgen.routers_have_failure(): | |
1183 | pytest.skip(tgen.errors) | |
1184 | ||
1185 | step( | |
1186 | "Advertise prefixes from VNF routers R1 and R2 in associated " | |
1187 | "VRFs for both address-family." | |
1188 | ) | |
1189 | ||
1190 | for addr_type in ADDR_TYPES: | |
1191 | input_dict_1 = { | |
1192 | "r1": { | |
1193 | "static_routes": [ | |
1194 | { | |
1195 | "network": NETWORK1_1[addr_type], | |
1196 | "next_hop": NEXT_HOP_IP[addr_type], | |
1197 | "vrf": "RED", | |
1198 | } | |
1199 | ] | |
1200 | }, | |
1201 | "r2": { | |
1202 | "static_routes": [ | |
1203 | { | |
1204 | "network": NETWORK2_1[addr_type], | |
1205 | "next_hop": NEXT_HOP_IP[addr_type], | |
1206 | "vrf": "BLUE", | |
1207 | }, | |
1208 | { | |
1209 | "network": NETWORK3_1[addr_type], | |
1210 | "next_hop": NEXT_HOP_IP[addr_type], | |
1211 | "vrf": "GREEN", | |
701a0192 | 1212 | }, |
1b66072c | 1213 | ] |
701a0192 | 1214 | }, |
1b66072c KK |
1215 | } |
1216 | ||
1217 | result = create_static_routes(tgen, input_dict_1) | |
1218 | assert result is True, "Testcase {} : Failed \n Error: {}".format( | |
1219 | tc_name, result | |
1220 | ) | |
1221 | ||
1222 | step( | |
1223 | "Taken care in base config: Advertise VNFs'(R1 and R2) " | |
1224 | "originated routes in EVPN address-family from Edge-1 to " | |
1225 | "DCG-1 and DCG-2 routers." | |
1226 | ) | |
1227 | step( | |
1228 | "Taken care in base config: Advertise IPv4 and IPv6 routes " | |
1229 | "from default vrf in EVPN address-family from Edge-1." | |
1230 | ) | |
1231 | ||
1232 | step( | |
1233 | "Verify on DCG-2 that VNF routes are received in respective " | |
1234 | "VRFs along with auto derived RD/RT values 'show bgp l2vpn evpn'" | |
1235 | ) | |
1236 | for dut in ["d1", "d2"]: | |
1237 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
1238 | result = verify_evpn_routes(tgen, topo, dut, input_routes) | |
2055cbee DS |
1239 | assert result is True, "Testcase {} on {} :Failed \n Error: {}".format( |
1240 | tc_name, dut, result | |
1b66072c KK |
1241 | ) |
1242 | ||
1243 | input_routes = {key: topo["routers"][key] for key in ["r2"]} | |
1244 | result = verify_evpn_routes(tgen, topo, dut, input_routes) | |
2055cbee DS |
1245 | assert result is True, "Testcase {} on {} :Failed \n Error: {}".format( |
1246 | tc_name, dut, result | |
1b66072c KK |
1247 | ) |
1248 | ||
1249 | step( | |
1250 | "Verify on R3 and R4 that DCG-2 further advertises all EVPN " | |
1251 | "routes to corresponding VRFs." | |
1252 | ) | |
1253 | for addr_type in ADDR_TYPES: | |
1254 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
1255 | result = verify_rib(tgen, addr_type, "r3", input_routes) | |
1256 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
1257 | tc_name, result | |
1258 | ) | |
1259 | ||
1260 | for addr_type in ADDR_TYPES: | |
1261 | input_routes = {key: topo["routers"][key] for key in ["r2"]} | |
1262 | result = verify_rib(tgen, addr_type, "r4", input_routes) | |
1263 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
1264 | tc_name, result | |
1265 | ) | |
1266 | ||
1267 | step( | |
1268 | "Verify that DCG-2 receives EVPN routes associated to default " | |
1269 | "VRF and install in default IP routing table as well." | |
1270 | ) | |
1271 | for addr_type in ADDR_TYPES: | |
1272 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
5cbb02eb | 1273 | result = verify_rib(tgen, addr_type, "d2", input_routes) |
1b66072c KK |
1274 | assert result is True, "Testcase {} :Failed \n Error: {}".format( |
1275 | tc_name, result | |
1276 | ) | |
1277 | ||
1278 | for addr_type in ADDR_TYPES: | |
1279 | input_routes = {key: topo["routers"][key] for key in ["r2"]} | |
5cbb02eb | 1280 | result = verify_rib(tgen, addr_type, "d2", input_routes) |
1b66072c KK |
1281 | assert result is True, "Testcase {} :Failed \n Error: {}".format( |
1282 | tc_name, result | |
1283 | ) | |
1284 | ||
1285 | step("Withdraw the IP prefixes from VFN(R1).") | |
1286 | dut = "r1" | |
1287 | input_dict_2 = {} | |
1288 | static_routes = topo["routers"][dut]["static_routes"] | |
1289 | for static_route in static_routes: | |
1290 | static_route["delete"] = True | |
1291 | temp = {dut: {"static_routes": [static_route]}} | |
1292 | input_dict_2.update(temp) | |
1293 | ||
1294 | result = create_static_routes(tgen, input_dict_2) | |
1295 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
1296 | tc_name, result | |
1297 | ) | |
1298 | ||
1299 | step( | |
1300 | "Verify that DCG-2 removes EVPN routes corresponding to vrf RED and " | |
1301 | "send an withdraw to VNF(R3) as well." | |
1302 | ) | |
1303 | for addr_type in ADDR_TYPES: | |
1304 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
1305 | result = verify_rib(tgen, addr_type, "d2", input_routes, expected=False) | |
db726bb8 KK |
1306 | assert result is not True, ( |
1307 | "Testcase {} : Failed \n " | |
1308 | "Expected: Routes should not be present in {} RIB \n " | |
1309 | "Found: {}".format(tc_name, "d2", result) | |
1310 | ) | |
1b66072c KK |
1311 | |
1312 | for addr_type in ADDR_TYPES: | |
1313 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
1314 | result = verify_rib(tgen, addr_type, "r3", input_routes, expected=False) | |
db726bb8 KK |
1315 | assert result is not True, ( |
1316 | "Testcase {} : Failed \n " | |
1317 | "Expected: Routes should not be present in {} RIB \n " | |
1318 | "Found: {}".format(tc_name, "r3", result) | |
1319 | ) | |
1b66072c KK |
1320 | |
1321 | step("Re-advertise IP prefixes from VFN(R1).") | |
1322 | step( | |
1323 | "Advertise prefixes from VNF routers R1 and R2 in associated " | |
1324 | "VRFs for both address-family." | |
1325 | ) | |
1326 | ||
1327 | for addr_type in ADDR_TYPES: | |
1328 | input_dict_1 = { | |
1329 | "r1": { | |
1330 | "static_routes": [ | |
1331 | { | |
1332 | "network": NETWORK1_1[addr_type], | |
1333 | "next_hop": NEXT_HOP_IP[addr_type], | |
1334 | "vrf": "RED", | |
1335 | } | |
1336 | ] | |
1337 | }, | |
1338 | "r2": { | |
1339 | "static_routes": [ | |
1340 | { | |
1341 | "network": NETWORK2_1[addr_type], | |
1342 | "next_hop": NEXT_HOP_IP[addr_type], | |
1343 | "vrf": "BLUE", | |
1344 | }, | |
1345 | { | |
1346 | "network": NETWORK3_1[addr_type], | |
1347 | "next_hop": NEXT_HOP_IP[addr_type], | |
1348 | "vrf": "GREEN", | |
701a0192 | 1349 | }, |
1b66072c | 1350 | ] |
701a0192 | 1351 | }, |
1b66072c KK |
1352 | } |
1353 | ||
1354 | result = create_static_routes(tgen, input_dict_1) | |
1355 | assert result is True, "Testcase {} : Failed \n Error: {}".format( | |
1356 | tc_name, result | |
1357 | ) | |
1358 | ||
1359 | step( | |
1360 | "Verify that DCG-2 receives EVPN routes corresponding to vrf RED " | |
1361 | "again and send an update to VNF(R3) as well." | |
1362 | ) | |
1363 | for addr_type in ADDR_TYPES: | |
1364 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
1365 | result = verify_rib(tgen, addr_type, "d2", input_routes) | |
1366 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
1367 | tc_name, result | |
1368 | ) | |
1369 | ||
1370 | for addr_type in ADDR_TYPES: | |
1371 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
1372 | result = verify_rib(tgen, addr_type, "r3", input_routes) | |
1373 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
1374 | tc_name, result | |
1375 | ) | |
1376 | ||
1377 | step("Delete vrf BLUE from router Edge-1") | |
1378 | input_dict_3 = {"e1": {"vrfs": [{"name": "BLUE", "id": "2", "delete": True}]}} | |
1379 | ||
1380 | result = create_vrf_cfg(tgen, input_dict_3) | |
1381 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
1382 | ||
1383 | step( | |
1384 | "Verify that DCG-2 removes EVPN routes corresponding to " | |
1385 | "vrf BLUE and send an withdraw to VNF(R4) as well." | |
1386 | ) | |
1387 | for addr_type in ADDR_TYPES: | |
1388 | input_routes = { | |
1389 | "r2": {"static_routes": [{"network": NETWORK2_1[addr_type], "vrf": "BLUE"}]} | |
1390 | } | |
1391 | ||
1392 | result = verify_rib(tgen, addr_type, "d2", input_routes, expected=False) | |
db726bb8 KK |
1393 | assert result is not True, ( |
1394 | "Testcase {} : Failed \n " | |
1395 | "Expected: Routes should not be present in {} RIB \n " | |
1396 | "Found: {}".format(tc_name, "d2", result) | |
1397 | ) | |
1b66072c KK |
1398 | |
1399 | result = verify_rib(tgen, addr_type, "r4", input_routes, expected=False) | |
db726bb8 KK |
1400 | assert result is not True, ( |
1401 | "Testcase {} : Failed \n " | |
1402 | "Expected: Routes should not be present in {} RIB \n " | |
1403 | "Found: {}".format(tc_name, "r4", result) | |
1404 | ) | |
1b66072c KK |
1405 | |
1406 | step("Add vrf BLUE on router Edge-1 again.") | |
1407 | interface = topo["routers"]["e1"]["links"]["r2-link1"]["interface"] | |
1408 | input_dict_3 = { | |
1409 | "e1": { | |
1410 | "links": { | |
1411 | "r2-link1": { | |
1412 | "interface": interface, | |
1413 | "ipv4": "auto", | |
1414 | "ipv6": "auto", | |
1415 | "vrf": "BLUE", | |
1416 | } | |
1417 | }, | |
1418 | "vrfs": [{"name": "BLUE", "id": "2"}], | |
1419 | } | |
1420 | } | |
1421 | result = create_vrf_cfg(tgen, input_dict_3) | |
1422 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
1423 | ||
1424 | logger.info( | |
1425 | "After deleting VRFs ipv6 addresses wil be deleted " | |
1426 | "from kernel Adding back ipv6 addresses" | |
1427 | ) | |
1428 | dut = "e1" | |
1429 | vrfs = ["BLUE"] | |
1430 | ||
1431 | for vrf in vrfs: | |
1432 | for c_link, c_data in topo["routers"][dut]["links"].items(): | |
1433 | if "vrf" in c_data: | |
1434 | if c_data["vrf"] != vrf: | |
1435 | continue | |
1436 | ||
1437 | intf_name = c_data["interface"] | |
1438 | intf_ipv6 = c_data["ipv6"] | |
1439 | ||
1440 | create_interface_in_kernel( | |
1441 | tgen, dut, intf_name, intf_ipv6, vrf, create=False | |
1442 | ) | |
1443 | ||
9dfe1acd DS |
1444 | result = verify_bgp_convergence(tgen, topo, dut) |
1445 | assert result is True, "Failed to converge on {}".format(dut) | |
1b66072c KK |
1446 | |
1447 | step( | |
1448 | "Verify that DCG-2 receives EVPN routes corresponding to " | |
1449 | "vrf BLUE again and send an update to VNF(R4) as well." | |
1450 | ) | |
1451 | for addr_type in ADDR_TYPES: | |
1452 | input_routes = { | |
1453 | "r2": {"static_routes": [{"network": NETWORK2_1[addr_type], "vrf": "BLUE"}]} | |
1454 | } | |
1455 | ||
1456 | result = verify_rib(tgen, addr_type, "d2", input_routes) | |
1457 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
1458 | tc_name, result | |
1459 | ) | |
1460 | ||
1461 | result = verify_rib(tgen, addr_type, "r4", input_routes) | |
1462 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
1463 | tc_name, result | |
1464 | ) | |
1465 | ||
1466 | step("Withdraw IPv6 address-family in EVPN advertisements for " "VRF GREEN") | |
1467 | addr_type = "ipv6" | |
1468 | input_dict_4 = { | |
1469 | "e1": { | |
1470 | "bgp": [ | |
1471 | { | |
1472 | "local_as": "100", | |
1473 | "vrf": "GREEN", | |
1474 | "address_family": { | |
1475 | "l2vpn": { | |
1476 | "evpn": { | |
1477 | "advertise": {addr_type: {"unicast": {"delete": True}}} | |
1478 | } | |
1479 | } | |
1480 | }, | |
1481 | } | |
1482 | ] | |
1483 | } | |
1484 | } | |
1485 | ||
1486 | result = create_router_bgp(tgen, topo, input_dict_4) | |
1487 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
1488 | ||
1489 | step( | |
1490 | "Verify that EVPN routes (IPv6)associated with vrf GREEN are " | |
1491 | "withdrawn from DCG-2 and VNF R4." | |
1492 | ) | |
1493 | input_routes = { | |
1494 | "r2": {"static_routes": [{"network": NETWORK3_1[addr_type], "vrf": "GREEN"}]} | |
1495 | } | |
1496 | ||
1497 | result = verify_rib(tgen, addr_type, "d2", input_routes, expected=False) | |
db726bb8 KK |
1498 | assert result is not True, ( |
1499 | "Testcase {} : Failed \n " | |
1500 | "Expected: Routes should not be present in {} RIB \n " | |
1501 | "Found: {}".format(tc_name, "d2", result) | |
1502 | ) | |
1b66072c KK |
1503 | |
1504 | result = verify_rib(tgen, addr_type, "r4", input_routes, expected=False) | |
db726bb8 KK |
1505 | assert result is not True, ( |
1506 | "Testcase {} : Failed \n " | |
1507 | "Expected: Routes should not be present in {} RIB \n " | |
1508 | "Found: {}".format(tc_name, "r4", result) | |
1509 | ) | |
1b66072c KK |
1510 | |
1511 | step("Advertise IPv6 address-family in EVPN advertisements " "for VRF GREEN.") | |
1512 | addr_type = "ipv6" | |
1513 | input_dict_4 = { | |
1514 | "e1": { | |
1515 | "bgp": [ | |
1516 | { | |
1517 | "local_as": "100", | |
1518 | "vrf": "GREEN", | |
1519 | "address_family": { | |
1520 | "l2vpn": {"evpn": {"advertise": {addr_type: {"unicast": {}}}}} | |
1521 | }, | |
1522 | } | |
1523 | ] | |
1524 | } | |
1525 | } | |
1526 | ||
1527 | result = create_router_bgp(tgen, topo, input_dict_4) | |
1528 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
1529 | ||
1530 | for addr_type in ADDR_TYPES: | |
1531 | input_routes = { | |
1532 | "r2": { | |
1533 | "static_routes": [{"network": NETWORK3_1[addr_type], "vrf": "GREEN"}] | |
1534 | } | |
1535 | } | |
1536 | ||
1537 | result = verify_rib(tgen, addr_type, "d2", input_routes) | |
1538 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
1539 | tc_name, result | |
1540 | ) | |
1541 | ||
1542 | result = verify_rib(tgen, addr_type, "r4", input_routes) | |
1543 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
1544 | tc_name, result | |
1545 | ) | |
1546 | ||
1547 | write_test_footer(tc_name) | |
1548 | ||
1549 | ||
1550 | @pytest.mark.parametrize( | |
1551 | "attribute", [{"route-type": "prefix"}, {"vni": VNI_1}, {"rt": "300:300"}] | |
1552 | ) | |
1553 | def test_route_map_operations_for_evpn_address_family_p1(request, attribute): | |
1554 | """ | |
1555 | Route-map operations for EVPN address family. | |
1556 | """ | |
1557 | ||
1558 | tgen = get_topogen() | |
1559 | tc_name = request.node.name | |
1560 | write_test_header(tc_name) | |
1561 | check_router_status(tgen) | |
1562 | reset_config_on_routers(tgen) | |
1563 | add_default_routes(tgen) | |
1564 | ||
1565 | step( | |
1566 | "Advertise prefixes from VNF routers R1 and R2 in associated " | |
1567 | "VRFs for both address-family." | |
1568 | ) | |
1569 | ||
1570 | for addr_type in ADDR_TYPES: | |
1571 | input_dict_1 = { | |
1572 | "r1": { | |
1573 | "static_routes": [ | |
1574 | { | |
1575 | "network": NETWORK1_1[addr_type], | |
1576 | "next_hop": NEXT_HOP_IP[addr_type], | |
1577 | "vrf": "RED", | |
1578 | } | |
1579 | ] | |
1580 | }, | |
1581 | "r2": { | |
1582 | "static_routes": [ | |
1583 | { | |
1584 | "network": NETWORK2_1[addr_type], | |
1585 | "next_hop": NEXT_HOP_IP[addr_type], | |
1586 | "vrf": "BLUE", | |
1587 | }, | |
1588 | { | |
1589 | "network": NETWORK3_1[addr_type], | |
1590 | "next_hop": NEXT_HOP_IP[addr_type], | |
1591 | "vrf": "GREEN", | |
701a0192 | 1592 | }, |
1b66072c | 1593 | ] |
701a0192 | 1594 | }, |
1b66072c KK |
1595 | } |
1596 | ||
1597 | result = create_static_routes(tgen, input_dict_1) | |
1598 | assert result is True, "Testcase {} : Failed \n Error: {}".format( | |
1599 | tc_name, result | |
1600 | ) | |
1601 | ||
1602 | if tgen.routers_have_failure(): | |
1603 | pytest.skip(tgen.errors) | |
1604 | ||
1605 | step( | |
1606 | "Advertise VRF routes in EVPN address family from Edge-1 router." | |
1607 | " Configure a route-map on e1 to filter EVPN routes based on" | |
1608 | " below keywords: route-type: prefix" | |
1609 | ) | |
1610 | ||
1611 | for key, value in attribute.items(): | |
1612 | if key == "rt": | |
1613 | logger.info("Creating extcommunity using raw_config") | |
1614 | raw_config = { | |
1615 | "d2": { | |
1616 | "raw_config": [ | |
1617 | "bgp extcommunity-list standard ECOMM300 permit {} {}".format( | |
1618 | key, value | |
1619 | ) | |
1620 | ] | |
1621 | } | |
1622 | } | |
1623 | result = apply_raw_config(tgen, raw_config) | |
1624 | assert result is True, "Testcase {} : Failed Error: {}".format( | |
1625 | tc_name, result | |
1626 | ) | |
1627 | ||
1628 | input_dict_1 = { | |
1629 | "e1": { | |
1630 | "route_maps": { | |
1631 | "rmap_route_type": [ | |
1632 | {"action": "permit", "set": {"extcommunity": {key: value}}} | |
1633 | ] | |
1634 | } | |
1635 | }, | |
1636 | "d2": { | |
1637 | "route_maps": { | |
1638 | "rmap_route_type": [ | |
1639 | {"action": "permit", "match": {"extcommunity": "ECOMM300"}} | |
1640 | ] | |
1641 | } | |
1642 | }, | |
1643 | } | |
1644 | ||
1645 | else: | |
1646 | input_dict_1 = { | |
1647 | "e1": { | |
1648 | "route_maps": { | |
1649 | "rmap_route_type": [ | |
1650 | {"action": "permit", "match": {"evpn": {key: value}}} | |
1651 | ] | |
1652 | } | |
1653 | }, | |
1654 | "d2": { | |
1655 | "route_maps": { | |
1656 | "rmap_route_type": [ | |
1657 | {"action": "permit", "match": {"evpn": {key: value}}} | |
1658 | ] | |
1659 | } | |
1660 | }, | |
1661 | } | |
1662 | result = create_route_maps(tgen, input_dict_1) | |
1663 | assert result is True, "Testcase {} : Failed \n Error: {}".format( | |
1664 | tc_name, result | |
1665 | ) | |
1666 | ||
1667 | input_dict_2 = { | |
1668 | "e1": { | |
1669 | "bgp": [ | |
1670 | { | |
1671 | "local_as": "100", | |
1672 | "address_family": { | |
1673 | "l2vpn": { | |
1674 | "evpn": { | |
1675 | "neighbor": { | |
1676 | "d2": { | |
1677 | "ipv4": { | |
1678 | "e1-link1": { | |
1679 | "route_maps": [ | |
1680 | { | |
1681 | "name": "rmap_route_type", | |
1682 | "direction": "out", | |
1683 | } | |
1684 | ] | |
1685 | } | |
1686 | } | |
1687 | } | |
1688 | } | |
1689 | } | |
1690 | } | |
1691 | }, | |
1692 | } | |
1693 | ] | |
1694 | }, | |
1695 | "d2": { | |
1696 | "bgp": [ | |
1697 | { | |
1698 | "local_as": "200", | |
1699 | "address_family": { | |
1700 | "l2vpn": { | |
1701 | "evpn": { | |
1702 | "neighbor": { | |
1703 | "e1": { | |
1704 | "ipv4": { | |
1705 | "d2-link1": { | |
1706 | "route_maps": [ | |
1707 | { | |
1708 | "name": "rmap_route_type", | |
1709 | "direction": "in", | |
1710 | } | |
1711 | ] | |
1712 | } | |
1713 | } | |
1714 | } | |
1715 | } | |
1716 | } | |
1717 | } | |
1718 | }, | |
1719 | } | |
1720 | ] | |
1721 | }, | |
1722 | } | |
1723 | ||
1724 | result = create_router_bgp(tgen, topo, input_dict_2) | |
1725 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
1726 | ||
1727 | step( | |
1728 | "Verify on router DCG-2 that EVPN routes corresponding to all " | |
1729 | "VRFs are received. As all EVPN routes are type-5 only." | |
1730 | ) | |
1731 | ||
1732 | input_routes = {key: topo["routers"][key] for key in ["r1"]} | |
1733 | result = verify_evpn_routes(tgen, topo, "d2", input_routes) | |
1734 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
1735 | ||
1736 | input_routes = {key: topo["routers"][key] for key in ["r2"]} | |
1737 | result = verify_evpn_routes(tgen, topo, "d2", input_routes) | |
1738 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
1739 | ||
1740 | write_test_footer(tc_name) | |
1741 | ||
1742 | ||
cbeda33d KK |
1743 | def test_evpn_address_family_with_graceful_restart_p0(request): |
1744 | """ | |
1745 | Verify Graceful-restart function for EVPN address-family. | |
1746 | """ | |
1747 | ||
1748 | tgen = get_topogen() | |
1749 | tc_name = request.node.name | |
1750 | write_test_header(tc_name) | |
1751 | check_router_status(tgen) | |
1752 | reset_config_on_routers(tgen) | |
1753 | add_default_routes(tgen) | |
1754 | ||
1755 | if tgen.routers_have_failure(): | |
1756 | pytest.skip(tgen.errors) | |
1757 | ||
1758 | for addr_type in ADDR_TYPES: | |
1759 | input_dict_1 = { | |
1760 | "r3": { | |
ac6ef90b KK |
1761 | "static_routes": [ |
1762 | { | |
1763 | "network": NETWORK1_2[addr_type], | |
1764 | "next_hop": NEXT_HOP_IP[addr_type], | |
1765 | "vrf": "RED", | |
1766 | } | |
1767 | ] | |
1768 | }, | |
1769 | "r4": { | |
1770 | "static_routes": [ | |
1771 | { | |
1772 | "network": NETWORK1_3[addr_type], | |
1773 | "next_hop": NEXT_HOP_IP[addr_type], | |
1774 | "vrf": "BLUE", | |
1775 | }, | |
1776 | { | |
1777 | "network": NETWORK1_4[addr_type], | |
1778 | "next_hop": NEXT_HOP_IP[addr_type], | |
1779 | "vrf": "GREEN", | |
1780 | }, | |
1781 | ] | |
cbeda33d | 1782 | }, |
cbeda33d KK |
1783 | } |
1784 | ||
1785 | result = create_static_routes(tgen, input_dict_1) | |
ac6ef90b KK |
1786 | assert result is True, "Testcase {} : Failed \n Error: {}".format( |
1787 | tc_name, result | |
1788 | ) | |
cbeda33d | 1789 | |
ac6ef90b KK |
1790 | step( |
1791 | "Redistribute static in (IPv4 and IPv6) address-family " | |
1792 | "on Edge-1 for all VRFs." | |
1793 | ) | |
cbeda33d | 1794 | |
ac6ef90b | 1795 | input_dict_2 = {} |
cbeda33d KK |
1796 | for dut in ["r3", "r4"]: |
1797 | temp = {dut: {"bgp": []}} | |
1798 | input_dict_2.update(temp) | |
1799 | ||
1800 | if dut == "r3": | |
1801 | VRFS = ["RED"] | |
1802 | AS_NUM = [3] | |
1803 | if dut == "r4": | |
1804 | VRFS = ["BLUE", "GREEN"] | |
1805 | AS_NUM = [4, 4] | |
1806 | ||
1807 | for vrf, as_num in zip(VRFS, AS_NUM): | |
1808 | temp[dut]["bgp"].append( | |
1809 | { | |
1810 | "local_as": as_num, | |
1811 | "vrf": vrf, | |
1812 | "address_family": { | |
1813 | "ipv4": { | |
ac6ef90b | 1814 | "unicast": {"redistribute": [{"redist_type": "static"}]} |
cbeda33d KK |
1815 | }, |
1816 | "ipv6": { | |
ac6ef90b KK |
1817 | "unicast": {"redistribute": [{"redist_type": "static"}]} |
1818 | }, | |
1819 | }, | |
1820 | } | |
1821 | ) | |
cbeda33d KK |
1822 | |
1823 | result = create_router_bgp(tgen, topo, input_dict_2) | |
ac6ef90b | 1824 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) |
cbeda33d | 1825 | |
ac6ef90b KK |
1826 | step( |
1827 | "Verify on router Edge-1 that EVPN routes corresponding to " | |
1828 | "all VRFs are received from both routers DCG-1 and DCG-2" | |
1829 | ) | |
cbeda33d KK |
1830 | |
1831 | for addr_type in ADDR_TYPES: | |
1832 | input_routes = { | |
1833 | "r3": { | |
ac6ef90b KK |
1834 | "static_routes": [ |
1835 | { | |
1836 | "network": NETWORK1_2[addr_type], | |
1837 | "next_hop": NEXT_HOP_IP[addr_type], | |
1838 | "vrf": "RED", | |
1839 | } | |
1840 | ] | |
1841 | }, | |
1842 | "r4": { | |
1843 | "static_routes": [ | |
1844 | { | |
1845 | "network": NETWORK1_3[addr_type], | |
1846 | "next_hop": NEXT_HOP_IP[addr_type], | |
1847 | "vrf": "BLUE", | |
1848 | }, | |
1849 | { | |
1850 | "network": NETWORK1_4[addr_type], | |
1851 | "next_hop": NEXT_HOP_IP[addr_type], | |
1852 | "vrf": "GREEN", | |
1853 | }, | |
1854 | ] | |
cbeda33d | 1855 | }, |
cbeda33d KK |
1856 | } |
1857 | ||
1858 | result = verify_rib(tgen, addr_type, "e1", input_routes) | |
ac6ef90b KK |
1859 | assert result is True, "Testcase {} :Failed \n Error: {}".format( |
1860 | tc_name, result | |
1861 | ) | |
cbeda33d | 1862 | |
ac6ef90b KK |
1863 | step( |
1864 | "Configure DCG-2 as GR restarting node for EVPN session between" | |
cbeda33d | 1865 | " DCG-2 and EDGE-1, following by a session reset using 'clear bgp *'" |
ac6ef90b KK |
1866 | " command." |
1867 | ) | |
cbeda33d KK |
1868 | |
1869 | input_dict_gr = { | |
1870 | "d2": { | |
ac6ef90b | 1871 | "bgp": [ |
cbeda33d KK |
1872 | { |
1873 | "local_as": "200", | |
1874 | "graceful-restart": { | |
1875 | "graceful-restart": True, | |
ac6ef90b | 1876 | }, |
cbeda33d KK |
1877 | } |
1878 | ] | |
1879 | } | |
1880 | } | |
1881 | ||
1882 | result = create_router_bgp(tgen, topo, input_dict_gr) | |
ac6ef90b | 1883 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) |
cbeda33d | 1884 | |
ac6ef90b KK |
1885 | step( |
1886 | "Verify that DCG-2 changes it's role to GR-restarting router " | |
1887 | "and EDGE-1 becomes the GR-helper." | |
1888 | ) | |
cbeda33d KK |
1889 | |
1890 | step("Kill BGPd daemon on DCG-2.") | |
1891 | kill_router_daemons(tgen, "d2", ["bgpd"]) | |
1892 | ||
ac6ef90b KK |
1893 | step( |
1894 | "Verify that EDGE-1 keep stale entries for EVPN RT-5 routes " | |
1895 | "received from DCG-2 before the restart." | |
1896 | ) | |
cbeda33d KK |
1897 | |
1898 | for addr_type in ADDR_TYPES: | |
1899 | input_routes = { | |
ac6ef90b KK |
1900 | "r4": { |
1901 | "static_routes": [ | |
1902 | { | |
1903 | "network": NETWORK1_3[addr_type], | |
1904 | "next_hop": NEXT_HOP_IP[addr_type], | |
1905 | "vrf": "BLUE", | |
1906 | }, | |
1907 | { | |
1908 | "network": NETWORK1_4[addr_type], | |
1909 | "next_hop": NEXT_HOP_IP[addr_type], | |
1910 | "vrf": "GREEN", | |
1911 | }, | |
1912 | ] | |
cbeda33d KK |
1913 | } |
1914 | } | |
1915 | result = verify_evpn_routes(tgen, topo, "e1", input_routes) | |
ac6ef90b KK |
1916 | assert result is True, "Testcase {} :Failed \n Error: {}".format( |
1917 | tc_name, result | |
1918 | ) | |
cbeda33d | 1919 | |
ac6ef90b KK |
1920 | step( |
1921 | "Verify that DCG-2 keeps BGP routes in Zebra until BGPd " | |
1922 | "comes up or end of 'rib-stale-time'" | |
1923 | ) | |
cbeda33d KK |
1924 | |
1925 | step("Start BGPd daemon on DCG-2.") | |
1926 | start_router_daemons(tgen, "d2", ["bgpd"]) | |
1927 | ||
1928 | step("Verify that EDGE-1 removed all the stale entries.") | |
1929 | for addr_type in ADDR_TYPES: | |
1930 | input_routes = { | |
ac6ef90b KK |
1931 | "r4": { |
1932 | "static_routes": [ | |
1933 | { | |
1934 | "network": NETWORK1_3[addr_type], | |
1935 | "next_hop": NEXT_HOP_IP[addr_type], | |
1936 | "vrf": "BLUE", | |
1937 | }, | |
1938 | { | |
1939 | "network": NETWORK1_4[addr_type], | |
1940 | "next_hop": NEXT_HOP_IP[addr_type], | |
1941 | "vrf": "GREEN", | |
1942 | }, | |
1943 | ] | |
cbeda33d KK |
1944 | } |
1945 | } | |
1946 | result = verify_evpn_routes(tgen, topo, "e1", input_routes) | |
ac6ef90b KK |
1947 | assert result is True, "Testcase {} :Failed \n Error: {}".format( |
1948 | tc_name, result | |
1949 | ) | |
cbeda33d | 1950 | |
ac6ef90b KK |
1951 | step( |
1952 | "Verify that DCG-2 refresh zebra with EVPN routes. " | |
1953 | "(no significance of 'rib-stale-time'" | |
1954 | ) | |
cbeda33d KK |
1955 | |
1956 | for addr_type in ADDR_TYPES: | |
1957 | input_routes = { | |
ac6ef90b KK |
1958 | "r4": { |
1959 | "static_routes": [ | |
1960 | { | |
1961 | "network": NETWORK1_3[addr_type], | |
1962 | "next_hop": NEXT_HOP_IP[addr_type], | |
1963 | "vrf": "BLUE", | |
1964 | }, | |
1965 | { | |
1966 | "network": NETWORK1_4[addr_type], | |
1967 | "next_hop": NEXT_HOP_IP[addr_type], | |
1968 | "vrf": "GREEN", | |
1969 | }, | |
1970 | ] | |
cbeda33d KK |
1971 | } |
1972 | } | |
1973 | result = verify_rib(tgen, addr_type, "d2", input_routes) | |
ac6ef90b KK |
1974 | assert result is True, "Testcase {} :Failed \n Error: {}".format( |
1975 | tc_name, result | |
1976 | ) | |
cbeda33d KK |
1977 | |
1978 | write_test_footer(tc_name) | |
1979 | ||
1980 | ||
1b66072c KK |
1981 | @pytest.mark.parametrize("attribute", ["locPrf", "weight", "path"]) |
1982 | def test_bgp_attributes_for_evpn_address_family_p1(request, attribute): | |
1983 | """ | |
1984 | BGP attributes for EVPN address-family. | |
1985 | """ | |
1986 | ||
1987 | tgen = get_topogen() | |
1988 | tc_name = request.node.name | |
1989 | write_test_header(tc_name) | |
1990 | check_router_status(tgen) | |
1991 | reset_config_on_routers(tgen) | |
1992 | add_default_routes(tgen) | |
1993 | ||
1994 | if tgen.routers_have_failure(): | |
1995 | pytest.skip(tgen.errors) | |
1996 | ||
1997 | step( | |
1998 | "Advertise prefixes from VNF routers R1 and R2 in associated " | |
1999 | "VRFs for both address-family." | |
2000 | ) | |
2001 | ||
2002 | for addr_type in ADDR_TYPES: | |
2003 | input_dict_1 = { | |
2004 | "r1": { | |
2005 | "static_routes": [ | |
2006 | { | |
2007 | "network": NETWORK1_1[addr_type], | |
2008 | "next_hop": NEXT_HOP_IP[addr_type], | |
2009 | "vrf": "RED", | |
2010 | } | |
2011 | ] | |
2012 | }, | |
2013 | "r2": { | |
2014 | "static_routes": [ | |
2015 | { | |
2016 | "network": NETWORK2_1[addr_type], | |
2017 | "next_hop": NEXT_HOP_IP[addr_type], | |
2018 | "vrf": "BLUE", | |
2019 | }, | |
2020 | { | |
2021 | "network": NETWORK3_1[addr_type], | |
2022 | "next_hop": NEXT_HOP_IP[addr_type], | |
2023 | "vrf": "GREEN", | |
701a0192 | 2024 | }, |
1b66072c | 2025 | ] |
701a0192 | 2026 | }, |
1b66072c KK |
2027 | } |
2028 | ||
2029 | result = create_static_routes(tgen, input_dict_1) | |
2030 | assert result is True, "Testcase {} : Failed \n Error: {}".format( | |
2031 | tc_name, result | |
2032 | ) | |
2033 | ||
2034 | topo_local = deepcopy(topo) | |
2035 | ||
2036 | logger.info("Modifying topology b/w e1 and d1 from iBGP to eBGP") | |
2037 | step("Delete BGP config for vrf RED.") | |
2038 | ||
2039 | if attribute == "locPrf": | |
2040 | input_dict_vni = { | |
2041 | "d1": { | |
2042 | "vrfs": [ | |
2043 | {"name": "RED", "no_vni": VNI_1}, | |
2044 | {"name": "BLUE", "no_vni": VNI_2}, | |
2045 | {"name": "GREEN", "no_vni": VNI_3}, | |
2046 | ] | |
2047 | } | |
2048 | } | |
2049 | result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni) | |
2050 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
2051 | tc_name, result | |
2052 | ) | |
2053 | ||
2054 | input_dict_2 = {} | |
2055 | for dut in ["d1"]: | |
2056 | temp = {dut: {"bgp": []}} | |
2057 | input_dict_2.update(temp) | |
2058 | ||
2059 | INDEX = [0, 1, 2, 3] | |
2060 | VRFS = ["RED", "BLUE", "GREEN", None] | |
2061 | AS_NUM = [100, 100, 100, 100] | |
2062 | ||
2063 | for index, vrf, as_num in zip(INDEX, VRFS, AS_NUM): | |
2064 | topo_local["routers"][dut]["bgp"][index]["local_as"] = 200 | |
2065 | if vrf: | |
2066 | temp[dut]["bgp"].append( | |
2067 | {"local_as": as_num, "vrf": vrf, "delete": True} | |
2068 | ) | |
2069 | else: | |
2070 | temp[dut]["bgp"].append({"local_as": as_num, "delete": True}) | |
2071 | ||
2072 | result = create_router_bgp(tgen, topo, input_dict_2) | |
2055cbee | 2073 | assert result is True, "Testcase {} on d1 :Failed \n Error: {}".format( |
1b66072c KK |
2074 | tc_name, result |
2075 | ) | |
2076 | ||
2077 | result = create_router_bgp(tgen, topo_local["routers"]) | |
2078 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
2079 | tc_name, result | |
2080 | ) | |
2081 | ||
2082 | step("Advertise VRF routes in EVPN address-family from DCG-1 " "and DCG-2 routers.") | |
2083 | ||
2084 | for addr_type in ADDR_TYPES: | |
2085 | input_dict_1 = { | |
2086 | "r3": { | |
2087 | "static_routes": [ | |
2088 | { | |
2089 | "network": NETWORK1_2[addr_type], | |
2090 | "next_hop": NEXT_HOP_IP[addr_type], | |
2091 | "vrf": "RED", | |
2092 | } | |
2093 | ] | |
2094 | }, | |
2095 | "r4": { | |
2096 | "static_routes": [ | |
2097 | { | |
2098 | "network": NETWORK1_3[addr_type], | |
2099 | "next_hop": NEXT_HOP_IP[addr_type], | |
2100 | "vrf": "BLUE", | |
2101 | }, | |
2102 | { | |
2103 | "network": NETWORK1_4[addr_type], | |
2104 | "next_hop": NEXT_HOP_IP[addr_type], | |
2105 | "vrf": "GREEN", | |
2106 | }, | |
2107 | ] | |
2108 | }, | |
2109 | } | |
2110 | ||
2111 | result = create_static_routes(tgen, input_dict_1) | |
2112 | assert result is True, "Testcase {} : Failed \n Error: {}".format( | |
2113 | tc_name, result | |
2114 | ) | |
2115 | ||
2116 | step( | |
2117 | "Redistribute static in (IPv4 and IPv6) address-family " | |
2118 | "on Edge-1 for all VRFs." | |
2119 | ) | |
2120 | ||
2121 | input_dict_2 = {} | |
2122 | for dut in ["r3", "r4"]: | |
2123 | temp = {dut: {"bgp": []}} | |
2124 | input_dict_2.update(temp) | |
2125 | ||
2126 | if dut == "r3": | |
2127 | VRFS = ["RED"] | |
2128 | AS_NUM = [3] | |
2129 | if dut == "r4": | |
2130 | VRFS = ["BLUE", "GREEN"] | |
2131 | AS_NUM = [4, 4] | |
2132 | ||
2133 | for vrf, as_num in zip(VRFS, AS_NUM): | |
2134 | temp[dut]["bgp"].append( | |
2135 | { | |
2136 | "local_as": as_num, | |
2137 | "vrf": vrf, | |
2138 | "address_family": { | |
2139 | "ipv4": { | |
2140 | "unicast": {"redistribute": [{"redist_type": "static"}]} | |
2141 | }, | |
2142 | "ipv6": { | |
2143 | "unicast": {"redistribute": [{"redist_type": "static"}]} | |
2144 | }, | |
2145 | }, | |
2146 | } | |
2147 | ) | |
2148 | ||
2149 | result = create_router_bgp(tgen, topo, input_dict_2) | |
2150 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
2151 | ||
2152 | step( | |
2153 | "Verify on router Edge-1 that EVPN routes corresponding to " | |
2154 | "all VRFs are received from both routers DCG-1 and DCG-2" | |
2155 | ) | |
2156 | ||
2157 | for addr_type in ADDR_TYPES: | |
2158 | input_routes = { | |
2159 | "r3": { | |
2160 | "static_routes": [ | |
2161 | { | |
2162 | "network": NETWORK1_2[addr_type], | |
2163 | "next_hop": NEXT_HOP_IP[addr_type], | |
2164 | "vrf": "RED", | |
2165 | } | |
2166 | ] | |
2167 | }, | |
2168 | "r4": { | |
2169 | "static_routes": [ | |
2170 | { | |
2171 | "network": NETWORK1_3[addr_type], | |
2172 | "next_hop": NEXT_HOP_IP[addr_type], | |
2173 | "vrf": "BLUE", | |
2174 | }, | |
2175 | { | |
2176 | "network": NETWORK1_4[addr_type], | |
2177 | "next_hop": NEXT_HOP_IP[addr_type], | |
2178 | "vrf": "GREEN", | |
2179 | }, | |
2180 | ] | |
2181 | }, | |
2182 | } | |
2183 | ||
2184 | result = verify_rib(tgen, addr_type, "e1", input_routes) | |
2185 | assert result is True, "Testcase {} :Failed \n Error: {}".format( | |
2186 | tc_name, result | |
2187 | ) | |
2188 | ||
2189 | step( | |
2190 | "Configure a route-map on Edge-1 to modify below BGP attributes " | |
2191 | "for EVPN address-family:" | |
2192 | ) | |
2193 | ||
2194 | if attribute == "path": | |
2195 | input_dict_1 = { | |
2196 | "e1": { | |
2197 | "route_maps": { | |
d7d21c3a | 2198 | "rmap_d1": [ |
1b66072c KK |
2199 | { |
2200 | "action": "permit", | |
2201 | "set": { | |
2202 | attribute: { | |
2203 | "as_num": "123 231 321", | |
2204 | "as_action": "prepend", | |
2205 | } | |
2206 | }, | |
2207 | } | |
2208 | ], | |
d7d21c3a | 2209 | "rmap_d2": [ |
1b66072c KK |
2210 | { |
2211 | "action": "permit", | |
2212 | "set": { | |
2213 | attribute: {"as_num": "121", "as_action": "prepend"} | |
2214 | }, | |
2215 | } | |
2216 | ], | |
2217 | } | |
2218 | } | |
2219 | } | |
2220 | else: | |
2221 | input_dict_1 = { | |
2222 | "e1": { | |
2223 | "route_maps": { | |
a53c08bc CH |
2224 | "rmap_d1": [{"action": "permit", "set": {attribute: 120}}], |
2225 | "rmap_d2": [{"action": "permit", "set": {attribute: 150}}], | |
1b66072c KK |
2226 | } |
2227 | } | |
2228 | } | |
2229 | result = create_route_maps(tgen, input_dict_1) | |
2230 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
2231 | ||
2232 | input_dict_2 = { | |
2233 | "e1": { | |
2234 | "bgp": [ | |
2235 | { | |
2236 | "local_as": "100", | |
2237 | "address_family": { | |
2238 | "l2vpn": { | |
2239 | "evpn": { | |
2240 | "neighbor": { | |
2241 | "d1": { | |
2242 | "ipv4": { | |
2243 | "e1-link1": { | |
2244 | "route_maps": [ | |
2245 | { | |
2246 | "name": "rmap_d1", | |
2247 | "direction": "in", | |
2248 | } | |
2249 | ] | |
2250 | } | |
2251 | } | |
2252 | }, | |
2253 | "d2": { | |
2254 | "ipv4": { | |
2255 | "e1-link1": { | |
2256 | "route_maps": [ | |
2257 | { | |
2258 | "name": "rmap_d2", | |
2259 | "direction": "in", | |
2260 | } | |
2261 | ] | |
2262 | } | |
2263 | } | |
2264 | }, | |
2265 | } | |
2266 | } | |
2267 | } | |
2268 | }, | |
2269 | } | |
2270 | ] | |
2271 | } | |
2272 | } | |
2273 | ||
2274 | result = create_router_bgp(tgen, topo, input_dict_2) | |
2275 | assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) | |
2276 | ||
2277 | step( | |
2278 | "Verify on router Edge-1 that EVPN routes are preferred via" | |
2279 | " DCG-1 or DCG-2 based on best path selection criteria " | |
2280 | "(according to the configured BGP attribute values in route-map)." | |
2281 | ) | |
2282 | ||
2283 | for addr_type in ADDR_TYPES: | |
2284 | input_routes = { | |
2285 | "r3": { | |
2286 | "static_routes": [ | |
2287 | { | |
2288 | "network": NETWORK1_2[addr_type], | |
2289 | "next_hop": NEXT_HOP_IP[addr_type], | |
2290 | "vrf": "RED", | |
2291 | } | |
2292 | ] | |
2293 | }, | |
2294 | "r4": { | |
2295 | "static_routes": [ | |
2296 | { | |
2297 | "network": NETWORK1_3[addr_type], | |
2298 | "next_hop": NEXT_HOP_IP[addr_type], | |
2299 | "vrf": "BLUE", | |
2300 | }, | |
2301 | { | |
2302 | "network": NETWORK1_4[addr_type], | |
2303 | "next_hop": NEXT_HOP_IP[addr_type], | |
2304 | "vrf": "GREEN", | |
2305 | }, | |
2306 | ] | |
2307 | }, | |
2308 | } | |
2309 | ||
2310 | result = verify_best_path_as_per_bgp_attribute( | |
2311 | tgen, addr_type, "e1", input_routes, attribute | |
2312 | ) | |
2313 | assert result is True, "Testcase {} : Failed \n Error: {}".format( | |
2314 | tc_name, result | |
2315 | ) | |
2316 | ||
2317 | write_test_footer(tc_name) | |
2318 | ||
2319 | ||
2320 | if __name__ == "__main__": | |
2321 | args = ["-s"] + sys.argv[1:] | |
2322 | sys.exit(pytest.main(args)) |