第12章 PCI デバイス割り当て

Red Hat Enterprise Linux 6 は、以下の 3 つのクラスのデバイスを仮想マシンに公開します。
  • エミュレートされたデバイス は、実際のハードウェアを模倣する純粋の仮想デバイスです。変換されていないゲストオペレーティングシステムは標準のインボックスドライバーを使ってこれらのデバイスと動作できるようになります。
  • Virtio デバイス は、仮想マシン内で最適に動作するように設計された純粋の仮想デバイスです。Virtio デバイスは、エミュレートされたデバイスと似ていますが、Linux 以外の仮想マシンにはこれらデバイスが必要とするドライバーがデフォルトで含まれていません。仮想マシンマネージャー (virt-manager) や Red Hat Enterprise Virtualization Hypervisor といった仮想化管理ソフトウェアは、対応する Linux 以外のゲストオペレーティングシステムにこれらのドライバーを自動的にインストールします。
  • 割り当てデバイス は、仮想マシンに公開されている物理デバイスです。この方法は、「パススルー」とも呼ばれます。デバイス割り当てにより、仮想マシンは幅広いタスクで PCI デバイスへの独占アクセスが可能になり、PCI デバイスはゲストオペレーティングシステムに物理的にアタッチされているかのように表示され、動作することが可能になります。
    デバイス割り当ては、グラフィックスカードを除いて PCI Express デバイス上でサポートされています。パラレル PCI デバイスは割り当てデバイスとしてのサポートが可能ですが、セキュリティーとシステム設定の競合により厳しい制限があります。
Red Hat Enterprise Linux 6 は、仮想マシン 1 台あたり 32 の PCI デバイススロットと、デバイススロット 1 つあたり 8 つの PCI 機能をサポートします。これにより、理論上はゲストあたり最大 256 の設定可能な PCI 機能が提供されることになります。
しかし、この理論上の最大数は以下の制限に影響されます。
  • 仮想マシンがサポートするのは、最大 8 つの割り当てデバイス機能です。
  • 4 つの PCI デバイススロットは、デフォルトで 5 つのエミュレートされたデバイスに設定されています。しかしユーザーは、ゲストオペレーティングシステムの操作に不要な場合、デフォルト設定のエミュレートされたデバイスの内 2 つを明示的に削除できます (スロット 2 のビデオアダプターデバイスと、通常はスロット 3 である一番下にある利用可能なスロットのメモリーバルーンドライバーデバイス)。これにより、ユーザーは仮想マシン 1 台あたり最大 30 の PCI デバイススロット機能のサポートを受けられます。
Red Hat Enterprise Linux 6.0 およびそれ以降は、仮想マシンへの割り当て PCI デバイスのホットプラグをサポートします。しかし、PCI デバイスのホットプラグはスロットレベルで行われていることから、マルチ機能の PCI デバイスをサポートしていません。マルチ機能の PCI デバイスは、静的デバイスの設定にのみ推奨されます。

注記

Red Hat Enterprise Linux 6.0 では、ゲストオペレーティングシステムドライバーによるデバイスの標準および拡張設定領域へのアクセスが制限されていました。Red Hat Enterprise Linux 6.0 での制限は、Red Hat Enterprise Linux 6.1 で大幅に少なくなっており、より大型の PCI Express デバイスのセットが KVM ゲストに正常に割り当てられるようになっています。
セキュアなデバイス割り当ては、割り込み再マッピングのサポートも必要とします。プラットフォームが割り込み再マッピングをサポートしない場合、デバイス割り当ては失敗します。開発環境で割り込み再マッピングのサポートなしにデバイス割り当てを使用するには、allow_unsafe_assigned_interrupts KVM モジュールパラメーターを 1 に設定します。
PCI デバイス割り当ては、Intel VT-d または AMD IOMMU 対応のハードウェアプラットフォーム上でのみ利用可能です。PCI デバイス割り当てが機能するには、Intel VT-d または AMD IOMMU の仕様が BIOS で有効化されている必要があります。

手順12.1 Intel システムでの PCI デバイス割り当て準備

  1. Intel VT-d 仕様の有効化

    Intel VT-d 仕様は、物理デバイスを直接仮想マシンに割り当てるためのハードウェアサポートを提供します。これらの仕様は、Red Hat Enterprise Linux で PCI デバイス割り当てを使用するために必要なものです。
    Intel VT-d 仕様は、BIOS で有効化されている必要があります。システムメーカーの中には、これらの仕様をデフォルトで無効としているところもあります。これらの仕様に言及するために使用される用語はメーカーによって異なります。該当する用語に関しては、システムメーカーの資料を参照してください。
  2. カーネル内で Intel VT-d をアクティブ化する

    カーネル内で Intel VT-d をアクティブ化するには、intel_iommu=on パラメーターを /boot/grub/grub.conf ファイル内のカーネル行に追加します。
    以下の修正例は、grub.conf ファイルで Intel VT-d がアクティブ化されたものです。
    default=0
    timeout=5
    splashimage=(hd0,0)/grub/splash.xpm.gz
    hiddenmenu
    title Red Hat Enterprise Linux Server (2.6.32-330.x86_645)
            root (hd0,0)
            kernel /vmlinuz-2.6.32-330.x86_64 ro root=/dev/VolGroup00/LogVol00 rhgb quiet intel_iommu=on
            initrd /initrd-2.6.32-330.x86_64.img
  3. 準備完了

    システムを再起動して、変更を有効にします。これでシステムは、PCI デバイス割り当てに対応します。

手順12.2 AMD システムでの PCI デバイス割り当て準備

  1. AMD IOMMU 仕様の有効化

    AMD IOMMU 仕様は、Red Hat Enterprise Linux で PCI デバイス割り当てを使用するために必要なものです。この仕様は、BIOS で有効化されている必要があります。システムメーカーの中には、これらの仕様をデフォルトで無効にしているところもあります。
  2. IOMMU カーネルサポートの有効化

    amd_iommu=on/boot/grub/grub.conf 内のカーネルコマンド行に追加します。これで AMD IOMMU 仕様は起動後に有効になります。
  3. 準備完了

    システムを再起動して、変更を有効にします。これでシステムは、PCI デバイス割り当てに対応します。

12.1. virsh を使用した PCI デバイスの割り当て

このステップでは、KVM ハイパーバイザー上の仮想マシンに PCI デバイスを割り当てる方法を説明します。
この例では、PCI 識別子コード pci_0000_01_00_0 の PCIe ネットワークコントローラーと guest1-rhel6-64 という名前の完全仮想化ゲストマシンを使います。

手順12.3 virsh を使用した PCI デバイスのゲスト仮想マシンへの割り当て

  1. デバイスの特定

    最初に、仮想マシンへのデバイス割り当てに指定されている PCI デバイスを特定します。lspci コマンドを使用して利用可能な PCI デバイスをリストします。lspci の出力は grep を使って絞り込むことができます。
    この例では、以下の出力で太字で表示されているイーサネットコントローラーを使用します。
    # lspci | grep Ethernet
    00:19.0 Ethernet controller: Intel Corporation 82567LM-2 Gigabit Network Connection
    01:00.0 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01)
    01:00.1 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01)
    このイーサネットコントローラーは、00:19.0 の短い識別子で表示されています。この PCI デバイスを仮想マシンに割り当てるには、virsh が使用する完全な識別子を見つける必要があります。
    これを実行するには、virsh nodedev-list コマンドと grep コマンドを組み合わせて使用し、ホストマシンにアタッチされている特定の種類 (pci) のデバイスすべてをリストします。次に、使用するデバイスの短い識別子にマッピングされているストリングの出力を参照します。
    この例では、短い識別子 00:19.0 でイーサネットコントローラーにマッピングされているストリングを太字で表示しています。完全な識別子では、:. の文字がアンダースコアに置換されていることに注意してください。
    # virsh nodedev-list --cap pci
    pci_0000_00_00_0
    pci_0000_00_01_0
    pci_0000_00_03_0
    pci_0000_00_07_0
    pci_0000_00_10_0
    pci_0000_00_10_1
    pci_0000_00_14_0
    pci_0000_00_14_1
    pci_0000_00_14_2
    pci_0000_00_14_3
    pci_0000_00_19_0
    pci_0000_00_1a_0
    pci_0000_00_1a_1
    pci_0000_00_1a_2
    pci_0000_00_1a_7
    pci_0000_00_1b_0
    pci_0000_00_1c_0
    pci_0000_00_1c_1
    pci_0000_00_1c_4
    pci_0000_00_1d_0
    pci_0000_00_1d_1
    pci_0000_00_1d_2
    pci_0000_00_1d_7
    pci_0000_00_1e_0
    pci_0000_00_1f_0
    pci_0000_00_1f_2
    pci_0000_00_1f_3
    pci_0000_01_00_0
    pci_0000_01_00_1
    pci_0000_02_00_0
    pci_0000_02_00_1
    pci_0000_06_00_0
    pci_0000_07_02_0
    pci_0000_07_03_0
    使用するデバイスを呼び出す PCI デバイス番号は他のステップで必要になるので、書き留めます。
  2. デバイス情報の確認

    ドメインやバス、機能の情報は、virsh nodedev-dumpxml コマンドからの出力で入手できます。
    virsh nodedev-dumpxml pci_0000_00_19_0
    <device>
      <name>pci_0000_00_19_0</name>
      <parent>computer</parent>
      <driver>
        <name>e1000e</name>
      </driver>
      <capability type='pci'>
        <domain>0</domain>
        <bus>0</bus>
        <slot>25</slot>
        <function>0</function>
        <product id='0x1502'>82579LM Gigabit Network Connection</product>
        <vendor id='0x8086'>Intel Corporation</vendor>
        <capability type='virt_functions'>
        </capability>
      </capability>
    </device>
  3. 必要な設定詳細の決定

    設定ファイルで必要な値については、virsh nodedev-dumpxml pci_0000_00_19_0 コマンドの出力を参照します。
    別の方法では、スロットと機能の値を (10 進法から) 16 進法に変換して PCI bus アドレスを確認します。出力の最初に "0x" を加えることで、コンピューターに値が 16 進法の値であることを知らせます。
    サンプルのデバイスでは、以下の値となっています。bus = 0、slot = 25、function = 0。10 進法の設定では、これらの値を使用します。
    bus='0'
    slot='25'
    function='0'
    10 進法から 16 進法に値を変換したい場合は、以下の例で示すように printf ユーティリティーを使います。
    $ printf %x 0
    0
    $ printf %x 25
    19
    $ printf %x 0
    0
    サンプルのデバイスでは、設定ファイルで以下の 16 進法の値を使います。
    bus='0x0'
    slot='0x19'
    function='0x0'
  4. 設定詳細の追加

    仮想マシン名を特定して virsh edit を実行し、<source> セクションにデバイスエントリーを追加して PCI デバイスをゲスト仮想マシンに割り当てます。
    # virsh edit guest1-rhel6-64
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <source>
         <address domain='0x0' bus='0x0' slot='0x19' function='0x0'/>
      </source>
    </hostdev>
    別の方法では、仮想マシン名とゲストの XML ファイルを特定して virsh attach-device を実行します。
    virsh attach-device guest1-rhel6-64 file.xml
  5. デバイス管理の許可

    SELinux boolean を設定して仮想マシンからの PCI デバイス管理を可能にします。
    # setsebool -P virt_use_sysfs 1
  6. 仮想マシンの開始

    # virsh start guest1-rhel6-64
これで PCI デバイスは正しく仮想マシンに割り当てられ、ゲストオペレーティングシステムにアクセスできます。