diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/lib_errors.c | 6 | ||||
| -rw-r--r-- | lib/lib_errors.h | 1 | ||||
| -rw-r--r-- | lib/northbound.c | 432 | ||||
| -rw-r--r-- | lib/northbound.h | 85 | ||||
| -rw-r--r-- | lib/northbound_cli.c | 120 | ||||
| -rw-r--r-- | lib/northbound_confd.c | 322 | ||||
| -rw-r--r-- | lib/northbound_sysrepo.c | 186 | ||||
| -rw-r--r-- | lib/yang.c | 110 | ||||
| -rw-r--r-- | lib/yang.h | 118 | ||||
| -rw-r--r-- | lib/yang_translator.c | 54 | ||||
| -rw-r--r-- | lib/yang_wrappers.c | 4 | ||||
| -rw-r--r-- | lib/yang_wrappers.h | 4 |
12 files changed, 1029 insertions, 413 deletions
diff --git a/lib/lib_errors.c b/lib/lib_errors.c index 71d1ec6e58..b1ed7d2f6b 100644 --- a/lib/lib_errors.c +++ b/lib/lib_errors.c @@ -135,6 +135,12 @@ static struct log_ref ferr_lib_warn[] = { .suggestion = "This is a bug; please report it" }, { + .code = EC_LIB_NB_OPERATIONAL_DATA, + .title = "Failure to obtain operational data", + .description = "The northbound subsystem failed to obtain YANG-modeled operational data", + .suggestion = "This is a bug; please report it" + }, + { .code = EC_LIB_NB_TRANSACTION_CREATION_FAILED, .title = "Failure to create a configuration transaction", .description = "The northbound subsystem failed to create a configuration transaction", diff --git a/lib/lib_errors.h b/lib/lib_errors.h index 38c75f913e..5534edbd8d 100644 --- a/lib/lib_errors.h +++ b/lib/lib_errors.h @@ -62,6 +62,7 @@ enum lib_log_refs { EC_LIB_NB_CB_RPC, EC_LIB_NB_CANDIDATE_INVALID, EC_LIB_NB_CANDIDATE_EDIT_ERROR, + EC_LIB_NB_OPERATIONAL_DATA, EC_LIB_NB_TRANSACTION_CREATION_FAILED, EC_LIB_NB_TRANSACTION_RECORD_FAILED, EC_LIB_LIBYANG, diff --git a/lib/northbound.c b/lib/northbound.c index 12d08310c6..490b3abe57 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -50,8 +50,26 @@ static void nb_transaction_free(struct nb_transaction *transaction); static int nb_transaction_process(enum nb_event event, struct nb_transaction *transaction); static void nb_transaction_apply_finish(struct nb_transaction *transaction); +static int nb_oper_data_iter_node(const struct lys_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 lys_node *snode, void *arg) +{ + bool *config_only = arg; + + if (CHECK_FLAG(snode->flags, LYS_CONFIG_R)) { + *config_only = false; + return YANG_ITER_STOP; + } + + return YANG_ITER_CONTINUE; +} -static void nb_node_new_cb(const struct lys_node *snode, void *arg1, void *arg2) +static int nb_node_new_cb(const struct lys_node *snode, void *arg) { struct nb_node *nb_node; struct lys_node *sparent, *sparent_list; @@ -67,21 +85,46 @@ static void nb_node_new_cb(const struct lys_node *snode, void *arg1, void *arg2) if (sparent_list) nb_node->parent_list = sparent_list->priv; + /* Set flags. */ + if (CHECK_FLAG(snode->nodetype, LYS_CONTAINER | LYS_LIST)) { + bool config_only = true; + + yang_snodes_iterate_subtree(snode, nb_node_check_config_only, + YANG_ITER_ALLOW_AUGMENTATIONS, + &config_only); + if (config_only) + SET_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY); + } + /* * Link the northbound node and the libyang schema node with one * another. */ nb_node->snode = snode; lys_set_private(snode, nb_node); + + return YANG_ITER_CONTINUE; } -static void nb_node_del_cb(const struct lys_node *snode, void *arg1, void *arg2) +static int nb_node_del_cb(const struct lys_node *snode, void *arg) { struct nb_node *nb_node; nb_node = snode->priv; lys_set_private(snode, NULL); XFREE(MTYPE_NB_NODE, nb_node); + + return YANG_ITER_CONTINUE; +} + +void nb_nodes_create(void) +{ + yang_snodes_iterate_all(nb_node_new_cb, 0, NULL); +} + +void nb_nodes_delete(void) +{ + yang_snodes_iterate_all(nb_node_del_cb, 0, NULL); } struct nb_node *nb_node_find(const char *xpath) @@ -170,15 +213,16 @@ static unsigned int nb_node_validate_priority(const struct nb_node *nb_node) return 0; } -static void nb_node_validate(const struct lys_node *snode, void *arg1, - void *arg2) +static int nb_node_validate(const struct lys_node *snode, void *arg) { struct nb_node *nb_node = snode->priv; - unsigned int *errors = arg1; + unsigned int *errors = arg; /* Validate callbacks and priority. */ *errors += nb_node_validate_cbs(nb_node); *errors += nb_node_validate_priority(nb_node); + + return YANG_ITER_CONTINUE; } struct nb_config *nb_config_new(struct lyd_node *dnode) @@ -189,7 +233,7 @@ struct nb_config *nb_config_new(struct lyd_node *dnode) if (dnode) config->dnode = dnode; else - config->dnode = yang_dnode_new(ly_native_ctx); + config->dnode = yang_dnode_new(ly_native_ctx, true); config->version = 0; return config; @@ -236,7 +280,8 @@ void nb_config_replace(struct nb_config *config_dst, config_dst->version = config_src->version; /* Update dnode. */ - yang_dnode_free(config_dst->dnode); + if (config_dst->dnode) + yang_dnode_free(config_dst->dnode); if (preserve_source) { config_dst->dnode = yang_dnode_dup(config_src->dnode); } else { @@ -380,7 +425,8 @@ static void nb_config_diff(const struct nb_config *config1, nb_config_diff_add_change(changes, operation, dnode); if (type == LYD_DIFF_CREATED - && (dnode->schema->nodetype & (LYS_CONTAINER | LYS_LIST))) + && CHECK_FLAG(dnode->schema->nodetype, + LYS_CONTAINER | LYS_LIST)) nb_config_diff_new_subtree(dnode, changes); } @@ -890,15 +936,341 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction) } } +static int nb_oper_data_iter_children(const struct lys_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 lys_node *child; + + LY_TREE_FOR (snode->child, 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 (lys_is_key((struct lys_node_leaf *)nb_node->snode, NULL)) + return NB_OK; + + data = nb_node->cbs.get_elem(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) +{ + if (CHECK_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY)) + return NB_OK; + + /* Presence containers. */ + if (nb_node->cbs.get_elem) { + struct yang_data *data; + int ret; + + data = nb_node->cbs.get_elem(xpath, list_entry); + if (data == NULL) + /* Presence container is not present. */ + return NB_OK; + + ret = (*cb)(nb_node->snode, translator, data, arg); + if (ret != NB_OK) + return ret; + } + + /* Iterate over the child nodes. */ + return nb_oper_data_iter_children(nb_node->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_node->cbs.get_next(parent_list_entry, list_entry); + if (!list_entry) + /* End of the list. */ + break; + + data = nb_node->cbs.get_elem(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) +{ + struct lys_node_list *slist = (struct lys_node_list *)nb_node->snode; + const void *list_entry = NULL; + + 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; + char xpath[XPATH_MAXLEN]; + int ret; + + /* Obtain list entry. */ + list_entry = + nb_node->cbs.get_next(parent_list_entry, list_entry); + if (!list_entry) + /* End of the list. */ + break; + + /* Obtain the list entry keys. */ + if (nb_node->cbs.get_keys(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)); + for (unsigned int i = 0; i < list_keys.num; i++) { + snprintf(xpath + strlen(xpath), + sizeof(xpath) - strlen(xpath), "[%s='%s']", + slist->keys[i]->name, list_keys.key[i]); + } + + /* 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 lys_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) + 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_errno = 0; + dnode = lyd_new_path(NULL, ly_native_ctx, xpath, NULL, 0, + LYD_PATH_OPT_UPDATE); + if (!dnode && ly_errno) { + flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path() failed", + __func__); + return NB_ERR; + } + /* + * We can remove the following two lines once we depend on + * libyang-v0.16-r2, which has the LYD_PATH_OPT_NOPARENTRET flag for + * lyd_new_path(). + */ + dnode = yang_dnode_get(dnode, xpath); + assert(dnode); + + /* + * Create a linked list to sort the data nodes starting from the root. + */ + list_dnodes = list_new(); + for (dn = dnode; dn; dn = dn->parent) { + if (dn->schema->nodetype != LYS_LIST || !dn->child) + 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_TREE_FOR (dn->child, child) { + if (!lys_is_key((struct lys_node_leaf *)child->schema, + NULL)) + continue; + strlcpy(list_keys.key[n], + yang_dnode_get_string(child, NULL), + sizeof(list_keys.key[n])); + n++; + } + list_keys.num = n; + assert(list_keys.num + == ((struct lys_node_list *)dn->schema)->keys_size); + + /* Find the list entry pointer. */ + nn = dn->schema->priv; + list_entry = nn->cbs.lookup_entry(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 && dnode->child) + 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 lys_node *snode) { + struct nb_node *nb_node = snode->priv; struct lys_node_container *scontainer; struct lys_node_leaf *sleaf; switch (operation) { case NB_OP_CREATE: - if (!(snode->flags & LYS_CONFIG_W)) + if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W)) return false; switch (snode->nodetype) { @@ -920,7 +1292,7 @@ bool nb_operation_is_valid(enum nb_operation operation, } return true; case NB_OP_MODIFY: - if (!(snode->flags & LYS_CONFIG_W)) + if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W)) return false; switch (snode->nodetype) { @@ -938,7 +1310,7 @@ bool nb_operation_is_valid(enum nb_operation operation, } return true; case NB_OP_DELETE: - if (!(snode->flags & LYS_CONFIG_W)) + if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W)) return false; switch (snode->nodetype) { @@ -957,7 +1329,8 @@ bool nb_operation_is_valid(enum nb_operation operation, return true; if (sleaf->when) return true; - if ((sleaf->flags & LYS_MAND_TRUE) || sleaf->dflt) + if (CHECK_FLAG(sleaf->flags, LYS_MAND_TRUE) + || sleaf->dflt) return false; break; case LYS_CONTAINER: @@ -973,13 +1346,13 @@ bool nb_operation_is_valid(enum nb_operation operation, } return true; case NB_OP_MOVE: - if (!(snode->flags & LYS_CONFIG_W)) + if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W)) return false; switch (snode->nodetype) { case LYS_LIST: case LYS_LEAFLIST: - if (!(snode->flags & LYS_USERORDERED)) + if (!CHECK_FLAG(snode->flags, LYS_USERORDERED)) return false; break; default: @@ -987,15 +1360,16 @@ bool nb_operation_is_valid(enum nb_operation operation, } return true; case NB_OP_APPLY_FINISH: - if (!(snode->flags & LYS_CONFIG_W)) + if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W)) return false; return true; case NB_OP_GET_ELEM: - if (!(snode->flags & LYS_CONFIG_R)) + if (!CHECK_FLAG(snode->flags, LYS_CONFIG_R)) return false; switch (snode->nodetype) { case LYS_LEAF: + case LYS_LEAFLIST: break; case LYS_CONTAINER: scontainer = (struct lys_node_container *)snode; @@ -1007,20 +1381,32 @@ bool nb_operation_is_valid(enum nb_operation operation, } return true; case NB_OP_GET_NEXT: + switch (snode->nodetype) { + case LYS_LIST: + if (CHECK_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY)) + return false; + break; + case LYS_LEAFLIST: + if (CHECK_FLAG(snode->flags, LYS_CONFIG_W)) + return false; + break; + default: + return false; + } + return true; case NB_OP_GET_KEYS: case NB_OP_LOOKUP_ENTRY: - if (!(snode->flags & LYS_CONFIG_R)) - return false; - switch (snode->nodetype) { case LYS_LIST: + if (CHECK_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY)) + return false; break; default: return false; } return true; case NB_OP_RPC: - if (snode->flags & (LYS_CONFIG_W | LYS_CONFIG_R)) + if (CHECK_FLAG(snode->flags, LYS_CONFIG_W | LYS_CONFIG_R)) return false; switch (snode->nodetype) { @@ -1162,14 +1548,14 @@ void nb_init(const struct frr_yang_module_info *modules[], size_t nmodules) yang_module_load(modules[i]->name); /* Create a nb_node for all YANG schema nodes. */ - yang_all_snodes_iterate(nb_node_new_cb, 0, NULL, NULL); + nb_nodes_create(); /* Load northbound callbacks. */ for (size_t i = 0; i < nmodules; i++) nb_load_callbacks(modules[i]); /* Validate northbound callbacks. */ - yang_all_snodes_iterate(nb_node_validate, 0, &errors, NULL); + yang_snodes_iterate_all(nb_node_validate, 0, &errors); if (errors > 0) { flog_err( EC_LIB_NB_CBS_VALIDATION, @@ -1197,7 +1583,7 @@ void nb_terminate(void) nb_cli_terminate(); /* Delete all nb_node's from all YANG modules. */ - yang_all_snodes_iterate(nb_node_del_cb, 0, NULL, NULL); + nb_nodes_delete(); /* Delete the running configuration. */ nb_config_free(running_config); diff --git a/lib/northbound.h b/lib/northbound.h index 8ab6662ecc..e26a2f8617 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -21,9 +21,10 @@ #define _FRR_NORTHBOUND_H_ #include "hook.h" -#include "yang.h" #include "linklist.h" #include "openbsd-tree.h" +#include "yang.h" +#include "yang_translator.h" /* Forward declaration(s). */ struct vty; @@ -211,15 +212,15 @@ struct nb_callbacks { /* * Operational data callback. * - * The callback function should return the value of a specific leaf or - * inform if a typeless value (presence containers or leafs of type - * empty) exists or not. + * The callback function should return the value of a specific leaf, + * leaf-list entry or inform if a typeless value (presence containers or + * leafs of type empty) exists or not. * * xpath * YANG data path of the data we want to get. * * list_entry - * Pointer to list entry. + * Pointer to list entry (might be NULL). * * Returns: * Pointer to newly created yang_data structure, or NULL to indicate @@ -229,22 +230,24 @@ struct nb_callbacks { const void *list_entry); /* - * Operational data callback for YANG lists. + * Operational data callback for YANG lists and leaf-lists. * - * The callback function should return the next entry in the list. The - * 'list_entry' parameter will be NULL on the first invocation. + * The callback function should return the next entry in the list or + * leaf-list. The 'list_entry' parameter will be NULL on the first + * invocation. * - * xpath - * Data path of the YANG list. + * parent_list_entry + * Pointer to parent list entry. * * list_entry - * Pointer to list entry. + * Pointer to (leaf-)list entry. * * Returns: - * Pointer to the next entry in the list, or NULL to signal that the - * end of the list was reached. + * Pointer to the next entry in the (leaf-)list, or NULL to signal + * that the end of the (leaf-)list was reached. */ - const void *(*get_next)(const char *xpath, const void *list_entry); + const void *(*get_next)(const void *parent_list_entry, + const void *list_entry); /* * Operational data callback for YANG lists. @@ -270,13 +273,17 @@ struct nb_callbacks { * The callback function should return a list entry based on the list * keys given as a parameter. * + * parent_list_entry + * Pointer to parent list entry. + * * keys * Structure containing the keys of the list entry. * * Returns: * Pointer to the list entry if found, or NULL if not found. */ - const void *(*lookup_entry)(const struct yang_list_keys *keys); + const void *(*lookup_entry)(const void *parent_list_entry, + const struct yang_list_keys *keys); /* * RPC and action callback. @@ -349,11 +356,16 @@ struct nb_node { /* Pointer to the nearest parent list, if any. */ struct nb_node *parent_list; + /* Flags. */ + uint8_t flags; + #ifdef HAVE_CONFD /* ConfD hash value corresponding to this YANG path. */ int confd_hash; #endif }; +/* The YANG container or list contains only config data. */ +#define F_NB_NODE_CONFIG_ONLY 0x01 struct frr_yang_module_info { /* YANG module name. */ @@ -429,6 +441,14 @@ struct nb_transaction { struct nb_config_cbs changes; }; +/* Callback function used by nb_oper_data_iterate(). */ +typedef int (*nb_oper_data_cb)(const struct lys_node *snode, + struct yang_translator *translator, + struct yang_data *data, void *arg); + +/* Iterate over direct child nodes only. */ +#define NB_OPER_DATA_ITER_NORECURSE 0x0001 + DECLARE_HOOK(nb_notification_send, (const char *xpath, struct list *arguments), (xpath, arguments)) @@ -436,6 +456,16 @@ extern int debug_northbound; extern struct nb_config *running_config; /* + * Create a northbound node for all YANG schema nodes. + */ +void nb_nodes_create(void); + +/* + * Delete all northbound nodes from all YANG schema nodes. + */ +void nb_nodes_delete(void); + +/* * Find the northbound node corresponding to a YANG data path. * * xpath @@ -686,6 +716,31 @@ extern int nb_candidate_commit(struct nb_config *candidate, const char *comment, uint32_t *transaction_id); /* + * Iterate over operetional data. + * + * xpath + * Data path of the YANG data we want to iterate over. + * + * translator + * YANG module translator (might be NULL). + * + * flags + * NB_OPER_DATA_ITER_ flags to control how the iteration is performed. + * + * cb + * Function to call with each data node. + * + * arg + * Arbitrary argument passed as the fourth parameter in each call to 'cb'. + * + * Returns: + * NB_OK on success, NB_ERR otherwise. + */ +extern int nb_oper_data_iterate(const char *xpath, + struct yang_translator *translator, + uint32_t flags, nb_oper_data_cb cb, void *arg); + +/* * Validate if the northbound operation is valid for the given node. * * operation diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index 94f7bb7c1e..a3006264f1 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -386,7 +386,7 @@ static int nb_cli_show_config_libyang(struct vty *vty, LYD_FORMAT format, { struct lyd_node *dnode; char *strp; - int options; + int options = 0; dnode = yang_dnode_dup(config->dnode); if (translator @@ -398,11 +398,11 @@ static int nb_cli_show_config_libyang(struct vty *vty, LYD_FORMAT format, return CMD_WARNING; } - options = LYP_FORMAT | LYP_WITHSIBLINGS; + SET_FLAG(options, LYP_FORMAT | LYP_WITHSIBLINGS); if (with_defaults) - options |= LYP_WD_ALL; + SET_FLAG(options, LYP_WD_ALL); else - options |= LYP_WD_TRIM; + SET_FLAG(options, LYP_WD_TRIM); if (lyd_print_mem(&strp, dnode, format, options) == 0 && strp) { vty_out(vty, "%s", strp); @@ -1124,6 +1124,117 @@ DEFPY (show_config_transaction, #endif /* HAVE_CONFIG_ROLLBACKS */ } +static int nb_cli_oper_data_cb(const struct lys_node *snode, + struct yang_translator *translator, + struct yang_data *data, void *arg) +{ + struct lyd_node *dnode = arg; + struct ly_ctx *ly_ctx; + + if (translator) { + int ret; + + ret = yang_translate_xpath(translator, + YANG_TRANSLATE_FROM_NATIVE, + data->xpath, sizeof(data->xpath)); + switch (ret) { + case YANG_TRANSLATE_SUCCESS: + break; + case YANG_TRANSLATE_NOTFOUND: + goto exit; + case YANG_TRANSLATE_FAILURE: + goto error; + } + + ly_ctx = translator->ly_ctx; + } else + ly_ctx = ly_native_ctx; + + ly_errno = 0; + dnode = lyd_new_path(dnode, ly_ctx, data->xpath, (void *)data->value, 0, + LYD_PATH_OPT_UPDATE); + if (!dnode && ly_errno) { + flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path() failed", + __func__); + goto error; + } + +exit: + yang_data_free(data); + return NB_OK; + +error: + yang_data_free(data); + return NB_ERR; +} + +DEFPY (show_yang_operational_data, + show_yang_operational_data_cmd, + "show yang operational-data XPATH$xpath\ + [{\ + format <json$json|xml$xml>\ + |translate WORD$translator_family\ + }]", + SHOW_STR + "YANG information\n" + "Show YANG operational data\n" + "XPath expression specifying the YANG data path\n" + "Set the output format\n" + "JavaScript Object Notation\n" + "Extensible Markup Language\n" + "Translate operational data\n" + "YANG module translator\n") +{ + LYD_FORMAT format; + struct yang_translator *translator = NULL; + struct ly_ctx *ly_ctx; + struct lyd_node *dnode; + char *strp; + + if (xml) + format = LYD_XML; + else + format = LYD_JSON; + + if (translator_family) { + translator = yang_translator_find(translator_family); + if (!translator) { + vty_out(vty, "%% Module translator \"%s\" not found\n", + translator_family); + return CMD_WARNING; + } + + ly_ctx = translator->ly_ctx; + } else + ly_ctx = ly_native_ctx; + + /* Obtain data. */ + dnode = yang_dnode_new(ly_ctx, false); + if (nb_oper_data_iterate(xpath, translator, 0, nb_cli_oper_data_cb, + dnode) + != NB_OK) { + vty_out(vty, "%% Failed to fetch operational data.\n"); + yang_dnode_free(dnode); + return CMD_WARNING; + } + lyd_validate(&dnode, LYD_OPT_DATA | LYD_OPT_DATA_NO_YANGLIB, ly_ctx); + + /* Display the data. */ + if (lyd_print_mem(&strp, dnode, format, + LYP_FORMAT | LYP_WITHSIBLINGS | LYP_WD_ALL) + != 0 + || !strp) { + vty_out(vty, "%% Failed to display operational data.\n"); + yang_dnode_free(dnode); + return CMD_WARNING; + } + vty_out(vty, "%s", strp); + free(strp); + yang_dnode_free(dnode); + + return CMD_SUCCESS; +} + DEFPY (show_yang_module, show_yang_module_cmd, "show yang module [module-translator WORD$translator_family]", @@ -1463,6 +1574,7 @@ void nb_cli_init(void) /* Other commands. */ install_element(CONFIG_NODE, &yang_module_translator_load_cmd); install_element(CONFIG_NODE, &yang_module_translator_unload_cmd); + install_element(ENABLE_NODE, &show_yang_operational_data_cmd); install_element(ENABLE_NODE, &show_yang_module_cmd); install_element(ENABLE_NODE, &show_yang_module_detail_cmd); install_element(ENABLE_NODE, &show_yang_module_translator_cmd); diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c index ec5e0c32c3..3579d1da00 100644 --- a/lib/northbound_confd.c +++ b/lib/northbound_confd.c @@ -91,22 +91,61 @@ static int frr_confd_val2str(const char *xpath, const confd_value_t *value, return 0; } -/* Obtain list keys from ConfD hashed keypath. */ -static void frr_confd_hkeypath_get_keys(const confd_hkeypath_t *kp, - struct yang_list_keys *keys) +/* Obtain list entry from ConfD hashed keypath. */ +static int frr_confd_hkeypath_get_list_entry(const confd_hkeypath_t *kp, + struct nb_node *nb_node, + const void **list_entry) { - memset(keys, 0, sizeof(*keys)); - for (int i = 0; i < kp->len; i++) { + struct nb_node *nb_node_list; + int parent_lists = 0; + int curr_list = 0; + + *list_entry = NULL; + + /* + * Count the number of YANG lists in the path, disconsidering the + * last element. + */ + nb_node_list = nb_node; + while (nb_node_list->parent_list) { + nb_node_list = nb_node_list->parent_list; + parent_lists++; + } + if (nb_node->snode->nodetype != LYS_LIST && parent_lists == 0) + return 0; + + /* Start from the beginning and move down the tree. */ + for (int i = kp->len; i >= 0; i--) { + struct yang_list_keys keys; + + /* Not a YANG list. */ if (kp->v[i][0].type != C_BUF) continue; + /* Obtain list keys. */ + memset(&keys, 0, sizeof(keys)); for (int j = 0; kp->v[i][j].type != C_NOEXISTS; j++) { - strlcpy(keys->key[keys->num].value, + strlcpy(keys.key[keys.num], (char *)kp->v[i][j].val.buf.ptr, - sizeof(keys->key[keys->num].value)); - keys->num++; + sizeof(keys.key[keys.num])); + keys.num++; } + + /* Obtain northbound node associated to the YANG list. */ + nb_node_list = nb_node; + for (int j = curr_list; j < parent_lists; j++) + nb_node_list = nb_node_list->parent_list; + + /* Obtain list entry. */ + *list_entry = + nb_node_list->cbs.lookup_entry(*list_entry, &keys); + if (*list_entry == NULL) + return -1; + + curr_list++; } + + return 0; } /* Fill the current date and time into a confd_datetime structure. */ @@ -430,6 +469,9 @@ static int frr_confd_init_cdb(void) continue; } + if (CHECK_FLAG(snode->flags, LYS_CONFIG_R)) + continue; + nb_node = snode->priv; if (debug_northbound) zlog_debug("%s: subscribing to '%s'", __func__, @@ -490,12 +532,13 @@ static int frr_confd_transaction_init(struct confd_trans_ctx *tctx) return CONFD_OK; } +#define CONFD_MAX_CHILD_NODES 32 + static int frr_confd_data_get_elem(struct confd_trans_ctx *tctx, confd_hkeypath_t *kp) { - struct nb_node *nb_node, *parent_list; + struct nb_node *nb_node; char xpath[BUFSIZ]; - struct yang_list_keys keys; struct yang_data *data; confd_value_t v; const void *list_entry = NULL; @@ -510,17 +553,9 @@ static int frr_confd_data_get_elem(struct confd_trans_ctx *tctx, return CONFD_OK; } - parent_list = nb_node->parent_list; - if (parent_list) { - frr_confd_hkeypath_get_keys(kp, &keys); - list_entry = parent_list->cbs.lookup_entry(&keys); - if (!list_entry) { - flog_warn(EC_LIB_NB_CB_STATE, - "%s: list entry not found: %s", __func__, - xpath); - confd_data_reply_not_found(tctx); - return CONFD_OK; - } + if (frr_confd_hkeypath_get_list_entry(kp, nb_node, &list_entry) != 0) { + confd_data_reply_not_found(tctx); + return CONFD_OK; } data = nb_node->cbs.get_elem(xpath, list_entry); @@ -543,7 +578,8 @@ static int frr_confd_data_get_next(struct confd_trans_ctx *tctx, struct nb_node *nb_node; char xpath[BUFSIZ]; struct yang_list_keys keys; - const void *nb_next; + struct yang_data *data; + const void *parent_list_entry, *nb_next; confd_value_t v[LIST_MAXKEYS]; frr_confd_get_xpath(kp, xpath, sizeof(xpath)); @@ -556,24 +592,51 @@ static int frr_confd_data_get_next(struct confd_trans_ctx *tctx, return CONFD_OK; } - nb_next = nb_node->cbs.get_next(xpath, - (next == -1) ? NULL : (void *)next); - if (!nb_next) { - /* End of the list. */ + if (frr_confd_hkeypath_get_list_entry(kp, nb_node, &parent_list_entry) + != 0) { + /* List entry doesn't exist anymore. */ confd_data_reply_next_key(tctx, NULL, -1, -1); return CONFD_OK; } - if (nb_node->cbs.get_keys(nb_next, &keys) != NB_OK) { - flog_warn(EC_LIB_NB_CB_STATE, "%s: failed to get list keys", - __func__); + + nb_next = nb_node->cbs.get_next(parent_list_entry, + (next == -1) ? NULL : (void *)next); + if (!nb_next) { + /* End of the list or leaf-list. */ confd_data_reply_next_key(tctx, NULL, -1, -1); return CONFD_OK; } - /* Feed keys to ConfD. */ - for (size_t i = 0; i < keys.num; i++) - CONFD_SET_STR(&v[i], keys.key[i].value); - confd_data_reply_next_key(tctx, v, keys.num, (long)nb_next); + switch (nb_node->snode->nodetype) { + case LYS_LIST: + memset(&keys, 0, sizeof(keys)); + if (nb_node->cbs.get_keys(nb_next, &keys) != NB_OK) { + flog_warn(EC_LIB_NB_CB_STATE, + "%s: failed to get list keys", __func__); + confd_data_reply_next_key(tctx, NULL, -1, -1); + return CONFD_OK; + } + + /* Feed keys to ConfD. */ + for (size_t i = 0; i < keys.num; i++) + CONFD_SET_STR(&v[i], keys.key[i]); + confd_data_reply_next_key(tctx, v, keys.num, (long)nb_next); + break; + case LYS_LEAFLIST: + data = nb_node->cbs.get_elem(xpath, nb_next); + if (data) { + if (data->value) { + CONFD_SET_STR(&v[0], data->value); + confd_data_reply_next_key(tctx, v, 1, + (long)nb_next); + } + yang_data_free(data); + } else + confd_data_reply_next_key(tctx, NULL, -1, -1); + break; + default: + break; + } return CONFD_OK; } @@ -585,15 +648,14 @@ static int frr_confd_data_get_object(struct confd_trans_ctx *tctx, confd_hkeypath_t *kp) { struct nb_node *nb_node; + const struct lys_node *child; char xpath[BUFSIZ]; - char xpath_children[XPATH_MAXLEN]; char xpath_child[XPATH_MAXLEN]; - struct yang_list_keys keys; struct list *elements; struct yang_data *data; const void *list_entry; - struct ly_set *set; - confd_value_t *values; + confd_value_t values[CONFD_MAX_CHILD_NODES]; + size_t nvalues = 0; frr_confd_get_xpath(kp, xpath, sizeof(xpath)); @@ -602,57 +664,53 @@ static int frr_confd_data_get_object(struct confd_trans_ctx *tctx, flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, "%s: unknown data path: %s", __func__, xpath); confd_data_reply_not_found(tctx); - return CONFD_OK; + return CONFD_ERR; } - frr_confd_hkeypath_get_keys(kp, &keys); - list_entry = nb_node->cbs.lookup_entry(&keys); - if (!list_entry) { - flog_warn(EC_LIB_NB_CB_STATE, "%s: list entry not found: %s", - __func__, xpath); + if (frr_confd_hkeypath_get_list_entry(kp, nb_node, &list_entry) != 0) { confd_data_reply_not_found(tctx); return CONFD_OK; } - /* Find list child nodes. */ - snprintf(xpath_children, sizeof(xpath_children), "%s/*", xpath); - set = lys_find_path(nb_node->snode->module, NULL, xpath_children); - if (!set) { - flog_warn(EC_LIB_LIBYANG, "%s: lys_find_path() failed", - __func__); - return CONFD_ERR; - } - elements = yang_data_list_new(); - values = XMALLOC(MTYPE_CONFD, set->number * sizeof(*values)); /* Loop through list child nodes. */ - for (size_t i = 0; i < set->number; i++) { - struct lys_node *child; - struct nb_node *nb_node_child; + LY_TREE_FOR (nb_node->snode->child, child) { + struct nb_node *nb_node_child = child->priv; + confd_value_t *v; + + if (nvalues > CONFD_MAX_CHILD_NODES) + break; + + v = &values[nvalues++]; - child = set->set.s[i]; - nb_node_child = child->priv; + /* Non-presence containers, lists and leaf-lists. */ + if (!nb_node_child->cbs.get_elem) { + CONFD_SET_NOEXISTS(v); + continue; + } snprintf(xpath_child, sizeof(xpath_child), "%s/%s", xpath, child->name); - data = nb_node_child->cbs.get_elem(xpath_child, list_entry); if (data) { if (data->value) - CONFD_SET_STR(&values[i], data->value); - else - CONFD_SET_NOEXISTS(&values[i]); + CONFD_SET_STR(v, data->value); + else { + /* Presence containers and empty leafs. */ + CONFD_SET_XMLTAG( + v, nb_node_child->confd_hash, + confd_str2hash(nb_node_child->snode + ->module->ns)); + } listnode_add(elements, data); } else - CONFD_SET_NOEXISTS(&values[i]); + CONFD_SET_NOEXISTS(v); } - confd_data_reply_value_array(tctx, values, set->number); + confd_data_reply_value_array(tctx, values, nvalues); /* Release memory. */ - ly_set_free(set); - XFREE(MTYPE_CONFD, values); list_delete(&elements); return CONFD_OK; @@ -665,10 +723,9 @@ static int frr_confd_data_get_next_object(struct confd_trans_ctx *tctx, confd_hkeypath_t *kp, long next) { char xpath[BUFSIZ]; - char xpath_children[XPATH_MAXLEN]; struct nb_node *nb_node; - struct ly_set *set; struct list *elements; + const void *parent_list_entry; const void *nb_next; #define CONFD_OBJECTS_PER_TIME 100 struct confd_next_object objects[CONFD_OBJECTS_PER_TIME + 1]; @@ -684,13 +741,10 @@ static int frr_confd_data_get_next_object(struct confd_trans_ctx *tctx, return CONFD_OK; } - /* Find list child nodes. */ - snprintf(xpath_children, sizeof(xpath_children), "%s/*", xpath); - set = lys_find_path(nb_node->snode->module, NULL, xpath_children); - if (!set) { - flog_warn(EC_LIB_LIBYANG, "%s: lys_find_path() failed", - __func__); - return CONFD_ERR; + if (frr_confd_hkeypath_get_list_entry(kp, nb_node, &parent_list_entry) + != 0) { + confd_data_reply_next_object_array(tctx, NULL, 0, 0); + return CONFD_OK; } elements = yang_data_list_new(); @@ -699,62 +753,76 @@ static int frr_confd_data_get_next_object(struct confd_trans_ctx *tctx, memset(objects, 0, sizeof(objects)); for (int j = 0; j < CONFD_OBJECTS_PER_TIME; j++) { struct confd_next_object *object; - struct yang_list_keys keys; + struct lys_node *child; struct yang_data *data; - const void *list_entry; + size_t nvalues = 0; object = &objects[j]; - nb_next = nb_node->cbs.get_next(xpath, nb_next); + nb_next = nb_node->cbs.get_next(parent_list_entry, nb_next); if (!nb_next) /* End of the list. */ break; - if (nb_node->cbs.get_keys(nb_next, &keys) != NB_OK) { - flog_warn(EC_LIB_NB_CB_STATE, - "%s: failed to get list keys", __func__); - continue; - } object->next = (long)nb_next; - list_entry = nb_node->cbs.lookup_entry(&keys); - if (!list_entry) { - flog_warn(EC_LIB_NB_CB_STATE, - "%s: failed to lookup list entry", __func__); - continue; + /* Leaf-lists require special handling. */ + if (nb_node->snode->nodetype == LYS_LEAFLIST) { + object->v = XMALLOC(MTYPE_CONFD, sizeof(confd_value_t)); + data = nb_node->cbs.get_elem(xpath, nb_next); + assert(data && data->value); + CONFD_SET_STR(object->v, data->value); + nvalues++; + listnode_add(elements, data); + goto next; } - object->v = XMALLOC(MTYPE_CONFD, - set->number * sizeof(confd_value_t)); + object->v = + XMALLOC(MTYPE_CONFD, + CONFD_MAX_CHILD_NODES * sizeof(confd_value_t)); /* Loop through list child nodes. */ - for (unsigned int i = 0; i < set->number; i++) { - struct lys_node *child; - struct nb_node *nb_node_child; + LY_TREE_FOR (nb_node->snode->child, child) { + struct nb_node *nb_node_child = child->priv; char xpath_child[XPATH_MAXLEN]; - confd_value_t *v = &object->v[i]; + confd_value_t *v; + + if (nvalues > CONFD_MAX_CHILD_NODES) + break; - child = set->set.s[i]; - nb_node_child = child->priv; + v = &object->v[nvalues++]; + + /* Non-presence containers, lists and leaf-lists. */ + if (!nb_node_child->cbs.get_elem) { + CONFD_SET_NOEXISTS(v); + continue; + } snprintf(xpath_child, sizeof(xpath_child), "%s/%s", xpath, child->name); - data = nb_node_child->cbs.get_elem(xpath_child, - list_entry); + nb_next); if (data) { if (data->value) CONFD_SET_STR(v, data->value); - else - CONFD_SET_NOEXISTS(v); + else { + /* + * Presence containers and empty leafs. + */ + CONFD_SET_XMLTAG( + v, nb_node_child->confd_hash, + confd_str2hash( + nb_node_child->snode + ->module->ns)); + } listnode_add(elements, data); } else CONFD_SET_NOEXISTS(v); } - object->n = set->number; + next: + object->n = nvalues; nobjects++; } - ly_set_free(set); if (nobjects == 0) { confd_data_reply_next_object_array(tctx, NULL, 0, 0); @@ -816,10 +884,18 @@ static int frr_confd_notification_send(const char *xpath, CONFD_SET_TAG_XMLBEGIN(&values[i++], nb_node->confd_hash, module->confd_hash); for (ALL_LIST_ELEMENTS_RO(arguments, node, data)) { - struct nb_node *option_arg; + struct nb_node *nb_node_arg; + + nb_node_arg = nb_node_find(data->xpath); + if (!nb_node_arg) { + flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, + "%s: unknown data path: %s", __func__, + data->xpath); + XFREE(MTYPE_CONFD, values); + return NB_ERR; + } - option_arg = data->snode->priv; - CONFD_SET_TAG_STR(&values[i++], option_arg->confd_hash, + CONFD_SET_TAG_STR(&values[i++], nb_node_arg->confd_hash, data->value); } CONFD_SET_TAG_XMLEND(&values[i++], nb_node->confd_hash, @@ -921,9 +997,18 @@ static int frr_confd_action_execute(struct confd_user_info *uinfo, listcount(output) * sizeof(*reply)); for (ALL_LIST_ELEMENTS_RO(output, node, data)) { + struct nb_node *nb_node_output; int hash; - hash = confd_str2hash(data->snode->name); + nb_node_output = nb_node_find(data->xpath); + if (!nb_node_output) { + flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, + "%s: unknown data path: %s", __func__, + data->xpath); + goto exit; + } + + hash = confd_str2hash(nb_node_output->snode->name); CONFD_SET_TAG_STR(&reply[i++], hash, data->value); } confd_action_reply_values(uinfo, reply, listcount(output)); @@ -962,17 +1047,16 @@ static int frr_confd_dp_read(struct thread *thread) return 0; } -static void frr_confd_subscribe_state(const struct lys_node *snode, void *arg1, - void *arg2) +static int frr_confd_subscribe_state(const struct lys_node *snode, void *arg) { struct nb_node *nb_node = snode->priv; - struct confd_data_cbs *data_cbs = arg1; + struct confd_data_cbs *data_cbs = arg; - if (!(snode->flags & LYS_CONFIG_R)) - return; + if (!CHECK_FLAG(snode->flags, LYS_CONFIG_R)) + return YANG_ITER_CONTINUE; /* We only need to subscribe to the root of the state subtrees. */ - if (snode->parent && (snode->parent->flags & LYS_CONFIG_R)) - return; + if (snode->parent && CHECK_FLAG(snode->parent->flags, LYS_CONFIG_R)) + return YANG_ITER_CONTINUE; if (debug_northbound) zlog_debug("%s: providing data to '%s' (callpoint %s)", @@ -981,6 +1065,8 @@ static void frr_confd_subscribe_state(const struct lys_node *snode, void *arg1, strlcpy(data_cbs->callpoint, snode->name, sizeof(data_cbs->callpoint)); if (confd_register_data_cb(dctx, data_cbs) != CONFD_OK) flog_err_confd("confd_register_data_cb"); + + return YANG_ITER_CONTINUE; } static int frr_confd_init_dp(const char *program_name) @@ -1053,7 +1139,7 @@ static int frr_confd_init_dp(const char *program_name) * Iterate over all loaded YANG modules and subscribe to the paths * referent to state data. */ - yang_all_snodes_iterate(frr_confd_subscribe_state, 0, &data_cbs, NULL); + yang_snodes_iterate_all(frr_confd_subscribe_state, 0, &data_cbs); /* Register notification stream. */ memset(&ncbs, 0, sizeof(ncbs)); @@ -1117,12 +1203,14 @@ static void frr_confd_finish_dp(void) /* ------------ Main ------------ */ -static void frr_confd_calculate_snode_hash(const struct lys_node *snode, - void *arg1, void *arg2) +static int frr_confd_calculate_snode_hash(const struct lys_node *snode, + void *arg) { struct nb_node *nb_node = snode->priv; nb_node->confd_hash = confd_str2hash(snode->name); + + return YANG_ITER_CONTINUE; } static int frr_confd_init(const char *program_name) @@ -1153,7 +1241,7 @@ static int frr_confd_init(const char *program_name) goto error; } - yang_all_snodes_iterate(frr_confd_calculate_snode_hash, 0, NULL, NULL); + yang_snodes_iterate_all(frr_confd_calculate_snode_hash, 0, NULL); hook_register(nb_notification_send, frr_confd_notification_send); diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c index f645adede3..ffda4c65d0 100644 --- a/lib/northbound_sysrepo.c +++ b/lib/northbound_sysrepo.c @@ -45,6 +45,7 @@ static int frr_sr_finish(void); /* Convert FRR YANG data value to sysrepo YANG data value. */ static int yang_data_frr2sr(struct yang_data *frr_data, sr_val_t *sr_data) { + struct nb_node *nb_node; const struct lys_node *snode; struct lys_node_container *scontainer; struct lys_node_leaf *sleaf; @@ -53,7 +54,15 @@ static int yang_data_frr2sr(struct yang_data *frr_data, sr_val_t *sr_data) sr_val_set_xpath(sr_data, frr_data->xpath); - snode = frr_data->snode; + nb_node = nb_node_find(frr_data->xpath); + if (!nb_node) { + flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, + "%s: unknown data path: %s", __func__, + frr_data->xpath); + return -1; + } + + snode = nb_node->snode; switch (snode->nodetype) { case LYS_CONTAINER: scontainer = (struct lys_node_container *)snode; @@ -290,111 +299,15 @@ static int frr_sr_config_change_cb(sr_session_ctx_t *session, } } -static void frr_sr_state_get_elem(struct list *elements, - struct nb_node *nb_node, - const void *list_entry, const char *xpath) +static int frr_sr_state_data_iter_cb(const struct lys_node *snode, + struct yang_translator *translator, + struct yang_data *data, void *arg) { - struct yang_data *data; - - data = nb_node->cbs.get_elem(xpath, list_entry); - if (data) - listnode_add(elements, data); -} + struct list *elements = arg; -static void frr_sr_state_cb_container(struct list *elements, const char *xpath, - const struct lys_node *snode) -{ - struct lys_node *child; - - LY_TREE_FOR (snode->child, child) { - struct nb_node *nb_node = child->priv; - char xpath_child[XPATH_MAXLEN]; - - if (!nb_operation_is_valid(NB_OP_GET_ELEM, child)) - continue; - - snprintf(xpath_child, sizeof(xpath_child), "%s/%s", xpath, - child->name); - - frr_sr_state_get_elem(elements, nb_node, NULL, xpath_child); - } -} - -static void frr_sr_state_cb_list_entry(struct list *elements, - const char *xpath_list, - const void *list_entry, - struct lys_node *child) -{ - struct nb_node *nb_node = child->priv; - struct lys_node_leaf *sleaf; - char xpath_child[XPATH_MAXLEN]; - - /* Sysrepo doesn't want to know about list keys. */ - switch (child->nodetype) { - case LYS_LEAF: - sleaf = (struct lys_node_leaf *)child; - if (lys_is_key(sleaf, NULL)) - return; - break; - case LYS_LEAFLIST: - break; - default: - return; - } - - if (!nb_operation_is_valid(NB_OP_GET_ELEM, child)) - return; - - snprintf(xpath_child, sizeof(xpath_child), "%s/%s", xpath_list, - child->name); - - frr_sr_state_get_elem(elements, nb_node, list_entry, xpath_child); -} + listnode_add(elements, data); -static void frr_sr_state_cb_list(struct list *elements, const char *xpath, - const struct lys_node *snode) -{ - struct nb_node *nb_node = snode->priv; - struct lys_node_list *slist = (struct lys_node_list *)snode; - const void *next; - - for (next = nb_node->cbs.get_next(xpath, NULL); next; - next = nb_node->cbs.get_next(xpath, next)) { - struct yang_list_keys keys; - const void *list_entry; - char xpath_list[XPATH_MAXLEN]; - struct lys_node *child; - - /* Get the list keys. */ - if (nb_node->cbs.get_keys(next, &keys) != NB_OK) { - flog_warn(EC_LIB_NB_CB_STATE, - "%s: failed to get list keys", __func__); - continue; - } - - /* Get list item. */ - list_entry = nb_node->cbs.lookup_entry(&keys); - if (!list_entry) { - flog_warn(EC_LIB_NB_CB_STATE, - "%s: failed to lookup list entry", __func__); - continue; - } - - /* Append list keys to the XPath. */ - strlcpy(xpath_list, xpath, sizeof(xpath_list)); - for (unsigned int i = 0; i < keys.num; i++) { - snprintf(xpath_list + strlen(xpath_list), - sizeof(xpath_list) - strlen(xpath_list), - "[%s='%s']", slist->keys[i]->name, - keys.key[i].value); - } - - /* Loop through list entries. */ - LY_TREE_FOR (snode->child, child) { - frr_sr_state_cb_list_entry(elements, xpath_list, - list_entry, child); - } - } + return NB_OK; } /* Callback for state retrieval. */ @@ -404,26 +317,20 @@ static int frr_sr_state_cb(const char *xpath, sr_val_t **values, { struct list *elements; struct yang_data *data; - const struct lys_node *snode; struct listnode *node; sr_val_t *v; int ret, count, i = 0; - /* Find schema node. */ - snode = ly_ctx_get_node(ly_native_ctx, NULL, xpath, 0); - elements = yang_data_list_new(); - - switch (snode->nodetype) { - case LYS_CONTAINER: - frr_sr_state_cb_container(elements, xpath, snode); - break; - case LYS_LIST: - frr_sr_state_cb_list(elements, xpath, snode); - break; - default: - break; + if (nb_oper_data_iterate(xpath, NULL, NB_OPER_DATA_ITER_NORECURSE, + frr_sr_state_data_iter_cb, elements) + != NB_OK) { + flog_warn(EC_LIB_NB_OPERATIONAL_DATA, + "%s: failed to obtain operational data [xpath %s]", + __func__, xpath); + goto exit; } + if (list_isempty(elements)) goto exit; @@ -723,18 +630,17 @@ static void frr_sr_subscribe_config(struct yang_module *module) sr_strerror(ret)); } -static void frr_sr_subscribe_state(const struct lys_node *snode, void *arg1, - void *arg2) +static int frr_sr_subscribe_state(const struct lys_node *snode, void *arg) { - struct yang_module *module = arg1; + struct yang_module *module = arg; struct nb_node *nb_node; int ret; - if (!(snode->flags & LYS_CONFIG_R)) - return; + if (!CHECK_FLAG(snode->flags, LYS_CONFIG_R)) + return YANG_ITER_CONTINUE; /* We only need to subscribe to the root of the state subtrees. */ - if (snode->parent && (snode->parent->flags & LYS_CONFIG_R)) - return; + if (snode->parent && CHECK_FLAG(snode->parent->flags, LYS_CONFIG_R)) + return YANG_ITER_CONTINUE; nb_node = snode->priv; if (debug_northbound) @@ -747,17 +653,18 @@ static void frr_sr_subscribe_state(const struct lys_node *snode, void *arg1, if (ret != SR_ERR_OK) flog_err(EC_LIB_LIBSYSREPO, "sr_dp_get_items_subscribe(): %s", sr_strerror(ret)); + + return YANG_ITER_CONTINUE; } -static void frr_sr_subscribe_rpc(const struct lys_node *snode, void *arg1, - void *arg2) +static int frr_sr_subscribe_rpc(const struct lys_node *snode, void *arg) { - struct yang_module *module = arg1; + struct yang_module *module = arg; struct nb_node *nb_node; int ret; if (snode->nodetype != LYS_RPC) - return; + return YANG_ITER_CONTINUE; nb_node = snode->priv; if (debug_northbound) @@ -770,17 +677,18 @@ static void frr_sr_subscribe_rpc(const struct lys_node *snode, void *arg1, if (ret != SR_ERR_OK) flog_err(EC_LIB_LIBSYSREPO, "sr_rpc_subscribe(): %s", sr_strerror(ret)); + + return YANG_ITER_CONTINUE; } -static void frr_sr_subscribe_action(const struct lys_node *snode, void *arg1, - void *arg2) +static int frr_sr_subscribe_action(const struct lys_node *snode, void *arg) { - struct yang_module *module = arg1; + struct yang_module *module = arg; struct nb_node *nb_node; int ret; if (snode->nodetype != LYS_ACTION) - return; + return YANG_ITER_CONTINUE; nb_node = snode->priv; if (debug_northbound) @@ -793,6 +701,8 @@ static void frr_sr_subscribe_action(const struct lys_node *snode, void *arg1, if (ret != SR_ERR_OK) flog_err(EC_LIB_LIBSYSREPO, "sr_action_subscribe(): %s", sr_strerror(ret)); + + return YANG_ITER_CONTINUE; } /* FRR's Sysrepo initialization. */ @@ -830,12 +740,12 @@ static int frr_sr_init(const char *program_name) /* Perform subscriptions. */ RB_FOREACH (module, yang_modules, &yang_modules) { frr_sr_subscribe_config(module); - yang_module_snodes_iterate(module->info, frr_sr_subscribe_state, - 0, module, NULL); - yang_module_snodes_iterate(module->info, frr_sr_subscribe_rpc, - 0, module, NULL); - yang_module_snodes_iterate( - module->info, frr_sr_subscribe_action, 0, module, NULL); + yang_snodes_iterate_module(module->info, frr_sr_subscribe_state, + 0, module); + yang_snodes_iterate_module(module->info, frr_sr_subscribe_rpc, + 0, module); + yang_snodes_iterate_module(module->info, + frr_sr_subscribe_action, 0, module); } hook_register(nb_notification_send, frr_sr_notification_send); diff --git a/lib/yang.c b/lib/yang.c index 757982d367..462e693549 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -71,6 +71,11 @@ static const char *yang_module_imp_clb(const char *mod_name, return NULL; } +static const char * const frr_native_modules[] = { + "frr-interface", + "frr-ripd", +}; + /* Generate the yang_modules tree. */ static inline int yang_module_compare(const struct yang_module *a, const struct yang_module *b) @@ -108,6 +113,12 @@ struct yang_module *yang_module_load(const char *module_name) return module; } +void yang_module_load_all(void) +{ + for (size_t i = 0; i < array_size(frr_native_modules); i++) + yang_module_load(frr_native_modules[i]); +} + struct yang_module *yang_module_find(const char *module_name) { struct yang_module s; @@ -116,23 +127,18 @@ struct yang_module *yang_module_find(const char *module_name) return RB_FIND(yang_modules, &yang_modules, &s); } -/* - * Helper function for yang_module_snodes_iterate() and - * yang_all_snodes_iterate(). This is a recursive function. - */ -static void yang_snodes_iterate(const struct lys_node *snode, - void (*func)(const struct lys_node *, void *, - void *), - uint16_t flags, void *arg1, void *arg2) +int yang_snodes_iterate_subtree(const struct lys_node *snode, + yang_iterate_cb cb, uint16_t flags, void *arg) { struct lys_node *child; + int ret = YANG_ITER_CONTINUE; if (CHECK_FLAG(flags, YANG_ITER_FILTER_IMPLICIT)) { switch (snode->nodetype) { case LYS_CASE: case LYS_INPUT: case LYS_OUTPUT: - if (snode->flags & LYS_IMPLICIT) + if (CHECK_FLAG(snode->flags, LYS_IMPLICIT)) goto next; break; default: @@ -162,7 +168,7 @@ static void yang_snodes_iterate(const struct lys_node *snode, break; case LYS_GROUPING: /* Return since we're not interested in the grouping subtree. */ - return; + return YANG_ITER_CONTINUE; case LYS_USES: case LYS_AUGMENT: /* Always ignore nodes of these types. */ @@ -176,50 +182,66 @@ static void yang_snodes_iterate(const struct lys_node *snode, break; } - (*func)(snode, arg1, arg2); + ret = (*cb)(snode, arg); + if (ret == YANG_ITER_STOP) + return ret; next: /* * YANG leafs and leaf-lists can't have child nodes, and trying to * access snode->child is undefined behavior. */ - if (snode->nodetype & (LYS_LEAF | LYS_LEAFLIST)) - return; + if (CHECK_FLAG(snode->nodetype, LYS_LEAF | LYS_LEAFLIST)) + return YANG_ITER_CONTINUE; LY_TREE_FOR (snode->child, child) { - if (child->parent != snode) + if (!CHECK_FLAG(flags, YANG_ITER_ALLOW_AUGMENTATIONS) + && child->parent != snode) continue; - yang_snodes_iterate(child, func, flags, arg1, arg2); + + ret = yang_snodes_iterate_subtree(child, cb, flags, arg); + if (ret == YANG_ITER_STOP) + return ret; } + + return ret; } -void yang_module_snodes_iterate(const struct lys_module *module, - void (*func)(const struct lys_node *, void *, - void *), - uint16_t flags, void *arg1, void *arg2) +int yang_snodes_iterate_module(const struct lys_module *module, + yang_iterate_cb cb, uint16_t flags, void *arg) { struct lys_node *snode; + int ret = YANG_ITER_CONTINUE; LY_TREE_FOR (module->data, snode) { - yang_snodes_iterate(snode, func, flags, arg1, arg2); + ret = yang_snodes_iterate_subtree(snode, cb, flags, arg); + if (ret == YANG_ITER_STOP) + return ret; } for (uint8_t i = 0; i < module->augment_size; i++) { - yang_snodes_iterate( - (const struct lys_node *)&module->augment[i], func, - flags, arg1, arg2); + ret = yang_snodes_iterate_subtree( + (const struct lys_node *)&module->augment[i], cb, flags, + arg); + if (ret == YANG_ITER_STOP) + return ret; } + + return ret; } -void yang_all_snodes_iterate(void (*func)(const struct lys_node *, void *, - void *), - uint16_t flags, void *arg1, void *arg2) +int yang_snodes_iterate_all(yang_iterate_cb cb, uint16_t flags, void *arg) { struct yang_module *module; + int ret = YANG_ITER_CONTINUE; - RB_FOREACH (module, yang_modules, &yang_modules) - yang_module_snodes_iterate(module->info, func, flags, arg1, - arg2); + RB_FOREACH (module, yang_modules, &yang_modules) { + ret = yang_snodes_iterate_module(module->info, cb, flags, arg); + if (ret == YANG_ITER_STOP) + return ret; + } + + return ret; } void yang_snode_get_path(const struct lys_node *snode, enum yang_path_type type, @@ -324,7 +346,7 @@ const struct lys_type *yang_snode_get_type(const struct lys_node *snode) struct lys_node_leaf *sleaf = (struct lys_node_leaf *)snode; struct lys_type *type; - if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) + if (!CHECK_FLAG(sleaf->nodetype, LYS_LEAF | LYS_LEAFLIST)) return NULL; type = &sleaf->type; @@ -463,7 +485,7 @@ bool yang_dnode_is_default_recursive(const struct lyd_node *dnode) struct lyd_node *root, *next, *dnode_iter; snode = dnode->schema; - if (snode->nodetype & (LYS_LEAF | LYS_LEAFLIST)) + if (CHECK_FLAG(snode->nodetype, LYS_LEAF | LYS_LEAFLIST)) return yang_dnode_is_default(dnode, NULL); if (!yang_dnode_is_default(dnode, NULL)) @@ -489,7 +511,7 @@ void yang_dnode_change_leaf(struct lyd_node *dnode, const char *value) void yang_dnode_set_entry(const struct lyd_node *dnode, void *entry) { - assert(dnode->schema->nodetype & (LYS_LIST | LYS_CONTAINER)); + assert(CHECK_FLAG(dnode->schema->nodetype, LYS_LIST | LYS_CONTAINER)); lyd_set_private(dnode, entry); } @@ -523,12 +545,18 @@ void *yang_dnode_get_entry(const struct lyd_node *dnode, abort(); } -struct lyd_node *yang_dnode_new(struct ly_ctx *ly_ctx) +struct lyd_node *yang_dnode_new(struct ly_ctx *ly_ctx, bool config_only) { struct lyd_node *dnode; + int options; + + if (config_only) + options = LYD_OPT_CONFIG; + else + options = LYD_OPT_DATA | LYD_OPT_DATA_NO_YANGLIB; dnode = NULL; - if (lyd_validate(&dnode, LYD_OPT_CONFIG, ly_ctx) != 0) { + if (lyd_validate(&dnode, options, ly_ctx) != 0) { /* Should never happen. */ flog_err(EC_LIB_LIBYANG, "%s: lyd_validate() failed", __func__); exit(1); @@ -544,27 +572,17 @@ struct lyd_node *yang_dnode_dup(const struct lyd_node *dnode) void yang_dnode_free(struct lyd_node *dnode) { + while (dnode->parent) + dnode = dnode->parent; lyd_free_withsiblings(dnode); } struct yang_data *yang_data_new(const char *xpath, const char *value) { - const struct lys_node *snode; struct yang_data *data; - snode = ly_ctx_get_node(ly_native_ctx, NULL, xpath, 0); - if (!snode) - snode = ly_ctx_get_node(ly_native_ctx, NULL, xpath, 1); - if (!snode) { - flog_err(EC_LIB_YANG_UNKNOWN_DATA_PATH, - "%s: unknown data path: %s", __func__, xpath); - zlog_backtrace(LOG_ERR); - abort(); - } - data = XCALLOC(MTYPE_YANG_DATA, sizeof(*data)); strlcpy(data->xpath, xpath, sizeof(data->xpath)); - data->snode = snode; if (value) data->value = strdup(value); diff --git a/lib/yang.h b/lib/yang.h index c920060071..3259189e98 100644 --- a/lib/yang.h +++ b/lib/yang.h @@ -69,12 +69,6 @@ struct yang_data { /* XPath identifier of the data element. */ char xpath[XPATH_MAXLEN]; - /* - * Schema information (necessary to interpret certain values like - * enums). - */ - const struct lys_node *snode; - /* Value encoded as a raw string. */ char *value; }; @@ -83,16 +77,8 @@ struct yang_list_keys { /* Number os keys (max: LIST_MAXKEYS). */ uint8_t num; - struct { - /* - * Schema information (necessary to interpret certain values - * like enums). - */ - struct lys_node *snode; - - /* Value encoded as a raw string. */ - char value[LIST_MAXKEYLEN]; - } key[LIST_MAXKEYS]; + /* Value encoded as a raw string. */ + char key[LIST_MAXKEYS][LIST_MAXKEYLEN]; }; enum yang_path_type { @@ -100,14 +86,29 @@ enum yang_path_type { YANG_PATH_DATA, }; -/* Filter non-presence containers. */ -#define YANG_ITER_FILTER_NPCONTAINERS 0x0001 -/* Filter list keys (leafs). */ -#define YANG_ITER_FILTER_LIST_KEYS 0x0002 -/* Filter RPC input/output nodes. */ -#define YANG_ITER_FILTER_INPUT_OUTPUT 0x0004 -/* Filter implicitely created nodes. */ -#define YANG_ITER_FILTER_IMPLICIT 0x0008 +enum yang_iter_flags { + /* Filter non-presence containers. */ + YANG_ITER_FILTER_NPCONTAINERS = (1<<0), + + /* Filter list keys (leafs). */ + YANG_ITER_FILTER_LIST_KEYS = (1<<1), + + /* Filter RPC input/output nodes. */ + YANG_ITER_FILTER_INPUT_OUTPUT = (1<<2), + + /* Filter implicitely created nodes. */ + YANG_ITER_FILTER_IMPLICIT = (1<<3), + + /* Allow iteration over augmentations. */ + YANG_ITER_ALLOW_AUGMENTATIONS = (1<<4), +}; + +/* Callback used by the yang_snodes_iterate_*() family of functions. */ +typedef int (*yang_iterate_cb)(const struct lys_node *snode, void *arg); + +/* Return values of the 'yang_iterate_cb' callback. */ +#define YANG_ITER_CONTINUE 0 +#define YANG_ITER_STOP -1 /* Global libyang context for native FRR models. */ extern struct ly_ctx *ly_native_ctx; @@ -129,6 +130,11 @@ extern struct yang_modules yang_modules; extern struct yang_module *yang_module_load(const char *module_name); /* + * Load all FRR native YANG models. + */ +extern void yang_module_load_all(void); + +/* * Find a YANG module by its name. * * module_name @@ -150,46 +156,66 @@ extern struct yang_module *yang_module_find(const char *module_name); extern void yang_module_embed(struct yang_module_embed *embed); /* + * Iterate recursively over all children of a schema node. + * + * snode + * YANG schema node to operate on. + * + * cb + * Function to call with each schema node. + * + * flags + * YANG_ITER_* flags to control how the iteration is performed. + * + * arg + * Arbitrary argument passed as the second parameter in each call to 'cb'. + * + * Returns: + * The return value of the last called callback. + */ +extern int yang_snodes_iterate_subtree(const struct lys_node *snode, + yang_iterate_cb cb, uint16_t flags, + void *arg); + +/* * Iterate over all libyang schema nodes from the given YANG module. * * module * YANG module to operate on. * - * func + * cb * Function to call with each schema node. * * flags - * YANG_ITER_FILTER_* flags to specify node types that should be filtered. + * YANG_ITER_* flags to control how the iteration is performed. * - * arg1 - * Arbitrary argument passed as the second parameter in each call to 'func'. + * arg + * Arbitrary argument passed as the second parameter in each call to 'cb'. * - * arg2 - * Arbitrary argument passed as the third parameter in each call to 'func'. + * Returns: + * The return value of the last called callback. */ -extern void yang_module_snodes_iterate(const struct lys_module *module, - void (*func)(const struct lys_node *, - void *, void *), - uint16_t flags, void *arg1, void *arg2); +extern int yang_snodes_iterate_module(const struct lys_module *module, + yang_iterate_cb cb, uint16_t flags, + void *arg); /* * Iterate over all libyang schema nodes from all loaded YANG modules. * - * func + * cb * Function to call with each schema node. * * flags - * YANG_ITER_FILTER_* flags to specify node types that should be filtered. + * YANG_ITER_* flags to control how the iteration is performed. * - * arg1 - * Arbitrary argument passed as the second parameter in each call to 'func'. + * arg + * Arbitrary argument passed as the second parameter in each call to 'cb'. * - * arg2 - * Arbitrary argument passed as the third parameter in each call to 'func'. + * Returns: + * The return value of the last called callback. */ -extern void yang_all_snodes_iterate(void (*func)(const struct lys_node *, - void *, void *), - uint16_t flags, void *arg1, void *arg2); +extern int yang_snodes_iterate_all(yang_iterate_cb cb, uint16_t flags, + void *arg); /* * Build schema path or data path of the schema node. @@ -423,10 +449,14 @@ extern void *yang_dnode_get_entry(const struct lyd_node *dnode, * ly_ctx * libyang context to operate on. * + * config + * Specify whether the data node will contain only configuration data (true) + * or both configuration data and state data (false). + * * Returns: * Pointer to newly created libyang data node. */ -extern struct lyd_node *yang_dnode_new(struct ly_ctx *ly_ctx); +extern struct lyd_node *yang_dnode_new(struct ly_ctx *ly_ctx, bool config_only); /* * Duplicate a libyang data node. diff --git a/lib/yang_translator.c b/lib/yang_translator.c index 02da3ebd6a..c3092e56e5 100644 --- a/lib/yang_translator.c +++ b/lib/yang_translator.c @@ -351,7 +351,7 @@ int yang_translate_dnode(const struct yang_translator *translator, int dir, ly_ctx = ly_native_ctx; else ly_ctx = translator->ly_ctx; - new = yang_dnode_new(ly_ctx); + new = yang_dnode_new(ly_ctx, false); /* Iterate over all nodes from the data tree. */ LY_TREE_FOR (*dnode, root) { @@ -400,24 +400,28 @@ error: return YANG_TRANSLATE_FAILURE; } -static void yang_translator_validate_cb(const struct lys_node *snode_custom, - void *arg1, void *arg2) +struct translator_validate_args { + struct yang_translator *translator; + unsigned int errors; +}; + +static int yang_translator_validate_cb(const struct lys_node *snode_custom, + void *arg) { - struct yang_translator *translator = arg1; - unsigned int *errors = arg2; + struct translator_validate_args *args = arg; struct yang_mapping_node *mapping; const struct lys_node *snode_native; const struct lys_type *stype_custom, *stype_native; char xpath[XPATH_MAXLEN]; yang_snode_get_path(snode_custom, YANG_PATH_DATA, xpath, sizeof(xpath)); - mapping = yang_mapping_lookup(translator, YANG_TRANSLATE_TO_NATIVE, - xpath); + mapping = yang_mapping_lookup(args->translator, + YANG_TRANSLATE_TO_NATIVE, xpath); if (!mapping) { flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD, "%s: missing mapping for \"%s\"", __func__, xpath); - *errors += 1; - return; + args->errors += 1; + return YANG_ITER_CONTINUE; } snode_native = @@ -433,12 +437,14 @@ static void yang_translator_validate_cb(const struct lys_node *snode_custom, EC_LIB_YANG_TRANSLATOR_LOAD, "%s: YANG types are incompatible (xpath: \"%s\")", __func__, xpath); - *errors += 1; - return; + args->errors += 1; + return YANG_ITER_CONTINUE; } /* TODO: check if the value spaces are identical. */ } + + return YANG_ITER_CONTINUE; } /* @@ -449,32 +455,36 @@ static unsigned int yang_translator_validate(struct yang_translator *translator) { struct yang_tmodule *tmodule; struct listnode *ln; - unsigned int errors = 0; + struct translator_validate_args args; + + args.translator = translator; + args.errors = 0; for (ALL_LIST_ELEMENTS_RO(translator->modules, ln, tmodule)) { - yang_module_snodes_iterate( + yang_snodes_iterate_module( tmodule->module, yang_translator_validate_cb, YANG_ITER_FILTER_NPCONTAINERS | YANG_ITER_FILTER_LIST_KEYS | YANG_ITER_FILTER_INPUT_OUTPUT, - translator, &errors); + &args); } - if (errors) + if (args.errors) flog_warn( EC_LIB_YANG_TRANSLATOR_LOAD, "%s: failed to validate \"%s\" module translator: %u error(s)", - __func__, translator->family, errors); + __func__, translator->family, args.errors); - return errors; + return args.errors; } -static void yang_module_nodes_count_cb(const struct lys_node *snode, void *arg1, - void *arg2) +static int yang_module_nodes_count_cb(const struct lys_node *snode, void *arg) { - unsigned int *total = arg1; + unsigned int *total = arg; *total += 1; + + return YANG_ITER_CONTINUE; } /* Calculate the number of nodes for the given module. */ @@ -482,11 +492,11 @@ static unsigned int yang_module_nodes_count(const struct lys_module *module) { unsigned int total = 0; - yang_module_snodes_iterate(module, yang_module_nodes_count_cb, + yang_snodes_iterate_module(module, yang_module_nodes_count_cb, YANG_ITER_FILTER_NPCONTAINERS | YANG_ITER_FILTER_LIST_KEYS | YANG_ITER_FILTER_INPUT_OUTPUT, - &total, NULL); + &total); return total; } diff --git a/lib/yang_wrappers.c b/lib/yang_wrappers.c index da9d37669b..96076d6468 100644 --- a/lib/yang_wrappers.c +++ b/lib/yang_wrappers.c @@ -840,7 +840,7 @@ void yang_str2ipv4p(const char *value, union prefixptr prefix) } struct yang_data *yang_data_new_ipv4p(const char *xpath, - const union prefixptr prefix) + union prefixconstptr prefix) { char value_str[PREFIX2STR_BUFFER]; @@ -950,7 +950,7 @@ void yang_str2ipv6p(const char *value, union prefixptr prefix) } struct yang_data *yang_data_new_ipv6p(const char *xpath, - const union prefixptr prefix) + union prefixconstptr prefix) { char value_str[PREFIX2STR_BUFFER]; diff --git a/lib/yang_wrappers.h b/lib/yang_wrappers.h index 08a263bac4..5203a033ad 100644 --- a/lib/yang_wrappers.h +++ b/lib/yang_wrappers.h @@ -127,7 +127,7 @@ extern void yang_get_default_ipv4(struct in_addr *var, const char *xpath_fmt, /* ipv4p */ extern void yang_str2ipv4p(const char *value, union prefixptr prefix); extern struct yang_data *yang_data_new_ipv4p(const char *xpath, - const union prefixptr prefix); + union prefixconstptr prefix); extern void yang_dnode_get_ipv4p(union prefixptr prefix, const struct lyd_node *dnode, const char *xpath_fmt, ...); @@ -147,7 +147,7 @@ extern void yang_get_default_ipv6(struct in6_addr *var, const char *xpath_fmt, /* ipv6p */ extern void yang_str2ipv6p(const char *value, union prefixptr prefix); extern struct yang_data *yang_data_new_ipv6p(const char *xpath, - const union prefixptr prefix); + union prefixconstptr prefix); extern void yang_dnode_get_ipv6p(union prefixptr prefix, const struct lyd_node *dnode, const char *xpath_fmt, ...); |
