Added support for XPATH functions:
* `contains`,
* `derived-from` and `derived-from-or-self`
* in particular in augment/when statements as shown in eg RFC 7950.
This commit is contained in:
parent
6d7b76550f
commit
c616aa1569
18 changed files with 800 additions and 48 deletions
|
|
@ -77,7 +77,7 @@ SRC = clixon_sig.c clixon_uid.c clixon_log.c clixon_err.c clixon_event.c \
|
|||
clixon_path.c clixon_validate.c \
|
||||
clixon_hash.c clixon_options.c clixon_data.c clixon_plugin.c \
|
||||
clixon_proto.c clixon_proto_client.c \
|
||||
clixon_xpath.c clixon_xpath_ctx.c clixon_xpath_eval.c clixon_xpath_optimize.c \
|
||||
clixon_xpath.c clixon_xpath_ctx.c clixon_xpath_eval.c clixon_xpath_function.c clixon_xpath_optimize.c \
|
||||
clixon_sha1.c clixon_datastore.c clixon_datastore_write.c clixon_datastore_read.c \
|
||||
clixon_netconf_lib.c clixon_stream.c clixon_nacm.c
|
||||
|
||||
|
|
|
|||
|
|
@ -1174,11 +1174,45 @@ xml_yang_validate_all(clicon_handle h,
|
|||
/* "when" sub-node RFC 7950 Sec 7.21.5. Can only be one. */
|
||||
if ((yc = yang_find(ys, Y_WHEN, NULL)) != NULL){
|
||||
xpath = yang_argument_get(yc); /* "when" has xpath argument */
|
||||
if ((nr = xpath_vec_bool(xt, NULL, "%s", xpath)) < 0)
|
||||
/* WHEN xpath needs namespace context */
|
||||
if (xml_nsctx_yang(ys, &nsc) < 0)
|
||||
goto done;
|
||||
if (!nr){
|
||||
if ((nr = xpath_vec_bool(xt, nsc,
|
||||
"%s", xpath)) < 0)
|
||||
goto done;
|
||||
if (nsc){
|
||||
xml_nsctx_free(nsc);
|
||||
nsc = NULL;
|
||||
}
|
||||
if (nr == 0){
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "Failed WHEN condition of %s in module %s",
|
||||
xml_name(xt),
|
||||
yang_argument_get(ys_module(ys)));
|
||||
if (netconf_operation_failed_xml(xret, "application",
|
||||
"when xpath validation failed") < 0)
|
||||
cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
/* Augmented when using special struct. */
|
||||
if ((xpath = yang_when_xpath_get(ys)) != NULL){
|
||||
if ((nr = xpath_vec_bool(xml_parent(xt), yang_when_nsc_get(ys),
|
||||
"%s", xpath)) < 0)
|
||||
goto done;
|
||||
if (nr == 0){
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "Failed augmented WHEN condition of %s in module %s",
|
||||
xml_name(xt),
|
||||
yang_argument_get(ys_module(ys)));
|
||||
if (netconf_operation_failed_xml(xret, "application",
|
||||
cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2180,3 +2180,4 @@ xml_copy_marked(cxobj *x0,
|
|||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@
|
|||
#include "clixon_xpath_ctx.h"
|
||||
#include "clixon_xpath.h"
|
||||
#include "clixon_xpath_optimize.h"
|
||||
#include "clixon_xpath_function.h"
|
||||
#include "clixon_xpath_eval.h"
|
||||
|
||||
/* Mapping between XPATH operator string <--> int */
|
||||
|
|
@ -178,8 +179,8 @@ nodetest_eval_node(cxobj *x,
|
|||
*/
|
||||
static int
|
||||
nodetest_eval_node_localonly(cxobj *x,
|
||||
xpath_tree *xs,
|
||||
cvec *nsc)
|
||||
xpath_tree *xs,
|
||||
cvec *nsc)
|
||||
{
|
||||
int retval = -1;
|
||||
char *name1 = xml_name(x);
|
||||
|
|
@ -237,11 +238,11 @@ nodetest_eval(cxobj *x,
|
|||
|
||||
/*!
|
||||
* @param[in] xn
|
||||
* @param[in] nodetest XPATH stack
|
||||
* @param[in] nodetest XPATH stack
|
||||
* @param[in] node_type
|
||||
* @param[in] flags
|
||||
* @param[in] nsc XML Namespace context
|
||||
* @param[in] localonly Skip prefix and namespace tests (non-standard)
|
||||
* @param[in] localonly Skip prefix and namespace tests (non-standard)
|
||||
* @param[out] vec0
|
||||
* @param[out] vec0len
|
||||
*/
|
||||
|
|
@ -333,7 +334,7 @@ xp_eval_step(xp_ctx *xc0,
|
|||
else{
|
||||
if (nodetest->xs_type==XP_NODE_FN &&
|
||||
nodetest->xs_s0 &&
|
||||
strcmp(nodetest->xs_s0,"current")==0){
|
||||
strcmp(nodetest->xs_s0, "current")==0){
|
||||
if (cxvec_append(xc->xc_initial, &vec, &veclen) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -522,7 +523,6 @@ xp_eval_predicate(xp_ctx *xc,
|
|||
if (xrc)
|
||||
ctx_free(xrc);
|
||||
}
|
||||
|
||||
}
|
||||
assert(xr0||xr1);
|
||||
if (xr1){
|
||||
|
|
@ -972,6 +972,25 @@ xp_eval(xp_ctx *xc,
|
|||
goto done;
|
||||
goto ok;
|
||||
break;
|
||||
case XP_PRIME_FN:
|
||||
if (xs->xs_s0){
|
||||
if (strcmp(xs->xs_s0, "contains") == 0){
|
||||
if (xp_function_contains(xc, xs->xs_c0, nsc, localonly, xrp) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
else if (strcmp(xs->xs_s0, "derived-from") == 0){
|
||||
if (xp_function_derived_from(xc, xs->xs_c0, nsc, localonly, 0, xrp) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
else if (strcmp(xs->xs_s0, "derived-from-or-self") == 0){
|
||||
if (xp_function_derived_from(xc, xs->xs_c0, nsc, localonly, 1, xrp) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1047,12 +1066,10 @@ xp_eval(xp_ctx *xc,
|
|||
xr0->xc_type = XT_STRING;
|
||||
xr0->xc_string = xs->xs_s0?strdup(xs->xs_s0):NULL;
|
||||
break;
|
||||
case XP_PRIME_FN:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Eval second child c0
|
||||
/* Eval second child c1
|
||||
* Note, some operators like locationpath, need transitive context (use_xr0)
|
||||
*/
|
||||
if (xs->xs_c1)
|
||||
|
|
|
|||
295
lib/src/clixon_xpath_function.c
Normal file
295
lib/src/clixon_xpath_function.c
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2019 Olof Hagsand
|
||||
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)
|
||||
|
||||
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 *****
|
||||
|
||||
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
|
||||
* and rfc 7950
|
||||
*
|
||||
*/
|
||||
#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 <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h> /* NaN */
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
/* clicon */
|
||||
#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_options.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_yang_type.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_xml_map.h"
|
||||
#include "clixon_yang_module.h"
|
||||
#include "clixon_validate.h"
|
||||
#include "clixon_xpath_ctx.h"
|
||||
#include "clixon_xpath.h"
|
||||
#include "clixon_xpath_eval.h"
|
||||
#include "clixon_xpath_function.h"
|
||||
|
||||
/*! Eval xpath function contains
|
||||
* @param[in] xc Incoming context
|
||||
* @param[in] xs XPATH node tree
|
||||
* @param[in] nsc XML Namespace context
|
||||
* @param[in] localonly Skip prefix and namespace tests (non-standard)
|
||||
* @param[out] xrp Resulting context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see https://www.w3.org/TR/xpath-10/#NT-FunctionName 4.2 String Functions
|
||||
*/
|
||||
int
|
||||
xp_function_contains(xp_ctx *xc,
|
||||
struct xpath_tree *xs,
|
||||
cvec *nsc,
|
||||
int localonly,
|
||||
xp_ctx **xrp)
|
||||
{
|
||||
int retval = -1;
|
||||
xp_ctx *xr0 = NULL;
|
||||
xp_ctx *xr1 = NULL;
|
||||
xp_ctx *xr = NULL;
|
||||
char *s0 = NULL;
|
||||
char *s1 = NULL;
|
||||
|
||||
/* contains two arguments in xs: boolean contains(string, string) */
|
||||
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
|
||||
goto done;
|
||||
if (ctx2string(xr0, &s0) < 0)
|
||||
goto done;
|
||||
if (xp_eval(xc, xs->xs_c1, nsc, localonly, &xr1) < 0)
|
||||
goto done;
|
||||
if (ctx2string(xr1, &s1) < 0)
|
||||
goto done;
|
||||
if ((xr = malloc(sizeof(*xr))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(xr, 0, sizeof(*xr));
|
||||
xr->xc_type = XT_BOOL;
|
||||
xr->xc_bool = (strstr(s0, s1) != NULL);
|
||||
*xrp = xr;
|
||||
xr = NULL;
|
||||
retval = 0;
|
||||
done:
|
||||
if (xr0)
|
||||
ctx_free(xr0);
|
||||
if (xr1)
|
||||
ctx_free(xr1);
|
||||
if (s0)
|
||||
free(s0);
|
||||
if (s1)
|
||||
free(s1);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Helper function for derived-from(-and-self) - eval one node
|
||||
* @param[in] nsc XML Namespace context
|
||||
* @param[in] self If set, implements derived_from_or_self
|
||||
* @retval 1 OK and match
|
||||
* @retval 0 OK but not match
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
derived_from_one(char *baseidentity,
|
||||
cvec *nsc,
|
||||
cxobj *xleaf,
|
||||
int self)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yleaf;
|
||||
yang_stmt *ytype;
|
||||
yang_stmt *ybaseid;
|
||||
yang_stmt *ymod;
|
||||
cvec *idrefvec; /* Derived identityref list: (module:id)**/
|
||||
char *node = NULL;
|
||||
char *prefix = NULL;
|
||||
char *id = NULL;
|
||||
cbuf *cb = NULL;
|
||||
char *baseid = NULL;
|
||||
|
||||
/* Split baseidentity to get its id (w/o prefix) */
|
||||
if (nodeid_split(baseidentity, NULL, &baseid) < 0)
|
||||
goto done;
|
||||
if ((yleaf = xml_spec(xleaf)) == NULL)
|
||||
goto nomatch;
|
||||
if (yang_keyword_get(yleaf) != Y_LEAF && yang_keyword_get(yleaf) != Y_LEAF_LIST)
|
||||
goto nomatch;
|
||||
/* Node is of type identityref */
|
||||
if (yang_type_get(yleaf, NULL, &ytype, NULL, NULL, NULL, NULL, NULL) < 0)
|
||||
goto done;
|
||||
if (ytype == NULL || strcmp(yang_argument_get(ytype), "identityref"))
|
||||
goto nomatch;
|
||||
/* Find if the derivation chain is: identity ->...-> ytype
|
||||
* Example:
|
||||
* identity is ex:ethernet
|
||||
* xleaf <type>fast-ethernet</type>
|
||||
* yleaf type identityref{base interface-type;}
|
||||
*/
|
||||
/* Just get the object corresponding to the base identity */
|
||||
if ((ybaseid = yang_find_identity_nsc(ys_spec(yleaf), baseidentity, nsc)) == NULL)
|
||||
goto nomatch;
|
||||
/* Get its list of derived identities */
|
||||
idrefvec = yang_cvec_get(ybaseid);
|
||||
/* Get and split the leaf id reference */
|
||||
if ((node = xml_body(xleaf)) == NULL) /* It may not be empty */
|
||||
goto nomatch;
|
||||
if (nodeid_split(node, &prefix, &id) < 0)
|
||||
goto done;
|
||||
/* Get its module (prefixes are not used here) */
|
||||
if (prefix == NULL)
|
||||
ymod = ys_module(yleaf);
|
||||
else{ /* from prefix to name */
|
||||
#if 1 /* IDENTITYREF_KLUDGE */
|
||||
ymod = yang_find_module_by_prefix_yspec(ys_spec(yleaf), prefix);
|
||||
#endif
|
||||
}
|
||||
if (ymod == NULL)
|
||||
goto nomatch;
|
||||
/* self special case, ie that the xleaf has a ref to itself */
|
||||
if (self &&
|
||||
ymod == ys_module(ybaseid) &&
|
||||
strcmp(baseid, id) == 0){
|
||||
; /* match */
|
||||
}
|
||||
else {
|
||||
/* Allocate cbuf */
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "%s:%s", yang_argument_get(ymod), id);
|
||||
if (cvec_find(idrefvec, cbuf_get(cb)) == NULL)
|
||||
goto nomatch;
|
||||
}
|
||||
retval = 1;
|
||||
done:
|
||||
if (baseid)
|
||||
free(baseid);
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
if (id)
|
||||
free(id);
|
||||
if (prefix)
|
||||
free(prefix);
|
||||
return retval;
|
||||
nomatch:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Eval xpath function derived-from(-and-self)
|
||||
* @param[in] xc Incoming context
|
||||
* @param[in] xs XPATH node tree
|
||||
* @param[in] nsc XML Namespace context
|
||||
* @param[in] localonly Skip prefix and namespace tests (non-standard)
|
||||
* @param[in] self If set, implements derived_from_or_self
|
||||
* @param[out] xrp Resulting context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see rfc7950 10.4.1
|
||||
* Returns "true" if any node in the argument "nodes" is a node of type "identityref" and its
|
||||
* value is an identity that is derived from (see Section 7.18.2) the identity "identity"
|
||||
* boolean derived-from(node-set nodes, string identity)
|
||||
* @see validate_identityref for similar code other usage
|
||||
*/
|
||||
int
|
||||
xp_function_derived_from(xp_ctx *xc,
|
||||
struct xpath_tree *xs,
|
||||
cvec *nsc,
|
||||
int localonly,
|
||||
int self,
|
||||
xp_ctx **xrp)
|
||||
{
|
||||
int retval = -1;
|
||||
xp_ctx *xr0 = NULL;
|
||||
xp_ctx *xr1 = NULL;
|
||||
xp_ctx *xr = NULL;
|
||||
char *identity = NULL;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
/* contains two arguments in xs: boolean derived-from(node-set, string) */
|
||||
/* This evolves to a set of (identityref) nodes */
|
||||
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
|
||||
goto done;
|
||||
if (xr0->xc_type != XT_NODESET)
|
||||
goto done;
|
||||
/* This evolves to a string identity */
|
||||
if (xp_eval(xc, xs->xs_c1, nsc, localonly, &xr1) < 0)
|
||||
goto done;
|
||||
if (ctx2string(xr1, &identity) < 0)
|
||||
goto done;
|
||||
/* Allocate a return struct of type boolean */
|
||||
if ((xr = malloc(sizeof(*xr))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(xr, 0, sizeof(*xr));
|
||||
xr->xc_type = XT_BOOL;
|
||||
/* ANY node is an identityref and its value an identity that is derived ... */
|
||||
for (i=0; i<xr0->xc_size; i++){
|
||||
if ((ret = derived_from_one(identity, nsc, xr0->xc_nodeset[i], self)) < 0)
|
||||
goto done;
|
||||
if (ret == 1)
|
||||
break;
|
||||
}
|
||||
xr->xc_bool = ret;
|
||||
*xrp = xr;
|
||||
xr = NULL;
|
||||
retval = 0;
|
||||
done:
|
||||
if (xr0)
|
||||
ctx_free(xr0);
|
||||
if (xr1)
|
||||
ctx_free(xr1);
|
||||
if (identity)
|
||||
free(identity);
|
||||
return retval;
|
||||
}
|
||||
47
lib/src/clixon_xpath_function.h
Normal file
47
lib/src/clixon_xpath_function.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2019 Olof Hagsand
|
||||
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)
|
||||
|
||||
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 *****
|
||||
|
||||
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10 (Base XML)
|
||||
* and rfc 7950 (YANG-specific)
|
||||
*/
|
||||
#ifndef _CLIXON_XPATH_FUNCTION_H
|
||||
#define _CLIXON_XPATH_FUNCTION_H
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int xp_function_contains(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
int xp_function_derived_from(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, int self, xp_ctx **xrp);
|
||||
|
||||
#endif /* _CLIXON_XPATH_FUNCTION_H */
|
||||
|
|
@ -113,6 +113,7 @@ ncname {namestart}{namechar}*
|
|||
<TOKEN>last { clixon_xpath_parselval.string = strdup(yytext); return FUNCTIONNAME; }
|
||||
<TOKEN>position { clixon_xpath_parselval.string = strdup(yytext); return FUNCTIONNAME; }
|
||||
<TOKEN>count { clixon_xpath_parselval.string = strdup(yytext); return FUNCTIONNAME; }
|
||||
<TOKEN>contains { clixon_xpath_parselval.string = strdup(yytext); return FUNCTIONNAME; }
|
||||
<TOKEN>re-match { clixon_xpath_parselval.string = strdup(yytext); return FUNCTIONNAME; }
|
||||
<TOKEN>deref { clixon_xpath_parselval.string = strdup(yytext); return FUNCTIONNAME; }
|
||||
<TOKEN>derived-from { clixon_xpath_parselval.string = strdup(yytext); return FUNCTIONNAME; }
|
||||
|
|
|
|||
|
|
@ -316,6 +316,87 @@ yang_flag_reset(yang_stmt *ys,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Get yang xpath for "when"-associated augment
|
||||
*
|
||||
* Ie, for yang structures like: augment <path> { when <xpath>; ... }
|
||||
* Will insert new yang nodes at <path> with this special "when" struct (not yang node)
|
||||
* @param[in] ys Yang statement
|
||||
* @retval xpath xpath should evaluate to true at validation
|
||||
* @retval NULL Not set
|
||||
*/
|
||||
char*
|
||||
yang_when_xpath_get(yang_stmt *ys)
|
||||
{
|
||||
return ys->ys_when_xpath;
|
||||
}
|
||||
|
||||
/*! Set yang xpath and namespace context for "when"-associated augment
|
||||
*
|
||||
* Ie, for yang structures like: augment <path> { when <xpath>; ... }
|
||||
* Will insert new yang nodes at <path> with this special "when" struct (not yang node)
|
||||
* @param[in] ys Yang statement
|
||||
* @param[in] xpath If set, this xpath should evaluate to true at validation, copied
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
yang_when_xpath_set(yang_stmt *ys,
|
||||
char *xpath)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
if (xpath == NULL){
|
||||
clicon_err(OE_YANG, EINVAL, "xpath is NULL");
|
||||
goto done;
|
||||
}
|
||||
if ((ys->ys_when_xpath = strdup(xpath)) == NULL){
|
||||
clicon_err(OE_YANG, errno, "strdup");
|
||||
goto done;
|
||||
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Get yang namespace context for "when"-associated augment
|
||||
*
|
||||
* Ie, for yang structures like: augment <path> { when <xpath>; ... }
|
||||
* Will insert new yang nodes at <path> with this special "when" struct (not yang node)
|
||||
* @param[in] ys Yang statement
|
||||
* @retval nsc Namespace context
|
||||
* @note retval is direct pointer, may need to be copied
|
||||
*/
|
||||
cvec *
|
||||
yang_when_nsc_get(yang_stmt *ys)
|
||||
{
|
||||
return ys->ys_when_nsc;
|
||||
}
|
||||
|
||||
/*! Set yang namespace context for "when"-associated augment
|
||||
*
|
||||
* Ie, for yang structures like: augment <path> { when <xpath>; ... }
|
||||
* Will insert new yang nodes at <path> with this special "when" struct (not yang node)
|
||||
* @param[in] ys Yang statement
|
||||
* @param[in] nsc Namespace context for when xpath
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
yang_when_nsc_set(yang_stmt *ys,
|
||||
cvec *nsc)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
if (nsc && (ys->ys_when_nsc = cvec_dup(nsc)) == NULL){
|
||||
clicon_err(OE_YANG, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* End access functions */
|
||||
|
||||
/*! Create new yang specification
|
||||
|
|
@ -390,6 +471,10 @@ ys_free1(yang_stmt *ys,
|
|||
yang_type_cache_free(ys->ys_typecache);
|
||||
ys->ys_typecache = NULL;
|
||||
}
|
||||
if (ys->ys_when_xpath)
|
||||
free(ys->ys_when_xpath);
|
||||
if (ys->ys_when_nsc)
|
||||
cvec_free(ys->ys_when_nsc);
|
||||
if (self)
|
||||
free(ys);
|
||||
return 0;
|
||||
|
|
@ -523,6 +608,17 @@ ys_cp(yang_stmt *ynew,
|
|||
if (yang_type_cache_cp(ynew, yold) < 0)
|
||||
goto done;
|
||||
}
|
||||
if (yold->ys_when_xpath)
|
||||
if ((ynew->ys_when_xpath = strdup(yold->ys_when_xpath)) == NULL){
|
||||
clicon_err(OE_YANG, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
if (yold->ys_when_nsc){
|
||||
if ((ynew->ys_when_nsc = cvec_dup(yold->ys_when_nsc)) == NULL){
|
||||
clicon_err(OE_YANG, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
for (i=0; i<ynew->ys_len; i++){
|
||||
yco = yold->ys_stmt[i];
|
||||
if ((ycn = ys_dup(yco)) == NULL)
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ struct yang_stmt{
|
|||
enum rfc_6020 ys_keyword; /* See clicon_yang_parse.tab.h */
|
||||
|
||||
char *ys_argument; /* String / argument depending on keyword */
|
||||
uint16_t ys_flags; /* Flags according to YANG_FLAG_* */
|
||||
uint16_t ys_flags; /* Flags according to YANG_FLAG_MARK and others */
|
||||
yang_stmt *ys_mymodule; /* Shortcut to "my" module. Augmented
|
||||
nodes can belong to other
|
||||
modules than the ancestor module */
|
||||
|
|
@ -87,7 +87,10 @@ struct yang_stmt{
|
|||
types as <module>:<id> list
|
||||
*/
|
||||
yang_type_cache *ys_typecache; /* If ys_keyword==Y_TYPE, cache all typedef data except unions */
|
||||
char *ys_when_xpath; /* Special conditional for a "when"-associated augment xpath */
|
||||
cvec *ys_when_nsc; /* Special conditional for a "when"-associated augment namespace ctx */
|
||||
int _ys_vector_i; /* internal use: yn_each */
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@
|
|||
#include "clixon_yang_internal.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_xml_nsctx.h"
|
||||
#include "clixon_yang_module.h"
|
||||
#include "clixon_plugin.h"
|
||||
#include "clixon_data.h"
|
||||
|
|
@ -203,6 +204,10 @@ ys_grouping_resolve(yang_stmt *yuses,
|
|||
* All data nodes defined in the "augment" statement are defined as XML
|
||||
* elements in the XML namespace of the module where the "augment" is
|
||||
* specified.
|
||||
*
|
||||
* @note If the augment has a when statement, which is commonplace, the when statement is not copied as
|
||||
* datanodes are, since it should not apply to the target node. Instead it is added as a special "when"
|
||||
* struct to the yang statements being inserted.
|
||||
*/
|
||||
static int
|
||||
yang_augment_node(yang_stmt *ys,
|
||||
|
|
@ -214,6 +219,9 @@ yang_augment_node(yang_stmt *ys,
|
|||
yang_stmt *yc0;
|
||||
yang_stmt *yc;
|
||||
yang_stmt *ymod;
|
||||
yang_stmt *ywhen;
|
||||
char *wxpath = NULL; /* xpath of when statement */
|
||||
cvec *wnsc = NULL; /* namespace context of when statement */
|
||||
|
||||
if ((ymod = ys_module(ys)) == NULL){
|
||||
clicon_err(OE_YANG, 0, "My yang module not found");
|
||||
|
|
@ -226,6 +234,12 @@ yang_augment_node(yang_stmt *ys,
|
|||
goto done;
|
||||
if (ytarget == NULL)
|
||||
goto ok;
|
||||
/* Find when statement, if present */
|
||||
if ((ywhen = yang_find(ys, Y_WHEN, NULL)) != NULL){
|
||||
wxpath = yang_argument_get(ywhen);
|
||||
if (xml_nsctx_yang(ywhen, &wnsc) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* Extend ytarget with ys' schemanode children */
|
||||
yc0 = NULL;
|
||||
while ((yc0 = yn_each(ys, yc0)) != NULL) {
|
||||
|
|
@ -236,10 +250,19 @@ yang_augment_node(yang_stmt *ys,
|
|||
yc->ys_mymodule = ymod;
|
||||
if (yn_insert(ytarget, yc) < 0)
|
||||
goto done;
|
||||
/* If there is an associated when statement, add a special when struct to the yang */
|
||||
if (ywhen){
|
||||
if (yang_when_xpath_set(yc, wxpath) < 0)
|
||||
goto done;
|
||||
if (yang_when_nsc_set(yc, wnsc) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (wnsc)
|
||||
cvec_free(wnsc);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2020 Olof Hagsand
|
||||
|
||||
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
|
||||
Copyright (C) 2017-2019 Olof Hagsand
|
||||
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
|
|
@ -94,6 +96,7 @@
|
|||
#include "clixon_hash.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_xml_nsctx.h"
|
||||
#include "clixon_yang_module.h"
|
||||
#include "clixon_plugin.h"
|
||||
#include "clixon_options.h"
|
||||
|
|
@ -1007,31 +1010,14 @@ ys_typedef_up(yang_stmt *ys)
|
|||
return (yang_stmt*)ys;
|
||||
}
|
||||
|
||||
/*! Find identity yang-stmt
|
||||
* This is a sanity check of base identity of identity-ref and for identity
|
||||
* statements when parsing.
|
||||
/*! Find identity yang-stmt given a name and a yang statement for prefix context
|
||||
*
|
||||
* Return true if node is identityref and is derived from identity_name
|
||||
* The derived-from() function returns true if the (first) node (in
|
||||
* document order in the argument "nodes") is a node of type identityref,
|
||||
* and its value is an identity that is derived from the identity
|
||||
* "identity-name" defined in the YANG module "module-name"; otherwise
|
||||
* it returns false.
|
||||
*
|
||||
* Valid values for an identityref are any identities derived from the
|
||||
* identityref's base identity.
|
||||
* 1. (base) identity must exist (be found). This is a sanity check
|
||||
* of the specification and also necessary for identity statements.
|
||||
* (This is what is done here)
|
||||
* 2. Check if a given node has value derived from base identity. This is
|
||||
* a run-time check necessary when validating eg netconf.
|
||||
* (This is validation)
|
||||
* 3. Find all valid derived identities from a identityref base identity.
|
||||
* (This is for cli generation)
|
||||
* @param[in] ys Yang spec of id statement
|
||||
* @param[in] identity Identity string -check if it exists
|
||||
* @retval 0 OK
|
||||
* @param[in] identity Identity string on the form <prefix>:<id>
|
||||
* @retval yid yang-stmt of type IDENTITY
|
||||
* @retval NULL Not found
|
||||
* @see validate_identityref for (2) above
|
||||
* @see xml_find_identity
|
||||
*/
|
||||
yang_stmt *
|
||||
yang_find_identity(yang_stmt *ys,
|
||||
|
|
@ -1076,6 +1062,44 @@ yang_find_identity(yang_stmt *ys,
|
|||
return yid;
|
||||
}
|
||||
|
||||
/*! Find identity yang-stmt given a name and a xml node for prefix context
|
||||
*
|
||||
* @param[in] yspec Top-level yang-spec
|
||||
* @param[in] identity Identity string on the form <prefix>:<id>
|
||||
* @param[in] nsc Namespace context for <prefix>
|
||||
* @retval yid yang-stmt of type IDENTITY
|
||||
* @retval NULL Not found
|
||||
* @see validate_identityref for (2) above
|
||||
* @see xml_find_identity
|
||||
*/
|
||||
yang_stmt *
|
||||
yang_find_identity_nsc(yang_stmt *yspec,
|
||||
char *identity,
|
||||
cvec *nsc)
|
||||
{
|
||||
char *id = NULL;
|
||||
char *prefix = NULL;
|
||||
yang_stmt *ymodule;
|
||||
yang_stmt *yid = NULL;
|
||||
char *ns = NULL;
|
||||
|
||||
if (nodeid_split(identity, &prefix, &id) < 0)
|
||||
goto done;
|
||||
if ((ns = xml_nsctx_get(nsc, prefix)) == NULL)
|
||||
goto done;
|
||||
if ((ymodule = yang_find_module_by_namespace(yspec, ns)) == NULL)
|
||||
goto done;
|
||||
/* if ymodule is a sub-module, the identity may be found in a
|
||||
* sub-module of ymod */
|
||||
yid = yang_find(ymodule, Y_IDENTITY, id);
|
||||
done:
|
||||
if (id)
|
||||
free(id);
|
||||
if (prefix)
|
||||
free(prefix);
|
||||
return yid;
|
||||
}
|
||||
|
||||
/*! Resolve type restrictions, return constraining parameters
|
||||
*
|
||||
* This is for types with range/length/regexp restrictions of the base type
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue