On Thu, 2025-01-02 at 19:24 +0100, Jose E. Marchesi wrote: [...] > IMO the BPP selftest (and BPF programs in general) must not include host > glibc headers at all, regardless of what BPF compiler is used. The > glibc headers installed in the host are tailored to some particular > architecture, be it x86_64 or whatever, not necessarily compatible with > what the compilers assume for the BPF target. > > This particular case shows the problem well: all the glibc headers > included by that BPF selftest assume that `long' is 32 bits, not 64 > bits, because x86_64 is not defined. This conflicts with both clang's > and GCC's assumption that in BPF a `long' is 64 bits. This may or may > not be a problem, depending on whether the BPF program uses the stuff > defined in the headers and how it uses it. Had you be using an arm or > sparc host instead of x86_64, you may be including macros and stuff that > assume chars are unsigned. But chars are signed in bpf. This makes sense, but might cause some friction. The following glibc headers are included directly from selftests: - errno.h - features.h - inttypes.h - limits.h - netinet/in.h - netinet/udp.h - sched.h - stdint.h - stdlib.h - string.h - sys/socket.h - sys/types.h - time.h - unistd.h However, removing includes for these headers does not help the test in question, because some linux UAPI headers include libc headers when exported: In file included from /usr/include/netinet/udp.h:51, from progs/test_cls_redirect_dynptr.c:20: /home/eddy/work/tmp/gccbpf/lib/gcc/bpf-unknown-none/15.0.0/include/stdint.h:43:24: error: conflicting types for ‘int64_t’; have ‘long int’ 43 | typedef __INT64_TYPE__ int64_t; | ^~~~~~~ In file included from /usr/include/sys/types.h:155, from /usr/include/bits/socket.h:29, from /usr/include/sys/socket.h:33, from /usr/include/linux/if.h:28, from /usr/include/linux/icmp.h:23, from progs/test_cls_redirect_dynptr.c:12: /usr/include/bits/stdint-intn.h:27:19: note: previous declaration of ‘int64_t’ with type ‘int64_t’ {aka ‘long long int’} 27 | typedef __int64_t int64_t; | ^~~~~~~ On my system (Fedora 41) the linux/{icmp,if}.h UAPI headers are provided by kernel-headers package, sys/socket.h is provided by glibc-devel package. The UAPI headers have two modes depending whether __KERNEL__ is defined. When used during kernel build the __KERNEL__ is defined and there are no outside references. When exported for packages like kernel-headers (via 'make headers' target) the __KERNEL__ is not defined and there are some references to libc includes (in fact, references to '#ifdef __KERNEL__' blocks are cut out during headers export). E.g. here is a fragment of linux/if.h, when viewed from kernel source: #ifndef _LINUX_IF_H #define _LINUX_IF_H #include <linux/libc-compat.h> /* for compatibility with glibc */ #include <linux/types.h> /* for "__kernel_caddr_t" et al */ #include <linux/socket.h> /* for "struct sockaddr" et al */ #include <linux/compiler.h> /* for "__user" et al */ #ifndef __KERNEL__ #include <sys/socket.h> /* for struct sockaddr. */ #endif And here is the same fragment as part of the kernel-headers package (/usr/include/linux/if.h): #ifndef _LINUX_IF_H #define _LINUX_IF_H #include <linux/libc-compat.h> /* for compatibility with glibc */ #include <linux/types.h> /* for "__kernel_caddr_t" et al */ #include <linux/socket.h> /* for "struct sockaddr" et al */ /* for "__user" et al */ #include <sys/socket.h> /* for struct sockaddr. */ As far as I understand, the idea right now is that BPF users can install the kernel-headers package (or its equivalent) and start hacking. If we declare that this is no longer a blessed way, people would need to switch to packages like kernel-devel that provide full set of kernel headers for use with dkms etc, e.g. for my system the if.h would be located here: /usr/src/kernels/6.12.6-200.fc41.x86_64/include/uapi/linux/if.h . To me this seems logical, however potentially such change might have implications for existing BPF code-base.