* 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
* YANG parser cardinality checked (only modules level yet)
* See https://github.com/clicon/clixon/issues/84
* Support of submodule, include and belongs-to.
* 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)
* 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
* XML parser conformance to W3 spec

View file

@ -25,7 +25,7 @@ support.
* [Tests](test/)
* [Docker](docker/)
* [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
==========
@ -124,6 +124,10 @@ However, the following YANG syntax modules are not implemented:
- action
- 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
=======
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)
* guest: No access
Runtime
=======
@ -225,3 +228,12 @@ Runtime
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)
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;
fd = fileno(f);
/* Read configfile */
@ -753,11 +753,10 @@ main(int argc,
/* Load main application yang specification either module or specific file
* If -y <file> is given, it overrides main module */
if (yang_filename){
if (yang_spec_parse_file(h, yang_filename, clicon_yang_dir(h), yspec, NULL) < 0)
if (yang_spec_parse_file(h, yang_filename, yspec, NULL) < 0)
goto done;
}
else if (yang_spec_parse_module(h, clicon_yang_module_main(h),
clicon_yang_dir(h),
clicon_yang_module_revision(h),
yspec, NULL) < 0)
goto done;
@ -770,11 +769,11 @@ main(int argc,
goto done;
/* Load yang Restconf stream discovery */
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;
/* Load yang Netconf stream discovery */
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;
/* Set options: database dir and yangspec (could be hidden in connect?)*/
if (xmldb_setopt(h, "dbdir", clicon_xmldb_dir(h)) < 0)

View file

@ -51,7 +51,7 @@
#include <assert.h>
#include <fcntl.h>
#include <sys/param.h>
#include <math.h> /* For pow() kludge in cvtype_max2str_dup2 */
/* cligen */
#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,
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
* Check for completion (of already existent values), ranges (eg range[min:max]) and
* patterns, (eg regexp:"[0.9]*").
@ -282,10 +304,12 @@ yang2cli_var_sub(clicon_handle h,
}
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");
goto done;
}
}
}
cprintf(cb, "%s]", r); /* range */
free(r);
@ -410,7 +434,7 @@ yang2cli_var(clicon_handle h,
cbuf *cb,
char *helptext)
{
int retval = -1;
int retval = -1;
char *origtype;
yang_stmt *yrestype; /* resolved type */
char *restype; /* resolved type */
@ -513,10 +537,12 @@ yang2cli_leaf(clicon_handle h,
if (helptext)
cprintf(cbuf, "(\"%s\")", helptext);
cprintf(cbuf, " ");
yang2cli_var(h, ys, cbuf, helptext);
if (yang2cli_var(h, ys, cbuf, helptext) < 0)
goto done;
}
else
yang2cli_var(h, ys, cbuf, helptext);
if (yang2cli_var(h, ys, cbuf, helptext) < 0)
goto done;
if (callback){
if (cli_callback_generate(h, ys, cbuf) < 0)
goto done;

View file

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

View file

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

View file

@ -32,7 +32,13 @@
***** 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
#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));
/* 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;
/* Check if found */
if (yrpc != NULL){

View file

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

11
configure vendored
View file

@ -4391,15 +4391,14 @@ fi
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"
cat >>confdefs.h <<_ACEOF
#define CLIXON_DATADIR "${CLIXON_DATADIR}"
_ACEOF
# Default location for config file
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)
# 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)
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
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>
/* 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
*/
@ -85,8 +85,7 @@ usage(char *argv0)
"\t-d <db>\t\tDatabase name. Default: running. Alt: candidate,startup\n"
"\t-b <dir>\tDatabase directory. Mandatory\n"
"\t-p <plugin>\tDatastore plugin. Mandatory\n"
"\t-y <dir>\tYang directory (where modules are stored). Mandatory\n"
"\t-m <module>\tYang module. Mandatory\n"
"\t-y <file>\tYang file. Mandatory\n"
"and command is either:\n"
"\tget [<xpath>]\n"
"\tmget <nr> [<xpath>]\n"
@ -115,7 +114,6 @@ main(int argc, char **argv)
char *plugin = NULL;
char *cmd = NULL;
yang_spec *yspec = NULL;
char *yangdir = NULL;
char *yangmodule = NULL;
char *dbdir = NULL;
int ret;
@ -158,12 +156,7 @@ main(int argc, char **argv)
usage(argv0);
dbdir = optarg;
break;
case 'y': /* Yang directory */
if (!optarg)
usage(argv0);
yangdir = optarg;
break;
case 'm': /* Yang module */
case 'y': /* Yang file */
if (!optarg)
usage(argv0);
yangmodule = optarg;
@ -188,10 +181,6 @@ main(int argc, char **argv)
clicon_err(OE_DB, 0, "Missing dbdir -b option");
goto done;
}
if (yangdir == NULL){
clicon_err(OE_YANG, 0, "Missing yangdir -y option");
goto done;
}
if (yangmodule == NULL){
clicon_err(OE_YANG, 0, "Missing yang module -m option");
goto done;
@ -206,7 +195,7 @@ main(int argc, char **argv)
if ((yspec = yspec_new()) == NULL)
goto done;
/* 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;
/* Set database directory option */
if (xmldb_setopt(h, "dbdir", dbdir) < 0)

View file

@ -1367,8 +1367,7 @@ main(int argc,
enum operation_type op;
char *cmd;
char *db;
char *yangdir;
char *yangmod;
char *yangmod; /* yang file */
yang_spec *yspec = NULL;
clicon_handle h;
@ -1381,12 +1380,11 @@ main(int argc,
}
cmd = argv[1];
db = argv[2];
yangdir = argv[3];
yangmod = argv[4];
db_init(db);
if ((yspec = yspec_new()) == NULL)
goto done
if (yang_parse(h, NULL, yangmod, yangdir, NULL, yspec) < 0)
if (yang_parse(h, NULL, yangmod, NULL, yspec) < 0)
goto done;
if (strcmp(cmd, "get")==0){
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
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 --with-configfile=FILE when configuring
- 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 --with-sysconfig=<dir> when configuring. Then FILE is <dir>/clixon.xml
- Provide --sysconfig=<dir> when configuring. Then FILE is <dir>/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?
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"
# Regular doxygen documentation
# Need to install doxygen
doc:
doxygen Doxyfile # generates html dir
echo "Build doxygen graphs: make graphs"
# doxygen documentation with callgraphs
# Need to install graphviz
graphs:
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_FEATURE>*:*</CLICON_FEATURE>
<CLICON_YANG_DIR>/usr/local/share/example/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
<CLICON_CLI_MODE>example</CLICON_CLI_MODE>
<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. */
/* Clixon data dir for system yang files etc */
#undef CLIXON_DATADIR
/* Location for apps to find default config file */
#undef CLIXON_DEFAULT_CONFIG
@ -42,6 +39,9 @@
/* Define to 1 if you have the `crypt' library (-lcrypt). */
#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). */
#undef HAVE_LIBDL
@ -133,4 +133,4 @@
`char[]'. */
#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){
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){
return clicon_option_str(h, "CLICON_YANG_MODULE_MAIN");
}

View file

@ -95,6 +95,7 @@ enum rfc_6020{
Y_MANDATORY,
Y_MAX_ELEMENTS,
Y_MIN_ELEMENTS,
Y_MODIFIER,
Y_MODULE,
Y_MUST,
Y_NAMESPACE,
@ -193,6 +194,8 @@ struct yang_stmt{
char *ys_argument; /* String / argument depending on keyword */
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()
Following stmts have cv:s:
leaf: for default value
@ -200,7 +203,7 @@ struct yang_stmt{
config: boolean true or false
mandatory: boolean true or false
fraction-digits for fraction-digits
unkown-stmt (argument)
unknown-stmt (argument)
*/
cvec *ys_cvec; /* List of stmt-specific variables
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);
yang_stmt *yang_parse_file(int fd, const char *name, yang_spec *ysp);
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);
int yang_apply(yang_node *yn, enum rfc_6020 key, yang_applyfn_t fn,
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);
int yang_desc_schema_nodeid(yang_node *yn, char *schema_nodeid,
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 yang_mandatory(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_file(clicon_handle h, char *filename, char *dir, 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, yang_spec *yspec, yang_stmt **ymodp);
cvec *yang_arg2cvec(yang_stmt *ys, char *delimi);
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);
/* 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;
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;
if ((xc = clicon_conf_xml(h)) == NULL){
clicon_err(OE_CFG, ENOENT, "Clicon configuration not loaded");

View file

@ -178,8 +178,16 @@ parse_configfile(clicon_handle h,
__FUNCTION__, name, body);
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)
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,
name,
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);
goto done;
}
/* Parse clixon yang spec */
if (yang_parse(h, NULL, "clixon-config", CLIXON_DATADIR, NULL, yspec, NULL) < 0)
goto done;
/* Read configfile */
/* Read configfile first without yangspec, for bootstrapping */
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);
/* 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);
/* Specific option handling */
if (clicon_option_bool(h, "CLICON_XML_SORT") == 1)
@ -638,7 +657,7 @@ clicon_conf_xml(clicon_handle h)
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
*/
int

View file

@ -122,6 +122,7 @@ static const map_str2int ykmap[] = {
{"mandatory", Y_MANDATORY},
{"max-elements", Y_MAX_ELEMENTS},
{"min-elements", Y_MIN_ELEMENTS},
{"modifier", Y_MODIFIER},
{"module", Y_MODULE},
{"must", Y_MUST},
{"namespace", Y_NAMESPACE},
@ -206,6 +207,8 @@ ys_free1(yang_stmt *ys)
{
if (ys->ys_argument)
free(ys->ys_argument);
if (ys->ys_extra)
free(ys->ys_extra);
if (ys->ys_cv)
cv_free(ys->ys_cv);
if (ys->ys_cvec)
@ -233,7 +236,8 @@ ys_free(yang_stmt *ys)
return 0;
}
/*! Free a yang specification recursively */
/*! Free a yang specification recursively
*/
int
yspec_free(yang_spec *yspec)
{
@ -294,6 +298,11 @@ ys_cp(yang_stmt *ynew,
clicon_err(OE_YANG, errno, "strdup");
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 ((ynew->ys_cv = cv_dup(yold->ys_cv)) == NULL){
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)
goto done;
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)
goto ok;
goto done;
@ -771,7 +781,7 @@ yang_order(yang_stmt *y)
int j=0;
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;
for (i=0; i<ypp->yn_len; i++){
yn = (yang_node*)ypp->yn_stmt[i];
@ -800,7 +810,8 @@ yang_key2str(int 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.
* @param[in] ys Any yang statement in a yang tree
* @retval ymod The top module or sub-module
@ -811,14 +822,13 @@ ys_module(yang_stmt *ys)
{
yang_node *yn;
#if 1
if (ys==NULL || ys->ys_keyword==Y_SPEC)
return NULL;
#else
if (ys==NULL || ys->ys_keyword==Y_SPEC)
if (ys->ys_keyword == Y_MODULE || ys->ys_keyword == Y_SUBMODULE)
return ys;
#endif
while (ys != NULL && ys->ys_keyword != Y_MODULE && ys->ys_keyword != Y_SUBMODULE){
while (ys != NULL &&
ys->ys_keyword != Y_MODULE &&
ys->ys_keyword != Y_SUBMODULE){
yn = ys->ys_parent;
/* Some extra stuff to ensure ys is a stmt */
if (yn && yn->yn_keyword == Y_SPEC)
@ -973,7 +983,8 @@ yang_find_module_by_prefix(yang_stmt *ys,
}
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;
if ((yprefix = yang_find((yang_node*)yimport, Y_PREFIX, NULL)) != NULL &&
strcmp(yprefix->ys_argument, prefix) == 0){
@ -981,9 +992,10 @@ yang_find_module_by_prefix(yang_stmt *ys,
}
}
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",
yimport->ys_argument);
prefix);
yimport = NULL;
goto done; /* unresolved */
}
@ -1411,9 +1423,9 @@ ys_populate_feature(clicon_handle h,
cg_var *cv;
char *module;
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)
goto ok;
if ((ymod = ys_module(ys)) == NULL){
@ -1422,14 +1434,14 @@ ys_populate_feature(clicon_handle h,
}
module = ymod->ys_argument;
feature = ys->ys_argument;
x1 = NULL;
while ((x1 = xml_child_each(x, x1, CX_ELMNT)) != NULL && found == 0) {
xc = NULL;
while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL && found == 0) {
char *m = NULL;
char *f = NULL;
if (strcmp(xml_name(x1), "CLICON_FEATURE") != 0)
if (strcmp(xml_name(xc), "CLICON_FEATURE") != 0)
continue;
/* 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;
if (m && f &&
(strcmp(m,"*")==0 ||
@ -1454,6 +1466,51 @@ ys_populate_feature(clicon_handle h,
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.
*
* 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)
goto done;
break;
case Y_UNKNOWN:
if (ys_populate_unknown(ys) < 0)
goto done;
break;
default:
break;
}
@ -1555,12 +1616,11 @@ yang_augment_node(yang_stmt *ys,
yang_stmt *yss = NULL;
yang_stmt *yc;
int i;
schema_nodeid = ys->ys_argument;
clicon_debug(1, "%s %s", __FUNCTION__, schema_nodeid);
/* 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;
if (yss == NULL)
goto ok;
@ -1646,14 +1706,15 @@ yang_expand(yang_node *yn)
prefix = yarg_prefix(ys); /* And this its prefix */
if (ys_grouping_resolve(ys, prefix, name, &ygrouping) < 0)
goto done;
if (prefix)
free(prefix);
if (ygrouping == NULL){
clicon_log(LOG_NOTICE, "%s: Yang error : grouping \"%s\" not found",
__FUNCTION__, ys->ys_argument);
clicon_log(LOG_NOTICE, "%s: Yang error : grouping \"%s\" not found in module \"%s\"",
__FUNCTION__, ys->ys_argument, ys_module(ys)->ys_argument);
goto done;
break;
}
if (prefix)
free(prefix); /* XXX move up */
/* 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
the 'uses' place */
@ -1825,48 +1886,69 @@ yang_parse_file(int fd,
return ymod; /* top-level (sub)module */
}
/*! No specific revision give. Match a yang file given dir and module
/*! No specific revision give. Match a yang file given module
* @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] revision Revision or NULL
* @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 0 No matching entry found
* @retval -1 Error
*/
static int
yang_parse_find_match(const char *yang_dir,
const char *module,
yang_parse_find_match(clicon_handle h,
const char *module,
const char *revision,
cbuf *fbuf)
{
int retval = -1;
int retval = -1;
struct dirent *dp = NULL;
int ndp;
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){
clicon_err(OE_YANG, errno, "cbuf_new");
goto done;
}
/* RFC 6020: The name of the file SHOULD be of the form:
module-or-submodule-name ['@' revision-date] ( '.yang' / '.yin' )
revision-date ::= 4DIGIT "-" 2DIGIT "-" 2DIGIT
*/
cprintf(regex, "^%s(@[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9])?(.yang)$",
module);
if ((ndp = clicon_file_dirent(yang_dir,
&dp,
cbuf_get(regex),
S_IFREG)) < 0)
goto done;
/* Entries are sorted, last entry should be most recent date */
if (ndp != 0){
cprintf(fbuf, "%s/%s", yang_dir, dp[ndp-1].d_name);
retval = 1;
}
* module-or-submodule-name ['@' revision-date] ( '.yang' / '.yin' )
* revision-date ::= 4DIGIT "-" 2DIGIT "-" 2DIGIT
*/
if (revision)
cprintf(regex, "^%s@%s(.yang)$", module, revision);
else
retval = 0;
cprintf(regex, "^%s(@[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9])?(.yang)$",
module);
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,
cbuf_get(regex),
S_IFREG)) < 0)
goto done;
/* Entries are sorted, last entry should be most recent date
* Found
*/
if (ndp != 0){
cprintf(fbuf, "%s/%s", dir, dp[ndp-1].d_name);
retval = 1;
goto done;
}
}
ok:
retval = 0;
done:
if (regex)
cbuf_free(regex);
@ -1875,7 +1957,6 @@ yang_parse_find_match(const char *yang_dir,
return retval;
}
/*! Open a file, read into a string and invoke yang parsing
*
* Similar to clicon_yang_str(), just read a file first
@ -1903,7 +1984,6 @@ yang_parse_filename(const char *filename,
int fd = -1;
struct stat st;
clicon_log(LOG_DEBUG, "Parsing yang file: %s", filename);
if (stat(filename, &st) < 0){
clicon_err(OE_YANG, errno, "%s not found", filename);
goto done;
@ -1921,8 +2001,8 @@ yang_parse_filename(const char *filename,
}
static yang_stmt *
yang_parse_module(const char *module,
const char *dir,
yang_parse_module(clicon_handle h,
const char *module,
const char *revision,
yang_spec *ysp)
{
@ -1934,16 +2014,12 @@ yang_parse_module(const char *module,
clicon_err(OE_YANG, errno, "cbuf_new");
goto done;
}
if (revision)
cprintf(fbuf, "%s/%s@%s.yang", dir, module, revision);
else{
/* No specific revision, Match a yang file */
if ((nr = yang_parse_find_match(dir, module, fbuf)) < 0)
goto done;
if (nr == 0){
clicon_err(OE_YANG, errno, "No matching %s yang files found in %s (expected module name or absolute filename)", module, dir);
goto done;
}
/* Match a yang file with or without revision in yang-dir list */
if ((nr = yang_parse_find_match(h, module, revision, fbuf)) < 0)
goto done;
if (nr == 0){
clicon_err(OE_YANG, errno, "No yang files found matching \"%s\" in the list of CLICON_YANG_DIRs", module);
goto done;
}
if ((ymod = yang_parse_filename(cbuf_get(fbuf), ysp)) == NULL)
goto done;
@ -1953,10 +2029,9 @@ yang_parse_module(const char *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] yang_dir Directory where all YANG module files reside
* @param[in] module Name of main YANG module. Or absolute file name.
* @param[in] revision Module revision date or NULL
* @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
*/
static int
yang_parse_recurse(yang_stmt *ymod,
const char *dir,
yang_parse_recurse(clicon_handle h,
yang_stmt *ymod,
yang_spec *ysp)
{
int retval = -1;
@ -1982,21 +2057,29 @@ yang_parse_recurse(yang_stmt *ymod,
char *submodule;
char *subrevision;
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){
if (yi->ys_keyword != Y_IMPORT)
keyw = yi->ys_keyword;
if (keyw != Y_IMPORT && keyw != Y_INCLUDE)
continue;
/* common part */
submodule = yi->ys_argument;
/* Is there a specific revision (or just latest)? */
if ((yrev = yang_find((yang_node*)yi, Y_REVISION_DATE, NULL)) != NULL)
subrevision = yrev->ys_argument;
else
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 */
if ((subymod = yang_parse_module(submodule, dir, subrevision, ysp)) == NULL)
if ((subymod = yang_parse_module(h, submodule, subrevision, ysp)) == NULL)
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;
goto done;
}
@ -2019,7 +2102,8 @@ ys_schemanode_check(yang_stmt *ys,
yp = ys->ys_parent;
switch (ys->ys_keyword){
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;
/* fallthru */
case Y_REFINE:
@ -2035,7 +2119,7 @@ ys_schemanode_check(yang_stmt *ys,
break;
case Y_DEVIATION:
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;
if (yres == NULL){
clicon_err(OE_YANG, 0, "schemanode sanity check of %s", ys->ys_argument);
@ -2127,10 +2211,69 @@ yang_features(clicon_handle h,
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
*
* @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] module Name of main YANG module. Or absolute file name.
* @param[in] revision Main module revision date string or NULL
@ -2154,7 +2297,6 @@ int
yang_parse(clicon_handle h,
const char *filename,
const char *module,
const char *dir,
const char *revision,
yang_spec *ysp,
yang_stmt **ymodp)
@ -2164,63 +2306,89 @@ yang_parse(clicon_handle h,
int i;
int modnr; /* Existing number of modules */
/* Apply steps 2.. on new modules, ie ones after modnr. */
modnr = ysp->yp_len;
if (filename){
if ((ymod = yang_parse_filename(filename, ysp)) == NULL)
goto done;
}
else
if ((ymod = yang_parse_module(module, dir, revision, ysp)) == NULL)
if ((ymod = yang_parse_module(h, module, revision, ysp)) == NULL)
goto done;
/* From here on, apply actions on new modules, ie ones after modnr. */
/* Step 1: parse from text to yang parse-tree. */
/* 1: Parse from text to yang parse-tree. */
/* Iterate through modules */
if (yang_parse_recurse(ymod, dir, ysp) < 0)
if (yang_parse_recurse(h, ymod, ysp) < 0)
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 */
if (yang_cardinality(h, ysp->yp_stmt[i], ysp->yp_stmt[i]->ys_argument) < 0)
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 */
if (yang_features(h, ysp->yp_stmt[i]) < 0)
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++)
if (yang_apply((yang_node*)ysp->yp_stmt[i], -1, ys_populate, (void*)h) < 0)
goto done;
/* Step 4: Resolve all types: populate type caches. Requires eg length/range cvecs
* from ys_populate step
/* 6: Resolve all types: populate type caches. Requires eg length/range cvecs
* from ys_populate step.
* Must be done using static binding.
*/
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
context they are used. Like static scoping. After this we expand all
grouping/uses and unfold all macros into a single tree as they are used.
*/
/* Up to here resolving is made in the context they are defined, rather
* than the context they are used (except for submodules being merged w
* 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++){
if (yang_expand((yang_node*)ysp->yp_stmt[i]) < 0)
goto done;
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)
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++)
if (yang_apply((yang_node*)ysp->yp_stmt[i], -1, ys_schemanode_check, NULL) < 0)
goto done;
/* Return main module parsed in step 1 */
if (ymodp)
*ymodp = ymod;
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
* @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] keyword A schemode of this type, or -1 if any
* @param[out] yres Result yang statement node, or NULL if not found
@ -2382,6 +2551,7 @@ schema_nodeid_vec(yang_node *yn,
*/
int
yang_abs_schema_nodeid(yang_spec *yspec,
yang_stmt *yn,
char *schema_nodeid,
enum rfc_6020 keyword,
yang_stmt **yres)
@ -2389,7 +2559,7 @@ yang_abs_schema_nodeid(yang_spec *yspec,
int retval = -1;
char **vec = NULL;
int nvec;
yang_stmt *ymod;
yang_stmt *ymod = NULL;
char *id;
char *prefix = NULL;
yang_stmt *yprefix;
@ -2421,16 +2591,20 @@ yang_abs_schema_nodeid(yang_spec *yspec,
}
prefix[id-vec[1]] = '\0';
id++;
ymod = NULL;
while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) {
if ((yprefix = yang_find((yang_node*)ymod, Y_PREFIX, NULL)) != NULL &&
strcmp(yprefix->ys_argument, prefix) == 0){
break;
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;
while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) {
if ((yprefix = yang_find((yang_node*)ymod, Y_PREFIX, NULL)) != NULL &&
strcmp(yprefix->ys_argument, prefix) == 0){
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){
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;
}
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 &&
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;
}
}
@ -2546,12 +2720,7 @@ ys_parse_sub(yang_stmt *ys,
char *extra)
{
int retval = -1;
int cvret;
char *reason = NULL;
yang_stmt *ymod;
uint8_t fd;
char *prefix = NULL;
char *name;
switch (ys->ys_keyword){
case Y_FRACTION_DIGITS:
@ -2563,40 +2732,17 @@ ys_parse_sub(yang_stmt *ys,
goto done;
}
break;
case Y_UNKNOWN:
case Y_UNKNOWN: /* XXX This code assumes ymod already loaded
but it may not be */
if (extra == NULL)
break;
/* 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;
}
ys->ys_extra = extra;
break;
default:
break;
}
ok:
retval = 0;
done:
if (prefix)
free(prefix);
return retval;
}
@ -2654,7 +2800,6 @@ 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)
@ -2674,11 +2819,7 @@ yang_spec_parse_module(clicon_handle h,
clicon_err(OE_YANG, EINVAL, "yang module illegal format");
goto done;
}
if (dir == NULL){
clicon_err(OE_YANG, EINVAL, "yang dir not set");
goto done;
}
if (yang_parse(h, NULL, module, dir, revision, yspec, ymodp) < 0)
if (yang_parse(h, NULL, module, revision, yspec, ymodp) < 0)
goto done;
retval = 0;
done:
@ -2698,7 +2839,6 @@ yang_spec_parse_module(clicon_handle h,
int
yang_spec_parse_file(clicon_handle h,
char *filename,
char *dir,
yang_spec *yspec,
yang_stmt **ymodp)
{
@ -2708,11 +2848,7 @@ yang_spec_parse_file(clicon_handle h,
clicon_err(OE_YANG, EINVAL, "yang spec is NULL");
goto done;
}
if (dir == NULL){
clicon_err(OE_YANG, EINVAL, "yang dir not set");
goto done;
}
if (yang_parse(h, filename, NULL, dir, NULL, yspec, ymodp) < 0)
if (yang_parse(h, filename, NULL, NULL, yspec, ymodp) < 0)
goto done;
retval = 0;
done:

View file

@ -193,7 +193,8 @@ yang_cardinality(clicon_handle h,
pk = yt->ys_keyword;
/* 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 */
i = 0;
while (i<yt->ys_len){
@ -231,14 +232,15 @@ yang_cardinality(clicon_handle h,
}
if (0) { /* Notyet */
/* 4) Recurse */
i = 0;
while (i<yt->ys_len){ /* Note, children may be removed */
ys = yt->ys_stmt[i++];
if (yang_cardinality(h, ys, modname) < 0)
goto done;
}
/* 4) Recurse */
i = 0;
while (i<yt->ys_len){ /* Note, children may be removed */
ys = yt->ys_stmt[i++];
if (yang_cardinality(h, ys, modname) < 0)
goto done;
}
}
ok:
retval = 0;
done:
return retval;

View file

@ -77,7 +77,6 @@
*
* Load RFC7895 yang spec, module-set-id, etc.
* @param[in] h Clicon handle
* @note CLIXON_DATADIR is hardcoded
*/
int
yang_modules_init(clicon_handle h)
@ -94,7 +93,7 @@ yang_modules_init(clicon_handle h)
goto done;
}
/* 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;
/* Find revision */
if (yang_modules_revision(h) == NULL){
@ -121,7 +120,8 @@ yang_modules_revision(clicon_handle h)
char *revision = NULL;
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){
revision = yrev->ys_argument;
}
@ -172,7 +172,8 @@ yang_modules_state_get(clicon_handle h,
char *module = "ietf-yang-library";
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);
goto done;
}
@ -189,7 +190,8 @@ yang_modules_state_get(clicon_handle h,
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;
cprintf(cb,"<module>");
cprintf(cb,"<name>%s</name>", ymod->ys_argument);

View file

@ -42,9 +42,6 @@
* identifier_ref = 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);
* - length-arg-str
* - path-arg-str
@ -124,6 +121,7 @@
%token K_MANDATORY
%token K_MAX_ELEMENTS
%token K_MIN_ELEMENTS
%token K_MODIFIER
%token K_MODULE
%token K_MUST
%token K_NAMESPACE
@ -369,29 +367,28 @@ file : module_stmt MY_EOF
/* For extensions */
unknown_stmt : ustring ':' ustring ';'
{ char *id; if ((id=string_del_join($1, ":", $3)) == NULL) _YYERROR("0");
if (ysp_add(_yy, Y_UNKNOWN, id, NULL) == 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("unknown_stmt");
clicon_debug(2,"unknown-stmt -> ustring : ustring");
}
| ustring ':' ustring ' ' string ';'
{ char *id; if ((id=string_del_join($1, ":", $3)) == NULL) _YYERROR("0");
if (ysp_add(_yy, Y_UNKNOWN, id, $5) == 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("unknwon_stmt"); }
clicon_debug(2,"unknown-stmt -> ustring : ustring string");
if ($5) free($5);
}
;
/* module identifier-arg-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 '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("2");
clicon_debug(2,"module_stmt -> id-arg-str { module-substmts }");}
{ if (ystack_pop(_yy) < 0) _YYERROR("module_stmt");
clicon_debug(2,"module_stmt -> id-arg-str { module-substmts }");}
;
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
{ clicon_debug(2,"module-substmts ->");}
;
@ -406,10 +403,11 @@ module_substmt : module_header_stmts { clicon_debug(2,"module-substmt -> module-
;
/* submodule */
submodule_stmt : K_SUBMODULE identifier_str '{' submodule_substmts '}'
{ if ((_YY->yy_module = ysp_add_push(_yy, Y_SUBMODULE, $2)) == NULL) _YYERROR("3");
clicon_debug(2,"submodule -> id-arg-str { submodule-stmts }");
}
submodule_stmt : K_SUBMODULE identifier_str
{ if ((_YY->yy_module = ysp_add_push(_yy, Y_SUBMODULE, $2)) == NULL) _YYERROR("submodule_stmt"); }
'{' 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
@ -464,16 +462,16 @@ submodule_header_stmt : yang_version_stmt
;
/* yang-version-stmt = yang-version-keyword yang-version-arg-str */
yang_version_stmt : K_YANG_VERSION string ';'
{ if (ysp_add(_yy, Y_YANG_VERSION, $2, NULL) == NULL) _YYERROR("83");
yang_version_stmt : K_YANG_VERSION string stmtend
{ if (ysp_add(_yy, Y_YANG_VERSION, $2, NULL) == NULL) _YYERROR("yang_version_stmt");
clicon_debug(2,"yang-version-stmt -> YANG-VERSION string"); }
;
/* import */
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 '}'
{ 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 }");}
;
@ -484,69 +482,79 @@ import_substmts : import_substmts import_substmt
;
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 ';'
{ if (ysp_add(_yy, Y_INCLUDE, $2, NULL)== NULL) _YYERROR("97");
clicon_debug(2,"include-stmt -> id-arg-str"); }
| K_INCLUDE identifier_str '{' revision_date_stmt '}'
{ if (ysp_add(_yy, Y_INCLUDE, $2, NULL)== NULL) _YYERROR("98");
clicon_debug(2,"include-stmt -> id-arg-str { revision-date-stmt }"); }
{ if (ysp_add(_yy, Y_INCLUDE, $2, NULL)== NULL) _YYERROR("include_stmt");
clicon_debug(2,"include-stmt -> id-str"); }
| K_INCLUDE identifier_str '{' include_substmts '}'
{ if (ysp_add(_yy, Y_INCLUDE, $2, NULL)== NULL) _YYERROR("include_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 : 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"); }
;
prefix_stmt : K_PREFIX identifier_str ';' /* XXX prefix-arg-str */
{ if (ysp_add(_yy, Y_PREFIX, $2, NULL)== NULL) _YYERROR("100");
prefix_stmt : K_PREFIX identifier_str stmtend /* XXX prefix-arg-str */
{ if (ysp_add(_yy, Y_PREFIX, $2, NULL)== NULL) _YYERROR("prefix_stmt");
clicon_debug(2,"prefix-stmt -> PREFIX string ;");}
;
belongs_to_stmt : K_BELONGS_TO identifier_str ';'
{ 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");
belongs_to_stmt : K_BELONGS_TO identifier_str '{' prefix_stmt '}'
{ if (ysp_add(_yy, Y_BELONGS_TO, $2, NULL)== NULL) _YYERROR("belongs_to_stmt");
clicon_debug(2,"belongs-to-stmt -> BELONGS-TO id-arg-str { prefix-stmt } ");}
;
organization_stmt: K_ORGANIZATION string ';'
{ if (ysp_add(_yy, Y_ORGANIZATION, $2, NULL)== NULL) _YYERROR("102");
organization_stmt: K_ORGANIZATION string stmtend
{ if (ysp_add(_yy, Y_ORGANIZATION, $2, NULL)== NULL) _YYERROR("belongs_to_stmt");
clicon_debug(2,"organization-stmt -> ORGANIZATION string ;");}
;
contact_stmt : K_CONTACT string ';'
{ if (ysp_add(_yy, Y_CONTACT, $2, NULL)== NULL) _YYERROR("95");
contact_stmt : K_CONTACT string stmtend
{ if (ysp_add(_yy, Y_CONTACT, $2, NULL)== NULL) _YYERROR("contact_stmt");
clicon_debug(2,"contact-stmt -> CONTACT string"); }
;
description_stmt: K_DESCRIPTION string ';'
{ if (ysp_add(_yy, Y_DESCRIPTION, $2, NULL)== NULL) _YYERROR("101");
description_stmt : K_DESCRIPTION string stmtend
{ if (ysp_add(_yy, Y_DESCRIPTION, $2, NULL)== NULL) _YYERROR("description_stmt");
clicon_debug(2,"description-stmt -> DESCRIPTION string ;");}
;
reference_stmt: K_REFERENCE string ';'
{ if (ysp_add(_yy, Y_REFERENCE, $2, NULL)== NULL) _YYERROR("105");
reference_stmt : K_REFERENCE string stmtend
{ if (ysp_add(_yy, Y_REFERENCE, $2, NULL)== NULL) _YYERROR("reference_stmt");
clicon_debug(2,"reference-stmt -> REFERENCE 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"); }
;
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 ;"); }
| 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 */
{ 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 }"); }
;
@ -570,19 +578,18 @@ revision_stmts : revision_stmts revision_stmt
{ clicon_debug(2,"revision-stmts -> "); }
;
revision_date_stmt : K_REVISION_DATE string ';' /* XXX date-arg-str */
{ if (ysp_add(_yy, Y_REVISION_DATE, $2, NULL) == NULL) _YYERROR("96");
revision_date_stmt : K_REVISION_DATE string stmtend /* XXX date-arg-str */
{ if (ysp_add(_yy, Y_REVISION_DATE, $2, NULL) == NULL) _YYERROR("revision_date_stmt");
clicon_debug(2,"revision-date-stmt -> date;"); }
;
/* Extension */
extension_stmt: K_EXTENSION identifier_str ';'
{ if (ysp_add(_yy, Y_EXTENSION, $2, NULL) == NULL) _YYERROR("59");
extension_stmt : K_EXTENSION identifier_str ';'
{ if (ysp_add(_yy, Y_EXTENSION, $2, NULL) == NULL) _YYERROR("extension_stmt");
clicon_debug(2,"extenstion-stmt -> EXTENSION id-arg-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 '}'
{ 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 }"); }
;
@ -612,13 +619,13 @@ yin_element_stmt1 : K_YIN_ELEMENT bool_str stmtend {free($2);}
/* Identity */
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 ;"); }
| 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 '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("67");
{ if (ystack_pop(_yy) < 0) _YYERROR("identity_stmt");
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 -> "); }
;
base_stmt : K_BASE identifier_ref_str ';'
{ if (ysp_add(_yy, Y_BASE, $2, NULL)== NULL) _YYERROR("90");
base_stmt : K_BASE identifier_ref_str stmtend
{ if (ysp_add(_yy, Y_BASE, $2, NULL)== NULL) _YYERROR("base_stmt");
clicon_debug(2,"base-stmt -> BASE identifier-ref-arg-str"); }
;
/* Feature */
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 ;"); }
| 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 '}'
{ 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 }"); }
;
@ -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 : 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"); }
;
/* Typedef */
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 '}'
{ 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 }"); }
;
@ -699,13 +706,13 @@ typedef_substmt : type_stmt { clicon_debug(2,"typedef-substmt -> type-s
/* Type */
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 ;");}
| 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 '}'
{ 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 }");}
;
@ -742,13 +749,13 @@ type_body_stmt/* numerical-restrictions */
/* range-stmt */
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 ;"); }
| 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 '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("70");
{ if (ystack_pop(_yy) < 0) _YYERROR("range_stmt");
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 : 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"); }
;
@ -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 : 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 : 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 ;"); }
| 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 '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("55");
{ if (ystack_pop(_yy) < 0) _YYERROR("length_stmt");
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_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 ;"); }
| 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 '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("58");
{ if (ystack_pop(_yy) < 0) _YYERROR("pattern_stmt");
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"); }
;
pattern_substmt : reference_stmt { clicon_debug(2,"pattern-substmt -> reference-stmt"); }
| error_message_stmt { clicon_debug(2,"pattern-substmt -> error-message-stmt");}
| unknown_stmt { clicon_debug(2,"pattern-substmt -> unknown-stmt");}
pattern_substmt : modifier_stmt { clicon_debug(2,"pattern-substmt -> modifier-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");}
| { clicon_debug(2,"pattern-substmt -> "); }
;
default_stmt : K_DEFAULT string ';'
{ if (ysp_add(_yy, Y_DEFAULT, $2, NULL)== NULL) _YYERROR("94");
modifier_stmt : K_MODIFIER string stmtend
{ 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"); }
;
/* enum-stmt */
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 ;"); }
| 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 '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("73");
{ if (ystack_pop(_yy) < 0) _YYERROR("enum_stmt");
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 -> "); }
;
path_stmt : K_PATH string ';' /* XXX: path-arg-str */
{ if (ysp_add(_yy, Y_PATH, $2, NULL)== NULL) _YYERROR("91");
path_stmt : K_PATH string stmtend /* XXX: path-arg-str */
{ if (ysp_add(_yy, Y_PATH, $2, NULL)== NULL) _YYERROR("path_stmt");
clicon_debug(2,"path-stmt -> PATH string"); }
;
require_instance_stmt : K_REQUIRE_INSTANCE bool_str ';'
{ if (ysp_add(_yy, Y_REQUIRE_INSTANCE, $2, NULL)== NULL) _YYERROR("92");
require_instance_stmt : K_REQUIRE_INSTANCE bool_str stmtend
{ if (ysp_add(_yy, Y_REQUIRE_INSTANCE, $2, NULL)== NULL) _YYERROR("require_instance_stmt");
clicon_debug(2,"require-instance-stmt -> REQUIRE-INSTANCE string"); }
;
/* bit-stmt */
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 ;"); }
| 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 '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("76");
{ if (ystack_pop(_yy) < 0) _YYERROR("bit_stmt");
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 : 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"); }
;
/* status-stmt = status-keyword sep status-arg-str XXX: current-keyword*/
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"); }
;
config_stmt : K_CONFIG bool_str ';'
{ if (ysp_add(_yy, Y_CONFIG, $2, NULL) == NULL) _YYERROR("89");
config_stmt : K_CONFIG bool_str stmtend
{ if (ysp_add(_yy, Y_CONFIG, $2, NULL) == NULL) _YYERROR("config_stmt");
clicon_debug(2,"config-stmt -> CONFIG config-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;
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 ;");}
;
presence_stmt: K_PRESENCE string ';'
presence_stmt : K_PRESENCE string stmtend
{ 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 ;");}
;
/* 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;
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 ;");}
;
/* must-stmt */
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 ;"); }
| 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 '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("79");
{ if (ystack_pop(_yy) < 0) _YYERROR("must_stmt");
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"); }
| error_app_tag_stmt { clicon_debug(2,"must-substmt -> error-app-tag-stmt"); }
| description_stmt { clicon_debug(2,"must-substmt -> description-stmt"); }
| reference_stmt { clicon_debug(2,"must-substmt -> reference-stmt"); }
| { clicon_debug(2,"must-substmt -> "); }
;
/* error-message-stmt */
error_message_stmt : K_ERROR_MESSAGE string ';'
{ if (ysp_add(_yy, Y_ERROR_MESSAGE, $2, NULL) == NULL) _YYERROR("80"); }
error_message_stmt : K_ERROR_MESSAGE string stmtend
{ 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: K_MIN_ELEMENTS integer_value_str stmtend
{ if (ysp_add(_yy, Y_MIN_ELEMENTS, $2, NULL)== NULL) _YYERROR("103");
min_elements_stmt : K_MIN_ELEMENTS integer_value_str stmtend
{ if (ysp_add(_yy, Y_MIN_ELEMENTS, $2, NULL)== NULL) _YYERROR("min_elements_stmt");
clicon_debug(2,"min-elements-stmt -> MIN-ELEMENTS integer ;");}
;
/* max-elements-stmt = max-elements-keyword ("unbounded"|integer-value)
* XXX cannot use integer-value
*/
max_elements_stmt: K_MAX_ELEMENTS string ';'
{ if (ysp_add(_yy, Y_MAX_ELEMENTS, $2, NULL)== NULL) _YYERROR("104");
max_elements_stmt : K_MAX_ELEMENTS string stmtend
{ if (ysp_add(_yy, Y_MAX_ELEMENTS, $2, NULL)== NULL) _YYERROR("max_elements_stmt");
clicon_debug(2,"max-elements-stmt -> MIN-ELEMENTS integer ;");}
;
value_stmt : K_VALUE integer_value_str ';'
{ if (ysp_add(_yy, Y_VALUE, $2, NULL) == NULL) _YYERROR("86");
value_stmt : K_VALUE integer_value_str stmtend
{ if (ysp_add(_yy, Y_VALUE, $2, NULL) == NULL) _YYERROR("value_stmt");
clicon_debug(2,"value-stmt -> VALUE integer-value"); }
;
/* Grouping */
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 '}'
{ 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 }"); }
;
@ -1006,12 +1032,12 @@ grouping_substmt : status_stmt { clicon_debug(2,"grouping-substmt -> st
/* container */
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 ;");}
| 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 '}'
{ 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 }");}
;
@ -1036,14 +1062,13 @@ container_substmt : when_stmt { clicon_debug(2,"container-substmt -> when-
| { clicon_debug(2,"container-substmt ->");}
;
/* leaf */
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 ;");}
| 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 '}'
{ 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 }");}
;
@ -1068,12 +1093,12 @@ leaf_substmt : when_stmt { clicon_debug(2,"leaf-substmt -> when-stmt
/* leaf-list */
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 ;");}
| 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 '}'
{ 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 }");}
;
@ -1097,14 +1122,13 @@ leaf_list_substmt : when_stmt { clicon_debug(2,"leaf-list-substmt -> when
| { clicon_debug(2,"leaf-list-stmt ->"); }
;
/* list */
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 ;"); }
| 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 '}'
{ 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 }"); }
;
@ -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 : 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 ;");}
;
/* unique-stmt = unique-keyword unique-arg-str */
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 ;");}
;
/* choice */
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 ;"); }
| 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 '}'
{ 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 }"); }
;
@ -1180,12 +1204,12 @@ choice_substmt : when_stmt { clicon_debug(2,"choice-substmt -> when-st
/* case */
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 ;"); }
| 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 '}'
{ 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 }"); }
;
@ -1206,23 +1230,23 @@ case_substmt : when_stmt { clicon_debug(2,"case-substmt -> when-stmt
;
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 ;"); }
| 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 '}'
{ 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 }"); }
;
/* anyxml */
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 ;"); }
| 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 '}'
{ 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 }"); }
;
@ -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 : 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 ;"); }
| 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 '}'
{ 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 }"); }
;
@ -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 : 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 ;"); }
| 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 '}'
{ 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 }"); }
;
@ -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 : 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 '}'
{ 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 }"); }
@ -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
*/
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 '}'
{ 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 }"); }
;
@ -1333,12 +1357,12 @@ augment_substmt : when_stmt { clicon_debug(2,"augment-substmt -> when-s
/* when */
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 ;"); }
| 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 '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("38");
{ if (ystack_pop(_yy) < 0) _YYERROR("when_stmt");
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_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 ;"); }
| 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 '}'
{ 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 }"); }
;
@ -1383,23 +1407,23 @@ rpc_substmt : if_feature_stmt { clicon_debug(2,"rpc-substmt -> if-feature-stm
/* action */
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 ;"); }
| 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 '}'
{ 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 }"); }
;
/* notification */
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 ;"); }
| 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 '}'
{ 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 }"); }
;
@ -1427,9 +1451,9 @@ notification_substmt : if_feature_stmt { clicon_debug(2,"notification-substmt -
*/
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 '}'
{ 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 }"); }
;
@ -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 : 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_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_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 '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("43");
{ if (ystack_pop(_yy) < 0) _YYERROR("input_stmt");
clicon_debug(2,"input-stmt -> INPUT { input-substmts }"); }
;
@ -1512,15 +1532,12 @@ input_substmt : typedef_stmt { clicon_debug(2,"input-substmt -> typedef-
/* output */
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 '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("45");
{ if (ystack_pop(_yy) < 0) _YYERROR("output_stmt");
clicon_debug(2,"output-stmt -> OUTPUT { input-substmts }"); }
;
string : qstrings { $$=$1; clicon_debug(2,"string -> qstrings (%s)", $1); }
| ustring { $$=$1; clicon_debug(2,"string -> ustring (%s)", $1); }
;
@ -1554,12 +1571,11 @@ ustring : ustring CHAR
{$$=$1; }
;
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"); }
| '/' 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"); }
;
@ -1572,7 +1588,7 @@ desc_schema_node_str : desc_schema_nodeid
desc_schema_nodeid : node_identifier
{ $$= $1; clicon_debug(2,"descendant-schema-nodeid -> node_identifier"); }
| 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;
@ -1602,7 +1618,7 @@ bool_str : '"' BOOL '"' { $$ = $2;
node_identifier : IDENTIFIER
{ $$=$1; clicon_debug(2,"identifier-ref-arg-str -> string"); }
| 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"); }
;

View file

@ -150,7 +150,7 @@ yang_type_cache_set(yang_type_cache **ycache0,
return retval;
}
/*! Get individual fields (direct/destrucively) from yang type cache. */
/*! Get individual fields (direct/destructively) from yang type cache. */
int
yang_type_cache_get(yang_type_cache *ycache,
yang_stmt **resolved,
@ -227,19 +227,17 @@ ys_resolve_type(yang_stmt *ys,
yang_stmt *resolved = NULL;
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,
&options, &mincv, &maxcv, &pattern, &fraction) < 0)
goto done;
if (resolved && strcmp(resolved->ys_argument, "union")==0)
;
/* 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,
resolved, options, mincv, maxcv, pattern, fraction) < 0)
goto done;
/* Cache the resolve locally */
if (yang_type_cache_set(&ys->ys_typecache,
resolved, options, mincv, maxcv, pattern, fraction) < 0)
goto done;
retval = 0;
done:
return retval;
@ -660,10 +658,12 @@ ys_cv_validate_union_one(yang_stmt *ys,
clicon_err(OE_UNIX, errno, "cv_new");
goto done;
}
if (cv_parse(val, cvt) <0){
if ((retval = cv_parse1(val, cvt, reason)) < 0){
clicon_err(OE_UNIX, errno, "cv_parse");
goto done;
}
if (retval == 0)
goto done;
if ((retval = cv_validate1(cvt, cvtype, options, range_min, range_max,
pattern, yrt, restype, reason)) < 0)
goto done;
@ -688,16 +688,32 @@ ys_cv_validate_union(yang_stmt *ys,
{
int retval = 1; /* valid */
yang_stmt *yt = NULL;
char *reason1 = NULL; /* saved reason */
while ((yt = yn_each((yang_node*)yrestype, yt)) != NULL){
if (yt->ys_keyword != Y_TYPE)
continue;
if ((retval = ys_cv_validate_union_one(ys, reason, yt, type, val)) < 0)
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 */
break;
}
done:
if (retval == 0 && reason1){
*reason = reason1;
reason1 = NULL;
}
if (reason1)
free(reason1);
return retval;
}
@ -908,7 +924,7 @@ resolve_restrictions(yang_stmt *yrange,
}
/*! 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[out] yrestype resolved type. return built-in type or NULL. mandatory
* @param[out] options pointer to flags field of optional values. optional
@ -945,14 +961,14 @@ yang_type_resolve(yang_stmt *ys,
char *prefix = NULL;
int retval = -1;
yang_node *yn;
yang_stmt *ymod;
yang_stmt *yrmod; /* module where resolved type is looked for */
if (options)
*options = 0x0;
*yrestype = NULL; /* Initialization of resolved type that may not be necessary */
type = yarg_id(ytype); /* This is the type to resolve */
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_type_cache_get(ytype->ys_typecache,
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 */
if (prefix){ /* Go to top and find import that matches */
if ((ymod = yang_find_module_by_prefix(ys, prefix)) == NULL){
clicon_err(OE_DB, 0, "Type not resolved: %s:%s", prefix, type);
if ((yrmod = yang_find_module_by_prefix(ytype, prefix)) == NULL){
clicon_err(OE_DB, 0, "Type not resolved: \"%s:%s\" in module %s",
prefix, type, ys_module(ys)->ys_argument);
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 */
}
else

View file

@ -78,14 +78,24 @@ expectfn(){
expect2=
fi
ret=$($cmd)
r=$?
# echo "cmd:\"$cmd\""
# echo "retval:\"$retval\""
# echo "ret:\"$ret\""
if [ $? -ne $retval ]; then
echo -e "\e[31m\nError in Test$testnr [$testname]:"
# echo "r:\"$r\""
if [ $r != $retval ]; then
echo -e "\e[31m\nError ($r != $retval) in Test$testnr [$testname]:"
echo -e "\e[0m:"
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
if [ -z "$ret" -a -z "$expect" ]; then
return

View file

@ -17,6 +17,7 @@ cat <<EOF > $cfg
<config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>$APPNAME</CLICON_YANG_MODULE_MAIN>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>

View file

@ -57,7 +57,7 @@ run(){
fi
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"
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 ""
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"
expectfn "$datastore $conf copy kalle" 0 ""

View file

@ -13,6 +13,7 @@ cat <<EOF > $cfg
<CLICON_FEATURE>ietf-routing:router-id</CLICON_FEATURE>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_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>

View file

@ -11,6 +11,7 @@ cat <<EOF > $cfg
<config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<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_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<CLICON_BACKEND_REGEXP>example_backend.so$</CLICON_BACKEND_REGEXP>

View file

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

View file

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

View file

@ -15,6 +15,7 @@ cat <<EOF > $cfg
<config>
<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_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>

View file

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

View file

@ -13,6 +13,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_MODULE_SET_ID>42</CLICON_MODULE_SET_ID>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<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"
#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"
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
# 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=../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
. ./lib.sh
# Openconfig
# Files not parseable:
# - openconfig-access-points.yang
# - openconfig-access-points.yang
new "Openconfig"
# Yang specifics: multi-keys and empty type
APPNAME=example
# include err() and new() functions and creates $dir
. ./lib.sh
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")
# Just cound nr of modules (exclude submodule)
let m=0; # Nr of modules
for f in $files; do
new "$f"
YANG=$(cat $f)
# NYI
expecteof "$PROG" 0 "$YANG" "module"
if [ -n "$(head -1 $f|grep '^module')" ]; then
let m++;
fi
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

View file

@ -26,6 +26,7 @@ cat <<EOF > $cfg
<config>
<CLICON_CONFIGFILE>/tmp/conf_yang.xml</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</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>

View file

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

View file

@ -11,6 +11,7 @@ cat <<EOF > $cfg
<config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>

View file

@ -12,6 +12,7 @@ cat <<EOF > $cfg
<config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<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_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>$dir/restconf.pidfile</CLICON_BACKEND_PIDFILE>

View file

@ -14,6 +14,7 @@ cat <<EOF > $cfg
<config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
<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)
if [ ! -x $UTIL ]; then
echo "$UTIL not found. To build: (cd ../util; make clixon_util_stream)"
exit 1
(cd ../util; make clixon_util_stream)
fi
DATE=$(date +"%Y-%m-%d")
# include err() and new() functions and creates $dir

View file

@ -7,11 +7,15 @@ APPNAME=example
cfg=$dir/conf_yang.xml
fyang=$dir/type.yang
fyang2=$dir/example2.yang
fyang3=$dir/example3.yang
cat <<EOF > $cfg
<config>
<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/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MODULE_MAIN>example</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>
@ -21,14 +25,59 @@ cat <<EOF > $cfg
<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_XMLDB_CACHE>false</CLICON_XMLDB_CACHE>
</config>
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
module example{
yang-version 1.1;
namespace "urn:example:clixon";
prefix ex;
import example2 { prefix ex2; }
typedef ab {
type string {
pattern
@ -136,6 +185,10 @@ module example{
leaf mbits{
type mybits;
}
container c{
description "transitive type- exists in ex3";
uses ex2:gr2;
}
}
EOF
@ -151,6 +204,50 @@ if [ $? -ne 0 ]; then
err
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"
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>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_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>

View file

@ -6,12 +6,16 @@ APPNAME=example
cfg=$dir/conf_yang.xml
fyang=$dir/test.yang
fsubmod=$dir/example-types.yang
fyangerr=$dir/err.yang
# <CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
cat <<EOF > $cfg
<config>
<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_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
@ -30,6 +34,7 @@ module $APPNAME{
yang-version 1.1;
prefix ex;
namespace "urn:example:clixon";
include example-types;
extension c-define {
description "Example from RFC 6020";
argument "name";
@ -85,6 +90,41 @@ module $APPNAME{
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
@ -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>]]>]]>$"
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 "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>]]>]]>$"
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"
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>]]>]]>$"
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
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"
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"
# Check if premature kill
pid=`pgrep -u root -f clixon_backend`

View file

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

View file

@ -133,11 +133,14 @@ module clixon-config {
description
"Location of configuration-file for default values (this file)";
}
leaf CLICON_YANG_DIR {
leaf-list CLICON_YANG_DIR {
type string;
mandatory true;
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 {
type string;