XDP minimal example

First written 2020-11-15; Last updated 2020-11-15

This note shows a minimal XDP (eXpress Data Path) setup with libbpf and BTF/BPF CO-RE because it took me a while to collect all the pieces for a working program. It should also serve as starting point for BPF in general. It also lists some useful BPF-related resources.

BPF is a fast moving target so this information might be outdated.


See libbpf for the requirements to use BTF/BPF CO-RE and to run the minimal example below.

Minimal example

The full source for this example is licensed under LGPL-2.1-or-later and BSD-2-Clause and is available at my Gitweb and can be cloned with:

git clone https://ruderich.org/simon/bpf/xdp-example.git/

BPF side: example.bpf.c

The minimal BPF side is very simple.

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>

int xdp_prog(struct xdp_md *ctx) {
    return XDP_PASS;
char LICENSE[] SEC("license") = "GPL";

XDP_PASS accepts all packets making this XDP program a NOP.

User-space side: example.c

The user-space is a bit more complicated. The following code omits error checks for brevity, see the Git repository for the full code.

#include <net/if.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <unistd.h>

#include <bpf/bpf.h>
#include <linux/if_link.h>

libbpf’s skeleton is used to reduce the boilerplate. The skeleton is generated by the Makefile from example.bpf.c with bpftool gen skeleton.

#include "example.skel.h"

int main(int argc, char **argv) {

The interface index is required to attach the XDP program.

    unsigned int ifindex = if_nametoindex(argv[1]);

Larger BPF programs require more memory.

    struct rlimit rlim = {
        .rlim_cur = RLIM_INFINITY,
        .rlim_max = RLIM_INFINITY,
    setrlimit(RLIMIT_MEMLOCK, &rlim);

Load the skeleton and compile the BPF.

    int err;
    struct example_bpf *obj;

    obj = example_bpf__open();
    err = example_bpf__load(obj);

Attach the BPF program to the network interface.

    int flags = XDP_FLAGS_SKB_MODE;
    int fd = bpf_program__fd(obj->progs.xdp_prog);

    err = bpf_set_link_xdp_fd(ifindex, fd, flags);

After attaching the XDP program there are two possibilities: Either exit, this will keep the XDP program attached to the interface, or, enter a main loop and interact with the XDP program (e.g. using maps). For this example we just sleep ten seconds.


For the latter type of XDP programs we must now detach from the network interface.

    fd = -1;
    err = bpf_set_link_xdp_fd(ifindex, fd, flags);



$ make vmlinux.h
$ make
$ ./example eth0

Open another terminal and run ip link, you should see something like this:

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 xdpgeneric [...]
    link/ether [...] brd ff:ff:ff:ff:ff:ff
    prog/xdp id 5520 tag 3b185187f1855c4c

Last updated 2020-11-15

Impressum Datenschutzerklärung