Quick and dirty BPF map updates with bpftool

Thu Jan 23 '20

The bpftool utility makes easy work of reading and updating BPF maps. This post will start with a really simple BPF program that uses a map to determine whether a message should be printed on each packet that goes through a BPF program running on a route.


You’ll need to start by installing dependencies. Assuming you’re already set up for bpf development[1], you may just need the bpftool package.

zypper in bpftool

The BPF program

Here is a minimal[2] BPF program that has some maps we can use for demonstration. This example is meant to attach to a route using BPF_PROG_TYPE_LWT_OUT. But really, it’s not picky. It will attach to anything that is foolish enough to give it a skb and accept payment in the form of BPF_OK in return.

// lwt_out.c
#include <linux/bpf.h>
#include "include/bpf_helpers.h"

struct bpf_map_def SEC("maps") printk_map = {
    .type = BPF_MAP_TYPE_ARRAY,
    .key_size = sizeof(int),
    .value_size = sizeof(int),
    .max_entries = 1

int prog_lwt_out(struct __sk_buff *skb)
    const char fmt[] = "Print about this skb boi\n";
    int *value, key = 0;

    value = bpf_map_lookup_elem(&printk_map, &key);
    if (value && !*value)
        bpf_trace_printk(fmt, sizeof(fmt));

    return BPF_OK;

char _license[] SEC("license") = "GPL";

In a nutshell[3], unless otherwise told by the value in the BPF_MAP_TYPE_ARRAY, this program will print on every single packet that leaves via the route it is attached to. Compile the program and install it to a route:

clang -O2 -g -Wall -Werror -target bpf -emit-llvm -c lwt_out.c -o - | \
    llc -march=bpf -filetype=obj -o lwt_out.o

pahole -J lwt_out.o

ip link add dum-dum type dummy

ip link set dum-dum up

ip route add dev dum-dum encap bpf out obj lwt_out.o section lwt_out

Note pahole is optional but converts the DWARF format into BTF format for better debugging.

At this point, you should be able to ping and see the printk output:

bpftool prog tracelog
ping-24366 [007] .... 18601.103214: 0: Print about this skb boi
ping-24366 [007] .... 18602.125616: 0: Print about this skb boi

Enter the maps

Okay. Obviously this blue part here is the land…

—Buster Bluth

Now that we have our super useful and not-at-all demonstrative program running, we need a way to turn logging on and off using the map we created in lwt_out.c above.

Lets first get an idea of what our map looks like. The map_ids field shows a list of maps attached to our program.

bpftool prog show id 85 | grep lwt_out -A2
85: lwt_out  tag 671a86d804002c58  gpl
    loaded_at 2020-01-21T21:56:21-0800  uid 0
    xlated 264B  jited 164B  memlock 4096B  map_ids 25

Knowing the map ID, we can show it.

bpftool map show id 25
25: array  flags 0x0
    key 4B  value 4B  max_entries 1  memlock 4096B

There’s a --json flag to output as JSON. There’s a --pretty flag you can use instead of piping to jq, but I find the latter prettier.

bpftool map dump id 25 -j | jq
    "key": [
    "value": [

Finally, updating the map is trivial with bpftool. The printk output should stop immediately upon entering this command.

bpftool map update id 25 key 0 0 0 0 value 1 0 0 0

Easy! Note that this will parse the byte sequence as decimal, but you can prefix it with 0x for hexadecimal, or 0 for octal. Alternatively, if you get sick of typing 0x in front of everything, just use the hex keyword in front of the byte sequence.

For technically-accurate and better-wrtten content on bpftool’s abilities around maps, check out man bpftool-map.

Now that you know how easy it is, get out there, and be creative!∎