Netconf monitoring statistics frm RFC 6022

This commit is contained in:
Olof hagsand 2023-02-02 16:42:00 +01:00
parent 5da8ce211a
commit 6681eb99d3
13 changed files with 186 additions and 39 deletions

View file

@ -51,14 +51,15 @@ Expected: beginning of 2023
* New plugin callback: `ca_yang_mount` * New plugin callback: `ca_yang_mount`
* Standards: RFC 8528 * Standards: RFC 8528
* To enable configure with `--enable-yang-schema-mount` * To enable configure with `--enable-yang-schema-mount`
* Netconf monitoring RFC 6022 , part 2 * Netconf monitoring RFC 6022
* Datastores and sessions * This is part 2, first part was in 6.0
* Datastores, sessions and statistics
* Added clixon-specific transport identities: cli, snmp, netconf, restconf * Added clixon-specific transport identities: cli, snmp, netconf, restconf
* Added source-host fro native restonf, but no other transports * Added source-host from native restonf, but no other transports
* Hello statistics is based on backend statistics, hellos from RESTCONF, SNMP and CLI clients are included and dropped external NETCONF sessions are not
* Standards * Standards
* RFC 6022 "YANG Module for NETCONF Monitoring" * RFC 6022 "YANG Module for NETCONF Monitoring"
* See [Feature Request: Support RFC 6022 (NETCONF Monitoring)](https://github.com/clicon/clixon/issues/370) * See [Feature Request: Support RFC 6022 (NETCONF Monitoring)](https://github.com/clicon/clixon/issues/370)
* Remaining: statistics state
### API changes on existing protocol/config features ### API changes on existing protocol/config features

View file

@ -32,7 +32,7 @@
the terms of any one of the Apache License version 2 or the GPL. the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK ***** ***** END LICENSE BLOCK *****
* note: there is also client code in clixon_backend_handle.c
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
@ -117,6 +117,9 @@ ce_event_cb(clicon_handle h,
} }
break; break;
} }
/* note there may be other notifications than RFC5277 streams */
ce->ce_out_notifications++;
netconf_monitoring_counter_inc(h, "out-notifications");
} }
return 0; return 0;
} }
@ -218,7 +221,7 @@ backend_monitoring_state_get(clicon_handle h,
cprintf(cb, "<in-rpcs>%u</in-rpcs>", ce->ce_in_rpcs); 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, "<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-rpc-errors>%u</out-rpc-errors>", ce->ce_out_rpc_errors);
cprintf(cb, "<out-notifications>%u</out-notifications>", 0); cprintf(cb, "<out-notifications>%u</out-notifications>", ce->ce_out_notifications);
cprintf(cb, "</session>"); cprintf(cb, "</session>");
} }
cprintf(cb, "</sessions>"); cprintf(cb, "</sessions>");
@ -263,7 +266,6 @@ backend_client_rm(clicon_handle h,
clicon_err(OE_YANG, ENOENT, "No yang spec"); clicon_err(OE_YANG, ENOENT, "No yang spec");
goto done; goto done;
} }
if (if_feature(yspec, "ietf-netconf", "confirmed-commit")) { if (if_feature(yspec, "ietf-netconf", "confirmed-commit")) {
if (confirmed_commit_state_get(h) == EPHEMERAL) { if (confirmed_commit_state_get(h) == EPHEMERAL) {
/* See if this client is the origin */ /* See if this client is the origin */
@ -301,9 +303,8 @@ backend_client_rm(clicon_handle h,
ce_prev = &c->ce_next; ce_prev = &c->ce_next;
} }
retval = backend_client_delete(h, ce); /* actually purge it */ retval = backend_client_delete(h, ce); /* actually purge it */
done:
done: return retval;
return retval;
} }
/*! Get clixon per datastore stats /*! Get clixon per datastore stats
@ -325,7 +326,6 @@ clixon_stats_datastore_get(clicon_handle h,
cxobj *xn = NULL; cxobj *xn = NULL;
/* This is the db cache */ /* This is the db cache */
if ((xt = xmldb_cache_get(h, dbname)) == NULL){ if ((xt = xmldb_cache_get(h, dbname)) == NULL){
/* Trigger cache if no exist */ /* Trigger cache if no exist */
if (xmldb_get(h, dbname, NULL, "/", &xn) < 0) if (xmldb_get(h, dbname, NULL, "/", &xn) < 0)
@ -1604,7 +1604,6 @@ from_client_msg(clicon_handle h,
} }
if (strcmp(rpcname, "rpc") == 0){ if (strcmp(rpcname, "rpc") == 0){
ce->ce_in_rpcs++; /* Track all RPCs */
} }
else if (strcmp(rpcname, "hello") == 0){ else if (strcmp(rpcname, "hello") == 0){
if ((ret = from_client_hello(h, x, ce, cbret)) <0) if ((ret = from_client_hello(h, x, ce, cbret)) <0)
@ -1616,21 +1615,29 @@ from_client_msg(clicon_handle h,
goto done; goto done;
ce->ce_in_bad_rpcs++; ce->ce_in_bad_rpcs++;
ce->ce_out_rpc_errors++; /* Number of <rpc-reply> messages sent that contained an <rpc-error> */ ce->ce_out_rpc_errors++; /* Number of <rpc-reply> messages sent that contained an <rpc-error> */
netconf_monitoring_counter_inc(h, "in-bad-rpcs");
netconf_monitoring_counter_inc(h, "out-rpc-errors");
goto reply; goto reply;
} }
/* As a side-effect, this expands xt with default values according to "report-all" /* 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 * This may not be correct, the RFC does not mention expanding default values for
* input RPC * input RPC
*/ */
if ((ret = xml_yang_validate_rpc(h, x, 1, &xret)) < 0) if ((ret = xml_yang_validate_rpc(h, x, 1, &xret)) < 0){
ce->ce_in_bad_rpcs++;
netconf_monitoring_counter_inc(h, "in-bad-rpcs");
goto done; goto done;
}
if (ret == 0){ if (ret == 0){
if (clixon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0) if (clixon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
goto done; goto done;
ce->ce_in_bad_rpcs++; ce->ce_in_bad_rpcs++;
ce->ce_in_rpcs--; /* Track all RPCs */ netconf_monitoring_counter_inc(h, "in-bad-rpcs");
goto reply; goto reply;
} }
ce->ce_in_rpcs++; /* Track all RPCs */
netconf_monitoring_counter_inc(h, "in-rpcs");
xe = NULL; xe = NULL;
username = xml_find_value(x, "username"); username = xml_find_value(x, "username");
/* May be used by callbacks, etc */ /* May be used by callbacks, etc */
@ -1641,6 +1648,7 @@ from_client_msg(clicon_handle h,
if (netconf_operation_not_supported(cbret, "protocol", rpc) < 0) if (netconf_operation_not_supported(cbret, "protocol", rpc) < 0)
goto done; goto done;
ce->ce_out_rpc_errors++; ce->ce_out_rpc_errors++;
netconf_monitoring_counter_inc(h, "out-rpc-errors");
goto reply; goto reply;
} }
if ((ymod = ys_module(ye)) == NULL){ if ((ymod = ys_module(ye)) == NULL){
@ -1669,6 +1677,7 @@ from_client_msg(clicon_handle h,
goto done; goto done;
if (ret == 0){ /* credentials fail */ if (ret == 0){ /* credentials fail */
ce->ce_out_rpc_errors++; ce->ce_out_rpc_errors++;
netconf_monitoring_counter_inc(h, "out-rpc-errors");
goto reply; goto reply;
} }
/* NACM rpc operation exec validation */ /* NACM rpc operation exec validation */
@ -1676,6 +1685,7 @@ from_client_msg(clicon_handle h,
goto done; goto done;
if (ret == 0){ /* Not permitted and cbret set */ if (ret == 0){ /* Not permitted and cbret set */
ce->ce_out_rpc_errors++; ce->ce_out_rpc_errors++;
netconf_monitoring_counter_inc(h, "out-rpc-errors");
goto reply; goto reply;
} }
} }
@ -1685,16 +1695,19 @@ from_client_msg(clicon_handle h,
goto done; goto done;
clicon_log(LOG_NOTICE, "%s Error in rpc_callback_call:%s", __FUNCTION__, xml_name(xe)); clicon_log(LOG_NOTICE, "%s Error in rpc_callback_call:%s", __FUNCTION__, xml_name(xe));
ce->ce_out_rpc_errors++; ce->ce_out_rpc_errors++;
netconf_monitoring_counter_inc(h, "out-rpc-errors");
goto reply; /* Dont quit here on user callbacks */ goto reply; /* Dont quit here on user callbacks */
} }
if (ret == 0){ if (ret == 0){
ce->ce_out_rpc_errors++; ce->ce_out_rpc_errors++;
netconf_monitoring_counter_inc(h, "out-rpc-errors");
goto reply; goto reply;
} }
if (nr == 0){ /* not handled by callback */ if (nr == 0){ /* not handled by callback */
if (netconf_operation_not_supported(cbret, "application", "RPC operation not supported")< 0) if (netconf_operation_not_supported(cbret, "application", "RPC operation not supported")< 0)
goto done; goto done;
ce->ce_out_rpc_errors++; ce->ce_out_rpc_errors++;
netconf_monitoring_counter_inc(h, "out-rpc-errors");
goto reply; goto reply;
} }
if (xnacm){ if (xnacm){
@ -1775,8 +1788,10 @@ from_client(int s,
} }
if (clicon_msg_rcv(ce->ce_s, &msg, &eof) < 0) if (clicon_msg_rcv(ce->ce_s, &msg, &eof) < 0)
goto done; goto done;
if (eof) if (eof){
backend_client_rm(h, ce); backend_client_rm(h, ce);
netconf_monitoring_counter_inc(h, "dropped-sessions");
}
else else
if (from_client_msg(h, ce, msg) < 0) if (from_client_msg(h, ce, msg) < 0)
goto done; goto done;

View file

@ -62,6 +62,7 @@ struct client_entry{
uint32_t ce_in_rpcs ; /* Number of correct <rpc> messages received. */ uint32_t ce_in_rpcs ; /* Number of correct <rpc> messages received. */
uint32_t ce_in_bad_rpcs; /* Not correct <rpc> messages */ uint32_t ce_in_bad_rpcs; /* Not correct <rpc> messages */
uint32_t ce_out_rpc_errors; /* <rpc-error> messages*/ uint32_t ce_out_rpc_errors; /* <rpc-error> messages*/
uint32_t ce_out_notifications; /* Outgoing notifications */
}; };
/* /*

View file

@ -121,9 +121,9 @@ restconf_client_get_capabilities(clicon_handle h,
* @param[in] module Name of yang module * @param[in] module Name of yang module
* @param[in] top Top symbol, ie netconf or restconf-state * @param[in] top Top symbol, ie netconf or restconf-state
* @param[in,out] xret Existing XML tree, merge x into this * @param[in,out] xret Existing XML tree, merge x into this
* @retval -1 Error (fatal)
* @retval 0 Statedata callback failed
* @retval 1 OK * @retval 1 OK
* @retval 0 Statedata callback failed
* @retval -1 Error (fatal)
*/ */
static int static int
client_get_streams(clicon_handle h, client_get_streams(clicon_handle h,
@ -182,9 +182,9 @@ client_get_streams(clicon_handle h,
* @param[in] nsc XML Namespace context for xpath * @param[in] nsc XML Namespace context for xpath
* @param[in] wdef With-defaults parameter, see RFC 6243 * @param[in] wdef With-defaults parameter, see RFC 6243
* @param[in,out] xret Existing XML tree, merge x into this, or rpc-error * @param[in,out] xret Existing XML tree, merge x into this, or rpc-error
* @retval -1 Error (fatal)
* @retval 0 Statedata callback failed (error in xret)
* @retval 1 OK * @retval 1 OK
* @retval 0 Statedata callback failed (error in xret)
* @retval -1 Error (fatal)
* @note This code in general does not look at xpath, needs to be filtered in retrospect * @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 * @note Awkward error handling. Even if most of this is during development phase, except for plugin
* state callbacks. * state callbacks.
@ -497,9 +497,9 @@ get_nacm_and_reply(clicon_handle h,
* @param[in] defaultstr Default string which is accepted and sets value to 0 * @param[in] defaultstr Default string which is accepted and sets value to 0
* @param[in,out] cbret Output buffer for internal bad-element RPC message if invalid * @param[in,out] cbret Output buffer for internal bad-element RPC message if invalid
* @param[out] value Value * @param[out] value Value
* @retval -1 Error
* @retval 0 Invalid, netconf bad-element error cbret set
* @retval 1 OK (or not found) * @retval 1 OK (or not found)
* @retval 0 Invalid, netconf bad-element error cbret set
* @retval -1 Error
*/ */
static int static int
element2value(clicon_handle h, element2value(clicon_handle h,
@ -527,9 +527,9 @@ element2value(clicon_handle h,
* @param[out] offset Number of entries in the working result-set that should be skipped * @param[out] offset Number of entries in the working result-set that should be skipped
* @param[out] limit Limits the number of entries returned from the working result-set * @param[out] limit Limits the number of entries returned from the working result-set
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error.. * @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @retval -1 Error
* @retval 0 Invalid, netconf bad-element error cbret set
* @retval 1 OK * @retval 1 OK
* @retval 0 Invalid, netconf bad-element error cbret set
* @retval -1 Error
*/ */
static int static int
list_pagination_hdr(clicon_handle h, list_pagination_hdr(clicon_handle h,

View file

@ -1066,6 +1066,8 @@ main(int argc,
if (stream_timer_setup(0, h) < 0) if (stream_timer_setup(0, h) < 0)
goto done; goto done;
/* Just before event-loop, after socket bind/listen */ /* Just before event-loop, after socket bind/listen */
if (netconf_monitoring_statistics_init(h) < 0)
goto done;
clicon_log(LOG_NOTICE, "%s: %u Started", __PROGRAM__, getpid()); clicon_log(LOG_NOTICE, "%s: %u Started", __PROGRAM__, getpid());
if (clixon_event_loop(h) < 0) if (clixon_event_loop(h) < 0)
goto done; goto done;

View file

@ -152,6 +152,7 @@ backend_client_add(clicon_handle h,
} }
clicon_session_id_set(h, ce->ce_id + 1); clicon_session_id_set(h, ce->ce_id + 1);
gettimeofday(&ce->ce_time, NULL); gettimeofday(&ce->ce_time, NULL);
netconf_monitoring_counter_inc(h, "in-sessions");
bh->bh_ce_list = ce; bh->bh_ce_list = ce;
return ce; return ce;
} }

View file

@ -42,5 +42,7 @@
* Prototypes * Prototypes
*/ */
int netconf_monitoring_state_get(clicon_handle h, yang_stmt *yspec, char *xpath, cvec *nsc, cxobj **xret, cxobj **xerr); int netconf_monitoring_state_get(clicon_handle h, yang_stmt *yspec, char *xpath, cvec *nsc, cxobj **xret, cxobj **xerr);
int netconf_monitoring_statistics_init(clicon_handle h);
int netconf_monitoring_counter_inc(clicon_handle h, char *name);
#endif /* _CLIXON_NETCONF_MONITORING_H_ */ #endif /* _CLIXON_NETCONF_MONITORING_H_ */

View file

@ -102,7 +102,7 @@ clicon_data_get(clicon_handle h,
/*! Set generic clixon data on the form <name>=<val> where <val> is string /*! Set generic clixon data on the form <name>=<val> where <val> is string
* @param[in] h Clicon handle * @param[in] h Clicon handle
* @param[in] name Data name * @param[in] name Data name
* @param[in] val Data value as null-terminated string * @param[in] val Data value as null-terminated string (copied)
* @retval 0 OK * @retval 0 OK
* @retval -1 Error * @retval -1 Error
* @see clicon_option_str_set * @see clicon_option_str_set

View file

@ -41,6 +41,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
#include <ctype.h> #include <ctype.h>
@ -62,6 +63,7 @@
#include "clixon_netconf_lib.h" #include "clixon_netconf_lib.h"
#include "clixon_options.h" #include "clixon_options.h"
#include "clixon_err.h" #include "clixon_err.h"
#include "clixon_data.h"
#include "clixon_datastore.h" #include "clixon_datastore.h"
#include "clixon_netconf_monitoring.h" #include "clixon_netconf_monitoring.h"
@ -100,8 +102,8 @@ per_datastore(clicon_handle h,
* @param[in] h Clicon handle * @param[in] h Clicon handle
* @param[in] yspec Yang spec * @param[in] yspec Yang spec
* @param[in,out] cb CLIgen buffer * @param[in,out] cb CLIgen buffer
* @retval -1 Error (fatal)
* @retval 0 OK * @retval 0 OK
* @retval -1 Error (fatal)
* @see RFC 6022 Section 2.1.2 * @see RFC 6022 Section 2.1.2
*/ */
static int static int
@ -131,8 +133,8 @@ netconf_monitoring_datastores(clicon_handle h,
* @param[in] h Clicon handle * @param[in] h Clicon handle
* @param[in] yspec Yang spec * @param[in] yspec Yang spec
* @param[in,out] cb CLIgen buffer * @param[in,out] cb CLIgen buffer
* @retval -1 Error (fatal)
* @retval 0 OK * @retval 0 OK
* @retval -1 Error (fatal)
* @see RFC 6022 Section 2.1.3 * @see RFC 6022 Section 2.1.3
*/ */
static int static int
@ -182,20 +184,45 @@ netconf_monitoring_schemas(clicon_handle h,
* @param[in] h Clicon handle * @param[in] h Clicon handle
* @param[in] yspec Yang spec * @param[in] yspec Yang spec
* @param[in,out] cb CLIgen buffer * @param[in,out] cb CLIgen buffer
* @retval -1 Error (fatal)
* @retval 0 OK * @retval 0 OK
* @retval -1 Error (fatal)
* @see RFC 6022 Section 2.1.5 * @see RFC 6022 Section 2.1.5
* XXX: NYI
*/ */
static int static int
netconf_monitoring_statistics(clicon_handle h, netconf_monitoring_statistics(clicon_handle h,
yang_stmt *yspec, yang_stmt *yspec,
cbuf *cb) cbuf *cb)
{ {
int retval = -1; int retval = -1;
char *str;
cvec *cvv = NULL;
cg_var *cv;
cprintf(cb, "<statistics>");
if (clicon_data_get(h, "netconf-start-time", &str) == 0 &&
str != NULL){
cprintf(cb, "<netconf-start-time>%s</netconf-start-time>", str);
}
if ((cvv = clicon_data_cvec_get(h, "netconf-statistics")) == NULL)
goto ok;
if ((cv = cvec_find(cvv, "in-bad-hellos")) != NULL)
cprintf(cb, "<in-bad-hellos>%u</in-bad-hellos>", cv_uint32_get(cv));
if ((cv = cvec_find(cvv, "in-sessions")) != NULL)
cprintf(cb, "<in-sessions>%u</in-sessions>", cv_uint32_get(cv));
if ((cv = cvec_find(cvv, "dropped-sessions")) != NULL)
cprintf(cb, "<dropped-sessions>%u</dropped-sessions>", cv_uint32_get(cv));
if ((cv = cvec_find(cvv, "in-rpcs")) != NULL)
cprintf(cb, "<in-rpcs>%u</in-rpcs>", cv_uint32_get(cv));
if ((cv = cvec_find(cvv, "in-bad-rpcs")) != NULL)
cprintf(cb, "<in-bad-rpcs>%u</in-bad-rpcs>", cv_uint32_get(cv));
if ((cv = cvec_find(cvv, "out-rpc-errors")) != NULL)
cprintf(cb, "<out-rpc-errors>%u</out-rpc-errors>", cv_uint32_get(cv));
if ((cv = cvec_find(cvv, "out-notifications")) != NULL)
cprintf(cb, "<out-notifications>%u</out-notifications>", cv_uint32_get(cv));
cprintf(cb, "</statistics>");
ok:
retval = 0; retval = 0;
//done: // done:
return retval; return retval;
} }
@ -209,9 +236,9 @@ netconf_monitoring_statistics(clicon_handle h,
* @param[in] nsc XML Namespace context for xpath * @param[in] nsc XML Namespace context for xpath
* @param[in,out] xret Existing XML tree, merge x into this * @param[in,out] xret Existing XML tree, merge x into this
* @param[out] xerr XML error tree, if retval = 0 * @param[out] xerr XML error tree, if retval = 0
* @retval -1 Error (fatal)
* @retval 0 Statedata callback failed, error in xret
* @retval 1 OK * @retval 1 OK
* @retval 0 Statedata callback failed, error in xret
* @retval -1 Error (fatal)
* @see backend_monitoring_state_get * @see backend_monitoring_state_get
* @see RFC 6022 * @see RFC 6022
*/ */
@ -257,3 +284,92 @@ netconf_monitoring_state_get(clicon_handle h,
retval = 0; retval = 0;
goto done; goto done;
} }
/*! Add RFC6022 empty counter32 with zero
*
* @param[in] cvv Cligen vector
* @param[in] name Name of new counter
*/
static int
stat_counter_add(cvec *cvv,
char *name)
{
int retval = -1;
cg_var *cv;
if ((cv = cvec_add(cvv, CGV_UINT32)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_add");
goto done;
}
cv_name_set(cv, name);
cv_uint32_set(cv, 0);
retval = 0;
done:
return retval;
}
/*! Init RFC6022 stats
*
* @param[in] h Clicon handle
*/
int
netconf_monitoring_statistics_init(clicon_handle h)
{
int retval = -1;
struct timeval tv;
char timestr[28];
cvec *cvv = NULL;
gettimeofday(&tv, NULL);
if (time2str(tv, timestr, sizeof(timestr)) < 0)
goto done;
clicon_data_set(h, "netconf-start-time", timestr); /* RFC 6022 */
if ((cvv = cvec_new(0)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_new");
goto done;
}
if (clicon_data_cvec_set(h, "netconf-statistics", cvv) < 0)
goto done;
if (stat_counter_add(cvv, "in-bad-hellos") < 0)
goto done;
if (stat_counter_add(cvv, "in-sessions") < 0)
goto done;
if (stat_counter_add(cvv, "dropped-sessions") < 0)
goto done;
if (stat_counter_add(cvv, "in-rpcs") < 0)
goto done;
if (stat_counter_add(cvv, "in-bad-rpcs") < 0)
goto done;
if (stat_counter_add(cvv, "out-rpc-errors") < 0)
goto done;
if (stat_counter_add(cvv, "out-notifications") < 0)
goto done;
retval = 0;
done:
return retval;
}
/*! Increment RFC6022 statistics counter
*
* @param[in] h Clixon handle
* @param[in] name Name of counter
*/
int
netconf_monitoring_counter_inc(clicon_handle h,
char *name)
{
int retval = -1;
cvec *cvv = NULL;
cg_var *cv;
uint32_t u32;
if ((cvv = clicon_data_cvec_get(h, "netconf-statistics")) != NULL){
if ((cv = cvec_find(cvv, name)) != NULL){
u32 = cv_uint32_get(cv);
u32++;
cv_uint32_set(cv, u32);
}
}
retval = 0;
return retval;
}

View file

@ -768,7 +768,7 @@ send_msg_notify(int s,
* @param[in] xev Event as XML * @param[in] xev Event as XML
* @retval 0 OK * @retval 0 OK
* @retval -1 Error * @retval -1 Error
* @see send_msg_notify XXX beauty contest * @see send_msg_notify
*/ */
int int
send_msg_notify_xml(clicon_handle h, send_msg_notify_xml(clicon_handle h,

View file

@ -231,7 +231,7 @@ xml_type2str(enum cxobj_type type)
return (char*)clicon_int2str(xsmap, type); return (char*)clicon_int2str(xsmap, type);
} }
/* Stats */ /* Stats (too low-level to hang it on handle) */
static uint64_t _stats_xml_nr = 0; static uint64_t _stats_xml_nr = 0;
/*! Get global statistics about XML objects /*! Get global statistics about XML objects

View file

@ -68,9 +68,9 @@ new "wait backend"
wait_backend wait_backend
new "Retrieving all state via <get> operation" 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><sessions>.*</sessions></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><statistics>.*</statistics></netconf-state></data></rpc-reply>"
# send multiple frames # send multiple frames using locks for more interesting datastore stat
rpc=$(chunked_framing "<rpc $DEFAULTNS><lock><target><candidate/></target></lock></rpc>") rpc=$(chunked_framing "<rpc $DEFAULTNS><lock><target><candidate/></target></lock></rpc>")
rpc="${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>")" $(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>")"
@ -94,13 +94,18 @@ done
# 4.1. Retrieving Schema List via <get> Operation # 4.1. Retrieving Schema List via <get> Operation
# match bith module and sub-module # match bith module and sub-module
# 2.1.3
new "Retrieving Schema List via <get> Operation" 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>" 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 # Session 2.1.4
new "Retrieve 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>" 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>"
# Statistics 2.1.5
new "Retrieve Statistics"
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\"><statistics/></netconf-state></filter></get></rpc>" "<rpc-reply $DEFAULTNS><data><netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\"><statistics><netconf-start-time>20[0-9][0-9]\-[0-9][0-9]\-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9]*Z</netconf-start-time><in-bad-hellos>[0-9]\+</in-bad-hellos><in-sessions>[1-9][0-9]*</in-sessions><dropped-sessions>[0-9]\+</dropped-sessions><in-rpcs>[1-9][0-9]*</in-rpcs><in-bad-rpcs>[0-9]\+</in-bad-rpcs><out-rpc-errors>[0-9]\+</out-rpc-errors><out-notifications>[0-9]\+</out-notifications></statistics></netconf-state></data></rpc-reply>"
# 4.2. Retrieving Schema Instances # 4.2. Retrieving Schema Instances
# From 2b. bar, version 2008-06-1 in YANG format, via get-schema # From 2b. bar, version 2008-06-1 in YANG format, via get-schema
new "Retrieving clixon-example schema instance using id, version, format" new "Retrieving clixon-example schema instance using id, version, format"

View file

@ -42,6 +42,7 @@ cat <<EOF > $cfg
<CLICON_STREAM_DISCOVERY_RFC5277>true</CLICON_STREAM_DISCOVERY_RFC5277> <CLICON_STREAM_DISCOVERY_RFC5277>true</CLICON_STREAM_DISCOVERY_RFC5277>
<CLICON_STREAM_PATH>streams</CLICON_STREAM_PATH> <CLICON_STREAM_PATH>streams</CLICON_STREAM_PATH>
<CLICON_STREAM_RETENTION>60</CLICON_STREAM_RETENTION> <CLICON_STREAM_RETENTION>60</CLICON_STREAM_RETENTION>
<CLICON_NETCONF_MONITORING>true</CLICON_NETCONF_MONITORING>
</clixon-config> </clixon-config>
EOF EOF
@ -117,6 +118,9 @@ expectwait "$clixon_netconf -D $DBG -qef $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTN
new "netconf subscription with empty startTime" new "netconf subscription with empty startTime"
expecteof_netconf "$clixon_netconf -D $DBG -qef $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><create-subscription xmlns=\"urn:ietf:params:xml:ns:netmod:notification\"><stream>EXAMPLE</stream><startTime/></create-subscription></rpc>" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>startTime</bad-element></error-info><error-severity>error</error-severity><error-message>regexp match fail:" "" expecteof_netconf "$clixon_netconf -D $DBG -qef $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><create-subscription xmlns=\"urn:ietf:params:xml:ns:netmod:notification\"><stream>EXAMPLE</stream><startTime/></create-subscription></rpc>" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>startTime</bad-element></error-info><error-severity>error</error-severity><error-message>regexp match fail:" ""
new "out-notification statistics expect 1-3"
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\"><statistics><out-notifications/></statistics></netconf-state></filter></get></rpc>" "<rpc-reply $DEFAULTNS><data><netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\"><statistics><out-notifications>[1-3]</out-notifications></statistics></netconf-state></data></rpc-reply>"
new "netconf EXAMPLE subscription with simple filter" new "netconf EXAMPLE subscription with simple filter"
expectwait "$clixon_netconf -D $DBG -qef $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><create-subscription xmlns=\"urn:ietf:params:xml:ns:netmod:notification\"><stream>EXAMPLE</stream><filter type=\"xpath\" select=\"event\"/></create-subscription></rpc>" $NCWAIT "<rpc-reply $DEFAULTNS><ok/></rpc-reply>" "<notification xmlns=\"urn:ietf:params:xml:ns:netconf:notification:1.0\"><eventTime>20" expectwait "$clixon_netconf -D $DBG -qef $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><create-subscription xmlns=\"urn:ietf:params:xml:ns:netmod:notification\"><stream>EXAMPLE</stream><filter type=\"xpath\" select=\"event\"/></create-subscription></rpc>" $NCWAIT "<rpc-reply $DEFAULTNS><ok/></rpc-reply>" "<notification xmlns=\"urn:ietf:params:xml:ns:netconf:notification:1.0\"><eventTime>20"