]>
git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/ospf6_topo2/test_ospf6_topo2.py
5 # Part of NetDEF Topology Tests
7 # Copyright (c) 2021 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
26 test_ospf6_topo2.py: Test the FRR OSPFv3 daemon.
31 from functools
import partial
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
, "../"))
38 # pylint: disable=C0413
39 # Import topogen and topotest helpers
40 from lib
import topotest
41 from lib
.topogen
import Topogen
, TopoRouter
, get_topogen
42 from lib
.topolog
import logger
44 # Required to instantiate the topology builder class.
46 pytestmark
= [pytest
.mark
.ospf6d
]
49 def expect_lsas(router
, area
, lsas
, wait
=5, extra_params
=""):
51 Run the OSPFv3 show LSA database command and expect the supplied LSAs.
54 * `wait`: amount of seconds to wait.
55 * `extra_params`: extra LSA database parameters.
56 * `inverse`: assert the inverse of the expected.
60 command
= "show ipv6 ospf6 database {} json".format(extra_params
)
62 logger
.info("waiting OSPFv3 router '{}' LSA".format(router
))
64 topotest
.router_json_cmp
,
67 {"areaScopedLinkStateDb": [{"areaId": area
, "lsa": lsas
}]},
69 _
, result
= topotest
.run_and_expect(test_func
, None, count
=wait
, wait
=1)
70 assertmsg
= '"{}" convergence failure'.format(router
)
72 assert result
is None, assertmsg
75 def expect_ospfv3_routes(router
, routes
, wait
=5, type=None, detail
=False):
76 "Run command `ipv6 ospf6 route` and expect route with type."
81 cmd
= "show ipv6 ospf6 route json"
83 cmd
= "show ipv6 ospf6 route {} json".format(type)
86 cmd
= "show ipv6 ospf6 route detail json"
88 cmd
= "show ipv6 ospf6 route {} detail json".format(type)
90 logger
.info("waiting OSPFv3 router '{}' route".format(router
))
92 topotest
.router_json_cmp
, tgen
.gears
[router
], cmd
, {"routes": routes
}
94 _
, result
= topotest
.run_and_expect(test_func
, None, count
=wait
, wait
=1)
95 assertmsg
= '"{}" convergence failure'.format(router
)
97 assert result
is None, assertmsg
100 def dont_expect_route(router
, unexpected_route
, type=None):
101 "Specialized test function to expect route go missing"
105 cmd
= "show ipv6 ospf6 route json"
107 cmd
= "show ipv6 ospf6 route {} json".format(type)
109 output
= tgen
.gears
[router
].vtysh_cmd(cmd
, isjson
=True)
110 if unexpected_route
in output
["routes"]:
111 return output
["routes"][unexpected_route
]
115 def build_topo(tgen
):
119 for routern
in range(1, 5):
120 tgen
.add_router("r{}".format(routern
))
122 switch
= tgen
.add_switch("s1")
123 switch
.add_link(tgen
.gears
["r1"])
124 switch
.add_link(tgen
.gears
["r2"])
126 switch
= tgen
.add_switch("s2")
127 switch
.add_link(tgen
.gears
["r2"])
128 switch
.add_link(tgen
.gears
["r3"])
130 switch
= tgen
.add_switch("s3")
131 switch
.add_link(tgen
.gears
["r2"])
132 switch
.add_link(tgen
.gears
["r4"])
134 switch
= tgen
.add_switch("s4")
135 switch
.add_link(tgen
.gears
["r4"], nodeif
="r4-stubnet")
138 def setup_module(mod
):
139 "Sets up the pytest environment"
140 tgen
= Topogen(build_topo
, mod
.__name
__)
141 tgen
.start_topology()
143 router_list
= tgen
.routers()
144 for rname
, router
in router_list
.items():
145 daemon_file
= "{}/{}/zebra.conf".format(CWD
, rname
)
146 if os
.path
.isfile(daemon_file
):
147 router
.load_config(TopoRouter
.RD_ZEBRA
, daemon_file
)
149 daemon_file
= "{}/{}/ospf6d.conf".format(CWD
, rname
)
150 if os
.path
.isfile(daemon_file
):
151 router
.load_config(TopoRouter
.RD_OSPF6
, daemon_file
)
153 # Initialize all routers.
157 def test_wait_protocol_convergence():
158 "Wait for OSPFv3 to converge"
160 if tgen
.routers_have_failure():
161 pytest
.skip(tgen
.errors
)
163 logger
.info("waiting for protocols to converge")
165 def expect_neighbor_full(router
, neighbor
):
166 "Wait until OSPFv3 convergence."
167 logger
.info("waiting OSPFv3 router '{}'".format(router
))
169 topotest
.router_json_cmp
,
171 "show ipv6 ospf6 neighbor json",
172 {"neighbors": [{"neighborId": neighbor
, "state": "Full"}]},
174 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
175 assertmsg
= '"{}" convergence failure'.format(router
)
176 assert result
is None, assertmsg
178 expect_neighbor_full("r1", "10.254.254.2")
179 expect_neighbor_full("r2", "10.254.254.1")
180 expect_neighbor_full("r2", "10.254.254.3")
181 expect_neighbor_full("r2", "10.254.254.4")
182 expect_neighbor_full("r3", "10.254.254.2")
183 expect_neighbor_full("r4", "10.254.254.2")
186 def test_ospfv3_expected_route_types():
187 "Test routers route type to determine if NSSA/Stub is working as expected."
189 if tgen
.routers_have_failure():
190 pytest
.skip(tgen
.errors
)
192 logger
.info("waiting for protocols to converge")
194 def expect_ospf6_route_types(router
, expected_summary
):
195 "Expect the correct route types."
196 logger
.info("waiting OSPFv3 router '{}'".format(router
))
198 topotest
.router_json_cmp
,
200 "show ipv6 ospf6 route summary json",
203 _
, result
= topotest
.run_and_expect(test_func
, None, count
=10, wait
=1)
204 assertmsg
= '"{}" convergence failure'.format(router
)
205 assert result
is None, assertmsg
207 # Stub router: no external routes.
208 expect_ospf6_route_types(
211 "numberOfIntraAreaRoutes": 1,
212 "numberOfInterAreaRoutes": 3,
213 "numberOfExternal1Routes": 0,
214 "numberOfExternal2Routes": 0,
217 # NSSA router: no external routes.
218 expect_ospf6_route_types(
221 "numberOfIntraAreaRoutes": 1,
222 "numberOfInterAreaRoutes": 2,
223 "numberOfExternal1Routes": 0,
224 "numberOfExternal2Routes": 3,
229 def test_ospf6_default_route():
230 "Wait for OSPFv3 default route in stub area."
232 if tgen
.routers_have_failure():
233 pytest
.skip(tgen
.errors
)
235 logger
.info("waiting for default route")
237 def expect_route(router
, route
, metric
):
238 "Test OSPF6 route existence."
239 logger
.info("waiting OSPFv3 router '{}' routes".format(router
))
241 topotest
.router_json_cmp
,
243 "show ipv6 route json",
244 {route
: [{"metric": metric
}]},
246 _
, result
= topotest
.run_and_expect(test_func
, None, count
=5, wait
=1)
247 assertmsg
= '"{}" convergence failure'.format(router
)
248 assert result
is None, assertmsg
254 [{"prefix": "::/0", "metric": metric
}],
255 extra_params
="inter-prefix detail",
257 expect_route("r1", "::/0", metric
+ 10)
260 def test_redistribute_metrics():
262 Test that the configured metrics are honored when a static route is
266 if tgen
.routers_have_failure():
267 pytest
.skip(tgen
.errors
)
269 # Add new static route on r3.
272 ipv6 route 2001:db8:500::/64 Null0
274 tgen
.gears
["r3"].vtysh_cmd(config
)
277 "2001:db8:500::/64": {
283 "Expecting AS-external route 2001:db8:500::/64 to show up with default metrics"
285 expect_ospfv3_routes("r2", route
, wait
=30, detail
=True)
287 # Change the metric of redistributed routes of the static type on r3.
291 redistribute static metric 50 metric-type 1
293 tgen
.gears
["r3"].vtysh_cmd(config
)
295 # Check if r3 reinstalled 2001:db8:500::/64 using the new metric type and value.
297 "2001:db8:500::/64": {
303 "Expecting AS-external route 2001:db8:500::/64 to show up with updated metric type and value"
305 expect_ospfv3_routes("r2", route
, wait
=30, detail
=True)
308 def test_nssa_lsa_type7():
310 Test that static route gets announced as external route when redistributed
311 and gets removed when redistribution stops.
314 if tgen
.routers_have_failure():
315 pytest
.skip(tgen
.errors
)
318 # Add new static route and check if it gets announced as LSA Type-7.
322 ipv6 route 2001:db8:100::/64 Null0
324 tgen
.gears
["r2"].vtysh_cmd(config
)
329 "advertisingRouter": "10.254.254.2",
330 "prefix": "2001:db8:100::/64",
331 "forwardingAddress": "2001:db8:3::1",
335 "2001:db8:100::/64": {
337 "nextHops": [{"nextHop": "::", "interfaceName": "r4-eth0"}],
341 logger
.info("Expecting LSA type-7 and OSPFv3 route 2001:db8:100::/64 to show up")
342 expect_lsas("r4", "0.0.0.2", lsas
, wait
=30, extra_params
="type-7 detail")
343 expect_ospfv3_routes("r4", route
, wait
=30)
346 # Remove static route and check for LSA Type-7 removal.
350 no ipv6 route 2001:db8:100::/64 Null0
352 tgen
.gears
["r2"].vtysh_cmd(config
)
354 def dont_expect_lsa(unexpected_lsa
):
355 "Specialized test function to expect LSA go missing"
356 output
= tgen
.gears
["r4"].vtysh_cmd(
357 "show ipv6 ospf6 database type-7 detail json", isjson
=True
359 for lsa
in output
["areaScopedLinkStateDb"][0]["lsa"]:
360 if lsa
["prefix"] == unexpected_lsa
["prefix"]:
361 if lsa
["forwardingAddress"] == unexpected_lsa
["forwardingAddress"]:
365 logger
.info("Expecting LSA type-7 and OSPFv3 route 2001:db8:100::/64 to go away")
367 # Test that LSA doesn't exist.
368 test_func
= partial(dont_expect_lsa
, lsas
[0])
369 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
370 assertmsg
= '"{}" LSA still exists'.format("r4")
371 assert result
is None, assertmsg
373 # Test that route doesn't exist.
374 test_func
= partial(dont_expect_route
, "r4", "2001:db8:100::/64")
375 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
376 assertmsg
= '"{}" route still exists'.format("r4")
377 assert result
is None, assertmsg
380 def test_nssa_no_summary():
383 * Type-3 inter-area routes should be removed when the NSSA no-summary option
385 * A type-3 inter-area default route should be originated into the NSSA area
386 when the no-summary option is configured;
387 * Once the no-summary option is unconfigured, all previously existing
388 Type-3 inter-area routes should be re-added, and the inter-area default
392 if tgen
.routers_have_failure():
393 pytest
.skip(tgen
.errors
)
396 # Configure area 1 as a NSSA totally stub area.
401 area 2 nssa no-summary
403 tgen
.gears
["r2"].vtysh_cmd(config
)
405 logger
.info("Expecting inter-area routes to be removed")
406 for route
in ["2001:db8:1::/64", "2001:db8:2::/64"]:
407 test_func
= partial(dont_expect_route
, "r4", route
, type="inter-area")
408 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
409 assertmsg
= "{}'s {} inter-area route still exists".format("r4", route
)
410 assert result
is None, assertmsg
412 logger
.info("Expecting inter-area default-route to be added")
413 routes
= {"::/0": {}}
414 expect_ospfv3_routes("r4", routes
, wait
=30, type="inter-area")
417 # Configure area 1 as a regular NSSA area.
424 tgen
.gears
["r2"].vtysh_cmd(config
)
426 logger
.info("Expecting inter-area routes to be re-added")
427 routes
= {"2001:db8:1::/64": {}, "2001:db8:2::/64": {}}
428 expect_ospfv3_routes("r4", routes
, wait
=30, type="inter-area")
430 logger
.info("Expecting inter-area default route to be removed")
431 test_func
= partial(dont_expect_route
, "r4", "::/0", type="inter-area")
432 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
433 assertmsg
= "{}'s inter-area default route still exists".format("r4")
434 assert result
is None, assertmsg
437 def test_nssa_default_originate():
440 * A type-7 default route should be originated into the NSSA area
441 when the default-information-originate option is configured;
442 * Once the default-information-originate option is unconfigured, the
443 previously originated Type-7 default route should be removed.
446 if tgen
.routers_have_failure():
447 pytest
.skip(tgen
.errors
)
450 # Configure r2 to announce a Type-7 default route.
455 no default-information originate
456 area 2 nssa default-information-originate
458 tgen
.gears
["r2"].vtysh_cmd(config
)
460 logger
.info("Expecting Type-7 default-route to be added")
461 routes
= {"::/0": {}}
462 expect_ospfv3_routes("r4", routes
, wait
=30, type="external-2")
465 # Configure r2 to stop announcing a Type-7 default route.
472 tgen
.gears
["r2"].vtysh_cmd(config
)
474 logger
.info("Expecting Type-7 default route to be removed")
475 test_func
= partial(dont_expect_route
, "r4", "::/0", type="external-2")
476 _
, result
= topotest
.run_and_expect(test_func
, None, count
=30, wait
=1)
477 assertmsg
= "r4's Type-7 default route still exists"
478 assert result
is None, assertmsg
481 def test_area_filters():
483 Test ABR import/export filters.
486 if tgen
.routers_have_failure():
487 pytest
.skip(tgen
.errors
)
490 # Configure import/export filters on r2 (ABR for area 2).
494 ipv6 access-list ACL_IMPORT seq 5 permit 2001:db8:2::/64
495 ipv6 access-list ACL_IMPORT seq 10 deny any
496 ipv6 access-list ACL_EXPORT seq 10 deny any
498 area 1 import-list ACL_IMPORT
499 area 1 export-list ACL_EXPORT
501 tgen
.gears
["r2"].vtysh_cmd(config
)
503 logger
.info("Expecting inter-area routes to be removed on r1")
504 for route
in ["::/0", "2001:db8:3::/64"]:
505 test_func
= partial(dont_expect_route
, "r1", route
, type="inter-area")
506 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
507 assertmsg
= "{}'s {} inter-area route still exists".format("r1", route
)
508 assert result
is None, assertmsg
510 logger
.info("Expecting inter-area routes to be removed on r3")
511 for route
in ["2001:db8:1::/64"]:
512 test_func
= partial(dont_expect_route
, "r3", route
, type="inter-area")
513 _
, result
= topotest
.run_and_expect(test_func
, None, count
=130, wait
=1)
514 assertmsg
= "{}'s {} inter-area route still exists".format("r3", route
)
515 assert result
is None, assertmsg
518 # Update the ACLs used by the import/export filters.
522 ipv6 access-list ACL_IMPORT seq 6 permit 2001:db8:3::/64
523 ipv6 access-list ACL_EXPORT seq 5 permit 2001:db8:1::/64
525 tgen
.gears
["r2"].vtysh_cmd(config
)
527 logger
.info("Expecting 2001:db8:3::/64 to be re-added on r1")
528 routes
= {"2001:db8:3::/64": {}}
529 expect_ospfv3_routes("r1", routes
, wait
=30, type="inter-area")
530 logger
.info("Expecting 2001:db8:1::/64 to be re-added on r3")
531 routes
= {"2001:db8:1::/64": {}}
532 expect_ospfv3_routes("r3", routes
, wait
=30, type="inter-area")
535 # Unconfigure r2's ABR import/export filters.
540 no area 1 import-list ACL_IMPORT
541 no area 1 export-list ACL_EXPORT
543 tgen
.gears
["r2"].vtysh_cmd(config
)
545 logger
.info("Expecting ::/0 to be re-added on r1")
546 routes
= {"::/0": {}}
547 expect_ospfv3_routes("r1", routes
, wait
=30, type="inter-area")
550 def test_nssa_range():
552 Test NSSA ABR ranges.
555 if tgen
.routers_have_failure():
556 pytest
.skip(tgen
.errors
)
558 # Configure new addresses on r4 and enable redistribution of connected
563 ipv6 address 2001:db8:1000::1/128
564 ipv6 address 2001:db8:1000::2/128
566 redistribute connected
568 tgen
.gears
["r4"].vtysh_cmd(config
)
569 logger
.info("Expecting NSSA-translated external routes to be added on r3")
570 routes
= {"2001:db8:1000::1/128": {}, "2001:db8:1000::2/128": {}}
571 expect_ospfv3_routes("r3", routes
, wait
=30, type="external-2")
573 # Configure an NSSA range on r2 (ABR for area 2).
577 area 2 nssa range 2001:db8:1000::/64
579 tgen
.gears
["r2"].vtysh_cmd(config
)
580 logger
.info("Expecting summarized routes to be removed from r3")
581 for route
in ["2001:db8:1000::1/128", "2001:db8:1000::2/128"]:
582 test_func
= partial(dont_expect_route
, "r3", route
, type="external-2")
583 _
, result
= topotest
.run_and_expect(test_func
, None, count
=30, wait
=1)
584 assertmsg
= "{}'s {} summarized route still exists".format("r3", route
)
585 assert result
is None, assertmsg
586 logger
.info("Expecting NSSA range to be added on r3")
588 "2001:db8:1000::/64": {
594 expect_ospfv3_routes("r3", routes
, wait
=30, type="external-2", detail
=True)
596 # Change the NSSA range cost.
600 area 2 nssa range 2001:db8:1000::/64 cost 1000
602 tgen
.gears
["r2"].vtysh_cmd(config
)
603 logger
.info("Expecting NSSA range to be updated with new cost")
605 "2001:db8:1000::/64": {
608 "metricCostE2": 1000,
611 expect_ospfv3_routes("r3", routes
, wait
=30, type="external-2", detail
=True)
613 # Configure the NSSA range to not be advertised.
617 area 2 nssa range 2001:db8:1000::/64 not-advertise
619 tgen
.gears
["r2"].vtysh_cmd(config
)
620 logger
.info("Expecting NSSA summary route to be removed")
621 route
= "2001:db8:1000::/64"
622 test_func
= partial(dont_expect_route
, "r3", route
, type="external-2")
623 _
, result
= topotest
.run_and_expect(test_func
, None, count
=30, wait
=1)
624 assertmsg
= "{}'s {} NSSA summary route still exists".format("r3", route
)
625 assert result
is None, assertmsg
627 # Remove the NSSA range.
631 no area 2 nssa range 2001:db8:1000::/64
633 tgen
.gears
["r2"].vtysh_cmd(config
)
634 logger
.info("Expecting previously summarized routes to be re-added")
636 "2001:db8:1000::1/128": {
640 "2001:db8:1000::2/128": {
645 expect_ospfv3_routes("r3", routes
, wait
=30, type="external-2", detail
=True)
648 def teardown_module(_mod
):
649 "Teardown the pytest environment"
654 def test_memory_leak():
655 "Run the memory leak test and report results."
657 if not tgen
.is_memleak_enabled():
658 pytest
.skip("Memory leak test/report is disabled")
660 tgen
.report_memory_leaks()
663 if __name__
== "__main__":
664 args
= ["-s"] + sys
.argv
[1:]
665 sys
.exit(pytest
.main(args
))