付録E IOMMU グループの使用

Red Hat Enterprise Linux 7 で導入された VFIO(Virtual Function I/O) は、ユーザー空間のドライバーフレームワークを提供する一連の Linux カーネルモジュールです。このフレームワークにより、ユーザー空間ドライバーのセキュアなデバイスアクセスを有効にするために IOMMU (Input–output memory management unit) 保護が使用されます。VFIO は、DPDK (Data Plane Development Kit) やより一般的な PCI デバイス割り当て などのユーザー空間ドライバーを有効にします。
VFIO は IOMMU グループを使用してデバイスを分離し、ホスト物理マシン上で実行される 2 つのデバイス間で意図しない DMA (Direct Memory Access、直接メモリーアクセス) が発生しないようにします。意図しない DAM はホストとゲストの機能に影響を与える可能性があります。Red Hat Enterprise Linux 7 で利用できる IOMMU グループは、Red Hat Enterprise Linux 6 で利用可能なレガシー KVM デバイス割り当てよりも大幅に改良されています。この付録では、以下を重点的に取り上げます。
  • IOMMU グループの概要
  • デバイス分離の重要性
  • VFIO の利点

E.1. IOMMU の概要

IOMMU はデバイスの仮想アドレス空間を作成します。ここで、各 I/O Virtual Address (IOVA) は物理システムメモリーの異なるアドレスに変換されます。この変換が完了すると、デバイスは物理システムのメモリー内の異なるアドレスに接続されます。IOMMU がない場合、すべてのデバイスは、メモリーアドレス変換がないために物理メモリーの共有されたフラットビューを持ちます。IOMMU がある場合、デバイスは、デバイスの割り当てに役立つ新規のアドレス空間である IOVA 空間を受信します。
IOMMU が異なると機能レベルも異なります。過去において、IOMMU は変換のみを提供するよう制限され、アドレス空間の小規模な枠にのみ使用されることが多くありました。たとえば、IOMMU は複数デバイスで共有されるローメモリー (low memory) の IOVA 空間の小規模な枠 (1GB 以下) のみを予約しました。AMD GART (graphics address remapping table) が汎用 IOMMU として使用される場合がこのモデルの例になります。これらの従来の IOMMU は、バウンスバッファー (bounce buffers) および アドレスコアレッシング (address coalescing) という 2 つの機能を主に提供してきました。IOMMU が異なると機能レベルも異なります。過去において、IOMMU は変換のみを提供することに制限され、アドレス空間の小規模な枠にのみ使用されることが多くありました。たとえば、IOMMU は複数デバイスで共有されるローメモリー (low memory) の IOVA 空間の小規模な枠 (1GB 以下) のみを予約しました。AMD GART (graphics address remapping table) が汎用 IOMMU として使用される場合がこのモデルの例になります。これらの従来の IOMMU は、バウンスバッファー (bounce buffer) およびアドレスコアレッシング (address coalescing) という 2 つの機能を主に提供してきました。
  • バウンスバッファーは、デバイスのアドレス機能がプラットフォームの同機能よりも小さい場合に必要になります。たとえば、デバイスのアドレス空間がメモリーの 4GB (32 ビット) に制限され、ドライバーが 4GB を超えるバッファーに割り当てようとする場合に、デバイスはバッファーに直接アクセスできなくなります。このような状況ではバウンスバッファーを使用する必要があります。ローメモリー (low memory) にあるバッファー領域では、デバイスが DMA 操作を実行できます。バッファーのデータは操作の完了時にドライバーの割り当て済みバッファーにのみコピーされます。つまり、バッファーはローメモリー (low memory) アドレスからハイメモリー (high memory) アドレスにバウンスされます。IOMMU は、デバイスのアドレス空間内で IOVA 変換を提供してバウンスバッファーを防止します。これにより、デバイスは、バッファーがデバイスの物理アドレス空間を超えても DMA 操作を直接バッファーで実行します。これまでこの IOMMU 機能は、IOMMU での使用に制限されてきましたが、PCI-Express (PCIe) の導入により、4GB を超えるアドレスのサポート機能がレガシー以外のすべてのエンドポイントで必要になりました。
  • 従来のメモリー割り当てでは、メモリーのブロックはアプリケーションのニーズに応じて割り当てや解放が実行されます。この方法を使用することにより、物理アドレス空間全体に分散するメモリーギャップが生成されます。メモリーギャップがコアレッシング (結合) され、より効率的に使用できるほうがよいでしょう。IOMMU は、scatter-gather 一覧と呼ばれることもある分散したメモリーの一覧のコアレッシングを IOVA 空間全体で実行します。これにより、IOMMU は連続的な DMA 操作を作成し、最終的には I/O パフォーマンスの効率を高めます。最も簡単な例として、ドライバーは物理メモリー領域の連続しない 2 つの 4KB バッファーを割り当てることができます。IOMMU は、これらのバッファーの連続する範囲を割り当て、I/O デバイスが 2 つの 4 KB DMA ではなく単一の 8KB DVA を実行できるようにします。
メモリーコアレッシングおよびバウンスバッファーはホストの高パフォーマンス I/O において重要ですが、仮想化環境に不可欠な IOMMU 機能は最新 IOMMU の 分離機能です。従来の PCI は要求側のデバイスの ID (リクエスター ID) でトランザクションにタグ付けしないため、PCI-Express 以前には分離を広範囲に実行することはできませんでした。PCI-X にはある程度のリクエスター ID が含まれていましたが、トランザクションの所有権を取得するデバイスに相互接続するためのルールは、デバイス分離の完全サポートは提供しませんでした。
PCIe では、各デバイスのトランザクションは、デバイスに固有のリクエスター ID (BDF と省略されることの多い PCI バス/デバイス/機能番号) でタグ付けされ、これはデバイスの固有の IOVA テーブルを参照するために使用されます。分離が可能になることにより、IOVA 空間は接続できないメモリーのオフロードやメモリーコアレッシングなどの変換操作のみならず、デバイスから DMA アクセスを制限するためにも使用できるようになりました。これにより、デバイスを相互に分離し、メモリー領域の重複した割り当てを防ぐことができます。これは適切なゲスト仮想マシンデバイス管理に不可欠です。これらの機能をゲスト仮想マシンで使用することにより、割り当て済みデバイスの IOVA 空間には仮想マシンについてのゲスト物理およびホスト物理メモリーのマッピングが設定されます。これがいったん実行されると、デバイスはゲスト仮想マシンのアドレス空間で DMA 操作を透過的に実行します。


[1] この付録の元の内容はプリンシパルソフトウェアエンジニアの Alex Williamson によって提供されました。