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