]> git.proxmox.com Git - mirror_frr.git/blob - lib/yang_translator.c
Merge pull request #8665 from volta-networks/fix_pathd_coverity
[mirror_frr.git] / lib / yang_translator.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 #include <zebra.h>
21
22 #include "log.h"
23 #include "lib_errors.h"
24 #include "hash.h"
25 #include "yang.h"
26 #include "yang_translator.h"
27 #include "frrstr.h"
28
29 DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR, "YANG Translator");
30 DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR_MODULE, "YANG Translator Module");
31 DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR_MAPPING, "YANG Translator Mapping");
32
33 /* Generate the yang_translators tree. */
34 static inline int yang_translator_compare(const struct yang_translator *a,
35 const struct yang_translator *b)
36 {
37 return strcmp(a->family, b->family);
38 }
39 RB_GENERATE(yang_translators, yang_translator, entry, yang_translator_compare)
40
41 struct yang_translators yang_translators = RB_INITIALIZER(&yang_translators);
42
43 /* Separate libyang context for the translator module. */
44 static struct ly_ctx *ly_translator_ctx;
45
46 static unsigned int
47 yang_translator_validate(struct yang_translator *translator);
48 static unsigned int yang_module_nodes_count(const struct lys_module *module);
49
50 struct yang_mapping_node {
51 char xpath_from_canonical[XPATH_MAXLEN];
52 char xpath_from_fmt[XPATH_MAXLEN];
53 char xpath_to_fmt[XPATH_MAXLEN];
54 };
55
56 static bool yang_mapping_hash_cmp(const void *value1, const void *value2)
57 {
58 const struct yang_mapping_node *c1 = value1;
59 const struct yang_mapping_node *c2 = value2;
60
61 return strmatch(c1->xpath_from_canonical, c2->xpath_from_canonical);
62 }
63
64 static unsigned int yang_mapping_hash_key(const void *value)
65 {
66 return string_hash_make(value);
67 }
68
69 static void *yang_mapping_hash_alloc(void *p)
70 {
71 struct yang_mapping_node *new, *key = p;
72
73 new = XCALLOC(MTYPE_YANG_TRANSLATOR_MAPPING, sizeof(*new));
74 strlcpy(new->xpath_from_canonical, key->xpath_from_canonical,
75 sizeof(new->xpath_from_canonical));
76
77 return new;
78 }
79
80 static void yang_mapping_hash_free(void *arg)
81 {
82 XFREE(MTYPE_YANG_TRANSLATOR_MAPPING, arg);
83 }
84
85 static struct yang_mapping_node *
86 yang_mapping_lookup(const struct yang_translator *translator, int dir,
87 const char *xpath)
88 {
89 struct yang_mapping_node s;
90
91 strlcpy(s.xpath_from_canonical, xpath, sizeof(s.xpath_from_canonical));
92 return hash_lookup(translator->mappings[dir], &s);
93 }
94
95 static void yang_mapping_add(struct yang_translator *translator, int dir,
96 const struct lysc_node *snode,
97 const char *xpath_from_fmt,
98 const char *xpath_to_fmt)
99 {
100 struct yang_mapping_node *mapping, s;
101
102 yang_snode_get_path(snode, YANG_PATH_DATA, s.xpath_from_canonical,
103 sizeof(s.xpath_from_canonical));
104 mapping = hash_get(translator->mappings[dir], &s,
105 yang_mapping_hash_alloc);
106 strlcpy(mapping->xpath_from_fmt, xpath_from_fmt,
107 sizeof(mapping->xpath_from_fmt));
108 strlcpy(mapping->xpath_to_fmt, xpath_to_fmt,
109 sizeof(mapping->xpath_to_fmt));
110
111 const char *keys[] = {"KEY1", "KEY2", "KEY3", "KEY4"};
112 char *xpfmt;
113
114 for (unsigned int i = 0; i < array_size(keys); i++) {
115 xpfmt = frrstr_replace(mapping->xpath_from_fmt, keys[i],
116 "%[^']");
117 strlcpy(mapping->xpath_from_fmt, xpfmt,
118 sizeof(mapping->xpath_from_fmt));
119 XFREE(MTYPE_TMP, xpfmt);
120 }
121
122 for (unsigned int i = 0; i < array_size(keys); i++) {
123 xpfmt = frrstr_replace(mapping->xpath_to_fmt, keys[i], "%s");
124 strlcpy(mapping->xpath_to_fmt, xpfmt,
125 sizeof(mapping->xpath_to_fmt));
126 XFREE(MTYPE_TMP, xpfmt);
127 }
128 }
129
130 struct yang_translator *yang_translator_load(const char *path)
131 {
132 struct yang_translator *translator;
133 struct yang_tmodule *tmodule;
134 const char *family;
135 struct lyd_node *dnode;
136 struct ly_set *set;
137 struct listnode *ln;
138 LY_ERR err;
139
140 /* Load module translator (JSON file). */
141 err = lyd_parse_data_path(ly_translator_ctx, path, LYD_JSON,
142 LYD_PARSE_NO_STATE, LYD_VALIDATE_NO_STATE,
143 &dnode);
144 if (err) {
145 flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD,
146 "%s: lyd_parse_path() failed: %d", __func__, err);
147 return NULL;
148 }
149 dnode = yang_dnode_get(dnode,
150 "/frr-module-translator:frr-module-translator");
151 /*
152 * libyang guarantees the "frr-module-translator" top-level container is
153 * always present since it contains mandatory child nodes.
154 */
155 assert(dnode);
156
157 family = yang_dnode_get_string(dnode, "./family");
158 translator = yang_translator_find(family);
159 if (translator != NULL) {
160 flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD,
161 "%s: module translator \"%s\" is loaded already",
162 __func__, family);
163 return NULL;
164 }
165
166 translator = XCALLOC(MTYPE_YANG_TRANSLATOR, sizeof(*translator));
167 strlcpy(translator->family, family, sizeof(translator->family));
168 translator->modules = list_new();
169 for (size_t i = 0; i < YANG_TRANSLATE_MAX; i++)
170 translator->mappings[i] = hash_create(yang_mapping_hash_key,
171 yang_mapping_hash_cmp,
172 "YANG translation table");
173 RB_INSERT(yang_translators, &yang_translators, translator);
174
175 /* Initialize the translator libyang context. */
176 translator->ly_ctx = yang_ctx_new_setup(false, false);
177 if (!translator->ly_ctx) {
178 flog_warn(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
179 goto error;
180 }
181
182 /* Load modules */
183 if (lyd_find_xpath(dnode, "./module", &set) != LY_SUCCESS)
184 assert(0); /* XXX libyang2: old ly1 code asserted success */
185
186 for (size_t i = 0; i < set->count; i++) {
187 const char *module_name;
188
189 tmodule =
190 XCALLOC(MTYPE_YANG_TRANSLATOR_MODULE, sizeof(*tmodule));
191
192 module_name = yang_dnode_get_string(set->dnodes[i], "./name");
193 tmodule->module = ly_ctx_load_module(translator->ly_ctx,
194 module_name, NULL, NULL);
195 if (!tmodule->module) {
196 flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD,
197 "%s: failed to load module: %s", __func__,
198 module_name);
199 ly_set_free(set, NULL);
200 goto error;
201 }
202 }
203
204 /* Count nodes in modules. */
205 for (ALL_LIST_ELEMENTS_RO(translator->modules, ln, tmodule)) {
206 tmodule->nodes_before_deviations =
207 yang_module_nodes_count(tmodule->module);
208 }
209
210 /* Load the deviations and count nodes again */
211 for (ALL_LIST_ELEMENTS_RO(translator->modules, ln, tmodule)) {
212 const char *module_name = tmodule->module->name;
213 tmodule->deviations = ly_ctx_load_module(
214 translator->ly_ctx, module_name, NULL, NULL);
215 if (!tmodule->deviations) {
216 flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD,
217 "%s: failed to load module: %s", __func__,
218 module_name);
219 ly_set_free(set, NULL);
220 goto error;
221 }
222
223 tmodule->nodes_after_deviations =
224 yang_module_nodes_count(tmodule->module);
225 }
226 ly_set_free(set, NULL);
227
228 /* Calculate the coverage. */
229 for (ALL_LIST_ELEMENTS_RO(translator->modules, ln, tmodule)) {
230 tmodule->coverage = ((double)tmodule->nodes_after_deviations
231 / (double)tmodule->nodes_before_deviations)
232 * 100;
233 }
234
235 /* Load mappings. */
236 if (lyd_find_xpath(dnode, "./module/mappings", &set) != LY_SUCCESS)
237 assert(0); /* XXX libyang2: old ly1 code asserted success */
238 for (size_t i = 0; i < set->count; i++) {
239 const char *xpath_custom, *xpath_native;
240 const struct lysc_node *snode_custom, *snode_native;
241
242 xpath_custom =
243 yang_dnode_get_string(set->dnodes[i], "./custom");
244
245 snode_custom = lys_find_path(translator->ly_ctx, NULL,
246 xpath_custom, 0);
247 if (!snode_custom) {
248 flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD,
249 "%s: unknown data path: %s", __func__,
250 xpath_custom);
251 ly_set_free(set, NULL);
252 goto error;
253 }
254
255 xpath_native =
256 yang_dnode_get_string(set->dnodes[i], "./native");
257 snode_native =
258 lys_find_path(ly_native_ctx, NULL, xpath_native, 0);
259 if (!snode_native) {
260 flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD,
261 "%s: unknown data path: %s", __func__,
262 xpath_native);
263 ly_set_free(set, NULL);
264 goto error;
265 }
266
267 yang_mapping_add(translator, YANG_TRANSLATE_TO_NATIVE,
268 snode_custom, xpath_custom, xpath_native);
269 yang_mapping_add(translator, YANG_TRANSLATE_FROM_NATIVE,
270 snode_native, xpath_native, xpath_custom);
271 }
272 ly_set_free(set, NULL);
273
274 /* Validate mappings. */
275 if (yang_translator_validate(translator) != 0)
276 goto error;
277
278 yang_dnode_free(dnode);
279
280 return translator;
281
282 error:
283 yang_dnode_free(dnode);
284 yang_translator_unload(translator);
285
286 return NULL;
287 }
288
289 static void yang_tmodule_delete(struct yang_tmodule *tmodule)
290 {
291 XFREE(MTYPE_YANG_TRANSLATOR_MODULE, tmodule);
292 }
293
294 void yang_translator_unload(struct yang_translator *translator)
295 {
296 for (size_t i = 0; i < YANG_TRANSLATE_MAX; i++)
297 hash_clean(translator->mappings[i], yang_mapping_hash_free);
298 translator->modules->del = (void (*)(void *))yang_tmodule_delete;
299 list_delete(&translator->modules);
300 ly_ctx_destroy(translator->ly_ctx);
301 RB_REMOVE(yang_translators, &yang_translators, translator);
302 XFREE(MTYPE_YANG_TRANSLATOR, translator);
303 }
304
305 struct yang_translator *yang_translator_find(const char *family)
306 {
307 struct yang_translator s;
308
309 strlcpy(s.family, family, sizeof(s.family));
310 return RB_FIND(yang_translators, &yang_translators, &s);
311 }
312
313 enum yang_translate_result
314 yang_translate_xpath(const struct yang_translator *translator, int dir,
315 char *xpath, size_t xpath_len)
316 {
317 struct ly_ctx *ly_ctx;
318 const struct lysc_node *snode;
319 struct yang_mapping_node *mapping;
320 char xpath_canonical[XPATH_MAXLEN];
321 char keys[4][LIST_MAXKEYLEN];
322 int n;
323
324 if (dir == YANG_TRANSLATE_TO_NATIVE)
325 ly_ctx = translator->ly_ctx;
326 else
327 ly_ctx = ly_native_ctx;
328
329 snode = lys_find_path(ly_ctx, NULL, xpath, 0);
330 if (!snode) {
331 flog_warn(EC_LIB_YANG_TRANSLATION_ERROR,
332 "%s: unknown data path: %s", __func__, xpath);
333 return YANG_TRANSLATE_FAILURE;
334 }
335
336 yang_snode_get_path(snode, YANG_PATH_DATA, xpath_canonical,
337 sizeof(xpath_canonical));
338 mapping = yang_mapping_lookup(translator, dir, xpath_canonical);
339 if (!mapping)
340 return YANG_TRANSLATE_NOTFOUND;
341
342 n = sscanf(xpath, mapping->xpath_from_fmt, keys[0], keys[1], keys[2],
343 keys[3]);
344 if (n < 0) {
345 flog_warn(EC_LIB_YANG_TRANSLATION_ERROR,
346 "%s: sscanf() failed: %s", __func__,
347 safe_strerror(errno));
348 return YANG_TRANSLATE_FAILURE;
349 }
350
351 snprintf(xpath, xpath_len, mapping->xpath_to_fmt, keys[0], keys[1],
352 keys[2], keys[3]);
353
354 return YANG_TRANSLATE_SUCCESS;
355 }
356
357 int yang_translate_dnode(const struct yang_translator *translator, int dir,
358 struct lyd_node **dnode)
359 {
360 struct ly_ctx *ly_ctx;
361 struct lyd_node *new;
362 struct lyd_node *root, *dnode_iter;
363
364 /* Create new libyang data node to hold the translated data. */
365 if (dir == YANG_TRANSLATE_TO_NATIVE)
366 ly_ctx = ly_native_ctx;
367 else
368 ly_ctx = translator->ly_ctx;
369 new = yang_dnode_new(ly_ctx, false);
370
371 /* Iterate over all nodes from the data tree. */
372 LY_LIST_FOR (*dnode, root) {
373 LYD_TREE_DFS_BEGIN (root, dnode_iter) {
374 char xpath[XPATH_MAXLEN];
375 enum yang_translate_result ret;
376
377 yang_dnode_get_path(dnode_iter, xpath, sizeof(xpath));
378 ret = yang_translate_xpath(translator, dir, xpath,
379 sizeof(xpath));
380 switch (ret) {
381 case YANG_TRANSLATE_SUCCESS:
382 break;
383 case YANG_TRANSLATE_NOTFOUND:
384 goto next;
385 case YANG_TRANSLATE_FAILURE:
386 goto error;
387 }
388
389 /* Create new node in the tree of translated data. */
390 if (lyd_new_path(new, ly_ctx, xpath,
391 (void *)yang_dnode_get_string(
392 dnode_iter, NULL),
393 LYD_NEW_PATH_UPDATE, NULL)) {
394 flog_err(EC_LIB_LIBYANG,
395 "%s: lyd_new_path() failed", __func__);
396 goto error;
397 }
398
399 next:
400 LYD_TREE_DFS_END(root, dnode_iter);
401 }
402 }
403
404 /* Replace dnode by the new translated dnode. */
405 yang_dnode_free(*dnode);
406 *dnode = new;
407
408 return YANG_TRANSLATE_SUCCESS;
409
410 error:
411 yang_dnode_free(new);
412
413 return YANG_TRANSLATE_FAILURE;
414 }
415
416 struct translator_validate_args {
417 struct yang_translator *translator;
418 unsigned int errors;
419 };
420
421 static int yang_translator_validate_cb(const struct lysc_node *snode_custom,
422 void *arg)
423 {
424 struct translator_validate_args *args = arg;
425 struct yang_mapping_node *mapping;
426 const struct lysc_node *snode_native;
427 const struct lysc_type *stype_custom, *stype_native;
428 char xpath[XPATH_MAXLEN];
429
430 yang_snode_get_path(snode_custom, YANG_PATH_DATA, xpath, sizeof(xpath));
431 mapping = yang_mapping_lookup(args->translator,
432 YANG_TRANSLATE_TO_NATIVE, xpath);
433 if (!mapping) {
434 flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD,
435 "%s: missing mapping for \"%s\"", __func__, xpath);
436 args->errors += 1;
437 return YANG_ITER_CONTINUE;
438 }
439
440 snode_native =
441 lys_find_path(ly_native_ctx, NULL, mapping->xpath_to_fmt, 0);
442 assert(snode_native);
443
444 /* Check if the YANG types are compatible. */
445 stype_custom = yang_snode_get_type(snode_custom);
446 stype_native = yang_snode_get_type(snode_native);
447 if (stype_custom && stype_native) {
448 if (stype_custom->basetype != stype_native->basetype) {
449 flog_warn(
450 EC_LIB_YANG_TRANSLATOR_LOAD,
451 "%s: YANG types are incompatible (xpath: \"%s\")",
452 __func__, xpath);
453 args->errors += 1;
454 return YANG_ITER_CONTINUE;
455 }
456
457 /* TODO: check if the value spaces are identical. */
458 }
459
460 return YANG_ITER_CONTINUE;
461 }
462
463 /*
464 * Check if the modules from the translator have a mapping for all of their
465 * schema nodes (after loading the deviations).
466 */
467 static unsigned int yang_translator_validate(struct yang_translator *translator)
468 {
469 struct yang_tmodule *tmodule;
470 struct listnode *ln;
471 struct translator_validate_args args;
472
473 args.translator = translator;
474 args.errors = 0;
475
476 for (ALL_LIST_ELEMENTS_RO(translator->modules, ln, tmodule)) {
477 yang_snodes_iterate(tmodule->module,
478 yang_translator_validate_cb,
479 YANG_ITER_FILTER_NPCONTAINERS
480 | YANG_ITER_FILTER_LIST_KEYS
481 | YANG_ITER_FILTER_INPUT_OUTPUT,
482 &args);
483 }
484
485 if (args.errors)
486 flog_warn(
487 EC_LIB_YANG_TRANSLATOR_LOAD,
488 "%s: failed to validate \"%s\" module translator: %u error(s)",
489 __func__, translator->family, args.errors);
490
491 return args.errors;
492 }
493
494 static int yang_module_nodes_count_cb(const struct lysc_node *snode, void *arg)
495 {
496 unsigned int *total = arg;
497
498 *total += 1;
499
500 return YANG_ITER_CONTINUE;
501 }
502
503 /* Calculate the number of nodes for the given module. */
504 static unsigned int yang_module_nodes_count(const struct lys_module *module)
505 {
506 unsigned int total = 0;
507
508 yang_snodes_iterate(module, yang_module_nodes_count_cb,
509 YANG_ITER_FILTER_NPCONTAINERS
510 | YANG_ITER_FILTER_LIST_KEYS
511 | YANG_ITER_FILTER_INPUT_OUTPUT,
512 &total);
513
514 return total;
515 }
516
517 void yang_translator_init(void)
518 {
519 ly_translator_ctx = yang_ctx_new_setup(true, false);
520 if (!ly_translator_ctx) {
521 flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
522 exit(1);
523 }
524
525 if (!ly_ctx_load_module(ly_translator_ctx, "frr-module-translator",
526 NULL, NULL)) {
527 flog_err(
528 EC_LIB_YANG_MODULE_LOAD,
529 "%s: failed to load the \"frr-module-translator\" module",
530 __func__);
531 exit(1);
532 }
533 }
534
535 void yang_translator_terminate(void)
536 {
537 while (!RB_EMPTY(yang_translators, &yang_translators)) {
538 struct yang_translator *translator;
539
540 translator = RB_ROOT(yang_translators, &yang_translators);
541 yang_translator_unload(translator);
542 }
543
544 ly_ctx_destroy(ly_translator_ctx);
545 }