那个人是我!!!

一贯以来,作为面向用户态的内核态接口,syscall 的定义是非常稳定的;变更 syscall 的接口定义是非常罕见的。

在 Alexei 的授意下,我扩展了 BPF syscall,新增了 common attributes 的支持:给非 BPF_PROG_LOAD/BPF_BTF_LOAD 增加 log 支持。

1. 扩展 BPF syscall

BPF syscall 接口定义的变更:

1
2
3
-SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
+SYSCALL_DEFINE5(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size,
+                struct bpf_common_attr __user *, uattr_common, unsigned int, size_common)

新增 2 个参数:uattr_commonsize_common,common attributes 对应的用户态指针以及指针指向的内存大小。

2. 给 BPF_MAP_CREATE 增加 common attributes 支持

在创建 map 时,syscall.c::map_create() 里有不少地方直接返回 -EINVAL,缺少对应的 log 说明。

通过 common attributes,BPF_MAP_CREATE 便有办法给那些 -EINVAL 提供 log 说明了;比如:

1
2
3
4
5
6
7
     err = bpf_obj_name_cpy(map->name, attr->map_name,
                            sizeof(attr->map_name));
-   if (err < 0)
+   if (err < 0) {
+       bpf_log(log, "Invalid map_name.\n");
         goto free_map;
+   }

有了这些 log 说明,极大地提升 map 创建失败时的用户体验。

BPF_LINK_CREATE 是一个比 BPF_MAP_CREATE 更加复杂的 BPF 子命令。

BPF_LINK_CREATE 失败时,很多时候一头雾水,难以推测是哪里出了问题。

比如,我最近修的一个 BUG: bpf: Fix abuse of kprobe_write_ctx via freplace。背景是我给 #bpfsnoop kfuncs: Add multi mode support using kprobe.{multi,session} 时,BPF_LINK_CREATE 直接返回 -EINVAL;通过修改内核,确认是 kprobe_write_ctx=true 的 prog 不允许 attach 到内核函数导致的。如果不修改内核,BPF_LINK_CREATE 是否可以直接提供 kprobe_write_ctx=true prog is not allowed to attach to kernel functions. 错误提示呢?

比如,我当初给 XDP 新增 tracepoint: bpf, xdp: Add tracepoint to xdp attaching failure。一开始的想法就是直接向用户态空间报告底层驱动提供的错误提示。如今,终于可以通过 common attributes 实现这个想法了;从而去掉这个丑陋的 tracepoint。

4. 小结

在跟 Alexei 来回拉扯的过程中,得到了一点启发:通过机制解决一系列痛点,而不是逐个痛点去解决。