* Strict namespace setting can be a problem when upgrading existing database files, such as startup-db or persistent running-db, or any other saved XML file.
* For backward compatibility, load of startup and running set CLICON_XML_NS_STRICT to false temporarily. * Added three-valued return values for several validate functions where -1 is fatal error, 0 is validation failed and 1 is validation OK. * This includes: `xmldb_put`, `xml_yang_validate_all`, `xml_yang_validate_add`, `xml_yang_validate_rpc`, `api_path2xml`, `api_path2xpath` * Added new xml functions for specific types: `xml_child_nr_notype`, `xml_child_nr_notype`, `xml_child_i_type`, `xml_find_type`.
This commit is contained in:
parent
861300d6c0
commit
0baebc93fd
71 changed files with 2679 additions and 1573 deletions
|
|
@ -292,7 +292,7 @@ client_get_streams(clicon_handle h,
|
|||
* @param[in,out] xret Existing XML tree, merge x into this
|
||||
* @retval -1 Error (fatal)
|
||||
* @retval 0 OK
|
||||
* @retval 1 Statedata callback failed
|
||||
* @retval 1 Statedata callback failed (clicon_err called)
|
||||
*/
|
||||
static int
|
||||
client_statedata(clicon_handle h,
|
||||
|
|
@ -309,15 +309,15 @@ client_statedata(clicon_handle h,
|
|||
clicon_err(OE_YANG, ENOENT, "No yang spec");
|
||||
goto done;
|
||||
}
|
||||
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") &&
|
||||
(retval = client_get_streams(h, yspec, xpath, "ietf-netconf-notification", "netconf", xret)) != 0)
|
||||
goto done;
|
||||
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
|
||||
(retval = client_get_streams(h, yspec, xpath, "ietf-restconf-monitoring", "restconf-state", xret)) != 0)
|
||||
goto done;
|
||||
if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895") &&
|
||||
(retval = yang_modules_state_get(h, yspec, xret)) != 0)
|
||||
goto done;
|
||||
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277"))
|
||||
if ((retval = client_get_streams(h, yspec, xpath, "ietf-netconf-notification", "netconf", xret)) != 0)
|
||||
goto done;
|
||||
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040"))
|
||||
if ((retval = client_get_streams(h, yspec, xpath, "ietf-restconf-monitoring", "restconf-state", xret)) != 0)
|
||||
goto done;
|
||||
if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895"))
|
||||
if ((retval = yang_modules_state_get(h, yspec, xret)) != 0)
|
||||
goto done;
|
||||
if ((retval = clixon_plugin_statedata(h, yspec, xpath, xret)) != 0)
|
||||
goto done;
|
||||
/* Code complex to filter out anything that is outside of xpath */
|
||||
|
|
@ -339,7 +339,7 @@ client_statedata(clicon_handle h,
|
|||
/* reset flag */
|
||||
if (xml_apply(*xret, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
retval = 0; /* OK */
|
||||
done:
|
||||
if (xvec)
|
||||
free(xvec);
|
||||
|
|
@ -363,7 +363,6 @@ from_client_get(clicon_handle h,
|
|||
char *xpath = "/";
|
||||
cxobj *xret = NULL;
|
||||
int ret;
|
||||
cbuf *cbx = NULL; /* Assist cbuf */
|
||||
|
||||
if ((xfilter = xml_find(xe, "filter")) != NULL)
|
||||
if ((xpath = xml_find_value(xfilter, "select"))==NULL)
|
||||
|
|
@ -379,33 +378,24 @@ from_client_get(clicon_handle h,
|
|||
clicon_err_reset();
|
||||
if ((ret = client_statedata(h, xpath, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* OK */
|
||||
cprintf(cbret, "<rpc-reply>");
|
||||
if (xret==NULL)
|
||||
cprintf(cbret, "<data/>");
|
||||
else{
|
||||
if (xml_name_set(xret, "data") < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
goto done;
|
||||
}
|
||||
cprintf(cbret, "</rpc-reply>");
|
||||
}
|
||||
else { /* 1 Error from callback */
|
||||
if ((cbx = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
if (ret == 1){ /* Error from callback (error in xret) */
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
goto done;
|
||||
}
|
||||
cprintf(cbx, "Internal error:%s", clicon_err_reason);
|
||||
if (netconf_operation_failed(cbret, "rpc", cbuf_get(cbx))< 0)
|
||||
goto done;
|
||||
clicon_log(LOG_NOTICE, "%s Error in backend_statedata_call:%s", __FUNCTION__, xml_name(xe));
|
||||
goto ok;
|
||||
}
|
||||
cprintf(cbret, "<rpc-reply>"); /* OK */
|
||||
if (xret==NULL)
|
||||
cprintf(cbret, "<data/>");
|
||||
else{
|
||||
if (xml_name_set(xret, "data") < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
goto done;
|
||||
}
|
||||
cprintf(cbret, "</rpc-reply>");
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (cbx)
|
||||
cbuf_free(cbx);
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
return retval;
|
||||
|
|
@ -433,6 +423,7 @@ from_client_edit_config(clicon_handle h,
|
|||
int non_config = 0;
|
||||
yang_spec *yspec;
|
||||
cbuf *cbx = NULL; /* Assist cbuf */
|
||||
int ret;
|
||||
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_YANG, ENOENT, "No yang spec9");
|
||||
|
|
@ -491,24 +482,27 @@ from_client_edit_config(clicon_handle h,
|
|||
/* Cant do this earlier since we dont have a yang spec to
|
||||
* the upper part of the tree, until we get the "config" tree.
|
||||
*/
|
||||
if (xml_child_sort && xml_apply0(xc, CX_ELMNT, xml_sort, NULL) < 0)
|
||||
if (clicon_xml_sort(h) && xml_apply0(xc, CX_ELMNT, xml_sort, NULL) < 0)
|
||||
goto done;
|
||||
if (xmldb_put(h, target, operation, xc, cbret) < 0){
|
||||
if ((ret = xmldb_put(h, target, operation, xc, cbret)) < 0){
|
||||
clicon_debug(1, "%s ERROR PUT", __FUNCTION__);
|
||||
if (netconf_operation_failed(cbret, "protocol", clicon_err_reason)< 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if (ret == 0)
|
||||
goto ok;
|
||||
}
|
||||
assert(cbuf_len(cbret) == 0);
|
||||
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
||||
ok:
|
||||
if (!cbuf_len(cbret))
|
||||
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
||||
retval = 0;
|
||||
done:
|
||||
if (cbx)
|
||||
cbuf_free(cbx);
|
||||
clicon_debug(1, "%s done cbret:%s", __FUNCTION__, cbuf_get(cbret));
|
||||
return retval;
|
||||
|
||||
} /* from_client_edit_config */
|
||||
|
||||
/*! Internal message: Lock database
|
||||
|
|
|
|||
|
|
@ -165,12 +165,24 @@ validate_common(clicon_handle h,
|
|||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
}
|
||||
/* 2. Parse xml trees */
|
||||
/* 2. Parse xml trees
|
||||
* This is the state we are going from */
|
||||
if (xmldb_get(h, "running", "/", 1, &td->td_src) < 0)
|
||||
goto done;
|
||||
/* This is the state we are going to */
|
||||
if (xmldb_get(h, candidate, "/", 1, &td->td_target) < 0)
|
||||
goto done;
|
||||
|
||||
/* Validate the target state. It is not completely clear this should be done
|
||||
* here. It is being made in generic_validate below.
|
||||
* But xml_diff requires some basic validation, at least check that yang-specs
|
||||
* have been assigned
|
||||
*/
|
||||
if ((ret = xml_yang_validate_all_top(td->td_target, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
|
||||
/* 3. Compute differences */
|
||||
if (xml_diff(yspec,
|
||||
td->td_src,
|
||||
|
|
@ -240,7 +252,7 @@ validate_common(clicon_handle h,
|
|||
* do something more drastic?
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] candidate A candidate database, not necessarily "candidate"
|
||||
* @retval -1 Error - or validation failed (but cbret not set)
|
||||
* @retval -1 Error - or validation failed
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
* @note Need to differentiate between error and validation fail
|
||||
|
|
@ -259,7 +271,9 @@ candidate_commit(clicon_handle h,
|
|||
if ((td = transaction_new()) == NULL)
|
||||
goto done;
|
||||
|
||||
/* Common steps (with validate). Note this is only call that uses 3-values */
|
||||
/* Common steps (with validate). Load candidate and running and compute diffs
|
||||
* Note this is only call that uses 3-values
|
||||
*/
|
||||
if ((ret = validate_common(h, candidate, td, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
|
|
@ -270,12 +284,14 @@ candidate_commit(clicon_handle h,
|
|||
goto done;
|
||||
|
||||
/* Optionally write (potentially modified) tree back to candidate */
|
||||
if (clicon_option_bool(h, "CLICON_TRANSACTION_MOD"))
|
||||
if (xmldb_put(h, candidate, OP_REPLACE, td->td_target, NULL) < 0)
|
||||
if (clicon_option_bool(h, "CLICON_TRANSACTION_MOD")){
|
||||
if ((ret = xmldb_put(h, candidate, OP_REPLACE, td->td_target, NULL)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
}
|
||||
/* 8. Success: Copy candidate to running
|
||||
*/
|
||||
|
||||
if (xmldb_copy(h, candidate, "running") < 0)
|
||||
goto done;
|
||||
|
||||
|
|
@ -423,9 +439,11 @@ from_client_validate(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
/* Optionally write (potentially modified) tree back to candidate */
|
||||
if (clicon_option_bool(h, "CLICON_TRANSACTION_MOD"))
|
||||
if (xmldb_put(h, "candidate", OP_REPLACE, td->td_target, NULL) < 0)
|
||||
goto done;
|
||||
if (clicon_option_bool(h, "CLICON_TRANSACTION_MOD")){
|
||||
if ((ret = xmldb_put(h, "candidate", OP_REPLACE, td->td_target, cbret)) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
||||
ok:
|
||||
retval = 0;
|
||||
|
|
|
|||
|
|
@ -176,22 +176,24 @@ db_reset(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Merge db1 into db2 without commit
|
||||
* @retval -1 Error
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
*/
|
||||
static int
|
||||
db_merge(clicon_handle h,
|
||||
const char *db1,
|
||||
const char *db2)
|
||||
const char *db2,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xt = NULL;
|
||||
|
||||
int retval = -1;
|
||||
cxobj *xt = NULL;
|
||||
|
||||
/* Get data as xml from db1 */
|
||||
if (xmldb_get(h, (char*)db1, NULL, 1, &xt) < 0)
|
||||
goto done;
|
||||
/* Merge xml into db2. Without commit */
|
||||
if (xmldb_put(h, (char*)db2, OP_MERGE, xt, NULL) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
retval = xmldb_put(h, (char*)db2, OP_MERGE, xt, cbret);
|
||||
done:
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
|
|
@ -288,18 +290,22 @@ nacm_load_external(clicon_handle h)
|
|||
}
|
||||
|
||||
/*! Merge xml in filename into database
|
||||
* @retval -1 Error
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
*/
|
||||
static int
|
||||
load_extraxml(clicon_handle h,
|
||||
char *filename,
|
||||
const char *db)
|
||||
const char *db,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xt = NULL;
|
||||
int fd = -1;
|
||||
|
||||
|
||||
if (filename == NULL)
|
||||
return 0;
|
||||
return 1;
|
||||
if ((fd = open(filename, O_RDONLY)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "open(%s)", filename);
|
||||
goto done;
|
||||
|
|
@ -310,9 +316,7 @@ load_extraxml(clicon_handle h,
|
|||
if (xml_rootchild(xt, 0, &xt) < 0)
|
||||
goto done;
|
||||
/* Merge user reset state */
|
||||
if (xmldb_put(h, (char*)db, OP_MERGE, xt, NULL) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
retval = xmldb_put(h, (char*)db, OP_MERGE, xt, cbret);
|
||||
done:
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
|
|
@ -385,9 +389,13 @@ static int
|
|||
startup_mode_running(clicon_handle h,
|
||||
char *extraxml_file)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cbret = NULL;
|
||||
int retval = -1;
|
||||
cbuf *cbret = NULL;
|
||||
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
/* Stash original running to candidate for later commit */
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
|
|
@ -400,41 +408,46 @@ startup_mode_running(clicon_handle h,
|
|||
/* Application may define extra xml in its reset function*/
|
||||
if (clixon_plugin_reset(h, "tmp") < 0)
|
||||
goto done;
|
||||
/* XXX Kludge to low-level functions to search for xml in all yang modules */
|
||||
_CLICON_XML_NS_STRICT = 0;
|
||||
/* Get application extra xml from file */
|
||||
if (load_extraxml(h, extraxml_file, "tmp") < 0)
|
||||
goto done;
|
||||
if (load_extraxml(h, extraxml_file, "tmp", cbret) < 1)
|
||||
goto fail;
|
||||
/* Clear running db */
|
||||
if (db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
/* Commit original running. Assume -1 is validate fail */
|
||||
if (candidate_commit(h, "candidate", cbret) < 1){
|
||||
/* (1) We cannot differentiate between fatal errors and validation
|
||||
* failures
|
||||
* (2) If fatal error, we should exit
|
||||
* (3) If validation fails we cannot continue. How could we?
|
||||
* (4) Need to restore the running db since we destroyed it above
|
||||
*/
|
||||
clicon_log(LOG_NOTICE, "%s: Commit of saved running failed, exiting: %s.",
|
||||
__FUNCTION__, cbuf_get(cbret));
|
||||
/* Reinstate original */
|
||||
if (xmldb_copy(h, "candidate", "running") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
}
|
||||
if (candidate_commit(h, "candidate", cbret) < 1)
|
||||
goto fail;
|
||||
/* Merge user reset state and extra xml file (no commit) */
|
||||
if (db_merge(h, "tmp", "running") < 0)
|
||||
goto done;
|
||||
if (db_merge(h, "tmp", "running", cbret) < 1)
|
||||
goto fail;
|
||||
retval = 0;
|
||||
done:
|
||||
/* XXX Kludge to low-level functions to search for xml in all yang modules */
|
||||
_CLICON_XML_NS_STRICT = clicon_option_bool(h, "CLICON_XML_NS_STRICT");
|
||||
if (cbret)
|
||||
cbuf_free(cbret);
|
||||
if (xmldb_delete(h, "tmp") < 0)
|
||||
goto done;
|
||||
return retval;
|
||||
fail:
|
||||
/* (1) We cannot differentiate between fatal errors and validation
|
||||
* failures
|
||||
* (2) If fatal error, we should exit
|
||||
* (3) If validation fails we cannot continue. How could we?
|
||||
* (4) Need to restore the running db since we destroyed it above
|
||||
*/
|
||||
if (strlen(cbuf_get(cbret)))
|
||||
clicon_log(LOG_NOTICE, "%s: Commit of running failed, exiting: %s.",
|
||||
__FUNCTION__, cbuf_get(cbret));
|
||||
else
|
||||
clicon_log(LOG_NOTICE, "%s: Commit of running failed, exiting: %s.",
|
||||
__FUNCTION__, clicon_err_reason);
|
||||
/* Reinstate original */
|
||||
if (xmldb_copy(h, "candidate", "running") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Clixon startup startup mode: Commit startup configuration into running state
|
||||
|
|
@ -460,11 +473,16 @@ startup -------------------------+--|
|
|||
*/
|
||||
static int
|
||||
startup_mode_startup(clicon_handle h,
|
||||
char *extraxml_file)
|
||||
char *extraxml_file)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cbret = NULL;
|
||||
|
||||
/* Create return buffer for netconf xml errors */
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
/* Stash original running to backup */
|
||||
if (xmldb_copy(h, "running", "backup") < 0)
|
||||
goto done;
|
||||
|
|
@ -481,34 +499,25 @@ startup_mode_startup(clicon_handle h,
|
|||
/* Application may define extra xml in its reset function*/
|
||||
if (clixon_plugin_reset(h, "tmp") < 0)
|
||||
goto done;
|
||||
/* XXX Kludge to low-level functions to search for xml in all yang modules */
|
||||
_CLICON_XML_NS_STRICT = 0;
|
||||
/* Get application extra xml from file */
|
||||
if (load_extraxml(h, extraxml_file, "tmp") < 0)
|
||||
goto done;
|
||||
if (load_extraxml(h, extraxml_file, "tmp", cbret) < 1)
|
||||
goto fail;
|
||||
/* Clear running db */
|
||||
if (db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
/* Create return buffer (not used) */
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Commit startup */
|
||||
if (candidate_commit(h, "startup", cbret) < 1){ /* diff */
|
||||
/* We cannot differentiate between fatal errors and validation
|
||||
* failures
|
||||
* In both cases we copy back the original running and quit
|
||||
*/
|
||||
clicon_log(LOG_NOTICE, "%s: Commit of startup failed, exiting: %s.",
|
||||
__FUNCTION__, cbuf_get(cbret));
|
||||
if (xmldb_copy(h, "backup", "running") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
}
|
||||
if (candidate_commit(h, "startup", cbret) < 1) /* diff */
|
||||
goto fail;
|
||||
/* Merge user reset state and extra xml file (no commit) */
|
||||
if (db_merge(h, "tmp", "running") < 0)
|
||||
goto done;
|
||||
if (db_merge(h, "tmp", "running", cbret) < 1)
|
||||
goto fail;
|
||||
retval = 0;
|
||||
done:
|
||||
/* XXX Kludge to low-level functions to search for xml in all yang modules */
|
||||
_CLICON_XML_NS_STRICT = clicon_option_bool(h, "CLICON_XML_NS_STRICT");
|
||||
if (cbret)
|
||||
cbuf_free(cbret);
|
||||
if (xmldb_delete(h, "backup") < 0)
|
||||
|
|
@ -516,6 +525,20 @@ startup_mode_startup(clicon_handle h,
|
|||
if (xmldb_delete(h, "tmp") < 0)
|
||||
goto done;
|
||||
return retval;
|
||||
fail:
|
||||
/* We cannot differentiate between fatal errors and validation
|
||||
* failures
|
||||
* In both cases we copy back the original running and quit
|
||||
*/
|
||||
if (strlen(cbuf_get(cbret)))
|
||||
clicon_log(LOG_NOTICE, "%s: Commit of startup failed, exiting: %s.",
|
||||
__FUNCTION__, cbuf_get(cbret));
|
||||
else
|
||||
clicon_log(LOG_NOTICE, "%s: Commit of startup failed, exiting: %s.",
|
||||
__FUNCTION__, clicon_err_reason);
|
||||
if (xmldb_copy(h, "backup", "running") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -540,7 +563,6 @@ main(int argc,
|
|||
int sockfamily;
|
||||
char *xmldb_plugin;
|
||||
int xml_cache;
|
||||
int xml_pretty;
|
||||
char *xml_format;
|
||||
char *nacm_mode;
|
||||
int logdst = CLICON_LOG_SYSLOG|CLICON_LOG_STDERR;
|
||||
|
|
@ -808,9 +830,10 @@ main(int argc,
|
|||
if ((xml_format = clicon_option_str(h, "CLICON_XMLDB_FORMAT")) >= 0)
|
||||
if (xmldb_setopt(h, "format", (void*)xml_format) < 0)
|
||||
goto done;
|
||||
if ((xml_pretty = clicon_option_bool(h, "CLICON_XMLDB_PRETTY")) >= 0)
|
||||
if (xmldb_setopt(h, "pretty", (void*)(intptr_t)xml_pretty) < 0)
|
||||
goto done;
|
||||
if (xmldb_setopt(h, "pretty", (void*)(intptr_t)clicon_option_bool(h, "CLICON_XMLDB_PRETTY")) < 0)
|
||||
goto done;
|
||||
if (xmldb_setopt(h, "sort", (void*)(intptr_t)clicon_option_bool(h, "CLICON_XML_SORT")) < 0)
|
||||
goto done;
|
||||
/* Startup mode needs to be defined, */
|
||||
startup_mode = clicon_startup_mode(h);
|
||||
if (startup_mode == -1){
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ clixon_plugin_reset(clicon_handle h,
|
|||
* @param[in,out] xtop State XML tree is merged with existing tree.
|
||||
* @retval -1 Error
|
||||
* @retval 0 OK
|
||||
* @retval 1 Statedata callback failed
|
||||
* @retval 1 Statedata callback failed (xret set with netconf-error)
|
||||
* @note xtop can be replaced
|
||||
*/
|
||||
int
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue