
Scrivi i tuoi programmi BPF in Go, non in C. gobee transpila un sottoinsieme di Go in BPF C e genera binding cilium/ebpf tipizzati.
Scrivi i tuoi programmi BPF in Go, non in C. gobee transpila un sottoinsieme rigoroso di Go in BPF C, genera binding Go tipizzati per il lato userspace e controlla i load rispetto al kernel in esecuzione.
L'ecosistema Go ha strumenti userspace solidi per BPF. Il lato kernel si è sempre concluso con "ora scrivi il tuo programma in C." Aya ha portato eBPF su Rust scrivendo un nuovo backend BPF in rustc. gobee ci arriva in un altro modo: transpilando in C e riusando il backend maturo di clang.
Un tracepoint che invia in streaming ogni execve allo userspace tramite un ringbuf:
| Il tuo input (Go) | Ciò che gobee genera (BPF C) |
|---|---|
|
|
gobee translate --bindings-dir ./bpf ./bpf/src produce entrambi i file, più una sourcemap (events.bpf.c.map) così gli errori del verifier vengono mappati sulle righe Go e un file di binding tipizzati (bpf/events_bindings.go) così il driver userspace scrive objs.Events, objs.AttachOnExec() e decodifica i payload del ringbuf direttamente in bpf.Event (la stessa struct che vedi sopra, ripubblicata in Go) invece di lookup coll.Programs["..."] tipizzati come stringhe.
Il C è leggibile di proposito. Se gobee emette qualcosa di strano, puoi vederlo. Per tracepoint + kprobe + XDP combinati in un unico binario, vedi example/sysmon/.
| gobee | C + clang + bpf2go | Aya (Rust) | bpftrace | BCC | |
|---|---|---|---|---|---|
| Linguaggio lato kernel | sottoinsieme di Go | C | Rust | DSL | C |
| Integrazione userspace | binding Go tipizzati + cilium/ebpf | bpf2go | aya-runtime | nessuno | python |
| CO-RE | ✅ via clang | ✅ | ✅ via LLVM | ✅ | ✅ |
| Copertura helper | 200 wrapper Go tipizzati | completo (scrivi C) | completo | limitato | completo (scrivi C) |
| Errore del verifier → sorgente | ✅ Go file:line:col | ❌ C grezzo | ✅ Rust file:line | ❌ | parziale |
| Controllo versione kernel al load | ✅ via bpfvet | manuale | manuale | n/a | runtime |
| Dipendenze toolchain | Go + clang | clang + bpf2go | rustc + LLVM | bpftrace | python + bcc |
| Artefatto generato | .bpf.o + binario Go | .bpf.o + binario Go | .bpf.o + binario Rust | JIT | JIT |
Se sei già in un workflow C / libbpf, gobee non cerca di sostituirlo del tutto. È pensato per i casi in cui vuoi il lato kernel, il lato userspace e la pipeline di build tutti in un unico modulo Go.
Vedi docs/status.md per la matrice completa (sottoinsieme di Go, statement, espressioni, ogni helper, ogni tipo di mappa, ogni direttiva). Vista rapida:
| Ambito | Copertura |
|---|---|
| Tipi di programma (8) | XDP, tracepoint, kprobe / kretprobe, uprobe / uretprobe, sock_ops, TC, cgroup_skb, LSM |
| Tipi di mappa (19) | array, hash, lru_hash, varianti per-CPU, bloom_filter, lpm_trie, ringbuf, perf_event_array, prog_array, queue, stack, storage sk/task/inode, devmap/cpumap/xskmap |
| Helper BPF | ~200 stub Go tipizzati auto-generati dagli header libbpf v1.5.0. Quelli esercitati da example/helloworld/ e example/sysmon/ sono testati in CI su kernel reale; il resto non è verificato. Apri una issue se uno stub non corrisponde alla firma del kernel |
| CO-RE | ✅ rilevato automaticamente. BPF_CORE_READ per i campi delle struct interne al kernel (task_struct, sock, inode); ctx->field diretto per le struct di contesto BPF UAPI (xdp_md, __sk_buff, bpf_sock_ops). Testato su Linux 6.x (CI Ubuntu 24.04); i kernel meno recenti non sono ancora nella matrice CI |
| Output pronto per BTF | ✅ il C emesso include vmlinux.h e usa BPF_CORE_READ per le letture dei campi interni al kernel, così il BTF che clang genera da clang -g porta le giuste rilocazioni. clang stesso resta una tua responsabilità (i Makefile di esempio mostrano l'invocazione canonica) |
| Helper definiti dall'utente | ✅ le func Go di primo livello senza //bpf:section vengono emesse come funzioni C static __always_inline |
| Binding Go tipizzati | ✅ Load<Stem>, Close, Attach<Name> per programma, AttachAll, più i tuoi tipi di struct lato kernel e le costanti ripubblicati in Go |
| Controllo versione kernel | ✅ bpfvet viene eseguito al momento del load. Fallisce rapidamente con bpf program needs kernel >= 5.8, host is 5.4 invece dell'opaco EINVAL |
| Errore del verifier → sorgente Go | ✅ annotato automaticamente dentro Load<Stem>. Nessun pipe manuale verso gobee diagnose; *ebpf.VerifierError ritorna con marcatori → counter.go:18:5 |
| Sourcemap sidecar | ✅ <stem>.bpf.c.map scritto accanto a ogni .bpf.c anche per l'uso offline di gobee diagnose |
| Cross-arch | ✅ Linux arm64 + amd64 |
go/types sul tuo input prima, così gli usi errati emergono a file:line:col).<Stem>_bindings.go tipizzato accanto al .bpf.c: bpf.LoadCounter(spec), objs.PerIface.Lookup(...), objs.AttachAll(ifindex), più i tuoi tipi di struct lato kernel e le costanti ripubblicati in Go.*ebpf.VerifierError di LoadAndAssign con posizioni nel sorgente Go, senza bisogno di pipe manuale verso gobee diagnose.Load<Stem> così i kernel vecchi falliscono rapidamente con bpf program needs kernel >= 5.8, host is 5.4.static __always_inline.cilium/ebpf. I binding generati si appoggiano su di esso.gc, il compilatore Go, non ha un backend BPF basato su LLVM. Aggiungerne uno è un progetto di compilatore pluriennale. rustc è costruito su LLVM ed è per questo che Aya funziona. Quindi gobee emette C e riusa il backend BPF di clang, che ci dà gratuitamente codegen maturo, BTF e rilocazioni CO-RE.