Moved with-defaults processing from get(-config) to xmldb_get when reading db

With-defaults: fixed cornercase in xpath used in list pagination
C-API: Added `with-defaults` parameter (default 0) to `xmldb_get0()`
This commit is contained in:
Olof hagsand 2022-12-16 16:42:05 +01:00
parent e885d63f68
commit 0d41d49fa9
19 changed files with 420 additions and 196 deletions

View file

@ -51,6 +51,7 @@ Developers may need to change their code
* Added netconf ssh subsystem * Added netconf ssh subsystem
* Renamed from `clixon` built in `docker/base` * Renamed from `clixon` built in `docker/base`
* C-API * C-API
* Added `with-defaults` parameter (default 0) to `xmldb_get0()`
* Added `sock_flags` parameter to `clixon_proc_socket()` * Added `sock_flags` parameter to `clixon_proc_socket()`
### Minor features ### Minor features

View file

@ -180,7 +180,7 @@ startup_common(clicon_handle h,
* It is done below, later in this function * It is done below, later in this function
*/ */
if (clicon_option_bool(h, "CLICON_XMLDB_UPGRADE_CHECKOLD")){ if (clicon_option_bool(h, "CLICON_XMLDB_UPGRADE_CHECKOLD")){
if ((ret = xmldb_get0(h, db, YB_MODULE, NULL, "/", 0, &xt, msdiff, &xerr)) < 0) if ((ret = xmldb_get0(h, db, YB_MODULE, NULL, "/", 0, 0, &xt, msdiff, &xerr)) < 0)
goto done; goto done;
if (ret == 0){ /* ret should not be 0 */ if (ret == 0){ /* ret should not be 0 */
/* Print upgraded db: -q backend switch for debugging/ showing upgraded config only */ /* Print upgraded db: -q backend switch for debugging/ showing upgraded config only */
@ -197,7 +197,7 @@ startup_common(clicon_handle h,
} }
} }
else { else {
if (xmldb_get0(h, db, YB_NONE, NULL, "/", 0, &xt, msdiff, &xerr) < 0) if (xmldb_get0(h, db, YB_NONE, NULL, "/", 0, 0, &xt, msdiff, &xerr) < 0)
goto done; goto done;
} }
if (msdiff && msdiff->md_status == 0){ // Possibly check for CLICON_XMLDB_MODSTATE if (msdiff && msdiff->md_status == 0){ // Possibly check for CLICON_XMLDB_MODSTATE
@ -488,7 +488,7 @@ validate_common(clicon_handle h,
goto done; goto done;
} }
/* This is the state we are going to */ /* This is the state we are going to */
if ((ret = xmldb_get0(h, db, YB_MODULE, NULL, "/", 0, &td->td_target, NULL, xret)) < 0) if ((ret = xmldb_get0(h, db, YB_MODULE, NULL, "/", 0, 0, &td->td_target, NULL, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -497,7 +497,7 @@ validate_common(clicon_handle h,
(void*)(XML_FLAG_MARK|XML_FLAG_CHANGE)); (void*)(XML_FLAG_MARK|XML_FLAG_CHANGE));
/* 2. Parse xml trees /* 2. Parse xml trees
* This is the state we are going from */ * This is the state we are going from */
if ((ret = xmldb_get0(h, "running", YB_MODULE, NULL, "/", 0, &td->td_src, NULL, xret)) < 0) if ((ret = xmldb_get0(h, "running", YB_MODULE, NULL, "/", 0, 0, &td->td_src, NULL, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -960,7 +960,7 @@ from_client_restart_one(clicon_handle h,
if ((td = transaction_new()) == NULL) if ((td = transaction_new()) == NULL)
goto done; goto done;
/* This is the state we are going to */ /* This is the state we are going to */
if (xmldb_get0(h, "running", YB_MODULE, NULL, "/", 0, &td->td_target, NULL, NULL) < 0) if (xmldb_get0(h, "running", YB_MODULE, NULL, "/", 0, 0, &td->td_target, NULL, NULL) < 0)
goto done; goto done;
if ((ret = xml_yang_validate_all_top(h, td->td_target, &xerr)) < 0) if ((ret = xml_yang_validate_all_top(h, td->td_target, &xerr)) < 0)
goto done; goto done;
@ -970,7 +970,7 @@ from_client_restart_one(clicon_handle h,
goto fail; goto fail;
} }
/* This is the state we are going from */ /* This is the state we are going from */
if (xmldb_get0(h, db, YB_MODULE, NULL, "/", 0, &td->td_src, NULL, NULL) < 0) if (xmldb_get0(h, db, YB_MODULE, NULL, "/", 0, 0, &td->td_src, NULL, NULL) < 0)
goto done; goto done;
/* 3. Compute differences */ /* 3. Compute differences */

View file

@ -180,16 +180,18 @@ client_get_streams(clicon_handle h,
* @param[in] h Clicon handle * @param[in] h Clicon handle
* @param[in] xpath XPath selection, may be used to filter early * @param[in] xpath XPath selection, may be used to filter early
* @param[in] nsc XML Namespace context for xpath * @param[in] nsc XML Namespace context for xpath
* @param[in] wdef With-defaults parameter, see RFC 6243
* @param[in,out] xret Existing XML tree, merge x into this * @param[in,out] xret Existing XML tree, merge x into this
* @retval -1 Error (fatal) * @retval -1 Error (fatal)
* @retval 0 Statedata callback failed (clicon_err called) * @retval 0 Statedata callback failed (clicon_err called)
* @retval 1 OK * @retval 1 OK
*/ */
static int static int
get_client_statedata(clicon_handle h, get_client_statedata(clicon_handle h,
char *xpath, char *xpath,
cvec *nsc, cvec *nsc,
cxobj **xret) withdefaults_type wdef,
cxobj **xret)
{ {
int retval = -1; int retval = -1;
yang_stmt *yspec; yang_stmt *yspec;
@ -258,16 +260,63 @@ get_client_statedata(clicon_handle h,
goto fail; goto fail;
} }
/* Use plugin state callbacks */ /* Use plugin state callbacks */
if ((ret = clixon_plugin_statedata_all(h, yspec, nsc, xpath, xret)) < 0) if ((ret = clixon_plugin_statedata_all(h, yspec, nsc, xpath, wdef, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
/* Add default state to config if present */ switch (wdef){
if (xml_default_recurse(*xret, 1) < 0) case WITHDEFAULTS_REPORT_ALL:
goto done; case WITHDEFAULTS_EXPLICIT:
/* Add default global state */ /* Add global defaults. */
if (xml_global_defaults(h, *xret, nsc, xpath, yspec, 1) < 0) if (xml_global_defaults(h, *xret, nsc, xpath, yspec, 1) < 0)
goto done; goto done;
/* Apply default values */
if (xml_default_recurse(*xret, 1) < 0)
goto done;
break;
case WITHDEFAULTS_TRIM:
/* Mark and remove nodes having schema default values */
if (xml_apply((*xret), CX_ELMNT, (xml_applyfn_t*) xml_flag_state_default_value, (void*) XML_FLAG_MARK) < 0)
goto done;
if (xml_tree_prune_flags((*xret), XML_FLAG_MARK, XML_FLAG_MARK)
< 0)
goto done;
if (xml_defaults_nopresence((*xret), 1) < 0)
goto done;
break;
case WITHDEFAULTS_REPORT_ALL_TAGGED:{
cxobj *xc;
char *ns;
/* Add global defaults. */
if (xml_global_defaults(h, *xret, nsc, xpath, yspec, 1) < 0)
goto done;
/* Apply default values */
if (xml_default_recurse(*xret, 1) < 0)
goto done;
xc = NULL;
while ((xc = xml_child_each((*xret), xc, CX_ELMNT)) != NULL){
/* Check if exists */
ns = NULL;
if (xml2ns(xc, IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX, &ns) < 0)
goto done;
if (ns == NULL){
if (xmlns_set(xc, IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX, IETF_NETCONF_WITH_DEFAULTS_ATTR_NAMESPACE) < 0)
goto done;
}
else if (strcmp(ns, IETF_NETCONF_WITH_DEFAULTS_ATTR_NAMESPACE) != 0){
/* XXX: Assume if namespace is set that it is withdefaults otherwise just ignore? */
continue;
}
}
/* Mark nodes having default schema values */
if (xml_apply(*xret, CX_ELMNT, (xml_applyfn_t*) xml_flag_state_default_value, (void*) XML_FLAG_MARK) < 0)
goto done;
/* Add tag attributes to default nodes */
if (xml_apply(*xret, CX_ELMNT, (xml_applyfn_t*) xml_add_default_tag, (void*) (XML_FLAG_DEFAULT | XML_FLAG_MARK)) < 0)
goto done;
break;
}
} /* switch wdef */
retval = 1; /* OK */ retval = 1; /* OK */
done: done:
clicon_debug(1, "%s %d", __FUNCTION__, retval); clicon_debug(1, "%s %d", __FUNCTION__, retval);
@ -416,141 +465,6 @@ element2value(clicon_handle h,
return 1; return 1;
} }
/*! Set flag on node having schema default value.
* @param[in] x XML node
* @param[in] flag Flag to be used
* @retval 0 OK
*/
static int
xml_flag_default_value(cxobj *x,
uint16_t flag)
{
yang_stmt *y;
cg_var *cv;
char *yv;
char *xv;
xml_flag_reset(x, flag); /* Assume not default value */
if ((xv = xml_body(x)) == NULL)
goto done;
if ((y = xml_spec(x)) == NULL)
goto done;
if ((cv = yang_cv_get(y)) == NULL)
goto done;
if ((cv = yang_cv_get(y)) == NULL)
goto done;
if (cv_name_get(cv) == NULL)
goto done;
if ((yv = cv2str_dup(cv)) == NULL)
goto done;
if (strcmp(xv, yv) == 0)
xml_flag_set(x, flag); /* Actual value same as default value */
free(yv);
done:
return 0;
}
/*! Add default attribute to node with default value.
* @param[in] x XML node
* @param[in] flags Flags indicatiing default nodes
* @retval 0 OK
* @retval -1 Error
*/
static int
xml_add_default_tag(cxobj *x,
uint16_t flags)
{
int retval = -1;
cxobj *xattr;
if (xml_flag(x, flags)) {
/* set default attribute */
if ((xattr = xml_new("default", x, CX_ATTR)) == NULL)
goto done;
if (xml_value_set(xattr, "true") < 0)
goto done;
if (xml_prefix_set(xattr, IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
/*! Update XML return tree according to RFC6243: with-defaults
* @param[in] xe Request: <rpc><xn></rpc>
* @param[in] xret XML return tree to be updated
* @retval 0 OK
* @retval -1 Error
*/
static int
with_defaults(cxobj *xe,
cxobj *xret)
{
int retval = -1;
cxobj *xfind;
char *mode;
cxobj *x;
if ((xfind = xml_find(xe, "with-defaults")) != NULL) {
if ((mode = xml_find_value(xfind, "body")) == NULL)
goto done;
if (strcmp(mode, "explicit") == 0) {
/* Clear marked nodes */
if (xml_apply(xret, CX_ELMNT, (xml_applyfn_t*) xml_flag_reset,(void*) XML_FLAG_MARK) < 0)
goto done;
/* Mark state nodes */
if (xml_non_config_data(xret, NULL) < 0)
goto done;
/* Remove default configuration nodes */
if (xml_tree_prune_flags(xret, XML_FLAG_DEFAULT, XML_FLAG_MARK | XML_FLAG_DEFAULT) < 0)
goto done;
/* Remove empty containers */
if (xml_defaults_nopresence(xret, 1) < 0)
goto done;
goto ok;
}
else if (strcmp(mode, "trim") == 0) {
/* Remove default nodes from XML */
if (xml_tree_prune_flags(xret, XML_FLAG_DEFAULT, XML_FLAG_DEFAULT) < 0)
goto done;
/* Mark and remove nodes having schema default values */
if (xml_apply(xret, CX_ELMNT, (xml_applyfn_t*) xml_flag_default_value, (void*) XML_FLAG_MARK) < 0)
goto done;
if (xml_tree_prune_flags(xret, XML_FLAG_MARK, XML_FLAG_MARK)
< 0)
goto done;
/* Remove empty containers */
if (xml_defaults_nopresence(xret, 1) < 0)
goto done;
goto ok;
}
else if (strcmp(mode, "report-all-tagged") == 0) {
x = NULL;
while ((x = xml_child_each(xret, x, CX_ELMNT)) != NULL)
if (xmlns_set(x, IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX, IETF_NETCONF_WITH_DEFAULTS_ATTR_NAMESPACE) < 0)
goto done;
/* Mark nodes having default schema values */
if (xml_apply(xret, CX_ELMNT, (xml_applyfn_t*) xml_flag_default_value, (void*) XML_FLAG_MARK) < 0)
goto done;
/* Add tag attributes to default nodes */
if (xml_apply(xret, CX_ELMNT, (xml_applyfn_t*) xml_add_default_tag, (void*) (XML_FLAG_DEFAULT | XML_FLAG_MARK)) < 0)
goto done;
goto ok;
}
else if (strcmp(mode, "report-all") == 0) {
/* Accept mode, do nothing */
goto ok;
}
}
ok:
retval = 0;
done:
return retval;
}
/*! Extract offset and limit from get/list-pagination /*! Extract offset and limit from get/list-pagination
* *
* @param[in] h Clicon handle * @param[in] h Clicon handle
@ -592,6 +506,8 @@ list_pagination_hdr(clicon_handle h,
* @param[in] db Database name * @param[in] db Database name
* @param[in] xpath XPath point to object to get * @param[in] xpath XPath point to object to get
* @param[in] nsc Namespace context of xpath * @param[in] nsc Namespace context of xpath
* @param[in] username
* @param[in] wdef With-defaults parameter, see RFC 6243
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error.. * @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @retval 0 OK * @retval 0 OK
* @retval -1 Error * @retval -1 Error
@ -610,6 +526,7 @@ get_list_pagination(clicon_handle h,
char *xpath, char *xpath,
cvec *nsc, cvec *nsc,
char *username, char *username,
withdefaults_type wdef,
cbuf *cbret cbuf *cbret
) )
{ {
@ -733,7 +650,7 @@ get_list_pagination(clicon_handle h,
/* Append predicate to original xpath and replace it */ /* Append predicate to original xpath and replace it */
xpath2 = cbuf_get(cbpath); xpath2 = cbuf_get(cbpath);
/* specific xpath */ /* specific xpath */
if (xmldb_get0(h, db, YB_MODULE, nsc, xpath2?xpath2:"/", 1, &xret, NULL, NULL) < 0) { if (xmldb_get0(h, db, YB_MODULE, nsc, xpath2?xpath2:"/", 1, wdef, &xret, NULL, NULL) < 0) {
if ((cbmsg = cbuf_new()) == NULL){ if ((cbmsg = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new"); clicon_err(OE_UNIX, errno, "cbuf_new");
goto done; goto done;
@ -803,8 +720,6 @@ get_list_pagination(clicon_handle h,
goto ok; goto ok;
} }
} }
if (with_defaults(xml_parent(xe), xret) < 0)
goto done;
if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done; goto done;
/* Help function to filter out anything that is outside of xpath */ /* Help function to filter out anything that is outside of xpath */
@ -900,6 +815,8 @@ get_common(clicon_handle h,
cxobj *xfind; cxobj *xfind;
uint32_t offset = 0; uint32_t offset = 0;
uint32_t limit = 0; uint32_t limit = 0;
withdefaults_type wdef = WITHDEFAULTS_REPORT_ALL;
char *wdefstr;
clicon_debug(1, "%s", __FUNCTION__); clicon_debug(1, "%s", __FUNCTION__);
username = clicon_username_get(h); username = clicon_username_get(h);
@ -939,6 +856,8 @@ get_common(clicon_handle h,
goto ok; goto ok;
} }
} }
if ((wdefstr = xml_find_body(xe, "with-defaults")) != NULL)
wdef = withdefaults_str2int(wdefstr);
/* Check if list pagination */ /* Check if list pagination */
if ((xfind = xml_find_type(xe, NULL, "list-pagination", CX_ELMNT)) != NULL){ if ((xfind = xml_find_type(xe, NULL, "list-pagination", CX_ELMNT)) != NULL){
/* with non-presence list-pagination, use ad-hoc algorithm to determine /* with non-presence list-pagination, use ad-hoc algorithm to determine
@ -962,7 +881,7 @@ get_common(clicon_handle h,
if (get_list_pagination(h, ce, if (get_list_pagination(h, ce,
xfind, xfind,
content, db, content, db,
depth, yspec, xpath, nsc, username, depth, yspec, xpath, nsc, username, wdef,
cbret) < 0) cbret) < 0)
goto done; goto done;
goto ok; goto ok;
@ -971,7 +890,7 @@ get_common(clicon_handle h,
switch (content){ switch (content){
case CONTENT_CONFIG: /* config data only */ case CONTENT_CONFIG: /* config data only */
/* specific xpath */ /* specific xpath */
if (xmldb_get0(h, db, YB_MODULE, nsc, xpath?xpath:"/", 1, &xret, NULL, NULL) < 0) { if (xmldb_get0(h, db, YB_MODULE, nsc, xpath?xpath:"/", 1, wdef, &xret, NULL, NULL) < 0) {
if ((cbmsg = cbuf_new()) == NULL){ if ((cbmsg = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new"); clicon_err(OE_UNIX, errno, "cbuf_new");
goto done; goto done;
@ -986,7 +905,7 @@ get_common(clicon_handle h,
case CONTENT_NONCONFIG: /* state data only */ case CONTENT_NONCONFIG: /* state data only */
if (clicon_option_bool(h, "CLICON_VALIDATE_STATE_XML")){ if (clicon_option_bool(h, "CLICON_VALIDATE_STATE_XML")){
/* Whole config tree, for validate debug */ /* Whole config tree, for validate debug */
if (xmldb_get0(h, "running", YB_MODULE, nsc, NULL, 1, &xret, NULL, NULL) < 0) { if (xmldb_get0(h, "running", YB_MODULE, nsc, NULL, 1, wdef, &xret, NULL, NULL) < 0) {
if ((cbmsg = cbuf_new()) == NULL){ if ((cbmsg = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new"); clicon_err(OE_UNIX, errno, "cbuf_new");
goto done; goto done;
@ -999,7 +918,7 @@ get_common(clicon_handle h,
} }
else if (content == CONTENT_ALL){ else if (content == CONTENT_ALL){
/* specific xpath */ /* specific xpath */
if (xmldb_get0(h, db, YB_MODULE, nsc, xpath?xpath:"/", 1, &xret, NULL, NULL) < 0) { if (xmldb_get0(h, db, YB_MODULE, nsc, xpath?xpath:"/", 1, wdef, &xret, NULL, NULL) < 0) {
if ((cbmsg = cbuf_new()) == NULL){ if ((cbmsg = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new"); clicon_err(OE_UNIX, errno, "cbuf_new");
goto done; goto done;
@ -1024,7 +943,7 @@ get_common(clicon_handle h,
break; break;
case CONTENT_ALL: /* both config and state */ case CONTENT_ALL: /* both config and state */
case CONTENT_NONCONFIG: /* state data only */ case CONTENT_NONCONFIG: /* state data only */
if ((ret = get_client_statedata(h, xpath?xpath:"/", nsc, &xret)) < 0) if ((ret = get_client_statedata(h, xpath?xpath:"/", nsc, wdef, &xret)) < 0)
goto done; goto done;
if (ret == 0){ /* Error from callback (error in xret) */ if (ret == 0){ /* Error from callback (error in xret) */
if (clixon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0) if (clixon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
@ -1033,8 +952,6 @@ get_common(clicon_handle h,
} }
break; break;
} }
if (with_defaults(xe, xret) < 0)
goto done;
if (content != CONTENT_CONFIG && if (content != CONTENT_CONFIG &&
clicon_option_bool(h, "CLICON_VALIDATE_STATE_XML")){ clicon_option_bool(h, "CLICON_VALIDATE_STATE_XML")){
/* Check XML by validating it. return internal error with error cause /* Check XML by validating it. return internal error with error cause

View file

@ -320,10 +320,7 @@ clixon_plugin_statedata_one(clixon_plugin_t *cp,
* @param[in] yspec Yang spec * @param[in] yspec Yang spec
* @param[in] nsc Namespace context * @param[in] nsc Namespace context
* @param[in] xpath String with XPATH syntax. or NULL for all * @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in] pagmode List pagination mode * @param[in] wdef With-defaults parameter, see RFC 6243
* @param[in] offset Offset, for list pagination
* @param[in] limit Limit, for list pagination
* @param[out] remaining Remaining elements (if limit is non-zero)
* @param[in,out] xret State XML tree is merged with existing tree. * @param[in,out] xret State XML tree is merged with existing tree.
* @retval -1 Error * @retval -1 Error
* @retval 0 Statedata callback failed (xret set with netconf-error) * @retval 0 Statedata callback failed (xret set with netconf-error)
@ -335,6 +332,7 @@ clixon_plugin_statedata_all(clicon_handle h,
yang_stmt *yspec, yang_stmt *yspec,
cvec *nsc, cvec *nsc,
char *xpath, char *xpath,
withdefaults_type wdef,
cxobj **xret) cxobj **xret)
{ {
int retval = -1; int retval = -1;
@ -388,10 +386,9 @@ clixon_plugin_statedata_all(clicon_handle h,
if (xml_sort_recurse(x) < 0) if (xml_sort_recurse(x) < 0)
goto done; goto done;
/* Remove global defaults and empty non-presence containers */ /* Remove global defaults and empty non-presence containers */
/* XXX: only for state data and according to with-defaults setting */
if (xml_defaults_nopresence(x, 2) < 0) if (xml_defaults_nopresence(x, 2) < 0)
goto done; goto done;
if (xml_default_recurse(x, 1) < 0)
goto done;
if ((ret = netconf_trymerge(x, yspec, xret)) < 0) if ((ret = netconf_trymerge(x, yspec, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)

View file

@ -86,7 +86,7 @@ db_merge(clicon_handle h,
cxobj *xt = NULL; cxobj *xt = NULL;
/* Get data as xml from db1 */ /* Get data as xml from db1 */
if (xmldb_get0(h, (char*)db1, YB_MODULE, NULL, NULL, 0, &xt, NULL, NULL) < 0) if (xmldb_get0(h, (char*)db1, YB_MODULE, NULL, NULL, 0, 0, &xt, NULL, NULL) < 0)
goto done; goto done;
xml_name_set(xt, NETCONF_INPUT_CONFIG); xml_name_set(xt, NETCONF_INPUT_CONFIG);
/* Merge xml into db2. Without commit */ /* Merge xml into db2. Without commit */

View file

@ -99,7 +99,7 @@ int clixon_plugin_pre_daemon_all(clicon_handle h);
int clixon_plugin_daemon_all(clicon_handle h); int clixon_plugin_daemon_all(clicon_handle h);
int clixon_plugin_statedata_all(clicon_handle h, yang_stmt *yspec, cvec *nsc, char *xpath, int clixon_plugin_statedata_all(clicon_handle h, yang_stmt *yspec, cvec *nsc, char *xpath,
cxobj **xtop); withdefaults_type wdef, cxobj **xtop);
int clixon_plugin_lockdb_all(clicon_handle h, char *db, int lock, int id); int clixon_plugin_lockdb_all(clicon_handle h, char *db, int lock, int id);
int clixon_pagination_cb_register(clicon_handle h, handler_function fn, char *path, void *arg); int clixon_pagination_cb_register(clicon_handle h, handler_function fn, char *path, void *arg);

View file

@ -448,7 +448,7 @@ example_statedata(clicon_handle h,
* Get config according to xpath */ * Get config according to xpath */
if ((nsc1 = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-interfaces")) == NULL) if ((nsc1 = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-interfaces")) == NULL)
goto done; goto done;
if (xmldb_get0(h, "running", YB_MODULE, nsc1, "/interfaces/interface/name", 1, &xt, NULL, NULL) < 0) if (xmldb_get0(h, "running", YB_MODULE, nsc1, "/interfaces/interface/name", 1, 0, &xt, NULL, NULL) < 0)
goto done; goto done;
if (xpath_vec(xt, nsc1, "/interfaces/interface/name", &xvec, &xlen) < 0) if (xpath_vec(xt, nsc1, "/interfaces/interface/name", &xvec, &xlen) < 0)
goto done; goto done;

View file

@ -52,8 +52,8 @@ int xmldb_disconnect(clicon_handle h);
/* in clixon_datastore_read.[ch] */ /* in clixon_datastore_read.[ch] */
int xmldb_get(clicon_handle h, const char *db, cvec *nsc, char *xpath, cxobj **xtop); int xmldb_get(clicon_handle h, const char *db, cvec *nsc, char *xpath, cxobj **xtop);
int xmldb_get0(clicon_handle h, const char *db, yang_bind yb, int xmldb_get0(clicon_handle h, const char *db, yang_bind yb,
cvec *nsc, const char *xpath, cvec *nsc, const char *xpath, int copy, withdefaults_type wdef,
int copy, cxobj **xtop, modstate_diff_t *msd, cxobj **xerr); cxobj **xtop, modstate_diff_t *msd, cxobj **xerr);
int xmldb_get0_clear(clicon_handle h, cxobj *x); int xmldb_get0_clear(clicon_handle h, cxobj *x);
int xmldb_get0_free(clicon_handle h, cxobj **xp); int xmldb_get0_free(clicon_handle h, cxobj **xp);
int xmldb_put(clicon_handle h, const char *db, enum operation_type op, cxobj *xt, char *username, cbuf *cbret); /* in clixon_datastore_write.[ch] */ int xmldb_put(clicon_handle h, const char *db, enum operation_type op, cxobj *xt, char *username, cbuf *cbret); /* in clixon_datastore_write.[ch] */

View file

@ -129,6 +129,17 @@ enum framing_type{
}; };
typedef enum framing_type netconf_framing_type; typedef enum framing_type netconf_framing_type;
/* NETCONF with-defaults
* @see RFC 6243
*/
enum withdefaults_type{
WITHDEFAULTS_REPORT_ALL = 0, /* default */
WITHDEFAULTS_TRIM,
WITHDEFAULTS_EXPLICIT,
WITHDEFAULTS_REPORT_ALL_TAGGED
};
typedef enum withdefaults_type withdefaults_type;
/* /*
* Macros * Macros
*/ */
@ -142,6 +153,8 @@ typedef enum framing_type netconf_framing_type;
/* /*
* Prototypes * Prototypes
*/ */
char *withdefaults_int2str(int keyword);
int withdefaults_str2int(char *str);
int netconf_in_use(cbuf *cb, char *type, char *message); int netconf_in_use(cbuf *cb, char *type, char *message);
int netconf_invalid_value(cbuf *cb, char *type, char *message); int netconf_invalid_value(cbuf *cb, char *type, char *message);
int netconf_invalid_value_xml(cxobj **xret, char *type, char *message); int netconf_invalid_value_xml(cxobj **xret, char *type, char *message);

View file

@ -79,5 +79,8 @@ int yang_xml_mandatory(cxobj *xt, yang_stmt *ys);
int xml_rpc_isaction(cxobj *xn); int xml_rpc_isaction(cxobj *xn);
int xml_find_action(cxobj *xn, int top, cxobj **xap); int xml_find_action(cxobj *xn, int top, cxobj **xap);
int purge_tagged_nodes(cxobj *xn, char *ns, char *name, char *value, int keepnode); int purge_tagged_nodes(cxobj *xn, char *ns, char *name, char *value, int keepnode);
int xml_add_default_tag(cxobj *x, uint16_t flags);
int xml_flag_state_default_value(cxobj *x, uint16_t flag);
int xml_flag_default_value(cxobj *x, uint16_t flag);
#endif /* _CLIXON_XML_MAP_H_ */ #endif /* _CLIXON_XML_MAP_H_ */

View file

@ -75,6 +75,7 @@
#include "clixon_plugin.h" #include "clixon_plugin.h"
#include "clixon_options.h" #include "clixon_options.h"
#include "clixon_data.h" #include "clixon_data.h"
#include "clixon_netconf_lib.h"
#include "clixon_datastore.h" #include "clixon_datastore.h"
#include "clixon_datastore_write.h" #include "clixon_datastore_write.h"
#include "clixon_datastore_read.h" #include "clixon_datastore_read.h"

View file

@ -662,6 +662,7 @@ xmldb_readfile(clicon_handle h,
* @param[in] yb How to bind yang to XML top-level when parsing * @param[in] yb How to bind yang to XML top-level when parsing
* @param[in] nsc External XML namespace context, or NULL * @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH syntax. or NULL for all * @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in] wdef With-defaults parameter, see RFC 6243
* @param[out] xret Single return XML tree. Free with xml_free() * @param[out] xret Single return XML tree. Free with xml_free()
* @param[out] msdiff If set, return modules-state differences * @param[out] msdiff If set, return modules-state differences
* @param[out] xerr XML error if retval is 0 * @param[out] xerr XML error if retval is 0
@ -677,6 +678,7 @@ xmldb_get_nocache(clicon_handle h,
yang_bind yb, yang_bind yb,
cvec *nsc, cvec *nsc,
const char *xpath, const char *xpath,
withdefaults_type wdef,
cxobj **xtop, cxobj **xtop,
modstate_diff_t *msdiff, modstate_diff_t *msdiff,
cxobj **xerr) cxobj **xerr)
@ -734,6 +736,54 @@ xmldb_get_nocache(clicon_handle h,
if (xml_default_recurse(xt, 0) < 0) if (xml_default_recurse(xt, 0) < 0)
goto done; goto done;
} }
#if 1
/* Sub-optimal: first add defaults, then remove them in some cases
* Reason is code is primarily test for _cache case and I dont have time to "revert" it here
*/
switch (wdef){
case WITHDEFAULTS_REPORT_ALL:
break;
case WITHDEFAULTS_TRIM:
/* Mark and remove nodes having schema default values */
if (xml_apply(xt, CX_ELMNT, (xml_applyfn_t*) xml_flag_default_value, (void*) XML_FLAG_MARK) < 0)
goto done;
if (xml_tree_prune_flags(xt, XML_FLAG_MARK, XML_FLAG_MARK)
< 0)
goto done;
if (xml_defaults_nopresence(xt, 1) < 0)
goto done;
break;
case WITHDEFAULTS_EXPLICIT:
if (xml_defaults_nopresence(xt, 2) < 0)
goto done;
break;
case WITHDEFAULTS_REPORT_ALL_TAGGED:{
cxobj *x;
char *ns;
x = NULL;
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL){
ns = NULL;
if (xml2ns(x, IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX, &ns) < 0)
goto done;
if (ns == NULL){
if (xmlns_set(x, IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX, IETF_NETCONF_WITH_DEFAULTS_ATTR_NAMESPACE) < 0)
goto done;
}
else if (strcmp(ns, IETF_NETCONF_WITH_DEFAULTS_ATTR_NAMESPACE) != 0){
/* XXX: Assume if namespace is set that it is withdefaults otherwise just ignore? */
continue;
}
}
/* Mark nodes having default schema values */
if (xml_apply(xt, CX_ELMNT, (xml_applyfn_t*) xml_flag_default_value, (void*) XML_FLAG_MARK) < 0)
goto done;
/* Add tag attributes to default nodes */
if (xml_apply(xt, CX_ELMNT, (xml_applyfn_t*) xml_add_default_tag, (void*) (XML_FLAG_DEFAULT | XML_FLAG_MARK)) < 0)
goto done;
break;
}
} /* switch wdef */
#endif
/* If empty NACM config, then disable NACM if loaded /* If empty NACM config, then disable NACM if loaded
*/ */
if (clicon_option_bool(h, "CLICON_NACM_DISABLED_ON_EMPTY")){ if (clicon_option_bool(h, "CLICON_NACM_DISABLED_ON_EMPTY")){
@ -774,6 +824,7 @@ xmldb_get_nocache(clicon_handle h,
* @param[in] yb How to bind yang to XML top-level when parsing * @param[in] yb How to bind yang to XML top-level when parsing
* @param[in] nsc External XML namespace context, or NULL * @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH syntax. or NULL for all * @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in] wdef With-defaults parameter, see RFC 6243
* @param[out] xret Single return XML tree. Free with xml_free() * @param[out] xret Single return XML tree. Free with xml_free()
* @param[out] msdiff If set, return modules-state differences * @param[out] msdiff If set, return modules-state differences
* @param[out] xerr XML error if retval is 0 * @param[out] xerr XML error if retval is 0
@ -789,6 +840,7 @@ xmldb_get_cache(clicon_handle h,
yang_bind yb, yang_bind yb,
cvec *nsc, cvec *nsc,
const char *xpath, const char *xpath,
withdefaults_type wdef,
cxobj **xtop, cxobj **xtop,
modstate_diff_t *msdiff, modstate_diff_t *msdiff,
cxobj **xerr) cxobj **xerr)
@ -889,17 +941,52 @@ xmldb_get_cache(clicon_handle h,
if (xml_apply(x1t, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)(XML_FLAG_MARK|XML_FLAG_CHANGE)) < 0) if (xml_apply(x1t, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)(XML_FLAG_MARK|XML_FLAG_CHANGE)) < 0)
goto done; goto done;
} }
/* Remove global defaults and empty non-presence containers */ /* Original tree: Remove global defaults and empty non-presence containers */
if (xml_defaults_nopresence(x0t, 2) < 0) if (xml_defaults_nopresence(x0t, 2) < 0)
goto done; goto done;
if (yb != YB_NONE){ switch (wdef){
/* Add default global values */ case WITHDEFAULTS_REPORT_ALL:
if (xml_global_defaults(h, x1t, nsc, xpath, yspec, 0) < 0) break;
case WITHDEFAULTS_TRIM:
/* Mark and remove nodes having schema default values */
if (xml_apply(x1t, CX_ELMNT, (xml_applyfn_t*) xml_flag_default_value, (void*) XML_FLAG_MARK) < 0)
goto done; goto done;
/* Add default recursive values */ if (xml_tree_prune_flags(x1t, XML_FLAG_MARK, XML_FLAG_MARK)
if (xml_default_recurse(x1t, 0) < 0) < 0)
goto done; goto done;
if (xml_defaults_nopresence(x1t, 1) < 0)
goto done;
break;
case WITHDEFAULTS_EXPLICIT:
if (xml_defaults_nopresence(x1t, 2) < 0)
goto done;
break;
case WITHDEFAULTS_REPORT_ALL_TAGGED:{
cxobj *x;
char *ns;
x = NULL;
while ((x = xml_child_each(x1t, x, CX_ELMNT)) != NULL){
ns = NULL;
if (xml2ns(x, IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX, &ns) < 0)
goto done;
if (ns == NULL){
if (xmlns_set(x, IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX, IETF_NETCONF_WITH_DEFAULTS_ATTR_NAMESPACE) < 0)
goto done;
}
else if (strcmp(ns, IETF_NETCONF_WITH_DEFAULTS_ATTR_NAMESPACE) != 0){
/* XXX: Assume if namespace is set that it is withdefaults otherwise just ignore? */
continue;
}
}
/* Mark nodes having default schema values */
if (xml_apply(x1t, CX_ELMNT, (xml_applyfn_t*) xml_flag_default_value, (void*) XML_FLAG_MARK) < 0)
goto done;
/* Add tag attributes to default nodes */
if (xml_apply(x1t, CX_ELMNT, (xml_applyfn_t*) xml_add_default_tag, (void*) (XML_FLAG_DEFAULT | XML_FLAG_MARK)) < 0)
goto done;
break;
} }
} /* switch wdef */
/* If empty NACM config, then disable NACM if loaded /* If empty NACM config, then disable NACM if loaded
*/ */
if (clicon_option_bool(h, "CLICON_NACM_DISABLED_ON_EMPTY")){ if (clicon_option_bool(h, "CLICON_NACM_DISABLED_ON_EMPTY")){
@ -932,7 +1019,7 @@ xmldb_get_cache(clicon_handle h,
* @param[in] yb How to bind yang to XML top-level when parsing * @param[in] yb How to bind yang to XML top-level when parsing
* @param[in] nsc External XML namespace context, or NULL * @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH syntax. or NULL for all * @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in] config If set only configuration data, else also state * @param[in] wdef With-defaults parameter, see RFC 6243
* @param[out] xret Single return XML tree. Free with xml_free() * @param[out] xret Single return XML tree. Free with xml_free()
* @param[out] msdiff If set, return modules-state differences * @param[out] msdiff If set, return modules-state differences
* @param[out] xerr XML error if retval is 0 * @param[out] xerr XML error if retval is 0
@ -947,6 +1034,7 @@ xmldb_get_zerocopy(clicon_handle h,
yang_bind yb, yang_bind yb,
cvec *nsc, cvec *nsc,
const char *xpath, const char *xpath,
withdefaults_type wdef,
cxobj **xtop, cxobj **xtop,
modstate_diff_t *msdiff, modstate_diff_t *msdiff,
cxobj **xerr) cxobj **xerr)
@ -1005,6 +1093,54 @@ xmldb_get_zerocopy(clicon_handle h,
if (xml_default_recurse(x0t, 0) < 0) if (xml_default_recurse(x0t, 0) < 0)
goto done; goto done;
} }
#if 1
/* Sub-optimal: first add defaults, then remove them in some cases
* Reason is code is primarily test for _cache case and I dont have time to "revert" it here
*/
switch (wdef){
case WITHDEFAULTS_REPORT_ALL:
break;
case WITHDEFAULTS_TRIM:
/* Mark and remove nodes having schema default values */
if (xml_apply(x0t, CX_ELMNT, (xml_applyfn_t*) xml_flag_default_value, (void*) XML_FLAG_MARK) < 0)
goto done;
if (xml_tree_prune_flags(x0t, XML_FLAG_MARK, XML_FLAG_MARK)
< 0)
goto done;
if (xml_defaults_nopresence(x0t, 1) < 0)
goto done;
break;
case WITHDEFAULTS_EXPLICIT:
if (xml_defaults_nopresence(x0t, 2) < 0)
goto done;
break;
case WITHDEFAULTS_REPORT_ALL_TAGGED:{
cxobj *x;
char *ns;
x = NULL;
while ((x = xml_child_each(x0t, x, CX_ELMNT)) != NULL){
ns = NULL;
if (xml2ns(x, IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX, &ns) < 0)
goto done;
if (ns == NULL){
if (xmlns_set(x, IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX, IETF_NETCONF_WITH_DEFAULTS_ATTR_NAMESPACE) < 0)
goto done;
}
else if (strcmp(ns, IETF_NETCONF_WITH_DEFAULTS_ATTR_NAMESPACE) != 0){
/* XXX: Assume if namespace is set that it is withdefaults otherwise just ignore? */
continue;
}
}
/* Mark nodes having default schema values */
if (xml_apply(x0t, CX_ELMNT, (xml_applyfn_t*) xml_flag_default_value, (void*) XML_FLAG_MARK) < 0)
goto done;
/* Add tag attributes to default nodes */
if (xml_apply(x0t, CX_ELMNT, (xml_applyfn_t*) xml_add_default_tag, (void*) (XML_FLAG_DEFAULT | XML_FLAG_MARK)) < 0)
goto done;
break;
}
} /* switch wdef */
#endif
/* If empty NACM config, then disable NACM if loaded /* If empty NACM config, then disable NACM if loaded
*/ */
if (clicon_option_bool(h, "CLICON_NACM_DISABLED_ON_EMPTY")){ if (clicon_option_bool(h, "CLICON_NACM_DISABLED_ON_EMPTY")){
@ -1050,7 +1186,7 @@ xmldb_get(clicon_handle h,
char *xpath, char *xpath,
cxobj **xret) cxobj **xret)
{ {
return xmldb_get0(h, db, YB_MODULE, nsc, xpath, 1, xret, NULL, NULL); return xmldb_get0(h, db, YB_MODULE, nsc, xpath, 1, 0, xret, NULL, NULL);
} }
/*! Zero-copy variant of get content of database /*! Zero-copy variant of get content of database
@ -1067,6 +1203,7 @@ xmldb_get(clicon_handle h,
* @param[in] nsc External XML namespace context, or NULL * @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH syntax. or NULL for all * @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in] copy Force copy. Overrides cache_zerocopy -> cache * @param[in] copy Force copy. Overrides cache_zerocopy -> cache
* @param[in] wdef With-defaults parameter, see RFC 6243
* @param[out] xret Single return XML tree. Free with xml_free() * @param[out] xret Single return XML tree. Free with xml_free()
* @param[out] msdiff If set, return modules-state differences (upgrade code) * @param[out] msdiff If set, return modules-state differences (upgrade code)
* @param[out] xerr XML error if retval is 0 * @param[out] xerr XML error if retval is 0
@ -1077,7 +1214,7 @@ xmldb_get(clicon_handle h,
* @code * @code
* cxobj *xt; * cxobj *xt;
* cxobj *xerr = NULL; * cxobj *xerr = NULL;
* if (xmldb_get0(h, "running", YB_MODULE, nsc, "/interface[name="eth"]", 0, &xt, NULL, &xerr) < 0) * if (xmldb_get0(h, "running", YB_MODULE, nsc, "/interface[name="eth"]", 0, 0, &xt, NULL, &xerr) < 0)
* err; * err;
* if (ret == 0){ # Not if YB_NONE * if (ret == 0){ # Not if YB_NONE
* # Error handling * # Error handling
@ -1098,7 +1235,7 @@ xmldb_get(clicon_handle h,
* And a db content: * And a db content:
* <c><x>1</x></c> * <c><x>1</x></c>
* With the following call: * With the following call:
* xmldb_get0(h, "running", NULL, NULL, "/c[x=0]", 1, &xt, NULL, NULL) * xmldb_get0(h, "running", NULL, NULL, "/c[x=0]", 1, 0, &xt, NULL, NULL)
* which result in a miss (there is no c with x=0), but when the returned xt is printed * which result in a miss (there is no c with x=0), but when the returned xt is printed
* (the existing tree is discarded), the default (empty) xml tree is: * (the existing tree is discarded), the default (empty) xml tree is:
* <c><x>0</x></c> * <c><x>0</x></c>
@ -1110,6 +1247,7 @@ xmldb_get0(clicon_handle h,
cvec *nsc, cvec *nsc,
const char *xpath, const char *xpath,
int copy, int copy,
withdefaults_type wdef,
cxobj **xret, cxobj **xret,
modstate_diff_t *msdiff, modstate_diff_t *msdiff,
cxobj **xerr) cxobj **xerr)
@ -1122,7 +1260,7 @@ xmldb_get0(clicon_handle h,
* Add default values in copy * Add default values in copy
* Copy deleted by xmldb_free * Copy deleted by xmldb_free
*/ */
retval = xmldb_get_nocache(h, db, yb, nsc, xpath, xret, msdiff, xerr); retval = xmldb_get_nocache(h, db, yb, nsc, xpath, wdef, xret, msdiff, xerr);
break; break;
case DATASTORE_CACHE_ZEROCOPY: case DATASTORE_CACHE_ZEROCOPY:
/* Get cache (file if empty) mark xpath match in original tree /* Get cache (file if empty) mark xpath match in original tree
@ -1130,7 +1268,7 @@ xmldb_get0(clicon_handle h,
* Default values and markings removed in xmldb_clear * Default values and markings removed in xmldb_clear
*/ */
if (!copy){ if (!copy){
retval = xmldb_get_zerocopy(h, db, yb, nsc, xpath, xret, msdiff, xerr); retval = xmldb_get_zerocopy(h, db, yb, nsc, xpath, wdef, xret, msdiff, xerr);
break; break;
} }
/* fall through */ /* fall through */
@ -1139,7 +1277,7 @@ xmldb_get0(clicon_handle h,
* Add default values in copy, return copy * Add default values in copy, return copy
* Copy deleted by xmldb_free * Copy deleted by xmldb_free
*/ */
retval = xmldb_get_cache(h, db, yb, nsc, xpath, xret, msdiff, xerr); retval = xmldb_get_cache(h, db, yb, nsc, xpath, wdef, xret, msdiff, xerr);
break; break;
} }
return retval; return retval;

View file

@ -1216,7 +1216,7 @@ nacm_access_pre(clicon_handle h,
goto done; goto done;
} }
else if (strcmp(mode, "internal")==0){ else if (strcmp(mode, "internal")==0){
if (xmldb_get0(h, "running", YB_MODULE, nsc, "nacm", 1, &xnacm0, NULL, NULL) < 0) if (xmldb_get0(h, "running", YB_MODULE, nsc, "nacm", 1, 0, &xnacm0, NULL, NULL) < 0)
goto done; goto done;
} }
else{ else{

View file

@ -77,6 +77,35 @@
#include "clixon_netconf_lib.h" #include "clixon_netconf_lib.h"
/* Mapping between RFC6243 withdefaults strings <--> ints
*/
static const map_str2int wdmap[] = {
{"report-all", WITHDEFAULTS_REPORT_ALL},
{"trim", WITHDEFAULTS_TRIM},
{"explicit", WITHDEFAULTS_EXPLICIT},
{"report-all-tagged", WITHDEFAULTS_REPORT_ALL_TAGGED}
};
/*! Map from with-defaults ints to strings
* @param[in] int Integer representation of withdefaults values
* @retval str String representation of withdefaults values
*/
char *
withdefaults_int2str(int keyword)
{
return (char*)clicon_int2str(wdmap, keyword);
}
/*! Map from with-defaults strings to ints
* @param[in] str String representation of withdefaults values
* @retval int Integer representation of withdefaults values
*/
int
withdefaults_str2int(char *str)
{
return clicon_str2int(wdmap, str);
}
/*! Create Netconf in-use error XML tree according to RFC 6241 Appendix A /*! Create Netconf in-use error XML tree according to RFC 6241 Appendix A
* *
* The request requires a resource that already is in use. * The request requires a resource that already is in use.

View file

@ -1725,7 +1725,7 @@ xml_find_type_value(cxobj *xt,
* @code * @code
* cxobj *x = xml_find_type(x, "prefix", "name", CX_ATTR); * cxobj *x = xml_find_type(x, "prefix", "name", CX_ATTR);
* @endcode * @endcode
* @see xml_find which finds any child given name * @see xml_find which finds any child given name (and no prefix)
* @see xml_find_value where a body can be found as well * @see xml_find_value where a body can be found as well
*/ */
cxobj * cxobj *

View file

@ -781,12 +781,14 @@ xml_default_create(yang_stmt *y,
/*! Try to see if intermediate nodes are necessary for default values, create if so /*! Try to see if intermediate nodes are necessary for default values, create if so
* *
* @param[in] yt Yang container (no-presence) * @param[in] yt Yang container (no-presence)
* @param[in] state Set if global state, otherwise config
* @param[out] createp Need to create XML container * @param[out] createp Need to create XML container
* @retval 0 OK * @retval 0 OK
* @retval -1 Error * @retval -1 Error
*/ */
static int static int
xml_nopresence_try(yang_stmt *yt, xml_nopresence_try(yang_stmt *yt,
int state,
int *createp) int *createp)
{ {
int retval = -1; int retval = -1;
@ -801,9 +803,14 @@ xml_nopresence_try(yang_stmt *yt,
while ((y = yn_each(yt, y)) != NULL) { while ((y = yn_each(yt, y)) != NULL) {
switch (yang_keyword_get(y)){ switch (yang_keyword_get(y)){
case Y_LEAF: case Y_LEAF:
if (!cv_flag(yang_cv_get(y), V_UNSET)){ /* Default value exists */ /* Default value exists */
/* Need to create container */ if (!cv_flag(yang_cv_get(y), V_UNSET)){
*createp = 1; /* Want to add state defaults, but this is config */
if (state && yang_config_ancestor(y))
;
else
/* Need to create container */
*createp = 1;
goto ok; goto ok;
} }
break; break;
@ -812,7 +819,7 @@ xml_nopresence_try(yang_stmt *yt,
/* If this is non-presence, (and it does not exist in xt) call recursively /* If this is non-presence, (and it does not exist in xt) call recursively
* and create nodes if any default value exist first. Then continue and populate? * and create nodes if any default value exist first. Then continue and populate?
*/ */
if (xml_nopresence_try(y, createp) < 0) if (xml_nopresence_try(y, state, createp) < 0)
goto done; goto done;
if (*createp) if (*createp)
goto ok; goto ok;
@ -837,6 +844,8 @@ xml_nopresence_try(yang_stmt *yt,
* @param[in] state Set if global state, otherwise config * @param[in] state Set if global state, otherwise config
* @retval 0 OK * @retval 0 OK
* @retval -1 Error * @retval -1 Error
* XXX If state, should not add config defaults
* if (state && yang_config(yc))
*/ */
static int static int
xml_default1(yang_stmt *yt, xml_default1(yang_stmt *yt,
@ -867,10 +876,14 @@ xml_default1(yang_stmt *yt,
case Y_OUTPUT: case Y_OUTPUT:
yc = NULL; yc = NULL;
while ((yc = yn_each(yt, yc)) != NULL) { while ((yc = yn_each(yt, yc)) != NULL) {
/* If config parameter and local is config false */
if (!state && !yang_config(yc)) if (!state && !yang_config(yc))
continue; continue;
switch (yang_keyword_get(yc)){ switch (yang_keyword_get(yc)){
case Y_LEAF: case Y_LEAF:
/* Want to add state defaults, but this is config */
if (state && yang_config_ancestor(yc))
break;
if ((cv = yang_cv_get(yc)) == NULL){ if ((cv = yang_cv_get(yc)) == NULL){
clicon_err(OE_YANG,0, "Internal error: yang leaf %s not populated with cv as it should", clicon_err(OE_YANG,0, "Internal error: yang leaf %s not populated with cv as it should",
yang_argument_get(yc)); yang_argument_get(yc));
@ -903,7 +916,7 @@ xml_default1(yang_stmt *yt,
*/ */
if (xml_find_type(xt, NULL, yang_argument_get(yc), CX_ELMNT) == NULL){ if (xml_find_type(xt, NULL, yang_argument_get(yc), CX_ELMNT) == NULL){
/* No such container exist, recursively try if needed */ /* No such container exist, recursively try if needed */
if (xml_nopresence_try(yc, &create) < 0) if (xml_nopresence_try(yc, state, &create) < 0)
goto done; goto done;
if (create){ if (create){
/* Retval shows there is a default value need to create the /* Retval shows there is a default value need to create the
@ -2342,3 +2355,108 @@ purge_tagged_nodes(cxobj *xn,
done: done:
return retval; return retval;
} }
/*! Add default attribute to node with default value.
*
* Used in with-default code for report-all-tagged
* @param[in] x XML node
* @param[in] flags Flags indicatiing default nodes
* @retval 0 OK
* @retval -1 Error
*/
int
xml_add_default_tag(cxobj *x,
uint16_t flags)
{
int retval = -1;
cxobj *xattr;
if (xml_flag(x, flags)) {
/* set default attribute */
if ((xattr = xml_new("default", x, CX_ATTR)) == NULL)
goto done;
if (xml_value_set(xattr, "true") < 0)
goto done;
if (xml_prefix_set(xattr, IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
/*! Set flag on node having schema default value. (non-config)
*
* Used in with-default code for trim/report-all-tagged
* @param[in] x XML node
* @param[in] flag Flag to be used
* @retval 0 OK
* @see xml_flag_default_value for config default value
*/
int
xml_flag_state_default_value(cxobj *x,
uint16_t flag)
{
yang_stmt *y;
cg_var *cv;
char *yv;
char *xv;
xml_flag_reset(x, flag); /* Assume not default value */
if ((xv = xml_body(x)) == NULL)
goto done;
if ((y = xml_spec(x)) == NULL)
goto done;
if (yang_config_ancestor(y) == 1)
goto done;
if ((cv = yang_cv_get(y)) == NULL)
goto done;
if ((cv = yang_cv_get(y)) == NULL)
goto done;
if (cv_name_get(cv) == NULL)
goto done;
if ((yv = cv2str_dup(cv)) == NULL)
goto done;
if (strcmp(xv, yv) == 0)
xml_flag_set(x, flag); /* Actual value same as default value */
free(yv);
done:
return 0;
}
/*! Set flag on node having schema default value. (config)
*
* Used in with-default code for trim and report-all-tagged
* @param[in] x XML node
* @param[in] flag Flag to be used
* @retval 0 OK
* @see xml_flag_state_default_value for non-config default value
*/
int
xml_flag_default_value(cxobj *x,
uint16_t flag)
{
yang_stmt *y;
cg_var *cv;
char *yv;
char *xv;
xml_flag_reset(x, flag); /* Assume not default value */
if ((xv = xml_body(x)) == NULL)
goto done;
if ((y = xml_spec(x)) == NULL)
goto done;
if ((cv = yang_cv_get(y)) == NULL)
goto done;
if ((cv = yang_cv_get(y)) == NULL)
goto done;
if (cv_name_get(cv) == NULL)
goto done;
if ((yv = cv2str_dup(cv)) == NULL)
goto done;
if (strcmp(xv, yv) == 0)
xml_flag_set(x, flag); /* Actual value same as default value */
free(yv);
done:
return 0;
}

View file

@ -1501,7 +1501,7 @@ xml_find_index_yang(cxobj *xp,
* if (clixon_xml_find_index(xp, yp, NULL, "a", ns, cvk, xv) < 0) * if (clixon_xml_find_index(xp, yp, NULL, "a", ns, cvk, xv) < 0)
* err; * err;
* for (i=0; i<clixon_xvec_len(xv); i++){ * for (i=0; i<clixon_xvec_len(xv); i++){
* x = clixon_xpath_i(xv, i); * x = clixon_xvec_i(xv, i);
* ... * ...
* } * }
* clixon_xvec_free(xvec); * clixon_xvec_free(xvec);

View file

@ -1602,12 +1602,20 @@ yang_order(yang_stmt *y)
return retval; return retval;
} }
/*! Map from YANG keywords ints to strings
* @param[in] int Integer representation of YANG keywords
* @retval str String representation of YANG keywords
*/
char * char *
yang_key2str(int keyword) yang_key2str(int keyword)
{ {
return (char*)clicon_int2str(ykmap, keyword); return (char*)clicon_int2str(ykmap, keyword);
} }
/*! Map from yang keyword strings to ints
* @param[in] str String representation of YANG keywords
* @retval int Integer representation of YANG keywords
*/
int int
yang_str2key(char *str) yang_str2key(char *str)
{ {

View file

@ -485,7 +485,6 @@ expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" \
<interface><name>eth1</name><mtu wd:default=\"true\">1500</mtu></interface>\ <interface><name>eth1</name><mtu wd:default=\"true\">1500</mtu></interface>\
<interface><name>eth2</name><mtu>9000</mtu></interface>\ <interface><name>eth2</name><mtu>9000</mtu></interface>\
<interface><name>eth3</name><mtu wd:default=\"true\">1500</mtu></interface>\ <interface><name>eth3</name><mtu wd:default=\"true\">1500</mtu></interface>\
<cedv><edv wd:default=\"true\">edv</edv></cedv><cdv><dv wd:default=\"true\">dv</dv></cdv>\
</interfaces></data></rpc-reply>" </interfaces></data></rpc-reply>"
new "rfc8040 4.3. RESTCONF GET json" new "rfc8040 4.3. RESTCONF GET json"