Refactoring for better performance of large auto-cli specs
* Fixed: [very slow execution of load_set_file #288](https://github.com/clicon/clixon/issues/288) * New `clixon-lib@2021-11-11.yang` revision * Modified option: RPC stats extended with YANG stats * Modified `clixon-config@2021-11-11.yang` revision * Added option: * CLICON_PLUGIN_CALLBACK_CHECK * Enable to make plugin context check before and after all callbacks. * Added statistics for YANG: number of objects and memory used * Use the treeref no-copy option of CLIgen to reduce memory * Refactored cli-generation/autocli-start code * Refactored cligen glue functions to use cligen_eval directly (remove clicon_eval,clixon_cligen_eval)
This commit is contained in:
parent
b91ce762d5
commit
5388aace12
29 changed files with 760 additions and 451 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
|
@ -59,7 +59,11 @@ Users may have to change how they access the system
|
||||||
* New behavior:
|
* New behavior:
|
||||||
* JSON: `{"s":"<![CDATA[ z > x & x < y ]]>"}`
|
* JSON: `{"s":"<![CDATA[ z > x & x < y ]]>"}`
|
||||||
* To keep old behavior, set `JSON_CDATA_STRIP` in clixon_custom.h
|
* To keep old behavior, set `JSON_CDATA_STRIP` in clixon_custom.h
|
||||||
|
* New `clixon-lib@2021-11-11.yang` revision
|
||||||
|
* Modified option: RPC stats extended with YANG stats
|
||||||
* New `clixon-config@2021-11-11.yang` revision
|
* New `clixon-config@2021-11-11.yang` revision
|
||||||
|
* Added option:
|
||||||
|
* CLICON_PLUGIN_CALLBACK_CHECK
|
||||||
* Modified options:
|
* Modified options:
|
||||||
* CLICON_CLI_GENMODEL_TYPE: added OC_COMPRESS enum
|
* CLICON_CLI_GENMODEL_TYPE: added OC_COMPRESS enum
|
||||||
* CLICON_YANG_DIR: recursive search
|
* CLICON_YANG_DIR: recursive search
|
||||||
|
|
@ -92,6 +96,11 @@ Developers may need to change their code
|
||||||
|
|
||||||
### Minor features
|
### Minor features
|
||||||
|
|
||||||
|
* Added statistics for YANG: number of objects and memory used
|
||||||
|
* See clixon-lib: stats rpc
|
||||||
|
* Performance improvement
|
||||||
|
* Added ancestor config cache indicating wether the node or an ancestor is config false or true
|
||||||
|
* Improved yang cardinality lookup
|
||||||
* Added sorting of YANG statements
|
* Added sorting of YANG statements
|
||||||
* Some openconfig specs seem to have use/when before a "config" which it depends on. This leads to XML encoding being in the "wrong order.
|
* Some openconfig specs seem to have use/when before a "config" which it depends on. This leads to XML encoding being in the "wrong order.
|
||||||
* When parsing, clixon now sorts container/list statements so that sub-statements with WHEN are put last.
|
* When parsing, clixon now sorts container/list statements so that sub-statements with WHEN are put last.
|
||||||
|
|
@ -101,6 +110,7 @@ Developers may need to change their code
|
||||||
* Check blocked signals and signal handlers
|
* Check blocked signals and signal handlers
|
||||||
* Check termios settings
|
* Check termios settings
|
||||||
* Any changes to context are logged at loglevel WARNING
|
* Any changes to context are logged at loglevel WARNING
|
||||||
|
* New option: CLICON_PLUGIN_CALLBACK_CHECK: enable it to for checks (default false)
|
||||||
* [OpenConfig path compression](https://github.com/clicon/clixon/pull/276)
|
* [OpenConfig path compression](https://github.com/clicon/clixon/pull/276)
|
||||||
* C API: Added set/get pointer API to clixon_data:
|
* C API: Added set/get pointer API to clixon_data:
|
||||||
* Changed signature of `rpc_callback_call()`
|
* Changed signature of `rpc_callback_call()`
|
||||||
|
|
@ -114,6 +124,7 @@ Developers may need to change their code
|
||||||
|
|
||||||
### Corrected Bugs
|
### Corrected Bugs
|
||||||
|
|
||||||
|
* [very slow execution of load_set_file #288](https://github.com/clicon/clixon/issues/288)
|
||||||
* [RPC output not verified by yang](https://github.com/clicon/clixon/issues/283)
|
* [RPC output not verified by yang](https://github.com/clicon/clixon/issues/283)
|
||||||
* [Statements given in "load set" are order dependent](https://github.com/clicon/clixon/issues/287)
|
* [Statements given in "load set" are order dependent](https://github.com/clicon/clixon/issues/287)
|
||||||
* Modify ordering of XML encoding to put sub-elements with YANG WHEN statements last
|
* Modify ordering of XML encoding to put sub-elements with YANG WHEN statements last
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ backend_client_rm(clicon_handle h,
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
clixon_stats_get_db(clicon_handle h,
|
clixon_stats_datastore_get(clicon_handle h,
|
||||||
char *dbname,
|
char *dbname,
|
||||||
cbuf *cb)
|
cbuf *cb)
|
||||||
{
|
{
|
||||||
|
|
@ -234,6 +234,37 @@ clixon_stats_get_db(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Get clixon per datastore stats
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] dbname Datastore name
|
||||||
|
* @param[in,out] cb Cligen buf
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
clixon_stats_module_get(clicon_handle h,
|
||||||
|
yang_stmt *ys,
|
||||||
|
cbuf *cb)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
uint64_t nr = 0;
|
||||||
|
size_t sz = 0;
|
||||||
|
cxobj *xn = NULL;
|
||||||
|
|
||||||
|
if (ys == NULL)
|
||||||
|
return 0;
|
||||||
|
if (yang_stats(ys, &nr, &sz) < 0)
|
||||||
|
goto done;
|
||||||
|
cprintf(cb, "<module xmlns=\"%s\"><name>%s</name><nr>%" PRIu64 "</nr>"
|
||||||
|
"<size>%zu</size></module>",
|
||||||
|
CLIXON_LIB_NS, yang_argument_get(ys), nr, sz);
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xn)
|
||||||
|
xml_free(xn);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Loads all or part of a specified configuration to target configuration
|
/*! Loads all or part of a specified configuration to target configuration
|
||||||
*
|
*
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
|
|
@ -998,17 +1029,39 @@ from_client_stats(clicon_handle h,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
uint64_t nr;
|
uint64_t nr;
|
||||||
|
yang_stmt *ym;
|
||||||
|
|
||||||
cprintf(cbret, "<rpc-reply xmlns=\"%s\">", NETCONF_BASE_NAMESPACE);
|
cprintf(cbret, "<rpc-reply xmlns=\"%s\">", NETCONF_BASE_NAMESPACE);
|
||||||
|
xml_stats_global(&nr);
|
||||||
|
cprintf(cbret, "<global xmlns=\"%s\">", CLIXON_LIB_NS);
|
||||||
nr=0;
|
nr=0;
|
||||||
xml_stats_global(&nr);
|
xml_stats_global(&nr);
|
||||||
cprintf(cbret, "<global xmlns=\"%s\"><xmlnr>%" PRIu64 "</xmlnr></global>", CLIXON_LIB_NS, nr);
|
cprintf(cbret, "<xmlnr>%" PRIu64 "</xmlnr>", nr);
|
||||||
if (clixon_stats_get_db(h, "running", cbret) < 0)
|
nr=0;
|
||||||
|
yang_stats_global(&nr);
|
||||||
|
cprintf(cbret, "<yangnr>%" PRIu64 "</yangnr>", nr);
|
||||||
|
cprintf(cbret, "</global>");
|
||||||
|
if (clixon_stats_datastore_get(h, "running", cbret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clixon_stats_get_db(h, "candidate", cbret) < 0)
|
if (clixon_stats_datastore_get(h, "candidate", cbret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clixon_stats_get_db(h, "startup", cbret) < 0)
|
if (clixon_stats_datastore_get(h, "startup", cbret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
ym = NULL;
|
||||||
|
while ((ym = yn_each(clicon_config_yang(h), ym)) != NULL) {
|
||||||
|
if (clixon_stats_module_get(h, ym, cbret) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
ym = NULL;
|
||||||
|
while ((ym = yn_each(clicon_dbspec_yang(h), ym)) != NULL) {
|
||||||
|
if (clixon_stats_module_get(h, ym, cbret) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
ym = NULL;
|
||||||
|
while ((ym = yn_each(clicon_nacm_ext_yang(h), ym)) != NULL) {
|
||||||
|
if (clixon_stats_module_get(h, ym, cbret) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
cprintf(cbret, "</rpc-reply>");
|
cprintf(cbret, "</rpc-reply>");
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
|
||||||
|
|
@ -931,20 +931,21 @@ from_client_restart_one(clicon_handle h,
|
||||||
yang_stmt *yspec;
|
yang_stmt *yspec;
|
||||||
int i;
|
int i;
|
||||||
cxobj *xn;
|
cxobj *xn;
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
yspec = clicon_dbspec_yang(h);
|
yspec = clicon_dbspec_yang(h);
|
||||||
if (xmldb_db_reset(h, db) < 0)
|
if (xmldb_db_reset(h, db) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Application may define extra xml in its reset function*/
|
/* Application may define extra xml in its reset function*/
|
||||||
if ((resetfn = clixon_plugin_api_get(cp)->ca_reset) != NULL){
|
if ((resetfn = clixon_plugin_api_get(cp)->ca_reset) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((retval = resetfn(h, db)) < 0) {
|
if ((retval = resetfn(h, db)) < 0) {
|
||||||
clicon_debug(1, "plugin_start() failed");
|
clicon_debug(1, "plugin_start() failed");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* 1. Start transaction */
|
/* 1. Start transaction */
|
||||||
|
|
@ -998,7 +999,6 @@ from_client_restart_one(clicon_handle h,
|
||||||
xml_flag_set(xn, XML_FLAG_CHANGE);
|
xml_flag_set(xn, XML_FLAG_CHANGE);
|
||||||
xml_apply_ancestor(xn, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE);
|
xml_apply_ancestor(xn, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call plugin transaction start callbacks */
|
/* Call plugin transaction start callbacks */
|
||||||
if (plugin_transaction_begin_one(cp, h, td) < 0)
|
if (plugin_transaction_begin_one(cp, h, td) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -1026,8 +1026,6 @@ from_client_restart_one(clicon_handle h,
|
||||||
goto fail;
|
goto fail;
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
if (td){
|
if (td){
|
||||||
xmldb_get0_free(h, &td->td_target);
|
xmldb_get0_free(h, &td->td_target);
|
||||||
transaction_free(td);
|
transaction_free(td);
|
||||||
|
|
|
||||||
|
|
@ -80,24 +80,25 @@ clixon_plugin_reset_one(clixon_plugin_t *cp,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
plgreset_t *fn; /* callback */
|
plgreset_t *fn; /* callback */
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
if ((fn = clixon_plugin_api_get(cp)->ca_reset) != NULL){
|
if ((fn = clixon_plugin_api_get(cp)->ca_reset) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h, db) < 0) {
|
if (fn(h, db) < 0) {
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
|
goto done;
|
||||||
if (clicon_errno < 0)
|
if (clicon_errno < 0)
|
||||||
clicon_log(LOG_WARNING, "%s: Internal error: Reset callback in plugin: %s returned -1 but did not make a clicon_err call",
|
clicon_log(LOG_WARNING, "%s: Internal error: Reset callback in plugin: %s returned -1 but did not make a clicon_err call",
|
||||||
__FUNCTION__, clixon_plugin_name_get(cp));
|
__FUNCTION__, clixon_plugin_name_get(cp));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,26 +139,26 @@ clixon_plugin_pre_daemon_one(clixon_plugin_t *cp,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
plgdaemon_t *fn; /* Daemonize plugin callback function */
|
plgdaemon_t *fn; /* Daemonize plugin callback function */
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
if ((fn = clixon_plugin_api_get(cp)->ca_pre_daemon) != NULL){
|
if ((fn = clixon_plugin_api_get(cp)->ca_pre_daemon) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (fn(h) < 0) {
|
if (fn(h) < 0) {
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
|
goto done;
|
||||||
if (clicon_errno < 0)
|
if (clicon_errno < 0)
|
||||||
clicon_log(LOG_WARNING, "%s: Internal error: Pre-daemon callback in plugin:\
|
clicon_log(LOG_WARNING, "%s: Internal error: Pre-daemon callback in plugin:\
|
||||||
%s returned -1 but did not make a clicon_err call",
|
%s returned -1 but did not make a clicon_err call",
|
||||||
__FUNCTION__, clixon_plugin_name_get(cp));
|
__FUNCTION__, clixon_plugin_name_get(cp));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,24 +200,25 @@ clixon_plugin_daemon_one(clixon_plugin_t *cp,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
plgdaemon_t *fn; /* Daemonize plugin callback function */
|
plgdaemon_t *fn; /* Daemonize plugin callback function */
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
if ((fn = clixon_plugin_api_get(cp)->ca_daemon) != NULL){
|
if ((fn = clixon_plugin_api_get(cp)->ca_daemon) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h) < 0) {
|
if (fn(h) < 0) {
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
|
goto done;
|
||||||
if (clicon_errno < 0)
|
if (clicon_errno < 0)
|
||||||
clicon_log(LOG_WARNING, "%s: Internal error: Daemon callback in plugin: %s returned -1 but did not make a clicon_err call",
|
clicon_log(LOG_WARNING, "%s: Internal error: Daemon callback in plugin: %s returned -1 but did not make a clicon_err call",
|
||||||
__FUNCTION__, clixon_plugin_name_get(cp));
|
__FUNCTION__, clixon_plugin_name_get(cp));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -283,28 +285,29 @@ clixon_plugin_statedata_one(clixon_plugin_t *cp,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
plgstatedata_t *fn; /* Plugin statedata fn */
|
plgstatedata_t *fn; /* Plugin statedata fn */
|
||||||
cxobj *x = NULL;
|
cxobj *x = NULL;
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
if ((fn = clixon_plugin_api_get(cp)->ca_statedata) != NULL){
|
if ((fn = clixon_plugin_api_get(cp)->ca_statedata) != NULL){
|
||||||
if ((x = xml_new(DATASTORE_TOP_SYMBOL, NULL, CX_ELMNT)) == NULL)
|
if ((x = xml_new(DATASTORE_TOP_SYMBOL, NULL, CX_ELMNT)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h, nsc, xpath, x) < 0){
|
if (fn(h, nsc, xpath, x) < 0){
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
|
goto done;
|
||||||
if (clicon_errno < 0)
|
if (clicon_errno < 0)
|
||||||
clicon_log(LOG_WARNING, "%s: Internal error: State callback in plugin: %s returned -1 but did not make a clicon_err call",
|
clicon_log(LOG_WARNING, "%s: Internal error: State callback in plugin: %s returned -1 but did not make a clicon_err call",
|
||||||
__FUNCTION__, clixon_plugin_name_get(cp));
|
__FUNCTION__, clixon_plugin_name_get(cp));
|
||||||
goto fail; /* Dont quit here on user callbacks */
|
goto fail; /* Dont quit here on user callbacks */
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (xp && x)
|
if (xp && x)
|
||||||
*xp = x;
|
*xp = x;
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
fail:
|
fail:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -437,20 +440,19 @@ clixon_plugin_lockdb_one(clixon_plugin_t *cp,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
plglockdb_t *fn; /* Plugin statedata fn */
|
plglockdb_t *fn; /* Plugin statedata fn */
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
if ((fn = clixon_plugin_api_get(cp)->ca_lockdb) != NULL){
|
if ((fn = clixon_plugin_api_get(cp)->ca_lockdb) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h, db, lock, id) < 0)
|
if (fn(h, db, lock, id) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -613,24 +615,25 @@ plugin_transaction_begin_one(clixon_plugin_t *cp,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
trans_cb_t *fn;
|
trans_cb_t *fn;
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
if ((fn = clixon_plugin_api_get(cp)->ca_trans_begin) != NULL){
|
if ((fn = clixon_plugin_api_get(cp)->ca_trans_begin) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h, (transaction_data)td) < 0){
|
if (fn(h, (transaction_data)td) < 0){
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
|
goto done;
|
||||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
||||||
__FUNCTION__, clixon_plugin_name_get(cp));
|
__FUNCTION__, clixon_plugin_name_get(cp));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -673,24 +676,26 @@ plugin_transaction_validate_one(clixon_plugin_t *cp,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
trans_cb_t *fn;
|
trans_cb_t *fn;
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
if ((fn = clixon_plugin_api_get(cp)->ca_trans_validate) != NULL){
|
if ((fn = clixon_plugin_api_get(cp)->ca_trans_validate) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h, (transaction_data)td) < 0){
|
if (fn(h, (transaction_data)td) < 0){
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
|
goto done;
|
||||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
||||||
__FUNCTION__, clixon_plugin_name_get(cp));
|
__FUNCTION__, clixon_plugin_name_get(cp));
|
||||||
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -731,24 +736,25 @@ plugin_transaction_complete_one(clixon_plugin_t *cp,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
trans_cb_t *fn;
|
trans_cb_t *fn;
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
if ((fn = clixon_plugin_api_get(cp)->ca_trans_complete) != NULL){
|
if ((fn = clixon_plugin_api_get(cp)->ca_trans_complete) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h, (transaction_data)td) < 0){
|
if (fn(h, (transaction_data)td) < 0){
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
|
goto done;
|
||||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
||||||
__FUNCTION__, clixon_plugin_name_get(cp));
|
__FUNCTION__, clixon_plugin_name_get(cp));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -821,24 +827,25 @@ plugin_transaction_commit_one(clixon_plugin_t *cp,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
trans_cb_t *fn;
|
trans_cb_t *fn;
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
if ((fn = clixon_plugin_api_get(cp)->ca_trans_commit) != NULL){
|
if ((fn = clixon_plugin_api_get(cp)->ca_trans_commit) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h, (transaction_data)td) < 0){
|
if (fn(h, (transaction_data)td) < 0){
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
|
goto done;
|
||||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
||||||
__FUNCTION__, clixon_plugin_name_get(cp));
|
__FUNCTION__, clixon_plugin_name_get(cp));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -872,7 +879,6 @@ plugin_transaction_commit_all(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Call single plugin transaction_commit_done() in a commit transaction
|
/*! Call single plugin transaction_commit_done() in a commit transaction
|
||||||
* @param[in] cp Plugin handle
|
* @param[in] cp Plugin handle
|
||||||
* @param[in] h Clixon handle
|
* @param[in] h Clixon handle
|
||||||
|
|
@ -887,24 +893,25 @@ plugin_transaction_commit_done_one(clixon_plugin_t *cp,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
trans_cb_t *fn;
|
trans_cb_t *fn;
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
if ((fn = clixon_plugin_api_get(cp)->ca_trans_commit_done) != NULL){
|
if ((fn = clixon_plugin_api_get(cp)->ca_trans_commit_done) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h, (transaction_data)td) < 0){
|
if (fn(h, (transaction_data)td) < 0){
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
|
goto done;
|
||||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
||||||
__FUNCTION__, clixon_plugin_name_get(cp));
|
__FUNCTION__, clixon_plugin_name_get(cp));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -945,24 +952,25 @@ plugin_transaction_end_one(clixon_plugin_t *cp,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
trans_cb_t *fn;
|
trans_cb_t *fn;
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
if ((fn = clixon_plugin_api_get(cp)->ca_trans_end) != NULL){
|
if ((fn = clixon_plugin_api_get(cp)->ca_trans_end) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h, (transaction_data)td) < 0){
|
if (fn(h, (transaction_data)td) < 0){
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
|
goto done;
|
||||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
||||||
__FUNCTION__, clixon_plugin_name_get(cp));
|
__FUNCTION__, clixon_plugin_name_get(cp));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -996,24 +1004,25 @@ plugin_transaction_abort_one(clixon_plugin_t *cp,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
trans_cb_t *fn;
|
trans_cb_t *fn;
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
if ((fn = clixon_plugin_api_get(cp)->ca_trans_abort) != NULL){
|
if ((fn = clixon_plugin_api_get(cp)->ca_trans_abort) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h, (transaction_data)td) < 0){
|
if (fn(h, (transaction_data)td) < 0){
|
||||||
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
|
goto done;
|
||||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
||||||
__FUNCTION__, clixon_plugin_name_get(cp));
|
__FUNCTION__, clixon_plugin_name_get(cp));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@
|
||||||
static char *
|
static char *
|
||||||
co2apipath(cg_obj *co)
|
co2apipath(cg_obj *co)
|
||||||
{
|
{
|
||||||
struct cg_callback *cb;
|
cg_callback *cb;
|
||||||
cvec *cvv;
|
cvec *cvv;
|
||||||
cg_var *cv;
|
cg_var *cv;
|
||||||
|
|
||||||
|
|
@ -467,10 +467,19 @@ cli_auto_edit(clicon_handle h,
|
||||||
clicon_err(OE_PLUGIN, 0, "No such parsetree header: %s", treename);
|
clicon_err(OE_PLUGIN, 0, "No such parsetree header: %s", treename);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Find the matching cligen object */
|
/* Find the matching cligen object
|
||||||
if ((co = cligen_co_match(cli_cligen(h))) != NULL &&
|
* Note, is complictead: either an instantiated tree (co_treeref_orig)
|
||||||
(coorig = co->co_treeref_orig) != NULL)
|
* or actual tree (co_ref)
|
||||||
|
*/
|
||||||
|
if ((co = cligen_co_match(cli_cligen(h))) != NULL){
|
||||||
|
if ((coorig = co->co_treeref_orig) != NULL ||
|
||||||
|
(coorig = co->co_ref) != NULL)
|
||||||
cligen_ph_workpoint_set(ph, coorig);
|
cligen_ph_workpoint_set(ph, coorig);
|
||||||
|
else {
|
||||||
|
clicon_err(OE_YANG, EINVAL, "No workpoint found");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
else{
|
else{
|
||||||
clicon_err(OE_YANG, EINVAL, "No workpoint found");
|
clicon_err(OE_YANG, EINVAL, "No workpoint found");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -500,7 +509,7 @@ cli_auto_edit(clicon_handle h,
|
||||||
/*! CLI callback: Working point tree up to parent
|
/*! CLI callback: Working point tree up to parent
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
* @param[in] cvv Vector of variables from CLIgen command-line
|
* @param[in] cvv Vector of variables from CLIgen command-line
|
||||||
* @param[in] argv Vector oif user-supplied keywords
|
* @param[in] argv Vector of user-supplied keywords
|
||||||
* Format of argv:
|
* Format of argv:
|
||||||
* <treename> Name of generated cligen parse-tree, eg "datamodel"
|
* <treename> Name of generated cligen parse-tree, eg "datamodel"
|
||||||
*/
|
*/
|
||||||
|
|
@ -991,7 +1000,7 @@ cli_auto_sub_enter(clicon_handle h,
|
||||||
}
|
}
|
||||||
/* Find the point in the generated clispec tree where workpoint should be set */
|
/* Find the point in the generated clispec tree where workpoint should be set */
|
||||||
fa.fa_str = api_path_fmt;
|
fa.fa_str = api_path_fmt;
|
||||||
if (pt_apply(cligen_ph_parsetree_get(ph), cli_auto_findpt, &fa) < 0)
|
if (pt_apply(cligen_ph_parsetree_get(ph), cli_auto_findpt, INT32_MAX, &fa) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (fa.fa_co == NULL){
|
if (fa.fa_co == NULL){
|
||||||
clicon_err(OE_PLUGIN, ENOENT, "No such cligen object found %s", api_path);
|
clicon_err(OE_PLUGIN, ENOENT, "No such cligen object found %s", api_path);
|
||||||
|
|
|
||||||
|
|
@ -1113,36 +1113,27 @@ yang2cli_stmt(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Generate CLI code for Yang specification
|
|
||||||
* @param[in] h Clixon handle
|
|
||||||
* @param[in] yn Create parse-tree from this yang node
|
|
||||||
* @param[in] printgen Log generated CLIgen syntax
|
|
||||||
* @param[in] state Set to include state syntax
|
|
||||||
* @param[in] show_tree Is tree for show cli command
|
|
||||||
* @param[out] pt CLIgen parse-tree (must be created on input)
|
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1 Error
|
|
||||||
*/
|
|
||||||
int
|
int
|
||||||
yang2cli(clicon_handle h,
|
yang2cli_yspec(clicon_handle h,
|
||||||
yang_stmt *yn,
|
yang_stmt *yn,
|
||||||
|
char *name0,
|
||||||
int printgen,
|
int printgen,
|
||||||
int state,
|
int state,
|
||||||
int show_tree,
|
int show_tree)
|
||||||
parse_tree *pt)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cbuf *cb = NULL;
|
parse_tree *pt0 = NULL;
|
||||||
yang_stmt *yc;
|
cbuf *cb0 = NULL;
|
||||||
cvec *globals; /* global variables from syntax */
|
|
||||||
genmodel_type gt;
|
genmodel_type gt;
|
||||||
char *excludelist;
|
char *excludelist;
|
||||||
char **exvec = NULL;
|
char **exvec = NULL;
|
||||||
int nexvec = 0;
|
int nexvec = 0;
|
||||||
int e;
|
int e;
|
||||||
|
yang_stmt *ym;
|
||||||
|
pt_head *ph;
|
||||||
|
|
||||||
if (pt == NULL){
|
if ((pt0 = pt_new()) == NULL){
|
||||||
clicon_err(OE_YANG, EINVAL, "pt is NULL");
|
clicon_err(OE_UNIX, errno, "pt_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* List of modules that should not generate autocli */
|
/* List of modules that should not generate autocli */
|
||||||
|
|
@ -1151,48 +1142,49 @@ yang2cli(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
gt = clicon_cli_genmodel_type(h);
|
gt = clicon_cli_genmodel_type(h);
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb0 = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_XML, errno, "cbuf_new");
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Traverse YANG, loop through all modules and generate CLI */
|
/* Traverse YANG, loop through all modules and generate CLI */
|
||||||
yc = NULL;
|
ym = NULL;
|
||||||
while ((yc = yn_each(yn, yc)) != NULL){
|
while ((ym = yn_each(yn, ym)) != NULL){
|
||||||
/* Check if module is in exclude list */
|
/* Check if module is in exclude list */
|
||||||
for (e = 0; e < nexvec; e++){
|
for (e = 0; e < nexvec; e++){
|
||||||
if (strcmp(yang_argument_get(yc), exvec[e]) == 0)
|
if (strcmp(yang_argument_get(ym), exvec[e]) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (e < nexvec)
|
if (e < nexvec)
|
||||||
continue;
|
continue;
|
||||||
if (yang2cli_stmt(h, yc, gt, 0, state, show_tree, cb) < 0)
|
if (yang2cli_stmt(h, ym, gt, 0, state, show_tree, cb0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (printgen)
|
if (printgen)
|
||||||
clicon_log(LOG_NOTICE, "%s: Generated CLI spec:\n%s", __FUNCTION__, cbuf_get(cb));
|
clicon_log(LOG_NOTICE, "%s: Top-level api-spec %s:\n%s",
|
||||||
|
__FUNCTION__, name0, cbuf_get(cb0));
|
||||||
else
|
else
|
||||||
clicon_debug(2, "%s: buf\n%s\n", __FUNCTION__, cbuf_get(cb));
|
clicon_debug(2, "%s: Top-level api-spec %s:\n%s",
|
||||||
/* Parse the buffer using cligen parser. XXX why this?*/
|
__FUNCTION__, name0, cbuf_get(cb0));
|
||||||
if ((globals = cvec_new(0)) == NULL)
|
/* load top-level yangspec cli syntax (that point to modules) */
|
||||||
|
if (cligen_parse_str(cli_cligen(h), cbuf_get(cb0), "yang2cli", pt0, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* load cli syntax */
|
|
||||||
if (cligen_parse_str(cli_cligen(h), cbuf_get(cb), "yang2cli", pt, globals) < 0)
|
|
||||||
goto done;
|
|
||||||
cvec_free(globals);
|
|
||||||
/* Resolve the expand callback functions in the generated syntax.
|
/* Resolve the expand callback functions in the generated syntax.
|
||||||
* This "should" only be GENERATE_EXPAND_XMLDB
|
* This "should" only be GENERATE_EXPAND_XMLDB
|
||||||
* handle=NULL for global namespace, this means expand callbacks must be in
|
* handle=NULL for global namespace, this means expand callbacks must be in
|
||||||
* CLICON namespace, not in a cli frontend plugin.
|
* CLICON namespace, not in a cli frontend plugin.
|
||||||
*/
|
*/
|
||||||
if (cligen_expandv_str2fn(pt, (expandv_str2fn_t*)clixon_str2fn, NULL) < 0)
|
if (cligen_expandv_str2fn(pt0, (expandv_str2fn_t*)clixon_str2fn, NULL) < 0)
|
||||||
|
goto done;
|
||||||
|
/* Append cligen tree and name it */
|
||||||
|
if ((ph = cligen_ph_add(cli_cligen(h), name0)) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (cligen_ph_parsetree_set(ph, pt0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (exvec)
|
if (exvec)
|
||||||
free(exvec);
|
free(exvec);
|
||||||
if (cb)
|
if (cb0)
|
||||||
cbuf_free(cb);
|
cbuf_free(cb0);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
int yang2cli(clicon_handle h, yang_stmt *yspec,
|
int yang2cli_yspec(clicon_handle h, yang_stmt *yspec, char *name0,
|
||||||
int printgen, int state, int show_tree, parse_tree *ptnew);
|
int printgen, int state, int show_tree);
|
||||||
|
|
||||||
#endif /* _CLI_GENERATE_H_ */
|
#endif /* _CLI_GENERATE_H_ */
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,12 @@ cli_handle_init(void)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cligen_userhandle_set(clih, cl);
|
cligen_userhandle_set(clih, cl);
|
||||||
|
cligen_eval_wrap_fn_set(clih, plugin_context_check, cl);
|
||||||
|
/* To minimize memory, dont copy full treerefs on expand */
|
||||||
|
cligen_reftree_copy_set(clih, 0);
|
||||||
|
|
||||||
cl->cl_cligen = clih;
|
cl->cl_cligen = clih;
|
||||||
|
|
||||||
h = (clicon_handle)cl;
|
h = (clicon_handle)cl;
|
||||||
done:
|
done:
|
||||||
return h;
|
return h;
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@
|
||||||
#include "cli_handle.h"
|
#include "cli_handle.h"
|
||||||
|
|
||||||
/* Command line options to be passed to getopt(3) */
|
/* Command line options to be passed to getopt(3) */
|
||||||
#define CLI_OPTS "hD:f:E:l:F:1a:u:d:m:qp:GLy:c:U:o:"
|
#define CLI_OPTS "+hD:f:E:l:F:1a:u:d:m:qp:GLy:c:U:o:"
|
||||||
|
|
||||||
/*! Check if there is a CLI history file and if so dump the CLI histiry to it
|
/*! Check if there is a CLI history file and if so dump the CLI histiry to it
|
||||||
* Just log if file does not exist or is not readable
|
* Just log if file does not exist or is not readable
|
||||||
|
|
@ -242,57 +242,6 @@ cli_interactive(clicon_handle h)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Generate one autocli clispec tree
|
|
||||||
*
|
|
||||||
* @param[in] h Clixon handle
|
|
||||||
* @param[in] name Name of tree
|
|
||||||
* @param[in] gt genmodel-type, ie HOW to generate the CLI
|
|
||||||
* @param[in] printgen Print CLI syntax to stderr
|
|
||||||
* @param[in] show_tree Is tree for show cli command (1 - yes. 0 - no)
|
|
||||||
*
|
|
||||||
* Generate clispec (datamodel) from YANG dataspec and add to the set of cligen trees
|
|
||||||
* (as a separate mode)
|
|
||||||
* This tree is referenced from the main CLI spec (CLICON_CLISPEC_DIR) using the "tree reference"
|
|
||||||
* syntax, ie @datamodel
|
|
||||||
* @param[in] h Clixon handle
|
|
||||||
* @param[in] state Set to include state syntax
|
|
||||||
* @param[in] printgen Print CLI syntax generated from dbspec
|
|
||||||
* @param[in] show_tree Is tree for show cli command
|
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1 Error
|
|
||||||
*
|
|
||||||
* @note that yang2cli generates syntax for ALL modules under the loaded yangspec.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
autocli_tree(clicon_handle h,
|
|
||||||
char *name,
|
|
||||||
int state,
|
|
||||||
int printgen,
|
|
||||||
int show_tree)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
parse_tree *pt = NULL; /* cli parse tree */
|
|
||||||
yang_stmt *yspec;
|
|
||||||
pt_head *ph;
|
|
||||||
|
|
||||||
if ((pt = pt_new()) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "pt_new");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
yspec = clicon_dbspec_yang(h);
|
|
||||||
/* Generate tree (this is where the action is) */
|
|
||||||
if (yang2cli(h, yspec, printgen, state, show_tree, pt) < 0)
|
|
||||||
goto done;
|
|
||||||
/* Append cligen tree and name it */
|
|
||||||
if ((ph = cligen_ph_add(cli_cligen(h), name)) == NULL)
|
|
||||||
goto done;
|
|
||||||
if (cligen_ph_parsetree_set(ph, pt) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Generate autocli, ie if enabled, generate clispec from YANG and add to cligen parse-trees
|
/*! Generate autocli, ie if enabled, generate clispec from YANG and add to cligen parse-trees
|
||||||
*
|
*
|
||||||
* Generate clispec (datamodel) from YANG dataspec and add to the set of cligen trees
|
* Generate clispec (datamodel) from YANG dataspec and add to the set of cligen trees
|
||||||
|
|
@ -312,11 +261,14 @@ autocli_start(clicon_handle h,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int autocli_model = 0;
|
int autocli_model = 0;
|
||||||
cbuf *show_treename = NULL, *treename = NULL;
|
cbuf *show_treename = NULL;
|
||||||
|
cbuf *treename = NULL;
|
||||||
|
yang_stmt *yspec;
|
||||||
|
|
||||||
/* If autocli disabled quit */
|
/* If autocli disabled quit */
|
||||||
if ((autocli_model = clicon_cli_genmodel(h)) == 0)
|
if ((autocli_model = clicon_cli_genmodel(h)) == 0)
|
||||||
goto ok;
|
goto ok;
|
||||||
|
yspec = clicon_dbspec_yang(h);
|
||||||
/* Get the autocli type, ie HOW the cli is generated (could be much more here) */
|
/* Get the autocli type, ie HOW the cli is generated (could be much more here) */
|
||||||
/* Create show_treename cbuf */
|
/* Create show_treename cbuf */
|
||||||
if ((show_treename = cbuf_new()) == NULL){
|
if ((show_treename = cbuf_new()) == NULL){
|
||||||
|
|
@ -330,23 +282,22 @@ autocli_start(clicon_handle h,
|
||||||
}
|
}
|
||||||
/* The tree name is by default @datamodel but can be changed by option (why would one do that?) */
|
/* The tree name is by default @datamodel but can be changed by option (why would one do that?) */
|
||||||
cprintf(treename, "%s", clicon_cli_model_treename(h));
|
cprintf(treename, "%s", clicon_cli_model_treename(h));
|
||||||
if (autocli_tree(h, cbuf_get(treename), 0, printgen, 0) < 0)
|
if (yang2cli_yspec(h, yspec, cbuf_get(treename), printgen, 0, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* The tree name is by default @datamodelshow but can be changed by option (why would one do that?) */
|
/* The tree name is by default @datamodelshow but can be changed by option (why would one do that?) */
|
||||||
cprintf(show_treename, "%s", clicon_cli_model_treename(h));
|
cprintf(show_treename, "%s", clicon_cli_model_treename(h));
|
||||||
cprintf(show_treename, "show");
|
cprintf(show_treename, "show");
|
||||||
if (autocli_tree(h, cbuf_get(show_treename), 0, printgen, 1) < 0)
|
if (yang2cli_yspec(h, yspec, cbuf_get(show_treename), printgen, 0, 1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Create a tree for config+state. This tree's name has appended "state" to @datamodel
|
/* Create a tree for config+state. This tree's name has appended "state" to @datamodel
|
||||||
*/
|
*/
|
||||||
if (autocli_model > 1){
|
if (autocli_model > 1){
|
||||||
cprintf(treename, "state");
|
cprintf(treename, "state");
|
||||||
if (autocli_tree(h, cbuf_get(treename), 1, printgen, 1) < 0)
|
if (yang2cli_yspec(h, yspec, cbuf_get(treename), printgen, 1, 1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
|
||||||
|
|
@ -522,105 +522,6 @@ cli_handler_err(FILE *f)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Variant of eval for context checking
|
|
||||||
* @see cligen_eval
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
clixon_cligen_eval(cligen_handle h,
|
|
||||||
cg_obj *co,
|
|
||||||
cvec *cvv)
|
|
||||||
{
|
|
||||||
struct cg_callback *cc;
|
|
||||||
int retval = -1;
|
|
||||||
cvec *argv;
|
|
||||||
cvec *cvv1 = NULL; /* Modified */
|
|
||||||
plugin_context_t *pc = NULL; /* Clixon-specific */
|
|
||||||
|
|
||||||
|
|
||||||
/* Save matched object for plugin use */
|
|
||||||
if (h)
|
|
||||||
cligen_co_match_set(h, co);
|
|
||||||
/* Make a copy of var argument for modifications */
|
|
||||||
if ((cvv1 = cvec_dup(cvv)) == NULL)
|
|
||||||
goto done;
|
|
||||||
/* Make modifications to cvv */
|
|
||||||
if (cligen_expand_first_get(h) &&
|
|
||||||
cvec_expand_first(cvv1) < 0)
|
|
||||||
goto done;
|
|
||||||
if (cligen_exclude_keys_get(h) &&
|
|
||||||
cvec_exclude_keys(cvv1) < 0)
|
|
||||||
goto done;
|
|
||||||
/* Traverse callbacks */
|
|
||||||
for (cc = co->co_callbacks; cc; cc=cc->cc_next){
|
|
||||||
/* Vector cvec argument to callback */
|
|
||||||
if (cc->cc_fn_vec){
|
|
||||||
argv = cc->cc_cvec ? cvec_dup(cc->cc_cvec) : NULL;
|
|
||||||
cligen_fn_str_set(h, cc->cc_fn_str);
|
|
||||||
/* Clixon-specific */
|
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
|
||||||
break;
|
|
||||||
if ((retval = (*cc->cc_fn_vec)(
|
|
||||||
cligen_userhandle(h)?cligen_userhandle(h):h,
|
|
||||||
cvv1,
|
|
||||||
argv)) < 0){
|
|
||||||
if (argv != NULL)
|
|
||||||
cvec_free(argv);
|
|
||||||
cligen_fn_str_set(h, NULL);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* Clixon-specific */
|
|
||||||
if (plugin_context_check(pc, "CLIgen", cc->cc_fn_str) < 0)
|
|
||||||
break;
|
|
||||||
if (pc){
|
|
||||||
free(pc);
|
|
||||||
pc = NULL;
|
|
||||||
}
|
|
||||||
if (argv != NULL)
|
|
||||||
cvec_free(argv);
|
|
||||||
cligen_fn_str_set(h, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (pc) /* Clixon-specific */
|
|
||||||
free(pc);
|
|
||||||
if (cvv1)
|
|
||||||
cvec_free(cvv1);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Evaluate a matched command
|
|
||||||
* @param[in] h Clicon handle
|
|
||||||
* @param[in] cmd The command string
|
|
||||||
* @param[in] match_obj
|
|
||||||
* @param[in] cvv
|
|
||||||
* @retval int If there is a callback, the return value of the callback is returned,
|
|
||||||
* @retval 0 otherwise
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
clicon_eval(clicon_handle h,
|
|
||||||
char *cmd,
|
|
||||||
cg_obj *match_obj,
|
|
||||||
cvec *cvv)
|
|
||||||
{
|
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
cli_output_reset();
|
|
||||||
if (!cligen_exiting(cli_cligen(h))) {
|
|
||||||
clicon_err_reset();
|
|
||||||
|
|
||||||
if ((retval = clixon_cligen_eval(cli_cligen(h), match_obj, cvv)) < 0) {
|
|
||||||
#if 0 /* This is removed since we get two error messages on failure.
|
|
||||||
But maybe only sometime?
|
|
||||||
Both a real log when clicon_err is called, and the here again.
|
|
||||||
(Before clicon_err was silent) */
|
|
||||||
cli_handler_err(stdout);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Given a command string, parse and if match single command, eval it.
|
/*! Given a command string, parse and if match single command, eval it.
|
||||||
* Parse and evaluate the string according to
|
* Parse and evaluate the string according to
|
||||||
* the syntax parse tree of the syntax mode specified by *mode.
|
* the syntax parse tree of the syntax mode specified by *mode.
|
||||||
|
|
@ -646,16 +547,18 @@ clicon_parse(clicon_handle h,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *modename;
|
char *modename;
|
||||||
char *modename0;
|
int ret;
|
||||||
int r;
|
|
||||||
cli_syntax_t *stx = NULL;
|
cli_syntax_t *stx = NULL;
|
||||||
cli_syntaxmode_t *csm;
|
cli_syntaxmode_t *csm;
|
||||||
parse_tree *pt; /* Orig */
|
parse_tree *pt; /* Orig */
|
||||||
cg_obj *match_obj = NULL;
|
cg_obj *match_obj = NULL;
|
||||||
cvec *cvv = NULL;
|
cvec *cvv = NULL;
|
||||||
|
cg_callback *callbacks = NULL;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
char *reason = NULL;
|
char *reason = NULL;
|
||||||
|
cligen_handle ch;
|
||||||
|
|
||||||
|
ch = cli_cligen(h);
|
||||||
if (clicon_get_logflags()&CLICON_LOG_STDOUT)
|
if (clicon_get_logflags()&CLICON_LOG_STDOUT)
|
||||||
f = stdout;
|
f = stdout;
|
||||||
else
|
else
|
||||||
|
|
@ -672,34 +575,18 @@ clicon_parse(clicon_handle h,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (csm != NULL){
|
if (csm != NULL){
|
||||||
modename0 = NULL;
|
if (cligen_ph_active_set_byname(ch, modename) < 0){
|
||||||
if ((pt = cligen_pt_active_get(cli_cligen(h))) != NULL)
|
|
||||||
modename0 = pt_name_get(pt);
|
|
||||||
if (cligen_ph_active_set(cli_cligen(h), modename) < 0){
|
|
||||||
fprintf(stderr, "No such parse-tree registered: %s\n", modename);
|
fprintf(stderr, "No such parse-tree registered: %s\n", modename);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((pt = cligen_pt_active_get(cli_cligen(h))) == NULL){
|
if ((pt = cligen_pt_active_get(ch)) == NULL){
|
||||||
fprintf(stderr, "No such parse-tree registered: %s\n", modename);
|
fprintf(stderr, "No such parse-tree registered: %s\n", modename);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#if 0 // switch after 5.4
|
if (cliread_parse(ch, cmd, pt, &match_obj, &cvv, &callbacks, result, &reason) < 0)
|
||||||
if (cliread_parse2(cli_cligen(h), cmd, pt, &match_obj, &cvv, result, &reason) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
#else
|
|
||||||
if ((cvv = cvec_new(0)) == NULL)
|
|
||||||
goto done;;
|
|
||||||
if (cliread_parse(cli_cligen(h), cmd, pt, &match_obj, cvv, result, &reason) < 0)
|
|
||||||
goto done;
|
|
||||||
#endif
|
|
||||||
/* Debug command and result code */
|
/* Debug command and result code */
|
||||||
clicon_debug(1, "%s result:%d command: \"%s\"", __FUNCTION__, *result, cmd);
|
clicon_debug(1, "%s result:%d command: \"%s\"", __FUNCTION__, *result, cmd);
|
||||||
if (*result != CG_MATCH)
|
|
||||||
pt_expand_cleanup(pt); /* XXX change to pt_expand_treeref_cleanup */
|
|
||||||
if (modename0){
|
|
||||||
cligen_ph_active_set(cli_cligen(h), modename0);
|
|
||||||
modename0 = NULL;
|
|
||||||
}
|
|
||||||
switch (*result) {
|
switch (*result) {
|
||||||
case CG_EOF: /* eof */
|
case CG_EOF: /* eof */
|
||||||
case CG_ERROR:
|
case CG_ERROR:
|
||||||
|
|
@ -713,12 +600,17 @@ clicon_parse(clicon_handle h,
|
||||||
*modenamep = modename;
|
*modenamep = modename;
|
||||||
cli_set_syntax_mode(h, modename);
|
cli_set_syntax_mode(h, modename);
|
||||||
}
|
}
|
||||||
if ((r = clicon_eval(h, cmd, match_obj, cvv)) < 0)
|
cli_output_reset();
|
||||||
|
if (!cligen_exiting(ch)) {
|
||||||
|
clicon_err_reset();
|
||||||
|
if ((ret = cligen_eval(ch, match_obj, cvv, callbacks)) < 0)
|
||||||
cli_handler_err(stdout);
|
cli_handler_err(stdout);
|
||||||
pt_expand_cleanup(pt);
|
|
||||||
pt_expand_treeref_cleanup(pt);
|
}
|
||||||
|
else
|
||||||
|
ret = 0;
|
||||||
if (evalres)
|
if (evalres)
|
||||||
*evalres = r;
|
*evalres = ret;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(f, "CLI syntax error: \"%s\" is ambiguous\n", cmd);
|
fprintf(f, "CLI syntax error: \"%s\" is ambiguous\n", cmd);
|
||||||
|
|
@ -727,6 +619,8 @@ clicon_parse(clicon_handle h,
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (callbacks)
|
||||||
|
co_callbacks_free(&callbacks);
|
||||||
if (reason)
|
if (reason)
|
||||||
free(reason);
|
free(reason);
|
||||||
if (cvv)
|
if (cvv)
|
||||||
|
|
@ -850,7 +744,7 @@ clicon_cliread(clicon_handle h,
|
||||||
cli_prompt_set(h, promptstr);
|
cli_prompt_set(h, promptstr);
|
||||||
free(promptstr);
|
free(promptstr);
|
||||||
}
|
}
|
||||||
cligen_ph_active_set(cli_cligen(h), mode->csm_name);
|
cligen_ph_active_set_byname(cli_cligen(h), mode->csm_name);
|
||||||
|
|
||||||
if (cliread(cli_cligen(h), stringp) < 0){
|
if (cliread(cli_cligen(h), stringp) < 0){
|
||||||
clicon_err(OE_FATAL, errno, "CLIgen");
|
clicon_err(OE_FATAL, errno, "CLIgen");
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,10 @@
|
||||||
/* clicon generic callback pointer */
|
/* clicon generic callback pointer */
|
||||||
typedef void (clicon_callback_t)(clicon_handle h);
|
typedef void (clicon_callback_t)(clicon_handle h);
|
||||||
|
|
||||||
/* List of syntax modes */
|
/* List of syntax modes
|
||||||
|
* XXX: syntax modes seem not needed, could be replaced by existing (new) cligen structures, such
|
||||||
|
* as pt_head and others. But code is arcane and difficult to modify.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
qelem_t csm_qelem; /* List header */
|
qelem_t csm_qelem; /* List header */
|
||||||
char *csm_name; /* Syntax mode name */
|
char *csm_name; /* Syntax mode name */
|
||||||
|
|
@ -54,7 +57,8 @@ typedef struct {
|
||||||
parse_tree *csm_pt; /* CLIgen parse tree */
|
parse_tree *csm_pt; /* CLIgen parse tree */
|
||||||
} cli_syntaxmode_t;
|
} cli_syntaxmode_t;
|
||||||
|
|
||||||
/* Plugin group object. Just a single object, not list. part of cli_handle */
|
/* Plugin group object. Just a single object, not list. part of cli_handle
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int stx_nmodes; /* Number of syntax modes */
|
int stx_nmodes; /* Number of syntax modes */
|
||||||
cli_syntaxmode_t *stx_active_mode; /* Current active syntax mode */
|
cli_syntaxmode_t *stx_active_mode; /* Current active syntax mode */
|
||||||
|
|
@ -64,8 +68,6 @@ typedef struct {
|
||||||
|
|
||||||
void *clixon_str2fn(char *name, void *handle, char **error);
|
void *clixon_str2fn(char *name, void *handle, char **error);
|
||||||
|
|
||||||
int clicon_eval(clicon_handle h, char *cmd, cg_obj *match_obj, cvec *vr);
|
|
||||||
|
|
||||||
int clicon_parse(clicon_handle h, char *cmd, char **mode, cligen_result *result, int *evalres);
|
int clicon_parse(clicon_handle h, char *cmd, char **mode, cligen_result *result, int *evalres);
|
||||||
|
|
||||||
int clicon_cliread(clicon_handle h, char **stringp);
|
int clicon_cliread(clicon_handle h, char **stringp);
|
||||||
|
|
|
||||||
|
|
@ -337,7 +337,6 @@ struct clixon_plugin_api{
|
||||||
#define ca_trans_abort u.cau_backend.cb_trans_abort
|
#define ca_trans_abort u.cau_backend.cb_trans_abort
|
||||||
#define ca_datastore_upgrade u.cau_backend.cb_datastore_upgrade
|
#define ca_datastore_upgrade u.cau_backend.cb_datastore_upgrade
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Macros
|
* Macros
|
||||||
*/
|
*/
|
||||||
|
|
@ -379,8 +378,7 @@ int clixon_plugins_load(clicon_handle h, const char *function, const char *dir,
|
||||||
|
|
||||||
int clixon_pseudo_plugin(clicon_handle h, const char *name, clixon_plugin_t **cpp);
|
int clixon_pseudo_plugin(clicon_handle h, const char *name, clixon_plugin_t **cpp);
|
||||||
|
|
||||||
plugin_context_t * plugin_context_get(void);
|
int plugin_context_check(clicon_handle h, void **wh, const char *name, const char *fn);
|
||||||
int plugin_context_check(plugin_context_t *pc, const char *name, const char *fn);
|
|
||||||
|
|
||||||
int clixon_plugin_start_one(clixon_plugin_t *cp, clicon_handle h);
|
int clixon_plugin_start_one(clixon_plugin_t *cp, clicon_handle h);
|
||||||
int clixon_plugin_start_all(clicon_handle h);
|
int clixon_plugin_start_all(clicon_handle h);
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,10 @@ int yang_filename_set(yang_stmt *ys, const char *filename);
|
||||||
int yang_linenum_get(yang_stmt *ys);
|
int yang_linenum_get(yang_stmt *ys);
|
||||||
int yang_linenum_set(yang_stmt *ys, int linenum);
|
int yang_linenum_set(yang_stmt *ys, int linenum);
|
||||||
|
|
||||||
|
/* Stats */
|
||||||
|
int yang_stats_global(uint64_t *nr);
|
||||||
|
int yang_stats(yang_stmt *y, uint64_t *nrp, size_t *szp);
|
||||||
|
|
||||||
/* Other functions */
|
/* Other functions */
|
||||||
yang_stmt *yspec_new(void);
|
yang_stmt *yspec_new(void);
|
||||||
yang_stmt *ys_new(enum rfc_6020 keyw);
|
yang_stmt *ys_new(enum rfc_6020 keyw);
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@
|
||||||
#include "clixon_file.h"
|
#include "clixon_file.h"
|
||||||
#include "clixon_handle.h"
|
#include "clixon_handle.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
|
#include "clixon_options.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
#include "clixon_xml_nsctx.h"
|
#include "clixon_xml_nsctx.h"
|
||||||
#include "clixon_yang_module.h"
|
#include "clixon_yang_module.h"
|
||||||
|
|
@ -342,7 +343,7 @@ plugin_load_one(clicon_handle h,
|
||||||
clixon_plugin_t *cp = NULL;
|
clixon_plugin_t *cp = NULL;
|
||||||
char *name;
|
char *name;
|
||||||
char *p;
|
char *p;
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
clicon_debug(1, "%s file:%s function:%s", __FUNCTION__, file, function);
|
clicon_debug(1, "%s file:%s function:%s", __FUNCTION__, file, function);
|
||||||
dlerror(); /* Clear any existing error */
|
dlerror(); /* Clear any existing error */
|
||||||
|
|
@ -361,9 +362,9 @@ plugin_load_one(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
clicon_err_reset();
|
clicon_err_reset();
|
||||||
if ((pc = plugin_context_get()) < 0)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, file, __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if ((api = initfn(h)) == NULL) {
|
if ((api = initfn(h)) == NULL) {
|
||||||
if (!clicon_errno){ /* if clicon_err() is not called then log and continue */
|
if (!clicon_errno){ /* if clicon_err() is not called then log and continue */
|
||||||
clicon_log(LOG_DEBUG, "Warning: failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file);
|
clicon_log(LOG_DEBUG, "Warning: failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file);
|
||||||
|
|
@ -375,7 +376,7 @@ plugin_load_one(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, file, __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, file, __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Note: sizeof clixon_plugin_api which is largest of clixon_plugin_api:s */
|
/* Note: sizeof clixon_plugin_api which is largest of clixon_plugin_api:s */
|
||||||
|
|
@ -401,8 +402,8 @@ plugin_load_one(clicon_handle h,
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||||
if (pc)
|
if (wh != NULL)
|
||||||
free(pc);
|
free(wh);
|
||||||
if (retval != 1 && handle)
|
if (retval != 1 && handle)
|
||||||
dlclose(handle);
|
dlclose(handle);
|
||||||
if (cp)
|
if (cp)
|
||||||
|
|
@ -510,7 +511,7 @@ done:
|
||||||
* @retval NULL Error
|
* @retval NULL Error
|
||||||
* @see plugin_context_check
|
* @see plugin_context_check
|
||||||
* */
|
* */
|
||||||
plugin_context_t *
|
static void *
|
||||||
plugin_context_get(void)
|
plugin_context_get(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -521,7 +522,6 @@ plugin_context_get(void)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
memset(pc, 0, sizeof(*pc));
|
memset(pc, 0, sizeof(*pc));
|
||||||
|
|
||||||
if (sigprocmask(0, NULL, &pc->pc_sigset) < 0){
|
if (sigprocmask(0, NULL, &pc->pc_sigset) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "sigprocmask");
|
clicon_err(OE_UNIX, errno, "sigprocmask");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -553,30 +553,53 @@ plugin_context_get(void)
|
||||||
|
|
||||||
/*! Given an existing, old plugin context, check if anything has changed
|
/*! Given an existing, old plugin context, check if anything has changed
|
||||||
*
|
*
|
||||||
* Make a new check and compare with the old (procided as in-parameter).
|
* Called twice:
|
||||||
|
* 1) Make a check of resources
|
||||||
|
* 2) Make a new check and compare with the old check, return 1 on success, 0 on fail
|
||||||
* Log if there is a difference at loglevel WARNING.
|
* Log if there is a difference at loglevel WARNING.
|
||||||
* You can modify the code to also fail with assert if you want early fail.
|
* You can modify the code to also fail with assert if you want early fail.
|
||||||
|
* Controlled by option
|
||||||
*
|
*
|
||||||
* @param[in,out] oldpc Old plugin context
|
* @param[in] h Clixon handle
|
||||||
|
* @param[in,out] wh Either: NULL for init, will be assigned, OR previous handle (will be freed)
|
||||||
* @param[in] name Name of plugin for logging. Can be other name, context dependent
|
* @param[in] name Name of plugin for logging. Can be other name, context dependent
|
||||||
* @param[in] fn Typically name of callback, or caller function
|
* @param[in] fn Typically name of callback, or caller function
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @retval 0 Fail, log on syslog using LOG_WARNING
|
* @retval 0 Fail, log on syslog using LOG_WARNING
|
||||||
* @retval 1 OK
|
* @retval 1 OK
|
||||||
|
* @note Only logs error, does not generate error
|
||||||
* @note name and fn are context dependent, since the env of callback calls are very different
|
* @note name and fn are context dependent, since the env of callback calls are very different
|
||||||
* @see plugin_context_get
|
* @see plugin_context_get
|
||||||
|
* @see CLICON_PLUGIN_CALLBACK_CHECK Enable to activate these checks
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
plugin_context_check(plugin_context_t *oldpc0,
|
plugin_context_check(clicon_handle h,
|
||||||
|
void **wh,
|
||||||
const char *name,
|
const char *name,
|
||||||
const char *fn)
|
const char *fn)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int failed = 0;
|
int failed = 0;
|
||||||
int i;
|
int i;
|
||||||
struct plugin_context *oldpc = oldpc0;
|
struct plugin_context *oldpc;
|
||||||
struct plugin_context *newpc = NULL;
|
struct plugin_context *newpc = NULL;
|
||||||
|
|
||||||
|
if (h == NULL){
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Check if plugion checks are enabled */
|
||||||
|
if (!clicon_option_bool(h, "CLICON_PLUGIN_CALLBACK_CHECK"))
|
||||||
|
return 1;
|
||||||
|
if (wh == NULL){
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (*wh == NULL){
|
||||||
|
*wh = plugin_context_get();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
oldpc = (struct plugin_context *)*wh;
|
||||||
if ((newpc = plugin_context_get()) == NULL)
|
if ((newpc = plugin_context_get()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (oldpc->pc_termios.c_iflag != newpc->pc_termios.c_iflag){
|
if (oldpc->pc_termios.c_iflag != newpc->pc_termios.c_iflag){
|
||||||
|
|
@ -644,11 +667,14 @@ plugin_context_check(plugin_context_t *oldpc0,
|
||||||
}
|
}
|
||||||
if (failed)
|
if (failed)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
retval = 1; /* OK */
|
retval = 1; /* OK */
|
||||||
done:
|
done:
|
||||||
if (newpc)
|
if (newpc)
|
||||||
free(newpc);
|
free(newpc);
|
||||||
|
if (oldpc)
|
||||||
|
free(oldpc);
|
||||||
|
if (wh && *wh)
|
||||||
|
*wh = NULL;
|
||||||
return retval;
|
return retval;
|
||||||
fail:
|
fail:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -667,10 +693,11 @@ clixon_plugin_start_one(clixon_plugin_t *cp,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
plgstart_t *fn; /* Plugin start */
|
plgstart_t *fn; /* Plugin start */
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
if ((fn = cp->cp_api.ca_start) != NULL){
|
if ((fn = cp->cp_api.ca_start) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h) < 0) {
|
if (fn(h) < 0) {
|
||||||
if (clicon_errno < 0)
|
if (clicon_errno < 0)
|
||||||
|
|
@ -678,13 +705,11 @@ clixon_plugin_start_one(clixon_plugin_t *cp,
|
||||||
__FUNCTION__, cp->cp_name);
|
__FUNCTION__, cp->cp_name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, cp->cp_name, __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -722,10 +747,11 @@ clixon_plugin_exit_one(clixon_plugin_t *cp,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *error;
|
char *error;
|
||||||
plgexit_t *fn;
|
plgexit_t *fn;
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
if ((fn = cp->cp_api.ca_exit) != NULL){
|
if ((fn = cp->cp_api.ca_exit) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h) < 0) {
|
if (fn(h) < 0) {
|
||||||
if (clicon_errno < 0)
|
if (clicon_errno < 0)
|
||||||
|
|
@ -733,7 +759,7 @@ clixon_plugin_exit_one(clixon_plugin_t *cp,
|
||||||
__FUNCTION__, cp->cp_name);
|
__FUNCTION__, cp->cp_name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, cp->cp_name, __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (dlclose(cp->cp_handle) != 0) {
|
if (dlclose(cp->cp_handle) != 0) {
|
||||||
error = (char*)dlerror();
|
error = (char*)dlerror();
|
||||||
|
|
@ -742,8 +768,6 @@ clixon_plugin_exit_one(clixon_plugin_t *cp,
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -794,11 +818,12 @@ clixon_plugin_auth_one(clixon_plugin_t *cp,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
plgauth_t *fn; /* Plugin auth */
|
plgauth_t *fn; /* Plugin auth */
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if ((fn = cp->cp_api.ca_auth) != NULL){
|
if ((fn = cp->cp_api.ca_auth) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((retval = fn(h, req, auth_type, authp)) < 0) {
|
if ((retval = fn(h, req, auth_type, authp)) < 0) {
|
||||||
if (clicon_errno < 0)
|
if (clicon_errno < 0)
|
||||||
|
|
@ -806,14 +831,12 @@ clixon_plugin_auth_one(clixon_plugin_t *cp,
|
||||||
__FUNCTION__, cp->cp_name);
|
__FUNCTION__, cp->cp_name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, cp->cp_name, __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
retval = 0; /* Ignored / no callback */
|
retval = 0; /* Ignored / no callback */
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
clicon_debug(1, "%s retval:%d auth:%s", __FUNCTION__, retval, *authp);
|
clicon_debug(1, "%s retval:%d auth:%s", __FUNCTION__, retval, *authp);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
@ -879,10 +902,11 @@ clixon_plugin_extension_one(clixon_plugin_t *cp,
|
||||||
{
|
{
|
||||||
int retval = 1;
|
int retval = 1;
|
||||||
plgextension_t *fn; /* Plugin extension fn */
|
plgextension_t *fn; /* Plugin extension fn */
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
if ((fn = cp->cp_api.ca_extension) != NULL){
|
if ((fn = cp->cp_api.ca_extension) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h, yext, ys) < 0) {
|
if (fn(h, yext, ys) < 0) {
|
||||||
if (clicon_errno < 0)
|
if (clicon_errno < 0)
|
||||||
|
|
@ -890,13 +914,11 @@ clixon_plugin_extension_one(clixon_plugin_t *cp,
|
||||||
__FUNCTION__, cp->cp_name);
|
__FUNCTION__, cp->cp_name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, cp->cp_name, __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -950,10 +972,11 @@ clixon_plugin_datastore_upgrade_one(clixon_plugin_t *cp,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
datastore_upgrade_t *fn;
|
datastore_upgrade_t *fn;
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
|
|
||||||
if ((fn = cp->cp_api.ca_datastore_upgrade) != NULL){
|
if ((fn = cp->cp_api.ca_datastore_upgrade) != NULL){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h, db, xt, msd) < 0) {
|
if (fn(h, db, xt, msd) < 0) {
|
||||||
if (clicon_errno < 0)
|
if (clicon_errno < 0)
|
||||||
|
|
@ -961,13 +984,11 @@ clixon_plugin_datastore_upgrade_one(clixon_plugin_t *cp,
|
||||||
__FUNCTION__, cp->cp_name);
|
__FUNCTION__, cp->cp_name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (plugin_context_check(pc, cp->cp_name, __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1121,7 +1142,7 @@ rpc_callback_call(clicon_handle h,
|
||||||
char *ns;
|
char *ns;
|
||||||
int nr = 0; /* How many callbacks */
|
int nr = 0; /* How many callbacks */
|
||||||
plugin_module_struct *ms = plugin_module_struct_get(h);
|
plugin_module_struct *ms = plugin_module_struct_get(h);
|
||||||
plugin_context_t *pc = NULL;
|
void *wh = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (ms == NULL){
|
if (ms == NULL){
|
||||||
|
|
@ -1136,19 +1157,18 @@ rpc_callback_call(clicon_handle h,
|
||||||
if (strcmp(rc->rc_name, name) == 0 &&
|
if (strcmp(rc->rc_name, name) == 0 &&
|
||||||
ns && rc->rc_namespace &&
|
ns && rc->rc_namespace &&
|
||||||
strcmp(rc->rc_namespace, ns) == 0){
|
strcmp(rc->rc_namespace, ns) == 0){
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
wh = NULL;
|
||||||
|
if (plugin_context_check(h, &wh, rc->rc_name, __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (rc->rc_callback(h, xe, cbret, arg, rc->rc_arg) < 0){
|
if (rc->rc_callback(h, xe, cbret, arg, rc->rc_arg) < 0){
|
||||||
clicon_debug(1, "%s Error in: %s", __FUNCTION__, rc->rc_name);
|
clicon_debug(1, "%s Error in: %s", __FUNCTION__, rc->rc_name);
|
||||||
|
if (plugin_context_check(h, &wh, rc->rc_name, __FUNCTION__) < 0)
|
||||||
|
goto done;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
nr++;
|
nr++;
|
||||||
if (plugin_context_check(pc, rc->rc_name, __FUNCTION__) < 0)
|
if (plugin_context_check(h, &wh, rc->rc_name, __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (pc){
|
|
||||||
free(pc);
|
|
||||||
pc = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
rc = NEXTQ(rpc_callback_t *, rc);
|
rc = NEXTQ(rpc_callback_t *, rc);
|
||||||
} while (rc != ms->ms_rpc_callbacks);
|
} while (rc != ms->ms_rpc_callbacks);
|
||||||
|
|
@ -1162,8 +1182,6 @@ rpc_callback_call(clicon_handle h,
|
||||||
retval = 1; /* 0: none found, >0 nr of handlers called */
|
retval = 1; /* 0: none found, >0 nr of handlers called */
|
||||||
done:
|
done:
|
||||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||||
if (pc)
|
|
||||||
free(pc);
|
|
||||||
return retval;
|
return retval;
|
||||||
fail:
|
fail:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
|
||||||
|
|
@ -1505,6 +1505,7 @@ rpc_reply_check(clicon_handle h,
|
||||||
if ((ret = xml_bind_yang_rpc_reply(x, rpcname, yspec, &xret)) < 0)
|
if ((ret = xml_bind_yang_rpc_reply(x, rpcname, yspec, &xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
|
clicon_debug(1, "%s failure when validating:%s", __FUNCTION__, cbuf_get(cbret));
|
||||||
cbuf_reset(cbret);
|
cbuf_reset(cbret);
|
||||||
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
|
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1513,6 +1514,7 @@ rpc_reply_check(clicon_handle h,
|
||||||
if ((ret = xml_yang_validate_rpc_reply(h, x, &xret)) < 0)
|
if ((ret = xml_yang_validate_rpc_reply(h, x, &xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
|
clicon_debug(1, "%s failure when validating:%s", __FUNCTION__, cbuf_get(cbret));
|
||||||
cbuf_reset(cbret);
|
cbuf_reset(cbret);
|
||||||
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
|
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -232,19 +232,20 @@ xml_type2str(enum cxobj_type type)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stats */
|
/* Stats */
|
||||||
uint64_t _stats_nr = 0;
|
static uint64_t _stats_xml_nr = 0;
|
||||||
|
|
||||||
/*! Get global statistics about XML objects
|
/*! Get global statistics about XML objects
|
||||||
|
*
|
||||||
|
* @param[out] nr Number of existing XML objects (created - freed)
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml_stats_global(uint64_t *nr)
|
xml_stats_global(uint64_t *nr)
|
||||||
{
|
{
|
||||||
if (nr)
|
if (nr)
|
||||||
*nr = _stats_nr;
|
*nr = _stats_xml_nr;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Return the alloced memory of a single XML obj
|
/*! Return the alloced memory of a single XML obj
|
||||||
* @param[in] x XML object
|
* @param[in] x XML object
|
||||||
* @param[out] szp Size of this XML obj
|
* @param[out] szp Size of this XML obj
|
||||||
|
|
@ -257,7 +258,6 @@ xml_stats_one(cxobj *x,
|
||||||
{
|
{
|
||||||
size_t sz = 0;
|
size_t sz = 0;
|
||||||
|
|
||||||
|
|
||||||
if (x->x_name)
|
if (x->x_name)
|
||||||
sz += strlen(x->x_name) + 1;
|
sz += strlen(x->x_name) + 1;
|
||||||
if (x->x_prefix)
|
if (x->x_prefix)
|
||||||
|
|
@ -292,51 +292,12 @@ xml_stats_one(cxobj *x,
|
||||||
}
|
}
|
||||||
if (szp)
|
if (szp)
|
||||||
*szp = sz;
|
*szp = sz;
|
||||||
clicon_debug(1, "%s %zu", __FUNCTION__, sz);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
/*! Print memory stats of a single object
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
xml_print_stats_one(FILE *f,
|
|
||||||
cxobj *x)
|
|
||||||
{
|
|
||||||
size_t sz = 0;
|
|
||||||
|
|
||||||
xml_stats_one(x, &sz);
|
|
||||||
fprintf(f, "%s:\n", xml_name(x));
|
|
||||||
fprintf(f, " sum: \t\t%u\n", (unsigned int)sz);
|
|
||||||
if (xml_type(x) == CX_ELMNT)
|
|
||||||
fprintf(f, " base struct: \t%u\n", (unsigned int)sizeof(struct xml));
|
|
||||||
else
|
|
||||||
fprintf(f, " base struct: \t%u\n", (unsigned int)sizeof(struct xmlbody));
|
|
||||||
if (x->x_name)
|
|
||||||
fprintf(f, " name: \t%u\n", (unsigned int)strlen(x->x_name) + 1);
|
|
||||||
if (x->x_prefix)
|
|
||||||
fprintf(f, " prefix: \t%u\n", (unsigned int)strlen(x->x_prefix) + 1);
|
|
||||||
if (xml_type(x) == CX_ELMNT){
|
|
||||||
if (x->x_childvec_max)
|
|
||||||
fprintf(f, " childvec: \t%u\n", (unsigned int)(x->x_childvec_max*sizeof(struct xml*)));
|
|
||||||
if (x->x_ns_cache)
|
|
||||||
fprintf(f, " ns-cache: \t%u\n", (unsigned int)cvec_size(x->x_ns_cache));
|
|
||||||
if (x->x_cv)
|
|
||||||
fprintf(f, " value-cv: \t%u\n", (unsigned int)cv_size(x->x_cv));
|
|
||||||
if (x->x_search_index)
|
|
||||||
fprintf(f, " search-index: \t%u\n",
|
|
||||||
(unsigned int)(strlen(x->x_search_index->si_name) + 1 + clixon_xvec_len(x->x_search_index->si_xvec)*sizeof(struct cxobj*)));
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
if (x->x_value_cb)
|
|
||||||
fprintf(f, " value-cb: \t%u\n", cbuf_buflen(x->x_value_cb));
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*! Return statistics of an XML tree recursively
|
/*! Return statistics of an XML tree recursively
|
||||||
* @param[in] xt XML object
|
* @param[in] xt XML object
|
||||||
|
* @param[out] nrp Number of XML obj recursively
|
||||||
* @param[out] szp Size of this XML obj recursively
|
* @param[out] szp Size of this XML obj recursively
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
|
|
@ -354,7 +315,6 @@ xml_stats(cxobj *xt,
|
||||||
clicon_err(OE_XML, EINVAL, "xml node is NULL");
|
clicon_err(OE_XML, EINVAL, "xml node is NULL");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
// xml_print_stats_one(stderr, xt);
|
|
||||||
*nrp += 1;
|
*nrp += 1;
|
||||||
xml_stats_one(xt, &sz);
|
xml_stats_one(xt, &sz);
|
||||||
if (szp)
|
if (szp)
|
||||||
|
|
@ -366,7 +326,6 @@ xml_stats(cxobj *xt,
|
||||||
if (szp)
|
if (szp)
|
||||||
*szp += sz;
|
*szp += sz;
|
||||||
}
|
}
|
||||||
clicon_debug(1, "%s %zu", __FUNCTION__, *szp);
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -1131,7 +1090,7 @@ xml_new(char *name,
|
||||||
return NULL;
|
return NULL;
|
||||||
x->_x_i = xml_child_nr(xp)-1;
|
x->_x_i = xml_child_nr(xp)-1;
|
||||||
}
|
}
|
||||||
_stats_nr++;
|
_stats_xml_nr++;
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1901,7 +1860,7 @@ xml_free(cxobj *x)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
free(x);
|
free(x);
|
||||||
_stats_nr--;
|
_stats_xml_nr--;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -473,6 +473,100 @@ yang_linenum_set(yang_stmt *ys,
|
||||||
|
|
||||||
/* End access functions */
|
/* End access functions */
|
||||||
|
|
||||||
|
/* Stats */
|
||||||
|
static uint64_t _stats_yang_nr = 0;
|
||||||
|
|
||||||
|
/*! Get global statistics about YANG statements: created - freed
|
||||||
|
*
|
||||||
|
* @param[out] nr Number of existing YANG objects (created - freed)
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
yang_stats_global(uint64_t *nr)
|
||||||
|
{
|
||||||
|
if (nr)
|
||||||
|
*nr = _stats_yang_nr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Return the alloced memory of a single YANG obj
|
||||||
|
* @param[in] y YANG object
|
||||||
|
* @param[out] szp Size of this YANG obj
|
||||||
|
* @retval 0 OK
|
||||||
|
* (baseline: )
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
yang_stats_one(yang_stmt *y,
|
||||||
|
size_t *szp)
|
||||||
|
{
|
||||||
|
size_t sz = 0;
|
||||||
|
yang_type_cache *yc;
|
||||||
|
|
||||||
|
sz += sizeof(struct yang_stmt);
|
||||||
|
sz += y->ys_len*sizeof(struct yang_stmt*);
|
||||||
|
if (y->ys_argument)
|
||||||
|
sz += strlen(y->ys_argument) + 1;
|
||||||
|
if (y->ys_cv)
|
||||||
|
sz += cv_size(y->ys_cv);
|
||||||
|
if (y->ys_cvec)
|
||||||
|
sz += cvec_size(y->ys_cvec);
|
||||||
|
if ((yc = y->ys_typecache) != NULL){
|
||||||
|
sz += sizeof(struct yang_type_cache);
|
||||||
|
if (yc->yc_cvv)
|
||||||
|
sz += cvec_size(yc->yc_cvv);
|
||||||
|
if (yc->yc_patterns)
|
||||||
|
sz += cvec_size(yc->yc_patterns);
|
||||||
|
if (yc->yc_regexps)
|
||||||
|
sz += cvec_size(yc->yc_regexps);
|
||||||
|
}
|
||||||
|
if (y->ys_when_xpath)
|
||||||
|
sz += strlen(y->ys_when_xpath) + 1;
|
||||||
|
if (y->ys_when_nsc)
|
||||||
|
sz += cvec_size(y->ys_when_nsc);
|
||||||
|
if (y->ys_filename)
|
||||||
|
sz += strlen(y->ys_filename) + 1;
|
||||||
|
if (szp)
|
||||||
|
*szp = sz;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Return statistics of an YANG-stmt tree recursively
|
||||||
|
* @param[in] yt YANG object
|
||||||
|
* @param[out] nrp Number of YANG objects recursively
|
||||||
|
* @param[out] szp Size of this YANG stmt recursively
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
yang_stats(yang_stmt *yt,
|
||||||
|
uint64_t *nrp,
|
||||||
|
size_t *szp)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
size_t sz = 0;
|
||||||
|
yang_stmt *ys;
|
||||||
|
|
||||||
|
if (yt == NULL){
|
||||||
|
clicon_err(OE_XML, EINVAL, "yang spec is NULL");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
*nrp += 1;
|
||||||
|
yang_stats_one(yt, &sz);
|
||||||
|
if (szp)
|
||||||
|
*szp += sz;
|
||||||
|
ys = NULL;
|
||||||
|
while ((ys = yn_each(yt, ys)) != NULL) {
|
||||||
|
sz = 0;
|
||||||
|
yang_stats(ys, nrp, &sz);
|
||||||
|
if (szp)
|
||||||
|
*szp += sz;
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stats end */
|
||||||
|
|
||||||
/*! Create new yang specification
|
/*! Create new yang specification
|
||||||
* @retval yspec Free with ys_free()
|
* @retval yspec Free with ys_free()
|
||||||
* @retval NULL Error
|
* @retval NULL Error
|
||||||
|
|
@ -488,6 +582,7 @@ yspec_new(void)
|
||||||
}
|
}
|
||||||
memset(yspec, 0, sizeof(*yspec));
|
memset(yspec, 0, sizeof(*yspec));
|
||||||
yspec->ys_keyword = Y_SPEC;
|
yspec->ys_keyword = Y_SPEC;
|
||||||
|
_stats_yang_nr++;
|
||||||
return yspec;
|
return yspec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -514,6 +609,7 @@ ys_new(enum rfc_6020 keyw)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
yang_cvec_set(ys, cvv);
|
yang_cvec_set(ys, cvv);
|
||||||
|
_stats_yang_nr++;
|
||||||
return ys;
|
return ys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -555,8 +651,10 @@ ys_free1(yang_stmt *ys,
|
||||||
free(ys->ys_stmt);
|
free(ys->ys_stmt);
|
||||||
if (ys->ys_filename)
|
if (ys->ys_filename)
|
||||||
free(ys->ys_filename);
|
free(ys->ys_filename);
|
||||||
if (self)
|
if (self){
|
||||||
free(ys);
|
free(ys);
|
||||||
|
_stats_yang_nr++;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,8 @@ CLIXON_VERSION=@CLIXON_VERSION@
|
||||||
DATASTORE_TOP="config"
|
DATASTORE_TOP="config"
|
||||||
|
|
||||||
# clixon yang revisions occuring in tests
|
# clixon yang revisions occuring in tests
|
||||||
CLIXON_LIB_REV="2021-03-08"
|
CLIXON_LIB_REV="2021-11-11"
|
||||||
CLIXON_CONFIG_REV="2021-05-20"
|
CLIXON_CONFIG_REV="2021-11-11"
|
||||||
CLIXON_RESTCONF_REV="2021-05-20"
|
CLIXON_RESTCONF_REV="2021-05-20"
|
||||||
CLIXON_EXAMPLE_REV="2020-12-01"
|
CLIXON_EXAMPLE_REV="2020-12-01"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -270,6 +270,7 @@ fi
|
||||||
# arg1: expected
|
# arg1: expected
|
||||||
# arg2: errmsg[optional]
|
# arg2: errmsg[optional]
|
||||||
# Assumes: $dir and $expect are set
|
# Assumes: $dir and $expect are set
|
||||||
|
# see err1
|
||||||
function err(){
|
function err(){
|
||||||
echo -e "\e[31m\nError in Test$testnr [$testname]:"
|
echo -e "\e[31m\nError in Test$testnr [$testname]:"
|
||||||
if [ $# -gt 0 ]; then
|
if [ $# -gt 0 ]; then
|
||||||
|
|
|
||||||
|
|
@ -112,8 +112,6 @@ expectpart "$($clixon_cli -1 -f $cfg err x)" 255 "Config error: api-path syntax
|
||||||
new "err x a"
|
new "err x a"
|
||||||
expectpart "$($clixon_cli -1 -f $cfg err x a 99)" 255 "Config error: api-path syntax error \"/example:x/m1=%s\": rpc malformed-message List key m1 length mismatch : Invalid argument"
|
expectpart "$($clixon_cli -1 -f $cfg err x a 99)" 255 "Config error: api-path syntax error \"/example:x/m1=%s\": rpc malformed-message List key m1 length mismatch : Invalid argument"
|
||||||
|
|
||||||
endtest
|
|
||||||
|
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
# Check if premature kill
|
# Check if premature kill
|
||||||
pid=$(pgrep -u root -f clixon_backend)
|
pid=$(pgrep -u root -f clixon_backend)
|
||||||
|
|
@ -123,4 +121,6 @@ fi
|
||||||
# kill backend
|
# kill backend
|
||||||
stop_backend -f $cfg
|
stop_backend -f $cfg
|
||||||
|
|
||||||
|
endtest
|
||||||
|
|
||||||
rm -rf $dir
|
rm -rf $dir
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,7 @@ expectpart "$(cat $dir/config.cli)" 0 "set network-instances network-instance de
|
||||||
|
|
||||||
new "load saved cli config"
|
new "load saved cli config"
|
||||||
expectpart "$(cat $dir/config.cli | $clixon_cli -D $DBG -f $cfg 2>&1 > /dev/null)" 0 "^$"
|
expectpart "$(cat $dir/config.cli | $clixon_cli -D $DBG -f $cfg 2>&1 > /dev/null)" 0 "^$"
|
||||||
|
#time cat $dir/config.cli | $clixon_cli -D $DBG -f $cfg
|
||||||
|
|
||||||
if [ $BE -ne 0 ]; then
|
if [ $BE -ne 0 ]; then
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ function testrun(){
|
||||||
|
|
||||||
new "netconf get stats"
|
new "netconf get stats"
|
||||||
res=$(echo "$DEFAULTHELLO<rpc $DEFAULTNS><stats $LIBNS/></rpc>]]>]]>" | $clixon_netconf -qf $cfg)
|
res=$(echo "$DEFAULTHELLO<rpc $DEFAULTNS><stats $LIBNS/></rpc>]]>]]>" | $clixon_netconf -qf $cfg)
|
||||||
echo "res:$res"
|
# echo "res:$res"
|
||||||
err0=$(echo "$res" | $clixon_util_xpath -p "/rpc-reply/rpc-error")
|
err0=$(echo "$res" | $clixon_util_xpath -p "/rpc-reply/rpc-error")
|
||||||
err=${err0#"nodeset:"}
|
err=${err0#"nodeset:"}
|
||||||
if [ -n "$err" ]; then
|
if [ -n "$err" ]; then
|
||||||
|
|
@ -104,7 +104,7 @@ function testrun(){
|
||||||
echo " objects: $objects"
|
echo " objects: $objects"
|
||||||
|
|
||||||
#
|
#
|
||||||
if [ -f /proc/$pid/statm ]; then # This ony works on Linux
|
if [ -f /proc/$pid/statm ]; then # This only works on Linux
|
||||||
# cat /proc/$pid/statm
|
# cat /proc/$pid/statm
|
||||||
echo -n " /proc/$pid/statm: "
|
echo -n " /proc/$pid/statm: "
|
||||||
cat /proc/$pid/statm|awk '{print $1*4/1000 "M"}'
|
cat /proc/$pid/statm|awk '{print $1*4/1000 "M"}'
|
||||||
|
|
@ -121,7 +121,15 @@ function testrun(){
|
||||||
echo -n " mem: "
|
echo -n " mem: "
|
||||||
echo $resdb | $clixon_util_xpath -p "datastore/size" | awk -F ">" '{print $2}' | awk -F "<" '{print $1}' | awk '{print $1/1000000 "M"}'
|
echo $resdb | $clixon_util_xpath -p "datastore/size" | awk -F ">" '{print $2}' | awk -F "<" '{print $1}' | awk '{print $1/1000000 "M"}'
|
||||||
done
|
done
|
||||||
|
for mod in clixon-config; do
|
||||||
|
echo "$mod"
|
||||||
|
resmod0=$(echo "$res" | $clixon_util_xpath -p "/rpc-reply/module[name=\"$mod\"]")
|
||||||
|
resmod=${resmod0#"nodeset:0:"}
|
||||||
|
echo -n " objects: "
|
||||||
|
echo $resmod | $clixon_util_xpath -p "module/nr" | awk -F ">" '{print $2}' | awk -F "<" '{print $1}'
|
||||||
|
echo -n " mem: "
|
||||||
|
echo $resmod | $clixon_util_xpath -p "module/size" | awk -F ">" '{print $2}' | awk -F "<" '{print $1}' | awk '{print $1/1000000 "M"}'
|
||||||
|
done
|
||||||
if [ $BE -ne 0 ]; then
|
if [ $BE -ne 0 ]; then
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
# Check if premature kill
|
# Check if premature kill
|
||||||
|
|
|
||||||
|
|
@ -88,9 +88,19 @@ if [ $BE -ne 0 ]; then # Bring your own backend
|
||||||
start_backend -s $db -f $cfg
|
start_backend -s $db -f $cfg
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
new "wait backend"
|
||||||
|
wait_backend
|
||||||
|
|
||||||
# permission kludges
|
# permission kludges
|
||||||
|
new "chmod datastores"
|
||||||
sudo chmod 666 $dir/running_db
|
sudo chmod 666 $dir/running_db
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err1 "chmod $dir/running_db"
|
||||||
|
fi
|
||||||
sudo chmod 666 $dir/startup_db
|
sudo chmod 666 $dir/startup_db
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err1 "chmod $dir/startup_db"
|
||||||
|
fi
|
||||||
|
|
||||||
new "Checking startup unchanged"
|
new "Checking startup unchanged"
|
||||||
ret=$(diff $dir/startup_db <(echo "<${DATASTORE_TOP}>$XML</${DATASTORE_TOP}>"))
|
ret=$(diff $dir/startup_db <(echo "<${DATASTORE_TOP}>$XML</${DATASTORE_TOP}>"))
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,7 @@ main(int argc,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
clicon_debug_init(dbg, NULL);
|
clicon_debug_init(dbg, NULL);
|
||||||
|
yang_init(h);
|
||||||
/* Find and read configfile */
|
/* Find and read configfile */
|
||||||
if (clicon_options_main(h) < 0)
|
if (clicon_options_main(h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,7 @@ main(int argc,
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_conf_xml_set(h, xcfg) < 0)
|
if (clicon_conf_xml_set(h, xcfg) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
optind = 1;
|
optind = 1;
|
||||||
opterr = 0;
|
opterr = 0;
|
||||||
while ((c = getopt(argc, argv, UTIL_XML_OPTS)) != -1)
|
while ((c = getopt(argc, argv, UTIL_XML_OPTS)) != -1)
|
||||||
|
|
@ -241,6 +242,7 @@ main(int argc,
|
||||||
}
|
}
|
||||||
clicon_log_init(__FILE__, dbg?LOG_DEBUG:LOG_INFO, logdst);
|
clicon_log_init(__FILE__, dbg?LOG_DEBUG:LOG_INFO, logdst);
|
||||||
clicon_debug_init(dbg, NULL);
|
clicon_debug_init(dbg, NULL);
|
||||||
|
yang_init(h);
|
||||||
|
|
||||||
/* 1. Parse yang */
|
/* 1. Parse yang */
|
||||||
if (yang_file_dir){
|
if (yang_file_dir){
|
||||||
|
|
|
||||||
|
|
@ -228,6 +228,7 @@ main(int argc,
|
||||||
clicon_log_init("xpath", dbg?LOG_DEBUG:LOG_INFO, logdst);
|
clicon_log_init("xpath", dbg?LOG_DEBUG:LOG_INFO, logdst);
|
||||||
|
|
||||||
clicon_debug_init(dbg, NULL);
|
clicon_debug_init(dbg, NULL);
|
||||||
|
yang_init(h);
|
||||||
|
|
||||||
/* Parse yang */
|
/* Parse yang */
|
||||||
if (yang_file_dir){
|
if (yang_file_dir){
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ YANG_INSTALLDIR = @YANG_INSTALLDIR@
|
||||||
|
|
||||||
YANGSPECS = clixon-config@2021-07-11.yang # 5.3
|
YANGSPECS = clixon-config@2021-07-11.yang # 5.3
|
||||||
YANGSPECS = clixon-config@2021-11-11.yang # 5.4
|
YANGSPECS = clixon-config@2021-11-11.yang # 5.4
|
||||||
YANGSPECS += clixon-lib@2021-03-08.yang # 5.1
|
YANGSPECS += clixon-lib@2021-11-11.yang # 5.4
|
||||||
YANGSPECS += clixon-rfc5277@2008-07-01.yang
|
YANGSPECS += clixon-rfc5277@2008-07-01.yang
|
||||||
YANGSPECS += clixon-xml-changelog@2019-03-21.yang
|
YANGSPECS += clixon-xml-changelog@2019-03-21.yang
|
||||||
YANGSPECS += clixon-restconf@2021-05-20.yang # 5.2
|
YANGSPECS += clixon-restconf@2021-05-20.yang # 5.2
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,9 @@ module clixon-config {
|
||||||
|
|
||||||
revision 2021-11-11 {
|
revision 2021-11-11 {
|
||||||
description
|
description
|
||||||
"Modified options:
|
"Added option:
|
||||||
|
CLICON_PLUGIN_CALLBACK_CHECK
|
||||||
|
Modified options:
|
||||||
CLICON_CLI_GENMODEL_TYPE: added OC_COMPRESS enum
|
CLICON_CLI_GENMODEL_TYPE: added OC_COMPRESS enum
|
||||||
CLICON_YANG_DIR: recursive search
|
CLICON_YANG_DIR: recursive search
|
||||||
Released in Clixon 5.4";
|
Released in Clixon 5.4";
|
||||||
|
|
@ -930,6 +932,24 @@ module clixon-config {
|
||||||
lists, therefore it is recommended to enable it during development and debugging
|
lists, therefore it is recommended to enable it during development and debugging
|
||||||
but disable it in production, until this has been resolved.";
|
but disable it in production, until this has been resolved.";
|
||||||
}
|
}
|
||||||
|
leaf CLICON_PLUGIN_CALLBACK_CHECK {
|
||||||
|
type boolean;
|
||||||
|
default false;
|
||||||
|
description
|
||||||
|
"If enabled, make a check of resources before and after each plugin callback code
|
||||||
|
to check if the plugin violated resources.
|
||||||
|
This is primarily intended for development and debugging but may also be enabled
|
||||||
|
in a running system.
|
||||||
|
If enabled, errors will be logged to syslog as WARNINGs.
|
||||||
|
In case you want early detection and crash, you can uncomment assert statements and
|
||||||
|
recompile.
|
||||||
|
The checks are currently made by plugin_context_check() and include:
|
||||||
|
- termios settings
|
||||||
|
- signal vectors
|
||||||
|
The checks will be made for all callbacks as defined in struct clixon_plugin_api
|
||||||
|
as well as the CLIgen callbacks.
|
||||||
|
See https://clixon-docs.readthedocs.io/en/latest/backend.html#plugin-callback-guidelines";
|
||||||
|
}
|
||||||
leaf CLICON_NAMESPACE_NETCONF_DEFAULT {
|
leaf CLICON_NAMESPACE_NETCONF_DEFAULT {
|
||||||
type boolean;
|
type boolean;
|
||||||
default false;
|
default false;
|
||||||
|
|
|
||||||
262
yang/clixon/clixon-lib@2021-11-11.yang
Normal file
262
yang/clixon/clixon-lib@2021-11-11.yang
Normal file
|
|
@ -0,0 +1,262 @@
|
||||||
|
module clixon-lib {
|
||||||
|
yang-version 1.1;
|
||||||
|
namespace "http://clicon.org/lib";
|
||||||
|
prefix cl;
|
||||||
|
|
||||||
|
import ietf-yang-types {
|
||||||
|
prefix yang;
|
||||||
|
}
|
||||||
|
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
|
||||||
|
Copyright (C) 2020-2021 Olof Hagsand and Rubicon Communications, LLC(Netgate)
|
||||||
|
|
||||||
|
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 2021-11-11 {
|
||||||
|
description
|
||||||
|
"Changed: RPC stats extended with YANG stats";
|
||||||
|
}
|
||||||
|
revision 2021-03-08 {
|
||||||
|
description
|
||||||
|
"Changed: RPC process-control output to choice dependent on operation";
|
||||||
|
}
|
||||||
|
revision 2020-12-30 {
|
||||||
|
description
|
||||||
|
"Changed: RPC process-control output parameter status to pid";
|
||||||
|
}
|
||||||
|
revision 2020-12-08 {
|
||||||
|
description
|
||||||
|
"Added: autocli-op extension.
|
||||||
|
rpc process-control for process/daemon management
|
||||||
|
Released in clixon 4.9";
|
||||||
|
}
|
||||||
|
revision 2020-04-23 {
|
||||||
|
description
|
||||||
|
"Added: stats RPC for clixon XML and memory statistics.
|
||||||
|
Added: restart-plugin RPC for restarting individual plugins without restarting backend.";
|
||||||
|
}
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
typedef service-operation {
|
||||||
|
type enumeration {
|
||||||
|
enum start {
|
||||||
|
description
|
||||||
|
"Start if not already running";
|
||||||
|
}
|
||||||
|
enum stop {
|
||||||
|
description
|
||||||
|
"Stop if running";
|
||||||
|
}
|
||||||
|
enum restart {
|
||||||
|
description
|
||||||
|
"Stop if running, then start";
|
||||||
|
}
|
||||||
|
enum status {
|
||||||
|
description
|
||||||
|
"Check status";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
description
|
||||||
|
"Common operations that can be performed on a service";
|
||||||
|
}
|
||||||
|
extension autocli-op {
|
||||||
|
description
|
||||||
|
"Takes an argument an operation defing how to modify the clispec at
|
||||||
|
this point in the YANG tree for the automated generated CLI.
|
||||||
|
Note that this extension is only used in clixon_cli.
|
||||||
|
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)";
|
||||||
|
argument cliop;
|
||||||
|
}
|
||||||
|
rpc debug {
|
||||||
|
description "Set debug level of backend.";
|
||||||
|
input {
|
||||||
|
leaf level {
|
||||||
|
type uint32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rpc ping {
|
||||||
|
description "Check aliveness of backend daemon.";
|
||||||
|
}
|
||||||
|
rpc stats {
|
||||||
|
description "Clixon XML statistics.";
|
||||||
|
output {
|
||||||
|
container global{
|
||||||
|
description
|
||||||
|
"Clixon global statistics.
|
||||||
|
These are global counters incremented by new() and decreased by free() calls.
|
||||||
|
This number is higher than the sum of all datastore/module residing objects, since
|
||||||
|
objects may be used for other purposes than datastore/modules";
|
||||||
|
leaf xmlnr{
|
||||||
|
description
|
||||||
|
"Number of existing XML objects: number of residing xml/json objects
|
||||||
|
in the internal 'cxobj' representation.";
|
||||||
|
type uint64;
|
||||||
|
}
|
||||||
|
leaf yangnr{
|
||||||
|
description
|
||||||
|
"Number of resident YANG objects. ";
|
||||||
|
type uint64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list datastore{
|
||||||
|
description "Per datastore statistics for cxobj";
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list module{
|
||||||
|
description "Per YANG module statistics";
|
||||||
|
key "name";
|
||||||
|
leaf name{
|
||||||
|
description "Name of YANG module.";
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
leaf nr{
|
||||||
|
description
|
||||||
|
"Number of YANG objects. That is number of residing YANG objects";
|
||||||
|
type uint64;
|
||||||
|
}
|
||||||
|
leaf size{
|
||||||
|
description
|
||||||
|
"Size in bytes of internal YANG object representation.";
|
||||||
|
type uint64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rpc restart-plugin {
|
||||||
|
description "Restart specific backend plugins.";
|
||||||
|
input {
|
||||||
|
leaf-list plugin {
|
||||||
|
description "Name of plugin to restart";
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc process-control {
|
||||||
|
description
|
||||||
|
"Control a specific process or daemon: start/stop, etc.
|
||||||
|
This is for direct managing of a process by the backend.
|
||||||
|
Alternatively one can manage a daemon via systemd, containerd, kubernetes, etc.";
|
||||||
|
input {
|
||||||
|
leaf name {
|
||||||
|
description "Name of process";
|
||||||
|
type string;
|
||||||
|
mandatory true;
|
||||||
|
}
|
||||||
|
leaf operation {
|
||||||
|
type service-operation;
|
||||||
|
mandatory true;
|
||||||
|
description
|
||||||
|
"One of the strings 'start', 'stop', 'restart', or 'status'.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output {
|
||||||
|
choice result {
|
||||||
|
case status {
|
||||||
|
description
|
||||||
|
"Output from status rpc";
|
||||||
|
leaf active {
|
||||||
|
description
|
||||||
|
"True if process is running, false if not.
|
||||||
|
More specifically, there is a process-id and it exists (in Linux: kill(pid,0).
|
||||||
|
Note that this is actual state and status is administrative state,
|
||||||
|
which means that changing the administrative state, eg stopped->running
|
||||||
|
may not immediately switch active to true.";
|
||||||
|
type boolean;
|
||||||
|
}
|
||||||
|
leaf description {
|
||||||
|
type string;
|
||||||
|
description "Description of process. This is a static string";
|
||||||
|
}
|
||||||
|
leaf command {
|
||||||
|
type string;
|
||||||
|
description "Start command with arguments";
|
||||||
|
}
|
||||||
|
leaf status {
|
||||||
|
description
|
||||||
|
"Administrative status (except on external kill where it enters stopped
|
||||||
|
directly from running):
|
||||||
|
stopped: pid=0, No process running
|
||||||
|
running: pid set, Process started and believed to be running
|
||||||
|
exiting: pid set, Process is killed by parent but not waited for";
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
leaf starttime {
|
||||||
|
description "Time of starting process UTC";
|
||||||
|
type yang:date-and-time;
|
||||||
|
}
|
||||||
|
leaf pid {
|
||||||
|
description "Process-id of main running process (if active)";
|
||||||
|
type uint32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case other {
|
||||||
|
description
|
||||||
|
"Output from start/stop/restart rpc";
|
||||||
|
leaf ok {
|
||||||
|
type empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue