plugins exts FEATURE validation of operations
diff --git a/src/plugins_exts.h b/src/plugins_exts.h
index 747aa51..75dbf85 100644
--- a/src/plugins_exts.h
+++ b/src/plugins_exts.h
@@ -1,9 +1,10 @@
/**
* @file plugins_exts.h
* @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
* @brief libyang support for YANG extensions implementation.
*
- * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
+ * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
@@ -16,6 +17,7 @@
#define LY_PLUGINS_EXTS_H_
#include "log.h"
+#include "parser_data.h"
#include "plugins.h"
#include "tree_data.h"
#include "tree_edit.h"
@@ -100,7 +102,7 @@
/**
* @brief Extensions API version
*/
-#define LYPLG_EXT_API_VERSION 3
+#define LYPLG_EXT_API_VERSION 4
/**
* @brief Macro to define plugin information in external plugins
@@ -187,13 +189,16 @@
*
* @param[in] ext Compiled extension instance.
* @param[in] sibling First sibling with schema node returned by ::lyplg_ext_data_snode_clb.
+ * @param[in] dep_tree Tree to be used for validating references from the operation subtree, if operation.
+ * @param[in] data_type Validated data type, can be ::LYD_TYPE_DATA_YANG, ::LYD_TYPE_RPC_YANG, ::LYD_TYPE_NOTIF_YANG,
+ * or ::LYD_TYPE_REPLY_YANG.
* @param[in] val_opts Validation options, see @ref datavalidationoptions.
* @param[out] diff Optional diff with any changes made by the validation.
* @return LY_SUCCESS on success.
* @return LY_ERR on error.
*/
-typedef LY_ERR (*lyplg_ext_data_validate_clb)(struct lysc_ext_instance *ext, struct lyd_node *sibling, uint32_t val_opts,
- struct lyd_node **diff);
+typedef LY_ERR (*lyplg_ext_data_validate_clb)(struct lysc_ext_instance *ext, struct lyd_node *sibling,
+ const struct lyd_node *dep_tree, enum lyd_type data_type, uint32_t val_opts, struct lyd_node **diff);
/**
* @brief Extension plugin implementing various aspects of a YANG extension
diff --git a/src/plugins_exts/schema_mount.c b/src/plugins_exts/schema_mount.c
index f655e06..b823a8c 100644
--- a/src/plugins_exts/schema_mount.c
+++ b/src/plugins_exts/schema_mount.c
@@ -20,9 +20,11 @@
#include <stdlib.h>
#include <string.h>
+#include "common.h"
#include "dict.h"
#include "libyang.h"
#include "log.h"
+#include "parser_data.h"
#include "plugins_exts.h"
#include "plugins_types.h"
#include "tree_data.h"
@@ -604,13 +606,14 @@
LYD_VALUE_GET(&term->value, xp_val);
if ((ret = lyd_find_xpath4(ctx_node, ctx_node, lyxp_get_expr(xp_val->exp), xp_val->format, xp_val->prefix_data,
NULL, &par_set))) {
+ lyplg_ext_log(ext, LY_LLERR, ret, NULL, "Parent reference \"%s\" evaluation failed.", lyxp_get_expr(xp_val->exp));
goto cleanup;
}
for (j = 0; j < par_set->count; ++j) {
/* duplicate with parents in the context of the mounted data */
if ((ret = lyd_dup_single_to_ctx(par_set->dnodes[j], trg_ctx, NULL,
- LYD_DUP_RECURSIVE | LYD_DUP_WITH_PARENTS | LYD_DUP_WITH_FLAGS, &dup))) {
+ LYD_DUP_RECURSIVE | LYD_DUP_WITH_PARENTS | LYD_DUP_WITH_FLAGS | LYD_DUP_NO_EXT, &dup))) {
goto cleanup;
}
@@ -669,12 +672,13 @@
* @brief Validate callback for schema mount.
*/
static LY_ERR
-schema_mount_validate(struct lysc_ext_instance *ext, struct lyd_node *sibling, uint32_t val_opts, struct lyd_node **diff)
+schema_mount_validate(struct lysc_ext_instance *ext, struct lyd_node *sibling, const struct lyd_node *dep_tree,
+ enum lyd_type data_type, uint32_t val_opts, struct lyd_node **diff)
{
LY_ERR ret = LY_SUCCESS;
uint32_t old_log_opts, i;
struct ly_err_item *err;
- struct lyd_node *iter, *ext_data = NULL, *ref_first = NULL, *orig_parent = lyd_parent(sibling);
+ struct lyd_node *iter, *ext_data = NULL, *ref_first = NULL, *orig_parent = lyd_parent(sibling), *op_tree;
struct lyd_node *ext_diff = NULL, *diff_parent = NULL;
ly_bool ext_data_free = 0;
struct ly_set *ref_set = NULL;
@@ -703,6 +707,11 @@
goto cleanup;
}
+ if (data_type != LYD_TYPE_DATA_YANG) {
+ /* remember the operation data tree, it may be moved */
+ op_tree = sibling;
+ }
+
/* create accessible tree, remove LYD_EXT to not call this callback recursively */
lyd_unlink_siblings(sibling);
LY_LIST_FOR(sibling, iter) {
@@ -717,8 +726,15 @@
/* only store messages in the context, log as an extension */
old_log_opts = ly_log_options(LY_LOSTORE_LAST);
- /* validate all the data */
- ret = lyd_validate_all(&sibling, NULL, val_opts, diff ? &ext_diff : NULL);
+ if (data_type == LYD_TYPE_DATA_YANG) {
+ /* validate all the data */
+ ret = lyd_validate_all(&sibling, NULL, val_opts, diff ? &ext_diff : NULL);
+ } else {
+ /* validate the operation */
+ ret = lyd_validate_op(op_tree, dep_tree, data_type, diff ? &ext_diff : NULL);
+ }
+
+ /* restore logging */
ly_log_options(old_log_opts);
/* restore sibling tree */
diff --git a/src/tree_data_new.c b/src/tree_data_new.c
index 74f353d..148562f 100644
--- a/src/tree_data_new.c
+++ b/src/tree_data_new.c
@@ -1711,7 +1711,8 @@
}
/* resolve when and remove any invalid defaults */
- LY_CHECK_GOTO(ret = lyd_validate_unres(&tree, NULL, &node_when, LYXP_IGNORE_WHEN, NULL, NULL, NULL, 0, diff), cleanup);
+ ret = lyd_validate_unres(&tree, NULL, 0, &node_when, LYXP_IGNORE_WHEN, NULL, NULL, NULL, 0, diff);
+ LY_CHECK_GOTO(ret, cleanup);
cleanup:
ly_set_erase(&node_when, NULL);
@@ -1780,7 +1781,7 @@
LY_CHECK_GOTO(ret = lyd_new_implicit_r(NULL, tree, NULL, module, &node_when, NULL, implicit_options, diff), cleanup);
/* resolve when and remove any invalid defaults */
- LY_CHECK_GOTO(ret = lyd_validate_unres(tree, module, &node_when, LYXP_IGNORE_WHEN, NULL, NULL, NULL, 0, diff),
+ LY_CHECK_GOTO(ret = lyd_validate_unres(tree, module, 0, &node_when, LYXP_IGNORE_WHEN, NULL, NULL, NULL, 0, diff),
cleanup);
/* process nested nodes */
diff --git a/src/validation.c b/src/validation.c
index 269079a..3b0b51b 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -259,9 +259,9 @@
}
LY_ERR
-lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, struct ly_set *node_when, uint32_t when_xp_opts,
- struct ly_set *node_types, struct ly_set *meta_types, struct ly_set *ext_val, uint32_t val_opts,
- struct lyd_node **diff)
+lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, enum lyd_type data_type, struct ly_set *node_when,
+ uint32_t when_xp_opts, struct ly_set *node_types, struct ly_set *meta_types, struct ly_set *ext_val,
+ uint32_t val_opts, struct lyd_node **diff)
{
LY_ERR ret = LY_SUCCESS;
uint32_t i;
@@ -275,7 +275,7 @@
struct lyd_ctx_ext_val *ext_v = ext_val->objs[i];
/* validate extension data */
- ret = ext_v->ext->def->plugin->validate(ext_v->ext, ext_v->sibling, val_opts, diff);
+ ret = ext_v->ext->def->plugin->validate(ext_v->ext, ext_v->sibling, *tree, data_type, val_opts, diff);
LY_CHECK_RET(ret);
/* remove this item from the set */
@@ -1607,7 +1607,8 @@
}
/* finish incompletely validated terminal values/attributes and when conditions */
- ret = lyd_validate_unres(first2, mod, node_when_p, 0, node_types_p, meta_types_p, ext_val_p, val_opts, diff);
+ ret = lyd_validate_unres(first2, mod, LYD_TYPE_DATA_YANG, node_when_p, 0, node_types_p, meta_types_p, ext_val_p,
+ val_opts, diff);
LY_CHECK_GOTO(ret, cleanup);
/* perform final validation that assumes the data tree is final */
@@ -1720,6 +1721,7 @@
* @param[in] op_node Operation node itself.
* @param[in] dep_tree Tree to be used for validating references from the operation subtree.
* @param[in] int_opts Internal parser options.
+ * @param[in] data_type Type of validated data.
* @param[in] validate_subtree Whether subtree was already validated (as part of data parsing) or not (separate validation).
* @param[in] node_when_p Set of nodes with when conditions, if NULL a local set is used.
* @param[in] node_types_p Set of unres node types, if NULL a local set is used.
@@ -1730,12 +1732,12 @@
* @return LY_ERR error on error.
*/
static LY_ERR
-_lyd_validate_op(struct lyd_node *op_tree, struct lyd_node *op_node, const struct lyd_node *dep_tree,
+_lyd_validate_op(struct lyd_node *op_tree, struct lyd_node *op_node, const struct lyd_node *dep_tree, enum lyd_type data_type,
uint32_t int_opts, ly_bool validate_subtree, struct ly_set *node_when_p, struct ly_set *node_types_p,
struct ly_set *meta_types_p, struct ly_set *ext_val_p, struct lyd_node **diff)
{
LY_ERR rc = LY_SUCCESS;
- struct lyd_node *tree_sibling, *tree_parent, *op_subtree, *op_parent, *child;
+ struct lyd_node *tree_sibling, *tree_parent, *op_subtree, *op_parent, *op_sibling_before, *op_sibling_after, *child;
struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, ext_val = {0};
assert(op_tree && op_node);
@@ -1783,7 +1785,7 @@
/* finish incompletely validated terminal values/attributes and when conditions on the full tree,
* account for unresolved 'when' that may appear in the non-validated dependency data tree */
- LY_CHECK_GOTO(rc = lyd_validate_unres((struct lyd_node **)&dep_tree, NULL, node_when_p, LYXP_IGNORE_WHEN,
+ LY_CHECK_GOTO(rc = lyd_validate_unres((struct lyd_node **)&dep_tree, NULL, data_type, node_when_p, LYXP_IGNORE_WHEN,
node_types_p, meta_types_p, ext_val_p, 0, diff), cleanup);
/* perform final validation of the operation/notification */
@@ -1814,10 +1816,11 @@
{
struct lyd_node *op_node;
uint32_t int_opts;
+ struct ly_set ext_val = {0};
+ LY_ERR rc;
LY_CHECK_ARG_RET(NULL, op_tree, !dep_tree || !dep_tree->parent, (data_type == LYD_TYPE_RPC_YANG) ||
(data_type == LYD_TYPE_NOTIF_YANG) || (data_type == LYD_TYPE_REPLY_YANG), LY_EINVAL);
- LY_CHECK_CTX_EQUAL_RET(LYD_CTX(op_tree), dep_tree ? LYD_CTX(dep_tree) : NULL, LY_EINVAL);
if (diff) {
*diff = NULL;
}
@@ -1843,6 +1846,13 @@
LYD_TREE_DFS_BEGIN(op_tree, op_node) {
if (!op_node->schema) {
return lyd_parse_opaq_error(op_node);
+ } else if (op_node->flags & LYD_EXT) {
+ /* fully validate the rest using the extension instance callback */
+ LY_CHECK_RET(lyd_validate_nested_ext(op_node, &ext_val));
+ rc = lyd_validate_unres((struct lyd_node **)&dep_tree, NULL, data_type, NULL, 0, NULL, NULL, &ext_val,
+ 0, diff);
+ ly_set_erase(&ext_val, free);
+ return rc;
}
if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_REPLY)) &&
@@ -1868,5 +1878,5 @@
}
/* validate */
- return _lyd_validate_op(op_tree, op_node, dep_tree, int_opts, 1, NULL, NULL, NULL, NULL, diff);
+ return _lyd_validate_op(op_tree, op_node, dep_tree, data_type, int_opts, 1, NULL, NULL, NULL, NULL, diff);
}
diff --git a/src/validation.h b/src/validation.h
index abf7332..0fdd027 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -19,6 +19,7 @@
#include "diff.h"
#include "log.h"
+#include "parser_data.h"
struct ly_ctx;
struct ly_set;
@@ -45,6 +46,7 @@
* @param[in] mod Module of the @p tree to take into consideration when deleting @p tree and moving it.
* If set, it is expected @p tree should point to the first node of @p mod. Otherwise it will simply be
* the first top-level sibling.
+ * @param[in] data_type Validate data type.
* @param[in] node_when Set with nodes with "when" conditions, can be NULL.
* @param[in] when_xp_opts Additional XPath options to use for evaluating "when".
* @param[in] node_types Set with nodes with unresolved types, can be NULL
@@ -54,9 +56,9 @@
* @param[in,out] diff Validation diff.
* @return LY_ERR value.
*/
-LY_ERR lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, struct ly_set *node_when,
- uint32_t when_xp_opts, struct ly_set *node_types, struct ly_set *meta_types, struct ly_set *ext_val,
- uint32_t val_opts, struct lyd_node **diff);
+LY_ERR lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, enum lyd_type data_type,
+ struct ly_set *node_when, uint32_t when_xp_opts, struct ly_set *node_types, struct ly_set *meta_types,
+ struct ly_set *ext_val, uint32_t val_opts, struct lyd_node **diff);
/**
* @brief Validate new siblings. Specifically, check duplicated instances, autodelete default values and cases.