BPF Compiler CollectionでTCPのコネクションをトレースする

まず、Berkeley Packet FilterとBPF Compiler Collectionについて簡単に説明していきます。(以下ではそれぞれをBPFとBCCと略します。)

BPFとは

BPFは独自の命令セットを持つVMです。ユーザーランドのコードをカーネル内で安全に実行することができます。”The BSD Packet Filter: A New Architecture for User-Level Packet Captur”によると、1992年時点ではパケットフィルタリングのためのものだったようです。現在はセキュリティやトレーシングのためにも使用されています。

BCCとは

BPFでカーネルのトレーシングやフィルダリングなどを行うためのツール郡です。Python用のバインディングもあり、BPFを容易に扱うことができます。(実際にはC言語も書くことになりますが…)
インストール方法はこちらをご覧ください。

BCCを使用しない場合、BPFアセンブラを直接書いたり、ClangでC言語をBPFにコンパイルしたりすることでBPFを利用できます。(LLVM 3.7からLLVMのバックエンドにBPFが追加されています。)

トレース

BPFを利用すれば、下の図のようにカーネルの多くの部分にアタッチすることができます。

今回はすでに用意されているbpf/tools/tcptracer.py を利用して、TCPのコネクションをトレースしていきます。以下のようにPythonのファイルを実行します。(-t はタイムスタンプを表示するためのオプションです。)

プロセスごとのTCPコネクションの状態を確認することができました。T列のC,A,Xはそれぞれはシステムコールのconnect(), accept(), close()を示しています。

まとめ

BPFはプログラマブルでかつ、Linuxのさまざまな箇所にアタッチすることができるため、カーネルの動作を柔軟にトレースできます。また、BPFを容易に扱う手段としてBCCがあります。

参考

Software engineer