第41章 RHEL 9 の eBPF ネットワーク機能について

eBPF (extended Berkeley Packet Filter) は、カーネル領域でのコード実行を可能にするカーネル内の仮想マシンです。このコードは、限られた一連の関数にのみアクセスできる制限付きサンドボックス環境で実行されます。

ネットワークでは、eBPF を使用してカーネルパケット処理を補完したり、置き換えることができます。使用するフックに応じて、eBPF プログラムには以下のような記述があります。

  • パケットデータおよびメタデータへの読み取りおよび書き込みアクセス
  • ソケットとルートを検索できる
  • ソケットオプションを設定できる
  • パケットをリダイレクト可能

41.1. RHEL 9 におけるネットワーク eBPF 機能の概要

eBPF (extended Berkeley Paket Filter) ネットワークプログラムは、RHEL の以下のフックに割り当てることができます。

  • eXpress Data Path (XDP):カーネルネットワークスタックが受信したパケットを処理する前に、このパケットへの早期アクセスを提供します。
  • direct-action フラグを持つ tc eBPF 分類子:ingress および egress での強力なパケット処理を提供します。
  • Control Groups version 2 (cgroup v2):コントロールグループ内のプログラムが実行するソケットベースの操作のフィルタリングおよび上書きを有効にします。
  • ソケットフィルタリング:ソケットから受信したパケットのフィルタリングを有効にします。この機能は、従来の Berkeley Packet Filter (cBPF) でも利用できますが、eBPF プログラムに対応するために拡張されました。
  • ストリームパーサー:個別のメッセージへのストリームの分散、フィルタリング、ソケットへのリダイレクトを有効にします。
  • SO_REUSEPORT ソケットの選択:reuseport ソケットグループから受信したソケットをプログラム可能な選択を提供します。
  • Flow dissector:特定の状況でカーネルがパケットヘッダーを解析する方法をオーバーライドします。
  • TCP 輻輳制御コールバック:カスタム TCP 輻輳制御アルゴリズムの実装を有効にします。
  • カプセル化によるルート:カスタムのトンネルカプセル化の作成を有効にします。

XDP

BPF_PROG_TYPE_XDP タイプのプログラムはネットワークインターフェイスに割り当てることができます。次にカーネルは、カーネルネットワークスタックが処理を開始する前に受信したパケットでプログラムを実行します。これにより、高速パケットドロップなど、特定の状況で高速なパケット転送が可能になり、負荷分散シナリオにおいて DDoS (Distributed Denial of Service) 攻撃や高速パケットリダイレクトを防ぐことができます。

さまざまな形式のパケット監視やサンプリングに XDP を使用することもできます。カーネルは、XDP プログラムはパケットを変更し、カーネルネットワークスタックへのさらなる処理を可能にします。

以下の XDP モードを使用できます。

  • ネイティブ (ドライバー) XDP:カーネルは、パケット受信時に最速の可能点からプログラムを実行します。この時点で、カーネルはパケットを解析しなかったため、カーネルが提供するメタデータは利用できません。このモードでは、ネットワークインターフェイスドライバーが XDP をサポートしている必要がありますが、すべてのドライバーがこのネイティブモードをサポートするわけではありません。
  • ジェネリック XDP:カーネルネットワークスタックは、処理の初期段階で XDP プログラムを実行します。この時点で、カーネルデータ構造が割り当てられ、パケットを事前に処理しています。パケットをドロップまたはリダイレクトする必要がある場合は、ネイティブモードと比較して大きなオーバーヘッドが必要になります。ただし、汎用モードはネットワークインターフェイスドライバーのサポートを必要とせず、すべてのネットワークインターフェイスで機能します。
  • オフロード XDP:カーネルは、ホストの CPU 上ではなく、ネットワークインターフェイスで XDP プログラムを実行します。これには特定のハードウェアが必要で、特定の eBPF 機能のみがこのモードで使用できることに注意してください。

RHEL で、libxdp ライブラリーを使用してすべての XDP プログラムを読み込みます。このライブラリーは、XDP のシステム制御を可能にします。

注記

現在、XDP プログラムにはシステム設定に制限があります。たとえば、受信側インターフェイスで特定のハードウェアオフロード機能を無効にする必要があります。また、ネイティブモードをサポートするすべてのドライバーで利用可能なわけではありません。

RHEL 9 では、libxdp ライブラリーを使用してプログラムをカーネルにロードする場合にのみ、Red Hat は XDP 機能をサポートします。

AF_XDP

指定した AF_XDP ソケットにパケットをフィルターしてリダイレクトする XDP プログラムを使用すると、AF_XDP プロトコルファミリーから 1 つ以上のソケットを使用して、カーネルからユーザー空間にパケットを速やかにコピーできます。

トラフィック制御

Traffic Control (tc) サブシステムは、以下のタイプの eBPF プログラムを提供します。

  • BPF_PROG_TYPE_SCHED_CLS
  • BPF_PROG_TYPE_SCHED_ACT

これらのタイプを使用すると、カスタム tc 分類子と tc アクションを eBPF に記述できます。これは、tc エコシステムの一部とともに、強力なパケット処理機能を提供します。また、複数のコンテナーネットワークオーケストレーションソリューションの中核となります。

多くの場合、direct-action フラグと同様に、eBPF 分類子は、同じ eBPF プログラムから直接アクションを実行できます。clsact Queueing Discipline (qdisc) は、Ingress 側でこれを有効にするように設計されています。

flow dissector の eBPF プログラムは、flower などのその他の qdiscstc 分類子の操作に影響を与える可能性があることに注意してください。

ソケットフィルター

複数のユーティリティーは、ソケットで受信されるパケットのフィルタリングに、従来の Berkeley Packet Filter (cBPF) を使用または使用しています。たとえば、tcpdump ユーティリティーを使用すると、ユーザーは、どの tcpdump を cBPF コードに変換するか、式を指定できます。

cBPF の代替として、カーネルは、同じ目的で BPF_PROG_TYPE_SOCKET_FILTER タイプの eBPF プログラムを許可します。

コントロールグループ

RHEL では、cgroup に割り当てられる eBPF プログラムを複数使用できます。カーネルは、指定の cgroup のプログラムが操作を実行する際に、これらのプログラムを実行します。cgroups バージョン 2 のみを使用できます。

RHEL では、以下のネットワーク関連の cgroup eBPF プログラムが利用できます。

  • BPF_PROG_TYPE_SOCK_OPS:カーネルは、さまざまな TCP イベントでこのプログラムを呼び出します。プログラムは、カスタム TCP ヘッダーオプションなどを含め、カーネル TCP スタックの動作を調整できます。
  • BPF_PROG_TYPE_CGROUP_SOCK_ADDR:connectbindsendtorecvmsggetpeername、および getsockname の操作時に呼び出されます。このプログラムは、IP アドレスとポートを変更できます。これは、ソケットベースのネットワークアドレス変換 (NAT) を eBPF に実装する場合に便利です。
  • BPF_PROG_TYPE_CGROUP_SOCKOPT:カーネルは、setsockopt および getsockopt 操作時にこのプログラムを呼び出して、オプションの変更を可能にします。
  • BPF_PROG_TYPE_CGROUP_SOCK:カーネルは、ソケットの作成時、ソケットの開放時、アドレスのバインド時にこのプログラムを呼び出します。これらのプログラムを使用して操作を許可または拒否するか、統計のソケット作成の検査のみを行います。
  • BPF_PROG_TYPE_CGROUP_SKB:このプログラムは ingress および egress の個別のパケットをフィルターし、パケットを受信または拒否できます。
  • BPF_PROG_TYPE_CGROUP_SYSCTL:このプログラムはシステム制御 (sysctl) へのアクセスをフィルタリングできます。

ストリームパーサー

ストリームパーサーは、特別な eBPF マップに追加されるソケットのグループで動作します。次に、eBPF プログラムは、カーネルがこれらのソケットで受信または送信するパケットを処理します。

RHEL では、以下のストリームパーサー eBPF プログラムを利用できます。

  • BPF_PROG_TYPE_SK_SKB:eBPF プログラムは、ソケットから受信したパケットを個別のメッセージに解析したり、それらのメッセージをドロップしたり、グループ内の別のソケットに送信するようにカーネルに指示します。
  • BPF_PROG_TYPE_SK_MSG:このプログラムは egress メッセージをフィルタリングします。eBPF プログラムは、パケットを個別のメッセージを解析し、そのパケットを承認または拒否します。

SO_REUSEPORT ソケットの選択

このソケットオプションを使用することで、複数のソケットを同じ IP アドレスとポートにバインドできます。eBPF がない場合、カーネルは接続ハッシュに基づいて受信ソケットを選択します。BPF_PROG_TYPE_SK_REUSEPORT プログラムを使用すると、受信ソケットの選択が完全にプログラム可能になります。

Flow dissector

プロトコルの完全なデコードを待たずにカーネルがパケットヘッダーを処理する必要がある場合、これらは 破棄されます。たとえば、これは、tc サブシステム、ボンディングのルーティング、またはパケットのハッシュを計算する際に発生します。この場合、カーネルはパケットヘッダーを解析し、パケットヘッダーからの情報を使用して内部構造を埋めます。この内部解析は、BPF_PROG_TYPE_FLOW_DISSECTOR プログラムを使用して置き換えることができます。RHEL の eBPF では、TCP および UDP を IPv4 および IPv6 上でのみ破棄できます。

TCP 輻輳制御

struct tcp_congestion_oops コールバックを実装する BPF_PROG_TYPE_STRUCT_OPS プログラムのグループを使用して、カスタム TCP 輻輳制御アルゴリズムを作成できます。この方法を実装するアルゴリズムは、ビルトインのカーネルアルゴリズムとともにシステムで利用できます。

カプセル化によるルート

以下のいずれかの eBPF プログラムタイプは、トンネルのカプセル化属性として、ルーティングテーブルのルートに割り当てることができます。

  • BPF_PROG_TYPE_LWT_IN
  • BPF_PROG_TYPE_LWT_OUT
  • BPF_PROG_TYPE_LWT_XMIT

このような eBPF プログラムの機能は特定のトンネル設定に限定され、汎用のカプセル化またはデシリアライズソリューションの作成はできません。

ソケットルックアップ

bind システムコールの制限を回避するには、BPF_PROG_TYPE_SK_LOOKUP タイプの eBPF プログラムを使用します。このようなプログラムは、新しい受信 TCP 接続のリスニングソケットまたは UDP パケットの非接続ソケットを選択できます。