]> git.proxmox.com Git - mirror_frr.git/blame - lib/yang.c
Merge pull request #3409 from opensourcerouting/feature/cleanup-topotest-docker-docs
[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"
23#include "log_int.h"
24#include "lib_errors.h"
25#include "yang.h"
26#include "yang_translator.h"
27#include "northbound.h"
28
29DEFINE_MTYPE(LIB, YANG_MODULE, "YANG module")
30DEFINE_MTYPE(LIB, YANG_DATA, "YANG data structure")
31
32/* libyang container. */
33struct ly_ctx *ly_native_ctx;
34
3a11599c
DL
35static struct yang_module_embed *embeds, **embedupd = &embeds;
36
37void yang_module_embed(struct yang_module_embed *embed)
38{
39 embed->next = NULL;
40 *embedupd = embed;
41 embedupd = &embed->next;
42}
43
44static 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
a1b5f469
RW
74static const char * const frr_native_modules[] = {
75 "frr-interface",
76 "frr-ripd",
77};
78
1c2facd1
RW
79/* Generate the yang_modules tree. */
80static 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}
85RB_GENERATE(yang_modules, yang_module, entry, yang_module_compare)
86
87struct yang_modules yang_modules = RB_INITIALIZER(&yang_modules);
88
89struct 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
a1b5f469
RW
116void 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
1c2facd1
RW
122struct 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
e0ccfad2
RW
130int yang_snodes_iterate_subtree(const struct lys_node *snode,
131 yang_iterate_cb cb, uint16_t flags, void *arg)
1c2facd1
RW
132{
133 struct lys_node *child;
e0ccfad2 134 int ret = YANG_ITER_CONTINUE;
1c2facd1
RW
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:
db452508 141 if (CHECK_FLAG(snode->flags, LYS_IMPLICIT))
1c2facd1
RW
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. */
e0ccfad2 171 return YANG_ITER_CONTINUE;
1c2facd1
RW
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
e0ccfad2
RW
185 ret = (*cb)(snode, arg);
186 if (ret == YANG_ITER_STOP)
187 return ret;
1c2facd1
RW
188
189next:
190 /*
191 * YANG leafs and leaf-lists can't have child nodes, and trying to
192 * access snode->child is undefined behavior.
193 */
db452508 194 if (CHECK_FLAG(snode->nodetype, LYS_LEAF | LYS_LEAFLIST))
e0ccfad2 195 return YANG_ITER_CONTINUE;
1c2facd1
RW
196
197 LY_TREE_FOR (snode->child, child) {
544ca69a
RW
198 if (!CHECK_FLAG(flags, YANG_ITER_ALLOW_AUGMENTATIONS)
199 && child->parent != snode)
1c2facd1 200 continue;
e0ccfad2
RW
201
202 ret = yang_snodes_iterate_subtree(child, cb, flags, arg);
203 if (ret == YANG_ITER_STOP)
204 return ret;
1c2facd1 205 }
e0ccfad2
RW
206
207 return ret;
1c2facd1
RW
208}
209
e0ccfad2
RW
210int yang_snodes_iterate_module(const struct lys_module *module,
211 yang_iterate_cb cb, uint16_t flags, void *arg)
1c2facd1
RW
212{
213 struct lys_node *snode;
e0ccfad2 214 int ret = YANG_ITER_CONTINUE;
1c2facd1
RW
215
216 LY_TREE_FOR (module->data, snode) {
e0ccfad2
RW
217 ret = yang_snodes_iterate_subtree(snode, cb, flags, arg);
218 if (ret == YANG_ITER_STOP)
219 return ret;
1c2facd1
RW
220 }
221
222 for (uint8_t i = 0; i < module->augment_size; i++) {
e0ccfad2
RW
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;
1c2facd1 228 }
e0ccfad2
RW
229
230 return ret;
1c2facd1
RW
231}
232
e0ccfad2 233int yang_snodes_iterate_all(yang_iterate_cb cb, uint16_t flags, void *arg)
1c2facd1
RW
234{
235 struct yang_module *module;
e0ccfad2
RW
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 }
1c2facd1 243
e0ccfad2 244 return ret;
1c2facd1
RW
245}
246
247void 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
268struct 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
292struct 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
309bool 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
326const 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
344const 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
db452508 349 if (!CHECK_FLAG(sleaf->nodetype, LYS_LEAF | LYS_LEAFLIST))
1c2facd1
RW
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
359void 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
3f662078
RW
369const 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
1c2facd1
RW
392struct 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
418exit:
419 ly_set_free(set);
420
421 return dnode_ret;
422}
423
424bool 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
443bool 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
482bool 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;
db452508 488 if (CHECK_FLAG(snode->nodetype, LYS_LEAF | LYS_LEAFLIST))
1c2facd1
RW
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
506void 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
512void yang_dnode_set_entry(const struct lyd_node *dnode, void *entry)
513{
db452508 514 assert(CHECK_FLAG(dnode->schema->nodetype, LYS_LIST | LYS_CONTAINER));
1c2facd1
RW
515 lyd_set_private(dnode, entry);
516}
517
25c780a3
RW
518void *yang_dnode_get_entry(const struct lyd_node *dnode,
519 bool abort_if_not_found)
1c2facd1
RW
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
25c780a3
RW
538 if (!abort_if_not_found)
539 return NULL;
540
1c2facd1
RW
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
5e02643a 548struct lyd_node *yang_dnode_new(struct ly_ctx *ly_ctx, bool config_only)
1c2facd1
RW
549{
550 struct lyd_node *dnode;
5e02643a
RW
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;
1c2facd1
RW
557
558 dnode = NULL;
5e02643a 559 if (lyd_validate(&dnode, options, ly_ctx) != 0) {
1c2facd1
RW
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
568struct lyd_node *yang_dnode_dup(const struct lyd_node *dnode)
569{
570 return lyd_dup_withsiblings(dnode, 1);
571}
572
573void yang_dnode_free(struct lyd_node *dnode)
574{
e5dc8a44
RW
575 while (dnode->parent)
576 dnode = dnode->parent;
1c2facd1
RW
577 lyd_free_withsiblings(dnode);
578}
579
580struct yang_data *yang_data_new(const char *xpath, const char *value)
581{
1c2facd1
RW
582 struct yang_data *data;
583
1c2facd1
RW
584 data = XCALLOC(MTYPE_YANG_DATA, sizeof(*data));
585 strlcpy(data->xpath, xpath, sizeof(data->xpath));
1c2facd1
RW
586 if (value)
587 data->value = strdup(value);
588
589 return data;
590}
591
592void yang_data_free(struct yang_data *data)
593{
594 if (data->value)
595 free(data->value);
596 XFREE(MTYPE_YANG_DATA, data);
597}
598
599struct 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
609static 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. */
616static 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
640void 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. */
f3e5b71c
RW
657 ly_native_ctx =
658 ly_ctx_new(YANG_MODELS_PATH, LY_CTX_DISABLE_SEARCHDIR_CWD);
1c2facd1
RW
659 if (!ly_native_ctx) {
660 flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
661 exit(1);
662 }
3a11599c 663 ly_ctx_set_module_imp_clb(ly_native_ctx, yang_module_imp_clb, NULL);
1c2facd1
RW
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
683void 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}