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で開発環境として必要そうなものをインストールしておきます。

```bash
sudo apt-get install build-essential
```

# DPDKのインストール

aptではいるらしい。

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

# 各種設定

## HUGEPAGE

編集して、

```text:/etc/default/grub
GRUB_CMDLINE_LINUX="hugepages=1024"
```

反映。

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

fstabも編集して、

```text:/etc/fstab
nodev /mnt/huge hugetlbfs defaults 0 0
```

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

```bash
sudo mkdir /mnt/huge
sudo reboot
```

## DPDKで使うNICの設定

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

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

```bash
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
```

```text: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にバインドしてみましょう。

```bash
/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にバインドされてることがわかります。


```bash
/usr/share/dpdk/tools/dpdk_nic_bind.py --status
```

```text: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>
```

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

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

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

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

```bash
cp -R /usr/share/dpdk/examples ~/dpdk-examples
cd ~/dpdk-examples/helloworld/
source /usr/share/dpdk/dpdk-sdk-env.sh
make
```

```text: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
```

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

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

今度は通りました。

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

```bash
sudo ./build/helloworld 
```

```text: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をつかもうとしてます。



[コマンドライン引数で、ブラックリストを指定できるという情報](https://twitter.com/slankdev/status/825366493713952768)を得たので、再チャレンジ。

```bash
sudo ./build/helloworld -b 0000:00:03.0
```

```text: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` ではコマンドライン引数の処理をしてないように見えますが、

```c
	ret = rte_eal_init(argc, argv);
```

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

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