blob: 04679aa5d378ecab7bbe87ea8a3cc6bae5115603 [file] [log] [blame]
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +01001/**
2 * @file schema_mount.c
3 * @author Tadeas Vintrlik <xvintr04@stud.fit.vutbr.cz>
4 * @brief libyang extension plugin - Schema Mount (RFC 8528)
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
15#define _GNU_SOURCE
16
17#include <assert.h>
Michal Vaskoddd76592022-01-17 13:34:48 +010018#include <pthread.h>
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010019#include <stdint.h>
20#include <stdlib.h>
21#include <string.h>
22
Michal Vaskofbbea932022-06-07 11:00:55 +020023#include "common.h"
Michal Vasko193dacd2022-10-13 08:43:05 +020024#include "compat.h"
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010025#include "dict.h"
26#include "libyang.h"
27#include "log.h"
Michal Vaskofbbea932022-06-07 11:00:55 +020028#include "parser_data.h"
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010029#include "plugins_exts.h"
Michal Vasko8cc3f662022-03-29 11:25:51 +020030#include "plugins_types.h"
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010031#include "tree_data.h"
32#include "tree_schema.h"
33
34/**
Michal Vaskoddd76592022-01-17 13:34:48 +010035 * @brief Internal schema mount data structure for holding all the contexts of parsed data.
36 */
37struct lyplg_ext_sm {
38 struct lyplg_ext_sm_shared {
39 pthread_mutex_t lock; /**< lock for accessing this shared structure */
40
41 struct {
42 struct ly_ctx *ctx; /**< context shared between all data of this mount point */
43 const char *mount_point; /**< mount point name */
44 const char *content_id; /**< yang-library content-id (alternatively module-set-id),
45 stored in the dictionary of the ext instance context */
46 } *schemas; /**< array of shared schema schemas */
47 uint32_t schema_count; /**< length of schemas array */
48 uint32_t ref_count; /**< number of references to this structure (mount-points with the same name
49 in the module) */
50 } *shared; /**< shared schema mount points */
51
52 struct lyplg_ext_sm_inln {
53 struct {
54 struct ly_ctx *ctx; /**< context created for single inline schema data */
55 } *schemas; /**< array of inline schemas */
56 uint32_t schema_count; /**< length of schemas array */
57 } inln; /**< inline mount points */
58};
59
Michal Vasko193dacd2022-10-13 08:43:05 +020060#define EXT_LOGERR_MEM_RET(cctx, ext) \
61 lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s:%d).", __FILE__, __LINE__); \
Michal Vaskoddd76592022-01-17 13:34:48 +010062 return LY_EMEM
63
Michal Vasko193dacd2022-10-13 08:43:05 +020064#define EXT_LOGERR_MEM_GOTO(cctx, ext, rc, label) \
65 lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EMEM, "Memory allocation failed (%s:%d).", __FILE__, __LINE__); \
Michal Vaskoddd76592022-01-17 13:34:48 +010066 rc = LY_EMEM; \
67 goto label
68
Michal Vasko193dacd2022-10-13 08:43:05 +020069#define EXT_LOGERR_INT_RET(cctx, ext) \
70 lyplg_ext_compile_log(cctx, ext, LY_LLERR, LY_EINT, "Internal error (%s:%d).", __FILE__, __LINE__); \
Michal Vaskoddd76592022-01-17 13:34:48 +010071 return LY_EINT
72
73/**
Michal Vasko193dacd2022-10-13 08:43:05 +020074 * @brief Check if given mount point is unique among its siblings
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010075 *
Michal Vasko193dacd2022-10-13 08:43:05 +020076 * @param[in] pctx Parse context.
77 * @param[in] ext Parsed extension instance.
Michal Vaskoddd76592022-01-17 13:34:48 +010078 * @return LY_SUCCESS if is unique;
79 * @return LY_EINVAL otherwise.
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010080 */
81static LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +020082schema_mount_parse_unique_mp(struct lysp_ctx *pctx, const struct lysp_ext_instance *ext)
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010083{
Michal Vasko193dacd2022-10-13 08:43:05 +020084 struct lysp_ext_instance *exts;
Michal Vaskoddd76592022-01-17 13:34:48 +010085 LY_ARRAY_COUNT_TYPE u;
Michal Vasko193dacd2022-10-13 08:43:05 +020086 struct lysp_node *parent;
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010087
Michal Vasko193dacd2022-10-13 08:43:05 +020088 /* check if it is the only instance of the mount-point among its siblings */
89 parent = ext->parent;
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010090 exts = parent->exts;
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010091 LY_ARRAY_FOR(exts, u) {
Michal Vasko193dacd2022-10-13 08:43:05 +020092 if (&exts[u] == ext) {
Michal Vaskoddd76592022-01-17 13:34:48 +010093 continue;
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010094 }
Michal Vaskoddd76592022-01-17 13:34:48 +010095
Michal Vasko193dacd2022-10-13 08:43:05 +020096 if (!strcmp(exts[u].name, ext->name)) {
97 lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Multiple extension \"%s\" instances.", ext->name);
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010098 return LY_EINVAL;
99 }
100 }
101 return LY_SUCCESS;
102}
103
Michal Vasko193dacd2022-10-13 08:43:05 +0200104/**
105 * @brief Schema mount parse.
106 * Checks if it can be a valid extension instance for yang schema mount.
107 *
108 * Implementation of ::lyplg_ext_parse_clb callback set as lyext_plugin::parse.
109 */
110static LY_ERR
111schema_mount_parse(struct lysp_ctx *pctx, struct lysp_ext_instance *ext)
112{
113 /* check YANG version 1.1 */
114 if (lyplg_ext_parse_get_cur_pmod(pctx)->version != LYS_VERSION_1_1) {
115 lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Extension \"%s\" instance not allowed in YANG version 1 module.",
116 ext->name);
117 return LY_EINVAL;
118 }
119
120 /* check parent nodetype */
121 if ((ext->parent_stmt != LY_STMT_CONTAINER) && (ext->parent_stmt != LY_STMT_LIST)) {
122 lyplg_ext_parse_log(pctx, ext, LY_LLERR, LY_EVALID, "Extension \"%s\" instance allowed only in container or list statement.",
123 ext->name);
124 return LY_EINVAL;
125 }
126
127 /* check uniqueness */
128 if (schema_mount_parse_unique_mp(pctx, ext)) {
129 return LY_EINVAL;
130 }
131
132 /* nothing to actually parse */
133 return LY_SUCCESS;
134}
135
Michal Vaskoddd76592022-01-17 13:34:48 +0100136struct lyplg_ext_sm_shared_cb_data {
137 const struct lysc_ext_instance *ext;
138 struct lyplg_ext_sm_shared *sm_shared;
139};
140
141static LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +0200142schema_mount_compile_mod_dfs_cb(struct lysc_node *node, void *data, ly_bool *UNUSED(dfs_continue))
Michal Vaskoddd76592022-01-17 13:34:48 +0100143{
144 struct lyplg_ext_sm_shared_cb_data *cb_data = data;
145 struct lyplg_ext_sm *sm_data;
146 struct lysc_ext_instance *exts;
147 LY_ARRAY_COUNT_TYPE u;
148
Michal Vaskoddd76592022-01-17 13:34:48 +0100149 if (node == cb_data->ext->parent) {
150 /* parent of the current compiled extension, skip */
151 return LY_SUCCESS;
152 }
153
154 /* find the same mount point */
155 exts = node->exts;
156 LY_ARRAY_FOR(exts, u) {
157 if (!strcmp(exts[u].def->module->name, "ietf-yang-schema-mount") && !strcmp(exts[u].def->name, "mount-point") &&
158 (exts[u].argument == cb_data->ext->argument)) {
159 /* same mount point, break the DFS search */
Michal Vasko193dacd2022-10-13 08:43:05 +0200160 sm_data = exts[u].compiled;
Michal Vaskoddd76592022-01-17 13:34:48 +0100161 cb_data->sm_shared = sm_data->shared;
162 return LY_EEXIST;
163 }
164 }
165
166 /* not found, continue search */
167 return LY_SUCCESS;
168}
169
170static struct lyplg_ext_sm_shared *
171schema_mount_compile_find_shared(const struct lys_module *mod, const struct lysc_ext_instance *ext)
172{
173 struct lyplg_ext_sm_shared_cb_data cb_data;
174 LY_ERR r;
175
176 /* prepare cb_data */
177 cb_data.ext = ext;
178 cb_data.sm_shared = NULL;
179
180 /* try to find the same mount point */
181 r = lysc_module_dfs_full(mod, schema_mount_compile_mod_dfs_cb, &cb_data);
Michal Vasko2a12cd92022-02-14 09:34:54 +0100182 (void)r;
Michal Vaskoddd76592022-01-17 13:34:48 +0100183 assert((!r && !cb_data.sm_shared) || ((r == LY_EEXIST) && cb_data.sm_shared));
184
185 return cb_data.sm_shared;
186}
187
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100188/**
189 * @brief Schema mount compile.
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100190 * Checks if it can be a valid extension instance for yang schema mount.
191 *
192 * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
193 */
194static LY_ERR
Michal Vasko193dacd2022-10-13 08:43:05 +0200195schema_mount_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *UNUSED(extp), struct lysc_ext_instance *ext)
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100196{
Michal Vaskodb641792022-03-21 10:04:54 +0100197 const struct lysc_node *node;
Michal Vaskoddd76592022-01-17 13:34:48 +0100198 struct lyplg_ext_sm *sm_data;
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100199
Michal Vaskoddd76592022-01-17 13:34:48 +0100200 /* init internal data */
201 sm_data = calloc(1, sizeof *sm_data);
202 if (!sm_data) {
Michal Vasko193dacd2022-10-13 08:43:05 +0200203 EXT_LOGERR_MEM_RET(cctx, ext);
Michal Vaskoddd76592022-01-17 13:34:48 +0100204 }
Michal Vasko193dacd2022-10-13 08:43:05 +0200205 ext->compiled = sm_data;
Michal Vaskoddd76592022-01-17 13:34:48 +0100206
Michal Vaskodb641792022-03-21 10:04:54 +0100207 /* find the owner module */
Michal Vasko193dacd2022-10-13 08:43:05 +0200208 node = ext->parent;
Michal Vaskodb641792022-03-21 10:04:54 +0100209 while (node->parent) {
210 node = node->parent;
211 }
212
Michal Vaskoddd76592022-01-17 13:34:48 +0100213 /* reuse/init shared schema */
Michal Vasko193dacd2022-10-13 08:43:05 +0200214 sm_data->shared = schema_mount_compile_find_shared(node->module, ext);
Michal Vaskoddd76592022-01-17 13:34:48 +0100215 if (sm_data->shared) {
216 ++sm_data->shared->ref_count;
217 } else {
218 sm_data->shared = calloc(1, sizeof *sm_data->shared);
219 if (!sm_data->shared) {
220 free(sm_data);
Michal Vasko193dacd2022-10-13 08:43:05 +0200221 EXT_LOGERR_MEM_RET(cctx, ext);
Michal Vaskoddd76592022-01-17 13:34:48 +0100222 }
223 pthread_mutex_init(&sm_data->shared->lock, NULL);
224 sm_data->shared->ref_count = 1;
225 }
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100226
227 return LY_SUCCESS;
228}
229
230/**
Michal Vaskoddd76592022-01-17 13:34:48 +0100231 * @brief Learn details about the current mount point.
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100232 *
Michal Vaskoddd76592022-01-17 13:34:48 +0100233 * @param[in] ext Compiled extension instance.
234 * @param[in] ext_data Extension data retrieved by the callback.
235 * @param[out] config Whether the whole schema should keep its config or be set to false.
236 * @param[out] shared Whether the schema is shared or inline.
237 * @return LY_ERR value.
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100238 */
239static LY_ERR
Michal Vaskoddd76592022-01-17 13:34:48 +0100240schema_mount_get_smount(const struct lysc_ext_instance *ext, const struct lyd_node *ext_data, ly_bool *config,
241 ly_bool *shared)
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100242{
Michal Vaskoddd76592022-01-17 13:34:48 +0100243 struct lyd_node *mpoint, *node;
244 char *path = NULL;
245 LY_ERR r;
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100246
Michal Vaskoddd76592022-01-17 13:34:48 +0100247 /* find the mount point */
248 if (asprintf(&path, "/ietf-yang-schema-mount:schema-mounts/mount-point[module='%s'][label='%s']", ext->module->name,
249 ext->argument) == -1) {
Michal Vasko193dacd2022-10-13 08:43:05 +0200250 EXT_LOGERR_MEM_RET(NULL, ext);
Michal Vaskoddd76592022-01-17 13:34:48 +0100251 }
252 r = ext_data ? lyd_find_path(ext_data, path, 0, &mpoint) : LY_ENOTFOUND;
253 free(path);
254 if (r) {
255 /* missing mount-point, cannot be data for this extension (https://datatracker.ietf.org/doc/html/rfc8528#page-10) */
256 return LY_ENOT;
257 }
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100258
Michal Vaskoddd76592022-01-17 13:34:48 +0100259 /* check config */
Michal Vasko9e12ffe2022-09-21 15:11:30 +0200260 *config = 1;
Michal Vaskoddd76592022-01-17 13:34:48 +0100261 if (!lyd_find_path(mpoint, "config", 0, &node) && !strcmp(lyd_get_value(node), "false")) {
262 *config = 0;
Michal Vasko9e12ffe2022-09-21 15:11:30 +0200263 }
264 assert((ext->parent_stmt == LY_STMT_CONTAINER) || (ext->parent_stmt == LY_STMT_LIST));
265 if (((struct lysc_node *)ext->parent)->flags & LYS_CONFIG_R) {
266 *config = 0;
Michal Vaskoddd76592022-01-17 13:34:48 +0100267 }
268
269 /* check schema-ref */
270 if (lyd_find_path(mpoint, "shared-schema", 0, NULL)) {
271 if (lyd_find_path(mpoint, "inline", 0, NULL)) {
Michal Vasko193dacd2022-10-13 08:43:05 +0200272 EXT_LOGERR_INT_RET(NULL, ext);
Michal Vaskoddd76592022-01-17 13:34:48 +0100273 }
274 *shared = 0;
275 } else {
276 *shared = 1;
277 }
278
279 return LY_SUCCESS;
280}
281
282/**
283 * @brief Create schema (context) based on retrieved extension data.
284 *
285 * @param[in] ext Compiled extension instance.
286 * @param[in] ext_data Extension data retrieved by the callback.
287 * @param[in] config Whether the whole schema should keep its config or be set to false.
288 * @param[out] ext_ctx Schema to use for parsing the data.
289 * @return LY_ERR value.
290 */
291static LY_ERR
292schema_mount_create_ctx(const struct lysc_ext_instance *ext, const struct lyd_node *ext_data, ly_bool config,
293 struct ly_ctx **ext_ctx)
294{
Michal Vasko0fca45c2022-06-07 10:57:32 +0200295 LY_ERR rc = LY_SUCCESS;
Michal Vaskoddd76592022-01-17 13:34:48 +0100296 const char * const *searchdirs;
Michal Vasko0fca45c2022-06-07 10:57:32 +0200297 char *sdirs = NULL;
Michal Vaskoddd76592022-01-17 13:34:48 +0100298 const struct lys_module *mod;
299 struct lysc_node *root, *node;
Michal Vasko0fca45c2022-06-07 10:57:32 +0200300 uint32_t i, idx = 0;
Michal Vaskoddd76592022-01-17 13:34:48 +0100301
302 /* get searchdirs from the current context */
303 searchdirs = ly_ctx_get_searchdirs(ext->module->ctx);
304
Michal Vasko0fca45c2022-06-07 10:57:32 +0200305 if (searchdirs) {
306 /* append them all into a single string */
307 for (i = 0; searchdirs[i]; ++i) {
Jan Kundrát1fbc90d2022-06-07 21:27:53 +0200308 if ((rc = ly_strcat(&sdirs, "%s" PATH_SEPARATOR, searchdirs[i]))) {
Michal Vasko0fca45c2022-06-07 10:57:32 +0200309 goto cleanup;
310 }
311 }
312 }
313
Michal Vaskoddd76592022-01-17 13:34:48 +0100314 /* create the context based on the data */
Michal Vasko0fca45c2022-06-07 10:57:32 +0200315 if ((rc = ly_ctx_new_yldata(sdirs, ext_data, ly_ctx_get_options(ext->module->ctx), ext_ctx))) {
Michal Vasko193dacd2022-10-13 08:43:05 +0200316 lyplg_ext_compile_log(NULL, ext, LY_LLERR, rc, "Failed to create context for the schema-mount data.");
Michal Vasko0fca45c2022-06-07 10:57:32 +0200317 goto cleanup;
Michal Vaskoddd76592022-01-17 13:34:48 +0100318 }
319
320 if (!config) {
321 /* manually change the config of all schema nodes in all the modules */
322 while ((mod = ly_ctx_get_module_iter(*ext_ctx, &idx))) {
323 if (!mod->implemented) {
324 continue;
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100325 }
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100326
Michal Vaskoddd76592022-01-17 13:34:48 +0100327 LY_LIST_FOR(mod->compiled->data, root) {
328 LYSC_TREE_DFS_BEGIN(root, node) {
329 node->flags &= ~LYS_CONFIG_W;
330 node->flags |= LYS_CONFIG_R;
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100331
Michal Vaskoddd76592022-01-17 13:34:48 +0100332 LYSC_TREE_DFS_END(root, node);
333 }
334 }
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100335 }
336 }
337
Michal Vasko0fca45c2022-06-07 10:57:32 +0200338cleanup:
339 free(sdirs);
340 return rc;
Michal Vaskoddd76592022-01-17 13:34:48 +0100341}
342
343/**
344 * @brief Get schema (context) for a shared-schema mount point.
345 *
346 * @param[in] ext Compiled extension instance.
347 * @param[in] ext_data Extension data retrieved by the callback.
348 * @param[in] config Whether the whole schema should keep its config or be set to false.
349 * @param[out] ext_ctx Schema to use for parsing the data.
350 * @return LY_ERR value.
351 */
352static LY_ERR
353schema_mount_get_ctx_shared(struct lysc_ext_instance *ext, const struct lyd_node *ext_data, ly_bool config,
354 const struct ly_ctx **ext_ctx)
355{
Michal Vasko193dacd2022-10-13 08:43:05 +0200356 struct lyplg_ext_sm *sm_data = ext->compiled;
Michal Vaskoddd76592022-01-17 13:34:48 +0100357 LY_ERR ret = LY_SUCCESS, r;
358 struct lyd_node *node = NULL;
ekinzie0ab8b302022-10-10 03:03:57 -0400359 struct ly_ctx *new_ctx = NULL;
Michal Vaskoddd76592022-01-17 13:34:48 +0100360 uint32_t i;
361 const char *content_id = NULL;
362 void *mem;
363
364 assert(sm_data && sm_data->shared);
365
366 /* get yang-library content-id or module-set-id */
367 if (ext_data) {
368 lyd_find_path(ext_data, "/ietf-yang-library:yang-library/content-id", 0, &node);
369 if (!node) {
370 lyd_find_path(ext_data, "/ietf-yang-library:modules-state/module-set-id", 0, &node);
371 }
372 if (node) {
373 content_id = lyd_get_value(node);
374 }
375 }
376 if (!content_id) {
Michal Vasko193dacd2022-10-13 08:43:05 +0200377 lyplg_ext_compile_log(NULL, ext, LY_LLERR, LY_EVALID,
378 "Missing \"content-id\" or \"module-set-id\" in ietf-yang-library data.");
Michal Vaskoddd76592022-01-17 13:34:48 +0100379 return LY_EVALID;
380 }
381
382 /* LOCK */
383 if ((r = pthread_mutex_lock(&sm_data->shared->lock))) {
Michal Vasko193dacd2022-10-13 08:43:05 +0200384 lyplg_ext_compile_log(NULL, ext, LY_LLERR, LY_ESYS, "Mutex lock failed (%s).", strerror(r));
Michal Vaskoddd76592022-01-17 13:34:48 +0100385 return LY_ESYS;
386 }
387
388 /* try to find this mount point */
389 for (i = 0; i < sm_data->shared->schema_count; ++i) {
390 if (ext->argument == sm_data->shared->schemas[i].mount_point) {
391 break;
392 }
393 }
394
395 if (i < sm_data->shared->schema_count) {
396 /* schema exists already */
397 if (strcmp(content_id, sm_data->shared->schemas[i].content_id)) {
Michal Vasko193dacd2022-10-13 08:43:05 +0200398 lyplg_ext_compile_log_path("/ietf-yang-library:yang-library/content-id", ext, LY_LLERR, LY_EVALID,
Michal Vaskoddd76592022-01-17 13:34:48 +0100399 "Shared-schema yang-library content-id \"%s\" differs from \"%s\" used previously.",
400 content_id, sm_data->shared->schemas[i].content_id);
401 ret = LY_EVALID;
402 goto cleanup;
403 }
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100404 } else {
Michal Vaskoddd76592022-01-17 13:34:48 +0100405 /* no schema found, create it */
406 if ((r = schema_mount_create_ctx(ext, ext_data, config, &new_ctx))) {
407 ret = r;
408 goto cleanup;
409 }
410
411 /* new entry */
412 mem = realloc(sm_data->shared->schemas, (i + 1) * sizeof *sm_data->shared->schemas);
413 if (!mem) {
414 ly_ctx_destroy(new_ctx);
Michal Vasko193dacd2022-10-13 08:43:05 +0200415 EXT_LOGERR_MEM_GOTO(NULL, ext, ret, cleanup);
Michal Vaskoddd76592022-01-17 13:34:48 +0100416 }
417 sm_data->shared->schemas = mem;
418 ++sm_data->shared->schema_count;
419
420 /* fill entry */
421 sm_data->shared->schemas[i].ctx = new_ctx;
422 sm_data->shared->schemas[i].mount_point = ext->argument;
423 lydict_insert(ext->module->ctx, content_id, 0, &sm_data->shared->schemas[i].content_id);
424 }
425
426 /* use the context */
427 *ext_ctx = sm_data->shared->schemas[i].ctx;
428
429cleanup:
430 /* UNLOCK */
431 pthread_mutex_unlock(&sm_data->shared->lock);
432
433 return ret;
434}
435
436/**
437 * @brief Get schema (context) for an inline mount point.
438 *
439 * @param[in] ext Compiled extension instance.
440 * @param[in] ext_data Extension data retrieved by the callback.
441 * @param[in] config Whether the whole schema should keep its config or be set to false.
442 * @param[out] ext_ctx Schema to use for parsing the data.
443 * @return LY_ERR value.
444 */
445static LY_ERR
446schema_mount_get_ctx_inline(struct lysc_ext_instance *ext, const struct lyd_node *ext_data, ly_bool config,
447 const struct ly_ctx **ext_ctx)
448{
Michal Vasko193dacd2022-10-13 08:43:05 +0200449 struct lyplg_ext_sm *sm_data = ext->compiled;
Michal Vaskoddd76592022-01-17 13:34:48 +0100450 LY_ERR r;
ekinzie0ab8b302022-10-10 03:03:57 -0400451 struct ly_ctx *new_ctx = NULL;
Michal Vaskoddd76592022-01-17 13:34:48 +0100452 uint32_t i;
453 void *mem;
454
455 assert(sm_data && sm_data->shared);
456
457 i = sm_data->inln.schema_count;
458
459 /* always new schema required, create context */
460 if ((r = schema_mount_create_ctx(ext, ext_data, config, &new_ctx))) {
461 return r;
462 }
463
464 /* new entry */
465 mem = realloc(sm_data->inln.schemas, (i + 1) * sizeof *sm_data->inln.schemas);
466 if (!mem) {
467 ly_ctx_destroy(new_ctx);
Michal Vasko193dacd2022-10-13 08:43:05 +0200468 EXT_LOGERR_MEM_RET(NULL, ext);
Michal Vaskoddd76592022-01-17 13:34:48 +0100469 }
470 sm_data->inln.schemas = mem;
471 ++sm_data->inln.schema_count;
472
473 /* fill entry */
474 sm_data->inln.schemas[i].ctx = new_ctx;
475
476 /* use the context */
477 *ext_ctx = sm_data->inln.schemas[i].ctx;
478 return LY_SUCCESS;
479}
480
481/**
482 * @brief Get schema (context) for a mount point.
483 *
484 * @param[in] ext Compiled extension instance.
485 * @param[out] ext_ctx Schema to use for parsing the data.
486 * @return LY_ERR value.
487 */
488static LY_ERR
489schema_mount_get_ctx(struct lysc_ext_instance *ext, const struct ly_ctx **ext_ctx)
490{
491 LY_ERR ret = LY_SUCCESS, r;
492 struct lyd_node *iter, *ext_data = NULL;
493 ly_bool ext_data_free = 0, config, shared;
494
495 *ext_ctx = NULL;
496
497 /* get operational data with ietf-yang-library and ietf-yang-schema-mount data */
498 if ((r = lyplg_ext_get_data(ext->module->ctx, ext, (void **)&ext_data, &ext_data_free))) {
499 ret = r;
500 goto cleanup;
501 }
502
503 LY_LIST_FOR(ext_data, iter) {
504 if (iter->flags & LYD_NEW) {
505 /* must be validated for the parent-reference prefix data to be stored */
Michal Vasko193dacd2022-10-13 08:43:05 +0200506 lyplg_ext_compile_log(NULL, ext, LY_LLERR, LY_EINVAL, "Provided ext data have not been validated.");
Michal Vaskoddd76592022-01-17 13:34:48 +0100507 ret = LY_EINVAL;
508 goto cleanup;
509 }
510 }
511
512 /* learn about this mount point */
513 if ((r = schema_mount_get_smount(ext, ext_data, &config, &shared))) {
514 ret = r;
515 goto cleanup;
516 }
517
518 /* create/get the context for parsing the data */
519 if (shared) {
520 r = schema_mount_get_ctx_shared(ext, ext_data, config, ext_ctx);
521 } else {
522 r = schema_mount_get_ctx_inline(ext, ext_data, config, ext_ctx);
523 }
524 if (r) {
525 ret = r;
526 goto cleanup;
527 }
528
529cleanup:
530 if (ext_data_free) {
531 lyd_free_all(ext_data);
532 }
533 return ret;
534}
535
536/**
Michal Vasko8cc3f662022-03-29 11:25:51 +0200537 * @brief Snode callback for schema mount.
538 * Check if data are valid for schema mount and returns their schema node.
Michal Vaskoddd76592022-01-17 13:34:48 +0100539 */
540static LY_ERR
Michal Vasko8cc3f662022-03-29 11:25:51 +0200541schema_mount_snode(struct lysc_ext_instance *ext, const struct lyd_node *parent, const struct lysc_node *sparent,
542 const char *prefix, size_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data, const char *name, size_t name_len,
543 const struct lysc_node **snode)
Michal Vaskoddd76592022-01-17 13:34:48 +0100544{
Michal Vasko8cc3f662022-03-29 11:25:51 +0200545 LY_ERR r;
546 const struct lys_module *mod;
ekinzie0ab8b302022-10-10 03:03:57 -0400547 const struct ly_ctx *ext_ctx = NULL;
Michal Vaskoddd76592022-01-17 13:34:48 +0100548
549 /* get context based on ietf-yang-library data */
550 if ((r = schema_mount_get_ctx(ext, &ext_ctx))) {
551 return r;
552 }
553
Michal Vasko8cc3f662022-03-29 11:25:51 +0200554 /* get the module */
555 mod = lyplg_type_identity_module(ext_ctx, parent ? parent->schema : sparent, prefix, prefix_len, format, prefix_data);
556 if (!mod) {
557 return LY_ENOT;
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100558 }
559
Michal Vasko8cc3f662022-03-29 11:25:51 +0200560 /* get the top-level schema node */
561 *snode = lys_find_child(NULL, mod, name, name_len, 0, 0);
562 return *snode ? LY_SUCCESS : LY_ENOT;
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100563}
564
ekinzie0ab8b302022-10-10 03:03:57 -0400565static LY_ERR
566schema_mount_get_parent_ref(const struct lysc_ext_instance *ext, const struct lyd_node *ext_data,
567 struct ly_set **set)
568{
569 LY_ERR ret = LY_SUCCESS;
570 char *path = NULL;
571
572 /* get all parent references of this mount point */
573 if (asprintf(&path, "/ietf-yang-schema-mount:schema-mounts/mount-point[module='%s'][label='%s']"
574 "/shared-schema/parent-reference", ext->module->name, ext->argument) == -1) {
Michal Vasko193dacd2022-10-13 08:43:05 +0200575 EXT_LOGERR_MEM_GOTO(NULL, ext, ret, cleanup);
ekinzie0ab8b302022-10-10 03:03:57 -0400576 }
577 if ((ret = lyd_find_xpath(ext_data, path, set))) {
578 goto cleanup;
579 }
580
581cleanup:
582 free(path);
583 return ret;
584}
585
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100586/**
Michal Vaskoddd76592022-01-17 13:34:48 +0100587 * @brief Duplicate all accessible parent references for a shared-schema mount point.
588 *
589 * @param[in] ext Compiled extension instance.
590 * @param[in] ctx_node Context node for evaluating the parent-reference XPath expressions.
591 * @param[in] ext_data Extension data retrieved by the callback.
592 * @param[in] trg_ctx Mounted data context to use for duplication.
593 * @param[out] ref_set Set of all top-level parent-ref subtrees connected to each other, may be empty.
594 * @return LY_ERR value.
595 */
596static LY_ERR
597schema_mount_dup_parent_ref(const struct lysc_ext_instance *ext, const struct lyd_node *ctx_node,
598 const struct lyd_node *ext_data, const struct ly_ctx *trg_ctx, struct ly_set **ref_set)
599{
600 LY_ERR ret = LY_SUCCESS;
601 char *path = NULL;
602 struct ly_set *set = NULL, *par_set = NULL;
603 struct lyd_node_term *term;
604 struct lyd_node *dup = NULL, *top_node, *first;
605 struct lyd_value_xpath10 *xp_val;
606 uint32_t i, j;
607
608 *ref_set = NULL;
609
610 if (!ext_data) {
611 /* we expect the same ext data as before and there must be some for data to be parsed */
Michal Vasko193dacd2022-10-13 08:43:05 +0200612 lyplg_ext_compile_log(NULL, ext, LY_LLERR, LY_EINVAL, "No ext data provided.");
Michal Vaskoddd76592022-01-17 13:34:48 +0100613 ret = LY_EINVAL;
614 goto cleanup;
615 }
616
ekinzie0ab8b302022-10-10 03:03:57 -0400617 if ((ret = schema_mount_get_parent_ref(ext, ext_data, &set))) {
Michal Vaskoddd76592022-01-17 13:34:48 +0100618 goto cleanup;
619 }
620
621 /* prepare result set */
622 if ((ret = ly_set_new(ref_set))) {
623 goto cleanup;
624 }
625
626 first = NULL;
627 for (i = 0; i < set->count; ++i) {
628 term = set->objs[i];
629
630 /* get the referenced nodes (subtrees) */
631 LYD_VALUE_GET(&term->value, xp_val);
632 if ((ret = lyd_find_xpath4(ctx_node, ctx_node, lyxp_get_expr(xp_val->exp), xp_val->format, xp_val->prefix_data,
633 NULL, &par_set))) {
Michal Vasko193dacd2022-10-13 08:43:05 +0200634 lyplg_ext_compile_log(NULL, ext, LY_LLERR, ret, "Parent reference \"%s\" evaluation failed.",
635 lyxp_get_expr(xp_val->exp));
Michal Vaskoddd76592022-01-17 13:34:48 +0100636 goto cleanup;
637 }
638
639 for (j = 0; j < par_set->count; ++j) {
640 /* duplicate with parents in the context of the mounted data */
641 if ((ret = lyd_dup_single_to_ctx(par_set->dnodes[j], trg_ctx, NULL,
Michal Vaskofbbea932022-06-07 11:00:55 +0200642 LYD_DUP_RECURSIVE | LYD_DUP_WITH_PARENTS | LYD_DUP_WITH_FLAGS | LYD_DUP_NO_EXT, &dup))) {
Michal Vaskoddd76592022-01-17 13:34:48 +0100643 goto cleanup;
644 }
645
646 /* go top-level */
647 while (dup->parent) {
648 dup = lyd_parent(dup);
649 }
650
651 /* check whether the top-level node exists */
652 if (first) {
653 if ((ret = lyd_find_sibling_first(first, dup, &top_node)) && (ret != LY_ENOTFOUND)) {
654 goto cleanup;
655 }
656 } else {
657 top_node = NULL;
658 }
659
660 if (top_node) {
661 /* merge */
662 ret = lyd_merge_tree(&first, dup, LYD_MERGE_DESTRUCT);
663 dup = NULL;
664 if (ret) {
665 goto cleanup;
666 }
667 } else {
668 /* insert */
669 if ((ret = lyd_insert_sibling(first, dup, &first))) {
670 goto cleanup;
671 }
672
673 /* add into the result set because a new top-level node was added */
674 if ((ret = ly_set_add(*ref_set, dup, 1, NULL))) {
675 goto cleanup;
676 }
677 dup = NULL;
678 }
679 }
680 }
681
682cleanup:
683 free(path);
684 ly_set_free(set, NULL);
685 ly_set_free(par_set, NULL);
686 lyd_free_tree(dup);
687 if (ret && *ref_set) {
688 if ((*ref_set)->count) {
689 lyd_free_siblings((*ref_set)->dnodes[0]);
690 }
691 ly_set_free(*ref_set, NULL);
692 *ref_set = NULL;
693 }
694 return ret;
695}
696
ekinzie0ab8b302022-10-10 03:03:57 -0400697LY_ERR
698lyplg_ext_schema_mount_get_parent_ref(const struct lysc_ext_instance *ext, struct ly_set **refs)
699{
aPiecekb72a6df2022-10-10 10:02:38 +0200700 LY_ERR rc;
ekinzie0ab8b302022-10-10 03:03:57 -0400701 struct ly_set *pref_set = NULL;
aPiecekb72a6df2022-10-10 10:02:38 +0200702 struct ly_set *snode_set = NULL;
ekinzie0ab8b302022-10-10 03:03:57 -0400703 struct ly_set *results_set = NULL;
704 struct lyd_node *ext_data;
705 ly_bool ext_data_free;
706
707 /* get operational data with ietf-yang-library and ietf-yang-schema-mount data */
aPiecekb72a6df2022-10-10 10:02:38 +0200708 if ((rc = lyplg_ext_get_data(ext->module->ctx, ext, (void **)&ext_data, &ext_data_free))) {
709 return rc;
ekinzie0ab8b302022-10-10 03:03:57 -0400710 }
711
aPiecekb72a6df2022-10-10 10:02:38 +0200712 LY_CHECK_GOTO(rc = schema_mount_get_parent_ref(ext, ext_data, &pref_set), cleanup);
ekinzie0ab8b302022-10-10 03:03:57 -0400713 if (pref_set->count == 0) {
aPiecekb72a6df2022-10-10 10:02:38 +0200714 goto cleanup;
ekinzie0ab8b302022-10-10 03:03:57 -0400715 }
716
aPiecekb72a6df2022-10-10 10:02:38 +0200717 LY_CHECK_GOTO(rc = ly_set_new(&results_set), cleanup);
ekinzie0ab8b302022-10-10 03:03:57 -0400718
719 for (uint32_t i = 0; i < pref_set->count; ++i) {
720 struct lyd_node_term *term;
721 struct lyd_value_xpath10 *xp_val;
722 char *value;
723 struct ly_err_item *err;
724
725 term = (struct lyd_node_term *)pref_set->dnodes[i];
726 LYD_VALUE_GET(&term->value, xp_val);
aPiecekb72a6df2022-10-10 10:02:38 +0200727 LY_CHECK_GOTO(rc = lyplg_type_print_xpath10_value(xp_val, LY_VALUE_JSON, NULL, &value, &err), cleanup);
728 LY_CHECK_ERR_GOTO(rc = lys_find_xpath(ext->module->ctx, NULL, value, 0, &snode_set), free(value), cleanup);
ekinzie0ab8b302022-10-10 03:03:57 -0400729 free(value);
730 for (uint32_t sn = 0; sn < snode_set->count; sn++) {
aPiecekb72a6df2022-10-10 10:02:38 +0200731 LY_CHECK_GOTO(rc = ly_set_add(results_set, snode_set->snodes[sn], 0, NULL), cleanup);
ekinzie0ab8b302022-10-10 03:03:57 -0400732 }
733 ly_set_free(snode_set, NULL);
aPiecekb72a6df2022-10-10 10:02:38 +0200734 snode_set = NULL;
ekinzie0ab8b302022-10-10 03:03:57 -0400735 }
736
737 *refs = results_set;
738
aPiecekb72a6df2022-10-10 10:02:38 +0200739cleanup:
740 if (rc) {
741 ly_set_free(results_set, NULL);
742 }
743 ly_set_free(snode_set, NULL);
ekinzie0ab8b302022-10-10 03:03:57 -0400744 if (ext_data_free) {
745 lyd_free_all(ext_data);
746 }
747 ly_set_free(pref_set, NULL);
aPiecekb72a6df2022-10-10 10:02:38 +0200748
749 return rc;
ekinzie0ab8b302022-10-10 03:03:57 -0400750}
751
Michal Vaskoddd76592022-01-17 13:34:48 +0100752/**
753 * @brief Validate callback for schema mount.
754 */
755static LY_ERR
Michal Vaskofbbea932022-06-07 11:00:55 +0200756schema_mount_validate(struct lysc_ext_instance *ext, struct lyd_node *sibling, const struct lyd_node *dep_tree,
757 enum lyd_type data_type, uint32_t val_opts, struct lyd_node **diff)
Michal Vaskoddd76592022-01-17 13:34:48 +0100758{
759 LY_ERR ret = LY_SUCCESS;
760 uint32_t old_log_opts, i;
761 struct ly_err_item *err;
Michal Vaskofbbea932022-06-07 11:00:55 +0200762 struct lyd_node *iter, *ext_data = NULL, *ref_first = NULL, *orig_parent = lyd_parent(sibling), *op_tree;
Michal Vaskof4c6f002022-04-01 09:12:22 +0200763 struct lyd_node *ext_diff = NULL, *diff_parent = NULL;
Michal Vaskoddd76592022-01-17 13:34:48 +0100764 ly_bool ext_data_free = 0;
765 struct ly_set *ref_set = NULL;
766
767 if (!sibling) {
768 /* some data had to be parsed for this callback to be called */
Michal Vasko193dacd2022-10-13 08:43:05 +0200769 EXT_LOGERR_INT_RET(NULL, ext);
Michal Vaskoddd76592022-01-17 13:34:48 +0100770 }
771
772 /* get operational data with ietf-yang-library and ietf-yang-schema-mount data */
773 if ((ret = lyplg_ext_get_data(ext->module->ctx, ext, (void **)&ext_data, &ext_data_free))) {
774 goto cleanup;
775 }
776
777 LY_LIST_FOR(ext_data, iter) {
778 if (iter->flags & LYD_NEW) {
779 /* must be validated for the parent-reference prefix data to be stored */
Michal Vasko193dacd2022-10-13 08:43:05 +0200780 lyplg_ext_compile_log(NULL, ext, LY_LLERR, LY_EINVAL, "Provided ext data have not been validated.");
Michal Vaskoddd76592022-01-17 13:34:48 +0100781 ret = LY_EINVAL;
782 goto cleanup;
783 }
784 }
785
786 /* duplicate the referenced parent nodes into ext context */
787 if ((ret = schema_mount_dup_parent_ref(ext, orig_parent, ext_data, LYD_CTX(sibling), &ref_set))) {
788 goto cleanup;
789 }
790
Michal Vaskofbbea932022-06-07 11:00:55 +0200791 if (data_type != LYD_TYPE_DATA_YANG) {
792 /* remember the operation data tree, it may be moved */
793 op_tree = sibling;
794 }
795
Michal Vaskoddd76592022-01-17 13:34:48 +0100796 /* create accessible tree, remove LYD_EXT to not call this callback recursively */
797 lyd_unlink_siblings(sibling);
798 LY_LIST_FOR(sibling, iter) {
799 iter->flags &= ~LYD_EXT;
800 }
801 if (ref_set->count) {
802 if ((ret = lyd_insert_sibling(sibling, ref_set->dnodes[0], &sibling))) {
803 goto cleanup;
804 }
805 }
806
807 /* only store messages in the context, log as an extension */
808 old_log_opts = ly_log_options(LY_LOSTORE_LAST);
809
Michal Vaskofbbea932022-06-07 11:00:55 +0200810 if (data_type == LYD_TYPE_DATA_YANG) {
811 /* validate all the data */
812 ret = lyd_validate_all(&sibling, NULL, val_opts, diff ? &ext_diff : NULL);
813 } else {
814 /* validate the operation */
815 ret = lyd_validate_op(op_tree, dep_tree, data_type, diff ? &ext_diff : NULL);
816 }
817
818 /* restore logging */
Michal Vaskoddd76592022-01-17 13:34:48 +0100819 ly_log_options(old_log_opts);
820
821 /* restore sibling tree */
822 for (i = 0; i < ref_set->count; ++i) {
823 if (ref_set->dnodes[i] == sibling) {
824 sibling = sibling->next;
825 }
826 lyd_free_tree(ref_set->dnodes[i]);
827 }
828 LY_LIST_FOR(sibling, iter) {
829 iter->flags |= LYD_EXT;
830 }
Michal Vasko193dacd2022-10-13 08:43:05 +0200831 lyplg_ext_insert(orig_parent, sibling);
Michal Vaskoddd76592022-01-17 13:34:48 +0100832
833 if (ret) {
834 /* log the error in the original context */
835 err = ly_err_first(LYD_CTX(sibling));
836 if (!err) {
Michal Vasko193dacd2022-10-13 08:43:05 +0200837 lyplg_ext_compile_log(NULL, ext, LY_LLERR, ret, "Unknown validation error (err code %d).", ret);
Michal Vaskoddd76592022-01-17 13:34:48 +0100838 } else {
Michal Vasko193dacd2022-10-13 08:43:05 +0200839 lyplg_ext_compile_log_path(err->path, ext, LY_LLERR, err->no, "%s", err->msg);
Michal Vaskoddd76592022-01-17 13:34:48 +0100840 }
841 goto cleanup;
842 }
843
Michal Vaskof4c6f002022-04-01 09:12:22 +0200844 /* create proper diff */
845 if (diff && ext_diff) {
846 /* diff nodes from an extension instance */
847 LY_LIST_FOR(ext_diff, iter) {
848 iter->flags |= LYD_EXT;
849 }
850
851 /* create the parent and insert the diff */
852 if ((ret = lyd_dup_single(lyd_parent(sibling), NULL, LYD_DUP_WITH_PARENTS | LYD_DUP_NO_META, &diff_parent))) {
853 goto cleanup;
854 }
Michal Vasko193dacd2022-10-13 08:43:05 +0200855 if ((ret = lyplg_ext_insert(diff_parent, ext_diff))) {
Michal Vaskof4c6f002022-04-01 09:12:22 +0200856 goto cleanup;
857 }
858 ext_diff = NULL;
859
860 /* go top-level and set the operation */
861 while (lyd_parent(diff_parent)) {
862 diff_parent = lyd_parent(diff_parent);
863 }
864 if ((ret = lyd_new_meta(LYD_CTX(diff_parent), diff_parent, NULL, "yang:operation", "none", 0, NULL))) {
865 goto cleanup;
866 }
867
868 /* finally merge into the global diff */
869 if ((ret = lyd_diff_merge_all(diff, diff_parent, LYD_DIFF_MERGE_DEFAULTS))) {
870 goto cleanup;
871 }
872 }
873
Michal Vaskoddd76592022-01-17 13:34:48 +0100874cleanup:
875 ly_set_free(ref_set, NULL);
876 lyd_free_siblings(ref_first);
Michal Vaskof4c6f002022-04-01 09:12:22 +0200877 lyd_free_tree(ext_diff);
878 lyd_free_all(diff_parent);
Michal Vaskoddd76592022-01-17 13:34:48 +0100879 if (ext_data_free) {
880 lyd_free_all(ext_data);
881 }
882 return ret;
883}
884
885/**
Michal Vasko193dacd2022-10-13 08:43:05 +0200886 * @brief Schema mount compile free.
Michal Vaskoddd76592022-01-17 13:34:48 +0100887 *
Michal Vasko193dacd2022-10-13 08:43:05 +0200888 * Implementation of ::lyplg_ext_compile_free_clb callback set as ::lyext_plugin::cfree.
Michal Vaskoddd76592022-01-17 13:34:48 +0100889 */
890static void
Michal Vasko193dacd2022-10-13 08:43:05 +0200891schema_mount_cfree(const struct ly_ctx *ctx, struct lysc_ext_instance *ext)
Michal Vaskoddd76592022-01-17 13:34:48 +0100892{
Michal Vasko193dacd2022-10-13 08:43:05 +0200893 struct lyplg_ext_sm *sm_data = ext->compiled;
Michal Vaskoddd76592022-01-17 13:34:48 +0100894 uint32_t i;
895
896 if (!sm_data) {
897 return;
898 }
899
900 if (!--sm_data->shared->ref_count) {
901 for (i = 0; i < sm_data->shared->schema_count; ++i) {
902 ly_ctx_destroy(sm_data->shared->schemas[i].ctx);
903 lydict_remove(ctx, sm_data->shared->schemas[i].content_id);
904 }
905 free(sm_data->shared->schemas);
906 pthread_mutex_destroy(&sm_data->shared->lock);
907 free(sm_data->shared);
908 }
909
910 for (i = 0; i < sm_data->inln.schema_count; ++i) {
911 ly_ctx_destroy(sm_data->inln.schemas[i].ctx);
912 }
913 free(sm_data->inln.schemas);
914 free(sm_data);
915}
916
ekinzie0ab8b302022-10-10 03:03:57 -0400917LIBYANG_API_DEF LY_ERR
918lyplg_ext_schema_mount_create_context(const struct lysc_ext_instance *ext, struct ly_ctx **ctx)
919{
920 struct lyd_node *ext_data;
921 ly_bool ext_data_free;
922 ly_bool config;
923 ly_bool shared;
924 LY_ERR res;
925
926 if (!ext->module->ctx->ext_clb) {
927 return LY_EINVAL;
928 }
929
930 if (strcmp(ext->def->module->name, "ietf-yang-schema-mount") ||
931 strcmp(ext->def->name, "mount-point")) {
932 return LY_EINVAL;
933 }
934
935 /* get operational data with ietf-yang-library and ietf-yang-schema-mount data */
936 if ((res = lyplg_ext_get_data(ext->module->ctx, ext, (void **)&ext_data, &ext_data_free))) {
937 return res;
938 }
939
940 /* learn about this mount point */
941 if ((res = schema_mount_get_smount(ext, ext_data, &config, &shared))) {
942 goto out;
943 }
944
945 res = schema_mount_create_ctx(ext, ext_data, config, ctx);
946
947out:
948 if (ext_data_free) {
949 lyd_free_all(ext_data);
950 }
951 return res;
952}
953
Michal Vaskoddd76592022-01-17 13:34:48 +0100954/**
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100955 * @brief Plugin descriptions for the Yang Schema Mount extension.
956 *
957 * Note that external plugins are supposed to use:
958 *
959 * LYPLG_EXTENSIONS = {
960 */
961const struct lyplg_ext_record plugins_schema_mount[] = {
962 {
963 .module = "ietf-yang-schema-mount",
964 .revision = "2019-01-14",
965 .name = "mount-point",
966
Michal Vasko193dacd2022-10-13 08:43:05 +0200967 .plugin.id = "ly2 schema mount v1",
968 .plugin.parse = schema_mount_parse,
969 .plugin.compile = schema_mount_compile,
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100970 .plugin.sprinter = NULL,
Michal Vasko135719f2022-08-25 12:18:17 +0200971 .plugin.node = NULL,
Michal Vasko193dacd2022-10-13 08:43:05 +0200972 .plugin.snode = schema_mount_snode,
973 .plugin.validate = schema_mount_validate,
974 .plugin.pfree = NULL,
975 .plugin.cfree = schema_mount_cfree
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100976 },
977 {0} /* terminating zeroed item */
978};