From 27802d3feedc70d69a8986cdbf10fea57f1b2be4 Mon Sep 17 00:00:00 2001 From: vdhingra Date: Fri, 24 Apr 2020 05:36:14 -0700 Subject: [PATCH] lib : Yang wrappers 1. To get the parent node 2. To auto delete the parent when last node in list gets deleted Signed-off-by: VishalDhingra --- lib/yang.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/yang.h | 53 +++++++++++++++++++- 2 files changed, 196 insertions(+), 1 deletion(-) diff --git a/lib/yang.c b/lib/yang.c index 0714ddf7bb..db99c0339e 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -749,3 +749,147 @@ void yang_terminate(void) ly_ctx_destroy(ly_native_ctx, NULL); } + +const struct lyd_node *yang_dnode_get_parent(const struct lyd_node *dnode, + const char *name) +{ + const struct lyd_node *orig_dnode = dnode; + + while (orig_dnode) { + switch (orig_dnode->schema->nodetype) { + case LYS_LIST: + case LYS_CONTAINER: + if (!strcmp(orig_dnode->schema->name, name)) + return orig_dnode; + break; + default: + break; + } + + orig_dnode = orig_dnode->parent; + } + + return NULL; +} + +/* API to check if the given node is last node in the list */ +static bool yang_is_last_list_dnode(const struct lyd_node *dnode) +{ + return (((dnode->next == NULL) + || (dnode->next + && (strcmp(dnode->next->schema->name, dnode->schema->name) + != 0))) + && dnode->prev + && ((dnode->prev == dnode) + || (strcmp(dnode->prev->schema->name, dnode->schema->name) + != 0))); +} + +/* API to check if the given node is last node in the data tree level */ +static bool yang_is_last_level_dnode(const struct lyd_node *dnode) +{ + const struct lyd_node *parent; + const struct lys_node_list *snode; + const struct lyd_node *key_leaf; + uint8_t keys_size; + + switch (dnode->schema->nodetype) { + case LYS_LIST: + assert(dnode->parent); + parent = dnode->parent; + snode = (struct lys_node_list *)parent->schema; + key_leaf = dnode->prev; + for (keys_size = 1; keys_size < snode->keys_size; keys_size++) + key_leaf = key_leaf->prev; + if (key_leaf->prev == dnode) + return true; + break; + case LYS_CONTAINER: + return true; + default: + break; + } + + return false; +} + + +const struct lyd_node * +yang_get_subtree_with_no_sibling(const struct lyd_node *dnode) +{ + bool parent = true; + const struct lyd_node *node; + const struct lys_node_container *snode; + + node = dnode; + if (node->schema->nodetype != LYS_LIST) + return node; + + while (parent) { + switch (node->schema->nodetype) { + case LYS_CONTAINER: + snode = (struct lys_node_container *)node->schema; + if ((!snode->presence) + && yang_is_last_level_dnode(node)) { + if (node->parent + && (node->parent->schema->module + == dnode->schema->module)) + node = node->parent; + else + parent = false; + } else + parent = false; + break; + case LYS_LIST: + if (yang_is_last_list_dnode(node) + && yang_is_last_level_dnode(node)) { + if (node->parent + && (node->parent->schema->module + == dnode->schema->module)) + node = node->parent; + else + parent = false; + } else + parent = false; + break; + default: + parent = false; + break; + } + } + return node; +} + +uint32_t yang_get_list_pos(const struct lyd_node *node) +{ + return lyd_list_pos(node); +} + +uint32_t yang_get_list_elements_count(const struct lyd_node *node) +{ + unsigned int count; + struct lys_node *schema; + + if (!node + || ((node->schema->nodetype != LYS_LIST) + && (node->schema->nodetype != LYS_LEAFLIST))) { + return 0; + } + + schema = node->schema; + count = 0; + do { + if (node->schema == schema) + ++count; + node = node->next; + } while (node); + return count; +} + + +const struct lyd_node *yang_dnode_get_child(const struct lyd_node *dnode) +{ + if (dnode) + return dnode->child; + return NULL; +} diff --git a/lib/yang.h b/lib/yang.h index 85ef0d758c..d526d2f5d6 100644 --- a/lib/yang.h +++ b/lib/yang.h @@ -34,7 +34,7 @@ extern "C" { #endif /* Maximum XPath length. */ -#define XPATH_MAXLEN 512 +#define XPATH_MAXLEN 1024 /* Maximum list key length. */ #define LIST_MAXKEYS 8 @@ -551,6 +551,57 @@ extern void yang_init(bool embedded_modules); */ extern void yang_terminate(void); +/* + * API to return the parent dnode having a given schema-node name + * Use case: One has to access the parent dnode's private pointer + * for a given child node. + * For that there is a need to find parent dnode first. + * + * dnode The starting node to work on + * + * name The name of container/list schema-node + * + * Returns The dnode matched with the given name + */ +extern const struct lyd_node * +yang_dnode_get_parent(const struct lyd_node *dnode, const char *name); + + +/* + * In some cases there is a need to auto delete the parent nodes + * if the given node is last in the list. + * It tries to delete all the parents in a given tree in a given module. + * The use case is with static routes and route maps + * example : ip route 1.1.1.1/32 ens33 + * ip route 1.1.1.1/32 ens34 + * After this no ip route 1.1.1.1/32 ens34 came, now staticd + * has to find out upto which level it has to delete the dnodes. + * For this case it has to send delete nexthop + * After this no ip route 1.1.1.1/32 ens33 came, now staticd has to + * clear nexthop, path and route nodes. + * The same scheme is required for routemaps also + * dnode The starting node to work on + * + * Returns The final parent node selected for deletion + */ +extern const struct lyd_node * +yang_get_subtree_with_no_sibling(const struct lyd_node *dnode); + +/* To get the relative position of a node in list */ +extern uint32_t yang_get_list_pos(const struct lyd_node *node); + +/* To get the number of elements in a list + * + * dnode : The head of list + * Returns : The number of dnodes present in the list + */ +extern uint32_t yang_get_list_elements_count(const struct lyd_node *node); + + +/* To get the immediate child of a dnode */ +const struct lyd_node *yang_dnode_get_child(const struct lyd_node *dnode); + + #ifdef __cplusplus } #endif -- 2.39.5