Merge branch 'master' into filter-and-xml-encoding-fixes

This commit is contained in:
Phil Heller 2021-07-29 23:01:47 -06:00
commit 3c5f956805
97 changed files with 2861 additions and 1480 deletions

View file

@ -170,9 +170,10 @@ clixon_client_lock(int sock,
clicon_err(OE_PLUGIN, errno, "cbuf_new");
goto done;
}
cprintf(msg, "<rpc xmlns=\"%s\">"
cprintf(msg, "<rpc xmlns=\"%s\" %s>"
"<%slock><target><%s/></target></%slock></rpc>",
NETCONF_BASE_NAMESPACE,
NETCONF_MESSAGE_ID_ATTR,
lock?"":"un", db, lock?"":"un");
if (clicon_rpc1(sock, msg, msgret) < 0)
goto done;
@ -422,6 +423,7 @@ clixon_client_get_xdata(int sock,
cprintf(msg, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
cprintf(msg, " xmlns:%s=\"%s\"",
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
cprintf(msg, " %s", NETCONF_MESSAGE_ID_ATTR);
cprintf(msg, "><get-config><source><%s/></source>", db);
if (xpath && strlen(xpath)){
cprintf(msg, "<%s:filter %s:type=\"xpath\" xmlns=\"%s\" %s:select=\"%s\"",

View file

@ -539,7 +539,7 @@ xmldb_empty_get(clicon_handle h,
return de->de_empty;
}
/*! Get modified flag from datastore
/*! Set modified flag from datastore
* @param[in] h Clicon handle
* @param[in] db Database name
* @param[in] value 0 or 1

View file

@ -557,7 +557,7 @@ xmldb_readfile(clicon_handle h,
}
cprintf(cberr, "Internal error: %s", clicon_err_reason);
clicon_err_reset();
if (netconf_operation_failed_xml(xerr, "application", cbuf_get(cberr))< 0)
if (xerr && netconf_operation_failed_xml(xerr, "application", cbuf_get(cberr))< 0)
goto done;
cbuf_free(cberr);
goto fail;

View file

@ -459,7 +459,7 @@ text_modify(clicon_handle h,
changed++;
if (op==OP_NONE)
xml_flag_set(x0, XML_FLAG_NONE); /* Mark for potential deletion */
if (x1bstr){ /* empty type does not have body */
if (x1bstr){ /* empty type does not have body */ /* XXX Here x0 = <b></b> */
if ((x0b = xml_new("body", x0, CX_BODY)) == NULL)
goto done;
}
@ -499,23 +499,26 @@ text_modify(clicon_handle h,
if (assign_namespace_body(x1, x0) < 0)
goto done;
}
if ((x0b = xml_body_get(x0)) != NULL){
x0bstr = xml_value(x0b);
if (x0bstr==NULL || strcmp(x0bstr, x1bstr)){
if ((op != OP_NONE) && !permit && xnacm){
if ((ret = nacm_datanode_write(h, x1, x1t,
x0bstr==NULL?NACM_CREATE:NACM_UPDATE,
username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
}
if (xml_value_set(x0b, x1bstr) < 0)
/* XXX here x1bstr is checked for null, while adding an empty string above */
if ((x0b = xml_body_get(x0)) == NULL && x1bstr && strlen(x1bstr)){
if ((x0b = xml_new("body", x0, CX_BODY)) == NULL)
goto done;
}
x0bstr = xml_value(x0b);
if (x0bstr==NULL || strcmp(x0bstr, x1bstr)){
if ((op != OP_NONE) && !permit && xnacm){
if ((ret = nacm_datanode_write(h, x1, x1t,
x0bstr==NULL?NACM_CREATE:NACM_UPDATE,
username, xnacm, cbret)) < 0)
goto done;
/* If a default value ies replaced, then reset default flag */
if (xml_flag(x0, XML_FLAG_DEFAULT))
xml_flag_reset(x0, XML_FLAG_DEFAULT);
if (ret == 0)
goto fail;
}
if (xml_value_set(x0b, x1bstr) < 0)
goto done;
/* If a default value ies replaced, then reset default flag */
if (xml_flag(x0, XML_FLAG_DEFAULT))
xml_flag_reset(x0, XML_FLAG_DEFAULT);
}
} /* x1bstr */
if (changed){

View file

@ -1238,7 +1238,7 @@ _json_parse(char *str,
goto done;
}
cprintf(cberr, "Top-level JSON object %s is not qualified with namespace which is a MUST according to RFC 7951", xml_name(x));
if (netconf_malformed_message_xml(xerr, cbuf_get(cberr)) < 0)
if (xerr && netconf_malformed_message_xml(xerr, cbuf_get(cberr)) < 0)
goto done;
goto fail;
}

View file

@ -65,6 +65,7 @@
#include "clixon_xml.h"
#include "clixon_options.h"
#include "clixon_data.h"
#include "clixon_xml_bind.h"
#include "clixon_xml_map.h"
#include "clixon_xml_io.h"
#include "clixon_xpath_ctx.h"
@ -130,6 +131,10 @@ netconf_invalid_value_xml(cxobj **xret,
char *encstr = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
goto done;
}
if (*xret == NULL){
if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
goto done;
@ -228,44 +233,86 @@ netconf_too_big(cbuf *cb,
goto done;
}
/*! Create Netconf missing-attribute error XML tree according to RFC 6241 App A
*
* An expected attribute is missing.
* @param[out] xret Error XML tree. Free with xml_free after use
* @param[in] type Error type: "rpc", "application" or "protocol"
* @param[in] attr bad-attribute and/or bad-element xml
* @param[in] message Error message (will be XML encoded)
*/
int
netconf_missing_attribute_xml(cxobj **xret,
char *type,
char *attr,
char *message)
{
int retval = -1;
cxobj *xerr = NULL;
char *encstr = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
goto done;
}
if (*xret == NULL){
if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
goto done;
}
else if (xml_name_set(*xret, "rpc-reply") < 0)
goto done;
if ((xa = xml_new("xmlns", *xret, CX_ATTR)) == NULL)
goto done;
if (xml_value_set(xa, NETCONF_BASE_NAMESPACE) < 0)
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-type>%s</error-type>"
"<error-tag>missing-attribute</error-tag>"
"<error-info><bad-attribute>%s</bad-attribute></error-info>"
"<error-severity>error</error-severity>", type, attr) < 0)
goto done;
if (message){
if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-message>%s</error-message>",
encstr) < 0)
goto done;
}
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
}
/*! Create Netconf missing-attribute error XML tree according to RFC 6241 App A
*
* An expected attribute is missing.
* @param[out] cb CLIgen buf. Error XML is written in this buffer
* @param[in] type Error type: "rpc", "application" or "protocol"
* @param[in] info bad-attribute or bad-element xml
* @param[in] message Error message (will be XML encoded)
* @param[in] attr bad-attribute
* @param[in] message Error message (will be XML encoded) or NULL
*/
int
netconf_missing_attribute(cbuf *cb,
char *type,
char *info,
char *attr,
char *message)
{
int retval = -1;
char *encstr = NULL;
int retval = -1;
cxobj *xret = NULL;
if (cprintf(cb, "<rpc-reply xmlns=\"%s\"><rpc-error>"
"<error-type>%s</error-type>"
"<error-tag>missing-attribute</error-tag>"
"<error-info>%s</error-info>"
"<error-severity>error</error-severity>",
NETCONF_BASE_NAMESPACE, type, info) <0)
goto err;
if (message){
if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "<error-message>%s</error-message>", encstr) < 0)
goto err;
}
if (cprintf(cb, "</rpc-error></rpc-reply>") <0)
goto err;
if (netconf_missing_attribute_xml(&xret, type, attr, message) < 0)
goto done;
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
goto done;
retval = 0;
done:
if (xret)
xml_free(xret);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
goto done;
}
/*! Create Netconf bad-attribute error XML tree according to RFC 6241 App A
@ -317,6 +364,10 @@ netconf_bad_attribute_xml(cxobj **xret,
char *encstr = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
goto done;
}
if (*xret == NULL){
if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
goto done;
@ -410,6 +461,10 @@ netconf_common_xml(cxobj **xret,
char *encstr = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
goto done;
}
if (*xret == NULL){
if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
goto done;
@ -666,6 +721,10 @@ netconf_access_denied_xml(cxobj **xret,
char *encstr = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
goto done;
}
if (*xret == NULL){
if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
goto done;
@ -902,6 +961,10 @@ netconf_data_missing_xml(cxobj **xret,
cxobj *xerr;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
goto done;
}
if (*xret == NULL){
if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
goto done;
@ -966,6 +1029,10 @@ netconf_operation_not_supported_xml(cxobj **xret,
char *encstr = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
goto done;
}
if (*xret == NULL){
if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
goto done;
@ -1077,6 +1144,10 @@ netconf_operation_failed_xml(cxobj **xret,
char *encstr = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
goto done;
}
if (*xret == NULL){
if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
goto done;
@ -1161,6 +1232,10 @@ netconf_malformed_message_xml(cxobj **xret,
char *encstr = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
goto done;
}
if (*xret == NULL){
if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
goto done;
@ -1211,8 +1286,12 @@ netconf_data_not_unique_xml(cxobj **xret,
cxobj *xerr;
cxobj *xinfo;
cbuf *cb = NULL;
cxobj *xa;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
goto done;
}
if (*xret == NULL){
if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
goto done;
@ -1277,6 +1356,10 @@ netconf_minmax_elements_xml(cxobj **xret,
cbuf *cb = NULL;
cxobj *xa;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
goto done;
}
if (*xret == NULL){
if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
goto done;
@ -1334,6 +1417,10 @@ netconf_trymerge(cxobj *x,
char *reason = NULL;
cxobj *xc;
if (xret == NULL){
clicon_err(OE_NETCONF, EINVAL, "xret is NULL");
goto done;
}
if (*xret == NULL){
if ((*xret = xml_dup(x)) == NULL)
goto done;
@ -1429,6 +1516,16 @@ netconf_module_load(clicon_handle h)
/* Load restconf yang. Note this is also a part of clixon-config */
if (yang_spec_parse_module(h, "clixon-restconf", NULL, yspec)< 0)
goto done;
#if 1
/* XXX: Both the following settings are because clicon-handle is not part of all API
* functions
* Treat unknown XML as anydata */
if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
xml_bind_yang_unknown_anydata(1);
/* Make message-id attribute optional */
if (clicon_option_bool(h, "CLICON_NETCONF_MESSAGE_ID_OPTIONAL") == 1)
xml_bind_netconf_message_id_optional(1);
#endif
retval = 0;
done:
return retval;

View file

@ -731,7 +731,8 @@ api_path2xpath_cvv(cvec *api_path,
cvk = yang_cvec_get(y); /* Use Y_LIST cache, see ys_populate_list() */
cvi = NULL;
/* Iterate over individual yang keys */
cprintf(xpath, "/");
if (i != offset)
cprintf(xpath, "/");
if (xprefix)
cprintf(xpath, "%s:", xprefix);
cprintf(xpath, "%s", name);
@ -752,7 +753,8 @@ api_path2xpath_cvv(cvec *api_path,
}
break;
case Y_LEAF_LIST: /* XXX: LOOP? */
cprintf(xpath, "/");
if (i != offset)
cprintf(xpath, "/");
if (xprefix)
cprintf(xpath, "%s:", xprefix);
cprintf(xpath, "%s", name);
@ -1129,6 +1131,9 @@ api_path2xml_vec(char **vec,
}
/*! Create xml tree from api-path
*
* Create an XML tree from "scratch" using api-path, ie no other input than the api-path itself,
* ie not from an existing datastore for example.
* @param[in] api_path (Absolute) API-path as defined in RFC 8040
* @param[in] yspec Yang spec
* @param[in,out] xtop Incoming XML tree

View file

@ -648,7 +648,7 @@ clixon_process_operation(clicon_handle h,
sched++;/* start: immediate stop/restart: not immediate: wait timeout */
}
else{
clicon_debug(1, "%s name:%s op %s cancelled by wrwap", __FUNCTION__, name, clicon_int2str(proc_operation_map, op0));
clicon_debug(1, "%s name:%s op %s cancelled by wrap", __FUNCTION__, name, clicon_int2str(proc_operation_map, op0));
}
break; /* hit break here */
}
@ -682,48 +682,54 @@ clixon_process_status(clicon_handle h,
int run;
int i;
char timestr[28];
int match = 0;
if (_proc_entry_list == NULL)
goto ok;
pe = _proc_entry_list;
do {
if (strcmp(pe->pe_name, name) == 0){
/* Check if running */
run = 0;
if (pe->pe_pid && proc_op_run(pe->pe_pid, &run) < 0)
goto done;
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><active xmlns=\"%s\">%s</active>",
NETCONF_BASE_NAMESPACE, CLIXON_LIB_NS, run?"true":"false");
if (pe->pe_description)
cprintf(cbret, "<description xmlns=\"%s\">%s</description>", CLIXON_LIB_NS, pe->pe_description);
cprintf(cbret, "<command xmlns=\"%s\">", CLIXON_LIB_NS);
/* the command may include any data, including XML (such as restconf -R command) and
therefore needs CDATA encoding */
cprintf(cbret, "<![CDATA[");
for (i=0; i<pe->pe_argc-1; i++){
if (i)
cprintf(cbret, " ");
cprintf(cbret, "%s", pe->pe_argv[i]);
}
cprintf(cbret, "]]>");
cprintf(cbret, "</command>");
cprintf(cbret, "<status xmlns=\"%s\">%s</status>", CLIXON_LIB_NS,
clicon_int2str(proc_state_map, pe->pe_state));
if (timerisset(&pe->pe_starttime)){
if (time2str(pe->pe_starttime, timestr, sizeof(timestr)) < 0){
clicon_err(OE_UNIX, errno, "time2str");
if (_proc_entry_list != NULL){
pe = _proc_entry_list;
do {
if (strcmp(pe->pe_name, name) == 0){
clicon_debug(1, "%s found %s pid:%d", __FUNCTION__, name, pe->pe_pid);
/* Check if running */
run = 0;
if (pe->pe_pid && proc_op_run(pe->pe_pid, &run) < 0)
goto done;
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><active xmlns=\"%s\">%s</active>",
NETCONF_BASE_NAMESPACE, CLIXON_LIB_NS, run?"true":"false");
if (pe->pe_description)
cprintf(cbret, "<description xmlns=\"%s\">%s</description>", CLIXON_LIB_NS, pe->pe_description);
cprintf(cbret, "<command xmlns=\"%s\">", CLIXON_LIB_NS);
/* the command may include any data, including XML (such as restconf -R command) and
therefore needs CDATA encoding */
cprintf(cbret, "<![CDATA[");
for (i=0; i<pe->pe_argc-1; i++){
if (i)
cprintf(cbret, " ");
cprintf(cbret, "%s", pe->pe_argv[i]);
}
cprintf(cbret, "<starttime xmlns=\"%s\">%s</starttime>", CLIXON_LIB_NS, timestr);
cprintf(cbret, "]]>");
cprintf(cbret, "</command>");
cprintf(cbret, "<status xmlns=\"%s\">%s</status>", CLIXON_LIB_NS,
clicon_int2str(proc_state_map, pe->pe_state));
if (timerisset(&pe->pe_starttime)){
if (time2str(pe->pe_starttime, timestr, sizeof(timestr)) < 0){
clicon_err(OE_UNIX, errno, "time2str");
goto done;
}
cprintf(cbret, "<starttime xmlns=\"%s\">%s</starttime>", CLIXON_LIB_NS, timestr);
}
if (pe->pe_pid)
cprintf(cbret, "<pid xmlns=\"%s\">%u</pid>", CLIXON_LIB_NS, pe->pe_pid);
cprintf(cbret, "</rpc-reply>");
match++;
break; /* hit break here */
}
if (pe->pe_pid)
cprintf(cbret, "<pid xmlns=\"%s\">%u</pid>", CLIXON_LIB_NS, pe->pe_pid);
cprintf(cbret, "</rpc-reply>");
break; /* hit break here */
}
pe = NEXTQ(process_entry_t *, pe);
} while (pe != _proc_entry_list);
ok:
pe = NEXTQ(process_entry_t *, pe);
} while (pe != _proc_entry_list);
}
if (!match){ /* No match, return error */
if (netconf_unknown_element(cbret, "application", (char*)name, "Process service is not known") < 0)
goto done;
}
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);

View file

@ -451,6 +451,7 @@ clicon_rpc_get_config(clicon_handle h,
cprintf(cb, " username=\"%s\"", username);
cprintf(cb, " xmlns:%s=\"%s\"",
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR);
cprintf(cb, "><get-config><source><%s/></source>", db);
if (xpath && strlen(xpath)){
cprintf(cb, "<%s:filter %s:type=\"xpath\" %s:select=\"%s\"",
@ -541,6 +542,7 @@ clicon_rpc_edit_config(clicon_handle h,
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
if ((username = clicon_username_get(h)) != NULL)
cprintf(cb, " username=\"%s\"", username);
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR);
cprintf(cb, "><edit-config><target><%s/></target>", db);
cprintf(cb, "<default-operation>%s</default-operation>",
xml_operation2str(op));
@ -595,10 +597,11 @@ clicon_rpc_copy_config(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\">"
"<rpc xmlns=\"%s\" username=\"%s\" %s>"
"<copy-config><source><%s/></source><target><%s/></target></copy-config></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
db1, db2)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
@ -641,10 +644,12 @@ clicon_rpc_delete_config(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\">"
"<rpc xmlns=\"%s\" username=\"%s\" %s>"
"<edit-config><target><%s/></target><default-operation>none</default-operation><config operation=\"delete\"/></edit-config></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"", db)) == NULL)
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
db)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -682,10 +687,12 @@ clicon_rpc_lock(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\">"
"<rpc xmlns=\"%s\" username=\"%s\" %s>"
"<lock><target><%s/></target></lock></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"", db)) == NULL)
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
db)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -723,10 +730,12 @@ clicon_rpc_unlock(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\">"
"<rpc xmlns=\"%s\" username=\"%s\" %s>"
"<unlock><target><%s/></target></unlock></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"", db)) == NULL)
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
db)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -805,6 +814,7 @@ clicon_rpc_get(clicon_handle h,
cprintf(cb, " username=\"%s\"", username);
cprintf(cb, " xmlns:%s=\"%s\"",
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR);
cprintf(cb, "><get");
/* Clixon extension, content=all,config, or nonconfig */
if ((int)content != -1)
@ -889,8 +899,9 @@ clicon_rpc_close_session(clicon_handle h)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\" message-id=\"%u\"><close-session/></rpc>",
NETCONF_BASE_NAMESPACE, username?username:"", 42)) == NULL)
"<rpc xmlns=\"%s\" username=\"%s\" %s><close-session/></rpc>",
NETCONF_BASE_NAMESPACE, username?username:"",
NETCONF_MESSAGE_ID_ATTR)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -932,9 +943,11 @@ clicon_rpc_kill_session(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(my_session_id,
"<rpc xmlns=\"%s\" username=\"%s\"><kill-session><session-id>%u</session-id></kill-session></rpc>",
"<rpc xmlns=\"%s\" username=\"%s\" %s><kill-session><session-id>%u</session-id></kill-session></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"", session_id)) == NULL)
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
session_id)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -972,9 +985,11 @@ clicon_rpc_validate(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\"><validate><source><%s/></source></validate></rpc>",
"<rpc xmlns=\"%s\" username=\"%s\" %s><validate><source><%s/></source></validate></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"", db)) == NULL)
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
db)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -1010,9 +1025,10 @@ clicon_rpc_commit(clicon_handle h)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\"><commit/></rpc>",
"<rpc xmlns=\"%s\" username=\"%s\" %s><commit/></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"")) == NULL)
username?username:"",
NETCONF_MESSAGE_ID_ATTR)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -1048,9 +1064,10 @@ clicon_rpc_discard_changes(clicon_handle h)
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\"><discard-changes/></rpc>",
"<rpc xmlns=\"%s\" username=\"%s\" %s><discard-changes/></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"")) == NULL)
username?username:"",
NETCONF_MESSAGE_ID_ATTR)) == NULL)
goto done;
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
@ -1094,12 +1111,13 @@ clicon_rpc_create_subscription(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\"><create-subscription xmlns=\"%s\">"
"<rpc xmlns=\"%s\" username=\"%s\" %s><create-subscription xmlns=\"%s\">"
"<stream>%s</stream>"
"<filter type=\"xpath\" select=\"%s\" />"
"</create-subscription></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
EVENT_RFC5277_NAMESPACE,
stream?stream:"", filter?filter:"")) == NULL)
goto done;
@ -1139,9 +1157,10 @@ clicon_rpc_debug(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\"><debug xmlns=\"%s\"><level>%d</level></debug></rpc>",
"<rpc xmlns=\"%s\" username=\"%s\" %s><debug xmlns=\"%s\"><level>%d</level></debug></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
CLIXON_LIB_NS,
level)) == NULL)
goto done;
@ -1189,9 +1208,10 @@ clicon_rpc_restconf_debug(clicon_handle h,
goto done;
username = clicon_username_get(h);
if ((msg = clicon_msg_encode(session_id,
"<rpc xmlns=\"%s\" username=\"%s\"><edit-config><target><candidate/></target><config><restconf xmlns=\"%s\"><debug>%d</debug></restconf></config></edit-config></rpc>",
"<rpc xmlns=\"%s\" username=\"%s\" %s><edit-config><target><candidate/></target><config><restconf xmlns=\"%s\"><debug>%d</debug></restconf></config></edit-config></rpc>",
NETCONF_BASE_NAMESPACE,
username?username:"",
NETCONF_MESSAGE_ID_ATTR,
CLIXON_RESTCONF_NS,
level)) == NULL)
goto done;

View file

@ -105,7 +105,6 @@ validate_leafref(cxobj *xt,
{
int retval = -1;
yang_stmt *ypath;
yang_stmt *yp;
cxobj **xvec = NULL;
cxobj *x;
int i;
@ -119,19 +118,13 @@ validate_leafref(cxobj *xt,
if ((leafrefbody = xml_body(xt)) == NULL)
goto ok;
if ((ypath = yang_find(ytype, Y_PATH, NULL)) == NULL){
if (netconf_missing_element_xml(xret, "application", yang_argument_get(ytype), "Leafref requires path statement") < 0)
if (xret && netconf_missing_element_xml(xret, "application", yang_argument_get(ytype), "Leafref requires path statement") < 0)
goto done;
goto fail;
}
/* See comment^: If path is defined in typedef or not */
if ((yp = yang_parent_get(ytype)) != NULL &&
yang_keyword_get(yp) == Y_TYPEDEF){
if (xml_nsctx_yang(ys, &nsc) < 0)
goto done;
}
else
if (xml_nsctx_yang(ytype, &nsc) < 0)
goto done;
if (xml_nsctx_node(xt, &nsc) < 0)
goto done;
path = yang_argument_get(ypath);
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, path) < 0)
goto done;
@ -148,7 +141,7 @@ validate_leafref(cxobj *xt,
goto done;
}
cprintf(cberr, "Leafref validation failed: No leaf %s matching path %s", leafrefbody, path);
if (netconf_bad_element_xml(xret, "application", leafrefbody, cbuf_get(cberr)) < 0)
if (xret && netconf_bad_element_xml(xret, "application", leafrefbody, cbuf_get(cberr)) < 0)
goto done;
goto fail;
}
@ -218,7 +211,7 @@ validate_identityref(cxobj *xt,
/* Get idref value. Then see if this value is derived from ytype.
*/
if ((node = xml_body(xt)) == NULL){ /* It may not be empty */
if (netconf_bad_element_xml(xret, "application", xml_name(xt), "Identityref should not be empty") < 0)
if (xret && netconf_bad_element_xml(xret, "application", xml_name(xt), "Identityref should not be empty") < 0)
goto done;
goto fail;
}
@ -226,13 +219,13 @@ validate_identityref(cxobj *xt,
goto done;
/* This is the type's base reference */
if ((ybaseref = yang_find(ytype, Y_BASE, NULL)) == NULL){
if (netconf_missing_element_xml(xret, "application", yang_argument_get(ytype), "Identityref validation failed, no base") < 0)
if (xret && netconf_missing_element_xml(xret, "application", yang_argument_get(ytype), "Identityref validation failed, no base") < 0)
goto done;
goto fail;
}
/* This is the actual base identity */
if ((ybaseid = yang_find_identity(ybaseref, yang_argument_get(ybaseref))) == NULL){
if (netconf_missing_element_xml(xret, "application", yang_argument_get(ybaseref), "Identityref validation failed, no base identity") < 0)
if (xret && netconf_missing_element_xml(xret, "application", yang_argument_get(ybaseref), "Identityref validation failed, no base identity") < 0)
goto done;
goto fail;
}
@ -261,7 +254,7 @@ validate_identityref(cxobj *xt,
if (cvec_find(idrefvec, idref) == NULL){
cprintf(cberr, "Identityref validation failed, %s not derived from %s",
node, yang_argument_get(ybaseid));
if (netconf_operation_failed_xml(xret, "application", cbuf_get(cberr)) < 0)
if (xret && netconf_operation_failed_xml(xret, "application", cbuf_get(cberr)) < 0)
goto done;
goto fail;
}
@ -344,7 +337,7 @@ xml_yang_validate_rpc(clicon_handle h,
goto done;
/* Only accept resolved NETCONF base namespace */
if (namespace == NULL || strcmp(namespace, NETCONF_BASE_NAMESPACE) != 0){
if (netconf_unknown_namespace_xml(xret, "protocol", rpcprefix, "No appropriate namespace associated with prefix")< 0)
if (xret && netconf_unknown_namespace_xml(xret, "protocol", rpcprefix, "No appropriate namespace associated with prefix")< 0)
goto done;
goto fail;
}
@ -352,7 +345,7 @@ xml_yang_validate_rpc(clicon_handle h,
/* xn is name of rpc, ie <rcp><xn/></rpc> */
while ((xn = xml_child_each(xrpc, xn, CX_ELMNT)) != NULL) {
if ((yn = xml_spec(xn)) == NULL){
if (netconf_unknown_element_xml(xret, "application", xml_name(xn), NULL) < 0)
if (xret && netconf_unknown_element_xml(xret, "application", xml_name(xn), NULL) < 0)
goto done;
goto fail;
}
@ -441,7 +434,7 @@ check_choice(cxobj *xt,
continue; /* not choice */
break;
}
if (netconf_bad_element_xml(xret, "application", xml_name(x), "Element in choice statement already exists") < 0)
if (xret && netconf_bad_element_xml(xret, "application", xml_name(x), "Element in choice statement already exists") < 0)
goto done;
goto fail;
} /* while */
@ -494,7 +487,7 @@ check_list_key(cxobj *xt,
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
keyname = cv_string_get(cvi);
if (xml_find_type(xt, NULL, keyname, CX_ELMNT) == NULL){
if (netconf_missing_element_xml(xret, "application", keyname, "Mandatory key") < 0)
if (xret && netconf_missing_element_xml(xret, "application", keyname, "Mandatory key") < 0)
goto done;
goto fail;
}
@ -564,7 +557,7 @@ check_mandatory(cxobj *xt,
goto done;
}
cprintf(cb, "Mandatory variable of %s in module %s", xml_name(xt), yang_argument_get(ys_module(yc)));
if (netconf_missing_element_xml(xret, "application", yang_argument_get(yc), cbuf_get(cb)) < 0)
if (xret && netconf_missing_element_xml(xret, "application", yang_argument_get(yc), cbuf_get(cb)) < 0)
goto done;
goto fail;
}
@ -581,7 +574,7 @@ check_mandatory(cxobj *xt,
if (x == NULL){
/* @see RFC7950: 15.6 Error Message for Data That Violates
* a Mandatory "choice" Statement */
if (netconf_data_missing_xml(xret, yang_argument_get(yc), NULL) < 0)
if (xret && netconf_data_missing_xml(xret, yang_argument_get(yc), NULL) < 0)
goto done;
goto fail;
}
@ -714,7 +707,7 @@ check_unique_list(cxobj *x,
if (cvi==NULL){
/* Last element (i) is newly inserted, see if it is already there */
if (check_insert_duplicate(vec, i, vlen, sorted) < 0){
if (netconf_data_not_unique_xml(xret, x, cvk) < 0)
if (xret && netconf_data_not_unique_xml(xret, x, cvk) < 0)
goto done;
goto fail;
}
@ -758,7 +751,7 @@ check_min_max(cxobj *xp,
if ((ymin = yang_find(y, Y_MIN_ELEMENTS, NULL)) != NULL){
cv = yang_cv_get(ymin);
if (nr < cv_uint32_get(cv)){
if (netconf_minmax_elements_xml(xret, xp, yang_argument_get(y), 0) < 0)
if (xret && netconf_minmax_elements_xml(xret, xp, yang_argument_get(y), 0) < 0)
goto done;
goto fail;
}
@ -767,7 +760,7 @@ check_min_max(cxobj *xp,
cv = yang_cv_get(ymax);
if (cv_uint32_get(cv) > 0 && /* 0 means unbounded */
nr > cv_uint32_get(cv)){
if (netconf_minmax_elements_xml(xret, xp, yang_argument_get(y), 1) < 0)
if (xret && netconf_minmax_elements_xml(xret, xp, yang_argument_get(y), 1) < 0)
goto done;
goto fail;
}
@ -858,7 +851,7 @@ check_list_unique_minmax(cxobj *xt,
/* Only lists and leaf-lists are allowed to be many
* This checks duplicate container and leafs
*/
if (netconf_minmax_elements_xml(xret, xt, xml_name(x), 1) < 0)
if (xret && netconf_minmax_elements_xml(xret, xt, xml_name(x), 1) < 0)
goto done;
goto fail;
}
@ -1025,14 +1018,14 @@ xml_yang_validate_add(clicon_handle h,
* are considered as "" */
cvtype = cv_type_get(cv);
if (cv_isint(cvtype) || cvtype == CGV_BOOL || cvtype == CGV_DEC64){
if (netconf_bad_element_xml(xret, "application", yang_argument_get(yt), "Invalid NULL value") < 0)
if (xret && netconf_bad_element_xml(xret, "application", yang_argument_get(yt), "Invalid NULL value") < 0)
goto done;
goto fail;
}
}
else{
if (cv_parse1(body, cv, &reason) != 1){
if (netconf_bad_element_xml(xret, "application", yang_argument_get(yt), reason) < 0)
if (xret && netconf_bad_element_xml(xret, "application", yang_argument_get(yt), reason) < 0)
goto done;
goto fail;
}
@ -1040,7 +1033,7 @@ xml_yang_validate_add(clicon_handle h,
if ((ret = ys_cv_validate(h, cv, yt, NULL, &reason)) < 0)
goto done;
if (ret == 0){
if (netconf_bad_element_xml(xret, "application", yang_argument_get(yt), reason) < 0)
if (xret && netconf_bad_element_xml(xret, "application", yang_argument_get(yt), reason) < 0)
goto done;
goto fail;
}
@ -1165,7 +1158,7 @@ xml_yang_validate_all(clicon_handle h,
goto done;
if (ns)
cprintf(cb, " in namespace: %s", ns);
if (netconf_unknown_element_xml(xret, "application", xml_name(xt), cbuf_get(cb)) < 0)
if (xret && netconf_unknown_element_xml(xret, "application", xml_name(xt), cbuf_get(cb)) < 0)
goto done;
goto fail;
}
@ -1224,7 +1217,7 @@ xml_yang_validate_all(clicon_handle h,
}
cprintf(cb, "Failed MUST xpath '%s' of '%s' in module %s",
xpath, xml_name(xt), yang_argument_get(ys_module(ys)));
if (netconf_operation_failed_xml(xret, "application",
if (xret && netconf_operation_failed_xml(xret, "application",
ye?yang_argument_get(ye):cbuf_get(cb)) < 0)
goto done;
goto fail;
@ -1254,7 +1247,7 @@ xml_yang_validate_all(clicon_handle h,
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",
if (xret && netconf_operation_failed_xml(xret, "application",
cbuf_get(cb)) < 0)
goto done;
goto fail;
@ -1276,7 +1269,7 @@ xml_yang_validate_all(clicon_handle h,
xpath,
xml_name(xt),
yang_argument_get(ys_module(ys)));
if (netconf_operation_failed_xml(xret, "application",
if (xret && netconf_operation_failed_xml(xret, "application",
cbuf_get(cb)) < 0)
goto done;
goto fail;

View file

@ -83,6 +83,7 @@
* Local variables
*/
static int _yang_unknown_anydata = 0;
static int _netconf_message_id_optional = 0;
/*! Kludge to equate unknown XML with anydata
* The problem with this is that its global and should be bound to a handle
@ -94,6 +95,16 @@ xml_bind_yang_unknown_anydata(int val)
return 0;
}
/*! Kludge to set message_id_optional
* The problem with this is that its global and should be bound to a handle
*/
int
xml_bind_netconf_message_id_optional(int val)
{
_netconf_message_id_optional = val;
return 0;
}
/*! After yang binding, bodies of containers and lists are stripped from XML bodies
* May apply to other nodes?
*/
@ -510,16 +521,16 @@ xml_bind_yang0(cxobj *xt,
* @retval -1 Error
* The
* @code
* if (xml_bind_yang_rpc(h, x, NULL) < 0)
* if (xml_bind_yang_rpc(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)
xml_bind_yang_rpc(cxobj *xrpc,
yang_stmt *yspec,
cxobj **xerr)
{
int retval = -1;
yang_stmt *yrpc = NULL; /* yang node */
@ -576,6 +587,17 @@ xml_bind_yang_rpc(cxobj *xrpc,
goto done;
goto fail;
}
if (_netconf_message_id_optional == 0){
/* RFC 6241 4.1:
* The <rpc> element has a mandatory attribute "message-id"
*/
if (xml_find_type(xrpc, NULL, "message-id", CX_ATTR) == NULL){
if (xerr &&
netconf_missing_attribute_xml(xerr, "rpc", "message-id", "Incoming rpc") < 0)
goto done;
goto fail;
}
}
x = NULL;
while ((x = xml_child_each(xrpc, x, CX_ELMNT)) != NULL) {
rpcname = xml_name(x);

View file

@ -239,7 +239,6 @@ xpath_tree_print(FILE *f,
* @param[in] xs XPATH tree
* @param[out] xpath XPath string as CLIgen buf
* @see xpath_tree_print
* @note XXX Not complete
*/
int
xpath_tree2cbuf(xpath_tree *xs,
@ -247,6 +246,7 @@ xpath_tree2cbuf(xpath_tree *xs,
{
int retval = -1;
/* 1. Before first child */
switch (xs->xs_type){
case XP_ABSPATH:
if (xs->xs_int == A_DESCENDANT_OR_SELF)
@ -283,16 +283,28 @@ xpath_tree2cbuf(xpath_tree *xs,
default:
break;
}
/* 2. First child */
if (xs->xs_c0 && xpath_tree2cbuf(xs->xs_c0, xcb) < 0)
goto done;
/* 3. Between first and second child */
switch (xs->xs_type){
case XP_AND: /* and or */
case XP_ADD: /* div mod + * - */
case XP_RELEX: /* !=, >= <= < > = */
case XP_UNION:
if (xs->xs_c1)
cprintf(xcb, " %s ", clicon_int2str(xpopmap, xs->xs_int));
break;
case XP_RELEX: /* !=, >= <= < > = */
case XP_UNION: /* | */
if (xs->xs_c1)
cprintf(xcb, "%s", clicon_int2str(xpopmap, xs->xs_int));
break;
case XP_PATHEXPR:
/* [19] PathExpr ::= | FilterExpr '/' RelativeLocationPath
| FilterExpr '//' RelativeLocationPath
*/
if (xs->xs_s0)
cprintf(xcb, "%s", xs->xs_s0);
break;
case XP_RELLOCPATH:
if (xs->xs_c1){
if (xs->xs_int == A_DESCENDANT_OR_SELF)
@ -311,8 +323,10 @@ xpath_tree2cbuf(xpath_tree *xs,
default:
break;
}
/* 4. Second child */
if (xs->xs_c1 && xpath_tree2cbuf(xs->xs_c1, xcb) < 0)
goto done;
/* 5. After second child */
switch (xs->xs_type){
case XP_PRED:
if (xs->xs_c1)
@ -915,6 +929,8 @@ xpath_vec_bool(cxobj *xcur,
return retval;
}
/*!
*/
static int
traverse_canonical(xpath_tree *xs,
yang_stmt *yspec,

View file

@ -163,7 +163,7 @@ xpath_parse_exit(clixon_xpath_yacc *xpy)
* @param[in] type XPATH tree node type
* @param[in] i0 step-> axis_type
* @param[in] numstr original string xs_double: numeric value
* @param[in] s0 String 0 set if XP_PRIME_STR, XP_PRIME_FN, XP_NODE[_FN] prefix
* @param[in] s0 String 0 set if XP_PRIME_STR, XP_PRIME_FN, XP_NODE[_FN] PATHEXPRE prefix
* @param[in] s1 String 1 set if XP_NODE NAME
* @param[in] c0 Child 0
* @param[in] c1 Child 1
@ -393,8 +393,8 @@ unionexpr : unionexpr '|' pathexpr { $$=xp_new(XP_UNION,XO_UNION,NULL,NULL,NUL
pathexpr : locationpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(3,"pathexpr-> locationpath"); }
| filterexpr { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(3,"pathexpr-> filterexpr"); }
| filterexpr '/' rellocpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,NULL,NULL,$1, $3);clicon_debug(3,"pathexpr-> filterexpr / rellocpath"); }
/* Filterexpr // relativelocationpath */
| filterexpr '/' rellocpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,strdup("/"),NULL,$1, $3);clicon_debug(3,"pathexpr-> filterexpr / rellocpath"); }
| filterexpr DOUBLESLASH rellocpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,strdup("//"),NULL,$1, $3);clicon_debug(3,"pathexpr-> filterexpr // rellocpath"); }
;
filterexpr : primaryexpr { $$=xp_new(XP_FILTEREXPR,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(3,"filterexpr-> primaryexpr"); }

View file

@ -256,6 +256,22 @@ yang_cv_get(yang_stmt *ys)
return ys->ys_cv;
}
/*! Set yang statement CLIgen variable
* @param[in] ys Yang statement node
* @param[in] cv cligen variable
* @note: Frees on replace, not if cv is NULL. This is for some ys_cp/ys_dup cases, which means
* you need to free it explicitly to set it to NULL proper.
*/
int
yang_cv_set(yang_stmt *ys,
cg_var *cv)
{
if (cv != NULL && ys->ys_cv != NULL)
cv_free(ys->ys_cv);
ys->ys_cv = cv;
return 0;
}
/*! Get yang statement CLIgen variable vector
* @param[in] ys Yang statement node
*/
@ -456,13 +472,15 @@ int
ys_free1(yang_stmt *ys,
int self)
{
cg_var *cv;
if (ys->ys_argument){
free(ys->ys_argument);
ys->ys_argument = NULL;
}
if (ys->ys_cv){
cv_free(ys->ys_cv);
ys->ys_cv = NULL;
if ((cv = yang_cv_get(ys)) != NULL){
yang_cv_set(ys, NULL); /* only frees on replace */
cv_free(cv);
}
if (ys->ys_cvec){
cvec_free(ys->ys_cvec);
@ -601,6 +619,8 @@ ys_cp(yang_stmt *ynew,
int i;
yang_stmt *ycn; /* new child */
yang_stmt *yco; /* old child */
cg_var *cvn;
cg_var *cvo;
memcpy(ynew, yold, sizeof(*yold));
ynew->ys_parent = NULL;
@ -614,11 +634,14 @@ ys_cp(yang_stmt *ynew,
clicon_err(OE_YANG, errno, "strdup");
goto done;
}
if (yold->ys_cv)
if ((ynew->ys_cv = cv_dup(yold->ys_cv)) == NULL){
yang_cv_set(ynew, NULL);
if ((cvo = yang_cv_get(yold)) != NULL){
if ((cvn = cv_dup(cvo)) == NULL){
clicon_err(OE_YANG, errno, "cv_dup");
goto done;
}
yang_cv_set(ynew, cvn);
}
if (yold->ys_cvec)
if ((ynew->ys_cvec = cvec_dup(yold->ys_cvec)) == NULL){
clicon_err(OE_YANG, errno, "cvec_dup");
@ -1414,6 +1437,7 @@ ys_real_module(yang_stmt *ys,
{
int retval = -1;
yang_stmt *ym = NULL;
yang_stmt *ysubm;
yang_stmt *yb;
char *name;
yang_stmt *yspec;
@ -1433,8 +1457,12 @@ ys_real_module(yang_stmt *ys,
clicon_err(OE_YANG, ENOENT, "Belongs-to statement of submodule %s has no argument", yang_argument_get(ym)); /* shouldnt happen */
goto done;
}
if ((ym = yang_find_module_by_name(yspec, name)) == NULL)
if ((ysubm = yang_find_module_by_name(yspec, name)) == NULL){
clicon_err(OE_YANG, ENOENT, "submodule %s references non-existent module %s in its belongs-to statement",
yang_argument_get(ym), name);
goto done;
}
ym = ysubm;
}
}
*ymod = ym;
@ -1447,7 +1475,8 @@ ys_real_module(yang_stmt *ys,
* @param[in] ys Any yang statement in a yang tree
* @retval yspec The top yang specification
* @see ys_module
* @see yang_augment_node where shortcut is set
* @see yang_augment_node where shortcut is set for augment
* @see yang_myroot for first node under (sub)module
*/
yang_stmt *
ys_spec(yang_stmt *ys)
@ -1765,8 +1794,7 @@ ys_populate_leaf(clicon_handle h,
yparent = ys->ys_parent; /* Find parent: list/container */
/* 1. Find type specification and set cv type accordingly */
if (yang_type_get(ys, &origtype, &yrestype, &options, NULL, NULL, NULL, &fraction_digits)
< 0)
if (yang_type_get(ys, &origtype, &yrestype, &options, NULL, NULL, NULL, &fraction_digits) < 0)
goto done;
restype = yrestype?yrestype->ys_argument:NULL;
if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0) /* This handles non-resolved also */
@ -1823,7 +1851,7 @@ ys_populate_leaf(clicon_handle h,
if ((ret = yang_key_match(yparent, ys->ys_argument)) < 0)
goto done;
}
ys->ys_cv = cv;
yang_cv_set(ys, cv);
retval = 0;
done:
if (origtype)
@ -2236,7 +2264,7 @@ ys_populate_feature(clicon_handle h,
cv_bool_set(cv, found);
if (found)
clicon_debug(1, "%s %s:%s", __FUNCTION__, module, feature);
ys->ys_cv = cv;
yang_cv_set(ys, cv);
ok:
retval = 0;
done:
@ -2490,7 +2518,7 @@ yang_if_feature(clicon_handle h,
yang_stmt *yfeat; /* feature yang node */
int opand = -1; /* -1:not set, 0:or, 1:and */
int enabled = 0;
cg_var *cv;
if ((vec = clicon_strsep(ys->ys_argument, " \t\r\n", &nvec)) == NULL)
goto done;
/* Two steps: first detect operators
@ -2579,7 +2607,8 @@ yang_if_feature(clicon_handle h,
/* Check if this feature is enabled or not
* Continue loop to catch unbound features and make verdict at end
*/
if (yfeat->ys_cv == NULL || !cv_bool_get(yfeat->ys_cv)){ /* disabled */
cv = yang_cv_get(yfeat);
if (cv == NULL || !cv_bool_get(cv)){ /* disabled */
/* if AND then this is permanently disabled */
if (opand && enabled)
enabled = 0;
@ -3019,14 +3048,15 @@ int
yang_mandatory(yang_stmt *ys)
{
yang_stmt *ym;
cg_var *cv;
/* 1) A leaf, choice, anydata, or anyxml node with a "mandatory"
* statement with the value "true". */
if (ys->ys_keyword == Y_LEAF || ys->ys_keyword == Y_CHOICE ||
ys->ys_keyword == Y_ANYDATA || ys->ys_keyword == Y_ANYXML){
if ((ym = yang_find(ys, Y_MANDATORY, NULL)) != NULL){
if (ym->ys_cv != NULL) /* shouldnt happen */
return cv_bool_get(ym->ys_cv);
if ((cv = yang_cv_get(ym)) != NULL) /* shouldnt happen */
return cv_bool_get(cv);
}
}
#if 0 /* See note above */
@ -3066,9 +3096,9 @@ yang_config(yang_stmt *ys)
yang_stmt *ym;
if ((ym = yang_find(ys, Y_CONFIG, NULL)) != NULL){
if (ym->ys_cv == NULL) /* shouldnt happen */
if (yang_cv_get(ym) == NULL) /* shouldnt happen */
return 1;
return cv_bool_get(ym->ys_cv);
return cv_bool_get(yang_cv_get(ym));
}
return 1;
}

View file

@ -33,6 +33,7 @@
***** END LICENSE BLOCK *****
* Yang cardinality functions according to RFC 7950
* That is, how many children any yang node has
*/
#ifdef HAVE_CONFIG_H
@ -69,28 +70,36 @@
/*
* Types
*/
/* Encode cardinality according to RFC 7950
/* Encode cardinality and ordering according to RFC 7950
* Example:
* 7.20.3.1. The deviation's Substatements
*
* +--------------+----------+-------------+
* | substatement | section | cardinality |
* +--------------+----------+-------------+
* | description | 7.21.3 | 0..1 |
* | deviate | 7.20.3.2 | 1..n |
* | reference | 7.21.4 | 0..1 |
* +--------------+----------+-------------+
* 7.1.1. The module's Substatements (subset)
* +--------------+----------+-------------+----------+
* | substatement | section | cardinality | ordering |
* +--------------+----------+-------------+----------+
* | contact | 7.1.8 | 0..1 | 2 |
* | import | 7.1.5 | 0..n | 1 |
* | include | 7.1.6 | 0..n | 1 |
* | namespace | 7.1.3 | 1 | 0 |
* | organization | 7.1.7 | 0..1 | 2 |
* | yang-version | 7.1.2 | 1 | 0 |
* +--------------+----------+-------------+----------+
* The cardinalities are (and how many time they occur)
* 0..1 149 See ycardmap_01
* 1..n, 1
* 0..n 176 (no restrictions)
* 1 10
*
* Ordering means in which order the statements may occur. If same ordering the may occur
* in any order. In the example above, namespace and yang-version occurs before
* import and include which in turn preceedes contact and organization
* Note: order is only relevant for modules and sub-modules
*/
struct ycard{
enum rfc_6020 yc_parent;
enum rfc_6020 yc_child;
int yc_min;
int yc_max;
int yc_order;
};
/*
@ -107,341 +116,341 @@ struct ycard{
*/
#define NMAX 1000000 /* Just a large number */
static const struct ycard yclist[] = {
{Y_ACTION, Y_DESCRIPTION, 0, 1},
{Y_ACTION, Y_GROUPING, 0, NMAX},
{Y_ACTION, Y_IF_FEATURE, 0, NMAX},
{Y_ACTION, Y_INPUT, 0, 1},
{Y_ACTION, Y_OUTPUT, 0, 1},
{Y_ACTION, Y_REFERENCE, 0, 1},
{Y_ACTION, Y_STATUS, 0, 1},
{Y_ACTION, Y_TYPEDEF, 0, NMAX},
{Y_ANYDATA, Y_CONFIG, 0, 1},
{Y_ANYDATA, Y_DESCRIPTION, 0, 1},
{Y_ANYDATA, Y_IF_FEATURE, 0, NMAX},
{Y_ANYDATA, Y_MANDATORY, 0, 1},
{Y_ANYDATA, Y_MUST, 0, NMAX},
{Y_ANYDATA, Y_REFERENCE, 0, 1},
{Y_ANYDATA, Y_STATUS, 0, 1},
{Y_ANYDATA, Y_WHEN, 0, 1},
{Y_ANYXML, Y_CONFIG, 0, 1},
{Y_ANYXML, Y_DESCRIPTION, 0, 1},
{Y_ANYXML, Y_IF_FEATURE, 0, NMAX},
{Y_ANYXML, Y_MANDATORY, 0, 1},
{Y_ANYXML, Y_MUST, 0, NMAX},
{Y_ANYXML, Y_REFERENCE, 0, 1},
{Y_ANYXML, Y_STATUS, 0, 1},
{Y_ANYXML, Y_WHEN, 0, 1},
{Y_ARGUMENT, Y_YIN_ELEMENT, 0, 1},
{Y_AUGMENT, Y_ACTION, 0, NMAX},
{Y_AUGMENT, Y_ANYDATA, 0, NMAX},
{Y_AUGMENT, Y_ANYXML, 0, NMAX},
{Y_AUGMENT, Y_CASE, 0, NMAX},
{Y_AUGMENT, Y_CHOICE, 0, NMAX},
{Y_AUGMENT, Y_CONTAINER, 0, NMAX},
{Y_AUGMENT, Y_DESCRIPTION, 0, 1},
{Y_AUGMENT, Y_IF_FEATURE, 0, NMAX},
{Y_AUGMENT, Y_LEAF, 0, NMAX},
{Y_AUGMENT, Y_LEAF_LIST, 0, NMAX},
{Y_AUGMENT, Y_LIST, 0, NMAX},
{Y_AUGMENT, Y_NOTIFICATION, 0, NMAX},
{Y_AUGMENT, Y_REFERENCE, 0, 1},
{Y_AUGMENT, Y_STATUS, 0, 1},
{Y_AUGMENT, Y_USES, 0, NMAX},
{Y_AUGMENT, Y_WHEN, 0, 1},
{Y_BELONGS_TO, Y_PREFIX, 1, 1},
{Y_BIT, Y_DESCRIPTION, 0, 1},
{Y_BIT, Y_IF_FEATURE, 0, NMAX},
{Y_BIT, Y_POSITION, 0, 1},
{Y_BIT, Y_REFERENCE, 0, 1},
{Y_BIT, Y_STATUS, 0, 1},
{Y_CASE, Y_ANYDATA, 0, NMAX},
{Y_CASE, Y_ANYXML, 0, NMAX},
{Y_CASE, Y_CHOICE, 0, NMAX},
{Y_CASE, Y_CONTAINER, 0, NMAX},
{Y_CASE, Y_DESCRIPTION, 0, 1},
{Y_CASE, Y_IF_FEATURE, 0, NMAX},
{Y_CASE, Y_LEAF, 0, NMAX},
{Y_CASE, Y_LEAF_LIST, 0, NMAX},
{Y_CASE, Y_LIST, 0, NMAX},
{Y_CASE, Y_REFERENCE, 0, 1},
{Y_CASE, Y_STATUS, 0, 1},
{Y_CASE, Y_USES, 0, NMAX},
{Y_CASE, Y_WHEN, 0, 1},
{Y_CHOICE, Y_ANYXML, 0, NMAX},
{Y_CHOICE, Y_CASE, 0, NMAX},
{Y_CHOICE, Y_CHOICE, 0, NMAX},
{Y_CHOICE, Y_CONFIG, 0, 1},
{Y_CHOICE, Y_CONTAINER, 0, NMAX},
{Y_CHOICE, Y_DEFAULT, 0, 1},
{Y_CHOICE, Y_DESCRIPTION, 0, 1},
{Y_CHOICE, Y_IF_FEATURE, 0, NMAX},
{Y_CHOICE, Y_LEAF, 0, NMAX},
{Y_CHOICE, Y_LEAF_LIST, 0, NMAX},
{Y_CHOICE, Y_LIST, 0, NMAX},
{Y_CHOICE, Y_MANDATORY, 0, 1},
{Y_CHOICE, Y_REFERENCE, 0, 1},
{Y_CHOICE, Y_STATUS, 0, 1},
{Y_CHOICE, Y_WHEN, 0, 1},
{Y_CHOICE, Y_ANYDATA, 0, NMAX},
{Y_CONTAINER, Y_ACTION, 0, NMAX},
{Y_CONTAINER, Y_ANYDATA, 0, NMAX},
{Y_CONTAINER, Y_ANYXML, 0, NMAX},
{Y_CONTAINER, Y_CHOICE, 0, NMAX},
{Y_CONTAINER, Y_CONFIG, 0, 1},
{Y_CONTAINER, Y_CONTAINER, 0, NMAX},
{Y_CONTAINER, Y_DESCRIPTION, 0, 1},
{Y_CONTAINER, Y_GROUPING, 0, NMAX},
{Y_CONTAINER, Y_IF_FEATURE, 0, NMAX},
{Y_CONTAINER, Y_LEAF, 0, NMAX},
{Y_CONTAINER, Y_LEAF_LIST, 0, NMAX},
{Y_CONTAINER, Y_LIST, 0, NMAX},
{Y_CONTAINER, Y_MUST, 0, NMAX},
{Y_CONTAINER, Y_NOTIFICATION, 0, NMAX},
{Y_CONTAINER, Y_PRESENCE, 0, 1},
{Y_CONTAINER, Y_REFERENCE, 0, 1},
{Y_CONTAINER, Y_STATUS, 0, 1},
{Y_CONTAINER, Y_TYPEDEF, 0, NMAX},
{Y_CONTAINER, Y_USES, 0, NMAX},
{Y_CONTAINER, Y_WHEN, 0, 1},
{Y_DEVIATE, Y_CONFIG, 0, 1},
{Y_DEVIATE, Y_DEFAULT, 0, NMAX},
{Y_DEVIATE, Y_MANDATORY, 0, 1},
{Y_DEVIATE, Y_MAX_ELEMENTS, 0, 1},
{Y_DEVIATE, Y_MIN_ELEMENTS, 0, 1},
{Y_DEVIATE, Y_MUST, 0, NMAX},
{Y_DEVIATE, Y_TYPE, 0, 1},
{Y_DEVIATE, Y_UNIQUE, 0, NMAX},
{Y_DEVIATE, Y_UNITS, 0, 1},
{Y_DEVIATION, Y_DESCRIPTION, 0, 1},
{Y_DEVIATION, Y_DEVIATE, 1, NMAX},
{Y_DEVIATION, Y_REFERENCE, 0, 1},
{Y_ENUM, Y_DESCRIPTION, 0, 1},
{Y_ENUM, Y_IF_FEATURE, 0, NMAX},
{Y_ENUM, Y_REFERENCE, 0, 1},
{Y_ENUM, Y_STATUS, 0, 1},
{Y_ENUM, Y_VALUE, 0, 1},
{Y_EXTENSION, Y_ARGUMENT, 0, 1},
{Y_EXTENSION, Y_DESCRIPTION, 0, 1},
{Y_EXTENSION, Y_REFERENCE, 0, 1},
{Y_EXTENSION, Y_STATUS, 0, 1},
{Y_FEATURE, Y_DESCRIPTION, 0, 1},
{Y_FEATURE, Y_IF_FEATURE, 0, NMAX},
{Y_FEATURE, Y_REFERENCE, 0, 1},
{Y_FEATURE, Y_STATUS, 0, 1},
{Y_GROUPING, Y_ACTION, 0, NMAX},
{Y_GROUPING, Y_ANYDATA, 0, NMAX},
{Y_GROUPING, Y_ANYXML, 0, NMAX},
{Y_GROUPING, Y_CHOICE, 0, NMAX},
{Y_GROUPING, Y_CONTAINER, 0, NMAX},
{Y_GROUPING, Y_DESCRIPTION, 0, 1},
{Y_GROUPING, Y_GROUPING, 0, NMAX},
{Y_GROUPING, Y_LEAF, 0, NMAX},
{Y_GROUPING, Y_LEAF_LIST, 0, NMAX},
{Y_GROUPING, Y_LIST, 0, NMAX},
{Y_GROUPING, Y_NOTIFICATION, 0, NMAX},
{Y_GROUPING, Y_REFERENCE, 0, 1},
{Y_GROUPING, Y_STATUS, 0, 1},
{Y_GROUPING, Y_TYPEDEF, 0, NMAX},
{Y_GROUPING, Y_USES, 0, NMAX},
{Y_IDENTITY, Y_BASE, 0, NMAX},
{Y_IDENTITY, Y_DESCRIPTION, 0, 1},
{Y_IDENTITY, Y_IF_FEATURE, 0, NMAX},
{Y_IDENTITY, Y_REFERENCE, 0, 1},
{Y_IDENTITY, Y_STATUS, 0, 1},
{Y_IMPORT, Y_DESCRIPTION, 0, 1},
{Y_IMPORT, Y_PREFIX, 1, 1},
{Y_IMPORT, Y_REFERENCE, 0, 1},
{Y_IMPORT, Y_REVISION_DATE,0, 1},
{Y_INCLUDE, Y_DESCRIPTION, 0, 1},
{Y_INCLUDE, Y_REFERENCE, 0, 1},
{Y_INCLUDE, Y_REVISION_DATE,0, 1},
{Y_INPUT, Y_ANYDATA, 0, NMAX},
{Y_INPUT, Y_ANYXML, 0, NMAX},
{Y_INPUT, Y_CHOICE, 0, NMAX},
{Y_INPUT, Y_CONTAINER, 0, NMAX},
{Y_INPUT, Y_GROUPING, 0, NMAX},
{Y_INPUT, Y_LEAF, 0, NMAX},
{Y_INPUT, Y_LEAF_LIST, 0, NMAX},
{Y_INPUT, Y_LIST, 0, NMAX},
{Y_INPUT, Y_MUST, 0, NMAX},
{Y_INPUT, Y_TYPEDEF, 0, NMAX},
{Y_INPUT, Y_USES, 0, NMAX},
{Y_LEAF, Y_CONFIG, 0, 1},
{Y_LEAF, Y_DEFAULT, 0, 1},
{Y_LEAF, Y_DESCRIPTION, 0, 1},
{Y_LEAF, Y_IF_FEATURE, 0, NMAX},
{Y_LEAF, Y_MANDATORY, 0, 1},
{Y_LEAF, Y_MUST, 0, NMAX},
{Y_LEAF, Y_REFERENCE, 0, 1},
{Y_LEAF, Y_STATUS, 0, 1},
{Y_LEAF, Y_TYPE, 1, 1},
{Y_LEAF, Y_UNITS, 0, 1},
{Y_LEAF, Y_WHEN, 0, 1},
{Y_LEAF_LIST, Y_CONFIG, 0, 1},
{Y_LEAF_LIST, Y_DEFAULT, 0, NMAX},
{Y_LEAF_LIST, Y_DESCRIPTION, 0, 1},
{Y_LEAF_LIST, Y_IF_FEATURE, 0, NMAX},
{Y_LEAF_LIST, Y_MAX_ELEMENTS, 0, 1},
{Y_LEAF_LIST, Y_MIN_ELEMENTS, 0, 1},
{Y_LEAF_LIST, Y_MUST, 0, NMAX},
{Y_LEAF_LIST, Y_ORDERED_BY, 0, 1},
{Y_LEAF_LIST, Y_REFERENCE, 0, 1},
{Y_LEAF_LIST, Y_STATUS, 0, 1},
{Y_LEAF_LIST, Y_TYPE, 1, 1},
{Y_LEAF_LIST, Y_UNITS, 0, 1},
{Y_LEAF_LIST, Y_WHEN, 0, 1},
{Y_LENGTH, Y_DESCRIPTION, 0, 1},
{Y_LENGTH, Y_ERROR_APP_TAG, 0, 1},
{Y_LENGTH, Y_ERROR_MESSAGE, 0, 1},
{Y_LENGTH, Y_REFERENCE, 0, 1},
{Y_LIST, Y_ACTION, 0, NMAX},
{Y_LIST, Y_ANYDATA, 0, NMAX},
{Y_LIST, Y_ANYXML, 0, NMAX},
{Y_LIST, Y_CHOICE, 0, NMAX},
{Y_LIST, Y_CONFIG, 0, 1},
{Y_LIST, Y_CONTAINER, 0, NMAX},
{Y_LIST, Y_DESCRIPTION, 0, 1},
{Y_LIST, Y_GROUPING, 0, NMAX},
{Y_LIST, Y_IF_FEATURE, 0, NMAX},
{Y_LIST, Y_KEY, 0, 1},
{Y_LIST, Y_LEAF, 0, NMAX},
{Y_LIST, Y_LEAF_LIST, 0, NMAX},
{Y_LIST, Y_LIST, 0, NMAX},
{Y_LIST, Y_MAX_ELEMENTS, 0, 1},
{Y_LIST, Y_MIN_ELEMENTS, 0, 1},
{Y_LIST, Y_MUST, 0, NMAX},
{Y_LIST, Y_NOTIFICATION, 0, NMAX},
{Y_LIST, Y_ORDERED_BY, 0, 1},
{Y_LIST, Y_REFERENCE, 0, 1},
{Y_LIST, Y_STATUS, 0, 1},
{Y_LIST, Y_TYPEDEF, 0, NMAX},
{Y_LIST, Y_UNIQUE, 0, NMAX},
{Y_LIST, Y_USES, 0, NMAX},
{Y_LIST, Y_WHEN, 0,1},
{Y_MODULE, Y_ANYDATA, 0, NMAX},
{Y_MODULE, Y_ANYXML, 0, NMAX},
{Y_MODULE, Y_AUGMENT, 0, NMAX},
{Y_MODULE, Y_CHOICE, 0, NMAX},
{Y_MODULE, Y_CONTACT, 0, 1},
{Y_MODULE, Y_CONTAINER, 0, NMAX},
{Y_MODULE, Y_DESCRIPTION, 0, 1},
{Y_MODULE, Y_DEVIATION, 0, NMAX},
{Y_MODULE, Y_EXTENSION, 0, NMAX},
{Y_MODULE, Y_FEATURE, 0, NMAX},
{Y_MODULE, Y_GROUPING, 0, NMAX},
{Y_MODULE, Y_IDENTITY, 0, NMAX},
{Y_MODULE, Y_IMPORT, 0, NMAX},
{Y_MODULE, Y_INCLUDE, 0, NMAX},
{Y_MODULE, Y_LEAF, 0, NMAX},
{Y_MODULE, Y_LEAF_LIST, 0, NMAX},
{Y_MODULE, Y_LIST, 0, NMAX},
{Y_MODULE, Y_NAMESPACE, 1, 1},
{Y_MODULE, Y_NOTIFICATION, 0, NMAX},
{Y_MODULE, Y_ORGANIZATION, 0, 1},
{Y_MODULE, Y_PREFIX, 1, 1},
{Y_MODULE, Y_REFERENCE, 0, 1},
{Y_MODULE, Y_REVISION, 0, NMAX},
{Y_MODULE, Y_RPC, 0, NMAX},
{Y_MODULE, Y_TYPEDEF, 0, NMAX},
{Y_MODULE, Y_USES, 0, NMAX},
{Y_MODULE, Y_YANG_VERSION, 0, 1},
{Y_MUST, Y_DESCRIPTION, 0, 1},
{Y_MUST, Y_ERROR_APP_TAG, 0, 1},
{Y_MUST, Y_ERROR_MESSAGE, 0, 1},
{Y_MUST, Y_REFERENCE, 0, 1},
{Y_NOTIFICATION, Y_ANYDATA, 0, NMAX},
{Y_NOTIFICATION, Y_ANYXML, 0, NMAX},
{Y_NOTIFICATION, Y_CHOICE, 0, NMAX},
{Y_NOTIFICATION, Y_CONTAINER, 0, NMAX},
{Y_NOTIFICATION, Y_DESCRIPTION, 0, 1},
{Y_NOTIFICATION, Y_GROUPING, 0, NMAX},
{Y_NOTIFICATION, Y_IF_FEATURE, 0, NMAX},
{Y_NOTIFICATION, Y_LEAF, 0, NMAX},
{Y_NOTIFICATION, Y_LEAF_LIST, 0, NMAX},
{Y_NOTIFICATION, Y_LIST, 0, NMAX},
{Y_NOTIFICATION, Y_MUST, 0, NMAX},
{Y_NOTIFICATION, Y_REFERENCE, 0, 1},
{Y_NOTIFICATION, Y_STATUS, 0, 1},
{Y_NOTIFICATION, Y_TYPEDEF, 0, NMAX},
{Y_NOTIFICATION, Y_USES, 0, NMAX},
{Y_OUTPUT, Y_ANYDATA, 0, NMAX},
{Y_OUTPUT, Y_ANYXML, 0, NMAX},
{Y_OUTPUT, Y_CHOICE, 0, NMAX},
{Y_OUTPUT, Y_CONTAINER, 0, NMAX},
{Y_OUTPUT, Y_GROUPING, 0, NMAX},
{Y_OUTPUT, Y_LEAF, 0, NMAX},
{Y_OUTPUT, Y_LEAF_LIST, 0, NMAX},
{Y_OUTPUT, Y_LIST, 0, NMAX},
{Y_OUTPUT, Y_MUST, 0, NMAX},
{Y_OUTPUT, Y_TYPEDEF, 0, NMAX},
{Y_OUTPUT, Y_USES, 0, NMAX},
{Y_PATTERN, Y_DESCRIPTION, 0, 1},
{Y_PATTERN, Y_ERROR_APP_TAG, 0, 1},
{Y_PATTERN, Y_ERROR_MESSAGE, 0, 1},
{Y_PATTERN, Y_MODIFIER, 0, 1},
{Y_PATTERN, Y_REFERENCE, 0, 1},
{Y_RANGE, Y_DESCRIPTION, 0, 1},
{Y_RANGE, Y_ERROR_APP_TAG, 0, 1},
{Y_RANGE, Y_ERROR_MESSAGE, 0, 1},
{Y_RANGE, Y_REFERENCE, 0, 1},
{Y_REVISION, Y_DESCRIPTION, 0, 1},
{Y_REVISION, Y_REFERENCE, 0, 1},
{Y_RPC, Y_DESCRIPTION, 0, 1},
{Y_RPC, Y_GROUPING, 0, NMAX},
{Y_RPC, Y_IF_FEATURE, 0, NMAX},
{Y_RPC, Y_INPUT, 0, 1},
{Y_RPC, Y_OUTPUT, 0, 1},
{Y_RPC, Y_REFERENCE, 0, 1},
{Y_RPC, Y_STATUS, 0, 1},
{Y_RPC, Y_TYPEDEF, 0, NMAX},
{Y_SUBMODULE, Y_ANYDATA, 0, NMAX},
{Y_SUBMODULE, Y_AUGMENT, 0, NMAX},
{Y_SUBMODULE, Y_BELONGS_TO, 1, 1},
{Y_SUBMODULE, Y_CHOICE, 0, NMAX},
{Y_SUBMODULE, Y_CONTACT, 0, 1},
{Y_SUBMODULE, Y_CONTAINER, 0, NMAX},
{Y_SUBMODULE, Y_DESCRIPTION,0, 1},
{Y_SUBMODULE, Y_DEVIATION, 0, NMAX},
{Y_SUBMODULE, Y_EXTENSION, 0, NMAX},
{Y_SUBMODULE, Y_FEATURE, 0, NMAX},
{Y_SUBMODULE, Y_GROUPING, 0, NMAX},
{Y_SUBMODULE, Y_IDENTITY, 0, NMAX},
{Y_SUBMODULE, Y_IMPORT, 0, NMAX},
{Y_SUBMODULE, Y_INCLUDE, 0, NMAX},
{Y_SUBMODULE, Y_LEAF, 0, NMAX},
{Y_SUBMODULE, Y_LEAF_LIST, 0, NMAX},
{Y_SUBMODULE, Y_LIST, 0, NMAX},
{Y_SUBMODULE, Y_NOTIFICATION,0, NMAX},
{Y_SUBMODULE, Y_ORGANIZATION,0, 1},
{Y_SUBMODULE, Y_REFERENCE, 0, 1},
{Y_SUBMODULE, Y_REVISION, 0, NMAX},
{Y_SUBMODULE, Y_RPC, 0, NMAX},
{Y_SUBMODULE, Y_TYPEDEF, 0, NMAX},
{Y_SUBMODULE, Y_USES, 0, NMAX},
{Y_SUBMODULE, Y_YANG_VERSION,0, 1}, /* "yang-version" statement is mandatory in YANG version "1.1". */
{Y_TYPE, Y_BASE, 0, NMAX},
{Y_TYPE, Y_BIT, 0, NMAX},
{Y_TYPE, Y_ENUM, 0, NMAX},
{Y_TYPE, Y_FRACTION_DIGITS, 0, 1},
{Y_TYPE, Y_LENGTH, 0, 1},
{Y_TYPE, Y_PATH, 0, 1},
{Y_TYPE, Y_PATTERN, 0, NMAX},
{Y_TYPE, Y_RANGE, 0, 1},
{Y_TYPE, Y_REQUIRE_INSTANCE, 0, 1},
{Y_TYPE, Y_TYPE, 0, NMAX},
{Y_TYPEDEF, Y_DEFAULT, 0, 1},
{Y_TYPEDEF, Y_DESCRIPTION,0, 1},
{Y_TYPEDEF, Y_REFERENCE, 0, 1},
{Y_TYPEDEF, Y_STATUS, 0, 1},
{Y_TYPEDEF, Y_TYPE, 1, 1},
{Y_TYPEDEF, Y_UNITS, 0, 1},
{Y_USES, Y_AUGMENT, 0, NMAX},
{Y_USES, Y_DESCRIPTION, 0, 1},
{Y_USES, Y_IF_FEATURE, 0, NMAX},
{Y_USES, Y_REFERENCE, 0, 1},
{Y_USES, Y_REFINE, 0, NMAX},
{Y_USES, Y_STATUS, 0, 1},
{Y_USES, Y_WHEN, 0, 1},
{Y_ACTION, Y_DESCRIPTION, 0, 1, 0},
{Y_ACTION, Y_GROUPING, 0, NMAX, 0},
{Y_ACTION, Y_IF_FEATURE, 0, NMAX, 0},
{Y_ACTION, Y_INPUT, 0, 1, 0},
{Y_ACTION, Y_OUTPUT, 0, 1, 0},
{Y_ACTION, Y_REFERENCE, 0, 1, 0},
{Y_ACTION, Y_STATUS, 0, 1, 0},
{Y_ACTION, Y_TYPEDEF, 0, NMAX, 0},
{Y_ANYDATA, Y_CONFIG, 0, 1, 0},
{Y_ANYDATA, Y_DESCRIPTION, 0, 1, 0},
{Y_ANYDATA, Y_IF_FEATURE, 0, NMAX, 0},
{Y_ANYDATA, Y_MANDATORY, 0, 1, 0},
{Y_ANYDATA, Y_MUST, 0, NMAX, 0},
{Y_ANYDATA, Y_REFERENCE, 0, 1, 0},
{Y_ANYDATA, Y_STATUS, 0, 1, 0},
{Y_ANYDATA, Y_WHEN, 0, 1, 0},
{Y_ANYXML, Y_CONFIG, 0, 1, 0},
{Y_ANYXML, Y_DESCRIPTION, 0, 1, 0},
{Y_ANYXML, Y_IF_FEATURE, 0, NMAX, 0},
{Y_ANYXML, Y_MANDATORY, 0, 1, 0},
{Y_ANYXML, Y_MUST, 0, NMAX, 0},
{Y_ANYXML, Y_REFERENCE, 0, 1, 0},
{Y_ANYXML, Y_STATUS, 0, 1, 0},
{Y_ANYXML, Y_WHEN, 0, 1, 0},
{Y_ARGUMENT, Y_YIN_ELEMENT, 0, 1, 0},
{Y_AUGMENT, Y_ACTION, 0, NMAX, 0},
{Y_AUGMENT, Y_ANYDATA, 0, NMAX, 0},
{Y_AUGMENT, Y_ANYXML, 0, NMAX, 0},
{Y_AUGMENT, Y_CASE, 0, NMAX, 0},
{Y_AUGMENT, Y_CHOICE, 0, NMAX, 0},
{Y_AUGMENT, Y_CONTAINER, 0, NMAX, 0},
{Y_AUGMENT, Y_DESCRIPTION, 0, 1, 0},
{Y_AUGMENT, Y_IF_FEATURE, 0, NMAX, 0},
{Y_AUGMENT, Y_LEAF, 0, NMAX, 0},
{Y_AUGMENT, Y_LEAF_LIST, 0, NMAX, 0},
{Y_AUGMENT, Y_LIST, 0, NMAX, 0},
{Y_AUGMENT, Y_NOTIFICATION, 0, NMAX, 0},
{Y_AUGMENT, Y_REFERENCE, 0, 1, 0},
{Y_AUGMENT, Y_STATUS, 0, 1, 0},
{Y_AUGMENT, Y_USES, 0, NMAX, 0},
{Y_AUGMENT, Y_WHEN, 0, 1, 0},
{Y_BELONGS_TO, Y_PREFIX, 1, 1, 0},
{Y_BIT, Y_DESCRIPTION, 0, 1, 0},
{Y_BIT, Y_IF_FEATURE, 0, NMAX, 0},
{Y_BIT, Y_POSITION, 0, 1, 0},
{Y_BIT, Y_REFERENCE, 0, 1, 0},
{Y_BIT, Y_STATUS, 0, 1, 0},
{Y_CASE, Y_ANYDATA, 0, NMAX, 0},
{Y_CASE, Y_ANYXML, 0, NMAX, 0},
{Y_CASE, Y_CHOICE, 0, NMAX, 0},
{Y_CASE, Y_CONTAINER, 0, NMAX, 0},
{Y_CASE, Y_DESCRIPTION, 0, 1, 0},
{Y_CASE, Y_IF_FEATURE, 0, NMAX, 0},
{Y_CASE, Y_LEAF, 0, NMAX, 0},
{Y_CASE, Y_LEAF_LIST, 0, NMAX, 0},
{Y_CASE, Y_LIST, 0, NMAX, 0},
{Y_CASE, Y_REFERENCE, 0, 1, 0},
{Y_CASE, Y_STATUS, 0, 1, 0},
{Y_CASE, Y_USES, 0, NMAX, 0},
{Y_CASE, Y_WHEN, 0, 1, 0},
{Y_CHOICE, Y_ANYXML, 0, NMAX, 0},
{Y_CHOICE, Y_CASE, 0, NMAX, 0},
{Y_CHOICE, Y_CHOICE, 0, NMAX, 0},
{Y_CHOICE, Y_CONFIG, 0, 1, 0},
{Y_CHOICE, Y_CONTAINER, 0, NMAX, 0},
{Y_CHOICE, Y_DEFAULT, 0, 1, 0},
{Y_CHOICE, Y_DESCRIPTION, 0, 1, 0},
{Y_CHOICE, Y_IF_FEATURE, 0, NMAX, 0},
{Y_CHOICE, Y_LEAF, 0, NMAX, 0},
{Y_CHOICE, Y_LEAF_LIST, 0, NMAX, 0},
{Y_CHOICE, Y_LIST, 0, NMAX, 0},
{Y_CHOICE, Y_MANDATORY, 0, 1, 0},
{Y_CHOICE, Y_REFERENCE, 0, 1, 0},
{Y_CHOICE, Y_STATUS, 0, 1, 0},
{Y_CHOICE, Y_WHEN, 0, 1, 0},
{Y_CHOICE, Y_ANYDATA, 0, NMAX, 0},
{Y_CONTAINER, Y_ACTION, 0, NMAX, 0},
{Y_CONTAINER, Y_ANYDATA, 0, NMAX, 0},
{Y_CONTAINER, Y_ANYXML, 0, NMAX, 0},
{Y_CONTAINER, Y_CHOICE, 0, NMAX, 0},
{Y_CONTAINER, Y_CONFIG, 0, 1, 0},
{Y_CONTAINER, Y_CONTAINER, 0, NMAX, 0},
{Y_CONTAINER, Y_DESCRIPTION, 0, 1, 0},
{Y_CONTAINER, Y_GROUPING, 0, NMAX, 0},
{Y_CONTAINER, Y_IF_FEATURE, 0, NMAX, 0},
{Y_CONTAINER, Y_LEAF, 0, NMAX, 0},
{Y_CONTAINER, Y_LEAF_LIST, 0, NMAX, 0},
{Y_CONTAINER, Y_LIST, 0, NMAX, 0},
{Y_CONTAINER, Y_MUST, 0, NMAX, 0},
{Y_CONTAINER, Y_NOTIFICATION, 0, NMAX, 0},
{Y_CONTAINER, Y_PRESENCE, 0, 1, 0},
{Y_CONTAINER, Y_REFERENCE, 0, 1, 0},
{Y_CONTAINER, Y_STATUS, 0, 1, 0},
{Y_CONTAINER, Y_TYPEDEF, 0, NMAX, 0},
{Y_CONTAINER, Y_USES, 0, NMAX, 0},
{Y_CONTAINER, Y_WHEN, 0, 1, 0},
{Y_DEVIATE, Y_CONFIG, 0, 1, 0},
{Y_DEVIATE, Y_DEFAULT, 0, NMAX, 0},
{Y_DEVIATE, Y_MANDATORY, 0, 1, 0},
{Y_DEVIATE, Y_MAX_ELEMENTS, 0, 1, 0},
{Y_DEVIATE, Y_MIN_ELEMENTS, 0, 1, 0},
{Y_DEVIATE, Y_MUST, 0, NMAX, 0},
{Y_DEVIATE, Y_TYPE, 0, 1, 0},
{Y_DEVIATE, Y_UNIQUE, 0, NMAX, 0},
{Y_DEVIATE, Y_UNITS, 0, 1, 0},
{Y_DEVIATION, Y_DESCRIPTION, 0, 1, 0},
{Y_DEVIATION, Y_DEVIATE, 1, NMAX, 0},
{Y_DEVIATION, Y_REFERENCE, 0, 1, 0},
{Y_ENUM, Y_DESCRIPTION, 0, 1, 0},
{Y_ENUM, Y_IF_FEATURE, 0, NMAX, 0},
{Y_ENUM, Y_REFERENCE, 0, 1, 0},
{Y_ENUM, Y_STATUS, 0, 1, 0},
{Y_ENUM, Y_VALUE, 0, 1, 0},
{Y_EXTENSION, Y_ARGUMENT, 0, 1, 0},
{Y_EXTENSION, Y_DESCRIPTION, 0, 1, 0},
{Y_EXTENSION, Y_REFERENCE, 0, 1, 0},
{Y_EXTENSION, Y_STATUS, 0, 1, 0},
{Y_FEATURE, Y_DESCRIPTION, 0, 1, 0},
{Y_FEATURE, Y_IF_FEATURE, 0, NMAX, 0},
{Y_FEATURE, Y_REFERENCE, 0, 1, 0},
{Y_FEATURE, Y_STATUS, 0, 1, 0},
{Y_GROUPING, Y_ACTION, 0, NMAX, 0},
{Y_GROUPING, Y_ANYDATA, 0, NMAX, 0},
{Y_GROUPING, Y_ANYXML, 0, NMAX, 0},
{Y_GROUPING, Y_CHOICE, 0, NMAX, 0},
{Y_GROUPING, Y_CONTAINER, 0, NMAX, 0},
{Y_GROUPING, Y_DESCRIPTION, 0, 1, 0},
{Y_GROUPING, Y_GROUPING, 0, NMAX, 0},
{Y_GROUPING, Y_LEAF, 0, NMAX, 0},
{Y_GROUPING, Y_LEAF_LIST, 0, NMAX, 0},
{Y_GROUPING, Y_LIST, 0, NMAX, 0},
{Y_GROUPING, Y_NOTIFICATION, 0, NMAX, 0},
{Y_GROUPING, Y_REFERENCE, 0, 1, 0},
{Y_GROUPING, Y_STATUS, 0, 1, 0},
{Y_GROUPING, Y_TYPEDEF, 0, NMAX, 0},
{Y_GROUPING, Y_USES, 0, NMAX, 0},
{Y_IDENTITY, Y_BASE, 0, NMAX, 0},
{Y_IDENTITY, Y_DESCRIPTION, 0, 1, 0},
{Y_IDENTITY, Y_IF_FEATURE, 0, NMAX, 0},
{Y_IDENTITY, Y_REFERENCE, 0, 1, 0},
{Y_IDENTITY, Y_STATUS, 0, 1, 0},
{Y_IMPORT, Y_DESCRIPTION, 0, 1, 0},
{Y_IMPORT, Y_PREFIX, 1, 1, 0},
{Y_IMPORT, Y_REFERENCE, 0, 1, 0},
{Y_IMPORT, Y_REVISION_DATE,0, 1, 0},
{Y_INCLUDE, Y_DESCRIPTION, 0, 1, 0},
{Y_INCLUDE, Y_REFERENCE, 0, 1, 0},
{Y_INCLUDE, Y_REVISION_DATE,0, 1, 0},
{Y_INPUT, Y_ANYDATA, 0, NMAX, 0},
{Y_INPUT, Y_ANYXML, 0, NMAX, 0},
{Y_INPUT, Y_CHOICE, 0, NMAX, 0},
{Y_INPUT, Y_CONTAINER, 0, NMAX, 0},
{Y_INPUT, Y_GROUPING, 0, NMAX, 0},
{Y_INPUT, Y_LEAF, 0, NMAX, 0},
{Y_INPUT, Y_LEAF_LIST, 0, NMAX, 0},
{Y_INPUT, Y_LIST, 0, NMAX, 0},
{Y_INPUT, Y_MUST, 0, NMAX, 0},
{Y_INPUT, Y_TYPEDEF, 0, NMAX, 0},
{Y_INPUT, Y_USES, 0, NMAX, 0},
{Y_LEAF, Y_CONFIG, 0, 1, 0},
{Y_LEAF, Y_DEFAULT, 0, 1, 0},
{Y_LEAF, Y_DESCRIPTION, 0, 1, 0},
{Y_LEAF, Y_IF_FEATURE, 0, NMAX, 0},
{Y_LEAF, Y_MANDATORY, 0, 1, 0},
{Y_LEAF, Y_MUST, 0, NMAX, 0},
{Y_LEAF, Y_REFERENCE, 0, 1, 0},
{Y_LEAF, Y_STATUS, 0, 1, 0},
{Y_LEAF, Y_TYPE, 1, 1, 0},
{Y_LEAF, Y_UNITS, 0, 1, 0},
{Y_LEAF, Y_WHEN, 0, 1, 0},
{Y_LEAF_LIST, Y_CONFIG, 0, 1, 0},
{Y_LEAF_LIST, Y_DEFAULT, 0, NMAX, 0},
{Y_LEAF_LIST, Y_DESCRIPTION, 0, 1, 0},
{Y_LEAF_LIST, Y_IF_FEATURE, 0, NMAX, 0},
{Y_LEAF_LIST, Y_MAX_ELEMENTS, 0, 1, 0},
{Y_LEAF_LIST, Y_MIN_ELEMENTS, 0, 1, 0},
{Y_LEAF_LIST, Y_MUST, 0, NMAX, 0},
{Y_LEAF_LIST, Y_ORDERED_BY, 0, 1, 0},
{Y_LEAF_LIST, Y_REFERENCE, 0, 1, 0},
{Y_LEAF_LIST, Y_STATUS, 0, 1, 0},
{Y_LEAF_LIST, Y_TYPE, 1, 1, 0},
{Y_LEAF_LIST, Y_UNITS, 0, 1, 0},
{Y_LEAF_LIST, Y_WHEN, 0, 1, 0},
{Y_LENGTH, Y_DESCRIPTION, 0, 1, 0},
{Y_LENGTH, Y_ERROR_APP_TAG, 0, 1, 0},
{Y_LENGTH, Y_ERROR_MESSAGE, 0, 1, 0},
{Y_LENGTH, Y_REFERENCE, 0, 1, 0},
{Y_LIST, Y_ACTION, 0, NMAX, 0},
{Y_LIST, Y_ANYDATA, 0, NMAX, 0},
{Y_LIST, Y_ANYXML, 0, NMAX, 0},
{Y_LIST, Y_CHOICE, 0, NMAX, 0},
{Y_LIST, Y_CONFIG, 0, 1, 0},
{Y_LIST, Y_CONTAINER, 0, NMAX, 0},
{Y_LIST, Y_DESCRIPTION, 0, 1, 0},
{Y_LIST, Y_GROUPING, 0, NMAX, 0},
{Y_LIST, Y_IF_FEATURE, 0, NMAX, 0},
{Y_LIST, Y_KEY, 0, 1, 0},
{Y_LIST, Y_LEAF, 0, NMAX, 0},
{Y_LIST, Y_LEAF_LIST, 0, NMAX, 0},
{Y_LIST, Y_LIST, 0, NMAX, 0},
{Y_LIST, Y_MAX_ELEMENTS, 0, 1, 0},
{Y_LIST, Y_MIN_ELEMENTS, 0, 1, 0},
{Y_LIST, Y_MUST, 0, NMAX, 0},
{Y_LIST, Y_NOTIFICATION, 0, NMAX, 0},
{Y_LIST, Y_ORDERED_BY, 0, 1, 0},
{Y_LIST, Y_REFERENCE, 0, 1, 0},
{Y_LIST, Y_STATUS, 0, 1, 0},
{Y_LIST, Y_TYPEDEF, 0, NMAX, 0},
{Y_LIST, Y_UNIQUE, 0, NMAX, 0},
{Y_LIST, Y_USES, 0, NMAX, 0},
{Y_LIST, Y_WHEN, 0,1, 0},
{Y_MODULE, Y_ANYDATA, 0, NMAX, 4},
{Y_MODULE, Y_ANYXML, 0, NMAX, 4},
{Y_MODULE, Y_AUGMENT, 0, NMAX, 4},
{Y_MODULE, Y_CHOICE, 0, NMAX, 4},
{Y_MODULE, Y_CONTACT, 0, 1, 2},
{Y_MODULE, Y_CONTAINER, 0, NMAX, 4},
{Y_MODULE, Y_DESCRIPTION, 0, 1, 2},
{Y_MODULE, Y_DEVIATION, 0, NMAX, 4},
{Y_MODULE, Y_EXTENSION, 0, NMAX, 4},
{Y_MODULE, Y_FEATURE, 0, NMAX, 4},
{Y_MODULE, Y_GROUPING, 0, NMAX, 4},
{Y_MODULE, Y_IDENTITY, 0, NMAX, 4},
{Y_MODULE, Y_IMPORT, 0, NMAX, 1},
{Y_MODULE, Y_INCLUDE, 0, NMAX, 1},
{Y_MODULE, Y_LEAF, 0, NMAX, 4},
{Y_MODULE, Y_LEAF_LIST, 0, NMAX, 4},
{Y_MODULE, Y_LIST, 0, NMAX, 4},
{Y_MODULE, Y_NAMESPACE, 1, 1, 0},
{Y_MODULE, Y_NOTIFICATION, 0, NMAX, 4},
{Y_MODULE, Y_ORGANIZATION, 0, 1, 2},
{Y_MODULE, Y_PREFIX, 1, 1, 0},
{Y_MODULE, Y_REFERENCE, 0, 1, 2},
{Y_MODULE, Y_REVISION, 0, NMAX, 3},
{Y_MODULE, Y_RPC, 0, NMAX, 4},
{Y_MODULE, Y_TYPEDEF, 0, NMAX, 4},
{Y_MODULE, Y_USES, 0, NMAX, 4},
{Y_MODULE, Y_YANG_VERSION, 0, 1, 0},
{Y_MUST, Y_DESCRIPTION, 0, 1, 0},
{Y_MUST, Y_ERROR_APP_TAG, 0, 1, 0},
{Y_MUST, Y_ERROR_MESSAGE, 0, 1, 0},
{Y_MUST, Y_REFERENCE, 0, 1, 0},
{Y_NOTIFICATION, Y_ANYDATA, 0, NMAX, 0},
{Y_NOTIFICATION, Y_ANYXML, 0, NMAX, 0},
{Y_NOTIFICATION, Y_CHOICE, 0, NMAX, 0},
{Y_NOTIFICATION, Y_CONTAINER, 0, NMAX, 0},
{Y_NOTIFICATION, Y_DESCRIPTION, 0, 1, 0},
{Y_NOTIFICATION, Y_GROUPING, 0, NMAX, 0},
{Y_NOTIFICATION, Y_IF_FEATURE, 0, NMAX, 0},
{Y_NOTIFICATION, Y_LEAF, 0, NMAX, 0},
{Y_NOTIFICATION, Y_LEAF_LIST, 0, NMAX, 0},
{Y_NOTIFICATION, Y_LIST, 0, NMAX, 0},
{Y_NOTIFICATION, Y_MUST, 0, NMAX, 0},
{Y_NOTIFICATION, Y_REFERENCE, 0, 1, 0},
{Y_NOTIFICATION, Y_STATUS, 0, 1, 0},
{Y_NOTIFICATION, Y_TYPEDEF, 0, NMAX, 0},
{Y_NOTIFICATION, Y_USES, 0, NMAX, 0},
{Y_OUTPUT, Y_ANYDATA, 0, NMAX, 0},
{Y_OUTPUT, Y_ANYXML, 0, NMAX, 0},
{Y_OUTPUT, Y_CHOICE, 0, NMAX, 0},
{Y_OUTPUT, Y_CONTAINER, 0, NMAX, 0},
{Y_OUTPUT, Y_GROUPING, 0, NMAX, 0},
{Y_OUTPUT, Y_LEAF, 0, NMAX, 0},
{Y_OUTPUT, Y_LEAF_LIST, 0, NMAX, 0},
{Y_OUTPUT, Y_LIST, 0, NMAX, 0},
{Y_OUTPUT, Y_MUST, 0, NMAX, 0},
{Y_OUTPUT, Y_TYPEDEF, 0, NMAX, 0},
{Y_OUTPUT, Y_USES, 0, NMAX, 0},
{Y_PATTERN, Y_DESCRIPTION, 0, 1, 0},
{Y_PATTERN, Y_ERROR_APP_TAG, 0, 1, 0},
{Y_PATTERN, Y_ERROR_MESSAGE, 0, 1, 0},
{Y_PATTERN, Y_MODIFIER, 0, 1, 0},
{Y_PATTERN, Y_REFERENCE, 0, 1, 0},
{Y_RANGE, Y_DESCRIPTION, 0, 1, 0},
{Y_RANGE, Y_ERROR_APP_TAG, 0, 1, 0},
{Y_RANGE, Y_ERROR_MESSAGE, 0, 1, 0},
{Y_RANGE, Y_REFERENCE, 0, 1, 0},
{Y_REVISION, Y_DESCRIPTION, 0, 1, 0},
{Y_REVISION, Y_REFERENCE, 0, 1, 0},
{Y_RPC, Y_DESCRIPTION, 0, 1, 0},
{Y_RPC, Y_GROUPING, 0, NMAX, 0},
{Y_RPC, Y_IF_FEATURE, 0, NMAX, 0},
{Y_RPC, Y_INPUT, 0, 1, 0},
{Y_RPC, Y_OUTPUT, 0, 1, 0},
{Y_RPC, Y_REFERENCE, 0, 1, 0},
{Y_RPC, Y_STATUS, 0, 1, 0},
{Y_RPC, Y_TYPEDEF, 0, NMAX, 0},
{Y_SUBMODULE, Y_ANYDATA, 0, NMAX, 4},
{Y_SUBMODULE, Y_AUGMENT, 0, NMAX, 4},
{Y_SUBMODULE, Y_BELONGS_TO, 1, 1, 0},
{Y_SUBMODULE, Y_CHOICE, 0, NMAX, 4},
{Y_SUBMODULE, Y_CONTACT, 0, 1, 2},
{Y_SUBMODULE, Y_CONTAINER, 0, NMAX, 4},
{Y_SUBMODULE, Y_DESCRIPTION,0, 1, 2},
{Y_SUBMODULE, Y_DEVIATION, 0, NMAX, 4},
{Y_SUBMODULE, Y_EXTENSION, 0, NMAX, 4},
{Y_SUBMODULE, Y_FEATURE, 0, NMAX, 4},
{Y_SUBMODULE, Y_GROUPING, 0, NMAX, 4},
{Y_SUBMODULE, Y_IDENTITY, 0, NMAX, 4},
{Y_SUBMODULE, Y_IMPORT, 0, NMAX, 1},
{Y_SUBMODULE, Y_INCLUDE, 0, NMAX, 1},
{Y_SUBMODULE, Y_LEAF, 0, NMAX, 4},
{Y_SUBMODULE, Y_LEAF_LIST, 0, NMAX, 4},
{Y_SUBMODULE, Y_LIST, 0, NMAX, 4},
{Y_SUBMODULE, Y_NOTIFICATION,0, NMAX, 4},
{Y_SUBMODULE, Y_ORGANIZATION,0, 1, 2},
{Y_SUBMODULE, Y_REFERENCE, 0, 1, 2},
{Y_SUBMODULE, Y_REVISION, 0, NMAX, 3},
{Y_SUBMODULE, Y_RPC, 0, NMAX, 4},
{Y_SUBMODULE, Y_TYPEDEF, 0, NMAX, 4},
{Y_SUBMODULE, Y_USES, 0, NMAX, 4},
{Y_SUBMODULE, Y_YANG_VERSION,0, 1, 0}, /* "yang-version" statement is mandatory in YANG version "1.1". */
{Y_TYPE, Y_BASE, 0, NMAX, 0},
{Y_TYPE, Y_BIT, 0, NMAX, 0},
{Y_TYPE, Y_ENUM, 0, NMAX, 0},
{Y_TYPE, Y_FRACTION_DIGITS, 0, 1, 0},
{Y_TYPE, Y_LENGTH, 0, 1, 0},
{Y_TYPE, Y_PATH, 0, 1, 0},
{Y_TYPE, Y_PATTERN, 0, NMAX, 0},
{Y_TYPE, Y_RANGE, 0, 1, 0},
{Y_TYPE, Y_REQUIRE_INSTANCE, 0, 1, 0},
{Y_TYPE, Y_TYPE, 0, NMAX, 0},
{Y_TYPEDEF, Y_DEFAULT, 0, 1, 0},
{Y_TYPEDEF, Y_DESCRIPTION,0, 1, 0},
{Y_TYPEDEF, Y_REFERENCE, 0, 1, 0},
{Y_TYPEDEF, Y_STATUS, 0, 1, 0},
{Y_TYPEDEF, Y_TYPE, 1, 1, 0},
{Y_TYPEDEF, Y_UNITS, 0, 1, 0},
{Y_USES, Y_AUGMENT, 0, NMAX, 0},
{Y_USES, Y_DESCRIPTION, 0, 1, 0},
{Y_USES, Y_IF_FEATURE, 0, NMAX, 0},
{Y_USES, Y_REFERENCE, 0, 1, 0},
{Y_USES, Y_REFINE, 0, NMAX, 0},
{Y_USES, Y_STATUS, 0, 1, 0},
{Y_USES, Y_WHEN, 0, 1, 0},
{0,}
};
@ -497,12 +506,17 @@ yang_cardinality(clicon_handle h,
int nr;
const struct ycard *ycplist; /* ycard parent table*/
const struct ycard *yc;
int order;
yang_stmt *yprev = NULL;
pk = yang_keyword_get(yt);
/* 0) Find parent sub-parts of cardinality vector */
if ((ycplist = ycard_find(pk, 0, yclist, 0)) == NULL)
goto ok; /* skip */
/* 1) For all children, if neither in 0..n, 0..1, 1 or 1..n ->ERROR */
/* 1) For all children, if neither in 0..n, 0..1, 1 or 1..n ->ERROR
* Also: check monotonically increasing order
*/
order = 0;
ys = NULL;
while ((ys = yn_each(yt, ys)) != NULL) {
ck = yang_keyword_get(ys);
@ -518,7 +532,21 @@ yang_cardinality(clicon_handle h,
yang_argument_get(yt));
goto done;
}
}
if (order > yc->yc_order){
clicon_err(OE_YANG, 0, "%s: yang node \"%s\"(%s) which is child of \"%s\"(%s) is not in correct order (should not be after \"%s\"(%s))",
modname,
yang_key2str(ck),
yang_argument_get(ys),
yang_key2str(pk),
yang_argument_get(yt),
yang_key2str(yang_keyword_get(yprev)),
yang_argument_get(yprev));
goto done;
}
if (order < yc->yc_order)
order = yc->yc_order;
yprev = ys;
}
/* 2) For all in 1 and 1..n list, if 0 such children ->ERROR */
for (yc = &ycplist[0]; (int)yc->yc_parent == pk; yc++){
if (yc->yc_min &&
@ -541,7 +569,7 @@ yang_cardinality(clicon_handle h,
goto done;
}
}
/* 4) Recurse */
i = 0;
while (i< yang_len_get(yt)){ /* Note, children may be removed cant use yn_each */

View file

@ -112,6 +112,7 @@ modstate_diff_free(modstate_diff_t *md)
*
* Load RFC7895 yang spec, module-set-id, etc.
* @param[in] h Clicon handle
* @see netconf_module_load
*/
int
yang_modules_init(clicon_handle h)
@ -328,7 +329,7 @@ yang_modules_state_get(clicon_handle h,
* Note, list is not sorted since it is state (should not be)
*/
if (clixon_xml_parse_string(cbuf_get(cb), YB_MODULE, yspec, &x, NULL) < 0){
if (netconf_operation_failed_xml(xret, "protocol", clicon_err_reason)< 0)
if (xret && netconf_operation_failed_xml(xret, "protocol", clicon_err_reason)< 0)
goto done;
goto fail;
}

View file

@ -633,13 +633,16 @@ yang_expand_uses_node(yang_stmt *yn,
yang_argument_get(yg),
yang_argument_get(ygrouping)
);
goto done;
goto done;
}
if (yang_when_xpath_set(yg, wxpath) < 0)
goto done;
if (yang_when_nsc_set(yg, wnsc) < 0)
goto done;
}
/* This is for extensions that allow list keys to be optional, see restconf_main_extension_cb */
if (yang_flag_get(ys, YANG_FLAG_NOKEY))
yang_flag_set(yg, YANG_FLAG_NOKEY);
yn->ys_stmt[i+k] = yg;
yg->ys_parent = yn;
k++;
@ -1032,6 +1035,10 @@ yang_parse_module(clicon_handle h,
ymod = NULL;
goto done;
}
/* Sanity check that requested module name matches loaded module
* If this does not match, the filename and containing module do not match
* RFC 7950 Sec 5.2
*/
if ((yrev = yang_find(ymod, Y_REVISION, NULL)) != NULL)
revm = cv_uint32_get(yang_cv_get(yrev));
if (filename2revision(filename, NULL, &revf) < 0)
@ -1064,14 +1071,18 @@ yang_parse_recurse(clicon_handle h,
yang_stmt *ymod,
yang_stmt *ysp)
{
int retval = -1;
yang_stmt *yi = NULL; /* import */
yang_stmt *yrev;
char *submodule;
char *subrevision;
yang_stmt *subymod;
int retval = -1;
yang_stmt *yi = NULL; /* import */
yang_stmt *yrev;
yang_stmt *ybelongto;
yang_stmt *yrealmod;
char *submodule;
char *subrevision;
yang_stmt *subymod;
enum rfc_6020 keyw;
if (ys_real_module(ymod, &yrealmod) < 0)
goto done;
/* go through all import (modules) and include(submodules) of ysp */
while ((yi = yn_each(ymod, yi)) != NULL){
keyw = yang_keyword_get(yi);
@ -1091,6 +1102,21 @@ yang_parse_recurse(clicon_handle h,
/* recursive call */
if ((subymod = yang_parse_module(h, submodule, subrevision, ysp)) == NULL)
goto done;
/* Sanity check: if submodule, its belongs-to statement shall point to the module */
if (keyw == Y_INCLUDE){
ybelongto = yang_find(subymod, Y_BELONGS_TO, NULL);
if (ybelongto == NULL){
clicon_err(OE_YANG, ENOENT, "Sub-module \"%s\" does not have a belongs-to statement", submodule); /* shouldnt happen */
goto done;
}
if (strcmp(yang_argument_get(ybelongto), yang_argument_get(yrealmod)) != 0){
clicon_err(OE_YANG, ENOENT, "Sub-module \"%s\" references module \"%s\" in its belongs-to statement but should reference \"%s\"",
submodule,
yang_argument_get(ybelongto),
yang_argument_get(yrealmod));
goto done;
}
}
/* Go through its sub-modules recursively */
if (yang_parse_recurse(h, subymod, ysp) < 0){
ymod = NULL;
@ -1173,7 +1199,7 @@ ys_schemanode_check(yang_stmt *ys,
* Verify the following rule:
* RFC 7950 7.8.2: The "key" statement, which MUST be present if the list represents
* configuration and MAY be present otherwise
* Unless CLICON_YANG_LIST_CHECK is false
* Unless CLICON_YANG_LIST_CHECK is false (obsolete)
* OR it is the "errors" rule of the ietf-restconf spec which seems to be a special case.
*/
static int
@ -1199,28 +1225,22 @@ ys_list_check(clicon_handle h,
if (keyw == Y_LIST &&
yang_find(ys, Y_KEY, NULL) == 0){
ymod = ys_module(ys);
#if 1
/* Except restconf error extension from sanity check, dont know why it has no keys */
if (strcmp(yang_find_mynamespace(ys),"urn:ietf:params:xml:ns:yang:ietf-restconf")==0 &&
strcmp(yang_argument_get(ys),"error") == 0)
;
else
#endif
{
if (clicon_option_bool(h, "CLICON_YANG_LIST_CHECK")){
clicon_log(LOG_ERR, "Error: LIST \"%s\" in module \"%s\" lacks key statement which MUST be present (See RFC 7950 Sec 7.8.2)",
yang_argument_get(ys),
yang_argument_get(ymod)
);
goto done;
}
else
clicon_log(LOG_WARNING, "Warning: LIST \"%s\" in module \"%s\" lacks key statement which MUST be present (See RFC 7950 Sec 7.8.2)",
/* Except nokey exceptions such as rrc 8040 yang-data */
if (!yang_flag_get(yroot, YANG_FLAG_NOKEY)){
/* Note obsolete */
if (clicon_option_bool(h, "CLICON_YANG_LIST_CHECK")){
clicon_log(LOG_ERR, "Error: LIST \"%s\" in module \"%s\" lacks key statement which MUST be present (See RFC 7950 Sec 7.8.2)",
yang_argument_get(ys),
yang_argument_get(ymod)
);
goto done;
}
else
clicon_log(LOG_WARNING, "Warning: LIST \"%s\" in module \"%s\" lacks key statement which MUST be present (See RFC 7950 Sec 7.8.2)",
yang_argument_get(ys),
yang_argument_get(ymod)
);
}
}
/* Traverse subs */
if (yang_schemanode(ys) || keyw == Y_MODULE || keyw == Y_SUBMODULE){
@ -1744,29 +1764,33 @@ cg_var *
ys_parse(yang_stmt *ys,
enum cv_type cvtype)
{
int cvret;
char *reason = NULL;
int cvret;
char *reason = NULL;
cg_var *cv = NULL;
assert(yang_cv_get(ys) == NULL); /* Cv:s are parsed in different places, difficult to separate */
if ((ys->ys_cv = cv_new(cvtype)) == NULL){
if ((cv = yang_cv_get(ys)) != NULL){
/* eg mandatory in uses is already set and then copied */
cv_free(cv);
yang_cv_set(ys, NULL);
}
if ((cv = cv_new(cvtype)) == NULL){
clicon_err(OE_YANG, errno, "cv_new");
goto done;
}
if ((cvret = cv_parse1(yang_argument_get(ys), ys->ys_cv, &reason)) < 0){ /* error */
if ((cvret = cv_parse1(yang_argument_get(ys), cv, &reason)) < 0){ /* error */
clicon_err(OE_YANG, errno, "parsing cv");
ys->ys_cv = NULL;
goto done;
}
if (cvret == 0){ /* parsing failed */
clicon_err(OE_YANG, errno, "Parsing CV: %s", reason);
ys->ys_cv = NULL;
goto done;
}
yang_cv_set(ys, cv);
/* cvret == 1 means parsing is OK */
done:
if (reason)
free(reason);
return ys->ys_cv;
return yang_cv_get(ys);
}
/*! First round yang syntactic statement specific checks. No context checks.
@ -1796,6 +1820,7 @@ ys_parse_sub(yang_stmt *ys,
char *reason = NULL;
int ret;
uint32_t minmax;
cg_var *cv = NULL;
arg = yang_argument_get(ys);
keyword = yang_keyword_get(ys);
@ -1803,7 +1828,11 @@ ys_parse_sub(yang_stmt *ys,
case Y_FRACTION_DIGITS:
if (ys_parse(ys, CGV_UINT8) == NULL)
goto done;
fd = cv_uint8_get(ys->ys_cv);
if ((cv = yang_cv_get(ys)) == NULL){
clicon_err(OE_YANG, ENOENT, "Unexpected NULL cv");
goto done;
}
fd = cv_uint8_get(cv);
if (fd < 1 || fd > 18){
clicon_err(OE_YANG, errno, "%u: Out of range, should be [1:18]", fd);
goto done;
@ -1818,11 +1847,12 @@ ys_parse_sub(yang_stmt *ys,
case Y_REVISION_DATE: /* YYYY-MM-DD encoded as uint32 YYYYMMDD */
if (ys_parse_date_arg(arg, &date) < 0)
goto done;
if ((ys->ys_cv = cv_new(CGV_UINT32)) == NULL){
if ((cv = cv_new(CGV_UINT32)) == NULL){
clicon_err(OE_YANG, errno, "cv_new");
goto done;
}
cv_uint32_set(ys->ys_cv, date);
yang_cv_set(ys, cv);
cv_uint32_set(cv, date);
break;
case Y_STATUS: /* RFC7950 7.21.2: "current", "deprecated", or "obsolete". */
if (strcmp(arg, "current") &&
@ -1835,13 +1865,14 @@ ys_parse_sub(yang_stmt *ys,
break;
case Y_MAX_ELEMENTS:
case Y_MIN_ELEMENTS:
if ((ys->ys_cv = cv_new(CGV_UINT32)) == NULL){
if ((cv = cv_new(CGV_UINT32)) == NULL){
clicon_err(OE_YANG, errno, "cv_new");
goto done;
}
yang_cv_set(ys, cv);
if (keyword == Y_MAX_ELEMENTS &&
strcmp(arg, "unbounded") == 0)
cv_uint32_set(ys->ys_cv, 0); /* 0 means unbounded for max */
cv_uint32_set(cv, 0); /* 0 means unbounded for max */
else{
if ((ret = parse_uint32(arg, &minmax, &reason)) < 0){
clicon_err(OE_YANG, errno, "parse_uint32");
@ -1853,7 +1884,7 @@ ys_parse_sub(yang_stmt *ys,
free(reason);
goto done;
}
cv_uint32_set(ys->ys_cv, minmax);
cv_uint32_set(cv, minmax);
}
break;
case Y_MODIFIER:
@ -1865,11 +1896,12 @@ ys_parse_sub(yang_stmt *ys,
case Y_UNKNOWN:{ /* save (optional) argument in ys_cv */
if (extra == NULL)
break;
if ((ys->ys_cv = cv_new(CGV_STRING)) == NULL){
if ((cv = cv_new(CGV_STRING)) == NULL){
clicon_err(OE_YANG, errno, "cv_new");
goto done;
}
if ((ret = cv_parse1(extra, ys->ys_cv, &reason)) < 0){ /* error */
yang_cv_set(ys, cv);
if ((ret = cv_parse1(extra, cv, &reason)) < 0){ /* error */
clicon_err(OE_YANG, errno, "parsing cv");
goto done;
}