diff --git a/CHANGELOG.md b/CHANGELOG.md index c82bd1bb..7bc20083 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ Expected: October 2024 ### Features +* Refactoring of schema mount-points + * Add new top-level `Y_MOUNTS` and add top-level yangs and mountpoints in yspecs * New `clixon-autocli@2024-08-01.yang` revision - Added: disable operation for module rules * Optimize YANG memory diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index 008807b4..3b1ff5bb 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -91,7 +91,6 @@ static int backend_terminate(clixon_handle h) { - yang_stmt *yspec; char *pidfile = clicon_backend_pidfile(h); int sockfamily = clicon_sock_family(h); char *sockpath = clicon_sock_str(h); @@ -113,14 +112,7 @@ backend_terminate(clixon_handle h) /* Free changelog */ if ((x = clicon_xml_changelog_get(h)) != NULL) xml_free(x); - if ((yspec = clicon_dbspec_yang(h)) != NULL){ - ys_free(yspec); - } yang_exit(h); - if ((yspec = clicon_config_yang(h)) != NULL) - ys_free(yspec); - if ((yspec = clicon_nacm_ext_yang(h)) != NULL) - ys_free(yspec); if ((nsctx = clicon_nsctx_global_get(h)) != NULL) cvec_free(nsctx); clicon_data_cvec_del(h, "netconf-statistics"); @@ -229,7 +221,7 @@ nacm_load_external(clixon_handle h) clixon_err(OE_UNIX, errno, "configure file: %s", filename); return -1; } - if ((yspec = yspec_new()) == NULL) + if ((yspec = yspec_new(h, YANG_NACM_TOP)) == NULL) goto done; if (yang_spec_parse_module(h, "ietf-netconf-acm", NULL, yspec) < 0) goto done; @@ -240,8 +232,6 @@ nacm_load_external(clixon_handle h) clixon_err(OE_XML, 0, "No xml tree in %s", filename); goto done; } - if (clicon_nacm_ext_yang_set(h, yspec) < 0) - goto done; if (clicon_nacm_ext_set(h, xt) < 0) goto done; @@ -617,7 +607,6 @@ main(int argc, clixon_log_init(h, __PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst); clixon_debug_init(h, dbg); yang_init(h); - /* Find and read configfile */ if (clicon_options_main(h) < 0){ if (help) @@ -836,14 +825,13 @@ main(int argc, * Note, loads yang -> extensions -> plugins */ nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE"); - if (nacm_mode && strcmp(nacm_mode, "external") == 0) + if (nacm_mode && strcmp(nacm_mode, "external") == 0){ if (nacm_load_external(h) < 0) goto done; - - /* Create top-level yang spec and store as option */ - if ((yspec = yspec_new()) == NULL) + } + /* Create top-level data yangs */ + if ((yspec = yspec_new(h, YANG_DATA_TOP)) == NULL) goto done; - clicon_dbspec_yang_set(h, yspec); /* Load backend plugins before yangs are loaded (eg extension callbacks) */ if ((dir = clicon_backend_dir(h)) != NULL && diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index ff88759b..ebb0cad4 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -170,7 +170,6 @@ cli_history_save(clixon_handle h) static int cli_terminate(clixon_handle h) { - yang_stmt *yspec; cvec *nsctx; cxobj *x; @@ -178,11 +177,7 @@ cli_terminate(clixon_handle h) clixon_exit_set(1); if (clicon_data_get(h, "session-transport", NULL) == 0) clicon_rpc_close_session(h); - if ((yspec = clicon_dbspec_yang(h)) != NULL) - ys_free(yspec); yang_exit(h); - if ((yspec = clicon_config_yang(h)) != NULL) - ys_free(yspec); if ((nsctx = clicon_nsctx_global_get(h)) != NULL) cvec_free(nsctx); if ((x = clicon_conf_xml(h)) != NULL) @@ -850,9 +845,8 @@ main(int argc, /* Set default namespace according to CLICON_NAMESPACE_NETCONF_DEFAULT */ xml_nsctx_namespace_netconf_default(h); /* Create top-level and store as option */ - if ((yspec = yspec_new()) == NULL) + if ((yspec = yspec_new(h, YANG_DATA_TOP)) == NULL) goto done; - clicon_dbspec_yang_set(h, yspec); /* Load Yang modules * 1. Load a yang module as a specific absolute filename */ diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index 53349478..a3232a47 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -575,7 +575,6 @@ send_hello(clixon_handle h, static int netconf_terminate(clixon_handle h) { - yang_stmt *yspec; cvec *nsctx; cxobj *x; @@ -584,10 +583,6 @@ netconf_terminate(clixon_handle h) /* Delete all plugins, and RPC callbacks */ clixon_plugin_module_exit(h); clicon_rpc_close_session(h); - if ((yspec = clicon_dbspec_yang(h)) != NULL) - ys_free(yspec); - if ((yspec = clicon_config_yang(h)) != NULL) - ys_free(yspec); yang_exit(h); if ((nsctx = clicon_nsctx_global_get(h)) != NULL) cvec_free(nsctx); @@ -874,9 +869,8 @@ main(int argc, if (yang_metadata_init(h) < 0) goto done; /* Create top-level yang spec and store as option */ - if ((yspec = yspec_new()) == NULL) + if ((yspec = yspec_new(h, YANG_DATA_TOP)) == NULL) goto done; - clicon_dbspec_yang_set(h, yspec); /* Load netconf plugins before yangs are loaded (eg extension callbacks) */ if ((dir = clicon_netconf_dir(h)) != NULL && diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c index 5cd57bb0..1b830f21 100644 --- a/apps/restconf/restconf_lib.c +++ b/apps/restconf/restconf_lib.c @@ -355,7 +355,6 @@ get_user_cookie(char *cookiestr, int restconf_terminate(clixon_handle h) { - yang_stmt *yspec; cvec *nsctx; cxobj *x; int fs; /* fgcx socket */ @@ -366,10 +365,6 @@ restconf_terminate(clixon_handle h) /* Delete all plugins, and RPC callbacks */ clixon_plugin_module_exit(h); clicon_rpc_close_session(h); - if ((yspec = clicon_dbspec_yang(h)) != NULL) - ys_free(yspec); - if ((yspec = clicon_config_yang(h)) != NULL) - ys_free(yspec); yang_exit(h); if ((nsctx = clicon_nsctx_global_get(h)) != NULL) cvec_free(nsctx); diff --git a/apps/restconf/restconf_main_fcgi.c b/apps/restconf/restconf_main_fcgi.c index 58c17eae..7c21c891 100644 --- a/apps/restconf/restconf_main_fcgi.c +++ b/apps/restconf/restconf_main_fcgi.c @@ -498,9 +498,8 @@ main(int argc, goto done; /* Create top-level yang spec and store as option */ - if ((yspec = yspec_new()) == NULL) + if ((yspec = yspec_new(h, YSPEC_DATA_TOP)) == NULL) goto done; - clicon_dbspec_yang_set(h, yspec); /* Initialize plugin module by creating a handle holding plugin and callback lists */ if (clixon_plugin_module_init(h) < 0) diff --git a/apps/restconf/restconf_main_native.c b/apps/restconf/restconf_main_native.c index 9da499ca..76c69880 100644 --- a/apps/restconf/restconf_main_native.c +++ b/apps/restconf/restconf_main_native.c @@ -967,9 +967,8 @@ restconf_clixon_init(clixon_handle h, if (yang_metadata_init(h) < 0) goto done; /* Create top-level yang spec and store as option */ - if ((yspec = yspec_new()) == NULL) + if ((yspec = yspec_new(h, YANG_DATA_TOP)) == NULL) goto done; - clicon_dbspec_yang_set(h, yspec); /* Load restconf plugins before yangs are loaded (eg extension callbacks) */ if ((dir = clicon_restconf_dir(h)) != NULL) diff --git a/apps/snmp/snmp_main.c b/apps/snmp/snmp_main.c index b9df58f5..a7d6601b 100644 --- a/apps/snmp/snmp_main.c +++ b/apps/snmp/snmp_main.c @@ -122,10 +122,6 @@ snmp_terminate(clixon_handle h) x = NULL; } clicon_rpc_close_session(h); - if ((yspec = clicon_dbspec_yang(h)) != NULL) - ys_free(yspec); - if ((yspec = clicon_config_yang(h)) != NULL) - ys_free(yspec); yang_exit(h); if ((nsctx = clicon_nsctx_global_get(h)) != NULL) cvec_free(nsctx); @@ -524,9 +520,8 @@ main(int argc, goto done; /* Create top-level yang spec and store as option */ - if ((yspec = yspec_new()) == NULL) + if ((yspec = yspec_new(h, YANG_DATA_TOP)) == NULL) goto done; - clicon_dbspec_yang_set(h, yspec); /* Load Yang modules * 1. Load a yang module as a specific absolute filename */ diff --git a/lib/clixon/clixon_data.h b/lib/clixon/clixon_data.h index 320d2c98..3871666d 100644 --- a/lib/clixon/clixon_data.h +++ b/lib/clixon/clixon_data.h @@ -65,14 +65,14 @@ int clicon_data_int_get(clixon_handle h, const char *name); int clicon_data_int_set(clixon_handle h, const char *name, int val); int clicon_data_int_del(clixon_handle h, const char *name); +yang_stmt *clixon_yang_mounts_get(clixon_handle h); +int clixon_yang_mounts_set(clixon_handle h, yang_stmt *ys); + yang_stmt * clicon_dbspec_yang(clixon_handle h); -int clicon_dbspec_yang_set(clixon_handle h, yang_stmt *ys); yang_stmt * clicon_config_yang(clixon_handle h); -int clicon_config_yang_set(clixon_handle h, yang_stmt *ys); yang_stmt * clicon_nacm_ext_yang(clixon_handle h); -int clicon_nacm_ext_yang_set(clixon_handle h, yang_stmt *ys); cvec *clicon_nsctx_global_get(clixon_handle h); int clicon_nsctx_global_set(clixon_handle h, cvec *nsctx); diff --git a/lib/clixon/clixon_yang.h b/lib/clixon/clixon_yang.h index 3fccfa4e..d8913c9d 100644 --- a/lib/clixon/clixon_yang.h +++ b/lib/clixon/clixon_yang.h @@ -98,6 +98,11 @@ * may be different from orig, therefore do not use link to * original. May also be due to deviations of derived trees */ +/*! Names of top-level data YANGs + */ +#define YANG_DATA_TOP "data" /* "dbspec" */ +#define YANG_CONFIG_TOP "config" +#define YANG_NACM_TOP "nacm_ext_yang" /* * Types @@ -110,6 +115,7 @@ * - Dont want to expose a generated yacc file to the API * - Cant use the symbols in this file because yacc needs token definitions * - Use 0 as no keyword --> therefore start enumeration with 1. + * @see ykmap for string/symbol mapping */ enum rfc_6020{ Y_ACTION = 1, @@ -181,7 +187,9 @@ enum rfc_6020{ Y_WHEN, /* See also ys_when_xpath / ys_when_nsc */ Y_YANG_VERSION, Y_YIN_ELEMENT, - Y_SPEC /* XXX: NOTE NOT YANG STATEMENT, reserved for top level spec */ + /* Note, from here not actual yang statement from the RFC */ + Y_MOUNTS, /* Top-level all mounts */ + Y_SPEC /* Specifications on top, config or mount-points */ }; /* Type used to group yang nodes used in some functions @@ -241,11 +249,11 @@ typedef enum validate_level_t validate_level; /* Access functions */ int yang_len_get(yang_stmt *ys); yang_stmt *yang_child_i(yang_stmt *ys, int i); - yang_stmt *yang_parent_get(yang_stmt *ys); enum rfc_6020 yang_keyword_get(yang_stmt *ys); char *yang_argument_get(yang_stmt *ys); int yang_argument_set(yang_stmt *ys, char *arg); +int yang_argument_dup(yang_stmt *ys, char *arg); yang_stmt *yang_orig_get(yang_stmt *ys); int yang_orig_set(yang_stmt *ys, yang_stmt *y0); cg_var *yang_cv_get(yang_stmt *ys); @@ -277,7 +285,7 @@ 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 *yspec_new(clixon_handle h, char *name); yang_stmt *ys_new(enum rfc_6020 keyw); yang_stmt *ys_prune(yang_stmt *yp, int i); int ys_prune_self(yang_stmt *ys); @@ -295,6 +303,7 @@ int ys_module_by_xml(yang_stmt *ysp, struct xml *xt, yang_stmt **ymodp); yang_stmt *ys_module(yang_stmt *ys); int ys_real_module(yang_stmt *ys, yang_stmt **ymod); yang_stmt *ys_spec(yang_stmt *ys); +yang_stmt *ys_mounts(yang_stmt *ys); yang_stmt *yang_find(yang_stmt *yn, int keyword, const char *argument); yang_stmt *yang_find_datanode(yang_stmt *yn, char *argument); yang_stmt *yang_find_schemanode(yang_stmt *yn, char *argument); diff --git a/lib/clixon/clixon_yang_module.h b/lib/clixon/clixon_yang_module.h index e55e14b6..f8fd069f 100644 --- a/lib/clixon/clixon_yang_module.h +++ b/lib/clixon/clixon_yang_module.h @@ -79,6 +79,6 @@ yang_stmt *yang_find_module_by_name_revision(yang_stmt *yspec, const char *name, yang_stmt *yang_find_module_by_name(yang_stmt *yspec, char *name); int yang_metadata_annotation_check(cxobj *x, yang_stmt *ymod, int *ismeta); int yang_metadata_init(clixon_handle h); -int yang_lib2yspec(clixon_handle h, cxobj *yanglib,yang_stmt *yspec); +int yang_lib2yspec(clixon_handle h, cxobj *yanglib, yang_stmt *yspec); #endif /* _CLIXON_YANG_MODULE_H_ */ diff --git a/lib/src/clixon_client.c b/lib/src/clixon_client.c index 89cdf73c..8de6777d 100644 --- a/lib/src/clixon_client.c +++ b/lib/src/clixon_client.c @@ -128,6 +128,7 @@ clixon_client_init(const char *config_file) /* Set clixon config file - reuse the one in the main installation */ clicon_option_str_set(h, "CLICON_CONFIGFILE", config_file?(char*)config_file:CLIXON_DEFAULT_CONFIG); + yang_init(h); /* Find, read and parse configfile */ if (clicon_options_main(h) < 0) return NULL; diff --git a/lib/src/clixon_data.c b/lib/src/clixon_data.c index a3aad207..201e8ce4 100644 --- a/lib/src/clixon_data.c +++ b/lib/src/clixon_data.c @@ -318,7 +318,34 @@ clicon_data_int_del(clixon_handle h, return clicon_hash_del(cdat, (char*)name); } -/*! Get data yangspec, yspec +/*! Get top-level yang mounts + * + * @param[in] h Clixon handle + * @retval ymnts Yang mounts + */ +yang_stmt * +clixon_yang_mounts_get(clixon_handle h) +{ + yang_stmt *ys = NULL; + + if (clicon_ptr_get(h, "yang-mounts", (void**)&ys) < 0) + return NULL; + return ys; +} + +/*! Set top-level yang mounts + * + * @param[in] h Clixon handle + * @param[in] yspec Yang spec (malloced pointer) + */ +int +clixon_yang_mounts_set(clixon_handle h, + yang_stmt *ys) +{ + return clicon_ptr_set(h, "yang-mounts", ys); +} + +/*! Get data yangspec, yspec * * @param[in] h Clixon handle * @retval yspec Yang spec @@ -328,25 +355,13 @@ yang_stmt * clicon_dbspec_yang(clixon_handle h) { yang_stmt *ys = NULL; + yang_stmt *ymounts = NULL; - if (clicon_ptr_get(h, "dbspec_yang", (void**)&ys) < 0) - return NULL; + if ((ymounts = clixon_yang_mounts_get(h)) != NULL) + ys = yang_find(ymounts, Y_SPEC, YANG_DATA_TOP); return ys; } -/*! Set yang specification for application specifications - * - * @param[in] h Clixon handle - * @param[in] yspec Yang spec (malloced pointer) - * @see clicon_config_yang_set for the configuration yang - */ -int -clicon_dbspec_yang_set(clixon_handle h, - yang_stmt *ys) -{ - return clicon_ptr_set(h, "dbspec_yang", ys); -} - /*! Get YANG specification for clixon config (separate from application yangs) * * @param[in] h Clixon handle @@ -356,26 +371,14 @@ clicon_dbspec_yang_set(clixon_handle h, yang_stmt * clicon_config_yang(clixon_handle h) { + yang_stmt *ymounts = NULL; yang_stmt *ys = NULL; - if (clicon_ptr_get(h, "control_yang", (void**)&ys) < 0) - return NULL; + if ((ymounts = clixon_yang_mounts_get(h)) != NULL) + ys = yang_find(ymounts, Y_SPEC, YANG_CONFIG_TOP); return ys; } -/*! Set yang specification for configuration - * - * @param[in] h Clixon handle - * @param[in] yspec Yang spec (malloced pointer) - * @see clicon_dbspec_yang_set for the application specs - */ -int -clicon_config_yang_set(clixon_handle h, - yang_stmt *ys) -{ - return clicon_ptr_set(h, "control_yang", ys); -} - /*! Get YANG specification for external NACM (separate from application yangs) * * @param[in] h Clixon handle @@ -385,26 +388,14 @@ clicon_config_yang_set(clixon_handle h, yang_stmt * clicon_nacm_ext_yang(clixon_handle h) { + yang_stmt *ymounts = NULL; yang_stmt *ys = NULL; - if (clicon_ptr_get(h, "nacm_ext_yang", (void**)&ys) < 0) - return NULL; + if ((ymounts = clixon_yang_mounts_get(h)) != NULL) + ys = yang_find(ymounts, Y_SPEC, YANG_NACM_TOP); return ys; } -/*! Set yang specification for external NACM - * - * @param[in] h Clixon handle - * @param[in] yspec Yang spec (malloced pointer) - * @see clicon_nacm_ext_set for external NACM XML - */ -int -clicon_nacm_ext_yang_set(clixon_handle h, - yang_stmt *ys) -{ - return clicon_ptr_set(h, "nacm_ext_yang", ys); -} - /*! Get Global "canonical" namespace context * * Canonical: use prefix and namespace specified in the yang modules. diff --git a/lib/src/clixon_datastore_read.c b/lib/src/clixon_datastore_read.c index 5e421949..03641f79 100644 --- a/lib/src/clixon_datastore_read.c +++ b/lib/src/clixon_datastore_read.c @@ -702,7 +702,7 @@ xmldb_readfile(clixon_handle h, * Same ymodules are inserted into yspec1, ie pointers only */ if (needclone && xmodfile){ - if ((yspec1 = yspec_new()) == NULL) + if ((yspec1 = yspec_new(h, "tmp")) == NULL) goto done; xmsd = NULL; while ((xmsd = xml_child_each(xmodfile, xmsd, CX_ELMNT)) != NULL) { diff --git a/lib/src/clixon_options.c b/lib/src/clixon_options.c index 6791bb8f..8b66f81b 100644 --- a/lib/src/clixon_options.c +++ b/lib/src/clixon_options.c @@ -639,7 +639,7 @@ clicon_options_main(clixon_handle h) char *yangspec = "clixon-config"; /* Create configure yang-spec */ - if ((yspec = yspec_new()) == NULL) + if ((yspec = yspec_new(h, YANG_CONFIG_TOP)) == NULL) goto done; /* * Set configure file if not set by command-line above @@ -708,19 +708,13 @@ clicon_options_main(clixon_handle h) clixon_err(OE_CFG, 0, "Config file %s: did not find corresponding Yang specification\nHint: File does not begin with: or clixon-config.yang not found?", configfile, CLIXON_CONF_NS); goto done; } - /* Set yang config spec (must store to free at exit, since conf_xml below uses it) */ - if (clicon_config_yang_set(h, yspec) < 0) - goto done; yspec = NULL; /* Set clixon_conf pointer to handle */ xml_sort(xconfig); if (clicon_conf_xml_set(h, xconfig) < 0) goto done; - retval = 0; done: - if (yspec) - ys_free(yspec); if (extraconfdir) free(extraconfdir); return retval; diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 1b44b847..865a99cd 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -238,20 +238,12 @@ yang_argument_get(yang_stmt *ys) return ys->ys_argument; } -/* - * Note on cvec on XML nodes: - * 1. It is always created in xml_new. It could be lazily created on use to save a little memory - * 2. Only some yang statements use the cvec, as follows: - * 2a. ranges and lengths: [min, max] - * 2b. list: keys - * 2c. identity types: derived instances: identityrefs, save : - * 2d. type: leafref types: derived instances. - */ /*! Set yang argument, not not copied * * @param[in] ys Yang statement node * @param[in] arg Argument, note must be malloced * Typically only done at parsing / initiation + * @see yang_argument_dup */ int yang_argument_set(yang_stmt *ys, @@ -261,6 +253,25 @@ yang_argument_set(yang_stmt *ys, return 0; } +/*! Set yang argument, copied + * + * @param[in] ys Yang statement node + * @param[in] arg Argument, is copied + */ +int +yang_argument_dup(yang_stmt *ys, + char *arg) +{ + char *dup; + + if ((dup = strdup(arg)) == NULL){ + clixon_err(OE_UNIX, errno, "strdup"); + return -1; + } + ys->ys_argument = dup; /* not strdup/copied */ + return 0; +} + /*! Get original back-pointer if node is grouping or augmented * * Defined only if this statement was created as part of a uses/grouping or augment expansion @@ -561,13 +572,13 @@ yang_when_xpath_get(yang_stmt *ys, * Ie, for yang structures like: augment { when ; ... } * Inserts new yang nodes at with this special "when" struct (not yang node) * @param[in] ys Yang statement - * @param[out] xpath - * @param[out] nsc + * @param[out] xpath Free after use + * @param[out] nsc Free with cvec_free */ int yang_when_canonical_xpath_get(yang_stmt *ys, - char **xpath, - cvec **nsc) + char **xpath, + cvec **nsc) { int retval = -1; yang_stmt *ywhen; @@ -836,24 +847,34 @@ yang_stats(yang_stmt *yt, /* stats end */ -/*! Create new yang specification +/*! Create new yang specification, addd as child to top-level yang_mounts * * @retval yspec Free with ys_free() * @retval NULL Error */ yang_stmt * -yspec_new(void) +yspec_new(clixon_handle h, + char *name) { + yang_stmt *ymounts; yang_stmt *yspec; - if ((yspec = malloc(sizeof(*yspec))) == NULL){ - clixon_err(OE_YANG, errno, "malloc"); - return NULL; + if ((ymounts = clixon_yang_mounts_get(h)) == NULL){ + clixon_err(OE_YANG, 0, "Yang-mounts not created"); + goto done; } - memset(yspec, 0, sizeof(*yspec)); - yspec->ys_keyword = Y_SPEC; - _stats_yang_nr++; + if ((yspec = ys_new(Y_SPEC)) == NULL) + goto done; + if (yang_argument_dup(yspec, name) < 0) + goto done; + if (yn_insert(ymounts, yspec) < 0) + goto done; + /* Special trick for shared yspecs */ + if (yang_cvec_add(yspec, CGV_STRING, name) < 0) + goto done; return yspec; + done: + return NULL; } /*! Create new yang node/statement given size @@ -1357,7 +1378,6 @@ yn_insert1(yang_stmt *ys_parent, * ...ynext... * } * @endcode - * @see yn_each */ yang_stmt * yn_iter(yang_stmt *yparent, @@ -2155,7 +2175,28 @@ ys_spec(yang_stmt *ys) ys = (yang_stmt*)yn; } /* Here it is either NULL or is a typedef-kind yang-stmt */ - return (yang_stmt*)ys; + return ys; +} + +/*! Find top of tree, the yang specification from within the tree + * + * @param[in] ys Any yang statement in a yang tree + * @retval yspec The top yang specification + * @see ys_module + * @see yang_augment_node where shortcut is set for augment + * @see yang_myroot for first node under (sub)module + */ +yang_stmt * +ys_mounts(yang_stmt *ys) +{ + yang_stmt *yn; + + while (ys != NULL && ys->ys_keyword != Y_MOUNTS){ + yn = ys->ys_parent; + ys = (yang_stmt*)yn; + } + /* Here it is either NULL or is a typedef-kind yang-stmt */ + return ys; } /*! String is quoted if it contains space or tab, needs double '' @@ -4096,18 +4137,14 @@ yang_type_cache_free(yang_type_cache *ycache) */ yang_stmt * yang_anydata_add(yang_stmt *yp, - char *name0) + char *name) { yang_stmt *ys = NULL; - char *name = NULL; if ((ys = ys_new(Y_ANYDATA)) == NULL) goto done; - if ((name = strdup(name0)) == NULL){ - clixon_err(OE_UNIX, errno, "strdup"); + if (yang_argument_dup(ys, name) < 0) goto done; - } - yang_argument_set(ys, name); if (yp && yn_insert(yp, ys) < 0){ /* Insert into hierarchy */ ys = NULL; goto done; @@ -4399,6 +4436,7 @@ yang_init(clixon_handle h) { int retval = -1; map_ptr2ptr *mp; + yang_stmt *ymounts; if ((mp = calloc(1, sizeof(*mp))) == NULL){ clixon_err(OE_UNIX, errno, "calloc"); @@ -4412,6 +4450,10 @@ yang_init(clixon_handle h) _yang_mymodule_map = mp; if (yang_cardinality_init(h) < 0) goto done; + if ((ymounts = ys_new(Y_MOUNTS)) == NULL) + goto done; + if (clixon_yang_mounts_set(h, ymounts) < 0) + goto done; retval = 0; done: return retval; @@ -4424,6 +4466,8 @@ yang_init(clixon_handle h) int yang_exit(clixon_handle h) { + yang_stmt *ymounts; + if (_yang_when_map != NULL) { free(_yang_when_map); _yang_when_map = NULL; @@ -4432,5 +4476,9 @@ yang_exit(clixon_handle h) free(_yang_mymodule_map); _yang_mymodule_map = NULL; } + if ((ymounts = clixon_yang_mounts_get(h)) != NULL){ + ys_free(ymounts); + } + clixon_yang_mounts_set(h, NULL); return 0; } diff --git a/lib/src/clixon_yang_internal.h b/lib/src/clixon_yang_internal.h index d6dec489..edc66c77 100644 --- a/lib/src/clixon_yang_internal.h +++ b/lib/src/clixon_yang_internal.h @@ -104,10 +104,12 @@ struct yang_stmt { Y_LENGTH: length_min, length_max Y_LIST: vector of keys Y_RANGE: range_min, range_max + Y_SPEC: shared mount-point xpaths Y_TYPE: store all derived types as : list Y_UNIQUE: vector of descendant schema node ids - # Y_UNKNOWN: app-dep: yang-mount-points + Y_UNKNOWN: app-dep: yang-mount-points */ + yang_stmt *ys_orig; /* Pointer to original (for uses/augment copies) */ union { /* Depends on ys_keyword */ rpc_callback_t *ysu_action_cb; /* Y_ACTION: Action callback list*/ diff --git a/lib/src/clixon_yang_schema_mount.c b/lib/src/clixon_yang_schema_mount.c index 185e2033..f1065739 100644 --- a/lib/src/clixon_yang_schema_mount.c +++ b/lib/src/clixon_yang_schema_mount.c @@ -63,6 +63,7 @@ * The calls in this code are: * - yang_schema_mount_point(): Is ymnt a yang mount-point? (ymnt) * - yang_mount_get(): ymnt + xpath -> yspec + * - yang_mount_get2(): ymnt + xpath -> yspec # NEW * - yang_mount_set(): ymnt + xpath -> yspec * - xml_yang_mount_get(): xmnt-> yspec * - xml_yang_mount_set(): xmnt -> yspec @@ -188,21 +189,31 @@ yang_schema_mount_point(yang_stmt *y) * @retval 0 OK */ int -yang_mount_get(yang_stmt *y, +yang_mount_get(yang_stmt *ys, char *xpath, - yang_stmt **yspec) + yang_stmt **yspecp) { - cvec *cvv; - cg_var *cv; + int retval = 1; + yang_stmt *ymounts; + yang_stmt *yspec = NULL; + int inext; - clixon_debug(CLIXON_DBG_YANG | CLIXON_DBG_DETAIL, "%s %p", xpath, y); - if ((cvv = yang_cvec_get(y)) != NULL && - (cv = cvec_find(cvv, xpath)) != NULL && - yspec) - *yspec = cv_void_get(cv); - else - *yspec = NULL; - return 0; + if ((ymounts = ys_mounts(ys)) == NULL){ + clixon_err(OE_YANG, ENOENT, "Top-level yang mounts not found"); + goto done; + } + inext = 0; + while ((yspec = yn_iter(ymounts, &inext)) != NULL) { + if (yang_keyword_get(yspec) != Y_SPEC || + yang_cvec_get(yspec) == NULL) + continue; + if (cvec_find(yang_cvec_get(yspec), xpath) != NULL) + break; + } + *yspecp = yspec; + retval = 0; + done: + return retval; } /*! Get any yspec of a mount-point, special function @@ -235,7 +246,7 @@ yang_mount_get_yspec_any(yang_stmt *y, /*! Set yangspec mount-point on yang node containing extension * - * Mount-points are stored in yang cvec in container/list node taht is a mount-point + * Mount-points are stored in yang cvec in container/list node that is a mount-point * as defined in yang_schema_mount_point() * @param[in] y Yang container/list containing unknown node * @param[in] xpath Key for yspec on y, in canonical form @@ -285,7 +296,7 @@ yang_mount_set(yang_stmt *y, * @param[in] h Clixon handle * @param[in] xmnt XML mount-point * @param[out] ymnt YANG mount-point - * @param[out] xpath Canonical XPath from XML top-level to xmnt + * @param[out] xpath Canonical XPath from XML top-level to xmnt, free after use * @retval 1 OK, xmnt is a mount-point with ymnt and xpath returned * @retval 0 OK, xmnt is not a mount point * @retval -1 Error @@ -395,7 +406,7 @@ xml_yang_mount_set(clixon_handle h, yang_stmt *yspec) { int retval = -1; - yang_stmt *ymnt; + yang_stmt *ymnt = NULL; char *xpath = NULL; int ret; @@ -897,6 +908,7 @@ yang_schema_yanglib_parse_mount(clixon_handle h, yang_stmt *yspec = NULL; int ret; int shared = 0; + char *xpath = NULL; /* 1. Get modstate (xyanglib) of node: xyanglib, by querying backend state (via callback) * XXX this xyanglib is not proper RFC8525, submodules appear as modules WHY? @@ -911,10 +923,17 @@ yang_schema_yanglib_parse_mount(clixon_handle h, goto done; if (yspec) shared++; + } + /* XXX done later too */ + if ((ret = yang_mount_xmnt2ymnt_xpath(h, xt, NULL, &xpath)) < 0) + goto done; + if (ret == 0){ + clixon_err(OE_YANG, 0, "Mapping xmnt to ymnt and xpath"); + goto done; } if (yspec == NULL){ /* Parse it and set mount-point */ - if ((yspec = yspec_new()) == NULL) + if ((yspec = yspec_new(h, xpath)) == NULL) goto done; clixon_debug(CLIXON_DBG_YANG, "new yang-spec: %p", yspec); if ((ret = yang_lib2yspec(h, xyanglib, yspec)) < 0) @@ -927,10 +946,14 @@ yang_schema_yanglib_parse_mount(clixon_handle h, if (xml_yang_mount_set(h, xt, yspec) < 0) goto done; if (shared) - yang_ref_inc(yspec); + if (yang_cvec_add(yspec, CGV_STRING, xpath) < 0) + goto done; + yang_ref_inc(yspec); yspec = NULL; retval = 1; done: + if (xpath) + free(xpath); if (yspec) ys_free(yspec); if (xyanglib)