#9 VFIOでDPDKを使う
はじめに
Linuxでは、NICなどのデバイスには、通常カーネル内で動作するドライバしかアクセスできません。ただし、Linuxには、ユーザー空間で動作するプログラムが、デバイスを直接アクセスできる仕組みがいくつかあります。ひとつはこれまでのigb_uioドライバを使う方法。その他の主要なものにvfioドライバを使う方法があります。vfioドライバには、igb_uioドライバにない2つの利点があります。ひとつは、IOMMUを利用してシステムの安全性を高められること。もうひとつは、カーネルの標準付属ドライバであるため、別途ビルドやインストールが不要であることです。
上記の内容からは、vfioドライバのほうが優れているように思われるかもしれません。たしかにそうではあるのですが、筆者のこれまでの経験ではうまく動作しないケースがあったため、より構築・設定が容易なigb_uioドライバをこれまでの記事では使用してきました。うまく行かないケースのひとつはIOMMU(次節で説明)機能をマシンが持っていない場合。また、特定のマシンやカーネルバージョンとの組み合わせでは意図したように機能しない場合があるようです。さらに、vfioはIOMMUグループという単位でデバイスのユーザー空間プログラムへの使用を許可します。そのため、グループに含まれるデバイスのひとつを、従来のようにカーネルで制御させて、残りをDPDKで使うということはできません。なお、IOMMUグループにどのデバイスが含まれるかは、マザーボードやBIOSの設計、カードを挿したスロットなどに依存します。
IOMMUについて
vfioドライバはCPUのIOMMU機能を必要とします。IOMMUはインテルのCPUではVT-dと呼ばれています。IOMMUは、デバイスのホストメモリに対するアクセスを制限できます。従来のアーキテクチャではデバイスはホストのすべてのメモリに対してアクセスすることが可能でした。すなわち、例えば、プログラムのバグにより、データの書き出しエリアとして正しくないアドレスをデバイスに通知すると、デバイスはそのエリアのデータを不正に上書きします。そこは、カーネルが使っているかもしれませんし、他のアプリケーションのメモリエリアかもしれません。何れにしても重大な問題が生じます。
IOMMUを適切に設定すると、デバイスは許可されているメモリエリしかアクセスできなくなります。ですので、DPDKのようなユーザー空間ドライバに不具合があっても、システムの他の部分への影響を抑えることができます。前節ではうまく機能しないケースに遭遇したことも書きましたが、最近ではかなり洗練されてきていますので、新しいマシンとカーネルでは問題が起こることも少なくなってきたように思います。では実際に設定してみましょう。
IOMMUの設定
今回は、次のスペックのマシンとOSを使用しました。これは第2回でセットアップしたものと同じです。
CPU | Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz |
Memory | DDR3-1600 8GB x4 |
DPDK用NIC | Intel Corporation Ethernet Controller 10-Gigabit X540-AT2 |
OS | CentOS 7.3 |
DPDK | 17.02 |
まず、BIOSでVT-dを有効にします。その後、カーネルの起動オプションを設定します。/etc/default/grubのGRUB_CMDLINE_LINUX行に以下の水色の語句を追加します。
GRUB_CMDLINE_LINUX="crashkernel=auto rhgb quiet default_hugepagesz=1G hugepagesz=1G hugepages=16 iommu=pt intel_iommu=on"
その後、次のようにしてgrub2.confを更新します。
# grub2-mkconfig -o /boot/grub2/grub.cfg
再起動後、うまく動作している場合、カーネルメッセージに次のような記述が含まれます。
$ dmesg | grep -i iommu
(略)
[ 0.000000] DMAR: IOMMU enabled
[ 0.031805] DMAR-IR: IOAPIC id 8 under DRHD base 0xfed91000 IOMMU 1
[ 0.554768] iommu: Adding device 0000:00:00.0 to group 0
[ 0.554779] iommu: Adding device 0000:00:01.0 to group 1
[ 0.554785] iommu: Adding device 0000:00:02.0 to group 2
(略)
DPDKへのNICのバインド
VFIOのためのドライバをロードします。
# modprobe vfio-pci
この状態で、dpdk-devbindを実行すると、次のとおりunusedにvfio-pciが含まれています。
# dpdk-devbind -s
Network devices using DPDK-compatible driver
============================================
<none>
Network devices using kernel driver
===================================
0000:01:00.0 'Ethernet Controller 10-Gigabit X540-AT2' if=enp1s0f0 drv=ixgbe unused=igb_uio,vfio-pci
0000:01:00.1 'Ethernet Controller 10-Gigabit X540-AT2' if=enp1s0f1 drv=ixgbe unused=igb_uio,vfio-pci
0000:03:00.0 'RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller' if=enp3s0 drv=r8169 unused=igb_uio,vfio-pci *Active*
(略)
vfio-pciをDPDKにバインドするには以下のように入力します。
# dpdk-devbind -b vfio-pci 0000:01:00.0 0000:01:00.1
再度、dpdk-devbindで状態を確かめると以下のようになっています。
# dpdk-devbind -s
Network devices using DPDK-compatible driver
============================================
0000:01:00.0 'Ethernet Controller 10-Gigabit X540-AT2' drv=vfio-pci unused=ixgbe,igb_uio
0000:01:00.1 'Ethernet Controller 10-Gigabit X540-AT2' drv=vfio-pci unused=ixgbe,igb_uio
Network devices using kernel driver
===================================
0000:03:00.0 'RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller' if=enp3s0 drv=r8169 unused=igb_uio,vfio-pci *Active*
(略)
testpmdでの稼働試験
これまで同様に次のような構成でスループットを測定しました。
これまで作業していたマシンは、上図のホスト2にあたります。testpmdの起動方法も、これまで同じですが、水色で強調したようにusing IOMMU type 1というメッセージが表示さます。
# testpmd -- -i --nb-cores=2
EAL: Detected 8 lcore(s)
EAL: Probing VFIO support...
EAL: VFIO support initialized
EAL: PCI device 0000:01:00.0 on NUMA socket -1
EAL: probe driver: 8086:1528 net_ixgbe
EAL: using IOMMU type 1 (Type 1)
EAL: PCI device 0000:01:00.1 on NUMA socket -1
EAL: probe driver: 8086:1528 net_ixgbe
Interactive-mode selected
結果を下の表に記します。性能としてはigb_uioを使った場合とほぼ同じでした。
パケット |
vfioドライバ |
参考: igb_uioドライバ #5での測定結果 (2Q2P) |
64 | 15.6 | 15.5 |
128 | 19.5 | 19.4 |
256 | 20.0 | 20.0 |
付録:vfioドライバの起動時の自動ロード
上記では、手動でvfioドライバをロードしました。この構成を継続して利用するなら、起動時に自動でロードされると便利です。そのためには、/etc/sysconfig/modules/vfio.modulesを作成し、以下のとおり記述します。
#!/bin/sh
modprobe vfio-pci
また、実行権限を付与しておきます。
# chmod +x /etc/sysconfig/modules/vfio.modules