# bpfman: a manager, a filesystem and a Kubernetes operator for eBPF

> bpfman, the CNCF Sandbox project formerly called bpfd, loads and administers eBPF programs on Linux and extends that to Kubernetes through a custom resource operator. It is a strong fit for platform teams that want one place to attach and watch eBPF, and a poor fit for a team that wants a small dependency with no daemon.

**bpfman/bpfman** — An eBPF Manager for Linux and Kubernetes

- Repository: https://github.com/bpfman/bpfman
- Website: https://bpfman.io
- Stars: 769 · Forks: 85
- Language: Go
- License: Apache-2.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/bpfman-bpfman

## bpfman puts a manager in front of eBPF loading

Loading an eBPF program is easy to do badly. You attach it, you hand it a hook, you hope the right packets reach it, and then you have no central place to ask what is attached where. bpfman exists to sit in that gap. The README describes it as an eBPF manager that focuses on simplifying the deployment and administration of eBPF programs, and it is a Cloud Native Computing Foundation Sandbox project, formerly known as bpfd.

Three capabilities are named in the README. A system overview gives insight into how eBPF is being used on the machine. A program loader comes built in, and it supports program cooperation for XDP and TC programs as well as deployment of eBPF programs from OCI images. And an eBPF filesystem manager makes it possible to deploy eBPF applications without requiring additional privileges.

On top of that sits a Kubernetes operator, so the same management idea reaches a cluster through custom resource definitions deployed across nodes. The homepage is bpfman.io, and the README points at a quick start page, local host and Kubernetes example pages, a building page and an operator quick start page. The project also publishes example eBPF programs written in Go that interact with bpfman, which is the fastest way to see what the interface looks like.

## Program cooperation, OCI images and the eBPF filesystem

The interesting mechanics are in the loader and the filesystem. Program cooperation is the part that changes how you attach things. Instead of one program owning the XDP or TC hook, several programs can be attached to it and the loader dispatches between them. The README's licence section names the TC dispatcher, a file in the repository's bpf directory, as one of the pieces written by the project's own authors, so the dispatching logic is part of the project rather than something borrowed.

The OCI path is the second piece. The Go module in this repository already depends on oras.land/oras-go, on go-containerregistry and on sigstore/cosign, so pulling a program packaged as a container image is a supported route rather than an aspiration, and signing tooling for those images sits in the same dependency set.

Underneath, the module carries cilium/ebpf v0.20.0 and vishvananda/netlink v1.3.1, plus mattn/go-sqlite3 and pressly/goose for a local store with schema migrations. There is a gRPC API with protobuf, and the container-storage-interface spec is a dependency, which is what makes the CSI piece possible. On the Rust side, the workspace pins aya 0.14.0 and aya-obj 0.3.0, so the same program can be loaded from either language's stack.

## The Kubernetes operator turns attach into a custom resource

Running one privileged agent per node is exactly the kind of thing a cluster administrator wants to stop doing by hand. bpfman's operator exists for that: the README says it lets users deploy eBPF through custom resource definitions across nodes in a cluster, so the desired state of an attachment is a Kubernetes object that can be reviewed, versioned and rolled back with the rest of your manifests.

The Go tree hints at how the API is shaped. Files named attach_kind.go and attach_spec.go sit at the top of the Go module, and the spec naming suggests the attachment is a first class, structured value in the API rather than a loose bag of flags. There is a bpfman-ns component for namespace handling, a clients/ directory for generated or hand written clients, and a cmd/ directory for entry points. The examples directory carries a build-release-yamls.sh script and a config/ directory, which is the shape of a project that ships its operator manifests as release artifacts rather than asking every adopter to hand assemble them.

Alongside the operator sit the two exporters, bpf-log-exporter and bpf-metrics-exporter, which are listed as separate members of the Rust workspace. The Go module also depends on the Prometheus client library, so the project clearly has a path for getting program output into monitoring, which is the practical reason to want a manager in the first place: attaching is easy, and then noticing that an attachment quietly stopped matching traffic is not.

## Two toolchains, one repository

The repository is a Go module and a Cargo workspace at the same time, and anyone building from source needs both. The Go side is module github.com/bpfman/bpfman and it asks for a recent toolchain:

```go
module github.com/bpfman/bpfman

go 1.25.7
```

The Rust side is a workspace whose package metadata is centralised:

```toml
[workspace.package]
documentation = "https://bpfman.io/main/getting-started/overview/"
edition = "2024"
homepage = "https://bpfman.io"
license = "Apache-2.0"
repository = "https://github.com/bpfman/bpfman"
rust-version = "1.85.0"
version = "0.6.0"
```

The workspace members are bpfman, bpfman-api, bpfman-ns, csi, the two exporters, an xtask crate and an integration test crate. That last one is deliberately kept out of the default members, and the comment in the workspace file says integration tests must be run through cargo xtask. Cargo.lock is committed, and Cross.toml is present for cross-compilation, which matters when you are producing node agent images for several architectures.

The Makefile carries the tool version pins in one place, including a Fedora version, a Go version, a golangci-lint version and a protoc version, and the comment there explains that protoc is downloaded rather than taken from the host so generated stubs stay reproducible. The practical cost of contributing is that a single build pulls a Rust toolchain, a Go toolchain and a protobuf compiler.

## Where to get it: quick start, a Fedora build and a family of Containerfiles

The README gives no copy-paste install command, which is worth knowing in advance. It points to the quick start page on bpfman.io, described as a quick installation without having to download or build the code from source, and separately to a page for setting up a development environment and building bpfman. If you want to see it working before reading much, the local host example page is the shortest path: it covers running bpfman on a host and using the CLI to install eBPF programs.

For packaging, the repository carries a bpfman.spec file and a README badge pointing at a Fedora COPR build, so a package exists for Fedora hosts. The container side is where the matrix shows: Containerfile.bpfman.local, Containerfile.bpfman.multi.arch, Containerfile.bpfman.openshift, Containerfile.bytecode, Containerfile.bytecode.multi.arch, and a matching set of Dockerfiles including Dockerfile.bpfman, Dockerfile.bpfman.dev, Dockerfile.ci and Dockerfile.csi-sanity. Separate local, multi-architecture, OpenShift and bytecode variants tell you the project expects to run in several different environments, and that a plain Dockerfile is not the whole story.

The docs site is built with MkDocs. The pyproject.toml for it pins mkdocs-material, mkdocs-callouts and mike, and requires Python 3.13 or newer, which is a detail to note if your documentation toolchain runs on an older interpreter.

## The licence splits the eBPF code from everything else

bpfman is not a single licence repository, and the split is deliberate. The README states that with the exception of eBPF code, everything is distributed under the Apache License version 2.0. The eBPF code is distributed under either the GNU General Public License version 2 or the BSD 2 Clause license, at your option.

The choice is not uniform inside that eBPF part, and the exact terms vary by file. Files originating from the project's own authors use the expression (GPL-2.0-only OR BSD-2-Clause), which the README gives as the pattern for the TC dispatcher and for the example programs. Files that came from libxdp use GPL-2.0-only, and the README links those back to the upstream xdp-tools project. The per-file SPDX-License-Identifier headers are the authority, so a license review of an embedded dispatcher has to look at the file, not at the repository level.

Contributions follow the same rule. The README says that unless you explicitly state otherwise, a contribution intentionally submitted for inclusion is dual licensed the same way, with no additional terms or conditions. In practice the practical effect is that the permissive Apache-2.0 covers the manager, the operator, the API and the exporters, while anything running inside the kernel is either BSD-2-Clause by choice or GPL-2.0-only where it came from libxdp.

## Where bpfman is the wrong tool

The clearest case against it is a small deployment that needs one eBPF program. bpfman brings a daemon, an eBPF filesystem, a Kubernetes operator, a CSI driver, two exporters and a build that needs both Go and Rust. For a single service that wants one kprobe, the cilium/ebpf library or the aya crate, both of which bpfman itself depends on, plus the ORAS client for images, is a much smaller path. Writing your own attach logic means you own the attach priorities and the lifecycle yourself, and you also give up the overview, the filesystem and the operator.

The second limitation is the release line. The version in the workspace metadata is 0.6.0, published as v0.6.0 on 2026-03-31. Before that came v0.5.6 on 2025-02-17 and v0.5.5 on 2025-01-04, so the gap between the two most recent tags is about thirteen months, and the project is still numbered below 1.0. The last push to the repository was on 2026-10-19, so work is landing on main even where releases lag, which is an argument for pinning an exact tag rather than tracking the branch.

A third point is scope of the cooperation model. The loader's cooperation support is named for XDP and TC. The example programs cover kprobes, uretprobes, uprobes, tracepoints, tcx and Go level counters, so the ecosystem of hooks is wider in the samples than in the manager's own cooperation story. Teams whose whole workload is uprobe based tracing should check that path before betting on the filesystem.

## Conclusion

bpfman earns its place on a platform team that attaches XDP and TC programs across many nodes and wants one loader, one filesystem and one Kubernetes operator instead of a pile of privileged DaemonSets. It is the wrong size for a single service that needs one kprobe: the daemon, the operator, the CSI driver and the two-language build are all overhead there. Before adopting, check the three things the repository leaves open: the release line is still pre-1.0 with v0.6.0 dated 2026-03-31 and a thirteen month gap behind it, so pin an exact version; the OCI path in the Go module depends on cosign, so decide who signs your eBPF images before enabling it; and the docs at bpfman.io, not the README, are where the install steps live, so read the quick start page before sizing the deployment.

## FAQ

### What is bpfman and what does it replace?

bpfman is an eBPF manager for Linux and Kubernetes, formerly known as bpfd, and a CNCF Sandbox project. It provides a system overview of eBPF usage, a program loader with cooperation support for XDP and TC programs and OCI image deployment, an eBPF filesystem, and a Kubernetes operator for deploying eBPF through custom resource definitions.

### How do I install bpfman without building it from source?

The README points to a quick start page on bpfman.io, described as a quick installation without downloading or building the code, and it carries a badge for a Fedora COPR build of the package. The repository also ships a bpfman.spec file and several Containerfiles for container based installs.

### Can I deploy eBPF programs to a Kubernetes cluster with bpfman?

Yes. The README says bpfman includes a Kubernetes operator that lets users deploy eBPF through custom resource definitions across nodes in a cluster, and it points to a page for deploying the operator and another for deploying example eBPF programs on Kubernetes.

## Sources

- [bpfman/bpfman on GitHub](https://github.com/bpfman/bpfman)
- [License: Apache-2.0](https://github.com/bpfman/bpfman/blob/main/LICENSE)
- [Project website](https://bpfman.io)
- [README](https://github.com/bpfman/bpfman/blob/main/README.md)
- [Releases](https://github.com/bpfman/bpfman/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/bpfman-bpfman
