Merge branch 'develop' into nacm

This commit is contained in:
Olof hagsand 2019-01-21 16:45:24 +01:00
commit d55787d8ec
92 changed files with 2929 additions and 9681 deletions

2
.gitignore vendored
View file

@ -12,6 +12,8 @@ etc/Makefile
example/Makefile example/Makefile
lib/Makefile lib/Makefile
lib/*/Makefile lib/*/Makefile
yang/Makefile
yang/*/Makefile
autom4te.cache/ autom4te.cache/
config.log config.log

View file

@ -81,10 +81,15 @@
* Recovery user "_nacm_recovery" added. * Recovery user "_nacm_recovery" added.
* Example use is restconf PUT when NACM edit-config is permitted, then automatic commit and discard are permitted using recovery user. * Example use is restconf PUT when NACM edit-config is permitted, then automatic commit and discard are permitted using recovery user.
* Example user changed adm1 to andy to comply with RFC8341 example * Example user changed adm1 to andy to comply with RFC8341 example
* Added -o "<option>=<value>" command-line option to all programs: backend, cli, netconf, restconf.
* Any config option from file can be overrided by giving them on command-line.
### API changes on existing features (you may need to change your code) ### API changes on existing features (you may need to change your code)
* Rearranged yang files
* Moved and updated all standard ietf and iana yang files from example and yang/ to `yang/standard`.
* Moved clixon yang files from yang to `yang/clixon`
* New configure option to disable standard yang files: `./configure --disable-stdyangs`
* This is to make it easier to use standard IETF/IANA yang files in separate directory
* Renamed example yang from example.yang -> clixon-example.yang
* clixon_cli -p (printspec) changed semantics to add new yang path dir (see minor changes).
* Date-and-time type now properly uses ISO 8601 UTC timezone designators. * Date-and-time type now properly uses ISO 8601 UTC timezone designators.
* Eg 2008-09-21T18:57:21.003456 is changed to 2008-09-21T18:57:21.003456Z * Eg 2008-09-21T18:57:21.003456 is changed to 2008-09-21T18:57:21.003456Z
* Renamed yang file `ietf-netconf-notification@2008-07-01.yang` to `clixon-rfc5277`. * Renamed yang file `ietf-netconf-notification@2008-07-01.yang` to `clixon-rfc5277`.
@ -107,6 +112,10 @@
* For backward compatibility, define CLICON_CLI_MODEL_TREENAME_PATCH in clixon_custom.h * For backward compatibility, define CLICON_CLI_MODEL_TREENAME_PATCH in clixon_custom.h
### Minor changes ### Minor changes
* Added -o "<option>=<value>" command-line option to all programs: backend, cli, netconf, restconf.
* Any config option from file can be overrided by giving them on command-line.
* Added -p <dir> command-line option to all programs: backend, cli, netconf, restconf.
* -p adds a new dir to the yang path dir. (same as -o CLICON_YAN_DIR=<dir>)
* Cligen uses posix regex while yang uses XSD. It differs in some aspects. A translator function has been added for `\d` -> `[0-9]` translation, there may be more. * Cligen uses posix regex while yang uses XSD. It differs in some aspects. A translator function has been added for `\d` -> `[0-9]` translation, there may be more.
* Added new clixon-lib yang module for internal netconf protocol. Currently only extends the standard with a debug RPC. * Added new clixon-lib yang module for internal netconf protocol. Currently only extends the standard with a debug RPC.
* Added three-valued return values for several validate functions where -1 is fatal error, 0 is validation failed and 1 is validation OK. * Added three-valued return values for several validate functions where -1 is fatal error, 0 is validation failed and 1 is validation OK.
@ -125,6 +134,12 @@
* <!DOCTYPE (ie DTD) is not supported. * <!DOCTYPE (ie DTD) is not supported.
### Corrected Bugs ### Corrected Bugs
* XML<>JSON conversion problems [https://github.com/clicon/clixon/issues/66]
* CDATA sections stripped from XML when converted to JSON
* Restconf returns error when RPC generates "ok" reply [https://github.com/clicon/clixon/issues/69]
* xsd regular expression support for character classes [https://github.com/clicon/clixon/issues/68]
* added support for \c, \d, \w, \W, \s, \S.
* Removing newlines from XML data [https://github.com/clicon/clixon/issues/65]
* [ietf-netconf-notification@2008-07-01.yang validation problem #62](https://github.com/clicon/clixon/issues/62) * [ietf-netconf-notification@2008-07-01.yang validation problem #62](https://github.com/clicon/clixon/issues/62)
* Ignore CR(\r) in yang files for DOS files * Ignore CR(\r) in yang files for DOS files
* Keyword "min" (not only "max") can be used in built-in types "range" and "length" statements. * Keyword "min" (not only "max") can be used in built-in types "range" and "length" statements.

View file

@ -5,7 +5,7 @@ NETCONF and RESTCONF interfaces, an embedded database and transaction
support. support.
* [Background](#background) * [Background](#background)
* [Frequently asked questions](doc/FAQ.md) * [Frequently asked questions (FAQ)](doc/FAQ.md)
* [Installation](#installation) * [Installation](#installation)
* [Licenses](#licenses) * [Licenses](#licenses)
* [Support](#support) * [Support](#support)

View file

@ -44,6 +44,7 @@ SHELL = /bin/sh
SUBDIRS = backend SUBDIRS = backend
SUBDIRS += cli SUBDIRS += cli
SUBDIRS += netconf SUBDIRS += netconf
# See configure.ac
ifeq ($(with_restconf),yes) ifeq ($(with_restconf),yes)
SUBDIRS += restconf SUBDIRS += restconf
endif endif

View file

@ -73,7 +73,7 @@
#include "backend_handle.h" #include "backend_handle.h"
/* Command line options to be passed to getopt(3) */ /* Command line options to be passed to getopt(3) */
#define BACKEND_OPTS "hD:f:l:d:b:Fza:u:P:1s:c:g:y:x:o:" #define BACKEND_OPTS "hD:f:l:d:p:b:Fza:u:P:1s:c:g:y:x:o:"
#define BACKEND_LOGFILE "/usr/local/var/clixon_backend.log" #define BACKEND_LOGFILE "/usr/local/var/clixon_backend.log"
@ -142,6 +142,7 @@ usage(clicon_handle h,
"\t-f <file>\tCLICON config file\n" "\t-f <file>\tCLICON config file\n"
"\t-l (s|e|o|f<file>) Log on (s)yslog, std(e)rr or std(o)ut (stderr is default) Only valid if -F, if background syslog is on syslog.\n" "\t-l (s|e|o|f<file>) Log on (s)yslog, std(e)rr or std(o)ut (stderr is default) Only valid if -F, if background syslog is on syslog.\n"
"\t-d <dir>\tSpecify backend plugin directory (default: %s)\n" "\t-d <dir>\tSpecify backend plugin directory (default: %s)\n"
"\t-p <dir>\tYang directory path (see CLICON_YANG_DIR)\n"
"\t-b <dir>\tSpecify XMLDB database directory\n" "\t-b <dir>\tSpecify XMLDB database directory\n"
"\t-F\t\tRun in foreground, do not run as daemon\n" "\t-F\t\tRun in foreground, do not run as daemon\n"
"\t-z\t\tKill other config daemon and exit\n" "\t-z\t\tKill other config daemon and exit\n"
@ -654,12 +655,18 @@ main(int argc,
case 'd': /* Plugin directory */ case 'd': /* Plugin directory */
if (!strlen(optarg)) if (!strlen(optarg))
usage(h, argv[0]); usage(h, argv[0]);
clicon_option_str_set(h, "CLICON_BACKEND_DIR", optarg); if (clicon_option_add(h, "CLICON_BACKEND_DIR", optarg) < 0)
goto done;
break; break;
case 'b': /* XMLDB database directory */ case 'b': /* XMLDB database directory */
if (!strlen(optarg)) if (!strlen(optarg))
usage(h, argv[0]); usage(h, argv[0]);
clicon_option_str_set(h, "CLICON_XMLDB_DIR", optarg); if (clicon_option_add(h, "CLICON_XMLDB_DIR", optarg) < 0)
goto done;
break;
case 'p' : /* yang dir path */
if (clicon_option_add(h, "CLICON_YANG_DIR", optarg) < 0)
goto done;
break; break;
case 'F' : /* foreground */ case 'F' : /* foreground */
foreground = 1; foreground = 1;
@ -668,21 +675,25 @@ main(int argc,
zap++; zap++;
break; break;
case 'a': /* internal backend socket address family */ case 'a': /* internal backend socket address family */
clicon_option_str_set(h, "CLICON_SOCK_FAMILY", optarg); if (clicon_option_add(h, "CLICON_SOCK_FAMILY", optarg) < 0)
goto done;
break; break;
case 'u': /* config unix domain path / ip address */ case 'u': /* config unix domain path / ip address */
if (!strlen(optarg)) if (!strlen(optarg))
usage(h, argv[0]); usage(h, argv[0]);
clicon_option_str_set(h, "CLICON_SOCK", optarg); if (clicon_option_add(h, "CLICON_SOCK", optarg) < 0)
goto done;
break; break;
case 'P': /* pidfile */ case 'P': /* pidfile */
clicon_option_str_set(h, "CLICON_BACKEND_PIDFILE", optarg); if (clicon_option_add(h, "CLICON_BACKEND_PIDFILE", optarg) < 0)
goto done;
break; break;
case '1' : /* Quit after reading database once - dont wait for events */ case '1' : /* Quit after reading database once - dont wait for events */
once = 1; once = 1;
break; break;
case 's' : /* startup mode */ case 's' : /* startup mode */
clicon_option_str_set(h, "CLICON_STARTUP_MODE", optarg); if (clicon_option_add(h, "CLICON_STARTUP_MODE", optarg) < 0)
goto done;
if (clicon_startup_mode(h) < 0){ if (clicon_startup_mode(h) < 0){
fprintf(stderr, "Invalid startup mode: %s\n", optarg); fprintf(stderr, "Invalid startup mode: %s\n", optarg);
usage(h, argv[0]); usage(h, argv[0]);
@ -692,16 +703,17 @@ main(int argc,
extraxml_file = optarg; extraxml_file = optarg;
break; break;
case 'g': /* config socket group */ case 'g': /* config socket group */
clicon_option_str_set(h, "CLICON_SOCK_GROUP", optarg); if (clicon_option_add(h, "CLICON_SOCK_GROUP", optarg) < 0)
goto done;
break; break;
case 'y' :{ /* Load yang absolute filename */ case 'y' : /* Load yang absolute filename */
clicon_option_str_set(h, "CLICON_YANG_MAIN_FILE", optarg); if (clicon_option_add(h, "CLICON_YANG_MAIN_FILE", optarg) < 0)
goto done;
break; break;
} case 'x' : /* xmldb plugin */
case 'x' :{ /* xmldb plugin */ if (clicon_option_add(h, "CLICON_XMLDB_PLUGIN", optarg) < 0)
clicon_option_str_set(h, "CLICON_XMLDB_PLUGIN", optarg); goto done;
break; break;
}
case 'o':{ /* Configuration option */ case 'o':{ /* Configuration option */
char *val; char *val;
if ((val = index(optarg, '=')) == NULL) if ((val = index(optarg, '=')) == NULL)

View file

@ -71,7 +71,7 @@
#include "cli_handle.h" #include "cli_handle.h"
/* Command line options to be passed to getopt(3) */ /* Command line options to be passed to getopt(3) */
#define CLI_OPTS "hD:f:xl:F:1a:u:d:m:qpGLy:c:U:o:" #define CLI_OPTS "hD:f:xl:F:1a:u:d:m:qp:GLy:c:U:o:"
#define CLI_LOGFILE "/tmp/clixon_cli.log" #define CLI_LOGFILE "/tmp/clixon_cli.log"
@ -221,7 +221,7 @@ usage(clicon_handle h,
"\t-d <dir>\tSpecify plugin directory (default: %s)\n" "\t-d <dir>\tSpecify plugin directory (default: %s)\n"
"\t-m <mode>\tSpecify plugin syntax mode\n" "\t-m <mode>\tSpecify plugin syntax mode\n"
"\t-q \t\tQuiet mode, dont print greetings or prompt, terminate on ctrl-C\n" "\t-q \t\tQuiet mode, dont print greetings or prompt, terminate on ctrl-C\n"
"\t-p \t\tPrint database yang specification\n" "\t-p <dir>\tYang directory path (see CLICON_YANG_DIR)\n"
"\t-G \t\tPrint CLI syntax generated from dbspec (if CLICON_CLI_GENMODEL enabled)\n" "\t-G \t\tPrint CLI syntax generated from dbspec (if CLICON_CLI_GENMODEL enabled)\n"
"\t-L \t\tDebug print dynamic CLI syntax including completions and expansions\n" "\t-L \t\tDebug print dynamic CLI syntax including completions and expansions\n"
"\t-l <s|e|o|f<file>> \tLog on (s)yslog, std(e)rr, std(o)ut or (f)ile (stderr is default)\n" "\t-l <s|e|o|f<file>> \tLog on (s)yslog, std(e)rr, std(o)ut or (f)ile (stderr is default)\n"
@ -246,7 +246,6 @@ main(int argc, char **argv)
char *tmp; char *tmp;
char *argv0 = argv[0]; char *argv0 = argv[0];
clicon_handle h; clicon_handle h;
int printspec = 0;
int printgen = 0; int printgen = 0;
int logclisyntax = 0; int logclisyntax = 0;
int help = 0; int help = 0;
@ -361,28 +360,33 @@ main(int argc, char **argv)
once = 1; once = 1;
break; break;
case 'a': /* internal backend socket address family */ case 'a': /* internal backend socket address family */
clicon_option_str_set(h, "CLICON_SOCK_FAMILY", optarg); if (clicon_option_add(h, "CLICON_SOCK_FAMILY", optarg) < 0)
goto done;
break; break;
case 'u': /* internal backend socket unix domain path or ip host */ case 'u': /* internal backend socket unix domain path or ip host */
if (!strlen(optarg)) if (!strlen(optarg))
usage(h, argv[0]); usage(h, argv[0]);
clicon_option_str_set(h, "CLICON_SOCK", optarg); if (clicon_option_add(h, "CLICON_SOCK", optarg) < 0)
goto done;
break; break;
case 'd': /* Plugin directory: overrides configfile */ case 'd': /* Plugin directory: overrides configfile */
if (!strlen(optarg)) if (!strlen(optarg))
usage(h, argv[0]); usage(h, argv[0]);
clicon_option_str_set(h, "CLICON_CLI_DIR", optarg); if (clicon_option_add(h, "CLICON_CLI_DIR", optarg) < 0)
goto done;
break; break;
case 'm': /* CLI syntax mode */ case 'm': /* CLI syntax mode */
if (!strlen(optarg)) if (!strlen(optarg))
usage(h, argv[0]); usage(h, argv[0]);
clicon_option_str_set(h, "CLICON_CLI_MODE", optarg); if (clicon_option_add(h, "CLICON_CLI_MODE", optarg) < 0)
goto done;
break; break;
case 'q' : /* Quiet mode */ case 'q' : /* Quiet mode */
clicon_quiet_mode_set(h, 1); clicon_quiet_mode_set(h, 1);
break; break;
case 'p' : /* Print spec */ case 'p' : /* yang dir path */
printspec++; if (clicon_option_add(h, "CLICON_YANG_DIR", optarg) < 0)
goto done;
break; break;
case 'G' : /* Print generated CLI syntax */ case 'G' : /* Print generated CLI syntax */
printgen++; printgen++;
@ -390,14 +394,14 @@ main(int argc, char **argv)
case 'L' : /* Debug print dynamic CLI syntax */ case 'L' : /* Debug print dynamic CLI syntax */
logclisyntax++; logclisyntax++;
break; break;
case 'y' :{ /* Load yang absolute filename */ case 'y' : /* Load yang absolute filename */
clicon_option_str_set(h, "CLICON_YANG_MAIN_FILE", optarg); if (clicon_option_add(h, "CLICON_YANG_MAIN_FILE", optarg) < 0)
goto done;
break; break;
} case 'c' : /* Overwrite clispec with absolute filename */
case 'c' :{ /* Overwrite clispec with absolute filename */ if (clicon_option_add(h, "CLICON_CLISPEC_FILE", optarg) < 0)
clicon_option_str_set(h, "CLICON_CLISPEC_FILE", optarg); goto done;
break; break;
}
case 'U': /* Clixon 'pseudo' user */ case 'U': /* Clixon 'pseudo' user */
if (!strlen(optarg)) if (!strlen(optarg))
usage(h, argv[0]); usage(h, argv[0]);
@ -463,8 +467,6 @@ main(int argc, char **argv)
/* Load yang module library, RFC7895 */ /* Load yang module library, RFC7895 */
if (yang_modules_init(h) < 0) if (yang_modules_init(h) < 0)
goto done; goto done;
if (printspec)
yang_print(stdout, (yang_node*)yspec);
/* Create tree generated from dataspec. If no other trees exists, this is /* Create tree generated from dataspec. If no other trees exists, this is
* the only one. * the only one.

View file

@ -71,7 +71,7 @@
#include "netconf_rpc.h" #include "netconf_rpc.h"
/* Command line options to be passed to getopt(3) */ /* Command line options to be passed to getopt(3) */
#define NETCONF_OPTS "hD:f:l:qa:u:d:y:U:t:o:" #define NETCONF_OPTS "hD:f:l:qa:u:d:p:y:U:t:o:"
#define NETCONF_LOGFILE "/tmp/clixon_netconf.log" #define NETCONF_LOGFILE "/tmp/clixon_netconf.log"
@ -324,13 +324,13 @@ usage(clicon_handle h,
"where options are\n" "where options are\n"
"\t-h\t\tHelp\n" "\t-h\t\tHelp\n"
"\t-D <level>\tDebug level\n" "\t-D <level>\tDebug level\n"
"\t-q\t\tQuiet: dont send hello prompt\n"
"\t-f <file>\tConfiguration file (mandatory)\n" "\t-f <file>\tConfiguration file (mandatory)\n"
"\t-l (e|o|s|f<file>) \tLog on std(e)rr, std(o)ut, (s)yslog, (f)ile (syslog is default)\n" "\t-l (e|o|s|f<file>) \tLog on std(e)rr, std(o)ut, (s)yslog, (f)ile (syslog is default)\n"
"\t-q\t\tQuiet: dont send hello prompt\n"
"\t-a UNIX|IPv4|IPv6\tInternal backend socket family\n" "\t-a UNIX|IPv4|IPv6\tInternal backend socket family\n"
"\t-u <path|addr>\tInternal socket domain path or IP addr (see -a)\n" "\t-u <path|addr>\tInternal socket domain path or IP addr (see -a)\n"
"\t-d <dir>\tSpecify netconf plugin directory dir (default: %s)\n" "\t-d <dir>\tSpecify netconf plugin directory dir (default: %s)\n"
"\t-p <dir>\tYang directory path (see CLICON_YANG_DIR)\n"
"\t-y <file>\tLoad yang spec file (override yang main module)\n" "\t-y <file>\tLoad yang spec file (override yang main module)\n"
"\t-U <user>\tOver-ride unix user with a pseudo user for NACM.\n" "\t-U <user>\tOver-ride unix user with a pseudo user for NACM.\n"
"\t-t <sec>\tTimeout in seconds. Quit after this time.\n" "\t-t <sec>\tTimeout in seconds. Quit after this time.\n"
@ -418,6 +418,9 @@ main(int argc,
case 'f': /* config file */ case 'f': /* config file */
case 'l': /* log */ case 'l': /* log */
break; /* see above */ break; /* see above */
case 'q': /* quiet: dont write hello */
quiet++;
break;
case 'a': /* internal backend socket address family */ case 'a': /* internal backend socket address family */
clicon_option_str_set(h, "CLICON_SOCK_FAMILY", optarg); clicon_option_str_set(h, "CLICON_SOCK_FAMILY", optarg);
break; break;
@ -426,18 +429,20 @@ main(int argc,
usage(h, argv[0]); usage(h, argv[0]);
clicon_option_str_set(h, "CLICON_SOCK", optarg); clicon_option_str_set(h, "CLICON_SOCK", optarg);
break; break;
case 'q': /* quiet: dont write hello */
quiet++;
break;
case 'd': /* Plugin directory */ case 'd': /* Plugin directory */
if (!strlen(optarg)) if (!strlen(optarg))
usage(h, argv[0]); usage(h, argv[0]);
clicon_option_str_set(h, "CLICON_NETCONF_DIR", optarg); if (clicon_option_add(h, "CLICON_NETCONF_DIR", optarg) < 0)
goto done;
break; break;
case 'y' :{ /* Load yang spec file (override yang main module) */ case 'p' : /* yang dir path */
clicon_option_str_set(h, "CLICON_YANG_MAIN_FILE", optarg); if (clicon_option_add(h, "CLICON_YANG_DIR", optarg) < 0)
goto done;
break;
case 'y' : /* Load yang spec file (override yang main module) */
if (clicon_option_add(h, "CLICON_YANG_MAIN_FILE", optarg) < 0)
goto done;
break; break;
}
case 'U': /* Clixon 'pseudo' user */ case 'U': /* Clixon 'pseudo' user */
if (!strlen(optarg)) if (!strlen(optarg))
usage(h, argv[0]); usage(h, argv[0]);

View file

@ -614,12 +614,18 @@ netconf_application_rpc(clicon_handle h,
else /* Send to backend */ else /* Send to backend */
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0) if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
goto done; goto done;
/* Sanity check of outgoing XML */ /* Sanity check of outgoing XML
* For now, skip outgoing checks.
* (1) Does not handle <ok/> properly
* (2) Uncertain how validation errors should be logged/handled
*/
if (0)
if ((youtput = yang_find((yang_node*)yrpc, Y_OUTPUT, NULL)) != NULL){ if ((youtput = yang_find((yang_node*)yrpc, Y_OUTPUT, NULL)) != NULL){
xoutput=xpath_first(*xret, "/"); xoutput=xpath_first(*xret, "/");
xml_spec_set(xoutput, youtput); /* needed for xml_spec_populate */ xml_spec_set(xoutput, youtput); /* needed for xml_spec_populate */
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0) if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done; goto done;
if ((ret = xml_yang_validate_all_top(xoutput, cbret)) < 0) if ((ret = xml_yang_validate_all_top(xoutput, cbret)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){

View file

@ -81,7 +81,7 @@
#include "restconf_stream.h" #include "restconf_stream.h"
/* Command line options to be passed to getopt(3) */ /* Command line options to be passed to getopt(3) */
#define RESTCONF_OPTS "hD:f:l:p:y:a:u:o:" #define RESTCONF_OPTS "hD:f:l:p:d:y:a:u:o:"
/* RESTCONF enables deployments to specify where the RESTCONF API is /* RESTCONF enables deployments to specify where the RESTCONF API is
located. The client discovers this by getting the "/.well-known/host-meta" located. The client discovers this by getting the "/.well-known/host-meta"
@ -492,6 +492,7 @@ usage(clicon_handle h,
"\t-D <level>\tDebug level\n" "\t-D <level>\tDebug level\n"
"\t-f <file>\tConfiguration file (mandatory)\n" "\t-f <file>\tConfiguration file (mandatory)\n"
"\t-l <s|f<file>> \tLog on (s)yslog, (f)ile (syslog is default)\n" "\t-l <s|f<file>> \tLog on (s)yslog, (f)ile (syslog is default)\n"
"\t-p <dir>\tYang directory path (see CLICON_YANG_DIR)\n"
"\t-d <dir>\tSpecify restconf plugin directory dir (default: %s)\n" "\t-d <dir>\tSpecify restconf plugin directory dir (default: %s)\n"
"\t-y <file>\tLoad yang spec file (override yang main module)\n" "\t-y <file>\tLoad yang spec file (override yang main module)\n"
"\t-a UNIX|IPv4|IPv6\tInternal backend socket family\n" "\t-a UNIX|IPv4|IPv6\tInternal backend socket family\n"
@ -596,6 +597,10 @@ main(int argc,
case 'f': /* config file */ case 'f': /* config file */
case 'l': /* log */ case 'l': /* log */
break; /* see above */ break; /* see above */
case 'p' : /* yang dir path */
if (clicon_option_add(h, "CLICON_YANG_DIR", optarg) < 0)
goto done;
break;
case 'd': /* Plugin directory */ case 'd': /* Plugin directory */
if (!strlen(optarg)) if (!strlen(optarg))
usage(h, argv[0]); usage(h, argv[0]);

View file

@ -270,8 +270,17 @@ api_data_get2(clicon_handle h,
} }
} }
else{ else{
if (xpath_vec(xret, "%s", &xvec, &xlen, path) < 0) if (xpath_vec(xret, "%s", &xvec, &xlen, path) < 0){
if (netconf_operation_failed_xml(&xerr, "application", clicon_err_reason) < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
goto done;
goto ok;
}
if (use_xml){ if (use_xml){
for (i=0; i<xlen; i++){ for (i=0; i<xlen; i++){
char *prefix, *namespace; char *prefix, *namespace;
@ -1260,9 +1269,8 @@ api_operations_post_input(clicon_handle h,
xml_name_set(xdata, "data"); xml_name_set(xdata, "data");
/* Here xdata is: /* Here xdata is:
* <data><input xmlns="urn:example:clixon">...</input></data> * <data><input xmlns="urn:example:clixon">...</input></data>
* Validate that exactly only <input> tag
*/ */
#if 0 #if 1
if (debug){ if (debug){
cbuf *ccc=cbuf_new(); cbuf *ccc=cbuf_new();
if (clicon_xml2cbuf(ccc, xdata, 0, 0) < 0) if (clicon_xml2cbuf(ccc, xdata, 0, 0) < 0)
@ -1270,6 +1278,7 @@ api_operations_post_input(clicon_handle h,
clicon_debug(1, "%s DATA:%s", __FUNCTION__, cbuf_get(ccc)); clicon_debug(1, "%s DATA:%s", __FUNCTION__, cbuf_get(ccc));
} }
#endif #endif
/* Validate that exactly only <input> tag */
if ((xinput = xml_child_i_type(xdata, 0, CX_ELMNT)) == NULL || if ((xinput = xml_child_i_type(xdata, 0, CX_ELMNT)) == NULL ||
strcmp(xml_name(xinput),"input") != 0 || strcmp(xml_name(xinput),"input") != 0 ||
xml_child_nr_type(xdata, CX_ELMNT) != 1){ xml_child_nr_type(xdata, CX_ELMNT) != 1){
@ -1347,8 +1356,9 @@ api_operations_post_output(clicon_handle h,
cxobj *x; cxobj *x;
cxobj *xok; cxobj *xok;
cbuf *cbret = NULL; cbuf *cbret = NULL;
int ret; int isempty;
// clicon_debug(1, "%s", __FUNCTION__);
if ((cbret = cbuf_new()) == NULL){ if ((cbret = cbuf_new()) == NULL){
clicon_err(OE_UNIX, 0, "cbuf_new"); clicon_err(OE_UNIX, 0, "cbuf_new");
goto done; goto done;
@ -1371,7 +1381,7 @@ api_operations_post_output(clicon_handle h,
/* 9. Translate to restconf RPC data */ /* 9. Translate to restconf RPC data */
xml_name_set(xoutput, "output"); xml_name_set(xoutput, "output");
/* xoutput should now look: <output><x xmlns="uri">0</x></output> */ /* xoutput should now look: <output><x xmlns="uri">0</x></output> */
#if 0 #if 1
if (debug){ if (debug){
cbuf *ccc=cbuf_new(); cbuf *ccc=cbuf_new();
if (clicon_xml2cbuf(ccc, xoutput, 0, 0) < 0) if (clicon_xml2cbuf(ccc, xoutput, 0, 0) < 0)
@ -1379,45 +1389,15 @@ api_operations_post_output(clicon_handle h,
clicon_debug(1, "%s XOUTPUT:%s", __FUNCTION__, cbuf_get(ccc)); clicon_debug(1, "%s XOUTPUT:%s", __FUNCTION__, cbuf_get(ccc));
} }
#endif #endif
/* Validate output (in case handlers are wrong) */
if (youtput==NULL){ /* Sanity check of outgoing XML
/* Special case, no yang output * For now, skip outgoing checks.
* RFC 7950 7.14.4 * (1) Does not handle <ok/> properly
* If the RPC operation invocation succeeded and no output parameters * (2) Uncertain how validation errors should be logged/handled
* are returned, the <rpc-reply> contains a single <ok/> element
* RFC 8040 3.6.2
* If the "rpc" statement has no "output" section, the response message
* MUST NOT include a message-body and MUST send a "204 No Content"
* status-line instead.
*/ */
if ((xok = xml_child_i_type(xoutput, 0, CX_ELMNT)) == NULL || if (youtput!=NULL){
strcmp(xml_name(xok),"ok") != 0 ||
xml_child_nr_type(xoutput, CX_ELMNT) != 1){
/* Internal error - invalid output from rpc handler */
if (xok){
if (netconf_operation_failed_xml(&xerr, "application",
"Internal error: Empty RPC reply is not ok") < 0)
goto done;
}
else
if (netconf_operation_failed_xml(&xerr, "application",
"Internal error: Empty RPC reply should have OK") < 0)
goto done;
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
goto done;
goto fail;
}
FCGX_SetExitStatus(204, r->out); /* OK */
FCGX_FPrintF(r->out, "Status: 204 No Content\r\n");
FCGX_FPrintF(r->out, "\r\n");
goto fail;
}
else{
xml_spec_set(xoutput, youtput); /* needed for xml_spec_populate */ xml_spec_set(xoutput, youtput); /* needed for xml_spec_populate */
#if 0
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0) if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done; goto done;
if ((ret = xml_yang_validate_all(xoutput, cbret)) < 0) if ((ret = xml_yang_validate_all(xoutput, cbret)) < 0)
@ -1436,7 +1416,28 @@ api_operations_post_output(clicon_handle h,
goto done; goto done;
goto fail; goto fail;
} }
#endif
}
/* Special case, no yang output (single <ok/> - or empty body?)
* RFC 7950 7.14.4
* If the RPC operation invocation succeeded and no output parameters
* are returned, the <rpc-reply> contains a single <ok/> element
* RFC 8040 3.6.2
* If the "rpc" statement has no "output" section, the response message
* MUST NOT include a message-body and MUST send a "204 No Content"
* status-line instead.
*/
isempty = xml_child_nr_type(xoutput, CX_ELMNT) == 0 ||
(xml_child_nr_type(xoutput, CX_ELMNT) == 1 &&
(xok = xml_child_i_type(xoutput, 0, CX_ELMNT)) != NULL &&
strcmp(xml_name(xok),"ok")==0);
if (isempty) {
/* Internal error - invalid output from rpc handler */
FCGX_SetExitStatus(204, r->out); /* OK */
FCGX_FPrintF(r->out, "Status: 204 No Content\r\n");
FCGX_FPrintF(r->out, "\r\n");
goto fail;
}
/* Clear namespace of parameters */ /* Clear namespace of parameters */
x = NULL; x = NULL;
while ((x = xml_child_each(xoutput, x, CX_ELMNT)) != NULL) { while ((x = xml_child_each(xoutput, x, CX_ELMNT)) != NULL) {
@ -1444,7 +1445,6 @@ api_operations_post_output(clicon_handle h,
if (xml_purge(xa) < 0) if (xml_purge(xa) < 0)
goto done; goto done;
} }
}
/* Set namespace on output */ /* Set namespace on output */
if (xmlns_set(xoutput, NULL, namespace) < 0) if (xmlns_set(xoutput, NULL, namespace) < 0)
goto done; goto done;
@ -1627,7 +1627,7 @@ api_operations_post(clicon_handle h,
} }
/* Here xtop is: /* Here xtop is:
<rpc username="foo"><myfn xmlns="uri"><x>42</x></myfn></rpc> */ <rpc username="foo"><myfn xmlns="uri"><x>42</x></myfn></rpc> */
#if 0 #if 1
if (debug){ if (debug){
cbuf *ccc=cbuf_new(); cbuf *ccc=cbuf_new();
if (clicon_xml2cbuf(ccc, xtop, 0, 0) < 0) if (clicon_xml2cbuf(ccc, xtop, 0, 0) < 0)
@ -1636,8 +1636,8 @@ api_operations_post(clicon_handle h,
__FUNCTION__, cbuf_get(ccc)); __FUNCTION__, cbuf_get(ccc));
} }
#endif #endif
/* 6. Validate outgoing RPC and fill in defaults */ /* 6. Validate incoming RPC and fill in defaults */
if (xml_spec_populate_rpc(h, xtop, yspec) < 0) if (xml_spec_populate_rpc(h, xtop, yspec) < 0) /* */
goto done; goto done;
if ((ret = xml_yang_validate_rpc(xtop, cbret)) < 0) if ((ret = xml_yang_validate_rpc(xtop, cbret)) < 0)
goto done; goto done;
@ -1694,7 +1694,7 @@ api_operations_post(clicon_handle h,
/* 8. Receive reply from local/backend handler as Netconf RPC /* 8. Receive reply from local/backend handler as Netconf RPC
* <rpc-reply><x xmlns="uri">0</x></rpc-reply> * <rpc-reply><x xmlns="uri">0</x></rpc-reply>
*/ */
#if 0 #if 1
if (debug){ if (debug){
cbuf *ccc=cbuf_new(); cbuf *ccc=cbuf_new();
if (clicon_xml2cbuf(ccc, xret, 0, 0) < 0) if (clicon_xml2cbuf(ccc, xret, 0, 0) < 0)

29
configure vendored
View file

@ -635,6 +635,7 @@ EXEEXT
ac_ct_CC ac_ct_CC
wwwuser wwwuser
wwwdir wwwdir
enable_stdyangs
with_restconf with_restconf
RANLIB RANLIB
SH_SUFFIX SH_SUFFIX
@ -711,6 +712,7 @@ ac_user_opts='
enable_option_checking enable_option_checking
enable_debug enable_debug
with_cligen with_cligen
enable_stdyangs
enable_publish enable_publish
with_restconf with_restconf
with_configfile with_configfile
@ -1350,6 +1352,8 @@ Optional Features:
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--enable-debug Build with debug symbols, default: no --enable-debug Build with debug symbols, default: no
--disable-stdyangs Include standard yang files in clixon install,
default: yes
--enable-publish Enable publish of notification streams using SSE and --enable-publish Enable publish of notification streams using SSE and
curl curl
@ -2457,6 +2461,7 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
# If yes, compile apps/restconf # If yes, compile apps/restconf
wwwdir=/www-data wwwdir=/www-data
wwwuser=www-data wwwuser=www-data
@ -3691,6 +3696,26 @@ if test "${with_cligen}"; then
test -d "$with_cligen" && CLIGEN_PREFIX="$with_cligen" test -d "$with_cligen" && CLIGEN_PREFIX="$with_cligen"
fi fi
# Disable/enable standard Yang files.
# If enable - include yang/standard/*.yang in clixon yang files (default)
# If disable - get standard yang files from elsewhere
# Check whether --enable-stdyangs was given.
if test "${enable_stdyangs+set}" = set; then :
enableval=$enable_stdyangs;
if test "$enableval" = no; then
enable_stdyangs=no
else
enable_stdyangs=yes
fi
else
enable_stdyangs=yes
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: stdyangs is $enable_stdyangs" >&5
$as_echo "stdyangs is $enable_stdyangs" >&6; }
# Experimental: Curl publish notification stream to eg Nginx nchan. # Experimental: Curl publish notification stream to eg Nginx nchan.
# Check whether --enable-publish was given. # Check whether --enable-publish was given.
if test "${enable_publish+set}" = set; then : if test "${enable_publish+set}" = set; then :
@ -4408,7 +4433,7 @@ _ACEOF
ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/restconf/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile extras/rpm/Makefile docker/Makefile datastore/Makefile datastore/text/Makefile util/Makefile yang/Makefile doc/Makefile" ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/restconf/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile extras/rpm/Makefile docker/Makefile datastore/Makefile datastore/text/Makefile util/Makefile yang/Makefile yang/clixon/Makefile yang/standard/Makefile doc/Makefile"
cat >confcache <<\_ACEOF cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure # This file is a shell script that caches the results of configure
@ -5121,6 +5146,8 @@ do
"datastore/text/Makefile") CONFIG_FILES="$CONFIG_FILES datastore/text/Makefile" ;; "datastore/text/Makefile") CONFIG_FILES="$CONFIG_FILES datastore/text/Makefile" ;;
"util/Makefile") CONFIG_FILES="$CONFIG_FILES util/Makefile" ;; "util/Makefile") CONFIG_FILES="$CONFIG_FILES util/Makefile" ;;
"yang/Makefile") CONFIG_FILES="$CONFIG_FILES yang/Makefile" ;; "yang/Makefile") CONFIG_FILES="$CONFIG_FILES yang/Makefile" ;;
"yang/clixon/Makefile") CONFIG_FILES="$CONFIG_FILES yang/clixon/Makefile" ;;
"yang/standard/Makefile") CONFIG_FILES="$CONFIG_FILES yang/standard/Makefile" ;;
"doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;

View file

@ -91,6 +91,7 @@ AC_SUBST(LIBS)
AC_SUBST(SH_SUFFIX) AC_SUBST(SH_SUFFIX)
AC_SUBST(RANLIB) AC_SUBST(RANLIB)
AC_SUBST(with_restconf) # If yes, compile apps/restconf AC_SUBST(with_restconf) # If yes, compile apps/restconf
AC_SUBST(enable_stdyangs)
AC_SUBST(wwwdir,/www-data) AC_SUBST(wwwdir,/www-data)
AC_SUBST(wwwuser,www-data) AC_SUBST(wwwuser,www-data)
# #
@ -145,6 +146,20 @@ if test "${with_cligen}"; then
test -d "$with_cligen" && CLIGEN_PREFIX="$with_cligen" test -d "$with_cligen" && CLIGEN_PREFIX="$with_cligen"
fi fi
# Disable/enable standard Yang files.
# If enable - include yang/standard/*.yang in clixon yang files (default)
# If disable - get standard yang files from elsewhere
AC_ARG_ENABLE(stdyangs, AS_HELP_STRING([--disable-stdyangs],[Include standard yang files in clixon install, default: yes]),[
if test "$enableval" = no; then
enable_stdyangs=no
else
enable_stdyangs=yes
fi
],
[ enable_stdyangs=yes])
AC_MSG_RESULT(stdyangs is $enable_stdyangs)
# Experimental: Curl publish notification stream to eg Nginx nchan. # Experimental: Curl publish notification stream to eg Nginx nchan.
AC_ARG_ENABLE(publish, AS_HELP_STRING([--enable-publish],[Enable publish of notification streams using SSE and curl]),[ AC_ARG_ENABLE(publish, AS_HELP_STRING([--enable-publish],[Enable publish of notification streams using SSE and curl]),[
if test "$enableval" = no; then if test "$enableval" = no; then
@ -231,6 +246,8 @@ AC_OUTPUT(Makefile
datastore/text/Makefile datastore/text/Makefile
util/Makefile util/Makefile
yang/Makefile yang/Makefile
yang/clixon/Makefile
yang/standard/Makefile
doc/Makefile doc/Makefile
) )

View file

@ -137,8 +137,12 @@ Start nginx daemon
``` ```
sudo /etc/init.d/nginx start sudo /etc/init.d/nginx start
``` ```
Start the clixon restconf daemon
```
sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data
```
Example: Then acess:
``` ```
curl -G http://127.0.0.1/restconf/data/ietf-interfaces:interfaces/interface=eth9/type curl -G http://127.0.0.1/restconf/data/ietf-interfaces:interfaces/interface=eth9/type
[ [
@ -147,7 +151,7 @@ Example:
} }
] ]
``` ```
Read more in the (restconf)[../apps/restconf] docs. Read more in the [restconf](../apps/restconf) docs.
## What about reference documentation? ## What about reference documentation?
Clixon uses [Doxygen](http://www.doxygen.nl/index.html) for reference documentation. Clixon uses [Doxygen](http://www.doxygen.nl/index.html) for reference documentation.
You need to install doxygen and graphviz on your system. You need to install doxygen and graphviz on your system.
@ -188,6 +192,15 @@ Clixon by default finds its configuration file at `/usr/local/etc/clixon.xml`. H
- Provide --sysconfig=<dir> when configuring. Then FILE is <dir>/etc/clixon.xml - Provide --sysconfig=<dir> when configuring. Then FILE is <dir>/etc/clixon.xml
- FILE is /usr/local/etc/clixon.xml - FILE is /usr/local/etc/clixon.xml
## Can I modify clixon options at runtime?
Yes, when you start a clixon program, you can supply the `-o` option to modify the configuration specified in the configuration file. Options that are leafs are overriden, whereas options that are leaf-lists are added to.
Example, add the "usr/local/share/ietf" directory to the list of directories where yang files are searched for:
```
clixon_cli -o CLICON_YANG_DIR=/usr/local/share/ietf
```
## How are Yang files found? ## How are Yang files found?
Yang files contain the configuration specification. A Clixon Yang files contain the configuration specification. A Clixon
@ -404,7 +417,7 @@ Please look at the example for an example on how to write a state data callback.
A YANG RPC is an application specific operation. Example: A YANG RPC is an application specific operation. Example:
``` ```
rpc fib-route { rpc example-rpc {
input { input {
leaf inarg { type string; } leaf inarg { type string; }
} }
@ -413,7 +426,7 @@ A YANG RPC is an application specific operation. Example:
} }
} }
``` ```
which defines the fib-route operation present in the example (the arguments have been changed). which defines the example-rpc operation present in the example (the arguments have been changed).
Clixon automatically relays the RPC to the clixon backend. To Clixon automatically relays the RPC to the clixon backend. To
implement the RFC, you need to register an RPC callback in the backend plugin: implement the RFC, you need to register an RPC callback in the backend plugin:
@ -423,14 +436,14 @@ int
clixon_plugin_init(clicon_handle h) clixon_plugin_init(clicon_handle h)
{ {
... ...
rpc_callback_register(h, fib_route, NULL, "fib-route"); rpc_callback_register(h, example_rpc, NULL, "example-rpc");
... ...
} }
``` ```
And then define the callback itself: And then define the callback itself:
``` ```
static int static int
fib_route(clicon_handle h, /* Clicon handle */ example_rpc(clicon_handle h, /* Clicon handle */
cxobj *xe, /* Request: <rpc><xn></rpc> */ cxobj *xe, /* Request: <rpc><xn></rpc> */
cbuf *cbret, /* Reply eg <rpc-reply>... */ cbuf *cbret, /* Reply eg <rpc-reply>... */
void *arg, /* Client session */ void *arg, /* Client session */

View file

@ -43,6 +43,8 @@ localstatedir = @localstatedir@
libdir = @exec_prefix@/lib libdir = @exec_prefix@/lib
APPNAME = example APPNAME = example
# Here is where example yang appears
CLIXON_DATADIR = @CLIXON_DATADIR@
# Install here if you want default clixon location: # Install here if you want default clixon location:
CLIXON_DEFAULT_CONFIG = @CLIXON_DEFAULT_CONFIG@ CLIXON_DEFAULT_CONFIG = @CLIXON_DEFAULT_CONFIG@
@ -70,16 +72,7 @@ all: $(PLUGINS)
CLISPECS = $(APPNAME)_cli.cli CLISPECS = $(APPNAME)_cli.cli
YANGSPECS = $(APPNAME).yang YANGSPECS = clixon-example@2019-01-13.yang
YANGSPECS += ietf-yang-types@2013-07-15.yang
YANGSPECS += ietf-inet-types@2013-07-15.yang
YANGSPECS += ietf-interfaces@2014-05-08.yang
YANGSPECS += ietf-ip@2014-06-16.yang
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 += iana-if-type@2014-05-08.yang
# Backend plugin # Backend plugin
BE_SRC = $(APPNAME)_backend.c BE_SRC = $(APPNAME)_backend.c
@ -125,7 +118,7 @@ install: $(YANGSPECS) $(CLISPECS) $(BE_PLUGIN) $(BE2_PLUGIN) $(CLI_PLUGIN) $(NET
install -m 0644 $(APPNAME).xml $(DESTDIR)$(sysconfdir) install -m 0644 $(APPNAME).xml $(DESTDIR)$(sysconfdir)
# install -m 0644 $(APPNAME).xml $(DESTDIR)$(CLIXON_DEFAULT_CONFIG) # install -m 0644 $(APPNAME).xml $(DESTDIR)$(CLIXON_DEFAULT_CONFIG)
install -d -m 0755 $(DESTDIR)$(datarootdir)/$(APPNAME)/yang install -d -m 0755 $(DESTDIR)$(datarootdir)/$(APPNAME)/yang
install -m 0644 $(YANGSPECS) $(DESTDIR)$(datarootdir)/$(APPNAME)/yang install -m 0644 $(YANGSPECS) $(DESTDIR)$(DESTDIR)$(CLIXON_DATADIR)
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/cli install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/cli
install -m 0644 $(INSTALLFLAGS) $(CLI_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/cli install -m 0644 $(INSTALLFLAGS) $(CLI_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/cli
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/backend install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/backend

View file

@ -16,9 +16,9 @@
This directory contains a Clixon example which includes a simple example. It contains the following files: This directory contains a Clixon example which includes a simple example. It contains the following files:
* `example.xml` The configuration file. See (yang/clixon-config@<date>.yang)[../yang/clixon-config@2018-10-21.yang] for the documentation of all available fields. * `example.xml` The configuration file. See (yang/clixon-config@<date>.yang)[../yang/clixon-config@2018-10-21.yang] for the documentation of all available fields.
* `example.yang` The yang spec of the example. It mainly includes ietf routing and IP modules. * `clixon-example@2019-01-13.yang` The yang spec of the example.
* `example_cli.cli` CLIgen specification. * `example_cli.cli` CLIgen specification.
* `example_cli.c` CLI callback plugin containing functions called in the cli file above: a generic callback (`mycallback`) and an RPC (`fib_route_rpc`). * `example_cli.c` CLI callback plugin containing functions called in the cli file above: a generic callback (`mycallback`) and an example RPC call (`example_client_rpc`).
* `example_backend.c` Backend callback plugin including example of: * `example_backend.c` Backend callback plugin including example of:
* transaction callbacks (validate/commit), * transaction callbacks (validate/commit),
* notification, * notification,
@ -115,6 +115,31 @@ The following example shows how to set data using netconf:
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface"/></get-config></rpc>]]>]]> <rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface"/></get-config></rpc>]]>]]>
<rpc><validate><source><candidate/></source></validate></rpc>]]>]]> <rpc><validate><source><candidate/></source></validate></rpc>]]>]]>
``` ```
## Restconf
Setup a web/reverse-proxy server.
For example, using nginx, install, and edit config file: /etc/nginx/sites-available/default:
```
server {
...
location /restconf {
fastcgi_pass unix:/www-data/fastcgi_restconf.sock;
include fastcgi_params;
}
}
```
Start nginx daemon
```
sudo /etc/init.d/nginx start
```
Start the clixon restconf daemon
```
sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data
```
then access using curl or wget:
```
curl -G http://127.0.0.1/restconf/data/ietf-interfaces:interfaces/interface=eth9/type
```
## Streams ## Streams
@ -153,52 +178,59 @@ independent of the yang rpc construct, but it is recommended. The example includ
Example using CLI: Example using CLI:
``` ```
clixon_cli -f /usr/local/etc/example.xml
cli> rpc ipv4 cli> rpc ipv4
rpc-reply { <rpc-reply><x xmlns="urn:example:clixon">ipv4</x><y xmlns="urn:example:clixon">42</y></rpc-reply>
route { ```
address-family ipv4; Example using Netconf:
next-hop { ```
next-hop-list 2.3.4.5; clixon_netconf -qf /usr/local/etc/example.xml
} <rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><example xmlns="urn:example:clixon"><x>ipv4</x></example></rpc>]]>]]>
source-protocol static; <rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><x xmlns="urn:example:clixon">ipv4</x><y xmlns="urn:example:clixon">42</y></rpc-reply>]]>]]>
```
Restconf (assuming nginx started):
```
sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data&
curl -X POST http://localhost/restconf/operations/clixon-example:example -d '{"clixon-example:input":{"x":"ipv4"}}'
{
"clixon-example:output": {
"x": "ipv4",
"y": "42"
} }
} }
``` ```
Netconf:
```
<rpc><fib-route xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"><routing-instance-name>ipv4</routing-instance-name></fib-route></rpc>]]>]]>
<rpc-reply><route xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop><source-protocol>static</source-protocol></route></rpc-reply>]]>]]>
```
Restconf:
```
curl -X POST http://localhost/restconf/operations/ietf-routing:fib-route -d '{"ietf-routing:input":{"routing-instance-name":"ipv4"}}'
```
### Details ### Details
The example works by creating a netconf rpc call and sending it to the backend: (see the fib_route_rpc() function in [example_cli.c](example_cli.c)). The example works by defining an RPC in clixon-example.yang:
```
rpc example {
description "Some example input/output for testing RFC7950 7.14.
RPC simply echoes the input for debugging.";
input {
leaf x {
...
```
In the (example_backend.c)[example_backend.c], a callback is registered (fib_route()) which handles the RPC (this is just dummy data): In the CLI a netconf rpc call is constructed and sent to the backend: See `example_client_rpc()` in [example_cli.c] CLI plugin.
The clixon backend plugin [example_backend.c] reveives the netconf call and replies. This is made byregistering a callback handling handling the RPC:
``` ```
static int static int
fib_route(clicon_handle h, example_rpc(clicon_handle h,
cxobj *xe, /* Request: <rpc><xn></rpc> */ cxobj *xe, /* Request: <rpc><xn></rpc> */
cbuf *cbret, /* Reply eg <rpc-reply>... */ cbuf *cbret, /* Reply eg <rpc-reply>... */
void *arg, /* Client session */ void *arg, /* Client session */
void *regarg) /* Argument given at register */ void *regarg) /* Argument given at register */
{ {
cprintf(cbret, "<rpc-reply><route xmlns=\"urn:ietf:params:xml:ns:yang:ietf-routing\">" /* code that echoes the request */
"<address-family>ipv4</address-family>"
"<next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop>"
"<source-protocol>static</source-protocol>"
"</route></rpc-reply>");
return 0; return 0;
} }
int int
clixon_plugin_init(clicon_handle h) clixon_plugin_init(clicon_handle h)
{ {
... ...
rpc_callback_register(h, fib_route, NULL, "fib-route"); rpc_callback_register(h, example_rpc, NULL, "example");
... ...
} }
``` ```
@ -274,7 +306,7 @@ clixon_plugin_api *
clixon_plugin_init(clicon_handle h) clixon_plugin_init(clicon_handle h)
{ {
/* Optional callback registration for RPC calls */ /* Optional callback registration for RPC calls */
rpc_callback_register(h, fib_route, NULL, "fib-route"); rpc_callback_register(h, example_rpc, NULL, "example");
/* Return plugin API */ /* Return plugin API */
return &api; /* Return NULL on error */ return &api; /* Return NULL on error */
} }

View file

@ -1,22 +1,20 @@
module example { module clixon-example {
yang-version 1.1; yang-version 1.1;
namespace "urn:example:clixon"; namespace "urn:example:clixon";
prefix ex; prefix ex;
revision 2019-01-13 {
description
"Released in Clixon 3.9";
}
import ietf-interfaces { import ietf-interfaces {
prefix if; prefix if;
} }
import ietf-ip { import ietf-ip {
prefix ip; prefix ip;
} }
import ietf-routing {
description "defines fib-route";
prefix rt;
}
import iana-if-type { import iana-if-type {
prefix ianaift; prefix ianaift;
} }
description
"Example code that includes ietf-ip and ietf-routing";
/* Example interface type for tests, local callbacks, etc */ /* Example interface type for tests, local callbacks, etc */
identity eth { identity eth {
base if:interface-type; base if:interface-type;
@ -78,7 +76,20 @@ module example {
} }
} }
rpc empty { rpc empty {
description "Smallest possible RPC with no input or output"; description "Smallest possible RPC with no input or output sections";
}
rpc optional {
description "Small RPC with optional input and output";
input {
leaf x {
type string;
}
}
output {
leaf x {
type string;
}
}
} }
rpc example { rpc example {
description "Some example input/output for testing RFC7950 7.14. description "Some example input/output for testing RFC7950 7.14.

View file

@ -1,9 +1,8 @@
<config> <config>
<CLICON_CONFIGFILE>/usr/local/etc/example.xml</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>/usr/local/etc/example.xml</CLICON_CONFIGFILE>
<CLICON_FEATURE>*:*</CLICON_FEATURE> <CLICON_FEATURE>*:*</CLICON_FEATURE>
<CLICON_YANG_DIR>/usr/local/share/example/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_MODULE_MAIN>clixon-example</CLICON_YANG_MODULE_MAIN>
<CLICON_CLI_MODE>example</CLICON_CLI_MODE> <CLICON_CLI_MODE>example</CLICON_CLI_MODE>
<CLICON_BACKEND_DIR>/usr/local/lib/example/backend</CLICON_BACKEND_DIR> <CLICON_BACKEND_DIR>/usr/local/lib/example/backend</CLICON_BACKEND_DIR>
<CLICON_NETCONF_DIR>/usr/local/lib/example/netconf</CLICON_NETCONF_DIR> <CLICON_NETCONF_DIR>/usr/local/lib/example/netconf</CLICON_NETCONF_DIR>

View file

@ -119,38 +119,6 @@ example_stream_timer_setup(clicon_handle h)
return event_reg_timeout(t, example_stream_timer, h, "example stream timer"); return event_reg_timeout(t, example_stream_timer, h, "example stream timer");
} }
/*! IETF Routing fib-route rpc
* @see ietf-routing@2014-10-26.yang (fib-route)
*/
static int
fib_route(clicon_handle h, /* Clicon handle */
cxobj *xe, /* Request: <rpc><xn></rpc> */
cbuf *cbret, /* Reply eg <rpc-reply>... */
void *arg, /* Client session */
void *regarg) /* Argument given at register */
{
cprintf(cbret, "<rpc-reply><route xmlns=\"urn:ietf:params:xml:ns:yang:ietf-routing\">"
"<address-family>ipv4</address-family>"
"<next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop>"
"<source-protocol>static</source-protocol>"
"</route></rpc-reply>");
return 0;
}
/*! IETF Routing route-count rpc
* @see ietf-routing@2014-10-26.yang (route-count)
*/
static int
route_count(clicon_handle h,
cxobj *xe, /* Request: <rpc><xn></rpc> */
cbuf *cbret, /* Reply eg <rpc-reply>... */
void *arg,
void *regarg) /* Argument given at register */
{
cprintf(cbret, "<rpc-reply><number-of-routes xmlns=\"urn:ietf:params:xml:ns:yang:ietf-routing\">42</number-of-routes></rpc-reply>");
return 0;
}
/*! Smallest possible RPC declaration for test /*! Smallest possible RPC declaration for test
* Yang/XML: * Yang/XML:
* If the RPC operation invocation succeeded and no output parameters * If the RPC operation invocation succeeded and no output parameters
@ -188,7 +156,9 @@ example_rpc(clicon_handle h, /* Clicon handle */
goto done; goto done;
} }
cprintf(cbret, "<rpc-reply>"); cprintf(cbret, "<rpc-reply>");
while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) { if (!xml_child_nr_type(xe, CX_ELMNT))
cprintf(cbret, "<ok/>");
else while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) {
if (xmlns_set(x, NULL, namespace) < 0) if (xmlns_set(x, NULL, namespace) < 0)
goto done; goto done;
if (clicon_xml2cbuf(cbret, x, 0, 0) < 0) if (clicon_xml2cbuf(cbret, x, 0, 0) < 0)
@ -200,7 +170,6 @@ example_rpc(clicon_handle h, /* Clicon handle */
return retval; return retval;
} }
/*! Called to get state data from plugin /*! Called to get state data from plugin
* @param[in] h Clicon handle * @param[in] h Clicon handle
* @param[in] xpath String with XPATH syntax. or NULL for all * @param[in] xpath String with XPATH syntax. or NULL for all
@ -364,24 +333,18 @@ clixon_plugin_init(clicon_handle h)
/* Register callback for routing rpc calls /* Register callback for routing rpc calls
*/ */
if (rpc_callback_register(h, fib_route,
NULL,
"fib-route"/* Xml tag when callback is made */
) < 0)
goto done;
/* From ietf-routing.yang */
if (rpc_callback_register(h, route_count,
NULL,
"route-count"/* Xml tag when callback is made */
) < 0)
goto done;
/* From example.yang (clicon) */ /* From example.yang (clicon) */
if (rpc_callback_register(h, empty_rpc, if (rpc_callback_register(h, empty_rpc,
NULL, NULL,
"empty"/* Xml tag when callback is made */ "empty"/* Xml tag when callback is made */
) < 0) ) < 0)
goto done; goto done;
/* Same as example but with optional input/output */
if (rpc_callback_register(h, example_rpc,
NULL,
"optional"/* Xml tag when callback is made */
) < 0)
goto done;
if (rpc_callback_register(h, example_rpc, if (rpc_callback_register(h, example_rpc,
NULL, NULL,
"example"/* Xml tag when callback is made */ "example"/* Xml tag when callback is made */
@ -393,4 +356,3 @@ clixon_plugin_init(clicon_handle h)
done: done:
return NULL; return NULL;
} }

View file

@ -71,7 +71,6 @@ mycallback(clicon_handle h, cvec *cvv, cvec *argv)
"/interfaces/interface[name='eth0']", "/interfaces/interface[name='eth0']",
&xret) < 0) &xret) < 0)
goto done; goto done;
xml_print(stdout, xret); xml_print(stdout, xret);
retval = 0; retval = 0;
done: done:
@ -80,25 +79,25 @@ mycallback(clicon_handle h, cvec *cvv, cvec *argv)
return retval; return retval;
} }
/*! Example "downcall": ietf-routing fib-route RPC */ /*! Example "downcall", ie initiate an RPC to the backend */
int int
fib_route_rpc(clicon_handle h, example_client_rpc(clicon_handle h,
cvec *cvv, cvec *cvv,
cvec *argv) cvec *argv)
{ {
int retval = -1; int retval = -1;
cg_var *instance; cg_var *cva;
cxobj *xtop = NULL; cxobj *xtop = NULL;
cxobj *xrpc; cxobj *xrpc;
cxobj *xret = NULL; cxobj *xret = NULL;
cxobj *xerr; cxobj *xerr;
/* User supplied variable in CLI command */ /* User supplied variable in CLI command */
instance = cvec_find(cvv, "instance"); /* get a cligen variable from vector */ cva = cvec_find(cvv, "a"); /* get a cligen variable from vector */
/* Create XML for fib-route netconf RPC */ /* Create XML for example netconf RPC */
if (xml_parse_va(&xtop, NULL, "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" username=\"%s\"><fib-route xmlns=\"urn:ietf:params:xml:ns:yang:ietf-routing\"><routing-instance-name>%s</routing-instance-name><destination-address><address-family>ipv4</address-family></destination-address></fib-route></rpc>", if (xml_parse_va(&xtop, NULL, "<rpc message-id=\"101\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" username=\"%s\"><example xmlns=\"urn:example:clixon\"><x>%s</x></example></rpc>",
clicon_username_get(h), clicon_username_get(h),
cv_string_get(instance)) < 0) cv_string_get(cva)) < 0)
goto done; goto done;
/* Skip top-level */ /* Skip top-level */
xrpc = xml_child_i(xtop, 0); xrpc = xml_child_i(xtop, 0);
@ -110,7 +109,12 @@ fib_route_rpc(clicon_handle h,
goto done; goto done;
} }
/* Print result */ /* Print result */
clicon_xml2file(stdout, xml_child_i(xret, 0), 0, 0);
fprintf(stdout,"\n");
/* pretty-print:
xml2txt(stdout, xml_child_i(xret, 0), 0); xml2txt(stdout, xml_child_i(xret, 0), 0);
*/
retval = 0; retval = 0;
done: done:
if (xret) if (xret)

View file

@ -63,7 +63,7 @@ load("Load configuration from XML file") <filename:string>("Filename (local file
merge("Merge file with existent candidate"), load_config_file("filename", "merge"); merge("Merge file with existent candidate"), load_config_file("filename", "merge");
} }
example("This is a comment") <var:int32>("Just a random number"), mycallback("myarg"); example("This is a comment") <var:int32>("Just a random number"), mycallback("myarg");
rpc("ex:fib-route rpc") <instance:string>("routing instance"), fib_route_rpc("myarg"); rpc("example rpc") <a:string>("routing instance"), example_client_rpc("");
notify("Get notifications from backend"), cli_notify("EXAMPLE", "1", "text"); notify("Get notifications from backend"), cli_notify("EXAMPLE", "1", "text");
no("Negate") notify("Get notifications from backend"), cli_notify("EXAMPLE", "0", "xml"); no("Negate") notify("Get notifications from backend"), cli_notify("EXAMPLE", "0", "xml");
lock,cli_lock("candidate"); lock,cli_lock("candidate");

View file

@ -1,698 +0,0 @@
module ietf-interfaces {
namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces";
prefix if;
import ietf-yang-types {
prefix yang;
}
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
WG Chair: Thomas Nadeau
<mailto:tnadeau@lucidvision.com>
WG Chair: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Editor: Martin Bjorklund
<mailto:mbj@tail-f.com>";
description
"This module contains a collection of YANG definitions for
managing network interfaces.
Copyright (c) 2014 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 7223; see
the RFC itself for full legal notices.";
revision 2014-05-08 {
description
"Initial revision.";
reference
"RFC 7223: A YANG Data Model for Interface Management";
}
/*
* Typedefs
*/
typedef interface-ref {
type leafref {
path "/if:interfaces/if:interface/if:name";
}
description
"This type is used by data models that need to reference
configured interfaces.";
}
typedef interface-state-ref {
type leafref {
path "/if:interfaces-state/if:interface/if:name";
}
description
"This type is used by data models that need to reference
the operationally present interfaces.";
}
/*
* Identities
*/
identity interface-type {
description
"Base identity from which specific interface types are
derived.";
}
/*
* Features
*/
feature arbitrary-names {
description
"This feature indicates that the device allows user-controlled
interfaces to be named arbitrarily.";
}
feature pre-provisioning {
description
"This feature indicates that the device supports
pre-provisioning of interface configuration, i.e., it is
possible to configure an interface whose physical interface
hardware is not present on the device.";
}
feature if-mib {
description
"This feature indicates that the device implements
the IF-MIB.";
reference
"RFC 2863: The Interfaces Group MIB";
}
/*
* Configuration data nodes
*/
container interfaces {
description
"Interface configuration parameters.";
list interface {
key "name";
description
"The list of configured interfaces on the device.
The operational state of an interface is available in the
/interfaces-state/interface list. If the configuration of a
system-controlled interface cannot be used by the system
(e.g., the interface hardware present does not match the
interface type), then the configuration is not applied to
the system-controlled interface shown in the
/interfaces-state/interface list. If the configuration
of a user-controlled interface cannot be used by the system,
the configured interface is not instantiated in the
/interfaces-state/interface list.";
leaf name {
type string;
description
"The name of the interface.
A device MAY restrict the allowed values for this leaf,
possibly depending on the type of the interface.
For system-controlled interfaces, this leaf is the
device-specific name of the interface. The 'config false'
list /interfaces-state/interface contains the currently
existing interfaces on the device.
If a client tries to create configuration for a
system-controlled interface that is not present in the
/interfaces-state/interface list, the server MAY reject
the request if the implementation does not support
pre-provisioning of interfaces or if the name refers to
an interface that can never exist in the system. A
NETCONF server MUST reply with an rpc-error with the
error-tag 'invalid-value' in this case.
If the device supports pre-provisioning of interface
configuration, the 'pre-provisioning' feature is
advertised.
If the device allows arbitrarily named user-controlled
interfaces, the 'arbitrary-names' feature is advertised.
When a configured user-controlled interface is created by
the system, it is instantiated with the same name in the
/interface-state/interface list.";
}
leaf description {
type string;
description
"A textual description of the interface.
A server implementation MAY map this leaf to the ifAlias
MIB object. Such an implementation needs to use some
mechanism to handle the differences in size and characters
allowed between this leaf and ifAlias. The definition of
such a mechanism is outside the scope of this document.
Since ifAlias is defined to be stored in non-volatile
storage, the MIB implementation MUST map ifAlias to the
value of 'description' in the persistently stored
datastore.
Specifically, if the device supports ':startup', when
ifAlias is read the device MUST return the value of
'description' in the 'startup' datastore, and when it is
written, it MUST be written to the 'running' and 'startup'
datastores. Note that it is up to the implementation to
decide whether to modify this single leaf in 'startup' or
perform an implicit copy-config from 'running' to
'startup'.
If the device does not support ':startup', ifAlias MUST
be mapped to the 'description' leaf in the 'running'
datastore.";
reference
"RFC 2863: The Interfaces Group MIB - ifAlias";
}
leaf type {
type identityref {
base interface-type;
}
mandatory true;
description
"The type of the interface.
When an interface entry is created, a server MAY
initialize the type leaf with a valid value, e.g., if it
is possible to derive the type from the name of the
interface.
If a client tries to set the type of an interface to a
value that can never be used by the system, e.g., if the
type is not supported or if the type does not match the
name of the interface, the server MUST reject the request.
A NETCONF server MUST reply with an rpc-error with the
error-tag 'invalid-value' in this case.";
reference
"RFC 2863: The Interfaces Group MIB - ifType";
}
leaf enabled {
type boolean;
default "true";
description
"This leaf contains the configured, desired state of the
interface.
Systems that implement the IF-MIB use the value of this
leaf in the 'running' datastore to set
IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry
has been initialized, as described in RFC 2863.
Changes in this leaf in the 'running' datastore are
reflected in ifAdminStatus, but if ifAdminStatus is
changed over SNMP, this leaf is not affected.";
reference
"RFC 2863: The Interfaces Group MIB - ifAdminStatus";
}
leaf link-up-down-trap-enable {
if-feature if-mib;
type enumeration {
enum enabled {
value 1;
}
enum disabled {
value 2;
}
}
description
"Controls whether linkUp/linkDown SNMP notifications
should be generated for this interface.
If this node is not configured, the value 'enabled' is
operationally used by the server for interfaces that do
not operate on top of any other interface (i.e., there are
no 'lower-layer-if' entries), and 'disabled' otherwise.";
reference
"RFC 2863: The Interfaces Group MIB -
ifLinkUpDownTrapEnable";
}
}
}
/*
* Operational state data nodes
*/
container interfaces-state {
config false;
description
"Data nodes for the operational state of interfaces.";
list interface {
key "name";
description
"The list of interfaces on the device.
System-controlled interfaces created by the system are
always present in this list, whether they are configured or
not.";
leaf name {
type string;
description
"The name of the interface.
A server implementation MAY map this leaf to the ifName
MIB object. Such an implementation needs to use some
mechanism to handle the differences in size and characters
allowed between this leaf and ifName. The definition of
such a mechanism is outside the scope of this document.";
reference
"RFC 2863: The Interfaces Group MIB - ifName";
}
leaf type {
type identityref {
base interface-type;
}
mandatory true;
description
"The type of the interface.";
reference
"RFC 2863: The Interfaces Group MIB - ifType";
}
leaf admin-status {
if-feature if-mib;
type enumeration {
enum up {
value 1;
description
"Ready to pass packets.";
}
enum down {
value 2;
description
"Not ready to pass packets and not in some test mode.";
}
enum testing {
value 3;
description
"In some test mode.";
}
}
mandatory true;
description
"The desired state of the interface.
This leaf has the same read semantics as ifAdminStatus.";
reference
"RFC 2863: The Interfaces Group MIB - ifAdminStatus";
}
leaf oper-status {
type enumeration {
enum up {
value 1;
description
"Ready to pass packets.";
}
enum down {
value 2;
description
"The interface does not pass any packets.";
}
enum testing {
value 3;
description
"In some test mode. No operational packets can
be passed.";
}
enum unknown {
value 4;
description
"Status cannot be determined for some reason.";
}
enum dormant {
value 5;
description
"Waiting for some external event.";
}
enum not-present {
value 6;
description
"Some component (typically hardware) is missing.";
}
enum lower-layer-down {
value 7;
description
"Down due to state of lower-layer interface(s).";
}
}
mandatory true;
description
"The current operational state of the interface.
This leaf has the same semantics as ifOperStatus.";
reference
"RFC 2863: The Interfaces Group MIB - ifOperStatus";
}
leaf last-change {
type yang:date-and-time;
description
"The time the interface entered its current operational
state. If the current state was entered prior to the
last re-initialization of the local network management
subsystem, then this node is not present.";
reference
"RFC 2863: The Interfaces Group MIB - ifLastChange";
}
leaf if-index {
if-feature if-mib;
type int32 {
range "1..2147483647";
}
mandatory true;
description
"The ifIndex value for the ifEntry represented by this
interface.";
reference
"RFC 2863: The Interfaces Group MIB - ifIndex";
}
leaf phys-address {
type yang:phys-address;
description
"The interface's address at its protocol sub-layer. For
example, for an 802.x interface, this object normally
contains a Media Access Control (MAC) address. The
interface's media-specific modules must define the bit
and byte ordering and the format of the value of this
object. For interfaces that do not have such an address
(e.g., a serial line), this node is not present.";
reference
"RFC 2863: The Interfaces Group MIB - ifPhysAddress";
}
leaf-list higher-layer-if {
type interface-state-ref;
description
"A list of references to interfaces layered on top of this
interface.";
reference
"RFC 2863: The Interfaces Group MIB - ifStackTable";
}
leaf-list lower-layer-if {
type interface-state-ref;
description
"A list of references to interfaces layered underneath this
interface.";
reference
"RFC 2863: The Interfaces Group MIB - ifStackTable";
}
leaf speed {
type yang:gauge64;
units "bits/second";
description
"An estimate of the interface's current bandwidth in bits
per second. For interfaces that do not vary in
bandwidth or for those where no accurate estimation can
be made, this node should contain the nominal bandwidth.
For interfaces that have no concept of bandwidth, this
node is not present.";
reference
"RFC 2863: The Interfaces Group MIB -
ifSpeed, ifHighSpeed";
}
container statistics {
description
"A collection of interface-related statistics objects.";
leaf discontinuity-time {
type yang:date-and-time;
mandatory true;
description
"The time on the most recent occasion at which any one or
more of this interface's counters suffered a
discontinuity. If no such discontinuities have occurred
since the last re-initialization of the local management
subsystem, then this node contains the time the local
management subsystem re-initialized itself.";
}
leaf in-octets {
type yang:counter64;
description
"The total number of octets received on the interface,
including framing characters.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifHCInOctets";
}
leaf in-unicast-pkts {
type yang:counter64;
description
"The number of packets, delivered by this sub-layer to a
higher (sub-)layer, that were not addressed to a
multicast or broadcast address at this sub-layer.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts";
}
leaf in-broadcast-pkts {
type yang:counter64;
description
"The number of packets, delivered by this sub-layer to a
higher (sub-)layer, that were addressed to a broadcast
address at this sub-layer.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB -
ifHCInBroadcastPkts";
}
leaf in-multicast-pkts {
type yang:counter64;
description
"The number of packets, delivered by this sub-layer to a
higher (sub-)layer, that were addressed to a multicast
address at this sub-layer. For a MAC-layer protocol,
this includes both Group and Functional addresses.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB -
ifHCInMulticastPkts";
}
leaf in-discards {
type yang:counter32;
description
"The number of inbound packets that were chosen to be
discarded even though no errors had been detected to
prevent their being deliverable to a higher-layer
protocol. One possible reason for discarding such a
packet could be to free up buffer space.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifInDiscards";
}
leaf in-errors {
type yang:counter32;
description
"For packet-oriented interfaces, the number of inbound
packets that contained errors preventing them from being
deliverable to a higher-layer protocol. For character-
oriented or fixed-length interfaces, the number of
inbound transmission units that contained errors
preventing them from being deliverable to a higher-layer
protocol.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifInErrors";
}
leaf in-unknown-protos {
type yang:counter32;
description
"For packet-oriented interfaces, the number of packets
received via the interface that were discarded because
of an unknown or unsupported protocol. For
character-oriented or fixed-length interfaces that
support protocol multiplexing, the number of
transmission units received via the interface that were
discarded because of an unknown or unsupported protocol.
For any interface that does not support protocol
multiplexing, this counter is not present.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifInUnknownProtos";
}
leaf out-octets {
type yang:counter64;
description
"The total number of octets transmitted out of the
interface, including framing characters.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifHCOutOctets";
}
leaf out-unicast-pkts {
type yang:counter64;
description
"The total number of packets that higher-level protocols
requested be transmitted, and that were not addressed
to a multicast or broadcast address at this sub-layer,
including those that were discarded or not sent.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts";
}
leaf out-broadcast-pkts {
type yang:counter64;
description
"The total number of packets that higher-level protocols
requested be transmitted, and that were addressed to a
broadcast address at this sub-layer, including those
that were discarded or not sent.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB -
ifHCOutBroadcastPkts";
}
leaf out-multicast-pkts {
type yang:counter64;
description
"The total number of packets that higher-level protocols
requested be transmitted, and that were addressed to a
multicast address at this sub-layer, including those
that were discarded or not sent. For a MAC-layer
protocol, this includes both Group and Functional
addresses.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB -
ifHCOutMulticastPkts";
}
leaf out-discards {
type yang:counter32;
description
"The number of outbound packets that were chosen to be
discarded even though no errors had been detected to
prevent their being transmitted. One possible reason
for discarding such a packet could be to free up buffer
space.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifOutDiscards";
}
leaf out-errors {
type yang:counter32;
description
"For packet-oriented interfaces, the number of outbound
packets that could not be transmitted because of errors.
For character-oriented or fixed-length interfaces, the
number of outbound transmission units that could not be
transmitted because of errors.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifOutErrors";
}
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,232 +0,0 @@
module ietf-ipv4-unicast-routing {
namespace "urn:ietf:params:xml:ns:yang:ietf-ipv4-unicast-routing";
prefix "v4ur";
import ietf-routing {
prefix "rt";
revision-date "2014-10-26";
}
import ietf-inet-types {
prefix "inet";
revision-date "2013-07-15";
}
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
WG Chair: Thomas Nadeau
<mailto:tnadeau@lucidvision.com>
WG Chair: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Editor: Ladislav Lhotka
<mailto:lhotka@nic.cz>";
description
"This YANG module augments the 'ietf-routing' module with basic
configuration and operational state data for IPv4 unicast
routing.
Copyright (c) 2014 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject to
the license terms contained in, the Simplified BSD License set
forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC XXXX; see the
RFC itself for full legal notices.";
revision 2014-10-26 {
description
"Initial revision.";
reference
"RFC XXXX: A YANG Data Model for Routing Management";
}
/* Identities */
identity ipv4-unicast {
base rt:ipv4;
description
"This identity represents the IPv4 unicast address family.";
}
/* Operational state data */
augment "/rt:routing-state/rt:ribs/rt:rib/rt:routes/rt:route" {
when "../../rt:address-family = 'v4ur:ipv4-unicast'" {
description
"This augment is valid only for IPv4 unicast.";
}
description
"This leaf augments an IPv4 unicast route.";
leaf destination-prefix {
type inet:ipv4-prefix;
description
"IPv4 destination prefix.";
}
}
augment "/rt:routing-state/rt:ribs/rt:rib/rt:routes/rt:route/"
+ "rt:next-hop/rt:next-hop-options/rt:simple-next-hop" {
when "../../../rt:address-family = 'v4ur:ipv4-unicast'" {
description
"This augment is valid only for IPv4 unicast.";
}
description
"This leaf augments the 'simple-next-hop' case of IPv4 unicast
routes.";
leaf next-hop-address {
type inet:ipv4-address;
description
"IPv4 address of the next-hop.";
}
}
augment "/rt:routing-state/rt:next-hop-lists/rt:next-hop-list/"
+ "rt:next-hop/rt:next-hop-options/rt:simple-next-hop" {
when "../rt:address-family = 'v4ur:ipv4-unicast'" {
description
"This augment is valid only for IPv4 unicast.";
}
description
"This leaf augments next-hop list with IPv4 next-hop address.
routes.";
leaf next-hop-address {
type inet:ipv4-address;
description
"IPv4 address of the next-hop.";
}
}
/* Configuration data */
augment "/rt:routing/rt:routing-instance/rt:routing-protocols/"
+ "rt:routing-protocol/rt:static-routes" {
description
"This augment defines the configuration of the 'static'
pseudo-protocol with data specific to IPv4 unicast.";
container ipv4 {
description
"Configuration of a 'static' pseudo-protocol instance
consists of a list of routes.";
list route {
key "destination-prefix";
ordered-by "user";
description
"A user-ordered list of static routes.";
leaf destination-prefix {
type inet:ipv4-prefix;
mandatory "true";
description
"IPv4 destination prefix.";
}
leaf description {
type string;
description
"Textual description of the route.";
}
container next-hop {
description
"Configuration of next-hop.";
grouping next-hop-content {
description
"Next-hop content for IPv4 unicast static routes.";
uses rt:next-hop-content {
augment "next-hop-options" {
description
"Add next-hop address case.";
leaf next-hop-address {
type inet:ipv4-address;
description
"IPv4 address of the next-hop.";
}
}
}
}
choice simple-or-list {
description
"Options for next-hops.";
list multipath-entry {
if-feature rt:multipath-routes;
key "name";
description
"List of alternative next-hops.";
leaf name {
type string;
description
"A unique identifier of the next-hop entry.";
}
uses next-hop-content;
uses rt:next-hop-classifiers;
}
case simple-next-hop {
uses next-hop-content;
}
}
}
}
}
}
/* RPC methods */
augment "/rt:fib-route/rt:input/rt:destination-address" {
when "rt:address-family='v4ur:ipv4-unicast'" {
description
"This augment is valid only for IPv4 unicast.";
}
description
"This leaf augments the 'rt:destination-address' parameter of
the 'rt:fib-route' operation.";
leaf address {
type inet:ipv4-address;
description
"IPv4 destination address.";
}
}
augment "/rt:fib-route/rt:output/rt:route" {
when "rt:address-family='v4ur:ipv4-unicast'" {
description
"This augment is valid only for IPv4 unicast.";
}
description
"This leaf augments the reply to the 'rt:fib-route'
operation.";
leaf destination-prefix {
type inet:ipv4-prefix;
description
"IPv4 destination prefix.";
}
}
augment "/rt:fib-route/rt:output/rt:route/rt:next-hop/"
+ "rt:next-hop-options/rt:simple-next-hop" {
when "../rt:address-family='v4ur:ipv4-unicast'" {
description
"This augment is valid only for IPv4 unicast.";
}
description
"This leaf augments the 'simple-next-hop' case in the reply to
the 'rt:fib-route' operation.";
leaf next-hop-address {
type inet:ipv4-address;
description
"IPv4 address of the next-hop.";
}
}
}

View file

@ -1,636 +0,0 @@
module ietf-ipv6-unicast-routing {
namespace "urn:ietf:params:xml:ns:yang:ietf-ipv6-unicast-routing";
prefix "v6ur";
import ietf-routing {
prefix "rt";
revision-date "2014-10-26";
}
import ietf-inet-types {
prefix "inet";
revision-date "2013-07-15";
}
import ietf-interfaces {
prefix "if";
revision-date "2013-07-15";
}
import ietf-ip {
prefix "ip";
revision-date "2014-06-16";
}
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
WG Chair: Thomas Nadeau
<mailto:tnadeau@lucidvision.com>
WG Chair: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Editor: Ladislav Lhotka
<mailto:lhotka@nic.cz>";
description
"This YANG module augments the 'ietf-routing' module with basic
configuration and operational state data for IPv6 unicast
routing.
Copyright (c) 2014 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject to
the license terms contained in, the Simplified BSD License set
forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC XXXX; see the
RFC itself for full legal notices.";
revision 2014-10-26 {
description
"Initial revision.";
reference
"RFC XXXX: A YANG Data Model for Routing Management";
}
/* Identities */
identity ipv6-unicast {
base rt:ipv6;
description
"This identity represents the IPv6 unicast address family.";
}
/* Operational state data */
augment "/rt:routing-state/rt:routing-instance/rt:interfaces/"
+ "rt:interface" {
description
"IPv6-specific parameters of router interfaces.";
container ipv6-router-advertisements {
description
"Parameters of IPv6 Router Advertisements.";
leaf send-advertisements {
type boolean;
description
"A flag indicating whether or not the router sends periodic
Router Advertisements and responds to Router
Solicitations.";
}
leaf max-rtr-adv-interval {
type uint16 {
range "4..1800";
}
units "seconds";
description
"The maximum time allowed between sending unsolicited
multicast Router Advertisements from the interface.";
}
leaf min-rtr-adv-interval {
type uint16 {
range "3..1350";
}
units "seconds";
description
"The minimum time allowed between sending unsolicited
multicast Router Advertisements from the interface.";
}
leaf managed-flag {
type boolean;
description
"The value that is placed in the 'Managed address
configuration' flag field in the Router Advertisement.";
}
leaf other-config-flag {
type boolean;
description
"The value that is placed in the 'Other configuration' flag
field in the Router Advertisement.";
}
leaf link-mtu {
type uint32;
description
"The value that is placed in MTU options sent by the
router. A value of zero indicates that no MTU options are
sent.";
}
leaf reachable-time {
type uint32 {
range "0..3600000";
}
units "milliseconds";
description
"The value that is placed in the Reachable Time field in
the Router Advertisement messages sent by the router. A
value of zero means unspecified (by this router).";
}
leaf retrans-timer {
type uint32;
units "milliseconds";
description
"The value that is placed in the Retrans Timer field in the
Router Advertisement messages sent by the router. A value
of zero means unspecified (by this router).";
}
leaf cur-hop-limit {
type uint8;
description
"The value that is placed in the Cur Hop Limit field in the
Router Advertisement messages sent by the router. A value
of zero means unspecified (by this router).";
}
leaf default-lifetime {
type uint16 {
range "0..9000";
}
units "seconds";
description
"The value that is placed in the Router Lifetime field of
Router Advertisements sent from the interface, in seconds.
A value of zero indicates that the router is not to be
used as a default router.";
}
container prefix-list {
description
"A list of prefixes that are placed in Prefix Information
options in Router Advertisement messages sent from the
interface.
By default, these are all prefixes that the router
advertises via routing protocols as being on-link for the
interface from which the advertisement is sent.";
list prefix {
key "prefix-spec";
description
"Advertised prefix entry and its parameters.";
leaf prefix-spec {
type inet:ipv6-prefix;
description
"IPv6 address prefix.";
}
leaf valid-lifetime {
type uint32;
units "seconds";
description
"The value that is placed in the Valid Lifetime in the
Prefix Information option. The designated value of all
1's (0xffffffff) represents infinity.";
}
leaf on-link-flag {
type boolean;
description
"The value that is placed in the on-link flag ('L-bit')
field in the Prefix Information option.";
}
leaf preferred-lifetime {
type uint32;
units "seconds";
description
"The value that is placed in the Preferred Lifetime in
the Prefix Information option, in seconds. The
designated value of all 1's (0xffffffff) represents
infinity.";
}
leaf autonomous-flag {
type boolean;
description
"The value that is placed in the Autonomous Flag field
in the Prefix Information option.";
}
}
}
}
}
augment "/rt:routing-state/rt:ribs/rt:rib/rt:routes/rt:route" {
when "../../rt:address-family = 'v6ur:ipv6-unicast'" {
description
"This augment is valid only for IPv6 unicast.";
}
description
"This leaf augments an IPv6 unicast route.";
leaf destination-prefix {
type inet:ipv6-prefix;
description
"IPv6 destination prefix.";
}
}
augment "/rt:routing-state/rt:ribs/rt:rib/rt:routes/rt:route/"
+ "rt:next-hop/rt:next-hop-options/rt:simple-next-hop" {
when "../../../rt:address-family = 'v6ur:ipv6-unicast'" {
description
"This augment is valid only for IPv6 unicast.";
}
description
"This leaf augments the 'simple-next-hop' case of IPv6 unicast
routes.";
leaf next-hop {
type inet:ipv6-address;
description
"IPv6 address of the next-hop.";
}
}
augment "/rt:routing-state/rt:next-hop-lists/rt:next-hop-list/"
+ "rt:next-hop/rt:next-hop-options/rt:simple-next-hop" {
when "../rt:address-family = 'v6ur:ipv6-unicast'" {
description
"This augment is valid only for IPv6 unicast.";
}
description
"This leaf augments next-hop list with IPv6 next-hop address.
routes.";
leaf next-hop-address {
type inet:ipv6-address;
description
"IPv6 address of the next-hop.";
}
}
/* Configuration data */
augment
"/rt:routing/rt:routing-instance/rt:interfaces/rt:interface" {
when "/if:interfaces/if:interface[if:name=current()/rt:name]/"
+ "ip:ipv6/ip:enabled='true'" {
description
"This augment is only valid for router interfaces with
enabled IPv6.";
}
description
"Configuration of IPv6-specific parameters of router
interfaces.";
container ipv6-router-advertisements {
description
"Configuration of IPv6 Router Advertisements.";
leaf send-advertisements {
type boolean;
default "false";
description
"A flag indicating whether or not the router sends periodic
Router Advertisements and responds to Router
Solicitations.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvSendAdvertisements.";
}
leaf max-rtr-adv-interval {
type uint16 {
range "4..1800";
}
units "seconds";
default "600";
description
"The maximum time allowed between sending unsolicited
multicast Router Advertisements from the interface.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
MaxRtrAdvInterval.";
}
leaf min-rtr-adv-interval {
type uint16 {
range "3..1350";
}
units "seconds";
must ". <= 0.75 * ../max-rtr-adv-interval" {
description
"The value MUST NOT be greater than 75 % of
'max-rtr-adv-interval'.";
}
description
"The minimum time allowed between sending unsolicited
multicast Router Advertisements from the interface.
The default value to be used operationally if this leaf is
not configured is determined as follows:
- if max-rtr-adv-interval >= 9 seconds, the default value
is 0.33 * max-rtr-adv-interval;
- otherwise it is 0.75 * max-rtr-adv-interval.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
MinRtrAdvInterval.";
}
leaf managed-flag {
type boolean;
default "false";
description
"The value to be placed in the 'Managed address
configuration' flag field in the Router Advertisement.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvManagedFlag.";
}
leaf other-config-flag {
type boolean;
default "false";
description
"The value to be placed in the 'Other configuration' flag
field in the Router Advertisement.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvOtherConfigFlag.";
}
leaf link-mtu {
type uint32;
default "0";
description
"The value to be placed in MTU options sent by the router.
A value of zero indicates that no MTU options are sent.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvLinkMTU.";
}
leaf reachable-time {
type uint32 {
range "0..3600000";
}
units "milliseconds";
default "0";
description
"The value to be placed in the Reachable Time field in the
Router Advertisement messages sent by the router. A value
of zero means unspecified (by this router).";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvReachableTime.";
}
leaf retrans-timer {
type uint32;
units "milliseconds";
default "0";
description
"The value to be placed in the Retrans Timer field in the
Router Advertisement messages sent by the router. A value
of zero means unspecified (by this router).";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvRetransTimer.";
}
leaf cur-hop-limit {
type uint8;
description
"The value to be placed in the Cur Hop Limit field in the
Router Advertisement messages sent by the router. A value
of zero means unspecified (by this router).
If this parameter is not configured, the device SHOULD use
the value specified in IANA Assigned Numbers that was in
effect at the time of implementation.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvCurHopLimit.
IANA: IP Parameters,
http://www.iana.org/assignments/ip-parameters";
}
leaf default-lifetime {
type uint16 {
range "0..9000";
}
units "seconds";
description
"The value to be placed in the Router Lifetime field of
Router Advertisements sent from the interface, in seconds.
It MUST be either zero or between max-rtr-adv-interval and
9000 seconds. A value of zero indicates that the router is
not to be used as a default router. These limits may be
overridden by specific documents that describe how IPv6
operates over different link layers.
If this parameter is not configured, the device SHOULD use
a value of 3 * max-rtr-adv-interval.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvDefaultLifeTime.";
}
container prefix-list {
description
"Configuration of prefixes to be placed in Prefix
Information options in Router Advertisement messages sent
from the interface.
Prefixes that are advertised by default but do not have
their entries in the child 'prefix' list are advertised
with the default values of all parameters.
The link-local prefix SHOULD NOT be included in the list
of advertised prefixes.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvPrefixList.";
list prefix {
key "prefix-spec";
description
"Configuration of an advertised prefix entry.";
leaf prefix-spec {
type inet:ipv6-prefix;
description
"IPv6 address prefix.";
}
choice control-adv-prefixes {
default "advertise";
description
"The prefix either may be explicitly removed from the
set of advertised prefixes, or parameters with which
it is advertised may be specified (default case).";
leaf no-advertise {
type empty;
description
"The prefix will not be advertised.
This can be used for removing the prefix from the
default set of advertised prefixes.";
}
case advertise {
leaf valid-lifetime {
type uint32;
units "seconds";
default "2592000";
description
"The value to be placed in the Valid Lifetime in
the Prefix Information option. The designated
value of all 1's (0xffffffff) represents
infinity.";
reference
"RFC 4861: Neighbor Discovery for IP version 6
(IPv6) - AdvValidLifetime.";
}
leaf on-link-flag {
type boolean;
default "true";
description
"The value to be placed in the on-link flag
('L-bit') field in the Prefix Information
option.";
reference
"RFC 4861: Neighbor Discovery for IP version 6
(IPv6) - AdvOnLinkFlag.";
}
leaf preferred-lifetime {
type uint32;
units "seconds";
must ". <= ../valid-lifetime" {
description
"This value MUST NOT be greater than
valid-lifetime.";
}
default "604800";
description
"The value to be placed in the Preferred Lifetime
in the Prefix Information option. The designated
value of all 1's (0xffffffff) represents
infinity.";
reference
"RFC 4861: Neighbor Discovery for IP version 6
(IPv6) - AdvPreferredLifetime.";
}
leaf autonomous-flag {
type boolean;
default "true";
description
"The value to be placed in the Autonomous Flag
field in the Prefix Information option.";
reference
"RFC 4861: Neighbor Discovery for IP version 6
(IPv6) - AdvAutonomousFlag.";
}
}
}
}
}
}
}
augment "/rt:routing/rt:routing-instance/rt:routing-protocols/"
+ "rt:routing-protocol/rt:static-routes" {
description
"This augment defines the configuration of the 'static'
pseudo-protocol with data specific to IPv6 unicast.";
container ipv6 {
description
"Configuration of a 'static' pseudo-protocol instance
consists of a list of routes.";
list route {
key "destination-prefix";
ordered-by "user";
description
"A user-ordered list of static routes.";
leaf destination-prefix {
type inet:ipv6-prefix;
mandatory "true";
description
"IPv6 destination prefix.";
}
leaf description {
type string;
description
"Textual description of the route.";
}
container next-hop {
description
"Configuration of next-hop.";
grouping next-hop-content {
description
"Next-hop content for IPv6 unicast static routes.";
uses rt:next-hop-content {
augment "next-hop-options" {
description
"Add next-hop address case.";
leaf next-hop-address {
type inet:ipv6-address;
description
"IPv6 address of the next-hop.";
}
}
}
}
choice simple-or-list {
description
"Options for next-hops.";
list multipath-entry {
if-feature rt:multipath-routes;
key "name";
description
"List of alternative next-hops.";
leaf name {
type string;
description
"A unique identifier of the next-hop entry.";
}
uses next-hop-content;
uses rt:next-hop-classifiers;
}
case simple-next-hop {
uses next-hop-content;
}
}
}
}
}
}
/* RPC methods */
augment "/rt:fib-route/rt:input/rt:destination-address" {
when "rt:address-family='v6ur:ipv6-unicast'" {
description
"This augment is valid only for IPv6 unicast.";
}
description
"This leaf augments the 'rt:destination-address' parameter of
the 'rt:fib-route' operation.";
leaf address {
type inet:ipv6-address;
description
"IPv6 destination address.";
}
}
augment "/rt:fib-route/rt:output/rt:route" {
when "rt:address-family='v6ur:ipv6-unicast'" {
description
"This augment is valid only for IPv6 unicast.";
}
description
"This leaf augments the reply to the 'rt:fib-route'
operation.";
leaf destination-prefix {
type inet:ipv6-prefix;
description
"IPv6 destination prefix.";
}
}
augment "/rt:fib-route/rt:output/rt:route/rt:next-hop/"
+ "rt:next-hop-options/rt:simple-next-hop" {
when "../rt:address-family='v4ur:ipv6-unicast'" {
description
"This augment is valid only for IPv6 unicast.";
}
description
"This leaf augments the 'simple-next-hop' case in the reply to
the 'rt:fib-route' operation.";
leaf next-hop-address {
type inet:ipv6-address;
description
"IPv6 address of the next-hop.";
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -190,14 +190,16 @@ array_eval(cxobj *xprev,
xml_type(xnext)==CX_ELMNT && xml_type(xnext)==CX_ELMNT &&
strcmp(xml_name(x),xml_name(xnext))==0){ strcmp(xml_name(x),xml_name(xnext))==0){
ns2 = xml_find_type_value(xnext, NULL, "xmlns", CX_ATTR); ns2 = xml_find_type_value(xnext, NULL, "xmlns", CX_ATTR);
if (nsx && ns2 && strcmp(nsx,ns2)==0) if ((!nsx && !ns2)
|| (nsx && ns2 && strcmp(nsx,ns2)==0))
eqnext++; eqnext++;
} }
if (xprev && if (xprev &&
xml_type(xprev)==CX_ELMNT && xml_type(xprev)==CX_ELMNT &&
strcmp(xml_name(x),xml_name(xprev))==0){ strcmp(xml_name(x),xml_name(xprev))==0){
ns2 = xml_find_type_value(xprev, NULL, "xmlns", CX_ATTR); ns2 = xml_find_type_value(xprev, NULL, "xmlns", CX_ATTR);
if (nsx && ns2 && strcmp(nsx,ns2)==0) if ((!nsx && !ns2)
|| (nsx && ns2 && strcmp(nsx,ns2)==0))
eqprev++; eqprev++;
} }
if (eqprev && eqnext) if (eqprev && eqnext)
@ -214,42 +216,58 @@ array_eval(cxobj *xprev,
return array; return array;
} }
/*! Escape a json string /*! Escape a json string as well as decode xml cdata
* And a
*/ */
static char * static int
json_str_escape(char *str) json_str_escape_cdata(cbuf *cb,
char *str)
{ {
int i, j; int retval = -1;
char *snew; char *snew = NULL;
int i;
int esc = 0; /* cdata escape */
j = 0;
for (i=0;i<strlen(str);i++) for (i=0;i<strlen(str);i++)
switch (str[i]){ switch (str[i]){
case '\n': case '\n':
case '\"': cprintf(cb, "\\n");
case '\\':
j++;
break;
}
if ((snew = malloc(strlen(str)+1+j))==NULL){
clicon_err(OE_XML, errno, "malloc");
return NULL;
}
j = 0;
for (i=0;i<strlen(str);i++)
switch (str[i]){
case '\n':
snew[j++]='\\';
snew[j++]='n';
break; break;
case '\"': case '\"':
cprintf(cb, "\\\"");
break;
case '\\': case '\\':
snew[j++]='\\'; cprintf(cb, "\\\\");
break;
case '<':
if (!esc &&
strncmp(&str[i], "<![CDATA[", strlen("<![CDATA[")) == 0){
esc=1;
i += strlen("<![CDATA[")-1;
}
else
cprintf(cb, "%c", str[i]);
break;
case ']':
if (esc &&
strncmp(&str[i], "]]>", strlen("]]>")) == 0){
esc=0;
i += strlen("]]>")-1;
}
else
cprintf(cb, "%c", str[i]);
break;
default: /* fall thru */ default: /* fall thru */
snew[j++]=str[i]; cprintf(cb, "%c", str[i]);
break;
} }
snew[j++]='\0'; if ((snew = strdup(cbuf_get(cb))) ==NULL){
return snew; clicon_err(OE_XML, errno, "strdup");
goto done;
}
retval = 0;
done:
return retval;
} }
/*! Do the actual work of translating XML to JSON /*! Do the actual work of translating XML to JSON
@ -307,10 +325,10 @@ xml2json1_cbuf(cbuf *cb,
yang_stmt *ymod; /* yang module */ yang_stmt *ymod; /* yang module */
yang_spec *yspec = NULL; /* yang spec */ yang_spec *yspec = NULL; /* yang spec */
int bodystr0=1; int bodystr0=1;
char *str;
char *prefix=NULL; /* prefix / local namespace name */ char *prefix=NULL; /* prefix / local namespace name */
char *namespace=NULL; /* namespace uri */ char *namespace=NULL; /* namespace uri */
char *modname=NULL; /* Module name */ char *modname=NULL; /* Module name */
int commas;
/* If x is labelled with a default namespace, it should be translated /* If x is labelled with a default namespace, it should be translated
* to a module name. * to a module name.
@ -335,10 +353,11 @@ xml2json1_cbuf(cbuf *cb,
switch(arraytype){ switch(arraytype){
case BODY_ARRAY:{ case BODY_ARRAY:{
if (bodystr){ if (bodystr){
if ((str = json_str_escape(xml_value(x))) == NULL) /* XXX String if right type */
cprintf(cb, "\"");
if (json_str_escape_cdata(cb, xml_value(x)) < 0)
goto done; goto done;
cprintf(cb, "\"%s\"", str); cprintf(cb, "\"");
free(str);
} }
else else
cprintf(cb, "%s", xml_value(x)); cprintf(cb, "%s", xml_value(x));
@ -432,6 +451,7 @@ xml2json1_cbuf(cbuf *cb,
break; break;
} }
commas = xml_child_nr_notype(x, CX_ATTR) - 1;
for (i=0; i<xml_child_nr(x); i++){ for (i=0; i<xml_child_nr(x); i++){
xc = xml_child_i(x, i); xc = xml_child_i(x, i);
if (xml_type(xc) == CX_ATTR) if (xml_type(xc) == CX_ATTR)
@ -444,8 +464,10 @@ xml2json1_cbuf(cbuf *cb,
xc_arraytype, xc_arraytype,
level+1, pretty, 0, bodystr0) < 0) level+1, pretty, 0, bodystr0) < 0)
goto done; goto done;
if (i<xml_child_nr_notype(x, CX_ATTR)-1) if (commas > 0) {
cprintf(cb, ",%s", pretty?"\n":""); cprintf(cb, ",%s", pretty?"\n":"");
--commas;
}
} }
switch (arraytype){ switch (arraytype){
case BODY_ARRAY: case BODY_ARRAY:

View file

@ -641,41 +641,68 @@ clixon_trim(char *str)
* POSIX ERE regexps according to man regex(3). * POSIX ERE regexps according to man regex(3).
* @param[in] xsd Input regex string according XSD * @param[in] xsd Input regex string according XSD
* @param[out] posix Output (malloced) string according to POSIX ERE * @param[out] posix Output (malloced) string according to POSIX ERE
* @see http://www.w3.org/TR/2004/REC-xmlschema-2-20041028 * @see https://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#regexs
* @note that the translation is ad-hoc, may need more translations * @see https://www.regular-expressions.info/posixbrackets.html#class translation
* Translation is not complete but covers some character sequences:
* \d decimal digit
* \w alphanum + underscore
*/ */
int int
regexp_xsd2posix(char *xsd, regexp_xsd2posix(char *xsd,
char **posix) char **posix)
{ {
int retval = -1; int retval = -1;
char *x; cbuf *cb = NULL;
char *p = NULL; char x;
int i; int i;
int len; int esc;
len = strlen(xsd); if ((cb = cbuf_new()) == NULL){
x = xsd; clicon_err(OE_UNIX, errno, "cbuf_new");
while ((x = strstr(x, "\\d")) != NULL){
len += 3; /* \d --> [0-9] */
x += 2;
}
if ((p = malloc(len+1)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done; goto done;
} }
memset(p, 0, len+1); esc=0;
*posix = p;
for (i=0; i<strlen(xsd); i++){ for (i=0; i<strlen(xsd); i++){
if (strncmp(&xsd[i], "\\d", 2) == 0){ x = xsd[i];
strcpy(p, "[0-9]"); if (esc){
p += 5; i++; esc = 0;
switch (x){
case 'c': /* xml namechar */
cprintf(cb, "[0-9a-zA-Z\\\\.\\\\-_:]");
break;
case 'd':
cprintf(cb, "[0-9]");
break;
case 'w':
cprintf(cb, "[0-9a-zA-Z_\\\\-]");
break;
case 'W':
cprintf(cb, "[^0-9a-zA-Z_\\\\-]");
break;
case 's':
cprintf(cb, "[ \t\r\n]");
break;
case 'S':
cprintf(cb, "[^ \t\r\n]");
break;
default:
cprintf(cb, "\\%c", x);
break;
} }
}
else if (x == '\\')
esc++;
else else
*p++ = xsd[i]; cprintf(cb, "%c", x);
}
if ((*posix = strdup(cbuf_get(cb))) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto done;
} }
retval = 0; retval = 0;
done: done:
if (cb)
cbuf_free(cb);
return retval; return retval;
} }

View file

@ -1483,7 +1483,7 @@ _xml_parse(const char *str,
{ {
int retval = -1; int retval = -1;
struct xml_parse_yacc_arg ya = {0,}; struct xml_parse_yacc_arg ya = {0,};
cxobj *x;
if (strlen(str) == 0) if (strlen(str) == 0)
return 0; /* OK */ return 0; /* OK */
if (xt == NULL){ if (xt == NULL){
@ -1501,6 +1501,9 @@ _xml_parse(const char *str,
goto done; goto done;
if (clixon_xml_parseparse(&ya) != 0) /* yacc returns 1 on error */ if (clixon_xml_parseparse(&ya) != 0) /* yacc returns 1 on error */
goto done; goto done;
x = NULL;
while ((x = xml_find_type(xt, NULL, "body", CX_BODY)) != NULL)
xml_purge(x);
/* Verify namespaces after parsing */ /* Verify namespaces after parsing */
if (xml_apply0(xt, CX_ELMNT, xml_localname_check, NULL) < 0) if (xml_apply0(xt, CX_ELMNT, xml_localname_check, NULL) < 0)
goto done; goto done;

View file

@ -1695,11 +1695,10 @@ xml_spec_populate_rpc(clicon_handle h,
yang_spec *yspec) yang_spec *yspec)
{ {
int retval = -1; int retval = -1;
yang_stmt *y=NULL; /* yang node */ yang_stmt *yrpc = NULL; /* yang node */
yang_stmt *ymod=NULL; /* yang module */ yang_stmt *ymod=NULL; /* yang module */
yang_stmt *yi = NULL; /* input */ yang_stmt *yi = NULL; /* input */
cxobj *x; cxobj *x;
// int i;
if ((strcmp(xml_name(xrpc), "rpc"))!=0){ if ((strcmp(xml_name(xrpc), "rpc"))!=0){
clicon_err(OE_UNIX, EINVAL, "RPC expected"); clicon_err(OE_UNIX, EINVAL, "RPC expected");
@ -1710,18 +1709,18 @@ xml_spec_populate_rpc(clicon_handle h,
if (ys_module_by_xml(yspec, x, &ymod) < 0) if (ys_module_by_xml(yspec, x, &ymod) < 0)
goto done; goto done;
if (ymod != NULL) if (ymod != NULL)
y = yang_find((yang_node*)ymod, Y_RPC, xml_name(x)); yrpc = yang_find((yang_node*)ymod, Y_RPC, xml_name(x));
/* Non-strict semantics: loop through all modules to find the node /* Non-strict semantics: loop through all modules to find the node
*/ */
if (y == NULL && if (yrpc == NULL &&
!clicon_option_bool(h, "CLICON_XML_NS_STRICT")){ !clicon_option_bool(h, "CLICON_XML_NS_STRICT")){
if (xml_yang_find_non_strict(x, yspec, &y) < 0) /* find rpc */ if (xml_yang_find_non_strict(x, yspec, &yrpc) < 0) /* find rpc */
goto done; goto done;
} }
if (y){ if (yrpc){
xml_spec_set(x, y); xml_spec_set(x, yrpc);
if ((yi = yang_find((yang_node*)y, Y_INPUT, NULL)) != NULL){ if ((yi = yang_find((yang_node*)yrpc, Y_INPUT, NULL)) != NULL){
/* kludge rpc -> input */ /* kludge rpc -> input XXX THIS HIDES AN ERROR IN xml_spec_populate */
xml_spec_set(x, yi); xml_spec_set(x, yi);
if (xml_apply(x, CX_ELMNT, xml_spec_populate, yspec) < 0) if (xml_apply(x, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done; goto done;
@ -1755,12 +1754,12 @@ xml_spec_populate(cxobj *x,
yang_stmt *y = NULL; /* yang node */ yang_stmt *y = NULL; /* yang node */
yang_stmt *yparent; /* yang parent */ yang_stmt *yparent; /* yang parent */
yang_stmt *ymod; /* yang module */ yang_stmt *ymod; /* yang module */
cxobj *xp; /* xml parent */ cxobj *xp = NULL; /* xml parent */
char *name; char *name;
yspec = (yang_spec*)arg; yspec = (yang_spec*)arg;
if (xml_spec(x)) if (xml_spec(x))
goto ok; ; // goto ok;
xp = xml_parent(x); xp = xml_parent(x);
name = xml_name(x); name = xml_name(x);
if (xp && (yparent = xml_spec(xp)) != NULL) if (xp && (yparent = xml_spec(xp)) != NULL)
@ -1785,7 +1784,7 @@ xml_spec_populate(cxobj *x,
goto done; goto done;
} }
#endif #endif
ok: // ok:
retval = 0; retval = 0;
done: done:
return retval; return retval;

View file

@ -105,8 +105,8 @@ ncname {namestart}{namechar}*
%% %%
<START,TEXTDECL>[ \t] ; <START,TEXTDECL>[ \t] ;
<START,STATEA,CMNT,TEXTDECL>\n { _YA->ya_linenum++; } <START,CMNT,TEXTDECL>\n { _YA->ya_linenum++; }
<START,STATEA,CMNT,TEXTDECL>\r <START,CMNT,TEXTDECL>\r
<START>{ncname} { clixon_xml_parselval.string = strdup(yytext); <START>{ncname} { clixon_xml_parselval.string = strdup(yytext);
return NAME; /* rather be catch-all */ return NAME; /* rather be catch-all */
@ -133,6 +133,10 @@ ncname {namestart}{namechar}*
<STATEA>"<?" { BEGIN(PIDECL); return BQMARK; } <STATEA>"<?" { BEGIN(PIDECL); return BQMARK; }
<STATEA>\< { BEGIN(START); return *clixon_xml_parsetext; } <STATEA>\< { BEGIN(START); return *clixon_xml_parsetext; }
<STATEA>& { _YA->ya_lex_state =STATEA;BEGIN(AMPERSAND);} <STATEA>& { _YA->ya_lex_state =STATEA;BEGIN(AMPERSAND);}
<STATEA>[ \t] { clixon_xml_parselval.string = yytext;return WHITESPACE; }
<STATEA>\r\n { clixon_xml_parselval.string = "\n";return WHITESPACE; }
<STATEA>\r { clixon_xml_parselval.string = "\n";return WHITESPACE; }
<STATEA>\n { clixon_xml_parselval.string = yytext; _YA->ya_linenum++;return WHITESPACE; }
<STATEA>. { clixon_xml_parselval.string = yytext; return CHARDATA; } <STATEA>. { clixon_xml_parselval.string = yytext; return CHARDATA; }
/* @see xml_chardata_encode */ /* @see xml_chardata_encode */

View file

@ -41,7 +41,7 @@
%start document %start document
%token <string> NAME CHARDATA STRING %token <string> NAME CHARDATA WHITESPACE STRING
%token MY_EOF %token MY_EOF
%token VER ENC SD %token VER ENC SD
%token BSLASH ESLASH %token BSLASH ESLASH
@ -363,6 +363,7 @@ misclist : misclist misc { clicon_debug(2, "misclist->misclist misc"); }
/* [27] Misc ::= Comment | PI | S */ /* [27] Misc ::= Comment | PI | S */
misc : comment { clicon_debug(2, "misc->comment"); } misc : comment { clicon_debug(2, "misc->comment"); }
| pi { clicon_debug(2, "misc->pi"); } | pi { clicon_debug(2, "misc->pi"); }
| WHITESPACE { clicon_debug(2, "misc->white space"); }
; ;
xmldcl : BXMLDCL verinfo encodingdecl sddecl EQMARK xmldcl : BXMLDCL verinfo encodingdecl sddecl EQMARK
@ -424,6 +425,8 @@ content : element { clicon_debug(2, "content -> element"); }
| pi { clicon_debug(2, "content -> pi"); } | pi { clicon_debug(2, "content -> pi"); }
| CHARDATA { if (xml_parse_content(_YA, $1) < 0) YYABORT; | CHARDATA { if (xml_parse_content(_YA, $1) < 0) YYABORT;
clicon_debug(2, "content -> CHARDATA %s", $1); } clicon_debug(2, "content -> CHARDATA %s", $1); }
| WHITESPACE { if (xml_parse_content(_YA, $1) < 0) YYABORT;
clicon_debug(2, "content -> WHITESPACE %s", $1); }
| { clicon_debug(2, "content -> "); } | { clicon_debug(2, "content -> "); }
; ;

View file

@ -450,7 +450,6 @@ xp_eval_predicate(xp_ctx *xc,
} }
retval = 0; retval = 0;
done: done:
assert(retval==0);
if (xr0) if (xr0)
ctx_free(xr0); ctx_free(xr0);
if (xr1) if (xr1)
@ -716,9 +715,17 @@ xp_relop(xp_ctx *xc1,
s1 = xml_body(x); s1 = xml_body(x);
switch(op){ switch(op){
case XO_EQ: case XO_EQ:
if (s1==NULL || s2==NULL){
clicon_err(OE_XML, EINVAL, "Malformed xpath: empty string");
goto done;
}
xr->xc_bool = (strcmp(s1, s2)==0); xr->xc_bool = (strcmp(s1, s2)==0);
break; break;
case XO_NE: case XO_NE:
if (s1==NULL || s2==NULL){
clicon_err(OE_XML, EINVAL, "Malformed xpath: empty string");
goto done;
}
xr->xc_bool = (strcmp(s1, s2)); xr->xc_bool = (strcmp(s1, s2));
break; break;
default: default:

View file

@ -1641,7 +1641,7 @@ yang_augment_node(yang_stmt *ys,
int i; int i;
schema_nodeid = ys->ys_argument; schema_nodeid = ys->ys_argument;
clicon_debug(1, "%s %s", __FUNCTION__, schema_nodeid); clicon_debug(2, "%s %s", __FUNCTION__, schema_nodeid);
/* Find the target */ /* Find the target */
if (yang_abs_schema_nodeid(ysp, ys, schema_nodeid, -1, &yss) < 0) if (yang_abs_schema_nodeid(ysp, ys, schema_nodeid, -1, &yss) < 0)
goto done; goto done;

View file

@ -1,6 +1,14 @@
#!/bin/bash #!/bin/bash
# Define test functions. # Define test functions.
# Create working dir as variable "dir" # Create working dir as variable "dir"
# The functions are somewhat wildgrown, a little too many:
# - expectfn
# - expecteq
# - expecteof
# - expecteofx
# - expecteof_file
# - expectwait
# - expectmatch
#set -e #set -e
@ -25,6 +33,9 @@ testname=
# Parse yang openconfig models from https://github.com/openconfig/public # Parse yang openconfig models from https://github.com/openconfig/public
: ${OPENCONFIG=$(pwd)/public} : ${OPENCONFIG=$(pwd)/public}
# Standard IETF RFC yang files.
: ${IETFRFC=$YANGMODELS/standard/ietf/RFC}
# For memcheck # For memcheck
#clixon_cli="valgrind --leak-check=full --show-leak-kinds=all clixon_cli" #clixon_cli="valgrind --leak-check=full --show-leak-kinds=all clixon_cli"
clixon_cli=clixon_cli clixon_cli=clixon_cli
@ -157,11 +168,54 @@ expecteq(){
# - expected command return value (0 if OK) # - expected command return value (0 if OK)
# - stdin input # - stdin input
# - expected stdout outcome # - expected stdout outcome
# Use this if you want regex eg ^foo$
expecteof(){ expecteof(){
cmd=$1 cmd=$1
retval=$2 retval=$2
input=$3 input=$3
expect=$4 expect=$4
# Do while read stuff
ret=$($cmd<<EOF
$input
EOF
)
r=$?
if [ $r != $retval ]; then
echo -e "\e[31m\nError ($r != $retval) in Test$testnr [$testname]:"
echo -e "\e[0m:"
exit -1
fi
# If error dont match output strings (why not?)
# if [ $r != 0 ]; then
# return
# fi
# Match if both are empty string
if [ -z "$ret" -a -z "$expect" ]; then
return
fi
# -G for basic regexp (eg ^$). -E for extended regular expression - differs in \
# -Z for nul character, -x for implicit ^$ -q for quiet
# -o only matching
# Two variants: -EZo and -Fxq
# match=`echo "$ret" | grep -FZo "$expect"`
r=$(echo "$ret" | grep -GZo "$expect")
match=$?
# echo "r:\"$r\""
# echo "ret:\"$ret\""
# echo "expect:\"$expect\""
# echo "match:\"$match\""
if [ $match -ne 0 ]; then
err "$expect" "$ret"
fi
}
# Like expecteof but with grep -Fxq instead of -EZq. Ie implicit ^$
# Use this for fixed all line, ie must match exact.
expecteofx(){
cmd=$1
retval=$2
input=$3
expect=$4
# Do while read stuff # Do while read stuff
ret=$($cmd<<EOF ret=$($cmd<<EOF
@ -182,11 +236,16 @@ EOF
if [ -z "$ret" -a -z "$expect" ]; then if [ -z "$ret" -a -z "$expect" ]; then
return return
fi fi
match=`echo "$ret" | grep -GZo "$expect"` # -E for regexp (eg ^$). -Z for nul character, -x for implicit ^$ -q for quiet
# -o only matching
# Two variants: -EZo and -Fxq
# match=`echo "$ret" | grep -FZo "$expect"`
r=$(echo "$ret" | grep -Fxq "$expect")
match=$?
# echo "ret:\"$ret\"" # echo "ret:\"$ret\""
# echo "expect:\"$expect\"" # echo "expect:\"$expect\""
# echo "match:\"$match\"" # echo "match:\"$match\""
if [ -z "$match" ]; then if [ $match -ne 0 ]; then
err "$expect" "$ret" err "$expect" "$ret"
fi fi
} }

View file

@ -17,8 +17,8 @@ cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>system</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_MODULE_MAIN>system</CLICON_YANG_MODULE_MAIN>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>

View file

@ -18,9 +18,9 @@ cfg=$dir/conf_yang.xml
cat <<EOF > $cfg cat <<EOF > $cfg
<config xmlns="urn:example:clixon"> <config xmlns="urn:example:clixon">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>$APPNAME</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>clixon-example</CLICON_YANG_MODULE_MAIN>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR> <CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
@ -115,13 +115,7 @@ expectfn "$clixon_cli -1 -f $cfg -l o debug level 1" 0 "^$"
expectfn "$clixon_cli -1 -f $cfg -l o debug level 0" 0 "^$" expectfn "$clixon_cli -1 -f $cfg -l o debug level 0" 0 "^$"
new "cli rpc" new "cli rpc"
expectfn "$clixon_cli -1 -f $cfg -l o rpc ipv4" 0 'rpc-reply { expectfn "$clixon_cli -1 -f $cfg -l o rpc ipv4" 0 '<rpc-reply><x xmlns="urn:example:clixon">ipv4</x><y xmlns="urn:example:clixon">42</y></rpc-reply>'
route {
address-family ipv4;
next-hop {
next-hop-list 2.3.4.5;
}
source-protocol static;'
if [ $BE -eq 0 ]; then if [ $BE -eq 0 ]; then
exit # BE exit # BE

View file

@ -8,12 +8,14 @@ APPNAME=example
. ./lib.sh . ./lib.sh
cfg=$dir/conf_startup.xml cfg=$dir/conf_startup.xml
# Use yang in example
cat <<EOF > $cfg cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>clixon-example</CLICON_YANG_MODULE_MAIN>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR> <CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<CLICON_NETCONF_DIR>/usr/local/lib/$APPNAME/netconf</CLICON_NETCONF_DIR> <CLICON_NETCONF_DIR>/usr/local/lib/$APPNAME/netconf</CLICON_NETCONF_DIR>

View file

@ -7,13 +7,14 @@ APPNAME=example
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
fyang=$dir/test.yang fyang=$dir/test.yang
# Note ietf-routing@2018-03-13 assumed
cat <<EOF > $cfg cat <<EOF > $cfg
<config> <config>
<CLICON_FEATURE>$APPNAME:A</CLICON_FEATURE> <CLICON_FEATURE>$APPNAME:A</CLICON_FEATURE>
<CLICON_FEATURE>ietf-routing:router-id</CLICON_FEATURE> <CLICON_FEATURE>ietf-routing:router-id</CLICON_FEATURE>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>$APPNAME</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_MODULE_MAIN>$APPNAME</CLICON_YANG_MODULE_MAIN>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
@ -81,10 +82,10 @@ new "cli disabled feature"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set y foo" 255 "CLI syntax error: \"set y foo\": Unknown command" expectfn "$clixon_cli -1f $cfg -l o -y $fyang set y foo" 255 "CLI syntax error: \"set y foo\": Unknown command"
new "cli enabled feature in other module" new "cli enabled feature in other module"
expectfn "$clixon_cli -1f $cfg -y $fyang set routing routing-instance A router-id 1.2.3.4" 0 "" expectfn "$clixon_cli -1f $cfg -y $fyang set routing router-id 1.2.3.4" 0 ""
new "cli disabled feature in other module" new "cli disabled feature in other module"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set routing routing-instance A default-ribs" 255 "CLI syntax error: \"set routing routing-instance A default-ribs\": Unknown command" expectfn "$clixon_cli -1f $cfg -l o -y $fyang set routing ribs rib default-rib false" 255 "CLI syntax error: \"set routing ribs rib default-rib\": Unknown command"
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
@ -136,7 +137,7 @@ if [ -z "$match" ]; then
fi fi
new "netconf module ietf-interfaces" new "netconf module ietf-interfaces"
expect="<module><name>ietf-interfaces</name><revision>2014-05-08</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace><conformance-type>implement</conformance-type></module>" expect="<module><name>ietf-interfaces</name><revision>2018-02-20</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace><conformance-type>implement</conformance-type></module>"
match=`echo "$ret" | grep -GZo "$expect"` match=`echo "$ret" | grep -GZo "$expect"`
if [ -z "$match" ]; then if [ -z "$match" ]; then
err "$expect" "$ret" err "$expect" "$ret"
@ -151,7 +152,7 @@ if [ -z "$match" ]; then
fi fi
new "netconf module ietf-routing" new "netconf module ietf-routing"
expect="<module><name>ietf-routing</name><revision>2014-10-26</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-routing</namespace><feature>router-id</feature><conformance-type>implement</conformance-type></module>" expect="<module><name>ietf-routing</name><revision>2018-03-13</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-routing</namespace><feature>router-id</feature><conformance-type>implement</conformance-type></module>"
match=`echo "$ret" | grep -GZo "$expect"` match=`echo "$ret" | grep -GZo "$expect"`
if [ -z "$match" ]; then if [ -z "$match" ]; then
err "$expect" "$ret" err "$expect" "$ret"

View file

@ -12,6 +12,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR> <CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<CLICON_BACKEND_REGEXP>example_backend.so$</CLICON_BACKEND_REGEXP> <CLICON_BACKEND_REGEXP>example_backend.so$</CLICON_BACKEND_REGEXP>

View file

@ -1,15 +1,22 @@
#!/bin/bash #!/bin/bash
# Test: JSON parser tests # Test: JSON parser tests
# Note that nmbers shouldnot be quoted. See test_restconf2.sh for typed
#PROG="valgrind --leak-check=full --show-leak-kinds=all ../util/clixon_util_json" #PROG="valgrind --leak-check=full --show-leak-kinds=all ../util/clixon_util_json"
PROG=../util/clixon_util_json PROG=../util/clixon_util_json
# include err() and new() functions and creates $dir # include err() and new() functions and creates $dir
. ./lib.sh . ./lib.sh
new "json parse" new "json parse to xml"
expecteof "$PROG" 0 '{"foo": -23}' "^<foo>-23</foo>$" expecteofx "$PROG" 0 '{"foo": -23}' "<foo>-23</foo>"
new "json parse list" new "json parse to json" # should be {"foo": -23}
expecteof "$PROG" 0 '{"a":[0,1,2,3]}' "^<a>0</a><a>1</a><a>2</a><a>3</a>$" expecteofx "$PROG -j" 0 '{"foo": -23}' '{"foo": "-23"}'
new "json parse list xml"
expecteofx "$PROG" 0 '{"a":[0,1,2,3]}' "<a>0</a><a>1</a><a>2</a><a>3</a>"
new "json parse list json" # should be {"a":[0,1,2,3]}
expecteofx "$PROG -j" 0 '{"a":[0,1,2,3]}' '{"a": "0"}{"a": "1"}{"a": "2"}{"a": "3"}'
rm -rf $dir rm -rf $dir

View file

@ -9,9 +9,10 @@ fyang=$dir/leafref.yang
cat <<EOF > $cfg cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
@ -72,73 +73,73 @@ module example{
} }
EOF EOF
new "test params: -f $cfg -y $fyang" new "test params: -f $cfg"
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "kill old backend" new "kill old backend"
sudo clixon_backend -zf $cfg -y $fyang sudo clixon_backend -zf $cfg
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
new "start backend -s init -f $cfg -y $fyang" new "start backend -s init -f $cfg"
sudo $clixon_backend -s init -f $cfg -y $fyang -D $DBG sudo $clixon_backend -s init -f $cfg -D $DBG
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
fi fi
new "leafref base config" new "leafref base config"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth0</name><type>ex:eth</type><ipv4><address><ip>192.0.2.1</ip><prefix-length>24</prefix-length></address><address><ip>192.0.2.2</ip><prefix-length>24</prefix-length></address></ipv4></interface><interface><name>lo</name><type>ex:lo</type><ipv4><address><ip>127.0.0.1</ip><prefix-length>32</prefix-length></address></ipv4></interface></interfaces></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth0</name><type>ex:eth</type><ipv4><address><ip>192.0.2.1</ip><prefix-length>24</prefix-length></address><address><ip>192.0.2.2</ip><prefix-length>24</prefix-length></address></ipv4></interface><interface><name>lo</name><type>ex:lo</type><ipv4><address><ip>127.0.0.1</ip><prefix-length>32</prefix-length></address></ipv4></interface></interfaces></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "leafref get config" new "leafref get config"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth0</name>' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth0</name>'
new "leafref base commit" new "leafref base commit"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "leafref get config" new "leafref get config"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth0</name>' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth0</name>'
new "leafref add wrong ref" new "leafref add wrong ref"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><absname>eth3</absname><address>10.0.4.6</address></default-address></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><absname>eth3</absname><address>10.0.4.6</address></default-address></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "leafref validate" new "leafref validate"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>eth3</bad-element></error-info><error-severity>error</error-severity><error-message>Leafref validation failed: No such leaf</error-message></rpc-error></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>eth3</bad-element></error-info><error-severity>error</error-severity><error-message>Leafref validation failed: No such leaf</error-message></rpc-error></rpc-reply>]]>]]>$'
new "leafref discard-changes" new "leafref discard-changes"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "leafref add correct absref" new "leafref add correct absref"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><absname>eth0</absname></default-address></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><absname>eth0</absname></default-address></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "leafref add correct relref" new "leafref add correct relref"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><relname>eth0</relname></default-address></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><relname>eth0</relname></default-address></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
# XXX add address # XXX add address
new "leafref validate (ok)" new "leafref validate (ok)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
new "leafref delete leaf" new "leafref delete leaf"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface operation="delete"><name>eth0</name></interface></interfaces></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface operation="delete"><name>eth0</name></interface></interfaces></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>'
new "leafref validate (should fail)" new "leafref validate (should fail)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>eth0</bad-element></error-info><error-severity>error</error-severity><error-message>Leafref validation failed: No such leaf</error-message></rpc-error></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>eth0</bad-element></error-info><error-severity>error</error-severity><error-message>Leafref validation failed: No such leaf</error-message></rpc-error></rpc-reply>]]>]]>$'
new "leafref discard-changes" new "leafref discard-changes"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "cli leafref lo" new "cli leafref lo"
expectfn "$clixon_cli -1f $cfg -y $fyang -l o set default-address absname lo" 0 "^$" expectfn "$clixon_cli -1f $cfg -l o set default-address absname lo" 0 "^$"
new "cli leafref validate" new "cli leafref validate"
expectfn "$clixon_cli -1f $cfg -y $fyang -l o validate" 0 "^$" expectfn "$clixon_cli -1f $cfg -l o validate" 0 "^$"
new "cli sender" new "cli sender"
expectfn "$clixon_cli -1f $cfg -y $fyang -l o set sender a" 0 "^$" expectfn "$clixon_cli -1f $cfg -l o set sender a" 0 "^$"
new "cli sender template" new "cli sender template"
expectfn "$clixon_cli -1f $cfg -y $fyang -l o set sender b template a" 0 "^$" expectfn "$clixon_cli -1f $cfg -l o set sender b template a" 0 "^$"
if [ $BE -eq 0 ]; then if [ $BE -eq 0 ]; then
exit # BE exit # BE

View file

@ -11,9 +11,9 @@ fyang=$dir/test.yang
cat <<EOF > $cfg cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>$APPNAME</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
@ -64,65 +64,65 @@ module $APPNAME{
} }
EOF EOF
new "test params: -f $cfg -y $fyang" new "test params: -f $cfg"
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "kill old backend" new "kill old backend"
sudo clixon_backend -zf $cfg -y $fyang sudo clixon_backend -zf $cfg
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
new "start backend -s init -f $cfg -y $fyang" new "start backend -s init -f $cfg"
# start new backend # start new backend
sudo $clixon_backend -s init -f $cfg -y $fyang -D $DBG sudo $clixon_backend -s init -f $cfg -D $DBG
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
fi fi
new "minmax: minimal" new "minmax: minimal"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><a1><k>0</k></a1><b1>0</b1></c></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><a1><k>0</k></a1><b1>0</b1></c></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "minmax: minimal validate ok" new "minmax: minimal validate ok"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "minmax: maximal" new "minmax: maximal"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><a0><k>0</k></a0><a0><k>1</k></a0><a0><k>unbounded</k></a0><a1><k>0</k></a1><a1><k>1</k></a1><b0>0</b0><b0>1</b0><b0>unbounded</b0><b1>0</b1><b0>1</b0></c></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><a0><k>0</k></a0><a0><k>1</k></a0><a0><k>unbounded</k></a0><a1><k>0</k></a1><a1><k>1</k></a1><b0>0</b0><b0>1</b0><b0>unbounded</b0><b1>0</b1><b0>1</b0></c></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "minmax: validate ok" new "minmax: validate ok"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "minmax: empty" new "minmax: empty"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"/></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"/></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
# NYI # NYI
if false; then if false; then
new "minmax: validate should fail" new "minmax: validate should fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$"
new "minmax: no list" new "minmax: no list"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><b1>0</b1></c></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><b1>0</b1></c></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "minmax: validate should fail" new "minmax: validate should fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$"
new "minmax: no leaf-list" new "minmax: no leaf-list"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><a1><k>0</k></a1></c></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><a1><k>0</k></a1></c></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "minmax: validate should fail" new "minmax: validate should fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$"
new "minmax: Too large list" new "minmax: Too large list"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><a1><k>0</k></a1><a1><k>1</k></a1><a1><k>2</k></a1><b1>0</b1></c></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><a1><k>0</k></a1><a1><k>1</k></a1><a1><k>2</k></a1><b1>0</b1></c></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "minmax: validate should fail" new "minmax: validate should fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$"
new "minmax: Too large leaf-list" new "minmax: Too large leaf-list"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><a1><k>0</k></a1><b1>0</b1><b1>1</b1><b1>2</b1></c></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><a1><k>0</k></a1><b1>0</b1><b1>1</b1><b1>2</b1></c></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "minmax: validate should fail" new "minmax: validate should fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$"
fi # NYI fi # NYI
if [ $BE -eq 0 ]; then if [ $BE -eq 0 ]; then

View file

@ -16,6 +16,7 @@ cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE> <CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR> <CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR>

View file

@ -27,6 +27,7 @@ cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE> <CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR> <CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR>
@ -146,6 +147,8 @@ RULES=$(cat <<EOF
EOF EOF
) )
exit # XXX
# kill old backend (if any) # kill old backend (if any)
new "kill old backend" new "kill old backend"
sudo clixon_backend -zf $cfg sudo clixon_backend -zf $cfg

View file

@ -18,8 +18,8 @@ nacmfile=$dir/nacmfile
cat <<EOF > $cfg cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/example/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE> <CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR> <CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
@ -41,13 +41,11 @@ EOF
cat <<EOF > $fyang cat <<EOF > $fyang
module $APPNAME{ module $APPNAME{
yang-version 1.1; yang-version 1.1;
namespace "urn:example:clixon"; namespace "urn:example:my";
import clixon-example {
prefix ex; prefix ex;
import ietf-routing {
description "For fib-route";
prefix rt;
} }
prefix my;
container authentication { container authentication {
description "Example code for enabling www basic auth and some example description "Example code for enabling www basic auth and some example
users"; users";
@ -73,13 +71,6 @@ module $APPNAME{
type int32; type int32;
description "something to edit"; description "something to edit";
} }
container state {
config false;
description "state data for example application";
leaf-list op {
type string;
}
}
} }
EOF EOF
@ -164,7 +155,7 @@ new "restconf DELETE whole datastore"
expecteq "$(curl -u andy:bar -sS -X DELETE http://localhost/restconf/data)" "" expecteq "$(curl -u andy:bar -sS -X DELETE http://localhost/restconf/data)" ""
new2 "auth get" new2 "auth get"
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/example:state)" '{"example:state": {"op": "42"}} expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": "42"}}
' '
new "Set x to 0" new "Set x to 0"
@ -210,7 +201,7 @@ new "cli show conf as guest"
expectfn "$clixon_cli -1 -U guest -l o -f $cfg show conf" 255 "protocol access-denied" expectfn "$clixon_cli -1 -U guest -l o -f $cfg show conf" 255 "protocol access-denied"
new "cli rpc as admin" new "cli rpc as admin"
expectfn "$clixon_cli -1 -U andy -l o -f $cfg rpc ipv4" 0 "next-hop-list 2.3.4.5;" expectfn "$clixon_cli -1 -U andy -l o -f $cfg rpc ipv4" 0 '<x xmlns="urn:example:clixon">ipv4</x><y xmlns="urn:example:clixon">42</y>'
new "cli rpc as limited" new "cli rpc as limited"
expectfn "$clixon_cli -1 -U wilma -l o -f $cfg rpc ipv4" 255 "protocol access-denied default deny" expectfn "$clixon_cli -1 -U wilma -l o -f $cfg rpc ipv4" 255 "protocol access-denied default deny"

View file

@ -24,10 +24,13 @@ cfg=$dir/conf_yang.xml
fyang=$dir/test.yang fyang=$dir/test.yang
fyangerr=$dir/err.yang fyangerr=$dir/err.yang
exit # XXX
cat <<EOF > $cfg cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE> <CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR> <CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR>

View file

@ -36,6 +36,7 @@ cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE> <CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR> <CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR>

View file

@ -5,15 +5,17 @@ APPNAME=example
. ./lib.sh . ./lib.sh
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
fyang=$dir/netconf.yang
tmp=$dir/tmp.x tmp=$dir/tmp.x
# Use yang in example
cat <<EOF > $cfg cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_MODULE_SET_ID>42</CLICON_MODULE_SET_ID> <CLICON_MODULE_SET_ID>42</CLICON_MODULE_SET_ID>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>clixon-example</CLICON_YANG_MODULE_MAIN>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR> <CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<CLICON_BACKEND_REGEXP>example_backend.so$</CLICON_BACKEND_REGEXP> <CLICON_BACKEND_REGEXP>example_backend.so$</CLICON_BACKEND_REGEXP>
@ -29,65 +31,7 @@ cat <<EOF > $cfg
</config> </config>
EOF EOF
cat <<EOF > $fyang new "test params: -f $cfg"
module example{
yang-version 1.1;
namespace "urn:example:clixon";
prefix ex;
import ietf-interfaces {
prefix if;
}
import ietf-ip {
prefix ip;
}
import ietf-routing {
prefix rt;
}
import ietf-inet-types {
prefix "inet";
revision-date "2013-07-15";
}
rpc empty {
}
list server {
key name;
leaf name {
type string;
}
action reset {
}
}
identity eth {
base if:interface-type;
}
rpc client-rpc {
description "Example local client-side RPC that is processed by the
the netconf/restconf and not sent to the backend.
This is a clixon implementation detail: some rpc:s
are better processed by the client for API or perf reasons";
input {
leaf request {
type string;
}
}
output {
leaf result{
type string;
}
}
}
container state {
config false;
description "state data for example application";
leaf-list op {
type string;
}
}
}
EOF
new "test params: -f $cfg -y $fyang"
# Bring your own backend # Bring your own backend
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
# kill old backend (if any) # kill old backend (if any)
@ -96,31 +40,31 @@ if [ $BE -ne 0 ]; then
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
new "start backend -s init -f $cfg -y $fyang" new "start backend -s init -f $cfg"
# start new backend # start new backend
sudo $clixon_backend -s init -f $cfg -y $fyang -D $DBG sudo $clixon_backend -s init -f $cfg -D $DBG
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
fi fi
new "netconf hello" new "netconf hello"
expecteof "$clixon_netconf -f $cfg -y $fyang" 0 '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability><capability>urn:ietf:params:netconf:capability:yang-library:1.0?revision=2016-06-21&amp;module-set-id=42</capability><capability>urn:ietf:params:netconf:capability:candidate:1:0</capability><capability>urn:ietf:params:netconf:capability:validate:1.1</capability><capability>urn:ietf:params:netconf:capability:startup:1.0</capability><capability>urn:ietf:params:netconf:capability:xpath:1.0</capability><capability>urn:ietf:params:netconf:capability:notification:1.0</capability></capabilities><session-id>[0-9]*</session-id></hello>]]>]]><rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -f $cfg" 0 '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability><capability>urn:ietf:params:netconf:capability:yang-library:1.0?revision=2016-06-21&amp;module-set-id=42</capability><capability>urn:ietf:params:netconf:capability:candidate:1:0</capability><capability>urn:ietf:params:netconf:capability:validate:1.1</capability><capability>urn:ietf:params:netconf:capability:startup:1.0</capability><capability>urn:ietf:params:netconf:capability:xpath:1.0</capability><capability>urn:ietf:params:netconf:capability:notification:1.0</capability></capabilities><session-id>[0-9]*</session-id></hello>]]>]]><rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'
new "netconf get-config double quotes" new "netconf get-config double quotes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><data/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><data/></rpc-reply>]]>]]>$'
new "netconf get-config single quotes" new "netconf get-config single quotes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc message-id='101' xmlns='urn:ietf:params:xml:ns:netconf:base:1.0'><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><data/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc message-id='101' xmlns='urn:ietf:params:xml:ns:netconf:base:1.0'><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><data/></rpc-reply>]]>]]>$'
new "Add subtree eth/0/0 using none which should not change anything" new "Add subtree eth/0/0 using none which should not change anything"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><default-operation>none</default-operation><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name></interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><default-operation>none</default-operation><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name></interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "Check nothing added" new "Check nothing added"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'
new "Add subtree eth/0/0 using none and create which should add eth/0/0" new "Add subtree eth/0/0 using none and create which should add eth/0/0"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface operation="create"><name>eth/0/0</name><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface operation="create"><name>eth/0/0</name><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
# Too many quotes, (single inside double inside single) need to fool bash # Too many quotes, (single inside double inside single) need to fool bash
cat <<EOF > $tmp # new cat <<EOF > $tmp # new
@ -128,22 +72,22 @@ cat <<EOF > $tmp # new
EOF EOF
new "Check eth/0/0 added using xpath" new "Check eth/0/0 added using xpath"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$'
new "Re-create same eth/0/0 which should generate error" new "Re-create same eth/0/0 which should generate error"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface operation="create"><name>eth/0/0</name><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error>' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface operation="create"><name>eth/0/0</name><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error>'
new "Delete eth/0/0 using none config" new "Delete eth/0/0 using none config"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface operation="delete"><name>eth/0/0</name><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface operation="delete"><name>eth/0/0</name><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "Check deleted eth/0/0 (non-presence container)" new "Check deleted eth/0/0 (non-presence container)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'
new "Re-Delete eth/0/0 using none should generate error" new "Re-Delete eth/0/0 using none should generate error"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface operation="delete"><name>eth/0/0</name><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error>' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface operation="delete"><name>eth/0/0</name><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error>'
new "netconf edit config" new "netconf edit config"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
# Too many quotes # Too many quotes
cat <<EOF > $tmp # new cat <<EOF > $tmp # new
@ -151,7 +95,7 @@ cat <<EOF > $tmp # new
EOF EOF
new "netconf get config xpath" new "netconf get config xpath"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth1</name><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth1</name><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$'
# Too many quotes # Too many quotes
cat <<EOF > $tmp # new cat <<EOF > $tmp # new
@ -159,99 +103,96 @@ cat <<EOF > $tmp # new
EOF EOF
new "netconf get config xpath parent" new "netconf get config xpath parent"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name><enabled>true</enabled></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><enabled>true</enabled><forwarding>false</forwarding><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name><enabled>true</enabled></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><enabled>true</enabled><forwarding>false</forwarding><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></data></rpc-reply>]]>]]>$'
new "netconf validate missing type" new "netconf validate missing type"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf get empty config2" new "netconf get empty config2"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data/></rpc-reply>]]>]]>$"
new "netconf edit extra xml" new "netconf edit extra xml"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><extra/></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error>" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><extra/></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error>"
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf edit config eth1" new "netconf edit config eth1"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth1</name><type>ex:eth</type></interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth1</name><type>ex:eth</type></interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate" new "netconf validate"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf commit" new "netconf commit"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf edit config merge" new "netconf edit config merge"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth2</name><type>ex:eth</type></interface></interfaces></config><default-operation>merge</default-operation></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth2</name><type>ex:eth</type></interface></interfaces></config><default-operation>merge</default-operation></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf edit ampersand encoding(<&): name:'eth&' type:'t<>'" new "netconf edit ampersand encoding(<&): name:'eth&' type:'t<>'"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth&amp;</name><type>t&lt;&gt;</type></interface></interfaces></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth&amp;</name><type>t&lt;&gt;</type></interface></interfaces></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "netconf get replaced config" new "netconf get replaced config"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth&amp;</name><type>t&lt;&gt;</type><enabled>true</enabled></interface><interface><name>eth1</name><type>ex:eth</type><enabled>true</enabled></interface><interface><name>eth2</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth&amp;</name><type>t&lt;&gt;</type><enabled>true</enabled></interface><interface><name>eth1</name><type>ex:eth</type><enabled>true</enabled></interface><interface><name>eth2</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$'
new "cli show configuration eth& - encoding tests" new "cli show configuration eth& - encoding tests"
expectfn "$clixon_cli -1 -f $cfg -y $fyang show conf cli" 0 "interfaces interface eth& type t<> expectfn "$clixon_cli -1 -f $cfg show conf cli" 0 "interfaces interface eth& type t<>
interfaces interface eth& enabled true" interfaces interface eth& enabled true"
new "netconf edit CDATA" new "netconf edit CDATA"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name><type>ex:eth</type><description><![CDATA[myeth&]]></description></interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name><type>ex:eth</type><description><![CDATA[myeth&]]></description></interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
#new "netconf get CDATA" #new "netconf get CDATA"
#expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/interfaces/interface[name='eth/0/0']/description\" /></get-config></rpc>]]>]]>' '<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name><description><![CDATA[myeth&]]></description><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>' #expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/interfaces/interface[name='eth/0/0']/description\" /></get-config></rpc>]]>]]>' '<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name><description><![CDATA[myeth&]]></description><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>'
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf edit state operation should fail" new "netconf edit state operation should fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><state xmlns="urn:example:clixon"><op>42</op></state></config></edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>invalid-value</error-tag>" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><state xmlns="urn:example:clixon"><op>42</op></state></config></edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>invalid-value</error-tag>"
new "netconf get state operation" new "netconf get state operation"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get><filter type=\"xpath\" select=\"/state\"/></get></rpc>]]>]]>" '^<rpc-reply><data><state xmlns="urn:example:clixon"><op>42</op></state></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get><filter type=\"xpath\" select=\"/state\"/></get></rpc>]]>]]>" '^<rpc-reply><data><state xmlns="urn:example:clixon"><op>42</op></state></data></rpc-reply>]]>]]>$'
new "netconf lock/unlock" new "netconf lock/unlock"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]><rpc><unlock><target><candidate/></target></unlock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]><rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]><rpc><unlock><target><candidate/></target></unlock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]><rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf lock/lock" new "netconf lock/lock"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf lock" new "netconf lock"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "close-session" new "close-session"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><close-session/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><close-session/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
# XXX NOTE that this does not actually kill a running session - and may even kill some random process,... # XXX NOTE that this does not actually kill a running session - and may even kill some random process,...
new "kill-session" new "kill-session"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><kill-session><session-id>44</session-id></kill-session></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><kill-session><session-id>44</session-id></kill-session></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "copy startup" new "copy startup"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><copy-config><target><startup/></target><source><candidate/></source></copy-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><copy-config><target><startup/></target><source><candidate/></source></copy-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf get startup" new "netconf get startup"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><startup/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth1</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><startup/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth1</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$'
new "netconf delete startup" new "netconf delete startup"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><delete-config><target><startup/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><delete-config><target><startup/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf check empty startup" new "netconf check empty startup"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><startup/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><startup/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data/></rpc-reply>]]>]]>$"
new "netconf rpc" new "netconf example rpc"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><fib-route xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"><routing-instance-name>ipv4</routing-instance-name><destination-address><address-family>ipv4</address-family></destination-address></fib-route></rpc>]]>]]>' '^<rpc-reply><route xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"><address-family>ipv4</address-family><next-hop><next-hop-list>' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><example xmlns="urn:example:clixon"><x>42</x></example></rpc>]]>]]>' '^<rpc-reply><x xmlns="urn:example:clixon">42</x><y xmlns="urn:example:clixon">42</y></rpc-reply>]]>]]>$'
#new "netconf rpc without namespace (iterate kludge should work)"
#expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><fib-route><routing-instance-name>ipv4</routing-instance-name><destination-address><address-family>ipv4</address-family></destination-address></fib-route></rpc>]]>]]>" "^<rpc-reply><route><address-family>ipv4</address-family><next-hop><next-hop-list>"
new "netconf empty rpc" new "netconf empty rpc"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><empty xmlns="urn:example:clixon"/></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><empty xmlns="urn:example:clixon"/></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf client-side rpc" new "netconf client-side rpc"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><client-rpc xmlns="urn:example:clixon"><request>example</request></client-rpc></rpc>]]>]]>' '^<rpc-reply><result xmlns="urn:example:clixon">ok</result></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><client-rpc xmlns="urn:example:clixon"><request>example</request></client-rpc></rpc>]]>]]>' '^<rpc-reply><result xmlns="urn:example:clixon">ok</result></rpc-reply>]]>]]>$'
if [ $BE -eq 0 ]; then if [ $BE -eq 0 ]; then
exit # BE exit # BE

View file

@ -9,6 +9,7 @@
APPNAME=example APPNAME=example
# include err() and new() functions and creates $dir # include err() and new() functions and creates $dir
. ./site.sh
. ./lib.sh . ./lib.sh
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
@ -61,9 +62,8 @@ cat <<EOF > $cfg
<CLICON_YANG_DIR>$OCDIR/wifi/mac</CLICON_YANG_DIR> <CLICON_YANG_DIR>$OCDIR/wifi/mac</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/wifi/phy</CLICON_YANG_DIR> <CLICON_YANG_DIR>$OCDIR/wifi/phy</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/wifi/types</CLICON_YANG_DIR> <CLICON_YANG_DIR>$OCDIR/wifi/types</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>$APPNAME</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>

View file

@ -24,9 +24,8 @@ fi
cat <<EOF > $cfg cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>/tmp/conf_yang.xml</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>/tmp/conf_yang.xml</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
@ -140,7 +139,7 @@ new "get each ordered-by user leaf-list"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k='b']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y3 xmlns="urn:example:clixon"><k>b</k><a>bar</a></y3></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k='b']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y3 xmlns="urn:example:clixon"><k>b</k><a>bar</a></y3></data></rpc-reply>]]>]]>$'
new "delete candidate" new "delete candidate"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><default-operation>none</default-operation><config operation="delete"/></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>none</default-operation><config operation="delete"/></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
# LEAF_LISTS # LEAF_LISTS

View file

@ -49,6 +49,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>scaling</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_MODULE_MAIN>scaling</CLICON_YANG_MODULE_MAIN>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK> <CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE> <CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>

View file

@ -5,14 +5,15 @@ APPNAME=example
# include err() and new() functions and creates $dir # include err() and new() functions and creates $dir
. ./lib.sh . ./lib.sh
cfg=$dir/conf.xml cfg=$dir/conf.xml
fyang=$dir/restconf.yang
# Use yang in example
cat <<EOF > $cfg cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>clixon-example</CLICON_YANG_MODULE_MAIN>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR> <CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<CLICON_BACKEND_REGEXP>example_backend.so$</CLICON_BACKEND_REGEXP> <CLICON_BACKEND_REGEXP>example_backend.so$</CLICON_BACKEND_REGEXP>
@ -29,64 +30,18 @@ cat <<EOF > $cfg
</config> </config>
EOF EOF
cat <<EOF > $fyang
module example{
yang-version 1.1;
namespace "urn:example:clixon";
prefix ex;
import ietf-interfaces {
prefix if;
}
import ietf-ip {
prefix ip;
}
import ietf-routing {
prefix rt;
}
import ietf-inet-types {
prefix "inet";
revision-date "2013-07-15";
}
identity eth {
base if:interface-type;
}
rpc empty {
}
rpc client-rpc {
description "Example local client-side rpc";
input {
leaf request {
type string;
}
}
output {
leaf result{
type string;
}
}
}
container state {
config false;
description "state data for example application";
leaf-list op {
type string;
}
}
}
EOF
# This is a fixed 'state' implemented in routing_backend. It is assumed to be always there # This is a fixed 'state' implemented in routing_backend. It is assumed to be always there
state='{"example:state": {"op": "42"}}' state='{"clixon-example:state": {"op": "42"}}'
new "test params: -f $cfg -y $fyang" new "test params: -f $cfg"
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "kill old backend" new "kill old backend"
sudo clixon_backend -zf $cfg sudo clixon_backend -zf $cfg
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
new "start backend -s init -f $cfg -y $fyang" new "start backend -s init -f $cfg"
sudo $clixon_backend -s init -f $cfg -y $fyang -D $DBG sudo $clixon_backend -s init -f $cfg -D $DBG
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
@ -96,7 +51,7 @@ new "kill old restconf daemon"
sudo pkill -u www-data clixon_restconf sudo pkill -u www-data clixon_restconf
new "start restconf daemon" new "start restconf daemon"
sudo su -c "$clixon_restconf -f $cfg -y $fyang -D $DBG" -s /bin/sh www-data & sudo su -c "$clixon_restconf -f $cfg -D $DBG" -s /bin/sh www-data &
sleep $RCWAIT sleep $RCWAIT
@ -118,12 +73,12 @@ expecteq "$(curl -s -H 'Accept: application/yang-data+xml' -G http://localhost/r
# Should be alphabetically ordered # Should be alphabetically ordered
new2 "restconf get restconf/operations. RFC8040 3.3.2 (json)" new2 "restconf get restconf/operations. RFC8040 3.3.2 (json)"
expecteq "$(curl -sG http://localhost/restconf/operations)" '{"operations": {"example:empty": null,"example:client-rpc": null,"ietf-routing:fib-route": null,"ietf-routing:route-count": null,"clixon-lib:debug": null} expecteq "$(curl -sG http://localhost/restconf/operations)" '{"operations": {"clixon-example:client-rpc": null,"clixon-example:empty": null,"clixon-example:optional": null,"clixon-example:example": null,"clixon-lib:debug": null}
' '
new "restconf get restconf/operations. RFC8040 3.3.2 (xml)" new "restconf get restconf/operations. RFC8040 3.3.2 (xml)"
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/operations) ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/operations)
expect='<operations><empty xmlns="urn:example:clixon"/><client-rpc xmlns="urn:example:clixon"/><fib-route xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"/><route-count xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"/><debug xmlns="http://clicon.org/lib"/></operations>' expect='<operations><client-rpc xmlns="urn:example:clixon"/><empty xmlns="urn:example:clixon"/><optional xmlns="urn:example:clixon"/><example xmlns="urn:example:clixon"/><debug xmlns="http://clicon.org/lib"/></operations>'
match=`echo $ret | grep -EZo "$expect"` match=`echo $ret | grep -EZo "$expect"`
if [ -z "$match" ]; then if [ -z "$match" ]; then
err "$expect" "$ret" err "$expect" "$ret"
@ -141,7 +96,7 @@ if [ -z "$match" ]; then
fi fi
new2 "restconf schema resource, RFC 8040 sec 3.7 according to RFC 7895 (explicit resource)" new2 "restconf schema resource, RFC 8040 sec 3.7 according to RFC 7895 (explicit resource)"
expecteq "$(curl -s -H 'Accept: application/yang-data+json' -G http://localhost/restconf/data/ietf-yang-library:modules-state/module=ietf-routing,2014-10-26/)" '{"ietf-yang-library:module": [{"name": "ietf-routing","revision": "2014-10-26","namespace": "urn:ietf:params:xml:ns:yang:ietf-routing","conformance-type": "implement"}]} expecteq "$(curl -s -H 'Accept: application/yang-data+json' -G http://localhost/restconf/data/ietf-yang-library:modules-state/module=ietf-interfaces,2018-02-20)" '{"ietf-yang-library:module": [{"name": "ietf-interfaces","revision": "2018-02-20","namespace": "urn:ietf:params:xml:ns:yang:ietf-interfaces","conformance-type": "implement"}]}
' '
new "restconf options. RFC 8040 4.1" new "restconf options. RFC 8040 4.1"
@ -152,24 +107,24 @@ expectfn "curl -s -I http://localhost/restconf/data" 0 "HTTP/1.1 200 OK"
#Content-Type: application/yang-data+json" #Content-Type: application/yang-data+json"
new "restconf empty rpc" new "restconf empty rpc"
expecteq "$(curl -s -X POST -d {\"example:input\":null} http://localhost/restconf/operations/example:empty)" "" expecteq "$(curl -s -X POST -d {\"clixon-example:input\":null} http://localhost/restconf/operations/clixon-example:empty)" ""
new2 "restconf empty rpc with extra args (should fail)" new2 "restconf empty rpc with extra args (should fail)"
expecteq "$(curl -s -X POST -d {\"example:input\":{\"extra\":null}} http://localhost/restconf/operations/example:empty)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "extra"},"error-severity": "error"}}} ' expecteq "$(curl -s -X POST -d {\"clixon-example:input\":{\"extra\":null}} http://localhost/restconf/operations/clixon-example:empty)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "extra"},"error-severity": "error"}}} '
new2 "restconf get empty config + state json" new2 "restconf get empty config + state json"
expecteq "$(curl -sSG http://localhost/restconf/data/example:state)" '{"example:state": {"op": "42"}} expecteq "$(curl -sSG http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": "42"}}
' '
new2 "restconf get empty config + state json + module" new2 "restconf get empty config + state json + module"
expecteq "$(curl -sSG http://localhost/restconf/data/example:state)" '{"example:state": {"op": "42"}} expecteq "$(curl -sSG http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": "42"}}
' '
new2 "restconf get empty config + state json with wrong module name" new2 "restconf get empty config + state json with wrong module name"
expecteq "$(curl -sSG http://localhost/restconf/data/badmodule:state)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "No such yang module: badmodule"}}} ' expecteq "$(curl -sSG http://localhost/restconf/data/badmodule:state)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "No such yang module: badmodule"}}} '
new "restconf get empty config + state xml" new "restconf get empty config + state xml"
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/example:state) ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/clixon-example:state)
expect='<state xmlns="urn:example:clixon"><op>42</op></state>' expect='<state xmlns="urn:example:clixon"><op>42</op></state>'
match=`echo $ret | grep -EZo "$expect"` match=`echo $ret | grep -EZo "$expect"`
if [ -z "$match" ]; then if [ -z "$match" ]; then
@ -177,12 +132,12 @@ if [ -z "$match" ]; then
fi fi
new2 "restconf get data/ json" new2 "restconf get data/ json"
expecteq "$(curl -s -G http://localhost/restconf/data/example:state/op=42)" '{"example:op": "42"} expecteq "$(curl -s -G http://localhost/restconf/data/clixon-example:state/op=42)" '{"clixon-example:op": "42"}
' '
new "restconf get state operation eth0 xml" new "restconf get state operation eth0 xml"
# Cant get shell macros to work, inline matching from lib.sh # Cant get shell macros to work, inline matching from lib.sh
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/example:state/op=42) ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/clixon-example:state/op=42)
expect='<op xmlns="urn:example:clixon">42</op>' expect='<op xmlns="urn:example:clixon">42</op>'
match=`echo $ret | grep -EZo "$expect"` match=`echo $ret | grep -EZo "$expect"`
if [ -z "$match" ]; then if [ -z "$match" ]; then
@ -190,12 +145,12 @@ if [ -z "$match" ]; then
fi fi
new2 "restconf get state operation eth0 type json" new2 "restconf get state operation eth0 type json"
expecteq "$(curl -s -G http://localhost/restconf/data/example:state/op=42)" '{"example:op": "42"} expecteq "$(curl -s -G http://localhost/restconf/data/clixon-example:state/op=42)" '{"clixon-example:op": "42"}
' '
new "restconf get state operation eth0 type xml" new "restconf get state operation eth0 type xml"
# Cant get shell macros to work, inline matching from lib.sh # Cant get shell macros to work, inline matching from lib.sh
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/example:state/op=42) ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/clixon-example:state/op=42)
expect='<op xmlns="urn:example:clixon">42</op>' expect='<op xmlns="urn:example:clixon">42</op>'
match=`echo $ret | grep -EZo "$expect"` match=`echo $ret | grep -EZo "$expect"`
if [ -z "$match" ]; then if [ -z "$match" ]; then
@ -203,7 +158,7 @@ if [ -z "$match" ]; then
fi fi
new2 "restconf GET datastore" new2 "restconf GET datastore"
expecteq "$(curl -s -X GET http://localhost/restconf/data/example:state)" '{"example:state": {"op": "42"}} expecteq "$(curl -s -X GET http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": "42"}}
' '
# Exact match # Exact match
@ -223,7 +178,7 @@ new "restconf delete interfaces"
expecteq $(curl -s -X DELETE http://localhost/restconf/data/ietf-interfaces:interfaces) "" expecteq $(curl -s -X DELETE http://localhost/restconf/data/ietf-interfaces:interfaces) ""
new "restconf Check empty config" new "restconf Check empty config"
expectfn "curl -sG http://localhost/restconf/data/example:state" 0 "$state" expectfn "curl -sG http://localhost/restconf/data/clixon-example:state" 0 "$state"
# XXX: gives <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"> # XXX: gives <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
# <interface xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"> # <interface xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
@ -237,7 +192,7 @@ expecteq "$(curl -s -G http://localhost/restconf/data/ietf-interfaces:interfaces
' '
new2 "restconf Check eth/0/0 added state" new2 "restconf Check eth/0/0 added state"
expecteq "$(curl -s -G http://localhost/restconf/data/example:state)" '{"example:state": {"op": "42"}} expecteq "$(curl -s -G http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": "42"}}
' '
new2 "restconf Re-post eth/0/0 which should generate error" new2 "restconf Re-post eth/0/0 which should generate error"
@ -270,52 +225,42 @@ expecteq "$(curl -s -G http://localhost/restconf/data/ietf-interfaces:interfaces
' '
new2 "restconf rpc using POST json" new2 "restconf rpc using POST json"
expecteq "$(curl -s -X POST -d '{"ietf-routing:input":{"routing-instance-name":"ipv4","destination-address":{"address-family":"ipv6"}}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-routing:output": {"route": {"address-family": "ipv4","next-hop": {"next-hop-list": "2.3.4.5"},"source-protocol": "static"}}} expecteq "$(curl -s -X POST -d '{"clixon-example:input":{"x":42}}' http://localhost/restconf/operations/clixon-example:example)" '{"clixon-example:output": {"x": "42","y": "42"}}
' '
# Cant get this to work due to quoting expecteq "$(curl -s -X POST -d '{"clixon-example:input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/clixon-example:example)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "wrongelement"},"error-severity": "error"}}} '
#new2 "restconf rpc using POST wrong JSON"
#expecteq "$(curl -s -X POST -d '{"ietf-routing:input":{"routing-instance-name":ipv4}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": " on line 1: syntax error at or before: i"}}} '
new2 "restconf rpc using POST json without mandatory element"
expecteq "$(curl -s -X POST -d '{"ietf-routing:input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "wrongelement"},"error-severity": "error"}}} '
new2 "restconf rpc non-existing rpc without namespace" new2 "restconf rpc non-existing rpc without namespace"
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/kalle)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "kalle"},"error-severity": "error","error-message": "RPC not defined"}}} ' expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/kalle)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "kalle"},"error-severity": "error","error-message": "RPC not defined"}}} '
new2 "restconf rpc non-existing rpc" new2 "restconf rpc non-existing rpc"
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/example:kalle)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "kalle"},"error-severity": "error","error-message": "RPC not defined"}}} ' expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/clixon-example:kalle)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "kalle"},"error-severity": "error","error-message": "RPC not defined"}}} '
new2 "restconf rpc missing name" new2 "restconf rpc missing name"
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "Operation name expected"}}} ' expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "Operation name expected"}}} '
new2 "restconf rpc missing input" new2 "restconf rpc missing input"
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "rpc","error-tag": "malformed-message","error-severity": "error","error-message": "restconf RPC does not have input statement"}}} ' expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/clixon-example:example)" '{"ietf-restconf:errors" : {"error": {"error-type": "rpc","error-tag": "malformed-message","error-severity": "error","error-message": "restconf RPC does not have input statement"}}} '
new "restconf rpc using POST xml" new "restconf rpc using POST xml"
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"ietf-routing:input":{"routing-instance-name":"ipv4","destination-address":{"address-family":"ipv4"}}}' http://localhost/restconf/operations/ietf-routing:fib-route) ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"clixon-example:input":{"x":42}}' http://localhost/restconf/operations/clixon-example:example)
expect='<output xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"><route><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop><source-protocol>static</source-protocol></route></output>' expect='<output xmlns="urn:example:clixon"><x>42</x><y>42</y></output>'
match=`echo $ret | grep -EZo "$expect"` match=`echo $ret | grep -EZo "$expect"`
if [ -z "$match" ]; then if [ -z "$match" ]; then
err "$expect" "$ret" err "$expect" "$ret"
fi fi
new2 "restconf rpc using wrong prefix" new2 "restconf rpc using wrong prefix"
expecteq "$(curl -s -X POST -d '{"wrong:input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/wrong:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "yang module not found"}}} ' expecteq "$(curl -s -X POST -d '{"wrong:input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/wrong:example)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "yang module not found"}}} '
new "restconf local client rpc using POST xml" new "restconf local client rpc using POST xml"
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"example:input":{"request":"example"}}' http://localhost/restconf/operations/example:client-rpc) ret=$(curl -s -i -X POST -H "Accept: application/yang-data+xml" -d '{"clixon-example:input":{"request":"example"}}' http://localhost/restconf/operations/clixon-example:client-rpc)
expect='<output xmlns="urn:example:clixon"><result>ok</result></output>' expect='<output xmlns="urn:example:clixon"><result>ok</result></output>'
match=`echo $ret | grep -EZo "$expect"` match=`echo $ret | grep -EZo "$expect"`
if [ -z "$match" ]; then if [ -z "$match" ]; then
err "$expect" "$ret" err "$expect" "$ret"
fi fi
# XXX cant get -H to work
#expecteq 'curl -s -X POST -H "Accept: application/yang-data+xml" -d {"ietf-routing:input":{"routing-instance-name":"ipv4"}} http://localhost/restconf/operations/ietf-routing:fib-route' '<output><route><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop></route></output>'
# Cant get shell macros to work, inline matching from lib.sh
new "Kill restconf daemon" new "Kill restconf daemon"
sudo pkill -u www-data -f "/www-data/clixon_restconf" sudo pkill -u www-data -f "/www-data/clixon_restconf"

View file

@ -13,6 +13,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/var</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/var</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY> <CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK> <CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>$dir/restconf.pidfile</CLICON_BACKEND_PIDFILE> <CLICON_BACKEND_PIDFILE>$dir/restconf.pidfile</CLICON_BACKEND_PIDFILE>
@ -43,6 +44,23 @@ module example{
type string; type string;
} }
} }
container types{
/* A couple of types to test quoting */
leaf tint {
type int32;
}
leaf tdec64 {
type decimal64{
fraction-digits 3;
}
}
leaf tbool {
type boolean;
}
leaf tstr {
type string;
}
}
} }
EOF EOF
@ -149,6 +167,13 @@ expectfn 'curl -s -X PUT -d {"interface":{"name":"TEST","type":"eth0"}} http://l
new "restconf PUT change key error" new "restconf PUT change key error"
expectfn 'curl -is -X PUT -d {"interface":{"name":"ALPHA","type":"eth0"}} http://localhost/restconf/data/example:cont1/interface=TEST' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "api-path keys do not match data keys"}}}' expectfn 'curl -is -X PUT -d {"interface":{"name":"ALPHA","type":"eth0"}} http://localhost/restconf/data/example:cont1/interface=TEST' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "api-path keys do not match data keys"}}}'
#--------------- json type tests
new "restconf POST type x3"
expectfn 'curl -s -X POST -d {"example:types":{"tint":42,"tdec64":42.123,"tbool":false,"tstr":"str"}} http://localhost/restconf/data' 0 ''
new "restconf POST type x3"
expectfn 'curl -s -X GET http://localhost/restconf/data/example:types' 0 '{"example:types": {"tint": 42,"tdec64": 42.123,"tbool": false,"tstr": "str"}}'
new "Kill restconf daemon" new "Kill restconf daemon"
sudo pkill -u www-data -f "/www-data/clixon_restconf" sudo pkill -u www-data -f "/www-data/clixon_restconf"

View file

@ -2,6 +2,9 @@
# RPC tests # RPC tests
# Validate parameters in restconf and netconf, check namespaces, etc # Validate parameters in restconf and netconf, check namespaces, etc
# See rfc8040 3.6 # See rfc8040 3.6
# Use the example application that has one mandatory input arg,
# At the end is an alternative Yang without mandatory arg for
# valid empty input and output.
APPNAME=example APPNAME=example
# include err() and new() functions and creates $dir # include err() and new() functions and creates $dir
@ -12,9 +15,9 @@ cfg=$dir/conf.xml
cat <<EOF > $cfg cat <<EOF > $cfg
<config xmlns="urn:example:clixon"> <config xmlns="urn:example:clixon">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>$APPNAME</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>clixon-example</CLICON_YANG_MODULE_MAIN>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR> <CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
@ -55,7 +58,7 @@ new "rpc tests"
# 1.First some positive tests vary media types # 1.First some positive tests vary media types
# extra complex because pattern matching on return haders # extra complex because pattern matching on return haders
new "restconf empty rpc" new "restconf empty rpc"
ret=$(curl -is -X POST http://localhost/restconf/operations/example:empty) ret=$(curl -is -X POST http://localhost/restconf/operations/clixon-example:empty)
expect="204 No Content" expect="204 No Content"
match=`echo $ret | grep -EZo "$expect"` match=`echo $ret | grep -EZo "$expect"`
if [ -z "$match" ]; then if [ -z "$match" ]; then
@ -66,28 +69,28 @@ new "netconf empty rpc"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><empty xmlns="urn:example:clixon"/></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><empty xmlns="urn:example:clixon"/></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><ok/></rpc-reply>]]>]]>$'
new2 "restconf example rpc json/json default - no http media headers" new2 "restconf example rpc json/json default - no http media headers"
expecteq "$(curl -s -X POST -d '{"example:input":{"x":0}}' http://localhost/restconf/operations/example:example)" '{"example:output": {"x": "0","y": "42"}} expecteq "$(curl -s -X POST -d '{"clixon-example:input":{"x":0}}' http://localhost/restconf/operations/clixon-example:example)" '{"clixon-example:output": {"x": "0","y": "42"}}
' '
new2 "restconf example rpc json/json change y default" new2 "restconf example rpc json/json change y default"
expecteq "$(curl -s -X POST -d '{"example:input":{"x":"0","y":"99"}}' http://localhost/restconf/operations/example:example)" '{"example:output": {"x": "0","y": "99"}} expecteq "$(curl -s -X POST -d '{"clixon-example:input":{"x":"0","y":"99"}}' http://localhost/restconf/operations/clixon-example:example)" '{"clixon-example:output": {"x": "0","y": "99"}}
' '
new2 "restconf example rpc json/json" new2 "restconf example rpc json/json"
# XXX example:input example:output # XXX example:input example:output
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+json' -H 'Content-Type: application/yang-data+json' -d '{"example:input":{"x":"0"}}' http://localhost/restconf/operations/example:example)" '{"example:output": {"x": "0","y": "42"}} expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+json' -H 'Content-Type: application/yang-data+json' -d '{"clixon-example:input":{"x":"0"}}' http://localhost/restconf/operations/clixon-example:example)" '{"clixon-example:output": {"x": "0","y": "42"}}
' '
new2 "restconf example rpc xml/json" new2 "restconf example rpc xml/json"
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+xml' -H 'Content-Type: application/yang-data+json' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' http://localhost/restconf/operations/example:example)" '{"example:output": {"x": "0","y": "42"}} expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+xml' -H 'Content-Type: application/yang-data+json' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' http://localhost/restconf/operations/clixon-example:example)" '{"clixon-example:output": {"x": "0","y": "42"}}
' '
new2 "restconf example rpc json/xml" new2 "restconf example rpc json/xml"
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '{"example:input":{"x":"0"}}' http://localhost/restconf/operations/example:example)" '<output xmlns="urn:example:clixon"><x>0</x><y>42</y></output> expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '{"clixon-example:input":{"x":"0"}}' http://localhost/restconf/operations/clixon-example:example)" '<output xmlns="urn:example:clixon"><x>0</x><y>42</y></output>
' '
new2 "restconf example rpc xml/xml" new2 "restconf example rpc xml/xml"
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+xml' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' http://localhost/restconf/operations/example:example)" '<output xmlns="urn:example:clixon"><x>0</x><y>42</y></output> expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+xml' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' http://localhost/restconf/operations/clixon-example:example)" '<output xmlns="urn:example:clixon"><x>0</x><y>42</y></output>
' '
new "netconf example rpc" new "netconf example rpc"
@ -95,29 +98,37 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netco
# 2. Then error cases # 2. Then error cases
# #
new "restconf empy rpc with null input" new "restconf empty rpc with null input"
ret=$(curl -is -X POST -d '{"example:input":null}' http://localhost/restconf/operations/example:empty) ret=$(curl -is -X POST -d '{"clixon-example:input":null}' http://localhost/restconf/operations/clixon-example:empty)
expect="204 No Content" expect="204 No Content"
match=`echo $ret | grep -EZo "$expect"` match=`echo $ret | grep -EZo "$expect"`
if [ -z "$match" ]; then if [ -z "$match" ]; then
err "$expect" "$ret" err "$expect" "$ret"
fi fi
new2 "restconf empy rpc with input x" new2 "restconf empty rpc with input x"
expecteq "$(curl -s -X POST -d '{"example:input":{"x":0}}' http://localhost/restconf/operations/example:empty)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "x"},"error-severity": "error"}}} ' expecteq "$(curl -s -X POST -d '{"clixon-example:input":{"x":0}}' http://localhost/restconf/operations/clixon-example:empty)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "x"},"error-severity": "error"}}} '
# cornercase: optional has yang input/output sections but test without body
new "restconf optional rpc with null input and output"
ret=$(curl -is -X POST -d '{"clixon-example:input":null}' http://localhost/restconf/operations/clixon-example:optional)
expect="204 No Content"
match=`echo $ret | grep -EZo "$expect"`
if [ -z "$match" ]; then
err "$expect" "$ret"
fi
new2 "restconf omit mandatory" new2 "restconf omit mandatory"
expecteq "$(curl -s -X POST -d '{"example:input":null}' http://localhost/restconf/operations/example:example)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "x"},"error-severity": "error","error-message": "Mandatory variable"}}} ' expecteq "$(curl -s -X POST -d '{"clixon-example:input":null}' http://localhost/restconf/operations/clixon-example:example)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "x"},"error-severity": "error","error-message": "Mandatory variable"}}} '
new2 "restconf add extra" new2 "restconf add extra"
expecteq "$(curl -s -X POST -d '{"example:input":{"x":"0","extra":"0"}}' http://localhost/restconf/operations/example:example)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "extra"},"error-severity": "error"}}} ' expecteq "$(curl -s -X POST -d '{"clixon-example:input":{"x":"0","extra":"0"}}' http://localhost/restconf/operations/clixon-example:example)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "extra"},"error-severity": "error"}}} '
new2 "restconf wrong method" new2 "restconf wrong method"
expecteq "$(curl -s -X POST -d '{"example:input":{"x":"0"}}' http://localhost/restconf/operations/example:wrong)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "wrong"},"error-severity": "error","error-message": "RPC not defined"}}} ' expecteq "$(curl -s -X POST -d '{"clixon-example:input":{"x":"0"}}' http://localhost/restconf/operations/clixon-example:wrong)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "wrong"},"error-severity": "error","error-message": "RPC not defined"}}} '
new2 "restconf example missing input" new2 "restconf example missing input"
expecteq "$(curl -s -X POST -d '{"example:input":null}' http://localhost/restconf/operations/ietf-netconf:edit-config)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "yang module not found"}}} ' expecteq "$(curl -s -X POST -d '{"clixon-example:input":null}' http://localhost/restconf/operations/ietf-netconf:edit-config)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "yang module not found"}}} '
new "netconf kill-session missing session-id mandatory" new "netconf kill-session missing session-id mandatory"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><kill-session/></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>missing-element</error-tag><error-info><bad-element>session-id</bad-element></error-info><error-severity>error</error-severity><error-message>Mandatory variable</error-message></rpc-error></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><kill-session/></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>missing-element</error-tag><error-info><bad-element>session-id</bad-element></error-info><error-severity>error</error-severity><error-message>Mandatory variable</error-message></rpc-error></rpc-reply>]]>]]>$'

View file

@ -13,9 +13,9 @@ cfg=$dir/conf_startup.xml
cat <<EOF > $cfg cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>clixon-example</CLICON_YANG_MODULE_MAIN>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR> <CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<CLICON_NETCONF_DIR>/usr/local/lib/$APPNAME/netconf</CLICON_NETCONF_DIR> <CLICON_NETCONF_DIR>/usr/local/lib/$APPNAME/netconf</CLICON_NETCONF_DIR>

View file

@ -39,6 +39,7 @@ cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY> <CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK> <CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR> <CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>

View file

@ -16,9 +16,8 @@ cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
@ -181,6 +180,16 @@ module example{
description "transitive type- exists in ex3"; description "transitive type- exists in ex3";
uses ex2:gr2; uses ex2:gr2;
} }
leaf digit4{
type string {
pattern '\d{4}';
}
}
leaf word4{
type string {
pattern '\w{4}';
}
}
} }
EOF EOF
@ -359,6 +368,31 @@ expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len2 ab" 255 "^$"
new "cli range test len3 42 ok" new "cli range test len3 42 ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len3 hsakjdhkjsahdkjsahdksahdksajdhsakjhd" 0 "^$" expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len3 hsakjdhkjsahdkjsahdksahdksajdhsakjhd" 0 "^$"
# XSD schema -> POSIX ECE translation
new "cli yang pattern \d ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set digit4 0123" 0 "^$"
new "cli yang pattern \d error"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set digit4 01b2" 255 "^$"
new "cli yang pattern \w ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set word4 a2-_" 0 "^$"
new "cli yang pattern \w error"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set word4 ab%d3" 255 "^$"
new "netconf pattern \w"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><word4 xmlns="urn:example:clixon">a-_9</word4></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf pattern \w valid"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf pattern \w error"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><word4 xmlns="urn:example:clixon">ab%d3</word4></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf pattern \w valid"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>word4</bad-element></error-info><error-severity>error</error-severity><error-message>regexp match fail: "ab%d3" does not match \\w{4}</error-message></rpc-error></rpc-reply>]]>]]>$'
if [ $BE -eq 0 ]; then if [ $BE -eq 0 ]; then
exit # BE exit # BE
fi fi

View file

@ -14,9 +14,8 @@ cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>

View file

@ -12,9 +12,8 @@ fyang=$dir/test.yang
cat <<EOF > $cfg cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>$APPNAME</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>

View file

@ -1,18 +1,22 @@
#!/bin/bash #!/bin/bash
# Test: XML parser tests # Test: XML parser tests and JSON translation
# @see https://www.w3.org/TR/2008/REC-xml-20081126 # @see https://www.w3.org/TR/2008/REC-xml-20081126
# https://www.w3.org/TR/2009/REC-xml-names-20091208 # https://www.w3.org/TR/2009/REC-xml-names-20091208
#PROG="valgrind --leak-check=full --show-leak-kinds=all ../util/clixon_util_xml" #PROG="valgrind --leak-check=full --show-leak-kinds=all ../util/clixon_util_xml"
PROG=../util/clixon_util_xml
# include err() and new() functions and creates $dir # include err() and new() functions and creates $dir
. ./lib.sh . ./lib.sh
PROG="../util/clixon_util_xml -D $DBG"
new "xml parse" new "xml parse"
expecteof "$PROG" 0 "<a><b/></a>" "^<a><b/></a>$" expecteof "$PROG" 0 "<a><b/></a>" "^<a><b/></a>$"
new "xml parse to json"
expecteof "$PROG -j" 0 "<a><b/></a>" '{"a": {"b": null}}'
new "xml parse strange names" new "xml parse strange names"
expecteof "$PROG" 0 "<_-><b0.><c-.-._/></b0.></_->" "^<_-><b0.><c-.-._/></b0.></_->$" expecteof "$PROG" 0 "<_-><b0.><c-.-._/></b0.></_->" "<_-><b0.><c-.-._/></b0.></_->"
new "xml parse name errors" new "xml parse name errors"
expecteof "$PROG" 255 "<-a/>" "" expecteof "$PROG" 255 "<-a/>" ""
@ -23,11 +27,24 @@ expecteof "$PROG" 255 "<9/>" ""
new "xml parse name errors" new "xml parse name errors"
expecteof "$PROG" 255 "<a%/>" "" expecteof "$PROG" 255 "<a%/>" ""
LF='
'
new "xml parse content with CR LF -> LF, CR->LF (see https://www.w3.org/TR/REC-xml/#sec-line-ends)"
ret=$(echo "<x>a b${LF}c ${LF}d</x>" | $PROG)
if [ "$ret" != "<x>a${LF}b${LF}c${LF}d</x>" ]; then
err '<x>a$LFb$LFc</x>' "$ret"
fi
new "xml simple CDATA"
expecteofx "$PROG" 0 '<a><![CDATA[a text]]></a>' '<a><![CDATA[a text]]></a>'
new "xml simple CDATA to json"
expecteofx "$PROG -j" 0 '<a><![CDATA[a text]]></a>' '{"a": "a text"}'
new "xml complex CDATA"
XML=$(cat <<EOF XML=$(cat <<EOF
<a><description>An example of escaped CENDs</description> <a><description>An example of escaped CENDs</description>
<sometext> <sometext><![CDATA[ They're saying "x < y" & that "z > y" so I guess that means that z > x ]]></sometext>
<![CDATA[ They're saying "x < y" & that "z > y" so I guess that means that z > x ]]>
</sometext>
<!-- This text contains a CEND ]]> --> <!-- This text contains a CEND ]]> -->
<!-- In this first case we put the ]] at the end of the first CDATA block <!-- In this first case we put the ]] at the end of the first CDATA block
and the > in the second CDATA block --> and the > in the second CDATA block -->
@ -38,33 +55,56 @@ XML=$(cat <<EOF
</a> </a>
EOF EOF
) )
new "xml CDATA"
expecteof "$PROG" 0 "$XML" "^<a><description>An example of escaped CENDs</description><sometext> expecteof "$PROG" 0 "$XML" "^<a><description>An example of escaped CENDs</description><sometext>
<![CDATA[ They're saying \"x < y\" & that \"z > y\" so I guess that means that z > x ]]> <![CDATA[ They're saying \"x < y\" & that \"z > y\" so I guess that means that z > x ]]>
</sometext><data><![CDATA[This text contains a CEND ]]]]><![CDATA[>]]></data><alternative><![CDATA[This text contains a CEND ]]]><![CDATA[]>]]></alternative></a>$" </sometext><data><![CDATA[This text contains a CEND ]]]]><![CDATA[>]]></data><alternative><![CDATA[This text contains a CEND ]]]><![CDATA[]>]]></alternative></a>$"
JSON=$(cat <<EOF
{"a": {"description": "An example of escaped CENDs","sometext": " They're saying \"x < y\" & that \"z > y\" so I guess that means that z > x ","data": "This text contains a CEND ]]>","alternative": "This text contains a CEND ]]>"}}
EOF
)
new "xml complex CDATA to json"
expecteofx "$PROG -j" 0 "$XML" "$JSON"
XML=$(cat <<EOF XML=$(cat <<EOF
<message>Less than: &lt; , greater than: &gt; ampersand: &amp; </message> <message>Less than: &lt; , greater than: &gt; ampersand: &amp; </message>
EOF EOF
) )
new "xml encode <>&" new "xml encode <>&"
expecteof "$PROG" 0 "$XML" "^$XML$" expecteof "$PROG" 0 "$XML" "$XML"
new "xml encode <>& to json"
expecteof "$PROG -j" 0 "$XML" '{"message": "Less than: < , greater than: > ampersand: & "}'
XML=$(cat <<EOF XML=$(cat <<EOF
<message>To allow attribute values to contain both single and double quotes, the apostrophe or single-quote character ' may be represented as &apos; and the double-quote character as &quot;</message> <message>single-quote character ' represented as &apos; and double-quote character as &quot;</message>
EOF EOF
) )
new "xml optional encode single and double quote" new "xml single and double quote"
expecteof "$PROG" 0 "$XML" "^<message>To allow attribute values to contain both single and double quotes, the apostrophe or single-quote character ' may be represented as ' and the double-quote character as \"</message>$" expecteof "$PROG" 0 "$XML" "<message>single-quote character ' represented as ' and double-quote character as \"</message>"
JSON=$(cat <<EOF
{"message": "single-quote character ' represented as ' and double-quote character as \""}
EOF
)
new "xml single and double quotes to json"
expecteofx "$PROG -j" 0 "$XML" "$JSON"
new "xml backspace"
expecteofx "$PROG" 0 "<a>a\b</a>" "<a>a\b</a>"
new "xml backspace to json"
expecteofx "$PROG -j" 0 "<a>a\b</a>" '{"a": "a\\b"}'
new "Double quotes for attributes" new "Double quotes for attributes"
expecteof "$PROG" 0 '<x a="t"/>' '^<x a="t"/>$' expecteof "$PROG" 0 '<x a="t"/>' '<x a="t"/>'
new "Single quotes for attributes (returns double quotes but at least parses right)" new "Single quotes for attributes (returns double quotes but at least parses right)"
expecteof "$PROG" 0 "<x a='t'/>" '^<x a="t"/>$' expecteof "$PROG" 0 "<x a='t'/>" '<x a="t"/>'
new "Mixed quotes" new "Mixed quotes"
expecteof "$PROG" 0 "<x a='t' b=\"q\"/>" '^<x a="t" b="q"/>$' expecteof "$PROG" 0 "<x a='t' b=\"q\"/>" '<x a="t" b="q"/>'
new "XMLdecl version" new "XMLdecl version"
expecteof "$PROG" 0 '<?xml version="1.0"?><a/>' '<a/>' expecteof "$PROG" 0 '<?xml version="1.0"?><a/>' '<a/>'
@ -79,7 +119,7 @@ new "XMLdecl no version"
expecteof "$PROG" 255 '<?xml ?><a/>' '' expecteof "$PROG" 255 '<?xml ?><a/>' ''
new "XMLdecl misspelled version" new "XMLdecl misspelled version"
expecteof "$PROG -l o" 255 '<?xml verion="1.0"?><a/>' 'yntax error: at or before: v' expecteof "$PROG -l o" 255 '<?xml verion="1.0"?><a/>' ''
new "XMLdecl version + encoding" new "XMLdecl version + encoding"
expecteof "$PROG" 0 '<?xml version="1.0" encoding="UTF-16"?><a/>' '<a/>' expecteof "$PROG" 0 '<?xml version="1.0" encoding="UTF-16"?><a/>' '<a/>'
@ -104,7 +144,7 @@ expecteof "$PROG" 0 '<?foo something ?><a/><?bar more stuff ?><!-- a comment-->'
#expecteof "$PROG" 255 '<a/><b/>' '' #expecteof "$PROG" 255 '<a/><b/>' ''
new "namespace: DefaultAttName" new "namespace: DefaultAttName"
expecteof "$PROG" 0 '<x xmlns="n1">hello</x>' '^<x xmlns="n1">hello</x>$' expecteof "$PROG" 0 '<x xmlns="n1">hello</x>' '<x xmlns="n1">hello</x>'
new "namespace: PrefixedAttName" new "namespace: PrefixedAttName"
expecteof "$PROG" 0 '<x xmlns:n2="urn:example:des"><n2:y>hello</n2:y></x>' '^<x xmlns:n2="urn:example:des"><n2:y>hello</n2:y></x>$' expecteof "$PROG" 0 '<x xmlns:n2="urn:example:des"><n2:y>hello</n2:y></x>' '^<x xmlns:n2="urn:example:des"><n2:y>hello</n2:y></x>$'

View file

@ -9,13 +9,12 @@ fyang=$dir/$APPNAME.yang
fsubmod=$dir/example-types.yang fsubmod=$dir/example-types.yang
fyangerr=$dir/err.yang fyangerr=$dir/err.yang
# <CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
cat <<EOF > $cfg cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>$APPNAME</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>

View file

@ -13,11 +13,9 @@ fyang1=$dir/$APPNAME@2018-12-02.yang
fyang2=$dir/$APPNAME@2018-01-01.yang fyang2=$dir/$APPNAME@2018-01-01.yang
fyang3=$dir/other.yang fyang3=$dir/other.yang
# <CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
# 1st variant of the example module # 1st variant of the example module
cat <<EOF > $fyang1 cat <<EOF > $fyang1
module $APPNAME{ module example{
prefix ex; prefix ex;
revision 2018-12-02; revision 2018-12-02;
namespace "urn:example:clixon"; namespace "urn:example:clixon";
@ -29,7 +27,7 @@ EOF
# 2nd variant of the same example module # 2nd variant of the same example module
cat <<EOF > $fyang2 cat <<EOF > $fyang2
module $APPNAME{ module example{
prefix ex; prefix ex;
revision 2018-01-01; revision 2018-01-01;
namespace "urn:example:clixon"; namespace "urn:example:clixon";
@ -58,6 +56,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang1</CLICON_YANG_MAIN_FILE> <CLICON_YANG_MAIN_FILE>$fyang1</CLICON_YANG_MAIN_FILE>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK> <CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE> <CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
@ -117,6 +116,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang2</CLICON_YANG_MAIN_FILE> <CLICON_YANG_MAIN_FILE>$fyang2</CLICON_YANG_MAIN_FILE>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK> <CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE> <CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
@ -165,6 +165,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK> <CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE> <CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
@ -209,6 +210,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
<CLICON_YANG_MODULE_REVISION>2018-01-01</CLICON_YANG_MODULE_REVISION> <CLICON_YANG_MODULE_REVISION>2018-01-01</CLICON_YANG_MODULE_REVISION>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK> <CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
@ -254,6 +256,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR> <CLICON_YANG_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK> <CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE> <CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
@ -298,6 +301,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR> <CLICON_YANG_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR>
<CLICON_YANG_MAIN_FILE>$fyang2</CLICON_YANG_MAIN_FILE> <CLICON_YANG_MAIN_FILE>$fyang2</CLICON_YANG_MAIN_FILE>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK> <CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
@ -344,6 +348,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR> <CLICON_YANG_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
<CLICON_YANG_MODULE_REVISION>2018-01-01</CLICON_YANG_MODULE_REVISION> <CLICON_YANG_MODULE_REVISION>2018-01-01</CLICON_YANG_MODULE_REVISION>
@ -390,6 +395,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang2</CLICON_YANG_MAIN_FILE> <CLICON_YANG_MAIN_FILE>$fyang2</CLICON_YANG_MAIN_FILE>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
<CLICON_YANG_MODULE_REVISION>2018-12-02</CLICON_YANG_MODULE_REVISION> <CLICON_YANG_MODULE_REVISION>2018-12-02</CLICON_YANG_MODULE_REVISION>

View file

@ -12,13 +12,12 @@ cfg=$dir/conf_yang.xml
fyang1=$dir/example1.yang fyang1=$dir/example1.yang
fyang2=$dir/example2.yang fyang2=$dir/example2.yang
# <CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
cat <<EOF > $cfg cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR> <CLICON_YANG_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
@ -39,10 +38,6 @@ module example1{
yang-version 1.1; yang-version 1.1;
prefix ex1; prefix ex1;
namespace "urn:example:clixon1"; namespace "urn:example:clixon1";
import ietf-routing {
description "defines fib-route";
prefix rt;
}
leaf x{ leaf x{
type int32; type int32;
} }

View file

@ -1,11 +0,0 @@
#!/bin/bash
# Test: YANG parser tests
#PROG="valgrind --leak-check=full --show-leak-kinds=all ../util/clixon_util_yang"
PROG=../util/clixon_util_yang
# include err() and new() functions and creates $dir
. ./lib.sh
rm -rf $dir

View file

@ -20,6 +20,7 @@
APPNAME=example APPNAME=example
# include err() and new() functions and creates $dir # include err() and new() functions and creates $dir
. ./site.sh
. ./lib.sh . ./lib.sh
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
@ -52,7 +53,7 @@ EOF
new "yangmodels parse: -f $cfg" new "yangmodels parse: -f $cfg"
new "yangmodel Experimental IEEE 802.1: $YANGMODELS/experimental/ieee/802.1" new "yangmodel Experimental IEEE 802.1: $YANGMODELS/experimental/ieee/802.1"
expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/experimental/ieee/802.1 -o CLICON_YANG_DIR=$YANGMODELS/experimental/ieee/1588 show version" 0 "3." expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/experimental/ieee/802.1 -p $YANGMODELS/experimental/ieee/1588 show version" 0 "3."
# experimental 802.3 dir is empty # experimental 802.3 dir is empty
#new "yangmodel Experimental IEEE 802.3: $YANGMODELS/experimental/ieee/802.3" #new "yangmodel Experimental IEEE 802.3: $YANGMODELS/experimental/ieee/802.3"
@ -85,7 +86,24 @@ expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/vendo
new "yangmodel vendor cisco xr 651: $YANGMODELS/vendor/cisco/xr/651" new "yangmodel vendor cisco xr 651: $YANGMODELS/vendor/cisco/xr/651"
expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/vendor/cisco/xr/651 show version" 0 "3." expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/vendor/cisco/xr/651 show version" 0 "3."
fi fi ### cisco
# vendor/junos
#junos : M/MX, T/TX, Some EX platforms, ACX
#junos-es : SRX, Jseries, LN-*
#junos-ex : EX series
#junos-qfx : QFX series
#junos-nfx : NFX series
new "yangmodel vendor junos: $YANGMODELS/vendor/juniper/18.2/18.2R1/junos/conf/"
expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_FILE=$YANGMODELS/vendor/juniper/18.2/18.2R1/junos/conf/junos-conf-interfaces@2018-01-01.yang -p $YANGMODELS/vendor/juniper/18.2/18.2R1/junos/conf -p $YANGMODELS/vendor/juniper/18.2/18.2R1/common show version" 0 "3."
# breaks memory and cpu limits,...
#new "yangmodel vendor junos: $YANGMODELS/vendor/juniper/18.2/18.2R1/junos/conf"
#expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/vendor/juniper/18.2/18.2R1/junos/conf -p $YANGMODELS/vendor/juniper/18.2/18.2R1/common show version" 0 "3."
#new "yangmodel vendor junos: $YANGMODELS/vendor/juniper/18.2/18.2R1/junos/rpc"
#expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/vendor/juniper/18.2/18.2R1/junos/rpc -p $YANGMODELS/vendor/juniper/18.2/18.2R1/common show version" 0 "3."
rm -rf $dir rm -rf $dir

View file

@ -70,7 +70,13 @@
static int static int
usage(char *argv0) usage(char *argv0)
{ {
fprintf(stderr, "usage:%s.\n\tInput on stdin\n", argv0); fprintf(stderr, "usage:%s [options]\n"
"where options are\n"
"\t-h \t\tHelp\n"
"\t-D <level> \tDebug\n"
"\t-j \t\tOutput as JSON\n"
"\t-l <s|e|o> \tLog on (s)yslog, std(e)rr, std(o)ut (stderr is default)\n",
argv0);
exit(0); exit(0);
} }
@ -78,25 +84,52 @@ int
main(int argc, main(int argc,
char **argv) char **argv)
{ {
int retval = -1;
cxobj *xt = NULL; cxobj *xt = NULL;
cxobj *xc; cxobj *xc;
cbuf *cb = cbuf_new(); cbuf *cb = cbuf_new();
int c;
int logdst = CLICON_LOG_STDERR;
int json = 0;
if (argc != 1){ optind = 1;
opterr = 0;
while ((c = getopt(argc, argv, "hD:jl:")) != -1)
switch (c) {
case 'h':
usage(argv[0]); usage(argv[0]);
return 0; break;
case 'D':
if (sscanf(optarg, "%d", &debug) != 1)
usage(argv[0]);
break;
case 'j':
json++;
break;
case 'l': /* Log destination: s|e|o|f */
if ((logdst = clicon_log_opt(optarg[0])) < 0)
usage(argv[0]);
break;
default:
usage(argv[0]);
break;
} }
clicon_log_init(__FILE__, LOG_INFO, CLICON_LOG_STDERR); clicon_log_init(__FILE__, debug?LOG_DEBUG:LOG_INFO, logdst);
if (json_parse_file(0, NULL, &xt) < 0) if (json_parse_file(0, NULL, &xt) < 0)
goto done; goto done;
xc = NULL; xc = NULL;
while ((xc = xml_child_each(xt, xc, -1)) != NULL) while ((xc = xml_child_each(xt, xc, -1)) != NULL)
if (json)
xml2json_cbuf(cb, xc, 0); /* print xml */
else
clicon_xml2cbuf(cb, xc, 0, 0); /* print xml */ clicon_xml2cbuf(cb, xc, 0, 0); /* print xml */
fprintf(stdout, "%s", cbuf_get(cb)); fprintf(stdout, "%s", cbuf_get(cb));
fflush(stdout);
retval = 0;
done: done:
if (xt) if (xt)
xml_free(xt); xml_free(xt);
if (cb) if (cb)
cbuf_free(cb); cbuf_free(cb);
return 0; return retval;
} }

View file

@ -72,6 +72,7 @@ usage(char *argv0)
"where options are\n" "where options are\n"
"\t-h \t\tHelp\n" "\t-h \t\tHelp\n"
"\t-D <level> \tDebug\n" "\t-D <level> \tDebug\n"
"\t-j \t\tOutput as JSON\n"
"\t-l <s|e|o> \tLog on (s)yslog, std(e)rr, std(o)ut (stderr is default)\n", "\t-l <s|e|o> \tLog on (s)yslog, std(e)rr, std(o)ut (stderr is default)\n",
argv0); argv0);
exit(0); exit(0);
@ -81,16 +82,17 @@ int
main(int argc, main(int argc,
char **argv) char **argv)
{ {
int retval = -1;
cxobj *xt = NULL; cxobj *xt = NULL;
cxobj *xc; cxobj *xc;
cbuf *cb = cbuf_new(); cbuf *cb = cbuf_new();
int retval = -1;
int c; int c;
int logdst = CLICON_LOG_STDERR; int logdst = CLICON_LOG_STDERR;
int json = 0;
optind = 1; optind = 1;
opterr = 0; opterr = 0;
while ((c = getopt(argc, argv, "hD:l:")) != -1) while ((c = getopt(argc, argv, "hD:jl:")) != -1)
switch (c) { switch (c) {
case 'h': case 'h':
usage(argv[0]); usage(argv[0]);
@ -99,6 +101,9 @@ main(int argc,
if (sscanf(optarg, "%d", &debug) != 1) if (sscanf(optarg, "%d", &debug) != 1)
usage(argv[0]); usage(argv[0]);
break; break;
case 'j':
json++;
break;
case 'l': /* Log destination: s|e|o|f */ case 'l': /* Log destination: s|e|o|f */
if ((logdst = clicon_log_opt(optarg[0])) < 0) if ((logdst = clicon_log_opt(optarg[0])) < 0)
usage(argv[0]); usage(argv[0]);
@ -107,13 +112,16 @@ main(int argc,
usage(argv[0]); usage(argv[0]);
break; break;
} }
clicon_log_init("clixon_util_xml", debug?LOG_DEBUG:LOG_INFO, logdst); clicon_log_init(__FILE__, debug?LOG_DEBUG:LOG_INFO, logdst);
if (xml_parse_file(0, "</config>", NULL, &xt) < 0){ if (xml_parse_file(0, "</config>", NULL, &xt) < 0){
fprintf(stderr, "xml parse error %s\n", clicon_err_reason); fprintf(stderr, "xml parse error %s\n", clicon_err_reason);
goto done; goto done;
} }
xc = NULL; xc = NULL;
while ((xc = xml_child_each(xt, xc, -1)) != NULL) while ((xc = xml_child_each(xt, xc, -1)) != NULL)
if (json)
xml2json_cbuf(cb, xc, 0); /* print xml */
else
clicon_xml2cbuf(cb, xc, 0, 0); /* print xml */ clicon_xml2cbuf(cb, xc, 0, 0); /* print xml */
fprintf(stdout, "%s", cbuf_get(cb)); fprintf(stdout, "%s", cbuf_get(cb));
fflush(stdout); fflush(stdout);

View file

@ -37,40 +37,48 @@ prefix = @prefix@
bindir = @bindir@ bindir = @bindir@
includedir = @includedir@ includedir = @includedir@
datarootdir = @datarootdir@ datarootdir = @datarootdir@
enable_stdyangs = @enable_stdyangs@
CLIXON_DATADIR = @CLIXON_DATADIR@ CLIXON_DATADIR = @CLIXON_DATADIR@
YANGSPECS = clixon-config@2018-10-21.yang SUBDIRS = clixon
YANGSPECS += clixon-lib@2019-01-02.yang # See configure.ac
YANGSPECS += ietf-netconf@2011-06-01.yang ifeq ($(enable_stdyangs),yes)
YANGSPECS += ietf-netconf-acm@2018-02-14.yang SUBDIRS += standard
YANGSPECS += ietf-inet-types@2013-07-15.yang endif
YANGSPECS += ietf-yang-types@2013-07-15.yang
YANGSPECS += ietf-restconf@2017-01-26.yang
YANGSPECS += ietf-restconf-monitoring@2017-01-26.yang
YANGSPECS += clixon-rfc5277@2008-07-01.yang
YANGSPECS += ietf-yang-library@2016-06-21.yang
APPNAME = clixon # subdir ehere these files are installed .PHONY: all clean depend install $(SUBDIRS)
all: all: $(SUBDIRS)
depend:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
$(SUBDIRS):
(cd $@; $(MAKE) $(MFLAGS) all)
install-include:
for i in $(SUBDIRS); \
do (cd $$i && $(MAKE) $(MFLAGS) $@||exit 1); done;
install:
for i in $(SUBDIRS); \
do (cd $$i && $(MAKE) $(MFLAGS) $@)||exit 1; done
uninstall:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@)||exit 1; done
clean: clean:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
distclean: clean distclean: clean
rm -f Makefile *~ .depend rm -f Makefile *~ .depend
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
install: $(YANGSPECS) TAGS:
install -d -m 0755 $(DESTDIR)$(CLIXON_DATADIR) find $(srcdir) -name '*.[chyl]' -print | etags -
install -m 0644 $(YANGSPECS) $(DESTDIR)$(CLIXON_DATADIR)
uninstall:
(cd $(DESTDIR)$(CLIXON_DATADIR); rm -rf *.yang)
install-include:
depend:
#include .depend

View file

@ -1,220 +0,0 @@
module clixon-config {
prefix cc;
organization
"Clicon / Clixon";
contact
"Olof Hagsand <olof@hagsand.se>";
description
"Clixon configuration file
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2017 Olof Hagsand and Benny Holmgren
This file is part of CLIXON
Licensed under the Apache License, Version 2.0 (the \"License\");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an \"AS IS\" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 3 or later (the \"GPL\"),
in which case the provisions of the GPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of the GPL, and not to allow others to
use your version of this file under the terms of Apache License version 2,
indicate your decision by deleting the provisions above and replace them with
the notice and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****";
revision 2017-07-02 {
description
"Added startup config";
}
typedef startup_mode{
description "Which method to boot/start clicon backend.
The methods differ in how they reach a running state
Which source database to commit from, if any.";
type enumeration{
enum none{
description "Do not touch running state
Typically after crash when running state and db are synched";
}
enum init{
description "Initialize running state.
Start with a completely clean running state";
}
enum running{
description "Commit running db configuration into running state
After reboot if a persistent running db exists";
}
enum startup{
description "Commit startup configuration into running state
After reboot when no persistent running db exists";
}
}
}
container config {
leaf CLICON_CONFIGFILE{
type string;
description "Location of configuration-file for default values (this file)";
}
leaf CLICON_YANG_DIR {
type string;
mandatory true;
description "Location of YANG module and submodule files. Only if CLICON_DBSPEC_TYPE is YANG";
}
leaf CLICON_YANG_MODULE_MAIN {
type string;
default "clicon";
description "Option used to construct initial yang file:
<module>[@<revision>]
This option is only relevant if CLICON_DBSPEC_TYPE is YANG";
}
leaf CLICON_YANG_MODULE_REVISION {
type string;
description "Option used to construct initial yang file:
<module>[@<revision>]";
}
leaf CLICON_BACKEND_DIR {
type string;
description "Location of backend .so plugins. Load all .so
plugins in this dir as backend plugins";
}
leaf CLICON_NETCONF_DIR {
type string;
description "Location of netconf (frontend) .so plugins";
}
leaf CLICON_RESTCONF_DIR {
type string;
description "Location of restconf (frontend) .so plugins. Load all .so
plugins in this dir as restconf code plugins";
}
leaf CLICON_RESTCONF_PATH {
type string;
default "/www-data/fastcgi_restconf.sock";
description "FastCGI unix socket. Should be specified in webserver
Eg in nginx: fastcgi_pass unix:/www-data/clicon_restconf.sock";
}
leaf CLICON_CLI_DIR {
type string;
description "Location of cli frontend .so plugins. Load all .so
plugins in this dir as CLI object plugins";
}
leaf CLICON_CLISPEC_DIR {
type string;
description "Location of frontend .cli cligen spec files. Load all .cli
files in this dir as CLI specification files";
}
leaf CLICON_CLISPEC_FILE {
type string;
description "Specific frontend .cli cligen spec file.";
}
leaf CLICON_CLI_MODE {
type string;
default "base";
description "Startup CLI mode. This should match a CLICON_MODE set in
one of the clispec files";
}
leaf CLICON_CLI_GENMODEL {
type int32;
default 1;
description "Generate code for CLI completion of existing db symbols.
Example: Add name=\"myspec\" in datamodel spec and reference
as @myspec";
}
leaf CLICON_CLI_GENMODEL_COMPLETION {
type int32;
default 1;
description "Generate code for CLI completion of existing db symbols";
}
leaf CLICON_CLI_GENMODEL_TYPE {
type string;
default "VARS";
description "How to generate and show CLI syntax: VARS|ALL";
}
leaf CLICON_CLI_VARONLY {
type int32;
default 1;
description "Dont include keys in cvec in cli vars callbacks, ie a & k in 'a <b> k <c>' ignored";
}
leaf CLICON_CLI_LINESCROLLING {
type int32;
default 1;
description "Set to 0 if you want CLI to wrap to next line.
Set to 1 if you want CLI to scroll sideways when approaching right margin";
}
leaf CLICON_SOCK_FAMILY {
type string;
default "UNIX";
description "Address family for communicating with clixon_backend (UNIX|IPv4|IPv6)";
}
leaf CLICON_SOCK {
type string;
mandatory true;
description "If family above is AF_UNIX: Unix socket for communicating
with clixon_backend. If family is AF_INET: IPv4 address";
}
leaf CLICON_SOCK_PORT {
type int32;
default 4535;
description "Inet socket port for communicating with clixon_backend (only IPv4|IPv6)";
}
leaf CLICON_SOCK_GROUP {
type string;
default "clicon";
description "Group membership to access clixon_backend unix socket";
}
leaf CLICON_BACKEND_PIDFILE {
type string;
mandatory true;
description "Process-id file";
}
leaf CLICON_AUTOCOMMIT {
type int32;
default 0;
description "Set if all configuration changes are committed directly,
commit command unnecessary";
}
leaf CLICON_MASTER_PLUGIN {
type string;
default "master";
description "Name of master plugin (both frontend and backend).
Master plugin has special callbacks for frontends.
See clicon user manual for more info. (Obsolete)";
}
leaf CLICON_XMLDB_DIR {
type string;
mandatory true;
description "Directory where \"running\", \"candidate\" and \"startup\" are placed";
}
leaf CLICON_USE_STARTUP_CONFIG {
type int32;
default 0;
description "Enabled uses \"startup\" configuration on boot. It is called
startup_db and exists in XMLDB_DIR. NOTE: Obsolete with CLICON_STARTUP_MODE";
}
leaf CLICON_XMLDB_PLUGIN {
type string;
mandatory true;
description "XMLDB datastore plugin filename (see datastore/ and clixon_xml_db.[ch])";
}
leaf CLICON_STARTUP_MODE {
type startup_mode;
description "Which method to boot/start clicon backend";
}
}
}

View file

@ -1,256 +0,0 @@
module clixon-config {
prefix cc;
organization
"Clicon / Clixon";
contact
"Olof Hagsand <olof@hagsand.se>";
description
"Clixon configuration file
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2017 Olof Hagsand and Benny Holmgren
This file is part of CLIXON
Licensed under the Apache License, Version 2.0 (the \"License\");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an \"AS IS\" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 3 or later (the \"GPL\"),
in which case the provisions of the GPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of the GPL, and not to allow others to
use your version of this file under the terms of Apache License version 2,
indicate your decision by deleting the provisions above and replace them with
the notice and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****";
revision 2017-12-03 {
description
"Added startup config for Clixon 1.3.3 and xmldb_cache in 1.4.0";
}
typedef startup_mode{
description
"Which method to boot/start clicon backend.
The methods differ in how they reach a running state
Which source database to commit from, if any.";
type enumeration{
enum none{
description
"Do not touch running state
Typically after crash when running state and db are synched";
}
enum init{
description
"Initialize running state.
Start with a completely clean running state";
}
enum running{
description
"Commit running db configuration into running state
After reboot if a persistent running db exists";
}
enum startup{
description
"Commit startup configuration into running state
After reboot when no persistent running db exists";
}
}
}
container config {
leaf CLICON_CONFIGFILE{
type string;
description
"Location of configuration-file for default values (this file)";
}
leaf CLICON_YANG_DIR {
type string;
mandatory true;
description
"Location of YANG module and submodule files.";
}
leaf CLICON_YANG_MODULE_MAIN {
type string;
default "clicon";
description
"Option used to construct initial yang file:
<module>[@<revision>]";
}
leaf CLICON_YANG_MODULE_REVISION {
type string;
description
"Option used to construct initial yang file:
<module>[@<revision>]";
}
leaf CLICON_BACKEND_DIR {
type string;
description
"Location of backend .so plugins. Load all .so
plugins in this dir as backend plugins";
}
leaf CLICON_NETCONF_DIR {
type string;
description "Location of netconf (frontend) .so plugins";
}
leaf CLICON_RESTCONF_DIR {
type string;
description
"Location of restconf (frontend) .so plugins. Load all .so
plugins in this dir as restconf code plugins";
}
leaf CLICON_RESTCONF_PATH {
type string;
default "/www-data/fastcgi_restconf.sock";
description
"FastCGI unix socket. Should be specified in webserver
Eg in nginx: fastcgi_pass unix:/www-data/clicon_restconf.sock";
}
leaf CLICON_CLI_DIR {
type string;
description
"Location of cli frontend .so plugins. Load all .so
plugins in this dir as CLI object plugins";
}
leaf CLICON_CLISPEC_DIR {
type string;
description
"Location of frontend .cli cligen spec files. Load all .cli
files in this dir as CLI specification files";
}
leaf CLICON_CLISPEC_FILE {
type string;
description "Specific frontend .cli cligen spec file.";
}
leaf CLICON_CLI_MODE {
type string;
default "base";
description
"Startup CLI mode. This should match a CLICON_MODE set in
one of the clispec files";
}
leaf CLICON_CLI_GENMODEL {
type int32;
default 1;
description
"Generate code for CLI completion of existing db symbols.
Example: Add name=\"myspec\" in datamodel spec and reference
as @myspec";
}
leaf CLICON_CLI_GENMODEL_COMPLETION {
type int32;
default 1;
description "Generate code for CLI completion of existing db symbols";
}
leaf CLICON_CLI_GENMODEL_TYPE {
type string;
default "VARS";
description "How to generate and show CLI syntax: VARS|ALL";
}
leaf CLICON_CLI_VARONLY {
type int32;
default 1;
description
"Dont include keys in cvec in cli vars callbacks,
ie a & k in 'a <b> k <c>' ignored";
}
leaf CLICON_CLI_LINESCROLLING {
type int32;
default 1;
description
"Set to 0 if you want CLI to wrap to next line.
Set to 1 if you want CLI to scroll sideways when approaching
right margin";
}
leaf CLICON_SOCK_FAMILY {
type string;
default "UNIX";
description
"Address family for communicating with clixon_backend
(UNIX|IPv4|IPv6)";
}
leaf CLICON_SOCK {
type string;
mandatory true;
description
"If family above is AF_UNIX: Unix socket for communicating
with clixon_backend. If family is AF_INET: IPv4 address";
}
leaf CLICON_SOCK_PORT {
type int32;
default 4535;
description
"Inet socket port for communicating with clixon_backend
(only IPv4|IPv6)";
}
leaf CLICON_SOCK_GROUP {
type string;
default "clicon";
description "Group membership to access clixon_backend unix socket";
}
leaf CLICON_BACKEND_PIDFILE {
type string;
mandatory true;
description "Process-id file of backend daemon";
}
leaf CLICON_AUTOCOMMIT {
type int32;
default 0;
description
"Set if all configuration changes are committed automatically
on every edit change. Explicit commit commands unnecessary";
}
leaf CLICON_MASTER_PLUGIN {
type string;
default "master";
description
"Name of master plugin (both frontend and backend).
Master plugin has special callbacks for frontends.
See clicon user manual for more info. (Obsolete?)";
}
leaf CLICON_XMLDB_DIR {
type string;
mandatory true;
description
"Directory where \"running\", \"candidate\" and \"startup\" are placed";
}
leaf CLICON_XMLDB_PLUGIN {
type string;
mandatory true;
description
"XMLDB datastore plugin filename
(see datastore/ and clixon_xml_db.[ch])";
}
leaf CLICON_XMLDB_CACHE {
type boolean;
default true;
description
"XMLDB datastore cache.
If set, XML parsed tree is stored in memory";
}
leaf CLICON_USE_STARTUP_CONFIG {
type int32;
default 0;
description
"Enabled uses \"startup\" configuration on boot. It is called
startup_db and exists in XMLDB_DIR.
NOTE: Obsolete with 1.3.3 and CLICON_STARTUP_MODE";
}
leaf CLICON_STARTUP_MODE {
type startup_mode;
description "Which method to boot/start clicon backend";
}
}
}

View file

@ -1,291 +0,0 @@
module clixon-config {
prefix cc;
organization
"Clicon / Clixon";
contact
"Olof Hagsand <olof@hagsand.se>";
description
"Clixon configuration file
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2017 Olof Hagsand and Benny Holmgren
This file is part of CLIXON
Licensed under the Apache License, Version 2.0 (the \"License\");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an \"AS IS\" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 3 or later (the \"GPL\"),
in which case the provisions of the GPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of the GPL, and not to allow others to
use your version of this file under the terms of Apache License version 2,
indicate your decision by deleting the provisions above and replace them with
the notice and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****";
revision 2017-12-27 {
description
"Added xml sort option for 1.4.0";
}
typedef startup_mode{
description
"Which method to boot/start clicon backend.
The methods differ in how they reach a running state
Which source database to commit from, if any.";
type enumeration{
enum none{
description
"Do not touch running state
Typically after crash when running state and db are synched";
}
enum init{
description
"Initialize running state.
Start with a completely clean running state";
}
enum running{
description
"Commit running db configuration into running state
After reboot if a persistent running db exists";
}
enum startup{
description
"Commit startup configuration into running state
After reboot when no persistent running db exists";
}
}
}
typedef xmldb_format{
description
"Format of TEXT xml database format.";
type enumeration{
enum xml{
description "Save and load xmldb as XML";
}
enum json{
description "Save and load xmldb as JSON";
}
}
}
container config {
leaf CLICON_CONFIGFILE{
type string;
description
"Location of configuration-file for default values (this file)";
}
leaf CLICON_YANG_DIR {
type string;
mandatory true;
description
"Location of YANG module and submodule files.";
}
leaf CLICON_YANG_MODULE_MAIN {
type string;
default "clicon";
description
"Option used to construct initial yang file:
<module>[@<revision>]";
}
leaf CLICON_YANG_MODULE_REVISION {
type string;
description
"Option used to construct initial yang file:
<module>[@<revision>]";
}
leaf CLICON_BACKEND_DIR {
type string;
description
"Location of backend .so plugins. Load all .so
plugins in this dir as backend plugins";
}
leaf CLICON_NETCONF_DIR {
type string;
description "Location of netconf (frontend) .so plugins";
}
leaf CLICON_RESTCONF_DIR {
type string;
description
"Location of restconf (frontend) .so plugins. Load all .so
plugins in this dir as restconf code plugins";
}
leaf CLICON_RESTCONF_PATH {
type string;
default "/www-data/fastcgi_restconf.sock";
description
"FastCGI unix socket. Should be specified in webserver
Eg in nginx: fastcgi_pass unix:/www-data/clicon_restconf.sock";
}
leaf CLICON_CLI_DIR {
type string;
description
"Location of cli frontend .so plugins. Load all .so
plugins in this dir as CLI object plugins";
}
leaf CLICON_CLISPEC_DIR {
type string;
description
"Location of frontend .cli cligen spec files. Load all .cli
files in this dir as CLI specification files";
}
leaf CLICON_CLISPEC_FILE {
type string;
description "Specific frontend .cli cligen spec file.";
}
leaf CLICON_CLI_MODE {
type string;
default "base";
description
"Startup CLI mode. This should match a CLICON_MODE set in
one of the clispec files";
}
leaf CLICON_CLI_GENMODEL {
type int32;
default 1;
description
"Generate code for CLI completion of existing db symbols.
Example: Add name=\"myspec\" in datamodel spec and reference
as @myspec";
}
leaf CLICON_CLI_GENMODEL_COMPLETION {
type int32;
default 1;
description "Generate code for CLI completion of existing db symbols";
}
leaf CLICON_CLI_GENMODEL_TYPE {
type string;
default "VARS";
description "How to generate and show CLI syntax: VARS|ALL";
}
leaf CLICON_CLI_VARONLY {
type int32;
default 1;
description
"Dont include keys in cvec in cli vars callbacks,
ie a & k in 'a <b> k <c>' ignored";
}
leaf CLICON_CLI_LINESCROLLING {
type int32;
default 1;
description
"Set to 0 if you want CLI to wrap to next line.
Set to 1 if you want CLI to scroll sideways when approaching
right margin";
}
leaf CLICON_SOCK_FAMILY {
type string;
default "UNIX";
description
"Address family for communicating with clixon_backend
(UNIX|IPv4|IPv6)";
}
leaf CLICON_SOCK {
type string;
mandatory true;
description
"If family above is AF_UNIX: Unix socket for communicating
with clixon_backend. If family is AF_INET: IPv4 address";
}
leaf CLICON_SOCK_PORT {
type int32;
default 4535;
description
"Inet socket port for communicating with clixon_backend
(only IPv4|IPv6)";
}
leaf CLICON_SOCK_GROUP {
type string;
default "clicon";
description "Group membership to access clixon_backend unix socket";
}
leaf CLICON_BACKEND_PIDFILE {
type string;
mandatory true;
description "Process-id file of backend daemon";
}
leaf CLICON_AUTOCOMMIT {
type int32;
default 0;
description
"Set if all configuration changes are committed automatically
on every edit change. Explicit commit commands unnecessary";
}
leaf CLICON_MASTER_PLUGIN {
type string;
default "master";
description
"Name of master plugin (both frontend and backend).
Master plugin has special callbacks for frontends.
See clicon user manual for more info. (Obsolete?)";
}
leaf CLICON_XMLDB_DIR {
type string;
mandatory true;
description
"Directory where \"running\", \"candidate\" and \"startup\" are placed";
}
leaf CLICON_XMLDB_PLUGIN {
type string;
mandatory true;
description
"XMLDB datastore plugin filename
(see datastore/ and clixon_xml_db.[ch])";
}
leaf CLICON_XMLDB_CACHE {
type boolean;
default true;
description
"XMLDB datastore cache.
If set, XML candidate/running parsed tree is stored in memory
If not set, candidate/running is always accessed via disk.";
}
leaf CLICON_XMLDB_FORMAT {
type xmldb_format;
default xml;
description "XMLDB datastore format.";
}
leaf CLICON_XMLDB_PRETTY {
type boolean;
default true;
description
"XMLDB datastore pretty print.
If set, insert spaces and line-feeds making the XML/JSON human
readable. If not set, make the XML/JSON more compact.";
}
leaf CLICON_XML_SORT {
type boolean;
default true;
description
"If set, sort XML lists and leaf-lists alphabetically and uses binary
search. Unless ordered-by user is used.
Only works for Yang specified XML.
If not set, all lists accessed via linear search.";
}
leaf CLICON_USE_STARTUP_CONFIG {
type int32;
default 0;
description
"Enabled uses \"startup\" configuration on boot. It is called
startup_db and exists in XMLDB_DIR.
NOTE: Obsolete with 1.3.3 and CLICON_STARTUP_MODE";
}
leaf CLICON_STARTUP_MODE {
type startup_mode;
description "Which method to boot/start clicon backend";
}
}
}

View file

@ -1,304 +0,0 @@
module clixon-config {
prefix cc;
organization
"Clicon / Clixon";
contact
"Olof Hagsand <olof@hagsand.se>";
description
"Clixon configuration file
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
This file is part of CLIXON
Licensed under the Apache License, Version 2.0 (the \"License\");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an \"AS IS\" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 3 or later (the \"GPL\"),
in which case the provisions of the GPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of the GPL, and not to allow others to
use your version of this file under the terms of Apache License version 2,
indicate your decision by deleting the provisions above and replace them with
the notice and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****";
revision 2018-02-12 {
description
"Added pretty print for datastore";
}
typedef startup_mode{
description
"Which method to boot/start clicon backend.
The methods differ in how they reach a running state
Which source database to commit from, if any.";
type enumeration{
enum none{
description
"Do not touch running state
Typically after crash when running state and db are synched";
}
enum init{
description
"Initialize running state.
Start with a completely clean running state";
}
enum running{
description
"Commit running db configuration into running state
After reboot if a persistent running db exists";
}
enum startup{
description
"Commit startup configuration into running state
After reboot when no persistent running db exists";
}
}
}
typedef xmldb_format{
description
"Format of TEXT xml database format.";
type enumeration{
enum xml{
description "Save and load xmldb as XML";
}
enum json{
description "Save and load xmldb as JSON";
}
}
}
container config {
leaf CLICON_CONFIGFILE{
type string;
description
"Location of configuration-file for default values (this file)";
}
leaf CLICON_YANG_DIR {
type string;
mandatory true;
description
"Location of YANG module and submodule files.";
}
leaf CLICON_YANG_MODULE_MAIN {
type string;
default "clicon";
description
"Option used to construct initial yang file:
<module>[@<revision>]";
}
leaf CLICON_YANG_MODULE_REVISION {
type string;
description
"Option used to construct initial yang file:
<module>[@<revision>]";
}
leaf CLICON_BACKEND_DIR {
type string;
description
"Location of backend .so plugins. Load all .so
plugins in this dir as backend plugins";
}
leaf CLICON_NETCONF_DIR {
type string;
description "Location of netconf (frontend) .so plugins";
}
leaf CLICON_RESTCONF_DIR {
type string;
description
"Location of restconf (frontend) .so plugins. Load all .so
plugins in this dir as restconf code plugins";
}
leaf CLICON_RESTCONF_PATH {
type string;
default "/www-data/fastcgi_restconf.sock";
description
"FastCGI unix socket. Should be specified in webserver
Eg in nginx: fastcgi_pass unix:/www-data/clicon_restconf.sock";
}
leaf CLICON_RESTCONF_PRETTY {
type boolean;
default true;
description
"Restconf return value pretty print.
Restconf clients may add HTTP header:
Accept: application/yang-data+json, or
Accept: application/yang-data+xml
to get return value in XML or JSON.
RFC 8040 examples print XML and JSON in pretty-printed form.
Setting this value to false makes restconf return not pretty-printed
which may be desirable for performance or tests";
}
leaf CLICON_CLI_DIR {
type string;
description
"Location of cli frontend .so plugins. Load all .so
plugins in this dir as CLI object plugins";
}
leaf CLICON_CLISPEC_DIR {
type string;
description
"Location of frontend .cli cligen spec files. Load all .cli
files in this dir as CLI specification files";
}
leaf CLICON_CLISPEC_FILE {
type string;
description "Specific frontend .cli cligen spec file.";
}
leaf CLICON_CLI_MODE {
type string;
default "base";
description
"Startup CLI mode. This should match a CLICON_MODE set in
one of the clispec files";
}
leaf CLICON_CLI_GENMODEL {
type int32;
default 1;
description
"Generate code for CLI completion of existing db symbols.
Example: Add name=\"myspec\" in datamodel spec and reference
as @myspec";
}
leaf CLICON_CLI_GENMODEL_COMPLETION {
type int32;
default 1;
description "Generate code for CLI completion of existing db symbols";
}
leaf CLICON_CLI_GENMODEL_TYPE {
type string;
default "VARS";
description "How to generate and show CLI syntax: VARS|ALL";
}
leaf CLICON_CLI_VARONLY {
type int32;
default 1;
description
"Dont include keys in cvec in cli vars callbacks,
ie a & k in 'a <b> k <c>' ignored";
}
leaf CLICON_CLI_LINESCROLLING {
type int32;
default 1;
description
"Set to 0 if you want CLI to wrap to next line.
Set to 1 if you want CLI to scroll sideways when approaching
right margin";
}
leaf CLICON_SOCK_FAMILY {
type string;
default "UNIX";
description
"Address family for communicating with clixon_backend
(UNIX|IPv4|IPv6)";
}
leaf CLICON_SOCK {
type string;
mandatory true;
description
"If family above is AF_UNIX: Unix socket for communicating
with clixon_backend. If family is AF_INET: IPv4 address";
}
leaf CLICON_SOCK_PORT {
type int32;
default 4535;
description
"Inet socket port for communicating with clixon_backend
(only IPv4|IPv6)";
}
leaf CLICON_SOCK_GROUP {
type string;
default "clicon";
description "Group membership to access clixon_backend unix socket";
}
leaf CLICON_BACKEND_PIDFILE {
type string;
mandatory true;
description "Process-id file of backend daemon";
}
leaf CLICON_AUTOCOMMIT {
type int32;
default 0;
description
"Set if all configuration changes are committed automatically
on every edit change. Explicit commit commands unnecessary";
}
leaf CLICON_MASTER_PLUGIN {
type string;
default "master";
description
"Name of master plugin (both frontend and backend).
Master plugin has special callbacks for frontends.
See clicon user manual for more info. (Obsolete?)";
}
leaf CLICON_XMLDB_DIR {
type string;
mandatory true;
description
"Directory where \"running\", \"candidate\" and \"startup\" are placed";
}
leaf CLICON_XMLDB_PLUGIN {
type string;
mandatory true;
description
"XMLDB datastore plugin filename
(see datastore/ and clixon_xml_db.[ch])";
}
leaf CLICON_XMLDB_CACHE {
type boolean;
default true;
description
"XMLDB datastore cache.
If set, XML candidate/running parsed tree is stored in memory
If not set, candidate/running is always accessed via disk.";
}
leaf CLICON_XMLDB_FORMAT {
type xmldb_format;
default xml;
description "XMLDB datastore format.";
}
leaf CLICON_XMLDB_PRETTY {
type boolean;
default true;
description
"XMLDB datastore pretty print.
If set, insert spaces and line-feeds making the XML/JSON human
readable. If not set, make the XML/JSON more compact.";
}
leaf CLICON_XML_SORT {
type boolean;
default true;
description
"If set, sort XML lists and leaf-lists alphabetically and uses binary
search. Unless ordered-by user is used.
Only works for Yang specified XML.
If not set, all lists accessed via linear search.";
}
leaf CLICON_USE_STARTUP_CONFIG {
type int32;
default 0;
description
"Enabled uses \"startup\" configuration on boot. It is called
startup_db and exists in XMLDB_DIR.
NOTE: Obsolete with 1.3.3 and CLICON_STARTUP_MODE";
}
leaf CLICON_STARTUP_MODE {
type startup_mode;
description "Which method to boot/start clicon backend";
}
}
}

View file

@ -1,353 +0,0 @@
module clixon-config {
prefix cc;
organization
"Clicon / Clixon";
contact
"Olof Hagsand <olof@hagsand.se>";
description
"Clixon configuration file
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
This file is part of CLIXON
Licensed under the Apache License, Version 2.0 (the \"License\");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an \"AS IS\" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 3 or later (the \"GPL\"),
in which case the provisions of the GPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of the GPL, and not to allow others to
use your version of this file under the terms of Apache License version 2,
indicate your decision by deleting the provisions above and replace them with
the notice and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****";
revision 2018-04-30 {
description
"Released with Clixon 3.6";
}
typedef startup_mode{
description
"Which method to boot/start clicon backend.
The methods differ in how they reach a running state
Which source database to commit from, if any.";
type enumeration{
enum none{
description
"Do not touch running state
Typically after crash when running state and db are synched";
}
enum init{
description
"Initialize running state.
Start with a completely clean running state";
}
enum running{
description
"Commit running db configuration into running state
After reboot if a persistent running db exists";
}
enum startup{
description
"Commit startup configuration into running state
After reboot when no persistent running db exists";
}
}
}
typedef xmldb_format{
description
"Format of TEXT xml database format.";
type enumeration{
enum xml{
description "Save and load xmldb as XML";
}
enum json{
description "Save and load xmldb as JSON";
}
}
}
typedef cli_genmodel_type{
description
"How to generate CLI from YANG model,
eg list a{ key x; leaf x; leaf y;}";
type enumeration{
enum NONE{
description "No extra keywords: a <x> <y>";
}
enum VARS{
description "Keywords on non-key variables: a <x> y <y>";
}
enum ALL{
description "Keywords on all variables: a x <x> y <y>";
}
}
}
typedef nacm_mode{
description
"Mode of RFC8341 Network Configuration Access Control Model.
It is unclear from the RFC whether NACM rules are internal
in a configuration (ie embedded in regular config) or external/OOB
in s separate, specific NACM-config";
type enumeration{
enum disabled{
description "NACM is disabled";
}
enum internal{
description "NACM is enabled and available in the regular config";
}
enum external{
description "NACM is enabled and available in a separate config";
}
}
}
container config {
leaf CLICON_CONFIGFILE{
type string;
description
"Location of configuration-file for default values (this file)";
}
leaf CLICON_YANG_DIR {
type string;
mandatory true;
description
"Location of YANG module and submodule files.";
}
leaf CLICON_YANG_MODULE_MAIN {
type string;
default "clicon";
description
"Option used to construct initial yang file:
<module>[@<revision>]";
}
leaf CLICON_YANG_MODULE_REVISION {
type string;
description
"Option used to construct initial yang file:
<module>[@<revision>]";
}
leaf CLICON_BACKEND_DIR {
type string;
description
"Location of backend .so plugins. Load all .so
plugins in this dir as backend plugins";
}
leaf CLICON_BACKEND_REGEXP {
type string;
description
"Regexp of matching backend plugins in CLICON_BACKEND_DIR";
default "(.so)$";
}
leaf CLICON_NETCONF_DIR {
type string;
description "Location of netconf (frontend) .so plugins";
}
leaf CLICON_RESTCONF_DIR {
type string;
description
"Location of restconf (frontend) .so plugins. Load all .so
plugins in this dir as restconf code plugins";
}
leaf CLICON_RESTCONF_PATH {
type string;
default "/www-data/fastcgi_restconf.sock";
description
"FastCGI unix socket. Should be specified in webserver
Eg in nginx: fastcgi_pass unix:/www-data/clicon_restconf.sock";
}
leaf CLICON_RESTCONF_PRETTY {
type boolean;
default true;
description
"Restconf return value pretty print.
Restconf clients may add HTTP header:
Accept: application/yang-data+json, or
Accept: application/yang-data+xml
to get return value in XML or JSON.
RFC 8040 examples print XML and JSON in pretty-printed form.
Setting this value to false makes restconf return not pretty-printed
which may be desirable for performance or tests";
}
leaf CLICON_CLI_DIR {
type string;
description
"Location of cli frontend .so plugins. Load all .so
plugins in this dir as CLI object plugins";
}
leaf CLICON_CLISPEC_DIR {
type string;
description
"Location of frontend .cli cligen spec files. Load all .cli
files in this dir as CLI specification files";
}
leaf CLICON_CLISPEC_FILE {
type string;
description "Specific frontend .cli cligen spec file.";
}
leaf CLICON_CLI_MODE {
type string;
default "base";
description
"Startup CLI mode. This should match a CLICON_MODE set in
one of the clispec files";
}
leaf CLICON_CLI_GENMODEL {
type int32;
default 1;
description
"Generate code for CLI completion of existing db symbols.
Example: Add name=\"myspec\" in datamodel spec and reference
as @myspec";
}
leaf CLICON_CLI_GENMODEL_COMPLETION {
type int32;
default 1;
description "Generate code for CLI completion of existing db symbols";
}
leaf CLICON_CLI_GENMODEL_TYPE {
type cli_genmodel_type;
default "VARS";
description "How to generate and show CLI syntax: VARS|ALL";
}
leaf CLICON_CLI_VARONLY {
type int32;
default 1;
description
"Dont include keys in cvec in cli vars callbacks,
ie a & k in 'a <b> k <c>' ignored";
}
leaf CLICON_CLI_LINESCROLLING {
type int32;
default 1;
description
"Set to 0 if you want CLI to wrap to next line.
Set to 1 if you want CLI to scroll sideways when approaching
right margin";
}
leaf CLICON_SOCK_FAMILY {
type string;
default "UNIX";
description
"Address family for communicating with clixon_backend
(UNIX|IPv4|IPv6)";
}
leaf CLICON_SOCK {
type string;
mandatory true;
description
"If family above is AF_UNIX: Unix socket for communicating
with clixon_backend. If family is AF_INET: IPv4 address";
}
leaf CLICON_SOCK_PORT {
type int32;
default 4535;
description
"Inet socket port for communicating with clixon_backend
(only IPv4|IPv6)";
}
leaf CLICON_SOCK_GROUP {
type string;
default "clicon";
description "Group membership to access clixon_backend unix socket";
}
leaf CLICON_BACKEND_PIDFILE {
type string;
mandatory true;
description "Process-id file of backend daemon";
}
leaf CLICON_AUTOCOMMIT {
type int32;
default 0;
description
"Set if all configuration changes are committed automatically
on every edit change. Explicit commit commands unnecessary";
}
leaf CLICON_XMLDB_DIR {
type string;
mandatory true;
description
"Directory where \"running\", \"candidate\" and \"startup\" are placed";
}
leaf CLICON_XMLDB_PLUGIN {
type string;
mandatory true;
description
"XMLDB datastore plugin filename
(see datastore/ and clixon_xml_db.[ch])";
}
leaf CLICON_XMLDB_CACHE {
type boolean;
default true;
description
"XMLDB datastore cache.
If set, XML candidate/running parsed tree is stored in memory
If not set, candidate/running is always accessed via disk.";
}
leaf CLICON_XMLDB_FORMAT {
type xmldb_format;
default xml;
description "XMLDB datastore format.";
}
leaf CLICON_XMLDB_PRETTY {
type boolean;
default true;
description
"XMLDB datastore pretty print.
If set, insert spaces and line-feeds making the XML/JSON human
readable. If not set, make the XML/JSON more compact.";
}
leaf CLICON_XML_SORT {
type boolean;
default true;
description
"If set, sort XML lists and leaf-lists alphabetically and uses binary
search. Unless ordered-by user is used.
Only works for Yang specified XML.
If not set, all lists accessed via linear search.";
}
leaf CLICON_USE_STARTUP_CONFIG {
type int32;
default 0;
description
"Enabled uses \"startup\" configuration on boot. It is called
startup_db and exists in XMLDB_DIR.
NOTE: Obsolete with 1.3.3 and CLICON_STARTUP_MODE";
}
leaf CLICON_STARTUP_MODE {
type startup_mode;
description "Which method to boot/start clicon backend";
}
leaf CLICON_TRANSACTION_MOD {
type boolean;
default false;
description "If set, modifications in validation and commit
callbacks are written back into the datastore";
}
leaf CLICON_NACM_MODE {
type nacm_mode;
default disabled;
description "RFC8341 network access configuration control model
(NACM) mode: disabled, in regular (internal) config
or separate external file given by CLICON_NACM_FILE";
}
leaf CLICON_NACM_FILE {
type string;
description "RFC8341 NACM external configuration file";
}
}
}

69
yang/clixon/Makefile.in Normal file
View file

@ -0,0 +1,69 @@
#
# ***** BEGIN LICENSE BLOCK *****
#
# Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
#
# This file is part of CLIXON
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Alternatively, the contents of this file may be used under the terms of
# the GNU General Public License Version 3 or later (the "GPL"),
# in which case the provisions of the GPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of the GPL, and not to allow others to
# use your version of this file under the terms of Apache License version 2,
# indicate your decision by deleting the provisions above and replace them with
# the notice and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the Apache License version 2 or the GPL.
#
# ***** END LICENSE BLOCK *****
#
VPATH = @srcdir@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
prefix = @prefix@
bindir = @bindir@
includedir = @includedir@
datarootdir = @datarootdir@
CLIXON_DATADIR = @CLIXON_DATADIR@
YANGSPECS = clixon-config@2018-10-21.yang
YANGSPECS += clixon-lib@2019-01-02.yang
YANGSPECS += clixon-rfc5277@2008-07-01.yang
APPNAME = clixon # subdir ehere these files are installed
all:
clean:
distclean: clean
rm -f Makefile *~ .depend
install: $(YANGSPECS)
install -d -m 0755 $(DESTDIR)$(CLIXON_DATADIR)
install -m 0644 $(YANGSPECS) $(DESTDIR)$(CLIXON_DATADIR)
uninstall:
(cd $(DESTDIR)$(CLIXON_DATADIR); rm -rf *.yang)
install-include:
depend:
#include .depend

View file

@ -134,6 +134,7 @@ module clixon-config {
"Location of configuration-file for default values (this file)"; "Location of configuration-file for default values (this file)";
} }
leaf-list CLICON_YANG_DIR { leaf-list CLICON_YANG_DIR {
ordered-by user;
type string; type string;
description description
"Yang directory path for finding module and submodule files. "Yang directory path for finding module and submodule files.

View file

@ -1,457 +0,0 @@
module ietf-inet-types {
namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
prefix "inet";
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
WG Chair: David Kessens
<mailto:david.kessens@nsn.com>
WG Chair: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Editor: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>";
description
"This module contains a collection of generally useful derived
YANG data types for Internet addresses and related things.
Copyright (c) 2013 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 6991; see
the RFC itself for full legal notices.";
revision 2013-07-15 {
description
"This revision adds the following new data types:
- ip-address-no-zone
- ipv4-address-no-zone
- ipv6-address-no-zone";
reference
"RFC 6991: Common YANG Data Types";
}
revision 2010-09-24 {
description
"Initial revision.";
reference
"RFC 6021: Common YANG Data Types";
}
/*** collection of types related to protocol fields ***/
typedef ip-version {
type enumeration {
enum unknown {
value "0";
description
"An unknown or unspecified version of the Internet
protocol.";
}
enum ipv4 {
value "1";
description
"The IPv4 protocol as defined in RFC 791.";
}
enum ipv6 {
value "2";
description
"The IPv6 protocol as defined in RFC 2460.";
}
}
description
"This value represents the version of the IP protocol.
In the value set and its semantics, this type is equivalent
to the InetVersion textual convention of the SMIv2.";
reference
"RFC 791: Internet Protocol
RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
RFC 4001: Textual Conventions for Internet Network Addresses";
}
typedef dscp {
type uint8 {
range "0..63";
}
description
"The dscp type represents a Differentiated Services Code Point
that may be used for marking packets in a traffic stream.
In the value set and its semantics, this type is equivalent
to the Dscp textual convention of the SMIv2.";
reference
"RFC 3289: Management Information Base for the Differentiated
Services Architecture
RFC 2474: Definition of the Differentiated Services Field
(DS Field) in the IPv4 and IPv6 Headers
RFC 2780: IANA Allocation Guidelines For Values In
the Internet Protocol and Related Headers";
}
typedef ipv6-flow-label {
type uint32 {
range "0..1048575";
}
description
"The ipv6-flow-label type represents the flow identifier or Flow
Label in an IPv6 packet header that may be used to
discriminate traffic flows.
In the value set and its semantics, this type is equivalent
to the IPv6FlowLabel textual convention of the SMIv2.";
reference
"RFC 3595: Textual Conventions for IPv6 Flow Label
RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
}
typedef port-number {
type uint16 {
range "0..65535";
}
description
"The port-number type represents a 16-bit port number of an
Internet transport-layer protocol such as UDP, TCP, DCCP, or
SCTP. Port numbers are assigned by IANA. A current list of
all assignments is available from <http://www.iana.org/>.
Note that the port number value zero is reserved by IANA. In
situations where the value zero does not make sense, it can
be excluded by subtyping the port-number type.
In the value set and its semantics, this type is equivalent
to the InetPortNumber textual convention of the SMIv2.";
reference
"RFC 768: User Datagram Protocol
RFC 793: Transmission Control Protocol
RFC 4960: Stream Control Transmission Protocol
RFC 4340: Datagram Congestion Control Protocol (DCCP)
RFC 4001: Textual Conventions for Internet Network Addresses";
}
/*** collection of types related to autonomous systems ***/
typedef as-number {
type uint32;
description
"The as-number type represents autonomous system numbers
which identify an Autonomous System (AS). An AS is a set
of routers under a single technical administration, using
an interior gateway protocol and common metrics to route
packets within the AS, and using an exterior gateway
protocol to route packets to other ASes. IANA maintains
the AS number space and has delegated large parts to the
regional registries.
Autonomous system numbers were originally limited to 16
bits. BGP extensions have enlarged the autonomous system
number space to 32 bits. This type therefore uses an uint32
base type without a range restriction in order to support
a larger autonomous system number space.
In the value set and its semantics, this type is equivalent
to the InetAutonomousSystemNumber textual convention of
the SMIv2.";
reference
"RFC 1930: Guidelines for creation, selection, and registration
of an Autonomous System (AS)
RFC 4271: A Border Gateway Protocol 4 (BGP-4)
RFC 4001: Textual Conventions for Internet Network Addresses
RFC 6793: BGP Support for Four-Octet Autonomous System (AS)
Number Space";
}
/*** collection of types related to IP addresses and hostnames ***/
typedef ip-address {
type union {
type inet:ipv4-address;
type inet:ipv6-address;
}
description
"The ip-address type represents an IP address and is IP
version neutral. The format of the textual representation
implies the IP version. This type supports scoped addresses
by allowing zone identifiers in the address format.";
reference
"RFC 4007: IPv6 Scoped Address Architecture";
}
typedef ipv4-address {
type string {
pattern
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ '(%[\p{N}\p{L}]+)?';
}
description
"The ipv4-address type represents an IPv4 address in
dotted-quad notation. The IPv4 address may include a zone
index, separated by a % sign.
The zone index is used to disambiguate identical address
values. For link-local addresses, the zone index will
typically be the interface index number or the name of an
interface. If the zone index is not present, the default
zone of the device will be used.
The canonical format for the zone index is the numerical
format";
}
typedef ipv6-address {
type string {
pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ '(%[\p{N}\p{L}]+)?';
pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ '(%.+)?';
}
description
"The ipv6-address type represents an IPv6 address in full,
mixed, shortened, and shortened-mixed notation. The IPv6
address may include a zone index, separated by a % sign.
The zone index is used to disambiguate identical address
values. For link-local addresses, the zone index will
typically be the interface index number or the name of an
interface. If the zone index is not present, the default
zone of the device will be used.
The canonical format of IPv6 addresses uses the textual
representation defined in Section 4 of RFC 5952. The
canonical format for the zone index is the numerical
format as described in Section 11.2 of RFC 4007.";
reference
"RFC 4291: IP Version 6 Addressing Architecture
RFC 4007: IPv6 Scoped Address Architecture
RFC 5952: A Recommendation for IPv6 Address Text
Representation";
}
typedef ip-address-no-zone {
type union {
type inet:ipv4-address-no-zone;
type inet:ipv6-address-no-zone;
}
description
"The ip-address-no-zone type represents an IP address and is
IP version neutral. The format of the textual representation
implies the IP version. This type does not support scoped
addresses since it does not allow zone identifiers in the
address format.";
reference
"RFC 4007: IPv6 Scoped Address Architecture";
}
typedef ipv4-address-no-zone {
type inet:ipv4-address {
pattern '[0-9\.]*';
}
description
"An IPv4 address without a zone index. This type, derived from
ipv4-address, may be used in situations where the zone is
known from the context and hence no zone index is needed.";
}
typedef ipv6-address-no-zone {
type inet:ipv6-address {
pattern '[0-9a-fA-F:\.]*';
}
description
"An IPv6 address without a zone index. This type, derived from
ipv6-address, may be used in situations where the zone is
known from the context and hence no zone index is needed.";
reference
"RFC 4291: IP Version 6 Addressing Architecture
RFC 4007: IPv6 Scoped Address Architecture
RFC 5952: A Recommendation for IPv6 Address Text
Representation";
}
typedef ip-prefix {
type union {
type inet:ipv4-prefix;
type inet:ipv6-prefix;
}
description
"The ip-prefix type represents an IP prefix and is IP
version neutral. The format of the textual representations
implies the IP version.";
}
typedef ipv4-prefix {
type string {
pattern
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ '/(([0-9])|([1-2][0-9])|(3[0-2]))';
}
description
"The ipv4-prefix type represents an IPv4 address prefix.
The prefix length is given by the number following the
slash character and must be less than or equal to 32.
A prefix length value of n corresponds to an IP address
mask that has n contiguous 1-bits from the most
significant bit (MSB) and all other bits set to 0.
The canonical format of an IPv4 prefix has all bits of
the IPv4 address set to zero that are not part of the
IPv4 prefix.";
}
typedef ipv6-prefix {
type string {
pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ '(/.+)';
}
description
"The ipv6-prefix type represents an IPv6 address prefix.
The prefix length is given by the number following the
slash character and must be less than or equal to 128.
A prefix length value of n corresponds to an IP address
mask that has n contiguous 1-bits from the most
significant bit (MSB) and all other bits set to 0.
The IPv6 address should have all bits that do not belong
to the prefix set to zero.
The canonical format of an IPv6 prefix has all bits of
the IPv6 address set to zero that are not part of the
IPv6 prefix. Furthermore, the IPv6 address is represented
as defined in Section 4 of RFC 5952.";
reference
"RFC 5952: A Recommendation for IPv6 Address Text
Representation";
}
/*** collection of domain name and URI types ***/
typedef domain-name {
type string {
pattern
'((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+ '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+ '|\.';
length "1..253";
}
description
"The domain-name type represents a DNS domain name. The
name SHOULD be fully qualified whenever possible.
Internet domain names are only loosely specified. Section
3.5 of RFC 1034 recommends a syntax (modified in Section
2.1 of RFC 1123). The pattern above is intended to allow
for current practice in domain name use, and some possible
future expansion. It is designed to hold various types of
domain names, including names used for A or AAAA records
(host names) and other records, such as SRV records. Note
that Internet host names have a stricter syntax (described
in RFC 952) than the DNS recommendations in RFCs 1034 and
1123, and that systems that want to store host names in
schema nodes using the domain-name type are recommended to
adhere to this stricter standard to ensure interoperability.
The encoding of DNS names in the DNS protocol is limited
to 255 characters. Since the encoding consists of labels
prefixed by a length bytes and there is a trailing NULL
byte, only 253 characters can appear in the textual dotted
notation.
The description clause of schema nodes using the domain-name
type MUST describe when and how these names are resolved to
IP addresses. Note that the resolution of a domain-name value
may require to query multiple DNS records (e.g., A for IPv4
and AAAA for IPv6). The order of the resolution process and
which DNS record takes precedence can either be defined
explicitly or may depend on the configuration of the
resolver.
Domain-name values use the US-ASCII encoding. Their canonical
format uses lowercase US-ASCII characters. Internationalized
domain names MUST be A-labels as per RFC 5890.";
reference
"RFC 952: DoD Internet Host Table Specification
RFC 1034: Domain Names - Concepts and Facilities
RFC 1123: Requirements for Internet Hosts -- Application
and Support
RFC 2782: A DNS RR for specifying the location of services
(DNS SRV)
RFC 5890: Internationalized Domain Names in Applications
(IDNA): Definitions and Document Framework";
}
typedef host {
type union {
type inet:ip-address;
type inet:domain-name;
}
description
"The host type represents either an IP address or a DNS
domain name.";
}
typedef uri {
type string;
description
"The uri type represents a Uniform Resource Identifier
(URI) as defined by STD 66.
Objects using the uri type MUST be in US-ASCII encoding,
and MUST be normalized as described by RFC 3986 Sections
6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary
percent-encoding is removed, and all case-insensitive
characters are set to lowercase except for hexadecimal
digits, which are normalized to uppercase as described in
Section 6.2.2.1.
The purpose of this normalization is to help provide
unique URIs. Note that this normalization is not
sufficient to provide uniqueness. Two URIs that are
textually distinct after this normalization may still be
equivalent.
Objects using the uri type may restrict the schemes that
they permit. For example, 'data:' and 'urn:' schemes
might not be appropriate.
A zero-length URI is not a valid URI. This can be used to
express 'URI absent' where required.
In the value set and its semantics, this type is equivalent
to the Uri SMIv2 textual convention defined in RFC 5017.";
reference
"RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
Group: Uniform Resource Identifiers (URIs), URLs,
and Uniform Resource Names (URNs): Clarifications
and Recommendations
RFC 5017: MIB Textual Conventions for Uniform Resource
Identifiers (URIs)";
}
}

View file

@ -1,279 +0,0 @@
module ietf-restconf {
yang-version 1.1;
namespace "urn:ietf:params:xml:ns:yang:ietf-restconf";
prefix "rc";
organization
"IETF NETCONF (Network Configuration) Working Group";
contact
"WG Web: <https://datatracker.ietf.org/wg/netconf/>
WG List: <mailto:netconf@ietf.org>
Author: Andy Bierman
<mailto:andy@yumaworks.com>
Author: Martin Bjorklund
<mailto:mbj@tail-f.com>
Author: Kent Watsen
<mailto:kwatsen@juniper.net>";
description
"This module contains conceptual YANG specifications
for basic RESTCONF media type definitions used in
RESTCONF protocol messages.
Note that the YANG definitions within this module do not
represent configuration data of any kind.
The 'restconf-media-type' YANG extension statement
provides a normative syntax for XML and JSON
message-encoding purposes.
Copyright (c) 2017 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 8040; see
the RFC itself for full legal notices.";
revision 2017-01-26 {
description
"Initial revision.";
reference
"RFC 8040: RESTCONF Protocol.";
}
extension yang-data {
argument name {
yin-element true;
}
description
"This extension is used to specify a YANG data template that
represents conceptual data defined in YANG. It is
intended to describe hierarchical data independent of
protocol context or specific message-encoding format.
Data definition statements within a yang-data extension
specify the generic syntax for the specific YANG data
template, whose name is the argument of the 'yang-data'
extension statement.
Note that this extension does not define a media type.
A specification using this extension MUST specify the
message-encoding rules, including the content media type.
The mandatory 'name' parameter value identifies the YANG
data template that is being defined. It contains the
template name.
This extension is ignored unless it appears as a top-level
statement. It MUST contain data definition statements
that result in exactly one container data node definition.
An instance of a YANG data template can thus be translated
into an XML instance document, whose top-level element
corresponds to the top-level container.
The module name and namespace values for the YANG module using
the extension statement are assigned to instance document data
conforming to the data definition statements within
this extension.
The substatements of this extension MUST follow the
'data-def-stmt' rule in the YANG ABNF.
The XPath document root is the extension statement itself,
such that the child nodes of the document root are
represented by the data-def-stmt substatements within
this extension. This conceptual document is the context
for the following YANG statements:
- must-stmt
- when-stmt
- path-stmt
- min-elements-stmt
- max-elements-stmt
- mandatory-stmt
- unique-stmt
- ordered-by
- instance-identifier data type
The following data-def-stmt substatements are constrained
when used within a 'yang-data' extension statement.
- The list-stmt is not required to have a key-stmt defined.
- The if-feature-stmt is ignored if present.
- The config-stmt is ignored if present.
- The available identity values for any 'identityref'
leaf or leaf-list nodes are limited to the module
containing this extension statement and the modules
imported into that module.
";
}
rc:yang-data yang-errors {
uses errors;
}
rc:yang-data yang-api {
uses restconf;
}
grouping errors {
description
"A grouping that contains a YANG container
representing the syntax and semantics of a
YANG Patch error report within a response message.";
container errors {
description
"Represents an error report returned by the server if
a request results in an error.";
list error {
description
"An entry containing information about one
specific error that occurred while processing
a RESTCONF request.";
reference
"RFC 6241, Section 4.3.";
leaf error-type {
type enumeration {
enum transport {
description
"The transport layer.";
}
enum rpc {
description
"The rpc or notification layer.";
}
enum protocol {
description
"The protocol operation layer.";
}
enum application {
description
"The server application layer.";
}
}
mandatory true;
description
"The protocol layer where the error occurred.";
}
leaf error-tag {
type string;
mandatory true;
description
"The enumerated error-tag.";
}
leaf error-app-tag {
type string;
description
"The application-specific error-tag.";
}
leaf error-path {
type instance-identifier;
description
"The YANG instance identifier associated
with the error node.";
}
leaf error-message {
type string;
description
"A message describing the error.";
}
anydata error-info {
description
"This anydata value MUST represent a container with
zero or more data nodes representing additional
error information.";
}
}
}
}
grouping restconf {
description
"Conceptual grouping representing the RESTCONF
root resource.";
container restconf {
description
"Conceptual container representing the RESTCONF
root resource.";
container data {
description
"Container representing the datastore resource.
Represents the conceptual root of all state data
and configuration data supported by the server.
The child nodes of this container can be any data
resources that are defined as top-level data nodes
from the YANG modules advertised by the server in
the 'ietf-yang-library' module.";
}
container operations {
description
"Container for all operation resources.
Each resource is represented as an empty leaf with the
name of the RPC operation from the YANG 'rpc' statement.
For example, the 'system-restart' RPC operation defined
in the 'ietf-system' module would be represented as
an empty leaf in the 'ietf-system' namespace. This is
a conceptual leaf and will not actually be found in
the module:
module ietf-system {
leaf system-reset {
type empty;
}
}
To invoke the 'system-restart' RPC operation:
POST /restconf/operations/ietf-system:system-restart
To discover the RPC operations supported by the server:
GET /restconf/operations
In XML, the YANG module namespace identifies the module:
<system-restart
xmlns='urn:ietf:params:xml:ns:yang:ietf-system'/>
In JSON, the YANG module name identifies the module:
{ 'ietf-system:system-restart' : [null] }
";
}
leaf yang-library-version {
type string {
pattern '\d{4}-\d{2}-\d{2}';
}
config false;
mandatory true;
description
"Identifies the revision date of the 'ietf-yang-library'
module that is implemented by this RESTCONF server.
Indicates the year, month, and day in YYYY-MM-DD
numeric format.";
}
}
}
}

View file

@ -1,481 +0,0 @@
module ietf-yang-types {
namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
prefix "yang";
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
WG Chair: David Kessens
<mailto:david.kessens@nsn.com>
WG Chair: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Editor: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>";
description
"This module contains a collection of generally useful derived
YANG data types.
Copyright (c) 2013 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 6991; see
the RFC itself for full legal notices.";
revision 2013-07-15 {
description
"This revision adds the following new data types:
- yang-identifier
- hex-string
- uuid
- dotted-quad";
reference
"RFC 6991: Common YANG Data Types";
}
revision 2010-09-24 {
description
"Initial revision.";
reference
"RFC 6021: Common YANG Data Types";
}
/*** collection of counter and gauge types ***/
typedef counter32 {
type uint32;
description
"The counter32 type represents a non-negative integer
that monotonically increases until it reaches a
maximum value of 2^32-1 (4294967295 decimal), when it
wraps around and starts increasing again from zero.
Counters have no defined 'initial' value, and thus, a
single value of a counter has (in general) no information
content. Discontinuities in the monotonically increasing
value normally occur at re-initialization of the
management system, and at other times as specified in the
description of a schema node using this type. If such
other times can occur, for example, the creation of
a schema node of type counter32 at times other than
re-initialization, then a corresponding schema node
should be defined, with an appropriate type, to indicate
the last discontinuity.
The counter32 type should not be used for configuration
schema nodes. A default statement SHOULD NOT be used in
combination with the type counter32.
In the value set and its semantics, this type is equivalent
to the Counter32 type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef zero-based-counter32 {
type yang:counter32;
default "0";
description
"The zero-based-counter32 type represents a counter32
that has the defined 'initial' value zero.
A schema node of this type will be set to zero (0) on creation
and will thereafter increase monotonically until it reaches
a maximum value of 2^32-1 (4294967295 decimal), when it
wraps around and starts increasing again from zero.
Provided that an application discovers a new schema node
of this type within the minimum time to wrap, it can use the
'initial' value as a delta. It is important for a management
station to be aware of this minimum time and the actual time
between polls, and to discard data if the actual time is too
long or there is no defined minimum time.
In the value set and its semantics, this type is equivalent
to the ZeroBasedCounter32 textual convention of the SMIv2.";
reference
"RFC 4502: Remote Network Monitoring Management Information
Base Version 2";
}
typedef counter64 {
type uint64;
description
"The counter64 type represents a non-negative integer
that monotonically increases until it reaches a
maximum value of 2^64-1 (18446744073709551615 decimal),
when it wraps around and starts increasing again from zero.
Counters have no defined 'initial' value, and thus, a
single value of a counter has (in general) no information
content. Discontinuities in the monotonically increasing
value normally occur at re-initialization of the
management system, and at other times as specified in the
description of a schema node using this type. If such
other times can occur, for example, the creation of
a schema node of type counter64 at times other than
re-initialization, then a corresponding schema node
should be defined, with an appropriate type, to indicate
the last discontinuity.
The counter64 type should not be used for configuration
schema nodes. A default statement SHOULD NOT be used in
combination with the type counter64.
In the value set and its semantics, this type is equivalent
to the Counter64 type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef zero-based-counter64 {
type yang:counter64;
default "0";
description
"The zero-based-counter64 type represents a counter64 that
has the defined 'initial' value zero.
A schema node of this type will be set to zero (0) on creation
and will thereafter increase monotonically until it reaches
a maximum value of 2^64-1 (18446744073709551615 decimal),
when it wraps around and starts increasing again from zero.
Provided that an application discovers a new schema node
of this type within the minimum time to wrap, it can use the
'initial' value as a delta. It is important for a management
station to be aware of this minimum time and the actual time
between polls, and to discard data if the actual time is too
long or there is no defined minimum time.
In the value set and its semantics, this type is equivalent
to the ZeroBasedCounter64 textual convention of the SMIv2.";
reference
"RFC 2856: Textual Conventions for Additional High Capacity
Data Types";
}
typedef gauge32 {
type uint32;
description
"The gauge32 type represents a non-negative integer, which
may increase or decrease, but shall never exceed a maximum
value, nor fall below a minimum value. The maximum value
cannot be greater than 2^32-1 (4294967295 decimal), and
the minimum value cannot be smaller than 0. The value of
a gauge32 has its maximum value whenever the information
being modeled is greater than or equal to its maximum
value, and has its minimum value whenever the information
being modeled is smaller than or equal to its minimum value.
If the information being modeled subsequently decreases
below (increases above) the maximum (minimum) value, the
gauge32 also decreases (increases).
In the value set and its semantics, this type is equivalent
to the Gauge32 type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef gauge64 {
type uint64;
description
"The gauge64 type represents a non-negative integer, which
may increase or decrease, but shall never exceed a maximum
value, nor fall below a minimum value. The maximum value
cannot be greater than 2^64-1 (18446744073709551615), and
the minimum value cannot be smaller than 0. The value of
a gauge64 has its maximum value whenever the information
being modeled is greater than or equal to its maximum
value, and has its minimum value whenever the information
being modeled is smaller than or equal to its minimum value.
If the information being modeled subsequently decreases
below (increases above) the maximum (minimum) value, the
gauge64 also decreases (increases).
In the value set and its semantics, this type is equivalent
to the CounterBasedGauge64 SMIv2 textual convention defined
in RFC 2856";
reference
"RFC 2856: Textual Conventions for Additional High Capacity
Data Types";
}
/*** collection of identifier-related types ***/
typedef object-identifier {
type string {
pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+ '(\.(0|([1-9]\d*)))*';
}
description
"The object-identifier type represents administratively
assigned names in a registration-hierarchical-name tree.
Values of this type are denoted as a sequence of numerical
non-negative sub-identifier values. Each sub-identifier
value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
are separated by single dots and without any intermediate
whitespace.
The ASN.1 standard restricts the value space of the first
sub-identifier to 0, 1, or 2. Furthermore, the value space
of the second sub-identifier is restricted to the range
0 to 39 if the first sub-identifier is 0 or 1. Finally,
the ASN.1 standard requires that an object identifier
has always at least two sub-identifiers. The pattern
captures these restrictions.
Although the number of sub-identifiers is not limited,
module designers should realize that there may be
implementations that stick with the SMIv2 limit of 128
sub-identifiers.
This type is a superset of the SMIv2 OBJECT IDENTIFIER type
since it is not restricted to 128 sub-identifiers. Hence,
this type SHOULD NOT be used to represent the SMIv2 OBJECT
IDENTIFIER type; the object-identifier-128 type SHOULD be
used instead.";
reference
"ISO9834-1: Information technology -- Open Systems
Interconnection -- Procedures for the operation of OSI
Registration Authorities: General procedures and top
arcs of the ASN.1 Object Identifier tree";
}
typedef object-identifier-128 {
type object-identifier {
pattern '\d*(\.\d*){1,127}';
}
description
"This type represents object-identifiers restricted to 128
sub-identifiers.
In the value set and its semantics, this type is equivalent
to the OBJECT IDENTIFIER type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef yang-identifier {
type string {
length "1..max";
pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
}
description
"A YANG identifier string as defined by the 'identifier'
rule in Section 12 of RFC 6020. An identifier must
start with an alphabetic character or an underscore
followed by an arbitrary sequence of alphabetic or
numeric characters, underscores, hyphens, or dots.
A YANG identifier MUST NOT start with any possible
combination of the lowercase or uppercase character
sequence 'xml'.";
reference
"RFC 6020: YANG - A Data Modeling Language for the Network
Configuration Protocol (NETCONF)";
}
/*** collection of types related to date and time***/
typedef date-and-time {
type string {
pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+ '(Z|[\+\-]\d{2}:\d{2})';
}
description
"The date-and-time type is a profile of the ISO 8601
standard for representation of dates and times using the
Gregorian calendar. The profile is defined by the
date-time production in Section 5.6 of RFC 3339.
The date-and-time type is compatible with the dateTime XML
schema type with the following notable exceptions:
(a) The date-and-time type does not allow negative years.
(b) The date-and-time time-offset -00:00 indicates an unknown
time zone (see RFC 3339) while -00:00 and +00:00 and Z
all represent the same time zone in dateTime.
(c) The canonical format (see below) of data-and-time values
differs from the canonical format used by the dateTime XML
schema type, which requires all times to be in UTC using
the time-offset 'Z'.
This type is not equivalent to the DateAndTime textual
convention of the SMIv2 since RFC 3339 uses a different
separator between full-date and full-time and provides
higher resolution of time-secfrac.
The canonical format for date-and-time values with a known time
zone uses a numeric time zone offset that is calculated using
the device's configured known offset to UTC time. A change of
the device's offset to UTC time will cause date-and-time values
to change accordingly. Such changes might happen periodically
in case a server follows automatically daylight saving time
(DST) time zone offset changes. The canonical format for
date-and-time values with an unknown time zone (usually
referring to the notion of local time) uses the time-offset
-00:00.";
reference
"RFC 3339: Date and Time on the Internet: Timestamps
RFC 2579: Textual Conventions for SMIv2
XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
}
typedef timeticks {
type uint32;
description
"The timeticks type represents a non-negative integer that
represents the time, modulo 2^32 (4294967296 decimal), in
hundredths of a second between two epochs. When a schema
node is defined that uses this type, the description of
the schema node identifies both of the reference epochs.
In the value set and its semantics, this type is equivalent
to the TimeTicks type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef timestamp {
type yang:timeticks;
description
"The timestamp type represents the value of an associated
timeticks schema node at which a specific occurrence
happened. The specific occurrence must be defined in the
description of any schema node defined using this type. When
the specific occurrence occurred prior to the last time the
associated timeticks attribute was zero, then the timestamp
value is zero. Note that this requires all timestamp values
to be reset to zero when the value of the associated timeticks
attribute reaches 497+ days and wraps around to zero.
The associated timeticks schema node must be specified
in the description of any schema node using this type.
In the value set and its semantics, this type is equivalent
to the TimeStamp textual convention of the SMIv2.";
reference
"RFC 2579: Textual Conventions for SMIv2";
}
/*** collection of generic address types ***/
typedef phys-address {
type string {
pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
}
description
"Represents media- or physical-level addresses represented
as a sequence octets, each octet represented by two hexadecimal
numbers. Octets are separated by colons. The canonical
representation uses lowercase characters.
In the value set and its semantics, this type is equivalent
to the PhysAddress textual convention of the SMIv2.";
reference
"RFC 2579: Textual Conventions for SMIv2";
}
typedef mac-address {
type string {
pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
}
description
"The mac-address type represents an IEEE 802 MAC address.
The canonical representation uses lowercase characters.
In the value set and its semantics, this type is equivalent
to the MacAddress textual convention of the SMIv2.";
reference
"IEEE 802: IEEE Standard for Local and Metropolitan Area
Networks: Overview and Architecture
RFC 2579: Textual Conventions for SMIv2";
}
/*** collection of XML-specific types ***/
typedef xpath1.0 {
type string;
description
"This type represents an XPATH 1.0 expression.
When a schema node is defined that uses this type, the
description of the schema node MUST specify the XPath
context in which the XPath expression is evaluated.";
reference
"XPATH: XML Path Language (XPath) Version 1.0";
}
/*** collection of string types ***/
typedef hex-string {
type string {
pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
}
description
"A hexadecimal string with octets represented as hex digits
separated by colons. The canonical representation uses
lowercase characters.";
}
typedef uuid {
type string {
pattern '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-'
+ '[0-9a-fA-F]{4}-[0-9a-fA-F]{12}';
}
description
"A Universally Unique IDentifier in the string representation
defined in RFC 4122. The canonical representation uses
lowercase characters.
The following is an example of a UUID in string representation:
f81d4fae-7dec-11d0-a765-00a0c91e6bf6
";
reference
"RFC 4122: A Universally Unique IDentifier (UUID) URN
Namespace";
}
typedef dotted-quad {
type string {
pattern
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])';
}
description
"An unsigned 32-bit number expressed in the dotted-quad
notation, i.e., four octets written as decimal numbers
and separated with the '.' (full stop) character.";
}
}

76
yang/standard/Makefile.in Normal file
View file

@ -0,0 +1,76 @@
#
# ***** BEGIN LICENSE BLOCK *****
#
# Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
#
# This file is part of CLIXON
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Alternatively, the contents of this file may be used under the terms of
# the GNU General Public License Version 3 or later (the "GPL"),
# in which case the provisions of the GPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of the GPL, and not to allow others to
# use your version of this file under the terms of Apache License version 2,
# indicate your decision by deleting the provisions above and replace them with
# the notice and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the Apache License version 2 or the GPL.
#
# ***** END LICENSE BLOCK *****
#
VPATH = @srcdir@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
prefix = @prefix@
bindir = @bindir@
includedir = @includedir@
datarootdir = @datarootdir@
# Could place them in separate standards dir?
CLIXON_DATADIR = @CLIXON_DATADIR@
YANGSPECS = iana-if-type@2014-05-08.yang
YANGSPECS += ietf-interfaces@2018-02-20.yang
YANGSPECS += ietf-yang-types@2013-07-15.yang
YANGSPECS += ietf-ip@2014-06-16.yang
YANGSPECS += ietf-inet-types@2013-07-15.yang
YANGSPECS += ietf-routing@2018-03-13.yang
YANGSPECS += ietf-yang-library@2016-06-21.yang
YANGSPECS += ietf-netconf@2011-06-01.yang
YANGSPECS += ietf-netconf-acm@2018-02-14.yang
YANGSPECS += ietf-restconf-monitoring@2017-01-26.yang
YANGSPECS += ietf-netconf-monitoring@2010-10-04.yang
all:
clean:
distclean: clean
rm -f Makefile *~ .depend
install: $(YANGSPECS)
install -d -m 0755 $(DESTDIR)$(CLIXON_DATADIR)
install -m 0644 $(YANGSPECS) $(DESTDIR)$(CLIXON_DATADIR)
uninstall:
(cd $(DESTDIR)$(CLIXON_DATADIR); rm -rf *.yang)
install-include:
depend:
#include .depend

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,684 @@
module ietf-routing {
yang-version "1.1";
namespace "urn:ietf:params:xml:ns:yang:ietf-routing";
prefix "rt";
import ietf-yang-types {
prefix "yang";
}
import ietf-interfaces {
prefix "if";
description
"An 'ietf-interfaces' module version that is compatible with
the Network Management Datastore Architecture (NMDA)
is required.";
}
organization
"IETF NETMOD (Network Modeling) Working Group";
contact
"WG Web: <https://datatracker.ietf.org/wg/netmod/>
WG List: <mailto:rtgwg@ietf.org>
Editor: Ladislav Lhotka
<mailto:lhotka@nic.cz>
Acee Lindem
<mailto:acee@cisco.com>
Yingzhen Qu
<mailto:yingzhen.qu@huawei.com>";
description
"This YANG module defines essential components for the management
of a routing subsystem. The model fully conforms to the Network
Management Datastore Architecture (NMDA).
Copyright (c) 2018 IETF Trust and the persons
identified as authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(https://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 8349; see
the RFC itself for full legal notices.";
revision 2018-03-13 {
description
"Network Management Datastore Architecture (NMDA) revision.";
reference
"RFC 8349: A YANG Data Model for Routing Management
(NMDA Version)";
}
revision 2016-11-04 {
description
"Initial revision.";
reference
"RFC 8022: A YANG Data Model for Routing Management";
}
/* Features */
feature multiple-ribs {
description
"This feature indicates that the server supports
user-defined RIBs.
Servers that do not advertise this feature SHOULD provide
exactly one system-controlled RIB per supported address family
and also make it the default RIB. This RIB then appears as an
entry in the list '/routing/ribs/rib'.";
}
feature router-id {
description
"This feature indicates that the server supports an explicit
32-bit router ID that is used by some routing protocols.
Servers that do not advertise this feature set a router ID
algorithmically, usually to one of the configured IPv4
addresses. However, this algorithm is implementation
specific.";
}
/* Identities */
identity address-family {
description
"Base identity from which identities describing address
families are derived.";
}
identity ipv4 {
base address-family;
description
"This identity represents an IPv4 address family.";
}
identity ipv6 {
base address-family;
description
"This identity represents an IPv6 address family.";
}
identity control-plane-protocol {
description
"Base identity from which control-plane protocol identities are
derived.";
}
identity routing-protocol {
base control-plane-protocol;
description
"Identity from which Layer 3 routing protocol identities are
derived.";
}
identity direct {
base routing-protocol;
description
"Routing pseudo-protocol that provides routes to directly
connected networks.";
}
identity static {
base routing-protocol;
description
"'Static' routing pseudo-protocol.";
}
/* Type Definitions */
typedef route-preference {
type uint32;
description
"This type is used for route preferences.";
}
/* Groupings */
grouping address-family {
description
"This grouping provides a leaf identifying an address
family.";
leaf address-family {
type identityref {
base address-family;
}
mandatory true;
description
"Address family.";
}
}
grouping router-id {
description
"This grouping provides a router ID.";
leaf router-id {
type yang:dotted-quad;
description
"A 32-bit number in the form of a dotted quad that is used by
some routing protocols identifying a router.";
reference
"RFC 2328: OSPF Version 2";
}
}
grouping special-next-hop {
description
"This grouping provides a leaf with an enumeration of special
next hops.";
leaf special-next-hop {
type enumeration {
enum blackhole {
description
"Silently discard the packet.";
}
enum unreachable {
description
"Discard the packet and notify the sender with an error
message indicating that the destination host is
unreachable.";
}
enum prohibit {
description
"Discard the packet and notify the sender with an error
message indicating that the communication is
administratively prohibited.";
}
enum receive {
description
"The packet will be received by the local system.";
}
}
description
"Options for special next hops.";
}
}
grouping next-hop-content {
description
"Generic parameters of next hops in static routes.";
choice next-hop-options {
mandatory true;
description
"Options for next hops in static routes.
It is expected that further cases will be added through
augments from other modules.";
case simple-next-hop {
description
"This case represents a simple next hop consisting of the
next-hop address and/or outgoing interface.
Modules for address families MUST augment this case with a
leaf containing a next-hop address of that address
family.";
leaf outgoing-interface {
type if:interface-ref;
description
"Name of the outgoing interface.";
}
}
case special-next-hop {
uses special-next-hop;
}
case next-hop-list {
container next-hop-list {
description
"Container for multiple next hops.";
list next-hop {
key "index";
description
"An entry in a next-hop list.
Modules for address families MUST augment this list
with a leaf containing a next-hop address of that
address family.";
leaf index {
type string;
description
"A user-specified identifier utilized to uniquely
reference the next-hop entry in the next-hop list.
The value of this index has no semantic meaning
other than for referencing the entry.";
}
leaf outgoing-interface {
type if:interface-ref;
description
"Name of the outgoing interface.";
}
}
}
}
}
}
grouping next-hop-state-content {
description
"Generic state parameters of next hops.";
choice next-hop-options {
mandatory true;
description
"Options for next hops.
It is expected that further cases will be added through
augments from other modules, e.g., for recursive
next hops.";
case simple-next-hop {
description
"This case represents a simple next hop consisting of the
next-hop address and/or outgoing interface.
Modules for address families MUST augment this case with a
leaf containing a next-hop address of that address
family.";
leaf outgoing-interface {
type if:interface-ref;
description
"Name of the outgoing interface.";
}
}
case special-next-hop {
uses special-next-hop;
}
case next-hop-list {
container next-hop-list {
description
"Container for multiple next hops.";
list next-hop {
description
"An entry in a next-hop list.
Modules for address families MUST augment this list
with a leaf containing a next-hop address of that
address family.";
leaf outgoing-interface {
type if:interface-ref;
description
"Name of the outgoing interface.";
}
}
}
}
}
}
grouping route-metadata {
description
"Common route metadata.";
leaf source-protocol {
type identityref {
base routing-protocol;
}
mandatory true;
description
"Type of the routing protocol from which the route
originated.";
}
leaf active {
type empty;
description
"The presence of this leaf indicates that the route is
preferred among all routes in the same RIB that have the
same destination prefix.";
}
leaf last-updated {
type yang:date-and-time;
description
"Timestamp of the last modification of the route. If the
route was never modified, it is the time when the route was
inserted into the RIB.";
}
}
/* Data nodes */
container routing {
description
"Configuration parameters for the routing subsystem.";
uses router-id {
if-feature "router-id";
description
"Support for the global router ID. Routing protocols
that use a router ID can use this parameter or override it
with another value.";
}
container interfaces {
config false;
description
"Network-layer interfaces used for routing.";
leaf-list interface {
type if:interface-ref;
description
"Each entry is a reference to the name of a configured
network-layer interface.";
}
}
container control-plane-protocols {
description
"Support for control-plane protocol instances.";
list control-plane-protocol {
key "type name";
description
"Each entry contains a control-plane protocol instance.";
leaf type {
type identityref {
base control-plane-protocol;
}
description
"Type of the control-plane protocol -- an identity
derived from the 'control-plane-protocol'
base identity.";
}
leaf name {
type string;
description
"An arbitrary name of the control-plane protocol
instance.";
}
leaf description {
type string;
description
"Textual description of the control-plane protocol
instance.";
}
container static-routes {
when "derived-from-or-self(../type, 'rt:static')" {
description
"This container is only valid for the 'static' routing
protocol.";
}
description
"Support for the 'static' pseudo-protocol.
Address-family-specific modules augment this node with
their lists of routes.";
}
}
}
container ribs {
description
"Support for RIBs.";
list rib {
key "name";
description
"Each entry contains a configuration for a RIB identified
by the 'name' key.
Entries having the same key as a system-controlled entry
in the list '/routing/ribs/rib' are used for
configuring parameters of that entry. Other entries
define additional user-controlled RIBs.";
leaf name {
type string;
description
"The name of the RIB.
For system-controlled entries, the value of this leaf
must be the same as the name of the corresponding entry
in the operational state.
For user-controlled entries, an arbitrary name can be
used.";
}
uses address-family {
description
"The address family of the system-controlled RIB.";
}
leaf default-rib {
if-feature "multiple-ribs";
type boolean;
default "true";
config false;
description
"This flag has the value of 'true' if and only if the RIB
is the default RIB for the given address family.
By default, control-plane protocols place their routes
in the default RIBs.";
}
container routes {
config false;
description
"Current contents of the RIB.";
list route {
description
"A RIB route entry. This data node MUST be augmented
with information specific to routes of each address
family.";
leaf route-preference {
type route-preference;
description
"This route attribute, also known as 'administrative
distance', allows for selecting the preferred route
among routes with the same destination prefix. A
smaller value indicates a route that is
more preferred.";
}
container next-hop {
description
"Route's next-hop attribute.";
uses next-hop-state-content;
}
uses route-metadata;
}
}
action active-route {
description
"Return the active RIB route that is used for the
destination address.
Address-family-specific modules MUST augment input
parameters with a leaf named 'destination-address'.";
output {
container route {
description
"The active RIB route for the specified destination.
If no route exists in the RIB for the destination
address, no output is returned.
Address-family-specific modules MUST augment this
container with appropriate route contents.";
container next-hop {
description
"Route's next-hop attribute.";
uses next-hop-state-content;
}
uses route-metadata;
}
}
}
leaf description {
type string;
description
"Textual description of the RIB.";
}
}
}
}
/*
* The subsequent data nodes are obviated and obsoleted
* by the Network Management Datastore Architecture
* as described in RFC 8342.
*/
container routing-state {
config false;
status obsolete;
description
"State data of the routing subsystem.";
uses router-id {
status obsolete;
description
"Global router ID.
It may be either configured or assigned algorithmically by
the implementation.";
}
container interfaces {
status obsolete;
description
"Network-layer interfaces used for routing.";
leaf-list interface {
type if:interface-state-ref;
status obsolete;
description
"Each entry is a reference to the name of a configured
network-layer interface.";
}
}
container control-plane-protocols {
status obsolete;
description
"Container for the list of routing protocol instances.";
list control-plane-protocol {
key "type name";
status obsolete;
description
"State data of a control-plane protocol instance.
An implementation MUST provide exactly one
system-controlled instance of the 'direct'
pseudo-protocol. Instances of other control-plane
protocols MAY be created by configuration.";
leaf type {
type identityref {
base control-plane-protocol;
}
status obsolete;
description
"Type of the control-plane protocol.";
}
leaf name {
type string;
status obsolete;
description
"The name of the control-plane protocol instance.
For system-controlled instances, this name is
persistent, i.e., it SHOULD NOT change across
reboots.";
}
}
}
container ribs {
status obsolete;
description
"Container for RIBs.";
list rib {
key "name";
min-elements 1;
status obsolete;
description
"Each entry represents a RIB identified by the 'name'
key. All routes in a RIB MUST belong to the same address
family.
An implementation SHOULD provide one system-controlled
default RIB for each supported address family.";
leaf name {
type string;
status obsolete;
description
"The name of the RIB.";
}
uses address-family {
status obsolete;
description
"The address family of the RIB.";
}
leaf default-rib {
if-feature "multiple-ribs";
type boolean;
default "true";
status obsolete;
description
"This flag has the value of 'true' if and only if the
RIB is the default RIB for the given address family.
By default, control-plane protocols place their routes
in the default RIBs.";
}
container routes {
status obsolete;
description
"Current contents of the RIB.";
list route {
status obsolete;
description
"A RIB route entry. This data node MUST be augmented
with information specific to routes of each address
family.";
leaf route-preference {
type route-preference;
status obsolete;
description
"This route attribute, also known as 'administrative
distance', allows for selecting the preferred route
among routes with the same destination prefix. A
smaller value indicates a route that is
more preferred.";
}
container next-hop {
status obsolete;
description
"Route's next-hop attribute.";
uses next-hop-state-content {
status obsolete;
description
"Route's next-hop attribute operational state.";
}
}
uses route-metadata {
status obsolete;
description
"Route metadata.";
}
}
}
action active-route {
status obsolete;
description
"Return the active RIB route that is used for the
destination address.
Address-family-specific modules MUST augment input
parameters with a leaf named 'destination-address'.";
output {
container route {
status obsolete;
description
"The active RIB route for the specified
destination.
If no route exists in the RIB for the destination
address, no output is returned.
Address-family-specific modules MUST augment this
container with appropriate route contents.";
container next-hop {
status obsolete;
description
"Route's next-hop attribute.";
uses next-hop-state-content {
status obsolete;
description
"Active route state data.";
}
}
uses route-metadata {
status obsolete;
description
"Active route metadata.";
}
}
}
}
}
}
}
}