* Pushed tag to 4.0.1.PRE

* Restconf RFC 8040 increased feature compliance
  * Cache-Control: no-cache added in HTTP responses (RFC Section 5.5)
  * Restconf monitoring capabilities (RFC Section 9.1)
* Added support for Yang extensions
  * New plugin callback: ca_extension
  * Main backend example includes example code on how to implement a Yang extension in a plugin.
* JSON changes
  * Non-pretty-print output removed all extra spaces.
    * Example: `{"nacm-example:x": 42}` --> {"nacm-example:x":42}`
  * Empty JSON container changed from `null` to `{}`.
    * Empty list and leafs remain as `null`
* Removed unnecessary configure dependencies
  * libnsl, libcrypt, libm, if_vlan,...
* pseudo-plugin added, to enable callbacks also for main programs. Useful for extensions
* Yang Unique statements with multiple schema identifiers did not work on some platforms due to memory error.
This commit is contained in:
Olof hagsand 2019-07-23 22:11:14 +02:00
parent fe46a0e093
commit e7b60619da
60 changed files with 1619 additions and 568 deletions

View file

@ -61,7 +61,7 @@ CLIXON_LIB = libclixon$(SH_SUFFIX).$(CLIXON_MAJOR).$(CLIXON_MINOR)
# even though it may exist in $(libdir). But the new version may not have been installed yet.
LIBDEPS = $(top_srcdir)/lib/src/$(CLIXON_LIB)
LIBS = -L$(top_srcdir)/lib/src @LIBS@ $(top_srcdir)/lib/src/$(CLIXON_LIB) -lpthread
LIBS = -L$(top_srcdir)/lib/src @LIBS@ $(top_srcdir)/lib/src/$(CLIXON_LIB)
CPPFLAGS = @CPPFLAGS@ -fPIC
INCLUDES = -I. -I$(top_srcdir)/lib/src -I$(top_srcdir)/lib -I$(top_srcdir)/include -I$(top_srcdir) @INCLUDES@

View file

@ -149,6 +149,37 @@ backend_client_rm(clicon_handle h,
return backend_client_delete(h, ce); /* actually purge it */
}
/*!
* Maybe should be in the restconf client instead of backend?
* @param[in] h Clicon handle
* @param[in] yspec Yang spec
* @param[in] xpath Xpath selection, not used but may be to filter early
* @param[out] xrs XML restconf-state node
* @see netconf_create_hello
* @see rfc8040 Sections 9.1
*/
static int
client_get_capabilities(clicon_handle h,
yang_stmt *yspec,
char *xpath,
cxobj **xret)
{
int retval = -1;
cxobj *xrstate = NULL; /* xml restconf-state node */
cxobj *xcap = NULL; /* xml capabilities node */
if ((xrstate = xpath_first(*xret, "restconf-state")) == NULL){
clicon_err(OE_YANG, ENOENT, "restconf-state not found in config node");
goto done;
}
if ((xcap = xml_new("capabilities", xrstate, yspec)) == NULL)
goto done;
if (xml_parse_va(&xcap, yspec, "<capability>urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=explicit</capability>") < 0)
goto done;
retval = 0;
done:
return retval;
}
/*! Get streams state according to RFC 8040 or RFC5277 common function
* @param[in] h Clicon handle
@ -165,23 +196,18 @@ static int
client_get_streams(clicon_handle h,
yang_stmt *yspec,
char *xpath,
char *module,
yang_stmt *ymod,
char *top,
cxobj **xret)
{
int retval = -1;
yang_stmt *ystream = NULL; /* yang stream module */
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);
goto done;
}
if ((yns = yang_find(ystream, Y_NAMESPACE, NULL)) == NULL){
clicon_err(OE_YANG, 0, "%s yang namespace not found", module);
if ((yns = yang_find(ymod, Y_NAMESPACE, NULL)) == NULL){
clicon_err(OE_YANG, 0, "%s yang namespace not found", yang_argument_get(ymod));
goto done;
}
if ((cb = cbuf_new()) == NULL){
@ -189,6 +215,9 @@ client_get_streams(clicon_handle h,
goto done;
}
cprintf(cb,"<%s xmlns=\"%s\">", top, yang_argument_get(yns));
/* Second argument is a hack to have the same function for the
* RFC5277 and 8040 stream cases
*/
if (stream_get_xml(h, strcmp(top,"restconf-state")==0, cb) < 0)
goto done;
cprintf(cb,"</%s>", top);
@ -234,23 +263,47 @@ client_statedata(clicon_handle h,
size_t xlen;
int i;
yang_stmt *yspec;
yang_stmt *ymod;
int ret;
char *namespace;
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 ((ret = client_get_streams(h, yspec, xpath, "clixon-rfc5277", "netconf", xret)) < 0)
if ((ymod = yang_find_module_by_name(yspec, "clixon-rfc5277")) == NULL){
clicon_err(OE_YANG, ENOENT, "yang module clixon-rfc5277 not found");
goto done;
}
if ((namespace = yang_find_mynamespace(ymod)) == NULL){
clicon_err(OE_YANG, ENOENT, "clixon-rfc5277 namespace not found");
goto done;
}
if (xml_parse_va(xret, yspec, "<netconf xmlns=\"%s\"/>", namespace) < 0)
goto done;
if ((ret = client_get_streams(h, yspec, xpath, ymod, "netconf", xret)) < 0)
goto done;
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)
if ((ymod = yang_find_module_by_name(yspec, "ietf-restconf-monitoring")) == NULL){
clicon_err(OE_YANG, ENOENT, "yang module ietf-restconf-monitoring not found");
goto done;
}
if ((namespace = yang_find_mynamespace(ymod)) == NULL){
clicon_err(OE_YANG, ENOENT, "ietf-restconf-monitoring namespace not found");
goto done;
}
if (xml_parse_va(xret, yspec, "<restconf-state xmlns=\"%s\"/>", namespace) < 0)
goto done;
if ((ret = client_get_streams(h, yspec, xpath, ymod, "restconf-state", xret)) < 0)
goto done;
if (ret == 0)
goto fail;
if ((ret = client_get_capabilities(h, yspec, xpath, xret)) < 0)
goto done;
}
if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895")){
if ((ret = yang_modules_state_get(h, yspec, xpath, nsc, 0, xret)) < 0)

View file

@ -332,6 +332,7 @@ main(int argc,
cbuf *cbret = NULL; /* startup cbuf if invalid */
enum startup_status status = STARTUP_ERR; /* Startup status */
int ret;
char *dir;
/* In the startup, logs to stderr & syslog and debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
@ -573,6 +574,13 @@ main(int argc,
if ((yspec = yspec_new()) == 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 &&
clixon_plugins_load(h, CLIXON_PLUGIN_INIT, dir,
clicon_option_str(h, "CLICON_BACKEND_REGEXP")) < 0)
goto done;
/* Load Yang modules
* 1. Load a yang module as a specific absolute filename */
if ((str = clicon_yang_main_file(h)) != NULL)
@ -596,6 +604,9 @@ main(int argc,
/* Add netconf yang spec, used by netconf client and as internal protocol */
if (netconf_module_load(h) < 0)
goto done;
/* Load yang restconf module */
if (yang_spec_parse_module(h, "ietf-restconf", NULL, yspec)< 0)
goto done;
/* Load yang Restconf stream discovery */
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
yang_spec_parse_module(h, "ietf-restconf-monitoring", NULL, yspec)< 0)
@ -646,8 +657,6 @@ main(int argc,
goto done;
case SM_NONE: /* Fall through *
* Load plugins and call plugin_init() */
if (backend_plugin_initiate(h) != 0)
goto done;
status = STARTUP_OK;
break;
case SM_RUNNING: /* Use running as startup */
@ -735,7 +744,6 @@ main(int argc,
clicon_err(OE_DEMON, errno, "Setting signal");
goto done;
}
/* Initialize server socket and save it to handle */
if ((ss = backend_server_socket(h)) < 0)
goto done;

View file

@ -63,23 +63,6 @@
#include "backend_plugin.h"
#include "backend_commit.h"
/*! Load a plugin group.
* @param[in] h Clicon handle
* @retval 0 OK
* @retval -1 Error
*/
int
backend_plugin_initiate(clicon_handle h)
{
char *dir;
/* Load application plugins */
if ((dir = clicon_backend_dir(h)) == NULL)
return 0;
return clixon_plugins_load(h, CLIXON_PLUGIN_INIT, dir,
clicon_option_str(h, "CLICON_BACKEND_REGEXP"));
}
/*! Request plugins to reset system state
* The system 'state' should be the same as the contents of running_db
* @param[in] h Clicon handle

View file

@ -67,8 +67,6 @@ typedef struct {
/*
* Prototypes
*/
int backend_plugin_initiate(clicon_handle h);
int clixon_plugin_reset(clicon_handle h, char *db);
int clixon_plugin_statedata(clicon_handle h, yang_stmt *yspec, cvec *nsc,

View file

@ -138,9 +138,6 @@ startup_mode_startup(clicon_handle h,
clicon_err(OE_FATAL, 0, "Invalid startup db: %s", db);
goto done;
}
/* Load plugins and call plugin_init() */
if (backend_plugin_initiate(h) != 0)
goto done;
/* If startup does not exist, create it empty */
if (xmldb_exists(h, db) != 1){ /* diff */
if (xmldb_create(h, db) < 0) /* diff */