]>
git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py
2 # SPDX-License-Identifier: ISC
5 # test_ospf_gr_topo1.py
6 # Part of NetDEF Topology Tests
8 # Copyright (c) 2021 by
9 # Network Device Education Foundation, Inc. ("NetDEF")
13 test_ospf_gr_topo1.py:
39 10.0.3.0/24 | | 10.0.4.0/24
40 +---------+ +--------+
43 +---------+ +---------+
45 | 4.4.4.4 | | 6.6.6.6 |
46 +---------+ +---------+
49 |10.0.5.0/24 |10.0.6.0/24
52 +---------+ +---------+
54 | 5.5.5.5 | | 7.7.7.7 |
55 +---------+ +---------+
62 from time
import sleep
63 from functools
import partial
65 # Save the Current Working Directory to find configuration files.
66 CWD
= os
.path
.dirname(os
.path
.realpath(__file__
))
67 sys
.path
.append(os
.path
.join(CWD
, "../"))
69 # pylint: disable=C0413
70 # Import topogen and topotest helpers
71 from lib
import topotest
72 from lib
.topogen
import Topogen
, TopoRouter
, get_topogen
73 from lib
.topolog
import logger
74 from lib
.common_config
import (
79 # Required to instantiate the topology builder class.
81 pytestmark
= [pytest
.mark
.ospfd
]
83 # Global multi-dimensional dictionary containing all expected outputs
91 for router
in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
92 tgen
.add_router(router
)
97 switch
= tgen
.add_switch("s1")
98 switch
.add_link(tgen
.gears
["rt1"], nodeif
="eth-rt2")
99 switch
.add_link(tgen
.gears
["rt2"], nodeif
="eth-rt1")
101 switch
= tgen
.add_switch("s2")
102 switch
.add_link(tgen
.gears
["rt1"], nodeif
="stub1")
104 switch
= tgen
.add_switch("s3")
105 switch
.add_link(tgen
.gears
["rt2"], nodeif
="eth-rt3")
106 switch
.add_link(tgen
.gears
["rt3"], nodeif
="eth-rt2")
108 switch
= tgen
.add_switch("s4")
109 switch
.add_link(tgen
.gears
["rt3"], nodeif
="eth-rt4")
110 switch
.add_link(tgen
.gears
["rt4"], nodeif
="eth-rt3")
112 switch
= tgen
.add_switch("s5")
113 switch
.add_link(tgen
.gears
["rt3"], nodeif
="eth-rt6")
114 switch
.add_link(tgen
.gears
["rt6"], nodeif
="eth-rt3")
116 switch
= tgen
.add_switch("s6")
117 switch
.add_link(tgen
.gears
["rt4"], nodeif
="eth-rt5")
118 switch
.add_link(tgen
.gears
["rt5"], nodeif
="eth-rt4")
120 switch
= tgen
.add_switch("s7")
121 switch
.add_link(tgen
.gears
["rt6"], nodeif
="eth-rt7")
122 switch
.add_link(tgen
.gears
["rt7"], nodeif
="eth-rt6")
124 switch
= tgen
.add_switch("s8")
125 switch
.add_link(tgen
.gears
["rt7"], nodeif
="stub1")
128 def setup_module(mod
):
129 "Sets up the pytest environment"
130 tgen
= Topogen(build_topo
, mod
.__name
__)
131 tgen
.start_topology()
133 router_list
= tgen
.routers()
135 # For all registered routers, load the zebra configuration file
136 for rname
, router
in router_list
.items():
138 TopoRouter
.RD_ZEBRA
, os
.path
.join(CWD
, "{}/zebra.conf".format(rname
))
141 TopoRouter
.RD_OSPF
, os
.path
.join(CWD
, "{}/ospfd.conf".format(rname
))
147 def teardown_module(mod
):
148 "Teardown the pytest environment"
151 # This function tears down the whole topology.
155 def router_compare_json_output(rname
, command
, reference
, tries
):
156 "Compare router JSON output"
158 logger
.info('Comparing router "%s" "%s" output', rname
, command
)
161 filename
= "{}/{}/{}".format(CWD
, rname
, reference
)
162 expected
= json
.loads(open(filename
).read())
164 test_func
= partial(topotest
.router_json_cmp
, tgen
.gears
[rname
], command
, expected
)
165 _
, diff
= topotest
.run_and_expect(test_func
, None, count
=tries
, wait
=0.5)
166 assertmsg
= '"{}" JSON output mismatches the expected result'.format(rname
)
167 assert diff
is None, assertmsg
170 def expect_grace_lsa(restarting
, area
, helper
):
172 Check if the given helper neighbor has already received a Grace-LSA from
173 the router performing a graceful restart.
178 "'{}': checking if a Grace-LSA was received from '{}'".format(
183 topotest
.router_json_cmp
,
185 "show ip ospf database opaque-link json",
187 "linkLocalOpaqueLsa": {
191 "advertisingRouter": restarting
,
192 "opaqueType": "Grace-LSA",
199 _
, result
= topotest
.run_and_expect(test_func
, None, count
=60, wait
=1)
200 assertmsg
= '"{}" didn\'t receive a Grace-LSA from "{}"'.format(helper
, restarting
)
202 assert result
is None, assertmsg
205 def check_routers(initial_convergence
=False, exiting
=None, restarting
=None):
206 for rname
in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
207 # Check the RIB first, which should be preserved across restarts in
208 # all routers of the routing domain.
209 # If we are not on initial convergence *but* we are checking
210 # after a restart. Looking in the zebra rib for installed
211 # is a recipe for test failure. Why? because if we are restarting
212 # then ospf is in the process of establishing neighbors and passing
213 # new routes to zebra. Zebra will not mark the route as installed
214 # when it receives a replacement from ospf until it has finished
215 # processing it. Let's give it a few seconds to allow this to happen
217 if initial_convergence
== True:
220 if restarting
!= None:
224 router_compare_json_output(
225 rname
, "show ip route ospf json", "show_ip_route.json", tries
228 # Check that all adjacencies are up and running (except when there's
229 # an OSPF instance that is shutting down).
232 router_compare_json_output(
233 rname
, "show ip ospf neighbor json", "show_ip_ospf_neighbor.json", tries
236 # Check the OSPF RIB and LSDB.
237 # In the restarting router, wait up to one minute for the LSDB to converge.
239 if initial_convergence
== True or restarting
== rname
:
243 router_compare_json_output(
244 rname
, "show ip ospf database json", "show_ip_ospf_database.json", tries
246 router_compare_json_output(
247 rname
, "show ip ospf route json", "show_ip_ospf_route.json", tries
251 def ensure_gr_is_in_zebra(rname
):
256 while retry
and retry_times
> 0:
257 out
= tgen
.net
[rname
].cmd(
258 'vtysh -c "show zebra client" | grep "Client: ospf$" -A 40 | grep "Capabilities "'
261 if "Graceful Restart" not in out
:
267 assertmsg
= "%s does not appear to have Graceful Restart setup" % rname
268 assert not retry
and retry_times
> 0, assertmsg
272 # Test initial network convergence
274 def test_initial_convergence():
275 logger
.info("Test: verify initial network convergence")
278 # Skip if previous fatal error condition is raised
279 if tgen
.routers_have_failure():
280 pytest
.skip(tgen
.errors
)
282 check_routers(initial_convergence
=True)
286 # Test rt1 performing a graceful restart
289 logger
.info("Test: verify rt1 performing a graceful restart")
292 # Skip if previous fatal error condition is raised
293 if tgen
.routers_have_failure():
294 pytest
.skip(tgen
.errors
)
296 tgen
.net
["rt1"].cmd('vtysh -c "graceful-restart prepare ip ospf"')
297 expect_grace_lsa(restarting
="1.1.1.1", area
="0.0.0.1", helper
="rt2")
298 ensure_gr_is_in_zebra("rt1")
299 kill_router_daemons(tgen
, "rt1", ["ospfd"], save_config
=False)
300 check_routers(exiting
="rt1")
302 start_router_daemons(tgen
, "rt1", ["ospfd"])
303 check_routers(restarting
="rt1")
307 # Test rt2 performing a graceful restart
310 logger
.info("Test: verify rt2 performing a graceful restart")
313 # Skip if previous fatal error condition is raised
314 if tgen
.routers_have_failure():
315 pytest
.skip(tgen
.errors
)
317 tgen
.net
["rt2"].cmd('vtysh -c "graceful-restart prepare ip ospf"')
318 expect_grace_lsa(restarting
="2.2.2.2", area
="0.0.0.1", helper
="rt1")
319 expect_grace_lsa(restarting
="2.2.2.2", area
="0.0.0.0", helper
="rt3")
320 ensure_gr_is_in_zebra("rt2")
321 kill_router_daemons(tgen
, "rt2", ["ospfd"], save_config
=False)
322 check_routers(exiting
="rt2")
324 start_router_daemons(tgen
, "rt2", ["ospfd"])
325 check_routers(restarting
="rt2")
329 # Test rt3 performing a graceful restart
332 logger
.info("Test: verify rt3 performing a graceful restart")
335 # Skip if previous fatal error condition is raised
336 if tgen
.routers_have_failure():
337 pytest
.skip(tgen
.errors
)
339 tgen
.net
["rt3"].cmd('vtysh -c "graceful-restart prepare ip ospf"')
340 expect_grace_lsa(restarting
="3.3.3.3", area
="0.0.0.0", helper
="rt2")
341 expect_grace_lsa(restarting
="3.3.3.3", area
="0.0.0.0", helper
="rt4")
342 expect_grace_lsa(restarting
="3.3.3.3", area
="0.0.0.0", helper
="rt6")
343 ensure_gr_is_in_zebra("rt3")
344 kill_router_daemons(tgen
, "rt3", ["ospfd"], save_config
=False)
345 check_routers(exiting
="rt3")
347 start_router_daemons(tgen
, "rt3", ["ospfd"])
348 check_routers(restarting
="rt3")
352 # Test rt4 performing a graceful restart
355 logger
.info("Test: verify rt4 performing a graceful restart")
358 # Skip if previous fatal error condition is raised
359 if tgen
.routers_have_failure():
360 pytest
.skip(tgen
.errors
)
362 tgen
.net
["rt4"].cmd('vtysh -c "graceful-restart prepare ip ospf"')
363 expect_grace_lsa(restarting
="4.4.4.4", area
="0.0.0.0", helper
="rt3")
364 expect_grace_lsa(restarting
="4.4.4.4", area
="0.0.0.2", helper
="rt5")
365 ensure_gr_is_in_zebra("rt4")
366 kill_router_daemons(tgen
, "rt4", ["ospfd"], save_config
=False)
367 check_routers(exiting
="rt4")
369 start_router_daemons(tgen
, "rt4", ["ospfd"])
370 check_routers(restarting
="rt4")
374 # Test rt5 performing a graceful restart
377 logger
.info("Test: verify rt5 performing a graceful restart")
380 # Skip if previous fatal error condition is raised
381 if tgen
.routers_have_failure():
382 pytest
.skip(tgen
.errors
)
384 tgen
.net
["rt5"].cmd('vtysh -c "graceful-restart prepare ip ospf"')
385 expect_grace_lsa(restarting
="5.5.5.5", area
="0.0.0.2", helper
="rt4")
386 ensure_gr_is_in_zebra("rt5")
387 kill_router_daemons(tgen
, "rt5", ["ospfd"], save_config
=False)
388 check_routers(exiting
="rt5")
390 start_router_daemons(tgen
, "rt5", ["ospfd"])
391 check_routers(restarting
="rt5")
395 # Test rt6 performing a graceful restart
398 logger
.info("Test: verify rt6 performing a graceful restart")
401 # Skip if previous fatal error condition is raised
402 if tgen
.routers_have_failure():
403 pytest
.skip(tgen
.errors
)
405 tgen
.net
["rt6"].cmd('vtysh -c "graceful-restart prepare ip ospf"')
406 expect_grace_lsa(restarting
="6.6.6.6", area
="0.0.0.0", helper
="rt3")
407 expect_grace_lsa(restarting
="6.6.6.6", area
="0.0.0.3", helper
="rt7")
408 ensure_gr_is_in_zebra("rt6")
409 kill_router_daemons(tgen
, "rt6", ["ospfd"], save_config
=False)
410 check_routers(exiting
="rt6")
412 start_router_daemons(tgen
, "rt6", ["ospfd"])
413 check_routers(restarting
="rt6")
417 # Test rt7 performing a graceful restart
420 logger
.info("Test: verify rt7 performing a graceful restart")
423 # Skip if previous fatal error condition is raised
424 if tgen
.routers_have_failure():
425 pytest
.skip(tgen
.errors
)
427 tgen
.net
["rt7"].cmd('vtysh -c "graceful-restart prepare ip ospf"')
428 expect_grace_lsa(restarting
="7.7.7.7", area
="0.0.0.3", helper
="rt6")
429 ensure_gr_is_in_zebra("rt7")
430 kill_router_daemons(tgen
, "rt7", ["ospfd"], save_config
=False)
431 check_routers(exiting
="rt7")
433 start_router_daemons(tgen
, "rt7", ["ospfd"])
434 check_routers(restarting
="rt7")
437 # Memory leak test template
438 def test_memory_leak():
439 "Run the memory leak test and report results."
441 if not tgen
.is_memleak_enabled():
442 pytest
.skip("Memory leak test/report is disabled")
444 tgen
.report_memory_leaks()
447 if __name__
== "__main__":
448 args
= ["-s"] + sys
.argv
[1:]
449 sys
.exit(pytest
.main(args
))