Metonymical Deflection

ゆるく日々のコト・たまにITインフラ

CentOS7 + pktgen with DPDKでパケットジェネレータ作成

CentOS7上に3台の仮想マシン(CentOS)を稼働させつつDPDKとpktgenをインストールして10Gワイヤーレートが出るパケットジェネレータを作成しました。

1.環境

1-1.母体(ホストOS)
筐体                             : ProLiant DL360p Gen8
System ROM                       : P71 01/22/2018
CPU                           : Intel(R) Xeon(R) CPU E5-2660 0 @ 2.20GHz 
NIC                              : Intel X520-SR2(82599ES)
OS                               : CentOS7.4(1708)
Kernel                           : kernel-3.10.0-693.el7.x86_64
Installed Environment Groups     : Server with GUI
Add-Ons for Selected Environment : Virtualization Client, Virtualization Hypervisor, Virtualization Tools
1-2.仮想マシン(ゲストOS)
筐体                             : 下記参照
System ROM                       : 下記参照
CPU                           : 下記参照 
NIC                              : Intel X520-SR2(82599ES)
OS                               : CentOS7.4(1708)
Kernel                           : kernel-3.10.0-693.el7.x86_64
Installed Environment Groups     : Server with GUI
Add-Ons for Selected Environment : Virtualization Client, Virtualization Hypervisor, Virtualization Tools , Development Tools

筐体、System ROMはホストOSにインストールされているqemu-kvmをそのまま使用。
yum updateやupgradeは未実施。
CPUはNestedKVMを有効化しているため、ホストOSと同一 。
ゲストOSはDPDKやpktgenのビルドが必須なため、Development Toolsを加えています。

1-3.全体の流れ

ホストOSでNestedKVM, SR-IOV, VFIOの設定
ゲストOSでHugePage & IOMMU, VFIOの設定
ゲストOSでDPDKのインストール, igb_uioの設定
ゲストOSでpktgenのインストール
ゲストOS×3台使った負荷試験

2.ホストOSの設定

2-1.NestedKVMの設定

ゲストOS3台の名前はc741, c742, c743とします。

ファイルを新規作成
vi /etc/modprobe.d/kvm-nested.conf
以下を追記して保存。
options kvm_intel nested=1

再読み込み
modprobe -r kvm_intel
modprobe kvm_intel

ゲストOS作成後、以下のようにvirshにて設定
virsh edit c741
<cpu mode='custom' match='exact'>
の行を
<cpu mode='host-passthrough'>
に変更して保存。
2-2.SR-IOVの設定*1

grubにiommuの設定追加

vi /etc/default/grub

GRUB_CMDLINE_LINUX=の行末に追加
intel_iommu=on iommu=pt pci=realloc

保存後、grubに反映
grub2-mkconfig -o /etc/grub2.cfg

起動時にVFが作成されるようrc.localの設定

vi /etc/rc.local

最下行に追加
echo 4 > /sys/class/net/ens1f0/device/sriov_numvfs
echo 4 > /sys/class/net/ens1f1/device/sriov_numvfs
sleep 1
ip link set ens1f0 vf 0 mac 00:11:22:33:44:50
ip link set ens1f0 vf 1 mac 00:11:22:33:44:51
ip link set ens1f0 vf 2 mac 00:11:22:33:44:52
ip link set ens1f0 vf 3 mac 00:11:22:33:44:53
ip link set ens1f1 vf 0 mac 00:11:22:33:44:60
ip link set ens1f1 vf 1 mac 00:11:22:33:44:61
ip link set ens1f1 vf 2 mac 00:11:22:33:44:62
ip link set ens1f1 vf 3 mac 00:11:22:33:44:63
sleep 1
ip link set ens1f0 vf 0 spoofchk off
ip link set ens1f0 vf 1 spoofchk off
ip link set ens1f0 vf 2 spoofchk off
ip link set ens1f0 vf 3 spoofchk off
ip link set ens1f1 vf 0 spoofchk off
ip link set ens1f1 vf 1 spoofchk off
ip link set ens1f1 vf 2 spoofchk off
ip link set ens1f1 vf 3 spoofchk off
exit 0

保存後、実行権限を付与
chmod +x /etc/rc.d/rc.local

VFがホストOSに読み込まれないよう設定

vi /lib/modprobe.d/dist-blacklist.conf

最下行に追加
# ixgbevf driver
blacklist ixgbevf
2-3.VFIOの設定*2
ファイルを新規作成
vi /etc/modprobe.d/vfio_pci.conf
以下を追記して保存
options vfio_pci ids=8086:10ed

こちらも追記
echo 'vfio_pci' > /etc/modules-load.d/vfio_pci.conf

一旦再起動
reboot

8086:10edはlspciで表示されるVFのBus,Slot,Function番号(筐体ごとに異なる)から、lspci -n -s 0008:10.2のようにコマンドを入力することでPCIバイスのベンダID(8086)とデバイスID(10ed)を確認し、ベンダID(8086)とデバイスID(10ed)をVFIO-PCI driverに登録します。

3.ゲストOSの設定

ゲストOSの設定の前にVirt-Managerなどで仮想マシンを作成してください。
その際、CPUは4コア、Memは8GB以上が理想です。また、管理用IP以外にPCI Host Deviceとして、VFを2つ追加してください。
VF追加は、こんな感じのイメージです。*3
f:id:metonymical:20180429101259j:plain

3-1.HugePageとIOMMUの設定
vi /etc/default/grub
GRUB_CMDLINE_LINUX=行の最後に以下を追記。
default_hugepagesz=1G hugepagesz=1G hugepages=8 intel_iommu=on iommu=pt

grub2-mkconfig -o /boot/grub2/grub.cfg
3-2.VFIOの設定
ホストOSと同様です。
ファイルを新規作成
vi /etc/modprobe.d/vfio_pci.conf
以下を追記して保存
options vfio_pci ids=8086:10ed

こちらも追記
echo 'vfio_pci' > /etc/modules-load.d/vfio_pci.conf

一旦シャットダウン
shutdown -h now
3-3.ホストパススルーの設定

ホストOS上でゲストOSに対しネストします。
3台とも実施してください。

virsh edit c741

<cpu mode='custom' match='exact'>
を
<cpu mode='host-passthrough'>
に変更して保存

virsh start c741
ゲストOS起動後、sshログインし、以下のコマンドにて動作確認。
dmesg | grep -i vfio
cat /proc/meminfo | grep ^Huge

4.DPDKのインストール

4-1.ソースのDLとビルド
ソースをDLします。
cd /usr/src
wget http://fast.dpdk.org/rel/dpdk-17.11.1.tar.gz
tar zxvf dpdk-17.11.1.tar.gz
cd dpdk-stable-17.11.1

展開したディレクトリでビルドを実施
make install T=x86_64-native-linuxapp-gcc DESTDIR=/usr/local EXTRA_CFLAGS="-O3"
4-2.igb_uioの設定
ファイルを新規作成
vi /etc/sysconfig/modules/igb_uio.modules

#!/bin/sh

modprobe uio
export KERNEL_VERSION=`uname -r`
insmod /usr/local/lib/modules/${KERNEL_VERSION}/extra/dpdk/igb_uio.ko

保存後に実行権限を付与
chmod +x /etc/sysconfig/modules/igb_uio.modules

一旦再起動
reboot

5.pktgenのインストール

5-1.ソースのDLとビルド
ソースをDLします。
cd /usr/src
wget http://www.dpdk.org/browse/apps/pktgen-dpdk/snapshot/pktgen-3.5.0.tar.gz
tar zxvf pktgen-3.5.0.tar.gz

一旦パスを通す
export RTE_SDK=/usr/src/dpdk-stable-17.11.1
export RTE_TARGET=x86_64-native-linuxapp-gcc

展開したディレクトリでビルドを実施
cd pktgen-3.5.0
make 

6.負荷試験

6-1.DPDKにバインド

SR-IOVでパススルーされたVFをゲストOSのKernelからDPDK管理下におくためにバインドします。

dpdk-devbind --status

Network devices using DPDK-compatible driver
============================================


Network devices using kernel driver
===================================
0000:00:07.0 '82599 Ethernet Controller Virtual Function' if=ins2f0 drv=ixgbevf unused=igb_uio,vfio-pci
0000:00:08.0 '82599 Ethernet Controller Virtual Function' if=ins2f1 drv=ixgbevf unused=igb_uio,vfio-pci

~略~

dpdk-devbind -b igb_uio 0000:00:07.0 0000:00:08.0
dpdk-devbind --status

上記バインドを実施することにより、ゲストOS上のカーネルドライバで動作していたVFがDPDKドライバで動作するようになります。バインド後、ゲストOS上でip link showなどを実施しても、ゲストOS上からVFが認識されなくなります(DPDK管理下におかれます)。

6-2.pktgenの起動
ビルドしたディレクトリに移動*4
cd /usr/src/pktgen-3.5.0

移動後のディレクトリ上で、pktgenの起動
app/x86_64-native-linuxapp-gcc/pktgen -- -m "1.0,2.1"
6-3.pktgenで負荷試験実行

pktgenが起動すると以下のような画面となります。
f:id:metonymical:20180507080855j:plain

プロンプトが
Pktgen:/>となるので、
start all
と入力

これを3台のゲストOSで同時に実施し、
行 Pkts /s Max/Tx
列 TotalRate
のフィールドが5Mppsくらいになると、
ワイヤーレート(14.8Mpps)が出てそうな雰囲気になります。
実際にやるとこんな感じです。
f:id:metonymical:20180507083540j:plain
1台あたり5Mpps超えてるのがかなり怪しいですが・・・
ホストOS単体では思うようにワイヤーレートが出なかったので、この辺りはもう少しチューニングが必要だと考えています。

以上です。

7.最後に

以下のサイトを参考にさせて頂きました。
みらくるブログ — サイバートラスト株式会社
Getting Started with Pktgen — Pktgen 3.2.4 documentation

私自身もまだまだ勉強不足なため、不要な設定が入っている気がしています。具体的にはホストOSでSR-IOVしているため、ホストOS上のVFIO設定は不要なのでは?といったところです。ホストとゲスト、ユーザ空間とカーネル空間のどこで必要とされている設定なのか?など、一度整理してみないとダメだなと考えています。

*1:詳細は過去記事を参照してください。CentOS7でSR-IOV設定 - Metonymical Deflection

*2:詳細は過去記事を参照してください。CentOS7でvThunderのセットアップ - Metonymical Deflection

*3:画像はX540のものですが、X520でも同様です。

*4:cdした/usr/src/pktgen-3.5.0のディレクトリ上からでないとpktgenが起動しませんでした。make時のパスの通し方がダメな気がしています。要調査