diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:53:30 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:53:30 +0000 |
commit | 2c7cac91ed6e7db0f6937923d2b57f97dbdbc337 (patch) | |
tree | c05dc0f8e6aa3accc84e3e5cffc933ed94941383 /tests/lib/northbound | |
parent | Initial commit. (diff) | |
download | frr-upstream.tar.xz frr-upstream.zip |
Adding upstream version 8.4.4.upstream/8.4.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/lib/northbound')
-rw-r--r-- | tests/lib/northbound/test_oper_data.c | 416 | ||||
-rw-r--r-- | tests/lib/northbound/test_oper_data.in | 1 | ||||
-rw-r--r-- | tests/lib/northbound/test_oper_data.py | 5 | ||||
-rw-r--r-- | tests/lib/northbound/test_oper_data.refout | 119 |
4 files changed, 541 insertions, 0 deletions
diff --git a/tests/lib/northbound/test_oper_data.c b/tests/lib/northbound/test_oper_data.c new file mode 100644 index 0000000..08eb0d5 --- /dev/null +++ b/tests/lib/northbound/test_oper_data.c @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2018 NetDEF, Inc. + * Renato Westphal + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <zebra.h> + +#include "thread.h" +#include "vty.h" +#include "command.h" +#include "memory.h" +#include "lib_vty.h" +#include "log.h" +#include "northbound.h" + +static struct thread_master *master; + +struct troute { + struct prefix_ipv4 prefix; + struct in_addr nexthop; + char ifname[IFNAMSIZ]; + uint8_t metric; + bool active; +}; + +struct tvrf { + char name[32]; + struct list *interfaces; + struct list *routes; +}; + +static struct list *vrfs; + +/* + * XPath: /frr-test-module:frr-test-module/vrfs/vrf + */ +static const void * +frr_test_module_vrfs_vrf_get_next(struct nb_cb_get_next_args *args) +{ + struct listnode *node; + + if (args->list_entry == NULL) + node = listhead(vrfs); + else + node = listnextnode((struct listnode *)args->list_entry); + + return node; +} + +static int frr_test_module_vrfs_vrf_get_keys(struct nb_cb_get_keys_args *args) +{ + const struct tvrf *vrf; + + vrf = listgetdata((struct listnode *)args->list_entry); + + args->keys->num = 1; + strlcpy(args->keys->key[0], vrf->name, sizeof(args->keys->key[0])); + + return NB_OK; +} + +static const void * +frr_test_module_vrfs_vrf_lookup_entry(struct nb_cb_lookup_entry_args *args) +{ + struct listnode *node; + struct tvrf *vrf; + const char *vrfname; + + vrfname = args->keys->key[0]; + + for (ALL_LIST_ELEMENTS_RO(vrfs, node, vrf)) { + if (strmatch(vrf->name, vrfname)) + return node; + } + + return NULL; +} + +/* + * XPath: /frr-test-module:frr-test-module/vrfs/vrf/name + */ +static struct yang_data * +frr_test_module_vrfs_vrf_name_get_elem(struct nb_cb_get_elem_args *args) +{ + const struct tvrf *vrf; + + vrf = listgetdata((struct listnode *)args->list_entry); + return yang_data_new_string(args->xpath, vrf->name); +} + +/* + * XPath: /frr-test-module:frr-test-module/vrfs/vrf/interfaces/interface + */ +static struct yang_data *frr_test_module_vrfs_vrf_interfaces_interface_get_elem( + struct nb_cb_get_elem_args *args) +{ + const char *interface; + + interface = listgetdata((struct listnode *)args->list_entry); + return yang_data_new_string(args->xpath, interface); +} + +static const void *frr_test_module_vrfs_vrf_interfaces_interface_get_next( + struct nb_cb_get_next_args *args) +{ + const struct tvrf *vrf; + struct listnode *node; + + vrf = listgetdata((struct listnode *)args->parent_list_entry); + if (args->list_entry == NULL) + node = listhead(vrf->interfaces); + else + node = listnextnode((struct listnode *)args->list_entry); + + return node; +} + +/* + * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route + */ +static const void * +frr_test_module_vrfs_vrf_routes_route_get_next(struct nb_cb_get_next_args *args) +{ + const struct tvrf *vrf; + struct listnode *node; + + vrf = listgetdata((struct listnode *)args->parent_list_entry); + if (args->list_entry == NULL) + node = listhead(vrf->routes); + else + node = listnextnode((struct listnode *)args->list_entry); + + return node; +} + +/* + * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/prefix + */ +static struct yang_data *frr_test_module_vrfs_vrf_routes_route_prefix_get_elem( + struct nb_cb_get_elem_args *args) +{ + const struct troute *route; + + route = listgetdata((struct listnode *)args->list_entry); + return yang_data_new_ipv4p(args->xpath, &route->prefix); +} + +/* + * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/next-hop + */ +static struct yang_data * +frr_test_module_vrfs_vrf_routes_route_next_hop_get_elem( + struct nb_cb_get_elem_args *args) +{ + const struct troute *route; + + route = listgetdata((struct listnode *)args->list_entry); + return yang_data_new_ipv4(args->xpath, &route->nexthop); +} + +/* + * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/interface + */ +static struct yang_data * +frr_test_module_vrfs_vrf_routes_route_interface_get_elem( + struct nb_cb_get_elem_args *args) +{ + const struct troute *route; + + route = listgetdata((struct listnode *)args->list_entry); + return yang_data_new_string(args->xpath, route->ifname); +} + +/* + * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/metric + */ +static struct yang_data *frr_test_module_vrfs_vrf_routes_route_metric_get_elem( + struct nb_cb_get_elem_args *args) +{ + const struct troute *route; + + route = listgetdata((struct listnode *)args->list_entry); + return yang_data_new_uint8(args->xpath, route->metric); +} + +/* + * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/active + */ +static struct yang_data *frr_test_module_vrfs_vrf_routes_route_active_get_elem( + struct nb_cb_get_elem_args *args) +{ + const struct troute *route; + + route = listgetdata((struct listnode *)args->list_entry); + if (route->active) + return yang_data_new(args->xpath, NULL); + + return NULL; +} + +/* clang-format off */ +const struct frr_yang_module_info frr_test_module_info = { + .name = "frr-test-module", + .nodes = { + { + .xpath = "/frr-test-module:frr-test-module/vrfs/vrf", + .cbs.get_next = frr_test_module_vrfs_vrf_get_next, + .cbs.get_keys = frr_test_module_vrfs_vrf_get_keys, + .cbs.lookup_entry = frr_test_module_vrfs_vrf_lookup_entry, + }, + { + .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/name", + .cbs.get_elem = frr_test_module_vrfs_vrf_name_get_elem, + }, + { + .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/interfaces/interface", + .cbs.get_elem = frr_test_module_vrfs_vrf_interfaces_interface_get_elem, + .cbs.get_next = frr_test_module_vrfs_vrf_interfaces_interface_get_next, + }, + { + .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route", + .cbs.get_next = frr_test_module_vrfs_vrf_routes_route_get_next, + }, + { + .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/prefix", + .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_prefix_get_elem, + }, + { + .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/next-hop", + .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_next_hop_get_elem, + }, + { + .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/interface", + .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_interface_get_elem, + }, + { + .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/metric", + .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_metric_get_elem, + }, + { + .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/active", + .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_active_get_elem, + }, + { + .xpath = NULL, + }, + } +}; +/* clang-format on */ + +static const struct frr_yang_module_info *const modules[] = { + &frr_test_module_info, +}; + +static void create_data(unsigned int num_vrfs, unsigned int num_interfaces, + unsigned int num_routes) +{ + struct prefix_ipv4 base_prefix; + struct in_addr base_nexthop; + + (void)str2prefix_ipv4("10.0.0.0/32", &base_prefix); + (void)inet_pton(AF_INET, "172.16.0.0", &base_nexthop); + + vrfs = list_new(); + + /* Create VRFs. */ + for (unsigned int i = 0; i < num_vrfs; i++) { + struct tvrf *vrf; + + vrf = XCALLOC(MTYPE_TMP, sizeof(*vrf)); + snprintf(vrf->name, sizeof(vrf->name), "vrf%u", i); + vrf->interfaces = list_new(); + vrf->routes = list_new(); + + /* Create interfaces. */ + for (unsigned int j = 0; j < num_interfaces; j++) { + char ifname[32]; + char *interface; + + snprintf(ifname, sizeof(ifname), "eth%u", j); + interface = XSTRDUP(MTYPE_TMP, ifname); + listnode_add(vrf->interfaces, interface); + } + + /* Create routes. */ + for (unsigned int j = 0; j < num_routes; j++) { + struct troute *route; + + route = XCALLOC(MTYPE_TMP, sizeof(*route)); + + memcpy(&route->prefix, &base_prefix, + sizeof(route->prefix)); + route->prefix.prefix.s_addr = + htonl(ntohl(route->prefix.prefix.s_addr) + j); + + memcpy(&route->nexthop, &base_nexthop, + sizeof(route->nexthop)); + route->nexthop.s_addr = + htonl(ntohl(route->nexthop.s_addr) + j); + + snprintf(route->ifname, sizeof(route->ifname), "eth%u", + j); + route->metric = j % 256; + route->active = (j % 2 == 0); + listnode_add(vrf->routes, route); + } + + listnode_add(vrfs, vrf); + } +} + +static void interface_delete(void *ptr) +{ + char *interface = ptr; + + XFREE(MTYPE_TMP, interface); +} + +static void route_delete(void *ptr) +{ + struct troute *route = ptr; + + XFREE(MTYPE_TMP, route); +} + +static void vrf_delete(void *ptr) +{ + struct tvrf *vrf = ptr; + + vrf->interfaces->del = interface_delete; + list_delete(&vrf->interfaces); + vrf->routes->del = route_delete; + list_delete(&vrf->routes); + XFREE(MTYPE_TMP, vrf); +} + +static void delete_data(void) +{ + vrfs->del = vrf_delete; + list_delete(&vrfs); +} + +static void vty_do_exit(int isexit) +{ + printf("\nend.\n"); + + delete_data(); + + cmd_terminate(); + vty_terminate(); + nb_terminate(); + yang_terminate(); + thread_master_free(master); + + log_memstats(stderr, "test-nb-oper-data"); + if (!isexit) + exit(0); +} + +/* main routine. */ +int main(int argc, char **argv) +{ + struct thread thread; + unsigned int num_vrfs = 2; + unsigned int num_interfaces = 4; + unsigned int num_routes = 6; + + if (argc > 1) + num_vrfs = atoi(argv[1]); + if (argc > 2) + num_interfaces = atoi(argv[2]); + if (argc > 3) + num_routes = atoi(argv[3]); + + /* Set umask before anything for security */ + umask(0027); + + /* master init. */ + master = thread_master_create(NULL); + + zlog_aux_init("NONE: ", ZLOG_DISABLED); + + /* Library inits. */ + cmd_init(1); + cmd_hostname_set("test"); + vty_init(master, false); + lib_cmd_init(); + nb_init(master, modules, array_size(modules), false); + + /* Create artificial data. */ + create_data(num_vrfs, num_interfaces, num_routes); + + /* Read input from .in file. */ + vty_stdio(vty_do_exit); + + /* Fetch next active thread. */ + while (thread_fetch(master, &thread)) + thread_call(&thread); + + /* Not reached. */ + exit(0); +} diff --git a/tests/lib/northbound/test_oper_data.in b/tests/lib/northbound/test_oper_data.in new file mode 100644 index 0000000..a6c4f87 --- /dev/null +++ b/tests/lib/northbound/test_oper_data.in @@ -0,0 +1 @@ +show yang operational-data /frr-test-module:frr-test-module diff --git a/tests/lib/northbound/test_oper_data.py b/tests/lib/northbound/test_oper_data.py new file mode 100644 index 0000000..a02bf05 --- /dev/null +++ b/tests/lib/northbound/test_oper_data.py @@ -0,0 +1,5 @@ +import frrtest + + +class TestNbOperData(frrtest.TestRefOut): + program = "./test_oper_data" diff --git a/tests/lib/northbound/test_oper_data.refout b/tests/lib/northbound/test_oper_data.refout new file mode 100644 index 0000000..57ecd2f --- /dev/null +++ b/tests/lib/northbound/test_oper_data.refout @@ -0,0 +1,119 @@ +test# show yang operational-data /frr-test-module:frr-test-module
+{
+ "frr-test-module:frr-test-module": {
+ "vrfs": {
+ "vrf": [
+ {
+ "name": "vrf0",
+ "interfaces": {
+ "interface": [
+ "eth0",
+ "eth1",
+ "eth2",
+ "eth3"
+ ]
+ },
+ "routes": {
+ "route": [
+ {
+ "prefix": "10.0.0.0/32",
+ "next-hop": "172.16.0.0",
+ "interface": "eth0",
+ "metric": 0,
+ "active": [null]
+ },
+ {
+ "prefix": "10.0.0.1/32",
+ "next-hop": "172.16.0.1",
+ "interface": "eth1",
+ "metric": 1
+ },
+ {
+ "prefix": "10.0.0.2/32",
+ "next-hop": "172.16.0.2",
+ "interface": "eth2",
+ "metric": 2,
+ "active": [null]
+ },
+ {
+ "prefix": "10.0.0.3/32",
+ "next-hop": "172.16.0.3",
+ "interface": "eth3",
+ "metric": 3
+ },
+ {
+ "prefix": "10.0.0.4/32",
+ "next-hop": "172.16.0.4",
+ "interface": "eth4",
+ "metric": 4,
+ "active": [null]
+ },
+ {
+ "prefix": "10.0.0.5/32",
+ "next-hop": "172.16.0.5",
+ "interface": "eth5",
+ "metric": 5
+ }
+ ]
+ }
+ },
+ {
+ "name": "vrf1",
+ "interfaces": {
+ "interface": [
+ "eth0",
+ "eth1",
+ "eth2",
+ "eth3"
+ ]
+ },
+ "routes": {
+ "route": [
+ {
+ "prefix": "10.0.0.0/32",
+ "next-hop": "172.16.0.0",
+ "interface": "eth0",
+ "metric": 0,
+ "active": [null]
+ },
+ {
+ "prefix": "10.0.0.1/32",
+ "next-hop": "172.16.0.1",
+ "interface": "eth1",
+ "metric": 1
+ },
+ {
+ "prefix": "10.0.0.2/32",
+ "next-hop": "172.16.0.2",
+ "interface": "eth2",
+ "metric": 2,
+ "active": [null]
+ },
+ {
+ "prefix": "10.0.0.3/32",
+ "next-hop": "172.16.0.3",
+ "interface": "eth3",
+ "metric": 3
+ },
+ {
+ "prefix": "10.0.0.4/32",
+ "next-hop": "172.16.0.4",
+ "interface": "eth4",
+ "metric": 4,
+ "active": [null]
+ },
+ {
+ "prefix": "10.0.0.5/32",
+ "next-hop": "172.16.0.5",
+ "interface": "eth5",
+ "metric": 5
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+}
+test# +end. |