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:
Olof hagsand 2017-07-20 10:54:31 +02:00
parent f995f1e268
commit e56cf607a3
17 changed files with 177 additions and 112 deletions

View file

@ -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

View file

@ -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
View 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";
}

View file

@ -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

View file

@ -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;

View file

@ -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;
}

View file

@ -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");