
Schreiben Sie Ihre BPF-Programme in Go, nicht in C. gobee transpiliert eine Go-Teilmenge in BPF-C und generiert typisierte cilium/ebpf-Bindungen.
Schreiben Sie Ihre BPF-Programme in Go, nicht in C. gobee transpiliert eine strenge Teilmenge von Go in BPF C, generiert typisierte Go-Bindings für die Userspace-Seite und prüft das Laden gegen den laufenden Kernel.
Das Go-Ökosystem hat solide Userspace-Tools für BPF. Die Kernelseite endete immer mit „Jetzt schreibe dein Programm in C.“ Aya brachte eBPF zu Rust, indem es ein neues BPF-Backend in rustc schrieb. gobee erreicht das auf einem anderen Weg: durch Transpilieren nach C und Wiederverwendung von clangs ausgereiftem Backend.
Ein Tracepoint, der jedes execve per Ringbuf an den Userspace streamt:
| Ihre Eingabe (Go) | Was gobee ausgibt (BPF C) |
|---|---|
|
|
gobee translate --bindings-dir ./bpf ./bpf/src erzeugt beide Dateien, plus eine Sourcemap (events.bpf.c.map), damit Verifier-Fehler auf Go-Zeilen abgebildet werden, und eine typisierte Bindings-Datei (bpf/events_bindings.go), sodass der Userspace-Treiber objs.Events, objs.AttachOnExec() schreibt und Ringbuf-Nutzlasten direkt in bpf.Event decodiert (dieselbe Struktur wie oben, in Go neu veröffentlicht) anstatt string-typisierte coll.Programs["..."]-Lookups zu verwenden.
Das C ist absichtlich lesbar. Wenn gobee etwas Seltsames ausgibt, können Sie es sehen. Für Tracepoints + Kprobes + XDP in einem Binärprogramm siehe example/sysmon/.
| gobee | C + clang + bpf2go | Aya (Rust) | bpftrace | BCC | |
|---|---|---|---|---|---|
| Sprache auf Kernelseite | Go-Teilmenge | C | Rust | DSL | C |
| Userspace-Integration | typisierte Go-Bindings + cilium/ebpf | bpf2go | aya-runtime | keine | Python |
| CO-RE | ✅ über clang | ✅ | ✅ über LLVM | ✅ | ✅ |
| Helper-Abdeckung | 200 typisierte Go-Wrapper | vollständig (C schreiben) | vollständig | begrenzt | vollständig (C schreiben) |
| Verifier-Fehler → Quelle | ✅ Go file:line:col | ❌ rohes C | ✅ Rust file:line | ❌ | teilweise |
| Kernel-Versionssperre beim Laden | ✅ über bpfvet | manuell | manuell | n.v. | Laufzeit |
| Toolchain-Abhängigkeiten | Go + clang | clang + bpf2go | rustc + LLVM | bpftrace | Python + bcc |
| Generiertes Artefakt | .bpf.o + Go-Binärdatei | .bpf.o + Go-Binärdatei | .bpf.o + Rust-Binärdatei | JIT | JIT |
Wenn Sie bereits in einem C-/libbpf-Workflow arbeiten, versucht gobee nicht, ihn vollständig zu ersetzen. Es ist für Fälle gedacht, in denen Sie die Kernelseite, die Userspace-Seite und die Build-Pipeline alle in einem Go-Modul haben möchten.
Siehe docs/status.md für die vollständige Matrix (Go-Teilmenge, Anweisungen, Ausdrücke, jeder Helper, jeder Map-Typ, jede Direktive). Kurzübersicht:
| Bereich | Abdeckung |
|---|---|
| Programmtypen (8) | XDP, tracepoint, kprobe / kretprobe, uprobe / uretprobe, sock_ops, TC, cgroup_skb, LSM |
| Map-Typen (19) | array, hash, lru_hash, per-CPU variants, bloom_filter, lpm_trie, ringbuf, perf_event_array, prog_array, queue, stack, sk/task/inode storage, devmap/cpumap/xskmap |
| BPF-Helper | ~200 typisierte Go-Stubs, die automatisch aus den libbpf v1.5.0-Headern generiert werden. Diejenigen, die von example/helloworld/ und example/sysmon/ verwendet werden, werden in realem Kernel-CI getestet; der Rest ist ungeprüft. Erstellen Sie ein Issue, wenn ein Stub nicht mit der Kernel-Signatur übereinstimmt |
| CO-RE | ✅ automatisch erkannt. BPF_CORE_READ für kernelinterne Strukturfelder (task_struct, sock, inode); direktes ctx->field für UAPI-BPF-Kontextstrukturen (xdp_md, __sk_buff, bpf_sock_ops). Getestet auf Linux 6.x (Ubuntu 24.04 CI); ältere Kernel sind noch nicht in der CI-Matrix enthalten |
| BTF-fähige Ausgabe | ✅ Das ausgegebene C enthält vmlinux.h und verwendet BPF_CORE_READ für kernelinterne Feldlesungen, sodass das von clang -g erzeugte BTF die richtigen Relocationen trägt. clang selbst bleibt in Ihrer Verantwortung (die Beispiel-Makefiles zeigen den kanonischen Aufruf) |
| Benutzerdefinierte Helper | ✅ Top-Level-Go-Funktionen ohne //bpf:section werden als static __always_inline C-Funktionen ausgegeben |
| Typisierte Go-Bindings | ✅ Load<Stem>, Close, pro Programm Attach<Name>, AttachAll, sowie Ihre kernelseitigen Strukturtypen und Konstanten, die in Go neu veröffentlicht werden |
go/types über Ihre Eingabe aus, sodass Missbrauch bei file:line:col aufgedeckt wird).<Stem>_bindings.go neben der .bpf.c: bpf.LoadCounter(spec), objs.PerIface.Lookup(...), objs.AttachAll(ifindex), sowie Ihre kernelseitigen Strukturtypen und Konstanten, die in Go neu veröffentlicht werden.*ebpf.VerifierError von LoadAndAssign mit Go-Quellpositionen, kein manuelles gobee diagnose-Pipe erforderlich.Load<Stem> aus, sodass alte Kernel schnell mit bpf program needs kernel >= 5.8, host is 5.4 scheitern.static __always_inline ausgegeben werden.cilium/ebpf. Die generierten Bindings sitzen darauf.gc, der Go-Compiler, hat kein LLVM-basiertes BPF-Backend. Eines hinzuzufügen ist ein mehrjähriges Compiler-Projekt. rustc basiert auf LLVM, und deshalb funktioniert Aya. Also gibt gobee C aus und nutzt clangs BPF-Backend, was uns ausgereifte Codegenerierung, BTF und CO-RE-Relocationen kostenlos liefert.
go install github.com/boratanrikulu/gobee/cmd/gobee@latest
cd example/helloworld
make build # gobee translate, clang, go build
sudo ./helloworld eth0
Sie benötigen clang mit dem BPF-Target. Unter Linux ist das das Distributionspaket; auf macOS brew install llvm. Der Transpiler selbst ist reines Go und läuft überall.
yourproject/
├── bpf/ # Go-Paket, überall in Ihrem Projekt importierbar
│ ├── embed_amd64.go # //go:embed bin/x86/your.bpf.o
│ ├── embed_arm64.go
│ ├── your_bindings.go # generated by gobee
│ ├── bin/{x86,arm64}/your.bpf.o
│ └── src/ # kein Go-Paket; clang lebt hier
│ ├── your.go # //go:build ignore: BPF source
│ ├── your.bpf.c # generated
│ ├── Makefile # clang per arch
│ └── vmlinux.h # vendored BTF dump
├── main.go # imports yourproject/bpf
└── Makefile
Die Aufteilung hält bpf/ als sauberes importierbares Go-Paket (Go lehnt .c-Dateien in Nicht-cgo-Paketen ab). Kernelquellen und clang-Artefakte leben eine Ebene tiefer in bpf/src/.
example/helloworld/: der kanonische XDP-Paketzähler, ~40 Zeilen BPF, ~80 Zeilen Userspace.example/sysmon/: XDP, zwei Tracepoints und ein Kprobe in einem Binärprogramm, die einen Ringbuf für Ereignisse teilen. Demonstriert pro-Syscall typisierte Kontexte, benutzerdefinierte Hilfsfunktionen und die Verknüpfung AttachAll.GitHub Actions führt bei jedem Push vier Ebenen aus:
go test, go vet, Transpiler-Golden-Tests//bpf:section-Art hat mindestens ein Beispielbpfvet-Portabilitätsberichtebpf.NewCollectionWithOptions auf jedem .bpf.o (Ubuntu 24.04 Runner, Kernel 6.x)docs/design.md: Architektur und Begründungdocs/go-subset.md: akzeptierte Go-Syntax in BPF-Quelldateiendocs/directives.md: //bpf:*-Referenzdocs/status.md: Unterstützungsmatrix (Single Source of Truth).bpf.o benötigt clang mit dem BPF-Target. Apples mitgelieferter clang wird nicht damit ausgeliefert; unter macOS verwenden Sie brew install llvm oder bauen in einer Linux-VM.MIT. Siehe LICENSE.
Copyright (c) 2026 Bora Tanrikulu [email protected]
✅ bpfvet wird beim Laden ausgeführt. Scheitert schnell mit bpf program needs kernel >= 5.8, host is 5.4 anstelle von undurchsichtigem EINVAL |
| Verifier-Fehler → Go-Quelle | ✅ automatisch annotiert innerhalb von Load<Stem>. Kein manuelles Pipe zu gobee diagnose; *ebpf.VerifierError wird mit → counter.go:18:5-Markern zurückgegeben |
| Sourcemap-Beilage | ✅ <stem>.bpf.c.map wird neben jeder .bpf.c geschrieben, auch für die Offline-Nutzung mit gobee diagnose |
| Plattformübergreifend | ✅ Linux arm64 + amd64 |