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