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