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