]> git.proxmox.com Git - mirror_frr.git/blob - lib/yang.c
Merge pull request #9880 from louis-oui/maximum-prefix-out
[mirror_frr.git] / lib / yang.c
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 "lib_errors.h"
24 #include "yang.h"
25 #include "yang_translator.h"
26 #include "northbound.h"
27
28 DEFINE_MTYPE_STATIC(LIB, YANG_MODULE, "YANG module");
29 DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure");
30
31 /* libyang container. */
32 struct ly_ctx *ly_native_ctx;
33
34 static struct yang_module_embed *embeds, **embedupd = &embeds;
35
36 void yang_module_embed(struct yang_module_embed *embed)
37 {
38 embed->next = NULL;
39 *embedupd = embed;
40 embedupd = &embed->next;
41 }
42
43 static 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 *))
49 {
50 struct yang_module_embed *e;
51
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
57 for (e = embeds; e; e = e->next) {
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 }
71
72 *format = e->format;
73 *module_data = e->data;
74 return LY_SUCCESS;
75 }
76
77 /* We get here for indirect modules like ietf-inet-types */
78 zlog_debug(
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 : "*");
82
83 return LY_ENOTFOUND;
84 }
85
86 /* clang-format off */
87 static const char *const frr_native_modules[] = {
88 "frr-interface",
89 "frr-vrf",
90 "frr-routing",
91 "frr-route-map",
92 "frr-nexthop",
93 "frr-ripd",
94 "frr-ripngd",
95 "frr-isisd",
96 "frr-vrrpd",
97 "frr-zebra",
98 "frr-pathd",
99 };
100 /* clang-format on */
101
102 /* Generate the yang_modules tree. */
103 static 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 }
108 RB_GENERATE(yang_modules, yang_module, entry, yang_module_compare)
109
110 struct yang_modules yang_modules = RB_INITIALIZER(&yang_modules);
111
112 struct yang_module *yang_module_load(const char *module_name)
113 {
114 struct yang_module *module;
115 const struct lys_module *module_info;
116
117 module_info =
118 ly_ctx_load_module(ly_native_ctx, module_name, NULL, NULL);
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
140 void 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
146 struct 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
154 int yang_snodes_iterate_subtree(const struct lysc_node *snode,
155 const struct lys_module *module,
156 yang_iterate_cb cb, uint16_t flags, void *arg)
157 {
158 const struct lysc_node *child;
159 int ret = YANG_ITER_CONTINUE;
160
161 if (module && snode->module != module)
162 goto next;
163
164 switch (snode->nodetype) {
165 case LYS_CONTAINER:
166 if (CHECK_FLAG(flags, YANG_ITER_FILTER_NPCONTAINERS)) {
167 if (!CHECK_FLAG(snode->flags, LYS_PRESENCE))
168 goto next;
169 }
170 break;
171 case LYS_LEAF:
172 if (CHECK_FLAG(flags, YANG_ITER_FILTER_LIST_KEYS)) {
173 /* Ignore list keys. */
174 if (lysc_is_key(snode))
175 goto next;
176 }
177 break;
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:
184 assert(snode->nodetype != LYS_AUGMENT
185 && snode->nodetype != LYS_GROUPING
186 && snode->nodetype != LYS_USES);
187 break;
188 }
189
190 ret = (*cb)(snode, arg);
191 if (ret == YANG_ITER_STOP)
192 return ret;
193
194 next:
195 /*
196 * YANG leafs and leaf-lists can't have child nodes.
197 */
198 if (CHECK_FLAG(snode->nodetype, LYS_LEAF | LYS_LEAFLIST))
199 return YANG_ITER_CONTINUE;
200
201 LY_LIST_FOR (lysc_node_child(snode), child) {
202 ret = yang_snodes_iterate_subtree(child, module, cb, flags,
203 arg);
204 if (ret == YANG_ITER_STOP)
205 return ret;
206 }
207 return ret;
208 }
209
210 int yang_snodes_iterate(const struct lys_module *module, yang_iterate_cb cb,
211 uint16_t flags, void *arg)
212 {
213 const struct lys_module *module_iter;
214 uint32_t idx = 0;
215 int ret = YANG_ITER_CONTINUE;
216
217 idx = ly_ctx_internal_modules_count(ly_native_ctx);
218 while ((module_iter = ly_ctx_get_module_iter(ly_native_ctx, &idx))) {
219 struct lysc_node *snode;
220
221 if (!module_iter->implemented)
222 continue;
223
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) {
237 ret = yang_snodes_iterate_subtree(snode, module, cb,
238 flags, arg);
239 if (ret == YANG_ITER_STOP)
240 return ret;
241 }
242 }
243
244 return ret;
245 }
246
247 void yang_snode_get_path(const struct lysc_node *snode,
248 enum yang_path_type type, char *xpath,
249 size_t xpath_len)
250 {
251 switch (type) {
252 case YANG_PATH_SCHEMA:
253 (void)lysc_path(snode, LYSC_PATH_LOG, xpath, xpath_len);
254 break;
255 case YANG_PATH_DATA:
256 (void)lysc_path(snode, LYSC_PATH_DATA, xpath, xpath_len);
257 break;
258 default:
259 flog_err(EC_LIB_DEVELOPMENT, "%s: unknown yang path type: %u",
260 __func__, type);
261 exit(1);
262 }
263 }
264
265 struct lysc_node *yang_snode_real_parent(const struct lysc_node *snode)
266 {
267 struct lysc_node *parent = snode->parent;
268
269 while (parent) {
270 switch (parent->nodetype) {
271 case LYS_CONTAINER:
272 if (CHECK_FLAG(parent->flags, LYS_PRESENCE))
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
286 struct lysc_node *yang_snode_parent_list(const struct lysc_node *snode)
287 {
288 struct lysc_node *parent = snode->parent;
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
303 bool yang_snode_is_typeless_data(const struct lysc_node *snode)
304 {
305 const struct lysc_node_leaf *sleaf;
306
307 switch (snode->nodetype) {
308 case LYS_LEAF:
309 sleaf = (struct lysc_node_leaf *)snode;
310 if (sleaf->type->basetype == LY_TYPE_EMPTY)
311 return true;
312 return false;
313 case LYS_LEAFLIST:
314 return false;
315 default:
316 return true;
317 }
318 }
319
320 const char *yang_snode_get_default(const struct lysc_node *snode)
321 {
322 const struct lysc_node_leaf *sleaf;
323
324 switch (snode->nodetype) {
325 case LYS_LEAF:
326 sleaf = (const struct lysc_node_leaf *)snode;
327 return sleaf->dflt ? lyd_value_get_canonical(sleaf->module->ctx,
328 sleaf->dflt)
329 : NULL;
330 case LYS_LEAFLIST:
331 /* TODO: check leaf-list default values */
332 return NULL;
333 default:
334 return NULL;
335 }
336 }
337
338 const struct lysc_type *yang_snode_get_type(const struct lysc_node *snode)
339 {
340 struct lysc_node_leaf *sleaf = (struct lysc_node_leaf *)snode;
341 struct lysc_type *type;
342
343 if (!CHECK_FLAG(sleaf->nodetype, LYS_LEAF | LYS_LEAFLIST))
344 return NULL;
345
346 type = sleaf->type;
347 while (type->basetype == LY_TYPE_LEAFREF)
348 type = ((struct lysc_type_leafref *)type)->realtype;
349
350 return type;
351 }
352
353 unsigned 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
368 void yang_dnode_get_path(const struct lyd_node *dnode, char *xpath,
369 size_t xpath_len)
370 {
371 lyd_path(dnode, LYD_PATH_STD, xpath, xpath_len);
372 }
373
374 const 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
397 struct lyd_node *yang_dnode_get(const struct lyd_node *dnode, const char *xpath)
398 {
399 struct ly_set *set = NULL;
400 struct lyd_node *dnode_ret = NULL;
401
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;
408
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)
414 goto exit;
415
416 if (set->count > 1) {
417 flog_warn(EC_LIB_YANG_DNODE_NOT_FOUND,
418 "%s: found %u elements (expected 0 or 1) [xpath %s]",
419 __func__, set->count, xpath);
420 goto exit;
421 }
422
423 dnode_ret = set->dnodes[0];
424
425 exit:
426 ly_set_free(set, NULL);
427
428 return dnode_ret;
429 }
430
431 struct lyd_node *yang_dnode_getf(const struct lyd_node *dnode,
432 const char *xpath_fmt, ...)
433 {
434 va_list ap;
435 char xpath[XPATH_MAXLEN];
436
437 va_start(ap, xpath_fmt);
438 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
439 va_end(ap);
440
441 return yang_dnode_get(dnode, xpath);
442 }
443
444 bool yang_dnode_exists(const struct lyd_node *dnode, const char *xpath)
445 {
446 struct ly_set *set = NULL;
447 bool exists = false;
448
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
458 bool 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);
469 }
470
471 void 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
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++) {
488 int ret;
489
490 ret = (*cb)(set->dnodes[i], arg);
491 if (ret == YANG_ITER_STOP)
492 break;
493 }
494
495 ly_set_free(set, NULL);
496 }
497
498 bool yang_dnode_is_default(const struct lyd_node *dnode, const char *xpath)
499 {
500 const struct lysc_node *snode;
501 struct lysc_node_leaf *sleaf;
502
503 if (xpath)
504 dnode = yang_dnode_get(dnode, xpath);
505
506 assert(dnode);
507 snode = dnode->schema;
508 switch (snode->nodetype) {
509 case LYS_LEAF:
510 sleaf = (struct lysc_node_leaf *)snode;
511 if (sleaf->type->basetype == LY_TYPE_EMPTY)
512 return false;
513 return lyd_is_default(dnode);
514 case LYS_LEAFLIST:
515 /* TODO: check leaf-list default values */
516 return false;
517 case LYS_CONTAINER:
518 if (CHECK_FLAG(snode->flags, LYS_PRESENCE))
519 return false;
520 return true;
521 default:
522 return false;
523 }
524 }
525
526 bool yang_dnode_is_defaultf(const struct lyd_node *dnode, const char *xpath_fmt,
527 ...)
528 {
529 if (!xpath_fmt)
530 return yang_dnode_is_default(dnode, NULL);
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
543 bool yang_dnode_is_default_recursive(const struct lyd_node *dnode)
544 {
545 struct lyd_node *root, *dnode_iter;
546
547 if (!yang_dnode_is_default(dnode, NULL))
548 return false;
549
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) {
555 if (!yang_dnode_is_default(dnode_iter, NULL))
556 return false;
557
558 LYD_TREE_DFS_END(root, dnode_iter);
559 }
560 }
561
562 return true;
563 }
564
565 void yang_dnode_change_leaf(struct lyd_node *dnode, const char *value)
566 {
567 assert(dnode->schema->nodetype == LYS_LEAF);
568 lyd_change_term(dnode, value);
569 }
570
571 struct lyd_node *yang_dnode_new(struct ly_ctx *ly_ctx, bool config_only)
572 {
573 struct lyd_node *dnode = NULL;
574 int options = config_only ? LYD_VALIDATE_NO_STATE : 0;
575
576 if (lyd_validate_all(&dnode, ly_ctx, options, NULL) != 0) {
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
585 struct lyd_node *yang_dnode_dup(const struct lyd_node *dnode)
586 {
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;
592 }
593
594 void yang_dnode_free(struct lyd_node *dnode)
595 {
596 while (dnode->parent)
597 dnode = lyd_parent(dnode);
598 lyd_free_all(dnode);
599 }
600
601 struct yang_data *yang_data_new(const char *xpath, const char *value)
602 {
603 struct yang_data *data;
604
605 data = XCALLOC(MTYPE_YANG_DATA, sizeof(*data));
606 strlcpy(data->xpath, xpath, sizeof(data->xpath));
607 if (value)
608 data->value = strdup(value);
609
610 return data;
611 }
612
613 void yang_data_free(struct yang_data *data)
614 {
615 if (data->value)
616 free(data->value);
617 XFREE(MTYPE_YANG_DATA, data);
618 }
619
620 struct 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
630 struct 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
649 /* Make libyang log its errors using FRR logging infrastructure. */
650 static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
651 {
652 int priority = LOG_ERR;
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:
662 case LY_LLDBG:
663 priority = LOG_DEBUG;
664 break;
665 }
666
667 if (path)
668 zlog(priority, "libyang: %s (%s)", msg, path);
669 else
670 zlog(priority, "libyang: %s", msg);
671 }
672
673 const 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
701 void yang_debugging_set(bool enable)
702 {
703 if (enable) {
704 ly_log_level(LY_LLDBG);
705 ly_log_dbg_groups(0xFF);
706 } else {
707 ly_log_level(LY_LLERR);
708 ly_log_dbg_groups(0);
709 }
710 }
711
712 struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile)
713 {
714 struct ly_ctx *ctx = NULL;
715 const char *yang_models_path = YANG_MODELS_PATH;
716 LY_ERR err;
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
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)
734 return NULL;
735
736 if (embedded_modules)
737 ly_ctx_set_module_imp_clb(ctx, yang_module_imp_clb, NULL);
738
739 return ctx;
740 }
741
742 void yang_init(bool embedded_modules, bool defer_compile)
743 {
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. */
749 ly_native_ctx = yang_ctx_new_setup(embedded_modules, defer_compile);
750 if (!ly_native_ctx) {
751 flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
752 exit(1);
753 }
754
755 yang_translator_init();
756 }
757
758 void 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
769 void 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
788 ly_ctx_destroy(ly_native_ctx);
789 }
790
791 const 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
807 orig_dnode = lyd_parent(orig_dnode);
808 }
809
810 return NULL;
811 }
812
813 bool yang_is_last_list_dnode(const struct lyd_node *dnode)
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
825 bool yang_is_last_level_dnode(const struct lyd_node *dnode)
826 {
827 const struct lyd_node *parent;
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);
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. */
837 key_leaf = dnode->prev;
838 for (keys_size = 1; keys_size < snode_num_keys; keys_size++)
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
852 const struct lyd_node *
853 yang_get_subtree_with_no_sibling(const struct lyd_node *dnode)
854 {
855 bool parent = true;
856 const struct lyd_node *node;
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:
865 if (!CHECK_FLAG(node->schema->flags, LYS_PRESENCE)) {
866 if (node->parent
867 && (node->parent->schema->module
868 == dnode->schema->module))
869 node = lyd_parent(node);
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))
881 node = lyd_parent(node);
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
895 uint32_t yang_get_list_pos(const struct lyd_node *node)
896 {
897 return lyd_list_pos(node);
898 }
899
900 uint32_t yang_get_list_elements_count(const struct lyd_node *node)
901 {
902 unsigned int count;
903 const struct lysc_node *schema;
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 }