diff --git a/CHANGELOG.md b/CHANGELOG.md index 63c5c63f..57ab07c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,15 @@ ## 3.10.0/4.0.0 (Upcoming) ### Major New features +* Yang "min-element" and "max-element" feature supported + * According to RFC 7950 7.7.4 and 7.7.5 + * See (tests)[test/test_minmax.sh] + * The following cornercases are not supported: + * Check for min-elements>0 for empty lists on top-level + * Check for min-elements>0 for empty lists in choice/case +* Yang "unique" feature supported + * According to RFC 7950 7.8.3 + * See (tests)[test/test_unique.sh] * Persistent CLI history: [Preserve CLI command history across sessions. The up/down arrows](https://github.com/clicon/clixon/issues/79) * The design is similar to bash history: * The CLI loads/saves its complete history to a file on entry and exit, respectively @@ -45,6 +54,11 @@ ### API changes on existing features (you may need to change your code) * Non-key list now not accepted in edit-config (before only on validation) +* Changed return values in internal functions + * These functions are affected: `netconf_trymerge`, `startup_module_state`, `yang_modules_state_get` + * They now comply to Clixon validation: Error: -1; Invalid: 0; OK: 1. +* New Clixon Yang RPC: ping. To check if backup is running. + * Try with `]]>]]>` * Restconf with startup feature will now copy all edit changes to startup db (as it should according to RFC 8040) * Netconf Startup feature is no longer hardcoded, you need to explicitly enable it (See RFC 6241, Section 8.7) * Enable in config file with: `ietf-netconf:startup`, or use `*:*` @@ -116,6 +130,8 @@ ### Minor changes * New XMLDB_FORMAT added: `tree`. An experimental record-based tree database for direct access of records. +* Netconf error handling modified + * New option -e added. If set, the netconf client returns -1 on error. * A new minimal "hello world" example has been added * Experimental customized error output strings, see [lib/clixon/clixon_err_string.h] * Empty leaf values, eg are now checked at validation. @@ -143,6 +159,9 @@ * Added libgen.h for baseline() ### Corrected Bugs +* Fixed support for multiple datanodes in a choice/case statement. Only single datanode was supported. +* Fixed an ordering problem showing up in validate/commit callbacks. If two new items following each order (yang-wise), only the first showed up in the new-list. Thanks achernavin! +* Fixed a problem caused by recent sorting patches that made "ordered-by user" lists fail in some cases, causing multiple list entries with same keys. NACM being one example. Thanks vratnikov! * [Restconf does not handle startup datastore according to the RFC](https://github.com/clicon/clixon/issues/74) * Failure in startup with -m startup or running left running_db cleared. * Running-db should not be changed on failure. Unless failure-db defined. Or if SEGV, etc. In those cases, tmp_db should include the original running-db. diff --git a/README.md b/README.md index 5d195282..36c29745 100644 --- a/README.md +++ b/README.md @@ -111,13 +111,11 @@ Clixon follows: However, the following YANG syntax modules are not implemented: - deviation -- min/max-elements -- unique - action - refine -- Yang extended Xpath functions: re-match, deref, derived-from, derived-from-or-self, enum-value, bit-is-set -Restrictions on Yang types are as follows: +The following restrictions on Yang exists: +- Yang extended Xpath functions: re-match, deref, derived-from, derived-from-or-self, enum-value, bit-is-set - Submodules cannot re-use a prefix in an import statement that is already used for another imported module in the module that the submodule belongs to. (see https://github.com/clicon/clixon/issues/60) - Default values on leaf-lists are not supported (RFC7950 7.7.2) diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index 73361f8d..c5a208ff 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -158,8 +158,8 @@ backend_client_rm(clicon_handle h, * @param[in] top Top symbol, ie netconf or restconf-state * @param[in,out] xret Existing XML tree, merge x into this * @retval -1 Error (fatal) - * @retval 0 OK - * @retval 1 Statedata callback failed + * @retval 0 Statedata callback failed + * @retval 1 OK */ static int client_get_streams(clicon_handle h, @@ -174,6 +174,7 @@ client_get_streams(clicon_handle h, yang_stmt *yns = NULL; /* yang namespace */ cxobj *x = NULL; cbuf *cb = NULL; + int ret; if ((ystream = yang_find(yspec, Y_MODULE, module)) == NULL){ clicon_err(OE_YANG, 0, "%s yang module not found", module); @@ -195,16 +196,22 @@ client_get_streams(clicon_handle h, if (xml_parse_string(cbuf_get(cb), yspec, &x) < 0){ if (netconf_operation_failed_xml(xret, "protocol", clicon_err_reason)< 0) goto done; - retval = 1; - goto done; + goto fail; } - retval = netconf_trymerge(x, yspec, xret); + if ((ret = netconf_trymerge(x, yspec, xret)) < 0) + goto done; + if (ret == 0) + goto fail; + retval = 1; done: if (cb) cbuf_free(cb); if (x) xml_free(x); return retval; + fail: + retval = 0; + goto done; } /*! Get system state-data, including streams and plugins @@ -212,8 +219,8 @@ client_get_streams(clicon_handle h, * @param[in] xpath Xpath selection, not used but may be to filter early * @param[in,out] xret Existing XML tree, merge x into this * @retval -1 Error (fatal) - * @retval 0 OK - * @retval 1 Statedata callback failed (clicon_err called) + * @retval 0 Statedata callback failed (clicon_err called) + * @retval 1 OK */ static int client_statedata(clicon_handle h, @@ -225,22 +232,34 @@ client_statedata(clicon_handle h, size_t xlen; int i; yang_stmt *yspec; + int ret; if ((yspec = clicon_dbspec_yang(h)) == NULL){ clicon_err(OE_YANG, ENOENT, "No yang spec"); goto done; } - if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277")) - if ((retval = client_get_streams(h, yspec, xpath, "clixon-rfc5277", "netconf", xret)) != 0) + if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277")){ + if ((ret = client_get_streams(h, yspec, xpath, "clixon-rfc5277", "netconf", xret)) < 0) goto done; - if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040")) - if ((retval = client_get_streams(h, yspec, xpath, "ietf-restconf-monitoring", "restconf-state", xret)) != 0) + if (ret == 0) + goto fail; + } + if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040")){ + if ((ret = client_get_streams(h, yspec, xpath, "ietf-restconf-monitoring", "restconf-state", xret)) < 0) goto done; - if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895")) - if ((retval = yang_modules_state_get(h, yspec, xpath, 0, xret)) != 0) + if (ret == 0) + goto fail; + } + if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895")){ + if ((ret = yang_modules_state_get(h, yspec, xpath, 0, xret)) < 0) goto done; - if ((retval = clixon_plugin_statedata(h, yspec, xpath, xret)) != 0) + if (ret == 0) + goto fail; + } + if ((ret = clixon_plugin_statedata(h, yspec, xpath, xret)) < 0) goto done; + if (ret == 0) + goto fail; /* Code complex to filter out anything that is outside of xpath */ if (xpath_vec(*xret, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) goto done; @@ -259,12 +278,15 @@ client_statedata(clicon_handle h, /* reset flag */ if (xml_apply(*xret, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0) goto done; - retval = 0; /* OK */ + retval = 1; /* OK */ done: clicon_debug(1, "%s %d", __FUNCTION__, retval); if (xvec) free(xvec); return retval; + fail: + retval = 0; + goto done; } /*! Retrieve all or part of a specified configuration. @@ -789,7 +811,7 @@ from_client_get(clicon_handle h, clicon_err_reset(); if ((ret = client_statedata(h, xpath, &xret)) < 0) goto done; - if (ret == 1){ /* Error from callback (error in xret) */ + if (ret == 0){ /* Error from callback (error in xret) */ if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0) goto done; goto ok; @@ -1045,6 +1067,26 @@ from_client_debug(clicon_handle h, return retval; } +/*! Check liveness of backend daemon, just send a reply + * @param[in] h Clicon handle + * @param[in] xe Request: + * @param[out] cbret Return xml tree, eg ..., "); + return 0; +} + /*! An internal clicon message has arrived from a client. Receive and dispatch. * @param[in] h Clicon handle * @param[in] s Socket where message arrived. read from this. @@ -1277,10 +1319,13 @@ backend_rpc_init(clicon_handle h) if (rpc_callback_register(h, from_client_create_subscription, NULL, "urn:ietf:params:xml:ns:netmod:notification", "create-subscription") < 0) goto done; - /* In backend_client.? Clixon RPC */ + /* Clixon RPC */ if (rpc_callback_register(h, from_client_debug, NULL, "http://clicon.org/lib", "debug") < 0) goto done; + if (rpc_callback_register(h, from_client_ping, NULL, + "http://clicon.org/lib", "ping") < 0) + goto done; retval =0; done: return retval; diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index 19b98c7e..de04d161 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -115,8 +115,8 @@ clixon_plugin_reset(clicon_handle h, * @param[in] xpath String with XPATH syntax. or NULL for all * @param[in,out] xtop State XML tree is merged with existing tree. * @retval -1 Error - * @retval 0 OK - * @retval 1 Statedata callback failed (xret set with netconf-error) + * @retval 0 Statedata callback failed (xret set with netconf-error) + * @retval 1 OK * @note xtop can be replaced */ int @@ -136,24 +136,25 @@ clixon_plugin_statedata(clicon_handle h, continue; if ((x = xml_new("config", NULL, NULL)) == NULL) goto done; - if (fn(h, xpath, x) < 0){ - retval = 1; - goto done; /* Dont quit here on user callbacks */ - } - if ((ret = netconf_trymerge(x, yspec, xret)) != 0){ - retval = ret; + if (fn(h, xpath, x) < 0) + goto fail; /* Dont quit here on user callbacks */ + if ((ret = netconf_trymerge(x, yspec, xret)) < 0) goto done; - } + if (ret == 0) + goto fail; if (x){ xml_free(x); x = NULL; } } - retval = 0; + retval = 1; done: if (x) xml_free(x); return retval; + fail: + retval = 0; + goto done; } /*! Create and initialize transaction */ diff --git a/apps/backend/backend_startup.c b/apps/backend/backend_startup.c index 96195f31..f2270644 100644 --- a/apps/backend/backend_startup.c +++ b/apps/backend/backend_startup.c @@ -331,6 +331,8 @@ startup_failsafe(clicon_handle h) /*! Init modules state of the backend (server). To compare with startup XML * Set the modules state as setopt to the datastore module. * Only if CLICON_XMLDB_MODSTATE is enabled + * @retval -1 Error + * @retval 0 OK */ int startup_module_state(clicon_handle h, @@ -338,17 +340,23 @@ startup_module_state(clicon_handle h, { int retval = -1; cxobj *x = NULL; + int ret; if (!clicon_option_bool(h, "CLICON_XMLDB_MODSTATE")) goto ok; /* Set up cache * Now, access brief module cache with clicon_modst_cache_get(h, 1) */ - if (yang_modules_state_get(h, yspec, NULL, 1, &x) < 0) + if ((ret = yang_modules_state_get(h, yspec, NULL, 1, &x)) < 0) goto done; + if (ret == 0) + goto fail; ok: - retval = 0; + retval = 1; done: if (x) xml_free(x); return retval; + fail: + retval = 0; + goto done; } diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index f85bba32..68d82705 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -71,10 +71,13 @@ #include "netconf_rpc.h" /* Command line options to be passed to getopt(3) */ -#define NETCONF_OPTS "hD:f:l:qa:u:d:p:y:U:t:o:" +#define NETCONF_OPTS "hD:f:l:qa:u:d:p:y:U:t:eo:" #define NETCONF_LOGFILE "/tmp/clixon_netconf.log" +/*! Ignore errors on packet errors: continue */ +static int ignore_packet_errors = 1; + /*! Process incoming packet * @param[in] h Clicon handle * @param[in] cb Packet buffer @@ -235,8 +238,9 @@ netconf_input_cb(int s, /* OK, we have an xml string from a client */ /* Remove trailer */ *(((char*)cbuf_get(cb)) + cbuf_len(cb) - strlen("]]>]]>")) = '\0'; - if (netconf_input_packet(h, cb) < 0) - ; //goto done; // ignore errors + if (netconf_input_packet(h, cb) < 0 && + !ignore_packet_errors) // default is to ignore errors + goto done; if (cc_closed) break; cbuf_reset(cb); @@ -338,6 +342,7 @@ usage(clicon_handle h, "\t-y \tLoad yang spec file (override yang main module)\n" "\t-U \tOver-ride unix user with a pseudo user for NACM.\n" "\t-t \tTimeout in seconds. Quit after this time.\n" + "\t-e \tDont ignore errors on packet input.\n" "\t-o \"