plugins exts UPDATE ext callback for data node validation

Fixes #1908
diff --git a/src/parser_common.c b/src/parser_common.c
index 3660b96..9a86ac1 100644
--- a/src/parser_common.c
+++ b/src/parser_common.c
@@ -58,6 +58,7 @@
     ly_set_erase(&lydctx->node_types, NULL);
     ly_set_erase(&lydctx->meta_types, NULL);
     ly_set_erase(&lydctx->node_when, NULL);
+    ly_set_erase(&lydctx->ext_node, free);
     ly_set_erase(&lydctx->ext_val, free);
 }
 
diff --git a/src/parser_internal.h b/src/parser_internal.h
index 8d1f24a..627836a 100644
--- a/src/parser_internal.h
+++ b/src/parser_internal.h
@@ -59,7 +59,8 @@
     struct ly_set node_when;       /**< set of nodes with "when" conditions */
     struct ly_set node_types;      /**< set of nodes validated with LY_EINCOMPLETE result */
     struct ly_set meta_types;      /**< set of metadata validated with LY_EINCOMPLETE result */
-    struct ly_set ext_val;         /**< set of first siblings parsed by extensions to validate */
+    struct ly_set ext_node;        /**< set of nodes with extension instances to validate */
+    struct ly_set ext_val;         /**< set of nested subtrees parsed by extensions to validate */
     struct lyd_node *op_node;      /**< if an RPC/action/notification is being parsed, store the pointer to it */
 
     /* callbacks */
@@ -85,6 +86,7 @@
     struct ly_set node_when;
     struct ly_set node_types;
     struct ly_set meta_types;
+    struct ly_set ext_node;
     struct ly_set ext_val;
     struct lyd_node *op_node;
 
@@ -107,6 +109,7 @@
     struct ly_set node_when;
     struct ly_set node_types;
     struct ly_set meta_types;
+    struct ly_set ext_node;
     struct ly_set ext_val;
     struct lyd_node *op_node;
 
@@ -135,6 +138,7 @@
     struct ly_set node_when;
     struct ly_set node_types;
     struct ly_set meta_types;
+    struct ly_set ext_node;
     struct ly_set ext_val;
     struct lyd_node *op_node;
 
@@ -153,6 +157,14 @@
 };
 
 /**
+ * @brief Parsed data node with extension instance to validate.
+ */
+struct lyd_ctx_ext_node {
+    struct lysc_ext_instance *ext;
+    struct lyd_node *node;
+};
+
+/**
  * @brief Common part to supplement the specific ::lyd_ctx_free_clb callbacks.
  */
 void lyd_ctx_free(struct lyd_ctx *ctx);
diff --git a/src/parser_json.c b/src/parser_json.c
index 4babe34..82275b6 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -1413,7 +1413,10 @@
         }
 
         /* add/correct flags */
-        lyd_parse_set_data_flags(*node, &(*node)->meta, (struct lyd_ctx *)lydctx, ext);
+        LY_CHECK_RET(lyd_parse_set_data_flags(*node, &(*node)->meta, (struct lyd_ctx *)lydctx, ext));
+
+        /* store for ext instance node validation, if needed */
+        LY_CHECK_RET(lyd_validate_node_ext(*node, &lydctx->ext_node));
     } else if (ret == LY_ENOT) {
         /* parse it again as an opaq node */
         ret = lydjson_parse_opaq(lydctx, name, name_len, prefix, prefix_len, parent, status, status, first_p, node);
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index db68205..fb7d3a1 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -989,7 +989,12 @@
     (*node)->meta = *meta;
     *meta = NULL;
 
+    /* insert into parent */
     lyb_insert_node(lybctx, parent, *node, first_p, parsed);
+
+    /* store for ext instance node validation, if needed */
+    (void)lyd_validate_node_ext(*node, &lybctx->ext_node);
+
     *node = NULL;
 }
 
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 4e19fd8..da43b40 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -841,9 +841,12 @@
     }
     assert(node);
 
-    /* add/correct flags */
     if (snode) {
+        /* add/correct flags */
         LY_CHECK_GOTO(ret = lyd_parse_set_data_flags(node, &meta, (struct lyd_ctx *)lydctx, ext), error);
+
+        /* store for ext instance node validation, if needed */
+        LY_CHECK_GOTO(ret = lyd_validate_node_ext(node, &lydctx->ext_node), error);
     }
 
     /* parser next */
diff --git a/src/plugins_exts.h b/src/plugins_exts.h
index 75dbf85..0e521ec 100644
--- a/src/plugins_exts.h
+++ b/src/plugins_exts.h
@@ -102,7 +102,7 @@
 /**
  * @brief Extensions API version
  */
-#define LYPLG_EXT_API_VERSION 4
+#define LYPLG_EXT_API_VERSION 5
 
 /**
  * @brief Macro to define plugin information in external plugins
@@ -161,6 +161,19 @@
 typedef void (*lyplg_ext_free_clb)(struct ly_ctx *ctx, struct lysc_ext_instance *ext);
 
 /**
+ * @brief Callback called for all data nodes connected to the extension instance.
+ *
+ * Can be used for additional data node validation. Is called only after the whole data tree is created and standard
+ * validation succeeds.
+ *
+ * @param[in] ext Compiled extension instance.
+ * @param[in] node Data node to process.
+ * @return LY_SUCCESS on success.
+ * @return LY_ERR on error.
+ */
+typedef LY_ERR (*lyplg_ext_data_node_clb)(struct lysc_ext_instance *ext, struct lyd_node *node);
+
+/**
  * @brief Callback for getting a schema node for a new YANG instance data described by an extension instance.
  * Needed only if the extension instance supports some nested standard YANG data.
  *
@@ -211,6 +224,8 @@
                                                  instance */
     lyplg_ext_free_clb free;                /**< free the extension-specific data created by its compilation */
 
+    lyplg_ext_data_node_clb node;           /**< callback to validate most relevant data instance for the extension
+                                                 instance */
     lyplg_ext_data_snode_clb snode;         /**< callback to get schema node for nested YANG data */
     lyplg_ext_data_validate_clb validate;   /**< callback to validate parsed data instances according to the extension
                                                  definition */
diff --git a/src/plugins_exts/metadata.c b/src/plugins_exts/metadata.c
index eebb434..8326f6b 100644
--- a/src/plugins_exts/metadata.c
+++ b/src/plugins_exts/metadata.c
@@ -163,6 +163,7 @@
         .plugin.compile = &annotation_compile,
         .plugin.sprinter = &annotation_schema_printer,
         .plugin.free = annotation_free,
+        .plugin.node = NULL,
         .plugin.snode = NULL,
         .plugin.validate = NULL
     },
diff --git a/src/plugins_exts/nacm.c b/src/plugins_exts/nacm.c
index 1a50ea3..a83e32b 100644
--- a/src/plugins_exts/nacm.c
+++ b/src/plugins_exts/nacm.c
@@ -161,6 +161,7 @@
         .plugin.compile = &nacm_compile,
         .plugin.sprinter = NULL,
         .plugin.free = NULL,
+        .plugin.node = NULL,
         .plugin.snode = NULL,
         .plugin.validate = NULL
     }, {
@@ -172,6 +173,7 @@
         .plugin.compile = &nacm_compile,
         .plugin.sprinter = NULL,
         .plugin.free = NULL,
+        .plugin.node = NULL,
         .plugin.snode = NULL,
         .plugin.validate = NULL
     }, {
@@ -183,6 +185,7 @@
         .plugin.compile = &nacm_compile,
         .plugin.sprinter = NULL,
         .plugin.free = NULL,
+        .plugin.node = NULL,
         .plugin.snode = NULL,
         .plugin.validate = NULL
     }, {
@@ -194,6 +197,7 @@
         .plugin.compile = &nacm_compile,
         .plugin.sprinter = NULL,
         .plugin.free = NULL,
+        .plugin.node = NULL,
         .plugin.snode = NULL,
         .plugin.validate = NULL
     },
diff --git a/src/plugins_exts/schema_mount.c b/src/plugins_exts/schema_mount.c
index 1cfea52..dce83dd 100644
--- a/src/plugins_exts/schema_mount.c
+++ b/src/plugins_exts/schema_mount.c
@@ -850,6 +850,7 @@
         .plugin.compile = &schema_mount_compile,
         .plugin.sprinter = NULL,
         .plugin.free = &schema_mount_free,
+        .plugin.node = NULL,
         .plugin.snode = &schema_mount_snode,
         .plugin.validate = &schema_mount_validate
     },
diff --git a/src/plugins_exts/yangdata.c b/src/plugins_exts/yangdata.c
index b2e6f62..38e4c16 100644
--- a/src/plugins_exts/yangdata.c
+++ b/src/plugins_exts/yangdata.c
@@ -171,9 +171,10 @@
         .name = "yang-data",
 
         .plugin.id = "libyang 2 - yang-data, version 1",
-        .plugin.compile = &yangdata_compile,
-        .plugin.sprinter = &yangdata_schema_printer,
+        .plugin.compile = yangdata_compile,
+        .plugin.sprinter = yangdata_schema_printer,
         .plugin.free = yangdata_free,
+        .plugin.node = NULL,
         .plugin.snode = NULL,
         .plugin.validate = NULL
     },
diff --git a/src/tree_data.c b/src/tree_data.c
index 0e8e4dc..a216317 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -143,7 +143,7 @@
     if (!(parse_opts & LYD_PARSE_ONLY)) {
         /* validate data */
         rc = lyd_validate(first_p, NULL, ctx, val_opts, 0, &lydctx->node_when, &lydctx->node_types, &lydctx->meta_types,
-                &lydctx->ext_val, NULL);
+                &lydctx->ext_node, &lydctx->ext_val, NULL);
         LY_CHECK_GOTO(rc, cleanup);
     }
 
diff --git a/src/tree_data_new.c b/src/tree_data_new.c
index ef99f3b..04fc32c 100644
--- a/src/tree_data_new.c
+++ b/src/tree_data_new.c
@@ -1711,7 +1711,7 @@
     }
 
     /* resolve when and remove any invalid defaults */
-    ret = lyd_validate_unres(&tree, NULL, 0, &node_when, LYXP_IGNORE_WHEN, NULL, NULL, NULL, 0, diff);
+    ret = lyd_validate_unres(&tree, NULL, 0, &node_when, LYXP_IGNORE_WHEN, NULL, NULL, NULL, NULL, 0, diff);
     LY_CHECK_GOTO(ret, cleanup);
 
 cleanup:
@@ -1781,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, 0, &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, NULL, 0, diff),
             cleanup);
 
     /* process nested nodes */
diff --git a/src/validation.c b/src/validation.c
index a0e7dfa..b95d0b2 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -264,8 +264,8 @@
 
 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)
+        uint32_t when_xp_opts, struct ly_set *node_types, struct ly_set *meta_types, struct ly_set *ext_node,
+        struct ly_set *ext_val, uint32_t val_opts, struct lyd_node **diff)
 {
     LY_ERR ret = LY_SUCCESS;
     uint32_t i;
@@ -287,6 +287,23 @@
         } while (i);
     }
 
+    if (ext_node && ext_node->count) {
+        /* validate data nodes with extension instances */
+        i = ext_node->count;
+        do {
+            --i;
+
+            struct lyd_ctx_ext_node *ext_n = ext_node->objs[i];
+
+            /* validate the node */
+            ret = ext_n->ext->def->plugin->node(ext_n->ext, ext_n->node);
+            LY_CHECK_RET(ret);
+
+            /* remove this item from the set */
+            ly_set_rm_index(ext_node, i, free);
+        } while (i);
+    }
+
     if (node_when) {
         /* evaluate all when conditions */
         uint32_t prev_count;
@@ -1466,6 +1483,29 @@
     return LY_SUCCESS;
 }
 
+LY_ERR
+lyd_validate_node_ext(struct lyd_node *node, struct ly_set *ext_node)
+{
+    struct lyd_ctx_ext_node *ext_n;
+    struct lysc_ext_instance *exts;
+    LY_ARRAY_COUNT_TYPE u;
+
+    /* try to find a relevant extension instance with node callback */
+    exts = node->schema->exts;
+    LY_ARRAY_FOR(exts, u) {
+        if (exts[u].def->plugin && exts[u].def->plugin->node) {
+            /* store for validation */
+            ext_n = malloc(sizeof *ext_n);
+            LY_CHECK_ERR_RET(!ext_n, LOGMEM(LYD_CTX(node)), LY_EMEM);
+            ext_n->ext = &exts[u];
+            ext_n->node = node;
+            LY_CHECK_RET(ly_set_add(ext_node, ext_n, 1, NULL));
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
 /**
  * @brief Validate the whole data subtree.
  *
@@ -1529,22 +1569,23 @@
 LY_ERR
 lyd_validate(struct lyd_node **tree, const struct lys_module *module, const struct ly_ctx *ctx, uint32_t val_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)
+        struct ly_set *ext_node_p, struct ly_set *ext_val_p, struct lyd_node **diff)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyd_node *first, *next, **first2, *iter;
     const struct lys_module *mod;
-    struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, ext_val = {0};
+    struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, ext_node = {0}, ext_val = {0};
     uint32_t i = 0;
 
     assert(tree && ctx);
-    assert((node_when_p && node_types_p && meta_types_p && ext_val_p) ||
-            (!node_when_p && !node_types_p && !meta_types_p && !ext_val_p));
+    assert((node_when_p && node_types_p && meta_types_p && ext_node_p && ext_val_p) ||
+            (!node_when_p && !node_types_p && !meta_types_p && !ext_node_p && !ext_val_p));
 
     if (!node_when_p) {
         node_when_p = &node_when;
         node_types_p = &node_types;
         meta_types_p = &meta_types;
+        ext_node_p = &ext_node;
         ext_val_p = &ext_val;
     }
 
@@ -1598,8 +1639,8 @@
         }
 
         /* finish incompletely validated terminal values/attributes and when conditions */
-        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);
+        ret = lyd_validate_unres(first2, mod, LYD_TYPE_DATA_YANG, node_when_p, 0, node_types_p, meta_types_p,
+                ext_node_p, ext_val_p, val_opts, diff);
         LY_CHECK_GOTO(ret, cleanup);
 
         /* perform final validation that assumes the data tree is final */
@@ -1611,6 +1652,7 @@
     ly_set_erase(&node_when, NULL);
     ly_set_erase(&node_types, NULL);
     ly_set_erase(&meta_types, NULL);
+    ly_set_erase(&ext_node, free);
     ly_set_erase(&ext_val, free);
     return ret;
 }
@@ -1627,7 +1669,7 @@
         *diff = NULL;
     }
 
-    return lyd_validate(tree, NULL, ctx, val_opts, 1, NULL, NULL, NULL, NULL, diff);
+    return lyd_validate(tree, NULL, ctx, val_opts, 1, NULL, NULL, NULL, NULL, NULL, diff);
 }
 
 LIBYANG_API_DEF LY_ERR
@@ -1639,7 +1681,8 @@
         *diff = NULL;
     }
 
-    return lyd_validate(tree, module, (*tree) ? LYD_CTX(*tree) : module->ctx, val_opts, 1, NULL, NULL, NULL, NULL, diff);
+    return lyd_validate(tree, module, (*tree) ? LYD_CTX(*tree) : module->ctx, val_opts, 1, NULL, NULL, NULL, NULL, NULL,
+            diff);
 }
 
 /**
@@ -1717,6 +1760,7 @@
  * @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.
  * @param[in] meta_types_p Set of unres metadata types, if NULL a local set is used.
+ * @param[in] ext_node_p Set of unres nodes with extensions to validate, if NULL a local set is used.
  * @param[in] ext_val_p Set of parsed extension data to validate, if NULL a local set is used.
  * @param[out] diff Optional diff with any changes made by the validation.
  * @return LY_SUCCESS on success.
@@ -1725,20 +1769,21 @@
 static LY_ERR
 _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)
+        struct ly_set *meta_types_p,  struct ly_set *ext_node_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, *op_sibling_before, *op_sibling_after, *child;
-    struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, ext_val = {0};
+    struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, ext_node = {0}, ext_val = {0};
 
     assert(op_tree && op_node);
-    assert((node_when_p && node_types_p && meta_types_p && ext_val_p) ||
-            (!node_when_p && !node_types_p && !meta_types_p && !ext_val_p));
+    assert((node_when_p && node_types_p && meta_types_p && ext_node_p && ext_val_p) ||
+            (!node_when_p && !node_types_p && !meta_types_p && !ext_node_p && !ext_val_p));
 
     if (!node_when_p) {
         node_when_p = &node_when;
         node_types_p = &node_types;
         meta_types_p = &meta_types;
+        ext_node_p = &ext_node;
         ext_val_p = &ext_val;
     }
 
@@ -1780,7 +1825,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, data_type, node_when_p, LYXP_IGNORE_WHEN,
-            node_types_p, meta_types_p, ext_val_p, 0, diff), cleanup);
+            node_types_p, meta_types_p, ext_node_p, ext_val_p, 0, diff), cleanup);
 
     /* perform final validation of the operation/notification */
     lyd_validate_obsolete(op_node);
@@ -1806,6 +1851,7 @@
     ly_set_erase(&node_when, NULL);
     ly_set_erase(&node_types, NULL);
     ly_set_erase(&meta_types, NULL);
+    ly_set_erase(&ext_node, free);
     ly_set_erase(&ext_val, free);
     return rc;
 }
@@ -1848,8 +1894,8 @@
             } 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);
+                rc = lyd_validate_unres((struct lyd_node **)&dep_tree, NULL, data_type, NULL, 0, NULL, NULL, NULL,
+                        &ext_val, 0, diff);
                 ly_set_erase(&ext_val, free);
                 return rc;
             }
@@ -1877,5 +1923,5 @@
     }
 
     /* validate */
-    return _lyd_validate_op(op_tree, op_node, dep_tree, data_type, 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, NULL, diff);
 }
diff --git a/src/validation.h b/src/validation.h
index 0fdd027..c9f5da0 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -3,7 +3,7 @@
  * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief Validation routines.
  *
- * Copyright (c) 2019 CESNET, z.s.p.o.
+ * Copyright (c) 2019 - 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.
@@ -51,6 +51,7 @@
  * @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
  * @param[in] meta_types Set with metadata with unresolved types, can be NULL.
+ * @param[in] ext_node Set with nodes with extensions to validate, can be NULL.
  * @param[in] ext_val Set with extension data to validate, can be NULL.
  * @param[in] val_opts Validation options, see @ref datavalidationoptions.
  * @param[in,out] diff Validation diff.
@@ -58,7 +59,7 @@
  */
 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);
+        struct ly_set *ext_node, 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.
@@ -75,6 +76,15 @@
         struct lyd_node **diff);
 
 /**
+ * @brief Validate data node with an extension instance, if any, by storing it in its unres set.
+ *
+ * @param[in] node Node to check for an extension instance with a node callback.
+ * @param[in,out] ext_node Set with data nodes to validate.
+ * @return LY_ERR value.
+ */
+LY_ERR lyd_validate_node_ext(struct lyd_node *node, struct ly_set *ext_node);
+
+/**
  * @brief Validate a data tree.
  *
  * @param[in,out] tree Data tree to validate, nodes may be autodeleted.
@@ -85,12 +95,13 @@
  * @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.
  * @param[in] meta_types_p Set of unres metadata types, if NULL a local set is used.
+ * @param[in] ext_node_p Set of unres nodes with extensions to validate, if NULL a local set is used.
  * @param[in] ext_val_p Set of unres extension data to validate, if NULL a local set is used.
  * @param[out] diff Generated validation diff, not generated if NULL.
  * @return LY_ERR value.
  */
 LY_ERR lyd_validate(struct lyd_node **tree, const struct lys_module *module, const struct ly_ctx *ctx, uint32_t val_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);
+        struct ly_set *ext_node_p, struct ly_set *ext_val_p, struct lyd_node **diff);
 
 #endif /* LY_VALIDATION_H_ */