2010年07月20日

実践SNMP+Java GetBulk

SNMP4Jを利用したSNMP GetBulk操作について説明します。

GetBulkは前回説明したGetNextの繰り返しであるWalkに近く、まとめて・複数のMIBオブジェクトを取得する為のSNMP PDUタイプです。
 
連続したMIBオブジェクトを一括で取得したい場合、GetNextに比較すると、
マネージャ/エージェント間のPDU数を減らすことが出来る為、効率良く取得出来ます。

<Javaコード>
 
  1.     String oid = ".1.3.6.1.2.1.1"; // mib-2.system
  2.     // SNMP通信パラメータを設定するクラス。
  3.     CommunityTarget comTgt = new CommunityTarget();
  4.     comTgt.setAddress( new UdpAddress("localhost/161") ); // UDPアドレス(ターゲット・アドレス/SNMPポート)
  5.     comTgt.setCommunity( new OctetString("public") ); // SNMPコミュニティ名
  6.     comTgt.setTimeout(1000); // タイムアウト時間(ミリ秒)
  7.     comTgt.setRetries(1); // リトライ数
  8.     comTgt.setVersion(SnmpConstants.version2c); // GetBulkはv2以降でサポート
  9.     // PDUを生成します。
  10.     PDU pdu = new PDU();
  11.     pdu.setType(PDU.GETBULK);
  12.     pdu.setMaxRepetitions(5); // 一括繰り返し取得数。system.sysDescr.0から5つをGetBulk
  13.     pdu.setNonRepeaters(0); // 繰り返し取得しないバーバインドのindex。
  14.     // PDUにバーバインドを格納します。
  15.     OID targetOID = new OID(oid);
  16.     pdu.add(new VariableBinding(targetOID));
  17.     // SNMP操作の基本になるクラス。
  18.     Snmp snmp = null;
  19.     // DefaultTcpTransportMappingクラスもありますが、使いどころは不明?
  20.     DefaultUdpTransportMapping utm = null;
  21.     try {
  22.       utm = new DefaultUdpTransportMapping();
  23.       snmp = new Snmp(utm);
  24.       snmp.listen(); // ローカルUDPポートのオープンと待機
  25.       // SNMP GetBulk
  26.       ResponseEvent response = snmp.getBulk(pdu, comTgt);
  27.       // レスポンスPDU
  28.       PDU resPdu = response.getResponse();
  29.       if ( resPdu != null && resPdu.getErrorStatus() == SnmpConstants.SNMP_ERROR_SUCCESS ) {
  30.         // レスポンスPDUに含まれるバーバインド数
  31.         int numVarBinds = resPdu.size();
  32.         for (int i=0; i<numVarBinds; i++) {
  33.           VariableBinding var = resPdu.get(i);
  34.           if ( !var.isException() ) {
  35.             System.out.println(var.getOid() + " -> " + var.getVariable().toString());
  36.           } else {
  37.             System.out.println(var.getOid() + " -> " + "has excepton syntax!");
  38.           }
  39.         }
  40.       } else {
  41.         if (resPdu == null) {
  42.           // レスポンスPDUがnullの場合はタイムアウトです。
  43.           System.out.println("request timeout.");
  44.         } else {
  45.           System.out.println(resPdu.getErrorStatusText());
  46.         }
  47.       }
  48.       // ローカルUDPポートのclose
  49.       snmp.close();
  50.     } catch (IOException e) {
  51.       e.printStackTrace();
  52.     }
 
<実行結果>
 
1.3.6.1.2.1.1.1.0 -> Hardware: x86 Family 6 Model 15 Stepping 6 AT/AT COMPATIBLE - Software: Windows 2000 Version 5.1 (Build 2600 Multiprocessor Free)
1.3.6.1.2.1.1.2.0 -> 1.3.6.1.4.1.311.1.1.3.1.1
1.3.6.1.2.1.1.3.0 -> 0:03:12.31
1.3.6.1.2.1.1.4.0 -> 
1.3.6.1.2.1.1.5.0 -> PANZERII
 
 
<説明>
 
1)リクエスト送信準備(1~16行目)
  まず、GetBulkはSNMPv2以降ですので、8行目でバージョンにv2(c)を指定しています。
  次に、10~16行目でGetBulkリクエストPDUを生成しています。
  G etBulkリクエスト特有のパラメータとしてMaxRepetitionsとNonRepeatersがあります。
  MaxRepetitionsは一括繰り返し取得回数を表すパラメータで、サンプル・コードでは、
  ".1.3.6.1.2.1.1"; // mib-2.system以降の5オブジェクトを一括取得するという意図で、
  pdu.setMaxRepetitions(5)を設定しています。
  ※MaxRepetitionsで指定できる数字に上限はありませんが、実際には、
  エージェント側の最大PDUサイズに依存し、それを超える場合には反映されません。
  (SNMP Getで説明したTooBigエラーと同じ理由です)
  NonRepeaters(一括繰り返し取得しないバーバインドのPDU内index)は、
  サンプルコードでは一括取得したいので、0(無し)にしています。
  NonRepeatersを0にする運用は少ないんじゃないじゃ無いかと思うんですが、
  一番最後に使用例を説明します。
 
2)リクエストの送信・レスポンスの受信(18行目)
  送信・受信はGet/GetNextと同様です。
  systemグループ(".1.3.6.1.2.1.1")のsystem.sysDescr.0~sysName.0まで
  5オブジェクトを一括取得しています。


<NonRepeatersの使いどころ>
 
僕自身このパラメータを実際の運用で使ったことは無いのですが、使いどころを
考えてみたいと思います。
もし、システムのホスト名(system.sysName.0)とインタフェースの
物理アドレス(ifTable.ifEntry.ifPhysAddress.$, $:ifIndex)を一括で
取得したいとなった場合、リクエストPDUの準備は次のようになります。
 
    PDU pdu = new PDU();
    pdu.setType(PDU.GETBULK);
    // add varbind(index:1). system.sysContact.0 (for system.sysName.0)
    pdu.add( new VariableBinding( new OID(".1.3.6.1.2.1.1.4.0") ) );
    // add varbind(index:2). ifTable.ifEntry.ifPhysAddress
    pdu.add(new VariableBinding( new OID(".1.3.6.1.2.1.2.2.1.6") ) );
    pdu.setMaxRepetitions(10); // 一括繰り返し取得数
    pdu.setNonRepeaters(1); //繰り返し取得しないバーバインドのindex。この例では1。

まず、system.sysName.0(1.3.6.1.2.1.1.5.0 )を取得したいのですが、
GetBulkでは指定したOID以降という意味になるので、その前のOIDである
".1.3.6.1.2.1.1.4.0"(system.sysContact.0)を指定しています。
次に、ifPhysAddressのOIDを設定しています。
インタフェースが幾つあるか事前にはわかりませんので、10以下を前提に
繰り返しで一括取得します。
最後にpdu.setNonRepeaters(1)ですが、sysName.0はエージェント側では
オブジェクト(インスタンス)を1つしか管理していないことが分かっており、
繰り返し取得する必要はなく、そのバーバインドのインデックスである1を
指定しています。
結果は次の通りです。
 
1.3.6.1.2.1.1.5.0 -> PANZERII
1.3.6.1.2.1.2.2.1.6.1 -> 
1.3.6.1.2.1.2.2.1.6.2 -> 00:50:56:c0:00:08
1.3.6.1.2.1.2.2.1.6.3 -> 00:50:56:c0:00:01
1.3.6.1.2.1.2.2.1.6.4 -> 00:1c:23:17:d5:9b
1.3.6.1.2.1.2.2.1.6.5 -> 00:1b:77:cf:40:dd
1.3.6.1.2.1.2.2.1.6.65543 -> 7a:79:05:2e:82:37
1.3.6.1.2.1.2.2.1.7.1 -> 1
1.3.6.1.2.1.2.2.1.7.2 -> 1
1.3.6.1.2.1.2.2.1.7.3 -> 1
1.3.6.1.2.1.2.2.1.7.4 -> 1
 
sysName.0とifPhysAddressの一覧が取得出来ました。
尚、実際には僕のPCには10個もネットワーク・インタフェースは無いので、
レスポンスにifTable.ifEntry.ifAdminStatus(.1.3.6.1.2.1.2.2.1.7)まで
含まれており、自分が欲しい情報か否かは、GetNetxで説明したIsSubTree
相当の処理を用意して判断します。

 
<最後に>

実践でGetNext、GetBulkを利用するケースとしてはMIBテーブルのフェッチが
多くなるのではないかと思います。
この時、GetNext/GetBulkではスピード、エージェント側負荷にどの程度の差が
出るのでしょうか?
この話しは別の機会にご説明します。
 
入門SNMP
入門SNMP
posted with amazlet at 13.01.12
ダグラス・R. マウロ ケビン・J. シュミット
オライリー・ジャパン
売り上げランキング: 257,278

Java ネットワーク プログラミング 基礎からわかる 完全入門
永嶋 浩
技術評論社
売り上げランキング: 228,941

Posted by netbuffalo at 14:50│TrackBack(0) 実践SNMP+Java 


この記事へのトラックバックURL