以前、以下の記事を書いた時に、
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) { // Set value for snmp getbulk 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; // Create target CommunityTarget target = new CommunityTarget(); target.setAddress(new UdpAddress(targetAddr + "/" + portNum)); target.setCommunity(new OctetString(commStr)); target.setTimeout(timeout); target.setRetries(retryCnt); target.setVersion(snmpVersion); // Create pdu PDU pdu = new PDU(); pdu.setType(PDU.GETBULK); pdu.setMaxRepetitions(maxRepetitions); pdu.setNonRepeaters(2); // ★NonRepeatersには 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(); // Execute snmp GetBulk ResponseEvent responseEv = snmp.getBulk(pdu, target); // Get response PDU response = responseEv.getResponse(); // --------------------------------- // Analyze response // --------------------------------- 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()); } // for } 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 については冒頭に述べた理解で合っていると思う。