]>
git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/ospf6_topo1/test_ospf6_topo1.py
5 # Part of NetDEF Topology Tests
7 # Copyright (c) 2016 by
8 # Network Device Education Foundation, Inc. ("NetDEF")
10 # Permission to use, copy, modify, and/or distribute this software
11 # for any purpose with or without fee is hereby granted, provided
12 # that the above copyright notice and this permission notice appear
15 # THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
16 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
18 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
19 # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
21 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
29 SW1 - Stub Net 1 SW2 - Stub Net 2 \
30 fc00:1:1:1::/64 fc00:2:2:2::/64 \
31 \___________________/ \___________________/ |
35 +---------+---------+ +---------+---------+ |
37 | FRRouting | | FRRouting | |
38 | Rtr-ID: 10.0.0.1 | | Rtr-ID: 10.0.0.2 | |
39 +---------+---------+ +---------+---------+ |
41 \______ ___________/ OSPFv3
47 ~~ fc00:A:A:A::/64 ~~ |
50 | ::3 | SW3 - Stub Net 3 |
51 +---------+---------+ /-+ fc00:3:3:3::/64 |
53 | FRRouting +--/ \---- /
54 | Rtr-ID: 10.0.0.3 | ::3 ___________/
55 +---------+---------+ \
61 ~~ fc00:B:B:B::/64 ~~ \
62 ~~~~~~~~~~~~~~~~~~ OSPFv3
65 +---------+---------+ /---- |
66 | R4 | | SW4 - Stub Net 4 |
67 | FRRouting +------+ fc00:4:4:4::/64 |
68 | Rtr-ID: 10.0.0.4 | ::4 | /
69 +-------------------+ \---- /
78 from functools
import partial
81 # Save the Current Working Directory to find configuration files later.
82 CWD
= os
.path
.dirname(os
.path
.realpath(__file__
))
83 sys
.path
.append(os
.path
.join(CWD
, "../"))
85 # pylint: disable=C0413
86 # Import topogen and topotest helpers
87 from lib
import topotest
88 from lib
.topogen
import Topogen
, TopoRouter
, get_topogen
89 from lib
.topolog
import logger
92 pytestmark
= [pytest
.mark
.ospfd
]
97 for routern
in range(1, 5):
98 tgen
.add_router("r{}".format(routern
))
101 # Wire up the switches and routers
102 # Note that we specify the link names so we match the config files
105 # Create a empty network for router 1
106 switch
= tgen
.add_switch("s1")
107 switch
.add_link(tgen
.gears
["r1"], nodeif
="r1-stubnet")
109 # Create a empty network for router 2
110 switch
= tgen
.add_switch("s2")
111 switch
.add_link(tgen
.gears
["r2"], nodeif
="r2-stubnet")
113 # Create a empty network for router 3
114 switch
= tgen
.add_switch("s3")
115 switch
.add_link(tgen
.gears
["r3"], nodeif
="r3-stubnet")
117 # Create a empty network for router 4
118 switch
= tgen
.add_switch("s4")
119 switch
.add_link(tgen
.gears
["r4"], nodeif
="r4-stubnet")
121 # Interconnect routers 1, 2, and 3
122 switch
= tgen
.add_switch("s5")
123 switch
.add_link(tgen
.gears
["r1"], nodeif
="r1-sw5")
124 switch
.add_link(tgen
.gears
["r2"], nodeif
="r2-sw5")
125 switch
.add_link(tgen
.gears
["r3"], nodeif
="r3-sw5")
127 # Interconnect routers 3 and 4
128 switch
= tgen
.add_switch("s6")
129 switch
.add_link(tgen
.gears
["r3"], nodeif
="r3-sw6")
130 switch
.add_link(tgen
.gears
["r4"], nodeif
="r4-sw6")
133 #####################################################
137 #####################################################
140 def setup_module(mod
):
141 "Sets up the pytest environment"
143 tgen
= Topogen(build_topo
, mod
.__name
__)
144 tgen
.start_topology()
146 logger
.info("** %s: Setup Topology" % mod
.__name
__)
147 logger
.info("******************************************")
149 # For debugging after starting net, but before starting FRR,
150 # uncomment the next line
153 router_list
= tgen
.routers()
154 for rname
, router
in router_list
.items():
156 TopoRouter
.RD_ZEBRA
, os
.path
.join(CWD
, "{}/zebra.conf".format(rname
))
159 TopoRouter
.RD_OSPF6
, os
.path
.join(CWD
, "{}/ospf6d.conf".format(rname
))
162 # Initialize all routers.
165 # For debugging after starting FRR daemons, uncomment the next line
169 def teardown_module(mod
):
170 "Teardown the pytest environment"
175 def test_wait_protocol_convergence():
176 "Wait for OSPFv3 to converge"
178 if tgen
.routers_have_failure():
179 pytest
.skip(tgen
.errors
)
181 logger
.info("waiting for protocols to converge")
183 def expect_neighbor_full(router
, neighbor
):
184 "Wait until OSPFv3 convergence."
185 logger
.info("waiting OSPFv3 router '{}'".format(router
))
187 topotest
.router_json_cmp
,
189 "show ipv6 ospf6 neighbor json",
190 {"neighbors": [{"neighborId": neighbor
, "state": "Full"}]},
192 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
193 assertmsg
= '"{}" convergence failure'.format(router
)
194 assert result
is None, assertmsg
196 expect_neighbor_full("r1", "10.0.0.2")
197 expect_neighbor_full("r1", "10.0.0.3")
199 expect_neighbor_full("r2", "10.0.0.1")
200 expect_neighbor_full("r2", "10.0.0.3")
202 expect_neighbor_full("r3", "10.0.0.1")
203 expect_neighbor_full("r3", "10.0.0.2")
204 expect_neighbor_full("r3", "10.0.0.4")
206 expect_neighbor_full("r4", "10.0.0.3")
209 def compare_show_ipv6(rname
, expected
):
211 Calls 'show ipv6 route' for router `rname` and compare the obtained
212 result with the expected output.
216 # Use the vtysh output, with some masking to make comparison easy
217 current
= topotest
.ip6_route_zebra(tgen
.gears
[rname
])
219 # Use just the 'O'spf lines of the output
221 for line
in current
.splitlines():
222 if re
.match("^O", line
):
225 current
= "\n".join(linearr
)
227 return topotest
.difflines(
228 topotest
.normalize_text(current
),
229 topotest
.normalize_text(expected
),
230 title1
="Current output",
231 title2
="Expected output",
235 def test_ospfv3_routingTable():
238 if tgen
.routers_have_failure():
239 pytest
.skip("skipped because of router(s) failure")
241 # For debugging, uncomment the next line
244 # Verify OSPFv3 Routing Table
245 for router
, rnode
in tgen
.routers().items():
246 logger
.info('Waiting for router "%s" convergence', router
)
248 # Load expected results from the command
249 reffile
= os
.path
.join(CWD
, "{}/show_ipv6_route.ref".format(router
))
250 expected
= open(reffile
).read()
252 # Run test function until we get an result. Wait at most 60 seconds.
253 test_func
= partial(compare_show_ipv6
, router
, expected
)
254 result
, diff
= topotest
.run_and_expect(test_func
, "", count
=120, wait
=0.5)
255 assert result
, "OSPFv3 did not converge on {}:\n{}".format(router
, diff
)
258 def test_linux_ipv6_kernel_routingTable():
262 if tgen
.routers_have_failure():
263 pytest
.skip("skipped because of router(s) failure")
265 # Verify Linux Kernel Routing Table
266 logger
.info("Verifying Linux IPv6 Kernel Routing Table")
270 # Get a list of all current link-local addresses first as they change for
271 # each run and we need to translate them
273 for i
in range(1, 5):
274 linklocals
+= tgen
.net
["r{}".format(i
)].get_ipv6_linklocal()
276 # Now compare the routing tables (after substituting link-local addresses)
278 for i
in range(1, 5):
279 # Actual output from router
280 actual
= tgen
.gears
["r{}".format(i
)].run("ip -6 route").rstrip()
282 refTableFile
= os
.path
.join(CWD
, "r{}/ip_6_address.nhg.ref".format(i
))
284 refTableFile
= os
.path
.join(CWD
, "r{}/ip_6_address.ref".format(i
))
286 if os
.path
.isfile(refTableFile
):
287 expected
= open(refTableFile
).read().rstrip()
288 # Fix newlines (make them all the same)
289 expected
= ("\n".join(expected
.splitlines())).splitlines(1)
291 # Mask out Link-Local mac addresses
292 for ll
in linklocals
:
293 actual
= actual
.replace(ll
[1], "fe80::__(%s)__" % ll
[0])
294 # Mask out protocol name or number
295 actual
= re
.sub(r
"[ ]+proto [0-9a-z]+ +", " proto XXXX ", actual
)
296 actual
= re
.sub(r
"[ ]+nhid [0-9]+ +", " nhid XXXX ", actual
)
297 # Remove ff00::/8 routes (seen on some kernels - not from FRR)
298 actual
= re
.sub(r
"ff00::/8.*", "", actual
)
301 actual
= actual
.lstrip()
302 actual
= actual
.rstrip()
303 actual
= re
.sub(r
" +", " ", actual
)
306 for line
in sorted(actual
.splitlines()):
307 if line
.startswith("fe80::/64 ") or line
.startswith(
308 "unreachable fe80::/64 "
311 filtered_lines
.append(line
)
312 actual
= "\n".join(filtered_lines
).splitlines(1)
315 # logger.info("Router r%s table" % i)
316 # for line in actual:
317 # logger.info(line.rstrip())
320 diff
= topotest
.get_textdiff(
323 title1
="actual OSPFv3 IPv6 routing table",
324 title2
="expected OSPFv3 IPv6 routing table",
327 # Empty string if it matches, otherwise diff contains unified diff
330 "r%s failed Linux IPv6 Kernel Routing Table Check:\n%s\n"
335 logger
.info("r%s ok" % i
)
337 assert failures
== 0, (
338 "Linux Kernel IPv6 Routing Table verification failed for router r%s:\n%s"
342 logger
.error("r{} failed - no nhid ref file: {}".format(i
, refTableFile
))
345 "Linux Kernel IPv6 Routing Table verification failed for router r%s\n"
350 def test_ospfv3_routingTable_write_multiplier():
353 if tgen
.routers_have_failure():
354 pytest
.skip("skipped because of router(s) failure")
356 # For debugging, uncomment the next line
359 # Modify R1 write muliplier and reset the interfaces
360 r1
= tgen
.gears
["r1"]
362 r1
.vtysh_cmd("conf t\nrouter ospf6\n write-multiplier 100")
363 r1
.vtysh_cmd("clear ipv6 ospf interface r1-stubnet")
364 r1
.vtysh_cmd("clear ipv6 ospf interface r1-sw5")
366 # Verify OSPFv3 Routing Table
367 for router
, rnode
in tgen
.routers().items():
368 logger
.info('Waiting for router "%s" convergence', router
)
370 # Load expected results from the command
371 reffile
= os
.path
.join(CWD
, "{}/show_ipv6_route.ref".format(router
))
372 expected
= open(reffile
).read()
374 # Run test function until we get an result. Wait at most 60 seconds.
375 test_func
= partial(compare_show_ipv6
, router
, expected
)
376 result
, diff
= topotest
.run_and_expect(test_func
, "", count
=120, wait
=0.5)
377 assert result
, "OSPFv3 did not converge on {}:\n{}".format(router
, diff
)
380 def test_shutdown_check_stderr():
384 if tgen
.routers_have_failure():
385 pytest
.skip("skipped because of router(s) failure")
387 if os
.environ
.get("TOPOTESTS_CHECK_STDERR") is None:
389 "SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n"
391 pytest
.skip("Skipping test for Stderr output")
395 logger
.info("\n\n** Verifying unexpected STDERR output from daemons")
396 logger
.info("******************************************")
398 for i
in range(1, 5):
399 net
["r%s" % i
].stopRouter()
400 log
= net
["r%s" % i
].getStdErr("ospf6d")
402 logger
.info("\nRouter r%s OSPF6d StdErr Log:\n%s" % (i
, log
))
403 log
= net
["r%s" % i
].getStdErr("zebra")
405 logger
.info("\nRouter r%s Zebra StdErr Log:\n%s" % (i
, log
))
408 def test_shutdown_check_memleak():
409 "Run the memory leak test and report results."
411 if os
.environ
.get("TOPOTESTS_CHECK_MEMLEAK") is None:
413 "SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)"
415 pytest
.skip("Skipping test for memory leaks")
421 for i
in range(1, 5):
422 net
["r%s" % i
].stopRouter()
423 net
["r%s" % i
].report_memory_leaks(
424 os
.environ
.get("TOPOTESTS_CHECK_MEMLEAK"), os
.path
.basename(__file__
)
428 if __name__
== "__main__":
430 # To suppress tracebacks, either use the following pytest call or
431 # add "--tb=no" to cli
432 # retval = pytest.main(["-s", "--tb=no"])
434 retval
= pytest
.main(["-s"])