Added YANG_SPEC_LINENR compile-time option
This commit is contained in:
parent
aa4feee03e
commit
af29a0f974
14 changed files with 532 additions and 202 deletions
|
|
@ -16,6 +16,9 @@ Expected: October 2024
|
|||
|
||||
### Features
|
||||
|
||||
* Added YANG struct memory optimization
|
||||
* Added union and extended struct for uncommon fields
|
||||
* Removed per-object YANG linenr info
|
||||
* New: [CLI simple alias](https://github.com/clicon/cligen/issues/112)
|
||||
* See: https://clixon-docs.readthedocs.io/en/latest/cli.html#cli-aliases
|
||||
* List pagination: Added where, sort-by and direction parameter for configured data
|
||||
|
|
@ -26,6 +29,8 @@ Expected: October 2024
|
|||
|
||||
Users may have to change how they access the system
|
||||
|
||||
* Removed YANG line-number in error-messages for memory optimization
|
||||
* Re-enable by setting `YANG_SPEC_LINENR` compile-time option
|
||||
* NETCONF error returns of failed leafref references, see https://github.com/clicon/clixon/issues/536
|
||||
* List pagination of large lists
|
||||
* For backward-compatibility, mark the list with extension cl:list-pagination-partial-state extension
|
||||
|
|
|
|||
|
|
@ -1581,7 +1581,7 @@ yang2cli_grouping(clixon_handle h,
|
|||
}
|
||||
/* Parse the buffer using cligen parser. load cli syntax */
|
||||
if (clispec_parse_str(cli_cligen(h), cbuf_get(cb), (char*)__FUNCTION__, NULL, pt, NULL) < 0){
|
||||
fprintf(stderr, "%s\n", cbuf_get(cb));
|
||||
clixon_err(OE_PLUGIN, 0, "%s", cbuf_get(cb));
|
||||
goto done;
|
||||
}
|
||||
clixon_debug(CLIXON_DBG_CLI, "Generated auto-cli for grouping:%s",
|
||||
|
|
|
|||
|
|
@ -195,3 +195,12 @@
|
|||
* This is a limitation of of the current implementation
|
||||
*/
|
||||
#define YANG_SCHEMA_MOUNT_YANG_LIB_FORCE
|
||||
|
||||
/*! For debug, YANG linenr shown in some YANG error-messages
|
||||
*
|
||||
* If set, report line-numbers in some error-messages (grouping/mandatory key),
|
||||
* However, almost all parsing still reports linenr on error.
|
||||
* Only exception is schema-nodeid sub-parsing
|
||||
* If not set, reduces memory with 8 bytes per yang-stmt.
|
||||
*/
|
||||
#undef YANG_SPEC_LINENR
|
||||
|
|
|
|||
|
|
@ -90,6 +90,9 @@
|
|||
* Set by yang_mount_set
|
||||
* Read by ys_free1
|
||||
*/
|
||||
#define YANG_FLAG_EXTENDED 0x400 /* Use extended struct to access uncommon fields
|
||||
* Memory optimization
|
||||
*/
|
||||
|
||||
/*
|
||||
* Types
|
||||
|
|
@ -254,8 +257,12 @@ cvec *yang_when_nsc_get(yang_stmt *ys);
|
|||
int yang_when_nsc_set(yang_stmt *ys, cvec *nsc);
|
||||
const char *yang_filename_get(yang_stmt *ys);
|
||||
int yang_filename_set(yang_stmt *ys, const char *filename);
|
||||
int yang_linenum_get(yang_stmt *ys);
|
||||
int yang_linenum_set(yang_stmt *ys, int linenum);
|
||||
uint32_t yang_linenum_get(yang_stmt *ys);
|
||||
int yang_linenum_set(yang_stmt *ys, uint32_t linenum);
|
||||
void *yang_typecache_get(yang_stmt *ys);
|
||||
int yang_typecache_set(yang_stmt *ys, void *ycache);
|
||||
yang_stmt* yang_mymodule_get(yang_stmt *ys);
|
||||
int yang_mymodule_set(yang_stmt *ys, yang_stmt *ym);
|
||||
|
||||
/* Stats */
|
||||
int yang_stats_global(uint64_t *nr);
|
||||
|
|
@ -264,12 +271,15 @@ int yang_stats(yang_stmt *y, enum rfc_6020 keyw, uint64_t *nrp, size_t *sz
|
|||
/* Other functions */
|
||||
yang_stmt *yspec_new(void);
|
||||
yang_stmt *ys_new(enum rfc_6020 keyw);
|
||||
yang_stmt *yse_new(enum rfc_6020 keyw);
|
||||
yang_stmt *ys_prune(yang_stmt *yp, int i);
|
||||
int ys_prune_self(yang_stmt *ys);
|
||||
int ys_free1(yang_stmt *ys, int self);
|
||||
int ys_free(yang_stmt *ys);
|
||||
int ys_cp_one(yang_stmt *nw, yang_stmt *old);
|
||||
int ys_cp(yang_stmt *nw, yang_stmt *old);
|
||||
yang_stmt *ys_dup(yang_stmt *old);
|
||||
yang_stmt *yse_dup(yang_stmt *old);
|
||||
int yn_insert(yang_stmt *ys_parent, yang_stmt *ys_child);
|
||||
int yn_insert1(yang_stmt *ys_parent, yang_stmt *ys_child);
|
||||
yang_stmt *yn_iter(yang_stmt *yparent, int *inext);
|
||||
|
|
@ -309,9 +319,9 @@ int yang_features(clixon_handle h, yang_stmt *yt);
|
|||
cvec *yang_arg2cvec(yang_stmt *ys, char *delimi);
|
||||
int yang_key_match(yang_stmt *yn, char *name, int *lastkey);
|
||||
int yang_type_cache_regexp_set(yang_stmt *ytype, int rxmode, cvec *regexps);
|
||||
int yang_type_cache_get(yang_stmt *ytype, yang_stmt **resolved, int *options,
|
||||
int yang_type_cache_get2(yang_stmt *ytype, yang_stmt **resolved, int *options,
|
||||
cvec **cvv, cvec *patterns, int *rxmode, cvec *regexps, uint8_t *fraction);
|
||||
int yang_type_cache_set(yang_stmt *ys, yang_stmt *resolved, int options, cvec *cvv,
|
||||
int yang_type_cache_set2(yang_stmt *ys, yang_stmt *resolved, int options, cvec *cvv,
|
||||
cvec *patterns, uint8_t fraction);
|
||||
yang_stmt *yang_anydata_add(yang_stmt *yp, char *name);
|
||||
int yang_extension_value(yang_stmt *ys, char *name, char *ns, int *exist, char **value);
|
||||
|
|
|
|||
|
|
@ -280,11 +280,13 @@ validate_identityref(cxobj *xt,
|
|||
ymod = yang_find_module_by_prefix_yspec(ys_spec(ys), prefix);
|
||||
}
|
||||
if (ymod == NULL){
|
||||
cprintf(cberr, "Identityref validation failed, %s not derived from %s in %s.yang:%d",
|
||||
cprintf(cberr, "Identityref validation failed, %s not derived from %s in %s.yang",
|
||||
node,
|
||||
yang_argument_get(ybaseid),
|
||||
yang_argument_get(ys_module(ybaseid)),
|
||||
yang_linenum_get(ybaseid));
|
||||
yang_argument_get(ys_module(ybaseid)));
|
||||
#ifdef YANG_SPEC_LINENR
|
||||
cprintf(cberr, ":%d", yang_linenum_get(ybaseid));
|
||||
#endif
|
||||
if (xret && netconf_operation_failed_xml(xret, "application", cbuf_get(cberr)) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
|
|
@ -296,11 +298,14 @@ validate_identityref(cxobj *xt,
|
|||
*/
|
||||
idrefvec = yang_cvec_get(ybaseid);
|
||||
if (cvec_find(idrefvec, idref) == NULL){
|
||||
cprintf(cberr, "Identityref validation failed, %s not derived from %s in %s.yang:%d",
|
||||
|
||||
cprintf(cberr, "Identityref validation failed, %s not derived from %s in %s.yang",
|
||||
node,
|
||||
yang_argument_get(ybaseid),
|
||||
yang_argument_get(ys_module(ybaseid)),
|
||||
yang_linenum_get(ybaseid));
|
||||
yang_argument_get(ys_module(ybaseid)));
|
||||
#ifdef YANG_SPEC_LINENR
|
||||
cprintf(cberr, ":%d", yang_linenum_get(ybaseid));
|
||||
#endif
|
||||
if (xret && netconf_operation_failed_xml(xret, "application", cbuf_get(cberr)) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
|
|
@ -684,9 +689,11 @@ check_list_key(cxobj *xt,
|
|||
}
|
||||
ymod = ys_module(yt);
|
||||
keyw = yang_keyword_get(yt);
|
||||
cprintf(cb, "Mandatory key in '%s %s' in %s.yang:%d",
|
||||
yang_key2str(keyw), xml_name(xt), yang_argument_get(ymod),
|
||||
yang_linenum_get(yc));
|
||||
cprintf(cb, "Mandatory key in '%s %s' in %s.yang",
|
||||
yang_key2str(keyw), xml_name(xt), yang_argument_get(ymod));
|
||||
#ifdef YANG_SPEC_LINENR
|
||||
cprintf(cb, ":%d", yang_linenum_get(yc));
|
||||
#endif
|
||||
if (netconf_missing_element_xml(xret, "application", keyname, cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
cbuf_free(cb);
|
||||
|
|
|
|||
|
|
@ -263,6 +263,7 @@ yang_argument_set(yang_stmt *ys,
|
|||
cg_var*
|
||||
yang_cv_get(yang_stmt *ys)
|
||||
{
|
||||
// assert(ys->ys_keyword == Y_FEATURE ||ys->ys_keyword == Y_LEAF || ys->ys_keyword == Y_LEAF_LIST || ys->ys_keyword == Y_CONFIG || ys->ys_keyword == Y_MANDATORY || ys->ys_keyword == Y_MAX_ELEMENTS|| ys->ys_keyword == Y_MIN_ELEMENTS || ys->ys_keyword == Y_REQUIRE_INSTANCE || ys->ys_keyword == Y_FRACTION_DIGITS || ys->ys_keyword == Y_REVISION || ys->ys_keyword == Y_REVISION_DATE || ys->ys_keyword == Y_UNKNOWN || ys->ys_keyword == Y_SPEC || ys->ys_keyword == Y_ENUM);
|
||||
return ys->ys_cv;
|
||||
}
|
||||
|
||||
|
|
@ -277,6 +278,7 @@ int
|
|||
yang_cv_set(yang_stmt *ys,
|
||||
cg_var *cv)
|
||||
{
|
||||
// assert(ys->ys_keyword == Y_FEATURE || ys->ys_keyword == Y_LEAF || ys->ys_keyword == Y_LEAF_LIST || ys->ys_keyword == Y_CONFIG || ys->ys_keyword == Y_MANDATORY || ys->ys_keyword == Y_MAX_ELEMENTS|| ys->ys_keyword == Y_MIN_ELEMENTS || ys->ys_keyword == Y_REQUIRE_INSTANCE || ys->ys_keyword == Y_FRACTION_DIGITS || ys->ys_keyword == Y_REVISION || ys->ys_keyword == Y_REVISION_DATE || ys->ys_keyword == Y_UNKNOWN || ys->ys_keyword == Y_SPEC || ys->ys_keyword == Y_ENUM);
|
||||
if (cv != NULL && ys->ys_cv != NULL)
|
||||
cv_free(ys->ys_cv);
|
||||
ys->ys_cv = cv;
|
||||
|
|
@ -292,6 +294,7 @@ yang_cv_set(yang_stmt *ys,
|
|||
cvec*
|
||||
yang_cvec_get(yang_stmt *ys)
|
||||
{
|
||||
// assert(ys->ys_keyword == Y_EXTENSION || ys->ys_keyword == Y_IDENTITY ||ys->ys_keyword == Y_LENGTH || ys->ys_keyword == Y_LIST ||ys->ys_keyword == Y_RANGE || ys->ys_keyword == Y_TYPE ||ys->ys_keyword == Y_UNIQUE ||ys->ys_keyword == Y_CONTAINER);
|
||||
return ys->ys_cvec;
|
||||
}
|
||||
|
||||
|
|
@ -306,6 +309,7 @@ int
|
|||
yang_cvec_set(yang_stmt *ys,
|
||||
cvec *cvv)
|
||||
{
|
||||
// assert(ys->ys_keyword == Y_EXTENSION || ys->ys_keyword == Y_IDENTITY ||ys->ys_keyword == Y_LENGTH || ys->ys_keyword == Y_LIST ||ys->ys_keyword == Y_RANGE || ys->ys_keyword == Y_TYPE ||ys->ys_keyword == Y_UNIQUE ||ys->ys_keyword == Y_CONTAINER);
|
||||
if (ys->ys_cvec)
|
||||
cvec_free(ys->ys_cvec);
|
||||
ys->ys_cvec = cvv;
|
||||
|
|
@ -328,6 +332,7 @@ yang_cvec_add(yang_stmt *ys,
|
|||
cg_var *cv;
|
||||
cvec *cvv;
|
||||
|
||||
// assert(ys->ys_keyword == Y_EXTENSION || ys->ys_keyword == Y_IDENTITY ||ys->ys_keyword == Y_LENGTH || ys->ys_keyword == Y_LIST ||ys->ys_keyword == Y_RANGE || ys->ys_keyword == Y_TYPE ||ys->ys_keyword == Y_UNIQUE ||ys->ys_keyword == Y_CONTAINER);
|
||||
if ((cvv = yang_cvec_get(ys)) == NULL){
|
||||
if ((cvv = cvec_new(0)) == NULL){
|
||||
clixon_err(OE_YANG, errno, "cvec_new");
|
||||
|
|
@ -354,6 +359,7 @@ yang_cvec_add(yang_stmt *ys,
|
|||
int
|
||||
yang_ref_get(yang_stmt *ys)
|
||||
{
|
||||
// assert(ys->ys_keyword == Y_SPEC);
|
||||
return ys->ys_ref;
|
||||
}
|
||||
|
||||
|
|
@ -365,6 +371,7 @@ yang_ref_get(yang_stmt *ys)
|
|||
int
|
||||
yang_ref_inc(yang_stmt *ys)
|
||||
{
|
||||
// assert(ys->ys_keyword == Y_SPEC);
|
||||
ys->ys_ref++;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -380,6 +387,7 @@ yang_ref_dec(yang_stmt *ys)
|
|||
{
|
||||
int retval = -1;
|
||||
|
||||
// assert(ys->ys_keyword == Y_SPEC);
|
||||
if (ys->ys_ref > 0)
|
||||
ys->ys_ref--;
|
||||
retval = 0;
|
||||
|
|
@ -439,7 +447,12 @@ yang_flag_reset(yang_stmt *ys,
|
|||
char*
|
||||
yang_when_xpath_get(yang_stmt *ys)
|
||||
{
|
||||
return ys->ys_when_xpath;
|
||||
yang_stmt_extended *yse = (yang_stmt_extended *)ys;
|
||||
|
||||
if ((ys->ys_flags & YANG_FLAG_EXTENDED) == 0x0)
|
||||
return NULL;
|
||||
else
|
||||
return yse->yse_when_xpath;
|
||||
}
|
||||
|
||||
/*! Set yang xpath and namespace context for "when"-associated augment
|
||||
|
|
@ -456,12 +469,18 @@ yang_when_xpath_set(yang_stmt *ys,
|
|||
char *xpath)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt_extended *yse = (yang_stmt_extended *)ys;
|
||||
|
||||
if (xpath == NULL){
|
||||
clixon_err(OE_YANG, EINVAL, "xpath is NULL");
|
||||
goto done;
|
||||
}
|
||||
if ((ys->ys_when_xpath = strdup(xpath)) == NULL){
|
||||
if ((ys->ys_flags & YANG_FLAG_EXTENDED) == 0x0){
|
||||
clixon_err(OE_YANG, EINVAL, "Yang node %s %s must have flag YANG_FLAG_EXTENDED for this operation",
|
||||
yang_key2str(ys->ys_keyword), ys->ys_argument);
|
||||
goto done;
|
||||
}
|
||||
if ((yse->yse_when_xpath = strdup(xpath)) == NULL){
|
||||
clixon_err(OE_YANG, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -481,7 +500,12 @@ yang_when_xpath_set(yang_stmt *ys,
|
|||
cvec *
|
||||
yang_when_nsc_get(yang_stmt *ys)
|
||||
{
|
||||
return ys->ys_when_nsc;
|
||||
yang_stmt_extended *yse = (yang_stmt_extended *)ys;
|
||||
|
||||
if ((ys->ys_flags & YANG_FLAG_EXTENDED) == 0x0)
|
||||
return NULL;
|
||||
else
|
||||
return yse->yse_when_nsc;
|
||||
}
|
||||
|
||||
/*! Set yang namespace context for "when"-associated augment
|
||||
|
|
@ -498,8 +522,14 @@ yang_when_nsc_set(yang_stmt *ys,
|
|||
cvec *nsc)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt_extended *yse = (yang_stmt_extended *)ys;
|
||||
|
||||
if (nsc && (ys->ys_when_nsc = cvec_dup(nsc)) == NULL){
|
||||
if ((ys->ys_flags & YANG_FLAG_EXTENDED) == 0x0){
|
||||
clixon_err(OE_YANG, EINVAL, "Yang node %s %s must have flag YANG_FLAG_EXTENDED for this operation",
|
||||
yang_key2str(ys->ys_keyword), ys->ys_argument);
|
||||
return -1;
|
||||
}
|
||||
if (nsc && (yse->yse_when_nsc = cvec_dup(nsc)) == NULL){
|
||||
clixon_err(OE_YANG, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -517,6 +547,7 @@ yang_when_nsc_set(yang_stmt *ys,
|
|||
const char *
|
||||
yang_filename_get(yang_stmt *ys)
|
||||
{
|
||||
// assert(ys->ys_keyword == Y_MODULE || ys->ys_keyword == Y_SUBMODULE);
|
||||
return ys->ys_filename;
|
||||
}
|
||||
|
||||
|
|
@ -532,6 +563,7 @@ int
|
|||
yang_filename_set(yang_stmt *ys,
|
||||
const char *filename)
|
||||
{
|
||||
// assert(ys->ys_keyword == Y_MODULE || ys->ys_keyword == Y_SUBMODULE);
|
||||
if ((ys->ys_filename = strdup(filename)) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "strdup");
|
||||
return -1;
|
||||
|
|
@ -544,10 +576,14 @@ yang_filename_set(yang_stmt *ys,
|
|||
* @param[in] ys Yang statement
|
||||
* @retval linenum
|
||||
*/
|
||||
int
|
||||
uint32_t
|
||||
yang_linenum_get(yang_stmt *ys)
|
||||
{
|
||||
#ifdef YANG_SPEC_LINENR
|
||||
return ys->ys_linenum;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*! Set line number of yang filename for error/debug purpose
|
||||
|
|
@ -557,9 +593,77 @@ yang_linenum_get(yang_stmt *ys)
|
|||
*/
|
||||
int
|
||||
yang_linenum_set(yang_stmt *ys,
|
||||
int linenum)
|
||||
uint32_t linenum)
|
||||
{
|
||||
#ifdef YANG_SPEC_LINENR
|
||||
ys->ys_linenum = linenum;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Get type cache
|
||||
*
|
||||
* @param[in] ys Yang statement
|
||||
* @retval ycache
|
||||
*/
|
||||
void *
|
||||
yang_typecache_get(yang_stmt *ys)
|
||||
{
|
||||
// assert(ys->ys_keyword == Y_TYPE);
|
||||
return ys->ys_typecache;
|
||||
}
|
||||
|
||||
/*! Set type cache
|
||||
*
|
||||
* @param[in] ys Yang statement
|
||||
* @param[in] ycache Type cache
|
||||
* @retval 0 OK
|
||||
*/
|
||||
int
|
||||
yang_typecache_set(yang_stmt *ys,
|
||||
void *ycache)
|
||||
{
|
||||
// assert(ys->ys_keyword == Y_TYPE);
|
||||
ys->ys_typecache = ycache;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Get mymodule
|
||||
*
|
||||
* Shortcut to "my" module. Used by augmented and unknown nodes
|
||||
* @param[in] ys YANG statement
|
||||
* @retval ymod YANG module
|
||||
*/
|
||||
yang_stmt*
|
||||
yang_mymodule_get(yang_stmt *ys)
|
||||
{
|
||||
yang_stmt_extended *yse = (yang_stmt_extended *)ys;
|
||||
|
||||
if ((ys->ys_flags & YANG_FLAG_EXTENDED) == 0x0)
|
||||
return NULL;
|
||||
else
|
||||
return yse->yse_mymodule;
|
||||
}
|
||||
|
||||
/*! Set mymodule
|
||||
*
|
||||
* Shortcut to "my" module. Used by augmented and unknown nodes
|
||||
* @param[in] ys YANG statement
|
||||
* @param[in] ymod YANG module
|
||||
* @retval 0 OK
|
||||
*/
|
||||
int
|
||||
yang_mymodule_set(yang_stmt *ys,
|
||||
yang_stmt *ym)
|
||||
{
|
||||
yang_stmt_extended *yse = (yang_stmt_extended *)ys;
|
||||
|
||||
if ((ys->ys_flags & YANG_FLAG_EXTENDED) == 0x0){
|
||||
clixon_err(OE_YANG, EINVAL, "Yang node %s %s must have flag YANG_FLAG_EXTENDED for this operation",
|
||||
yang_key2str(ys->ys_keyword), ys->ys_argument);
|
||||
return -1;
|
||||
}
|
||||
yse->yse_mymodule = ym;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -588,21 +692,31 @@ yang_stats_global(uint64_t *nr)
|
|||
* (baseline: )
|
||||
*/
|
||||
static int
|
||||
yang_stats_one(yang_stmt *y,
|
||||
yang_stats_one(yang_stmt *ys,
|
||||
size_t *szp)
|
||||
{
|
||||
size_t sz = 0;
|
||||
yang_type_cache *yc;
|
||||
|
||||
if (yang_flag_get(ys, YANG_FLAG_EXTENDED) == 0x0)
|
||||
sz += sizeof(struct yang_stmt_extended);
|
||||
else
|
||||
sz += sizeof(struct yang_stmt);
|
||||
sz += y->ys_len*sizeof(struct yang_stmt*);
|
||||
if (y->ys_argument)
|
||||
sz += strlen(y->ys_argument) + 1;
|
||||
if (y->ys_cv)
|
||||
sz += cv_size(y->ys_cv);
|
||||
if (y->ys_cvec)
|
||||
sz += cvec_size(y->ys_cvec);
|
||||
if ((yc = y->ys_typecache) != NULL){
|
||||
sz += ys->ys_len*sizeof(struct yang_stmt*);
|
||||
if (ys->ys_argument)
|
||||
sz += strlen(ys->ys_argument) + 1;
|
||||
if (ys->ys_cvec)
|
||||
sz += cvec_size(ys->ys_cvec);
|
||||
if (yang_flag_get(ys, YANG_FLAG_EXTENDED) != 0x0) {
|
||||
yang_stmt_extended *yse = (yang_stmt_extended *)ys;
|
||||
if (yse->yse_when_xpath)
|
||||
sz += strlen(yse->yse_when_xpath) + 1;
|
||||
if (yse->yse_when_nsc)
|
||||
sz += cvec_size(yse->yse_when_nsc);
|
||||
}
|
||||
switch (ys->ys_keyword) {
|
||||
case Y_TYPE:
|
||||
if ((yc = yang_typecache_get(ys)) != NULL){
|
||||
sz += sizeof(struct yang_type_cache);
|
||||
if (yc->yc_cvv)
|
||||
sz += cvec_size(yc->yc_cvv);
|
||||
|
|
@ -611,12 +725,15 @@ yang_stats_one(yang_stmt *y,
|
|||
if (yc->yc_regexps)
|
||||
sz += cvec_size(yc->yc_regexps);
|
||||
}
|
||||
if (y->ys_when_xpath)
|
||||
sz += strlen(y->ys_when_xpath) + 1;
|
||||
if (y->ys_when_nsc)
|
||||
sz += cvec_size(y->ys_when_nsc);
|
||||
if (y->ys_filename)
|
||||
sz += strlen(y->ys_filename) + 1;
|
||||
break;
|
||||
case Y_MODULE:
|
||||
case Y_SUBMODULE:
|
||||
if (ys->ys_filename)
|
||||
sz += strlen(ys->ys_filename) + 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (szp)
|
||||
*szp = sz;
|
||||
return 0;
|
||||
|
|
@ -686,23 +803,67 @@ yspec_new(void)
|
|||
return yspec;
|
||||
}
|
||||
|
||||
/*! Create new yang node/statement given size
|
||||
*
|
||||
* Size parameter for variable size, eg extended YANG struct
|
||||
* @param[in] keyw Yang stmt keyword
|
||||
* @param[in] sz Size of created struct
|
||||
* @retval ys New yang-stmt. Free with ys_free()
|
||||
* @retval NULL Error
|
||||
*/
|
||||
static yang_stmt *
|
||||
ys_new_sz(enum rfc_6020 keyw,
|
||||
size_t sz)
|
||||
{
|
||||
yang_stmt *ys;
|
||||
|
||||
if ((ys = malloc(sz)) == NULL){
|
||||
clixon_err(OE_YANG, errno, "malloc");
|
||||
return NULL;
|
||||
}
|
||||
memset(ys, 0, sz);
|
||||
ys->ys_keyword = keyw;
|
||||
_stats_yang_nr++;
|
||||
return ys;
|
||||
}
|
||||
|
||||
/*! Create new yang node/statement
|
||||
*
|
||||
* @retval ys Free with ys_free()
|
||||
* @param[in] keyw Yang stmt keyword
|
||||
* @retval ys New yang-stmt. Free with ys_free()
|
||||
* @retval NULL Error
|
||||
* @note UNKNOWN nodes are always extended
|
||||
*/
|
||||
yang_stmt *
|
||||
ys_new(enum rfc_6020 keyw)
|
||||
{
|
||||
size_t sz;
|
||||
yang_stmt *ys;
|
||||
|
||||
if ((ys = malloc(sizeof(*ys))) == NULL){
|
||||
clixon_err(OE_YANG, errno, "malloc");
|
||||
return NULL;
|
||||
if (keyw == Y_UNKNOWN)
|
||||
sz = sizeof(struct yang_stmt_extended);
|
||||
else
|
||||
sz = sizeof(*ys);
|
||||
if ((ys = ys_new_sz(keyw, sz)) != NULL &&
|
||||
keyw == Y_UNKNOWN){
|
||||
yang_flag_set(ys, YANG_FLAG_EXTENDED);
|
||||
}
|
||||
memset(ys, 0, sizeof(*ys));
|
||||
ys->ys_keyword = keyw;
|
||||
_stats_yang_nr++;
|
||||
return ys;
|
||||
}
|
||||
|
||||
/*! Create new extended yang node/statement
|
||||
*
|
||||
* @param[in] keyw Yang stmt keyword
|
||||
* @retval ys New yang-stmt. Free with ys_free()
|
||||
* @retval NULL Error
|
||||
*/
|
||||
yang_stmt *
|
||||
yse_new(enum rfc_6020 keyw)
|
||||
{
|
||||
yang_stmt *ys;
|
||||
|
||||
if ((ys = ys_new_sz(keyw, sizeof(struct yang_stmt_extended))) != NULL)
|
||||
yang_flag_set(ys, YANG_FLAG_EXTENDED);
|
||||
return ys;
|
||||
}
|
||||
|
||||
|
|
@ -718,11 +879,11 @@ int
|
|||
ys_free1(yang_stmt *ys,
|
||||
int self)
|
||||
{
|
||||
cg_var *cv;
|
||||
rpc_callback_t *rc;
|
||||
cg_var *cv;
|
||||
|
||||
if ((cv = yang_cv_get(ys)) != NULL){
|
||||
yang_cv_set(ys, NULL); /* only frees on replace */
|
||||
if ((cv = ys->ys_cv) != NULL){ // To not trigger asserts
|
||||
ys->ys_cv = NULL;
|
||||
cv_free(cv);
|
||||
}
|
||||
if (ys->ys_cvec){
|
||||
|
|
@ -738,18 +899,17 @@ ys_free1(yang_stmt *ys,
|
|||
free(ys->ys_argument);
|
||||
ys->ys_argument = NULL;
|
||||
}
|
||||
if (ys->ys_typecache){
|
||||
yang_type_cache_free(ys->ys_typecache);
|
||||
ys->ys_typecache = NULL;
|
||||
if (yang_flag_get(ys, YANG_FLAG_EXTENDED) != 0x0) {
|
||||
yang_stmt_extended *yse = (yang_stmt_extended *)ys;
|
||||
if (yse->yse_when_xpath)
|
||||
free(yse->yse_when_xpath);
|
||||
if (yse->yse_when_nsc)
|
||||
cvec_free(yse->yse_when_nsc);
|
||||
}
|
||||
if (ys->ys_when_xpath)
|
||||
free(ys->ys_when_xpath);
|
||||
if (ys->ys_when_nsc)
|
||||
cvec_free(ys->ys_when_nsc);
|
||||
if (ys->ys_stmt)
|
||||
free(ys->ys_stmt);
|
||||
if (ys->ys_filename)
|
||||
free(ys->ys_filename);
|
||||
switch (ys->ys_keyword) { /* type-specifi union fields */
|
||||
case Y_ACTION:
|
||||
while((rc = ys->ys_action_cb) != NULL) {
|
||||
DELQ(rc, ys->ys_action_cb, rpc_callback_t *);
|
||||
if (rc->rc_namespace)
|
||||
|
|
@ -758,6 +918,21 @@ ys_free1(yang_stmt *ys,
|
|||
free(rc->rc_name);
|
||||
free(rc);
|
||||
}
|
||||
break;
|
||||
case Y_TYPE:
|
||||
if (ys->ys_typecache){
|
||||
yang_type_cache_free(ys->ys_typecache);
|
||||
ys->ys_typecache = NULL;
|
||||
}
|
||||
break;
|
||||
case Y_MODULE:
|
||||
case Y_SUBMODULE:
|
||||
if (ys->ys_filename)
|
||||
free(ys->ys_filename);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (self){
|
||||
free(ys);
|
||||
_stats_yang_nr--;
|
||||
|
|
@ -892,6 +1067,73 @@ yn_realloc(yang_stmt *yn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ys_cp_one(yang_stmt *ynew,
|
||||
yang_stmt *yold)
|
||||
{
|
||||
int retval = -1;
|
||||
char *xpath;
|
||||
cvec *cvv;
|
||||
cg_var *cvn;
|
||||
cg_var *cvo;
|
||||
size_t sz;
|
||||
|
||||
if (yang_flag_get(yold, YANG_FLAG_EXTENDED) != 0x0)
|
||||
sz = sizeof(struct yang_stmt_extended);
|
||||
else
|
||||
sz = sizeof(*yold);
|
||||
memcpy(ynew, yold, sz);
|
||||
ynew->ys_parent = NULL;
|
||||
if (yold->ys_stmt)
|
||||
if ((ynew->ys_stmt = calloc(yold->ys_len, sizeof(yang_stmt *))) == NULL){
|
||||
clixon_err(OE_YANG, errno, "calloc");
|
||||
goto done;
|
||||
}
|
||||
if (yold->ys_argument)
|
||||
if ((ynew->ys_argument = strdup(yold->ys_argument)) == NULL){
|
||||
clixon_err(OE_YANG, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
if ((cvo = yold->ys_cv) != NULL){ // Note direct access to avoid wrappings
|
||||
yang_cv_set(ynew, NULL);
|
||||
if ((cvn = cv_dup(cvo)) == NULL){
|
||||
clixon_err(OE_YANG, errno, "cv_dup");
|
||||
goto done;
|
||||
}
|
||||
yang_cv_set(ynew, cvn);
|
||||
}
|
||||
if ((cvv = yold->ys_cvec) != NULL){ // Note direct access to avoid wrappings
|
||||
ynew->ys_cvec = NULL; // Note direct access to avoid cvec_free
|
||||
if ((cvv = cvec_dup(cvv)) == NULL){
|
||||
clixon_err(OE_YANG, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
yang_cvec_set(ynew, cvv);
|
||||
}
|
||||
switch (yold->ys_keyword) { /* type-specifi union fields */
|
||||
case Y_TYPE:
|
||||
if (yang_typecache_get(yold)){
|
||||
yang_typecache_set(ynew, NULL);
|
||||
if (yang_type_cache_cp(ynew, yold) < 0)
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if ((xpath = yang_when_xpath_get(yold)) != NULL){
|
||||
if (yang_when_xpath_set(ynew, xpath) < 0)
|
||||
goto done;
|
||||
}
|
||||
if ((cvv = yang_when_nsc_get(yold)) != NULL){
|
||||
if (yang_when_nsc_set(ynew, cvv) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Copy yang statement recursively from old to new
|
||||
*
|
||||
* @param[in] ynew New empty (but created) yang statement (to)
|
||||
|
|
@ -913,53 +1155,16 @@ ys_cp(yang_stmt *ynew,
|
|||
int i;
|
||||
yang_stmt *ycn; /* new child */
|
||||
yang_stmt *yco; /* old child */
|
||||
cg_var *cvn;
|
||||
cg_var *cvo;
|
||||
|
||||
memcpy(ynew, yold, sizeof(*yold));
|
||||
ynew->ys_parent = NULL;
|
||||
if (yold->ys_stmt)
|
||||
if ((ynew->ys_stmt = calloc(yold->ys_len, sizeof(yang_stmt *))) == NULL){
|
||||
clixon_err(OE_YANG, errno, "calloc");
|
||||
if (ys_cp_one(ynew, yold) < 0)
|
||||
goto done;
|
||||
}
|
||||
if (yold->ys_argument)
|
||||
if ((ynew->ys_argument = strdup(yold->ys_argument)) == NULL){
|
||||
clixon_err(OE_YANG, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
yang_cv_set(ynew, NULL);
|
||||
if ((cvo = yang_cv_get(yold)) != NULL){
|
||||
if ((cvn = cv_dup(cvo)) == NULL){
|
||||
clixon_err(OE_YANG, errno, "cv_dup");
|
||||
goto done;
|
||||
}
|
||||
yang_cv_set(ynew, cvn);
|
||||
}
|
||||
if (yold->ys_cvec)
|
||||
if ((ynew->ys_cvec = cvec_dup(yold->ys_cvec)) == NULL){
|
||||
clixon_err(OE_YANG, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
if (yold->ys_typecache){
|
||||
ynew->ys_typecache = NULL;
|
||||
if (yang_type_cache_cp(ynew, yold) < 0)
|
||||
goto done;
|
||||
}
|
||||
if (yold->ys_when_xpath)
|
||||
if ((ynew->ys_when_xpath = strdup(yold->ys_when_xpath)) == NULL){
|
||||
clixon_err(OE_YANG, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
if (yold->ys_when_nsc){
|
||||
if ((ynew->ys_when_nsc = cvec_dup(yold->ys_when_nsc)) == NULL){
|
||||
clixon_err(OE_YANG, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
for (i=0; i<ynew->ys_len; i++){
|
||||
yco = yold->ys_stmt[i];
|
||||
if ((ycn = ys_dup(yco)) == NULL)
|
||||
if (yang_flag_get(yco, YANG_FLAG_EXTENDED) != 0x0){
|
||||
if ((ycn = yse_dup(yco)) == NULL)
|
||||
goto done;
|
||||
}
|
||||
else if ((ycn = ys_dup(yco)) == NULL)
|
||||
goto done;
|
||||
ynew->ys_stmt[i] = ycn;
|
||||
ycn->ys_parent = ynew;
|
||||
|
|
@ -987,10 +1192,6 @@ ys_dup(yang_stmt *old)
|
|||
|
||||
if ((nw = ys_new(old->ys_keyword)) == NULL)
|
||||
return NULL;
|
||||
if (nw->ys_cvec){
|
||||
cvec_free(nw->ys_cvec);
|
||||
nw->ys_cvec = NULL;
|
||||
}
|
||||
if (ys_cp(nw, old) < 0){
|
||||
ys_free(nw);
|
||||
return NULL;
|
||||
|
|
@ -998,6 +1199,23 @@ ys_dup(yang_stmt *old)
|
|||
return nw;
|
||||
}
|
||||
|
||||
/*! Create a new extdended yang node and copy the contents recursively from the original.
|
||||
*/
|
||||
yang_stmt *
|
||||
yse_dup(yang_stmt *old)
|
||||
{
|
||||
yang_stmt *nw;
|
||||
|
||||
if ((nw = yse_new(old->ys_keyword)) == NULL)
|
||||
return NULL;
|
||||
if (ys_cp(nw, old) < 0){
|
||||
ys_free(nw);
|
||||
return NULL;
|
||||
}
|
||||
yang_flag_set(nw, YANG_FLAG_EXTENDED);
|
||||
return nw;
|
||||
}
|
||||
|
||||
/*! Replace yold with ynew (insert ynew at the exact place of yold). Keep yold pointer as-is.
|
||||
*
|
||||
* @param[in] yorig Existing yang statement
|
||||
|
|
@ -1786,8 +2004,8 @@ ys_module(yang_stmt *ys)
|
|||
while (ys != NULL &&
|
||||
ys->ys_keyword != Y_MODULE &&
|
||||
ys->ys_keyword != Y_SUBMODULE){
|
||||
if (ys->ys_mymodule){ /* shortcut due to augment */
|
||||
ys = ys->ys_mymodule;
|
||||
if (yang_mymodule_get(ys)){ /* shortcut due to augment */
|
||||
ys = yang_mymodule_get(ys);
|
||||
break;
|
||||
}
|
||||
yn = ys->ys_parent;
|
||||
|
|
@ -2859,7 +3077,7 @@ ys_populate_unknown(clixon_handle h,
|
|||
goto done;
|
||||
}
|
||||
/* To find right binding eg after grouping/uses */
|
||||
ys->ys_mymodule = ys_module(ys);
|
||||
yang_mymodule_set(ys, ys_module(ys));
|
||||
if ((yext = yang_find(ymod, Y_EXTENSION, id)) == NULL){
|
||||
clixon_err(OE_YANG, ENOENT, "Extension \"%s:%s\" not found", prefix, id);
|
||||
goto done;
|
||||
|
|
@ -2886,12 +3104,10 @@ ys_populate_unknown(clixon_handle h,
|
|||
*/
|
||||
if (clixon_plugin_extension_all(h, yext, ys) < 0)
|
||||
goto done;
|
||||
#if 1
|
||||
/* Add unknown to vector in extension */
|
||||
if ((cv = yang_cvec_add(yext, CGV_VOID, yang_argument_get(ys))) == NULL)
|
||||
goto done;
|
||||
cv_void_set(cv, ys);
|
||||
#endif
|
||||
retval = 0;
|
||||
done:
|
||||
if (prefix)
|
||||
|
|
@ -3631,7 +3847,7 @@ yang_key_match(yang_stmt *yn,
|
|||
* @see yang_type_cache_regexp_set where cache is extended w compiled regexps
|
||||
*/
|
||||
int
|
||||
yang_type_cache_set(yang_stmt *ys,
|
||||
yang_type_cache_set2(yang_stmt *ys,
|
||||
yang_stmt *resolved,
|
||||
int options,
|
||||
cvec *cvv,
|
||||
|
|
@ -3641,15 +3857,15 @@ yang_type_cache_set(yang_stmt *ys,
|
|||
int retval = -1;
|
||||
yang_type_cache *ycache;
|
||||
|
||||
if (ys->ys_typecache != NULL){
|
||||
if (yang_typecache_get(ys) != NULL){
|
||||
clixon_err(OE_YANG, EEXIST, "yang type cache");
|
||||
goto done;
|
||||
}
|
||||
if ((ys->ys_typecache = (yang_type_cache *)malloc(sizeof(*ycache))) == NULL){
|
||||
if ((ycache = (yang_type_cache *)malloc(sizeof(*ycache))) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
ycache = ys->ys_typecache;
|
||||
yang_typecache_set(ys, ycache);
|
||||
memset(ycache, 0, sizeof(*ycache));
|
||||
ycache->yc_resolved = resolved;
|
||||
ycache->yc_options = options;
|
||||
|
|
@ -3706,7 +3922,7 @@ yang_type_cache_regexp_set(yang_stmt *ytype,
|
|||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
yang_type_cache_get(yang_stmt *ytype,
|
||||
yang_type_cache_get2(yang_stmt *ytype,
|
||||
yang_stmt **resolved,
|
||||
int *options,
|
||||
cvec **cvv,
|
||||
|
|
@ -3719,7 +3935,7 @@ yang_type_cache_get(yang_stmt *ytype,
|
|||
cg_var *cv = NULL;
|
||||
yang_type_cache *ycache;
|
||||
|
||||
ycache = ytype->ys_typecache;
|
||||
ycache = yang_typecache_get(ytype);
|
||||
if (ycache == NULL){ /* No cache return 0 */
|
||||
retval = 0;
|
||||
goto done;
|
||||
|
|
@ -3770,11 +3986,11 @@ yang_type_cache_cp(yang_stmt *ynew,
|
|||
/* Note, regexps are not copied since they are voids, if they were, they
|
||||
* could not be freed in a simple way since copies are made at augment/group
|
||||
*/
|
||||
if ((ret = yang_type_cache_get(yold,
|
||||
if ((ret = yang_type_cache_get2(yold,
|
||||
&resolved, &options, &cvv, patterns, NULL, NULL, &fraction)) < 0)
|
||||
goto done;
|
||||
if (ret == 1 &&
|
||||
yang_type_cache_set(ynew, resolved, options, cvv, patterns, fraction) < 0)
|
||||
yang_type_cache_set2(ynew, resolved, options, cvv, patterns, fraction) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -3955,6 +4171,7 @@ yang_sort_subelements_fn(const void* arg1,
|
|||
else return ys1->_ys_vector_i - ys2->_ys_vector_i;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! Experimental code for sorting YANG children
|
||||
*
|
||||
* RFC 7950 7.5.7 and 7.8.5 says that containers and list sub elements are encoded in any order.
|
||||
|
|
@ -4109,6 +4326,7 @@ yang_single_child_type(yang_stmt *ys,
|
|||
void *
|
||||
yang_action_cb_get(yang_stmt *ys)
|
||||
{
|
||||
assert(ys->ys_keyword == Y_ACTION);
|
||||
return ys->ys_action_cb;
|
||||
}
|
||||
|
||||
|
|
@ -4122,6 +4340,7 @@ yang_action_cb_add(yang_stmt *ys,
|
|||
{
|
||||
rpc_callback_t *rc = (rpc_callback_t *)arg;
|
||||
|
||||
assert(ys->ys_keyword == Y_ACTION);
|
||||
if (rc == NULL){
|
||||
clixon_err(OE_YANG, EINVAL, "arg is NULL");
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -65,53 +65,103 @@ typedef struct yang_type_cache yang_type_cache;
|
|||
*
|
||||
* This is an internal type, not exposed in the API
|
||||
* The external type is "yang_stmt" defined in clixon_yang.h
|
||||
* @see struct yang_stmt_extended for extended struct (same beginning)
|
||||
* @note This struct MUST be identical in size to first part of yang_stmt_extended struct
|
||||
*/
|
||||
struct yang_stmt {
|
||||
int ys_len; /* Number of children */
|
||||
/* On x86_64, the following three fields take 8 bytes */
|
||||
enum rfc_6020 ys_keyword:16; /* YANG keyword */
|
||||
uint16_t ys_flags; /* Flags according to YANG_FLAG_MARK and others */
|
||||
uint32_t ys_len; /* Number of children */
|
||||
#ifdef YANG_SPEC_LINENR
|
||||
/* Increases memory w 8 extra bytes on x86_64
|
||||
* XXX: can we enable this when needed for schema nodeid sub-parsing? */
|
||||
uint32_t ys_linenum; /* For debug/errors: line number (in ys_filename) */
|
||||
#endif
|
||||
struct yang_stmt **ys_stmt; /* Vector of children statement pointers */
|
||||
struct yang_stmt *ys_parent; /* Backpointer to parent: yang-stmt or yang-spec */
|
||||
struct yang_stmt *ys_orig; /* Backpointer to grouping/augment original */
|
||||
enum rfc_6020 ys_keyword; /* YANG keyword */
|
||||
char *ys_argument; /* String / argument depending on keyword */
|
||||
uint16_t ys_flags; /* Flags according to YANG_FLAG_MARK and others */
|
||||
yang_stmt *ys_mymodule; /* Shortcut to "my" module. Used by:
|
||||
1) Augmented nodes "belong" to the module where the
|
||||
augment is declared, which may be different from
|
||||
the direct ancestor module
|
||||
2) Unknown nodes "belong" to where the extension is
|
||||
declared
|
||||
*/
|
||||
/* XXX: can we move this to union, No SPEC is already there */
|
||||
cg_var *ys_cv; /* cligen variable. See ys_populate()
|
||||
Following stmts have cv:s:
|
||||
leaf: for default value
|
||||
leaf-list,
|
||||
config: boolean true or false
|
||||
mandatory: boolean true or false
|
||||
require-instance: true or false
|
||||
fraction-digits for fraction-digits
|
||||
revision (uint32)
|
||||
unknown-stmt (optional argument)
|
||||
spec: mount-point xpath
|
||||
enum: value
|
||||
Y_FEATURE: boolean true or false
|
||||
Y_CONFIG: boolean true or false
|
||||
Y_LEAF: for default value
|
||||
Y_LEAF_LIST,
|
||||
Y_MAX_ELEMENTS:
|
||||
Y_MIN_ELEMENTS: inte
|
||||
Y_MANDATORY: boolean true or false
|
||||
Y_REQUIRE_INSTANCE: true or false
|
||||
Y_FRACTION_DIGITS for fraction-digits
|
||||
Y_REVISION (uint32)
|
||||
Y_REVISION_DATE (uint32)
|
||||
Y_UNKNOWN (optional argument)
|
||||
Y_SPEC: mount-point xpath
|
||||
Y_ENUM: value
|
||||
*/
|
||||
cvec *ys_cvec; /* List of stmt-specific variables
|
||||
Y_RANGE: range_min, range_max
|
||||
Y_LIST: vector of keys
|
||||
Y_TYPE & identity: store all derived
|
||||
types as <module>:<id> list
|
||||
Y_UNIQUE: vector of descendant schema node ids
|
||||
Y_CONTAINER: XXX or U_UNKNOWN?
|
||||
Y_EXTENSION: vector of instantiated UNKNOWNS
|
||||
Y_UNKNOWN: app-dep: yang-mount-points
|
||||
Y_IDENTITY: store all derived types as <module>:<id> list
|
||||
Y_LENGTH: length_min, length_max
|
||||
Y_LIST: vector of keys
|
||||
Y_RANGE: range_min, range_max
|
||||
Y_TYPE: store all derived types as <module>:<id> list
|
||||
Y_UNIQUE: vector of descendant schema node ids
|
||||
# Y_UNKNOWN: app-dep: yang-mount-points
|
||||
*/
|
||||
int ys_ref; /* Reference count for free, only YS_SPEC: 0 means
|
||||
* no sharing, 1: two references
|
||||
*/
|
||||
yang_type_cache *ys_typecache; /* If ys_keyword==Y_TYPE, cache all typedef data except unions */
|
||||
char *ys_when_xpath; /* Special conditional for a "when"-associated augment/uses xpath */
|
||||
cvec *ys_when_nsc; /* Special conditional for a "when"-associated augment/uses namespace ctx */
|
||||
char *ys_filename; /* For debug/errors: filename (only (sub)modules) */
|
||||
int ys_linenum; /* For debug/errors: line number (in ys_filename) */
|
||||
rpc_callback_t *ys_action_cb; /* Action callback list, only for Y_ACTION */
|
||||
union { /* depends on ys_keyword */
|
||||
rpc_callback_t *ysu_action_cb; /* Y_ACTION: Action callback list*/
|
||||
char *ysu_filename; /* Y_MODULE/Y_SUBMODULE: For debug/errors: filename */
|
||||
yang_type_cache *ysu_typecache; /* Y_TYPE: cache all typedef data except unions */
|
||||
int ysu_ref; /* Y_SPEC: Reference count for free: 0 means
|
||||
* no sharing, 1: two references */
|
||||
} u;
|
||||
};
|
||||
|
||||
/*! An extended yang struct for use of extra fields that consumes more memory
|
||||
*
|
||||
* Cannot fit this into the ysu union because keyword is unknown (or at least a set)
|
||||
* @see struct yang_stmt for the original struct
|
||||
* @note First part of this struct MUST resemble yang_stmt fields (in memory).
|
||||
*/
|
||||
struct yang_stmt_extended {
|
||||
/* On x86_64, the following four fields take 16 bytes */
|
||||
enum rfc_6020 ys_keyword:16; /* YANG keyword */
|
||||
uint16_t ys_flags; /* Flags according to YANG_FLAG_MARK and others */
|
||||
uint32_t ys_len; /* Number of children */
|
||||
#ifdef YANG_SPEC_LINENR
|
||||
uint32_t ys_linenum; /* For debug/errors: line number (in ys_filename) */
|
||||
#endif
|
||||
struct yang_stmt **ys_stmt; /* Vector of children statement pointers */
|
||||
struct yang_stmt *ys_parent; /* Backpointer to parent: yang-stmt or yang-spec */
|
||||
char *ys_argument; /* String / argument depending on keyword */
|
||||
cg_var *yse_cv; /* cligen variable. See ys_populate() */
|
||||
cvec *yse_cvec; /* List of stmt-specific variables */
|
||||
union { /* depends on ys_keyword */
|
||||
rpc_callback_t *ysu_action_cb; /* Y_ACTION: Action callback list*/
|
||||
char *ysu_filename; /* Y_MODULE/Y_SUBMODULE: For debug/errors: filename */
|
||||
yang_type_cache *ysu_typecache; /* Y_TYPE: cache all typedef data except unions */
|
||||
int ysu_ref; /* Y_SPEC: Reference count for free: 0 means
|
||||
* no sharing, 1: two references */
|
||||
} ue;
|
||||
/* Following fields could be extended only for unknown, grouped and augmented nodes
|
||||
*/
|
||||
char *yse_when_xpath; /* Special conditional for a "when"-associated augment/uses XPath */
|
||||
cvec *yse_when_nsc; /* Special conditional for a "when"-associated augment/uses namespace ctx */
|
||||
yang_stmt *yse_mymodule; /* Shortcut to "my" module. Used by:
|
||||
* 1) Augmented nodes "belong" to the module where the
|
||||
* augment is declared, which may be different from
|
||||
* the direct ancestor module
|
||||
* 2) Unknown nodes "belong" to where the extension is
|
||||
* declared */
|
||||
};
|
||||
typedef struct yang_stmt_extended yang_stmt_extended;
|
||||
|
||||
/* Access macros */
|
||||
#define ys_action_cb u.ysu_action_cb
|
||||
#define ys_filename u.ysu_filename
|
||||
#define ys_typecache u.ysu_typecache
|
||||
#define ys_ref u.ysu_ref
|
||||
|
||||
#endif /* _CLIXON_YANG_INTERNAL_H_ */
|
||||
|
|
|
|||
|
|
@ -181,8 +181,8 @@ ys_grouping_resolve(yang_stmt *yuses,
|
|||
else {
|
||||
ys = yuses; /* Check upwards in hierarchy for matching groupings */
|
||||
while (1){
|
||||
if (ys->ys_mymodule){
|
||||
yp = ys->ys_mymodule;
|
||||
if (yang_mymodule_get(ys)){
|
||||
yp = yang_mymodule_get(ys);
|
||||
}
|
||||
else
|
||||
if ((yp = yang_parent_get(ys)) == NULL)
|
||||
|
|
@ -356,13 +356,13 @@ yang_augment_node(clixon_handle h,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
if ((yc = ys_dup(yc0)) == NULL)
|
||||
if ((yc = yse_dup(yc0)) == NULL) /* Extended */
|
||||
goto done;
|
||||
#ifdef YANG_GROUPING_AUGMENT_SKIP
|
||||
/* cornercase: always expand uses under augment */
|
||||
yang_flag_reset(yc, YANG_FLAG_GROUPING);
|
||||
#endif
|
||||
yc->ys_mymodule = ymod;
|
||||
yang_mymodule_set(yc, ymod);
|
||||
if (yn_insert(ytarget, yc) < 0)
|
||||
goto done;
|
||||
/* If there is an associated when statement, add a special when struct to the yang
|
||||
|
|
@ -564,10 +564,17 @@ yang_expand_uses_node(yang_stmt *yn,
|
|||
if (ys_grouping_resolve(ys, prefix, id, &ygrouping) < 0)
|
||||
goto done;
|
||||
if (ygrouping == NULL){
|
||||
if ((ym = ys_module(yn)) != NULL)
|
||||
clixon_err(OE_YANG, 0, "Yang error : grouping \"%s\" not found in module \"%s\" in file: %s:%d",
|
||||
if ((ym = ys_module(yn)) != NULL){
|
||||
#ifdef YANG_SPEC_LINENR
|
||||
clixon_err(OE_YANG, 0, "Yang error : grouping \"%s\" not found in module \"%s\" in file: %s:%u",
|
||||
yang_argument_get(ys), yang_argument_get(ys_module(ys)),
|
||||
yang_filename_get(ym), yang_linenum_get(yn));
|
||||
#else
|
||||
clixon_err(OE_YANG, 0, "Yang error : grouping \"%s\" not found in module \"%s\" in file: %s",
|
||||
yang_argument_get(ys), yang_argument_get(ys_module(ys)),
|
||||
yang_filename_get(ym));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
clixon_err(OE_YANG, 0, "Yang error : grouping \"%s\" not found in module \"%s\"",
|
||||
yang_argument_get(ys), yang_argument_get(ys_module(ys)));
|
||||
|
|
@ -594,13 +601,42 @@ yang_expand_uses_node(yang_stmt *yn,
|
|||
if (yang_expand_grouping(ygrouping) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* Find when statement, if present */
|
||||
if ((ywhen = yang_find(ys, Y_WHEN, NULL)) != NULL){
|
||||
wxpath = yang_argument_get(ywhen);
|
||||
if (xml_nsctx_yang(ywhen, &wnsc) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* Make a copy of the grouping, then make refinements to this copy
|
||||
* Note this ygrouping2 object does not have a parent and does not work in many
|
||||
* functions which assume a full hierarchy, use the original ygrouping in those cases.
|
||||
*/
|
||||
if ((ygrouping2 = ys_dup(ygrouping)) == NULL)
|
||||
if ((ygrouping2 = ys_new(ygrouping->ys_keyword)) == NULL)
|
||||
goto done;
|
||||
/* Use yse_new() etc for ygrouping2 CHILDREN IF ywhen is set */
|
||||
if (ys_cp_one(ygrouping2, ygrouping) < 0){
|
||||
ys_free(ygrouping2);
|
||||
goto done;
|
||||
}
|
||||
{
|
||||
yang_stmt *ycn; /* new child */
|
||||
yang_stmt *yco; /* old child */
|
||||
int i;
|
||||
|
||||
for (i=0; i<ygrouping2->ys_len; i++){
|
||||
yco = ygrouping->ys_stmt[i];
|
||||
if (ywhen != NULL){
|
||||
if ((ycn = yse_dup(yco)) == NULL)
|
||||
goto done;
|
||||
}
|
||||
else {
|
||||
if ((ycn = ys_dup(yco)) == NULL)
|
||||
goto done;
|
||||
}
|
||||
ygrouping2->ys_stmt[i] = ycn;
|
||||
ycn->ys_parent = ygrouping2;
|
||||
}
|
||||
}
|
||||
/* Only replace data/schemanodes and unknowns:
|
||||
* Compute the number of such nodes, and extend the child vector with that below
|
||||
*/
|
||||
|
|
@ -631,12 +667,6 @@ yang_expand_uses_node(yang_stmt *yn,
|
|||
if (size)
|
||||
memmove(&yn->ys_stmt[i+glen+1], &yn->ys_stmt[i+1], size);
|
||||
}
|
||||
/* Find when statement, if present */
|
||||
if ((ywhen = yang_find(ys, Y_WHEN, NULL)) != NULL){
|
||||
wxpath = yang_argument_get(ywhen);
|
||||
if (xml_nsctx_yang(ywhen, &wnsc) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* Note: yang_desc_schema_nodeid() requires ygrouping2 to be in yspec tree,
|
||||
* due to correct module prefixes etc.
|
||||
* cannot be dangling, insert into tree here and then prune immediately after while loop
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@ ys_resolve_type(yang_stmt *ys,
|
|||
/* Cache the type resolving locally. Only place where this is done.
|
||||
* Why not do it in yang_type_resolve? (compile regexps needs clixon_handle)
|
||||
*/
|
||||
if (yang_type_cache_set(ys, resolved, options, cvv,
|
||||
if (yang_type_cache_set2(ys, resolved, options, cvv,
|
||||
patterns, fraction) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
|
|
@ -1345,14 +1345,14 @@ yang_type_resolve(yang_stmt *yorig,
|
|||
goto done;
|
||||
/* Cache does not work for eg string length 32? */
|
||||
#if 1
|
||||
if ((ret = yang_type_cache_get(ytype, yrestype,
|
||||
if ((ret = yang_type_cache_get2(ytype, yrestype,
|
||||
options, cvv, patterns, NULL, regexps, fraction)) < 0)
|
||||
goto done;
|
||||
if (ret == 1)
|
||||
goto ok;
|
||||
#else
|
||||
if (ytype->ys_typecache != NULL){
|
||||
if (yang_type_cache_get(ytype, yrestype,
|
||||
if (yang_typecache_get(ytype) != NULL){
|
||||
if (yang_type_cache_get2(ytype, yrestype,
|
||||
options, cvv, patterns, NULL, regexps, fraction) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ new "Netconf set undefined acl-type"
|
|||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><acls xmlns=\"urn:example:my-crypto\"><acl><name>x</name><type>undefined</type></acl></acls></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
new "netconf validate fail"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><validate><source><candidate/></source></validate></rpc>" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>Identityref validation failed, undefined not derived from acl-base in example-my-crypto.yang:[0-9]*</error-message></rpc-error></rpc-reply>" ""
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><validate><source><candidate/></source></validate></rpc>" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>Identityref validation failed, undefined not derived from acl-base in example-my-crypto.yang" ""
|
||||
|
||||
new "netconf discard-changes"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><discard-changes/></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ new "Re-Delete eth/0/0 using none should generate error"
|
|||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\" xmlns:nc=\"${BASENS}\"><interface nc:operation=\"delete\"><name>eth/0/0</name><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>" "<rpc-reply $DEFAULTNS><rpc-error>" ""
|
||||
|
||||
new "Add interface without key"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\" xmlns:nc=\"${BASENS}\"><interface nc:operation=\"create\"><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>missing-element</error-tag><error-info><bad-element>name</bad-element></error-info><error-severity>error</error-severity><error-message>Mandatory key in 'list interface' in ietf-interfaces.yang:[0-9]\+</error-message></rpc-error></rpc-reply>" ""
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\" xmlns:nc=\"${BASENS}\"><interface nc:operation=\"create\"><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>missing-element</error-tag><error-info><bad-element>name</bad-element></error-info><error-severity>error</error-severity><error-message>Mandatory key in 'list interface' in ietf-interfaces.yang"
|
||||
|
||||
new "netconf discard-changes"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><discard-changes/></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ cfg=$dir/conf_yang.xml
|
|||
new "openconfig"
|
||||
if [ ! -d "$OPENCONFIG" ]; then
|
||||
# err "Hmm Openconfig dir does not seem to exist, try git clone https://github.com/openconfig/public?"
|
||||
echo "...skipped: OPENCONFIG not set"
|
||||
echo "...skipped: OPENCONFIG not set or dir not exist"
|
||||
rm -rf $dir
|
||||
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ new "wait restconf"
|
|||
wait_restconf
|
||||
|
||||
new "restconf POST tree without key"
|
||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"example:cont1":{"interface":{"type":"regular"}}}' $RCPROTO://localhost/restconf/data)" 0 "HTTP/$HVER 400" "{\"ietf-restconf:errors\":{\"error\":{\"error-type\":\"application\",\"error-tag\":\"missing-element\",\"error-info\":{\"bad-element\":\"name\"},\"error-severity\":\"error\",\"error-message\":\"Mandatory key in 'list interface' in example.yang:7\"}}}"
|
||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"example:cont1":{"interface":{"type":"regular"}}}' $RCPROTO://localhost/restconf/data)" 0 "HTTP/$HVER 400" "{\"ietf-restconf:errors\":{\"error\":{\"error-type\":\"application\",\"error-tag\":\"missing-element\",\"error-info\":{\"bad-element\":\"name\"},\"error-severity\":\"error\",\"error-message\":\"Mandatory key in 'list interface' in example.yang"
|
||||
|
||||
new "restconf POST initial tree"
|
||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"example:cont1":{"interface":{"name":"local0","type":"regular"}}}' $RCPROTO://localhost/restconf/data)" 0 "HTTP/$HVER 201"
|
||||
|
|
@ -137,7 +137,7 @@ new "restconf POST interface without mandatory type"
|
|||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data/example:cont1 -d '{"example:interface":{"name":"TEST"}}')" 0 "HTTP/$HVER 400" '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"type"},"error-severity":"error","error-message":"Mandatory variable of interface in module example"}}}'
|
||||
|
||||
new "restconf POST interface without mandatory key"
|
||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data/example:cont1 -d '{"example:interface":{"type":"regular"}}')" 0 "HTTP/$HVER 400" "{\"ietf-restconf:errors\":{\"error\":{\"error-type\":\"application\",\"error-tag\":\"missing-element\",\"error-info\":{\"bad-element\":\"name\"},\"error-severity\":\"error\",\"error-message\":\"Mandatory key in 'list interface' in example.yang:7\"}}}"
|
||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data/example:cont1 -d '{"example:interface":{"type":"regular"}}')" 0 "HTTP/$HVER 400" "{\"ietf-restconf:errors\":{\"error\":{\"error-type\":\"application\",\"error-tag\":\"missing-element\",\"error-info\":{\"bad-element\":\"name\"},\"error-severity\":\"error\",\"error-message\":\"Mandatory key in 'list interface' in example.yang"
|
||||
|
||||
new "restconf POST interface"
|
||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"example:interface":{"name":"TEST","type":"eth0"}}' $RCPROTO://localhost/restconf/data/example:cont1)" 0 "HTTP/$HVER 201"
|
||||
|
|
|
|||
|
|
@ -347,8 +347,8 @@ new "netconf example rpc input list with key"
|
|||
expecteof_netconf "$clixon_netconf -qef $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><example xmlns=\"urn:example:clixon\"><x>mandatory</x>$LIST</example></rpc>" "" "<rpc-reply $DEFAULTNS><x xmlns=\"urn:example:clixon\">mandatory</x><y xmlns=\"urn:example:clixon\">42</y>$LIST</rpc-reply>"
|
||||
|
||||
LIST='<u1 xmlns="urn:example:clixon"><uk>bar</uk><val>1</val></u1><u1 xmlns="urn:example:clixon"><val>2</val></u1>'
|
||||
new "netconf example rpc input key list without key (should fail)"
|
||||
expecteof_netconf "$clixon_netconf -qef $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><example xmlns=\"urn:example:clixon\"><x>mandatory</x>$LIST</example></rpc>" "" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>missing-element</error-tag><error-info><bad-element>uk</bad-element></error-info><error-severity>error</error-severity><error-message>Mandatory key in 'list u1' in clixon-example.yang:62</error-message></rpc-error></rpc-reply>"
|
||||
new "netconf example rpc input key list without key (should fail) XXX"
|
||||
expecteof_netconf "$clixon_netconf -qef $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><example xmlns=\"urn:example:clixon\"><x>mandatory</x>$LIST</example></rpc>" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>missing-element</error-tag><error-info><bad-element>uk</bad-element></error-info><error-severity>error</error-severity><error-message>Mandatory key in 'list u1' in clixon-example.yang"
|
||||
|
||||
LIST='<u1 xmlns="urn:example:clixon"><uk>bar</uk><val>1</val></u1><u1 xmlns="urn:example:clixon"><uk>bar</uk><val>2</val></u1>'
|
||||
new "netconf example rpc input list with non-unique keys (should fail)"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue