]> git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/bgp_gshut_topo1/test_ibgp_gshut_topo1.py
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / tests / topotests / bgp_gshut_topo1 / test_ibgp_gshut_topo1.py
1 #!/usr/bin/env python
2 # SPDX-License-Identifier: ISC
3
4 #
5 # Copyright (c) 2021 by VMware, Inc. ("VMware")
6 # Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
7 # ("NetDEF") in this file.
8 #
9
10
11 """
12 Following tests are covered to test ecmp functionality on BGP GSHUT.
13 1. Verify graceful-shutdown functionality with iBGP peers
14 2. Verify graceful-shutdown functionality after
15 deleting/re-adding route-map with iBGP peers
16 """
17
18 import os
19 import sys
20 import time
21 import pytest
22
23 # Save the Current Working Directory to find configuration files.
24 CWD = os.path.dirname(os.path.realpath(__file__))
25 sys.path.append(os.path.join(CWD, "../"))
26 sys.path.append(os.path.join(CWD, "../../"))
27
28 # pylint: disable=C0413
29 # Import topogen and topotest helpers
30 from lib.topogen import Topogen, get_topogen
31
32 from lib.common_config import (
33 start_topology,
34 write_test_header,
35 write_test_footer,
36 verify_rib,
37 check_address_types,
38 reset_config_on_routers,
39 step,
40 get_frr_ipv6_linklocal,
41 create_route_maps,
42 create_bgp_community_lists,
43 required_linux_kernel_version,
44 )
45 from lib.topolog import logger
46 from lib.bgp import (
47 verify_bgp_convergence,
48 create_router_bgp,
49 verify_bgp_rib,
50 verify_bgp_attributes,
51 )
52 from lib.topojson import build_config_from_json
53
54 pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
55
56
57 # Global variables
58 NETWORK = {"ipv4": "100.0.10.1/32", "ipv6": "1::1/128"}
59 NEXT_HOP_IP_1 = {"ipv4": "10.0.3.1", "ipv6": "fd00:0:0:3::1"}
60 NEXT_HOP_IP_2 = {"ipv4": "10.0.4.1", "ipv6": "fd00:0:0:2::1"}
61 PREFERRED_NEXT_HOP = "link_local"
62 BGP_CONVERGENCE = False
63
64
65 def setup_module(mod):
66 """
67 Sets up the pytest environment
68
69 * `mod`: module name
70 """
71
72 global ADDR_TYPES
73
74 # Required linux kernel version for this suite to run.
75 result = required_linux_kernel_version("4.16")
76 if result is not True:
77 pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
78
79 testsuite_run_time = time.asctime(time.localtime(time.time()))
80 logger.info("Testsuite start time: {}".format(testsuite_run_time))
81 logger.info("=" * 40)
82
83 logger.info("Running setup_module to create topology")
84
85 # This function initiates the topology build with Topogen...
86 json_file = "{}/ibgp_gshut_topo1.json".format(CWD)
87 tgen = Topogen(json_file, mod.__name__)
88 global topo
89 topo = tgen.json_topo
90 # ... and here it calls Mininet initialization functions.
91
92 # Starting topology, create tmp files which are loaded to routers
93 # to start daemons and then start routers
94 start_topology(tgen)
95
96 # Creating configuration from JSON
97 build_config_from_json(tgen, topo)
98
99 # Don't run this test if we have any failure.
100 if tgen.routers_have_failure():
101 pytest.skip(tgen.errors)
102
103 # Api call verify whether BGP is converged
104 ADDR_TYPES = check_address_types()
105
106 BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
107 assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error:" " {}".format(
108 BGP_CONVERGENCE
109 )
110
111 logger.info("Running setup_module() done")
112
113
114 def teardown_module():
115 """
116 Teardown the pytest environment.
117
118 * `mod`: module name
119 """
120
121 logger.info("Running teardown_module to delete topology")
122
123 tgen = get_topogen()
124
125 # Stop toplogy and Remove tmp files
126 tgen.stop_topology()
127
128
129 ###########################
130 # Local APIs
131 ###########################
132
133
134 def next_hop_per_address_family(
135 tgen, dut, peer, addr_type, next_hop_dict, preferred_next_hop=PREFERRED_NEXT_HOP
136 ):
137 """
138 This function returns link_local or global next_hop per address-family
139 """
140
141 intferface = topo["routers"][peer]["links"]["{}".format(dut)]["interface"]
142 if addr_type == "ipv6" and "link_local" in preferred_next_hop:
143 next_hop = get_frr_ipv6_linklocal(tgen, peer, intf=intferface)
144 else:
145 next_hop = next_hop_dict[addr_type]
146
147 return next_hop
148
149
150 ###########################
151 # TESTCASES
152 ###########################
153
154
155 def test_verify_graceful_shutdown_functionality_with_iBGP_peers_p0(request):
156 """
157 Verify graceful-shutdown functionality with iBGP peers
158 """
159
160 tc_name = request.node.name
161 write_test_header(tc_name)
162 tgen = get_topogen()
163 reset_config_on_routers(tgen)
164
165 step("Done in base config: Configure base config as per the topology")
166 step("Base config should be up, verify using BGP convergence")
167 result = verify_bgp_convergence(tgen, topo)
168 assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
169
170 step("Done in base config: Advertise prefixes from R1")
171 step("Verify BGP routes are received at R4 with best path from R3 to R1")
172
173 for addr_type in ADDR_TYPES:
174 dut = "r4"
175 next_hop1 = next_hop_per_address_family(
176 tgen, "r4", "r2", addr_type, NEXT_HOP_IP_1
177 )
178 next_hop2 = next_hop_per_address_family(
179 tgen, "r4", "r3", addr_type, NEXT_HOP_IP_2
180 )
181
182 input_topo = {key: topo["routers"][key] for key in ["r1"]}
183 result = verify_bgp_rib(
184 tgen, addr_type, dut, input_topo, next_hop=[next_hop1, next_hop2]
185 )
186 assert result is True, "Test case {} : Failed \n Error: {}".format(
187 tc_name, result
188 )
189
190 result = verify_rib(
191 tgen, addr_type, dut, input_topo, next_hop=[next_hop1, next_hop2]
192 )
193 assert result is True, "Test case {} : Failed \n Error: {}".format(
194 tc_name, result
195 )
196
197 step("On R1 configure:")
198 step("Create standard bgp community-list to permit graceful-shutdown:")
199 input_dict_1 = {
200 "r1": {
201 "bgp_community_lists": [
202 {
203 "community_type": "standard",
204 "action": "permit",
205 "name": "GSHUT",
206 "value": "graceful-shutdown",
207 }
208 ]
209 }
210 }
211
212 result = create_bgp_community_lists(tgen, input_dict_1)
213 assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
214
215 step("Create route-map to set community GSHUT in OUT direction")
216
217 input_dict_2 = {
218 "r1": {
219 "route_maps": {
220 "GSHUT-OUT": [
221 {
222 "action": "permit",
223 "seq_id": "10",
224 "set": {"community": {"num": "graceful-shutdown"}},
225 }
226 ]
227 }
228 }
229 }
230
231 result = create_route_maps(tgen, input_dict_2)
232 assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
233
234 input_dict_3 = {
235 "r1": {
236 "bgp": {
237 "address_family": {
238 "ipv4": {
239 "unicast": {
240 "neighbor": {
241 "r3": {
242 "dest_link": {
243 "r1": {
244 "route_maps": [
245 {
246 "name": "GSHUT-OUT",
247 "direction": "out",
248 }
249 ]
250 }
251 }
252 }
253 }
254 }
255 },
256 "ipv6": {
257 "unicast": {
258 "neighbor": {
259 "r3": {
260 "dest_link": {
261 "r1": {
262 "route_maps": [
263 {
264 "name": "GSHUT-OUT",
265 "direction": "out",
266 }
267 ]
268 }
269 }
270 }
271 }
272 }
273 },
274 }
275 }
276 }
277 }
278
279 result = create_router_bgp(tgen, topo, input_dict_3)
280 assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
281
282 step(
283 "FRR is setting local-pref to 0 by-default on receiver GSHUT community, "
284 "below step is not needed, but keeping for reference"
285 )
286 step(
287 "On R3, apply route-map IN direction to match GSHUT community "
288 "and set local-preference to 0."
289 )
290
291 step(
292 "Verify BGP convergence on R4 and ensure all the neighbours state "
293 "is established"
294 )
295
296 result = verify_bgp_convergence(tgen, topo)
297 assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
298
299 step("Verify BGP routes on R4:")
300 step("local pref for routes coming from R1 is set to 0.")
301
302 for addr_type in ADDR_TYPES:
303 rmap_dict = {
304 "r1": {
305 "route_maps": {
306 "GSHUT-OUT": [{"set": {"locPrf": 0}}],
307 }
308 }
309 }
310
311 static_routes = [NETWORK[addr_type]]
312 result = verify_bgp_attributes(
313 tgen, addr_type, dut, static_routes, "GSHUT-OUT", rmap_dict
314 )
315 assert result is True, "Test case {} : Failed \n Error: {}".format(
316 tc_name, result
317 )
318
319 step("Ensure that best path is selected from R4 to R3.")
320
321 for addr_type in ADDR_TYPES:
322 dut = "r4"
323 next_hop1 = next_hop_per_address_family(
324 tgen, "r4", "r2", addr_type, NEXT_HOP_IP_1
325 )
326 next_hop2 = next_hop_per_address_family(
327 tgen, "r4", "r3", addr_type, NEXT_HOP_IP_2
328 )
329
330 input_topo = {key: topo["routers"][key] for key in ["r1"]}
331 result = verify_bgp_rib(
332 tgen, addr_type, dut, input_topo, next_hop=[next_hop1, next_hop2]
333 )
334 assert result is True, "Test case {} : Failed \n Error: {}".format(
335 tc_name, result
336 )
337
338 result = verify_rib(tgen, addr_type, dut, input_topo, next_hop=next_hop1)
339 assert result is True, "Test case {} : Failed \n Error: {}".format(
340 tc_name, result
341 )
342
343 write_test_footer(tc_name)
344
345
346 def test_verify_deleting_re_adding_route_map_with_iBGP_peers_p0(request):
347 """
348 Verify graceful-shutdown functionality after deleting/re-adding route-map
349 with iBGP peers
350 """
351
352 tc_name = request.node.name
353 write_test_header(tc_name)
354 tgen = get_topogen()
355 reset_config_on_routers(tgen)
356
357 step("Done in base config: Configure base config as per the topology")
358 step("Base config should be up, verify using BGP convergence")
359 result = verify_bgp_convergence(tgen, topo)
360 assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
361
362 step("Done in base config: Advertise prefixes from R1")
363 step("Verify BGP routes are received at R4 with best path from R3 to R1")
364
365 for addr_type in ADDR_TYPES:
366 dut = "r4"
367 next_hop1 = next_hop_per_address_family(
368 tgen, "r4", "r2", addr_type, NEXT_HOP_IP_1
369 )
370 next_hop2 = next_hop_per_address_family(
371 tgen, "r4", "r3", addr_type, NEXT_HOP_IP_2
372 )
373
374 input_topo = {key: topo["routers"][key] for key in ["r1"]}
375 result = verify_bgp_rib(
376 tgen, addr_type, dut, input_topo, next_hop=[next_hop1, next_hop2]
377 )
378 assert result is True, "Test case {} : Failed \n Error: {}".format(
379 tc_name, result
380 )
381
382 result = verify_rib(
383 tgen, addr_type, dut, input_topo, next_hop=[next_hop1, next_hop2]
384 )
385 assert result is True, "Test case {} : Failed \n Error: {}".format(
386 tc_name, result
387 )
388
389 step("On R1 configure:")
390 step("Create standard bgp community-list to permit graceful-shutdown:")
391 input_dict_1 = {
392 "r1": {
393 "bgp_community_lists": [
394 {
395 "community_type": "standard",
396 "action": "permit",
397 "name": "GSHUT",
398 "value": "graceful-shutdown",
399 }
400 ]
401 }
402 }
403
404 result = create_bgp_community_lists(tgen, input_dict_1)
405 assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
406
407 step("Create route-map to set community GSHUT in OUT direction")
408
409 input_dict_2 = {
410 "r1": {
411 "route_maps": {
412 "GSHUT-OUT": [
413 {
414 "action": "permit",
415 "seq_id": "10",
416 "set": {"community": {"num": "graceful-shutdown"}},
417 }
418 ]
419 }
420 }
421 }
422
423 result = create_route_maps(tgen, input_dict_2)
424 assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
425
426 input_dict_3 = {
427 "r1": {
428 "bgp": {
429 "address_family": {
430 "ipv4": {
431 "unicast": {
432 "neighbor": {
433 "r3": {
434 "dest_link": {
435 "r1": {
436 "route_maps": [
437 {
438 "name": "GSHUT-OUT",
439 "direction": "out",
440 }
441 ]
442 }
443 }
444 }
445 }
446 }
447 },
448 "ipv6": {
449 "unicast": {
450 "neighbor": {
451 "r3": {
452 "dest_link": {
453 "r1": {
454 "route_maps": [
455 {
456 "name": "GSHUT-OUT",
457 "direction": "out",
458 }
459 ]
460 }
461 }
462 }
463 }
464 }
465 },
466 }
467 }
468 }
469 }
470
471 result = create_router_bgp(tgen, topo, input_dict_3)
472 assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
473
474 step(
475 "FRR is setting local-pref to 0 by-default on receiver GSHUT community, "
476 "below step is not needed, but keeping for reference"
477 )
478 step(
479 "On R3, apply route-map IN direction to match GSHUT community "
480 "and set local-preference to 0."
481 )
482
483 step(
484 "Verify BGP convergence on R4 and ensure all the neighbours state "
485 "is established"
486 )
487
488 result = verify_bgp_convergence(tgen, topo)
489 assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
490
491 step("Verify BGP routes on R4:")
492 step("local pref for routes coming from R1 is set to 0.")
493
494 for addr_type in ADDR_TYPES:
495 rmap_dict = {
496 "r1": {
497 "route_maps": {
498 "GSHUT-OUT": [{"set": {"locPrf": 0}}],
499 }
500 }
501 }
502
503 static_routes = [NETWORK[addr_type]]
504 result = verify_bgp_attributes(
505 tgen, addr_type, dut, static_routes, "GSHUT-OUT", rmap_dict
506 )
507 assert result is True, "Test case {} : Failed \n Error: {}".format(
508 tc_name, result
509 )
510
511 step("Ensure that best path is selected from R4 to R3.")
512
513 for addr_type in ADDR_TYPES:
514 dut = "r4"
515 next_hop1 = next_hop_per_address_family(
516 tgen, "r4", "r2", addr_type, NEXT_HOP_IP_1
517 )
518 next_hop2 = next_hop_per_address_family(
519 tgen, "r4", "r3", addr_type, NEXT_HOP_IP_2
520 )
521
522 input_topo = {key: topo["routers"][key] for key in ["r1"]}
523 result = verify_bgp_rib(
524 tgen, addr_type, dut, input_topo, next_hop=[next_hop1, next_hop2]
525 )
526 assert result is True, "Test case {} : Failed \n Error: {}".format(
527 tc_name, result
528 )
529
530 result = verify_rib(tgen, addr_type, dut, input_topo, next_hop=next_hop1)
531 assert result is True, "Test case {} : Failed \n Error: {}".format(
532 tc_name, result
533 )
534
535 step("Delete route-map from R1")
536 del_rmap_dict = {
537 "r1": {
538 "route_maps": {
539 "GSHUT-OUT": [
540 {
541 "action": "permit",
542 "seq_id": "10",
543 "set": {
544 "community": {"num": "graceful-shutdown", "delete": True}
545 },
546 }
547 ]
548 }
549 }
550 }
551
552 result = create_route_maps(tgen, del_rmap_dict)
553 assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
554
555 step(
556 "Verify BGP convergence on R3 and ensure that all neighbor state "
557 "is established"
558 )
559 result = verify_bgp_convergence(tgen, topo)
560 assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
561
562 step("Verify BGP routes on R4:")
563 step("Ensure that best path is selected from R1->R3")
564
565 for addr_type in ADDR_TYPES:
566 dut = "r4"
567 next_hop1 = next_hop_per_address_family(
568 tgen, "r4", "r2", addr_type, NEXT_HOP_IP_1
569 )
570 next_hop2 = next_hop_per_address_family(
571 tgen, "r4", "r3", addr_type, NEXT_HOP_IP_2
572 )
573
574 input_topo = {key: topo["routers"][key] for key in ["r1"]}
575 result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop=[next_hop1])
576 assert result is True, "Test case {} : Failed \n Error: {}".format(
577 tc_name, result
578 )
579
580 result = verify_rib(tgen, addr_type, dut, input_topo, next_hop=[next_hop1])
581 assert result is True, "Test case {} : Failed \n Error: {}".format(
582 tc_name, result
583 )
584
585 step("Re-add route-map in R1")
586 result = create_route_maps(tgen, input_dict_2)
587 assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
588
589 step(
590 "Verify BGP convergence on R3 and ensure all the neighbours state "
591 "is established"
592 )
593
594 result = verify_bgp_convergence(tgen, topo)
595 assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
596
597 step("Verify BGP routes on R4:")
598 step("local pref for routes coming from R1 is set to 0.")
599
600 for addr_type in ADDR_TYPES:
601 rmap_dict = {"r1": {"route_maps": {"GSHUT-OUT": [{"set": {"locPrf": 0}}]}}}
602
603 static_routes = [NETWORK[addr_type]]
604 result = verify_bgp_attributes(
605 tgen, addr_type, dut, static_routes, "GSHUT-OUT", rmap_dict
606 )
607 assert result is True, "Test case {} : Failed \n Error: {}".format(
608 tc_name, result
609 )
610
611 step("Ensure that best path is selected from R4 to R3.")
612
613 for addr_type in ADDR_TYPES:
614 dut = "r4"
615 next_hop1 = next_hop_per_address_family(
616 tgen, "r4", "r2", addr_type, NEXT_HOP_IP_1
617 )
618 next_hop2 = next_hop_per_address_family(
619 tgen, "r4", "r3", addr_type, NEXT_HOP_IP_2
620 )
621
622 input_topo = {key: topo["routers"][key] for key in ["r1"]}
623 result = verify_bgp_rib(
624 tgen, addr_type, dut, input_topo, next_hop=[next_hop1, next_hop2]
625 )
626 assert result is True, "Test case {} : Failed \n Error: {}".format(
627 tc_name, result
628 )
629
630 result = verify_rib(tgen, addr_type, dut, input_topo, next_hop=next_hop1)
631 assert result is True, "Test case {} : Failed \n Error: {}".format(
632 tc_name, result
633 )
634
635 write_test_footer(tc_name)
636
637
638 if __name__ == "__main__":
639 args = ["-s"] + sys.argv[1:]
640 sys.exit(pytest.main(args))