Sanity check of mandatory key statement for Yang LISTs.
* If fails, exit with error message, eg: `Yang error: Sanity check failed: LIST vsDataContainer lacks key statement which MUST be present (See RFC 7950 Sec 7.8.2)` * Can be disabled by setting `CLICON_CLICON_YANG_LIST_CHECK` to `false`
This commit is contained in:
parent
237be5b819
commit
0e94937ccf
11 changed files with 138 additions and 39 deletions
|
|
@ -687,14 +687,13 @@ yang_find_datanode(yang_stmt *yn,
|
|||
yang_stmt *yspec;
|
||||
yang_stmt *ysmatch = NULL;
|
||||
char *name;
|
||||
int i, j;
|
||||
|
||||
for (i=0; i<yn->ys_len; i++){
|
||||
ys = yn->ys_stmt[i];
|
||||
if (ys->ys_keyword == Y_CHOICE){ /* Look for its children */
|
||||
for (j=0; j<ys->ys_len; j++){
|
||||
yc = ys->ys_stmt[j];
|
||||
if (yc->ys_keyword == Y_CASE) /* Look for its children */
|
||||
ys = NULL;
|
||||
while ((ys = yn_each(yn, ys)) != NULL){
|
||||
if (yang_keyword_get(ys) == Y_CHOICE){ /* Look for its children */
|
||||
yc = NULL;
|
||||
while ((yc = yn_each(ys, yc)) != NULL){
|
||||
if (yang_keyword_get(yc) == Y_CASE) /* Look for its children */
|
||||
ysmatch = yang_find_datanode(yc, argument);
|
||||
else
|
||||
if (yang_datanode(yc)){
|
||||
|
|
@ -726,8 +725,8 @@ yang_find_datanode(yang_stmt *yn,
|
|||
(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];
|
||||
ys = NULL;
|
||||
while ((ys = yn_each(yn, ys)) != NULL){
|
||||
if (yang_keyword_get(ys) == Y_INCLUDE){
|
||||
name = yang_argument_get(ys);
|
||||
yc = yang_find_module_by_name(yspec, name);
|
||||
|
|
@ -2083,12 +2082,15 @@ yang_apply(yang_stmt *yn,
|
|||
int
|
||||
yang_datanode(yang_stmt *ys)
|
||||
{
|
||||
return (yang_keyword_get(ys) == Y_CONTAINER ||
|
||||
yang_keyword_get(ys) == Y_LEAF ||
|
||||
yang_keyword_get(ys) == Y_LIST ||
|
||||
yang_keyword_get(ys) == Y_LEAF_LIST ||
|
||||
yang_keyword_get(ys) == Y_ANYXML ||
|
||||
yang_keyword_get(ys) == Y_ANYDATA);
|
||||
enum rfc_6020 keyw;
|
||||
|
||||
keyw = yang_keyword_get(ys);
|
||||
return (keyw == Y_CONTAINER ||
|
||||
keyw == Y_LEAF ||
|
||||
keyw == Y_LIST ||
|
||||
keyw == Y_LEAF_LIST ||
|
||||
keyw == Y_ANYXML ||
|
||||
keyw == Y_ANYDATA);
|
||||
}
|
||||
|
||||
/*! All the work for schema_nodeid functions both absolute and descendant
|
||||
|
|
|
|||
|
|
@ -90,21 +90,6 @@ struct yang_stmt{
|
|||
int _ys_vector_i; /* internal use: yn_each */
|
||||
};
|
||||
|
||||
/* Yang data definition statement
|
||||
* See RFC 7950 Sec 3:
|
||||
* o data definition statement: A statement that defines new data
|
||||
* nodes. One of "container", "leaf", "leaf-list", "list", "choice",
|
||||
* "case", "augment", "uses", "anydata", and "anyxml".
|
||||
*/
|
||||
#define yang_datadefinition(y) (yang_datanode(y) || (y)->ys_keyword == Y_CHOICE || (y)->ys_keyword == Y_CASE || (y)->ys_keyword == Y_AUGMENT || (y)->ys_keyword == Y_USES)
|
||||
|
||||
/* Yang schema node .
|
||||
* See RFC 7950 Sec 3:
|
||||
* o schema node: A node in the schema tree. One of action, container,
|
||||
* leaf, leaf-list, list, choice, case, rpc, input, output,
|
||||
* notification, anydata, and anyxml.
|
||||
*/
|
||||
#define yang_schemanode(y) (yang_datanode(y) || (y)->ys_keyword == Y_RPC || (y)->ys_keyword == Y_CHOICE || (y)->ys_keyword == Y_CASE || (y)->ys_keyword == Y_INPUT || (y)->ys_keyword == Y_OUTPUT || (y)->ys_keyword == Y_NOTIFICATION)
|
||||
|
||||
#endif /* _CLIXON_YANG_INTERNAL_H_ */
|
||||
|
||||
|
|
|
|||
|
|
@ -835,7 +835,7 @@ yang_parse_recurse(clicon_handle h,
|
|||
/*!
|
||||
* @param[in] ys Yang statement
|
||||
* @param[in] dummy Necessary for called in yang_apply
|
||||
* @see yang_apply_fn
|
||||
* @see yang_applyfn_t
|
||||
*/
|
||||
static int
|
||||
ys_schemanode_check(yang_stmt *ys,
|
||||
|
|
@ -906,6 +906,69 @@ ys_schemanode_check(yang_stmt *ys,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Check lists: non-config lists MUST have keys
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] ys Yang statement
|
||||
* Verify the following rule:
|
||||
* RFC 7950 7.8.2: The "key" statement, which MUST be present if the list represents
|
||||
* configuration and MAY be present otherwise
|
||||
* Unless CLICON_YANG_LIST_CHECK is false
|
||||
* OR it is the "errors" rule of the ietf-restconf spec which seems to be a special case.
|
||||
*/
|
||||
static int
|
||||
ys_list_check(clicon_handle h,
|
||||
yang_stmt *ys)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *ymod;
|
||||
yang_stmt *yc = NULL;
|
||||
enum rfc_6020 keyw;
|
||||
|
||||
/* This node has config false */
|
||||
if (yang_config(ys) == 0)
|
||||
return 0;
|
||||
keyw = yang_keyword_get(ys);
|
||||
/* Check if list and if keys do not exist */
|
||||
if (keyw == Y_LIST &&
|
||||
yang_find(ys, Y_KEY, NULL) == 0){
|
||||
ymod = ys_module(ys);
|
||||
#if 1
|
||||
/* Except restconf error extension from sanity check, dont know why it has no keys */
|
||||
if (strcmp(yang_find_mynamespace(ys),"urn:ietf:params:xml:ns:yang:ietf-restconf")==0 &&
|
||||
strcmp(yang_argument_get(ys),"error") == 0)
|
||||
;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (clicon_option_bool(h, "CLICON_YANG_LIST_CHECK")){
|
||||
clicon_log(LOG_ERR, "Error: LIST \"%s\" in module \"%s\" lacks key statement which MUST be present (See RFC 7950 Sec 7.8.2)",
|
||||
yang_argument_get(ys),
|
||||
yang_argument_get(ymod)
|
||||
);
|
||||
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
clicon_log(LOG_WARNING, "Warning: LIST \"%s\" in module \"%s\" lacks key statement which MUST be present (See RFC 7950 Sec 7.8.2)",
|
||||
yang_argument_get(ys),
|
||||
yang_argument_get(ymod)
|
||||
);
|
||||
}
|
||||
}
|
||||
/* Traverse subs */
|
||||
if (yang_schemanode(ys) || keyw == Y_MODULE || keyw == Y_SUBMODULE){
|
||||
yc = NULL;
|
||||
while ((yc = yn_each(ys, yc)) != NULL){
|
||||
if (ys_list_check(h, yc) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Parse top yang module including all its sub-modules. Expand and populate yang tree
|
||||
*
|
||||
* Perform secondary actions after yang parsing. These actions cannot be made at
|
||||
|
|
@ -986,10 +1049,15 @@ yang_parse_post(clicon_handle h,
|
|||
if (yang_apply(yspec->ys_stmt[i], -1, ys_populate2, (void*)h) < 0)
|
||||
goto done;
|
||||
|
||||
/* 8: sanity check of schemanode references, need more here */
|
||||
for (i=modnr; i<yang_len_get(yspec); i++)
|
||||
/* 8: sanity checks of expanded yangs need more here */
|
||||
for (i=modnr; i<yang_len_get(yspec); i++){
|
||||
/* Check schemanode references */
|
||||
if (yang_apply(yspec->ys_stmt[i], -1, ys_schemanode_check, NULL) < 0)
|
||||
goto done;
|
||||
/* Check list key values */
|
||||
if (ys_list_check(h, yspec->ys_stmt[i]) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue