]> git.proxmox.com Git - mirror_frr.git/blame - lib/yang.c
lib: rework the yang schema node iteration functions
[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) {
198 if (child->parent != snode)
199 continue;
e0ccfad2
RW
200
201 ret = yang_snodes_iterate_subtree(child, cb, flags, arg);
202 if (ret == YANG_ITER_STOP)
203 return ret;
1c2facd1 204 }
e0ccfad2
RW
205
206 return ret;
1c2facd1
RW
207}
208
e0ccfad2
RW
209int yang_snodes_iterate_module(const struct lys_module *module,
210 yang_iterate_cb cb, uint16_t flags, void *arg)
1c2facd1
RW
211{
212 struct lys_node *snode;
e0ccfad2 213 int ret = YANG_ITER_CONTINUE;
1c2facd1
RW
214
215 LY_TREE_FOR (module->data, snode) {
e0ccfad2
RW
216 ret = yang_snodes_iterate_subtree(snode, cb, flags, arg);
217 if (ret == YANG_ITER_STOP)
218 return ret;
1c2facd1
RW
219 }
220
221 for (uint8_t i = 0; i < module->augment_size; i++) {
e0ccfad2
RW
222 ret = yang_snodes_iterate_subtree(
223 (const struct lys_node *)&module->augment[i], cb, flags,
224 arg);
225 if (ret == YANG_ITER_STOP)
226 return ret;
1c2facd1 227 }
e0ccfad2
RW
228
229 return ret;
1c2facd1
RW
230}
231
e0ccfad2 232int yang_snodes_iterate_all(yang_iterate_cb cb, uint16_t flags, void *arg)
1c2facd1
RW
233{
234 struct yang_module *module;
e0ccfad2
RW
235 int ret = YANG_ITER_CONTINUE;
236
237 RB_FOREACH (module, yang_modules, &yang_modules) {
238 ret = yang_snodes_iterate_module(module->info, cb, flags, arg);
239 if (ret == YANG_ITER_STOP)
240 return ret;
241 }
1c2facd1 242
e0ccfad2 243 return ret;
1c2facd1
RW
244}
245
246void yang_snode_get_path(const struct lys_node *snode, enum yang_path_type type,
247 char *xpath, size_t xpath_len)
248{
249 char *xpath_ptr;
250
251 switch (type) {
252 case YANG_PATH_SCHEMA:
253 xpath_ptr = lys_path(snode, 0);
254 break;
255 case YANG_PATH_DATA:
256 xpath_ptr = lys_data_path(snode);
257 break;
258 default:
259 flog_err(EC_LIB_DEVELOPMENT, "%s: unknown yang path type: %u",
260 __func__, type);
261 exit(1);
262 }
263 strlcpy(xpath, xpath_ptr, xpath_len);
264 free(xpath_ptr);
265}
266
267struct lys_node *yang_snode_real_parent(const struct lys_node *snode)
268{
269 struct lys_node *parent = snode->parent;
270
271 while (parent) {
272 struct lys_node_container *scontainer;
273
274 switch (parent->nodetype) {
275 case LYS_CONTAINER:
276 scontainer = (struct lys_node_container *)parent;
277 if (scontainer->presence)
278 return parent;
279 break;
280 case LYS_LIST:
281 return parent;
282 default:
283 break;
284 }
285 parent = parent->parent;
286 }
287
288 return NULL;
289}
290
291struct lys_node *yang_snode_parent_list(const struct lys_node *snode)
292{
293 struct lys_node *parent = snode->parent;
294
295 while (parent) {
296 switch (parent->nodetype) {
297 case LYS_LIST:
298 return parent;
299 default:
300 break;
301 }
302 parent = parent->parent;
303 }
304
305 return NULL;
306}
307
308bool yang_snode_is_typeless_data(const struct lys_node *snode)
309{
310 struct lys_node_leaf *sleaf;
311
312 switch (snode->nodetype) {
313 case LYS_LEAF:
314 sleaf = (struct lys_node_leaf *)snode;
315 if (sleaf->type.base == LY_TYPE_EMPTY)
316 return true;
317 return false;
318 case LYS_LEAFLIST:
319 return false;
320 default:
321 return true;
322 }
323}
324
325const char *yang_snode_get_default(const struct lys_node *snode)
326{
327 struct lys_node_leaf *sleaf;
328
329 switch (snode->nodetype) {
330 case LYS_LEAF:
331 sleaf = (struct lys_node_leaf *)snode;
332
333 /* NOTE: this might be null. */
334 return sleaf->dflt;
335 case LYS_LEAFLIST:
336 /* TODO: check leaf-list default values */
337 return NULL;
338 default:
339 return NULL;
340 }
341}
342
343const struct lys_type *yang_snode_get_type(const struct lys_node *snode)
344{
345 struct lys_node_leaf *sleaf = (struct lys_node_leaf *)snode;
346 struct lys_type *type;
347
db452508 348 if (!CHECK_FLAG(sleaf->nodetype, LYS_LEAF | LYS_LEAFLIST))
1c2facd1
RW
349 return NULL;
350
351 type = &sleaf->type;
352 while (type->base == LY_TYPE_LEAFREF)
353 type = &type->info.lref.target->type;
354
355 return type;
356}
357
358void yang_dnode_get_path(const struct lyd_node *dnode, char *xpath,
359 size_t xpath_len)
360{
361 char *xpath_ptr;
362
363 xpath_ptr = lyd_path(dnode);
364 strlcpy(xpath, xpath_ptr, xpath_len);
365 free(xpath_ptr);
366}
367
368struct lyd_node *yang_dnode_get(const struct lyd_node *dnode,
369 const char *xpath_fmt, ...)
370{
371 va_list ap;
372 char xpath[XPATH_MAXLEN];
373 struct ly_set *set;
374 struct lyd_node *dnode_ret = NULL;
375
376 va_start(ap, xpath_fmt);
377 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
378 va_end(ap);
379
380 set = lyd_find_path(dnode, xpath);
381 assert(set);
382 if (set->number == 0)
383 goto exit;
384
385 if (set->number > 1) {
386 flog_warn(EC_LIB_YANG_DNODE_NOT_FOUND,
387 "%s: found %u elements (expected 0 or 1) [xpath %s]",
388 __func__, set->number, xpath);
389 goto exit;
390 }
391
392 dnode_ret = set->set.d[0];
393
394exit:
395 ly_set_free(set);
396
397 return dnode_ret;
398}
399
400bool yang_dnode_exists(const struct lyd_node *dnode, const char *xpath_fmt, ...)
401{
402 va_list ap;
403 char xpath[XPATH_MAXLEN];
404 struct ly_set *set;
405 bool found;
406
407 va_start(ap, xpath_fmt);
408 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
409 va_end(ap);
410
411 set = lyd_find_path(dnode, xpath);
412 assert(set);
413 found = (set->number > 0);
414 ly_set_free(set);
415
416 return found;
417}
418
419bool yang_dnode_is_default(const struct lyd_node *dnode, const char *xpath_fmt,
420 ...)
421{
422 struct lys_node *snode;
423 struct lys_node_leaf *sleaf;
424 struct lys_node_container *scontainer;
425
426 if (xpath_fmt) {
427 va_list ap;
428 char xpath[XPATH_MAXLEN];
429
430 va_start(ap, xpath_fmt);
431 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
432 va_end(ap);
433
434 dnode = yang_dnode_get(dnode, xpath);
435 }
436
437 assert(dnode);
438 snode = dnode->schema;
439 switch (snode->nodetype) {
440 case LYS_LEAF:
441 sleaf = (struct lys_node_leaf *)snode;
442 if (sleaf->type.base == LY_TYPE_EMPTY)
443 return false;
444 return lyd_wd_default((struct lyd_node_leaf_list *)dnode);
445 case LYS_LEAFLIST:
446 /* TODO: check leaf-list default values */
447 return false;
448 case LYS_CONTAINER:
449 scontainer = (struct lys_node_container *)snode;
450 if (scontainer->presence)
451 return false;
452 return true;
453 default:
454 return false;
455 }
456}
457
458bool yang_dnode_is_default_recursive(const struct lyd_node *dnode)
459{
460 struct lys_node *snode;
461 struct lyd_node *root, *next, *dnode_iter;
462
463 snode = dnode->schema;
db452508 464 if (CHECK_FLAG(snode->nodetype, LYS_LEAF | LYS_LEAFLIST))
1c2facd1
RW
465 return yang_dnode_is_default(dnode, NULL);
466
467 if (!yang_dnode_is_default(dnode, NULL))
468 return false;
469
470 LY_TREE_FOR (dnode->child, root) {
471 LY_TREE_DFS_BEGIN (root, next, dnode_iter) {
472 if (!yang_dnode_is_default(dnode_iter, NULL))
473 return false;
474
475 LY_TREE_DFS_END(root, next, dnode_iter);
476 }
477 }
478
479 return true;
480}
481
482void yang_dnode_change_leaf(struct lyd_node *dnode, const char *value)
483{
484 assert(dnode->schema->nodetype == LYS_LEAF);
485 lyd_change_leaf((struct lyd_node_leaf_list *)dnode, value);
486}
487
488void yang_dnode_set_entry(const struct lyd_node *dnode, void *entry)
489{
db452508 490 assert(CHECK_FLAG(dnode->schema->nodetype, LYS_LIST | LYS_CONTAINER));
1c2facd1
RW
491 lyd_set_private(dnode, entry);
492}
493
494void *yang_dnode_get_entry(const struct lyd_node *dnode)
495{
496 const struct lyd_node *orig_dnode = dnode;
497 char xpath[XPATH_MAXLEN];
498
499 while (dnode) {
500 switch (dnode->schema->nodetype) {
501 case LYS_CONTAINER:
502 case LYS_LIST:
503 if (dnode->priv)
504 return dnode->priv;
505 break;
506 default:
507 break;
508 }
509
510 dnode = dnode->parent;
511 }
512
513 yang_dnode_get_path(orig_dnode, xpath, sizeof(xpath));
514 flog_err(EC_LIB_YANG_DNODE_NOT_FOUND,
515 "%s: failed to find entry [xpath %s]", __func__, xpath);
516 zlog_backtrace(LOG_ERR);
517 abort();
518}
519
5e02643a 520struct lyd_node *yang_dnode_new(struct ly_ctx *ly_ctx, bool config_only)
1c2facd1
RW
521{
522 struct lyd_node *dnode;
5e02643a
RW
523 int options;
524
525 if (config_only)
526 options = LYD_OPT_CONFIG;
527 else
528 options = LYD_OPT_DATA | LYD_OPT_DATA_NO_YANGLIB;
1c2facd1
RW
529
530 dnode = NULL;
5e02643a 531 if (lyd_validate(&dnode, options, ly_ctx) != 0) {
1c2facd1
RW
532 /* Should never happen. */
533 flog_err(EC_LIB_LIBYANG, "%s: lyd_validate() failed", __func__);
534 exit(1);
535 }
536
537 return dnode;
538}
539
540struct lyd_node *yang_dnode_dup(const struct lyd_node *dnode)
541{
542 return lyd_dup_withsiblings(dnode, 1);
543}
544
545void yang_dnode_free(struct lyd_node *dnode)
546{
e5dc8a44
RW
547 while (dnode->parent)
548 dnode = dnode->parent;
1c2facd1
RW
549 lyd_free_withsiblings(dnode);
550}
551
552struct yang_data *yang_data_new(const char *xpath, const char *value)
553{
1c2facd1
RW
554 struct yang_data *data;
555
1c2facd1
RW
556 data = XCALLOC(MTYPE_YANG_DATA, sizeof(*data));
557 strlcpy(data->xpath, xpath, sizeof(data->xpath));
1c2facd1
RW
558 if (value)
559 data->value = strdup(value);
560
561 return data;
562}
563
564void yang_data_free(struct yang_data *data)
565{
566 if (data->value)
567 free(data->value);
568 XFREE(MTYPE_YANG_DATA, data);
569}
570
571struct list *yang_data_list_new(void)
572{
573 struct list *list;
574
575 list = list_new();
576 list->del = (void (*)(void *))yang_data_free;
577
578 return list;
579}
580
581static void *ly_dup_cb(const void *priv)
582{
583 /* Make a shallow copy of the priv pointer. */
584 return (void *)priv;
585}
586
587/* Make libyang log its errors using FRR logging infrastructure. */
588static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
589{
590 int priority;
591
592 switch (level) {
593 case LY_LLERR:
594 priority = LOG_ERR;
595 break;
596 case LY_LLWRN:
597 priority = LOG_WARNING;
598 break;
599 case LY_LLVRB:
600 priority = LOG_DEBUG;
601 break;
602 default:
603 return;
604 }
605
606 if (path)
607 zlog(priority, "libyang: %s (%s)", msg, path);
608 else
609 zlog(priority, "libyang: %s", msg);
610}
611
612void yang_init(void)
613{
614 static char ly_plugin_dir[PATH_MAX];
615 const char *const *ly_loaded_plugins;
616 const char *ly_plugin;
617 bool found_ly_frr_types = false;
618
619 /* Tell libyang where to find its plugins. */
620 snprintf(ly_plugin_dir, sizeof(ly_plugin_dir), "%s=%s",
621 "LIBYANG_USER_TYPES_PLUGINS_DIR", LIBYANG_PLUGINS_PATH);
622 putenv(ly_plugin_dir);
623
624 /* Initialize libyang global parameters that affect all containers. */
625 ly_set_log_clb(ly_log_cb, 1);
626 ly_log_options(LY_LOLOG | LY_LOSTORE);
627
628 /* Initialize libyang container for native models. */
629 ly_native_ctx = ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIR_CWD);
630 if (!ly_native_ctx) {
631 flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
632 exit(1);
633 }
3a11599c 634 ly_ctx_set_module_imp_clb(ly_native_ctx, yang_module_imp_clb, NULL);
1c2facd1
RW
635 ly_ctx_set_searchdir(ly_native_ctx, YANG_MODELS_PATH);
636 ly_ctx_set_priv_dup_clb(ly_native_ctx, ly_dup_cb);
637
638 /* Detect if the required libyang plugin(s) were loaded successfully. */
639 ly_loaded_plugins = ly_get_loaded_plugins();
640 for (size_t i = 0; (ly_plugin = ly_loaded_plugins[i]); i++) {
641 if (strmatch(ly_plugin, "frr_user_types")) {
642 found_ly_frr_types = true;
643 break;
644 }
645 }
646 if (!found_ly_frr_types) {
647 flog_err(EC_LIB_LIBYANG_PLUGIN_LOAD,
648 "%s: failed to load frr_user_types.so", __func__);
649 exit(1);
650 }
651
652 yang_translator_init();
653}
654
655void yang_terminate(void)
656{
657 struct yang_module *module;
658
659 yang_translator_terminate();
660
661 while (!RB_EMPTY(yang_modules, &yang_modules)) {
662 module = RB_ROOT(yang_modules, &yang_modules);
663
664 /*
665 * We shouldn't call ly_ctx_remove_module() here because this
666 * function also removes other modules that depend on it.
667 *
668 * ly_ctx_destroy() will release all memory for us.
669 */
670 RB_REMOVE(yang_modules, &yang_modules, module);
671 XFREE(MTYPE_YANG_MODULE, module);
672 }
673
674 ly_ctx_destroy(ly_native_ctx, NULL);
675}