Open lzh2nix opened 2 years ago
David 是 Docker 的核心开发者, 在社区也是比较活跃. 里面也提到两位作者将 BPF应用在了实际的工作中(David 将BPF使用在了influxDB 性能的分析, Lorenzo 使用在了security方面的应用).
200 页不到相对 Brendan Gregg 900页的大作确实是一个入门 BPF的最佳读物.
BPF’s History
大概的工作原理:
将C语言转换成字节码, 在确认安全之后load到内核中, 然后会attach到相应的 execution point 上.
BPF 的两个应用场景
BPF的核心原理就是在内核的指定 execution point 上执行指定的命令(记录/修改函数参数,返回值). 所以想要使用BPF, 就得告诉kernel 具体要执行什么函数. 下面就以一个简单的 hello world(在exec tracepoint上执行程序)来开启 BPF 之旅.
BPF 将程序分为了两部分:
指定execution point 上的的执行指令.
#include <linux/bpf.h>
#include <linux/ptrace.h>
#include <linux/version.h>
#include <bpf_helpers.h>
SEC("tracepoint/syscalls/sys_enter_execve") // 指定exec point
int bpf_prog(void *ctx) {
char msg[] = "Hello, BPF World!!!\n";
// bpf_trace_printk(msg, sizeof(msg));
int pid = bpf_get_current_pid_tgid() >> 32;
bpf_printk("Hello, world, from BPF! My PID is %d\n", pid);
return 0;
}
char _license[] SEC("license") = "GPL";
编译上面的 C 程序:
> clang -O2 -emit-llvm -I/kernel-src/tools/testing/selftests/bpf -c hello.c -o hello.ll
> llc -march=bpf -filetype=obj -o hello.o hello.ll
接下里就是将上面的编译出的hello.ll加载到内核中(使用最熟悉的golang):
package main
import (
"fmt"
"time"
"github.com/iovisor/gobpf/elf"
)
func main() {
mod := elf.NewModule("hello.o")
err := mod.Load(nil)
if err != nil {
panic(err)
}
err = mod.EnableTracepoint("tracepoint/syscalls/sys_enter_execve")
if err != nil {
panic(err)
}
for {
fmt.Println("Waiting...")
time.Sleep(10 * time.Second)
}
}
然后把这个程序跑起来, 另外开两个shell一个用来观察 /sys/kernel/debug/tracing/trace_pipe
, 另外一个做一些任意的操作就可以按到效果了.
BPF 的两大应用场景:
table of content