/ebpf
eBPF skill for Linux observability and networking. Use when writing eBPF programs with libbpf or bpftrace, attaching kprobes/tracepoints/XDP hooks, debugging verifier errors, working with eBPF maps, or achieving CO-RE portability across kernel versions. Activates on queries
$ npx -y skills add mohitmishra786/low-level-dev-skills --skill ebpf --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/ebpf
Context preview
The summary Claude sees to decide when to auto-load this skill.
eBPF skill for Linux observability and networking. Use when writing eBPF programs with libbpf or bpftrace, attaching kprobes/tracepoints/XDP hooks, debugging verifier errors, working with eBPF maps, or achieving CO-RE portability across kernel versions. Activates on queries
SKILL.md
ebpf.SKILL.mdname: ebpf
description: eBPF skill for Linux observability and networking. Use when writing eBPF programs with libbpf or bpftrace, attaching kprobes/tracepoints/XDP hooks, debugging verifier errors, working with eBPF maps, or achieving CO-RE portability across kernel versions. Activates on queries about eBPF, bpftool, bpftrace, XDP programs, libbpf, verifier errors, eBPF maps, or kernel tracing with BPF.
eBPF
Purpose
Guide agents through writing, loading, and debugging eBPF programs using libbpf, bpftrace, and bpftool. Covers map types, program types, verifier errors, XDP networking, and CO-RE portability.
Triggers
- "How do I write an eBPF program to trace system calls?"
- "My eBPF program fails with a verifier error"
- "How do I use bpftrace to trace kernel events?"
- "How do I share data between kernel eBPF and userspace?"
- "How do I write an XDP program for packet filtering?"
- "How do I make my eBPF program portable across kernel versions (CO-RE)?"
Workflow
1. Choose the right tool
Goal?
├── One-liner kernel tracing / scripting → bpftrace
├── Production eBPF program with userspace → libbpf (C) or aya (Rust)
├── Inspect loaded programs and maps → bpftool
└── High-performance packet processing → XDP + libbpf
2. bpftrace — quick kernel tracing
# Trace all execve calls with comm and args
bpftrace -e 'tracepoint:syscalls:sys_enter_execve { printf("%s %s\n", comm, str(args->filename)); }'
# Count syscalls by process
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'
# Latency histogram for read() syscall
bpftrace -e '
tracepoint:syscalls:sys_enter_read { @start[tid] = nsecs; }
tracepoint:syscalls:sys_exit_read { @us = hist((nsecs - @start[tid]) / 1000); delete(@start[tid]); }'
# List available tracepoints
bpftrace -l 'tracepoint:syscalls:*'
bpftrace -l 'kprobe:tcp_*'3. libbpf skeleton — minimal C program
// counter.bpf.c — kernel-side
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, u32);
__type(value, u64);
__uint(max_entries, 1024);
} call_count SEC(".maps");
SEC("tracepoint/syscalls/sys_enter_read")
int trace_read(struct trace_event_raw_sys_enter *ctx)
{
u32 pid = bpf_get_current_pid_tgid() >> 32;
u64 *cnt = bpf_map_lookup_elem(&call_count, &pid);
if (cnt)
(*cnt)++;
else {
u64 one = 1;
bpf_map_update_elem(&call_count, &pid, &one, BPF_ANY);
}
return 0;
}
char LICENSE[] SEC("license") = "GPL";// counter.c — userspace loader
#include "counter.skel.h"
int main(void) {
struct counter_bpf *skel = counter_bpf__open();
if (!skel || counter_bpf__load(skel))
return 1;
counter_bpf__attach(skel);
// read map, print results
counter_bpf__destroy(skel);
}# Build with libbpf 1.x
clang -g -O2 -target bpf -D__TARGET_ARCH_x86 -I/usr/include/bpf \
-c counter.bpf.c -o counter.bpf.o
bpftool gen skeleton counter.bpf.o > counter.skel.h
gcc -o counter counter.c -lbpf -lelf -lzlibbpf 1.x API changes:
// Open and load (replaces older bpf_object__open/load split patterns)
struct counter_bpf *skel = counter_bpf__open();
counter_bpf__load(skel);
counter_bpf__attach(skel);
// Or explicit file open
struct bpf_object *obj = bpf_object__open_file("counter.bpf.o", NULL);
bpf_object__load(obj);
// Skeleton generation (always via bpftool)
// bpftool gen skeleton counter.bpf.o name counter > counter.skel.h4. eBPF map types
| Map type | Key→Value | Use case | |----------|-----------|----------| | `BPF_MAP_TYPE_HASH` | arbitrary→arbitrary | Per-PID counters, state | | `BPF_MAP_TYPE_ARRAY` | u32→fixed | Config, metrics indexed by CPU | | `BPF_MAP_TYPE_PERCPU_HASH` | key→per-CPU val | High-frequency counters without locks | | `BPF_MAP_TYPE_RINGBUF` | — | Efficient kernel→userspace events | | `BPF_MAP_TYPE_PERF_EVENT_ARRAY` | — | Legacy perf event output | | `BPF_MAP_TYPE_LRU_HASH` | key→val | Connection tracking, limited size | | `BPF_MAP_TYPE_PROG_ARRAY` | u32→prog | Tail calls, program chaining | | `BPF_MAP_TYPE_XSKMAP` | — | AF_XDP socket redirection |
Use `BPF_MAP_TYPE_RINGBUF` over `PERF_EVENT_ARRAY` for new code — lower overhead, variable-size records.
5. Verifier error triage
| Error message | Root cause | Fix | |---------------|-----------|-----| | `invalid mem access 'scalar'` | Dereferencing unbounded pointer | Check pointer with null test before use | | `R0 !read_ok` | Return without setting R0 | Ensure all paths set a return value | | `jump out of range` | Branch target beyond program end | Restructure conditionals | | `back-edge detected` | Backward jump (loop) | Use `bpf_loop()` helper (kernel ≥5.17) or bounded loop | | `unreachable insn` | Dead code after return | Remove dead branches | | `invalid indirect read` | Stack read of uninitialised bytes | Zero-init structs: `struct foo x = {}` | | `misaligned stack access` | Pointer arithmetic off alignment | Align reads to `__u64` boundaries |
# Get detailed verifier log
bpftool prog load prog.bpf.o /sys/fs/bpf/prog type kprobe \
2>&1 | head -100
# Check loaded programs
bpftool prog list
bpftool prog dump xlated id 426. XDP programs
// xdp_drop_icmp.bpf.c
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
SEC("xdp")
int xdp_filter(struct xdp_md *ctx)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct ethhdr *eth = data;
if ((void *)(eth + 1) > data_end)
return XDP_PASS;
if (bpf_ntohs(eth->h_proto) != ETH_P_IP)
return XDP_PASS;
struct iphdr *ip = (void *)(eth + 1);
if ((void *)(ip + 1) > data_end)
return XDP_PASS;
if (ip->protocol == IPPROTO_ICMP)
return XDP_DROP;
return XDP_PASS;
}
char LICENSE[] SEC("license") = "GPL";# Attach XDP program to interface
ip link set dev eth0
Read more
name: ebpf description: eBPF skill for Linux observability and networking. Use when writing eBPF programs with libbpf or bpftrace, attaching kprobes/tracepoints/XDP hooks, debugging verifier errors, working with eBPF maps, or achieving CO-RE portability across kernel versions. Activates on queries about eBPF, bpftool, bpftrace, XDP programs, libbpf, verifier errors, eBPF maps, or kernel tracing with BPF.
eBPF
Purpose
Guide agents through writing, loading, and debugging eBPF programs using libbpf, bpftrace, and bpftool. Covers map types, program types, verifier errors, XDP networking, and CO-RE portability.
Triggers
- "How do I write an eBPF program to trace system calls?"
- "My eBPF program fails with a verifier error"
- "How do I use bpftrace to trace kernel events?"
- "How do I share data between kernel eBPF and userspace?"
- "How do I write an XDP program for packet filtering?"
- "How do I make my eBPF program portable across kernel versions (CO-RE)?"
Workflow
1. Choose the right tool
Goal? ├── One-liner kernel tracing / scripting → bpftrace ├── Production eBPF program with userspace → libbpf (C) or aya (Rust) ├── Inspect loaded programs and maps → bpftool └── High-performance packet processing → XDP + libbpf
2. bpftrace — quick kernel tracing
# Trace all execve calls with comm and args
bpftrace -e 'tracepoint:syscalls:sys_enter_execve { printf("%s %s\n", comm, str(args->filename)); }'
# Count syscalls by process
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'
# Latency histogram for read() syscall
bpftrace -e '
tracepoint:syscalls:sys_enter_read { @start[tid] = nsecs; }
tracepoint:syscalls:sys_exit_read { @us = hist((nsecs - @start[tid]) / 1000); delete(@start[tid]); }'
# List available tracepoints
bpftrace -l 'tracepoint:syscalls:*'
bpftrace -l 'kprobe:tcp_*'3. libbpf skeleton — minimal C program
// counter.bpf.c — kernel-side
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, u32);
__type(value, u64);
__uint(max_entries, 1024);
} call_count SEC(".maps");
SEC("tracepoint/syscalls/sys_enter_read")
int trace_read(struct trace_event_raw_sys_enter *ctx)
{
u32 pid = bpf_get_current_pid_tgid() >> 32;
u64 *cnt = bpf_map_lookup_elem(&call_count, &pid);
if (cnt)
(*cnt)++;
else {
u64 one = 1;
bpf_map_update_elem(&call_count, &pid, &one, BPF_ANY);
}
return 0;
}
char LICENSE[] SEC("license") = "GPL";// counter.c — userspace loader
#include "counter.skel.h"
int main(void) {
struct counter_bpf *skel = counter_bpf__open();
if (!skel || counter_bpf__load(skel))
return 1;
counter_bpf__attach(skel);
// read map, print results
counter_bpf__destroy(skel);
}# Build with libbpf 1.x
clang -g -O2 -target bpf -D__TARGET_ARCH_x86 -I/usr/include/bpf \
-c counter.bpf.c -o counter.bpf.o
bpftool gen skeleton counter.bpf.o > counter.skel.h
gcc -o counter counter.c -lbpf -lelf -lzlibbpf 1.x API changes:
// Open and load (replaces older bpf_object__open/load split patterns)
struct counter_bpf *skel = counter_bpf__open();
counter_bpf__load(skel);
counter_bpf__attach(skel);
// Or explicit file open
struct bpf_object *obj = bpf_object__open_file("counter.bpf.o", NULL);
bpf_object__load(obj);
// Skeleton generation (always via bpftool)
// bpftool gen skeleton counter.bpf.o name counter > counter.skel.h4. eBPF map types
| Map type | Key→Value | Use case | |----------|-----------|----------| | `BPF_MAP_TYPE_HASH` | arbitrary→arbitrary | Per-PID counters, state | | `BPF_MAP_TYPE_ARRAY` | u32→fixed | Config, metrics indexed by CPU | | `BPF_MAP_TYPE_PERCPU_HASH` | key→per-CPU val | High-frequency counters without locks | | `BPF_MAP_TYPE_RINGBUF` | — | Efficient kernel→userspace events | | `BPF_MAP_TYPE_PERF_EVENT_ARRAY` | — | Legacy perf event output | | `BPF_MAP_TYPE_LRU_HASH` | key→val | Connection tracking, limited size | | `BPF_MAP_TYPE_PROG_ARRAY` | u32→prog | Tail calls, program chaining | | `BPF_MAP_TYPE_XSKMAP` | — | AF_XDP socket redirection |
Use `BPF_MAP_TYPE_RINGBUF` over `PERF_EVENT_ARRAY` for new code — lower overhead, variable-size records.
5. Verifier error triage
| Error message | Root cause | Fix | |---------------|-----------|-----| | `invalid mem access 'scalar'` | Dereferencing unbounded pointer | Check pointer with null test before use | | `R0 !read_ok` | Return without setting R0 | Ensure all paths set a return value | | `jump out of range` | Branch target beyond program end | Restructure conditionals | | `back-edge detected` | Backward jump (loop) | Use `bpf_loop()` helper (kernel ≥5.17) or bounded loop | | `unreachable insn` | Dead code after return | Remove dead branches | | `invalid indirect read` | Stack read of uninitialised bytes | Zero-init structs: `struct foo x = {}` | | `misaligned stack access` | Pointer arithmetic off alignment | Align reads to `__u64` boundaries |
# Get detailed verifier log
bpftool prog load prog.bpf.o /sys/fs/bpf/prog type kprobe \
2>&1 | head -100
# Check loaded programs
bpftool prog list
bpftool prog dump xlated id 426. XDP programs
// xdp_drop_icmp.bpf.c
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
SEC("xdp")
int xdp_filter(struct xdp_md *ctx)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct ethhdr *eth = data;
if ((void *)(eth + 1) > data_end)
return XDP_PASS;
if (bpf_ntohs(eth->h_proto) != ETH_P_IP)
return XDP_PASS;
struct iphdr *ip = (void *)(eth + 1);
if ((void *)(ip + 1) > data_end)
return XDP_PASS;
if (ip->protocol == IPPROTO_ICMP)
return XDP_DROP;
return XDP_PASS;
}
char LICENSE[] SEC("license") = "GPL";# Attach XDP program to interface ip link set dev eth0
A curated suite of AI agent skills for systems and low-level programming — C/C++, Rust, Zig, GPU, bare-metal firmware, Linux kernel/driver development, computer architecture, compiler internals, HPC, and more.
Repo: mohitmishra786/low-level-dev-skills
Other skills on low-level-dev-skills.
- /custom-allocators
Custom allocator skill for memory allocation strategies. Use when implementing pool/slab/arena allocators, tuning jemalloc/mimalloc, writing Rust GlobalAlloc, or benchmarking allocator performance. Activates on queries about jemalloc, mimalloc, tcmalloc, arena allocator,
Open skill - /numa-programming
NUMA programming skill for multi-socket memory locality. Use when detecting NUMA topology, binding processes with numactl, using libnuma API, building NUMA-aware data structures, or measuring remote access penalties. Activates on queries about numactl, libnuma, NUMA topology,
Open skill - /af-xdp
AF_XDP skill for high-performance XDP sockets. Use when creating AF_XDP sockets, configuring UMEM and XSK rings, XDP_REDIRECT programs, copy vs zero-copy mode, or comparing with DPDK. Activates on queries about AF_XDP, xsk_umem, XDP_REDIRECT, libbpf xsk, or zero-copy XDP.
Open skill - /dpdk
DPDK skill for userspace packet I/O. Use when initializing EAL, configuring PMD drivers, using mbuf pools and rte_ring, setting up huge pages, RSS, or testpmd validation. Activates on queries about DPDK, EAL, rte_eth_rx_burst, hugepages, PMD, or testpmd.
Open skill - /io-uring
io_uring skill for Linux async I/O. Use when building high-performance servers with liburing, multi-shot operations, provided buffers, fixed files, zero-copy send, or tokio-uring. Activates on queries about io_uring, SQE/CQE, liburing, IORING_OP_PROVIDE_BUFFERS, or io_uring vs
Open skill - /adc-dac-baremetal
Bare-metal ADC and DAC skill. Use when configuring analog sampling, DMA-driven ADC, calibration, or DAC output on MCUs. Activates on queries about ADC bare-metal, sampling time, DMA ADC, or DAC channel setup.
Open skill

