Inspect eBPF Programs and Maps with bpftool
Someone tells you "it's probably eBPF" and walks off, and bpftool is how you find out what is actually loaded on the box. This guide gets you to a small, repeatable read-only workflow: check the installed build, list programs and maps, pull one object out as JSON, and probe which BPF features the kernel supports. Allow about fifteen minutes.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need a shell and a readable terminal. The commands here are ordinary and unprivileged unless stated otherwise. Nothing here loads, attaches, pins, updates or deletes a BPF object.
1. Check the installed command and its version
Start by checking which executable your shell resolves, then ask for its version:
$ command -v bpftool
/usr/sbin/bpftool
$ bpftool version
WARNING: bpftool not found for kernel 6.8.0-139
...
The exact warning depends on your running kernel and installed packages. On the reference machine, the local command comes from linux-tools-common version 6.8.0-139.139, but the matching kernel-specific executable is not installed, so it warns that linux-tools-6.8.0-139-generic and related cloud tools may be needed. A package providing the manual and wrapper is not proof the kernel-specific tool is present.
A warning is not a failed feature probe or a passed one. Check the exit status and keep the full output when you are diagnosing packaging:
bpftool version
status=$?
printf 'bpftool exit status: %s\n' "$status"
Checkpoint
If command -v prints nothing, stop and install the tool through your normal distribution process. Do not copy an executable from a different kernel release into /usr/sbin.
2. Read the help before you guess an object
The top-level manual describes map, prog, link, cgroup, perf, net, feature, btf, gen, struct_ops and iter objects. Ask the installed binary for its own syntax rather than trusting memory:
$ bpftool help
Usage: bpftool [OPTIONS] OBJECT { COMMAND | help }
bpftool batch file FILE
bpftool version
Output is not a stable interface: the manual warns formats can change, so scripts should read documented JSON fields for the version you have installed and still tolerate new fields turning up.
--jsonrequests JSON where the chosen command supports it.--prettyrequests human-readable JSON and implies--json.--debugprints library and verifier logs.--nomountstops automatic attempts to mount virtual filesystems such as tracefs or the BPF filesystem. Use it whenever an inspection must not mount anything.
3. List loaded programs and maps
These are the two object types you need for a first look:
$ bpftool --nomount prog list
$ bpftool --nomount map list
Empty output is a valid result. It means no objects are visible to this invocation, not that BPF is absent from the kernel. If the command reports insufficient permission or cannot reach a kernel interface, repeat the same read-only check with elevation, only where your system policy permits it:
$ sudo bpftool --nomount prog list
$ sudo bpftool --nomount map list
sudo does not install missing kernel support and will not make an unavailable program appear. Keep the unprivileged and elevated results separate in any incident record. The listed names, IDs, types, tags, owners and load information can vary in presentation between kernel and bpftool versions.
4. Pull one object out as JSON
Once a list shows an ID, request JSON for that specific object. Replace the placeholder with an ID that really appeared in your list:
$ BPF_PROG_ID=12345
$ bpftool --nomount --json prog show id "$BPF_PROG_ID"
$ BPF_MAP_ID=12345
$ bpftool --nomount --json map show id "$BPF_MAP_ID"
A stale ID gets rejected by the kernel: that is useful evidence, not a reason to guess a different one. Write the JSON to a file only after checking the destination is genuinely new:
test ! -e /tmp/bpftool-prog.json || {
printf '%s\n' 'Refusing to overwrite /tmp/bpftool-prog.json' >&2
exit 1
}
bpftool --nomount --json prog show id "$BPF_PROG_ID" > /tmp/bpftool-prog.json
test -s /tmp/bpftool-prog.json && echo 'JSON capture is non-empty'
This is a temporary diagnostic file, not a pinned BPF object. Remove it after review if your operational policy does not permit keeping it. Do not assume the JSON is a permanent schema: validate the fields your script needs and fail clearly when they are missing.
5. Probe available kernel features
Ask the running kernel what it supports:
$ bpftool --nomount feature probe
The probe covers supported program and map types plus other BPF capabilities, and it may need elevated privileges depending on the kernel and what you are querying:
$ sudo bpftool --nomount feature probe
Tip
A feature being listed means the kernel reports support for it. It does not prove your program will pass the verifier, that the needed privileges reach its service account, or that a particular helper is allowed for your program type. The kernel documentation describes bpftool as a central tool for BPF debugging and introspection, and that is the right way to think about it here.
6. Keep state-changing commands behind a deliberate review
Warning
The same command family includes prog load, prog attach, prog detach, map update, map delete and pin. Each of these can change packet handling, tracing, service behaviour or the lifetime of an object, and batch file FILE can run several such commands at once: treat a batch file as an executable change, not harmless configuration.
Before running any mutating command, record the exact program, map, link or cgroup target, check the syntax with bpftool OBJECT help, and have a rollback ready that matches the operation. Never test an attach or delete against a production ID copied from a list without an owner and a maintenance window. If an inspection unexpectedly tries to mount a virtual filesystem, stop it and rerun with --nomount rather than granting broader privilege to silence the symptom.
Common failure traps
- Version warning: the installed common package is not proof the kernel-specific tool is present. Check the executable and its exit status.
- Empty output: a genuinely empty list can be normal, not evidence that BPF is missing.
- Permission errors: elevate for read-only diagnosis only when authorised, and report the original privilege boundary.
- Unstable output: do not parse human-readable listings as a long-term API. Prefer JSON, but still handle version differences.
- Destructive shorthand: never paste a
delete,detachor batch command until its target and recovery path are written down.
Done means
- Identified the resolved
bpftoolexecutable and recorded its version output and exit status. - Used
--nomountfor read-only program, map and feature inspection. - Distinguished empty output, missing kernel tooling and insufficient permission.
- Captured JSON only for a verified object ID, without overwriting an existing diagnostic file.
- Kept loading, attaching, updating, deleting and batch execution out of the unattended workflow.