INtime SDK Help
bpf (Berkeley Packet Filter)

#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <net/bpf.h>

int 
bpf_open(char * name, int flags, int mode);

概要

バークレイパケットフィルタはプロトコルとは独立した方法でデータリンク層(レイヤ)に生のインタフェース(Raw Interface)を提供します。他のホスト宛のパケットであっても、本メカニズムを通して、ネットワーク上の全てのパケットにアクセスすることができます。

パケットフィルタはキャラクタ特殊デバイスとして使用します。 (/dev/bpf0、/dev/bpf1等)。デバイスのオープン後にファイルデスクリプタを特定のネットワークインターフェースとバインドする必要があります。BIOCETIF ioctlにて行ないます。指定されたインターフェースは複数のリスナにより共有可能となり各記述子のベースとなるフィルタは同一のパケットストリームを参照することになります。

別々のデバイスファイルにはそれぞれのマイナデバイスが必要とされます。ファイルが使用中である場合、bpf_openは失敗し、 EBUSYがerrnoに返却されます。

オープンしているbpfファイルの各インスタンスに関連付けされているものは、ユーザが設定可能なパケットフィルタです。インターフェースによるパケット受信時は常に、インターフェースにてlisten(接続待機)するすべてのファイルデスクリプタがフィルタを適用します。パケットを受け付ける各デスクリプタはそのコピーを受け付けることになります。

これらのファイルからの読み込みは、フィルタにマッチしたパケットの次のグループを返します。性能を向上させるためには、読み込みのために渡されたバッファサイズとbpfが内部で使用するバッファサイズを同じサイズにしなければいけません。このサイズは BIOCGBLEN ioctl (下記参照) によって返され、 BIOCSBLEN で設定できます。このサイズより大きい個々のパケットは必然的に切り詰められることに注意してください。

パケットフィルタは、固定長ヘッダを持つリンクレベルプロトコルをサポートします。現在はイーサネット、SLIP および PPPドライバのみがbpfと交信するように変更されています。

パケットデータはネットワークバイト順であるため、アプリケーションがマルチバイトの値を抽出するためには byteorderマクロを使用するべきです。

bpfファイルデスクリプタに書き込みすることにより、ネットワークにパケットを送出することができます。書き込みはバッファリングされないので、1 回の書き込みにつき1つのパケットだけしか処理されません。現在イーサネットと SLIP リンクへの書き込みのみがサポートされています。

bpf_open() modeflags はopenに定義されています。

IOCTLS

ioctlコマンドは<net/bpf.h>に定義されています。全てのコマンドは以下のインクルードファイルを必要とします:

     #include <sys/types.h>
     #include <sys/time.h>
     #include <sys/ioctl.h>
     #include <net/bpf.h>


さらに、BIOCGETIF と BIOCSETIF は <sys/socket.h>と<net/if.h> を必要とします。

FIONREAD と SIOCGIFADDR に加えて、次のコマンドはどんなbpfファイルのオープンに適用されます。 ioctlへの(3番目の)引数は指示されたタイプへのポインタであるべきです:

BPF ヘッダ

struct bpf_hdr {
             struct timeval bh_tstamp;     /* time stamp */
             u_long bh_caplen;             /* length of captured portion */
             u_long bh_datalen;            /* original length of packet */
             u_short bh_hdrlen;            /* length of bpf header (this struct
                                              plus alignment padding */
     };

次の構造体は readにより返却された各パケットの先頭に追加されます:

bh_hdrlen フィールドはヘッダとリンクレベルプロトコルの間のパディングとなるように存在しています。ここでの目的はパケットデータ構造の適切な境界調整を保証することです。それは、境界調整に注意を要するアーキテクチャで必要であり、他の多くのアーキテクチャで性能を向上させます。パケットフィルタは bpf_hdr とネットワーク層のヘッダがワード境界になることを保障します。境界調整が制限されたマシンのリンク層プロトコルのフィールドにアクセスするとき、適切な注意を払わなければなりません。(これはイーサネットに関する問題ではありません。なぜなら、タイプフィールドは偶数オフセットに当たる short であり、アドレスはおそらくバイト単位でアクセスされるからです)。

さらに、個々のパケットはそれぞれワード境界で始まるようにパディングされます。これは、アプリケーションがパケットから次のパケットをどのように取得するかに関する何らかの知識があることを必要とします。マクロ BPF_WORDALIGN は、この処理過程を容易にするために <NET bpf.h> で定義されます。その引数は最も近いワード境界値 (ここで、ワードは BPF_ALIGNMENT バイト幅) に切り上げられます。

例えば "p" がパケットの始まりを指すなら、次の式はポインタを次のパケットへ進めます:

p = (char *)p + BPF_WORDALIGN(p->bh_hdrlen + p->bh_caplen)

境界調整の機構が適切に動作するためには read に渡されるバッファはそれ自体がワード境界になければなりません。malloc 関数は常に境界調整されたバッファを返します。

フィルタマシン

フィルタプログラムはすべての分岐が前方に方向づけられた return 命令で終わる、命令の配列です。各命令は、アキュムレータ、インデックスレジスタ、一時メモリ記憶、および内在するプログラムカウンタから成る疑似マシン状態で何らかの動作を実行します。

次の構造体は命令形式を定義します:

struct bpf_insn {
         u_short code;
         u_char  jt;
         u_char  jf;
         u_long k;
     };

kフィールドはさまざまな命令でさまざまな方法で使用され、jt と jf フィールドは分岐命令によってオフセットとして使用されます。オペコードは準階層的な方法でコード化されます。次の 8 つのクラスの命令があります: BPF_LD, BPF_LDX, BPF_ST, BPF_STX, BPF_ALU, BPF_JMP, BPF_RET と BPF_MISC です。他の様々なモードと操作ビットは、実際の命令を与えるためにクラスに論理和 (or) されます。クラスとモードは<net/bpf.h>で定義されています。

以下は、定義されたそれぞれの bpf 命令のセマンティクス (意味) です。便宜的に A はアキュムレータ、X はインデックスレジスタ、P[] はパケットデータ、 M[] は一時メモリ記憶であるとします。P[i:n] はパケット中のバイトオフセット "i" のデータを示し、ワード (n= 4)、符号無しハーフワード (n=2) または符号無しバイト (n=1) と解釈されます。M[i] は、ワード単位でのみアドレス指定される一時メモリ記憶で i 番目のワードを示します。メモリ記憶は 0 から BPF_MEMWORDS - 1 までインデックス付けされます。k, jt と jf は命令定義の中で対応するフィールドです。"len" はパケットの長さを参照します。

bpf インタフェースは配列の初期化を容易にするために次のマクロを提供しています: BPF_STMT(opcode, operand) と BPF_JUMP(opcode, operand, true_offset, false_offset) です。

作者

Lawrence Berkeley 研究所の Steven McCanne は、1990 年夏にBPFを実装しました。デザインの多くはVan Jacobsonによります。

バグ

読み込みバッファは (BIOCGBLEN ioctl によって返される) 固定サイズでなければなりません。

無差別モードを要求しないファイルは同じハードウェアインタフェースでこのモードを要求する別のファイルの副作用として受信パケットを無差別に受信するかもしれません。これはオーバヘッドのある追加処理でカーネルで修正することができるかもしれません。しかしながら、私たちは、すべてのファイルがインタフェースが無差別であると仮定しなければならないようなモデルを好みます。そして、そうだとしたら必要に応じて、外部のパケットを拒否するためにフィルタを利用しなければなりません。

可変長ヘッダがあるデータリンクプロトコルは現在サポートされていません。

SEESENT, DIRECTION と FEEDBACK の設定は、ソフトウェアループバックとポイントツーポイントインタフェースよりむしろハードウェアループバックがあるそれらを含んで、いくつかのインタフェースタイプで正しく動作しないことが観測されました。それらは、広範囲のイーサネットスタイルインタフェースで正しく機能するように思われます。

関連ファイル

/dev/bpfn パケットフィルタデバイス

歴史

Enet パケットフィルタは、1980 年に Carnegie-Mellon 大学で Mike Accetta と Rick Rashid によって作成されました。Jeffrey Mogul は、Stanfordでコードを BSD に移植して、1983 年以降開発を続けました。それ以来、それは DEC の Ultrix Packet Filter、SunOS 4.1のSTREAMS NIT モジュール、そして BPF へと発展しています。

対応情報

Versions Link to
INtime 4.0 clib.lib
netlib.lib
関連トピック
フィードバック送信