* Support of yangmodels supported, see test_yangmodels.sh
* Added -o "<option>=<value>" command-line option to all programs: backend, cli, netconf, restconf. * Ignore CR(\r) in yang files for DOS files
This commit is contained in:
parent
c7e847cd24
commit
207858e20d
26 changed files with 635 additions and 256 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
|
@ -62,7 +62,11 @@
|
||||||
* RPC method input parameters validated
|
* RPC method input parameters validated
|
||||||
* see https://github.com/clicon/clixon/issues/47
|
* see https://github.com/clicon/clixon/issues/47
|
||||||
* Support of submodule, include and belongs-to.
|
* Support of submodule, include and belongs-to.
|
||||||
* Openconfig yang specs parsed: https://github.com/openconfig/public
|
* Parsing of standard yang files supported, such as:
|
||||||
|
* https://github.com/openconfig/public - except [https://github.com/clicon/clixon/issues/60].
|
||||||
|
* See [test/test_openconfig.sh]
|
||||||
|
* https://github.com/YangModels/yang - except vendor-specific specs
|
||||||
|
* See [test/test_yangmodels.sh]
|
||||||
* Improved "unknown" handling
|
* Improved "unknown" handling
|
||||||
* More precise Yang validation and better error messages
|
* More precise Yang validation and better error messages
|
||||||
* Example: adding bad-, missing-, or unknown-element error messages, instead of operation-failed.
|
* Example: adding bad-, missing-, or unknown-element error messages, instead of operation-failed.
|
||||||
|
|
@ -77,7 +81,9 @@
|
||||||
* Recovery user "_nacm_recovery" added.
|
* Recovery user "_nacm_recovery" added.
|
||||||
* Example use is restconf PUT when NACM edit-config is permitted, then automatic commit and discard are permitted using recovery user.
|
* Example use is restconf PUT when NACM edit-config is permitted, then automatic commit and discard are permitted using recovery user.
|
||||||
* Example user changed adm1 to andy to comply with RFC8341 example
|
* Example user changed adm1 to andy to comply with RFC8341 example
|
||||||
|
* Added -o "<option>=<value>" command-line option to all programs: backend, cli, netconf, restconf.
|
||||||
|
* Any config option from file can be overrided by giving them on command-line.
|
||||||
|
|
||||||
### API changes on existing features (you may need to change your code)
|
### API changes on existing features (you may need to change your code)
|
||||||
* Stricter YANG choice validation leads to enforcement of structures like: `choice c{ mandatory true; leaf x` statements. `x` was not previously enforced.
|
* Stricter YANG choice validation leads to enforcement of structures like: `choice c{ mandatory true; leaf x` statements. `x` was not previously enforced.
|
||||||
* Many hand-crafted validation messages have been removed and replaced with generic validations, which may lead to changed rpc-error messages.
|
* Many hand-crafted validation messages have been removed and replaced with generic validations, which may lead to changed rpc-error messages.
|
||||||
|
|
@ -112,6 +118,7 @@
|
||||||
* <!DOCTYPE (ie DTD) is not supported.
|
* <!DOCTYPE (ie DTD) is not supported.
|
||||||
|
|
||||||
### Corrected Bugs
|
### Corrected Bugs
|
||||||
|
* Ignore CR(\r) in yang files for DOS files
|
||||||
* Keyword "min" (not only "max") can be used in built-in types "range" and "length" statements.
|
* Keyword "min" (not only "max") can be used in built-in types "range" and "length" statements.
|
||||||
* Support for empty yang string added, eg `default "";`
|
* Support for empty yang string added, eg `default "";`
|
||||||
* Removed CLI generation for yang notifications (and other non-data yang nodes)
|
* Removed CLI generation for yang notifications (and other non-data yang nodes)
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@
|
||||||
#include "backend_handle.h"
|
#include "backend_handle.h"
|
||||||
|
|
||||||
/* Command line options to be passed to getopt(3) */
|
/* Command line options to be passed to getopt(3) */
|
||||||
#define BACKEND_OPTS "hD:f:l:d:b:Fza:u:P:1s:c:g:y:x:" /* substitute s: for IRCc:r */
|
#define BACKEND_OPTS "hD:f:l:d:b:Fza:u:P:1s:c:g:y:x:o:"
|
||||||
|
|
||||||
#define BACKEND_LOGFILE "/usr/local/var/clixon_backend.log"
|
#define BACKEND_LOGFILE "/usr/local/var/clixon_backend.log"
|
||||||
|
|
||||||
|
|
@ -154,7 +154,8 @@ usage(clicon_handle h,
|
||||||
"\t-g <group>\tClient membership required to this group (default: %s)\n"
|
"\t-g <group>\tClient membership required to this group (default: %s)\n"
|
||||||
|
|
||||||
"\t-y <file>\tLoad yang spec file (override yang main module)\n"
|
"\t-y <file>\tLoad yang spec file (override yang main module)\n"
|
||||||
"\t-x <plugin>\tXMLDB plugin\n",
|
"\t-x <plugin>\tXMLDB plugin\n"
|
||||||
|
"\t-o \"<option>=<value>\"\tGive configuration option overriding config file (see clixon-config.yang)\n",
|
||||||
argv0,
|
argv0,
|
||||||
plgdir ? plgdir : "none",
|
plgdir ? plgdir : "none",
|
||||||
confsock ? confsock : "none",
|
confsock ? confsock : "none",
|
||||||
|
|
@ -268,7 +269,7 @@ nacm_load_external(clicon_handle h)
|
||||||
}
|
}
|
||||||
if ((yspec = yspec_new()) == NULL)
|
if ((yspec = yspec_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (yang_parse(h, NULL, "ietf-netconf-acm", NULL, yspec) < 0)
|
if (yang_spec_parse_module(h, "ietf-netconf-acm", NULL, yspec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
fd = fileno(f);
|
fd = fileno(f);
|
||||||
/* Read configfile */
|
/* Read configfile */
|
||||||
|
|
@ -701,6 +702,15 @@ main(int argc,
|
||||||
clicon_option_str_set(h, "CLICON_XMLDB_PLUGIN", optarg);
|
clicon_option_str_set(h, "CLICON_XMLDB_PLUGIN", optarg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'o':{ /* Configuration option */
|
||||||
|
char *val;
|
||||||
|
if ((val = index(optarg, '=')) == NULL)
|
||||||
|
usage(h, argv0);
|
||||||
|
*val++ = '\0';
|
||||||
|
if (clicon_option_add(h, optarg, val) < 0)
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
usage(h, argv[0]);
|
usage(h, argv[0]);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -318,7 +318,7 @@ yang2cli_var_union_one(clicon_handle h,
|
||||||
char *restype;
|
char *restype;
|
||||||
|
|
||||||
/* Resolve the sub-union type to a resolved type */
|
/* Resolve the sub-union type to a resolved type */
|
||||||
if (yang_type_resolve(ys, ytsub, /* in */
|
if (yang_type_resolve(ys, ys, ytsub, /* in */
|
||||||
&ytype, &options, /* resolved type */
|
&ytype, &options, /* resolved type */
|
||||||
&cvv, &pattern, &fraction_digits) < 0)
|
&cvv, &pattern, &fraction_digits) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -778,7 +778,7 @@ yang2cli(clicon_handle h,
|
||||||
if (yang2cli_stmt(h, ymod, cbuf, gt, 0) < 0)
|
if (yang2cli_stmt(h, ymod, cbuf, gt, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
clicon_debug(0, "%s: buf\n%s\n", __FUNCTION__, cbuf_get(cbuf));
|
clicon_debug(2, "%s: buf\n%s\n", __FUNCTION__, cbuf_get(cbuf));
|
||||||
/* Parse the buffer using cligen parser. XXX why this?*/
|
/* Parse the buffer using cligen parser. XXX why this?*/
|
||||||
if ((globals = cvec_new(0)) == NULL)
|
if ((globals = cvec_new(0)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@
|
||||||
#include "cli_handle.h"
|
#include "cli_handle.h"
|
||||||
|
|
||||||
/* Command line options to be passed to getopt(3) */
|
/* Command line options to be passed to getopt(3) */
|
||||||
#define CLI_OPTS "hD:f:xl:F:1a:u:d:m:qpGLy:c:U:"
|
#define CLI_OPTS "hD:f:xl:F:1a:u:d:m:qpGLy:c:U:o:"
|
||||||
|
|
||||||
#define CLI_LOGFILE "/tmp/clixon_cli.log"
|
#define CLI_LOGFILE "/tmp/clixon_cli.log"
|
||||||
|
|
||||||
|
|
@ -227,7 +227,8 @@ usage(clicon_handle h,
|
||||||
"\t-l <s|e|o|f<file>> \tLog on (s)yslog, std(e)rr, std(o)ut or (f)ile (stderr is default)\n"
|
"\t-l <s|e|o|f<file>> \tLog on (s)yslog, std(e)rr, std(o)ut or (f)ile (stderr is default)\n"
|
||||||
"\t-y <file>\tOverride yang spec file (dont include .yang suffix)\n"
|
"\t-y <file>\tOverride yang spec file (dont include .yang suffix)\n"
|
||||||
"\t-c <file>\tSpecify cli spec file.\n"
|
"\t-c <file>\tSpecify cli spec file.\n"
|
||||||
"\t-U <user>\tOver-ride unix user with a pseudo user for NACM.\n",
|
"\t-U <user>\tOver-ride unix user with a pseudo user for NACM.\n"
|
||||||
|
"\t-o \"<option>=<value>\"\tGive configuration option overriding config file (see clixon-config.yang)\n",
|
||||||
argv0,
|
argv0,
|
||||||
plgdir ? plgdir : "none"
|
plgdir ? plgdir : "none"
|
||||||
);
|
);
|
||||||
|
|
@ -403,6 +404,15 @@ main(int argc, char **argv)
|
||||||
if (clicon_username_set(h, optarg) < 0)
|
if (clicon_username_set(h, optarg) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
|
case 'o':{ /* Configuration option */
|
||||||
|
char *val;
|
||||||
|
if ((val = index(optarg, '=')) == NULL)
|
||||||
|
usage(h, argv0);
|
||||||
|
*val++ = '\0';
|
||||||
|
if (clicon_option_add(h, optarg, val) < 0)
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
usage(h, argv[0]);
|
usage(h, argv[0]);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@
|
||||||
#include "netconf_rpc.h"
|
#include "netconf_rpc.h"
|
||||||
|
|
||||||
/* Command line options to be passed to getopt(3) */
|
/* Command line options to be passed to getopt(3) */
|
||||||
#define NETCONF_OPTS "hD:f:l:qa:u:d:y:U:t:"
|
#define NETCONF_OPTS "hD:f:l:qa:u:d:y:U:t:o:"
|
||||||
|
|
||||||
#define NETCONF_LOGFILE "/tmp/clixon_netconf.log"
|
#define NETCONF_LOGFILE "/tmp/clixon_netconf.log"
|
||||||
|
|
||||||
|
|
@ -333,7 +333,8 @@ usage(clicon_handle h,
|
||||||
|
|
||||||
"\t-y <file>\tLoad yang spec file (override yang main module)\n"
|
"\t-y <file>\tLoad yang spec file (override yang main module)\n"
|
||||||
"\t-U <user>\tOver-ride unix user with a pseudo user for NACM.\n"
|
"\t-U <user>\tOver-ride unix user with a pseudo user for NACM.\n"
|
||||||
"\t-t <sec>\tTimeout in seconds. Quit after this time.\n",
|
"\t-t <sec>\tTimeout in seconds. Quit after this time.\n"
|
||||||
|
"\t-o \"<option>=<value>\"\tGive configuration option overriding config file (see clixon-config.yang)\n",
|
||||||
argv0,
|
argv0,
|
||||||
clicon_netconf_dir(h)
|
clicon_netconf_dir(h)
|
||||||
);
|
);
|
||||||
|
|
@ -446,7 +447,15 @@ main(int argc,
|
||||||
case 't': /* timeout in seconds */
|
case 't': /* timeout in seconds */
|
||||||
tv.tv_sec = atoi(optarg);
|
tv.tv_sec = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'o':{ /* Configuration option */
|
||||||
|
char *val;
|
||||||
|
if ((val = index(optarg, '=')) == NULL)
|
||||||
|
usage(h, argv0);
|
||||||
|
*val++ = '\0';
|
||||||
|
if (clicon_option_add(h, optarg, val) < 0)
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
usage(h, argv[0]);
|
usage(h, argv[0]);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@
|
||||||
#include "restconf_stream.h"
|
#include "restconf_stream.h"
|
||||||
|
|
||||||
/* Command line options to be passed to getopt(3) */
|
/* Command line options to be passed to getopt(3) */
|
||||||
#define RESTCONF_OPTS "hD:f:l:p:y:a:u:"
|
#define RESTCONF_OPTS "hD:f:l:p:y:a:u:o:"
|
||||||
|
|
||||||
/* RESTCONF enables deployments to specify where the RESTCONF API is
|
/* RESTCONF enables deployments to specify where the RESTCONF API is
|
||||||
located. The client discovers this by getting the "/.well-known/host-meta"
|
located. The client discovers this by getting the "/.well-known/host-meta"
|
||||||
|
|
@ -495,7 +495,8 @@ usage(clicon_handle h,
|
||||||
"\t-d <dir>\tSpecify restconf plugin directory dir (default: %s)\n"
|
"\t-d <dir>\tSpecify restconf plugin directory dir (default: %s)\n"
|
||||||
"\t-y <file>\tLoad yang spec file (override yang main module)\n"
|
"\t-y <file>\tLoad yang spec file (override yang main module)\n"
|
||||||
"\t-a UNIX|IPv4|IPv6\tInternal backend socket family\n"
|
"\t-a UNIX|IPv4|IPv6\tInternal backend socket family\n"
|
||||||
"\t-u <path|addr>\tInternal socket domain path or IP addr (see -a)\n",
|
"\t-u <path|addr>\tInternal socket domain path or IP addr (see -a)\n"
|
||||||
|
"\t-o \"<option>=<value>\"\tGive configuration option overriding config file (see clixon-config.yang)\n",
|
||||||
argv0,
|
argv0,
|
||||||
clicon_restconf_dir(h)
|
clicon_restconf_dir(h)
|
||||||
);
|
);
|
||||||
|
|
@ -611,6 +612,15 @@ main(int argc,
|
||||||
usage(h, argv[0]);
|
usage(h, argv[0]);
|
||||||
clicon_option_str_set(h, "CLICON_SOCK", optarg);
|
clicon_option_str_set(h, "CLICON_SOCK", optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'o':{ /* Configuration option */
|
||||||
|
char *val;
|
||||||
|
if ((val = index(optarg, '=')) == NULL)
|
||||||
|
usage(h, argv0);
|
||||||
|
*val++ = '\0';
|
||||||
|
if (clicon_option_add(h, optarg, val) < 0)
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
usage(h, argv[0]);
|
usage(h, argv[0]);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ main(int argc, char **argv)
|
||||||
char *plugin = NULL;
|
char *plugin = NULL;
|
||||||
char *cmd = NULL;
|
char *cmd = NULL;
|
||||||
yang_spec *yspec = NULL;
|
yang_spec *yspec = NULL;
|
||||||
char *yangmodule = NULL;
|
char *yangfilename = NULL;
|
||||||
char *dbdir = NULL;
|
char *dbdir = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
int pid;
|
int pid;
|
||||||
|
|
@ -151,7 +151,7 @@ main(int argc, char **argv)
|
||||||
case 'y': /* Yang file */
|
case 'y': /* Yang file */
|
||||||
if (!optarg)
|
if (!optarg)
|
||||||
usage(argv0);
|
usage(argv0);
|
||||||
yangmodule = optarg;
|
yangfilename = optarg;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|
@ -173,8 +173,8 @@ main(int argc, char **argv)
|
||||||
clicon_err(OE_DB, 0, "Missing dbdir -b option");
|
clicon_err(OE_DB, 0, "Missing dbdir -b option");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (yangmodule == NULL){
|
if (yangfilename == NULL){
|
||||||
clicon_err(OE_YANG, 0, "Missing yang module -m option");
|
clicon_err(OE_YANG, 0, "Missing yang filename -y option");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Load datastore plugin */
|
/* Load datastore plugin */
|
||||||
|
|
@ -187,7 +187,7 @@ main(int argc, char **argv)
|
||||||
if ((yspec = yspec_new()) == NULL)
|
if ((yspec = yspec_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
/* Parse yang spec from given file */
|
/* Parse yang spec from given file */
|
||||||
if (yang_parse(h, yangmodule, NULL, NULL, yspec) < 0)
|
if (yang_spec_parse_file(h, yangfilename, yspec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Set database directory option */
|
/* Set database directory option */
|
||||||
if (xmldb_setopt(h, "dbdir", dbdir) < 0)
|
if (xmldb_setopt(h, "dbdir", dbdir) < 0)
|
||||||
|
|
|
||||||
|
|
@ -1453,7 +1453,7 @@ main(int argc,
|
||||||
db_init(db);
|
db_init(db);
|
||||||
if ((yspec = yspec_new()) == NULL)
|
if ((yspec = yspec_new()) == NULL)
|
||||||
goto done
|
goto done
|
||||||
if (yang_parse(h, NULL, yangmod, NULL, yspec) < 0)
|
if (yang_spec_parse_module(h, yangmod, NULL, yspec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (strcmp(cmd, "get")==0){
|
if (strcmp(cmd, "get")==0){
|
||||||
if (argc < 5)
|
if (argc < 5)
|
||||||
|
|
|
||||||
|
|
@ -197,7 +197,7 @@ are included.
|
||||||
|
|
||||||
The following configuration file options control the loading of Yang files:
|
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_DIR` - A list of directories (yang dir path) where Clixon searches for module and submodules.
|
||||||
- `CLICON_YANG_MAIN_FILE` - Load a specific Yang module fiven by a file.
|
- `CLICON_YANG_MAIN_FILE` - Load a specific Yang module given 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_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.
|
- `CLICON_YANG_MODULE_REVISION` : Specifies a revision to the main module.
|
||||||
- `CLICON_YANG_MAIN_DIR` - Load all yang modules in this directory.
|
- `CLICON_YANG_MAIN_DIR` - Load all yang modules in this directory.
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,10 @@ enum startup_mode_t{
|
||||||
|
|
||||||
/* Print registry on file. For debugging. */
|
/* Print registry on file. For debugging. */
|
||||||
void clicon_option_dump(clicon_handle h, int dblevel);
|
void clicon_option_dump(clicon_handle h, int dblevel);
|
||||||
|
|
||||||
|
/* Add a clicon options overriding file setting */
|
||||||
|
int clicon_option_add(clicon_handle h, char *name, char *value);
|
||||||
|
|
||||||
/* Initialize options: set defaults, read config-file, etc */
|
/* Initialize options: set defaults, read config-file, etc */
|
||||||
int clicon_options_main(clicon_handle h, yang_spec *yspec);
|
int clicon_options_main(clicon_handle h, yang_spec *yspec);
|
||||||
|
|
||||||
|
|
@ -174,10 +178,8 @@ int clicon_dbspec_yang_set(clicon_handle h, struct yang_spec *ys);
|
||||||
cxobj * clicon_nacm_ext(clicon_handle h);
|
cxobj * clicon_nacm_ext(clicon_handle h);
|
||||||
int clicon_nacm_ext_set(clicon_handle h, cxobj *xn);
|
int clicon_nacm_ext_set(clicon_handle h, cxobj *xn);
|
||||||
|
|
||||||
#if 1 /* Temporary function until "Top-level Yang symbol cannot be called "config"" is fixed */
|
|
||||||
yang_spec * clicon_config_yang(clicon_handle h);
|
yang_spec * clicon_config_yang(clicon_handle h);
|
||||||
int clicon_config_yang_set(clicon_handle h, struct yang_spec *ys);
|
int clicon_config_yang_set(clicon_handle h, struct yang_spec *ys);
|
||||||
#endif
|
|
||||||
|
|
||||||
cxobj *clicon_conf_xml(clicon_handle h);
|
cxobj *clicon_conf_xml(clicon_handle h);
|
||||||
int clicon_conf_xml_set(clicon_handle h, cxobj *x);
|
int clicon_conf_xml_set(clicon_handle h, cxobj *x);
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,6 @@ struct yang_stmt{
|
||||||
yang_type_cache *ys_typecache; /* If ys_keyword==Y_TYPE, cache all typedef data except unions */
|
yang_type_cache *ys_typecache; /* If ys_keyword==Y_TYPE, cache all typedef data except unions */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*! top-level yang parse-tree */
|
/*! top-level yang parse-tree */
|
||||||
struct yang_spec{
|
struct yang_spec{
|
||||||
int yp_len; /* Number of children */
|
int yp_len; /* Number of children */
|
||||||
|
|
@ -269,9 +268,6 @@ int yang_print(FILE *f, yang_node *yn);
|
||||||
int yang_print_cbuf(cbuf *cb, yang_node *yn, int marginal);
|
int yang_print_cbuf(cbuf *cb, yang_node *yn, int marginal);
|
||||||
int ys_populate(yang_stmt *ys, void *arg);
|
int ys_populate(yang_stmt *ys, void *arg);
|
||||||
yang_stmt *yang_parse_file(int fd, const char *name, yang_spec *ysp);
|
yang_stmt *yang_parse_file(int fd, const char *name, yang_spec *ysp);
|
||||||
int yang_parse(clicon_handle h, const char *filename,
|
|
||||||
const char *module,
|
|
||||||
const char *revision, yang_spec *ysp);
|
|
||||||
int yang_apply(yang_node *yn, enum rfc_6020 key, yang_applyfn_t fn,
|
int yang_apply(yang_node *yn, enum rfc_6020 key, yang_applyfn_t fn,
|
||||||
void *arg);
|
void *arg);
|
||||||
int yang_abs_schema_nodeid(yang_spec *yspec, yang_stmt *ys,
|
int yang_abs_schema_nodeid(yang_spec *yspec, yang_stmt *ys,
|
||||||
|
|
@ -283,8 +279,9 @@ cg_var *ys_parse(yang_stmt *ys, enum cv_type cvtype);
|
||||||
int ys_parse_sub(yang_stmt *ys, char *extra);
|
int ys_parse_sub(yang_stmt *ys, char *extra);
|
||||||
int yang_mandatory(yang_stmt *ys);
|
int yang_mandatory(yang_stmt *ys);
|
||||||
int yang_config(yang_stmt *ys);
|
int yang_config(yang_stmt *ys);
|
||||||
int yang_spec_parse_module(clicon_handle h, char *module, char *revision, yang_spec *yspec);
|
int yang_spec_parse_module(clicon_handle h, const char *module,
|
||||||
int yang_spec_parse_file(clicon_handle h, char *filename, yang_spec *yspec);
|
const char *revision, yang_spec *yspec);
|
||||||
|
int yang_spec_parse_file(clicon_handle h, const char *filename, yang_spec *yspec);
|
||||||
int yang_spec_load_dir(clicon_handle h, char *dir, yang_spec *yspec);
|
int yang_spec_load_dir(clicon_handle h, char *dir, yang_spec *yspec);
|
||||||
cvec *yang_arg2cvec(yang_stmt *ys, char *delimi);
|
cvec *yang_arg2cvec(yang_stmt *ys, char *delimi);
|
||||||
int yang_key_match(yang_node *yn, char *name);
|
int yang_key_match(yang_node *yn, char *name);
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ int clicon_type2cv(char *type, char *rtype, enum cv_type *cvtype);
|
||||||
int yang_type_get(yang_stmt *ys, char **otype, yang_stmt **restype,
|
int yang_type_get(yang_stmt *ys, char **otype, yang_stmt **restype,
|
||||||
int *options, cvec **cvv, char **pattern,
|
int *options, cvec **cvv, char **pattern,
|
||||||
uint8_t *fraction_digits);
|
uint8_t *fraction_digits);
|
||||||
int yang_type_resolve(yang_stmt *ys, yang_stmt *ytype,
|
int yang_type_resolve(yang_stmt *yorig, yang_stmt *ys, yang_stmt *ytype,
|
||||||
yang_stmt **restype, int *options,
|
yang_stmt **restype, int *options,
|
||||||
cvec **cvv, char **pattern, uint8_t *fraction);
|
cvec **cvv, char **pattern, uint8_t *fraction);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -87,9 +87,10 @@ exp ({integer}|{real})[eE][+-]{integer}
|
||||||
%s ESCAPE
|
%s ESCAPE
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
<START>[ \t]
|
<START>[ \t]
|
||||||
<START>\n { _JY->jy_linenum++; }
|
<START>\n { _JY->jy_linenum++; }
|
||||||
<START>\r { }
|
<START>\r
|
||||||
<START><<EOF>> { return J_EOF; }
|
<START><<EOF>> { return J_EOF; }
|
||||||
<START>\{ { return *yytext; }
|
<START>\{ { return *yytext; }
|
||||||
<START>\} { return *yytext; }
|
<START>\} { return *yytext; }
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,6 @@ clicon_option_dump(clicon_handle h,
|
||||||
clicon_debug(dbglevel, "%s = NULL", keys[i]);
|
clicon_debug(dbglevel, "%s = NULL", keys[i]);
|
||||||
}
|
}
|
||||||
free(keys);
|
free(keys);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Read filename and set values to global options registry. XML variant.
|
/*! Read filename and set values to global options registry. XML variant.
|
||||||
|
|
@ -216,6 +215,42 @@ parse_configfile(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Add configuration option overriding file setting
|
||||||
|
* Add to clicon_options hash, and to clicon_conf_xml tree
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] name Name of configuration option (see clixon-config.yang)
|
||||||
|
* @param[in] value String value
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
* @see clicon_options_main For loading options from file
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clicon_option_add(clicon_handle h,
|
||||||
|
char *name,
|
||||||
|
char *value)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
clicon_hash_t *copt = clicon_options(h);
|
||||||
|
cxobj *x;
|
||||||
|
|
||||||
|
if (strcmp(name, "CLICON_FEATURE")==0 ||
|
||||||
|
strcmp(name, "CLICON_YANG_DIR")==0){
|
||||||
|
if ((x = clicon_conf_xml(h)) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (xml_parse_va(&x, NULL, "<%s>%s</%s>",
|
||||||
|
name, value, name) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (hash_add(copt,
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
strlen(value)+1) == NULL)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Parse clixon yang file. Parse XML config file. Initialize option values
|
/*! Parse clixon yang file. Parse XML config file. Initialize option values
|
||||||
*
|
*
|
||||||
* Set default options, Read config-file, Check that all values are set.
|
* Set default options, Read config-file, Check that all values are set.
|
||||||
|
|
@ -265,7 +300,7 @@ clicon_options_main(clicon_handle h,
|
||||||
/* Set clixon_conf pointer to handle */
|
/* Set clixon_conf pointer to handle */
|
||||||
clicon_conf_xml_set(h, xconfig);
|
clicon_conf_xml_set(h, xconfig);
|
||||||
/* Parse clixon yang spec */
|
/* Parse clixon yang spec */
|
||||||
if (yang_parse(h, NULL, "clixon-config", NULL, yspec) < 0)
|
if (yang_spec_parse_module(h, "clixon-config", NULL, yspec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_conf_xml_set(h, NULL);
|
clicon_conf_xml_set(h, NULL);
|
||||||
if (xconfig)
|
if (xconfig)
|
||||||
|
|
|
||||||
|
|
@ -2413,7 +2413,7 @@ yang_enum_int_value(cxobj *node,
|
||||||
goto done;
|
goto done;
|
||||||
if ((ytype = yang_find((yang_node *)ys, Y_TYPE, NULL)) == NULL)
|
if ((ytype = yang_find((yang_node *)ys, Y_TYPE, NULL)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (yang_type_resolve(ys, ytype, &yrestype,
|
if (yang_type_resolve(ys, ys, ytype, &yrestype,
|
||||||
NULL, NULL, NULL, NULL) < 0)
|
NULL, NULL, NULL, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (yrestype==NULL || strcmp(yrestype->ys_argument, "enumeration"))
|
if (yrestype==NULL || strcmp(yrestype->ys_argument, "enumeration"))
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ ncname {namestart}{namechar}*
|
||||||
|
|
||||||
<START,TEXTDECL>[ \t] ;
|
<START,TEXTDECL>[ \t] ;
|
||||||
<START,STATEA,CMNT,TEXTDECL>\n { _YA->ya_linenum++; }
|
<START,STATEA,CMNT,TEXTDECL>\n { _YA->ya_linenum++; }
|
||||||
|
<START,STATEA,CMNT,TEXTDECL>\r
|
||||||
|
|
||||||
<START>{ncname} { clixon_xml_parselval.string = strdup(yytext);
|
<START>{ncname} { clixon_xml_parselval.string = strdup(yytext);
|
||||||
return NAME; /* rather be catch-all */
|
return NAME; /* rather be catch-all */
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,16 @@
|
||||||
* Yang functions
|
* Yang functions
|
||||||
* @see https://tools.ietf.org/html/rfc6020 YANG 1.0
|
* @see https://tools.ietf.org/html/rfc6020 YANG 1.0
|
||||||
* @see https://tools.ietf.org/html/rfc7950 YANG 1.1
|
* @see https://tools.ietf.org/html/rfc7950 YANG 1.1
|
||||||
|
*
|
||||||
|
* yang_spec_parse_module
|
||||||
|
* \
|
||||||
|
* yang_spec_parse_file-> yang_parse_post->yang_parse_recurse->yang_parse_module
|
||||||
|
* \ / v
|
||||||
|
* yang_spec_load_dir ------------------------------------> yang_parse_filename
|
||||||
|
* v
|
||||||
|
* yang_parse_file
|
||||||
|
* v
|
||||||
|
* yang_parse_str
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
|
|
@ -1068,7 +1078,8 @@ ys_populate_leaf(yang_stmt *ys,
|
||||||
|
|
||||||
yparent = ys->ys_parent; /* Find parent: list/container */
|
yparent = ys->ys_parent; /* Find parent: list/container */
|
||||||
/* 1. Find type specification and set cv type accordingly */
|
/* 1. Find type specification and set cv type accordingly */
|
||||||
if (yang_type_get(ys, &type, &yrestype, &options, NULL, NULL, &fraction_digits) < 0)
|
if (yang_type_get(ys, &type, &yrestype, &options, NULL, NULL, &fraction_digits)
|
||||||
|
< 0)
|
||||||
goto done;
|
goto done;
|
||||||
restype = yrestype?yrestype->ys_argument:NULL;
|
restype = yrestype?yrestype->ys_argument:NULL;
|
||||||
if (clicon_type2cv(type, restype, &cvtype) < 0) /* This handles non-resolved also */
|
if (clicon_type2cv(type, restype, &cvtype) < 0) /* This handles non-resolved also */
|
||||||
|
|
@ -1213,7 +1224,7 @@ ys_populate_range(yang_stmt *ys,
|
||||||
clicon_err(OE_YANG, 0, "parent should be type");
|
clicon_err(OE_YANG, 0, "parent should be type");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (yang_type_resolve(ys, (yang_stmt*)yparent, &yrestype,
|
if (yang_type_resolve(ys, ys, (yang_stmt*)yparent, &yrestype,
|
||||||
&options, NULL, NULL, &fraction_digits) < 0)
|
&options, NULL, NULL, &fraction_digits) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
restype = yrestype?yrestype->ys_argument:NULL;
|
restype = yrestype?yrestype->ys_argument:NULL;
|
||||||
|
|
@ -1467,7 +1478,7 @@ ys_populate_feature(clicon_handle h,
|
||||||
cv_name_set(cv, feature);
|
cv_name_set(cv, feature);
|
||||||
cv_bool_set(cv, found);
|
cv_bool_set(cv, found);
|
||||||
if (found)
|
if (found)
|
||||||
clicon_debug(1, "%s %s:%s", __FUNCTION__, module, feature);
|
clicon_debug(2, "%s %s:%s", __FUNCTION__, module, feature);
|
||||||
ys->ys_cv = cv;
|
ys->ys_cv = cv;
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -2085,7 +2096,7 @@ yang_parse_recurse(clicon_handle h,
|
||||||
subrevision = NULL;
|
subrevision = NULL;
|
||||||
/* if already loaded, ignore, else parse the file */
|
/* if already loaded, ignore, else parse the file */
|
||||||
if (yang_find((yang_node*)ysp,
|
if (yang_find((yang_node*)ysp,
|
||||||
keyw=Y_IMPORT?Y_MODULE:Y_SUBMODULE,
|
keyw==Y_IMPORT?Y_MODULE:Y_SUBMODULE,
|
||||||
submodule) == NULL){
|
submodule) == NULL){
|
||||||
/* recursive call */
|
/* recursive call */
|
||||||
if ((subymod = yang_parse_module(h, submodule, subrevision, ysp)) == NULL)
|
if ((subymod = yang_parse_module(h, submodule, subrevision, ysp)) == NULL)
|
||||||
|
|
@ -2249,7 +2260,9 @@ yang_merge_submodules(clicon_handle h,
|
||||||
}
|
}
|
||||||
modname = yb->ys_argument;
|
modname = yb->ys_argument;
|
||||||
if ((ymod = yang_find((yang_node*)yspec, Y_MODULE, modname)) == NULL){
|
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);
|
clicon_err(OE_YANG, ENOENT, "Submodule %s is loaded before/without its main module %s (you need to load the submodule together with or after the main module)",
|
||||||
|
ysubm->ys_argument,
|
||||||
|
modname);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Move sub-module statements to modules
|
/* Move sub-module statements to modules
|
||||||
|
|
@ -2304,64 +2317,29 @@ yang_merge_submodules(clicon_handle h,
|
||||||
* yang_parse_str # Set up yacc parser and call it given a string
|
* yang_parse_str # Set up yacc parser and call it given a string
|
||||||
* clixon_yang_parseparse # Actual yang parsing using yacc
|
* clixon_yang_parseparse # Actual yang parsing using yacc
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
yang_parse(clicon_handle h,
|
yang_parse_post(clicon_handle h,
|
||||||
const char *filename,
|
yang_spec *yspec,
|
||||||
const char *module,
|
int modnr)
|
||||||
const char *revision,
|
|
||||||
yang_spec *yspec)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_stmt *ymod = NULL; /* Top-level yang (sub)module */
|
int i;
|
||||||
int i;
|
|
||||||
int modnr; /* Existing number of modules */
|
|
||||||
char *base = NULL;;
|
|
||||||
|
|
||||||
/* Apply steps 2.. on new modules, ie ones after modnr. */
|
|
||||||
modnr = yspec->yp_len;
|
|
||||||
if (filename){
|
|
||||||
/* Find module, and do not load file if module already exists */
|
|
||||||
if (basename(filename) == NULL){
|
|
||||||
clicon_err(OE_YANG, errno, "No basename");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
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. */
|
/* 1: Parse from text to yang parse-tree. */
|
||||||
/* Iterate through modules */
|
/* Iterate through modules */
|
||||||
if (yang_parse_recurse(h, ymod, yspec) < 0)
|
for (i=modnr; i<yspec->yp_len; i++)
|
||||||
goto done;
|
if (yang_parse_recurse(h, yspec->yp_stmt[i], yspec) < 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
/* 2. 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<yspec->yp_len; i++) /* XXX */
|
for (i=modnr; i<yspec->yp_len; i++)
|
||||||
if (yang_cardinality(h, yspec->yp_stmt[i], yspec->yp_stmt[i]->ys_argument) < 0)
|
if (yang_cardinality(h, yspec->yp_stmt[i], yspec->yp_stmt[i]->ys_argument) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* 3: Merge sub-modules with modules - after this step, no submodules exist
|
/* 3: Merge sub-modules with modules - after this step, no submodules exist
|
||||||
* In the merge, remove submodule headers
|
* In the merge, remove submodule headers
|
||||||
*/
|
*/
|
||||||
for (i=modnr; i<yspec->yp_len; i++){
|
i = modnr;
|
||||||
if (yspec->yp_stmt[i]->ys_keyword != Y_SUBMODULE)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
i = 0;
|
|
||||||
while (i<yspec->yp_len){
|
while (i<yspec->yp_len){
|
||||||
int j;
|
int j;
|
||||||
if (yspec->yp_stmt[i]->ys_keyword != Y_SUBMODULE){
|
if (yspec->yp_stmt[i]->ys_keyword != Y_SUBMODULE){
|
||||||
|
|
@ -2416,7 +2394,48 @@ yang_parse(clicon_handle h,
|
||||||
for (i=modnr; i<yspec->yp_len; i++)
|
for (i=modnr; i<yspec->yp_len; i++)
|
||||||
if (yang_apply((yang_node*)yspec->yp_stmt[i], -1, ys_schemanode_check, NULL) < 0)
|
if (yang_apply((yang_node*)yspec->yp_stmt[i], -1, ys_schemanode_check, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Return main module parsed in step 1 */
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Parse yang specification and its dependencies recursively given module
|
||||||
|
* @param[in] h clicon handle
|
||||||
|
* @param[in] module Module name, or absolute filename (including dir)
|
||||||
|
* @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
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
* @see yang_spec_parse_file
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
yang_spec_parse_module(clicon_handle h,
|
||||||
|
const char *module,
|
||||||
|
const char *revision,
|
||||||
|
yang_spec *yspec)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
int modnr; /* Existing number of modules */
|
||||||
|
char *base = NULL;;
|
||||||
|
|
||||||
|
if (yspec == NULL){
|
||||||
|
clicon_err(OE_YANG, EINVAL, "yang spec is NULL");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (module == NULL){
|
||||||
|
clicon_err(OE_YANG, EINVAL, "yang module not set");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* Apply steps 2.. on new modules, ie ones after modnr. */
|
||||||
|
modnr = yspec->yp_len;
|
||||||
|
/* Do not load module if it already exists */
|
||||||
|
if (yang_find((yang_node*)yspec, Y_MODULE, module) != NULL)
|
||||||
|
goto ok;
|
||||||
|
if (yang_parse_module(h, module, revision, yspec) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (yang_parse_post(h, yspec, modnr) < 0)
|
||||||
|
goto done;
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
@ -2425,6 +2444,132 @@ yang_parse(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Parse yang specification and its dependencies recursively given filename
|
||||||
|
* @param[in] h clicon handle
|
||||||
|
* @param[in] filename Actual filename (including dir and revision)
|
||||||
|
* @param[in] dir Directory for sub-modules
|
||||||
|
* @param[in,out] yspec Modules parse are added to this yangspec
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
* @see yang_spec_parse_module for yang dir,module,revision instead of
|
||||||
|
* actual filename
|
||||||
|
* @see yang_spec_load_dir For loading all files in a directory
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
yang_spec_parse_file(clicon_handle h,
|
||||||
|
const char *filename,
|
||||||
|
yang_spec *yspec)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
int modnr; /* Existing number of modules */
|
||||||
|
char *base = NULL;;
|
||||||
|
|
||||||
|
/* Apply steps 2.. on new modules, ie ones after modnr. */
|
||||||
|
modnr = yspec->yp_len;
|
||||||
|
/* Find module, and do not load file if module already exists */
|
||||||
|
if (basename(filename) == NULL){
|
||||||
|
clicon_err(OE_YANG, errno, "No basename");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
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 (yang_parse_filename(filename, yspec) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (yang_parse_post(h, yspec, modnr) < 0)
|
||||||
|
goto done;
|
||||||
|
ok:
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (base)
|
||||||
|
free(base);
|
||||||
|
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
|
||||||
|
* @see yang_spec_parse_file
|
||||||
|
*/
|
||||||
|
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 = NULL; /* filename without dir */
|
||||||
|
char *b;
|
||||||
|
int j;
|
||||||
|
int modnr;
|
||||||
|
|
||||||
|
/* Get plugin objects names from plugin directory */
|
||||||
|
if((ndp = clicon_file_dirent(dir, &dp, "(.yang)$", S_IFREG)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ndp == 0)
|
||||||
|
clicon_log(LOG_WARNING, "%s: No yang files found in %s",
|
||||||
|
__FUNCTION__, dir);
|
||||||
|
/* Apply post steps on new modules, ie ones after modnr. */
|
||||||
|
modnr = yspec->yp_len;
|
||||||
|
/* Load all yang files in dir */
|
||||||
|
for (i = 0; i < ndp; i++) {
|
||||||
|
/* base = module name [+ @rev ] + .yang */
|
||||||
|
if (base)
|
||||||
|
free(base);
|
||||||
|
if ((base = strdup(dp[i].d_name)) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
*rindex(base, '.') = '\0'; /* strip postfix .yang */
|
||||||
|
/* base = module name [+ @rev]
|
||||||
|
* if it hasnt @rev then prefer it (dont check other files w @rev)
|
||||||
|
* Otherwise see if there is a newer
|
||||||
|
*/
|
||||||
|
if ((b = index(base, '@')) != NULL){
|
||||||
|
*b = '\0';
|
||||||
|
/* base = module name */
|
||||||
|
|
||||||
|
/* Entries are sorted, see if later entry exists (include @), if so
|
||||||
|
* skip this one and take last.
|
||||||
|
* Assume file without @ is last
|
||||||
|
*/
|
||||||
|
for (j = (i+1); j < ndp; j++)
|
||||||
|
if (strncmp(base, dp[j].d_name, strlen(base)) == 0)
|
||||||
|
break;
|
||||||
|
if (j<ndp){ /* exists later entry */
|
||||||
|
clicon_debug(1, "%s skip %s", __FUNCTION__, dp[i].d_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dp[i].d_name);
|
||||||
|
/* Dont parse if already exists */
|
||||||
|
if (yang_find((yang_node*)yspec, Y_MODULE, base) != NULL ||
|
||||||
|
yang_find((yang_node*)yspec, Y_SUBMODULE, base) != NULL)
|
||||||
|
continue;
|
||||||
|
if (yang_parse_filename(filename, yspec) == NULL)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (yang_parse_post(h, yspec, modnr) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (base)
|
||||||
|
free(base);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Apply a function call recursively on all yang-stmt s recursively
|
/*! Apply a function call recursively on all yang-stmt s recursively
|
||||||
*
|
*
|
||||||
* Recursively traverse all yang-nodes in a parse-tree and apply fn(arg) for
|
* Recursively traverse all yang-nodes in a parse-tree and apply fn(arg) for
|
||||||
|
|
@ -2835,121 +2980,6 @@ yang_config(yang_stmt *ys)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Parse yang specification and its dependencies recursively given module
|
|
||||||
* @param[in] h clicon handle
|
|
||||||
* @param[in] module Module name, or absolute filename (including dir)
|
|
||||||
* @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
|
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1 Error
|
|
||||||
* @see yang_spec_parse_file
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
yang_spec_parse_module(clicon_handle h,
|
|
||||||
char *module,
|
|
||||||
char *revision,
|
|
||||||
yang_spec *yspec)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
|
|
||||||
if (yspec == NULL){
|
|
||||||
clicon_err(OE_YANG, EINVAL, "yang spec is NULL");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (module == NULL){
|
|
||||||
clicon_err(OE_YANG, EINVAL, "yang module not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* Sanity check - use yang_spec_parse_file instead */
|
|
||||||
if (strlen(module) && module[0] == '/'){
|
|
||||||
clicon_err(OE_YANG, EINVAL, "yang module illegal format");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (yang_parse(h, NULL, module, revision, yspec) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Parse yang specification and its dependencies recursively given filename
|
|
||||||
* @param[in] h clicon handle
|
|
||||||
* @param[in] filename Actual filename (including dir and revision)
|
|
||||||
* @param[in] dir Directory for sub-modules
|
|
||||||
* @param[in,out] yspec Modules parse are added to this yangspec
|
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1 Error
|
|
||||||
* @see yang_spec_parse_module for yang dir,module,revision instead of actual filename
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
yang_spec_parse_file(clicon_handle h,
|
|
||||||
char *filename,
|
|
||||||
yang_spec *yspec)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
|
|
||||||
if (yspec == NULL){
|
|
||||||
clicon_err(OE_YANG, EINVAL, "yang spec is NULL");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
/* remove duplicates: there may be cornercases that dont work, eg
|
|
||||||
* mix of revisions and not? */
|
|
||||||
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
|
/*! Given a yang node, translate the argument string to a cv vector
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -513,8 +513,12 @@ yang_cardinality(clicon_handle h,
|
||||||
continue;
|
continue;
|
||||||
/* Find entry in yang cardinality table from parent/child keyword pair */
|
/* Find entry in yang cardinality table from parent/child keyword pair */
|
||||||
if ((yc = ycard_find(pk, ck, ycplist, 1)) == NULL){
|
if ((yc = ycard_find(pk, ck, ycplist, 1)) == NULL){
|
||||||
clicon_err(OE_YANG, 0, "%s: \"%s\" is child of \"%s\", but should not be",
|
clicon_err(OE_YANG, 0, "%s: \"%s\"(%s) is child of \"%s\"(%s), but should not be",
|
||||||
modname, yang_key2str(ck), yang_key2str(pk));
|
modname,
|
||||||
|
yang_key2str(ck),
|
||||||
|
ys->ys_argument,
|
||||||
|
yang_key2str(pk),
|
||||||
|
yt->ys_argument);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,9 +103,10 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]*
|
||||||
|
|
||||||
%%
|
%%
|
||||||
/* Common tokens */
|
/* Common tokens */
|
||||||
<KEYWORD,BOOLEAN,INTEGER,STRARG,ARGUMENT,STRING>[ \t]
|
<KEYWORD,BOOLEAN,INTEGER,STRARG,STRING,ARGUMENT,UNKNOWN>[ \t]
|
||||||
<KEYWORD,STRING,UNKNOWN><<EOF>> { return MY_EOF; }
|
<KEYWORD,STRING,UNKNOWN,COMMENT2><<EOF>> { return MY_EOF; }
|
||||||
<KEYWORD,BOOLEAN,INTEGER,STRARG,STRING,COMMENT1,UNKNOWN>\n { _YY->yy_linenum++; }
|
<KEYWORD,BOOLEAN,INTEGER,STRARG,STRING,COMMENT1,UNKNOWN>\n { _YY->yy_linenum++; }
|
||||||
|
<KEYWORD,BOOLEAN,INTEGER,STRARG,STRING,COMMENT1,UNKNOWN>\r
|
||||||
<KEYWORD,STRING>"/*" { _YY->yy_lex_state = YYSTATE; BEGIN(COMMENT1); }
|
<KEYWORD,STRING>"/*" { _YY->yy_lex_state = YYSTATE; BEGIN(COMMENT1); }
|
||||||
<KEYWORD,STRING>"//" { _YY->yy_lex_state = YYSTATE; BEGIN(COMMENT2); }
|
<KEYWORD,STRING>"//" { _YY->yy_lex_state = YYSTATE; BEGIN(COMMENT2); }
|
||||||
|
|
||||||
|
|
@ -194,7 +195,8 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]*
|
||||||
|
|
||||||
<UNKNOWN>: { return *yytext; }
|
<UNKNOWN>: { return *yytext; }
|
||||||
<UNKNOWN>; { BEGIN(KEYWORD); return *yytext; }
|
<UNKNOWN>; { BEGIN(KEYWORD); return *yytext; }
|
||||||
<UNKNOWN>[ \t] { return ' '; }
|
<UNKNOWN>\" { _YY->yy_lex_string_state =UNKNOWN; BEGIN(STRINGDQ); return *yytext; }
|
||||||
|
<UNKNOWN>\{ { BEGIN(KEYWORD); return *yytext; }
|
||||||
<UNKNOWN>. { clixon_yang_parselval.string = strdup(yytext);
|
<UNKNOWN>. { clixon_yang_parselval.string = strdup(yytext);
|
||||||
return CHAR; }
|
return CHAR; }
|
||||||
|
|
||||||
|
|
@ -220,14 +222,14 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]*
|
||||||
|
|
||||||
<STRING>\{ { BEGIN(KEYWORD); return *yytext; }
|
<STRING>\{ { BEGIN(KEYWORD); return *yytext; }
|
||||||
<STRING>; { BEGIN(KEYWORD); return *yytext; }
|
<STRING>; { BEGIN(KEYWORD); return *yytext; }
|
||||||
<STRING>\" { _YY->yy_lex_string_state =STRING; BEGIN(STRINGDQ); return DQ; }
|
<STRING>\" { _YY->yy_lex_string_state =STRING; BEGIN(STRINGDQ); return *yytext; }
|
||||||
<STRING>\' { _YY->yy_lex_string_state =STRING; BEGIN(STRINGSQ); return SQ; }
|
<STRING>\' { _YY->yy_lex_string_state =STRING; BEGIN(STRINGSQ); return SQ; }
|
||||||
<STRING>\+ { return *yytext; }
|
<STRING>\+ { return *yytext; }
|
||||||
<STRING>. { clixon_yang_parselval.string = strdup(yytext);
|
<STRING>. { clixon_yang_parselval.string = strdup(yytext);
|
||||||
return CHAR;}
|
return CHAR;}
|
||||||
|
|
||||||
<STRINGDQ>\\ { _YY->yy_lex_state = STRINGDQ; BEGIN(ESCAPE); }
|
<STRINGDQ>\\ { _YY->yy_lex_state = STRINGDQ; BEGIN(ESCAPE); }
|
||||||
<STRINGDQ>\" { BEGIN(_YY->yy_lex_string_state); return DQ; }
|
<STRINGDQ>\" { BEGIN(_YY->yy_lex_string_state); return *yytext; }
|
||||||
<STRINGDQ>\n { _YY->yy_linenum++; clixon_yang_parselval.string = strdup(yytext); return CHAR;}
|
<STRINGDQ>\n { _YY->yy_linenum++; clixon_yang_parselval.string = strdup(yytext); return CHAR;}
|
||||||
<STRINGDQ>. { clixon_yang_parselval.string = strdup(yytext);
|
<STRINGDQ>. { clixon_yang_parselval.string = strdup(yytext);
|
||||||
return CHAR;}
|
return CHAR;}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
%token MY_EOF
|
%token MY_EOF
|
||||||
%token DQ /* Double quote: " */
|
|
||||||
%token SQ /* Single quote: ' */
|
%token SQ /* Single quote: ' */
|
||||||
%token <string> CHAR
|
%token <string> CHAR
|
||||||
%token <string> IDENTIFIER
|
%token <string> IDENTIFIER
|
||||||
|
|
@ -70,7 +69,8 @@
|
||||||
%type <string> integer_value_str
|
%type <string> integer_value_str
|
||||||
%type <string> identifier_ref
|
%type <string> identifier_ref
|
||||||
%type <string> abs_schema_nodeid
|
%type <string> abs_schema_nodeid
|
||||||
%type <string> desc_schema_node_str
|
%type <string> desc_schema_nodeid_strs
|
||||||
|
%type <string> desc_schema_nodeid_str
|
||||||
%type <string> desc_schema_nodeid
|
%type <string> desc_schema_nodeid
|
||||||
%type <string> node_identifier
|
%type <string> node_identifier
|
||||||
%type <string> identifier_str
|
%type <string> identifier_str
|
||||||
|
|
@ -365,19 +365,6 @@ file : module_stmt MY_EOF
|
||||||
{ clicon_debug(2,"file->submodule-stmt"); YYACCEPT; }
|
{ clicon_debug(2,"file->submodule-stmt"); YYACCEPT; }
|
||||||
;
|
;
|
||||||
|
|
||||||
/* For extensions */
|
|
||||||
unknown_stmt : ustring ':' ustring ';'
|
|
||||||
{ 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("unknwon_stmt");
|
|
||||||
if (ysp_add(_yy, Y_UNKNOWN, id, $5) == NULL){ _YYERROR("unknwon_stmt"); }
|
|
||||||
clicon_debug(2,"unknown-stmt -> ustring : ustring string");
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
/* module identifier-arg-str */
|
/* module identifier-arg-str */
|
||||||
module_stmt : K_MODULE identifier_str
|
module_stmt : K_MODULE identifier_str
|
||||||
{ if ((_YY->yy_module = ysp_add_push(_yy, Y_MODULE, $2)) == NULL) _YYERROR("module_stmt");
|
{ if ((_YY->yy_module = ysp_add_push(_yy, Y_MODULE, $2)) == NULL) _YYERROR("module_stmt");
|
||||||
|
|
@ -591,15 +578,14 @@ revision_date_stmt : K_REVISION_DATE string stmtend /* XXX date-arg-str */
|
||||||
|
|
||||||
extension_stmt : K_EXTENSION identifier_str ';'
|
extension_stmt : K_EXTENSION identifier_str ';'
|
||||||
{ if (ysp_add(_yy, Y_EXTENSION, $2, NULL) == NULL) _YYERROR("extension_stmt");
|
{ if (ysp_add(_yy, Y_EXTENSION, $2, NULL) == NULL) _YYERROR("extension_stmt");
|
||||||
clicon_debug(2,"extenstion-stmt -> EXTENSION id-arg-str ;"); }
|
clicon_debug(2,"extenstion-stmt -> EXTENSION id-str ;"); }
|
||||||
| K_EXTENSION identifier_str
|
| K_EXTENSION identifier_str
|
||||||
{ if (ysp_add_push(_yy, Y_EXTENSION, $2) == NULL) _YYERROR("extension_stmt"); }
|
{ if (ysp_add_push(_yy, Y_EXTENSION, $2) == NULL) _YYERROR("extension_stmt"); }
|
||||||
'{' extension_substmts '}'
|
'{' extension_substmts '}'
|
||||||
{ if (ystack_pop(_yy) < 0) _YYERROR("extension_stmt");
|
{ if (ystack_pop(_yy) < 0) _YYERROR("extension_stmt");
|
||||||
clicon_debug(2,"extension-stmt -> FEATURE id-arg-str { extension-substmts }"); }
|
clicon_debug(2,"extension-stmt -> EXTENSION id-str { extension-substmts }"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
/* extension substmts */
|
/* extension substmts */
|
||||||
extension_substmts : extension_substmts extension_substmt
|
extension_substmts : extension_substmts extension_substmt
|
||||||
{ clicon_debug(2,"extension-substmts -> extension-substmts extension-substmt"); }
|
{ clicon_debug(2,"extension-substmts -> extension-substmts extension-substmt"); }
|
||||||
|
|
@ -615,10 +601,28 @@ extension_substmt : argument_stmt { clicon_debug(2,"extension-substmt -> argu
|
||||||
| { clicon_debug(2,"extension-substmt -> "); }
|
| { clicon_debug(2,"extension-substmt -> "); }
|
||||||
;
|
;
|
||||||
|
|
||||||
argument_stmt : K_ARGUMENT identifier_str ';' { free($2); }
|
argument_stmt : K_ARGUMENT identifier_str ';'
|
||||||
| K_ARGUMENT identifier_str '{' yin_element_stmt1 '}' { free($2); }
|
{ if (ysp_add(_yy, Y_ARGUMENT, $2, NULL) == NULL) _YYERROR("argument_stmt");
|
||||||
|
clicon_debug(2,"argument-stmt -> ARGUMENT identifier ;"); }
|
||||||
|
| K_ARGUMENT identifier_str
|
||||||
|
{ if (ysp_add_push(_yy, Y_ARGUMENT, $2) == NULL) _YYERROR("argument_stmt"); }
|
||||||
|
'{' argument_substmts '}'
|
||||||
|
{ if (ystack_pop(_yy) < 0) _YYERROR("argument_stmt");
|
||||||
|
clicon_debug(2,"argument-stmt -> ARGUMENT { argument-substmts }"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* argument substmts */
|
||||||
|
argument_substmts : argument_substmts argument_substmt
|
||||||
|
{ clicon_debug(2,"argument-substmts -> argument-substmts argument-substmt"); }
|
||||||
|
| argument_substmt
|
||||||
|
{ clicon_debug(2,"argument-substmts -> argument-substmt"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
argument_substmt : yin_element_stmt1 { clicon_debug(2,"argument-substmt -> yin-element-stmt1");}
|
||||||
|
| unknown_stmt { clicon_debug(2,"argument-substmt -> unknown-stmt");}
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
/* Example of optional rule, eg [yin-element-stmt] */
|
/* Example of optional rule, eg [yin-element-stmt] */
|
||||||
yin_element_stmt1 : K_YIN_ELEMENT bool_str stmtend {free($2);}
|
yin_element_stmt1 : K_YIN_ELEMENT bool_str stmtend {free($2);}
|
||||||
;
|
;
|
||||||
|
|
@ -752,6 +756,8 @@ type_body_stmt/* numerical-restrictions */
|
||||||
| bit_stmt { clicon_debug(2,"type-body-stmt -> bit-stmt"); }
|
| bit_stmt { clicon_debug(2,"type-body-stmt -> bit-stmt"); }
|
||||||
/* union-specification */
|
/* union-specification */
|
||||||
| type_stmt { clicon_debug(2,"type-body-stmt -> type-stmt"); }
|
| type_stmt { clicon_debug(2,"type-body-stmt -> type-stmt"); }
|
||||||
|
/* Cisco uses this (eg Cisco-IOS-XR-sysadmin-nto-misc-set-hostname.yang) but I dont see this is in the RFC */
|
||||||
|
| unknown_stmt { clicon_debug(2,"type-body-stmt -> unknown-stmt");}
|
||||||
;
|
;
|
||||||
|
|
||||||
/* range-stmt */
|
/* range-stmt */
|
||||||
|
|
@ -1305,10 +1311,10 @@ uses_substmt : when_stmt { clicon_debug(2,"uses-substmt -> when-stmt
|
||||||
;
|
;
|
||||||
|
|
||||||
/* refine-stmt = refine-keyword sep refine-arg-str */
|
/* refine-stmt = refine-keyword sep refine-arg-str */
|
||||||
refine_stmt : K_REFINE desc_schema_node_str ';'
|
refine_stmt : K_REFINE desc_schema_nodeid_strs ';'
|
||||||
{ if (ysp_add(_yy, Y_REFINE, $2, NULL) == NULL) _YYERROR("refine_stmt");
|
{ if (ysp_add(_yy, Y_REFINE, $2, NULL) == NULL) _YYERROR("refine_stmt");
|
||||||
clicon_debug(2,"refine-stmt -> REFINE id-arg-str ;"); }
|
clicon_debug(2,"refine-stmt -> REFINE id-arg-str ;"); }
|
||||||
| K_REFINE desc_schema_node_str
|
| K_REFINE desc_schema_nodeid_strs
|
||||||
{ if (ysp_add_push(_yy, Y_REFINE, $2) == NULL) _YYERROR("refine_stmt"); }
|
{ if (ysp_add_push(_yy, Y_REFINE, $2) == NULL) _YYERROR("refine_stmt"); }
|
||||||
'{' refine_substmts '}'
|
'{' refine_substmts '}'
|
||||||
{ if (ystack_pop(_yy) < 0) _YYERROR("refine_stmt");
|
{ if (ystack_pop(_yy) < 0) _YYERROR("refine_stmt");
|
||||||
|
|
@ -1335,8 +1341,10 @@ refine_substmt : if_feature_stmt { clicon_debug(2,"refine-substmt -> if-fea
|
||||||
| { clicon_debug(2,"refine-substmt -> "); }
|
| { clicon_debug(2,"refine-substmt -> "); }
|
||||||
;
|
;
|
||||||
|
|
||||||
/* uses-augment-stmt = augment-keyword augment-arg-str */
|
/* uses-augment-stmt = augment-keyword augment-arg-str
|
||||||
uses_augment_stmt : K_AUGMENT desc_schema_node_str
|
uses_augment_stmt : K_AUGMENT desc_schema_nodeid_strs
|
||||||
|
*/
|
||||||
|
uses_augment_stmt : K_AUGMENT string
|
||||||
{ if (ysp_add_push(_yy, Y_AUGMENT, $2) == NULL) _YYERROR("uses_augment_stmt"); }
|
{ if (ysp_add_push(_yy, Y_AUGMENT, $2) == NULL) _YYERROR("uses_augment_stmt"); }
|
||||||
'{' augment_substmts '}'
|
'{' augment_substmts '}'
|
||||||
{ if (ystack_pop(_yy) < 0) _YYERROR("uses_augment_stmt");
|
{ if (ystack_pop(_yy) < 0) _YYERROR("uses_augment_stmt");
|
||||||
|
|
@ -1345,6 +1353,7 @@ uses_augment_stmt : K_AUGMENT desc_schema_node_str
|
||||||
|
|
||||||
/* augment-stmt = augment-keyword sep augment-arg-str
|
/* augment-stmt = augment-keyword sep augment-arg-str
|
||||||
* XXX abs-schema-nodeid-str is too difficult, it needs the + semantics
|
* XXX abs-schema-nodeid-str is too difficult, it needs the + semantics
|
||||||
|
augment_stmt : K_AUGMENT abs_schema_nodeid_strs
|
||||||
*/
|
*/
|
||||||
augment_stmt : K_AUGMENT string
|
augment_stmt : K_AUGMENT string
|
||||||
{ if (ysp_add_push(_yy, Y_AUGMENT, $2) == NULL) _YYERROR("augment_stmt"); }
|
{ if (ysp_add_push(_yy, Y_AUGMENT, $2) == NULL) _YYERROR("augment_stmt"); }
|
||||||
|
|
@ -1418,6 +1427,7 @@ rpc_substmt : if_feature_stmt { clicon_debug(2,"rpc-substmt -> if-feature-stm
|
||||||
| grouping_stmt { clicon_debug(2,"rpc-substmt -> grouping-stmt"); }
|
| grouping_stmt { clicon_debug(2,"rpc-substmt -> grouping-stmt"); }
|
||||||
| input_stmt { clicon_debug(2,"rpc-substmt -> input-stmt"); }
|
| input_stmt { clicon_debug(2,"rpc-substmt -> input-stmt"); }
|
||||||
| output_stmt { clicon_debug(2,"rpc-substmt -> output-stmt"); }
|
| output_stmt { clicon_debug(2,"rpc-substmt -> output-stmt"); }
|
||||||
|
| unknown_stmt { clicon_debug(2,"rpc-substmt -> unknown-stmt");}
|
||||||
| { clicon_debug(2,"rpc-substmt -> "); }
|
| { clicon_debug(2,"rpc-substmt -> "); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
@ -1481,13 +1491,147 @@ deviation_substmts : deviation_substmts deviation_substmt
|
||||||
|
|
||||||
deviation_substmt : description_stmt { clicon_debug(2,"deviation-substmt -> description-stmt"); }
|
deviation_substmt : description_stmt { clicon_debug(2,"deviation-substmt -> description-stmt"); }
|
||||||
| reference_stmt { clicon_debug(2,"deviation-substmt -> reference-stmt"); }
|
| reference_stmt { clicon_debug(2,"deviation-substmt -> reference-stmt"); }
|
||||||
| deviate_not_supported_stmt { clicon_debug(2,"deviation-substmt -> deviate-not-supported-stmt"); }
|
| deviate_stmt { clicon_debug(2,"deviation-substmt -> deviate-stmt"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
deviate_not_supported_stmt : K_DEVIATE string stmtend
|
/* RFC7950 differentiates between deviate-not-supported, deviate-add,
|
||||||
|
* deviate-replave, and deviate-delete. Here all are bundled into a single
|
||||||
|
* deviate rule. For now, until "deviate" gets supported.
|
||||||
|
*/
|
||||||
|
deviate_stmt : K_DEVIATE string ';'
|
||||||
{ if (ysp_add(_yy, Y_DEVIATE, $2, NULL) == NULL) _YYERROR("notification_stmt");
|
{ if (ysp_add(_yy, Y_DEVIATE, $2, NULL) == NULL) _YYERROR("notification_stmt");
|
||||||
clicon_debug(2,"deviate-not-supported-stmt -> DEVIATE string ;"); }
|
clicon_debug(2,"deviate-not-supported-stmt -> DEVIATE string ;"); }
|
||||||
;
|
| K_DEVIATE string
|
||||||
|
{ if (ysp_add_push(_yy, Y_DEVIATE, $2) == NULL) _YYERROR("deviate_stmt"); }
|
||||||
|
'{' deviate_substmts '}'
|
||||||
|
{ if (ystack_pop(_yy) < 0) _YYERROR("deviate_stmt");
|
||||||
|
clicon_debug(2,"deviate-stmt -> DEVIATE string { deviate-substmts }"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
/* RFC7950 differentiates between deviate-not-supported, deviate-add,
|
||||||
|
* deviate-replave, and deviate-delete. Here all are bundled into a single
|
||||||
|
* deviate-substmt rule. For now, until "deviate" gets supported.
|
||||||
|
*/
|
||||||
|
deviate_substmts : deviate_substmts deviate_substmt
|
||||||
|
{ clicon_debug(2,"deviate-substmts -> deviate-substmts deviate-substmt"); }
|
||||||
|
| deviate_substmt
|
||||||
|
{ clicon_debug(2,"deviate-substmts -> deviate-substmt"); }
|
||||||
|
;
|
||||||
|
/* Bundled */
|
||||||
|
deviate_substmt : type_stmt { clicon_debug(2,"deviate-substmt -> type-stmt"); }
|
||||||
|
| units_stmt { clicon_debug(2,"deviate-substmt -> units-stmt"); }
|
||||||
|
| must_stmt { clicon_debug(2,"deviate-substmt -> must-stmt"); }
|
||||||
|
| unique_stmt { clicon_debug(2,"deviate-substmt -> unique-stmt"); }
|
||||||
|
| default_stmt { clicon_debug(2,"deviate-substmt -> default-stmt"); }
|
||||||
|
| config_stmt { clicon_debug(2,"deviate-substmt -> config-stmt"); }
|
||||||
|
| mandatory_stmt { clicon_debug(2,"deviate-substmt -> mandatory-stmt"); }
|
||||||
|
| min_elements_stmt { clicon_debug(2,"deviate-substmt -> min-elements-stmt"); }
|
||||||
|
| max_elements_stmt { clicon_debug(2,"deviate-substmt -> max-elements-stmt"); }
|
||||||
|
| { clicon_debug(2,"deviate-substmt -> "); }
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
/* For extensions */
|
||||||
|
unknown_stmt : ustring ':' ustring ';'
|
||||||
|
{ 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("unknown_stmt");
|
||||||
|
if (ysp_add(_yy, Y_UNKNOWN, id, $4) == NULL){ _YYERROR("unknwon_stmt"); }
|
||||||
|
clicon_debug(2,"unknown-stmt -> ustring : ustring string");
|
||||||
|
}
|
||||||
|
| ustring ':' ustring
|
||||||
|
{ if (ysp_add_push(_yy, Y_UNKNOWN, NULL) == NULL) _YYERROR("unknown_stmt"); }
|
||||||
|
'{' yang_stmts '}'
|
||||||
|
{ if (ystack_pop(_yy) < 0) _YYERROR("unknown_stmt");
|
||||||
|
clicon_debug(2,"unknown-stmt -> ustring : ustring { yang-stmts }"); }
|
||||||
|
| ustring ':' ustring string
|
||||||
|
{ if (ysp_add_push(_yy, Y_UNKNOWN, NULL) == NULL) _YYERROR("unknown_stmt"); }
|
||||||
|
'{' yang_stmts '}'
|
||||||
|
{ if (ystack_pop(_yy) < 0) _YYERROR("unknown_stmt");
|
||||||
|
clicon_debug(2,"unknown-stmt -> ustring : ustring string { yang-stmts }"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
yang_stmts : yang_stmts yang_stmt { clicon_debug(2,"yang-stmts -> yang-stmts yang-stmt"); }
|
||||||
|
| yang_stmt { clicon_debug(2,"yang-stmts -> yang-stmt");}
|
||||||
|
;
|
||||||
|
|
||||||
|
yang_stmt : action_stmt { clicon_debug(2,"yang-stmt -> action-stmt");}
|
||||||
|
| anydata_stmt { clicon_debug(2,"yang-stmt -> anydata-stmt");}
|
||||||
|
| anyxml_stmt { clicon_debug(2,"yang-stmt -> anyxml-stmt");}
|
||||||
|
| argument_stmt { clicon_debug(2,"yang-stmt -> argument-stmt");}
|
||||||
|
| augment_stmt { clicon_debug(2,"yang-stmt -> augment-stmt");}
|
||||||
|
| base_stmt { clicon_debug(2,"yang-stmt -> base-stmt");}
|
||||||
|
| bit_stmt { clicon_debug(2,"yang-stmt -> bit-stmt");}
|
||||||
|
| case_stmt { clicon_debug(2,"yang-stmt -> case-stmt");}
|
||||||
|
| choice_stmt { clicon_debug(2,"yang-stmt -> choice-stmt");}
|
||||||
|
| config_stmt { clicon_debug(2,"yang-stmt -> config-stmt");}
|
||||||
|
| contact_stmt { clicon_debug(2,"yang-stmt -> contact-stmt");}
|
||||||
|
| container_stmt { clicon_debug(2,"yang-stmt -> container-stmt");}
|
||||||
|
| default_stmt { clicon_debug(2,"yang-stmt -> default-stmt");}
|
||||||
|
| description_stmt { clicon_debug(2,"yang-stmt -> description-stmt");}
|
||||||
|
| deviate_stmt { clicon_debug(2,"yang-stmt -> deviate-stmt");}
|
||||||
|
/* deviate is not yet implemented, the above may be replaced by the following lines
|
||||||
|
| deviate_add_stmt { clicon_debug(2,"yang-stmt -> deviate-add-stmt");}
|
||||||
|
| deviate_delete_stmt { clicon_debug(2,"yang-stmt -> deviate-add-stmt");}
|
||||||
|
| deviate_replace_stmt { clicon_debug(2,"yang-stmt -> deviate-add-stmt");}
|
||||||
|
*/
|
||||||
|
| deviation_stmt { clicon_debug(2,"yang-stmt -> deviation-stmt");}
|
||||||
|
| enum_stmt { clicon_debug(2,"yang-stmt -> enum-stmt");}
|
||||||
|
| error_app_tag_stmt { clicon_debug(2,"yang-stmt -> error-app-tag-stmt");}
|
||||||
|
| error_message_stmt { clicon_debug(2,"yang-stmt -> error-message-stmt");}
|
||||||
|
| extension_stmt { clicon_debug(2,"yang-stmt -> extension-stmt");}
|
||||||
|
| feature_stmt { clicon_debug(2,"yang-stmt -> feature-stmt");}
|
||||||
|
| fraction_digits_stmt { clicon_debug(2,"yang-stmt -> fraction-digits-stmt");}
|
||||||
|
| grouping_stmt { clicon_debug(2,"yang-stmt -> grouping-stmt");}
|
||||||
|
| identity_stmt { clicon_debug(2,"yang-stmt -> identity-stmt");}
|
||||||
|
| if_feature_stmt { clicon_debug(2,"yang-stmt -> if-feature-stmt");}
|
||||||
|
| import_stmt { clicon_debug(2,"yang-stmt -> import-stmt");}
|
||||||
|
| include_stmt { clicon_debug(2,"yang-stmt -> include-stmt");}
|
||||||
|
| input_stmt { clicon_debug(2,"yang-stmt -> input-stmt");}
|
||||||
|
| key_stmt { clicon_debug(2,"yang-stmt -> key-stmt");}
|
||||||
|
| leaf_list_stmt { clicon_debug(2,"yang-stmt -> leaf-list-stmt");}
|
||||||
|
| leaf_stmt { clicon_debug(2,"yang-stmt -> leaf-stmt");}
|
||||||
|
| length_stmt { clicon_debug(2,"yang-stmt -> length-stmt");}
|
||||||
|
| list_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| mandatory_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| max_elements_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| min_elements_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| modifier_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| module_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| must_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| namespace_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| notification_stmt { clicon_debug(2,"yang-stmt -> notification-stmt");}
|
||||||
|
| ordered_by_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| organization_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| output_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| path_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| pattern_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| position_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| prefix_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| presence_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| range_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| reference_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| refine_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| require_instance_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| revision_date_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| revision_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| rpc_stmt { clicon_debug(2,"yang-stmt -> rpc-stmt");}
|
||||||
|
| status_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| submodule_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| typedef_stmt { clicon_debug(2,"yang-stmt -> typedef-stmt");}
|
||||||
|
| type_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| unique_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| units_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| uses_augment_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| uses_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| value_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| when_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
| yang_version_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
|
||||||
|
/* | yin_element_stmt { clicon_debug(2,"yang-stmt -> list-stmt");} */
|
||||||
|
;
|
||||||
|
|
||||||
/* body */
|
/* body */
|
||||||
body_stmts : body_stmts body_stmt { clicon_debug(2,"body-stmts -> body-stmts body-stmt"); }
|
body_stmts : body_stmts body_stmt { clicon_debug(2,"body-stmts -> body-stmts body-stmt"); }
|
||||||
|
|
@ -1571,8 +1715,8 @@ qstrings : qstrings '+' qstring
|
||||||
{ $$=$1; clicon_debug(2,"qstrings-> qstring"); }
|
{ $$=$1; clicon_debug(2,"qstrings-> qstring"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
qstring : DQ ustring DQ { $$=$2; clicon_debug(2,"string-> \" ustring \"");}
|
qstring : '"' ustring '"' { $$=$2; clicon_debug(2,"string-> \" ustring \"");}
|
||||||
| DQ DQ { $$=strdup(""); clicon_debug(2,"string-> \" \"");}
|
| '"' '"' { $$=strdup(""); clicon_debug(2,"string-> \" \"");}
|
||||||
| SQ ustring SQ { $$=$2; clicon_debug(2,"string-> ' ustring '"); }
|
| SQ ustring SQ { $$=$2; clicon_debug(2,"string-> ' ustring '"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
@ -1596,12 +1740,25 @@ abs_schema_nodeid : abs_schema_nodeid '/' node_identifier
|
||||||
clicon_debug(2,"absolute-schema-nodeid -> / node-identifier"); }
|
clicon_debug(2,"absolute-schema-nodeid -> / node-identifier"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
desc_schema_node_str : desc_schema_nodeid
|
desc_schema_nodeid_strs : desc_schema_nodeid_strs '+' desc_schema_nodeid_str
|
||||||
{ $$=$1; clicon_debug(2,"descendant-schema-node-str -> descendant-node"); }
|
{
|
||||||
|
int len = strlen($1);
|
||||||
|
$$ = realloc($1, len + strlen($3) + 1);
|
||||||
|
sprintf($$+len, "%s", $3);
|
||||||
|
free($3);
|
||||||
|
clicon_debug(2,"desc-schema-nodeid-strs-> desc-schema-nodeid-strs + desc-schema-nodeid-str");
|
||||||
|
}
|
||||||
|
| desc_schema_nodeid_str
|
||||||
|
{ $$=$1; clicon_debug(2,"desc-schema-nodeid-strs-> desc-schema-nodeid-str"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
desc_schema_nodeid_str : desc_schema_nodeid
|
||||||
|
{ $$=$1; clicon_debug(2,"descendant-schema-nodeid-str -> descendant-schema-nodeid"); }
|
||||||
| '"' desc_schema_nodeid '"'
|
| '"' desc_schema_nodeid '"'
|
||||||
{ $$=$2; clicon_debug(2,"descendant-schema-node-str -> descendant-node"); }
|
{ $$=$2; clicon_debug(2,"descendant-schema-nodeid-str -> descendant-schema-nodeid"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* descendant-schema-nodeid */
|
||||||
desc_schema_nodeid : node_identifier
|
desc_schema_nodeid : node_identifier
|
||||||
{ $$= $1; clicon_debug(2,"descendant-schema-nodeid -> node_identifier"); }
|
{ $$= $1; clicon_debug(2,"descendant-schema-nodeid -> node_identifier"); }
|
||||||
| node_identifier abs_schema_nodeid
|
| node_identifier abs_schema_nodeid
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,8 @@ ys_resolve_type(yang_stmt *ys,
|
||||||
/* Recursively resolve ys -> resolve with restrictions(options, etc)
|
/* Recursively resolve ys -> resolve with restrictions(options, etc)
|
||||||
* Note that the resolved type could be ys itself.
|
* Note that the resolved type could be ys itself.
|
||||||
*/
|
*/
|
||||||
if (yang_type_resolve((yang_stmt*)ys->ys_parent, ys, &resolved,
|
if (yang_type_resolve((yang_stmt*)ys->ys_parent, (yang_stmt*)ys->ys_parent,
|
||||||
|
ys, &resolved,
|
||||||
&options, &cvv, &pattern, &fraction) < 0)
|
&options, &cvv, &pattern, &fraction) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
|
@ -328,7 +329,7 @@ cv2yang_type(enum cv_type cv_type)
|
||||||
* to find special cligen types such as ipv4addr.
|
* to find special cligen types such as ipv4addr.
|
||||||
* not true yang types
|
* not true yang types
|
||||||
* @param[in] origtype Name of original type
|
* @param[in] origtype Name of original type
|
||||||
* @param[in] restype Resolved type. may be null, in that case origtype is used
|
* @param[in] restype Resolved type. May be null, in that case origtype is used
|
||||||
* @param[out] cvtype Translation from resolved type
|
* @param[out] cvtype Translation from resolved type
|
||||||
* @note Thereis a kludge for handling direct translations of native cligen types
|
* @note Thereis a kludge for handling direct translations of native cligen types
|
||||||
*/
|
*/
|
||||||
|
|
@ -343,7 +344,7 @@ clicon_type2cv(char *origtype,
|
||||||
if (restype != NULL){
|
if (restype != NULL){
|
||||||
yang2cv_type(restype, cvtype);
|
yang2cv_type(restype, cvtype);
|
||||||
if (*cvtype == CGV_ERR){
|
if (*cvtype == CGV_ERR){
|
||||||
clicon_err(OE_DB, 0, "\"%s\" type not translated", restype);
|
clicon_err(OE_YANG, EINVAL, "\"%s\" type not translated", restype);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -354,7 +355,7 @@ clicon_type2cv(char *origtype,
|
||||||
*/
|
*/
|
||||||
yang2cv_type(origtype, cvtype);
|
yang2cv_type(origtype, cvtype);
|
||||||
if (*cvtype == CGV_ERR){
|
if (*cvtype == CGV_ERR){
|
||||||
clicon_err(OE_DB, 0, "\"%s\": type not resolved", origtype);
|
clicon_err(OE_YANG, EINVAL, "\"%s\": type not resolved", origtype);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -601,7 +602,7 @@ ys_cv_validate_union_one(yang_stmt *ys,
|
||||||
enum cv_type cvtype;
|
enum cv_type cvtype;
|
||||||
cg_var *cvt=NULL;
|
cg_var *cvt=NULL;
|
||||||
|
|
||||||
if (yang_type_resolve(ys, yt, &yrt, &options, &cvv, &pattern,
|
if (yang_type_resolve(ys, ys, yt, &yrt, &options, &cvv, &pattern,
|
||||||
&fraction) < 0)
|
&fraction) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
restype = yrt?yrt->ys_argument:NULL;
|
restype = yrt?yrt->ys_argument:NULL;
|
||||||
|
|
@ -888,7 +889,8 @@ resolve_restrictions(yang_stmt *yrange,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Recursively resolve a yang type to built-in type with optional restrictions
|
/*! Recursively resolve a yang type to built-in type with optional restrictions
|
||||||
* @param[in] ys (original) type yang-stmt where the current search is based
|
* @param[in] yorig (original) type yang-stmt where original search is based
|
||||||
|
* @param[in] ys (transitive) yang-stmt where current search is based
|
||||||
* @param[in] ytype yang-stmt object containing currently resolving type
|
* @param[in] ytype yang-stmt object containing currently resolving type
|
||||||
* @param[out] yrestype resolved type. return built-in type or NULL. mandatory
|
* @param[out] yrestype resolved type. return built-in type or NULL. mandatory
|
||||||
* @param[out] options pointer to flags field of optional values. optional
|
* @param[out] options pointer to flags field of optional values. optional
|
||||||
|
|
@ -906,7 +908,8 @@ resolve_restrictions(yang_stmt *yrange,
|
||||||
* Note also that for all pointer arguments, if NULL is given, no value is assigned.
|
* Note also that for all pointer arguments, if NULL is given, no value is assigned.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
yang_type_resolve(yang_stmt *ys,
|
yang_type_resolve(yang_stmt *yorig,
|
||||||
|
yang_stmt *ys,
|
||||||
yang_stmt *ytype,
|
yang_stmt *ytype,
|
||||||
yang_stmt **yrestype,
|
yang_stmt **yrestype,
|
||||||
int *options,
|
int *options,
|
||||||
|
|
@ -938,6 +941,7 @@ yang_type_resolve(yang_stmt *ys,
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
|
/* Resolving type restrictions */
|
||||||
yrange = yang_find((yang_node*)ytype, Y_RANGE, NULL);
|
yrange = yang_find((yang_node*)ytype, Y_RANGE, NULL);
|
||||||
ylength = yang_find((yang_node*)ytype, Y_LENGTH, NULL);
|
ylength = yang_find((yang_node*)ytype, Y_LENGTH, NULL);
|
||||||
ypattern = yang_find((yang_node*)ytype, Y_PATTERN, NULL);
|
ypattern = yang_find((yang_node*)ytype, Y_PATTERN, NULL);
|
||||||
|
|
@ -955,11 +959,12 @@ yang_type_resolve(yang_stmt *ys,
|
||||||
if (prefix){ /* Go to top and find import that matches */
|
if (prefix){ /* Go to top and find import that matches */
|
||||||
if ((yrmod = yang_find_module_by_prefix(ytype, prefix)) == NULL){
|
if ((yrmod = yang_find_module_by_prefix(ytype, prefix)) == NULL){
|
||||||
clicon_err(OE_DB, 0, "Type not resolved: \"%s:%s\" in module %s",
|
clicon_err(OE_DB, 0, "Type not resolved: \"%s:%s\" in module %s",
|
||||||
prefix, type, ys_module(ys)->ys_argument);
|
prefix, type, ys_module(yorig)->ys_argument);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((rytypedef = yang_find((yang_node*)yrmod, Y_TYPEDEF, type)) == NULL)
|
if ((rytypedef = yang_find((yang_node*)yrmod, Y_TYPEDEF, type)) == NULL)
|
||||||
goto ok; /* unresolved */
|
goto ok; /* unresolved */
|
||||||
|
ys = rytypedef;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
while (1){
|
while (1){
|
||||||
|
|
@ -984,7 +989,7 @@ yang_type_resolve(yang_stmt *ys,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* recursively resolve this new type */
|
/* recursively resolve this new type */
|
||||||
if (yang_type_resolve(ys, rytype, yrestype,
|
if (yang_type_resolve(yorig, ys, rytype, yrestype,
|
||||||
options, cvv, pattern, fraction) < 0)
|
options, cvv, pattern, fraction) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* overwrites the resolved if any */
|
/* overwrites the resolved if any */
|
||||||
|
|
@ -1060,7 +1065,7 @@ yang_type_get(yang_stmt *ys,
|
||||||
type = yarg_id(ytype);
|
type = yarg_id(ytype);
|
||||||
if (origtype)
|
if (origtype)
|
||||||
*origtype = type;
|
*origtype = type;
|
||||||
if (yang_type_resolve(ys, ytype, yrestype,
|
if (yang_type_resolve(ys, ys, ytype, yrestype,
|
||||||
options, cvv, pattern, fraction) < 0)
|
options, cvv, pattern, fraction) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_debug(3, "%s: %s %s->%s", __FUNCTION__, ys->ys_argument, type,
|
clicon_debug(3, "%s: %s %s->%s", __FUNCTION__, ys->ys_argument, type,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,10 @@
|
||||||
|
|
||||||
#set -e
|
#set -e
|
||||||
|
|
||||||
|
if [ -x ./site.sh ]; then
|
||||||
|
. ./site.sh
|
||||||
|
fi
|
||||||
|
|
||||||
testnr=0
|
testnr=0
|
||||||
testname=
|
testname=
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Parse yang openconfig tests
|
# Parse yang openconfig yangs from https://github.com/openconfig/public
|
||||||
# Note that the openconfig test suites are patched to counter CLixon issues as follows:
|
# Notes:
|
||||||
# - release/models/mpls/openconfig-mpls-te.yang
|
# - 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
|
# issue: https://github.com/clicon/clixon/issues/60
|
||||||
|
# - Env variable YANGMODELS should point to checkout place. (define it in site.sh for example)
|
||||||
|
|
||||||
# Yang specifics: multi-keys and empty type
|
|
||||||
APPNAME=example
|
APPNAME=example
|
||||||
|
|
||||||
# include err() and new() functions and creates $dir
|
# include err() and new() functions and creates $dir
|
||||||
|
|
|
||||||
91
test/test_yangmodels.sh
Executable file
91
test/test_yangmodels.sh
Executable file
|
|
@ -0,0 +1,91 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Parse yangmodels from https://github.com/YangModels/yang
|
||||||
|
# Notes:
|
||||||
|
# - Env variable YANGMODELS should point to checkout place. (define it in site.sh for example)
|
||||||
|
# - Only cisco/nx/9.2-2 # Many other versions
|
||||||
|
# - Only cisco/xe/1631 # Many other versions
|
||||||
|
# - Only cisco/xr/530 # Many other versions
|
||||||
|
# - Only juniper/18.2/18.2R/junos # Many other versions and platoforms
|
||||||
|
|
||||||
|
# These are the test scripts:
|
||||||
|
#./experimental/ieee/check.sh
|
||||||
|
#./standard/ieee/check.sh
|
||||||
|
#./standard/ietf/check.sh
|
||||||
|
#./vendor/cisco/xr/check.sh
|
||||||
|
#./vendor/cisco/check.sh
|
||||||
|
#./vendor/cisco/xe/check.sh
|
||||||
|
#./vendor/cisco/nx/check.sh
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
if [ ! -d "$YANGMODELS" ]; then
|
||||||
|
err "Hmm Yangmodels dir does not seem to exist, try git clone https://github.com/YangModels/yang?"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Experimental IEEE
|
||||||
|
cat <<EOF > $cfg
|
||||||
|
<config>
|
||||||
|
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||||
|
<CLICON_YANG_DIR>$YANGMODELS/standard/ietf/RFC</CLICON_YANG_DIR>
|
||||||
|
<CLICON_YANG_DIR>$YANGMODELS/standard/ieee/draft</CLICON_YANG_DIR>
|
||||||
|
<CLICON_YANG_DIR>$YANGMODELS/standard/ieee/802.1/draft</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_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
|
||||||
|
|
||||||
|
new "yangmodels parse: -f $cfg"
|
||||||
|
|
||||||
|
new "yangmodel Experimental IEEE 802.1: $YANGMODELS/experimental/ieee/802.1"
|
||||||
|
expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/experimental/ieee/802.1 -o CLICON_YANG_DIR=$YANGMODELS/experimental/ieee/1588 show version" 0 "3."
|
||||||
|
|
||||||
|
# experimental 802.3 dir is empty
|
||||||
|
#new "yangmodel Experimental IEEE 802.3: $YANGMODELS/experimental/ieee/802.3"
|
||||||
|
#expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/experimental/ieee/802.3 show version" 0 "3."
|
||||||
|
|
||||||
|
new "yangmodel Experimental IEEE 1588: $YANGMODELS/experimental/ieee/1588"
|
||||||
|
expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/experimental/ieee/1588 show version" 0 "3."
|
||||||
|
|
||||||
|
# Standard IEEE
|
||||||
|
new "yangmodel Standard IEEE 802.1: $YANGMODELS/standard/ieee/802.1/draft"
|
||||||
|
expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/standard/ieee/802.1/draft show version" 0 "3."
|
||||||
|
|
||||||
|
new "yangmodel Standard IEEE 802.3: $YANGMODELS/standard/ieee/802.3/draft"
|
||||||
|
expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/standard/ieee/802.3/draft show version" 0 "3."
|
||||||
|
|
||||||
|
# Standard IETF
|
||||||
|
new "yangmodel Standard IETF: $YANGMODELS/standard/ietf/RFC"
|
||||||
|
expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/standard/ietf/RFC show version" 0 "3."
|
||||||
|
|
||||||
|
if false; then
|
||||||
|
# vendor/cisco/xr
|
||||||
|
new "yangmodel vendor cisco xr 623: $YANGMODELS/vendor/cisco/xr/623"
|
||||||
|
expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/vendor/cisco/xr/623 show version" 0 "3."
|
||||||
|
|
||||||
|
new "yangmodel vendor cisco xr 632: $YANGMODELS/vendor/cisco/xr/632"
|
||||||
|
expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/vendor/cisco/xr/632 show version" 0 "3."
|
||||||
|
|
||||||
|
new "yangmodel vendor cisco xr 623: $YANGMODELS/vendor/cisco/xr/642"
|
||||||
|
expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/vendor/cisco/xr/642 show version" 0 "3."
|
||||||
|
|
||||||
|
new "yangmodel vendor cisco xr 651: $YANGMODELS/vendor/cisco/xr/651"
|
||||||
|
expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/vendor/cisco/xr/651 show version" 0 "3."
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf $dir
|
||||||
|
|
||||||
|
|
@ -100,6 +100,9 @@ distclean: clean
|
||||||
rm -f Makefile *~ .depend
|
rm -f Makefile *~ .depend
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
# install -d -m 0755 $(DESTDIR)$(bindir)
|
||||||
|
# install -m 0755 $(INSTALLFLAGS) $(APPS) $(DESTDIR)$(bindir)
|
||||||
|
|
||||||
|
|
||||||
install-include:
|
install-include:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@
|
||||||
static int
|
static int
|
||||||
usage(char *argv0)
|
usage(char *argv0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "usage:%s [options]\n"
|
fprintf(stderr, "usage:%s [options] # input yang spec on stdin\n"
|
||||||
"where options are\n"
|
"where options are\n"
|
||||||
"\t-h \t\tHelp\n"
|
"\t-h \t\tHelp\n"
|
||||||
"\t-D <level> \tDebug\n"
|
"\t-D <level> \tDebug\n"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue