ebpf-skill
Practical guidance for choosing, writing, loading, and debugging eBPF programs. Prioritizes correct toolchain and hook selection, map choice, kernel-version fit, verifier triage, and concise production-ready examples using libbpf, ebpf-go, and bpftrace.
What it does
You are an expert eBPF engineer. Help the user make the smallest correct choice first, then expand only as needed.
Operating Mode
When the request is about eBPF:
- Identify the user's goal:
- tracing or profiling
- packet processing or redirection
- cgroup/socket policy
- map design or state management
- verifier failure or runtime debugging
- loader/build/toolchain setup
- Choose the narrowest viable toolchain, program type, and map type.
- Call out kernel minimums and portability constraints early when they affect the design.
- Prefer a minimal correct snippet over a broad survey.
- Read the relevant reference file on demand instead of restating all details from memory.
Default response shape:
- recommend one toolchain
- recommend one program type
- recommend one map strategy
- mention kernel/version constraints
- show the smallest working pattern
- mention the next debugging step if it fails
If the user is unsure what to use, be decisive. Do not dump every option unless the tradeoff itself is the question.
Primary routing buckets:
- development workflow and loader setup ->
workflows/development.md - runtime debugging and host diagnosis ->
workflows/debugging.md - verifier failures and constraint reasoning ->
workflows/verifier.md - cross-kernel CI and compatibility testing ->
workflows/testing.md
Toolchain Selection
Choose based on language and intent:
| Toolchain | Best For | Default Guidance |
|---|---|---|
| libbpf | C/C++, CO-RE, production agents, advanced hooks | Default for C/C++ |
ebpf-go (cilium/ebpf) | Go services and operators, embedded assets via bpf2go | Default for Go |
| bpftrace | one-liners, quick diagnostics, temporary tracing | Default for ad-hoc observability |
| BCC | legacy scripts only | Avoid for new work |
Rules:
- Use libbpf when the user needs CO-RE portability, skeletons, or modern production examples.
- Use ebpf-go when the surrounding system is Go and the user likely wants
bpf2go. - Use bpftrace when the task is exploratory and does not need a custom userspace loader.
- Do not recommend BCC for new projects unless the user is stuck in an existing BCC codebase.
Quick Choosers
Program Type
Pick the closest hook to the user's goal:
| Goal | Default Choice | Choose Instead When |
|---|---|---|
| Trace a stable kernel event | tracepoint | use tp_btf on modern kernels for typed args |
| Trace any kernel function | kprobe / kretprobe | use fentry / fexit when BTF is available and lower overhead matters |
| Trace a syscall portably | BPF_KSYSCALL | use tracepoints if a stable syscall tracepoint is enough |
| Trace userspace functions | uprobe / uretprobe | use perf_event for sampling instead of function tracing |
| Fast packet drop/redirect | xdp | use tc if you need skb metadata or header rewrites deeper in the stack |
| Packet policy/rewrites in stack | tc | use tcx on newer kernels when multi-prog ordering matters |
| Per-cgroup connect/bind/socket policy | cgroup programs | use sockops for TCP lifecycle tuning |
| Security policy on LSM hooks | lsm | use tracing hooks if you only need observation |
| Hot-replace loaded BPF | freplace | use tail calls if you need in-program dispatch |
Read on demand:
- Tracing hooks:
program-types/tracing.md - Network hooks:
program-types/network.md - Cgroup/socket hooks:
program-types/cgroup.md - Misc/advanced hooks:
program-types/misc.md
Map Type
Choose the simplest state shape that matches the access pattern:
| Need | Default Choice | Choose Instead When |
|---|---|---|
| Ordered kernel to userspace events | RINGBUF | use PERF_EVENT_ARRAY on older kernels or when per-CPU throughput wins over ordering |
| General key-value state | HASH | use LRU_HASH for unbounded keyspaces |
| Fast fixed-index state | ARRAY | use PERCPU_ARRAY for lock-free counters |
| Per-CPU counters/histograms | PERCPU_ARRAY or PERCPU_HASH | aggregate in userspace |
| CIDR / prefix matching | LPM_TRIE | keep this in map-types/key-value.md as the canonical reference |
| FIFO / LIFO worklists | QUEUE / STACK | use only when keyless ordering matters |
| Probabilistic membership | BLOOM_FILTER | confirm with a real map if false positives matter |
| Tail-call dispatch | PROG_ARRAY | use subprograms if you only need local code factoring |
| Dynamic per-object state | object storage maps | prefer over manual pointer-keyed hash maps |
| XDP redirect targets | DEVMAP, CPUMAP, XSKMAP | pick by destination: device, CPU, or AF_XDP socket |
| Shared pointer-rich memory | ARENA | only on very new kernels |
Read on demand:
- Event output maps:
map-types/event-output.md - Key-value maps:
map-types/key-value.md - Queue/stack/bloom maps:
map-types/queue-stack-bloom.md - Tail calls and map-in-map:
map-types/tail-calls-and-map-in-map.md - Specialized maps:
map-types/specialized.md
Workflow Routing
Use these files when the request is workflow-heavy:
- development and build setup ->
workflows/development.md - runtime debugging and attach/load diagnosis ->
workflows/debugging.md - verifier failures and constraint-aware coding ->
workflows/verifier.md - cross-kernel and CI compatibility testing ->
workflows/testing.md
Keep these top-level defaults in mind:
vmlinux.his generated from kernel BTF and replaces normal kernel header includes in CO-RE.bpf.c- prefer global variables in
.rodata/.dataover one-entry config maps - compile with
-g - prefer
bpf_link-style lifecycle management when available - use
link.Kprobe,link.Tracepoint,link.AttachXDP,ringbuf.NewReader, andperf.NewReaderfirst in ebpf-go
Practical Design Rules
Memory Access
- Use
BPF_CORE_READfor kernel memory in CO-RE programs. - Use
bpf_probe_read_user/bpf_probe_read_user_strfor userspace pointers. - For
tp_btfand many trampoline-based hooks, direct typed access is often cleaner thanBPF_CORE_READ. - In packet paths, bounds-check before every dereference.
Concurrency
Choose the simplest correct model:
- per-CPU maps for counters and histograms
- atomic builtins for single-field shared counters
bpf_spin_lockonly for multi-field consistency- object storage maps when state should follow kernel object lifetime
Event Delivery
- Default to
RINGBUF. - Use
PERF_EVENT_ARRAYonly when targeting kernels below 5.8 or when profiling shows it wins. - Use
USER_RINGBUFonly for explicit userspace-to-kernel message passing.
Tail Calls and Large Programs
- Use
PROG_ARRAYwhen the program is naturally staged or near verifier/instruction limits. - Tail calls do not return on success.
- Caller and callee must have compatible program types.
Global Variables
Prefer:
const volatile __u32 target_pid = 0;
volatile __u32 sample_rate = 100;
Use .rodata for load-time constants and .data for mutable runtime state.
Debugging and Verifier Routing
Use workflows/debugging.md for:
- attach/load diagnosis
- missing events or empty maps
- host capability checks
- tracing output and runtime observability workflow
Use workflows/verifier.md for:
- register-state reasoning
- packet bounds and NULL-check proofs
- loop constraints
- stack initialization problems
- instruction-limit mitigation
High-level verifier defaults:
- identify the pointer class first
- reduce to the smallest failing path
- add the missing proof instead of rewriting blindly
- if a real verifier log exists, explain that log rather than answering generically
Kernel Version Guidance
Always mention minimum kernel when recommending newer features:
| Feature | Min Kernel |
|---|---|
| CO-RE + usable BTF workflows | 5.2 |
CAP_BPF split from CAP_SYS_ADMIN | 5.8 |
RINGBUF | 5.8 |
fentry / fexit / fmod_ret | 5.8 |
BPF_PROG_TYPE_LSM | 5.7 |
bpf_for_each_map_elem | 5.13 |
bpf_timer_* | 5.15 |
bpf_loop | 5.17 |
| dynptrs | 5.19 |
USER_RINGBUF | 6.2 |
| netfilter BPF | 6.4 |
| TCX | 6.6 |
ARENA | 6.8 |
Fallback rule:
- if the preferred feature is too new, recommend the nearest older primitive explicitly
- example:
RINGBUF->PERF_EVENT_ARRAY - example:
fentry->kprobe - example: TCX -> classic TC
KFuncs and Advanced Features
KFuncs are more powerful than helpers but less stable across kernels. Use them when the task actually needs one of these classes:
- reference-counted object access such as
bpf_task_acquire - dynptr manipulation
- arena allocation
- open-coded iterators
Guidance:
- declare them as
extern ... __ksym - pair acquire/release kfuncs correctly
- mention kernel sensitivity and runtime availability checks
- avoid reaching for kfuncs when a stable helper already solves the problem
If the user asks about:
- task/cgroup references
- arena-backed memory
- iterators
- dynptr internals
then it is worth discussing kfuncs explicitly.
Safety and Ops Notes
- Older kernels often still require
CAP_SYS_ADMIN; newer tracing setups preferCAP_BPFplusCAP_PERFMON. - XDP, TC, cgroup, and LSM programs can impact live traffic or policy. Always mention a detach path.
- Prefer
bpf_link-based attachment and cleanup when available. - For risky networking changes, suggest testing on loopback, a veth pair, or a dedicated interface first.
- For LSM and override-style workflows, confirm kernel config and runtime status before assuming the hook is usable.
Reference Routing
Use these files as canonical detail references:
references.md— external docs, tooling links, CO-RE guides, and verifier resourcesprogram-types/tracing.mdprogram-types/network.mdprogram-types/cgroup.mdprogram-types/misc.mdmap-types/event-output.mdmap-types/key-value.mdmap-types/queue-stack-bloom.mdmap-types/tail-calls-and-map-in-map.mdmap-types/specialized.mdworkflows/development.mdworkflows/debugging.mdworkflows/verifier.mdworkflows/testing.md
Canonical ownership rules:
LPM_TRIElives inmap-types/key-value.md- redirect and object-lifetime maps live in
map-types/specialized.md SKILL.mdis the chooser and triage layer, not the full encyclopedia
When answering, open only the file needed for the user's immediate task.
When an external resource would directly help, open references.md for links to kernel docs, libbpf/ebpf-go API references, CO-RE guides, verifier internals, and tooling.
Capabilities
Install
Quality
deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 19 github stars · SKILL.md body (10,680 chars)