diff --git a/apps/snmp/snmp_handler.c b/apps/snmp/snmp_handler.c index 6ebc0643..a19bfe11 100644 --- a/apps/snmp/snmp_handler.c +++ b/apps/snmp/snmp_handler.c @@ -249,7 +249,7 @@ snmp_scalar_set(clicon_handle h, } if ((xb = xml_new("body", xbot, CX_BODY)) == NULL) goto done; - if ((ret = type_snmp2xml(requestvb, reqinfo, requests, &valstr)) < 0) + if ((ret = type_snmp2xml(ys, requestvb, reqinfo, requests, &valstr)) < 0) goto done; if (ret == 0) goto ok; diff --git a/apps/snmp/snmp_lib.c b/apps/snmp/snmp_lib.c index 0735ecf2..96c13981 100644 --- a/apps/snmp/snmp_lib.c +++ b/apps/snmp/snmp_lib.c @@ -99,7 +99,7 @@ static const map_str2int snmp_type_map[] = { {"int32", ASN_INTEGER}, // 2 {"string", ASN_OCTET_STR}, // 4 {"enumeration", ASN_INTEGER}, // 2 special case - {"uint32", ASN_GAUGE}, // 0x42 + {"uint32", ASN_GAUGE}, // 0x42 / 66 {"uint64", ASN_COUNTER64}, // 0x46 / 70 {"boolean", ASN_INTEGER}, // 2 special case -> enumeration {NULL, -1} @@ -168,97 +168,6 @@ type_yang2asn1(yang_stmt *ys, return retval; } -#if 0 -/*! Translate from yang/xml/clixon to SNMP/ASN.1 - * - * @param[in] valstr Clixon/yang/xml string value - * @param[in] cvtype Type of clixon type - * @param[in] reqinfo snmpd API struct for error - * @param[in] requests snmpd API struct for error - * @param[out] snmpval Malloc:ed snmp type - * @param[out] snmplen Length of snmp type - * @retval 1 OK - * @retval 0 Invalid value or type - * @retval -1 Error - */ -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 retval = -1; - int ret; - char *reason = NULL; - size_t cvlen; - cg_var *cv; - - clicon_debug(1, "%s", __FUNCTION__); - if (snmpval == NULL || snmplen == NULL){ - clicon_err(OE_UNIX, EINVAL, "snmpval or snmplen is NULL"); - goto done; - } - if ((cv = cv_new(cvtype)) == NULL){ - clicon_err(OE_UNIX, errno, "cv_new"); - goto done; - } - if ((ret = cv_parse1(valstr, cv, &reason)) < 0) - goto done; - if (ret == 0){ - clicon_debug(1, "%s %s", __FUNCTION__, reason); - netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGTYPE); - goto fail; - } - cvlen = cv_len(cv); - if ((*snmpval = malloc(cvlen)) == NULL){ - clicon_err(OE_UNIX, errno, "malloc"); - goto done; - } - switch (cvtype){ - case CGV_INT32:{ - int i = cv_int32_get(cv); - memcpy(*snmpval, &i, cvlen); - *snmplen = cvlen; - break; - } - case CGV_STRING:{ - strcpy((char*)*snmpval, cv_string_get(cv)); - *snmplen = cvlen; - break; - } - case CGV_UINT32:{ - uint32_t i = cv_uint32_get(cv); - memcpy(*snmpval, &i, cvlen); - *snmplen = cvlen; - break; - } - case CGV_UINT64:{ - uint64_t i = cv_uint32_get(cv); - memcpy(*snmpval, &i, cvlen); - *snmplen = cvlen; - break; - } - default: - clicon_debug(1, "%s %s not supported", __FUNCTION__, cv_type2str(cvtype)); - assert(0); // XXX - netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGTYPE); - goto fail; - break; - } - retval = 1; - done: - clicon_debug(1, "%s %d", __FUNCTION__, retval); - if (reason) - free(reason); - return retval; - fail: - retval = 0; - goto done; -} -#endif - /*! Translate from yang/xml/clixon to SNMP/ASN.1 * * @param[in] snmpval Malloc:ed snmp type @@ -269,37 +178,85 @@ type_yang2snmp(char *valstr, * @retval 1 OK, and valstr set * @retval 0 Invalid value or type * @retval -1 Error + * @see type_xml2snmpstr for snmpget */ int -type_snmp2xml(netsnmp_variable_list *requestvb, +type_snmp2xml(yang_stmt *ys, + netsnmp_variable_list *requestvb, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests, char **valstr) { int retval = -1; - char *cvtypestr; + char *cvstr; enum cv_type cvtype; cg_var *cv; + yang_stmt *yrestype; /* resolved type */ + char *restype; /* resolved type */ + char *origtype=NULL; /* original type */ clicon_debug(1, "%s", __FUNCTION__); if (valstr == NULL){ clicon_err(OE_UNIX, EINVAL, "valstr is NULL"); goto done; } - cvtypestr = (char*)clicon_int2str(snmp_type_map, requestvb->type); - cvtype = cv_str2type(cvtypestr); + cvstr = (char*)clicon_int2str(snmp_type_map, requestvb->type); + /* 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; + /* special case for enum */ + if (strcmp(cvstr, "int32")==0 && strcmp(restype, "enumeration") == 0) + cvstr = "string"; + else if (strcmp(cvstr, "int32")==0 && strcmp(restype, "boolean") == 0) + cvstr = "string"; + cvtype = cv_str2type(cvstr); if ((cv = cv_new(cvtype)) == NULL){ clicon_err(OE_UNIX, errno, "cv_new"); goto done; } switch (requestvb->type){ - case ASN_BOOLEAN: - case ASN_INTEGER: - cv_int32_set(cv, *requestvb->val.integer); + case ASN_INTEGER: // 2 + if (cvtype == CGV_STRING){ /* special case for enum */ + char *xmlstr; + cbuf *cb = NULL; + + if (strcmp(restype, "enumeration") == 0){ + if ((cb = cbuf_new()) == NULL){ + clicon_err(OE_UNIX, errno, "cbuf_new"); + goto done; + } + cprintf(cb, "%ld", *requestvb->val.integer); + if (yang_valstr2enum(yrestype, cbuf_get(cb), &xmlstr) < 0) + goto done; + cbuf_free(cb); + } + else if (strcmp(restype, "boolean") == 0){ + if (*requestvb->val.integer == 1) + xmlstr = "true"; + else + xmlstr = "false"; + } + cv_string_set(cv, xmlstr); + } + else + cv_int32_set(cv, *requestvb->val.integer); break; - case ASN_OCTET_STR: + case ASN_GAUGE: // 0x42 + cv_uint32_set(cv, *requestvb->val.integer); + break; + case ASN_OCTET_STR: // 4 cv_string_set(cv, (char*)requestvb->val.string); break; + case ASN_COUNTER64:{ // 0x46 / 70 + uint64_t u64; + struct counter64 *c64; + c64 = requestvb->val.counter64; + u64 = c64->low; + u64 += c64->high*0x100000000; + cv_uint64_set(cv, u64); + break; + } default: assert(0); // XXX clicon_debug(1, "%s %s not supported", __FUNCTION__, cv_type2str(cvtype)); @@ -307,6 +264,7 @@ type_snmp2xml(netsnmp_variable_list *requestvb, goto fail; break; } + if ((*valstr = cv2str_dup(cv)) == NULL){ clicon_err(OE_UNIX, errno, "cv2str_dup"); goto done; @@ -323,6 +281,7 @@ type_snmp2xml(netsnmp_variable_list *requestvb, /*! 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 + * @see type_snmp2xml for snmpset */ int type_xml2snmpstr(char *xmlstr, @@ -345,7 +304,7 @@ type_xml2snmpstr(char *xmlstr, 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) + if (yang_enum2valstr(yrestype, xmlstr, &str) < 0) goto done; } /* special case for bool: although smidump translates TruthValue to boolean @@ -398,8 +357,6 @@ type_snmpstr2val(char *snmpstr, goto done; } switch (asn1type){ - case ASN_BOOLEAN: // 1 - break; case ASN_INTEGER: // 2 *snmplen = 4; if ((*snmpval = malloc(*snmplen)) == NULL){ diff --git a/apps/snmp/snmp_lib.h b/apps/snmp/snmp_lib.h index b46b5f4c..fd75149c 100644 --- a/apps/snmp/snmp_lib.h +++ b/apps/snmp/snmp_lib.h @@ -61,7 +61,8 @@ typedef struct clixon_snmp_handle clixon_snmp_handle; int snmp_access_str2int(char *modes_str); const char *snmp_msg_int2str(int msg); int type_yang2asn1(yang_stmt *ys, int *asn1_type); -int type_snmp2xml(netsnmp_variable_list *requestvb, +int type_snmp2xml(yang_stmt *ys, + netsnmp_variable_list *requestvb, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests, char **valstr); diff --git a/lib/clixon/clixon_xml_map.h b/lib/clixon/clixon_xml_map.h index 95bd43f2..434d3282 100644 --- a/lib/clixon/clixon_xml_map.h +++ b/lib/clixon/clixon_xml_map.h @@ -70,7 +70,8 @@ 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_valstr2enum(yang_stmt *ytype, char *valstr, char **enumstr); +int yang_enum2valstr(yang_stmt *ytype, char *enumstr, char **valstr); 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); diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index b8635998..b048fe09 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -1810,32 +1810,63 @@ 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 Integer string value + * @param[out] enumstr Value of enum, dont free + */ +int +yang_valstr2enum(yang_stmt *ytype, + char *valstr, + char **enumstr) +{ + int retval = -1; + yang_stmt *yenum = NULL; + yang_stmt *yval; + + if (enumstr == NULL){ + clicon_err(OE_UNIX, EINVAL, "str is NULL"); + goto done; + } + while ((yenum = yn_each(ytype, yenum)) != NULL) { + if ((yval = yang_find(yenum, Y_VALUE, NULL)) == NULL) + goto done; + if (strcmp(yang_argument_get(yval), valstr) == 0) + break; + } + if (yenum) + *enumstr = yang_argument_get(yenum); + retval = 0; + done: + return retval; +} /*! 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) + * @param[in] enumstr Value of enum + * @param[out] valstr Corresponding string containing an int (direct pointer, dont free) */ int -yang_enum2intstr(yang_stmt *ytype, - char *valstr, - char **intstr) +yang_enum2valstr(yang_stmt *ytype, + char *enumstr, + char **valstr) { int retval = -1; yang_stmt *yenum; yang_stmt *yval; - if (intstr == NULL){ - clicon_err(OE_UNIX, EINVAL, "intstr is NULL"); + if (valstr == NULL){ + clicon_err(OE_UNIX, EINVAL, "valstr is NULL"); goto done; } - if ((yenum = yang_find(ytype, Y_ENUM, valstr)) == NULL) + if ((yenum = yang_find(ytype, Y_ENUM, enumstr)) == 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); + *valstr = yang_argument_get(yval); retval = 0; done: return retval; @@ -1883,7 +1914,7 @@ yang_enum_int_value(cxobj *node, } if (yrestype==NULL || strcmp(yang_argument_get(yrestype), "enumeration")) goto done; - if (yang_enum2intstr(yrestype, xml_body(node), &intstr) < 0) + if (yang_enum2valstr(yrestype, xml_body(node), &intstr) < 0) goto done; /* reason is string containing why int could not be parsed */ if (parse_int32(intstr, val, &reason) < 0) diff --git a/test/test_snmp_set.sh b/test/test_snmp_set.sh index b3afeefe..66f43142 100755 --- a/test/test_snmp_set.sh +++ b/test/test_snmp_set.sh @@ -29,13 +29,14 @@ cat < $cfg $cfg ${YANG_INSTALLDIR} ${YANG_STANDARD_DIR} - ${MIB_GENERATED_YANG_DIR} + + /home/olof/src/mib-yangs $fyang $dir/$APPNAME.sock /var/tmp/$APPNAME.pidfile $dir unix:$SOCK - NET-SNMP-EXAMPLES-MIB + CLIXON-TYPES-MIB EOF @@ -44,10 +45,10 @@ module clixon-example{ yang-version 1.1; namespace "urn:example:clixon"; prefix ex; - import NET-SNMP-EXAMPLES-MIB { - prefix "net-snmp-examples"; + import CLIXON-TYPES-MIB { + prefix "clixon-types"; } - deviation "/net-snmp-examples:NET-SNMP-EXAMPLES-MIB" { + deviation "/clixon-types:CLIXON-TYPES-MIB" { deviate replace { config true; } @@ -55,13 +56,6 @@ module clixon-example{ } EOF -# This is state data written to file that backend reads from (on request) -cat < $fstate - - x - -EOF - function testinit(){ new "test params: -f $cfg" @@ -104,8 +98,29 @@ testinit # NET-SNMP-EXAMPLES-MIB::netSnmpExamples MIB=".1.3.6.1.4.1.8072.2" -OID1="${MIB}.1.1" # netSnmpExampleInteger -OID3="${MIB}.1.3" # netSnmpExampleString +OID1="${MIB}.1.1" # netSnmpExampleInteger +OID2="${MIB}.1.2" # netSnmpExampleSleeper +OID3="${MIB}.1.3" # netSnmpExampleString +OID4="${MIB}.1.4" # ifTableLastChange +OID5="${MIB}.1.5" # ifType +OID6="${MIB}.1.6" # ifSpeed +OID7="${MIB}.1.7" # ifAdminStatus +OID8="${MIB}.1.8" # ifInOctets +OID9="${MIB}.1.9" # ifHCInOctets +OID10="${MIB}.1.10" # ifPromiscuousMode +OID11="${MIB}.1.11" # ifCounterDiscontinuityTime +OID12="${MIB}.1.12" # ifStackStatus +OID13="${MIB}.2.1" # netSnmpIETFWGTable +OID14="${MIB}.2.1.1" # netSnmpIETFWGEntry +OID15="${MIB}.2.1.1.1" # nsIETFWGName +OID16="${MIB}.2.1.1.2" # nsIETFWGChair1 +OID17="${MIB}.2.1.1.3" # nsIETFWGChair2 +OID18="${MIB}.2.2" # netSnmpHostsTable +OID19="${MIB}.2.2.1.1" # netSnmpHostName +OID20="${MIB}.2.2.1.2" # netSnmpHostAddressType +OID21="${MIB}.2.2.1.3" # netSnmpHostAddress +OID22="${MIB}.2.2.1.4" # netSnmpHostStorage +OID23="${MIB}.2.2.1.5" # netSnmpHostRowStatus new "Test SNMP get for default value" expectpart "$($snmpget $OID1)" 0 "$OID1 = INTEGER: 42" @@ -117,7 +132,7 @@ new "Get new value" expectpart "$($snmpget $OID1)" 0 "$OID1 = INTEGER: 1234" new "Set new value via NETCONF" -expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "none999" "" "" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "none999" "" "" new "netconf commit" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" @@ -134,6 +149,111 @@ expectpart "$($snmpset $OID3 s foobar)" 0 "$OID3 = STRING: foobar" new "Get new value" expectpart "$($snmpget $OID3)" 0 "$OID3 = STRING: foobar" +NAME=ifTableLastChange +OID=$OID4 +VALUE=12345678 +TYPE=Gauge32 # TimeTicks + +new "Get $NAME" +expectpart "$($snmpget $OID)" 0 "$OID = No Such Instance currently exists at this OID" + +new "Set $NAME $VALUE" +expectpart "$($snmpset $OID u $VALUE)" 0 "$OID = $TYPE: $VALUE" + +new "Get $NAME $VALUE" +expectpart "$($snmpget $OID)" 0 "$OID = $TYPE: $VALUE" + +NAME=ifType +OID=$OID5 +VALUE=48 # modem(48) +TYPE=INTEGER # enum IANAifType modem(48) + +new "Set $NAME $VALUE" +expectpart "$($snmpset $OID i $VALUE)" 0 "$OID = $TYPE: $VALUE" + +new "Get $NAME $VALUE" +expectpart "$($snmpget $OID)" 0 "$OID = $TYPE: $VALUE" + +NAME=ifSpeed +OID=$OID6 +VALUE=123123123 +TYPE=Gauge32 + +new "Set $NAME $VALUE" +expectpart "$($snmpset $OID u $VALUE)" 0 "$OID = $TYPE: $VALUE" + +new "Get $NAME $VALUE" +expectpart "$($snmpget $OID)" 0 "$OID = $TYPE: $VALUE" + +NAME=ifAdminStatus +OID=$OID7 +VALUE=3 # testing(3) +TYPE=INTEGER + +new "Set $NAME $VALUE" +expectpart "$($snmpset $OID i $VALUE)" 0 "$OID = $TYPE: $VALUE" + +new "Get $NAME $VALUE" +expectpart "$($snmpget $OID)" 0 "$OID = $TYPE: $VALUE" + +NAME=ifInOctets +OID=$OID8 +VALUE=123456 +TYPE=Gauge32 + +new "Set $NAME $VALUE" +expectpart "$($snmpset $OID u $VALUE)" 0 "$OID = $TYPE: $VALUE" + +new "Get $NAME $VALUE" +expectpart "$($snmpget $OID)" 0 "$OID = $TYPE: $VALUE" + +if false; then # XXX i/u/c doesnt work? +NAME=ifHCInOctets +OID=$OID9 +VALUE=4294967296 +TYPE=Counter64 + +new "Set $NAME $VALUE" +#expectpart "$($snmpset $OID C $VALUE)" 0 "$OID = $TYPE: $VALUE" + +new "Get $NAME $VALUE" +expectpart "$($snmpget $OID)" 0 "$OID = $TYPE: $VALUE" + +fi + +NAME=ifPromiscuousMode +OID=$OID10 +VALUE=1 # true(1) +TYPE=INTEGER + +new "Set $NAME $VALUE" +expectpart "$($snmpset $OID i $VALUE)" 0 "$OID = $TYPE: $VALUE" + +new "Get $NAME $VALUE" +expectpart "$($snmpget $OID)" 0 "$OID = $TYPE: $VALUE" + +NAME=ifCounterDiscontinuityTime +OID=$OID11 +VALUE=1234567890 +TYPE=Gauge32 + +new "Set $NAME $VALUE" +expectpart "$($snmpset $OID u $VALUE)" 0 "$OID = $TYPE: $VALUE" + +new "Get $NAME $VALUE" +expectpart "$($snmpget $OID)" 0 "$OID = $TYPE: $VALUE" + +NAME=ifStackStatus +OID=$OID12 +VALUE=1 # active(1) +TYPE=INTEGER + +new "Set $NAME $VALUE" +expectpart "$($snmpset $OID i $VALUE)" 0 "$OID = $TYPE: $VALUE" + +new "Get $NAME $VALUE" +expectpart "$($snmpget $OID)" 0 "$OID = $TYPE: $VALUE" + new "Cleaning up" testexit diff --git a/test/test_snmp_types.sh b/test/test_snmp_types.sh index 7c81c539..7baede11 100755 --- a/test/test_snmp_types.sh +++ b/test/test_snmp_types.sh @@ -135,15 +135,15 @@ MIB=".1.3.6.1.4.1.8072.2" OID1="${MIB}.1.1" # netSnmpExampleInteger OID2="${MIB}.1.2" # netSnmpExampleSleeper OID3="${MIB}.1.3" # netSnmpExampleString -OID4="${MIB}.1.4" # ifTableLastChange -OID5="${MIB}.1.5" # ifType -OID6="${MIB}.1.6" # ifSpeed -OID7="${MIB}.1.7" # ifAdminStatus -OID8="${MIB}.1.8" # ifInOctets -OID9="${MIB}.1.9" # ifHCInOctets -OID10="${MIB}.1.10" # ifPromiscuousMode -OID11="${MIB}.1.11" # ifCounterDiscontinuityTime -OID12="${MIB}.1.12" # ifStackStatus +OID4="${MIB}.1.4" # ifTableLastChange 12345678 +OID5="${MIB}.1.5" # ifType modem(48) +OID6="${MIB}.1.6" # ifSpeed 123123123 +OID7="${MIB}.1.7" # ifAdminStatus testing(3) +OID8="${MIB}.1.8" # ifInOctets 123456 +OID9="${MIB}.1.9" # ifHCInOctets 4294967296 +OID10="${MIB}.1.10" # ifPromiscuousMode true(1) +OID11="${MIB}.1.11" # ifCounterDiscontinuityTime 1234567890 TimeStamp +OID12="${MIB}.1.12" # ifStackStatus active(1) OID13="${MIB}.2.1" # netSnmpIETFWGTable OID14="${MIB}.2.1.1" # netSnmpIETFWGEntry OID15="${MIB}.2.1.1.1" # nsIETFWGName @@ -156,7 +156,6 @@ OID21="${MIB}.2.2.1.3" # netSnmpHostAddress OID22="${MIB}.2.2.1.4" # netSnmpHostStorage OID23="${MIB}.2.2.1.5" # netSnmpHostRowStatus - new "$snmpget" new "Test SNMP get netSnmpExampleInteger" @@ -177,13 +176,13 @@ expectpart "$($snmpget $OID3)" 0 "$OID3 = STRING: This is not default" --not-- " new "Test SNMP getnext netSnmpExampleString" expectpart "$($snmpgetnext $OID3)" 0 "" -new "Test SNMP get ipTableLastChnage" +new "Test SNMP get ipTableLastChnage" # TimeTicks expectpart "$($snmpget $OID4)" 0 "$OID4 = Gauge32: 12345678" -new "Test SNMP getnext ipTableLastChnage" +new "Test SNMP getnext ipTableLastChange" expectpart "$($snmpgetnext $OID4)" 0 "" -new "Test SNMP get ifType" +new "Test SNMP get ifType" # modem(48) expectpart "$($snmpget $OID5)" 0 "$OID5 = INTEGER: 48" new "Test SNMP getnext ifType"