blob: 12c548cdd57fc23bc22fda9d419404b36988dabe [file] [log] [blame]
Michal Vaskoedb0fa52022-10-04 10:36:00 +02001/**
2 * @file structure.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief libyang extension plugin - strcture (RFC 8791)
5 *
6 * Copyright (c) 2022 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
15#include <stdint.h>
16#include <stdlib.h>
17#include <string.h>
18
Michal Vasko0b50f6b2022-10-05 15:07:55 +020019#include "compat.h"
Michal Vaskoedb0fa52022-10-04 10:36:00 +020020#include "libyang.h"
21#include "plugins_exts.h"
22
23struct lysc_ext_instance_structure {
24 struct lysc_must *musts;
25 uint16_t flags;
26 const char *dsc;
27 const char *ref;
28 struct lysp_tpdf *typedefs;
29 struct lysp_node_grp *groupings;
30 struct lysc_node *child;
31};
32
Michal Vasko0b50f6b2022-10-05 15:07:55 +020033struct lysc_ext_instance_augment_structure {
34 uint16_t flags;
35 const char *dsc;
36 const char *ref;
37};
38
Michal Vaskoedb0fa52022-10-04 10:36:00 +020039/**
40 * @brief Compile structure extension instances.
41 *
42 * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
43 */
44static LY_ERR
45structure_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext, struct lysc_ext_instance *c_ext)
46{
Michal Vasko0b50f6b2022-10-05 15:07:55 +020047 LY_ERR rc;
Michal Vaskoedb0fa52022-10-04 10:36:00 +020048 LY_ARRAY_COUNT_TYPE u;
49 struct lysc_module *mod_c;
50 const struct lysc_node *child;
Michal Vasko0b50f6b2022-10-05 15:07:55 +020051 struct lysc_ext_instance_structure *struct_data;
Michal Vaskoedb0fa52022-10-04 10:36:00 +020052 uint32_t prev_options = *lysc_ctx_get_options(cctx);
53
54 /* structure can appear only at the top level of a YANG module or submodule */
55 if ((c_ext->parent_stmt != LY_STMT_MODULE) && (c_ext->parent_stmt != LY_STMT_SUBMODULE)) {
56 lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
57 "Extension %s must not be used as a non top-level statement in \"%s\" statement.",
58 p_ext->name, ly_stmt2str(c_ext->parent_stmt));
59 return LY_EVALID;
60 }
61
62 mod_c = (struct lysc_module *)c_ext->parent;
63
64 /* check identifier namespace */
65 LY_ARRAY_FOR(mod_c->exts, u) {
66 if ((&mod_c->exts[u] != c_ext) && (mod_c->exts[u].def == c_ext->def) && !strcmp(mod_c->exts[u].argument, c_ext->argument)) {
67 /* duplication of the same structure extension in a single module */
68 lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx), "Extension %s is instantiated multiple times.", p_ext->name);
69 return LY_EVALID;
70 }
71 }
72 LY_LIST_FOR(mod_c->data, child) {
73 if (!strcmp(child->name, c_ext->argument)) {
74 /* identifier collision */
75 lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx), "Extension %s collides "
76 "with a %s with the same identifier.", p_ext->name, lys_nodetype2str(child->nodetype));
77 return LY_EVALID;
78 }
79 }
80
81 /* allocate the storage */
Michal Vasko0b50f6b2022-10-05 15:07:55 +020082 struct_data = calloc(1, sizeof *struct_data);
83 if (!struct_data) {
Michal Vaskoedb0fa52022-10-04 10:36:00 +020084 goto emem;
85 }
Michal Vasko0b50f6b2022-10-05 15:07:55 +020086 c_ext->data = struct_data;
Michal Vaskoedb0fa52022-10-04 10:36:00 +020087
88 /* compile substatements */
Michal Vasko0b50f6b2022-10-05 15:07:55 +020089 LY_ARRAY_CREATE_GOTO(cctx->ctx, c_ext->substmts, 14, rc, emem);
Michal Vaskoedb0fa52022-10-04 10:36:00 +020090 LY_ARRAY_INCREMENT(c_ext->substmts);
91 c_ext->substmts[0].stmt = LY_STMT_MUST;
Michal Vasko0b50f6b2022-10-05 15:07:55 +020092 c_ext->substmts[0].storage = &struct_data->musts;
Michal Vaskoedb0fa52022-10-04 10:36:00 +020093
94 LY_ARRAY_INCREMENT(c_ext->substmts);
95 c_ext->substmts[1].stmt = LY_STMT_STATUS;
Michal Vasko0b50f6b2022-10-05 15:07:55 +020096 c_ext->substmts[1].storage = &struct_data->flags;
Michal Vaskoedb0fa52022-10-04 10:36:00 +020097
98 LY_ARRAY_INCREMENT(c_ext->substmts);
99 c_ext->substmts[2].stmt = LY_STMT_DESCRIPTION;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200100 c_ext->substmts[2].storage = &struct_data->dsc;
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200101
102 LY_ARRAY_INCREMENT(c_ext->substmts);
103 c_ext->substmts[3].stmt = LY_STMT_REFERENCE;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200104 c_ext->substmts[3].storage = &struct_data->ref;
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200105
106 LY_ARRAY_INCREMENT(c_ext->substmts);
107 c_ext->substmts[4].stmt = LY_STMT_TYPEDEF;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200108 c_ext->substmts[4].storage = &struct_data->typedefs;
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200109
110 LY_ARRAY_INCREMENT(c_ext->substmts);
111 c_ext->substmts[5].stmt = LY_STMT_GROUPING;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200112 c_ext->substmts[5].storage = &struct_data->groupings;
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200113
114 /* data-def-stmt */
115 LY_ARRAY_INCREMENT(c_ext->substmts);
116 c_ext->substmts[6].stmt = LY_STMT_CONTAINER;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200117 c_ext->substmts[6].storage = &struct_data->child;
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200118
119 LY_ARRAY_INCREMENT(c_ext->substmts);
120 c_ext->substmts[7].stmt = LY_STMT_LEAF;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200121 c_ext->substmts[7].storage = &struct_data->child;
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200122
123 LY_ARRAY_INCREMENT(c_ext->substmts);
124 c_ext->substmts[8].stmt = LY_STMT_LEAF_LIST;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200125 c_ext->substmts[8].storage = &struct_data->child;
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200126
127 LY_ARRAY_INCREMENT(c_ext->substmts);
128 c_ext->substmts[9].stmt = LY_STMT_LIST;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200129 c_ext->substmts[9].storage = &struct_data->child;
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200130
131 LY_ARRAY_INCREMENT(c_ext->substmts);
132 c_ext->substmts[10].stmt = LY_STMT_CHOICE;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200133 c_ext->substmts[10].storage = &struct_data->child;
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200134
135 LY_ARRAY_INCREMENT(c_ext->substmts);
136 c_ext->substmts[11].stmt = LY_STMT_ANYDATA;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200137 c_ext->substmts[11].storage = &struct_data->child;
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200138
139 LY_ARRAY_INCREMENT(c_ext->substmts);
140 c_ext->substmts[12].stmt = LY_STMT_ANYXML;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200141 c_ext->substmts[12].storage = &struct_data->child;
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200142
143 LY_ARRAY_INCREMENT(c_ext->substmts);
144 c_ext->substmts[13].stmt = LY_STMT_USES;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200145 c_ext->substmts[13].storage = &struct_data->child;
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200146
147 *lysc_ctx_get_options(cctx) |= LYS_COMPILE_NO_CONFIG | LYS_COMPILE_NO_DISABLED;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200148 rc = lys_compile_extension_instance(cctx, p_ext, c_ext);
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200149 *lysc_ctx_get_options(cctx) = prev_options;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200150 if (rc) {
151 return rc;
152 }
153
154 return LY_SUCCESS;
155
156emem:
157 lyplg_ext_log(c_ext, LY_LLERR, LY_EMEM, lysc_ctx_get_path(cctx), "Memory allocation failed (%s()).", __func__);
158 return LY_EMEM;
159}
160
161/**
162 * @brief Compile augment-structure extension instances.
163 *
164 * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
165 */
166static LY_ERR
167structure_aug_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext, struct lysc_ext_instance *c_ext)
168{
169 LY_ERR rc;
170 struct lysp_stmt *stmt;
171 struct lysc_node *aug_target;
172 struct lysc_ext_instance *target_ext;
173 struct lysc_ext_instance_structure *target_data;
174 struct lysc_ext_instance_augment_structure *aug_data;
175 uint32_t prev_options = *lysc_ctx_get_options(cctx), i;
176
177 /* augment-structure can appear only at the top level of a YANG module or submodule */
178 if ((c_ext->parent_stmt != LY_STMT_MODULE) && (c_ext->parent_stmt != LY_STMT_SUBMODULE)) {
179 lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
180 "Extension %s must not be used as a non top-level statement in \"%s\" statement.",
181 p_ext->name, ly_stmt2str(c_ext->parent_stmt));
182 return LY_EVALID;
183 }
184
185 /* augment-structure must define some data-def-stmt */
186 LY_LIST_FOR(p_ext->child, stmt) {
187 if (LY_STMT_IS_DATA_NODE(stmt->kw)) {
188 break;
189 }
190 }
191 if (!stmt) {
192 lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
193 "Extension %s does not define any data-def-stmt statements.", p_ext->name);
194 return LY_EVALID;
195 }
196
197 /* find the target struct ext instance */
198 if ((rc = lys_compile_extension_instance_find_augment_target(cctx, p_ext->argument, &target_ext, &aug_target))) {
199 return rc;
200 }
201
202 /* check target_ext */
203 if (strcmp(target_ext->def->name, "structure") || strcmp(target_ext->def->module->name, "ietf-yang-structure-ext")) {
204 lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
205 "Extension %s can only target extension instances of \"ietf-yang-structure-ext:structure\".", p_ext->name);
206 return LY_EVALID;
207 }
208 target_data = target_ext->data;
209
210 /* allocate the storage */
211 aug_data = calloc(1, sizeof *aug_data);
212 if (!aug_data) {
213 goto emem;
214 }
215 c_ext->data = aug_data;
216
217 /* compile substatements */
218 LY_ARRAY_CREATE_GOTO(cctx->ctx, c_ext->substmts, 12, rc, emem);
219 LY_ARRAY_INCREMENT(c_ext->substmts);
220 c_ext->substmts[0].stmt = LY_STMT_STATUS;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200221 c_ext->substmts[0].storage = &aug_data->flags;
222
223 LY_ARRAY_INCREMENT(c_ext->substmts);
224 c_ext->substmts[1].stmt = LY_STMT_DESCRIPTION;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200225 c_ext->substmts[1].storage = &aug_data->dsc;
226
227 LY_ARRAY_INCREMENT(c_ext->substmts);
228 c_ext->substmts[2].stmt = LY_STMT_REFERENCE;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200229 c_ext->substmts[2].storage = &aug_data->ref;
230
231 /* data-def-stmt */
232 LY_ARRAY_INCREMENT(c_ext->substmts);
233 c_ext->substmts[3].stmt = LY_STMT_CONTAINER;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200234 c_ext->substmts[3].storage = &target_data->child;
235
236 LY_ARRAY_INCREMENT(c_ext->substmts);
237 c_ext->substmts[4].stmt = LY_STMT_LEAF;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200238 c_ext->substmts[4].storage = &target_data->child;
239
240 LY_ARRAY_INCREMENT(c_ext->substmts);
241 c_ext->substmts[5].stmt = LY_STMT_LEAF_LIST;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200242 c_ext->substmts[5].storage = &target_data->child;
243
244 LY_ARRAY_INCREMENT(c_ext->substmts);
245 c_ext->substmts[6].stmt = LY_STMT_LIST;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200246 c_ext->substmts[6].storage = &target_data->child;
247
248 LY_ARRAY_INCREMENT(c_ext->substmts);
249 c_ext->substmts[7].stmt = LY_STMT_CHOICE;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200250 c_ext->substmts[7].storage = &target_data->child;
251
252 LY_ARRAY_INCREMENT(c_ext->substmts);
253 c_ext->substmts[8].stmt = LY_STMT_ANYDATA;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200254 c_ext->substmts[8].storage = &target_data->child;
255
256 LY_ARRAY_INCREMENT(c_ext->substmts);
257 c_ext->substmts[9].stmt = LY_STMT_ANYXML;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200258 c_ext->substmts[9].storage = &target_data->child;
259
260 LY_ARRAY_INCREMENT(c_ext->substmts);
261 c_ext->substmts[10].stmt = LY_STMT_USES;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200262 c_ext->substmts[10].storage = &target_data->child;
263
264 /* case */
265 LY_ARRAY_INCREMENT(c_ext->substmts);
266 c_ext->substmts[11].stmt = LY_STMT_CASE;
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200267 c_ext->substmts[11].storage = &target_data->child;
268
269 *lysc_ctx_get_options(cctx) |= LYS_COMPILE_NO_CONFIG | LYS_COMPILE_NO_DISABLED;
270 rc = lys_compile_extension_instance_augment(cctx, p_ext, c_ext, aug_target);
271 *lysc_ctx_get_options(cctx) = prev_options;
272 if (rc) {
273 return rc;
274 }
275
276 /* data-def-statements are now part of the target extension (do not print nor free them) */
277 for (i = 0; i < 9; ++i) {
278 LY_ARRAY_DECREMENT(c_ext->substmts);
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200279 }
280
281 return LY_SUCCESS;
282
283emem:
284 lyplg_ext_log(c_ext, LY_LLERR, LY_EMEM, lysc_ctx_get_path(cctx), "Memory allocation failed (%s()).", __func__);
285 return LY_EMEM;
286}
287
288/**
289 * @brief INFO printer
290 *
291 * Implementation of ::lyplg_ext_schema_printer_clb set as ::lyext_plugin::sprinter
292 */
293static LY_ERR
294structure_schema_printer(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag)
295{
296 lysc_print_extension_instance(ctx, ext, flag);
297 return LY_SUCCESS;
298}
299
300/**
301 * @brief Free structure extension instances' data.
302 *
303 * Implementation of ::lyplg_clb_free_clb callback set as lyext_plugin::free.
304 */
305static void
306structure_free(struct ly_ctx *ctx, struct lysc_ext_instance *ext)
307{
308 lyplg_ext_instance_substatements_free(ctx, ext->substmts);
309 free(ext->data);
310}
311
312/**
313 * @brief Plugin descriptions for the structure extension
314 *
315 * Note that external plugins are supposed to use:
316 *
317 * LYPLG_EXTENSIONS = {
318 */
319const struct lyplg_ext_record plugins_structure[] = {
320 {
321 .module = "ietf-yang-structure-ext",
322 .revision = "2020-06-17",
323 .name = "structure",
324
325 .plugin.id = "libyang 2 - structure, version 1",
326 .plugin.compile = structure_compile,
327 .plugin.sprinter = structure_schema_printer,
328 .plugin.free = structure_free,
329 .plugin.node = NULL,
330 .plugin.snode = NULL,
331 .plugin.validate = NULL
332 },
Michal Vasko0b50f6b2022-10-05 15:07:55 +0200333 {
334 .module = "ietf-yang-structure-ext",
335 .revision = "2020-06-17",
336 .name = "augment-structure",
337
338 .plugin.id = "libyang 2 - structure, version 1",
339 .plugin.compile = structure_aug_compile,
340 .plugin.sprinter = structure_schema_printer,
341 .plugin.free = structure_free,
342 .plugin.node = NULL,
343 .plugin.snode = NULL,
344 .plugin.validate = NULL
345 },
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200346 {0} /* terminating zeroed record */
347};