eBPFとXDPによるパケット処理
カーネル改造もモジュール開発も不要で、NIC直後の超高速フックにロードバランサやDDoS対策を安全に差し込める理由が原理から分かる。
- 1.eBPFはカーネル内の仮想マシンで、検証器がループ禁止・メモリ境界・型を静的解析して安全性を保証したうえでJITネイティブコードとして実行するため、カーネル改造なしに拡張できる。
- 2.XDPはNICドライバの受信直後、`sk_buff` 生成前の最速フックでeBPFを実行し、`XDP_DROP`/`XDP_TX`/`XDP_REDIRECT` 等の即時判定によりDDoS対策やロードバランサを数千万pps級で処理できる。
- 3.フック位置がTC/ソケットより手前にあるほど速いが扱える情報は少なく、ドロップ判定はXDPで即座に、複雑な状態管理はTCやソケット層のeBPFに委ねる階層設計が実務の定石となる。
カーネルを改造せずに拡張する発想
カーネルのパケット処理を変えたい場合、従来は専用のカーネルモジュールを書くか、カーネル本体にパッチを送るしかありませんでした。モジュールはクラッシュすればカーネルごと落ち、任意のコードを特権モードで実行できてしまう危険もあります。eBPF(extended Berkeley Packet Filter) はこの問題を、「カーネル内に小さな仮想マシンを用意し、検証済みのプログラムだけを安全に実行させる」方式で解決します。ユーザーが書いたプログラムはバイトコードへコンパイルされ、カーネルにロードされる際に**検証器(verifier)**の静的解析を通過して初めて実行が許可されます。
eBPFの前身BPFはtcpdumpのパケットフィルタ用でしたが、eBPFは汎用の命令セットとフック機構へ拡張されており、パケット処理だけでなくトレーシング(kprobe)、セキュリティポリシー、性能計測など幅広く使われます。本稿ではネットワーク用途に絞ります。
検証器:安全性を静的解析で保証する
検証器はロード時にプログラムのCFG(制御フローグラフ)を辿り、次のような性質を機械的に確認します。ループの禁止(有界ループを除き無限ループになり得る構造を拒否し、カーネルをハングさせない)、メモリアクセスの境界チェック(パケットバッファやスタックへのアクセスがすべて範囲内に収まると証明できない場合は拒否)、未初期化メモリの読み出し禁止、スタックサイズの上限、到達可能な全パスでの終了保証です。これらすべてを満たして初めて、プログラムはJIT(Just-In-Time)コンパイラによりCPUネイティブの機械語へ変換され、通常のカーネルコードと同等の速度で実行されます。
ユーザー: eBPFプログラム(Cのサブセットで記述)
↓ clang/LLVM でコンパイル
バイトコード(eBPF命令列)
↓ bpf() システムコールでロード要求
検証器: CFG解析・境界チェック・ループ検出・終了保証
↓ 合格のみ通過
JIT: ネイティブ機械語へ変換
↓
カーネル内で実行(フックに接続)
検証器は保守的です。安全だが複雑すぎて検証器が追い切れないプログラムは、実際には問題なくても拒否されます。ループが必要な場合は「有界ループ」(コンパイル時に上限回数が確定するもの)かbpf_loop()ヘルパーを使うなど、検証器が解析できる形に書き直す必要があります。
プログラムはカーネル内の任意のメモリへ自由にアクセスできるわけではなく、ヘルパー関数(bpf_map_lookup_elem()など、カーネルが提供する限定APIの集合)を通してのみカーネルの状態とやり取りします。ユーザー空間とのデータ共有にはeBPFマップ(ハッシュテーブルや配列としてカーネル・ユーザー双方から読み書きできる領域)を使い、統計情報やロードバランサの転送テーブルなどはここに置かれます。
XDP:NIC直後の最速フック
**XDP(eXpress Data Path)**は、NICドライバがパケットを受け取った直後、Linuxの標準的なパケット表現であるsk_buff(ソケットバッファ構造体)を生成するより前の段階でeBPFプログラムを実行するフックです。sk_buffの確保はフィールドが多く重い処理で、カーネルのパケット受信経路:NAPI と割り込み緩和 で説明される受信パイプラインの入口でもコストがかかります。XDPはこの手前で動くため、後続のスタック処理を丸ごと省略できるパケットに対しては極めて低いオーバーヘッドで判定を下せます。
XDPプログラムは処理の結果として次のいずれかの**戻り値(アクション)**を返し、カーネルはそれに従います。
| アクション | 動作 | 典型用途 |
|---|---|---|
| XDP_DROP | 即座に破棄、以降の処理は一切なし | DDoS対策(悪性パケットの遮断) |
| XDP_PASS | 通常のカーネルスタックへ渡す | 正当なトラフィックの通常処理 |
| XDP_TX | 受信したNICへそのまま送り返す | 低遅延な応答・パケット反射 |
| XDP_REDIRECT | 別NIC/CPU/AF_XDPソケットへ転送 | ロードバランシング・コンテナ間転送 |
| XDP_ABORTED | エラーとして破棄(トレース記録) | デバッグ・異常検知 |
XDP_DROPが特に強力なのは、破棄判定にかかるコストが「NICのリングからパケットを見て条件を評価する」だけで済み、sk_buff確保・スタック通過・ソケットへのコピーといった通常経路のコストが一切発生しない点です。これにより1コアで数千万pps級のドロップ性能が実現し、大量の攻撃パケットを浴びせるDDoS攻撃に対して、正規トラフィックへの影響を最小化しながら攻撃パケットだけを最上流で捨てられます。関連する増幅型の攻撃像は DNS/NTPリフレクション増幅DDoS攻撃の原理 で扱っています。
XDPには(1)ドライバがXDPをネイティブサポートするネイティブモード(最速)、(2)NICが未対応でも汎用パスで動く汎用(generic)モード(sk_buff生成後に動くため速度は劣るが互換性は高い)、(3)NIC自体がXDPプログラムをオフロード実行するオフロードモード(CPUを一切使わない)があります。性能を最大化するにはネイティブモードかオフロードモードが前提です。
フック位置と性能特性のトレードオフ
eBPFはXDP以外にも複数の位置にフックできます。フックが**パケット経路の上流(NICに近い側)**にあるほど、扱える情報は少ない代わりに処理コストが小さく、下流に行くほど情報は豊富になる代わりにコストが増えます。
NIC受信
→ XDP(sk_buff生成前。最速、L2/L3ヘッダとペイロード先頭のみ参照可能)
→ TC ingress(sk_buff生成後。qdiscと連携、フロー情報や既存のTCインフラと統合しやすい)
→ ソケット層(cgroup/ソケットフィルタ。プロセス・ソケット単位のポリシーに向く)
→ アプリケーション
たとえばロードバランサの実装では、単純な宛先IP・ポートに基づく転送判定はXDPで最上流に置き、コネクションの状態管理や複雑なポリシー適用が必要な部分はTCフックやソケット層のeBPFに委ねる、という階層設計が定石です。これは状態を持つファイアウォールの判定を専用の追跡テーブルに任せる conntrackとステートフルファイアウォールの原理 の考え方とも通じます。フローをコアやバックエンドへ振り分ける計算そのものは、コンシステントハッシュ法によるロードバランシング や ECMPのフローハッシュと5-タプルの原理 で説明されるハッシュ設計と組み合わせて使われることが多く、XDPはその判定結果を「どのバックエンドへXDP_REDIRECTするか」という形で高速に実行する層にあたります。
XDPが速いのはパケット単位で完結する軽い判定に限られます。TCPの再組み立てやTLS終端のような、複数パケットにまたがる状態やペイロード全体の処理が必要な処理には向きません。無理に全処理をXDPへ詰め込もうとすると、検証器の制約(ループ・スタックサイズ)に阻まれるか、複雑化してバグの温床になります。ユーザー空間で全処理を担うカーネルバイパスとの対比は DPDKとユーザー空間ネットワーキングの原理 が参考になります。
実務での使われ方
DDoS対策では、攻撃シグネチャ(特定パターンのUDPパケットの急増など)をeBPFマップで検出し、送信元IPやパターンに一致するパケットをXDP_DROPで最上流で捨てる構成が典型です。ロードバランサでは、外部から来たパケットの宛先を書き換えてXDP_TXやXDP_REDIRECTでバックエンドへ転送し、カーネルのルーティングテーブルやNATを経由しない分だけ遅延と消費CPUを削減します。KubernetesのCNI(Cilium等)でもeBPFとXDPが多用され、Pod間・ノード間の転送ポリシーをiptablesのルールチェーン走査に代えてeBPFマップのO(1)ルックアップで解決することで、ルール数増加時の劣化を防ぎます。
「eBPFが安全な理由」→ 検証器がロード時に静的解析(ループ禁止・境界チェック・終了保証)を行い、合格したものだけJITで実行するため。「XDPが速い理由」→ sk_buff生成前、NICドライバ直後の最上流フックで動作し、後続処理を丸ごと省略できるため。「XDPの主要アクション」→ DROP/PASS/TX/REDIRECT/ABORTEDの5種。「フック位置のトレードオフ」→ 上流ほど速いが情報が少なく、下流ほど情報は増えるがコストも増える。
まとめ
eBPFは、カーネル内に安全な実行環境を作ることで「カーネルを改造せず拡張する」という課題を解決します。検証器がループ・メモリ境界・終了性を静的に証明し、合格したプログラムだけがJITでネイティブ速度で走る——この安全性と速度の両立が核心です。XDPはそのeBPFをsk_buff生成前という最上流のフックに配置し、DROP/PASS/TX/REDIRECTの即時判定によって数千万pps級の処理を可能にします。フックが上流にあるほど速いが扱える情報は少ないというトレードオフを理解し、単純な判定はXDPで、複雑な状態管理はTCやソケット層のeBPFに委ねる階層設計が、DDoS対策やロードバランサを実務で構築する際の定石です。
ネットワーク Article
eBPFとXDPによるパケット処理を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
eBPF
比較で見る軸
難易度: advanced / カテゴリ: ネットワーク / タグ数: 5
導入後に効く点
XDPはNICドライバの受信直後、`sk_buff` 生成前の最速フックでeBPFを実行し、`XDP_DROP`/`XDP_TX`/`XDP_REDIRECT` 等の即時判定によりDDoS対策やロードバランサを数千万pps級で処理できる。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- ネットワーク
- タグ数
- 5
判断チェックリスト
- 自社の用途が「eBPF / XDP」に近いか確認する。
- 強みである「eBPFはカーネル内の仮想マシンで、検証器がループ禁止・メモリ境界・型を静的解析して安全性を保証したうえでJITネイティブコードとして実行するため、カーネル改造なしに拡張できる。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。