This commit is contained in:
Olof Hagsand 2020-05-11 14:37:26 +00:00
commit 1d17c762d2
16 changed files with 142 additions and 200 deletions

View file

@ -35,21 +35,27 @@ Expected: May 2020
* ca_trans_commit_done: Called when all plugin commits have been done.
* Note: If you have used "end" callback and usign transaction data, you should probably use this instead.
### API changes on existing protocol/config features (You may have have to change how you use Clixon)
### API changes on existing protocol/config features (For users, you may have have to change how you use Clixon)
* Stricter validation detecting duplicate container or leaf in XML.
* Eg `<x><a/><a/></x>` is invalid if `a` is anything else than leaf or leaf-list
* Eg `<x><a/><a/></x>` is invalid if `a` is a leaf or container.
* New clixon-lib@2020-04-23.yang revision
* Added: stats RPC for clixon XML and memory statistics.
* Added: restart-plugin RPC for restarting individual plugins without restarting backend.
* xml-stats moved from clixon-config.yang as state data to an rpc `datastats` in clixon-lib.yang
* New RPC: `stats` for clixon XML and memory statistics.
* New RPC: `restart-plugin` for restarting individual plugins without restarting backend.
* New clixon-config@2020-04-23.yang revision
* Removed xml-stats non-config data (replaced by rpc `stats` in clixon-lib.yang)
* Added option `CLICON_YANG_UNKNOWN_ANYDATA` to treat unknown XML (wrt YANG) as anydata.
* This is a way to loosen sanity checks if you need to accept eg unsynchronized YANG and XML
* Stricter incoming RPC sanity checking, error messages may have changed.
* Changed output of `clixon_cli -G` option to show generated CLI spec original text instead of resulting parse-tree, which gives better detail from a debugging perspective.
### C-API changes on existing features (you may need to change your plugin C-code)
### C-API changes on existing features (For developers: you may need to change your plugin C-code)
* Length of xml vector in many structs changed from `size_t` to `int`since it is a vector size, not byte size. This includes `transaction_data_t`
* Length of xml vector in many structs changed from `size_t` to `int`since it is a vector size, not byte size.
* Example: `transaction_data_t`
* `xml_merge()` changed to use 3-value return: 1:OK, 0:Yang failed, -1: Error
* Some function changed to use 3-value return: 1:OK, 0:Yang failed, -1: Error.
* Example: `xml_merge()`
* `clixon_netconf_error(category, xerr, msg, arg)` removed first argument -> `clixon_netconf_error(xerr, msg, arg)`
* CLI
* `clicon_parse()`: Changed signature due to new cligen error and result handling:
@ -59,22 +65,23 @@ Expected: May 2020
* Added decriptive error message when plugins produce invalid state XML.
* Example: `<error-tag>operation-failed</error-tag><error-info><bad-element>mystate</bad-element></error-info><error-message>No such yang module. Internal error, state callback returned invalid XML: example_backend</error-message>`
* Added option `CLICON_YANG_UNKNOWN_ANYDATA` to treat unknown XML (wrt YANG) as anydata.
* This is a way to loosen sanity checks if you need to accept eg unsynchronized YANG and XML
* Such a message means there is something wrong in the internal plugins or elsewehere, ie it is not a proper end-user error.
* Compile-time option: `USE_CLIGEN44` for running clixon-45 with cligen-44.
* Temporary fix since cligen-45 have some non-backward compatible behaviour.
* Optimizations
* Reduced memory for attribute and body objects, see `XML_NEW_DIFFERENTIATE` compile-time option.
* Optimized prefix checks at xml parse time: using many prefixes slowed down parsing considerably
* Optimized cbuf handling in parsing and xml2cbuf functions.
* Cycle optimizations
* Optimized namespace prefix checks at xml parse time: using many prefixes slowed down parsing considerably
* Optimized cbuf handling in parsing and xml2cbuf functions: use of new `cbuf_append()` function.
* Optimized xml scanner to read strings rather than single chars
* Optimized xml_merge for the case of disjunct trees.
* Cleared startup-db cache after restart
* Experimental optimzations of yang-bind and sort for large lists
* Enabled by compile-time options: `OPTIMIZE_45_BIND` and `OPTIMIZE_45_SORT`
* Identify early that trees are disjunct instead of recursively merge in `xml_merge`
* Optimizations of `yang_bind` for large lists: use a "sibling/template" to use same binding as previous element.
* Memory optimizations
* Reduced memory for attribute and body objects, by allocating less memory in `xml_new()` than for elements, reducing XML storage with ca 25%
* Cleared startup-db cache after restart, slashing datastore cache with (best-case) a third.
* Removed nameserver binding cache for leaf/leaf-list objects.
* Remove xml value cache after sorting (just use cligen value cache at sorting, remove after use)
* Adapted to CLIgen 4.5 API changes, eg: `cliread()` and `cliread_parse()`
* Renamed utility function `clixon_util_insert()` to `clixon_util_xml_mod()` and added merge functionality.
* Sanity check of duplicates prefixes in Yang modules and submodules as defined in RFC 7950 Sec 7.1.4
* Sanity check of duplicate prefixes in Yang modules and submodules as defined in RFC 7950 Sec 7.1.4
### Corrected Bugs

View file

@ -1425,7 +1425,6 @@ from_client_stats(clicon_handle h,
return retval;
}
#ifdef RESTART_PLUGIN_RPC
/*! Request restart of specific plugins
* @param[in] h Clicon handle
* @param[in] xe Request: <rpc><xn></rpc>
@ -1472,7 +1471,6 @@ from_client_restart_plugin(clicon_handle h,
free(vec);
return retval;
}
#endif /* RESTART_PLUGIN_RPC */
/*! Verify nacm user with peer uid credentials
* @param[in] mode Peer credential mode: none, exact or except
@ -1838,11 +1836,9 @@ backend_rpc_init(clicon_handle h)
if (rpc_callback_register(h, from_client_stats, NULL,
CLIXON_LIB_NS, "stats") < 0)
goto done;
#ifdef RESTART_PLUGIN_RPC
if (rpc_callback_register(h, from_client_restart_plugin, NULL,
CLIXON_LIB_NS, "restart-plugin") < 0)
goto done;
#endif
retval =0;
done:
return retval;

View file

@ -810,7 +810,6 @@ from_client_validate(clicon_handle h,
return retval;
} /* from_client_validate */
#ifdef RESTART_PLUGIN_RPC
/*! Restart specific backend plugins without full backend restart
* Note, depending on plugin callbacks, there may be other dependencies which may make this
* difficult in the general case.
@ -928,4 +927,4 @@ from_client_restart_one(clicon_handle h,
retval = 0;
goto done;
}
#endif /* RESTART_PLUGIN_RPC */

View file

@ -48,8 +48,6 @@ int from_client_commit(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void
int from_client_discard_changes(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg);
int from_client_cancel_commit(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg);
int from_client_validate(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg);
#ifdef RESTART_PLUGIN_RPC
int from_client_restart_one(clicon_handle h, clixon_plugin *cp, cbuf *cbret);
#endif
#endif /* _BACKEND_COMMIT_H_ */

View file

@ -101,26 +101,6 @@
*/
#define STATE_ORDERED_BY_SYSTEM
/*! Restart specific backend plugins
* Note, depending on plugin callbacks, there may be other dependencies which may make this
* difficult in the general case.
*/
#define RESTART_PLUGIN_RPC
/*! Differentiate creating XML object body/element vs elenmet to reduce space
*/
#define XML_NEW_DIFFERENTIATE
/*! Clixon 4.5 optimizing experiments for yang bind
* Primarily for large lists
*/
#define OPTIMIZE_45_BIND
/*! Clixon 4.5 optimizing experiments for sorting yang-bound XML trees
* Primarily for large lists
*/
#define OPTIMIZE_45_SORT
/*! Use cligen 4.4 instead of master / cligen 4.5.pre
* Temporary fix
*/

View file

@ -43,7 +43,7 @@
/*
* Prototypes
*/
int xml_bind_yang_unknown_anydata(int bool);
int xml_bind_yang_unknown_anydata(int val);
int xml_bind_yang_rpc(cxobj *xrpc, yang_stmt *yspec, cxobj **xerr);
int xml_bind_yang_rpc_reply(cxobj *xrpc, char *name, yang_stmt *yspec, cxobj **xerr);
int xml_bind_yang0(cxobj *xt, yang_bind yb, yang_stmt *yspec, cxobj **xerr);

View file

@ -141,7 +141,7 @@ clicon_err_reset(void)
* @param[in] fn Inline function name (when called from clicon_err() macro)
* @param[in] line Inline file line number (when called from clicon_err() macro)
* @param[in] category Clixon error category, See enum clicon_err
* @param[in] errno Error number, typically errno
* @param[in] suberr Error number, typically errno
* @param[in] reason Error string, format with argv
* @see clicon_err_reser Resetting the global error variables.
*/

View file

@ -158,6 +158,7 @@ struct search_index{
* - Local name: In either case the "local name" is N (also "prefix")
* It is this combination of the universally managed URI namespace with the
* vocabulary's local names that is effective in avoiding name clashes.
* @see struct xmlbody For XML body and attributes
*/
struct xml{
enum cxobj_type x_type; /* type of node: element, attribute, body */
@ -186,9 +187,8 @@ struct xml{
#endif
};
#ifdef XML_NEW_DIFFERENTIATE
/* This is experimental variant of struct xml for use by non-elements to save space
/* Variant of struct xml for use by non-elements to save space
* @see struct xml For XML elements
*/
struct xmlbody{
enum cxobj_type xb_type; /* type of node: element, attribute, body */
@ -201,7 +201,6 @@ struct xmlbody{
see xml_enumerate and xml_cmp */
cbuf *xb_value_cb; /* attribute and body nodes have values */
};
#endif /* XML_NEW_DIFFERENTIATE */
/*
* Variables
@ -277,11 +276,7 @@ xml_stats_one(cxobj *x,
break;
case CX_BODY:
case CX_ATTR:
#ifdef XML_NEW_DIFFERENTIATE
sz += sizeof(struct xmlbody);
#else
sz += sizeof(struct xml);
#endif
if (x->x_value_cb)
sz += cbuf_buflen(x->x_value_cb);
break;
@ -1042,10 +1037,9 @@ xml_childvec_get(cxobj *x)
* ...
* xml_free(x);
* @endcode
* @note Differentiates between body/attribute vs element to reduce mem allocation
* @see xml_sort_insert
*/
#ifdef XML_NEW_DIFFERENTIATE
/* Differentiate creating XML object body/element vs elenmet to reduce space */
cxobj *
xml_new(char *name,
cxobj *xp,
@ -1085,35 +1079,6 @@ xml_new(char *name,
return x;
}
#else /* XML_NEW_DIFFERENTIATE */
cxobj *
xml_new(char *name,
cxobj *xp,
enum cxobj_type type)
{
cxobj *x;
if ((x = malloc(sizeof(cxobj))) == NULL){
clicon_err(OE_XML, errno, "malloc");
return NULL;
}
memset(x, 0, sizeof(cxobj));
xml_type_set(x, type);
if (name != NULL &&
xml_name_set(x, name) < 0)
return NULL;
if (xp){
xml_parent_set(x, xp);
if (xml_child_append(xp, x) < 0)
return NULL;
x->_x_i = xml_child_nr(xp)-1;
}
_stats_nr++;
return x;
}
#endif /* XML_NEW_DIFFERENTIATE */
/*! Create a new XML node and set it's body to a value
*
* @param[in] name The name of the new node

View file

@ -88,9 +88,9 @@ static int _yang_unknown_anydata = 0;
* The problem with this is that its global and shuld be bound to a handle
*/
int
xml_bind_yang_unknown_anydata(int bool)
xml_bind_yang_unknown_anydata(int val)
{
_yang_unknown_anydata = bool;
_yang_unknown_anydata = val;
return 0;
}
@ -128,9 +128,7 @@ strip_whitespace(cxobj *xt)
*/
static int
populate_self_parent(cxobj *xt,
#ifdef OPTIMIZE_45_BIND
cxobj *xsibling,
#endif
cxobj **xerr)
{
int retval = -1;
@ -143,14 +141,12 @@ populate_self_parent(cxobj *xt,
cbuf *cb = NULL;
name = xml_name(xt);
#ifdef OPTIMIZE_45_BIND
/* optimization for massive lists - use the first element as role model */
if (xsibling &&
xml_child_nr_type(xt, CX_ATTR) == 0){
y = xml_spec(xsibling);
goto set;
}
#endif
xp = xml_parent(xt);
if (xp == NULL){
if (xerr &&
@ -202,9 +198,7 @@ populate_self_parent(cxobj *xt,
goto done;
goto fail;
}
#ifdef OPTIMIZE_45_BIND
set:
#endif
xml_spec_set(xt, y);
#ifdef XML_EXPLICIT_INDEX
if (xml_search_index_p(xt))
@ -354,7 +348,6 @@ xml_bind_yang(cxobj *xt,
goto done;
}
#ifdef OPTIMIZE_45_BIND
int
xml_bind_yang0_opt(cxobj *xt,
yang_bind yb,
@ -424,8 +417,6 @@ xml_bind_yang0_opt(cxobj *xt,
retval = 0;
goto done;
}
#endif /* OPTIMIZE_45_BIND */
/*! Find yang spec association of tree of XML nodes
*
@ -455,11 +446,7 @@ xml_bind_yang0(cxobj *xt,
goto done;
break;
case YB_PARENT:
if ((ret = populate_self_parent(xt,
#ifdef OPTIMIZE_45_BIND
NULL,
#endif
xerr)) < 0)
if ((ret = populate_self_parent(xt, NULL, xerr)) < 0)
goto done;
break;
case YB_NONE:
@ -477,13 +464,8 @@ xml_bind_yang0(cxobj *xt,
strip_whitespace(xt);
xc = NULL; /* Apply on children */
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL) {
#ifdef OPTIMIZE_45_BIND
if ((ret = xml_bind_yang0_opt(xc, YB_PARENT, NULL, xerr)) < 0)
goto done;
#else
if ((ret = xml_bind_yang0(xc, YB_PARENT, NULL, xerr)) < 0)
goto done;
#endif
if (ret == 0)
failed++;
}

View file

@ -464,9 +464,7 @@ xml2ns(cxobj *x,
* If not, this is devastating when populating deep yang structures
*/
if (ns &&
#ifdef OPTIMIZE_45_BIND /* Dont set cache if few children: if 1 child typically a body */
xml_child_nr(x) > 1 &&
#endif
xml_child_nr(x) > 1 && /* Dont set cache if few children: if 1 child typically a body */
nscache_set(x, prefix, ns) < 0)
goto done;
ok:

View file

@ -143,7 +143,6 @@ xml_cv_cache(cxobj *x,
return retval;
}
#ifdef OPTIMIZE_45_SORT
static int
xml_cv_cache_clear(cxobj *xt)
{
@ -157,7 +156,6 @@ xml_cv_cache_clear(cxobj *xt)
done:
return retval;
}
#endif /* OPTIMIZE_45_SORT */
/*! Help function to qsort for sorting entries in xml child vector same parent
* @param[in] x1 object 1
@ -433,7 +431,6 @@ xml_sort_recurse(cxobj *xn)
cxobj *x;
int ret;
#ifdef OPTIMIZE_45_SORT
ret = xml_sort_verify(xn, NULL);
if (ret == 1) /* This node is not sortable */
goto ok;
@ -445,12 +442,6 @@ xml_sort_recurse(cxobj *xn)
}
if (xml_cv_cache_clear(xn) < 0)
goto done;
#else
if ((ret = xml_sort(xn)) < 0)
goto done;
if (ret == 1) /* This node is not sortable */
goto ok;
#endif
x = NULL;
while ((x = xml_child_each(xn, x, CX_ELMNT)) != NULL) {
if (xml_sort_recurse(x) < 0)

View file

@ -80,6 +80,7 @@ expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 ipv4 address 1
new "cli configure ip descr"
expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 description mydesc" 0 "^$"
new "cli configure ip type"
expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 type ex:eth" 0 "^$"

View file

@ -3,7 +3,7 @@
#
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
# Copyright (C) 2017-2019 Olof Hagsand
# Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)#
# Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)
# This file is part of CLIXON
#
# Licensed under the Apache License, Version 2.0 (the "License");
@ -42,7 +42,7 @@ datarootdir = @datarootdir@
# See also OPT_YANG_INSTALLDIR for the standard yang files
YANG_INSTALLDIR = @YANG_INSTALLDIR@
YANGSPECS = clixon-config@2020-02-22.yang
YANGSPECS = clixon-config@2020-04-23.yang
YANGSPECS += clixon-lib@2020-04-23.yang
YANGSPECS += clixon-rfc5277@2008-07-01.yang
YANGSPECS += clixon-xml-changelog@2019-03-21.yang

View file

@ -40,8 +40,6 @@ module clixon-config {
***** END LICENSE BLOCK *****";
/* Deleted: clixon-stats state for clixon XML and memory statistics. (moved to clixon-lib)
*/
revision 2020-02-22 {
description
"Added: search index extension,
@ -314,14 +312,6 @@ module clixon-config {
Some yang specs seem not to fulfil this. However, if you reset this, there may
be follow-up errors due to code that assumes a configuration list has keys";
}
leaf CLICON_YANG_UNKNOWN_ANYDATA{
type boolean;
default false;
description
"Treat unknown XML/JSON nodes as anydata.
This does not apply to namespaces, which means a top-level node: xxx:yyy
is accepted only if yyy is unknown, not xxx";
}
leaf CLICON_BACKEND_DIR {
type string;
description
@ -728,4 +718,33 @@ module clixon-config {
}
}
container clixon-stats{
config false;
description "Clixon backend statistics.";
container global{
description "Clixon global statistics";
leaf xmlnr{
description "Number of XML objects. That is number of residing xml/json objects
in the internal 'cxobj' representation.";
type uint64;
}
}
list datastore{
description "Datastore statistics";
key "name";
leaf name{
description "name of datastore (eg running).";
type string;
}
leaf nr{
description "Number of XML objects. That is number of residing xml/json objects
in the internal 'cxobj' representation.";
type uint64;
}
leaf size{
description "Size in bytes of internal datastore cache of datastore tree.";
type uint64;
}
}
}
}

View file

@ -13,6 +13,7 @@ module clixon-config {
"Clixon configuration file
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2019 Olof Hagsand
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)
This file is part of CLIXON
@ -39,6 +40,22 @@ module clixon-config {
***** END LICENSE BLOCK *****";
/* Deleted: clixon-stats state for clixon XML and memory statistics. (moved to clixon-lib)
*/
revision 2020-04-23 {
description
"Added: CLICON_YANG_UNKNOWN_ANYDATA to treat unknown XML (wrt YANG) as anydata.
Deleted: xml-stats non-config data (replaced by rpc stats in clixon-lib.yang)";
}
revision 2020-02-22 {
description
"Added: search index extension,
Added: clixon-stats state for clixon XML and memory statistics.
Added: CLICON_CLI_BUF_START and CLICON_CLI_BUF_THRESHOLD for quadratic and linear
growth of CLIgen buffers (cbuf:s)
Added: CLICON_VALIDATE_STATE_XML for controling validation of user state XML
Added: CLICON_CLICON_YANG_LIST_CHECK to skip list key checks";
}
revision 2019-09-11 {
description
"Added: CLICON_BACKEND_USER: drop of privileges to user,
@ -67,6 +84,10 @@ module clixon-config {
description
"Released in Clixon 3.8";
}
extension search_index {
description "This list argument acts as a search index using optimized binary search.
";
}
typedef startup_mode{
description
"Which method to boot/start clicon backend.
@ -289,6 +310,23 @@ module clixon-config {
There is a 'good-enough' posix translation mode and a complete
libxml2 mode";
}
leaf CLICON_YANG_LIST_CHECK {
type boolean;
default true;
description
"If false, skip Yang list check sanity checks from RFC 7950, Sec 7.8.2:
The 'key' statement, which MUST be present if the list represents configuration.
Some yang specs seem not to fulfil this. However, if you reset this, there may
be follow-up errors due to code that assumes a configuration list has keys";
}
leaf CLICON_YANG_UNKNOWN_ANYDATA{
type boolean;
default false;
description
"Treat unknown XML/JSON nodes as anydata.
This does not apply to namespaces, which means a top-level node: xxx:yyy
is accepted only if yyy is unknown, not xxx";
}
leaf CLICON_BACKEND_DIR {
type string;
description
@ -440,6 +478,25 @@ module clixon-config {
Also, if CLICON_CLI_HIST_FILE is set, also the size in lines
of the saved history.";
}
leaf CLICON_CLI_BUF_START {
type uint32;
default 256;
description
"CLIgen buffer (cbuf) initial size.
When the buffer needs to grow, the allocation grows quadratic up to a threshold
after which linear growth continues.
See CLICON_CLI_BUF_THRESHOLD";
}
leaf CLICON_CLI_BUF_THRESHOLD {
type uint32;
default 65536;
description
"CLIgen buffer (cbuf) threshold size.
When the buffer exceeds the threshold, the allocation grows by adding the threshold
value to the buffer length.
If 0, the growth continues with quadratic growth.
See CLICON_CLI_BUF_THRESHOLD";
}
leaf CLICON_SOCK_FAMILY {
type string;
default "UNIX";
@ -552,6 +609,20 @@ module clixon-config {
If CLICON_XML_CHANGELOG is true, Clixon
reads the module changelog from this file.";
}
leaf CLICON_VALIDATE_STATE_XML {
type boolean;
default false;
description
"Validate user state callback content.
Users may register state callbacks using ca_statedata callback
When set, the XML returned from the callback is validated after merging with
the running db. If it fails, an internal error is returned to the originating
user.
If the option is not set, the XML returned by the user is not validated.
Note that enabling currently causes a large performance overhead for large
lists, therefore it is recommended to enable it during development and debugging
but disable it in production, until this has been resolved.";
}
leaf CLICON_STARTUP_MODE {
type startup_mode;
description "Which method to boot/start clicon backend";
@ -560,7 +631,9 @@ module clixon-config {
type boolean;
default false;
description "If set, modifications in validation and commit
callbacks are written back into the datastore";
callbacks are written back into the datastore.
This is a bad idea and therefore obsoleted.";
status obsolete;
}
leaf CLICON_NACM_MODE {
type nacm_mode;
@ -659,6 +732,5 @@ module clixon-config {
data to store before dropping. 0 means no retention";
}
}
}

View file

@ -1,66 +0,0 @@
module clixon-lib {
yang-version 1.1;
namespace "http://clicon.org/lib";
prefix cl;
organization
"Clicon / Clixon";
contact
"Olof Hagsand <olof@hagsand.se>";
description
"Clixon Netconf extensions for communication between clients and backend.
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
This file is part of CLIXON
Licensed under the Apache License, Version 2.0 (the \"License\");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an \"AS IS\" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 3 or later (the \"GPL\"),
in which case the provisions of the GPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of the GPL, and not to allow others to
use your version of this file under the terms of Apache License version 2,
indicate your decision by deleting the provisions above and replace them with
the notice and other provisions required by the GPL. If you do not delete
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 *****";
revision 2019-08-13 {
description
"No changes (reverted change)";
}
revision 2019-06-05 {
description
"ping rpc added for liveness";
}
revision 2019-01-02 {
description
"Released in Clixon 3.9";
}
rpc debug {
description "Set debug level of backend.";
input {
leaf level {
type uint32;
}
}
}
rpc ping {
description "Check aliveness of backend daemon.";
}
}