git clone https://ruderich.org/simon/bpf/xdp-example.git/
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.
Note
|
BPF is a fast moving target so this information might be outdated. |
man bpf
: information about bpf(2)
syscall; architecture, parameters,
etc.; good place to get an overview what’s possible
libbpf: helper library to interface with the kernel and which provides BPF CO-RE (Compile Once - Run Everywhere); mirror of the kernel’s source code
Cilium’s BPF and XDP Reference Guide: technical overview of BPF and XDP with examples and links
Facebook’s BPF Blog: HOWTO BCC to libbpf conversion: information about libbpf and CO-RE
Facebook’s BPF Blog: BPF Portability and CO-RE: details about CO-RE
BCC’s libbpf-tools: real-world programs using libbpf and CO-RE which can serve as examples; its Makefile served as starting point for my Makefile below
See libbpf for the requirements to use BTF/BPF CO-RE and to run the minimal example below.
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/
example.bpf.c
The minimal BPF side is very simple.
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
SEC("xdp")
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.
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.
sleep(10);
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);
example_bpf__destroy(obj);
}
$ 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