char *errmsg, size_t errmsg_len);
static void nb_transaction_apply_finish(struct nb_transaction *transaction,
char *errmsg, size_t errmsg_len);
-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 lyd_node *pdnode);
static int nb_node_check_config_only(const struct lysc_node *snode, void *arg)
{
}
}
-static int nb_oper_data_iter_children(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 lyd_node *pdnode)
-{
- const struct lysc_node *child;
-
- LY_LIST_FOR (lysc_node_child(snode), child) {
- int ret;
-
- ret = nb_oper_data_iter_node(child, xpath, list_entry,
- list_keys, translator, false,
- flags, cb, arg, pdnode);
- if (ret != NB_OK)
- return ret;
- }
-
- return NB_OK;
-}
-
-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,
- struct lyd_node *pdnode)
-{
- const struct lysc_node *snode = nb_node->snode;
- struct yang_data *data;
- LY_ERR err = LY_SUCCESS;
-
-
- if (CHECK_FLAG(snode->flags, LYS_CONFIG_W))
- return NB_OK;
-
- /* Ignore list keys. */
- if (lysc_is_key(snode))
- return NB_OK;
-
- data = nb_callback_get_elem(nb_node, xpath, list_entry);
- if (data == NULL)
- /* Leaf of type "empty" is not present. */
- return NB_OK;
-
- /*
- * 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, 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, 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;
-
- if (!first) {
- err = lyd_new_inner(pdnode, snode->module, snode->name,
- false, &cnode);
- if (err)
- return NB_ERR_RESOURCE;
- }
-
- if (cb) {
- ret = (*cb)(snode, translator, data, arg);
- if (ret != NB_OK)
- return ret;
- }
- }
-
- 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. */
- 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
-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,
- struct lyd_node *pdnode)
-{
- const struct lysc_node *snode = nb_node->snode;
- const void *list_entry = NULL;
- LY_ERR err;
-
- if (CHECK_FLAG(snode->flags, LYS_CONFIG_W))
- return NB_OK;
-
- do {
- struct yang_data *data;
- int ret;
-
- list_entry = nb_callback_get_next(nb_node, parent_list_entry,
- list_entry);
- if (!list_entry)
- /* End of the list. */
- break;
-
- data = nb_callback_get_elem(nb_node, xpath, list_entry);
- if (data == NULL)
- continue;
-
- /*
- * 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;
-}
-
-static int nb_oper_data_iter_list(const struct nb_node *nb_node,
- const char *xpath_list,
- 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,
- 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;
-
- /* Iterate over all list entries. */
- do {
- struct yang_list_keys list_keys = {};
- int len, ret;
-
- /* Obtain list entry. */
- list_entry = nb_callback_get_next(nb_node, parent_list_entry,
- list_entry);
- if (!list_entry)
- /* End of the list. */
- break;
-
- if (!CHECK_FLAG(nb_node->flags, F_NB_NODE_KEYLESS_LIST)) {
- /* Obtain the list entry keys. */
- if (nb_callback_get_keys(nb_node, list_entry,
- &list_keys)
- != NB_OK) {
- flog_warn(EC_LIB_NB_CB_STATE,
- "%s: failed to get list keys",
- __func__);
- return NB_ERR;
- }
-
- /* Build XPath of the list entry. */
- strlcpy(xpath, xpath_list, sizeof(xpath));
- len = strlen(xpath);
- key_preds = &xpath[len];
-
- uint n = yang_get_key_preds(xpath + len, snode,
- &list_keys,
- sizeof(xpath) - len);
- assert(n == list_keys.num);
-
- } else {
- /*
- * Keyless list - build XPath using a positional index.
- */
- snprintf(xpath, sizeof(xpath), "%s[%u]", xpath_list,
- position);
- 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, list_node);
- if (ret != NB_OK)
- return ret;
- } while (list_entry);
-
- return NB_OK;
-}
-
-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 lyd_node *pdnode)
-{
- struct nb_node *nb_node;
- char xpath[XPATH_MAXLEN];
- int ret = NB_OK;
-
- if (!first && CHECK_FLAG(flags, NB_OPER_DATA_ITER_NORECURSE)
- && 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) {
- struct lysc_node *parent;
-
- /* Get the real parent. */
- parent = snode->parent;
-
- /*
- * When necessary, include the namespace of the augmenting
- * module.
- */
- if (parent && parent->module != snode->module)
- snprintf(xpath + strlen(xpath),
- sizeof(xpath) - strlen(xpath), "/%s:%s",
- snode->module->name, snode->name);
- else
- snprintf(xpath + strlen(xpath),
- sizeof(xpath) - strlen(xpath), "/%s",
- snode->name);
- }
-
- nb_node = snode->priv;
- switch (snode->nodetype) {
- case LYS_CONTAINER:
- /* does something, then walks children */
- ret = nb_oper_data_iter_container(nb_node, xpath, first,
- list_entry, list_keys,
- translator, flags, cb, arg,
- pdnode);
-
- break;
- case LYS_LEAF:
- /* does something then returns */
- ret = nb_oper_data_iter_leaf(nb_node, xpath, list_entry,
- list_keys, translator, flags, cb,
- arg, pdnode);
- break;
- case LYS_LEAFLIST:
- /* walks leaf list doing things and returns */
- ret = nb_oper_data_iter_leaflist(nb_node, xpath, list_entry,
- list_keys, translator, flags,
- cb, arg, pdnode);
- break;
- case LYS_LIST:
- /* walks children */
- ret = nb_oper_data_iter_list(nb_node, xpath, list_entry,
- list_keys, translator, flags, cb,
- arg, pdnode);
- break;
- case LYS_USES:
- /* walks children */
- ret = nb_oper_data_iter_children(snode, xpath, list_entry,
- list_keys, translator, false,
- flags, cb, arg, pdnode);
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-static int nb_xpath_dirname(char *xpath)
-{
- int len = strlen(xpath);
- bool abs = xpath[0] == '/';
- char *slash;
-
- /* "//" or "/" => NULL */
- if (abs && (len == 1 || (len == 2 && xpath[1] == '/')))
- return NB_ERR_NOT_FOUND;
- slash = (char *)frrstr_back_to_char(xpath, '/');
- /* "/foo/bar/" or "/foo/bar//" => "/foo " */
- if (slash && slash == &xpath[len - 1]) {
- xpath[--len] = 0;
- slash = (char *)frrstr_back_to_char(xpath, '/');
- if (slash && slash == &xpath[len - 1]) {
- xpath[--len] = 0;
- slash = (char *)frrstr_back_to_char(xpath, '/');
- }
- }
- if (!slash)
- return NB_ERR_NOT_FOUND;
- *slash = 0;
- return NB_OK;
-}
-
-static int nb_oper_data_xpath_to_tree(const char *xpath_in,
- struct lyd_node **dnode,
- bool is_top_node_list)
-{
- /* Eventually this function will loop until it finds a concrete path */
- char *xpath;
- LY_ERR err;
- int ret;
-
- err = lyd_new_path2(NULL, ly_native_ctx, xpath_in, NULL, 0, 0,
- LYD_NEW_PATH_UPDATE, NULL, dnode);
- if (err == LY_SUCCESS)
- return NB_OK;
- if (!is_top_node_list)
- return NB_ERR_NOT_FOUND;
-
- xpath = XSTRDUP(MTYPE_TMP, xpath_in);
- ret = nb_xpath_dirname(xpath);
- if (ret != NB_OK)
- goto done;
-
- err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0, 0,
- LYD_NEW_PATH_UPDATE, NULL, dnode);
- if (err != LY_SUCCESS)
- ret = NB_ERR_NOT_FOUND;
-done:
- XFREE(MTYPE_TMP, xpath);
- return ret;
-}
-
-int nb_oper_data_iterate(const char *xpath, struct yang_translator *translator,
- uint32_t flags, nb_oper_data_cb cb, void *arg,
- struct lyd_node **tree)
-{
- struct nb_node *nb_node;
- const void *list_entry = NULL;
- struct yang_list_keys list_keys;
- struct list *list_dnodes;
- struct lyd_node *dnode, *dn;
- struct listnode *ln;
- int ret;
-
- nb_node = nb_node_find(xpath);
- if (!nb_node) {
- flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH,
- "%s: unknown data path: %s", __func__, xpath);
- return NB_ERR;
- }
-
- /* For now this function works only with containers and lists. */
- if (!CHECK_FLAG(nb_node->snode->nodetype, LYS_CONTAINER | LYS_LIST)) {
- flog_warn(
- EC_LIB_NB_OPERATIONAL_DATA,
- "%s: can't iterate over YANG leaf or leaf-list [xpath %s]",
- __func__, xpath);
- return NB_ERR;
- }
-
- /*
- * Create a data tree from the XPath so that we can parse the keys of
- * all YANG lists (if any).
- */
-
- ret = nb_oper_data_xpath_to_tree(xpath, &dnode,
- nb_node->snode->nodetype == LYS_LIST);
- if (ret) {
- flog_warn(EC_LIB_LIBYANG,
- "%s: can't instantiate concrete path using xpath: %s",
- __func__, xpath);
- return ret;
- }
- assert(dnode);
-
- /*
- * Create a linked list to sort the data nodes starting from the root.
- */
- list_dnodes = list_new();
- for (dn = dnode; dn; dn = lyd_parent(dn))
- if (dn->schema->nodetype == LYS_LIST)
- listnode_add_head(list_dnodes, dn);
-
- /*
- * Use the northbound callbacks to find list entry pointer corresponding
- * to the given XPath.
- */
- for (ALL_LIST_ELEMENTS_RO(list_dnodes, ln, dn)) {
- struct lyd_node *child;
- struct nb_node *nn;
- unsigned int n = 0;
-
- /* Obtain the list entry keys. */
- memset(&list_keys, 0, sizeof(list_keys));
- LY_LIST_FOR (lyd_child(dn), child) {
- if (!lysc_is_key(child->schema))
- break;
- strlcpy(list_keys.key[n],
- yang_dnode_get_string(child, NULL),
- sizeof(list_keys.key[n]));
- n++;
- }
- list_keys.num = n;
- if (list_keys.num != yang_snode_num_keys(dn->schema)) {
- flog_warn(
- EC_LIB_NB_OPERATIONAL_DATA,
- "%s: internal list entry '%s' missing required key values predicates in xpath: %s",
- __func__, dn->schema->name, xpath);
- list_delete(&list_dnodes);
- yang_dnode_free(dnode);
- return NB_ERR_NOT_FOUND;
- }
-
- /* Find the list entry pointer. */
- nn = dn->schema->priv;
- if (!nn->cbs.lookup_entry) {
- flog_warn(
- EC_LIB_NB_OPERATIONAL_DATA,
- "%s: data path doesn't support iteration over operational data: %s",
- __func__, xpath);
- list_delete(&list_dnodes);
- yang_dnode_free(dnode);
- return NB_ERR;
- }
-
- /* NOTE: To add support for multiple levels of unspecified keys
- * we need to loop here using the list entry's get_next to work
- * with each "existing in the data" list entry. It will be a bit
- * tricky b/c we are inside a loop here.
- */
- list_entry =
- nb_callback_lookup_entry(nn, list_entry, &list_keys);
- if (list_entry == NULL) {
- list_delete(&list_dnodes);
- yang_dnode_free(dnode);
- return NB_ERR_NOT_FOUND;
- }
- }
-
- /* If a list entry was given with keys as the last node in the path,
- * iterate over that list entry only.
- */
- 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, dnode);
- else
- ret = nb_oper_data_iter_node(nb_node->snode, xpath, list_entry,
- &list_keys, translator, true,
- flags, cb, arg, dnode);
-
- list_delete(&list_dnodes);
- while (lyd_parent(dnode))
- dnode = lyd_parent(dnode);
-
- if (tree && ret == NB_OK)
- *tree = dnode;
- else {
- lyd_free_all(dnode);
- if (tree)
- *tree = NULL;
- }
-
- return ret;
-}
-
bool nb_operation_is_valid(enum nb_operation operation,
const struct lysc_node *snode)
{