本文档描述Open vSwitch结合DPDK数据路径的使用。
重点:
要使用DPDK数据路径功能需要在OVS编译时开启DPDK支持选项。OVS与DPDK的版本对应关系可能随发布版本不同而变化。版本对应信息可参考OVS文档releases FAQ。编译指令可参考/intro/install/dpdk。
ovs-vsctl工具可用来创建网桥和其它Open vSwitch支持的特性。网桥创建时应指定选项datapath_type=netdev
::
$ ovs-vsctl add-br br0 -- set bridge br0 datapath_type=netdev
ovs-vsctl工具也可用来添加DPDK设备。ovs-vswitchd应在日志文件中打印发现到的DPDK设备数量::
$ ovs-vsctl add-port br0 dpdk-p0 -- set Interface dpdk-p0 type=dpdk \
options:dpdk-devargs=0000:01:00.0
$ ovs-vsctl add-port br0 dpdk-p1 -- set Interface dpdk-p1 type=dpdk \
options:dpdk-devargs=0000:01:00.1
一些网卡(如,Mellanox ConnectX-3)仅有一个PCI地址关联与多个网口。以上的配置方式将无法工作。所以,建议以下的用法::
$ ovs-vsctl add-port br0 dpdk-p0 -- set Interface dpdk-p0 type=dpdk \
options:dpdk-devargs="class=eth,mac=00:11:22:33:44:55"
$ ovs-vsctl add-port br0 dpdk-p1 -- set Interface dpdk-p1 type=dpdk \
options:dpdk-devargs="class=eth,mac=00:11:22:33:44:56"
重点:
以上语法不支持热插拔的物理接口。此缺陷有望在DPDK v18.05的发布版中解决。关于物理口热插拔的信息,应参考port-hotplug。
在DPDK接口添加到网桥之后,轮询线程将不停的检测DPDK设备,消耗处理核心100%的资源,可通过以下的top
和 ps
命令查看::
$ top -H
$ ps -eLo pid,psr,comm | grep pmd
创建DPDK接口的聚合链路与创建系统接口的聚合链路稍有不同。对于DPDK而言,接口类型type和devarfs参数必须明确的指定。如下列::
$ ovs-vsctl add-bond br0 dpdkbond p0 p1 \
-- set Interface p0 type=dpdk options:dpdk-devargs=0000:01:00.0 \
-- set Interface p1 type=dpdk options:dpdk-devargs=0000:01:00.1
要停止ovs-vswitchd服务,删除网桥,执行以下的命令::
$ ovs-appctl -t ovs-vswitchd exit
$ ovs-appctl -t ovsdb-server exit
$ ovs-vsctl del-br br0
如果你打算在QEMU虚拟机内部运行以DPDK作为后端的ovs-vswitchd服务,需要进行额外的配置。ovs-vswitchd服务为每个可用的处理器核心创建单独的DPDK发送队列。但是默认情况下,提供给客户机的VirtIO网卡仅支持单一的发送和接收队列,导致ovs-vswitchd在QEMU虚拟机中操作失败。为改变此行为,你需要为所有QEMU模拟并提供于DPDK使用的virtio-net-pci
驱动网卡开启mq
(多队列)的属性。你可以手动开启(修改QEMU命令行参数)或者,如果使用Libvirt,在所有DPDK使用的网路设备的
部分增加以下的字符串::
where:
N
定义有多少队列可被客户机使用.
此配置需要 QEMU >= 2.2.
添加一个用户空间网桥和两个dpdk
(PHY) 网口::
# 添加用户空间网桥
$ ovs-vsctl add-br br0 -- set bridge br0 datapath_type=netdev
# 添加两个DPDK网口
$ ovs-vsctl add-port br0 phy0 -- set Interface phy0 type=dpdk \
options:dpdk-devargs=0000:01:00.0 ofport_request=1
$ ovs-vsctl add-port br0 phy1 -- set Interface phy1 type=dpdk
options:dpdk-devargs=0000:01:00.1 ofport_request=2
添加测试流以便在DPDK网口0和1之间转发报文::
# 清空当前流
$ ovs-ofctl del-flows br0
# 添加网口 1 (phy0) 与网口2 (phy1)之间流
$ ovs-ofctl add-flow br0 in_port=1,action=output:2
$ ovs-ofctl add-flow br0 in_port=2,action=output:1
在任一网口发送流量,应当由另外一个网口观察到返回的相同流量。
添加用户空间网桥,两个dpdk
(PHY)网口,以及两个dpdkvhostuser
网口::
# 添加用户空间网桥
$ ovs-vsctl add-br br0 -- set bridge br0 datapath_type=netdev
# 添加两个DPDK网口
$ ovs-vsctl add-port br0 phy0 -- set Interface phy0 type=dpdk \
options:dpdk-devargs=0000:01:00.0 ofport_request=1
$ ovs-vsctl add-port br0 phy1 -- set Interface phy1 type=dpdk
options:dpdk-devargs=0000:01:00.1 ofport_request=2
# 添加两个 dpdkvhostuser 网口
$ ovs-vsctl add-port br0 dpdkvhostuser0 \
-- set Interface dpdkvhostuser0 type=dpdkvhostuser ofport_request=3
$ ovs-vsctl add-port br0 dpdkvhostuser1 \
-- set Interface dpdkvhostuser1 type=dpdkvhostuser ofport_request=4
添加测试流以便在DPDK设备与VM网口之间转发报文::
# 清空当前流
$ ovs-ofctl del-flows br0
# 添加流
$ ovs-ofctl add-flow br0 in_port=1,action=output:3
$ ovs-ofctl add-flow br0 in_port=3,action=output:1
$ ovs-ofctl add-flow br0 in_port=4,action=output:2
$ ovs-ofctl add-flow br0 in_port=2,action=output:4
# Dump flows
$ ovs-ofctl dump-flows br0
按照以下配置创建虚拟机:
Configuration | Values | Comments |
---|---|---|
QEMU version | 2.2.0 | n/a |
QEMU thread affinity | core 5 | taskset 0x20 |
Memory | 4GB | n/a |
Cores | 2 | n/a |
Qcow2 image | CentOS7 | n/a |
mrg_rxbuf | off | n/a |
你可通过QEMU的qemu-system-x86_64
应用直接完成以上配置::
$ export VM_NAME=vhost-vm
$ export GUEST_MEM=3072M
$ export QCOW2_IMAGE=/root/CentOS7_x86_64.qcow2
$ export VHOST_SOCK_DIR=/usr/local/var/run/openvswitch
$ taskset 0x20 qemu-system-x86_64 -name $VM_NAME -cpu host -enable-kvm \
-m $GUEST_MEM -drive file=$QCOW2_IMAGE --nographic -snapshot \
-numa node,memdev=mem -mem-prealloc -smp sockets=1,cores=2 \
-object memory-backend-file,id=mem,size=$GUEST_MEM,mem-path=/dev/hugepages,share=on \
-chardev socket,id=char0,path=$VHOST_SOCK_DIR/dpdkvhostuser0 \
-netdev type=vhost-user,id=mynet1,chardev=char0,vhostforce \
-device virtio-net-pci,mac=00:00:00:00:00:01,netdev=mynet1,mrg_rxbuf=off \
-chardev socket,id=char1,path=$VHOST_SOCK_DIR/dpdkvhostuser1 \
-netdev type=vhost-user,id=mynet2,chardev=char1,vhostforce \
-device virtio-net-pci,mac=00:00:00:00:00:02,netdev=mynet2,mrg_rxbuf=off
关于以上命令以及其它可用的配置实现方法,诸如通过libvirt启动虚拟机等的解释,请参考[/topics/dpdk/vhost-user].
一旦客户机配置好并完成启动,配置DPDK报文在客户机中的转发。要完成此配置,按照[dpdk-testpmd]中的描述编译testpmd
。编译完成之后,启动应用::
$ cd $DPDK_DIR/app/test-pmd;
$ ./testpmd -c 0x3 -n 4 --socket-mem 1024 -- \
--burst=64 -i --txqflags=0xf00 --disable-hw-vlan
$ set fwd mac retry
$ start
完成测试之后,将虚拟网卡绑定会内核驱动::
$ $DPDK_DIR/usertools/dpdk-devbind.py --bind=virtio-pci 0000:00:03.0
$ $DPDK_DIR/usertools/dpdk-devbind.py --bind=virtio-pci 0000:00:04.0
注意::
以上示例中必须制定有效的PCI IDs。PCI IDs可使用以下命令获取::
$ $DPDK_DIR/usertools/dpdk-devbind.py --status
更多关于dpdkvhostuser网口的信息可参见[/topics/dpdk/vhost-user].
上节[dpdk-vhost-loopback] 详述了PHY-VM-PHY 回环拓扑的测试用例步骤,其中报文的转发使用客户机中的DPDK testpmd应用完成。对于希望内核协议栈完成报文转发的用户,需要在客户机中执行以下的命令::
$ ip addr add 1.1.1.2/24 dev eth1
$ ip addr add 1.1.2.2/24 dev eth2
$ ip link set eth1 up
$ ip link set eth2 up
$ systemctl stop firewalld.service
$ systemctl stop iptables.service
# 打开IPv4转发功能
$ sysctl -w net.ipv4.ip_forward=1
# 关闭反向路径过滤(Reverse Path Filtering)
$ sysctl -w net.ipv4.conf.all.rp_filter=0
$ sysctl -w net.ipv4.conf.eth1.rp_filter=0
$ sysctl -w net.ipv4.conf.eth2.rp_filter=0
$ route add -net 1.1.2.0/24 eth2
$ route add -net 1.1.1.0/24 eth1
# 添加静态邻居表项
$ arp -s 1.1.2.99 DE:AD:BE:EF:CA:FE
$ arp -s 1.1.1.99 DE:AD:BE:EF:CA:EE
vHost多队列功能也可使用PHY-VM-PHY配置拓扑来验证。首先,遵照[dpdk-phy-phy]一节描述的步骤创建和初始化数据库,启动ovs-vswitchd服务,并且添加dpdk
类型设备到网桥br0
中。完成之后,执行以下的步骤:
配置PMD和RXQs.
例如,DPDK网口的接收队列数量至少设置为2,vHost-user接口的接收队列数量在virtio设备连接之后将被自动配置,不需要手动配置::
$ ovs-vsctl set Open_vSwitch . other_config:pmd-cpu-mask=0xc
$ ovs-vsctl set Interface phy0 options:n_rxq=2
$ ovs-vsctl set Interface phy1 options:n_rxq=2
通过QEMU命令行实例化虚拟机
我们必须使用合适的软件版本以确保此特性是被支持的。
Setting | value |
---|---|
QEMU version | 2.5.0 |
QEMU thread affinity | 2 cores (taskset 0x30) |
Memory | 4 GB |
Cores | 2 |
Distro | Fedora 22 |
Multiqueue | Enabled |
以下命令实例化客户机::
$ export VM_NAME=vhost-vm
$ export GUEST_MEM=4096M
$ export QCOW2_IMAGE=/root/Fedora22_x86_64.qcow2
$ export VHOST_SOCK_DIR=/usr/local/var/run/openvswitch
$ taskset 0x30 qemu-system-x86_64 -cpu host -smp 2,cores=2 -m 4096M \
-drive file=$QCOW2_IMAGE --enable-kvm -name $VM_NAME \
-nographic -numa node,memdev=mem -mem-prealloc \
-object memory-backend-file,id=mem,size=$GUEST_MEM,mem-path=/dev/hugepages,share=on \
-chardev socket,id=char1,path=$VHOST_SOCK_DIR/dpdkvhostuser0 \
-netdev type=vhost-user,id=mynet1,chardev=char1,vhostforce,queues=2 \
-device virtio-net-pci,mac=00:00:00:00:00:01,netdev=mynet1,mq=on,vectors=6 \
-chardev socket,id=char2,path=$VHOST_SOCK_DIR/dpdkvhostuser1 \
-netdev type=vhost-user,id=mynet2,chardev=char2,vhostforce,queues=2 \
-device virtio-net-pci,mac=00:00:00:00:00:02,netdev=mynet2,mq=on,vectors=6
注意::
以上队列数应匹配OVS中配置的队列数目,参数vector的值应当设置为"number of queues x 2 + 2"。
配置客户机接口
假设客户机有两个接口eth0,eth1,以下命令检查接口的channel配置,并且设置virtio设备的combined channel数目为2::
$ ethtool -l eth0
$ ethtool -L eth0 combined 2
$ ethtool -L eth1 combined 2
更多信息可参见vHost walkthrough一节。
配置内核报文转
配置IP地址并使能接口::
$ ip addr add 5.5.5.1/24 dev eth0
$ ip addr add 90.90.90.1/24 dev eth1
$ ip link set eth0 up
$ ip link set eth1 up
配置IP转发,并添加路由条目::
$ sysctl -w net.ipv4.ip_forward=1
$ sysctl -w net.ipv4.conf.all.rp_filter=0
$ sysctl -w net.ipv4.conf.eth0.rp_filter=0
$ sysctl -w net.ipv4.conf.eth1.rp_filter=0
$ ip route add 2.1.1.0/24 dev eth1
$ route add default gw 2.1.1.2 eth1
$ route add default gw 90.90.90.90 eth1
$ arp -s 90.90.90.90 DE:AD:BE:EF:CA:FE
$ arp -s 2.1.1.2 DE:AD:BE:EF:CA:FA
查看多个队列上的流量::
$ cat /proc/interrupts | grep virtio
默认情况下,流的硬件卸载功能是关闭的,可使用如下命令开启::
$ ovs-vsctl set Open_vSwitch . other_config:hw-offload=true
目前为止,仅实现了部分流卸载。而且,仅在PMD驱动的rte_flow动作支持"MARK + RSS"的条件下工作。
验证过的网卡有:
硬件卸载支持的协议有:
更多详细信息可参考DPDK topics section文档。