Especially in large software projects which have contributions from dozens of developers, changes can unexpectedly disrupt related functionalities.
Likewise, eBPF programs require thorough testing to detect issues before they could impact production applications.
In today’s newsletter, I will demonstrate how to test eBPF XDP programs.
The core functionality for unit testing eBPF programs is the BPF_PROG_RUN
command, which was previously named BPF_PROG_TEST_RUN
and can be used interchangeably.
This command is invoked via the bpf()
syscall to execute an eBPF program and return its results to user-space, enabling unit tests with user-supplied context objects.
As of this writing, it supports the execution of the following eBPF program types:
BPF_PROG_TYPE_SOCKET_FILTER
BPF_PROG_TYPE_SCHED_CLS
BPF_PROG_TYPE_SCHED_ACT
BPF_PROG_TYPE_XDP
BPF_PROG_TYPE_SK_LOOKUP
BPF_PROG_TYPE_CGROUP_SKB
BPF_PROG_TYPE_LWT_IN
BPF_PROG_TYPE_LWT_OUT
BPF_PROG_TYPE_LWT_XMIT
BPF_PROG_TYPE_LWT_SEG6LOCAL
BPF_PROG_TYPE_FLOW_DISSECTOR
BPF_PROG_TYPE_STRUCT_OPS
BPF_PROG_TYPE_RAW_TRACEPOINT
BPF_PROG_TYPE_SYSCALL
However, directly invoking the syscall and ensuring all parameters are correctly set can be tedious. To simplify this, libbpf
offers the bpf_prog_test_run_opts
wrapper, which streamlines the process.
💡libbpf
is a C library that provides essential tools and abstractions for loading, managing, and interacting with eBPF programs in the Linux kernel.
The arguments for the bpf_prog_test_run_opts
function are an eBPF program file descriptor and a bpf_test_run_opts
structure.
Inside the function, bpf_prog_test_run_opts
simply copies the provided bpf_test_run_opts
struct, performs some sanity checks, and then directly invokes the bpf()
syscall through the sys_bpf()
wrapper.
While many fields in the bpf_test_run_opts
struct are optional, it really depends on the type of eBPF program you are testing.
The important fields we utilize for unit testing XDP programs are:
sz
is always required, and it is simply set tosizeof(bpf_test_run_opts).
data_in
anddata_size_in
allow us to provide mock data to the eBPF program. In the case of an XDP program, this would be an IPv4 packet.repeat
specifies how many times the test should run. This is useful if we want to gather some performance measurements.
I find code example renders in Substack tedious, so I’ll refer to my GitHub repository with the complete code demonstration.
⏪ Did you miss the previous issues? I'm sure you wouldn't, but JUST in case:
I hope you find this resource as interesting as I do. Stay tuned for more exciting developments and updates in the world of eBPF in next week's newsletter.
Until then, keep 🐝-ing!
Warm regards, Teodor