Linux eBPF 监控与调试实践

1次阅读

bpf_trace_printk 生产环境禁用,因限频1024次/秒、触发vprintk导致延迟和加载失败;应改用bpf_perf_event_output;其格式串上限128字节且不报错;bpf_probe_read_kernel需检查返回值并用btf/co-re避免硬编码偏移。

Linux eBPF 监控与调试实践

为什么 bpf_trace_printk 在生产环境几乎没用

它会把日志打到内核 ring buffer,但默认只允许每秒最多 1024 次调用,超了就静默丢弃;更关键的是,它会强制触发内核的 vprintk 路径,带来不可控延迟,eBPF 程序可能被内核直接拒绝加载(报错 invalid bpf_context accesstoo many instructions)。真正上线必须换路。

  • 调试阶段可用,但建议加条件:只在特定 PID、特定函数入口打一次,比如 if (pid == target_pid && !printed) { bpf_trace_printk(...); printed = 1; }
  • 生产环境一律改用 bpf_perf_event_output + 用户态 perf_event_open 读取,吞吐高、可控性强
  • 注意 bpf_trace_printk 的格式字符串长度上限是 128 字节(含终止符),超长截断不报错,容易漏信息

bpf_probe_read_kernel 读内核结构体总 panic?

不是函数写错了,是没判断地址有效性。eBPF 不允许直接解引用任意指针bpf_probe_read_kernel 只负责“尝试拷贝”,但若源地址根本不在当前上下文可访问的内核内存页上(比如进程已退出、模块卸载、或字段偏移随内核版本变化),就会触发 -EFAULT,而你没检查返回值——程序继续往下跑,访问未初始化内存,最终触发 verifier 拒绝或运行时 crash。

  • 每次调用后必须检查返回值:if (bpf_probe_read_kernel(&val, sizeof(val), &src->field) != 0) return 0;
  • 别硬编码结构体偏移,优先用 BTF(如 bpftool btf dump 查)或 libbpfbpf_object__find_map_by_name + CO-RE
  • 对链表遍历类操作(如遍历 task_struct->children),务必限制最大循环次数(比如 for (int i = 0; i ),否则 verifier 会因无法验证循环边界而拒绝加载

tc exec bpf 加载后没流量经过?

最常见原因是挂载点(ingress/egress)和网络命名空间不匹配。eBPF 程序绑定在某个 netns 的某块网卡上,但你的测试流量根本没走那条路径——比如容器里跑的程序,实际出口是 veth peer,而不是宿主机 eth0。

  • 先确认目标接口是否启用:运行 ip link show dev <code>ens3,看 state 是否为 UP
  • tc qdisc show dev <code>ens3 检查是否真挂上了,输出应包含 bpf 和对应 prog id
  • 如果绑的是 ingress,注意:ingress qdisc 是逻辑设备,不处理本地生成包(即本机 curl 自己不算),只处理进入该接口的外部流量
  • 抓包交叉验证:tcpdump -i <code>ens3 port 80 看是否有原始流量,再对比 eBPF 输出,才能确定是没触发还是逻辑写错了

为什么 libbpf 加载失败,报 failed to load program: Permission denied

不是权限不够,而是内核配置没开全。现代发行版(尤其是 RHEL/centos 8+、ubuntu 20.04+)默认禁用部分 eBPF 功能,或者启用了 lockdown mode,导致即使 root 也无法加载某些类型的程序。

  • 检查 /proc/sys/kernel/unprivileged_bpf_disabled:值为 2 表示完全禁止非特权加载(包括 root),需设为 01(后者仅限 root)
  • 确认内核编译选项:CONFIG_BPF_SYSCALL=yCONFIG_BPF_JIT=yCONFIG_HAVE_EBPF_JIT 必须启用;若用 tracepoint,还需 CONFIG_TRACING
  • Secure Boot 启用时,部分系统(如 Fedora)会强制 kernel lockdown,此时需临时关掉:sudo mokutil --disable-validation(重启生效)

CO-RE 和 BTF 是现在绕过内核版本碎片的唯一靠谱路径,但前提是目标机器有完整 BTF 信息——别信 /usr/lib/debug 下的 vmlinux,得用 bpftool btf dump file /sys/kernel/btf/vmlinux format c 验证能否成功解析。

text=ZqhQzanResources