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