summaryrefslogtreecommitdiffstats
path: root/tests/topotests/ospf6_topo2
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tests/topotests/ospf6_topo2/r1/ospf6d.conf37
-rw-r--r--tests/topotests/ospf6_topo2/r1/zebra.conf5
-rw-r--r--tests/topotests/ospf6_topo2/r2/ospf6d.conf51
-rw-r--r--tests/topotests/ospf6_topo2/r2/zebra.conf11
-rw-r--r--tests/topotests/ospf6_topo2/r3/ospf6d.conf38
-rw-r--r--tests/topotests/ospf6_topo2/r3/zebra.conf8
-rw-r--r--tests/topotests/ospf6_topo2/r4/ospf6d.conf37
-rw-r--r--tests/topotests/ospf6_topo2/r4/zebra.conf5
-rw-r--r--tests/topotests/ospf6_topo2/test_ospf6_topo2.dot83
-rw-r--r--tests/topotests/ospf6_topo2/test_ospf6_topo2.pngbin0 -> 44388 bytes
-rw-r--r--tests/topotests/ospf6_topo2/test_ospf6_topo2.py665
11 files changed, 940 insertions, 0 deletions
diff --git a/tests/topotests/ospf6_topo2/r1/ospf6d.conf b/tests/topotests/ospf6_topo2/r1/ospf6d.conf
new file mode 100644
index 0000000..a9d46be
--- /dev/null
+++ b/tests/topotests/ospf6_topo2/r1/ospf6d.conf
@@ -0,0 +1,37 @@
+! debug ospf6 lsa router
+! debug ospf6 lsa router originate
+! debug ospf6 lsa router examine
+! debug ospf6 lsa router flooding
+! debug ospf6 lsa nssa
+! debug ospf6 lsa nssa originate
+! debug ospf6 lsa nssa examine
+! debug ospf6 lsa nssa flooding
+! debug ospf6 lsa as-external
+! debug ospf6 lsa as-external originate
+! debug ospf6 lsa as-external examine
+! debug ospf6 lsa as-external flooding
+! debug ospf6 lsa intra-prefix
+! debug ospf6 lsa intra-prefix originate
+! debug ospf6 lsa intra-prefix examine
+! debug ospf6 lsa intra-prefix flooding
+! debug ospf6 border-routers
+! debug ospf6 zebra
+! debug ospf6 interface
+! debug ospf6 neighbor
+! debug ospf6 flooding
+! debug ospf6 spf process
+! debug ospf6 route intra-area
+! debug ospf6 route inter-area
+! debug ospf6 abr
+! debug ospf6 asbr
+! debug ospf6 nssa
+!
+interface r1-eth0
+ ipv6 ospf6 area 0.0.0.1
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+router ospf6
+ ospf6 router-id 10.254.254.1
+ area 0.0.0.1 stub
+!
diff --git a/tests/topotests/ospf6_topo2/r1/zebra.conf b/tests/topotests/ospf6_topo2/r1/zebra.conf
new file mode 100644
index 0000000..7fee2da
--- /dev/null
+++ b/tests/topotests/ospf6_topo2/r1/zebra.conf
@@ -0,0 +1,5 @@
+ipv6 forwarding
+!
+interface r1-eth0
+ ipv6 address 2001:db8:1::2/64
+!
diff --git a/tests/topotests/ospf6_topo2/r2/ospf6d.conf b/tests/topotests/ospf6_topo2/r2/ospf6d.conf
new file mode 100644
index 0000000..8819a58
--- /dev/null
+++ b/tests/topotests/ospf6_topo2/r2/ospf6d.conf
@@ -0,0 +1,51 @@
+! debug ospf6 lsa router
+! debug ospf6 lsa router originate
+! debug ospf6 lsa router examine
+! debug ospf6 lsa router flooding
+! debug ospf6 lsa nssa
+! debug ospf6 lsa nssa originate
+! debug ospf6 lsa nssa examine
+! debug ospf6 lsa nssa flooding
+! debug ospf6 lsa as-external
+! debug ospf6 lsa as-external originate
+! debug ospf6 lsa as-external examine
+! debug ospf6 lsa as-external flooding
+! debug ospf6 lsa intra-prefix
+! debug ospf6 lsa intra-prefix originate
+! debug ospf6 lsa intra-prefix examine
+! debug ospf6 lsa intra-prefix flooding
+! debug ospf6 border-routers
+! debug ospf6 zebra
+! debug ospf6 interface
+! debug ospf6 neighbor
+! debug ospf6 flooding
+! debug ospf6 spf process
+! debug ospf6 route intra-area
+! debug ospf6 route inter-area
+! debug ospf6 abr
+! debug ospf6 asbr
+! debug ospf6 nssa
+!
+interface r2-eth0
+ ipv6 ospf6 area 0.0.0.1
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+interface r2-eth1
+ ipv6 ospf6 area 0.0.0.0
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+interface r2-eth2
+ ipv6 ospf6 area 0.0.0.2
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+router ospf6
+ ospf6 router-id 10.254.254.2
+ redistribute connected
+ redistribute static
+ default-information originate always metric 123
+ area 0.0.0.1 stub
+ area 0.0.0.2 nssa
+!
diff --git a/tests/topotests/ospf6_topo2/r2/zebra.conf b/tests/topotests/ospf6_topo2/r2/zebra.conf
new file mode 100644
index 0000000..559f502
--- /dev/null
+++ b/tests/topotests/ospf6_topo2/r2/zebra.conf
@@ -0,0 +1,11 @@
+ipv6 forwarding
+!
+interface r2-eth0
+ ipv6 address 2001:db8:1::1/64
+!
+interface r2-eth1
+ ipv6 address 2001:db8:2::2/64
+!
+interface r2-eth2
+ ipv6 address 2001:db8:3::1/64
+!
diff --git a/tests/topotests/ospf6_topo2/r3/ospf6d.conf b/tests/topotests/ospf6_topo2/r3/ospf6d.conf
new file mode 100644
index 0000000..6e4f56b
--- /dev/null
+++ b/tests/topotests/ospf6_topo2/r3/ospf6d.conf
@@ -0,0 +1,38 @@
+! debug ospf6 lsa router
+! debug ospf6 lsa router originate
+! debug ospf6 lsa router examine
+! debug ospf6 lsa router flooding
+! debug ospf6 lsa nssa
+! debug ospf6 lsa nssa originate
+! debug ospf6 lsa nssa examine
+! debug ospf6 lsa nssa flooding
+! debug ospf6 lsa as-external
+! debug ospf6 lsa as-external originate
+! debug ospf6 lsa as-external examine
+! debug ospf6 lsa as-external flooding
+! debug ospf6 lsa intra-prefix
+! debug ospf6 lsa intra-prefix originate
+! debug ospf6 lsa intra-prefix examine
+! debug ospf6 lsa intra-prefix flooding
+! debug ospf6 border-routers
+! debug ospf6 zebra
+! debug ospf6 interface
+! debug ospf6 neighbor
+! debug ospf6 flooding
+! debug ospf6 spf process
+! debug ospf6 route intra-area
+! debug ospf6 route inter-area
+! debug ospf6 abr
+! debug ospf6 asbr
+! debug ospf6 nssa
+!
+interface r3-eth0
+ ipv6 ospf6 area 0.0.0.0
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+router ospf6
+ ospf6 router-id 10.254.254.3
+ redistribute connected
+ redistribute static
+!
diff --git a/tests/topotests/ospf6_topo2/r3/zebra.conf b/tests/topotests/ospf6_topo2/r3/zebra.conf
new file mode 100644
index 0000000..dea2fe4
--- /dev/null
+++ b/tests/topotests/ospf6_topo2/r3/zebra.conf
@@ -0,0 +1,8 @@
+ipv6 forwarding
+!
+interface r3-eth0
+ ipv6 address 2001:db8:2::1/64
+!
+ipv6 route fc00:1::/64 fc00:100::1234
+ipv6 route fc00:2::/64 fc00:100::1234
+ipv6 route fc00:3::/64 fc00:100::1234
diff --git a/tests/topotests/ospf6_topo2/r4/ospf6d.conf b/tests/topotests/ospf6_topo2/r4/ospf6d.conf
new file mode 100644
index 0000000..59a2fd5
--- /dev/null
+++ b/tests/topotests/ospf6_topo2/r4/ospf6d.conf
@@ -0,0 +1,37 @@
+! debug ospf6 lsa router
+! debug ospf6 lsa router originate
+! debug ospf6 lsa router examine
+! debug ospf6 lsa router flooding
+! debug ospf6 lsa nssa
+! debug ospf6 lsa nssa originate
+! debug ospf6 lsa nssa examine
+! debug ospf6 lsa nssa flooding
+! debug ospf6 lsa as-external
+! debug ospf6 lsa as-external originate
+! debug ospf6 lsa as-external examine
+! debug ospf6 lsa as-external flooding
+! debug ospf6 lsa intra-prefix
+! debug ospf6 lsa intra-prefix originate
+! debug ospf6 lsa intra-prefix examine
+! debug ospf6 lsa intra-prefix flooding
+! debug ospf6 border-routers
+! debug ospf6 zebra
+! debug ospf6 interface
+! debug ospf6 neighbor
+! debug ospf6 flooding
+! debug ospf6 spf process
+! debug ospf6 route intra-area
+! debug ospf6 route inter-area
+! debug ospf6 abr
+! debug ospf6 asbr
+! debug ospf6 nssa
+!
+interface r4-eth0
+ ipv6 ospf6 area 0.0.0.2
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+router ospf6
+ ospf6 router-id 10.254.254.4
+ area 0.0.0.2 nssa
+!
diff --git a/tests/topotests/ospf6_topo2/r4/zebra.conf b/tests/topotests/ospf6_topo2/r4/zebra.conf
new file mode 100644
index 0000000..86cb972
--- /dev/null
+++ b/tests/topotests/ospf6_topo2/r4/zebra.conf
@@ -0,0 +1,5 @@
+ipv6 forwarding
+!
+interface r4-eth0
+ ipv6 address 2001:db8:3::2/64
+!
diff --git a/tests/topotests/ospf6_topo2/test_ospf6_topo2.dot b/tests/topotests/ospf6_topo2/test_ospf6_topo2.dot
new file mode 100644
index 0000000..238ec7a
--- /dev/null
+++ b/tests/topotests/ospf6_topo2/test_ospf6_topo2.dot
@@ -0,0 +1,83 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="ospf6-topo2";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ shape=doubleoctagon
+ label="r3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r4 [
+ shape=doubleoctagon
+ label="r4",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ sw1 [
+ shape=oval,
+ label="sw1\n2001:db8:1::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw2 [
+ shape=oval,
+ label="sw2\n2001:db8:2::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw3 [
+ shape=oval,
+ label="sw3\n2001:db8:3::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ subgraph cluster0 {
+ label="area 0.0.0.1";
+ r1 -- sw1 [label="eth0\n.2"];
+ }
+
+ subgraph cluster1 {
+ label="area 0.0.0.2";
+ r4 -- sw3 [label="eth0\n.2"];
+ }
+
+ subgraph cluster2 {
+ label="area 0.0.0.0";
+ r2 -- sw1 [label="eth0\n.1"];
+ r2 -- sw2 [label="eth1\n.2"];
+ r2 -- sw3 [label="eth2\n.1"];
+
+ r3 -- sw2 [label="eth0\n.1"];
+ }
+}
diff --git a/tests/topotests/ospf6_topo2/test_ospf6_topo2.png b/tests/topotests/ospf6_topo2/test_ospf6_topo2.png
new file mode 100644
index 0000000..4e79559
--- /dev/null
+++ b/tests/topotests/ospf6_topo2/test_ospf6_topo2.png
Binary files differ
diff --git a/tests/topotests/ospf6_topo2/test_ospf6_topo2.py b/tests/topotests/ospf6_topo2/test_ospf6_topo2.py
new file mode 100644
index 0000000..d17aeda
--- /dev/null
+++ b/tests/topotests/ospf6_topo2/test_ospf6_topo2.py
@@ -0,0 +1,665 @@
+#!/usr/bin/env python
+
+#
+# test_ospf6_topo2.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2021 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_ospf6_topo2.py: Test the FRR OSPFv3 daemon.
+"""
+
+import os
+import sys
+from functools import partial
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+
+pytestmark = [pytest.mark.ospf6d]
+
+
+def expect_lsas(router, area, lsas, wait=5, extra_params=""):
+ """
+ Run the OSPFv3 show LSA database command and expect the supplied LSAs.
+
+ Optional parameters:
+ * `wait`: amount of seconds to wait.
+ * `extra_params`: extra LSA database parameters.
+ * `inverse`: assert the inverse of the expected.
+ """
+ tgen = get_topogen()
+
+ command = "show ipv6 ospf6 database {} json".format(extra_params)
+
+ logger.info("waiting OSPFv3 router '{}' LSA".format(router))
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ command,
+ {"areaScopedLinkStateDb": [{"areaId": area, "lsa": lsas}]},
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=wait, wait=1)
+ assertmsg = '"{}" convergence failure'.format(router)
+
+ assert result is None, assertmsg
+
+
+def expect_ospfv3_routes(router, routes, wait=5, type=None, detail=False):
+ "Run command `ipv6 ospf6 route` and expect route with type."
+ tgen = get_topogen()
+
+ if detail == False:
+ if type == None:
+ cmd = "show ipv6 ospf6 route json"
+ else:
+ cmd = "show ipv6 ospf6 route {} json".format(type)
+ else:
+ if type == None:
+ cmd = "show ipv6 ospf6 route detail json"
+ else:
+ cmd = "show ipv6 ospf6 route {} detail json".format(type)
+
+ logger.info("waiting OSPFv3 router '{}' route".format(router))
+ test_func = partial(
+ topotest.router_json_cmp, tgen.gears[router], cmd, {"routes": routes}
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=wait, wait=1)
+ assertmsg = '"{}" convergence failure'.format(router)
+
+ assert result is None, assertmsg
+
+
+def dont_expect_route(router, unexpected_route, type=None):
+ "Specialized test function to expect route go missing"
+ tgen = get_topogen()
+
+ if type == None:
+ cmd = "show ipv6 ospf6 route json"
+ else:
+ cmd = "show ipv6 ospf6 route {} json".format(type)
+
+ output = tgen.gears[router].vtysh_cmd(cmd, isjson=True)
+ if unexpected_route in output["routes"]:
+ return output["routes"][unexpected_route]
+ return None
+
+
+def build_topo(tgen):
+ "Build function"
+
+ # Create 4 routers
+ for routern in range(1, 5):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r4"])
+
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["r4"], nodeif="r4-stubnet")
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ daemon_file = "{}/{}/zebra.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_ZEBRA, daemon_file)
+
+ daemon_file = "{}/{}/ospf6d.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_OSPF6, daemon_file)
+
+ # Initialize all routers.
+ tgen.start_router()
+
+
+def test_wait_protocol_convergence():
+ "Wait for OSPFv3 to converge"
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for protocols to converge")
+
+ def expect_neighbor_full(router, neighbor):
+ "Wait until OSPFv3 convergence."
+ logger.info("waiting OSPFv3 router '{}'".format(router))
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ "show ipv6 ospf6 neighbor json",
+ {"neighbors": [{"neighborId": neighbor, "state": "Full"}]},
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+ assertmsg = '"{}" convergence failure'.format(router)
+ assert result is None, assertmsg
+
+ expect_neighbor_full("r1", "10.254.254.2")
+ expect_neighbor_full("r2", "10.254.254.1")
+ expect_neighbor_full("r2", "10.254.254.3")
+ expect_neighbor_full("r2", "10.254.254.4")
+ expect_neighbor_full("r3", "10.254.254.2")
+ expect_neighbor_full("r4", "10.254.254.2")
+
+
+def test_ospfv3_expected_route_types():
+ "Test routers route type to determine if NSSA/Stub is working as expected."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for protocols to converge")
+
+ def expect_ospf6_route_types(router, expected_summary):
+ "Expect the correct route types."
+ logger.info("waiting OSPFv3 router '{}'".format(router))
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ "show ipv6 ospf6 route summary json",
+ expected_summary,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=10, wait=1)
+ assertmsg = '"{}" convergence failure'.format(router)
+ assert result is None, assertmsg
+
+ # Stub router: no external routes.
+ expect_ospf6_route_types(
+ "r1",
+ {
+ "numberOfIntraAreaRoutes": 1,
+ "numberOfInterAreaRoutes": 3,
+ "numberOfExternal1Routes": 0,
+ "numberOfExternal2Routes": 0,
+ },
+ )
+ # NSSA router: no external routes.
+ expect_ospf6_route_types(
+ "r4",
+ {
+ "numberOfIntraAreaRoutes": 1,
+ "numberOfInterAreaRoutes": 2,
+ "numberOfExternal1Routes": 0,
+ "numberOfExternal2Routes": 3,
+ },
+ )
+
+
+def test_ospf6_default_route():
+ "Wait for OSPFv3 default route in stub area."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for default route")
+
+ def expect_route(router, route, metric):
+ "Test OSPF6 route existence."
+ logger.info("waiting OSPFv3 router '{}' routes".format(router))
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ "show ipv6 route json",
+ {route: [{"metric": metric}]},
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=4, wait=1)
+ assertmsg = '"{}" convergence failure'.format(router)
+ assert result is None, assertmsg
+
+ metric = 123
+ expect_lsas(
+ "r1",
+ "0.0.0.1",
+ [{"prefix": "::/0", "metric": metric}],
+ extra_params="inter-prefix detail",
+ )
+ expect_route("r1", "::/0", metric + 10)
+
+
+def test_redistribute_metrics():
+ """
+ Test that the configured metrics are honored when a static route is
+ redistributed.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Add new static route on r3.
+ config = """
+ configure terminal
+ ipv6 route 2001:db8:500::/64 Null0
+ """
+ tgen.gears["r3"].vtysh_cmd(config)
+
+ route = {
+ "2001:db8:500::/64": {
+ "metricType": 2,
+ "metricCost": 10,
+ }
+ }
+ logger.info(
+ "Expecting AS-external route 2001:db8:500::/64 to show up with default metrics"
+ )
+ expect_ospfv3_routes("r2", route, wait=30, detail=True)
+
+ # Change the metric of redistributed routes of the static type on r3.
+ config = """
+ configure terminal
+ router ospf6
+ redistribute static metric 50 metric-type 1
+ """
+ tgen.gears["r3"].vtysh_cmd(config)
+
+ # Check if r3 reinstalled 2001:db8:500::/64 using the new metric type and value.
+ route = {
+ "2001:db8:500::/64": {
+ "metricType": 1,
+ "metricCost": 60,
+ }
+ }
+ logger.info(
+ "Expecting AS-external route 2001:db8:500::/64 to show up with updated metric type and value"
+ )
+ expect_ospfv3_routes("r2", route, wait=30, detail=True)
+
+
+def test_nssa_lsa_type7():
+ """
+ Test that static route gets announced as external route when redistributed
+ and gets removed when redistribution stops.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ #
+ # Add new static route and check if it gets announced as LSA Type-7.
+ #
+ config = """
+ configure terminal
+ ipv6 route 2001:db8:100::/64 Null0
+ """
+ tgen.gears["r2"].vtysh_cmd(config)
+
+ lsas = [
+ {
+ "type": "NSSA",
+ "advertisingRouter": "10.254.254.2",
+ "prefix": "2001:db8:100::/64",
+ "forwardingAddress": "2001:db8:3::1",
+ }
+ ]
+ route = {
+ "2001:db8:100::/64": {
+ "pathType": "E2",
+ "nextHops": [{"nextHop": "::", "interfaceName": "r4-eth0"}],
+ }
+ }
+
+ logger.info("Expecting LSA type-7 and OSPFv3 route 2001:db8:100::/64 to show up")
+ expect_lsas("r4", "0.0.0.2", lsas, wait=30, extra_params="type-7 detail")
+ expect_ospfv3_routes("r4", route, wait=30)
+
+ #
+ # Remove static route and check for LSA Type-7 removal.
+ #
+ config = """
+ configure terminal
+ no ipv6 route 2001:db8:100::/64 Null0
+ """
+ tgen.gears["r2"].vtysh_cmd(config)
+
+ def dont_expect_lsa(unexpected_lsa):
+ "Specialized test function to expect LSA go missing"
+ output = tgen.gears["r4"].vtysh_cmd(
+ "show ipv6 ospf6 database type-7 detail json", isjson=True
+ )
+ for lsa in output["areaScopedLinkStateDb"][0]["lsa"]:
+ if lsa["prefix"] == unexpected_lsa["prefix"]:
+ if lsa["forwardingAddress"] == unexpected_lsa["forwardingAddress"]:
+ return lsa
+ return None
+
+ logger.info("Expecting LSA type-7 and OSPFv3 route 2001:db8:100::/64 to go away")
+
+ # Test that LSA doesn't exist.
+ test_func = partial(dont_expect_lsa, lsas[0])
+ _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+ assertmsg = '"{}" LSA still exists'.format("r4")
+ assert result is None, assertmsg
+
+ # Test that route doesn't exist.
+ test_func = partial(dont_expect_route, "r4", "2001:db8:100::/64")
+ _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+ assertmsg = '"{}" route still exists'.format("r4")
+ assert result is None, assertmsg
+
+
+def test_nssa_no_summary():
+ """
+ Test the following:
+ * Type-3 inter-area routes should be removed when the NSSA no-summary option
+ is configured;
+ * A type-3 inter-area default route should be originated into the NSSA area
+ when the no-summary option is configured;
+ * Once the no-summary option is unconfigured, all previously existing
+ Type-3 inter-area routes should be re-added, and the inter-area default
+ route removed.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ #
+ # Configure area 1 as a NSSA totally stub area.
+ #
+ config = """
+ configure terminal
+ router ospf6
+ area 2 nssa no-summary
+ """
+ tgen.gears["r2"].vtysh_cmd(config)
+
+ logger.info("Expecting inter-area routes to be removed")
+ for route in ["2001:db8:1::/64", "2001:db8:2::/64"]:
+ test_func = partial(dont_expect_route, "r4", route, type="inter-area")
+ _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+ assertmsg = "{}'s {} inter-area route still exists".format("r4", route)
+ assert result is None, assertmsg
+
+ logger.info("Expecting inter-area default-route to be added")
+ routes = {"::/0": {}}
+ expect_ospfv3_routes("r4", routes, wait=30, type="inter-area")
+
+ #
+ # Configure area 1 as a regular NSSA area.
+ #
+ config = """
+ configure terminal
+ router ospf6
+ area 2 nssa
+ """
+ tgen.gears["r2"].vtysh_cmd(config)
+
+ logger.info("Expecting inter-area routes to be re-added")
+ routes = {"2001:db8:1::/64": {}, "2001:db8:2::/64": {}}
+ expect_ospfv3_routes("r4", routes, wait=30, type="inter-area")
+
+ logger.info("Expecting inter-area default route to be removed")
+ test_func = partial(dont_expect_route, "r4", "::/0", type="inter-area")
+ _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+ assertmsg = "{}'s inter-area default route still exists".format("r4")
+ assert result is None, assertmsg
+
+
+def test_nssa_default_originate():
+ """
+ Test the following:
+ * A type-7 default route should be originated into the NSSA area
+ when the default-information-originate option is configured;
+ * Once the default-information-originate option is unconfigured, the
+ previously originated Type-7 default route should be removed.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ #
+ # Configure r2 to announce a Type-7 default route.
+ #
+ config = """
+ configure terminal
+ router ospf6
+ no default-information originate
+ area 2 nssa default-information-originate
+ """
+ tgen.gears["r2"].vtysh_cmd(config)
+
+ logger.info("Expecting Type-7 default-route to be added")
+ routes = {"::/0": {}}
+ expect_ospfv3_routes("r4", routes, wait=30, type="external-2")
+
+ #
+ # Configure r2 to stop announcing a Type-7 default route.
+ #
+ config = """
+ configure terminal
+ router ospf6
+ area 2 nssa
+ """
+ tgen.gears["r2"].vtysh_cmd(config)
+
+ logger.info("Expecting Type-7 default route to be removed")
+ test_func = partial(dont_expect_route, "r4", "::/0", type="external-2")
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = "r4's Type-7 default route still exists"
+ assert result is None, assertmsg
+
+
+def test_area_filters():
+ """
+ Test ABR import/export filters.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ #
+ # Configure import/export filters on r2 (ABR for area 2).
+ #
+ config = """
+ configure terminal
+ ipv6 access-list ACL_IMPORT seq 5 permit 2001:db8:2::/64
+ ipv6 access-list ACL_IMPORT seq 10 deny any
+ ipv6 access-list ACL_EXPORT seq 10 deny any
+ router ospf6
+ area 1 import-list ACL_IMPORT
+ area 1 export-list ACL_EXPORT
+ """
+ tgen.gears["r2"].vtysh_cmd(config)
+
+ logger.info("Expecting inter-area routes to be removed on r1")
+ for route in ["::/0", "2001:db8:3::/64"]:
+ test_func = partial(dont_expect_route, "r1", route, type="inter-area")
+ _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+ assertmsg = "{}'s {} inter-area route still exists".format("r1", route)
+ assert result is None, assertmsg
+
+ logger.info("Expecting inter-area routes to be removed on r3")
+ for route in ["2001:db8:1::/64"]:
+ test_func = partial(dont_expect_route, "r3", route, type="inter-area")
+ _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+ assertmsg = "{}'s {} inter-area route still exists".format("r3", route)
+ assert result is None, assertmsg
+
+ #
+ # Update the ACLs used by the import/export filters.
+ #
+ config = """
+ configure terminal
+ ipv6 access-list ACL_IMPORT seq 6 permit 2001:db8:3::/64
+ ipv6 access-list ACL_EXPORT seq 5 permit 2001:db8:1::/64
+ """
+ tgen.gears["r2"].vtysh_cmd(config)
+
+ logger.info("Expecting 2001:db8:3::/64 to be re-added on r1")
+ routes = {"2001:db8:3::/64": {}}
+ expect_ospfv3_routes("r1", routes, wait=30, type="inter-area")
+ logger.info("Expecting 2001:db8:1::/64 to be re-added on r3")
+ routes = {"2001:db8:1::/64": {}}
+ expect_ospfv3_routes("r3", routes, wait=30, type="inter-area")
+
+ #
+ # Unconfigure r2's ABR import/export filters.
+ #
+ config = """
+ configure terminal
+ router ospf6
+ no area 1 import-list ACL_IMPORT
+ no area 1 export-list ACL_EXPORT
+ """
+ tgen.gears["r2"].vtysh_cmd(config)
+
+ logger.info("Expecting ::/0 to be re-added on r1")
+ routes = {"::/0": {}}
+ expect_ospfv3_routes("r1", routes, wait=30, type="inter-area")
+
+
+def test_nssa_range():
+ """
+ Test NSSA ABR ranges.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Configure new addresses on r4 and enable redistribution of connected
+ # routes.
+ config = """
+ configure terminal
+ interface r4-stubnet
+ ipv6 address 2001:db8:1000::1/128
+ ipv6 address 2001:db8:1000::2/128
+ router ospf6
+ redistribute connected
+ """
+ tgen.gears["r4"].vtysh_cmd(config)
+ logger.info("Expecting NSSA-translated external routes to be added on r3")
+ routes = {"2001:db8:1000::1/128": {}, "2001:db8:1000::2/128": {}}
+ expect_ospfv3_routes("r3", routes, wait=30, type="external-2")
+
+ # Configure an NSSA range on r2 (ABR for area 2).
+ config = """
+ configure terminal
+ router ospf6
+ area 2 nssa range 2001:db8:1000::/64
+ """
+ tgen.gears["r2"].vtysh_cmd(config)
+ logger.info("Expecting summarized routes to be removed from r3")
+ for route in ["2001:db8:1000::1/128", "2001:db8:1000::2/128"]:
+ test_func = partial(dont_expect_route, "r3", route, type="external-2")
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = "{}'s {} summarized route still exists".format("r3", route)
+ assert result is None, assertmsg
+ logger.info("Expecting NSSA range to be added on r3")
+ routes = {
+ "2001:db8:1000::/64": {
+ "metricType": 2,
+ "metricCost": 20,
+ "metricCostE2": 10,
+ }
+ }
+ expect_ospfv3_routes("r3", routes, wait=30, type="external-2", detail=True)
+
+ # Change the NSSA range cost.
+ config = """
+ configure terminal
+ router ospf6
+ area 2 nssa range 2001:db8:1000::/64 cost 1000
+ """
+ tgen.gears["r2"].vtysh_cmd(config)
+ logger.info("Expecting NSSA range to be updated with new cost")
+ routes = {
+ "2001:db8:1000::/64": {
+ "metricType": 2,
+ "metricCost": 20,
+ "metricCostE2": 1000,
+ }
+ }
+ expect_ospfv3_routes("r3", routes, wait=30, type="external-2", detail=True)
+
+ # Configure the NSSA range to not be advertised.
+ config = """
+ configure terminal
+ router ospf6
+ area 2 nssa range 2001:db8:1000::/64 not-advertise
+ """
+ tgen.gears["r2"].vtysh_cmd(config)
+ logger.info("Expecting NSSA summary route to be removed")
+ route = "2001:db8:1000::/64"
+ test_func = partial(dont_expect_route, "r3", route, type="external-2")
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = "{}'s {} NSSA summary route still exists".format("r3", route)
+ assert result is None, assertmsg
+
+ # Remove the NSSA range.
+ config = """
+ configure terminal
+ router ospf6
+ no area 2 nssa range 2001:db8:1000::/64
+ """
+ tgen.gears["r2"].vtysh_cmd(config)
+ logger.info("Expecting previously summarized routes to be re-added")
+ routes = {
+ "2001:db8:1000::1/128": {
+ "metricType": 2,
+ "metricCostE2": 20,
+ },
+ "2001:db8:1000::2/128": {
+ "metricType": 2,
+ "metricCostE2": 20,
+ },
+ }
+ expect_ospfv3_routes("r3", routes, wait=30, type="external-2", detail=True)
+
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))