2 * Copyright (C) 2018 NetDEF, Inc.
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)
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
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
24 #include "lib_errors.h"
26 #include "yang_translator.h"
27 #include "northbound.h"
29 DEFINE_MTYPE(LIB
, YANG_MODULE
, "YANG module")
30 DEFINE_MTYPE(LIB
, YANG_DATA
, "YANG data structure")
32 /* libyang container. */
33 struct ly_ctx
*ly_native_ctx
;
35 static struct yang_module_embed
*embeds
, **embedupd
= &embeds
;
37 void yang_module_embed(struct yang_module_embed
*embed
)
41 embedupd
= &embed
->next
;
44 static const char *yang_module_imp_clb(const char *mod_name
,
46 const char *submod_name
,
47 const char *submod_rev
,
50 void (**free_module_data
)
53 struct yang_module_embed
*e
;
55 if (submod_name
|| submod_rev
)
58 for (e
= embeds
; e
; e
= e
->next
) {
59 if (strcmp(e
->mod_name
, mod_name
))
61 if (mod_rev
&& strcmp(e
->mod_rev
, mod_rev
))
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
: "*");
74 /* Generate the yang_modules tree. */
75 static inline int yang_module_compare(const struct yang_module
*a
,
76 const struct yang_module
*b
)
78 return strcmp(a
->name
, b
->name
);
80 RB_GENERATE(yang_modules
, yang_module
, entry
, yang_module_compare
)
82 struct yang_modules yang_modules
= RB_INITIALIZER(&yang_modules
);
84 struct yang_module
*yang_module_load(const char *module_name
)
86 struct yang_module
*module
;
87 const struct lys_module
*module_info
;
89 module_info
= ly_ctx_load_module(ly_native_ctx
, module_name
, NULL
);
91 flog_err(EC_LIB_YANG_MODULE_LOAD
,
92 "%s: failed to load data model: %s", __func__
,
97 module
= XCALLOC(MTYPE_YANG_MODULE
, sizeof(*module
));
98 module
->name
= module_name
;
99 module
->info
= module_info
;
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__
,
111 struct yang_module
*yang_module_find(const char *module_name
)
113 struct yang_module s
;
115 s
.name
= module_name
;
116 return RB_FIND(yang_modules
, &yang_modules
, &s
);
120 * Helper function for yang_module_snodes_iterate() and
121 * yang_all_snodes_iterate(). This is a recursive function.
123 static void yang_snodes_iterate(const struct lys_node
*snode
,
124 void (*func
)(const struct lys_node
*, void *,
126 uint16_t flags
, void *arg1
, void *arg2
)
128 struct lys_node
*child
;
130 if (CHECK_FLAG(flags
, YANG_ITER_FILTER_IMPLICIT
)) {
131 switch (snode
->nodetype
) {
135 if (snode
->flags
& LYS_IMPLICIT
)
143 switch (snode
->nodetype
) {
145 if (CHECK_FLAG(flags
, YANG_ITER_FILTER_NPCONTAINERS
)) {
146 struct lys_node_container
*scontainer
;
148 scontainer
= (struct lys_node_container
*)snode
;
149 if (!scontainer
->presence
)
154 if (CHECK_FLAG(flags
, YANG_ITER_FILTER_LIST_KEYS
)) {
155 struct lys_node_leaf
*sleaf
;
157 /* Ignore list keys. */
158 sleaf
= (struct lys_node_leaf
*)snode
;
159 if (lys_is_key(sleaf
, NULL
))
164 /* Return since we're not interested in the grouping subtree. */
168 /* Always ignore nodes of these types. */
172 if (CHECK_FLAG(flags
, YANG_ITER_FILTER_INPUT_OUTPUT
))
179 (*func
)(snode
, arg1
, arg2
);
183 * YANG leafs and leaf-lists can't have child nodes, and trying to
184 * access snode->child is undefined behavior.
186 if (snode
->nodetype
& (LYS_LEAF
| LYS_LEAFLIST
))
189 LY_TREE_FOR (snode
->child
, child
) {
190 if (child
->parent
!= snode
)
192 yang_snodes_iterate(child
, func
, flags
, arg1
, arg2
);
196 void yang_module_snodes_iterate(const struct lys_module
*module
,
197 void (*func
)(const struct lys_node
*, void *,
199 uint16_t flags
, void *arg1
, void *arg2
)
201 struct lys_node
*snode
;
203 LY_TREE_FOR (module
->data
, snode
) {
204 yang_snodes_iterate(snode
, func
, flags
, arg1
, arg2
);
207 for (uint8_t i
= 0; i
< module
->augment_size
; i
++) {
209 (const struct lys_node
*)&module
->augment
[i
], func
,
214 void yang_all_snodes_iterate(void (*func
)(const struct lys_node
*, void *,
216 uint16_t flags
, void *arg1
, void *arg2
)
218 struct yang_module
*module
;
220 RB_FOREACH (module
, yang_modules
, &yang_modules
)
221 yang_module_snodes_iterate(module
->info
, func
, flags
, arg1
,
225 void yang_snode_get_path(const struct lys_node
*snode
, enum yang_path_type type
,
226 char *xpath
, size_t xpath_len
)
231 case YANG_PATH_SCHEMA
:
232 xpath_ptr
= lys_path(snode
, 0);
235 xpath_ptr
= lys_data_path(snode
);
238 flog_err(EC_LIB_DEVELOPMENT
, "%s: unknown yang path type: %u",
242 strlcpy(xpath
, xpath_ptr
, xpath_len
);
246 struct lys_node
*yang_snode_real_parent(const struct lys_node
*snode
)
248 struct lys_node
*parent
= snode
->parent
;
251 struct lys_node_container
*scontainer
;
253 switch (parent
->nodetype
) {
255 scontainer
= (struct lys_node_container
*)parent
;
256 if (scontainer
->presence
)
264 parent
= parent
->parent
;
270 struct lys_node
*yang_snode_parent_list(const struct lys_node
*snode
)
272 struct lys_node
*parent
= snode
->parent
;
275 switch (parent
->nodetype
) {
281 parent
= parent
->parent
;
287 bool yang_snode_is_typeless_data(const struct lys_node
*snode
)
289 struct lys_node_leaf
*sleaf
;
291 switch (snode
->nodetype
) {
293 sleaf
= (struct lys_node_leaf
*)snode
;
294 if (sleaf
->type
.base
== LY_TYPE_EMPTY
)
304 const char *yang_snode_get_default(const struct lys_node
*snode
)
306 struct lys_node_leaf
*sleaf
;
308 switch (snode
->nodetype
) {
310 sleaf
= (struct lys_node_leaf
*)snode
;
312 /* NOTE: this might be null. */
315 /* TODO: check leaf-list default values */
322 const struct lys_type
*yang_snode_get_type(const struct lys_node
*snode
)
324 struct lys_node_leaf
*sleaf
= (struct lys_node_leaf
*)snode
;
325 struct lys_type
*type
;
327 if (!(sleaf
->nodetype
& (LYS_LEAF
| LYS_LEAFLIST
)))
331 while (type
->base
== LY_TYPE_LEAFREF
)
332 type
= &type
->info
.lref
.target
->type
;
337 void yang_dnode_get_path(const struct lyd_node
*dnode
, char *xpath
,
342 xpath_ptr
= lyd_path(dnode
);
343 strlcpy(xpath
, xpath_ptr
, xpath_len
);
347 struct lyd_node
*yang_dnode_get(const struct lyd_node
*dnode
,
348 const char *xpath_fmt
, ...)
351 char xpath
[XPATH_MAXLEN
];
353 struct lyd_node
*dnode_ret
= NULL
;
355 va_start(ap
, xpath_fmt
);
356 vsnprintf(xpath
, sizeof(xpath
), xpath_fmt
, ap
);
359 set
= lyd_find_path(dnode
, xpath
);
361 if (set
->number
== 0)
364 if (set
->number
> 1) {
365 flog_warn(EC_LIB_YANG_DNODE_NOT_FOUND
,
366 "%s: found %u elements (expected 0 or 1) [xpath %s]",
367 __func__
, set
->number
, xpath
);
371 dnode_ret
= set
->set
.d
[0];
379 bool yang_dnode_exists(const struct lyd_node
*dnode
, const char *xpath_fmt
, ...)
382 char xpath
[XPATH_MAXLEN
];
386 va_start(ap
, xpath_fmt
);
387 vsnprintf(xpath
, sizeof(xpath
), xpath_fmt
, ap
);
390 set
= lyd_find_path(dnode
, xpath
);
392 found
= (set
->number
> 0);
398 bool yang_dnode_is_default(const struct lyd_node
*dnode
, const char *xpath_fmt
,
401 struct lys_node
*snode
;
402 struct lys_node_leaf
*sleaf
;
403 struct lys_node_container
*scontainer
;
407 char xpath
[XPATH_MAXLEN
];
409 va_start(ap
, xpath_fmt
);
410 vsnprintf(xpath
, sizeof(xpath
), xpath_fmt
, ap
);
413 dnode
= yang_dnode_get(dnode
, xpath
);
417 snode
= dnode
->schema
;
418 switch (snode
->nodetype
) {
420 sleaf
= (struct lys_node_leaf
*)snode
;
421 if (sleaf
->type
.base
== LY_TYPE_EMPTY
)
423 return lyd_wd_default((struct lyd_node_leaf_list
*)dnode
);
425 /* TODO: check leaf-list default values */
428 scontainer
= (struct lys_node_container
*)snode
;
429 if (scontainer
->presence
)
437 bool yang_dnode_is_default_recursive(const struct lyd_node
*dnode
)
439 struct lys_node
*snode
;
440 struct lyd_node
*root
, *next
, *dnode_iter
;
442 snode
= dnode
->schema
;
443 if (snode
->nodetype
& (LYS_LEAF
| LYS_LEAFLIST
))
444 return yang_dnode_is_default(dnode
, NULL
);
446 if (!yang_dnode_is_default(dnode
, NULL
))
449 LY_TREE_FOR (dnode
->child
, root
) {
450 LY_TREE_DFS_BEGIN (root
, next
, dnode_iter
) {
451 if (!yang_dnode_is_default(dnode_iter
, NULL
))
454 LY_TREE_DFS_END(root
, next
, dnode_iter
);
461 void yang_dnode_change_leaf(struct lyd_node
*dnode
, const char *value
)
463 assert(dnode
->schema
->nodetype
== LYS_LEAF
);
464 lyd_change_leaf((struct lyd_node_leaf_list
*)dnode
, value
);
467 void yang_dnode_set_entry(const struct lyd_node
*dnode
, void *entry
)
469 assert(dnode
->schema
->nodetype
& (LYS_LIST
| LYS_CONTAINER
));
470 lyd_set_private(dnode
, entry
);
473 void *yang_dnode_get_entry(const struct lyd_node
*dnode
)
475 const struct lyd_node
*orig_dnode
= dnode
;
476 char xpath
[XPATH_MAXLEN
];
479 switch (dnode
->schema
->nodetype
) {
489 dnode
= dnode
->parent
;
492 yang_dnode_get_path(orig_dnode
, xpath
, sizeof(xpath
));
493 flog_err(EC_LIB_YANG_DNODE_NOT_FOUND
,
494 "%s: failed to find entry [xpath %s]", __func__
, xpath
);
495 zlog_backtrace(LOG_ERR
);
499 struct lyd_node
*yang_dnode_new(struct ly_ctx
*ly_ctx
)
501 struct lyd_node
*dnode
;
504 if (lyd_validate(&dnode
, LYD_OPT_CONFIG
, ly_ctx
) != 0) {
505 /* Should never happen. */
506 flog_err(EC_LIB_LIBYANG
, "%s: lyd_validate() failed", __func__
);
513 struct lyd_node
*yang_dnode_dup(const struct lyd_node
*dnode
)
515 return lyd_dup_withsiblings(dnode
, 1);
518 void yang_dnode_free(struct lyd_node
*dnode
)
520 lyd_free_withsiblings(dnode
);
523 struct yang_data
*yang_data_new(const char *xpath
, const char *value
)
525 const struct lys_node
*snode
;
526 struct yang_data
*data
;
528 snode
= ly_ctx_get_node(ly_native_ctx
, NULL
, xpath
, 0);
530 snode
= ly_ctx_get_node(ly_native_ctx
, NULL
, xpath
, 1);
532 flog_err(EC_LIB_YANG_UNKNOWN_DATA_PATH
,
533 "%s: unknown data path: %s", __func__
, xpath
);
534 zlog_backtrace(LOG_ERR
);
538 data
= XCALLOC(MTYPE_YANG_DATA
, sizeof(*data
));
539 strlcpy(data
->xpath
, xpath
, sizeof(data
->xpath
));
542 data
->value
= strdup(value
);
547 void yang_data_free(struct yang_data
*data
)
551 XFREE(MTYPE_YANG_DATA
, data
);
554 struct list
*yang_data_list_new(void)
559 list
->del
= (void (*)(void *))yang_data_free
;
564 static void *ly_dup_cb(const void *priv
)
566 /* Make a shallow copy of the priv pointer. */
570 /* Make libyang log its errors using FRR logging infrastructure. */
571 static void ly_log_cb(LY_LOG_LEVEL level
, const char *msg
, const char *path
)
580 priority
= LOG_WARNING
;
583 priority
= LOG_DEBUG
;
590 zlog(priority
, "libyang: %s (%s)", msg
, path
);
592 zlog(priority
, "libyang: %s", msg
);
597 static char ly_plugin_dir
[PATH_MAX
];
598 const char *const *ly_loaded_plugins
;
599 const char *ly_plugin
;
600 bool found_ly_frr_types
= false;
602 /* Tell libyang where to find its plugins. */
603 snprintf(ly_plugin_dir
, sizeof(ly_plugin_dir
), "%s=%s",
604 "LIBYANG_USER_TYPES_PLUGINS_DIR", LIBYANG_PLUGINS_PATH
);
605 putenv(ly_plugin_dir
);
607 /* Initialize libyang global parameters that affect all containers. */
608 ly_set_log_clb(ly_log_cb
, 1);
609 ly_log_options(LY_LOLOG
| LY_LOSTORE
);
611 /* Initialize libyang container for native models. */
613 ly_ctx_new(YANG_MODELS_PATH
, LY_CTX_DISABLE_SEARCHDIR_CWD
);
614 if (!ly_native_ctx
) {
615 flog_err(EC_LIB_LIBYANG
, "%s: ly_ctx_new() failed", __func__
);
618 ly_ctx_set_module_imp_clb(ly_native_ctx
, yang_module_imp_clb
, NULL
);
619 ly_ctx_set_priv_dup_clb(ly_native_ctx
, ly_dup_cb
);
621 /* Detect if the required libyang plugin(s) were loaded successfully. */
622 ly_loaded_plugins
= ly_get_loaded_plugins();
623 for (size_t i
= 0; (ly_plugin
= ly_loaded_plugins
[i
]); i
++) {
624 if (strmatch(ly_plugin
, "frr_user_types")) {
625 found_ly_frr_types
= true;
629 if (!found_ly_frr_types
) {
630 flog_err(EC_LIB_LIBYANG_PLUGIN_LOAD
,
631 "%s: failed to load frr_user_types.so", __func__
);
635 yang_translator_init();
638 void yang_terminate(void)
640 struct yang_module
*module
;
642 yang_translator_terminate();
644 while (!RB_EMPTY(yang_modules
, &yang_modules
)) {
645 module
= RB_ROOT(yang_modules
, &yang_modules
);
648 * We shouldn't call ly_ctx_remove_module() here because this
649 * function also removes other modules that depend on it.
651 * ly_ctx_destroy() will release all memory for us.
653 RB_REMOVE(yang_modules
, &yang_modules
, module
);
654 XFREE(MTYPE_YANG_MODULE
, module
);
657 ly_ctx_destroy(ly_native_ctx
, NULL
);