diff options
Diffstat (limited to 'lib/northbound.c')
| -rw-r--r-- | lib/northbound.c | 436 |
1 files changed, 51 insertions, 385 deletions
diff --git a/lib/northbound.c b/lib/northbound.c index 32988dfc15..18d65e47f1 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -70,12 +70,6 @@ static int nb_transaction_process(enum nb_event event, 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); static int nb_node_check_config_only(const struct lysc_node *snode, void *arg) { @@ -1465,6 +1459,50 @@ const void *nb_callback_lookup_entry(const struct nb_node *nb_node, return nb_node->cbs.lookup_entry(&args); } +const void *nb_callback_lookup_node_entry(struct lyd_node *node, + const void *parent_list_entry) +{ + struct yang_list_keys keys; + struct nb_cb_lookup_entry_args args = {}; + const struct nb_node *nb_node = node->schema->priv; + + if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS)) + return NULL; + + if (yang_get_node_keys(node, &keys)) { + flog_warn(EC_LIB_LIBYANG, + "%s: can't get keys for lookup from existing data node %s", + __func__, node->schema->name); + return NULL; + } + + DEBUGD(&nb_dbg_cbs_state, + "northbound callback (lookup_node_entry): node [%s] parent_list_entry [%p]", + nb_node->xpath, parent_list_entry); + + args.parent_list_entry = parent_list_entry; + args.keys = &keys; + return nb_node->cbs.lookup_entry(&args); +} + +const void *nb_callback_lookup_next(const struct nb_node *nb_node, + const void *parent_list_entry, + const struct yang_list_keys *keys) +{ + struct nb_cb_lookup_entry_args args = {}; + + if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS)) + return NULL; + + DEBUGD(&nb_dbg_cbs_state, + "northbound callback (lookup_entry): node [%s] parent_list_entry [%p]", + nb_node->xpath, parent_list_entry); + + args.parent_list_entry = parent_list_entry; + args.keys = keys; + return nb_node->cbs.lookup_next(&args); +} + int nb_callback_rpc(const struct nb_node *nb_node, const char *xpath, const struct list *input, struct list *output, char *errmsg, size_t errmsg_len) @@ -1767,385 +1805,6 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction, } } -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) -{ - 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); - 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 yang_data *data; - - if (CHECK_FLAG(nb_node->snode->flags, LYS_CONFIG_W)) - return NB_OK; - - /* Ignore list keys. */ - if (lysc_is_key(nb_node->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; - - return (*cb)(nb_node->snode, translator, data, arg); -} - -static int nb_oper_data_iter_container(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) -{ - const struct lysc_node *snode = nb_node->snode; - - if (CHECK_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY)) - return NB_OK; - - /* Read-only presence containers. */ - if (nb_node->cbs.get_elem) { - struct yang_data *data; - int ret; - - 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; - } - - /* Read-write presence containers. */ - if (CHECK_FLAG(snode->flags, LYS_CONFIG_W)) { - struct lysc_node_container *scontainer; - - scontainer = (struct lysc_node_container *)snode; - if (CHECK_FLAG(scontainer->flags, LYS_PRESENCE) - && !yang_dnode_get(running_config->dnode, xpath)) - return NB_OK; - } - - /* Iterate over the child nodes. */ - return nb_oper_data_iter_children(snode, xpath, list_entry, list_keys, - translator, false, flags, cb, arg); -} - -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) -{ - const void *list_entry = NULL; - - if (CHECK_FLAG(nb_node->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; - - 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) -{ - const struct lysc_node *snode = nb_node->snode; - const void *list_entry = NULL; - uint32_t position = 1; - - if (CHECK_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY)) - return NB_OK; - - /* Iterate over all list entries. */ - do { - const struct lysc_node_leaf *skey; - struct yang_list_keys list_keys = {}; - char xpath[XPATH_MAXLEN * 2]; - int 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)); - 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]); - i++; - } - assert(i == list_keys.num); - } else { - /* - * Keyless list - build XPath using a positional index. - */ - snprintf(xpath, sizeof(xpath), "%s[%u]", xpath_list, - position); - position++; - } - - /* Iterate over the child nodes. */ - ret = nb_oper_data_iter_children( - nb_node->snode, xpath, list_entry, &list_keys, - translator, false, flags, cb, arg); - if (ret != NB_OK) - return ret; - } while (list_entry); - - return NB_OK; -} - -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 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; - - /* 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: - ret = nb_oper_data_iter_container(nb_node, xpath, list_entry, - list_keys, translator, flags, - cb, arg); - break; - case LYS_LEAF: - ret = nb_oper_data_iter_leaf(nb_node, xpath, list_entry, - list_keys, translator, flags, cb, - arg); - break; - case LYS_LEAFLIST: - ret = nb_oper_data_iter_leaflist(nb_node, xpath, list_entry, - list_keys, translator, flags, - cb, arg); - break; - case LYS_LIST: - ret = nb_oper_data_iter_list(nb_node, xpath, list_entry, - list_keys, translator, flags, cb, - arg); - break; - case LYS_USES: - ret = nb_oper_data_iter_children(snode, xpath, list_entry, - list_keys, translator, false, - flags, cb, arg); - break; - default: - break; - } - - 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 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). - */ - - LY_ERR err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0, 0, - LYD_NEW_PATH_UPDATE, NULL, &dnode); - if (err || !dnode) { - const char *errmsg = - err ? ly_errmsg(ly_native_ctx) : "node not found"; - flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path() failed %s", - __func__, errmsg); - return NB_ERR; - } - - /* - * 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 || !lyd_child(dn)) - continue; - 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)) { - 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; - } - - 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, iterate over that list entry only. */ - if (dnode->schema->nodetype == LYS_LIST && lyd_child(dnode)) - ret = nb_oper_data_iter_children( - nb_node->snode, xpath, list_entry, &list_keys, - translator, true, flags, cb, arg); - else - ret = nb_oper_data_iter_node(nb_node->snode, xpath, list_entry, - &list_keys, translator, true, - flags, cb, arg); - - list_delete(&list_dnodes); - yang_dnode_free(dnode); - - return ret; -} - bool nb_operation_is_valid(enum nb_operation operation, const struct lysc_node *snode) { @@ -2544,6 +2203,8 @@ const char *nb_err_name(enum nb_error error) return "failed to allocate resource"; case NB_ERR_INCONSISTENCY: return "internal inconsistency"; + case NB_YIELD: + return "should yield"; } assert(!"Reached end of function we should never hit"); @@ -2665,10 +2326,15 @@ void nb_init(struct event_loop *tm, /* Initialize the northbound CLI. */ nb_cli_init(tm); + + /* Initialize oper-state */ + nb_oper_init(tm); } void nb_terminate(void) { + nb_oper_terminate(); + /* Terminate the northbound CLI. */ nb_cli_terminate(); |
