Refactoring of dunplication detect
This commit is contained in:
parent
06e1a48480
commit
0c284f0594
3 changed files with 155 additions and 318 deletions
|
|
@ -667,17 +667,17 @@ from_client_edit_config(clixon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
/* Disable duplicate check in NETCONF messages. */
|
/* Disable duplicate check in NETCONF messages. */
|
||||||
if (clicon_option_bool(h, "CLICON_NETCONF_DUPLICATE_ALLOW")){
|
if (clicon_option_bool(h, "CLICON_NETCONF_DUPLICATE_ALLOW")){
|
||||||
if (xml_duplicate_remove_recurse(xc) < 0)
|
if ((ret = xml_duplicate_detect(xc, 1, NULL)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ((ret = xml_yang_validate_unique_recurse(xc, &xret)) < 0)
|
if ((ret = xml_duplicate_detect(xc, 0, &xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){
|
}
|
||||||
if (clixon_xml2cbuf(cbret, xret, 0, 0, NULL, -1, 0) < 0)
|
if (ret == 0){
|
||||||
goto done;
|
if (clixon_xml2cbuf(cbret, xret, 0, 0, NULL, -1, 0) < 0)
|
||||||
goto ok;
|
goto done;
|
||||||
}
|
goto ok;
|
||||||
}
|
}
|
||||||
/* xmldb_put (difflist handling) requires list keys */
|
/* xmldb_put (difflist handling) requires list keys */
|
||||||
if ((ret = xml_yang_validate_list_key_only(xc, &xret)) < 0)
|
if ((ret = xml_yang_validate_list_key_only(xc, &xret)) < 0)
|
||||||
|
|
|
||||||
|
|
@ -44,9 +44,6 @@
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
int xml_yang_validate_minmax(cxobj *xt, int presence, cxobj **xret);
|
int xml_yang_validate_minmax(cxobj *xt, int presence, cxobj **xret);
|
||||||
int xml_yang_validate_minmax_recurse(cxobj *xt, cxobj **xret);
|
int xml_duplicate_detect(cxobj *xt, int rm, cxobj **xret);
|
||||||
int xml_yang_validate_unique(cxobj *xt, cxobj **xret);
|
|
||||||
int xml_yang_validate_unique_recurse(cxobj *xt, cxobj **xret);
|
|
||||||
int xml_duplicate_remove_recurse(cxobj *xt);
|
|
||||||
|
|
||||||
#endif /* _CLIXON_VALIDATE_MINMAX_H_ */
|
#endif /* _CLIXON_VALIDATE_MINMAX_H_ */
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,9 @@
|
||||||
|
|
||||||
*
|
*
|
||||||
* Check YANG validation for min/max-elements and unique
|
* Check YANG validation for min/max-elements and unique
|
||||||
|
* For duplicate detection, there is an (older) mechanism in check_unique_list_direct
|
||||||
|
* and a new more optimized in xml_duplicate_detect
|
||||||
|
* TODO: use the new mechanism for all purposes, but need some restructuring
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "clixon_config.h" /* generated by config & autoconf */
|
#include "clixon_config.h" /* generated by config & autoconf */
|
||||||
|
|
@ -46,7 +49,6 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
@ -214,7 +216,6 @@ check_insert_duplicate(char **vec,
|
||||||
* @param[in] xt The parent of x (a list)
|
* @param[in] xt The parent of x (a list)
|
||||||
* @param[in] y Its yang spec (Y_LIST)
|
* @param[in] y Its yang spec (Y_LIST)
|
||||||
* @param[in] yu A yang unique (Y_UNIQUE) for unique schema node ids or (Y_LIST) for list keys
|
* @param[in] yu A yang unique (Y_UNIQUE) for unique schema node ids or (Y_LIST) for list keys
|
||||||
* @param[in] mark If set, a flag mask to mark (prior) duplicate object with
|
|
||||||
* @param[out] xret Error XML tree. Free with xml_free after use
|
* @param[out] xret Error XML tree. Free with xml_free after use
|
||||||
* @retval 1 Validation OK
|
* @retval 1 Validation OK
|
||||||
* @retval 0 Validation failed (cbret set)
|
* @retval 0 Validation failed (cbret set)
|
||||||
|
|
@ -232,13 +233,13 @@ check_insert_duplicate(char **vec,
|
||||||
* The combined values of all the leafs specified in the key are used to
|
* The combined values of all the leafs specified in the key are used to
|
||||||
* uniquely identify a list entry. All key leafs MUST be given values
|
* uniquely identify a list entry. All key leafs MUST be given values
|
||||||
* when a list entry is created.
|
* when a list entry is created.
|
||||||
|
* @see xml_duplicate_detect1 optimized variant
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
check_unique_list_direct(cxobj *x,
|
check_unique_list_direct(cxobj *x,
|
||||||
cxobj *xt,
|
cxobj *xt,
|
||||||
yang_stmt *y,
|
yang_stmt *y,
|
||||||
yang_stmt *yu,
|
yang_stmt *yu,
|
||||||
int mark,
|
|
||||||
cxobj **xret)
|
cxobj **xret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -303,8 +304,6 @@ check_unique_list_direct(cxobj *x,
|
||||||
if (cvi==NULL){
|
if (cvi==NULL){
|
||||||
/* Last element (i) is newly inserted, see if it is already there */
|
/* Last element (i) is newly inserted, see if it is already there */
|
||||||
if (check_insert_duplicate(vec, i, clen, sorted, &dupl) < 0){
|
if (check_insert_duplicate(vec, i, clen, sorted, &dupl) < 0){
|
||||||
if (mark)
|
|
||||||
xml_flag_set(xvec[dupl], mark);
|
|
||||||
if (xret && netconf_data_not_unique_xml(xret, x, cvk) < 0)
|
if (xret && netconf_data_not_unique_xml(xret, x, cvk) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -333,7 +332,6 @@ check_unique_list_direct(cxobj *x,
|
||||||
* @param[in] xt The parent of x (a list)
|
* @param[in] xt The parent of x (a list)
|
||||||
* @param[in] y Its yang spec (Y_LIST)
|
* @param[in] y Its yang spec (Y_LIST)
|
||||||
* @param[in] yu A yang unique (Y_UNIQUE) for unique schema node ids or (Y_LIST) for list keys
|
* @param[in] yu A yang unique (Y_UNIQUE) for unique schema node ids or (Y_LIST) for list keys
|
||||||
* @param[in] mark If set, a flag mask to mark (prior) duplicate object with
|
|
||||||
* @param[out] xret Error XML tree. Free with xml_free after use
|
* @param[out] xret Error XML tree. Free with xml_free after use
|
||||||
* @retval 1 Validation OK
|
* @retval 1 Validation OK
|
||||||
* @retval 0 Validation failed (xret set)
|
* @retval 0 Validation failed (xret set)
|
||||||
|
|
@ -357,24 +355,23 @@ check_unique_list(cxobj *x,
|
||||||
cxobj *xt,
|
cxobj *xt,
|
||||||
yang_stmt *y,
|
yang_stmt *y,
|
||||||
yang_stmt *yu,
|
yang_stmt *yu,
|
||||||
uint16_t mark,
|
|
||||||
cxobj **xret)
|
cxobj **xret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cg_var *cvi; /* unique node name */
|
cg_var *cvi; /* unique node name */
|
||||||
char **svec = NULL; /* vector of search results */
|
char **svec = NULL; /* vector of search results */
|
||||||
size_t slen = 0;
|
size_t slen = 0;
|
||||||
char *xpath0 = NULL;
|
char *xpath0 = NULL;
|
||||||
char *xpath1 = NULL;
|
char *xpath1 = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
cvec *cvk;
|
cvec *cvk;
|
||||||
cvec *nsc0 = NULL;
|
cvec *nsc0 = NULL;
|
||||||
cvec *nsc1 = NULL;
|
cvec *nsc1 = NULL;
|
||||||
|
|
||||||
/* Check if multiple direct children */
|
/* Check if multiple direct children */
|
||||||
cvk = yang_cvec_get(yu);
|
cvk = yang_cvec_get(yu);
|
||||||
if (cvec_len(cvk) > 1){
|
if (cvec_len(cvk) > 1){
|
||||||
retval = check_unique_list_direct(x, xt, y, yu, mark, xret);
|
retval = check_unique_list_direct(x, xt, y, yu, xret);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cvi = cvec_i(cvk, 0);
|
cvi = cvec_i(cvk, 0);
|
||||||
|
|
@ -384,7 +381,7 @@ check_unique_list(cxobj *x,
|
||||||
}
|
}
|
||||||
/* Check if direct schmeanode-id , ie not xpath */
|
/* Check if direct schmeanode-id , ie not xpath */
|
||||||
if (index(xpath0, '/') == NULL){
|
if (index(xpath0, '/') == NULL){
|
||||||
retval = check_unique_list_direct(x, xt, y, yu, mark, xret);
|
retval = check_unique_list_direct(x, xt, y, yu, xret);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Here proper xpath with at least one slash (can there be a descendant schemanodeid w/o slash?) */
|
/* Here proper xpath with at least one slash (can there be a descendant schemanodeid w/o slash?) */
|
||||||
|
|
@ -520,50 +517,38 @@ check_empty_list_minmax(cxobj *xt,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Check duplicates/unique in list
|
/*! Check YANG unique constraint
|
||||||
*
|
*
|
||||||
* @param[in] x XML LIST node
|
* Here is a list w unique constraints identified by:
|
||||||
|
* its first element x, its yang spec y, its parent xt, and
|
||||||
|
* a unique yang spec yu,
|
||||||
|
* Two cases:
|
||||||
|
* 1) multiple direct children (no prefixes), eg "a b"
|
||||||
|
* 2) single xpath with canonical prefixes, eg "/ex:a/ex:b"
|
||||||
|
* @param[in] x XML LIST node
|
||||||
* @param[in] xt XML parent
|
* @param[in] xt XML parent
|
||||||
* @param[in] y YANG of x
|
* @param[in] y YANG of x
|
||||||
* @param[in] mark If set, a flag mask to mark (prior) duplicate object with
|
|
||||||
* @param[out] xret Error as XML if ret = 0
|
* @param[out] xret Error as XML if ret = 0
|
||||||
* @retval 1 Validation OK
|
* @retval 1 Validation OK
|
||||||
* @retval 0 Validation failed (xret set)
|
* @retval 0 Validation failed (xret set)
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
xml_yang_minmax_new_list(cxobj *x,
|
xml_unique_detect(cxobj *x,
|
||||||
cxobj *xt,
|
cxobj *xt,
|
||||||
yang_stmt *y,
|
yang_stmt *y,
|
||||||
int mark,
|
cxobj **xret)
|
||||||
cxobj **xret)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_stmt *yu;
|
|
||||||
int inext;
|
int inext;
|
||||||
|
yang_stmt *yu;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Here new (first element) of lists only
|
|
||||||
* First check unique keys direct children
|
|
||||||
*/
|
|
||||||
if ((ret = check_unique_list_direct(x, xt, y, y, mark, xret)) < 0)
|
|
||||||
goto done;
|
|
||||||
if (ret == 0)
|
|
||||||
goto fail;
|
|
||||||
/* Check if there is a unique constraint on the list
|
|
||||||
*/
|
|
||||||
inext = 0;
|
inext = 0;
|
||||||
while ((yu = yn_iter(y, &inext)) != NULL) {
|
while ((yu = yn_iter(y, &inext)) != NULL) {
|
||||||
if (yang_keyword_get(yu) != Y_UNIQUE)
|
if (yang_keyword_get(yu) != Y_UNIQUE)
|
||||||
continue;
|
continue;
|
||||||
/* Here is a list w unique constraints identified by:
|
if ((ret = check_unique_list(x, xt, y, yu, xret)) < 0)
|
||||||
* its first element x, its yang spec y, its parent xt, and
|
|
||||||
* a unique yang spec yu,
|
|
||||||
* Two cases:
|
|
||||||
* 1) multiple direct children (no prefixes), eg "a b"
|
|
||||||
* 2) single xpath with canonical prefixes, eg "/ex:a/ex:b"
|
|
||||||
*/
|
|
||||||
if ((ret = check_unique_list(x, xt, y, yu, 0, xret)) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -576,67 +561,6 @@ xml_yang_minmax_new_list(cxobj *x,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Check duplicates in leaf-list
|
|
||||||
*
|
|
||||||
* @param[in] x0 XML LIST node
|
|
||||||
* @param[in] xt XML parent
|
|
||||||
* @param[in] y0 YANG of x0
|
|
||||||
* @param[in] mark If set, a flag mask to mark (prior) duplicate object with
|
|
||||||
* @param[out] xret Error as XML if ret = 0
|
|
||||||
* @retval 1 Validation OK
|
|
||||||
* @retval 0 Validation failed (xret set)
|
|
||||||
* @retval -1 Error
|
|
||||||
* @note works for both ordered-by user and system. But worst case quadratic
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
xml_yang_minmax_new_leaf_list(cxobj *x0,
|
|
||||||
cxobj *xt,
|
|
||||||
yang_stmt *y0,
|
|
||||||
int mark,
|
|
||||||
cxobj **xret)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
cxobj *xi;
|
|
||||||
cxobj *xj;
|
|
||||||
char *bi;
|
|
||||||
char *bj;
|
|
||||||
cvec *cvv = NULL;
|
|
||||||
|
|
||||||
xi = x0;
|
|
||||||
do {
|
|
||||||
if ((bi = xml_body(xi)) == NULL)
|
|
||||||
continue;
|
|
||||||
xj = xi;
|
|
||||||
while ((xj = xml_child_each(xt, xj, CX_ELMNT)) != NULL &&
|
|
||||||
xml_spec(xj) == y0) {
|
|
||||||
if ((bj = xml_body(xj)) == NULL)
|
|
||||||
continue;
|
|
||||||
if (bi && bj && strcmp(bi, bj) == 0){
|
|
||||||
if (mark)
|
|
||||||
xml_flag_set(xi, mark);
|
|
||||||
if ((cvv = cvec_new(0)) == NULL){
|
|
||||||
clixon_err(OE_UNIX, errno, "cvec_new");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
cvec_add_string(cvv, "name", bi);
|
|
||||||
if (xret && netconf_data_not_unique_xml(xret, xi, cvv) < 0)
|
|
||||||
goto done;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ((xi = xml_child_each(xt, xi, CX_ELMNT)) != NULL &&
|
|
||||||
xml_spec(xi) == y0);
|
|
||||||
retval = 1;
|
|
||||||
done:
|
|
||||||
if (cvv)
|
|
||||||
cvec_free(cvv);
|
|
||||||
return retval;
|
|
||||||
fail:
|
|
||||||
retval = 0;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Perform gap analysis in a child-vector interval [ye,y]
|
/*! Perform gap analysis in a child-vector interval [ye,y]
|
||||||
*
|
*
|
||||||
* Gap analysis here meaning if there is a list x with min-element constraint but there are no
|
* Gap analysis here meaning if there is a list x with min-element constraint but there are no
|
||||||
|
|
@ -805,15 +729,15 @@ xml_yang_validate_minmax(cxobj *xt,
|
||||||
/* new list check */
|
/* new list check */
|
||||||
if (ret){
|
if (ret){
|
||||||
if (keyw == Y_LIST){
|
if (keyw == Y_LIST){
|
||||||
if ((ret = xml_yang_minmax_new_list(x, xt, y, 0, xret)) < 0)
|
if ((ret = check_unique_list_direct(x, xt, y, y, xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
if (ret == 0)
|
||||||
#ifdef NOTYET /* XXX This is enforced in xml_yang_validate_unique instead */
|
goto fail;
|
||||||
else if (keyw == Y_LEAF_LIST){
|
if ((ret = xml_unique_detect(x, xt, y, xret)) < 0)
|
||||||
if ((ret = xml_yang_minmax_new_leaf_list(x, xt, y, xret)) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -888,168 +812,6 @@ xml_yang_validate_minmax(cxobj *xt,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Recursive minmax check
|
|
||||||
*
|
|
||||||
* Callback function type for xml_apply
|
|
||||||
* @param[in] x XML node
|
|
||||||
* @param[in] arg General-purpose argument
|
|
||||||
* @retval 2 Locally abort this subtree, continue with others
|
|
||||||
* @retval 1 Abort, dont continue with others, return 1 to end user
|
|
||||||
* @retval 0 OK, continue
|
|
||||||
* @retval -1 Error, aborted at first error encounter, return -1 to end user
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
xml_yang_minmax_apply(cxobj *x,
|
|
||||||
void *arg)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
cxobj **xret = (cxobj **)arg;
|
|
||||||
|
|
||||||
if ((ret = xml_yang_validate_minmax(x, 1, xret)) < 0)
|
|
||||||
return -1;
|
|
||||||
if (ret == 0){ /* Validation failed (xret set) */
|
|
||||||
return 1; /* Abort dont continue */
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Recursive YANG Minmax check
|
|
||||||
*
|
|
||||||
* @param[in] xt XML parent (may have lists w unique constraints as child)
|
|
||||||
* @param[out] xret Error XML tree. Free with xml_free after use
|
|
||||||
* @retval 1 Validation OK
|
|
||||||
* @retval 0 Validation failed (xret set)
|
|
||||||
* @retval -1 Error
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
xml_yang_validate_minmax_recurse(cxobj *xt,
|
|
||||||
cxobj **xret)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if ((ret = xml_apply0(xt, CX_ELMNT, xml_yang_minmax_apply, xret)) < 0)
|
|
||||||
goto done;
|
|
||||||
if (ret == 1)
|
|
||||||
goto fail;
|
|
||||||
retval = 1;
|
|
||||||
done:
|
|
||||||
return retval;
|
|
||||||
fail:
|
|
||||||
retval = 0;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! YANG unique check, no recursion
|
|
||||||
*
|
|
||||||
* Assume xt:s children are sorted and yang populated.
|
|
||||||
* @param[in] xt XML parent (may have lists w unique constraints as child)
|
|
||||||
* @param[out] xret Error XML tree. Free with xml_free after use
|
|
||||||
* @retval 1 Validation OK
|
|
||||||
* @retval 0 Validation failed (xret set)
|
|
||||||
* @retval -1 Error
|
|
||||||
* @see xml_yang_validate_minmax which include these unique tests
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
xml_yang_validate_unique(cxobj *xt,
|
|
||||||
cxobj **xret)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
cxobj *x = NULL;
|
|
||||||
yang_stmt *y;
|
|
||||||
yang_stmt *yprev = NULL;
|
|
||||||
enum rfc_6020 keyw;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL){
|
|
||||||
if ((y = xml_spec(x)) == NULL)
|
|
||||||
continue;
|
|
||||||
keyw = yang_keyword_get(y);
|
|
||||||
if (keyw == Y_LIST || keyw == Y_LEAF_LIST){
|
|
||||||
/* equal: just continue*/
|
|
||||||
if (y == yprev){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* new list check */
|
|
||||||
switch (keyw){
|
|
||||||
case Y_LIST:
|
|
||||||
if ((ret = xml_yang_minmax_new_list(x, xt, y, 0, xret)) < 0)
|
|
||||||
goto done;
|
|
||||||
if (ret == 0)
|
|
||||||
goto fail;
|
|
||||||
break;
|
|
||||||
case Y_LEAF_LIST:
|
|
||||||
if ((ret = xml_yang_minmax_new_leaf_list(x, xt, y, 0, xret)) < 0)
|
|
||||||
goto done;
|
|
||||||
if (ret == 0)
|
|
||||||
goto fail;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
yprev = y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
retval = 1;
|
|
||||||
done:
|
|
||||||
return retval;
|
|
||||||
fail:
|
|
||||||
retval = 0;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Recursive unique check
|
|
||||||
*
|
|
||||||
* Callback function type for xml_apply
|
|
||||||
* @param[in] x XML node
|
|
||||||
* @param[in] arg General-purpose argument
|
|
||||||
* @retval 2 Locally abort this subtree, continue with others
|
|
||||||
* @retval 1 Abort, dont continue with others, return 1 to end user
|
|
||||||
* @retval 0 OK, continue
|
|
||||||
* @retval -1 Error, aborted at first error encounter, return -1 to end user
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
xml_yang_unique_apply(cxobj *x,
|
|
||||||
void *arg)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
cxobj **xret = (cxobj **)arg;
|
|
||||||
|
|
||||||
if ((ret = xml_yang_validate_unique(x, xret)) < 0)
|
|
||||||
return -1;
|
|
||||||
if (ret == 0){ /* Validation failed (xret set) */
|
|
||||||
return 1; /* Abort dont continue */
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Recursive YANG unique check
|
|
||||||
*
|
|
||||||
* @param[in] xt XML parent (may have lists w unique constraints as child)
|
|
||||||
* @param[out] xret Error XML tree. Free with xml_free after use
|
|
||||||
* @retval 1 Validation OK
|
|
||||||
* @retval 0 Validation failed (xret set)
|
|
||||||
* @retval -1 Error
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
xml_yang_validate_unique_recurse(cxobj *xt,
|
|
||||||
cxobj **xret)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if ((ret = xml_apply0(xt, CX_ELMNT, xml_yang_unique_apply, xret)) < 0)
|
|
||||||
goto done;
|
|
||||||
if (ret == 1)
|
|
||||||
goto fail;
|
|
||||||
retval = 1;
|
|
||||||
done:
|
|
||||||
return retval;
|
|
||||||
fail:
|
|
||||||
retval = 0;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*----------- New linear vector code -----------------*/
|
/*----------- New linear vector code -----------------*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
@ -1081,8 +843,6 @@ cmp_list_qsort(const void *arg1,
|
||||||
|
|
||||||
eq = 0;
|
eq = 0;
|
||||||
for (i=0; i<v1->vo_slen; i++){
|
for (i=0; i<v1->vo_slen; i++){
|
||||||
assert(v1->vo_strvec[i]);
|
|
||||||
assert(v2->vo_strvec[i]);
|
|
||||||
if ((eq = strcmp(v1->vo_strvec[i], v2->vo_strvec[i])) != 0)
|
if ((eq = strcmp(v1->vo_strvec[i], v2->vo_strvec[i])) != 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1099,11 +859,23 @@ cmp_list_qsort(const void *arg1,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Remove duplicates list
|
/*! Remove duplicates list
|
||||||
|
*
|
||||||
|
* @param[in] vec Ordered vector of string vectors
|
||||||
|
* @param[in] vlen Length of vec
|
||||||
|
* @param[in] rm 0: return 0 on first duplicate, 1: remove all duplicates
|
||||||
|
* @param[in] cvv Vector of keys (for error)
|
||||||
|
* @param[out] xret Error XML tree. Free with xml_free after use
|
||||||
|
* @retval 1 OK, no duplicates
|
||||||
|
* @retval 0 Validation failed (xret set) (only if rm=0)
|
||||||
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
remove_duplicates_list(struct vec_order *vec,
|
remove_duplicates_list(yang_stmt *y,
|
||||||
size_t vlen,
|
struct vec_order *vec,
|
||||||
int *nr)
|
size_t vlen,
|
||||||
|
int rm,
|
||||||
|
int *nr,
|
||||||
|
cxobj **xret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int v;
|
int v;
|
||||||
|
|
@ -1117,48 +889,95 @@ remove_duplicates_list(struct vec_order *vec,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (i==vec[v-1].vo_slen){
|
if (i==vec[v-1].vo_slen){
|
||||||
if (xml_purge(vec[v-1].vo_xml) < 0)
|
if (rm){
|
||||||
goto done;
|
if (xml_purge(vec[v-1].vo_xml) < 0)
|
||||||
if (nr)
|
goto done;
|
||||||
(*nr)++;
|
if (nr)
|
||||||
|
(*nr)++;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
cvec *cvk = NULL;
|
||||||
|
if (yang_keyword_get(y) == Y_LEAF_LIST){
|
||||||
|
if ((cvk = cvec_new(0)) == NULL){
|
||||||
|
clixon_err(OE_UNIX, errno, "cvec_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cvec_add_string(cvk, "name", vec[v].vo_strvec[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cvk = yang_cvec_get(y);
|
||||||
|
if (xret && netconf_data_not_unique_xml(xret, vec[0].vo_xml, cvk) < 0)
|
||||||
|
goto done;
|
||||||
|
if (yang_keyword_get(y) == Y_LEAF_LIST && cvk != NULL)
|
||||||
|
cvec_free(cvk);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
fail:
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Analyze sorted list: detect and potentially remove duplicates
|
||||||
|
*
|
||||||
|
* @param[in] y YANG node of list segment
|
||||||
|
* @param[in] vec Ordered vector of string vectors
|
||||||
|
* @param[in] vlen Length of vec
|
||||||
|
* @param[in] x Most recent XML element, for adjustment
|
||||||
|
* @param[in] rm 0: return 0 on first duplicate, 1: remove all duplicates
|
||||||
|
* @param[out] xret Error XML tree. Free with xml_free after use
|
||||||
|
* @retval 1 OK, no duplicates
|
||||||
|
* @retval 0 Validation failed (xret set) (only if rm=0)
|
||||||
|
* @retval -1 Error
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
vec_order_analyze(yang_stmt *y,
|
vec_order_analyze(yang_stmt *y,
|
||||||
struct vec_order *vec,
|
struct vec_order *vec,
|
||||||
size_t vlen,
|
size_t vlen,
|
||||||
cxobj *x)
|
cxobj *x,
|
||||||
|
int rm,
|
||||||
|
cxobj **xret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int nr = 0;
|
int nr = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (yang_find(y, Y_ORDERED_BY, "user") != NULL)
|
if (yang_find(y, Y_ORDERED_BY, "user") != NULL)
|
||||||
qsort(vec, vlen, sizeof(*vec), cmp_list_qsort);
|
qsort(vec, vlen, sizeof(*vec), cmp_list_qsort);
|
||||||
if (remove_duplicates_list(vec, vlen, &nr) < 0)
|
if ((ret = remove_duplicates_list(y, vec, vlen, rm, &nr, xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (ret == 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
if (x && nr)
|
if (x && nr)
|
||||||
xml_vector_decrement(x, nr);
|
xml_vector_decrement(x, nr);
|
||||||
retval = 0;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
fail:
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! YANG unique check and remove duplicates, keep last
|
/*! YANG unique check and remove duplicates single node, keep last
|
||||||
*
|
*
|
||||||
* Assume xt:s children are sorted and yang populated.
|
* Assume xt:s children are sorted and yang populated.
|
||||||
* @param[in] xt XML parent (may have lists w unique constraints as child)
|
* @param[in] xt XML parent (may have lists w unique constraints as child)
|
||||||
|
* @param[in] rm 0: return 0 on first duplicate, 1: remove all duplicates
|
||||||
* @param[out] xret Error XML tree. Free with xml_free after use
|
* @param[out] xret Error XML tree. Free with xml_free after use
|
||||||
* @retval 0 OK
|
* @retval 1 OK, no duplicates
|
||||||
|
* @retval 0 Validation failed (xret set) (only if rm=0)
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @see xml_yang_validate_minmax which include these unique tests
|
* @see xml_yang_validate_minmax which include these unique tests
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
xml_duplicate_remove(cxobj *xt)
|
xml_duplicate_detect1(cxobj *xt,
|
||||||
|
int rm,
|
||||||
|
cxobj **xret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
|
|
@ -1175,6 +994,7 @@ xml_duplicate_remove(cxobj *xt)
|
||||||
char *str;
|
char *str;
|
||||||
cxobj *xi;
|
cxobj *xi;
|
||||||
int v;
|
int v;
|
||||||
|
int ret;
|
||||||
|
|
||||||
xml_enumerate_children(xt); // Could be done in-line
|
xml_enumerate_children(xt); // Could be done in-line
|
||||||
y0 = NULL;
|
y0 = NULL;
|
||||||
|
|
@ -1184,8 +1004,10 @@ xml_duplicate_remove(cxobj *xt)
|
||||||
if ((y = xml_spec(x)) == NULL)
|
if ((y = xml_spec(x)) == NULL)
|
||||||
continue;
|
continue;
|
||||||
if (y != y0 && vec != NULL){ /* New */
|
if (y != y0 && vec != NULL){ /* New */
|
||||||
if (vec_order_analyze(y0, vec, vlen, x) < 0)
|
if ((ret = vec_order_analyze(y0, vec, vlen, x, rm, xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
goto fail;
|
||||||
if (vec_free(vec, vlen) < 0)
|
if (vec_free(vec, vlen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
vec = NULL;
|
vec = NULL;
|
||||||
|
|
@ -1203,7 +1025,6 @@ xml_duplicate_remove(cxobj *xt)
|
||||||
clixon_err(OE_YANG, 0, "List key vector mismatch %lu != %lu", slen0, clen);
|
clixon_err(OE_YANG, 0, "List key vector mismatch %lu != %lu", slen0, clen);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* see check_unique_list_direct */
|
|
||||||
if ((vec = realloc(vec, (vlen+1)*sizeof(*vec))) == NULL){
|
if ((vec = realloc(vec, (vlen+1)*sizeof(*vec))) == NULL){
|
||||||
clixon_err(OE_UNIX, errno, "cvec_new");
|
clixon_err(OE_UNIX, errno, "cvec_new");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1235,6 +1056,11 @@ xml_duplicate_remove(cxobj *xt)
|
||||||
slen0 = clen;
|
slen0 = clen;
|
||||||
vlen++;
|
vlen++;
|
||||||
}
|
}
|
||||||
|
/* Special case of YANG unique statement */
|
||||||
|
if ((ret = xml_unique_detect(x, xt, y, xret)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
goto fail;
|
||||||
break;
|
break;
|
||||||
case Y_LEAF_LIST:
|
case Y_LEAF_LIST:
|
||||||
if (vec>0 && slen0 != 1){ /* Sanity check */
|
if (vec>0 && slen0 != 1){ /* Sanity check */
|
||||||
|
|
@ -1262,41 +1088,55 @@ xml_duplicate_remove(cxobj *xt)
|
||||||
y0 = y;
|
y0 = y;
|
||||||
}
|
}
|
||||||
if (y0 && vec != NULL){
|
if (y0 && vec != NULL){
|
||||||
if (vec_order_analyze(y0, vec, vlen, NULL) < 0)
|
if ((ret = vec_order_analyze(y0, vec, vlen, NULL, rm, xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (vec_free(vec, vlen) < 0)
|
if (ret == 0)
|
||||||
goto done;
|
goto fail;
|
||||||
vec = NULL;
|
|
||||||
vlen = 0;
|
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
if (vec)
|
if (vec)
|
||||||
free(vec);
|
vec_free(vec, vlen);
|
||||||
return retval;
|
return retval;
|
||||||
|
fail:
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Recursive YANG unique check and remove duplicates, keep last
|
/*! Recursive YANG unique check and potential remove duplicates, keep last
|
||||||
*
|
*
|
||||||
* @param[in] xt XML parent (may have lists w unique constraints as child)
|
* @param[in] xt XML parent (may have lists w unique constraints as child)
|
||||||
* @retval 0 Validation OK
|
* @param[in] rm 0: return 0 on first duplicate, 1: remove all duplicates
|
||||||
|
* @param[out] xret Error XML tree. Free with xml_free after use
|
||||||
|
* @retval 1 OK, no duplicates
|
||||||
|
* @retval 0 Validation failed (xret set) (only if rm=0)
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @see xml_yang_validate_unique_recurse This function destructively removes
|
* @see xml_yang_validate_unique_recurse This function destructively removes
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml_duplicate_remove_recurse(cxobj *xt)
|
xml_duplicate_detect(cxobj *xt,
|
||||||
|
int rm,
|
||||||
|
cxobj **xret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (xml_duplicate_remove(xt) < 0)
|
if ((ret = xml_duplicate_detect1(xt, rm, xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
goto fail;
|
||||||
x = NULL;
|
x = NULL;
|
||||||
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
|
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
|
||||||
if (xml_duplicate_remove_recurse(x) < 0)
|
if ((ret = xml_duplicate_detect(x, rm, xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
fail:
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue