From 399547f3e35f8370cc094f8640b86a127b3c4e58 Mon Sep 17 00:00:00 2001 From: Yuqing Zhao Date: Wed, 27 Nov 2024 07:53:16 +0000 Subject: [PATCH] lib, tests: Add topotest for srv6 static local SID Add topotest zebra_static_opcode_sid to check whether static opcode can be configured manually and generate mySID properly. Besides, supplement JSON display for these sids info. The corresponding command is "show segment-rouing srv6 locator NAME detail json". Signed-off-by: Yuqing Zhao --- lib/srv6.c | 33 +++ lib/srv6.h | 2 + .../zebra_static_opcode_sid/__init__.py | 0 .../zebra_static_opcode_sid/r1/bgpd.conf | 10 + .../zebra_static_opcode_sid/r1/zebra.conf | 9 + .../zebra_static_opcode_sid/r2/bgpd.conf | 10 + .../zebra_static_opcode_sid/r2/zebra.conf | 9 + .../test_zebra_static_opcode_sid.py | 190 ++++++++++++++++++ 8 files changed, 263 insertions(+) create mode 100644 tests/topotests/zebra_static_opcode_sid/__init__.py create mode 100644 tests/topotests/zebra_static_opcode_sid/r1/bgpd.conf create mode 100644 tests/topotests/zebra_static_opcode_sid/r1/zebra.conf create mode 100644 tests/topotests/zebra_static_opcode_sid/r2/bgpd.conf create mode 100644 tests/topotests/zebra_static_opcode_sid/r2/zebra.conf create mode 100644 tests/topotests/zebra_static_opcode_sid/test_zebra_static_opcode_sid.py diff --git a/lib/srv6.c b/lib/srv6.c index e6fc375fbb11..969dc613f62a 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -316,6 +316,27 @@ srv6_locator_chunk_detailed_json(const struct srv6_locator_chunk *chunk) return jo_root; } +json_object *srv6_locator_sid_detailed_json(const struct srv6_locator *locator, + const struct seg6_sid *sid) +{ + json_object *jo_root = NULL; + char buf[256]; + + jo_root = json_object_new_object(); + + /* set opcode */ + prefix2str(&sid->ipv6Addr, buf, sizeof(buf)); + json_object_string_add(jo_root, "opcode", buf); + + /* set sidaction */ + json_object_string_add(jo_root, "sidaction", seg6local_action2str(sid->sidaction)); + + /* set vrf */ + json_object_string_add(jo_root, "vrf", sid->vrfName); + + return jo_root; +} + json_object *srv6_locator_json(const struct srv6_locator *loc) { struct listnode *node; @@ -392,10 +413,14 @@ json_object *srv6_locator_json(const struct srv6_locator *loc) json_object *srv6_locator_detailed_json(const struct srv6_locator *loc) { struct listnode *node; + struct listnode *sidnode; struct srv6_locator_chunk *chunk; + struct seg6_sid *sid = NULL; json_object *jo_root = NULL; json_object *jo_chunk = NULL; json_object *jo_chunks = NULL; + json_object *jo_sid = NULL; + json_object *jo_sids = NULL; jo_root = json_object_new_object(); @@ -461,5 +486,13 @@ json_object *srv6_locator_detailed_json(const struct srv6_locator *loc) json_object_array_add(jo_chunks, jo_chunk); } + /* set sids */ + jo_sids = json_object_new_array(); + json_object_object_add(jo_root, "sids", jo_sids); + for (ALL_LIST_ELEMENTS_RO(loc->sids, sidnode, sid)) { + jo_sid = srv6_locator_sid_detailed_json(loc, sid); + json_object_array_add(jo_sids, jo_sid); + } + return jo_root; } diff --git a/lib/srv6.h b/lib/srv6.h index 9a041e3d85b2..12393a73d6e7 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -388,6 +388,8 @@ json_object *srv6_locator_json(const struct srv6_locator *loc); json_object *srv6_locator_detailed_json(const struct srv6_locator *loc); json_object * srv6_locator_chunk_detailed_json(const struct srv6_locator_chunk *chunk); +json_object *srv6_locator_sid_detailed_json(const struct srv6_locator *locator, + const struct seg6_sid *sid); extern struct srv6_sid_format *srv6_sid_format_alloc(const char *name); extern void srv6_sid_format_free(struct srv6_sid_format *format); diff --git a/tests/topotests/zebra_static_opcode_sid/__init__.py b/tests/topotests/zebra_static_opcode_sid/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/topotests/zebra_static_opcode_sid/r1/bgpd.conf b/tests/topotests/zebra_static_opcode_sid/r1/bgpd.conf new file mode 100644 index 000000000000..d87e4d97b1ac --- /dev/null +++ b/tests/topotests/zebra_static_opcode_sid/r1/bgpd.conf @@ -0,0 +1,10 @@ +router bgp 65000 + no bgp ebgp-requires-policy + timers bgp start-timer 0 + neighbor aaa peer-group + neighbor aaa remote-as 65001 + neighbor 192.168.254.2 peer-group aaa + neighbor 192.168.255.2 remote-as 65001 + neighbor 192.168.255.2 timers 3 10 + exit-address-family +! diff --git a/tests/topotests/zebra_static_opcode_sid/r1/zebra.conf b/tests/topotests/zebra_static_opcode_sid/r1/zebra.conf new file mode 100644 index 000000000000..57958c442006 --- /dev/null +++ b/tests/topotests/zebra_static_opcode_sid/r1/zebra.conf @@ -0,0 +1,9 @@ +! +interface r1-eth0 + ip address 192.168.255.1/24 +! +interface r1-eth1 + ip address 192.168.254.1/24 +! +ip forwarding +! diff --git a/tests/topotests/zebra_static_opcode_sid/r2/bgpd.conf b/tests/topotests/zebra_static_opcode_sid/r2/bgpd.conf new file mode 100644 index 000000000000..35094f35c170 --- /dev/null +++ b/tests/topotests/zebra_static_opcode_sid/r2/bgpd.conf @@ -0,0 +1,10 @@ +router bgp 65001 + no bgp ebgp-requires-policy + timers bgp start-timer 0 + neighbor aaa peer-group + neighbor aaa remote-as 65000 + neighbor 192.168.254.1 peer-group aaa + neighbor 192.168.255.1 remote-as 65000 + neighbor 192.168.255.1 timers 3 10 + exit-address-family +! diff --git a/tests/topotests/zebra_static_opcode_sid/r2/zebra.conf b/tests/topotests/zebra_static_opcode_sid/r2/zebra.conf new file mode 100644 index 000000000000..f2daa523acdd --- /dev/null +++ b/tests/topotests/zebra_static_opcode_sid/r2/zebra.conf @@ -0,0 +1,9 @@ +! +interface r2-eth0 + ip address 192.168.255.2/24 +! +interface r2-eth1 + ip address 192.168.254.2/24 +! +ip forwarding +! diff --git a/tests/topotests/zebra_static_opcode_sid/test_zebra_static_opcode_sid.py b/tests/topotests/zebra_static_opcode_sid/test_zebra_static_opcode_sid.py new file mode 100644 index 000000000000..4dff633a3d4a --- /dev/null +++ b/tests/topotests/zebra_static_opcode_sid/test_zebra_static_opcode_sid.py @@ -0,0 +1,190 @@ +""" +test_zebra_static_opcode_sid.py + +Test if works the following commands: +segment-routing + srv6 + locators + locator loc1 + prefix fd00:201:201::/48 block-len 32 node-len 16 func-bits 16 + opcode ::fff1:11:0:0:0 end-dt46 vrf Vrf1 + opcode ::fff1:12:0:0:0 end-dt46 vrf Vrf2 + +Test contains two parts: +- Verify that the static opcode is configured and generates mySID correctly. +- Ensure that the opcode and the corresponding SID can be removed properly. +""" + +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.topolog import logger +from lib.common_config import step + + +def build_topo(tgen): + for routern in range(1, 3): + 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["r1"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_zebra_static_opcode_sid(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + r1 = tgen.gears['r1'] + + def _zebra_conf_static_opcode(router, locator_conf_args): + router.vtysh_cmd(locator_conf_args) + + + def _zebra_check_static_opcode_sids(router, cmd_args, expected_args): + output = json.loads(router.vtysh_cmd(cmd_args)) + return topotest.json_cmp(output, expected_args) + + + locator_conf_args = """ + configure terminal + segment-routing + srv6 + locators + locator loc1 + prefix fd00:202:202::/48 block-len 32 node-len 16 func-bits 16 + opcode ::fff1:11:0:0:0 end-dt46 vrf Vrf1 + opcode ::fff1:12:0:0:0 end-dt46 vrf Vrf2 + """ + locator_rm_conf_args = """ + configure terminal + segment-routing + srv6 + locators + locator loc1 + prefix fd00:202:202::/48 block-len 32 node-len 16 func-bits 16 + no opcode ::fff1:11:0:0:0 + no opcode ::fff1:12:0:0:0 + """ + cmd_args = "show segment-routing srv6 locator loc1 detail json" + expected_sids_args = { + "name":"loc1", + "prefix":"fd00:202:202::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "algoNum":0, + "statusUp":True, + "chunks":[ + { + "prefix":"fd00:202:202::/48", + "blockBitsLength":0, + "nodeBitsLength":0, + "functionBitsLength":0, + "argumentBitsLength":0, + "keep":0, + "proto":"system", + "instance":0, + "sessionId":0 + } + ], + "sids":[ + { + "opcode":"::fff1:11:0:0:0/128", + "sidaction":"End.DT46", + "vrf":"Vrf1" + }, + { + "opcode":"::fff1:12:0:0:0/128", + "sidaction":"End.DT46", + "vrf":"Vrf2" + } + ] + } + expected_no_sids_args = { + "name":"loc1", + "prefix":"fd00:202:202::/48", + "blockBitsLength":32, + "nodeBitsLength":16, + "functionBitsLength":16, + "argumentBitsLength":0, + "algoNum":0, + "statusUp":True, + "chunks":[ + { + "prefix":"fd00:202:202::/48", + "blockBitsLength":0, + "nodeBitsLength":0, + "functionBitsLength":0, + "argumentBitsLength":0, + "keep":0, + "proto":"system", + "instance":0, + "sessionId":0 + } + ], + "sids":[ + ] + } + + + step("Configure the static opcode for locator loc1 on router1") + _zebra_conf_static_opcode(r1, locator_conf_args) + + step("Check mySID (ADD)") + test_func = functools.partial(_zebra_check_static_opcode_sids, r1, + cmd_args, expected_sids_args) + _, result = topotest.run_and_expect(test_func, None, count=5, wait=5) + + assert result is None, 'Failed to add static opcode' + + step("Remove the static opcode for locator loc1 on router1") + _zebra_conf_static_opcode(r1, locator_rm_conf_args) + + step("Check mySID (DEL)") + test_func = functools.partial(_zebra_check_static_opcode_sids, r1, + cmd_args, expected_no_sids_args) + _, result = topotest.run_and_expect(test_func, None, count=5, wait=5) + + assert result is None, 'Failed to remove static opcode' + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) \ No newline at end of file