]> git.proxmox.com Git - mirror_frr.git/blame - lib/yang.c
Merge pull request #5793 from ton31337/fix/formatting_show_bgp_summary_failed
[mirror_frr.git] / lib / yang.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#include <zebra.h>
21
22#include "log.h"
1c2facd1
RW
23#include "lib_errors.h"
24#include "yang.h"
25#include "yang_translator.h"
26#include "northbound.h"
27
02a0df1f
DL
28#include <libyang/user_types.h>
29
eaf58ba9
DL
30DEFINE_MTYPE_STATIC(LIB, YANG_MODULE, "YANG module")
31DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure")
1c2facd1
RW
32
33/* libyang container. */
34struct ly_ctx *ly_native_ctx;
35
3a11599c
DL
36static struct yang_module_embed *embeds, **embedupd = &embeds;
37
38void yang_module_embed(struct yang_module_embed *embed)
39{
40 embed->next = NULL;
41 *embedupd = embed;
42 embedupd = &embed->next;
43}
44
45static const char *yang_module_imp_clb(const char *mod_name,
46 const char *mod_rev,
47 const char *submod_name,
48 const char *submod_rev,
49 void *user_data,
50 LYS_INFORMAT *format,
51 void (**free_module_data)
52 (void *, void*))
53{
54 struct yang_module_embed *e;
55
56 if (submod_name || submod_rev)
57 return NULL;
58
59 for (e = embeds; e; e = e->next) {
60 if (strcmp(e->mod_name, mod_name))
61 continue;
62 if (mod_rev && strcmp(e->mod_rev, mod_rev))
63 continue;
64
65 *format = e->format;
66 return e->data;
67 }
68
69 flog_warn(EC_LIB_YANG_MODULE_LOAD,
70 "YANG model \"%s@%s\" not embedded, trying external file",
71 mod_name, mod_rev ? mod_rev : "*");
72 return NULL;
73}
74
96f2c009 75static const char *const frr_native_modules[] = {
a1b5f469
RW
76 "frr-interface",
77 "frr-ripd",
e9ce224b 78 "frr-ripngd",
96f2c009 79 "frr-isisd",
f495425b 80 "frr-vrrpd",
a1b5f469
RW
81};
82
1c2facd1
RW
83/* Generate the yang_modules tree. */
84static 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}
89RB_GENERATE(yang_modules, yang_module, entry, yang_module_compare)
90
91struct yang_modules yang_modules = RB_INITIALIZER(&yang_modules);
92
93struct 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
a1b5f469
RW
120void 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
1c2facd1
RW
126struct 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
e0ccfad2
RW
134int yang_snodes_iterate_subtree(const struct lys_node *snode,
135 yang_iterate_cb cb, uint16_t flags, void *arg)
1c2facd1
RW
136{
137 struct lys_node *child;
e0ccfad2 138 int ret = YANG_ITER_CONTINUE;
1c2facd1
RW
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:
db452508 145 if (CHECK_FLAG(snode->flags, LYS_IMPLICIT))
1c2facd1
RW
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. */
e0ccfad2 175 return YANG_ITER_CONTINUE;
1c2facd1
RW
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
e0ccfad2
RW
189 ret = (*cb)(snode, arg);
190 if (ret == YANG_ITER_STOP)
191 return ret;
1c2facd1
RW
192
193next:
194 /*
195 * YANG leafs and leaf-lists can't have child nodes, and trying to
196 * access snode->child is undefined behavior.
197 */
db452508 198 if (CHECK_FLAG(snode->nodetype, LYS_LEAF | LYS_LEAFLIST))
e0ccfad2 199 return YANG_ITER_CONTINUE;
1c2facd1
RW
200
201 LY_TREE_FOR (snode->child, child) {
544ca69a
RW
202 if (!CHECK_FLAG(flags, YANG_ITER_ALLOW_AUGMENTATIONS)
203 && child->parent != snode)
1c2facd1 204 continue;
e0ccfad2
RW
205
206 ret = yang_snodes_iterate_subtree(child, cb, flags, arg);
207 if (ret == YANG_ITER_STOP)
208 return ret;
1c2facd1 209 }
e0ccfad2
RW
210
211 return ret;
1c2facd1
RW
212}
213
e0ccfad2
RW
214int yang_snodes_iterate_module(const struct lys_module *module,
215 yang_iterate_cb cb, uint16_t flags, void *arg)
1c2facd1
RW
216{
217 struct lys_node *snode;
e0ccfad2 218 int ret = YANG_ITER_CONTINUE;
1c2facd1
RW
219
220 LY_TREE_FOR (module->data, snode) {
e0ccfad2
RW
221 ret = yang_snodes_iterate_subtree(snode, cb, flags, arg);
222 if (ret == YANG_ITER_STOP)
223 return ret;
1c2facd1
RW
224 }
225
226 for (uint8_t i = 0; i < module->augment_size; i++) {
e0ccfad2
RW
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;
1c2facd1 232 }
e0ccfad2
RW
233
234 return ret;
1c2facd1
RW
235}
236
e0ccfad2 237int yang_snodes_iterate_all(yang_iterate_cb cb, uint16_t flags, void *arg)
1c2facd1
RW
238{
239 struct yang_module *module;
e0ccfad2
RW
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 }
1c2facd1 247
e0ccfad2 248 return ret;
1c2facd1
RW
249}
250
251void 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
272struct 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
296struct 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
313bool 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
330const 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
348const 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
db452508 353 if (!CHECK_FLAG(sleaf->nodetype, LYS_LEAF | LYS_LEAFLIST))
1c2facd1
RW
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
363void 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
3f662078
RW
373const 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
1c2facd1
RW
396struct 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
422exit:
423 ly_set_free(set);
424
425 return dnode_ret;
426}
427
428bool 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
447bool 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
486bool 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;
db452508 492 if (CHECK_FLAG(snode->nodetype, LYS_LEAF | LYS_LEAFLIST))
1c2facd1
RW
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
510void 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
5e02643a 516struct lyd_node *yang_dnode_new(struct ly_ctx *ly_ctx, bool config_only)
1c2facd1
RW
517{
518 struct lyd_node *dnode;
5e02643a
RW
519 int options;
520
521 if (config_only)
522 options = LYD_OPT_CONFIG;
523 else
524 options = LYD_OPT_DATA | LYD_OPT_DATA_NO_YANGLIB;
1c2facd1
RW
525
526 dnode = NULL;
5e02643a 527 if (lyd_validate(&dnode, options, ly_ctx) != 0) {
1c2facd1
RW
528 /* Should never happen. */
529 flog_err(EC_LIB_LIBYANG, "%s: lyd_validate() failed", __func__);
530 exit(1);
531 }
532
533 return dnode;
534}
535
536struct lyd_node *yang_dnode_dup(const struct lyd_node *dnode)
537{
538 return lyd_dup_withsiblings(dnode, 1);
539}
540
541void yang_dnode_free(struct lyd_node *dnode)
542{
e5dc8a44
RW
543 while (dnode->parent)
544 dnode = dnode->parent;
1c2facd1
RW
545 lyd_free_withsiblings(dnode);
546}
547
548struct yang_data *yang_data_new(const char *xpath, const char *value)
549{
1c2facd1
RW
550 struct yang_data *data;
551
1c2facd1
RW
552 data = XCALLOC(MTYPE_YANG_DATA, sizeof(*data));
553 strlcpy(data->xpath, xpath, sizeof(data->xpath));
1c2facd1
RW
554 if (value)
555 data->value = strdup(value);
556
557 return data;
558}
559
560void yang_data_free(struct yang_data *data)
561{
562 if (data->value)
563 free(data->value);
564 XFREE(MTYPE_YANG_DATA, data);
565}
566
567struct list *yang_data_list_new(void)
568{
569 struct list *list;
570
571 list = list_new();
572 list->del = (void (*)(void *))yang_data_free;
573
574 return list;
575}
576
fcb7bffd
RW
577struct yang_data *yang_data_list_find(const struct list *list,
578 const char *xpath_fmt, ...)
579{
580 char xpath[XPATH_MAXLEN];
581 struct yang_data *data;
582 struct listnode *node;
583 va_list ap;
584
585 va_start(ap, xpath_fmt);
586 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
587 va_end(ap);
588
589 for (ALL_LIST_ELEMENTS_RO(list, node, data))
590 if (strmatch(data->xpath, xpath))
591 return data;
592
593 return NULL;
594}
595
1c2facd1
RW
596/* Make libyang log its errors using FRR logging infrastructure. */
597static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
598{
96679938 599 int priority = LOG_ERR;
1c2facd1
RW
600
601 switch (level) {
602 case LY_LLERR:
603 priority = LOG_ERR;
604 break;
605 case LY_LLWRN:
606 priority = LOG_WARNING;
607 break;
608 case LY_LLVRB:
96679938 609 case LY_LLDBG:
1c2facd1
RW
610 priority = LOG_DEBUG;
611 break;
1c2facd1
RW
612 }
613
614 if (path)
615 zlog(priority, "libyang: %s (%s)", msg, path);
616 else
617 zlog(priority, "libyang: %s", msg);
618}
619
62ae9ade
RW
620void yang_debugging_set(bool enable)
621{
622 if (enable) {
623 ly_verb(LY_LLDBG);
624 ly_verb_dbg(0xFF);
625 } else {
626 ly_verb(LY_LLERR);
627 ly_verb_dbg(0);
628 }
629}
630
591f57cf
DL
631struct ly_ctx *yang_ctx_new_setup(void)
632{
633 struct ly_ctx *ctx;
634 const char *yang_models_path = YANG_MODELS_PATH;
635
636 if (access(yang_models_path, R_OK | X_OK)) {
637 yang_models_path = NULL;
638 if (errno == ENOENT)
639 zlog_info("yang model directory \"%s\" does not exist",
640 YANG_MODELS_PATH);
641 else
642 flog_err_sys(EC_LIB_LIBYANG,
643 "cannot access yang model directory \"%s\"",
644 YANG_MODELS_PATH);
645 }
646
647 ctx = ly_ctx_new(yang_models_path, LY_CTX_DISABLE_SEARCHDIR_CWD);
648 if (!ctx)
649 return NULL;
650 ly_ctx_set_module_imp_clb(ctx, yang_module_imp_clb, NULL);
651 return ctx;
652}
653
1c2facd1
RW
654void yang_init(void)
655{
1c2facd1
RW
656 /* Initialize libyang global parameters that affect all containers. */
657 ly_set_log_clb(ly_log_cb, 1);
658 ly_log_options(LY_LOLOG | LY_LOSTORE);
659
660 /* Initialize libyang container for native models. */
591f57cf 661 ly_native_ctx = yang_ctx_new_setup();
1c2facd1
RW
662 if (!ly_native_ctx) {
663 flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
664 exit(1);
665 }
1c2facd1 666
1c2facd1
RW
667 yang_translator_init();
668}
669
670void yang_terminate(void)
671{
672 struct yang_module *module;
673
674 yang_translator_terminate();
675
676 while (!RB_EMPTY(yang_modules, &yang_modules)) {
677 module = RB_ROOT(yang_modules, &yang_modules);
678
679 /*
680 * We shouldn't call ly_ctx_remove_module() here because this
681 * function also removes other modules that depend on it.
682 *
683 * ly_ctx_destroy() will release all memory for us.
684 */
685 RB_REMOVE(yang_modules, &yang_modules, module);
686 XFREE(MTYPE_YANG_MODULE, module);
687 }
688
689 ly_ctx_destroy(ly_native_ctx, NULL);
690}