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