bobuhiro11's diary

Linux Observability with BPF 読書メモ

14 Dec 2019

Linux Observability with BPFを読んだので、メモしておく。 今月、Brendan Gregg氏のBPF本も出るので、 それも読みたいな。

# SHELL
# BPFプログラムをELFバイナリへコンパイル
clang -O2 -target bpf -c bpf_program.c -o bpf_program.o

# BPF用仮想FSのマウント
mount -t bpf /sys/fs/bpf /sys/fs/bpf

# USDTの確認
tplist -l ./hello_usdt

# スタックトレースの取得とflamegraphの作成
./profiler.py `pgrep -nx go` > /tmp/profile.out
./flamegraph.pl /tmp/profile.out > /tmp/flamegraph.svg

# kubectl-traceの実行例
kubectl trace run pod/pod_identifier -n application_name -e <<PROGRAM
  uretprobe:/proc/$container_pid/exe:"main.main" {
    printf("exit: %d\n", retval)
  }
PROGRAM

# XDP BPFプログラムのロード
# native mode がダメなら、generic mode で動く。強制することもできる
ip link set dev eth0 xdp obj program.o sec mysection
// C
// bpf syscall でBPFマップを作成
int fd = bpf(BPF_MAP_REATE, &my_map, sizeof(my_map));

// bpf map 一覧取得
int next_key, lookup_key;  = -1;
while (bpf_map_get_next\key(map_data[0].fd, &lookup_key, &next_key) == 0) {
  printf("The next key in the map: %d\n", next_key);
  lookup_key = next_key;
}
# BCC (python)
from bcc import BPF

# kprobesの例
bpf_source = """
int do_sys_execve(struct pt_regs *ctx, void filename, void argv, void envp) {
  char comm[16];
  bpf_get_current_comm(&comm, sizeof(comm));
  bpf_trace_printk("executing program: %s", comm);
  return 0;
}
"""
bpf = BPF(text = bpf_source)
execve_function = bpf.get_syscall_fnname("execve")
bpf.attach_kprobe(event = execve_function, fn_name = "do_sys_execve")
bpf.trace_print()

# tracepointの例
bpf_source = """
int trace_bpf_prog_load(void ctx) {
  char comm[16];
  bpf_get_current_comm(&comm, sizeof(comm));
  bpf_trace_printk("%s is loading a BPF program", comm);
  return 0;
}
"""
bpf = BPF(text = bpf_source)
bpf.attach_tracepoint(tp = "bpf:bpf_prog_load",
fn_name = "trace_bpf_prog_load")
bpf.trace_print()

# uprobesの例
bpf_source = """
int trace_go_main(struct pt_regs *ctx) {
  u64 pid = bpf_get_current_pid_tgid();
  bpf_trace_printk("New hello-bpf process running with PID: %d", pid);
}
"""
bpf = BPF(text = bpf_source)
bpf.attach_uprobe(name = "hello-bpf",
sym = "main.main", fn_name = "trace_go_main")
bpf.trace_print()

# USDTの例
from bcc import BPF, USDT
bpf_source = """
#include <uapi/linux/ptrace.h>
int trace_binary_exec(struct pt_regs *ctx) {
  u64 pid = bpf_get_current_pid_tgid();
  bpf_trace_printk("New hello_usdt process running with PID: %d", pid);
}
"""
usdt = USDT(path = "./hello_usdt")
usdt.enable_probe(probe = "probe-main", fn_name = "trace_binary_exec")
bpf = BPF(text = bpf_source, usdt = usdt)
bpf.trace_print()
# BPFTrace のDSL
# bpftrace /tmp/examble.bt で実行
BEGIN
{
  printf("starting BPFTrace program\n")
}
kprobe:do_sys_open
{
  printf("opening file descriptor: %s\n", str(arg1))
  @opens[str(arg1)] = count()
}
END
{
  printf("exiting BPFTrace program\n")
}

comments powered by Disqus < Kubernetes完全ガイド 読書メモ