* Yang Support of submodule, include and belongs-to.

* Improved unknown handling
* Configure option `CLICON_YANG_DIR` is changed from a single directory to a path of directories
    * Note CLIXON_DATADIR (=/usr/local/share/clixon) need to be in the list
This commit is contained in:
Olof hagsand 2018-12-01 18:17:42 +01:00
parent 56da97cb5b
commit 39a5086218
47 changed files with 977 additions and 469 deletions

View file

@ -9,10 +9,16 @@
* More complete Yang parser * More complete Yang parser
* YANG parser cardinality checked (only modules level yet) * YANG parser cardinality checked (only modules level yet)
* See https://github.com/clicon/clixon/issues/84 * See https://github.com/clicon/clixon/issues/84
* Support of submodule, include and belongs-to.
* Openconfig yang specs parsed: https://github.com/openconfig/public * Openconfig yang specs parsed: https://github.com/openconfig/public
* Improved unknown handling
* `CLICON_YANG_DIR` is changed from a single directory to a path of directories
* Note CLIXON_DATADIR (=/usr/local/share/clixon) need to be in the list
### API changes on existing features (you may need to change your code) ### API changes on existing features (you may need to change your code)
* Yang parser is stricter (see above) which may break parsing of existing yang specs. * Yang parser is stricter (see above) which may break parsing of existing yang specs.
* Yang parser functions have changed signatures. Please check the source if you call these functions.
* Add `<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>` to your configuration file, or corresponding CLICON_DATADIR directory for Clixon system yang files.
### Minor changes ### Minor changes
* XML parser conformance to W3 spec * XML parser conformance to W3 spec

View file

@ -25,7 +25,7 @@ support.
* [Tests](test/) * [Tests](test/)
* [Docker](docker/) * [Docker](docker/)
* [Roadmap](ROADMAP.md) * [Roadmap](ROADMAP.md)
* [Reference manual](http://www.clicon.org/doxygen/index.html) (Note: the link may not be up-to-date. It is better to build your own: `cd doc; make doc`) * [Reference manual](#reference)
Background Background
========== ==========
@ -124,6 +124,10 @@ However, the following YANG syntax modules are not implemented:
- action - action
- belongs-to - belongs-to
Restrictions on Yang types are as follows:
- The range statement does not support multiple values (RFC7895 sec 9.2.4)
- Submodules cannot re-use a prefix in an import statement that is already used for another imported module in the module that the submodule belongs to.
Netconf Netconf
======= =======
Clixon implements the following NETCONF proposals or standards: Clixon implements the following NETCONF proposals or standards:
@ -217,7 +221,6 @@ The tests outlines an example of three groups (taken from the RFC): admin, limit
* limited: Read access (get and get-config) * limited: Read access (get and get-config)
* guest: No access * guest: No access
Runtime Runtime
======= =======
@ -225,3 +228,12 @@ Runtime
The figure shows the SDK runtime of Clixon. The figure shows the SDK runtime of Clixon.
Reference
=========
A reference manual can be built using [Doxygen](http://www.doxygen.nl/index.html). You need to install doxygen and graphviz on your system.
Build it in the doc directory and point the browser to `.../clixon/doc/html/index.html` as follows:
```
> cd doc
> make doc
> make graphs # detailed callgraphs
```

View file

@ -264,7 +264,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, NULL, "ietf-netconf-acm", CLIXON_DATADIR, NULL, yspec, NULL) < 0) if (yang_parse(h, NULL, "ietf-netconf-acm", NULL, yspec, NULL) < 0)
goto done; goto done;
fd = fileno(f); fd = fileno(f);
/* Read configfile */ /* Read configfile */
@ -753,11 +753,10 @@ main(int argc,
/* Load main application yang specification either module or specific file /* Load main application yang specification either module or specific file
* If -y <file> is given, it overrides main module */ * If -y <file> is given, it overrides main module */
if (yang_filename){ if (yang_filename){
if (yang_spec_parse_file(h, yang_filename, clicon_yang_dir(h), yspec, NULL) < 0) if (yang_spec_parse_file(h, yang_filename, yspec, NULL) < 0)
goto done; goto done;
} }
else if (yang_spec_parse_module(h, clicon_yang_module_main(h), else if (yang_spec_parse_module(h, clicon_yang_module_main(h),
clicon_yang_dir(h),
clicon_yang_module_revision(h), clicon_yang_module_revision(h),
yspec, NULL) < 0) yspec, NULL) < 0)
goto done; goto done;
@ -770,11 +769,11 @@ main(int argc,
goto done; goto done;
/* Load yang Restconf stream discovery */ /* Load yang Restconf stream discovery */
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") && if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
yang_spec_parse_module(h, "ietf-restconf-monitoring", CLIXON_DATADIR, NULL, yspec, NULL)< 0) yang_spec_parse_module(h, "ietf-restconf-monitoring", NULL, yspec, NULL)< 0)
goto done; goto done;
/* Load yang Netconf stream discovery */ /* Load yang Netconf stream discovery */
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") && if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") &&
yang_spec_parse_module(h, "ietf-netconf-notification", CLIXON_DATADIR, NULL, yspec, NULL)< 0) yang_spec_parse_module(h, "ietf-netconf-notification", NULL, yspec, NULL)< 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

@ -51,7 +51,7 @@
#include <assert.h> #include <assert.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/param.h> #include <sys/param.h>
#include <math.h> /* For pow() kludge in cvtype_max2str_dup2 */
/* cligen */ /* cligen */
#include <cligen/cligen.h> #include <cligen/cligen.h>
@ -169,6 +169,28 @@ static int yang2cli_stmt(clicon_handle h, yang_stmt *ys, cbuf *cb,
static int yang2cli_var_union(clicon_handle h, yang_stmt *ys, char *origtype, static int yang2cli_var_union(clicon_handle h, yang_stmt *ys, char *origtype,
yang_stmt *ytype, cbuf *cb, char *helptext); yang_stmt *ytype, cbuf *cb, char *helptext);
/*! Patched maxstring to account for DEC64 types
* @note kludge to fix overflow error -> Fix the original error in cvtype_max2str
* by adding a fraction_digits argument.
*/
static char *
cvtype_max2str_dup2(enum cv_type type,
int fraction_digits)
{
int len;
char *str;
if (type!=CGV_DEC64 || fraction_digits==0)
return cvtype_max2str_dup(type);
if ((len = cvtype_max2str(type, NULL, 0)) < 0)
return NULL;
if ((str = (char *)malloc(len+1)) == NULL)
return NULL;
memset(str, '\0', len+1);
len = snprintf(str, len+1, "%" PRId64 ".0", (INT64_MAX/((int)pow(10,fraction_digits))));
return str;
}
/*! Generate CLI code for Yang leaf statement to CLIgen variable of specific type /*! Generate CLI code for Yang leaf statement to CLIgen variable of specific type
* Check for completion (of already existent values), ranges (eg range[min:max]) and * Check for completion (of already existent values), ranges (eg range[min:max]) and
* patterns, (eg regexp:"[0.9]*"). * patterns, (eg regexp:"[0.9]*").
@ -282,11 +304,13 @@ yang2cli_var_sub(clicon_handle h,
} }
snprintf(r, 512, "%d", MAXPATHLEN); snprintf(r, 512, "%d", MAXPATHLEN);
} }
else if ((r = cvtype_max2str_dup(cvtype)) == NULL){ else {
if ((r = cvtype_max2str_dup2(cvtype, fraction_digits)) == NULL){
clicon_err(OE_UNIX, errno, "cvtype_max2str"); clicon_err(OE_UNIX, errno, "cvtype_max2str");
goto done; goto done;
} }
} }
}
cprintf(cb, "%s]", r); /* range */ cprintf(cb, "%s]", r); /* range */
free(r); free(r);
r = NULL; r = NULL;
@ -513,10 +537,12 @@ yang2cli_leaf(clicon_handle h,
if (helptext) if (helptext)
cprintf(cbuf, "(\"%s\")", helptext); cprintf(cbuf, "(\"%s\")", helptext);
cprintf(cbuf, " "); cprintf(cbuf, " ");
yang2cli_var(h, ys, cbuf, helptext); if (yang2cli_var(h, ys, cbuf, helptext) < 0)
goto done;
} }
else else
yang2cli_var(h, ys, cbuf, helptext); if (yang2cli_var(h, ys, cbuf, helptext) < 0)
goto done;
if (callback){ if (callback){
if (cli_callback_generate(h, ys, cbuf) < 0) if (cli_callback_generate(h, ys, cbuf) < 0)
goto done; goto done;

View file

@ -433,11 +433,10 @@ main(int argc, char **argv)
/* Load main application yang specification either module or specific file /* Load main application yang specification either module or specific file
* If -y <file> is given, it overrides main module */ * If -y <file> is given, it overrides main module */
if (yang_filename){ if (yang_filename){
if (yang_spec_parse_file(h, yang_filename, clicon_yang_dir(h), yspec, &ymod) < 0) if (yang_spec_parse_file(h, yang_filename, yspec, &ymod) < 0)
goto done; goto done;
} }
else if (yang_spec_parse_module(h, clicon_yang_module_main(h), else if (yang_spec_parse_module(h, clicon_yang_module_main(h),
clicon_yang_dir(h),
clicon_yang_module_revision(h), clicon_yang_module_revision(h),
yspec, &ymod) < 0) yspec, &ymod) < 0)
goto done; goto done;

View file

@ -447,11 +447,10 @@ main(int argc,
/* Load main application yang specification either module or specific file /* Load main application yang specification either module or specific file
* If -y <file> is given, it overrides main module */ * If -y <file> is given, it overrides main module */
if (yang_filename){ if (yang_filename){
if (yang_spec_parse_file(h, yang_filename, clicon_yang_dir(h), yspec, NULL) < 0) if (yang_spec_parse_file(h, yang_filename, yspec, NULL) < 0)
goto done; goto done;
} }
else if (yang_spec_parse_module(h, clicon_yang_module_main(h), else if (yang_spec_parse_module(h, clicon_yang_module_main(h),
clicon_yang_dir(h),
clicon_yang_module_revision(h), clicon_yang_module_revision(h),
yspec, NULL) < 0) yspec, NULL) < 0)
goto done; goto done;

View file

@ -32,7 +32,13 @@
***** END LICENSE BLOCK ***** ***** END LICENSE BLOCK *****
* *
* Code for handling netconf rpc messages according to RFC 4741 and RFC 5277 * Code for handling netconf rpc messages according to RFC 4741,5277,6241
* All NETCONF protocol elements are defined in the following namespace:
* urn:ietf:params:xml:ns:netconf:base:1.0
* YANG defines an XML namespace for NETCONF <edit-config> operations,
* <error-info> content, and the <action> element. The name of this
* namespace is "urn:ietf:params:xml:ns:yang:1".
*
*****************************************************************************/ *****************************************************************************/
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "clixon_config.h" /* generated by config & autoconf */ #include "clixon_config.h" /* generated by config & autoconf */
@ -894,7 +900,7 @@ netconf_application_rpc(clicon_handle h,
} }
cprintf(cb, "/%s:%s", xml_namespace(xn), xml_name(xn)); cprintf(cb, "/%s:%s", xml_namespace(xn), xml_name(xn));
/* Find yang rpc statement, return yang rpc statement if found */ /* Find yang rpc statement, return yang rpc statement if found */
if (yang_abs_schema_nodeid(yspec, cbuf_get(cb), Y_RPC, &yrpc) < 0) if (yang_abs_schema_nodeid(yspec, xml_spec(xn), cbuf_get(cb), Y_RPC, &yrpc) < 0)
goto done; goto done;
/* Check if found */ /* Check if found */
if (yrpc != NULL){ if (yrpc != NULL){

View file

@ -517,7 +517,6 @@ main(int argc,
char *sockpath; char *sockpath;
char *path; char *path;
clicon_handle h; clicon_handle h;
char *yangspec=NULL;
char *dir; char *dir;
char *tmp; char *tmp;
int logdst = CLICON_LOG_SYSLOG; int logdst = CLICON_LOG_SYSLOG;
@ -619,10 +618,6 @@ main(int argc,
argc -= optind; argc -= optind;
argv += optind; argv += optind;
/* Overwrite yang module with -y option */
if (yangspec)
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", yangspec);
/* Initialize plugins group */ /* Initialize plugins group */
if ((dir = clicon_restconf_dir(h)) != NULL) if ((dir = clicon_restconf_dir(h)) != NULL)
if (clixon_plugins_load(h, CLIXON_PLUGIN_INIT, dir, NULL) < 0) if (clixon_plugins_load(h, CLIXON_PLUGIN_INIT, dir, NULL) < 0)
@ -635,11 +630,10 @@ main(int argc,
/* Load main application yang specification either module or specific file /* Load main application yang specification either module or specific file
* If -y <file> is given, it overrides main module */ * If -y <file> is given, it overrides main module */
if (yang_filename){ if (yang_filename){
if (yang_spec_parse_file(h, yang_filename, clicon_yang_dir(h), yspec, NULL) < 0) if (yang_spec_parse_file(h, yang_filename, yspec, NULL) < 0)
goto done; goto done;
} }
else if (yang_spec_parse_module(h, clicon_yang_module_main(h), else if (yang_spec_parse_module(h, clicon_yang_module_main(h),
clicon_yang_dir(h),
clicon_yang_module_revision(h), clicon_yang_module_revision(h),
yspec, NULL) < 0) yspec, NULL) < 0)
goto done; goto done;
@ -649,10 +643,10 @@ main(int argc,
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_parse_module(h, "ietf-restconf-monitoring", CLIXON_DATADIR, NULL, yspec, NULL)< 0) yang_spec_parse_module(h, "ietf-restconf-monitoring", NULL, yspec, NULL)< 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_parse_module(h, "ietf-netconf-notification", CLIXON_DATADIR, NULL, yspec, NULL)< 0) yang_spec_parse_module(h, "ietf-netconf-notification", NULL, yspec, NULL)< 0)
goto done; goto done;
/* Call start function in all plugins before we go interactive /* Call start function in all plugins before we go interactive
Pass all args after the standard options to plugin_start Pass all args after the standard options to plugin_start

11
configure vendored
View file

@ -4391,15 +4391,14 @@ fi
done done
# This is to find clixon system files in the source code and Makefile # CLIXON_DATADIR is where clixon installs the "system" yang files in yang/Makfile
# This directory should most probably be included in each application,
# so each application designer may need to place CLIXON_DATADIR in their config
# (last in yang dir list):
# <CLIXON-YANG-DIR>$CLIXON_DATADIR</CLIXON-YANG_DIR>
CLIXON_DATADIR="${prefix}/share/clixon" CLIXON_DATADIR="${prefix}/share/clixon"
cat >>confdefs.h <<_ACEOF
#define CLIXON_DATADIR "${CLIXON_DATADIR}"
_ACEOF
# Default location for config file # Default location for config file
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF

View file

@ -199,10 +199,13 @@ AC_CHECK_LIB(dl, dlopen)
AC_CHECK_FUNCS(inet_aton sigaction sigvec strlcpy strsep strndup alphasort versionsort strverscmp) AC_CHECK_FUNCS(inet_aton sigaction sigvec strlcpy strsep strndup alphasort versionsort strverscmp)
# This is to find clixon system files in the source code and Makefile # CLIXON_DATADIR is where clixon installs the "system" yang files in yang/Makfile
# This directory should most probably be included in each application,
# so each application designer may need to place CLIXON_DATADIR in their config
# (last in yang dir list):
# <CLIXON-YANG-DIR>$CLIXON_DATADIR</CLIXON-YANG_DIR>
AC_SUBST(CLIXON_DATADIR) AC_SUBST(CLIXON_DATADIR)
CLIXON_DATADIR="${prefix}/share/clixon" CLIXON_DATADIR="${prefix}/share/clixon"
AC_DEFINE_UNQUOTED(CLIXON_DATADIR, "${CLIXON_DATADIR}", [Clixon data dir for system yang files etc])
# Default location for config file # Default location for config file
AC_DEFINE_UNQUOTED(CLIXON_DEFAULT_CONFIG,"${CLIXON_DEFAULT_CONFIG}",[Location for apps to find default config file]) AC_DEFINE_UNQUOTED(CLIXON_DEFAULT_CONFIG,"${CLIXON_DEFAULT_CONFIG}",[Location for apps to find default config file])

View file

@ -71,7 +71,7 @@ sudo ./datastore_client -d candidate -b /usr/local/var/example -p /home/olof/src
#include <clixon/clixon.h> #include <clixon/clixon.h>
/* Command line options to be passed to getopt(3) */ /* Command line options to be passed to getopt(3) */
#define DATASTORE_OPTS "hDd:p:b:y:m:" #define DATASTORE_OPTS "hDd:p:b:y:"
/*! usage /*! usage
*/ */
@ -85,8 +85,7 @@ usage(char *argv0)
"\t-d <db>\t\tDatabase name. Default: running. Alt: candidate,startup\n" "\t-d <db>\t\tDatabase name. Default: running. Alt: candidate,startup\n"
"\t-b <dir>\tDatabase directory. Mandatory\n" "\t-b <dir>\tDatabase directory. Mandatory\n"
"\t-p <plugin>\tDatastore plugin. Mandatory\n" "\t-p <plugin>\tDatastore plugin. Mandatory\n"
"\t-y <dir>\tYang directory (where modules are stored). Mandatory\n" "\t-y <file>\tYang file. Mandatory\n"
"\t-m <module>\tYang module. Mandatory\n"
"and command is either:\n" "and command is either:\n"
"\tget [<xpath>]\n" "\tget [<xpath>]\n"
"\tmget <nr> [<xpath>]\n" "\tmget <nr> [<xpath>]\n"
@ -115,7 +114,6 @@ main(int argc, char **argv)
char *plugin = NULL; char *plugin = NULL;
char *cmd = NULL; char *cmd = NULL;
yang_spec *yspec = NULL; yang_spec *yspec = NULL;
char *yangdir = NULL;
char *yangmodule = NULL; char *yangmodule = NULL;
char *dbdir = NULL; char *dbdir = NULL;
int ret; int ret;
@ -158,12 +156,7 @@ main(int argc, char **argv)
usage(argv0); usage(argv0);
dbdir = optarg; dbdir = optarg;
break; break;
case 'y': /* Yang directory */ case 'y': /* Yang file */
if (!optarg)
usage(argv0);
yangdir = optarg;
break;
case 'm': /* Yang module */
if (!optarg) if (!optarg)
usage(argv0); usage(argv0);
yangmodule = optarg; yangmodule = optarg;
@ -188,10 +181,6 @@ main(int argc, char **argv)
clicon_err(OE_DB, 0, "Missing dbdir -b option"); clicon_err(OE_DB, 0, "Missing dbdir -b option");
goto done; goto done;
} }
if (yangdir == NULL){
clicon_err(OE_YANG, 0, "Missing yangdir -y option");
goto done;
}
if (yangmodule == NULL){ if (yangmodule == NULL){
clicon_err(OE_YANG, 0, "Missing yang module -m option"); clicon_err(OE_YANG, 0, "Missing yang module -m option");
goto done; goto done;
@ -206,7 +195,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, NULL, yangmodule, yangdir, NULL, yspec, NULL) < 0) if (yang_parse(h, yangmodule, NULL, NULL, yspec, NULL) < 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

@ -1367,8 +1367,7 @@ main(int argc,
enum operation_type op; enum operation_type op;
char *cmd; char *cmd;
char *db; char *db;
char *yangdir; char *yangmod; /* yang file */
char *yangmod;
yang_spec *yspec = NULL; yang_spec *yspec = NULL;
clicon_handle h; clicon_handle h;
@ -1381,12 +1380,11 @@ main(int argc,
} }
cmd = argv[1]; cmd = argv[1];
db = argv[2]; db = argv[2];
yangdir = argv[3];
yangmod = argv[4]; yangmod = argv[4];
db_init(db); db_init(db);
if ((yspec = yspec_new()) == NULL) if ((yspec = yspec_new()) == NULL)
goto done goto done
if (yang_parse(h, NULL, yangmod, yangdir, NULL, yspec) < 0) if (yang_parse(h, NULL, yangmod, 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

@ -97,13 +97,31 @@ configuration file is /usr/local/etc/clixon.xml. The example
configuration file is installed at /usr/local/etc/example.xml. The configuration file is installed at /usr/local/etc/example.xml. The
YANG specification for the configuration file is clixon-config.yang. YANG specification for the configuration file is clixon-config.yang.
You can change where Clixon looks for the configuration FILE as follows: ## How are Clixon configuration files found?
Clixon by default finds its configuration file at `/usr/local/etc/clixon.xml`. However, you can modify this location as follows:
- Provide -f FILE option when starting a program (eg clixon_backend -f FILE) - Provide -f FILE option when starting a program (eg clixon_backend -f FILE)
- Provide --with-configfile=FILE when configuring - Provide --with-configfile=FILE when configuring
- Provide --with-sysconfig=<dir> when configuring, then FILE is <dir>/clixon.xml - Provide --with-sysconfig=<dir> when configuring. Then FILE is <dir>/clixon.xml
- 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
## How are Yang files found?
Yang files contain the configuration specification. A Clixon
application loads yang files and clixon itself loads system yang
files. When Yang files are loaded modules are imported and submodules
are included.
The following configuration file options control the loading of Yang files:
- `CLICON_YANG_DIR` - A list of directories (yang dir path) where Clixon searches for module and submodules.
- `CLICON_YANG_MODULE_MAIN` - Specifies a single module to load. The module is searched for in the yang dir path.
- `CLICON_YANG_MODULE_REVISION` : Specifies a revision to the main module.
Note that the special `CLIXON_DATADIR`, by default `/usr/local/share/clixon` should be included in the yang dir path for Clixon system files to be found.
Application also has a command-line option `-y` to include a single Yang using absolute file path. This is mainly for debugging.
## How do I enable Yang features? ## How do I enable Yang features?
Yang models have features, and parts of a specification can be Yang models have features, and parts of a specification can be

View file

@ -44,11 +44,13 @@ all: $(SUBDIRS) doc
echo "Build doxygen doc: make doc" echo "Build doxygen doc: make doc"
# Regular doxygen documentation # Regular doxygen documentation
# Need to install doxygen
doc: doc:
doxygen Doxyfile # generates html dir doxygen Doxyfile # generates html dir
echo "Build doxygen graphs: make graphs" echo "Build doxygen graphs: make graphs"
# doxygen documentation with callgraphs # doxygen documentation with callgraphs
# Need to install graphviz
graphs: graphs:
doxygen Doxyfile.graphs # generates html dir + call graphs (takes time) doxygen Doxyfile.graphs # generates html dir + call graphs (takes time)

View file

@ -2,6 +2,7 @@
<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/example/yang</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>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>

View file

@ -1,8 +1,5 @@
/* include/clixon_config.h.in. Generated from configure.ac by autoheader. */ /* include/clixon_config.h.in. Generated from configure.ac by autoheader. */
/* Clixon data dir for system yang files etc */
#undef CLIXON_DATADIR
/* Location for apps to find default config file */ /* Location for apps to find default config file */
#undef CLIXON_DEFAULT_CONFIG #undef CLIXON_DEFAULT_CONFIG
@ -42,6 +39,9 @@
/* Define to 1 if you have the `crypt' library (-lcrypt). */ /* Define to 1 if you have the `crypt' library (-lcrypt). */
#undef HAVE_LIBCRYPT #undef HAVE_LIBCRYPT
/* Define to 1 if you have the `curl' library (-lcurl). */
#undef HAVE_LIBCURL
/* Define to 1 if you have the `dl' library (-ldl). */ /* Define to 1 if you have the `dl' library (-ldl). */
#undef HAVE_LIBDL #undef HAVE_LIBDL
@ -133,4 +133,4 @@
`char[]'. */ `char[]'. */
#undef YYTEXT_POINTER #undef YYTEXT_POINTER
#include "clixon_custom.h" #include <clixon_custom.h>

View file

@ -105,9 +105,6 @@ int clicon_option_del(clicon_handle h, const char *name);
static inline char *clicon_configfile(clicon_handle h){ static inline char *clicon_configfile(clicon_handle h){
return clicon_option_str(h, "CLICON_CONFIGFILE"); return clicon_option_str(h, "CLICON_CONFIGFILE");
} }
static inline char *clicon_yang_dir(clicon_handle h){
return clicon_option_str(h, "CLICON_YANG_DIR");
}
static inline char *clicon_yang_module_main(clicon_handle h){ static inline char *clicon_yang_module_main(clicon_handle h){
return clicon_option_str(h, "CLICON_YANG_MODULE_MAIN"); return clicon_option_str(h, "CLICON_YANG_MODULE_MAIN");
} }

View file

@ -95,6 +95,7 @@ enum rfc_6020{
Y_MANDATORY, Y_MANDATORY,
Y_MAX_ELEMENTS, Y_MAX_ELEMENTS,
Y_MIN_ELEMENTS, Y_MIN_ELEMENTS,
Y_MODIFIER,
Y_MODULE, Y_MODULE,
Y_MUST, Y_MUST,
Y_NAMESPACE, Y_NAMESPACE,
@ -193,6 +194,8 @@ struct yang_stmt{
char *ys_argument; /* String / argument depending on keyword */ char *ys_argument; /* String / argument depending on keyword */
int ys_flags; /* Flags according to YANG_FLAG_* above */ int ys_flags; /* Flags according to YANG_FLAG_* above */
/*--------------here common for all -------*/
char *ys_extra; /* For unknown */
cg_var *ys_cv; /* cligen variable. See ys_populate() cg_var *ys_cv; /* cligen variable. See ys_populate()
Following stmts have cv:s: Following stmts have cv:s:
leaf: for default value leaf: for default value
@ -200,7 +203,7 @@ struct yang_stmt{
config: boolean true or false config: boolean true or false
mandatory: boolean true or false mandatory: boolean true or false
fraction-digits for fraction-digits fraction-digits for fraction-digits
unkown-stmt (argument) unknown-stmt (argument)
*/ */
cvec *ys_cvec; /* List of stmt-specific variables cvec *ys_cvec; /* List of stmt-specific variables
Y_RANGE: range_min, range_max Y_RANGE: range_min, range_max
@ -265,11 +268,12 @@ 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 *filename, int yang_parse(clicon_handle h, const char *filename,
const char *module, const char *dir, const char *module,
const char *revision, yang_spec *ysp, yang_stmt **ymodp); const char *revision, yang_spec *ysp, yang_stmt **ymodp);
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, yang_stmt *ys,
char *schema_nodeid,
enum rfc_6020 keyword, yang_stmt **yres); enum rfc_6020 keyword, yang_stmt **yres);
int yang_desc_schema_nodeid(yang_node *yn, char *schema_nodeid, int yang_desc_schema_nodeid(yang_node *yn, char *schema_nodeid,
enum rfc_6020 keyword, yang_stmt **yres); enum rfc_6020 keyword, yang_stmt **yres);
@ -277,8 +281,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);
int yang_spec_parse_module(clicon_handle h, char *module, char *dir, char *revision, yang_spec *yspec, yang_stmt **ymodp); int yang_spec_parse_module(clicon_handle h, char *module, char *revision, yang_spec *yspec, yang_stmt **ymodp);
int yang_spec_parse_file(clicon_handle h, char *filename, char *dir, yang_spec *yspec, yang_stmt **ymodp); int yang_spec_parse_file(clicon_handle h, char *filename, yang_spec *yspec, yang_stmt **ymodp);
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

@ -988,9 +988,9 @@ netconf_module_load(clicon_handle h)
yspec = clicon_dbspec_yang(h); yspec = clicon_dbspec_yang(h);
/* Load yang spec */ /* Load yang spec */
if (yang_spec_parse_module(h, "ietf-netconf", CLIXON_DATADIR, NULL, yspec, NULL)< 0) if (yang_spec_parse_module(h, "ietf-netconf", NULL, yspec, NULL)< 0)
goto done; goto done;
if (yang_spec_parse_module(h, "ietf-netconf-notification", CLIXON_DATADIR, NULL, yspec, NULL)< 0) if (yang_spec_parse_module(h, "ietf-netconf-notification", NULL, yspec, NULL)< 0)
goto done; goto done;
if ((xc = clicon_conf_xml(h)) == NULL){ if ((xc = clicon_conf_xml(h)) == NULL){
clicon_err(OE_CFG, ENOENT, "Clicon configuration not loaded"); clicon_err(OE_CFG, ENOENT, "Clicon configuration not loaded");

View file

@ -178,8 +178,16 @@ parse_configfile(clicon_handle h,
__FUNCTION__, name, body); __FUNCTION__, name, body);
continue; continue;
} }
/* hard-coded exceptions for configure options that are leaf-lists (not leaf)
* They must be accessed directly by looping over clicon_conf_xml(h)
*/
if (strcmp(name,"CLICON_FEATURE")==0) if (strcmp(name,"CLICON_FEATURE")==0)
continue; continue;
if (strcmp(name,"CLICON_YANG_DIR")==0)
continue;
/* Used as an arg to this fn */
if (strcmp(name,"CLICON_CONFIGFILE")==0)
continue;
if (hash_add(copt, if (hash_add(copt,
name, name,
body, body,
@ -236,14 +244,25 @@ clicon_options_main(clicon_handle h,
clicon_err(OE_CFG, 0, "%s: suffix %s not recognized (Run ./configure --with-config-compat?)", configfile, suffix); clicon_err(OE_CFG, 0, "%s: suffix %s not recognized (Run ./configure --with-config-compat?)", configfile, suffix);
goto done; goto done;
} }
/* Parse clixon yang spec */ /* Read configfile first without yangspec, for bootstrapping */
if (yang_parse(h, NULL, "clixon-config", CLIXON_DATADIR, NULL, yspec, NULL) < 0)
goto done;
/* Read configfile */
if (parse_configfile(h, configfile, yspec, &xconfig) < 0) if (parse_configfile(h, configfile, yspec, &xconfig) < 0)
goto done; goto done;
if (xml_rootchild(xconfig, 0, &xconfig) < 0) if (xml_rootchild(xconfig, 0, &xconfig) < 0)
goto done; goto done;
/* Set clixon_conf pointer to handle */
clicon_conf_xml_set(h, xconfig);
/* Parse clixon yang spec */
if (yang_parse(h, NULL, "clixon-config", NULL, yspec, NULL) < 0)
goto done;
clicon_conf_xml_set(h, NULL);
if (xconfig)
xml_free(xconfig);
/* Read configfile second time now with check yang spec */
if (parse_configfile(h, configfile, yspec, &xconfig) < 0)
goto done;
if (xml_rootchild(xconfig, 0, &xconfig) < 0)
goto done;
/* Set clixon_conf pointer to handle */
clicon_conf_xml_set(h, xconfig); clicon_conf_xml_set(h, xconfig);
/* Specific option handling */ /* Specific option handling */
if (clicon_option_bool(h, "CLICON_XML_SORT") == 1) if (clicon_option_bool(h, "CLICON_XML_SORT") == 1)
@ -638,7 +657,7 @@ clicon_conf_xml(clicon_handle h)
return NULL; return NULL;
} }
/*! Set YANG specification for Clixon system options and features /*! Set YANG specification for Clixon system options and features
* ys must be a malloced pointer * ys must be a malloced pointer
*/ */
int int

View file

@ -122,6 +122,7 @@ static const map_str2int ykmap[] = {
{"mandatory", Y_MANDATORY}, {"mandatory", Y_MANDATORY},
{"max-elements", Y_MAX_ELEMENTS}, {"max-elements", Y_MAX_ELEMENTS},
{"min-elements", Y_MIN_ELEMENTS}, {"min-elements", Y_MIN_ELEMENTS},
{"modifier", Y_MODIFIER},
{"module", Y_MODULE}, {"module", Y_MODULE},
{"must", Y_MUST}, {"must", Y_MUST},
{"namespace", Y_NAMESPACE}, {"namespace", Y_NAMESPACE},
@ -206,6 +207,8 @@ ys_free1(yang_stmt *ys)
{ {
if (ys->ys_argument) if (ys->ys_argument)
free(ys->ys_argument); free(ys->ys_argument);
if (ys->ys_extra)
free(ys->ys_extra);
if (ys->ys_cv) if (ys->ys_cv)
cv_free(ys->ys_cv); cv_free(ys->ys_cv);
if (ys->ys_cvec) if (ys->ys_cvec)
@ -233,7 +236,8 @@ ys_free(yang_stmt *ys)
return 0; return 0;
} }
/*! Free a yang specification recursively */ /*! Free a yang specification recursively
*/
int int
yspec_free(yang_spec *yspec) yspec_free(yang_spec *yspec)
{ {
@ -294,6 +298,11 @@ ys_cp(yang_stmt *ynew,
clicon_err(OE_YANG, errno, "strdup"); clicon_err(OE_YANG, errno, "strdup");
goto done; goto done;
} }
if (yold->ys_extra)
if ((ynew->ys_extra = strdup(yold->ys_extra)) == NULL){
clicon_err(OE_YANG, errno, "strdup");
goto done;
}
if (yold->ys_cv) if (yold->ys_cv)
if ((ynew->ys_cv = cv_dup(yold->ys_cv)) == NULL){ if ((ynew->ys_cv = cv_dup(yold->ys_cv)) == NULL){
clicon_err(OE_YANG, errno, "cv_dup"); clicon_err(OE_YANG, errno, "cv_dup");
@ -672,7 +681,8 @@ yang_find_topnode(yang_spec *ysp,
if (yang_nodeid_split(nodeid, &prefix, &id) < 0) if (yang_nodeid_split(nodeid, &prefix, &id) < 0)
goto done; goto done;
if (prefix){ if (prefix){
if ((ymod = yang_find((yang_node*)ysp, Y_MODULE, prefix)) != NULL){ if ((ymod = yang_find((yang_node*)ysp, Y_MODULE, prefix)) != NULL ||
(ymod = yang_find((yang_node*)ysp, Y_SUBMODULE, prefix)) != NULL){
if ((yres = yang_find((yang_node*)ymod, 0, id)) != NULL) if ((yres = yang_find((yang_node*)ymod, 0, id)) != NULL)
goto ok; goto ok;
goto done; goto done;
@ -771,7 +781,7 @@ yang_order(yang_stmt *y)
int j=0; int j=0;
yp = y->ys_parent; yp = y->ys_parent;
if (yp->yn_keyword == Y_MODULE ||yp->yn_keyword == Y_SUBMODULE){ if (yp->yn_keyword == Y_MODULE || yp->yn_keyword == Y_SUBMODULE){
ypp = yp->yn_parent; ypp = yp->yn_parent;
for (i=0; i<ypp->yn_len; i++){ for (i=0; i<ypp->yn_len; i++){
yn = (yang_node*)ypp->yn_stmt[i]; yn = (yang_node*)ypp->yn_stmt[i];
@ -800,7 +810,8 @@ yang_key2str(int keyword)
return (char*)clicon_int2str(ykmap, keyword); return (char*)clicon_int2str(ykmap, keyword);
} }
/*! Find top module or sub-module given a statement. Ultimate top is yang spec /*! Find top module or sub-module given a statement.
* Ultimate top is yang spec, dont return that
* The routine recursively finds ancestors. * 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
@ -811,14 +822,13 @@ ys_module(yang_stmt *ys)
{ {
yang_node *yn; yang_node *yn;
#if 1
if (ys==NULL || ys->ys_keyword==Y_SPEC) if (ys==NULL || ys->ys_keyword==Y_SPEC)
return NULL; return NULL;
#else if (ys->ys_keyword == Y_MODULE || ys->ys_keyword == Y_SUBMODULE)
if (ys==NULL || ys->ys_keyword==Y_SPEC)
return ys; return ys;
#endif while (ys != NULL &&
while (ys != NULL && ys->ys_keyword != Y_MODULE && ys->ys_keyword != Y_SUBMODULE){ ys->ys_keyword != Y_MODULE &&
ys->ys_keyword != Y_SUBMODULE){
yn = ys->ys_parent; yn = ys->ys_parent;
/* Some extra stuff to ensure ys is a stmt */ /* Some extra stuff to ensure ys is a stmt */
if (yn && yn->yn_keyword == Y_SPEC) if (yn && yn->yn_keyword == Y_SPEC)
@ -973,7 +983,8 @@ yang_find_module_by_prefix(yang_stmt *ys,
} }
yimport = NULL; yimport = NULL;
while ((yimport = yn_each((yang_node*)my_ymod, yimport)) != NULL) { while ((yimport = yn_each((yang_node*)my_ymod, yimport)) != NULL) {
if (yimport->ys_keyword != Y_IMPORT) if (yimport->ys_keyword != Y_IMPORT &&
yimport->ys_keyword != Y_INCLUDE)
continue; continue;
if ((yprefix = yang_find((yang_node*)yimport, Y_PREFIX, NULL)) != NULL && if ((yprefix = yang_find((yang_node*)yimport, Y_PREFIX, NULL)) != NULL &&
strcmp(yprefix->ys_argument, prefix) == 0){ strcmp(yprefix->ys_argument, prefix) == 0){
@ -981,9 +992,10 @@ yang_find_module_by_prefix(yang_stmt *ys,
} }
} }
if (yimport){ if (yimport){
if ((ymod = yang_find((yang_node*)yspec, Y_MODULE, yimport->ys_argument)) == NULL){ if ((ymod = yang_find((yang_node*)yspec, Y_MODULE, yimport->ys_argument)) == NULL &&
(ymod = yang_find((yang_node*)yspec, Y_SUBMODULE, yimport->ys_argument)) == NULL){
clicon_err(OE_YANG, 0, "No module or sub-module found with prefix %s", clicon_err(OE_YANG, 0, "No module or sub-module found with prefix %s",
yimport->ys_argument); prefix);
yimport = NULL; yimport = NULL;
goto done; /* unresolved */ goto done; /* unresolved */
} }
@ -1411,9 +1423,9 @@ ys_populate_feature(clicon_handle h,
cg_var *cv; cg_var *cv;
char *module; char *module;
char *feature; char *feature;
cxobj *x1; cxobj *xc;
/* Eg, when parsing the config xml itself */ /* get clicon config file in xml form */
if ((x = clicon_conf_xml(h)) == NULL) if ((x = clicon_conf_xml(h)) == NULL)
goto ok; goto ok;
if ((ymod = ys_module(ys)) == NULL){ if ((ymod = ys_module(ys)) == NULL){
@ -1422,14 +1434,14 @@ ys_populate_feature(clicon_handle h,
} }
module = ymod->ys_argument; module = ymod->ys_argument;
feature = ys->ys_argument; feature = ys->ys_argument;
x1 = NULL; xc = NULL;
while ((x1 = xml_child_each(x, x1, CX_ELMNT)) != NULL && found == 0) { while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL && found == 0) {
char *m = NULL; char *m = NULL;
char *f = NULL; char *f = NULL;
if (strcmp(xml_name(x1), "CLICON_FEATURE") != 0) if (strcmp(xml_name(xc), "CLICON_FEATURE") != 0)
continue; continue;
/* get m and f from configuration feature rules */ /* get m and f from configuration feature rules */
if (yang_nodeid_split(xml_body(x1), &m, &f) < 0) if (yang_nodeid_split(xml_body(xc), &m, &f) < 0)
goto done; goto done;
if (m && f && if (m && f &&
(strcmp(m,"*")==0 || (strcmp(m,"*")==0 ||
@ -1454,6 +1466,51 @@ ys_populate_feature(clicon_handle h,
return retval; return retval;
} }
/*! Populate unknown node with extension
*/
static int
ys_populate_unknown(yang_stmt *ys)
{
int retval = -1;
int cvret;
char *reason = NULL;
yang_stmt *ymod;
char *prefix = NULL;
char *name;
char *extra;
if ((extra = ys->ys_extra) == NULL)
goto ok;
/* Find extension, if found, store it as unknown, if not,
break for error */
prefix = yarg_prefix(ys); /* And this its prefix */
name = yarg_id(ys); /* This is the type to resolve */
if ((ymod = yang_find_module_by_prefix(ys, prefix)) == NULL)
goto ok; /* shouldnt happen */
if (yang_find((yang_node*)ymod, Y_EXTENSION, name) == NULL){
clicon_err(OE_YANG, errno, "Extension %s:%s not found", prefix, name);
goto done;
}
if ((ys->ys_cv = cv_new(CGV_STRING)) == NULL){
clicon_err(OE_YANG, errno, "cv_new");
goto done;
}
if ((cvret = cv_parse1(extra, ys->ys_cv, &reason)) < 0){ /* error */
clicon_err(OE_YANG, errno, "parsing cv");
goto done;
}
if (cvret == 0){ /* parsing failed */
clicon_err(OE_YANG, errno, "Parsing CV: %s", reason);
goto done;
}
ok:
retval = 0;
done:
if (prefix)
free(prefix);
return retval;
}
/*! Populate with cligen-variables, default values, etc. Sanity checks on complete tree. /*! Populate with cligen-variables, default values, etc. Sanity checks on complete tree.
* *
* We do this in 2nd pass after complete parsing to be sure to have a complete parse-tree * We do this in 2nd pass after complete parsing to be sure to have a complete parse-tree
@ -1495,6 +1552,10 @@ ys_populate(yang_stmt *ys,
if (ys_populate_identity(ys, NULL) < 0) if (ys_populate_identity(ys, NULL) < 0)
goto done; goto done;
break; break;
case Y_UNKNOWN:
if (ys_populate_unknown(ys) < 0)
goto done;
break;
default: default:
break; break;
} }
@ -1558,9 +1619,8 @@ yang_augment_node(yang_stmt *ys,
schema_nodeid = ys->ys_argument; schema_nodeid = ys->ys_argument;
clicon_debug(1, "%s %s", __FUNCTION__, schema_nodeid); clicon_debug(1, "%s %s", __FUNCTION__, schema_nodeid);
/* Find the target */ /* Find the target */
if (yang_abs_schema_nodeid(ysp, schema_nodeid, -1, &yss) < 0) if (yang_abs_schema_nodeid(ysp, ys, schema_nodeid, -1, &yss) < 0)
goto done; goto done;
if (yss == NULL) if (yss == NULL)
goto ok; goto ok;
@ -1646,14 +1706,15 @@ yang_expand(yang_node *yn)
prefix = yarg_prefix(ys); /* And this its prefix */ prefix = yarg_prefix(ys); /* And this its prefix */
if (ys_grouping_resolve(ys, prefix, name, &ygrouping) < 0) if (ys_grouping_resolve(ys, prefix, name, &ygrouping) < 0)
goto done; goto done;
if (prefix)
free(prefix);
if (ygrouping == NULL){ if (ygrouping == NULL){
clicon_log(LOG_NOTICE, "%s: Yang error : grouping \"%s\" not found", clicon_log(LOG_NOTICE, "%s: Yang error : grouping \"%s\" not found in module \"%s\"",
__FUNCTION__, ys->ys_argument); __FUNCTION__, ys->ys_argument, ys_module(ys)->ys_argument);
goto done; goto done;
break; break;
} }
if (prefix)
free(prefix); /* XXX move up */
/* Check mark flag to see if this grouping (itself) has been expanded /* Check mark flag to see if this grouping (itself) has been expanded
If not, this needs to be done before we can insert it into If not, this needs to be done before we can insert it into
the 'uses' place */ the 'uses' place */
@ -1825,47 +1886,68 @@ yang_parse_file(int fd,
return ymod; /* top-level (sub)module */ 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 module
* @param[in] h CLICON handle * @param[in] h CLICON handle
* @param[in] yang_dir Directory where all YANG module files reside * @param[in] dir Directory, if NULL, look in YANG_DIR path
* @param[in] module Name of main YANG module. * @param[in] module Name of main YANG module.
* @param[in] revision Revision or NULL
* @param[out] fbuf Buffer containing filename * @param[out] fbuf Buffer containing filename
* * @note for bootstrapping, dir may have to be set.
* @retval 1 Match found, Most recent entry returned in fbuf * @retval 1 Match found, Most recent entry returned in fbuf
* @retval 0 No matching entry found * @retval 0 No matching entry found
* @retval -1 Error * @retval -1 Error
*/ */
static int static int
yang_parse_find_match(const char *yang_dir, yang_parse_find_match(clicon_handle h,
const char *module, const char *module,
const char *revision,
cbuf *fbuf) cbuf *fbuf)
{ {
int retval = -1; int retval = -1;
struct dirent *dp = NULL; struct dirent *dp = NULL;
int ndp; int ndp;
cbuf *regex = NULL; cbuf *regex = NULL;
cxobj *x;
cxobj *xc;
char *dir;
/* get clicon config file in xml form */
if ((x = clicon_conf_xml(h)) == NULL)
goto ok;
if ((regex = cbuf_new()) == NULL){ if ((regex = cbuf_new()) == NULL){
clicon_err(OE_YANG, errno, "cbuf_new"); clicon_err(OE_YANG, errno, "cbuf_new");
goto done; goto done;
} }
/* RFC 6020: The name of the file SHOULD be of the form: /* RFC 6020: The name of the file SHOULD be of the form:
module-or-submodule-name ['@' revision-date] ( '.yang' / '.yin' ) * module-or-submodule-name ['@' revision-date] ( '.yang' / '.yin' )
revision-date ::= 4DIGIT "-" 2DIGIT "-" 2DIGIT * revision-date ::= 4DIGIT "-" 2DIGIT "-" 2DIGIT
*/ */
if (revision)
cprintf(regex, "^%s@%s(.yang)$", module, revision);
else
cprintf(regex, "^%s(@[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9])?(.yang)$", cprintf(regex, "^%s(@[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9])?(.yang)$",
module); module);
if ((ndp = clicon_file_dirent(yang_dir, xc = NULL;
while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL) {
if (strcmp(xml_name(xc), "CLICON_YANG_DIR") != 0)
continue;
dir = xml_body(xc);
/* get all matching files in this directory */
if ((ndp = clicon_file_dirent(dir,
&dp, &dp,
cbuf_get(regex), cbuf_get(regex),
S_IFREG)) < 0) S_IFREG)) < 0)
goto done; goto done;
/* Entries are sorted, last entry should be most recent date */ /* Entries are sorted, last entry should be most recent date
* Found
*/
if (ndp != 0){ if (ndp != 0){
cprintf(fbuf, "%s/%s", yang_dir, dp[ndp-1].d_name); cprintf(fbuf, "%s/%s", dir, dp[ndp-1].d_name);
retval = 1; retval = 1;
goto done;
} }
else }
ok:
retval = 0; retval = 0;
done: done:
if (regex) if (regex)
@ -1875,7 +1957,6 @@ yang_parse_find_match(const char *yang_dir,
return retval; return retval;
} }
/*! Open a file, read into a string and invoke yang parsing /*! Open a file, read into a string and invoke yang parsing
* *
* Similar to clicon_yang_str(), just read a file first * Similar to clicon_yang_str(), just read a file first
@ -1903,7 +1984,6 @@ yang_parse_filename(const char *filename,
int fd = -1; int fd = -1;
struct stat st; struct stat st;
clicon_log(LOG_DEBUG, "Parsing yang file: %s", filename);
if (stat(filename, &st) < 0){ if (stat(filename, &st) < 0){
clicon_err(OE_YANG, errno, "%s not found", filename); clicon_err(OE_YANG, errno, "%s not found", filename);
goto done; goto done;
@ -1921,8 +2001,8 @@ yang_parse_filename(const char *filename,
} }
static yang_stmt * static yang_stmt *
yang_parse_module(const char *module, yang_parse_module(clicon_handle h,
const char *dir, const char *module,
const char *revision, const char *revision,
yang_spec *ysp) yang_spec *ysp)
{ {
@ -1934,17 +2014,13 @@ yang_parse_module(const char *module,
clicon_err(OE_YANG, errno, "cbuf_new"); clicon_err(OE_YANG, errno, "cbuf_new");
goto done; goto done;
} }
if (revision) /* Match a yang file with or without revision in yang-dir list */
cprintf(fbuf, "%s/%s@%s.yang", dir, module, revision); if ((nr = yang_parse_find_match(h, module, revision, fbuf)) < 0)
else{
/* No specific revision, Match a yang file */
if ((nr = yang_parse_find_match(dir, module, fbuf)) < 0)
goto done; goto done;
if (nr == 0){ if (nr == 0){
clicon_err(OE_YANG, errno, "No matching %s yang files found in %s (expected module name or absolute filename)", module, dir); clicon_err(OE_YANG, errno, "No yang files found matching \"%s\" in the list of CLICON_YANG_DIRs", module);
goto done; goto done;
} }
}
if ((ymod = yang_parse_filename(cbuf_get(fbuf), ysp)) == NULL) if ((ymod = yang_parse_filename(cbuf_get(fbuf), ysp)) == NULL)
goto done; goto done;
done: done:
@ -1953,10 +2029,9 @@ yang_parse_module(const char *module,
return ymod; /* top-level (sub)module */ return ymod; /* top-level (sub)module */
} }
/*! Parse one yang module then go through (sub)modules and parse them recursively /*! Given a (sub)module, parse all (sub)modules in turn recursively
* *
* @param[in] h CLICON handle * @param[in] h CLICON handle
* @param[in] yang_dir Directory where all YANG module files reside
* @param[in] module Name of main YANG module. Or absolute file name. * @param[in] module Name of main YANG module. Or absolute file name.
* @param[in] revision Module revision date or NULL * @param[in] revision Module revision date or NULL
* @param[in] ysp Yang specification. Should have been created by caller using yspec_new * @param[in] ysp Yang specification. Should have been created by caller using yspec_new
@ -1972,8 +2047,8 @@ yang_parse_module(const char *module,
* clixon_yang_parseparse # Actual yang parsing using yacc * clixon_yang_parseparse # Actual yang parsing using yacc
*/ */
static int static int
yang_parse_recurse(yang_stmt *ymod, yang_parse_recurse(clicon_handle h,
const char *dir, yang_stmt *ymod,
yang_spec *ysp) yang_spec *ysp)
{ {
int retval = -1; int retval = -1;
@ -1982,21 +2057,29 @@ yang_parse_recurse(yang_stmt *ymod,
char *submodule; char *submodule;
char *subrevision; char *subrevision;
yang_stmt *subymod; yang_stmt *subymod;
enum rfc_6020 keyw;
/* go through all import statements of ysp (or its module) */ /* go through all import (modules) and include(submodules) of ysp */
while ((yi = yn_each((yang_node*)ymod, yi)) != NULL){ while ((yi = yn_each((yang_node*)ymod, yi)) != NULL){
if (yi->ys_keyword != Y_IMPORT) keyw = yi->ys_keyword;
if (keyw != Y_IMPORT && keyw != Y_INCLUDE)
continue; continue;
/* common part */
submodule = yi->ys_argument; submodule = yi->ys_argument;
/* Is there a specific revision (or just latest)? */
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, submodule) == NULL){ /* if already loaded, ignore, else parse the file */
if (yang_find((yang_node*)ysp,
keyw=Y_IMPORT?Y_MODULE:Y_SUBMODULE,
submodule) == NULL){
/* recursive call */ /* recursive call */
if ((subymod = yang_parse_module(submodule, dir, subrevision, ysp)) == NULL) if ((subymod = yang_parse_module(h, submodule, subrevision, ysp)) == NULL)
goto done; goto done;
if (yang_parse_recurse(subymod, dir, ysp) < 0){ /* Go through its sub-modules recursively */
if (yang_parse_recurse(h, subymod, ysp) < 0){
ymod = NULL; ymod = NULL;
goto done; goto done;
} }
@ -2019,7 +2102,8 @@ ys_schemanode_check(yang_stmt *ys,
yp = ys->ys_parent; yp = ys->ys_parent;
switch (ys->ys_keyword){ switch (ys->ys_keyword){
case Y_AUGMENT: case Y_AUGMENT:
if (yp->yn_keyword == Y_MODULE) /* Not top-level */ if (yp->yn_keyword == Y_MODULE || /* Not top-level */
yp->yn_keyword == Y_SUBMODULE)
break; break;
/* fallthru */ /* fallthru */
case Y_REFINE: case Y_REFINE:
@ -2035,7 +2119,7 @@ ys_schemanode_check(yang_stmt *ys,
break; break;
case Y_DEVIATION: case Y_DEVIATION:
yspec = ys_spec(ys); yspec = ys_spec(ys);
if (yang_abs_schema_nodeid(yspec, ys->ys_argument, -1, &yres) < 0) if (yang_abs_schema_nodeid(yspec, ys, ys->ys_argument, -1, &yres) < 0)
goto done; goto done;
if (yres == NULL){ if (yres == NULL){
clicon_err(OE_YANG, 0, "schemanode sanity check of %s", ys->ys_argument); clicon_err(OE_YANG, 0, "schemanode sanity check of %s", ys->ys_argument);
@ -2127,10 +2211,69 @@ yang_features(clicon_handle h,
return retval; return retval;
} }
/*! Merge yang submodule into the module it belongs to
* Skip submodule header fields
* @param[in] h Clicon handle
* @param[in] yspec Yang spec
* @param[in] ysubm Yang submodule
*/
static int
yang_merge_submodules(clicon_handle h,
yang_spec *yspec,
yang_stmt *ysubm)
{
int retval = -1;
yang_stmt *yb; /* belongs-to */
yang_stmt *ymod; /* parent yang module */
yang_stmt *yc; /* yang child */
char *modname;
int i;
assert(ysubm->ys_keyword == Y_SUBMODULE);
/* Get parent name (via belongs-to) and find parent module */
if ((yb = yang_find((yang_node*)ysubm, Y_BELONGS_TO, NULL)) == NULL){
clicon_err(OE_YANG, ENOENT, "submodule %s does not have a mandatory belongs-to statement", ysubm->ys_argument);
goto done;
}
modname = yb->ys_argument;
if ((ymod = yang_find((yang_node*)yspec, Y_MODULE, modname)) == NULL){
clicon_err(OE_YANG, ENOENT, "Module %s which submodule %s belongs to is not found", modname, ysubm->ys_argument);
goto done;
}
/* Move sub-module statements to modules
* skip belongs-to, revision, organization, reference, yang-version)
* since main module has its own and may only have one
* XXX: use queue,...
*/
for (i=0; i<ysubm->ys_len; i++){
yc = ysubm->ys_stmt[i];
if (yc->ys_keyword == Y_BELONGS_TO ||
yc->ys_keyword == Y_CONTACT ||
yc->ys_keyword == Y_DESCRIPTION ||
yc->ys_keyword == Y_ORGANIZATION ||
yc->ys_keyword == Y_REVISION ||
yc->ys_keyword == Y_REFERENCE ||
yc->ys_keyword == Y_YANG_VERSION)
ys_free(yc);
else{
if (yn_insert((yang_node*)ymod, yc) < 0)
goto done;
}
}
if (ysubm->ys_stmt){
free(ysubm->ys_stmt);
ysubm->ys_stmt = NULL;
}
ysubm->ys_len = 0;
ys_free(ysubm);
retval = 0;
done:
return retval;
}
/*! Parse top yang module including all its sub-modules. Expand and populate yang tree /*! Parse top yang module including all its sub-modules. Expand and populate yang tree
* *
* @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] filename File name containing Yang specification. Overrides module * @param[in] filename File name containing Yang specification. Overrides module
* @param[in] module Name of main YANG module. Or absolute file name. * @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
@ -2154,7 +2297,6 @@ int
yang_parse(clicon_handle h, yang_parse(clicon_handle h,
const char *filename, const char *filename,
const char *module, const char *module,
const char *dir,
const char *revision, const char *revision,
yang_spec *ysp, yang_spec *ysp,
yang_stmt **ymodp) yang_stmt **ymodp)
@ -2164,63 +2306,89 @@ yang_parse(clicon_handle h,
int i; int i;
int modnr; /* Existing number of modules */ int modnr; /* Existing number of modules */
/* Apply steps 2.. on new modules, ie ones after modnr. */
modnr = ysp->yp_len; modnr = ysp->yp_len;
if (filename){ if (filename){
if ((ymod = yang_parse_filename(filename, ysp)) == NULL) if ((ymod = yang_parse_filename(filename, ysp)) == NULL)
goto done; goto done;
} }
else else
if ((ymod = yang_parse_module(module, dir, revision, ysp)) == NULL) if ((ymod = yang_parse_module(h, module, revision, ysp)) == NULL)
goto done; goto done;
/* From here on, apply actions on new modules, ie ones after modnr. */ /* 1: Parse from text to yang parse-tree. */
/* Step 1: parse from text to yang parse-tree. */
/* Iterate through modules */ /* Iterate through modules */
if (yang_parse_recurse(ymod, dir, ysp) < 0) if (yang_parse_recurse(h, ymod, ysp) < 0)
goto done; goto done;
/* Check cardinality maybe this should be done after grouping/augment */ /* 2. Check cardinality maybe this should be done after grouping/augment */
for (i=modnr; i<ysp->yp_len; i++) /* XXX */ for (i=modnr; i<ysp->yp_len; i++) /* XXX */
if (yang_cardinality(h, ysp->yp_stmt[i], ysp->yp_stmt[i]->ys_argument) < 0) if (yang_cardinality(h, ysp->yp_stmt[i], ysp->yp_stmt[i]->ys_argument) < 0)
goto done; goto done;
/* Step 2: check features: check if enabled and remove disabled features */ /* 3: Merge sub-modules with modules - after this step, no submodules exist
* In the merge, remove submodule headers
*/
for (i=modnr; i<ysp->yp_len; i++){
if (ysp->yp_stmt[i]->ys_keyword != Y_SUBMODULE)
continue;
}
i = 0;
while (i<ysp->yp_len){
int j;
if (ysp->yp_stmt[i]->ys_keyword != Y_SUBMODULE){
i++;
continue;
}
if (yang_merge_submodules(h, ysp, ysp->yp_stmt[i]) < 0)
goto done;
/* shift down one step */
for (j=i; j<ysp->yp_len-1; j++)
ysp->yp_stmt[j] = ysp->yp_stmt[j+1];
ysp->yp_len--;
}
/* 4: Check features: check if enabled and remove disabled features */
for (i=modnr; i<ysp->yp_len; i++) /* XXX */ for (i=modnr; i<ysp->yp_len; i++) /* XXX */
if (yang_features(h, ysp->yp_stmt[i]) < 0) if (yang_features(h, ysp->yp_stmt[i]) < 0)
goto done; goto done;
/* Step 3: Go through parse tree and populate it with cv types */ /* 5: Go through parse tree and populate it with cv types */
for (i=modnr; i<ysp->yp_len; i++) for (i=modnr; i<ysp->yp_len; i++)
if (yang_apply((yang_node*)ysp->yp_stmt[i], -1, ys_populate, (void*)h) < 0) if (yang_apply((yang_node*)ysp->yp_stmt[i], -1, ys_populate, (void*)h) < 0)
goto done; goto done;
/* 6: Resolve all types: populate type caches. Requires eg length/range cvecs
/* Step 4: Resolve all types: populate type caches. Requires eg length/range cvecs * from ys_populate step.
* from ys_populate step * Must be done using static binding.
*/ */
for (i=modnr; i<ysp->yp_len; i++) for (i=modnr; i<ysp->yp_len; i++)
yang_apply((yang_node*)ysp->yp_stmt[i], Y_TYPE, ys_resolve_type, NULL); if (yang_apply((yang_node*)ysp->yp_stmt[i], Y_TYPE, ys_resolve_type, NULL) < 0)
goto done;
/* 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
context they are used. Like static scoping. After this we expand all * than the context they are used (except for submodules being merged w
grouping/uses and unfold all macros into a single tree as they are used. * modules). Like static scoping.
* After this we expand all grouping/uses and unfold all macros into a
*single tree as they are used.
*/ */
/* Step 5: Macro expansion of all grouping/uses pairs. Expansion needs marking */ /* 7: Macro expansion of all grouping/uses pairs. Expansion needs marking */
for (i=modnr; i<ysp->yp_len; i++){ for (i=modnr; i<ysp->yp_len; i++){
if (yang_expand((yang_node*)ysp->yp_stmt[i]) < 0) if (yang_expand((yang_node*)ysp->yp_stmt[i]) < 0)
goto done; goto done;
yang_apply((yang_node*)ysp->yp_stmt[i], -1, ys_flag_reset, (void*)YANG_FLAG_MARK); yang_apply((yang_node*)ysp->yp_stmt[i], -1, ys_flag_reset, (void*)YANG_FLAG_MARK);
} }
/* Step 6: Top-level augmentation of all modules XXX: only new modules? */ /* 8: 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;
/* Step 7: sanity check of schemanode references, need more here */ /* 9: sanity check of schemanode references, need more here */
for (i=modnr; i<ysp->yp_len; i++) for (i=modnr; i<ysp->yp_len; i++)
if (yang_apply((yang_node*)ysp->yp_stmt[i], -1, ys_schemanode_check, NULL) < 0) if (yang_apply((yang_node*)ysp->yp_stmt[i], -1, ys_schemanode_check, NULL) < 0)
goto done; goto done;
/* Return main module parsed in step 1 */
if (ymodp) if (ymodp)
*ymodp = ymod; *ymodp = ymod;
retval = 0; retval = 0;
@ -2367,6 +2535,7 @@ schema_nodeid_vec(yang_node *yn,
/*! Given an absolute schema-nodeid (eg /a/b/c) find matching yang spec /*! Given an absolute schema-nodeid (eg /a/b/c) find matching yang spec
* @param[in] yspec Yang specification. * @param[in] yspec Yang specification.
* @param[in] yn Original yang stmt (where call is made) if any
* @param[in] schema_nodeid Absolute schema-node-id, ie /a/b * @param[in] schema_nodeid Absolute schema-node-id, ie /a/b
* @param[in] keyword A schemode of this type, or -1 if any * @param[in] keyword A schemode of this type, or -1 if any
* @param[out] yres Result yang statement node, or NULL if not found * @param[out] yres Result yang statement node, or NULL if not found
@ -2382,6 +2551,7 @@ schema_nodeid_vec(yang_node *yn,
*/ */
int int
yang_abs_schema_nodeid(yang_spec *yspec, yang_abs_schema_nodeid(yang_spec *yspec,
yang_stmt *yn,
char *schema_nodeid, char *schema_nodeid,
enum rfc_6020 keyword, enum rfc_6020 keyword,
yang_stmt **yres) yang_stmt **yres)
@ -2389,7 +2559,7 @@ yang_abs_schema_nodeid(yang_spec *yspec,
int retval = -1; int retval = -1;
char **vec = NULL; char **vec = NULL;
int nvec; int nvec;
yang_stmt *ymod; yang_stmt *ymod = NULL;
char *id; char *id;
char *prefix = NULL; char *prefix = NULL;
yang_stmt *yprefix; yang_stmt *yprefix;
@ -2421,6 +2591,9 @@ yang_abs_schema_nodeid(yang_spec *yspec,
} }
prefix[id-vec[1]] = '\0'; prefix[id-vec[1]] = '\0';
id++; id++;
if (yn) /* Find module using local prefix definition */
ymod = yang_find_module_by_prefix(yn, prefix);
if (ymod == NULL){ /* Try (global) prefix the module itself uses */
ymod = NULL; ymod = NULL;
while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) { while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) {
if ((yprefix = yang_find((yang_node*)ymod, Y_PREFIX, NULL)) != NULL && if ((yprefix = yang_find((yang_node*)ymod, Y_PREFIX, NULL)) != NULL &&
@ -2428,9 +2601,10 @@ yang_abs_schema_nodeid(yang_spec *yspec,
break; break;
} }
} }
if (ymod == NULL){ /* Try with topnode */ }
if (ymod == NULL){ /* Try find id from topnode without prefix XXX remove?*/
if ((ys = yang_find_topnode(yspec, id, YC_SCHEMANODE)) == NULL){ if ((ys = yang_find_topnode(yspec, id, YC_SCHEMANODE)) == NULL){
clicon_err(OE_YANG, 0, "Module with id:%s:%s not found", prefix,id); clicon_err(OE_YANG, 0, "Module with id:\"%s:%s\" not found", prefix,id);
goto done; goto done;
} }
if ((ymod = ys_module(ys)) == NULL){ if ((ymod = ys_module(ys)) == NULL){
@ -2439,7 +2613,7 @@ yang_abs_schema_nodeid(yang_spec *yspec,
} }
if ((yprefix = yang_find((yang_node*)ymod, Y_PREFIX, NULL)) != NULL && if ((yprefix = yang_find((yang_node*)ymod, Y_PREFIX, NULL)) != NULL &&
strcmp(yprefix->ys_argument, prefix) != 0){ strcmp(yprefix->ys_argument, prefix) != 0){
clicon_err(OE_YANG, 0, "Module with id:%s:%s not found", prefix,id); clicon_err(OE_YANG, 0, "Module with id:\"%s:%s\" not found", prefix,id);
goto done; goto done;
} }
} }
@ -2546,12 +2720,7 @@ ys_parse_sub(yang_stmt *ys,
char *extra) char *extra)
{ {
int retval = -1; int retval = -1;
int cvret;
char *reason = NULL;
yang_stmt *ymod;
uint8_t fd; uint8_t fd;
char *prefix = NULL;
char *name;
switch (ys->ys_keyword){ switch (ys->ys_keyword){
case Y_FRACTION_DIGITS: case Y_FRACTION_DIGITS:
@ -2563,40 +2732,17 @@ ys_parse_sub(yang_stmt *ys,
goto done; goto done;
} }
break; break;
case Y_UNKNOWN: case Y_UNKNOWN: /* XXX This code assumes ymod already loaded
but it may not be */
if (extra == NULL) if (extra == NULL)
break; break;
/* Find extension, if found, store it as unknown, if not, ys->ys_extra = extra;
break for error */
prefix = yarg_prefix(ys); /* And this its prefix */
name = yarg_id(ys); /* This is the type to resolve */
if ((ymod = yang_find_module_by_prefix(ys, prefix)) == NULL)
goto ok; /* shouldnt happen */
if (yang_find((yang_node*)ymod, Y_EXTENSION, name) == NULL){
clicon_err(OE_YANG, errno, "Extension %s:%s not found", prefix, name);
goto done;
}
if ((ys->ys_cv = cv_new(CGV_STRING)) == NULL){
clicon_err(OE_YANG, errno, "cv_new");
goto done;
}
if ((cvret = cv_parse1(extra, ys->ys_cv, &reason)) < 0){ /* error */
clicon_err(OE_YANG, errno, "parsing cv");
goto done;
}
if (cvret == 0){ /* parsing failed */
clicon_err(OE_YANG, errno, "Parsing CV: %s", reason);
goto done;
}
break; break;
default: default:
break; break;
} }
ok:
retval = 0; retval = 0;
done: done:
if (prefix)
free(prefix);
return retval; return retval;
} }
@ -2654,7 +2800,6 @@ yang_config(yang_stmt *ys)
int int
yang_spec_parse_module(clicon_handle h, yang_spec_parse_module(clicon_handle h,
char *module, char *module,
char *dir,
char *revision, char *revision,
yang_spec *yspec, yang_spec *yspec,
yang_stmt **ymodp) yang_stmt **ymodp)
@ -2674,11 +2819,7 @@ yang_spec_parse_module(clicon_handle h,
clicon_err(OE_YANG, EINVAL, "yang module illegal format"); clicon_err(OE_YANG, EINVAL, "yang module illegal format");
goto done; goto done;
} }
if (dir == NULL){ if (yang_parse(h, NULL, module, revision, yspec, ymodp) < 0)
clicon_err(OE_YANG, EINVAL, "yang dir not set");
goto done;
}
if (yang_parse(h, NULL, module, dir, revision, yspec, ymodp) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:
@ -2698,7 +2839,6 @@ yang_spec_parse_module(clicon_handle h,
int int
yang_spec_parse_file(clicon_handle h, yang_spec_parse_file(clicon_handle h,
char *filename, char *filename,
char *dir,
yang_spec *yspec, yang_spec *yspec,
yang_stmt **ymodp) yang_stmt **ymodp)
{ {
@ -2708,11 +2848,7 @@ yang_spec_parse_file(clicon_handle h,
clicon_err(OE_YANG, EINVAL, "yang spec is NULL"); clicon_err(OE_YANG, EINVAL, "yang spec is NULL");
goto done; goto done;
} }
if (dir == NULL){ if (yang_parse(h, filename, NULL, NULL, yspec, ymodp) < 0)
clicon_err(OE_YANG, EINVAL, "yang dir not set");
goto done;
}
if (yang_parse(h, filename, NULL, dir, NULL, yspec, ymodp) < 0)
goto done; goto done;
retval = 0; retval = 0;
done: done:

View file

@ -193,7 +193,8 @@ yang_cardinality(clicon_handle h,
pk = yt->ys_keyword; pk = yt->ys_keyword;
/* 0) Find parent sub-parts of cardinality vector */ /* 0) Find parent sub-parts of cardinality vector */
ycplist = ycard_find(pk, 0, yclist, 0); if ((ycplist = ycard_find(pk, 0, yclist, 0)) == NULL)
goto ok; /* skip */
/* 1) For all children, if neither in 0..n, 0..1, 1 or 1..n ->ERROR */ /* 1) For all children, if neither in 0..n, 0..1, 1 or 1..n ->ERROR */
i = 0; i = 0;
while (i<yt->ys_len){ while (i<yt->ys_len){
@ -239,6 +240,7 @@ yang_cardinality(clicon_handle h,
goto done; goto done;
} }
} }
ok:
retval = 0; retval = 0;
done: done:
return retval; return retval;

View file

@ -77,7 +77,6 @@
* *
* Load RFC7895 yang spec, module-set-id, etc. * Load RFC7895 yang spec, module-set-id, etc.
* @param[in] h Clicon handle * @param[in] h Clicon handle
* @note CLIXON_DATADIR is hardcoded
*/ */
int int
yang_modules_init(clicon_handle h) yang_modules_init(clicon_handle h)
@ -94,7 +93,7 @@ yang_modules_init(clicon_handle h)
goto done; goto done;
} }
/* Ensure revision exists is set */ /* Ensure revision exists is set */
if (yang_spec_parse_module(h, "ietf-yang-library", CLIXON_DATADIR, NULL, yspec, NULL)< 0) if (yang_spec_parse_module(h, "ietf-yang-library", NULL, yspec, NULL)< 0)
goto done; goto done;
/* Find revision */ /* Find revision */
if (yang_modules_revision(h) == NULL){ if (yang_modules_revision(h) == NULL){
@ -121,7 +120,8 @@ yang_modules_revision(clicon_handle h)
char *revision = NULL; char *revision = NULL;
yspec = clicon_dbspec_yang(h); yspec = clicon_dbspec_yang(h);
if ((ymod = yang_find((yang_node*)yspec, Y_MODULE, "ietf-yang-library")) != NULL){ if ((ymod = yang_find((yang_node*)yspec, Y_MODULE, "ietf-yang-library")) != NULL ||
(ymod = yang_find((yang_node*)yspec, Y_SUBMODULE, "ietf-yang-library")) != NULL){
if ((yrev = yang_find((yang_node*)ymod, Y_REVISION, NULL)) != NULL){ if ((yrev = yang_find((yang_node*)ymod, Y_REVISION, NULL)) != NULL){
revision = yrev->ys_argument; revision = yrev->ys_argument;
} }
@ -172,7 +172,8 @@ yang_modules_state_get(clicon_handle h,
char *module = "ietf-yang-library"; char *module = "ietf-yang-library";
module_set_id = clicon_option_str(h, "CLICON_MODULE_SET_ID"); module_set_id = clicon_option_str(h, "CLICON_MODULE_SET_ID");
if ((ylib = yang_find((yang_node*)yspec, Y_MODULE, module)) == NULL){ if ((ylib = yang_find((yang_node*)yspec, Y_MODULE, module)) == NULL &&
(ylib = yang_find((yang_node*)yspec, Y_SUBMODULE, module)) == NULL){
clicon_err(OE_YANG, 0, "%s not found", module); clicon_err(OE_YANG, 0, "%s not found", module);
goto done; goto done;
} }
@ -189,7 +190,8 @@ yang_modules_state_get(clicon_handle h,
ymod = NULL; ymod = NULL;
while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) { while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) {
if (ymod->ys_keyword != Y_MODULE) if (ymod->ys_keyword != Y_MODULE &&
ymod->ys_keyword != Y_SUBMODULE)
continue; continue;
cprintf(cb,"<module>"); cprintf(cb,"<module>");
cprintf(cb,"<name>%s</name>", ymod->ys_argument); cprintf(cb,"<name>%s</name>", ymod->ys_argument);

View file

@ -42,9 +42,6 @@
* identifier_ref = prefix : IDENTIFIER * identifier_ref = prefix : IDENTIFIER
* node_identier = prefix : IDENTIFIER * node_identier = prefix : IDENTIFIER
* *
* Missing top-level statements (will break parser if in yang spec):
* - error-app-tag-stmt
* - any-data-stmt
* Missing args (just strings); * Missing args (just strings);
* - length-arg-str * - length-arg-str
* - path-arg-str * - path-arg-str
@ -124,6 +121,7 @@
%token K_MANDATORY %token K_MANDATORY
%token K_MAX_ELEMENTS %token K_MAX_ELEMENTS
%token K_MIN_ELEMENTS %token K_MIN_ELEMENTS
%token K_MODIFIER
%token K_MODULE %token K_MODULE
%token K_MUST %token K_MUST
%token K_NAMESPACE %token K_NAMESPACE
@ -369,29 +367,28 @@ file : module_stmt MY_EOF
/* For extensions */ /* For extensions */
unknown_stmt : ustring ':' ustring ';' unknown_stmt : ustring ':' ustring ';'
{ char *id; if ((id=string_del_join($1, ":", $3)) == NULL) _YYERROR("0"); { char *id; if ((id=string_del_join($1, ":", $3)) == NULL) _YYERROR("unknown_stmt");
if (ysp_add(_yy, Y_UNKNOWN, id, NULL) == NULL) _YYERROR("0"); if (ysp_add(_yy, Y_UNKNOWN, id, NULL) == NULL) _YYERROR("unknown_stmt");
clicon_debug(2,"unknown-stmt -> ustring : ustring"); clicon_debug(2,"unknown-stmt -> ustring : ustring");
} }
| ustring ':' ustring ' ' string ';' | ustring ':' ustring ' ' string ';'
{ char *id; if ((id=string_del_join($1, ":", $3)) == NULL) _YYERROR("0"); { char *id; if ((id=string_del_join($1, ":", $3)) == NULL) _YYERROR("unknwon_stmt");
if (ysp_add(_yy, Y_UNKNOWN, id, $5) == NULL){ _YYERROR("0"); } if (ysp_add(_yy, Y_UNKNOWN, id, $5) == NULL){ _YYERROR("unknwon_stmt"); }
clicon_debug(2,"unknown-stmt -> ustring : ustring string"); clicon_debug(2,"unknown-stmt -> ustring : ustring string");
if ($5) free($5);
} }
; ;
/* module identifier-arg-str */ /* module identifier-arg-str */
module_stmt : K_MODULE identifier_str module_stmt : K_MODULE identifier_str
{ if ((_YY->yy_module = ysp_add_push(_yy, Y_MODULE, $2)) == NULL) _YYERROR("1"); { if ((_YY->yy_module = ysp_add_push(_yy, Y_MODULE, $2)) == NULL) _YYERROR("module_stmt");
} }
'{' module_substmts '}' '{' module_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("2"); { if (ystack_pop(_yy) < 0) _YYERROR("module_stmt");
clicon_debug(2,"module_stmt -> id-arg-str { module-substmts }");} clicon_debug(2,"module_stmt -> id-arg-str { module-substmts }");}
; ;
module_substmts : module_substmts module_substmt module_substmts : module_substmts module_substmt
{ clicon_debug(2,"module-substmts -> module-substmts module-substm");} {clicon_debug(2,"module-substmts -> module-substmts module-substm");}
| module_substmt | module_substmt
{ clicon_debug(2,"module-substmts ->");} { clicon_debug(2,"module-substmts ->");}
; ;
@ -406,10 +403,11 @@ module_substmt : module_header_stmts { clicon_debug(2,"module-substmt -> module-
; ;
/* submodule */ /* submodule */
submodule_stmt : K_SUBMODULE identifier_str '{' submodule_substmts '}' submodule_stmt : K_SUBMODULE identifier_str
{ if ((_YY->yy_module = ysp_add_push(_yy, Y_SUBMODULE, $2)) == NULL) _YYERROR("3"); { if ((_YY->yy_module = ysp_add_push(_yy, Y_SUBMODULE, $2)) == NULL) _YYERROR("submodule_stmt"); }
clicon_debug(2,"submodule -> id-arg-str { submodule-stmts }"); '{' submodule_substmts '}'
} { if (ystack_pop(_yy) < 0) _YYERROR("submodule_stmt");
clicon_debug(2,"submodule_stmt -> id-arg-str { submodule-substmts }");}
; ;
submodule_substmts : submodule_substmts submodule_substmt submodule_substmts : submodule_substmts submodule_substmt
@ -464,16 +462,16 @@ submodule_header_stmt : yang_version_stmt
; ;
/* yang-version-stmt = yang-version-keyword yang-version-arg-str */ /* yang-version-stmt = yang-version-keyword yang-version-arg-str */
yang_version_stmt : K_YANG_VERSION string ';' yang_version_stmt : K_YANG_VERSION string stmtend
{ if (ysp_add(_yy, Y_YANG_VERSION, $2, NULL) == NULL) _YYERROR("83"); { if (ysp_add(_yy, Y_YANG_VERSION, $2, NULL) == NULL) _YYERROR("yang_version_stmt");
clicon_debug(2,"yang-version-stmt -> YANG-VERSION string"); } clicon_debug(2,"yang-version-stmt -> YANG-VERSION string"); }
; ;
/* import */ /* import */
import_stmt : K_IMPORT identifier_str import_stmt : K_IMPORT identifier_str
{ if (ysp_add_push(_yy, Y_IMPORT, $2) == NULL) _YYERROR("81"); } { if (ysp_add_push(_yy, Y_IMPORT, $2) == NULL) _YYERROR("import_stmt"); }
'{' import_substmts '}' '{' import_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("82"); { if (ystack_pop(_yy) < 0) _YYERROR("import_stmt");
clicon_debug(2,"import-stmt -> IMPORT id-arg-str { import-substmts }");} clicon_debug(2,"import-stmt -> IMPORT id-arg-str { import-substmts }");}
; ;
@ -485,68 +483,78 @@ import_substmts : import_substmts import_substmt
import_substmt : prefix_stmt { clicon_debug(2,"import-stmt -> prefix-stmt"); } import_substmt : prefix_stmt { clicon_debug(2,"import-stmt -> prefix-stmt"); }
| revision_date_stmt { clicon_debug(2,"import-stmt -> revision-date-stmt"); } | revision_date_stmt { clicon_debug(2,"import-stmt -> revision-date-stmt"); }
| description_stmt { clicon_debug(2,"import-stmt -> description-stmt"); }
| reference_stmt { clicon_debug(2,"import-stmt -> reference-stmt"); }
; ;
include_stmt : K_INCLUDE identifier_str ';' include_stmt : K_INCLUDE identifier_str ';'
{ if (ysp_add(_yy, Y_INCLUDE, $2, NULL)== NULL) _YYERROR("97"); { if (ysp_add(_yy, Y_INCLUDE, $2, NULL)== NULL) _YYERROR("include_stmt");
clicon_debug(2,"include-stmt -> id-arg-str"); } clicon_debug(2,"include-stmt -> id-str"); }
| K_INCLUDE identifier_str '{' revision_date_stmt '}' | K_INCLUDE identifier_str '{' include_substmts '}'
{ if (ysp_add(_yy, Y_INCLUDE, $2, NULL)== NULL) _YYERROR("98"); { if (ysp_add(_yy, Y_INCLUDE, $2, NULL)== NULL) _YYERROR("include_stmt");
clicon_debug(2,"include-stmt -> id-arg-str { revision-date-stmt }"); } clicon_debug(2,"include-stmt -> id-str { include-substmts }"); }
; ;
include_substmts : include_substmts include_substmt
{ clicon_debug(2,"include-substmts -> include-substmts include-substm");}
| include_substmt
{ clicon_debug(2,"include-substmts ->");}
;
include_substmt : revision_date_stmt { clicon_debug(2,"include-stmt -> revision-date-stmt"); }
| description_stmt { clicon_debug(2,"include-stmt -> description-stmt"); }
| reference_stmt { clicon_debug(2,"include-stmt -> reference-stmt"); }
;
/* namespace-stmt = namespace-keyword sep uri-str */ /* namespace-stmt = namespace-keyword sep uri-str */
namespace_stmt : K_NAMESPACE string stmtend namespace_stmt : K_NAMESPACE string stmtend
{ if (ysp_add(_yy, Y_NAMESPACE, $2, NULL)== NULL) _YYERROR("99"); { if (ysp_add(_yy, Y_NAMESPACE, $2, NULL)== NULL) _YYERROR("namespace_stmt");
clicon_debug(2,"namespace-stmt -> NAMESPACE string"); } clicon_debug(2,"namespace-stmt -> NAMESPACE string"); }
; ;
prefix_stmt : K_PREFIX identifier_str ';' /* XXX prefix-arg-str */ prefix_stmt : K_PREFIX identifier_str stmtend /* XXX prefix-arg-str */
{ if (ysp_add(_yy, Y_PREFIX, $2, NULL)== NULL) _YYERROR("100"); { if (ysp_add(_yy, Y_PREFIX, $2, NULL)== NULL) _YYERROR("prefix_stmt");
clicon_debug(2,"prefix-stmt -> PREFIX string ;");} clicon_debug(2,"prefix-stmt -> PREFIX string ;");}
; ;
belongs_to_stmt : K_BELONGS_TO identifier_str ';' belongs_to_stmt : K_BELONGS_TO identifier_str '{' prefix_stmt '}'
{ if (ysp_add(_yy, Y_BELONGS_TO, $2, NULL)== NULL) _YYERROR("belongs_to_stmt");
{ if (ysp_add(_yy, Y_BELONGS_TO, $2, NULL)== NULL) _YYERROR("100");
clicon_debug(2,"belongs-to-stmt -> BELONGS-TO id-arg-str ;");}
| K_BELONGS_TO identifier_str '{' prefix_stmt '}'
{ if (ysp_add(_yy, Y_BELONGS_TO, $2, NULL)== NULL) _YYERROR("98");
clicon_debug(2,"belongs-to-stmt -> BELONGS-TO id-arg-str { prefix-stmt } ");} clicon_debug(2,"belongs-to-stmt -> BELONGS-TO id-arg-str { prefix-stmt } ");}
; ;
organization_stmt: K_ORGANIZATION string ';' organization_stmt: K_ORGANIZATION string stmtend
{ if (ysp_add(_yy, Y_ORGANIZATION, $2, NULL)== NULL) _YYERROR("102"); { if (ysp_add(_yy, Y_ORGANIZATION, $2, NULL)== NULL) _YYERROR("belongs_to_stmt");
clicon_debug(2,"organization-stmt -> ORGANIZATION string ;");} clicon_debug(2,"organization-stmt -> ORGANIZATION string ;");}
; ;
contact_stmt : K_CONTACT string ';' contact_stmt : K_CONTACT string stmtend
{ if (ysp_add(_yy, Y_CONTACT, $2, NULL)== NULL) _YYERROR("95"); { if (ysp_add(_yy, Y_CONTACT, $2, NULL)== NULL) _YYERROR("contact_stmt");
clicon_debug(2,"contact-stmt -> CONTACT string"); } clicon_debug(2,"contact-stmt -> CONTACT string"); }
; ;
description_stmt: K_DESCRIPTION string ';' description_stmt : K_DESCRIPTION string stmtend
{ if (ysp_add(_yy, Y_DESCRIPTION, $2, NULL)== NULL) _YYERROR("101"); { if (ysp_add(_yy, Y_DESCRIPTION, $2, NULL)== NULL) _YYERROR("description_stmt");
clicon_debug(2,"description-stmt -> DESCRIPTION string ;");} clicon_debug(2,"description-stmt -> DESCRIPTION string ;");}
; ;
reference_stmt: K_REFERENCE string ';' reference_stmt : K_REFERENCE string stmtend
{ if (ysp_add(_yy, Y_REFERENCE, $2, NULL)== NULL) _YYERROR("105"); { if (ysp_add(_yy, Y_REFERENCE, $2, NULL)== NULL) _YYERROR("reference_stmt");
clicon_debug(2,"reference-stmt -> REFERENCE string ;");} clicon_debug(2,"reference-stmt -> REFERENCE string ;");}
; ;
units_stmt : K_UNITS string ';' units_stmt : K_UNITS string ';'
{ if (ysp_add(_yy, Y_UNITS, $2, NULL)== NULL) _YYERROR("93"); { if (ysp_add(_yy, Y_UNITS, $2, NULL)== NULL) _YYERROR("units_stmt");
clicon_debug(2,"units-stmt -> UNITS string"); } clicon_debug(2,"units-stmt -> UNITS string"); }
; ;
revision_stmt : K_REVISION string ';' /* XXX date-arg-str */ revision_stmt : K_REVISION string ';' /* XXX date-arg-str */
{ if (ysp_add(_yy, Y_REVISION, $2, NULL) == NULL) _YYERROR("4"); { if (ysp_add(_yy, Y_REVISION, $2, NULL) == NULL) _YYERROR("revision_stmt");
clicon_debug(2,"revision-stmt -> date-arg-str ;"); } clicon_debug(2,"revision-stmt -> date-arg-str ;"); }
| K_REVISION string | K_REVISION string
{ if (ysp_add_push(_yy, Y_REVISION, $2) == NULL) _YYERROR("5"); } { if (ysp_add_push(_yy, Y_REVISION, $2) == NULL) _YYERROR("revision_stmt"); }
'{' revision_substmts '}' /* XXX date-arg-str */ '{' revision_substmts '}' /* XXX date-arg-str */
{ if (ystack_pop(_yy) < 0) _YYERROR("6"); { if (ystack_pop(_yy) < 0) _YYERROR("revision_stmt");
clicon_debug(2,"revision-stmt -> date-arg-str { revision-substmts }"); } clicon_debug(2,"revision-stmt -> date-arg-str { revision-substmts }"); }
; ;
@ -570,19 +578,18 @@ revision_stmts : revision_stmts revision_stmt
{ clicon_debug(2,"revision-stmts -> "); } { clicon_debug(2,"revision-stmts -> "); }
; ;
revision_date_stmt : K_REVISION_DATE string ';' /* XXX date-arg-str */ revision_date_stmt : K_REVISION_DATE string stmtend /* XXX date-arg-str */
{ if (ysp_add(_yy, Y_REVISION_DATE, $2, NULL) == NULL) _YYERROR("96"); { if (ysp_add(_yy, Y_REVISION_DATE, $2, NULL) == NULL) _YYERROR("revision_date_stmt");
clicon_debug(2,"revision-date-stmt -> date;"); } clicon_debug(2,"revision-date-stmt -> date;"); }
; ;
/* Extension */ extension_stmt : K_EXTENSION identifier_str ';'
extension_stmt: K_EXTENSION identifier_str ';' { if (ysp_add(_yy, Y_EXTENSION, $2, NULL) == NULL) _YYERROR("extension_stmt");
{ if (ysp_add(_yy, Y_EXTENSION, $2, NULL) == NULL) _YYERROR("59");
clicon_debug(2,"extenstion-stmt -> EXTENSION id-arg-str ;"); } clicon_debug(2,"extenstion-stmt -> EXTENSION id-arg-str ;"); }
| K_EXTENSION identifier_str | K_EXTENSION identifier_str
{ if (ysp_add_push(_yy, Y_EXTENSION, $2) == NULL) _YYERROR("60"); } { if (ysp_add_push(_yy, Y_EXTENSION, $2) == NULL) _YYERROR("extension_stmt"); }
'{' extension_substmts '}' '{' extension_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("61"); { if (ystack_pop(_yy) < 0) _YYERROR("extension_stmt");
clicon_debug(2,"extension-stmt -> FEATURE id-arg-str { extension-substmts }"); } clicon_debug(2,"extension-stmt -> FEATURE id-arg-str { extension-substmts }"); }
; ;
@ -612,13 +619,13 @@ yin_element_stmt1 : K_YIN_ELEMENT bool_str stmtend {free($2);}
/* Identity */ /* Identity */
identity_stmt : K_IDENTITY identifier_str ';' identity_stmt : K_IDENTITY identifier_str ';'
{ if (ysp_add(_yy, Y_IDENTITY, $2, NULL) == NULL) _YYERROR("65"); { if (ysp_add(_yy, Y_IDENTITY, $2, NULL) == NULL) _YYERROR("identity_stmt");
clicon_debug(2,"identity-stmt -> IDENTITY string ;"); } clicon_debug(2,"identity-stmt -> IDENTITY string ;"); }
| K_IDENTITY identifier_str | K_IDENTITY identifier_str
{ if (ysp_add_push(_yy, Y_IDENTITY, $2) == NULL) _YYERROR("66"); } { if (ysp_add_push(_yy, Y_IDENTITY, $2) == NULL) _YYERROR("identity_stmt"); }
'{' identity_substmts '}' '{' identity_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("67"); { if (ystack_pop(_yy) < 0) _YYERROR("identity_stmt");
clicon_debug(2,"identity-stmt -> IDENTITY string { identity-substmts }"); } clicon_debug(2,"identity-stmt -> IDENTITY string { identity-substmts }"); }
; ;
@ -636,19 +643,19 @@ identity_substmt : base_stmt { clicon_debug(2,"identity-substmt -> base-
| { clicon_debug(2,"identity-substmt -> "); } | { clicon_debug(2,"identity-substmt -> "); }
; ;
base_stmt : K_BASE identifier_ref_str ';' base_stmt : K_BASE identifier_ref_str stmtend
{ if (ysp_add(_yy, Y_BASE, $2, NULL)== NULL) _YYERROR("90"); { if (ysp_add(_yy, Y_BASE, $2, NULL)== NULL) _YYERROR("base_stmt");
clicon_debug(2,"base-stmt -> BASE identifier-ref-arg-str"); } clicon_debug(2,"base-stmt -> BASE identifier-ref-arg-str"); }
; ;
/* Feature */ /* Feature */
feature_stmt : K_FEATURE identifier_str ';' feature_stmt : K_FEATURE identifier_str ';'
{ if (ysp_add(_yy, Y_FEATURE, $2, NULL) == NULL) _YYERROR("62"); { if (ysp_add(_yy, Y_FEATURE, $2, NULL) == NULL) _YYERROR("feature_stmt");
clicon_debug(2,"feature-stmt -> FEATURE id-arg-str ;"); } clicon_debug(2,"feature-stmt -> FEATURE id-arg-str ;"); }
| K_FEATURE identifier_str | K_FEATURE identifier_str
{ if (ysp_add_push(_yy, Y_FEATURE, $2) == NULL) _YYERROR("63"); } { if (ysp_add_push(_yy, Y_FEATURE, $2) == NULL) _YYERROR("feature_stmt"); }
'{' feature_substmts '}' '{' feature_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("64"); { if (ystack_pop(_yy) < 0) _YYERROR("feature_stmt");
clicon_debug(2,"feature-stmt -> FEATURE id-arg-str { feature-substmts }"); } clicon_debug(2,"feature-stmt -> FEATURE id-arg-str { feature-substmts }"); }
; ;
@ -669,15 +676,15 @@ feature_substmt : if_feature_stmt { clicon_debug(2,"feature-substmt -> if-fea
/* if-feature-stmt = if-feature-keyword sep if-feature-expr-str */ /* if-feature-stmt = if-feature-keyword sep if-feature-expr-str */
if_feature_stmt : K_IF_FEATURE string stmtend if_feature_stmt : K_IF_FEATURE string stmtend
{ if (ysp_add(_yy, Y_IF_FEATURE, $2, NULL) == NULL) _YYERROR("85"); { if (ysp_add(_yy, Y_IF_FEATURE, $2, NULL) == NULL) _YYERROR("if_feature_stmt");
clicon_debug(2,"if-feature-stmt -> IF-FEATURE identifier-ref-arg-str"); } clicon_debug(2,"if-feature-stmt -> IF-FEATURE identifier-ref-arg-str"); }
; ;
/* Typedef */ /* Typedef */
typedef_stmt : K_TYPEDEF identifier_str typedef_stmt : K_TYPEDEF identifier_str
{ if (ysp_add_push(_yy, Y_TYPEDEF, $2) == NULL) _YYERROR("46"); } { if (ysp_add_push(_yy, Y_TYPEDEF, $2) == NULL) _YYERROR("typedef_stmt"); }
'{' typedef_substmts '}' '{' typedef_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("47"); { if (ystack_pop(_yy) < 0) _YYERROR("typedef_stmt");
clicon_debug(2,"typedef-stmt -> TYPEDEF id-arg-str { typedef-substmts }"); } clicon_debug(2,"typedef-stmt -> TYPEDEF id-arg-str { typedef-substmts }"); }
; ;
@ -699,13 +706,13 @@ typedef_substmt : type_stmt { clicon_debug(2,"typedef-substmt -> type-s
/* Type */ /* Type */
type_stmt : K_TYPE identifier_ref_str ';' type_stmt : K_TYPE identifier_ref_str ';'
{ if (ysp_add(_yy, Y_TYPE, $2, NULL) == NULL) _YYERROR("48"); { if (ysp_add(_yy, Y_TYPE, $2, NULL) == NULL) _YYERROR("type_stmt");
clicon_debug(2,"type-stmt -> TYPE identifier-ref-arg-str ;");} clicon_debug(2,"type-stmt -> TYPE identifier-ref-arg-str ;");}
| K_TYPE identifier_ref_str | K_TYPE identifier_ref_str
{ if (ysp_add_push(_yy, Y_TYPE, $2) == NULL) _YYERROR("49"); { if (ysp_add_push(_yy, Y_TYPE, $2) == NULL) _YYERROR("type_stmt");
} }
'{' type_body_stmts '}' '{' type_body_stmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("50"); { if (ystack_pop(_yy) < 0) _YYERROR("type_stmt");
clicon_debug(2,"type-stmt -> TYPE identifier-ref-arg-str { type-body-stmts }");} clicon_debug(2,"type-stmt -> TYPE identifier-ref-arg-str { type-body-stmts }");}
; ;
@ -742,13 +749,13 @@ type_body_stmt/* numerical-restrictions */
/* range-stmt */ /* range-stmt */
range_stmt : K_RANGE string ';' /* XXX range-arg-str */ range_stmt : K_RANGE string ';' /* XXX range-arg-str */
{ if (ysp_add(_yy, Y_RANGE, $2, NULL) == NULL) _YYERROR("68"); { if (ysp_add(_yy, Y_RANGE, $2, NULL) == NULL) _YYERROR("range_stmt");
clicon_debug(2,"range-stmt -> RANGE string ;"); } clicon_debug(2,"range-stmt -> RANGE string ;"); }
| K_RANGE string | K_RANGE string
{ if (ysp_add_push(_yy, Y_RANGE, $2) == NULL) _YYERROR("69"); } { if (ysp_add_push(_yy, Y_RANGE, $2) == NULL) _YYERROR("range_stmt"); }
'{' range_substmts '}' '{' range_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("70"); { if (ystack_pop(_yy) < 0) _YYERROR("range_stmt");
clicon_debug(2,"range-stmt -> RANGE string { range-substmts }"); } clicon_debug(2,"range-stmt -> RANGE string { range-substmts }"); }
; ;
@ -767,7 +774,7 @@ range_substmt : error_message_stmt { clicon_debug(2,"range-substmt -> error-me
/* fraction-digits-stmt = fraction-digits-keyword fraction-digits-arg-str */ /* fraction-digits-stmt = fraction-digits-keyword fraction-digits-arg-str */
fraction_digits_stmt : K_FRACTION_DIGITS string stmtend fraction_digits_stmt : K_FRACTION_DIGITS string stmtend
{ if (ysp_add(_yy, Y_FRACTION_DIGITS, $2, NULL) == NULL) _YYERROR("84"); { if (ysp_add(_yy, Y_FRACTION_DIGITS, $2, NULL) == NULL) _YYERROR("fraction_digits_stmt");
clicon_debug(2,"fraction-digits-stmt -> FRACTION-DIGITS string"); } clicon_debug(2,"fraction-digits-stmt -> FRACTION-DIGITS string"); }
; ;
@ -776,15 +783,22 @@ meta_stmts : meta_stmts meta_stmt { clicon_debug(2,"meta-stmts -> meta-stmts
| meta_stmt { clicon_debug(2,"meta-stmts -> meta-stmt"); } | meta_stmt { clicon_debug(2,"meta-stmts -> meta-stmt"); }
; ;
meta_stmt : organization_stmt { clicon_debug(2,"meta-stmt -> organization-stmt"); }
| contact_stmt { clicon_debug(2,"meta-stmt -> contact-stmt"); }
| description_stmt { clicon_debug(2,"meta-stmt -> description-stmt"); }
| reference_stmt { clicon_debug(2,"meta-stmt -> reference-stmt"); }
;
/* length-stmt */ /* length-stmt */
length_stmt : K_LENGTH string ';' /* XXX length-arg-str */ length_stmt : K_LENGTH string ';' /* XXX length-arg-str */
{ if (ysp_add(_yy, Y_LENGTH, $2, NULL) == NULL) _YYERROR("53"); { if (ysp_add(_yy, Y_LENGTH, $2, NULL) == NULL) _YYERROR("length_stmt");
clicon_debug(2,"length-stmt -> LENGTH string ;"); } clicon_debug(2,"length-stmt -> LENGTH string ;"); }
| K_LENGTH string | K_LENGTH string
{ if (ysp_add_push(_yy, Y_LENGTH, $2) == NULL) _YYERROR("54"); } { if (ysp_add_push(_yy, Y_LENGTH, $2) == NULL) _YYERROR("length_stmt"); }
'{' length_substmts '}' '{' length_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("55"); { if (ystack_pop(_yy) < 0) _YYERROR("length_stmt");
clicon_debug(2,"length-stmt -> LENGTH string { length-substmts }"); } clicon_debug(2,"length-stmt -> LENGTH string { length-substmts }"); }
; ;
@ -803,13 +817,13 @@ length_substmt : error_message_stmt { clicon_debug(2,"length-substmt -> error-m
/* Pattern */ /* Pattern */
pattern_stmt : K_PATTERN string ';' pattern_stmt : K_PATTERN string ';'
{ if (ysp_add(_yy, Y_PATTERN, $2, NULL) == NULL) _YYERROR("56"); { if (ysp_add(_yy, Y_PATTERN, $2, NULL) == NULL) _YYERROR("pattern_stmt");
clicon_debug(2,"pattern-stmt -> PATTERN string ;"); } clicon_debug(2,"pattern-stmt -> PATTERN string ;"); }
| K_PATTERN string | K_PATTERN string
{ if (ysp_add_push(_yy, Y_PATTERN, $2) == NULL) _YYERROR("57"); } { if (ysp_add_push(_yy, Y_PATTERN, $2) == NULL) _YYERROR("pattern_stmt"); }
'{' pattern_substmts '}' '{' pattern_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("58"); { if (ystack_pop(_yy) < 0) _YYERROR("pattern_stmt");
clicon_debug(2,"pattern-stmt -> PATTERN string { pattern-substmts }"); } clicon_debug(2,"pattern-stmt -> PATTERN string { pattern-substmts }"); }
; ;
@ -819,27 +833,34 @@ pattern_substmts : pattern_substmts pattern_substmt
{ clicon_debug(2,"pattern-substmts -> pattern-substmt"); } { clicon_debug(2,"pattern-substmts -> pattern-substmt"); }
; ;
pattern_substmt : reference_stmt { clicon_debug(2,"pattern-substmt -> reference-stmt"); } pattern_substmt : modifier_stmt { clicon_debug(2,"pattern-substmt -> modifier-stmt");}
| error_message_stmt { clicon_debug(2,"pattern-substmt -> error-message-stmt");} | error_message_stmt { clicon_debug(2,"pattern-substmt -> error-message-stmt");}
| error_app_tag_stmt { clicon_debug(2,"pattern-substmt -> error-app-tag-stmt");}
| description_stmt { clicon_debug(2,"pattern-substmt -> description-stmt");}
| reference_stmt { clicon_debug(2,"pattern-substmt -> reference-stmt"); }
| unknown_stmt { clicon_debug(2,"pattern-substmt -> unknown-stmt");} | unknown_stmt { clicon_debug(2,"pattern-substmt -> unknown-stmt");}
| { clicon_debug(2,"pattern-substmt -> "); } | { clicon_debug(2,"pattern-substmt -> "); }
; ;
default_stmt : K_DEFAULT string ';' modifier_stmt : K_MODIFIER string stmtend
{ if (ysp_add(_yy, Y_DEFAULT, $2, NULL)== NULL) _YYERROR("94"); { if (ysp_add(_yy, Y_DEFAULT, $2, NULL)== NULL) _YYERROR("modifier_stmt");
clicon_debug(2,"modifier-stmt -> MODIFIER string"); }
;
default_stmt : K_DEFAULT string stmtend
{ if (ysp_add(_yy, Y_DEFAULT, $2, NULL)== NULL) _YYERROR("default_stmt");
clicon_debug(2,"default-stmt -> DEFAULT string"); } clicon_debug(2,"default-stmt -> DEFAULT string"); }
; ;
/* enum-stmt */ /* enum-stmt */
enum_stmt : K_ENUM string ';' enum_stmt : K_ENUM string ';'
{ if (ysp_add(_yy, Y_ENUM, $2, NULL) == NULL) _YYERROR("71"); { if (ysp_add(_yy, Y_ENUM, $2, NULL) == NULL) _YYERROR("enum_stmt");
clicon_debug(2,"enum-stmt -> ENUM string ;"); } clicon_debug(2,"enum-stmt -> ENUM string ;"); }
| K_ENUM string | K_ENUM string
{ if (ysp_add_push(_yy, Y_ENUM, $2) == NULL) _YYERROR("72"); } { if (ysp_add_push(_yy, Y_ENUM, $2) == NULL) _YYERROR("enum_stmt"); }
'{' enum_substmts '}' '{' enum_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("73"); { if (ystack_pop(_yy) < 0) _YYERROR("enum_stmt");
clicon_debug(2,"enum-stmt -> ENUM string { enum-substmts }"); } clicon_debug(2,"enum-stmt -> ENUM string { enum-substmts }"); }
; ;
@ -857,24 +878,24 @@ enum_substmt : value_stmt { clicon_debug(2,"enum-substmt -> value-stm
| { clicon_debug(2,"enum-substmt -> "); } | { clicon_debug(2,"enum-substmt -> "); }
; ;
path_stmt : K_PATH string ';' /* XXX: path-arg-str */ path_stmt : K_PATH string stmtend /* XXX: path-arg-str */
{ if (ysp_add(_yy, Y_PATH, $2, NULL)== NULL) _YYERROR("91"); { if (ysp_add(_yy, Y_PATH, $2, NULL)== NULL) _YYERROR("path_stmt");
clicon_debug(2,"path-stmt -> PATH string"); } clicon_debug(2,"path-stmt -> PATH string"); }
; ;
require_instance_stmt : K_REQUIRE_INSTANCE bool_str ';' require_instance_stmt : K_REQUIRE_INSTANCE bool_str stmtend
{ if (ysp_add(_yy, Y_REQUIRE_INSTANCE, $2, NULL)== NULL) _YYERROR("92"); { if (ysp_add(_yy, Y_REQUIRE_INSTANCE, $2, NULL)== NULL) _YYERROR("require_instance_stmt");
clicon_debug(2,"require-instance-stmt -> REQUIRE-INSTANCE string"); } clicon_debug(2,"require-instance-stmt -> REQUIRE-INSTANCE string"); }
; ;
/* bit-stmt */ /* bit-stmt */
bit_stmt : K_BIT identifier_str ';' bit_stmt : K_BIT identifier_str ';'
{ if (ysp_add(_yy, Y_BIT, $2, NULL) == NULL) _YYERROR("74"); { if (ysp_add(_yy, Y_BIT, $2, NULL) == NULL) _YYERROR("bit_stmt");
clicon_debug(2,"bit-stmt -> BIT string ;"); } clicon_debug(2,"bit-stmt -> BIT string ;"); }
| K_BIT identifier_str | K_BIT identifier_str
{ if (ysp_add_push(_yy, Y_BIT, $2) == NULL) _YYERROR("75"); } { if (ysp_add_push(_yy, Y_BIT, $2) == NULL) _YYERROR("bit_stmt"); }
'{' bit_substmts '}' '{' bit_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("76"); { if (ystack_pop(_yy) < 0) _YYERROR("bit_stmt");
clicon_debug(2,"bit-stmt -> BIT string { bit-substmts }"); } clicon_debug(2,"bit-stmt -> BIT string { bit-substmts }"); }
; ;
@ -893,50 +914,50 @@ bit_substmt : position_stmt { clicon_debug(2,"bit-substmt -> positition
/* position-stmt = position-keyword position-value-arg-str */ /* position-stmt = position-keyword position-value-arg-str */
position_stmt : K_POSITION integer_value_str stmtend position_stmt : K_POSITION integer_value_str stmtend
{ if (ysp_add(_yy, Y_POSITION, $2, NULL) == NULL) _YYERROR("87"); { if (ysp_add(_yy, Y_POSITION, $2, NULL) == NULL) _YYERROR("position_stmt");
clicon_debug(2,"position-stmt -> POSITION integer-value"); } clicon_debug(2,"position-stmt -> POSITION integer-value"); }
; ;
/* status-stmt = status-keyword sep status-arg-str XXX: current-keyword*/ /* status-stmt = status-keyword sep status-arg-str XXX: current-keyword*/
status_stmt : K_STATUS string stmtend status_stmt : K_STATUS string stmtend
{ if (ysp_add(_yy, Y_STATUS, $2, NULL) == NULL) _YYERROR("88"); { if (ysp_add(_yy, Y_STATUS, $2, NULL) == NULL) _YYERROR("status_stmt");
clicon_debug(2,"status-stmt -> STATUS string"); } clicon_debug(2,"status-stmt -> STATUS string"); }
; ;
config_stmt : K_CONFIG bool_str ';' config_stmt : K_CONFIG bool_str stmtend
{ if (ysp_add(_yy, Y_CONFIG, $2, NULL) == NULL) _YYERROR("89"); { if (ysp_add(_yy, Y_CONFIG, $2, NULL) == NULL) _YYERROR("config_stmt");
clicon_debug(2,"config-stmt -> CONFIG config-arg-str"); } clicon_debug(2,"config-stmt -> CONFIG config-arg-str"); }
; ;
/* mandatory-stmt = mandatory-keyword mandatory-arg-str */ /* mandatory-stmt = mandatory-keyword mandatory-arg-str */
mandatory_stmt: K_MANDATORY bool_str ';' mandatory_stmt : K_MANDATORY bool_str stmtend
{ yang_stmt *ys; { yang_stmt *ys;
if ((ys = ysp_add(_yy, Y_MANDATORY, $2, NULL))== NULL) _YYERROR("106"); if ((ys = ysp_add(_yy, Y_MANDATORY, $2, NULL))== NULL) _YYERROR("mandatory_stmt");
clicon_debug(2,"mandatory-stmt -> MANDATORY mandatory-arg-str ;");} clicon_debug(2,"mandatory-stmt -> MANDATORY mandatory-arg-str ;");}
; ;
presence_stmt: K_PRESENCE string ';' presence_stmt : K_PRESENCE string stmtend
{ yang_stmt *ys; { yang_stmt *ys;
if ((ys = ysp_add(_yy, Y_PRESENCE, $2, NULL))== NULL) _YYERROR("107"); if ((ys = ysp_add(_yy, Y_PRESENCE, $2, NULL))== NULL) _YYERROR("presence_stmt");
clicon_debug(2,"presence-stmt -> PRESENCE string ;");} clicon_debug(2,"presence-stmt -> PRESENCE string ;");}
; ;
/* ordered-by-stmt = ordered-by-keyword sep ordered-by-arg-str */ /* ordered-by-stmt = ordered-by-keyword sep ordered-by-arg-str */
ordered_by_stmt: K_ORDERED_BY string stmtend ordered_by_stmt : K_ORDERED_BY string stmtend
{ yang_stmt *ys; { yang_stmt *ys;
if ((ys = ysp_add(_yy, Y_ORDERED_BY, $2, NULL))== NULL) _YYERROR("108"); if ((ys = ysp_add(_yy, Y_ORDERED_BY, $2, NULL))== NULL) _YYERROR("ordered_by_stmt");
clicon_debug(2,"ordered-by-stmt -> ORDERED-BY ordered-by-arg ;");} clicon_debug(2,"ordered-by-stmt -> ORDERED-BY ordered-by-arg ;");}
; ;
/* must-stmt */ /* must-stmt */
must_stmt : K_MUST string ';' must_stmt : K_MUST string ';'
{ if (ysp_add(_yy, Y_MUST, $2, NULL) == NULL) _YYERROR("77"); { if (ysp_add(_yy, Y_MUST, $2, NULL) == NULL) _YYERROR("must_stmt");
clicon_debug(2,"must-stmt -> MUST string ;"); } clicon_debug(2,"must-stmt -> MUST string ;"); }
| K_MUST string | K_MUST string
{ if (ysp_add_push(_yy, Y_MUST, $2) == NULL) _YYERROR("78"); } { if (ysp_add_push(_yy, Y_MUST, $2) == NULL) _YYERROR("must_stmt"); }
'{' must_substmts '}' '{' must_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("79"); { if (ystack_pop(_yy) < 0) _YYERROR("must_stmt");
clicon_debug(2,"must-stmt -> MUST string { must-substmts }"); } clicon_debug(2,"must-stmt -> MUST string { must-substmts }"); }
; ;
@ -947,42 +968,47 @@ must_substmts : must_substmts must_substmt
; ;
must_substmt : error_message_stmt { clicon_debug(2,"must-substmt -> error-message-stmt"); } must_substmt : error_message_stmt { clicon_debug(2,"must-substmt -> error-message-stmt"); }
| error_app_tag_stmt { clicon_debug(2,"must-substmt -> error-app-tag-stmt"); }
| description_stmt { clicon_debug(2,"must-substmt -> description-stmt"); } | description_stmt { clicon_debug(2,"must-substmt -> description-stmt"); }
| reference_stmt { clicon_debug(2,"must-substmt -> reference-stmt"); } | reference_stmt { clicon_debug(2,"must-substmt -> reference-stmt"); }
| { clicon_debug(2,"must-substmt -> "); } | { clicon_debug(2,"must-substmt -> "); }
; ;
/* error-message-stmt */ /* error-message-stmt */
error_message_stmt : K_ERROR_MESSAGE string ';' error_message_stmt : K_ERROR_MESSAGE string stmtend
{ if (ysp_add(_yy, Y_ERROR_MESSAGE, $2, NULL) == NULL) _YYERROR("80"); } { if (ysp_add(_yy, Y_ERROR_MESSAGE, $2, NULL) == NULL) _YYERROR("error_message_stmt");
clicon_debug(2,"error-message-stmt -> ERROR-MESSAGE string"); }
; ;
/* XXX error-app-tag-stmt */ error_app_tag_stmt : K_ERROR_APP_TAG string stmtend
{ if (ysp_add(_yy, Y_ERROR_MESSAGE, $2, NULL) == NULL) _YYERROR("error_message_stmt");
clicon_debug(2,"error-app-tag-stmt -> ERROR-APP-TAG string"); }
;
/* min-elements-stmt = min-elements-keyword min-value-arg-str */ /* min-elements-stmt = min-elements-keyword min-value-arg-str */
min_elements_stmt: K_MIN_ELEMENTS integer_value_str stmtend min_elements_stmt : K_MIN_ELEMENTS integer_value_str stmtend
{ if (ysp_add(_yy, Y_MIN_ELEMENTS, $2, NULL)== NULL) _YYERROR("103"); { if (ysp_add(_yy, Y_MIN_ELEMENTS, $2, NULL)== NULL) _YYERROR("min_elements_stmt");
clicon_debug(2,"min-elements-stmt -> MIN-ELEMENTS integer ;");} clicon_debug(2,"min-elements-stmt -> MIN-ELEMENTS integer ;");}
; ;
/* max-elements-stmt = max-elements-keyword ("unbounded"|integer-value) /* max-elements-stmt = max-elements-keyword ("unbounded"|integer-value)
* XXX cannot use integer-value * XXX cannot use integer-value
*/ */
max_elements_stmt: K_MAX_ELEMENTS string ';' max_elements_stmt : K_MAX_ELEMENTS string stmtend
{ if (ysp_add(_yy, Y_MAX_ELEMENTS, $2, NULL)== NULL) _YYERROR("104"); { if (ysp_add(_yy, Y_MAX_ELEMENTS, $2, NULL)== NULL) _YYERROR("max_elements_stmt");
clicon_debug(2,"max-elements-stmt -> MIN-ELEMENTS integer ;");} clicon_debug(2,"max-elements-stmt -> MIN-ELEMENTS integer ;");}
; ;
value_stmt : K_VALUE integer_value_str ';' value_stmt : K_VALUE integer_value_str stmtend
{ if (ysp_add(_yy, Y_VALUE, $2, NULL) == NULL) _YYERROR("86"); { if (ysp_add(_yy, Y_VALUE, $2, NULL) == NULL) _YYERROR("value_stmt");
clicon_debug(2,"value-stmt -> VALUE integer-value"); } clicon_debug(2,"value-stmt -> VALUE integer-value"); }
; ;
/* Grouping */ /* Grouping */
grouping_stmt : K_GROUPING identifier_str grouping_stmt : K_GROUPING identifier_str
{ if (ysp_add_push(_yy, Y_GROUPING, $2) == NULL) _YYERROR("51"); } { if (ysp_add_push(_yy, Y_GROUPING, $2) == NULL) _YYERROR("grouping_stmt"); }
'{' grouping_substmts '}' '{' grouping_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("52"); { if (ystack_pop(_yy) < 0) _YYERROR("grouping_stmt");
clicon_debug(2,"grouping-stmt -> GROUPING id-arg-str { grouping-substmts }"); } clicon_debug(2,"grouping-stmt -> GROUPING id-arg-str { grouping-substmts }"); }
; ;
@ -1006,12 +1032,12 @@ grouping_substmt : status_stmt { clicon_debug(2,"grouping-substmt -> st
/* container */ /* container */
container_stmt : K_CONTAINER identifier_str ';' container_stmt : K_CONTAINER identifier_str ';'
{ if (ysp_add(_yy, Y_CONTAINER, $2, NULL) == NULL) _YYERROR("7"); { if (ysp_add(_yy, Y_CONTAINER, $2, NULL) == NULL) _YYERROR("container_stmt");
clicon_debug(2,"container-stmt -> CONTAINER id-arg-str ;");} clicon_debug(2,"container-stmt -> CONTAINER id-arg-str ;");}
| K_CONTAINER identifier_str | K_CONTAINER identifier_str
{ if (ysp_add_push(_yy, Y_CONTAINER, $2) == NULL) _YYERROR("8"); } { if (ysp_add_push(_yy, Y_CONTAINER, $2) == NULL) _YYERROR("container_stmt"); }
'{' container_substmts '}' '{' container_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("9"); { if (ystack_pop(_yy) < 0) _YYERROR("container_stmt");
clicon_debug(2,"container-stmt -> CONTAINER id-arg-str { container-substmts }");} clicon_debug(2,"container-stmt -> CONTAINER id-arg-str { container-substmts }");}
; ;
@ -1036,14 +1062,13 @@ container_substmt : when_stmt { clicon_debug(2,"container-substmt -> when-
| { clicon_debug(2,"container-substmt ->");} | { clicon_debug(2,"container-substmt ->");}
; ;
/* leaf */
leaf_stmt : K_LEAF identifier_str ';' leaf_stmt : K_LEAF identifier_str ';'
{ if (ysp_add(_yy, Y_LEAF, $2, NULL) == NULL) _YYERROR("10"); { if (ysp_add(_yy, Y_LEAF, $2, NULL) == NULL) _YYERROR("leaf_stmt");
clicon_debug(2,"leaf-stmt -> LEAF id-arg-str ;");} clicon_debug(2,"leaf-stmt -> LEAF id-arg-str ;");}
| K_LEAF identifier_str | K_LEAF identifier_str
{ if (ysp_add_push(_yy, Y_LEAF, $2) == NULL) _YYERROR("11"); } { if (ysp_add_push(_yy, Y_LEAF, $2) == NULL) _YYERROR("leaf_stmt"); }
'{' leaf_substmts '}' '{' leaf_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("12"); { if (ystack_pop(_yy) < 0) _YYERROR("leaf_stmt");
clicon_debug(2,"leaf-stmt -> LEAF id-arg-str { lead-substmts }");} clicon_debug(2,"leaf-stmt -> LEAF id-arg-str { lead-substmts }");}
; ;
@ -1068,12 +1093,12 @@ leaf_substmt : when_stmt { clicon_debug(2,"leaf-substmt -> when-stmt
/* leaf-list */ /* leaf-list */
leaf_list_stmt : K_LEAF_LIST identifier_str ';' leaf_list_stmt : K_LEAF_LIST identifier_str ';'
{ if (ysp_add(_yy, Y_LEAF_LIST, $2, NULL) == NULL) _YYERROR("13"); { if (ysp_add(_yy, Y_LEAF_LIST, $2, NULL) == NULL) _YYERROR("leaf_list_stmt");
clicon_debug(2,"leaf-list-stmt -> LEAF id-arg-str ;");} clicon_debug(2,"leaf-list-stmt -> LEAF id-arg-str ;");}
| K_LEAF_LIST identifier_str | K_LEAF_LIST identifier_str
{ if (ysp_add_push(_yy, Y_LEAF_LIST, $2) == NULL) _YYERROR("14"); } { if (ysp_add_push(_yy, Y_LEAF_LIST, $2) == NULL) _YYERROR("leaf_list_stmt"); }
'{' leaf_list_substmts '}' '{' leaf_list_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("15"); { if (ystack_pop(_yy) < 0) _YYERROR("leaf_list_stmt");
clicon_debug(2,"leaf-list-stmt -> LEAF-LIST id-arg-str { lead-substmts }");} clicon_debug(2,"leaf-list-stmt -> LEAF-LIST id-arg-str { lead-substmts }");}
; ;
@ -1097,14 +1122,13 @@ leaf_list_substmt : when_stmt { clicon_debug(2,"leaf-list-substmt -> when
| { clicon_debug(2,"leaf-list-stmt ->"); } | { clicon_debug(2,"leaf-list-stmt ->"); }
; ;
/* list */
list_stmt : K_LIST identifier_str ';' list_stmt : K_LIST identifier_str ';'
{ if (ysp_add(_yy, Y_LIST, $2, NULL) == NULL) _YYERROR("16"); { if (ysp_add(_yy, Y_LIST, $2, NULL) == NULL) _YYERROR("list_stmt");
clicon_debug(2,"list-stmt -> LIST id-arg-str ;"); } clicon_debug(2,"list-stmt -> LIST id-arg-str ;"); }
| K_LIST identifier_str | K_LIST identifier_str
{ if (ysp_add_push(_yy, Y_LIST, $2) == NULL) _YYERROR("17"); } { if (ysp_add_push(_yy, Y_LIST, $2) == NULL) _YYERROR("list_stmt"); }
'{' list_substmts '}' '{' list_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("18"); { if (ystack_pop(_yy) < 0) _YYERROR("list_stmt");
clicon_debug(2,"list-stmt -> LIST id-arg-str { list-substmts }"); } clicon_debug(2,"list-stmt -> LIST id-arg-str { list-substmts }"); }
; ;
@ -1137,24 +1161,24 @@ list_substmt : when_stmt { clicon_debug(2,"list-substmt -> when-stmt
/* key-stmt = key-keyword sep key-arg-str */ /* key-stmt = key-keyword sep key-arg-str */
key_stmt : K_KEY string stmtend key_stmt : K_KEY string stmtend
{ if (ysp_add(_yy, Y_KEY, $2, NULL)== NULL) _YYERROR("109"); { if (ysp_add(_yy, Y_KEY, $2, NULL)== NULL) _YYERROR("key_stmt");
clicon_debug(2,"key-stmt -> KEY id-arg-str ;");} clicon_debug(2,"key-stmt -> KEY id-arg-str ;");}
; ;
/* unique-stmt = unique-keyword unique-arg-str */ /* unique-stmt = unique-keyword unique-arg-str */
unique_stmt : K_UNIQUE string stmtend unique_stmt : K_UNIQUE string stmtend
{ if (ysp_add(_yy, Y_UNIQUE, $2, NULL)== NULL) _YYERROR("110"); { if (ysp_add(_yy, Y_UNIQUE, $2, NULL)== NULL) _YYERROR("unique_stmt");
clicon_debug(2,"key-stmt -> KEY id-arg-str ;");} clicon_debug(2,"key-stmt -> KEY id-arg-str ;");}
; ;
/* choice */ /* choice */
choice_stmt : K_CHOICE identifier_str ';' choice_stmt : K_CHOICE identifier_str ';'
{ if (ysp_add(_yy, Y_CHOICE, $2, NULL) == NULL) _YYERROR("19"); { if (ysp_add(_yy, Y_CHOICE, $2, NULL) == NULL) _YYERROR("choice_stmt");
clicon_debug(2,"choice-stmt -> CHOICE id-arg-str ;"); } clicon_debug(2,"choice-stmt -> CHOICE id-arg-str ;"); }
| K_CHOICE identifier_str | K_CHOICE identifier_str
{ if (ysp_add_push(_yy, Y_CHOICE, $2) == NULL) _YYERROR("20"); } { if (ysp_add_push(_yy, Y_CHOICE, $2) == NULL) _YYERROR("choice_stmt"); }
'{' choice_substmts '}' '{' choice_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("21"); { if (ystack_pop(_yy) < 0) _YYERROR("choice_stmt");
clicon_debug(2,"choice-stmt -> CHOICE id-arg-str { choice-substmts }"); } clicon_debug(2,"choice-stmt -> CHOICE id-arg-str { choice-substmts }"); }
; ;
@ -1180,12 +1204,12 @@ choice_substmt : when_stmt { clicon_debug(2,"choice-substmt -> when-st
/* case */ /* case */
case_stmt : K_CASE identifier_str ';' case_stmt : K_CASE identifier_str ';'
{ if (ysp_add(_yy, Y_CASE, $2, NULL) == NULL) _YYERROR("22"); { if (ysp_add(_yy, Y_CASE, $2, NULL) == NULL) _YYERROR("case_stmt");
clicon_debug(2,"case-stmt -> CASE id-arg-str ;"); } clicon_debug(2,"case-stmt -> CASE id-arg-str ;"); }
| K_CASE identifier_str | K_CASE identifier_str
{ if (ysp_add_push(_yy, Y_CASE, $2) == NULL) _YYERROR("23"); } { if (ysp_add_push(_yy, Y_CASE, $2) == NULL) _YYERROR("case_stmt"); }
'{' case_substmts '}' '{' case_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("24"); { if (ystack_pop(_yy) < 0) _YYERROR("case_stmt");
clicon_debug(2,"case-stmt -> CASE id-arg-str { case-substmts }"); } clicon_debug(2,"case-stmt -> CASE id-arg-str { case-substmts }"); }
; ;
@ -1206,23 +1230,23 @@ case_substmt : when_stmt { clicon_debug(2,"case-substmt -> when-stmt
; ;
anydata_stmt : K_ANYDATA identifier_str ';' anydata_stmt : K_ANYDATA identifier_str ';'
{ if (ysp_add(_yy, Y_ANYDATA, $2, NULL) == NULL) _YYERROR("25"); { if (ysp_add(_yy, Y_ANYDATA, $2, NULL) == NULL) _YYERROR("anydata_stmt");
clicon_debug(2,"anydata-stmt -> ANYDATA id-arg-str ;"); } clicon_debug(2,"anydata-stmt -> ANYDATA id-arg-str ;"); }
| K_ANYDATA identifier_str | K_ANYDATA identifier_str
{ if (ysp_add_push(_yy, Y_ANYDATA, $2) == NULL) _YYERROR("26"); } { if (ysp_add_push(_yy, Y_ANYDATA, $2) == NULL) _YYERROR("anydata_stmt"); }
'{' anyxml_substmts '}' '{' anyxml_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("27"); { if (ystack_pop(_yy) < 0) _YYERROR("anydata_stmt");
clicon_debug(2,"anydata-stmt -> ANYDATA id-arg-str { anyxml-substmts }"); } clicon_debug(2,"anydata-stmt -> ANYDATA id-arg-str { anyxml-substmts }"); }
; ;
/* anyxml */ /* anyxml */
anyxml_stmt : K_ANYXML identifier_str ';' anyxml_stmt : K_ANYXML identifier_str ';'
{ if (ysp_add(_yy, Y_ANYXML, $2, NULL) == NULL) _YYERROR("25"); { if (ysp_add(_yy, Y_ANYXML, $2, NULL) == NULL) _YYERROR("anyxml_stmt");
clicon_debug(2,"anyxml-stmt -> ANYXML id-arg-str ;"); } clicon_debug(2,"anyxml-stmt -> ANYXML id-arg-str ;"); }
| K_ANYXML identifier_str | K_ANYXML identifier_str
{ if (ysp_add_push(_yy, Y_ANYXML, $2) == NULL) _YYERROR("26"); } { if (ysp_add_push(_yy, Y_ANYXML, $2) == NULL) _YYERROR("anyxml_stmt"); }
'{' anyxml_substmts '}' '{' anyxml_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("27"); { if (ystack_pop(_yy) < 0) _YYERROR("anyxml_stmt");
clicon_debug(2,"anyxml-stmt -> ANYXML id-arg-str { anyxml-substmts }"); } clicon_debug(2,"anyxml-stmt -> ANYXML id-arg-str { anyxml-substmts }"); }
; ;
@ -1245,12 +1269,12 @@ anyxml_substmt : when_stmt { clicon_debug(2,"anyxml-substmt -> when-st
/* uses-stmt = uses-keyword identifier-ref-arg-str */ /* uses-stmt = uses-keyword identifier-ref-arg-str */
uses_stmt : K_USES identifier_ref_str ';' uses_stmt : K_USES identifier_ref_str ';'
{ if (ysp_add(_yy, Y_USES, $2, NULL) == NULL) _YYERROR("28"); { if (ysp_add(_yy, Y_USES, $2, NULL) == NULL) _YYERROR("uses_stmt");
clicon_debug(2,"uses-stmt -> USES id-arg-str ;"); } clicon_debug(2,"uses-stmt -> USES id-arg-str ;"); }
| K_USES identifier_ref_str | K_USES identifier_ref_str
{ if (ysp_add_push(_yy, Y_USES, $2) == NULL) _YYERROR("29"); } { if (ysp_add_push(_yy, Y_USES, $2) == NULL) _YYERROR("uses_stmt"); }
'{' uses_substmts '}' '{' uses_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("30"); { if (ystack_pop(_yy) < 0) _YYERROR("uses_stmt");
clicon_debug(2,"uses-stmt -> USES id-arg-str { uses-substmts }"); } clicon_debug(2,"uses-stmt -> USES id-arg-str { uses-substmts }"); }
; ;
@ -1273,12 +1297,12 @@ uses_substmt : when_stmt { clicon_debug(2,"uses-substmt -> when-stmt
/* refine-stmt = refine-keyword sep refine-arg-str */ /* refine-stmt = refine-keyword sep refine-arg-str */
refine_stmt : K_REFINE desc_schema_node_str ';' refine_stmt : K_REFINE desc_schema_node_str ';'
{ if (ysp_add(_yy, Y_REFINE, $2, NULL) == NULL) _YYERROR("31"); { if (ysp_add(_yy, Y_REFINE, $2, NULL) == NULL) _YYERROR("refine_stmt");
clicon_debug(2,"refine-stmt -> REFINE id-arg-str ;"); } clicon_debug(2,"refine-stmt -> REFINE id-arg-str ;"); }
| K_REFINE desc_schema_node_str | K_REFINE desc_schema_node_str
{ if (ysp_add_push(_yy, Y_REFINE, $2) == NULL) _YYERROR("32"); } { if (ysp_add_push(_yy, Y_REFINE, $2) == NULL) _YYERROR("refine_stmt"); }
'{' refine_substmts '}' '{' refine_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("33"); { if (ystack_pop(_yy) < 0) _YYERROR("refine_stmt");
clicon_debug(2,"refine-stmt -> REFINE id-arg-str { refine-substmts }"); } clicon_debug(2,"refine-stmt -> REFINE id-arg-str { refine-substmts }"); }
; ;
@ -1297,9 +1321,9 @@ refine_substmt : must_stmt { clicon_debug(2,"refine-substmt -> must-stmt");
/* uses-augment-stmt = augment-keyword augment-arg-str */ /* uses-augment-stmt = augment-keyword augment-arg-str */
uses_augment_stmt : K_AUGMENT desc_schema_node_str uses_augment_stmt : K_AUGMENT desc_schema_node_str
{ if (ysp_add_push(_yy, Y_AUGMENT, $2) == NULL) _YYERROR("34"); } { if (ysp_add_push(_yy, Y_AUGMENT, $2) == NULL) _YYERROR("uses_augment_stmt"); }
'{' augment_substmts '}' '{' augment_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("35"); { if (ystack_pop(_yy) < 0) _YYERROR("uses_augment_stmt");
clicon_debug(2,"uses-augment-stmt -> AUGMENT desc-schema-node-str { augment-substmts }"); } clicon_debug(2,"uses-augment-stmt -> AUGMENT desc-schema-node-str { augment-substmts }"); }
@ -1307,9 +1331,9 @@ uses_augment_stmt : K_AUGMENT desc_schema_node_str
* XXX abs-schema-nodeid-str is too difficult, it needs the + semantics * XXX abs-schema-nodeid-str is too difficult, it needs the + semantics
*/ */
augment_stmt : K_AUGMENT string augment_stmt : K_AUGMENT string
{ if (ysp_add_push(_yy, Y_AUGMENT, $2) == NULL) _YYERROR("34"); } { if (ysp_add_push(_yy, Y_AUGMENT, $2) == NULL) _YYERROR("augment_stmt"); }
'{' augment_substmts '}' '{' augment_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("35"); { if (ystack_pop(_yy) < 0) _YYERROR("augment_stmt");
clicon_debug(2,"augment-stmt -> AUGMENT abs-schema-node-str { augment-substmts }"); } clicon_debug(2,"augment-stmt -> AUGMENT abs-schema-node-str { augment-substmts }"); }
; ;
@ -1333,12 +1357,12 @@ augment_substmt : when_stmt { clicon_debug(2,"augment-substmt -> when-s
/* when */ /* when */
when_stmt : K_WHEN string ';' when_stmt : K_WHEN string ';'
{ if (ysp_add(_yy, Y_WHEN, $2, NULL) == NULL) _YYERROR("36"); { if (ysp_add(_yy, Y_WHEN, $2, NULL) == NULL) _YYERROR("when_stmt");
clicon_debug(2,"when-stmt -> WHEN string ;"); } clicon_debug(2,"when-stmt -> WHEN string ;"); }
| K_WHEN string | K_WHEN string
{ if (ysp_add_push(_yy, Y_WHEN, $2) == NULL) _YYERROR("37"); } { if (ysp_add_push(_yy, Y_WHEN, $2) == NULL) _YYERROR("when_stmt"); }
'{' when_substmts '}' '{' when_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("38"); { if (ystack_pop(_yy) < 0) _YYERROR("when_stmt");
clicon_debug(2,"when-stmt -> WHEN string { when-substmts }"); } clicon_debug(2,"when-stmt -> WHEN string { when-substmts }"); }
; ;
@ -1355,12 +1379,12 @@ when_substmt : description_stmt { clicon_debug(2,"when-substmt -> description-s
/* rpc */ /* rpc */
rpc_stmt : K_RPC identifier_str ';' rpc_stmt : K_RPC identifier_str ';'
{ if (ysp_add(_yy, Y_RPC, $2, NULL) == NULL) _YYERROR("39"); { if (ysp_add(_yy, Y_RPC, $2, NULL) == NULL) _YYERROR("rpc_stmt");
clicon_debug(2,"rpc-stmt -> RPC id-arg-str ;"); } clicon_debug(2,"rpc-stmt -> RPC id-arg-str ;"); }
| K_RPC identifier_str | K_RPC identifier_str
{ if (ysp_add_push(_yy, Y_RPC, $2) == NULL) _YYERROR("40"); } { if (ysp_add_push(_yy, Y_RPC, $2) == NULL) _YYERROR("rpc_stmt"); }
'{' rpc_substmts '}' '{' rpc_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("41"); { if (ystack_pop(_yy) < 0) _YYERROR("rpc_stmt");
clicon_debug(2,"rpc-stmt -> RPC id-arg-str { rpc-substmts }"); } clicon_debug(2,"rpc-stmt -> RPC id-arg-str { rpc-substmts }"); }
; ;
@ -1383,23 +1407,23 @@ rpc_substmt : if_feature_stmt { clicon_debug(2,"rpc-substmt -> if-feature-stm
/* action */ /* action */
action_stmt : K_ACTION identifier_str ';' action_stmt : K_ACTION identifier_str ';'
{ if (ysp_add(_yy, Y_ACTION, $2, NULL) == NULL) _YYERROR("39"); { if (ysp_add(_yy, Y_ACTION, $2, NULL) == NULL) _YYERROR("action_stmt");
clicon_debug(2,"action-stmt -> ACTION id-arg-str ;"); } clicon_debug(2,"action-stmt -> ACTION id-arg-str ;"); }
| K_ACTION identifier_str | K_ACTION identifier_str
{ if (ysp_add_push(_yy, Y_ACTION, $2) == NULL) _YYERROR("40"); } { if (ysp_add_push(_yy, Y_ACTION, $2) == NULL) _YYERROR("action_stmt"); }
'{' rpc_substmts '}' '{' rpc_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("41"); { if (ystack_pop(_yy) < 0) _YYERROR("action_stmt");
clicon_debug(2,"action-stmt -> ACTION id-arg-str { rpc-substmts }"); } clicon_debug(2,"action-stmt -> ACTION id-arg-str { rpc-substmts }"); }
; ;
/* notification */ /* notification */
notification_stmt : K_NOTIFICATION identifier_str ';' notification_stmt : K_NOTIFICATION identifier_str ';'
{ if (ysp_add(_yy, Y_NOTIFICATION, $2, NULL) == NULL) _YYERROR("46"); { if (ysp_add(_yy, Y_NOTIFICATION, $2, NULL) == NULL) _YYERROR("notification_stmt");
clicon_debug(2,"notification-stmt -> NOTIFICATION id-arg-str ;"); } clicon_debug(2,"notification-stmt -> NOTIFICATION id-arg-str ;"); }
| K_NOTIFICATION identifier_str | K_NOTIFICATION identifier_str
{ if (ysp_add_push(_yy, Y_NOTIFICATION, $2) == NULL) _YYERROR("47"); } { if (ysp_add_push(_yy, Y_NOTIFICATION, $2) == NULL) _YYERROR("notification_stmt"); }
'{' notification_substmts '}' '{' notification_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("48"); { if (ystack_pop(_yy) < 0) _YYERROR("notification_stmt");
clicon_debug(2,"notification-stmt -> NOTIFICATION id-arg-str { notification-substmts }"); } clicon_debug(2,"notification-stmt -> NOTIFICATION id-arg-str { notification-substmts }"); }
; ;
@ -1427,9 +1451,9 @@ notification_substmt : if_feature_stmt { clicon_debug(2,"notification-substmt -
*/ */
deviation_stmt : K_DEVIATION string deviation_stmt : K_DEVIATION string
{ if (ysp_add_push(_yy, Y_DEVIATION, $2) == NULL) _YYERROR("47"); } { if (ysp_add_push(_yy, Y_DEVIATION, $2) == NULL) _YYERROR("deviation_stmt"); }
'{' deviation_substmts '}' '{' deviation_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("48"); { if (ystack_pop(_yy) < 0) _YYERROR("deviation_stmt");
clicon_debug(2,"deviation-stmt -> DEVIATION id-arg-str { notification-substmts }"); } clicon_debug(2,"deviation-stmt -> DEVIATION id-arg-str { notification-substmts }"); }
; ;
@ -1444,14 +1468,10 @@ deviation_substmt : description_stmt { clicon_debug(2,"deviation-substmt -> des
| deviate_not_supported_stmt { clicon_debug(2,"deviation-substmt -> deviate-not-supported-stmt"); } | deviate_not_supported_stmt { clicon_debug(2,"deviation-substmt -> deviate-not-supported-stmt"); }
; ;
deviate_not_supported_stmt : K_DEVIATE string { clicon_debug(2,"deviate-not-supported-stmt -> DEVIATE string"); } deviate_not_supported_stmt : K_DEVIATE string stmtend
{ clicon_debug(2,"deviate-not-supported-stmt -> DEVIATE string"); }
; ;
meta_stmt : organization_stmt { clicon_debug(2,"meta-stmt -> organization-stmt"); }
| contact_stmt { clicon_debug(2,"meta-stmt -> contact-stmt"); }
| description_stmt { clicon_debug(2,"meta-stmt -> description-stmt"); }
| reference_stmt { clicon_debug(2,"meta-stmt -> reference-stmt"); }
;
/* body */ /* body */
body_stmts : body_stmts body_stmt { clicon_debug(2,"body-stmts -> body-stmts body-stmt"); } body_stmts : body_stmts body_stmt { clicon_debug(2,"body-stmts -> body-stmts body-stmt"); }
@ -1492,9 +1512,9 @@ short_case_stmt : container_stmt { clicon_debug(2,"short-case-substmt -> conta
/* input */ /* input */
input_stmt : K_INPUT input_stmt : K_INPUT
{ if (ysp_add_push(_yy, Y_INPUT, NULL) == NULL) _YYERROR("42"); } { if (ysp_add_push(_yy, Y_INPUT, NULL) == NULL) _YYERROR("input_stmt"); }
'{' input_substmts '}' '{' input_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("43"); { if (ystack_pop(_yy) < 0) _YYERROR("input_stmt");
clicon_debug(2,"input-stmt -> INPUT { input-substmts }"); } clicon_debug(2,"input-stmt -> INPUT { input-substmts }"); }
; ;
@ -1512,15 +1532,12 @@ input_substmt : typedef_stmt { clicon_debug(2,"input-substmt -> typedef-
/* output */ /* output */
output_stmt : K_OUTPUT /* XXX reuse input-substatements since they are same */ output_stmt : K_OUTPUT /* XXX reuse input-substatements since they are same */
{ if (ysp_add_push(_yy, Y_OUTPUT, NULL) == NULL) _YYERROR("44"); } { if (ysp_add_push(_yy, Y_OUTPUT, NULL) == NULL) _YYERROR("output_stmt"); }
'{' input_substmts '}' '{' input_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("45"); { if (ystack_pop(_yy) < 0) _YYERROR("output_stmt");
clicon_debug(2,"output-stmt -> OUTPUT { input-substmts }"); } clicon_debug(2,"output-stmt -> OUTPUT { input-substmts }"); }
; ;
string : qstrings { $$=$1; clicon_debug(2,"string -> qstrings (%s)", $1); } string : qstrings { $$=$1; clicon_debug(2,"string -> qstrings (%s)", $1); }
| ustring { $$=$1; clicon_debug(2,"string -> ustring (%s)", $1); } | ustring { $$=$1; clicon_debug(2,"string -> ustring (%s)", $1); }
; ;
@ -1554,12 +1571,11 @@ ustring : ustring CHAR
{$$=$1; } {$$=$1; }
; ;
abs_schema_nodeid : abs_schema_nodeid '/' node_identifier abs_schema_nodeid : abs_schema_nodeid '/' node_identifier
{ if (($$=string_del_join($1, "/", $3)) == NULL) _YYERROR("0"); { if (($$=string_del_join($1, "/", $3)) == NULL) _YYERROR("abs_schema_nodeid");
clicon_debug(2,"absolute-schema-nodeid -> absolute-schema-nodeid / node-identifier"); } clicon_debug(2,"absolute-schema-nodeid -> absolute-schema-nodeid / node-identifier"); }
| '/' node_identifier | '/' node_identifier
{ if (($$=string_del_join(NULL, "/", $2)) == NULL) _YYERROR("0"); { if (($$=string_del_join(NULL, "/", $2)) == NULL) _YYERROR("abs_schema_nodeid");
clicon_debug(2,"absolute-schema-nodeid -> / node-identifier"); } clicon_debug(2,"absolute-schema-nodeid -> / node-identifier"); }
; ;
@ -1572,7 +1588,7 @@ desc_schema_node_str : desc_schema_nodeid
desc_schema_nodeid : node_identifier desc_schema_nodeid : node_identifier
{ $$= $1; clicon_debug(2,"descendant-schema-nodeid -> node_identifier"); } { $$= $1; clicon_debug(2,"descendant-schema-nodeid -> node_identifier"); }
| node_identifier abs_schema_nodeid | node_identifier abs_schema_nodeid
{ if (($$=string_del_join($1, " ", $2)) == NULL) _YYERROR("0");clicon_debug(2,"descendant-schema-nodeid -> node_identifier abs_schema_nodeid"); } { if (($$=string_del_join($1, " ", $2)) == NULL) _YYERROR("desc_schema_nodeid");clicon_debug(2,"descendant-schema-nodeid -> node_identifier abs_schema_nodeid"); }
; ;
identifier_str : '"' IDENTIFIER '"' { $$ = $2; identifier_str : '"' IDENTIFIER '"' { $$ = $2;
@ -1602,7 +1618,7 @@ bool_str : '"' BOOL '"' { $$ = $2;
node_identifier : IDENTIFIER node_identifier : IDENTIFIER
{ $$=$1; clicon_debug(2,"identifier-ref-arg-str -> string"); } { $$=$1; clicon_debug(2,"identifier-ref-arg-str -> string"); }
| IDENTIFIER ':' IDENTIFIER | IDENTIFIER ':' IDENTIFIER
{ if (($$=string_del_join($1, ":", $3)) == NULL) _YYERROR("112"); { if (($$=string_del_join($1, ":", $3)) == NULL) _YYERROR("node_identifier");
clicon_debug(2,"identifier-ref-arg-str -> prefix : string"); } clicon_debug(2,"identifier-ref-arg-str -> prefix : string"); }
; ;

View file

@ -150,7 +150,7 @@ yang_type_cache_set(yang_type_cache **ycache0,
return retval; return retval;
} }
/*! Get individual fields (direct/destrucively) from yang type cache. */ /*! Get individual fields (direct/destructively) from yang type cache. */
int int
yang_type_cache_get(yang_type_cache *ycache, yang_type_cache_get(yang_type_cache *ycache,
yang_stmt **resolved, yang_stmt **resolved,
@ -227,16 +227,14 @@ ys_resolve_type(yang_stmt *ys,
yang_stmt *resolved = NULL; yang_stmt *resolved = NULL;
assert(ys->ys_keyword == Y_TYPE); assert(ys->ys_keyword == Y_TYPE);
/* Recursively resolve ys -> resolve with restrictions(options, etc)
* Note that the resolved type could be ys itself.
*/
if (yang_type_resolve((yang_stmt*)ys->ys_parent, ys, &resolved, if (yang_type_resolve((yang_stmt*)ys->ys_parent, ys, &resolved,
&options, &mincv, &maxcv, &pattern, &fraction) < 0) &options, &mincv, &maxcv, &pattern, &fraction) < 0)
goto done; goto done;
if (resolved && strcmp(resolved->ys_argument, "union")==0) /* Cache the resolve locally */
;
/* skip unions since they may have different sets of options, mincv, etc
* You would have to resolve all sub-types also recursively
*/
else
if (yang_type_cache_set(&ys->ys_typecache, if (yang_type_cache_set(&ys->ys_typecache,
resolved, options, mincv, maxcv, pattern, fraction) < 0) resolved, options, mincv, maxcv, pattern, fraction) < 0)
goto done; goto done;
@ -660,10 +658,12 @@ ys_cv_validate_union_one(yang_stmt *ys,
clicon_err(OE_UNIX, errno, "cv_new"); clicon_err(OE_UNIX, errno, "cv_new");
goto done; goto done;
} }
if (cv_parse(val, cvt) <0){ if ((retval = cv_parse1(val, cvt, reason)) < 0){
clicon_err(OE_UNIX, errno, "cv_parse"); clicon_err(OE_UNIX, errno, "cv_parse");
goto done; goto done;
} }
if (retval == 0)
goto done;
if ((retval = cv_validate1(cvt, cvtype, options, range_min, range_max, if ((retval = cv_validate1(cvt, cvtype, options, range_min, range_max,
pattern, yrt, restype, reason)) < 0) pattern, yrt, restype, reason)) < 0)
goto done; goto done;
@ -688,16 +688,32 @@ ys_cv_validate_union(yang_stmt *ys,
{ {
int retval = 1; /* valid */ int retval = 1; /* valid */
yang_stmt *yt = NULL; yang_stmt *yt = NULL;
char *reason1 = NULL; /* saved reason */
while ((yt = yn_each((yang_node*)yrestype, yt)) != NULL){ while ((yt = yn_each((yang_node*)yrestype, yt)) != NULL){
if (yt->ys_keyword != Y_TYPE) if (yt->ys_keyword != Y_TYPE)
continue; continue;
if ((retval = ys_cv_validate_union_one(ys, reason, yt, type, val)) < 0) if ((retval = ys_cv_validate_union_one(ys, reason, yt, type, val)) < 0)
goto done; goto done;
/* If validation failed, save reason, reset error and continue,
* save latest reason if noithing validates.
*/
if (retval == 0 && reason && *reason != NULL){
if (reason1)
free(reason1);
reason1 = *reason;
*reason = NULL;
}
if (retval == 1) /* Enough that one type validates value */ if (retval == 1) /* Enough that one type validates value */
break; break;
} }
done: done:
if (retval == 0 && reason1){
*reason = reason1;
reason1 = NULL;
}
if (reason1)
free(reason1);
return retval; return retval;
} }
@ -908,7 +924,7 @@ resolve_restrictions(yang_stmt *yrange,
} }
/*! Recursively resolve a yang type to built-in type with optional restrictions /*! Recursively resolve a yang type to built-in type with optional restrictions
* @param[in] ys yang-stmt from where the current search is based * @param[in] ys (original) type yang-stmt where the current search is based
* @param[in] ytype yang-stmt object containing currently resolving type * @param[in] ytype yang-stmt object containing currently resolving type
* @param[out] yrestype resolved type. return built-in type or NULL. mandatory * @param[out] yrestype resolved type. return built-in type or NULL. mandatory
* @param[out] options pointer to flags field of optional values. optional * @param[out] options pointer to flags field of optional values. optional
@ -945,14 +961,14 @@ yang_type_resolve(yang_stmt *ys,
char *prefix = NULL; char *prefix = NULL;
int retval = -1; int retval = -1;
yang_node *yn; yang_node *yn;
yang_stmt *ymod; yang_stmt *yrmod; /* module where resolved type is looked for */
if (options) if (options)
*options = 0x0; *options = 0x0;
*yrestype = NULL; /* Initialization of resolved type that may not be necessary */ *yrestype = NULL; /* Initialization of resolved type that may not be necessary */
type = yarg_id(ytype); /* This is the type to resolve */ type = yarg_id(ytype); /* This is the type to resolve */
prefix = yarg_prefix(ytype); /* And this its prefix */ prefix = yarg_prefix(ytype); /* And this its prefix */
/* Cache does not work for eg string length 32 */ /* Cache does not work for eg string length 32? */
if (!yang_builtin(type) && ytype->ys_typecache != NULL){ if (!yang_builtin(type) && ytype->ys_typecache != NULL){
if (yang_type_cache_get(ytype->ys_typecache, if (yang_type_cache_get(ytype->ys_typecache,
yrestype, options, mincv, maxcv, pattern, fraction) < 0) yrestype, options, mincv, maxcv, pattern, fraction) < 0)
@ -974,11 +990,12 @@ yang_type_resolve(yang_stmt *ys,
/* Not basic type. Now check if prefix which means we look in other module */ /* Not basic type. Now check if prefix which means we look in other module */
if (prefix){ /* Go to top and find import that matches */ if (prefix){ /* Go to top and find import that matches */
if ((ymod = yang_find_module_by_prefix(ys, prefix)) == NULL){ if ((yrmod = yang_find_module_by_prefix(ytype, prefix)) == NULL){
clicon_err(OE_DB, 0, "Type not resolved: %s:%s", prefix, type); clicon_err(OE_DB, 0, "Type not resolved: \"%s:%s\" in module %s",
prefix, type, ys_module(ys)->ys_argument);
goto done; goto done;
} }
if ((rytypedef = yang_find((yang_node*)ymod, Y_TYPEDEF, type)) == NULL) if ((rytypedef = yang_find((yang_node*)yrmod, Y_TYPEDEF, type)) == NULL)
goto ok; /* unresolved */ goto ok; /* unresolved */
} }
else else

View file

@ -78,14 +78,24 @@ expectfn(){
expect2= expect2=
fi fi
ret=$($cmd) ret=$($cmd)
r=$?
# echo "cmd:\"$cmd\"" # echo "cmd:\"$cmd\""
# echo "retval:\"$retval\"" # echo "retval:\"$retval\""
# echo "ret:\"$ret\"" # echo "ret:\"$ret\""
if [ $? -ne $retval ]; then # echo "r:\"$r\""
echo -e "\e[31m\nError in Test$testnr [$testname]:" if [ $r != $retval ]; then
echo -e "\e[31m\nError ($r != $retval) in Test$testnr [$testname]:"
echo -e "\e[0m:" echo -e "\e[0m:"
exit -1 exit -1
fi fi
if [ $r != 0 ]; then
return
fi
# if [ $ret -ne $retval ]; then
# echo -e "\e[31m\nError in Test$testnr [$testname]:"
# echo -e "\e[0m:"
# exit -1
# fi
# Match if both are empty string # Match if both are empty string
if [ -z "$ret" -a -z "$expect" ]; then if [ -z "$ret" -a -z "$expect" ]; then
return return

View file

@ -17,6 +17,7 @@ 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_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>$APPNAME</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_MODULE_MAIN>$APPNAME</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>

View file

@ -57,7 +57,7 @@ run(){
fi fi
rm -rf $mydir/* rm -rf $mydir/*
conf="-d candidate -b $mydir -p ../datastore/$name/$name.so -y $dir -m ietf-ip" conf="-d candidate -b $mydir -p ../datastore/$name/$name.so -y $dir/ietf-ip.yang"
new "datastore $name init" new "datastore $name init"
expectfn "$datastore $conf init" 0 "" expectfn "$datastore $conf init" 0 ""
@ -144,7 +144,7 @@ run(){
expectfn "$datastore $conf put create <config><x><y><a>1</a><b>3</b><c>newentry</c></y></x></config>" 0 "" expectfn "$datastore $conf put create <config><x><y><a>1</a><b>3</b><c>newentry</c></y></x></config>" 0 ""
new "datastore other db init" new "datastore other db init"
expectfn "$datastore -d kalle -b $mydir -p ../datastore/$name/$name.so -y $dir -m ietf-ip init" 0 "" expectfn "$datastore -d kalle -b $mydir -p ../datastore/$name/$name.so -y $dir/ietf-ip.yang init" 0 ""
new "datastore other db copy" new "datastore other db copy"
expectfn "$datastore $conf copy kalle" 0 "" expectfn "$datastore $conf copy kalle" 0 ""

View file

@ -13,6 +13,7 @@ cat <<EOF > $cfg
<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/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</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>

View file

@ -11,6 +11,7 @@ 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/clixon</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

@ -10,6 +10,7 @@ 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_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</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_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>

View file

@ -12,6 +12,7 @@ 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_DIR>/usr/local/share/clixon</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>

View file

@ -15,6 +15,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>/usr/local/share/clixon</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_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,6 +18,7 @@ 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_DIR>/usr/local/share/clixon</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

@ -13,6 +13,7 @@ cat <<EOF > $cfg
<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/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</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>
@ -200,7 +201,6 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><can
#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><interface><name>eth/0/0</name><description><![CDATA[myeth&]]></description><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>" #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><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 -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"

View file

@ -1,24 +1,104 @@
#!/bin/bash #!/bin/bash
# Parse yang openconfig tests # Parse yang openconfig tests
# Note that the openconfig test suites are patched to counter CLixon issues as follows:
# - release/models/mpls/openconfig-mpls-te.yang
# issue: https://github.com/clicon/clixon/issues/60
# - release/models/wifi/types/openconfig-wifi-types.yang
# issue: https://github.com/clicon/clixon/issues/59
#
#PROG="valgrind --leak-check=full --show-leak-kinds=all ../util/clixon_util_yang" #PROG="valgrind --leak-check=full --show-leak-kinds=all ../util/clixon_util_yang"
PROG=../util/clixon_util_yang PROG=../util/clixon_util_yang
OPENCONFIG=~/syssrc/openconfig OPENCONFIG=public
OCDIR=$OPENCONFIG/release/models
# Clone openconfig dir if not there
if [ ! -d public ]; then
git clone https://github.com/openconfig/public
else
(cd public; git pull)
fi
# include err() and new() functions and creates $dir # include err() and new() functions and creates $dir
. ./lib.sh . ./lib.sh
# Openconfig # Yang specifics: multi-keys and empty type
# Files not parseable: APPNAME=example
# - openconfig-access-points.yang # include err() and new() functions and creates $dir
# - openconfig-access-points.yang . ./lib.sh
new "Openconfig"
cfg=$dir/conf_yang.xml
fyang=$dir/test.yang
cat <<EOF > $cfg
<config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$OCDIR</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/acl</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/aft</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/bfd</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/bgp</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/catalog</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/interfaces</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/isis</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/lacp</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/lldp</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/local-routing</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/mpls</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/multicast</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/network-instance</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/openflow</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/optical-transport</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/ospf</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/platform</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/policy</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/policy-forwarding</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/probes</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/qos</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/relay-agent</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/rib</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/segment-routing</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/stp</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/system</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/telemetry</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/types</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/vlan</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/wifi</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/wifi/access-points</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$OCDIR/wifi/ap-manager</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/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_MODULE_MAIN>$APPNAME</CLICON_YANG_MODULE_MAIN>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_CLI_GENMODEL_COMPLETION>1</CLICON_CLI_GENMODEL_COMPLETION>
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
<CLICON_XMLDB_PLUGIN>/usr/local/lib/xmldb/text.so</CLICON_XMLDB_PLUGIN>
<CLICON_MODULE_LIBRARY_RFC7895>true</CLICON_MODULE_LIBRARY_RFC7895>
</config>
EOF
files=$(find $OPENCONFIG -name "*.yang") files=$(find $OPENCONFIG -name "*.yang")
# Just cound nr of modules (exclude submodule)
let m=0; # Nr of modules
for f in $files; do for f in $files; do
new "$f" if [ -n "$(head -1 $f|grep '^module')" ]; then
YANG=$(cat $f) let m++;
# NYI fi
expecteof "$PROG" 0 "$YANG" "module"
done done
echo "Number of modules:$m"
for f in $files; do
if [ -n "$(head -1 $f|grep '^module')" ]; then
new "cli $f"
expectfn "$clixon_cli -1f $cfg -y $f show version" 0 "3."
fi
done
rm -rf $dir rm -rf $dir

View file

@ -26,6 +26,7 @@ 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/$APPNAME/yang</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>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_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>

View file

@ -23,7 +23,7 @@ fyang=$dir/scaling.yang
fconfig=$dir/config fconfig=$dir/config
cat <<EOF > $fyang cat <<EOF > $fyang
module ietf-ip{ module scaling{
yang-version 1.1; yang-version 1.1;
namespace "urn:example:clixon"; namespace "urn:example:clixon";
prefix ip; prefix ip;
@ -47,8 +47,9 @@ EOF
cat <<EOF > $cfg cat <<EOF > $cfg
<config> <config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$fyang</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>ietf-ip</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<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>
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY> <CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>

View file

@ -11,6 +11,7 @@ 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_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</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>

View file

@ -12,6 +12,7 @@ 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_DIR>/usr/local/share/clixon</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>

View file

@ -14,6 +14,7 @@ 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_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> <CLICON_YANG_MODULE_MAIN>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>

View file

@ -25,8 +25,7 @@ UTIL=../util/clixon_util_stream
NCWAIT=5 # Wait (netconf valgrind may need more time) NCWAIT=5 # Wait (netconf valgrind may need more time)
if [ ! -x $UTIL ]; then if [ ! -x $UTIL ]; then
echo "$UTIL not found. To build: (cd ../util; make clixon_util_stream)" (cd ../util; make clixon_util_stream)
exit 1
fi fi
DATE=$(date +"%Y-%m-%d") DATE=$(date +"%Y-%m-%d")
# include err() and new() functions and creates $dir # include err() and new() functions and creates $dir

View file

@ -7,11 +7,15 @@ APPNAME=example
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
fyang=$dir/type.yang fyang=$dir/type.yang
fyang2=$dir/example2.yang
fyang3=$dir/example3.yang
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/$APPNAME/yang</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_MODULE_MAIN>example</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_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
@ -21,14 +25,59 @@ cat <<EOF > $cfg
<CLICON_CLI_GENMODEL_COMPLETION>1</CLICON_CLI_GENMODEL_COMPLETION> <CLICON_CLI_GENMODEL_COMPLETION>1</CLICON_CLI_GENMODEL_COMPLETION>
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR> <CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
<CLICON_XMLDB_PLUGIN>/usr/local/lib/xmldb/text.so</CLICON_XMLDB_PLUGIN> <CLICON_XMLDB_PLUGIN>/usr/local/lib/xmldb/text.so</CLICON_XMLDB_PLUGIN>
<CLICON_XMLDB_CACHE>false</CLICON_XMLDB_CACHE>
</config> </config>
EOF EOF
# transitive type, exists in fyang3, referenced from fyang2, but not declared in fyang
cat <<EOF > $fyang3
module example3{
prefix ex3;
namespace "urn:example:example3";
typedef w{
type union{
type int32{
range "4..44";
}
}
}
typedef u{
type union {
type w;
type enumeration {
enum "bounded";
enum "unbounded";
}
}
}
typedef t{
type string{
pattern '[a-z][0-9]*';
}
}
}
EOF
cat <<EOF > $fyang2
module example2{
import example3 { prefix ex3; }
namespace "urn:example:example2";
prefix ex2;
grouping gr2 {
leaf talle{
type ex3:t;
}
leaf ulle{
type ex3:u;
}
}
}
EOF
cat <<EOF > $fyang cat <<EOF > $fyang
module example{ module example{
yang-version 1.1; yang-version 1.1;
namespace "urn:example:clixon"; namespace "urn:example:clixon";
prefix ex; prefix ex;
import example2 { prefix ex2; }
typedef ab { typedef ab {
type string { type string {
pattern pattern
@ -136,6 +185,10 @@ module example{
leaf mbits{ leaf mbits{
type mybits; type mybits;
} }
container c{
description "transitive type- exists in ex3";
uses ex2:gr2;
}
} }
EOF EOF
@ -151,6 +204,50 @@ if [ $? -ne 0 ]; then
err err
fi fi
new "cli set transitive string"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c talle x99" 0 "^$"
new "cli set transitive string error"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c talle 9xx" 255 "^$"
new "netconf set transitive string error"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><c><talle>9xx</talle></c></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>"
new "netconf validate should fail"
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>validation of talle failed regexp match fail"
new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "cli set transitive union int"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c ulle 33" 0 "^$"
new "cli validate"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang -l o validate" 0 "^$"
new "cli set transitive union string"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c ulle unbounded" 0 "^$"
new "cli validate"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang -l o validate" 0 "^$"
new "cli set transitive union error. should fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c ulle kalle" 255 ""
new "cli set transitive union error int"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c ulle 55" 255 ""
new "netconf set transitive union error int"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><c><ulle>55</ulle></c></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>"
new "netconf validate should fail"
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>validation of ulle failed"
new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
#-----------
new "cli set ab" new "cli set ab"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list a.b.a.b" 0 "^$" expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list a.b.a.b" 0 "^$"

View file

@ -13,6 +13,7 @@ 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_DIR>/usr/local/share/clixon</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>

View file

@ -6,12 +6,16 @@ APPNAME=example
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
fyang=$dir/test.yang fyang=$dir/test.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>/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_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>
@ -30,6 +34,7 @@ module $APPNAME{
yang-version 1.1; yang-version 1.1;
prefix ex; prefix ex;
namespace "urn:example:clixon"; namespace "urn:example:clixon";
include example-types;
extension c-define { extension c-define {
description "Example from RFC 6020"; description "Example from RFC 6020";
argument "name"; argument "name";
@ -85,6 +90,41 @@ module $APPNAME{
type string; type string;
} }
} }
list mylist{ /* uses submodule */
key x;
leaf x{
type string;
}
uses ex:subm-group;
}
}
EOF
# Submodule Example from rfc7950 sec 7.2.3
cat <<EOF > $fsubmod
submodule example-types {
yang-version 1.1;
belongs-to $APPNAME {
prefix "sys";
}
import ietf-yang-types {
prefix "yang";
}
organization "Example Inc.";
contact "Joe L. User";
description
"This submodule defines common Example types.";
revision "2007-06-09" {
description "Initial revision.";
}
grouping subm-group {
description "Defined in submodule";
container subm-container{
leaf subm-leaf{
type string;
}
}
}
} }
EOF EOF
@ -128,7 +168,8 @@ new "netconf get config"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><f><e/><e>a</e></f></x></data></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><f><e/><e>a</e></f></x></data></rpc-reply>]]>]]>$"
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg" 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>]]>]]>$"
#new "cli not defined extension" #new "cli not defined extension"
#new "netconf not defined extension" #new "netconf not defined extension"
@ -182,7 +223,7 @@ new "netconf get presence only"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/nopresence"/></get-config></rpc>]]>]]>' "^<rpc-reply><data/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/nopresence"/></get-config></rpc>]]>]]>' "^<rpc-reply><data/></rpc-reply>]]>]]>$"
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg" 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>]]>]]>$"
new "netconf anyxml" new "netconf anyxml"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><x><any><foo><bar a=\"nisse\"/></foo></any></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><x><any><foo><bar a=\"nisse\"/></foo></any></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
@ -191,7 +232,7 @@ new "netconf validate anyxml"
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 -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf delete candidate" new "netconf delete candidate"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><delete-config><target><candidate/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><delete-config><target><candidate/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
# Check 3-keys # Check 3-keys
new "netconf add one 3-key entry" new "netconf add one 3-key entry"
@ -218,6 +259,25 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><can
new "netconf check delete" new "netconf check delete"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></data></rpc-reply>]]>]]>' expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></data></rpc-reply>]]>]]>'
# clear db for next test
new "netconf delete candidate"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><delete-config><target><candidate/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf commit empty candidate"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconfig config submodule"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><mylist><x>a</x><subm-container><subm-leaf>foo</subm-leaf></subm-container></mylist></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf submodule get config"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><mylist><x>a</x><subm-container><subm-leaf>foo</subm-leaf></subm-container></mylist></data></rpc-reply>]]>]]>$"
new "netconf submodule validate"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf submodule discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill
pid=`pgrep -u root -f clixon_backend` pid=`pgrep -u root -f clixon_backend`

View file

@ -31,6 +31,8 @@
***** END LICENSE BLOCK ***** ***** END LICENSE BLOCK *****
* Parse a SINGLE yang file - no dependencies - utility function only useful
* for basic syntactic checks.
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H

View file

@ -133,11 +133,14 @@ module clixon-config {
description description
"Location of configuration-file for default values (this file)"; "Location of configuration-file for default values (this file)";
} }
leaf CLICON_YANG_DIR { leaf-list CLICON_YANG_DIR {
type string; type string;
mandatory true;
description description
"Location of YANG module and submodule files."; "Yang directory path for finding module and submodule files.
A list of these options should be in the configuration.
When loading a Yang module, Clixon searches this list in the order
they appear. Ensure that CLIXON_DATADIR(default
/usr/local/share/clixon) is present in the path";
} }
leaf CLICON_YANG_MODULE_MAIN { leaf CLICON_YANG_MODULE_MAIN {
type string; type string;