Home / Alt manpages / bpftool-struct_ops(8)

  • bpftool-struct_ops(8)
  • Admin command
  • linux

Inspect and Safely Manage BPF struct_ops with bpftool

You will learn to list and inspect the BPF struct_ops objects currently registered with the kernel, register an existing ELF object, optionally pin its links, and unregister the right object afterwards. The commands below follow the bpftool-struct_ops(8) manpage installed with linux-tools-common version 6.8.0-139.139. Allow about 15 minutes if the object is already built. Building a suitable BPF object is a separate job.

1. Check the local tool and its contract

Start with ordinary, read-only commands. The subcommand is part of bpftool, rather than a separate executable named bpftool-struct_ops.

$ command -v bpftool
$ bpftool version
$ bpftool struct_ops help

On the reference installation, the package version is 6.8.0-139.139. The actual binary may come from a kernel-specific linux-tools package, so a package version and a runnable binary are not the same check. If bpftool version warns that it cannot find the tool for the running kernel, stop and install the matching package through your normal system administration process. Do not work around that warning by copying a random binary into place.

2. See what is registered

Listing does not change kernel state and normally needs no elevated privileges. It prints the map ID first, then the map name and the kernel type.

$ bpftool struct_ops show
100: dctcp           tcp_congestion_ops
105: cubic           tcp_congestion_ops

The exact IDs and names vary by host. list is an alias for the same brief view. Save the output before making a change, especially if more than one object has a similar name.

$ bpftool struct_ops list
$ bpftool -j struct_ops show

The JSON form is useful for scripts. Add -p when you want human-readable JSON. An empty result can be perfectly valid: it means no struct_ops objects are currently visible to the command.

3. Inspect one object before changing it

Use the saved numeric ID or an exact map name. The dump command shows detail for one object, or for all objects when you omit the selector.

$ bpftool struct_ops dump id 105
$ bpftool struct_ops dump name cubic

Use the dump to confirm that the object you intend to remove belongs to the expected subsystem. Do not infer an ID from an old terminal capture: IDs can change as objects are registered and unregistered.

4. Register an existing struct_ops object

Registration changes kernel state and normally requires elevated privileges. It loads the BPF struct_ops found in the ELF sections named .struct_ops and .struct_ops.link. Replace the placeholder with a real object produced by your build.

$ sudo bpftool struct_ops register /path/to/bpf_struct_ops.o
Registered tcp_congestion_ops cubic id 110

A single object can contain more than one struct_ops definition. The command registers all of them. A verifier, BTF, permissions or subsystem error means registration did not complete; keep the diagnostic output and fix the object or its environment before retrying.

If the ELF contains entries in .struct_ops.link, pass a directory to pin the created links:

$ sudo install -d -m 0755 /run/bpf/struct_ops
$ sudo bpftool struct_ops register /path/to/bpf_struct_ops.o /run/bpf/struct_ops
$ sudo find /run/bpf/struct_ops -maxdepth 1 -type f -print

The links are pinned there using the corresponding map names. Choose a directory owned by the service that needs the pins, and record it in that service's configuration. The manpage specifies the directory argument, but it does not create a lifecycle policy for the pins.

5. Verify the new state

After registration, use a fresh listing rather than trusting a success message alone.

$ bpftool struct_ops show
$ bpftool struct_ops dump name cubic
$ bpftool -j struct_ops show

Match the returned name and kernel type to the object you meant to register. If you are automating this, parse JSON and treat a changed ID as expected. The ID is an identifier for the current kernel object, not a durable name.

6. Unregister with a deliberate recovery plan

Unregistering is service-disrupting when the struct_ops supplies live kernel behaviour. Check the name, ID and owning service first. This command requires elevated privileges on most systems and removes the registration from the kernel subsystem.

$ sudo bpftool struct_ops show
$ sudo bpftool struct_ops unregister id 105
Unregistered tcp_congestion_ops cubic id 105

You can use name instead when the name is unambiguous:

$ sudo bpftool struct_ops unregister name cubic

There is no rollback command in this interface. The practical undo is to register the original ELF object again, provided it is still available and the subsystem accepts it. Recheck the result:

$ bpftool struct_ops show
$ test -e /run/bpf/struct_ops/cubic && echo "pin remains" || echo "pin absent"

If you pinned links, account for their files separately. Unregistering an object and removing a pin are different lifecycle actions. Do not delete pins merely to make a directory look tidy while a consumer may still depend on them.

Common traps

  • Confusing the manpage name with the command: run bpftool struct_ops, not bpftool-struct_ops.
  • Using a stale ID: list again immediately before an unregister operation.
  • Assuming register loads every BPF section: this command targets the .struct_ops and .struct_ops.link sections described by the manpage.
  • Expecting plain output to be stable for a script: request JSON with -j and handle an empty object list.
  • Debugging too late: add -d to print libbpf and verifier diagnostics when a load fails, but avoid treating verbose logs as proof that registration succeeded.

Done means

  • You can identify each visible struct_ops by a fresh ID, name and kernel type.
  • You inspected the intended object with dump before changing state.
  • Any registration used the intended ELF file and, if needed, an explicit pin directory.
  • You verified the post-change listing and kept the original ELF available for recovery.