* Netconf message-id attribute changed from optional to mandatory
* Made NETCONF message handling more strict according to RFC 6241 * Set `CLICON_NETCONF_MESSAGE_ID_OPTIONAL` to true to accept omission of message-id attribute * Fixed: [need make sure message-id exist in rpc validate #240](https://github.com/clicon/clixon/issues/240)
This commit is contained in:
parent
96c9296056
commit
85e2945ec9
22 changed files with 196 additions and 89 deletions
10
CHANGELOG.md
10
CHANGELOG.md
|
|
@ -57,6 +57,10 @@ Expected: June 2021
|
||||||
|
|
||||||
Users may have to change how they access the system
|
Users may have to change how they access the system
|
||||||
|
|
||||||
|
* Netconf message-id attribute changed from optional to mandatory
|
||||||
|
* Made NETCONF message handling more strict according to RFC 6241
|
||||||
|
* Set `CLICON_NETCONF_MESSAGE_ID_OPTIONAL` to true to accept omission of message-id attribute
|
||||||
|
* See also [need make sure message-id exist in rpc validate #240](https://github.com/clicon/clixon/issues/240)
|
||||||
* Changed config and install options for Restconf
|
* Changed config and install options for Restconf
|
||||||
* clixon_restconf daemon is installed in /usr/local/sbin (as clixon_backend), instead of /www-data
|
* clixon_restconf daemon is installed in /usr/local/sbin (as clixon_backend), instead of /www-data
|
||||||
* `configure --with-wwwdir=<dir>` remains but only applies to fcgi socket and log
|
* `configure --with-wwwdir=<dir>` remains but only applies to fcgi socket and log
|
||||||
|
|
@ -64,11 +68,13 @@ Users may have to change how they access the system
|
||||||
* Restconf drop privileges user is defined by `CLICON_RESTCONF_USER`
|
* Restconf drop privileges user is defined by `CLICON_RESTCONF_USER`
|
||||||
* `configure --with-wwwuser=<user>` is removed
|
* `configure --with-wwwuser=<user>` is removed
|
||||||
* clixon_restconf drop of privileges is defined by `CLICON_RESTCONF_PRIVILEGES` option
|
* clixon_restconf drop of privileges is defined by `CLICON_RESTCONF_PRIVILEGES` option
|
||||||
* New clixon-config@2020-05-20.yang revision
|
* New clixon-config@2021-05-20.yang revision
|
||||||
* Added: `CLICON_RESTCONF_USER`
|
* Added: `CLICON_RESTCONF_USER`
|
||||||
* Added: `CLICON_RESTCONF_PRIVILEGES`
|
* Added: `CLICON_RESTCONF_PRIVILEGES`
|
||||||
* Added: `CLICON_RESTCONF_INSTALLDIR`
|
* Added: `CLICON_RESTCONF_INSTALLDIR`
|
||||||
* Added: `CLICON_RESTCONF_STARTUP_DONTUPDATE`
|
* Added: `CLICON_RESTCONF_STARTUP_DONTUPDATE`
|
||||||
|
* Added: `CLICON_RESTCONF_STARTUP_DONTUPDATE`
|
||||||
|
* Added: `CLICON_NETCONF_MESSAGE_ID_OPTIONAL`
|
||||||
* New clixon-restconf@2020-05-20.yang revision
|
* New clixon-restconf@2020-05-20.yang revision
|
||||||
* Added: restconf `log-destination`
|
* Added: restconf `log-destination`
|
||||||
* RESTCONF error replies have changed
|
* RESTCONF error replies have changed
|
||||||
|
|
@ -110,6 +116,8 @@ Developers may need to change their code
|
||||||
|
|
||||||
### Corrected Bugs
|
### Corrected Bugs
|
||||||
|
|
||||||
|
* Fixed: [need make sure message-id exist in rpc validate #240](https://github.com/clicon/clixon/issues/240)
|
||||||
|
* Netconf message-id attribute changed from optional to mandatory (see API changes)
|
||||||
* Fixed: [restconf patch method unable to chage value to empty string #229](https://github.com/clicon/clixon/issues/229)
|
* Fixed: [restconf patch method unable to chage value to empty string #229](https://github.com/clicon/clixon/issues/229)
|
||||||
* Fixed: [restconf patch method adds redundant namespaces #235](https://github.com/clicon/clixon/issues/235)
|
* Fixed: [restconf patch method adds redundant namespaces #235](https://github.com/clicon/clixon/issues/235)
|
||||||
* Fixed: Restconf HEAD did not work everywhere GET did, such as well-known and exact root.
|
* Fixed: Restconf HEAD did not work everywhere GET did, such as well-known and exact root.
|
||||||
|
|
|
||||||
|
|
@ -747,11 +747,6 @@ main(int argc,
|
||||||
clicon_configfile(h));
|
clicon_configfile(h));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Treat unknown XML as anydata */
|
|
||||||
if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
|
|
||||||
xml_bind_yang_unknown_anydata(1);
|
|
||||||
|
|
||||||
/* Publish stream on pubsub channels.
|
/* Publish stream on pubsub channels.
|
||||||
* CLICON_STREAM_PUB should be set to URL to where streams are published
|
* CLICON_STREAM_PUB should be set to URL to where streams are published
|
||||||
* and configure should be run with --enable-publish
|
* and configure should be run with --enable-publish
|
||||||
|
|
|
||||||
|
|
@ -635,11 +635,6 @@ main(int argc,
|
||||||
goto done;
|
goto done;
|
||||||
/* Set default namespace according to CLICON_NAMESPACE_NETCONF_DEFAULT */
|
/* Set default namespace according to CLICON_NAMESPACE_NETCONF_DEFAULT */
|
||||||
xml_nsctx_namespace_netconf_default(h);
|
xml_nsctx_namespace_netconf_default(h);
|
||||||
|
|
||||||
/* Treat unknwon XML as anydata */
|
|
||||||
if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
|
|
||||||
xml_bind_yang_unknown_anydata(1);
|
|
||||||
|
|
||||||
/* Create top-level and store as option */
|
/* Create top-level and store as option */
|
||||||
if ((yspec = yspec_new()) == NULL)
|
if ((yspec = yspec_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -495,8 +495,8 @@ cli_show_config1(clicon_handle h,
|
||||||
cli_xml2cli(xc, prefix, gt, cligen_output); /* cli syntax */
|
cli_xml2cli(xc, prefix, gt, cligen_output); /* cli syntax */
|
||||||
break;
|
break;
|
||||||
case FORMAT_NETCONF:
|
case FORMAT_NETCONF:
|
||||||
cligen_output(stdout, "<rpc xmlns=\"%s\"><edit-config><target><candidate/></target><config>\n",
|
cligen_output(stdout, "<rpc xmlns=\"%s\" %s><edit-config><target><candidate/></target><config>\n",
|
||||||
NETCONF_BASE_NAMESPACE);
|
NETCONF_BASE_NAMESPACE, NETCONF_MESSAGE_ID_ATTR);
|
||||||
xc = NULL; /* Dont print xt itself */
|
xc = NULL; /* Dont print xt itself */
|
||||||
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
|
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
|
||||||
cli_xml2file(xc, 2, 1, cligen_output);
|
cli_xml2file(xc, 2, 1, cligen_output);
|
||||||
|
|
|
||||||
|
|
@ -375,10 +375,6 @@ main(int argc,
|
||||||
if ((yspec = yspec_new()) == NULL)
|
if ((yspec = yspec_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_dbspec_yang_set(h, yspec);
|
clicon_dbspec_yang_set(h, yspec);
|
||||||
/* Treat unknown XML as anydata */
|
|
||||||
if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
|
|
||||||
xml_bind_yang_unknown_anydata(1);
|
|
||||||
|
|
||||||
/* Initialize plugin module by creating a handle holding plugin and callback lists */
|
/* Initialize plugin module by creating a handle holding plugin and callback lists */
|
||||||
if (clixon_plugin_module_init(h) < 0)
|
if (clixon_plugin_module_init(h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -1687,10 +1687,6 @@ restconf_clixon_init(clicon_handle h,
|
||||||
if ((yspec = yspec_new()) == NULL)
|
if ((yspec = yspec_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_dbspec_yang_set(h, yspec);
|
clicon_dbspec_yang_set(h, yspec);
|
||||||
/* Treat unknown XML as anydata */
|
|
||||||
if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
|
|
||||||
xml_bind_yang_unknown_anydata(1);
|
|
||||||
|
|
||||||
/* Load restconf plugins before yangs are loaded (eg extension callbacks) */
|
/* Load restconf plugins before yangs are loaded (eg extension callbacks) */
|
||||||
if ((dir = clicon_restconf_dir(h)) != NULL)
|
if ((dir = clicon_restconf_dir(h)) != NULL)
|
||||||
if (clixon_plugins_load(h, CLIXON_PLUGIN_INIT, dir, NULL) < 0)
|
if (clixon_plugins_load(h, CLIXON_PLUGIN_INIT, dir, NULL) < 0)
|
||||||
|
|
|
||||||
|
|
@ -513,11 +513,12 @@ api_data_write(clicon_handle h,
|
||||||
/* Create text buffer for transfer to backend */
|
/* Create text buffer for transfer to backend */
|
||||||
if ((cbx = cbuf_new()) == NULL)
|
if ((cbx = cbuf_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
cprintf(cbx, "<rpc xmlns=\"%s\" username=\"%s\" xmlns:%s=\"%s\">",
|
cprintf(cbx, "<rpc xmlns=\"%s\" username=\"%s\" xmlns:%s=\"%s\" %s>",
|
||||||
NETCONF_BASE_NAMESPACE,
|
NETCONF_BASE_NAMESPACE,
|
||||||
username?username:"",
|
username?username:"",
|
||||||
NETCONF_BASE_PREFIX,
|
NETCONF_BASE_PREFIX,
|
||||||
NETCONF_BASE_NAMESPACE); /* bind nc to netconf namespace */
|
NETCONF_BASE_NAMESPACE, /* bind nc to netconf namespace */
|
||||||
|
NETCONF_MESSAGE_ID_ATTR);
|
||||||
cprintf(cbx, "<edit-config");
|
cprintf(cbx, "<edit-config");
|
||||||
/* RFC8040 Sec 1.4:
|
/* RFC8040 Sec 1.4:
|
||||||
* If this is a "data" request and the NETCONF server supports :startup,
|
* If this is a "data" request and the NETCONF server supports :startup,
|
||||||
|
|
@ -753,11 +754,12 @@ api_data_delete(clicon_handle h,
|
||||||
/* For internal XML protocol: add username attribute for access control
|
/* For internal XML protocol: add username attribute for access control
|
||||||
*/
|
*/
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
cprintf(cbx, "<rpc xmlns=\"%s\" username=\"%s\" xmlns:%s=\"%s\">",
|
cprintf(cbx, "<rpc xmlns=\"%s\" username=\"%s\" xmlns:%s=\"%s\" %s>",
|
||||||
NETCONF_BASE_NAMESPACE,
|
NETCONF_BASE_NAMESPACE,
|
||||||
username?username:"",
|
username?username:"",
|
||||||
NETCONF_BASE_PREFIX,
|
NETCONF_BASE_PREFIX,
|
||||||
NETCONF_BASE_NAMESPACE); /* bind nc to netconf namespace */
|
NETCONF_BASE_NAMESPACE,
|
||||||
|
NETCONF_MESSAGE_ID_ATTR); /* bind nc to netconf namespace */
|
||||||
|
|
||||||
cprintf(cbx, "<edit-config");
|
cprintf(cbx, "<edit-config");
|
||||||
/* RFC8040 Sec 1.4:
|
/* RFC8040 Sec 1.4:
|
||||||
|
|
|
||||||
|
|
@ -336,11 +336,12 @@ api_data_post(clicon_handle h,
|
||||||
/* For internal XML protocol: add username attribute for access control
|
/* For internal XML protocol: add username attribute for access control
|
||||||
*/
|
*/
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
cprintf(cbx, "<rpc xmlns=\"%s\" username=\"%s\" xmlns:%s=\"%s\">",
|
cprintf(cbx, "<rpc xmlns=\"%s\" username=\"%s\" xmlns:%s=\"%s\" %s>",
|
||||||
NETCONF_BASE_NAMESPACE,
|
NETCONF_BASE_NAMESPACE,
|
||||||
username?username:"",
|
username?username:"",
|
||||||
NETCONF_BASE_PREFIX,
|
NETCONF_BASE_PREFIX,
|
||||||
NETCONF_BASE_NAMESPACE); /* bind nc to netconf namespace */
|
NETCONF_BASE_NAMESPACE,
|
||||||
|
NETCONF_MESSAGE_ID_ATTR); /* bind nc to netconf namespace */
|
||||||
|
|
||||||
cprintf(cbx, "<edit-config");
|
cprintf(cbx, "<edit-config");
|
||||||
/* RFC8040 Sec 1.4:
|
/* RFC8040 Sec 1.4:
|
||||||
|
|
@ -755,13 +756,13 @@ api_operations_post(clicon_handle h,
|
||||||
* <rpc username="foo"><myfn xmlns="uri"/>
|
* <rpc username="foo"><myfn xmlns="uri"/>
|
||||||
*/
|
*/
|
||||||
if ((username = clicon_username_get(h)) != NULL){
|
if ((username = clicon_username_get(h)) != NULL){
|
||||||
if (clixon_xml_parse_va(YB_NONE, NULL, &xtop, NULL, "<rpc xmlns=\"%s\" username=\"%s\"/>",
|
if (clixon_xml_parse_va(YB_NONE, NULL, &xtop, NULL, "<rpc xmlns=\"%s\" username=\"%s\" %s/>",
|
||||||
NETCONF_BASE_NAMESPACE, username) < 0)
|
NETCONF_BASE_NAMESPACE, username, NETCONF_MESSAGE_ID_ATTR) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (clixon_xml_parse_va(YB_NONE, NULL, &xtop, NULL, "<rpc xmlns=\"%s\"/>",
|
if (clixon_xml_parse_va(YB_NONE, NULL, &xtop, NULL, "<rpc xmlns=\"%s\" %s/>",
|
||||||
NETCONF_BASE_NAMESPACE) < 0)
|
NETCONF_BASE_NAMESPACE, NETCONF_MESSAGE_ID_ATTR) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xml_rootchild(xtop, 0, &xtop) < 0)
|
if (xml_rootchild(xtop, 0, &xtop) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -269,8 +269,8 @@ restconf_stream(clicon_handle h,
|
||||||
clicon_err(OE_XML, errno, "cbuf_new");
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cprintf(cb, "<rpc xmlns=\"%s\"><create-subscription xmlns=\"%s\"><stream>%s</stream>",
|
cprintf(cb, "<rpc xmlns=\"%s\" %s><create-subscription xmlns=\"%s\"><stream>%s</stream>",
|
||||||
NETCONF_BASE_NAMESPACE, EVENT_RFC5277_NAMESPACE, name);
|
NETCONF_BASE_NAMESPACE, NETCONF_MESSAGE_ID_ATTR, EVENT_RFC5277_NAMESPACE, name);
|
||||||
/* Print all fields */
|
/* Print all fields */
|
||||||
for (i=0; i<cvec_len(qvec); i++){
|
for (i=0; i<cvec_len(qvec); i++){
|
||||||
cv = cvec_i(qvec, i);
|
cv = cvec_i(qvec, i);
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,10 @@
|
||||||
#define NETCONF_BASE_NAMESPACE "urn:ietf:params:xml:ns:netconf:base:1.0"
|
#define NETCONF_BASE_NAMESPACE "urn:ietf:params:xml:ns:netconf:base:1.0"
|
||||||
#define NETCONF_BASE_PREFIX "nc"
|
#define NETCONF_BASE_PREFIX "nc"
|
||||||
|
|
||||||
|
/* In cases where message-id is not given by external client, use this */
|
||||||
|
#define NETCONF_MESSAGE_ID_DEFAULT "42"
|
||||||
|
#define NETCONF_MESSAGE_ID_ATTR "message-id=\"42\""
|
||||||
|
|
||||||
/* Netconf base capability as defined in RFC4741, Sec 8.1
|
/* Netconf base capability as defined in RFC4741, Sec 8.1
|
||||||
*/
|
*/
|
||||||
#define NETCONF_BASE_CAPABILITY_1_0 "urn:ietf:params:netconf:base:1.0"
|
#define NETCONF_BASE_CAPABILITY_1_0 "urn:ietf:params:netconf:base:1.0"
|
||||||
|
|
@ -97,6 +101,7 @@ 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);
|
||||||
int netconf_too_big(cbuf *cb, char *type, char *message);
|
int netconf_too_big(cbuf *cb, char *type, char *message);
|
||||||
int netconf_missing_attribute(cbuf *cb, char *type, char *info, char *message);
|
int netconf_missing_attribute(cbuf *cb, char *type, char *info, char *message);
|
||||||
|
int netconf_missing_attribute_xml(cxobj **xret, char *type, char *info, char *message);
|
||||||
int netconf_bad_attribute(cbuf *cb, char *type, char *info, char *message);
|
int netconf_bad_attribute(cbuf *cb, char *type, char *info, char *message);
|
||||||
int netconf_bad_attribute_xml(cxobj **xret, char *type, char *info, char *message);
|
int netconf_bad_attribute_xml(cxobj **xret, char *type, char *info, char *message);
|
||||||
int netconf_unknown_attribute(cbuf *cb, char *type, char *info, char *message);
|
int netconf_unknown_attribute(cbuf *cb, char *type, char *info, char *message);
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
int xml_bind_yang_unknown_anydata(int val);
|
int xml_bind_yang_unknown_anydata(int val);
|
||||||
|
int xml_bind_netconf_message_id_optional(int val);
|
||||||
int xml_bind_yang_rpc(cxobj *xrpc, yang_stmt *yspec, cxobj **xerr);
|
int xml_bind_yang_rpc(cxobj *xrpc, yang_stmt *yspec, cxobj **xerr);
|
||||||
int xml_bind_yang_rpc_reply(cxobj *xrpc, char *name, yang_stmt *yspec, cxobj **xerr);
|
int xml_bind_yang_rpc_reply(cxobj *xrpc, char *name, yang_stmt *yspec, cxobj **xerr);
|
||||||
int xml_bind_yang0(cxobj *xt, yang_bind yb, yang_stmt *yspec, cxobj **xerr);
|
int xml_bind_yang0(cxobj *xt, yang_bind yb, yang_stmt *yspec, cxobj **xerr);
|
||||||
|
|
|
||||||
|
|
@ -170,9 +170,10 @@ clixon_client_lock(int sock,
|
||||||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cprintf(msg, "<rpc xmlns=\"%s\">"
|
cprintf(msg, "<rpc xmlns=\"%s\" %s>"
|
||||||
"<%slock><target><%s/></target></%slock></rpc>",
|
"<%slock><target><%s/></target></%slock></rpc>",
|
||||||
NETCONF_BASE_NAMESPACE,
|
NETCONF_BASE_NAMESPACE,
|
||||||
|
NETCONF_MESSAGE_ID_ATTR,
|
||||||
lock?"":"un", db, lock?"":"un");
|
lock?"":"un", db, lock?"":"un");
|
||||||
if (clicon_rpc1(sock, msg, msgret) < 0)
|
if (clicon_rpc1(sock, msg, msgret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -422,6 +423,7 @@ clixon_client_get_xdata(int sock,
|
||||||
cprintf(msg, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
|
cprintf(msg, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
|
||||||
cprintf(msg, " xmlns:%s=\"%s\"",
|
cprintf(msg, " xmlns:%s=\"%s\"",
|
||||||
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
|
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
|
||||||
|
cprintf(msg, " %s", NETCONF_MESSAGE_ID_ATTR);
|
||||||
cprintf(msg, "><get-config><source><%s/></source>", db);
|
cprintf(msg, "><get-config><source><%s/></source>", db);
|
||||||
if (xpath && strlen(xpath)){
|
if (xpath && strlen(xpath)){
|
||||||
cprintf(msg, "<%s:filter %s:type=\"xpath\" xmlns=\"%s\" %s:select=\"%s\"",
|
cprintf(msg, "<%s:filter %s:type=\"xpath\" xmlns=\"%s\" %s:select=\"%s\"",
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
#include "clixon_data.h"
|
#include "clixon_data.h"
|
||||||
|
#include "clixon_xml_bind.h"
|
||||||
#include "clixon_xml_map.h"
|
#include "clixon_xml_map.h"
|
||||||
#include "clixon_xml_io.h"
|
#include "clixon_xml_io.h"
|
||||||
#include "clixon_xpath_ctx.h"
|
#include "clixon_xpath_ctx.h"
|
||||||
|
|
@ -228,44 +229,82 @@ netconf_too_big(cbuf *cb,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Create Netconf missing-attribute error XML tree according to RFC 6241 App A
|
||||||
|
*
|
||||||
|
* An expected attribute is missing.
|
||||||
|
* @param[out] xret Error XML tree. Free with xml_free after use
|
||||||
|
* @param[in] type Error type: "rpc", "application" or "protocol"
|
||||||
|
* @param[in] attr bad-attribute and/or bad-element xml
|
||||||
|
* @param[in] message Error message (will be XML encoded)
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
netconf_missing_attribute_xml(cxobj **xret,
|
||||||
|
char *type,
|
||||||
|
char *attr,
|
||||||
|
char *message)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *xerr = NULL;
|
||||||
|
char *encstr = NULL;
|
||||||
|
cxobj *xa;
|
||||||
|
|
||||||
|
if (*xret == NULL){
|
||||||
|
if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else if (xml_name_set(*xret, "rpc-reply") < 0)
|
||||||
|
goto done;
|
||||||
|
if ((xa = xml_new("xmlns", *xret, CX_ATTR)) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (xml_value_set(xa, NETCONF_BASE_NAMESPACE) < 0)
|
||||||
|
goto done;
|
||||||
|
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-type>%s</error-type>"
|
||||||
|
"<error-tag>missing-attribute</error-tag>"
|
||||||
|
"<error-info><bad-attribute>%s</bad-attribute></error-info>"
|
||||||
|
"<error-severity>error</error-severity>", type, attr) < 0)
|
||||||
|
goto done;
|
||||||
|
if (message){
|
||||||
|
if (xml_chardata_encode(&encstr, "%s", message) < 0)
|
||||||
|
goto done;
|
||||||
|
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-message>%s</error-message>",
|
||||||
|
encstr) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (encstr)
|
||||||
|
free(encstr);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Create Netconf missing-attribute error XML tree according to RFC 6241 App A
|
/*! Create Netconf missing-attribute error XML tree according to RFC 6241 App A
|
||||||
*
|
*
|
||||||
* An expected attribute is missing.
|
* An expected attribute is missing.
|
||||||
* @param[out] cb CLIgen buf. Error XML is written in this buffer
|
* @param[out] cb CLIgen buf. Error XML is written in this buffer
|
||||||
* @param[in] type Error type: "rpc", "application" or "protocol"
|
* @param[in] type Error type: "rpc", "application" or "protocol"
|
||||||
* @param[in] info bad-attribute or bad-element xml
|
* @param[in] attr bad-attribute
|
||||||
* @param[in] message Error message (will be XML encoded)
|
* @param[in] message Error message (will be XML encoded) or NULL
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
netconf_missing_attribute(cbuf *cb,
|
netconf_missing_attribute(cbuf *cb,
|
||||||
char *type,
|
char *type,
|
||||||
char *info,
|
char *attr,
|
||||||
char *message)
|
char *message)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *encstr = NULL;
|
cxobj *xret = NULL;
|
||||||
|
|
||||||
if (cprintf(cb, "<rpc-reply xmlns=\"%s\"><rpc-error>"
|
if (netconf_missing_attribute_xml(&xret, type, attr, message) < 0)
|
||||||
"<error-type>%s</error-type>"
|
goto done;
|
||||||
"<error-tag>missing-attribute</error-tag>"
|
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
|
||||||
"<error-info>%s</error-info>"
|
|
||||||
"<error-severity>error</error-severity>",
|
|
||||||
NETCONF_BASE_NAMESPACE, type, info) <0)
|
|
||||||
goto err;
|
|
||||||
if (message){
|
|
||||||
if (xml_chardata_encode(&encstr, "%s", message) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
if (cprintf(cb, "<error-message>%s</error-message>", encstr) < 0)
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
if (cprintf(cb, "</rpc-error></rpc-reply>") <0)
|
|
||||||
goto err;
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (xret)
|
||||||
|
xml_free(xret);
|
||||||
return retval;
|
return retval;
|
||||||
err:
|
|
||||||
clicon_err(OE_XML, errno, "cprintf");
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Create Netconf bad-attribute error XML tree according to RFC 6241 App A
|
/*! Create Netconf bad-attribute error XML tree according to RFC 6241 App A
|
||||||
|
|
@ -1429,6 +1468,16 @@ netconf_module_load(clicon_handle h)
|
||||||
/* Load restconf yang. Note this is also a part of clixon-config */
|
/* Load restconf yang. Note this is also a part of clixon-config */
|
||||||
if (yang_spec_parse_module(h, "clixon-restconf", NULL, yspec)< 0)
|
if (yang_spec_parse_module(h, "clixon-restconf", NULL, yspec)< 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
#if 1
|
||||||
|
/* XXX: Both the following settings are because clicon-handle is not part of all API
|
||||||
|
* functions
|
||||||
|
* Treat unknown XML as anydata */
|
||||||
|
if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
|
||||||
|
xml_bind_yang_unknown_anydata(1);
|
||||||
|
/* Make message-id attribute optional */
|
||||||
|
if (clicon_option_bool(h, "CLICON_NETCONF_MESSAGE_ID_OPTIONAL") == 1)
|
||||||
|
xml_bind_netconf_message_id_optional(1);
|
||||||
|
#endif
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
||||||
|
|
@ -451,6 +451,7 @@ clicon_rpc_get_config(clicon_handle h,
|
||||||
cprintf(cb, " username=\"%s\"", username);
|
cprintf(cb, " username=\"%s\"", username);
|
||||||
cprintf(cb, " xmlns:%s=\"%s\"",
|
cprintf(cb, " xmlns:%s=\"%s\"",
|
||||||
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
|
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
|
||||||
|
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR);
|
||||||
cprintf(cb, "><get-config><source><%s/></source>", db);
|
cprintf(cb, "><get-config><source><%s/></source>", db);
|
||||||
if (xpath && strlen(xpath)){
|
if (xpath && strlen(xpath)){
|
||||||
cprintf(cb, "<%s:filter %s:type=\"xpath\" %s:select=\"%s\"",
|
cprintf(cb, "<%s:filter %s:type=\"xpath\" %s:select=\"%s\"",
|
||||||
|
|
@ -541,6 +542,7 @@ clicon_rpc_edit_config(clicon_handle h,
|
||||||
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
|
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
|
||||||
if ((username = clicon_username_get(h)) != NULL)
|
if ((username = clicon_username_get(h)) != NULL)
|
||||||
cprintf(cb, " username=\"%s\"", username);
|
cprintf(cb, " username=\"%s\"", username);
|
||||||
|
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR);
|
||||||
cprintf(cb, "><edit-config><target><%s/></target>", db);
|
cprintf(cb, "><edit-config><target><%s/></target>", db);
|
||||||
cprintf(cb, "<default-operation>%s</default-operation>",
|
cprintf(cb, "<default-operation>%s</default-operation>",
|
||||||
xml_operation2str(op));
|
xml_operation2str(op));
|
||||||
|
|
@ -595,10 +597,11 @@ clicon_rpc_copy_config(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
if ((msg = clicon_msg_encode(session_id,
|
if ((msg = clicon_msg_encode(session_id,
|
||||||
"<rpc xmlns=\"%s\" username=\"%s\">"
|
"<rpc xmlns=\"%s\" username=\"%s\" %s>"
|
||||||
"<copy-config><source><%s/></source><target><%s/></target></copy-config></rpc>",
|
"<copy-config><source><%s/></source><target><%s/></target></copy-config></rpc>",
|
||||||
NETCONF_BASE_NAMESPACE,
|
NETCONF_BASE_NAMESPACE,
|
||||||
username?username:"",
|
username?username:"",
|
||||||
|
NETCONF_MESSAGE_ID_ATTR,
|
||||||
db1, db2)) == NULL)
|
db1, db2)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||||
|
|
@ -641,10 +644,12 @@ clicon_rpc_delete_config(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
if ((msg = clicon_msg_encode(session_id,
|
if ((msg = clicon_msg_encode(session_id,
|
||||||
"<rpc xmlns=\"%s\" username=\"%s\">"
|
"<rpc xmlns=\"%s\" username=\"%s\" %s>"
|
||||||
"<edit-config><target><%s/></target><default-operation>none</default-operation><config operation=\"delete\"/></edit-config></rpc>",
|
"<edit-config><target><%s/></target><default-operation>none</default-operation><config operation=\"delete\"/></edit-config></rpc>",
|
||||||
NETCONF_BASE_NAMESPACE,
|
NETCONF_BASE_NAMESPACE,
|
||||||
username?username:"", db)) == NULL)
|
username?username:"",
|
||||||
|
NETCONF_MESSAGE_ID_ATTR,
|
||||||
|
db)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -682,10 +687,12 @@ clicon_rpc_lock(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
if ((msg = clicon_msg_encode(session_id,
|
if ((msg = clicon_msg_encode(session_id,
|
||||||
"<rpc xmlns=\"%s\" username=\"%s\">"
|
"<rpc xmlns=\"%s\" username=\"%s\" %s>"
|
||||||
"<lock><target><%s/></target></lock></rpc>",
|
"<lock><target><%s/></target></lock></rpc>",
|
||||||
NETCONF_BASE_NAMESPACE,
|
NETCONF_BASE_NAMESPACE,
|
||||||
username?username:"", db)) == NULL)
|
username?username:"",
|
||||||
|
NETCONF_MESSAGE_ID_ATTR,
|
||||||
|
db)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -723,10 +730,12 @@ clicon_rpc_unlock(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
if ((msg = clicon_msg_encode(session_id,
|
if ((msg = clicon_msg_encode(session_id,
|
||||||
"<rpc xmlns=\"%s\" username=\"%s\">"
|
"<rpc xmlns=\"%s\" username=\"%s\" %s>"
|
||||||
"<unlock><target><%s/></target></unlock></rpc>",
|
"<unlock><target><%s/></target></unlock></rpc>",
|
||||||
NETCONF_BASE_NAMESPACE,
|
NETCONF_BASE_NAMESPACE,
|
||||||
username?username:"", db)) == NULL)
|
username?username:"",
|
||||||
|
NETCONF_MESSAGE_ID_ATTR,
|
||||||
|
db)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -805,6 +814,7 @@ clicon_rpc_get(clicon_handle h,
|
||||||
cprintf(cb, " username=\"%s\"", username);
|
cprintf(cb, " username=\"%s\"", username);
|
||||||
cprintf(cb, " xmlns:%s=\"%s\"",
|
cprintf(cb, " xmlns:%s=\"%s\"",
|
||||||
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
|
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
|
||||||
|
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR);
|
||||||
cprintf(cb, "><get");
|
cprintf(cb, "><get");
|
||||||
/* Clixon extension, content=all,config, or nonconfig */
|
/* Clixon extension, content=all,config, or nonconfig */
|
||||||
if ((int)content != -1)
|
if ((int)content != -1)
|
||||||
|
|
@ -889,8 +899,9 @@ clicon_rpc_close_session(clicon_handle h)
|
||||||
goto done;
|
goto done;
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
if ((msg = clicon_msg_encode(session_id,
|
if ((msg = clicon_msg_encode(session_id,
|
||||||
"<rpc xmlns=\"%s\" username=\"%s\" message-id=\"%u\"><close-session/></rpc>",
|
"<rpc xmlns=\"%s\" username=\"%s\" %s><close-session/></rpc>",
|
||||||
NETCONF_BASE_NAMESPACE, username?username:"", 42)) == NULL)
|
NETCONF_BASE_NAMESPACE, username?username:"",
|
||||||
|
NETCONF_MESSAGE_ID_ATTR)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -932,9 +943,11 @@ clicon_rpc_kill_session(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
if ((msg = clicon_msg_encode(my_session_id,
|
if ((msg = clicon_msg_encode(my_session_id,
|
||||||
"<rpc xmlns=\"%s\" username=\"%s\"><kill-session><session-id>%u</session-id></kill-session></rpc>",
|
"<rpc xmlns=\"%s\" username=\"%s\" %s><kill-session><session-id>%u</session-id></kill-session></rpc>",
|
||||||
NETCONF_BASE_NAMESPACE,
|
NETCONF_BASE_NAMESPACE,
|
||||||
username?username:"", session_id)) == NULL)
|
username?username:"",
|
||||||
|
NETCONF_MESSAGE_ID_ATTR,
|
||||||
|
session_id)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -972,9 +985,11 @@ clicon_rpc_validate(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
if ((msg = clicon_msg_encode(session_id,
|
if ((msg = clicon_msg_encode(session_id,
|
||||||
"<rpc xmlns=\"%s\" username=\"%s\"><validate><source><%s/></source></validate></rpc>",
|
"<rpc xmlns=\"%s\" username=\"%s\" %s><validate><source><%s/></source></validate></rpc>",
|
||||||
NETCONF_BASE_NAMESPACE,
|
NETCONF_BASE_NAMESPACE,
|
||||||
username?username:"", db)) == NULL)
|
username?username:"",
|
||||||
|
NETCONF_MESSAGE_ID_ATTR,
|
||||||
|
db)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1010,9 +1025,10 @@ clicon_rpc_commit(clicon_handle h)
|
||||||
goto done;
|
goto done;
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
if ((msg = clicon_msg_encode(session_id,
|
if ((msg = clicon_msg_encode(session_id,
|
||||||
"<rpc xmlns=\"%s\" username=\"%s\"><commit/></rpc>",
|
"<rpc xmlns=\"%s\" username=\"%s\" %s><commit/></rpc>",
|
||||||
NETCONF_BASE_NAMESPACE,
|
NETCONF_BASE_NAMESPACE,
|
||||||
username?username:"")) == NULL)
|
username?username:"",
|
||||||
|
NETCONF_MESSAGE_ID_ATTR)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1048,9 +1064,10 @@ clicon_rpc_discard_changes(clicon_handle h)
|
||||||
goto done;
|
goto done;
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
if ((msg = clicon_msg_encode(session_id,
|
if ((msg = clicon_msg_encode(session_id,
|
||||||
"<rpc xmlns=\"%s\" username=\"%s\"><discard-changes/></rpc>",
|
"<rpc xmlns=\"%s\" username=\"%s\" %s><discard-changes/></rpc>",
|
||||||
NETCONF_BASE_NAMESPACE,
|
NETCONF_BASE_NAMESPACE,
|
||||||
username?username:"")) == NULL)
|
username?username:"",
|
||||||
|
NETCONF_MESSAGE_ID_ATTR)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1094,12 +1111,13 @@ clicon_rpc_create_subscription(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
if ((msg = clicon_msg_encode(session_id,
|
if ((msg = clicon_msg_encode(session_id,
|
||||||
"<rpc xmlns=\"%s\" username=\"%s\"><create-subscription xmlns=\"%s\">"
|
"<rpc xmlns=\"%s\" username=\"%s\" %s><create-subscription xmlns=\"%s\">"
|
||||||
"<stream>%s</stream>"
|
"<stream>%s</stream>"
|
||||||
"<filter type=\"xpath\" select=\"%s\" />"
|
"<filter type=\"xpath\" select=\"%s\" />"
|
||||||
"</create-subscription></rpc>",
|
"</create-subscription></rpc>",
|
||||||
NETCONF_BASE_NAMESPACE,
|
NETCONF_BASE_NAMESPACE,
|
||||||
username?username:"",
|
username?username:"",
|
||||||
|
NETCONF_MESSAGE_ID_ATTR,
|
||||||
EVENT_RFC5277_NAMESPACE,
|
EVENT_RFC5277_NAMESPACE,
|
||||||
stream?stream:"", filter?filter:"")) == NULL)
|
stream?stream:"", filter?filter:"")) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1139,9 +1157,10 @@ clicon_rpc_debug(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
if ((msg = clicon_msg_encode(session_id,
|
if ((msg = clicon_msg_encode(session_id,
|
||||||
"<rpc xmlns=\"%s\" username=\"%s\"><debug xmlns=\"%s\"><level>%d</level></debug></rpc>",
|
"<rpc xmlns=\"%s\" username=\"%s\" %s><debug xmlns=\"%s\"><level>%d</level></debug></rpc>",
|
||||||
NETCONF_BASE_NAMESPACE,
|
NETCONF_BASE_NAMESPACE,
|
||||||
username?username:"",
|
username?username:"",
|
||||||
|
NETCONF_MESSAGE_ID_ATTR,
|
||||||
CLIXON_LIB_NS,
|
CLIXON_LIB_NS,
|
||||||
level)) == NULL)
|
level)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1189,9 +1208,10 @@ clicon_rpc_restconf_debug(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
if ((msg = clicon_msg_encode(session_id,
|
if ((msg = clicon_msg_encode(session_id,
|
||||||
"<rpc xmlns=\"%s\" username=\"%s\"><edit-config><target><candidate/></target><config><restconf xmlns=\"%s\"><debug>%d</debug></restconf></config></edit-config></rpc>",
|
"<rpc xmlns=\"%s\" username=\"%s\" %s><edit-config><target><candidate/></target><config><restconf xmlns=\"%s\"><debug>%d</debug></restconf></config></edit-config></rpc>",
|
||||||
NETCONF_BASE_NAMESPACE,
|
NETCONF_BASE_NAMESPACE,
|
||||||
username?username:"",
|
username?username:"",
|
||||||
|
NETCONF_MESSAGE_ID_ATTR,
|
||||||
CLIXON_RESTCONF_NS,
|
CLIXON_RESTCONF_NS,
|
||||||
level)) == NULL)
|
level)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@
|
||||||
* Local variables
|
* Local variables
|
||||||
*/
|
*/
|
||||||
static int _yang_unknown_anydata = 0;
|
static int _yang_unknown_anydata = 0;
|
||||||
|
static int _netconf_message_id_optional = 0;
|
||||||
|
|
||||||
/*! Kludge to equate unknown XML with anydata
|
/*! Kludge to equate unknown XML with anydata
|
||||||
* The problem with this is that its global and should be bound to a handle
|
* The problem with this is that its global and should be bound to a handle
|
||||||
|
|
@ -94,6 +95,16 @@ xml_bind_yang_unknown_anydata(int val)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Kludge to set message_id_optional
|
||||||
|
* The problem with this is that its global and should be bound to a handle
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_bind_netconf_message_id_optional(int val)
|
||||||
|
{
|
||||||
|
_netconf_message_id_optional = val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*! After yang binding, bodies of containers and lists are stripped from XML bodies
|
/*! After yang binding, bodies of containers and lists are stripped from XML bodies
|
||||||
* May apply to other nodes?
|
* May apply to other nodes?
|
||||||
*/
|
*/
|
||||||
|
|
@ -510,7 +521,7 @@ xml_bind_yang0(cxobj *xt,
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* The
|
* The
|
||||||
* @code
|
* @code
|
||||||
* if (xml_bind_yang_rpc(h, x, NULL) < 0)
|
* if (xml_bind_yang_rpc(x, NULL) < 0)
|
||||||
* err;
|
* err;
|
||||||
* @endcode
|
* @endcode
|
||||||
* @see xml_bind_yang For other generic cases
|
* @see xml_bind_yang For other generic cases
|
||||||
|
|
@ -576,6 +587,17 @@ xml_bind_yang_rpc(cxobj *xrpc,
|
||||||
goto done;
|
goto done;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
if (_netconf_message_id_optional == 0){
|
||||||
|
/* RFC 6241 4.1:
|
||||||
|
* The <rpc> element has a mandatory attribute "message-id"
|
||||||
|
*/
|
||||||
|
if (xml_find_type(xrpc, NULL, "message-id", CX_ATTR) == NULL){
|
||||||
|
if (xerr &&
|
||||||
|
netconf_missing_attribute_xml(xerr, "rpc", "message-id", "Incoming rpc") < 0)
|
||||||
|
goto done;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
x = NULL;
|
x = NULL;
|
||||||
while ((x = xml_child_each(xrpc, x, CX_ELMNT)) != NULL) {
|
while ((x = xml_child_each(xrpc, x, CX_ELMNT)) != NULL) {
|
||||||
rpcname = xml_name(x);
|
rpcname = xml_name(x);
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ new "wait backend"
|
||||||
wait_backend
|
wait_backend
|
||||||
|
|
||||||
new "Netconf runtime test"
|
new "Netconf runtime test"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><example xmlns=\"urn:example:clixon\"><x>0</x></example></rpc>]]>]]>" '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><x xmlns="urn:example:clixon">0</x><y xmlns="urn:example:clixon">42</y></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><example xmlns=\"urn:example:clixon\"><x>0</x></example></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><x xmlns=\"urn:example:clixon\">0</x><y xmlns=\"urn:example:clixon\">42</y></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
if [ $BE -ne 0 ]; then
|
if [ $BE -ne 0 ]; then
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ main(int argc,
|
||||||
/* Provide a clixon config-file, get a clixon handle */
|
/* Provide a clixon config-file, get a clixon handle */
|
||||||
if ((h = clixon_client_init("$cfg")) == NULL)
|
if ((h = clixon_client_init("$cfg")) == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
/* Make a conenction over netconf or ssh/netconf */
|
/* Make a connection over netconf or ssh/netconf */
|
||||||
if ((ch = clixon_client_connect(h, CLIXON_CLIENT_NETCONF)) == NULL)
|
if ((ch = clixon_client_connect(h, CLIXON_CLIENT_NETCONF)) == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -232,13 +232,13 @@ new "limit rpc ok"
|
||||||
expectpart "$(curl -u wilma:bar $CURLOPTS -X POST $RCPROTO://localhost/restconf/operations/clixon-example:example -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":42}}' )" 0 "HTTP/$HVER 200" '{"clixon-example:output":{"x":"42","y":"42"}}'
|
expectpart "$(curl -u wilma:bar $CURLOPTS -X POST $RCPROTO://localhost/restconf/operations/clixon-example:example -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":42}}' )" 0 "HTTP/$HVER 200" '{"clixon-example:output":{"x":"42","y":"42"}}'
|
||||||
|
|
||||||
new "limit rpc netconf ok"
|
new "limit rpc netconf ok"
|
||||||
expecteof "$clixon_netconf -U wilma -qf $cfg" 0 "$DEFAULTHELLO<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><example xmlns=\"urn:example:clixon\"><x>0</x></example></rpc>]]>]]>" '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><x xmlns="urn:example:clixon">0</x><y xmlns="urn:example:clixon">42</y></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -U wilma -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><example xmlns=\"urn:example:clixon\"><x>0</x></example></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><x xmlns=\"urn:example:clixon\">0</x><y xmlns=\"urn:example:clixon\">42</y></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "guest rpc fail"
|
new "guest rpc fail"
|
||||||
expectpart "$(curl -u guest:bar $CURLOPTS -X POST $RCPROTO://localhost/restconf/operations/clixon-example:example -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":42}}' )" 0 "HTTP/$HVER 403" '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}}'
|
expectpart "$(curl -u guest:bar $CURLOPTS -X POST $RCPROTO://localhost/restconf/operations/clixon-example:example -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":42}}' )" 0 "HTTP/$HVER 403" '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}}'
|
||||||
|
|
||||||
new "guest rpc netconf fail"
|
new "guest rpc netconf fail"
|
||||||
expecteof "$clixon_netconf -U guest -qf $cfg" 0 "$DEFAULTHELLO<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><example xmlns=\"urn:example:clixon\"><x>0</x></example></rpc>]]>]]>" '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><rpc-error><error-type>application</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -U guest -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><example xmlns=\"urn:example:clixon\"><x>0</x></example></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
#------------------ Set read-default permit
|
#------------------ Set read-default permit
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ cat <<EOF > $cfg
|
||||||
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
||||||
<CLICON_BACKEND_REGEXP>example_backend.so$</CLICON_BACKEND_REGEXP>
|
<CLICON_BACKEND_REGEXP>example_backend.so$</CLICON_BACKEND_REGEXP>
|
||||||
<CLICON_NETCONF_DIR>/usr/local/lib/$APPNAME/netconf</CLICON_NETCONF_DIR>
|
<CLICON_NETCONF_DIR>/usr/local/lib/$APPNAME/netconf</CLICON_NETCONF_DIR>
|
||||||
|
<CLICON_NETCONF_MESSAGE_ID_OPTIONAL>false</CLICON_NETCONF_MESSAGE_ID_OPTIONAL>
|
||||||
<CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR>
|
<CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR>
|
||||||
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
|
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
|
||||||
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
|
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
|
||||||
|
|
@ -67,6 +68,9 @@ expecteof "$clixon_netconf -qf $cfg" 0 "<hello $DEFAULTNS><capabilities><capabil
|
||||||
new "Frame with unknown message"
|
new "Frame with unknown message"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<xxx $DEFAULTNS></xxx>]]>]]>" "^<rpc-reply $DEFAULTNS><rpc-error><error-type>protocol</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>xxx</bad-element></error-info><error-severity>error</error-severity><error-message>Unrecognized netconf operation</error-message></rpc-error></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<xxx $DEFAULTNS></xxx>]]>]]>" "^<rpc-reply $DEFAULTNS><rpc-error><error-type>protocol</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>xxx</bad-element></error-info><error-severity>error</error-severity><error-message>Unrecognized netconf operation</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "Frame without message-id attribute"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTONLY><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTONLY><rpc-error><error-type>rpc</error-type><error-tag>missing-attribute</error-tag><error-info><bad-attribute>message-id</bad-attribute></error-info><error-severity>error</error-severity><error-message>Incoming rpc</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf rcv hello, disable RFC7895/ietf-yang-library"
|
new "netconf rcv hello, disable RFC7895/ietf-yang-library"
|
||||||
expecteof "$clixon_netconf -f $cfg -o CLICON_MODULE_LIBRARY_RFC7895=0" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<hello $DEFAULTNS><capabilities><capability>urn:ietf:params:netconf:base:1.1</capability><capability>urn:ietf:params:netconf:base:1.0</capability><capability>urn:ietf:params:netconf:capability:candidate:1.0</capability><capability>urn:ietf:params:netconf:capability:validate:1.1</capability><capability>urn:ietf:params:netconf:capability:startup:1.0</capability><capability>urn:ietf:params:netconf:capability:xpath:1.0</capability><capability>urn:ietf:params:netconf:capability:notification:1.0</capability></capabilities><session-id>[0-9]*</session-id></hello>]]>]]><rpc-reply $DEFAULTNS><data/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -f $cfg -o CLICON_MODULE_LIBRARY_RFC7895=0" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<hello $DEFAULTNS><capabilities><capability>urn:ietf:params:netconf:base:1.1</capability><capability>urn:ietf:params:netconf:base:1.0</capability><capability>urn:ietf:params:netconf:capability:candidate:1.0</capability><capability>urn:ietf:params:netconf:capability:validate:1.1</capability><capability>urn:ietf:params:netconf:capability:startup:1.0</capability><capability>urn:ietf:params:netconf:capability:xpath:1.0</capability><capability>urn:ietf:params:netconf:capability:notification:1.0</capability></capabilities><session-id>[0-9]*</session-id></hello>]]>]]><rpc-reply $DEFAULTNS><data/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -393,7 +393,7 @@ function testrun()
|
||||||
|
|
||||||
new "restconf rpc using POST xml"
|
new "restconf rpc using POST xml"
|
||||||
ret=$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -H "Accept: application/yang-data+xml" -d '{"clixon-example:input":{"x":42}}' $proto://$addr/restconf/operations/clixon-example:example)
|
ret=$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -H "Accept: application/yang-data+xml" -d '{"clixon-example:input":{"x":42}}' $proto://$addr/restconf/operations/clixon-example:example)
|
||||||
expect='<output xmlns="urn:example:clixon"><x>42</x><y>42</y></output>'
|
expect='<output message-id="42" xmlns="urn:example:clixon"><x>42</x><y>42</y></output>'
|
||||||
match=`echo $ret | grep --null -Eo "$expect"`
|
match=`echo $ret | grep --null -Eo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
err "$expect" "$ret"
|
err "$expect" "$ret"
|
||||||
|
|
|
||||||
|
|
@ -89,10 +89,10 @@ new "restconf example rpc xml/json"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+json' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+json' '{"clixon-example:output":{"x":"0","y":"42"}}'
|
expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+json' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+json' '{"clixon-example:output":{"x":"0","y":"42"}}'
|
||||||
|
|
||||||
new "restconf example rpc json/xml"
|
new "restconf example rpc json/xml"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '{"clixon-example:input":{"x":"0"}}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+xml' '<output xmlns="urn:example:clixon"><x>0</x><y>42</y></output>'
|
expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '{"clixon-example:input":{"x":"0"}}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+xml' '<output message-id="42" xmlns="urn:example:clixon"><x>0</x><y>42</y></output>'
|
||||||
|
|
||||||
new "restconf example rpc xml/xml"
|
new "restconf example rpc xml/xml"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+xml' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+xml' '<output xmlns="urn:example:clixon"><x>0</x><y>42</y></output>'
|
expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+xml' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+xml' '<output message-id="42" xmlns="urn:example:clixon"><x>0</x><y>42</y></output>'
|
||||||
|
|
||||||
new "restconf example rpc xml in w json encoding (expect fail)"
|
new "restconf example rpc xml in w json encoding (expect fail)"
|
||||||
expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 "HTTP/$HVER 400" "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>rpc</error-type><error-tag>malformed-message</error-tag><error-severity>error</error-severity><error-message>json_parse: line 1: syntax error at or before: '<'</error-message></error></errors>"
|
expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 "HTTP/$HVER 400" "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>rpc</error-type><error-tag>malformed-message</error-tag><error-severity>error</error-severity><error-message>json_parse: line 1: syntax error at or before: '<'</error-message></error></errors>"
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ module clixon-config {
|
||||||
CLICON_RESTCONF_PRIVILEGES
|
CLICON_RESTCONF_PRIVILEGES
|
||||||
CLICON_RESTCONF_INSTALLDIR
|
CLICON_RESTCONF_INSTALLDIR
|
||||||
CLICON_RESTCONF_STARTUP_DONTUPDATE
|
CLICON_RESTCONF_STARTUP_DONTUPDATE
|
||||||
|
CLICON_NETCONF_MESSAGE_ID_OPTIONAL
|
||||||
Released in Clixon 5.2";
|
Released in Clixon 5.2";
|
||||||
}
|
}
|
||||||
revision 2021-03-08 {
|
revision 2021-03-08 {
|
||||||
|
|
@ -465,6 +466,16 @@ module clixon-config {
|
||||||
is returned, which conforms to the RFC.
|
is returned, which conforms to the RFC.
|
||||||
Note this applies only to external NETCONF, not the internal (IPC) netconf";
|
Note this applies only to external NETCONF, not the internal (IPC) netconf";
|
||||||
}
|
}
|
||||||
|
leaf CLICON_NETCONF_MESSAGE_ID_OPTIONAL {
|
||||||
|
type boolean;
|
||||||
|
default false;
|
||||||
|
description
|
||||||
|
"This option relates to RFC 6241 Sec 4.1 <rpc> Element
|
||||||
|
The <rpc> element has a mandatory attribute 'message-id', which is a
|
||||||
|
string chosen by the sender of the RPC.
|
||||||
|
If true, an RPC can be sent without a message-id.
|
||||||
|
This applies to both external NETCONF and internal (IPC) netconf";
|
||||||
|
}
|
||||||
leaf CLICON_RESTCONF_DIR {
|
leaf CLICON_RESTCONF_DIR {
|
||||||
type string;
|
type string;
|
||||||
description
|
description
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue