]> git.proxmox.com Git - mirror_frr.git/blob - lib/yang.c
Merge pull request #3762 from pguibert6WIND/do_not_alloc_lists_fs_by_def
[mirror_frr.git] / lib / yang.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 "log_int.h"
24 #include "lib_errors.h"
25 #include "yang.h"
26 #include "yang_translator.h"
27 #include "northbound.h"
28
29 #include <libyang/user_types.h>
30
31 DEFINE_MTYPE(LIB, YANG_MODULE, "YANG module")
32 DEFINE_MTYPE(LIB, YANG_DATA, "YANG data structure")
33
34 /* libyang container. */
35 struct ly_ctx *ly_native_ctx;
36
37 static struct yang_module_embed *embeds, **embedupd = &embeds;
38
39 void yang_module_embed(struct yang_module_embed *embed)
40 {
41 embed->next = NULL;
42 *embedupd = embed;
43 embedupd = &embed->next;
44 }
45
46 static const char *yang_module_imp_clb(const char *mod_name,
47 const char *mod_rev,
48 const char *submod_name,
49 const char *submod_rev,
50 void *user_data,
51 LYS_INFORMAT *format,
52 void (**free_module_data)
53 (void *, void*))
54 {
55 struct yang_module_embed *e;
56
57 if (submod_name || submod_rev)
58 return NULL;
59
60 for (e = embeds; e; e = e->next) {
61 if (strcmp(e->mod_name, mod_name))
62 continue;
63 if (mod_rev && strcmp(e->mod_rev, mod_rev))
64 continue;
65
66 *format = e->format;
67 return e->data;
68 }
69
70 flog_warn(EC_LIB_YANG_MODULE_LOAD,
71 "YANG model \"%s@%s\" not embedded, trying external file",
72 mod_name, mod_rev ? mod_rev : "*");
73 return NULL;
74 }
75
76 static const char *const frr_native_modules[] = {
77 "frr-interface",
78 "frr-ripd",
79 "frr-ripngd",
80 "frr-isisd",
81 };
82
83 /* Generate the yang_modules tree. */
84 static inline int yang_module_compare(const struct yang_module *a,
85 const struct yang_module *b)
86 {
87 return strcmp(a->name, b->name);
88 }
89 RB_GENERATE(yang_modules, yang_module, entry, yang_module_compare)
90
91 struct yang_modules yang_modules = RB_INITIALIZER(&yang_modules);
92
93 struct yang_module *yang_module_load(const char *module_name)
94 {
95 struct yang_module *module;
96 const struct lys_module *module_info;
97
98 module_info = ly_ctx_load_module(ly_native_ctx, module_name, NULL);
99 if (!module_info) {
100 flog_err(EC_LIB_YANG_MODULE_LOAD,
101 "%s: failed to load data model: %s", __func__,
102 module_name);
103 exit(1);
104 }
105
106 module = XCALLOC(MTYPE_YANG_MODULE, sizeof(*module));
107 module->name = module_name;
108 module->info = module_info;
109
110 if (RB_INSERT(yang_modules, &yang_modules, module) != NULL) {
111 flog_err(EC_LIB_YANG_MODULE_LOADED_ALREADY,
112 "%s: YANG module is loaded already: %s", __func__,
113 module_name);
114 exit(1);
115 }
116
117 return module;
118 }
119
120 void yang_module_load_all(void)
121 {
122 for (size_t i = 0; i < array_size(frr_native_modules); i++)
123 yang_module_load(frr_native_modules[i]);
124 }
125
126 struct yang_module *yang_module_find(const char *module_name)
127 {
128 struct yang_module s;
129
130 s.name = module_name;
131 return RB_FIND(yang_modules, &yang_modules, &s);
132 }
133
134 int yang_snodes_iterate_subtree(const struct lys_node *snode,
135 yang_iterate_cb cb, uint16_t flags, void *arg)
136 {
137 struct lys_node *child;
138 int ret = YANG_ITER_CONTINUE;
139
140 if (CHECK_FLAG(flags, YANG_ITER_FILTER_IMPLICIT)) {
141 switch (snode->nodetype) {
142 case LYS_CASE:
143 case LYS_INPUT:
144 case LYS_OUTPUT:
145 if (CHECK_FLAG(snode->flags, LYS_IMPLICIT))
146 goto next;
147 break;
148 default:
149 break;
150 }
151 }
152
153 switch (snode->nodetype) {
154 case LYS_CONTAINER:
155 if (CHECK_FLAG(flags, YANG_ITER_FILTER_NPCONTAINERS)) {
156 struct lys_node_container *scontainer;
157
158 scontainer = (struct lys_node_container *)snode;
159 if (!scontainer->presence)
160 goto next;
161 }
162 break;
163 case LYS_LEAF:
164 if (CHECK_FLAG(flags, YANG_ITER_FILTER_LIST_KEYS)) {
165 struct lys_node_leaf *sleaf;
166
167 /* Ignore list keys. */
168 sleaf = (struct lys_node_leaf *)snode;
169 if (lys_is_key(sleaf, NULL))
170 goto next;
171 }
172 break;
173 case LYS_GROUPING:
174 /* Return since we're not interested in the grouping subtree. */
175 return YANG_ITER_CONTINUE;
176 case LYS_USES:
177 case LYS_AUGMENT:
178 /* Always ignore nodes of these types. */
179 goto next;
180 case LYS_INPUT:
181 case LYS_OUTPUT:
182 if (CHECK_FLAG(flags, YANG_ITER_FILTER_INPUT_OUTPUT))
183 goto next;
184 break;
185 default:
186 break;
187 }
188
189 ret = (*cb)(snode, arg);
190 if (ret == YANG_ITER_STOP)
191 return ret;
192
193 next:
194 /*
195 * YANG leafs and leaf-lists can't have child nodes, and trying to
196 * access snode->child is undefined behavior.
197 */
198 if (CHECK_FLAG(snode->nodetype, LYS_LEAF | LYS_LEAFLIST))
199 return YANG_ITER_CONTINUE;
200
201 LY_TREE_FOR (snode->child, child) {
202 if (!CHECK_FLAG(flags, YANG_ITER_ALLOW_AUGMENTATIONS)
203 && child->parent != snode)
204 continue;
205
206 ret = yang_snodes_iterate_subtree(child, cb, flags, arg);
207 if (ret == YANG_ITER_STOP)
208 return ret;
209 }
210
211 return ret;
212 }
213
214 int yang_snodes_iterate_module(const struct lys_module *module,
215 yang_iterate_cb cb, uint16_t flags, void *arg)
216 {
217 struct lys_node *snode;
218 int ret = YANG_ITER_CONTINUE;
219
220 LY_TREE_FOR (module->data, snode) {
221 ret = yang_snodes_iterate_subtree(snode, cb, flags, arg);
222 if (ret == YANG_ITER_STOP)
223 return ret;
224 }
225
226 for (uint8_t i = 0; i < module->augment_size; i++) {
227 ret = yang_snodes_iterate_subtree(
228 (const struct lys_node *)&module->augment[i], cb, flags,
229 arg);
230 if (ret == YANG_ITER_STOP)
231 return ret;
232 }
233
234 return ret;
235 }
236
237 int yang_snodes_iterate_all(yang_iterate_cb cb, uint16_t flags, void *arg)
238 {
239 struct yang_module *module;
240 int ret = YANG_ITER_CONTINUE;
241
242 RB_FOREACH (module, yang_modules, &yang_modules) {
243 ret = yang_snodes_iterate_module(module->info, cb, flags, arg);
244 if (ret == YANG_ITER_STOP)
245 return ret;
246 }
247
248 return ret;
249 }
250
251 void yang_snode_get_path(const struct lys_node *snode, enum yang_path_type type,
252 char *xpath, size_t xpath_len)
253 {
254 char *xpath_ptr;
255
256 switch (type) {
257 case YANG_PATH_SCHEMA:
258 xpath_ptr = lys_path(snode, 0);
259 break;
260 case YANG_PATH_DATA:
261 xpath_ptr = lys_data_path(snode);
262 break;
263 default:
264 flog_err(EC_LIB_DEVELOPMENT, "%s: unknown yang path type: %u",
265 __func__, type);
266 exit(1);
267 }
268 strlcpy(xpath, xpath_ptr, xpath_len);
269 free(xpath_ptr);
270 }
271
272 struct lys_node *yang_snode_real_parent(const struct lys_node *snode)
273 {
274 struct lys_node *parent = snode->parent;
275
276 while (parent) {
277 struct lys_node_container *scontainer;
278
279 switch (parent->nodetype) {
280 case LYS_CONTAINER:
281 scontainer = (struct lys_node_container *)parent;
282 if (scontainer->presence)
283 return parent;
284 break;
285 case LYS_LIST:
286 return parent;
287 default:
288 break;
289 }
290 parent = parent->parent;
291 }
292
293 return NULL;
294 }
295
296 struct lys_node *yang_snode_parent_list(const struct lys_node *snode)
297 {
298 struct lys_node *parent = snode->parent;
299
300 while (parent) {
301 switch (parent->nodetype) {
302 case LYS_LIST:
303 return parent;
304 default:
305 break;
306 }
307 parent = parent->parent;
308 }
309
310 return NULL;
311 }
312
313 bool yang_snode_is_typeless_data(const struct lys_node *snode)
314 {
315 struct lys_node_leaf *sleaf;
316
317 switch (snode->nodetype) {
318 case LYS_LEAF:
319 sleaf = (struct lys_node_leaf *)snode;
320 if (sleaf->type.base == LY_TYPE_EMPTY)
321 return true;
322 return false;
323 case LYS_LEAFLIST:
324 return false;
325 default:
326 return true;
327 }
328 }
329
330 const char *yang_snode_get_default(const struct lys_node *snode)
331 {
332 struct lys_node_leaf *sleaf;
333
334 switch (snode->nodetype) {
335 case LYS_LEAF:
336 sleaf = (struct lys_node_leaf *)snode;
337
338 /* NOTE: this might be null. */
339 return sleaf->dflt;
340 case LYS_LEAFLIST:
341 /* TODO: check leaf-list default values */
342 return NULL;
343 default:
344 return NULL;
345 }
346 }
347
348 const struct lys_type *yang_snode_get_type(const struct lys_node *snode)
349 {
350 struct lys_node_leaf *sleaf = (struct lys_node_leaf *)snode;
351 struct lys_type *type;
352
353 if (!CHECK_FLAG(sleaf->nodetype, LYS_LEAF | LYS_LEAFLIST))
354 return NULL;
355
356 type = &sleaf->type;
357 while (type->base == LY_TYPE_LEAFREF)
358 type = &type->info.lref.target->type;
359
360 return type;
361 }
362
363 void yang_dnode_get_path(const struct lyd_node *dnode, char *xpath,
364 size_t xpath_len)
365 {
366 char *xpath_ptr;
367
368 xpath_ptr = lyd_path(dnode);
369 strlcpy(xpath, xpath_ptr, xpath_len);
370 free(xpath_ptr);
371 }
372
373 const char *yang_dnode_get_schema_name(const struct lyd_node *dnode,
374 const char *xpath_fmt, ...)
375 {
376 if (xpath_fmt) {
377 va_list ap;
378 char xpath[XPATH_MAXLEN];
379
380 va_start(ap, xpath_fmt);
381 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
382 va_end(ap);
383
384 dnode = yang_dnode_get(dnode, xpath);
385 if (!dnode) {
386 flog_err(EC_LIB_YANG_DNODE_NOT_FOUND,
387 "%s: couldn't find %s", __func__, xpath);
388 zlog_backtrace(LOG_ERR);
389 abort();
390 }
391 }
392
393 return dnode->schema->name;
394 }
395
396 struct lyd_node *yang_dnode_get(const struct lyd_node *dnode,
397 const char *xpath_fmt, ...)
398 {
399 va_list ap;
400 char xpath[XPATH_MAXLEN];
401 struct ly_set *set;
402 struct lyd_node *dnode_ret = NULL;
403
404 va_start(ap, xpath_fmt);
405 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
406 va_end(ap);
407
408 set = lyd_find_path(dnode, xpath);
409 assert(set);
410 if (set->number == 0)
411 goto exit;
412
413 if (set->number > 1) {
414 flog_warn(EC_LIB_YANG_DNODE_NOT_FOUND,
415 "%s: found %u elements (expected 0 or 1) [xpath %s]",
416 __func__, set->number, xpath);
417 goto exit;
418 }
419
420 dnode_ret = set->set.d[0];
421
422 exit:
423 ly_set_free(set);
424
425 return dnode_ret;
426 }
427
428 bool yang_dnode_exists(const struct lyd_node *dnode, const char *xpath_fmt, ...)
429 {
430 va_list ap;
431 char xpath[XPATH_MAXLEN];
432 struct ly_set *set;
433 bool found;
434
435 va_start(ap, xpath_fmt);
436 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
437 va_end(ap);
438
439 set = lyd_find_path(dnode, xpath);
440 assert(set);
441 found = (set->number > 0);
442 ly_set_free(set);
443
444 return found;
445 }
446
447 bool yang_dnode_is_default(const struct lyd_node *dnode, const char *xpath_fmt,
448 ...)
449 {
450 struct lys_node *snode;
451 struct lys_node_leaf *sleaf;
452 struct lys_node_container *scontainer;
453
454 if (xpath_fmt) {
455 va_list ap;
456 char xpath[XPATH_MAXLEN];
457
458 va_start(ap, xpath_fmt);
459 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
460 va_end(ap);
461
462 dnode = yang_dnode_get(dnode, xpath);
463 }
464
465 assert(dnode);
466 snode = dnode->schema;
467 switch (snode->nodetype) {
468 case LYS_LEAF:
469 sleaf = (struct lys_node_leaf *)snode;
470 if (sleaf->type.base == LY_TYPE_EMPTY)
471 return false;
472 return lyd_wd_default((struct lyd_node_leaf_list *)dnode);
473 case LYS_LEAFLIST:
474 /* TODO: check leaf-list default values */
475 return false;
476 case LYS_CONTAINER:
477 scontainer = (struct lys_node_container *)snode;
478 if (scontainer->presence)
479 return false;
480 return true;
481 default:
482 return false;
483 }
484 }
485
486 bool yang_dnode_is_default_recursive(const struct lyd_node *dnode)
487 {
488 struct lys_node *snode;
489 struct lyd_node *root, *next, *dnode_iter;
490
491 snode = dnode->schema;
492 if (CHECK_FLAG(snode->nodetype, LYS_LEAF | LYS_LEAFLIST))
493 return yang_dnode_is_default(dnode, NULL);
494
495 if (!yang_dnode_is_default(dnode, NULL))
496 return false;
497
498 LY_TREE_FOR (dnode->child, root) {
499 LY_TREE_DFS_BEGIN (root, next, dnode_iter) {
500 if (!yang_dnode_is_default(dnode_iter, NULL))
501 return false;
502
503 LY_TREE_DFS_END(root, next, dnode_iter);
504 }
505 }
506
507 return true;
508 }
509
510 void yang_dnode_change_leaf(struct lyd_node *dnode, const char *value)
511 {
512 assert(dnode->schema->nodetype == LYS_LEAF);
513 lyd_change_leaf((struct lyd_node_leaf_list *)dnode, value);
514 }
515
516 void yang_dnode_set_entry(const struct lyd_node *dnode, void *entry)
517 {
518 assert(CHECK_FLAG(dnode->schema->nodetype, LYS_LIST | LYS_CONTAINER));
519 lyd_set_private(dnode, entry);
520 }
521
522 void *yang_dnode_get_entry(const struct lyd_node *dnode,
523 bool abort_if_not_found)
524 {
525 const struct lyd_node *orig_dnode = dnode;
526 char xpath[XPATH_MAXLEN];
527
528 while (dnode) {
529 switch (dnode->schema->nodetype) {
530 case LYS_CONTAINER:
531 case LYS_LIST:
532 if (dnode->priv)
533 return dnode->priv;
534 break;
535 default:
536 break;
537 }
538
539 dnode = dnode->parent;
540 }
541
542 if (!abort_if_not_found)
543 return NULL;
544
545 yang_dnode_get_path(orig_dnode, xpath, sizeof(xpath));
546 flog_err(EC_LIB_YANG_DNODE_NOT_FOUND,
547 "%s: failed to find entry [xpath %s]", __func__, xpath);
548 zlog_backtrace(LOG_ERR);
549 abort();
550 }
551
552 struct lyd_node *yang_dnode_new(struct ly_ctx *ly_ctx, bool config_only)
553 {
554 struct lyd_node *dnode;
555 int options;
556
557 if (config_only)
558 options = LYD_OPT_CONFIG;
559 else
560 options = LYD_OPT_DATA | LYD_OPT_DATA_NO_YANGLIB;
561
562 dnode = NULL;
563 if (lyd_validate(&dnode, options, ly_ctx) != 0) {
564 /* Should never happen. */
565 flog_err(EC_LIB_LIBYANG, "%s: lyd_validate() failed", __func__);
566 exit(1);
567 }
568
569 return dnode;
570 }
571
572 struct lyd_node *yang_dnode_dup(const struct lyd_node *dnode)
573 {
574 return lyd_dup_withsiblings(dnode, 1);
575 }
576
577 void yang_dnode_free(struct lyd_node *dnode)
578 {
579 while (dnode->parent)
580 dnode = dnode->parent;
581 lyd_free_withsiblings(dnode);
582 }
583
584 struct yang_data *yang_data_new(const char *xpath, const char *value)
585 {
586 struct yang_data *data;
587
588 data = XCALLOC(MTYPE_YANG_DATA, sizeof(*data));
589 strlcpy(data->xpath, xpath, sizeof(data->xpath));
590 if (value)
591 data->value = strdup(value);
592
593 return data;
594 }
595
596 void yang_data_free(struct yang_data *data)
597 {
598 if (data->value)
599 free(data->value);
600 XFREE(MTYPE_YANG_DATA, data);
601 }
602
603 struct list *yang_data_list_new(void)
604 {
605 struct list *list;
606
607 list = list_new();
608 list->del = (void (*)(void *))yang_data_free;
609
610 return list;
611 }
612
613 struct yang_data *yang_data_list_find(const struct list *list,
614 const char *xpath_fmt, ...)
615 {
616 char xpath[XPATH_MAXLEN];
617 struct yang_data *data;
618 struct listnode *node;
619 va_list ap;
620
621 va_start(ap, xpath_fmt);
622 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
623 va_end(ap);
624
625 for (ALL_LIST_ELEMENTS_RO(list, node, data))
626 if (strmatch(data->xpath, xpath))
627 return data;
628
629 return NULL;
630 }
631
632 static void *ly_dup_cb(const void *priv)
633 {
634 /* Make a shallow copy of the priv pointer. */
635 return (void *)priv;
636 }
637
638 /* Make libyang log its errors using FRR logging infrastructure. */
639 static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
640 {
641 int priority;
642
643 switch (level) {
644 case LY_LLERR:
645 priority = LOG_ERR;
646 break;
647 case LY_LLWRN:
648 priority = LOG_WARNING;
649 break;
650 case LY_LLVRB:
651 priority = LOG_DEBUG;
652 break;
653 default:
654 return;
655 }
656
657 if (path)
658 zlog(priority, "libyang: %s (%s)", msg, path);
659 else
660 zlog(priority, "libyang: %s", msg);
661 }
662
663 #if CONFDATE > 20190401
664 CPP_NOTICE("lib/yang: time to remove non-LIBYANG_EXT_BUILTIN support")
665 #endif
666
667 #ifdef LIBYANG_EXT_BUILTIN
668 extern struct lytype_plugin_list frr_user_types[];
669 #endif
670
671 struct ly_ctx *yang_ctx_new_setup(void)
672 {
673 struct ly_ctx *ctx;
674 const char *yang_models_path = YANG_MODELS_PATH;
675
676 if (access(yang_models_path, R_OK | X_OK)) {
677 yang_models_path = NULL;
678 if (errno == ENOENT)
679 zlog_info("yang model directory \"%s\" does not exist",
680 YANG_MODELS_PATH);
681 else
682 flog_err_sys(EC_LIB_LIBYANG,
683 "cannot access yang model directory \"%s\"",
684 YANG_MODELS_PATH);
685 }
686
687 ctx = ly_ctx_new(yang_models_path, LY_CTX_DISABLE_SEARCHDIR_CWD);
688 if (!ctx)
689 return NULL;
690 ly_ctx_set_module_imp_clb(ctx, yang_module_imp_clb, NULL);
691 return ctx;
692 }
693
694 void yang_init(void)
695 {
696 #ifndef LIBYANG_EXT_BUILTIN
697 CPP_NOTICE("lib/yang: deprecated libyang <0.16.74 extension loading in use!")
698 static char ly_plugin_dir[PATH_MAX];
699 const char *const *ly_loaded_plugins;
700 const char *ly_plugin;
701 bool found_ly_frr_types = false;
702
703 /* Tell libyang where to find its plugins. */
704 snprintf(ly_plugin_dir, sizeof(ly_plugin_dir), "%s=%s",
705 "LIBYANG_USER_TYPES_PLUGINS_DIR", LIBYANG_PLUGINS_PATH);
706 putenv(ly_plugin_dir);
707 #endif
708
709 /* Initialize libyang global parameters that affect all containers. */
710 ly_set_log_clb(ly_log_cb, 1);
711 ly_log_options(LY_LOLOG | LY_LOSTORE);
712
713 #ifdef LIBYANG_EXT_BUILTIN
714 if (ly_register_types(frr_user_types, "frr_user_types")) {
715 flog_err(EC_LIB_LIBYANG_PLUGIN_LOAD,
716 "ly_register_types() failed");
717 exit(1);
718 }
719 #endif
720
721 /* Initialize libyang container for native models. */
722 ly_native_ctx = yang_ctx_new_setup();
723 if (!ly_native_ctx) {
724 flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
725 exit(1);
726 }
727 ly_ctx_set_priv_dup_clb(ly_native_ctx, ly_dup_cb);
728
729 #ifndef LIBYANG_EXT_BUILTIN
730 /* Detect if the required libyang plugin(s) were loaded successfully. */
731 ly_loaded_plugins = ly_get_loaded_plugins();
732 for (size_t i = 0; (ly_plugin = ly_loaded_plugins[i]); i++) {
733 if (strmatch(ly_plugin, "frr_user_types")) {
734 found_ly_frr_types = true;
735 break;
736 }
737 }
738 if (!found_ly_frr_types) {
739 flog_err(EC_LIB_LIBYANG_PLUGIN_LOAD,
740 "%s: failed to load frr_user_types.so", __func__);
741 exit(1);
742 }
743 #endif
744
745 yang_translator_init();
746 }
747
748 void yang_terminate(void)
749 {
750 struct yang_module *module;
751
752 yang_translator_terminate();
753
754 while (!RB_EMPTY(yang_modules, &yang_modules)) {
755 module = RB_ROOT(yang_modules, &yang_modules);
756
757 /*
758 * We shouldn't call ly_ctx_remove_module() here because this
759 * function also removes other modules that depend on it.
760 *
761 * ly_ctx_destroy() will release all memory for us.
762 */
763 RB_REMOVE(yang_modules, &yang_modules, module);
764 XFREE(MTYPE_YANG_MODULE, module);
765 }
766
767 ly_ctx_destroy(ly_native_ctx, NULL);
768 }