背景
eBPFに興味はあったもののそれとなくしか理解してなかったのでせっかくなので概要だけでも掴もうと思って書く記事。とりあえず概要とかとよく読むカーネル関数とかをattachしてみて引数を見るみたいなのまでやってみました。
(私の事前の知識レベルとしては「eBPFを使えば、システムコール、パケットの受信など、カーネルで発生する様々なイベントに対して動かしたいコードを動かして遊べる機能だ!」くらいの感じで始めました)
eBPFとは
eBPF(extended Berkeley Packet Filter)とは任意の様々なタイミングでバイトコードを実行できるLinuxカーネルの機能です(BPFはLinux3.15に最初に追加された新機能)。カーネルのソースコードを変更したり、カーネルモジュールをロードしたりすることなく、カーネルの機能を安全かつ効率的に拡張するために使用されたりする(独自の命令セット を持つカーネル内部の仮想マシン上で実行できる機能)。カーネル自体に手を入れることや、kprobeを利用するカーネルモジュールを書くことに比べ遥かに簡単に追うことができたりするという印象を持ちました。
ユーザが定義したプログラムをカーネルランドで実行するための仕組みで。パフォーマンスの計測、セキュリティ、ネットワーク処理などの利用用途があります
また、BPF Compiler Collection (BCC)という、eBPFプログラムの作成や実行を手助けしてくれる便利なツールキットがあります。(ちなみにBCCが使用するものの多くは、Linux4.1以降を必要とするのでCentOS7をそのまま使うのは若干厳しいのでカーネルを上げるなり違うディストロを用意するなどが必要です)
Brendan Gregg's Blogでの言及もとても面白かったです。
学ぶ順番も記されており
- bcc/tutorial.md at master · iovisor/bcc · GitHub
- bpftrace/tutorial_one_liners.md at master · iovisor/bpftrace · GitHub
あたりを行なっていきます。
BPF
歴史的にeBPFの前にBPFがあるとのことですが今はeBPFのことを「BPF」古いBPFのことを「cBPF」と呼ぶことが多いらしいです。BPFの初版はwikiを見てたらなんと 1992年12月とのこと。(年上だったとは...!!!)
BPFのドキュメントは以下。BPF設計Q&Aは見ておいても良いかもと思った。(が、見れていないので後で見る)
eBPF Foundation
Linux Foundationをスポンサーとした、eBPFプロジェクトのための「eBPF Foundation」という団体もあるらしい。Facebook、Google、Isovalent、Microsoft、Netflixという名だたる企業が並んでいる。
昨年はeBPF Summitというイベントも開催されていたらしい。(界隈の盛り上がりをとても感じる。)、eBPFのいくつかの主要なユースケースとして、可観測性、負荷分散の話なんかがされていた模様。
使っていく
環境構築は以下の記事を参考にBCCでeBPFのコードを書いていく感じで進める。
何はともあれhello worldをやってみる。
#!/usr/bin/python3 from bcc import BPF bpf_text = """ int trace_sys_clone(struct pt_regs *ctx) { bpf_trace_printk("Hello, World!\\n"); return 0; } """ b = BPF(text=bpf_text) b.attach_kprobe(event="__x64_sys_clone", fn_name="trace_sys_clone") b.trace_print()
カーネル内部で __x64_sys_clone
関数が呼ばれたときに、自分で定義した trace_sys_clone
関数を呼び出すという流れです。bpf_trace_printk
で中身を出力しているように見えますが実際は/sys/kernel/debug/tracing/trace_pipe
へ出力が行われていてb.trace_print()
で中身を見にいてっています。
システムコールの入口を知る: get_syscall_fnname
b = BPF(text=bpf_text) print b.get_syscall_fnname("inotify_init") # sys_inotify_init
気になるbccツール
biotop.py
block device (disk) I/O をプロセスごとに表示してくれるツール
PID COMM D MAJ MIN DISK I/O Kbytes AVGms 14501 cksum R 202 1 xvda1 361 28832 3.39 6961 dd R 202 1 xvda1 1628 13024 0.59 13855 dd R 202 1 xvda1 1627 13016 0.59 326 jbd2/xvda1-8 W 202 1 xvda1 3 168 3.00 1880 supervise W 202 1 xvda1 2 8 6.71 1873 supervise W 202 1 xvda1 2 8 2.51 1871 supervise W 202 1 xvda1 2 8 1.57 1876 supervise W 202 1 xvda1 2 8 1.22 1892 supervise W 202 1 xvda1 2 8 0.62 1878 supervise W 202 1 xvda1 2 8 0.78 1886 supervise W 202 1 xvda1 2 8 1.30 1894 supervise W 202 1 xvda1 2 8 3.46 1869 supervise W 202 1 xvda1 2 8 0.73 1888 supervise W 202 1 xvda1 2 8 1.48
cachetop.py
読み取りを含むLinuxページキャッシュのヒット/ミス統計を表示するツール。異常に高い数値が出てるかどうかはすぐにでも見れそうなツール
13:01:01 Buffers MB: 76 / Cached MB: 114 / Sort: HITS / Order: ascending PID UID CMD HITS MISSES DIRTIES READ_HIT% WRITE_HIT% 1 root systemd 2 0 0 100.0% 0.0% 680 root vminfo 3 4 2 14.3% 42.9% 567 syslog rs:main Q:Reg 10 4 2 57.1% 21.4% 986 root kworker/u2:2 10 2457 4 0.2% 99.5% 988 root kworker/u2:2 10 9 4 31.6% 36.8% 877 vagrant systemd 18 4 2 72.7% 13.6% 983 root python 148 3 143 3.3% 1.3% 981 root strace 419 3 143 65.4% 0.5% 544 messageb dbus-daemon 455 371 454 0.1% 0.4% 243 root jbd2/dm-0-8 457 371 454 0.4% 0.4% 985 root (mount) 560 2457 4 18.4% 81.4% 987 root systemd-udevd 566 9 4 97.7% 1.2% 988 root systemd-cgroups 569 9 4 97.8% 1.2% 986 root modprobe 578 9 4 97.8% 1.2% 287 root systemd-journal 598 371 454 14.9% 0.3% 985 root mount 692 2457 4 21.8% 78.0% 984 vagrant find 9529 2457 4 79.5% 20.5%
cpudist.py
タスクごとのオンCPU時間をヒストグラムとして表示するツール
Tracing on-CPU time... Hit Ctrl-C to end. ^C usecs : count distribution 0 -> 1 : 0 | | 2 -> 3 : 1 | | 4 -> 7 : 1 | | 8 -> 15 : 13 |** | 16 -> 31 : 187 |****************************************| 32 -> 63 : 89 |******************* | 64 -> 127 : 26 |***** | 128 -> 255 : 0 | | 256 -> 511 : 1 | |
vfscount.py
vfs_*の関数ごとのコール数を表示
ADDR FUNC COUNT ffffffff87325781 b'vfs_symlink' 1 ffffffff8739f971 b'vfs_test_lock' 2 ffffffff87351fd1 b'vfs_fsync_range' 2 ffffffff87354d21 b'vfs_statfs' 3 ffffffff87323871 b'vfs_rename' 3 ffffffff87325aa1 b'vfs_mkdir' 4 ffffffff87323561 b'vfs_unlink' 4 ffffffff873287b1 b'vfs_readlink' 15 ffffffff8731a671 b'vfs_fstat' 260 ffffffff87310c61 b'vfs_open' 330 ffffffff873124b1 b'vfs_write' 404 ffffffff87319601 b'vfs_statx' 491 ffffffff873a1261 b'vfs_lock_file' 523 ffffffff873195b1 b'vfs_getattr' 594 ffffffff873194f1 b'vfs_getattr_nosec' 594 ffffffff87312201 b'vfs_read' 1304
vfsstat.py
vfscountをvmstatみたいに表示してくれるツール
TIME READ/s WRITE/s FSYNC/s OPEN/s CREATE/s 22:52:16: 813 372 0 66 0 22:52:17: 41 42 0 13 0 22:52:18: 3 2 0 0 0 22:52:19: 23 7 0 8 0 22:52:20: 5 6 0 0 0
memleak.py
解放されなかった未処理のメモリ割り当てをトレースツール
Attaching to pid 5193, Ctrl+C to quit. [11:16:33] Top 2 stacks with outstanding allocations: addr = 948cd0 size = 16 addr = 948d10 size = 16 addr = 948d30 size = 16 addr = 948cf0 size = 16 64 bytes in 4 allocations from stack main+0x6d [allocs] __libc_start_main+0xf0 [libc-2.21.so]
libbpf
bccで抱える課題を解決するべく「libbpf + BPF CO-RE」という開発環境が今後は主流になるらしい。bccのツールの書き換えも実施されていて今後の動向は見守っていく必要がありそう。ただ現段階では私はbccでさっとかけるくらいで良いので方向変えたりはもう少ししばらくはしない。(ポータビリティとかバイナリサイズが減ったりランタイムオーバーヘッドが減るなどのメリットが挙げられている)
bccもある程度触ったらlibbpfgoかrustに入門して触り始めるかしても良いのだろうかな(この辺はよくわかってないので別途検討)
用途とか実例とか
いろんな会社で実例があったので読んだものとか気になってるものをメモ。
- LINE
- eXpress Data Path (XDP) の概要とLINEにおける利活用
- 独自パケット処理の実装を行なっている
- Netflix
- CloudFlare
- Microsoft
ファイアウォール、デバイスドライバー、ネットワークパフォーマンス監視などなど色々な文脈で登場する技術のようです。
Cilium
Cilium は、コンテナ ワークロードのスケーラビリティ、セキュリティ、可視性に関する新たな要件に対応するため、eBPF を基礎として設計されたオープンソース プロジェクト。
おまけ
/sys/kernel/debug/kprobes/list
/sys/kernel/debug/kprobes/list
を見るとsystem :: probeに登録されているすべてのプローブを一覧表示することができます。
cat /sys/kernel/debug/kprobes/list ffffffffaa8af6d0 k tcp_init_sock+0x0 [FTRACE] ffffffffaa3cb990 k do_writepages+0x0 [FTRACE]
参考記事
- Learn eBPF Tracing: Tutorial and Examples
- eBPFによるパフォーマンス分析 - Qiita
- eBPF の紹介 - Qiita
- eBPFでお手軽?ファジング|ラック・セキュリティごった煮ブログ編集部|note
- eBPF入門
- 第688回 eBPFのコンパイラーに対応したツールでさまざまな挙動を可視化する:Ubuntu Weekly Recipe|gihyo.jp … 技術評論社
- eBPFとは何か、なぜそれがオブザーバビリティに関係するのか? | New Relic
- eBPFとSysdigによるコンテナーの可観測性について | eBPF | Sysdigブログ | コンテナ・Kubernetes環境向けセキュリティ・モニタリング プラットフォーム
- BPF(bcc)のメモ
- Linux 5.5におけるBPF(Berkeley Packet Filter)の新機能:Berkeley Packet Filter(BPF)入門(7) - @IT