Unfortunately some distros don't have their accurate kernel version defined correctly in version.h due to long term support decisions. This makes LINUX_VERSION_CODE to be defined as the original upstream version in header, while the running in-kernel version is different. Older kernels might still check kern_version during bpf_prog_load(), making it impossible to load a program that could still be portable. This patch allows one to override bpf objects kern_version attributes, so program can bypass this in-kernel check during load. Example: A kernel 4.15.0-129.132, for example, might have 4.15.18 version defined in its headers, which is the kernel it is based on, but have a 4.15.0 version defined within the kernel due to other factors. $ export LIBBPF_KERN_VERSION=4.15.18 $ sudo -E ./portablebpf -v ... libbpf: bpf object: kernel_version enforced by env variable: 266002 ... This will also help portable binaries within similar older kernels, as long as they have their BTF data converted from DWARVES (for example). Signed-off-by: Rafael David Tinoco <rafaeldtinoco@xxxxxxxxxx> --- src/libbpf.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/libbpf.c b/src/libbpf.c index 4dc09d3..cbc6e61 100644 --- a/src/libbpf.c +++ b/src/libbpf.c @@ -708,13 +708,19 @@ bpf_object__add_programs(struct bpf_object *obj, Elf_Data *sec_data, static __u32 get_kernel_version(void) { - __u32 major, minor, patch; struct utsname info; + __u32 major, minor, patch, ver; + char *ptr, *e = getenv("LIBBPF_KERN_VERSION"); uname(&info); - if (sscanf(info.release, "%u.%u.%u", &major, &minor, &patch) != 3) + ptr = (e != NULL) ? e : (char *) &info.release; + if (sscanf(ptr, "%u.%u.%u", &major, &minor, &patch) != 3) return 0; - return KERNEL_VERSION(major, minor, patch); + ver = KERNEL_VERSION(major, minor, patch); + if (e) + pr_debug("bpf object: kernel_version enforced by env variable: %u\n", ver); + + return ver; } static const struct btf_member * -- 2.17.1