eBPF カーネル データ プレーン (テクニカル プレビュー)
概要 ジュニパークラウドネイティブContrail Networking(CN2)リリース23.3は、Linuxカーネル向けの拡張バークレーパケットフィルタ(eBPF)データプレーンをサポートしています。eBPFベースのデータプレーンにより、高性能アプリケーション向けにプログラムをカーネルにロードできます。
Linux カーネルの概要
Linuxカーネルメモリは、大きく次の2つの領域に分けられます。
-
カーネル空間:OSのコアはカーネル空間で動作します。OSは、メモリ、ストレージ、CPUを含むすべてのホストリソースに無制限にアクセスできます。カーネル領域は、特権 OS カーネル、カーネル拡張機能、およびホストのデバイス ドライバーの大部分を実行するために厳密に予約されています。カーネル領域は保護され、信頼されたコードのみが実行されます。
-
ユーザー空間ライブラリ:通常のアプリケーションなどの非カーネルプロセスは、ユーザー空間内で動作します。ユーザー空間で実行されるコードは、ハードウェアリソースへのアクセスが制限されており、通常、ディスクやネットワークI/Oなどの特権操作を実行するためにカーネル空間に依存しています。ユーザー空間アプリケーションは、APIまたはシステムコールを介してカーネルからサービスを要求します。システムコールは、プロセスとOS間のインターフェイスを提供し、ユーザースペースプロセスがOSのサービスを要求できるようにします。
場合によっては、開発者はシステムコールインターフェイスを介して割り当てられたよりも多くのカーネルパフォーマンスを必要とすることがあります。カスタムシステムコール、新しいハードウェアのサポート、新しいファイルシステムはすべて、カーネルの柔軟性を必要とする場合があります。このような場合は、ソースコードに追加せずにカーネルを強化する必要があります。Linuxカーネルモジュール(LKM)は、ソースコードを追加または変更することなく、ベースカーネルを拡張します。LKMは、システムコールとは異なり、実行時にカーネルに直接ロードされます。これは、新しいLKMが必要になるたびにカーネルを再コンパイルして再起動する必要がないことを意味します。LKMはカーネルを拡張しますが、高性能パケット処理などのユースケースに関しては、LKMは依然としてカーネル自体のオーバーヘッドとネットワークの制限によって制約されます。さらに、LKM には解決が必要なカーネルバージョンの互換性の問題があることが多く、アップストリーム化されていない LKM には信頼の問題が発生する可能性があります。
詳細については、 Juniper CN2テクノロジープレビュー(技術プレビュー) を参照するか、 ジュニパーサポートにお問い合わせください。
eBPF の概要
バークレーパケットフィルタ(BPF)は、カーネルからユーザー空間への無駄なパケットコピーを回避し、パケットを効率的にフィルタリングする方法を提供します。eBPFは、カーネル空間で実行されるコードを記述するためのメカニズムです。開発者は、制限された C 言語で eBPF プログラムを作成します。バイトコードと呼ばれるこのコードは、Clang/LLVMなどのコンパイラツールチェーンによってコンパイルおよび生成されます。
BPF のセキュリティ上の利点の 1 つは、カーネルでアクティブになる前に BPF プログラムを検証する必要があることです。BPF プログラムは、カーネル内の仮想マシン (VM) で実行されます。検証プロセスにより、BPF プログラムが VM 内でループすることなく完了することが保証されます。検証プロセスには、有効なレジスタ状態、プログラムのサイズ、およびアウトオブバウンドジャンプのチェックも含まれます。検証プロセスの後、プログラムはカーネル内でアクティブになります。
eBPF カーネル データ プレーン
eBPFカーネルデータプレーンを使用すると、従来のLKMよりも安全かつ効率的にカーネルの動作を拡張およびカスタマイズできます。LKMと同様に、カーネルはリロードされず、カーネルのコードは変更されません。カーネルデータプレーンのeBPFは、ユーザースペースアプリケーションがカーネル内を流れるデータを処理できることを意味します。つまり、eBPF を利用するアプリケーションはカーネル内で記述および処理されるため、一般的なカーネルプロセスのネットワーク層のオーバーヘッドが大幅に削減されます。高性能パケット処理、パケットフィルタリング、トレース、セキュリティ監視などのタスクはすべて、eBPFが提供する追加のカーネルパフォーマンスの恩恵を受けます。
eBPF プログラムを理解する
イベントとフッキング
eBPF プログラムは、イベント駆動型環境で実行されます。イベントとは、監視、トレース、または分析される特定の状況または状態です。たとえば、インターフェイスに到着するネットワーク パケットはイベントです。eBPF プログラムはこのイベントにアタッチされ、イングレスネットワークパケットを分析したり、パケットのパスをトレースしたりできます。
フッキングとは、eBPFプログラムをカーネルフロー内の特定の実行ポイントにアタッチするプロセスを指します。フックがトリガされると、eBPF プログラムが実行されます。eBPF プログラムは、イベント動作を変更したり、イベントに関連するデータを記録したりすることができます。たとえば、システムコールはフックとして機能する場合があります。システムコールが開始されると、フックがトリガされ、eBPF プログラムがシステムプロセスを監視できるようになります。
フックの他の例は次のとおりです。
ヘルパー関数
eBPF プログラムはヘルパー関数を呼び出し、eBPF プログラムを効果的に機能豊富にします。ヘルパー関数は、次の処理を実行します。
- キーと値のペアを検索、更新、削除する
- 擬似乱数を生成する
- トンネルメタデータの取得と設定
- eBPF プログラムのチェイニング (テールコール)
- ソケットを使用して、バインド、Cookie の取得、パケットのリダイレクトなどのタスクを実行する
カーネルはヘルパー関数を定義し、eBPF プログラムが行う呼び出しの範囲をホワイトリストに登録します。
eBPF マップ
マップは、eBPF プログラムで使用される主要なデータ構造です。マップは、カーネルとユーザー空間の間のデータの通信を可能にします。マップは、値が任意のデータのバイナリ BLOB として扱われるキーと値のストアです。マップが不要になった場合は、関連付けられたファイル記述子を閉じることによって削除されます。
各マップには、型、含めることができる要素の最大数、値のサイズ (バイト単位)、キーのサイズ (バイト単位) の 4 つの属性があります。さまざまなマップタイプが利用可能で、それぞれが異なる動作とトレードオフを提供します。すべてのマップは、bpf_map_lookup_elem() および bpf_map_update_elem() 関数を利用して、eBPF プログラムとユーザー空間プログラムの両方からアクセスおよび操作できます。
eBPF プログラムの実行
カーネルは、すべての eBPF プログラムがバイトコードとしてロードされることを期待しています。その結果、eBPF プログラムはツールチェーンを使用してバイトコードにコンパイルする必要があります。コンパイルされると、eBPFプログラムは、指定されたフックポイントで展開される前に、カーネル内で検証されます。eBPFは最新のアーキテクチャをサポートしているため、合計11レジスタで64ビットエンコードにアップグレードされます。これは、eBPFをx86_64、ARM、arm64アーキテクチャなどのハードウェアに密接にマッピングします。
最も重要なことは、eBPFがカーネルレベルのイベントへのアクセスのロックを解除し、カーネルコードの直接変更に関連する一般的な制約を回避することです。要約すると、eBPFは以下によって機能します。
-
eBPF プログラムのバイトコードへのコンパイル
-
フックポイントでのVMロードでプログラムを安全に実行する検証
-
指定されたイベントによってトリガーされるカーネル内のフックポイントへのプログラムのアタッチ
-
移植性を高めるための実行時にネイティブバイトコードへのコンパイル
-
プログラムの実行時にデータを操作するためのヘルパー関数の呼び出し
-
マップ(キーと値のペア)を使用して、ユーザー空間とカーネル空間の間でデータを共有し、状態を維持する
図1: eBPFプログラムの実行
XDP の概要
eXpress Data Path(XDP)は、カーネルネットワークスタックの新しいプログラム可能なレイヤーです。XDP は、eBPF バイトコードがアタッチされて実行される新しいフックポイントの 1 つです。XDP オブジェクトファイルは、従来の eBPF プログラムに必要な再コンパイルを必要とせずに、複数のカーネルやアーキテクチャにロードされます。XDP プログラムは、カーネルバイパスソリューションと比較してパフォーマンスのギャップを狭めますが、プログラムはカーネルをバイパスしません。XDP を定義するいくつかの重要な特性を次に示します。
-
カーネルバイパスよりも高速になることを意図したものではありません
-
パケット バッファー上で直接動作
-
パケット当たりの実行命令数を減少
カーネルネットワークスタックは、ソケット配信のユースケース向けに設計されています。その結果、常にすべての着信パケットをソケットバッファ(SKB)に変換します。XDP を使用すると、パケットを SKB に変換する前に処理できます。XDP は、カーネルを変更することなく、既存のカーネルスタックと組み合わせて動作します。これにより、XDPは、より大きな柔軟性を提供するカーネル内の代替手段になります。
XDP およびトラフィック制御フック
すべての eBPF バイトコードの読み込み、マップの作成、更新、および読込は、BPF システムコールによって処理されます。XDP ドライバーフックはイングレスでのみ使用できることに注意してください。エグレスパケットを処理する必要がある場合は、TC(トラフィック制御)などの代替フックを使用する必要がある場合があります。より広いレベルでは、XDP BPF プログラムと TC BPF プログラムの間にはいくつかの違いがあります。
-
XDP フックが早く発生するため、パフォーマンスが向上します。
-
TC フックは後で発生します。その結果、ソケットバッファ (
sk_buff
) 構造体とフィールドにアクセスできます。データ構造には、カーネルのネットワークスタックがパケットを効率的に処理およびルーティングできるようにするメタデータと情報が含まれているためsk_buff
、これはXDPフックとTCフックのパフォーマンスの違いに大きく影響します。構造体とその属性にアクセスするsk_buff
と、カーネルスタックがTCフックに到達するまでパケットの割り当て、メタデータの抽出、および管理を行う必要があるため、一定のオーバーヘッドが発生します。
-
-
TC フックにより、パケット マングリングが向上します。
-
完全なパケット書き換えには XDP の方が適しています。
-
このユースケースには
sk_buff
、GSO(ジェネリックセグメンテーションオフロード)に関連する状態情報など、プロトコル固有の広範な詳細が含まれています。このため、パケットデータを書き換えるだけでプロトコルを切り替えることは困難です。その結果、BPF ヘルパー関数によって実行されるさらなる変換が必要です。これらのヘルパー関数は、の内部sk_buff
コンポーネントが正しく変換されることを保証します。対照的に、ユースケースでは
xdp_buff
これらの問題は発生しません。カーネルsk_buff
が.その結果、このシナリオであらゆるタイプのパケット書き換えを簡単に行うことができます。
-
-
補完的なプログラムとしてのTC、eBPF、およびXDP。
-
ユースケースでパケットの書き換えとデータの複雑なマングリングの両方が必要な場合、両方のタイプの補完的なプログラムを操作することで、各プログラムタイプの制限を克服できます。たとえば、イングレスポイントの XDP プログラムは、完全なパケット書き換えを実行し、カスタムメタデータを XDP BPF から TC BPF に送信できます。TC BPF プログラムは、XDP メタデータと
sk_buff
フィールドを活用して、複雑なパケット処理を実行できます。
-
-
TC BPF では、ハードウェア ドライバを変更する必要はありません。XDP は、最高のパフォーマンスを得るためにネイティブドライバーモードを使用します。
図 2: XDP フックと TC フック
XDP コントロールプレーンとデータ プレーン
XDP では、データプレーンはカーネル内に存在し、カーネルコアとカーネル内 eBPF プログラムの 2 つのコンポーネントに分割されます。コントロールプレーンはユーザー空間に常駐し、カーネル空間と連携して動作し、BPFプログラムをカーネルにロードしたり、マップを使用してプログラムの動作を管理したりするなどの重要なタスクを実行します。
XDP のアクションと動作
XDP フックポイントで実行されている eBPF プログラムは、プログラムがパケットを処理する方法に基づいて次のアクションを返します。
- イングレスパケットを他のインターフェイスまたはユーザースペースにリダイレクトします。
-
受信したパケットを、到着したのと同じインターフェイスから送り返します。
-
パケットをカーネル スタックに送信して処理します。
-
パケットをドロップします。
XDP および eBPF
XDP は、カーネルのネットワークスタックのソフトウェアオフロードレイヤーとして機能します。理想的なユースケースは、Linuxカーネルのネットワークスタックと組み合わせてパフォーマンスを向上させることです。たとえば、IPルーティングのユースケースでは、カーネルがルートテーブル管理とネイバールックアップを処理し、XDPはヘルパー関数を使用してこれらのルーティングテーブルに効率的にアクセスすることでパケット処理を高速化します。ルックアップが完了し、ネクストホップが特定されると、それに応じてパケットヘッダーが変更されます。変更が必要ない場合、パケットはそのままカーネルに転送されます。
XDP は RX メモリモデルに次の制限を課すことに注意してください。
- 現在、すべての一般的なドライバーのジャンボフレームをサポートしているわけではありませんが、i40e、Veth、および virtio はジャンボフレームをサポートしています。
-
カーネル空間にマルチキャスト・サポートが存在する
eBPF XDP ドライバーモードベースのアプローチを利用すると、vRouter カーネルモジュールなどの独自のカーネルモジュールよりも優れています。利点には、ライフサイクル管理 (LCM)、安全性、パフォーマンスの向上などがあります。Linux アップストリームツリーに統合されたカーネルモジュールと比較すると、代替の eBPF XDP カーネルプログラムを維持することは、カーネルバージョン間でより効率的です。これは、カーネルの依存関係が eBPF ヘルパー関数の小さなセットに制限されているためです。
コントローラ/ライブラリがクラッシュした場合でも、XDP または TC プログラムはトラフィックを転送することに注意してください。XDP または TC プログラムを再アタッチまたは置き換えても、ネットワークトラフィックは中断されません。
カーネルからユーザー空間への通信
AF_XDPソケットは、XDP フックで動作するカーネル空間プログラムとユーザー空間ライブラリ間の通信を容易にするために使用されます。AF_XDP は Linux 4.1.8 で導入された。AF_XDP は、ユーザー空間アプリケーションへの高速 raw パケット配信のための新しいソケットタイプです。AF_XDPは、Linuxカーネルドライバーを活用して、高性能とスケーラビリティを実現します。特に、ゼロコピーデータ転送のサポート、割り込みへの依存の最小化、データプレーン開発キット(DPDK)やベクトルパケットプロセッシング(VPP)と同様のネットワークドライバーの最適化などの機能も提供します。
AF_XDPソケットを流れるパケットのパスは次のとおりです。
NIC 固有のドライバーは、NIC で着信パケットにアクセスします。ドライバーは、対応するインターフェイスにバインドされている XDP フックで実行されている eBPF プログラムを介してそれらをインターセプトして処理します。XDP プログラムは各パケットを個別に処理し、完了すると、「XDP アクションと協力」セクションで説明されているようにアクションを生成します。XDP_REDIRECTを利用することにより、パケットは、そのインターフェイスに関連付けられたAF_XDPソケットを介してユーザー空間に送信されます。これにより、NICから直接生のパケットを受信できるようになります。カーネル空間をバイパスすることで、カーネルのオーバーヘッドが回避され、パケットはユーザー空間ライブラリに直接アクセスします。
eBPF データプレーンの有効化
eBPF データ プレーン機能を有効にするには、vRouter の仕様で指定します agentModeType: xdp
。現在、すべての XDP ドライバーがジャンボフレームをサポートしているわけではないため、CN2 デプロイヤーはファブリック、ループバック、および veth インターフェイスの最大伝送単位(MTU)値を設定します。
次の例は、XDP-eBPF が有効になっている vRouter リソースです。
apiVersion: dataplane.juniper.net/v1 kind: Vrouter metadata: name: contrail-vrouter-masters namespace: contrail spec: agent: default: collectors: - localhost:6700 xmppAuthEnable: true sandesh: introspectSslEnable: true sandeshSslEnable: true agentModeType: xdp common: containers: - name: contrail-vrouter-agent image: contrail-vrouter-agent - name: contrail-watcher image: contrail-init - name: contrail-vrouter-telemetry-exporter image: contrail-vrouter-telemetry-exporter initContainers: - name: contrail-init image: contrail-init - name: contrail-cni-init image: contrail-cni-init
フィールドをメモします name: contrail-vrouter-masters
。この vRouter はマスターノードとして指定されているため、使用可能なすべてのマスターノードはデプロイヤーの適用時にに設定されます agentModeType: xdp
。このロジックはワーカー ノードにも適用されます。デプロイヤーのワーカーノードリソースに「XDP」を指定すると、すべてのワーカーノードが XDP-eBPF 用に構成されます。
XDP でサポートされているドライバー
次の表に、eBPF-XDP データパスを持つ CN2 検証済み XDP ドライバーを示します。
ドライバー名 | 基になるプラットフォーム |
---|---|
恵那 | Aws |
ベス | ポッド接続 |
virtio | CN2-On-CN2 |
i40e | ベア メタル |
クラスターで NIC インターフェイスに AWS ENA 基盤ドライバーを使用している場合、デプロイヤーは物理インターフェイスのキュー設定を 4 受信 (RX) と 4 送信 (TX) に設定します。この変更は、ENA ドライバーのデフォルトの RX および TX キューカウントが XDP でサポートされていないために発生します。
eBPFデータプレーンの設計とCN2の実装
eBPF カーネルデータプレーンは、カーネル内 XDP プログラムと補完的なユーザー空間ライブラリという 2 つのコアコンポーネントで構成されています。このeBPFを搭載したデータプレーンは、カーネルモジュールベースのvRouterおよびDPDKと並ぶ、vRouterの3番目のデータプレーンオプションです。以降のセクションでは、このテクノロジによって提供されるさまざまなデータ プレーン機能の設計と実装の詳細について説明します。
eBPFデータプレーンコンポーネント
前述のように、eBPF データプレーンは XDP に基づいています。デフォルトの名前空間から発信されるパケットを必要とする機能では、エグレス TC フックが必要になる場合もあります。これは、エグレス パスに XDP フックがないためです。TC プログラムでは、TC フックが SKB で動作するため、新しい解析関数も導入されています。
eBPF データプレーンは、独立したデーモンとして意図されたものではありません。代わりに、コントローラ(CN2の場合はvRouterエージェント)内のライブラリとして統合されます。この実装は、次の 2 つのコンポーネントに分かれています。
-
ユーザスペースライブラリ: ユーザスペースライブラリは、カーネル eBPF プログラムとユーザスペースで実行されているコントローラ (vRouter エージェント) との間のインタフェースとして機能します。これは、vRouter エージェントがデータ パスをプログラムするために利用する API を公開します。このコンポーネントは、次の機能を実行します。
-
eBPF プログラムをカーネルにロードおよびアンロードします
-
eBPF プログラムをインターフェイスにバインドします。
-
マップエントリの設定と読み取り
-
ユーザー空間データパス内でパケットを転送、変更、フィルタリング
-
-
カーネルスペースプログラム:これらのeBPFプログラムは、カーネルコアで実行されるメインデータパスを構成します。このプログラムは、インターフェイスの XDP フックにロードされ、それらのインターフェイスのすべての着信パケットを処理します。TCは、ループバックインターフェイスのエグレスでも使用されます。前述のように、ユーザースペースのeBPFライブラリは、eBPFプログラムをカーネルコアにロードする役割を果たします。カーネルスペースプログラムは、次のことを行います。
-
カーネル内のパケットの転送、変更、フィルタリングを行います。
-
ヘルパー関数を使用してカーネルの残りの部分と対話します
-
マップの作成、更新、および読み取り (マップは、ユーザー空間ライブラリとカーネル空間プログラムの間で共有されるデータ構造です)
-
vRouter エージェントは、いくつかの方法でユーザー空間ライブラリを介して eBPF データプレーンと対話します。
-
コントローラ(vRouterエージェント)は、ユーザースペースeBPFライブラリによって公開されているAPIを直接呼び出します。
-
ライブラリによって公開されるパブリックAPIは、他のデータパスに使用されるksync/Sandeshレイヤーによって提供される機能を置き換えます
-
エージェントは、フローミスや関心のあるパケットの受信のためにコールバックをユーザースペースライブラリに登録します
-
- ライブラリは、ネットリンクソケットイベントもリッスンします。ユーザー空間ライブラリは、カーネルからのルート、ARPおよびアドレス更新をリッスンできます
- ライブラリはカーネルに他の情報も照会します