]> git.proxmox.com Git - mirror_frr.git/blob - tests/lib/northbound/test_oper_data.c
lib: rewrite zlog lock-free & TLS-buffered
[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 "lib_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 /*
157 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/prefix
158 */
159 static struct yang_data *
160 frr_test_module_vrfs_vrf_routes_route_prefix_get_elem(const char *xpath,
161 const void *list_entry)
162 {
163 const struct troute *route;
164
165 route = listgetdata((struct listnode *)list_entry);
166 return yang_data_new_ipv4p(xpath, &route->prefix);
167 }
168
169 /*
170 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/next-hop
171 */
172 static struct yang_data *
173 frr_test_module_vrfs_vrf_routes_route_next_hop_get_elem(const char *xpath,
174 const void *list_entry)
175 {
176 const struct troute *route;
177
178 route = listgetdata((struct listnode *)list_entry);
179 return yang_data_new_ipv4(xpath, &route->nexthop);
180 }
181
182 /*
183 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/interface
184 */
185 static struct yang_data *
186 frr_test_module_vrfs_vrf_routes_route_interface_get_elem(const char *xpath,
187 const void *list_entry)
188 {
189 const struct troute *route;
190
191 route = listgetdata((struct listnode *)list_entry);
192 return yang_data_new_string(xpath, route->ifname);
193 }
194
195 /*
196 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/metric
197 */
198 static struct yang_data *
199 frr_test_module_vrfs_vrf_routes_route_metric_get_elem(const char *xpath,
200 const void *list_entry)
201 {
202 const struct troute *route;
203
204 route = listgetdata((struct listnode *)list_entry);
205 return yang_data_new_uint8(xpath, route->metric);
206 }
207
208 /*
209 * XPath: /frr-test-module:frr-test-module/vrfs/vrf/routes/route/active
210 */
211 static struct yang_data *
212 frr_test_module_vrfs_vrf_routes_route_active_get_elem(const char *xpath,
213 const void *list_entry)
214 {
215 const struct troute *route;
216
217 route = listgetdata((struct listnode *)list_entry);
218 if (route->active)
219 return yang_data_new(xpath, NULL);
220
221 return NULL;
222 }
223
224 /* clang-format off */
225 const struct frr_yang_module_info frr_test_module_info = {
226 .name = "frr-test-module",
227 .nodes = {
228 {
229 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf",
230 .cbs.get_next = frr_test_module_vrfs_vrf_get_next,
231 .cbs.get_keys = frr_test_module_vrfs_vrf_get_keys,
232 .cbs.lookup_entry = frr_test_module_vrfs_vrf_lookup_entry,
233 },
234 {
235 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/name",
236 .cbs.get_elem = frr_test_module_vrfs_vrf_name_get_elem,
237 },
238 {
239 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/interfaces/interface",
240 .cbs.get_elem = frr_test_module_vrfs_vrf_interfaces_interface_get_elem,
241 .cbs.get_next = frr_test_module_vrfs_vrf_interfaces_interface_get_next,
242 },
243 {
244 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route",
245 .cbs.get_next = frr_test_module_vrfs_vrf_routes_route_get_next,
246 },
247 {
248 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/prefix",
249 .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_prefix_get_elem,
250 },
251 {
252 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/next-hop",
253 .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_next_hop_get_elem,
254 },
255 {
256 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/interface",
257 .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_interface_get_elem,
258 },
259 {
260 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/metric",
261 .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_metric_get_elem,
262 },
263 {
264 .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/active",
265 .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_active_get_elem,
266 },
267 {
268 .xpath = NULL,
269 },
270 }
271 };
272 /* clang-format on */
273
274 static const struct frr_yang_module_info *const modules[] = {
275 &frr_test_module_info,
276 };
277
278 static void create_data(unsigned int num_vrfs, unsigned int num_interfaces,
279 unsigned int num_routes)
280 {
281 struct prefix_ipv4 base_prefix;
282 struct in_addr base_nexthop;
283
284 (void)str2prefix_ipv4("10.0.0.0/32", &base_prefix);
285 (void)inet_pton(AF_INET, "172.16.0.0", &base_nexthop);
286
287 vrfs = list_new();
288
289 /* Create VRFs. */
290 for (unsigned int i = 0; i < num_vrfs; i++) {
291 struct tvrf *vrf;
292
293 vrf = XCALLOC(MTYPE_TMP, sizeof(*vrf));
294 snprintf(vrf->name, sizeof(vrf->name), "vrf%u", i);
295 vrf->interfaces = list_new();
296 vrf->routes = list_new();
297
298 /* Create interfaces. */
299 for (unsigned int j = 0; j < num_interfaces; j++) {
300 char ifname[32];
301 char *interface;
302
303 snprintf(ifname, sizeof(ifname), "eth%u", j);
304 interface = XSTRDUP(MTYPE_TMP, ifname);
305 listnode_add(vrf->interfaces, interface);
306 }
307
308 /* Create routes. */
309 for (unsigned int j = 0; j < num_routes; j++) {
310 struct troute *route;
311
312 route = XCALLOC(MTYPE_TMP, sizeof(*route));
313
314 memcpy(&route->prefix, &base_prefix,
315 sizeof(route->prefix));
316 route->prefix.prefix.s_addr =
317 htonl(ntohl(route->prefix.prefix.s_addr) + j);
318
319 memcpy(&route->nexthop, &base_nexthop,
320 sizeof(route->nexthop));
321 route->nexthop.s_addr =
322 htonl(ntohl(route->nexthop.s_addr) + j);
323
324 snprintf(route->ifname, sizeof(route->ifname), "eth%u",
325 j);
326 route->metric = j % 256;
327 route->active = (j % 2 == 0);
328 listnode_add(vrf->routes, route);
329 }
330
331 listnode_add(vrfs, vrf);
332 }
333 }
334
335 static void interface_delete(void *ptr)
336 {
337 char *interface = ptr;
338
339 XFREE(MTYPE_TMP, interface);
340 }
341
342 static void route_delete(void *ptr)
343 {
344 struct troute *route = ptr;
345
346 XFREE(MTYPE_TMP, route);
347 }
348
349 static void vrf_delete(void *ptr)
350 {
351 struct tvrf *vrf = ptr;
352
353 vrf->interfaces->del = interface_delete;
354 list_delete(&vrf->interfaces);
355 vrf->routes->del = route_delete;
356 list_delete(&vrf->routes);
357 XFREE(MTYPE_TMP, vrf);
358 }
359
360 static void delete_data(void)
361 {
362 vrfs->del = vrf_delete;
363 list_delete(&vrfs);
364 }
365
366 static void vty_do_exit(int isexit)
367 {
368 printf("\nend.\n");
369
370 delete_data();
371
372 cmd_terminate();
373 vty_terminate();
374 nb_terminate();
375 yang_terminate();
376 thread_master_free(master);
377
378 log_memstats(stderr, "test-nb-oper-data");
379 if (!isexit)
380 exit(0);
381 }
382
383 /* main routine. */
384 int main(int argc, char **argv)
385 {
386 struct thread thread;
387 unsigned int num_vrfs = 2;
388 unsigned int num_interfaces = 4;
389 unsigned int num_routes = 6;
390
391 if (argc > 1)
392 num_vrfs = atoi(argv[1]);
393 if (argc > 2)
394 num_interfaces = atoi(argv[2]);
395 if (argc > 3)
396 num_routes = atoi(argv[3]);
397
398 /* Set umask before anything for security */
399 umask(0027);
400
401 /* master init. */
402 master = thread_master_create(NULL);
403
404 zlog_aux_init("NONE: ", ZLOG_DISABLED);
405
406 /* Library inits. */
407 cmd_init(1);
408 cmd_hostname_set("test");
409 vty_init(master, false);
410 lib_cmd_init();
411 yang_init();
412 nb_init(master, modules, array_size(modules));
413
414 /* Create artificial data. */
415 create_data(num_vrfs, num_interfaces, num_routes);
416
417 /* Read input from .in file. */
418 vty_stdio(vty_do_exit);
419
420 /* Fetch next active thread. */
421 while (thread_fetch(master, &thread))
422 thread_call(&thread);
423
424 /* Not reached. */
425 exit(0);
426 }