TIL: Pinning eBPF maps

2024-11-18 00:00:00 +0000 UTC

Sometimes, you want two eBPF programs to share one map for inter-eBPF communication, or access to some pooled collection from your userspace program. In order to do this, eBPF provides a “pinning” mechanism.

To use this mechanism when loading the eBPF program using ebpf-go, you must first mark your maps pinned in your eBPF C files. In my case, I want to apply uprobe and uretprobe eBPF programs to the same function, and push their messages to the same BPF perf event array. So I define my struct like this:

struct {
    __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
    __uint(pinning, LIBBPF_PIN_BY_NAME);		
} bash_uprobe_events SEC(".maps");

Next, in our Go program, we need to load our programs using a pinning option:

if err := os.MkdirAll("/sys/fs/bpf/uprobe_bash_pin", os.ModePerm); err != nil {
    log.Fatalf("failed to create bpf path: %+v", err)
}

options := ebpf.CollectionOptions{
    Maps: ebpf.MapOptions{
        PinPath: "/sys/fs/bpf/uprobe_bash_pin",
    },
}

This ebpf.CollectionOptions struct is accepted by the bpf2go generated load*Objects() functions as well as the underlying ebpf.LoadAndAssign function.

Sources: * eBPF.io: Pinning * ebpf-go pinning example

Tags: C linux ebpf go