Transform YANG when expressions to canonical xpath form

This commit is contained in:
Olof hagsand 2024-08-21 21:55:14 +02:00
parent 71e921520e
commit 26ca872b0c
8 changed files with 262 additions and 87 deletions

View file

@ -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,

View file

@ -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);

View file

@ -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

View file

@ -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 */

View file

@ -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

View file

@ -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)

View file

@ -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"'

View file

@ -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>"