On 5/4/23 4:09 AM, Menglong Dong wrote:
Hello, I find that it's not supported yet to check if the bpf features are supported by the target kernel in the BPF program, which makes it hard to keep the BPF program compatible with different kernel versions. For example, I want to use the helper bpf_jiffies64(), but I am not sure if it is supported by the target, as my program can run in kernel 5.4 or kernel 5.10. Therefore, I have to compile two versions BPF elf and load one of them according to the current kernel version. The part of BPF program can be this: #ifdef BPF_FEATS_JIFFIES64 jiffies = bpf_jiffies64(); #else jiffies = 0; #endif And I will generate xxx_no_jiffies.skel.h and xxx_jiffies.skel.h with -DBPF_FEATS_JIFFIES64 or not. This method is too silly, as I have to compile 8(2*2*2) versions of the BPF program if I am not sure if 3 bpf helpers are supported by the target kernel. Therefore, I think it may be helpful if we can check if the helpers are support like this: if (bpf_core_helper_exist(bpf_jiffies64)) jiffies = bpf_jiffies64(); else jiffies = 0; And bpf_core_helper_exist() can be defined like this: #define bpf_core_helper_exist(helper) \ __builtin_preserve_helper_info(helper, BPF_HELPER_EXISTS) Besides, in order to prevent the verifier from checking the helper that is not supported, we need to remove the dead code in libbpf. As the kernel already has the ability to remove dead and nop insn, we can just make the dead insn to nop. Another option is to make the BPF program support "const value". Such const values can be rewrite before load, the dead code can be removed. For example: #define bpf_const_value __attribute__((preserve_const_value)) bpf_const_value bool is_bpf_jiffies64_supported = 0; if (is_bpf_jiffies64_supported) jiffies = bpf_jiffies64(); else jiffies = 0; The 'is_bpf_jiffies64_supported' will be compiled to an imm, and can be rewrite and relocated through libbpf by the user. Then, we can make the dead insn 'nop'.
A variant of the second approach should already work. You can do, volatile const is_bpf_jiffies64_supported; ... if (is_bpf_jiffies64_supported) jiffies = bpf_jiffies64(); else jiffies = 0; After skeleton is openned but before prog load, you can do a probe into the kernel to find whether the helper is supported or not, and set is_bpf_jiffies64_supported accordingly. After loading the program, is_bpf_jiffies64_supported will be changed to 0/1, verifier will do dead code elimination properly.
What do you think? I'm not sure if these methods work and want to get some advice before coding. Thanks! Menglong Dong