YANG Action (RFC 7950 Section 7.15)

See [Support for "action" statement](https://github.com/clicon/clixon/issues/101)
This commit is contained in:
Olof hagsand 2022-06-03 11:14:58 +02:00
parent 87c65c3541
commit bdb516fec9
16 changed files with 583 additions and 104 deletions

View file

@ -77,6 +77,7 @@
#include "clixon_netconf_lib.h"
#include "clixon_xml_sort.h"
#include "clixon_yang_type.h"
#include "clixon_xml_map.h"
#include "clixon_xml_bind.h"
/*
@ -183,31 +184,33 @@ populate_self_parent(cxobj *xt,
}
if (xml2ns(xt, xml_prefix(xt), &ns) < 0)
goto done;
if ((y = yang_find_datanode(yparent, name)) == NULL){
if (_yang_unknown_anydata){
/* Add dummy Y_ANYDATA yang stmt, see ysp_add */
if ((y = yang_anydata_add(yparent, name)) < 0)
/* Special case since action is not a datanode */
if ((y = yang_find(yparent, Y_ACTION, name)) == NULL)
if ((y = yang_find_datanode(yparent, name)) == NULL){
if (_yang_unknown_anydata){
/* Add dummy Y_ANYDATA yang stmt, see ysp_add */
if ((y = yang_anydata_add(yparent, name)) < 0)
goto done;
xml_spec_set(xt, y);
retval = 2; /* treat as anydata */
clicon_log(LOG_WARNING,
"%s: %d: No YANG spec for %s, anydata used",
__FUNCTION__, __LINE__, name);
goto done;
xml_spec_set(xt, y);
retval = 2; /* treat as anydata */
clicon_log(LOG_WARNING,
"%s: %d: No YANG spec for %s, anydata used",
__FUNCTION__, __LINE__, name);
goto done;
}
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
cprintf(cb, "Failed to find YANG spec of XML node: %s", name);
cprintf(cb, " with parent: %s", xml_name(xp));
if (ns)
cprintf(cb, " in namespace: %s", ns);
if (xerr &&
netconf_unknown_element_xml(xerr, "application", name, cbuf_get(cb)) < 0)
goto done;
goto fail;
}
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
cprintf(cb, "Failed to find YANG spec of XML node: %s", name);
cprintf(cb, " with parent: %s", xml_name(xp));
if (ns)
cprintf(cb, " in namespace: %s", ns);
if (xerr &&
netconf_unknown_element_xml(xerr, "application", name, cbuf_get(cb)) < 0)
goto done;
goto fail;
}
nsy = yang_find_mynamespace(y);
if (ns == NULL || nsy == NULL){
if (xerr &&
@ -516,6 +519,92 @@ xml_bind_yang0(cxobj *xt,
goto done;
}
/*! RPC-specific
*/
static int
xml_bind_yang_rpc_rpc(cxobj *x,
yang_stmt *yrpc,
char *rpcname,
cxobj **xerr)
{
int retval = -1;
cbuf *cb = NULL;
char *name;
cxobj *xc;
yang_stmt *yi = NULL; /* input */
int ret;
xml_spec_set(x, yrpc); /* required for validate */
if ((yi = yang_find(yrpc, Y_INPUT, NULL)) == NULL){
/* If no yang input spec but RPC has elements, return unknown element */
if (xml_child_nr_type(x, CX_ELMNT) != 0){
xc = xml_child_i_type(x, 0, CX_ELMNT); /* Pick first */
name = xml_name(xc);
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
cprintf(cb, "Unrecognized parameter: %s in rpc: %s", name, rpcname);
if (xerr &&
netconf_unknown_element_xml(xerr, "application", name, cbuf_get(cb)) < 0)
goto done;
goto fail;
}
}
else{
/* xml_bind_yang need to have parent with yang spec for
* recursive population to work. Therefore, assign input yang
* to rpc level although not 100% intuitive */
xml_spec_set(x, yi);
if ((ret = xml_bind_yang(x, YB_PARENT, NULL, xerr)) < 0)
goto done;
if (ret == 0)
goto fail;
}
retval = 1;
done:
if (cb)
cbuf_free(cb);
return retval;
fail:
retval = 0;
goto done;
}
/*! Action-specific
*
* Find the innermost container or list containing an XML element that carries the name of the
* defined action.
* Only one action can be invoked in one rpc
* XXX if not more action, consider folding into calling function
*/
static int
xml_bind_yang_rpc_action(cxobj *xn,
yang_stmt *yspec,
cxobj **xerr)
{
int retval = -1;
int ret;
cxobj *xi;
yang_stmt *yi;;
if ((ret = xml_bind_yang(xn, YB_MODULE, yspec, xerr)) < 0)
goto done;
if (ret == 0)
goto fail;
/* Special case: bind "action" node to module for validate code to work */
if ((xi = xml_child_i_type(xn, 0, CX_ELMNT)) != NULL &&
(yi = xml_spec(xi))){
xml_spec_set(xn, ys_module(yi));
}
retval = 1;
done:
return retval;
fail:
retval = 0;
goto done;
}
/*! Find yang spec association of XML node for incoming RPC starting with <rpc>
*
* Incoming RPC has an "input" structure that is not taken care of by xml_bind_yang
@ -541,13 +630,11 @@ xml_bind_yang_rpc(cxobj *xrpc,
int retval = -1;
yang_stmt *yrpc = NULL; /* yang node */
yang_stmt *ymod=NULL; /* yang module */
yang_stmt *yi = NULL; /* input */
cxobj *x;
int ret;
char *opname; /* top-level netconf operation */
char *rpcname; /* RPC name */
char *name;
cbuf *cb = NULL;
cxobj *xc;
opname = xml_name(xrpc);
@ -607,6 +694,15 @@ xml_bind_yang_rpc(cxobj *xrpc,
x = NULL;
while ((x = xml_child_each(xrpc, x, CX_ELMNT)) != NULL) {
rpcname = xml_name(x);
if ((ret = xml_rpc_isaction(x)) < 0)
goto done;
if (ret == 1){
if ((ret = xml_bind_yang_rpc_action(x, yspec, xerr)) < 0)
goto done;
if (ret == 0)
goto fail;
goto ok;
} /* if not action fall through */
if (ys_module_by_xml(yspec, x, &ymod) < 0)
goto done;
if (ymod == NULL){
@ -621,39 +717,14 @@ xml_bind_yang_rpc(cxobj *xrpc,
goto done;
goto fail;
}
xml_spec_set(x, yrpc); /* required for validate */
if ((yi = yang_find(yrpc, Y_INPUT, NULL)) == NULL){
/* If no yang input spec but RPC has elements, return unknown element */
if (xml_child_nr_type(x, CX_ELMNT) != 0){
xc = xml_child_i_type(x, 0, CX_ELMNT); /* Pick first */
name = xml_name(xc);
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
cprintf(cb, "Unrecognized parameter: %s in rpc: %s", name, rpcname);
if (xerr &&
netconf_unknown_element_xml(xerr, "application", name, cbuf_get(cb)) < 0)
goto done;
goto fail;
}
}
else{
/* xml_bind_yang need to have parent with yang spec for
* recursive population to work. Therefore, assign input yang
* to rpc level although not 100% intuitive */
xml_spec_set(x, yi);
if ((ret = xml_bind_yang(x, YB_PARENT, NULL, xerr)) < 0)
goto done;
if (ret == 0)
goto fail;
}
if ((ret = xml_bind_yang_rpc_rpc(x, yrpc, rpcname, xerr)) < 0)
goto done;
if (ret == 0)
goto fail;
}
ok:
retval = 1;
done:
if (cb)
cbuf_free(cb);
return retval;
fail:
retval = 0;