Claude-skill-registry ebpf-cnf-scaffold
Scaffold new eBPF-based Cloud Native Network Function (CNF) projects with proper directory structure, boilerplate C kernel code, Go userspace application, bpf2go generation, and build configuration following established patterns. Use when creating new CNF examples or starting fresh eBPF projects.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/ebpf-cnf-scaffold" ~/.claude/skills/majiayu000-claude-skill-registry-ebpf-cnf-scaffold && rm -rf "$T"
skills/data/ebpf-cnf-scaffold/SKILL.mdeBPF CNF Scaffold Skill
This skill scaffolds complete eBPF-based CNF projects following the established patterns in this repository.
What This Skill Does
Creates a new eBPF CNF project with:
- Proper directory structure (
)examples/{name}/ - eBPF kernel program in Restricted C (
)bytecode/{name}.c - Go userspace application (
)main.go - bpf2go code generation setup (
)bytecode/gen.go - Go module initialization
- README with build/run instructions
- Optional Dockerfile for containerization
When to Use
- Creating a new CNF from scratch
- Adding a new example to the examples/ directory
- Starting a new eBPF networking project
- Need a working template that follows repository conventions
Project Structure Created
Basic Structure
examples/{name}/ ├── main.go # Go userspace application ├── bytecode/ │ ├── gen.go # bpf2go generation directive │ ├── {name}.c # eBPF kernel program (Restricted C) │ ├── {name}_bpfel.go # Generated (after go generate) │ └── {name}_bpfeb.go # Generated (after go generate) ├── go.mod # Go module file ├── README.md # Build and run instructions └── Dockerfile # Optional containerization
With Internal Packages
For complex CNFs, use subpackages to organize code:
examples/{name}/ ├── main.go # Entry point, CLI, event loop ├── main_test.go # Integration tests ├── bytecode/ │ ├── gen.go # bpf2go generation │ ├── vmlinux.h # Kernel types for CO-RE │ ├── {name}.c # eBPF program │ ├── {name}_bpfel.go # Generated │ └── {name}_bpfeb.go # Generated ├── {subpkg}/ # Internal package │ ├── {subpkg}.go # Core functionality │ ├── {subpkg}_test.go # Unit tests │ └── options.go # Functional options ├── go.mod └── README.md
Example from
netkit-ipv6:
examples/netkit-ipv6/ ├── main.go ├── main_test.go ├── bytecode/ │ ├── gen.go │ ├── vmlinux.h │ └── netkit_ipv6.c ├── netkit/ # Subpackage for device management │ ├── netkit.go # CreatePair, Delete │ ├── netkit_test.go │ ├── options.go # WithL2Mode, WithL3Mode │ └── ipv6.go # ConfigureIPv6LinkLocal └── go.mod
Benefits of subpackages:
- Separation of concerns (bytecode generation vs device management)
- Reusable components
- Independent unit testing
- Clearer imports in main.go
Information to Gather
Before scaffolding, ask the user:
- CNF Name: What to name the CNF (lowercase, hyphens only)
- Hook Type: Which eBPF hook to use (XDP, TC/tcx, netkit, kprobe, tracepoint)
- Functionality: Brief description of what the CNF should do
- Maps Needed: Does it need eBPF maps? (hash, array, ringbuf, etc.)
- Dockerfile: Should a Dockerfile be included?
Boilerplate Components
1. eBPF Program Template (bytecode/{name}.c)
//go:build ignore #include <linux/bpf.h> #include <bpf/bpf_helpers.h> // Add appropriate headers based on hook type // XDP: <linux/if_ether.h>, <linux/ip.h> // TC/tcx: <linux/pkt_cls.h> // netkit: <linux/if_link.h> char _license[] SEC("license") = "GPL"; SEC("{hook_section}") int {function_name}(struct {ctx_type} *ctx) { // TODO: Implement CNF logic return {return_value}; }
2. Go Generation File (bytecode/gen.go)
package bytecode //go:generate go tool bpf2go -type {types} {CapitalizedName} {name}.c -- -O2 -Wall -Werror
3. Go Userspace Application (main.go)
package main import ( "log" "os" "os/signal" "syscall" "{module}/bytecode" "github.com/cilium/ebpf" "github.com/cilium/ebpf/link" ) func main() { // Load eBPF objects spec, err := bytecode.Load{Name}() if err != nil { log.Fatalf("loading eBPF spec: %v", err) } objs := &bytecode.{Name}Objects{} if err := spec.LoadAndAssign(objs, nil); err != nil { log.Fatalf("loading eBPF objects: %v", err) } defer objs.Close() // TODO: Attach program to hook // TODO: Read from maps/ringbufs if needed log.Println("{Name} CNF is running...") // Wait for signal sig := make(chan os.Signal, 1) signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) <-sig log.Println("Shutting down...") }
4. README Template
# {Name} CNF {Description} ## Build Compile the eBPF program: ```shell go generate ./bytecode ``` Build the userspace application: ```shell go build -o {name} ``` ## Run ```shell sudo ./{name} ``` ## Test ```shell sudo -E go test . ```
Hook-Specific Configuration
XDP
- Section:
SEC("xdp") - Context:
struct xdp_md *ctx - Return values:
,XDP_PASS
,XDP_DROP
,XDP_TX
,XDP_REDIRECTXDP_ABORTED - Attach:
link.AttachXDP()
TC/tcx (Kernel 6.6+)
- Section:
orSEC("tc")
/SEC("tcx/ingress")SEC("tcx/egress") - Context:
struct __sk_buff *skb - Return values:
,TC_ACT_OK
,TC_ACT_SHOT
,TC_ACT_REDIRECTTC_ACT_PIPE - Attach:
for tcx,link.AttachTCX()
for legacylink.AttachTC()
netkit (BPF-programmable network device)
- Section:
andSEC("netkit/primary")SEC("netkit/peer") - Context:
struct __sk_buff *skb - Return values:
,NETKIT_PASS
,NETKIT_DROPNETKIT_REDIRECT - Attach:
withlink.AttachNetkit()
orebpf.AttachNetkitPrimaryebpf.AttachNetkitPeer - Note: Requires two programs (primary and peer) for bidirectional processing
kprobe/kretprobe
- Section:
orSEC("kprobe/function_name")SEC("kretprobe/function_name") - Context:
struct pt_regs *ctx - Return value:
0 - Attach:
orlink.Kprobe()link.Kretprobe()
tracepoint
- Section:
SEC("tracepoint/category/name") - Context: Custom struct based on tracepoint
- Return value:
0 - Attach:
link.Tracepoint()
Go Module Initialization
After creating the structure, initialize the Go module:
cd examples/{name} go mod init github.com/{username}/xcnf/examples/{name} go get -tool github.com/cilium/ebpf/cmd/bpf2go go mod tidy
Post-Scaffold Instructions
After scaffolding, remind the user to:
-
Enter the Linux VM (if using OrbStack):
orb -
Generate vmlinux.h (for CO-RE programs):
cd examples/{name}/bytecode bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h -
Generate eBPF bytecode:
cd examples/{name} go generate ./bytecode -
Implement the CNF logic in:
- kernel-space processingbytecode/{name}.c
- userspace control and data handlingmain.go
-
Build and test:
go build -o {name} sudo ./{name}
Best Practices
- Use meaningful variable names that describe the CNF's purpose
- Add TODO comments for areas that need implementation
- Include bounds checking for all packet data access
- Use appropriate helper functions (
for debugging)bpf_printk - Follow the existing patterns in the repository
- Add proper error handling in Go code
- Use
for cleanup (Close(), link cleanup)defer
Example Usage
User: "Create a new CNF called 'rate-limiter' that uses XDP to rate limit incoming packets"