Building a Raspberry Pi Kernel to Run dae

Enable the BPF stream parser and BTF support required by dae on Raspberry Pi by cross-compiling a Raspberry Pi 5 kernel from Arch Linux

dae is a convenient option for using a Raspberry Pi as a software router. It depends heavily on kernel eBPF-related modules. The official Raspberry Pi kernel already enables most eBPF-related options, but it lacks CONFIG_BPF_STREAM_PARSER and BTF, so dae may fail its capability checks during startup.

You can cross-compile the Raspberry Pi kernel on a host machine, enable the kernel options required by dae, and install the new kernel onto the Raspberry Pi boot disk. The example below uses Arch Linux as the build environment and targets a 64-bit Raspberry Pi kernel. The kernel_2712 and bcm2712_defconfig values used in the commands correspond to Raspberry Pi 5 / BCM2712. For other models, replace them with the appropriate kernel image name and defconfig.

You can directly download the build scripts and compiled artifacts here.

Kernel options required by dae

daed mainly requires kernel support for eBPF and debug information:

CONFIG_BPF=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT=y
CONFIG_CGROUPS=y
CONFIG_KPROBES=y
CONFIG_NET_INGRESS=y
CONFIG_NET_EGRESS=y
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_CLS_BPF=m
CONFIG_NET_CLS_ACT=y
CONFIG_BPF_STREAM_PARSER=y
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_INFO_REDUCED is not set
CONFIG_DEBUG_INFO_BTF=y
CONFIG_KPROBE_EVENTS=y
CONFIG_BPF_EVENTS=y

Options such as CONFIG_NET_CLS_BPF and CONFIG_NET_SCH_INGRESS can either be built into the kernel or provided as modules. CONFIG_DEBUG_INFO_BTF requires pahole to be installed on the build host; otherwise, the kernel build cannot generate BTF information.

You can first check the current kernel configuration on the Raspberry Pi:

(zcat /proc/config.gz || cat /boot/{config,config-$(uname -r)}) | grep -E 'CONFIG_(DEBUG_INFO|DEBUG_INFO_BTF|KPROBES|KPROBE_EVENTS|BPF|BPF_SYSCALL|BPF_JIT|BPF_STREAM_PARSER|NET_CLS_ACT|NET_SCH_INGRESS|NET_INGRESS|NET_EGRESS|NET_CLS_BPF|BPF_EVENTS|CGROUPS)=|# CONFIG_DEBUG_INFO_REDUCED is not set'

The official Raspberry Pi kernel already enables these options:

CONFIG_BPF=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT=y
CONFIG_CGROUPS=y
CONFIG_KPROBES=y
CONFIG_NET_INGRESS=y
CONFIG_NET_EGRESS=y
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_CLS_BPF=y
CONFIG_NET_CLS_ACT=y
CONFIG_KPROBE_EVENTS=y
CONFIG_BPF_EVENTS=y

The options that actually need to be enabled additionally are:

CONFIG_BPF_STREAM_PARSER=y
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_INFO_REDUCED is not set
CONFIG_DEBUG_INFO_BTF=y

Prepare the cross-compilation environment

On Arch Linux, install the cross-compilation toolchain and the BTF generation tool:

sudo pacman -Syu base-devel git bc bison flex ncurses openssl aarch64-linux-gnu-gcc pahole

pahole: when the kernel has CONFIG_DEBUG_INFO_BTF enabled, it uses this tool to generate BTF from DWARF debug information.

Get the Raspberry Pi kernel source

Clone the kernel source maintained by Raspberry Pi:

git clone --depth=1 https://github.com/raspberrypi/linux
cd linux

Set a few variables for the following commands:

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
export KERNEL=kernel_2712

KERNEL=kernel_2712 is the kernel image name for Raspberry Pi 5. Other 64-bit Raspberry Pi models usually use a different name, so confirm the actual kernel file on the /boot partition before replacing it.

Generate and modify the kernel configuration

First, generate .config from the default Raspberry Pi 5 configuration:

make bcm2712_defconfig

Then open the menu configuration interface:

make menuconfig

In menuconfig, press / and search for the following symbol names directly. Enable the options according to their dependency requirements:

BPF_STREAM_PARSER
DEBUG_INFO
DEBUG_INFO_BTF
DEBUG_INFO_REDUCED

Build the kernel, modules, and device trees

Start the build:

make -j"$(nproc)" Image modules dtbs

If a step related to CONFIG_DEBUG_INFO_BTF fails, first check whether the build host can find pahole:

pahole --version

Mount the Raspberry Pi boot disk

Connect the Raspberry Pi SD card to the build host, then use lsblk to find the correct partitions:

lsblk -f

This example assumes:

  • /dev/sda1 is the boot partition.
  • /dev/sda2 is the rootfs partition.

Replace these with your actual device names when running the commands:

mkdir -p mnt/boot
mkdir -p mnt/root

sudo mount /dev/sda1 mnt/boot
sudo mount /dev/sda2 mnt/root

Install kernel modules

First, install the modules into the target system’s rootfs:

sudo env PATH="$PATH" make -j"$(nproc)" INSTALL_MOD_PATH=mnt/root modules_install

Install the kernel and device trees

Before replacing the kernel, back up the old kernel image:

sudo cp "mnt/boot/$KERNEL.img" "mnt/boot/$KERNEL-backup.img"

Then install the new kernel, device trees, and overlays:

sudo cp arch/arm64/boot/Image "mnt/boot/$KERNEL.img"
sudo cp arch/arm64/boot/dts/broadcom/*.dtb mnt/boot/
sudo cp arch/arm64/boot/dts/overlays/*.dtb* mnt/boot/overlays/
sudo cp arch/arm64/boot/dts/overlays/README mnt/boot/overlays/

Finally, unmount the partitions:

sudo umount mnt/boot
sudo umount mnt/root

Insert the boot disk back into the Raspberry Pi and boot it.

Verify after boot

After logging into the Raspberry Pi, confirm that it has booted into the new kernel:

uname -a

Then check the key configuration options:

(zcat /proc/config.gz || cat /boot/{config,config-$(uname -r)}) | grep -E 'CONFIG_(DEBUG_INFO|DEBUG_INFO_BTF|KPROBES|KPROBE_EVENTS|BPF|BPF_SYSCALL|BPF_JIT|BPF_STREAM_PARSER|NET_CLS_ACT|NET_SCH_INGRESS|NET_INGRESS|NET_EGRESS|NET_CLS_BPF|BPF_EVENTS|CGROUPS)=|# CONFIG_DEBUG_INFO_REDUCED is not set'

Check especially that these lines exist:

CONFIG_BPF_STREAM_PARSER=y
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_INFO_REDUCED is not set
CONFIG_DEBUG_INFO_BTF=y

If you have changed the default boot kernel, set this in /boot/firmware/config.txt:

[all]
kernel=kernel_2712.img