Hand-crafted validation messages removed and replaced with generic validations.

This commit is contained in:
Olof hagsand 2019-01-05 14:16:56 +01:00
parent 5b6af82e29
commit 0502ca4218
2 changed files with 30 additions and 364 deletions

View file

@ -80,9 +80,9 @@
### API changes on existing features (you may need to change your code)
* Stricter YANG choice validation leads to enforcement of structures like: `choice c{ mandatory true; leaf x` statements. `x` was not previously enforced.
* CLICON_XML_SORT option (in clixon-config.yang) has been removed and set to true permanently since setting it to false is obsolete.
* Many hand-crafted validation messages have been removed and replaced with generic validations, which may lead to changed rpc-error messages.
* CLICON_XML_SORT option (in clixon-config.yang) has been removed and set to true permanently. Unsorted XML lists leads to slower performance and old obsolete code can be removed.
* 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.
* Removed `delete-config` support for candidate db since it is not supported in RFC6241.
* Switched the order of `error-type` and `error-tag` in all netconf and restconf error messages to comply to RFC order.
* Yang parser is stricter (see above) which may break parsing of existing yang specs.

View file

@ -135,20 +135,10 @@ netconf_get_config(clicon_handle h,
{
cxobj *xfilter; /* filter */
int retval = -1;
char *source;
char *ftype = NULL;
cxobj *xfilterconf;
cxobj *xconf;
if ((source = netconf_get_target(xn, "source")) == NULL){
xml_parse_va(xret, NULL, "<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>");
goto ok;
}
/* ie <filter>...</filter> */
if ((xfilter = xpath_first(xn, "filter")) != NULL)
ftype = xml_find_value(xfilter, "type");
@ -187,7 +177,6 @@ netconf_get_config(clicon_handle h,
"<error-info>type</error-info>"
"</rpc-error></rpc-reply>");
}
ok: /* netconf error is not fatal */
retval = 0;
done:
return retval;
@ -223,11 +212,9 @@ get_edit_opts(cxobj *xn,
if ((optstr = xml_body(x)) != NULL){
if (strcmp(optstr, "test-then-set") == 0)
*testopt = TEST_THEN_SET;
else
if (strcmp(optstr, "set") == 0)
else if (strcmp(optstr, "set") == 0)
*testopt = SET;
else
if (strcmp(optstr, "test-only") == 0)
else if (strcmp(optstr, "test-only") == 0)
*testopt = TEST_ONLY;
else
goto parerr;
@ -311,52 +298,18 @@ netconf_edit_config(clicon_handle h,
{
int retval = -1;
int optret;
enum operation_type operation = OP_MERGE;
enum test_option testopt = TEST_THEN_SET;/* only supports this */
enum error_option erropt = STOP_ON_ERROR; /* only supports this */
cxobj *x;
cxobj *xfilter;
char *ftype = NULL;
char *target; /* db */
/* must have target, and it should be candidate */
if ((target = netconf_get_target(xn, "target")) == NULL ||
strcmp(target, "candidate")){
xml_parse_va(xret, NULL, "<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>");
goto ok;
}
/* CLICON addition, eg <filter type="restconf" select=<api-path> /> */
if ((xfilter = xpath_first(xn, "filter")) != NULL) {
if ((ftype = xml_find_value(xfilter, "type")) != NULL)
if (strcmp(ftype,"restconf")){
xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>"
"<error-tag>invalid-value</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"</rpc-error></rpc-reply>");
goto ok;
}
}
if ((x = xpath_first(xn, "default-operation")) != NULL){
if (xml_operation(xml_body(x), &operation) < 0){
xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>"
"<error-tag>invalid-value</error-tag>"
"<error-type>protocol</error-type>"
"<error-severity>error</error-severity>"
"</rpc-error></rpc-reply>");
goto ok;
}
}
if ((optret = get_edit_opts(xn, &testopt, &erropt, xret)) < 0)
goto done;
if (optret == 0) /* error in opt parameters */
goto ok;
/* not supported opts */
/* These constraints are clixon-specific since :validate should
* support all testopts, and erropts should be supported
* And therefore extends the validation
* (implement the features before removing these checks)
*/
if (testopt!=TEST_THEN_SET || erropt!=STOP_ON_ERROR){
xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>"
"<error-tag>operation-not-supported</error-tag>"
@ -373,149 +326,6 @@ netconf_edit_config(clicon_handle h,
return retval;
}
/*! Netconf copy configuration
<copy-config>
<target>
<candidate/>
</target>
<source>
<url>
<!- - location specifier for file containing the new configuration - ->
</url>
</source>
<copy-config>
* @param[in] h clicon handle
* @param[in] xn Sub-tree (under xorig) at <rpc>...</rpc> level.
* @param[out] xret Return XML, error or OK
*/
static int
netconf_copy_config(clicon_handle h,
cxobj *xn,
cxobj **xret)
{
int retval = -1;
char *source;
char *target; /* filenames */
if ((source = netconf_get_target(xn, "source")) == NULL){
xml_parse_va(xret, NULL, "<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>");
goto ok;
}
if ((target = netconf_get_target(xn, "target")) == NULL){
xml_parse_va(xret, NULL, "<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>");
goto ok;
}
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
goto done;
ok:
retval = 0;
done:
return retval;
}
/*! Delete configuration
<delete-config>
<target>
<candidate/>
</target>
</delete-config>
Delete a configuration datastore. The <running>
configuration datastore cannot be deleted.
* @param[in] h clicon handle
* @param[in] xn Sub-tree (under xorig) at <rpc>...</rpc> level.
* @param[out] xret Return XML, error or OK
*/
static int
netconf_delete_config(clicon_handle h,
cxobj *xn,
cxobj **xret)
{
char *target; /* filenames */
int retval = -1;
if ((target = netconf_get_target(xn, "target")) == NULL ||
strcmp(target, "running")==0){
xml_parse_va(xret, NULL, "<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>");
goto ok;
}
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
goto done;
ok:
retval = 0;
done:
return retval;
}
/*! Lock a database
<lock>
<target>
<candidate/>
</target>
</lock>
* @param[in] h clicon handle
* @param[in] xn Sub-tree (under xorig) at <rpc>...</rpc> level.
* @param[out] xret Return XML, error or OK
*/
static int
netconf_lock(clicon_handle h,
cxobj *xn,
cxobj **xret)
{
int retval = -1;
char *target;
if ((target = netconf_get_target(xn, "target")) == NULL){
xml_parse_va(xret, NULL, "<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>");
goto ok;
}
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
goto done;
ok:
retval = 0;
done:
return retval;
}
/*! Unlock a database
<unlock>
<target>
<candidate/>
</target>
</unlock>
XXX
* @param[in] h clicon handle
* @param[in] xn Sub-tree (under xorig) at <rpc>...</rpc> level.
* @param[out] xret Return XML, error or OK
*/
static int
netconf_unlock(clicon_handle h,
cxobj *xn,
cxobj **xret)
{
return netconf_lock(h, xn, xret);
}
/*! Get running configuration and device state information
*
*
@ -579,133 +389,6 @@ netconf_get(clicon_handle h,
"<error-info>type</error-info>"
"</rpc-error></rpc-reply>");
}
// ok: /* netconf error is not fatal */
retval = 0;
done:
return retval;
}
/*! Close a (user) session
<close-session/>
* @param[in] xn Sub-tree (under xorig) at <rpc>...</rpc> level.
* @param[out] xret Return XML, error or OK
*/
static int
netconf_close_session(clicon_handle h,
cxobj *xn,
cxobj **xret)
{
int retval = -1;
cc_closed++;
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
goto done;
retval = 0;
done:
return retval;
}
/*! Kill other user sessions
<kill-session>
<session-id>PID</session-id>
</kill-session>
* @param[in] xn Sub-tree (under xorig) at <rpc>...</rpc> level.
* @param[out] xret Return XML, error or OK
*/
static int
netconf_kill_session(clicon_handle h,
cxobj *xn,
cxobj **xret)
{
int retval=-1;
cxobj *xs;
if ((xs = xpath_first(xn, "//session-id")) == NULL){
xml_parse_va(xret, NULL, "<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>");
goto ok;
}
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
goto done;
ok:
retval = 0;
done:
return retval;
}
/*! Check the semantic consistency of candidate
<validate/>
:validate
* @param[in] h clicon handle
* @param[in] xn Sub-tree (under xorig) at <rpc>...</rpc> level.
* @param[out] xret Return XML, error or OK
*/
static int
netconf_validate(clicon_handle h,
cxobj *xn,
cxobj **xret)
{
int retval = -1;
char *target;
if ((target = netconf_get_target(xn, "source")) == NULL){
xml_parse_va(xret, NULL, "<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>");
goto ok;
}
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
goto done;
ok:
retval = 0;
done:
return retval;
}
/*! Commit candidate -> running
<commit/>
:candidate
* @param[in] h clicon handle
* @param[in] xn Sub-tree (under xorig) at <rpc>...</rpc> level.
* @param[out] xret Return XML, error or OK
*/
static int
netconf_commit(clicon_handle h,
cxobj *xn,
cxobj **xret)
{
int retval = -1;
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
goto done;
retval = 0;
done:
return retval;
}
/*! Discard all changes in candidate / revert to running
<discard-changes/>
:candidate
* @param[in] h clicon handle
* @param[in] xn Sub-tree (under xorig) at <rpc>...</rpc> level.
* @param[out] xret Return XML, error or OK
*/
static int
netconf_discard_changes(clicon_handle h,
cxobj *xn,
cxobj **xret)
{
int retval = -1;
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
goto done;
retval = 0;
done:
return retval;
@ -993,9 +676,25 @@ netconf_rpc_dispatch(clicon_handle h,
if (xml_value_set(xa, username) < 0)
goto done;
}
/* Many of these calls are now calling generic clicon_rpc_netconf_xml
* directly, since the validation is generic and done before this place
* in the call. Some call however need extra validation, such as the
* filter parameter to get/get-config and tes- err-opts of edit-config.
*/
xe = NULL;
while ((xe = xml_child_each(xn, xe, CX_ELMNT)) != NULL) {
if (strcmp(xml_name(xe), "get-config") == 0){
if (strcmp(xml_name(xe), "copy-config") == 0 ||
strcmp(xml_name(xe), "delete-config") == 0 ||
strcmp(xml_name(xe), "lock") == 0 ||
strcmp(xml_name(xe), "unlock") == 0 ||
strcmp(xml_name(xe), "kill-session") == 0 ||
strcmp(xml_name(xe), "validate") == 0 || /* :validate */
strcmp(xml_name(xe), "commit") == 0 || /* :candidate */
strcmp(xml_name(xe), "discard-changes") == 0){
if (clicon_rpc_netconf_xml(h, xml_parent(xe), xret, NULL) < 0)
goto done;
}
else if (strcmp(xml_name(xe), "get-config") == 0){
if (netconf_get_config(h, xe, xret) < 0)
goto done;
}
@ -1003,46 +702,13 @@ netconf_rpc_dispatch(clicon_handle h,
if (netconf_edit_config(h, xe, xret) < 0)
goto done;
}
else if (strcmp(xml_name(xe), "copy-config") == 0){
if (netconf_copy_config(h, xe, xret) < 0)
goto done;
}
else if (strcmp(xml_name(xe), "delete-config") == 0){
if (netconf_delete_config(h, xe, xret) < 0)
goto done;
}
else if (strcmp(xml_name(xe), "lock") == 0) {
if (netconf_lock(h, xe, xret) < 0)
goto done;
}
else if (strcmp(xml_name(xe), "unlock") == 0){
if (netconf_unlock(h, xe, xret) < 0)
goto done;
}
else if (strcmp(xml_name(xe), "get") == 0){
if (netconf_get(h, xe, xret) < 0)
goto done;
}
else if (strcmp(xml_name(xe), "close-session") == 0){
if (netconf_close_session(h, xe, xret) < 0)
goto done;
}
else if (strcmp(xml_name(xe), "kill-session") == 0) {
if (netconf_kill_session(h, xe, xret) < 0)
goto done;
}
/* Validate capability :validate */
else if (strcmp(xml_name(xe), "validate") == 0){
if (netconf_validate(h, xe, xret) < 0)
goto done;
}
/* Candidate configuration capability :candidate */
else if (strcmp(xml_name(xe), "commit") == 0){
if (netconf_commit(h, xe, xret) < 0)
goto done;
}
else if (strcmp(xml_name(xe), "discard-changes") == 0){
if (netconf_discard_changes(h, xe, xret) < 0)
cc_closed++;
if (clicon_rpc_netconf_xml(h, xml_parent(xe), xret, NULL) < 0)
goto done;
}
/* RFC 5277 :notification */