赵占旭的博客

ovs-dpdk中的Jumbo Frames

注:本文是参照了一些其他文章,原文地址点击这里

巨帧


巨帧是为了区别标准帧所叫的名字:任意大于标准Ethernet MTU(1500B)的报文都可以成为巨帧。因为一个应用程序发送的数据都会进行转换成报文,然后进行报头的封装和校验的计算,而帧大的话,报文数少了,报头也就少了,这样就少了不少封装的工作和网络路径的调用,所以对于性能提升还是有优势的。

巨帧的用处

在需要大量的网络流量需要传输的环境中,巨帧还是比较有用的。比如SANs(Storage Area Networks),需要提高大文件传输的性能。好多SANs使用FCoE(Fibre Channel over Ethernet)合并他们的存储和网络到一个单独的网络中。FCoE使用最小2112B的帧,所以使用巨帧避免分片是非常必要的。在overlay网路中,巨帧也是有用的,因为overlay需要额外的报文封装,很容易就超过标准MTU,需要分片了。使用巨帧可以减少分片的可能性。

ovs中的巨帧

netdevs(Network devices)一般默认不支持巨帧,但是很容易通过配置来支持这个特性。下图展示了将OVS的网络设备MTU从1500设置为9000的方式。

avatar

从上图我们可以看到使用ifconfig就可以简单的配置MTU,而OVS-DPDK不能利用ifconfig,所以OVS-DPDK自身支持了修改MTU的方式。

OVS-DPDK中的巨帧


本节简单介绍一下DPDK和OVS中帧的区别,和DPDK怎么管理报文内存。然后介绍OVS-DPDK怎么支持巨帧。

在OVS中,帧以dp_packets的形式存在于OVS的datapath(dpif)中,如下图所示。一个dp_packets包含了报文自身、额外的metadata和OVS需要在转发报文时需要记录的一些信息。

avatar

在DPDK中,帧包含了rte_mbuf(message buffer data structure),mbuf包含了DPDK处理报文所用的metadata和一个指向mbuf后面连续存储数据的空间。mbuf的buf_addr指向了message buffer的起始位置,但是帧数据起始位置还要再偏移data_off,当中的这data_off大小的空间存储的是RTE_PKTMBUF_HEADROOM(128B)。

avatar

而在OVS-DPDK当中,帧首先就是dp_packets,只不过里面包含了rte_mbuf,结果如下图所示

avatar

DPDK的目标是优化报文处理,如果在运行的时候再去heap中申请内存存储报文是比较慢的,所以DPDK在初始化的时候就会分配好内存,一开始创建一个或者多个的内存池,保证DPDK能够在后续运行的时候申请mbufs的开销最小。mempools的创建使用函数rte_mempool_create

1
2
3
4
5
struct rte_mempool *rte_mempool_create(const char *name, unsigned n, unsigned elt_size,
unsigned cache_size, unsigned private_data_size,
rte_mempool_ctor_t *mp_init, void *mp_init_arg,
rte_mempool_obj_cb_t *obj_init, void *obj_init_arg,
int socket_id, unsigned flags)

以上函数返回一个mempool,mempool中的所有元素大小都相同,元素的数目和大小由参数cache_size和elt_size决定。在OVS-DPDK中,我们要确定elt_size足够大,能够存储上面图中的报文大小。上面的报文包含了dp_packet(mbuf也包含在内),L2头和CRC,IP pyload,mbuf headroom(tailroom)。默认情况下,elt_size只能支持标准帧大小,如果我们只要巨帧,要允许elt_size足够大。

在OVS中,我们通过ifconfig配置MTU,而在OVS-DPDK中,我们可以使用ovs-vsctl配置MTU,如下命令分别是添加端口并且配置MTU和直接配置MTU的方式

1
2
ovs-vsctl add-port br0 dpdk0 -- set Interface dpdk0 type=dpdk -- set Interface dpdk0 mtu_request=9000
ovs-vsctl -- set Interface dpdk0 mtu_request=9000

注意:mtu_request是指的L3的MTU,涉及到L2还需要18B的L2头和CRC,所以最大的帧大小应该是9018B。

功能测试配置


本节展示了OVS-DPDK的物理端口和虚拟端口的功能测试。第一个测试是验证巨帧支持各种端口,第二种是通过动态修改MTU查看变化情况。在测试过程中,巨帧流量的验证在两个地方:guest的协议栈tcpdump抓包和流量发生器的RX接口抓包。

avatar

测试环境

avatar

流量配置

avatar

测试时,帧大小为9018B,IP报文大小为9000B,数据大小为8960B,这些很重要,如下图所示

avatar

NIC配置

没必要单独配置NIC来支持巨帧,通过mtu_request配置OVS-DPDK就可以了。唯一的限制就是MTU不要超过NIC的硬件限制,具体情况需要查询NIC的datasheet。我手头的Intel® Ethernet Controller XL710 network adapter最大的帧大小支持9728B1,支持最大的mtu_request值为9710。

OVS配置

编译DPDK和OVS,mount hugepages和启动OVS,一定要确认参数dpdk-init,dpdk-lcore-mask,dpdk-socket-mem等都已经设置了。为了支持巨帧,OVS需要多一些的内存,我们这里设置了4G的hugepages。

1
ovs-vsctl –no-wait set Open_vSwitch.other_config:dpdk-socket-mem=4096,0

为OVS创建一个netdev类型的bridge,并且给桥添加两个DPDK物理网口,两个虚拟网口,添加网口的时候,需要指定mtu_request为9000。

1
2
3
4
5
6
ovs-vsctl add-br br0 –- set Bridge br0 datapath_type=netdev
ovs-vsctl –no-wait set Open_vSwitch.other_config:pmd-cpu-mask=6
ovs-vsctl add-port br0 dpdk0 -- set Interface dpdk0 type=dpdk -- set Interface dpdk0 mtu_request=9000
ovs-vsctl add-port br0 dpdk1 -- set Interface dpdk0 type=dpdk -- set Interface dpdk1 mtu_request=9000
ovs-vsctl add-port br0 dpdkvhostuser0 -- set Interface dpdkvhostuser0 type=dpdkvhostuser -- set Interface dpdkvhostuser0 mtu_request=9000
ovs-vsctl add-port br0 dpdkvhostuser1 -- set Interface dpdkvhostuser1 type=dpdkvhostuser -- set Interface dpdkvhostuser1 mtu_request=9000

为了确保所有的端口的MTU都是9000,我们可以列出所有的端口

1
ovs-appctl dpctl/show

avatar

也可以单独的列出端口

1
ovs-vsctl get Interface [dpdk0|dpdk1|dpdkvhostuser0|dpdkvhostuser1] mtu

avatar

启动Guest

1
2
3
4
5
6
7
sudo -E $QEMU_DIR/x86_64-softmmu/qemu-system-x86_64 -name us-vhost-vm1 -cpu host -enable-kvm \
-m $MEM -object memory-backend-file,id=mem,size=$MEM,mem-path=$HUGE_DIR,share=on -numa node,memdev=mem -mem-prealloc -smp 2 -drive file=/$VM1 \
-chardev socket,id=char0,path=$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=on \
-chardev socket,id=char1,path=$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=on \
--nographic -vnc :1 \

Guest配置

巨帧需要端到端的配置。我们也需要将Guest的网络设备MTU设置为9000,这样避免了VM的网路协议栈中出现分片。

1
2
ifconfig eth1 mtu 9000
ifconfig eth2 mtu 9000

配置IP,并且设置为up

1
2
ifconfig eth1 5.5.5.2/24 up
ifconfig eth2 7.7.7.2/24 up

启动IP转发,目的IP为7.7.7.0/24的报文将返回给OVS

1
sysctl net.ipv4.ip_forward=1

随着流量生成器的启动,需要为目的IP设置静态的ARP

1
arp -s 7.7.7.3 00:00:de:ad:be:ef

测试用例1

这个测试只是简单的展示OVS-DPDK中dpdk和dpdkvhostuser两种类型的端口是否支持巨帧。在Guest中打开tcpdump进行抓包,tcpdump输出被限制在20帧,以防止输出太多。

1
2
tcpdump -i eth1 –v –c 20 # view ingress traffic
tcpdump -i eth2 –v –c 20 # view egress traffic

tcpdump的输出如下图所示,IP长度是9000,蓝色圈出来了,tcp的长度是8960,绿色标注。

avatar

下图展示了流量生成器处的抓包,Ethernet帧长度为9018B,橙色标注。IP和数据长度分别是9000和8960,和上面一致,表明报文没有分片,dpdk和vhostuser类型的端口都支持巨帧。

avatar

测试用力2

这个测试是运行时进行MTU的修改,开始时MTU为9000,随后将dpdk类型的物理端口MTU修改为6000。

1
ovs-vsctl set Interface dpdk0 mtu_request=6000

验证dpdk0的MTU设置正确,其余端口的MTU不变,入下图所示:

1
ovs-vsctl dpctl/show

avatar

观察到ovs不再接收流量,查看没有任何流表

1
ovs-appctl dpctl/dump-flows

avatar

在Guest运行tcpdump,确定没有报文到达。

然后减少流量生成器的帧大小为6018。然后观察发送到Guest的帧IP数据大小为6000,TCP大小为5960。

avatar

检查流量生成器的流量,证实收到了6018大小的帧,IP报文的长度也达到预期。

avatar

性能测试配置


本节主要是验证巨帧的性能优势,在该测试中,在同一个主机上启动两个VM,两者进行通信。一个VM运行iperf3 server,另一个运行iperf3 client。测试配置入下图所示:

avatar

测试环境

宿主机的配置和之前功能性验证一致,guest环境的

avatar

OVS配置

启动OVS,确定DPDK相关的配置生效

1
2
3
4
sudo -E $OVS_DIR/utilities/ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-init=true
sudo -E $OVS_DIR/utilities/ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-lcore-mask=0x10
sudo -E $OVS_DIR/utilities/ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-socket-mem=4096,0
sudo -E $OVS_DIR/vswitchd/ovs-vswitchd unix:$DB_SOCK --pidfile --detach --log-file &

为OVS创建bridge,并且添加两个dpdkvhostuser的端口

1
2
3
4
sudo -E $OVS_DIR/utilities/ovs-vsctl --timeout 10 --may-exist add-br br0 -- set Bridge br0 datapath_type=netdev -- br-set-external-id br0 bridge-id br0 -- set bridge br0 fail-mode=standalone
sudo -E $OVS_DIR/utilities/ovs-vsctl --timeout 10 set Open_vSwitch . other_config:pmd-cpu-mask=6
sudo -E $OVS_DIR/utilities/ovs-vsctl --timeout 10 add-port br0 $PORT0_NAME -- set Interface $PORT0_NAME type=dpdkvhostuser
sudo -E $OVS_DIR/utilities/ovs-vsctl --timeout 10 add-port br0 $PORT1_NAME -- set Interface $PORT1_NAME type=dpdkvhostuser

启动guest,确定mergeable buffers已经使能。

VM1

sudo -E taskset 0x60 $QEMU_DIR/x86_64-softmmu/qemu-system-x86_64 -name us-vhost-vm1 -cpu host -enable-kvm -m 4096M -object memory-backend-file,id=mem,size=4096M,mem-path=$HUGE_DIR,share=on -numa node,memdev=mem -mem-prealloc -smp 2 -drive file=$VM1 -chardev socket,id=char0,path=$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=on,csum=off,gso=off,guest_csum=off,guest_tso4=off,guest_tso6=off,guest_ecn=off --nographic -vnc :1

VM2

sudo -E taskset 0x180 $QEMU_DIR/x86_64-softmmu/qemu-system-x86_64 -name us-vhost-vm2 -cpu host -enable-kvm -m 4096M -object memory-backend-file,id=mem,size=4096M,mem-path=$HUGE_DIR,share=on -numa node,memdev=mem -mem-prealloc -smp 2 -drive file=$VM2 -chardev socket,id=char1,path=$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=on,csum=off,gso=off,guest_csum=off,guest_tso4=off,guest_tso6=off,guest_ecn=off --nographic -vnc :2

Guest配置

配置IP并且up。

VM1

1
ifconfig eth1 5.5.5.1/24 up

VM2

1
ifconfig eth2 5.5.5.2/24 up

确认性能基线

VM2启动iperf3 server

1
iperf3 -s

VM1启动iperf3 client并且连接VM2的iperf3 server

1
iperf3 –c 5.5.5.2

观察服务端和客户端的性能,之间数据传输为6.98gbps的平均速率,作为我们的性能基线,如下图所示:

avatar

测试巨帧的性能

此测试可以在之前的测试后完成,没必要重新搭建环境

额外的宿主机配置

为dpdkvhostuser的端口MTU修改为9710

1
2
ovs-vsctl set Interface dpdkvhostuser0 mtu_request=9710
ovs-vsctl set Interface dpdkvhostuser1 mtu_request=9710

确认两个端口的MTU已经设置正确

1
ovs-appctl dpctl/show

avatar

额外的Guest配置

每一个VM的MTU都设置为9710

1
2
ifconfig eth1 mtu 9710
ifconfig eth1 | grep mtu

avatar

1
2
ifconfig eth2 mtu 9710
ifconfig eth2 | grep mtu

avatar

像之前那样运行iperf3进行传输速率的测试,速率大概为7Gbps到15.6Gbps,如下图所示

avatar

注意:所有文章非特别说明皆为原创。为保证信息与源同步,转载时请务必注明文章出处!谢谢合作 :-)

原始链接:http://zhaozhanxu.com/2016/09/26/SDN/OVS/2016-09-26-jumbo-frames/

许可协议: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。