* Improved submodule implementation, as part of [Yang submodule import prefix restrictions #60](https://github.com/clicon/clixon/issues/60).

This commit is contained in:
Olof hagsand 2019-05-14 14:09:02 +02:00
parent 70221742f7
commit d775eb5374
10 changed files with 366 additions and 122 deletions

View file

@ -548,21 +548,38 @@ yang_find(yang_stmt *yn,
{
yang_stmt *ys = NULL;
int i;
int match = 0;
yang_stmt *yret = NULL;
char *name;
yang_stmt *yspec;
yang_stmt *ym;
for (i=0; i<yn->ys_len; i++){
ys = yn->ys_stmt[i];
if (keyword == 0 || ys->ys_keyword == keyword){
if (argument == NULL)
match++;
else
if (ys->ys_argument && strcmp(argument, ys->ys_argument) == 0)
match++;
if (match)
if (argument == NULL ||
(ys->ys_argument && strcmp(argument, ys->ys_argument) == 0)){
yret = ys;
break;
}
}
}
return match ? ys : NULL;
/* Special case: if not match and yang node is module or submodule, extend
* search to include submodules */
if (yret == NULL &&
(yang_keyword_get(yn) == Y_MODULE ||
yang_keyword_get(yn) == Y_SUBMODULE)){
yspec = ys_spec(yn);
for (i=0; i<yn->ys_len; i++){
ys = yn->ys_stmt[i];
if (yang_keyword_get(ys) == Y_INCLUDE){
name = yang_argument_get(ys);
ym = yang_find_module_by_name(yspec, name);
if ((yret = yang_find(ym, keyword, argument)) != NULL)
break;
}
}
}
return yret;
}
/*! Count number of children that matches keyword and argument
@ -611,7 +628,9 @@ yang_find_datanode(yang_stmt *yn,
{
yang_stmt *ys = NULL;
yang_stmt *yc = NULL;
yang_stmt *yspec;
yang_stmt *ysmatch = NULL;
char *name;
int i, j;
for (i=0; i<yn->ys_len; i++){
@ -644,6 +663,22 @@ yang_find_datanode(yang_stmt *yn,
goto match;
}
}
/* Special case: if not match and yang node is module or submodule, extend
* search to include submodules */
if (ysmatch == NULL &&
(yang_keyword_get(yn) == Y_MODULE ||
yang_keyword_get(yn) == Y_SUBMODULE)){
yspec = ys_spec(yn);
for (i=0; i<yn->ys_len; i++){
ys = yn->ys_stmt[i];
if (yang_keyword_get(ys) == Y_INCLUDE){
name = yang_argument_get(ys);
yc = yang_find_module_by_name(yspec, name);
if ((ysmatch = yang_find_datanode(yc, argument)) != NULL)
break;
}
}
}
match:
return ysmatch;
}
@ -660,7 +695,9 @@ yang_find_schemanode(yang_stmt *yn,
{
yang_stmt *ys = NULL;
yang_stmt *yc = NULL;
yang_stmt *yspec;
yang_stmt *ysmatch = NULL;
char *name;
int i, j;
for (i=0; i<yn->ys_len; i++){
@ -693,6 +730,22 @@ yang_find_schemanode(yang_stmt *yn,
goto match;
}
}
/* Special case: if not match and yang node is module or submodule, extend
* search to include submodules */
if (ysmatch == NULL &&
(yang_keyword_get(yn) == Y_MODULE ||
yang_keyword_get(yn) == Y_SUBMODULE)){
yspec = ys_spec(yn);
for (i=0; i<yn->ys_len; i++){
ys = yn->ys_stmt[i];
if (yang_keyword_get(ys) == Y_INCLUDE){
name = yang_argument_get(ys);
yc = yang_find_module_by_name(yspec, name);
if ((ysmatch = yang_find_schemanode(yc, argument)) != NULL)
break;
}
}
}
match:
return ysmatch;
}
@ -713,7 +766,8 @@ yang_find_myprefix(yang_stmt *ys)
yang_stmt *yprefix;
char *prefix = NULL;
if ((ymod = ys_module(ys)) == NULL){
/* Not good enough with submodule, must be actual module */
if ((ymod = ys_real_module(ys)) == NULL){
clicon_err(OE_YANG, 0, "My yang module not found");
goto done;
}
@ -740,7 +794,7 @@ yang_find_mynamespace(yang_stmt *ys)
yang_stmt *ynamespace;
char *namespace = NULL;
if ((ymod = ys_module(ys)) == NULL){
if ((ymod = ys_real_module(ys)) == NULL){
clicon_err(OE_YANG, 0, "My yang module not found");
goto done;
}
@ -926,6 +980,7 @@ yang_key2str(int keyword)
* @retval 0 OK
* @retval -1 Error
* @note works for xml namespaces (xmlns / xmlns:ns)
* Note that xt xml symbol may belong to submodule of ymod
*/
int
ys_module_by_xml(yang_stmt *ysp,
@ -970,6 +1025,7 @@ ys_module_by_xml(yang_stmt *ysp,
* @param[in] ys Any yang statement in a yang tree
* @retval ymod The top module or sub-module
* @see ys_spec
* @see ys_real_module find the submodule's belongs-to module
* @note For an augmented node, the original module is returned
*/
yang_stmt *
@ -984,8 +1040,8 @@ ys_module(yang_stmt *ys)
while (ys != NULL &&
ys->ys_keyword != Y_MODULE &&
ys->ys_keyword != Y_SUBMODULE){
if (ys->ys_module){ /* shortcut due to augment */
ys = ys->ys_module;
if (ys->ys_mymodule){ /* shortcut due to augment */
ys = ys->ys_mymodule;
break;
}
yn = ys->ys_parent;
@ -998,6 +1054,41 @@ ys_module(yang_stmt *ys)
return ys;
}
/*! Find real top module given a statement in a yang tree
* With "real" top module means that if sub-module is the top-node,
* the module that the sub-module belongs-to is found recursively
* @param[in] ys Any yang statement in a yang tree
* @retval ymod The top module or sub-module
* @see ys_module
* @note For an augmented node, the original module is returned
*/
yang_stmt *
ys_real_module(yang_stmt *ys)
{
yang_stmt *ym = NULL;
yang_stmt *yb;
char *name;
yang_stmt *yspec;
if ((ym = ys_module(ys)) != NULL){
yspec = ys_spec(ym);
while (yang_keyword_get(ym) == Y_SUBMODULE){
if ((yb = yang_find(ym, Y_BELONGS_TO, NULL)) == NULL){
clicon_err(OE_YANG, ENOENT, "No belongs-to statement of submodule %s", yang_argument_get(ym)); /* shouldnt happen */
goto done;
}
if ((name = yang_argument_get(yb)) == NULL){
clicon_err(OE_YANG, ENOENT, "Belongs-to statement of submodule %s has no argument", yang_argument_get(ym)); /* shouldnt happen */
goto done;
}
ym = yang_find_module_by_name(yspec, name);
}
}
return ym;
done:
return NULL;
}
/*! Find top of tree, the yang specification from within the tree
* @param[in] ys Any yang statement in a yang tree
* @retval yspec The top yang specification
@ -1901,7 +1992,7 @@ yang_augment_node(yang_stmt *ys,
for (i=0; i<ys->ys_len; i++){
if ((yc = ys_dup(ys->ys_stmt[i])) == NULL)
goto done;
yc->ys_module = ymod;
yc->ys_mymodule = ymod;
if (yn_insert(ytarget, yc) < 0)
goto done;
}
@ -2085,7 +2176,7 @@ yang_parse_str(char *str,
if (strlen(str)){ /* Not empty */
if (yang_scan_init(&yy) < 0)
goto done;
if (yang_parse_init(&yy, yspec) < 0)
if (yang_parse_init(&yy) < 0)
goto done;
if (clixon_yang_parseparse(&yy) != 0) { /* yacc returns 1 on error */
clicon_log(LOG_NOTICE, "Yang error: %s on line %d", name, yy.yy_linenum);
@ -2485,70 +2576,6 @@ yang_features(clicon_handle h,
return retval;
}
#if 1 /* This will be made OBSOLETE */
/*! Merge yang submodule into the module it belongs to
* Skip submodule header fields
* @param[in] h Clicon handle
* @param[in] yspec Yang spec
* @param[in] ysubm Yang submodule
*/
static int
yang_merge_submodules(clicon_handle h,
yang_stmt *yspec,
yang_stmt *ysubm)
{
int retval = -1;
yang_stmt *yb; /* belongs-to */
yang_stmt *ymod; /* parent yang module */
yang_stmt *yc; /* yang child */
char *modname;
int i;
assert(ysubm->ys_keyword == Y_SUBMODULE);
/* Get parent name (via belongs-to) and find parent module */
if ((yb = yang_find(ysubm, Y_BELONGS_TO, NULL)) == NULL){
clicon_err(OE_YANG, ENOENT, "submodule %s does not have a mandatory belongs-to statement", ysubm->ys_argument);
goto done;
}
modname = yb->ys_argument;
if ((ymod = yang_find(yspec, Y_MODULE, modname)) == NULL){
clicon_err(OE_YANG, ENOENT, "Submodule %s is loaded before/without its main module %s (you need to load the submodule together with or after the main module)",
ysubm->ys_argument,
modname);
goto done;
}
/* Move sub-module statements to modules
* skip belongs-to, revision, organization, reference, yang-version)
* since main module has its own and may only have one
* XXX: use queue,...
*/
for (i=0; i<ysubm->ys_len; i++){
yc = ysubm->ys_stmt[i];
if (yc->ys_keyword == Y_BELONGS_TO ||
yc->ys_keyword == Y_CONTACT ||
yc->ys_keyword == Y_DESCRIPTION ||
yc->ys_keyword == Y_ORGANIZATION ||
yc->ys_keyword == Y_REVISION ||
yc->ys_keyword == Y_REFERENCE ||
yc->ys_keyword == Y_YANG_VERSION)
ys_free(yc);
else{
if (yn_insert(ymod, yc) < 0)
goto done;
}
}
if (ysubm->ys_stmt){
free(ysubm->ys_stmt);
ysubm->ys_stmt = NULL;
}
ysubm->ys_len = 0;
ys_free(ysubm);
retval = 0;
done:
return retval;
}
#endif
/*! Parse top yang module including all its sub-modules. Expand and populate yang tree
*
* @param[in] h CLICON handle
@ -2589,38 +2616,18 @@ yang_parse_post(clicon_handle h,
for (i=modnr; i<yspec->ys_len; i++)
if (yang_cardinality(h, yspec->ys_stmt[i], yspec->ys_stmt[i]->ys_argument) < 0)
goto done;
#if 1 /* Will be OBSOLETE */
/* 3: Merge sub-modules with modules - after this step, no submodules exist
* In the merge, remove submodule headers
*/
i = modnr;
while (i<yspec->ys_len){
int j;
if (yspec->ys_stmt[i]->ys_keyword != Y_SUBMODULE){
i++;
continue;
}
if (yang_merge_submodules(h, yspec, yspec->ys_stmt[i]) < 0)
goto done;
/* shift down one step */
for (j=i; j<yspec->ys_len-1; j++)
yspec->ys_stmt[j] = yspec->ys_stmt[j+1];
yspec->ys_len--;
}
#endif /* OBSOLETE */
/* 4: Check features: check if enabled and remove disabled features */
/* 3: Check features: check if enabled and remove disabled features */
for (i=modnr; i<yspec->ys_len; i++) /* XXX */
if (yang_features(h, yspec->ys_stmt[i]) < 0)
goto done;
/* 5: Go through parse tree and populate it with cv types */
/* 4: Go through parse tree and populate it with cv types */
for (i=modnr; i<yspec->ys_len; i++)
if (yang_apply(yspec->ys_stmt[i], -1, ys_populate, (void*)h) < 0)
goto done;
/* 6: Resolve all types: populate type caches. Requires eg length/range cvecs
/* 5: Resolve all types: populate type caches. Requires eg length/range cvecs
* from ys_populate step.
* Must be done using static binding.
*/
@ -2632,21 +2639,21 @@ yang_parse_post(clicon_handle h,
* than the context they are used (except for submodules being merged w
* modules). Like static scoping.
* After this we expand all grouping/uses and unfold all macros into a
*single tree as they are used.
* single tree as they are used.
*/
/* 7: Macro expansion of all grouping/uses pairs. Expansion needs marking */
/* 6: Macro expansion of all grouping/uses pairs. Expansion needs marking */
for (i=modnr; i<yspec->ys_len; i++){
if (yang_expand(yspec->ys_stmt[i]) < 0)
goto done;
yang_apply(yspec->ys_stmt[i], -1, ys_flag_reset, (void*)YANG_FLAG_MARK);
}
/* 8: Top-level augmentation of all modules XXX: only new modules? */
/* 7: Top-level augmentation of all modules XXX: only new modules? */
if (yang_augment_spec(yspec, modnr) < 0)
goto done;
/* 9: sanity check of schemanode references, need more here */
/* 8: sanity check of schemanode references, need more here */
for (i=modnr; i<yspec->ys_len; i++)
if (yang_apply(yspec->ys_stmt[i], -1, ys_schemanode_check, NULL) < 0)
goto done;