2010年07月17日

実践SNMP+Java GetNextとWalk

SNMP4Jを利用したSNMP GetNextとWalk操作について説明します。
まずは、シンプルなGetNextコードから説明します。 

<Javaコード(GetNext)>

  1.     String oid = ".1.3.6.1.2.1.1"; // mib-2.system
  2.     //oid = ".1.3.6.1.2.1.2.2.1.2", // ifTable.ifEntry.ifDescr
  3.     // SNMP通信パラメータを設定するクラス。
  4.     CommunityTarget comTgt = new CommunityTarget();
  5.     comTgt.setAddress( new UdpAddress("localhost/161") ); // UDPアドレス(ターゲット・アドレス/SNMPポート)
  6.     comTgt.setCommunity( new OctetString("public") ); // SNMPコミュニティ名
  7.     comTgt.setTimeout(1000); // タイムアウト時間(ミリ秒)
  8.     comTgt.setRetries(1); // リトライ数
  9.     comTgt.setVersion(SnmpConstants.version1); // SNMPバージョン
  10.     // PDUを生成します。
  11.     PDU pdu = new PDU();
  12.     pdu.setType(PDU.GETNEXT);
  13.     // PDUにバーバインドを格納します。
  14.     OID targetOID = new OID(oid);
  15.     pdu.add( new VariableBinding(targetOID) );
  16.     // SNMP操作の基本になるクラス。
  17.     Snmp snmp = null;
  18.     // DefaultTcpTransportMappingクラスもあります
  19.     DefaultUdpTransportMapping utm = null;
  20.     try {
  21.       utm = new DefaultUdpTransportMapping();
  22.       snmp = new Snmp(utm);
  23.       snmp.listen(); // ローカルUDPポートのオープンと待機
  24.       // SNMP GetNext
  25.       ResponseEvent response = snmp.getNext(pdu, comTgt);
  26.       // レスポンスPDU
  27.       PDU resPdu = response.getResponse();
  28.       if ( resPdu != null && resPdu.getErrorStatus() == SnmpConstants.SNMP_ERROR_SUCCESS ) {
  29.         // このサンプルではリクエストPDUに含まれるバーバインドは1つだけだったのでget(0)
  30.         VariableBinding var = resPdu.get(0);
  31.         if ( !var.isException() ) {
  32.           System.out.println(var.getOid() + " -> " + var.getVariable().toString());
  33.         } else {
  34.           System.out.println(var.getOid() + " -> " + "has exception syntax!");
  35.         }
  36.       } else {
  37.         if (resPdu == null) {
  38.           // レスポンスPDUがnullの場合はタイムアウトです。
  39.           System.out.println("request timeout.");
  40.         } else {
  41.           System.out.println(resPdu.getErrorStatus()+"/"+resPdu.getErrorStatusText());
  42.         }
  43.       }
  44.       // ローカルUDPポートのclose
  45.       snmp.close();
  46.     } catch (IOException e) {
  47.       e.printStackTrace();
  48.     }


<実行結果(GetNext)


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)


<説明(GetNext)> 


1)GetNextリクエスト送信準備(1~23行目)
  ここまではSNMP Getの説明と同じになるので割愛します。
  PDUタイプはPDU.GETNEXTに設定しています。
  ちなみにGet記事で説明したインスタンス識別子が事前にはわからない場合に
  GetNextを使います。
  このサンプルでは、String OID = ".1.3.6.1.2.1.1"; // mib-2.systemを問合せ
  OIDにしています。
  (この次のOID/インスタンスをエージェントに問合せます)

2)GetNextリクエストの送信とレスポンスの受信
  こちらもSNMP Getと基本的に同じです。
  実行結果を見ると、指定した".1.3.6.1.2.1.1"; // mib-2.systemに対してエージェント側で
  その次に管理しているsystem.sysDescr.0(systemグループの先頭)が戻ります。
  このあたりの話しになるとMIBファイルとそのブラウザも合わせて使わないとわからなくなってきます。
  #その通りだという方は、’MIBブラウザ’で検索し、適当なMIBブラウザをダウンロード、
  #インストールしてみて下さい。
 
  以上でGetNextは完了です。

  引き続き、SNMP Walkについて説明します。 
  GetNextは一度にまとめてオブジェクトを取得したい場合には、繰り返し操作になるので、
  人が行うには不便です。
  ですので、ある条件をもって、GetNextを繰り返し取得することをWalkと言います。
  ただ、WalkはSNMPの標準仕様ではありませんので、Snmpクラスにも用意されていません。
  次はこのWalkと呼ばれる指定したOIDのサブツリーに含まれる全てオブジェクトを取得する
  コードを書いてみます。


Javaコード(シンプルなWalk)> 
  1.   public void snmpWalk() {
  2.     String oid = ".1.3.6.1.2.1.1"; // mib-2.system
  3.     //oid = ".1.3.6.1.2.1.2.2.1.2"; // ifTable.ifEntry.ifDescr
  4.     // SNMP通信パラメータを設定するクラス。
  5.     CommunityTarget comTgt = new CommunityTarget();
  6.     comTgt.setAddress( new UdpAddress("localhost/161") ); // UDPアドレス(ターゲット・アドレス/SNMPポート)
  7.     comTgt.setCommunity( new OctetString("public") ); // SNMPコミュニティ名
  8.     comTgt.setTimeout(1000); // タイムアウト時間(ミリ秒)
  9.     comTgt.setRetries(1); // リトライ数
  10.     comTgt.setVersion(SnmpConstants.version1); // SNMPバージョン
  11.     // PDUを生成します。
  12.     PDU pdu = new PDU();
  13.     pdu.setType(PDU.GETNEXT);
  14.     // PDUにバーバインドを格納します。
  15.     OID rootOID = new OID(oid);
  16.     pdu.add( new VariableBinding(rootOID) );
  17.     // SNNMP操作の基本になるクラス。
  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 Walk
  26.       while ( true ) {
  27.         // SNMP GetNext
  28.         ResponseEvent response = snmp.getNext(pdu, comTgt);
  29.         // レスポンスPDU
  30.         PDU resPdu = response.getResponse();
  31.         if ( resPdu != null && resPdu.getErrorStatus() == SnmpConstants.SNMP_ERROR_SUCCESS ) {
  32.           // このサンプルではリクエストPDUに含まれるバーバインドは1つだけだったのでget(0)
  33.           VariableBinding var = resPdu.get(0);
  34.           OID currentOID = var.getOid();
  35.           if ( !var.isException() ) {
  36.             if ( isSubTree(rootOID, currentOID) ) {
  37.               System.out.println(currentOID + " -> " + var.getVariable().toString());
  38.               pdu = new PDU();
  39.               pdu.setType(PDU.GETNEXT);
  40.               pdu.addOID( new VariableBinding(currentOID) );
  41.             } else {
  42.               System.out.println("out of sub tree!");
  43.               System.out.println(currentOID + " -> " + var.getVariable().toString());
  44.               break;
  45.             }
  46.           } else {
  47.             System.out.println(currentOID + " -> " + "has exception syntax!");
  48.             break;
  49.           }
  50.         } else {
  51.           if (resPdu == null) {
  52.             // レスポンスPDUがnullの場合はタイムアウトです。
  53.             System.out.println("request timeout.");
  54.           } else {
  55.             System.out.println(resPdu.getErrorStatus()+"/"+resPdu.getErrorStatusText());
  56.           }
  57.           break;
  58.         }
  59.       }
  60.       // ローカルUDPポートのclose
  61.       snmp.close();
  62.     } catch (IOException e) {
  63.       e.printStackTrace();
  64.     }
  65.   }
  66.   public boolean isSubTree(OID rootOID, OID currentOID) {
  67.     boolean b = true;
  68.     /**
  69.      * Compares the n leftmost sub-identifiers with the given OID in left-to-right direction.
  70.      * 0 if the first n sub-identifiers are the same.
  71.      * <0 if the first n sub-identifiers of this OID are lexicographic less than those of the comparand.
  72.      * >0 if the first n sub-identifiers of this OID are lexicographic greater than those of the comparand
  73.      */
  74.     if ( rootOID.leftMostCompare(rootOID.size(), currentOID) != 0 ) {
  75.       b = false;
  76.     }
  77.     return b;
  78.   }


<実行結果(Walk)>

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 -> 1 day, 4:21:14.10
1.3.6.1.2.1.1.4.0 -> 
1.3.6.1.2.1.1.5.0 -> PANZERII
1.3.6.1.2.1.1.6.0 -> 
1.3.6.1.2.1.1.7.0 -> 76
out of sub tree!
1.3.6.1.2.1.2.1.0 -> 6

<説明(Walk)>

1)Walkの開始(26行目)と終了条件
  GetNextのループです。凝った作りにはしておらず、タイムアウト、SNMPエラーが発生した際には
  ループを抜けます。あともう一つ抜ける条件がありまして、36行目で評価しているisSubTreeが
  falseの場合にも、レスポンスに含まれるOIDが、初期値として指定したルートOIDのサブツリーでは
  無くなったと判断して、ループを抜けます。
  isSubTreeの実装ですが、一から作らず、[SNMP4J] SnmpWalk Termination Conditions
  参考にrootOID.leftMostCompare(rootOID.size(), currentOID) != 0で判断しています。
  #FrankさんはSNMP4Jの開発者

  実際に実行結果を見ると、OID = ".1.3.6.1.2.1.1"; // mib-2.system以下のオブジェクトを
  全て終了し、.1.3.6.1.2.1.2.1.0(interfaces.ifNumber.0)になったところで終了しています。

2)最後に
  2行目をコメントインして、ifTable.ifEntry.ifDescrを取得するとインタフェース名の
  一覧を取得し、結果を表示しますが、Windowsの場合、期待した通りのインタフェース名称が
  表示されないことがあります。
  #この時点で想像ができる人は鋭いですね。 
  理由は、ifDescrがDisplayStringでというデータ型(Syntax)で、エージェントから取得した値が
  印字可能か否かが影響しているのですが、その対応方法は別記事で説明しようと思います。
  (GetNext/WalkはMIBテーブルへのアクセスに利用する事が多く、サンプル・コードを試す場合に、
  ifTableはその第一候補かと思いましたので、先に断っておきます)


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

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

Posted by netbuffalo at 17:47│TrackBack(0) 実践SNMP+Java 


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