]> git.proxmox.com Git - mirror_frr.git/blame - tools/gen_northbound_callbacks.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / tools / gen_northbound_callbacks.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
1c2facd1
RW
2/*
3 * Copyright (C) 2018 NetDEF, Inc.
4 * Renato Westphal
1c2facd1
RW
5 */
6
7#define REALLY_NEED_PLAIN_GETOPT 1
8
9#include <zebra.h>
10
11#include <unistd.h>
12
13#include "yang.h"
14#include "northbound.h"
15
f5f0a0e3
RW
16static bool static_cbs;
17
1c2facd1
RW
18static void __attribute__((noreturn)) usage(int status)
19{
88292d69 20 extern const char *__progname;
f5f0a0e3 21 fprintf(stderr, "usage: %s [-h] [-s] [-p path] MODULE\n", __progname);
1c2facd1
RW
22 exit(status);
23}
24
25static struct nb_callback_info {
26 int operation;
27 bool optional;
28 char return_type[32];
29 char return_value[32];
30 char arguments[128];
31} nb_callbacks[] = {
32 {
33 .operation = NB_OP_CREATE,
34 .return_type = "int ",
35 .return_value = "NB_OK",
60ee8be1 36 .arguments = "struct nb_cb_create_args *args",
1c2facd1
RW
37 },
38 {
39 .operation = NB_OP_MODIFY,
40 .return_type = "int ",
41 .return_value = "NB_OK",
60ee8be1 42 .arguments = "struct nb_cb_modify_args *args",
1c2facd1
RW
43 },
44 {
95ce849b 45 .operation = NB_OP_DESTROY,
1c2facd1
RW
46 .return_type = "int ",
47 .return_value = "NB_OK",
60ee8be1 48 .arguments = "struct nb_cb_destroy_args *args",
1c2facd1
RW
49 },
50 {
51 .operation = NB_OP_MOVE,
52 .return_type = "int ",
53 .return_value = "NB_OK",
60ee8be1 54 .arguments = "struct nb_cb_move_args *args",
1c2facd1
RW
55 },
56 {
57 .operation = NB_OP_APPLY_FINISH,
58 .optional = true,
59 .return_type = "void ",
60 .return_value = "",
60ee8be1 61 .arguments = "struct nb_cb_apply_finish_args *args",
1c2facd1
RW
62 },
63 {
64 .operation = NB_OP_GET_ELEM,
65 .return_type = "struct yang_data *",
66 .return_value = "NULL",
60ee8be1 67 .arguments = "struct nb_cb_get_elem_args *args",
1c2facd1
RW
68 },
69 {
70 .operation = NB_OP_GET_NEXT,
71 .return_type = "const void *",
72 .return_value = "NULL",
60ee8be1 73 .arguments = "struct nb_cb_get_next_args *args",
1c2facd1
RW
74 },
75 {
76 .operation = NB_OP_GET_KEYS,
77 .return_type = "int ",
78 .return_value = "NB_OK",
60ee8be1 79 .arguments = "struct nb_cb_get_keys_args *args",
1c2facd1
RW
80 },
81 {
82 .operation = NB_OP_LOOKUP_ENTRY,
83 .return_type = "const void *",
84 .return_value = "NULL",
60ee8be1 85 .arguments = "struct nb_cb_lookup_entry_args *args",
1c2facd1
RW
86 },
87 {
88 .operation = NB_OP_RPC,
89 .return_type = "int ",
90 .return_value = "NB_OK",
60ee8be1 91 .arguments = "struct nb_cb_rpc_args *args",
1c2facd1
RW
92 },
93 {
94 /* sentinel */
95 .operation = -1,
96 },
97};
98
99static void replace_hyphens_by_underscores(char *str)
100{
101 char *p;
102
103 p = str;
104 while ((p = strchr(p, '-')) != NULL)
105 *p++ = '_';
106}
107
3bb513c3 108static void generate_callback_name(const struct lysc_node *snode,
1c2facd1
RW
109 enum nb_operation operation, char *buffer,
110 size_t size)
111{
112 struct list *snodes;
113 struct listnode *ln;
114
115 snodes = list_new();
3bb513c3 116 for (; snode; snode = snode->parent) {
1c2facd1 117 /* Skip schema-only snodes. */
db452508
RW
118 if (CHECK_FLAG(snode->nodetype, LYS_USES | LYS_CHOICE | LYS_CASE
119 | LYS_INPUT
120 | LYS_OUTPUT))
1c2facd1
RW
121 continue;
122
3bb513c3 123 listnode_add_head(snodes, (void *)snode);
1c2facd1
RW
124 }
125
126 memset(buffer, 0, size);
127 for (ALL_LIST_ELEMENTS_RO(snodes, ln, snode)) {
128 strlcat(buffer, snode->name, size);
129 strlcat(buffer, "_", size);
130 }
131 strlcat(buffer, nb_operation_name(operation), size);
132 list_delete(&snodes);
133
134 replace_hyphens_by_underscores(buffer);
135}
136
f5f0a0e3
RW
137static void generate_prototype(const struct nb_callback_info *ncinfo,
138 const char *cb_name)
139{
140 printf("%s%s(%s);\n", ncinfo->return_type, cb_name, ncinfo->arguments);
141}
142
3bb513c3 143static int generate_prototypes(const struct lysc_node *snode, void *arg)
f5f0a0e3
RW
144{
145 switch (snode->nodetype) {
146 case LYS_CONTAINER:
147 case LYS_LEAF:
148 case LYS_LEAFLIST:
149 case LYS_LIST:
150 case LYS_NOTIF:
151 case LYS_RPC:
152 break;
153 default:
154 return YANG_ITER_CONTINUE;
155 }
156
157 for (struct nb_callback_info *cb = &nb_callbacks[0];
158 cb->operation != -1; cb++) {
159 char cb_name[BUFSIZ];
160
161 if (cb->optional
162 || !nb_operation_is_valid(cb->operation, snode))
163 continue;
164
3bb513c3
CH
165 generate_callback_name(snode, cb->operation, cb_name,
166 sizeof(cb_name));
f5f0a0e3
RW
167 generate_prototype(cb, cb_name);
168 }
169
170 return YANG_ITER_CONTINUE;
171}
172
c681616f
RZ
173static void generate_callback(const struct nb_callback_info *ncinfo,
174 const char *cb_name)
175{
f5f0a0e3 176 printf("%s%s%s(%s)\n{\n", static_cbs ? "static " : "",
c681616f
RZ
177 ncinfo->return_type, cb_name, ncinfo->arguments);
178
179 switch (ncinfo->operation) {
180 case NB_OP_CREATE:
181 case NB_OP_MODIFY:
182 case NB_OP_DESTROY:
183 case NB_OP_MOVE:
1c7f6245 184 printf("\tswitch (args->event) {\n"
c681616f
RZ
185 "\tcase NB_EV_VALIDATE:\n"
186 "\tcase NB_EV_PREPARE:\n"
187 "\tcase NB_EV_ABORT:\n"
188 "\tcase NB_EV_APPLY:\n"
189 "\t\t/* TODO: implement me. */\n"
190 "\t\tbreak;\n"
191 "\t}\n\n"
192 );
193 break;
194
195 default:
196 printf("\t/* TODO: implement me. */\n");
197 break;
198 }
199
200 printf("\treturn %s;\n}\n\n", ncinfo->return_value);
201}
202
3bb513c3 203static int generate_callbacks(const struct lysc_node *snode, void *arg)
1c2facd1
RW
204{
205 bool first = true;
206
207 switch (snode->nodetype) {
208 case LYS_CONTAINER:
209 case LYS_LEAF:
210 case LYS_LEAFLIST:
211 case LYS_LIST:
212 case LYS_NOTIF:
213 case LYS_RPC:
214 break;
215 default:
e0ccfad2 216 return YANG_ITER_CONTINUE;
1c2facd1
RW
217 }
218
219 for (struct nb_callback_info *cb = &nb_callbacks[0];
220 cb->operation != -1; cb++) {
221 char cb_name[BUFSIZ];
222
223 if (cb->optional
224 || !nb_operation_is_valid(cb->operation, snode))
225 continue;
226
227 if (first) {
228 char xpath[XPATH_MAXLEN];
229
230 yang_snode_get_path(snode, YANG_PATH_DATA, xpath,
231 sizeof(xpath));
232
233 printf("/*\n"
234 " * XPath: %s\n"
235 " */\n",
236 xpath);
237 first = false;
238 }
239
3bb513c3
CH
240 generate_callback_name(snode, cb->operation, cb_name,
241 sizeof(cb_name));
c681616f 242 generate_callback(cb, cb_name);
1c2facd1 243 }
e0ccfad2
RW
244
245 return YANG_ITER_CONTINUE;
1c2facd1
RW
246}
247
3bb513c3 248static int generate_nb_nodes(const struct lysc_node *snode, void *arg)
1c2facd1
RW
249{
250 bool first = true;
251
252 switch (snode->nodetype) {
253 case LYS_CONTAINER:
254 case LYS_LEAF:
255 case LYS_LEAFLIST:
256 case LYS_LIST:
257 case LYS_NOTIF:
258 case LYS_RPC:
259 break;
260 default:
e0ccfad2 261 return YANG_ITER_CONTINUE;
1c2facd1
RW
262 }
263
264 for (struct nb_callback_info *cb = &nb_callbacks[0];
265 cb->operation != -1; cb++) {
266 char cb_name[BUFSIZ];
267
268 if (cb->optional
269 || !nb_operation_is_valid(cb->operation, snode))
270 continue;
271
272 if (first) {
273 char xpath[XPATH_MAXLEN];
274
275 yang_snode_get_path(snode, YANG_PATH_DATA, xpath,
276 sizeof(xpath));
277
278 printf("\t\t{\n"
279 "\t\t\t.xpath = \"%s\",\n",
280 xpath);
13080468 281 printf("\t\t\t.cbs = {\n");
1c2facd1
RW
282 first = false;
283 }
284
3bb513c3
CH
285 generate_callback_name(snode, cb->operation, cb_name,
286 sizeof(cb_name));
13080468
RZ
287 printf("\t\t\t\t.%s = %s,\n", nb_operation_name(cb->operation),
288 cb_name);
1c2facd1
RW
289 }
290
13080468
RZ
291 if (!first) {
292 printf("\t\t\t}\n");
1c2facd1 293 printf("\t\t},\n");
13080468 294 }
e0ccfad2
RW
295
296 return YANG_ITER_CONTINUE;
1c2facd1
RW
297}
298
299int main(int argc, char *argv[])
300{
88292d69 301 const char *search_path = NULL;
1c2facd1
RW
302 struct yang_module *module;
303 char module_name_underscores[64];
88292d69 304 struct stat st;
1c2facd1
RW
305 int opt;
306
f5f0a0e3 307 while ((opt = getopt(argc, argv, "hp:s")) != -1) {
1c2facd1
RW
308 switch (opt) {
309 case 'h':
310 usage(EXIT_SUCCESS);
311 /* NOTREACHED */
88292d69
RZ
312 case 'p':
313 if (stat(optarg, &st) == -1) {
314 fprintf(stderr,
315 "error: invalid search path '%s': %s\n",
316 optarg, strerror(errno));
317 exit(EXIT_FAILURE);
318 }
319 if (S_ISDIR(st.st_mode) == 0) {
320 fprintf(stderr,
321 "error: search path is not directory");
322 exit(EXIT_FAILURE);
323 }
324
325 search_path = optarg;
326 break;
f5f0a0e3
RW
327 case 's':
328 static_cbs = true;
329 break;
1c2facd1
RW
330 default:
331 usage(EXIT_FAILURE);
332 /* NOTREACHED */
333 }
334 }
335 argc -= optind;
336 argv += optind;
337 if (argc != 1)
338 usage(EXIT_FAILURE);
339
3bb513c3 340 yang_init(false, true);
1c2facd1 341
88292d69
RZ
342 if (search_path)
343 ly_ctx_set_searchdir(ly_native_ctx, search_path);
344
544ca69a
RW
345 /* Load all FRR native models to ensure all augmentations are loaded. */
346 yang_module_load_all();
3bb513c3 347
544ca69a
RW
348 module = yang_module_find(argv[0]);
349 if (!module)
350 /* Non-native FRR module (e.g. modules from unit tests). */
351 module = yang_module_load(argv[0]);
352
3bb513c3
CH
353 yang_init_loading_complete();
354
544ca69a
RW
355 /* Create a nb_node for all YANG schema nodes. */
356 nb_nodes_create();
1c2facd1 357
f5f0a0e3
RW
358 /* Generate callback prototypes. */
359 if (!static_cbs) {
360 printf("/* prototypes */\n");
8d869d37 361 yang_snodes_iterate(module->info, generate_prototypes, 0, NULL);
f5f0a0e3
RW
362 printf("\n");
363 }
364
1c2facd1 365 /* Generate callback functions. */
8d869d37 366 yang_snodes_iterate(module->info, generate_callbacks, 0, NULL);
1c2facd1
RW
367
368 strlcpy(module_name_underscores, module->name,
369 sizeof(module_name_underscores));
370 replace_hyphens_by_underscores(module_name_underscores);
371
372 /* Generate frr_yang_module_info array. */
373 printf("/* clang-format off */\n"
374 "const struct frr_yang_module_info %s_info = {\n"
375 "\t.name = \"%s\",\n"
376 "\t.nodes = {\n",
377 module_name_underscores, module->name);
8d869d37 378 yang_snodes_iterate(module->info, generate_nb_nodes, 0, NULL);
1c2facd1
RW
379 printf("\t\t{\n"
380 "\t\t\t.xpath = NULL,\n"
381 "\t\t},\n");
382 printf("\t}\n"
383 "};\n");
384
385 /* Cleanup and exit. */
544ca69a 386 nb_nodes_delete();
1c2facd1
RW
387 yang_terminate();
388
389 return 0;
390}