- Yang deviation [deviation statement not yet support #211](https://github.com/clicon/clixon/issues/211)
- Added "depth" parameter to yang_apply - Added extra API function to yang_cardinality to check individual relation
This commit is contained in:
parent
6e5e53e02e
commit
5a72626aa4
7 changed files with 311 additions and 92 deletions
|
|
@ -513,6 +513,40 @@ ys_prune(yang_stmt *yp,
|
|||
return yc;
|
||||
}
|
||||
|
||||
/*! Remove yang node from parent (dont free
|
||||
* @param[in] ys Yang node to remove
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see ys_prune if parent and position is known
|
||||
* @note Do not call this in a loop of yang children (unless you know what you are doing)
|
||||
*/
|
||||
static int
|
||||
ys_prune_self(yang_stmt *ys)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yp;
|
||||
yang_stmt *yc;
|
||||
int i;
|
||||
|
||||
if ((yp = yang_parent_get(ys)) != NULL){
|
||||
yc = NULL;
|
||||
i = 0;
|
||||
/* Find order of ys in child-list */
|
||||
while ((yc = yn_each(yp, yc)) != NULL) {
|
||||
if (ys == yc)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
if (yc != NULL){
|
||||
assert(yc == ys);
|
||||
ys_prune(yp, i);
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
// done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Free a yang statement tree recursively
|
||||
* @param[in] ys Yang node to remove and all its children recursively
|
||||
* @note does not remove yang node from tree
|
||||
|
|
@ -1555,6 +1589,105 @@ yang_print_cbuf(cbuf *cb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Yang deviation/deviate
|
||||
*
|
||||
* Identify deviation target node, and go through all its deviate statements.
|
||||
* Features/if-feature must have run before
|
||||
* @param[in] ys The yang deviation to populate.
|
||||
* @param[in] h Clicon handle
|
||||
* @see RFC 7950 5.6.3 and 7.20.3
|
||||
*/
|
||||
int
|
||||
yang_deviation(yang_stmt *ys,
|
||||
void *arg)
|
||||
|
||||
{
|
||||
int retval = -1;
|
||||
char *nodeid;
|
||||
yang_stmt *ytarget = NULL;
|
||||
yang_stmt *yd;
|
||||
yang_stmt *yc;
|
||||
yang_stmt *yc1;
|
||||
char *devop;
|
||||
clicon_handle h = (clicon_handle)arg;
|
||||
enum rfc_6020 kw;
|
||||
int min;
|
||||
int max;
|
||||
|
||||
if (yang_keyword_get(ys) != Y_DEVIATION)
|
||||
goto ok;
|
||||
/* Absolute schema node identifier identifying target node */
|
||||
if ((nodeid = yang_argument_get(ys)) == NULL){
|
||||
clicon_err(OE_YANG, EINVAL, "No argument to deviation");
|
||||
goto done;
|
||||
}
|
||||
/* Get target node */
|
||||
if (yang_abs_schema_nodeid(ys, nodeid, &ytarget) < 0)
|
||||
goto done;
|
||||
if (ytarget == NULL){
|
||||
goto ok;
|
||||
/* The RFC does not explicitly say the target node MUST exist
|
||||
clicon_err(OE_YANG, 0, "schemanode sanity check of %s", nodeid);
|
||||
goto done;
|
||||
*/
|
||||
}
|
||||
/* Go through deviates of deviation */
|
||||
yd = NULL;
|
||||
while ((yd = yn_each(ys, yd)) != NULL) {
|
||||
/* description / if-feature / reference */
|
||||
if (yang_keyword_get(yd) != Y_DEVIATE)
|
||||
continue;
|
||||
devop = yang_argument_get(yd);
|
||||
if (strcmp(devop, "not-supported") == 0){
|
||||
if (ys_prune_self(ytarget) < 0)
|
||||
goto done;
|
||||
if (ys_free(ytarget) < 0)
|
||||
goto done;
|
||||
goto ok; /* Target node removed, no other deviates possible */
|
||||
}
|
||||
else if (strcmp(devop, "add") == 0){
|
||||
yc = NULL;
|
||||
while ((yc = yn_each(yd, yc)) != NULL) {
|
||||
/* If a property can only appear once, the property MUST NOT
|
||||
exist in the target node. */
|
||||
kw = yang_keyword_get(yc);
|
||||
if (yang_find(ytarget, kw, NULL) != NULL){
|
||||
if (yang_cardinality_interval(h,
|
||||
yang_keyword_get(ytarget),
|
||||
kw,
|
||||
&min,
|
||||
&max) < 0)
|
||||
goto done;
|
||||
if (max == 1){
|
||||
clicon_err(OE_YANG, 0, "deviation %s: \"%s %s\" added but node already exist in target %s",
|
||||
nodeid,
|
||||
yang_key2str(kw), yang_argument_get(yc),
|
||||
yang_argument_get(ytarget));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
/* Make a copy of deviate child and insert. */
|
||||
if ((yc1 = ys_dup(yc)) == NULL)
|
||||
goto done;
|
||||
if (yn_insert(ytarget, yc1) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else if (strcmp(devop, "replace") == 0){
|
||||
}
|
||||
else if (strcmp(devop, "delete") == 0){
|
||||
}
|
||||
else{ /* Shouldnt happen, lex/yacc takes it */
|
||||
clicon_err(OE_YANG, EINVAL, "%s: invalid deviate operator", devop);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Populate yang leafs after parsing. Create cv and fill it in.
|
||||
*
|
||||
* Populate leaf in 2nd round of yang parsing, now that context is complete:
|
||||
|
|
@ -2507,6 +2640,7 @@ yang_features(clicon_handle h,
|
|||
* @param[in] yn yang node
|
||||
* @param[in] key yang keyword to use as filer or -1 for all
|
||||
* @param[in] fn Callback
|
||||
* @param[in] depth Depth argument: where to start. If <=0 call the calling node yn, if 1 start with its children, etc
|
||||
* @param[in] arg Argument
|
||||
* @retval -1 Error, aborted at first error encounter
|
||||
* @retval 0 OK, all nodes traversed
|
||||
|
|
@ -2516,7 +2650,7 @@ yang_features(clicon_handle h,
|
|||
* {
|
||||
* return 0;
|
||||
* }
|
||||
* yang_apply(ys, Y_TYPE, ys_fn, NULL);
|
||||
* yang_apply(ys, Y_TYPE, ys_fn, 1, NULL); // Call all yn:s children recursively
|
||||
* @endcode
|
||||
* @note do not delete or move around any children during this function
|
||||
*/
|
||||
|
|
@ -2524,6 +2658,7 @@ int
|
|||
yang_apply(yang_stmt *yn,
|
||||
enum rfc_6020 keyword,
|
||||
yang_applyfn_t fn,
|
||||
int depth,
|
||||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -2531,17 +2666,19 @@ yang_apply(yang_stmt *yn,
|
|||
int i;
|
||||
int ret;
|
||||
|
||||
for (i=0; i<yn->ys_len; i++){
|
||||
ys = yn->ys_stmt[i];
|
||||
if ((int)keyword == -1 || keyword == ys->ys_keyword){
|
||||
if ((ret = fn(ys, arg)) < 0)
|
||||
if (depth <= 0){
|
||||
if ((int)keyword == -1 || keyword == yn->ys_keyword){
|
||||
if ((ret = fn(yn, arg)) < 0)
|
||||
goto done;
|
||||
if (ret > 0){
|
||||
retval = ret;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if ((ret = yang_apply(ys, keyword, fn, arg)) < 0)
|
||||
}
|
||||
for (i=0; i<yn->ys_len; i++){
|
||||
ys = yn->ys_stmt[i];
|
||||
if ((ret = yang_apply(ys, keyword, fn, depth-1, arg)) < 0)
|
||||
goto done;
|
||||
if (ret > 0){
|
||||
retval = ret;
|
||||
|
|
@ -2551,7 +2688,7 @@ yang_apply(yang_stmt *yn,
|
|||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
/*! Check if a node is a yang "data node"
|
||||
* @param[in] ys Yang statement node
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue