Ubuntu18.04 でbcc, bpftraceを動かす
最近流行りのeBPFを研究でつかっている?のですが、せっかくなので使い方のメモを公開しておこうと思います。
OSのセットアップ
タイトルにもあるようにUbuntu18.04を使います。
bpfは最近流行っていることもあり、新しいバージョンのカーネルでないと使えない機能もあります。
せっかくなのでカーネルのバージョンを新しいものに上げておきましょう。
また、ヘッダーも必要なので、合わせてインストールしておきます。
sudo sed -i.bak -e "s%http://archive.ubuntu.com/ubuntu/%http://ftp.iij.ad.jp/pub/linux/ubuntu/archive/%g" /etc/apt/sources.list sudo apt update LATEST_KERNEL_IMAGE=$(apt search linux-image- 2>/dev/null |egrep '^linux-image-[45].*-generic' |cut -d'/' -f1 | tail -n -1) LATEST_KERNEL_HEADER=$(apt search linux-headers- 2>/dev/null |egrep '^linux-headers-[45].*-generic' |cut -d'/' -f1 | tail -n -1) sudo apt install -y $LATEST_KERNEL_HEADER $LATEST_KERNEL_IMAGE sudo reboot
bcc
bccはbpf用のツールチェーンです。
特に、pythonモジュールを使うことで、かんたんにBPFのプログラムを動かすことができます。
Ubuntu 18.04では、aptを使えばbcc自体は入るのですが、
aptで入るbccはライブラリの依存の関係でbpftraceには使えないので、bcc自体も自分でビルドします。
基本的には公式のリポジトリの説明のとおりですが、python3で使いたいので
cmake
の際に-DPYTHON_CMD=python3
を足します。
$ cd ~ $ sudo apt-get -y install bison build-essential cmake flex git libedit-dev \ libllvm6.0 llvm-6.0-dev libclang-6.0-dev python zlib1g-dev libelf-dev $ git clone https://github.com/iovisor/bcc.git $ mkdir bcc/build; cd bcc/build $ cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DPYTHON_CMD=python3 $ make -j4 $ sudo make install
これでインストールは完了です。
早速動かしてみましょう。
cd ..
$ sudo python3 examples/hello_world.py
多分これだけだと何も表示されないはずです。
それもそのはず、このpythonのプログラムは以下のようにcloneが呼ばれたらHello, World!
を出力する仕様になっています。
code = ''' int kprobe__sys_clone(void *ctx) { bpf_trace_printk("Hello, World!\\n"); return 0; } ''' BPF(text=code).trace_print()
というわけで、別端末等で適当にコマンドを実行してみましょう。
(シェルのbuiltinだとcloneが実行されない場合があるので、注意)
こんな感じで出力されるはずです。
b' bash-1048 [000] .... 2985.061252: 0: Hello, World!' b' bash-1048 [000] .... 2987.416850: 0: Hello, World!'
余談ですが、python3ではなく2系で実行したらb' 'とは表示されませんでした。
python3対応が遅れてるみたいですね(涙)
なお、このブログを書いている時は Vagrantで試しているせいか引っかからなかったですが、
実機で試したときは
# echo 1 > /proc/sys/kernel/sysrq # echo x > /proc/sysrq-trigger
としなければ動きませんでした。
このあたりの問題は FAQにまとめてあるので、 動かなかったら見てみると良いでしょう。
また、もしかすると、ライブラリを認識させるために、sudo ldconfig
を実行する必要があるかもしれません。
bccの使い方についての説明は今回は省略します。
bpftrace
Dtrace や SystemTapのようなツールです。
カーネル内部にさくっとフックを仕込んでトレースしたい場合に便利なツールです。
(カーネル内部だけでなく、ユーザー空間にフックを仕込むとう、幅広い使い方ができます。)
$ sudo apt update $ sudo apt install -y bison cmake flex g++ git libelf-dev zlib1g-dev libfl-dev systemtap-sdt-dev \ llvm-7-dev llvm-7-runtime libclang-7-dev clang-7 $ git clone https://github.com/iovisor/bpftrace $ mkdir bpftrace/build; cd bpftrace/build; $ cmake -DCMAKE_BUILD_TYPE=Release .. $ make -j4 $ sudo make install
さて、実行してみます。
(このプログラムは自分で終了する必要があります。数秒立ったらCtrl+Cで止めましょう。 実際の出力が出るまで少し時間がかかるかもしれません。)
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_* { @[probe] = count(); }' Attaching 332 probes... ^C @[tracepoint:syscalls:sys_enter_getsockname]: 1 @[tracepoint:syscalls:sys_enter_prctl]: 1 @[tracepoint:syscalls:sys_enter_adjtimex]: 1 @[tracepoint:syscalls:sys_enter_rename]: 1 @[tracepoint:syscalls:sys_enter_bind]: 1 @[tracepoint:syscalls:sys_enter_clone]: 1 @[tracepoint:syscalls:sys_enter_fchmod]: 1 @[tracepoint:syscalls:sys_enter_kill]: 1 @[tracepoint:syscalls:sys_enter_epoll_create1]: 1 @[tracepoint:syscalls:sys_enter_lseek]: 1 @[tracepoint:syscalls:sys_enter_exit_group]: 1 @[tracepoint:syscalls:sys_enter_rt_sigreturn]: 2 @[tracepoint:syscalls:sys_enter_getdents]: 2 @[tracepoint:syscalls:sys_enter_epoll_ctl]: 2 @[tracepoint:syscalls:sys_enter_socket]: 2 @[tracepoint:syscalls:sys_enter_write]: 3 @[tracepoint:syscalls:sys_enter_newlstat]: 3 @[tracepoint:syscalls:sys_enter_getpid]: 3 @[tracepoint:syscalls:sys_enter_getrandom]: 3 @[tracepoint:syscalls:sys_enter_readlinkat]: 3 @[tracepoint:syscalls:sys_enter_poll]: 4 @[tracepoint:syscalls:sys_enter_select]: 4 @[tracepoint:syscalls:sys_enter_futex]: 5 @[tracepoint:syscalls:sys_enter_munmap]: 5 @[tracepoint:syscalls:sys_enter_sendmsg]: 5 @[tracepoint:syscalls:sys_enter_inotify_add_watch]: 8 @[tracepoint:syscalls:sys_enter_access]: 9 @[tracepoint:syscalls:sys_enter_rt_sigprocmask]: 10 @[tracepoint:syscalls:sys_enter_recvmsg]: 11 @[tracepoint:syscalls:sys_enter_fcntl]: 12 @[tracepoint:syscalls:sys_enter_alarm]: 15 @[tracepoint:syscalls:sys_enter_rt_sigaction]: 20 @[tracepoint:syscalls:sys_enter_newfstat]: 30 @[tracepoint:syscalls:sys_enter_newstat]: 31 @[tracepoint:syscalls:sys_enter_epoll_wait]: 39 @[tracepoint:syscalls:sys_enter_read]: 148 @[tracepoint:syscalls:sys_enter_perf_event_open]: 150 @[tracepoint:syscalls:sys_enter_dup]: 302 @[tracepoint:syscalls:sys_enter_bpf]: 322 @[tracepoint:syscalls:sys_enter_openat]: 347 @[tracepoint:syscalls:sys_enter_ioctl]: 565 @[tracepoint:syscalls:sys_enter_dup2]: 602 @[tracepoint:syscalls:sys_enter_close]: 1029
ちゃんと動きました。
本記事はこれで終わり。
probeにも色々な種類があり、使い方に癖があったりするので、
その気になったらまた記事にするかもしれません。