eBPF Talk: pwru 自己挖坑自己填
文章目录
当遇上 cilium/pwru
时,我便放弃维护自己的 skbtracer
了。
挖坑
之前,学习了 eBPF Talk: 全局变量实战指南,就打算在开源项目 GitHub cilium/pwru 上一展身手:
2023 年 2 月 4 日提了 PR,很快就被合并了。
而后 2 月 24 日有人提了个 issue:
气人的是,3 月 9 日晚上跑 ./pwru --filter-dst-ip 1.1.1.1 --output-tuple
的时候,遇到同样的问题。
既然遇上了,那就不能放过它。
分析
使用 bpf_printk()
打印日志,很快就定位出有问题的代码位置:
|
|
只有 --filter-dst-ip
or --filter-src-ip
时,这里判断的 config 就为空。
奇怪的地方就在这里,明明指定了 --filter-dst-ip
。
分析过程如下(就不详细展开了):
bpftool prog dump jited id ${PROG ID}
。bpftool prog dump xlated id ${PROG ID}
。llvm-objdump -S kprobepwru_bpfel.o
查看 BPF 指令。
发现真相:
|
|
检查 addr
的代码被编译器优化掉了。
证明:addr_empty()
有问题。
|
|
填坑
尝试填坑的过程都是泪。
- 将
union addr
改成struct addr
。 - 意识到传的实参是
cfg->saddr
时,将union addr
改成union addr *
。
以上两个尝试都失败了。
回头看看 cfg
的定义:
|
|
Emm,“天才”般的写法。
将 addr_empty()
改为:
|
|
就阔以了。
这么改动的原因,也是尝试填坑失败的原因,如下:
- 将全局变量
CFG
的一部分union addr
传给函数时,编译器认为这部分内存不是volatile
的,所以将addr_empty()
函数调用给优化掉了。 - 编译器不允许将
volatile const structc config CFG
的一部分使用指针提供给函数使用。 - 宏不是函数,不存在传参问题。
提了如下 PR 进行修复:
总结
要么不挖坑,要么挖坑的同时得有能力填坑。
发现是自己破坏了 pwru
,心里有点难过;毕竟这是大家都可以使用的软件。
还好是自己修复的,拿回了点心理补偿。
Generate better sentence of this. “I think it’s the behaviour of clang compiler. It eliminates the addr_empty()
with considering a part of global variable CFG
is not volatile. But with macro, it accesses CFG
directly.”
I believe the behavior of the Clang compiler is to eliminate the addr_empty()
function by assuming that a non-volatile portion of the global variable CFG
does not change. However, when using a macro, CFG
is accessed directly.
文章作者 Leon Hwang
上次更新 2024-03-31