mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-28 00:27:07 +00:00
Merge pull request #15086 from LabNConsulting/chopps/remove-old-oper-iter-code
lib: remove unused/replaced oper-state iteration code
This commit is contained in:
commit
d04349e7f6
540
lib/northbound.c
540
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,
|
||||
struct lyd_node *pdnode);
|
||||
|
||||
static int nb_node_check_config_only(const struct lysc_node *snode, void *arg)
|
||||
{
|
||||
@ -1811,540 +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,
|
||||
struct lyd_node *pdnode)
|
||||
{
|
||||
const struct lysc_node *child;
|
||||
|
||||
LY_LIST_FOR (lysc_node_child(snode), child) {
|
||||
int ret;
|
||||
|
||||
ret = nb_oper_data_iter_node(child, xpath, list_entry,
|
||||
list_keys, translator, false,
|
||||
flags, cb, arg, pdnode);
|
||||
if (ret != NB_OK)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
static int nb_oper_data_iter_leaf(const struct nb_node *nb_node,
|
||||
const char *xpath, const void *list_entry,
|
||||
const struct yang_list_keys *list_keys,
|
||||
struct yang_translator *translator,
|
||||
uint32_t flags, nb_oper_data_cb cb, void *arg,
|
||||
struct lyd_node *pdnode)
|
||||
{
|
||||
const struct lysc_node *snode = nb_node->snode;
|
||||
struct yang_data *data;
|
||||
LY_ERR err = LY_SUCCESS;
|
||||
|
||||
|
||||
if (CHECK_FLAG(snode->flags, LYS_CONFIG_W))
|
||||
return NB_OK;
|
||||
|
||||
/* Ignore list keys. */
|
||||
if (lysc_is_key(snode))
|
||||
return NB_OK;
|
||||
|
||||
data = nb_callback_get_elem(nb_node, xpath, list_entry);
|
||||
if (data == NULL)
|
||||
/* Leaf of type "empty" is not present. */
|
||||
return NB_OK;
|
||||
|
||||
/*
|
||||
* Add a dnode to our tree
|
||||
*/
|
||||
err = lyd_new_term(pdnode, snode->module, snode->name, data->value,
|
||||
false, NULL);
|
||||
if (err)
|
||||
return NB_ERR_RESOURCE;
|
||||
|
||||
if (cb)
|
||||
return (*cb)(nb_node->snode, translator, data, arg);
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
static int nb_oper_data_iter_container(const struct nb_node *nb_node,
|
||||
const char *xpath, bool first,
|
||||
const void *list_entry,
|
||||
const struct yang_list_keys *list_keys,
|
||||
struct yang_translator *translator,
|
||||
uint32_t flags, nb_oper_data_cb cb,
|
||||
void *arg, struct lyd_node *pdnode)
|
||||
{
|
||||
const struct lysc_node *snode = nb_node->snode;
|
||||
struct lyd_node *cnode = NULL;
|
||||
bool presence = false;
|
||||
LY_ERR err;
|
||||
int ret;
|
||||
|
||||
if (CHECK_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY))
|
||||
return NB_OK;
|
||||
|
||||
if (pdnode->schema == snode)
|
||||
assert(first);
|
||||
else
|
||||
assert(!first);
|
||||
|
||||
/* Read-only presence containers. */
|
||||
if (nb_node->cbs.get_elem) {
|
||||
struct yang_data *data;
|
||||
int ret;
|
||||
|
||||
presence = true;
|
||||
data = nb_callback_get_elem(nb_node, xpath, list_entry);
|
||||
if (data == NULL)
|
||||
/* Presence container is not present. */
|
||||
return NB_OK;
|
||||
|
||||
if (!first) {
|
||||
err = lyd_new_inner(pdnode, snode->module, snode->name,
|
||||
false, &cnode);
|
||||
if (err)
|
||||
return NB_ERR_RESOURCE;
|
||||
}
|
||||
|
||||
if (cb) {
|
||||
ret = (*cb)(snode, translator, data, arg);
|
||||
if (ret != NB_OK)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (first)
|
||||
cnode = pdnode;
|
||||
else if (!cnode) {
|
||||
/* Add a node in for this container in-case we have children. */
|
||||
err = lyd_new_inner(pdnode, snode->module, snode->name, false,
|
||||
&cnode);
|
||||
if (err)
|
||||
return NB_ERR_RESOURCE;
|
||||
}
|
||||
|
||||
/* Iterate over the child nodes. */
|
||||
ret = nb_oper_data_iter_children(snode, xpath, list_entry, list_keys,
|
||||
translator, false, flags, cb, arg,
|
||||
cnode);
|
||||
|
||||
/* TODO: here we are freeing only if we created; however, we may want to
|
||||
* also free if pdnode was cnode on entry to cleanup the data tree
|
||||
*/
|
||||
/* If we aren't presence container and we gained no children remove */
|
||||
if (!presence && !first && !lyd_child(cnode))
|
||||
lyd_free_tree(cnode);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nb_oper_data_iter_leaflist(const struct nb_node *nb_node, const char *xpath,
|
||||
const void *parent_list_entry,
|
||||
const struct yang_list_keys *parent_list_keys,
|
||||
struct yang_translator *translator, uint32_t flags,
|
||||
nb_oper_data_cb cb, void *arg,
|
||||
struct lyd_node *pdnode)
|
||||
{
|
||||
const struct lysc_node *snode = nb_node->snode;
|
||||
const void *list_entry = NULL;
|
||||
LY_ERR err;
|
||||
|
||||
if (CHECK_FLAG(snode->flags, LYS_CONFIG_W))
|
||||
return NB_OK;
|
||||
|
||||
do {
|
||||
struct yang_data *data;
|
||||
int ret;
|
||||
|
||||
list_entry = nb_callback_get_next(nb_node, parent_list_entry,
|
||||
list_entry);
|
||||
if (!list_entry)
|
||||
/* End of the list. */
|
||||
break;
|
||||
|
||||
data = nb_callback_get_elem(nb_node, xpath, list_entry);
|
||||
if (data == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Add a dnode to our tree
|
||||
*/
|
||||
err = lyd_new_term(pdnode, snode->module, snode->name,
|
||||
data->value, false, NULL);
|
||||
if (err)
|
||||
return NB_ERR_RESOURCE;
|
||||
|
||||
if (cb) {
|
||||
ret = (*cb)(nb_node->snode, translator, data, arg);
|
||||
if (ret != NB_OK)
|
||||
return ret;
|
||||
}
|
||||
} while (list_entry);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
static int nb_oper_data_iter_list(const struct nb_node *nb_node,
|
||||
const char *xpath_list,
|
||||
const void *parent_list_entry,
|
||||
const struct yang_list_keys *parent_list_keys,
|
||||
struct yang_translator *translator,
|
||||
uint32_t flags, nb_oper_data_cb cb, void *arg,
|
||||
struct lyd_node *pdnode)
|
||||
{
|
||||
char xpath[XPATH_MAXLEN * 2];
|
||||
const struct lysc_node *snode = nb_node->snode;
|
||||
const void *list_entry = NULL;
|
||||
struct lyd_node *list_node = NULL;
|
||||
const char *key_preds = NULL;
|
||||
uint32_t position = 1;
|
||||
LY_ERR err;
|
||||
|
||||
if (CHECK_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY))
|
||||
return NB_OK;
|
||||
|
||||
/* Iterate over all list entries. */
|
||||
do {
|
||||
struct yang_list_keys list_keys = {};
|
||||
int len, ret;
|
||||
|
||||
/* Obtain list entry. */
|
||||
list_entry = nb_callback_get_next(nb_node, parent_list_entry,
|
||||
list_entry);
|
||||
if (!list_entry)
|
||||
/* End of the list. */
|
||||
break;
|
||||
|
||||
if (!CHECK_FLAG(nb_node->flags, F_NB_NODE_KEYLESS_LIST)) {
|
||||
/* Obtain the list entry keys. */
|
||||
if (nb_callback_get_keys(nb_node, list_entry,
|
||||
&list_keys)
|
||||
!= NB_OK) {
|
||||
flog_warn(EC_LIB_NB_CB_STATE,
|
||||
"%s: failed to get list keys",
|
||||
__func__);
|
||||
return NB_ERR;
|
||||
}
|
||||
|
||||
/* Build XPath of the list entry. */
|
||||
strlcpy(xpath, xpath_list, sizeof(xpath));
|
||||
len = strlen(xpath);
|
||||
key_preds = &xpath[len];
|
||||
|
||||
uint n = yang_get_key_preds(xpath + len, snode,
|
||||
&list_keys,
|
||||
sizeof(xpath) - len);
|
||||
assert(n == list_keys.num);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Keyless list - build XPath using a positional index.
|
||||
*/
|
||||
snprintf(xpath, sizeof(xpath), "%s[%u]", xpath_list,
|
||||
position);
|
||||
position++;
|
||||
}
|
||||
|
||||
/*
|
||||
* `pdnode` needs to point at lib - and it does for
|
||||
* "/frr-vrf:lib/vrf" need to test "/frr-vrf:lib" too though
|
||||
*/
|
||||
err = lyd_new_list2(pdnode, snode->module, snode->name,
|
||||
key_preds, false, &list_node);
|
||||
if (err)
|
||||
return NB_ERR_RESOURCE;
|
||||
|
||||
/* Iterate over the child nodes. */
|
||||
ret = nb_oper_data_iter_children(nb_node->snode, xpath,
|
||||
list_entry, &list_keys,
|
||||
translator, false, flags, cb,
|
||||
arg, list_node);
|
||||
if (ret != NB_OK)
|
||||
return ret;
|
||||
} while (list_entry);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int nb_oper_data_iter_node(const struct lysc_node *snode,
|
||||
const char *xpath_parent, const void *list_entry,
|
||||
const struct yang_list_keys *list_keys,
|
||||
struct yang_translator *translator, bool first,
|
||||
uint32_t flags, nb_oper_data_cb cb, void *arg,
|
||||
struct lyd_node *pdnode)
|
||||
{
|
||||
struct nb_node *nb_node;
|
||||
char xpath[XPATH_MAXLEN];
|
||||
int ret = NB_OK;
|
||||
|
||||
if (!first && CHECK_FLAG(flags, NB_OPER_DATA_ITER_NORECURSE)
|
||||
&& CHECK_FLAG(snode->nodetype, LYS_CONTAINER | LYS_LIST))
|
||||
return NB_OK;
|
||||
|
||||
/*
|
||||
* would be nice to just be building a libyang data tree here as well
|
||||
*/
|
||||
|
||||
/* Update XPath. */
|
||||
strlcpy(xpath, xpath_parent, sizeof(xpath));
|
||||
if (!first && snode->nodetype != LYS_USES) {
|
||||
struct lysc_node *parent;
|
||||
|
||||
/* Get the real parent. */
|
||||
parent = snode->parent;
|
||||
|
||||
/*
|
||||
* When necessary, include the namespace of the augmenting
|
||||
* module.
|
||||
*/
|
||||
if (parent && parent->module != snode->module)
|
||||
snprintf(xpath + strlen(xpath),
|
||||
sizeof(xpath) - strlen(xpath), "/%s:%s",
|
||||
snode->module->name, snode->name);
|
||||
else
|
||||
snprintf(xpath + strlen(xpath),
|
||||
sizeof(xpath) - strlen(xpath), "/%s",
|
||||
snode->name);
|
||||
}
|
||||
|
||||
nb_node = snode->priv;
|
||||
switch (snode->nodetype) {
|
||||
case LYS_CONTAINER:
|
||||
/* does something, then walks children */
|
||||
ret = nb_oper_data_iter_container(nb_node, xpath, first,
|
||||
list_entry, list_keys,
|
||||
translator, flags, cb, arg,
|
||||
pdnode);
|
||||
|
||||
break;
|
||||
case LYS_LEAF:
|
||||
/* does something then returns */
|
||||
ret = nb_oper_data_iter_leaf(nb_node, xpath, list_entry,
|
||||
list_keys, translator, flags, cb,
|
||||
arg, pdnode);
|
||||
break;
|
||||
case LYS_LEAFLIST:
|
||||
/* walks leaf list doing things and returns */
|
||||
ret = nb_oper_data_iter_leaflist(nb_node, xpath, list_entry,
|
||||
list_keys, translator, flags,
|
||||
cb, arg, pdnode);
|
||||
break;
|
||||
case LYS_LIST:
|
||||
/* walks children */
|
||||
ret = nb_oper_data_iter_list(nb_node, xpath, list_entry,
|
||||
list_keys, translator, flags, cb,
|
||||
arg, pdnode);
|
||||
break;
|
||||
case LYS_USES:
|
||||
/* walks children */
|
||||
ret = nb_oper_data_iter_children(snode, xpath, list_entry,
|
||||
list_keys, translator, false,
|
||||
flags, cb, arg, pdnode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nb_xpath_dirname(char *xpath)
|
||||
{
|
||||
int len = strlen(xpath);
|
||||
bool abs = xpath[0] == '/';
|
||||
char *slash;
|
||||
|
||||
/* "//" or "/" => NULL */
|
||||
if (abs && (len == 1 || (len == 2 && xpath[1] == '/')))
|
||||
return NB_ERR_NOT_FOUND;
|
||||
slash = (char *)frrstr_back_to_char(xpath, '/');
|
||||
/* "/foo/bar/" or "/foo/bar//" => "/foo " */
|
||||
if (slash && slash == &xpath[len - 1]) {
|
||||
xpath[--len] = 0;
|
||||
slash = (char *)frrstr_back_to_char(xpath, '/');
|
||||
if (slash && slash == &xpath[len - 1]) {
|
||||
xpath[--len] = 0;
|
||||
slash = (char *)frrstr_back_to_char(xpath, '/');
|
||||
}
|
||||
}
|
||||
if (!slash)
|
||||
return NB_ERR_NOT_FOUND;
|
||||
*slash = 0;
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
static int nb_oper_data_xpath_to_tree(const char *xpath_in,
|
||||
struct lyd_node **dnode,
|
||||
bool is_top_node_list)
|
||||
{
|
||||
/* Eventually this function will loop until it finds a concrete path */
|
||||
char *xpath;
|
||||
LY_ERR err;
|
||||
int ret;
|
||||
|
||||
err = lyd_new_path2(NULL, ly_native_ctx, xpath_in, NULL, 0, 0,
|
||||
LYD_NEW_PATH_UPDATE, NULL, dnode);
|
||||
if (err == LY_SUCCESS)
|
||||
return NB_OK;
|
||||
if (!is_top_node_list)
|
||||
return NB_ERR_NOT_FOUND;
|
||||
|
||||
xpath = XSTRDUP(MTYPE_TMP, xpath_in);
|
||||
ret = nb_xpath_dirname(xpath);
|
||||
if (ret != NB_OK)
|
||||
goto done;
|
||||
|
||||
err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0, 0,
|
||||
LYD_NEW_PATH_UPDATE, NULL, dnode);
|
||||
if (err != LY_SUCCESS)
|
||||
ret = NB_ERR_NOT_FOUND;
|
||||
done:
|
||||
XFREE(MTYPE_TMP, xpath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int nb_oper_data_iterate(const char *xpath, struct yang_translator *translator,
|
||||
uint32_t flags, nb_oper_data_cb cb, void *arg,
|
||||
struct lyd_node **tree)
|
||||
{
|
||||
struct nb_node *nb_node;
|
||||
const void *list_entry = NULL;
|
||||
struct yang_list_keys list_keys;
|
||||
struct list *list_dnodes;
|
||||
struct lyd_node *dnode, *dn;
|
||||
struct listnode *ln;
|
||||
int ret;
|
||||
|
||||
nb_node = nb_node_find(xpath);
|
||||
if (!nb_node) {
|
||||
flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH,
|
||||
"%s: unknown data path: %s", __func__, xpath);
|
||||
return NB_ERR;
|
||||
}
|
||||
|
||||
/* For now this function works only with containers and lists. */
|
||||
if (!CHECK_FLAG(nb_node->snode->nodetype, LYS_CONTAINER | LYS_LIST)) {
|
||||
flog_warn(
|
||||
EC_LIB_NB_OPERATIONAL_DATA,
|
||||
"%s: can't iterate over YANG leaf or leaf-list [xpath %s]",
|
||||
__func__, xpath);
|
||||
return NB_ERR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a data tree from the XPath so that we can parse the keys of
|
||||
* all YANG lists (if any).
|
||||
*/
|
||||
|
||||
ret = nb_oper_data_xpath_to_tree(xpath, &dnode,
|
||||
nb_node->snode->nodetype == LYS_LIST);
|
||||
if (ret) {
|
||||
flog_warn(EC_LIB_LIBYANG,
|
||||
"%s: can't instantiate concrete path using xpath: %s",
|
||||
__func__, xpath);
|
||||
return ret;
|
||||
}
|
||||
assert(dnode);
|
||||
|
||||
/*
|
||||
* Create a linked list to sort the data nodes starting from the root.
|
||||
*/
|
||||
list_dnodes = list_new();
|
||||
for (dn = dnode; dn; dn = lyd_parent(dn))
|
||||
if (dn->schema->nodetype == LYS_LIST)
|
||||
listnode_add_head(list_dnodes, dn);
|
||||
|
||||
/*
|
||||
* Use the northbound callbacks to find list entry pointer corresponding
|
||||
* to the given XPath.
|
||||
*/
|
||||
for (ALL_LIST_ELEMENTS_RO(list_dnodes, ln, dn)) {
|
||||
struct lyd_node *child;
|
||||
struct nb_node *nn;
|
||||
unsigned int n = 0;
|
||||
|
||||
/* Obtain the list entry keys. */
|
||||
memset(&list_keys, 0, sizeof(list_keys));
|
||||
LY_LIST_FOR (lyd_child(dn), child) {
|
||||
if (!lysc_is_key(child->schema))
|
||||
break;
|
||||
strlcpy(list_keys.key[n],
|
||||
yang_dnode_get_string(child, NULL),
|
||||
sizeof(list_keys.key[n]));
|
||||
n++;
|
||||
}
|
||||
list_keys.num = n;
|
||||
if (list_keys.num != yang_snode_num_keys(dn->schema)) {
|
||||
flog_warn(
|
||||
EC_LIB_NB_OPERATIONAL_DATA,
|
||||
"%s: internal list entry '%s' missing required key values predicates in xpath: %s",
|
||||
__func__, dn->schema->name, xpath);
|
||||
list_delete(&list_dnodes);
|
||||
yang_dnode_free(dnode);
|
||||
return NB_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Find the list entry pointer. */
|
||||
nn = dn->schema->priv;
|
||||
if (!nn->cbs.lookup_entry) {
|
||||
flog_warn(
|
||||
EC_LIB_NB_OPERATIONAL_DATA,
|
||||
"%s: data path doesn't support iteration over operational data: %s",
|
||||
__func__, xpath);
|
||||
list_delete(&list_dnodes);
|
||||
yang_dnode_free(dnode);
|
||||
return NB_ERR;
|
||||
}
|
||||
|
||||
/* NOTE: To add support for multiple levels of unspecified keys
|
||||
* we need to loop here using the list entry's get_next to work
|
||||
* with each "existing in the data" list entry. It will be a bit
|
||||
* tricky b/c we are inside a loop here.
|
||||
*/
|
||||
list_entry =
|
||||
nb_callback_lookup_entry(nn, list_entry, &list_keys);
|
||||
if (list_entry == NULL) {
|
||||
list_delete(&list_dnodes);
|
||||
yang_dnode_free(dnode);
|
||||
return NB_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
/* If a list entry was given with keys as the last node in the path,
|
||||
* iterate over that list entry only.
|
||||
*/
|
||||
if (dnode->schema->nodetype == LYS_LIST && lyd_child(dnode)
|
||||
&& dnode->schema == nb_node->snode)
|
||||
ret = nb_oper_data_iter_children(nb_node->snode, xpath,
|
||||
list_entry, &list_keys,
|
||||
translator, true, flags, cb,
|
||||
arg, dnode);
|
||||
else
|
||||
ret = nb_oper_data_iter_node(nb_node->snode, xpath, list_entry,
|
||||
&list_keys, translator, true,
|
||||
flags, cb, arg, dnode);
|
||||
|
||||
list_delete(&list_dnodes);
|
||||
while (lyd_parent(dnode))
|
||||
dnode = lyd_parent(dnode);
|
||||
|
||||
if (tree && ret == NB_OK)
|
||||
*tree = dnode;
|
||||
else {
|
||||
lyd_free_all(dnode);
|
||||
if (tree)
|
||||
*tree = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool nb_operation_is_valid(enum nb_operation operation,
|
||||
const struct lysc_node *snode)
|
||||
{
|
||||
|
@ -1295,11 +1295,6 @@ extern int nb_running_unlock(enum nb_client client, const void *user);
|
||||
*/
|
||||
extern int nb_running_lock_check(enum nb_client client, const void *user);
|
||||
|
||||
extern int nb_oper_data_iterate(const char *xpath,
|
||||
struct yang_translator *translator,
|
||||
uint32_t flags, nb_oper_data_cb cb, void *arg,
|
||||
struct lyd_node **tree);
|
||||
|
||||
/*
|
||||
* Iterate over operational data -- deprecated.
|
||||
*
|
||||
@ -1333,7 +1328,7 @@ extern enum nb_error nb_oper_iterate_legacy(const char *xpath,
|
||||
void *arg, struct lyd_node **tree);
|
||||
|
||||
/**
|
||||
* nb_op_walk() - walk the schema building operational state.
|
||||
* nb_oper_walk() - walk the schema building operational state.
|
||||
* @xpath -
|
||||
* @translator -
|
||||
* @flags -
|
||||
@ -1351,7 +1346,7 @@ extern void *nb_oper_walk(const char *xpath, struct yang_translator *translator,
|
||||
void *finish_arg);
|
||||
|
||||
/**
|
||||
* nb_op_iterate_yielding_cancel() - cancel the in progress walk.
|
||||
* nb_oper_cancel_walk() - cancel the in progress walk.
|
||||
* @walk - value returned from nb_op_iterate_yielding()
|
||||
*
|
||||
* Should only be called on an in-progress walk. It is invalid to cancel and
|
||||
|
Loading…
Reference in New Issue
Block a user