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
24 """OSPF Basic Functionality Automation."""
30 from copy
import deepcopy
31 from ipaddress
import IPv4Address
32 from lib
.topotest
import frr_unicode
34 # Save the Current Working Directory to find configuration files.
35 CWD
= os
.path
.dirname(os
.path
.realpath(__file__
))
36 sys
.path
.append(os
.path
.join(CWD
, "../"))
37 sys
.path
.append(os
.path
.join(CWD
, "../lib/"))
39 # pylint: disable=C0413
40 # Import topogen and topotest helpers
41 from mininet
.topo
import Topo
42 from lib
.topogen
import Topogen
, get_topogen
45 # Import topoJson from lib, to create topology and initial configuration
46 from lib
.common_config
import (
50 reset_config_on_routers
,
55 shutdown_bringup_interface
,
56 create_interfaces_cfg
,
58 get_frr_ipv6_linklocal
,
60 from lib
.topolog
import logger
61 from lib
.topojson
import build_topo_from_json
, build_config_from_json
63 from lib
.ospf
import (
64 verify_ospf6_neighbor
,
65 config_ospf_interface
,
69 verify_ospf6_interface
,
70 verify_ospf6_database
,
71 config_ospf6_interface
,
74 from ipaddress
import IPv6Address
76 pytestmark
= [pytest
.mark
.ospfd
, pytest
.mark
.staticd
]
82 # Reading the data from JSON File for topology creation
83 jsonFile
= "{}/ospfv3_ecmp.json".format(CWD
)
85 with
open(jsonFile
, "r") as topoJson
:
86 topo
= json
.load(topoJson
)
88 assert False, "Could not read file {}".format(jsonFile
)
98 "ipv6": ["2::1/128", "2::2/128", "2::3/128", "2::4/128", "2::5/128"],
102 Please view in a fixed-width font such as Courier.
104 +R1 +------------+R2 |
113 +R0 +-------------+R3 |
117 1. Verify OSPF ECMP with max path configured as 8 (ECMPconfigured at FRR level)
118 2. Verify OSPF ECMP with max path configured as 2 (Edge having 2 uplink ports)
122 class CreateTopo(Topo
):
124 Test topology builder.
126 * `Topo`: Topology object
129 def build(self
, *_args
, **_opts
):
130 """Build function."""
131 tgen
= get_topogen(self
)
133 # Building topology from json file
134 build_topo_from_json(tgen
, topo
)
137 def setup_module(mod
):
139 Sets up the pytest environment
144 testsuite_run_time
= time
.asctime(time
.localtime(time
.time()))
145 logger
.info("Testsuite start time: {}".format(testsuite_run_time
))
146 logger
.info("=" * 40)
148 logger
.info("Running setup_module to create topology")
150 # This function initiates the topology build with Topogen...
151 tgen
= Topogen(CreateTopo
, mod
.__name
__)
152 # ... and here it calls Mininet initialization functions.
154 # get list of daemons needs to be started for this suite.
155 daemons
= topo_daemons(tgen
, topo
)
157 # Starting topology, create tmp files which are loaded to routers
158 # to start deamons and then start routers
159 start_topology(tgen
, daemons
)
161 # Creating configuration from JSON
162 build_config_from_json(tgen
, topo
)
164 # Don't run this test if we have any failure.
165 if tgen
.routers_have_failure():
166 pytest
.skip(tgen
.errors
)
168 ospf_covergence
= verify_ospf6_neighbor(tgen
, topo
)
169 assert ospf_covergence
is True, "setup_module :Failed \n Error:" " {}".format(
173 logger
.info("Running setup_module() done")
176 def teardown_module(mod
):
178 Teardown the pytest environment.
183 logger
.info("Running teardown_module to delete topology")
187 # Stop toplogy and Remove tmp files
191 "Testsuite end time: {}".format(time
.asctime(time
.localtime(time
.time())))
193 logger
.info("=" * 40)
196 def red_static(dut
, config
=True):
197 """Local def for Redstribute static routes inside ospf."""
201 ospf_red
= {dut
: {"ospf6": {"redistribute": [{"redist_type": "static"}]}}}
205 "ospf6": {"redistribute": [{"redist_type": "static", "delete": True}]}
208 result
= create_router_ospf(tgen
, topo
, ospf_red
)
209 assert result
is True, "Testcase : Failed \n Error: {}".format(result
)
212 def red_connected(dut
, config
=True):
213 """Local def for Redstribute connected routes inside ospf."""
217 ospf_red
= {dut
: {"ospf6": {"redistribute": [{"redist_type": "connected"}]}}}
222 "redistribute": [{"redist_type": "connected", "del_action": True}]
226 result
= create_router_ospf(tgen
, topo
, ospf_red
)
227 assert result
is True, "Testcase: Failed \n Error: {}".format(result
)
230 def get_llip(onrouter
, intf
):
232 API to get the link local ipv6 address of a perticular interface
236 * `fromnode`: Source node
237 * `tonode` : interface for which link local ip needs to be returned.
241 result = get_llip('r1', 'r2-link0')
245 1) link local ipv6 address from the interface.
246 2) errormsg - when link local ip not found.
249 intf
= topo
["routers"][onrouter
]["links"][intf
]["interface"]
250 llip
= get_frr_ipv6_linklocal(tgen
, onrouter
, intf
)
252 logger
.info("llip ipv6 address to be set as NH is %s", llip
)
257 def get_glipv6(onrouter
, intf
):
259 API to get the global ipv6 address of a perticular interface
263 * `onrouter`: Source node
264 * `intf` : interface for which link local ip needs to be returned.
268 result = get_glipv6('r1', 'r2-link0')
272 1) global ipv6 address from the interface.
273 2) errormsg - when link local ip not found.
275 glipv6
= (topo
["routers"][onrouter
]["links"][intf
]["ipv6"]).split("/")[0]
277 logger
.info("Global ipv6 address to be set as NH is %s", glipv6
)
282 # ##################################
283 # Test cases start here.
284 # ##################################
287 def test_ospfv3_ecmp_tc16_p0(request
):
291 Verify OSPF ECMP with max path configured as 8 (ECMP
292 configured at FRR level)
294 tc_name
= request
.node
.name
295 write_test_header(tc_name
)
298 # Don't run this test if we have any failure.
299 if tgen
.routers_have_failure():
300 pytest
.skip(tgen
.errors
)
303 step("Bring up the base config as per the topology")
304 step("Configure 8 interfaces between R1 and R2 and enable ospf in area 0.")
306 reset_config_on_routers(tgen
)
308 step("Verify that OSPF is up with 8 neighborship sessions.")
310 ospf_covergence
= verify_ospf6_neighbor(tgen
, topo
, dut
=dut
)
311 assert ospf_covergence
is True, "setup_module :Failed \n Error:" " {}".format(
315 step("Configure a static route in R0 and redistribute in OSPF.")
321 "network": NETWORK
["ipv6"][0],
328 result
= create_static_routes(tgen
, input_dict
)
329 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
334 llip
= get_llip("r0", "r1-link1")
335 assert llip
is not None, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
337 step("Verify that route in R2 in stalled with 8 next hops.")
339 for item
in range(1, 7):
342 llip
= get_llip("r0", "r1")
343 assert llip
is not None, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
350 result
= verify_ospf6_rib(tgen
, dut
, input_dict
, next_hop
=nh
)
351 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
354 result
= verify_rib(tgen
, "ipv6", dut
, input_dict
, protocol
=protocol
, next_hop
=nh
)
355 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
357 step("shut no shut all the interfaces on the remote router - R2")
359 for intfr
in range(1, 7):
360 intf
= topo
["routers"]["r1"]["links"]["r0-link{}".format(intfr
)]["interface"]
361 shutdown_bringup_interface(tgen
, dut
, intf
, False)
363 result
= verify_ospf6_rib(tgen
, dut
, input_dict
, next_hop
=nh
, expected
=False)
366 ), "Testcase {} : Failed \n Route present in OSPF RIB. Error: {}".format(
372 tgen
, "ipv6", dut
, input_dict
, protocol
=protocol
, next_hop
=nh
, expected
=False
376 ), "Testcase {} : Failed \n Route present in RIB. Error: {}".format(tc_name
, result
)
378 for intfr
in range(1, 7):
379 intf
= topo
["routers"]["r1"]["links"]["r0-link{}".format(intfr
)]["interface"]
380 shutdown_bringup_interface(tgen
, dut
, intf
, True)
382 result
= verify_ospf6_rib(tgen
, dut
, input_dict
, next_hop
=nh
)
383 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
386 result
= verify_rib(tgen
, "ipv6", dut
, input_dict
, protocol
=protocol
, next_hop
=nh
)
387 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
389 step("shut no shut on all the interfaces on DUT (r1)")
390 for intfr
in range(1, 7):
391 intf
= topo
["routers"]["r1"]["links"]["r0-link{}".format(intfr
)]["interface"]
392 shutdown_bringup_interface(tgen
, dut
, intf
, False)
394 for intfr
in range(1, 7):
395 intf
= topo
["routers"]["r1"]["links"]["r0-link{}".format(intfr
)]["interface"]
396 shutdown_bringup_interface(tgen
, dut
, intf
, True)
399 "Verify that all the neighbours are up and routes are installed"
400 " with 8 next hop in ospf and ip route tables on R1."
403 step("Verify that OSPF is up with 8 neighborship sessions.")
405 ospf_covergence
= verify_ospf6_neighbor(tgen
, topo
, dut
=dut
)
406 assert ospf_covergence
is True, "setup_module :Failed \n Error:" " {}".format(
411 result
= verify_ospf6_rib(tgen
, dut
, input_dict
, next_hop
=nh
)
412 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
415 result
= verify_rib(tgen
, "ipv6", dut
, input_dict
, protocol
=protocol
, next_hop
=nh
)
416 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
418 write_test_footer(tc_name
)
421 def test_ospfv3_ecmp_tc17_p0(request
):
425 Verify OSPF ECMP with max path configured as 2 (Edge having 2 uplink ports)
427 tc_name
= request
.node
.name
428 write_test_header(tc_name
)
431 # Don't run this test if we have any failure.
432 if tgen
.routers_have_failure():
433 pytest
.skip(tgen
.errors
)
436 step("Bring up the base config as per the topology")
437 step("Configure 2 interfaces between R1 and R2 & enable ospf in area 0.")
439 reset_config_on_routers(tgen
)
441 step("Verify that OSPF is up with 2 neighborship sessions.")
443 ospf_covergence
= verify_ospf6_neighbor(tgen
, topo
, dut
=dut
)
444 assert ospf_covergence
is True, "setup_module :Failed \n Error:" " {}".format(
448 step("Configure a static route in R0 and redistribute in OSPF.")
454 "network": NETWORK
["ipv6"][0],
461 result
= create_static_routes(tgen
, input_dict
)
462 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
467 step("Verify that route in R2 in stalled with 2 next hops.")
469 llip
= get_llip("r0", "r1-link1")
470 assert llip
is not None, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
474 llip
= get_llip("r0", "r1")
475 assert llip
is not None, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
482 result
= verify_ospf6_rib(tgen
, dut
, input_dict
, next_hop
=nh
)
483 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
486 result
= verify_rib(tgen
, "ipv6", dut
, input_dict
, protocol
=protocol
, next_hop
=nh
)
487 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
489 step("Configure ECMP value as 1.")
490 max_path
= {"r1": {"ospf6": {"maximum-paths": 1}}}
491 result
= create_router_ospf(tgen
, topo
, max_path
)
492 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
494 result
= verify_rib(tgen
, "ipv6", dut
, input_dict
, protocol
=protocol
, next_hop
=nh2
)
495 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
498 max_path
= {"r1": {"ospf6": {"maximum-paths": 2}}}
499 result
= create_router_ospf(tgen
, topo
, max_path
)
500 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
502 result
= verify_rib(tgen
, "ipv6", dut
, input_dict
, protocol
=protocol
, next_hop
=nh
)
503 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
505 step("Configure cost on R0 as 100")
506 r0_ospf_cost
= {"r0": {"links": {"r1": {"ospf6": {"cost": 100}}}}}
507 result
= config_ospf6_interface(tgen
, topo
, r0_ospf_cost
)
508 assert result
is True, "Testcase {} :Failed \n Error: {}".format(tc_name
, result
)
511 result
= verify_ospf6_rib(tgen
, dut
, input_dict
, next_hop
=nh
)
512 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
515 result
= verify_rib(tgen
, "ipv6", dut
, input_dict
, protocol
=protocol
, next_hop
=nh
)
516 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
518 write_test_footer(tc_name
)
521 if __name__
== "__main__":
522 args
= ["-s"] + sys
.argv
[1:]
523 sys
.exit(pytest
.main(args
))