Transform YANG when expressions to canonical xpath form
This commit is contained in:
parent
71e921520e
commit
26ca872b0c
8 changed files with 262 additions and 87 deletions
|
|
@ -149,7 +149,10 @@ cxobj *xpath_first(cxobj *xcur, cvec *nsc, const char *xpformat, ...) __attribu
|
||||||
cxobj *xpath_first_localonly(cxobj *xcur, const char *xpformat, ...) __attribute__ ((format (printf, 2, 3)));
|
cxobj *xpath_first_localonly(cxobj *xcur, const char *xpformat, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
int xpath_vec(cxobj *xcur, cvec *nsc, const char *xpformat, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 3, 6)));
|
int xpath_vec(cxobj *xcur, cvec *nsc, const char *xpformat, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 3, 6)));
|
||||||
|
|
||||||
int xpath2canonical(const char *xpath0, cvec *nsc0, yang_stmt *yspec, char **xpath1, cvec **nsc1, cbuf **cbreason);
|
int xpath2canonical(const char *xpath0, cvec *nsc0, yang_stmt *yspec,
|
||||||
|
char **xpath1, cvec **nsc1, cbuf **cbreason);
|
||||||
|
int xpath2canonical1(const char *xpath0, cvec *nsc0, yang_stmt *yspec, int exprstr,
|
||||||
|
char **xpath1, cvec **nsc1, cbuf **cbreason);
|
||||||
int xpath_count(cxobj *xcur, cvec *nsc, const char *xpath, uint32_t *count);
|
int xpath_count(cxobj *xcur, cvec *nsc, const char *xpath, uint32_t *count);
|
||||||
int xml2xpath(cxobj *x, cvec *nsc, int spec, int apostrophe, char **xpath);
|
int xml2xpath(cxobj *x, cvec *nsc, int spec, int apostrophe, char **xpath);
|
||||||
int xpath2xml(char *xpath, cvec *nsc, cxobj *xtop, yang_stmt *ytop,
|
int xpath2xml(char *xpath, cvec *nsc, cxobj *xtop, yang_stmt *ytop,
|
||||||
|
|
|
||||||
|
|
@ -261,8 +261,8 @@ int yang_flag_set(yang_stmt *ys, uint16_t flag);
|
||||||
int yang_flag_reset(yang_stmt *ys, uint16_t flag);
|
int yang_flag_reset(yang_stmt *ys, uint16_t flag);
|
||||||
yang_stmt *yang_when_get(clixon_handle h, yang_stmt *ys);
|
yang_stmt *yang_when_get(clixon_handle h, yang_stmt *ys);
|
||||||
int yang_when_set(clixon_handle h, yang_stmt *ys, yang_stmt *ywhen);
|
int yang_when_set(clixon_handle h, yang_stmt *ys, yang_stmt *ywhen);
|
||||||
char *yang_when_xpath_get(yang_stmt *ys);
|
int yang_when_xpath_get(yang_stmt *ys, char **xpath, cvec **nsc);
|
||||||
cvec *yang_when_nsc_get(yang_stmt *ys);
|
int yang_when_canonical_xpath_get(yang_stmt *ys, char **xpath, cvec **nsc);
|
||||||
const char *yang_filename_get(yang_stmt *ys);
|
const char *yang_filename_get(yang_stmt *ys);
|
||||||
int yang_filename_set(yang_stmt *ys, const char *filename);
|
int yang_filename_set(yang_stmt *ys, const char *filename);
|
||||||
uint32_t yang_linenum_get(yang_stmt *ys);
|
uint32_t yang_linenum_get(yang_stmt *ys);
|
||||||
|
|
|
||||||
|
|
@ -281,56 +281,94 @@ check_body_namespace(cxobj *x0,
|
||||||
* @retval 1 OK
|
* @retval 1 OK
|
||||||
* @retval 0 Failed (cbret set)
|
* @retval 0 Failed (cbret set)
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @note There may be some combination cases (x0+x1) that are not covered in this function.
|
* XXX this code is a mess. It tries multiple methods, one after the other. The solution
|
||||||
|
* is probably to make xpath evaluation namespace aware in combination with XML evaluation
|
||||||
|
* (3+4)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
check_when_condition(cxobj *x0p,
|
check_when_condition(cxobj *x0p,
|
||||||
cxobj *x1,
|
cxobj *x1,
|
||||||
yang_stmt *y0,
|
yang_stmt *y0,
|
||||||
cbuf *cbret)
|
cbuf *cbret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *xpath = NULL;
|
char *xpath = NULL;
|
||||||
cvec *nsc = NULL;
|
cvec *nsc = NULL;
|
||||||
int nr;
|
int nr;
|
||||||
yang_stmt *y = NULL;
|
yang_stmt *y = NULL;
|
||||||
cbuf *cberr = NULL;
|
cbuf *cberr = NULL;
|
||||||
cxobj *x1p;
|
cxobj *x1p;
|
||||||
|
cvec *cnsc = NULL;
|
||||||
|
cvec *nnsc = NULL;
|
||||||
|
char *cxpath = NULL;
|
||||||
|
|
||||||
if ((y = y0) != NULL ||
|
if ((y = y0) != NULL ||
|
||||||
(y = (yang_stmt*)xml_spec(x1)) != NULL){
|
(y = (yang_stmt*)xml_spec(x1)) != NULL){
|
||||||
if ((xpath = yang_when_xpath_get(y)) != NULL){
|
x1p = xml_parent(x1);
|
||||||
nsc = yang_when_nsc_get(y);
|
if (yang_when_xpath_get(y, &xpath, &nsc) < 0)
|
||||||
x1p = xml_parent(x1);
|
goto done;
|
||||||
if ((nr = xpath_vec_bool(x1p, nsc, "%s", xpath)) < 0) /* Try request */
|
if (xpath == NULL)
|
||||||
goto done;
|
goto ok;
|
||||||
if (nr == 0){
|
/* 1. Try yang context for existing xml
|
||||||
/* Try existing tree */
|
* Sufficient for all clixon/controller tests.
|
||||||
if ((nr = xpath_vec_bool(x0p, nsc, "%s", xpath)) < 0)
|
* Required for test_augment */
|
||||||
goto done;
|
if ((nr = xpath_vec_bool(x0p, nsc, "%s", xpath)) < 0)
|
||||||
if (nr == 0){
|
goto done;
|
||||||
if ((cberr = cbuf_new()) == NULL){
|
if (nr != 0)
|
||||||
clixon_err(OE_UNIX, errno, "cbuf_new");
|
goto ok;
|
||||||
goto done;
|
if (xml_nsctx_node(x1p, &nnsc) < 0)
|
||||||
}
|
goto done;
|
||||||
cprintf(cberr, "Node '%s' tagged with 'when' condition '%s' in module '%s' evaluates to false in edit-config operation (see RFC 7950 Sec 8.3.2)",
|
/* 2. Try yang context for incoming xml */
|
||||||
yang_argument_get(y),
|
if ((nr = xpath_vec_bool(x1p, nsc, "%s", xpath)) < 0)
|
||||||
xpath,
|
goto done;
|
||||||
yang_argument_get(ys_module(y)));
|
if (nr != 0)
|
||||||
if (netconf_unknown_element(cbret, "application", yang_argument_get(y),
|
goto ok;
|
||||||
cbuf_get(cberr)) < 0)
|
/* 3. Try xml context for incoming xml */
|
||||||
goto done;
|
if ((nr = xpath_vec_bool(x1p, nnsc, "%s", xpath)) < 0) /* Try request */
|
||||||
goto fail;
|
goto done;
|
||||||
}
|
if (nr != 0)
|
||||||
}
|
goto ok;
|
||||||
|
/* 4. Try xml context for existing xml */
|
||||||
|
if ((nr = xpath_vec_bool(x0p, nnsc, "%s", xpath)) < 0) /* Try request */
|
||||||
|
goto done;
|
||||||
|
if (nr != 0)
|
||||||
|
goto ok;
|
||||||
|
if (yang_when_canonical_xpath_get(y, &cxpath, &cnsc) < 0)
|
||||||
|
goto done;
|
||||||
|
/* 5. Try yang canonical context for incoming xml */
|
||||||
|
if ((nr = xpath_vec_bool(x1p, cnsc, "%s", cxpath)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (nr != 0)
|
||||||
|
goto ok;
|
||||||
|
/* 6. Try yang canonical context for existing xml */
|
||||||
|
if ((nr = xpath_vec_bool(x0p, cnsc, "%s", cxpath)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (nr != 0)
|
||||||
|
goto ok;
|
||||||
|
if ((cberr = cbuf_new()) == NULL){
|
||||||
|
clixon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
cprintf(cberr, "Node '%s' tagged with 'when' condition '%s' in module '%s' evaluates to false in edit-config operation (see RFC 7950 Sec 8.3.2)",
|
||||||
|
yang_argument_get(y),
|
||||||
|
xpath,
|
||||||
|
yang_argument_get(ys_module(y)));
|
||||||
|
if (netconf_unknown_element(cbret, "application", yang_argument_get(y),
|
||||||
|
cbuf_get(cberr)) < 0)
|
||||||
|
goto done;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
ok:
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
if (nsc)
|
if (nsc)
|
||||||
cvec_free(nsc);
|
cvec_free(nsc);
|
||||||
if (cberr)
|
if (cberr)
|
||||||
cbuf_free(cberr);
|
cbuf_free(cberr);
|
||||||
|
if (cxpath)
|
||||||
|
free(cxpath);
|
||||||
|
if (nnsc)
|
||||||
|
cvec_free(nnsc);
|
||||||
return retval;
|
return retval;
|
||||||
fail:
|
fail:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -466,7 +504,6 @@ choice_other_match(cxobj *x0,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Modify a base tree x0 with x1 with yang spec y according to operation op
|
/*! Modify a base tree x0 with x1 with yang spec y according to operation op
|
||||||
*
|
*
|
||||||
* @param[in] h Clixon handle
|
* @param[in] h Clixon handle
|
||||||
|
|
|
||||||
|
|
@ -2091,9 +2091,10 @@ yang_check_when_xpath(cxobj *xn,
|
||||||
int xmalloc = 0; /* ugly help variable to clean temporary object */
|
int xmalloc = 0; /* ugly help variable to clean temporary object */
|
||||||
|
|
||||||
/* First variant */
|
/* First variant */
|
||||||
if ((xpath = yang_when_xpath_get(yn)) != NULL){
|
if (yang_when_canonical_xpath_get(yn, &xpath, &nsc) < 0)
|
||||||
|
goto done;
|
||||||
|
if (xpath != NULL){
|
||||||
x = xp;
|
x = xp;
|
||||||
nsc = yang_when_nsc_get(yn);
|
|
||||||
*hit = 1;
|
*hit = 1;
|
||||||
}
|
}
|
||||||
/* Second variant */
|
/* Second variant */
|
||||||
|
|
|
||||||
|
|
@ -974,21 +974,78 @@ xpath_vec_bool(cxobj *xcur,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Translate literal string to "canonical" form
|
||||||
|
*
|
||||||
|
* the prefix according to actual namespace.
|
||||||
|
* Actually it depends on context if the rewrite should be made.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
traverse_canonical_str(xpath_tree *xs,
|
||||||
|
yang_stmt *yspec,
|
||||||
|
cvec *nsc0,
|
||||||
|
cvec *nsc1)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *name = NULL;
|
||||||
|
char *prefix0 = NULL;
|
||||||
|
char *prefix1 = NULL;
|
||||||
|
char *namespace;
|
||||||
|
yang_stmt *ymod;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
|
||||||
|
if (nodeid_split(xs->xs_s0, &prefix0, &name) < 0)
|
||||||
|
goto done;
|
||||||
|
if (prefix0 != NULL && name != NULL &&
|
||||||
|
(namespace = xml_nsctx_get(nsc0, prefix0)) != NULL) {
|
||||||
|
if ((ymod = yang_find_module_by_namespace(yspec, namespace)) != NULL &&
|
||||||
|
(prefix1 = yang_find_myprefix(ymod)) != NULL){
|
||||||
|
if (xml_nsctx_get(nsc1, prefix1) == NULL)
|
||||||
|
if (xml_nsctx_add(nsc1, prefix1, namespace) < 0)
|
||||||
|
goto done;
|
||||||
|
free(xs->xs_s0);
|
||||||
|
xs->xs_s0 = NULL;
|
||||||
|
if ((cb = cbuf_new()) == NULL){
|
||||||
|
clixon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cprintf(cb, "%s:%s", prefix1, name);
|
||||||
|
if ((xs->xs_s0 = strdup(cbuf_get(cb))) == NULL){
|
||||||
|
clixon_err(OE_UNIX, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
if (name)
|
||||||
|
free(name);
|
||||||
|
if (prefix0)
|
||||||
|
free(prefix0);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Translate an xpath/nsc pair to a "canonical" form using yang prefixes
|
/*! Translate an xpath/nsc pair to a "canonical" form using yang prefixes
|
||||||
*
|
*
|
||||||
|
* Returns new namespace context and rewrites the xpath tree
|
||||||
* @param[in] xs Parsed xpath - xpath_tree
|
* @param[in] xs Parsed xpath - xpath_tree
|
||||||
* @param[in] yspec Yang spec containing all modules, associated with namespaces
|
* @param[in] yspec Yang spec containing all modules, associated with namespaces
|
||||||
* @param[in] nsc0 Input namespace context
|
* @param[in] nsc0 Input namespace context
|
||||||
|
* @param[in] exprstr Interpret strings as <prefix>:<name> (primaryexpr/literal/string)
|
||||||
* @param[out] nsc1 Output namespace context. Free after use with xml_nsctx_free
|
* @param[out] nsc1 Output namespace context. Free after use with xml_nsctx_free
|
||||||
* @param[out] reason Error reason if result is 0 - failed
|
* @param[out] reason Error reason if result is 0 - failed
|
||||||
* @retval 1 OK with nsc1 containing the transformed nsc
|
* @retval 1 OK with nsc1 containing the transformed nsc
|
||||||
* @retval 0 XPath failure with reason set to why
|
* @retval 0 XPath failure with reason set to why
|
||||||
* @retval -1 Fatal Error
|
* @retval -1 Fatal Error
|
||||||
|
* @note Setting str to 1 requires a knowledge of the context of the xpath, ie that strings are
|
||||||
|
* something like identityref and is safe to translate into canonical form
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
xpath_traverse_canonical(xpath_tree *xs,
|
xpath_traverse_canonical(xpath_tree *xs,
|
||||||
yang_stmt *yspec,
|
yang_stmt *yspec,
|
||||||
cvec *nsc0,
|
cvec *nsc0,
|
||||||
|
int exprstr,
|
||||||
cvec *nsc1,
|
cvec *nsc1,
|
||||||
cbuf **reason)
|
cbuf **reason)
|
||||||
{
|
{
|
||||||
|
|
@ -999,9 +1056,13 @@ xpath_traverse_canonical(xpath_tree *xs,
|
||||||
yang_stmt *ymod;
|
yang_stmt *ymod;
|
||||||
cbuf *cb = NULL;
|
cbuf *cb = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
// char *name;
|
|
||||||
|
|
||||||
switch (xs->xs_type){
|
switch (xs->xs_type){
|
||||||
|
case XP_PRIME_STR:
|
||||||
|
if (exprstr != 0)
|
||||||
|
if (traverse_canonical_str(xs, yspec, nsc0, nsc1) < 0)
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
case XP_NODE: /* s0 is namespace prefix, s1 is name */
|
case XP_NODE: /* s0 is namespace prefix, s1 is name */
|
||||||
/* Nodetest = * needs no prefix */
|
/* Nodetest = * needs no prefix */
|
||||||
if (xs->xs_s1 && strcmp(xs->xs_s1, "*") == 0)
|
if (xs->xs_s1 && strcmp(xs->xs_s1, "*") == 0)
|
||||||
|
|
@ -1061,13 +1122,13 @@ xpath_traverse_canonical(xpath_tree *xs,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (xs->xs_c0){
|
if (xs->xs_c0){
|
||||||
if ((ret = xpath_traverse_canonical(xs->xs_c0, yspec, nsc0, nsc1, reason)) < 0)
|
if ((ret = xpath_traverse_canonical(xs->xs_c0, yspec, nsc0, exprstr, nsc1, reason)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (xs->xs_c1){
|
if (xs->xs_c1){
|
||||||
if ((ret = xpath_traverse_canonical(xs->xs_c1, yspec, nsc0, nsc1, reason)) < 0)
|
if ((ret = xpath_traverse_canonical(xs->xs_c1, yspec, nsc0, exprstr, nsc1, reason)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -1085,8 +1146,10 @@ xpath_traverse_canonical(xpath_tree *xs,
|
||||||
* @param[in] xpath0 Input xpath
|
* @param[in] xpath0 Input xpath
|
||||||
* @param[in] nsc0 Input namespace context
|
* @param[in] nsc0 Input namespace context
|
||||||
* @param[in] yspec Yang spec containing all modules, associated with namespaces
|
* @param[in] yspec Yang spec containing all modules, associated with namespaces
|
||||||
|
* @param[in] exprstr Interpret strings as <prefix>:<name> (primaryexpr/literal/string)
|
||||||
* @param[out] xpath1 Output xpath. Free after use with free
|
* @param[out] xpath1 Output xpath. Free after use with free
|
||||||
* @param[out] nsc1 Output namespace context. Free after use with xml_nsctx_free
|
* @param[out] nsc1 Output namespace context. Free after use with xml_nsctx_free
|
||||||
|
* @param[out] cbreason reason if retval = 0
|
||||||
* @retval 1 OK, xpath1 and nsc1 allocated
|
* @retval 1 OK, xpath1 and nsc1 allocated
|
||||||
* @retval 0 XPath failure with reason set to why
|
* @retval 0 XPath failure with reason set to why
|
||||||
* @retval -1 Fatal Error
|
* @retval -1 Fatal Error
|
||||||
|
|
@ -1116,12 +1179,13 @@ xpath_traverse_canonical(xpath_tree *xs,
|
||||||
* @see xpath2xml
|
* @see xpath2xml
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xpath2canonical(const char *xpath0,
|
xpath2canonical1(const char *xpath0,
|
||||||
cvec *nsc0,
|
cvec *nsc0,
|
||||||
yang_stmt *yspec,
|
yang_stmt *yspec,
|
||||||
char **xpath1,
|
int exprstr,
|
||||||
cvec **nsc1p,
|
char **xpath1,
|
||||||
cbuf **cbreason)
|
cvec **nsc1p,
|
||||||
|
cbuf **cbreason)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
xpath_tree *xpt = NULL;
|
xpath_tree *xpt = NULL;
|
||||||
|
|
@ -1133,13 +1197,14 @@ xpath2canonical(const char *xpath0,
|
||||||
/* Parse input xpath into an xpath-tree */
|
/* Parse input xpath into an xpath-tree */
|
||||||
if (xpath_parse(xpath0, &xpt) < 0)
|
if (xpath_parse(xpath0, &xpt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
// xpath_tree_print(stderr, xpt);
|
||||||
/* Create new nsc */
|
/* Create new nsc */
|
||||||
if ((nsc1 = xml_nsctx_init(NULL, NULL)) == NULL)
|
if ((nsc1 = xml_nsctx_init(NULL, NULL)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
/* Traverse tree to find prefixes, transform them to canonical form and
|
/* Traverse tree to find prefixes, transform them to canonical form and
|
||||||
* create a canonical network namespace
|
* create a canonical network namespace
|
||||||
*/
|
*/
|
||||||
if ((ret = xpath_traverse_canonical(xpt, yspec, nsc0, nsc1, cbreason)) < 0)
|
if ((ret = xpath_traverse_canonical(xpt, yspec, nsc0, exprstr, nsc1, cbreason)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -1174,6 +1239,17 @@ xpath2canonical(const char *xpath0,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xpath2canonical(const char *xpath0,
|
||||||
|
cvec *nsc0,
|
||||||
|
yang_stmt *yspec,
|
||||||
|
char **xpath1,
|
||||||
|
cvec **nsc1p,
|
||||||
|
cbuf **cbreason)
|
||||||
|
{
|
||||||
|
return xpath2canonical1(xpath0, nsc0, yspec, 0, xpath1, nsc1p, cbreason);
|
||||||
|
}
|
||||||
|
|
||||||
/*! Return a count(xpath)
|
/*! Return a count(xpath)
|
||||||
*
|
*
|
||||||
* @param[in] xcur xml-tree where to search
|
* @param[in] xcur xml-tree where to search
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,8 @@
|
||||||
#include "clixon_log.h"
|
#include "clixon_log.h"
|
||||||
#include "clixon_debug.h"
|
#include "clixon_debug.h"
|
||||||
#include "clixon_xml_nsctx.h"
|
#include "clixon_xml_nsctx.h"
|
||||||
|
#include "clixon_xpath_ctx.h"
|
||||||
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_yang_module.h"
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
#include "clixon_data.h"
|
#include "clixon_data.h"
|
||||||
|
|
@ -524,45 +526,68 @@ yang_when_set(clixon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Get yang xpath for "when"-associated augment
|
/*! Get xpath and namespace context for "when"-associated augment
|
||||||
*
|
*
|
||||||
* Ie, for yang structures like: augment <path> { when <xpath>; ... }
|
* Ie, for yang structures like: augment <path> { when <xpath>; ... }
|
||||||
* Will insert new yang nodes at <path> with this special "when" struct (not yang node)
|
* Inserts new yang nodes at <path> with this special "when" struct (not yang node)
|
||||||
* @param[in] ys Yang statement
|
* @param[in] ys Yang statement
|
||||||
* @retval xpath xpath should evaluate to true at validation
|
* @param[out] xpath
|
||||||
* @retval NULL Not set
|
* @param[out] nsc
|
||||||
* @note xpath context is PARENT which is different from when actual when child which is
|
|
||||||
* child itself
|
|
||||||
*/
|
*/
|
||||||
char*
|
int
|
||||||
yang_when_xpath_get(yang_stmt *ys)
|
yang_when_xpath_get(yang_stmt *ys,
|
||||||
|
char **xpath,
|
||||||
|
cvec **nsc)
|
||||||
{
|
{
|
||||||
yang_stmt *ywhen;
|
int retval = -1;
|
||||||
|
yang_stmt *ywhen;
|
||||||
if ((ywhen = yang_when_get(NULL, ys)) != NULL)
|
cvec *nsc0 = NULL;
|
||||||
return yang_argument_get(ywhen);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Get yang namespace context for "when"-associated augment
|
|
||||||
*
|
|
||||||
* Ie, for yang structures like: augment <path> { when <xpath>; ... }
|
|
||||||
* Will insert new yang nodes at <path> with this special "when" struct (not yang node)
|
|
||||||
* @param[in] ys Yang statement
|
|
||||||
* @retval nsc Namespace context (caller frees with cvec_free)
|
|
||||||
* @note retval is direct pointer, may need to be copied
|
|
||||||
*/
|
|
||||||
cvec *
|
|
||||||
yang_when_nsc_get(yang_stmt *ys)
|
|
||||||
{
|
|
||||||
yang_stmt *ywhen;
|
|
||||||
cvec *wnsc = NULL;
|
|
||||||
|
|
||||||
if ((ywhen = yang_when_get(NULL, ys)) != NULL) {
|
if ((ywhen = yang_when_get(NULL, ys)) != NULL) {
|
||||||
if (xml_nsctx_yang(ywhen, &wnsc) < 0)
|
if (xml_nsctx_yang(ywhen, nsc) < 0)
|
||||||
wnsc = NULL;
|
goto done;
|
||||||
|
if (xpath)
|
||||||
|
*xpath = yang_argument_get(ywhen);
|
||||||
}
|
}
|
||||||
return wnsc;
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (nsc0)
|
||||||
|
cvec_free(nsc0);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Get canonical xpath and namespace context for "when"-associated augment
|
||||||
|
*
|
||||||
|
* Ie, for yang structures like: augment <path> { when <xpath>; ... }
|
||||||
|
* Inserts new yang nodes at <path> with this special "when" struct (not yang node)
|
||||||
|
* @param[in] ys Yang statement
|
||||||
|
* @param[out] xpath
|
||||||
|
* @param[out] nsc
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
yang_when_canonical_xpath_get(yang_stmt *ys,
|
||||||
|
char **xpath,
|
||||||
|
cvec **nsc)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
yang_stmt *ywhen;
|
||||||
|
char *xpath0;
|
||||||
|
cvec *nsc0 = NULL;
|
||||||
|
|
||||||
|
if ((ywhen = yang_when_get(NULL, ys)) != NULL) {
|
||||||
|
if (xml_nsctx_yang(ywhen, &nsc0) < 0)
|
||||||
|
goto done;
|
||||||
|
xpath0 = yang_argument_get(ywhen);
|
||||||
|
if (xpath0 && nsc0){
|
||||||
|
if (xpath2canonical1(xpath0, nsc0, ys_spec(ys), 1, xpath, nsc, NULL) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (nsc0)
|
||||||
|
cvec_free(nsc0);
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Get yang filename for error/debug purpose (only modules)
|
/*! Get yang filename for error/debug purpose (only modules)
|
||||||
|
|
|
||||||
|
|
@ -14,15 +14,37 @@ fi
|
||||||
|
|
||||||
# canonical namespace xpath tests
|
# canonical namespace xpath tests
|
||||||
# need yang modules
|
# need yang modules
|
||||||
|
cat <<EOF > $ydir/t.yang
|
||||||
|
module t {
|
||||||
|
namespace "urn:example:t";
|
||||||
|
prefix t;
|
||||||
|
|
||||||
|
identity baseid {
|
||||||
|
description "Base identity";
|
||||||
|
}
|
||||||
|
identity des {
|
||||||
|
base "baseid";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
cat <<EOF > $ydir/a.yang
|
cat <<EOF > $ydir/a.yang
|
||||||
module a{
|
module a{
|
||||||
namespace "urn:example:a";
|
namespace "urn:example:a";
|
||||||
prefix a;
|
prefix a;
|
||||||
container x{
|
import t {
|
||||||
leaf xa{
|
prefix t;
|
||||||
type string;
|
}
|
||||||
}
|
container x{
|
||||||
}
|
leaf xa{
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
leaf xb{
|
||||||
|
type identityref {
|
||||||
|
base "t:baseid";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
@ -37,6 +59,17 @@ module b{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
new "xpath canonical identity predicate"
|
||||||
|
expectpart "$($clixon_util_xpath -c -y $ydir -p "/x[xb=t2:des]" -n null:urn:example:a -n t2:urn:example:t)" 0 "/a:x\[a:xb=t:des\]" '0 : a = "urn:example:a"' '1 : t = "urn:example:t"'
|
||||||
|
|
||||||
|
new "xpath canonical identity predicate"
|
||||||
|
expectpart "$($clixon_util_xpath -c -y $ydir -p "/x[xb='t2:des']" -n null:urn:example:a -n t2:urn:example:t)" 0 "/a:x\[a:xb='t:des'\]" '0 : a = "urn:example:a"' '1 : t = "urn:example:t"'
|
||||||
|
|
||||||
|
new "xpath canonical identity boolean"
|
||||||
|
expectpart "$($clixon_util_xpath -c -y $ydir -p /x/xb='t2:des' -n null:urn:example:a -n t2:urn:example:t)" 0 "/a:x/a:xb=t:des" '0 : a = "urn:example:a"' '1 : t = "urn:example:t"'
|
||||||
|
|
||||||
|
new "xpath canonical identity boolean with quotes"
|
||||||
|
expectpart "$($clixon_util_xpath -c -y $ydir -p "/x/xb='t2:des'" -n null:urn:example:a -n t2:urn:example:t)" 0 "/a:x/a:xb='t:des'" '0 : a = "urn:example:a"' '1 : t = "urn:example:t"'
|
||||||
|
|
||||||
new "xpath canonical form (already canonical)"
|
new "xpath canonical form (already canonical)"
|
||||||
expectpart "$($clixon_util_xpath -c -y $ydir -p /a:x/b:y -n a:urn:example:a -n b:urn:example:b)" 0 '/a:x/b:y' '0 : a = "urn:example:a"' '1 : b = "urn:example:b"'
|
expectpart "$($clixon_util_xpath -c -y $ydir -p /a:x/b:y -n a:urn:example:a -n b:urn:example:b)" 0 '/a:x/b:y' '0 : a = "urn:example:a"' '1 : b = "urn:example:b"'
|
||||||
|
|
|
||||||
|
|
@ -189,13 +189,13 @@ new "Change type to atm"
|
||||||
expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><interface xmlns=\"urn:example:clixon\"><name>e0</name><type>atm</type></interface></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><interface xmlns=\"urn:example:clixon\"><name>e0</name><type>atm</type></interface></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||||
|
|
||||||
new "netconf validate not OK (mtu not allowed)"
|
new "netconf validate not OK (mtu not allowed)"
|
||||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><validate><source><candidate/></source></validate></rpc>" "" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>Failed WHEN condition of mtu in module example (WHEN xpath is derived-from(type, \"ex:ethernet\"))</error-message></rpc-error></rpc-reply>"
|
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><validate><source><candidate/></source></validate></rpc>" "" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>Failed WHEN condition of mtu in module example (WHEN xpath is derived-from(ex:type,'ex:ethernet'))</error-message></rpc-error></rpc-reply>"
|
||||||
|
|
||||||
new "Change type to ethernet (self)"
|
new "Change type to ethernet (self)"
|
||||||
expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><interface xmlns=\"urn:example:clixon\"><name>e0</name><type>ethernet</type></interface></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><interface xmlns=\"urn:example:clixon\"><name>e0</name><type>ethernet</type></interface></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||||
|
|
||||||
new "netconf validate not OK (mtu not allowed on self)"
|
new "netconf validate not OK (mtu not allowed on self)"
|
||||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><validate><source><candidate/></source></validate></rpc>" "" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>Failed WHEN condition of mtu in module example (WHEN xpath is derived-from(type, \"ex:ethernet\"))</error-message></rpc-error></rpc-reply>"
|
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><validate><source><candidate/></source></validate></rpc>" "" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>Failed WHEN condition of mtu in module example (WHEN xpath is derived-from(ex:type,'ex:ethernet'))</error-message></rpc-error></rpc-reply>"
|
||||||
|
|
||||||
new "netconf discard-changes"
|
new "netconf discard-changes"
|
||||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><discard-changes/></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><discard-changes/></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||||
|
|
@ -211,7 +211,7 @@ new "Change type to atm"
|
||||||
expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><interface xmlns=\"urn:example:clixon\"><name>e0</name><type>atm</type></interface></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><interface xmlns=\"urn:example:clixon\"><name>e0</name><type>atm</type></interface></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||||
|
|
||||||
new "netconf validate not OK (crc not allowed)"
|
new "netconf validate not OK (crc not allowed)"
|
||||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><validate><source><candidate/></source></validate></rpc>" "" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>Failed WHEN condition of crc in module example (WHEN xpath is derived-from-or-self(type, \"ex:ethernet\"))</error-message></rpc-error></rpc-reply>"
|
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><validate><source><candidate/></source></validate></rpc>" "" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>Failed WHEN condition of crc in module example (WHEN xpath is derived-from-or-self(ex:type,'ex:ethernet'))</error-message></rpc-error></rpc-reply>"
|
||||||
|
|
||||||
new "Change type to ethernet (self)"
|
new "Change type to ethernet (self)"
|
||||||
expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><interface xmlns=\"urn:example:clixon\"><name>e0</name><type>ethernet</type></interface></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><interface xmlns=\"urn:example:clixon\"><name>e0</name><type>ethernet</type></interface></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue