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