DPDK数据路径提供DPDK支持的vHost User端口作为与客户机交互的主要方式。有关vHost User的详细信息,请参阅’qemu’在同一文件上。
重要:
要使用任何基于DPDK的端口,你必须确保网桥已正确配置。更多信息请参见bridge.
快速示例
本示例演示如何添加两个dpdkvhostuserclient
端口到已有的网桥br0
中:
$ ovs-vsctl add-port br0 dpdkvhostclient0 \
-- set Interface dpdkvhostclient0 type=dpdkvhostuserclient \
options:vhost-server-path=/tmp/dpdkvhostclient0
$ ovs-vsctl add-port br0 dpdkvhostclient1 \
-- set Interface dpdkvhostclient1 type=dpdkvhostuserclient \
options:vhost-server-path=/tmp/dpdkvhostclient1
以上的示例要正常工作,相应的服务套接口必须在指定目录创建 (/tmp/dpdkvhostclient0
和 /tmp/dpdkvhostclient1
). 这些套接口可通过QEMU创建。详细信息参见vhost-user client一节.
vhost-user vs. vhost-user-client
Open vSwitch提供两种类型的vHost User 端口:
-
vhost-user (
dpdkvhostuser
) -
vhost-user-client (
dpdkvhostuserclient
)
vHost User使用客户端-服务器模型。服务端创建/管理/销毁vHost User套接口,客户端连接到服务端。依据使用的端口类型,dpdkvhostuser
或者 dpdkvhostuserclient
,客户端-服务器模型使用不同的配置。
对于vhost-user端口,Open vSwitch作为服务端,QEMU为客户端。这意味着如果OVS进程挂掉,所有的虚拟机必须重新启动。反之,对于vhost-user-client端口,OVS作为客户端,QEMU为服务器。这意味着OVS可以挂掉,并在不引起问题的情况下重新启动,也可重新启动客户机自身。由此原因,vhost-user-client端口为在所有已知情况下的首选类型。唯一的限制时vhost-user-client类型端口需要QEMU版本2.7. 端口类型vhost-user目前不赞成使用,并且将在以后的版本中移除。
vhost-user
重要:
使用vhost-user端口需要QEMU >= 2.2; vhost-user端口已被废弃.
要使用vhost-user 端口, 必须先将端口添加到交换机. DPDK vhost-user 端口可取任意的名称,但是不能包含反向和正向斜线。对于vhost-user,端口类型为dpdkvhostuser
:
$ ovs-vsctl add-port br0 vhost-user-1 -- set Interface vhost-user-1 \
type=dpdkvhostuser
此命令创建位于/usr/local/var/run/openvswitch/vhost-user-1
的套接口, 在虚拟机的QEMU命令行需要提供此套接口地址.
注意:
如果你希望vhost-user的套接口创建在/usr/local/var/run/openvswitch
的子目录下,需要在ovsdb中执行此目录:
$ ovs-vsctl --no-wait \
set Open_vSwitch . other_config:vhost-sock-dir=subdir
一旦在交换机中添加了vhost-user端口, 必须添加到客户机中。由两种方式可实现此操作:直接使用QEMU,或者使用libvirt.
注意:
IOMMU 和 Post-copy Live Migration 不支持vhost-user端口.
添加vhost-user端口到客户机 (QEMU)
首先,你必须将vhost-user设备套接字连接到客户机。要实现此操作,你必须将以下参数传递给QEMU:
-chardev socket,id=char1,path=/usr/local/var/run/openvswitch/vhost-user-1
-netdev type=vhost-user,id=mynet1,chardev=char1,vhostforce
-device virtio-net-pci,mac=00:00:00:00:00:01,netdev=mynet1
其中vhost-user-1
是添加到交换机中的vhost-user端口的名称.
对多个设备重复上述参数,更改chardev路径
以及id
值。注意,需要为每个vhost-user设备指定一个单独并且不同的chardev路径
。例如,你的第二个vhost-user端口名为vhost-user-2
,额外增加QEMU命令行参数如下:
-chardev socket,id=char2,path=/usr/local/var/run/openvswitch/vhost-user-2
-netdev type=vhost-user,id=mynet2,chardev=char2,vhostforce
-device virtio-net-pci,mac=00:00:00:00:00:02,netdev=mynet2
此外,QEMU必须在hugetlbfs上分配VM的内存。vhost-user端口访问virtio-net设备的虚拟环和数据包缓冲区,其为在Hugetlbfs上映射的虚拟机的物理内存。开启vhost-user端口以映射虚拟机的内存到进程地址空间中,需将以下参数传递给qemu:
-object memory-backend-file,id=mem,size=4096M,mem-path=/dev/hugepages,share=on
-numa node,memdev=mem -mem-prealloc
最后,您可能希望启用多队列支持。这是可选的,但是,如果要启用它,请运行:
-chardev socket,id=char2,path=/usr/local/var/run/openvswitch/vhost-user-2
-netdev type=vhost-user,id=mynet2,chardev=char2,vhostforce,queues=$q
-device virtio-net-pci,mac=00:00:00:00:00:02,netdev=mynet2,mq=on,vectors=$v
where:
$q
队列数量
$v
向量数量, 其值等于$q
* 2 + 2
vhost-user端口在virtio设备连接之后,将根据需要自动重新配置Rx和Tx队列数。不支持手动配置n_rxq
,因为OVS只能在n_rxq
与QEMU中配置的队列数量匹配时正常工作。
如果目的地为配置了多队列设备的虚拟机的流量,由物理DPDK端口进入到了虚拟交换机中,则该物理DPDK端口的RX队列的数量也应设置为两个以上。此举可增加以下的可能性,即一个不同的PMD程序处理到客户机的多队列传输,其使用一个不同的vhost队列。
如果用户希望在客户机中使用多队列的接口,则客户机操作系统中的驱动程序也必须执行此配置。建议配置的队列数等于$q
。
例如,对于Linux内核的virtio-net驱动程序,使用以下命令实现:
$ ethtool -L <DEV> combined <$q>
where:
-L
更改指定网络设备的通道数
combined
更改多用途通道的数量.
Adding vhost-user ports to the guest (libvirt)
首先,必须更改运行QEMU的用户和组,然后重新启动libvirtd.
-
在文件
/etc/libvirt/qemu.conf
中增加/编辑如下行:user = "root" group = "root"
-
最后,重启libvirtd进程, 例如,在Fedora系统上:
$ systemctl restart libvirtd.service
完成之后,示例化VM虚拟机. 此文件末尾提供了一个示例XML配置文件demovm. 保存此文件,然后,使用此文件创建虚拟机:
$ virsh create demovm.xml
创建完成后,你可连接到客户机的console控制台:
$ virsh console demovm
demovm
XML文件的配置意在虚拟机中实现超越其自身的性能。这些增强功能包括:
-
使用
vcpupin
工具将vcpus固定在CPU Socket 0的核心上. -
配置NUMA单元,并使用
memAccess='shared'
配置共享内存。 -
禁用
mrg_rxbuf='off'
更多信息,请参见 libvirt documentation
.
vhost-user-client
重要:
使用vhost-user-client端口要求 QEMU >= 2.7
要使用vhost-user-client端口,必须首先将所述端口添加到交换机。类似与DPDK vhost-user端口,DPDK vhost-user-client端口名称可以任意命名。但是,为端口指定的名称并不决定相应套接口设备的名称。相反,用户必须通过vhost-server-path
选项配置套接口名称。对于vhost-user-client端口,端口类型为dpdkvhostuserclient
:
$ VHOST_USER_SOCKET_PATH=/path/to/socket
$ ovs-vsctl add-port br0 vhost-client-1 \
-- set Interface vhost-client-1 type=dpdkvhostuserclient \
options:vhost-server-path=$VHOST_USER_SOCKET_PATH
将vhost-user-client端口添加到交换机后,它们必须添加到客户机。类似vhost-user端口,有两种方法可以做到这一点:直接使用QEMU,或使用libvirt。这里只讨论QEMU的情况。
Adding vhost-user-client ports to the guest (QEMU)
将vhost-user设备套接口连接到客户机。要做到这一点,你必须给QEMU传递以下的参数:
-chardev socket,id=char1,path=$VHOST_USER_SOCKET_PATH,server
-netdev type=vhost-user,id=mynet1,chardev=char1,vhostforce
-device virtio-net-pci,mac=00:00:00:00:00:01,netdev=mynet1
其中 vhost-user-1
是添加到交换机中的vhost-user端口的名称.
如果相应的dpdkvhostuserclient
端口还没有在OVS中配置参数vhost-server-path=/path/to/socket
, QEMU 将打印类似于如下的日志信息:
QEMU waiting for connection on: disconnected:unix:/path/to/socket,server
QEMU将一直等待,直到OVS中的端口成功地创建出来,才开始启动VM。使用此模式的一个好处是vhost端口能够在交换机发生crash或被关闭后进行重新连接。一旦交换机重新启动,vHost端口将自动重新连接,并恢复正常服务。
vhost-user-client IOMMU Support
vhost IOMMU是限制virtio设备可访问的vhost内存的功能,因此在注重安全的部署环境中有益处。
可以通过全局配置值启用IOMMU支持:vhost-iommu-support
。将此设置为true将为所有可用的vhost端口启用vhost IOMMU支持:
$ ovs-vsctl set Open_vSwitch . other_config:vhost-iommu-support=true
默认值为false.
重要:
修改此值需要重新启动daemon.
重要:
启用IOMMU功能将同时启用vhost user reply-ack协议;已知在QEMU 2.10.0版本上正常工作,但在旧版本上有错误(2.7.0-2.9.0,含2.7.0-2.9.0)。因此,IOMMU功能默认被禁用(如果使用上述版本的QEMU,应保存禁用)。从QEMU v2.9.1开始,vhost-iommu-support支持可以安全地启用,即使没有IOMMU设备,也没有性能损失。
vhost-user-client Post-copy Live Migration Support (experimental)
Post-copy
迁移是在所有内存迁移之前,目标CPU已经启动的一种迁移模式。主要优势是可预测的迁移时间。多用做通常的pre-copy
迁移之后的第二阶段,以防总得时间过长。
更多信息参见QEMU文档migration.
可以通过全局配置值vhost-postcopy-support
启用Post-copy
的支持。将其设置为true
将为所有vhost-user-client端口启用Post-copy
支持:
$ ovs-vsctl set Open_vSwitch . other_config:vhost-postcopy-support=true
默认值为false
.
重要:
修改此值需要重新启动daemon.
重要:
DPDK Post-copy迁移模式使用userfaultfd 系统调用与内核交互缺页处理,以及使用基于巨页的共享内存。所以目标主机的Linux内核应该支持共享hugetlbfs之上的userfaultfd系统调用。此功能仅在内核上游版本4.11中引入。
DPDK自18.11.0版本以后,QEMU自2.12.0版本以后,开始支持Post-copy功能。但建议使用QEMU>=3.0.1,因为在3.0中修复了post-copy的迁移恢复,并且在3.0.1发布版中几乎没有其他额外修复。
DPDK Post-copy功能要求避免填充客户机内存(应用程序不能调用 mlock*类系统调用)。所以启用mlockall和dequeue zero-copy功能与post-copy功能不兼容。
请注意,在迁移vhost-user设备期间,PMD线程挂起从源主机下载出错页的一段时间。在10Gbps的链路上传输1GB Hugepage,速度可能非常慢。推荐使用2M大小的hugepage。
DPDK in the Guest
DPDKtestpmd
应用程序可以在客户机VMs中运行,用于高速数据包在vhostuser端口之间转发。DPDK和testpmd应用程序必须在客户机虚拟机上编译。下面是在虚拟机中启动testpmd的步骤。
注意:
客户机中的DPDK支持要求 QEMU >= 2.2
首先,按照dpdk-vhost-user
或dpdk vhost user client
的说明实例化一个客户机。启动后,连接到虚拟机,下载DPDK源码到VM并编译DPDK:
$ cd /root/dpdk/
$ wget http://fast.dpdk.org/rel/dpdk-18.11.1.tar.xz
$ tar xf dpdk-18.11.1.tar.xz
$ export DPDK_DIR=/root/dpdk/dpdk-stable-18.11.1
$ export DPDK_TARGET=x86_64-native-linuxapp-gcc
$ export DPDK_BUILD=$DPDK_DIR/$DPDK_TARGET
$ cd $DPDK_DIR
$ make install T=$DPDK_TARGET DESTDIR=install
编译 test-pmd 应用程序:
$ cd app/test-pmd
$ export RTE_SDK=$DPDK_DIR
$ export RTE_TARGET=$DPDK_TARGET
$ make
设置 huge pages 及 DPDK 设备绑定 UIO驱动:
$ sysctl vm.nr_hugepages=1024
$ mkdir -p /dev/hugepages
$ mount -t hugetlbfs hugetlbfs /dev/hugepages # only if not already mounted
$ modprobe uio
$ insmod $DPDK_BUILD/kmod/igb_uio.ko
$ $DPDK_DIR/usertools/dpdk-devbind.py --status
$ $DPDK_DIR/usertools/dpdk-devbind.py -b igb_uio 00:03.0 00:04.0
注意:
vhost ports pci ids 可使用如下命令获取:
lspci | grep Ethernet
最后,启动testpmd应用。
Sample XML
<domain type='kvm'>
<name>demovm</name>
<uuid>4a9b3f53-fa2a-47f3-a757-dd87720d9d1d</uuid>
<memory unit='KiB'>4194304</memory>
<currentMemory unit='KiB'>4194304</currentMemory>
<memoryBacking>
<hugepages>
<page size='2' unit='M' nodeset='0'/>
</hugepages>
</memoryBacking>
<vcpu placement='static'>2</vcpu>
<cputune>
<shares>4096</shares>
<vcpupin vcpu='0' cpuset='4'/>
<vcpupin vcpu='1' cpuset='5'/>
<emulatorpin cpuset='4,5'/>
</cputune>
<os>
<type arch='x86_64' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
</features>
<cpu mode='host-model'>
<model fallback='allow'/>
<topology sockets='2' cores='1' threads='1'/>
<numa>
<cell id='0' cpus='0-1' memory='4194304' unit='KiB' memAccess='shared'/>
</numa>
</cpu>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='none'/>
<source file='/root/CentOS7_x86_64.qcow2'/>
<target dev='vda' bus='virtio'/>
</disk>
<interface type='vhostuser'>
<mac address='00:00:00:00:00:01'/>
<source type='unix' path='/usr/local/var/run/openvswitch/dpdkvhostuser0' mode='client'/>
<model type='virtio'/>
<driver queues='2'>
<host mrg_rxbuf='on'/>
</driver>
</interface>
<interface type='vhostuser'>
<mac address='00:00:00:00:00:02'/>
<source type='unix' path='/usr/local/var/run/openvswitch/dpdkvhostuser1' mode='client'/>
<model type='virtio'/>
<driver queues='2'>
<host mrg_rxbuf='on'/>
</driver>
</interface>
<serial type='pty'>
<target port='0'/>
</serial>
<console type='pty'>
<target type='serial' port='0'/>
</console>
</devices>
</domain>
Jumbo Frames
DPDK vHost User端口可以配置为使用巨型帧。更多信息,请参阅:jumbo frames。
vhost-user Dequeue Zero Copy (experimental)
通常,当从vHost User设备中出列(dequeue)一个数据包时,必须使用memcpy操作用于将该数据包从客户机地址空间复制到主机地址空间。通过启用Dequeue zero-copy功能,可以省去memcpy操作,如下所示:
$ ovs-vsctl add-port br0 dpdkvhostuserclient0 -- set Interface \
dpdkvhostuserclient0 type=dpdkvhostuserclient \
options:vhost-server-path=/tmp/dpdkvhostclient0 \
options:dq-zero-copy=true
启用此功能后,会将指向数据包的引用(指针)传递给主机,而不是数据包的拷贝副本。移除此memcpy可以为某些用例带来性能改进,例如在不同的虚拟机之间交换大数据包。但是,可能会观察到额外的数据包丢失。
请注意,该功能在默认情况下是禁用的,必须显式启用。当指定host-server-path
选项时通过将dq-zero-copy
选项设置为true
开启此功能。如果你想分为多个命令执行,确保在设置vhost-server-path
之前设置dq-zero-copy
:
$ ovs-vsctl set Interface dpdkvhostuserclient0 options:dq-zero-copy=true
$ ovs-vsctl set Interface dpdkvhostuserclient0 \
options:vhost-server-path=/tmp/dpdkvhostclient0
此功能仅对dpdkvhostuserclient
类型端口可用.
存在这样一个限制,即如果来自设置了dq-zero-copy=true
的vHost端口的数据包,目的地是dpdk
类型端口,此端口的发送描述符数量(n_txq_desc
)必须减少到一个较小的值,128为推荐值。这可以通过执行以下命令来实现:
$ ovs-vsctl set Interface dpdkport options:n_txq_desc=128
注意:VM将发送报文到的所有dpdk
端口的TX描述符之和不应超过128。例如,如果绑定了两个物理端口,工作在balance-tcp模式的聚合接口,必须将128除以聚合中的链接数。
参考dpdk-queues-sizes
获取更多信息.
这种限制的原因是由zero-copy功能的实现造成的。vHost设备的tx used vring
,是用于跟踪使用的发送描述符的virtio结构,其仅在NIC释放相应的mbuf时更新。如果我们释放mbuf的频度不是足够快,VRing将处于饥饿状态,数据包将得不到处理。一种确保我们不会遇到这种情况方法,即将n_txq_desc
配置为足够小的数字,以便更频繁的达到NIC的mbuf free threshold
阈值,因此能更频繁地释放mbuf。建议值为128,但是值64和256也已经过测试和验证能够工作,但是具有不同的性能表现。如果客户机中的virtio队列大小增加到1024(可在QEMU 2.10及更高版本中配置),也可以使用512。此值的设置方式如下:
$ qemu-system-x86_64 ... -chardev socket,id=char1,path=<sockpath>,server
-netdev type=vhost-user,id=mynet1,chardev=char1,vhostforce
-device virtio-net-pci,mac=00:00:00:00:00:01,netdev=mynet1,
tx_queue_size=1024
由于此限制, 此功能被认为是实验性质的
.
注意:
Post-copy Live Migration 与 Dequeue zero-copy 不兼容.
进阶信息可参考文档DPDK documentation