Merge branch 'clixon-4.5'
C-API changes for CLIgen code: * `clicon_parse()`: Changed signature due to new cligen error and result handling: * Removed: `cli_nomatch()`
This commit is contained in:
commit
f9998c441c
9 changed files with 69 additions and 466 deletions
|
|
@ -1022,406 +1022,6 @@ xml_non_config_data(cxobj *xt,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Associate XML node x with x:s parents yang:s matching child
|
||||
*
|
||||
* @param[in] xt XML tree node
|
||||
* @param[out] xerr Reason for failure, or NULL
|
||||
* @retval 2 OK yang assignment made
|
||||
* @retval 1 OK, Yang assignment not made because yang parent is anyxml or anydata
|
||||
* @retval 0 Yang assigment not made and xerr set
|
||||
* @retval -1 Error
|
||||
* @see populate_self_top
|
||||
*/
|
||||
static int
|
||||
populate_self_parent(cxobj *xt,
|
||||
cxobj **xerr)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *y = NULL; /* yang node */
|
||||
yang_stmt *yparent; /* yang parent */
|
||||
cxobj *xp = NULL; /* xml parent */
|
||||
char *name;
|
||||
char *ns = NULL; /* XML namespace of xt */
|
||||
char *nsy = NULL; /* Yang namespace of xt */
|
||||
|
||||
xp = xml_parent(xt);
|
||||
name = xml_name(xt);
|
||||
if (xp == NULL){
|
||||
if (xerr &&
|
||||
netconf_bad_element_xml(xerr, "application", name, "Missing parent") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
if ((yparent = xml_spec(xp)) == NULL){
|
||||
if (xerr &&
|
||||
netconf_bad_element_xml(xerr, "application", name, "Missing parent yang node") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
if (yang_keyword_get(yparent) == Y_ANYXML || yang_keyword_get(yparent) == Y_ANYDATA){
|
||||
retval = 1;
|
||||
goto done;
|
||||
}
|
||||
if ((y = yang_find_datanode(yparent, name)) == NULL){
|
||||
if (xerr &&
|
||||
netconf_bad_element_xml(xerr, "application", name, "Missing matching yang node") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
if (xml2ns(xt, xml_prefix(xt), &ns) < 0)
|
||||
goto done;
|
||||
nsy = yang_find_mynamespace(y);
|
||||
if (ns == NULL || nsy == NULL){
|
||||
if (xerr &&
|
||||
netconf_bad_element_xml(xerr, "application", name, "Missing namespace") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
/* Assign spec only if namespaces match */
|
||||
if (strcmp(ns, nsy) != 0){
|
||||
if (xerr &&
|
||||
netconf_bad_element_xml(xerr, "application", name, "Namespace mismatch") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
xml_spec_set(xt, y);
|
||||
#ifdef XML_EXPLICIT_INDEX
|
||||
if (xml_search_index_p(xt))
|
||||
xml_search_child_insert(xp, xt);
|
||||
#endif
|
||||
retval = 2;
|
||||
done:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Associate XML node x with yang spec y by going through all top-level modules and finding match
|
||||
*
|
||||
* @param[in] xt XML tree node
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[out] xerr Reason for failure, or NULL
|
||||
* @retval 2 OK yang assignment made
|
||||
* @retval 1 OK, Yang assignment not made because yang parent is anyxml or anydata
|
||||
* @retval 0 yang assigment not made and xerr set
|
||||
* @retval -1 Error
|
||||
* @see populate_self_parent
|
||||
*/
|
||||
static int
|
||||
populate_self_top(cxobj *xt,
|
||||
yang_stmt *yspec,
|
||||
cxobj **xerr)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *y = NULL; /* yang node */
|
||||
yang_stmt *ymod; /* yang module */
|
||||
char *name;
|
||||
char *ns = NULL; /* XML namespace of xt */
|
||||
char *nsy = NULL; /* Yang namespace of xt */
|
||||
|
||||
name = xml_name(xt);
|
||||
if (yspec == NULL){
|
||||
if (xerr &&
|
||||
netconf_bad_element_xml(xerr, "application", name, "Missing yang spec") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
if (ys_module_by_xml(yspec, xt, &ymod) < 0)
|
||||
goto done;
|
||||
/* ymod is "real" module, name may belong to included submodule */
|
||||
if (ymod == NULL){
|
||||
if (xerr &&
|
||||
netconf_bad_element_xml(xerr, "application", name, "No such yang module") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
if ((y = yang_find_schemanode(ymod, name)) == NULL){ /* also rpc */
|
||||
if (xerr &&
|
||||
netconf_bad_element_xml(xerr, "application", name, "Missing matching yang node") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
if (xml2ns(xt, xml_prefix(xt), &ns) < 0)
|
||||
goto done;
|
||||
nsy = yang_find_mynamespace(y);
|
||||
if (ns == NULL || nsy == NULL){
|
||||
if (xerr &&
|
||||
netconf_bad_element_xml(xerr, "application", name, "Missing namespace") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
/* Assign spec only if namespaces match */
|
||||
if (strcmp(ns, nsy) != 0){
|
||||
if (xerr &&
|
||||
netconf_bad_element_xml(xerr, "application", name, "Namespace mismatch") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
xml_spec_set(xt, y);
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! After yang binding, bodies of containers and lists are stripped from XML bodies
|
||||
* May apply to other nodes?
|
||||
*/
|
||||
static int
|
||||
strip_whitespace(cxobj *xt)
|
||||
{
|
||||
yang_stmt *yt;
|
||||
enum rfc_6020 keyword;
|
||||
cxobj *xc;
|
||||
|
||||
if ((yt = xml_spec(xt)) != NULL){
|
||||
keyword = yang_keyword_get(yt);
|
||||
if (keyword == Y_LIST || keyword == Y_CONTAINER){
|
||||
xc = NULL;
|
||||
while ((xc = xml_find_type(xt, NULL, "body", CX_BODY)) != NULL)
|
||||
xml_purge(xc);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Find yang spec association of tree of XML nodes
|
||||
*
|
||||
* Populate xt:s children as top-level symbols
|
||||
* This may be unnecessary if yspec is set on manual creation. Also note that for incoming or
|
||||
* outgoing RPC need specialized function. maybe it can be built into the same function, but
|
||||
* you dont know whether it is input or output rpc.
|
||||
* @param[in] xt XML tree node
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[out] xerr Reason for failure, or NULL
|
||||
* @retval 1 OK yang assignment made
|
||||
* @retval 0 Partial or no yang assigment made (at least one failed) and xerr set
|
||||
* @retval -1 Error
|
||||
* @code
|
||||
* if (xml_bind_yang(x, YB_MODULE, yspec, NULL) < 0)
|
||||
* err;
|
||||
* @endcode
|
||||
* @note For subs to anyxml nodes will not have spec set
|
||||
* There are several functions in the API family
|
||||
* @see xml_bind_yang_rpc for incoming rpc
|
||||
* @see xml_bind_yang0 If the calling xml object should also be populated
|
||||
*/
|
||||
int
|
||||
xml_bind_yang(cxobj *xt,
|
||||
yang_bind yb,
|
||||
yang_stmt *yspec,
|
||||
cxobj **xerr)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xc; /* xml child */
|
||||
int ret;
|
||||
int failed = 0; /* we continue loop after failure, should we stop at fail?`*/
|
||||
|
||||
strip_whitespace(xt);
|
||||
xc = NULL; /* Apply on children */
|
||||
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL) {
|
||||
if ((ret = xml_bind_yang0(xc, yb, yspec, xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
failed++;
|
||||
}
|
||||
if (failed)
|
||||
goto fail;
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Find yang spec association of tree of XML nodes
|
||||
*
|
||||
* @param[in] xt XML tree node
|
||||
* @param[in] yb How to bind yang to XML top-level when parsing
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[out] xerr Reason for failure, or NULL
|
||||
* @retval 1 OK yang assignment made
|
||||
* @retval 0 Partial or no yang assigment made (at least one failed) and xerr set
|
||||
* @retval -1 Error
|
||||
* Populate xt as top-level node
|
||||
*/
|
||||
int
|
||||
xml_bind_yang0(cxobj *xt,
|
||||
yang_bind yb,
|
||||
yang_stmt *yspec,
|
||||
cxobj **xerr)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xc; /* xml child */
|
||||
int ret;
|
||||
int failed = 0; /* we continue loop after failure, should we stop at fail?`*/
|
||||
|
||||
switch (yb){
|
||||
case YB_MODULE:
|
||||
if ((ret = populate_self_top(xt, yspec, xerr)) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case YB_PARENT:
|
||||
if ((ret = populate_self_parent(xt, xerr)) < 0)
|
||||
goto done;
|
||||
break;
|
||||
default:
|
||||
clicon_err(OE_XML, EINVAL, "Invalid yang binding: %d", yb);
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
strip_whitespace(xt);
|
||||
xc = NULL; /* Apply on children */
|
||||
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL) {
|
||||
if ((ret = xml_bind_yang0(xc, YB_PARENT, yspec, xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
failed++;
|
||||
}
|
||||
if (failed)
|
||||
goto fail;
|
||||
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
|
||||
* @param[in] xrpc XML rpc node
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[out] xerr Reason for failure, or NULL
|
||||
* @retval 1 OK yang assignment made
|
||||
* @retval 0 Partial or no yang assigment made (at least one failed) and xerr set
|
||||
* @retval -1 Error
|
||||
* The
|
||||
* @code
|
||||
* if (xml_bind_yang_rpc(h, x, NULL) < 0)
|
||||
* err;
|
||||
* @endcode
|
||||
* @see xml_bind_yang For other generic cases
|
||||
* @see xml_bind_yang_rpc_reply
|
||||
*/
|
||||
int
|
||||
xml_bind_yang_rpc(cxobj *xrpc,
|
||||
yang_stmt *yspec,
|
||||
cxobj **xerr)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yrpc = NULL; /* yang node */
|
||||
yang_stmt *ymod=NULL; /* yang module */
|
||||
yang_stmt *yi = NULL; /* input */
|
||||
cxobj *x;
|
||||
int ret;
|
||||
|
||||
if ((strcmp(xml_name(xrpc), "rpc")) != 0){
|
||||
clicon_err(OE_UNIX, EINVAL, "RPC expected");
|
||||
goto done;
|
||||
}
|
||||
x = NULL;
|
||||
while ((x = xml_child_each(xrpc, x, CX_ELMNT)) != NULL) {
|
||||
if (ys_module_by_xml(yspec, x, &ymod) < 0)
|
||||
goto done;
|
||||
if (ymod != NULL)
|
||||
yrpc = yang_find(ymod, Y_RPC, xml_name(x));
|
||||
/* Non-strict semantics: loop through all modules to find the node
|
||||
*/
|
||||
if (yrpc){
|
||||
xml_spec_set(x, yrpc);
|
||||
if ((yi = yang_find(yrpc, Y_INPUT, NULL)) != NULL){
|
||||
/* 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:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Find yang spec association of XML node for outgoing RPC starting with <rpc-reply>
|
||||
*
|
||||
* Incoming RPC has an "input" structure that is not taken care of by xml_bind_yang
|
||||
* @param[in] xrpc XML rpc node
|
||||
* @param[in] name Name of RPC (not seen in output/reply)
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[out] xerr Reason for failure, or NULL
|
||||
* @retval 1 OK yang assignment made
|
||||
* @retval 0 Partial or no yang assigment made (at least one failed) and xerr set
|
||||
* @retval -1 Error
|
||||
*
|
||||
* @code
|
||||
* if (xml_bind_yang_rpc_reply(x, "get-config", yspec, name) < 0)
|
||||
* err;
|
||||
* @endcode
|
||||
* @see xml_bind_yang For other generic cases
|
||||
*/
|
||||
int
|
||||
xml_bind_yang_rpc_reply(cxobj *xrpc,
|
||||
char *name,
|
||||
yang_stmt *yspec,
|
||||
cxobj **xerr)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yrpc = NULL; /* yang node */
|
||||
yang_stmt *ymod=NULL; /* yang module */
|
||||
yang_stmt *yo = NULL; /* output */
|
||||
cxobj *x;
|
||||
int ret;
|
||||
|
||||
if (strcmp(xml_name(xrpc), "rpc-reply")){
|
||||
clicon_err(OE_UNIX, EINVAL, "rpc-reply expected");
|
||||
goto done;
|
||||
}
|
||||
x = NULL;
|
||||
while ((x = xml_child_each(xrpc, x, CX_ELMNT)) != NULL) {
|
||||
if (ys_module_by_xml(yspec, x, &ymod) < 0)
|
||||
goto done;
|
||||
if (ymod == NULL)
|
||||
continue;
|
||||
if ((yrpc = yang_find(ymod, Y_RPC, name)) == NULL)
|
||||
continue;
|
||||
// xml_spec_set(xrpc, yrpc);
|
||||
if ((yo = yang_find(yrpc, Y_OUTPUT, NULL)) == NULL)
|
||||
continue;
|
||||
/* 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 */
|
||||
break;
|
||||
}
|
||||
if (yo != NULL){
|
||||
xml_spec_set(xrpc, yo);
|
||||
if ((ret = xml_bind_yang(xrpc, YB_MODULE, yspec, xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
}
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Given an XML node, build an xpath to root, internal function
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error. eg XML malformed
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue