blob: 55a03e326b24e286cd2f3be90f7928be42768cac [file] [log] [blame]
Radek Krejci5fa32a32021-02-08 18:12:38 +01001/**
aPiecek023f83a2021-05-11 07:37:03 +02002 * @file yangdata.c
Radek Krejci5fa32a32021-02-08 18:12:38 +01003 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief libyang extension plugin - yang-data (RFC 8040)
5 *
6 * Copyright (c) 2021 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
Radek Krejci883355a2021-03-11 11:54:41 +010015#include <stdint.h>
Radek Krejci5fa32a32021-02-08 18:12:38 +010016#include <stdlib.h>
Radek Krejci883355a2021-03-11 11:54:41 +010017#include <string.h>
Radek Krejci5fa32a32021-02-08 18:12:38 +010018
Radek Krejci883355a2021-03-11 11:54:41 +010019#include "libyang.h"
Radek Krejci5fa32a32021-02-08 18:12:38 +010020#include "plugins_exts.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010021
Radek Krejci5fa32a32021-02-08 18:12:38 +010022/**
Radek Krejci5fa32a32021-02-08 18:12:38 +010023 * @brief Free yang-data extension instances' data.
24 *
Radek Krejci0b013302021-03-29 15:22:32 +020025 * Implementation of ::lyplg_clb_free_clb callback set as lyext_plugin::free.
Radek Krejci5fa32a32021-02-08 18:12:38 +010026 */
Radek Krejci3e6632f2021-03-22 22:08:21 +010027static void
Radek Krejci5fa32a32021-02-08 18:12:38 +010028yangdata_free(struct ly_ctx *ctx, struct lysc_ext_instance *ext)
29{
Radek Krejci0b013302021-03-29 15:22:32 +020030 lyplg_ext_instance_substatements_free(ctx, ext->substmts);
Radek Krejci5fa32a32021-02-08 18:12:38 +010031}
32
33/**
34 * @brief Compile yang-data extension instances.
35 *
Radek Krejci0b013302021-03-29 15:22:32 +020036 * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
Radek Krejci5fa32a32021-02-08 18:12:38 +010037 */
Radek Krejci3e6632f2021-03-22 22:08:21 +010038static LY_ERR
Radek Krejci5fa32a32021-02-08 18:12:38 +010039yangdata_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext, struct lysc_ext_instance *c_ext)
40{
41 LY_ERR ret;
42 LY_ARRAY_COUNT_TYPE u;
43 struct lysc_module *mod_c;
44 const struct lysc_node *child;
45 ly_bool valid = 1;
Radek Krejci5f9a3672021-03-05 21:35:22 +010046 uint32_t prev_options = *lysc_ctx_get_options(cctx);
Radek Krejci5fa32a32021-02-08 18:12:38 +010047
48 /* yang-data can appear only at the top level of a YANG module or submodule */
Radek Krejciab430862021-03-02 20:13:40 +010049 if ((c_ext->parent_stmt != LY_STMT_MODULE) && (c_ext->parent_stmt != LY_STMT_SUBMODULE)) {
Radek Krejci0b013302021-03-29 15:22:32 +020050 lyplg_ext_log(c_ext, LY_LLWRN, 0, lysc_ctx_get_path(cctx),
Radek Krejci5fa32a32021-02-08 18:12:38 +010051 "Extension %s is ignored since it appears as a non top-level statement in \"%s\" statement.",
Radek Krejciab430862021-03-02 20:13:40 +010052 p_ext->name, ly_stmt2str(c_ext->parent_stmt));
Radek Krejci5fa32a32021-02-08 18:12:38 +010053 return LY_ENOT;
54 }
Radek Krejci5fa32a32021-02-08 18:12:38 +010055
56 mod_c = (struct lysc_module *)c_ext->parent;
57
58 /* check for duplication */
59 LY_ARRAY_FOR(mod_c->exts, u) {
60 if ((&mod_c->exts[u] != c_ext) && (mod_c->exts[u].def == c_ext->def) && !strcmp(mod_c->exts[u].argument, c_ext->argument)) {
61 /* duplication of the same yang-data extension in a single module */
Radek Krejci0b013302021-03-29 15:22:32 +020062 lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx), "Extension %s is instantiated multiple times.", p_ext->name);
Radek Krejci5fa32a32021-02-08 18:12:38 +010063 return LY_EVALID;
64 }
65 }
66
67 /* compile annotation substatements
68 * To let the compilation accept different statements possibly leading to the container top-level node, there are 3
69 * allowed substatements pointing to a single storage. But when compiled, the substaments list is compressed just to
70 * a single item providing the schema tree. */
Radek Krejci859a15a2021-03-05 20:56:59 +010071 LY_ARRAY_CREATE_GOTO(cctx->ctx, c_ext->substmts, 3, ret, emem);
Radek Krejci5fa32a32021-02-08 18:12:38 +010072 LY_ARRAY_INCREMENT(c_ext->substmts);
73 c_ext->substmts[0].stmt = LY_STMT_CONTAINER;
74 c_ext->substmts[0].cardinality = LY_STMT_CARD_OPT;
75 c_ext->substmts[0].storage = &c_ext->data;
76
77 LY_ARRAY_INCREMENT(c_ext->substmts);
78 c_ext->substmts[1].stmt = LY_STMT_CHOICE;
79 c_ext->substmts[1].cardinality = LY_STMT_CARD_OPT;
80 c_ext->substmts[1].storage = &c_ext->data;
81
82 LY_ARRAY_INCREMENT(c_ext->substmts);
83 c_ext->substmts[2].stmt = LY_STMT_USES;
84 c_ext->substmts[2].cardinality = LY_STMT_CARD_OPT;
85 c_ext->substmts[2].storage = &c_ext->data;
86
Radek Krejci5f9a3672021-03-05 21:35:22 +010087 *lysc_ctx_get_options(cctx) |= LYS_COMPILE_NO_CONFIG | LYS_COMPILE_NO_DISABLED;
Radek Krejci5fa32a32021-02-08 18:12:38 +010088 ret = lys_compile_extension_instance(cctx, p_ext, c_ext);
Radek Krejci5f9a3672021-03-05 21:35:22 +010089 *lysc_ctx_get_options(cctx) = prev_options;
Radek Krejci5fa32a32021-02-08 18:12:38 +010090 LY_ARRAY_DECREMENT(c_ext->substmts);
91 LY_ARRAY_DECREMENT(c_ext->substmts);
Radek Krejci5f9a3672021-03-05 21:35:22 +010092 if (ret) {
93 return ret;
94 }
Radek Krejci5fa32a32021-02-08 18:12:38 +010095
96 /* check that we have really just a single container data definition in the top */
97 child = *(struct lysc_node **)c_ext->substmts[0].storage;
98 if (!child) {
99 valid = 0;
Radek Krejci0b013302021-03-29 15:22:32 +0200100 lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
Radek Krejci5fa32a32021-02-08 18:12:38 +0100101 "Extension %s is instantiated without any top level data node, but exactly one container data node is expected.",
102 p_ext->name);
103 } else if (child->next) {
104 valid = 0;
Radek Krejci0b013302021-03-29 15:22:32 +0200105 lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
Radek Krejci5fa32a32021-02-08 18:12:38 +0100106 "Extension %s is instantiated with multiple top level data nodes, but only a single container data node is allowed.",
107 p_ext->name);
108 } else if (child->nodetype == LYS_CHOICE) {
109 /* all the choice's case are expected to result to a single container node */
110 const struct lysc_node *snode = NULL;
111
112 while ((snode = lys_getnext(snode, child, mod_c, 0))) {
113 if (snode->next) {
114 valid = 0;
Radek Krejci0b013302021-03-29 15:22:32 +0200115 lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
Radek Krejci5fa32a32021-02-08 18:12:38 +0100116 "Extension %s is instantiated with multiple top level data nodes (inside a single choice's case), "
117 "but only a single container data node is allowed.", p_ext->name);
118 break;
119 } else if (snode->nodetype != LYS_CONTAINER) {
120 valid = 0;
Radek Krejci0b013302021-03-29 15:22:32 +0200121 lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
Radek Krejci5fa32a32021-02-08 18:12:38 +0100122 "Extension %s is instantiated with %s top level data node (inside a choice), "
123 "but only a single container data node is allowed.", p_ext->name, lys_nodetype2str(snode->nodetype));
124 break;
125 }
126 }
127 } else if (child->nodetype != LYS_CONTAINER) {
128 /* via uses */
129 valid = 0;
Radek Krejci0b013302021-03-29 15:22:32 +0200130 lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
Radek Krejci5fa32a32021-02-08 18:12:38 +0100131 "Extension %s is instantiated with %s top level data node, but only a single container data node is allowed.",
132 p_ext->name, lys_nodetype2str(child->nodetype));
133 }
134
135 if (!valid) {
Radek Krejci5f9a3672021-03-05 21:35:22 +0100136 yangdata_free(lysc_ctx_get_ctx(cctx), c_ext);
Radek Krejci5fa32a32021-02-08 18:12:38 +0100137 c_ext->data = c_ext->substmts = NULL;
138 return LY_EVALID;
139 }
140
141 return LY_SUCCESS;
Radek Krejci859a15a2021-03-05 20:56:59 +0100142
143emem:
Radek Krejci0b013302021-03-29 15:22:32 +0200144 lyplg_ext_log(c_ext, LY_LLERR, LY_EMEM, lysc_ctx_get_path(cctx), "Memory allocation failed (%s()).", __func__);
Radek Krejci859a15a2021-03-05 20:56:59 +0100145 return LY_EMEM;
Radek Krejci5fa32a32021-02-08 18:12:38 +0100146}
147
148/**
Radek Krejciadcf63d2021-02-09 10:21:18 +0100149 * @brief INFO printer
150 *
Radek Krejci0b013302021-03-29 15:22:32 +0200151 * Implementation of ::lyplg_ext_schema_printer_clb set as ::lyext_plugin::sprinter
Radek Krejciadcf63d2021-02-09 10:21:18 +0100152 */
Radek Krejci3e6632f2021-03-22 22:08:21 +0100153static LY_ERR
Radek Krejcif8d7f9a2021-03-10 14:32:36 +0100154yangdata_schema_printer(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag)
Radek Krejciadcf63d2021-02-09 10:21:18 +0100155{
156 lysc_print_extension_instance(ctx, ext, flag);
157 return LY_SUCCESS;
158}
159
160/**
Radek Krejci3e6632f2021-03-22 22:08:21 +0100161 * @brief Plugin descriptions for the yang-data extension
Radek Krejcia6f61e72021-03-24 21:00:19 +0100162 *
163 * Note that external plugins are supposed to use:
164 *
165 * LYPLG_EXTENSIONS = {
Radek Krejci5fa32a32021-02-08 18:12:38 +0100166 */
Radek Krejci3e6632f2021-03-22 22:08:21 +0100167const struct lyplg_ext_record plugins_yangdata[] = {
168 {
169 .module = "ietf-restconf",
170 .revision = "2017-01-26",
171 .name = "yang-data",
172
173 .plugin.id = "libyang 2 - yang-data, version 1",
174 .plugin.compile = &yangdata_compile,
Radek Krejci3e6632f2021-03-22 22:08:21 +0100175 .plugin.sprinter = &yangdata_schema_printer,
Michal Vaskoddd76592022-01-17 13:34:48 +0100176 .plugin.free = yangdata_free,
177 .plugin.parse = NULL,
178 .plugin.validate = NULL
Radek Krejci3e6632f2021-03-22 22:08:21 +0100179 },
180 {0} /* terminating zeroed record */
Radek Krejci5fa32a32021-02-08 18:12:38 +0100181};