現在位置: ホーム / みらくるブログ / #9 VFIOでDPDKを使う

#9 VFIOでDPDKを使う

これまでは、DPDKに付属のigb_uioというドライバを使って、DPDKがユーザー空間でNICを制御していました。今回は、カーネルに付属しているvfio-pciというドライバを使います。igb_uioを使っていると、カーネルがバージョンアップするたびに再ビルドが必要ですが、vfio-pciはカーネル標準のドライバなので、このような作業が不要です。

はじめに

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での稼働試験

これまで同様に次のような構成でスループットを測定しました。

06-testpmd.png

これまで作業していたマシンは、上図のホスト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を使った場合とほぼ同じでした。

パケット
サイズ(B)

vfioドライバ
(Mbps)

参考: 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