diff --git a/tests/topotests/zebra_operational_data/r1/frr.conf b/tests/topotests/zebra_operational_data/r1/frr.conf new file mode 100644 index 0000000000..72a67bf020 --- /dev/null +++ b/tests/topotests/zebra_operational_data/r1/frr.conf @@ -0,0 +1,41 @@ +log timestamp precision 6 +log file frr.log + +no debug memstats-at-exit + +debug northbound notifications +debug northbound libyang +debug northbound events +debug northbound callbacks + +debug mgmt backend datastore frontend transaction +debug mgmt client frontend +debug mgmt client backend + +interface r1-eth0 + ip address 1.1.1.1/24 + ipv6 address 2001:1111::1/64 +exit + +interface r1-eth1 + ip address 2.2.2.1/24 + ipv6 address 2002:2222::1/64 +exit + +interface r1-eth2 vrf red + ip address 3.3.3.1/24 + ipv6 address 2003:333::1/64 +exit + +interface r1-eth3 vrf red + ip address 4.4.4.1/24 + ipv6 address 2004:4444::1/64 +exit + +ip route 11.0.0.0/8 Null0 +ip route 11.11.11.11/32 1.1.1.2 +ip route 12.12.12.12/32 2.2.2.2 + +ip route 13.0.0.0/8 Null0 vrf red +ip route 13.13.13.13/32 3.3.3.2 vrf red +ip route 14.14.14.14/32 4.4.4.2 vrf red \ No newline at end of file diff --git a/tests/topotests/zebra_operational_data/test_zebra_operational.py b/tests/topotests/zebra_operational_data/test_zebra_operational.py new file mode 100644 index 0000000000..c4ab5be973 --- /dev/null +++ b/tests/topotests/zebra_operational_data/test_zebra_operational.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: ISC +# +# Copyright (c) 2025 Nvidia Inc. +# Donald Sharp +# +""" +Test zebra operational values +""" + +import pytest +import json +from lib.topogen import Topogen +from lib.topolog import logger + + +pytestmark = [pytest.mark.mgmtd] + + +@pytest.fixture(scope="module") +def tgen(request): + "Setup/Teardown the environment and provide tgen argument to tests" + + topodef = {"s1": ("r1",), "s2": ("r1",), "s3": ("r1",), "s4": ("r1",)} + + tgen = Topogen(topodef, request.module.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + # Setup VRF red + router.net.add_l3vrf("red", 10) + router.net.add_loop("lo-red") + router.net.attach_iface_to_l3vrf("lo-red", "red") + router.net.attach_iface_to_l3vrf(rname + "-eth2", "red") + router.net.attach_iface_to_l3vrf(rname + "-eth3", "red") + router.load_frr_config("frr.conf") + + tgen.start_router() + yield tgen + tgen.stop_topology() + + +def test_zebra_operationalr(tgen): + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + output = json.loads(r1.vtysh_cmd("show mgmt get-data /frr-zebra:zebra")) + + logger.info("Output") + logger.info(output) + + logger.info("Ensuring that the max-multipath value is returned") + assert "max-multipath" in output["frr-zebra:zebra"].keys() + + +if __name__ == "__main__": + # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli + # retval = pytest.main(["-s", "--tb=no"]) + retval = pytest.main(["-s"]) + sys.exit(retval) diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang index a3c066c56c..5f1b711b97 100644 --- a/yang/frr-zebra.yang +++ b/yang/frr-zebra.yang @@ -2842,6 +2842,17 @@ module frr-zebra { container zebra { description "Data model for the Zebra daemon."; + leaf max-multipath { + config false; + type uint16 { + range "1..65535"; + } + description + "The maximum number of nexthops for a route. At this point it + is unlikely that a multipath number will ever get larger then + 1024 but to allow for future expansions, the yang returns a + 16 bit number"; + } leaf ip-forwarding { type boolean; description diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c index 6b41993a95..81fe2ab6a0 100644 --- a/zebra/zebra_nb.c +++ b/zebra/zebra_nb.c @@ -25,6 +25,12 @@ const struct frr_yang_module_info frr_zebra_info = { .name = "frr-zebra", .features = features, .nodes = { + { + .xpath = "/frr-zebra:zebra/max-multipath", + .cbs = { + .get_elem = zebra_max_multipath_get_elem, + } + }, { .xpath = "/frr-zebra:zebra/ip-forwarding", .cbs = { diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h index 785291bc68..426ad4b7de 100644 --- a/zebra/zebra_nb.h +++ b/zebra/zebra_nb.h @@ -14,6 +14,7 @@ extern "C" { extern const struct frr_yang_module_info frr_zebra_info; /* prototypes */ +struct yang_data *zebra_max_multipath_get_elem(struct nb_cb_get_elem_args *args); int get_route_information_rpc(struct nb_cb_rpc_args *args); int get_v6_mroute_info_rpc(struct nb_cb_rpc_args *args); int get_vrf_info_rpc(struct nb_cb_rpc_args *args); diff --git a/zebra/zebra_nb_state.c b/zebra/zebra_nb_state.c index 6ed11f75f1..a7091821b5 100644 --- a/zebra/zebra_nb_state.c +++ b/zebra/zebra_nb_state.c @@ -1157,3 +1157,12 @@ lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_weight_get_elem( return NULL; } + +/* + * XPath: + * /frr-zebra:zebra/max-multipath + */ +struct yang_data *zebra_max_multipath_get_elem(struct nb_cb_get_elem_args *args) +{ + return yang_data_new_uint16(args->xpath, zrouter.multipath_num); +}