summaryrefslogtreecommitdiffstats
path: root/lib/yang.c
diff options
context:
space:
mode:
authorChristian Hopps <chopps@labn.net>2024-01-06 10:45:29 +0100
committerChristian Hopps <chopps@labn.net>2024-01-07 16:17:30 +0100
commitcf67a7e26577b0dda276324b40a602ae084e504e (patch)
tree7019c29239c15d507736b2330ead23774d636481 /lib/yang.c
parentlib: fix clang SA warnings (diff)
downloadfrr-cf67a7e26577b0dda276324b40a602ae084e504e.tar.xz
frr-cf67a7e26577b0dda276324b40a602ae084e504e.zip
lib: mgmtd: implement full XPath 1.0 predicate functionality
Allow user to specify full YANG compatible XPath 1.0 predicates. This allows for trimming results of generic queries using functions and other non-key predicates from XPath 1.0 Signed-off-by: Christian Hopps <chopps@labn.net>
Diffstat (limited to 'lib/yang.c')
-rw-r--r--lib/yang.c105
1 files changed, 105 insertions, 0 deletions
diff --git a/lib/yang.c b/lib/yang.c
index 18d2ac58d..b2cc71b30 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -251,6 +251,38 @@ void yang_snode_get_path(const struct lysc_node *snode,
}
}
+LY_ERR yang_resolve_snode_xpath(struct ly_ctx *ly_ctx, const char *xpath,
+ struct lysc_node ***snodes, bool *simple)
+{
+ struct lysc_node *snode;
+ struct ly_set *set;
+ LY_ERR err;
+
+ /* lys_find_path will not resolve complex xpaths */
+ snode = (struct lysc_node *)lys_find_path(ly_ctx, NULL, xpath, 0);
+ if (snode) {
+ *darr_append(*snodes) = snode;
+ *simple = true;
+ return LY_SUCCESS;
+ }
+
+ /* Try again to catch complex query cases */
+ err = lys_find_xpath(ly_native_ctx, NULL, xpath, 0, &set);
+ if (err)
+ return err;
+ if (!set->count) {
+ ly_set_free(set, NULL);
+ return LY_ENOTFOUND;
+ }
+
+ *simple = false;
+ darr_ensure_i(*snodes, set->count - 1);
+ memcpy(*snodes, set->snodes, set->count * sizeof(set->snodes[0]));
+ ly_set_free(set, NULL);
+ return LY_SUCCESS;
+}
+
+
struct lysc_node *yang_find_snode(struct ly_ctx *ly_ctx, const char *xpath,
uint32_t options)
{
@@ -1019,3 +1051,76 @@ LY_ERR yang_lyd_new_list(struct lyd_node_inner *parent,
/*NOTREACHED*/
return LY_EINVAL;
}
+
+
+int yang_trim_tree(struct lyd_node *root, const char *xpath)
+{
+ enum nb_error ret = NB_OK;
+ LY_ERR err;
+#if 0
+ err = lyd_trim_xpath(&root, xpath, NULL);
+ if (err) {
+ flog_err_sys(EC_LIB_LIBYANG,
+ "cannot obtain specific result for xpath \"%s\"",
+ xpath);
+ return NB_ERR;
+ }
+ return NB_OK;
+#else
+ struct lyd_node *node;
+ struct lyd_node **remove = NULL;
+ struct ly_set *set = NULL;
+ uint32_t i;
+
+ err = lyd_find_xpath3(NULL, root, xpath, NULL, &set);
+ if (err) {
+ flog_err_sys(EC_LIB_LIBYANG,
+ "cannot obtain specific result for xpath \"%s\"",
+ xpath);
+ ret = NB_ERR;
+ goto done;
+ }
+ /*
+ * Mark keepers and sweep deleting non-keepers.
+ *
+ * NOTE: We assume the data-nodes have NULL priv pointers and use that
+ * for our mark.
+ */
+
+ /* Mark */
+ for (i = 0; i < set->count; i++) {
+ for (node = set->dnodes[i]; node; node = &node->parent->node) {
+ if (node->priv)
+ break;
+ if (node == set->dnodes[i])
+ node->priv = (void *)2;
+ else
+ node->priv = (void *)1;
+ }
+ }
+
+ darr_ensure_cap(remove, 128);
+ LYD_TREE_DFS_BEGIN (root, node) {
+ /*
+ * If this is a direct matching node then include it's subtree
+ * which won't be marked and would otherwise be removed.
+ */
+ if (node->priv == (void *)2)
+ LYD_TREE_DFS_continue = 1;
+ else if (!node->priv) {
+ LYD_TREE_DFS_continue = 1;
+ *darr_append(remove) = node;
+ }
+ LYD_TREE_DFS_END(root, node);
+ }
+ darr_foreach_i (remove, i)
+ lyd_free_tree(remove[i]);
+ darr_free(remove);
+
+done:
+ if (set)
+ ly_set_free(set, NULL);
+
+ return ret;
+#endif
+}