本文档描述Open vSwitch结合DPDK数据路径的使用。node
重点:
要使用DPDK数据路径功能须要在OVS编译时开启DPDK支持选项。OVS与DPDK的版本对应关系可能随发布版本不一样而变化。版本对应信息可参考OVS文档releases FAQ。编译指令可参考/intro/install/dpdk。web
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地址关联与多个网口。以上的配置方式将没法工做。因此,建议如下的用法::app
$ 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"
重点:socket
以上语法不支持热插拔的物理接口。此缺陷有望在DPDK v18.05的发布版中解决。关于物理口热插拔的信息,应参考port-hotplug。svg
在DPDK接口添加到网桥以后,轮询线程将不停的检测DPDK设备,消耗处理核心100%的资源,可经过如下的top
和 ps
命令查看::工具
$ top -H $ ps -eLo pid,psr,comm | grep pmd
建立DPDK接口的聚合链路与建立系统接口的聚合链路稍有不一样。对于DPDK而言,接口类型type和devarfs参数必须明确的指定。以下列::oop
$ 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使用的网路设备的<interface>
部分增长如下的字符串::
<driver name='vhost' queues='N'/>
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文档。