このページの目次

eBPF プログラムタイプ

カバー範囲: すべての BPF_PROG_TYPE → アタッチポイント → コンテキスト → 利用可能なヘルパー → 使用シナリオ → カーネル実装のポイント

プログラムタイプの概要

各プログラムタイプは、以下を定義します:どこにアタッチするか、コンテキスト引数の型、利用可能なヘルパー関数のホワイトリスト。

タイプアタッチポイントコンテキスト用途
XDPネットワークカードドライバの NAPI pollxdp_mdDDoS/ロードバランシング (最も早期の接触点)
SCHED_CLSTC ingress/egress__sk_buffファイアウォール/Cilium
SCHED_ACTTC アクション__sk_buffパケット変換/リダイレクト
KPROBEkprobe (関数エントリ)pt_regs観測性
TRACEPOINTtracepointtracepoint 固有の structイベント追跡
PERF_EVENTperf_event_openbpf_perf_event_dataパフォーマンスサンプリング
CGROUP_SKBcgroup egress/ingress__sk_buffコンテナネットワークポリシー
CGROUP_SOCKソケット作成/解放bpf_sockソケットオプション制御
SOCK_OPSソケット操作 (TCP ステート)bpf_sock_opsTCP 最適化/BBR ポリシー
SK_MSGソケットメッセージsk_msg_mdソケットリダイレクト
LSMLSM フックbpf_lsm_ctxセキュリティポリシー
SK_LOOKUPソケットルックアップbpf_sk_lookupソケットバインドのオーバーライド
SYSCALLシステムコールbpf_syscall_ctxシステムコールフィルタリング
STRUCT_OPS関数ポインタの置換操作固有の struct輻輳制御などの置換

主要なプログラムタイプの詳細

XDP (eXpress Data Path)

// drivers/net/ 内の各ドライバ → XDP フック → BPF プログラム
// 最も早期の処理ポイント: NAPI poll 内、sk_buff 割り当て前
// コンテキスト: struct xdp_md { data, data_end, data_meta }

// 戻り値:
enum xdp_action {
    XDP_DROP,       // ドロップ (最速!)
    XDP_PASS,       // 通過、プロトコルスタックに渡す
    XDP_TX,         // 同一ネットワークカードから送信 (ヘアピン)
    XDP_REDIRECT,   // 他のネットワークカード/CPU へリダイレクト
};

// 高速な理由:
//   - sk_buff 割り当て前に実行されるため → 割り当てオーバーヘッドゼロ
//   - ドライバ内でインライン実行されるため → 関数呼び出しオーバーヘッドなし (一部のドライバ)
//   - DROP の場合: BPF_JMP XDP_DROP → ドライバが DMA バッファを解放 → 完了

// 読み込み:
ip link set dev eth0 xdp obj xdp_drop.o sec xdp
bpftool net attach xdpdrv id <prog_id> dev eth0

kprobe / kretprobe

// 任意のカーネル関数を動的にプローブ (非安定 API!)
// kprobe: 関数エントリ → R0..R5 = 関数引数
// kretprobe: 関数戻り → R0 = 戻り値

// 制限:
//   - 関数シグネチャはバージョン間で変化する可能性がある → CO-RE は完全にはカバーしない (BTF が必要)
//   - カーネルは関数をインライン展開できる → kprobe はアタッチできない
//   - ブラックリスト: 一部の関数はプローブできない (ロック、NMI など)
//     → /sys/kernel/debug/kprobes/blacklist

// ユーザー空間プローブ (uprobe):
//   ユーザー空間関数のエントリ/戻りにアタッチ
//   → デバッグには適しているが、本番環境には不向き (オーバーヘッドが大きい)

Tracepoint

// カーネルが事前に定義した安定したプローブポイント → 関数シグネチャに依存しない
// /sys/kernel/debug/tracing/events/ ディレクトリ構造
// 各 tracepoint には特定のコンテキスト struct がある (BTF で確認可能)

// 例: sched_switch
//   コンテキスト: prev_pid, prev_comm, next_pid, next_comm, ...

// 利点:
//   - 安定した API (kprobe より信頼性が高い)
//   - BTF で完全なカバーが可能
//   - kprobe よりオーバーヘッドが低い (関数呼び出しが 1 回少ない)

// 欠点:
//   - カーネルが事前に定義したポイントのみ → kprobe より柔軟性に欠ける

CGROUP_SKB (コンテナネットワークポリシー)

アタッチポイント: cgroup v2 の egress/ingress
  → この cgroup 内のすべてのタスクのソケットトラフィックが通過する
  → コンテナの出口: アタッチポイントは cgroup net_cls 上

Cilium の中核: CGROUP_SKB を使用して以下を実現:
  - コンテナ間 L3/L4 ポリシー (トンネルなし、iptables なし)
  - IP ではなく ID ベース
  - iptables より 10 倍高速 (ハッシュルックアップ vs リニアチェーン)

LSM BPF (5.7 以降)

// security/ + BPF
// BPF プログラムが LSM フックを実装 → カーネルコードを変更せずにセキュリティポリシーをカスタマイズ可能

// bpf(BPF_PROG_LOAD, BPF_PROG_TYPE_LSM, ...)
// → LSM フックにアタッチ: bpf(BPF_RAW_TRACEPOINT_OPEN, lsm/file_open)

// 適用例:
//   - カスタム監査ポリシー
//   - Android: デバイスレベルのセキュリティポリシー
//   - コンテナセキュリティ (seccomp より柔軟)

ヘルパー利用可能性マトリックス

// すべてのヘルパーがすべてのプログラムタイプで利用可能なわけではない
// ルールはカーネルのコンパイル時に決定される: include/uapi/linux/bpf.h

// 例: bpf_skb_load_bytes() は SKB タイプでのみ利用可能
//     bpf_xdp_adjust_head() は XDP のみで利用可能
//     bpf_get_current_pid_tgid() はすべてのトレーシングタイプで利用可能

// ツール: bpftool feature probe で、現在のカーネルがサポートしているヘルパーを確認

リファレンス

  • ソースコード⁠: include/uapi/linux/bpf.h (すべてのタイプ定義)、kernel/bpf/syscall.c (ロードパス)、net/core/filter.c (ネットワーク関連ヘルパー)
  • カーネルドキュメント⁠: Documentation/bpf/libbpf/
  • Cilium BPF ドキュメント⁠: docs.cilium.io (最も優れた BPF ネットワークプラクティスのドキュメント)

キーワード: BPF_PROG_TYPE, XDP, kprobe, tracepoint, CGROUP_SKB, LSM BPF, ヘルパーホワイトリスト