Added new backend plugin callback: plugin_statedata() for getting state data; Added generic xml_merge() function.
This commit is contained in:
parent
f5d2473618
commit
4e986d6660
24 changed files with 600 additions and 88 deletions
|
|
@ -242,7 +242,6 @@ from_client_get_config(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
cprintf(cbret, "<rpc-reply><data>");
|
||||
/* if empty only <data/>, if any data then <data><config>..</config></data> */
|
||||
if (xret!=NULL){
|
||||
if (xml_child_nr(xret)){
|
||||
if (xml_name_set(xret, "config") < 0)
|
||||
|
|
@ -265,6 +264,7 @@ from_client_get_config(clicon_handle h,
|
|||
* @param[in] h Clicon handle
|
||||
* @param[in] xe Netconf request xml tree
|
||||
* @param[out] cbret Return xml value cligen buffer
|
||||
* @see from_client_get_config
|
||||
*/
|
||||
static int
|
||||
from_client_get(clicon_handle h,
|
||||
|
|
@ -279,6 +279,7 @@ from_client_get(clicon_handle h,
|
|||
if ((xfilter = xml_find(xe, "filter")) != NULL)
|
||||
if ((selector = xml_find_value(xfilter, "select"))==NULL)
|
||||
selector="/";
|
||||
/* Get config */
|
||||
if (xmldb_get(h, "running", selector, 0, &xret) < 0){
|
||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
|
|
@ -288,8 +289,12 @@ from_client_get(clicon_handle h,
|
|||
"</rpc-error></rpc-reply>");
|
||||
goto ok;
|
||||
}
|
||||
/* Get state data from plugins as defined by plugin_statedata(), if any */
|
||||
assert(xret);
|
||||
if (backend_statedata_call(h, selector, xret) < 0)
|
||||
goto done;
|
||||
cprintf(cbret, "<rpc-reply><data>");
|
||||
/* if empty only <data/>, if any data then <data><config>..</config></data> */
|
||||
/* if empty only <config/> */
|
||||
if (xret!=NULL){
|
||||
if (xml_child_nr(xret)){
|
||||
if (xml_name_set(xret, "config") < 0)
|
||||
|
|
@ -984,7 +989,7 @@ from_client_msg(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
else{
|
||||
if ((ret = backend_netconf_plugin_callbacks(h, xe, ce, cbret)) < 0)
|
||||
if ((ret = backend_rpc_cb_call(h, xe, ce, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0) /* not handled by callback */
|
||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ backend_terminate(clicon_handle h)
|
|||
if ((yspec = clicon_dbspec_yang(h)) != NULL)
|
||||
yspec_free(yspec);
|
||||
plugin_finish(h);
|
||||
/* Delete all backend plugin RPC callbacks */
|
||||
backend_rpc_cb_delete_all();
|
||||
if (pidfile)
|
||||
unlink(pidfile);
|
||||
if (sockpath)
|
||||
|
|
|
|||
|
|
@ -68,11 +68,22 @@
|
|||
* Types
|
||||
*/
|
||||
/* Following are specific to backend. For common see clicon_plugin.h
|
||||
* @note the following should match the prototypes in clicon_backend.h
|
||||
* @note the following should match the prototypes in clixon_backend.h
|
||||
*/
|
||||
#define PLUGIN_RESET "plugin_reset"
|
||||
typedef int (plgreset_t)(clicon_handle h, char *dbname); /* Reset system status */
|
||||
|
||||
/*! Plugin callback, if defined called to get state data from plugin
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||
* @param[in] xtop XML tree, <config/> on entry.
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see xmldb_get
|
||||
*/
|
||||
#define PLUGIN_STATEDATA "plugin_statedata"
|
||||
typedef int (plgstatedata_t)(clicon_handle h, char *xpath, cxobj *xtop);
|
||||
|
||||
#define PLUGIN_TRANS_BEGIN "transaction_begin"
|
||||
#define PLUGIN_TRANS_VALIDATE "transaction_validate"
|
||||
#define PLUGIN_TRANS_COMPLETE "transaction_complete"
|
||||
|
|
@ -80,6 +91,7 @@ typedef int (plgreset_t)(clicon_handle h, char *dbname); /* Reset system status
|
|||
#define PLUGIN_TRANS_END "transaction_end"
|
||||
#define PLUGIN_TRANS_ABORT "transaction_abort"
|
||||
|
||||
|
||||
typedef int (trans_cb_t)(clicon_handle h, transaction_data td); /* Transaction cbs */
|
||||
|
||||
/* Backend (config) plugins */
|
||||
|
|
@ -90,12 +102,14 @@ struct plugin {
|
|||
plgstart_t *p_start; /* Start */
|
||||
plgexit_t *p_exit; /* Exit */
|
||||
plgreset_t *p_reset; /* Reset state */
|
||||
plgstatedata_t *p_statedata; /* State-data callback */
|
||||
trans_cb_t *p_trans_begin; /* Transaction start */
|
||||
trans_cb_t *p_trans_validate; /* Transaction validation */
|
||||
trans_cb_t *p_trans_complete; /* Transaction validation complete */
|
||||
trans_cb_t *p_trans_commit; /* Transaction commit */
|
||||
trans_cb_t *p_trans_end; /* Transaction completed */
|
||||
trans_cb_t *p_trans_abort; /* Transaction aborted */
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -212,6 +226,8 @@ backend_plugin_load (clicon_handle h,
|
|||
clicon_debug(2, "%s callback registered.", PLUGIN_EXIT);
|
||||
if ((new->p_reset = dlsym(handle, PLUGIN_RESET)) != NULL)
|
||||
clicon_debug(2, "%s callback registered.", PLUGIN_RESET);
|
||||
if ((new->p_statedata = dlsym(handle, PLUGIN_STATEDATA)) != NULL)
|
||||
clicon_debug(2, "%s callback registered.", PLUGIN_STATEDATA);
|
||||
if ((new->p_trans_begin = dlsym(handle, PLUGIN_TRANS_BEGIN)) != NULL)
|
||||
clicon_debug(2, "%s callback registered.", PLUGIN_TRANS_BEGIN);
|
||||
if ((new->p_trans_validate = dlsym(handle, PLUGIN_TRANS_VALIDATE)) != NULL)
|
||||
|
|
@ -700,3 +716,82 @@ plugin_transaction_abort(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
* Backend state data callbacks
|
||||
*/
|
||||
|
||||
/*! Go through all backend statedata callbacks and collect state data
|
||||
* This is internal system call, plugin is invoked (does not call) this function
|
||||
* Backend plugins can register
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||
* @param[in,out] xml XML tree.
|
||||
* @retval -1 Error
|
||||
* @retval 0 OK
|
||||
*/
|
||||
int
|
||||
backend_statedata_call(clicon_handle h,
|
||||
char *xpath,
|
||||
cxobj *xtop)
|
||||
{
|
||||
int retval = -1;
|
||||
struct plugin *p;
|
||||
int i;
|
||||
cxobj *x = NULL;
|
||||
yang_spec *yspec;
|
||||
cxobj **xvec = NULL;
|
||||
size_t xlen;
|
||||
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_YANG, ENOENT, "No yang spec");
|
||||
goto done;
|
||||
}
|
||||
if (xtop==NULL){
|
||||
clicon_err(OE_CFG, ENOENT, "XML tree expected");
|
||||
goto done;
|
||||
}
|
||||
for (i = 0; i < nplugins; i++) {
|
||||
p = &plugins[i];
|
||||
if (p->p_statedata) {
|
||||
if ((x = xml_new("config", NULL)) == NULL)
|
||||
goto done;
|
||||
if ((p->p_statedata)(h, xpath, x) < 0)
|
||||
goto done;
|
||||
if (xml_merge(xtop, x, yspec) < 0)
|
||||
goto done;
|
||||
if (x){
|
||||
xml_free(x);
|
||||
x = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
/* Code complex to filter out anything that is outside of xpath */
|
||||
if (xpath_vec(xtop, xpath?xpath:"/", &xvec, &xlen) < 0)
|
||||
goto done;
|
||||
|
||||
/* If vectors are specified then mark the nodes found and
|
||||
* then filter out everything else,
|
||||
* otherwise return complete tree.
|
||||
*/
|
||||
if (xvec != NULL){
|
||||
for (i=0; i<xlen; i++)
|
||||
xml_flag_set(xvec[i], XML_FLAG_MARK);
|
||||
}
|
||||
/* Remove everything that is not marked */
|
||||
if (!xml_flag(xtop, XML_FLAG_MARK))
|
||||
if (xml_tree_prune_flagged_sub(xtop, XML_FLAG_MARK, 1, NULL) < 0)
|
||||
goto done;
|
||||
/* reset flag */
|
||||
if (xml_apply(xtop, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (x)
|
||||
xml_free(x);
|
||||
if (xvec)
|
||||
free(xvec);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ int plugin_finish(clicon_handle h);
|
|||
int plugin_reset_state(clicon_handle h, char *dbname);
|
||||
int plugin_start_hooks(clicon_handle h, int argc, char **argv);
|
||||
|
||||
int backend_statedata_call(clicon_handle h, char *xpath, cxobj *xml);
|
||||
|
||||
transaction_data_t * transaction_new(void);
|
||||
int transaction_free(transaction_data_t *);
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,11 @@ int plugin_exit(clicon_handle h);
|
|||
*/
|
||||
int plugin_reset(clicon_handle h, char *dbname);
|
||||
|
||||
/*! Retreive statedata, add statedata to XML tree
|
||||
* @see plgstatedata_ t
|
||||
*/
|
||||
int plugin_statedata(clicon_handle h, char *xpath, cxobj *xtop);
|
||||
|
||||
/*! Called before a commit/validate sequence begins. Eg setup state before commit
|
||||
* @see trans_cb_t
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -430,48 +430,57 @@ subscription_each(clicon_handle h,
|
|||
return hs;
|
||||
}
|
||||
|
||||
/* Database dependency description */
|
||||
struct backend_netconf_reg {
|
||||
qelem_t nr_qelem; /* List header */
|
||||
backend_netconf_cb_t nr_callback; /* Validation/Commit Callback */
|
||||
void *nr_arg; /* Application specific argument to cb */
|
||||
char *nr_tag; /* Xml tag when matched, callback called */
|
||||
};
|
||||
typedef struct backend_netconf_reg backend_netconf_reg_t;
|
||||
/*--------------------------------------------------------------------
|
||||
* Backend netconf rpc callbacks
|
||||
*/
|
||||
typedef struct {
|
||||
qelem_t rc_qelem; /* List header */
|
||||
backend_rpc_cb rc_callback; /* RPC Callback */
|
||||
void *rc_arg; /* Application specific argument to cb */
|
||||
char *rc_tag; /* Xml tag when matched, callback called */
|
||||
} backend_rpc_cb_entry;
|
||||
|
||||
static backend_netconf_reg_t *deps = NULL;
|
||||
/*! Register netconf callback
|
||||
/* List of backend rpc callback entries */
|
||||
static backend_rpc_cb_entry *rpc_cb_list = NULL;
|
||||
|
||||
/*! Register netconf backend rpc callback
|
||||
* Called from plugin to register a callback for a specific netconf XML tag.
|
||||
*
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] cb, Callback called
|
||||
* @param[in] arg, Arg to send to callback
|
||||
* @param[in] tag Xml tag when callback is made
|
||||
* @see backend_rpc_cb_call
|
||||
*/
|
||||
int
|
||||
backend_netconf_register_callback(clicon_handle h,
|
||||
backend_netconf_cb_t cb, /* Callback called */
|
||||
void *arg, /* Arg to send to callback */
|
||||
char *tag) /* Xml tag when callback is made */
|
||||
backend_rpc_cb_register(clicon_handle h,
|
||||
backend_rpc_cb cb,
|
||||
void *arg,
|
||||
char *tag)
|
||||
{
|
||||
backend_netconf_reg_t *nr;
|
||||
backend_rpc_cb_entry *rc;
|
||||
|
||||
if ((nr = malloc(sizeof(backend_netconf_reg_t))) == NULL) {
|
||||
if ((rc = malloc(sizeof(backend_rpc_cb_entry))) == NULL) {
|
||||
clicon_err(OE_DB, errno, "malloc: %s", strerror(errno));
|
||||
goto catch;
|
||||
}
|
||||
memset (nr, 0, sizeof (*nr));
|
||||
nr->nr_callback = cb;
|
||||
nr->nr_arg = arg;
|
||||
nr->nr_tag = strdup(tag); /* XXX strdup memleak */
|
||||
INSQ(nr, deps);
|
||||
memset (rc, 0, sizeof (*rc));
|
||||
rc->rc_callback = cb;
|
||||
rc->rc_arg = arg;
|
||||
rc->rc_tag = strdup(tag); /* XXX strdup memleak */
|
||||
INSQ(rc, rpc_cb_list);
|
||||
return 0;
|
||||
catch:
|
||||
if (nr){
|
||||
if (nr->nr_tag)
|
||||
free(nr->nr_tag);
|
||||
free(nr);
|
||||
if (rc){
|
||||
if (rc->rc_tag)
|
||||
free(rc->rc_tag);
|
||||
free(rc);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*! See if there is any callback registered for this tag
|
||||
*
|
||||
/*! Search netconf backend callbacks and invoke if match
|
||||
* This is internal system call, plugin is invoked (does not call) this functino
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] xe Sub-tree (under xorig) at child of rpc: <rpc><xn></rpc>.
|
||||
* @param[in] ce Client (session) entry
|
||||
|
|
@ -480,28 +489,49 @@ catch:
|
|||
* @retval -1 Error
|
||||
* @retval 0 OK, not found handler.
|
||||
* @retval 1 OK, handler called
|
||||
* @see backend_rpc_cb_register
|
||||
*/
|
||||
int
|
||||
backend_netconf_plugin_callbacks(clicon_handle h,
|
||||
cxobj *xe,
|
||||
struct client_entry *ce,
|
||||
cbuf *cbret)
|
||||
backend_rpc_cb_call(clicon_handle h,
|
||||
cxobj *xe,
|
||||
struct client_entry *ce,
|
||||
cbuf *cbret)
|
||||
{
|
||||
backend_netconf_reg_t *nreg;
|
||||
int retval;
|
||||
backend_rpc_cb_entry *rc;
|
||||
int retval = -1;
|
||||
|
||||
if (deps == NULL)
|
||||
if (rpc_cb_list == NULL)
|
||||
return 0;
|
||||
nreg = deps;
|
||||
rc = rpc_cb_list;
|
||||
do {
|
||||
if (strcmp(nreg->nr_tag, xml_name(xe)) == 0){
|
||||
if ((retval = nreg->nr_callback(h, xe, ce, cbret, nreg->nr_arg)) < 0)
|
||||
return -1;
|
||||
else
|
||||
return 1; /* handled */
|
||||
if (strcmp(rc->rc_tag, xml_name(xe)) == 0){
|
||||
if ((retval = rc->rc_callback(h, xe, ce, cbret, rc->rc_arg)) < 0)
|
||||
goto done;
|
||||
else{
|
||||
retval = 1; /* handled */
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
nreg = NEXTQ(backend_netconf_reg_t *, nreg);
|
||||
} while (nreg != deps);
|
||||
rc = NEXTQ(backend_rpc_cb_entry *, rc);
|
||||
} while (rc != rpc_cb_list);
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Delete all state data callbacks.
|
||||
*/
|
||||
int
|
||||
backend_rpc_cb_delete_all(void)
|
||||
{
|
||||
backend_rpc_cb_entry *rc;
|
||||
|
||||
while((rc = rpc_cb_list) != NULL) {
|
||||
DELQ(rc, rpc_cb_list, backend_rpc_cb_entry *);
|
||||
if (rc->rc_tag)
|
||||
free(rc->rc_tag);
|
||||
free(rc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,13 +44,15 @@
|
|||
* Types
|
||||
*/
|
||||
struct client_entry;
|
||||
typedef int (*backend_netconf_cb_t)(
|
||||
typedef int (*backend_rpc_cb)(
|
||||
clicon_handle h,
|
||||
cxobj *xe, /* Request: <rpc><xn></rpc> */
|
||||
struct client_entry *ce, /* Client session */
|
||||
cbuf *cbret, /* Reply eg <rpc-reply>... */
|
||||
void *arg /* Argument given at register */
|
||||
cxobj *xe, /* Request: <rpc><xn></rpc> */
|
||||
struct client_entry *ce, /* Client session */
|
||||
cbuf *cbret,/* Reply eg <rpc-reply>... */
|
||||
void *arg /* Argument given at register */
|
||||
);
|
||||
typedef backend_rpc_cb backend_netconf_cb_t; /* XXX backward compat */
|
||||
|
||||
|
||||
/*! Generic downcall registration.
|
||||
* Enables any function to be called from (cli) frontend
|
||||
|
|
@ -88,14 +90,16 @@ int subscription_delete(clicon_handle h, char *stream,
|
|||
subscription_fn_t fn, void *arg);
|
||||
|
||||
struct handle_subscription *subscription_each(clicon_handle h,
|
||||
struct handle_subscription *hprev);
|
||||
struct handle_subscription *hprev);
|
||||
|
||||
int backend_netconf_register_callback(clicon_handle h,
|
||||
backend_netconf_cb_t cb, /* Callback called */
|
||||
void *arg, /* Arg to send to callback */
|
||||
char *tag); /* Xml tag when callback is made */
|
||||
/* XXX backward compat */
|
||||
#define backend_netconf_register_callback(a,b,c,d) backend_rpc_cb_register(a,b,c,d)
|
||||
int backend_rpc_cb_register(clicon_handle h, backend_rpc_cb cb, void *arg,
|
||||
char *tag);
|
||||
|
||||
int backend_netconf_plugin_callbacks(clicon_handle h, cxobj *xe,
|
||||
struct client_entry *ce, cbuf *cbret);
|
||||
int backend_rpc_cb_call(clicon_handle h, cxobj *xe, struct client_entry *ce,
|
||||
cbuf *cbret);
|
||||
|
||||
int backend_rpc_cb_delete_all(void);
|
||||
|
||||
#endif /* _CLIXON_BACKEND_HANDLE_H_ */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue