summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDonald Sharp <sharpd@nvidia.com>2025-01-27 10:34:31 -0500
committerMergify <37929162+mergify[bot]@users.noreply.github.com>2025-02-11 08:46:13 +0000
commitcbe6684fee700f81b1650d3cdf4fcd1c624d919b (patch)
tree94f66d04a23f22b3ea58a13881e775fb09020a78
parent319df238a0ffce2c20d916c30c81b7e423244f01 (diff)
tests: Add a test that shows the v6 recursive nexthop problem
Currently FRR does not handle v6 recurisive resolution properly when the route being recursed through changes and the most significant bits of the route are not changed. Signed-off-by: Donald Sharp <sharpd@nvidia.com> (cherry picked from commit 73ab6a46c51db91df297774221053ab8fc4d12ae)
-rw-r--r--tests/topotests/v6_nexthop_group_recursive_resolution/r1/frr.conf4
-rw-r--r--tests/topotests/v6_nexthop_group_recursive_resolution/test_v6_nexthop_group_recursive_resolution.py189
2 files changed, 193 insertions, 0 deletions
diff --git a/tests/topotests/v6_nexthop_group_recursive_resolution/r1/frr.conf b/tests/topotests/v6_nexthop_group_recursive_resolution/r1/frr.conf
new file mode 100644
index 0000000000..f4da11af06
--- /dev/null
+++ b/tests/topotests/v6_nexthop_group_recursive_resolution/r1/frr.conf
@@ -0,0 +1,4 @@
+int r1-eth0
+ ipv6 address fc00::1/64
+
+ipv6 route 1::1/128 fc00::2
diff --git a/tests/topotests/v6_nexthop_group_recursive_resolution/test_v6_nexthop_group_recursive_resolution.py b/tests/topotests/v6_nexthop_group_recursive_resolution/test_v6_nexthop_group_recursive_resolution.py
new file mode 100644
index 0000000000..587a951c85
--- /dev/null
+++ b/tests/topotests/v6_nexthop_group_recursive_resolution/test_v6_nexthop_group_recursive_resolution.py
@@ -0,0 +1,189 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+#
+# Copyright (c) 2024 by Nvidia Corporation
+# Donald Sharp
+#
+
+"""
+Check that the v6 nexthop recursive resolution works when it changes
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.staticd]
+
+
+def build_topo(tgen):
+
+ tgen.add_router("r1")
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for rname, router in router_list.items():
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)),
+ [(TopoRouter.RD_MGMTD, None),
+ (TopoRouter.RD_ZEBRA, None),
+ (TopoRouter.RD_STATIC, None),
+ (TopoRouter.RD_SHARP, None)])
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_recursive_v6_nexthop_generation():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Testing v6 nexthop resolution")
+
+ #assert False
+ router = tgen.gears["r1"]
+
+ def _v6_converge_1_1_initial():
+ output = json.loads(
+ router.vtysh_cmd("show ipv6 route 1::1 json"))
+
+ expected = {
+ "1::1/128":[
+ {
+ "prefix":"1::1/128",
+ "prefixLen":128,
+ "protocol":"static",
+ "vrfName":"default",
+ "selected":True,
+ "destSelected":True,
+ "distance":1,
+ "metric":0,
+ "installed":True,
+ "table":254,
+ "nexthops":[
+ {
+ "fib":True,
+ "ip":"fc00::2",
+ "afi":"ipv6",
+ "interfaceName":"r1-eth0",
+ "active":True,
+ "weight":1
+ }
+ ]
+ }
+ ]
+ }
+
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_v6_converge_1_1_initial)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to install v6 1::1 route"
+
+ router.vtysh_cmd("sharp install routes 2::2 nexthop 1::1 1")
+ router.vtysh_cmd("conf\nipv6 route 1::1/128 fc00::3\nno ipv6 route 1::1/128 fc00::2")
+
+ def _v6_converge_1_1_post():
+ output = json.loads(
+ router.vtysh_cmd("show ipv6 route 1::1 json"))
+
+ expected = {
+ "1::1/128":[
+ {
+ "prefix":"1::1/128",
+ "prefixLen":128,
+ "protocol":"static",
+ "vrfName":"default",
+ "selected":True,
+ "destSelected":True,
+ "distance":1,
+ "metric":0,
+ "installed":True,
+ "table":254,
+ "nexthops":[
+ {
+ "fib":True,
+ "ip":"fc00::3",
+ "afi":"ipv6",
+ "interfaceName":"r1-eth0",
+ "active":True,
+ "weight":1
+ }
+ ]
+ }
+ ]
+ }
+
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_v6_converge_1_1_post)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to change v6 1::1 route"
+
+ router.vtysh_cmd("sharp install routes 2::2 nexthop 1::1 1")
+
+ def _v6_change_2_2_post():
+ output = json.loads(
+ router.vtysh_cmd("show ipv6 route 2::2 json"))
+
+ expected = {
+ "2::2/128":[
+ {
+ "prefix":"2::2/128",
+ "prefixLen":128,
+ "protocol":"sharp",
+ "vrfName":"default",
+ "selected":True,
+ "destSelected":True,
+ "distance":150,
+ "metric":0,
+ "installed":True,
+ "table":254,
+ "nexthops":[
+ {
+ "fib":True,
+ "ip":"fc00::3",
+ "afi":"ipv6",
+ "interfaceName":"r1-eth0",
+ "active":True,
+ "weight":1
+ }
+ ]
+ }
+ ]
+ }
+
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_v6_change_2_2_post)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to see sharpd route correctly"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))