* Proper RFC 6241 Netconf error handling

* New functions added in clixon_netconf_lib.[ch]
  * Datastore code modified for RFC 6241
  * Remaining: validate, generic restconf and netconf code
This commit is contained in:
Olof hagsand 2018-03-18 18:06:02 +00:00
parent 52e510cfdf
commit efa72e9e6f
26 changed files with 1196 additions and 475 deletions

View file

@ -180,7 +180,7 @@ backend_client_rm(clicon_handle h,
return backend_client_delete(h, ce); /* actually purge it */
}
/*! FInd target/source in netconf request. Assume sanity made so not finding is error */
/*! Find target/source in netconf request. Assume sanity- not finding is error */
static char*
netconf_db_find(cxobj *xn,
char *name)
@ -214,31 +214,28 @@ from_client_get_config(clicon_handle h,
cxobj *xfilter;
char *selector = "/";
cxobj *xret = NULL;
cbuf *cbx = NULL; /* Assist cbuf */
if ((db = netconf_db_find(xe, "source")) == NULL){
clicon_err(OE_XML, 0, "db not found");
goto done;
}
if (xmldb_validate_db(db) < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>invalid-value</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>No such database: %s</error-message>"
"</rpc-error></rpc-reply>", db);
if ((cbx = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cbx, "No such database: %s", db);
if (netconf_invalid_value(cbret, "protocol", cbuf_get(cbx))< 0)
goto done;
goto ok;
}
if ((xfilter = xml_find(xe, "filter")) != NULL)
if ((selector = xml_find_value(xfilter, "select"))==NULL)
selector="/";
if (xmldb_get(h, db, selector, 1, &xret) < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
"<error-type>application</error-type>"
"<error-severity>error</error-severity>"
"<error-info>read-registry</error-info>"
"</rpc-error></rpc-reply>");
if (netconf_operation_failed(cbret, "application", "read registry")< 0)
goto done;
goto ok;
}
cprintf(cbret, "<rpc-reply>");
@ -254,6 +251,8 @@ from_client_get_config(clicon_handle h,
ok:
retval = 0;
done:
if (cbx)
cbuf_free(cbx);
if (xret)
xml_free(xret);
return retval;
@ -276,18 +275,15 @@ from_client_get(clicon_handle h,
char *selector = "/";
cxobj *xret = NULL;
int ret;
cbuf *cbx = NULL; /* Assist cbuf */
if ((xfilter = xml_find(xe, "filter")) != NULL)
if ((selector = xml_find_value(xfilter, "select"))==NULL)
selector="/";
/* Get config */
if (xmldb_get(h, "running", selector, 0, &xret) < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
"<error-type>application</error-type>"
"<error-severity>error</error-severity>"
"<error-info>read-registry</error-info>"
"</rpc-error></rpc-reply>");
if (netconf_operation_failed(cbret, "application", "read registry")< 0)
goto done;
goto ok;
}
/* Get state data from plugins as defined by plugin_statedata(), if any */
@ -308,23 +304,25 @@ from_client_get(clicon_handle h,
cprintf(cbret, "</rpc-reply>");
}
else { /* 1 Error from callback */
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
"<error-type>rpc</error-type>"
"<error-severity>error</error-severity>"
"<error-message>Internal error:%s</error-message>"
"</rpc-error></rpc-reply>", clicon_err_reason);
if ((cbx = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
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));
}
ok:
retval = 0;
done:
if (cbx)
cbuf_free(cbx);
if (xret)
xml_free(xret);
return retval;
}
/*! Internal message: edit-config
*
* @param[in] h Clicon handle
@ -340,14 +338,13 @@ from_client_edit_config(clicon_handle h,
{
int retval = -1;
char *target;
cbuf *cb = NULL;
cxobj *xret = NULL;
cxobj *xc;
cxobj *x;
enum operation_type operation = OP_MERGE;
int piddb;
int non_config = 0;
yang_spec *yspec;
cbuf *cbx = NULL; /* Assist cbuf */
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_YANG, ENOENT, "No yang spec");
@ -357,50 +354,44 @@ from_client_edit_config(clicon_handle h,
clicon_err(OE_XML, 0, "db not found");
goto done;
}
if ((cbx = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
if (xmldb_validate_db(target) < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>invalid-value</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>No such database: %s</error-message>"
"</rpc-error></rpc-reply>", target);
cprintf(cbx, "No such database: %s", target);
if (netconf_invalid_value(cbret, "protocol", cbuf_get(cbx))< 0)
goto done;
goto ok;
}
/* Check if target locked by other client */
piddb = xmldb_islocked(h, target);
if (piddb && mypid != piddb){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>lock-denied</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>Operation failed, lock is already held</error-message>"
"<error-info><session-id>%d</session-id></error-info>"
"</rpc-error></rpc-reply>",
piddb);
cprintf(cbx, "<session-id>%d</session-id>", piddb);
if (netconf_lock_denied(cbret, cbuf_get(cbx), "Operation failed, lock is already held") < 0)
goto done;
goto ok;
}
if ((x = xpath_first(xn, "default-operation")) != NULL){
if (xml_operation(xml_body(x), &operation) < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>invalid-value</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"</rpc-error></rpc-reply>");
if (netconf_invalid_value(cbret, "protocol", "Wrong operation")< 0)
goto done;
goto ok;
}
}
if ((xc = xpath_first(xn, "config")) != NULL){
if ((xc = xpath_first(xn, "config")) == NULL){
if (netconf_missing_element(cbret, "protocol", "<bad-element>config</bad-element>", NULL) < 0)
goto done;
goto ok;
}
else{
if (xml_apply(xc, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done;
if (xml_apply(xc, CX_ELMNT, xml_non_config_data, &non_config) < 0)
goto done;
if (non_config){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>invalid-value</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>state data not allowed</error-message>"
"</rpc-error></rpc-reply>");
if (netconf_invalid_value(cbret, "protocol", "State data not allowed")< 0)
goto done;
goto ok;
}
/* Cant do this earlier since we dont have a yang spec to
@ -408,35 +399,23 @@ from_client_edit_config(clicon_handle h,
*/
if (xml_child_sort && xml_apply0(xc, CX_ELMNT, xml_sort, NULL) < 0)
goto done;
if (xmldb_put(h, target, operation, xc) < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>%s</error-message>"
"</rpc-error></rpc-reply>", clicon_err_reason);
if (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;
}
}
else{
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>missing-element</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-info><bad-element>config</bad-element></error-info>"
"</rpc-error></rpc-reply>");
goto ok;
}
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
ok:
if (!cbuf_len(cbret))
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
retval = 0;
done:
if (xret)
xml_free(xret);
if (cb)
cbuf_free(cb);
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
*
@ -454,26 +433,23 @@ from_client_lock(clicon_handle h,
int retval = -1;
char *db;
int piddb;
cbuf *cbx = NULL; /* Assist cbuf */
if ((db = netconf_db_find(xe, "target")) == NULL){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>missing-element</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-info><bad-element>target</bad-element></error-info>"
"</rpc-error></rpc-reply>");
if (netconf_missing_element(cbret, "protocol", "<bad-element>target</bad-element>", NULL) < 0)
goto done;
goto ok;
}
if ((cbx = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
if (xmldb_validate_db(db) < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>invalid-value</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>No such database: %s</error-message>"
"</rpc-error></rpc-reply>", db);
cprintf(cbx, "No such database: %s", db);
if (netconf_invalid_value(cbret, "protocol", cbuf_get(cbx))< 0)
goto done;
goto ok;
}
/*
* A lock MUST not be granted if either of the following conditions is true:
* 1) A lock is already held by any NETCONF session or another entity.
@ -482,23 +458,21 @@ from_client_lock(clicon_handle h,
*/
piddb = xmldb_islocked(h, db);
if (piddb){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>lock-denied</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>Lock failed, lock is already held</error-message>"
"<error-info><session-id>%d</session-id></error-info>"
"</rpc-error></rpc-reply>",
piddb);
cprintf(cbx, "<session-id>%d</session-id>", piddb);
if (netconf_lock_denied(cbret, cbuf_get(cbx), "Operation failed, lock is already held") < 0)
goto done;
goto ok;
}
else{
xmldb_lock(h, db, pid);
if (xmldb_lock(h, db, pid) < 0)
goto done;
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
}
ok:
retval = 0;
// done:
done:
if (cbx)
cbuf_free(cbx);
return retval;
}
@ -518,23 +492,21 @@ from_client_unlock(clicon_handle h,
int retval = -1;
char *db;
int piddb;
cbuf *cbx = NULL; /* Assist cbuf */
if ((db = netconf_db_find(xe, "target")) == NULL){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>missing-element</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-info><bad-element>target</bad-element></error-info>"
"</rpc-error></rpc-reply>");
if (netconf_missing_element(cbret, "protocol", "<bad-element>target</bad-element>", NULL) < 0)
goto done;
goto ok;
}
if ((cbx = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
if (xmldb_validate_db(db) < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>invalid-value</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>No such database: %s</error-message>"
"</rpc-error></rpc-reply>", db);
cprintf(cbx, "No such database: %s", db);
if (netconf_invalid_value(cbret, "protocol", cbuf_get(cbx))< 0)
goto done;
goto ok;
}
piddb = xmldb_islocked(h, db);
@ -546,14 +518,9 @@ from_client_unlock(clicon_handle h,
* session that obtained the lock
*/
if (piddb==0 || piddb != pid){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>lock-denied</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>Unlock failed, lock is already held</error-message>"
"<error-info><session-id>pid=%d piddb=%d</session-id></error-info>"
"</rpc-error></rpc-reply>",
pid, piddb);
cprintf(cbx, "<session-id>pid=%d piddb=%d</session-id>", pid, piddb);
if (netconf_lock_denied(cbret, cbuf_get(cbx), "Unlock failed, lock is already held") < 0)
goto done;
goto ok;
}
else{
@ -585,15 +552,11 @@ from_client_kill_session(clicon_handle h,
struct client_entry *ce;
char *db = "running"; /* XXX */
cxobj *x;
if ((x = xml_find(xe, "session-id")) == NULL ||
(str = xml_find_value(x, "body")) == NULL){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>missing-element</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-info><bad-element>session-id</bad-element></error-info>"
"</rpc-error></rpc-reply>");
if (netconf_missing_element(cbret, "protocol", "<bad-element>session-id</bad-element>", NULL) < 0)
goto done;
goto ok;
}
pid = atoi(str);
@ -618,18 +581,14 @@ from_client_kill_session(clicon_handle h,
xmldb_unlock(h, db);
}
else{ /* failed to kill client */
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
"<error-type>application</error-type>"
"<error-severity>error</error-severity>"
"<error-message>Faile to kill session</error-message>"
"</rpc-error></rpc-reply>");
if (netconf_operation_failed(cbret, "application", "Failed to kill session")< 0)
goto done;
goto ok;
}
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
ok:
retval = 0;
// done:
done:
return retval;
}
@ -647,74 +606,57 @@ from_client_copy_config(clicon_handle h,
int mypid,
cbuf *cbret)
{
char *source;
char *target;
int retval = -1;
int piddb;
char *source;
char *target;
int retval = -1;
int piddb;
cbuf *cbx = NULL; /* Assist cbuf */
if ((source = netconf_db_find(xe, "source")) == NULL){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>missing-element</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-info><bad-element>source</bad-element></error-info>"
"</rpc-error></rpc-reply>");
if (netconf_missing_element(cbret, "protocol", "<bad-element>source</bad-element>", NULL) < 0)
goto done;
goto ok;
}
if ((cbx = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
if (xmldb_validate_db(source) < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>invalid-value</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>No such database: %s</error-message>"
"</rpc-error></rpc-reply>", source);
cprintf(cbx, "No such database: %s", source);
if (netconf_invalid_value(cbret, "protocol", cbuf_get(cbx))< 0)
goto done;
goto ok;
}
if ((target = netconf_db_find(xe, "target")) == NULL){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>missing-element</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-info><bad-element>target</bad-element></error-info>"
"</rpc-error></rpc-reply>");
if (netconf_missing_element(cbret, "protocol", "<bad-element>target</bad-element>", NULL) < 0)
goto done;
goto ok;
}
if (xmldb_validate_db(target) < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>invalid-value</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>No such database: %s</error-message>"
"</rpc-error></rpc-reply>", target);
cprintf(cbx, "No such database: %s", target);
if (netconf_invalid_value(cbret, "protocol", cbuf_get(cbx))< 0)
goto done;
goto ok;
}
/* Check if target locked by other client */
piddb = xmldb_islocked(h, target);
if (piddb && mypid != piddb){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>lock-denied</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>Operation failed, lock is already held</error-message>"
"<error-info><session-id>%d</session-id></error-info>"
"</rpc-error></rpc-reply>",
piddb);
cprintf(cbx, "<session-id>%d</session-id>", piddb);
if (netconf_lock_denied(cbret, cbuf_get(cbx), "Copy failed, lock is already held") < 0)
goto done;
goto ok;
}
if (xmldb_copy(h, source, target) < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
"<error-type>application</error-type>"
"<error-severity>error</error-severity>"
"<error-info>read-registry</error-info>"
"</rpc-error></rpc-reply>");
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
goto done;
goto ok;
}
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
ok:
retval = 0;
// done:
done:
if (cbx)
cbuf_free(cbx);
return retval;
}
@ -732,67 +674,51 @@ from_client_delete_config(clicon_handle h,
int mypid,
cbuf *cbret)
{
int retval = -1;
char *target;
int piddb;
int retval = -1;
char *target;
int piddb;
cbuf *cbx = NULL; /* Assist cbuf */
if ((target = netconf_db_find(xe, "target")) == NULL||
strcmp(target, "running")==0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>missing-element</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-info><bad-element>target</bad-element></error-info>"
"</rpc-error></rpc-reply>");
if (netconf_missing_element(cbret, "protocol", "<bad-element>target</bad-element>", NULL) < 0)
goto done;
goto ok;
}
if ((cbx = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
if (xmldb_validate_db(target) < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>invalid-value</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>No such database: %s</error-message>"
"</rpc-error></rpc-reply>", target);
cprintf(cbx, "No such database: %s", target);
if (netconf_invalid_value(cbret, "protocol", cbuf_get(cbx))< 0)
goto done;
goto ok;
}
/* Check if target locked by other client */
piddb = xmldb_islocked(h, target);
if (piddb && mypid != piddb){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>lock-denied</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>Operation failed, lock is already held</error-message>"
"<error-info><session-id>%d</session-id></error-info>"
"</rpc-error></rpc-reply>",
piddb);
cprintf(cbx, "<session-id>%d</session-id>", piddb);
if (netconf_lock_denied(cbret, cbuf_get(cbx), "Operation failed, lock is already held") < 0)
goto done;
goto ok;
}
if (xmldb_delete(h, target) < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-info>Internal error</error-info>"
"<error-message>%s</error-message>"
"</rpc-error></rpc-reply>", clicon_err_reason);
if (netconf_operation_failed(cbret, "protocol", clicon_err_reason)< 0)
goto done;
goto ok;
}
if (xmldb_create(h, target) < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-info>Internal error</error-info>"
"<error-message>%s</error-message>"
"</rpc-error></rpc-reply>", clicon_err_reason);
if (netconf_operation_failed(cbret, "protocol", clicon_err_reason)< 0)
goto done;
goto ok;
}
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
ok:
retval = 0;
// done:
done:
if (cbx)
cbuf_free(cbx);
return retval;
}
@ -829,13 +755,8 @@ from_client_create_subscription(clicon_handle h,
if ((ftype = xml_find_value(x, "type")) != NULL){
/* Only accept xpath as filter type */
if (strcmp(ftype, "xpath") != 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
"<error-type>application</error-type>"
"<error-severity>error</error-severity>"
"<error-message>only xpath filter type supported</error-message>"
"<error-info>type</error-info>"
"</rpc-error></rpc-reply>");
if (netconf_operation_failed(cbret, "application", "Only xpath filter type supported")< 0)
goto done;
goto ok;
}
}
@ -866,12 +787,8 @@ from_client_debug(clicon_handle h,
char *valstr;
if ((valstr = xml_find_body(xe, "level")) == NULL){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>missing-element</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-info><bad-element>level</bad-element></error-info>"
"</rpc-error></rpc-reply>");
if (netconf_missing_element(cbret, "application", "<bad-element>level</bad-element>", NULL) < 0)
goto done;
goto ok;
}
level = atoi(valstr);
@ -882,7 +799,7 @@ from_client_debug(clicon_handle h,
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
ok:
retval = 0;
//done:
done:
return retval;
}
@ -917,23 +834,13 @@ from_client_msg(clicon_handle h,
goto done;
}
if (clicon_msg_decode(msg, &xt) < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
"<error-type>rpc</error-type>"
"<error-severity>error</error-severity>"
"<error-message>rpc expected</error-message>"
"<error-info>Not recognized</error-info>"
"</rpc-error></rpc-reply>");
if (netconf_malformed_message(cbret, "Not recognized, rpc expected")< 0)
goto done;
goto reply;
}
if ((x = xpath_first(xt, "/rpc")) == NULL){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
"<error-type>rpc</error-type>"
"<error-severity>error</error-severity>"
"<error-message>rpc expected</error-message>"
"<error-info>Not recognized</error-info>"
"</rpc-error></rpc-reply>");
if (netconf_malformed_message(cbret, "Not recognized, rpc expected")< 0)
goto done;
goto reply;
}
xe = NULL;
@ -977,12 +884,8 @@ from_client_msg(clicon_handle h,
}
else if (strcmp(name, "validate") == 0){
if ((db = netconf_db_find(xe, "source")) == NULL){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>missing-element</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-info><bad-element>source</bad-element></error-info>"
"</rpc-error></rpc-reply>");
if (netconf_missing_element(cbret, "protocol", "<bad-element>source</bad-element>", NULL) < 0)
goto done;
goto reply;
}
if (from_client_validate(h, db, cbret) < 0)
@ -1007,34 +910,22 @@ from_client_msg(clicon_handle h,
else{
clicon_err_reset();
if ((ret = backend_rpc_cb_call(h, xe, ce, cbret)) < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
"<error-type>rpc</error-type>"
"<error-severity>error</error-severity>"
"<error-message>Internal error:%s</error-message>"
"</rpc-error></rpc-reply>", clicon_err_reason);
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
goto done;
clicon_log(LOG_NOTICE, "%s Error in backend_rpc_call:%s", __FUNCTION__, xml_name(xe));
goto reply; /* Dont quit here on user callbacks */
}
if (ret == 0) /* not handled by callback */
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
"<error-type>rpc</error-type>"
"<error-severity>error</error-severity>"
"<error-message>%s</error-message>"
"<error-info>Not recognized</error-info>"
"</rpc-error></rpc-reply>",
name);
if (ret == 0){ /* not handled by callback */
if (netconf_operation_failed(cbret, "application", "Callback not recognized")< 0)
goto done;
goto reply;
}
}
}
reply:
if (cbuf_len(cbret) == 0)
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
"<error-type>rpc</error-type>"
"<error-severity>error</error-severity>"
"<error-message>Internal error %s</error-message>"
"</rpc-error></rpc-reply>",clicon_err_reason);
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
goto done;
clicon_debug(1, "%s cbret:%s", __FUNCTION__, cbuf_get(cbret));
if (send_msg_reply(ce->ce_s, cbuf_get(cbret), cbuf_len(cbret)+1) < 0){
switch (errno){
@ -1055,7 +946,7 @@ from_client_msg(clicon_handle h,
}
// ok:
retval = 0;
done:
done:
if (xt)
xml_free(xt);
if (cbret)

View file

@ -241,7 +241,7 @@ candidate_commit(clicon_handle h,
/* 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) < 0)
if (xmldb_put(h, candidate, OP_REPLACE, td->td_target, NULL) < 0)
goto done;
/* 8. Success: Copy candidate to running
*/
@ -282,35 +282,32 @@ from_client_commit(clicon_handle h,
{
int retval = -1;
int piddb;
cbuf *cbx = NULL; /* Assist cbuf */
/* Check if target locked by other client */
piddb = xmldb_islocked(h, "running");
if (piddb && mypid != piddb){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>lock-denied</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>Operation failed, lock is already held</error-message>"
"<error-info><session-id>%d</session-id></error-info>"
"</rpc-error></rpc-reply>",
piddb);
if ((cbx = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cbx, "<session-id>%d</session-id>", piddb);
if (netconf_lock_denied(cbret, cbuf_get(cbx), "Operation failed, lock is already held") < 0)
goto done;
goto ok;
}
if (candidate_commit(h, "candidate") < 0){ /* Assume validation fail, nofatal */
clicon_debug(1, "Commit candidate failed");
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>invalid-value</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>%s</error-message>"
"</rpc-error></rpc-reply>",
clicon_err_reason);
if (netconf_invalid_value(cbret, "protocol", clicon_err_reason)< 0)
goto done;
goto ok;
}
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
ok:
retval = 0;
// done:
done:
if (cbx)
cbuf_free(cbx);
return retval; /* may be zero if we ignoring errors from commit */
} /* from_client_commit */
@ -328,33 +325,31 @@ from_client_discard_changes(clicon_handle h,
{
int retval = -1;
int piddb;
cbuf *cbx = NULL; /* Assist cbuf */
/* Check if target locked by other client */
piddb = xmldb_islocked(h, "candidate");
if (piddb && mypid != piddb){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>lock-denied</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>Operation failed, lock is already held</error-message>"
"<error-info><session-id>%d</session-id></error-info>"
"</rpc-error></rpc-reply>",
piddb);
if ((cbx = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cbx, "<session-id>%d</session-id>", piddb);
if (netconf_lock_denied(cbret, cbuf_get(cbx), "Operation failed, lock is already held") < 0)
goto done;
goto ok;
}
if (xmldb_copy(h, "running", "candidate") < 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
"<error-type>application</error-type>"
"<error-severity>error</error-severity>"
"<error-info>read-registry</error-info>"
"</rpc-error></rpc-reply>");
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
goto done;
goto ok;
}
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
ok:
retval = 0;
// done:
done:
if (cbx)
cbuf_free(cbx);
return retval; /* may be zero if we ignoring errors from commit */
}
@ -374,11 +369,8 @@ from_client_validate(clicon_handle h,
transaction_data_t *td = NULL;
if (strcmp(db, "candidate") != 0 && strcmp(db, "tmp") != 0){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>invalid-value</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"</rpc-error></rpc-reply>");
if (netconf_invalid_value(cbret, "protocol", "No such database")< 0)
goto done;
goto ok;
}
clicon_debug(1, "Validate %s", db);
@ -390,18 +382,13 @@ from_client_validate(clicon_handle h,
if (validate_common(h, db, td) < 0){
clicon_debug(1, "Validate %s failed", db);
/* XXX: candidate_validate should have proper error handling */
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>missing-attribute</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"<error-message>%s</error-message>"
"</rpc-error></rpc-reply>",
clicon_err_reason);
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
goto done;
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) < 0)
if (xmldb_put(h, "candidate", OP_REPLACE, td->td_target, NULL) < 0)
goto done;
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
ok:

View file

@ -174,8 +174,8 @@ db_merge(clicon_handle h,
/* 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) < 0)
/* Merge xml into db2. Without commit */
if (xmldb_put(h, (char*)db2, OP_MERGE, xt, NULL) < 0)
goto done;
retval = 0;
done:
@ -283,7 +283,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) < 0)
if (xmldb_put(h, (char*)db, OP_MERGE, xt, NULL) < 0)
goto done;
retval = 0;
done:
@ -703,43 +703,41 @@ main(int argc, char **argv)
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 startup mode is not defined, eg via OPTION or -s, assume old method */
/* Startup mode needs to be defined, */
startup_mode = clicon_startup_mode(h);
if (startup_mode == -1){
clicon_log(LOG_ERR, "Startup mode undefined. Specify option CLICON_STARTUP_MODE or specify -s option to clicon_backend.\n");
goto done;
}
else {
/* Init running db if it is not there
*/
if (xmldb_exists(h, "running") != 1)
if (xmldb_create(h, "running") < 0)
return -1;
switch (startup_mode){
case SM_NONE:
if (startup_mode_none(h) < 0)
goto done;
break;
case SM_INIT: /* -I */
if (startup_mode_init(h) < 0)
goto done;
break;
case SM_RUNNING: /* -CIr */
if (startup_mode_running(h, extraxml_file) < 0)
goto done;
break;
case SM_STARTUP: /* startup configuration */
if (startup_mode_startup(h, extraxml_file) < 0)
goto done;
break;
}
/* Initiate the shared candidate. */
if (xmldb_copy(h, "running", "candidate") < 0)
/* Init running db if it is not there
*/
if (xmldb_exists(h, "running") != 1)
if (xmldb_create(h, "running") < 0)
return -1;
switch (startup_mode){
case SM_NONE:
if (startup_mode_none(h) < 0)
goto done;
/* Call plugin_start with user -- options */
if (plugin_start_useroptions(h, argv0, argc, argv) <0)
break;
case SM_INIT: /* -I */
if (startup_mode_init(h) < 0)
goto done;
break;
case SM_RUNNING: /* -CIr */
if (startup_mode_running(h, extraxml_file) < 0)
goto done;
break;
case SM_STARTUP: /* startup configuration */
if (startup_mode_startup(h, extraxml_file) < 0)
goto done;
break;
}
/* Initiate the shared candidate. */
if (xmldb_copy(h, "running", "candidate") < 0)
goto done;
/* Call backend plugin_start with user -- options */
if (plugin_start_useroptions(h, argv0, argc, argv) <0)
goto done;
if (once)
goto done;

View file

@ -100,13 +100,9 @@ process_incoming_packet(clicon_handle h,
/* Parse incoming XML message */
if (xml_parse_string(str, NULL, &xreq) < 0){
if ((cbret = cbuf_new()) == NULL){
cprintf(cbret, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
"<error-type>rpc</error-type>"
"<error-severity>error</error-severity>"
"<error-message>internal error</error-message>"
"</rpc-error></rpc-reply>");
netconf_output(1, cb, "rpc-error");
if (netconf_operation_failed(cbret, "rpc", "internal error")< 0)
goto done;
netconf_output(1, cbret, "rpc-error");
}
else
clicon_log(LOG_ERR, "%s: cbuf_new", __FUNCTION__);

View file

@ -42,7 +42,6 @@
#include <fcntl.h>
#include <ctype.h>
#include <time.h>
#include <fcgi_stdio.h>
#include <signal.h>
#include <dlfcn.h>
#include <sys/param.h>
@ -55,6 +54,8 @@
/* clicon */
#include <clixon/clixon.h>
#include <fcgi_stdio.h> /* Need to be after clixon_xml-h due to attribute format */
#include "restconf_lib.h"
/* See RFC 8040 Section 7: Mapping from NETCONF<error-tag> to Status Code

View file

@ -54,7 +54,7 @@
#include <syslog.h>
#include <fcntl.h>
#include <time.h>
#include <fcgi_stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/wait.h>
@ -66,6 +66,8 @@
/* clicon */
#include <clixon/clixon.h>
#include <fcgi_stdio.h> /* Need to be after clixon_xml-h due to attribute format */
/* restconf */
#include "restconf_lib.h"
#include "restconf_methods.h"
@ -208,9 +210,9 @@ api_well_known(clicon_handle h,
FCGX_FPrintF(r->out, "Content-Type: application/xrd+xml\r\n");
FCGX_FPrintF(r->out, "\r\n");
FCGX_SetExitStatus(200, r->out); /* OK */
FCGX_FPrintF(r->out, "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>\r\n");
FCGX_FPrintF(r->out, " <Link rel='restconf' href='/restconf'/>\r\n");
FCGX_FPrintF(r->out, "</XRD>\r\n");
FCGX_FPrintF(r->out, "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>\n");
FCGX_FPrintF(r->out, " <Link rel='restconf' href='/restconf'/>\n");
FCGX_FPrintF(r->out, "</XRD>\n");
return 0;
}
@ -258,7 +260,7 @@ api_root(clicon_handle h,
if (xml2json_cbuf(cb, xt, pretty) < 0)
goto done;
FCGX_FPrintF(r->out, "%s", cb?cbuf_get(cb):"");
FCGX_FPrintF(r->out, "\r\n\r\n");
FCGX_FPrintF(r->out, "\n\n");
retval = 0;
done:
if (cb)
@ -307,8 +309,8 @@ api_yang_library_version(clicon_handle h,
goto done;
}
clicon_debug(1, "%s cb%s", __FUNCTION__, cbuf_get(cb));
FCGX_FPrintF(r->out, "%s\r\n", cb?cbuf_get(cb):"");
FCGX_FPrintF(r->out, "\r\n\r\n");
FCGX_FPrintF(r->out, "%s\n", cb?cbuf_get(cb):"");
FCGX_FPrintF(r->out, "\n\n");
retval = 0;
done:
if (cb)
@ -599,7 +601,7 @@ main(int argc,
}
else
clicon_debug(1, "NULL URI");
FCGX_Finish_r(r);
FCGX_Finish_r(r);
}
retval = 0;
done:

View file

@ -104,7 +104,6 @@ Mapping netconf error-tag -> status code
#include <fcntl.h>
#include <assert.h>
#include <time.h>
#include <fcgi_stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/wait.h>
@ -115,6 +114,8 @@ Mapping netconf error-tag -> status code
/* clicon */
#include <clixon/clixon.h>
#include <fcgi_stdio.h> /* Need to be after clixon_xml-h due to attribute format */
#include "restconf_lib.h"
#include "restconf_methods.h"
@ -157,6 +158,7 @@ api_return_err(clicon_handle h,
int retval = -1;
cbuf *cb = NULL;
cxobj *xtag;
char *tagstr;
int code;
const char *reason_phrase;
@ -167,7 +169,8 @@ api_return_err(clicon_handle h,
notfound(r); /* bad reply? */
goto ok;
}
code = restconf_err2code(xml_body(xtag));
tagstr = xml_body(xtag);
code = restconf_err2code(tagstr);
if ((reason_phrase = restconf_code2reason(code)) == NULL)
reason_phrase="";
if (xml_name_set(xerr, "error") < 0)
@ -183,22 +186,29 @@ api_return_err(clicon_handle h,
FCGX_FPrintF(r->out, "Content-Type: application/yang-data+%s\r\n\r\n",
use_xml?"xml":"json");
if (use_xml){
FCGX_FPrintF(r->out, " <errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\">%s", cbuf_get(cb), pretty?"\r\n":"");
FCGX_FPrintF(r->out, "%s", cbuf_get(cb));
FCGX_FPrintF(r->out, " </errors>\r\n");
if (pretty){
FCGX_FPrintF(r->out, " <errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\">\n", cbuf_get(cb));
FCGX_FPrintF(r->out, "%s", cbuf_get(cb));
FCGX_FPrintF(r->out, " </errors>\n");
}
else {
FCGX_FPrintF(r->out, "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\">", cbuf_get(cb));
FCGX_FPrintF(r->out, "%s", cbuf_get(cb));
FCGX_FPrintF(r->out, "</errors>\n");
}
}
else{
if (pretty){
FCGX_FPrintF(r->out, "{\r\n");
FCGX_FPrintF(r->out, " \"ietf-restconf:errors\" : %s\r\n",
FCGX_FPrintF(r->out, "{\n");
FCGX_FPrintF(r->out, " \"ietf-restconf:errors\" : %s\n",
cbuf_get(cb));
FCGX_FPrintF(r->out, "}\r\n");
FCGX_FPrintF(r->out, "}\n");
}
else{
FCGX_FPrintF(r->out, "{");
FCGX_FPrintF(r->out, "\"ietf-restconf:errors\" : ");
FCGX_FPrintF(r->out, "%s", cbuf_get(cb));
FCGX_FPrintF(r->out, "}\r\n");
FCGX_FPrintF(r->out, "}\n");
}
}
ok:
@ -330,7 +340,7 @@ api_data_get2(clicon_handle h,
clicon_debug(1, "%s cbuf:%s", __FUNCTION__, cbuf_get(cbx));
FCGX_FPrintF(r->out, "%s", cbx?cbuf_get(cbx):"");
FCGX_FPrintF(r->out, "\r\n\r\n");
FCGX_FPrintF(r->out, "\n\n");
ok:
retval = 0;
done:
@ -1010,9 +1020,9 @@ api_operations_get(clicon_handle h,
clicon_debug(1, "%s ret:%s", __FUNCTION__, cbuf_get(cbx));
FCGX_SetExitStatus(200, r->out); /* OK */
FCGX_FPrintF(r->out, "Content-Type: application/yang-data+%s\r\n", use_xml?"xml":"json");
FCGX_FPrintF(r->out, "\r\n");
FCGX_FPrintF(r->out, "\n");
FCGX_FPrintF(r->out, "%s", cbx?cbuf_get(cbx):"");
FCGX_FPrintF(r->out, "\r\n\r\n");
FCGX_FPrintF(r->out, "\n\n");
// ok:
retval = 0;
done:
@ -1183,7 +1193,7 @@ api_operations_post(clicon_handle h,
goto done;
clicon_debug(1, "%s xoutput:%s", __FUNCTION__, cbuf_get(cbx));
FCGX_FPrintF(r->out, "%s", cbx?cbuf_get(cbx):"");
FCGX_FPrintF(r->out, "\r\n\r\n");
FCGX_FPrintF(r->out, "\n\n");
}
ok:
retval = 0;