EN JA
SIFTR(4)
SIFTR(4) FreeBSD Kernel Interfaces Manual SIFTR(4)

名称

SIFTRTCP 調査のための統計情報

書式

実行時にモジュールとしてドライバをロードするためには、root として次のコマンドを実行します:

kldload siftr

もう一つの方法として、ブート時にモジュールとしてドライバをロードするためには、次の行を loader.conf(5) ファイルに追加します:

siftr_load="YES"

解説

SIFTR ( Statistical Information For TCP Research) カーネルモジュールは、アクティブな TCP 接続での一連の統計をログファイルにログ記録します。それは、システム管理者、開発者と研究者を対象にした、TCP 接続状態の極めて粒度の細かい測定を行う能力を提供します。

コンパイル時の設定

SIFTR のデフォルト動作は、IPv4 TCP/IP パケットをキャプチャすることです。次を非コメント化して再コンパイルすることによって IPv4 と IPv6 をサポートするための SIFTR を設定することができます:

CFLAGS+=-DSIFTR_IPV6

これは、<sys/modules/siftr/Makefile>にあります。

IPv4 だけ (デフォルト) のモードで、標準のドット付き 10 進記法 (例えば、"136.186.229.95") は、ログ記録のために IPv4 アドレスを書式化するために使用されます。 IPv6 モードで、標準のドット付き 10 進記法は、IPv4 アドレスを書式化するために使用され、標準のコロンで区切られた 16 進記法 (RFC 4291 参照) は、ログ記録のために IPv6 アドレスを書式化するために使用されます。 SIFTR は、IPv6 アドレスを書式化するために圧縮復元された記法を使用することに注意してください。例えば、アドレス "fe80::20f:feff:fea2:531b"は、"fe80:0:0:0:20f:feff:fea2:531b"としてログ記録されます。

実行時の設定

SIFTR は、ユーザ空間に設定変数をエクスポートするために sysctl(8) インタフェースを利用します。次の変数が利用可能です:
net.inet.siftr.enabled
モジュールが測定を実行するかどうかを制御します。デフォルトで、値は、モジュールが任意の測定値も取らないことを意味する、 0 に設定されます。 0 に設定された net.inet.siftr.enabled でロードされたモジュールを得るためには、 net.inet.siftr.enabled が 1 に設定されるときだけ、パケットフィルタリングフックが挿入されるように、ネットワークスタックの性能に影響されません。
net.inet.siftr.ppl
与えられた TCP 接続のための着信/発信パケットが接続のために生成されるログメッセージをどのくらいもたらすかを制御します。デフォルトで、値は、モジュールがすべての TCP 接続のあらゆるパケットに対してメッセージをログ記録することを意味する、1 に設定されます。値は、範囲 [1,2^32] の任意の整数を設定でき、モジュールが有効にされている間でも、いつでも変更することができます。
net.inet.siftr.logfile
モジュールがログメッセージを書き込むファイルのパスを制御します。デフォルトで、ファイル /var/log/siftr.log が使用されます。モジュールが有効にされている間でも、いつでも、パスを変更することができます。
net.inet.siftr.genhashes
ハッシュが SIFTR によって見られる各 TCP パケットのために生成されるかどうかを制御します。デフォルトで、値は、ハッシュが生成されないことを意味する、0 に設定されます。ハッシュは、特定のログメッセージの生成の引き金となった TCP パケットを相互に関連付けるために役に立ちますが、それらを計算することは、追加のコンピュータのオーバヘッドを速いパスに加えます。訳注: 意味不明。

ログ形式

代表的な SIFTR ログファイルは、3 つの異なったタイプのログメッセージを含みます。すべてのメッセージは、平板な ASCII テキストで書き込まれます。

注意: このセクションの例のログメッセージの“\”表現は、行の継続を示していて、実際のログメッセージの一部ではありません。

最初のログメッセージのタイプは、モジュールが有効にされるとき、ファイルに書き込まれ、実行しているカーネルからデータの収集を開始します。下記のテキストは、例のモジュールがログを有効にすることを示しています。フィールドは、システムに関する何らかの基本情報について説明している、タブで区切られたキーと値の組です。

enable_time_secs=1238556193    enable_time_usecs=462104 \ 
siftrver=1.2.2    hz=1000    tcp_rtt_scale=32 \ 
sysname=FreeBSD    sysver=604000    ipmode=4

フィールドの説明は、次の通りです:

enable_time_secs
UNIX 基準時点からの秒単位のモジュールが有効にされた時間。
enable_time_usecs
enable_time_secs 以来のマイクロ秒単位のモジュールが有効にされた時間。
siftrver
SIFTR のバージョン。
hz
1 秒毎の tick (刻) 単位のカーネルの tick レート。
tcp_rtt_scale
平滑化した RTT の見積りスケールファクタ。
sysname
オペレーティングシステム名。
sysver
オペレーティングシステムのバージョン。
ipmode
コンパイル時に定義される IP モード。 "4"の ipmode は、IPv6 がサポートされず、IP アドレスが通常のドット付き 4 つ組形式でログインされることを意味します。 "6"の ipmode は、IPv6 がサポートされ、“コンパイル時の設定”サブセクションで説明されるように、 IP アドレスがドット付き 4 つ組または 16 進数形式でログインされることを意味します。

ログメッセージの 2 番目のタイプは、データログメッセージが生成されるとき、ファイルに書き込まれます。下記のテキストは、IPv4 TCP/IP パケットによって引き金となった例のデータログを示しています。データは、書式化された CSV です。

o,0xbec491a5,1238556193.463551,172.16.7.28,22,172.16.2.5,55931, \ 
1073725440,172312,6144,66560,66608,8,1,4,1448,936,1,996,255, \ 
33304,208,66608,0,208,0

フィールドの説明は、次の通りです:

1
ログメッセージの引き金となったパケットの方向。入力のための“i”または出力のための“o”のいずれかです。
2
ログメッセージの引き金となったパケットのハッシュ。
3
ログメッセージの引き金となったパケットが、 pfil(9) フック関数によって処理された、UNIX 基準時点からの秒とマイクロ秒単位の時間。
4
ドット付き 4 つ組 (IPv4 パケット) またはコロンで区切られた 16 進数 (IPv6 パケット) 記法での、ローカルホストの IPv4 または IPv6 アドレス。
5
ローカルホストが通信している TCP ポート。
6
ドット付き 4 つ組 (IPv4 パケット) またはコロンで区切られた 16 進数 (IPv6 パケット) 記法での、外部ホストの IPv4 または IPv6 アドレス。
7
外部ホストが通信している TCP ポート。
8
バイト単位のフローのための遅く開始した閾値。
9
バイト単位のフローのための現在の混雑状態のウィンドウ。
10
バイト単位のフローのための現在の帯域幅で制御されたウィンドウ。
11
バイト単位のフローのための現在の送信ウィンドウ。ポスト scaled 値は、unscaled 値が、報告される時間の間に初期のハンドシェイク (最初のわずかなパケット) の間を除いて、報告されます。
12
バイト単位のフローのための現在の受信ウィンドウ。ポスト scaled 値は、常に報告されます。
13
送信ウィンドウのための現在のウィンドウのスケールファクタ。
14
受信ウィンドウのための現在のウィンドウのスケールファクタ。
15
< netinet/tcp_fsm.h>で定義されるような TCP の有限な状態マシンの現在の状態。
16
バイト単位のフローのための最大のセグメントサイズ。
17
TCP_RTT_SCALE * HZ の単位のフローのための現在の平滑化した RTT 見積り、ここで、TCP_RTT_SCALE は、tcp_var.h に定義されていて、 HZ は、カーネルの tick タイマです。秒単位の RTT を取得するために、TCP_RTT_SCALE * HZ で割られます。 TCP_RTT_SCALE と HZ は、有効にされたログメッセージで報告されます。
18
有効にされた SACK インジケータ。 SACK が有効にされるなら、1、そうでなければ、0 です。
19
フローのための TCP フラグの現在の状態。様々なフラグの情報については、< netinet/tcp_var.h>を参照してください。
20
HZ の単位のフローのための現在の再送タイムアウトの長さ、ここで、HZ は、カーネルの tick タイマです。秒単位のタイムアウトの長さを取得するるために HZ で割られます。 HZ は、有効にされたログメッセージで報告されます。
21
バイト単位のソケット送信バッファの現在のサイズ。
22
ソケット送信バッファの現在のバイト数。
23
バイト単位のソケット受信バッファの現在のサイズ。
24
ソケット受信バッファの現在のバイト数。
25
送信中 (in-flight) 応答されていない現在のバイト数。 SACK を通して肯定応答されたバイトは、このカウントから排除されません。
26
再構築キューのセグメントの現在の番号。

ログメッセージの 3 番目のタイプは、モジュールが無効にされるとき、ファイルに書き込まれ、実行しているカーネルからデータを収集することを停止します。下記のテキストは、ログを無効にされた例のモジュールを示しています。フィールドは、モジュールがごく最近有効にされてから操作に関する統計を提供している、タブで区切られたキーと値の組です。

disable_time_secs=1238556197    disable_time_usecs=933607 \ 
num_inbound_tcp_pkts=356    num_outbound_tcp_pkts=627 \ 
total_tcp_pkts=983    num_inbound_skipped_pkts_malloc=0 \ 
num_outbound_skipped_pkts_malloc=0    num_inbound_skipped_pkts_mtx=0 \ 
num_outbound_skipped_pkts_mtx=0    num_inbound_skipped_pkts_tcb=0 \ 
num_outbound_skipped_pkts_tcb=0    num_inbound_skipped_pkts_icb=0 \ 
num_outbound_skipped_pkts_icb=0    total_skipped_tcp_pkts=0 \ 
flow_list=172.16.7.28;22-172.16.2.5;55931,

フィールドの説明は、次の通りです:

disable_time_secs
UNIX 基準時点からの秒単位のモジュールが無効にされた時間。
disable_time_usecs
disable_time_secs からのマイクロ秒単位のモジュールが無効にされた時間。
num_inbound_tcp_pkts
ネットワークスタックを上方に横断する TCP パケットの数。これは、 SIFTR が有効にされた期間に、着信の TCP パケットのみを含んでいます。
num_outbound_tcp_pkts
ネットワークスタックを下方に横断する TCP パケットの数。これは、 SIFTR が有効にされた期間に、発信の TCP パケットのみを含んでいます。
total_tcp_pkts
num_inbound_tcp_pkts と num_outbound_tcp_pkts の合計。
num_inbound_skipped_pkts_malloc
失敗した malloc() 呼び出しのために、処理されなかった着信パケットの数。
num_outbound_skipped_pkts_malloc
失敗した malloc() 呼び出しのために、処理されなかった発信パケットの数。
num_inbound_skipped_pkts_mtx
失敗したパケット処理キューへのパケットの追加のために、処理されなかった着信パケットの数。
num_outbound_skipped_pkts_mtx
失敗したパケット処理キューへのパケットの追加のために、処理されなかった発信パケットの数。
num_inbound_skipped_pkts_tcb
失敗したパケットに関連している TCP 制御ブロックの検索のために、処理されなかった着信パケットの数。
num_outbound_skipped_pkts_tcb
失敗したパケットに関連している TCP 制御ブロックの検索のために、処理されなかった発信パケットの数。
num_inbound_skipped_pkts_icb
失敗したパケットに関連している IP 制御ブロックの検索のために、処理されなかった着信パケットの数。
num_outbound_skipped_pkts_icb
失敗したパケットに関連している IP 制御ブロックの検索のために、処理されなかった発信パケットの数。
total_skipped_tcp_pkts
すべてのスキップされたパケットカウンタの合計。
flow_list
モジュールがロードされてから生成されるデータログメッセージの引き金となった TCP フローの CSV リスト。 CSV リストの各フローエントリは、“local_ip;local_port-foreign_ip;foreign_port”として書式化されます。リストにエントリがない (すなわち、データログメッセージが生成されなかった) なら、値は、空白となります。リストに少なくとも 1 つのエントリがあるなら、後続するコンマは、常に存在します。

total_tcp_pkts - total_skipped_tcp_pkts と同じであるべきサイクルを有効にするか、または無効にするモジュールのためのログファイル中に見つけられるデータログメッセージの合計数。

実装に関する注

SIFTR は、 pfil(9) インタフェースを使用してネットワークスタックに接続します。現在の生まれ変わりでは、ネットワークスタックの IP 層でパケットを見ることを意味する、AF_INET/AF_INET6 (IPv4/IPv6) pfil(9) フィルタリングポイントに接続します。これは、TCP 層によって処理される前に、スタックに着信する TCP パケットがインタセプトされることを意味します。スタックから発信されるパケットは、TCP 層によって処理された後に、インタセプトされます。

下記のダイヤグラムは、 SIFTR がどのようにそれ自体をスタックに挿入するかを図解しています。

---------------------------------- 
           Upper Layers 
---------------------------------- 
    ^                       | 
    |                       | 
    |                       | 
    |                       v 
 TCP in                  TCP out 
---------------------------------- 
    ^                      | 
    |________     _________| 
            |     | 
            |     v 
           --------- 
           | SIFTR | 
           --------- 
            ^     | 
    ________|     |__________ 
    |                       | 
    |                       v 
IPv{4/6} in            IPv{4/6} out 
---------------------------------- 
    ^                       | 
    |                       | 
    |                       v 
Layer 2 in             Layer 2 out 
---------------------------------- 
          Physical Layer 
----------------------------------

SIFTR は、ディスクへのデータの書き込みを管理するために alq(9) インタフェースを使用します。

一見したところでは、利用者は、 SIFTR が個々の TCP パケットから情報を抽出していると誤って考えるかもしれません。これは、そうではありません。 SIFTR は、そのフローのための TCP 制御ブロックの状態のダンプの引き金となるシステムから起こる各 TCP フローのための (着信と発信) の TCP パケットイベントを使用します。 PPL は、1 に設定された状態で、私たちはフローパケットがシステムに入るか、または出るのと同じくらいの頻度で各 TCP フローの制御ブロック状態を抽出することは有効です。例えば、PPL を 2 に設定すると、標本抽出率は、半分にされます、すなわち、あらゆる 2 番目のフローパケット (着信または発信) によって、制御ブロック状態のダンプを引き起こします。

SIFTR が、 tcpdump(1) のようなパケットキャプチャ (捕獲) ツールの必要性を取り除かないので、個々のパケットの問い合わせに対して制御ブロックの問い合わせの区別は、重要です。 SIFTR によって、利用者は、 ( tcpdump(1) のようなツールを使用してキャプチャされる) ワイヤ上に見るものと、興味があるフローに対応する TCP 制御ブロックの変更の間の原因と影響 (cause-and-affect) の関係を相互に関連付けて、観測することができます。したがって、完全な絵のようにつなぎ合わせる必要なデータを集めるのに SIFTRtcpdump(1) のようなツールを使用するのは、役に立ちます。それ自体でいずれかのツールを使用することは、必要なデータのすべてを提供できません。

TCP 制御ブロックを問い合わせるために必要な結果として、接続のライフサイクルの間の特定のパケットは、 SIFTR ログメッセージの引き金となることができません。初期のハンドシェイクは、制御ブロックの存在なしで行われ、最終的な ACK は、接続が TIMEWAIT 状態であるとき、交換されます。

SIFTR は、ネットワークスタックを横断するパケットに導入された遅延を最小となるように設計されました。この設計は、高度に最適化され、パケットを保持して、これらの詳細を実際の処理とログ記録のための別のスレッドに渡している間に必要な最小の詳細を抽出する最小のフック関数を要求しました。

このマルチスレッド化された設計は、スレッドの動作の間に共有されたデータ構造にアクセスするとき、いくつかの競合問題を持ち込みます。フック関数が構造体の詳細を認識するとき、最初に、排他的なロックを獲得しなければなりません。同様に、処理スレッドが構造体から詳細を読み込もうとするとき、そうするために排他的なロックも獲得しなければなりません。 1 つのスレッドがロックを保持するなら、それを取得できる前に、他方は、待た (ウェートし) なければなりません。これは、カーネルのパケット処理コードパスに何らかの追加の境界の遅延を持ち込みます。

ある場合には (例えば、少ない記憶、接続の終了)、 SIFTR pfil(9) フック関数に入る TCP パケットは、生成されるログメッセージの引き金となりません。 SIFTR は、“スキップされたパケット”としてこの効果を言及します。 SIFTR は、たとえ、それらが、データログメッセージの引き金となることが成功できなくても、常にパケットがスタックを通して継続できることを確実にすることに注意してください。したがって、 SIFTR は、ネットワークスタックを横断する TCP/IP パケットのための少しのパケットの損失も起こりません。

重要な振る舞い

モジュールが有効にされる間のログファイルのパスの変更の振る舞いは、次の通りです:
  1. 書き込みのために新しいファイルのパスをオープンすることを試みます。これが失敗するなら、パスの変更は、失敗し、既存のパスが、引続き使用されます。
  2. 新しいパスは、有効で、成功してオープンされたと仮定します:
    • すべての保留中 (pending) のログメッセージを古いファイルのパスにフラッシュします。
    • 古いファイルのパスをクローズします。
    • アクティブなログファイルのポインタを新しいファイルのパスを指すようにスイッチします。
    • 新しいファイルにログ記録を開始します。

保留中のログメッセージを古いファイルにフラッシュし、新しいファイルにログ記録を開始する間の期間に、新しいログメッセージは、生成され、バッファリングされます。新しいファイルに書き込む準備ができるとすぐに、蓄積されたログメッセージは、ファイルに書き込まれます。

使用例

モジュールの動作を有効にするには、root として次のコマンドを実行します: sysctl net.inet.siftr.enabled=1

1 つのログメッセージが 1 つの接続あたり 10 の TCP パケット毎のために生成されるような、ログメッセージの精度を変更するには、 root として次のコマンドを実行します: sysctl net.inet.siftr.ppl=10

ログファイル位置を /tmp/siftr.log に変更するには、 root として次のコマンドを実行します: sysctl net.inet.siftr.logfile=/tmp/siftr.log

謝辞

このソフトウェアの開発は、 Community Foundation Silicon Valley の Cisco University Research Program Fund と FreeBSD Foundation からの補助金によって部分的に可能となりました。

歴史

SIFTR は、 FreeBSD 7.4FreeBSD 8.2 ではじめて登場しました。

SIFTR は、Community Foundation Silicon Valley の Cisco University Research Program Fund からの補助金によって部分的に可能となった、Advanced Internet Architectures, Melbourne, Australia のために Swinburne University of Technology の Centre で NewTCP 研究プロジェクトで、仕事をしている間に、Lawrence Stewart と James Healy によって、 2007 年に最初にリリースされました。その他の詳細については、次で利用可能です:

http://caia.swin.edu.au/urp/newtcp/

SIFTR v1.2.x の取り組みは、“Enhancing the FreeBSD TCP Implementation”プロジェクト 2008-2009 の一環として FreeBSD 財団によって資金提供されました。その他の詳細については、次で利用可能です:

http://www.freebsdfoundation.org/

http://caia.swin.edu.au/freebsd/etcp09/

作者

SIFTR は、 Lawrence Stewart <lstewart@FreeBSD.org>と James Healy <jimmy@deefa.com>によって書かれました。

このマニュアルページは、 Lawrence Stewart <lstewart@FreeBSD.org>によって書かれました。

バグ

現在の知られている制限といくつかの関連する回避策は、以下に概説されます:
  • スレッドの動作の間に情報を渡すために使用される内部のキューは、現在、バインドされていません。これによって、 SIFTR は、爆発的なネットワークトラフィックに対処することができますが、処理しているスレッドがパケットレートを維持することができないなら、持続している高い 1 秒あたりのパケットのトラフィックは、カーネルメモリの消耗を引き起こすかもしれません。
  • また pfil(9) フレームワーク、例えば、 dummynet(4), ipfw(8), pf(4) を利用する他のモジュールを実行するマシンで SIFTR を使用するなら、モジュールをロードする順序は、重要です。利用者は、 SIFTR がそれらを“見て、”処理する前に、TCP パケットが任意の必要な操作も受けることを確実にすように、最初に他のモジュールを kldload するべきです。
  • SIFTRwitness(4) サポートでコンパイルされたカーネルで有効にされるとき、 witness(4) によって報告された pfil(9) ミューテックスと tcbinfo TCP ロックの間で知られていて、無害なロック順序逆転の警告があります。
  • 利用者がデータを得たい TCP フローをフィルタリングする方法はありません。後処理は、関心がある特定のフローに属すデータを分離するために必要です。
  • モジュールは、ログファイルのパスの削除を検出しません。新しいログメッセージは、モジュールがファイルを使用するように設定される間に、 SIFTR によって使用されているログファイルが、削除されるなら、単に失われます。 net.inet.siftr.logfile 変数を使用する新しいログファイルに切り替えることは、新しいファイルを作成して、ログメッセージを再びディスクに書き込み始めることができます。新しいログファイルのパスは、パスから削除されたファイルまで異ならなければなりません。
  • コード中で使用されるハッシュテーブルは、 65536 のフローを保持するために大きさです。チェーン構造がハッシュテーブル構造内で衝突を取り扱うために使用されるので、これは、厳しい制限ではありません。しかしながら、私たちは、性能 (と、したがって、モジュールのパケット処理性能) を検索するハッシュテーブルが、サイクルのアプローチを有効/無効にし、65536 を上回るモジュールで扱われたユニークなフローの数として指数関数的な方法でデグレードされると (他のハッシュテーブル性能データとの類推に基づいて) 疑います。
  • フローハッシュテーブルで実行されるガーベージコレクションは、ありません。現在、それをフラッシュする唯一の方法は、 SIFTR を無効にすることです。
  • PPL 変数は、フック関数で受信された合計パケットではなく、処理しているスレッドにそれを行うパケットに適用されます。パケットは、PPL 変数が適用される前に、スキップされます、それは、ログメッセージの引き金となることでわずかな不一致となるかもしれないことを意味します。例えば、PPL が 10 に設定されていたなら、最後のログメッセージから 8 番目のパケットは、スキップされ、 11 番目のパケットは、実際に生成されるログメッセージの引き金となります。これは、CAIA 技術報告書 070824A でさらに深く議論されています。
  • これを書いている時点で、パケットをインタセプトするために TCP 層に接続する簡単な方法はありませんでした。 IP 層のフックポイントの SIFTR の使用は、すべての IP トラフィックが、マイナですが、それでも同様に、TCP でないパケットのためにシステムで不要なパケット遅延と処理のオーバヘッドを取り入れる、 SIFTR pfil(9) フック関数によって処理されることを意味します。また、IP 層でのフッキングは、データ収集の観点から望ましくありません。スタックを横断するパケットは、インタセプトされ、同じくらい正確に着信イベントと対応する TCP 制御ブロックの間の原因と影響 (cause-and-affect) の関係を観測できないことを意味する、 TCP 層によって処理される「前に」、ログメッセージの生成を引き起こします。理想としては、 SIFTR は、パケットが TCP 層によって処理された後に、それらをインタセプトするべきです、すなわち、tcp_input() によって処理された後に、スタックから上がってくるパケットをインタセプトし、tcp_output() によって処理された後に、スタックに落されるパケットをインタセプトします。現在のコードは、着信イベントが、発信イベントの引き金となる傾向があり、原因と影響 (cause-and-affect) を、同様に発信イベントの状態を捕獲することによって間接的に観測できるように、まだ満足できる精度を与えています。
  • SIFTR によってログ記録された“inflight bytes” (飛行中のバイト) 値は、受信ホストによって SACK されているバイトを考慮に入れません。
  • パケットのハッシュ生成は、現在、IPv6 ベースの TCP パケットにはうまくいきません。
  • 圧縮された記法は、IPv6 アドレス表現には使用されません。これは、ログ出力で必要とするより多くのバイトを消費します。
November 12, 2010 FreeBSD