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