From af29a0f9748e0b4ebec77b460051d1f360f06638 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sun, 28 Jul 2024 19:41:35 +0200 Subject: [PATCH] Added YANG_SPEC_LINENR compile-time option --- CHANGELOG.md | 5 + apps/cli/cli_generate.c | 2 +- include/clixon_custom.h | 9 + lib/clixon/clixon_yang.h | 22 +- lib/src/clixon_validate.c | 25 +- lib/src/clixon_yang.c | 469 +++++++++++++++++++++++--------- lib/src/clixon_yang_internal.h | 124 ++++++--- lib/src/clixon_yang_parse_lib.c | 56 +++- lib/src/clixon_yang_type.c | 8 +- test/test_identity.sh | 2 +- test/test_netconf.sh | 2 +- test/test_openconfig.sh | 2 +- test/test_restconf_op.sh | 4 +- test/test_rpc.sh | 4 +- 14 files changed, 532 insertions(+), 202 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 784546ad..bdbd2af7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/apps/cli/cli_generate.c b/apps/cli/cli_generate.c index 9d84e097..62ca7e89 100644 --- a/apps/cli/cli_generate.c +++ b/apps/cli/cli_generate.c @@ -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", diff --git a/include/clixon_custom.h b/include/clixon_custom.h index b4a58b42..92fc21b7 100644 --- a/include/clixon_custom.h +++ b/include/clixon_custom.h @@ -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 diff --git a/lib/clixon/clixon_yang.h b/lib/clixon/clixon_yang.h index 914d884b..bc4ac96c 100644 --- a/lib/clixon/clixon_yang.h +++ b/lib/clixon/clixon_yang.h @@ -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,22 +257,29 @@ 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); -int yang_stats(yang_stmt *y, enum rfc_6020 keyw, uint64_t *nrp, size_t *szp); +int yang_stats_global(uint64_t *nr); +int yang_stats(yang_stmt *y, enum rfc_6020 keyw, uint64_t *nrp, size_t *szp); /* 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); diff --git a/lib/src/clixon_validate.c b/lib/src/clixon_validate.c index e6192797..cb7a95cd 100644 --- a/lib/src/clixon_validate.c +++ b/lib/src/clixon_validate.c @@ -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); diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 5ccfd0d8..785534fa 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -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 @@ -455,13 +468,19 @@ int yang_when_xpath_set(yang_stmt *ys, char *xpath) { - int retval = -1; + 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 @@ -497,9 +521,15 @@ int yang_when_nsc_set(yang_stmt *ys, cvec *nsc) { - int retval = -1; + 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,35 +692,48 @@ 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; - 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 += sizeof(struct yang_type_cache); - if (yc->yc_cvv) - sz += cvec_size(yc->yc_cvv); - if (yc->yc_patterns) - sz += cvec_size(yc->yc_patterns); - if (yc->yc_regexps) - sz += cvec_size(yc->yc_regexps); + if (yang_flag_get(ys, YANG_FLAG_EXTENDED) == 0x0) + sz += sizeof(struct yang_stmt_extended); + else + sz += sizeof(struct yang_stmt); + 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); + if (yc->yc_patterns) + sz += cvec_size(yc->yc_patterns); + if (yc->yc_regexps) + sz += cvec_size(yc->yc_regexps); + } + break; + case Y_MODULE: + case Y_SUBMODULE: + if (ys->ys_filename) + sz += strlen(ys->ys_filename) + 1; + break; + default: + break; } - 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; 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() - * @retval NULL Error + * @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,25 +899,39 @@ 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); - while((rc = ys->ys_action_cb) != NULL) { - DELQ(rc, ys->ys_action_cb, rpc_callback_t *); - if (rc->rc_namespace) - free(rc->rc_namespace); - if (rc->rc_name) - free(rc->rc_name); - free(rc); + 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) + free(rc->rc_namespace); + if (rc->rc_name) + 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); @@ -892,7 +1067,74 @@ yn_realloc(yang_stmt *yn) return 0; } -/*! Copy yang statement recursively from old to new +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) * @param[in] yold Old existing yang statement (from) @@ -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"); - 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; - } - } + if (ys_cp_one(ynew, yold) < 0) + goto done; for (i=0; iys_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,25 +3847,25 @@ 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_stmt *resolved, - int options, - cvec *cvv, - cvec *patterns, - uint8_t fraction) +yang_type_cache_set2(yang_stmt *ys, + yang_stmt *resolved, + int options, + cvec *cvv, + cvec *patterns, + uint8_t fraction) { 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; diff --git a/lib/src/clixon_yang_internal.h b/lib/src/clixon_yang_internal.h index 69a376f8..c335f142 100644 --- a/lib/src/clixon_yang_internal.h +++ b/lib/src/clixon_yang_internal.h @@ -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 */ +struct yang_stmt { + /* 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 : 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 : 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 : 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_ */ diff --git a/lib/src/clixon_yang_parse_lib.c b/lib/src/clixon_yang_parse_lib.c index c4eb2a64..ae4c2d1d 100644 --- a/lib/src/clixon_yang_parse_lib.c +++ b/lib/src/clixon_yang_parse_lib.c @@ -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; iys_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 diff --git a/lib/src/clixon_yang_type.c b/lib/src/clixon_yang_type.c index bd3f84ce..bd53b4c3 100644 --- a/lib/src/clixon_yang_type.c +++ b/lib/src/clixon_yang_type.c @@ -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; diff --git a/test/test_identity.sh b/test/test_identity.sh index e88d4806..aa80034c 100755 --- a/test/test_identity.sh +++ b/test/test_identity.sh @@ -292,7 +292,7 @@ new "Netconf set undefined acl-type" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "xundefined" "" "" new "netconf validate fail" -expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "applicationoperation-failederrorIdentityref validation failed, undefined not derived from acl-base in example-my-crypto.yang:[0-9]*" "" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "applicationoperation-failederrorIdentityref 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" "" "" "" diff --git a/test/test_netconf.sh b/test/test_netconf.sh index 22ee0db5..6fdaf391 100755 --- a/test/test_netconf.sh +++ b/test/test_netconf.sh @@ -227,7 +227,7 @@ new "Re-Delete eth/0/0 using none should generate error" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "eth/0/0ex:ethnone " "" "" new "Add interface without key" -expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "ex:ethnone " "applicationmissing-elementnameerrorMandatory key in 'list interface' in ietf-interfaces.yang:[0-9]\+" "" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "ex:ethnone " "applicationmissing-elementnameerrorMandatory key in 'list interface' in ietf-interfaces.yang" new "netconf discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" diff --git a/test/test_openconfig.sh b/test/test_openconfig.sh index 7de6553c..850007c9 100755 --- a/test/test_openconfig.sh +++ b/test/test_openconfig.sh @@ -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 diff --git a/test/test_restconf_op.sh b/test/test_restconf_op.sh index b82a0dc8..d4c0438c 100755 --- a/test/test_restconf_op.sh +++ b/test/test_restconf_op.sh @@ -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" diff --git a/test/test_rpc.sh b/test/test_rpc.sh index 7d1692aa..372e7de2 100755 --- a/test/test_rpc.sh +++ b/test/test_rpc.sh @@ -347,8 +347,8 @@ new "netconf example rpc input list with key" expecteof_netconf "$clixon_netconf -qef $cfg" 0 "$DEFAULTHELLO" "mandatory$LIST" "" "mandatory42$LIST" LIST='bar12' -new "netconf example rpc input key list without key (should fail)" -expecteof_netconf "$clixon_netconf -qef $cfg" 0 "$DEFAULTHELLO" "mandatory$LIST" "" "applicationmissing-elementukerrorMandatory key in 'list u1' in clixon-example.yang:62" +new "netconf example rpc input key list without key (should fail) XXX" +expecteof_netconf "$clixon_netconf -qef $cfg" 0 "$DEFAULTHELLO" "mandatory$LIST" "applicationmissing-elementukerrorMandatory key in 'list u1' in clixon-example.yang" LIST='bar1bar2' new "netconf example rpc input list with non-unique keys (should fail)"