Optmize YANG memory: Yang-type cache only for original trees

This commit is contained in:
Olof hagsand 2024-08-13 13:30:28 +02:00
parent 9da4939ee0
commit bd5214dde1
4 changed files with 109 additions and 180 deletions

View file

@ -16,9 +16,10 @@ Expected: October 2024
### Features ### Features
* Added YANG struct memory optimization * Optimize YANG memory
* Added union and extended struct for uncommon fields * Added union and extended struct for uncommon fields
* Removed per-object YANG linenr info * Removed per-object YANG linenr info
* Yang-type cache only for original trees (not derived via grouping/augment)
* New: [CLI simple alias](https://github.com/clicon/cligen/issues/112) * New: [CLI simple alias](https://github.com/clicon/cligen/issues/112)
* See: https://clixon-docs.readthedocs.io/en/latest/cli.html#cli-aliases * See: https://clixon-docs.readthedocs.io/en/latest/cli.html#cli-aliases
* List pagination: Added where, sort-by and direction parameter for configured data * List pagination: Added where, sort-by and direction parameter for configured data

View file

@ -320,11 +320,10 @@ int yang_config_ancestor(yang_stmt *ys);
int yang_features(clixon_handle h, yang_stmt *yt); int yang_features(clixon_handle h, yang_stmt *yt);
cvec *yang_arg2cvec(yang_stmt *ys, char *delimi); cvec *yang_arg2cvec(yang_stmt *ys, char *delimi);
int yang_key_match(yang_stmt *yn, char *name, int *lastkey); int yang_key_match(yang_stmt *yn, char *name, int *lastkey);
int yang_type_cache_regexp_set(yang_stmt *ytype, int rxmode, cvec *regexps);
int yang_type_cache_get2(yang_stmt *ytype, yang_stmt **resolved, int *options, int yang_type_cache_get2(yang_stmt *ytype, yang_stmt **resolved, int *options,
cvec **cvv, cvec *patterns, int *rxmode, cvec *regexps, uint8_t *fraction); cvec **cvv, cvec *patterns, cvec *regexps, uint8_t *fraction);
int yang_type_cache_set2(yang_stmt *ys, yang_stmt *resolved, int options, cvec *cvv, int yang_type_cache_set2(yang_stmt *ys, yang_stmt *resolved, int options, cvec *cvv,
cvec *patterns, uint8_t fraction); cvec *patterns, uint8_t fraction, int rxmode, cvec *regexps);
yang_stmt *yang_anydata_add(yang_stmt *yp, char *name); yang_stmt *yang_anydata_add(yang_stmt *yp, char *name);
int yang_extension_value(yang_stmt *ys, char *name, char *ns, int *exist, char **value); int yang_extension_value(yang_stmt *ys, char *name, char *ns, int *exist, char **value);
int yang_sort_subelements(yang_stmt *ys); int yang_sort_subelements(yang_stmt *ys);

View file

@ -180,7 +180,6 @@ static map_ptr2ptr *_yang_mymodule_map = NULL;
/* Forward static */ /* Forward static */
static int yang_type_cache_free(yang_type_cache *ycache); static int yang_type_cache_free(yang_type_cache *ycache);
static int yang_type_cache_cp(yang_stmt *ynew, yang_stmt *yold);
/* Access functions /* Access functions
*/ */
@ -1071,30 +1070,40 @@ yn_realloc(yang_stmt *yn)
* Comments includes for: * Comments includes for:
* - nodes that could not be skipped and the failed test * - nodes that could not be skipped and the failed test
* - nodes that have children in turn * - nodes that have children in turn
* - nodes that can be refined
* @note RFC 7950 Sec 7.13.2. The "refine" Statement can change the following nodes
* - default values
* - description
* - reference
* - config
* - mandatory
* - presence
* - min/max-elements
* - if-feature
*/ */
static int static int
uses_orig_ptr(enum rfc_6020 keyword) uses_orig_ptr(enum rfc_6020 keyword)
{ {
return return
// keyword == Y_CONFIG // NO (test_openconfig.sh) // keyword == Y_CONFIG // NO (test_openconfig.sh) + refine
// keyword == Y_DEFAULT // NO (test_augment.sh) // keyword == Y_DEFAULT // NO (test_augment.sh) + refine
keyword == Y_DESCRIPTION keyword == Y_DESCRIPTION // XXX refine
|| keyword == Y_ENUM // children || keyword == Y_ENUM // children
|| keyword == Y_ERROR_APP_TAG || keyword == Y_ERROR_APP_TAG
|| keyword == Y_ERROR_MESSAGE || keyword == Y_ERROR_MESSAGE
|| keyword == Y_FRACTION_DIGITS || keyword == Y_FRACTION_DIGITS
// || keyword == Y_KEY // NO // || keyword == Y_KEY // NO
|| keyword == Y_LENGTH // children || keyword == Y_LENGTH // children
|| keyword == Y_MANDATORY || keyword == Y_MANDATORY // XXX refine
|| keyword == Y_MAX_ELEMENTS || keyword == Y_MAX_ELEMENTS // XXX refine
|| keyword == Y_MIN_ELEMENTS || keyword == Y_MIN_ELEMENTS // XXX refine
|| keyword == Y_MODIFIER || keyword == Y_MODIFIER
|| keyword == Y_ORDERED_BY || keyword == Y_ORDERED_BY
|| keyword == Y_PATH || keyword == Y_PATH
|| keyword == Y_PATTERN // children || keyword == Y_PATTERN // children
|| keyword == Y_POSITION || keyword == Y_POSITION
|| keyword == Y_PREFIX || keyword == Y_PREFIX
|| keyword == Y_PRESENCE || keyword == Y_PRESENCE // XXX refine
|| keyword == Y_RANGE // children || keyword == Y_RANGE // children
|| keyword == Y_REQUIRE_INSTANCE || keyword == Y_REQUIRE_INSTANCE
|| keyword == Y_STATUS || keyword == Y_STATUS
@ -1163,11 +1172,8 @@ ys_cp_one(yang_stmt *ynew,
} }
switch (yold->ys_keyword) { /* type-specifi union fields */ switch (yold->ys_keyword) { /* type-specifi union fields */
case Y_TYPE: case Y_TYPE:
if (yang_typecache_get(yold)){ if (yang_typecache_get(yold)) /* Dont copy type cache, use only original */
yang_typecache_set(ynew, NULL); yang_typecache_set(ynew, NULL);
if (yang_type_cache_cp(ynew, yold) < 0)
goto done;
}
break; break;
default: default:
break; break;
@ -2503,10 +2509,10 @@ ys_populate_leaf(clixon_handle h,
int cvret; int cvret;
int ret; int ret;
char *reason = NULL; char *reason = NULL;
yang_stmt *yrestype; /* resolved type */ yang_stmt *yrestype = NULL; /* resolved type */
char *restype; /* resolved type */ char *restype; /* resolved type */
char *origtype=NULL; /* original type */ char *origtype=NULL; /* original type */
uint8_t fraction_digits; uint8_t fraction_digits = 0;
int options = 0x0; int options = 0x0;
yang_stmt *ytypedef; /* where type is define */ yang_stmt *ytypedef; /* where type is define */
@ -3275,6 +3281,12 @@ ys_populate(yang_stmt *ys,
/*! Run after grouping expand and augment /*! Run after grouping expand and augment
* *
* Run in yang_apply but also other places
* @param[in] yn yang node
* @param[in] arg Argument
* @retval n OK, abort traversal and return to caller with "n"
* @retval 0 OK, continue with next
* @retval -1 Error, abort
* @see ys_populate run before grouping expand and augment * @see ys_populate run before grouping expand and augment
*/ */
int int
@ -3287,6 +3299,11 @@ ys_populate2(yang_stmt *ys,
int ret; int ret;
switch(ys->ys_keyword){ switch(ys->ys_keyword){
case Y_AUGMENT:
case Y_GROUPING:
retval = 2; /* Skip sub-tree */
goto done;
break;
case Y_LEAF: case Y_LEAF:
case Y_LEAF_LIST: case Y_LEAF_LIST:
if (ys_populate_leaf(h, ys) < 0) if (ys_populate_leaf(h, ys) < 0)
@ -3828,7 +3845,6 @@ yang_arg2cvec(yang_stmt *ys,
return cvv; return cvv;
} }
/*! Check if yang node yn has key-stmt as child which matches name /*! Check if yang node yn has key-stmt as child which matches name
* *
* The function looks at the LIST argument string (not actual children) * The function looks at the LIST argument string (not actual children)
@ -3883,7 +3899,6 @@ yang_key_match(yang_stmt *yn,
* @param[in] rxmode Which regexp engine to use, see enum regexp_mode * @param[in] rxmode Which regexp engine to use, see enum regexp_mode
* @retval 0 OK * @retval 0 OK
* @retval -1 Error * @retval -1 Error
* @see yang_type_cache_regexp_set where cache is extended w compiled regexps
*/ */
int int
yang_type_cache_set2(yang_stmt *ys, yang_type_cache_set2(yang_stmt *ys,
@ -3891,7 +3906,9 @@ yang_type_cache_set2(yang_stmt *ys,
int options, int options,
cvec *cvv, cvec *cvv,
cvec *patterns, cvec *patterns,
uint8_t fraction) uint8_t fraction,
int rxmode,
cvec *regexps)
{ {
int retval = -1; int retval = -1;
yang_type_cache *ycache; yang_type_cache *ycache;
@ -3919,45 +3936,13 @@ yang_type_cache_set2(yang_stmt *ys,
goto done; goto done;
} }
ycache->yc_fraction = fraction; ycache->yc_fraction = fraction;
retval = 0; if (regexps != NULL) {
done:
return retval;
}
/*! Extend yang type cache with compiled regexps
*
* Compiled Regexps are computed in validate code - after initial cache set
* @param[in] ytype YANG type statement
* @param[in] rxmode Which regexp engine to use, see enum regexp_mode
* @param[in] regexps
* @retval 0 OK
* @retval -1 Error
*/
int
yang_type_cache_regexp_set(yang_stmt *ytype,
int rxmode,
cvec *regexps)
{
int retval = -1;
yang_type_cache *ycache;
if (regexps == NULL || yang_keyword_get(ytype) != Y_TYPE) {
clixon_err(OE_YANG, EINVAL, "regexps is NULL, or are already set, or ytype is not YTYPE");
goto done;
}
if ((ycache = ytype->ys_typecache) == NULL){
clixon_err(OE_YANG, 0, "Typecache is NULL");
goto done;
}
if (ycache->yc_regexps != NULL){
clixon_err(OE_YANG, 0, "regexp is already set");
goto done;
}
ycache->yc_rxmode = rxmode; ycache->yc_rxmode = rxmode;
if ((ycache->yc_regexps = cvec_dup(regexps)) == NULL){ if ((ycache->yc_regexps = cvec_dup(regexps)) == NULL){
clixon_err(OE_UNIX, errno, "cvec_dup"); clixon_err(OE_UNIX, errno, "cvec_dup");
goto done; goto done;
} }
}
retval = 0; retval = 0;
done: done:
return retval; return retval;
@ -3977,7 +3962,6 @@ yang_type_cache_get2(yang_stmt *ytype,
int *options, int *options,
cvec **cvv, cvec **cvv,
cvec *patterns, cvec *patterns,
int *rxmode,
cvec *regexps, cvec *regexps,
uint8_t *fraction) uint8_t *fraction)
{ {
@ -4006,8 +3990,6 @@ yang_type_cache_get2(yang_stmt *ytype,
while ((cv = cvec_each(ycache->yc_regexps, cv)) != NULL) while ((cv = cvec_each(ycache->yc_regexps, cv)) != NULL)
cvec_append_var(regexps, cv); cvec_append_var(regexps, cv);
} }
if (rxmode)
*rxmode = ycache->yc_rxmode;
if (fraction) if (fraction)
*fraction = ycache->yc_fraction; *fraction = ycache->yc_fraction;
retval = 1; /* cache exists and is returned OK */ retval = 1; /* cache exists and is returned OK */
@ -4015,40 +3997,6 @@ yang_type_cache_get2(yang_stmt *ytype,
return retval; return retval;
} }
/*! Copy yang type cache
*/
static int
yang_type_cache_cp(yang_stmt *ynew,
yang_stmt *yold)
{
int retval = -1;
int options;
cvec *cvv;
cvec *patterns = NULL;
uint8_t fraction;
yang_stmt *resolved;
int ret;
if ((patterns = cvec_new(0)) == NULL){
clixon_err(OE_UNIX, errno, "cvec_new");
goto done;
}
/* Note, regexps are not copied since they are voids, if they were, they
* could not be freed in a simple way since copies are made at augment/group
*/
if ((ret = yang_type_cache_get2(yold,
&resolved, &options, &cvv, patterns, NULL, NULL, &fraction)) < 0)
goto done;
if (ret == 1 &&
yang_type_cache_set2(ynew, resolved, options, cvv, patterns, fraction) < 0)
goto done;
retval = 0;
done:
if (patterns)
cvec_free(patterns);
return retval;
}
/*! Free yang type cache /*! Free yang type cache
*/ */
static int static int
@ -4252,7 +4200,6 @@ yang_sort_subelements(yang_stmt *ys)
#endif #endif
} }
#ifdef XML_EXPLICIT_INDEX #ifdef XML_EXPLICIT_INDEX
/*! Mark element as search_index in list /*! Mark element as search_index in list
* *

View file

@ -34,7 +34,7 @@
* Yang type related functions * Yang type related functions
* Part of this is type resolving which is pretty complex * Part of this is type resolving which is pretty complex
* +--> yang_type_cache_set * +--> yang_type_cache_set2
* (called at parse) | * (called at parse) |
* ys_resolve_type --+ ys_populate_range, yang_enum_int_value(NULL) * ys_resolve_type --+ ys_populate_range, yang_enum_int_value(NULL)
* \ | cml * \ | cml
@ -44,11 +44,10 @@
* ^ ^ ^ ^ * ^ ^ ^ ^
* | | | | * | | | |
* | yang2cli_var | yang2cli_var_union_one * | yang2cli_var | yang2cli_var_union_one
* ys_cv_validate---+ ys_cv_validate_union_one * ys_cv_validate
* | \ / * |
* | \ / yang_type_cache_regexp_set * ys_populate_leaf,
* ys_populate_leaf, +--> compile_pattern2regexp (compile regexps) * xml_cv_cache (NULL)
* xml_cv_cache (NULL) +--> cv_validate1 --> cv_validate_pattern (exec regexps)
* yang_type2cv (simplified) * yang_type2cv (simplified)
* *
* NOTE * NOTE
@ -231,18 +230,19 @@ compile_pattern2regexp(clixon_handle h,
* @note unions not cached * @note unions not cached
*/ */
int int
ys_resolve_type(yang_stmt *ys, ys_resolve_type(yang_stmt *ytype,
void *arg) void *arg)
{ {
// clixon_handle h = (clixon_handle)arg; clixon_handle h = (clixon_handle)arg;
int retval = -1; int retval = -1;
int options = 0x0; int options = 0x0;
cvec *cvv = NULL; cvec *cvv = NULL;
cvec *patterns = NULL; cvec *patterns = NULL;
uint8_t fraction = 0; uint8_t fraction = 0;
yang_stmt *resolved = NULL; yang_stmt *resolved = NULL;
cvec *regexps = NULL;
if (yang_keyword_get(ys) != Y_TYPE){ if (yang_keyword_get(ytype) != Y_TYPE){
clixon_err(OE_YANG, EINVAL, "Expected Y_TYPE"); clixon_err(OE_YANG, EINVAL, "Expected Y_TYPE");
goto done; goto done;
} }
@ -250,25 +250,35 @@ ys_resolve_type(yang_stmt *ys,
clixon_err(OE_UNIX, errno, "cvec_new"); clixon_err(OE_UNIX, errno, "cvec_new");
goto done; goto done;
} }
/* Recursively resolve ys -> resolve with restrictions(options, etc) /* Recursively resolve ytype -> resolve with restrictions(options, etc)
* Note that the resolved type could be ys itself. * Note that the resolved type could be ytype itself.
*/ */
if (yang_type_resolve(yang_parent_get(ys), yang_parent_get(ys), if (yang_type_resolve(yang_parent_get(ytype), yang_parent_get(ytype),
ys, &resolved, ytype, &resolved,
&options, &cvv, patterns, NULL, &fraction) < 0) &options, &cvv, patterns, NULL, &fraction) < 0){
goto done; goto done;
}
if (resolved == NULL){ if (resolved == NULL){
clixon_err(OE_YANG, 0, "result-type should not be NULL"); clixon_err(OE_YANG, 0, "result-type should not be NULL");
goto done; goto done;
} }
/* Cache the type resolving locally. Only place where this is done. /* Cache the type resolving locally. Only place where this is done.
* Why not do it in yang_type_resolve? (compile regexps needs clixon_handle) * Compile / initialize pattern regexp cache */
*/ if (cvec_len(patterns) > 0) {
if (yang_type_cache_set2(ys, resolved, options, cvv, if ((regexps = cvec_new(0)) == NULL){
patterns, fraction) < 0) clixon_err(OE_UNIX, errno, "cvec_new");
goto done;
}
if (compile_pattern2regexp(h, patterns, regexps) < 1)
goto done;
}
if (yang_type_cache_set2(ytype, resolved, options, cvv,
patterns, fraction, clicon_yang_regexp(h), regexps) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:
if (regexps)
cvec_free(regexps);
if (patterns) if (patterns)
cvec_free(patterns); cvec_free(patterns);
return retval; return retval;
@ -887,17 +897,6 @@ ys_cv_validate_union_one(clixon_handle h,
} }
if (retval == 0) if (retval == 0)
goto done; goto done;
/* The regexp cache may be invalidated, in that case re-compile
* eg due to copying
*/
if (cvec_len(patterns)!=0 && cvec_len(regexps)==0){
if (compile_pattern2regexp(h, patterns, regexps) < 1)
goto done;
if (yang_type_cache_regexp_set(yt,
clicon_yang_regexp(h),
regexps) < 0)
goto done;
}
if ((retval = cv_validate1(h, cvt, cvtype, options, cvv, if ((retval = cv_validate1(h, cvt, cvtype, options, cvv,
regexps, yrestype, restype, reason)) < 0) regexps, yrestype, restype, reason)) < 0)
goto done; goto done;
@ -1001,12 +1000,12 @@ ys_cv_validate(clixon_handle h,
cvec *regexps = NULL; cvec *regexps = NULL;
enum cv_type cvtype; enum cv_type cvtype;
char *origtype = NULL; /* orig type */ char *origtype = NULL; /* orig type */
yang_stmt *yrestype; /* resolved type */ yang_stmt *yrestype = NULL; /* resolved type */
char *restype; char *restype;
uint8_t fraction = 0; uint8_t fraction = 0;
int retval2; int retval2;
char *val; char *val;
cg_var *cvt=NULL; cg_var *cvt = NULL;
if (reason) if (reason)
*reason=NULL; *reason=NULL;
@ -1015,23 +1014,23 @@ ys_cv_validate(clixon_handle h,
goto done; goto done;
} }
ycv = yang_cv_get(ys); ycv = yang_cv_get(ys);
if ((regexps = cvec_new(0)) == NULL){ if ((patterns = cvec_new(0)) == NULL){
clixon_err(OE_UNIX, errno, "cvec_new"); clixon_err(OE_UNIX, errno, "cvec_new");
goto done; goto done;
} }
if ((patterns = cvec_new(0)) == NULL){ if ((regexps = cvec_new(0)) == NULL){
clixon_err(OE_UNIX, errno, "cvec_new"); clixon_err(OE_UNIX, errno, "cvec_new");
goto done; goto done;
} }
if (yang_type_get(ys, &origtype, &yrestype, if (yang_type_get(ys, &origtype, &yrestype,
&options, &cvv, &options, &cvv,
patterns, regexps, patterns,
regexps,
&fraction) < 0) &fraction) < 0)
goto done; goto done;
restype = yrestype?yang_argument_get(yrestype):NULL; restype = yrestype?yang_argument_get(yrestype):NULL;
if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0) if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0)
goto done; goto done;
if (cv_type_get(ycv) != cvtype){ if (cv_type_get(ycv) != cvtype){
/* special case: dbkey has rest syntax-> cv but yang cant have that */ /* special case: dbkey has rest syntax-> cv but yang cant have that */
if (cvtype == CGV_STRING && cv_type_get(ycv) == CGV_REST) if (cvtype == CGV_STRING && cv_type_get(ycv) == CGV_REST)
@ -1058,19 +1057,6 @@ ys_cv_validate(clixon_handle h,
retval = retval2; /* invalid (0) with latest reason or valid 1 */ retval = retval2; /* invalid (0) with latest reason or valid 1 */
} }
else{ else{
/* The regexp cache may be invalidated, in that case re-compile
* eg due to copying
*/
if (cvec_len(patterns)!=0 && cvec_len(regexps)==0){
yang_stmt *yt;
if (compile_pattern2regexp(h, patterns, regexps) < 1)
goto done;
yt = yang_find(ys, Y_TYPE, NULL);
if (yang_type_cache_regexp_set(yt,
clicon_yang_regexp(h),
regexps) < 0)
goto done;
}
/* Leafref needs to resolve referred node for type information /* Leafref needs to resolve referred node for type information
* From rfc7950 Sec 9.9: * From rfc7950 Sec 9.9:
* The leafref built-in type is restricted to the value space of some * The leafref built-in type is restricted to the value space of some
@ -1329,11 +1315,11 @@ yang_type_resolve(yang_stmt *yorig,
cvec *regexps, cvec *regexps,
uint8_t *fraction) uint8_t *fraction)
{ {
int retval = -1;
yang_stmt *rytypedef = NULL; /* Resolved typedef of ytype */ yang_stmt *rytypedef = NULL; /* Resolved typedef of ytype */
yang_stmt *rytype; /* Resolved type of ytype */ yang_stmt *rytype; /* Resolved type of ytype */
char *type = NULL; char *type = NULL;
char *prefix = NULL; char *prefix = NULL;
int retval = -1;
yang_stmt *yn; yang_stmt *yn;
yang_stmt *yrmod; /* module where resolved type is looked for */ yang_stmt *yrmod; /* module where resolved type is looked for */
int ret; int ret;
@ -1341,24 +1327,13 @@ yang_type_resolve(yang_stmt *yorig,
if (options) if (options)
*options = 0x0; *options = 0x0;
*yrestype = NULL; /* Initialization of resolved type that may not be necessary */ *yrestype = NULL; /* Initialization of resolved type that may not be necessary */
if (nodeid_split(yang_argument_get(ytype), &prefix, &type) < 0)
goto done;
/* Cache does not work for eg string length 32? */
#if 1
if ((ret = yang_type_cache_get2(ytype, yrestype, if ((ret = yang_type_cache_get2(ytype, yrestype,
options, cvv, patterns, NULL, regexps, fraction)) < 0) options, cvv, patterns, regexps, fraction)) < 0)
goto done; goto done;
if (ret == 1) if (ret == 1)
goto ok; goto ok;
#else if (nodeid_split(yang_argument_get(ytype), &prefix, &type) < 0)
if (yang_typecache_get(ytype) != NULL){
if (yang_type_cache_get2(ytype, yrestype,
options, cvv, patterns, NULL, regexps, fraction) < 0)
goto done; goto done;
goto ok;
}
#endif
/* Check if type is basic type. If so, return that */ /* Check if type is basic type. If so, return that */
if ((prefix == NULL && yang_builtin(type))){ if ((prefix == NULL && yang_builtin(type))){
*yrestype = ytype; *yrestype = ytype;
@ -1366,7 +1341,6 @@ yang_type_resolve(yang_stmt *yorig,
goto done; goto done;
goto ok; goto ok;
} }
/* Not basic type. Now check if prefix which means we look in other module */ /* Not basic type. Now check if prefix which means we look in other module */
if (prefix){ /* Go to top and find import that matches */ if (prefix){ /* Go to top and find import that matches */
if ((yrmod = yang_find_module_by_prefix(ytype, prefix)) == NULL){ if ((yrmod = yang_find_module_by_prefix(ytype, prefix)) == NULL){
@ -1400,7 +1374,7 @@ yang_type_resolve(yang_stmt *yorig,
clixon_err(OE_DB, 0, "mandatory type object is not found"); clixon_err(OE_DB, 0, "mandatory type object is not found");
goto done; goto done;
} }
/* recursively resolve this new type */ /* Recursively resolve this new type */
if (yang_type_resolve(yorig, ys, rytype, yrestype, if (yang_type_resolve(yorig, ys, rytype, yrestype,
options, cvv, options, cvv,
patterns, regexps, patterns, regexps,
@ -1483,6 +1457,7 @@ yang_type_get(yang_stmt *ys,
{ {
int retval = -1; int retval = -1;
yang_stmt *ytype; /* type */ yang_stmt *ytype; /* type */
yang_stmt *yorig;
char *type = NULL; char *type = NULL;
if (yrestype == NULL){ if (yrestype == NULL){
@ -1491,6 +1466,10 @@ yang_type_get(yang_stmt *ys,
} }
if (options) if (options)
*options = 0x0; *options = 0x0;
/* Use original tree to resolve types */
if ((yorig = yang_orig_get(ys)) != NULL) {
ys = yorig;
}
/* Find mandatory type */ /* Find mandatory type */
if ((ytype = yang_find(ys, Y_TYPE, NULL)) == NULL){ if ((ytype = yang_find(ys, Y_TYPE, NULL)) == NULL){
clixon_err(OE_DB, ENOENT, "mandatory type object is not found"); clixon_err(OE_DB, ENOENT, "mandatory type object is not found");
@ -1504,8 +1483,11 @@ yang_type_get(yang_stmt *ys,
clixon_err(OE_XML, errno, "stdup"); clixon_err(OE_XML, errno, "stdup");
goto done; goto done;
} }
if (yang_type_resolve(ys, ys, ytype, yrestype, if (yang_type_resolve(ys, ys, ytype,
options, cvv, patterns, regexps, fraction) < 0) yrestype,
options,
cvv, patterns, regexps,
fraction) < 0)
goto done; goto done;
if (*yrestype == NULL){ if (*yrestype == NULL){
clixon_err(OE_YANG, 0, "result-type should not be NULL"); clixon_err(OE_YANG, 0, "result-type should not be NULL");