VirtualBoxでDPDKを動かす


なかなか実機ではテストするのがめんどくさいので、VirtualBoxでDPDKのサンプルをビルドして動かすところまでやってみます。

仮想マシンの作成

VirtualBoxで仮想マシンを作成する、この時注意することがいくつかあります。

  • CPUは2コア以上にする
  • メモリは4GB以上にする
  • NICは3つ用意する
    • 1杖のNICはインターネット接続用、デフォルトのままでOK
    • 2,3枚目のNICはDPDK動かす用、詳細から種類として Intel PRO/1000 MT Server (82545EM) を選択すること

OSインストール

Ubuntu Server 16.04を普通にISOからインストールします。

aptで開発環境として必要そうなものをインストールしておきます。

sudo apt-get install build-essential

DPDKのインストール

aptではいるらしい。

sudo apt-get install dpdk dpdk-dev dpdk-doc libdpdk-dev

各種設定

HUGEPAGE

編集して、

/etc/default/grub
GRUB_CMDLINE_LINUX="hugepages=1024"

反映。

sudo grub-mkconfig -o /boot/grub/grub.cfg

fstabも編集して、

/etc/fstab
nodev /mnt/huge hugetlbfs defaults 0 0

ディレクトリ作成して再起動。

sudo mkdir /mnt/huge
sudo reboot

DPDKで使うNICの設定

DPDKとNICのバインドはスクリプト /usr/share/dpdk/tools/dpdk_nic_bind.py で行います。

まず、現在の設定を確認しましょう。

sudo insmod /lib/modules/4.4.0-31-generic/kernel/drivers/uio/uio_pci_generic.ko
/usr/share/dpdk/tools/dpdk_nic_bind.py --status
output
Network devices using DPDK-compatible driver
============================================
<none>

Network devices using kernel driver
===================================
0000:00:03.0 'Virtio network device' if= drv=virtio-pci unused= 
0000:00:08.0 '82545EM Gigabit Ethernet Controller (Copper)' if=enp0s8 drv=e1000 unused=uio_pci_generic 
0000:00:09.0 '82545EM Gigabit Ethernet Controller (Copper)' if=enp0s9 drv=e1000 unused=uio_pci_generic 

Other network devices
=====================
<none>

まだ何も設定されていないことがわかります。
そこで、2つのIntel NICをDPDKにバインドしてみましょう。

/usr/share/dpdk/tools/dpdk_nic_bind.py --bind=uio_pci_generic 0000:00:08.0
/usr/share/dpdk/tools/dpdk_nic_bind.py --bind=uio_pci_generic 0000:00:09.0

もう一度状態を確認すると、DPDKにバインドされてることがわかります。

/usr/share/dpdk/tools/dpdk_nic_bind.py --status
output
Network devices using DPDK-compatible driver
============================================
0000:00:08.0 '82545EM Gigabit Ethernet Controller (Copper)' drv=uio_pci_generic unused=e1000
0000:00:09.0 '82545EM Gigabit Ethernet Controller (Copper)' drv=uio_pci_generic unused=e1000

Network devices using kernel driver
===================================
0000:00:03.0 'Virtio network device' if= drv=virtio-pci unused=uio_pci_generic 

Other network devices
=====================
<none>

インターフェースの永続化

設定を永続化するには、ファイルに記載しておきます。

/etc/dpdk/interfaces
pci 0000:00:08.0 uio_pci_generic
pci 0000:00:09.0 uio_pci_generic

サンプルファイルのビルド

cp -R /usr/share/dpdk/examples ~/dpdk-examples
cd ~/dpdk-examples/helloworld/
source /usr/share/dpdk/dpdk-sdk-env.sh
make
output
  CC main.o
  LD helloworld
/usr/bin/ld: -lpcap が見つかりません
/usr/bin/ld: -lxenstore が見つかりません
collect2: error: ld returned 1 exit status
/usr/share/dpdk//mk/rte.app.mk:221: ターゲット 'helloworld' のレシピで失敗しました
make[1]: *** [helloworld] エラー 1
/usr/share/dpdk//mk/rte.extapp.mk:42: ターゲット 'all' のレシピで失敗しました
make: *** [all] エラー 2

パッケージが足りないようなのでインストールしてやり直します。

sudo apt-get install libpcap-dev libxen-dev 
make

今度は通りました。

実行してみます。root権限が必要です。

sudo ./build/helloworld 
output(抜粋)
EAL: PCI device 0000:00:03.0 on NUMA socket -1
EAL:   probe driver: 1af4:1000 rte_virtio_pmd
PMD: device not available for DPDK (in use by kernel)
EAL: Error - exiting with code: 1
  Cause: Requested device 0000:00:03.0 cannot be used

あれ?動かない...掴んで欲しくないNICをつかもうとしてます。

コマンドライン引数で、ブラックリストを指定できるという情報を得たので、再チャレンジ。

sudo ./build/helloworld -b 0000:00:03.0
output(抜粋)
EAL: Master lcore 0 is ready (tid=177968c0;cpuset=[0])
EAL: lcore 1 is ready (tid=937fe700;cpuset=[1])
EAL: PCI device 0000:00:03.0 on NUMA socket -1
EAL:   probe driver: 1af4:1000 rte_virtio_pmd
EAL:   Device is blacklisted, not initializing
EAL: PCI device 0000:00:08.0 on NUMA socket -1
EAL:   probe driver: 8086:100f rte_em_pmd
EAL:   PCI memory mapped at 0x7f5114c00000
PMD: eth_em_dev_init(): port_id 0 vendorID=0x8086 deviceID=0x100f
EAL: PCI device 0000:00:09.0 on NUMA socket -1
EAL:   probe driver: 8086:100f rte_em_pmd
EAL:   PCI memory mapped at 0x7f5114c20000
PMD: eth_em_dev_init(): port_id 1 vendorID=0x8086 deviceID=0x100f
hello from core 1
hello from core 0

今度はNIC2つを掴んで成功です!

コマンドライン引数の正体

helloworld/main.c ではコマンドライン引数の処理をしてないように見えますが、

    ret = rte_eal_init(argc, argv);

ここで、EALを初期化するときにコマンドラインオプションが色々渡せるようになっています。

渡せるオプションはたくさんあって、DPDKのドキュメントにも載っていました。
http://dpdk.org/doc/guides/testpmd_app_ug/run_app.html