Skip to main content
RunBook Academy

LinuxXLIII · eBPF and Advanced ObservabilityBPF maps

BPF maps and state - communicating with userspace

Advanced⏱ ~10 minbpftoolbpftrace

What you'll learn

  • Describe what BPF maps are
  • Use the common map types
  • Communicate between kernel and userspace
  • Recognise map patterns in production tools

Prerequisites

Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09

Not yet marked complete on this device.

BPF maps are the key-value data structures that eBPF programs use to store state and communicate with userspace. Without maps, eBPF programs can only do trace-and-print output. With maps, they can do aggregations, histograms, and stateful processing.

Map types

TypeDescription
BPF_MAP_TYPE_HASHHash table (key-value)
BPF_MAP_TYPE_ARRAYFixed-size array
BPF_MAP_TYPE_LRU_HASHLRU hash (auto-evict)
BPF_MAP_TYPE_PERCPU_HASHPer-CPU hash (no lock contention)
BPF_MAP_TYPE_RINGBUFRing buffer (efficient kernel-to-userspace)
BPF_MAP_TYPE_PERF_EVENT_ARRAYPerf event array (legacy)

For most use cases, BPF_MAP_TYPE_HASH and BPF_MAP_TYPE_PERCPU_HASH are sufficient. For high-volume event streaming, BPF_MAP_TYPE_RINGBUF is efficient.

bpftrace and maps

In bpftrace, maps are implicit:

# @ is the map (auto-created)
bpftrace -e 'tracepoint:syscalls:sys_enter_openat { @[comm] = count(); }'

# Per-CPU map
bpftrace -e 'tracepoint:syscalls:sys_enter_openat { @cpu[comm, cpu] = count(); }'

# Histogram
bpftrace -e 'tracepoint:syscalls:sys_enter_read { @bytes = hist(arg2); }'

@[comm] = count() creates a hash map keyed by comm (process name) with counter values.

After running bpftrace, the map is printed when the program ends (or on Ctrl-C):

@:
[
  nginx
]
@:
[
  12345
]
@:
[
  curl
]

Maps in C (bpf)

In raw bpf (C), declare maps explicitly:

struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 1024);
    __type(key, u32);
    __type(value, u64);
} count_map SEC(".maps");

Then access from the program:

u32 key = pid >> 32;
u64 *val = bpf_map_lookup_elem(&count_map, &key);
if (val) {
    (*val)++;
}

Communicating with userspace

Maps are the interface between kernel eBPF and userspace. A userspace program reads the map and processes the data:

// userspace
while (1) {
    int key = next_key();
    u64 value;
    bpf_map_lookup_elem(fd, &key, &value);
    printf("pid %d: %llu\n", key, value);
}

For events (not aggregates), use BPF_MAP_TYPE_RINGBUF:

// kernel
struct event_t *e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
*e = ...;
bpf_ringbuf_submit(e, 0);
// userspace
struct event_t *e;
e = bpf_ringbuf_consume(&events);
if (e) {
    process(e);
    bpf_ringbuf_mark_done(&events, e);
}

Ringbuf is efficient for high-volume event streaming.

Inspect maps with bpftool

# Substitute your own values before running:
KEY_ID=3B4FE6ACC0B21F32
KEY=ABCD1234EF567890

# List maps
bpftool map list

# Dump a map
bpftool map dump id "$KEY_ID"

# Lookup a key
bpftool map lookup id "$KEY_ID" key "$KEY"

# Delete a key
bpftool map delete id "$KEY_ID" key "$KEY"

For production debugging, bpftool map is the standard way to inspect what an eBPF program is doing.

Knowledge check

Knowledge check · 3 questions

  1. Q1. What is a BPF map?

  2. Q2. BPF ring buffer is efficient for high-volume event streaming.

  3. Q3. Which of the following are valid BPF map types? Select all that apply.

Passing score: 75%. Answers are checked in this browser.