summaryrefslogtreecommitdiff
path: root/lib/northbound.c
diff options
context:
space:
mode:
authorChristian Hopps <chopps@labn.net>2023-10-13 22:51:11 -0400
committerChristian Hopps <chopps@labn.net>2023-12-28 17:52:57 +0000
commit408ee24e411714596115d15c831dc59b22dec9f8 (patch)
treedc4a0a2aa61bfb608ce186fe92fa8e80ae2e8fc4 /lib/northbound.c
parentd58653a5ba004f1d55981e8a69bcbdb82b87d354 (diff)
lib: create and use libyang tree during oper-state walk
Signed-off-by: Christian Hopps <chopps@labn.net>
Diffstat (limited to 'lib/northbound.c')
-rw-r--r--lib/northbound.c203
1 files changed, 148 insertions, 55 deletions
diff --git a/lib/northbound.c b/lib/northbound.c
index e70d05cea9..d55255a046 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -73,9 +73,9 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction,
static int nb_oper_data_iter_node(const struct lysc_node *snode,
const char *xpath, const void *list_entry,
const struct yang_list_keys *list_keys,
- struct yang_translator *translator,
- bool first, uint32_t flags,
- nb_oper_data_cb cb, void *arg);
+ struct yang_translator *translator, bool first,
+ uint32_t flags, nb_oper_data_cb cb, void *arg,
+ struct lyd_node *pdnode);
static int nb_node_check_config_only(const struct lysc_node *snode, void *arg)
{
@@ -1772,7 +1772,8 @@ static int nb_oper_data_iter_children(const struct lysc_node *snode,
const struct yang_list_keys *list_keys,
struct yang_translator *translator,
bool first, uint32_t flags,
- nb_oper_data_cb cb, void *arg)
+ nb_oper_data_cb cb, void *arg,
+ struct lyd_node *pdnode)
{
const struct lysc_node *child;
@@ -1781,7 +1782,7 @@ static int nb_oper_data_iter_children(const struct lysc_node *snode,
ret = nb_oper_data_iter_node(child, xpath, list_entry,
list_keys, translator, false,
- flags, cb, arg);
+ flags, cb, arg, pdnode);
if (ret != NB_OK)
return ret;
}
@@ -1793,15 +1794,19 @@ static int nb_oper_data_iter_leaf(const struct nb_node *nb_node,
const char *xpath, const void *list_entry,
const struct yang_list_keys *list_keys,
struct yang_translator *translator,
- uint32_t flags, nb_oper_data_cb cb, void *arg)
+ uint32_t flags, nb_oper_data_cb cb, void *arg,
+ struct lyd_node *pdnode)
{
+ const struct lysc_node *snode = nb_node->snode;
struct yang_data *data;
+ LY_ERR err = LY_SUCCESS;
- if (CHECK_FLAG(nb_node->snode->flags, LYS_CONFIG_W))
+
+ if (CHECK_FLAG(snode->flags, LYS_CONFIG_W))
return NB_OK;
/* Ignore list keys. */
- if (lysc_is_key(nb_node->snode))
+ if (lysc_is_key(snode))
return NB_OK;
data = nb_callback_get_elem(nb_node, xpath, list_entry);
@@ -1809,50 +1814,89 @@ static int nb_oper_data_iter_leaf(const struct nb_node *nb_node,
/* Leaf of type "empty" is not present. */
return NB_OK;
- return (*cb)(nb_node->snode, translator, data, arg);
+ /*
+ * Add a dnode to our tree
+ */
+ err = lyd_new_term(pdnode, snode->module, snode->name, data->value,
+ false, NULL);
+ if (err)
+ return NB_ERR_RESOURCE;
+
+ if (cb)
+ return (*cb)(nb_node->snode, translator, data, arg);
+ return NB_OK;
}
static int nb_oper_data_iter_container(const struct nb_node *nb_node,
- const char *xpath,
+ const char *xpath, bool first,
const void *list_entry,
const struct yang_list_keys *list_keys,
struct yang_translator *translator,
uint32_t flags, nb_oper_data_cb cb,
- void *arg)
+ void *arg, struct lyd_node *pdnode)
{
const struct lysc_node *snode = nb_node->snode;
+ struct lyd_node *cnode = NULL;
+ bool presence = false;
+ LY_ERR err;
+ int ret;
if (CHECK_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY))
return NB_OK;
+ if (pdnode->schema == snode)
+ assert(first);
+ else
+ assert(!first);
+
/* Read-only presence containers. */
if (nb_node->cbs.get_elem) {
struct yang_data *data;
int ret;
+ presence = true;
data = nb_callback_get_elem(nb_node, xpath, list_entry);
if (data == NULL)
/* Presence container is not present. */
return NB_OK;
- ret = (*cb)(snode, translator, data, arg);
- if (ret != NB_OK)
- return ret;
- }
+ if (!first) {
+ err = lyd_new_inner(pdnode, snode->module, snode->name,
+ false, &cnode);
+ if (err)
+ return NB_ERR_RESOURCE;
+ }
- /* Read-write presence containers. */
- if (CHECK_FLAG(snode->flags, LYS_CONFIG_W)) {
- struct lysc_node_container *scontainer;
+ if (cb) {
+ ret = (*cb)(snode, translator, data, arg);
+ if (ret != NB_OK)
+ return ret;
+ }
+ }
- scontainer = (struct lysc_node_container *)snode;
- if (CHECK_FLAG(scontainer->flags, LYS_PRESENCE)
- && !yang_dnode_get(running_config->dnode, xpath))
- return NB_OK;
+ if (first)
+ cnode = pdnode;
+ else if (!cnode) {
+ /* Add a node in for this container in-case we have children. */
+ err = lyd_new_inner(pdnode, snode->module, snode->name, false,
+ &cnode);
+ if (err)
+ return NB_ERR_RESOURCE;
}
/* Iterate over the child nodes. */
- return nb_oper_data_iter_children(snode, xpath, list_entry, list_keys,
- translator, false, flags, cb, arg);
+ ret = nb_oper_data_iter_children(snode, xpath, list_entry, list_keys,
+ translator, false, flags, cb, arg,
+ cnode);
+
+ /* TODO: here we are freeing only if we created; however, we may want to
+ * also free if pdnode was cnode on entry to cleanup the data tree
+ */
+ /* If we aren't presence container and we gained no children remove */
+ if (!presence && !first && !lyd_child(cnode))
+ lyd_free_tree(cnode);
+
+ return ret;
}
static int
@@ -1860,11 +1904,14 @@ nb_oper_data_iter_leaflist(const struct nb_node *nb_node, const char *xpath,
const void *parent_list_entry,
const struct yang_list_keys *parent_list_keys,
struct yang_translator *translator, uint32_t flags,
- nb_oper_data_cb cb, void *arg)
+ nb_oper_data_cb cb, void *arg,
+ struct lyd_node *pdnode)
{
+ const struct lysc_node *snode = nb_node->snode;
const void *list_entry = NULL;
+ LY_ERR err;
- if (CHECK_FLAG(nb_node->snode->flags, LYS_CONFIG_W))
+ if (CHECK_FLAG(snode->flags, LYS_CONFIG_W))
return NB_OK;
do {
@@ -1881,9 +1928,19 @@ nb_oper_data_iter_leaflist(const struct nb_node *nb_node, const char *xpath,
if (data == NULL)
continue;
- ret = (*cb)(nb_node->snode, translator, data, arg);
- if (ret != NB_OK)
- return ret;
+ /*
+ * Add a dnode to our tree
+ */
+ err = lyd_new_term(pdnode, snode->module, snode->name,
+ data->value, false, NULL);
+ if (err)
+ return NB_ERR_RESOURCE;
+
+ if (cb) {
+ ret = (*cb)(nb_node->snode, translator, data, arg);
+ if (ret != NB_OK)
+ return ret;
+ }
} while (list_entry);
return NB_OK;
@@ -1894,11 +1951,16 @@ static int nb_oper_data_iter_list(const struct nb_node *nb_node,
const void *parent_list_entry,
const struct yang_list_keys *parent_list_keys,
struct yang_translator *translator,
- uint32_t flags, nb_oper_data_cb cb, void *arg)
+ uint32_t flags, nb_oper_data_cb cb, void *arg,
+ struct lyd_node *pdnode)
{
+ char xpath[XPATH_MAXLEN * 2];
const struct lysc_node *snode = nb_node->snode;
const void *list_entry = NULL;
+ struct lyd_node *list_node = NULL;
+ const char *key_preds = NULL;
uint32_t position = 1;
+ LY_ERR err;
if (CHECK_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY))
return NB_OK;
@@ -1907,8 +1969,7 @@ static int nb_oper_data_iter_list(const struct nb_node *nb_node,
do {
const struct lysc_node_leaf *skey;
struct yang_list_keys list_keys = {};
- char xpath[XPATH_MAXLEN * 2];
- int ret;
+ int len, len2, ret;
/* Obtain list entry. */
list_entry = nb_callback_get_next(nb_node, parent_list_entry,
@@ -1930,16 +1991,23 @@ static int nb_oper_data_iter_list(const struct nb_node *nb_node,
/* Build XPath of the list entry. */
strlcpy(xpath, xpath_list, sizeof(xpath));
+ len = strlen(xpath);
+ key_preds = &xpath[len];
+
unsigned int i = 0;
LY_FOR_KEYS (snode, skey) {
assert(i < list_keys.num);
- snprintf(xpath + strlen(xpath),
- sizeof(xpath) - strlen(xpath),
- "[%s='%s']", skey->name,
- list_keys.key[i]);
+ len2 = snprintf(xpath + len, sizeof(xpath) - len,
+ "[%s='%s']", skey->name,
+ list_keys.key[i]);
+ if (len2 > (ssize_t)sizeof(xpath) - len)
+ len = sizeof(xpath);
+ else
+ len += len2;
i++;
}
assert(i == list_keys.num);
+
} else {
/*
* Keyless list - build XPath using a positional index.
@@ -1949,10 +2017,20 @@ static int nb_oper_data_iter_list(const struct nb_node *nb_node,
position++;
}
+ /*
+ * `pdnode` needs to point at lib - and it does for
+ * "/frr-vrf:lib/vrf" need to test "/frr-vrf:lib" too though
+ */
+ err = lyd_new_list2(pdnode, snode->module, snode->name,
+ key_preds, false, &list_node);
+ if (err)
+ return NB_ERR_RESOURCE;
+
/* Iterate over the child nodes. */
- ret = nb_oper_data_iter_children(
- nb_node->snode, xpath, list_entry, &list_keys,
- translator, false, flags, cb, arg);
+ ret = nb_oper_data_iter_children(nb_node->snode, xpath,
+ list_entry, &list_keys,
+ translator, false, flags, cb,
+ arg, list_node);
if (ret != NB_OK)
return ret;
} while (list_entry);
@@ -1964,9 +2042,9 @@ static int nb_oper_data_iter_node(const struct lysc_node *snode,
const char *xpath_parent,
const void *list_entry,
const struct yang_list_keys *list_keys,
- struct yang_translator *translator,
- bool first, uint32_t flags,
- nb_oper_data_cb cb, void *arg)
+ struct yang_translator *translator, bool first,
+ uint32_t flags, nb_oper_data_cb cb, void *arg,
+ struct lyd_node *pdnode)
{
struct nb_node *nb_node;
char xpath[XPATH_MAXLEN];
@@ -1976,6 +2054,10 @@ static int nb_oper_data_iter_node(const struct lysc_node *snode,
&& CHECK_FLAG(snode->nodetype, LYS_CONTAINER | LYS_LIST))
return NB_OK;
+ /*
+ * would be nice to just be building a libyang data tree here as well
+ */
+
/* Update XPath. */
strlcpy(xpath, xpath_parent, sizeof(xpath));
if (!first && snode->nodetype != LYS_USES) {
@@ -2001,29 +2083,31 @@ static int nb_oper_data_iter_node(const struct lysc_node *snode,
nb_node = snode->priv;
switch (snode->nodetype) {
case LYS_CONTAINER:
- ret = nb_oper_data_iter_container(nb_node, xpath, list_entry,
- list_keys, translator, flags,
- cb, arg);
+ ret = nb_oper_data_iter_container(nb_node, xpath, first,
+ list_entry, list_keys,
+ translator, flags, cb, arg,
+ pdnode);
+
break;
case LYS_LEAF:
ret = nb_oper_data_iter_leaf(nb_node, xpath, list_entry,
list_keys, translator, flags, cb,
- arg);
+ arg, pdnode);
break;
case LYS_LEAFLIST:
ret = nb_oper_data_iter_leaflist(nb_node, xpath, list_entry,
list_keys, translator, flags,
- cb, arg);
+ cb, arg, pdnode);
break;
case LYS_LIST:
ret = nb_oper_data_iter_list(nb_node, xpath, list_entry,
list_keys, translator, flags, cb,
- arg);
+ arg, pdnode);
break;
case LYS_USES:
ret = nb_oper_data_iter_children(snode, xpath, list_entry,
list_keys, translator, false,
- flags, cb, arg);
+ flags, cb, arg, pdnode);
break;
default:
break;
@@ -2089,7 +2173,8 @@ done:
int nb_oper_data_iterate(const char *xpath, struct yang_translator *translator,
- uint32_t flags, nb_oper_data_cb cb, void *arg)
+ uint32_t flags, nb_oper_data_cb cb, void *arg,
+ struct lyd_node **tree)
{
struct nb_node *nb_node;
const void *list_entry = NULL;
@@ -2198,16 +2283,24 @@ int nb_oper_data_iterate(const char *xpath, struct yang_translator *translator,
*/
if (dnode->schema->nodetype == LYS_LIST && lyd_child(dnode)
&& dnode->schema == nb_node->snode)
- ret = nb_oper_data_iter_children(
- nb_node->snode, xpath, list_entry, &list_keys,
- translator, true, flags, cb, arg);
+ ret = nb_oper_data_iter_children(nb_node->snode, xpath,
+ list_entry, &list_keys,
+ translator, true, flags, cb,
+ arg, dnode);
else
ret = nb_oper_data_iter_node(nb_node->snode, xpath, list_entry,
&list_keys, translator, true,
- flags, cb, arg);
+ flags, cb, arg, dnode);
list_delete(&list_dnodes);
- yang_dnode_free(dnode);
+ if (dnode) {
+ while (lyd_parent(dnode))
+ dnode = lyd_parent(dnode);
+ if (!tree)
+ lyd_free_all(dnode);
+ else
+ *tree = dnode;
+ }
return ret;
}