]> git.proxmox.com Git - mirror_frr.git/blob - tests/lib/northbound/test_oper_data.c
Merge pull request #12248 from pguibert6WIND/bgpasdot
[mirror_frr.git] / tests / lib / northbound / test_oper_data.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2018 NetDEF, Inc.
4 * Renato Westphal
5 */
6
7 #include <zebra.h>
8
9 #include "thread.h"
10 #include "vty.h"
11 #include "command.h"
12 #include "memory.h"
13 #include "lib_vty.h"
14 #include "log.h"
15 #include "northbound.h"
16
17 static struct thread_master *master;
18
19 struct troute {
20 struct prefix_ipv4 prefix;
21 struct in_addr nexthop;
22 char ifname[IFNAMSIZ];
23 uint8_t metric;
24 bool active;
25 };
26
27 struct tvrf {
28 char name[32];
29 struct list *interfaces;
30 struct list *routes;
31 };
32
33 static struct list *vrfs;
34
35 /*
36 * XPath: /frr-test-module:frr-test-module/vrfs/vrf
37 */
38 static const void *
39 frr_test_module_vrfs_vrf_get_next(struct nb_cb_get_next_args *args)
40 {
41 struct listnode *node;
42
43 if (args->list_entry == NULL)
44 node = listhead(vrfs);
45 else
46 node = listnextnode((struct listnode *)args->list_entry);
47
48 return node;
49 }
50
51 static int frr_test_module_vrfs_vrf_get_keys(struct nb_cb_get_keys_args *args)
52 {
53 const struct tvrf *vrf;
54
55 vrf = listgetdata((struct listnode *)args->list_entry);
56
57 args->keys->num = 1;
58 strlcpy(args->keys->key[0], vrf->name, sizeof(args->keys->key[0]));
59
60 return NB_OK;
61 }
62
63 static const void *
64 frr_test_module_vrfs_vrf_lookup_entry(struct nb_cb_lookup_entry_args *args)
65 {
66 struct listnode *node;
67 struct tvrf *vrf;
68 const char *vrfname;
69
70 vrfname = args->keys->key[0];
71
72 for (ALL_LIST_ELEMENTS_RO(vrfs, node, vrf)) {
73 if (strmatch(vrf->name, vrfname))
74 return node;
75 }
76
77 return NULL;
78 }
79
80 /*
81 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/name
82 */
83 static struct yang_data *
84 frr_test_module_vrfs_vrf_name_get_elem(struct nb_cb_get_elem_args *args)
85 {
86 const struct tvrf *vrf;
87
88 vrf = listgetdata((struct listnode *)args->list_entry);
89 return yang_data_new_string(args->xpath, vrf->name);
90 }
91
92 /*
93 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/interfaces/interface
94 */
95 static struct yang_data *frr_test_module_vrfs_vrf_interfaces_interface_get_elem(
96 struct nb_cb_get_elem_args *args)
97 {
98 const char *interface;
99
100 interface = listgetdata((struct listnode *)args->list_entry);
101 return yang_data_new_string(args->xpath, interface);
102 }
103
104 static const void *frr_test_module_vrfs_vrf_interfaces_interface_get_next(
105 struct nb_cb_get_next_args *args)
106 {
107 const struct tvrf *vrf;
108 struct listnode *node;
109
110 vrf = listgetdata((struct listnode *)args->parent_list_entry);
111 if (args->list_entry == NULL)
112 node = listhead(vrf->interfaces);
113 else
114 node = listnextnode((struct listnode *)args->list_entry);
115
116 return node;
117 }
118
119 /*
120 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route
121 */
122 static const void *
123 frr_test_module_vrfs_vrf_routes_route_get_next(struct nb_cb_get_next_args *args)
124 {
125 const struct tvrf *vrf;
126 struct listnode *node;
127
128 vrf = listgetdata((struct listnode *)args->parent_list_entry);
129 if (args->list_entry == NULL)
130 node = listhead(vrf->routes);
131 else
132 node = listnextnode((struct listnode *)args->list_entry);
133
134 return node;
135 }
136
137 /*
138 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/prefix
139 */
140 static struct yang_data *frr_test_module_vrfs_vrf_routes_route_prefix_get_elem(
141 struct nb_cb_get_elem_args *args)
142 {
143 const struct troute *route;
144
145 route = listgetdata((struct listnode *)args->list_entry);
146 return yang_data_new_ipv4p(args->xpath, &route->prefix);
147 }
148
149 /*
150 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/next-hop
151 */
152 static struct yang_data *
153 frr_test_module_vrfs_vrf_routes_route_next_hop_get_elem(
154 struct nb_cb_get_elem_args *args)
155 {
156 const struct troute *route;
157
158 route = listgetdata((struct listnode *)args->list_entry);
159 return yang_data_new_ipv4(args->xpath, &route->nexthop);
160 }
161
162 /*
163 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/interface
164 */
165 static struct yang_data *
166 frr_test_module_vrfs_vrf_routes_route_interface_get_elem(
167 struct nb_cb_get_elem_args *args)
168 {
169 const struct troute *route;
170
171 route = listgetdata((struct listnode *)args->list_entry);
172 return yang_data_new_string(args->xpath, route->ifname);
173 }
174
175 /*
176 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/metric
177 */
178 static struct yang_data *frr_test_module_vrfs_vrf_routes_route_metric_get_elem(
179 struct nb_cb_get_elem_args *args)
180 {
181 const struct troute *route;
182
183 route = listgetdata((struct listnode *)args->list_entry);
184 return yang_data_new_uint8(args->xpath, route->metric);
185 }
186
187 /*
188 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/active
189 */
190 static struct yang_data *frr_test_module_vrfs_vrf_routes_route_active_get_elem(
191 struct nb_cb_get_elem_args *args)
192 {
193 const struct troute *route;
194
195 route = listgetdata((struct listnode *)args->list_entry);
196 if (route->active)
197 return yang_data_new(args->xpath, NULL);
198
199 return NULL;
200 }
201
202 /* clang-format off */
203 const struct frr_yang_module_info frr_test_module_info = {
204 .name = "frr-test-module",
205 .nodes = {
206 {
207 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf",
208 .cbs.get_next = frr_test_module_vrfs_vrf_get_next,
209 .cbs.get_keys = frr_test_module_vrfs_vrf_get_keys,
210 .cbs.lookup_entry = frr_test_module_vrfs_vrf_lookup_entry,
211 },
212 {
213 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/name",
214 .cbs.get_elem = frr_test_module_vrfs_vrf_name_get_elem,
215 },
216 {
217 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/interfaces/interface",
218 .cbs.get_elem = frr_test_module_vrfs_vrf_interfaces_interface_get_elem,
219 .cbs.get_next = frr_test_module_vrfs_vrf_interfaces_interface_get_next,
220 },
221 {
222 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route",
223 .cbs.get_next = frr_test_module_vrfs_vrf_routes_route_get_next,
224 },
225 {
226 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/prefix",
227 .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_prefix_get_elem,
228 },
229 {
230 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/next-hop",
231 .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_next_hop_get_elem,
232 },
233 {
234 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/interface",
235 .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_interface_get_elem,
236 },
237 {
238 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/metric",
239 .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_metric_get_elem,
240 },
241 {
242 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/active",
243 .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_active_get_elem,
244 },
245 {
246 .xpath = NULL,
247 },
248 }
249 };
250 /* clang-format on */
251
252 static const struct frr_yang_module_info *const modules[] = {
253 &frr_test_module_info,
254 };
255
256 static void create_data(unsigned int num_vrfs, unsigned int num_interfaces,
257 unsigned int num_routes)
258 {
259 struct prefix_ipv4 base_prefix;
260 struct in_addr base_nexthop;
261
262 (void)str2prefix_ipv4("10.0.0.0/32", &base_prefix);
263 (void)inet_pton(AF_INET, "172.16.0.0", &base_nexthop);
264
265 vrfs = list_new();
266
267 /* Create VRFs. */
268 for (unsigned int i = 0; i < num_vrfs; i++) {
269 struct tvrf *vrf;
270
271 vrf = XCALLOC(MTYPE_TMP, sizeof(*vrf));
272 snprintf(vrf->name, sizeof(vrf->name), "vrf%u", i);
273 vrf->interfaces = list_new();
274 vrf->routes = list_new();
275
276 /* Create interfaces. */
277 for (unsigned int j = 0; j < num_interfaces; j++) {
278 char ifname[32];
279 char *interface;
280
281 snprintf(ifname, sizeof(ifname), "eth%u", j);
282 interface = XSTRDUP(MTYPE_TMP, ifname);
283 listnode_add(vrf->interfaces, interface);
284 }
285
286 /* Create routes. */
287 for (unsigned int j = 0; j < num_routes; j++) {
288 struct troute *route;
289
290 route = XCALLOC(MTYPE_TMP, sizeof(*route));
291
292 memcpy(&route->prefix, &base_prefix,
293 sizeof(route->prefix));
294 route->prefix.prefix.s_addr =
295 htonl(ntohl(route->prefix.prefix.s_addr) + j);
296
297 memcpy(&route->nexthop, &base_nexthop,
298 sizeof(route->nexthop));
299 route->nexthop.s_addr =
300 htonl(ntohl(route->nexthop.s_addr) + j);
301
302 snprintf(route->ifname, sizeof(route->ifname), "eth%u",
303 j);
304 route->metric = j % 256;
305 route->active = (j % 2 == 0);
306 listnode_add(vrf->routes, route);
307 }
308
309 listnode_add(vrfs, vrf);
310 }
311 }
312
313 static void interface_delete(void *ptr)
314 {
315 char *interface = ptr;
316
317 XFREE(MTYPE_TMP, interface);
318 }
319
320 static void route_delete(void *ptr)
321 {
322 struct troute *route = ptr;
323
324 XFREE(MTYPE_TMP, route);
325 }
326
327 static void vrf_delete(void *ptr)
328 {
329 struct tvrf *vrf = ptr;
330
331 vrf->interfaces->del = interface_delete;
332 list_delete(&vrf->interfaces);
333 vrf->routes->del = route_delete;
334 list_delete(&vrf->routes);
335 XFREE(MTYPE_TMP, vrf);
336 }
337
338 static void delete_data(void)
339 {
340 vrfs->del = vrf_delete;
341 list_delete(&vrfs);
342 }
343
344 static void vty_do_exit(int isexit)
345 {
346 printf("\nend.\n");
347
348 delete_data();
349
350 cmd_terminate();
351 vty_terminate();
352 nb_terminate();
353 yang_terminate();
354 thread_master_free(master);
355
356 log_memstats(stderr, "test-nb-oper-data");
357 if (!isexit)
358 exit(0);
359 }
360
361 /* main routine. */
362 int main(int argc, char **argv)
363 {
364 struct thread thread;
365 unsigned int num_vrfs = 2;
366 unsigned int num_interfaces = 4;
367 unsigned int num_routes = 6;
368
369 if (argc > 1)
370 num_vrfs = atoi(argv[1]);
371 if (argc > 2)
372 num_interfaces = atoi(argv[2]);
373 if (argc > 3)
374 num_routes = atoi(argv[3]);
375
376 /* Set umask before anything for security */
377 umask(0027);
378
379 /* master init. */
380 master = thread_master_create(NULL);
381
382 zlog_aux_init("NONE: ", ZLOG_DISABLED);
383
384 /* Library inits. */
385 cmd_init(1);
386 cmd_hostname_set("test");
387 vty_init(master, false);
388 lib_cmd_init();
389 nb_init(master, modules, array_size(modules), false);
390
391 /* Create artificial data. */
392 create_data(num_vrfs, num_interfaces, num_routes);
393
394 /* Read input from .in file. */
395 vty_stdio(vty_do_exit);
396
397 /* Fetch next active thread. */
398 while (thread_fetch(master, &thread))
399 thread_call(&thread);
400
401 /* Not reached. */
402 exit(0);
403 }