SNMP frontend: SNMP2YANG type conversion for snmpset

This commit is contained in:
Olof hagsand 2022-05-23 14:32:44 +02:00
parent d78f6c5ac7
commit 675f4c9f7e
7 changed files with 253 additions and 144 deletions

View file

@ -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;

View file

@ -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){

View file

@ -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);

View file

@ -72,7 +72,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);

View file

@ -1922,32 +1922,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;
@ -1995,7 +2026,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)

View file

@ -29,13 +29,14 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>${YANG_INSTALLDIR}</CLICON_YANG_DIR>
<CLICON_YANG_DIR>${YANG_STANDARD_DIR}</CLICON_YANG_DIR>
<CLICON_YANG_DIR>${MIB_GENERATED_YANG_DIR}</CLICON_YANG_DIR>
<!--CLICON_YANG_DIR>${MIB_GENERATED_YANG_DIR}</CLICON_YANG_DIR-->
<CLICON_YANG_DIR>/home/olof/src/mib-yangs</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_SOCK>$dir/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/var/tmp/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
<CLICON_SNMP_AGENT_SOCK>unix:$SOCK</CLICON_SNMP_AGENT_SOCK>
<CLICON_SNMP_MIB>NET-SNMP-EXAMPLES-MIB</CLICON_SNMP_MIB>
<CLICON_SNMP_MIB>CLIXON-TYPES-MIB</CLICON_SNMP_MIB>
</clixon-config>
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 <<EOF > $fstate
<sender-state xmlns="urn:example:example">
<ref>x</ref>
</sender-state>
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" "<rpc $DEFAULTNS><edit-config><default-operation>none</default-operation><target><candidate/></target><config><NET-SNMP-EXAMPLES-MIB xmlns=\"urn:ietf:params:xml:ns:yang:smiv2:NET-SNMP-EXAMPLES-MIB\"><netSnmpExampleScalars><netSnmpExampleInteger>999</netSnmpExampleInteger></netSnmpExampleScalars></NET-SNMP-EXAMPLES-MIB></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><default-operation>none</default-operation><target><candidate/></target><config><CLIXON-TYPES-MIB xmlns=\"urn:ietf:params:xml:ns:yang:smiv2:CLIXON-TYPES-MIB\"><netSnmpExampleScalars><netSnmpExampleInteger>999</netSnmpExampleInteger></netSnmpExampleScalars></CLIXON-TYPES-MIB></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
new "netconf commit"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><commit/></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
@ -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

View file

@ -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"