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