* Generilized top-level yang parsing functions

* Clarified semantics of main yang module:
    * -y option to commands MUST specify filename
    * CLICON_YANG_MODULE_MAIN MUST specify a module
    * yang_parse() changed to take either filename or module name and revision.
  * Removed clicon_dbspec_name[_set]().
    * Use yang_main_module_name() instead.
  * Replaced yang_spec_main with yang_spec_parse_module
  * Added yang_spec_parse_file
This commit is contained in:
Olof hagsand 2018-10-07 11:04:33 +02:00
parent 782f75a7b9
commit acb8748470
21 changed files with 369 additions and 340 deletions

View file

@ -3,14 +3,18 @@
## 3.8.0 (Upcoming) ## 3.8.0 (Upcoming)
### Major New features ### Major New features
### API changes on existing features (you may need to change your code)
* YANG Module Library support * YANG Module Library support
* According to RFC 7895 and implemented by ietf-yang-library.yang * According to RFC 7895 and implemented by ietf-yang-library.yang
* Supported: module, name, revision, namespace * Supported: module, name, revision, namespace
* Not supported: notification, deviation, module-set-id, etc. * Not supported: notification, deviation, module-set-id, etc.
* Enabled by default, disable by resetting CLICON_MODULE_LIBRARY_RFC7895 * Enabled by default, disable by resetting CLICON_MODULE_LIBRARY_RFC7895
* Yang 1.1 notification support (RFC 7950: Sec 7.16) * Yang 1.1 notification support (RFC 7950: Sec 7.16)
* Major rewrite of event streams
* See clicon_stream.[ch] for details
* Added stream discovery according to RFC 5277 for netconf and RFC 8040 for restconf
* Enabled by CLICON_STREAM_DISCOVERY_RFC5277 and CLICON_STREAM_DISCOVERY_RFC8040.
### API changes on existing features (you may need to change your code)
* Major rewrite of event streams * Major rewrite of event streams
* If you used old event callbacks API, you need to switch to the streams API * If you used old event callbacks API, you need to switch to the streams API
* See clixon_stream.[ch] * See clixon_stream.[ch]
@ -18,23 +22,30 @@
* clicon_log_register_callback() * clicon_log_register_callback()
* subscription_add() --> stream_register() * subscription_add() --> stream_register()
* backend_notify() and backend_notify_xml() - use stream_notify() instead * backend_notify() and backend_notify_xml() - use stream_notify() instead
* Added stream discovery according to RFC 5277 for netconf and RFC 8040 for restconf
* Enabled by CLICON_STREAM_DISCOVERY_RFC5277 and CLICON_STREAM_DISCOVERY_RFC8040.
* Example uses "NETCONF" stream instead of "ROUTING" * Example uses "NETCONF" stream instead of "ROUTING"
* clixon_restconf and clixon_netconf now take -D <level> as command-line option instead of just -D * clixon_restconf and clixon_netconf now take -D <level> as command-line option instead of just -D
* This aligns to clixon_cli and clixon_backend * This aligns to clixon_cli and clixon_backend
* Application command option -S to clixon_netconf is obsolete. Use `clixon_netconf -l s` instead. * Application command option -S to clixon_netconf is obsolete. Use `clixon_netconf -l s` instead.
### Minor changes
* Added timeout option -t for clixon_netconf - quit after max time.
* Comply to RFC 8040 3.5.3.1 rule: api-identifier = [module-name ":"] identifier
* The "module-name" was a no-op before.
* This means that there was no difference between eg: GET /restconf/data/ietf-yang-library:modules-state and GET /restconf/data/XXXX:modules-state
* Unified log handling for all clicon applications using -l e|o|s|f<file>. * Unified log handling for all clicon applications using -l e|o|s|f<file>.
* The options stand for e:stderr, o:stdout, s: syslog, f:file * The options stand for e:stderr, o:stdout, s: syslog, f:file
* Added file logging (`-l f` or `-l f<file>`) for cases where neither syslog nor stderr is useful. * Added file logging (`-l f` or `-l f<file>`) for cases where neither syslog nor stderr is useful.
* Comply to RFC 8040 3.5.3.1 rule: api-identifier = [module-name ":"] identifier
* The "module-name" was a no-op before.
* This means that there was no difference between eg: GET /restconf/data/ietf-yang-library:modules-state and GET /restconf/data/XXXX:modules-state
* Generilized top-level yang parsing functions
* Clarified semantics of main yang module:
* -y option to commands MUST specify filename
* CLICON_YANG_MODULE_MAIN MUST specify a module
* yang_parse() changed to take either filename or module name and revision.
* Removed clicon_dbspec_name[_set]().
* Use yang_main_module_name() instead.
* Replaced yang_spec_main with yang_spec_parse_module
* Added yang_spec_parse_file
### Minor changes
* Obsoleted COMPAT_CLIV and COMPAT_XSL that were optional in 3.7 * Obsoleted COMPAT_CLIV and COMPAT_XSL that were optional in 3.7
* Added timeout option -t for clixon_netconf - quit after max time.
* Added -l option for clixon_backend for directing syslog to stderr or stdout if running in foreground * Added -l option for clixon_backend for directing syslog to stderr or stdout if running in foreground
### Corrected Bugs ### Corrected Bugs

View file

@ -129,24 +129,24 @@ usage(clicon_handle h,
fprintf(stderr, "usage:%s\n" fprintf(stderr, "usage:%s\n"
"where options are\n" "where options are\n"
" -h\t\tHelp\n" "\t-h\t\tHelp\n"
" -D <level>\tDebug level\n" "\t-D <level>\tDebug level\n"
" -f <file>\tCLICON config file\n" "\t-f <file>\tCLICON config file\n"
" -l <s|e|o|f<file>> \tLog 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"
" -d <dir>\tSpecify backend plugin directory (default: %s)\n" "\t-d <dir>\tSpecify backend plugin directory (default: %s)\n"
" -b <dir>\tSpecify XMLDB database directory\n" "\t-b <dir>\tSpecify XMLDB database directory\n"
" -F\t\tRun in foreground, do not run as daemon\n" "\t-F\t\tRun in foreground, do not run as daemon\n"
" -z\t\tKill other config daemon and exit\n" "\t-z\t\tKill other config daemon and exit\n"
" -a UNIX|IPv4|IPv6\tInternal backend socket family\n" "\t-a UNIX|IPv4|IPv6 Internal backend socket family\n"
" -u <path|addr>\tInternal socket domain path or IP addr (see -a)(default: %s)\n" "\t-u <path|addr>\tInternal socket domain path or IP addr (see -a)(default: %s)\n"
" -P <file>\tPid filename (default: %s)\n" "\t-P <file>\tPid filename (default: %s)\n"
" -1\t\tRun once and then quit (dont wait for events)\n" "\t-1\t\tRun once and then quit (dont wait for events)\n"
" -s <mode>\tSpecify backend startup mode: none|startup|running|init (replaces -IRCr\n" "\t-s <mode>\tSpecify backend startup mode: none|startup|running|init)\n"
" -c <file>\tLoad extra xml configuration, but don't commit.\n" "\t-c <file>\tLoad extra xml configuration, but don't commit.\n"
" -g <group>\tClient membership required to this group (default: %s)\n" "\t-g <group>\tClient membership required to this group (default: %s)\n"
" -y <file>\tOverride yang spec file (dont include .yang suffix)\n" "\t-y <file>\tLoad yang spec file (override yang main module)\n"
" -x <plugin>\tXMLDB plugin\n", "\t-x <plugin>\tXMLDB plugin\n",
argv0, argv0,
plgdir ? plgdir : "none", plgdir ? plgdir : "none",
confsock ? confsock : "none", confsock ? confsock : "none",
@ -258,7 +258,7 @@ nacm_load_external(clicon_handle h)
} }
if ((yspec = yspec_new()) == NULL) if ((yspec = yspec_new()) == NULL)
goto done; goto done;
if (yang_parse(h, CLIXON_DATADIR, "ietf-netconf-acm", NULL, yspec) < 0) if (yang_parse(h, NULL, "ietf-netconf-acm", CLIXON_DATADIR, NULL, yspec) < 0)
goto done; goto done;
fd = fileno(f); fd = fileno(f);
/* Read configfile */ /* Read configfile */
@ -518,7 +518,9 @@ main(int argc,
int xml_pretty; int xml_pretty;
char *xml_format; char *xml_format;
char *nacm_mode; char *nacm_mode;
int logdst = CLICON_LOG_SYSLOG|CLICON_LOG_STDERR; int logdst = CLICON_LOG_SYSLOG|CLICON_LOG_STDERR;
yang_spec *yspec = NULL;
char *yang_filename = NULL;
/* In the startup, logs to stderr & syslog and debug flag set later */ /* In the startup, logs to stderr & syslog and debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst); clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
@ -638,8 +640,8 @@ main(int argc,
case 'g': /* config socket group */ case 'g': /* config socket group */
clicon_option_str_set(h, "CLICON_SOCK_GROUP", optarg); clicon_option_str_set(h, "CLICON_SOCK_GROUP", optarg);
break; break;
case 'y' :{ /* Override yang module or absolute filename */ case 'y' :{ /* Load yang spec file (override yang main module) */
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", optarg); yang_filename = optarg;
break; break;
} }
case 'x' :{ /* xmldb plugin */ case 'x' :{ /* xmldb plugin */
@ -727,18 +729,31 @@ main(int argc,
/* Connect to plugin to get a handle */ /* Connect to plugin to get a handle */
if (xmldb_connect(h) < 0) if (xmldb_connect(h) < 0)
goto done; goto done;
/* Read and parse application yang specification */ if ((yspec = yspec_new()) == NULL)
if (yang_spec_main(h) == NULL)
goto done; goto done;
clicon_dbspec_yang_set(h, yspec);
/* Read and parse application yang specification: either a module and search
* in dir, or a specific file
*/
if (yang_filename){
if (yang_spec_parse_file(h, yang_filename, clicon_yang_dir(h), yspec) < 0)
goto done;
}
else if (yang_spec_parse_module(h, clicon_yang_module_main(h),
clicon_yang_dir(h),
clicon_yang_module_revision(h),
yspec) < 0)
goto done;
/* Add system modules */ /* Add system modules */
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") && if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
yang_spec_append(h, CLIXON_DATADIR, "ietf-restconf-monitoring", NULL)< 0) yang_spec_parse_module(h, "ietf-restconf-monitoring", CLIXON_DATADIR, NULL, yspec)< 0)
goto done; goto done;
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") && if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") &&
yang_spec_append(h, CLIXON_DATADIR, "ietf-netconf-notification", NULL)< 0) yang_spec_parse_module(h, "ietf-netconf-notification", CLIXON_DATADIR, NULL, yspec)< 0)
goto done; goto done;
if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895") && if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895") &&
yang_spec_append(h, CLIXON_DATADIR, "ietf-yang-library", NULL)< 0) yang_spec_parse_module(h, "ietf-yang-library", CLIXON_DATADIR, NULL, yspec)< 0)
goto done; goto done;
/* Set options: database dir and yangspec (could be hidden in connect?)*/ /* Set options: database dir and yangspec (could be hidden in connect?)*/
if (xmldb_setopt(h, "dbdir", clicon_xmldb_dir(h)) < 0) if (xmldb_setopt(h, "dbdir", clicon_xmldb_dir(h)) < 0)

View file

@ -251,6 +251,7 @@ main(int argc, char **argv)
int dump_configfile_xml = 0; int dump_configfile_xml = 0;
yang_spec *yspec; yang_spec *yspec;
struct passwd *pw; struct passwd *pw;
char *yang_filename = NULL;
/* Defaults */ /* Defaults */
once = 0; once = 0;
@ -379,8 +380,8 @@ 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' :{ /* Overwrite yang module or absolute filename */ case 'y' :{ /* Load yang spec file (override yang main module) */
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", optarg); yang_filename = optarg;
break; break;
} }
case 'c' :{ /* Overwrite clispec with absolute filename */ case 'c' :{ /* Overwrite clispec with absolute filename */
@ -414,8 +415,19 @@ main(int argc, char **argv)
*/ */
cv_exclude_keys(clicon_cli_varonly(h)); cv_exclude_keys(clicon_cli_varonly(h));
/* Parse db specification as cli*/ if ((yspec = yspec_new()) == NULL)
if ((yspec = yang_spec_main(h)) == NULL) goto done;
clicon_dbspec_yang_set(h, yspec);
/* Parse db specification as cli.
* If -y <file> is given, it overrides main module */
if (yang_filename){
if (yang_spec_parse_file(h, yang_filename, clicon_yang_dir(h), yspec) < 0)
goto done;
}
else if (yang_spec_parse_module(h, clicon_yang_module_main(h),
clicon_yang_dir(h),
clicon_yang_module_revision(h),
yspec) < 0)
goto done; goto done;
if (printspec) if (printspec)
yang_print(stdout, (yang_node*)yspec); yang_print(stdout, (yang_node*)yspec);
@ -424,18 +436,21 @@ main(int argc, char **argv)
* the only one. * the only one.
*/ */
if (clicon_cli_genmodel(h)){ if (clicon_cli_genmodel(h)){
parse_tree pt = {0,}; /* cli parse tree */ parse_tree pt = {0,}; /* cli parse tree */
char *name; /* main module name */
/* Create cli command tree from dbspec */ /* Create cli command tree from dbspec */
if (yang2cli(h, yspec, &pt, clicon_cli_genmodel_type(h)) < 0) if (yang2cli(h, yspec, &pt, clicon_cli_genmodel_type(h)) < 0)
goto done; goto done;
len = strlen("datamodel:") + strlen(clicon_dbspec_name(h)) + 1; name = yang_main_module_name(yspec);
len = strlen("datamodel:") + strlen(name) + 1;
if ((treename = malloc(len)) == NULL){ if ((treename = malloc(len)) == NULL){
clicon_err(OE_UNIX, errno, "malloc"); clicon_err(OE_UNIX, errno, "malloc");
goto done; goto done;
} }
snprintf(treename, len, "datamodel:%s", clicon_dbspec_name(h)); snprintf(treename, len, "datamodel:%s", name);
cligen_tree_add(cli_cligen(h), treename, pt); cligen_tree_add(cli_cligen(h), treename, pt);
if (printgen) if (printgen)

View file

@ -276,8 +276,6 @@ netconf_terminate(clicon_handle h)
clicon_rpc_close_session(h); clicon_rpc_close_session(h);
if ((yspec = clicon_dbspec_yang(h)) != NULL) if ((yspec = clicon_dbspec_yang(h)) != NULL)
yspec_free(yspec); yspec_free(yspec);
if ((yspec = clicon_netconf_yang(h)) != NULL)
yspec_free(yspec);
event_exit(); event_exit();
clicon_handle_exit(h); clicon_handle_exit(h);
clicon_log_exit(); clicon_log_exit();
@ -306,12 +304,12 @@ usage(clicon_handle h,
"\t-D <level>\tDebug level\n" "\t-D <level>\tDebug level\n"
"\t-q\t\tQuiet: dont send hello prompt\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-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-y <file>\tOverride yang spec file (dont include .yang suffix)\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",
argv0, argv0,
@ -333,7 +331,9 @@ main(int argc,
int logdst = CLICON_LOG_STDERR; int logdst = CLICON_LOG_STDERR;
struct passwd *pw; struct passwd *pw;
struct timeval tv = {0,}; /* timeout */ struct timeval tv = {0,}; /* timeout */
yang_spec *yspec = NULL;
char *yang_filename = NULL;
/* Create handle */ /* Create handle */
if ((h = clicon_handle_init()) == NULL) if ((h = clicon_handle_init()) == NULL)
return -1; return -1;
@ -407,8 +407,8 @@ main(int argc,
usage(h, argv[0]); usage(h, argv[0]);
clicon_option_str_set(h, "CLICON_NETCONF_DIR", optarg); clicon_option_str_set(h, "CLICON_NETCONF_DIR", optarg);
break; break;
case 'y' :{ /* Overwrite yang module or absolute filename */ case 'y' :{ /* Load yang spec file (override yang main module) */
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", optarg); yang_filename = optarg;
break; break;
} }
case 'U': /* Clixon 'pseudo' user */ case 'U': /* Clixon 'pseudo' user */
@ -428,13 +428,23 @@ main(int argc,
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if ((yspec = yspec_new()) == NULL)
goto done;
clicon_dbspec_yang_set(h, yspec);
/* Parse yang database spec file */ /* Parse yang database spec file */
if (yang_spec_main(h) == NULL) if (yang_filename){
goto done; if (yang_spec_parse_file(h, yang_filename, clicon_yang_dir(h), yspec) < 0)
goto done;
/* Parse netconf yang spec file */ }
if (yang_spec_netconf(h) == NULL) else if (yang_spec_parse_module(h, clicon_yang_module_main(h),
clicon_yang_dir(h),
clicon_yang_module_revision(h),
yspec) < 0)
goto done; goto done;
/* Add netconf yang spec, used by netconf client and as internal protocol */
if (yang_spec_parse_module(h, "ietf-yang-library", CLIXON_DATADIR, NULL, yspec)< 0)
goto done;
/* Initialize plugins group */ /* Initialize plugins group */
if ((dir = clicon_netconf_dir(h)) != NULL) if ((dir = clicon_netconf_dir(h)) != NULL)

View file

@ -955,15 +955,9 @@ netconf_rpc_dispatch(clicon_handle h,
{ {
int retval = -1; int retval = -1;
cxobj *xe; cxobj *xe;
yang_spec *yspec = NULL;
char *username; char *username;
cxobj *xa; cxobj *xa;
/* Check incoming RPC against system / netconf RPC:s */
if ((yspec = clicon_netconf_yang(h)) == NULL){
clicon_err(OE_YANG, ENOENT, "No netconf yang spec");
goto done;
}
/* Tag username on all incoming requests in case they are forwarded as internal messages /* Tag username on all incoming requests in case they are forwarded as internal messages
* This may be unecesary since not all are forwarded. * This may be unecesary since not all are forwarded.
* It may even be wrong if something else is done with the incoming message? * It may even be wrong if something else is done with the incoming message?

View file

@ -494,7 +494,7 @@ usage(clicon_handle h,
"\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-d <dir>\tSpecify restconf plugin directory dir (default: %s)\n" "\t-d <dir>\tSpecify restconf plugin directory dir (default: %s)\n"
"\t-y <file>\tOverride yang spec file (dont include .yang suffix)\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"
"\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",
argv0, argv0,
@ -522,6 +522,8 @@ main(int argc,
char *dir; char *dir;
char *tmp; char *tmp;
int logdst = CLICON_LOG_SYSLOG; int logdst = CLICON_LOG_SYSLOG;
yang_spec *yspec = NULL;
char *yang_filename = NULL;
/* In the startup, logs to stderr & debug flag set later */ /* In the startup, logs to stderr & debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst); clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
@ -589,8 +591,8 @@ main(int argc,
usage(h, argv[0]); usage(h, argv[0]);
clicon_option_str_set(h, "CLICON_RESTCONF_DIR", optarg); clicon_option_str_set(h, "CLICON_RESTCONF_DIR", optarg);
break; break;
case 'y' : /* yang module */ case 'y' : /* Load yang spec file (override yang main module) */
yangspec = optarg; yang_filename = optarg;
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); clicon_option_str_set(h, "CLICON_SOCK_FAMILY", optarg);
@ -616,18 +618,28 @@ main(int argc,
if (clixon_plugins_load(h, CLIXON_PLUGIN_INIT, dir, NULL) < 0) if (clixon_plugins_load(h, CLIXON_PLUGIN_INIT, dir, NULL) < 0)
return -1; return -1;
/* Parse yang database spec file */ /* Parse main yang spec */
if (yang_spec_main(h) == NULL) if ((yspec = yspec_new()) == NULL)
goto done;
clicon_dbspec_yang_set(h, yspec);
if (yang_filename){
if (yang_spec_parse_file(h, yang_filename, clicon_yang_dir(h), yspec) < 0)
goto done;
}
else if (yang_spec_parse_module(h, clicon_yang_module_main(h),
clicon_yang_dir(h),
clicon_yang_module_revision(h),
yspec) < 0)
goto done; goto done;
/* Add system modules */ /* Add system modules */
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") && if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
yang_spec_append(h, CLIXON_DATADIR, "ietf-restconf-monitoring", NULL)< 0) yang_spec_parse_module(h, "ietf-restconf-monitoring", CLIXON_DATADIR, NULL, yspec)< 0)
goto done; goto done;
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") && if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") &&
yang_spec_append(h, CLIXON_DATADIR, "ietf-netconf-notification", NULL)< 0) yang_spec_parse_module(h, "ietf-netconf-notification", CLIXON_DATADIR, NULL, yspec)< 0)
goto done; goto done;
if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895") && if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895") &&
yang_spec_append(h, CLIXON_DATADIR, "ietf-yang-library", NULL)< 0) yang_spec_parse_module(h, "ietf-yang-library", CLIXON_DATADIR, NULL, yspec)< 0)
goto done; goto done;
if (stream_register(h, "NETCONF", "default NETCONF event stream") < 0) if (stream_register(h, "NETCONF", "default NETCONF event stream") < 0)

View file

@ -206,7 +206,7 @@ main(int argc, char **argv)
if ((yspec = yspec_new()) == NULL) if ((yspec = yspec_new()) == NULL)
goto done; goto done;
/* Parse yang spec from given file */ /* Parse yang spec from given file */
if (yang_parse(h, yangdir, yangmodule, NULL, yspec) < 0) if (yang_parse(h, NULL, yangmodule, yangdir, NULL, yspec) < 0)
goto done; goto done;
/* Set database directory option */ /* Set database directory option */
if (xmldb_setopt(h, "dbdir", dbdir) < 0) if (xmldb_setopt(h, "dbdir", dbdir) < 0)

View file

@ -1387,7 +1387,7 @@ main(int argc,
db_init(db); db_init(db);
if ((yspec = yspec_new()) == NULL) if ((yspec = yspec_new()) == NULL)
goto done goto done
if (yang_parse(h, yangdir, yangmod, NULL, yspec) < 0) if (yang_parse(h, NULL, yangmod, yangdir, NULL, yspec) < 0)
goto done; goto done;
if (strcmp(cmd, "get")==0){ if (strcmp(cmd, "get")==0){
if (argc < 5) if (argc < 5)

View file

@ -44,6 +44,7 @@
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/syslog.h>
/* clicon */ /* clicon */
#include <cligen/cligen.h> #include <cligen/cligen.h>
@ -119,7 +120,7 @@ clixon_plugin_init(clicon_handle h)
clicon_debug(1, "%s backend nacm", __FUNCTION__); clicon_debug(1, "%s backend nacm", __FUNCTION__);
nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE"); nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE");
if (nacm_mode==NULL || strcmp(nacm_mode, "disabled") == 0){ if (nacm_mode==NULL || strcmp(nacm_mode, "disabled") == 0){
clicon_debug(1, "%s CLICON_NACM_MODE not enabled: example nacm module disabled", __FUNCTION__); clicon_log(LOG_WARNING, "%s CLICON_NACM_MODE not enabled: example nacm module disabled", __FUNCTION__);
return NULL; return NULL;
} }
return &api; return &api;

View file

@ -164,12 +164,6 @@ int clicon_quiet_mode_set(clicon_handle h, int val);
yang_spec * clicon_dbspec_yang(clicon_handle h); yang_spec * clicon_dbspec_yang(clicon_handle h);
int clicon_dbspec_yang_set(clicon_handle h, struct yang_spec *ys); int clicon_dbspec_yang_set(clicon_handle h, struct yang_spec *ys);
char *clicon_dbspec_name(clicon_handle h);
int clicon_dbspec_name_set(clicon_handle h, char *name);
yang_spec *clicon_netconf_yang(clicon_handle h);
int clicon_netconf_yang_set(clicon_handle h, struct yang_spec *ys);
plghndl_t clicon_xmldb_plugin_get(clicon_handle h); plghndl_t clicon_xmldb_plugin_get(clicon_handle h);
int clicon_xmldb_plugin_set(clicon_handle h, plghndl_t handle); int clicon_xmldb_plugin_set(clicon_handle h, plghndl_t handle);

View file

@ -244,6 +244,7 @@ yang_stmt *ys_dup(yang_stmt *old);
int yn_insert(yang_node *yn_parent, yang_stmt *ys_child); int yn_insert(yang_node *yn_parent, yang_stmt *ys_child);
yang_stmt *yn_each(yang_node *yn, yang_stmt *ys); yang_stmt *yn_each(yang_node *yn, yang_stmt *ys);
char *yang_key2str(int keyword); char *yang_key2str(int keyword);
char *yang_main_module_name(yang_spec *ysp);
char *yarg_prefix(yang_stmt *ys); char *yarg_prefix(yang_stmt *ys);
char *yarg_id(yang_stmt *ys); char *yarg_id(yang_stmt *ys);
int yang_nodeid_split(char *nodeid, char **prefix, char **id); int yang_nodeid_split(char *nodeid, char **prefix, char **id);
@ -260,8 +261,9 @@ int yang_print(FILE *f, yang_node *yn);
int yang_print_cbuf(cbuf *cb, yang_node *yn, int marginal); int yang_print_cbuf(cbuf *cb, yang_node *yn, int marginal);
int ys_populate(yang_stmt *ys, void *arg); int ys_populate(yang_stmt *ys, void *arg);
yang_stmt *yang_parse_file(int fd, const char *name, yang_spec *ysp); yang_stmt *yang_parse_file(int fd, const char *name, yang_spec *ysp);
int yang_parse(clicon_handle h, const char *yang_dir, int yang_parse(clicon_handle h, const char *filename,
const char *module, const char *revision, yang_spec *ysp); const char *module, const char *dir,
const char *revision, yang_spec *ysp);
int yang_apply(yang_node *yn, enum rfc_6020 key, yang_applyfn_t fn, int yang_apply(yang_node *yn, enum rfc_6020 key, yang_applyfn_t fn,
void *arg); void *arg);
int yang_abs_schema_nodeid(yang_spec *yspec, char *schema_nodeid, int yang_abs_schema_nodeid(yang_spec *yspec, char *schema_nodeid,
@ -272,9 +274,8 @@ cg_var *ys_parse(yang_stmt *ys, enum cv_type cvtype);
int ys_parse_sub(yang_stmt *ys, char *extra); int ys_parse_sub(yang_stmt *ys, char *extra);
int yang_mandatory(yang_stmt *ys); int yang_mandatory(yang_stmt *ys);
int yang_config(yang_stmt *ys); int yang_config(yang_stmt *ys);
yang_spec *yang_spec_netconf(clicon_handle h); int yang_spec_parse_module(clicon_handle h, char *module, char *dir, char *revision, yang_spec *yspec);
yang_spec *yang_spec_main(clicon_handle h); int yang_spec_parse_file(clicon_handle h, char *filename, char *dir, yang_spec *yspec);
int yang_spec_append(clicon_handle h, char *yang_dir, char *yang_module, char *yang_revision);
cvec *yang_arg2cvec(yang_stmt *ys, char *delimi); cvec *yang_arg2cvec(yang_stmt *ys, char *delimi);
int yang_key_match(yang_node *yn, char *name); int yang_key_match(yang_node *yn, char *name);

View file

@ -216,7 +216,7 @@ clicon_options_main(clicon_handle h)
if (xml){ /* Read clixon yang file */ if (xml){ /* Read clixon yang file */
if ((yspec = yspec_new()) == NULL) if ((yspec = yspec_new()) == NULL)
goto done; goto done;
if (yang_parse(h, CLIXON_DATADIR, "clixon-config", NULL, yspec) < 0) if (yang_parse(h, NULL, "clixon-config", CLIXON_DATADIR, NULL, yspec) < 0)
goto done; goto done;
/* Read configfile */ /* Read configfile */
if (clicon_option_readfile_xml(copt, configfile, yspec) < 0) if (clicon_option_readfile_xml(copt, configfile, yspec) < 0)
@ -571,58 +571,6 @@ clicon_dbspec_yang_set(clicon_handle h,
return 0; return 0;
} }
/*! Get YANG NETCONF specification
* Must use hash functions directly since they are not strings.
*/
yang_spec *
clicon_netconf_yang(clicon_handle h)
{
clicon_hash_t *cdat = clicon_data(h);
size_t len;
void *p;
if ((p = hash_value(cdat, "netconf_yang", &len)) != NULL)
return *(yang_spec **)p;
return NULL;
}
/*! Set yang netconf specification
* ys must be a malloced pointer
*/
int
clicon_netconf_yang_set(clicon_handle h,
struct yang_spec *ys)
{
clicon_hash_t *cdat = clicon_data(h);
/* It is the pointer to ys that should be copied by hash,
so we send a ptr to the ptr to indicate what to copy.
*/
if (hash_add(cdat, "netconf_yang", &ys, sizeof(ys)) == NULL)
return -1;
return 0;
}
/*! Get dbspec name as read from spec. Can be used in CLI '@' syntax.
* XXX: this we muśt change,...
*/
char *
clicon_dbspec_name(clicon_handle h)
{
if (!clicon_option_exists(h, "dbspec_name"))
return NULL;
return clicon_option_str(h, "dbspec_name");
}
/*! Set dbspec name as read from spec. Can be used in CLI '@' syntax.
*/
int
clicon_dbspec_name_set(clicon_handle h, char *name)
{
return clicon_option_str_set(h, "dbspec_name", name);
}
/*! Get xmldb datastore plugin handle, as used by dlopen/dlsym/dlclose */ /*! Get xmldb datastore plugin handle, as used by dlopen/dlsym/dlclose */
plghndl_t plghndl_t
clicon_xmldb_plugin_get(clicon_handle h) clicon_xmldb_plugin_get(clicon_handle h)

View file

@ -344,6 +344,8 @@ ys_dup(yang_stmt *old)
/*! Insert yang statement as child of a parent yang_statement, last in list /*! Insert yang statement as child of a parent yang_statement, last in list
* *
* @param[in] yn_parent Add child to this parent
* @param[in] ys_child Add this child
* Also add parent to child as up-pointer * Also add parent to child as up-pointer
*/ */
int int
@ -607,7 +609,6 @@ yang_find_schemanode(yang_node *yn,
return ysmatch; return ysmatch;
} }
/*! Find first matching data node in all (sub)modules in a yang spec /*! Find first matching data node in all (sub)modules in a yang spec
* *
* @param[in] ysp Yang specification * @param[in] ysp Yang specification
@ -756,7 +757,22 @@ yang_key2str(int keyword)
return (char*)clicon_int2str(ykmap, keyword); return (char*)clicon_int2str(ykmap, keyword);
} }
/*! Find top module or sub-module. Note that ultimate top is yang spec /*! Name of main module of a specification. That is, name of first module
* @param[in] ysp Yang specification
* @retval name Name of first yang module
*/
char *
yang_main_module_name(yang_spec *ysp)
{
yang_stmt *ym;
if ((ym = yang_find((yang_node*)ysp, Y_MODULE, 0)) != NULL)
return ym->ys_argument;
return NULL;
}
/*! Find top module or sub-module given a statement. Ultimate top is yang spec
* The routine recursively finds ancestors.
* @param[in] ys Any yang statement in a yang tree * @param[in] ys Any yang statement in a yang tree
* @retval ymod The top module or sub-module * @retval ymod The top module or sub-module
* @see ys_spec * @see ys_spec
@ -1611,8 +1627,9 @@ yang_expand(yang_node *yn)
* @retval NULL Error encountered * @retval NULL Error encountered
* Calling order: * Calling order:
* yang_parse # Parse top-level yang module. Expand and populate yang tree * yang_parse # Parse top-level yang module. Expand and populate yang tree
* yang_parse_recurse # Parse one yang module, go through its (sub)modules, parse them and then recursively parse them * yang_parse_recurse # Parse one yang module, go through its (sub)modules, parse them and then recursively parse them
* yang_parse_file # Read yang file into a string * yang_parse_filename # Read yang file into a string
* yang_parse_file # Read yang open file descriptor into a string
* yang_parse_str # Set up yacc parser and call it given a string * yang_parse_str # Set up yacc parser and call it given a string
* clixon_yang_parseparse # Actual yang parsing using yacc * clixon_yang_parseparse # Actual yang parsing using yacc
*/ */
@ -1712,49 +1729,6 @@ yang_parse_file(int fd,
return ymod; /* top-level (sub)module */ return ymod; /* top-level (sub)module */
} }
/*! Open a file, read into a string and invoke yang parsing
*
* Similar to clicon_yang_str(), just read a file first
* (cloned from cligen)
* @param[in] h CLICON handle
* @param[in] filename Name of file
* @param[in] ysp Yang specification. Should ave been created by caller using yspec_new
* @retval ymod Top-level yang (sub)module
* @retval NULL Error encountered
* The database symbols are inserted in alphabetical order.
* Calling order:
* yang_parse # Parse top-level yang module. Expand and populate yang tree
* yang_parse_recurse # Parse one yang module, go through its (sub)modules, parse them and then recursively parse them
* yang_parse_file # Read yang file into a string
* yang_parse_str # Set up yacc parser and call it given a string
* clixon_yang_parseparse # Actual yang parsing using yacc
*/
static yang_stmt *
yang_parse_filename(const char *filename,
yang_spec *ysp)
{
yang_stmt *ymod = NULL;
int fd = -1;
struct stat st;
clicon_log(LOG_DEBUG, "Parsing yang file: %s", filename);
if (stat(filename, &st) < 0){
clicon_err(OE_YANG, errno, "%s not found", filename);
goto done;
}
if ((fd = open(filename, O_RDONLY)) < 0){
clicon_err(OE_YANG, errno, "open(%s)", filename);
goto done;
}
if ((ymod = yang_parse_file(fd, filename, ysp)) < 0)
goto done;
done:
if (fd != -1)
close(fd);
return ymod; /* top-level (sub)module */
}
/*! No specific revision give. Match a yang file given dir and module /*! No specific revision give. Match a yang file given dir and module
* @param[in] h CLICON handle * @param[in] h CLICON handle
* @param[in] yang_dir Directory where all YANG module files reside * @param[in] yang_dir Directory where all YANG module files reside
@ -1805,6 +1779,82 @@ yang_parse_find_match(const char *yang_dir,
return retval; return retval;
} }
/*! Open a file, read into a string and invoke yang parsing
*
* Similar to clicon_yang_str(), just read a file first
* (cloned from cligen)
* @param[in] h CLICON handle
* @param[in] filename Name of file
* @param[in] ysp Yang specification. Should ave been created by caller using yspec_new
* @retval ymod Top-level yang (sub)module
* @retval NULL Error encountered
* The database symbols are inserted in alphabetical order.
* Calling order:
* yang_parse # Parse top-level yang module. Expand and populate yang tree
* yang_parse_recurse # Parse one yang module, go through its (sub)modules, parse them and then recursively parse them
* yang_parse_filename # Read yang file into a string
* yang_parse_file # Read yang open file descriptor into a string
* yang_parse_str # Set up yacc parser and call it given a string
* clixon_yang_parseparse # Actual yang parsing using yacc
*/
static yang_stmt *
yang_parse_filename(const char *filename,
yang_spec *ysp)
{
yang_stmt *ymod = NULL;
int fd = -1;
struct stat st;
clicon_log(LOG_DEBUG, "Parsing yang file: %s", filename);
if (stat(filename, &st) < 0){
clicon_err(OE_YANG, errno, "%s not found", filename);
goto done;
}
if ((fd = open(filename, O_RDONLY)) < 0){
clicon_err(OE_YANG, errno, "open(%s)", filename);
goto done;
}
if ((ymod = yang_parse_file(fd, filename, ysp)) < 0)
goto done;
done:
if (fd != -1)
close(fd);
return ymod; /* top-level (sub)module */
}
static yang_stmt *
yang_parse_module(const char *module,
const char *dir,
const char *revision,
yang_spec *ysp)
{
cbuf *fbuf = NULL;
int nr;
yang_stmt *ymod = NULL;
if ((fbuf = cbuf_new()) == NULL){
clicon_err(OE_YANG, errno, "cbuf_new");
goto done;
}
if (revision)
cprintf(fbuf, "%s/%s@%s.yang", dir, module, revision);
else{
/* No specific revision, Match a yang file */
if ((nr = yang_parse_find_match(dir, module, fbuf)) < 0)
goto done;
if (nr == 0){
clicon_err(OE_YANG, errno, "No matching %s yang files found in %s (expected module name or absolute filename)", module, dir);
goto done;
}
}
if ((ymod = yang_parse_filename(cbuf_get(fbuf), ysp)) == NULL)
goto done;
done:
return ymod; /* top-level (sub)module */
}
/*! Parse one yang module then go through (sub)modules and parse them recursively /*! Parse one yang module then go through (sub)modules and parse them recursively
* *
* @param[in] h CLICON handle * @param[in] h CLICON handle
@ -1818,68 +1868,44 @@ yang_parse_find_match(const char *yang_dir,
* Calling order: * Calling order:
* yang_parse # Parse top-level yang module. Expand and populate yang tree * yang_parse # Parse top-level yang module. Expand and populate yang tree
* yang_parse_recurse # Parse one yang module, go through its (sub)modules, parse them and then recursively parse them * yang_parse_recurse # Parse one yang module, go through its (sub)modules, parse them and then recursively parse them
* yang_parse_file # Read yang file into a string * yang_parse_filename # Read yang file into a string
* yang_parse_file # Read yang open file descriptor into a string
* yang_parse_str # Set up yacc parser and call it given a string * yang_parse_str # Set up yacc parser and call it given a string
* clixon_yang_parseparse # Actual yang parsing using yacc * clixon_yang_parseparse # Actual yang parsing using yacc
*/ */
static yang_stmt * static int
yang_parse_recurse(const char *yang_dir, yang_parse_recurse(yang_stmt *ymod,
const char *module, const char *dir,
const char *revision,
yang_spec *ysp) yang_spec *ysp)
{ {
int retval = -1;
yang_stmt *yi = NULL; /* import */ yang_stmt *yi = NULL; /* import */
yang_stmt *ymod = NULL;
yang_stmt *yrev; yang_stmt *yrev;
char *modname; char *submodule;
char *subrevision; char *subrevision;
cbuf *fbuf = NULL; yang_stmt *subymod;
int nr;
if (module[0] == '/'){
if ((ymod = yang_parse_filename(module, ysp)) == NULL)
goto done;
}
else {
if ((fbuf = cbuf_new()) == NULL){
clicon_err(OE_YANG, errno, "cbuf_new");
goto done;
}
if (revision)
cprintf(fbuf, "%s/%s@%s.yang", yang_dir, module, revision);
else{
/* No specific revision, Match a yang file */
if ((nr = yang_parse_find_match(yang_dir, module, fbuf)) < 0)
goto done;
if (nr == 0){
clicon_err(OE_YANG, errno, "No matching %s yang files found in %s (expected module name or absolute filename)", module, yang_dir);
goto done;
}
}
if ((ymod = yang_parse_filename(cbuf_get(fbuf), ysp)) == NULL)
goto done;
}
/* go through all import statements of ysp (or its module) */ /* go through all import statements of ysp (or its module) */
while ((yi = yn_each((yang_node*)ymod, yi)) != NULL){ while ((yi = yn_each((yang_node*)ymod, yi)) != NULL){
if (yi->ys_keyword != Y_IMPORT) if (yi->ys_keyword != Y_IMPORT)
continue; continue;
modname = yi->ys_argument; submodule = yi->ys_argument;
if ((yrev = yang_find((yang_node*)yi, Y_REVISION_DATE, NULL)) != NULL) if ((yrev = yang_find((yang_node*)yi, Y_REVISION_DATE, NULL)) != NULL)
subrevision = yrev->ys_argument; subrevision = yrev->ys_argument;
else else
subrevision = NULL; subrevision = NULL;
if (yang_find((yang_node*)ysp, Y_MODULE, modname) == NULL) if (yang_find((yang_node*)ysp, Y_MODULE, submodule) == NULL)
/* recursive call */ /* recursive call */
if (yang_parse_recurse(yang_dir, modname, subrevision, ysp) == NULL){ if ((subymod = yang_parse_module(submodule, dir, subrevision, ysp)) == NULL)
goto done;
if (yang_parse_recurse(subymod, dir, ysp) < 0){
ymod = NULL; ymod = NULL;
goto done; goto done;
} }
} }
done: retval = 0;
if (fbuf) done:
cbuf_free(fbuf); return retval; /* top-level (sub)module */
return ymod; /* top-level (sub)module */
} }
int int
@ -1929,7 +1955,8 @@ ys_schemanode_check(yang_stmt *ys,
* *
* @param[in] h CLICON handle * @param[in] h CLICON handle
* @param[in] yang_dir Directory where all YANG module files reside (except mainfile) * @param[in] yang_dir Directory where all YANG module files reside (except mainfile)
* @param[in] mainmod Name of main YANG module. Or absolute file name. * @param[in] filename File name containing Yang specification. Overrides module
* @param[in] module Name of main YANG module. Or absolute file name.
* @param[in] revision Main module revision date string or NULL * @param[in] revision Main module revision date string or NULL
* @param[out] ysp Yang specification. Should have been created by caller using yspec_new * @param[out] ysp Yang specification. Should have been created by caller using yspec_new
* @retval 0 Everything OK * @retval 0 Everything OK
@ -1941,34 +1968,49 @@ ys_schemanode_check(yang_stmt *ys,
* yang_parse # Parse top-level yang module. Expand and populate yang tree * yang_parse # Parse top-level yang module. Expand and populate yang tree
* yang_parse_recurse # Parse one yang module, go through its (sub)modules, * yang_parse_recurse # Parse one yang module, go through its (sub)modules,
* parse them and then recursively parse them * parse them and then recursively parse them
* yang_parse_file # Read yang file into a string * yang_parse_filename # Read yang file into a string
* yang_parse_file # Read yang open file descriptor into a string
* yang_parse_str # Set up yacc parser and call it given a string * yang_parse_str # Set up yacc parser and call it given a string
* clixon_yang_parseparse # Actual yang parsing using yacc * clixon_yang_parseparse # Actual yang parsing using yacc
*/ */
int int
yang_parse(clicon_handle h, yang_parse(clicon_handle h,
const char *yang_dir, const char *filename,
const char *mainmodule, const char *module,
const char *dir,
const char *revision, const char *revision,
yang_spec *ysp) yang_spec *ysp)
{ {
int retval = -1; int retval = -1;
yang_stmt *ymod; /* Top-level yang (sub)module */ yang_stmt *ymod = NULL; /* Top-level yang (sub)module */
int i;
int modnr; /* Existing number of modules */
modnr = ysp->yp_len;
if (filename){
if ((ymod = yang_parse_filename(filename, ysp)) == NULL)
goto done;
}
else
if ((ymod = yang_parse_module(module, dir, revision, ysp)) == NULL)
goto done;
/* From here on, apply actions on new modules, ie ones after modnr. */
/* Step 1: parse from text to yang parse-tree. */ /* Step 1: parse from text to yang parse-tree. */
if ((ymod = yang_parse_recurse(yang_dir, mainmodule, revision, ysp)) == NULL) /* Iterate through modules */
if (yang_parse_recurse(ymod, dir, ysp) < 0)
goto done; goto done;
/* Add top module name as dbspec-name */
clicon_dbspec_name_set(h, ymod->ys_argument);
/* Step 2: Go through parse tree and populate it with cv types */ /* Step 2: Go through parse tree and populate it with cv types */
if (yang_apply((yang_node*)ysp, -1, ys_populate, NULL) < 0) for (i=modnr; i<ysp->yp_len; i++)
goto done; if (yang_apply((yang_node*)ysp->yp_stmt[i], -1, ys_populate, NULL) < 0)
goto done;
/* Step 3: Resolve all types: populate type caches. Requires eg length/range cvecs /* Step 3: Resolve all types: populate type caches. Requires eg length/range cvecs
* from ys_populate step * from ys_populate step
*/ */
yang_apply((yang_node*)ysp, Y_TYPE, ys_resolve_type, NULL); for (i=modnr; i<ysp->yp_len; i++)
yang_apply((yang_node*)ysp->yp_stmt[i], Y_TYPE, ys_resolve_type, NULL);
/* Up to here resolving is made in the context they are defined, rather than the /* Up to here resolving is made in the context they are defined, rather than the
context they are used. Like static scoping. After this we expand all context they are used. Like static scoping. After this we expand all
@ -1976,17 +2018,20 @@ yang_parse(clicon_handle h,
*/ */
/* Step 4: Macro expansion of all grouping/uses pairs. Expansion needs marking */ /* Step 4: Macro expansion of all grouping/uses pairs. Expansion needs marking */
if (yang_expand((yang_node*)ysp) < 0) for (i=modnr; i<ysp->yp_len; i++){
goto done; if (yang_expand((yang_node*)ysp->yp_stmt[i]) < 0)
yang_apply((yang_node*)ymod, -1, ys_flag_reset, (void*)YANG_FLAG_MARK); goto done;
yang_apply((yang_node*)ysp->yp_stmt[i], -1, ys_flag_reset, (void*)YANG_FLAG_MARK);
}
/* Step 4: Top-level augmentation of all modules */ /* Step 4: Top-level augmentation of all modules XXX: only new modules? */
if (yang_augment_spec(ysp) < 0) if (yang_augment_spec(ysp) < 0)
goto done; goto done;
/* sanity check of schemanode references, need more here */ /* sanity check of schemanode references, need more here */
if (yang_apply((yang_node*)ysp, -1, ys_schemanode_check, NULL) < 0) for (i=modnr; i<ysp->yp_len; i++)
goto done; if (yang_apply((yang_node*)ysp->yp_stmt[i], -1, ys_schemanode_check, NULL) < 0)
goto done;
retval = 0; retval = 0;
done: done:
@ -2405,94 +2450,84 @@ yang_config(yang_stmt *ys)
return 1; return 1;
} }
/*! Parse netconf yang spec, used by netconf client and as internal protocol /*! Parse yang specification and its dependencies recursively given module
* @note not used yet - unfinnisshed code * @param[in] h clicon handle
*/ * @param[in] module Module name, or absolute filename (including dir)
yang_spec * * @param[in] dir Directory where to look for modules and sub-modules
yang_spec_netconf(clicon_handle h) * @param[in] revision Revision, or NULL
{ * @param[in,out] yspec Modules parse are added to this yangspec
yang_spec *yspec = NULL; * @retval 0 OK
* @retval -1 Error
if ((yspec = yspec_new()) == NULL) * @see yang_spec_parse_file
goto done;
if (yang_parse(h, CLIXON_DATADIR, "ietf-netconf", NULL, yspec) < 0){
yspec_free(yspec); yspec = NULL;
goto done;
}
clicon_netconf_yang_set(h, yspec);
done:
return yspec;
}
/*! Parse yang specification and its dependencies recursively and return
* @param[in] h clicon handle
*/
yang_spec*
yang_spec_main(clicon_handle h)
{
yang_spec *yspec = NULL;
char *yang_module;
char *yang_revision;
char *yang_dir;
if ((yang_dir = clicon_yang_dir(h)) == NULL){
clicon_err(OE_FATAL, 0, "CLICON_YANG_DIR option not set");
goto done;
}
/* Yang module is either specific absolute filename, or main module */
if ((yang_module = clicon_yang_module_main(h)) == NULL){
clicon_err(OE_FATAL, 0, "CLICON_YANG_MODULE_MAIN option not set");
goto done;
}
yang_revision = clicon_yang_module_revision(h);
if ((yspec = yspec_new()) == NULL)
goto done;
if (yang_parse(h, yang_dir, yang_module, yang_revision, yspec) < 0){
yspec_free(yspec); yspec = NULL;
goto done;
}
clicon_dbspec_yang_set(h, yspec);
done:
return yspec;
}
/*! Parse yang specification, its dependencies, and append to default yang spec
* yang_spec_main should have been called first.
* @param[in] h clicon handle
* @param[in] yang_dir Directory, either system-wide or application-specific
* @param[in] yang_module Name of module
* @param[in] yang_revision Revision, or NULL
* @see yang_spec_main
*/ */
int int
yang_spec_append(clicon_handle h, yang_spec_parse_module(clicon_handle h,
char *yang_dir, char *module,
char *yang_module, char *dir,
char *yang_revision) char *revision,
yang_spec *yspec)
{ {
int retval = -1; int retval = -1;
yang_spec *yspec = NULL;
yang_spec *yspec0; if (yspec == NULL){
yang_stmt *ym = NULL; /* module */ clicon_err(OE_YANG, EINVAL, "yang spec is NULL");
if ((yspec0 = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_YANG, ENOENT, "yang spec not found");
goto done; goto done;
} }
if ((yspec = yspec_new()) == NULL) if (module == NULL){
goto done; clicon_err(OE_YANG, EINVAL, "yang module not set");
if (yang_parse(h, yang_dir, yang_module, yang_revision, yspec) < 0){
yspec_free(yspec); yspec = NULL;
goto done; goto done;
} }
while ((ym = yn_each((yang_node*)yspec, ym)) != NULL) /* Sanity check - use yang_spec_parse_file instead */
if (yn_insert((yang_node*)yspec0, ym) < 0) if (strlen(module) && module[0] == '/'){
goto done; clicon_err(OE_YANG, EINVAL, "yang module illegal format");
yspec->yp_len = 0; goto done;
retval = 0; }
done: if (dir == NULL){
if (yspec) clicon_err(OE_YANG, EINVAL, "yang dir not set");
goto done;
}
if (yang_parse(h, NULL, module, dir, revision, yspec) < 0){
yspec_free(yspec); yspec_free(yspec);
yspec = NULL;
goto done;
}
retval = 0;
done:
return retval;
}
/*! Parse yang specification and its dependencies recursively given filename
* @param[in] h clicon handle
* @param[in] filename Actual filename (including dir and revision)
* @param[in] dir Directory for sub-modules
* @param[in,out] yspec Modules parse are added to this yangspec
* @retval 0 OK
* @retval -1 Error
* @see yang_spec_parse_module for yang dir,module,revision instead of actual filename
*/
int
yang_spec_parse_file(clicon_handle h,
char *filename,
char *dir,
yang_spec *yspec)
{
int retval = -1;
if (yspec == NULL){
clicon_err(OE_YANG, EINVAL, "yang spec is NULL");
goto done;
}
if (dir == NULL){
clicon_err(OE_YANG, EINVAL, "yang dir not set");
goto done;
}
if (yang_parse(h, filename, NULL, dir, NULL, yspec) < 0){
yspec_free(yspec);
yspec = NULL;
goto done;
}
retval = 0;
done:
return retval; return retval;
} }

View file

@ -15,7 +15,6 @@ 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_MODULE_MAIN>$fyang</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_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR> <CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_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,7 +18,6 @@ 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/example/yang</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>$fyang</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>

View file

@ -13,7 +13,6 @@ 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_MODULE_MAIN>$fyang</CLICON_YANG_MODULE_MAIN>
<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>
@ -88,7 +87,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 start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg -D 1 sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg -y $fyang # -D 1
sleep 1 sleep 1
@ -110,7 +109,7 @@ expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription><stre
new "netconf NETCONF subscription with simple filter" new "netconf NETCONF subscription with simple filter"
expectwait "$clixon_netconf -qf $cfg -y $fyang" "<rpc><create-subscription><stream>NETCONF</stream><filter type=\"xpath\" select=\"event\"/></create-subscription></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' 5 expectwait "$clixon_netconf -qf $cfg -y $fyang" "<rpc><create-subscription><stream>NETCONF</stream><filter type=\"xpath\" select=\"event\"/></create-subscription></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' 5
new "netconf NETCONF subscription with filter classfier" new "netconf NETCONF subscription with filter classifier"
expectwait "$clixon_netconf -qf $cfg -y $fyang" "<rpc><create-subscription><stream>NETCONF</stream><filter type=\"xpath\" select=\"event[event-class='fault']\"/></create-subscription></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' 5 expectwait "$clixon_netconf -qf $cfg -y $fyang" "<rpc><create-subscription><stream>NETCONF</stream><filter type=\"xpath\" select=\"event[event-class='fault']\"/></create-subscription></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' 5
#new "restconf monitor event stream RFC8040 Sec 6.3" #new "restconf monitor event stream RFC8040 Sec 6.3"

View file

@ -11,7 +11,6 @@ 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_MODULE_MAIN>$fyang</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>
@ -163,22 +162,22 @@ new "netconf validate"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>operation-failed</error-tag><error-type>application</error-type><error-severity>error</error-severity><error-message>Identityref validation failed, foo:bar not derived from crypto-alg</error-message></rpc-error></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>operation-failed</error-tag><error-type>application</error-type><error-severity>error</error-severity><error-message>Identityref validation failed, foo:bar not derived from crypto-alg</error-message></rpc-error></rpc-reply>]]>]]>$"
new "cli set crypto to mc:aes" new "cli set crypto to mc:aes"
expectfn "$clixon_cli -1 -f $cfg -l o set crypto mc:aes" 0 "^$" expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o set crypto mc:aes" 0 "^$"
new "cli validate" new "cli validate"
expectfn "$clixon_cli -1 -f $cfg -l o validate" 0 "^$" expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o validate" 0 "^$"
new "cli set crypto to aes" new "cli set crypto to aes"
expectfn "$clixon_cli -1 -f $cfg -l o set crypto aes" 0 "^$" expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o set crypto aes" 0 "^$"
new "cli validate" new "cli validate"
expectfn "$clixon_cli -1 -f $cfg -l o validate" 0 "^$" expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o validate" 0 "^$"
new "cli set crypto to des:des3" new "cli set crypto to des:des3"
expectfn "$clixon_cli -1 -f $cfg -l o set crypto des:des3" 0 "^$" expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o set crypto des:des3" 0 "^$"
new "cli validate" new "cli validate"
expectfn "$clixon_cli -1 -f $cfg -l o validate" 0 "^$" expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o validate" 0 "^$"
new "Kill backend" new "Kill backend"
# Check if still alive # Check if still alive

View file

@ -12,7 +12,6 @@ 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/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>$fyang</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>

View file

@ -7,12 +7,11 @@ APPNAME=example
cfg=$dir/conf.xml cfg=$dir/conf.xml
fyang=$dir/restconf.yang fyang=$dir/restconf.yang
# <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
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/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>$fyang</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_MODULE_MAIN>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>

View file

@ -12,7 +12,6 @@ cat <<EOF > $cfg
<config> <config>
<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_MODULE_MAIN>$fyang</CLICON_YANG_MODULE_MAIN>
<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>
@ -60,7 +59,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 start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg # -D 1 sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg -y $fyang # -D 1
sleep 1 sleep 1

View file

@ -351,9 +351,9 @@ module clixon-config {
} }
leaf CLICON_MODULE_LIBRARY_RFC7895 { leaf CLICON_MODULE_LIBRARY_RFC7895 {
type boolean; type boolean;
default false; default true;
description "Enable RFC 7895 YANG Module library support as state description "Enable RFC 7895 YANG Module library support as state
data. Ifenabled, module info will appear when doing data. If enabled, module info will appear when doing
netconf get or restconf GET"; netconf get or restconf GET";
} }
leaf CLICON_STREAM_DISCOVERY_RFC5277 { leaf CLICON_STREAM_DISCOVERY_RFC5277 {