
Write your BPF programs in Go, not C. gobee transpiles a Go subset to BPF C and generates typed cilium/ebpf bindings.
BPF 프로그램을 C가 아닌 Go로 작성하세요. gobee는 Go의 엄격한 부분 집합을 BPF C로 트랜스파일하고, 사용자 공간 측을 위한 타입이 있는 Go 바인딩을 생성하며, 실행 중인 커널에 대해 로드를 게이트합니다.
Go 생태계는 BPF를 위한 견고한 사용자 공간 도구를 갖추고 있습니다. 커널 측은 항상 "이제 C로 프로그램을 작성하세요"로 끝났습니다. Aya는 rustc에 새로운 BPF 백엔드를 작성하여 Rust로 eBPF를 가져왔습니다. gobee는 다른 방식으로 접근합니다: C로 트랜스파일하여 clang의 성숙한 백엔드를 재사용합니다.
링 버퍼를 통해 모든 execve를 사용자 공간으로 스트리밍하는 트레이스포인트:
| 입력 (Go) | gobee가 생성하는 것 (BPF C) |
|---|---|
|
|
gobee translate --bindings-dir ./bpf ./bpf/src는 두 파일을 모두 생성하며, 검증기 오류를 Go 라인에 매핑하는 소스맵(events.bpf.c.map)과 사용자 공간 드라이버가 문자열 기반의 coll.Programs["..."] 조회 대신 objs.Events, objs.AttachOnExec()를 작성하고 링 버퍼 페이로드를 직접 bpf.Event(위에서 본 동일한 구조체를 Go로 다시 게시한 것)로 디코딩할 수 있도록 하는 타입이 있는 바인딩 파일(bpf/events_bindings.go)을 생성합니다.
C는 의도적으로 읽기 쉽게 되어 있습니다. gobee가 이상한 것을 내보내면 볼 수 있습니다. 트레이스포인트 + kprobe + XDP가 하나의 바이너리로 결합된 예제는 example/sysmon/을 참조하세요.
이미 C / libbpf 워크플로우에 있다면 gobee가 이를 완전히 대체하려는 것은 아닙니다. 커널 측, 사용자 공간 측, 빌드 파이프라인을 모두 하나의 Go 모듈에 포함시키고 싶은 경우를 위한 것입니다.
전체 매트릭스(Go 부분 집합, 문, 표현식, 모든 헬퍼, 모든 맵 유형, 모든 지시문)는 docs/status.md를 참조하세요. 빠른 개요:
go/types를 실행하여 file:line:col에서 오용을 표시)..bpf.c 옆에 타입이 있는 <Stem>_bindings.go를 생성합니다: bpf.LoadCounter(spec), objs.PerIface.Lookup(...), objs.AttachAll(ifindex), 그리고 커널 측 구조체 유형과 상수를 Go로 다시 게시.LoadAndAssign의 *ebpf.VerifierError를 Go 소스 위치로 자동 주석 처리합니다. 수동 gobee diagnose 파이프가 필요 없음.Load<Stem> 내부에서 bpfvet를 실행하여 오래된 커널이 bpf program needs kernel >= 5.8, host is 5.4로 빠르게 실패하도록 함.static __always_inline으로 생성)를 제공합니다.cilium/ebpf를 대체하지 않습니다. 생성된 바인딩은 그 위에 있습니다.Go 컴파일러 gc는 LLVM 기반 BPF 백엔드가 없습니다. 하나를 추가하는 것은 수년이 걸리는 컴파일러 프로젝트입니다. rustc는 LLVM 위에 구축되어 있으며 이것이 Aya가 작동하는 이유입니다. 따라서 gobee는 C를 생성하고 clang의 BPF 백엔드를 재사용하여 성숙한 코드 생성, BTF, CO-RE 재배치를 무료로 얻습니다.
go install github.com/boratanrikulu/gobee/cmd/gobee@latest
cd example/helloworld
make build # gobee translate, clang, go build
sudo ./helloworld eth0
BPF 대상을 지원하는 clang이 필요합니다. Linux에서는 배포판 패키지로 제공됩니다. macOS에서는 brew install llvm을 사용하세요. 트랜스파일러 자체는 순수 Go로 작성되어 어디서나 실행됩니다.
yourproject/
├── bpf/ # Go 패키지, 프로젝트 어디서든 임포트 가능
│ ├── embed_amd64.go # //go:embed bin/x86/your.bpf.o
│ ├── embed_arm64.go
│ ├── your_bindings.go # gobee에 의해 생성됨
│ ├── bin/{x86,arm64}/your.bpf.o
│ └── src/ # Go 패키지 아님; clang이 여기에 있음
│ ├── your.go # //go:build ignore: BPF 소스
│ ├── your.bpf.c # 생성됨
│ ├── Makefile # 아키텍처별 clang
│ └── vmlinux.h # 벤더링된 BTF 덤프
├── main.go # yourproject/bpf 임포트
└── Makefile
이 분할은 bpf/를 깨끗한 임포트 가능한 Go 패키지로 유지합니다 (Go는 cgo가 아닌 패키지에서 .c 파일을 거부합니다). 커널 소스와 clang 아티팩트는 bpf/src/ 아래 한 단계 더 있습니다.
example/helloworld/: 표준 XDP 패킷 카운터, ~40줄 BPF, ~80줄 사용자 공간.example/sysmon/: 하나의 바이너리에 XDP, 두 개의 트레이스포인트, 하나의 kprobe가 포함되어 있으며 이벤트를 위해 링 버퍼를 공유합니다. 시스템 호출별 타입이 있는 컨텍스트, 사용자 정의 헬퍼 함수, AttachAll 단축키를 보여줍니다.GitHub Actions는 모든 푸시마다 네 가지 레이어를 실행합니다:
go test, go vet, 트랜스파일러 골든 테스트//bpf:section 종류에 대해 최소한 하나의 예제.bpf.o에 대한 ebpf.NewCollectionWithOptions (Ubuntu 24.04 러너, 커널 6.x)docs/design.md: 아키텍처 및 근거docs/go-subset.md: BPF 소스 파일에서 허용되는 Go 구문docs/directives.md: //bpf:* 참조docs/status.md: 지원 매트릭스 (단일 진실 공급원).bpf.o 컴파일에는 BPF 대상을 지원하는 clang이 필요합니다. Apple 번들 clang에는 포함되어 있지 않습니다. macOS에서는 brew install llvm을 사용하거나 Linux VM 내에서 빌드하세요.MIT. LICENSE를 참조하세요.
Copyright (c) 2026 Bora Tanrikulu <[email protected]>
| gobee | C + clang + bpf2go | Aya (Rust) | bpftrace | BCC |
|---|
| 커널 측 언어 | Go 부분 집합 | C | Rust | DSL | C |
| 사용자 공간 통합 | 타입이 있는 Go 바인딩 + cilium/ebpf | bpf2go | aya-runtime | 없음 | python |
| CO-RE | ✅ via clang | ✅ | ✅ via LLVM | ✅ | ✅ |
| 헬퍼 범위 | 200개의 타입이 있는 Go 래퍼 | 전체 (C 작성) | 전체 | 제한적 | 전체 (C 작성) |
| 검증기 오류 → 소스 | ✅ Go 파일:라인:컬럼 | ❌ raw C | ✅ Rust 파일:라인 | ❌ | 부분적 |
| 로드 시 커널 버전 게이트 | ✅ via bpfvet | 수동 | 수동 | 해당 없음 | 런타임 |
| 도구 체인 의존성 | Go + clang | clang + bpf2go | rustc + LLVM | bpftrace | python + bcc |
| 생성된 아티팩트 | .bpf.o + Go 바이너리 | .bpf.o + Go 바이너리 | .bpf.o + Rust 바이너리 | JIT | JIT |
| 항목 | 지원 범위 |
|---|
| 프로그램 유형 (8) | XDP, tracepoint, kprobe / kretprobe, uprobe / uretprobe, sock_ops, TC, cgroup_skb, LSM |
| 맵 유형 (19) | array, hash, lru_hash, per-CPU 변형, bloom_filter, lpm_trie, ringbuf, perf_event_array, prog_array, queue, stack, sk/task/inode storage, devmap/cpumap/xskmap |
| BPF 헬퍼 | libbpf v1.5.0 헤더에서 자동 생성된 약 200개의 타입이 있는 Go 스텁. example/helloworld/ 및 example/sysmon/에서 사용되는 것은 실제 커널 CI에서 테스트됨; 나머지는 검증되지 않음. 스텁이 커널 서명과 일치하지 않으면 이슈를 제출하세요 |
| CO-RE | ✅ 자동 감지. 커널 내부 구조체 필드(task_struct, sock, inode)에는 BPF_CORE_READ; UAPI BPF 컨텍스트 구조체(xdp_md, __sk_buff, bpf_sock_ops)에는 ctx->field 직접 접근. Linux 6.x (Ubuntu 24.04 CI)에서 테스트됨; 이전 커널은 아직 CI 매트릭스에 포함되지 않음 |
| BTF 준비 출력 | ✅ 생성된 C에는 vmlinux.h가 포함되고 커널 내부 필드 읽기에 BPF_CORE_READ를 사용하므로, clang -g에서 clang이 생성하는 BTF가 올바른 재배치를 전달함. clang 자체는 사용자 책임으로 남습니다 (예제 Makefile은 표준 호출 방법을 보여줌) |
| 사용자 정의 헬퍼 | ✅ //bpf:section이 없는 최상위 Go 함수는 static __always_inline C 함수로 생성됨 |
| 타입이 있는 Go 바인딩 | ✅ Load<Stem>, Close, 프로그램별 Attach<Name>, AttachAll, 그리고 커널 측 구조체 유형과 상수가 Go로 다시 게시됨 |
| 커널 버전 게이트 | ✅ bpfvet가 로드 시 실행됨. 불투명한 EINVAL 대신 bpf program needs kernel >= 5.8, host is 5.4로 빠르게 실패 |
| 검증기 오류 → Go 소스 | ✅ Load<Stem> 내부에서 자동으로 주석 처리됨. gobee diagnose로의 수동 파이프 없음; *ebpf.VerifierError가 → counter.go:18:5 마커와 함께 반환됨 |
| 소스맵 사이드카 | ✅ 모든 .bpf.c 옆에 <stem>.bpf.c.map이 기록되어 오프라인 gobee diagnose에서도 사용 가능 |
| 크로스 아키텍처 | ✅ Linux arm64 + amd64 |