
Пишите свои BPF-программы на Go, а не на C. gobee транспилирует подмножество Go в BPF C и генерирует типизированные привязки cilium/ebpf.
Пишите свои BPF-программы на Go, а не на C. gobee транслирует строгое подмножество Go в BPF C, генерирует типизированные Go-привязки для пользовательской стороны и проверяет загрузку на соответствие версии работающего ядра.
Экосистема Go имеет надежные пользовательские инструменты для BPF. Но сторона ядра всегда заканчивалась фразой «теперь напишите свою программу на C». Aya привнесла eBPF в Rust, написав новый бэкенд BPF в rustc. gobee добивается этого иначе: транслируя в C и используя зрелый бэкенд clang.
Точка трассировки, которая отправляет каждый execve в пользовательское пространство через ringbuf:
| Ваш вход (Go) | Что выдает gobee (BPF C) |
|---|---|
|
|
gobee translate --bindings-dir ./bpf ./bpf/src создает оба файла, а также sourcemap (events.bpf.c.map), чтобы ошибки проверяющего соответствовали строкам Go, и типизированный файл привязок (bpf/events_bindings.go), чтобы пользовательский драйвер писал objs.Events, objs.AttachOnExec() и декодировал полезные данные ringbuf напрямую в bpf.Event (ту же структуру, что приведена выше, переизданную в Go) вместо строковых поисков coll.Programs["..."].
C-код намеренно читаем. Если gobee выдает что-то странное, вы это видите. Пример объединения tracepoints + kprobes + XDP в один бинарник см. в example/sysmon/.
| gobee | C + clang + bpf2go | Aya (Rust) | bpftrace | BCC | |
|---|---|---|---|---|---|
| Язык для стороны ядра | Подмножество Go | C | Rust | DSL | C |
| Интеграция с пользовательским пространством | типизированные Go-привязки + cilium/ebpf | bpf2go | aya-runtime | нет | python |
| CO-RE | ✅ через clang | ✅ | ✅ через LLVM | ✅ | ✅ |
| Покрытие хелперов | 200 типизированных Go-обёрток | полное (пишите на C) | полное | ограниченное | полное (пишите на C) |
| Ошибка верификатора → исходник | ✅ Go файл:строка:столбец | ❌ сырой C | ✅ Rust файл:строка | ❌ | частично |
| Шлюзование по версии ядра при загрузке | ✅ через bpfvet | вручную | вручную | н/п | во время выполнения |
| Зависимости инструментов | Go + clang | clang + bpf2go | rustc + LLVM | bpftrace | python + bcc |
| Создаваемый артефакт | .bpf.o + Go-бинарник | .bpf.o + Go-бинарник | .bpf.o + Rust-бинарник | JIT | JIT |
Если вы уже используете рабочий процесс C / libbpf, gobee не пытается полностью его заменить. Он предназначен для случаев, когда вы хотите иметь сторону ядра, пользовательскую сторону и конвейер сборки в одном Go-модуле.
См. docs/status.md для полной матрицы (подмножество Go, операторы, выражения, каждый хелпер, каждый тип карты, каждая директива). Краткий обзор:
| Поверхность | Покрытие |
|---|---|
| Типы программ (8) | XDP, tracepoint, kprobe / kretprobe, uprobe / uretprobe, sock_ops, TC, cgroup_skb, LSM |
| Типы карт (19) | array, hash, lru_hash, варианты на CPU, bloom_filter, lpm_trie, ringbuf, perf_event_array, prog_array, queue, stack, sk/task/inode storage, devmap/cpumap/xskmap |
| Хелперы BPF | ~200 типизированных Go-заглушек, автоматически сгенерированных из заголовков libbpf v1.5.0. Те, что используются в example/helloworld/ и example/sysmon/, протестированы в CI на реальном ядре; остальные непроверены. Создайте issue, если заглушка не соответствует сигнатуре ядра |
| CO-RE | ✅ автоопределение. BPF_CORE_READ для полей внутренних структур ядра (task_struct, sock, inode); прямой ctx->field для UAPI-структур контекста BPF (xdp_md, __sk_buff, bpf_sock_ops). Протестировано на Linux 6.x (Ubuntu 24.04 CI); старые ядра пока не в матрице CI |
| BTF-готовый вывод | ✅ генерируемый C включает vmlinux.h и использует BPF_CORE_READ для чтения полей внутри ядра, так что BTF, создаваемый clang из clang -g, содержит правильные релокации. Сам clang остаётся вашей ответственностью (примеры Makefile показывают канонический вызов) |
| Пользовательские хелперы | ✅ функции Go верхнего уровня без //bpf:section генерируются как static __always_inline C-функции |
| Типизированные Go-привязки | ✅ Load<Stem>, Close, per-program Attach<Name>, AttachAll, а также типы структур и константы стороны ядра, переизданные в Go |
| Шлюзование по версии ядра | ✅ bpfvet выполняется во время загрузки. Быстро завершается с ошибкой bpf program needs kernel >= 5.8, host is 5.4 вместо непонятного EINVAL |
| Ошибка верификатора → Go-исходник | ✅ автоматически аннотируется внутри Load<Stem>. Без ручного вызова gobee diagnose; *ebpf.VerifierError возвращается с маркерами → counter.go:18:5 |
| Файл sourcemap | ✅ <stem>.bpf.c.map записывается рядом с каждым .bpf.c для офлайн-использования также через gobee diagnose |
| Кроссплатформенность | ✅ Linux arm64 + amd64 |
go/types над вашим входом, чтобы ошибки использования отображались с file:line:col).<Stem>_bindings.go рядом с .bpf.c: bpf.LoadCounter(spec), objs.PerIface.Lookup(...), objs.AttachAll(ifindex), а также типы структур и константы стороны ядра, переизданные в Go.*ebpf.VerifierError от LoadAndAssign с позициями в Go-исходнике; ручной вызов gobee diagnose не требуется.Load<Stem>, так что старые ядра быстро завершаются с bpf program needs kernel >= 5.8, host is 5.4.static __always_inline.cilium/ebpf. Сгенерированные привязки работают поверх него.