4 # Copyright (c) 2021 by VMware, Inc. ("VMware")
5 # Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
6 # ("NetDEF") in this file.
8 # Permission to use, copy, modify, and/or distribute this software
9 # for any purpose with or without fee is hereby granted, provided
10 # that the above copyright notice and this permission notice appear
13 # THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
14 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
16 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
17 # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
25 Following tests are covered to test ecmp functionality on BGP GSHUT.
26 1. Verify graceful-shutdown functionality with eBGP peers
27 2. Verify graceful-shutdown functionality when daemons
28 bgpd/zebra/staticd and frr services are restarted with eBGP peers
37 # Save the Current Working Directory to find configuration files.
38 CWD
= os
.path
.dirname(os
.path
.realpath(__file__
))
39 sys
.path
.append(os
.path
.join(CWD
, "../"))
40 sys
.path
.append(os
.path
.join(CWD
, "../../"))
42 # pylint: disable=C0413
43 # Import topogen and topotest helpers
44 from lib
.topogen
import Topogen
, get_topogen
45 from mininet
.topo
import Topo
46 from time
import sleep
48 from lib
.common_config
import (
56 reset_config_on_routers
,
58 get_frr_ipv6_linklocal
,
64 create_bgp_community_lists
,
66 required_linux_kernel_version
,
68 from lib
.topolog
import logger
70 verify_bgp_convergence
,
74 verify_bgp_attributes
,
76 from lib
.topojson
import build_topo_from_json
, build_config_from_json
78 pytestmark
= [pytest
.mark
.bgpd
, pytest
.mark
.staticd
]
81 # Reading the data from JSON File for topology and configuration creation
82 jsonFile
= "{}/ebgp_gshut_topo1.json".format(CWD
)
84 with
open(jsonFile
, "r") as topoJson
:
85 topo
= json
.load(topoJson
)
87 logger
.info("Could not read file:", jsonFile
)
90 NETWORK
= {"ipv4": "100.0.10.1/32", "ipv6": "1::1/128"}
91 NEXT_HOP_IP_1
= {"ipv4": "10.0.2.1", "ipv6": "fd00:0:0:1::1"}
92 NEXT_HOP_IP_2
= {"ipv4": "10.0.4.2", "ipv6": "fd00:0:0:3::2"}
93 PREFERRED_NEXT_HOP
= "link_local"
94 BGP_CONVERGENCE
= False
97 class GenerateTopo(Topo
):
101 * `Topo`: Topology object
104 def build(self
, *_args
, **_opts
):
106 tgen
= get_topogen(self
)
108 # This function only purpose is to create topology
109 # as defined in input json file.
111 # Create topology (setup module)
112 # Creating 2 routers topology, r1, r2in IBGP
115 # Building topology from json file
116 build_topo_from_json(tgen
, topo
)
119 def setup_module(mod
):
121 Sets up the pytest environment
128 # Required linux kernel version for this suite to run.
129 result
= required_linux_kernel_version("4.16")
130 if result
is not True:
131 pytest
.skip("Kernel requirements are not met")
133 testsuite_run_time
= time
.asctime(time
.localtime(time
.time()))
134 logger
.info("Testsuite start time: {}".format(testsuite_run_time
))
135 logger
.info("=" * 40)
137 logger
.info("Running setup_module to create topology")
139 # This function initiates the topology build with Topogen...
140 tgen
= Topogen(GenerateTopo
, mod
.__name
__)
141 # ... and here it calls Mininet initialization functions.
143 # Starting topology, create tmp files which are loaded to routers
144 # to start deamons and then start routers
147 # Creating configuration from JSON
148 build_config_from_json(tgen
, topo
)
150 # Don't run this test if we have any failure.
151 if tgen
.routers_have_failure():
152 pytest
.skip(tgen
.errors
)
154 # Api call verify whether BGP is converged
155 ADDR_TYPES
= check_address_types()
157 BGP_CONVERGENCE
= verify_bgp_convergence(tgen
, topo
)
158 assert BGP_CONVERGENCE
is True, "setup_module :Failed \n Error:" " {}".format(
162 logger
.info("Running setup_module() done")
165 def teardown_module():
167 Teardown the pytest environment.
172 logger
.info("Running teardown_module to delete topology")
176 # Stop toplogy and Remove tmp files
180 ###########################
182 ###########################
185 def next_hop_per_address_family(
186 tgen
, dut
, peer
, addr_type
, next_hop_dict
, preferred_next_hop
=PREFERRED_NEXT_HOP
189 This function returns link_local or global next_hop per address-family
192 intferface
= topo
["routers"][peer
]["links"]["{}".format(dut
)]["interface"]
193 if addr_type
== "ipv6" and "link_local" in preferred_next_hop
:
194 next_hop
= get_frr_ipv6_linklocal(tgen
, peer
, intf
=intferface
)
196 next_hop
= next_hop_dict
[addr_type
]
201 ###########################
203 ###########################
206 def test_verify_graceful_shutdown_functionality_with_eBGP_peers_p0(request
):
208 Verify graceful-shutdown functionality with eBGP peers
211 tc_name
= request
.node
.name
212 write_test_header(tc_name
)
214 reset_config_on_routers(tgen
)
216 step("Done in base config: Configure base config as per the topology")
217 step("Base config should be up, verify using BGP convergence")
218 result
= verify_bgp_convergence(tgen
, topo
)
219 assert result
is True, "Test case {} : Failed \n Error: {}".format(tc_name
, result
)
221 step("Done in base config: Advertise prefixes from R1")
222 step("Verify BGP routes are received at R3 with best path from R3 to R1")
224 for addr_type
in ADDR_TYPES
:
226 next_hop1
= next_hop_per_address_family(
227 tgen
, "r3", "r1", addr_type
, NEXT_HOP_IP_1
229 next_hop2
= next_hop_per_address_family(
230 tgen
, "r3", "r4", addr_type
, NEXT_HOP_IP_2
233 input_topo
= {key
: topo
["routers"][key
] for key
in ["r1"]}
234 result
= verify_bgp_rib(
235 tgen
, addr_type
, dut
, input_topo
, next_hop
=[next_hop1
, next_hop2
]
237 assert result
is True, "Test case {} : Failed \n Error: {}".format(
241 result
= verify_rib(tgen
, addr_type
, dut
, input_topo
, next_hop
=next_hop1
)
242 assert result
is True, "Test case {} : Failed \n Error: {}".format(
246 step("On R1 configure:")
247 step("Create standard bgp community-list to permit graceful-shutdown:")
250 "bgp_community_lists": [
252 "community_type": "standard",
255 "value": "graceful-shutdown",
261 result
= create_bgp_community_lists(tgen
, input_dict_1
)
262 assert result
is True, "Test case {} : Failed \n Error: {}".format(tc_name
, result
)
264 step("Create route-map to set community GSHUT in OUT direction")
273 "set": {"community": {"num": "graceful-shutdown"}},
280 result
= create_route_maps(tgen
, input_dict_2
)
281 assert result
is True, "Test case {} : Failed \n Error: {}".format(tc_name
, result
)
328 result
= create_router_bgp(tgen
, topo
, input_dict_3
)
329 assert result
is True, "Test case {} : Failed \n Error: {}".format(tc_name
, result
)
332 "FRR is setting local-pref to 0 by-default on receiver GSHUT community, "
333 "below step is not needed, but keeping for reference"
336 "On R3, apply route-map IN direction to match GSHUT community "
337 "and set local-preference to 0."
341 "Verify BGP convergence on R3 and ensure all the neighbours state "
345 result
= verify_bgp_convergence(tgen
, topo
)
346 assert result
is True, "Test case {} : Failed \n Error: {}".format(tc_name
, result
)
348 step("Verify BGP routes on R3:")
349 step("local pref for routes coming from R1 is set to 0.")
351 for addr_type
in ADDR_TYPES
:
352 rmap_dict
= {"r1": {"route_maps": {"GSHUT-OUT": [{"set": {"locPrf": 0}}],}}}
354 static_routes
= [NETWORK
[addr_type
]]
355 result
= verify_bgp_attributes(
356 tgen
, addr_type
, dut
, static_routes
, "GSHUT-OUT", rmap_dict
358 assert result
is True, "Test case {} : Failed \n Error: {}".format(
362 step("Ensure that best path is selected from R4 to R3.")
364 for addr_type
in ADDR_TYPES
:
366 next_hop1
= next_hop_per_address_family(
367 tgen
, "r3", "r1", addr_type
, NEXT_HOP_IP_1
369 next_hop2
= next_hop_per_address_family(
370 tgen
, "r3", "r4", addr_type
, NEXT_HOP_IP_2
373 input_topo
= {key
: topo
["routers"][key
] for key
in ["r1"]}
374 result
= verify_bgp_rib(
375 tgen
, addr_type
, dut
, input_topo
, next_hop
=[next_hop1
, next_hop2
]
377 assert result
is True, "Test case {} : Failed \n Error: {}".format(
381 result
= verify_rib(tgen
, addr_type
, dut
, input_topo
, next_hop
=next_hop2
)
382 assert result
is True, "Test case {} : Failed \n Error: {}".format(
386 write_test_footer(tc_name
)
389 def test_verify_restarting_zebra_bgpd_staticd_frr_with_eBGP_peers_p0(request
):
391 Verify graceful-shutdown functionality when daemons bgpd/zebra/staticd and
392 frr services are restarted with eBGP peers
395 tc_name
= request
.node
.name
396 write_test_header(tc_name
)
398 reset_config_on_routers(tgen
)
400 step("Done in base config: Configure base config as per the topology")
401 step("Base config should be up, verify using BGP convergence")
402 result
= verify_bgp_convergence(tgen
, topo
)
403 assert result
is True, "Test case {} : Failed \n Error: {}".format(tc_name
, result
)
405 step("Done in base config: Advertise prefixes from R1")
406 step("Verify BGP routes are received at R3 with best path from R3 to R1")
408 for addr_type
in ADDR_TYPES
:
410 next_hop1
= next_hop_per_address_family(
411 tgen
, "r3", "r1", addr_type
, NEXT_HOP_IP_1
413 next_hop2
= next_hop_per_address_family(
414 tgen
, "r3", "r4", addr_type
, NEXT_HOP_IP_2
417 input_topo
= {key
: topo
["routers"][key
] for key
in ["r1"]}
418 result
= verify_bgp_rib(
419 tgen
, addr_type
, dut
, input_topo
, next_hop
=[next_hop1
, next_hop2
]
421 assert result
is True, "Test case {} : Failed \n Error: {}".format(
425 result
= verify_rib(tgen
, addr_type
, dut
, input_topo
, next_hop
=next_hop1
)
426 assert result
is True, "Test case {} : Failed \n Error: {}".format(
430 step("On R1 configure:")
431 step("Create standard bgp community-list to permit graceful-shutdown:")
434 "bgp_community_lists": [
436 "community_type": "standard",
439 "value": "graceful-shutdown",
445 result
= create_bgp_community_lists(tgen
, input_dict_1
)
446 assert result
is True, "Test case {} : Failed \n Error: {}".format(tc_name
, result
)
448 step("Create route-map to set community GSHUT in OUT direction")
457 "set": {"community": {"num": "graceful-shutdown"}},
464 result
= create_route_maps(tgen
, input_dict_2
)
465 assert result
is True, "Test case {} : Failed \n Error: {}".format(tc_name
, result
)
512 result
= create_router_bgp(tgen
, topo
, input_dict_3
)
513 assert result
is True, "Test case {} : Failed \n Error: {}".format(tc_name
, result
)
516 "FRR is setting local-pref to 0 by-default on receiver GSHUT community, "
517 "below step is not needed, but keeping for reference"
520 "On R3, apply route-map IN direction to match GSHUT community "
521 "and set local-preference to 0."
525 "Verify BGP convergence on R3 and ensure all the neighbours state "
529 result
= verify_bgp_convergence(tgen
, topo
)
530 assert result
is True, "Test case {} : Failed \n Error: {}".format(tc_name
, result
)
532 step("Verify BGP routes on R3:")
533 step("local pref for routes coming from R1 is set to 0.")
535 for addr_type
in ADDR_TYPES
:
536 rmap_dict
= {"r1": {"route_maps": {"GSHUT-OUT": [{"set": {"locPrf": 0}}]}}}
538 static_routes
= [NETWORK
[addr_type
]]
539 result
= verify_bgp_attributes(
540 tgen
, addr_type
, dut
, static_routes
, "GSHUT-OUT", rmap_dict
542 assert result
is True, "Test case {} : Failed \n Error: {}".format(
546 step("Ensure that best path is selected from R4 to R3.")
548 for addr_type
in ADDR_TYPES
:
550 next_hop1
= next_hop_per_address_family(
551 tgen
, "r3", "r1", addr_type
, NEXT_HOP_IP_1
553 next_hop2
= next_hop_per_address_family(
554 tgen
, "r3", "r4", addr_type
, NEXT_HOP_IP_2
557 input_topo
= {key
: topo
["routers"][key
] for key
in ["r1"]}
558 result
= verify_bgp_rib(
559 tgen
, addr_type
, dut
, input_topo
, next_hop
=[next_hop1
, next_hop2
]
561 assert result
is True, "Test case {} : Failed \n Error: {}".format(
565 result
= verify_rib(tgen
, addr_type
, dut
, input_topo
, next_hop
=next_hop2
)
566 assert result
is True, "Test case {} : Failed \n Error: {}".format(
570 step("Restart daemons and frr services")
572 for daemon
in ["bgpd", "zebra", "staticd", "frr"]:
574 kill_router_daemons(tgen
, "r3", ["staticd"])
575 start_router_daemons(tgen
, "r3", ["staticd"])
577 stop_router(tgen
, "r3")
578 start_router(tgen
, "r3")
581 "Verify BGP convergence on R3 and ensure all the neighbours state "
585 result
= verify_bgp_convergence(tgen
, topo
)
586 assert result
is True, "Test case {} : Failed \n Error: {}".format(
590 step("Verify BGP routes on R3:")
591 step("local pref for routes coming from R1 is set to 0.")
593 for addr_type
in ADDR_TYPES
:
594 rmap_dict
= {"r1": {"route_maps": {"GSHUT-OUT": [{"set": {"locPrf": 0}}]}}}
596 static_routes
= [NETWORK
[addr_type
]]
597 result
= verify_bgp_attributes(
598 tgen
, addr_type
, dut
, static_routes
, "GSHUT-OUT", rmap_dict
600 assert result
is True, "Test case {} : Failed \n Error: {}".format(
604 step("Ensure that best path is selected from R4 to R3.")
606 for addr_type
in ADDR_TYPES
:
608 next_hop1
= next_hop_per_address_family(
609 tgen
, "r3", "r1", addr_type
, NEXT_HOP_IP_1
611 next_hop2
= next_hop_per_address_family(
612 tgen
, "r3", "r4", addr_type
, NEXT_HOP_IP_2
615 input_topo
= {key
: topo
["routers"][key
] for key
in ["r1"]}
616 result
= verify_bgp_rib(
617 tgen
, addr_type
, dut
, input_topo
, next_hop
=[next_hop1
, next_hop2
]
619 assert result
is True, "Test case {} : Failed \n Error: {}".format(
623 result
= verify_rib(tgen
, addr_type
, dut
, input_topo
, next_hop
=next_hop2
)
624 assert result
is True, "Test case {} : Failed \n Error: {}".format(
628 write_test_footer(tc_name
)
631 if __name__
== "__main__":
632 args
= ["-s"] + sys
.argv
[1:]
633 sys
.exit(pytest
.main(args
))