たまには「〜話」メソッドでブログを書く。あと6月は二回ブログを書けたのでめでたい。
さて、タイトルのようなことをしています。
前提としてeBPFという、カーネル内で動く特定の目的のプログラムを比較的高速・安全に書くための技術があるのですが、そのプログラムはバイトコードベースなので、eBPFを扱うプログラムをもう少し人間的な形式で書きたくなります。せめてC言語とか。そのためのコンパイラがlibbccです。
大きくはkprobe、uprobe、kernel tracepointといったカーネルイベントのトレースをしたり、XDPというネットワーク周りのトレースをしたり挙動を変更する処理を書くことができたりします。
以下の記事が詳しいと思います。
知人の id:mrtc0 さんという人がeBPF関係の中でもUSDTという、プログラムの任意の箇所に任意のプローブ(もともと探針、みたいな意味ですね)を埋め込む(それも元のプログラムへ影響を最小限にして埋め込める)機能があるのですが、その検証をしていたりします。
今回、mrubyでその範囲の機能だけでもポートできた気がするので紹介します。
まずmrubyのプログラムにUSDT Probeを埋め込むためのmrbgemを作ってます。
exampleにもあるんですがこういうコードを書くと、とりあえずprobeを送り込めます。このmruby側のAPIは仮なので変えるかもですが...。
puts Process.pid i = 0 loop do Probe.probe(i) i += 1 sleep 1 end
これを起動しておく。
$ ./mruby/bin/mruby example/probe.rb 19975
つづいて、mruby-bccというmrbgemを利用して、こういうコードを書きました。
pid = ARGV[0] bpf_text = <<CLANG #include <uapi/linux/ptrace.h> int do_trace(struct pt_regs *ctx) { long buf, tgt; bpf_usdt_readarg(1, ctx, &buf); bpf_probe_read(&tgt, sizeof(tgt), (void *)&buf); bpf_trace_printk("%ld\\n", tgt); return 0; }; CLANG u = BCC::USDT.new(pid: pid.to_i) u.enable_probe(probe: "mruby", fn_name: "do_trace") b = BCC::BPF.new(text: bpf_text, usdt_context: u) printf("%-18s %-16s %-6s %s\n", "TIME(s)", "COMM", "PID", "mruby-probe") b.trace_fields do |task, pid, cpu, flags, ts, msg| printf("%-18.9f %-16s %-6d %s", ts, task, pid, msg) end
このコード、分かると思いますが、Python版(標準添付)のbccラッパーのAPIを強く意識したものに、敢えてしています。
これを特権ありで実行すると、さっき起動したmruby-probeのプログラムから随時送られてくるprobeをトレースして表示できるようになります。
$ sudo ./mruby/bin/mruby example/usdt.rb 19975 TIME(s) COMM PID mruby-probe 82312.907943000 mruby 19975 16 82313.908693000 mruby 19975 17 82314.918178000 mruby 19975 18 82315.918618000 mruby 19975 19 82316.919467000 mruby 19975 20 82317.928667000 mruby 19975 21 82318.938109000 mruby 19975 22 82319.948643000 mruby 19975 23 82320.949394000 mruby 19975 24 82321.950322000 mruby 19975 25 82322.951750000 mruby 19975 26
ひとまず USDT/uprobe に対応していますが、kprobeなども同じように対応できるはずなので、徐々にPython側のコードを見ながらポートしていく予定。そもそも、eBPFで何ができるかの全貌がまだわかっていないので、勉強しながら。
あと、コードを見ると分かるとおり最終的なエンドポイントが全てCになっているのでそこもなんとか整理したい。
そういう感じでeBPFやっていきましょう。