以前、以下の記事を書いた時に、
akrad.hatenablog.com
SNMPのgetbulkで出てくる nonRepeaters が何なのかあまり分かっていなかったので、今回それを調べてみた。
まず、nonRepeaters については、
http://net-snmp.sourceforge.net/wiki/index.php/GETBULK
に以下の記載がある。
「the number of objects that are only expected to return a single GETNEXT instance, not multiple instances. Managers frequently request the value of sysUpTime and only want that instance plus a list of other objects.」
ざっくり言うと、nonRepeaters は、getbulkで取得対象とした OID の中で繰り返し取得を行わないものの個数であると思われる。例えば、getbulk で OID1, OID2, OID3 配下のMIBを getbulk で取得するとして、nonRepeaters を 2 とすると、OID1 と OID2 については繰り返し取得を実施せず、OID3 についてだけは繰り返し取得を実施する。
以下、上記の解釈で正しいのか、サンプルプログラムを作って調査した。
import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.*;
import org.snmp4j.transport.DefaultUdpTransportMapping;
public class Snmpbulk {
public static void main(String[] args) {
String targetAddr = "localhost";
String oidStr1 = ".1.3.6.1.2.1.1";
String oidStr2 = ".1.3.6.1.2.1.2";
String oidStr3 = ".1.3.6.1.2.1.3";
String commStr = "public";
int snmpVersion = SnmpConstants.version2c;
String portNum = "161";
int timeout = 3000;
int retryCnt = 1;
int maxRepetitions = 5;
CommunityTarget target = new CommunityTarget();
target.setAddress(new UdpAddress(targetAddr + "/" + portNum));
target.setCommunity(new OctetString(commStr));
target.setTimeout(timeout);
target.setRetries(retryCnt);
target.setVersion(snmpVersion);
PDU pdu = new PDU();
pdu.setType(PDU.GETBULK);
pdu.setMaxRepetitions(maxRepetitions);
pdu.setNonRepeaters(2);
OID targetOID1 = new OID(oidStr1);
OID targetOID2 = new OID(oidStr2);
OID targetOID3 = new OID(oidStr3);
pdu.add(new VariableBinding(targetOID1));
pdu.add(new VariableBinding(targetOID2));
pdu.add(new VariableBinding(targetOID3));
Snmp snmp = null;
try {
snmp = new Snmp(new DefaultUdpTransportMapping());
snmp.listen();
ResponseEvent responseEv = snmp.getBulk(pdu, target);
PDU response = responseEv.getResponse();
if (response == null) {
System.out.println("Request timeout...");
return;
}
if (response.getErrorStatus() != SnmpConstants.SNMP_ERROR_SUCCESS) {
System.out.println("Error happened...");
System.out.println(response.getErrorStatusText());
return;
}
int numVarBinds = response.size();
for (int i = 0; i < numVarBinds; i++) {
VariableBinding varbind = response.get(i);
if (varbind == null) {
continue;
}
if (varbind.isException()) {
System.out.println(varbind.getOid() + " : " + "Exception happened");
continue;
}
System.out.println(
varbind.getOid() +
" : " +
varbind.getVariable().getSyntaxString() +
" : " +
varbind.getVariable());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (snmp != null) {
snmp.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
上記の通り、snmp4j ライブラリを使って getBulk を実行している。snmp4j は有名なライブラリで RFC に沿っているはずなので、それで実装して実機検証すれば、事実が分かるというスタンスである。
上記のプログラムの実行結果は以下である。
1.3.6.1.2.1.1.1.0 : OCTET STRING : xxxxx
1.3.6.1.2.1.2.1.0 : Integer32 : 42
1.3.6.1.2.1.4.1.0 : Integer32 : 2
1.3.6.1.2.1.4.2.0 : Integer32 : 128
1.3.6.1.2.1.4.3.0 : Counter : 2509066
1.3.6.1.2.1.4.4.0 : Counter : 0
1.3.6.1.2.1.4.5.0 : Counter : 6
想定通り、「.1.3.6.1.2.1.1」と「.1.3.6.1.2.1.2」については繰り返し取得が実施されておらず、「.1.3.6.1.2.1.3」に対してのみ繰り返し取得が実施されている。なお、検証で用いたSNMPエージェントは「.1.3.6.1.2.1.3」のMIBを持っていないので、「.1.3.6.1.2.1.3」への取得要求に対して、SNMPエージェントは「.1.3.6.1.2.1.4」配下のMIBを返している。
これにより、nonRepeaters については冒頭に述べた理解で合っていると思う。