]> git.proxmox.com Git - mirror_frr.git/blame - lib/yang.c
Merge pull request #11469 from donaldsharp/fdev2
[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
bf8d3d6a
DL
28DEFINE_MTYPE_STATIC(LIB, YANG_MODULE, "YANG module");
29DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure");
1c2facd1
RW
30
31/* libyang container. */
32struct ly_ctx *ly_native_ctx;
33
3a11599c
DL
34static struct yang_module_embed *embeds, **embedupd = &embeds;
35
36void yang_module_embed(struct yang_module_embed *embed)
37{
38 embed->next = NULL;
39 *embedupd = embed;
40 embedupd = &embed->next;
41}
42
3bb513c3
CH
43static LY_ERR yang_module_imp_clb(const char *mod_name, const char *mod_rev,
44 const char *submod_name,
45 const char *submod_rev, void *user_data,
46 LYS_INFORMAT *format,
47 const char **module_data,
48 void (**free_module_data)(void *, void *))
3a11599c
DL
49{
50 struct yang_module_embed *e;
51
908e4c85
DL
52 if (!strcmp(mod_name, "ietf-inet-types") ||
53 !strcmp(mod_name, "ietf-yang-types"))
54 /* libyang has these built in, don't try finding them here */
55 return LY_ENOTFOUND;
56
3a11599c 57 for (e = embeds; e; e = e->next) {
65de8bc8 58 if (e->sub_mod_name && submod_name) {
59 if (strcmp(e->sub_mod_name, submod_name))
60 continue;
61
62 if (submod_rev && strcmp(e->sub_mod_rev, submod_rev))
63 continue;
64 } else {
65 if (strcmp(e->mod_name, mod_name))
66 continue;
67
68 if (mod_rev && strcmp(e->mod_rev, mod_rev))
69 continue;
70 }
3a11599c
DL
71
72 *format = e->format;
3bb513c3
CH
73 *module_data = e->data;
74 return LY_SUCCESS;
3a11599c
DL
75 }
76
3bb513c3
CH
77 /* We get here for indirect modules like ietf-inet-types */
78 zlog_debug(
65de8bc8 79 "YANG model \"%s@%s\" \"%s@%s\"not embedded, trying external file",
80 mod_name, mod_rev ? mod_rev : "*",
81 submod_name ? submod_name : "*", submod_rev ? submod_rev : "*");
3bb513c3
CH
82
83 return LY_ENOTFOUND;
3a11599c
DL
84}
85
40664f16 86/* clang-format off */
96f2c009 87static const char *const frr_native_modules[] = {
a1b5f469 88 "frr-interface",
bc867a5d 89 "frr-vrf",
6a7fb29c
CS
90 "frr-routing",
91 "frr-route-map",
92 "frr-nexthop",
a1b5f469 93 "frr-ripd",
e9ce224b 94 "frr-ripngd",
96f2c009 95 "frr-isisd",
f495425b 96 "frr-vrrpd",
0d2e2bd1 97 "frr-zebra",
4d7b695d 98 "frr-pathd",
a1b5f469 99};
40664f16 100/* clang-format on */
a1b5f469 101
1c2facd1
RW
102/* Generate the yang_modules tree. */
103static inline int yang_module_compare(const struct yang_module *a,
104 const struct yang_module *b)
105{
106 return strcmp(a->name, b->name);
107}
108RB_GENERATE(yang_modules, yang_module, entry, yang_module_compare)
109
110struct yang_modules yang_modules = RB_INITIALIZER(&yang_modules);
111
112struct yang_module *yang_module_load(const char *module_name)
113{
114 struct yang_module *module;
115 const struct lys_module *module_info;
116
3bb513c3
CH
117 module_info =
118 ly_ctx_load_module(ly_native_ctx, module_name, NULL, NULL);
1c2facd1
RW
119 if (!module_info) {
120 flog_err(EC_LIB_YANG_MODULE_LOAD,
121 "%s: failed to load data model: %s", __func__,
122 module_name);
123 exit(1);
124 }
125
126 module = XCALLOC(MTYPE_YANG_MODULE, sizeof(*module));
127 module->name = module_name;
128 module->info = module_info;
129
130 if (RB_INSERT(yang_modules, &yang_modules, module) != NULL) {
131 flog_err(EC_LIB_YANG_MODULE_LOADED_ALREADY,
132 "%s: YANG module is loaded already: %s", __func__,
133 module_name);
134 exit(1);
135 }
136
137 return module;
138}
139
a1b5f469
RW
140void yang_module_load_all(void)
141{
142 for (size_t i = 0; i < array_size(frr_native_modules); i++)
143 yang_module_load(frr_native_modules[i]);
144}
145
1c2facd1
RW
146struct yang_module *yang_module_find(const char *module_name)
147{
148 struct yang_module s;
149
150 s.name = module_name;
151 return RB_FIND(yang_modules, &yang_modules, &s);
152}
153
3bb513c3 154int yang_snodes_iterate_subtree(const struct lysc_node *snode,
8a923b48 155 const struct lys_module *module,
e0ccfad2 156 yang_iterate_cb cb, uint16_t flags, void *arg)
1c2facd1 157{
3bb513c3 158 const struct lysc_node *child;
e0ccfad2 159 int ret = YANG_ITER_CONTINUE;
1c2facd1 160
8a923b48
RW
161 if (module && snode->module != module)
162 goto next;
163
1c2facd1
RW
164 switch (snode->nodetype) {
165 case LYS_CONTAINER:
166 if (CHECK_FLAG(flags, YANG_ITER_FILTER_NPCONTAINERS)) {
3bb513c3 167 if (!CHECK_FLAG(snode->flags, LYS_PRESENCE))
1c2facd1
RW
168 goto next;
169 }
170 break;
171 case LYS_LEAF:
172 if (CHECK_FLAG(flags, YANG_ITER_FILTER_LIST_KEYS)) {
1c2facd1 173 /* Ignore list keys. */
3bb513c3 174 if (lysc_is_key(snode))
1c2facd1
RW
175 goto next;
176 }
177 break;
1c2facd1
RW
178 case LYS_INPUT:
179 case LYS_OUTPUT:
180 if (CHECK_FLAG(flags, YANG_ITER_FILTER_INPUT_OUTPUT))
181 goto next;
182 break;
183 default:
3bb513c3
CH
184 assert(snode->nodetype != LYS_AUGMENT
185 && snode->nodetype != LYS_GROUPING
186 && snode->nodetype != LYS_USES);
1c2facd1
RW
187 break;
188 }
189
e0ccfad2
RW
190 ret = (*cb)(snode, arg);
191 if (ret == YANG_ITER_STOP)
192 return ret;
1c2facd1
RW
193
194next:
195 /*
3bb513c3 196 * YANG leafs and leaf-lists can't have child nodes.
1c2facd1 197 */
db452508 198 if (CHECK_FLAG(snode->nodetype, LYS_LEAF | LYS_LEAFLIST))
e0ccfad2 199 return YANG_ITER_CONTINUE;
1c2facd1 200
3bb513c3 201 LY_LIST_FOR (lysc_node_child(snode), child) {
8a923b48
RW
202 ret = yang_snodes_iterate_subtree(child, module, cb, flags,
203 arg);
e0ccfad2
RW
204 if (ret == YANG_ITER_STOP)
205 return ret;
1c2facd1 206 }
e0ccfad2 207 return ret;
1c2facd1
RW
208}
209
8d869d37
RW
210int yang_snodes_iterate(const struct lys_module *module, yang_iterate_cb cb,
211 uint16_t flags, void *arg)
1c2facd1 212{
9bde0b25
RW
213 const struct lys_module *module_iter;
214 uint32_t idx = 0;
e0ccfad2 215 int ret = YANG_ITER_CONTINUE;
1c2facd1 216
9bde0b25
RW
217 idx = ly_ctx_internal_modules_count(ly_native_ctx);
218 while ((module_iter = ly_ctx_get_module_iter(ly_native_ctx, &idx))) {
3bb513c3 219 struct lysc_node *snode;
1c2facd1 220
9bde0b25
RW
221 if (!module_iter->implemented)
222 continue;
223
3bb513c3
CH
224 LY_LIST_FOR (module_iter->compiled->data, snode) {
225 ret = yang_snodes_iterate_subtree(snode, module, cb,
226 flags, arg);
227 if (ret == YANG_ITER_STOP)
228 return ret;
229 }
230 LY_LIST_FOR (&module_iter->compiled->rpcs->node, snode) {
231 ret = yang_snodes_iterate_subtree(snode, module, cb,
232 flags, arg);
233 if (ret == YANG_ITER_STOP)
234 return ret;
235 }
236 LY_LIST_FOR (&module_iter->compiled->notifs->node, snode) {
9bde0b25
RW
237 ret = yang_snodes_iterate_subtree(snode, module, cb,
238 flags, arg);
239 if (ret == YANG_ITER_STOP)
240 return ret;
241 }
1c2facd1 242 }
e0ccfad2
RW
243
244 return ret;
1c2facd1
RW
245}
246
3bb513c3
CH
247void yang_snode_get_path(const struct lysc_node *snode,
248 enum yang_path_type type, char *xpath,
249 size_t xpath_len)
1c2facd1 250{
1c2facd1
RW
251 switch (type) {
252 case YANG_PATH_SCHEMA:
3bb513c3 253 (void)lysc_path(snode, LYSC_PATH_LOG, xpath, xpath_len);
1c2facd1
RW
254 break;
255 case YANG_PATH_DATA:
3bb513c3 256 (void)lysc_path(snode, LYSC_PATH_DATA, xpath, xpath_len);
1c2facd1
RW
257 break;
258 default:
259 flog_err(EC_LIB_DEVELOPMENT, "%s: unknown yang path type: %u",
260 __func__, type);
261 exit(1);
262 }
1c2facd1
RW
263}
264
3bb513c3 265struct lysc_node *yang_snode_real_parent(const struct lysc_node *snode)
1c2facd1 266{
3bb513c3 267 struct lysc_node *parent = snode->parent;
1c2facd1
RW
268
269 while (parent) {
1c2facd1
RW
270 switch (parent->nodetype) {
271 case LYS_CONTAINER:
3bb513c3 272 if (CHECK_FLAG(parent->flags, LYS_PRESENCE))
1c2facd1
RW
273 return parent;
274 break;
275 case LYS_LIST:
276 return parent;
277 default:
278 break;
279 }
280 parent = parent->parent;
281 }
282
283 return NULL;
284}
285
3bb513c3 286struct lysc_node *yang_snode_parent_list(const struct lysc_node *snode)
1c2facd1 287{
3bb513c3 288 struct lysc_node *parent = snode->parent;
1c2facd1
RW
289
290 while (parent) {
291 switch (parent->nodetype) {
292 case LYS_LIST:
293 return parent;
294 default:
295 break;
296 }
297 parent = parent->parent;
298 }
299
300 return NULL;
301}
302
3bb513c3 303bool yang_snode_is_typeless_data(const struct lysc_node *snode)
1c2facd1 304{
3bb513c3 305 const struct lysc_node_leaf *sleaf;
1c2facd1
RW
306
307 switch (snode->nodetype) {
308 case LYS_LEAF:
3bb513c3
CH
309 sleaf = (struct lysc_node_leaf *)snode;
310 if (sleaf->type->basetype == LY_TYPE_EMPTY)
1c2facd1
RW
311 return true;
312 return false;
313 case LYS_LEAFLIST:
314 return false;
315 default:
316 return true;
317 }
318}
319
3bb513c3 320const char *yang_snode_get_default(const struct lysc_node *snode)
1c2facd1 321{
3bb513c3 322 const struct lysc_node_leaf *sleaf;
1c2facd1
RW
323
324 switch (snode->nodetype) {
325 case LYS_LEAF:
3bb513c3
CH
326 sleaf = (const struct lysc_node_leaf *)snode;
327 return sleaf->dflt ? lyd_value_get_canonical(sleaf->module->ctx,
328 sleaf->dflt)
329 : NULL;
1c2facd1
RW
330 case LYS_LEAFLIST:
331 /* TODO: check leaf-list default values */
332 return NULL;
333 default:
334 return NULL;
335 }
336}
337
3bb513c3 338const struct lysc_type *yang_snode_get_type(const struct lysc_node *snode)
1c2facd1 339{
3bb513c3
CH
340 struct lysc_node_leaf *sleaf = (struct lysc_node_leaf *)snode;
341 struct lysc_type *type;
1c2facd1 342
db452508 343 if (!CHECK_FLAG(sleaf->nodetype, LYS_LEAF | LYS_LEAFLIST))
1c2facd1
RW
344 return NULL;
345
3bb513c3
CH
346 type = sleaf->type;
347 while (type->basetype == LY_TYPE_LEAFREF)
348 type = ((struct lysc_type_leafref *)type)->realtype;
1c2facd1
RW
349
350 return type;
351}
352
3bb513c3
CH
353unsigned int yang_snode_num_keys(const struct lysc_node *snode)
354{
355 const struct lysc_node_leaf *skey;
356 uint count = 0;
357
358 if (!CHECK_FLAG(snode->nodetype, LYS_LIST))
359 return 0;
360
361 /* Walk list of children */
362 LY_FOR_KEYS (snode, skey) {
363 count++;
364 }
365 return count;
366}
367
1c2facd1
RW
368void yang_dnode_get_path(const struct lyd_node *dnode, char *xpath,
369 size_t xpath_len)
370{
3bb513c3 371 lyd_path(dnode, LYD_PATH_STD, xpath, xpath_len);
1c2facd1
RW
372}
373
3f662078
RW
374const char *yang_dnode_get_schema_name(const struct lyd_node *dnode,
375 const char *xpath_fmt, ...)
376{
377 if (xpath_fmt) {
378 va_list ap;
379 char xpath[XPATH_MAXLEN];
380
381 va_start(ap, xpath_fmt);
382 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
383 va_end(ap);
384
385 dnode = yang_dnode_get(dnode, xpath);
386 if (!dnode) {
387 flog_err(EC_LIB_YANG_DNODE_NOT_FOUND,
388 "%s: couldn't find %s", __func__, xpath);
389 zlog_backtrace(LOG_ERR);
390 abort();
391 }
392 }
393
394 return dnode->schema->name;
395}
396
3bb513c3 397struct lyd_node *yang_dnode_get(const struct lyd_node *dnode, const char *xpath)
1c2facd1 398{
3bb513c3 399 struct ly_set *set = NULL;
1c2facd1
RW
400 struct lyd_node *dnode_ret = NULL;
401
3bb513c3
CH
402 /*
403 * XXX a lot of the code uses this for style I guess. It shouldn't, as
404 * it adds to the xpath parsing complexity in libyang.
405 */
406 if (xpath[0] == '.' && xpath[1] == '/')
407 xpath += 2;
1c2facd1 408
3bb513c3
CH
409 if (lyd_find_xpath(dnode, xpath, &set)) {
410 assert(0); /* XXX replicates old libyang1 base code */
411 goto exit;
412 }
413 if (set->count == 0)
1c2facd1
RW
414 goto exit;
415
3bb513c3 416 if (set->count > 1) {
1c2facd1
RW
417 flog_warn(EC_LIB_YANG_DNODE_NOT_FOUND,
418 "%s: found %u elements (expected 0 or 1) [xpath %s]",
3bb513c3 419 __func__, set->count, xpath);
1c2facd1
RW
420 goto exit;
421 }
422
3bb513c3 423 dnode_ret = set->dnodes[0];
1c2facd1
RW
424
425exit:
3bb513c3 426 ly_set_free(set, NULL);
1c2facd1
RW
427
428 return dnode_ret;
429}
430
3bb513c3
CH
431struct lyd_node *yang_dnode_getf(const struct lyd_node *dnode,
432 const char *xpath_fmt, ...)
1c2facd1
RW
433{
434 va_list ap;
435 char xpath[XPATH_MAXLEN];
1c2facd1
RW
436
437 va_start(ap, xpath_fmt);
438 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
439 va_end(ap);
440
3bb513c3
CH
441 return yang_dnode_get(dnode, xpath);
442}
443
444bool yang_dnode_exists(const struct lyd_node *dnode, const char *xpath)
445{
446 struct ly_set *set = NULL;
447 bool exists = false;
1c2facd1 448
3bb513c3
CH
449 if (xpath[0] == '.' && xpath[1] == '/')
450 xpath += 2;
451 if (lyd_find_xpath(dnode, xpath, &set))
452 return false;
453 exists = set->count > 0;
454 ly_set_free(set, NULL);
455 return exists;
456}
457
458bool yang_dnode_existsf(const struct lyd_node *dnode, const char *xpath_fmt,
459 ...)
460{
461 va_list ap;
462 char xpath[XPATH_MAXLEN];
463
464 va_start(ap, xpath_fmt);
465 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
466 va_end(ap);
467
468 return yang_dnode_exists(dnode, xpath);
1c2facd1
RW
469}
470
7b611145
RW
471void yang_dnode_iterate(yang_dnode_iter_cb cb, void *arg,
472 const struct lyd_node *dnode, const char *xpath_fmt,
473 ...)
474{
475 va_list ap;
476 char xpath[XPATH_MAXLEN];
477 struct ly_set *set;
478
479 va_start(ap, xpath_fmt);
480 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
481 va_end(ap);
482
3bb513c3
CH
483 if (lyd_find_xpath(dnode, xpath, &set)) {
484 assert(0); /* XXX libyang2: ly1 code asserted success */
485 return;
486 }
487 for (unsigned int i = 0; i < set->count; i++) {
7b611145
RW
488 int ret;
489
3bb513c3 490 ret = (*cb)(set->dnodes[i], arg);
7b611145 491 if (ret == YANG_ITER_STOP)
4e32d023 492 break;
7b611145
RW
493 }
494
3bb513c3 495 ly_set_free(set, NULL);
7b611145
RW
496}
497
3bb513c3 498bool yang_dnode_is_default(const struct lyd_node *dnode, const char *xpath)
1c2facd1 499{
3bb513c3
CH
500 const struct lysc_node *snode;
501 struct lysc_node_leaf *sleaf;
1c2facd1 502
3bb513c3 503 if (xpath)
1c2facd1 504 dnode = yang_dnode_get(dnode, xpath);
1c2facd1
RW
505
506 assert(dnode);
507 snode = dnode->schema;
508 switch (snode->nodetype) {
509 case LYS_LEAF:
3bb513c3
CH
510 sleaf = (struct lysc_node_leaf *)snode;
511 if (sleaf->type->basetype == LY_TYPE_EMPTY)
1c2facd1 512 return false;
3bb513c3 513 return lyd_is_default(dnode);
1c2facd1
RW
514 case LYS_LEAFLIST:
515 /* TODO: check leaf-list default values */
516 return false;
517 case LYS_CONTAINER:
3bb513c3 518 if (CHECK_FLAG(snode->flags, LYS_PRESENCE))
1c2facd1
RW
519 return false;
520 return true;
521 default:
522 return false;
523 }
524}
525
3bb513c3
CH
526bool yang_dnode_is_defaultf(const struct lyd_node *dnode, const char *xpath_fmt,
527 ...)
1c2facd1 528{
3bb513c3 529 if (!xpath_fmt)
1c2facd1 530 return yang_dnode_is_default(dnode, NULL);
3bb513c3
CH
531 else {
532 va_list ap;
533 char xpath[XPATH_MAXLEN];
534
535 va_start(ap, xpath_fmt);
536 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
537 va_end(ap);
538
539 return yang_dnode_is_default(dnode, xpath);
540 }
541}
542
543bool yang_dnode_is_default_recursive(const struct lyd_node *dnode)
544{
545 struct lyd_node *root, *dnode_iter;
1c2facd1
RW
546
547 if (!yang_dnode_is_default(dnode, NULL))
548 return false;
549
3bb513c3
CH
550 if (CHECK_FLAG(dnode->schema->nodetype, LYS_LEAF | LYS_LEAFLIST))
551 return true;
552
553 LY_LIST_FOR (lyd_child(dnode), root) {
554 LYD_TREE_DFS_BEGIN (root, dnode_iter) {
1c2facd1
RW
555 if (!yang_dnode_is_default(dnode_iter, NULL))
556 return false;
557
3bb513c3 558 LYD_TREE_DFS_END(root, dnode_iter);
1c2facd1
RW
559 }
560 }
561
562 return true;
563}
564
565void yang_dnode_change_leaf(struct lyd_node *dnode, const char *value)
566{
567 assert(dnode->schema->nodetype == LYS_LEAF);
3bb513c3 568 lyd_change_term(dnode, value);
1c2facd1
RW
569}
570
5e02643a 571struct lyd_node *yang_dnode_new(struct ly_ctx *ly_ctx, bool config_only)
1c2facd1 572{
3bb513c3
CH
573 struct lyd_node *dnode = NULL;
574 int options = config_only ? LYD_VALIDATE_NO_STATE : 0;
1c2facd1 575
3bb513c3 576 if (lyd_validate_all(&dnode, ly_ctx, options, NULL) != 0) {
1c2facd1
RW
577 /* Should never happen. */
578 flog_err(EC_LIB_LIBYANG, "%s: lyd_validate() failed", __func__);
579 exit(1);
580 }
581
582 return dnode;
583}
584
585struct lyd_node *yang_dnode_dup(const struct lyd_node *dnode)
586{
3bb513c3
CH
587 struct lyd_node *dup = NULL;
588 LY_ERR err;
589 err = lyd_dup_siblings(dnode, NULL, LYD_DUP_RECURSIVE, &dup);
590 assert(!err);
591 return dup;
1c2facd1
RW
592}
593
594void yang_dnode_free(struct lyd_node *dnode)
595{
e5dc8a44 596 while (dnode->parent)
3bb513c3
CH
597 dnode = lyd_parent(dnode);
598 lyd_free_all(dnode);
1c2facd1
RW
599}
600
601struct yang_data *yang_data_new(const char *xpath, const char *value)
602{
1c2facd1
RW
603 struct yang_data *data;
604
1c2facd1
RW
605 data = XCALLOC(MTYPE_YANG_DATA, sizeof(*data));
606 strlcpy(data->xpath, xpath, sizeof(data->xpath));
1c2facd1
RW
607 if (value)
608 data->value = strdup(value);
609
610 return data;
611}
612
613void yang_data_free(struct yang_data *data)
614{
615 if (data->value)
616 free(data->value);
617 XFREE(MTYPE_YANG_DATA, data);
618}
619
620struct list *yang_data_list_new(void)
621{
622 struct list *list;
623
624 list = list_new();
625 list->del = (void (*)(void *))yang_data_free;
626
627 return list;
628}
629
fcb7bffd
RW
630struct yang_data *yang_data_list_find(const struct list *list,
631 const char *xpath_fmt, ...)
632{
633 char xpath[XPATH_MAXLEN];
634 struct yang_data *data;
635 struct listnode *node;
636 va_list ap;
637
638 va_start(ap, xpath_fmt);
639 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
640 va_end(ap);
641
642 for (ALL_LIST_ELEMENTS_RO(list, node, data))
643 if (strmatch(data->xpath, xpath))
644 return data;
645
646 return NULL;
647}
648
1c2facd1
RW
649/* Make libyang log its errors using FRR logging infrastructure. */
650static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
651{
96679938 652 int priority = LOG_ERR;
1c2facd1
RW
653
654 switch (level) {
655 case LY_LLERR:
656 priority = LOG_ERR;
657 break;
658 case LY_LLWRN:
659 priority = LOG_WARNING;
660 break;
661 case LY_LLVRB:
96679938 662 case LY_LLDBG:
1c2facd1
RW
663 priority = LOG_DEBUG;
664 break;
1c2facd1
RW
665 }
666
667 if (path)
668 zlog(priority, "libyang: %s (%s)", msg, path);
669 else
670 zlog(priority, "libyang: %s", msg);
671}
672
df5eda3d
RW
673const char *yang_print_errors(struct ly_ctx *ly_ctx, char *buf, size_t buf_len)
674{
675 struct ly_err_item *ei;
676 const char *path;
677
678 ei = ly_err_first(ly_ctx);
679 if (!ei)
680 return "";
681
682 strlcpy(buf, "YANG error(s):\n", buf_len);
683 for (; ei; ei = ei->next) {
684 strlcat(buf, " ", buf_len);
685 strlcat(buf, ei->msg, buf_len);
686 strlcat(buf, "\n", buf_len);
687 }
688
689 path = ly_errpath(ly_ctx);
690 if (path) {
691 strlcat(buf, " YANG path: ", buf_len);
692 strlcat(buf, path, buf_len);
693 strlcat(buf, "\n", buf_len);
694 }
695
696 ly_err_clean(ly_ctx, NULL);
697
698 return buf;
699}
700
62ae9ade
RW
701void yang_debugging_set(bool enable)
702{
703 if (enable) {
3bb513c3
CH
704 ly_log_level(LY_LLDBG);
705 ly_log_dbg_groups(0xFF);
62ae9ade 706 } else {
3bb513c3
CH
707 ly_log_level(LY_LLERR);
708 ly_log_dbg_groups(0);
62ae9ade
RW
709 }
710}
711
3bb513c3 712struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile)
591f57cf 713{
3bb513c3 714 struct ly_ctx *ctx = NULL;
591f57cf 715 const char *yang_models_path = YANG_MODELS_PATH;
3bb513c3 716 LY_ERR err;
591f57cf
DL
717
718 if (access(yang_models_path, R_OK | X_OK)) {
719 yang_models_path = NULL;
720 if (errno == ENOENT)
721 zlog_info("yang model directory \"%s\" does not exist",
722 YANG_MODELS_PATH);
723 else
724 flog_err_sys(EC_LIB_LIBYANG,
725 "cannot access yang model directory \"%s\"",
726 YANG_MODELS_PATH);
727 }
728
3bb513c3
CH
729 uint options = LY_CTX_NO_YANGLIBRARY | LY_CTX_DISABLE_SEARCHDIR_CWD;
730 if (explicit_compile)
731 options |= LY_CTX_EXPLICIT_COMPILE;
732 err = ly_ctx_new(yang_models_path, options, &ctx);
733 if (err)
591f57cf 734 return NULL;
b90204a8
RW
735
736 if (embedded_modules)
737 ly_ctx_set_module_imp_clb(ctx, yang_module_imp_clb, NULL);
738
591f57cf
DL
739 return ctx;
740}
741
3bb513c3 742void yang_init(bool embedded_modules, bool defer_compile)
1c2facd1 743{
1c2facd1
RW
744 /* Initialize libyang global parameters that affect all containers. */
745 ly_set_log_clb(ly_log_cb, 1);
746 ly_log_options(LY_LOLOG | LY_LOSTORE);
747
748 /* Initialize libyang container for native models. */
3bb513c3 749 ly_native_ctx = yang_ctx_new_setup(embedded_modules, defer_compile);
1c2facd1
RW
750 if (!ly_native_ctx) {
751 flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
752 exit(1);
753 }
1c2facd1 754
1c2facd1
RW
755 yang_translator_init();
756}
757
3bb513c3
CH
758void yang_init_loading_complete(void)
759{
760 /* Compile everything */
761 if (ly_ctx_compile(ly_native_ctx) != LY_SUCCESS) {
762 flog_err(EC_LIB_YANG_MODULE_LOAD,
763 "%s: failed to compile loaded modules: %s", __func__,
764 ly_errmsg(ly_native_ctx));
765 exit(1);
766 }
767}
768
1c2facd1
RW
769void yang_terminate(void)
770{
771 struct yang_module *module;
772
773 yang_translator_terminate();
774
775 while (!RB_EMPTY(yang_modules, &yang_modules)) {
776 module = RB_ROOT(yang_modules, &yang_modules);
777
778 /*
779 * We shouldn't call ly_ctx_remove_module() here because this
780 * function also removes other modules that depend on it.
781 *
782 * ly_ctx_destroy() will release all memory for us.
783 */
784 RB_REMOVE(yang_modules, &yang_modules, module);
785 XFREE(MTYPE_YANG_MODULE, module);
786 }
787
3bb513c3 788 ly_ctx_destroy(ly_native_ctx);
1c2facd1 789}
27802d3f 790
791const struct lyd_node *yang_dnode_get_parent(const struct lyd_node *dnode,
792 const char *name)
793{
794 const struct lyd_node *orig_dnode = dnode;
795
796 while (orig_dnode) {
797 switch (orig_dnode->schema->nodetype) {
798 case LYS_LIST:
799 case LYS_CONTAINER:
800 if (!strcmp(orig_dnode->schema->name, name))
801 return orig_dnode;
802 break;
803 default:
804 break;
805 }
806
3bb513c3 807 orig_dnode = lyd_parent(orig_dnode);
27802d3f 808 }
809
810 return NULL;
811}
812
cf740d2e 813bool yang_is_last_list_dnode(const struct lyd_node *dnode)
27802d3f 814{
815 return (((dnode->next == NULL)
816 || (dnode->next
817 && (strcmp(dnode->next->schema->name, dnode->schema->name)
818 != 0)))
819 && dnode->prev
820 && ((dnode->prev == dnode)
821 || (strcmp(dnode->prev->schema->name, dnode->schema->name)
822 != 0)));
823}
824
cf740d2e 825bool yang_is_last_level_dnode(const struct lyd_node *dnode)
27802d3f 826{
827 const struct lyd_node *parent;
27802d3f 828 const struct lyd_node *key_leaf;
829 uint8_t keys_size;
830
831 switch (dnode->schema->nodetype) {
832 case LYS_LIST:
833 assert(dnode->parent);
3bb513c3
CH
834 parent = lyd_parent(dnode);
835 uint snode_num_keys = yang_snode_num_keys(parent->schema);
836 /* XXX libyang2: q: really don't understand this code. */
27802d3f 837 key_leaf = dnode->prev;
3bb513c3 838 for (keys_size = 1; keys_size < snode_num_keys; keys_size++)
27802d3f 839 key_leaf = key_leaf->prev;
840 if (key_leaf->prev == dnode)
841 return true;
842 break;
843 case LYS_CONTAINER:
844 return true;
845 default:
846 break;
847 }
848
849 return false;
850}
851
27802d3f 852const struct lyd_node *
853yang_get_subtree_with_no_sibling(const struct lyd_node *dnode)
854{
855 bool parent = true;
856 const struct lyd_node *node;
27802d3f 857
858 node = dnode;
859 if (node->schema->nodetype != LYS_LIST)
860 return node;
861
862 while (parent) {
863 switch (node->schema->nodetype) {
864 case LYS_CONTAINER:
3bb513c3 865 if (!CHECK_FLAG(node->schema->flags, LYS_PRESENCE)) {
27802d3f 866 if (node->parent
867 && (node->parent->schema->module
868 == dnode->schema->module))
3bb513c3 869 node = lyd_parent(node);
27802d3f 870 else
871 parent = false;
872 } else
873 parent = false;
874 break;
875 case LYS_LIST:
876 if (yang_is_last_list_dnode(node)
877 && yang_is_last_level_dnode(node)) {
878 if (node->parent
879 && (node->parent->schema->module
880 == dnode->schema->module))
3bb513c3 881 node = lyd_parent(node);
27802d3f 882 else
883 parent = false;
884 } else
885 parent = false;
886 break;
887 default:
888 parent = false;
889 break;
890 }
891 }
892 return node;
893}
894
895uint32_t yang_get_list_pos(const struct lyd_node *node)
896{
897 return lyd_list_pos(node);
898}
899
900uint32_t yang_get_list_elements_count(const struct lyd_node *node)
901{
902 unsigned int count;
3bb513c3 903 const struct lysc_node *schema;
27802d3f 904
905 if (!node
906 || ((node->schema->nodetype != LYS_LIST)
907 && (node->schema->nodetype != LYS_LEAFLIST))) {
908 return 0;
909 }
910
911 schema = node->schema;
912 count = 0;
913 do {
914 if (node->schema == schema)
915 ++count;
916 node = node->next;
917 } while (node);
918 return count;
919}