This guide covers eBPF development for the Antimetal Agent, including CO-RE (Compile Once - Run Everywhere) support, development workflows, and best practices.
The Antimetal Agent uses CO-RE technology for portable eBPF programs that work across different kernel versions without recompilation. This provides significant operational benefits:
- Single Binary Deployment: Same eBPF program runs on kernels 4.18+
- Automatic Field Relocation: Kernel structure changes handled automatically
- No Runtime Compilation: Pre-compiled programs with BTF relocations
- Improved Reliability: Reduced kernel compatibility issues
- Native kernel BTF on kernels 5.2+ at
/sys/kernel/btf/vmlinux - Pre-generated vmlinux.h from BTF hub for portability
- BTF verification during build process
CFLAGS := -g -O2 -Wall -target bpf -D__TARGET_ARCH_$(ARCH) \
-fdebug-types-section -fno-stack-protector-g: Enable BTF generation-fdebug-types-section: Improve BTF quality-fno-stack-protector: Required for BPF
- Use
BPF_CORE_READ()for field access - Automatic offset calculation at load time
- Example:
BPF_CORE_READ(task, real_parent, tgid)
pkg/ebpf/corepackage for kernel feature detection- Automatic BTF discovery and loading
- cilium/ebpf v0.19.0 handles relocations
| Kernel Version | BTF Support | CO-RE Support | Notes |
|---|---|---|---|
| 5.2+ | Native | Full | Best performance, native BTF |
| 4.18-5.1 | External | Partial | Requires BTF from btfhub |
| <4.18 | None | None | Traditional compilation only |
#include "vmlinux.h"
#include <bpf/bpf_core_read.h>
// Use CO-RE macros for kernel struct access
pid_t ppid = BPF_CORE_READ(task, real_parent, tgid);make build-ebpf # Automatically uses CO-RE flags- Build process includes BTF verification step
- Check with:
bpftool btf dump file <program>.bpf.o
./ebpf/scripts/check_core_support.sh # Check system CO-RE support- Create
ebpf/src/your_program.bpf.c - Include CO-RE headers:
#include "vmlinux.h" #include <bpf/bpf_core_read.h>
- Use CO-RE macros for kernel struct access
- Add to
BPF_PROGSinebpf/Makefile - Run
make build-ebpf
- Create
ebpf/include/your_collector_types.hwith C structs - Run
make generate-ebpf-typesto generate Go types - Generated files appear in
pkg/performance/collectors/
| Command | Purpose |
|---|---|
make build-ebpf |
Build eBPF programs with CO-RE support |
make generate-ebpf-bindings |
Generate Go bindings from eBPF C code |
make generate-ebpf-types |
Generate Go types from eBPF header files |
make build-ebpf-builder |
Build/rebuild eBPF Docker image |
./ebpf/scripts/check_core_support.sh |
Check system CO-RE capabilities |
- Prefer
BPF_CORE_READ()over direct field access - Use
BPF_CORE_READ_STR()for string fields - Check field existence with
BPF_CORE_FIELD_EXISTS()
- Test on minimum supported kernel (4.18)
- Verify on latest stable kernel
- Use KIND clusters with different kernel versions
- Not all kernel versions have all fields
- Use conditional compilation or runtime checks
- Provide fallback behavior
- BTF adds ~100KB to each eBPF object
- Worth it for portability benefits
- Strip BTF for size-critical deployments if needed
- Ensure clang has
-gflag - Check clang version (10+ recommended)
- Verify vmlinux.h is accessible
- Check kernel has BTF:
ls /sys/kernel/btf/vmlinux - Verify CO-RE support:
./ebpf/scripts/check_core_support.sh - Check dmesg for BPF verifier errors
- Ensure using CO-RE macros not direct access
- Verify field exists in target kernel version
- Check struct definitions in vmlinux.h
For a complete example of an eBPF-based collector implementation, see:
ebpf/src/execsnoop.bpf.c- eBPF C programpkg/performance/collectors/execsnoop.go- Go integrationpkg/performance/collectors/execsnoop_test.go- Testing approach