gobee
- title
- gobee
- type
- toolbox
- summary
- Go-to-BPF-C transpiler that reuses clang's BPF backend and generates typed cilium/ebpf bindings
- tags
- go, ebpf, bpf, transpiler, kernel, linux
- language
- Go
- license
- MIT
- created
- 2026-05-22
- updated
- 2026-05-22
Bora Tanrıkulu's Go-to-BPF-C transpiler. Write your kernel-side BPF program in a strict subset of Go; gobee emits BPF C, runs clang, and generates typed Go bindings so the userspace driver works in terms of your own structs and program names instead of stringly-typed coll.Programs["..."] lookups.
The structural decision is the interesting part. Aya (Rust eBPF) gets there by adding a new BPF backend to rustc — feasible because rustc is built on LLVM. The Go compiler gc isn't, so adding a BPF backend would be a multi-year compiler project. gobee skips that work by emitting C and reusing clang's mature BPF backend, which gets you CO-RE, BTF, and verifier-friendly codegen for free. The cost is that clang stays in the user's toolchain.
How it works
Pipeline:
- Type-check.
go/typesruns over the input first so misuses surface at Gofile:line:col, not somewhere downstream in clang's error stream. - Transpile.
gobee translate --bindings-dir ./bpf ./bpf/srcproduces three artifacts per kernel source:<stem>.bpf.c, a sourcemap<stem>.bpf.c.map, and a typed<stem>_bindings.go. - Compile. User runs clang to produce
<stem>.bpf.o. Same Makefile pattern as bpf2go. - Load. The generated
Load<Stem>function calls intocilium/ebpfand runs bpfvet inside it. If the host kernel's too old for any helper the program uses, load fails fast withbpf program needs kernel >= 5.8, host is 5.4instead of opaqueEINVAL. If the verifier rejects the program, the returned*ebpf.VerifierErroris auto-annotated with→ counter.go:18:5markers pointing back to the Go source.
The emitted C is readable on purpose — when gobee emits something weird, you can see it.
Surface coverage
8 program types (XDP, tracepoint, kprobe/kretprobe, uprobe/uretprobe, sock_ops, TC, cgroup_skb, LSM). 19 map types including ringbuf, perf_event_array, sk/task/inode storage, devmap/cpumap/xskmap. About 200 typed Go stubs auto-generated from libbpf v1.5.0 headers — the ones exercised by example/helloworld/ and example/sysmon/ are tested in real-kernel CI; the rest are unverified.
User-defined helper functions: top-level Go funcs without //bpf:section are emitted as static __always_inline C functions.
CO-RE is auto-detected — BPF_CORE_READ for kernel-internal struct fields (task_struct, sock, inode), direct ctx->field access for UAPI BPF context structs (xdp_md, __sk_buff, bpf_sock_ops). Exercised on Linux 6.x (Ubuntu 24.04 CI); older kernels not yet in the CI matrix. Cross-arch: Linux arm64 + amd64.
What it explicitly won't do
- Replace clang. Reimplementing clang's BPF backend would cost years and gain nothing.
- Replace
cilium/ebpf. The generated bindings sit on top of it. - Hide BPF. The Go subset maps 1:1 to BPF C idioms. If you know BPF, gobee is thin sugar; if you don't, the manual is still required reading.
- Run clang for you. Compile, embed, and load remain user-owned — same pattern as
bpf2go.
Where it fits
Same author as gecit and bpfvet; gobee uses bpfvet at load time and gecit demonstrates the kind of in-kernel networking BPF program (sock_ops SNI desync) gobee is aimed at making more pleasant to write. See bora-blog for the author's writing on this space.
For sandboxing context — the layer where this matters operationally — see ebpf-sock-ops and sandboxing-ai-agents (Layer 1 / kernel boundary discussion). Compare-and-contrast tools: bpf2go (the C+clang baseline) and Aya (Rust via rustc BPF backend).
Limitations
- macOS/Windows: gobee itself runs (pure Go), but compiling
.bpf.oneeds clang with the BPF target — Apple's bundled clang doesn't ship it, sobrew install llvmor a Linux VM is required. - Running the artifact: Linux on arm64 or amd64.
- Helper coverage outside the CI examples is unverified; expect issues on niche kernel helpers until the matrix expands.
Repo
github.com/boratanrikulu/gobee · 25★ at ingest · MIT · created 2026-05-01.