libbpf for Go, transpiled, CGo-free.
Can be built with CGO_ENABLED=0 and does not need a system libbpf,
libelf, zlib, pkg-config, C compiler, or dynamic C library for ordinary
Go builds.
The module exposes two packages:
go.dw1.io/bpf: the Go API for object, map, program, link, BTF, buffer, skeleton, and low-level libbpf workflows.go.dw1.io/bpf/abi: the low-level generated libbpf ABI for generated packages and advanced interop.
Generated ABI output is checked in. Users do not need to run the generator to import the module.
This repository currently generates ABI files for:
linux/amd64linux/arm64
Other targets fail clearly from go.dw1.io/bpf/abi
instead of silently using a different implementation.
The checked-in source baseline is upstream libbpf v1.7.0 at commit
f5dcbae736e5d7f83a35718e01be1a8e3010fa39.
The root package is intended for Go application code that wants libbpf-style
loading and attachment without cgo. It is not an eBPF bytecode compiler. Runtime
operations still use kernel BPF facilities, so loading programs, attaching links,
pinning objects, or changing network hooks can require privileges such as
CAP_BPF, CAP_NET_ADMIN, CAP_SYS_ADMIN, or root depending on the kernel and
operation.
The module is pre-v1. Public APIs should be treated as usable but still subject to compatibility cleanup before a stable release.
go get go.dw1.io/bpfOpen ELF object files with OpenObjectFile
or in-memory object bytes with OpenObjectMem:
package main
import (
"fmt"
"go.dw1.io/bpf"
)
func main() {
obj, err := bpf.OpenObjectFile("program.bpf.o", bpf.ObjectOptions{})
if err != nil {
panic(err)
}
defer obj.Close()
prog, err := obj.Program("handle_packet")
if err != nil {
panic(err)
}
fmt.Println(prog.Name(), prog.SectionName())
if err := obj.Load(); err != nil {
panic(err)
}
}Object exposes loaded maps,
programs, BTF, kernel logs, pinning helpers, and access to the wrapped generated
ABI handle when lower-level interop is required.
Programs expose libbpf attachment workflows as Go methods:
obj, err := bpf.OpenObjectFile("trace.bpf.o", bpf.ObjectOptions{})
if err != nil {
panic(err)
}
defer obj.Close()
if err := obj.Load(); err != nil {
panic(err)
}
prog, err := obj.Program("trace_openat")
if err != nil {
panic(err)
}
link, err := prog.AttachTracepoint("syscalls", "sys_enter_openat")
if err != nil {
panic(err)
}
defer link.Close()Available attachment helpers include kprobes, uprobes, tracepoints, raw tracepoints, perf events, cgroups, XDP, TCX, netfilter, netkit, LSM, struct_ops, USDT, and libbpf's generic auto-attach path.
Maps can be discovered from an opened object and manipulated through Go-shaped methods:
cfg, err := obj.Map("config")
if err != nil {
panic(err)
}
key := make([]byte, cfg.KeySize())
value := make([]byte, cfg.ValueSize())
copy(value, []byte{1})
if err := cfg.Update(key, value, bpf.UpdateAny); err != nil {
panic(err)
}
current, err := cfg.Lookup(key, 0)
if err != nil {
panic(err)
}
_ = currentThe package also exposes lower-level helpers such as
CreateMap,
LookupMapElement, and
UpdateMapElement for code
that works directly with file descriptors.
Ring-buffer callbacks receive a borrowed view into libbpf-owned memory. Copy the sample if it needs to outlive the callback:
events, err := obj.Map("events")
if err != nil {
panic(err)
}
rb, err := bpf.NewRingBuffer(events.FD(), func(sample bpf.RingBufferSample) error {
data := append([]byte(nil), sample.Data...)
_ = data
return nil
})
if err != nil {
panic(err)
}
defer rb.Close()
if _, err := rb.Poll(100); err != nil {
panic(err)
}Perf buffers, raw perf buffers, and user ring buffers are available through the same root package.
The root package includes BTF construction, parsing, kernel loading, lookup, and mutation helpers:
btf, err := bpf.LoadKernelBTF()
if err != nil {
panic(err)
}
defer btf.Close()
_ = btf.TypeCount()Use ParseBTFFile,
ParseBTFELF,
LoadKernelBTF, and related
helpers for BTF workflows. BTFDump
wraps libbpf's C declaration dumping APIs.
go.dw1.io/bpf/abi exposes the
generated libbpf-like ABI. It is intentionally version-coupled to the pinned
upstream source and uses ccgo/modernc runtime conventions.
Application code should prefer the root package. Generated packages or systems
code that need raw libbpf symbols can depend on
go.dw1.io/bpf/abi instead of carrying a
private libbpf copy.
The generator lives in internal/cmd/genbpf and is wired through go generate:
go generate ./...The generated package includes:
abi/libbpf_linux_amd64.goabi/libbpf_linux_arm64.goabi/SOURCE-MANIFEST.txtabi/SYMBOLS.txtabi/BEHAVIOR-COVERAGE.txt- ABI option, record, callback, skeleton, and symbol tests
- unsupported-target build failure stubs
SOURCE-MANIFEST.txt records the libbpf source commit, selected headers and
sources, target list, source adjustments, local bridge files, upstream license
inputs, generated files, and ccgo/modernc tool versions. SYMBOLS.txt records
the public libbpf symbols expected in the ABI package. BEHAVIOR-COVERAGE.txt
records which libbpf exports are implemented through root-package workflows,
root low-level helpers, or ABI-only support.
Check that committed generated output is current with:
go run ./internal/cmd/genbpf -checkUseful local checks:
make check
go test ./...
CGO_ENABLED=0 go test ./...
go run ./internal/cmd/genbpf -checkmake check runs the generator freshness check, the regular Go test suite, and
the CGO_ENABLED=0 test suite. Some runtime behavior depends on the local Linux
kernel and available BPF privileges.
This module is licensed under the Apache License, Version 2.0. See the LICENSE.