シンプル・ネットワーク管理プロトコル (SNMP) は,ルータ,ブリッジ,ホストなど,ネットワークに接続されているデバイスのリモート管理とデータ収集を可能にするアプリケーション層プロトコルです。
管理されたネットーワーク接続デバイスは,そのデバイスのための SNMP エージェントとして機能するソフトウェアを含んでいます。 このソフトウェアは,SNMP に対するアプリケーション層プロトコルを処理し,管理コマンドを実行します。 管理コマンドは,情報収集パラメータおよび操作に関する設定パラメータで構成されます。
ネットワーク上の各管理デバイスに SNMP コマンドを送って管理タスクを実行するネットワーク管理プログラムもあります。 通常このプログラムは,ネットワーク上のいずれかの単一ホストで実行されます。 このプログラムが実行する管理タスクとしては,構成管理,ネットワーク・トラフィックの監視,ネットワークに関するトラブル・シューティングなどがあります。
eSNMP (Extensible Simple Network Management Protocol) は,Tru64 UNIX あるいは DIGITAL UNIX の以前のバージョンのための SNMP エージェントです。 このエージェントは,マスタ・エージェント・プロセスと eSNMP サブエージェントなどの複数の関連プロセスで構成されます。 マスタ・エージェントは SNMP プロトコルを処理し,サブエージェントは要求された管理コマンドを実行します。 この章では,次の項目については既知であると仮定して説明します。
SNMP プロトコル
MIB (Management Information Base) 定義および RFC (Request for Commnet)
OID (Object Identifier) および ISO (International Standards Organization) 登録階層 (1.3.6.1.2.1 など)
C プログラミング言語
この章では次の情報を提供します。
eSNMP の概要
eSNMP アプリケーション・プログラミング・インタフェース (API) の概要
eSNMP ルーチンについての詳細
以降の節では,eSNMP エージェントの構成要素とアーキテクチャについて下記の順に説明します。
eSNMP の構成要素
アーキテクチャ
SNMP バージョン
/usr/sbin/snmpd
-- マスタ・エージェント・デーモン
/usr/sbin/os_mibs
-- ホスト MIB およびネットワーキング・サブエージェント・デーモン
/usr/sbin/svrMgt_mib
--
サーバ管理サブエージェント・デーモン
/usr/sbin/svrSystem_mib
--
サーバ・システム・サブエージェント・デーモン
/usr/sbin/mosy
-- MIB コンパイラ
/usr/sbin/snmpi
-- オブジェクト・テーブル・コード・ジェネレータ
/usr/shlib/libesnmp.so
-- eSNMP ライブラリ
/usr/include/esnmp.h
-- eSNMP 定義
/usr/examples/esnmp/*
-- サンプル・コード
MIB (Management Information Base) 定義は,ネットワーク管理に関係するデータ要素群です。 これらの多くは,インターネット協会 (Internet Society) の IETF (Internet Engineering Task Force) ワーキング・グループの標準化作業の成果物として作成された RFC で標準化されています。
RFC で定義されているデータ要素は,階層構造のネーミング・スキームで識別されます。 階層構造の各レベルのそれぞれの名前は,それに対応する番号を持っています。 MIB 定義のデータ要素は,データ要素の名前あるいはオブジェクト識別子 (OID) と呼ばれる対応するシーケンス番号によって参照することができます。 各データ要素の OID は,さらに番号を追加することにより,データ要素の特定のインスタンスを識別するように拡張できます。 管理されたデータ要素の集合全体を MIB ツリーと呼びます。
各 SNMP エージェントは,管理されているデバイスに属する MIB 要素と,いくつかの共通 MIB 要素を実現します。 これらの MIB 要素をサポート MIB ツリー要素と呼びます。 拡張 SNMP エージェントは,このサポート MIB ツリー要素を複数のプロセス間に分散させ,動的に変更することができます。
eSNMP には,1 つのマスタ・エージェントといくつかのサブエージェントがあります。
マスタ・エージェントは,SNMP プロトコルを扱い,SNMP 自身に関連した MIB をサポートし,接続されたサブエージェントおよびサブエージェントがサポートする MIB サブツリーの登録の管理を行います。
eSNMP のためのマスタ・エージェントは,デーモン・プロセス
/usr/sbin/snmpd
です。
Tru64 UNIX は,IETF 標準もしくは HP 独自の異なる MIB をいくつか実現しているサブエージェントを提供します。
詳細は,『QuickSpecs』,『Tru64 UNIX 概要』
および
snmpd
(8)6.1.2 アーキテクチャ
マスタ・エージェントは,事前に割り当てられている UDP (ユーザ・データグラム・プロトコル) ポート上で,SNMP 要求が送られてくるのを待っています。
SNMP 要求を受信すると,マスタ・エージェントはローカル・セキュリティ・データベース
(
snmpd
(8)snmpd
デーモンはその MIB 登録を照会します。
要求に含まれているそれぞれの要求 MIB オブジェクトに対して,どの登録済 MIB がそのオブジェクトを含み,どのサブエージェントがその MIB を登録したかを判断します。
その後,マスタ・エージェントは (SNMP 要求に含まれる各サブエージェントに対して) 一連のメッセージを作成します。
各サブエージェント・プログラムは,シェアード・ライブラリ
libesnmp.so
にリンクしています。
このライブラリには,マスタ・エージェントとサブエージェントとの通信を可能にするプロトコルのインプリメンテーションが含まれています。
このコードは,マスタ・エージェントのメッセージを解析し,ローカル・オブジェクト・テーブルを照会します。
オブジェクト・テーブルは,snmpi
および
mosy
MIB コンパイラ・ツールで生成されたコードで定義および初期化されたデータ構造体です。
このデータ構造体には,サブエージェントで実現されている MIB に含まれる各 MIB オブジェクトに対するエントリが含まれています。
オブジェクト・テーブル・エントリのある部分は,MIB オブジェクトに対する要求をサービスする関数のアドレスです。
この関数をメソッド・ルーチンと呼びます。
eSNMP ライブラリ・コードは,マスタ・エージェントのメッセージにおいて各 MIB 変数に対して指定されたメソッド・ルーチンに呼び込まれます。 eSNMP ライブラリ・コードは,戻り値をもとに応答パケットを作成し,それをマスタ・エージェントへ返します。
マスタ・エージェントはタイマを起動し,すべてのサブエージェントからの応答パケットを整理します。
(たとえば
GetNext
要求など) 特定の要求に依存して,マスタ・エージェントは新しいサブエージェント・メッセージを再作成し再送します。
必要なデータあるいはエラー応答をマスタ・エージェントがすべて持っている場合 (あるいはサブエージェントからの応答が時間切れになっても届かない場合),
マスタ・エージェントは SNMP 応答メッセージを作成し,もとの SNMP アプリケーションに送ります。
要求を出している SNMP 管理アプリケーションには,マスタ・エージェントとサブエージェントとのやり取りは見えません。
サブエージェント・プログラムは,すべてのプロトコル処理および発送を行う
libesnmp.so
シェアラブル・ライブラリにリンクしています。
サブエージェント開発者は,それらの定義済みの MIB オブジェクトだけに対するメソッド・ルーチンをコーディングする必要があります。
6.1.3 SNMP バージョン
拡張 SNMP は,次の範囲で SNMPv2c をサポートします。 これは,RFC 1901 から RFC 1908 までをベースにしています。
MIB ツール (mosy
および
snmpi
プログラム) は SNMPv2c Structure of Management Information for SNMPv2 (SMIv2) と textual conventions をサポートしています。
eSNMP ライブラリ API は,SNMPv2c,変数割り当て例外処理,エラー・コードをサポートします。
マスタ・エージェントは現在のところ SNMPv1 および SNMPv2c を 2 か国語方式でサポートしています。 サブエージェントからの SNMPv2c 固有情報はすべて,必要な場合には,RFC 2089 に従って SNMPv1 関連のデータにマップされます。 たとえば,管理アプリケーションが SNMPv1 PDU を使用して要求を作成すると,マスタ・エージェントは SNMPv1 PDU を使用して応答し,サブエージェントから受け取った SNMPv2c SMI 要素をすべてマップします。 つまり,以前のバージョンの eSNMP API で作成されたサブエージェントでは,コード変更が不要であり,再コンパイルの必要がありません。
マスタ・エージェント間で
libesnmp.so
ライブラリによって実行される通信はすべて,RFC 2741,『Agent Extensibility (AgentX) Version 1』
を実現して行われています。
RFC 2741 は,拡張可能なエージェント構成要素,マスタ・エージェント,複数のサブエージェントの間の通信に関する標準的なプロトコルを定義しています。
すなわち,eSNMP API を使用するサブエージェントは,異なるベンダのマスタ・エージェント (RFC 2741 に準拠しているもの) が Tru64 UNIX ホスト上で実行されていても,修正なしで正しく動作します。
6.2 拡張 SNMP アプリケーション・プログラミング・インタフェースの概要
サブエージェントの機能は,マスタ・エージェントとの通信を確立し,処理しようとしている MIB サブツリーを登録し,マスタ・エージェントからの要求を処理することです。 また,ホスト・アプリケーションに代わって SNMP トラップを送ることができます。
サブエージェントは,次のものから構成されます。
メイン関数 (開発者によって作成される)
AgentX プロトコル動作を実行する eSNMP ライブラリ・ルーチン
特定の MIB 要素を処理するメソッド・ルーチン (開発者によって作成される)
(mosy
および
snmpi
プログラムを使用して RFC から生成された) オブジェクト・テーブル構造体
通常,サブエージェントはルータ・デーモンなどのアプリケーション内に組み込まれています。 サブエージェントの処理はプロセスが実行する処理のほんの一部分です。 この場合,アプリケーションのメイン・イベント・ループは,eSNMP ライブラリを呼び出します。 また,サブエージェントが独自のメインルーチンを持つスタンドアロン・デーモンである場合もあります。
マスタ・エージェントからのパケット処理中に eSNMP ライブラリは,要求された各 MIB 変数に対して指定のメソッド・ルーチンを呼び出します。
オブジェクト・テーブルの定義済みの各 MIB 変数は,その MIB 変数の要求を処理するためのメソッド・ルーチンへのポインタを含んでいます。
サブエージェントのオブジェクト・テーブルは
mosy
および
snmpi
プログラムによって生成されるため,
メソッド・ルーチン名は静的です。
オペレーティング・システムで提供される eSNMP 開発者キットには次のものが含まれます。
/usr/sbin/mosy
-- MIB コンパイラ・ユーティリティ
/usr/sbin/snmpi
-- オブジェクト・テーブル・コード生成ユーティリティ
/usr/examples/esnmp/mib-converter.sh
-- MIB テキスト抽出ツール
/usr/shlib/libesnmp.so
-- eSNMP シェアード・ライブラリ
/usr/include/esnmp.h
-- eSNMP 定義ファイル
/usr/examples/esnmp/*
-- サブエージェント・サンプル・ソース・コード
eSNMP シェアード・ライブラリ (libesnmp.so
) は次のサービスを提供しています。
マスタ・エージェント/サブエージェント間プロトコル処理ルーチン
サブエージェントの代わりにマスタ・エージェントと通信する以下のルーチン
esnmp_init
プロトコルを初期化します (マスタ・エージェントとハンドシエークを行います)。
esnmp_allocate
1 つまたは複数の特定のインデックス・オブジェクト (OID) に値を割り当てるように,マスタ・エージェントに要求します。
esnmp_deallocate
1 つまたは複数のインデックス・オブジェクト (OID) の値を割り当て解除するように,マスタ・エージェントに要求します。
esnmp_register
マスタ・エージェントに MIB サブツリーを登録します。
esnmp_poll
マスタ・エージェントからのパケットを処理します。
esnmp_trap
マスタ・エージェントに SNMP トラップを生成するよう要求します。
esnmp_are_you_there
マスタ・エージェントに対して
ping
コマンドを実行します。
esnmp_unregister
MIB サブツリーの登録を解除します。
esnmp_term
マスタ・エージェントとの通信を終了し,拡張 SNMP を終了します。
esnmp_sysuptime
--
時間処理および同期化。
サポート・ルーチン
メソッド・ルーチンの開発の役に立つルーチン。 詳細なリストと各 eSNMP サポート・ルーチンの説明については,6.3 節を参照してください。
eSNMP に関連して
esnmp.h
ヘッダ・ファイルが提供されています。
このファイルは,eSNMP API に対するサブエージェントを実現するのに必要なすべてのデータ構造,定数,関数プロトタイプを定義しています。
サブエージェントの動作と eSNMP API について理解するためには,MIB サブツリーについて理解することが非常に重要です。
注意
この項では,SNMP で使用される OID 命名構造については理解しているものとして説明します。 OID 命名構造については,RFC 1902『Structure of Management Information for Version 2 of the Simple Network Management Protocol (SNMPv2)』を参照してください。
SNMP における情報は,逆ツリー構造の階層構造になっています。 この階層構造のなかで,データは,リーフ・ノードに対応付けられます。 各ノードには名称と番号が付けられます。 各ノードは,OID によっても識別することができます。 OID は,ツリーのルートからそのノードまでのパス上に存在する,サブ識別子と呼ばれる負でない番号を連鎖したものです。 OID の長さは,最低でサブ識別子が 2 つなければならず,サブ識別子が,たかだか 128 個の長さです。 有効なサブ識別子 1 の値は,込みで 0 から 2 の範囲であり,サブ識別子 2 の値は,込みで 0 から 39 の範囲であり,残りのサブ識別子の値は,負でない番号です。
たとえば,/usr/examples/esnmp
ディレクトリのサンプル・コードで提供される
chess
MIB は,chess
という名前の要素を持っています。
要素
chess
の OID は,ツリーの階層構造における位置を表す
1.3.6.1.4.1.36.2.15.2.99
です。
iso(1) org(3) dod(6) internet(1) private(4) enterprise(1) digital(36) ema(2) sysobjects(15) decosf(2) chess(99)
MIB 階層構造のどのノードも MIB サブツリーを定義することができます。
サブツリー内のすべての要素は,サブツリー・ベースの OID で始まる OID を持っています。
たとえば
chess
を MIB サブツリー・ベースとして定義した場合,chess
OID をプレフィックスとして持つ要素は,次のようにすべて MIB サブツリー内に存在します。
chess 1.3.6.1.4.1.36.2.15.2.99 chessProductID 1.3.6.1.4.1.36.2.15.2.99.1 chessMaxGames 1.3.6.1.4.1.36.2.15.2.99.2 chessNumGames 1.3.6.1.4.1.36.2.15.2.99.3 gameTable 1.3.6.1.4.1.36.2.15.2.99.4 gameEntry 1.3.6.1.4.1.36.2.15.2.99.4.1 gameIndex 1.3.6.1.4.1.36.2.15.2.99.4.1.1 gameDescr 1.3.6.1.4.1.36.2.15.2.99.4.1.2 gameNumMoves 1.3.6.1.4.1.36.2.15.2.99.4.1.3 gameStatus 1.3.6.1.4.1.36.2.15.2.99.4.1.4 moveTable 1.3.6.1.4.1.36.2.15.2.99.5 moveEntry 1.3.6.1.4.1.36.2.15.2.99.5.1 moveIndex 1.3.6.1.4.1.36.2.15.2.99.5.1.1 moveByWhite 1.3.6.1.4.1.36.2.15.2.99.5.1.2 moveByBlack 1.3.6.1.4.1.36.2.15.2.99.5.1.3 moveStatus 1.3.6.1.4.1.36.2.15.2.99.5.1.4 chessTraps 1.3.6.1.4.1.36.2.15.2.99.6 moveTrap 1.3.6.1.4.1.36.2.15.2.99.6.1
サブツリー内の要素に関連するすべての要求をこのサブエージェントが処理することを,マスタ・エージェントに知らせるために登録されるのは,この MIB サブツリー・ベースです。
マスタ・エージェントは,登録されている MIB サブツリーに従属するすべてのオブジェクトをサブエージェントが処理することを期待します。 この原則を考慮して MIB サブツリーを選択してください。
たとえば,サブエージェントが
chess
サブツリーの要素に関する要求をすべて処理できると考えるのは現実的なので,chess
のサブツリーを登録するのは妥当です。
また,特定のアプリケーションはアプリケーション固有の MIB で定義されているすべてのオブジェクトを処理することを期待するため,アプリケーション固有の MIB 全体を登録するのも通常は適切です。
(FDDI や トークンリングなど)
transmission
に従属するすべての定義済み MIB オブジェクトをサブエージェントが処理できるように用意されていることはありえないので,(MIB-2 の下の)
transmission
のサブツリーを登録するのは間違いです。
サブエージェントは必要な数の MIB サブツリーを登録します。 サブエージェントは,そのサブエージェント自身あるいは他のサブエージェントによる別の登録と重複して OID を登録することができます。 ただし,サブエージェントは同じ OID を 2 回以上登録することはできません。 サブエージェントがマスタ・エージェントとの通信を確立した後は,いつでも MIB サブツリーの登録および登録の解除を行うことができます。
通常,サブツリーとしてマスタ・エージェントに登録されるのは非リーフ・ノードです。 ただし,リーフ・ノード (インスタンスと対応する値を持ちうる MIB 変数に相当),あるいは特定のインスタンスも,サブツリーとして登録することができます。
マスタ・エージェントは,プレフィックスが最長で,最適な優先度の MIB サブツリーを持つサブエージェントへ要求を送ります。
6.2.2 オブジェクト・テーブル
mosy
および
snmpi
ユーティリティによって,MIB からオブジェクト・テーブルを定義する C 言語コードが生成されます。
オブジェクト・テーブルは,サブエージェント内にコンパイルされる
subtree_tbl.h
および
subtree_tbl.c
ファイルで定義されます。
これらのモジュールは,上記のユーティリティによって作成されます。
編集しないことをお勧めします。
MIB を変更する場合,あるいは将来のバージョンの eSNMP 開発ユーティリティがオブジェクト・テーブルを再作成する場合,これらのファイルに対して編集を加えていなければより簡単にファイルを再作成/再コンパイルできます。
6.2.2.1 subtree_tbl.h ファイル
subtree_tbl.h
ファイルには,次の情報が含まれています。
MIB サブツリー構造の宣言
MIB サブツリーにおける各 MIB 変数のためのインデックス定義
計数値を持つ MIB 変数のための列挙定義
MIB グループ・データ構造体定義
メソッド・ルーチンの関数プロトタイプ
MIB サブツリー構造の宣言
MIB サブツリーは,subtree_tbl.c
ファイルのコードによって自動的に初期化されます。
この構造へのポインタは,マスタ・エージェントに MIB サブツリーを登録するために
esnmp_register
ルーチンへ渡されます。
この MIB サブツリーに関するオブジェクト・テーブルへのすべてのアクセスは,このポインタを通して行なわれます。
宣言の形式は次のとおりです。
extern
SUBTREE
subtree_subtree;
インデックス定義
SUBTREE
における各 MIB 変数に対するインデックス定義は,次の形式です。
#define I_mib-variable nnnn
これらの値は MIB サブツリー内の各 MIB 変数に対してユニークで,この MIB 変数のためのオブジェクト・テーブルへのインデックスです。
また,これらの値は,スイッチ操作で使用できるように同じメソッド・ルーチンでインプリメントされている変数を区別するのにも使用されます。
列挙定義
"SYNTAX INTEGER" および列挙された値で定義される MIB 変数に対する列挙定義は,次の形式です。
#define D_mib-variable_enumeration-name value
列挙定義は,計数 MIB 値がとる可能性のある構造値を記述するため,有用です。 次に例を示します。
/* enumerations for gameEntry group */ #define D_gameStatus_complete 1 #define D_gameStatus_underway 2 #define D_gameStatus_delete 3
データ構造体定義
MIB グループ・データ構造体定義は,次の形式です。
typedef struct xxx
{type mib-variable;
.
.
.char mib-variable_mark;
.
.
.
}mib-group_type
データ構造体が,MIB サブツリー内の各MIB グループに対して送られます。
各構造体定義には,グループ内の各MIB 変数を表すフィールドが含まれています。
subtree_tbl.h
ファイルが作成されるときに
snmpi
プログラムに渡される MIB のプール内で MIB 変数名が ユニークでない場合,それをユニークにするために
snmpi
プログラムは,親変数の名前 (グループ名) で名前を限定しません。
MIB 変数フィールドに加えて,各変数に対して 1 バイトの
mib-variable_mark
フィールドが構造体に含まれています。
このフィールドは,MIB 変数の状態を管理するために使用することができます。
次に示すのは,chess
MIB のグループ構造体の例です。
typedef struct _chess_type { OID chessProductID; int chessMaxGames; int chessNumGames; char chessProductID_mark; char chessMaxGames_mark; char chessNumGames_mark; } chess_type;
MIB グループ構造体はユーザが使用するために提供されますが,必須ではありません。
メソッド・ルーチンの中で最も簡単な構造体を使用することができます。
メソッド・ルーチン関数プロトタイプ
MIB サブツリー内の各 MIB グループは,メソッド・ルーチン・プロトタイプを定義してます。 MIB グループは,同じ親ノードを持つリーフ・ノードの MIB 変数の集まりです。
Get
,GetNext
,および
GetBulk
操作を処理するメソッド・ルーチンに対しては関数プロトタイプが常にあります。
グループに書き込み可能変数が含まれる場合は,SET
操作を処理するメソッド・ルーチン用の関数プロトタイプもあります。
これらのルーチンへのポインタは,subtree_tbl.c
モジュールで初期化される MIB サブツリーのオブジェクト・テーブルに含まれています。
次のように,定義されている各プロトタイプに対してメソッド・ルーチンを作成する必要があります。
extern int mib-group_get(
METHOD *method
);
extern int mib-group_set(
METHOD *method
);
次に例を示します。
extern int chess_get(METHOD *method); extern int chess_set(METHOD *method);
メソッド・ルーチンについての詳細は,6.3.2.3 項を参照してください。
6.2.2.2 subtree_tbl.c ファイル
subtree_tbl.c
ファイルには次の情報が含まれています。
各 MIB 変数の OID を表す整数の配列
OBJECT
構造体の配列 (esnmp.h
参照)
初期化された
SUBTREE
構造体
整数の配列
MIB サブツリーにおける各 MIB 変数の OID として使用される整数の配列は,次の形式です。
static unsigned int elems[] = { ...
OBJECT 構造体
MIB サブツリー内の各 MIB 変数に対して 1 つの
OBJECT
があります (esnmp.h
を参照)。
OBJECT
は MIB 変数を表現し,次のフィールドを持ちます。
object_index
--
subtree_tbl.h
ファイルからの定数
I_mib-variable
oid
-- 変数の OID (elems[]
の部分をポイントする)
type
-- 変数のデータ型
getfunc
--
Get
操作のために呼び出すメソッド・ルーチンのアドレス
setfunc
--
Set
操作のために呼び出すメソッド・ルーチンのアドレス
マスタ・エージェントは,オブジェクト・テーブルあるいは MIB 変数についての情報は持っていません。
マスタ・エージェントは,MIB サブツリーの登録情報のみを管理します。
特定の MIB 変数に対する要求を受け取った場合,次のように処理されます。
以下の手順では,MIB 変数は
mib_var
で MIB サブツリーは
subtree_1
です。
マスタ・エージェントは,MIB サブツリーの登録情報内で
mib_var
の最も優先度が高い領域として
subtree_1
を見つけます。
最も優先度の高い領域は,プレフィックスが最長で,最適な優先度を持つ登録済みの MIB サブツリーとして決定されます。
マスタ・エージェントは,subtree_1
を登録したサブエージェントに eSNMP メッセージを送ります。
サブエージェントは登録済み MIB サブツリーのリストを照会して
subtree_1
を探し,subtree_1
のオブジェクト・テーブルで次のものを探します。
mib_var
(Get
および
Set
要求の場合)
mib_var
の後の最初のオブジェクト
(GetNext
あるいは
GetBulk
要求の場合)
サブエージェントは,適切なメソッド・ルーチンを呼び出します。
メソッド・ルーチンが正常に終了すると,マスタ・エージェントへデータが返されます。
正常に終了しなかった場合,Get
あるいは
Set
に対してはエラーが返されます。
GetNext
あるいは
GetBulk
に対しては,メソッド・ルーチンが正常に終了するかあるいはすべてのオブジェクトを実行するまで,libesnmp
ライブラリ・コードはその後に続く
subtree_1
のオブジェクト・テーブルのオブジェクトを実行し続けます。
どちらの場合も適切な応答が返されます。
GetNext
あるいは
GetBulk
ルーチンで
subtree_1
がデータを返せなかったことをマスタ・エージェントが検出した場合,サブエージェントが値を返すか,MIB サブツリーの登録情報がなくなるまでsubtree_1
の後のサブツリーを繰り返し実行します。
初期化済み SUBTREE 構造体
SUBTREE
構造体へのポインタが,MIB サブツリーを登録するために
esnmp_register
eSNMP ライブラリ・ルーチンへ渡されます。
ライブラリ・ルーチンは,このポインタを通してオブジェクト構造体を見つけます。
次に示すのは
chess
サブツリー構造体の例です。
SUBTREE chess_subtree = { "chess", "1.3.6.1.4.1.36.2.15.2.99", { 11, &elems[0] }, objects, I_moveStatus};
SUBTREE
構造体は次の要素を含んでいます。
name
MIB サブツリーのベース・ノードの名前
dots
MIB サブツリー の OID の ASCII 文字列表現。 実際に登録される値。
oid
サブツリーのベース・ノードの OID。 整数の配列をポイントする。
object_tbl
オブジェクト・テーブルに含まれるオブジェクトの配列へのポインタ。
subtree_tbl.h
ファイルに記述されている
I_xxxx
定義によって示される。
last
object_tbl
ファイルの最後のオブジェクトのインデックス。
テーブルの最後に到達したことを検知するために使用されます。
subtree_tbl.c
の最後のセクションには,mib-group_type
構造体を割り当て/解放するための短いルーチンが含まれています。
この部分は必ずしも API の一部として提供する必要はありません。
6.2.3 サブエージェントの実現
サブエージェント開発者は,通常,UNIX アプリケーションや,デーモン,ドライバ (たとえば
gated
デーモンや ATM ドライバ) が提供されており,SNMP インタフェースを実現する必要があります。
以下に,その手順を示します。
MIB 仕様の入手
MIB の開発は MIB 仕様から始まり,通常は RFC の形式です。 SNMPv1 については,仕様は RFC 1212 に従って コンサイス MIB フォーマットで作成されます。 SNMPv2c については,仕様は,それぞれ RFC 1902 および RFC 1903 で指定されている SMIv2 および textual conventions で作成されます。 MIB の設計および仕様決定については,本書では触れません。 すでに MIB 仕様をお持ちであることを前提に説明します。
標準の RFC は,次の URL の RFC サイトから入手できます。
http://www.rfc-editor.org/rfc.html
ユーザ自身の MIB 仕様を作成する必要がある場合は,他のベンダが作成した同じような MIB を参考にして行うことができます。 公開 MIB のソースは,次の URL の Network Management ページのアーカイブ・セクションで参照することができます。
http://smurfland.cit.buffalo.edu/NetMan/index.html
サブエージェントで実現しようとしているすべての要素に対する MIB,およびそれらが参照する MIB が必要になります。
最低限必要なのは,SMIv2 MIB
snmp-smi.my
と textual convention
snmp-tc.my
です。
これらは
/usr/examples/esnmp
ディレクトリにあります。
MIB をコンパイルします。
MIB 定義を入手したら,それらを使用して新しいサブエージェント用のオブジェクト・テーブルを生成します。 目的は,各 MIB の MIB 仕様テキストを取り出し,ASN.1 仕様を抽出して,それらをローカル・オブジェクト・テーブルを含む C 言語モジュールにコンパイルすることです。
次のツールを使用して MIB をコンパイルします。
mib-converter.sh
mib-converter.sh
は,RFC テキストから MIB ASN.1 定義を抽出するための
awk
シエル・スクリプトです。
このステップでは,MIB 定義の前後を削除し,ページ・ヘッダおよびフッダを削除します。
mib-converter.sh
スクリプトは,不要なものをすべて削除してくれるわけではありません。
このため,場合によってはテキスト・エディタを使用して手作業で削除する必要があります。
mib-converter.sh
スクリプトの使用例を次に示します。
# /usr/examples/esnmp/mib-converter.sh mib-def.txt > \ mib-def.my
RFC によっては複数の MIB 定義を含む場合がありますので注意してください。
mib-converter.sh
スクリプトは,単一の MIB 定義を含む RFC に対してのみ使用することができます。
mosy
コンパイラも,複数の MIB 定義を含むファイルは処理できません。
複数の MIB 定義を含む RFC を使用する場合は,それぞれを別々の入力ファイルに分割します。
抽出された MIB ASN.1 定義を含む結果の出力ファイルは,次のような形式になります。
mib-def.my
mosy
mosy
コンパイラは,mib-converter.sh
スクリプトによって作成された
.my
ファイルを解析し,それらを
.defs
ファイルにコンパイルします。
.defs
ファイルは,MIB 内のオブジェクト階層構造を記述します。
.defs
ファイルは,いくつかのツールのフロント・エンドになっています。
mosy
コンパイラの使用例を次に示します。
# mosy mib-def.my
mosy
コンパイラは
mib-def.defs
ファイルを作成します。
この
mosy
プログラムは,4BSD/ISODE SNMPv2 パッケージで配布されている ISODE 8.0 に含まれているものです。
snmpi
MIB データ・イニシャライザ作成プログラム (snmpi
) は,mosy
コンパイラによってコンパイルされた
.def
ファイルの連鎖を読み取り,指定された MIB サブツリーのオブジェクト・テーブルの静的な構造を定義する C コードを生成します。
注意
このオペレーティング・システムで提供する
snmpi
プログラムは BSD/ISODE SMUX のsnmpi
プログラムとは異なります。
mosy
コンパイラによってコンパイルされた
.def
ファイルは,objects.defs
ファイルに連鎖させてください。
また,コンパイルしたバージョンの
snmp-smi.my
および
snmp-tc.my
を含めてください。
objects.defs
ファイルには,サブツリーで使用されていないものも含めて,すべての MIB 名を解決するのに必要な全 MIB を含める必要があります。
オブジェクト・テーブル・ファイルは次のコマンドで生成します。
# /usr/sbin/snmpi objects.defs subtree
snmpi
プログラムは,objects.defs
ファイルに含まれているオブジェクトの結果として生成されたツリー全体の内容をダンプするためのプリント・オプションを備えています。
サブツリーに問題がある場合,この情報が役に立つ場合があります。
リストを生成する場合は次のコマンドを使用してください。
# /usr/sbin/snmpi -p objects.defs > objects.txt
snmpi
プログラムは
subtree_tbl.c
および
subtree_tbl.h
を出力します。
ここで
subtree
は,MIB サブツリーのベース MIB 変数名です。
これらの 2 つのファイルは,指定したサブツリーの MIB オブジェクト・テーブルを初期化するための C コードです (これはローカル・オブジェクト・テーブルです)。
サブエージェントで実現されている各 MIB ツリーに対して,この処理を繰り返してください。
snmpi
プログラムは省略時の設定により,メソッド・ルーチンの細分性レベルとして MIB グループを使用するように設定されています。
つまり,グループ内のすべての MIB 変数は同じメソッド・ルーチンによってサービスが行われるという前提があります。
(このプログラムは,これを支援するための
mib-group_type
データ構造体も提供します。
)
mib-group_type
構造体は API の一部ではありません。
利便性のために提供されています。
この構造体は,オブジェクト・テーブルの
mib-group
を使用する際に役立ちます。
これは,それらのオブジェクトが論理的に関連していて,通常はグループとしてアクセスされるためです。
たとえば
ipRoutes
は,だいたい,カーネルルーティング・テーブルから返されます。
メソッド・ルーチンおよび API コールをコーディングします。
マスタ・エージェント (snmpd
) との通信を初期化し MIB を登録するための eSNMP ライブラリ API を呼び出すコードを作成します
(6.2.4 項参照)。
必要なメソッド・ルーチンのためのコードを作成します (6.3 節参照)。
通常は,登録された MIB サブツリー内の各 MIB グループに対して,1 つの
Get
メソッド・ルーチンと 1 つの
SET
メソッド・ルーチンが必要になります。
前のステップで生成された
subtree_tbl.h
ファイルは,各メソッド・ルーチンの名前と関数プロトタイプを定義します。
サブエージェントを作成します。
/usr/examples/esnmp
ディレクトリにサンプルの Makefile (chess.mk
) が提供されています。
サブエージェントの実行とテストを行います。
他のプログラムやデーモンと同じようにサブエージェントを実行します。
デバッグ処理で使用できるように eSNMP ライブラリ・ルーチンにトレース機能が組み込まれています。
この機能を使用する場合は,main
セクションで
set_debug_level
ルーチンを使用してください。
サブエージェントが初期化され,MIB サブツリーが正しく登録されると,HP Insight Manager,HP Openview,あるいはその他の MIB ブラウザなどの標準アプリケーションを使用して,SNMP 要求を送信することができます。
SNMP アプリケーションにアクセスできない場合は,snmp_request
,snmp_traprcv
および
snmp_trapsnd
プログラムを使用してサブエージェントのデバッグを行うことができます。
対話式デバッグを行うと,サブエージェントが SNMP 要求のタイムアウトの原因になることに注意してください。
通常,すべてのエラーおよび警告メッセージは,システムのデーモン・ログに記録されます。
chess
サブエージェントおよび
os_mibs
サブエージェントを実行する場合,次のようにトレース実行時引数を指定します。
os_mibs -trace
トレース・オプションが有効な場合,プログラムはデーモンとして実行されず,すべてのトレース出力は
stdout
に送られ,処理される各メッセージを表示します。
この機能は,サブエージェントで
set_debug_level
ルーチンを呼び出し
TRACE
パラメータを渡すことによって使用できます。
デバッグ・マクロで渡されるものは,次のように
stdout
に送られます。
ESNMP_LOG
((TRACE,("message_text \n"));
警告メッセージを表示しないですべてをデーモン・ログに送るには,set_debug_level
ルーチンを呼び出して
WARNING || DAEMON_LOG
パラメータを渡すか,あるいは,set_debug_level
ルーチンを呼び出して
ERROR || DAEMON_LOG
パラメータを渡します。
eSNMP API は,マスタ・エージェント (snmpd
) に密接に結び付かない自主的なサブエージェントのために提供します。
サブエージェントは,他のサブシステムあるは製品の 1 部分でもあり,SNMP とは関連しない本来の機能を持っています。
たとえば,gated
デーモンは本来はインターネット・ルーティングに関係していますが,サブエージェントとしても機能します。
特に,snmpd
デーモンは,スタートアップあるいはシャットダウン・プロシージャの中ではどのサブエージェント・デーモンの起動/停止も行いません。
また,サブエージェントに関するディスク上の構成情報の保守も行いません。
snmpd
デーモンは,以前のサブエージェントあるいはサブツリーの登録情報については,起動時には何も持っていません。
通常,オペレーティング・システム上の各デーモンは,システムの実行レベルが変わる際にすべて一緒に開始あるいは停止します。
しかしサブエージェントは,snmpd
デーモンの前にそれらをどこで開始するか,あるいは構成ファイルから情報を再ロードするために
snmpd
デーモンを再起動する間それらをどこで実行しているか,正しく状況を処理する必要があります。
このような状況では,サブエージェントは,次の項で説明するように eSNMP プロトコルを再起動する必要があります。
6.2.4.1 操作の順序
一連のサブエージェント・プロトコルの操作は次のとおりです。
初期化 (esnmp_init
)
複数のサブエージェント間で共用されるテーブルで必要なインデックスの割り当て (esnmp_allocate
)
登録 (esnmp_register [esnmp_register ...]
)
データ通信
次のようなループを繰り返し実行します。
{ determine sockets with data pending if the eSNMP socket has data pending esnmp_poll periodically call esnmp_are_you_there as required during periods of inactivity }
終了 (esnmp_term
)
サブエージェントを終了する際に
esnmp_term
関数を呼び出すことは非常に重要です。
この操作によって eSNMP は,サブエージェントが使用していたシステム・リソースを解放します。
サブエージェント・プロトコル操作のコーディング方法については,/usr/examples/esnmp
ディレクトリのサンプル・サブエージェントを参照してください。
6.2.4.2 関数の戻り値
eSNMP API 関数の戻り値は,要求された操作の成功あるいは失敗と,マスタ・エージェントの状態を,サブエージェントに示します。 以下に,各戻り値の意味とサブエージェントの対処を示します。
ESNMP_LIB_OK
操作が成功しました。
ESNMP_LIB_NO_CONNECTION
サブエージェントとマスタ・エージェントを接続できません。
この値は,esnmp_init
関数によって返されます。
原因
マスタ・エージェントが実行されていません。 あるいは応答がありません。
対処
一定時間経過後
esnmp_init
を呼び出してプロトコルを再起動します。
ESNMP_LIB_BAD_ALLOC
1 つまたは複数のインデックスを割り当てることができません。
この値は,esnmp_allocate
関数によって返されます。
原因は次のとおりです。
esnmp_allocate
関数を呼び出す前に,esnmp_init
関数が正常に呼び出されていません。
esnmp_allocate
関数のいずれかのパラメータが不正です。
ログ・ファイルを参照して,不正なパラメータを調べてください。
対処
正しい順序と正しい引数で
esnmp_allocate
関数を呼び出します。
ESNMP_LIB_BAD_DEALLOC
1 つまたは複数のインデックスを割り当て解除できません。
この値は,esnmp_deallocate
関数によって返されます。
原因は次のとおりです。
esnmp_deallocate
関数を呼び出す前に,esnmp_init
関数が正常に呼び出されていません。
esnmp_deallocate
関数のいずれかのパラメータが不正です。
ログ・ファイルを参照して,不正なパラメータを調べてください。
対処
正しい順序と正しい引数で
esnmp_deallocate
関数を呼び出します。
ESNMP_LIB_LOST_CONNECTION
マスタ・エージェントとの通信が途切れました。
この値は,esnmp_register
,esnmp_poll
,esnmp_are_you_there
,esnmp_unregister
,あるいは
esnmp_trap
関数によって返されます。
原因
マスタ・エージェント・ソケットへのパケット送信が失敗しました。 通常は,マスタ・エージェントの異常終了が原因です。
対処
一定時間経過後,esnmp_init
を呼び出してプロトコルを再起動します。
ESNMP_LIB_BAD_REG
登録の送信が失敗しました。
この値は,esnmp_register
,esnmp_unregister
,あるいは
esnmp_poll
関数が返します。
原因は次のとおりです。
esnmp_register
関数を呼び出す前に,esnmp_init
関数が正しく呼び出されていません。
esnmp_register
関数の
timeout
パラメータが正しくありません。
esnmp_register
に渡されたサブツリーはすでに登録のためにキューイングされています。
あるいは,すでにこのサブエージェントによって登録されています。
以前の登録が失敗しています (esnmp_poll
関数によって返された場合)。
失敗の原因および失敗したサブツリーについては,ログ・ファイルを参照してください。
登録されていないサブツリーの登録を解除しようとしています (esnmp_unregister
関数によって返された場合)。
対処
正しい引数を指定して,適切な順序で
esnmp_register
を呼び出します。
ESNMP_LIB_CLOSE
マスタ・エージェントが停止しています。
この値は,esnmp_poll
関数によって返されます。
原因
マスタ・エージェントを命令に従ってシャットダウンしています。
対処
esnmp_init
関数でプロトコルを再起動します。
ESNMP_LIB_NOTOK
eSNMP プロトコル・エラーが発生して,パケットが廃棄されました。
この値は,esnmp_poll
あるいは
esnmp_trap
関数によって返されます。
原因
サブエージェント内のメモリ・リソースの不足が原因でパケット・レベルのプロトコル・エラーが発生しています。
対処
続行します。
6.3 拡張 SNMP アプリケーション・プログラミング・インタフェース
以降の節では,SNMP アプリケーション・プログラミング・インタフェースに関して,次の項目について詳しく説明します。
呼び出しインタフェース
メソッド・ルーチン呼び出しインタフェース
libesnmp
サポート・ルーチン
esnmp_init
esnmp_allocate
esnmp_deallocate
esnmp_register
esnmp_register2
esnmp_unregister
esnmp_unregister2
esnmp_capabilities
esnmp_uncapabilities
esnmp_poll
esnmp_are_you_there
esnmp_trap
esnmp_term
esnmp_sysuptime
esnmp_init
ルーチンは,eSNMP サブエージェントをローカルに初期化し,マスタ・エージェントとの通信を開始します。
このコールは,マスタ・エージェントからの応答を待つ間ブロックは行いません。
esnmp_init
ルーチンを呼び出したら,サブエージェントが扱う各 MIB サブツリーに対して
esnmp_register
ルーチンを呼び出します。
このルーチンは,プログラム初期化中か,eSNMP プロトコルの再起動のために呼び出してください。
再起動の場合,esnmp_init
ルーチンはすべての登録をクリアするので各サブツリーを再登録する必要があります。
プログラム名 (argv[0]
) に説明的なテキストを追加して,ユニークな
subagent_identifier を作成するようにします。
esnmp_init
ルーチンの構文は次のとおりです。
int esnmp_init(
int *socket,
char *subagent_identifier
);
引数は次のとおりです。
eSNMP が使用するソケット記述子を受信する整数のアドレス。
サブエージェントを識別するヌルで終る文字列 (通常はプログラム名) のアドレス。
戻り値は次のとおりです。
初期化できないかあるいはマスタ・エージェントと通信できません。 後で再度実行してください。
esnmp_init
ルーチンが正常に終了しました。
サブエージェントにメモリを割り当てられませんでした。
次に示すのは
esnmp_init
ルーチンの例です。
#include <esnmp.h> int socket; status = esnmp_init(&socket, "gated");
esnmp_allocate
ルーチンは,1 つまたは複数の特定のインデックス・オブジェクトに対する値の割り当てを要求します。
インデックスの割り当ては,AgentX に準拠したマスタ・エージェントが提供するサービスです。 これは,お互いに関する知識を持たないサブエージェント間で,MIB の概念的テーブルを共用するための機能です。 マスタ・エージェントはインデックス・オブジェクト (OID) と,各インデックスに割り当てられている値からなるデータベースを保守します。 マスタ・エージェントは,各インデックスが表す MIB 変数 (ある場合) を意識しません。 規約により,サブエージェントの開発者は,INDEX 句にリストされている MIB 変数を,値を割り当てるインデックス・オブジェクトとして使用する必要があります。
複数の変数でインデックスされるテーブルでは,各インデックスに対してそれぞれ値を割り当てることができますが,多くの場合これは不要です。 サブエージェントは,次の割り当てタイプのいずれかで要求することができます。
特定のインデックス値
現在割り当てられていないインデックス値
一度も割り当てられていないインデックス値
2 番目と 3 番目のタイプは,多くの MIB 仕様で,不特定の整数インデックスに対し一意性と不変性が要求されるために必要になります。
たとえば,IF-MIB (RFC 2233) の
ifIndex
,FDDI MIB (RFC 1285) の
snmpFddiSMTIndex
,System Application MIB (RFC 2287) の
sysApplInstallPkgIndex
があります。
サブエージェントがこのようなインデックスを用いてテーブルを共用しなければならないということが,インデックス割り当てメカニズムが必要な主な理由です。
インデックス割り当てと MIB リージョン登録は,マスタ・エージェント内で連動していません。 マスタ・エージェントは,登録要求を処理する際に,インデックス割り当ての現在の状態を考慮しません。 また,インデックスの割り当て要求を処理する際に,現在の登録状況を考慮することもありません。 これは主に,非 AgentX のサブエージェントの便宜を図るためです。
サブエージェントの開発者は,まずインデックスの割り当てを要求し,次に対応するリージョンを登録しなければなりません。 この順序で実行すると,インデックス割り当て要求に成功したときに,サブエージェントは,何を登録できるかということに対する適切なヒント (ただし保証ではない) を得ることができます。 他のエージェントがテーブルのその row にすでに登録しているために,登録に失敗することがあります。
サブエージェントは,共用テーブルの概念的な row を次の順序で登録する必要があります。
インデックス値を正常に割り当てます。
割り当てられたインデックス値をESNMP_REG
構造体の
instance
フィールドに設定し,esnmp_register2
ルーチンに渡します。
このようにして,eSNMP サブエージェント開発者は,サブツリーとその
ESNMP_REG
構造体の任意の
range_subid
および
range_upper_bound
フィールドで指定される MIB リージョンを完全に限定できます。
サブエージェントの開発者は,インスタンスにより登録を行う場合は,priority
フィールドを 255 に設定しなければなりません。
結果コード ESNMP_REG_STATE_REGDUP で登録に失敗した場合は,以前に割り当てたインデックス値を
esnmp_deallocate
ルーチンでこの row から割り当て解除し,ステップ 1 からもう一度処理を始めます。
インデックス割り当ては,インデックスが任意の値であり,サブエージェント開発者が,どのインデックス値を使えばよいか判断できない場合にのみ必要になります。
インデックス値に固有の意味がある場合,サブエージェントではそのインデックス値を割り当てないようにします。
たとえば,RFC 1514
では,実行中のソフトウェア・プロセスのテーブル (hrSWRunTable
) は,システム固有のプロセス識別子 (pid) によってインデックスされます。
サブエージェント自身のプロセスに対応する
hrSWRunTable
の row を実装するサブエージェントでは,その row のオブジェクト・インスタンスを定義するリージョンを登録します。
インデックス値を割り当てる必要はありません。
esnmp_allocate
ルーチンの構文は次のとおりです。
int esnmp_allocate(
ESNMP_ALLOC *alloc_parm
);
引数の定義は次のとおりです。
ESNMP_ALLOC
構造体へのポインタ。
呼び出す側は,この構造体とこれから参照される
VARBIND
リストを (メモリ内に) 継続的に確保しなければなりません。
これは,eSNMP の実行時ライブラリが,マスタ・エージェントから返される,インデックス割り当て要求の結果をフィールドに格納するために必要です。
この構造体には,次のようなフィールドがあります。
1 つまたは複数の
VARBIND
からなる変数バインディング・リストへのポインタ。
リスト内の
VARBIND
にはそれぞれ,値を割り当てるインデックス・オブジェクトの名前が含まれています。
各
VARBIND
にはそれぞれ値が必要です。
ESNMP_ALLOC_ANY_INDEX フラグと ESNMP_ALLOC_NEW_INDEX フラグのどちらも指定されていない場合,マスタ・エージェントは,インデックス割り当て要求を処理する際に,指定された値すべてを使用します。
ESNMP_ALLOC_ANY_INDEX フラグまたは ESNMP_ALLOC_NEW_INDEX フラグが指定された場合,マスタ・エージェントは,インデックス割り当て要求を処理する際に,指定された値をすべて無視し,各
VARBIND
には適切な値を生成します。
次の値のビットマスク。
インデックス割り当て要求は,クラスタ・コンテキストに対するものです。
このインデックス割り当て要求では,新しい値の割り当てを要求します。
マスタ・エージェントは,実行を開始して以来使用されていない
VARBIND
に対してそれぞれ値を生成します。
これらの値は,成功応答で返されます。
このインデックス割り当て要求では,未使用の値の割り当てを要求します。
マスタ・エージェントは,実行を開始してから使用されたか使用されていないかに関係なく
VARBIND
に対してそれぞれ値を生成します。
これらの値は,成功応答で返されます。
次に示す整数値のいずれかをとり,呼び出し側に対して,インデックス割り当て要求の状態を示します。
この状態コードは非同期に更新されます。
esnmp_poll
ルーチンから戻った後,呼び出し側は,このパラメータを調べることができます。
以下の状態コードでは,alloc->error_index
フィールドには値ゼロ (0) が格納されています。
インデックス割り当て要求は,現在ローカルに保留されており,マスタ・エージェントへの接続を待っています。
インデックス割り当て要求は,マスタ・エージェントに送信されました (最終状態はまだ保留)。
マスタ・エージェントは,インデックス割り当て要求の処理に成功し肯定応答を返しました。
これでサブエージェントは,esnmp_register2
呼び出しに渡す
esnmp_reg->instance
フィールドで,割り当てられたインデックス値を使用できます。
以下の状態コードでは,alloc->error_index
フィールドにはゼロ以外の値が格納されています。
インデックス・タイプまたはオプションが不正のため,マスタ・エージェントはインデックス割り当て要求をリジェクトしました。
指定されたインデックス・オブジェクトの値が現在使用されているため,マスタ・エージェントはインデックス割り当て要求をリジェクトしました。
要求されたインデックス・オブジェクトに対して使用できる値がないため,マスタ・エージェントはインデックス割り当て要求をリジェクトしました。 この状態は,ESNMP_ALLOC_NEW_INDEX または ESNMP_ALLOC_ANY_INDEX オプションを指定した場合にのみ返されます。
クラスタ・コンテキスト・オプションをサポートしていないため,マスタ・エージェントはインデックス割り当て要求をリジェクトしました。
マスタ・エージェントはその他の理由でインデックス割り当て要求をリジェクトしました。
状態コードが
alloc.vb
varbind リスト内のどの
VARBIND
(1 から開始) に対応しているかを示します。
esnmp_poll
ルーチンから戻った後,呼び出し側はこのパラメータを調べることができます。
戻り値は次のとおりです。
alloc_parm 引数が指定されていません。
esnmp_allocate
ルーチンは正常に終了しました。
サブエージェントとマスタ・エージェントの通信が途切れました。
サブエージェントとマスタ・エージェントが接続されていないか,alloc_parm
引数によって指定された
VARBIND
に有効なものがありません。
ログ・ファイルにもメッセージが出力されます。
この戻り値は,インデックス割り当て要求の開始のみを示していることに注意してください。
マスタ・エージェントからの応答で返された実際の状態コードは,その後
esnmp_poll
ルーチンを呼び出したときに,alloc->status
および
alloc->error_index
フィールドに返されます。
esnmp_allocate
ルーチンの例を,次に示します。
#define INDENT_SIZE 4 #define RESPONSE_TIMEOUT 0 /* use the default time set in esnmp_init message */ #define REGISTRATION_PRIORITY 128 /* priority at which the MIB subtree will register */ #define RANGE_SUBID 10 /* the identifier position in oid->elements just after ifEntry */ #define RANGE_UPPER_BOUND 22 /* the identifier for ifSpecific, under ifEntry */ int rc, status; unsigned int our_ifIndex_instance = 0; int ready_to_register = 0; int have_a_good_registration = 0; extern SUBTREE ifEntry_subtree; /* generated by /usr/sbin/snmpi -r ifEntry */ OBJECT *ifIndex_object = &ifEntry_subtree.object_tbl[I_ifIndex]; static ESNMP_ALLOC esnmp_alloc_for_ifIndex; /* retain this structure to obtain status code and index object values. Also, retain this structure for a subsequent call to esnmp_deallocate */ static ESNMP_REG esnmp_reg_for_ifEntry; /* retain this structure for a subsequent call to esnmp_unregister2 */ static OID ifEntry_instance_oid; VARBIND *vb; /* * initialize the ESNMP_ALLOC structure */ memset(&esnmp_alloc_for_ifIndex, 0, sizeof(ESNMP_ALLOC)); esnmp_alloc_for_ifIndex.options = ESNMP_ALLOC_NEW_INDEX; esnmp_alloc_for_ifIndex.vb = vb = (VARBIND *)malloc(sizeof(VARBIND)); bzero((char *)vb, sizeof(VARBIND)); clone_oid(&vb->name, &ifIndex_object->oid); o_integer(vb, ifIndex_object, (unsigned long)0); /* master will return actual value assigned */ while(!have_a_good_registration) { status = esnmp_allocate(&esnmp_alloc_for_ifIndex ); if (status != ESNMP_LIB_OK) { printf("Could not queue the 'ifIndex' \n"); printf("index object for index allocation\n") }
.
.
.
rc = esnmp_poll();
.
.
.
if (esnmp_alloc_for_ifIndex.status > ESNMP_ALLOC_STATE_SENT) { /* * esnmp_alloc_for_ifIndex.status nows contain the final * status from the master agent. */ switch(esnmp_alloc_for_ifIndex.status) { case ESNMP_ALLOC_STATE_DONE our_ifIndex_instance = esnmp_alloc_for_ifIndex.vb->value.ul; ready_to_register = 1; printf("\n*** Successful index allocation. Our conceptual row in the"); printf("\n*** interfaces table was allocated. ifIndex value is %i\n\n", our_ifIndex_instance); break; case ESNMP_ALLOC_STATE_ALLOCTYPE: printf("\n*** Failed index allocation - 'allocation type'"); printf("\n*** associated with supplied varbind #%i.\n\n", esnmp_alloc_for_ifIndex.error_index); break; case ESNMP_ALLOC_STATE_ALLOCINUSE: printf("\n*** Failed index allocation - 'allocation in use'"); printf("\n*** associated with supplied varbind #%i.\n\n", esnmp_alloc_for_ifIndex.error_index); break; case ESNMP_ALLOC_STATE_ALLOCAVAIL: printf("\n*** Failed index allocation - 'no available values'"); printf("\n*** associated with supplied varbind #%i.\n\n", esnmp_alloc_for_ifIndex.error_index); break; case ESNMP_ALLOC_STATE_ALLOCNOCLU: printf("\n*** Failed index allocation - 'cluster context not supported'"); printf("\n*** associated with supplied varbind #%i.\n\n", esnmp_alloc_for_ifIndex.error_index); esnmp_alloc_for_ifIndex.options &= ~ESNMP_ALLOC_CLUSTER; break; case ESNMP_ALLOC_STATE_REJ: printf("\n*** failed index allocation - 'other reasons'"); printf("\n*** associated with supplied varbind #%i.\n\n", esnmp_alloc_for_ifIndex.error_index); break; } /* End switch */ } /* End if */ if (ready_to_register) { vb = esnmp_alloc_for_ifIndex.vb; memset(&esnmp_reg_for_ifEntry, 0, sizeof(ESNMP_REG)); esnmp_reg_for_ifEntry.subtree = &ifEntry_subtree; esnmp_reg_for_ifEntry.priority = REGISTRATION_PRIORITY; esnmp_reg_for_ifEntry.timeout = RESPONSE_TIMEOUT; esnmp_reg_for_ifEntry.range_subid = RANGE_SUBID; esnmp_reg_for_ifEntry.range_upper_bound = RANGE_UPPER_BOUND; ifEntry_instance_oid.nelem = 1; ifEntry_instance_oid.elements = &our_ifIndex_instance; esnmp_reg_for_ifEntry.instance = (OID *)malloc(sizeof(OID)); esnmp_reg_for_ifEntry.instance = clone_oid(esnmp_reg_for_ifEntry.instance, &ifEntry_instance_oid); status = esnmp_register2(&esnmp_reg_for_ifEntry); if (status != ESNMP_LIB_OK) { printf("Could not queue the registration for 'ifEntry'\n"); } else {
.
.
.
rc = esnmp_poll();
.
.
.
if (esnmp_reg_for_ifEntry.state > ESNMP_REG_STATE_SENT) { /* * esnmp_reg_for_ifEntry.status nows contain the final * status from the master agent. */ switch(esnmp_reg_for_ifEntry.state) { case ESNMP_REG_STATE_DONE: printf("\n*** Successful registration for conceptual row in"); printf("\n*** the interfaces table indexed by an ifIndex"); printf("\n*** value of %i.\n\n", our_ifIndex_instance); have_a_good_registration = 1; break; case ESNMP_REG_STATE_REGDUP: printf("\n*** Failed registration - Duplicate registration."); printf("\n*** We need to deallocate this ifIndex value and"; printf("\n*** allocate a new value\n\n"); break; case ESNMP_REG_STATE_REGNOCLU: printf("\n*** Failed registration - Cluster context not supported."); printf("\n*** Need to deallocate this ifIndex value and to"); printf("\n*** allocate a new value in the default context\n\n"); esnmp_alloc_for_ifIndex.options &= ~ESNMP_ALLOC_CLUSTER; break; case ESNMP_REG_STATE_REJ: printf("\n*** Failed registration - Other reasons\n\n"); break; } if (!have_a_good_registration) { esnmp_deallocate(&esnmp_alloc_for_ifIndex); ready_to_register = 0; rc = esnmp_poll(); free_oid(esnmp_reg_for_ifEntry.instance); free(esnmp_reg_for_ifEntry.instance); esnmp_reg_for_ifEntry.instance = NULL; } } } } }
esnmp_deallocate
ルーチンは,1 つまたは複数のインデックス・オブジェクトについて,このサブエージェントに以前に割り当てた値の割り当てを解除するよう,マスタ・エージェントに要求します。
マスタ・エージェントはインデックスの割り当て解除要求を受けると,インデックス・オブジェクト (OID) のデータベースを更新し,指定された値に割り当て解除のマークを付けます。 ここで解放された値は,その後のインデックス割り当て要求での割り当てに使用できます。
esnmp_deallocate
ルーチンの構文は,次のとおりです。
int esnmp_deallocate(
ESNMP_ALLOC *alloc_parm
);
引数の定義は次のとおりです。
ESNMP_ALLOC
構造体へのポインタ。
通常,これは前に呼び出した
esnmp_allocate
で使用された構造体と同じものです。
呼び出す側は,この構造体とこれから参照される
VARBIND
リストを (メモリ内に) 継続的に確保しなければなりません。
これは,eSNMP の実行時ライブラリが,マスタ・エージェントから返される,インデックス割り当て解除要求の結果をフィールドに格納するために必要です。
この構造体には,次のようなフィールドがあります。
1 つまたは複数の
VARBIND
からなる変数バインディング・リストへのポインタ。
リスト内の
VARBIND
にはそれぞれ,割り当て済みインデックス・オブジェクトの名前と値が含まれています。
次の値のビットマスク。
インデックス割り当て要求は,クラスタ・コンテキストに対するものです。
次に示す整数値のいずれかをとり,呼び出し側に対して,インデックス割り当て解除要求の状態を示します。
この状態コードは非同期に更新されます。
esnmp_poll
ルーチンから戻った後,呼び出し側は,このパラメータを調べることができます。
以下の状態コードでは,alloc->error_index
フィールドには値ゼロ (0) が格納されています。
インデックス割り当て解除要求は,マスタ・エージェントに送信されました (最終状態はまだ保留)。
マスタ・エージェントは,インデックス割り当て解除要求の処理に成功し肯定応答を返しました。 これでマスタ・エージェントは,その後のインデックス割り当て要求を処理する際に,このインデックス値を再度使用できるようになります。
以下の状態コードでは,alloc->error_index
フィールドにはゼロ以外の値が格納されています。
割り当てが未知であるため,マスタ・エージェントはインデックス割り当て解除要求をリジェクトしました。
マスタ・エージェントはその他の理由でインデックス割り当て解除要求をリジェクトしました。
状態コードが
alloc.vb
リスト内のどの
VARBIND
(1 から開始) に対応しているかを示します。
esnmp_poll
ルーチンから戻った後,呼び出し側はこのパラメータを調べることができます。
戻り値は次のとおりです。
alloc_parm 引数が指定されていません。
esnmp_allocate
ルーチンは正常に終了しました。
サブエージェントとマスタ・エージェントの通信が途切れました。
サブエージェントとマスタ・エージェントが接続されていないか,alloc_parm
引数によって指定された
VARBIND
に有効なものがありません。
ログ・ファイルを参照してください。
この戻り値は,インデックス割り当て解除要求の開始のみを示していることに注意してください。
マスタ・エージェントからの応答で返された実際の状態コードは,その後
esnmp_poll
ルーチンを呼び出したときに,alloc->status
および
alloc->error_index
フィールドに返されます。
esnmp_deallocate
ルーチンの例を,次に示します。
#include <esnmp.h> int status; static ESNMP_ALLOC esnmp_alloc_for_ifIndex; /* structure retained from a previous call to esnmp_allocation(). Retain this structure for update with final status from the master agent */ /* call to unregister2() goes here */ esnmp_alloc_for_ifIndex.options = 0; /* clear options */ status = esnmp_deallocate( &esnmp_alloc_for_ifIndex ); if (status != ESNMP_LIB_OK) { printf("Could not queue the 'ifIndex' \n"); printf("index object for index allocation\n"); }
.
.
.
esnmp_poll();
.
.
.
if (esnmp_alloc_for_ifIndex.status > ESNMP_ALLOC_STATE_SENT) { /* * the final status from the master agent is available */ switch(esnmp_alloc_for_ifIndex.status) { case ESNMP_ALLOC_STATE_DONE: printf("Successful index deallocation for value(s) associated\n"); printf("with the 'ifIndex' index object.\n"); free_varbind(esnmp_alloc_forifIndex.vb); break; case ESNMP_ALLOC_STATE_DEALLOC_REJ: printf("Failed index deallocation due to 'unknown allocation'\n"); printf("associated with supplied varbind #%i.\n", esnmp_alloc_for_ifIndex.error_index); break; case ESNMP_ALLOC_STATE_REJ: printf("Failed index deallocation due to 'other reasons'\n"); printf("associated with supplied varbind #%i.\n", esnmp_alloc_for_ifIndex.error_index); break; } }
esnmp_register
ルーチンは,単一の MIB サブツリーの登録を要求します。
これは,サブエージェントが登録された MIB サブツリー内で MIB 変数のインスタンスを生成することをマスタ・エージェントに示します。
esnmp_register
を呼び出す前に,初期化ルーチン (esnmp_init
) を呼び出す必要があります。
処理しようとする各 MIB サブツリーに対応するそれぞれの
SUBTREE
構造体に対して,esnmp_register
ルーチンを呼び出す必要があります。
esnmp_unregister
を呼び出すと MIB サブツリーの登録が解除され,その後
esnmp_register
を呼び出すと再登録されます。
esnmp_init
を呼び出してeSNMP プロトコルを再起動すると,すべての MIB サブツリーの登録がクリアされます。
この場合,すべての MIB サブツリーを再登録する必要があります。
MIB サブツリーは,MIB 変数名と対応する OID によって識別されます。
この集合は,MIB サブツリーに含まれるすべての MIB 変数の親に相当します。
たとえば,MIB-2
tcp
サブツリーの OID は
1.3.6.1.2.1.6
です。
この OID に従属する (同じ 7 つの識別子で始まる) すべての MIB 変数がサブツリーの領域に含まれています。
MIB サブツリーは,単一の MIB 変数 (リーフ・ノード) でも特定のインスタンスでもかまいません。
MIB サブツリーを登録すると,サブエージェントは,その MIB サブツリーの領域内のすべての MIB 変数 (もしくは OID) に対するSNMP 要求を処理することを表示します。 したがって,サブエージェントは MIB 変数をまだ組み込んでいるいる MIB サブツリーの中で最も完全に (長く) 修飾されたものを登録します。
マスタ・エージェントは,サブエーエジェントが同じ MIB サブツリーを 2 回以上登録できないようにします。 この制限事項を除いて,サブエージェントは,以前に登録した MIB サブツリーの OID 範囲に重複して, あるいは他のサブエージェントが登録した MIB サブツリーの OID 範囲に重複して MIB サブツリーを登録できます。
たとえば,os_mibs
および
gated
の 2 つの Tru64 UNIX デーモンを考えてみると,os_mibs
デーモンは
ip
MIB サブツリー (1.3.6.1.2.1.4) を登録し,gated
デーモンは
ipRouteEntry
MIB サブツリー (1.3.6.1.2.1.4.21.1) を登録します。
ipRouteIfIndex
(1.3.6.1.2.1.4.21.1.2) などの
ipRouteEntry
内の
ip
MIB 変数に対する要求は,gated
サブエージェントへ送られます。
ipNetToMediaIfIndex
(1.3.6.1.2.1.4.22.1.1) などの他の
ip
変数への要求は,os_mibs
サブエージェントへ送られます。
gated
プロセスを終了した場合あるいは
ipRouteEntry
MIB サブツリーの登録を解除した場合,すべての
ipRouteEntry
MIB 変数を含む
ip
MIB サブツリーがipRouteIfIndex
に対する要求のもっとも優先度が高い領域となっているので,その後の
ipRouteIfIndex
への要求は
os_mibs
サブエージェントへ送られます。
マスタ・エージェントが SIGUSR1 シグナルを受け取ると,その MIB 登録が
/usr/tmp/snmpd_dump.log
ファイルへ送られます。
詳細については
snmpd
(8)
esnmp_register
ルーチンの構文は次のとおりです。
int esnmp_register(
SUBTREE *subtree,
int timeout,
int priority
);
引数の定義は次のとおりです。
処理する MIB サブツリーに対応する
SUBTREE
構造体へのポインタ。
SUBTREE
構造体は,MIB ドキュメントから直接得られた
mosy
および
snmpi
ユーティリティで生成されたコードで (xxx_tbl.c
および
xxx_tbl.h
,xxx は MIB サブツリー名) 外部的に宣言され初期化されます。
注意
subtree フィールドでポイントされているすべてのメモリは,プログラムの存続期間中,
libesnmp
によって参照されるため,永続的なストレージを持っていなければなりません。snmpi
ユーティリティによって発行されたデータ宣言を使用してください。
この MIB サブツリーでデータを要求した際にマスタ・エージェントが応答を待つ秒数。 0 〜 300 の値を指定します。 0 を指定した場合は,省略時のタイムアウト (3 秒) が使用されます。 省略時の値を使用することをお勧めします。
登録の優先順位。 番号の大きいエントリの方が優先順位が高くなります。 指定できる範囲は 1 〜 255 です。 OID (オブジェクトID) の範囲内で最も高い優先順位の MIB サブツリーを登録したサブエージェントが,その範囲の OID (オブジェクト識別子) に対するすべての要求を受け取ります。
同じ優先順位で登録されている MIB サブツリーは,重複しているとされ,登録はマスタ・エージェントによってリジェクトされます。
priority 引数は,異なる構成を処理する協力関係のある複数のサブエージェントのためのメカニズムです。
戻り値は次のとおりです。
esnmp_register
ルーチンが正常に終了しました。
esnmp_init
ルーチンが呼び出されていない,タイムアウト・パラメータが正しくない,あるいはその MIB サブツリーがすでに登録されています。
サブエージェントとマスタ・エージェントとの通信が途絶えています。
状態は要求の開始のみを示します。
マスタ・エージェントの応答で返される実際の状態は,その後の
esnmp_poll
ルーチンへの呼び出しで返されます。
次に示すのは
esnmp_register
ルーチンの例です。
#include <esnmp.h> #define RESPONSE_TIMEOUT 0 /* use the default time set in OPEN message */ #define REGISTRATION_PRIORITY 10 /* priority at which subtrees will register */ int status; extern SUBTREE ipRouteEntry_subtree; status = esnmp_register( &ipRouteEntry_subtree, RESPONSE_TIMEOUT, REGISTRATION_PRIORITY ); if (status != ESNMP_LIB_OK) { printf ("Could not queue the 'ipRouteEntry' \n"); printf ("subtree for registration\n"); }
esnmp_unregister
ルーチンは,マスタ・エージェントから MIB サブツリーの登録を解除します。
このルーチンは,この MIB サブツリーの変数に対する要求をそれ以上処理しないことを eSNMP サブエージェントに伝えるアプリケーション・コードによって呼び出されます。
esnmp_register
ルーチンを呼び出すことによって,必要に応じて MIB サブツリーを後で再登録することができます。
esnmp_unregister
ルーチンの構文は次のとおりです。
int esnmp_unregister(
SUBTREE *subtree
);
引数は次のとおりです。
登録を解除する MIB サブツリーのSUBTREE
構造体へのポインタ。
戻り値は次のとおりです。
ルーチンが正常に終了しました。
指定した MIB サブツリーが登録されていません。
MIB サブツリーの登録を解除する要求が送信できませんでした。 プロトコルを再起動する必要があります。
次は,esnmp_unregister
ルーチンの例です。
#include <esnmp.h> int status extern SUBTREE ipRouteEntry_subtree; status = esnmp_unregister( &ipRouteEntry_subtree ); switch (status) { case ESNMP_LIB_OK: printf ("The esnmp_unregister routine completed successfully.\n"); break; case ESNMP_LIB_BAD_REG: printf ("The MIB subtree was not registered.\n"); break; case ESNMP_LIB_LOST_CONNECTION: printf("%s%s%s\n", "The request to unregister the ", "MIB subtree could not be sent. ", "You should restart the protocol.\n"); break; }
esnmp_register2
ルーチンは,esnmp_register
ルーチンを拡張したものです。
esnmp_register2
ルーチンを呼び出す前に,初期化ルーチン (esnmp_init
) を呼び出す必要があります。
処理しようとする各 MIB サブツリーに対応するそれぞれのサブツリー構造体に対して,esnmp_register2
関数を呼び出す必要があります。
いつでも,esnmp_unregister2
を呼び出すと MIB サブツリーの登録が解除され,その後
esnmp_register2
を呼び出すと再登録されます。
esnmp_init
を呼び出して eSNMP プロトコルを再起動すると,すべての MIB サブツリーの登録がクリアされます。
MIB サブツリーはすべて再登録する必要があります。
MIB サブツリーは,ベース MIB 名と対応する OID によって識別されます。
この集合は,MIB サブツリーに含まれるすべての MIB 変数の親を表します。
たとえば,MIB-2
tcp
サブツリーの OID は
1.3.6.1.2.1.6
です。
この OID に従属する (同じ 7 つの識別子で始まる) すべての要素は,サブツリーのオブジェクト・テーブルに含まれています。
MIB サブツリーは,単一の MIB オブジェクト (リーフ・ノード) でも特定のインスタンスでもかまいません。
MIB サブツリーを登録することにより,サブエージェントは,その MIB サブツリーの領域内部にあるすべての MIB 変数 (または OID) に対する SNMP 要求を処理するということを示します。 したがって,サブエージェントは MIB 変数をまだ組み込んでいるいる MIB サブツリーの中で最も完全に (長く) 修飾されたものを登録します。
esnmp_register2
ルーチンを使用するサブエージェントは,ローカル・ノードとクラスタに対して,同じ MIB サブツリーを登録できます。
MIB サブツリーを両方に登録するには,esnmp_register2
ルーチンを 2 回呼び出す必要があります。
1 回は
options
パラメータで ESNMP_REG_OPT_CLUSTER ビットをセットし,もう 1 回は
options
パラメータで ESNMP_REG_OPT_CLUSTER ビットをクリアして呼び出します。
あるいは,MIB サブツリーをクラスタのみ,またはローカル・ノードのみに対して登録することもできます。
この場合は,options
パラメータで ESNMP_REG_OPT_CLUSTER ビットをそれぞれセット/クリアします。
また,サブエージェントは,以前に登録したサブツリーの OID 範囲に重複して,あるいは他のサブエージェントが登録したサブツリーの OID の範囲に重複して MIB サブツリーを登録できます。
たとえば,os_mibs
と
gated
という 2 つの Tru64 UNIX デーモンを考えてみます。
os_mibs
デーモンは
ip
MIB サブツリー (1.3.6.1.2.1.4) を登録し,gated
デーモンは
ipRouteEntry
MIB サブツリー (1.3.6.1.2.1.4.21.1) を登録します。
これらの登録はどちらも,options
パラメータで ESNMP_REG_OPT_CLUSTER ビットをセットして行われます。
ipRouteIfIndex
(1.3.6.1.2.1.4.21.1.2) などの
ipRouteEntry
内の
ip
MIB 変数に対する要求は,gated
サブエージェントへ送られます。
ipNetToMediaIfIndex
(1.3.6.1.2.1.4.22.1.1) などの他の
ip
変数に対する要求は,os_mibs
サブエージェントへ送られます。
gated
プロセスが終了した場合,またはipRouteEntry
MIB サブツリーへの登録を解除した場合,その後の
ipRouteIfIndex
への要求は,os_mibs
サブエージェントへ送られます。
これは,すべての
ipRouteEntry
MIB 変数を含む
ip
MIB サブツリーが,ipRouteIfIndex
に対する要求の最も優先順位が高い領域となっているためです。
esnmp_register2
ルーチンの構文は次のとおりです。
int esnmp_register2(
ESNMP_REG *reg
);
引数の定義は次のとおりです。
ESNMP_REG
構造体へのポインタ。
次のようなフィールドがあります。
処理する MIB サブツリーに対応する
SUBTREE
構造体へのポインタ。
SUBTREE
構造体は,MIB ドキュメントから直接得られた
mosy
および
snmpi
ユーティリティで生成されたコードで外部宣言され初期化されます (xxx_tbl.c
および
xxx_tbl.h
,xxx
はサブツリー名)。
注意
このフィールドによってポイントされているメモリはすべて,プログラムの存続期間中に
libesnmp
によって参照されるため,永続的なストレージを持っていなければなりません。snmpi
ユーティリティによって発行されたデータ宣言を使用してください。
登録の優先順位。 数値が最大のエントリは,優先順位が最も高くなっています。 範囲は 1 〜 255 です。 OID (オブジェクト識別子) の範囲内で優先順位が最も高い MIB サブツリーを登録したサブエージェントは,その OID の範囲内の要求をすべて受け取ります。
同じ優先順位で登録されているサブツリーは重複しているとされ,マスタ・エージェントにより登録はリジェクトされます。
priority フィールドは異なる構成を処理するために協力するサブエージェントのためのメカニズムです。
この MIB サブツリーでデータを要求した際に,マスタ・エージェントが応答を待つ秒数。 0 〜 300 までの値を指定します。 0 を指定した場合は,省略時のタイムアウト (3 秒) が使用されます。 省略時の値を使用することをお勧めします。
整数の値。 0 以外の場合,range_upper_bound フィールドとともに,MIB サブツリーの OID サブ識別子の 1 つの代わりに範囲を指定します。 range_subid フィールドは,range_upper_bound フィールドによって変更される OID サブ識別子を指定します。
整数の値。 0 以外の range_subid フィールドと組み合わせて,MIB サブツリーの OID サブ識別子の 1 つの代わりに範囲を指定します。 MIB サブツリーの OID サブ識別子の範囲に関して,range_upper_bound フィールドは上限,range_subid は下限になります。
整数の値。 ESNMP_REG_OPT_CLUSTER に設定されると,登録がクラスタ全体で有効であることを示し,0 に設定されると,登録がローカル・ノードに対して有効であることを示します。
次に示す整数の値のいずれかをとり,呼び出す側に対して,この MIB サブツリーの登録の非同期更新を行います。
esnmp_poll
ルーチンが終了した後,呼び出す側はこのパラメータを調べることができます。
登録は現在ローカルに保留されており,マスタ・エージェントとの接続を待っています。
登録はマスタ・エージェントに送られました。
登録はマスタ・エージェントから正常に肯定応答されました。
重複しているため,登録はマスタ・エージェントからリジェクトされました。
マスタ・エージェントはクラスタ登録をサポートしていません。
マスタ・エージェントは他の理由でリジェクトしました。
ヌルでない場合,この入力パラメータは,登録内の MIB サブツリーに対して部分的にまたは完全に限定されたインスタンスを指定します。
テーブル内の row を登録する際は,このパラメータを使用します。
テーブル内の row の登録についての詳細は,6.3.1.2 項
と
snmpi
(8)
戻り値は次のとおりです。
esnmp_register2
ルーチンが正常に終了しました。
esnmp_init
が呼び出されていないか,タイムアウト・パラメータが正しくないか,登録の余地がないか,MIB サブツリーがすでに登録のキューにいれられているかしています。
また,ログ・ファイルにもメッセージがあります。
サブエージェントとマスタ・エージェントとの通信が途絶えています。
状態は,要求の開始のみを示しています。
マスタ・エージェントの応答に返される実際の状態は,その後の
esnmp_poll
ルーチンへの呼び出しで
reg->state
フィールドに返されます。
次に示すのは
esnmp_register2
ルーチンの例です。
#include <esnmp.h> #define RESPONSE_TIMEOUT 0 /* use the default time set in esnmp_init message */ #define REGISTRATION_PRIORITY 10 /* priority at which the MIB subtree will register */ #define RANGE_SUBID 7 /* the identifier position in oid->elements just after mib-2 */ #define RANGE_UPPER_BOUND 8 /* the identifier for egp, under mib-2 */ int status; extern SUBTREE ip_subtree; static ESNMP_REG esnmp_reg_for_ip2egp; /* retain this structure for a subsequent call to esnmp_unregister2 */ /* * initialize the ESNMP_REG structure */ memset(&esnmp_reg_for_ip2egp, 0, sizeof(ESNMP_REG)); esnmp_reg_for_ip2egp.subtree = &ip_subtree; esnmp_reg_for_ip2egp.priority = REGISTRATION_PRIORITY; esnmp_reg_for_ip2egp.timeout = RESPONSE_TIMEOUT; esnmp_reg_for_ip2egp.range_subid = RANGE_SUBID; esnmp_reg_for_ip2egp.range_upper_bound = RANGE_UPPER_BOUND; status = esnmp_register2( &esnmp_reg_for_ip2egp ); if (status != ESNMP_LIB_OK) { printf("Could not queue the 'ipRouteEntry' \n"); printf("subtree for registration\n"); }
6.3.1.7 esnmp_unregister2 ルーチン
esnmp_unregister2
ルーチンは マスタ・エージェントから MIB サブツリーの登録を解除します。
このルーチンは,MIB サブツリーが
esnmp_register2
ルーチンを用いて登録されている場合にのみ使用してください。
このルーチンをアプリケーションから呼び出して,eSNMP サブエージェントに対して,この MIB サブツリーの変数への要求をそれ以上処理しないように通知することができます。
MIB サブツリーは,その後必要に応じて
esnmp_register2
ルーチンを呼び出して登録できます。
esnmp_unregister2
ルーチンの構文は次のとおりです。
int esnmp_unregister2(
ESNMP_REG *reg
);
引数は次のとおりです。
esnmp_register2
ルーチンが呼び出されたときに使用される,ESNMP_REG
構造体へのポインタ。
戻り値は次のとおりです。
ルーチンは正常に終了しました。
MIB サブツリーが登録されていません。
MIB サブツリーの登録を解除する要求が送信できませんでした。 プロトコルを再起動する必要があります。
次に示すのは
esnmp_unregister2
ルーチンの例です。
#include <esnmp.h> int status extern ESNMP_REG esnmp_reg_for_ip2egp; status = esnmp_unregister2( &esnmp_reg_for_ip2egp ); switch(status) { case ESNMP_LIB_OK: printf("The esnmp_unregister2 routine completed successfully.\n"); break; case ESNMP_LIB_BAD_REG: printf("The MIB subtree was not registered.\n"); break; case ESNMP_LIB_LOST_CONNECTION: printf("%s%s%s\n", "The request to unregister the ", "MIB subtree could not be sent. ", "You should restart the protocol.\n"); break; }
6.3.1.8 esnmp_capabilities ルーチン
esnmp_capabilities
ルーチンは,サブエージェントの機能をマスタ・エージェントの sysORTable に追加します。
sysORTable はエージェントのオブジェクト・リソースを含む概念的なテーブルであり,RFC 1907
で記述されています。
このルーチンは,esnmp_init
ルーチンを呼び出して eSNMP を初期化した後の任意の時点で呼び出されます。
esnmp_capabilities
ルーチンの構文は次のとおりです。
void esnmp_capabilities(
OID *agent_cap_id,
char *agent_cap_descr
);
引数は次のとおりです。
最も優先順位が高いエージェント機能識別子を表すオブジェクト識別子へのポインタ。 この値は,管理対象ノードの sysORTable で sysORID オブジェクトに対して使用されます。
agent_cap_id を記述するヌル終了文字列へのポインタ。 この値は,管理対象ノードの sysORTable で sysORDescr オブジェクトに対して使用されます。
6.3.1.9 esnmp_uncapabilities ルーチン
esnmp_uncapabilities
ルーチンは,サブエージェントの機能をマスタ・エージェントの sysORTable から削除します。
このルーチンは,サブエージェントがその機能を動的に変更する場合に呼び出されます。 サブエージェントに対する論理接続がクローズされると,マスタ・エージェントは sysORTable 内の関連エントリを削除します。
esnmp_uncapabilities
ルーチンの構文は次のとおりです。
void esnmp_uncapabilities(
OID *agent_cap_id
);
引数は次のとおりです。
sysORTable から削除されるエージェント機能文のオブジェクト識別子へのポインタ。
esnmp_poll
ルーチンは,マスタ・エージェントによって送信されているペンディング・メッセージを処理します。
このルーチンは,ユーザの
select()
コールが eSNMP ソケットにデータが用意されていることを示した後に呼び出されます (このソケットは
esnmp_init
ルーチンに対する呼び出しから返されます)。
そのソケットでメッセージがペンディングされていない場合は,esnmp_poll
ルーチンはメッセージを受け取るまでブロックします。
受けとったメッセージが問題を指摘している場合,ルーチンは
syslog
ファイルにエントリを作成し,エラー状態を返します。
受けとったメッセージが SNMP データに対する要求である場合,ルーチンはオブジェクト・テーブルを照会し,適切なメソッド・ルーチンを呼び出します。
esnmp_poll
ルーチンの構文は次のとおりです。
int esnmp_poll(
void
);
戻り値は次のとおりです。
esnmp_poll
ルーチンが正しく終了しました。
マスタ・エージェントによる以前の再登録が失敗しています。 ログ・ファイルを参照してください。
重複するサブエージェント ID がマスタ・エージェントによって既に受け取られています。
これは,esnmp_init
エラーです。
マスタ・エージェントは
esnmp_init
要求の開始に失敗しました。
後で再実行してください。
また,ログ・ファイルを参照してください。
CLOSE メッセージが受信されました。
eSNMP プロトコル・エラーが発生しました。 パケットは放棄されました。
マスタ・エージェントとの通信がロストしました。 再度接続してください。
6.3.1.11 esnmp_are_you_there ルーチン
esnmp_are_you_there
ルーチンは,ネットワーク・インタフェースが動作しているかどうかをすぐに報告することをマスタ・エージェントに要求します。
この呼び出しは応答を待つ間ブロックしません。
応答は,esnmp_poll
ルーチンを呼び出すことによって処理されます。
タイムアウト時間内に応答がない場合,アプリケーションはesnmp_init
ルーチンを呼び出すことによって eSNMP プロトコルを再起動します。
eSNMP ライブラリが管理するタイマはありません。
esnmp_are_you_there
ルーチンの構文は次のとおりです。
int esnmp_are_you_there(
void
);
戻り値は次のとおりです。
要求が送信されました。
マスタ・エージェントがダウンしているため要求を送信できません。
esnmp_trap
ルーチンは,マスタ・エージェントへトラップ・メッセージを送ります。
この関数はいつでも呼び出すことができます。
マスタ・エージェントが eSNMP プロトコルを実行していない場合,トラップはキュー登録され,通信が確立したときに送られます。
トラップ・メッセージが実際にマスタ・エージェントへ送られるのは,esnmp_init
呼び出しに対するマスタ・エージェントの応答が処理された後です。
esnmp_poll
ルーチンの後の呼び出し中のほとんどの場合に対して,この処理は API コール内で行われます。
esnmp_init
,esnmp_poll
,および
esnmp_trap
ルーチンを呼び出すのが,マスタ・エージェントへトラップを送る最も速い方法です。
マスタ・エージェントはトラップを SNMP トラップ・メッセージへフォーマットし,現在の構成のベースになっている管理ステーションへ送ります。
マスタ・エージェントの構成については,
snmpd
(8)snmpd.conf
(4)
マスタ・エージェントから返されるトラップに関する応答はありません。
esnmp_trap
ルーチンの構文は次のとおりです。
int esnmp_trap(
int generic_trap,
int specific_trap,
char *enterprise,
VARBIND *vb
);
引数は次のとおりです。
汎用トラップ・コード。 SNMPv2 トラップに対しては 0 を設定します。
特定トラップ・コード。 SNMPv2 トラップに対しては 0 を設定します。
ドット表記の エンタープライズ OID 文字列。
MIB 仕様を定義する際に NOTIFICATION-TYPE マクロによって定義されるオブジェクト識別子を設定します。
この値は,SNMPv2-Trap-PDU 内の
SnmpTrapOID.0
の値として受け渡されます。
データの
VARBIND
リスト (NULL ポインタはデータがないことを示します。
)
戻り値は次のとおりです。
ルーチンが正しく終了しました。
ルーチンは,マスタ・エージェントへトラップ・メッセージを送信できませんでした。
何らかの原因でメッセージが生成されませんでした。
esnmp_term
ルーチンは,マスタ・エージェントにクローズ・メッセージを送り,eSNMP プロトコルをシャット・ダウンします。
すべてのサブエージェントは,終了時にこのルーチンを呼び出して,マスタ・エージェントが MIB 登録をすぐに更新できるようにして,サブエージェントに代わって eSNMP によって使用されているシステム・リソースを解放できるようにする必要があります。
esnmp_term
ルーチンの構文は次のとおりです。
void esnmp_term(
void
);
戻り値は次のとおりです。
esnmp_term
ルーチンは,パケットを送信できない場合でも,常に
ESNMP_LIB_OK
を返します。
esnmp_sysuptime
ルーチンは,gettimeofday
によって取得した UNIX システム時間を
sysUpTime
と同じタイム・ベースに変換します。
このデータは,1/100 秒の単位で
TimeTicks
データ・タイプ (マスタ・エージェントが起動されてからの時間) として使用することができます。
このタイム・ベースは,esnmp_init
ルーチンに応答してマスタ・エージェントから取得されます。
このルーチンは UNIX タイムスタンプを SNMP
TimeTicks
に変換するための一般的なメカニズムを提供します。
この関数は,特定のUNIXに対する
sysUpTime
の適切な値を返します。
ヌルのタイムスタンプを渡すと
sysUpTime
の現在の値が返されます。
構文は次のとおりです。
unsigned int esnmp_sysuptime(
struct timeval *timestamp
);
引数は次のとおりです。
gettimeofday
システム・コールから取得した値を含んでいる
struct timeval
へのポインタです。
構造体は
include/sys/time.h
に定義されています。
NULL ポインタは現在の
sysUpTime
を返すことを意味します。
esnmp_sysuptime
ルーチンの例を次に示します。
#include <sys/time.h> #include <esnmp.h> struct timeval timestamp; gettimeofday(×tamp, NULL); o_integer(vb, object, esnmp_sysuptime(×tamp));
戻り値は次のとおりです。
0
エラー (gettimeofday
の失敗) を示します。
それ以外の場合は,timestamp
に,マスタ・エージェント・プロトコルが開始されてからの時間が 1/100 秒の単位で含まれます。
SNMP 要求には,多数の
VariableBindings
(コード化された MIB 変数) が含まれていることがあります。
サブエジェントで実行されている
libsnmp
コードは,それぞれの
VariableBinding
をオブジェクト・テーブル項目と照合します。
そのとき,オブジェクト・テーブルのメソッド・ルーチンが呼ばれます。
このため,メソッド・ルーチンは単一の MIB 変数をサービスするため呼び出され,単一の SNMP 要求の中で同じメソッド・ルーチンが複数回呼び出されることもあります。
メソッド・ルーチン呼び出しインタフェースには次の関数が含まれます。
*_get
*_set
メソッド・ルーチンについての詳細は,6.3.2.3 項を参照してください。
6.3.2.1 *_get ルーチン
*_get
ルーチンは,MIB グループ (たとえば MIB-2 における
system
) やテーブル・エントリ (たとえば MIB-2 における
ifEntry
) などの,指定した MIB 項目に対するメソッド・ルーチンです。
しかし,それはどうとでもできます。
詳細については,
snmpi
(8)
libesnmp
ルーチンは,登録されているサブツリーによって認識されるオブジェクト・テーブルの
Get
操作に対して指定されているルーチンを呼び出します。
この関数は,サブエージェント・オブジェクト・テーブルのいくつかの要素によってポイントされます。
要求がオブジェクトに届くと,そのメソッド・ルーチンが呼び出されます。
*_get
メソッド・ルーチンが
Get
SNMP 要求に対する応答の際に呼び出されます。
*_get
ルーチンの構文は次のとおりです。
int mib-group_get(
METHOD *method
);
引数は次のとおりです。
次のフィールドを含む
METHOD
へのポインタです。
ESNMP_ACT_GET,ESNMP_ACT_GETNEXT,あるいは ESNMP_ACT_GETBULK のいずれか。
この SNMP 要求に対してユニークな整数値。 単一の SNMP 要求をサービスしている間に呼び出されるメソッド・ルーチンは,同じ値 serial_num を受け取ります。 新しい SNMP 要求は,新しい値 serial_num によって示されます。
GetBulk
に対してのみ使用します。
この値は,反復している
VARBIND
の現在の反復値を示します。
この値は,1〜
max_repetitions
の間で増加します。
0 の値は,VARBIND
構造体を反復しないことを示します。
GetBulk
に使用します。
反復数の最大値です。
VARBIND
構造体を反復しない場合は 0 になります。
呼び出しの繰り返し数の最大値を知ることによって,その後の処理を最適化することができます。
OID およびデータ・フィールドを埋めなければならない
VARBIND
構造体に対するポインタ。
メソッド・ルーチンのエントリ時,method->varbind->name
フィールドは要求された OID です。
メソッド・ルーチンの終了時,要求されたデータが
method->varbind
フィールドに含まれ,返された
VARBIND
に対する実際のインスタンス OID を反映して
method->varbind->name
フィールドが変更されます。
libsnmp
ルーチン (o_integer
,o_string
,o_oid
,および
o_octet
) は一般にデータをロードするために使用されます。
libsnmp instance2oid
ルーチンは,method->varbind->name
フィールドで OID を更新するために使用されます。
MIB 変数が参照されているオブジェクト・テーブル・エントリへのポインタ。
method->object->object_index
フィールドは,(1 つのメソッド・ルーチンが多くのオブジェクトをサービスする際に便利な) オブジェクト・テーブル内でのこのオブジェクトのユニークなインデックスです。
method->object->oid
フィールドは,MIB においてこのオブジェクトに対して定義される OID です。
要求されたインスタンスは,この OID と
method->varbind->name
フィールドで発見された要求の OID とを比較することによって引き出されます。
この操作には
oid2instance
が便利です。
*_get
ルーチンに対する可能な戻り値は次のとおりです。
ルーチンが正常終了しました。
要求したオブジェクトが返されないか,あるいは存在していません。
オブジェクトの要求したインスタンスが返されないか,あるいは存在していません。
一般的な処理エラー。
*_set
メソッド・ルーチンは,MIB グループ (たとえば MIB-2 の
system
) あるいはテーブル・エントリ (たとえば MIB-2 の
ifEntry
) などの,指定された MIB 項目のためのものです。
しかし,どうとでもなります。
詳細については,
snmpi
(8)
libesnmp
ルーチンは,登録されているサブツリーによって認識されるオブジェクト・テーブルの
Set
操作に対して指定されているルーチンを呼び出します。
この関数は,サブエージェント・オブジェクト・テーブルのいくつかの要素によってポイントされます。
オブジェクトに対する要求が到着すると,そのメソッド・ルーチンが呼び出されます。
*_set
メソッド・ルーチンは
Set
SNMP 要求に応答して呼び出されます。
*_set
メソッド・ルーチンの構文は次のとおりです。
int mib-group_set(
METHOD *method
);
引数は次のとおりです。
次のフィールドを含む
METHOD
構造体へのポインタです。
ESNMP_ACT_SET,ESNMP_ACT_COMMIT,ESNMP_ACT_UNDO,あるいは ESNMP_ACT_CLEANUP のいずれか。
この SNMP 要求に対してユニークな整数値。 単一の SNMP 要求をサービスしている間に呼び出されるメソッド・ルーチンは,同じ値 serial_num を受け取ります。 新しい SNMP 要求は,新しい値 serial_num によって示されます。
MIB 変数の提供するデータおよび名前 (OID) を含む
VARBIND
構造体に対するポインタ。
インスタンス情報は OID から展開され,method->row->instance
フィールドに置かれます。
MIB 変数が参照されているオブジェクト・テーブル・エントリへのポインタ。
method->object->object_index
フィールドは,(1 つのメソッド・ルーチンが多くのオブジェクトをサービスする際に便利な) オブジェクト・テーブル内でのこのオブジェクトのユニークなインデックスです。
method->object->oid
フィールドは,MIB においてこのオブジェクトに対して定義される OID です。
libesnmp
によって設定される読み取り専用の整数ビットマスクです。
ESNMP_FIRST_IN_ROW ビットを設定すると,この呼び出しが row に設定される最初のオブジェクトであることを示します。
ESNMP_LAST_IN_ROW ビットを設定すると,この呼び出しが row に設定される最後のオブジェクトであることを示します。
ESNMP_LAST_IN_ROW ビットが設定されている
METHOD
構造体だけが,commit,undo,cleanup のフェーズのメソッド・ルーチンに渡されます。
esnmp.h
ヘッダ・ファイルで定義されている
ROW_CONTEXT
構造体へのポインタです。
同じグループを参照し同じインスタンス番号を持つメソッド・ルーチンに対するすべての
Set
呼び出しは,同じ row 構造体に存在します。
メソッド・ルーチンは,Set
呼び出し実行中に,commit および undo フェーズで使用する情報を row 構造体に蓄積することができます。
累積されたデータは,cleanup フェーズでメソッド・ルーチンを使用して解放することができます。
ROW_CONTEXT
構造体には次のファールドがあります。
概念的 row に対するインスタンス OID を含む配列のアドレスです。
libesnmp
ルーチンは,要求された変数binding oid
から
object oid
を引くことによってこの配列を作成します。
method->row->instance
フィールドのサイズです。
要求の処理に必要となるデータを参照するために,メソッド・ルーチンが使用するプライベートなポインタです。
要求の undo に必要となるデータを参照するために,メソッド・ルーチンがプライベートに使用するポインタです。
状態情報を保持するためにメソッド・ルーチンがプライベートに使用する整数です。
*_set
メソッド・ルーチンの可能な戻り値は次のとおりです。
ルーチンが正常終了しました。
要求したオブジェクトが設定できないか,あるいは実現されていません。
要求された値のデータ型が正しくありません。
要求した値の長さが正しくありません。
要求した値の表現が正しくありません。
要求した値が範囲外です。
要求したインスタンスは常に作成できません。
要求したインスタンスは現在作成できません。
要求した値に矛盾があります。
リソースの制約によって失敗しました。
一般的な処理エラーが発生しました。
commit フェーズが失敗しました。
undo フェーズが失敗しました。
各変数割り当ては解析され,そのオブジェクトはオブジェクト・テーブルに置かれます。
各
VARBIND
構造体に対して
METHOD
構造体が作成されます。
これらの
METHOD
構造体は,各フェーズの処理に便利な
ROW_CONTEXT
構造体をポイントします。
同じ概念的 row の オブジェクトは,すべて同じ
ROW_CONTEXT
構造体をポイントします。
決定は,次の項目をチェックすることによって行われます。
参照されるオブジェクトが同じ MIB グループに存在する。
VARBIND
構造体が同じインスタンス OID を持つ。
各
ROW_CONTEXT
構造体は,概念的 row に対するインスタンス情報でロードされます。
ROW_CONTEXT
構造体の
context
および
save
フィールドは NULL に設定され,
state
フィールドは ESNMP_SET_UNKNOWN に設定されます。
各オブジェクトに対するメソッド・ルーチンが呼び出され,アクション・コードに ESNMP_ACT_SET を持つ
METHOD
構造体が渡されます。
すべてのメソッド・ルーチンが正常終了を返す場合,各 row に対して単一のメソッド・ルーチン (最後に呼び出されたメソッド・ルーチン) が
method->action == ESNMP_ACT_COMMIT
で呼び出されます。
いずれかの row が失敗を報告すると,正常にコミットしたすべての row に対してフェーズを行わないよう伝えます。
この処理は,method->action == ESNMP_ACT_UNDO
で,各 row に対して単一のメソッド・ルーチン (commit フェーズで呼び出されたメソッド・ルーチン) を呼び出すことによって行われます。
最後に各 row が解放されます。
各 row に対する単一のメソッド・ルーチンは,method->action == ESNMP_ACT_CLEANUP
で呼び出されます。
この処理は,前の処理の結果にかかわらず,各 row ごとに行われます。
次のリストでアクション・コードを説明しています。
ESNMP_ACT_SET
各オブジェクトのメソッド・ルーチンは,Set
フェーズですべてのオブジェクトが処理されるかメソッド・ルーチンがエラー状態値を返すまでの間に呼び出されます (これは,各オブジェクトのメソッド・ルーチンが呼び出される唯一のフェーズです)。
同じ概念 row における変数割り当てのために,method->row
は共通の
ROW_CONTEXT
をポイントします。
呼び出されてるのが
ROW_CONTEXT
に対する最後のオブジェクトである場合,method->flags
ビットマスクは
ESNMP_LAST_IN_ROW
ビットを設定します。
これによって,概念的 row に対する各変数割り当てを見ることができるため,最後の整合性チェックが可能になります。
このフェーズにおけるメソッド・ルーチンのジョブは,SetRequest
が動作するかどうか判断し,そうでない場合は正しい SNMP エラー・コードを返し,commit フェーズで
Set
を実際に実行するのに必要なコンテキスト・データを用意することです。
method->row->context
はメソッド・ルーチンに対してプライベートで,libesnmp
はこれを使用しません。
典型的な使用方法は,概念的 row に対する
VARBIND
からのデータでロードされた,エミットされた
foo_type
構造体のアドレスを保管することです。
ESNMP_ACT_COMMIT
いくつかの変数割り当てが概念的 row に存在していたとしても,(SetRequest
の順序で) 最後の変数割り当てのみが処理されます。
そのため,共通の row をポイントするすべてのメソッド・ルーチンのうち最後のルーチンのみが呼び出されます。
このメソッド・ルーチンは,操作を実行するのに必要なすべてのデータおよびコンテキストが利用できなければなりません。
また,現在のデータのスナップショットあるいは
Set
を undo するために必要なデータを保管する必要があります。
method->row->save
フィールドは,この処理を実行するのに必要なデータへのポインタを保持します。
典型的な使用方法は,概念的 row の現在のデータでロードされた,xxx
構造体のアドレスを保管することです。
xxx
構造体は,snmpi
プログラムが自動的に生成したものです。
method->row->save
フィールドもメソッド・ルーチンに対してプライベートで,libesnmp
はこれを使用しません。
set 操作が成功した場合,ESNMP_MTHD_noError を返します。 失敗した場合はコミットを取消し,ESNMP_MTHD_commitFailed の値を返します。
commit フェーズでエラーが返された場合,libesnmp
は undo フェーズに入ります。
それ以外の場合は,cleanup フェーズに入ります。
注意
現在のサブエージェントで
Set
操作が成功しても,SetRequest
が他のサブエージェントに及び,他のサブエージェントが失敗するため,undo フェーズが発生する場合があります。
ESNMP_ACT_UNDO
正しくコミットした各概念的 row に対しては,method->action == ESNMP_ACT_UNDO
で同じメソッド・ルーチンが呼び出されます。
commit フェーズでまだ呼び出されていないROW_CONTEXT
構造体は,undo フェーズで呼び出されることはなく,cleanup フェーズで呼び出されます。
メソッド・ルーチンは,commit フェーズで実行されたときの条件をリストアすべきです (この処理は,method->row->save
フィールドによってポイントされるデータを使用して行われます)。
成功した場合は ESNMP_MTHD_noError を返し,失敗した場合は ESNMP_MTHD_undoFail を返します。
ESNMP_ACT_CLEANUP
何が発生したかに関係なく,この時点で各
ROW_CONTEXT
は cleanup フェーズに入ります。
commit フェーズで呼び出されたのと同じメソッド・ルーチンは,method->action == ESNMP_ACT_CLEANUP
で呼び出されます。
これは,SetRequest
の処理の終わりを示します。
メソッド・ルーチンは,method->row->context
および
method->row->save
フィールドで割り当てられ保管されていたダイナミック・メモリの解放など,必要な処理を行います。
cleanup フェーズの関数の戻り状態値は無視されます。
6.3.2.3 メソッド・ルーチンのアプリケーションでのプログラミング
subtree_tbl.h
ファイルで宣言されるているメソッド・ルーチンのコードを作成する必要があります。
各メソッド・ルーチンは,次のように
METHOD
構造体へのポインタを引数として持ちます。
int mib_group_get(
METHOD *method
int mib_group_set(
METHOD *method
);
Get
メソッド・ルーチンは,Get
,GetNext
および
GetBulk
を実行するのに使用されます。
Get
メソッド・ルーチンは次のタスクを行います。
必要な OID のインスタンス部分を抽出します。
この処理は
oid2instance
libesnmp
ルーチンで行います。
method->object->oid
フィールド (オブジェクトのベース OID) と
method->varbind->name
フィールド (要求された OID) とを比較することによって手作業でこの処理を行うこともできます。
インスタンスの妥当性を判断します。 インスタンス OID は,ヌル,あるいはいずれかの長さです (何が要求され,オブジェクトがどのように選択されたかに依存します)。 インスタンス OID のチェックによって,要求をすぐにリジェクトすることができます。
データを抽出します。 インスタンス OID と method->action フィールドをもとに,どのようなデータを返すべきかを判断します。
応答 OID をそのメソッドの
VARBIND
構造体にロードします。
返されている実際の MIB 変数インスタンスの OID を
method->varbind
フィールドに設定します。
この処理は,返したいインスタンス OID を整数の配列にロードし
instance2OID
libesnmp
ルーチンを呼び出すことによって行われます。
応答データをメソッドの
VARBIND
構造体にロードします。
次に示す,データ・タイプに対応する
libesnmp
ライブラリを使用して,返すデータを
method->varbind
フィールドにロードします。
o_integer
o_string
o_octet
o_oid
これらのルーチンは,指定したデータのコピーを作成します。
libesnmp
関数はコピーされたデータに関係するメモリの管理を行います。
メソッド・ルーチンはオリジナル・データのメモリ管理を行う必要があります。
ルーチンは,MIB 変数に対するオブジェクト・テーブルで定義されているタイプへの必要な変換を行い,変換したデータを method->varbind フィールドへコピーします。
データ値の表現については,値の表現の項を参照してください。
次のように正しい状態値を返します。
ESNMP_MTHD_noError -- ルーチンが正常に終了したか,あるいはエラーが検出されませんでした。
ESNMP_MTHD_noSuchInstance
-- 要求されたオブジェクトにはそのようなインスタンスがありません。
ESNMP_MTHD_noSuchObject
-- そのようなオブジェクトは存在しません。
ESNMP_MTHD_genErr -- エラーが発生し,ルーチンが正常に終了しませんでした。
各データ型に対する
VARBIND
構造体の値は次のように表現されます。
(OCT
および
OID
構造体については
esnmp.h
ファイルを参照してください。
)
ESNMP_TYPE_Integer32 (varbind->value.sl
フィールド)
32 ビットの符号付き整数。
整数値を
VARBIND
に挿入するには
o_integer
ルーチンを使用します。
この値の引数のプロトタイプは符号なしロングなので,場合によってはこの値を
signed int
にキャストする必要があります。
ESNMP_TYPE_DisplayString,ESNMP_TYPE_Opaque,ESNMP_TYPE_OctetString
(varbind->value.oct
フィールド)
オクテット文字の文字列。
この値は,長さおよび動的に割り当てられた文字配列に対するポインタを含む
OCT
構造体として,VARBIND
構造体に含まれます。
DisplayString
は,文字配列が ASCII テキストとして解釈される点で
OctetString
と異なります。
OctetString
にビットもしくはビット列がある場合は,OCT
構造体には次のものが含まれます。
その値を含むのに必要なバイト数に等しい長さ (すなわち,((qty-bits - 1)/8 + 1))。
bbbbb..bb
の形式の
bitstring
のビットを含むバッファへのポインタ。
ここで,bb
オクテットはビット列自身を表し,ビット 0 が先頭です。
最後のオクテットの使用していないビットは,0 に設定されます。
VARBIND
構造体 (バッファおよび長さ) に値を挿入するには
o_string
ルーチンを使用します。
新しいスペースが割り当てられ,バッファがその新しいスペースへコピーされます。
値を
VARBIND
構造体 (OCT
構造体へのポインタ)に挿入するには
o_octet
ルーチンを使用します。
新しいスペースが割り当てられ,OCT
構造体によってポイントされるバッファがコピーされます。
ESNMP_TYPE_ObjectId
(varbind->value.oid
および
varbind->name
フィールド)
オブジェクト識別子。
要素の数と,動的に割り当てられた符号なし整数の配列へのポインタを含む
OID
構造体として,VARBIND
構造体に含まれます。
varbind->name
フィールドは,オブジェクト識別子と MIB 変数を識別するインスタンス情報を保持するのに使用されます。
要求の OID からインスタンス要素を取り出すには
OID2Instance
関数を使用します。
応答を作成する際に
VARBIND
構造体の
name
フィールドを設定するために,インスタンス要素と MIB 変数のベース OID を組み合わせるには,instance2oid
関数を使用します。
データとして返される OID 値が
OID
構造体へのポインタとなっている場合に,オブジェクト識別子を
VARBIND
構造体に挿入するには,o_oid
関数を使用します。
データとして返される OID 値が,たとえば
1.3.6.1.2.1.3.1.1.2.0
のようにドット・フォーマットの OID を含む ASCII 文字へのポインタとなっている場合,オブジェクトID を
VARBIND
構造体に挿入するには
o_string
関数を使用します。
ESNMP_TYPE_NULL
NULL あるいは空のタイプ。
この値は,値がないことを示すために使用されます。
長さは 0 で,VARBIND
構造体における共用体値は 0 です。
Get
,GetNext
,および
GetBulk
での
VARBIND
は,このデータ・タイプを持ちます。
メソッド・ルーチンは,このような値は返しません。
Set
要求は,VARBIND
構造体でこのような値は持ちません。
ESNMP_TYPE_IpAddress
(varbind->value.oct
フィールド)
IP アドレス。
この値は,長さ 4 およびネットワーク・バイト順で 4 バイトの IP アドレスを含む動的に割り当てられるバッファへのポインタを持つ
OCT
構造体として,VARBIND
構造体に含まれます。
値がネットワーク順の符号なし整数の場合に IP アドレスを
VARBIND
構造体に挿入するには,o_integer
関数を使用します。
値が (ネットワーク・バイト順の) バイト配列の場合に IP アドレスを
VARBIND
構造体に挿入するには,o_string
関数を使用します。
長さは 4 を使用します。
ESNMP_TYPE_UInteger32 ESNMP_TYPE_Counter32 ESNMP_TYPE_Gauge32
(varbind->value.ul
フィールド)
32 ビット・カウンタおよび 32 ビット・ゲージ・データ・タイプが,unsigned int
として
VARBIND
構造体に保管されます。
VARBIND
構造体に符号なしの値を挿入するには,o_integer
関数を使用します。
ESNMP_TYPE_TimeTicks
(varbind->value.ul
フィールド)
32 ビット・タイムチケット・タイプの値が,unsigned int
として
VARBIND
構造体に保管されます。
符号なしの値を
VARBIND
構造体に挿入するには,o_integer
関数を使用してください。
ESNMP_TYPE_Counter64
(varbind->value.ul64
)
64 ビット・カウンタは,64 ビット値を使用する Alpha マシンで,unsigned long
として
VARBIND
構造体に保管されます。
符号なしロング値 (64 ビット) を
VARBIND
構造体に挿入するには,o_integer
関数を使用してください。
以降の節では,libsnmp
サポート・ルーチンについて説明します。
libsnmp
サポート・ルーチンには次のルーチンがあります。
o_integer
o_octet
o_oid
o_string
str2oid
sprintoid
instance2oid
oid2instance
inst2ip
cmp_oid
cmp_oid_prefix
clone_oid
free_oid
clone_buf
mem2oct
cmp_oct
clone_oct
free_oct
free_varbind_data
set_debug_level
is_debug_level
ESNMP_LOG
o_integer
ルーチンは,整数値を適切なデータ型で
VARBIND
構造体にロードします。
構文は次のとおりです。
int o_integer(
VARBIND *vb,
OBJECT *obj,
unsigned long value
);
引数は次のとおりです。
データを受け取る
VARBIND
構造体へのポインタです。
この関数はVARBIND
構造体は割り当てません。
VARBIND
構造体において
OID
と関連する MIB 変数に対する
OBJECT
構造体へのポインタです。
VARBIND
構造体に挿入される値です。
オブジェクト構造体で定義されているように,実数型は次のいずれかでなければなりません。 これ以外の場合は,エラーが返されます。
実数型が
IpAddress
の場合,ネットワーク・バイト順で 4 バイト整数が仮定されます。
IMPLICIT OCTET STRING (4)
o_integer
ルーチンの例を次に示します。
#include <esnmp.h> #include "ip_tbl.h" <-- for ipNetToMediaEntry_type definition VARBIND *vb = method->varbind; OBJECT *object = method->object; ipNetToMediaEntry_type *data; : : assume buffer and structure member assignments occur here : switch(arg) { case I_atIfIndex: return o_integer(vb, object, data->ipNetToMediaIfIndex);
戻り値は次のとおりです。
ルーチンが正常に終了しました。
エラーが発生しました。
o_octet
ルーチンはオクテット値を適切なデータ型で
VARBIND
構造体へロードします。
構文は次のとおりです。
int o_octet(
VARBIND *vb,
OBJECT *obj,
OCT *oct
);
引数は次のとおりです。
データを受け取る
VARBIND
構造体へのポインタです。
この関数は
VARBIND
構造体を割り当てません。
注意
vb フィールドのもとの値が NULL でない場合,このルーチンはそれを解放しようとします。 このため,自身の vb 構造体を割り当てるために
malloc
コマンドを使用する場合は,使用する前にゼロ詰めします。
VARBIND
構造体の
OID
に関係する MIB 変数に対する
OBJECT
構造体へのポインタです。
VARBIND
構造体に挿入される値です。
オブジェクト構造体で定義されているように,実数型は次のいずれかでなければなりません。 これ以外の場合は,エラーが返されます。
o_octet
ルーチンの例を次に示します。
#include <esnmp.h> #include "ip_tbl.h" <-- for ipNetToMediaEntry_type definition VARBIND *vb = method->varbind; OBJECT *object = method->object; ipNetToMediaEntry_type *data; : : assume buffer and structure member assignments occur here : switch(arg) { case I_atPhysAddress: return o_octet(vb, object, &data->ipNetToMediaPhysAddress);
戻り値は次のとおりです。
ルーチンが正常に終了しました。
エラー状態が発生しました。
o_oid
ルーチンは,OID 値を適切なデータ型で
VARBIND
構造体にロードします。
構文は次のとおりです。
int o_oid(
VARBIND *vb,
OBJECT *obj,
OID *oid
);
引数は次のとおりです。
データを受け取る
VARBIND
構造体へのポインタです。
この関数は
VARBIND
構造体の割り当ては行いません。
注意
vb フィールドのもとの値が NULL でない場合,このルーチンはそれを解放しようとします。 このため,自身の vb 構造体を割り当てるために
malloc
コマンドを使用する場合は,使用する前にゼロ詰めします。
VARBIND
構造体の OID と関係する MIB 変数に対する
OBJECT
構造体へのポインタです。
VARBIND
構造体にデータとして挿入される値です。
OID の長さと値については,6.2.1 項を参照してください。
オブジェクト構造体で定義されているように,実数型は次のいずれかでなければなりません。 これ以外の場合は,エラーが返されます。
o_oid
ルーチンの例を次に示します。
#include <esnmp.h> #include "ip_tbl.h" <-- for ipNetToMediaEntry_type definition VARBIND *vb = method->varbind; OBJECT *object = method->object; ipNetToMediaEntry_type *data; : : assume buffer and structure member assignments occur here : switch(arg) { case I_atObjectID: return o_oid(vb, object, &data->ipNetToMediaObjectID);
戻り値は次のとおりです。
ルーチンが正常に完了しました。
エラー状態が発生しました。
o_string
ルーチンは,文字列値を適切なデータ型で
VARBIND
構造体へロードします。
構文は次のとおりです。
int o_string(
VARBIND *vb,
OBJECT *obj,
unsigned char *ptr,
int len
);
引数は次のとおりです。
データを受け取る
VARBIND
構造体へのポインタです。
この関数は
VARBIND
構造体を割り当てません。
注意
vb フィールドのもとの値が
NULL
でない場合,このルーチンはそれを解放しようとします。 このため,自身の vb 構造体を割り当てるためにmalloc
コマンドを使用する場合は,使用する前にゼロ詰めします。
VARBIND
構造体の
oid
と関係する MIB 変数に対する
OBJECT
構造体へのポインタです。
VARBIND
構造体へ挿入するデータを含んでいるバッファへのポインタです。
ptr フィールドがポイントするバッファ内のデータの長さです。
オブジェクト構造体で定義されているように,実数型は次のいずれかでなければなりません。 これ以外の場合は,エラーが返されます。
o_string
ルーチンの例を次に示します。
#include <esnmp.h> #include "ip_tbl.h" <-- for ipNetToMediaEntry_type definition VARBIND *vb = method->varbind; OBJECT *object = method->object; ipNetToMediaEntry_type *data; : : assume buffer and structure member assignments occur here : switch(arg) { case I_atPhysAddress: return o_string(vb, object, data->ipNetToMediaPhysAddress.ptr, data->ipNetToMediaPhysAddress.len);
戻り値は次のとおりです。
ルーチンが正常に終了しました。
エラー状態が発生しました。
str2oid
ルーチンは,ヌルで終了する OID 文字列 (ドット表記) を
OID
構造体へ変換します。
このルーチンは要素バッファを動的に割り当て,そのポインタを
OID
構造体に挿入します。
このバッファは呼び出し元の責任で解放されます。
OID は最大 128 の要素を持つことができます。
空文字列もしくは空き文字列は,0 の要素をひとつ持つ
OID
構造体を返します。
str2oid
ルーチンは,OID
構造体を割り当てません。
構文は次のとおりです。
OID * str2oid(
OID *oid,
char *s
);
str2oid
ルーチンの例を次に示します。
#include <esnmp.h> OID abc; if (str2oid(&abc, "1.2.5.4.3.6") == NULL) DPRINTF((WARNING,"It did not work...\n"));
戻り値は次のとおりです。
エラーが発生しました。
そうでない場合は,OID
へのポインタ (最初の引数) が返されます。
sprintoid
ルーチンは
OID
をヌルで終わるドット表記の文字列に変換します。
OID
構造体は要素を 128 まで持つことができます。
フル・サイズの
OID
構造体は大きなバッファを必要とします。
構文は次のとおりです。
char * sprintoid(
char *buffer,
OID *oid
);
sprintoid
ルーチンの例を次に示します。
#include <esnmp.h> #define SOMETHING_BIG 1024 OID abc; char buffer[SOMETHING_BIG]; : : assume abc gets initialized with some value : printf("dots=%s\n", sprintoid(buffer, &abc));
戻り値は最初の引数をポイントします。
6.3.3.7 instance2oid ルーチン
instance2oid
ルーチンは,オブジェクトのベース OID のコピーを作成しインスタンス配列のコピーを追加して,値に対する完全な OID を作成します。
instance
は整数の配列で,len
は要素数です。
インスタンス配列は
oid2instance
によって作成されるか,あるいは
get_next
探索の結果としてキー値から作成されます。
このルーチンは要素バッファを動的に割り当て,呼び出しで渡される
OID
構造体にそのポインタを挿入します。
このバッファの解放は呼び出し元のプログラムもしくはモジュールの責任で行われます。
このルーチンを使うには,新しい
OID
値を受け取る
OID
構造体をポイントして,このルーチンを呼び出してください。
OID
構造体の以前の値は
free_oid
を最初に呼び出すときに解放され,新しい値が動的に割り当てられ挿入されます。
新しい
OID
構造体の初期値はすべて 0 です。
instance2oid
ルーチンは
OID
構造体を割り当てるのではなく,要素を含む配列のみを割り当てることに注意してください。
構文は次のとおりです。
OID * instance2oid(
OID *new,
OBJECT *obj,
unsigned int *instance,
int len
);
引数は次のとおりです。
新しい OID 値を受け取る
OID
構造体のポインタです。
入手されている MIB 変数に対するオプジェクト・テーブル・エントリのポインタです。 新しい OID の最初の部分は,MIB オブジェクト・テーブル・エントリから得られた OID です。
instance 値の配列のポインタです。 これらの値は,MIB オブジェクト・テーブル・エントリから得られたベース OID に追加され,新しい OID を構成します。
instance 配列の要素数です。
instance2oid
ルーチンの例を次に示します。
#include <esnmp.h> VARBIND *vb; <-- filled in OBJECT *object; <-- filled in unsigned int instance[6]; -- Construct the outgoing OID in a GETNEXT -- -- Instance is N.1.A.A.A.A where A's are IP address -- instance[0] = data->ipNetToMediaIfIndex; instance[1] = 1; for (i = 0; i < 4; i++) { instance[i+2]=((unsigned char *)(&data->ipNetToMediaNetAddress))[i]; } instance2oid(&vb->name, object, instance, 6);
戻り値は次のとおりです。
エラーが発生しました。
それ以外の場合は,OID
構造体のポインタ (最初の引数) が返されます。
oid2instance
ルーチンは,OID
構造体からインスタンス値を取り出し,それらを指定した整数配列にコピーします。
その後,配列内の要素数を返します。
インスタンスは,MIB 変数を識別する要素以外の OID の要素です。
それらは,MIB 値の特定のインスタンスを識別するためのインデックスとして使用されます。
OID
構造体が予想より多くの要素を含んでいる場合は (max_len
パラメータで指定した値より大きい場合),この関数は
max_len
で指定した要素数だけをコピーし,コピーした要素の総数を返します。
構文は次のとおりです。
int oid2instance(
OID *oid,
OBJECT *obj,
unsigned int *instance,
int max_len
);
引数は次のとおりです。
インスタンスあるいはインスタンスの一部が含まれている
OID
構造体へのポインタ。
MIB 変数に対するオブジェクト・テーブル・エントリへのポインタ。
インデックスが置かれる符号なし整数配列へのポインタ。
インスタンス配列で使用できる要素の数。
#include <esnmp.h> OID *incoming = &method->varbind->name; OBJECT *object = method->object; int instLength; unsigned int instance[6]; -- in a GET operation -- -- Expected Instance is N.1.A.A.A.A where A's are IP address -- instLength = oid2instance(incoming, object, instance, 6); if (instLength != 6) return ESNMP_MTHD_noSuchInstance;
N
は
instance[0]
,IP アドレスは
instance[2]
,instance[3]
,instance[4]
および
instance[5]
になります。
戻り値は次のとおりです。
<0 -- エラーが生じました。
この
oid
を見ることによってオブジェクトが取得された場合,これは返されません。
0 -- インスタンス要素がありません。
>0 -- インデックスの要素数です (これは max_len パラメータの値より大きい場合もあります)。
inst2ip
ルーチンは,OID インスタンスから得られた IP アドレスを返します。
Get
および
Set
操作のインスタンスの評価には,EXACT モードを使用します。
GetNext
および
GetBulk
操作には,NEXT モードを使用します。
NEXT モードを使用する場合,このルーチンのロジックは,一致するデータあるいはそれより大きいデータでデータ探索を実行すると想定します。
構文は次のとおりです。
int inst2ip(
unsigned int *inst,
int length,
unsigned int *ipAddr,
int exact,
int carry
);
引数は次のとおりです。
IP アドレスへ変換するために
oid2instance
ルーチンによって返されるインスタンス番号を含む
unsigned int
の配列へのポインタ。
各要素は 0 〜 255 の範囲にあります。
EXACT モードを使用すると,要素が範囲外の場合 1 を返します。
NEXT モードを使用すると,255 より大きな値は要素がオーバフローする原因となります。
0 にセットされ,次に重要な要素が増分されると,辞書的に次に来る
ipAddress
と同等な値を返します。
インスタンス配列の要素数です。
4 つ目以降のインスタンスは無視されます。
長さが 4 より小さい場合,足りない値には 0 が使用されます。
長さが負の場合,ipAddr
の値は 0 です。
Get
など正確な照合のためには,正確に 4 つの要素でなければなりません。
IP アドレス値を返す場所へのポインタです。 ネットワーク・バイト順で最も顕著な要素が最初にきます。
TRUE あるいは FALSE のどちらかです。
TRUE の場合 EXACT を使用します。
要素が 255 より大きい場合,あるいは正確に 4 つの要素がない場合は,1 を返します。
引数
carry
は無視されます。
FALSE の場合 NEXT を使用します。
carry
が設定されていて長さが 4 以上ある場合は,辞書的に次にくる IP アドレスが返されます。
要素数が 4 より小さい場合,足りない値には 0 が使用されます。
いずれかの要素が 255 より大きい場合,0 が使用され次の要素が増加します。
NEXT で IP アドレスを追加するキャリィです。 次の IP アドレスを調べる場合は 1 を渡します。 それ以外は 0 を渡します。 4 より小さい長さはキャリィをキャンセルします。
次に示すのは,inst2ip
ルーチンの例です。
次の例では,EXACT
で,インスタンスを
Get
のための IP アドレスに変換します。
#include <esnmp.h> OID *incoming = &method->varbind->name; OBJECT *object = method->object; int instLength; unsigned int instance[6]; unsigned int ip_addr; int iface; -- The instance is N.1.A.A.A.A where A.A.A.A is the IP address-- instLength = oid2instance(incoming, object, instance, 6); if (instLength == 6 && !inst2ip(&instance[2], 4, &ip_addr, TRUE,0)) { iface = (int) instance[0]; } else return ESNMP_MTHD_noSuchInstance;
次の例は,キーが 1 つしかないか,または
ipAddr
値がキーの一番重要でない部分の場合の
GetNext
オペレーションを示しています。
これは NEXT であるため,carry
値に 1 が渡されます。
#include <esnmp.h> OID *incoming = &method->varbind->name; OBJECT *object = method->object; int instLength; unsigned int instance[6]; unsigned int ip_addr; int iface; -- The instance is N.1.A.A.A.A where A.A.A.A is the IP address-- instLength = oid2instance(incoming, object, instance, 6); iface = (instLength < 1) ? 0 :(int) instance[0]; iface += inst2ip(&instance[2], instLength - 2, &ip_addr, FALSE, 1);
次の例では,検索キーに複数の部分があり,GetNext
オペレーションを行っている場合は,検索キーについて次にありそうな値を見つけて,カスケード式に「greater-than」または「equal-to」検索をします。
OID のインスタンス部分で
N.A.A.A.A.B.B.B.B
として表現される 1 つの数と 2 つの
ipAddr
値からなる検索キーがある場合は (N
は 1 つの値を持つ整数,A.A.A.A
は 1 つの IP アドレス,B.B.B.B
は 2 番目の IP アドレスとし,すべて指定された場合の長さが 9 になる),キーの一番重要でない部分 (B.B.B.B
の部分) を変更することによって検索を開始します。
inst2ip
ルーチンを呼び出して,キャリィに 1 を渡し,長さに (length-5) を渡すことによってこれを行います。
B.B.B.B 部分の変換でキャリィが生成された場合 (1 が返される) は,それをキーの次に重要な部分に渡します。
したがって,inst2ip
ルーチンを呼び出し,B.B.B.B
部分の変換から返されたキャリィおよび長さに (length-1) を渡すことにより,A.A.A.A
部分を変換します。
最も重要な要素である
N
は数です。
したがって,A.A.A.A
変換から返されたキャリィをその数に加算します。
それもオーバフローした場合,それは有効な検索キーではありません。
#include <esnmp.h> OID *incoming = &method->varbind->name; OBJECT *object = method->object; int instLength; unsigned int instance[9]; unsigned int ip_addrA; unsigned int ip_addrB; int iface; int carry; -- The instance is N.A.A.A.A.B.B.B.B -- instLength = oid2instance(incoming, object, instance, 9); iface = (instLength < 1) ? 0 :(int) instance[0]; carry = inst2ip(&instance[5],instLength - 5,&ip_addrB,FALSE,1); carry = inst2ip(&instance[1],instLength - 1,&ip_addrA,FALSE,carry); iface += carry; if (iface > carry) { -- a carry caused an overflow in the most significant element return ESNMP_MTHD_noSuchInstance; }
戻り値は次のとおりです。
carry が 0 の場合,ルーチンは正常に完了しています。
EXACT の場合あるいは NEXT に対するキャリィがある場合は,carry が 1 だと,エラーを意味します。 キャリィがある場合,返される ipAddr は 0 です。
cmp_oid
ルーチンは 2 つの
OID
構造体を比較します。
このルーチンは,要素 0 から各要素ごとに比較を行います。
他の要素がすべて等しければ,最も小さな要素の
OID
構造体がより小さいと考えられます。
構文は次のとおりです。
int cmp_oid(
OID *q,
OID *p
);
戻り値は次のとおりです。
+1 --
oid
q
が
oid
p
より大きい。
0 --
oid
q
と
oid
p
が等しい。
-1 --
oid
q
が
oid
p
より小さい。
cmp_oid_prefix
ルーチンは,プレフィックスに対して
OID
構造体を比較します。
プレフィックスは,おそらくオブジェクト・テーブル内のオブジェクトの OID です。
プレフィックスを越える要素はインスタンス情報です。
このルーチンは,要素 0 から各要素ごとに比較を行います。
プレフィックス OID のすべての要素が
OID
q
構造体の対応する要素と正確に一致する場合は,OID
q
構造体に別の要素が含まれていても等しいと考えられます。
最初の一致しない要素が大きければ,OID
q
構造体は
OID
プレフィックスより大きいと考えられます。
最初の一致しない要素が小さければ,OID
q
はプレフィックスより小さいと考えられます。
構文は次のとおりです。
int cmp_oid_prefix(
OID *q,
OID *prefix
);
cmp_oid_prefix
ルーチンの例を次に示します。
#include <esnmp.h> OID *q; OBJECT *object; if (cmp_oid_prefix(q, &object->oid) == 0) printf("matches prefix\n");
戻り値は次のとおりです。
-1 --
oid
がプレフィックスより小さい。
0 --
oid
がプレフィックスと等しい。
+1 --
oid
がプレフィックスより大きい。
clone_oid
ルーチンは
OID
構造体のコピーを作成します。
このルーチンは要素のバッファを動的に割り当て,そのポインタを渡される
OID
構造体に挿入します。
このルーチンを使うには,コピーされる古い
OID
構造体へのポインタとコピーされた OID 値を受け取る新しい
OID
構造体へのポインタを渡します。
このバッファの解放は呼び出し元のプログラムもしくはモジュールの責任で行われます。
新しい OID 構造体によってポイントされる以前の要素のバッファは解放され,動的に割り当てられる新しいバッファへのポインタが挿入されます。
解放できる要素バッファを含んでいない場合は,OID
構造体を 0 で初期化します。
このルーチンは
OID
構造体を割り当てません。
古い
OID
構造体が NULL であるか,要素バッファへの NULL ポインタを含んでいる場合は,{0.0} の新しい
OID
が生成されます。
構文は次のとおりです。
OID *clone_oid(
OID *new,
OID *oid
);
引数は次のとおりです。
コピーを受け取る
OID
構造体へのポインタです。
データを入手する
OID
構造体のポインタです。
clone_oid
ルーチンの例を次に示します。
#include <esnmp.h> OID oid1; OID oid2; : : assume oid1 gets assigned a value : memset(&oid2, 0, sizeof(OID)); if (clone_oid(&oid2, &oid1) == NULL) ESNMP_LOG((WARNING, "It did not work\n"));
戻り値は次のとおりです。
エラーが生じました。 そうでない場合は新しい OID へのポインタ (最初の引数) が返されます。
free_oid
ルーチンは,OID
構造体の要素バッファを解放します。
oid->elements
フィールドによってポイントされるバッファを解放する場合,そのフィールドと
oid->nelem
フィールドをゼロにします。
このルーチンは
OID
構造体自身の割り当て解除は行いません。
要素バッファの割り当て解除のみを行います。
構文は次のとおりです。
void free_oid(
OID *oid
);
free_oid
ルーチンの例を次に示します。
#include <esnmp.h> OID oid; : : assume oid was assigned a value (perhaps with clone_oid() : and we are now finished with it. : free_oid(&oid);
clone_buf
ルーチンは,動的に割り当てられた領域のバッファのコピーを作成します。
1 つの特別なバイトが最後に割り当てられ,\0
が埋め込まれます。
len
パラメータが 0 より小さい場合は,複製バッファ長は 0 に設定されます。
ルーチンは,malloc
エラーがない限り常にバッファ・ポインタを返します。
割り当てたバッファの解放は呼び出し元の責任で行われます。
構文は次のとおりです。
char *clone_buf(
char *str,
int len
);
引数は次のとおりです。
コピーを作成したバッファへのポインタ。
コピーするバイト数。
clone_buf
ルーチンの例を次に示します。
#include <esnmp.h> char *str = "something nice"; char *copy; copy = clone_buf(str, strlen(str));
戻り値は次のとおりです。
malloc
エラーが生じました。
それ以外の場合は,オリジナル・バッファのコピーを含む割り当てバッファへのポインタが返されます。
mem2oct
ルーチンは文字列 (バッファおよび長さ) を
OCT
構造体に変換します。
このルーチンは新しいバッファを動的に割り当て,指定されたデータをそこにコピーし,OID
構造体を新しいバッファのアドレスと長さで更新します。
このバッファの解放は呼び出し元の責任で行われます。
このルーチンは
OCT
構造体を割り当てません。
以前に割り当てた
OCT
構造体でポイントしているデータの解放は行いません。
構文は次のとおりです。
OCT * mem2oct(
OCT *new,
char *buffer,
int len
);
mem2oct
ルーチンの例を次に示します。
#include <esnmp.h> char buffer; int len; OCT abc; : : buffer and len are initialized to something : memset(&abc, 0, sizeof(OCT)); if (mem2oct(&abc, buffer, len) == NULL) ESNMP_LOG((WARNING,"It did not work...\n"));
戻り値は次のとおりです。
エラーが生じました。
それ以外の場合は,OCT
構造体へのポインタ (最初の引数) が返されます。
cmp_oct
は 2 つのオクテット文字列を比較します。
2 つのオクテット文字列は,バイトごとに最も短いオクテット文字列の長さを比較されます。
すべてのバイトが等しい場合は,長さが比較されます。
ヌル・ポインタのオクテットは,長さ0 のオクテットと同じであると考えられます。
構文は次のとおりです。
int cmp_oct(
OCT *oct1,
OCT *oct2
);
cmp_oct
ルーチンの例を次に示します。
#include <esnmp.h> OCT abc, efg; : : abc and efg are initialized to something : if (cmp_oct(&abc, &efg) > 0) ESNMP_LOG((WARNING,"octet abc is larger than efg...\n"));
戻り値は次のとおりです。
-1 -- 最初のパラメータでポイントされる文字列は 2 つ目よりも小さい。
0 -- 最初のパラメータでポイントされる文字列は 2 つ目と等しい。
+1 -- 最初のパラメータでポイントされる文字列は 2 つ目より大きい。
clone_oct
ルーチンは,OCT
構造体のコピーを作成します。
呼び出し元は,コピーされる古い
OCT
構造体のへのポインタとコピーされた
OCT
構造体の値を受け取る新しい
OCT
構造体へのポインタを渡します。
このルーチンはバッファを動的に割り当て,バッファのアドレスと長さで新しい
OCT
構造体を更新します。
この割り当てられたバッファの解放は呼び出し元の責任で行われます。
新しい OID 構造体によってポイントされる以前のバッファは解放され,動的に割り当てられる新しいバッファへのポインタが挿入されます。
解放できる要素バッファを含んでいない場合は,新しい
OCT
構造体を 0 で初期化します。
このルーチンは
OCT
構造体を割り当てません。
OCT
構造体によってポイントされる要素バッファのみを割り当てます。
構文は次のとおりです。
OCT *clone_oct(
OCT *new,
OCT *old
);
引数は次のとおりです。
コピーを受け取る
OCT
構造体へのポインタです。
データを入手する
OCT
構造体のポインタです。
clone_oct
ルーチンの例を次に示します。
#include <esnmp.h> OCT octet1; OCT octet2; : : assume octet1 gets assigned a value : memset(&octet2, 0, sizeof(OCT)); if (clone_oct(&octet2, &octet1) == NULL) ESNMP_LOG((WARNING, "It did not work\n"));
戻り値は次のとおりです。
エラーが生じました。
それ以外の場合は,OCT
構造体へのポインタ (最初の引数) が返されます。
free_oct
ルーチンは
OCT
構造体のバッファを解放します。
OCT
構造体がポイントする動的に割り当てられたバッファを解放し,OCT
構造体のポインタと長さフィールドを 0 にします。
OCT
構造体がすでに NULL の場合は何もしません。
OCT
構造体に接続されたバッファがすでに NULL の場合は,OCT
構造体の
length
フィールドを 0 にします。
このルーチンは
OCT
構造体の割り当て解除は行わず,ポイントするバッファの割り当て解除のみを行います。
構文は次のとおりです。
void free_oct(
OCT *oct
);
free_oct
ルーチンの例を次に示します。
#include <esnmp.h> OCT octet; : : assume octet was assigned a value (perhaps with clone_oct() : and we are now finished with it. : free_oct(&octet);
6.3.3.19 free_varbind_data ルーチン
free_varbind_data
ルーチンは,VARBIND
構造体に動的に割り当てられたフィールドを解放します。
このルーチンは,free_oid
(vb->name
) 操作を行います。
vb->type
フィールドを指定すると,free_out
あるいは
free_oid
ルーチンのどちらかを使用して
vb->value
データを解放します。
VARBIND
構造体自身の割り当て解除は行わず,それがポイントする名前バッファおよびデータ・バッファのみを割り当て解除します。
構文は次のとおりです。
void free_varbind_data(
VARBIND *vb
);
free_varbind_data
ルーチンの例を次に示します。
#include <esnmp.h> VARBIND *vb; : : assume oid and data are declared and : assigned appropriate values : vb = (VARBIND*)malloc(sizeof(VARBIND)); clone_oid(&vb->name, oid); clone_oct(&vb->value.oct, data); : : some processing that uses vb occurs here : free_varbind_data(vb); free(vb);
set_debug_level
ルーチンは,どのようなログ・メッセージが生成されたかを検出するロギング・レベルを設定します。
プログラムもしくはモジュールが,実行時オプションに応じて,プログラムの初期化時にこのルーチンを呼び出します。
このルーチンが呼び出されていない場合,省略時の設定として WARNING および ERROR メッセージが
stdout
に送られます。
構文は次のとおりです。
void set_debug_level(
int stat,
LOG_CALLBACK_ROUTINE callback_routine
);
引数は次のとおりです.
ログ・レベル。 次の値が,個別もしくは組み合わせで設定されます。
エラーが発生し,再起動を必要とする場合。
パケットを処理できない場合。 ERROR も含む。
すべてのパケットをトレースする場合。 ERROR および WARNING を含む。
標準出力でなく
syslog
へ出力が送られる。
ログ・メッセージを出力するためにコールバック関数が呼び出される。 このビットが設定されている場合は,2 つ目の引数としてユーザが提供する外部コールバック関数のポインタを指定する必要がある。 DAEMON_LOG および EXTERN_LOG が指定されていない場合は,標準出力へ送られる。
ユーザ定義の外部コールバック関数。 たとえば,次のように定義します。
void callback_function(
int level,
char *message
);
level
には,ERROR
,WARNING
あるいは
TRACE
を指定します。
EXTERN_LOG ビットが
stat
に設定されている場合,ESNMP_LOG
マクロが実行されると
callback
関数が呼び出され,ログ・レベルは生成するログ・メッセージを指定します。
この機能によって,eSNMP ライブラリ関数がログ・メッセージを出力する場所を制御できます。
EXTERN_LOG
ビットが設定されていない場合は,コールバック関数の引数として NULL ポインタが渡されます。
set_debug_level
ルーチンの例を次に示します。
#include <esnmp.h> extern void log_handler(int level, char *message); if (daemonize) set_debug_level(EXTERN_LOG | WARNING, log_handler); else set_debug_level(TRACE, NULL);
is_debug_level
ルーチンは,指定したレベルが設定されているかどうかロギングのレベルをテストします。
次のようにレベルをテストできます。
ERROR -- エラーが発生し,再起動を必要とする場合。
WARNING -- パケットを処理できない場合。 ERROR も含む。
TRACE -- すべてのパケットをトレースする場合。 ERROR および WARNING も含む。
DAEMON_LOG --
syslog
に出力する場合。
EXTERN_LOG -- ログ・メッセージを出力するために callback 関数を呼び出す場合。
構文は次のとおりです。
int is_debug_level(
int type
);
戻り値は次のとおりです。
要求したレベルが設定されており
ESNMP_LOG
が出力を生成します。
あるいは指定した場所へ出力されます。
ロギング・レベルが設定されていません。
is_debug_level
ルーチンの例を次に示します。
#include <esnmp.h> if (is_debug_level(TRACE)) dump_packet();
ESNMP_LOG
ルーチンは,<esnmp.h>
ヘッダファイルで定義されているエラー宣言 C マクロです。
取得できる情報を集め,ログに送ります。
DAEMON_LOG
が設定されている場合,ログ・メッセージはデーモン・ログへ送られます。
EXTERN_LOG
が設定されている場合,ログ・メッセージは
callback
関数へ送られます。
それ以外の場合は,標準出力へ出力されます。
注意
esnmp_log
ルーチンは,ESNMP_LOG マクロを使用して呼び出されます。 ESNMP_LOG マクロは,テキスト部分をフォーマットするのにヘルパー・ルーチンesnmp_logs
を使用します。 これらの関数はESNMP_LOG
マクロなしで使用しないでください。
#define ESNMP_LOG(level, x) if (is_debug_level(level)) { \ esnmp_log(level, esnmp_logs x, __LINE__, __FILE__);}
x には次の構文で文字列を指定します。
text -
format, arguments, ....
たとえば
printf
文を指定します。
次のいずれかを指定します。
ERROR
エラー状態を宣言します。
WARNING
警告を宣言します。
TRACE
トレースがアクティブな場合ログ・ファイルを挿入します。
構文は次のとおりです。
ESNMP_LOG(level,(format,...))
ESNMP_LOG
ルーチンの例を次に示します。
#include <esnmp.h> ESNMP_LOG( ERROR, ("Cannot open file %s\n", file));