eBPF Talk: trace XDP 程序
文章目录
在 XDP 程序运行起来后,特别是在生产环境中,有没有办法去观察它的运行情况呢?特别是 XDP 程序的最终结果。
将问题泛化一下,即有没有办法去 trace bpf 程序?
TL;DR 有,却没有,得看具体是那种 bpf 程序。不过,trace XDP 程序是可以的。
- eBPF Talk: trace XDP 程序
- eBPF Talk: trace tc-bpf 程序
- eBPF Talk: trace bpf2bpf 函数调用
- eBPF Talk: trace freplace 程序
- eBPF Talk: trace tailcall 程序?NO!
- eBPF Talk: trace kprobe 程序
- eBPF Talk: trace tracepoint 程序
trace XDP 程序的 demo
demo 效果如下:
|
|
其中使用的 trace 手段是 fentry
和 fexit
。
demo 使用的 bpf 代码如下:
|
|
对下面 XDP 程序进行 trace 的时候,
|
|
用户态的 Go 代码需要做的事情是:
|
|
- 第一步,创建 XDP 程序。
- 第二步,给
fentry
和fexit
程序指定AttachTarget
和AttachTo
。 - 其中,
AttachTarget
是 XDP 程序,AttachTo
是 XDP 程序中的函数名。 - 即,将
fentry
和fexit
程序 attach 到 XDP 程序的dummy
函数上。
P.S. demo 源代码:GitHub Asphaltt/learn-by-example/ebpf/fentry_fexit-xdp
fentry
/fexit
的函数参数
仔细对比上面 fentry
/fexit
的函数定义和 XDP 程序的函数定义:
|
|
为什么 fentry
/fexit
的函数参数是 struct xdp_buff *xdp
,而 XDP 程序的函数参数是 struct xdp_md *ctx
呢?
fentry
/fexit
的函数参数里不能再使用 ctx
这是因为 BPF_PROG()
宏里已默认提供了 ctx
参数,所以不能再使用 ctx
参数名了。
|
|
fentry
/fexit
的函数参数类型用的是 struct xdp_buff *
而不是 struct xdp_md *
在理解了 fentry
/fexit
的实现原理后,就知道 fentry
/fexit
程序接受的参数是目标函数真实的参数,而非 XDP 程序所使用的参数。
所以,fentry
/fexit
程序的目标函数是 XDP 程序里的入口函数时,fentry
/fexit
程序接受的参数是 struct xdp_buff *
。
|
|
运行 XDP 程序时传的参数是 struct xdp_buff *xdp
。
XDP 程序的入参为什么是 struct xdp_md *
?
其实,这是一个约定,约定 XDP 程序的参数是 struct xdp_md *
。而在运行的时候,从实参中读取对应的属性。
|
|
那么,运行的时候是怎么从实参中读取对应的属性呢?
真实情况是,在 verifier 阶段,就会将 struct xdp_md *
的属性访问替换成对应的 struct xdp_buff *
的属性访问。
|
|
小结
fentry
/fexit
的函数参数是目标函数真实的参数,而非 XDP 程序所使用的参数。fexit
能够获取到目标函数的返回值,即 XDP 程序的返回值。- XDP 程序的入参为什么是
struct xdp_md *
?这是一个约定,约定 XDP 程序的参数是struct xdp_md *
。 - 在 verifier 阶段,就会将
struct xdp_md *
的属性访问替换成对应的struct xdp_buff *
的属性访问。
看到 xdp_verifier_ops
,不枉我对 bpf verifier 的一番探索。
文章作者 Leon Hwang
上次更新 2024-04-04