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