bcc实战开发eBPF程序

ebpf 开发实战

环境搭建

大部分是 follow from 官方教程

https://github.com/iovisor/bcc/blob/master/INSTALL.md#ubuntu---binary

1
2
3
4
5
6
# 但是域名repo.iovisor.org 可能证书过期
# ubuntu 下最简单的方案: 忽略证书过期
# copy from bcc:issue [ https://github.com/iovisor/bcc/issues/3724#issuecomment-1021618465]
cat /etc/apt/apt.conf.d/io
Acquire::https::repo.iovisor.org::Verify-Peer "false";
Acquire::https::repo.iovisor.org::Verify-Host "false";
1
2
3
4
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4052245BD4284CDD
echo "deb https://repo.iovisor.org/apt/$(lsb_release -cs) $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/iovisor.list
sudo apt-get update
sudo apt-get install bcc-tools libbcc-examples linux-headers-$(uname -r)

脚本开发

需求

打印所有进程,已经读取的文件

例如 某个进程正在使用的配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# coding = utf-8
from bcc import BPF

# define BPF program (""" is used for multi-line string).
# '#' indicates comments for python, while '//' indicates comments for C.
# process event
start = 0

prog = """
#include <uapi/linux/ptrace.h>
#include <uapi/linux/limits.h>
#include <linux/sched.h>
// define output data structure in C
struct data_t
{
u32 pid;
u64 ts;
char comm[TASK_COMM_LEN];
char fname[NAME_MAX];
};
BPF_PERF_OUTPUT(events);
// define the handler for do_sys_open.
// ctx is required, while other params depends on traced function.
int hello(struct pt_regs *ctx, int dfd, const char __user *filename, int flags)
{
struct data_t data = {};
data.pid = bpf_get_current_pid_tgid();
data.ts = bpf_ktime_get_ns();
if (bpf_get_current_comm(&data.comm, sizeof(data.comm)) == 0)
{
bpf_probe_read(&data.fname, sizeof(data.fname), (void *)filename);
}
events.perf_submit(ctx, &data, sizeof(data));
return 0;}
"""
# load BPF program
b = BPF(text=prog)
# attach the kprobe for do_sys_open, and set handler to hello
b.attach_kprobe(event="do_sys_open", fn_name="hello")


def print_event(cpu, data, size):
global start

time_s = 0
event = b["events"].event(data)
if start == 0:
start = event.ts
time_s = (float(event.ts - start)) / 1000000000
print("%-18.9f %-16s %-6d %-16s" % (time_s, event.comm, event.pid, event.fname))

# loop with callback to print_event
b["events"].open_perf_buffer(print_event)

# print header
print("%-18s %-16s %-6s %-16s" % ("TIME(s)", "COMM", "PID", "FILE"))
# start the event polling loop
while 1:
try:
b.perf_buffer_poll()
except KeyboardInterrupt:
exit()
# b.perf_buffer_poll()


效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
TIME(s)            COMM             PID    FILE            
0.000000000 trojan 2918 /proc/net/dev
0.000000000 python 12851 /usr/lib/python2.7/encodings/ascii.x86_64-linux-gnu.so
0.000000000 python 12851 /usr/lib/python2.7/encodings/ascii.so
0.000000000 python 12851 /usr/lib/python2.7/encodings/asciimodule.so
0.000000000 python 12851 /usr/lib/python2.7/encodings/ascii.py
0.000000000 python 12851 /usr/lib/python2.7/encodings/ascii.pyc
0.000000000 trojan 2918 /proc/net/dev
0.000000000 trojan 2918 /proc/net/dev
0.000000000 irqbalance 234 /proc/interrupts
0.000000000 irqbalance 234 /proc/stat
0.000000000 irqbalance 234 /proc/irq/11/smp_affinity
0.000000000 irqbalance 234 /proc/irq/9/smp_affinity
0.000000000 trojan 2918 /proc/net/dev