2 # SPDX-License-Identifier: ISC
5 # Copyright (c) 2021 by VMware, Inc. ("VMware")
6 # Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
7 # ("NetDEF") in this file.
11 """OSPF Basic Functionality Automation."""
17 from copy
import deepcopy
18 from ipaddress
import IPv4Address
19 from lib
.topotest
import frr_unicode
22 # Save the Current Working Directory to find configuration files.
23 CWD
= os
.path
.dirname(os
.path
.realpath(__file__
))
24 sys
.path
.append(os
.path
.join(CWD
, "../"))
25 sys
.path
.append(os
.path
.join(CWD
, "../lib/"))
27 # pylint: disable=C0413
28 # Import topogen and topotest helpers
29 from lib
.topogen
import Topogen
, get_topogen
31 # Import topoJson from lib, to create topology and initial configuration
32 from lib
.common_config
import (
36 reset_config_on_routers
,
41 shutdown_bringup_interface
,
42 create_interfaces_cfg
,
43 get_frr_ipv6_linklocal
,
45 from lib
.topolog
import logger
46 from lib
.topojson
import build_config_from_json
48 from lib
.ospf
import (
49 verify_ospf6_neighbor
,
50 config_ospf_interface
,
54 verify_ospf6_interface
,
55 verify_ospf6_database
,
56 config_ospf6_interface
,
59 from ipaddress
import IPv6Address
61 pytestmark
= [pytest
.mark
.ospfd
, pytest
.mark
.staticd
]
75 "ipv6": ["2::1/128", "2::2/128", "2::3/128", "2::4/128", "2::5/128"],
77 MASK
= {"ipv6": "32", "ipv6": "128"}
81 Please view in a fixed-width font such as Courier.
82 Topo : Broadcast Networks
83 +---+ +---+ +---+ +---+
84 |R0 + +R1 + +R2 + +R3 |
85 +-+-+ +-+-+ +-+-+ +-+-+
88 --+-----------+--------------+---------------+-----
92 1. Verify OSPF ECMP with max path configured as 8
93 (Edge having 1 uplink port as broadcast network,
94 connect to 8 TORs - LAN case)
99 def setup_module(mod
):
101 Sets up the pytest environment
105 global topo
, switch_name
106 testsuite_run_time
= time
.asctime(time
.localtime(time
.time()))
107 logger
.info("Testsuite start time: {}".format(testsuite_run_time
))
108 logger
.info("=" * 40)
110 logger
.info("Running setup_module to create topology")
112 # This function initiates the topology build with Topogen...
113 json_file
= "{}/ospfv3_ecmp_lan.json".format(CWD
)
114 tgen
= Topogen(json_file
, mod
.__name
__)
116 topo
= tgen
.json_topo
117 # ... and here it calls Mininet initialization functions.
119 # Starting topology, create tmp files which are loaded to routers
120 # to start daemons and then start routers
123 # Creating configuration from JSON
124 build_config_from_json(tgen
, topo
)
126 # Don't run this test if we have any failure.
127 if tgen
.routers_have_failure():
128 pytest
.skip(tgen
.errors
)
129 # Api call verify whether OSPF is converged
130 ospf_covergence
= verify_ospf6_neighbor(tgen
, topo
, lan
=True)
131 assert ospf_covergence
is True, "setup_module :Failed \n Error:" " {}".format(
135 switch_name
= [k
for k
in topo
["switches"].keys()][0]
137 logger
.info("Running setup_module() done")
140 def teardown_module(mod
):
142 Teardown the pytest environment.
147 logger
.info("Running teardown_module to delete topology")
151 # Stop toplogy and Remove tmp files
154 # Stop toplogy and Remove tmp files
158 # OSError exception is raised when mininet tries to stop switch
159 # though switch is stopped once but mininet tries to stop same
160 # switch again, where it ended up with exception
163 "Testsuite end time: {}".format(time
.asctime(time
.localtime(time
.time())))
165 logger
.info("=" * 40)
168 def red_static(dut
, config
=True):
169 """Local def for Redstribute static routes inside ospf."""
173 ospf_red
= {dut
: {"ospf6": {"redistribute": [{"redist_type": "static"}]}}}
177 "ospf6": {"redistribute": [{"redist_type": "static", "delete": True}]}
180 result
= create_router_ospf(tgen
, topo
, ospf_red
)
181 assert result
is True, "Testcase : Failed \n Error: {}".format(result
)
184 def red_connected(dut
, config
=True):
185 """Local def for Redstribute connected routes inside ospf."""
189 ospf_red
= {dut
: {"ospf6": {"redistribute": [{"redist_type": "connected"}]}}}
194 "redistribute": [{"redist_type": "connected", "del_action": True}]
198 result
= create_router_ospf(tgen
, topo
, ospf_red
)
199 assert result
is True, "Testcase: Failed \n Error: {}".format(result
)
202 def get_llip(onrouter
, intf
):
204 API to get the link local ipv6 address of a particular interface
208 * `fromnode`: Source node
209 * `tonode` : interface for which link local ip needs to be returned.
213 result = get_llip('r1', 'r2-link0')
217 1) link local ipv6 address from the interface.
218 2) errormsg - when link local ip not found.
221 intf
= topo
["routers"][onrouter
]["links"][intf
]["interface"]
222 llip
= get_frr_ipv6_linklocal(tgen
, onrouter
, intf
)
224 logger
.info("llip ipv6 address to be set as NH is %s", llip
)
229 def get_glipv6(onrouter
, intf
):
231 API to get the global ipv6 address of a particular interface
235 * `onrouter`: Source node
236 * `intf` : interface for which link local ip needs to be returned.
240 result = get_glipv6('r1', 'r2-link0')
244 1) global ipv6 address from the interface.
245 2) errormsg - when link local ip not found.
247 glipv6
= (topo
["routers"][onrouter
]["links"][intf
]["ipv6"]).split("/")[0]
249 logger
.info("Global ipv6 address to be set as NH is %s", glipv6
)
254 # ##################################
255 # Test cases start here.
256 # ##################################
259 def test_ospfv3_lan_ecmp_tc18_p0(request
):
263 Verify OSPF ECMP with max path configured as 8
264 (Edge having 1 uplink port as broadcast network,
265 connect to 8 TORs - LAN case)
268 tc_name
= request
.node
.name
269 write_test_header(tc_name
)
272 # Don't run this test if we have any failure.
273 if tgen
.routers_have_failure():
274 pytest
.skip(tgen
.errors
)
277 step("Bring up the base config as per the topology")
278 step(". Configure ospf in all the routers on LAN interface.")
280 reset_config_on_routers(tgen
)
282 step("Verify that OSPF is up with 8 neighborship sessions.")
284 ospf_covergence
= verify_ospf6_neighbor(tgen
, topo
, lan
=True)
285 assert ospf_covergence
is True, "setup_module :Failed \n Error:" " {}".format(
290 "Configure a static route in all the routes and "
291 "redistribute static/connected in OSPF."
294 for rtr
in topo
["routers"]:
298 {"network": NETWORK
["ipv6"][0], "no_of_ip": 5, "next_hop": "Null0"}
302 result
= create_static_routes(tgen
, input_dict
)
303 assert result
is True, "Testcase {} : Failed \n Error: {}".format(
311 "Verify that route in R0 in stalled with 8 hops. "
312 "Verify ospf route table and ip route table."
316 for rtr
in topo
["routers"]:
317 llip
= get_llip(rtr
, switch_name
)
318 assert llip
is not None, "Testcase {} : Failed \n Error: {}".format(
323 llip
= get_llip("r1", switch_name
)
324 assert llip
is not None, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
328 result
= verify_ospf6_rib(tgen
, dut
, input_dict
)
329 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
332 result
= verify_rib(tgen
, "ipv6", dut
, input_dict
, protocol
=protocol
)
333 assert result
is True, "Testcase {} : Failed \n Error: {}".format(tc_name
, result
)
335 step(" clear ip ospf interface on DUT(r0)")
336 clear_ospf(tgen
, "r0", ospf
="ospf6")
339 "Verify that after clearing the ospf interface all the "
340 "neighbours are up and routes are installed with 8 next hop "
341 "in ospf and ip route tables on R0"
345 ospf_covergence
= verify_ospf6_neighbor(tgen
, topo
, dut
=dut
, lan
=True)
346 assert ospf_covergence
is True, "setup_module :Failed \n Error:" " {}".format(
350 step(" clear ip ospf interface on R2")
351 clear_ospf(tgen
, "r2")
354 ospf_covergence
= verify_ospf6_neighbor(tgen
, topo
, dut
=dut
, lan
=True)
355 assert ospf_covergence
is True, "setup_module :Failed \n Error:" " {}".format(
359 step("Delete static/connected cmd in ospf in all the routes one by one.")
360 for rtr
in topo
["routers"]:
365 "network": NETWORK
["ipv6"][0],
373 result
= create_static_routes(tgen
, input_dict
)
374 assert result
is True, "Testcase {} : Failed \n Error: {}".format(
378 write_test_footer(tc_name
)
381 if __name__
== "__main__":
382 args
= ["-s"] + sys
.argv
[1:]
383 sys
.exit(pytest
.main(args
))