Change internal protocol from clicon_proto.h to netconf.
This commit is contained in:
parent
2e09f54d12
commit
2fcefda831
66 changed files with 3012 additions and 5141 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -70,8 +70,6 @@ struct client_subscription{
|
|||
* Prototypes
|
||||
*/
|
||||
int backend_client_rm(clicon_handle h, struct client_entry *ce);
|
||||
int config_snapshot(clicon_handle h, char *dbname, char *dir);
|
||||
|
||||
int from_client(int fd, void *arg);
|
||||
|
||||
#endif /* _BACKEND_CLIENT_H_ */
|
||||
|
|
|
|||
|
|
@ -126,6 +126,10 @@ generic_validate(yang_spec *yspec,
|
|||
}
|
||||
|
||||
/*! Common code of candidate_validate and candidate_commit
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] candidate The candidate database. The wanted backend state
|
||||
* @retval 0 OK
|
||||
* @retval -1 Fatal error or netconf error XXX Differentiate
|
||||
*/
|
||||
static int
|
||||
validate_common(clicon_handle h,
|
||||
|
|
@ -137,7 +141,6 @@ validate_common(clicon_handle h,
|
|||
int i;
|
||||
cxobj *xn;
|
||||
|
||||
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
|
|
@ -253,126 +256,117 @@ candidate_commit(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Do a diff between candidate and running, then start a validate transaction
|
||||
*
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] candidate: The candidate database. The wanted backend state
|
||||
*/
|
||||
int
|
||||
candidate_validate(clicon_handle h,
|
||||
char *candidate)
|
||||
{
|
||||
int retval = -1;
|
||||
transaction_data_t *td = NULL;
|
||||
|
||||
/* 1. Start transaction */
|
||||
if ((td = transaction_new()) == NULL)
|
||||
goto done;
|
||||
|
||||
/* Common steps (with commit) */
|
||||
if (validate_common(h, candidate, td) < 0)
|
||||
goto done;
|
||||
|
||||
retval = 0;
|
||||
done:
|
||||
/* In case of failure, call plugin transaction termination callbacks */
|
||||
if (retval < 0 && td)
|
||||
plugin_transaction_abort(h, td);
|
||||
if (td)
|
||||
transaction_free(td);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Handle an incoming commit message from a client.
|
||||
* XXX: If commit succeeds and snapshot/startup fails, we have strange state:
|
||||
* the commit has succeeded but an error message is returned.
|
||||
/*! Discard all changes in candidate / revert to running
|
||||
* @param[in] h Clicon handle
|
||||
* @param[out] cbret Return xml value cligen buffer
|
||||
* @retval 0 OK. This may indicate both ok and err msg back to client
|
||||
* @retval -1 (Local) Error
|
||||
*/
|
||||
int
|
||||
from_client_commit(clicon_handle h,
|
||||
int s,
|
||||
struct clicon_msg *msg,
|
||||
const char *label)
|
||||
from_client_commit(clicon_handle h,
|
||||
cbuf *cbret)
|
||||
|
||||
{
|
||||
int retval = -1;
|
||||
char *candidate;
|
||||
char *running;
|
||||
|
||||
if (clicon_msg_commit_decode(msg,
|
||||
&candidate,
|
||||
&running,
|
||||
label) < 0)
|
||||
goto err;
|
||||
|
||||
if (strcmp(candidate, "candidate") && strcmp(candidate, "tmp")){
|
||||
clicon_err(OE_PLUGIN, 0, "candidate is not \"candidate\" or tmp");
|
||||
goto err;
|
||||
}
|
||||
if (strcmp(running, "running")){
|
||||
clicon_err(OE_PLUGIN, 0, "running db is not \"running\"");
|
||||
goto err;
|
||||
}
|
||||
if (candidate_commit(h, "candidate") < 0){
|
||||
clicon_debug(1, "Commit %s failed", candidate);
|
||||
retval = 0; /* We ignore errors from commit, but maybe
|
||||
we should fail on fatal errors? */
|
||||
goto err;
|
||||
clicon_debug(1, "Commit candidate failed");
|
||||
/* XXX: candidate_validate should have proper error handling */
|
||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>missing-attribute</error-tag>"
|
||||
"<error-type>protocol</error-type>"
|
||||
"<error-severity>error</error-severity>"
|
||||
"<error-message>%s</error-message>"
|
||||
"</rpc-error></rpc-reply>",
|
||||
clicon_err_reason);
|
||||
goto ok;
|
||||
}
|
||||
clicon_debug(1, "Commit %s", candidate);
|
||||
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
||||
ok:
|
||||
retval = 0;
|
||||
if (send_msg_ok(s) < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
err:
|
||||
/* XXX: more elaborate errstring? */
|
||||
if (send_msg_err(s, clicon_errno, clicon_suberrno, "%s", clicon_err_reason) < 0)
|
||||
retval = -1;
|
||||
done:
|
||||
unchunk_group(__FUNCTION__);
|
||||
|
||||
// done:
|
||||
return retval; /* may be zero if we ignoring errors from commit */
|
||||
} /* from_client_commit */
|
||||
|
||||
/*! Discard all changes in candidate / revert to running
|
||||
* @param[in] h Clicon handle
|
||||
* @param[out] cbret Return xml value cligen buffer
|
||||
* @retval 0 OK. This may indicate both ok and err msg back to client
|
||||
* @retval -1 (Local) Error
|
||||
*/
|
||||
int
|
||||
from_client_discard_changes(clicon_handle h,
|
||||
cbuf *cbret)
|
||||
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
if (xmldb_copy(h, "running", "candidate") < 0){
|
||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
"<error-type>application</error-type>"
|
||||
"<error-severity>error</error-severity>"
|
||||
"<error-info>read-registry</error-info>"
|
||||
"</rpc-error></rpc-reply>");
|
||||
goto ok;
|
||||
}
|
||||
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
||||
ok:
|
||||
retval = 0;
|
||||
// done:
|
||||
return retval; /* may be zero if we ignoring errors from commit */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*! Handle an incoming validate message from a client.
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] db Database name
|
||||
* @param[out] cbret Return xml value cligen buffer
|
||||
* @retval 0 OK. This may indicate both ok and err msg back to client (eg invalid)
|
||||
* @retval -1 (Local) Error
|
||||
*/
|
||||
int
|
||||
from_client_validate(clicon_handle h,
|
||||
int s,
|
||||
struct clicon_msg *msg,
|
||||
const char *label)
|
||||
from_client_validate(clicon_handle h,
|
||||
char *db,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
char *candidate;
|
||||
int retval = -1;
|
||||
transaction_data_t *td = NULL;
|
||||
|
||||
if (clicon_msg_validate_decode(msg,
|
||||
&candidate,
|
||||
label) < 0){
|
||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
||||
clicon_err_reason);
|
||||
goto err;
|
||||
if (strcmp(db, "candidate") != 0 && strcmp(db, "tmp") != 0){
|
||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>invalid-value</error-tag>"
|
||||
"<error-type>protocol</error-type>"
|
||||
"<error-severity>error</error-severity>"
|
||||
"</rpc-error></rpc-reply>");
|
||||
goto ok;
|
||||
}
|
||||
if (strcmp(candidate, "candidate") != 0 && strcmp(candidate, "tmp") != 0){
|
||||
clicon_err(OE_PLUGIN, 0, "candidate is not \"candidate\" or tmp");
|
||||
goto err;
|
||||
}
|
||||
clicon_debug(1, "Validate %s", candidate);
|
||||
if (candidate_validate(h, candidate) < 0){
|
||||
clicon_debug(1, "Validate %s failed", candidate);
|
||||
retval = 0; /* We ignore errors from commit, but maybe
|
||||
we should fail on fatal errors? */
|
||||
goto err;
|
||||
}
|
||||
retval = 0;
|
||||
if (send_msg_ok(s) < 0)
|
||||
clicon_debug(1, "Validate %s", db);
|
||||
|
||||
/* 1. Start transaction */
|
||||
if ((td = transaction_new()) == NULL)
|
||||
goto done;
|
||||
goto done;
|
||||
err:
|
||||
/* XXX: more elaborate errstring? */
|
||||
if (send_msg_err(s, clicon_errno, clicon_suberrno, "%s", clicon_err_reason) < 0)
|
||||
retval = -1;
|
||||
done:
|
||||
unchunk_group(__FUNCTION__);
|
||||
/* Common steps (with commit) */
|
||||
if (validate_common(h, db, td) < 0){
|
||||
clicon_debug(1, "Validate %s failed", db);
|
||||
/* XXX: candidate_validate should have proper error handling */
|
||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>missing-attribute</error-tag>"
|
||||
"<error-type>protocol</error-type>"
|
||||
"<error-severity>error</error-severity>"
|
||||
"<error-message>%s</error-message>"
|
||||
"</rpc-error></rpc-reply>",
|
||||
clicon_err_reason);
|
||||
goto ok;
|
||||
}
|
||||
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (retval < 0 && td)
|
||||
plugin_transaction_abort(h, td);
|
||||
if (td)
|
||||
transaction_free(td);
|
||||
return retval;
|
||||
} /* from_client_validate */
|
||||
|
|
|
|||
|
|
@ -40,8 +40,9 @@
|
|||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int from_client_validate(clicon_handle h, int s, struct clicon_msg *msg, const char *label);
|
||||
int from_client_commit(clicon_handle h, int s, struct clicon_msg *msg, const char *label);
|
||||
int candidate_commit(clicon_handle h, char *candidate);
|
||||
int from_client_validate(clicon_handle h, char *db, cbuf *cbret);
|
||||
int from_client_commit(clicon_handle h, cbuf *cbret);
|
||||
int from_client_discard_changes(clicon_handle h, cbuf *cbret);
|
||||
int candidate_commit(clicon_handle h, char *db);
|
||||
|
||||
#endif /* _BACKEND_COMMIT_H_ */
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@
|
|||
#ifndef _BACKEND_HANDLE_H_
|
||||
#define _BACKEND_HANDLE_H_
|
||||
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
* not exported.
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@
|
|||
#include "backend_handle.h"
|
||||
|
||||
/* Command line options to be passed to getopt(3) */
|
||||
#define BACKEND_OPTS "hD:f:d:Fzu:P:1IRCc:rg:ptx:"
|
||||
#define BACKEND_OPTS "hD:f:d:Fzu:P:1IRCc:rg:pt"
|
||||
|
||||
/*! Terminate. Cannot use h after this */
|
||||
static int
|
||||
|
|
@ -141,8 +141,7 @@ usage(char *argv0, clicon_handle h)
|
|||
" -r\t\tReload running database\n"
|
||||
" -p \t\tPrint database yang specification\n"
|
||||
" -t \t\tPrint alternate spec translation (eg if YANG print KEY, if KEY print YANG)\n"
|
||||
" -g <group>\tClient membership required to this group (default: %s)\n"
|
||||
" -x <status>\tSet CLICON_XMLDB_RPC to 0 or 1.\n",
|
||||
" -g <group>\tClient membership required to this group (default: %s)\n",
|
||||
argv0,
|
||||
plgdir ? plgdir : "none",
|
||||
confsock ? confsock : "none",
|
||||
|
|
@ -153,11 +152,12 @@ usage(char *argv0, clicon_handle h)
|
|||
}
|
||||
|
||||
static int
|
||||
rundb_init(clicon_handle h)
|
||||
db_reset(clicon_handle h,
|
||||
char *db)
|
||||
{
|
||||
if (xmldb_delete(h, "running") != 0 && errno != ENOENT)
|
||||
if (xmldb_delete(h, db) != 0 && errno != ENOENT)
|
||||
return -1;
|
||||
if (xmldb_init(h, "running") < 0)
|
||||
if (xmldb_init(h, db) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -192,7 +192,7 @@ rundb_main(clicon_handle h,
|
|||
if (clicon_xml_parse_file(fd, &xt, "</clicon>") < 0)
|
||||
goto done;
|
||||
if ((xn = xml_child_i(xt, 0)) != NULL)
|
||||
if (xmldb_put(h, "tmp", xn, OP_MERGE) < 0)
|
||||
if (xmldb_put(h, "tmp", OP_MERGE, NULL, xn) < 0)
|
||||
goto done;
|
||||
if (candidate_commit(h, "tmp") < 0)
|
||||
goto done;
|
||||
|
|
@ -426,14 +426,6 @@ main(int argc, char **argv)
|
|||
case 't' : /* Print alternative dbspec format (eg if YANG, print KEY) */
|
||||
printalt++;
|
||||
break;
|
||||
case 'x' : /* set xmldb rpc on */
|
||||
{
|
||||
int i;
|
||||
if (sscanf(optarg, "%d", &i) != 1)
|
||||
usage(argv[0], h);
|
||||
clicon_option_int_set(h, "CLICON_XMLDB_RPC", i);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
usage(argv[0], h);
|
||||
break;
|
||||
|
|
@ -503,7 +495,7 @@ main(int argc, char **argv)
|
|||
if (yang_spec_main(h, stdout, printspec) < 0)
|
||||
goto done;
|
||||
|
||||
/* First check for starup config
|
||||
/* First check for startup config
|
||||
XXX the options below have become out-of-hand.
|
||||
Too complex, need to simplify*/
|
||||
if (clicon_option_int(h, "CLICON_USE_STARTUP_CONFIG") > 0){
|
||||
|
|
@ -513,8 +505,12 @@ main(int argc, char **argv)
|
|||
goto done;
|
||||
}
|
||||
else
|
||||
if (rundb_init(h) < 0)
|
||||
if (db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
if (xmldb_init(h, "candidate") < 0)
|
||||
goto done;
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
}
|
||||
/* If running exists and reload_running set, make a copy to candidate */
|
||||
if (reload_running){
|
||||
|
|
@ -529,9 +525,17 @@ main(int argc, char **argv)
|
|||
/* Init running db
|
||||
* -I or if it isnt there
|
||||
*/
|
||||
if (init_rundb || xmldb_exists(h, "running") != 1)
|
||||
if (rundb_init(h) < 0)
|
||||
if (init_rundb || xmldb_exists(h, "running") != 1){
|
||||
if (db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
}
|
||||
/* If candidate does not exist, create it from running */
|
||||
if (xmldb_exists(h, "candidate") != 1){
|
||||
if (xmldb_init(h, "candidate") < 0)
|
||||
goto done;
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Initialize plugins
|
||||
(also calls plugin_init() and plugin_start(argc,argv) in each plugin */
|
||||
|
|
|
|||
|
|
@ -470,55 +470,6 @@ plugin_finish(clicon_handle h)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Call from frontend to function 'func' in plugin 'plugin'.
|
||||
* Plugin function is supposed to populate 'retlen' and 'retarg' where
|
||||
* 'retarg' is malloc:ed data if non-NULL.
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] req Clicon message containing information about the downcall
|
||||
* @param[out] retlen Length of return value
|
||||
* @param[out] ret Return value
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
plugin_downcall(clicon_handle h,
|
||||
struct clicon_msg_call_req *req,
|
||||
uint16_t *retlen,
|
||||
void **retarg)
|
||||
{
|
||||
int retval = -1;
|
||||
int i;
|
||||
downcall_cb funcp;
|
||||
char name[PATH_MAX];
|
||||
char *error;
|
||||
struct plugin *p;
|
||||
|
||||
for (i = 0; i < nplugins; i++) {
|
||||
p = &plugins[i];
|
||||
strncpy(name, p->p_name, sizeof(name)-1);
|
||||
if (!strcmp(name+strlen(name)-3, ".so"))
|
||||
name[strlen(name)-3] = '\0';
|
||||
/* If no plugin is given or the plugin-name matches */
|
||||
if (req->cr_plugin == NULL || strlen(req->cr_plugin)==0 ||
|
||||
strcmp(name, req->cr_plugin) == 0) {
|
||||
funcp = dlsym(p->p_handle, req->cr_func);
|
||||
if ((error = (char*)dlerror()) != NULL) {
|
||||
clicon_err(OE_PROTO, ENOENT,
|
||||
"Function does not exist: %s()", req->cr_func);
|
||||
return -1;
|
||||
}
|
||||
retval = funcp(h, req->cr_op, req->cr_arglen, req->cr_arg, retlen, retarg);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
clicon_err(OE_PROTO, ENOENT,"%s: %s(): Plugin does not exist: %s",
|
||||
__FUNCTION__, req->cr_func, req->cr_plugin);
|
||||
return -1;
|
||||
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Create and initialize transaction */
|
||||
transaction_data_t *
|
||||
transaction_new(void)
|
||||
|
|
@ -771,4 +722,3 @@ plugin_transaction_abort(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@
|
|||
* Types
|
||||
*/
|
||||
|
||||
|
||||
/*! Transaction data
|
||||
* Clicon internal, presented as void* to app's callback in the 'transaction_data'
|
||||
* type in clicon_backend_api.h
|
||||
|
|
@ -69,8 +68,6 @@ 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 plugin_downcall(clicon_handle h, struct clicon_msg_call_req *req,
|
||||
uint16_t *retlen, void **retarg);
|
||||
|
||||
transaction_data_t * transaction_new(void);
|
||||
int transaction_free(transaction_data_t *);
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ config_accept_client(int fd, void *arg)
|
|||
/*
|
||||
* Here we register callbacks for actual data socket
|
||||
*/
|
||||
if (event_reg_fd(s, from_client, (void*)ce, "client socket") < 0)
|
||||
if (event_reg_fd(s, from_client, (void*)ce, "local netconf client socket") < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ backend_notify(clicon_handle h,
|
|||
struct handle_subscription *hs;
|
||||
int retval = -1;
|
||||
|
||||
clicon_debug(1, "%s %s", __FUNCTION__, stream);
|
||||
/* First thru all clients(sessions), and all subscriptions and find matches */
|
||||
for (ce = backend_client_list(h); ce; ce = ce_next){
|
||||
ce_next = ce->ce_next;
|
||||
|
|
@ -257,7 +258,8 @@ backend_notify_xml(clicon_handle h,
|
|||
}
|
||||
|
||||
struct client_entry *
|
||||
backend_client_add(clicon_handle h, struct sockaddr *addr)
|
||||
backend_client_add(clicon_handle h,
|
||||
struct sockaddr *addr)
|
||||
{
|
||||
struct backend_handle *cb = handle(h);
|
||||
struct client_entry *ce;
|
||||
|
|
@ -411,3 +413,79 @@ subscription_each(clicon_handle h,
|
|||
hs = cb->cb_subscription;
|
||||
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;
|
||||
|
||||
static backend_netconf_reg_t *deps = NULL;
|
||||
/*! Register netconf callback
|
||||
* Called from plugin to register a callback for a specific netconf XML tag.
|
||||
*/
|
||||
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_netconf_reg_t *nr;
|
||||
|
||||
if ((nr = malloc(sizeof(backend_netconf_reg_t))) == 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); /* strdup */
|
||||
INSQ(nr, deps);
|
||||
return 0;
|
||||
catch:
|
||||
if (nr){
|
||||
if (nr->nr_tag)
|
||||
free(nr->nr_tag);
|
||||
free(nr);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*! See if there is any callback registered for this tag
|
||||
*
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] xn Sub-tree (under xorig) at child of rpc: <rpc><xn></rpc>.
|
||||
* @param[out] cb Output xml stream. For reply
|
||||
* @param[out] cb_err Error xml stream. For error reply
|
||||
* @param[out] xret Return XML, error or OK
|
||||
*
|
||||
* @retval -1 Error
|
||||
* @retval 0 OK, not found handler.
|
||||
* @retval 1 OK, handler called
|
||||
*/
|
||||
int
|
||||
backend_netconf_plugin_callbacks(clicon_handle h,
|
||||
cxobj *xe,
|
||||
struct client_entry *ce,
|
||||
cbuf *cbret)
|
||||
{
|
||||
backend_netconf_reg_t *nreg;
|
||||
int retval;
|
||||
|
||||
if (deps == NULL)
|
||||
return 0;
|
||||
nreg = deps;
|
||||
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 */
|
||||
}
|
||||
nreg = NEXTQ(backend_netconf_reg_t *, nreg);
|
||||
} while (nreg != deps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,14 @@
|
|||
/*
|
||||
* Types
|
||||
*/
|
||||
struct client_entry;
|
||||
typedef int (*backend_netconf_cb_t)(
|
||||
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 */
|
||||
);
|
||||
|
||||
/*! Generic downcall registration.
|
||||
* Enables any function to be called from (cli) frontend
|
||||
|
|
@ -81,4 +89,13 @@ int subscription_delete(clicon_handle h, char *stream,
|
|||
|
||||
struct handle_subscription *subscription_each(clicon_handle h,
|
||||
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 */
|
||||
|
||||
int backend_netconf_plugin_callbacks(clicon_handle h, cxobj *xe,
|
||||
struct client_entry *ce, cbuf *cbret);
|
||||
|
||||
#endif /* _CLIXON_BACKEND_HANDLE_H_ */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue