diff options
| author | Christian Hopps <chopps@labn.net> | 2023-10-13 22:51:11 -0400 |
|---|---|---|
| committer | Christian Hopps <chopps@labn.net> | 2023-12-28 17:52:57 +0000 |
| commit | 408ee24e411714596115d15c831dc59b22dec9f8 (patch) | |
| tree | dc4a0a2aa61bfb608ce186fe92fa8e80ae2e8fc4 /lib/northbound.c | |
| parent | d58653a5ba004f1d55981e8a69bcbdb82b87d354 (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.c | 203 |
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; } |
