Optimized search performance for large lists by sorting and binary search
This commit is contained in:
parent
b743b0a080
commit
4b92dbdc10
28 changed files with 1405 additions and 701 deletions
|
|
@ -2,6 +2,15 @@
|
|||
|
||||
## 3.4.0 (Upcoming)
|
||||
|
||||
* Optimized search performance for large lists by sorting and binary search.
|
||||
* New CLICON_XML_SORT configuration option. Default is 1. Disable by setting to 0.
|
||||
* New yang config file: clixon-config@2017-12-27.yang
|
||||
* Added yang ordered-by user. The default (ordered-by system) will now sort lists and leaf-lists alphabetically to increase search performance.
|
||||
* This replaces XML hash experimental code, ie xml_child_hash variables and all xml_hash_ functions have been removed.
|
||||
|
||||
|
||||
* Cached keys in yang Y_LIST node as cligen vector, see ys_populate_list()
|
||||
|
||||
* Clixon_backend now returns -1/255 on error instead of 0. Useful for systemd restarts, for example.
|
||||
|
||||
* Fixed bug that deletes running on startup if backup started with -m running.
|
||||
|
|
|
|||
|
|
@ -547,7 +547,6 @@ yang2cli_list(clicon_handle h,
|
|||
{
|
||||
yang_stmt *yc;
|
||||
yang_stmt *yd;
|
||||
yang_stmt *ykey;
|
||||
yang_stmt *yleaf;
|
||||
int i;
|
||||
cg_var *cvi;
|
||||
|
|
@ -568,13 +567,7 @@ yang2cli_list(clicon_handle h,
|
|||
cprintf(cbuf, "(\"%s\")", helptext);
|
||||
}
|
||||
/* Loop over all key variables */
|
||||
if ((ykey = yang_find((yang_node*)ys, Y_KEY, NULL)) == NULL){
|
||||
clicon_err(OE_XML, 0, "List statement \"%s\" has no key", ys->ys_argument);
|
||||
goto done;
|
||||
}
|
||||
/* The value is a list of keys: <key>[ <key>]* */
|
||||
if ((cvk = yang_arg2cvec(ykey, " ")) == NULL)
|
||||
goto done;
|
||||
cvk = ys->ys_cvec; /* Use Y_LIST cache, see ys_populate_list() */
|
||||
cvi = NULL;
|
||||
/* Iterate over individual keys */
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
|
||||
|
|
@ -614,8 +607,6 @@ yang2cli_list(clicon_handle h,
|
|||
done:
|
||||
if (helptext)
|
||||
free(helptext);
|
||||
if (cvk)
|
||||
cvec_free(cvk);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -201,14 +201,7 @@ append_listkeys(cbuf *ckey,
|
|||
char *bodyenc;
|
||||
int i=0;
|
||||
|
||||
if ((ykey = yang_find((yang_node*)ys, Y_KEY, NULL)) == NULL){
|
||||
clicon_err(OE_XML, errno, "%s: List statement \"%s\" has no key",
|
||||
__FUNCTION__, ys->ys_argument);
|
||||
goto done;
|
||||
}
|
||||
/* The value is a list of keys: <key>[ <key>]* */
|
||||
if ((cvk = yang_arg2cvec(ykey, " ")) == NULL)
|
||||
goto done;
|
||||
cvk = ys->ys_cvec; /* Use Y_LIST cache, see ys_populate_list() */
|
||||
cvi = NULL;
|
||||
/* Iterate over individual keys */
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
|
||||
|
|
@ -230,8 +223,6 @@ append_listkeys(cbuf *ckey,
|
|||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (cvk)
|
||||
cvec_free(cvk);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -276,7 +276,6 @@ text_setopt(xmldb_handle xh,
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Ensure that xt only has a single sub-element and that is "config"
|
||||
*/
|
||||
static int
|
||||
|
|
@ -446,6 +445,9 @@ text_get(xmldb_handle xh,
|
|||
if (singleconfigroot(xt, &xt) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* Sort XML children according to YANG and ordered-by XXX */
|
||||
if (xml_child_sort && xml_apply0(xt, CX_ELMNT, xml_sort, NULL) < 0)
|
||||
goto done;
|
||||
} /* xt == NULL */
|
||||
/* Here xt looks like: <config>...</config> */
|
||||
|
||||
|
|
@ -507,7 +509,10 @@ text_get(xmldb_handle xh,
|
|||
if (xml_apply(xt, CX_ELMNT, xml_default, NULL) < 0)
|
||||
goto done;
|
||||
/* Order XML children according to YANG */
|
||||
if (xml_apply(xt, CX_ELMNT, xml_order, NULL) < 0)
|
||||
if (!xml_child_sort && xml_apply(xt, CX_ELMNT, xml_order, NULL) < 0)
|
||||
goto done;
|
||||
/* XXX again just so default values are placed correctly */
|
||||
if (xml_child_sort && xml_apply0(xt, CX_ELMNT, xml_sort, NULL) < 0)
|
||||
goto done;
|
||||
if (debug>1)
|
||||
clicon_xml2file(stderr, xt, 0, 1);
|
||||
|
|
@ -600,10 +605,6 @@ text_modify(cxobj *x0,
|
|||
if (xml_value_set(x0b, x1bstr) < 0)
|
||||
goto done;
|
||||
}
|
||||
if (xml_child_hash &&
|
||||
xml_apply0(x0, CX_ELMNT, xml_hash_op, (void*)1) < 0)
|
||||
goto done;
|
||||
|
||||
break;
|
||||
case OP_DELETE:
|
||||
if (x0==NULL){
|
||||
|
|
@ -652,11 +653,7 @@ text_modify(cxobj *x0,
|
|||
goto done;
|
||||
if (op==OP_NONE)
|
||||
xml_flag_set(x0, XML_FLAG_NONE); /* Mark for potential deletion */
|
||||
|
||||
}
|
||||
if (xml_child_hash &&
|
||||
xml_apply0(x0, CX_ELMNT, xml_hash_op, (void*)1) < 0)
|
||||
goto done;
|
||||
/* First pass: mark existing children in base */
|
||||
/* Loop through children of the modification tree */
|
||||
if ((x0vec = calloc(xml_child_nr(x1), sizeof(x1))) == NULL){
|
||||
|
|
@ -826,6 +823,7 @@ text_put(xmldb_handle xh,
|
|||
struct text_handle *th = handle(xh);
|
||||
char *dbfile = NULL;
|
||||
int fd = -1;
|
||||
FILE *f = NULL;
|
||||
cbuf *cb = NULL;
|
||||
yang_spec *yspec;
|
||||
cxobj *x0 = NULL;
|
||||
|
|
@ -880,17 +878,14 @@ text_put(xmldb_handle xh,
|
|||
}
|
||||
|
||||
/* Add yang specification backpointer to all XML nodes */
|
||||
/* XXX: where is thiscreated? Add yspec */
|
||||
/* XXX: where is this created? Add yspec */
|
||||
if (xml_apply(x1, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
/* Add hash */
|
||||
#if 0
|
||||
if (xml_child_hash &&
|
||||
xml_apply0(x0, CX_ELMNT, xml_hash_op, (void*)1) < 0)
|
||||
if (xml_child_sort && xml_apply0(x1, CX_ELMNT, xml_sort, NULL) < 0)
|
||||
goto done;
|
||||
#endif
|
||||
/*
|
||||
* Modify base tree x with modification x1
|
||||
* Modify base tree x with modification x1. This is where the
|
||||
* new tree is made.
|
||||
*/
|
||||
if (text_modify_top(x0, x1, yspec, op) < 0)
|
||||
goto done;
|
||||
|
|
@ -907,6 +902,8 @@ text_put(xmldb_handle xh,
|
|||
/* Remove (prune) nodes that are marked (non-presence containers w/o children) */
|
||||
if (xml_tree_prune_flagged(x0, XML_FLAG_MARK, 1) < 0)
|
||||
goto done;
|
||||
if (xml_child_sort && xml_apply0(x0, CX_ELMNT, xml_sort, NULL) < 0)
|
||||
goto done;
|
||||
|
||||
/* Write back to datastore cache if first time */
|
||||
if (xmltree_cache){
|
||||
|
|
@ -926,42 +923,20 @@ text_put(xmldb_handle xh,
|
|||
goto done;
|
||||
}
|
||||
}
|
||||
#if 1
|
||||
if (fd != -1)
|
||||
if (fd != -1){
|
||||
close(fd);
|
||||
{
|
||||
FILE *f;
|
||||
if ((f = fopen(dbfile, "w")) == NULL){
|
||||
clicon_err(OE_CFG, errno, "Creating file %s", dbfile);
|
||||
goto done;
|
||||
}
|
||||
if (xml_print(f, x0) < 0)
|
||||
goto done;
|
||||
fclose(f);
|
||||
fd = -1;
|
||||
}
|
||||
#else
|
||||
// output:
|
||||
/* Print out top-level xml tree after modification to file */
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
if ((f = fopen(dbfile, "w")) == NULL){
|
||||
clicon_err(OE_CFG, errno, "Creating file %s", dbfile);
|
||||
goto done;
|
||||
}
|
||||
if (clicon_xml2cbuf(cb, x0, 0, 1) < 0)
|
||||
}
|
||||
if (xml_print(f, x0) < 0)
|
||||
goto done;
|
||||
/* Reopen file in write mode */
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
if ((fd = open(dbfile, O_WRONLY | O_TRUNC, S_IRWXU)) < 0) {
|
||||
clicon_err(OE_UNIX, errno, "open(%s)", dbfile);
|
||||
goto done;
|
||||
}
|
||||
if (write(fd, cbuf_get(cb), cbuf_len(cb)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "write(%s)", dbfile);
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
retval = 0;
|
||||
done:
|
||||
if (f != NULL)
|
||||
fclose(f);
|
||||
if (dbfile)
|
||||
free(dbfile);
|
||||
if (fd != -1)
|
||||
|
|
@ -1020,7 +995,6 @@ text_copy(xmldb_handle xh,
|
|||
hash_add(th->th_dbs, to, &de0, sizeof(de0));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (text_db2file(th, from, &fromfile) < 0)
|
||||
goto done;
|
||||
|
|
@ -1175,7 +1149,8 @@ text_delete(xmldb_handle xh,
|
|||
struct text_handle *th = handle(xh);
|
||||
struct db_element *de = NULL;
|
||||
cxobj *xt = NULL;
|
||||
|
||||
struct stat sb;
|
||||
|
||||
if (xmltree_cache){
|
||||
if ((de = hash_value(th->th_dbs, db, NULL)) != NULL){
|
||||
if ((xt = de->de_xml) != NULL){
|
||||
|
|
@ -1186,10 +1161,11 @@ text_delete(xmldb_handle xh,
|
|||
}
|
||||
if (text_db2file(th, db, &filename) < 0)
|
||||
goto done;
|
||||
if (unlink(filename) < 0){
|
||||
clicon_err(OE_DB, errno, "unlink %s", filename);
|
||||
goto done;
|
||||
}
|
||||
if (lstat(filename, &sb) == 0)
|
||||
if (unlink(filename) < 0){
|
||||
clicon_err(OE_DB, errno, "unlink %s", filename);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (filename)
|
||||
|
|
@ -1303,7 +1279,8 @@ usage(char *argv0)
|
|||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
main(int argc,
|
||||
char **argv)
|
||||
{
|
||||
cxobj *xt;
|
||||
cxobj *xn;
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@
|
|||
#include <clixon/clixon_string.h>
|
||||
#include <clixon/clixon_file.h>
|
||||
#include <clixon/clixon_xml.h>
|
||||
#include <clixon/clixon_xml_sort.h>
|
||||
#include <clixon/clixon_proto.h>
|
||||
#include <clixon/clixon_proto_client.h>
|
||||
#include <clixon/clixon_plugin.h>
|
||||
|
|
|
|||
|
|
@ -80,10 +80,10 @@ typedef int (xml_applyfn_t)(cxobj *yn, void *arg);
|
|||
#define XML_FLAG_CHANGE 0x08 /* Node is changed (commits) or child changed rec */
|
||||
#define XML_FLAG_NONE 0x10 /* Node is added as NONE */
|
||||
|
||||
/* Hash for XML trees list entries
|
||||
/* Sort and binary search of XML children
|
||||
* Experimental
|
||||
*/
|
||||
extern int xml_child_hash;
|
||||
extern int xml_child_sort;
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
|
|
@ -160,14 +160,7 @@ int xml_body_int32(cxobj *xb, int32_t *val);
|
|||
int xml_body_uint32(cxobj *xb, uint32_t *val);
|
||||
int xml_operation(char *opstr, enum operation_type *op);
|
||||
char *xml_operation2str(enum operation_type op);
|
||||
int xml_child_spec(char *name, cxobj *xp, yang_spec *yspec, yang_stmt **yp);
|
||||
|
||||
clicon_hash_t *xml_hash(cxobj *x);
|
||||
int xml_hash_key(cxobj *x, yang_stmt *y, cbuf *key);
|
||||
int xml_hash_op(cxobj *x, void *arg);
|
||||
int xml_hash_add(cxobj *x);
|
||||
int xml_hash_rm_only(cxobj *x);
|
||||
int xml_hash_rm_entry(cxobj *x);
|
||||
int xml_sort(cxobj *x0, void *arg);
|
||||
|
||||
#ifdef XML_COMPAT /* See CHANGELOG */
|
||||
/* MANUAL CHANGE: xml_new(name, parent) --> xml_new(name, parent, NULL) */
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ int api_path2xpath_cvv(yang_spec *yspec, cvec *cvv, int offset, cbuf *xpath);
|
|||
int api_path2xpath(yang_spec *yspec, char *api_path, cbuf *xpath);
|
||||
int api_path2xml(char *api_path, yang_spec *yspec, cxobj *xtop,
|
||||
int schemanode, cxobj **xpathp, yang_node **ypathp);
|
||||
int match_base_child(cxobj *x0, cxobj *x1c, cxobj **x0cp, yang_stmt *yc);
|
||||
int xml_merge(cxobj *x0, cxobj *x1, yang_spec *yspec);
|
||||
int yang_enum_int_value(cxobj *node, int32_t *val);
|
||||
|
||||
|
|
|
|||
52
lib/clixon/clixon_xml_sort.h
Normal file
52
lib/clixon/clixon_xml_sort.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2017 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 *****
|
||||
|
||||
* XML sort and earch functions when used with YANG
|
||||
*/
|
||||
#ifndef _CLIXON_XML_SORT_H
|
||||
#define _CLIXON_XML_SORT_H
|
||||
|
||||
/* Sort and binary search of XML children
|
||||
* Experimental
|
||||
*/
|
||||
extern int xml_child_sort;
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int xml_child_spec(char *name, cxobj *xp, yang_spec *yspec, yang_stmt **yp);
|
||||
cxobj *xml_search(cxobj *x, char *name, int yangi, enum rfc_6020 keyword, int keynr, char **keyvec, char **keyval);
|
||||
cxobj *xml_match(cxobj *x0, char *name, enum rfc_6020 keyword, int keynr, char **keyvec, char **keyval);
|
||||
int match_base_child(cxobj *x0, cxobj *x1c, cxobj **x0cp, yang_stmt *yc);
|
||||
|
||||
#endif /* _CLIXON_XML_SORT_H */
|
||||
|
|
@ -155,10 +155,17 @@ struct yang_stmt{
|
|||
|
||||
char *ys_argument; /* String / argument depending on keyword */
|
||||
int ys_flags; /* Flags according to YANG_FLAG_* above */
|
||||
cg_var *ys_cv; /* cligen variable. The following stmts have cvs::
|
||||
leaf, leaf-list, mandatory, fraction-digits */
|
||||
cg_var *ys_cv; /* cligen variable. See ys_populate()
|
||||
Following stmts have cv:s:
|
||||
leaf: for default value
|
||||
leaf-list,
|
||||
config: boolean true or false
|
||||
mandatory: boolean true or false
|
||||
fraction-digits for fraction-digits */
|
||||
cvec *ys_cvec; /* List of stmt-specific variables
|
||||
Y_RANGE: range_min, range_max */
|
||||
Y_RANGE: range_min, range_max
|
||||
Y_LIST: vector of keys
|
||||
*/
|
||||
yang_type_cache *ys_typecache; /* If ys_keyword==Y_TYPE, cache all typedef data except unions */
|
||||
};
|
||||
|
||||
|
|
@ -208,7 +215,7 @@ yang_stmt *yang_find(yang_node *yn, int keyword, char *argument);
|
|||
yang_stmt *yang_find_datanode(yang_node *yn, char *argument);
|
||||
yang_stmt *yang_find_schemanode(yang_node *yn, char *argument);
|
||||
yang_stmt *yang_find_topnode(yang_spec *ysp, char *name, int schemanode);
|
||||
|
||||
int yang_order(yang_stmt *y);
|
||||
int yang_print(FILE *f, yang_node *yn);
|
||||
int yang_print_cbuf(cbuf *cb, yang_node *yn, int marginal);
|
||||
int yang_parse(clicon_handle h, const char *yang_dir,
|
||||
|
|
|
|||
|
|
@ -64,7 +64,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_map.c clixon_file.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_hash.c clixon_options.c clixon_plugin.c \
|
||||
clixon_proto.c clixon_proto_client.c \
|
||||
|
|
|
|||
|
|
@ -382,6 +382,11 @@ clicon_options_main(clicon_handle h)
|
|||
/* Read configfile */
|
||||
if (clicon_option_readfile_xml(copt, configfile, yspec) < 0)
|
||||
goto done;
|
||||
/* Specific option handling */
|
||||
if (clicon_option_bool(h, "CLICON_XML_SORT") == 1)
|
||||
xml_child_sort = 1;
|
||||
else
|
||||
xml_child_sort = 0;
|
||||
}
|
||||
else {
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
|
@ -409,6 +414,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
|
||||
*/
|
||||
int
|
||||
clicon_option_exists(clicon_handle h,
|
||||
|
|
|
|||
|
|
@ -82,21 +82,37 @@
|
|||
/*! xml tree node, with name, type, parent, children, etc
|
||||
* Note that this is a private type not visible from externally, use
|
||||
* access functions.
|
||||
* A word on ordering of x_children:
|
||||
* If there is no yang specification, xml children are ordered as they are entered.
|
||||
* If there is a yang specification (and the appropriate functions are called) the
|
||||
* xml children are ordered as follows:
|
||||
* 1) After yang specification order.
|
||||
* 2) list and leaf-list are sorted alphabetically unless ordered-by user.
|
||||
* Example:
|
||||
* container c{
|
||||
* leaf a;
|
||||
* leaf-list x;
|
||||
* }
|
||||
* then regardless in which order the xml is entered, it will be sorted as follows:
|
||||
* <c>
|
||||
* <a/>
|
||||
* <x>a</<x>
|
||||
* <x>b</<x>
|
||||
* </c>
|
||||
*/
|
||||
struct xml{
|
||||
char *x_name; /* name of node */
|
||||
char *x_namespace; /* namespace, if any */
|
||||
struct xml *x_up; /* parent node in hierarchy if any */
|
||||
struct xml **x_childvec; /* vector of children nodes */
|
||||
int x_childvec_len; /* length of vector */
|
||||
int x_childvec_len;/* length of vector */
|
||||
enum cxobj_type x_type; /* type of node: element, attribute, body */
|
||||
char *x_value; /* attribute and body nodes have values */
|
||||
int _x_vector_i; /* internal use: xml_child_each */
|
||||
int x_flags; /* Flags according to XML_FLAG_* above */
|
||||
yang_stmt *x_spec; /* Pointer to specification, eg yang, by
|
||||
reference, dont free */
|
||||
cg_var *x_cv; /* If body this contains the typed value */
|
||||
clicon_hash_t *x_hash; /* Hash of children */
|
||||
cg_var *x_cv; /* If body this contains the typed value */
|
||||
};
|
||||
|
||||
/* Mapping between xml type <--> string */
|
||||
|
|
@ -108,10 +124,6 @@ static const map_str2int xsmap[] = {
|
|||
{NULL, -1}
|
||||
};
|
||||
|
||||
/* Hash for XML trees list entries
|
||||
* Experimental XXX DOES NOT WORK
|
||||
*/
|
||||
int xml_child_hash = 0;
|
||||
|
||||
/*! Translate from xml type in enum form to string keyword
|
||||
* @param[in] type Xml type
|
||||
|
|
@ -475,11 +487,11 @@ xml_child_append(cxobj *x,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Set a a childvec to a speciufic size, fill with children after
|
||||
/*! Set a a childvec to a specific size, fill with children after
|
||||
* @code
|
||||
* xml_childvec_set(x, 2);
|
||||
* xml_child_i(x, 0) = xc0;
|
||||
* xml_child_i(x, 1) = xc1;
|
||||
* xml_child_i_set(x, 0, xc0)
|
||||
* xml_child_i_set(x, 1, xc1);
|
||||
* @endcode
|
||||
*/
|
||||
int
|
||||
|
|
@ -502,9 +514,9 @@ xml_childvec_get(cxobj *x)
|
|||
|
||||
/*! Create new xml node given a name and parent. Free with xml_free().
|
||||
*
|
||||
* @param[in] name Name of new
|
||||
* @param[in] xp The parent where the new xml node should be inserted
|
||||
* @param[in] spec Yang stmt or NULL.
|
||||
* @param[in] name Name of XML node
|
||||
* @param[in] xp The parent where the new xml node will be appended
|
||||
* @param[in] spec Yang statement of this XML or NULL.
|
||||
* @retval xml Created xml object if successful. Free with xml_free()
|
||||
* @retval NULL Error and clicon_err() called
|
||||
* @code
|
||||
|
|
@ -536,8 +548,6 @@ xml_new(char *name,
|
|||
if (xp && xml_child_append(xp, x) < 0)
|
||||
return NULL;
|
||||
x->x_spec = spec; /* Can be NULL */
|
||||
if (xml_child_hash && spec && xml_hash_add(x) < 0)
|
||||
return NULL;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
|
@ -655,8 +665,6 @@ xml_purge(cxobj *xc)
|
|||
int i;
|
||||
cxobj *xp;
|
||||
|
||||
if (xml_child_hash)
|
||||
xml_hash_rm_entry(xc);
|
||||
if ((xp = xml_parent(xc)) != NULL){
|
||||
/* Find child order i in parent*/
|
||||
for (i=0; i<xml_child_nr(xp); i++)
|
||||
|
|
@ -928,8 +936,6 @@ xml_free(cxobj *x)
|
|||
x->x_childvec[i] = NULL;
|
||||
}
|
||||
}
|
||||
if (x->x_hash)
|
||||
hash_free(x->x_hash);
|
||||
if (x->x_childvec)
|
||||
free(x->x_childvec);
|
||||
free(x);
|
||||
|
|
@ -1830,276 +1836,93 @@ xml_operation2str(enum operation_type op)
|
|||
}
|
||||
}
|
||||
|
||||
/*! Given an XML object and a child name, return yang stmt of child
|
||||
* If no xml parent, find root yang stmt matching name
|
||||
* @param[in] name Name of child
|
||||
* @param[in] xp XML parent, can be NULL.
|
||||
* @param[in] yspec Yang specification (top level)
|
||||
* @param[out] yresult Pointer to yang stmt of result, or NULL, if not found
|
||||
/*! Help function to qsort for sorting entries in xml child vector
|
||||
* @param[in] arg1
|
||||
* @param[in] arg2
|
||||
* @retval 0 If equal
|
||||
* @retval <0 if arg1 is less than arg2
|
||||
* @retval >0 if arg1 is greater than arg2
|
||||
* @note must be in clixon_xml.c since it uses internal (hidden) struct xml
|
||||
*/
|
||||
int
|
||||
xml_child_spec(char *name,
|
||||
cxobj *xp,
|
||||
yang_spec *yspec,
|
||||
yang_stmt **yresult)
|
||||
{
|
||||
yang_stmt *y; /* result yang node */
|
||||
yang_stmt *yparent; /* parent yang */
|
||||
|
||||
if (xp && (yparent = xml_spec(xp)) != NULL)
|
||||
y = yang_find_datanode((yang_node*)yparent, name);
|
||||
else if (yspec)
|
||||
y = yang_find_topnode(yspec, name, 0); /* still NULL for config */
|
||||
else
|
||||
y = NULL;
|
||||
*yresult = y;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Return yang hash
|
||||
* Not necessarily set. Either has not been set yet (by xml_spec_set( or anyxml.
|
||||
*/
|
||||
clicon_hash_t *
|
||||
xml_hash(cxobj *x)
|
||||
{
|
||||
return x->x_hash;
|
||||
}
|
||||
|
||||
static int
|
||||
xml_hash_init(cxobj *x)
|
||||
xml_cmp(const void* arg1,
|
||||
const void* arg2)
|
||||
{
|
||||
if ((x->x_hash = hash_init()) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! XML remove hash only. Not in parent.
|
||||
* @param[in] x XML object
|
||||
* eg same as xml_hash_op(x, -1)
|
||||
*/
|
||||
int
|
||||
xml_hash_rm_only(cxobj *x)
|
||||
{
|
||||
if (x && x->x_hash){
|
||||
hash_free(x->x_hash);
|
||||
x->x_hash = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute hash key for xml entry
|
||||
* @param[in] x
|
||||
* @param[in] y
|
||||
* @param[out] key
|
||||
* key: yangtype+x1name
|
||||
* LEAFLIST: b0
|
||||
* LIST: b2vec+b0 -> x0c
|
||||
*/
|
||||
int
|
||||
xml_hash_key(cxobj *x,
|
||||
yang_stmt *y,
|
||||
cbuf *key)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *ykey;
|
||||
cvec *cvk = NULL; /* vector of index keys */
|
||||
cg_var *cvi;
|
||||
char *keyname;
|
||||
char *b;
|
||||
char *str;
|
||||
|
||||
switch (y->ys_keyword){
|
||||
case Y_CONTAINER: str = "c"; break;
|
||||
case Y_LEAF: str = "e"; break;
|
||||
case Y_LEAF_LIST: str = "l"; break;
|
||||
case Y_LIST: str = "i"; break;
|
||||
default:
|
||||
str = "xx"; break;
|
||||
break;
|
||||
}
|
||||
cprintf(key, "%s%s", str, xml_name(x));
|
||||
switch (y->ys_keyword){
|
||||
case Y_LEAF_LIST: /* Match with name and value */
|
||||
if ((b = xml_body(x)) == NULL){
|
||||
cbuf_reset(key);
|
||||
goto ok;
|
||||
}
|
||||
cprintf(key, "%s", xml_body(x));
|
||||
break;
|
||||
case Y_LIST: /* Match with key values */
|
||||
if ((ykey = yang_find((yang_node*)y, Y_KEY, NULL)) == NULL){
|
||||
clicon_err(OE_XML, errno, "%s: List statement \"%s\" has no key",
|
||||
__FUNCTION__, y->ys_argument);
|
||||
goto done;
|
||||
}
|
||||
/* The value is a list of keys: <key>[ <key>]* */
|
||||
if ((cvk = yang_arg2cvec(ykey, " ")) == NULL)
|
||||
goto done;
|
||||
cvi = NULL;
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL){
|
||||
keyname = cv_string_get(cvi);
|
||||
if ((b = xml_find_body(x, keyname)) == NULL){
|
||||
cbuf_reset(key);
|
||||
goto ok;
|
||||
}
|
||||
cprintf(key, "/%s", b);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (cvk)
|
||||
cvec_free(cvk);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! XML hash add. Create hash and add key/value to parent
|
||||
*
|
||||
* @param[in] arg add flag. If 1, else if 0 remove.
|
||||
* Typically called for a whole tree.
|
||||
*/
|
||||
int
|
||||
xml_hash_op(cxobj *x,
|
||||
void *arg)
|
||||
{
|
||||
int add = (intptr_t)arg;
|
||||
#if 1
|
||||
if (add)
|
||||
return xml_hash_add(x);
|
||||
else
|
||||
return xml_hash_rm_entry(x);
|
||||
#else
|
||||
struct xml *x1 = *(struct xml**)arg1;
|
||||
struct xml *x2 = *(struct xml**)arg2;
|
||||
yang_stmt *y1;
|
||||
yang_stmt *y2;
|
||||
int yi1;
|
||||
int yi2;
|
||||
cvec *cvk = NULL; /* vector of index keys */
|
||||
cg_var *cvi;
|
||||
int equal = 0;
|
||||
char *b1;
|
||||
char *b2;
|
||||
char *keyname;
|
||||
|
||||
int retval = -1;
|
||||
cxobj *xp;
|
||||
clicon_hash_t *ph;
|
||||
yang_stmt *y;
|
||||
cbuf *key = NULL; /* cligen buffer hash key */
|
||||
|
||||
|
||||
if (xml_hash(x)==NULL){
|
||||
if (add)
|
||||
xml_hash_init(x);
|
||||
if (x1 == NULL){
|
||||
if (x2 == NULL)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else if (!add)
|
||||
xml_hash_rm_only(x);
|
||||
if ((xp = xml_parent(x)) == NULL)
|
||||
goto ok;
|
||||
if ((ph = xml_hash(xp))==NULL)
|
||||
goto ok;
|
||||
if ((y = xml_spec(x)) == NULL)
|
||||
goto ok;
|
||||
if ((key = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
else if (x2 == NULL)
|
||||
return 1;
|
||||
y1 = xml_spec(x1);
|
||||
y2 = xml_spec(x2);
|
||||
if (y1==NULL || y2==NULL)
|
||||
return 0; /* just ignore */
|
||||
if (y1 != y2){
|
||||
yi1 = yang_order(y1);
|
||||
yi2 = yang_order(y2);
|
||||
if ((equal = yi1-yi2) != 0)
|
||||
return equal;
|
||||
}
|
||||
if (xml_hash_key(x, y, key) < 0)
|
||||
goto done;
|
||||
if (cbuf_len(key)){
|
||||
// fprintf(stderr, "%s add %s = 0x%x\n", __FUNCTION__, cbuf_get(key), (unsigned int)x);
|
||||
if (add){
|
||||
if (hash_add(ph, cbuf_get(key), &x, sizeof(x)) == NULL)
|
||||
/* Now y1=y2, same Yang spec, can only be list or leaf-list,
|
||||
* sort according to key
|
||||
*/
|
||||
if (yang_find((yang_node*)y1, Y_ORDERED_BY, "user") != NULL)
|
||||
return 0; /* Ordered by user: maintain existing order */
|
||||
switch (y1->ys_keyword){
|
||||
case Y_LEAF_LIST: /* Match with name and value */
|
||||
equal = strcmp(xml_body(x1), xml_body(x2));
|
||||
break;
|
||||
case Y_LIST: /* Match with key values
|
||||
* Use Y_LIST cache (see struct yang_stmt)
|
||||
*/
|
||||
cvk = y1->ys_cvec; /* Use Y_LIST cache, see ys_populate_list() */
|
||||
cvi = NULL;
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
|
||||
keyname = cv_string_get(cvi);
|
||||
b1 = xml_find_body(x1, keyname);
|
||||
b2 = xml_find_body(x2, keyname);
|
||||
if ((equal = strcmp(b1,b2)) != 0)
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
if (hash_del(ph, cbuf_get(key)) < 0)
|
||||
goto done;
|
||||
equal = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (key)
|
||||
cbuf_free(key);
|
||||
return retval;
|
||||
#endif
|
||||
return equal;
|
||||
}
|
||||
|
||||
/*! XML hash add. Create hash and add key/value to parent
|
||||
*
|
||||
* @param[in] x XML object
|
||||
* eg same as xml_hash_op(x, 1)
|
||||
/*! Sort children of an XML node
|
||||
* Assume populated by yang spec.
|
||||
* @param[in] x0 XML node
|
||||
* @param[in] arg Dummy so it can be called by xml_apply()
|
||||
* @note must be in clixon_xml.c since it uses internal (hidden) struct xml
|
||||
*/
|
||||
int
|
||||
xml_hash_add(cxobj *x)
|
||||
xml_sort(cxobj *x,
|
||||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xp;
|
||||
clicon_hash_t *ph;
|
||||
yang_stmt *y;
|
||||
yang_stmt *yp;
|
||||
cbuf *key = NULL; /* cligen buffer hash key */
|
||||
|
||||
if ((ph = xml_hash(x))==NULL){
|
||||
xml_hash_init(x);
|
||||
ph = xml_hash(x);
|
||||
}
|
||||
if ((xp = xml_parent(x)) == NULL)
|
||||
goto ok;
|
||||
yp = xml_spec(xp);
|
||||
if (yp && yp->ys_keyword != Y_LIST)
|
||||
goto ok;
|
||||
if ((y = xml_spec(x)) == NULL)
|
||||
goto ok;
|
||||
if ((key = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (xml_hash_key(x, y, key) < 0)
|
||||
goto done;
|
||||
if (cbuf_len(key)){
|
||||
if (hash_add(ph, cbuf_get(key), &x, sizeof(x)) == NULL)
|
||||
goto done;
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (key)
|
||||
cbuf_free(key);
|
||||
return retval;
|
||||
qsort(x->x_childvec, x->x_childvec_len, sizeof(struct xml*), xml_cmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! XML hash rm. Create hash and add key/value to parent
|
||||
*
|
||||
* @param[in] x XML object
|
||||
* eg same as xml_hash_op(x, 0)
|
||||
*/
|
||||
int
|
||||
xml_hash_rm_entry(cxobj *x)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xp;
|
||||
clicon_hash_t *ph;
|
||||
yang_stmt *y;
|
||||
cbuf *key = NULL; /* cligen buffer hash key */
|
||||
|
||||
if (xml_hash(x)!=NULL)
|
||||
xml_hash_rm_only(x);
|
||||
if ((xp = xml_parent(x)) == NULL)
|
||||
goto ok;
|
||||
if ((ph = xml_hash(xp))==NULL)
|
||||
goto ok;
|
||||
if ((y = xml_spec(x)) == NULL)
|
||||
goto ok;
|
||||
if ((key = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (xml_hash_key(x, y, key) < 0)
|
||||
goto done;
|
||||
if (cbuf_len(key)){
|
||||
if (hash_del(ph, cbuf_get(key)) < 0)
|
||||
goto done;
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (key)
|
||||
cbuf_free(key);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn this on to get a xml parse and pretty print test program
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@
|
|||
#include "clixon_xsl.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_err.h"
|
||||
#include "clixon_xml_sort.h"
|
||||
#include "clixon_xml_map.h"
|
||||
|
||||
/* Something to do with reverse engineering of junos syntax? */
|
||||
|
|
@ -590,136 +591,6 @@ cvec2xml_1(cvec *cvv,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Given child tree x1c, find matching child in base tree x0
|
||||
* param[in] x0 Base tree node
|
||||
* param[in] x1c Modification tree child
|
||||
* param[in] yc Yang spec of tree child
|
||||
* param[out] x0cp Matching base tree child (if any)
|
||||
* @note XXX: room for optimization? on 1K calls we have 1M body calls and
|
||||
500K xml_child_each/cvec_each calls.
|
||||
The outer loop is large for large lists
|
||||
The inner loop is small
|
||||
Major time in xml_find_body()
|
||||
Can one do a binary search in the x0 list?
|
||||
*/
|
||||
int
|
||||
match_base_child(cxobj *x0,
|
||||
cxobj *x1c,
|
||||
cxobj **x0cp,
|
||||
yang_stmt *yc)
|
||||
{
|
||||
int retval = -1;
|
||||
char *x1cname;
|
||||
cxobj *x0c = NULL; /* x0 child */
|
||||
cvec *cvk = NULL; /* vector of index keys */
|
||||
cg_var *cvi;
|
||||
char *b0;
|
||||
char *b1;
|
||||
yang_stmt *ykey;
|
||||
char *keyname;
|
||||
int equal;
|
||||
char **b1vec = NULL;
|
||||
int i;
|
||||
cxobj **p;
|
||||
cbuf *key = NULL; /* cligen buffer hash key */
|
||||
size_t vlen;
|
||||
|
||||
if (xml_child_hash){
|
||||
*x0cp = NULL; /* return value */
|
||||
if (xml_hash(x0) == NULL)
|
||||
goto nohash;
|
||||
if ((key = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done1;
|
||||
}
|
||||
if (xml_hash_key(x1c, yc, key) < 0)
|
||||
goto done;
|
||||
x0c = NULL;
|
||||
if (cbuf_len(key))
|
||||
if ((p = hash_value(xml_hash(x0), cbuf_get(key), &vlen)) != NULL){
|
||||
assert(vlen == sizeof(x0c));
|
||||
x0c = *p;
|
||||
}
|
||||
// fprintf(stderr, "%s get %s = 0x%x\n", __FUNCTION__, cbuf_get(key), (unsigned int)x0c);
|
||||
*x0cp = x0c;
|
||||
retval = 0;
|
||||
done1:
|
||||
if (key)
|
||||
cbuf_free(key);
|
||||
return retval;
|
||||
}
|
||||
nohash:
|
||||
*x0cp = NULL; /* return value */
|
||||
x1cname = xml_name(x1c);
|
||||
switch (yc->ys_keyword){
|
||||
case Y_CONTAINER: /* Equal regardless */
|
||||
case Y_LEAF: /* Equal regardless */
|
||||
x0c = xml_find(x0, x1cname);
|
||||
break;
|
||||
case Y_LEAF_LIST: /* Match with name and value */
|
||||
if ((b1 = xml_body(x1c)) == NULL)
|
||||
goto ok;
|
||||
x0c = xml_find_body_obj(x0, x1cname, b1);
|
||||
break;
|
||||
case Y_LIST: /* Match with key values */
|
||||
if ((ykey = yang_find((yang_node*)yc, Y_KEY, NULL)) == NULL){
|
||||
clicon_err(OE_XML, errno, "%s: List statement \"%s\" has no key",
|
||||
__FUNCTION__, yc->ys_argument);
|
||||
goto done;
|
||||
}
|
||||
/* The value is a list of keys: <key>[ <key>]* */
|
||||
if ((cvk = yang_arg2cvec(ykey, " ")) == NULL)
|
||||
goto done;
|
||||
cvi = NULL; i = 0;
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL)
|
||||
i++;
|
||||
if ((b1vec = calloc(i, sizeof(b1))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "calloc");
|
||||
goto done;
|
||||
}
|
||||
cvi = NULL; i = 0;
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
|
||||
keyname = cv_string_get(cvi);
|
||||
if ((b1 = xml_find_body(x1c, keyname)) == NULL)
|
||||
goto ok; /* not found */
|
||||
b1vec[i++] = b1;
|
||||
}
|
||||
/* Iterate over x0 tree to (1) find a child that matches name
|
||||
(2) that have keys that matches */
|
||||
x0c = NULL;
|
||||
while ((x0c = xml_child_each(x0, x0c, CX_ELMNT)) != NULL){
|
||||
equal = 0;
|
||||
if (strcmp(xml_name(x0c), x1cname))
|
||||
continue;
|
||||
/* Must be inner loop */
|
||||
cvi = NULL; i = 0;
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
|
||||
b1 = b1vec[i++];
|
||||
equal = 0;
|
||||
keyname = cv_string_get(cvi);
|
||||
if ((b0 = xml_find_body(x0c, keyname)) == NULL)
|
||||
break; /* error case */
|
||||
if (strcmp(b0, b1))
|
||||
break; /* stop as soon as inequal key found */
|
||||
equal=1; /* reaches here for all keynames, x0c is found. */
|
||||
}
|
||||
if (equal) /* x0c and x1c equal, otherwise look for other */
|
||||
break;
|
||||
} /* while x0c */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ok:
|
||||
*x0cp = x0c;
|
||||
retval = 0;
|
||||
done:
|
||||
if (b1vec)
|
||||
free(b1vec);
|
||||
if (cvk)
|
||||
cvec_free(cvk);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Find next yang node, either start from yang_spec or some yang-node
|
||||
* @param[in] y Node spec or sny yang-node
|
||||
|
|
@ -895,7 +766,6 @@ yang2api_path_fmt_1(yang_stmt *ys,
|
|||
cbuf *cb)
|
||||
{
|
||||
yang_node *yp; /* parent */
|
||||
yang_stmt *ykey;
|
||||
int i;
|
||||
cvec *cvk = NULL; /* vector of index keys */
|
||||
int retval = -1;
|
||||
|
|
@ -926,14 +796,7 @@ yang2api_path_fmt_1(yang_stmt *ys,
|
|||
|
||||
switch (ys->ys_keyword){
|
||||
case Y_LIST:
|
||||
if ((ykey = yang_find((yang_node*)ys, Y_KEY, NULL)) == NULL){
|
||||
clicon_err(OE_XML, errno, "%s: List statement \"%s\" has no key",
|
||||
__FUNCTION__, ys->ys_argument);
|
||||
goto done;
|
||||
}
|
||||
/* The value is a list of keys: <key>[ <key>]* */
|
||||
if ((cvk = yang_arg2cvec(ykey, " ")) == NULL)
|
||||
goto done;
|
||||
cvk = ys->ys_cvec; /* Use Y_LIST cache, see ys_populate_list() */
|
||||
if (cvec_len(cvk))
|
||||
cprintf(cb, "=");
|
||||
/* Iterate over individual keys */
|
||||
|
|
@ -951,8 +814,6 @@ yang2api_path_fmt_1(yang_stmt *ys,
|
|||
} /* switch */
|
||||
retval = 0;
|
||||
done:
|
||||
if (cvk)
|
||||
cvec_free(cvk);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -1370,13 +1231,16 @@ xml_order(cxobj *xt,
|
|||
goto done;
|
||||
}
|
||||
j0 = 0;
|
||||
/* Go through xml children and ensure they are same order as yspec children */
|
||||
/* Go through yang node's children and ensure that the
|
||||
* xml children follow this order.
|
||||
* Do not order the list or leaf-list children (have same name).
|
||||
*/
|
||||
for (i=0; i<y->ys_len; i++){
|
||||
yc = y->ys_stmt[i];
|
||||
if (!yang_datanode(yc))
|
||||
continue;
|
||||
yname = yc->ys_argument;
|
||||
/* First go thru xml children with same name */
|
||||
/* First go thru xml children with same name in rest of list */
|
||||
for (; j0<xml_child_nr(xt); j0++){
|
||||
xc = xml_child_i(xt, j0);
|
||||
if (xml_type(xc) != CX_ELMNT)
|
||||
|
|
@ -1528,7 +1392,6 @@ api_path2xpath_cvv(yang_spec *yspec,
|
|||
yang_stmt *y = NULL;
|
||||
char *val;
|
||||
char *v;
|
||||
yang_stmt *ykey;
|
||||
cg_var *cvi;
|
||||
|
||||
for (i=offset; i<cvec_len(cvv); i++){
|
||||
|
|
@ -1559,17 +1422,7 @@ api_path2xpath_cvv(yang_spec *yspec,
|
|||
*v = '\0';
|
||||
v++;
|
||||
}
|
||||
/* Find keys */
|
||||
if ((ykey = yang_find((yang_node*)y, Y_KEY, NULL)) == NULL){
|
||||
clicon_err(OE_XML, errno, "%s: List statement \"%s\" has no key",
|
||||
__FUNCTION__, y->ys_argument);
|
||||
goto done;
|
||||
}
|
||||
clicon_debug(1, "ykey:%s", ykey->ys_argument);
|
||||
|
||||
/* The value is a list of keys: <key>[ <key>]* */
|
||||
if ((cvk = yang_arg2cvec(ykey, " ")) == NULL)
|
||||
goto done;
|
||||
cvk = y->ys_cvec; /* Use Y_LIST cache, see ys_populate_list() */
|
||||
cvi = NULL;
|
||||
/* Iterate over individual yang keys */
|
||||
cprintf(xpath, "/%s", name);
|
||||
|
|
@ -1647,7 +1500,6 @@ api_path2xml_vec(char **vec,
|
|||
char *name;
|
||||
char *restval = NULL;
|
||||
char *restval_enc;
|
||||
yang_stmt *ykey;
|
||||
cxobj *xn = NULL; /* new */
|
||||
cxobj *xb; /* body */
|
||||
cvec *cvk = NULL; /* vector of index keys */
|
||||
|
|
@ -1709,15 +1561,7 @@ api_path2xml_vec(char **vec,
|
|||
goto done;
|
||||
break;
|
||||
case Y_LIST:
|
||||
/* Get the yang list key */
|
||||
if ((ykey = yang_find((yang_node*)y, Y_KEY, NULL)) == NULL){
|
||||
clicon_err(OE_XML, errno, "%s: List statement \"%s\" has no key",
|
||||
__FUNCTION__, y->ys_argument);
|
||||
goto done;
|
||||
}
|
||||
/* The value is a list of keys: <key>[ <key>]* */
|
||||
if ((cvk = yang_arg2cvec(ykey, " ")) == NULL)
|
||||
goto done;
|
||||
cvk = y->ys_cvec; /* Use Y_LIST cache, see ys_populate_list() */
|
||||
if (valvec){
|
||||
free(valvec);
|
||||
valvec = NULL;
|
||||
|
|
@ -1754,10 +1598,6 @@ api_path2xml_vec(char **vec,
|
|||
if (xml_value_set(xb, val2) <0)
|
||||
goto done;
|
||||
}
|
||||
if (cvk){
|
||||
cvec_free(cvk);
|
||||
cvk = NULL;
|
||||
}
|
||||
break;
|
||||
default: /* eg Y_CONTAINER, Y_LEAF */
|
||||
if ((x = xml_new(name, x0, y)) == NULL)
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@
|
|||
#include "clixon_handle.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_xml_sort.h"
|
||||
#include "clixon_xml_parse.h"
|
||||
|
||||
void
|
||||
|
|
|
|||
476
lib/src/clixon_xml_sort.c
Normal file
476
lib/src/clixon_xml_sort.c
Normal file
|
|
@ -0,0 +1,476 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2017 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 *****
|
||||
|
||||
* XML search functions when used with YANG
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "clixon_config.h" /* generated by config & autoconf */
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
/* clixon */
|
||||
#include "clixon_err.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_string.h"
|
||||
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_xml_sort.h"
|
||||
|
||||
/*
|
||||
* Variables
|
||||
*/
|
||||
|
||||
/* Sort and binary search of XML children
|
||||
* Experimental
|
||||
*/
|
||||
int xml_child_sort = 1;
|
||||
|
||||
|
||||
/*! Given an XML object and a child name, return yang stmt of child
|
||||
* If no xml parent, find root yang stmt matching name
|
||||
* @param[in] name Name of child
|
||||
* @param[in] xp XML parent, can be NULL.
|
||||
* @param[in] yspec Yang specification (top level)
|
||||
* @param[out] yresult Pointer to yang stmt of result, or NULL, if not found
|
||||
*/
|
||||
int
|
||||
xml_child_spec(char *name,
|
||||
cxobj *xp,
|
||||
yang_spec *yspec,
|
||||
yang_stmt **yresult)
|
||||
{
|
||||
yang_stmt *y; /* result yang node */
|
||||
yang_stmt *yparent; /* parent yang */
|
||||
|
||||
if (xp && (yparent = xml_spec(xp)) != NULL)
|
||||
y = yang_find_datanode((yang_node*)yparent, name);
|
||||
else if (yspec)
|
||||
y = yang_find_topnode(yspec, name, 0); /* still NULL for config */
|
||||
else
|
||||
y = NULL;
|
||||
*yresult = y;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @param[in] yangi Yang order
|
||||
* @param[in] keynr Length of keyvec/keyval vector when applicable
|
||||
* @param[in] keyvec Array of of yang key identifiers
|
||||
* @param[in] keyval Array of of yang key values
|
||||
* @param[out] userorder If set, this yang order is user ordered, linear search
|
||||
* @retval 0 If equal (or userorder set)
|
||||
* @retval <0 if arg1 is less than arg2
|
||||
* @retval >0 if arg1 is greater than arg2
|
||||
*/
|
||||
static int
|
||||
xml_cmp1(cxobj *x,
|
||||
yang_stmt *y,
|
||||
char *name,
|
||||
enum rfc_6020 keyword,
|
||||
int keynr,
|
||||
char **keyvec,
|
||||
char **keyval,
|
||||
int *userorder)
|
||||
{
|
||||
char *b;
|
||||
int i;
|
||||
char *keyname;
|
||||
char *key;
|
||||
|
||||
/* Check if same yang spec (order in yang stmt list) */
|
||||
switch (keyword){
|
||||
case Y_CONTAINER: /* Match with name */
|
||||
case Y_LEAF: /* Match with name */
|
||||
return strcmp(name, xml_name(x));
|
||||
break;
|
||||
case Y_LEAF_LIST: /* Match with name and value */
|
||||
if (userorder && yang_find((yang_node*)y, Y_ORDERED_BY, "user") != NULL)
|
||||
*userorder=1;
|
||||
b=xml_body(x);
|
||||
return strcmp(keyval[0], b);
|
||||
break;
|
||||
case Y_LIST: /* Match with array of key values */
|
||||
if (userorder && yang_find((yang_node*)y, Y_ORDERED_BY, "user") != NULL)
|
||||
*userorder=1;
|
||||
for (i=0; i<keynr; i++){
|
||||
keyname = keyvec[i];
|
||||
key = keyval[i];
|
||||
if ((b = xml_find_body(x, keyname)) == NULL)
|
||||
break; /* error case */
|
||||
return strcmp(key, b);
|
||||
}
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0; /* should not reach here */
|
||||
}
|
||||
|
||||
static cxobj *
|
||||
xml_search_userorder(cxobj *x0,
|
||||
yang_stmt *y,
|
||||
char *name,
|
||||
int yangi,
|
||||
int mid,
|
||||
enum rfc_6020 keyword,
|
||||
int keynr,
|
||||
char **keyvec,
|
||||
char **keyval)
|
||||
{
|
||||
int i;
|
||||
cxobj *xc;
|
||||
|
||||
for (i=mid+1; i<xml_child_nr(x0); i++){ /* First increment */
|
||||
xc = xml_child_i(x0, i);
|
||||
y = xml_spec(xc);
|
||||
if (yangi!=yang_order(y))
|
||||
break;
|
||||
if (xml_cmp1(xc, y, name, keyword, keynr, keyvec, keyval, NULL) == 0)
|
||||
return xc;
|
||||
}
|
||||
for (i=mid-1; i>=0; i--){ /* Then decrement */
|
||||
xc = xml_child_i(x0, i);
|
||||
y = xml_spec(xc);
|
||||
if (yangi!=yang_order(y))
|
||||
break;
|
||||
if (xml_cmp1(xc, y, name, keyword, keynr, keyvec, keyval, NULL) == 0)
|
||||
return xc;
|
||||
}
|
||||
return NULL; /* Not found */
|
||||
}
|
||||
|
||||
/*!
|
||||
* @param[in] yangi Yang order
|
||||
* @param[in] keynr Length of keyvec/keyval vector when applicable
|
||||
* @param[in] keyvec Array of of yang key identifiers
|
||||
* @param[in] keyval Array of of yang key values
|
||||
* @param[in] low Lower bound of childvec search interval
|
||||
* @param[in] upper Lower bound of childvec search interval
|
||||
*/
|
||||
static cxobj *
|
||||
xml_search1(cxobj *x0,
|
||||
char *name,
|
||||
int yangi,
|
||||
enum rfc_6020 keyword,
|
||||
int keynr,
|
||||
char **keyvec,
|
||||
char **keyval,
|
||||
int low,
|
||||
int upper)
|
||||
{
|
||||
int mid;
|
||||
int cmp;
|
||||
cxobj *xc;
|
||||
yang_stmt *y;
|
||||
int userorder= 0;
|
||||
|
||||
if (upper < low)
|
||||
return NULL; /* not found */
|
||||
mid = (low + upper) / 2;
|
||||
if (mid >= xml_child_nr(x0)) /* beyond range */
|
||||
return NULL;
|
||||
xc = xml_child_i(x0, mid);
|
||||
assert(y = xml_spec(xc));
|
||||
if ((cmp = yangi-yang_order(y)) == 0){
|
||||
cmp = xml_cmp1(xc, y, name, keyword, keynr, keyvec, keyval, &userorder);
|
||||
if (userorder && cmp) /* Look inside this yangi order */
|
||||
return xml_search_userorder(x0, y, name, yangi, mid, keyword, keynr, keyvec, keyval);
|
||||
}
|
||||
if (cmp == 0)
|
||||
return xc;
|
||||
else if (cmp < 0)
|
||||
return xml_search1(x0, name, yangi, keyword,
|
||||
keynr, keyvec, keyval, low, mid-1);
|
||||
else
|
||||
return xml_search1(x0, name, yangi, keyword,
|
||||
keynr, keyvec, keyval, mid+1, upper);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @param[in] yangi yang child order
|
||||
* @param[in] keynr Length of keyvec/keyval vector when applicable
|
||||
* @param[in] keyvec Array of of yang key identifiers
|
||||
* @param[in] keyval Array of of yang key values
|
||||
*/
|
||||
cxobj *
|
||||
xml_search(cxobj *x0,
|
||||
char *name,
|
||||
int yangi,
|
||||
enum rfc_6020 keyword,
|
||||
int keynr,
|
||||
char **keyvec,
|
||||
char **keyval)
|
||||
{
|
||||
return xml_search1(x0, name, yangi, keyword, keynr, keyvec, keyval,
|
||||
0, xml_child_nr(x0));
|
||||
}
|
||||
|
||||
/*! Find matching xml child given name and optional key values
|
||||
* container: x0, y->keyword, name
|
||||
* list: x0, y->keyword, y->key, name
|
||||
*
|
||||
* The function needs a vector of key values (or single for LEAF_LIST).
|
||||
* What format?
|
||||
* 1) argc/argv:: "val1","val2" <<==
|
||||
* 2) cv-list?
|
||||
* 3) va-list?
|
||||
*
|
||||
* yc - LIST (interface) -
|
||||
* ^
|
||||
* |
|
||||
* x0-->x0c-->(name=interface)+->x(name=name)->xb(value="eth0") <==this is
|
||||
* |
|
||||
* v
|
||||
* x1c->name (interface)
|
||||
* x1c->x(name=name)->xb(value="eth0")
|
||||
*
|
||||
* CONTAINER:name
|
||||
* LEAF: name
|
||||
* LEAFLIST: name/body... #b0
|
||||
* LIST: name/key0/key1... #b2vec+b0 -> x0c
|
||||
|
||||
* <interface><name>eth0</name></interface>
|
||||
* <interface><name>eth1</name></interface>
|
||||
* <interface><name>eth2</name></interface>
|
||||
* @param[in] x0 XML node. Find child of this node.
|
||||
* @param[in] keyword Yang keyword. Relevant: container, list, leaf, leaf_list
|
||||
* @param[in] keynr Length of keyvec/keyval vector when applicable
|
||||
* @param[in] keyvec Array of of yang key identifiers
|
||||
* @param[in] keyval Array of of yang key values
|
||||
* @param[out] xp Return value on success, pointer to XML child node
|
||||
* @note If keyword is:
|
||||
* - list, keyvec and keyval should be an array with keynr length
|
||||
* - leaf_list, keyval should be 1 and keyval should contain one element
|
||||
* - otherwise, keyval should be 0 and keyval and keyvec should be both NULL.
|
||||
*/
|
||||
cxobj *
|
||||
xml_match(cxobj *x0,
|
||||
char *name,
|
||||
enum rfc_6020 keyword,
|
||||
int keynr,
|
||||
char **keyvec,
|
||||
char **keyval)
|
||||
{
|
||||
char *key;
|
||||
char *keyname;
|
||||
char *b0;
|
||||
cxobj *x = NULL;
|
||||
int equal;
|
||||
int i;
|
||||
|
||||
x = NULL;
|
||||
switch (keyword){
|
||||
case Y_CONTAINER: /* Match with name */
|
||||
case Y_LEAF: /* Match with name */
|
||||
if (keynr != 0){
|
||||
clicon_err(OE_XML, EINVAL, "Expected no key argument to CONTAINER or LEAF");
|
||||
goto ok;
|
||||
}
|
||||
x = xml_find(x0, name);
|
||||
break;
|
||||
case Y_LEAF_LIST: /* Match with name and value */
|
||||
if (keynr != 1)
|
||||
goto ok;
|
||||
x = xml_find_body_obj(x0, name, keyval[0]);
|
||||
break;
|
||||
case Y_LIST: /* Match with array of key values */
|
||||
i = 0;
|
||||
while ((x = xml_child_each(x0, x, CX_ELMNT)) != NULL){
|
||||
equal = 0;
|
||||
if (strcmp(xml_name(x), name))
|
||||
continue;
|
||||
/* Must be inner loop */
|
||||
for (i=0; i<keynr; i++){
|
||||
keyname = keyvec[i];
|
||||
key = keyval[i];
|
||||
equal = 0;
|
||||
if ((b0 = xml_find_body(x, keyname)) == NULL)
|
||||
break; /* error case */
|
||||
if (strcmp(b0, key))
|
||||
break; /* stop as soon as inequal key found */
|
||||
equal=1; /* reaches here for all keynames, x is found. */
|
||||
}
|
||||
if (equal) /* x matches, oyherwise look for other */
|
||||
break;
|
||||
} /* while x */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ok:
|
||||
return x;
|
||||
}
|
||||
/*! Given child tree x1c, find matching child in base tree x0
|
||||
* param[in] x0 Base tree node
|
||||
* param[in] x1c Modification tree child
|
||||
* param[in] yc Yang spec of tree child
|
||||
* param[out] x0cp Matching base tree child (if any)
|
||||
* @note XXX: room for optimization? on 1K calls we have 1M body calls and
|
||||
500K xml_child_each/cvec_each calls.
|
||||
The outer loop is large for large lists
|
||||
The inner loop is small
|
||||
Major time in xml_find_body()
|
||||
Can one do a binary search in the x0 list?
|
||||
*/
|
||||
int
|
||||
match_base_child(cxobj *x0,
|
||||
cxobj *x1c,
|
||||
cxobj **x0cp,
|
||||
yang_stmt *yc)
|
||||
{
|
||||
int retval = -1;
|
||||
cvec *cvk = NULL; /* vector of index keys */
|
||||
cg_var *cvi;
|
||||
char *b1;
|
||||
char *keyname;
|
||||
char **keyval = NULL;
|
||||
char **keyvec = NULL;
|
||||
char keynr = 0;
|
||||
int i;
|
||||
|
||||
*x0cp = NULL; /* return value */
|
||||
switch (yc->ys_keyword){
|
||||
case Y_CONTAINER: /* Equal regardless */
|
||||
case Y_LEAF: /* Equal regardless */
|
||||
break;
|
||||
case Y_LEAF_LIST: /* Match with name and value */
|
||||
keynr = 1;
|
||||
if ((keyval = calloc(keynr+1, sizeof(char*))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "calloc");
|
||||
goto done;
|
||||
}
|
||||
if ((keyval[0] = xml_body(x1c)) == NULL)
|
||||
goto ok;
|
||||
break;
|
||||
case Y_LIST: /* Match with key values */
|
||||
cvk = yc->ys_cvec; /* Use Y_LIST cache, see ys_populate_list() */
|
||||
/* Count number of key indexes */
|
||||
cvi = NULL; keynr = 0;
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL)
|
||||
keynr++;
|
||||
if ((keyval = calloc(keynr+1, sizeof(char*))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "calloc");
|
||||
goto done;
|
||||
}
|
||||
if ((keyvec = calloc(keynr+1, sizeof(char*))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "calloc");
|
||||
goto done;
|
||||
}
|
||||
cvi = NULL; i = 0;
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
|
||||
keyname = cv_string_get(cvi);
|
||||
keyvec[i] = keyname;
|
||||
if ((b1 = xml_find_body(x1c, keyname)) == NULL)
|
||||
goto ok; /* not found */
|
||||
keyval[i++] = b1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Get match */
|
||||
{
|
||||
yang_node *y0;
|
||||
int yorder;
|
||||
|
||||
if ((y0 = yc->ys_parent) == NULL)
|
||||
goto done;
|
||||
/* XXX: No we cant do this. on uppermost layer it can look like this:
|
||||
* config
|
||||
* ximport-----ymod = ietf
|
||||
* interfaces--ymod = example
|
||||
* Which means yang order can be different for different children in the
|
||||
* same childvec.
|
||||
*/
|
||||
if (xml_child_sort==0)
|
||||
*x0cp = xml_match(x0, xml_name(x1c), yc->ys_keyword, keynr, keyvec, keyval);
|
||||
else{
|
||||
#if 1
|
||||
if (xml_child_nr(x0)==0 || xml_spec(xml_child_i(x0,0))!=NULL){
|
||||
yorder = yang_order(yc);
|
||||
*x0cp = xml_search(x0, xml_name(x1c), yorder, yc->ys_keyword, keynr, keyvec, keyval);
|
||||
}
|
||||
else{
|
||||
clicon_log(LOG_WARNING, "%s No yspec", __FUNCTION__);
|
||||
*x0cp = xml_match(x0, xml_name(x1c), yc->ys_keyword, keynr, keyvec, keyval);
|
||||
}
|
||||
#else
|
||||
cxobj *xx;
|
||||
|
||||
|
||||
|
||||
*x0cp = xml_match(x0, xml_name(x1c), yc->ys_keyword, keynr, keyvec, keyval);
|
||||
if (xml_child_nr(x0) && xml_spec(xml_child_i(x0,0))!=NULL){
|
||||
xx = xml_search(x0, xml_name(x1c), yorder, yc->ys_keyword, keynr, keyvec, keyval);
|
||||
if (xx!=*x0cp){
|
||||
clicon_log(LOG_WARNING, "%s mismatch", __FUNCTION__);
|
||||
fprintf(stderr, "mismatch\n");
|
||||
xml_search(x0, xml_name(x1c), yorder, yc->ys_keyword, keynr, keyvec, keyval);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
clicon_log(LOG_WARNING, "%s No yspec", __FUNCTION__);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (keyval)
|
||||
free(keyval);
|
||||
if (keyvec)
|
||||
free(keyvec);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -373,7 +373,7 @@ yn_each(yang_node *yn,
|
|||
*
|
||||
* @param[in] yn Yang node, current context node.
|
||||
* @param[in] keyword if 0 match any keyword
|
||||
* @param[in] argument String compare w wrgument. if NULL, match any.
|
||||
* @param[in] argument String compare w argument. if NULL, match any.
|
||||
* This however means that if you actually want to match only a yang-stmt with
|
||||
* argument==NULL you cannot, but I have not seen any such examples.
|
||||
* @see yang_find_datanode
|
||||
|
|
@ -384,8 +384,8 @@ yang_find(yang_node *yn,
|
|||
char *argument)
|
||||
{
|
||||
yang_stmt *ys = NULL;
|
||||
int i;
|
||||
int match = 0;
|
||||
int i;
|
||||
int match = 0;
|
||||
|
||||
for (i=0; i<yn->yn_len; i++){
|
||||
ys = yn->yn_stmt[i];
|
||||
|
|
@ -558,6 +558,54 @@ yang_find_myprefix(yang_stmt *ys)
|
|||
return prefix;
|
||||
}
|
||||
|
||||
/*! Find matching y in yp:s children, return 0 and index or -1 if not found.
|
||||
* @retval 0 not found
|
||||
* @retval 1 found
|
||||
*/
|
||||
static int
|
||||
order1(yang_node *yp,
|
||||
yang_stmt *y,
|
||||
int *index)
|
||||
{
|
||||
yang_stmt *ys;
|
||||
int i;
|
||||
|
||||
for (i=0; i<yp->yn_len; i++){
|
||||
ys = yp->yn_stmt[i];
|
||||
if (!yang_datanode(ys))
|
||||
continue;
|
||||
if (ys==y)
|
||||
return 1;
|
||||
(*index)++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Return order of yang statement y in parents child vector
|
||||
* @retval i Order of child with specified argument
|
||||
* @retval -1 Not found
|
||||
*/
|
||||
int
|
||||
yang_order(yang_stmt *y)
|
||||
{
|
||||
yang_node *yp;
|
||||
yang_node *ypp;
|
||||
yang_node *yn;
|
||||
int i;
|
||||
int j=0;
|
||||
|
||||
yp = y->ys_parent;
|
||||
if (yp->yn_keyword == Y_MODULE ||yp->yn_keyword == Y_SUBMODULE){
|
||||
ypp = yp->yn_parent;
|
||||
for (i=0; i<ypp->yn_len; i++){
|
||||
yn = (yang_node*)ypp->yn_stmt[i];
|
||||
if (order1(yn, y, &j) == 1)
|
||||
return j;
|
||||
}
|
||||
}
|
||||
order1(yp, y, &j);
|
||||
return j;
|
||||
}
|
||||
|
||||
/*! Reset flag in complete tree, arg contains flag */
|
||||
static int
|
||||
|
|
@ -880,6 +928,20 @@ ys_populate_leaf(yang_stmt *ys,
|
|||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
ys_populate_list(yang_stmt *ys,
|
||||
void *arg)
|
||||
{
|
||||
yang_stmt *ykey;
|
||||
|
||||
if ((ykey = yang_find((yang_node*)ys, Y_KEY, NULL)) == NULL)
|
||||
return 0;
|
||||
cvec_free(ys->ys_cvec);
|
||||
if ((ys->ys_cvec = yang_arg2cvec(ykey, " ")) == NULL)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Populate range and length statements
|
||||
*
|
||||
* Create cvec variables "range_min" and "range_max". Assume parent is type.
|
||||
|
|
@ -1061,6 +1123,10 @@ ys_populate(yang_stmt *ys,
|
|||
if (ys_populate_leaf(ys, arg) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case Y_LIST:
|
||||
if (ys_populate_list(ys, arg) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case Y_RANGE:
|
||||
case Y_LENGTH:
|
||||
if (ys_populate_range(ys, arg) < 0)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
testnr=0
|
||||
testname=
|
||||
clixon_cf=/usr/local/etc/routing.xml
|
||||
# error and exit, arg is optional extra errmsg
|
||||
err(){
|
||||
echo "Error in Test$testnr [$testname]:"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
# include err() and new() functions
|
||||
. ./lib.sh
|
||||
clixon_cf="-f /usr/local/etc/routing.xml"
|
||||
cfg=/usr/local/etc/routing.xml
|
||||
|
||||
# For memcheck
|
||||
#clixon_cli="valgrind --leak-check=full --show-leak-kinds=all clixon_cli"
|
||||
|
|
@ -17,81 +17,81 @@ clixon_cli=clixon_cli
|
|||
|
||||
# kill old backend (if any)
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -z $clixon_cf
|
||||
sudo clixon_backend -z -f $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
new "start backend"
|
||||
# start new backend
|
||||
sudo clixon_backend -s init $clixon_cf
|
||||
sudo clixon_backend -s init -f $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
new "cli tests"
|
||||
|
||||
new "cli configure top"
|
||||
expectfn "$clixon_cli -1 $clixon_cf set interfaces" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg set interfaces" "^$"
|
||||
|
||||
new "cli show configuration top (no presence)"
|
||||
expectfn "$clixon_cli -1 $clixon_cf show conf cli" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg show conf cli" "^$"
|
||||
|
||||
new "cli configure delete top"
|
||||
expectfn "$clixon_cli -1 $clixon_cf delete interfaces" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg delete interfaces" "^$"
|
||||
|
||||
new "cli show configuration delete top"
|
||||
expectfn "$clixon_cli -1 $clixon_cf show conf cli" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg show conf cli" "^$"
|
||||
|
||||
new "cli configure"
|
||||
expectfn "$clixon_cli -1 $clixon_cf set interfaces interface eth/0/0" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0" "^$"
|
||||
|
||||
new "cli show configuration"
|
||||
expectfn "$clixon_cli -1 $clixon_cf show conf cli" "^interfaces interface name eth/0/0" "interfaces interface enabled true$"
|
||||
expectfn "$clixon_cli -1 -f $cfg show conf cli" "^interfaces interface name eth/0/0" "interfaces interface enabled true$"
|
||||
|
||||
new "cli failed validate"
|
||||
expectfn "$clixon_cli -1 $clixon_cf -l o validate" "Missing mandatory variable"
|
||||
expectfn "$clixon_cli -1 -f $cfg -l o validate" "Missing mandatory variable"
|
||||
|
||||
new "cli configure more"
|
||||
expectfn "$clixon_cli -1 $clixon_cf set interfaces interface eth/0/0 ipv4 address 1.2.3.4 prefix-length 24" "^$"
|
||||
expectfn "$clixon_cli -1 $clixon_cf set interfaces interface eth/0/0 description mydesc" "^$"
|
||||
expectfn "$clixon_cli -1 $clixon_cf set interfaces interface eth/0/0 type bgp" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 ipv4 address 1.2.3.4 prefix-length 24" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 description mydesc" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 type bgp" "^$"
|
||||
|
||||
new "cli show xpath description"
|
||||
expectfn "$clixon_cli -1 $clixon_cf -l o show xpath /interfaces/interface/description" "<description>mydesc</description>"
|
||||
expectfn "$clixon_cli -1 -f $cfg -l o show xpath /interfaces/interface/description" "<description>mydesc</description>"
|
||||
|
||||
new "cli delete description"
|
||||
expectfn "$clixon_cli -1 $clixon_cf -l o delete interfaces interface eth/0/0 description mydesc"
|
||||
expectfn "$clixon_cli -1 -f $cfg -l o delete interfaces interface eth/0/0 description mydesc"
|
||||
|
||||
new "cli show xpath no description"
|
||||
expectfn "$clixon_cli -1 $clixon_cf -l o show xpath /interfaces/interface/description" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg -l o show xpath /interfaces/interface/description" "^$"
|
||||
|
||||
new "cli copy interface"
|
||||
expectfn "$clixon_cli -1 $clixon_cf copy interface eth/0/0 to eth99" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg copy interface eth/0/0 to eth99" "^$"
|
||||
|
||||
new "cli success validate"
|
||||
expectfn "$clixon_cli -1 $clixon_cf -l o validate" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg -l o validate" "^$"
|
||||
|
||||
new "cli commit"
|
||||
expectfn "$clixon_cli -1 $clixon_cf -l o commit" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg -l o commit" "^$"
|
||||
|
||||
new "cli save"
|
||||
expectfn "$clixon_cli -1 $clixon_cf -l o save /tmp/foo" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg -l o save /tmp/foo" "^$"
|
||||
|
||||
new "cli delete all"
|
||||
expectfn "$clixon_cli -1 $clixon_cf -l o delete all" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg -l o delete all" "^$"
|
||||
|
||||
new "cli load"
|
||||
expectfn "$clixon_cli -1 $clixon_cf -l o load /tmp/foo" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg -l o load /tmp/foo" "^$"
|
||||
|
||||
new "cli check load"
|
||||
expectfn "$clixon_cli -1 $clixon_cf -l o show conf cli" "^interfaces interface name eth/0/0" "interfaces interface enabled true$"
|
||||
expectfn "$clixon_cli -1 -f $cfg -l o show conf cli" "^interfaces interface name eth/0/0" "interfaces interface enabled true$"
|
||||
|
||||
new "cli debug"
|
||||
expectfn "$clixon_cli -1 $clixon_cf -l o debug level 1" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg -l o debug level 1" "^$"
|
||||
# How to test this?
|
||||
expectfn "$clixon_cli -1 $clixon_cf -l o debug level 0" "^$"
|
||||
expectfn "$clixon_cli -1 -f $cfg -l o debug level 0" "^$"
|
||||
|
||||
new "cli rpc"
|
||||
expectfn "$clixon_cli -1 $clixon_cf -l o rpc ipv4" "^<rpc-reply>"
|
||||
expectfn "$clixon_cli -1 -f $cfg -l o rpc ipv4" "^<rpc-reply>"
|
||||
|
||||
new "Kill backend"
|
||||
# Check if still alive
|
||||
|
|
@ -100,7 +100,7 @@ if [ -z "$pid" ]; then
|
|||
err "backend already dead"
|
||||
fi
|
||||
# kill backend
|
||||
sudo clixon_backend -z $clixon_cf
|
||||
sudo clixon_backend -z -f $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err "kill backend"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -3,13 +3,15 @@
|
|||
|
||||
# include err() and new() functions
|
||||
. ./lib.sh
|
||||
cfg=/usr/local/etc/routing.xml
|
||||
fyang=/tmp/leafref.yang
|
||||
|
||||
# For memcheck
|
||||
# clixon_netconf="valgrind --leak-check=full --show-leak-kinds=all clixon_netconf"
|
||||
clixon_netconf=clixon_netconf
|
||||
clixon_cli=clixon_cli
|
||||
|
||||
cat <<EOF > /tmp/leafref.yang
|
||||
cat <<EOF > $fyang
|
||||
module example{
|
||||
import ietf-ip {
|
||||
prefix ip;
|
||||
|
|
@ -48,70 +50,70 @@ EOF
|
|||
|
||||
# kill old backend (if any)
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $clixon_cf -y /tmp/leafref.yang
|
||||
sudo clixon_backend -zf $cfg -y $fyang
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
||||
new "start backend"
|
||||
# start new backend
|
||||
sudo clixon_backend -s init -f $clixon_cf -y /tmp/leafref.yang
|
||||
sudo clixon_backend -s init -f $cfg -y $fyang
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
||||
new "leafref base config"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><edit-config><target><candidate/></target><config><interfaces>
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><interfaces>
|
||||
<interface><name>eth0</name> <type>eth</type> <ipv4><address><ip>192.0.2.1</ip></address><address><ip>192.0.2.2</ip></address></ipv4></interface>
|
||||
<interface><name>lo</name><type>lo</type><ipv4><address><ip>127.0.0.1</ip></address></ipv4></interface>
|
||||
</interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "leafref get config"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interfaces><interface><name>eth0</name>'
|
||||
expecteof "$clixon_netconf -qf $cfg" '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interfaces><interface><name>eth0</name>'
|
||||
|
||||
new "leafref base commit"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "leafref add wrong ref"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><edit-config><target><candidate/></target><config><default-address><absname>eth3</absname><address>10.0.4.6</address></default-address></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><default-address><absname>eth3</absname><address>10.0.4.6</address></default-address></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "leafref validate"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>missing-attribute</error-tag>"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>missing-attribute</error-tag>"
|
||||
|
||||
new "leafref discard-changes"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "leafref add correct absref"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><edit-config><target><candidate/></target><config><default-address><absname>eth0</absname></default-address></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><default-address><absname>eth0</absname></default-address></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "leafref add correct relref"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><edit-config><target><candidate/></target><config><default-address><relname>eth0</relname></default-address></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><default-address><relname>eth0</relname></default-address></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
# XXX add address
|
||||
|
||||
new "leafref validate (ok)"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
|
||||
|
||||
new "leafref delete leaf"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation=\"delete\"><name>eth0</name></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation=\"delete\"><name>eth0</name></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
|
||||
|
||||
new "leafref validate (should fail)"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>missing-attribute</error-tag>"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>missing-attribute</error-tag>"
|
||||
|
||||
new "leafref discard-changes"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
exit
|
||||
new "cli leafref lo"
|
||||
expectfn "$clixon_cli -1f $clixon_cf -y /tmp/leafref.yang -l o set default-address absname lo" "^$"
|
||||
expectfn "$clixon_cli -1f $cfg -y $fyang -l o set default-address absname lo" "^$"
|
||||
|
||||
new "cli leafref validate"
|
||||
expectfn "$clixon_cli -1f $clixon_cf -y /tmp/leafref.yang -l o validate" "^$"
|
||||
expectfn "$clixon_cli -1f $cfg -y $fyang -l o validate" "^$"
|
||||
|
||||
new "cli sender"
|
||||
expectfn "$clixon_cli -1f $clixon_cf -y /tmp/leafref.yang -l o set sender a" "^$"
|
||||
expectfn "$clixon_cli -1f $cfg -y $fyang -l o set sender a" "^$"
|
||||
|
||||
new "cli sender template"
|
||||
expectfn "$clixon_cli -1f $clixon_cf -y /tmp/leafref.yang -l o set sender b template a" "^$"
|
||||
expectfn "$clixon_cli -1f $cfg -y $fyang -l o set sender b template a" "^$"
|
||||
|
||||
new "Kill backend"
|
||||
# Check if still alive
|
||||
|
|
@ -120,7 +122,7 @@ if [ -z "$pid" ]; then
|
|||
err "backend already dead"
|
||||
fi
|
||||
# kill backend
|
||||
sudo clixon_backend -zf $clixon_cf
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err "kill backend"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -3,137 +3,137 @@
|
|||
|
||||
# include err() and new() functions
|
||||
. ./lib.sh
|
||||
clixon_cf="-f /usr/local/etc/routing.xml"
|
||||
cfg=/usr/local/etc/routing.xml
|
||||
|
||||
# For memcheck
|
||||
#clixon_netconf="valgrind --leak-check=full --show-leak-kinds=all clixon_netconf"
|
||||
clixon_netconf=clixon_netconf
|
||||
|
||||
echo "clixon_backend -z $clixon_cf"
|
||||
echo "clixon_backend -zf $cfg"
|
||||
# kill old backend (if any)
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -z $clixon_cf
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
new "start backend"
|
||||
# start new backend
|
||||
sudo clixon_backend -s init $clixon_cf
|
||||
sudo clixon_backend -s init -f $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
||||
new "netconf tests"
|
||||
|
||||
expecteof "$clixon_netconf -q $clixon_cf" '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'
|
||||
expecteof "$clixon_netconf -qf $cfg" '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'
|
||||
|
||||
new "Add subtree eth/0/0 using none which should not change anything"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><edit-config><default-operation>none</default-operation><target><candidate/></target><config><interfaces><interface><name>eth/0/0</name></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><edit-config><default-operation>none</default-operation><target><candidate/></target><config><interfaces><interface><name>eth/0/0</name></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "Check nothing added"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'
|
||||
expecteof "$clixon_netconf -qf $cfg" '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'
|
||||
|
||||
new "Add subtree eth/0/0 using none and create which should add eth/0/0"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="create"><name>eth/0/0</name><type>eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="create"><name>eth/0/0</name><type>eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "Check eth/0/0 added using xpath"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth/0/0]"/></get-config></rpc>]]>]]>' "^<rpc-reply><data><interfaces><interface><name>eth/0/0</name><type>eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth/0/0]"/></get-config></rpc>]]>]]>' "^<rpc-reply><data><interfaces><interface><name>eth/0/0</name><type>eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "Re-create same eth/0/0 which should generate error"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="create"><name>eth/0/0</name><type>eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error>"
|
||||
expecteof "$clixon_netconf -qf $cfg" '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="create"><name>eth/0/0</name><type>eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error>"
|
||||
|
||||
new "Delete eth/0/0 using none config"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="delete"><name>eth/0/0</name><type>eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="delete"><name>eth/0/0</name><type>eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "Check deleted eth/0/0 (non-presence container)"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'
|
||||
expecteof "$clixon_netconf -qf $cfg" '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'
|
||||
|
||||
new "Re-Delete eth/0/0 using none should generate error"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="delete"><name>eth/0/0</name><type>eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error>"
|
||||
expecteof "$clixon_netconf -qf $cfg" '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="delete"><name>eth/0/0</name><type>eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error>"
|
||||
|
||||
new "netconf edit config"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth/0/0</name></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth/0/0</name></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf get config xpath"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth1]/enabled"/></get-config></rpc>]]>]]>' "^<rpc-reply><data><interfaces><interface><name>eth1</name><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth1]/enabled"/></get-config></rpc>]]>]]>' "^<rpc-reply><data><interfaces><interface><name>eth1</name><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf get config xpath parent"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth1]/enabled/../.."/></get-config></rpc>]]>]]>' "^<rpc-reply><data><interfaces><interface><name>eth/0/0</name><enabled>true</enabled></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><enabled>true</enabled><forwarding>false</forwarding><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth1]/enabled/../.."/></get-config></rpc>]]>]]>' "^<rpc-reply><data><interfaces><interface><name>eth/0/0</name><enabled>true</enabled></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><enabled>true</enabled><forwarding>false</forwarding><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf validate missing type"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
||||
|
||||
new "netconf discard-changes"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf get empty config2"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf edit extra xml"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><edit-config><target><candidate/></target><config><interfaces><extra/></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><edit-config><target><candidate/></target><config><interfaces><extra/></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
||||
|
||||
new "netconf discard-changes"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf edit config eth1"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth1</name><type>eth</type></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth1</name><type>eth</type></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf validate"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf commit"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf edit config replace XXX is merge?"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth2</name><type>eth</type></interface></interfaces></config><default-operation>merge</default-operation></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth2</name><type>eth</type></interface></interfaces></config><default-operation>merge</default-operation></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf get replaced config"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><interfaces><interface><name>eth1</name><type>eth</type><enabled>true</enabled></interface><interface><name>eth2</name><type>eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><interfaces><interface><name>eth1</name><type>eth</type><enabled>true</enabled></interface><interface><name>eth2</name><type>eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf discard-changes"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf edit state operation should fail"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><edit-config><target><candidate/></target><config><interfaces-state><interface><name>eth1</name><type>eth</type></interface></interfaces-state></config></edit-config></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>invalid-value</error-tag>"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><edit-config><target><candidate/></target><config><interfaces-state><interface><name>eth1</name><type>eth</type></interface></interfaces-state></config></edit-config></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>invalid-value</error-tag>"
|
||||
|
||||
new "netconf get state operation"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><get><filter type=\"xpath\" select=\"/interfaces-state\"/></get></rpc>]]>]]>" "^<rpc-reply><data><interfaces-state><interface><name>eth0</name><type>eth</type><if-index>42</if-index></interface></interfaces-state></data></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><get><filter type=\"xpath\" select=\"/interfaces-state\"/></get></rpc>]]>]]>" "^<rpc-reply><data><interfaces-state><interface><name>eth0</name><type>eth</type><if-index>42</if-index></interface></interfaces-state></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf lock/unlock"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]><rpc><unlock><target><candidate/></target></unlock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]><rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]><rpc><unlock><target><candidate/></target></unlock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]><rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf lock/lock"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf lock"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "close-session"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><close-session/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><close-session/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "kill-session"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><kill-session><session-id>44</session-id></kill-session></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><kill-session><session-id>44</session-id></kill-session></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "copy startup"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><copy-config><target><startup/></target><source><candidate/></source></copy-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><copy-config><target><startup/></target><source><candidate/></source></copy-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf get startup"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><get-config><source><startup/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><interfaces><interface><name>eth1</name><type>eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><get-config><source><startup/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><interfaces><interface><name>eth1</name><type>eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf delete startup"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><delete-config><target><startup/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><delete-config><target><startup/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf check empty startup"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><get-config><source><startup/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><get-config><source><startup/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf rpc"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><rt:fib-route><routing-instance-name>ipv4</routing-instance-name><destination-address><address-family>ipv4</address-family></destination-address></rt:fib-route></rpc>]]>]]>" "^<rpc-reply><route><address-family>ipv4</address-family><next-hop><next-hop-list>"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><rt:fib-route><routing-instance-name>ipv4</routing-instance-name><destination-address><address-family>ipv4</address-family></destination-address></rt:fib-route></rpc>]]>]]>" "^<rpc-reply><route><address-family>ipv4</address-family><next-hop><next-hop-list>"
|
||||
|
||||
new "netconf rpc w/o namespace"
|
||||
expecteof "$clixon_netconf -q $clixon_cf" "<rpc><fib-route><routing-instance-name>ipv4</routing-instance-name><destination-address><address-family>ipv4</address-family></destination-address></fib-route></rpc>]]>]]>" "^<rpc-reply><route><address-family>ipv4</address-family><next-hop><next-hop-list>"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><fib-route><routing-instance-name>ipv4</routing-instance-name><destination-address><address-family>ipv4</address-family></destination-address></fib-route></rpc>]]>]]>" "^<rpc-reply><route><address-family>ipv4</address-family><next-hop><next-hop-list>"
|
||||
|
||||
new "netconf subscription"
|
||||
expectwait "$clixon_netconf -q $clixon_cf" "<rpc><create-subscription><stream>ROUTING</stream></create-subscription></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]><notification><event>Routing notification</event></notification>]]>]]>$" 30
|
||||
expectwait "$clixon_netconf -qf $cfg" "<rpc><create-subscription><stream>ROUTING</stream></create-subscription></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]><notification><event>Routing notification</event></notification>]]>]]>$" 30
|
||||
|
||||
new "Kill backend"
|
||||
# Check if still alive
|
||||
|
|
@ -142,7 +142,7 @@ if [ -z "$pid" ]; then
|
|||
err "backend already dead"
|
||||
fi
|
||||
# kill backend
|
||||
sudo clixon_backend -z $clixon_cf
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err "kill backend"
|
||||
fi
|
||||
|
|
|
|||
177
test/test_order.sh
Executable file
177
test/test_order.sh
Executable file
|
|
@ -0,0 +1,177 @@
|
|||
#!/bin/bash
|
||||
# Order test. test ordered-by user and ordered-by system.
|
||||
# For each leaf and leaf-lists, there are two lists,
|
||||
# one ordered-by user and one ordered by system.
|
||||
# The ordered-by user MUST be the order it is entered.
|
||||
# No test of ordered-by system is done yet
|
||||
# (we may want to sort them alphabetically for better performance).
|
||||
|
||||
# include err() and new() functions
|
||||
. ./lib.sh
|
||||
cfg=/tmp/conf_yang.xml
|
||||
fyang=/tmp/order.yang
|
||||
|
||||
# For memcheck
|
||||
# clixon_netconf="valgrind --leak-check=full --show-leak-kinds=all clixon_netconf"
|
||||
clixon_netconf=clixon_netconf
|
||||
clixon_cli=clixon_cli
|
||||
dbdir=/tmp/order
|
||||
|
||||
new "Set up $dbdir"
|
||||
rm -rf $dbdir
|
||||
mkdir $dbdir
|
||||
|
||||
cat <<EOF > $cfg
|
||||
<config>
|
||||
<CLICON_CONFIGFILE>/tmp/conf_yang.xml</CLICON_CONFIGFILE>
|
||||
<CLICON_YANG_DIR>/usr/local/share/routing/yang</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
|
||||
<CLICON_CLISPEC_DIR>/usr/local/lib/routing/clispec</CLICON_CLISPEC_DIR>
|
||||
<CLICON_CLI_DIR>/usr/local/lib/routing/cli</CLICON_CLI_DIR>
|
||||
<CLICON_CLI_MODE>routing</CLICON_CLI_MODE>
|
||||
<CLICON_SOCK>/usr/local/var/routing/routing.sock</CLICON_SOCK>
|
||||
<CLICON_BACKEND_PIDFILE>/usr/local/var/routing/routing.pidfile</CLICON_BACKEND_PIDFILE>
|
||||
<CLICON_CLI_GENMODEL_COMPLETION>1</CLICON_CLI_GENMODEL_COMPLETION>
|
||||
<CLICON_XMLDB_DIR>$dbdir</CLICON_XMLDB_DIR>
|
||||
<CLICON_XMLDB_PLUGIN>/usr/local/lib/xmldb/text.so</CLICON_XMLDB_PLUGIN>
|
||||
<CLICON_XML_SORT>true</CLICON_XML_SORT>
|
||||
</config>
|
||||
EOF
|
||||
|
||||
cat <<EOF > $fyang
|
||||
module example{
|
||||
container c{
|
||||
leaf d{
|
||||
type string;
|
||||
}
|
||||
}
|
||||
leaf l{
|
||||
type string;
|
||||
}
|
||||
leaf-list y0 {
|
||||
ordered-by user;
|
||||
type string;
|
||||
}
|
||||
leaf-list y1 {
|
||||
ordered-by system;
|
||||
type string;
|
||||
}
|
||||
list y2 {
|
||||
ordered-by user;
|
||||
key "k";
|
||||
leaf k {
|
||||
type string;
|
||||
}
|
||||
leaf a {
|
||||
type string;
|
||||
}
|
||||
}
|
||||
list y3 {
|
||||
ordered-by system;
|
||||
key "k";
|
||||
leaf k {
|
||||
type string;
|
||||
}
|
||||
leaf a {
|
||||
type string;
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
cat <<EOF > $dbdir/running_db
|
||||
<config>
|
||||
<y0>d</y0>
|
||||
<y1>d</y1>
|
||||
<y2><k>d</k><a>bar</a></y2>
|
||||
<y3><k>d</k><a>bar</a></y3>
|
||||
<y0>b</y0>
|
||||
<y1>b</y1>
|
||||
<c><d>hej</d></c>
|
||||
<y0>c</y0>
|
||||
<y1>c</y1>
|
||||
<y2><k>a</k><a>bar</a></y2>
|
||||
<y3><k>a</k><a>bar</a></y3>
|
||||
<l>hopp</l>
|
||||
<y0>a</y0>
|
||||
<y1>a</y1>
|
||||
<y2><k>c</k><a>bar</a></y2>
|
||||
<y3><k>c</k><a>bar</a></y3>
|
||||
<y2><k>b</k><a>bar</a></y2>
|
||||
<y3><k>b</k><a>bar</a></y3>
|
||||
</config>
|
||||
EOF
|
||||
|
||||
# kill old backend (if any)
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $cfg -y $fyang
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
||||
new "start backend"
|
||||
# start new backend
|
||||
sudo clixon_backend -s running -f $cfg -y $fyang
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
||||
# Check as file
|
||||
new "verify running from start, should be: l,c,y0,y1,y2,y3; y1 and y3 sorted. Note this fails if XML_SORT set to false"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><get-config><source><running/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><c><d>hej</d></c><l>hopp</l><y0>d</y0><y0>b</y0><y0>c</y0><y0>a</y0><y1>a</y1><y1>b</y1><y1>c</y1><y1>d</y1><y2><k>d</k><a>bar</a></y2><y2><k>a</k><a>bar</a></y2><y2><k>c</k><a>bar</a></y2><y2><k>b</k><a>bar</a></y2><y3><k>a</k><a>bar</a></y3><y3><k>b</k><a>bar</a></y3><y3><k>c</k><a>bar</a></y3><y3><k>d</k><a>bar</a></y3></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "get each ordered-by user leaf-list"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k=a]\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y2><k>a</k><a>bar</a></y2></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "get each ordered-by user leaf-list"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k=a]\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y3><k>a</k><a>bar</a></y3></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "get each ordered-by user leaf-list"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k=b]\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y2><k>b</k><a>bar</a></y2></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "get each ordered-by user leaf-list"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k=b]\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y3><k>b</k><a>bar</a></y3></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "delete candidate"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><delete-config><target><candidate/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
# LEAF_LISTS
|
||||
|
||||
new "add two entries to leaf-list user order"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><y0>c</y0><y0>b</y0></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "add one entry to leaf-list user order"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><y0>a</y0></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf commit"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "add one entry to leaf-list user order after commit"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><y0>0</y0></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf commit"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "verify leaf-list user order in running (as entered)"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y0\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y0>c</y0><y0>b</y0><y0>a</y0><y0>0</y0></data></rpc-reply>]]>]]>$"
|
||||
|
||||
# LISTS
|
||||
|
||||
new "add two entries to list user order"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><y2><k>c</k><a>bar</a></y2><y2><k>b</k><a>foo</a></y2></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "add one entry to list user order"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><y2><k>a</k><a>fie</a></y2></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "verify list user order (as entered)"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/y2\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y2><k>c</k><a>bar</a></y2><y2><k>b</k><a>foo</a></y2><y2><k>a</k><a>fie</a></y2></data></rpc-reply>]]>]]>$"
|
||||
|
||||
pid=`pgrep clixon_backend`
|
||||
if [ -z "$pid" ]; then
|
||||
err "backend already dead"
|
||||
fi
|
||||
# kill backend
|
||||
#sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err "kill backend"
|
||||
fi
|
||||
|
|
@ -14,13 +14,14 @@ else
|
|||
echo "Usage: $0 [<number> [<requests>]]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cfg=/tmp/scaling-conf.xml
|
||||
fyang=/tmp/scaling.yang
|
||||
fconfig=/tmp/config
|
||||
|
||||
|
||||
# include err() and new() functions
|
||||
. ./lib.sh
|
||||
clixon_cf=/tmp/scaling-conf.xml
|
||||
|
||||
|
||||
# For memcheck
|
||||
# clixon_netconf="valgrind --leak-check=full --show-leak-kinds=all clixon_netconf"
|
||||
|
|
@ -46,9 +47,9 @@ module ietf-ip{
|
|||
}
|
||||
EOF
|
||||
|
||||
cat <<EOF > $clixon_cf
|
||||
cat <<EOF > $cfg
|
||||
<config>
|
||||
<CLICON_CONFIGFILE>$clixon_cf</CLICON_CONFIGFILE>
|
||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||
<CLICON_YANG_DIR>$fyang</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_MODULE_MAIN>ietf-ip</CLICON_YANG_MODULE_MAIN>
|
||||
<CLICON_SOCK>/usr/local/var/routing/routing.sock</CLICON_SOCK>
|
||||
|
|
@ -61,14 +62,14 @@ EOF
|
|||
|
||||
# kill old backend (if any)
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $clixon_cf -y $fyang
|
||||
sudo clixon_backend -zf $cfg -y $fyang
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
||||
new "start backend"
|
||||
# start new backend
|
||||
sudo clixon_backend -s init -f $clixon_cf -y $fyang
|
||||
sudo clixon_backend -s init -f $cfg -y $fyang
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
|
@ -81,43 +82,43 @@ done
|
|||
echo "</x></config></edit-config></rpc>]]>]]>" >> $fconfig
|
||||
|
||||
# Just for manual dbg
|
||||
echo "$clixon_netconf -qf $clixon_cf -y $fyang"
|
||||
echo "$clixon_netconf -qf $cfg -y $fyang"
|
||||
|
||||
new "netconf edit large config"
|
||||
expecteof_file "time -p $clixon_netconf -qf $clixon_cf -y $fyang" "$fconfig" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof_file "time -p $clixon_netconf -qf $cfg -y $fyang" "$fconfig" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
#echo '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' | $clixon_netconf -qf $clixon_cf -y $fyang
|
||||
#echo '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' | $clixon_netconf -qf $cfg -y $fyang
|
||||
|
||||
new "netconf edit large config again"
|
||||
expecteof_file "time -p $clixon_netconf -qf $clixon_cf -y $fyang" "$fconfig" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof_file "time -p $clixon_netconf -qf $cfg -y $fyang" "$fconfig" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
#echo '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' | $clixon_netconf -qf $clixon_cf -y $fyang
|
||||
#echo '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' | $clixon_netconf -qf $cfg -y $fyang
|
||||
|
||||
rm $fconfig
|
||||
|
||||
new "netconf commit large config"
|
||||
expecteof "time -p $clixon_netconf -qf $clixon_cf -y $fyang" "<rpc><commit><source><candidate/></source></commit></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "time -p $clixon_netconf -qf $cfg -y $fyang" "<rpc><commit><source><candidate/></source></commit></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf commit same config again"
|
||||
expecteof "time -p $clixon_netconf -qf $clixon_cf -y $fyang" "<rpc><commit><source><candidate/></source></commit></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
expecteof "time -p $clixon_netconf -qf $cfg -y $fyang" "<rpc><commit><source><candidate/></source></commit></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
exit
|
||||
new "netconf add one small config"
|
||||
expecteof "time -p $clixon_netconf -qf $clixon_cf -y $fyang" "<rpc><edit-config><target><candidate/></target><config><x><y><a>x</a><b>y</b></y></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "time -p $clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><x><y><a>x</a><b>y</b></y></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf add $req small config"
|
||||
time -p for (( i=0; i<$req; i++ )); do
|
||||
rnd=$(( ( RANDOM % $number ) ))
|
||||
echo "<rpc><edit-config><target><candidate/></target><config><x><y><a>$rnd</a><b>$rnd</b></y></x></config></edit-config></rpc>]]>]]>"
|
||||
done | $clixon_netconf -qf $clixon_cf -y $fyang > /dev/null
|
||||
done | $clixon_netconf -qf $cfg -y $fyang > /dev/null
|
||||
|
||||
new "netconf get large config"
|
||||
expecteof "time -p $clixon_netconf -qf $clixon_cf -y $fyang" "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><y><a>0</a><b>0</b></y><y><a>1</a><b>1</b>"
|
||||
expecteof "time -p $clixon_netconf -qf $cfg -y $fyang" "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><y><a>0</a><b>0</b></y><y><a>1</a><b>1</b>"
|
||||
|
||||
new "netconf get $req small config"
|
||||
time -p for (( i=0; i<$req; i++ )); do
|
||||
rnd=$(( ( RANDOM % $number ) ))
|
||||
echo "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/y[a=$rnd][b=$rnd]\" /></get-config></rpc>]]>]]>"
|
||||
done | $clixon_netconf -qf $clixon_cf -y $fyang > /dev/null
|
||||
done | $clixon_netconf -qf $cfg -y $fyang > /dev/null
|
||||
|
||||
new "generate large leaf-list config"
|
||||
echo -n "<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><x>" > $fconfig
|
||||
|
|
@ -127,21 +128,21 @@ done
|
|||
echo "</x></config></edit-config></rpc>]]>]]>" >> $fconfig
|
||||
|
||||
new "netconf replace large list-leaf config"
|
||||
expecteof_file "time -p $clixon_netconf -qf $clixon_cf -y $fyang" "$fconfig" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof_file "time -p $clixon_netconf -qf $cfg -y $fyang" "$fconfig" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
rm $fconfig
|
||||
|
||||
new "netconf commit large leaf-list config"
|
||||
expecteof "time -p $clixon_netconf -qf $clixon_cf -y $fyang" "<rpc><commit><source><candidate/></source></commit></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "time -p $clixon_netconf -qf $cfg -y $fyang" "<rpc><commit><source><candidate/></source></commit></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf add small leaf-list config"
|
||||
expecteof "time -p $clixon_netconf -qf $clixon_cf -y $fyang" "<rpc><edit-config><target><candidate/></target><config><x><c>x</c></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "time -p $clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><x><c>x</c></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf commit small leaf-list config"
|
||||
expecteof "time -p $clixon_netconf -qf $clixon_cf -y $fyang" "<rpc><commit><source><candidate/></source></commit></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "time -p $clixon_netconf -qf $cfg -y $fyang" "<rpc><commit><source><candidate/></source></commit></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf get large leaf-list config"
|
||||
expecteof "time -p $clixon_netconf -qf $clixon_cf -y $fyang" "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><c>0</c><c>1</c>"
|
||||
expecteof "time -p $clixon_netconf -qf $cfg -y $fyang" "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><c>0</c><c>1</c>"
|
||||
|
||||
new "Kill backend"
|
||||
# Check if still alive
|
||||
|
|
@ -150,7 +151,7 @@ if [ -z "$pid" ]; then
|
|||
err "backend already dead"
|
||||
fi
|
||||
# kill backend
|
||||
sudo clixon_backend -zf $clixon_cf
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err "kill backend"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -4,18 +4,19 @@
|
|||
|
||||
# include err() and new() functions
|
||||
. ./lib.sh
|
||||
cfg=/usr/local/etc/routing.xml
|
||||
|
||||
# This is a fixed 'state' implemented in routing_backend. It is always there
|
||||
state='{"interfaces-state": {"interface": {"name": "eth0","type": "eth","if-index": "42"}}}'
|
||||
|
||||
# kill old backend (if any)
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $clixon_cf
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
new "start backend"
|
||||
sudo clixon_backend -s init -f $clixon_cf
|
||||
sudo clixon_backend -s init -f $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
|
@ -109,7 +110,7 @@ if [ -z "$pid" ]; then
|
|||
err "backend already dead"
|
||||
fi
|
||||
# kill backend
|
||||
sudo clixon_backend -zf $clixon_cf
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err "kill backend"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -8,12 +8,36 @@
|
|||
|
||||
# include err() and new() functions
|
||||
. ./lib.sh
|
||||
cfg=/tmp/conf_startup.xml
|
||||
|
||||
# For memcheck
|
||||
# clixon_netconf="valgrind --leak-check=full --show-leak-kinds=all clixon_netconf"
|
||||
clixon_netconf=clixon_netconf
|
||||
clixon_cli=clixon_cli
|
||||
|
||||
cat <<EOF > $cfg
|
||||
<config>
|
||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||
<CLICON_YANG_DIR>/usr/local/share/routing/yang</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
|
||||
<CLICON_CLI_MODE>routing</CLICON_CLI_MODE>
|
||||
<CLICON_BACKEND_DIR>/usr/local/lib/routing/backend</CLICON_BACKEND_DIR>
|
||||
<CLICON_NETCONF_DIR>/usr/local/lib/routing/netconf</CLICON_NETCONF_DIR>
|
||||
<CLICON_RESTCONF_DIR>/usr/local/lib/routing/restconf</CLICON_RESTCONF_DIR>
|
||||
<CLICON_CLI_DIR>/usr/local/lib/routing/cli</CLICON_CLI_DIR>
|
||||
<CLICON_CLISPEC_DIR>/usr/local/lib/routing/clispec</CLICON_CLISPEC_DIR>
|
||||
<CLICON_SOCK>/usr/local/var/routing/routing.sock</CLICON_SOCK>
|
||||
<CLICON_BACKEND_PIDFILE>/usr/local/var/routing/routing.pidfile</CLICON_BACKEND_PIDFILE>
|
||||
<CLICON_CLI_GENMODEL_COMPLETION>1</CLICON_CLI_GENMODEL_COMPLETION>
|
||||
<CLICON_XMLDB_DIR>/usr/local/var/routing</CLICON_XMLDB_DIR>
|
||||
<CLICON_XMLDB_PLUGIN>/usr/local/lib/xmldb/text.so</CLICON_XMLDB_PLUGIN>
|
||||
<CLICON_CLI_LINESCROLLING>0</CLICON_CLI_LINESCROLLING>
|
||||
<CLICON_STARTUP_MODE>init</CLICON_STARTUP_MODE>
|
||||
<CLICON_XML_SORT>true</CLICON_XML_SORT>
|
||||
</config>
|
||||
|
||||
EOF
|
||||
|
||||
run(){
|
||||
mode=$1
|
||||
expect=$2
|
||||
|
|
@ -42,7 +66,7 @@ EOF
|
|||
EOF
|
||||
sudo mv /tmp/db /usr/local/var/routing/startup_db
|
||||
|
||||
cat <<EOF > /tmp/config
|
||||
cat <<EOF > /tmp/config
|
||||
<config>
|
||||
<interfaces>
|
||||
<interface>
|
||||
|
|
@ -55,20 +79,20 @@ EOF
|
|||
|
||||
# kill old backend (if any)
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $clixon_cf
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
||||
new "start backend"
|
||||
# start new backend
|
||||
sudo clixon_backend -f $clixon_cf -s $mode -c /tmp/config
|
||||
sudo clixon_backend -f $cfg -s $mode -c /tmp/config
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
||||
new "Check $mode"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc><get-config><source><running/></source></get-config></rpc>]]>]]>' "^<rpc-reply>$expect</rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" '<rpc><get-config><source><running/></source></get-config></rpc>]]>]]>' "^<rpc-reply>$expect</rpc-reply>]]>]]>$"
|
||||
|
||||
new "Kill backend"
|
||||
# Check if still alive
|
||||
|
|
@ -77,7 +101,7 @@ EOF
|
|||
err "backend already dead"
|
||||
fi
|
||||
# kill backend
|
||||
sudo clixon_backend -zf $clixon_cf
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err "kill backend"
|
||||
fi
|
||||
|
|
@ -85,6 +109,6 @@ EOF
|
|||
|
||||
run init '<data/>'
|
||||
run none '<data><interfaces><interface><name>run</name><type>eth</type><enabled>true</enabled></interface></interfaces></data>'
|
||||
run running '<data><interfaces><interface><name>run</name><type>eth</type><enabled>true</enabled></interface><interface><name>lo</name><type>local</type><enabled>true</enabled></interface><interface><name>extra</name><type>eth</type><enabled>true</enabled></interface></interfaces></data>'
|
||||
run startup '<data><interfaces><interface><name>startup</name><type>eth</type><enabled>true</enabled></interface><interface><name>lo</name><type>local</type><enabled>true</enabled></interface><interface><name>extra</name><type>eth</type><enabled>true</enabled></interface></interfaces></data>'
|
||||
run running '<data><interfaces><interface><name>extra</name><type>eth</type><enabled>true</enabled></interface><interface><name>lo</name><type>local</type><enabled>true</enabled></interface><interface><name>run</name><type>eth</type><enabled>true</enabled></interface></interfaces></data>'
|
||||
run startup '<data><interfaces><interface><name>extra</name><type>eth</type><enabled>true</enabled></interface><interface><name>lo</name><type>local</type><enabled>true</enabled></interface><interface><name>startup</name><type>eth</type><enabled>true</enabled></interface></interfaces></data>'
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,15 @@
|
|||
|
||||
# include err() and new() functions
|
||||
. ./lib.sh
|
||||
cfg=/usr/local/etc/routing.xml
|
||||
fyang=/tmp/type.yang
|
||||
|
||||
# For memcheck
|
||||
#clixon_cli="valgrind --leak-check=full --show-leak-kinds=all clixon_cli"
|
||||
clixon_cli=clixon_cli
|
||||
clixon_netconf=clixon_netconf
|
||||
|
||||
cat <<EOF > /tmp/type.yang
|
||||
cat <<EOF > $fyang
|
||||
module example{
|
||||
typedef ab {
|
||||
type string {
|
||||
|
|
@ -63,55 +65,55 @@ EOF
|
|||
|
||||
# kill old backend (if any)
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $clixon_cf
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
new "start backend"
|
||||
# start new backend
|
||||
sudo clixon_backend -s init -f $clixon_cf -y /tmp/type.yang
|
||||
sudo clixon_backend -s init -f $cfg -y $fyang
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
||||
new "cli set ab"
|
||||
expectfn "$clixon_cli -1f $clixon_cf -l o -y /tmp/type.yang set list a.b.a.b" "^$"
|
||||
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list a.b.a.b" "^$"
|
||||
|
||||
new "cli set cd"
|
||||
expectfn "$clixon_cli -1f $clixon_cf -l o -y /tmp/type.yang set list c.d.c.d" "^$"
|
||||
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list c.d.c.d" "^$"
|
||||
|
||||
new "cli set ef"
|
||||
expectfn "$clixon_cli -1f $clixon_cf -l o -y /tmp/type.yang set list e.f.e.f" "^$"
|
||||
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list e.f.e.f" "^$"
|
||||
|
||||
new "cli set ab fail"
|
||||
expectfn "$clixon_cli -1f $clixon_cf -l o -y /tmp/type.yang set list a&b&a&b" "^CLI syntax error"
|
||||
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list a&b&a&b" "^CLI syntax error"
|
||||
|
||||
new "cli set ad fail"
|
||||
expectfn "$clixon_cli -1f $clixon_cf -l o -y /tmp/type.yang set list a.b.c.d" "^CLI syntax error"
|
||||
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set list a.b.c.d" "^CLI syntax error"
|
||||
|
||||
new "cli validate"
|
||||
expectfn "$clixon_cli -1f $clixon_cf -l o -y /tmp/type.yang -l o validate" "^$"
|
||||
expectfn "$clixon_cli -1f $cfg -l o -y $fyang -l o validate" "^$"
|
||||
|
||||
new "cli commit"
|
||||
expectfn "$clixon_cli -1f $clixon_cf -l o -y /tmp/type.yang -l o commit" "^$"
|
||||
expectfn "$clixon_cli -1f $cfg -l o -y $fyang -l o commit" "^$"
|
||||
|
||||
new "netconf validate ok"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/type.yang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf set ab wrong"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/type.yang" "<rpc><edit-config><target><candidate/></target><config><list><ip>a.b&c.d</ip></list></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><list><ip>a.b&c.d</ip></list></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf validate"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/type.yang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
||||
|
||||
new "netconf discard-changes"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/type.yang" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf commit"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/type.yang" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "cli enum value"
|
||||
expectfn "$clixon_cli -1f $clixon_cf -l o -y /tmp/type.yang set status down" "^$"
|
||||
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set status down" "^$"
|
||||
|
||||
new "Kill backend"
|
||||
# Check if still alive
|
||||
|
|
@ -120,7 +122,7 @@ if [ -z "$pid" ]; then
|
|||
err "backend already dead"
|
||||
fi
|
||||
# kill backend
|
||||
sudo clixon_backend -zf $clixon_cf
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err "kill backend"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -3,16 +3,17 @@
|
|||
|
||||
# include err() and new() functions
|
||||
. ./lib.sh
|
||||
clixon_cf=/tmp/conf_yang.xml
|
||||
cfg=/tmp/conf_yang.xml
|
||||
fyang=/tmp/test.yang
|
||||
|
||||
# For memcheck
|
||||
# clixon_netconf="valgrind --leak-check=full --show-leak-kinds=all clixon_netconf"
|
||||
clixon_netconf=clixon_netconf
|
||||
clixon_cli=clixon_cli
|
||||
|
||||
cat <<EOF > /tmp/conf_yang.xml
|
||||
cat <<EOF > $cfg
|
||||
<config>
|
||||
<CLICON_CONFIGFILE>/tmp/conf_yang.xml</CLICON_CONFIGFILE>
|
||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||
<CLICON_YANG_DIR>/usr/local/share/routing/yang</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
|
||||
<CLICON_CLISPEC_DIR>/usr/local/lib/routing/clispec</CLICON_CLISPEC_DIR>
|
||||
|
|
@ -26,7 +27,7 @@ cat <<EOF > /tmp/conf_yang.xml
|
|||
</config>
|
||||
EOF
|
||||
|
||||
cat <<EOF > /tmp/test.yang
|
||||
cat <<EOF > $fyang
|
||||
module example{
|
||||
container x {
|
||||
list y {
|
||||
|
|
@ -80,74 +81,73 @@ EOF
|
|||
|
||||
# kill old backend (if any)
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $clixon_cf -y /tmp/test.yang
|
||||
sudo clixon_backend -zf $cfg -y $fyang
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
||||
new "start backend"
|
||||
# start new backend
|
||||
sudo clixon_backend -s init -f $clixon_cf -y /tmp/test.yang
|
||||
sudo clixon_backend -s init -f $cfg -y $fyang
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
||||
new "netconf edit config"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><edit-config><target><candidate/></target><config><x><y><a>1</a><b>2</b><c>5</c></y><d/></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><x><y><a>1</a><b>2</b><c>5</c></y><d/></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf commit"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
# text empty type in running
|
||||
new "netconf commit 2nd"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf get config xpath"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/y[a=1][b=2]\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><y><a>1</a><b>2</b><c>5</c></y></x></data></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/y[a=1][b=2]\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><y><a>1</a><b>2</b><c>5</c></y></x></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf edit leaf-list"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><edit-config><target><candidate/></target><config><x><f><e>hej</e><e>hopp</e></f></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><x><f><e>hej</e><e>hopp</e></f></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf get leaf-list"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/f/e\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/f/e\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf get leaf-list path"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/f[e=hej]\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/f[e=hej]\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf get (should be some)"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><get><filter type=\"xpath\" select=\"/\"/></get></rpc>]]>]]>" "^<rpc-reply><data><x><y><a>1</a><b>2</b><c>5</c></y><d/></x></data></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><get><filter type=\"xpath\" select=\"/\"/></get></rpc>]]>]]>" "^<rpc-reply><data><x><y><a>1</a><b>2</b><c>5</c></y><d/></x></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "cli set leaf-list"
|
||||
expectfn "$clixon_cli -1f $clixon_cf -y /tmp/test.yang set x f e foo" ""
|
||||
expectfn "$clixon_cli -1f $cfg -y $fyang set x f e foo" ""
|
||||
|
||||
new "cli show leaf-list"
|
||||
expectfn "$clixon_cli -1f $clixon_cf -y /tmp/test.yang show xpath /x/f/e" "<e>foo</e>"
|
||||
expectfn "$clixon_cli -1f $cfg -y $fyang show xpath /x/f/e" "<e>foo</e>"
|
||||
new "netconf set state data (not allowed)"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><edit-config><target><candidate/></target><config><state><op>42</op></state></config></edit-config></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>invalid-value"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><state><op>42</op></state></config></edit-config></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>invalid-value"
|
||||
|
||||
new "netconf set presence and not present"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><edit-config><target><candidate/></target><config><x><nopresence/><presence/></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><x><nopresence/><presence/></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf get presence only"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/*presence"/></get-config></rpc>]]>]]>' "^<rpc-reply><data><x><presence/></x></data></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/*presence"/></get-config></rpc>]]>]]>' "^<rpc-reply><data><x><presence/></x></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf discard-changes"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf anyxml"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><edit-config><target><candidate/></target><config><x><any><foo><bar a=\"nisse\"/></foo></any></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><x><any><foo><bar a=\"nisse\"/></foo></any></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf validate anyxml"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "Kill backend"
|
||||
# Check if still alive
|
||||
pid=`pgrep clixon_backend`
|
||||
if [ -z "$pid" ]; then
|
||||
err "backend already dead"
|
||||
fi
|
||||
# kill backend
|
||||
sudo clixon_backend -zf $clixon_cf
|
||||
#sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err "kill backend"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ bindir = @bindir@
|
|||
includedir = @includedir@
|
||||
datarootdir = @datarootdir@
|
||||
|
||||
YANGSPECS = clixon-config@2017-12-03.yang
|
||||
YANGSPECS = clixon-config@2017-12-27.yang
|
||||
YANGSPECS += ietf-netconf@2011-06-01.yang
|
||||
YANGSPECS += ietf-inet-types@2013-07-15.yang
|
||||
|
||||
|
|
|
|||
266
yang/clixon-config@2017-12-27.yang
Normal file
266
yang/clixon-config@2017-12-27.yang
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
module clixon-config {
|
||||
|
||||
prefix cc;
|
||||
|
||||
organization
|
||||
"Clicon / Clixon";
|
||||
|
||||
contact
|
||||
"Olof Hagsand <olof@hagsand.se>";
|
||||
|
||||
description
|
||||
"Clixon configuration file
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
Copyright (C) 2009-2017 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 *****";
|
||||
|
||||
revision 2017-12-27 {
|
||||
description
|
||||
"Added xml sort option for 1.4.0";
|
||||
}
|
||||
typedef startup_mode{
|
||||
description
|
||||
"Which method to boot/start clicon backend.
|
||||
The methods differ in how they reach a running state
|
||||
Which source database to commit from, if any.";
|
||||
type enumeration{
|
||||
enum none{
|
||||
description
|
||||
"Do not touch running state
|
||||
Typically after crash when running state and db are synched";
|
||||
}
|
||||
enum init{
|
||||
description
|
||||
"Initialize running state.
|
||||
Start with a completely clean running state";
|
||||
}
|
||||
enum running{
|
||||
description
|
||||
"Commit running db configuration into running state
|
||||
After reboot if a persistent running db exists";
|
||||
}
|
||||
enum startup{
|
||||
description
|
||||
"Commit startup configuration into running state
|
||||
After reboot when no persistent running db exists";
|
||||
}
|
||||
}
|
||||
}
|
||||
container config {
|
||||
leaf CLICON_CONFIGFILE{
|
||||
type string;
|
||||
description
|
||||
"Location of configuration-file for default values (this file)";
|
||||
}
|
||||
leaf CLICON_YANG_DIR {
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"Location of YANG module and submodule files.";
|
||||
}
|
||||
leaf CLICON_YANG_MODULE_MAIN {
|
||||
type string;
|
||||
default "clicon";
|
||||
description
|
||||
"Option used to construct initial yang file:
|
||||
<module>[@<revision>]";
|
||||
}
|
||||
leaf CLICON_YANG_MODULE_REVISION {
|
||||
type string;
|
||||
description
|
||||
"Option used to construct initial yang file:
|
||||
<module>[@<revision>]";
|
||||
}
|
||||
leaf CLICON_BACKEND_DIR {
|
||||
type string;
|
||||
description
|
||||
"Location of backend .so plugins. Load all .so
|
||||
plugins in this dir as backend plugins";
|
||||
}
|
||||
leaf CLICON_NETCONF_DIR {
|
||||
type string;
|
||||
description "Location of netconf (frontend) .so plugins";
|
||||
}
|
||||
leaf CLICON_RESTCONF_DIR {
|
||||
type string;
|
||||
description
|
||||
"Location of restconf (frontend) .so plugins. Load all .so
|
||||
plugins in this dir as restconf code plugins";
|
||||
}
|
||||
leaf CLICON_RESTCONF_PATH {
|
||||
type string;
|
||||
default "/www-data/fastcgi_restconf.sock";
|
||||
description
|
||||
"FastCGI unix socket. Should be specified in webserver
|
||||
Eg in nginx: fastcgi_pass unix:/www-data/clicon_restconf.sock";
|
||||
}
|
||||
leaf CLICON_CLI_DIR {
|
||||
type string;
|
||||
description
|
||||
"Location of cli frontend .so plugins. Load all .so
|
||||
plugins in this dir as CLI object plugins";
|
||||
}
|
||||
leaf CLICON_CLISPEC_DIR {
|
||||
type string;
|
||||
description
|
||||
"Location of frontend .cli cligen spec files. Load all .cli
|
||||
files in this dir as CLI specification files";
|
||||
}
|
||||
leaf CLICON_CLISPEC_FILE {
|
||||
type string;
|
||||
description "Specific frontend .cli cligen spec file.";
|
||||
}
|
||||
leaf CLICON_CLI_MODE {
|
||||
type string;
|
||||
default "base";
|
||||
description
|
||||
"Startup CLI mode. This should match a CLICON_MODE set in
|
||||
one of the clispec files";
|
||||
}
|
||||
leaf CLICON_CLI_GENMODEL {
|
||||
type int32;
|
||||
default 1;
|
||||
description
|
||||
"Generate code for CLI completion of existing db symbols.
|
||||
Example: Add name=\"myspec\" in datamodel spec and reference
|
||||
as @myspec";
|
||||
}
|
||||
leaf CLICON_CLI_GENMODEL_COMPLETION {
|
||||
type int32;
|
||||
default 1;
|
||||
description "Generate code for CLI completion of existing db symbols";
|
||||
}
|
||||
leaf CLICON_CLI_GENMODEL_TYPE {
|
||||
type string;
|
||||
default "VARS";
|
||||
description "How to generate and show CLI syntax: VARS|ALL";
|
||||
}
|
||||
leaf CLICON_CLI_VARONLY {
|
||||
type int32;
|
||||
default 1;
|
||||
description
|
||||
"Dont include keys in cvec in cli vars callbacks,
|
||||
ie a & k in 'a <b> k <c>' ignored";
|
||||
}
|
||||
leaf CLICON_CLI_LINESCROLLING {
|
||||
type int32;
|
||||
default 1;
|
||||
description
|
||||
"Set to 0 if you want CLI to wrap to next line.
|
||||
Set to 1 if you want CLI to scroll sideways when approaching
|
||||
right margin";
|
||||
}
|
||||
leaf CLICON_SOCK_FAMILY {
|
||||
type string;
|
||||
default "UNIX";
|
||||
description
|
||||
"Address family for communicating with clixon_backend
|
||||
(UNIX|IPv4|IPv6)";
|
||||
}
|
||||
leaf CLICON_SOCK {
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"If family above is AF_UNIX: Unix socket for communicating
|
||||
with clixon_backend. If family is AF_INET: IPv4 address";
|
||||
}
|
||||
leaf CLICON_SOCK_PORT {
|
||||
type int32;
|
||||
default 4535;
|
||||
description
|
||||
"Inet socket port for communicating with clixon_backend
|
||||
(only IPv4|IPv6)";
|
||||
}
|
||||
leaf CLICON_SOCK_GROUP {
|
||||
type string;
|
||||
default "clicon";
|
||||
description "Group membership to access clixon_backend unix socket";
|
||||
}
|
||||
leaf CLICON_BACKEND_PIDFILE {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Process-id file of backend daemon";
|
||||
}
|
||||
leaf CLICON_AUTOCOMMIT {
|
||||
type int32;
|
||||
default 0;
|
||||
description
|
||||
"Set if all configuration changes are committed automatically
|
||||
on every edit change. Explicit commit commands unnecessary";
|
||||
}
|
||||
leaf CLICON_MASTER_PLUGIN {
|
||||
type string;
|
||||
default "master";
|
||||
description
|
||||
"Name of master plugin (both frontend and backend).
|
||||
Master plugin has special callbacks for frontends.
|
||||
See clicon user manual for more info. (Obsolete?)";
|
||||
}
|
||||
leaf CLICON_XMLDB_DIR {
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"Directory where \"running\", \"candidate\" and \"startup\" are placed";
|
||||
}
|
||||
leaf CLICON_XMLDB_PLUGIN {
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"XMLDB datastore plugin filename
|
||||
(see datastore/ and clixon_xml_db.[ch])";
|
||||
}
|
||||
leaf CLICON_XMLDB_CACHE {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"XMLDB datastore cache.
|
||||
If set, XML candidate/running parsed tree is stored in memory
|
||||
If not set, candidate/running is always accessed via disk.";
|
||||
}
|
||||
leaf CLICON_XML_SORT {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"If set, sort XML lists and leaf-lists alphabetically and uses binary
|
||||
search. Unless ordered-by user is used.
|
||||
Only works for Yang specified XML.
|
||||
If not set, all lists accessed via linear search.";
|
||||
}
|
||||
leaf CLICON_USE_STARTUP_CONFIG {
|
||||
type int32;
|
||||
default 0;
|
||||
description
|
||||
"Enabled uses \"startup\" configuration on boot. It is called
|
||||
startup_db and exists in XMLDB_DIR.
|
||||
NOTE: Obsolete with 1.3.3 and CLICON_STARTUP_MODE";
|
||||
}
|
||||
leaf CLICON_STARTUP_MODE {
|
||||
type startup_mode;
|
||||
description "Which method to boot/start clicon backend";
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue