2011年05月27日

実践SNMP+Java MIBテーブルのフェッチ(TableUtils)

今日はSNMP4Jを利用したMIBテーブルのフェッチ(取得)について解説します。

MIBテーブルとはデータベースのテーブルと同様に行と列で管理されたMIBオブジェクトの集まりです。

MIBテーブルを理解するにはMIBブラウザを使って視覚的に捉えることも重要です。ここではiREASONING社のMIBブラウザ(無料)を使って説明します。

早速、MIBブラウザでRFC1213-MIB::ifTableを確認してみましょう。

37)

これを見ると、ifTableにはifIndex, ifDescr, ifTypeなどがエントリされており、テーブルのインデックスはifIndexであることがわかります(鍵のアイコンになっています)。もちろん、MIBファイルを直接確認しても良いでしょう。

ifEntry OBJECT-TYPE
    SYNTAX  IfEntry
    ACCESS  not-accessible
    STATUS  mandatory
    DESCRIPTION
            "An interface entry containing objects at the
            subnetwork layer and below for a particular
            interface."
    INDEX   { ifIndex }

このようにMIBテーブルには必ず行を特定する為のIndexが定義されており、この値を使って各OIDのインスタンスを指し示す事が出来ます(例:ifDescr.1)。尚、テーブルによっては複合indexの場合もあります。
早速、SNMP4Jを使ってifTableの値を幾つかフェッチしてみましょう。


Javaコード


 public void getTable() throws IOException {
  String host = "localhost";
  //host = "192.168.10.1";
  int port = 161;
  String community = "public";

  String[] oids = {
      ".1.3.6.1.2.1.2.2.1.1", // ifIndex
      ".1.3.6.1.2.1.2.2.1.2", // ifType
      ".1.3.6.1.2.1.2.2.1.3", // ifMtu
      ".1.3.6.1.2.1.2.2.1.4", // ifSpeed
      ".1.3.6.1.2.1.2.2.1.5" // ifPhysAddress
  };

  Snmp snmp = new Snmp(new DefaultUdpTransportMapping());
  snmp.listen();
  CommunityTarget comTgt = new CommunityTarget();
  comTgt.setAddress(new UdpAddress(host+"/"+port));
  comTgt.setCommunity(new OctetString(community)); // snmp community.
  comTgt.setVersion(SnmpConstants.version2c);

  TableUtils table = new TableUtils(snmp, new DefaultPDUFactory());

  OID[] columnOIDs = new OID[oids.length];
  for (int i=0; i<oids.length; i++) {
    columnOIDs[i] = new OID(oids[i]);
  }

  OID lowerBoundIndex = null; //new OID("1");
  OID upperBoundIndex = null;
  // getTable params. 
  // Target target, OID[] columnOIDs, OID lowerBoundIndex, OID upperBoundIndex
  List result = table.getTable(
      comTgt, columnOIDs, lowerBoundIndex, upperBoundIndex);

  for (int i=0; i<result.size(); i++) { 
    TableEvent event = (TableEvent) result.get(i);
    /*
     * org.snmp4j.util.RetrievalEvent
     * public static final int  STATUS_EXCEPTION  -4
     * public static final int  STATUS_OK  0
     * public static final int  STATUS_REPORT  -3
     * public static final int  STATUS_TIMEOUT  -1
     * public static final int  STATUS_WRONG_ORDER  -2
     */
    int status = event.getStatus();
    if (status == RetrievalEvent.STATUS_OK) {
      VariableBinding[] vbs = event.getColumns();
      System.out.print("table index:"+event.getIndex().toString()+"¥t -> ");
      for (int j=0; j<vbs.length; j++) {
        VariableBinding vb = vbs[j];
        System.out.print(
            //vb.getOid()+"->"+
            vb.getVariable()+"¥t");
      }
    }
    System.out.println();
  }

  snmp.close(); // close local udp port and response dispacher.
}


実行結果(サンプル)


table index:1  -> 1 lo0 24 16384 0

table index:2  -> 2 gif0 55 1280 0

table index:3  -> 3 stf0 57 1280 0

table index:4  -> 4 en0 6 1500 1000000000

table index:5  -> 5 en1 6 1500 10000000

table index:6  -> 6 fw0 144 4078 10000000



説明


7~13行目でifTableから取得するOIDの配列(ifIndex~ifPhysAddress)を定義しています。
22行目でテーブルのフェッチに利用するTabaleUtilsクラスのインスタンスを生成し、33行目でgetTableメソッドを呼出し、フェッチを実行しています。
ポーリング結果は、行に相当するTableEventインスタンスのListとして戻ります。この値を36行目以降で取り出しています。もし、OIDも合わせて確認したい場合、53行目のコメントを外してください。

TableEventクラスの面白い(便利な)ところはgetIndexメソッドでテーブルのインデックスを取得出来るところです。このIndexを取り出すという作業は大して難しい事では無く、VariableBinding::getOidメソッドの戻り値であるOIDインスタンスの値を分解すれば良いのですが、SNMP4J(API)側で提供してくれるとコード量も減って便利です。試しに複合Indexを持つipNetToMediaTableもフェッチしてみましょう。

16)

実行結果は次の通りです。

table index:5.192.168.0.1  -> 00:a0:de:36:ff:30 1

table index:5.192.168.0.12  -> 90:27:e4:3a:57:69 1

table index:5.192.168.0.14  -> 00:1a:a0:90:17:81 1

table index:5.192.168.0.25  -> cc:08:e0:c9:f8:da 1

table index:5.192.168.0.30  -> 00:21:70:33:15:e3 1

table index:5.192.168.0.132  -> 00:0c:29:bd:1b:07 1

table index:5.192.168.0.135  -> 00:0c:29:d6:a4:89 1


複合indexでも問題ありませんね(難しい処理では無いので当然なのですが)。
最後にTableUtils::getTableメソッドの引数であるlowerBoundIndex、upperBoundIndexについて説明します。これは開始、終了行のインデックスを使い、フェッチ範囲を指定する為のオプションです。もし、29行目のlowerBoundIndexを new OID("1") とすると、実行結果は次のようになります。

table index:2  -> 2 gif0 55 1280 0

table index:3  -> 3 stf0 57 1280 0

table index:4  -> 4 en0 6 1500 1000000000

table index:5  -> 5 en1 6 1500 10000000

table index:6  -> 6 fw0 144 4078 10000000


index:1の行が無くなっていますね。つまりlowerBoundIndexを指定するとそれ以降のインデックス持つ行のみ取得します。upperBoundIndexはこの逆です。


実践で使えるか?


僕自身はTableUtilsクラスを利用していないので何とも言えません。僕の場合、より細かなチューニングが出来るよう、GetNext/GetBulkを組み合わせた独自クラスを用意しMIBテーブルをフィッチしています。
TableUtilsクラスはHight Level APIと言われる、ある程度の処理までをAPI側で隠蔽してくれる便利なクラスですが、その反面チューニングが難しい、SNMP4J APIに依存したアプリケーションになる、というリスクもあります。

複雑・巨大なテーブルはフェッチしない、SNMP4Jに依存しても問題無い、という方は是非どうぞ。


入門SNMP
入門SNMP
posted with amazlet at 11.05.27
ダグラス・R. マウロ ケビン・J. シュミット 
オライリー・ジャパン 
売り上げランキング: 49043



Posted by netbuffalo at 18:58│TrackBack(0) 実践SNMP+Java 


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