SNMP frontend: Reworked types for GET types translation
YANG enum type, split up enum to int into two functions
This commit is contained in:
parent
31fea9e6c8
commit
aa95ead1cc
6 changed files with 252 additions and 72 deletions
|
|
@ -126,54 +126,69 @@ snmp_scalar_get(clicon_handle h,
|
|||
yang_stmt *ys,
|
||||
netsnmp_variable_list *requestvb,
|
||||
char *defaultval,
|
||||
enum cv_type cvtype,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests)
|
||||
{
|
||||
int retval = -1;
|
||||
cvec *nsc = NULL;
|
||||
char *xpath = NULL;
|
||||
cxobj *xt = NULL;
|
||||
cxobj *xerr;
|
||||
cxobj *x;
|
||||
char *valstr = NULL;
|
||||
int retval = -1;
|
||||
cvec *nsc = NULL;
|
||||
char *xpath = NULL;
|
||||
cxobj *xt = NULL;
|
||||
cxobj *xerr;
|
||||
cxobj *x;
|
||||
char *snmpstr = NULL;
|
||||
u_char *snmpval = NULL;
|
||||
size_t snmplen;
|
||||
int ret;
|
||||
size_t snmplen = 0;
|
||||
int ret;
|
||||
int asn1type;
|
||||
char *reason = NULL;
|
||||
|
||||
/* Prepare backend call by constructing namespace context */
|
||||
if (xml_nsctx_yang(ys, &nsc) < 0)
|
||||
goto done;
|
||||
/* Create xpath from yang (XXX works not for lists) */
|
||||
if (yang2xpath(ys, &xpath) < 0)
|
||||
goto done;
|
||||
/* Do the backend call */
|
||||
if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, &xt) < 0)
|
||||
goto done;
|
||||
/* Detect error XXX Error handling could improve */
|
||||
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||
clixon_netconf_error(xerr, "clicon_rpc_get", NULL);
|
||||
goto done;
|
||||
}
|
||||
/* Get value, either from xml, or smiv2 default */
|
||||
if ((x = xpath_first(xt, nsc, "%s", xpath)) != NULL) {
|
||||
valstr = xml_body(x);
|
||||
/*
|
||||
* The xml to snmp value conversion is done here. It is done in two steps:
|
||||
* 1. From XML to SNMP string, there is a special case for enumeration, and for default value
|
||||
* 2. From SNMP string to SNMP binary value which invloves parsing
|
||||
*/
|
||||
if ((x = xpath_first(xt, nsc, "%s", xpath)) != NULL){
|
||||
assert(xml_spec(x) == ys);
|
||||
if (type_xml2snmpstr(xml_body(x), ys, &snmpstr) < 0)
|
||||
goto done;
|
||||
}
|
||||
else if (defaultval != NULL){
|
||||
if ((snmpstr = strdup(defaultval)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else if ((valstr = defaultval) != NULL)
|
||||
;
|
||||
else{
|
||||
netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE);
|
||||
goto ok;
|
||||
}
|
||||
if ((ret = type_yang2snmp(valstr, cvtype, reqinfo, requests, &snmpval, &snmplen)) < 0)
|
||||
if (type_yang2asn1(ys, &asn1type) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto ok;
|
||||
|
||||
/* 1. use cligen object and get rwa buf / size from that, OR
|
||||
* + have parse function from YANG
|
||||
* - does not have
|
||||
* 2. use union netsnmp_vardata and pass that here?
|
||||
* 3. Make cv2asn1 conversion function <--
|
||||
if ((ret = type_snmpstr2val(snmpstr, asn1type, &snmpval, &snmplen, &reason)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
clicon_debug(1, "%s %s", __FUNCTION__, reason);
|
||||
netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGTYPE);
|
||||
goto ok;
|
||||
}
|
||||
/* see snmplib/snmp_client. somewhat indirect
|
||||
*/
|
||||
|
||||
/* see snmplib/snmp_client.c */
|
||||
requestvb->type = asn1type; // ASN_NULL on input
|
||||
if (snmp_set_var_value(requestvb,
|
||||
snmpval,
|
||||
snmplen) != 0){
|
||||
|
|
@ -183,6 +198,10 @@ snmp_scalar_get(clicon_handle h,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (reason)
|
||||
free(reason);
|
||||
if (snmpstr)
|
||||
free(snmpstr);
|
||||
if (snmpval)
|
||||
free(snmpval);
|
||||
if (xt)
|
||||
|
|
@ -230,7 +249,7 @@ snmp_scalar_set(clicon_handle h,
|
|||
}
|
||||
if ((xb = xml_new("body", xbot, CX_BODY)) == NULL)
|
||||
goto done;
|
||||
if ((ret = type_snmp2yang(requestvb, reqinfo, requests, &valstr)) < 0)
|
||||
if ((ret = type_snmp2xml(requestvb, reqinfo, requests, &valstr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto ok;
|
||||
|
|
@ -273,7 +292,6 @@ snmp_scalar_handler(netsnmp_mib_handler *handler,
|
|||
yang_stmt *ys;
|
||||
int asn1_type;
|
||||
netsnmp_variable_list *requestvb; /* sub of requests */
|
||||
enum cv_type cvtype;
|
||||
|
||||
/*
|
||||
* can be used to pass information on a per-pdu basis from a
|
||||
|
|
@ -312,20 +330,19 @@ snmp_scalar_handler(netsnmp_mib_handler *handler,
|
|||
SNMP_NOSUCHOBJECT);
|
||||
return SNMP_ERR_NOERROR;
|
||||
#endif
|
||||
if (yang2snmp_types(ys, &asn1_type, &cvtype) < 0)
|
||||
goto done;
|
||||
|
||||
/* see net-snmp/agent/snmp_agent.h / net-snmp/library/snmp.h */
|
||||
switch (reqinfo->mode) {
|
||||
case MODE_GET: /* 160 */
|
||||
requestvb->type = asn1_type; // ASN_NULL on input
|
||||
if (snmp_scalar_get(sh->sh_h, ys, requestvb, sh->sh_default, cvtype, reqinfo, requests) < 0)
|
||||
if (snmp_scalar_get(sh->sh_h, ys, requestvb, sh->sh_default, reqinfo, requests) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case MODE_GETNEXT: /* 161 */
|
||||
assert(0); // Not seen?
|
||||
break;
|
||||
case MODE_SET_RESERVE1: /* 0 */
|
||||
/* Translate from YANG ys leaf type to SNMP asn1.1 type ids (not value), also cvtype */
|
||||
if (type_yang2asn1(ys, &asn1_type) < 0)
|
||||
goto done;
|
||||
if (requestvb->type != asn1_type)
|
||||
netsnmp_set_request_error(reqinfo, requests,
|
||||
SNMP_ERR_WRONGTYPE);
|
||||
|
|
|
|||
|
|
@ -96,17 +96,12 @@ static const map_str2int snmp_access_map[] = {
|
|||
* XXX TimeTicks
|
||||
*/
|
||||
static const map_str2int snmp_type_map[] = {
|
||||
|
||||
{"int32", ASN_INTEGER},
|
||||
{"string", ASN_OCTET_STR},
|
||||
{"uint32", ASN_INTEGER},
|
||||
{"uint64", ASN_INTEGER},
|
||||
// {"bool", ASN_BOOLEAN},
|
||||
// {"empty", ASN_NULL},
|
||||
// {"bits", ASN_BIT_STR},
|
||||
// {"", ASN_OBJECT_ID},
|
||||
// {"", ASN_SEQUENCE},
|
||||
// {"", ASN_SET},
|
||||
{"int32", ASN_INTEGER}, // 2
|
||||
{"string", ASN_OCTET_STR}, // 4
|
||||
{"enumeration", ASN_INTEGER}, // 2 special case
|
||||
{"uint32", ASN_GAUGE}, // 0x42
|
||||
{"uint64", ASN_COUNTER64}, // 0x46 / 70
|
||||
{"boolean", ASN_INTEGER}, // 2 special case -> enumeration
|
||||
{NULL, -1}
|
||||
};
|
||||
|
||||
|
|
@ -136,18 +131,18 @@ snmp_msg_int2str(int msg)
|
|||
{
|
||||
return clicon_int2str(snmp_msg_map, msg);
|
||||
}
|
||||
|
||||
/*! Translate from YANG to SNMP asn1.1 type ids (not value)
|
||||
*
|
||||
* @param[in] ys YANG leaf node
|
||||
* @param[out] asn1_type ASN.1 type id
|
||||
* @param[out] cvtype Clixon cv type
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see type_yang2snmp, yang only
|
||||
*/
|
||||
int
|
||||
yang2snmp_types(yang_stmt *ys,
|
||||
int *asn1_type,
|
||||
enum cv_type *cvtype)
|
||||
type_yang2asn1(yang_stmt *ys,
|
||||
int *asn1_type)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yrestype; /* resolved type */
|
||||
|
|
@ -163,18 +158,17 @@ yang2snmp_types(yang_stmt *ys,
|
|||
if ((at = clicon_str2int(snmp_type_map, restype)) < 0){
|
||||
clicon_err(OE_YANG, 0, "No snmp translation for YANG %s type:%s",
|
||||
yang_argument_get(ys), restype);
|
||||
// goto done;
|
||||
goto done;
|
||||
}
|
||||
if (asn1_type)
|
||||
*asn1_type = at;
|
||||
if (cvtype && clicon_type2cv(origtype, restype, ys, cvtype) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s type:%s", __FUNCTION__, restype);
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*! Translate from yang/xml/clixon to SNMP/ASN.1
|
||||
*
|
||||
* @param[in] valstr Clixon/yang/xml string value
|
||||
|
|
@ -263,6 +257,8 @@ type_yang2snmp(char *valstr,
|
|||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! Translate from yang/xml/clixon to SNMP/ASN.1
|
||||
*
|
||||
* @param[in] snmpval Malloc:ed snmp type
|
||||
|
|
@ -275,10 +271,10 @@ type_yang2snmp(char *valstr,
|
|||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
type_snmp2yang(netsnmp_variable_list *requestvb,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests,
|
||||
char **valstr)
|
||||
type_snmp2xml(netsnmp_variable_list *requestvb,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests,
|
||||
char **valstr)
|
||||
{
|
||||
int retval = -1;
|
||||
char *cvtypestr;
|
||||
|
|
@ -324,6 +320,146 @@ type_snmp2yang(netsnmp_variable_list *requestvb,
|
|||
goto done;
|
||||
}
|
||||
|
||||
/*! Given xml value and YANG,m return corresponding malloced snmp string
|
||||
* There is a special case for enumeration which is integer in snmp, string in YANG
|
||||
* @param[in] xmlstr
|
||||
*/
|
||||
int
|
||||
type_xml2snmpstr(char *xmlstr,
|
||||
yang_stmt *ys,
|
||||
char **snmpstr)
|
||||
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yrestype; /* resolved type */
|
||||
char *restype; /* resolved type */
|
||||
char *origtype=NULL; /* original type */
|
||||
char *str = NULL;
|
||||
|
||||
if (snmpstr == NULL){
|
||||
clicon_err(OE_UNIX, EINVAL, "snmpstr");
|
||||
goto done;
|
||||
}
|
||||
/* Get yang type of leaf and trasnslate to ASN.1 */
|
||||
if (yang_type_get(ys, &origtype, &yrestype, NULL, NULL, NULL, NULL, NULL) < 0)
|
||||
goto done;
|
||||
restype = yrestype?yang_argument_get(yrestype):NULL;
|
||||
if (strcmp(restype, "enumeration") == 0){ /* special case for enum */
|
||||
if (yang_enum2intstr(yrestype, xmlstr, &str) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* special case for bool: although smidump translates TruthValue to boolean
|
||||
* and there is an ASN_BOOLEAN constant:
|
||||
* 1) there is no code for ASN_BOOLEAN and
|
||||
* 2) Truthvalue actually translates to enum true(1)/false(0)
|
||||
*/
|
||||
else if (strcmp(restype, "boolean") == 0){
|
||||
if (strcmp(xmlstr, "false")==0)
|
||||
str = "0";
|
||||
else
|
||||
str = "1";
|
||||
}
|
||||
else{
|
||||
str = xmlstr;
|
||||
}
|
||||
if ((*snmpstr = strdup(str)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Given snmp string value (as translated frm XML) parse into snmp value
|
||||
*
|
||||
* @param[in] snmpstr SNMP type string
|
||||
* @param[in] asn1type ASN.1 type id
|
||||
* @param[out] snmpval Malloc:ed snmp type
|
||||
* @param[out] snmplen Length of snmp type
|
||||
* @param[out] reason Error reason if retval is 0
|
||||
* @retval 1 OK
|
||||
* @retval 0 Invalid
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
type_snmpstr2val(char *snmpstr,
|
||||
int asn1type,
|
||||
u_char **snmpval,
|
||||
size_t *snmplen,
|
||||
char **reason)
|
||||
{
|
||||
int retval = -1;
|
||||
int ret;
|
||||
|
||||
if (snmpval == NULL || snmplen == NULL){
|
||||
clicon_err(OE_UNIX, EINVAL, "snmpval or snmplen is NULL");
|
||||
goto done;
|
||||
}
|
||||
switch (asn1type){
|
||||
case ASN_BOOLEAN: // 1
|
||||
break;
|
||||
case ASN_INTEGER: // 2
|
||||
*snmplen = 4;
|
||||
if ((*snmpval = malloc(*snmplen)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
if ((ret = parse_int32(snmpstr, (int32_t*)*snmpval, reason)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
break;
|
||||
case ASN_GAUGE: // 0x42
|
||||
*snmplen = 4;
|
||||
if ((*snmpval = malloc(*snmplen)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
if ((ret = parse_uint32(snmpstr, (uint32_t*)*snmpval, reason)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
|
||||
break;
|
||||
case ASN_OCTET_STR: // 4
|
||||
*snmplen = strlen(snmpstr)+1;
|
||||
if ((*snmpval = (u_char*)strdup((snmpstr))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case ASN_COUNTER64:{ // 0x46 / 70
|
||||
uint64_t u64;
|
||||
struct counter64 *c64;
|
||||
*snmplen = sizeof(struct counter64); // 16!
|
||||
if ((*snmpval = malloc(*snmplen)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(*snmpval, 0, *snmplen);
|
||||
if ((ret = parse_uint64(snmpstr, &u64, reason)) < 0)
|
||||
goto done;
|
||||
c64 = (struct counter64 *)*snmpval;
|
||||
c64->low = u64&0xffffffff;
|
||||
c64->high = u64/0x100000000;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
retval = 1;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Construct an xpath from yang statement, internal fn using cb
|
||||
* Recursively construct it to the top.
|
||||
* @param[in] ys Yang statement
|
||||
|
|
|
|||
|
|
@ -60,14 +60,14 @@ typedef struct clixon_snmp_handle clixon_snmp_handle;
|
|||
*/
|
||||
int snmp_access_str2int(char *modes_str);
|
||||
const char *snmp_msg_int2str(int msg);
|
||||
int yang2snmp_types(yang_stmt *ys, int *asn1_type, enum cv_type *cvtype);
|
||||
int type_yang2snmp(char *valstr, enum cv_type cvtype,
|
||||
netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests,
|
||||
u_char **snmpval, size_t *snmplen);
|
||||
int type_snmp2yang(netsnmp_variable_list *requestvb,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests,
|
||||
char **valstr);
|
||||
int type_yang2asn1(yang_stmt *ys, int *asn1_type);
|
||||
int type_snmp2xml(netsnmp_variable_list *requestvb,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests,
|
||||
char **valstr);
|
||||
int type_xml2snmpstr(char *xmlstr, yang_stmt *ys, char **snmpstr);
|
||||
|
||||
int type_snmpstr2val(char *snmpstr, int asn1type, u_char **snmpval, size_t *snmplen, char **reason);
|
||||
int yang2xpath(yang_stmt *ys, char **xpath);
|
||||
int clixon_table_create(netsnmp_table_data_set *table, yang_stmt *ys, clicon_handle h);
|
||||
|
||||
|
|
|
|||
|
|
@ -205,8 +205,8 @@ mib_yang_leaf(clicon_handle h,
|
|||
}
|
||||
if (yang_extension_value(ys, "max-access", IETF_YANG_SMIV2_NS, NULL, &modes_str) < 0)
|
||||
goto done;
|
||||
#if 0 /* Sanity check of types */
|
||||
if (yang2snmp_types(ys, NULL, NULL) < 0)
|
||||
#if 1 /* Sanity check of types */
|
||||
if (type_yang2asn1(ys, NULL) < 0)
|
||||
goto done;
|
||||
#endif
|
||||
/* Get modes (access) read-only, read-write, not-accessible, oaccessible-for-notify
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ int xml2xpath(cxobj *x, cvec *nsc, char **xpath);
|
|||
int assign_namespace_element(cxobj *x0, cxobj *x1, cxobj *x1p);
|
||||
int assign_namespace_body(cxobj *x0, cxobj *x1);
|
||||
int xml_merge(cxobj *x0, cxobj *x1, yang_stmt *yspec, char **reason);
|
||||
int yang_enum2intstr(yang_stmt *ytype, char *value, char **intstr);
|
||||
int yang_enum_int_value(cxobj *node, int32_t *val);
|
||||
int xml_copy_marked(cxobj *x0, cxobj *x1);
|
||||
int yang_check_when_xpath(cxobj *xn, cxobj *xp, yang_stmt *yn, int *hit, int *nrp, char **xpathp);
|
||||
|
|
|
|||
|
|
@ -1810,6 +1810,37 @@ xml_merge(cxobj *x0,
|
|||
goto done;
|
||||
}
|
||||
|
||||
|
||||
/*! Given a YANG (enum) type node and a value, return the string containing corresponding int str
|
||||
*
|
||||
* @param[in] ytype YANG type noden
|
||||
* @param[in] valstr Value of enum
|
||||
* @param[out] intstr Corresponding string containing an int (direct pointer, dont free)
|
||||
*/
|
||||
int
|
||||
yang_enum2intstr(yang_stmt *ytype,
|
||||
char *valstr,
|
||||
char **intstr)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yenum;
|
||||
yang_stmt *yval;
|
||||
|
||||
if (intstr == NULL){
|
||||
clicon_err(OE_UNIX, EINVAL, "intstr is NULL");
|
||||
goto done;
|
||||
}
|
||||
if ((yenum = yang_find(ytype, Y_ENUM, valstr)) == NULL)
|
||||
goto done;
|
||||
/* Should assign value if yval not found */
|
||||
if ((yval = yang_find(yenum, Y_VALUE, NULL)) == NULL)
|
||||
goto done;
|
||||
*intstr = yang_argument_get(yval);
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Get integer value from xml node from yang enumeration
|
||||
* @param[in] node XML node in a tree
|
||||
* @param[out] val Integer value returned
|
||||
|
|
@ -1832,9 +1863,8 @@ yang_enum_int_value(cxobj *node,
|
|||
yang_stmt *ys;
|
||||
yang_stmt *ytype;
|
||||
yang_stmt *yrestype; /* resolved type */
|
||||
yang_stmt *yenum;
|
||||
yang_stmt *yval;
|
||||
char *reason = NULL;
|
||||
char *intstr = NULL;
|
||||
|
||||
if (node == NULL)
|
||||
goto done;
|
||||
|
|
@ -1853,20 +1883,16 @@ yang_enum_int_value(cxobj *node,
|
|||
}
|
||||
if (yrestype==NULL || strcmp(yang_argument_get(yrestype), "enumeration"))
|
||||
goto done;
|
||||
if ((yenum = yang_find(yrestype, Y_ENUM, xml_body(node))) == NULL)
|
||||
goto done;
|
||||
/* Should assign value if yval not found */
|
||||
if ((yval = yang_find(yenum, Y_VALUE, NULL)) == NULL)
|
||||
if (yang_enum2intstr(yrestype, xml_body(node), &intstr) < 0)
|
||||
goto done;
|
||||
/* reason is string containing why int could not be parsed */
|
||||
if (parse_int32(yang_argument_get(yval), val, &reason) < 0)
|
||||
if (parse_int32(intstr, val, &reason) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Given XML tree x0 with marked nodes, copy marked nodes to new tree x1
|
||||
* Two marks are used: XML_FLAG_MARK and XML_FLAG_CHANGE
|
||||
*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue