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