]> git.proxmox.com Git - mirror_frr.git/blob - tests/lib/northbound/test_oper_data.c
7c5713d8f99ce5c50a0a8e0d9782026ca34c6879
[mirror_frr.git] / tests / lib / northbound / test_oper_data.c
1 /*
2 * Copyright (C) 2018 NetDEF, Inc.
3 * Renato Westphal
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include <zebra.h>
21
22 #include "thread.h"
23 #include "vty.h"
24 #include "command.h"
25 #include "memory.h"
26 #include "memory_vty.h"
27 #include "log.h"
28 #include "northbound.h"
29
30 static struct thread_master *master;
31
32 struct troute {
33 struct prefix_ipv4 prefix;
34 struct in_addr nexthop;
35 char ifname[IFNAMSIZ];
36 uint8_t metric;
37 bool active;
38 };
39
40 struct tvrf {
41 char name[32];
42 struct list *interfaces;
43 struct list *routes;
44 };
45
46 static struct list *vrfs;
47
48 /*
49 * XPath: /frr-test-module:frr-test-module/vrfs/vrf
50 */
51 static const void *
52 frr_test_module_vrfs_vrf_get_next(const void *parent_list_entry,
53 const void *list_entry)
54 {
55 struct listnode *node;
56
57 if (list_entry == NULL)
58 node = listhead(vrfs);
59 else
60 node = listnextnode((struct listnode *)list_entry);
61
62 return node;
63 }
64
65 static int frr_test_module_vrfs_vrf_get_keys(const void *list_entry,
66 struct yang_list_keys *keys)
67 {
68 const struct tvrf *vrf;
69
70 vrf = listgetdata((struct listnode *)list_entry);
71
72 keys->num = 1;
73 strlcpy(keys->key[0], vrf->name, sizeof(keys->key[0]));
74
75 return NB_OK;
76 }
77
78 static const void *
79 frr_test_module_vrfs_vrf_lookup_entry(const void *parent_list_entry,
80 const struct yang_list_keys *keys)
81 {
82 struct listnode *node;
83 struct tvrf *vrf;
84 const char *vrfname;
85
86 vrfname = keys->key[0];
87
88 for (ALL_LIST_ELEMENTS_RO(vrfs, node, vrf)) {
89 if (strmatch(vrf->name, vrfname))
90 return node;
91 }
92
93 return NULL;
94 }
95
96 /*
97 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/name
98 */
99 static struct yang_data *
100 frr_test_module_vrfs_vrf_name_get_elem(const char *xpath,
101 const void *list_entry)
102 {
103 const struct tvrf *vrf;
104
105 vrf = listgetdata((struct listnode *)list_entry);
106 return yang_data_new_string(xpath, vrf->name);
107 }
108
109 /*
110 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/interfaces/interface
111 */
112 static struct yang_data *
113 frr_test_module_vrfs_vrf_interfaces_interface_get_elem(const char *xpath,
114 const void *list_entry)
115 {
116 const char *interface;
117
118 interface = listgetdata((struct listnode *)list_entry);
119 return yang_data_new_string(xpath, interface);
120 }
121
122 static const void *frr_test_module_vrfs_vrf_interfaces_interface_get_next(
123 const void *parent_list_entry, const void *list_entry)
124 {
125 const struct tvrf *vrf;
126 struct listnode *node;
127
128 vrf = listgetdata((struct listnode *)parent_list_entry);
129 if (list_entry == NULL)
130 node = listhead(vrf->interfaces);
131 else
132 node = listnextnode((struct listnode *)list_entry);
133
134 return node;
135 }
136
137 /*
138 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route
139 */
140 static const void *
141 frr_test_module_vrfs_vrf_routes_route_get_next(const void *parent_list_entry,
142 const void *list_entry)
143 {
144 const struct tvrf *vrf;
145 struct listnode *node;
146
147 vrf = listgetdata((struct listnode *)parent_list_entry);
148 if (list_entry == NULL)
149 node = listhead(vrf->routes);
150 else
151 node = listnextnode((struct listnode *)list_entry);
152
153 return node;
154 }
155
156 static int
157 frr_test_module_vrfs_vrf_routes_route_get_keys(const void *list_entry,
158 struct yang_list_keys *keys)
159 {
160 const struct troute *route;
161
162 route = listgetdata((struct listnode *)list_entry);
163
164 keys->num = 1;
165 (void)prefix2str(&route->prefix, keys->key[0], sizeof(keys->key[0]));
166
167 return NB_OK;
168 }
169
170 static const void *frr_test_module_vrfs_vrf_routes_route_lookup_entry(
171 const void *parent_list_entry, const struct yang_list_keys *keys)
172 {
173 const struct tvrf *vrf;
174 const struct troute *route;
175 struct listnode *node;
176 struct prefix prefix;
177
178 yang_str2ipv4p(keys->key[0], &prefix);
179
180 vrf = listgetdata((struct listnode *)parent_list_entry);
181 for (ALL_LIST_ELEMENTS_RO(vrf->routes, node, route)) {
182 if (prefix_same((struct prefix *)&route->prefix, &prefix))
183 return node;
184 }
185
186 return NULL;
187 }
188
189 /*
190 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/prefix
191 */
192 static struct yang_data *
193 frr_test_module_vrfs_vrf_routes_route_prefix_get_elem(const char *xpath,
194 const void *list_entry)
195 {
196 const struct troute *route;
197
198 route = listgetdata((struct listnode *)list_entry);
199 return yang_data_new_ipv4p(xpath, &route->prefix);
200 }
201
202 /*
203 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/next-hop
204 */
205 static struct yang_data *
206 frr_test_module_vrfs_vrf_routes_route_next_hop_get_elem(const char *xpath,
207 const void *list_entry)
208 {
209 const struct troute *route;
210
211 route = listgetdata((struct listnode *)list_entry);
212 return yang_data_new_ipv4(xpath, &route->nexthop);
213 }
214
215 /*
216 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/interface
217 */
218 static struct yang_data *
219 frr_test_module_vrfs_vrf_routes_route_interface_get_elem(const char *xpath,
220 const void *list_entry)
221 {
222 const struct troute *route;
223
224 route = listgetdata((struct listnode *)list_entry);
225 return yang_data_new_string(xpath, route->ifname);
226 }
227
228 /*
229 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/metric
230 */
231 static struct yang_data *
232 frr_test_module_vrfs_vrf_routes_route_metric_get_elem(const char *xpath,
233 const void *list_entry)
234 {
235 const struct troute *route;
236
237 route = listgetdata((struct listnode *)list_entry);
238 return yang_data_new_uint8(xpath, route->metric);
239 }
240
241 /*
242 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/active
243 */
244 static struct yang_data *
245 frr_test_module_vrfs_vrf_routes_route_active_get_elem(const char *xpath,
246 const void *list_entry)
247 {
248 const struct troute *route;
249
250 route = listgetdata((struct listnode *)list_entry);
251 if (route->active)
252 return yang_data_new(xpath, NULL);
253
254 return NULL;
255 }
256
257 /* clang-format off */
258 const struct frr_yang_module_info frr_test_module_info = {
259 .name = "frr-test-module",
260 .nodes = {
261 {
262 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf",
263 .cbs.get_next = frr_test_module_vrfs_vrf_get_next,
264 .cbs.get_keys = frr_test_module_vrfs_vrf_get_keys,
265 .cbs.lookup_entry = frr_test_module_vrfs_vrf_lookup_entry,
266 },
267 {
268 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/name",
269 .cbs.get_elem = frr_test_module_vrfs_vrf_name_get_elem,
270 },
271 {
272 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/interfaces/interface",
273 .cbs.get_elem = frr_test_module_vrfs_vrf_interfaces_interface_get_elem,
274 .cbs.get_next = frr_test_module_vrfs_vrf_interfaces_interface_get_next,
275 },
276 {
277 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route",
278 .cbs.get_next = frr_test_module_vrfs_vrf_routes_route_get_next,
279 .cbs.get_keys = frr_test_module_vrfs_vrf_routes_route_get_keys,
280 .cbs.lookup_entry = frr_test_module_vrfs_vrf_routes_route_lookup_entry,
281 },
282 {
283 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/prefix",
284 .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_prefix_get_elem,
285 },
286 {
287 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/next-hop",
288 .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_next_hop_get_elem,
289 },
290 {
291 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/interface",
292 .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_interface_get_elem,
293 },
294 {
295 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/metric",
296 .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_metric_get_elem,
297 },
298 {
299 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/active",
300 .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_active_get_elem,
301 },
302 {
303 .xpath = NULL,
304 },
305 }
306 };
307 /* clang-format on */
308
309 static const struct frr_yang_module_info *modules[] = {
310 &frr_test_module_info,
311 };
312
313 static void create_data(unsigned int num_vrfs, unsigned int num_interfaces,
314 unsigned int num_routes)
315 {
316 struct prefix_ipv4 base_prefix;
317 struct in_addr base_nexthop;
318
319 (void)str2prefix_ipv4("10.0.0.0/32", &base_prefix);
320 (void)inet_pton(AF_INET, "172.16.0.0", &base_nexthop);
321
322 vrfs = list_new();
323
324 /* Create VRFs. */
325 for (unsigned int i = 0; i < num_vrfs; i++) {
326 struct tvrf *vrf;
327
328 vrf = XCALLOC(MTYPE_TMP, sizeof(*vrf));
329 snprintf(vrf->name, sizeof(vrf->name), "vrf%u", i);
330 vrf->interfaces = list_new();
331 vrf->routes = list_new();
332
333 /* Create interfaces. */
334 for (unsigned int j = 0; j < num_interfaces; j++) {
335 char ifname[32];
336 char *interface;
337
338 snprintf(ifname, sizeof(ifname), "eth%u", j);
339 interface = XSTRDUP(MTYPE_TMP, ifname);
340 listnode_add(vrf->interfaces, interface);
341 }
342
343 /* Create routes. */
344 for (unsigned int j = 0; j < num_routes; j++) {
345 struct troute *route;
346
347 route = XCALLOC(MTYPE_TMP, sizeof(*route));
348
349 memcpy(&route->prefix, &base_prefix,
350 sizeof(route->prefix));
351 route->prefix.prefix.s_addr =
352 htonl(ntohl(route->prefix.prefix.s_addr) + j);
353
354 memcpy(&route->nexthop, &base_nexthop,
355 sizeof(route->nexthop));
356 route->nexthop.s_addr =
357 htonl(ntohl(route->nexthop.s_addr) + j);
358
359 snprintf(route->ifname, sizeof(route->ifname), "eth%u",
360 j);
361 route->metric = j % 256;
362 route->active = (j % 2 == 0);
363 listnode_add(vrf->routes, route);
364 }
365
366 listnode_add(vrfs, vrf);
367 }
368 }
369
370 static void interface_delete(void *ptr)
371 {
372 char *interface = ptr;
373
374 XFREE(MTYPE_TMP, interface);
375 }
376
377 static void route_delete(void *ptr)
378 {
379 struct troute *route = ptr;
380
381 XFREE(MTYPE_TMP, route);
382 }
383
384 static void vrf_delete(void *ptr)
385 {
386 struct tvrf *vrf = ptr;
387
388 vrf->interfaces->del = interface_delete;
389 list_delete(&vrf->interfaces);
390 vrf->routes->del = route_delete;
391 list_delete(&vrf->routes);
392 XFREE(MTYPE_TMP, vrf);
393 }
394
395 static void delete_data(void)
396 {
397 vrfs->del = vrf_delete;
398 list_delete(&vrfs);
399 }
400
401 static void vty_do_exit(int isexit)
402 {
403 printf("\nend.\n");
404
405 delete_data();
406
407 cmd_terminate();
408 vty_terminate();
409 nb_terminate();
410 yang_terminate();
411 thread_master_free(master);
412 closezlog();
413
414 log_memstats(stderr, "test-nb-oper-data");
415 if (!isexit)
416 exit(0);
417 }
418
419 /* main routine. */
420 int main(int argc, char **argv)
421 {
422 struct thread thread;
423 unsigned int num_vrfs = 2;
424 unsigned int num_interfaces = 4;
425 unsigned int num_routes = 6;
426
427 if (argc > 1)
428 num_vrfs = atoi(argv[1]);
429 if (argc > 2)
430 num_interfaces = atoi(argv[2]);
431 if (argc > 3)
432 num_routes = atoi(argv[3]);
433
434 /* Set umask before anything for security */
435 umask(0027);
436
437 /* master init. */
438 master = thread_master_create(NULL);
439
440 openzlog("test-nb-oper-data", "NONE", 0,
441 LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
442 zlog_set_level(ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
443 zlog_set_level(ZLOG_DEST_STDOUT, ZLOG_DISABLED);
444 zlog_set_level(ZLOG_DEST_MONITOR, LOG_DEBUG);
445
446 /* Library inits. */
447 cmd_init(1);
448 cmd_hostname_set("test");
449 vty_init(master);
450 memory_init();
451 yang_init();
452 nb_init(master, modules, array_size(modules));
453
454 /* Create artificial data. */
455 create_data(num_vrfs, num_interfaces, num_routes);
456
457 /* Read input from .in file. */
458 vty_stdio(vty_do_exit);
459
460 /* Fetch next active thread. */
461 while (thread_fetch(master, &thread))
462 thread_call(&thread);
463
464 /* Not reached. */
465 exit(0);
466 }