18. dpdk-validate-bpf Application

The dpdk-validate-bpf tool is an application that allows evaluating BPF programs against the lib/bpf library. It can be used to pre-validate BPF programs before loading them in a real application to ensure that they pass the internal verifier. This makes it a useful tool for integrating into build systems and continuous integration (CI) pipelines to verify the correctness of BPF programs during compilation, as well as for debugging validation issues.

18.1. Running the Application

The tool requires a path to a compiled BPF object file. It also provides options to configure the execution environment and external symbol definitions.

For a comprehensive list of options and their meanings, refer to the built-in help by running dpdk-validate-bpf --help.

The most important options for a minimal example are:

--prog-arg <type>

Define program arguments, if different from struct rte_mbuf *. This argument may be repeated up to 5 times.

--xsym '<type> <name> | <type> <name>(<type>, ...)'

Define an external symbol (variable or function) that the BPF program uses. This allows the validator to recognize external calls and memory accesses. Multiple external symbols can be defined by repeating this option.

--section <name>

Specify the ELF section name in the BPF object file to load and validate. The default section name is .text, which is typically fine in cases where the object file contains only one program.

18.2. Interactive Debugging Mode

The interactive mode (enabled with the --debug flag) allows the user to debug the BPF validation process itself. This is particularly useful when BPF program fails verification, allowing you to trace the state changes per instruction and understand the validator’s decisions.

18.2.1. Design

The interactive debugger provides a command-line interface similar to GDB. It allows setting breakpoints at specific instructions, or catchpoints on validator events (such as branch-enter or branch-prune). Users can step through the validation process, inspect the state of registers, and query if certain conditional jumps may be taken based on the validator’s knowledge of the program state.

18.2.2. Usage Example

Launch the tool in debug mode with a compiled BPF object file:

$ dpdk-validate-bpf bpf_prog.o --prog-arg={'void *',uint64_t} --debug
 =>          0:  b7 00 00 00 01 00 00 00         mov r0, #0x1
 (validate) list 3
 =>          0:  b7 00 00 00 01 00 00 00         mov r0, #0x1
             1:  25 02 01 00 0e 00 00 00         jgt r2, #0xe, L3
             2:  b7 00 00 00 00 00 00 00         mov r0, #0x0
 (validate) break 2
 Breakpoint 0 at 2.
 (validate) catch branch-enter
 Catchpoint 1 on branch-enter.
 (validate) continue
 Catchpoint 1 on branch-enter.
 Entered new branch at pc 1.
 =>          3:  95 00 00 00 00 00 00 00         exit
 (validate) where
             1:  25 02 01 00 0e 00 00 00         jgt r2, #0xe, L3        ; taken
 =>          3:  95 00 00 00 00 00 00 00         exit
 (validate) info r1
    r1:  %buffer<0> + 0
 (validate) info r2
    r2:  0xf..UINT64_MAX
 (validate) may r2 <= 14
 NO
 (validate) continue
 Catchpoint 1 on branch-enter.
 Entered new branch at pc 1.
 Breakpoint 0 at 2.
 =>          2:  b7 00 00 00 00 00 00 00         mov r0, #0x0
 (validate) continue
 Validation succeeded.
 (validate) quit