Added YANG RPC support, with example rpc documentation and testcase (test7.sh); Extended example with ietf-routing (not only ietf-ip).
This commit is contained in:
parent
f995f1e268
commit
e56cf607a3
17 changed files with 177 additions and 112 deletions
|
|
@ -67,6 +67,7 @@ YANGSPECS += ietf-routing@2014-10-26.yang
|
|||
YANGSPECS += ietf-ipv4-unicast-routing@2014-10-26.yang
|
||||
YANGSPECS += ietf-ipv6-unicast-routing@2014-10-26.yang
|
||||
YANGSPECS += ietf-ipsec@2016-03-09.yang
|
||||
YANGSPECS += example.yang
|
||||
|
||||
# Backend plugin
|
||||
BE_SRC = routing_backend.c
|
||||
|
|
|
|||
|
|
@ -65,22 +65,45 @@ Routing notification
|
|||
...
|
||||
```
|
||||
|
||||
## Extending
|
||||
## Operation data
|
||||
|
||||
Clixon has an extension mechanism which can be used to make extended internal
|
||||
netconf messages to the backend configuration engine. You may need this to
|
||||
make some special operation that is not covered by standard
|
||||
netconf functions. The example has a simple "echo" downcall
|
||||
mechanism that simply echoes what is sent down and is included for
|
||||
reference. A more realistic downcall would perform some action, such as
|
||||
reading some status.
|
||||
Clixon implements Yang RPC operations by an extension mechanism. The
|
||||
extension mechanism enables you to add application-specific
|
||||
operations. It works by adding user-defined callbacks for added
|
||||
netconf operations. It is possible to use the extension mechanism
|
||||
independent of the yang rpc construct, but it is recommended to use
|
||||
that, and the example includes such an example:
|
||||
|
||||
Example:
|
||||
```
|
||||
cli> downcall "This is a string"
|
||||
This is a string
|
||||
cli> rpc ipv4
|
||||
<rpc-reply>
|
||||
<ok/>
|
||||
</rpc-reply>
|
||||
```
|
||||
|
||||
The example works by creating a netconf rpc call and sending it to the backend: (see the fib_route_rpc() function).
|
||||
```
|
||||
<rpc>
|
||||
<fib-route>
|
||||
<routing-instance-name>ipv4</routing-instance-name>
|
||||
</fib-route>
|
||||
</rpc>
|
||||
```
|
||||
|
||||
The backend in turn registers a callback (fib_route()) which handles the RPC.
|
||||
```
|
||||
static int
|
||||
fib_route(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 */
|
||||
{
|
||||
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
## State data
|
||||
|
||||
Netconf <get> and restconf GET also returns state data, in contrast to
|
||||
|
|
|
|||
10
example/example.yang
Normal file
10
example/example.yang
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
module example {
|
||||
import ietf-ip {
|
||||
prefix ip;
|
||||
}
|
||||
import ietf-routing {
|
||||
prefix rt;
|
||||
}
|
||||
description
|
||||
"Example code that includes ietf-ip and ietf-routing";
|
||||
}
|
||||
|
|
@ -5,11 +5,12 @@ CLICON_CLI_MODE routing
|
|||
|
||||
# Option used to construct initial yang file:
|
||||
# <module>[@<revision>]
|
||||
CLICON_YANG_MODULE_MAIN ietf-ip
|
||||
#CLICON_YANG_MODULE_MAIN ietf-ip
|
||||
CLICON_YANG_MODULE_MAIN example
|
||||
|
||||
# Option used to construct initial yang file:
|
||||
# <module>[@<revision>]
|
||||
CLICON_YANG_MODULE_REVISION 2014-06-16
|
||||
#CLICON_YANG_MODULE_REVISION 2014-06-16
|
||||
|
||||
# Generate code for CLI completion of existing db symbols
|
||||
# CLICON_CLI_GENMODEL_COMPLETION 0
|
||||
|
|
|
|||
|
|
@ -119,14 +119,27 @@ notification_timer_setup(clicon_handle h)
|
|||
return event_reg_timeout(t, notification_timer, h, "notification timer");
|
||||
}
|
||||
|
||||
/*! IETF Routing fib-route rpc */
|
||||
static int
|
||||
routing_downcall(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 */
|
||||
fib_route(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 */
|
||||
{
|
||||
cprintf(cbret, "<rpc-reply><ok>%s</ok></rpc-reply>", xml_body(xe));
|
||||
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! IETF Routing route-count rpc */
|
||||
static int
|
||||
route_count(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 */
|
||||
{
|
||||
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -173,10 +186,15 @@ plugin_init(clicon_handle h)
|
|||
|
||||
if (notification_timer_setup(h) < 0)
|
||||
goto done;
|
||||
/* Register callback for netconf application-specific rpc call */
|
||||
if (backend_rpc_cb_register(h, routing_downcall,
|
||||
/* Register callback for routing rpc calls */
|
||||
if (backend_rpc_cb_register(h, fib_route,
|
||||
NULL,
|
||||
"myrouting"/* Xml tag when callback is made */
|
||||
"fib-route"/* Xml tag when callback is made */
|
||||
) < 0)
|
||||
goto done;
|
||||
if (backend_rpc_cb_register(h, route_count,
|
||||
NULL,
|
||||
"route-count"/* Xml tag when callback is made */
|
||||
) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
|
|
|
|||
|
|
@ -92,40 +92,36 @@ mycallback(clicon_handle h, cvec *cvv, cvec *argv)
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! get argument and send as string to backend as RPC (which returns the string)
|
||||
*/
|
||||
/*! Example "downcall": ietf-routing fib-route RPC */
|
||||
int
|
||||
downcall(clicon_handle h,
|
||||
cvec *vars,
|
||||
cvec *argv)
|
||||
fib_route_rpc(clicon_handle h,
|
||||
cvec *cvv,
|
||||
cvec *argv)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg = NULL;
|
||||
char *str="";
|
||||
cg_var *cv;
|
||||
cxobj *xret=NULL;
|
||||
cxobj *xerr;
|
||||
cxobj *xdata;
|
||||
int retval = -1;
|
||||
cg_var *instance;
|
||||
cxobj *xtop = NULL;
|
||||
cxobj *xrpc;
|
||||
cxobj *xret = NULL;
|
||||
|
||||
if (cvec_len(vars)==2){
|
||||
if ((cv = cvec_i(vars, 1)) != NULL)
|
||||
str = cv_string_get(cv);
|
||||
}
|
||||
if ((msg = clicon_msg_encode("<rpc><myrouting>%s</myrouting></rpc>", str)) == NULL)
|
||||
/* User supplied variable in CLI command */
|
||||
instance = cvec_find(cvv, "instance"); /* get a cligen variable from vector */
|
||||
/* Create XML for fib-route netconf RPC */
|
||||
if (clicon_xml_parse(&xtop, "<rpc><fib-route><routing-instance-name>%s</routing-instance-name></fib-route></rpc>", instance) < 0)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
/* Skip top-level */
|
||||
xrpc = xml_child_i(xtop, 0);
|
||||
/* Send to backend */
|
||||
if (clicon_rpc_netconf_xml(h, xrpc, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error(xerr);
|
||||
goto done;
|
||||
}
|
||||
if ((xdata = xpath_first(xret, "//ok")) != NULL)
|
||||
cli_output(stdout, "%s\n", xml_body(xdata));
|
||||
retval = 0;
|
||||
done:
|
||||
/* Print result */
|
||||
xml_print(stdout, xml_child_i(xret, 0));
|
||||
retval = 0;
|
||||
done:
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (msg)
|
||||
free(msg);
|
||||
xml_free(xret);
|
||||
if (xtop)
|
||||
xml_free(xtop);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ CLICON_PROMPT="%U@%H> ";
|
|||
CLICON_PLUGIN="routing_cli";
|
||||
|
||||
# Note, when switching to PT, change datamodel to only @datamodel
|
||||
set @datamodel:ietf-ip, cli_set();
|
||||
merge @datamodel:ietf-ip, cli_merge();
|
||||
create @datamodel:ietf-ip, cli_create();
|
||||
delete("Delete a configuration item") @datamodel:ietf-ip, cli_del();
|
||||
set @datamodel:example, cli_set();
|
||||
merge @datamodel:example, cli_merge();
|
||||
create @datamodel:example, cli_create();
|
||||
delete("Delete a configuration item") @datamodel:example, cli_del();
|
||||
|
||||
validate("Validate changes"), cli_validate();
|
||||
commit("Commit the changes"), cli_commit();
|
||||
|
|
@ -49,7 +49,7 @@ load("Load configuration from XML file") <filename:string>("Filename (local file
|
|||
merge("Merge file with existent candidate"), load_config_file("filename", "merge");
|
||||
}
|
||||
example("This is a comment") <var:int32>("Just a random number"), mycallback("myarg");
|
||||
downcall("This is a downcall") <str:rest>, downcall();
|
||||
rpc("fib-route rpc") <instance:string>("routing instance"), fib_route_rpc("myarg");
|
||||
notify("Get notifications from backend"), cli_notify("ROUTING", "1", "text");
|
||||
no("Negate") notify("Get notifications from backend"), cli_notify("ROUTING", "0", "xml");
|
||||
lock,cli_lock("candidate");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue