* Yang Configure options changed

* `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
  * CLICON_YANG_MAIN_FILE Provides a filename with a single module filename.
  * CLICON_YANG_MAIN_DIR Provides a directory where all yang modules should be loaded.
* Change all @datamodel:tree to @datamodel in all CLI specification files
  * If you generate CLI code from the model (CLIXON_CLI_GENMODEL).
  * For backward compatibility, define CLICON_CLI_MODEL_TREENAME_PATCH in clixon_custom.h
* Removed return value ymodp from yang parse functions (eg yang_parse()).
* New config option: CLICON_CLI_MODEL_TREENAME defining name of generated syntax tree if CLIXON_CLI_GENMODEL is set.
This commit is contained in:
Olof hagsand 2018-12-03 21:16:35 +01:00
parent d09a8c08aa
commit ac1aa44fc4
21 changed files with 309 additions and 140 deletions

View file

@ -12,15 +12,23 @@
* Support of submodule, include and belongs-to.
* Openconfig yang specs parsed: https://github.com/openconfig/public
* Improved unknown handling
* Configure option `CLICON_YANG_DIR` is changed from a single directory to a path of directories
* Yang Configure options changed
* `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
* CLICON_YANG_MAIN_FILE Provides a filename with a single module filename.
* CLICON_YANG_MAIN_DIR Provides a directory where all yang modules should be loaded.
### 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.
* Change all @datamodel:tree to @datamodel in all CLI specification files
* If you generate CLI code from the model (CLIXON_CLI_GENMODEL).
* For backward compatibility, define CLICON_CLI_MODEL_TREENAME_PATCH in clixon_custom.h
### Minor changes
* Removed return value ymodp from yang parse functions (eg yang_parse()).
* New config option: CLICON_CLI_MODEL_TREENAME defining name of generated syntax tree if CLIXON_CLI_GENMODEL is set.
* XML parser conformance to W3 spec
* Names lexically correct (NCName)
* Syntactically Correct handling of '<?' (processing instructions) and '<?xml' (XML declaration)

View file

@ -230,7 +230,8 @@ 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.
Clixon uses [Doxygen](http://www.doxygen.nl/index.html) for reference documentation.
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

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", NULL, yspec, NULL) < 0)
if (yang_parse(h, NULL, "ietf-netconf-acm", NULL, yspec) < 0)
goto done;
fd = fileno(f);
/* Read configfile */
@ -527,7 +527,7 @@ main(int argc,
int logdst = CLICON_LOG_SYSLOG|CLICON_LOG_STDERR;
yang_spec *yspec = NULL;
yang_spec *yspecfg = NULL; /* For config XXX clixon bug */
char *yang_filename = NULL;
char *str;
/* In the startup, logs to stderr & syslog and debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
@ -652,8 +652,8 @@ main(int argc,
case 'g': /* config socket group */
clicon_option_str_set(h, "CLICON_SOCK_GROUP", optarg);
break;
case 'y' :{ /* Load yang spec file (override yang main module) */
yang_filename = optarg;
case 'y' :{ /* Load yang absolute filename */
clicon_option_str_set(h, "CLICON_YANG_MAIN_FILE", optarg);
break;
}
case 'x' :{ /* xmldb plugin */
@ -750,17 +750,20 @@ main(int argc,
if ((yspec = yspec_new()) == NULL)
goto done;
clicon_dbspec_yang_set(h, yspec);
/* 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, yspec, NULL) < 0)
/* Load Yang modules
* 1. Load a yang module as a specific absolute filename */
if ((str = clicon_yang_main_file(h)) != NULL)
if (yang_spec_parse_file(h, str, yspec) < 0)
goto done;
}
else if (yang_spec_parse_module(h, clicon_yang_module_main(h),
clicon_yang_module_revision(h),
yspec, NULL) < 0)
/* 2. Load a (single) main module */
if ((str = clicon_yang_module_main(h)) != NULL)
if (yang_spec_parse_module(h, str, clicon_yang_module_revision(h),
yspec) < 0)
goto done;
/* 3. Load all modules in a directory */
if ((str = clicon_yang_main_dir(h)) != NULL)
if (yang_spec_load_dir(h, str, yspec) < 0)
goto done;
/* Load yang module library, RFC7895 */
if (yang_modules_init(h) < 0)
goto done;
@ -769,11 +772,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", NULL, yspec, NULL)< 0)
yang_spec_parse_module(h, "ietf-restconf-monitoring", NULL, yspec)< 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", NULL, yspec, NULL)< 0)
yang_spec_parse_module(h, "ietf-netconf-notification", NULL, yspec)< 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

@ -250,15 +250,14 @@ main(int argc, char **argv)
int logclisyntax = 0;
int help = 0;
char *treename = NULL;
int len;
// int len;
int logdst = CLICON_LOG_STDERR;
char *restarg = NULL; /* what remains after options */
int dump_configfile_xml = 0;
yang_spec *yspec;
yang_spec *yspecfg = NULL; /* For config XXX clixon bug */
struct passwd *pw;
char *yang_filename = NULL;
yang_stmt *ymod = NULL; /* Main module */
char *str;
/* Defaults */
once = 0;
@ -390,8 +389,8 @@ main(int argc, char **argv)
case 'L' : /* Debug print dynamic CLI syntax */
logclisyntax++;
break;
case 'y' :{ /* Load yang spec file (override yang main module) */
yang_filename = optarg;
case 'y' :{ /* Load yang absolute filename */
clicon_option_str_set(h, "CLICON_YANG_MAIN_FILE", optarg);
break;
}
case 'c' :{ /* Overwrite clispec with absolute filename */
@ -430,16 +429,24 @@ main(int argc, char **argv)
goto done;
clicon_dbspec_yang_set(h, yspec);
/* 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, yspec, &ymod) < 0)
/* Load Yang modules
* 1. Load a yang module as a specific absolute filename */
if ((str = clicon_yang_main_file(h)) != NULL){
if (yang_spec_parse_file(h, str, yspec) < 0)
goto done;
}
else if (yang_spec_parse_module(h, clicon_yang_module_main(h),
clicon_yang_module_revision(h),
yspec, &ymod) < 0)
/* 2. Load a (single) main module */
if ((str = clicon_yang_module_main(h)) != NULL){
if (yang_spec_parse_module(h, str, clicon_yang_module_revision(h),
yspec) < 0)
goto done;
}
/* 3. Load all modules in a directory */
if ((str = clicon_yang_main_dir(h)) != NULL){
if (yang_spec_load_dir(h, str, yspec) < 0)
goto done;
}
/* Load yang module library, RFC7895 */
if (yang_modules_init(h) < 0)
goto done;
@ -448,25 +455,22 @@ main(int argc, char **argv)
/* Create tree generated from dataspec. If no other trees exists, this is
* the only one.
* The following code creates the tree @datamodel
* This tree is referenced from the main CLI spec (CLICON_CLISPEC_DIR)
* using the "tree reference"
* syntax, ie @datamodel
* But note that yang2cli generates syntax for ALL modules, not just for
* <module>.
*/
if (clicon_cli_genmodel(h)){
parse_tree pt = {0,}; /* cli parse tree */
char *name; /* main module name */
char *treeref;
treeref = clicon_cli_model_treename(h);
/* Create cli command tree from dbspec */
if (yang2cli(h, yspec, &pt, clicon_cli_genmodel_type(h)) < 0)
goto done;
/* name of main module */
name = ymod->ys_argument;
len = strlen("datamodel:") + strlen(name) + 1;
if ((treename = malloc(len)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
snprintf(treename, len, "datamodel:%s", name);
cligen_tree_add(cli_cligen(h), treename, pt);
cligen_tree_add(cli_cligen(h), treeref, pt);
if (printgen)
cligen_print(stdout, pt, 1);

View file

@ -209,6 +209,30 @@ clixon_str2fn(char *name,
return NULL;
}
#ifdef CLICON_CLI_MODEL_TREENAME_PATCH
/*! Patch all CLI spec calls to @datamodel:tree to @datamodel.
* This is a backward compatible fix for 3.9 for CLIgen specification files
* using model generation (CLIXON_CLI_GENMODEL).
* All new references should use @datamodel (or CLICON_CLI_MODEL_TREENAME).
* whereas older code used @datamodel:tree.
*/
static int
mask_datamodel_fn(cg_obj *co,
void *arg)
{
char *str = "datamodel:";
int len = strlen(str);
if (co->co_type == CO_REFERENCE){
if (strlen(co->co_command) > len &&
strncmp(co->co_command, "datamodel:", len)==0){
co->co_command[len-1] = '\0';
}
}
return 0;
}
#endif /* CLICON_CLI_MODEL_TREENAME_PATCH */
/*! Append to syntax mode from file
* @param[in] h Clixon handle
* @param[in] filename Name of file where syntax is specified (in syntax-group dir)
@ -253,7 +277,10 @@ cli_load_syntax(clicon_handle h,
goto done;
}
fclose(f);
#ifdef CLICON_CLI_MODEL_TREENAME_PATCH
if (pt_apply(pt, mask_datamodel_fn, h) < 0)
goto done;
#endif
/* Get CLICON specific global variables */
prompt = cvec_find_str(cvv, "CLICON_PROMPT");
plgnam = cvec_find_str(cvv, "CLICON_PLUGIN");

View file

@ -341,7 +341,7 @@ main(int argc,
struct timeval tv = {0,}; /* timeout */
yang_spec *yspec = NULL;
yang_spec *yspecfg = NULL; /* For config XXX clixon bug */
char *yang_filename = NULL;
char *str;
/* Create handle */
if ((h = clicon_handle_init()) == NULL)
@ -420,7 +420,7 @@ main(int argc,
clicon_option_str_set(h, "CLICON_NETCONF_DIR", optarg);
break;
case 'y' :{ /* Load yang spec file (override yang main module) */
yang_filename = optarg;
clicon_option_str_set(h, "CLICON_YANG_MAIN_FILE", optarg);
break;
}
case 'U': /* Clixon 'pseudo' user */
@ -444,16 +444,23 @@ main(int argc,
if ((yspec = yspec_new()) == NULL)
goto done;
clicon_dbspec_yang_set(h, yspec);
/* 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, yspec, NULL) < 0)
/* Load Yang modules
* 1. Load a yang module as a specific absolute filename */
if ((str = clicon_yang_main_file(h)) != NULL){
if (yang_spec_parse_file(h, str, yspec) < 0)
goto done;
}
else if (yang_spec_parse_module(h, clicon_yang_module_main(h),
clicon_yang_module_revision(h),
yspec, NULL) < 0)
/* 2. Load a (single) main module */
if ((str = clicon_yang_module_main(h)) != NULL){
if (yang_spec_parse_module(h, str, clicon_yang_module_revision(h),
yspec) < 0)
goto done;
}
/* 3. Load all modules in a directory */
if ((str = clicon_yang_main_dir(h)) != NULL){
if (yang_spec_load_dir(h, str, yspec) < 0)
goto done;
}
/* Load yang module library, RFC7895 */
if (yang_modules_init(h) < 0)

View file

@ -522,9 +522,9 @@ main(int argc,
int logdst = CLICON_LOG_SYSLOG;
yang_spec *yspec = NULL;
yang_spec *yspecfg = NULL; /* For config XXX clixon bug */
char *yang_filename = NULL;
char *stream_path;
int finish;
char *str;
/* In the startup, logs to stderr & debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
@ -601,7 +601,7 @@ main(int argc,
clicon_option_str_set(h, "CLICON_RESTCONF_DIR", optarg);
break;
case 'y' : /* Load yang spec file (override yang main module) */
yang_filename = optarg;
clicon_option_str_set(h, "CLICON_YANG_MAIN_FILE", optarg);
break;
case 'a': /* internal backend socket address family */
clicon_option_str_set(h, "CLICON_SOCK_FAMILY", optarg);
@ -627,26 +627,34 @@ main(int argc,
if ((yspec = yspec_new()) == NULL)
goto done;
clicon_dbspec_yang_set(h, yspec);
/* 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, yspec, NULL) < 0)
/* Load Yang modules
* 1. Load a yang module as a specific absolute filename */
if ((str = clicon_yang_main_file(h)) != NULL){
if (yang_spec_parse_file(h, str, yspec) < 0)
goto done;
}
else if (yang_spec_parse_module(h, clicon_yang_module_main(h),
clicon_yang_module_revision(h),
yspec, NULL) < 0)
/* 2. Load a (single) main module */
if ((str = clicon_yang_module_main(h)) != NULL){
if (yang_spec_parse_module(h, str, clicon_yang_module_revision(h),
yspec) < 0)
goto done;
}
/* 3. Load all modules in a directory */
if ((str = clicon_yang_main_dir(h)) != NULL){
if (yang_spec_load_dir(h, str, yspec) < 0)
goto done;
}
/* Load yang module library, RFC7895 */
if (yang_modules_init(h) < 0)
goto done;
/* Add system modules */
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
yang_spec_parse_module(h, "ietf-restconf-monitoring", NULL, yspec, NULL)< 0)
yang_spec_parse_module(h, "ietf-restconf-monitoring", NULL, yspec)< 0)
goto done;
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") &&
yang_spec_parse_module(h, "ietf-netconf-notification", NULL, yspec, NULL)< 0)
yang_spec_parse_module(h, "ietf-netconf-notification", NULL, yspec)< 0)
goto done;
/* Call start function in all plugins before we go interactive
Pass all args after the standard options to plugin_start

View file

@ -195,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, yangmodule, NULL, NULL, yspec, NULL) < 0)
if (yang_parse(h, yangmodule, NULL, NULL, yspec) < 0)
goto done;
/* Set database directory option */
if (xmldb_setopt(h, "dbdir", dbdir) < 0)

View file

@ -73,8 +73,14 @@ clicon:x:1001:<user>,www-data
```
## What about reference documentation?
Clixon uses Doxygen for reference documentation.
Build using 'make doc' and aim your browser at doc/html/index.html.
Clixon uses [Doxygen](http://www.doxygen.nl/index.html) for reference documentation.
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
```
## How is configuration data stored?
Configuration data is stored in an XML datastore. In the example the
@ -115,12 +121,15 @@ 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_MAIN_DIR` - Load all yang modules in this directory.
- `CLICON_YANG_MAIN_FILE` - Load a specific Yang module fiven by a file.
- `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.
You can combine the options, however, more specific options override
less specific. For example, `CLICON_YANG_MAIN_FILE` overrides `CLICON_YANG_MODULE_MAIN`.
## How do I enable Yang features?

View file

@ -7,10 +7,10 @@ CLICON_PLUGIN="example_cli";
translate value (<value:string translate:incstr()>),cli_set("/translate/value");
# Note, when switching to PT, change datamodel to only @datamodel
set @datamodel:example, cli_set();
merge @datamodel:example, cli_merge();
create @datamodel:example, cli_create();
delete("Delete a configuration item") @datamodel:example, cli_del();
set @datamodel, cli_set();
merge @datamodel, cli_merge();
create @datamodel, cli_create();
delete("Delete a configuration item") @datamodel, cli_del();
validate("Validate changes"), cli_validate();
commit("Commit the changes"), cli_commit();
@ -40,19 +40,19 @@ show("Show a particular state of the system"){
}
configuration("Show configuration"), cli_show_config("candidate", "text", "/");{
xml("Show configuration as XML"), cli_show_config("candidate", "xml", "/");{
@datamodel:example, cli_show_auto("candidate", "text");
@datamodel, cli_show_auto("candidate", "text");
}
cli("Show configuration as CLI commands"), cli_show_config("candidate", "cli", "/");{
@datamodel:example, cli_show_auto("candidate", "cli");
@datamodel, cli_show_auto("candidate", "cli");
}
netconf("Show configuration as netconf edit-config operation"), cli_show_config("candidate", "netconf", "/");{
@datamodel:example, cli_show_auto("candidate", "netconf");
@datamodel, cli_show_auto("candidate", "netconf");
}
text("Show configuration as text"), cli_show_config("candidate","text","/");{
@datamodel:example, cli_show_auto("candidate", "text");
@datamodel, cli_show_auto("candidate", "text");
}
json("Show configuration as JSON"), cli_show_config("candidate", "json", "/");{
@datamodel:example, cli_show_auto("candidate", "json");
@datamodel, cli_show_auto("candidate", "json");
}
}
}

View file

@ -51,3 +51,15 @@ int strverscmp (__const char *__s1, __const char *__s2);
*/
#define XMLNS_YANG_ONLY 1
/* Set for full XML namespace code in XML, NETCONF and YANG
* Experimental
*/
#undef ENABLE_XMLNS
/* If set, patch all CLI spec calls to @datamodel:tree to @datamodel.
* This is a backward compatible fix for 3.9 for CLIgen specification files
* using model generation (CLIXON_CLI_GENMODEL).
* All new references should use @datamodel (or CLICON_CLI_MODEL_TREENAME).
* whereas older code used @datamodel:tree.
*/
#define CLICON_CLI_MODEL_TREENAME_PATCH

View file

@ -105,6 +105,12 @@ 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_main_file(clicon_handle h){
return clicon_option_str(h, "CLICON_YANG_MAIN_FILE");
}
static inline char *clicon_yang_main_dir(clicon_handle h){
return clicon_option_str(h, "CLICON_YANG_MAIN_DIR");
}
static inline char *clicon_yang_module_main(clicon_handle h){
return clicon_option_str(h, "CLICON_YANG_MODULE_MAIN");
}
@ -129,6 +135,9 @@ static inline char *clicon_clispec_dir(clicon_handle h){
static inline char *clicon_cli_mode(clicon_handle h){
return clicon_option_str(h, "CLICON_CLI_MODE");
}
static inline char *clicon_cli_model_treename(clicon_handle h){
return clicon_option_str(h, "CLICON_CLI_MODEL_TREENAME");
}
static inline char *clicon_sock(clicon_handle h){
return clicon_option_str(h, "CLICON_SOCK");
}

View file

@ -256,7 +256,7 @@ int yang_nodeid_split(char *nodeid, char **prefix, char **id);
yang_stmt *ys_module(yang_stmt *ys);
yang_spec *ys_spec(yang_stmt *ys);
yang_stmt *yang_find_module_by_prefix(yang_stmt *ys, char *prefix);
yang_stmt *yang_find(yang_node *yn, int keyword, char *argument);
yang_stmt *yang_find(yang_node *yn, int keyword, const char *argument);
int yang_match(yang_node *yn, int keyword, char *argument);
yang_stmt *yang_find_datanode(yang_node *yn, char *argument);
yang_stmt *yang_find_schemanode(yang_node *yn, char *argument);
@ -269,7 +269,7 @@ 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 *revision, yang_spec *ysp, yang_stmt **ymodp);
const char *revision, yang_spec *ysp);
int yang_apply(yang_node *yn, enum rfc_6020 key, yang_applyfn_t fn,
void *arg);
int yang_abs_schema_nodeid(yang_spec *yspec, yang_stmt *ys,
@ -281,8 +281,9 @@ 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 *revision, yang_spec *yspec, yang_stmt **ymodp);
int yang_spec_parse_file(clicon_handle h, char *filename, yang_spec *yspec, yang_stmt **ymodp);
int yang_spec_parse_module(clicon_handle h, char *module, char *revision, yang_spec *yspec);
int yang_spec_parse_file(clicon_handle h, char *filename, yang_spec *yspec);
int yang_spec_load_dir(clicon_handle h, char *dir, yang_spec *yspec);
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", NULL, yspec, NULL)< 0)
if (yang_spec_parse_module(h, "ietf-netconf", NULL, yspec)< 0)
goto done;
if (yang_spec_parse_module(h, "ietf-netconf-notification", NULL, yspec, NULL)< 0)
if (yang_spec_parse_module(h, "ietf-netconf-notification", NULL, yspec)< 0)
goto done;
if ((xc = clicon_conf_xml(h)) == NULL){
clicon_err(OE_CFG, ENOENT, "Clicon configuration not loaded");

View file

@ -252,7 +252,7 @@ clicon_options_main(clicon_handle h,
/* 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)
if (yang_parse(h, NULL, "clixon-config", NULL, yspec) < 0)
goto done;
clicon_conf_xml_set(h, NULL);
if (xconfig)

View file

@ -269,8 +269,7 @@ clixon_plugins_load(clicon_handle h,
clicon_debug(1, "%s", __FUNCTION__);
/* Get plugin objects names from plugin directory */
if((ndp = clicon_file_dirent(dir, &dp,
regexp?regexp:"(.so)$", S_IFREG))<0)
if((ndp = clicon_file_dirent(dir, &dp, regexp?regexp:"(.so)$", S_IFREG)) < 0)
goto done;
/* Load all plugins */
for (i = 0; i < ndp; i++) {

View file

@ -315,7 +315,7 @@ xml_parse_attr(struct xml_parse_yacc_arg *ya,
int retval = -1;
cxobj *xa;
#ifdef notyet
#ifdef ENABLE_XMLNS
if (prefix && strcmp(prefix,"xmlns")==0)
fprintf(stderr, "PrefixedAttName NCNAME:%s = %s\n", name, attval);
if (prefix==NULL && strcmp(name,"xmlns")==0)

View file

@ -56,6 +56,7 @@
#include <syslog.h>
#include <assert.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <netinet/in.h>
/* cligen */
@ -416,7 +417,7 @@ yn_each(yang_node *yn,
yang_stmt *
yang_find(yang_node *yn,
int keyword,
char *argument)
const char *argument)
{
yang_stmt *ys = NULL;
int i;
@ -1939,7 +1940,6 @@ yang_parse_find_match(clicon_handle h,
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);
@ -2278,7 +2278,6 @@ yang_merge_submodules(clicon_handle h,
* @param[in] module Name of main YANG module. Or absolute file name.
* @param[in] revision Main module revision date string or NULL
* @param[in,out] ysp Yang specification. Should have been created by caller using yspec_new
* @param[out] ymodp Yang module of first, topmost Yang module, if given.
* @retval 0 Everything OK
* @retval -1 Error encountered
* The database symbols are inserted in alphabetical order.
@ -2298,72 +2297,89 @@ yang_parse(clicon_handle h,
const char *filename,
const char *module,
const char *revision,
yang_spec *ysp,
yang_stmt **ymodp)
yang_spec *yspec)
{
int retval = -1;
yang_stmt *ymod = NULL; /* Top-level yang (sub)module */
int i;
int modnr; /* Existing number of modules */
char *base = NULL;;
/* Apply steps 2.. on new modules, ie ones after modnr. */
modnr = ysp->yp_len;
modnr = yspec->yp_len;
if (filename){
if ((ymod = yang_parse_filename(filename, ysp)) == NULL)
/* Find module, and do not load file if module already exists */
if (basename(filename) == NULL){
clicon_err(OE_YANG, errno, "No basename");
goto done;
}
else
if ((ymod = yang_parse_module(h, module, revision, ysp)) == NULL)
if ((base = strdup(basename(filename))) == NULL){
clicon_err(OE_YANG, errno, "strdup");
goto done;
}
if (index(base, '@') != NULL)
*index(base, '@') = '\0';
if (yang_find((yang_node*)yspec, Y_MODULE, base) != NULL)
goto ok;
if ((ymod = yang_parse_filename(filename, yspec)) == NULL)
goto done;
}
else {
/* Do not load module if it already exists */
if (yang_find((yang_node*)yspec, Y_MODULE, module) != NULL)
goto ok;
if ((ymod = yang_parse_module(h, module, revision, yspec)) == NULL)
goto done;
}
/* 1: Parse from text to yang parse-tree. */
/* Iterate through modules */
if (yang_parse_recurse(h, ymod, ysp) < 0)
if (yang_parse_recurse(h, ymod, yspec) < 0)
goto done;
/* 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)
for (i=modnr; i<yspec->yp_len; i++) /* XXX */
if (yang_cardinality(h, yspec->yp_stmt[i], yspec->yp_stmt[i]->ys_argument) < 0)
goto done;
/* 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)
for (i=modnr; i<yspec->yp_len; i++){
if (yspec->yp_stmt[i]->ys_keyword != Y_SUBMODULE)
continue;
}
i = 0;
while (i<ysp->yp_len){
while (i<yspec->yp_len){
int j;
if (ysp->yp_stmt[i]->ys_keyword != Y_SUBMODULE){
if (yspec->yp_stmt[i]->ys_keyword != Y_SUBMODULE){
i++;
continue;
}
if (yang_merge_submodules(h, ysp, ysp->yp_stmt[i]) < 0)
if (yang_merge_submodules(h, yspec, yspec->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--;
for (j=i; j<yspec->yp_len-1; j++)
yspec->yp_stmt[j] = yspec->yp_stmt[j+1];
yspec->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)
for (i=modnr; i<yspec->yp_len; i++) /* XXX */
if (yang_features(h, yspec->yp_stmt[i]) < 0)
goto done;
/* 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)
for (i=modnr; i<yspec->yp_len; i++)
if (yang_apply((yang_node*)yspec->yp_stmt[i], -1, ys_populate, (void*)h) < 0)
goto done;
/* 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++)
if (yang_apply((yang_node*)ysp->yp_stmt[i], Y_TYPE, ys_resolve_type, NULL) < 0)
for (i=modnr; i<yspec->yp_len; i++)
if (yang_apply((yang_node*)yspec->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
@ -2374,25 +2390,26 @@ yang_parse(clicon_handle h,
*/
/* 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)
for (i=modnr; i<yspec->yp_len; i++){
if (yang_expand((yang_node*)yspec->yp_stmt[i]) < 0)
goto done;
yang_apply((yang_node*)ysp->yp_stmt[i], -1, ys_flag_reset, (void*)YANG_FLAG_MARK);
yang_apply((yang_node*)yspec->yp_stmt[i], -1, ys_flag_reset, (void*)YANG_FLAG_MARK);
}
/* 8: Top-level augmentation of all modules XXX: only new modules? */
if (yang_augment_spec(ysp) < 0)
if (yang_augment_spec(yspec) < 0)
goto done;
/* 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)
for (i=modnr; i<yspec->yp_len; i++)
if (yang_apply((yang_node*)yspec->yp_stmt[i], -1, ys_schemanode_check, NULL) < 0)
goto done;
/* Return main module parsed in step 1 */
if (ymodp)
*ymodp = ymod;
ok:
retval = 0;
done:
if (base)
free(base);
return retval;
}
@ -2792,7 +2809,6 @@ yang_config(yang_stmt *ys)
* @param[in] dir Directory where to look for modules and sub-modules
* @param[in] revision Revision, or NULL
* @param[in,out] yspec Modules parse are added to this yangspec
* @param[out] ymodp Yang module of first, topmost Yang module, if given.
* @retval 0 OK
* @retval -1 Error
* @see yang_spec_parse_file
@ -2801,8 +2817,7 @@ int
yang_spec_parse_module(clicon_handle h,
char *module,
char *revision,
yang_spec *yspec,
yang_stmt **ymodp)
yang_spec *yspec)
{
int retval = -1;
@ -2819,7 +2834,7 @@ yang_spec_parse_module(clicon_handle h,
clicon_err(OE_YANG, EINVAL, "yang module illegal format");
goto done;
}
if (yang_parse(h, NULL, module, revision, yspec, ymodp) < 0)
if (yang_parse(h, NULL, module, revision, yspec) < 0)
goto done;
retval = 0;
done:
@ -2831,7 +2846,6 @@ yang_spec_parse_module(clicon_handle h,
* @param[in] filename Actual filename (including dir and revision)
* @param[in] dir Directory for sub-modules
* @param[in,out] yspec Modules parse are added to this yangspec
* @param[out] ymodp Yang module of first, topmost Yang module, if given.
* @retval 0 OK
* @retval -1 Error
* @see yang_spec_parse_module for yang dir,module,revision instead of actual filename
@ -2839,8 +2853,7 @@ yang_spec_parse_module(clicon_handle h,
int
yang_spec_parse_file(clicon_handle h,
char *filename,
yang_spec *yspec,
yang_stmt **ymodp)
yang_spec *yspec)
{
int retval = -1;
@ -2848,13 +2861,62 @@ yang_spec_parse_file(clicon_handle h,
clicon_err(OE_YANG, EINVAL, "yang spec is NULL");
goto done;
}
if (yang_parse(h, filename, NULL, NULL, yspec, ymodp) < 0)
if (yang_parse(h, filename, NULL, NULL, yspec) < 0)
goto done;
retval = 0;
done:
return retval;
}
/*! Load all yang modules in directory
* @param[in] h Clicon handle
* @param[in] dir Load all yang modules in this directory
* @param[in,out] yspec Modules parse are added to this yangspec
* @retval 0 OK
* @retval -1 Error
*/
int
yang_spec_load_dir(clicon_handle h,
char *dir,
yang_spec *yspec)
{
int retval = -1;
int ndp;
struct dirent *dp = NULL;
int i;
char filename[MAXPATHLEN];
char *base;
char *b;
int j;
int len;
/* Get plugin objects names from plugin directory */
if((ndp = clicon_file_dirent(dir, &dp, "(.yang)$", S_IFREG)) < 0)
goto done;
/* Load all yang files */
for (i = 0; i < ndp; i++) {
base = dp[i].d_name;
/* Entries are sorted, see if later entry exists (include @), if so skip
* this one and take last.
*/
if ((b = index(base, '@')) != NULL)
len = b-base;
else
len = strlen(base);
for (j = (i+1); j < ndp; j++)
if (strncmp(base, dp[j].d_name, len) == 0)
break;
if (j<ndp) /* exists later entry */
continue;
snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dp[i].d_name);
if (yang_parse(h, filename, NULL, NULL, yspec) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
/*! Given a yang node, translate the argument string to a cv vector
*
* @param[in] ys Yang statement

View file

@ -93,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", NULL, yspec, NULL)< 0)
if (yang_spec_parse_module(h, "ietf-yang-library", NULL, yspec)< 0)
goto done;
/* Find revision */
if (yang_modules_revision(h) == NULL){

View file

@ -5,7 +5,7 @@ APPNAME=example
. ./lib.sh
cfg=$dir/conf_yang.xml
fyang=$dir/test.yang
fyang=$dir/$APPNAME.yang
fsubmod=$dir/example-types.yang
fyangerr=$dir/err.yang

View file

@ -142,9 +142,19 @@ module clixon-config {
they appear. Ensure that CLIXON_DATADIR(default
/usr/local/share/clixon) is present in the path";
}
leaf CLICON_YANG_MAIN_FILE {
type string;
description
"If specified load a yang module in a specific absolute filename";
}
leaf CLICON_YANG_MAIN_DIR {
type string;
description
"If given, load all modules in this directory.
See also CLICON_YANG_DIR which specifies a path of dirs";
}
leaf CLICON_YANG_MODULE_MAIN {
type string;
default "clicon";
description
"Option used to construct initial yang file:
<module>[@<revision>]";
@ -224,9 +234,18 @@ module clixon-config {
type int32;
default 1;
description
"Generate code for CLI completion of existing db symbols.
Example: Add name=\"myspec\" in datamodel spec and reference
as @myspec";
"If set, generate CLI specification for CLI completion of
loaded Yang modules. This CLI tree can be accessed in CLI
spec files using the tree reference syntax (eg @datamodel).
See also CLICON_CLI_MODEL_TREENAME.";
}
leaf CLICON_CLI_MODEL_TREENAME {
type string;
default "datamodel";
description
"If CLICON_CLI_GENMODEL is set, CLI specs can reference the
model syntax using this reference.
Example: set @datamodel, cli_set();";
}
leaf CLICON_CLI_GENMODEL_COMPLETION {
type int32;