近来,没怎么学习 eBPF,就给 pwru
做下贡献。
- Replace objs with collection
- Support tracing tc-bpf
- Support tracking skb clones
- Accelerate attaching/detaching kprobes WIP
Replace objs with collection
该 PR 重构了一下 pwru
中管理 bpf
对象的代码,将 bpf
对象的管理从 struct
改成 collection
。
因为 --backend kprobe-multi
、--output-skb
会生成多个 struct
,导致 pwru
为了兼容这些选项而生成了 getter
代码;getter
就是根据不同的选项从对应的 struct
中获取 bpf
对象。
然后,go-ebpf 库除了 bpf2go
生成 struct
之外,还提供了 collection
的方式来管理 bpf
对象。对于 pwru
动态获取 bpf
对象的需求,collection
更加适合。
使用 collection
方式后,pwru
不需要再为了兼容 --backend kprobe-mult
、--output-skb
而生成 getter
代码了,可以直接从 collection
中获取 bpf
对象。
最终,效果显著:
1
2
3
|
# git diff --stat 88ccb274abd158d7b4ec82a051bf2bdc0572fefa 6639252d68ba99600f0ec7636c75ad34f7dcf210
...
59 files changed, 14 insertions(+), 22480 deletions(-)
|
Support tracing tc-bpf
该 PR 支持了 tc-bpf
的跟踪。意即,跟踪 tc-bpf
就像其它 kprobe
一样,能够跟踪 tc-bpf
处理 skb
的事件。
效果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# ./pwru --output-limit-lines 10 --output-meta --output-tuple --filter-trace-tc --filter-func '.*udp' icmp
2023/10/21 15:22:05 Attaching kprobes (via kprobe-multi)...
1 / 1 [------------------------------------------------------------------------------------------------------------] 100.00% ? p/s
2023/10/21 15:22:05 Attached (ignored 0)
2023/10/21 15:22:05 Listening for events..
SKB CPU PROCESS FUNC
0xffff940944c67900 3 [<empty>] dummy netns=4026531840 mark=0x0 iface=2(enp0s1) proto=0x0800 mtu=1500 len=98 192.168.64.1:0->192.168.64.2:0(icmp)
0xffff940944c67c00 3 [pwru] dummy netns=4026531840 mark=0x0 iface=2(enp0s1) proto=0x0800 mtu=1500 len=98 192.168.64.1:0->192.168.64.2:0(icmp)
0xffff940944c67e00 3 [<empty>] dummy netns=4026531840 mark=0x0 iface=2(enp0s1) proto=0x0800 mtu=1500 len=98 192.168.64.1:0->192.168.64.2:0(icmp)
0xffff9408f1c97c00 3 [<empty>] dummy netns=4026531840 mark=0x0 iface=2(enp0s1) proto=0x0800 mtu=1500 len=98 192.168.64.1:0->192.168.64.2:0(icmp)
0xffff9408f1c97600 3 [<empty>] dummy netns=4026531840 mark=0x0 iface=2(enp0s1) proto=0x0800 mtu=1500 len=98 192.168.64.1:0->192.168.64.2:0(icmp)
0xffff940944c67700 3 [<empty>] dummy netns=4026531840 mark=0x0 iface=2(enp0s1) proto=0x0800 mtu=1500 len=98 192.168.64.1:0->192.168.64.2:0(icmp)
0xffff940944c67b00 3 [<empty>] dummy netns=4026531840 mark=0x0 iface=2(enp0s1) proto=0x0800 mtu=1500 len=98 192.168.64.1:0->192.168.64.2:0(icmp)
0xffff940944c67f00 3 [<empty>] dummy netns=4026531840 mark=0x0 iface=2(enp0s1) proto=0x0800 mtu=1500 len=98 192.168.64.1:0->192.168.64.2:0(icmp)
0xffff940944c67400 3 [<empty>] dummy netns=4026531840 mark=0x0 iface=2(enp0s1) proto=0x0800 mtu=1500 len=98 192.168.64.1:0->192.168.64.2:0(icmp)
0xffff940944c67900 3 [<empty>] dummy netns=4026531840 mark=0x0 iface=2(enp0s1) proto=0x0800 mtu=1500 len=98 192.168.64.1:0->192.168.64.2:0(icmp)
2023/10/21 15:22:08 Printed 10 events, exiting program..
|
其中关键的 bpf
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
SEC("fentry/tc")
int BPF_PROG(fentry_tc, struct sk_buff *skb) {
struct event_t event = {};
if (!handle_everything(skb, ctx, &event))
return BPF_OK;
event.skb_addr = (u64) skb;
event.addr = bpf_get_func_ip(ctx);
bpf_map_push_elem(&events, &event, BPF_EXIST);
return BPF_OK;
}
|
跟踪 tc-bpf
中的 skb
的参数为什么是 struct sk_buff
而不是 struct __sk_buff
呢?详情请查看 eBPF Talk: trace tc-bpf 程序。
Support tracking skb clones
该 PR 是为了支持需求 Track SKB clones,即跟踪 skb
的克隆。
只有在指定 --filter-track-skb
选项后,才会跟踪 skb
的克隆。当然,得当前内核支持 fexit
才行。
经过一番讨论后,最终决定使用 fexit
来跟踪 skb_copy()
和 skb_clone()
这两个函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
static __always_inline int
track_skb_clone(u64 old, u64 new) {
if (bpf_map_lookup_elem(&skb_addresses, &old))
bpf_map_update_elem(&skb_addresses, &new, &TRUE, BPF_ANY);
return BPF_OK;
}
SEC("fexit/skb_clone")
int BPF_PROG(fexit_skb_clone, u64 old, gfp_t mask, u64 new) {
return track_skb_clone(old, new);
}
SEC("fexit/skb_copy")
int BPF_PROG(fexit_skb_copy, u64 old, gfp_t mask, u64 new) {
return track_skb_clone(old, new);
}
|
Accelerate attaching/detaching kprobes
该 PR 还在审核中,因为 GitHub Actions 中的 bpf-next 没跑成功。
该 PR 主要是为了加速 pwru
的 kprobe
的挂载和卸载。将 kprobe
的挂载和卸载方式从串行改成并行。
并行化后,pwru
的 kprobe
的挂载和卸载的速度提升了一丢丢:
1
2
3
4
5
6
7
8
|
2023/10/25 14:16:03 Attaching kprobes (via kprobe)...
1462 / 1462 [----------------------------------------------------------------------------------------------------] 100.00% 342 p/s
2023/10/25 14:16:07 Attached (ignored 0)
2023/10/25 14:16:07 Listening for events..
SKB CPU PROCESS FUNC
^C2023/10/25 14:16:08 Received signal, exiting program..
2023/10/25 14:16:08 Detaching kprobes...
1462 / 1462 [-----------------------------------------------------------------------------------------------------] 100.00% 35 p/s
|
对比串行化的挂载和卸载:
1
2
3
4
5
6
7
8
|
2023/10/25 14:17:27 Attaching kprobes (via kprobe)...
1462 / 1462 [----------------------------------------------------------------------------------------------------] 100.00% 282 p/s
2023/10/25 14:17:32 Attached (ignored 0)
2023/10/25 14:17:32 Listening for events..
SKB CPU PROCESS FUNC
^C2023/10/25 14:17:33 Received signal, exiting program..
2023/10/25 14:17:33 Detaching kprobes...
1462 / 1462 [-----------------------------------------------------------------------------------------------------] 100.00% 21 p/s
|
当然,这是为了支持需求 Would be nice if probe unloading was faster。
Add XDP support
未来,还会支持 XDP 的跟踪。详情请查看 Add XDP support。
不过,目前 pwru
的 PR 都没有合并,因为 bpf-next GitHub Actions 没跑成功。所以,还是先等等吧。
小结
本文介绍了最近给 pwru
做的贡献,主要是重构了一下 pwru
中管理 bpf
对象的代码,支持了 tc-bpf
的跟踪,支持了跟踪 skb
的克隆,加速了 kprobe
的挂载和卸载。