Added validation for leafref forward and nackward references.
This commit is contained in:
parent
96f341d8fc
commit
1b6c9aacbe
11 changed files with 295 additions and 49 deletions
|
|
@ -1,5 +1,7 @@
|
||||||
# Clixon CHANGELOG
|
# Clixon CHANGELOG
|
||||||
|
|
||||||
|
- Added validation for leafref forward and nackward references.
|
||||||
|
|
||||||
- Added new backend plugin callback: "plugin_statedata()" for retreiving state data
|
- Added new backend plugin callback: "plugin_statedata()" for retreiving state data
|
||||||
|
|
||||||
- Added yang dir with ietf-netconf and clixon-config yang specs for internal usage.
|
- Added yang dir with ietf-netconf and clixon-config yang specs for internal usage.
|
||||||
|
|
|
||||||
|
|
@ -89,15 +89,19 @@ generic_validate(yang_spec *yspec,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *x1;
|
cxobj *x1;
|
||||||
cxobj *x2;
|
cxobj *x2;
|
||||||
int i;
|
|
||||||
yang_stmt *ys;
|
yang_stmt *ys;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* All entries */
|
||||||
|
if (xml_apply(td->td_target, CX_ELMNT,
|
||||||
|
(xml_applyfn_t*)xml_yang_validate_all, NULL) < 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
/* changed entries */
|
/* changed entries */
|
||||||
for (i=0; i<td->td_clen; i++){
|
for (i=0; i<td->td_clen; i++){
|
||||||
x1 = td->td_scvec[i]; /* source changed */
|
x1 = td->td_scvec[i]; /* source changed */
|
||||||
x2 = td->td_tcvec[i]; /* target changed */
|
x2 = td->td_tcvec[i]; /* target changed */
|
||||||
ys = xml_spec(x1);
|
if (xml_yang_validate_add(x2, NULL) < 0)
|
||||||
if (xml_yang_validate(x2, ys) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* deleted entries */
|
/* deleted entries */
|
||||||
|
|
@ -113,11 +117,8 @@ generic_validate(yang_spec *yspec,
|
||||||
/* added entries */
|
/* added entries */
|
||||||
for (i=0; i<td->td_alen; i++){
|
for (i=0; i<td->td_alen; i++){
|
||||||
x2 = td->td_avec[i];
|
x2 = td->td_avec[i];
|
||||||
ys = xml_spec(x2);
|
if (xml_apply0(x2, CX_ELMNT,
|
||||||
if (xml_yang_validate(x2, ys) < 0)
|
(xml_applyfn_t*)xml_yang_validate_add, NULL) < 0)
|
||||||
goto done;
|
|
||||||
if (xml_apply(x2, CX_ELMNT,
|
|
||||||
(xml_applyfn_t*)xml_yang_validate, NULL) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
|
||||||
|
|
@ -275,9 +275,10 @@ yang2cli_var_sub(clicon_handle h,
|
||||||
if (helptext)
|
if (helptext)
|
||||||
cprintf(cb0, "(\"%s\")", helptext);
|
cprintf(cb0, "(\"%s\")", helptext);
|
||||||
if (completion){
|
if (completion){
|
||||||
|
#if 0
|
||||||
if (type && (strcmp(type, "leafref") == 0)){
|
if (type && (strcmp(type, "leafref") == 0)){
|
||||||
yang_stmt *ypath;
|
yang_stmt *ypath;
|
||||||
|
/* XXX only for absolute xpath */
|
||||||
if ((ypath = yang_find((yang_node*)ytype, Y_PATH, NULL)) == NULL){
|
if ((ypath = yang_find((yang_node*)ytype, Y_PATH, NULL)) == NULL){
|
||||||
clicon_err(OE_XML, 0, "leafref should have path sub");
|
clicon_err(OE_XML, 0, "leafref should have path sub");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -290,6 +291,7 @@ yang2cli_var_sub(clicon_handle h,
|
||||||
ypath->ys_argument);
|
ypath->ys_argument);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
#endif
|
||||||
if (cli_expand_var_generate(h, ys, cvtype, cb0,
|
if (cli_expand_var_generate(h, ys, cvtype, cb0,
|
||||||
options, fraction_digits) < 0)
|
options, fraction_digits) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -141,12 +141,29 @@ expand_dbvar(void *h,
|
||||||
if (api_path_fmt2xpath(api_path, cvv, &xpath) < 0)
|
if (api_path_fmt2xpath(api_path, cvv, &xpath) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* XXX read whole configuration, why not send xpath? */
|
/* XXX read whole configuration, why not send xpath? */
|
||||||
if (clicon_rpc_get_config(h, dbstr, "/", &xt) < 0)
|
if (clicon_rpc_get_config(h, dbstr, xpath, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error(xerr);
|
clicon_rpc_generate_error(xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
|
/* Get xpath from datastore?
|
||||||
|
* 1. Get whole datastore,
|
||||||
|
* 2. Add tentative my location to xpath,
|
||||||
|
* 3. If leafref, compute relative xpath
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
cxobj *xcur = NULL; /* xpath, NULL if datastore */
|
||||||
|
// yang_node *y = NULL; /* yang spec of xpath */
|
||||||
|
|
||||||
|
if ((xcur = xpath_first(xt, xpath)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* One round to detect duplicates
|
/* One round to detect duplicates
|
||||||
* XXX The code below would benefit from some cleanup
|
* XXX The code below would benefit from some cleanup
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,26 @@ catch:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ys_find_rpc(yang_stmt *ys,
|
||||||
|
void *arg)
|
||||||
|
{
|
||||||
|
cxobj *xn = (cxobj*)arg;
|
||||||
|
char *name = xml_name(xn);
|
||||||
|
|
||||||
|
if (ys->ys_keyword == Y_RPC && strcmp(name, ys->ys_argument) == 0){
|
||||||
|
/*
|
||||||
|
* XXX
|
||||||
|
* 1. Check xn arguments with input statement.
|
||||||
|
* 2. Send to backend as clicon_msg-encode()
|
||||||
|
* 3. In backend to similar but there call actual backend
|
||||||
|
*/
|
||||||
|
return 1; /* handled */
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! See if there is any callback registered for this tag
|
/*! See if there is any callback registered for this tag
|
||||||
*
|
*
|
||||||
* @param[in] h clicon handle
|
* @param[in] h clicon handle
|
||||||
|
|
@ -211,21 +231,28 @@ netconf_plugin_callbacks(clicon_handle h,
|
||||||
cxobj *xn,
|
cxobj *xn,
|
||||||
cxobj **xret)
|
cxobj **xret)
|
||||||
{
|
{
|
||||||
|
int retval = -1;
|
||||||
netconf_reg_t *nreg;
|
netconf_reg_t *nreg;
|
||||||
int retval;
|
yang_spec *yspec;
|
||||||
|
|
||||||
if (deps == NULL)
|
if (deps != NULL){
|
||||||
return 0;
|
|
||||||
nreg = deps;
|
nreg = deps;
|
||||||
do {
|
do {
|
||||||
if (strcmp(nreg->nr_tag, xml_name(xn)) == 0){
|
if (strcmp(nreg->nr_tag, xml_name(xn)) == 0){
|
||||||
if ((retval = nreg->nr_callback(h, xn, xret, nreg->nr_arg)) < 0)
|
retval = nreg->nr_callback(h, xn, xret, nreg->nr_arg);
|
||||||
return -1;
|
goto done;
|
||||||
else
|
|
||||||
return 1; /* handled */
|
|
||||||
}
|
}
|
||||||
nreg = NEXTQ(netconf_reg_t *, nreg);
|
nreg = NEXTQ(netconf_reg_t *, nreg);
|
||||||
} while (nreg != deps);
|
} while (nreg != deps);
|
||||||
return 0;
|
}
|
||||||
|
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||||
|
clicon_err(OE_YANG, ENOENT, "No yang spec");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (yang_apply((yang_node*)yspec, ys_find_rpc, xn) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,8 @@ enum {
|
||||||
*/
|
*/
|
||||||
int xml2txt(FILE *f, cxobj *x, int level);
|
int xml2txt(FILE *f, cxobj *x, int level);
|
||||||
int xml2cli(FILE *f, cxobj *x, char *prepend, enum genmodel_type gt);
|
int xml2cli(FILE *f, cxobj *x, char *prepend, enum genmodel_type gt);
|
||||||
int xml_yang_validate(cxobj *xt, yang_stmt *ys) ;
|
int xml_yang_validate_add(cxobj *xt, void *arg);
|
||||||
|
int xml_yang_validate_all(cxobj *xt, void *arg);
|
||||||
int xml2cvec(cxobj *xt, yang_stmt *ys, cvec **cvv0);
|
int xml2cvec(cxobj *xt, yang_stmt *ys, cvec **cvv0);
|
||||||
int cvec2xml_1(cvec *cvv, char *toptag, cxobj *xp, cxobj **xt0);
|
int cvec2xml_1(cvec *cvv, char *toptag, cxobj *xp, cxobj **xt0);
|
||||||
int xml_diff(yang_spec *yspec, cxobj *xt1, cxobj *xt2,
|
int xml_diff(yang_spec *yspec, cxobj *xt1, cxobj *xt2,
|
||||||
|
|
|
||||||
|
|
@ -274,16 +274,62 @@ xml2cli(FILE *f,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Validate an xml node of type leafref, ensure the value is one of that path's reference
|
||||||
|
* @param[in] xt XML leaf node of type leafref
|
||||||
|
* @param[in] ytype Yang type statement belonging to the XML node
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
validate_leafref(cxobj *xt,
|
||||||
|
yang_stmt *ytype)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
yang_stmt *ypath;
|
||||||
|
cxobj **xvec = NULL;
|
||||||
|
cxobj *x;
|
||||||
|
int i;
|
||||||
|
size_t xlen = 0;
|
||||||
|
char *leafrefbody;
|
||||||
|
char *leafbody;
|
||||||
|
|
||||||
/*! Validate a single XML node with yang specification
|
|
||||||
* - If no value and mandatory flag set in spec, report error.
|
if ((leafrefbody = xml_body(xt)) == NULL)
|
||||||
* - Validate value versus spec, and report error if no match. Currently
|
return 0;
|
||||||
* only int ranges and string regexp checked.
|
if ((ypath = yang_find((yang_node*)ytype, Y_PATH, NULL)) == NULL){
|
||||||
* @retval 0 OK
|
clicon_err(OE_DB, 0, "Leafref %s requires path statement", ytype->ys_argument);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (xpath_vec(xt, ypath->ys_argument, &xvec, &xlen) < 0)
|
||||||
|
goto done;
|
||||||
|
for (i = 0; i < xlen; i++) {
|
||||||
|
x = xvec[i];
|
||||||
|
if ((leafbody = xml_body(x)) == NULL)
|
||||||
|
continue;
|
||||||
|
if (strcmp(leafbody, leafrefbody) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i==xlen){
|
||||||
|
clicon_err(OE_DB, 0, "Leafref validation failed, no such leaf: %s",
|
||||||
|
leafrefbody);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xvec)
|
||||||
|
free(xvec);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Validate a single XML node with yang specification for added entry
|
||||||
|
* 1. Check if mandatory leafs present as subs.
|
||||||
|
* 2. Check leaf values, eg int ranges and string regexps.
|
||||||
|
* @param[in] xt XML node to be validated
|
||||||
|
* @retval 0 Valid OK
|
||||||
|
* @retval -1 Validation failed
|
||||||
|
* @see xml_yang_validate_all
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml_yang_validate(cxobj *xt,
|
xml_yang_validate_add(cxobj *xt,
|
||||||
yang_stmt *ys0)
|
void *arg)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cg_var *cv = NULL;
|
cg_var *cv = NULL;
|
||||||
|
|
@ -294,7 +340,7 @@ xml_yang_validate(cxobj *xt,
|
||||||
char *body;
|
char *body;
|
||||||
|
|
||||||
/* if not given by argument (overide) use default link */
|
/* if not given by argument (overide) use default link */
|
||||||
ys = ys0?ys0:xml_spec(xt);
|
ys = xml_spec(xt);
|
||||||
switch (ys->ys_keyword){
|
switch (ys->ys_keyword){
|
||||||
case Y_LIST:
|
case Y_LIST:
|
||||||
/* fall thru */
|
/* fall thru */
|
||||||
|
|
@ -346,6 +392,43 @@ xml_yang_validate(cxobj *xt,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Validate a single XML node with yang specification for all (not only added) entries
|
||||||
|
* 1. Check leafrefs. Eg you delete a leaf and a leafref references it.
|
||||||
|
* @param[in] xt XML node to be validated
|
||||||
|
* @retval 0 Valid OK
|
||||||
|
* @retval -1 Validation failed
|
||||||
|
* @see xml_yang_validate_add
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_yang_validate_all(cxobj *xt,
|
||||||
|
void *arg)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
yang_stmt *ys;
|
||||||
|
yang_stmt *ytype;
|
||||||
|
|
||||||
|
/* if not given by argument (overide) use default link */
|
||||||
|
ys = xml_spec(xt);
|
||||||
|
switch (ys->ys_keyword){
|
||||||
|
case Y_LEAF:
|
||||||
|
/* fall thru */
|
||||||
|
case Y_LEAF_LIST:
|
||||||
|
/* Special case if leaf is leafref, then first check against
|
||||||
|
current xml tree
|
||||||
|
*/
|
||||||
|
if ((ytype = yang_find((yang_node*)ys, Y_TYPE, NULL)) != NULL &&
|
||||||
|
strcmp(ytype->ys_argument, "leafref") == 0)
|
||||||
|
if (validate_leafref(xt, ytype) < 0)
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Translate a single xml node to a cligen variable vector. Note not recursive
|
/*! Translate a single xml node to a cligen variable vector. Note not recursive
|
||||||
* @param[in] xt XML tree containing one top node
|
* @param[in] xt XML tree containing one top node
|
||||||
* @param[in] ys Yang spec containing type specification of top-node of xt
|
* @param[in] ys Yang spec containing type specification of top-node of xt
|
||||||
|
|
@ -1908,3 +1991,4 @@ xml_merge(cxobj *x0,
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -435,6 +435,7 @@ recursive_find(cxobj *xn,
|
||||||
* - @<attr>=<value>
|
* - @<attr>=<value>
|
||||||
* - <number>
|
* - <number>
|
||||||
* - <name>=<value> # RelationalExpr '=' RelationalExpr
|
* - <name>=<value> # RelationalExpr '=' RelationalExpr
|
||||||
|
* - <name>=current()<xpath> XXX
|
||||||
* @see https://www.w3.org/TR/xpath/#predicates
|
* @see https://www.w3.org/TR/xpath/#predicates
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
|
|
@ -565,6 +566,7 @@ xpath_find(struct xpath_element *xe,
|
||||||
cxobj *xv;
|
cxobj *xv;
|
||||||
int descendants = 0;
|
int descendants = 0;
|
||||||
cxobj **vec1 = NULL;
|
cxobj **vec1 = NULL;
|
||||||
|
cxobj *xparent;
|
||||||
size_t vec1len = 0;
|
size_t vec1len = 0;
|
||||||
struct xpath_predicate *xp;
|
struct xpath_predicate *xp;
|
||||||
|
|
||||||
|
|
@ -587,10 +589,13 @@ xpath_find(struct xpath_element *xe,
|
||||||
case A_SELF:
|
case A_SELF:
|
||||||
break;
|
break;
|
||||||
case A_PARENT:
|
case A_PARENT:
|
||||||
|
j = 0;
|
||||||
for (i=0; i<vec0len; i++){
|
for (i=0; i<vec0len; i++){
|
||||||
xv = vec0[i];
|
xv = vec0[i];
|
||||||
vec0[i] = xml_parent(xv);
|
if ((xparent = xml_parent(xv)) != NULL)
|
||||||
|
vec0[j++] = xparent;
|
||||||
}
|
}
|
||||||
|
vec0len = j;
|
||||||
break;
|
break;
|
||||||
case A_ROOT: /* set list to NULL */
|
case A_ROOT: /* set list to NULL */
|
||||||
x = vec0[0];
|
x = vec0[0];
|
||||||
|
|
|
||||||
|
|
@ -1593,11 +1593,12 @@ yang_parse(clicon_handle h,
|
||||||
if (yang_expand((yang_node*)ysp) < 0)
|
if (yang_expand((yang_node*)ysp) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
yang_apply((yang_node*)ymod, ys_flag_reset, (void*)YANG_FLAG_MARK);
|
yang_apply((yang_node*)ymod, ys_flag_reset, (void*)YANG_FLAG_MARK);
|
||||||
/* Step 4: Go through parse tree and populate it with cv types */
|
|
||||||
|
/* Step 3: Go through parse tree and populate it with cv types */
|
||||||
if (yang_apply((yang_node*)ysp, ys_populate, NULL) < 0)
|
if (yang_apply((yang_node*)ysp, ys_populate, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Step 3: Top-level augmentation of all modules */
|
/* Step 4: Top-level augmentation of all modules */
|
||||||
if (yang_augment_spec(ysp) < 0)
|
if (yang_augment_spec(ysp) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
|
@ -1606,7 +1607,6 @@ yang_parse(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Apply a function call recursively on all yang-stmt s recursively
|
/*! Apply a function call recursively on all yang-stmt s recursively
|
||||||
*
|
*
|
||||||
* Recursively traverse all yang-nodes in a parse-tree and apply fn(arg) for
|
* Recursively traverse all yang-nodes in a parse-tree and apply fn(arg) for
|
||||||
|
|
@ -1614,10 +1614,12 @@ yang_parse(clicon_handle h,
|
||||||
* argument as args.
|
* argument as args.
|
||||||
* The tree is traversed depth-first, which at least guarantees that a parent is
|
* The tree is traversed depth-first, which at least guarantees that a parent is
|
||||||
* traversed before a child.
|
* traversed before a child.
|
||||||
* @param[in] xn XML node
|
* @param[in] yn yang node
|
||||||
* @param[in] type matching type or -1 for any
|
|
||||||
* @param[in] fn Callback
|
* @param[in] fn Callback
|
||||||
* @param[in] arg Argument
|
* @param[in] arg Argument
|
||||||
|
* @retval -1 Error, aborted at first error encounter
|
||||||
|
* @retval 0 OK, all nodes traversed
|
||||||
|
* @retval n OK, aborted at first encounter of first match
|
||||||
* @code
|
* @code
|
||||||
* int ys_fn(yang_stmt *ys, void *arg)
|
* int ys_fn(yang_stmt *ys, void *arg)
|
||||||
* {
|
* {
|
||||||
|
|
@ -1635,13 +1637,18 @@ yang_apply(yang_node *yn,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_stmt *ys = NULL;
|
yang_stmt *ys = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
for (i=0; i<yn->yn_len; i++){
|
for (i=0; i<yn->yn_len; i++){
|
||||||
ys = yn->yn_stmt[i];
|
ys = yn->yn_stmt[i];
|
||||||
if (fn(ys, arg) < 0)
|
if (fn(ys, arg) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (yang_apply((yang_node*)ys, fn, arg) < 0)
|
if ((ret = yang_apply((yang_node*)ys, fn, arg)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (ret > 0){
|
||||||
|
retval = ret;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,6 @@ static const map_str2int ytmap[] = {
|
||||||
{"int16", CGV_INT16},
|
{"int16", CGV_INT16},
|
||||||
{"int64", CGV_INT64},
|
{"int64", CGV_INT64},
|
||||||
{"leafref", CGV_STRING}, /* XXX */
|
{"leafref", CGV_STRING}, /* XXX */
|
||||||
|
|
||||||
{"uint8", CGV_UINT8},
|
{"uint8", CGV_UINT8},
|
||||||
{"uint16", CGV_UINT16},
|
{"uint16", CGV_UINT16},
|
||||||
{"uint32", CGV_UINT32},
|
{"uint32", CGV_UINT32},
|
||||||
|
|
@ -105,12 +104,6 @@ yang_builtin(char *type)
|
||||||
{
|
{
|
||||||
if (clicon_str2int(ytmap, type) != -1)
|
if (clicon_str2int(ytmap, type) != -1)
|
||||||
return 1;
|
return 1;
|
||||||
#if 0
|
|
||||||
const struct map_str2int *yt;
|
|
||||||
for (yt = &ytmap[0]; yt->ms_str; yt++)
|
|
||||||
if (strcmp(yt->ms_str, type) == 0)
|
|
||||||
return 1;
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -857,6 +850,7 @@ yang_type_resolve(yang_stmt *ys,
|
||||||
ylength = yang_find((yang_node*)ytype, Y_LENGTH, NULL);
|
ylength = yang_find((yang_node*)ytype, Y_LENGTH, NULL);
|
||||||
ypattern = yang_find((yang_node*)ytype, Y_PATTERN, NULL);
|
ypattern = yang_find((yang_node*)ytype, Y_PATTERN, NULL);
|
||||||
yfraction = yang_find((yang_node*)ytype, Y_FRACTION_DIGITS, NULL);
|
yfraction = yang_find((yang_node*)ytype, Y_FRACTION_DIGITS, NULL);
|
||||||
|
|
||||||
/* 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;
|
||||||
|
|
@ -867,8 +861,10 @@ yang_type_resolve(yang_stmt *ys,
|
||||||
|
|
||||||
/* 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 ((ymod = yang_find_module_by_prefix(ys, prefix)) == NULL)
|
if ((ymod = yang_find_module_by_prefix(ys, prefix)) == NULL){
|
||||||
|
clicon_err(OE_DB, 0, "Module not resolved: %s", prefix);
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
if ((rytypedef = yang_find((yang_node*)ymod, Y_TYPEDEF, type)) == NULL)
|
if ((rytypedef = yang_find((yang_node*)ymod, Y_TYPEDEF, type)) == NULL)
|
||||||
goto ok; /* unresolved */
|
goto ok; /* unresolved */
|
||||||
}
|
}
|
||||||
|
|
|
||||||
104
test/test7.sh
Executable file
104
test/test7.sh
Executable file
|
|
@ -0,0 +1,104 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Test7: Yang specifics: leafref
|
||||||
|
|
||||||
|
# include err() and new() functions
|
||||||
|
. ./lib.sh
|
||||||
|
|
||||||
|
# For memcheck
|
||||||
|
# clixon_netconf="valgrind --leak-check=full --show-leak-kinds=all clixon_netconf"
|
||||||
|
clixon_netconf=clixon_netconf
|
||||||
|
clixon_cli=clixon_cli
|
||||||
|
|
||||||
|
cat <<EOF > /tmp/leafref.yang
|
||||||
|
module ietf-ip{
|
||||||
|
typedef admin-status{
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
list interface {
|
||||||
|
key "name";
|
||||||
|
leaf name {
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
leaf admin-status {
|
||||||
|
type admin-status;
|
||||||
|
}
|
||||||
|
list address {
|
||||||
|
key "ip";
|
||||||
|
leaf ip {
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
container default-address {
|
||||||
|
leaf ifname {
|
||||||
|
type leafref {
|
||||||
|
path "../../interface/name";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
leaf address {
|
||||||
|
type leafref {
|
||||||
|
path "../../interface[name = current()/../ifname]"
|
||||||
|
+ "/address/ip";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
|
||||||
|
# kill old backend (if any)
|
||||||
|
new "kill old backend"
|
||||||
|
sudo clixon_backend -zf $clixon_cf -y /tmp/leafref
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
|
||||||
|
new "start backend"
|
||||||
|
# start new backend
|
||||||
|
sudo clixon_backend -If $clixon_cf -y /tmp/leafref
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
|
||||||
|
new "leafref base config"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref" "<rpc><edit-config><target><candidate/></target><config><interface><name>eth0</name><admin-status>up</admin-status><address><ip>192.0.2.1</ip></address><address><ip>192.0.2.2</ip></address></interface><interface><name>lo</name><admin-status>up</admin-status><address><ip>127.0.0.1</ip></address></interface></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "leafref get config"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><config><interface><name>eth0</name>'
|
||||||
|
|
||||||
|
new "leafref base commit"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "leafref add wrong ref"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref" "<rpc><edit-config><target><candidate/></target><config><default-address><ifname>eth3</ifname><address>10.0.4.6</address></default-address></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "leafref validate"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>missing-attribute</error-tag>"
|
||||||
|
|
||||||
|
new "leafref discard-changes"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "leafref add correct ref"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref" "<rpc><edit-config><target><candidate/></target><config><default-address><ifname>eth0</ifname><address>192.0.2.2</address></default-address></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "leafref validate (ok)"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
|
||||||
|
|
||||||
|
new "leafref delete leaf"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref" "<rpc><edit-config><target><candidate/></target><config><interface operation=\"delete\"><name>eth0</name></interface></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
|
||||||
|
|
||||||
|
new "leafref validate (should fail)"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>missing-attribute</error-tag>"
|
||||||
|
|
||||||
|
|
||||||
|
new "Kill backend"
|
||||||
|
# Check if still alive
|
||||||
|
pid=`pgrep clixon_backend`
|
||||||
|
if [ -z "$pid" ]; then
|
||||||
|
err "backend already dead"
|
||||||
|
fi
|
||||||
|
# kill backend
|
||||||
|
sudo clixon_backend -zf $clixon_cf
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err "kill backend"
|
||||||
|
fi
|
||||||
Loading…
Add table
Add a link
Reference in a new issue