From 1e136bc9df077fcba90e9942e34e9bdd91a33444 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sun, 12 Mar 2023 20:53:48 +0100 Subject: [PATCH] Added clicon_data_init API, and yang_mount_get API Moved dynamic options from options to data API --- apps/backend/backend_commit.c | 4 +- apps/backend/clixon_backend_client.h | 2 +- apps/netconf/netconf_main.c | 12 ++-- lib/clixon/clixon_data.h | 7 +- lib/clixon/clixon_yang_schema_mount.h | 3 + lib/src/clixon_data.c | 59 ++++++++++++++++ lib/src/clixon_datastore_read.c | 4 +- lib/src/clixon_netconf_lib.c | 4 +- lib/src/clixon_options.c | 24 ++++++- lib/src/clixon_xpath_yang.c | 2 + lib/src/clixon_yang_schema_mount.c | 96 +++++++++++++++++++-------- 11 files changed, 174 insertions(+), 43 deletions(-) diff --git a/apps/backend/backend_commit.c b/apps/backend/backend_commit.c index 9d3d3243..f12ad873 100644 --- a/apps/backend/backend_commit.c +++ b/apps/backend/backend_commit.c @@ -177,7 +177,7 @@ startup_common(clicon_handle h, if (clicon_option_bool(h, "CLICON_XMLDB_MODSTATE")) if ((msdiff = modstate_diff_new()) == NULL) goto done; - clicon_debug(1, "Reading startup config from %s", db); + clicon_debug(1, "Reading initial config from %s", db); /* Get the startup datastore WITHOUT binding to YANG, sorting and default setting. * It is done below, later in this function */ @@ -202,6 +202,7 @@ startup_common(clicon_handle h, if (xmldb_get0(h, db, YB_NONE, NULL, "/", 0, 0, &xt, msdiff, &xerr) < 0) goto done; } + clicon_debug_xml(CLIXON_DBG_DETAIL, xt, "startup"); if (msdiff && msdiff->md_status == 0){ // Possibly check for CLICON_XMLDB_MODSTATE clicon_log(LOG_WARNING, "Modstate expected in startup datastore but not found\n" "This may indicate that the datastore is not initialized corrrectly, such as copy/pasted.\n" @@ -439,6 +440,7 @@ startup_commit(clicon_handle h, * edit-config */ xml_name_set(td->td_target, NETCONF_INPUT_CONFIG); + if ((ret = xmldb_put(h, "running", OP_REPLACE, td->td_target, clicon_username_get(h), cbret)) < 0) goto done; diff --git a/apps/backend/clixon_backend_client.h b/apps/backend/clixon_backend_client.h index 04b3f7d4..c972afe7 100644 --- a/apps/backend/clixon_backend_client.h +++ b/apps/backend/clixon_backend_client.h @@ -73,7 +73,7 @@ struct client_entry{ uint32_t ce_out_rpc_errors; /* messages*/ uint32_t ce_out_notifications; /* Outgoing notifications */ }; - +typedef struct client_entry client_entry; /* * Prototypes diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index 6b179061..a35548b5 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -171,7 +171,7 @@ netconf_hello_msg(clicon_handle h, else if (strncmp(body, NETCONF_BASE_CAPABILITY_1_1, strlen(NETCONF_BASE_CAPABILITY_1_1)) == 0 && clicon_option_int(h, "CLICON_NETCONF_BASE_CAPABILITY") > 0){ /* RFC 6241 */ foundbase_11++; - clicon_option_int_set(h, "netconf-framing", NETCONF_SSH_CHUNKED); /* enable chunked enc */ + clicon_data_int_set(h, "netconf-framing", NETCONF_SSH_CHUNKED); /* enable chunked enc */ } } } @@ -208,7 +208,7 @@ netconf_rpc_message(clicon_handle h, cxobj *xc; netconf_framing_type framing; - framing = clicon_option_int(h, "netconf-framing"); + framing = clicon_data_int_get(h, "netconf-framing"); if (_netconf_hello_nr == 0 && clicon_option_bool(h, "CLICON_NETCONF_HELLO_OPTIONAL") == 0){ if (netconf_operation_failed_xml(&xret, "rpc", "Client must send an hello element before any RPC")< 0) @@ -321,7 +321,7 @@ netconf_input_packet(clicon_handle h, clicon_debug(1, "%s", __FUNCTION__); rpcname = xml_name(xreq); rpcprefix = xml_prefix(xreq); - framing = clicon_option_int(h, "netconf-framing"); + framing = clicon_data_int_get(h, "netconf-framing"); if (xml2ns(xreq, rpcprefix, &namespace) < 0) goto done; if (strcmp(rpcname, "rpc") == 0){ @@ -406,7 +406,7 @@ netconf_input_frame(clicon_handle h, clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__); clicon_debug(CLIXON_DBG_MSG, "Recv ext: %s", cbuf_get(cb)); - framing = clicon_option_int(h, "netconf-framing"); + framing = clicon_data_int_get(h, "netconf-framing"); yspec = clicon_dbspec_yang(h); if ((str = strdup(cbuf_get(cb))) == NULL){ clicon_err(OE_UNIX, errno, "strdup"); @@ -582,7 +582,7 @@ netconf_input_cb(int s, for (i=0; i]]> * For now this only applies to external protocol */ - clicon_option_int_set(h, "netconf-framing", NETCONF_SSH_EOM); + clicon_data_int_set(h, "netconf-framing", NETCONF_SSH_EOM); if (clicon_option_bool(h, "CLICON_NETCONF_HELLO_OPTIONAL")){ if (clicon_option_int(h, "CLICON_NETCONF_BASE_CAPABILITY") > 0) /* RFC 6241 */ - clicon_option_int_set(h, "netconf-framing", NETCONF_SSH_CHUNKED); + clicon_data_int_set(h, "netconf-framing", NETCONF_SSH_CHUNKED); } retval = 0; done: diff --git a/lib/src/clixon_options.c b/lib/src/clixon_options.c index c0c98d61..17375a43 100644 --- a/lib/src/clixon_options.c +++ b/lib/src/clixon_options.c @@ -129,6 +129,7 @@ static const map_str2int yang_regexp_map[] = { }; /*! Print registry on file. For debugging. + * * @param[in] h Clicon handle * @param[in] dbglevel Debug level * @retval 0 OK @@ -190,6 +191,7 @@ clicon_option_dump(clicon_handle h, } /*! Open and parse single config file + * * @param[in] filename * @param[in] yspec * @param[out] xconfig Pointer to xml config tree. Should be freed by caller @@ -426,6 +428,7 @@ parse_configfile(clicon_handle h, } /*! Add configuration option overriding file setting + * * Add to clicon_options hash, and to clicon_conf_xml tree * Assumes clicon_conf_xml_set has been called * @param[in] h Clicon handle @@ -579,6 +582,7 @@ clicon_options_main(clicon_handle h) } /*! Check if a clicon option has a value + * * @param[in] h clicon_handle * @param[in] name option name * @retval !=0 option exists @@ -597,8 +601,8 @@ clicon_option_exists(clicon_handle h, * * @param[in] h clicon_handle * @param[in] name option name - * @retval NULL If option not found, or value of option is NULL * @retval string value of option if found + * @retval NULL If option not found, or value of option is NULL * clicon options should be strings. * @note To differentiate the two reasons why NULL may be returned, use function * clicon_option_exists() before the call @@ -615,6 +619,7 @@ clicon_option_str(clicon_handle h, } /*! Set a single string option via handle + * * @param[in] h clicon_handle * @param[in] name option name * @param[in] val option value, must be null-terminated string @@ -646,6 +651,7 @@ clicon_option_str_set(clicon_handle h, * Note that -1 can be both error and value. * This means that it should be used together with clicon_option_exists() and * supply a default value as shown in the example. + * @see clicon_data_int_get for transient values (not clixon config file) */ int clicon_option_int(clicon_handle h, @@ -659,6 +665,7 @@ clicon_option_int(clicon_handle h, } /*! Set option given as int. + * * @param[in] h Clicon handle * @param[in] name Name of option to set * @param[in] val Integer value @@ -707,6 +714,7 @@ clicon_option_bool(clicon_handle h, } /*! Set option given as bool + * * @param[in] h Clicon handle * @param[in] name Name of option to set * @param[in] val Boolean value, 0 or 1 @@ -730,6 +738,7 @@ clicon_option_bool_set(clicon_handle h, } /*! Delete option + * * @param[in] h Clicon handle * @param[in] name Name of option to delete */ @@ -754,6 +763,7 @@ clicon_option_del(clicon_handle h, *-----------------------------------------------------------------*/ /*! Get "do not include keys in cvec" in cli vars callbacks + * * @param[in] h Clicon handle * @retval flag If set, get only vars * @see clixon-config@.yang CLICON_CLI_VARONLY @@ -770,6 +780,7 @@ clicon_cli_varonly(clicon_handle h) } /*! Get family of backend socket: AF_UNIX, AF_INET or AF_INET6 + * * @see clixon-config@.yang CLICON_SOCK_FAMILY * @param[in] h Clicon handle * @retval fam Socket family @@ -792,6 +803,7 @@ clicon_sock_family(clicon_handle h) } /*! Get port for backend socket in case of AF_INET or AF_INET6 + * * @param[in] h Clicon handle * @retval port Socket port * @see clixon-config@.yang CLICON_SOCK_PORT @@ -807,6 +819,7 @@ clicon_sock_port(clicon_handle h) } /*! Set if all configuration changes are committed automatically + * * @param[in] h Clicon handle * @retval flag Autocommit (or not) */ @@ -822,6 +835,7 @@ clicon_autocommit(clicon_handle h) } /*! Which method to boot/start clicon backend + * * @param[in] h Clicon handle * @retval mode Startup mode */ @@ -836,6 +850,7 @@ clicon_startup_mode(clicon_handle h) } /*! Which privileges drop method to use for backend + * * @param[in] h Clicon handle * @retval mode Privileges mode */ @@ -850,6 +865,7 @@ clicon_backend_privileges_mode(clicon_handle h) } /*! Which privileges drop method to use for restconf + * * @param[in] h Clicon handle * @retval mode Privileges mode */ @@ -864,6 +880,7 @@ clicon_restconf_privileges_mode(clicon_handle h) } /*! Which privileges drop method to use + * * @param[in] h Clicon handle * @retval mode Privileges mode */ @@ -878,6 +895,7 @@ clicon_nacm_credentials(clicon_handle h) } /*! Which datastore cache method to use + * * @param[in] h Clicon handle * @retval method Datastore cache method * @see clixon-config@.yang CLICON_DATASTORE_CACHE @@ -894,6 +912,7 @@ clicon_datastore_cache(clicon_handle h) } /*! Which Yang regexp/pattern engine to use + * * @param[in] h Clicon handle * @retval mode Regexp engine to use * @see clixon-config@.yang CLICON_YANG_REGEXP @@ -916,6 +935,7 @@ clicon_yang_regexp(clicon_handle h) *--------------------------------------------------------------------*/ /*! Get quiet mode eg -q option, do not print notifications on stdout + * * @param[in] h Clicon handle * @retval flag quiet mode on or off */ @@ -929,6 +949,7 @@ clicon_quiet_mode(clicon_handle h) } /*! Set quiet mode + * * @param[in] h Clicon handle * @param[in] val Flag value */ @@ -938,4 +959,3 @@ clicon_quiet_mode_set(clicon_handle h, { return clicon_option_int_set(h, "CLICON_QUIET", val); } - diff --git a/lib/src/clixon_xpath_yang.c b/lib/src/clixon_xpath_yang.c index dde39e3f..4afb83f9 100644 --- a/lib/src/clixon_xpath_yang.c +++ b/lib/src/clixon_xpath_yang.c @@ -445,6 +445,8 @@ xp_yang_eval(xp_yang_ctx *xy, * @param[in] ys YANG referring node * @param[in] path_arg path-arg * @param[out] yref YANG referred node + * @retval 0 OK + * @retval -1 Error * @note this function uses XPATH parser, which is (much too) general * @code * yang_stmt *ys; // source / referring node diff --git a/lib/src/clixon_yang_schema_mount.c b/lib/src/clixon_yang_schema_mount.c index bb647773..7c1edf2c 100644 --- a/lib/src/clixon_yang_schema_mount.c +++ b/lib/src/clixon_yang_schema_mount.c @@ -131,6 +131,65 @@ yang_schema_mount_point(yang_stmt *y) goto done; } +/*! Get yangspec mount-point + * + * @param[in] yu Yang unknown node to save the yspecs + * @param[in] xpath Key for yspec on yu + * @param[out] yspec YANG stmt spec + * @retval 0 OK + * @retval -1 Error + */ +int +yang_mount_get(yang_stmt *yu, + char *xpath, + yang_stmt **yspec) +{ + cvec *cvv = NULL; + cg_var *cv; + + /* Special value in yang unknown node for mount-points: mapping from xpath->mounted yspec */ + if ((cvv = yang_cvec_get(yu)) != NULL && + (cv = cvec_find(cvv, xpath)) != NULL && + yspec) + *yspec = cv_void_get(cv); + return 0; +} + +/*! Set yangspec mount-point on yang unknwon node + * + * Stored in a separate structure (not in XML config tree) + * @param[in] yu Yang unknown node to save the yspecs + * @param[in] xpath Key for yspec on yu + * @param[in] yspec Yangspec for this mount-point (consumed) + * @retval 0 OK + * @retval -1 Error + */ +int +yang_mount_set(yang_stmt *yu, + char *xpath, + yang_stmt *yspec) +{ + int retval = -1; + yang_stmt *yspec0; + cvec *cvv; + cg_var *cv; + + if ((cvv = yang_cvec_get(yu)) != NULL && + (cv = cvec_find(cvv, xpath)) != NULL && + (yspec0 = cv_void_get(cv)) != NULL){ +#if 0 /* Problematic to free yang specs here, upper layers should handle it? */ + ys_free(yspec0); +#endif + cv_void_set(cv, NULL); + } + else if ((cv = yang_cvec_add(yu, CGV_VOID, xpath)) == NULL) + goto done; + cv_void_set(cv, yspec); + retval = 0; + done: + return retval; +} + /*! Get yangspec mount-point * * @param[in] h Clixon handle @@ -148,8 +207,6 @@ xml_yang_mount_get(clicon_handle h, yang_stmt **yspec) { int retval = -1; - cvec *cvv = NULL; - cg_var *cv; yang_stmt *y; yang_stmt *yu; char *xpath = NULL; // XXX free it @@ -162,21 +219,15 @@ xml_yang_mount_get(clicon_handle h, if (ret == 0) goto fail; /* Check validate level */ - if (clixon_plugin_yang_mount_all(h, xt, NULL, vl, NULL) < 0) + if (vl && clixon_plugin_yang_mount_all(h, xt, NULL, vl, NULL) < 0) goto done; // XXX hardcoded prefix: yangmnt if ((yu = yang_find(y, Y_UNKNOWN, "yangmnt:mount-point")) == NULL) goto ok; if (xml2xpath(xt, NULL, 1, &xpath) < 0) goto done; - /* Special value in yang unknown node for mount-points: mapping from xpath->mounted yspec */ - if ((cvv = yang_cvec_get(yu)) == NULL) - goto ok; - if ((cv = cvec_find(cvv, xpath)) == NULL) - goto ok; - if (yspec) - - *yspec = cv_void_get(cv); + if (yang_mount_get(yu, xpath, yspec) < 0) + goto done; ok: retval = 1; done: @@ -188,7 +239,8 @@ xml_yang_mount_get(clicon_handle h, goto done; } -/*! Set yangspec mount-point + +/*! Set yangspec mount-point via XML mount-point node * * Stored in a separate structure (not in XML config tree) * @param[in] x XML moint-point node @@ -200,12 +252,10 @@ int xml_yang_mount_set(cxobj *x, yang_stmt *yspec) { - cg_var *cv; + int retval = -1; yang_stmt *y; yang_stmt *yu; - yang_stmt *yspec0; char *xpath = NULL; - cvec *cvv; if ((y = xml_spec(x)) == NULL || (yu = yang_find(y, Y_UNKNOWN, "yangmnt:mount-point")) == NULL){ @@ -213,21 +263,13 @@ xml_yang_mount_set(cxobj *x, } if (xml2xpath(x, NULL, 1, &xpath) < 0) goto done; - if ((cvv = yang_cvec_get(yu)) != NULL && - (cv = cvec_find(cvv, xpath)) != NULL && - (yspec0 = cv_void_get(cv)) != NULL){ -#if 0 /* Problematic to free yang specs here, upper layers should handle it? */ - ys_free(yspec0); -#endif - cv_void_set(cv, NULL); - } - else if ((cv = yang_cvec_add(yu, CGV_VOID, xpath)) == NULL) - return -1; - cv_void_set(cv, yspec); + if (yang_mount_set(yu, xpath, yspec) < 0) + goto done; + retval = 0; done: if (xpath) free(xpath); - return 0; + return retval; } /*! Free all yspec yang-mounts