]> git.proxmox.com Git - mirror_frr.git/blame - tools/gen_northbound_callbacks.c
tools: generate northbound code without warnings
[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
29static void __attribute__((noreturn)) usage(int status)
30{
88292d69
RZ
31 extern const char *__progname;
32 fprintf(stderr, "usage: %s [-h] [-p path] MODULE\n", __progname);
1c2facd1
RW
33 exit(status);
34}
35
36static 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 {
95ce849b 58 .operation = NB_OP_DESTROY,
1c2facd1
RW
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",
1a4bc045
RW
88 .arguments =
89 "const void *parent_list_entry, const void *list_entry",
1c2facd1
RW
90 },
91 {
92 .operation = NB_OP_GET_KEYS,
93 .return_type = "int ",
94 .return_value = "NB_OK",
1a4bc045
RW
95 .arguments =
96 "const void *list_entry, struct yang_list_keys *keys",
1c2facd1
RW
97 },
98 {
99 .operation = NB_OP_LOOKUP_ENTRY,
100 .return_type = "const void *",
101 .return_value = "NULL",
1a4bc045
RW
102 .arguments =
103 "const void *parent_list_entry, const struct yang_list_keys *keys",
1c2facd1
RW
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
118static 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
127static 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. */
db452508
RW
137 if (CHECK_FLAG(snode->nodetype, LYS_USES | LYS_CHOICE | LYS_CASE
138 | LYS_INPUT
139 | LYS_OUTPUT))
1c2facd1
RW
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
e0ccfad2 156static int generate_callbacks(const struct lys_node *snode, void *arg)
1c2facd1
RW
157{
158 bool first = true;
159
160 switch (snode->nodetype) {
161 case LYS_CONTAINER:
162 case LYS_LEAF:
163 case LYS_LEAFLIST:
164 case LYS_LIST:
165 case LYS_NOTIF:
166 case LYS_RPC:
167 break;
168 default:
e0ccfad2 169 return YANG_ITER_CONTINUE;
1c2facd1
RW
170 }
171
172 for (struct nb_callback_info *cb = &nb_callbacks[0];
173 cb->operation != -1; cb++) {
174 char cb_name[BUFSIZ];
175
176 if (cb->optional
177 || !nb_operation_is_valid(cb->operation, snode))
178 continue;
179
180 if (first) {
181 char xpath[XPATH_MAXLEN];
182
183 yang_snode_get_path(snode, YANG_PATH_DATA, xpath,
184 sizeof(xpath));
185
186 printf("/*\n"
187 " * XPath: %s\n"
188 " */\n",
189 xpath);
190 first = false;
191 }
192
193 generate_callback_name((struct lys_node *)snode, cb->operation,
194 cb_name, sizeof(cb_name));
195 printf("static %s%s(%s)\n"
196 "{\n"
197 "\t/* TODO: implement me. */\n"
198 "\treturn %s;\n"
199 "}\n\n",
200 nb_callbacks[cb->operation].return_type, cb_name,
201 nb_callbacks[cb->operation].arguments,
202 nb_callbacks[cb->operation].return_value);
203 }
e0ccfad2
RW
204
205 return YANG_ITER_CONTINUE;
1c2facd1
RW
206}
207
e0ccfad2 208static int generate_nb_nodes(const struct lys_node *snode, void *arg)
1c2facd1
RW
209{
210 bool first = true;
211
212 switch (snode->nodetype) {
213 case LYS_CONTAINER:
214 case LYS_LEAF:
215 case LYS_LEAFLIST:
216 case LYS_LIST:
217 case LYS_NOTIF:
218 case LYS_RPC:
219 break;
220 default:
e0ccfad2 221 return YANG_ITER_CONTINUE;
1c2facd1
RW
222 }
223
224 for (struct nb_callback_info *cb = &nb_callbacks[0];
225 cb->operation != -1; cb++) {
226 char cb_name[BUFSIZ];
227
228 if (cb->optional
229 || !nb_operation_is_valid(cb->operation, snode))
230 continue;
231
232 if (first) {
233 char xpath[XPATH_MAXLEN];
234
235 yang_snode_get_path(snode, YANG_PATH_DATA, xpath,
236 sizeof(xpath));
237
238 printf("\t\t{\n"
239 "\t\t\t.xpath = \"%s\",\n",
240 xpath);
13080468 241 printf("\t\t\t.cbs = {\n");
1c2facd1
RW
242 first = false;
243 }
244
245 generate_callback_name((struct lys_node *)snode, cb->operation,
246 cb_name, sizeof(cb_name));
13080468
RZ
247 printf("\t\t\t\t.%s = %s,\n", nb_operation_name(cb->operation),
248 cb_name);
1c2facd1
RW
249 }
250
13080468
RZ
251 if (!first) {
252 printf("\t\t\t}\n");
1c2facd1 253 printf("\t\t},\n");
13080468 254 }
e0ccfad2
RW
255
256 return YANG_ITER_CONTINUE;
1c2facd1
RW
257}
258
259int main(int argc, char *argv[])
260{
88292d69 261 const char *search_path = NULL;
1c2facd1
RW
262 struct yang_module *module;
263 char module_name_underscores[64];
88292d69 264 struct stat st;
1c2facd1
RW
265 int opt;
266
88292d69 267 while ((opt = getopt(argc, argv, "hp:")) != -1) {
1c2facd1
RW
268 switch (opt) {
269 case 'h':
270 usage(EXIT_SUCCESS);
271 /* NOTREACHED */
88292d69
RZ
272 case 'p':
273 if (stat(optarg, &st) == -1) {
274 fprintf(stderr,
275 "error: invalid search path '%s': %s\n",
276 optarg, strerror(errno));
277 exit(EXIT_FAILURE);
278 }
279 if (S_ISDIR(st.st_mode) == 0) {
280 fprintf(stderr,
281 "error: search path is not directory");
282 exit(EXIT_FAILURE);
283 }
284
285 search_path = optarg;
286 break;
1c2facd1
RW
287 default:
288 usage(EXIT_FAILURE);
289 /* NOTREACHED */
290 }
291 }
292 argc -= optind;
293 argv += optind;
294 if (argc != 1)
295 usage(EXIT_FAILURE);
296
297 yang_init();
298
88292d69
RZ
299 if (search_path)
300 ly_ctx_set_searchdir(ly_native_ctx, search_path);
301
544ca69a
RW
302 /* Load all FRR native models to ensure all augmentations are loaded. */
303 yang_module_load_all();
304 module = yang_module_find(argv[0]);
305 if (!module)
306 /* Non-native FRR module (e.g. modules from unit tests). */
307 module = yang_module_load(argv[0]);
308
309 /* Create a nb_node for all YANG schema nodes. */
310 nb_nodes_create();
1c2facd1
RW
311
312 /* Generate callback functions. */
e0ccfad2 313 yang_snodes_iterate_module(module->info, generate_callbacks, 0, NULL);
1c2facd1
RW
314
315 strlcpy(module_name_underscores, module->name,
316 sizeof(module_name_underscores));
317 replace_hyphens_by_underscores(module_name_underscores);
318
319 /* Generate frr_yang_module_info array. */
320 printf("/* clang-format off */\n"
321 "const struct frr_yang_module_info %s_info = {\n"
322 "\t.name = \"%s\",\n"
323 "\t.nodes = {\n",
324 module_name_underscores, module->name);
e0ccfad2 325 yang_snodes_iterate_module(module->info, generate_nb_nodes, 0, NULL);
1c2facd1
RW
326 printf("\t\t{\n"
327 "\t\t\t.xpath = NULL,\n"
328 "\t\t},\n");
329 printf("\t}\n"
330 "};\n");
331
332 /* Cleanup and exit. */
544ca69a 333 nb_nodes_delete();
1c2facd1
RW
334 yang_terminate();
335
336 return 0;
337}