bpftool basic commands
eBPF Tooling
William Patterson  

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.

Table of Contents

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 typeAttach pointWhen to use
XDPDeviceHigh-performance packet handling
TCTraffic controlFlexible queuing and shaping
cgroupCgroup hooksPer-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 methodProsWhen to use
Distribution package (linux-tools)Quick, matches running kernel, easy updatesEveryday use on Ubuntu/Debian systems
Build from source (tools/bpf/bpftool)Access latest features, JIT, full docsNeeding disassembler or newest fixes
Make doc/doc-installLocal man pages and reference filesOffline 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.

ScopeUseWhy
netNetworking programsFilter network-related views
perfTracing programsFocus on perf arrays and events
bpffsPinned fileDocument 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.

inspect ebpf program

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.
ActionExampleWhen to use
Load singleprog load foo.o /sys/fs/bpf/barQuick deploy
Load allprog loadall bpf_flow.o /sys/fs/bpf/flowMulti-program ELF
Dump JITprog dump jited pinned /sys/fs/bpf/fooMatch 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.
OperationExampleWhen to use
Create + Pinmap create /sys/fs/bpf/stats_map …Persistent counters or shared state
Lookup / Dumpmap lookup id <id> key … / map dump id <id>Inspect live key value entries
Iterate / Freezemap 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.

ActionExampleWhy
List BTFbtf showSee available type information
Dump definitionsbtf dump <id|file> –format cRead types as C structs
Link checksshow prog/map idsConfirm 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 caseKey actionVerify
XDP attachnet attach xdp id <id> dev <iface>bpftool net show + ip link
TC attachtc qdisc add …; tc filter add … bpf objtc filter show + remove qdisc
Tracing & perftrace_pipe / prog trace log / prog profiletrace 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.

FAQ

What is bpftool and how will this how-to guide help me?

bpftool is a user-space utility that exposes eBPF programs, maps, and kernel objects so you can inspect and manage them. This how-to walks you through installing the tool, common tasks like listing programs and maps, and troubleshooting—so you can load XDP or tracing programs, examine map contents, and automate tasks with JSON output.

How do I install and verify bpftool on Ubuntu or Debian?

On Debian-based systems, install the linux-tools package that matches your kernel version, then run a version check to confirm the tool is present. If you need newer features, build from the kernel source tree with BPF and libbpf enabled. I also recommend enabling shell completion to speed up work and using the man pages for quick help.

How can I list loaded eBPF programs and filter the output?

Use the show and list verbs to enumerate programs and maps, and apply filters like program type or interface name to narrow results. You can request JSON output for reliable script parsing and automation. This makes it easier to find XDP, TC, cgroup, or tracing programs among many loaded objects.

What’s the best way to inspect program code, opcodes, and control flow?

Dump translated or JITed instructions to see opcodes and a human-readable view. For deeper analysis, generate a visual control-flow graph (CFG) and review disassembly to debug logic or verify optimizations. These dumps help when profiling or tracing unexpected behavior.

How do I attach eBPF programs to interfaces or subsystems like XDP, TC, or cgroups?

Attach programs by specifying the target—network interface for XDP or TC, or a cgroup path for cgroup programs—and create links that represent the attachment. You can list and detach links when needed. Some NICs support hardware offload, so check whether your driver and hardware can offload programs.

How can I reuse maps between multiple programs or preload map contents?

Create and pin maps in the bpffs or filesystem so multiple programs can reference the same map by FD or path. Use update and lookup operations to seed or read key-value pairs. For prog_array and other special maps, follow the required key/value formats and size constraints to avoid runtime errors.

What map types should I know and what are their constraints?

Familiar map types include hash, array, lru_hash, perf_event_array, prog_array, stack, and queue. Each type has limits on entry count and key/value sizes. Stack and queue maps offer push/pop semantics; prog_array holds program IDs for tail calls. Always verify size, max_entries, and value_size when creating maps.

How do I inspect and manipulate map entries, including hex keys and values?

Use dump and lookup to view entries; update to add or change keys, and delete or freeze to make maps read-only. When dealing with binary data, pass keys and values in hex format and specify correct endianness and size. For automation, request JSON output so scripts can parse entries reliably.

What is BTF and how does it help with debugging and discovery?

BTF (BPF Type Format) embeds type and line number info for programs and maps, which yields clearer struct formatting, better stack traces, and source-level insight. List and dump BTF objects to see types from the kernel and loaded modules, helping you map binary layout to C structs during debugging.

How do I use bpftool for tracing, perf events, and debug output?

Attach tracing programs or perf_event_array maps to capture events, then stream debug output via trace_pipe or perf tools. Use profile and test-run features to generate synthetic events and measure performance. These methods help pinpoint latency or verify that hooks fire as expected.

How can I automate workflows and integrate bpftool into scripts?

Prefer JSON output when scripting to avoid parsing brittle plain text. Combine show/list verbs with filtering and use pinned objects by path to maintain stable references across reboots. Shell completion and consistent naming reduce errors when invoking repetitive tasks.

Where can I go next to deepen my eBPF and tooling skills?

Explore advanced topics like hardware offload, building complex multi-program ELF objects with loadall, and using libbpf-based user programs to manage maps and programs programmatically. Read kernel docs, study open-source projects that use XDP or tracing, and practice on non-production systems to build confidence.