]> git.proxmox.com Git - mirror_frr.git/blame - lib/yang.c
lib, tools: use CHECK_FLAG/SET_FLAG more often in the northbound code
[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"
23#include "log_int.h"
24#include "lib_errors.h"
25#include "yang.h"
26#include "yang_translator.h"
27#include "northbound.h"
28
29DEFINE_MTYPE(LIB, YANG_MODULE, "YANG module")
30DEFINE_MTYPE(LIB, YANG_DATA, "YANG data structure")
31
32/* libyang container. */
33struct ly_ctx *ly_native_ctx;
34
3a11599c
DL
35static struct yang_module_embed *embeds, **embedupd = &embeds;
36
37void yang_module_embed(struct yang_module_embed *embed)
38{
39 embed->next = NULL;
40 *embedupd = embed;
41 embedupd = &embed->next;
42}
43
44static const char *yang_module_imp_clb(const char *mod_name,
45 const char *mod_rev,
46 const char *submod_name,
47 const char *submod_rev,
48 void *user_data,
49 LYS_INFORMAT *format,
50 void (**free_module_data)
51 (void *, void*))
52{
53 struct yang_module_embed *e;
54
55 if (submod_name || submod_rev)
56 return NULL;
57
58 for (e = embeds; e; e = e->next) {
59 if (strcmp(e->mod_name, mod_name))
60 continue;
61 if (mod_rev && strcmp(e->mod_rev, mod_rev))
62 continue;
63
64 *format = e->format;
65 return e->data;
66 }
67
68 flog_warn(EC_LIB_YANG_MODULE_LOAD,
69 "YANG model \"%s@%s\" not embedded, trying external file",
70 mod_name, mod_rev ? mod_rev : "*");
71 return NULL;
72}
73
1c2facd1
RW
74/* Generate the yang_modules tree. */
75static inline int yang_module_compare(const struct yang_module *a,
76 const struct yang_module *b)
77{
78 return strcmp(a->name, b->name);
79}
80RB_GENERATE(yang_modules, yang_module, entry, yang_module_compare)
81
82struct yang_modules yang_modules = RB_INITIALIZER(&yang_modules);
83
84struct yang_module *yang_module_load(const char *module_name)
85{
86 struct yang_module *module;
87 const struct lys_module *module_info;
88
89 module_info = ly_ctx_load_module(ly_native_ctx, module_name, NULL);
90 if (!module_info) {
91 flog_err(EC_LIB_YANG_MODULE_LOAD,
92 "%s: failed to load data model: %s", __func__,
93 module_name);
94 exit(1);
95 }
96
97 module = XCALLOC(MTYPE_YANG_MODULE, sizeof(*module));
98 module->name = module_name;
99 module->info = module_info;
100
101 if (RB_INSERT(yang_modules, &yang_modules, module) != NULL) {
102 flog_err(EC_LIB_YANG_MODULE_LOADED_ALREADY,
103 "%s: YANG module is loaded already: %s", __func__,
104 module_name);
105 exit(1);
106 }
107
108 return module;
109}
110
111struct yang_module *yang_module_find(const char *module_name)
112{
113 struct yang_module s;
114
115 s.name = module_name;
116 return RB_FIND(yang_modules, &yang_modules, &s);
117}
118
119/*
120 * Helper function for yang_module_snodes_iterate() and
121 * yang_all_snodes_iterate(). This is a recursive function.
122 */
123static void yang_snodes_iterate(const struct lys_node *snode,
124 void (*func)(const struct lys_node *, void *,
125 void *),
126 uint16_t flags, void *arg1, void *arg2)
127{
128 struct lys_node *child;
129
130 if (CHECK_FLAG(flags, YANG_ITER_FILTER_IMPLICIT)) {
131 switch (snode->nodetype) {
132 case LYS_CASE:
133 case LYS_INPUT:
134 case LYS_OUTPUT:
db452508 135 if (CHECK_FLAG(snode->flags, LYS_IMPLICIT))
1c2facd1
RW
136 goto next;
137 break;
138 default:
139 break;
140 }
141 }
142
143 switch (snode->nodetype) {
144 case LYS_CONTAINER:
145 if (CHECK_FLAG(flags, YANG_ITER_FILTER_NPCONTAINERS)) {
146 struct lys_node_container *scontainer;
147
148 scontainer = (struct lys_node_container *)snode;
149 if (!scontainer->presence)
150 goto next;
151 }
152 break;
153 case LYS_LEAF:
154 if (CHECK_FLAG(flags, YANG_ITER_FILTER_LIST_KEYS)) {
155 struct lys_node_leaf *sleaf;
156
157 /* Ignore list keys. */
158 sleaf = (struct lys_node_leaf *)snode;
159 if (lys_is_key(sleaf, NULL))
160 goto next;
161 }
162 break;
163 case LYS_GROUPING:
164 /* Return since we're not interested in the grouping subtree. */
165 return;
166 case LYS_USES:
167 case LYS_AUGMENT:
168 /* Always ignore nodes of these types. */
169 goto next;
170 case LYS_INPUT:
171 case LYS_OUTPUT:
172 if (CHECK_FLAG(flags, YANG_ITER_FILTER_INPUT_OUTPUT))
173 goto next;
174 break;
175 default:
176 break;
177 }
178
179 (*func)(snode, arg1, arg2);
180
181next:
182 /*
183 * YANG leafs and leaf-lists can't have child nodes, and trying to
184 * access snode->child is undefined behavior.
185 */
db452508 186 if (CHECK_FLAG(snode->nodetype, LYS_LEAF | LYS_LEAFLIST))
1c2facd1
RW
187 return;
188
189 LY_TREE_FOR (snode->child, child) {
190 if (child->parent != snode)
191 continue;
192 yang_snodes_iterate(child, func, flags, arg1, arg2);
193 }
194}
195
196void yang_module_snodes_iterate(const struct lys_module *module,
197 void (*func)(const struct lys_node *, void *,
198 void *),
199 uint16_t flags, void *arg1, void *arg2)
200{
201 struct lys_node *snode;
202
203 LY_TREE_FOR (module->data, snode) {
204 yang_snodes_iterate(snode, func, flags, arg1, arg2);
205 }
206
207 for (uint8_t i = 0; i < module->augment_size; i++) {
208 yang_snodes_iterate(
209 (const struct lys_node *)&module->augment[i], func,
210 flags, arg1, arg2);
211 }
212}
213
214void yang_all_snodes_iterate(void (*func)(const struct lys_node *, void *,
215 void *),
216 uint16_t flags, void *arg1, void *arg2)
217{
218 struct yang_module *module;
219
220 RB_FOREACH (module, yang_modules, &yang_modules)
221 yang_module_snodes_iterate(module->info, func, flags, arg1,
222 arg2);
223}
224
225void yang_snode_get_path(const struct lys_node *snode, enum yang_path_type type,
226 char *xpath, size_t xpath_len)
227{
228 char *xpath_ptr;
229
230 switch (type) {
231 case YANG_PATH_SCHEMA:
232 xpath_ptr = lys_path(snode, 0);
233 break;
234 case YANG_PATH_DATA:
235 xpath_ptr = lys_data_path(snode);
236 break;
237 default:
238 flog_err(EC_LIB_DEVELOPMENT, "%s: unknown yang path type: %u",
239 __func__, type);
240 exit(1);
241 }
242 strlcpy(xpath, xpath_ptr, xpath_len);
243 free(xpath_ptr);
244}
245
246struct lys_node *yang_snode_real_parent(const struct lys_node *snode)
247{
248 struct lys_node *parent = snode->parent;
249
250 while (parent) {
251 struct lys_node_container *scontainer;
252
253 switch (parent->nodetype) {
254 case LYS_CONTAINER:
255 scontainer = (struct lys_node_container *)parent;
256 if (scontainer->presence)
257 return parent;
258 break;
259 case LYS_LIST:
260 return parent;
261 default:
262 break;
263 }
264 parent = parent->parent;
265 }
266
267 return NULL;
268}
269
270struct lys_node *yang_snode_parent_list(const struct lys_node *snode)
271{
272 struct lys_node *parent = snode->parent;
273
274 while (parent) {
275 switch (parent->nodetype) {
276 case LYS_LIST:
277 return parent;
278 default:
279 break;
280 }
281 parent = parent->parent;
282 }
283
284 return NULL;
285}
286
287bool yang_snode_is_typeless_data(const struct lys_node *snode)
288{
289 struct lys_node_leaf *sleaf;
290
291 switch (snode->nodetype) {
292 case LYS_LEAF:
293 sleaf = (struct lys_node_leaf *)snode;
294 if (sleaf->type.base == LY_TYPE_EMPTY)
295 return true;
296 return false;
297 case LYS_LEAFLIST:
298 return false;
299 default:
300 return true;
301 }
302}
303
304const char *yang_snode_get_default(const struct lys_node *snode)
305{
306 struct lys_node_leaf *sleaf;
307
308 switch (snode->nodetype) {
309 case LYS_LEAF:
310 sleaf = (struct lys_node_leaf *)snode;
311
312 /* NOTE: this might be null. */
313 return sleaf->dflt;
314 case LYS_LEAFLIST:
315 /* TODO: check leaf-list default values */
316 return NULL;
317 default:
318 return NULL;
319 }
320}
321
322const struct lys_type *yang_snode_get_type(const struct lys_node *snode)
323{
324 struct lys_node_leaf *sleaf = (struct lys_node_leaf *)snode;
325 struct lys_type *type;
326
db452508 327 if (!CHECK_FLAG(sleaf->nodetype, LYS_LEAF | LYS_LEAFLIST))
1c2facd1
RW
328 return NULL;
329
330 type = &sleaf->type;
331 while (type->base == LY_TYPE_LEAFREF)
332 type = &type->info.lref.target->type;
333
334 return type;
335}
336
337void yang_dnode_get_path(const struct lyd_node *dnode, char *xpath,
338 size_t xpath_len)
339{
340 char *xpath_ptr;
341
342 xpath_ptr = lyd_path(dnode);
343 strlcpy(xpath, xpath_ptr, xpath_len);
344 free(xpath_ptr);
345}
346
347struct lyd_node *yang_dnode_get(const struct lyd_node *dnode,
348 const char *xpath_fmt, ...)
349{
350 va_list ap;
351 char xpath[XPATH_MAXLEN];
352 struct ly_set *set;
353 struct lyd_node *dnode_ret = NULL;
354
355 va_start(ap, xpath_fmt);
356 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
357 va_end(ap);
358
359 set = lyd_find_path(dnode, xpath);
360 assert(set);
361 if (set->number == 0)
362 goto exit;
363
364 if (set->number > 1) {
365 flog_warn(EC_LIB_YANG_DNODE_NOT_FOUND,
366 "%s: found %u elements (expected 0 or 1) [xpath %s]",
367 __func__, set->number, xpath);
368 goto exit;
369 }
370
371 dnode_ret = set->set.d[0];
372
373exit:
374 ly_set_free(set);
375
376 return dnode_ret;
377}
378
379bool yang_dnode_exists(const struct lyd_node *dnode, const char *xpath_fmt, ...)
380{
381 va_list ap;
382 char xpath[XPATH_MAXLEN];
383 struct ly_set *set;
384 bool found;
385
386 va_start(ap, xpath_fmt);
387 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
388 va_end(ap);
389
390 set = lyd_find_path(dnode, xpath);
391 assert(set);
392 found = (set->number > 0);
393 ly_set_free(set);
394
395 return found;
396}
397
398bool yang_dnode_is_default(const struct lyd_node *dnode, const char *xpath_fmt,
399 ...)
400{
401 struct lys_node *snode;
402 struct lys_node_leaf *sleaf;
403 struct lys_node_container *scontainer;
404
405 if (xpath_fmt) {
406 va_list ap;
407 char xpath[XPATH_MAXLEN];
408
409 va_start(ap, xpath_fmt);
410 vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
411 va_end(ap);
412
413 dnode = yang_dnode_get(dnode, xpath);
414 }
415
416 assert(dnode);
417 snode = dnode->schema;
418 switch (snode->nodetype) {
419 case LYS_LEAF:
420 sleaf = (struct lys_node_leaf *)snode;
421 if (sleaf->type.base == LY_TYPE_EMPTY)
422 return false;
423 return lyd_wd_default((struct lyd_node_leaf_list *)dnode);
424 case LYS_LEAFLIST:
425 /* TODO: check leaf-list default values */
426 return false;
427 case LYS_CONTAINER:
428 scontainer = (struct lys_node_container *)snode;
429 if (scontainer->presence)
430 return false;
431 return true;
432 default:
433 return false;
434 }
435}
436
437bool yang_dnode_is_default_recursive(const struct lyd_node *dnode)
438{
439 struct lys_node *snode;
440 struct lyd_node *root, *next, *dnode_iter;
441
442 snode = dnode->schema;
db452508 443 if (CHECK_FLAG(snode->nodetype, LYS_LEAF | LYS_LEAFLIST))
1c2facd1
RW
444 return yang_dnode_is_default(dnode, NULL);
445
446 if (!yang_dnode_is_default(dnode, NULL))
447 return false;
448
449 LY_TREE_FOR (dnode->child, root) {
450 LY_TREE_DFS_BEGIN (root, next, dnode_iter) {
451 if (!yang_dnode_is_default(dnode_iter, NULL))
452 return false;
453
454 LY_TREE_DFS_END(root, next, dnode_iter);
455 }
456 }
457
458 return true;
459}
460
461void yang_dnode_change_leaf(struct lyd_node *dnode, const char *value)
462{
463 assert(dnode->schema->nodetype == LYS_LEAF);
464 lyd_change_leaf((struct lyd_node_leaf_list *)dnode, value);
465}
466
467void yang_dnode_set_entry(const struct lyd_node *dnode, void *entry)
468{
db452508 469 assert(CHECK_FLAG(dnode->schema->nodetype, LYS_LIST | LYS_CONTAINER));
1c2facd1
RW
470 lyd_set_private(dnode, entry);
471}
472
473void *yang_dnode_get_entry(const struct lyd_node *dnode)
474{
475 const struct lyd_node *orig_dnode = dnode;
476 char xpath[XPATH_MAXLEN];
477
478 while (dnode) {
479 switch (dnode->schema->nodetype) {
480 case LYS_CONTAINER:
481 case LYS_LIST:
482 if (dnode->priv)
483 return dnode->priv;
484 break;
485 default:
486 break;
487 }
488
489 dnode = dnode->parent;
490 }
491
492 yang_dnode_get_path(orig_dnode, xpath, sizeof(xpath));
493 flog_err(EC_LIB_YANG_DNODE_NOT_FOUND,
494 "%s: failed to find entry [xpath %s]", __func__, xpath);
495 zlog_backtrace(LOG_ERR);
496 abort();
497}
498
5e02643a 499struct lyd_node *yang_dnode_new(struct ly_ctx *ly_ctx, bool config_only)
1c2facd1
RW
500{
501 struct lyd_node *dnode;
5e02643a
RW
502 int options;
503
504 if (config_only)
505 options = LYD_OPT_CONFIG;
506 else
507 options = LYD_OPT_DATA | LYD_OPT_DATA_NO_YANGLIB;
1c2facd1
RW
508
509 dnode = NULL;
5e02643a 510 if (lyd_validate(&dnode, options, ly_ctx) != 0) {
1c2facd1
RW
511 /* Should never happen. */
512 flog_err(EC_LIB_LIBYANG, "%s: lyd_validate() failed", __func__);
513 exit(1);
514 }
515
516 return dnode;
517}
518
519struct lyd_node *yang_dnode_dup(const struct lyd_node *dnode)
520{
521 return lyd_dup_withsiblings(dnode, 1);
522}
523
524void yang_dnode_free(struct lyd_node *dnode)
525{
526 lyd_free_withsiblings(dnode);
527}
528
529struct yang_data *yang_data_new(const char *xpath, const char *value)
530{
1c2facd1
RW
531 struct yang_data *data;
532
1c2facd1
RW
533 data = XCALLOC(MTYPE_YANG_DATA, sizeof(*data));
534 strlcpy(data->xpath, xpath, sizeof(data->xpath));
1c2facd1
RW
535 if (value)
536 data->value = strdup(value);
537
538 return data;
539}
540
541void yang_data_free(struct yang_data *data)
542{
543 if (data->value)
544 free(data->value);
545 XFREE(MTYPE_YANG_DATA, data);
546}
547
548struct list *yang_data_list_new(void)
549{
550 struct list *list;
551
552 list = list_new();
553 list->del = (void (*)(void *))yang_data_free;
554
555 return list;
556}
557
558static void *ly_dup_cb(const void *priv)
559{
560 /* Make a shallow copy of the priv pointer. */
561 return (void *)priv;
562}
563
564/* Make libyang log its errors using FRR logging infrastructure. */
565static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
566{
567 int priority;
568
569 switch (level) {
570 case LY_LLERR:
571 priority = LOG_ERR;
572 break;
573 case LY_LLWRN:
574 priority = LOG_WARNING;
575 break;
576 case LY_LLVRB:
577 priority = LOG_DEBUG;
578 break;
579 default:
580 return;
581 }
582
583 if (path)
584 zlog(priority, "libyang: %s (%s)", msg, path);
585 else
586 zlog(priority, "libyang: %s", msg);
587}
588
589void yang_init(void)
590{
591 static char ly_plugin_dir[PATH_MAX];
592 const char *const *ly_loaded_plugins;
593 const char *ly_plugin;
594 bool found_ly_frr_types = false;
595
596 /* Tell libyang where to find its plugins. */
597 snprintf(ly_plugin_dir, sizeof(ly_plugin_dir), "%s=%s",
598 "LIBYANG_USER_TYPES_PLUGINS_DIR", LIBYANG_PLUGINS_PATH);
599 putenv(ly_plugin_dir);
600
601 /* Initialize libyang global parameters that affect all containers. */
602 ly_set_log_clb(ly_log_cb, 1);
603 ly_log_options(LY_LOLOG | LY_LOSTORE);
604
605 /* Initialize libyang container for native models. */
606 ly_native_ctx = ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIR_CWD);
607 if (!ly_native_ctx) {
608 flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
609 exit(1);
610 }
3a11599c 611 ly_ctx_set_module_imp_clb(ly_native_ctx, yang_module_imp_clb, NULL);
1c2facd1
RW
612 ly_ctx_set_searchdir(ly_native_ctx, YANG_MODELS_PATH);
613 ly_ctx_set_priv_dup_clb(ly_native_ctx, ly_dup_cb);
614
615 /* Detect if the required libyang plugin(s) were loaded successfully. */
616 ly_loaded_plugins = ly_get_loaded_plugins();
617 for (size_t i = 0; (ly_plugin = ly_loaded_plugins[i]); i++) {
618 if (strmatch(ly_plugin, "frr_user_types")) {
619 found_ly_frr_types = true;
620 break;
621 }
622 }
623 if (!found_ly_frr_types) {
624 flog_err(EC_LIB_LIBYANG_PLUGIN_LOAD,
625 "%s: failed to load frr_user_types.so", __func__);
626 exit(1);
627 }
628
629 yang_translator_init();
630}
631
632void yang_terminate(void)
633{
634 struct yang_module *module;
635
636 yang_translator_terminate();
637
638 while (!RB_EMPTY(yang_modules, &yang_modules)) {
639 module = RB_ROOT(yang_modules, &yang_modules);
640
641 /*
642 * We shouldn't call ly_ctx_remove_module() here because this
643 * function also removes other modules that depend on it.
644 *
645 * ly_ctx_destroy() will release all memory for us.
646 */
647 RB_REMOVE(yang_modules, &yang_modules, module);
648 XFREE(MTYPE_YANG_MODULE, module);
649 }
650
651 ly_ctx_destroy(ly_native_ctx, NULL);
652}