Metonymical Deflection

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

vDPA の設定方法 vhost_vdpa + VM編

CentOS8によるvDPA(virtio data path acceleration)の設定方法について記載しました。*1
vDPAは、SR-IOVの性能とVirtIOの柔軟性を兼ね備えたフレームワークです。
クラウドネイティブNWを見据え、今後が期待されている技術であり、Linux Kernel 5.7.0より正式にマージされています。
vDPAの詳細はThe official Red Hat blogを参照してください。

本ブログでは、vhost_vdpaモジュールを使用したVM(仮想マシン)間通信の設定方法について記載していきます。

1.構成

1-1.環境
IA server                        : ProLiant DL360p Gen8 or DL360 Gen9
System ROM                       : P71 01/22/2018
NIC                              : Mellanox ConnectX-6 Dx (MCX623106AS-CDAT)
OS                               : CentOS8.3(2011)
Kernel                           : 5.11.11-1.el8.elrepo.x86_64
Installed Environment Groups     : 
  @^graphical-server-environment
  @container-management
  @development
  @virtualization-client
  @virtualization-hypervisor
  @virtualization-tools 
Mellanox OFED                    : v5.2-2.2.0.0
qemu-kvm                         : v6.0.0-rc1
DPDK                             : v21.02
ovs                              : v2.14.1
1-2.全体の流れ

事前準備
Kernelアップデート
qemuのビルド
dpdkのビルド
SR-IOV switchdev modeへ変更
ovs-dpdkとVMの設定
動作確認

1-3.全体構成

DAC(Direct Attached Cable)を使用してループ接続します。 *2
fig.1
f:id:metonymical:20210407180251j:plain
fig.1は簡易的に記載しており、内部アーキテクチャは省略しています。このため、実際は以下の構成をイメージして頂ければと思います。

fig.2
f:id:metonymical:20210408164131j:plain

Red HatのBlogより引用
vDPA kernel framework part 3: usage for VMs and containers

オレンジ色点線の(A)(B)が、それぞれfig.1とfig.2に対応しています。
さらに、fig.2においては、実際のトラフィックフローを青文字と赤文字で記載しています。*3

fig.2において、SR-IOVのPFとVFをそれぞれ記載していますが、これに加えて「VF rep」を記載しています。PFとVF repのbsf(Bus, Slot, Function)番号が同一である点も注意が必要です。

PF VF0 VF0 rep
ens2f0 ens2f0v0 ens2f0_0
07:00.0 07:00.2 07:00.0

rep=representorは、SR-IOVにおけるswtichdevモード特有のインターフェースで、swtichdevモードを有効化することにより作成されます。
また、swtichdevモードに対して、従来のSR-IOV VFをlegacyモードと呼び、明示的に別けて使用する必要があります。加えて、ConnectX-6 Dxでは、vDPA HW offloadを有効化するために、swtichdevモードが必須要件となっています。

2.事前準備

特に記載しませんが、SELinux無効化、FW無効化、NTP時刻同期設定は事前に行っています。

2-1.HugePageとIOMMUの有効化
sed -i -e "/GRUB_CMDLINE_LINUX=/s/\"$/ default_hugepagesz=1G hugepagesz=1G hugepages=16\"/g" /etc/default/grub
sed -i -e "/GRUB_CMDLINE_LINUX=/s/\"$/ intel_iommu=on iommu=pt pci=realloc\"/g" /etc/default/grub
grub2-mkconfig -o /etc/grub2.cfg

次にHugePageのマウント設定を実施しておきます。次回OS起動時に自動マウントされます。

vi /etc/fstab

nodev  /dev/hugepages hugetlbfs pagesize=1GB    0 0
2-2.SR-IOV VFの設定

SR-IOV VFの設定を実施します。VF数を増やしても問題ありませんが、ここでは説明をシンプルにするため、VF数「1」としています。加えて、MACアドレスの設定は必須です。*4

vi /etc/rc.local

echo 1 > /sys/class/net/ens2f0/device/sriov_numvfs
echo 1 > /sys/class/net/ens2f1/device/sriov_numvfs
sleep 1
ip link set ens2f0 vf 0 mac 00:11:22:33:44:00
ip link set ens2f1 vf 0 mac 00:11:22:33:44:10
sleep 1
exit 0

chmod +x /etc/rc.d/rc.local
2-3.Mellanoxドライバ(OFED)のインストール

isoファイルはMellanoxのサイトからDLしてください。Mellanox Download Site
DLしたisoファイルは、/root/tmp/に保存してください。
以下のコマンドにて、Mellanoxドライバをインストールしますが、ovs v2.14.1も同時にインストールされます。

dnf -y install tcl tk unbound && \
mount -t iso9660 -o loop /root/tmp/MLNX_OFED_LINUX-5.2-2.2.0.0-rhel8.3-x86_64.iso /mnt && \
/mnt/mlnxofedinstall --upstream-libs --dpdk --ovs-dpdk --with-mft --with-mstflint

インストールが完了したら、再起動してください。

reboot

再起動が完了したら、HugePageを確認します。

cat /proc/meminfo | grep Huge
grep hugetlbfs /proc/mounts

[root@c83g155 ~]# cat /proc/meminfo | grep Huge
AnonHugePages:    452608 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:      16
HugePages_Free:       16
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:    1048576 kB
Hugetlb:        16777216 kB

[root@c83g155 ~]# grep hugetlbfs /proc/mounts
nodev /dev/hugepages hugetlbfs rw,relatime,pagesize=1024M 0 0

3.Kernelアップデート

2021年4月8日現在、vDPA関連モジュールは高い頻度で更新されていますので、最新のKernelをインストールします。

3-2.Kernelのインストール
dnf list installed | grep kernel
dnf -y --enablerepo=elrepo-kernel install kernel-ml kernel-ml-devel
dnf list installed | grep kernel
reboot

現在インストール済みのKernelを確認
kernel-ml, kernel-ml-develをインストール*5
インストール済みKernelの確認
再起動

3-3.Kernel headersなどのインストール
uname -r
dnf -y swap --enablerepo=elrepo-kernel kernel-headers -- kernel-ml-headers && \
dnf -y remove kernel-tools kernel-tools-libs && \
dnf -y --enablerepo=elrepo-kernel install kernel-ml-tools kernel-ml-tools-libs
dnf list installed | grep kernel

現在起動中のKernel Version確認
kernel-headersのインストール
既存のkernel-tools kernel-tools-libsの削除
kernel-tools kernel-tools-libsのインストール
インストール済みKernelの確認

以下の出力になっていればOKです。

[root@c83g155 ~]# dnf list installed | grep kernel
kernel.x86_64                                      4.18.0-240.el8                                @anaconda
kernel-core.x86_64                                 4.18.0-240.el8                                @anaconda
kernel-devel.x86_64                                4.18.0-240.el8                                @anaconda
kernel-ml.x86_64                                   5.11.11-1.el8.elrepo                          @elrepo-kernel
kernel-ml-core.x86_64                              5.11.11-1.el8.elrepo                          @elrepo-kernel
kernel-ml-devel.x86_64                             5.11.11-1.el8.elrepo                          @elrepo-kernel
kernel-ml-headers.x86_64                           5.11.11-1.el8.elrepo                          @elrepo-kernel
kernel-ml-modules.x86_64                           5.11.11-1.el8.elrepo                          @elrepo-kernel
kernel-ml-tools.x86_64                             5.11.11-1.el8.elrepo                          @elrepo-kernel
kernel-ml-tools-libs.x86_64                        5.11.11-1.el8.elrepo                          @elrepo-kernel
kernel-modules.x86_64                              4.18.0-240.el8                                @anaconda
kmod-kernel-mft-mlnx.x86_64                        4.16.1-1.rhel8u3                              @System
kmod-mlnx-ofa_kernel.x86_64                        5.2-OFED.5.2.2.2.0.1.rhel8u3                  @System
mlnx-ofa_kernel.x86_64                             5.2-OFED.5.2.2.2.0.1.rhel8u3                  @System
mlnx-ofa_kernel-devel.x86_64                       5.2-OFED.5.2.2.2.0.1.rhel8u3                  @System

4.qemuのビルド

4-1.PowerToolsリポジトリの有効化
vi /etc/yum.repos.d/CentOS-Linux-PowerTools.repo

enable=1
4-2.必要なパッケージのインストール

qemuに加えて、dpdkのビルドで必要とされるパッケージも合わせてインストールしています。

dnf -y install cmake gcc libnl3-devel libudev-devel make numactl numactl-devel \
pkgconfig valgrind-devel pandoc libibverbs libmlx5 libmnl-devel meson ninja-build \
glibc-utils glib2 glib2-devel pixman pixman-devel zlib zlib-devel && \
wget https://cbs.centos.org/kojifiles/packages/pyelftools/0.26/1.el8/noarch/python3-pyelftools-0.26-1.el8.noarch.rpm && \
dnf -y localinstall python3-pyelftools-0.26-1.el8.noarch.rpm
4-3.qemuのビルド
cd /usr/src && \
git clone https://github.com/qemu/qemu.git && \
cd qemu/ && \
git checkout v6.0.0-rc1 && \
mkdir build && \
cd build/ && \
../configure --enable-vhost-vdpa --target-list=x86_64-softmmu && \
make -j && \
make install

インストール後のVersion確認

/usr/local/bin/qemu-system-x86_64 --version

[root@c83g155 ~]# /usr/local/bin/qemu-system-x86_64 --version
QEMU emulator version 5.2.91 (v6.0.0-rc1)
Copyright (c) 2003-2021 Fabrice Bellard and the QEMU Project developers
4-4.qemu実行Pathの変更
mv /usr/libexec/qemu-kvm /usr/libexec/qemu-kvm.org
ln -s /usr/local/bin/qemu-system-x86_64 /usr/libexec/qemu-kvm
4-5.qemu実行ユーザの変更
vi /etc/libvirt/qemu.conf

user = "root"  #comment out
group = "root"  #comment out

5.dpdkのビルド

5-1.dpdkのビルド
cd /usr/src/ && \
git clone git://dpdk.org/dpdk && \
cd dpdk && \
git checkout v21.02 && \
meson -Dexamples=all build && \
ninja -C build && \
ninja -C build install
5-2.dpdk関連ライブラリのリンク

viで新規ファイルを作成し、libのPathを記載してください。

vi /etc/ld.so.conf.d/libdpdk.conf

/usr/src/dpdk/build/lib

ldconfigを実行後、libがリンクされたことを確認してください。

ldconfig
ldconfig -p |grep dpdk

以下のようにポイントされていればOKです。

[root@c83g155 dpdk]# ldconfig -p |grep dpdk
        librte_vhost.so.21 (libc6,x86-64) => /usr/src/dpdk/build/lib/librte_vhost.so.21
        librte_vhost.so (libc6,x86-64) => /usr/src/dpdk/build/lib/librte_vhost.so
        librte_timer.so.21 (libc6,x86-64) => /usr/src/dpdk/build/lib/librte_timer.so.21

ここで、一旦再起動しておきます。

reboot

6.SR-IOV switchdev modeへ変更

6-1.現在の動作モードを確認
lshw -businfo -c network
devlink dev eswitch show pci/0000:07:00.0
devlink dev eswitch show pci/0000:07:00.1

PCIバイスのbsf(bus, slot, function)番号を確認
07:00.0(ens2f0)のステータス確認
07:00.1(ens2f1)のステータス確認

以下のように出力されます。

[root@c83g155 ~]# lshw -businfo -c network
Bus info          Device      Class          Description
========================================================
pci@0000:04:00.0  ens1f0      network        82599ES 10-Gigabit SFI/SFP+ Network Connection
pci@0000:04:00.1  ens1f1      network        82599ES 10-Gigabit SFI/SFP+ Network Connection
pci@0000:03:00.0  eno1        network        NetXtreme BCM5719 Gigabit Ethernet PCIe
pci@0000:03:00.1  eno2        network        NetXtreme BCM5719 Gigabit Ethernet PCIe
pci@0000:03:00.2  eno3        network        NetXtreme BCM5719 Gigabit Ethernet PCIe
pci@0000:03:00.3  eno4        network        NetXtreme BCM5719 Gigabit Ethernet PCIe
pci@0000:07:00.0  ens2f0      network        MT2892 Family [ConnectX-6 Dx]
pci@0000:07:00.1  ens2f1      network        MT2892 Family [ConnectX-6 Dx]
pci@0000:07:00.2  ens2f0v0    network        ConnectX Family mlx5Gen Virtual Function
pci@0000:07:01.2  ens2f1v0    network        ConnectX Family mlx5Gen Virtual Function

[root@c83g155 ~]# devlink dev eswitch show pci/0000:07:00.0
pci/0000:07:00.0: mode legacy inline-mode none encap disable

[root@c83g155 ~]# devlink dev eswitch show pci/0000:07:00.1
pci/0000:07:00.1: mode legacy inline-mode none encap disable
6-2.動作モードの変更

bsf番号が微妙に異なっている点に注意してください。*6

echo 0000:07:00.2 > /sys/bus/pci/drivers/mlx5_core/unbind && \
echo 0000:07:01.2 > /sys/bus/pci/drivers/mlx5_core/unbind && \
devlink dev eswitch set pci/0000:07:00.0 mode switchdev && \
devlink dev eswitch set pci/0000:07:00.1 mode switchdev && \
echo 0000:07:00.2 > /sys/bus/pci/drivers/mlx5_core/bind && \
echo 0000:07:01.2 > /sys/bus/pci/drivers/mlx5_core/bind

VFのmlx5_coreドライバをアンバインドします。

07:00.2 ens2f0v0
07:01.2 ens2f1v0

PFの動作モードをswitchdevに変更します。

07:00.0 ens2f0
07:00.1 ens2f1

VFのmlx5_coreドライバを再バインドします。

07:00.2 ens2f0v0
07:01.2 ens2f1v0
6-3.変更後の動作モードを確認
devlink dev eswitch show pci/0000:07:00.0
devlink dev eswitch show pci/0000:07:00.1

switchdev モードに変更されました。

[root@c83g155 ~]# devlink dev eswitch show pci/0000:07:00.0
pci/0000:07:00.0: mode switchdev inline-mode none encap enable

[root@c83g155 ~]# devlink dev eswitch show pci/0000:07:00.1
pci/0000:07:00.1: mode switchdev inline-mode none encap enable

VF Representerが追加されています。

[root@c83g155 ~]# lshw -businfo -c network                                                                                   Bus info          Device      Class          Description
========================================================
pci@0000:04:00.0  ens1f0      network        82599ES 10-Gigabit SFI/SFP+ Network Connection
pci@0000:04:00.1  ens1f1      network        82599ES 10-Gigabit SFI/SFP+ Network Connection
pci@0000:03:00.0  eno1        network        NetXtreme BCM5719 Gigabit Ethernet PCIe
pci@0000:03:00.1  eno2        network        NetXtreme BCM5719 Gigabit Ethernet PCIe
pci@0000:03:00.2  eno3        network        NetXtreme BCM5719 Gigabit Ethernet PCIe
pci@0000:03:00.3  eno4        network        NetXtreme BCM5719 Gigabit Ethernet PCIe
pci@0000:07:00.0  ens2f0      network        MT2892 Family [ConnectX-6 Dx]
pci@0000:07:00.1  ens2f1      network        MT2892 Family [ConnectX-6 Dx]
pci@0000:07:00.2  ens2f0v0    network        ConnectX Family mlx5Gen Virtual Function
pci@0000:07:01.2  ens2f1v0    network        ConnectX Family mlx5Gen Virtual Function
pci@0000:07:00.0  ens2f0_0    network        Ethernet interface
pci@0000:07:00.1  ens2f1_0    network        Ethernet interface

さらに、NICのHW offload機能が有効化されていることも確認します。

ethtool -k ens2f0 |grep tc
ethtool -k ens2f1 |grep tc

[root@c83g155 ~]# ethtool -k ens2f0 |grep tc
tcp-segmentation-offload: on
        tx-tcp-segmentation: on
        tx-tcp-ecn-segmentation: off [fixed]
        tx-tcp-mangleid-segmentation: off
        tx-tcp6-segmentation: on
hw-tc-offload: on

[root@c83g155 ~]# ethtool -k ens2f1 |grep tc
tcp-segmentation-offload: on
        tx-tcp-segmentation: on
        tx-tcp-ecn-segmentation: off [fixed]
        tx-tcp-mangleid-segmentation: off
        tx-tcp6-segmentation: on
hw-tc-offload: on

7.ovs-dpdkとVMの設定

7-1.全体の流れ ~概要~

以下のfig.1に記載されている(1)-(9)の順に設定していきます。
fig.1
f:id:metonymical:20210407180251j:plain

  1. vhost_vdpaモジュールの有効化:(1)
  2. ovsの初期設定
  3. br30-ovsの設定:(2)(3)(4)
  4. br31-ovsの設定:(5)(6)(7)
  5. 仮想マシンc77g153の設定と起動:(8)
  6. 仮想マシンc77g159の設定と起動:(9)
7-2.全体の流れ ~コマンドのみ~

以下のコマンドを投入していきます。
詳細な解説は後述しますが、解説が不要な方はコマンドだけを実行してください。

1.vhost_vdpaモジュールの有効化
(1)
modprobe vhost_vdpa

2.ovsの初期設定
systemctl start openvswitch
ovs-vsctl set Open_vSwitch . other_config:dpdk-init=true
ovs-vsctl set Open_vSwitch . other_config:hw-offload=true other_config:tc-policy=none
ovs-vsctl set Open_vSwitch . other_config:dpdk-socket-mem=1024,1024
ovs-vsctl set Open_vSwitch . other_config:vhost-iommu-support=true
ovs-vsctl set Open_vSwitch . other_config:dpdk-extra=" \
-w 0000:07:00.0,representor=[0],dv_flow_en=1,dv_esw_en=1,dv_xmeta_en=0 \
-w 0000:07:00.1,representor=[0],dv_flow_en=1,dv_esw_en=1,dv_xmeta_en=0"
systemctl restart openvswitch

3.br30-ovsの設定
(2)
ovs-vsctl add-br br30-ovs -- set bridge br30-ovs datapath_type=netdev
(3)
ovs-vsctl add-port br30-ovs ens2f0 -- set Interface ens2f0 type=dpdk options:dpdk-devargs=0000:07:00.0
(4)
ovs-vsctl add-port br30-ovs ens2f0_0 -- set Interface ens2f0_0 type=dpdk options:dpdk-devargs=0000:07:00.0,representor=[0]
 
4.br31-ovsの設定
(5)
ovs-vsctl add-br br31-ovs -- set bridge br31-ovs datapath_type=netdev
(6)
ovs-vsctl add-port br31-ovs ens2f1 -- set Interface ens2f1 type=dpdk options:dpdk-devargs=0000:07:00.1
(7)
ovs-vsctl add-port br31-ovs ens2f1_0 -- set Interface ens2f1_0 type=dpdk options:dpdk-devargs=0000:07:00.1,representor=[0]

5.仮想マシンc77g153の設定と起動
(8)
qemu-system-x86_64 \
 -enable-kvm \
 -cpu host \
 -m 8G \
 -hda /var/lib/libvirt/images/c77g1532.qcow2 \
 -netdev type=vhost-vdpa,vhostdev=/dev/vhost-vdpa-0,id=vhost-vdpa0 \
 -device virtio-net-pci,netdev=vhost-vdpa0,page-per-vq=on,iommu_platform=on,disable-legacy=on \
 -nographic \
 2>&1 | tee vm153.log

6.仮想マシンc77g159の設定と起動
(9)
qemu-system-x86_64 \
 -enable-kvm \
 -cpu host \
 -m 8G \
 -hda /var/lib/libvirt/images/c77g1592.qcow2 \
 -netdev type=vhost-vdpa,vhostdev=/dev/vhost-vdpa-1,id=vhost-vdpa1 \
 -device virtio-net-pci,netdev=vhost-vdpa1,page-per-vq=on,iommu_platform=on,disable-legacy=on \
 -nographic \
 2>&1 | tee vm159.log
7-3.vhost_vdpaモジュールの有効化:(1)

modprobe vhost_vdpa コマンドの実行前と実行後の変化を確認していきます。

modprobe vhost_vdpa実行前

lsmod |grep vd
ls -Fal /dev
ls -Fal /sys/bus/vdpa/drivers/vhost_vdpa

[root@c83g155 ~]# lsmod |grep vd
mlx5_vdpa              45056  0
vhost_iotlb            16384  2 vhost,mlx5_vdpa
vdpa                   16384  1 mlx5_vdpa
mlx5_core            1216512  2 mlx5_vdpa,mlx5_ib

[root@c83g155 ~]# ls -Fal /dev
total 0
drwxr-xr-x  22 root root          3660 Apr  8 00:02 ./
dr-xr-xr-x. 17 root root           244 Apr  7 20:30 ../
crw-r--r--   1 root root       10, 235 Apr  7 23:28 autofs
drwxr-xr-x   2 root root           160 Apr  7 23:28 block/
drwxr-xr-x   2 root root           100 Apr  7 23:28 bsg/
============ s n i p ============
drwxr-xr-x   2 root root            60 Apr  7 23:28 vfio/
crw-------   1 root root       10, 127 Apr  7 23:28 vga_arbiter
crw-------   1 root root       10, 137 Apr  7 23:28 vhci
crw-------   1 root root       10, 238 Apr  7 23:28 vhost-net
crw-------   1 root root       10, 241 Apr  7 23:28 vhost-vsock

[root@c83g155 ~]# ls -Fal /sys/bus/vdpa/drivers/vhost_vdpa
ls: cannot access '/sys/bus/vdpa/drivers/vhost_vdpa': No such file or directory

modprobe vhost_vdpa実行後

modprobe vhost_vdpa
lsmod |grep vd
ls -Fal /dev
ls -Fal /sys/bus/vdpa/drivers/vhost_vdpa

[root@c83g155 ~]# lsmod |grep vd
vhost_vdpa             24576  0
vhost                  57344  1 vhost_vdpa
mlx5_vdpa              45056  0
vhost_iotlb            16384  3 vhost_vdpa,vhost,mlx5_vdpa
vdpa                   16384  2 vhost_vdpa,mlx5_vdpa
irqbypass              16384  2 vhost_vdpa,kvm
mlx5_core            1216512  2 mlx5_vdpa,mlx5_ib

[root@c83g155 ~]# ls -Fal /dev
total 0
drwxr-xr-x  22 root root          3660 Apr  8 00:02 ./
dr-xr-xr-x. 17 root root           244 Apr  7 20:30 ../
crw-r--r--   1 root root       10, 235 Apr  7 23:28 autofs
drwxr-xr-x   2 root root           160 Apr  7 23:28 block/
drwxr-xr-x   2 root root           100 Apr  7 23:28 bsg/
============ s n i p ============
drwxr-xr-x   2 root root            60 Apr  7 23:28 vfio/
crw-------   1 root root       10, 127 Apr  7 23:28 vga_arbiter
crw-------   1 root root       10, 137 Apr  7 23:28 vhci
crw-------   1 root root       10, 238 Apr  7 23:28 vhost-net
crw-------   1 root root      240,   0 Apr  8 00:06 vhost-vdpa-0
crw-------   1 root root      240,   1 Apr  8 00:06 vhost-vdpa-1
crw-------   1 root root       10, 241 Apr  7 23:28 vhost-vsock

[root@c83g155 ~]# ls -Fal /sys/bus/vdpa/drivers/vhost_vdpa
total 0
drwxr-xr-x 2 root root    0 Apr  8 00:06 ./
drwxr-xr-x 3 root root    0 Apr  7 23:49 ../
--w------- 1 root root 4096 Apr  8 00:07 bind
lrwxrwxrwx 1 root root    0 Apr  8 00:07 module -> ../../../../module/vhost_vdpa/
--w------- 1 root root 4096 Apr  8 00:06 uevent
--w------- 1 root root 4096 Apr  8 00:07 unbind
lrwxrwxrwx 1 root root    0 Apr  8 00:07 vdpa0 -> ../../../../devices/pci0000:00/0000:00:03.0/0000:07:00.2/vdpa0/
lrwxrwxrwx 1 root root    0 Apr  8 00:07 vdpa1 -> ../../../../devices/pci0000:00/0000:00:03.0/0000:07:01.2/vdpa1/

上記の出力結果より、以下のことが確認できます。

  • /dev/vhost-vdpa-0と/dev/vhost-vdpa-1がvhost_vdpaデバイスとして認識されている
  • 0000:07:00.2/vdpa0と0000:07:01.2/vdpa1がvhost_vdpaドライバで制御されている
7-4.ovsの初期設定

ovsは、既にインストール済みなので*7、systemctlからサービスをスタートします。

systemctl start openvswitch
ovs-vsctl set Open_vSwitch . other_config:dpdk-init=true
ovs-vsctl set Open_vSwitch . other_config:hw-offload=true other_config:tc-policy=none
ovs-vsctl set Open_vSwitch . other_config:dpdk-socket-mem=1024,1024
ovs-vsctl set Open_vSwitch . other_config:vhost-iommu-support=true
ovs-vsctl set Open_vSwitch . other_config:dpdk-extra=" \
-w 0000:07:00.0,representor=[0],dv_flow_en=1,dv_esw_en=1,dv_xmeta_en=0 \
-w 0000:07:00.1,representor=[0],dv_flow_en=1,dv_esw_en=1,dv_xmeta_en=0"
systemctl restart openvswitch

ovsサービスの起動
dpdkの初期化
HW offloadとtc-policyの設定
メモリ割当て
vhostのIOMMU設定
representerの設定
ovsサービスの再起動(上記設定を反映させるため)

以下のコマンドで設定内容を確認します。

ovs-vsctl get Open_vSwitch . other_config

[root@c83g155 ~]# ovs-vsctl get Open_vSwitch . other_config
{dpdk-extra=" -w 0000:07:00.0,representor=[0],dv_flow_en=1,dv_esw_en=1,dv_xmeta_en=0 -w 0000:07:00.1,representor=[0],dv_flow_en=1,dv_esw_en=1,dv_xmeta_en=0", dpdk-init="true", dpdk-socket-mem="1024,1024", hw-offload="true", tc-policy=none, vhost-iommu-support="true"}

<補足1>
other_config:dpdk-extraについて、補足します。
lshw -businfo -c network の出力結果とother_config:dpdk-extra で設定したコマンドには、以下の対応関係があります。

0000:07:00.0 ens2f0_0 -w 0000:07:00.0,representor=[0]
0000:07:00.1 ens2f1_0 -w 0000:07:00.1,representor=[0]

<補足2>
other_config:tc-policyについて、補足します。
tc-policyは、以下のオプションが設定可能です。

none adds a TC rule to both the software and the hardware (default)
skip_sw adds a TC rule only to the hardware
skip_hw adds a TC rule only to the software

<補足3>
設定を削除したい場合は、以下のようにコマンドを実行してください。
dpdk-extra がキーとなっていますので、dpdk-initやhw-offloadなど、削除したい任意のキーを指定してください。

ovs-vsctl remove Open_vSwitch . other_config dpdk-extra
7-5.br30-ovsの設定:(2)(3)(4)

1つ目のブリッジを作成します。

(2)
ovs-vsctl add-br br30-ovs -- set bridge br30-ovs datapath_type=netdev
(3)
ovs-vsctl add-port br30-ovs ens2f0 -- set Interface ens2f0 type=dpdk options:dpdk-devargs=0000:07:00.0
(4)
ovs-vsctl add-port br30-ovs ens2f0_0 -- set Interface ens2f0_0 type=dpdk options:dpdk-devargs=0000:07:00.0,representor=[0]

(2)ブリッジの作成
(3)アップリンクの作成(PFを指定し、外部NW向けのインターフェースを設定)
(4)ダウンリンクの作成(VF Representerを指定し、VM向けのインターフェースを設定)

以下のコマンドで設定を確認します。

[root@c83g155 ~]# ovs-vsctl show
59a34ea2-ca80-48b9-8b14-a656c79bc451
    Bridge br30-ovs
        datapath_type: netdev
        Port br30-ovs
            Interface br30-ovs
                type: internal
        Port ens2f0_0
            Interface ens2f0_0
                type: dpdk
                options: {dpdk-devargs="0000:07:00.0,representor=[0]"}
        Port ens2f0
            Interface ens2f0
                type: dpdk
                options: {dpdk-devargs="0000:07:00.0"}
    ovs_version: "2.14.1"
7-6.br31-ovsの設定:(5)(6)(7)

2つ目のブリッジを作成します。

(5)
ovs-vsctl add-br br31-ovs -- set bridge br31-ovs datapath_type=netdev
(6)
ovs-vsctl add-port br31-ovs ens2f1 -- set Interface ens2f1 type=dpdk options:dpdk-devargs=0000:07:00.1
(7)
ovs-vsctl add-port br31-ovs ens2f1_0 -- set Interface ens2f1_0 type=dpdk options:dpdk-devargs=0000:07:00.1,representor=[0]

(2)(3)(4)と同様です。

以下のコマンドで設定を確認します。青文字が追加された部分です。

[root@c83g155 ~]# ovs-vsctl show
59a34ea2-ca80-48b9-8b14-a656c79bc451
    Bridge br31-ovs
        datapath_type: netdev
        Port ens2f1_0
            Interface ens2f1_0
                type: dpdk
                options: {dpdk-devargs="0000:07:00.1,representor=[0]"}
        Port ens2f1
            Interface ens2f1
                type: dpdk
                options: {dpdk-devargs="0000:07:00.1"}
        Port br31-ovs
            Interface br31-ovs
                type: internal
    Bridge br30-ovs
        datapath_type: netdev
        Port br30-ovs
            Interface br30-ovs
                type: internal
        Port ens2f0_0
            Interface ens2f0_0
                type: dpdk
                options: {dpdk-devargs="0000:07:00.0,representor=[0]"}
        Port ens2f0
            Interface ens2f0
                type: dpdk
                options: {dpdk-devargs="0000:07:00.0"}
    ovs_version: "2.14.1"
7-7.仮想マシンc77g153の設定と起動:(8)

/var/lib/libvirt/images/にqcow2ファイルをアップロードしておいてください。
本ブログでは、CentOS7.7をインストールしたqcow2ファイルを予め準備していました。

(8)
qemu-system-x86_64 \
 -enable-kvm \
 -cpu host \
 -m 8G \
 -hda /var/lib/libvirt/images/c77g1532.qcow2 \
 -netdev type=vhost-vdpa,vhostdev=/dev/vhost-vdpa-0,id=vhost-vdpa0 \
 -device virtio-net-pci,netdev=vhost-vdpa0,page-per-vq=on,iommu_platform=on,disable-legacy=on \
 -nographic \
 2>&1 | tee vm153.log
type=vhost-vdpa vhost-vdpaをtypeに指定できるようにするため、qemuをソースからビルドしています。
vhostdev=/dev/vhost-vdpa-0 modprobe vhost_vdpa コマンドで生成されたvdpaデバイスを指定しています。
page-per-vq=on virtqueueを使用するため必須の設定です
iommu_platform=on 詳細は確認できていませんが、fig.2よりPlatformIOMMUとvirtqueueのやり取りで使用するため必須の設定と思われます。
7-8.仮想マシンc77g159の設定と起動:(9)

qcow2ファイルやvdpaデバイス以外は、7-7と同様です。

(9)
qemu-system-x86_64 \
 -enable-kvm \
 -cpu host \
 -m 8G \
 -hda /var/lib/libvirt/images/c77g1592.qcow2 \
 -netdev type=vhost-vdpa,vhostdev=/dev/vhost-vdpa-1,id=vhost-vdpa1 \
 -device virtio-net-pci,netdev=vhost-vdpa1,page-per-vq=on,iommu_platform=on,disable-legacy=on \
 -nographic \
 2>&1 | tee vm159.log

8.動作確認

既に(8)(9)のコマンドを実行した結果、VM(c77g153 と c77g159)が起動済みですが、正常動作を確認するため、一旦シャットダウンしてください。

8-1.事前準備

ホストOS c83g155で5つのコンソールを準備してください。

ConsoleA tail -f /var/log/messages VM起動時に確認すべきログを参照するため
ConsoleB watch ovs-ofctl -O OpenFlow14 dump-ports br30-ovs c77g153のパケットカウントを確認するため
ConsoleC watch ovs-ofctl -O OpenFlow14 dump-ports br31-ovs c77g159のパケットカウントを確認するため
ConsoleD (8)のコマンドを実行 仮想マシンc77g153のコンソール用
ConsoleE (9)のコマンドを実行 仮想マシンc77g159のコンソール用
8-2.VMの起動

VMを起動する前に、ConsoleA, B, Cでは上記のコマンドを実行しておいてください。
その後、(8)のコマンドを実行し、c77g153を起動します。
数秒待ってから、(9)のコマンドを実行し、c77g159を起動します。
c77g153 or c77g159からPingを飛ばしてください。
例として、fig.1に従い、c77g153から ping 192.168.30.159 -f を実行します。

fig.1
f:id:metonymical:20210407180251j:plain

以下、出力結果です。注目する箇所は赤文字にしています。
ConsoleA

Apr  8 10:38:21 c83g155 dbus-daemon[2076]: [session uid=0 pid=2076] Activating via systemd: service name='org.freedesktop.Tracker1.Miner.Extract' unit='tracker-extract.service' requested by ':1.72' (uid=0 pid=2706 comm="/usr/libexec/tracker-miner-fs ")
Apr  8 10:38:21 c83g155 systemd[1919]: Starting Tracker metadata extractor...
Apr  8 10:38:21 c83g155 kernel: mlx5_core 0000:07:00.2: mlx5_vdpa_set_status:1786:(pid 5077): performing device reset
Apr  8 10:38:21 c83g155 kvm[5088]: 1 guest now active
Apr  8 10:38:21 c83g155 dbus-daemon[2076]: [session uid=0 pid=2076] Successfully activated service 'org.freedesktop.Tracker1.Miner.Extract'
Apr  8 10:38:21 c83g155 systemd[1919]: Started Tracker metadata extractor.
Apr  8 10:38:46 c83g155 kernel: mlx5_core 0000:07:00.2: mlx5_vdpa_handle_set_map:473:(pid 5086): memory map update
Apr  8 10:38:51 c83g155 ovs-vswitchd[4998]: ovs|00001|dpif_netdev(revalidator17)|ERR|internal error parsing flow key skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(6),packet_type(ns=0,id=0),eth(src=00:11:22:33:44:00,dst=01:00:5e:00:00:16),eth_type(0x0800),ipv4(src=192.168.30.153,dst=224.0.0.22,proto=2,tos=0xc0,ttl=1,frag=no)
Apr  8 10:38:51 c83g155 ovs-vswitchd[4998]: ovs|00002|dpif_netdev(revalidator17)|ERR|internal error parsing flow key skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(3),packet_type(ns=0,id=0),eth(src=00:11:22:33:44:00,dst=01:00:5e:00:00:16),eth_type(0x0800),ipv4(src=192.168.30.153,dst=224.0.0.22,proto=2,tos=0xc0,ttl=1,frag=no)
Apr  8 10:39:08 c83g155 systemd[1919]: tracker-extract.service: Succeeded.

Apr  8 10:41:52 c83g155 dbus-daemon[2076]: [session uid=0 pid=2076] Activating via systemd: service name='org.freedesktop.Tracker1.Miner.Extract' unit='tracker-extract.service' requested by ':1.72' (uid=0 pid=2706 comm="/usr/libexec/tracker-miner-fs ")
Apr  8 10:41:52 c83g155 systemd[1919]: Starting Tracker metadata extractor...
Apr  8 10:41:52 c83g155 kernel: mlx5_core 0000:07:01.2: mlx5_vdpa_set_status:1786:(pid 5370): performing device reset
Apr  8 10:41:52 c83g155 kvm[5380]: 2 guests now active
Apr  8 10:41:52 c83g155 dbus-daemon[2076]: [session uid=0 pid=2076] Successfully activated service 'org.freedesktop.Tracker1.Miner.Extract'
Apr  8 10:41:52 c83g155 systemd[1919]: Started Tracker metadata extractor.
Apr  8 10:42:16 c83g155 kernel: mlx5_core 0000:07:01.2: mlx5_vdpa_handle_set_map:473:(pid 5381): memory map update
Apr  8 10:42:21 c83g155 ovs-vswitchd[4998]: ovs|00005|dpif_netdev(revalidator17)|ERR|internal error parsing flow key skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(2),packet_type(ns=0,id=0),eth(src=00:11:22:33:44:10,dst=01:00:5e:00:00:16),eth_type(0x0800),ipv4(src=192.168.30.159,dst=224.0.0.22,proto=2,tos=0xc0,ttl=1,frag=no)
Apr  8 10:42:21 c83g155 ovs-vswitchd[4998]: ovs|00006|dpif_netdev(revalidator17)|ERR|internal error parsing flow key skb_priority(0),skb_mark(0),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(4),packet_type(ns=0,id=0),eth(src=00:11:22:33:44:10,dst=01:00:5e:00:00:16),eth_type(0x0800),ipv4(src=192.168.30.159,dst=224.0.0.22,proto=2,tos=0xc0,ttl=1,frag=no)
Apr  8 10:42:40 c83g155 systemd[1919]: tracker-extract.service: Succeeded.

ConsoleB

[root@c83g155 ~]# ovs-ofctl -O OpenFlow14 dump-ports br30-ovs
OFPST_PORT reply (OF1.4) (xid=0x2): 3 ports
  port  ens2f0: rx pkts=85847, bytes=8414161, drop=0, errs=0, frame=?, over=?, crc=?
           tx pkts=85847, bytes=8414028, drop=0, errs=0, coll=?
           duration=423.079s
           rx rfc2819 broadcast_packets=2,
           tx rfc2819 multicast_packets=54, broadcast_packets=1,
           CUSTOM Statistics
                      ovs_tx_failure_drops=0, ovs_tx_mtu_exceeded_drops=0, ovs_tx_qos_drops=0,
                      ovs_rx_qos_drops=0, ovs_tx_invalid_hwol_drops=0, rx_missed_errors=0,
                      rx_errors=0, tx_errors=0, rx_mbuf_allocation_errors=0,
                      rx_q0_errors=0, rx_wqe_errors=0, rx_phy_crc_errors=0,
                      rx_phy_in_range_len_errors=0, rx_phy_symbol_errors=0, tx_phy_errors=0,
                      tx_pp_missed_interrupt_errors=0, tx_pp_rearm_queue_errors=0, tx_pp_clock_queue_errors=0,
                      tx_pp_timestamp_past_errors=0, tx_pp_timestamp_future_errors=0,
  port LOCAL: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
           tx pkts=0, bytes=0, drop=55, errs=0, coll=0
           duration=423.075s
  port  "ens2f0_0": rx pkts=85847, bytes=8414028, drop=0, errs=0, frame=?, over=?, crc=?
           tx pkts=85847, bytes=8414161, drop=0, errs=0, coll=?
           duration=422.848s
           CUSTOM Statistics
                      ovs_tx_failure_drops=0, ovs_tx_mtu_exceeded_drops=0, ovs_tx_qos_drops=0,
                      ovs_rx_qos_drops=0, ovs_tx_invalid_hwol_drops=0, rx_missed_errors=0,
                      rx_errors=0, tx_errors=0, rx_mbuf_allocation_errors=0,
                      rx_q0_errors=0, tx_pp_missed_interrupt_errors=0, tx_pp_rearm_queue_errors=0,
                      tx_pp_clock_queue_errors=0, tx_pp_timestamp_past_errors=0, tx_pp_timestamp_future_errors=0,

ConsoleC

[root@c83g155 ~]# ovs-ofctl -O OpenFlow14 dump-ports br31-ovs
OFPST_PORT reply (OF1.4) (xid=0x2): 3 ports
  port  ens2f1: rx pkts=85847, bytes=8414104, drop=0, errs=0, frame=?, over=?, crc=?
           tx pkts=85847, bytes=8414085, drop=0, errs=0, coll=?
           duration=450.620s
           rx rfc2819 broadcast_packets=2,
           tx rfc2819 multicast_packets=54, broadcast_packets=1,
           CUSTOM Statistics
                      ovs_tx_failure_drops=0, ovs_tx_mtu_exceeded_drops=0, ovs_tx_qos_drops=0,
                      ovs_rx_qos_drops=0, ovs_tx_invalid_hwol_drops=0, rx_missed_errors=0,
                      rx_errors=0, tx_errors=0, rx_mbuf_allocation_errors=0,
                      rx_q0_errors=0, rx_wqe_errors=0, rx_phy_crc_errors=0,
                      rx_phy_in_range_len_errors=0, rx_phy_symbol_errors=0, tx_phy_errors=0,
                      tx_pp_missed_interrupt_errors=0, tx_pp_rearm_queue_errors=0, tx_pp_clock_queue_errors=0,
                      tx_pp_timestamp_past_errors=0, tx_pp_timestamp_future_errors=0,
  port LOCAL: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
           tx pkts=0, bytes=0, drop=55, errs=0, coll=0
           duration=451.970s
  port  "ens2f1_0": rx pkts=85847, bytes=8414085, drop=0, errs=0, frame=?, over=?, crc=?
           tx pkts=85847, bytes=8414104, drop=0, errs=0, coll=?
           duration=450.915s
           CUSTOM Statistics
                      ovs_tx_failure_drops=0, ovs_tx_mtu_exceeded_drops=0, ovs_tx_qos_drops=0,
                      ovs_rx_qos_drops=0, ovs_tx_invalid_hwol_drops=0, rx_missed_errors=0,
                      rx_errors=0, tx_errors=0, rx_mbuf_allocation_errors=0,
                      rx_q0_errors=0, tx_pp_missed_interrupt_errors=0, tx_pp_rearm_queue_errors=0,
                      tx_pp_clock_queue_errors=0, tx_pp_timestamp_past_errors=0, tx_pp_timestamp_future_errors=0,

ConsoleD

[root@c77g153 ~]# ping 192.168.30.159 -f
PING 192.168.30.159 (192.168.30.159) 56(84) bytes of data.

--- 192.168.30.159 ping statistics ---
85742 packets transmitted, 85742 received, 0% packet loss, time 20040ms
rtt min/avg/max/mdev = 0.093/0.111/7.100/0.055 ms, ipg/ewma 0.233/0.144 ms

<補足>

performing device reset mlx5_coreによりmlx5_vdpaが初期化されています。
memory map update mlx5_coreによりmlx5_vdpaのIOMMUメモリマッピングとアップデートが実行されています。なお、このログが出力されない限り、絶対に通信することはできないため、最重要メッセージとなります。
internal error parsing flow key ovsがマルチキャスト関連のエラーを出していますが、特に問題はありません。気にしないでください。
ens2f0 "ens2f0_0" 各ポートのtx/rxのパケットカウントとバイトカウントが上昇していることが確認できます。


以上です。

*1:各種ドキュメントを確認した結果、vDPAの"v"は、virtual, vhost, virtioの3種類ありますが、意味は全て同じようです。本ブログでは、 Introduction to vDPA kernel framework に従い、virtioの表記で統一しました。

*2:対向機器に100Gbpsスイッチや100GNIC搭載サーバが用意できない場合を考慮し、ループ接続としています。但し、VMで生成したパケットが物理的に外部へ送信されることが重要と考えているため、fig.1の構成としています。

*3:私が理解した内容を記載しています。内容が誤っている場合には、ご指摘ください。

*4:MACアドレスの設定を実施しておかないと、VM起動後にVMがVFを認識しない事象を確認しました。

*5:coreやmodulesも同時にインストールされます

*6:蛇足ですが、bsf番号の前の「0000」は、Domain番号と呼ばれています。私が知る限りでは「0000」以外の値を見たことが無いため、あまり気にしなくてよいと思います。

*7:2-3.Mellanoxドライバ(OFED)のインストールで、インストール済みです。