Added cache for modules-state RFC7895 to avoid building new XML every get call
This commit is contained in:
parent
a20865846e
commit
3c332b689f
8 changed files with 193 additions and 76 deletions
|
|
@ -250,6 +250,7 @@
|
||||||
example backend_main() and others if you need details.
|
example backend_main() and others if you need details.
|
||||||
|
|
||||||
### Minor changes
|
### Minor changes
|
||||||
|
* Added cache for modules-state RFC7895 to avoid building new XML every get call
|
||||||
* Renamed test/test_auth*.sh tests to test/test_nacm*.sh
|
* Renamed test/test_auth*.sh tests to test/test_nacm*.sh
|
||||||
* YANG keywords "action" and "belongs-to" implemented by syntactically by parser (but not proper semantics).
|
* YANG keywords "action" and "belongs-to" implemented by syntactically by parser (but not proper semantics).
|
||||||
* clixon-config YAML file has new revision: 2018-10-21.
|
* clixon-config YAML file has new revision: 2018-10-21.
|
||||||
|
|
|
||||||
|
|
@ -335,7 +335,7 @@ client_statedata(clicon_handle h,
|
||||||
if ((retval = client_get_streams(h, yspec, xpath, "ietf-restconf-monitoring", "restconf-state", xret)) != 0)
|
if ((retval = client_get_streams(h, yspec, xpath, "ietf-restconf-monitoring", "restconf-state", xret)) != 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895"))
|
if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895"))
|
||||||
if ((retval = yang_modules_state_get(h, yspec, xret)) != 0)
|
if ((retval = yang_modules_state_get(h, yspec, xpath, xret)) != 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((retval = clixon_plugin_statedata(h, yspec, xpath, xret)) != 0)
|
if ((retval = clixon_plugin_statedata(h, yspec, xpath, xret)) != 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,7 @@ backend_terminate(clicon_handle h)
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if ((ss = clicon_socket_get(h)) != -1)
|
if ((ss = clicon_socket_get(h)) != -1)
|
||||||
close(ss);
|
close(ss);
|
||||||
|
modules_state_cache_set(h, NULL);
|
||||||
if ((yspec = clicon_dbspec_yang(h)) != NULL)
|
if ((yspec = clicon_dbspec_yang(h)) != NULL)
|
||||||
yspec_free(yspec);
|
yspec_free(yspec);
|
||||||
if ((yspec = clicon_config_yang(h)) != NULL)
|
if ((yspec = clicon_config_yang(h)) != NULL)
|
||||||
|
|
|
||||||
|
|
@ -573,7 +573,7 @@ text_get(xmldb_handle xh,
|
||||||
/* Add default values (if not set) */
|
/* Add default values (if not set) */
|
||||||
if (xml_apply(xt, CX_ELMNT, xml_default, NULL) < 0)
|
if (xml_apply(xt, CX_ELMNT, xml_default, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
#if 1 /* debug */
|
#if 0 /* debug */
|
||||||
if (xml_apply0(xt, -1, xml_sort_verify, NULL) < 0)
|
if (xml_apply0(xt, -1, xml_sort_verify, NULL) < 0)
|
||||||
clicon_log(LOG_NOTICE, "%s: sort verify failed #2", __FUNCTION__);
|
clicon_log(LOG_NOTICE, "%s: sort verify failed #2", __FUNCTION__);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -202,4 +202,8 @@ int clicon_username_set(clicon_handle h, void *username);
|
||||||
int clicon_socket_get(clicon_handle h);
|
int clicon_socket_get(clicon_handle h);
|
||||||
int clicon_socket_set(clicon_handle h, int s);
|
int clicon_socket_set(clicon_handle h, int s);
|
||||||
|
|
||||||
|
/*! Set and set module state cache */
|
||||||
|
cxobj *clicon_module_state_get(clicon_handle h);
|
||||||
|
int clicon_module_state_set(clicon_handle h, cxobj *xms);
|
||||||
|
|
||||||
#endif /* _CLIXON_OPTIONS_H_ */
|
#endif /* _CLIXON_OPTIONS_H_ */
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,10 @@
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
|
int modules_state_cache_set(clicon_handle h, cxobj *msx);
|
||||||
int yang_modules_init(clicon_handle h);
|
int yang_modules_init(clicon_handle h);
|
||||||
char *yang_modules_revision(clicon_handle h);
|
char *yang_modules_revision(clicon_handle h);
|
||||||
int yang_modules_state_get(clicon_handle h, yang_spec *yspec, cxobj **xret);
|
int yang_modules_state_get(clicon_handle h, yang_spec *yspec, char *xpath,
|
||||||
|
cxobj **xret);
|
||||||
|
|
||||||
#endif /* _CLIXON_YANG_MODULE_H_ */
|
#endif /* _CLIXON_YANG_MODULE_H_ */
|
||||||
|
|
|
||||||
|
|
@ -922,3 +922,36 @@ clicon_socket_set(clicon_handle h,
|
||||||
return hash_del(cdat, "socket");
|
return hash_del(cdat, "socket");
|
||||||
return hash_add(cdat, "socket", &s, sizeof(int))==NULL?-1:0;
|
return hash_add(cdat, "socket", &s, sizeof(int))==NULL?-1:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Get module state cache
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @retval xms Module state cache XML tree
|
||||||
|
*/
|
||||||
|
cxobj *
|
||||||
|
clicon_module_state_get(clicon_handle h)
|
||||||
|
{
|
||||||
|
clicon_hash_t *cdat = clicon_data(h);
|
||||||
|
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if ((p = hash_value(cdat, "module_state_cache", NULL)) != NULL)
|
||||||
|
return *(cxobj **)p;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set module state cache
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] s Open socket (or -1 to close)
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clicon_module_state_set(clicon_handle h,
|
||||||
|
cxobj *xms)
|
||||||
|
{
|
||||||
|
clicon_hash_t *cdat = clicon_data(h);
|
||||||
|
|
||||||
|
if (hash_add(cdat, "module_state_cache", &xms, sizeof(xms))==NULL)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,8 @@
|
||||||
#include "clixon_file.h"
|
#include "clixon_file.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xpath_ctx.h"
|
||||||
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
#include "clixon_netconf_lib.h"
|
#include "clixon_netconf_lib.h"
|
||||||
#include "clixon_yang_module.h"
|
#include "clixon_yang_module.h"
|
||||||
|
|
@ -129,9 +131,64 @@ yang_modules_revision(clicon_handle h)
|
||||||
return revision;
|
return revision;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Get modules state cache associated with module_set_id, or NULL if none
|
||||||
|
* @param[in] h Clixon handle
|
||||||
|
* @param[in] msid Module set id. Cache stored per id
|
||||||
|
* @param[out] xms XML tree for module state cache. Note need to xml_dup it.
|
||||||
|
* @retval 0 OK, x is either NULL or set
|
||||||
|
* @retval -1 Error
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
modules_state_cache_get(clicon_handle h,
|
||||||
|
char *msid,
|
||||||
|
cxobj **xms)
|
||||||
|
{
|
||||||
|
cxobj *x; /* module state cache XML */
|
||||||
|
cxobj *xmsid; /* module state id of cache XML */
|
||||||
|
|
||||||
|
if ((x = clicon_module_state_get(h)) == NULL)
|
||||||
|
return 0;
|
||||||
|
if ((xmsid = xpath_first(x, "modules-state/module-set-id")) == NULL)
|
||||||
|
return 0;
|
||||||
|
if (strcmp(xml_body(xmsid), msid) == 0) /* return cache */
|
||||||
|
*xms = x;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set modules state cache associated with msid, or NULL if none
|
||||||
|
* @param[in] h Clixon handle
|
||||||
|
* @param[in] msid Module set id. Cache stored per id
|
||||||
|
* @param[out] xms XML tree for module state cache. Note need to xml_dup it.
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
modules_state_cache_set(clicon_handle h,
|
||||||
|
cxobj *msx)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *x; /* module state cache XML */
|
||||||
|
|
||||||
|
if ((x = clicon_module_state_get(h)) != NULL)
|
||||||
|
xml_free(x);
|
||||||
|
clicon_module_state_set(h, NULL);
|
||||||
|
if (msx == NULL)
|
||||||
|
goto ok;
|
||||||
|
/* Duplicate XML tree from original. */
|
||||||
|
if ((x = xml_dup(msx)) == NULL)
|
||||||
|
goto done;
|
||||||
|
clicon_module_state_set(h, x);
|
||||||
|
ok:
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Get modules state according to RFC 7895
|
/*! Get modules state according to RFC 7895
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] yspec Yang spec
|
* @param[in] yspec Yang spec
|
||||||
|
* @param[in] xpath XML Xpath
|
||||||
* @param[in,out] xret Existing XML tree, merge x into this
|
* @param[in,out] xret Existing XML tree, merge x into this
|
||||||
* @retval -1 Error (fatal)
|
* @retval -1 Error (fatal)
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
|
|
@ -158,6 +215,7 @@ x +--ro namespace inet:uri
|
||||||
int
|
int
|
||||||
yang_modules_state_get(clicon_handle h,
|
yang_modules_state_get(clicon_handle h,
|
||||||
yang_spec *yspec,
|
yang_spec *yspec,
|
||||||
|
char *xpath,
|
||||||
cxobj **xret)
|
cxobj **xret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -168,85 +226,103 @@ yang_modules_state_get(clicon_handle h,
|
||||||
yang_stmt *ymod; /* generic module */
|
yang_stmt *ymod; /* generic module */
|
||||||
yang_stmt *ys;
|
yang_stmt *ys;
|
||||||
yang_stmt *yc;
|
yang_stmt *yc;
|
||||||
char *module_set_id;
|
char *msid; /* modules-set-id */
|
||||||
char *module = "ietf-yang-library";
|
char *module = "ietf-yang-library";
|
||||||
|
cxobj *x1;
|
||||||
|
|
||||||
module_set_id = clicon_option_str(h, "CLICON_MODULE_SET_ID");
|
msid = clicon_option_str(h, "CLICON_MODULE_SET_ID");
|
||||||
if ((ylib = yang_find((yang_node*)yspec, Y_MODULE, module)) == NULL &&
|
if (modules_state_cache_get(h, msid, &x) < 0)
|
||||||
(ylib = yang_find((yang_node*)yspec, Y_SUBMODULE, module)) == NULL){
|
|
||||||
clicon_err(OE_YANG, 0, "%s not found", module);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
if (x != NULL){ /* Yes a cache (but no duplicate) */
|
||||||
if ((yns = yang_find((yang_node*)ylib, Y_NAMESPACE, NULL)) == NULL){
|
if (xpath_first(x, "%s", xpath)){
|
||||||
clicon_err(OE_YANG, 0, "%s yang namespace not found", module);
|
if ((x1 = xml_dup(x)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
x = x1;
|
||||||
if ((cb = cbuf_new()) == NULL){
|
|
||||||
clicon_err(OE_UNIX, 0, "clicon buffer");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
cprintf(cb,"<modules-state xmlns=\"%s\">", yns->ys_argument);
|
|
||||||
cprintf(cb,"<module-set-id>%s</module-set-id>", module_set_id);
|
|
||||||
|
|
||||||
ymod = NULL;
|
|
||||||
while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) {
|
|
||||||
if (ymod->ys_keyword != Y_MODULE &&
|
|
||||||
ymod->ys_keyword != Y_SUBMODULE)
|
|
||||||
continue;
|
|
||||||
cprintf(cb,"<module>");
|
|
||||||
cprintf(cb,"<name>%s</name>", ymod->ys_argument);
|
|
||||||
if ((ys = yang_find((yang_node*)ymod, Y_REVISION, NULL)) != NULL)
|
|
||||||
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
|
|
||||||
else
|
|
||||||
cprintf(cb,"<revision></revision>");
|
|
||||||
if ((ys = yang_find((yang_node*)ymod, Y_NAMESPACE, NULL)) != NULL)
|
|
||||||
cprintf(cb,"<namespace>%s</namespace>", ys->ys_argument);
|
|
||||||
else
|
|
||||||
cprintf(cb,"<namespace></namespace>");
|
|
||||||
/* This follows order in rfc 7895: feature, conformance-type, submodules */
|
|
||||||
yc = NULL;
|
|
||||||
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
|
|
||||||
switch(yc->ys_keyword){
|
|
||||||
case Y_FEATURE:
|
|
||||||
if (yc->ys_cv && cv_bool_get(yc->ys_cv))
|
|
||||||
cprintf(cb,"<feature>%s</feature>", yc->ys_argument);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
cprintf(cb, "<conformance-type>implement</conformance-type>");
|
else
|
||||||
yc = NULL;
|
x = NULL;
|
||||||
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
|
|
||||||
switch(yc->ys_keyword){
|
|
||||||
case Y_SUBMODULE:
|
|
||||||
cprintf(cb,"<submodule>");
|
|
||||||
cprintf(cb,"<name>%s</name>", yc->ys_argument);
|
|
||||||
if ((ys = yang_find((yang_node*)yc, Y_REVISION, NULL)) != NULL)
|
|
||||||
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
|
|
||||||
else
|
|
||||||
cprintf(cb,"<revision></revision>");
|
|
||||||
cprintf(cb,"</submodule>");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cprintf(cb,"</module>");
|
|
||||||
}
|
}
|
||||||
cprintf(cb,"</modules-state>");
|
else { /* No cache -> build the tree */
|
||||||
|
if ((ylib = yang_find((yang_node*)yspec, Y_MODULE, module)) == NULL &&
|
||||||
if (xml_parse_string(cbuf_get(cb), yspec, &x) < 0){
|
(ylib = yang_find((yang_node*)yspec, Y_SUBMODULE, module)) == NULL){
|
||||||
if (netconf_operation_failed_xml(xret, "protocol", clicon_err_reason)< 0)
|
clicon_err(OE_YANG, 0, "%s not found", module);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((yns = yang_find((yang_node*)ylib, Y_NAMESPACE, NULL)) == NULL){
|
||||||
|
clicon_err(OE_YANG, 0, "%s yang namespace not found", module);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((cb = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_UNIX, 0, "clicon buffer");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cprintf(cb,"<modules-state xmlns=\"%s\">", yns->ys_argument);
|
||||||
|
cprintf(cb,"<module-set-id>%s</module-set-id>", msid);
|
||||||
|
|
||||||
|
ymod = NULL;
|
||||||
|
while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) {
|
||||||
|
if (ymod->ys_keyword != Y_MODULE &&
|
||||||
|
ymod->ys_keyword != Y_SUBMODULE)
|
||||||
|
continue;
|
||||||
|
cprintf(cb,"<module>");
|
||||||
|
cprintf(cb,"<name>%s</name>", ymod->ys_argument);
|
||||||
|
if ((ys = yang_find((yang_node*)ymod, Y_REVISION, NULL)) != NULL)
|
||||||
|
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
|
||||||
|
else
|
||||||
|
cprintf(cb,"<revision></revision>");
|
||||||
|
if ((ys = yang_find((yang_node*)ymod, Y_NAMESPACE, NULL)) != NULL)
|
||||||
|
cprintf(cb,"<namespace>%s</namespace>", ys->ys_argument);
|
||||||
|
else
|
||||||
|
cprintf(cb,"<namespace></namespace>");
|
||||||
|
/* This follows order in rfc 7895: feature, conformance-type, submodules */
|
||||||
|
yc = NULL;
|
||||||
|
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
|
||||||
|
switch(yc->ys_keyword){
|
||||||
|
case Y_FEATURE:
|
||||||
|
if (yc->ys_cv && cv_bool_get(yc->ys_cv))
|
||||||
|
cprintf(cb,"<feature>%s</feature>", yc->ys_argument);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cprintf(cb, "<conformance-type>implement</conformance-type>");
|
||||||
|
yc = NULL;
|
||||||
|
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
|
||||||
|
switch(yc->ys_keyword){
|
||||||
|
case Y_SUBMODULE:
|
||||||
|
cprintf(cb,"<submodule>");
|
||||||
|
cprintf(cb,"<name>%s</name>", yc->ys_argument);
|
||||||
|
if ((ys = yang_find((yang_node*)yc, Y_REVISION, NULL)) != NULL)
|
||||||
|
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
|
||||||
|
else
|
||||||
|
cprintf(cb,"<revision></revision>");
|
||||||
|
cprintf(cb,"</submodule>");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cprintf(cb,"</module>");
|
||||||
|
}
|
||||||
|
cprintf(cb,"</modules-state>");
|
||||||
|
|
||||||
|
if (xml_parse_string(cbuf_get(cb), yspec, &x) < 0){
|
||||||
|
if (netconf_operation_failed_xml(xret, "protocol", clicon_err_reason)< 0)
|
||||||
|
goto done;
|
||||||
|
retval = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (modules_state_cache_set(h, x) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 1;
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
retval = netconf_trymerge(x, yspec, xret);
|
if (x && netconf_trymerge(x, yspec, xret) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (cb)
|
|
||||||
cbuf_free(cb);
|
|
||||||
if (x)
|
if (x)
|
||||||
xml_free(x);
|
xml_free(x);
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue