blob: 32229d73767ac3ad79461f94371466336270f073 [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>
Michal Vasko193dacd2022-10-13 08:43:05 +02004 * @author Michal Vasko <mvasko@cesnet.cz>
Radek Krejci5fa32a32021-02-08 18:12:38 +01005 * @brief libyang extension plugin - yang-data (RFC 8040)
6 *
Michal Vasko193dacd2022-10-13 08:43:05 +02007 * Copyright (c) 2021 - 2022 CESNET, z.s.p.o.
Radek Krejci5fa32a32021-02-08 18:12:38 +01008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
Radek Krejci883355a2021-03-11 11:54:41 +010016#include <stdint.h>
Radek Krejci5fa32a32021-02-08 18:12:38 +010017#include <stdlib.h>
Radek Krejci883355a2021-03-11 11:54:41 +010018#include <string.h>
Radek Krejci5fa32a32021-02-08 18:12:38 +010019
Radek Krejci883355a2021-03-11 11:54:41 +010020#include "libyang.h"
Radek Krejci5fa32a32021-02-08 18:12:38 +010021#include "plugins_exts.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010022
Michal Vasko193dacd2022-10-13 08:43:05 +020023static void yangdata_cfree(const struct ly_ctx *ctx, struct lysc_ext_instance *ext);
24
Radek Krejci5fa32a32021-02-08 18:12:38 +010025/**
Michal Vasko193dacd2022-10-13 08:43:05 +020026 * @brief Parse yang-data extension instances.
Radek Krejci5fa32a32021-02-08 18:12:38 +010027 *
Michal Vasko193dacd2022-10-13 08:43:05 +020028 * Implementation of ::lyplg_ext_parse_clb callback set as lyext_plugin::parse.
Radek Krejci5fa32a32021-02-08 18:12:38 +010029 */
Michal Vasko193dacd2022-10-13 08:43:05 +020030static LY_ERR
31yangdata_parse(struct lysp_ctx *pctx, struct lysp_ext_instance *ext)
Radek Krejci5fa32a32021-02-08 18:12:38 +010032{
Michal Vasko193dacd2022-10-13 08:43:05 +020033 LY_ERR ret;
34 LY_ARRAY_COUNT_TYPE u;
35 struct lysp_module *pmod;
36
37 /* yang-data can appear only at the top level of a YANG module or submodule */
38 if ((ext->parent_stmt != LY_STMT_MODULE) && (ext->parent_stmt != LY_STMT_SUBMODULE)) {
39 lyplg_ext_parse_log(pctx, ext, LY_LLWRN, 0, "Extension %s is ignored since it appears as a non top-level statement "
40 "in \"%s\" statement.", ext->name, lyplg_ext_stmt2str(ext->parent_stmt));
41 return LY_ENOT;
42 }
43
44 pmod = ext->parent;
45
46 /* check for duplication */
47 LY_ARRAY_FOR(pmod->exts, u) {
48 if ((&pmod->exts[u] != ext) && (pmod->exts[u].name == ext->name) && !strcmp(pmod->exts[u].argument, ext->argument)) {
49 /* duplication of the same yang-data extension in a single module */
50 lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Extension %s is instantiated multiple times.", ext->name);
51 return LY_EVALID;
52 }
53 }
54
55 /* parse yang-data substatements */
56 LY_ARRAY_CREATE_GOTO(lyplg_extp_cur_pmod(pctx)->mod->ctx, ext->substmts, 3, ret, emem);
57 LY_ARRAY_INCREMENT(ext->substmts);
58 ext->substmts[0].stmt = LY_STMT_CONTAINER;
59 ext->substmts[0].storage = &ext->parsed;
60
61 LY_ARRAY_INCREMENT(ext->substmts);
62 ext->substmts[1].stmt = LY_STMT_CHOICE;
63 ext->substmts[1].storage = &ext->parsed;
64
65 LY_ARRAY_INCREMENT(ext->substmts);
66 ext->substmts[2].stmt = LY_STMT_USES;
67 ext->substmts[2].storage = &ext->parsed;
68
69 if ((ret = lyplg_ext_parse_extension_instance(pctx, ext))) {
70 return ret;
71 }
72
73 return LY_SUCCESS;
74
75emem:
76 lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s()).", __func__);
77 return LY_EMEM;
Radek Krejci5fa32a32021-02-08 18:12:38 +010078}
79
80/**
81 * @brief Compile yang-data extension instances.
82 *
Radek Krejci0b013302021-03-29 15:22:32 +020083 * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
Radek Krejci5fa32a32021-02-08 18:12:38 +010084 */
Radek Krejci3e6632f2021-03-22 22:08:21 +010085static LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +020086yangdata_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *extp, struct lysc_ext_instance *ext)
Radek Krejci5fa32a32021-02-08 18:12:38 +010087{
88 LY_ERR ret;
Radek Krejci5fa32a32021-02-08 18:12:38 +010089 const struct lysc_node *child;
90 ly_bool valid = 1;
Michal Vasko193dacd2022-10-13 08:43:05 +020091 uint32_t prev_options = *lyplg_ext_compile_get_options(cctx);
Radek Krejci5fa32a32021-02-08 18:12:38 +010092
Michal Vasko193dacd2022-10-13 08:43:05 +020093 /* compile yangg-data substatements */
94 LY_ARRAY_CREATE_GOTO(cctx->ctx, ext->substmts, 3, ret, emem);
95 LY_ARRAY_INCREMENT(ext->substmts);
96 ext->substmts[0].stmt = LY_STMT_CONTAINER;
97 ext->substmts[0].storage = &ext->compiled;
Radek Krejci5fa32a32021-02-08 18:12:38 +010098
Michal Vasko193dacd2022-10-13 08:43:05 +020099 LY_ARRAY_INCREMENT(ext->substmts);
100 ext->substmts[1].stmt = LY_STMT_CHOICE;
101 ext->substmts[1].storage = &ext->compiled;
Radek Krejci5fa32a32021-02-08 18:12:38 +0100102
Michal Vasko193dacd2022-10-13 08:43:05 +0200103 LY_ARRAY_INCREMENT(ext->substmts);
104 ext->substmts[2].stmt = LY_STMT_USES;
105 ext->substmts[2].storage = &ext->compiled;
Radek Krejci5fa32a32021-02-08 18:12:38 +0100106
Michal Vasko193dacd2022-10-13 08:43:05 +0200107 *lyplg_ext_compile_get_options(cctx) |= LYS_COMPILE_NO_CONFIG | LYS_COMPILE_NO_DISABLED;
108 ret = lyplg_ext_compile_extension_instance(cctx, extp, ext);
109 *lyplg_ext_compile_get_options(cctx) = prev_options;
Radek Krejci5f9a3672021-03-05 21:35:22 +0100110 if (ret) {
111 return ret;
112 }
Radek Krejci5fa32a32021-02-08 18:12:38 +0100113
114 /* check that we have really just a single container data definition in the top */
Michal Vasko193dacd2022-10-13 08:43:05 +0200115 child = ext->compiled;
Radek Krejci5fa32a32021-02-08 18:12:38 +0100116 if (!child) {
117 valid = 0;
Michal Vasko193dacd2022-10-13 08:43:05 +0200118 lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EVALID,
Radek Krejci5fa32a32021-02-08 18:12:38 +0100119 "Extension %s is instantiated without any top level data node, but exactly one container data node is expected.",
Michal Vasko193dacd2022-10-13 08:43:05 +0200120 extp->name);
Radek Krejci5fa32a32021-02-08 18:12:38 +0100121 } else if (child->next) {
122 valid = 0;
Michal Vasko193dacd2022-10-13 08:43:05 +0200123 lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EVALID,
Radek Krejci5fa32a32021-02-08 18:12:38 +0100124 "Extension %s is instantiated with multiple top level data nodes, but only a single container data node is allowed.",
Michal Vasko193dacd2022-10-13 08:43:05 +0200125 extp->name);
Radek Krejci5fa32a32021-02-08 18:12:38 +0100126 } else if (child->nodetype == LYS_CHOICE) {
127 /* all the choice's case are expected to result to a single container node */
Michal Vasko193dacd2022-10-13 08:43:05 +0200128 struct lysc_module *mod_c = ext->parent;
Radek Krejci5fa32a32021-02-08 18:12:38 +0100129 const struct lysc_node *snode = NULL;
130
131 while ((snode = lys_getnext(snode, child, mod_c, 0))) {
132 if (snode->next) {
133 valid = 0;
Michal Vasko193dacd2022-10-13 08:43:05 +0200134 lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EVALID,
Radek Krejci5fa32a32021-02-08 18:12:38 +0100135 "Extension %s is instantiated with multiple top level data nodes (inside a single choice's case), "
Michal Vasko193dacd2022-10-13 08:43:05 +0200136 "but only a single container data node is allowed.", extp->name);
Radek Krejci5fa32a32021-02-08 18:12:38 +0100137 break;
138 } else if (snode->nodetype != LYS_CONTAINER) {
139 valid = 0;
Michal Vasko193dacd2022-10-13 08:43:05 +0200140 lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EVALID,
Radek Krejci5fa32a32021-02-08 18:12:38 +0100141 "Extension %s is instantiated with %s top level data node (inside a choice), "
Michal Vasko193dacd2022-10-13 08:43:05 +0200142 "but only a single container data node is allowed.", extp->name, lys_nodetype2str(snode->nodetype));
Radek Krejci5fa32a32021-02-08 18:12:38 +0100143 break;
144 }
145 }
146 } else if (child->nodetype != LYS_CONTAINER) {
147 /* via uses */
148 valid = 0;
Michal Vasko193dacd2022-10-13 08:43:05 +0200149 lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EVALID,
Radek Krejci5fa32a32021-02-08 18:12:38 +0100150 "Extension %s is instantiated with %s top level data node, but only a single container data node is allowed.",
Michal Vasko193dacd2022-10-13 08:43:05 +0200151 extp->name, lys_nodetype2str(child->nodetype));
Radek Krejci5fa32a32021-02-08 18:12:38 +0100152 }
153
154 if (!valid) {
Michal Vasko193dacd2022-10-13 08:43:05 +0200155 yangdata_cfree(lyplg_ext_compile_get_ctx(cctx), ext);
156 ext->compiled = ext->substmts = NULL;
Radek Krejci5fa32a32021-02-08 18:12:38 +0100157 return LY_EVALID;
158 }
159
160 return LY_SUCCESS;
Radek Krejci859a15a2021-03-05 20:56:59 +0100161
162emem:
Michal Vasko193dacd2022-10-13 08:43:05 +0200163 lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s()).", __func__);
Radek Krejci859a15a2021-03-05 20:56:59 +0100164 return LY_EMEM;
Radek Krejci5fa32a32021-02-08 18:12:38 +0100165}
166
167/**
Radek Krejciadcf63d2021-02-09 10:21:18 +0100168 * @brief INFO printer
169 *
Radek Krejci0b013302021-03-29 15:22:32 +0200170 * Implementation of ::lyplg_ext_schema_printer_clb set as ::lyext_plugin::sprinter
Radek Krejciadcf63d2021-02-09 10:21:18 +0100171 */
Radek Krejci3e6632f2021-03-22 22:08:21 +0100172static LY_ERR
Radek Krejcif8d7f9a2021-03-10 14:32:36 +0100173yangdata_schema_printer(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag)
Radek Krejciadcf63d2021-02-09 10:21:18 +0100174{
Michal Vasko193dacd2022-10-13 08:43:05 +0200175 lyplg_ext_print_extension_instance(ctx, ext, flag);
Radek Krejciadcf63d2021-02-09 10:21:18 +0100176 return LY_SUCCESS;
177}
178
179/**
Michal Vasko193dacd2022-10-13 08:43:05 +0200180 * @brief Free parsed yang-data extension instance data.
181 *
182 * Implementation of ::lyplg_clb_parse_free_clb callback set as lyext_plugin::pfree.
183 */
184static void
185yangdata_pfree(const struct ly_ctx *ctx, struct lysp_ext_instance *ext)
186{
187 lyplg_ext_pfree_instance_substatements(ctx, ext->substmts);
188}
189
190/**
191 * @brief Free compiled yang-data extension instance data.
192 *
193 * Implementation of ::lyplg_clb_compile_free_clb callback set as lyext_plugin::cfree.
194 */
195static void
196yangdata_cfree(const struct ly_ctx *ctx, struct lysc_ext_instance *ext)
197{
198 lyplg_ext_cfree_instance_substatements(ctx, ext->substmts);
199}
200
201/**
Radek Krejci3e6632f2021-03-22 22:08:21 +0100202 * @brief Plugin descriptions for the yang-data extension
Radek Krejcia6f61e72021-03-24 21:00:19 +0100203 *
204 * Note that external plugins are supposed to use:
205 *
206 * LYPLG_EXTENSIONS = {
Radek Krejci5fa32a32021-02-08 18:12:38 +0100207 */
Radek Krejci3e6632f2021-03-22 22:08:21 +0100208const struct lyplg_ext_record plugins_yangdata[] = {
209 {
210 .module = "ietf-restconf",
211 .revision = "2017-01-26",
212 .name = "yang-data",
213
Michal Vasko193dacd2022-10-13 08:43:05 +0200214 .plugin.id = "ly2 yang-data v1",
215 .plugin.parse = yangdata_parse,
Michal Vasko135719f2022-08-25 12:18:17 +0200216 .plugin.compile = yangdata_compile,
217 .plugin.sprinter = yangdata_schema_printer,
Michal Vasko135719f2022-08-25 12:18:17 +0200218 .plugin.node = NULL,
Michal Vasko8cc3f662022-03-29 11:25:51 +0200219 .plugin.snode = NULL,
Michal Vasko193dacd2022-10-13 08:43:05 +0200220 .plugin.validate = NULL,
221 .plugin.pfree = yangdata_pfree,
222 .plugin.cfree = yangdata_cfree
Radek Krejci3e6632f2021-03-22 22:08:21 +0100223 },
224 {0} /* terminating zeroed record */
Radek Krejci5fa32a32021-02-08 18:12:38 +0100225};