]> git.proxmox.com Git - mirror_frr.git/blame - lib/yang.c
lib: don't fetch schema information when creating yang_data structures
[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:
135 if (snode->flags & LYS_IMPLICIT)
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 */
186 if (snode->nodetype & (LYS_LEAF | LYS_LEAFLIST))
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
327 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)))
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;
443 if (snode->nodetype & (LYS_LEAF | LYS_LEAFLIST))
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{
469 assert(dnode->schema->nodetype & (LYS_LIST | LYS_CONTAINER));
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
499struct lyd_node *yang_dnode_new(struct ly_ctx *ly_ctx)
500{
501 struct lyd_node *dnode;
502
503 dnode = NULL;
504 if (lyd_validate(&dnode, LYD_OPT_CONFIG, ly_ctx) != 0) {
505 /* Should never happen. */
506 flog_err(EC_LIB_LIBYANG, "%s: lyd_validate() failed", __func__);
507 exit(1);
508 }
509
510 return dnode;
511}
512
513struct lyd_node *yang_dnode_dup(const struct lyd_node *dnode)
514{
515 return lyd_dup_withsiblings(dnode, 1);
516}
517
518void yang_dnode_free(struct lyd_node *dnode)
519{
520 lyd_free_withsiblings(dnode);
521}
522
523struct yang_data *yang_data_new(const char *xpath, const char *value)
524{
1c2facd1
RW
525 struct yang_data *data;
526
1c2facd1
RW
527 data = XCALLOC(MTYPE_YANG_DATA, sizeof(*data));
528 strlcpy(data->xpath, xpath, sizeof(data->xpath));
1c2facd1
RW
529 if (value)
530 data->value = strdup(value);
531
532 return data;
533}
534
535void yang_data_free(struct yang_data *data)
536{
537 if (data->value)
538 free(data->value);
539 XFREE(MTYPE_YANG_DATA, data);
540}
541
542struct list *yang_data_list_new(void)
543{
544 struct list *list;
545
546 list = list_new();
547 list->del = (void (*)(void *))yang_data_free;
548
549 return list;
550}
551
552static void *ly_dup_cb(const void *priv)
553{
554 /* Make a shallow copy of the priv pointer. */
555 return (void *)priv;
556}
557
558/* Make libyang log its errors using FRR logging infrastructure. */
559static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
560{
561 int priority;
562
563 switch (level) {
564 case LY_LLERR:
565 priority = LOG_ERR;
566 break;
567 case LY_LLWRN:
568 priority = LOG_WARNING;
569 break;
570 case LY_LLVRB:
571 priority = LOG_DEBUG;
572 break;
573 default:
574 return;
575 }
576
577 if (path)
578 zlog(priority, "libyang: %s (%s)", msg, path);
579 else
580 zlog(priority, "libyang: %s", msg);
581}
582
583void yang_init(void)
584{
585 static char ly_plugin_dir[PATH_MAX];
586 const char *const *ly_loaded_plugins;
587 const char *ly_plugin;
588 bool found_ly_frr_types = false;
589
590 /* Tell libyang where to find its plugins. */
591 snprintf(ly_plugin_dir, sizeof(ly_plugin_dir), "%s=%s",
592 "LIBYANG_USER_TYPES_PLUGINS_DIR", LIBYANG_PLUGINS_PATH);
593 putenv(ly_plugin_dir);
594
595 /* Initialize libyang global parameters that affect all containers. */
596 ly_set_log_clb(ly_log_cb, 1);
597 ly_log_options(LY_LOLOG | LY_LOSTORE);
598
599 /* Initialize libyang container for native models. */
600 ly_native_ctx = ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIR_CWD);
601 if (!ly_native_ctx) {
602 flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
603 exit(1);
604 }
3a11599c 605 ly_ctx_set_module_imp_clb(ly_native_ctx, yang_module_imp_clb, NULL);
1c2facd1
RW
606 ly_ctx_set_searchdir(ly_native_ctx, YANG_MODELS_PATH);
607 ly_ctx_set_priv_dup_clb(ly_native_ctx, ly_dup_cb);
608
609 /* Detect if the required libyang plugin(s) were loaded successfully. */
610 ly_loaded_plugins = ly_get_loaded_plugins();
611 for (size_t i = 0; (ly_plugin = ly_loaded_plugins[i]); i++) {
612 if (strmatch(ly_plugin, "frr_user_types")) {
613 found_ly_frr_types = true;
614 break;
615 }
616 }
617 if (!found_ly_frr_types) {
618 flog_err(EC_LIB_LIBYANG_PLUGIN_LOAD,
619 "%s: failed to load frr_user_types.so", __func__);
620 exit(1);
621 }
622
623 yang_translator_init();
624}
625
626void yang_terminate(void)
627{
628 struct yang_module *module;
629
630 yang_translator_terminate();
631
632 while (!RB_EMPTY(yang_modules, &yang_modules)) {
633 module = RB_ROOT(yang_modules, &yang_modules);
634
635 /*
636 * We shouldn't call ly_ctx_remove_module() here because this
637 * function also removes other modules that depend on it.
638 *
639 * ly_ctx_destroy() will release all memory for us.
640 */
641 RB_REMOVE(yang_modules, &yang_modules, module);
642 XFREE(MTYPE_YANG_MODULE, module);
643 }
644
645 ly_ctx_destroy(ly_native_ctx, NULL);
646}