Netconf monitoring RFC 6022 Sessions (https://github.com/clicon/clixon/issues/370)

- statistics and transport/source-host parameters
  - extended internal NETCONF hello with transport and source-host attributes
clixon-lib,yang
  - Moved all extended internal NETCONF attributes to the clicon-lib namespace
C-API:
  - wrapped most attribute creation into new fn xml_add_attr()
This commit is contained in:
Olof hagsand 2023-01-14 11:25:39 +01:00
parent 7558d40faa
commit 3916fa919c
36 changed files with 883 additions and 402 deletions

View file

@ -44,8 +44,8 @@ Expected: beginning of 2023
### New features
* Netconf monitoring, part 2
* Datastores
* Remaining: sessions and statistics state
* Datastores and sessions
* Remaining: statistics state
* Standards
* RFC 6022 "YANG Module for NETCONF Monitoring"
* See [Feature Request: Support RFC 6022 (NETCONF Monitoring)](https://github.com/clicon/clixon/issues/370)
@ -54,6 +54,9 @@ Expected: beginning of 2023
Users may have to change how they access the system
* clixon-lib,yang
* Moved all extended internal NETCONF attributes to the clicon-lib namespace
* The internal attributes are documented in https://clixon-docs.readthedocs.io/en/latest/netconf.html
* With-defaults default retrieval mode has changed from `REPORT-ALL` to `EXPLICIT`
* This means that all get operations without `with-defaults` parameter do no longer
return implicit default values, only explicitly set values.

View file

@ -154,6 +154,81 @@ release_all_dbs(clicon_handle h,
return retval;
}
/*! Get backend-specific client netconf monitoring state
*
* Backend-specific netconf monitoring state is:
* sessions
* @param[in] h Clicon handle
* @param[in] yspec Yang spec
* @param[in] xpath XML Xpath
* @param[in] nsc XML Namespace context for xpath
* @param[in,out] xret Existing XML tree, merge x into this
* @param[out] xerr XML error tree, if retval = 0
* @retval -1 Error (fatal)
* @retval 0 Statedata callback failed, error in xerr
* @retval 1 OK
* @see RFC 6022
*/
int
backend_monitoring_state_get(clicon_handle h,
yang_stmt *yspec,
char *xpath,
cvec *nsc,
cxobj **xret,
cxobj **xerr)
{
int retval = -1;
cbuf *cb = NULL;
struct client_entry *ce;
char timestr[28];
int ret;
if ((cb = cbuf_new()) ==NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<netconf-state xmlns=\"%s\">", NETCONF_MONITORING_NAMESPACE);
cprintf(cb, "<sessions>");
for (ce = backend_client_list(h); ce; ce = ce->ce_next){
cprintf(cb, "<session>");
cprintf(cb, "<session-id>%u</session-id>", ce->ce_id);
if (ce->ce_transport)
cprintf(cb, "<transport xmlns:%s=\"%s\">%s</transport>",
CLIXON_LIB_PREFIX, CLIXON_LIB_NS,
ce->ce_transport);
cprintf(cb, "<username>%s</username>", ce->ce_username);
if (ce->ce_source_host)
cprintf(cb, "<source-host>%s</source-host>", ce->ce_source_host);
if (ce->ce_time.tv_sec != 0){
if (time2str(ce->ce_time, timestr, sizeof(timestr)) < 0){
clicon_err(OE_UNIX, errno, "time2str");
goto done;
}
cprintf(cb, "<login-time>%s</login-time>", timestr);
}
cprintf(cb, "<in-rpcs>%u</in-rpcs>", ce->ce_in_rpcs);
cprintf(cb, "<in-bad-rpcs>%u</in-bad-rpcs>", ce->ce_in_bad_rpcs);
cprintf(cb, "<out-rpc-errors>%u</out-rpc-errors>", ce->ce_out_rpc_errors);
cprintf(cb, "<out-notifications>%u</out-notifications>", 0);
cprintf(cb, "</session>");
}
cprintf(cb, "</sessions>");
cprintf(cb, "</netconf-state>");
if ((ret = clixon_xml_parse_string(cbuf_get(cb), YB_MODULE, yspec, xret, xerr)) < 0)
goto done;
if (ret == 0)
goto fail;
retval = 1;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
if (cb)
cbuf_free(cb);
return retval;
fail:
retval = 0;
goto done;
}
/*! Remove client entry state
* Close down everything wrt clients (eg sockets, subscriptions)
* Finally actually remove client struct in handle
@ -513,7 +588,9 @@ from_client_edit_config(clicon_handle h,
}
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><ok", NETCONF_BASE_NAMESPACE);
if (clicon_data_get(h, "objectexisted", &val) == 0)
cprintf(cbret, " objectexisted=\"%s\"", val);
cprintf(cbret, " %s:objectexisted=\"%s\" xmlns:%s=\"%s\"",
CLIXON_LIB_PREFIX, val,
CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
cprintf(cbret, "/></rpc-reply>");
ok:
retval = 0;
@ -1375,6 +1452,11 @@ from_client_process_control(clicon_handle h,
}
/*! Clixon hello to check liveness
*
* @param[in] h Clixon handle
* @param[in] x Incoming XML of hello request
* @param[in] ce Client entry (from)
* @param[out] cbret Hello reply
* @retval 0 OK
* @retval -1 Error
*/
@ -1386,11 +1468,24 @@ from_client_hello(clicon_handle h,
{
int retval = -1;
uint32_t id;
char *val;
if (clicon_session_id_get(h, &id) < 0){
clicon_err(OE_NETCONF, ENOENT, "session_id not set");
goto done;
}
if ((val = xml_find_type_value(x, "cl", "transport", CX_ATTR)) != NULL){
if ((ce->ce_transport = strdup(val)) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto done;
}
}
if ((val = xml_find_type_value(x, "cl", "source-host", CX_ATTR)) != NULL){
if ((ce->ce_source_host = strdup(val)) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto done;
}
}
id++;
clicon_session_id_set(h, id);
cprintf(cbret, "<hello xmlns=\"%s\"><session-id>%u</session-id></hello>",
@ -1498,7 +1593,7 @@ from_client_msg(clicon_handle h,
}
if (strcmp(rpcname, "rpc") == 0){
; /* continue below */
ce->ce_in_rpcs++; /* Track all RPCs */
}
else if (strcmp(rpcname, "hello") == 0){
if ((ret = from_client_hello(h, x, ce, cbret)) <0)
@ -1508,9 +1603,12 @@ from_client_msg(clicon_handle h,
else{
if (netconf_unknown_element(cbret, "protocol", rpcname, "Unrecognized netconf operation")< 0)
goto done;
ce->ce_in_bad_rpcs++;
ce->ce_out_rpc_errors++; /* Number of <rpc-reply> messages sent that contained an <rpc-error> */
goto reply;
}
ce->ce_id = id;
/* As a side-effect, this expands xt with default values according to "report-all"
* This may not be correct, the RFC does not mention expanding default values for
* input RPC
@ -1520,6 +1618,8 @@ from_client_msg(clicon_handle h,
if (ret == 0){
if (clixon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
goto done;
ce->ce_in_bad_rpcs++;
ce->ce_in_rpcs--; /* Track all RPCs */
goto reply;
}
xe = NULL;
@ -1531,6 +1631,7 @@ from_client_msg(clicon_handle h,
if ((ye = xml_spec(xe)) == NULL){
if (netconf_operation_not_supported(cbret, "protocol", rpc) < 0)
goto done;
ce->ce_out_rpc_errors++;
goto reply;
}
if ((ymod = ys_module(ye)) == NULL){
@ -1557,26 +1658,34 @@ from_client_msg(clicon_handle h,
creds = clicon_nacm_credentials(h);
if ((ret = verify_nacm_user(h, creds, ce->ce_username, username, cbret)) < 0)
goto done;
if (ret == 0) /* credentials fail */
if (ret == 0){ /* credentials fail */
ce->ce_out_rpc_errors++;
goto reply;
}
/* NACM rpc operation exec validation */
if ((ret = nacm_rpc(rpc, module, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0) /* Not permitted and cbret set */
if (ret == 0){ /* Not permitted and cbret set */
ce->ce_out_rpc_errors++;
goto reply;
}
}
clicon_err_reset();
if ((ret = rpc_callback_call(h, xe, ce, &nr, cbret)) < 0){
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
goto done;
clicon_log(LOG_NOTICE, "%s Error in rpc_callback_call:%s", __FUNCTION__, xml_name(xe));
ce->ce_out_rpc_errors++;
goto reply; /* Dont quit here on user callbacks */
}
if (ret == 0)
if (ret == 0){
ce->ce_out_rpc_errors++;
goto reply;
}
if (nr == 0){ /* not handled by callback */
if (netconf_operation_not_supported(cbret, "application", "RPC operation not supported")< 0)
goto done;
ce->ce_out_rpc_errors++;
goto reply;
}
if (xnacm){

View file

@ -41,24 +41,33 @@
* Types
*/
/*
* Client entry.
* Backend client entry.
* Keep state about every connected client.
* References from RFC 6022, ietf-netconf-monitoring.yang sessions container
*/
struct client_entry{
struct client_entry *ce_next; /* The clients linked list */
struct sockaddr ce_addr; /* The clients (UNIX domain) address */
int ce_s; /* stream socket to client */
int ce_nr; /* Client number (for dbg/tracing) */
int ce_stat_in; /* Nr of received msgs from client */
int ce_stat_out;/* Nr of sent msgs to client */
uint32_t ce_id; /* Session id, accessor functions: clicon_session_id_get/set */
char *ce_username;/* Translated from peer user cred */
clicon_handle ce_handle; /* clicon config handle (all clients have same?) */
char *ce_transport; /* Identifies the transport for each session.
Clixon-lib.yang extends these values by prefixing with
"cl:", where cl is ensured to be declared ie by
netconf-monitoring state */
char *ce_source_host; /* Host identifier of the NETCONF client */
struct timeval ce_time; /* Time at the server at which the session was established. */
uint32_t ce_in_rpcs ; /* Number of correct <rpc> messages received. */
uint32_t ce_in_bad_rpcs; /* Not correct <rpc> messages */
uint32_t ce_out_rpc_errors; /* <rpc-error> messages*/
};
/*
* Prototypes
*/
int backend_monitoring_state_get(clicon_handle h, yang_stmt *yspec, char *xpath, cvec *nsc, cxobj **xret, cxobj **xerr);
int backend_client_rm(clicon_handle h, struct client_entry *ce);
int from_client(int fd, void *arg);
int backend_rpc_init(clicon_handle h);

View file

@ -181,10 +181,22 @@ client_get_streams(clicon_handle h,
* @param[in] xpath XPath selection, may be used to filter early
* @param[in] nsc XML Namespace context for xpath
* @param[in] wdef With-defaults parameter, see RFC 6243
* @param[in,out] xret Existing XML tree, merge x into this
* @param[in,out] xret Existing XML tree, merge x into this, or rpc-error
* @retval -1 Error (fatal)
* @retval 0 Statedata callback failed (clicon_err called)
* @retval 0 Statedata callback failed (error in xret)
* @retval 1 OK
* @note This code in general does not look at xpath, needs to be filtered in retrospect
* @note Awkward error handling. Even if most of this is during development phase, except for plugin
* state callbacks.
* Present behavior:
* - Present behavior: should be returned in xret with retval 0(error) or 1(ok)
* - On error, previous content of xret is not freed
* - xret is in turn translated to cbuf in calling function
* Instead, I think there should be a second out argument **xerr with the error message, see code
* for CLICON_NETCONF_MONITORING which is transformed in calling function(?) to an internal error
* message. But this needs to be explored in all sub-functions
*
*
*/
static int
get_client_statedata(clicon_handle h,
@ -196,9 +208,11 @@ get_client_statedata(clicon_handle h,
int retval = -1;
yang_stmt *yspec;
yang_stmt *ymod;
cxobj *x1 = NULL;
int ret;
char *namespace;
cbuf *cb = NULL;
cxobj *xerr = NULL;
clicon_debug(1, "%s", __FUNCTION__);
if ((yspec = clicon_dbspec_yang(h)) == NULL){
@ -236,7 +250,6 @@ get_client_statedata(clicon_handle h,
goto done;
}
cbuf_reset(cb);
/* XXX This code does not filter state data with xpath */
cprintf(cb, "<restconf-state xmlns=\"%s\"/>", namespace);
if (clixon_xml_parse_string(cbuf_get(cb), YB_MODULE, yspec, xret, NULL) < 0)
goto done;
@ -254,7 +267,32 @@ get_client_statedata(clicon_handle h,
goto fail;
}
if (clicon_option_bool(h, "CLICON_NETCONF_MONITORING")){
if ((ret = netconf_monitoring_state_get(h, yspec, xpath, nsc, 0, xret)) < 0)
if ((ret = netconf_monitoring_state_get(h, yspec, xpath, nsc, xret, &xerr)) < 0)
goto done;
if (ret == 0){
if (clixon_netconf_internal_error(xerr, " . Internal error, netconf_monitoring_state returned invalid XML", NULL) < 0)
goto done;
if (*xret)
xml_free(*xret);
*xret = xerr;
xerr = NULL;
goto fail;
}
/* Some state, client state, is avaliable in backend only, not in lib
* Needs merge since same subtree as previous lib state
*/
if ((ret = backend_monitoring_state_get(h, yspec, xpath, nsc, &x1, &xerr)) < 0)
goto done;
if (ret == 0){
if (clixon_netconf_internal_error(xerr, " . Internal error, baenckend_monitoring_state_get returned invalid XML", NULL) < 0)
goto done;
if (*xret)
xml_free(*xret);
*xret = xerr;
xerr = NULL;
goto fail;
}
if ((ret = netconf_trymerge(x1, yspec, xret)) < 0)
goto done;
if (ret == 0)
goto fail;
@ -320,6 +358,10 @@ get_client_statedata(clicon_handle h,
retval = 1; /* OK */
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
if (xerr)
xml_free(xerr);
if (x1)
xml_free(x1);
if (cb)
cbuf_free(cb);
return retval;
@ -734,18 +776,12 @@ get_list_pagination(clicon_handle h,
cbuf *cba = NULL;
/* Add remaining attribute */
if ((xa = xml_new("remaining", x1, CX_ATTR)) == NULL)
goto done;
if ((cba = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
cprintf(cba, "%u", remaining);
if (xml_value_set(xa, cbuf_get(cba)) < 0)
goto done;
if (xml_prefix_set(xa, "cp") < 0)
goto done;
if (xmlns_set(x1, "cp", "http://clicon.org/clixon-netconf-list-pagination") < 0)
if (xml_add_attr(x1, "remaining", cbuf_get(cba), "cp", "http://clicon.org/clixon-netconf-list-pagination") < 0)
goto done;
if (cba)
cbuf_free(cba);

View file

@ -249,7 +249,6 @@ backend_accept_client(int fd,
}
if ((ce = backend_client_add(h, &from)) == NULL)
goto done;
ce->ce_handle = h;
/*
* Get credentials of connected peer - only for unix socket

View file

@ -145,6 +145,8 @@ backend_client_add(clicon_handle h,
ce->ce_nr = bh->bh_ce_nr++; /* Session-id ? */
memcpy(&ce->ce_addr, addr, sizeof(*addr));
ce->ce_next = bh->bh_ce_list;
ce->ce_handle = h;
gettimeofday(&ce->ce_time, NULL);
bh->bh_ce_list = ce;
return ce;
}
@ -180,6 +182,10 @@ backend_client_delete(clicon_handle h,
*ce_prev = c->ce_next;
if (ce->ce_username)
free(ce->ce_username);
if (ce->ce_transport)
free(ce->ce_transport);
if (ce->ce_source_host)
free(ce->ce_source_host);
free(ce);
break;
}
@ -203,8 +209,9 @@ backend_client_print(clicon_handle h,
fprintf(f, "Client: %d\n", ce->ce_nr);
fprintf(f, " Session: %d\n", ce->ce_id);
fprintf(f, " Socket: %d\n", ce->ce_s);
fprintf(f, " Msgs in: %d\n", ce->ce_stat_in);
fprintf(f, " Msgs out: %d\n", ce->ce_stat_out);
fprintf(f, " RPCs in: %u\n", ce->ce_in_rpcs);
fprintf(f, " Bad RPCs in: %u\n", ce->ce_in_bad_rpcs);
fprintf(f, " Err RPCs out: %u\n", ce->ce_out_rpc_errors);
fprintf(f, " Username: %s\n", ce->ce_username);
}
return 0;

View file

@ -294,7 +294,6 @@ cli_dbxml(clicon_handle h,
cxobj *xbot = NULL; /* xpath, NULL if datastore */
yang_stmt *y = NULL; /* yang spec of xpath */
cxobj *xtop = NULL; /* xpath root */
cxobj *xa; /* attribute */
cxobj *xerr = NULL;
int ret;
cg_var *cv;
@ -338,11 +337,7 @@ cli_dbxml(clicon_handle h,
goto done;
}
}
if ((xa = xml_new("operation", xbot, CX_ATTR)) == NULL)
goto done;
if (xml_prefix_set(xa, NETCONF_BASE_PREFIX) < 0)
goto done;
if (xml_value_set(xa, xml_operation2str(op)) < 0)
if (xml_add_attr(xbot, "operation", xml_operation2str(op), NETCONF_BASE_PREFIX, NULL) < 0)
goto done;
/* Add body last in case of leaf */
if (cvec_len(cvv) > 1 &&

View file

@ -818,6 +818,11 @@ main(int argc,
if (evalresult < 0)
goto done;
}
/* Set RFC6022 session parameters that will be sent in first hello,
* @see clicon_hello_req
*/
clicon_data_set(h, "session-transport", "cl:cli");
clicon_data_set(h, "session-source-host", "localhost");
/* Go into event-loop unless -1 command-line */
if (!once){

View file

@ -110,6 +110,15 @@ netconf_add_request_attr(cxobj *xrpc,
/* If attribute already exists, dont copy it */
if (xml_find_type(xrep, NULL, xml_name(xa), CX_ATTR) != NULL)
continue; /* Skip already present (dont overwrite) */
/* Filter all clixon-lib attributes and namespace declaration
* to acvoid leaking internal attributes to external NETCONF
* note this is only done on top-level.
*/
if (xml_prefix(xa) && strcmp(xml_prefix(xa), CLIXON_LIB_PREFIX) == 0)
continue;
if (xml_prefix(xa) && strcmp(xml_prefix(xa), "xmlns") == 0 &&
strcmp(xml_name(xa), CLIXON_LIB_PREFIX) == 0)
continue;
if ((xa2 = xml_dup(xa)) ==NULL)
goto done;
if (xml_addsub(xrep, xa2) < 0)
@ -240,9 +249,9 @@ netconf_rpc_message(clicon_handle h,
goto done;
goto ok;
}
if (netconf_rpc_dispatch(h, xrpc, &xret, eof) < 0){
if (netconf_rpc_dispatch(h, xrpc, &xret, eof) < 0)
goto done;
}
/* Is there a return message in xret? */
if (xret == NULL){
if (netconf_operation_failed_xml(&xret, "rpc", "Internal error: no xml return")< 0)
@ -988,7 +997,7 @@ main(int argc,
* used by the client, even though new TCP sessions are created for
* each message sent to the backend.
*/
if (clicon_hello_req(h, &id) < 0)
if (clicon_hello_req(h, "cl:netconf", NULL, &id) < 0)
goto done;
clicon_session_id_set(h, id);

View file

@ -704,9 +704,7 @@ netconf_rpc_dispatch(clicon_handle h,
* It may even be wrong if something else is done with the incoming message?
*/
if ((username = clicon_username_get(h)) != NULL){
if ((xa = xml_new("username", xn, CX_ATTR)) == NULL)
goto done;
if (xml_value_set(xa, username) < 0)
if (xml_add_attr(xn, "username", username, CLIXON_LIB_PREFIX, CLIXON_LIB_NS) < 0)
goto done;
}
/* Many of these calls are now calling generic clicon_rpc_netconf_xml

View file

@ -405,7 +405,6 @@ restconf_insert_attributes(cxobj *xdata,
cvec *qvec)
{
int retval = -1;
cxobj *xa;
char *instr;
char *pstr;
yang_stmt *y;
@ -422,12 +421,7 @@ restconf_insert_attributes(cxobj *xdata,
/* First add xmlns:yang attribute */
if (xmlns_set(xdata, "yang", YANG_XML_NAMESPACE) < 0)
goto done;
/* Then add insert attribute */
if ((xa = xml_new("insert", xdata, CX_ATTR)) == NULL)
goto done;
if (xml_prefix_set(xa, "yang") < 0)
goto done;
if (xml_value_set(xa, instr) < 0)
if (xml_add_attr(xdata, "insert", instr, "yang", NULL) < 0)
goto done;
}
if ((pstr = cvec_find_str(qvec, "point")) != NULL){
@ -439,11 +433,7 @@ restconf_insert_attributes(cxobj *xdata,
attrname="key";
else
attrname="value";
/* Then add value/key attribute */
if ((xa = xml_new(attrname, xdata, CX_ATTR)) == NULL)
goto done;
if (xml_prefix_set(xa, "yang") < 0)
goto done;
if ((ret = api_path2xpath(pstr, ys_spec(y), &xpath, &nsc, NULL)) < 0)
goto done;
if ((cb = cbuf_new()) == NULL){
@ -471,7 +461,7 @@ restconf_insert_attributes(cxobj *xdata,
p++;
cprintf(cb, "%s", p);
}
if (xml_value_set(xa, cbuf_get(cb)) < 0)
if (xml_add_attr(xdata, attrname, cbuf_get(cb), "yang", NULL) < 0)
goto done;
}
/* Add prefix/namespaces used in attributes */

View file

@ -163,7 +163,7 @@ restconf_main_config(clicon_handle h,
else {
/* Loop to wait for backend starting, try again if not done */
while (1){
if (clicon_hello_req(h, &id) < 0){
if (clicon_hello_req(h, "cl:restconf", NULL, &id) < 0){
if (errno == ENOENT){
fprintf(stderr, "waiting");
sleep(1);

View file

@ -634,7 +634,7 @@ restconf_clixon_backend(clicon_handle h,
/* Loop to wait for backend starting, try again if not done */
while (1){
if (clicon_hello_req(h, &id) < 0){
if (clicon_hello_req(h, "cl:restconf", NULL, &id) < 0){
if (errno == ENOENT){
fprintf(stderr, "waiting");
sleep(1);

View file

@ -384,23 +384,11 @@ api_data_write(clicon_handle h,
/* Add operation create as attribute. If that fails with Conflict, then
* try "replace" (see comment in function header)
*/
if ((xa = xml_new("operation", xdata, CX_ATTR)) == NULL)
if (xml_add_attr(xdata, "operation", xml_operation2str(op), NETCONF_BASE_PREFIX, NULL) < 0)
goto done;
if (xml_prefix_set(xa, NETCONF_BASE_PREFIX) < 0)
goto done;
if (xml_value_set(xa, xml_operation2str(op)) < 0) /* XXX here is where op is used */
goto done;
if ((xa = xml_new("objectcreate", xdata, CX_ATTR)) == NULL)
goto done;
if (plain_patch){
/* RFC 8040 4.6. PATCH:
* If the target resource instance does not exist, the server MUST NOT create it.
*/
if (xml_value_set(xa, "false") < 0)
goto done;
}
else
if (xml_value_set(xa, "true") < 0)
if (xml_add_attr(xdata, "objectcreate",
plain_patch?"false":"true",
CLIXON_LIB_PREFIX, CLIXON_LIB_NS) < 0)
goto done;
/* Top-of tree, no api-path
* Replace xparent with x, ie bottom of api-path with data
@ -512,16 +500,20 @@ api_data_write(clicon_handle h,
} /* api-path != NULL */
/* For internal XML protocol: add username attribute for access control
*/
username = clicon_username_get(h);
/* Create text buffer for transfer to backend */
if ((cbx = cbuf_new()) == NULL)
goto done;
cprintf(cbx, "<rpc xmlns=\"%s\" username=\"%s\" xmlns:%s=\"%s\" %s>",
NETCONF_BASE_NAMESPACE,
username?username:"",
cprintf(cbx, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cbx, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cbx, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cbx, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cbx, " xmlns:%s=\"%s\"",
NETCONF_BASE_PREFIX,
NETCONF_BASE_NAMESPACE, /* bind nc to netconf namespace */
NETCONF_MESSAGE_ID_ATTR);
NETCONF_BASE_NAMESPACE); /* bind nc to netconf namespace */
cprintf(cbx, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cbx, ">");
cprintf(cbx, "<edit-config");
/* RFC8040 Sec 1.4:
* If this is a "data" request and the NETCONF server supports :startup,
@ -532,9 +524,11 @@ api_data_write(clicon_handle h,
if ((IETF_DS_NONE == ds) &&
if_feature(yspec, "ietf-netconf", "startup") &&
!clicon_option_bool(h, "CLICON_RESTCONF_STARTUP_DONTUPDATE")){
cprintf(cbx, " copystartup=\"true\"");
cprintf(cbx, " %s:copystartup=\"true\"", CLIXON_LIB_PREFIX);
cprintf(cbx, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cbx, " autocommit=\"true\"");
cprintf(cbx, " %s:autocommit=\"true\" xmlns:%s=\"%s\"",
CLIXON_LIB_PREFIX, CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
cprintf(cbx, "><target><candidate /></target>");
cprintf(cbx, "<default-operation>none</default-operation>");
if (clixon_xml2cbuf(cbx, xtop, 0, 0, -1, 0) < 0)
@ -759,14 +753,17 @@ api_data_delete(clicon_handle h,
goto done;
/* For internal XML protocol: add username attribute for access control
*/
username = clicon_username_get(h);
cprintf(cbx, "<rpc xmlns=\"%s\" username=\"%s\" xmlns:%s=\"%s\" %s>",
NETCONF_BASE_NAMESPACE,
username?username:"",
cprintf(cbx, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cbx, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cbx, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cbx, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cbx, " xmlns:%s=\"%s\"",
NETCONF_BASE_PREFIX,
NETCONF_BASE_NAMESPACE,
NETCONF_MESSAGE_ID_ATTR); /* bind nc to netconf namespace */
NETCONF_BASE_NAMESPACE);
cprintf(cbx, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cbx, ">");
cprintf(cbx, "<edit-config");
/* RFC8040 Sec 1.4:
* If this is a "data" request and the NETCONF server supports :startup,
@ -777,9 +774,11 @@ api_data_delete(clicon_handle h,
if ((IETF_DS_NONE == ds) &&
if_feature(yspec, "ietf-netconf", "startup") &&
!clicon_option_bool(h, "CLICON_RESTCONF_STARTUP_DONTUPDATE")){
cprintf(cbx, " copystartup=\"true\"");
cprintf(cbx, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
cprintf(cbx, " %s:copystartup=\"true\"", CLIXON_LIB_PREFIX);
}
cprintf(cbx, " autocommit=\"true\"");
cprintf(cbx, " %s:autocommit=\"true\" xmlns:%s=\"%s\"",
CLIXON_LIB_PREFIX, CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
cprintf(cbx, "><target><candidate /></target>");
cprintf(cbx, "<default-operation>none</default-operation>");
if (clixon_xml2cbuf(cbx, xtop, 0, 0, -1, 0) < 0)

View file

@ -337,14 +337,15 @@ api_data_post(clicon_handle h,
}
/* For internal XML protocol: add username attribute for access control
*/
username = clicon_username_get(h);
cprintf(cbx, "<rpc xmlns=\"%s\" username=\"%s\" xmlns:%s=\"%s\" %s>",
NETCONF_BASE_NAMESPACE,
cprintf(cbx, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cbx, " %s:username=\"%s\" xmlns:%s=\"%s\"",
NETCONF_BASE_PREFIX,
username?username:"",
NETCONF_BASE_PREFIX,
NETCONF_BASE_NAMESPACE,
NETCONF_MESSAGE_ID_ATTR); /* bind nc to netconf namespace */
NETCONF_BASE_NAMESPACE);
}
cprintf(cbx, " %s>", NETCONF_MESSAGE_ID_ATTR); /* bind nc to netconf namespace */
cprintf(cbx, "<edit-config");
/* RFC8040 Sec 1.4:
* If this is a "data" request and the NETCONF server supports :startup,
@ -355,9 +356,11 @@ api_data_post(clicon_handle h,
if ((IETF_DS_NONE == ds) &&
if_feature(yspec, "ietf-netconf", "startup") &&
!clicon_option_bool(h, "CLICON_RESTCONF_STARTUP_DONTUPDATE")){
cprintf(cbx, " copystartup=\"true\"");
cprintf(cbx, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
cprintf(cbx, " %s:copystartup=\"true\"", CLIXON_LIB_PREFIX);
}
cprintf(cbx, " autocommit=\"true\"");
cprintf(cbx, " %s:autocommit=\"true\" xmlns:%s=\"%s\"",
CLIXON_LIB_PREFIX, CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
cprintf(cbx, "><target><candidate /></target>");
cprintf(cbx, "<default-operation>none</default-operation>");
if (clixon_xml2cbuf(cbx, xtop, 0, 0, -1, 0) < 0)

32
apps/snmp/README.md Normal file
View file

@ -0,0 +1,32 @@
SNMP
====
The SNMP frontend acts as an intermediate daemon between the Net-SNMP
daemon (snmpd) and the Clixon backend. Clixon-snmp communicates over the AgentX
protocol to snmpd typically via a UNIX socket, and over the internal IPC protocol to the Clixon
backend.
Use Net-SNMP version 5.9 or later
To set up AgentX communication between ``clixon_snmp`` and ``snmpd`` a
Unix or TCP socket is configured. This socket is also configured in
Clixon (see below). An example `/etc/snmpd/snmpd.conf` is as follows::
master agentx
agentaddress 127.0.0.1,[::1]
rwcommunity public localhost
agentXSocket unix:/var/run/snmp.sock
agentxperms 777 777
It is necessary to ensure snmpd does `not` to load modules
implemented by Clixon. For example, if Clixon implements the IF-MIB and
system MIBs, snmpd should not load those modules. This can be done
using the "-I" flag and prepending a "-" before each module::
-I -ifTable -I -system_mib -I -sysORTable
Net-snmp must be started via systemd or some other external mechanism before clixon_snmp is started.
To build the snmp support, netsnmp is enabled at configure time. Two configure options are added for SNMP:
* ``--enable-netsnmp`` Enable SNMP support.
* ``--with-mib-generated-yang-dir`` For tests: Directory of generated YANG specs (default: $prefix/share/mibyang)

View file

@ -525,7 +525,7 @@ main(int argc,
* used by the client, even though new TCP sessions are created for
* each message sent to the backend.
*/
if (clicon_hello_req(h, &id) < 0)
if (clicon_hello_req(h, "cl:snmp", "localhost", &id) < 0)
goto done;
clicon_session_id_set(h, id);

View file

@ -41,6 +41,6 @@
/*
* Prototypes
*/
int netconf_monitoring_state_get(clicon_handle h, yang_stmt *yspec, char *xpath, cvec *nsc, int brief, cxobj **xret);
int netconf_monitoring_state_get(clicon_handle h, yang_stmt *yspec, char *xpath, cvec *nsc, cxobj **xret, cxobj **xerr);
#endif /* _CLIXON_NETCONF_MONITORING_H_ */

View file

@ -51,7 +51,9 @@
* @see clixon-lib.yang
*/
#define CLIXON_CONF_NS "http://clicon.org/config"
#define CLIXON_CONF_PREFIX "cc"
#define CLIXON_LIB_NS "http://clicon.org/lib"
#define CLIXON_LIB_PREFIX "cl"
#define CLIXON_AUTOCLI_NS "http://clicon.org/autocli"
#define CLIXON_RESTCONF_NS "http://clicon.org/restconf"

View file

@ -68,7 +68,7 @@ int clicon_rpc_discard_changes(clicon_handle h);
int clicon_rpc_create_subscription(clicon_handle h, char *stream, char *filter, int *s);
int clicon_rpc_debug(clicon_handle h, int level);
int clicon_rpc_restconf_debug(clicon_handle h, int level);
int clicon_hello_req(clicon_handle h, uint32_t *id);
int clicon_hello_req(clicon_handle h, char *transport, char *source_host, uint32_t *id);
int clicon_rpc_restart_plugin(clicon_handle h, char *plugin);
#endif /* _CLIXON_PROTO_CLIENT_H_ */

View file

@ -279,7 +279,9 @@ cxobj *xml_root(cxobj *xn);
int xml_operation(char *opstr, enum operation_type *op);
char *xml_operation2str(enum operation_type op);
int xml_attr_insert2val(char *instr, enum insert_type *ins);
int xml_add_attr(cxobj *xn, char *name, char *value, char *prefix, char *ns);
int clicon_log_xml(int level, cxobj *x, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
#ifdef XML_EXPLICIT_INDEX
int xml_search_index_p(cxobj *x);

View file

@ -168,7 +168,6 @@ check_body_namespace(cxobj *x0,
char *prefix = NULL;
char *ns0 = NULL;
char *ns1 = NULL;
cxobj *xa;
cxobj *x;
int isroot;
cbuf *cberr = NULL;
@ -210,16 +209,11 @@ bad-attribue?
goto done;
/* Create xmlns attribute to x0 XXX same code ^*/
if (prefix){
if ((xa = xml_new(prefix, x, CX_ATTR)) == NULL)
goto done;
if (xml_prefix_set(xa, "xmlns") < 0)
if (xml_add_attr(x, prefix, ns0, "xmlns", NULL) < 0)
goto done;
}
else{
if ((xa = xml_new("xmlns", x, CX_ATTR)) == NULL)
goto done;
}
if (xml_value_set(xa, ns0) < 0)
else
if (xml_add_attr(x, "xmlns", ns0, NULL, NULL) < 0)
goto done;
xml_sort(x); /* Ensure attr is first / XXX xml_insert? */
}
@ -237,11 +231,7 @@ bad-attribue?
;
}
else{ /* Add it according to the kludge,... */
if ((xa = xml_new(prefix, x0, CX_ATTR)) == NULL)
goto done;
if (xml_prefix_set(xa, "xmlns") < 0)
goto done;
if (xml_value_set(xa, ns0) < 0)
if (xml_add_attr(x0, prefix, ns0, "xmlns", NULL) < 0)
goto done;
}
}

View file

@ -293,7 +293,6 @@ json2xml_decode_identityref(cxobj *x,
char *ns;
char *body;
cxobj *xb;
cxobj *xa;
char *prefix = NULL;
char *id = NULL;
yang_stmt *ymod;
@ -333,12 +332,9 @@ json2xml_decode_identityref(cxobj *x,
if (prefix2 == NULL)
prefix2 = yang_find_myprefix(ymod);
/* Add "xmlns:prefix2=namespace" */
if ((xa = xml_new(prefix2, x, CX_ATTR)) == NULL)
goto done;
if (xml_prefix_set(xa, "xmlns") < 0)
goto done;
if (xml_value_set(xa, ns) < 0)
if (xml_add_attr(x, prefix2, ns, "xmlns", NULL) < 0)
goto done;
}
/* Here prefix2 is valid and can be NULL
Change body prefix to prefix2:id */

View file

@ -161,7 +161,6 @@ netconf_invalid_value_xml(cxobj **xret,
int retval =-1;
cxobj *xerr = NULL;
char *encstr = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
@ -173,9 +172,7 @@ netconf_invalid_value_xml(cxobj **xret,
}
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)
if (xml_add_attr(*xret, "xmlns", NETCONF_BASE_NAMESPACE, NULL, NULL) < 0)
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
@ -282,7 +279,6 @@ netconf_missing_attribute_xml(cxobj **xret,
int retval = -1;
cxobj *xerr = NULL;
char *encstr = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
@ -294,9 +290,7 @@ netconf_missing_attribute_xml(cxobj **xret,
}
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)
if (xml_add_attr(*xret, "xmlns", NETCONF_BASE_NAMESPACE, NULL, NULL) < 0)
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
@ -394,7 +388,6 @@ netconf_bad_attribute_xml(cxobj **xret,
int retval = -1;
cxobj *xerr = NULL;
char *encstr = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
@ -406,9 +399,7 @@ netconf_bad_attribute_xml(cxobj **xret,
}
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)
if (xml_add_attr(*xret, "xmlns", NETCONF_BASE_NAMESPACE, NULL, NULL) < 0)
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
@ -491,7 +482,6 @@ netconf_common_xml(cxobj **xret,
int retval =-1;
cxobj *xerr;
char *encstr = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
@ -500,9 +490,7 @@ netconf_common_xml(cxobj **xret,
if (*xret == NULL){
if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
goto done;
if ((xa = xml_new("xmlns", *xret, CX_ATTR)) == NULL)
goto done;
if (xml_value_set(xa, NETCONF_BASE_NAMESPACE) < 0)
if (xml_add_attr(*xret, "xmlns", NETCONF_BASE_NAMESPACE, NULL, NULL) < 0)
goto done;
}
else if (xml_name_set(*xret, "rpc-reply") < 0)
@ -751,7 +739,6 @@ netconf_access_denied_xml(cxobj **xret,
int retval =-1;
cxobj *xerr;
char *encstr = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
@ -763,9 +750,7 @@ netconf_access_denied_xml(cxobj **xret,
}
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)
if (xml_add_attr(*xret, "xmlns", NETCONF_BASE_NAMESPACE, NULL, NULL) < 0)
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
@ -987,7 +972,6 @@ netconf_data_missing_xml(cxobj **xret,
int retval = -1;
char *encstr = NULL;
cxobj *xerr;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
@ -999,9 +983,7 @@ netconf_data_missing_xml(cxobj **xret,
}
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)
if (xml_add_attr(*xret, "xmlns", NETCONF_BASE_NAMESPACE, NULL, NULL) < 0)
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
@ -1045,7 +1027,6 @@ netconf_missing_choice_xml(cxobj **xret,
int retval = -1;
char *encstr = NULL;
cxobj *xerr;
cxobj *xa;
char *path = NULL;
char *encpath = NULL;
@ -1059,9 +1040,7 @@ netconf_missing_choice_xml(cxobj **xret,
}
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)
if (xml_add_attr(*xret, "xmlns", NETCONF_BASE_NAMESPACE, NULL, NULL) < 0)
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
@ -1122,7 +1101,6 @@ netconf_operation_not_supported_xml(cxobj **xret,
int retval =-1;
cxobj *xerr;
char *encstr = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
@ -1134,9 +1112,7 @@ netconf_operation_not_supported_xml(cxobj **xret,
}
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)
if (xml_add_attr(*xret, "xmlns", NETCONF_BASE_NAMESPACE, NULL, NULL) < 0)
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
@ -1237,7 +1213,6 @@ netconf_operation_failed_xml(cxobj **xret,
int retval =-1;
cxobj *xerr;
char *encstr = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
@ -1249,9 +1224,7 @@ netconf_operation_failed_xml(cxobj **xret,
}
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)
if (xml_add_attr(*xret, "xmlns", NETCONF_BASE_NAMESPACE, NULL, NULL) < 0)
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
@ -1325,7 +1298,6 @@ netconf_malformed_message_xml(cxobj **xret,
int retval =-1;
cxobj *xerr;
char *encstr = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
@ -1337,9 +1309,7 @@ netconf_malformed_message_xml(cxobj **xret,
}
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)
if (xml_add_attr(*xret, "xmlns", NETCONF_BASE_NAMESPACE, NULL, NULL) < 0)
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
@ -1408,7 +1378,6 @@ netconf_data_not_unique_xml(cxobj **xret,
cg_var *cvi = NULL;
cxobj *xerr;
cxobj *xinfo;
cxobj *xa;
char *path = NULL;
char *encpath = NULL;
@ -1422,9 +1391,7 @@ netconf_data_not_unique_xml(cxobj **xret,
}
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)
if (xml_add_attr(*xret, "xmlns", NETCONF_BASE_NAMESPACE, NULL, NULL) < 0)
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
@ -1482,7 +1449,6 @@ netconf_minmax_elements_xml(cxobj **xret,
cxobj *xerr;
char *path = NULL;
char *encpath = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
@ -1494,9 +1460,7 @@ netconf_minmax_elements_xml(cxobj **xret,
}
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)
if (xml_add_attr(*xret, "xmlns", NETCONF_BASE_NAMESPACE, NULL, NULL) < 0)
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
@ -1528,9 +1492,9 @@ netconf_minmax_elements_xml(cxobj **xret,
* @param[in] x XML tree
* @param[in] yspec Yang spec
* @param[in,out] xret Existing XML tree, merge x into this
* @retval -1 Error (fatal)
* @retval 0 Statedata callback failed
* @retval 1 OK
* @retval 0 Statedata callback failed, error in xret?
* @retval -1 Error (fatal)
*/
int
netconf_trymerge(cxobj *x,
@ -1995,9 +1959,9 @@ clixon_netconf_internal_error(cxobj *xerr,
* @param[in] defaultstr If given, default string which is accepted and sets value to 0
* @param[in,out] cbret Output buffer for internal RPC message if invalid
* @param[out] value Value if valid
* @retval -1 Error
* @retval 0 Invalid, cbret set
* @retval 1 OK
* @retval 0 Invalid, cbret set
* @retval -1 Error
* @code
* char *name = "a";
* char *valstr = "322";
@ -2238,10 +2202,10 @@ netconf_output_encap(netconf_framing_type framing,
* @param[in] ch New input character
* @param[in,out] state State machine state
* @param[in,out] size Remaining expecting chunk bytes.
* @retval -1 Error
* @retval 0 Framing char, not data
* @retval 1 Chunk-data
* @retval 2 End-of-frame
* @retval 1 Chunk-data
* @retval 0 Framing char, not data
* @retval -1 Error
* Example:
C: \n#4\n
C: <rpc
@ -2352,3 +2316,4 @@ netconf_input_chunked_framing(char ch,
retval = -1; /* Error */
goto done;
}

View file

@ -78,6 +78,7 @@ per_datastore(clicon_handle h,
cprintf(cb, "<datastore><name>%s</name>", db);
if ((sid = xmldb_islocked(h, db)) > 0){
cprintf(cb, "<locks>");
cprintf(cb, "<global-lock>");
cprintf(cb, "<locked-by-session>%u</locked-by-session>", sid);
xmldb_lock_timestamp(h, db, &tv);
if (time2str(tv, timestr, sizeof(timestr)) < 0){
@ -85,6 +86,7 @@ per_datastore(clicon_handle h,
goto done;
}
cprintf(cb, "<locked-time>%s</locked-time>", timestr);
cprintf(cb, "</global-lock>");
cprintf(cb, "</locks>");
}
cprintf(cb, "</datastore>");
@ -175,28 +177,6 @@ netconf_monitoring_schemas(clicon_handle h,
return retval;
}
/*! Get netconf monitoring sessions state
*
* @param[in] h Clicon handle
* @param[in] yspec Yang spec
* @param[in,out] cb CLIgen buffer
* @retval -1 Error (fatal)
* @retval 0 OK
* @see RFC 6022 Section 2.1.4
* XXX: NYI
*/
static int
netconf_monitoring_sessions(clicon_handle h,
yang_stmt *yspec,
cbuf *cb)
{
int retval = -1;
retval = 0;
//done:
return retval;
}
/*! Get netconf monitoring statistics state
*
* @param[in] h Clicon handle
@ -227,11 +207,12 @@ netconf_monitoring_statistics(clicon_handle h,
* @param[in] yspec Yang spec
* @param[in] xpath XML Xpath
* @param[in] nsc XML Namespace context for xpath
* @param[in] brief Just name, revision and uri (no cache)
* @param[in,out] xret Existing XML tree, merge x into this
* @param[out] xerr XML error tree, if retval = 0
* @retval -1 Error (fatal)
* @retval 0 Statedata callback failed
* @retval 0 Statedata callback failed, error in xret
* @retval 1 OK
* @see backend_monitoring_state_get
* @see RFC 6022
*/
int
@ -239,11 +220,12 @@ netconf_monitoring_state_get(clicon_handle h,
yang_stmt *yspec,
char *xpath,
cvec *nsc,
int brief,
cxobj **xret)
cxobj **xret,
cxobj **xerr)
{
int retval = -1;
cbuf *cb = NULL;
int ret;
if ((cb = cbuf_new()) ==NULL){
clicon_err(OE_XML, errno, "cbuf_new");
@ -256,20 +238,22 @@ netconf_monitoring_state_get(clicon_handle h,
goto done;
if (netconf_monitoring_schemas(h, yspec, cb) < 0)
goto done;
if (netconf_monitoring_sessions(h, yspec, cb) < 0)
goto done;
/* sessions is backend-specific */
if (netconf_monitoring_statistics(h, yspec, cb) < 0)
goto done;
cprintf(cb, "</netconf-state>");
if (clixon_xml_parse_string(cbuf_get(cb), YB_MODULE, yspec, xret, NULL) < 0)
if ((ret = clixon_xml_parse_string(cbuf_get(cb), YB_MODULE, yspec, xret, xerr)) < 0)
goto done;
if (ret == 0){
goto fail;
}
retval = 1;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
if (cb)
cbuf_free(cb);
return retval;
// fail:
// retval = 0;
// goto done;
fail:
retval = 0;
goto done;
}

View file

@ -88,6 +88,11 @@
#define TIMEOUT_XML_FMT "<confirm-timeout>%u</confirm-timeout>"
/*! Connect to internal netconf socket
*
* @param[in] h Clixon handle
* @param[out] sockp Socket
* @retval 0 OK
* @retval -1 Error
*/
int
clicon_rpc_connect(clicon_handle h,
@ -133,10 +138,13 @@ clicon_rpc_connect(clicon_handle h,
}
/*! Connect to backend or use cached socket and send RPC
*
* @param[in] h Clixon handle
* @param[in] msg Encoded message
* @param[out] xret Returned data as netconf xml tree.
* @param[out] eof Set if eof encountered
* @retval 0 OK
* @retval -1 Error
*/
static int
clicon_rpc_msg_once(clicon_handle h,
@ -168,9 +176,12 @@ clicon_rpc_msg_once(clicon_handle h,
}
/*! Send internal netconf rpc from client to backend
*
* @param[in] h CLICON handle
* @param[in] msg Encoded message. Deallocate with free
* @param[out] xret0 Return value from backend as xml tree. Free w xml_free
* @retval 0 OK
* @retval -1 Error
* @note xret is populated with yangspec according to standard handle yangspec
* @note side-effect, a socket created here is cached
* @see clicon_rpc_msg_persistent
@ -242,11 +253,14 @@ clicon_rpc_msg(clicon_handle h,
}
/*! Send internal netconf rpc from client to backend and return a persistent socket
*
* @param[in] h CLICON handle
* @param[in] msg Encoded message. Deallocate with free
* @param[out] xret0 Return value from backend as xml tree. Free w xml_free
* @param[out] sock0 If pointer exists, do not close socket to backend on success
* and return it here. For keeping a notify socket open
* @retval 0 OK
* @retval -1 Error
* @note xret is populated with yangspec according to standard handle yangspec
*/
int
@ -311,6 +325,7 @@ clicon_rpc_msg_persistent(clicon_handle h,
}
/*! Check if there is a valid (cached) session-id. If not, send a hello request to backend
*
* Session-ids survive TCP sessions that are created for each message sent to the backend.
* Clients use two approaches, either:
* (1) Once at the beginning of the session. Netconf and restconf does this
@ -329,7 +344,7 @@ session_id_check(clicon_handle h,
uint32_t id;
if (clicon_session_id_get(h, &id) < 0){ /* Not set yet */
if (clicon_hello_req(h, &id) < 0)
if (clicon_hello_req(h, NULL, NULL, &id) < 0)
goto done;
clicon_session_id_set(h, id);
}
@ -345,6 +360,8 @@ session_id_check(clicon_handle h,
* @param[in] xmlstr XML netconf tree as string
* @param[out] xret Return XML netconf tree, error or OK (need to be freed)
* @param[out] sp Socket pointer for notification, otherwise NULL
* @retval 0 OK
* @retval -1 Error
* @code
* cxobj *xret = NULL;
* int s = -1;
@ -383,6 +400,7 @@ clicon_rpc_netconf(clicon_handle h,
}
/*! Generic xml netconf clicon rpc
*
* Want to go over to use netconf directly between client and server,...
* @param[in] h clicon handle
* @param[in] xml XML netconf tree
@ -397,7 +415,6 @@ clicon_rpc_netconf(clicon_handle h,
* err;
* xml_free(xret);
* @endcode
* @see clicon_rpc_netconf xml as string instead of tree
*/
int
@ -456,6 +473,7 @@ clicon_rpc_netconf_xml(clicon_handle h,
}
/*! Get database configuration
*
* Same as clicon_proto_change just with a cvec instead of lvec
* @param[in] h CLICON handle
* @param[in] username If NULL, use default
@ -490,7 +508,7 @@ clicon_rpc_netconf_xml(clicon_handle h,
*/
int
clicon_rpc_get_config(clicon_handle h,
char *username,
char *username, // XXX: why is this only rpc call with username parameter?
char *db,
char *xpath,
cvec *nsc,
@ -510,16 +528,20 @@ clicon_rpc_get_config(clicon_handle h,
if (session_id_check(h, &session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL)
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
if (username == NULL)
username = clicon_username_get(h);
if (username != NULL)
cprintf(cb, " username=\"%s\"", username);
if (username != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " xmlns:%s=\"%s\"",
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR);
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, "><get-config><source><%s/></source>", db);
if (xpath && strlen(xpath)){
cprintf(cb, "<%s:filter %s:type=\"xpath\" %s:select=\"%s\"",
@ -591,6 +613,7 @@ clicon_rpc_get_config(clicon_handle h,
}
/*! Send database entries as XML to backend daemon
*
* @param[in] h CLICON handle
* @param[in] db Name of database
* @param[in] op Operation on database item: OP_MERGE, OP_REPLACE
@ -620,13 +643,17 @@ clicon_rpc_edit_config(clicon_handle h,
if (session_id_check(h, &session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL)
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL)
cprintf(cb, " username=\"%s\"", username);
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, "><edit-config><target><%s/></target>", db);
cprintf(cb, "<default-operation>%s</default-operation>",
xml_operation2str(op));
@ -653,6 +680,7 @@ clicon_rpc_edit_config(clicon_handle h,
}
/*! Send a request to backend to copy a file from one location to another
*
* Note this assumes the backend can access these files and (usually) assumes
* clients and servers have the access to the same filesystem.
* @param[in] h CLICON handle
@ -676,17 +704,25 @@ clicon_rpc_copy_config(clicon_handle h,
cxobj *xerr;
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s>"
"<copy-config><source><%s/></source><target><%s/></target></copy-config></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
db1, db2)) == NULL)
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, ">");
cprintf(cb, "<copy-config><source><%s/></source><target><%s/></target></copy-config></rpc>",
db1, db2);
if ((msg = clicon_msg_encode(session_id, "%s", cbuf_get(cb))) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -696,6 +732,8 @@ clicon_rpc_copy_config(clicon_handle h,
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
if (xret)
xml_free(xret);
if (msg)
@ -704,6 +742,7 @@ clicon_rpc_copy_config(clicon_handle h,
}
/*! Send a request to backend to delete a config database
*
* @param[in] h CLICON handle
* @param[in] db database, eg "running"
* @retval 0 OK
@ -723,17 +762,25 @@ clicon_rpc_delete_config(clicon_handle h,
cxobj *xerr;
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s>"
"<edit-config><target><%s/></target><default-operation>none</default-operation><config operation=\"delete\"/></edit-config></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
db)) == NULL)
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, ">");
cprintf(cb, "<edit-config><target><%s/></target><default-operation>none</default-operation><config operation=\"delete\"/></edit-config>", db);
cprintf(cb, "</rpc>");
if ((msg = clicon_msg_encode(session_id, "%s", cbuf_get(cb))) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -743,6 +790,8 @@ clicon_rpc_delete_config(clicon_handle h,
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
if (xret)
xml_free(xret);
if (msg)
@ -766,17 +815,25 @@ clicon_rpc_lock(clicon_handle h,
cxobj *xerr;
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s>"
"<lock><target><%s/></target></lock></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
db)) == NULL)
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, ">");
cprintf(cb, "<lock><target><%s/></target></lock>", db);
cprintf(cb, "</rpc>");
if ((msg = clicon_msg_encode(session_id, "%s", cbuf_get(cb))) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -786,6 +843,8 @@ clicon_rpc_lock(clicon_handle h,
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
if (xret)
xml_free(xret);
if (msg)
@ -809,17 +868,25 @@ clicon_rpc_unlock(clicon_handle h,
cxobj *xerr;
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s>"
"<unlock><target><%s/></target></unlock></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
db)) == NULL)
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, ">");
cprintf(cb, "<unlock><target><%s/></target></unlock>", db);
cprintf(cb, "</rpc>");
if ((msg = clicon_msg_encode(session_id, "%s", cbuf_get(cb))) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -829,6 +896,8 @@ clicon_rpc_unlock(clicon_handle h,
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
if (xret)
xml_free(xret);
if (msg)
@ -894,21 +963,30 @@ clicon_rpc_get(clicon_handle h,
if (session_id_check(h, &session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL)
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL)
cprintf(cb, " username=\"%s\"", username);
cprintf(cb, " xmlns:%s=\"%s\"",
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR);
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, "><get");
/* Clixon extension, content=all,config, or nonconfig */
if ((int)content != -1)
cprintf(cb, " content=\"%s\"", netconf_content_int2str(content));
cprintf(cb, " %s:content=\"%s\" xmlns:%s=\"%s\"",
CLIXON_LIB_PREFIX,
netconf_content_int2str(content),
CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
/* Clixon extension, depth=<level> */
if (depth != -1)
cprintf(cb, " depth=\"%d\"", depth);
cprintf(cb, " %s:depth=\"%d\" xmlns:%s=\"%s\"",
CLIXON_LIB_PREFIX,
depth,
CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
cprintf(cb, ">"); /* get */
/* If xpath, add a filter */
if (xpath && strlen(xpath)) {
@ -980,6 +1058,7 @@ clicon_rpc_get(clicon_handle h,
}
/*! Get database configuration and state data collection
*
* @param[in] h Clicon handle
* @param[in] xpath To identify a list/leaf-list
* @param[in] namespace Namespace associated w xpath
@ -1033,21 +1112,31 @@ clicon_rpc_get_pageable_list(clicon_handle h,
}
if (session_id_check(h, &session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL)
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL)
cprintf(cb, " username=\"%s\"", username);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " xmlns:%s=\"%s\"",
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR);
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, "><get ");
/* Clixon extension, content=all,config, or nonconfig */
if ((int)content != -1)
cprintf(cb, " content=\"%s\"", netconf_content_int2str(content));
cprintf(cb, " %s:content=\"%s\" xmlns:%s=\"%s\"",
CLIXON_LIB_PREFIX,
netconf_content_int2str(content),
CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
/* Clixon extension, depth=<level> */
if (depth != -1)
cprintf(cb, " depth=\"%d\"", depth);
cprintf(cb, " %s:depth=\"%d\" xmlns:%s=\"%s\"",
CLIXON_LIB_PREFIX,
depth,
CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
/* declare lp prefix in get, so sub-elements dont need to */
cprintf(cb, ">"); /* get */
/* If xpath, add a filter */
@ -1152,14 +1241,25 @@ clicon_rpc_close_session(clicon_handle h)
char *username;
uint32_t session_id;
int s;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s><close-session/></rpc>",
NETCONF_BASE_NAMESPACE, username?username:"",
NETCONF_MESSAGE_ID_ATTR)) == NULL)
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, ">");
cprintf(cb, "<close-session/>");
cprintf(cb, "</rpc>");
if ((msg = clicon_msg_encode(session_id, "%s", cbuf_get(cb))) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -1173,6 +1273,8 @@ clicon_rpc_close_session(clicon_handle h)
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
if (xret)
xml_free(xret);
if (msg)
@ -1181,6 +1283,7 @@ clicon_rpc_close_session(clicon_handle h)
}
/*! Kill other user sessions
*
* @param[in] h CLICON handle
* @param[in] session_id Session id of other user session
* @retval 0 OK
@ -1196,16 +1299,25 @@ clicon_rpc_kill_session(clicon_handle h,
cxobj *xerr;
char *username;
uint32_t my_session_id; /* Not the one to kill */
cbuf *cb = NULL;
if (session_id_check(h, &my_session_id) < 0)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(my_session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s><kill-session><session-id>%u</session-id></kill-session></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
session_id)) == NULL)
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, ">");
cprintf(cb, "<kill-session><session-id>%u</session-id></kill-session>", session_id);
cprintf(cb, "</rpc>");
if ((msg = clicon_msg_encode(my_session_id, "%s", cbuf_get(cb))) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -1215,6 +1327,8 @@ clicon_rpc_kill_session(clicon_handle h,
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
if (xret)
xml_free(xret);
if (msg)
@ -1223,6 +1337,7 @@ clicon_rpc_kill_session(clicon_handle h,
}
/*! Send validate request to backend daemon
*
* @param[in] h CLICON handle
* @param[in] db Name of database
* @retval 1 OK
@ -1240,16 +1355,25 @@ clicon_rpc_validate(clicon_handle h,
cxobj *xerr;
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s><validate><source><%s/></source></validate></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
db)) == NULL)
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, ">");
cprintf(cb, "<validate><source><%s/></source></validate>", db);
cprintf(cb, "</rpc>");
if ((msg = clicon_msg_encode(session_id, "%s", cbuf_get(cb))) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -1260,6 +1384,8 @@ clicon_rpc_validate(clicon_handle h,
}
retval = 1;
done:
if (cb)
cbuf_free(cb);
if (msg)
free(msg);
if (xret)
@ -1268,6 +1394,7 @@ clicon_rpc_validate(clicon_handle h,
}
/*! Commit changes send a commit request to backend daemon
*
* @param[in] h CLICON handle
* @param[in] confirmed If set, send commit/confirmed
* @param[in] cancel If set, send cancel-commit
@ -1297,6 +1424,7 @@ clicon_rpc_commit(clicon_handle h,
char *persist_id_xml = NULL;
char *persist_xml = NULL;
char *timeout_xml = NULL;
cbuf *cb = NULL;
if (persist_id) {
if ((persist_id_xml = malloc(strlen(persist_id) + strlen(PERSIST_ID_XML_FMT) + 1)) == NULL) {
@ -1325,32 +1453,34 @@ clicon_rpc_commit(clicon_handle h,
}
if (session_id_check(h, &session_id) < 0)
goto done;
username = clicon_username_get(h);
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, ">");
if (cancel) {
msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s><cancel-commit>%s</cancel-commit></rpc>",
NETCONF_BASE_NAMESPACE,
username ? username : "",
NETCONF_MESSAGE_ID_ATTR,
cprintf(cb, "<cancel-commit>%s</cancel-commit>",
persist_id ? persist_id_xml : "");
} else if (confirmed) {
msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s><commit><confirmed/>%s%s%s</commit></rpc>",
NETCONF_BASE_NAMESPACE,
username ? username : "",
NETCONF_MESSAGE_ID_ATTR,
}
else if (confirmed) {
cprintf(cb, "<commit><confirmed/>%s%s%s</commit>",
timeout ? timeout_xml : "",
persist_id ? persist_id_xml : "",
persist ? persist_xml : "");
} else {
msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s><commit>%s</commit></rpc>",
NETCONF_BASE_NAMESPACE,
username ? username : "",
NETCONF_MESSAGE_ID_ATTR,
cprintf(cb, "<commit>%s</commit>",
persist ? persist_xml : "");
}
if (msg == NULL)
cprintf(cb, "</rpc>");
if ((msg = clicon_msg_encode(session_id, "%s", cbuf_get(cb))) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -1361,6 +1491,8 @@ clicon_rpc_commit(clicon_handle h,
}
retval = 1;
done:
if (cb)
cbuf_free(cb);
if (xret)
xml_free(xret);
if (msg)
@ -1375,6 +1507,7 @@ clicon_rpc_commit(clicon_handle h,
}
/*! Discard all changes in candidate / revert to running
*
* @param[in] h CLICON handle
* @retval 0 OK
* @retval -1 Error and logged to syslog
@ -1388,15 +1521,25 @@ clicon_rpc_discard_changes(clicon_handle h)
cxobj *xerr;
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s><discard-changes/></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_MESSAGE_ID_ATTR)) == NULL)
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, ">");
cprintf(cb, "<discard-changes/>");
cprintf(cb, "</rpc>");
if ((msg = clicon_msg_encode(session_id, "%s", cbuf_get(cb))) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -1406,6 +1549,8 @@ clicon_rpc_discard_changes(clicon_handle h)
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
if (xret)
xml_free(xret);
if (msg)
@ -1414,13 +1559,13 @@ clicon_rpc_discard_changes(clicon_handle h)
}
/*! Create a new notification subscription
*
* @param[in] h Clicon handle
* @param{in] stream name of notificatio/log stream (CLICON is predefined)
* @param{in] filter message filter, eg xpath for xml notifications
* @param[out] s0 socket returned where notification mesages will appear
* @retval 0 OK
* @retval -1 Error and logged to syslog
* @note When using netconf create-subsrciption,status and format is not supported
*/
int
@ -1435,20 +1580,31 @@ clicon_rpc_create_subscription(clicon_handle h,
cxobj *xerr;
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s><create-subscription xmlns=\"%s\">"
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, ">");
cprintf(cb, "<create-subscription xmlns=\"%s\">"
"<stream>%s</stream>"
"<filter type=\"xpath\" select=\"%s\" />"
"</create-subscription></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
"</create-subscription>",
EVENT_RFC5277_NAMESPACE,
stream?stream:"", filter?filter:"")) == NULL)
stream?stream:"",
filter?filter:"");
cprintf(cb, "</rpc>");
if ((msg = clicon_msg_encode(session_id, "%s", cbuf_get(cb))) == NULL)
goto done;
if (clicon_rpc_msg_persistent(h, msg, &xret, s0) < 0)
goto done;
@ -1458,6 +1614,8 @@ clicon_rpc_create_subscription(clicon_handle h,
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
if (xret)
xml_free(xret);
if (msg)
@ -1466,6 +1624,7 @@ clicon_rpc_create_subscription(clicon_handle h,
}
/*! Send a debug request to backend server
*
* @param[in] h CLICON handle
* @param[in] level Debug level
* @retval 0 OK
@ -1481,17 +1640,26 @@ clicon_rpc_debug(clicon_handle h,
cxobj *xerr;
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s><debug xmlns=\"%s\"><level>%d</level></debug></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
CLIXON_LIB_NS,
level)) == NULL)
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, ">");
cprintf(cb, "<debug xmlns=\"%s\"><level>%d</level></debug>", CLIXON_LIB_NS, level);
cprintf(cb, "</rpc>");
if ((msg = clicon_msg_encode(session_id, "%s", cbuf_get(cb))) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -1505,6 +1673,8 @@ clicon_rpc_debug(clicon_handle h,
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
if (msg)
free(msg);
if (xret)
@ -1532,17 +1702,29 @@ clicon_rpc_restconf_debug(clicon_handle h,
cxobj *xerr;
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<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,
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, ">");
cprintf(cb, "<edit-config><target><candidate/></target><config>");
cprintf(cb, "<restconf xmlns=\"%s\"><debug>%d</debug></restconf>",
CLIXON_RESTCONF_NS,
level)) == NULL)
level);
cprintf(cb, "</config></edit-config>");
cprintf(cb, "</rpc>");
if ((msg = clicon_msg_encode(session_id, "%s", cbuf_get(cb))) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -1557,6 +1739,8 @@ clicon_rpc_restconf_debug(clicon_handle h,
if ((retval = clicon_rpc_commit(h, 0, 0, 0, NULL, NULL)) < 1)
goto done;
done:
if (cb)
cbuf_free(cb);
if (msg)
free(msg);
if (xret)
@ -1564,17 +1748,25 @@ clicon_rpc_restconf_debug(clicon_handle h,
return retval;
}
/*! Send a hello request to the backend server
* @param[in] h CLICON handle
* @param[in] level Debug level
/*! Send a hello request to the backend server on INTERNAL netconf connection
*
* @param[in] h Clixon handle
* @param[in] transport RFC 6022 transport.
* @param[in] source_host RFC 6022 source-host
* @param[out] id Session id returned by backend
* @retval 0 OK
* @retval -1 Error and logged to syslog
* @note this is internal netconf to backend, not northbound to user client
* @note this deviates from RFC6241 slightly in that it waits for a reply, the RFC does not
* stipulate that.
* @note transport is an identity defined in RFC6022 with added values in clixon-lib.yang for clixon,
* and should in those cases be prefixed with the localname "cl:",
* Example: cl:cli, cl:restconf, cl:netconf
*/
int
clicon_hello_req(clicon_handle h,
char *transport,
char *source_host,
uint32_t *id)
{
int retval = -1;
@ -1585,12 +1777,39 @@ clicon_hello_req(clicon_handle h,
char *username;
char *b;
int ret;
cbuf *cb = NULL;
int clixon_lib = 0;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(0, "<hello username=\"%s\" xmlns=\"%s\"><capabilities><capability>%s</capability></capabilities></hello>",
username?username:"",
NETCONF_BASE_NAMESPACE,
NETCONF_BASE_CAPABILITY_1_1)) == NULL)
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<hello xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
clixon_lib++;
}
/* RFC 6022 session parameters transport and source-host */
if (transport == NULL)
clicon_data_get(h, "session-transport", &transport);
if (transport){
cprintf(cb, " %s:transport=\"%s\"", CLIXON_LIB_PREFIX, transport);
clixon_lib++;
}
if (source_host == NULL)
clicon_data_get(h, "session-source-host", &source_host);
if (source_host){
cprintf(cb, " %s:source-host=\"%s\"", CLIXON_LIB_PREFIX, source_host);
clixon_lib++;
}
if (clixon_lib)
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
cprintf(cb, ">");
cprintf(cb, "<capabilities><capability>%s</capability></capabilities>",
NETCONF_BASE_CAPABILITY_1_1);
cprintf(cb, "</hello>");
if ((msg = clicon_msg_encode(0, "%s", cbuf_get(cb))) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -1609,6 +1828,8 @@ clicon_hello_req(clicon_handle h,
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
if (msg)
free(msg);
if (xret)
@ -1617,6 +1838,7 @@ clicon_hello_req(clicon_handle h,
}
/*! Send a restart plugin request to backend server
*
* @param[in] h CLICON handle
* @param[in] level Debug level
* @retval 0 OK
@ -1632,17 +1854,26 @@ clicon_rpc_restart_plugin(clicon_handle h,
cxobj *xerr;
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" %s><restart-plugin xmlns=\"%s\"><plugin>%s</plugin></restart-plugin></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
CLIXON_LIB_NS,
plugin)) == NULL)
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL){
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, ">");
cprintf(cb, "<restart-plugin xmlns=\"%s\"><plugin>%s</plugin></restart-plugin>",
CLIXON_LIB_NS, plugin);
cprintf(cb, "</rpc>");
if ((msg = clicon_msg_encode(session_id, "%s", cbuf_get(cb))) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -1656,6 +1887,8 @@ clicon_rpc_restart_plugin(clicon_handle h,
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
if (msg)
free(msg);
if (xret)

View file

@ -2332,6 +2332,42 @@ xml_attr_insert2val(char *instr,
return 0;
}
/*! Add attribute and value to an xml element as well as namespace mapping
*
* @param[in] xn XML element
* @param[in] name Attribute name
* @param[in] value Attribute value
* @param[in] prefix Attribute prefix, or NULL
* @param[in] namespace Attribute prefix, if NULL do not add namespace mapping
*/
int
xml_add_attr(cxobj *xn,
char *name,
char *value,
char *prefix,
char *namespace)
{
int retval = -1;
cxobj *xa;
char *ns = NULL;
if ((xa = xml_new(name, xn, CX_ATTR)) == NULL)
goto done;
if (prefix && xml_prefix_set(xa, prefix) < 0) /* clixon lib */
goto done;
if (xml_value_set(xa, value) < 0)
goto done;
if (namespace){
if (xml2ns(xn, prefix, &ns) < 0)
goto done;
if (ns == NULL && xmlns_set(xn, prefix, namespace) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
/*! Specialization of clicon_debug with xml tree
* @param[in] level log level, eg LOG_DEBUG,LOG_INFO,...,LOG_EMERG.
* @param[in] x XML tree that is logged without prettyprint

View file

@ -611,15 +611,10 @@ xml_add_default_tag(cxobj *x,
uint16_t flags)
{
int retval = -1;
cxobj *xattr;
if (xml_flag(x, flags)) {
/* set default attribute */
if ((xattr = xml_new("default", x, CX_ATTR)) == NULL)
goto done;
if (xml_value_set(xattr, "true") < 0)
goto done;
if (xml_prefix_set(xattr, IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX) < 0)
if (xml_add_attr(x, "default", "true", IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX, NULL) < 0)
goto done;
}
retval = 0;

View file

@ -648,7 +648,6 @@ xml_namespace_change(cxobj *x,
/* Add prefix to x, if any */
if (prefix && xml_prefix_set(x, prefix) < 0)
goto done;
}
ok:
retval = 0;

View file

@ -569,6 +569,7 @@ xml2ns_recurse(cxobj *xt)
* @retval 0 OK
* @retval -1 Error
* @see xml2ns
* @see xml_add_attr generic method for adding an attribute
*/
int
xmlns_set(cxobj *x,

View file

@ -82,6 +82,12 @@
#include "clixon_xml_map.h"
#include "clixon_yang_parse_lib.h"
/*! Create modstate structure
*
* @retval md modstate struct
* @retval NULL Error
* @see modstate_diff_free
*/
modstate_diff_t *
modstate_diff_new(void)
{
@ -95,6 +101,12 @@ modstate_diff_new(void)
return md;
}
/*! Free modstate structure
*
* @param[in] md Modstate struct
* @retval 0 OK
* @see modstate_diff_new
*/
int
modstate_diff_free(modstate_diff_t *md)
{
@ -112,6 +124,8 @@ modstate_diff_free(modstate_diff_t *md)
*
* Load RFC7895 yang spec, module-set-id, etc.
* @param[in] h Clicon handle
* @retval 0 OK
* @retval -1 Error
* @see netconf_module_load
*/
int
@ -167,6 +181,13 @@ yang_modules_revision(clicon_handle h)
/*! Actually build the yang modules state XML tree according to RFC8525
*
* @param[in] h Clixon handle
* @param[in] yspec
* @param[in] msid
* @param[in] brief
* @param[out] cb
* @retval 0 OK
* @retval -1 Error
* This assumes CLICON_YANG_LIBRARY is enabled
* If also CLICON_MODULE_LIBRARY_RFC7895 is set, module-state is built according to RFC7895 instead
* @see RFC8525
@ -277,9 +298,9 @@ yms_build(clicon_handle h,
* @param[in] nsc XML Namespace context for xpath
* @param[in] brief Just name, revision and uri (no cache)
* @param[in,out] xret Existing XML tree, merge x into this
* @retval -1 Error (fatal)
* @retval 0 Statedata callback failed
* @retval 1 OK
* @retval 0 Statedata callback failed
* @retval -1 Error (fatal)
* @notes NYI: schema, deviation
x +--ro modules-state
x +--ro module-set-id string

View file

@ -73,8 +73,8 @@ DATASTORE_TOP="config"
# clixon yang revisions occuring in tests (see eg yang/clixon/Makefile.in)
CLIXON_AUTOCLI_REV="2022-02-11"
CLIXON_LIB_REV="2021-12-05"
CLIXON_CONFIG_REV="2022-03-21"
CLIXON_LIB_REV="2022-12-01"
CLIXON_CONFIG_REV="2022-12-01"
CLIXON_RESTCONF_REV="2022-08-01"
CLIXON_EXAMPLE_REV="2022-11-01"

View file

@ -68,16 +68,13 @@ new "wait backend"
wait_backend
new "Retrieving all state via <get> operation"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get/></rpc>" "<rpc-reply $DEFAULTNS><data><netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\"><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability><capability>urn:ietf:params:netconf:base:1.1</capability>.*<capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring</capability>.*</capabilities><datastores><datastore><name>candidate</name></datastore><datastore><name>running</name></datastore></datastores><schemas>.*</schemas></netconf-state></data></rpc-reply>"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get/></rpc>" "<rpc-reply $DEFAULTNS><data><netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\"><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability><capability>urn:ietf:params:netconf:base:1.1</capability>.*<capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring</capability>.*</capabilities><datastores><datastore><name>candidate</name></datastore><datastore><name>running</name></datastore></datastores><schemas>.*</schemas><sessions>.*</sessions></netconf-state></data></rpc-reply>"
# send multiple frames
rpc=$(chunked_framing "<rpc $DEFAULTNS><lock><target><candidate/></target></lock></rpc>")
rpc="${rpc}
$(chunked_framing "<rpc $DEFAULTNS><get><filter type=\"subtree\"><netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\"><datastores><datastore><name>candidate</name></datastore></datastores></netconf-state></filter></get></rpc>")"
reply=$(chunked_framing "<rpc-reply $DEFAULTNS><ok/>/rpc-reply")
reply=${reply}$(chunked_framing "<rpc-reply $DEFAULTNS><data><netconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring"><datastores><datastore><name>candidate</name><locks><locked-by-session>3</locked-by-session><locked-time>2022-12-23T13:18:57.112204Z</locked-time></locks></datastore></datastores></netconf-state></data></rpc-reply")
new "Get databases with lock"
ret=$($clixon_netconf -q -f $cfg <<EOF
$DEFAULTHELLO$rpc
@ -87,7 +84,7 @@ r=$?
if [ $r -ne 0 ]; then
err "0" "$r"
fi
for expect in "<rpc-reply $DEFAULTNS><ok/></rpc-reply>" "<rpc-reply $DEFAULTNS><data><netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\"><datastores><datastore><name>candidate</name><locks><locked-by-session>[0-9]+</locked-by-session><locked-time>202.*Z</locked-time></locks></datastore></datastores></netconf-state></data></rpc-reply"; do
for expect in "<rpc-reply $DEFAULTNS><ok/></rpc-reply>" "<rpc-reply $DEFAULTNS><data><netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\"><datastores><datastore><name>candidate</name><locks><global-lock><locked-by-session>[0-9]+</locked-by-session><locked-time>202.*Z</locked-time></global-lock></locks></datastore></datastores></netconf-state></data></rpc-reply"; do
new "expect:$expect"
match=`echo $ret | grep --null -Eo "$expect"`
if [ -z "$match" ]; then
@ -100,6 +97,10 @@ done
new "Retrieving Schema List via <get> Operation"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"subtree\"><netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\"><schemas/></netconf-state></filter></get></rpc>" "<rpc-reply $DEFAULTNS><data><netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\"><schemas><schema><identifier>clixon-example</identifier><version>2022-01-01</version><format>yang</format><namespace>urn:example:clixon</namespace><location>NETCONF</location></schema>.*<schema><identifier>clixon-sub</identifier><version>2022-01-01</version><format>yang</format><namespace>urn:example:clixon</namespace><location>NETCONF</location></schema><schema>.*</schemas></netconf-state></data></rpc-reply>"
# Session
new "Retrieve Session"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"subtree\"><netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\"><sessions/></netconf-state></filter></get></rpc>" "<rpc-reply $DEFAULTNS><data><netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\"><sessions><session><session-id>[1-9][0-9]*</session-id><transport xmlns:cl=\"http://clicon.org/lib\">cl:netconf</transport><username>.*</username><login-time>.*</login-time><in-rpcs>[0-9][0-9]*</in-rpcs><in-bad-rpcs>[0-9][0-9]*</in-bad-rpcs><out-rpc-errors>[0-9][0-9]*</out-rpc-errors><out-notifications>[0-9][0-9]*</out-notifications></session>.*</sessions></netconf-state></data></rpc-reply>"
# 4.2. Retrieving Schema Instances
# From 2b. bar, version 2008-06-1 in YANG format, via get-schema
new "Retrieving clixon-example schema instance using id, version, format"

View file

@ -43,7 +43,7 @@ YANG_INSTALLDIR = @YANG_INSTALLDIR@
# Note: mirror these to test/config.sh.in
YANGSPECS = clixon-config@2022-12-01.yang # 6.1
YANGSPECS += clixon-lib@2021-12-05.yang # 5.5
YANGSPECS += clixon-lib@2022-12-01.yang # 6.1
YANGSPECS += clixon-rfc5277@2008-07-01.yang
YANGSPECS += clixon-xml-changelog@2019-03-21.yang
YANGSPECS += clixon-restconf@2022-08-01.yang # 5.9

View file

@ -15,6 +15,19 @@ module clixon-lib {
description
"Clixon Netconf extensions for communication between clients and backend.
Clixon extends NETCONF for internal use with some internal attributes. These
are not visible for external usage bit belongs to the namespace of this YANG.
The internal attributes are:
- content (also RESTCONF)
- depth (also RESTCONF)
- username
- autocommit
- copystartup
- transport (see RFC6022)
- source-host (see RFC6022)
- objectcreate
- objectexisted
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2019 Olof Hagsand
Copyright (C) 2020-2021 Olof Hagsand and Rubicon Communications, LLC(Netgate)

View file

@ -6,6 +6,9 @@ module clixon-lib {
import ietf-yang-types {
prefix yang;
}
import ietf-netconf-monitoring {
prefix ncm;
}
organization
"Clicon / Clixon";
@ -13,9 +16,7 @@ module clixon-lib {
"Olof Hagsand <olof@hagsand.se>";
description
"Clixon Netconf extensions for communication between clients and backend.
***** BEGIN LICENSE BLOCK *****
"***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2019 Olof Hagsand
Copyright (C) 2020-2021 Olof Hagsand and Rubicon Communications, LLC(Netgate)
@ -42,8 +43,37 @@ module clixon-lib {
the provisions above, a recipient may use your version of this file under
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****";
***** END LICENSE BLOCK *****
Clixon Netconf extensions for communication between clients and backend.
This scheme adds:
- Added values of RFC6022 transport identityref
- RPCs for debug, stats and process-control
- Informal description of attributes
Additionally, Clixon extends NETCONF for internal use with some internal attributes. These
are not visible for external usage bit belongs to the namespace of this YANG.
The internal attributes are:
- content (also RESTCONF)
- depth (also RESTCONF)
- username
- autocommit
- copystartup
- transport (see RFC6022)
- source-host (see RFC6022)
- objectcreate
- objectexisted
";
revision 2022-12-01 {
description
"Added values of RFC6022 transport identityref
Added description of internal netconf attributes";
}
revision 2021-12-05 {
description
"Obsoleted: extension autocli-op";
}
revision 2021-11-11 {
description
"Changed: RPC stats extended with YANG stats";
@ -101,6 +131,23 @@ module clixon-lib {
description
"Common operations that can be performed on a service";
}
identity snmp {
description
"SNMP";
base ncm:transport;
}
identity netconf {
description
"Just NETCONF without specitic underlying transport,
Clixon uses stdio for its netconf client and therefore does not know whether it is
invoked in a script, by a NETCONF/SSH subsystem, etc";
base ncm:transport;
}
identity restconf {
description
"RESTCONF either as HTTP/1 or /2, TLS or not, reverese proxy (eg fcgi/nginx) or native";
base ncm:transport;
}
extension autocli-op {
description
"Takes an argument an operation defing how to modify the clispec at
@ -109,8 +156,10 @@ module clixon-lib {
Operations is expected to be extended, but the following operations are defined:
- hide This command is active but not shown by ? or TAB (meaning, it hides the auto-completion of commands)
- hide-database This command hides the database
- hide-database-auto-completion This command hides the database and the auto completion (meaning, this command acts as both commands above)";
- hide-database-auto-completion This command hides the database and the auto completion (meaning, this command acts as both commands above)
Obsolete: use clixon-autocli:hide and clixon-autocli:hide-show instead";
argument cliop;
status obsolete;
}
rpc debug {
description "Set debug level of backend.";