Pin and Read a BPF Iterator with bpftool

You have already built a BPF iterator object, and now you need to turn it into something you can actually read: bpftool pins it into bpffs as a file. This guide covers pinning, reading and cleaning up an existing iterator, using a writable bpffs mount. Allow about fifteen minutes.

This is an operator guide for an already-compiled iterator: it does not build a BPF program, mount bpffs, or create either one for you. Loading BPF can need kernel privileges and a suitable kernel configuration, so treat the object file and destination as inputs to check, not values to guess.

1. Check the installed interface

Start with read-only checks that need no elevated privileges:

$ dpkg-query -W -f='${Package} ${Version}\n' linux-tools-common
linux-tools-common 6.8.0-139.139
$ bpftool iter help
Usage: bpftool iter { pin OBJ PATH [map MAP] | help }

Help text can vary with the installed build, but the contract stays bpftool iter pin OBJ PATH, with an optional map selector. On this machine the wrapper also warns if the matching kernel-specific tools package is missing. Do not treat that warning as a passed iterator test: confirm the command you intend to use is actually available for the running kernel.

Checkpoint: confirm the executable that will run:

$ command -v bpftool
/usr/sbin/bpftool

2. Check bpffs and the object file

A pinned iterator path must sit inside a mounted BPF filesystem. Inspect mounts and the object before changing anything:

$ findmnt -t bpf
$ test -r ./bpf_iter_netlink.o && echo "iterator object is readable"
iterator object is readable

The object name above is only a placeholder: replace it with the iterator you actually built. If findmnt prints nothing, stop and arrange a bpffs mount according to your distribution's administration policy. Mounting a filesystem is a privileged, persistent-enough host change and sits outside this guide.

3. Pin the iterator

Pinning creates the iterator and changes kernel state, and normally needs elevated privileges. Inspect the command and destination once before reaching for sudo:

$ ITER_OBJ=./bpf_iter_netlink.o
$ ITER_PIN=/sys/fs/bpf/my_netlink
$ sudo bpftool iter pin "$ITER_OBJ" "$ITER_PIN"

A successful command normally produces no output. The object must contain a BPF iterator program the running kernel accepts: a verifier error, an unsupported iterator target, an invalid object or a permissions error is a failure here, not a reason to retry with more privilege.

Checkpoint: verify the pinned path exists and is readable:

$ sudo test -r "$ITER_PIN" && echo "iterator is pinned"
iterator is pinned

The pinned file is a kernel-backed interface, not a copy of the object file. User space can open and read it, and its output is generated by the iterator program as the kernel walks its target data.

4. Read the generated output

Use cat to open the pinned iterator:

$ sudo cat "$ITER_PIN"
iterator output appears here

The output is target-specific: it might be formatted text, or binary data if the BPF program used a binary output method. Do not send unknown iterator output straight to a terminal unless it is documented as producing text; redirect it to a file and inspect that with an appropriate tool instead.

Reading again starts a fresh read of the iterator interface. It is not a permanent snapshot, so contents can change as kernel state changes. An empty result can be valid for a target with no matching objects; a non-zero exit status points to an open or read failure.

5. Supply a map for map-element iterators

A map-element iterator needs to know which map to walk. The manpage accepts either a map ID or a pinned map path:

$ sudo bpftool iter pin ./bpf_iter_hashmap.o \
    /sys/fs/bpf/my_hashmap map id MAP_ID

Replace MAP_ID with the numeric ID of the intended map. Using a pinned map instead, pass its path:

$ sudo bpftool iter pin ./bpf_iter_hashmap.o \
    /sys/fs/bpf/my_hashmap map pinned /sys/fs/bpf/existing_map

Check the map identity before pinning. A valid ID for the wrong map is still the wrong input, and the iterator can produce misleading output or fail its own checks.

6. Remove the pin when finished

Warning: removing the pin is destructive to this access path, although it does not rewrite the original object file. Confirm no reader still needs it, then remove exactly the path you created:

$ sudo rm -- "$ITER_PIN"
$ test ! -e "$ITER_PIN" && echo "iterator pin removed"
iterator pin removed

If other file descriptors still reference the iterator, the kernel object can stay alive until those descriptors close. A later command can reuse the same destination, but do not assume recreating a path gives you the same iterator state as before.

Done means