
Learn Basic bpftool Commands
You want clear, practical ways to inspect what runs in your kernel, and bpftool helps you do that without extra code or complex tooling.
I’ll show simple, repeatable steps to list programs and maps, read key information, and pin objects for persistence so you can reason about what the system is actually doing right now.
The focus is on day-to-day value: dumping translated instructions, using JSON output for scripts, and spotting the difference between a loaded program and one attached to a hook.
Key Takeaways
- You can discover and inspect BPF programs and maps in the kernel from user space.
- Use JSON output to make automation robust and avoid fragile parsing.
- Dumping translated or JIT instructions helps validate program logic.
- Pin maps or programs to the BPF file to share objects safely across processes.
- Learn a few focused commands to speed up troubleshooting and reduce guesswork.
What bpftool is and how this How-To guide will help
I’ll show how a single user-space bridge exposes eBPF internals and makes kernel inspection practical.
Think of this as one consistent interface to list, show, and manage every program and map the kernel holds. We use concise actions to move from a broad view to focused inspection—so you can find a program by id or name and then read the fields that matter.
User space interface to eBPF programs, maps, and the kernel
Under the hood, libbpf handles low-level details while the tool prints optional features with -V. You can list programs and maps with prog show/list and map show/list, then show details for a specific id or name.
Command-line abbreviations, man pages, and interactive help
To speed work, abbreviations exist—p for prog, d for dump, x for xlated—so shorter input maps cleanly to the same action. Use –help or -h and the generated man pages when syntax is unclear.
- Completion is context-aware and surfaces ids and names.
- We’ll also explain when to prefer name versus id for reproducible scripts.
- Different program types match different attach points—XDP versus TC, for example.
Program type | Attach point | When to use |
---|---|---|
XDP | Device | High-performance packet handling |
TC | Traffic control | Flexible queuing and shaping |
cgroup | Cgroup hooks | Per-process or container policies |
Install and verify bpftool on Linux
I’ll help you install the tool, check its version, and enable helpful extras like shell completion so you can read live kernel state with confidence.
Packages on Ubuntu and Debian: linux-tools and version check
On Ubuntu and Debian, install matching linux-tools packages so the binary aligns with your running kernel.
Run: sudo apt install linux-tools-common linux-tools-generic linux-tools-$(uname -r), then verify with bpftool -V. That single check prints version and optional features so you know if libbfd or skeleton support is present.
Building from the kernel source tree and enabling features
If you need the latest features or a JIT disassembler, build from the kernel source under tools/bpf/bpftool.
Use: cd tools/bpf/bpftool && make. Optionally run make install and build docs with make doc doc-install.
Note: distro packages (Ubuntu in particular) may omit JIT disassembly — building from source restores that value.
Shell completion, abbreviations, and getting help fast
The tool supports short abbreviations (for example: p d x i <id>), and bash completion is exhaustive. Tab completion saves time when you have many objects on the system.
Use –help or -h for interactive guidance, and consult the installed man pages for precise syntax when parsing options or flags.
Install method | Pros | When to use |
---|---|---|
Distribution package (linux-tools) | Quick, matches running kernel, easy updates | Everyday use on Ubuntu/Debian systems |
Build from source (tools/bpf/bpftool) | Access latest features, JIT, full docs | Needing disassembler or newest fixes |
Make doc/doc-install | Local man pages and reference files | Offline reference and faster troubleshooting |
bpftool basic commands
Start by listing the active programs and maps so you can build reproducible checks and automation.
I recommend an inventory pass: run bpftool prog show and bpftool map show to snapshot what the loaded system currently holds. Those outputs include ids and the basic information you need to pivot into deeper inspection.
Listing, targeting, and stable output
- Use prog show or prog list to view programs and pick an id or name to inspect further.
- List maps with map show, then follow a program’s map_ids to inspect each map’s type and key/value sizing.
- Prefer JSON with –json (-j) for scripts and –pretty (-p) for readable human checks.
- Add –bpffs to reveal pinned file paths when you manage pinned program or map objects.
For reliable parsing, pipe JSON into jq instead of grepping plain text. For example, extract an XDP id on eth0 using a structured query and then inspect instructions or JIT output from that program when you need to cross-check logic.
Scope | Use | Why |
---|---|---|
net | Networking programs | Filter network-related views |
perf | Tracing programs | Focus on perf arrays and events |
bpffs | Pinned file | Document or clean pinned handles |
Inspect and manage eBPF programs
I’ll show how to load, pin, and inspect programs so you can see exactly what runs in the kernel.
Start by loading an object and pinning the handle to the BPF file system so other tools can reuse it. For a single file, use bpftool prog load foo.o /sys/fs/bpf/bar. To bring in all sections, try bpftool prog loadall bpf_flow.o /sys/fs/bpf/flow type flow_dissector.
Pin a loaded program with bpftool prog pin id <id> /sys/fs/bpf/foo_prog, and remove a pinned path with a normal rm when you’re done.
Inspect code and control flow
Dump verifier-rewritten code to read instructions: bpftool prog dump xlated id <id>. If JIT is enabled, use bpftool prog dump jited pinned /sys/fs/bpf/foo and add opcodes for raw CPU opcodes.
To visualize basic blocks, output a dot file: bpftool prog dump xlated id <id> visual > prog.dot, then render with Graphviz.
Attach, reuse, and validate
- Attach to an interface: bpftool net attach xdp id <id> dev eth0 — detach with the same call.
- Cgroup attach: bpftool cgroup attach <cgroup> <attach type> <program>.
- Reuse maps on load by index or pinned path to avoid duplicate state: use map idx <i> id <id> or map name/pinned path options.
- Test-run via the system call bridge: bpftool prog run PROG data_in <file> data_out <file> and profile with bpftool prog profile. Enable stats with sysctl kernel.bpf_stats_enabled=1.
Action | Example | When to use |
---|---|---|
Load single | prog load foo.o /sys/fs/bpf/bar | Quick deploy |
Load all | prog loadall bpf_flow.o /sys/fs/bpf/flow | Multi-program ELF |
Dump JIT | prog dump jited pinned /sys/fs/bpf/foo | Match CPU behavior |
Create, update, and inspect maps for key-value data
Maps hold runtime state your eBPF program reads and writes. I’ll show practical patterns to create, pin, iterate, and freeze maps so your data survives restarts and is shareable across tools.
Create, pin, and freeze
Create a typed storage area with explicit sizing. For example:
bpftool map create /sys/fs/bpf/stats_map type array key 4 value 32 entries 8 name stats_map.
Pin the map under the BPF file system to make it persistent across process exit. When init ends, freeze a map to prevent user-space mutations while kernel reads continue.
Lookup, dump, and update entries
Lookup uses host byte order for keys. You can pass keys in hex with the key hex form for exact layouts.
Dump iterates all entries; with BTF present, dumps show structured key value pairs instead of raw hex. Update entries with bpftool map update id <id> key … value …. Arrays have fixed entries; hash maps allow insert/delete.
Iterate, prog_array, and special maps
- Use map getnext to walk hash keys and build a full snapshot.
- For tail calls, update a prog_array by referencing pinned program paths so entries remain valid.
- Stack and queue maps use push/enqueue and pop/dequeue/peek verbs and don’t need keys.
Operation | Example | When to use |
---|---|---|
Create + Pin | map create /sys/fs/bpf/stats_map … | Persistent counters or shared state |
Lookup / Dump | map lookup id <id> key … / map dump id <id> | Inspect live key value entries |
Iterate / Freeze | map getnext id <id> … / map freeze id <id> | Walk keys or lock config after init |
BTF-powered insight and advanced object discovery
BTF injects rich type and source information into eBPF artifacts so you can trace instructions back to your original source. I’ll show how that extra debug info changes program and map inspection from guesswork into a clear, repeatable workflow.
BTF for programs and maps: line numbers and struct formatting
Compile with -g (clang/LLVM 8+) to embed BTF in your object files. With that, use prog dump xlated id <id> linum to see file names and line numbers next to translated instructions.
When maps carry BTF, dumps show structured fields instead of hex. That makes it simple to spot layout mismatches between your source code and the live map contents.
List and dump BTF objects; kernel and module BTF
Discover what debug info is present with btf show. The list includes kernel-level entries like vmlinux, module-specific BTF, and standalone program/map objects.
Action | Example | Why |
---|---|---|
List BTF | btf show | See available type information |
Dump definitions | btf dump <id|file> –format c | Read types as C structs |
Link checks | show prog/map ids | Confirm BTF presence before relying on line output |
- Use BTF dumps to inspect types and sizes before interpreting map output.
- Map the program or map id to its BTF id to ensure you have the right debug context.
- When multiple modules exist, names (vmlinux, module_name) clarify which types apply.
Network and tracing use cases you’ll use right away
When you need to validate a packet path or measure latency, quick network and tracing use cases save time. I’ll show how to attach an XDP hook, inspect attachments, and stream trace output so you can iterate with confidence.
XDP and TC: attach, list, and detach on interfaces
Attach an XDP program to an interface with: bpftool net attach xdp id <id> dev <iface>, then verify with bpftool net show filtered by device and an ip check. Detach using the same attach call or remove the program id.
For TC, add a clsact qdisc: tc qdisc add dev <iface> clsact, then attach via tc filter … bpf direct-action obj <obj> sec <sec>. Remove the qdisc when testing finishes to keep the interface clean.
Trace and perf events: trace_pipe, debug output, and profiling
Stream live kernel events with cat /sys/kernel/debug/tracing/trace_pipe or use bpftool prog trace log for structured output. List tracing and perf programs with bpftool perf show.
Profile a program with bpftool prog profile <prog> <metrics> and enable –debug for extra verifier and libbpf messages when debugging. For hardware offload, enable hw-tc-offload on the NIC and use skip_sw filters so packets run on the device.
Use case | Key action | Verify |
---|---|---|
XDP attach | net attach xdp id <id> dev <iface> | bpftool net show + ip link |
TC attach | tc qdisc add …; tc filter add … bpf obj | tc filter show + remove qdisc |
Tracing & perf | trace_pipe / prog trace log / prog profile | trace output + perf metrics |
Where to go next with bpftool skills
When you outgrow manual checks, automation and deeper probes make investigations fast and reliable. I recommend scripting routine inspections with bpftool JSON output and jq so you can repeat audits across the loaded system.
Use batch files to chain list, show, and net queries into one tidy operation. For deeper debugging, expose JIT symbols to kallsyms and correlate perf samples back to a program id or tag.
Enumerate ebpf objects — programs, maps, BTF entries, and links — and find which PIDs hold references. Practice safe map update patterns, adjust memlock limits when needed, and enable stats selectively.
Keep learning: probe features, generate skeletons, and inspect control-flow graphs so changes to code are clear before deployment.