mcpField
E
ebpf

ebpf

github.com/mohitmishra786開発269629 回インストール18 週間前に更新
リポジトリ

ebpf について

eBPFプログラムの作成、ロード、デバッグを行うエージェント向けのスキルです。libbpf、bpftrace、bpftool、XDP、CO-REを扱います。

主な機能

  1. 01bpftrace によるカーネルイベント追跡
  2. 02libbpf による eBPF プログラムの構築
  3. 03eBPF map によるデータ共有
  4. 04verifier エラーの診断
  5. 05XDP ネットワークプログラムの作成
  6. 06CO-RE によるカーネル間の移植性向上

活用シーン

  1. 01システムコールやカーネルイベントの追跡
  2. 02eBPF verifier のロード失敗の調査
  3. 03カーネルとユーザー空間間のイベント転送
  4. 04XDP パケットフィルタリングプログラムの構築

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill ebpf

インストール後、Claude Code で/ebpfを入力して読み込まれたか確認します。

同梱ファイルreferences/ebpf-map-types.md

詳細

eBPF

目的

libbpf、bpftrace、bpftool を使用して eBPF プログラムを作成、ロード、デバッグする方法をエージェントに案内します。マップタイプ、プログラムタイプ、ベリファイアエラー、XDP ネットワーキング、CO-RE による移植性について説明します。

トリガー

  • 「システムコールをトレースする eBPF プログラムはどう書けばよいですか?」
  • 「eBPF プログラムでベリファイアエラーが発生します」
  • 「カーネルイベントのトレースに bpftrace を使うにはどうすればよいですか?」
  • 「カーネル内の eBPF とユーザー空間の間でデータを共有するにはどうすればよいですか?」
  • 「パケットフィルタリング用の XDP プログラムはどう書けばよいですか?」
  • 「カーネルのバージョン間で eBPF プログラムを移植可能にするにはどうすればよいですか(CO-RE)?」

ワークフロー

1. 適切なツールを選ぶ
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 — カーネルを手早くトレースする
# 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 スケルトン — 最小限の C プログラム
// 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 -lz

libbpf 1.x の API 変更点:

// 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.h
4. eBPF マップタイプ
マップタイプキー→値用途
BPF_MAP_TYPE_HASH任意→任意PID ごとのカウンター、状態
BPF_MAP_TYPE_ARRAYu32→固定設定、CPU ごとにインデックス化されたメトリクス
BPF_MAP_TYPE_PERCPU_HASHキー→CPU ごとの値ロックなしの高頻度カウンター
BPF_MAP_TYPE_RINGBUF—効率的なカーネル→ユーザー空間イベント
BPF_MAP_TYPE_PERF_EVENT_ARRAY—レガシーな perf イベント出力
BPF_MAP_TYPE_LRU_HASHキー→値接続追跡、サイズ制限あり
BPF_MAP_TYPE_PROG_ARRAYu32→プログラムテールコール、プログラムの連鎖
BPF_MAP_TYPE_XSKMAP—AF_XDP ソケットへのリダイレクト

新しいコードでは PERF_EVENT_ARRAY よりも BPF_MAP_TYPE_RINGBUF を使用してください。オーバーヘッドが低く、可変サイズのレコードを扱えます。

5. ベリファイアエラーの切り分け
エラーメッセージ根本原因修正方法
invalid mem access 'scalar'範囲が限定されていないポインターの参照使用前に null チェックでポインターを検証する
R0 !read_okR0 を設定せずに戻っているすべての経路で戻り値を設定する
jump out of range分岐先がプログラムの終端を超えている条件分岐を組み直す
back-edge detected後方へのジャンプ(ループ)bpf_loop() ヘルパー(カーネル ≥5.17)または回数が制限されたループを使う
unreachable insnreturn 後のデッドコードデッドブランチを削除する
invalid indirect read初期化されていないバイトをスタックから読み取っている構造体をゼロ初期化する:struct foo x = {}
misaligned stack accessポインター演算によるアラインメントのずれ読み取りを __u64 境界に合わせる
# 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 42
6. XDP プログラム
// 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 xdp obj xdp_drop_icmp.bpf.o sec xdp
# Remove
ip link set dev eth0 xdp off
# Use native (driver) mode for best performance
ip link set dev eth0 xdp obj prog.bpf.o sec xdp mode native

XDP の戻りコード:XDP_PASS、XDP_DROP、XDP_TX(ヘアピン)、XDP_REDIRECT。

7. CO-RE — 一度コンパイルすれば、どこでも実行

CO-RE(Compile Once - Run Everywhere)は BTF 型情報を使い、ロード時にフィールドアクセスを再配置します。

// Use BTF-based field access (CO-RE aware)
#include <vmlinux.h>        // generated from running kernel's BTF
#include <bpf/bpf_core_read.h>

SEC("kprobe/tcp_connect")
int trace_connect(struct pt_regs *ctx)
{
    struct sock *sk = (struct sock *)PT_REGS_PARM1(ctx);
    u16 dport = BPF_CORE_READ(sk, __sk_common.skc_dport);
    // BPF_CORE_READ relocates the field offset at load time
    bpf_printk("connect to port %d\n", bpf_ntohs(dport));
    return 0;
}
# Generate vmlinux.h from running kernel
bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

# Verify BTF is enabled
ls /sys/kernel/btf/vmlinux
8. BPF リングバッファと perf バッファの比較
// Ring buffer (preferred for new programs — better perf, no per-CPU loss)
struct {
    __uint(type, BPF_MAP_TYPE_RINGBUF);
    __uint(max_entries, 256 * 1024);
} rb SEC(".maps");

SEC("kprobe/sys_open")
int handle_open(struct pt_regs *ctx)
{
    struct event *e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0);
    if (!e)
        return 0;
    e->pid = bpf_get_current_pid_tgid() >> 32;
    bpf_ringbuf_submit(e, 0);
    // bpf_ringbuf_discard(e, 0) on error paths
    return 0;
}
特徴リングバッファperf バッファ
APIbpf_ringbuf_reserve/submitbpf_perf_event_output
バックプレッシャー満杯の場合、reserve は失敗するイベントがドロップされる場合がある
ユーザー空間ring_buffer__poll(libbpf)perf_buffer__poll
マルチプロデューサー対応CPU ごとのバッファ
9. BPF イテレーター
struct {
    __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
    __uint(max_entries, 1);
} iter_prog SEC(".maps");

SEC("iter/task")
int dump_tasks(struct bpf_iter__task *ctx)
{
    struct task_struct *task = ctx->task;
    if (task)
        bpf_seq_printf(ctx->meta->seq, "%d %s\n", task->tgid, task->comm);
    return 0;
}
# Read iterator output from userspace
bpftool prog tracelog   # or attach iter to seq_file reader
cat /sys/kernel/debug/tracing/trace_pipe

イテレーターは、要素ごとの kprobe オーバーヘッドなしで、カーネルのデータ構造(タスク、マップ、TCP ソケット)を走査します。

10. BPF アトミック操作
// GCC/Clang atomic builtins in BPF programs (kernel 5.12+)
static __always_inline void inc_counter(__u32 *counter)
{
    __sync_fetch_and_add(counter, 1);
}

// Use for per-CPU or map-backed counters under concurrent probes

高頻度カウンターには CPU ごとの配列マップを優先し、単一のマップ値に集約する場合はアトミック操作を使用してください。

マップタイプの全リファレンスについては、references/ebpf-map-types.md を参照してください。

関連スキル

  • Aya フレームワークを使った Rust eBPF プログラムには skills/observability/ebpf-rust を使用してください
  • eBPF を使わずに perf ベースのトレースを行うには skills/profilers/linux-perf を使用してください
  • seccomp-bpf によるシステムコールのフィルタリングには skills/runtimes/binary-hardening を使用してください
  • カーネルモジュールの開発には skills/low-level-programming/linux-kernel-modules を使用してください
  • XDP_REDIRECT を AF_XDP ソケットにリダイレクトするには skills/async-io/af-xdp を使用してください

コメント