日本語 man コマンド類 (ja-man-1.1j_5) と日本語 man ドキュメント (ja-man-doc-5.4 (5.4-RELEASE 用) など) をインストールすると、以下のような man コマンド閲覧、キーワード検索が コンソールからできるようになります。
4.11-RELEASE-K, 5.4-RELEASE-K, 5.5-RELEASE-K, 6.0-RELEASE-K から 6.4-RELEASE-K, 7.0-RELEASE-K から 7.4-RELEASE-K, 8.0-RELEASE-K から 8.4-RELEASE-K, 9.0-RELEASE-K から 9.3-RELEASE-K, 10.0-RELEASE-K から 10.3-RELEASE-K, 11.0-RELEASE-K から 11.4-RELEASE-K, 12.0-RELEASE-K, 12.1-RELEASE-K は、 プライベート版 (小金丸が編集してまとめたもの) ですが、 より多くの翻訳したファイルが含まれています。 (5.4-RELEASE-K から 6.4-RELEASE-K, 7.0-RELEASE-K から 7.4-RELEASE-K, 8.0-RELEASE-K から 8.4-RELEASE-K, 9.0-RELEASE-K から 9.3-RELEASE-K, 10.0-RELEASE-K から 10.3-RELEASE-K, 11.0-RELEASE-K から 11.4-RELEASE-K, 12.0-RELEASE-K から 12.4-RELEASE-K, 13.0-RELEASE-K から 13.3-RELEASE-K, 14.0-RELEASE-K から 14.1-RELEASE-K は、全翻訳済み)
13.3-STABLE-K, 15.0-CURRENT-K は現在、作成中で日々更新されています。
Table of Contents
BPF(4) FreeBSD カーネルインタフェースマニュアル BPF(4) 名称 bpf -- バークレイパケットフィルタ 書式 device bpf 解説 バークレイパケットフィルタは、プロトコルの独立の方法でデータリンク層 (レ イヤ) に生のインタフェースを提供します。ネットワーク上のすべてのパケット は、たとえ他のホストに向けられたものでも、この機構を通してアクセスできま す。 パケットフィルタは、キャラクタ特殊デバイス /dev/bpf として現れます。デバ イスをオープンした後に、ファイル記述子は、BIOCSETIF ioctl で特定のネット ワークインタフェースにバインドしなければなりません。あるインタフェース は、複数のリスナによって共有することができ、各記述子の基礎となるフィルタ は、同じパケットのストリームを見ることになります。 別々のデバイスファイルは、それぞれのマイナデバイスが必要とされます。ファ イルが使用中であるなら、オープンは、失敗し、errno は、EBUSY に設定されま す。 オープンしている bpf ファイルのインスタンスそれぞれに関連づけられているの は、ユーザが設定可能なパケットフィルタです。インタフェースでパケットが受 信されるときはいつでも、そのインタフェースで listen (接続を受け付け) して るすべてのファイル記述子は、それらのフィルタを適用します。パケットを受け 付ける各記述子は、それ自身のコピーを受け付けます。 パケットフィルタは、固定長ヘッダを持っているどんなリンクレベルプロトコル もサポートします。これまでのところ、イーサネット、SLIP および PPP ドライ バだけが bpf と交信するように変更されています。 パケットデータは、ネットワークバイト順になっているので、アプリケーション は、マルチバイトの値を抽出するためには byteorder(3) マクロを使用するべき です。 bpf ファイル記述子に書き込むことによってネットワークにパケットを送出する ことができます。書き込みは、バッファリングされないので、1 回の書き込みに つき 1 つのパケットだけしか処理されません。現在イーサネットと SLIP リンク への書き込みだけがサポートされています。 バッファモード bpf デバイスは、アプリケーションによって提供されたメモリバッファを通して パケットデータをアプリケーションに配信します。バッファモードは、 BIOCSETBUFMODE ioctl を使用して設定され、BIOCGETBUFMODE ioctl を使用して 読み込まれます。 バッファリングされた読み込みモード デフォルトで、bpf デバイスは、パケットデータが、read(2) システムコールを 使用してカーネルからユーザメモリへ明白にコピーされる、BPF_BUFMODE_BUFFER モードで動作します。ユーザプロセスは、内部のバッファをサイズを決めるため と、ファイル上のすべての read(2) 操作の両方ために使用される、固定のバッ ファサイズを宣言します。このサイズは、BIOCGBLEN ioctl を使用して問い会わ され、BIOCSBLEN ioctl を使用して設定されます。バッファサイズより大きい個 別のパケットは、必ずしも切り詰められないことに注意してください。 0 コピーバッファ (zero-copy buffer) モード また、bpf デバイスは、パケットデータが、システムコールとコピーのオーバ ヘッドの両方を避けて、カーネルによって 2 つのユーザメモリバッファに直接書 き込まれる、BPF_BUFMODE_ZEROCOPY モードで動作します。バッファは、固定の (等しい) サイズ、ページで整列され、偶数で複数ページサイズです。最大の 0 コピーバッファサイズは、BIOCGETZMAX ioctl によって返されます。バッファサ イズより大きい個別のパケットは、必ずしも切り詰められないことに注意してく ださい。 ユーザプロセスは、引数として struct bpf_zbuf ポインタを受け付ける BIOCSETZBUF ioctl を使用して 2 つのメモリバッファを登録します: struct bpf_zbuf { void *bz_bufa; void *bz_bufb; size_t bz_buflen; }; bz_bufa は、書き込まれる最初のバッファのユーザ空間のアドレスへのポインタ で、bz_bufb は、2 番目のバッファへのポインタです。bpf は、バッファが満杯 となり、認識されるとき、2 つのバッファの間を循環 (切り替え) します。 各バッファは、バッファのための同期とデータ長さの情報を保持するために、固 定長のヘッダで始まります: struct bpf_zbuf_header { volatile u_int bzh_kernel_gen; /* カーネル世代番号. */ volatile u_int bzh_kernel_len; /* バッファ内のデータ長. */ volatile u_int bzh_user_gen; /* ユーザ世代番号. */ /* ...将来の使用のための埋め草... */ }; すべての詰め物も含めて、各バッファのヘッダ構造は、それが BIOCSETZBUF を使 用して設定される前に、0 クリアされるべきです。バッファ中の残りの空間は、 バッファリングされる読み込みモードと同様に、パケットデータを格納し、同じ 形式でレイアウトするために、カーネルによって使用されます。 カーネルとユーザプロセスは、バッファへのアクセスを同期するためにバッファ ヘッダを通して簡単な承認プロトコルに従います: ヘッダ世代番号、 bzh_kernel_gen と bzh_user_gen が同じ値を保持するとき、カーネルが、バッ ファを所有し、異なるとき、ユーザ空間が、バッファを所有しています。 カーネルが、バッファを所有している間、内容は、不安定であり、非同期に変化 するかもしれません。ユーザプロセスが、バッファを所有している間、内容は、 安定していて、バッファが認識されるまで、変更されません。 バッファを登録する前にバッファヘッダをすべての 0 に初期化することは、両方 のバッファの最初の所有権をカーネルに割り当てるという効果があります。カー ネルは、バッファが bzh_kernel_gen を修正することによってユーザ空間に割り 当てられることで、シグナルを発生し、ユーザ空間がバッファを認識し、 bzh_user_gen の値を bzh_kernel_gen の値を設定することによって、それをカー ネルに返します。 キャッシュとメモリ再順序付けの効果を避けるために、ユーザプロセスは、バッ ファをチェックして、認識するとき、不可分な操作とメモリバリアを使用しなけ ればなりません: #include <machine/atomic.h> /* * 再利用のためにバッファの所有権をカーネルに返す. */ static void buffer_acknowledge(struct bpf_zbuf_header *bzh) { atomic_store_rel_int(&bzh->bzh_user_gen, bzh->bzh_kernel_gen); } /* * バッファがカーネルによってユーザ空間に割り当てられているかどうか * チェックする. ユーザ空間がバッファを所有しているなら, 真を返し, * そうでなければ, 偽を返します. */ static int buffer_check(struct bpf_zbuf_header *bzh) { return (bzh->bzh_user_gen != atomic_load_acq_int(&bzh->bzh_kernel_gen)); } ユーザプロセスは、任意のデータが、BIOCROTZBUF ioctl を使用するユーザ空間 で、保留中 (pending) であるなら、次のバッファの割り当てを強制します。これ によって、ユーザプロセスは、タイムアウトに続くような、バッファが満杯にな る前に、部分的に書き込まれたバッファのデータを検索することができます。プ ロセスは、データが存在していなかったなら、バッファがユーザ空間に割り当て られないときに、ヘッダの世代番号を使用してバッファの所有権を再チェックし なければなりません。 バッファリングされた読み込みモードで見られるように、kqueue(2), poll(2) と select(2) は、完了したバッファの利用可能性を待ってスリープするために使用 されます。それらは、次のバッファの所有権がユーザ空間に割り当てられると き、読み込み可能なファイル記述子を返します。 現在の実装では、カーネルは、0、1 または両方のバッファをユーザプロセスに割 り当てます。しかしながら、初期の実装は、多くても 1 つのバッファが、一度に ユーザプロセスに割り当てられる、不変条件を保っていました。発展と高性能を ともに確実にするために、ユーザプロセスは、できるだけはやく、再利用のため にそれを返して、別のバッファを保持している間に、2 番目のバッファでブロッ クのウェートしないで、完全に処理されたバッファを認識するべきです。 IOCTL 次の ioctl(2) コマンドコードは、<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 に加えて、次のコマンドは、どんな bpf ファイルのオープンに適用さ れます。ioctl(2) への (3 番目の) 引数は、指示されたタイプへのポインタであ るべきです。 BIOCGBLEN (u_int) bpf ファイル上で読み込みのために必要なバッファ長 を返します。 BIOCSBLEN (u_int) bpf ファイル上での読み込みのためのバッファ長を設 定します。バッファは、ファイルが BIOCSETIF によってインタ フェースにアタッチされる前に設定されなければなりません。 要求されたバッファサイズの場所を適用することができないな ら、許容できる最も近いサイズが設定され、引数に返されま す。このサイズでないバッファが渡されるなら、read (読み込 み) 呼び出しは、EINVAL エラーとなります。 BIOCGDLT (u_int) アタッチされたインタフェースの基本となるデータリ ンクレイアのタイプを返します。インタフェースが指定されて いないなら、EINVAL を返します。``DLT_'' が前に付いたデバ イスタイプは、<net/bpf.h> で定義されています。 BIOCGDLTLIST (struct bpf_dltlist) アタッチされたインタフェースの基本と なるデータリンクレイアの利用可能なタイプの配列を返します: struct bpf_dltlist { u_int bfl_len; u_int *bfl_list; }; 利用可能なタイプは、bfl_list フィールドによって指される配 列で返され、u_int のそれらの長さは、bfl_len フィールドに 供給されます。バッファ空間が十分でないなら、ENOMEM が返さ れ、悪いアドレスが遭遇されるなら、EFAULT が返されます。 bfl_len フィールドは、返された配列の u_int 単位の実際の長 さを示すように返り時に変更されます。bfl_list が NULL であ るなら、bfl_len フィールドは、u_int 単位の配列の要求され た長さを示すように設定されます。 BIOCSDLT (u_int) アタッチされたインタフェースの基本となるデータリ ンクレイアのタイプを変更します。インタフェースが指定され ていないか、または指定されたタイプがインタフェースのため に利用可能でないなら、EINVAL が返されます。 BIOCPROMISC 強制的にインタフェースを無差別 (promiscuous) モードにしま す。ローカルホストに向けられたものだけではなく、すべての パケットが処理されます。2 つ以上のファイルが与えられたイ ンタフェースで listen (接続を受け付け) されるかもしれない ので、インタフェースを無差別でないモードでオープンした listen する側は、無差別にパケットを受信することができま す。この問題は、適切なフィルタで改善することができます。 インタフェースは、無差別に listen (接続を受け付ける) して いるすべてのファイルがクローズされるまで、無差別モードの ままです。 BIOCFLUSH 着信パケットのバッファをフラッシュし、BIOCGSTATS によって 返される統計値をリセットします。 BIOCGETIF (struct ifreq) ファイルが listen (接続を受け付け) してい るハードウェアインタフェースの名前を返します。名前は、 ifreq 構造体の ifr_name フィールドに返されます。他のすべ てのフィールドは、未定義です。 BIOCSETIF (struct ifreq) ファイルに関連するハードウェアインタフェー スを設定します。このコマンドは、どんなパケットも読み込む ことができるようになる前に実行されなければなりません。デ バイスは、ifreq 構造体の ifr_name フィールドを使用する名 前によって示されます。さらに BIOCFLUSH の動作を実行しま す。 BIOCSRTIMEOUT BIOCGRTIMEOUT (struct timeval) 読み込みタイムアウトパラメータを設定また は取得します。引数は、読み込み要求でタイムアウトする前の 待ち時間の長さを指定します。このパラメータは、open(2) に よって 0 に初期化され、タイムアウトしないことを示します。 BIOCGSTATS (struct bpf_stat) パケットの統計値の次の構造体を返します: struct bpf_stat { u_int bs_recv; /* 受信したパケット数 */ u_int bs_drop; /* 落としたパケット数 */ }; フィールドは、次の通りです: bs_recv オープンまたはリセット以後にこの記述子に よって受信したパケットの数 (最後の read (読 み込み) 呼び出しのときからのバッファされて いるものを含みます)。 bs_dropフィルタで受け付けられましたが、バッファの オーバフローためにカーネルに落されたパケッ トの数 (すなわち、アプリケーションの読み込 みは、パケットトラフィックについていってい ません)。 BIOCIMMEDIATE (u_int) 引数の真偽値に基づいて ``直接モード'' を有効また は無効にします。直接モードが有効にされるとき、read (読み 込み) は、パケットの受信でただちに返ります。そうでなけれ ば、read は、カーネルバッファが満杯になるかタイムアウトが 起こるまでブロックされます。これは、リアルタイムでメッ セージに応答しなければならない rarpd(8) のようなプログラ ムで役に立ちます。新しいファイルに対するデフォルトは、オ フです。 BIOCSETF BIOCSETFNR (struct bpf_program) 興味のないパケットを捨てるためにカー ネルによって使用される読み込みフィルタプログラムを設定し ます。命令の配列とその長さは、次の構造体を使用して渡され ます: struct bpf_program { u_int bf_len; struct bpf_insn *bf_insns; }; フィルタプログラムは、bf_insns フィールドで指されますが、 `struct bpf_insn' のユニット中のフィルタプログラムの長さ は、bf_len フィールドによって与えられます。フィルタ言語の 説明については、セクションフィルタマシンを参照してくださ い。BIOCSETF と BIOCSETFNR の唯一の違いは、BIOCSETF が、 BIOCFLUSH の動作を実行しますが、BIOCSETFNR は、実行しませ ん。 BIOCSETWF (struct bpf_program) インタフェースへのどのようなタイプの パケットを書き込むことができるかを制御するカーネルによっ て使用される書き込みフィルタプログラムを設定します。bpf フィルタプログラムに関する詳しい情報については、BIOCSETF コマンドを参照してください。 BIOCVERSION (struct bpf_version) 現在カーネルで認識されているフィルタ 言語のメジャーとマイナバージョン番号を返します。フィルタ をインストールする前に、アプリケーションは、現在のバー ジョンが実行しているカーネルと互換性があるかどうかチェッ クしなければなりません。メジャー番号が一致し、アプリケー ションのマイナ番号がカーネルのマイナ番号と等しいか小さい なら、バージョン番号は互換性があります。カーネルのバー ジョン番号は、次の構造体で返されます: struct bpf_version { u_short bv_major; u_short bv_minor; }; 現在のバージョン番号は、<net/bpf.h> の BPF_MAJOR_VERSION と BPF_MINOR_VERSION によって与えられます。互換性のない フィルタは、未定義の動作となるかもしれません (たぶん、 ioctl() によってエラーが返されるかまたは偶然にパケットが 一致します)。 BIOCGRSIG BIOCSRSIG (u_int) 受信シグナルを設定または取得します。このシグナル は、FIOSETOWN によって指定されたプロセスまたはプロセスグ ループに送信されます。デフォルトは、SIGIO です。 BIOCSHDRCMPLT BIOCGHDRCMPLT (u_int) ``ヘッダ完全'' フラグの状態を設定するか取得しま す。リンクレベルソースアドレスがインタフェース出力ルーチ ンによって自動的に書き込まれるなら、0 が設定されます。リ ンクレベルソースアドレスが書き込まれるなら、通信する配線 に供給するように 1 に設定されます。このフラグは、デフォル トで 0 に初期化されます。 BIOCSSEESENT BIOCGSEESENT (u_int) これらのコマンドは、時代遅れですが、互換性のため に残されています。代わりに BIOCSDIRECTION と BIOCGDIRECTION を使用します。インタフェースで局所的で生成 されるパケットが BPF によって返されるべきであるかどうかを 決定するフラグを設定または取得します。インタフェースで着 信パケットだけを見るために 0 に設定します。インタフェース で局所的およびリモートに起因するパケットを見るために 1 に 設定します。このフラグは、デフォルトで 1 に初期化されま す。 BIOCSDIRECTION BIOCGDIRECTION (u_int) インタフェースの着信、発信、またはすべてのパケッ トが BPF によって返されるべきであるかどうか決定する設定を 設定するか、取得します。インタフェースの着信パケットのみ を見るためには、BPF_D_IN に設定します。インタフェースの ローカルとリモートから始まるパケットを見るためには BPF_D_INOUT に設定します。インタフェースの発信パケットの みを見るためには BPF_D_OUT に設定します。この設定は、デ フォルトで BPF_D_INOUT に初期化されます。 BIOCSTSTAMP BIOCGTSTAMP (u_int) BPF によって返されるタイムスタンプの形式と解像度 を設定するか、または取得します。64 ビットの struct timeval 形式でタイムスタンプを取得するために BPF_T_MICROTIME, BPF_T_MICROTIME_FAST, BPF_T_MICROTIME_MONOTONIC または BPF_T_MICROTIME_MONOTONIC_FAST を設定します。64 ビットの struct timespec 形式でタイムスタンプを取得するために BPF_T_NANOTIME, BPF_T_NANOTIME_FAST, BPF_T_NANOTIME_MONOTONIC または BPF_T_NANOTIME_MONOTONIC_FAST を設定します。64 ビットの struct bintime 形式でタイムスタンプを取得するために BPF_T_BINTIME, BPF_T_BINTIME_FAST, BPF_T_NANOTIME_MONOTONIC または BPF_T_BINTIME_MONOTONIC_FAST を設定します。タイムスタンプ を無視するために BPF_T_NONE を設定します。すべての 64 ビットのタイムスタンプの形式は、struct bpf_ts でラップさ れます。BPF_T_MICROTIME_FAST, BPF_T_NANOTIME_FAST, BPF_T_BINTIME_FAST, BPF_T_MICROTIME_MONOTONIC_FAST, BPF_T_NANOTIME_MONOTONIC_FAST と BPF_T_BINTIME_MONOTONIC_FAST は、_FAST 接尾辞のない対応す る形式に似ていますが、フルタイムカウンタ問い合わせを実行 しないので、それらの精度は、ワンタイマチック (one timer tick) です。BPF_T_MICROTIME_MONOTONIC, BPF_T_NANOTIME_MONOTONIC, BPF_T_BINTIME_MONOTONIC, BPF_T_MICROTIME_MONOTONIC_FAST, BPF_T_NANOTIME_MONOTONIC_FAST と BPF_T_BINTIME_MONOTONIC_FAST は、カーネルのブート以来の経 過時間を格納しています。この設定は、デフォルトで BPF_T_MICROTIME に初期化されています。 BIOCFEEDBACK (u_int) パケットフィードバックモードに設定します。これに よって、インタフェースを通る出力が成功するとき、インタ フェースへの入力のように、注入されたパケットをフィード バックすることができます。BPF_D_INOUT 方向が設定されると き、注入された発信パケットは、重複を避けるために BPF に よって返されません。このフラグは、デフォルトで 0 に初期化 されます。 BIOCLOCK bpf 記述子でロックされたフラグを設定します。これは、デバ イスの基本的な操作パラメータを変更することができるかもし れない ioctl コマンドの実行を防ぎます。 BIOCGETBUFMODE BIOCSETBUFMODE (u_int) 現在の bpf のバッファリングモードを取得か、または 設定します。指定できる値は、バッファリングされた読み込み モードの BPF_BUFMODE_BUFFER と 0 コピーバッファモードの BPF_BUFMODE_ZBUF です。 BIOCSETZBUF (struct bpf_zbuf) 現在の 0 コピーバッファ位置を設定しま す。バッファ位置は、いったん 0 コピーバッファモードが選択 されて、インタフェースにアタッチする前にだけ設定されま す。バッファは、同じサイズ、ページで整列され、ページの整 数の倍数のサイズでなければなりません。3 つのフィールド bz_bufa, bz_bufb と bz_buflen は、書き込まなければなりま せん。バッファが、既にこのデバイスに設定されていたなら、 ioctl は、失敗します。 BIOCGETZMAX (size_t) 許された最も大きい個々の 0 コピーバッファサイズ を取得します。2 つのバッファが 0 コピーバッファモードで使 用されるとき、(実際の) 制限は、返されたサイズの 2 倍で す。0 コピーバッファが、カーネルアドレス空間を消費すると き、特に 32 ビットのシステムで使用中の複数の bpf 記述子が あるとき、バッファサイズの保守的な選択が勧められます。 BIOCROTZBUF 任意のデータがバッファに存在するなら、次のバッファの所有 権を強制的にユーザ空間に割り当てられます。データが在して いないなら、バッファは、カーネルによって所有されていたま まとなります。これによって、0 コピーバッファリングの消費 者は、タイムアウトを実装することができ、部分的に満たされ たバッファを検索することができます。データがバッファに存 在しなくて、したがって、所有権が割り当てられない場合を扱 うために、ユーザプロセスは、bzh_kernel_gen に対して bzh_user_gen をチェックしなければなりません。 BIOCSETVLANPCP VLAN PCP ビットを指定された値に設定します。 標準 IOCTL bpf は、現在ユーザがオープンしているファイル記述子への非同期および/または ノンブロッキング I/O を行うことができるいくつかの標準的な ioctl(2) をサ ポートしています。 FIONREAD (int) 読み込みのために直ちに利用可能なバイト数を返します。 SIOCGIFADDR (struct ifreq) インタフェースに関連付けられたアドレスを返し ます。 FIONBIO (int) ノンブロッキング I/O を設定またはクリアします。arg が 0 以外であるなら、利用可能でないデータが -1 を返すとき、 errno は、EAGAIN に設定され、read(2) を行います。arg が 0 で あるなら、ノンブロッキング I/O は、無効にされます。注意: こ れを設定することは、BIOCSRTIMEOUT によって設定されたタイムア ウトを上書きします。 FIOASYNC (int) 非同期I/Oを有効または無効にします。有効にされるとき (arg が 0 以外)、FIOSETOWN によって指定されたプロセスまたは プロセスグループは、パケットが到着したとき、SIGIO 's の受信 を開始します。システムが利用者のためにこれをデフォルトしない ように、実施されるこれのために FIOSETOWN を行なわなければな らないことに注意してください。シグナルは、BIOCSRSIG を通して 変更されます。 FIOSETOWN FIOGETOWN (int) パケットが利用可能なとき、SIGIO を受信すべきプロセスま たはプロセスグループ (負であるなら) を設定または取得します。 シグナルは、BIOCSRSIG を使用して変更されます (上記参照)。 BPF ヘッダ 次の構造の 1 つは、read(2) によって、または 0 コピーバッファを通して返さ れた各パケットの先頭に追加されます: struct bpf_xhdr { struct bpf_ts bh_tstamp; /* タイムスタンプ */ uint32_t bh_caplen; /* キャプチャされた部分の長さ */ uint32_t bh_datalen; /* パケットのオリジナルの長さ */ u_short bh_hdrlen; /* bpf ヘッダの長さ (この構造体 + 境界調整パディング) */ }; struct bpf_hdr { struct timeval bh_tstamp; /* タイムスタンプ */ uint32_t bh_caplen; /* キャプチャされた部分の長さ */ uint32_t bh_datalen; /* パケットのオリジナルの長さ */ u_short bh_hdrlen; /* bpf ヘッダの長さ (この構造体 + 境界調整パディング) */ }; ホスト順に格納された値のフィールドは、次の通りです: bh_tstamp パケットがパケットフィルタによって処理された時刻。 bh_caplen パケットのキャプチャされている部分の長さ。これは、フィルタに よって指定された切り詰められた量の最小限とパケットの長さで す。 bh_datalen 通信する配線から離れたパケットの長さ。この値は、フィルタに よって指定された切り詰められた量に依存しません。 bh_hdrlen sizeof(struct bpf_xhdr) または sizeof(struct bpf_hdr) と等し くないかもしれない、bpf ヘッダの長さ。 bh_hdrlen フィールドは、ヘッダとリンクレベルプロトコルの間のパディングと なるように存在しています。ここでの目的は、パケットデータ構造の適切な境界 調整を保証することです。それは、境界調整に注意を要するアーキテクチャで必 要であり、他の多くのアーキテクチャで性能を向上させます。パケットフィルタ は、bpf_xhdr, bpf_hdr とネットワーク層のヘッダがワード境界になることを保 証します。現在、bpf_hdr は、タイムスタンプが後方互換性の理由のために BPF_T_MICROTIME, BPF_T_MICROTIME_FAST, BPF_T_MICROTIME_MONOTONIC, BPF_T_MICROTIME_MONOTONIC_FAST または BPF_T_NONE に設定されるとき、使用さ れます。そうでなければ、bpf_xhdr が使用されます。しかしながら、bpf_hdr は、近い将来、廃止される可能性があります。境界調整が制限されたマシンのリ ンク層プロトコルのフィールドにアクセスするとき、適切な注意を払わなければ なりません。(これは、イーサネットに関する問題ではありません。なぜなら、タ イプフィールドは、偶数オフセットに当たる short であり、アドレスは、おそら くバイト単位でアクセスされるからです)。 さらに、個々のパケットは、それぞれワード境界で始まるようにパディングされ ます。これは、アプリケーションがパケットから次のパケットをどのように取得 するかに関する何らかの知識があることを必要とします。マクロ BPF_WORDALIGN は、この処理過程を容易にするために <net/bpf.h> で定義されます。その引数 は、最も近いワード境界値 (ここで、ワードは、BPF_ALIGNMENT バイト幅) に切 り上げられます。 例えば `p' がパケットの始まりを指すなら、次の式は、ポインタを次のパケット へ進めます: p = (char *)p + BPF_WORDALIGN(p->bh_hdrlen + p->bh_caplen) 境界調整の機構が適切に動作するためには read(2) に渡されるバッファは、それ 自体がワード境界になければなりません。malloc(3) 関数は、常に境界調整され たバッファを返します。 フィルタマシン フィルタプログラムは、すべての分岐が前方に方向づけられた return 命令で終 わる、命令の配列です。各命令は、アキュムレータ、インデックスレジスタ、一 時メモリ記憶、および内在するプログラムカウンタから成る疑似マシン状態で何 らかの動作を実行します。 次の構造体は、命令形式を定義します: struct bpf_insn { u_short code; u_char jt; u_char jf; bpf_u_int32 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_LD これらの命令は、値をアキュムレータにコピーします。ソースオペラ ンドのタイプは、``アドレッシングモード'' によって指定され、定数 (BPF_IMM), 固定オフセットのパケットデータ (BPF_ABS), 可変オフ セットのパケットデータ (BPF_IND), パケットの長さ (BPF_LEN), ま たは一時メモリ記憶内のワード (BPF_MEM) になり得ます。BPF_IND と BPF_ABS に対しては、データサイズは、ワード (BPF_W), ハーフワー ド (BPF_H) またはバイト (BPF_B) を指定しなければなりません。 BPF_LD 命令として認識されるすべてのセマンティクス (意味) は、次 の通りです。 BPF_LD+BPF_W+BPF_ABS A <- P[k:4] BPF_LD+BPF_H+BPF_ABS A <- P[k:2] BPF_LD+BPF_B+BPF_ABS A <- P[k:1] BPF_LD+BPF_W+BPF_IND A <- P[X+k:4] BPF_LD+BPF_H+BPF_IND A <- P[X+k:2] BPF_LD+BPF_B+BPF_IND A <- P[X+k:1] BPF_LD+BPF_W+BPF_LEN A <- len BPF_LD+BPF_IMM A <- k BPF_LD+BPF_MEM A <- M[k] BPF_LDX これらの命令は、値をインデックスレジスタにロードします。このア ドレッシングモードは、アキュムレータのものをロードするよりもよ り制限されていますが、効率的に IP ヘッダ長をロードするための ハッキングである、BPF_MSH, を含んでいることに注意してください。 BPF_LDX+BPF_W+BPF_IMM X <- k BPF_LDX+BPF_W+BPF_MEM X <- M[k] BPF_LDX+BPF_W+BPF_LEN X <- len BPF_LDX+BPF_B+BPF_MSH X <- 4*(P[k:1]&0xf) BPF_ST この命令は、アキュムレータを一時メモリに格納します。宛先の可能 性が 1 つしかないので、アドレッシングモードを必要としません。 BPF_ST M[k] <- A BPF_STX この命令は、インデックスレジスタを一時メモリ記憶に格納します。 BPF_STX M[k] <- X BPF_ALU alu 命令は、アキュムレータとインデックスレジスタまたは定数の間 の操作を実行し、アキュムレータに結果を格納します。バイナリ操作 のためには、ソースモードは、(BPF_K または BPF_X) が必要です。 BPF_ALU+BPF_ADD+BPF_K A <- A + k BPF_ALU+BPF_SUB+BPF_K A <- A - k BPF_ALU+BPF_MUL+BPF_K A <- A * k BPF_ALU+BPF_DIV+BPF_K A <- A / k BPF_ALU+BPF_MOD+BPF_K A <- A % k BPF_ALU+BPF_AND+BPF_K A <- A & k BPF_ALU+BPF_OR+BPF_K A <- A | k BPF_ALU+BPF_XOR+BPF_K A <- A ^ k BPF_ALU+BPF_LSH+BPF_K A <- A << k BPF_ALU+BPF_RSH+BPF_K A <- A >> k BPF_ALU+BPF_ADD+BPF_X A <- A + X BPF_ALU+BPF_SUB+BPF_X A <- A - X BPF_ALU+BPF_MUL+BPF_X A <- A * X BPF_ALU+BPF_DIV+BPF_X A <- A / X BPF_ALU+BPF_MOD+BPF_X A <- A % X BPF_ALU+BPF_AND+BPF_X A <- A & X BPF_ALU+BPF_OR+BPF_X A <- A | X BPF_ALU+BPF_XOR+BPF_X A <- A ^ X BPF_ALU+BPF_LSH+BPF_X A <- A << X BPF_ALU+BPF_RSH+BPF_X A <- A >> X BPF_ALU+BPF_NEG A <- -A BPF_JMP ジャンプ命令は、制御の流れを変更します。条件付きのジャンプは、 アキュムレータと定数 (BPF_K) またはインデックスレジスタ (BPF_X) を比較します。結果が真 (または非 0) であるなら、真の分岐が解釈 され、そうでなければ偽の分岐が解釈されます。ジャンプオフセット は、8 ビットでコード化されるので、最長のジャンプは、256 命令で す。しかしながら、(BPF_JA) オペコードは、任意の距離がある行き先 を許す、オフセットとして 32 ビットの k フィールドを使用して常に ジャンプします。すべての条件文は、慣習として符号無しの比較を使 用します。 BPF_JMP+BPF_JA pc += k BPF_JMP+BPF_JGT+BPF_K pc += (A > k) ? jt : jf BPF_JMP+BPF_JGE+BPF_K pc += (A >= k) ? jt : jf BPF_JMP+BPF_JEQ+BPF_K pc += (A == k) ? jt : jf BPF_JMP+BPF_JSET+BPF_K pc += (A & k) ? jt : jf BPF_JMP+BPF_JGT+BPF_X pc += (A > X) ? jt : jf BPF_JMP+BPF_JGE+BPF_X pc += (A >= X) ? jt : jf BPF_JMP+BPF_JEQ+BPF_X pc += (A == X) ? jt : jf BPF_JMP+BPF_JSET+BPF_X pc += (A & X) ? jt : jf BPF_RET リターン命令は、フィルタプログラムを終了し、受信するパケットの 量を指定します (すなわち、それらは、切り詰め量を返します)。0 の 返り値は、パケットが無視されるべきであることを示しています。返 り値は、定数 (BPF_K) またはアキュムレータ (BPF_A) のいずれかで す。 BPF_RET+BPF_A A バイト受信 BPF_RET+BPF_K k バイト受信 BPF_MISC その他のカテゴリは、上記のクラスに適合しないもの、および追加す る必要がある新しい命令のために作成されました。現在、これらは、 インデックスレジスタをアキュムレータにコピーするまたはその逆を 行うレジスタ転送命令です。 BPF_MISC+BPF_TAX X <- A BPF_MISC+BPF_TXA A <- X bpf インタフェースは、配列の初期化を容易にするために次のマクロを提供して います: BPF_STMT(opcode, operand) と BPF_JUMP(opcode, operand, true_offset, false_offset) です。 SYSCTL 変数 sysctl(8) 変数の 1 組は、bpf サブシステムの振る舞いを制御します: net.bpf.optimize_writers: 0 様々なプログラムは、生のパケット (cdpd、lldpd、dhcpd、dhcp 中継な どは、そのようなプログラムのよい例です) を送信するために (しかし 受信ではなく) BPF を使用します。それらは、それらに送信されるため の着信パケットを必要としません、プログラムが pcap_set_filter() に よって明示的に読み込みフィルタを指定するまで、新しい BPF ユーザを 書き込み専用のインタフェースリストにアタッチすることで、このオプ ションを調整します。これは、高速インタフェースのためのあらゆる性 能劣化を排除します。 net.bpf.stats: 一般的な統計を検索するためのバイナリインタフェース。 net.bpf.zerocopy_enable: 0 0 のコピーがネットの BPF リーダで使用されることを可能にします。注 意して使用してください。 net.bpf.maxinsns: 512 BPF プログラムが含むことができる指示の最大数。あらゆるフィルタの ための指示の概数を決定するために tcpdump(1) -d オプションを使用し ます。 net.bpf.maxbufsize: 524288 パケットのバッファのために割り付ける最大のバッファサイズ。 net.bpf.bufsize: 4096 パケットのバッファに割り付けるデフォルトのバッファサイズ。 使用例 次のフィルタは、Reverse ARP デーモンから取得されます。それは、Reverse ARP 要求のみを受信します。 struct bpf_insn insns[] = { BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_REVARP, 0, 3), BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 20), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARPOP_REVREQUEST, 0, 1), BPF_STMT(BPF_RET+BPF_K, sizeof(struct ether_arp) + sizeof(struct ether_header)), BPF_STMT(BPF_RET+BPF_K, 0), }; このフィルタは、ホスト 128.3.112.15 と 128.3.112.35 の間の IP パケットだ けを受け付けます。 struct bpf_insn insns[] = { BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_IP, 0, 8), BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 26), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 2), BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 30), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 3, 4), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 0, 3), BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 30), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 1), BPF_STMT(BPF_RET+BPF_K, (u_int)-1), BPF_STMT(BPF_RET+BPF_K, 0), }; 最後に、このフィルタは、TCP finger パケットだけを返します。私たちは、TCP ヘッダに達するために IP ヘッダを解析しなければなりません。BPF_JSET 命令 は、IP フラグメントオフセットが 0 であることをチェックし、それで、私たち は、TCP ヘッダがあることを確信します。 struct bpf_insn insns[] = { BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_IP, 0, 10), BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 23), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_TCP, 0, 8), BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 20), BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x1fff, 6, 0), BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 14), BPF_STMT(BPF_LD+BPF_H+BPF_IND, 14), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 79, 2, 0), BPF_STMT(BPF_LD+BPF_H+BPF_IND, 16), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 79, 0, 1), BPF_STMT(BPF_RET+BPF_K, (u_int)-1), BPF_STMT(BPF_RET+BPF_K, 0), }; 関連項目 tcpdump(1), ioctl(2), kqueue(2), poll(2), select(2), ng_bpf(4), bpf(9) McCanne, S. and Jacobson V., An efficient, extensible, and portable network monitor. 歴史 Enet パケットフィルタは、1980 年に Carnegie-Mellon 大学で Mike Accetta と Rick Rashid によって作成されました。Jeffrey Mogul は、Stanford でコードを BSD に移植して、1983 年以降開発を続けました。それ以来、それは、DEC の Ultrix Packet Filter、SunOS 4.1 の STREAMS NIT モジュール、そして BPF へ と発展しています。 作者 Lawrence Berkeley 研究所の Steven McCanne は、1990 年夏に BPF を実装しま した。デザインの多くは、Van Jacobson のおかげです。 0 コピーバッファのサポートは、Seccuris Inc. と契約して Robert N. M. Watson によって追加されました。 バグ 読み込みバッファは、(BIOCGBLEN ioctl によって返される) 固定サイズでなけれ ばなりません。 無差別モードを要求しないファイルは、同じハードウェアインタフェースでこの モードを要求する別のファイルの副作用として受信パケットを無差別に受信する かもしれません。これは、オーバヘッドのある追加処理でカーネルで修正するこ とができるかもしれません。しかしながら、私たちは、すべてのファイルがイン タフェースが無差別であると仮定しなければならないようなモデルを好みます。 そして、そうだとしたら必要に応じて、外部のパケットを拒否するためにフィル タを利用しなければなりません。 SEESENT, DIRECTION と FEEDBACK の設定は、ソフトウェアループバックとポイン トツーポイントインタフェースよりむしろハードウェアループバックがあるそれ らを含んで、いくつかのインタフェースタイプで正しく動作しないことが観測さ れました。それらは、広範囲のイーサネットスタイルインタフェースで正しく機 能するように思われます。 FreeBSD 13.2 October 13, 2021 FreeBSD 13.2