RFC 7895:

* Changed Netconf hello to single capabilty urn:ietf:params:netconf:capability:yang-library:1.0 according to YANG 1.1 RFC7950 Sec 5.6.4.
  * Set by option: CLICON_MODULE_LIBRARY_RFC7895 - enabled by default
  * Option CLICON_MODULE_SET_ID is set and changed when modules change.
This commit is contained in:
Olof hagsand 2018-10-12 18:39:33 +02:00
parent 507e03742d
commit 65c44b41e8
16 changed files with 385 additions and 122 deletions

View file

@ -15,9 +15,10 @@
* logical combination of features not implemented, eg if-feature "not foo or bar and baz";
* YANG Module Library support
* According to RFC 7895 and implemented by ietf-yang-library.yang
* Supported: module, name, revision, namespace
* Not supported: notification, deviation, module-set-id, etc.
* Enabled by default, disable by resetting CLICON_MODULE_LIBRARY_RFC7895
* Changed Netconf hello to single capabilty urn:ietf:params:netconf:capability:yang-library:1.0 according to YANG 1.1 RFC7950 Sec 5.6.4.
* Set by option: CLICON_MODULE_LIBRARY_RFC7895 - enabled by default
* Option CLICON_MODULE_SET_ID is set and changed when modules change.
* Notification not supported
* Yang 1.1 notification support (RFC 7950: Sec 7.16)
* Major rewrite of event streams
* See clicon_stream.[ch] for details
@ -25,6 +26,8 @@
* Enabled by CLICON_STREAM_DISCOVERY_RFC5277 and CLICON_STREAM_DISCOVERY_RFC8040.
### API changes on existing features (you may need to change your code)
* Netconf hello capability updated to YANG 1.1 RFC7950 Sec 5.6.4
* A single capability is announced instead of many.
* Major rewrite of event streams
* If you used old event callbacks API, you need to switch to the streams API
* See clixon_stream.[ch]

View file

@ -274,76 +274,6 @@ client_get_streams(clicon_handle h,
return retval;
}
/*! Get modules state according to RFC 7895
* @param[in] h Clicon handle
* @param[in] yspec Yang spec
* @param[in] xpath Xpath selection, not used but may be to filter early
* @param[in] module Name of yang module
* @param[in,out] xret Existing XML tree, merge x into this
* @retval -1 Error (fatal)
* @retval 0 OK
* @retval 1 Statedata callback failed
*/
static int
client_get_modules(clicon_handle h,
yang_spec *yspec,
char *xpath,
char *module,
cxobj **xret)
{
int retval = -1;
cxobj *x = NULL;
cbuf *cb = NULL;
yang_stmt *ylib = NULL; /* ietf-yang-library */
yang_stmt *yns = NULL; /* namespace */
yang_stmt *ymod; /* generic module */
yang_stmt *ys;
if ((ylib = yang_find((yang_node*)yspec, Y_MODULE, module)) == NULL){
clicon_err(OE_YANG, 0, "%s not found", module);
goto done;
}
if ((yns = yang_find((yang_node*)ylib, Y_NAMESPACE, NULL)) == NULL){
clicon_err(OE_YANG, 0, "%s yang namespace not found", module);
goto done;
}
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, 0, "clicon buffer");
goto done;
}
cprintf(cb,"<modules-state xmlns=\"%s\">", yns->ys_argument);
cprintf(cb,"<module-set-id>1</module-set-id>"); /* NYI */
ymod = NULL;
while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) {
cprintf(cb,"<module>");
cprintf(cb,"<name>%s</name>", ymod->ys_argument);
if ((ys = yang_find((yang_node*)ymod, Y_REVISION, NULL)) != NULL)
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
else
cprintf(cb,"<revision></revision>");
if ((ys = yang_find((yang_node*)ymod, Y_NAMESPACE, NULL)) != NULL)
cprintf(cb,"<namespace>%s</namespace>", ys->ys_argument);
else
cprintf(cb,"<namespace></namespace>");
cprintf(cb,"</module>");
}
cprintf(cb,"</modules-state>");
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;
}
retval = netconf_trymerge(x, yspec, xret);
done:
if (cb)
cbuf_free(cb);
if (x)
xml_free(x);
return retval;
}
/*! Get system state-data, including streams and plugins
* @param[in] h Clicon handle
@ -375,7 +305,7 @@ client_statedata(clicon_handle h,
(retval = client_get_streams(h, yspec, xpath, "ietf-restconf-monitoring", "restconf-state", xret)) != 0)
goto done;
if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895") &&
(retval = client_get_modules(h, yspec, xpath, "ietf-yang-library", xret)) != 0)
(retval = yang_modules_state_get(h, yspec, xret)) != 0)
goto done;
if ((retval = clixon_plugin_statedata(h, yspec, xpath, xret)) != 0)
goto done;

View file

@ -735,8 +735,7 @@ main(int argc,
if ((yspec = yspec_new()) == NULL)
goto done;
clicon_dbspec_yang_set(h, yspec);
/* Read and parse application yang specification: either a module and search
* in dir, or a specific file
/* Load main application yang specification: either module or specific file
*/
if (yang_filename){
if (yang_spec_parse_file(h, yang_filename, clicon_yang_dir(h), yspec) < 0)
@ -747,17 +746,18 @@ main(int argc,
clicon_yang_module_revision(h),
yspec) < 0)
goto done;
/* Add system modules */
/* Load yang module library, RFC7895 */
if (yang_modules_init(h) < 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", CLIXON_DATADIR, NULL, yspec)< 0)
goto done;
/* Load yang Netconf stream discovery */
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") &&
yang_spec_parse_module(h, "ietf-netconf-notification", CLIXON_DATADIR, NULL, yspec)< 0)
goto done;
if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895") &&
yang_spec_parse_module(h, "ietf-yang-library", CLIXON_DATADIR, NULL, yspec)< 0)
goto done;
/* Set options: database dir and yangspec (could be hidden in connect?)*/
if (xmldb_setopt(h, "dbdir", clicon_xmldb_dir(h)) < 0)
goto done;

View file

@ -105,28 +105,37 @@ netconf_hello_dispatch(cxobj *xn)
return retval;
}
/*
* netconf_create_hello
* create capability string (once)
/*! Create Netconf hello. Single cap and defer individual to querying modules
* This follows YANG 1.1 RFC7950 Sec 5.6.4, where a single capability announced
* and a client may query supported modules using RFC 7895 (Yang Module
* Library).
* @param[in] h Clicon handle
* @param[in] cb Msg buffer
* @param[in] session_id Id of client session
*/
int
netconf_create_hello(cbuf *xf, /* msg buffer */
int session_id)
netconf_create_hello(clicon_handle h,
cbuf *cb,
int session_id)
{
int retval = 0;
int retval = -1;
char *module_set_id;
char *ietf_yang_library_revision;
add_preamble(xf);
cprintf(xf, "<hello>");
cprintf(xf, "<capabilities>");
cprintf(xf, "<capability>urn:ietf:params:xml:ns:netconf:base:1.0</capability>\n");
cprintf(xf, "<capability>urn:ietf:params:xml:ns:netconf:capability:candidate:1:0</capability>\n");
cprintf(xf, "<capability>urn:ietf:params:xml:ns:netconf:capability:validate:1.0</capability>\n");
cprintf(xf, "<capability>urn:ietf:params:netconf:capability:xpath:1.0</capability>\n");
cprintf(xf, "<capability>urn:ietf:params:netconf:capability:notification:1.0</capability>\n");
cprintf(xf, "<capability>urn:ietf:params:netconf:capability:startup:1.0</capability>\n");
cprintf(xf, "</capabilities>");
cprintf(xf, "<session-id>%lu</session-id>", (long unsigned int)42+session_id);
cprintf(xf, "</hello>");
add_postamble(xf);
module_set_id = clicon_option_str(h, "CLICON_MODULE_SET_ID");
if ((ietf_yang_library_revision = yang_modules_revision(h)) == NULL)
goto done;
add_preamble(cb);
cprintf(cb, "<hello>");
cprintf(cb, "<capabilities>");
cprintf(cb, "<capability>urn:ietf:params:netconf:capability:yang-library:1.0?revision=\"%s\"&module-set-id=%s</capability>",
ietf_yang_library_revision,
module_set_id);
cprintf(cb, "</capabilities>");
cprintf(cb, "<session-id>%lu</session-id>", (long unsigned int)42+session_id);
cprintf(cb, "</hello>");
add_postamble(cb);
retval = 0;
done:
return retval;
}

View file

@ -40,7 +40,7 @@
/*
* Prototypes
*/
int netconf_create_hello(cbuf *xf, int session_id);
int netconf_create_hello(clicon_handle h, cbuf *cb, int session_id);
int netconf_hello_dispatch(cxobj *xn);

View file

@ -241,28 +241,29 @@ netconf_input_cb(int s,
return retval;
}
/*
* send_hello
* args: s file descriptor to write on (eg 1 - stdout)
/*! Send netconf hello message
* @param[in] h Clicon handle
* @param[in] s File descriptor to write on (eg 1 - stdout)
*/
static int
send_hello(int s)
send_hello(clicon_handle h,
int s)
{
cbuf *xf;
int retval = -1;
int retval = -1;
cbuf *cb;
if ((xf = cbuf_new()) == NULL){
if ((cb = cbuf_new()) == NULL){
clicon_log(LOG_ERR, "%s: cbuf_new", __FUNCTION__);
goto done;
}
if (netconf_create_hello(xf, getpid()) < 0)
if (netconf_create_hello(h, cb, getpid()) < 0)
goto done;
if (netconf_output(s, xf, "hello") < 0)
if (netconf_output(s, cb, "hello") < 0)
goto done;
retval = 0;
done:
if (xf)
cbuf_free(xf);
if (cb)
cbuf_free(cb);
return retval;
}
@ -461,7 +462,7 @@ main(int argc,
*(argv-1) = tmp;
if (!quiet)
send_hello(1);
send_hello(h, 1);
if (event_reg_fd(0, netconf_input_cb, h, "netconf socket") < 0)
goto done;
if (debug)

View file

@ -266,6 +266,7 @@ api_yang_library_version(clicon_handle h,
cxobj *xt = NULL;
cbuf *cb = NULL;
int pretty;
char *ietf_yang_library_revision = "2016-06-21"; /* XXX */
clicon_debug(1, "%s", __FUNCTION__);
pretty = clicon_option_bool(h, "CLICON_RESTCONF_PRETTY");
@ -275,7 +276,7 @@ api_yang_library_version(clicon_handle h,
FCGX_SetExitStatus(200, r->out); /* OK */
FCGX_FPrintF(r->out, "Content-Type: application/yang-data+%s\r\n", use_xml?"xml":"json");
FCGX_FPrintF(r->out, "\r\n");
if (xml_parse_string("<yang-library-version>2016-06-21</yang-library-version>", NULL, &xt) < 0)
if (xml_parse_va(&xt, NULL, "<yang-library-version>%s</yang-library-version>", ietf_yang_library_revision) < 0)
goto done;
if (xml_rootchild(xt, 0, &xt) < 0)
goto done;
@ -641,9 +642,9 @@ main(int argc,
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") &&
yang_spec_parse_module(h, "ietf-netconf-notification", CLIXON_DATADIR, NULL, yspec)< 0)
goto done;
if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895") &&
yang_spec_parse_module(h, "ietf-yang-library", CLIXON_DATADIR, NULL, yspec)< 0)
goto done;
/* Load yang module library, RFC7895 */
if (yang_modules_init(h) < 0)
goto done;
if (stream_register(h, "NETCONF", "default NETCONF event stream") < 0)
goto done;

View file

@ -113,6 +113,9 @@ The example below shows enabling a specific feature; enabling all features in mo
<CLICON_FEATURE>*:*</CLICON_FEATURE>
```
Features can be probed by using RFC 7895 Yang module library which provides
information on all modules and which features are enabled.
## Can I run Clixon as docker containers?
Yes, the example works as docker containers as well. There should be a

View file

@ -75,6 +75,7 @@
#include <clixon/clixon_file.h>
#include <clixon/clixon_xml.h>
#include <clixon/clixon_xml_sort.h>
#include <clixon/clixon_yang_module.h>
#include <clixon/clixon_stream.h>
#include <clixon/clixon_proto.h>
#include <clixon/clixon_proto_client.h>

View file

@ -0,0 +1,57 @@
/*
*
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
This file is part of CLIXON.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 3 or later (the "GPL"),
in which case the provisions of the GPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of the GPL, and not to allow others to
use your version of this file under the terms of Apache License version 2,
indicate your decision by deleting the provisions above and replace them with
the notice and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****
* Yang module and feature handling
* @see https://tools.ietf.org/html/rfc7895
*/
#ifndef _CLIXON_YANG_MODULE_H_
#define _CLIXON_YANG_MODULE_H_
/*
* Constants
*/
/*
* Types
*/
/*
* Prototypes
*/
int yang_modules_init(clicon_handle h);
char *yang_modules_revision(clicon_handle h);
int yang_modules_state_get(clicon_handle h, yang_spec *yspec, cxobj **xret);
#endif /* _CLIXON_YANG_MODULE_H_ */

View file

@ -69,7 +69,7 @@ INCLUDES = -I. @INCLUDES@ -I$(top_srcdir)/lib/clixon -I$(top_srcdir)/include -I$
SRC = clixon_sig.c clixon_log.c clixon_err.c clixon_event.c \
clixon_string.c clixon_handle.c \
clixon_xml.c clixon_xml_sort.c clixon_xml_map.c clixon_file.c \
clixon_json.c clixon_yang.c clixon_yang_type.c \
clixon_json.c clixon_yang.c clixon_yang_type.c clixon_yang_module.c \
clixon_hash.c clixon_options.c clixon_plugin.c \
clixon_proto.c clixon_proto_client.c \
clixon_xpath.c clixon_xpath_ctx.c clixon_sha1.c \

View file

@ -255,9 +255,10 @@ 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
* @param[in] h clicon_handle
* @param[in] name option name
* @retval !=0 option exists
* @retval 0 option does not exists
*/
int
clicon_option_exists(clicon_handle h,

View file

@ -0,0 +1,240 @@
/*
*
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
This file is part of CLIXON.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 3 or later (the "GPL"),
in which case the provisions of the GPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of the GPL, and not to allow others to
use your version of this file under the terms of Apache License version 2,
indicate your decision by deleting the provisions above and replace them with
the notice and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****
* Yang module and feature handling
* @see https://tools.ietf.org/html/rfc7895
*/
#ifdef HAVE_CONFIG_H
#include "clixon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <regex.h>
#include <dirent.h>
#include <sys/types.h>
#include <fcntl.h>
#include <syslog.h>
#include <assert.h>
#include <sys/stat.h>
#include <netinet/in.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include "clixon_log.h"
#include "clixon_err.h"
#include "clixon_string.h"
#include "clixon_queue.h"
#include "clixon_hash.h"
#include "clixon_handle.h"
#include "clixon_file.h"
#include "clixon_yang.h"
#include "clixon_xml.h"
#include "clixon_options.h"
#include "clixon_netconf_lib.h"
#include "clixon_yang_module.h"
/*! Init the Yang module library
*
* Load RFC7895 yang spec, module-set-id, etc.
* @param[in] h Clicon handle
* @note CLIXON_DATADIR is hardcoded
*/
int
yang_modules_init(clicon_handle h)
{
int retval = -1;
yang_spec *yspec;
yspec = clicon_dbspec_yang(h);
if (!clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895"))
goto ok;
/* Ensure module-set-id is set */
if (!clicon_option_exists(h, "CLICON_MODULE_SET_ID")){
clicon_err(OE_CFG, ENOENT, "CLICON_MODULE_SET_ID must be defined when CLICON_MODULE_LIBRARY_RFC7895 is enabled");
goto done;
}
/* Ensure revision exists is set */
if (yang_spec_parse_module(h, "ietf-yang-library", CLIXON_DATADIR, NULL, yspec)< 0)
goto done;
/* Find revision */
if (yang_modules_revision(h) == NULL){
clicon_err(OE_CFG, ENOENT, "Yang client library yang spec has no revision");
goto done;
}
ok:
retval = 0;
done:
return retval;
}
/*! Return RFC7895 revision (if parsed)
* @param[in] h Clicon handle
* @retval revision String (dont free)
* @retval NULL Error: RFC7895 not loaded or revision not found
*/
char *
yang_modules_revision(clicon_handle h)
{
yang_spec *yspec;
yang_stmt *ymod;
yang_stmt *yrev;
char *revision = NULL;
yspec = clicon_dbspec_yang(h);
if ((ymod = yang_find((yang_node*)yspec, Y_MODULE, "ietf-yang-library")) != NULL){
if ((yrev = yang_find((yang_node*)ymod, Y_REVISION, NULL)) != NULL){
revision = yrev->ys_argument;
}
}
return revision;
}
/*! Get modules state according to RFC 7895
* @param[in] h Clicon handle
* @param[in] yspec Yang spec
* @param[in,out] xret Existing XML tree, merge x into this
* @retval -1 Error (fatal)
* @retval 0 OK
* @retval 1 Statedata callback failed
* @notes NYI: schema, deviation
x +--ro modules-state
x +--ro module-set-id string
x +--ro module* [name revision]
x +--ro name yang:yang-identifier
x +--ro revision union
+--ro schema? inet:uri
x +--ro namespace inet:uri
+--ro feature* yang:yang-identifier
+--ro deviation* [name revision]
| +--ro name yang:yang-identifier
| +--ro revision union
+--ro conformance-type enumeration
+--ro submodule* [name revision]
+--ro name yang:yang-identifier
+--ro revision union
+--ro schema? inet:uri
*/
int
yang_modules_state_get(clicon_handle h,
yang_spec *yspec,
cxobj **xret)
{
int retval = -1;
cxobj *x = NULL;
cbuf *cb = NULL;
yang_stmt *ylib = NULL; /* ietf-yang-library */
yang_stmt *yns = NULL; /* namespace */
yang_stmt *ymod; /* generic module */
yang_stmt *ys;
yang_stmt *yc;
char *module_set_id;
char *module = "ietf-yang-library";
module_set_id = clicon_option_str(h, "CLICON_MODULE_SET_ID");
if ((ylib = yang_find((yang_node*)yspec, Y_MODULE, module)) == NULL){
clicon_err(OE_YANG, 0, "%s not found", module);
goto done;
}
if ((yns = yang_find((yang_node*)ylib, Y_NAMESPACE, NULL)) == NULL){
clicon_err(OE_YANG, 0, "%s yang namespace not found", module);
goto done;
}
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, 0, "clicon buffer");
goto done;
}
cprintf(cb,"<modules-state xmlns=\"%s\">", yns->ys_argument);
cprintf(cb,"<module-set-id>%s</module-set-id>", module_set_id);
ymod = NULL;
while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) {
if (ymod->ys_keyword != Y_MODULE)
continue;
cprintf(cb,"<module>");
cprintf(cb,"<name>%s</name>", ymod->ys_argument);
if ((ys = yang_find((yang_node*)ymod, Y_REVISION, NULL)) != NULL)
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
else
cprintf(cb,"<revision></revision>");
if ((ys = yang_find((yang_node*)ymod, Y_NAMESPACE, NULL)) != NULL)
cprintf(cb,"<namespace>%s</namespace>", ys->ys_argument);
else
cprintf(cb,"<namespace></namespace>");
yc = NULL;
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
switch(yc->ys_keyword){
case Y_FEATURE:
if (yc->ys_cv && cv_bool_get(yc->ys_cv))
cprintf(cb,"<feature>%s</feature>", yc->ys_argument);
break;
case Y_SUBMODULE:
cprintf(cb,"<submodule>");
cprintf(cb,"<name>%s</name>", yc->ys_argument);
if ((ys = yang_find((yang_node*)yc, Y_REVISION, NULL)) != NULL)
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
else
cprintf(cb,"<revision></revision>");
cprintf(cb,"</submodule>");
break;
default:
break;
}
}
cprintf(cb,"</module>");
}
cprintf(cb,"</modules-state>");
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;
}
retval = netconf_trymerge(x, yspec, xret);
done:
if (cb)
cbuf_free(cb);
if (x)
xml_free(x);
return retval;
}

View file

@ -1,5 +1,5 @@
#!/bin/bash
# Yang features. if-feature
# Yang features. if-feature. and schema resources according to RFC7895
APPNAME=example
# include err() and new() functions and creates $dir
. ./lib.sh
@ -93,6 +93,9 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candid
new "netconf disabled feature"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><A>foo</A></config></edit-config></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-tag>operation-failed</error-tag><error-type>protocol</error-type><error-severity>error</error-severity><error-message>XML node config/A has no corresponding yang specification \(Invalid XML or wrong Yang spec?'
new "netconf schema resource, RFC 7895"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get><filter type="xpath" select="modules-state/module" xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"/></get></rpc>]]>]]>' '^<rpc-reply><data><modules-state><module><name>example</name><revision/><namespace/><feature>A</feature></module><module><name>ietf-inet-types</name><revision>2013-07-15</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-inet-types</namespace></module><module><name>ietf-interfaces</name><revision>2014-05-08</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace></module><module><name>ietf-routing</name><revision>2014-10-26</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-routing</namespace><feature>router-id</feature></module><module><name>ietf-yang-library</name><revision>2016-06-21</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace></module><module><name>ietf-yang-types</name><revision>2013-07-15</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace></module></modules-state></data></rpc-reply>]]>]]>$'
new "Kill backend"
# kill backend
sudo clixon_backend -zf $cfg

View file

@ -11,6 +11,7 @@ tmp=$dir/tmp.x
cat <<EOF > $cfg
<config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_MODULE_SET_ID>42</CLICON_MODULE_SET_ID>
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
@ -96,6 +97,9 @@ if [ $? -ne 0 ]; then
err
fi
new "netconf hello"
expecteof "$clixon_netconf -f $cfg -y $fyang" 0 '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<hello><capabilities><capability>urn:ietf:params:netconf:capability:yang-library:1.0\?revision="2016-06-21"\&module-set-id=42</capability></capabilities><session-id>'
exit
new "netconf get-config"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'

View file

@ -366,6 +366,16 @@ module clixon-config {
data. If enabled, module info will appear when doing
netconf get or restconf GET";
}
leaf CLICON_MODULE_SET_ID {
type string;
default "0";
description "If RFC 7895 YANG Module library enabled:
Contains a server-specific identifier representing
the current set of modules and submodules. The
server MUST change the value of this leaf if the
information represented by the 'module' list instances
has changed.";
}
leaf CLICON_STREAM_DISCOVERY_RFC5277 {
type boolean;
default false;