Empty yang type. Relaxed yang types for unions, eg two strings with different length.
This commit is contained in:
parent
bc2b606167
commit
319e7707d8
14 changed files with 64 additions and 113 deletions
|
|
@ -29,6 +29,8 @@
|
||||||
#
|
#
|
||||||
# ***** END LICENSE BLOCK *****
|
# ***** END LICENSE BLOCK *****
|
||||||
|
|
||||||
|
- Empty yang type. Relaxed yang types for unions, eg two strings with different length.
|
||||||
|
|
||||||
Dec 2016: Dual license: both GPLv3 and APLv2
|
Dec 2016: Dual license: both GPLv3 and APLv2
|
||||||
|
|
||||||
Feb 2016: Forked new clixon repository from clicon
|
Feb 2016: Forked new clixon repository from clicon
|
||||||
|
|
|
||||||
|
|
@ -495,7 +495,7 @@ compare_dbs(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
* cvv[2] = "bgp"
|
* cvv[2] = "bgp"
|
||||||
* arg = "/interfaces/interface/%s/type"
|
* arg = "/interfaces/interface/%s/type"
|
||||||
* op: OP_MERGE
|
* op: OP_MERGE
|
||||||
* @see cli_callback_xmlkeyfmt_generate where arg is generated
|
* @see cli_callback_generate where arg is generated
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
cli_dbxml(clicon_handle h,
|
cli_dbxml(clicon_handle h,
|
||||||
|
|
@ -508,17 +508,20 @@ cli_dbxml(clicon_handle h,
|
||||||
char *xkfmt; /* xml key format */
|
char *xkfmt; /* xml key format */
|
||||||
char *xk = NULL; /* xml key */
|
char *xk = NULL; /* xml key */
|
||||||
cg_var *cval;
|
cg_var *cval;
|
||||||
char *val = NULL;
|
int len;
|
||||||
|
|
||||||
xkfmt = cv_string_get(arg);
|
xkfmt = cv_string_get(arg);
|
||||||
if (xmlkeyfmt2key(xkfmt, cvv, &xk) < 0)
|
if (xmlkeyfmt2key(xkfmt, cvv, &xk) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
cval = cvec_i(cvv, cvec_len(cvv)-1);
|
len = cvec_len(cvv);
|
||||||
if ((val = cv2str_dup(cval)) == NULL){
|
if (len > 1){
|
||||||
|
cval = cvec_i(cvv, len-1);
|
||||||
|
if ((str = cv2str_dup(cval)) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "cv2str_dup");
|
clicon_err(OE_UNIX, errno, "cv2str_dup");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (clicon_rpc_change(h, "candidate", op, xk, val) < 0)
|
}
|
||||||
|
if (clicon_rpc_change(h, "candidate", op, xk, str) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_autocommit(h)) {
|
if (clicon_autocommit(h)) {
|
||||||
if (clicon_rpc_commit(h, "candidate", "running", 0, 0) < 0)
|
if (clicon_rpc_commit(h, "candidate", "running", 0, 0) < 0)
|
||||||
|
|
|
||||||
|
|
@ -72,104 +72,31 @@
|
||||||
/*=====================================================================
|
/*=====================================================================
|
||||||
* YANG generate CLI
|
* YANG generate CLI
|
||||||
*=====================================================================*/
|
*=====================================================================*/
|
||||||
#if 0 /* examples/ntp */
|
/*
|
||||||
ntp("Network Time Protocol"),cli_set("ntp");{
|
This is an example yang module:
|
||||||
logging("Configure NTP message logging"),cli_set("ntp.logging");{
|
module m {
|
||||||
status (<status:bool>),cli_set("ntp.logging $status:bool");
|
container x {
|
||||||
|
list m1 {
|
||||||
|
key "a";
|
||||||
|
leaf a {
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
leaf b {
|
||||||
|
type string;
|
||||||
}
|
}
|
||||||
server("Configure NTP Server") (<ipv4addr:ipv4addr>("IPv4 address of peer")),cli_set("ntp.server[] $!ipv4addr:ipv4addr");
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#if 0 /* examples/datamodel */
|
|
||||||
|
|
||||||
WITH COMPLETION:
|
|
||||||
a (<x:number>|<x:number expand_dbvar_auto("candidate a[] $!x")>),cli_set("a[] $!x");{
|
|
||||||
b,cli_set("a[].b $!x");{
|
|
||||||
y (<y:string>|<y:string expand_dbvar_auto("candidate a[].b $!x $y")>),cli_set("a[].b $!x $y");
|
|
||||||
}
|
}
|
||||||
z (<z:string>|<z:string expand_dbvar_auto("candidate a[] $!x $z")>),cli_set("a[] $!x $z");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
You can see which CLISPEC it generates via clixon_cli -D 1:
|
||||||
|
Jan 2 11:17:58: yang2cli: buf
|
||||||
#ifndef HAVE_CLIGEN_MAX2STR /* XXX cligen 3.6 feature */
|
} x,cli_set("/x");{
|
||||||
|
m1 (<a:string>|<a:string expand_dbvar("candidate /x/m1/%s/a")>),cli_set("/x/m1/%s");
|
||||||
/*! Print max value of a CLIgen variable type as string
|
|
||||||
* @param[in] type CLIgen variable type
|
|
||||||
* @param[out] str Max value printed in this string
|
|
||||||
* @param[in] size Length of 'str'
|
|
||||||
* @retval len How many bytes printed
|
|
||||||
* @see cvtype_max2str_dup
|
|
||||||
* You can use str=NULL to get the expected length.
|
|
||||||
* The number of (potentially if str=NULL) written bytes is returned.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
cvtype_max2str(enum cv_type type, char *str, size_t size)
|
|
||||||
{
|
{
|
||||||
int len = 0;
|
b (<b:string>|<b:string expand_dbvar("candidate /x/m1/%s/b")>),cli_set("/x/m1/%s/b");
|
||||||
|
|
||||||
switch (type){
|
|
||||||
case CGV_INT8:
|
|
||||||
len = snprintf(str, size, "%" PRId8, INT8_MAX);
|
|
||||||
break;
|
|
||||||
case CGV_INT16:
|
|
||||||
len = snprintf(str, size, "%" PRId16, INT16_MAX);
|
|
||||||
break;
|
|
||||||
case CGV_INT32:
|
|
||||||
len = snprintf(str, size, "%" PRId32, INT32_MAX);
|
|
||||||
break;
|
|
||||||
case CGV_INT64:
|
|
||||||
len = snprintf(str, size, "%" PRId64, INT64_MAX);
|
|
||||||
break;
|
|
||||||
case CGV_UINT8:
|
|
||||||
len = snprintf(str, size, "%" PRIu8, UINT8_MAX);
|
|
||||||
break;
|
|
||||||
case CGV_UINT16:
|
|
||||||
len = snprintf(str, size, "%" PRIu16, UINT16_MAX);
|
|
||||||
break;
|
|
||||||
case CGV_UINT32:
|
|
||||||
len = snprintf(str, size, "%" PRIu32, UINT32_MAX);
|
|
||||||
break;
|
|
||||||
case CGV_UINT64:
|
|
||||||
len = snprintf(str, size, "%" PRIu64, UINT64_MAX);
|
|
||||||
break;
|
|
||||||
case CGV_DEC64:
|
|
||||||
len = snprintf(str, size, "%" PRId64 ".0", INT64_MAX);
|
|
||||||
break;
|
|
||||||
case CGV_BOOL:
|
|
||||||
len = snprintf(str, size, "true");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Print max value of a CLIgen variable type as string
|
|
||||||
*
|
|
||||||
* The string should be freed after use.
|
|
||||||
* @param[in] type CLIgen variable type
|
|
||||||
* @retval str Malloced string containing value. Should be freed after use.
|
|
||||||
* @see cvtype_max2str
|
|
||||||
*/
|
*/
|
||||||
static char *
|
|
||||||
cvtype_max2str_dup(enum cv_type type)
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
char *str;
|
|
||||||
|
|
||||||
if ((len = cvtype_max2str(type, NULL, 0)) < 0)
|
|
||||||
return NULL;
|
|
||||||
if ((str = (char *)malloc (len+1)) == NULL)
|
|
||||||
return NULL;
|
|
||||||
memset (str, '\0', len+1);
|
|
||||||
if ((cvtype_max2str(type, str, len+1)) < 0){
|
|
||||||
free(str);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
#endif /* HAVE_CLIGEN_MAX2STR */
|
|
||||||
|
|
||||||
/*! Create cligen variable expand entry with xmlkey format string as argument
|
/*! Create cligen variable expand entry with xmlkey format string as argument
|
||||||
* @param[in] h clicon handle
|
* @param[in] h clicon handle
|
||||||
|
|
|
||||||
|
|
@ -377,6 +377,9 @@ main(int argc, char **argv)
|
||||||
/* Join rest of argv to a single command */
|
/* Join rest of argv to a single command */
|
||||||
restarg = clicon_strjoin(argc, argv, " ", __FUNCTION__);
|
restarg = clicon_strjoin(argc, argv, " ", __FUNCTION__);
|
||||||
|
|
||||||
|
/* If several cligen object variables match same preference, select first */
|
||||||
|
cligen_match_cgvar_same(1);
|
||||||
|
|
||||||
/* Call start function in all plugins before we go interactive
|
/* Call start function in all plugins before we go interactive
|
||||||
Pass all args after the standard options to plugin_start
|
Pass all args after the standard options to plugin_start
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -81,9 +81,9 @@ static int xml2csv(FILE *f, cxobj *x, cvec *cvv);
|
||||||
* Returns an expand-type list of commands as used by cligen 'expand'
|
* Returns an expand-type list of commands as used by cligen 'expand'
|
||||||
* functionality.
|
* functionality.
|
||||||
*
|
*
|
||||||
* Assume callback given in a cligen spec: a <x:int expand_dbvar_auto("arg")
|
* Assume callback given in a cligen spec: a <x:int expand_dbvar("arg")
|
||||||
* @param[in] h clicon handle
|
* @param[in] h clicon handle
|
||||||
* @param[in] name Name of this function (eg "expand_dbvar-auto")
|
* @param[in] name Name of this function (eg "expand_dbvar")
|
||||||
* @param[in] cvv The command so far. Eg: cvec [0]:"a 5 b"; [1]: x=5;
|
* @param[in] cvv The command so far. Eg: cvec [0]:"a 5 b"; [1]: x=5;
|
||||||
* @param[in] arg Argument given at the callback "<db> <xmlkeyfmt>"
|
* @param[in] arg Argument given at the callback "<db> <xmlkeyfmt>"
|
||||||
* @param[out] len len of return commands & helptxt
|
* @param[out] len len of return commands & helptxt
|
||||||
|
|
@ -121,7 +121,7 @@ expand_dbvar(void *h,
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* In the example, str = "candidate a[].b[] $!x $!y" */
|
/* In the example, str = "candidate /x/m1/%s/b" */
|
||||||
if ((vec = clicon_strsplit(str, " ", &nvec, __FUNCTION__)) == NULL){
|
if ((vec = clicon_strsplit(str, " ", &nvec, __FUNCTION__)) == NULL){
|
||||||
clicon_err(OE_PLUGIN, errno, "clicon_strsplit");
|
clicon_err(OE_PLUGIN, errno, "clicon_strsplit");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,8 @@ Q: How do you use netconf?
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
As an alternative to cli configuration, you can use netconf
|
As an alternative to cli configuration, you can use netconf
|
||||||
directly. Easiesty is to just pipe netconf commands to the
|
directly. Easiest is to just pipe netconf commands to the
|
||||||
clixon_netconf application.
|
clixon_netconf application.
|
||||||
Example:
|
Example:
|
||||||
echo "<rpc><get-config><source><candidate/></source><configuration/></get-config></rpc>]]>]]>" | clixon_netconf -f /usr/local/etc/routing.conf
|
echo "<rpc><get-config><source><candidate/></source><configuration/></get-config></rpc>]]>]]>" | clixon_netconf -f /usr/local/etc/routing.conf
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ enum clicon_msg_type{
|
||||||
2. uint32: length of value string
|
2. uint32: length of value string
|
||||||
3. string: name of database to change (eg "running")
|
3. string: name of database to change (eg "running")
|
||||||
4. string: key
|
4. string: key
|
||||||
5. string: value
|
5. string: value (can be NULL)
|
||||||
*/
|
*/
|
||||||
CLICON_MSG_XMLPUT, /* Send database entries as XML to backend daemon
|
CLICON_MSG_XMLPUT, /* Send database entries as XML to backend daemon
|
||||||
1. uint32: operation: LV_SET/LV_DELETE
|
1. uint32: operation: LV_SET/LV_DELETE
|
||||||
|
|
|
||||||
|
|
@ -200,7 +200,7 @@ clicon_rpc_change(clicon_handle h,
|
||||||
op,
|
op,
|
||||||
key,
|
key,
|
||||||
val,
|
val,
|
||||||
strlen(val)+1,
|
val?strlen(val)+1:0,
|
||||||
__FUNCTION__)) == NULL)
|
__FUNCTION__)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0)
|
if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0)
|
||||||
|
|
|
||||||
|
|
@ -199,7 +199,9 @@ clicon_msg_change_encode(char *db,
|
||||||
op, str_len, db, key);
|
op, str_len, db, key);
|
||||||
p = 0;
|
p = 0;
|
||||||
len = sizeof(*msg) + 2*sizeof(uint32_t) + strlen(db) + 1 +
|
len = sizeof(*msg) + 2*sizeof(uint32_t) + strlen(db) + 1 +
|
||||||
strlen(key) + 1 + str_len;
|
strlen(key) + str_len;
|
||||||
|
if (str_len)
|
||||||
|
len++; /* if str not null add end of string */
|
||||||
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
||||||
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -221,8 +223,10 @@ clicon_msg_change_encode(char *db,
|
||||||
p += strlen(db)+1;
|
p += strlen(db)+1;
|
||||||
strncpy(msg->op_body+p, key, len-p-hdrlen);
|
strncpy(msg->op_body+p, key, len-p-hdrlen);
|
||||||
p += strlen(key)+1;
|
p += strlen(key)+1;
|
||||||
|
if (str_len){
|
||||||
memcpy(msg->op_body+p, str, str_len);
|
memcpy(msg->op_body+p, str, str_len);
|
||||||
p += str_len;
|
p += str_len;
|
||||||
|
}
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,7 @@ yang2xmlkeyfmt(yang_stmt *ys,
|
||||||
* @param[in] cvv cligen variable vector, one for every wildchar in xkfmt
|
* @param[in] cvv cligen variable vector, one for every wildchar in xkfmt
|
||||||
* @param[out] xk XML key, eg /aaa/17. Free after use
|
* @param[out] xk XML key, eg /aaa/17. Free after use
|
||||||
* @note first and last elements of cvv are not used,..
|
* @note first and last elements of cvv are not used,..
|
||||||
|
* @see cli_dbxml where this function is called
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xmlkeyfmt2key(char *xkfmt,
|
xmlkeyfmt2key(char *xkfmt,
|
||||||
|
|
@ -247,7 +248,7 @@ xmlkeyfmt2key(char *xkfmt,
|
||||||
j,
|
j,
|
||||||
cvec_len(cvv),
|
cvec_len(cvv),
|
||||||
cv_string_get(cvec_i(cvv, 0)));
|
cv_string_get(cvec_i(cvv, 0)));
|
||||||
// goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
|
|
@ -1689,7 +1690,7 @@ xmldb_put_xkey_local(clicon_handle h,
|
||||||
case OP_MERGE:
|
case OP_MERGE:
|
||||||
case OP_REPLACE:
|
case OP_REPLACE:
|
||||||
if (y->ys_keyword == Y_LEAF || y->ys_keyword == Y_LEAF_LIST){
|
if (y->ys_keyword == Y_LEAF || y->ys_keyword == Y_LEAF_LIST){
|
||||||
if (db_set(filename, xk, val, strlen(val)+1) < 0)
|
if (db_set(filename, xk, val, val?strlen(val)+1:0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
/*
|
/*
|
||||||
|
* Yang 1.0 parser according to RFC6020.
|
||||||
|
* It is hopefully useful but not complete
|
||||||
|
* RFC7950 defines Yang version 1.1
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
/*
|
/*
|
||||||
|
* Yang 1.0 parser according to RFC6020.
|
||||||
|
* It is hopefully useful but not complete
|
||||||
|
* RFC7950 defines Yang version 1.1
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
/*
|
/*
|
||||||
|
* Yang 1.0 parser according to RFC6020.
|
||||||
|
* It is hopefully useful but not complete
|
||||||
|
* RFC7950 defines Yang version 1.1
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ static const struct map_str2int ytmap[] = {
|
||||||
{"uint16", CGV_UINT16},
|
{"uint16", CGV_UINT16},
|
||||||
{"uint32", CGV_UINT32},
|
{"uint32", CGV_UINT32},
|
||||||
{"uint64", CGV_UINT64},
|
{"uint64", CGV_UINT64},
|
||||||
{"union", CGV_VOID}, /* Is replaced by actual type */
|
{"union", CGV_REST}, /* Is replaced by actual type */
|
||||||
{NULL, -1}
|
{NULL, -1}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -912,6 +912,7 @@ yang_type_get(yang_stmt *ys,
|
||||||
clicon_err(OE_DB, 0, "%s: mandatory type object is not found", __FUNCTION__);
|
clicon_err(OE_DB, 0, "%s: mandatory type object is not found", __FUNCTION__);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
/* XXX: here we seem to have some problems if type is union */
|
||||||
type = ytype_id(ytype);
|
type = ytype_id(ytype);
|
||||||
if (origtype)
|
if (origtype)
|
||||||
*origtype = type;
|
*origtype = type;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue