summaryrefslogtreecommitdiff
path: root/lib/northbound.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/northbound.c')
-rw-r--r--lib/northbound.c436
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();