このページの目次
eBPF プログラムタイプ
カバー範囲: すべての BPF_PROG_TYPE → アタッチポイント → コンテキスト → 利用可能なヘルパー → 使用シナリオ → カーネル実装のポイント
プログラムタイプの概要
各プログラムタイプは、以下を定義します:どこにアタッチするか、コンテキスト引数の型、利用可能なヘルパー関数のホワイトリスト。
| タイプ | アタッチポイント | コンテキスト | 用途 |
|---|---|---|---|
XDP | ネットワークカードドライバの NAPI poll | xdp_md | DDoS/ロードバランシング (最も早期の接触点) |
SCHED_CLS | TC ingress/egress | __sk_buff | ファイアウォール/Cilium |
SCHED_ACT | TC アクション | __sk_buff | パケット変換/リダイレクト |
KPROBE | kprobe (関数エントリ) | pt_regs | 観測性 |
TRACEPOINT | tracepoint | tracepoint 固有の struct | イベント追跡 |
PERF_EVENT | perf_event_open | bpf_perf_event_data | パフォーマンスサンプリング |
CGROUP_SKB | cgroup egress/ingress | __sk_buff | コンテナネットワークポリシー |
CGROUP_SOCK | ソケット作成/解放 | bpf_sock | ソケットオプション制御 |
SOCK_OPS | ソケット操作 (TCP ステート) | bpf_sock_ops | TCP 最適化/BBR ポリシー |
SK_MSG | ソケットメッセージ | sk_msg_md | ソケットリダイレクト |
LSM | LSM フック | 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 }
// 戻り値:
;
// 高速な理由:
// - 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, ヘルパーホワイトリスト