我在Ubuntu主机上运行了3个QEMU-KVM VM。每个VM都有一个virt-io nic,并通过主机操作系统中的br0桥连接。每个NIC的MTU配置为1500.该平台运行基于消息队列的应用程序:一个VM作为生产者,一个VM作为消息队列服务器,最后一个VM作为消费者。
我的问题是:当来宾VM变忙时,消息队列服务器VM可能会偶尔发送大小为2k,4k或5k的数据包。它超过了NIC的MTU值,1500 !!!据我所知,Linux IP堆栈应该在发送之前切断小于MTU大小的IP帧。为什么这个VM在忙时发送大数据包?
以下是平台的架构:
[w2: celery caller (message queue producer) ]
| (messages in TCP)
V
[w3: rabbitmq server]
| (messages in TCP)
V
[w4: celeryd (message queue consumer)]
下面是在w3捕获的屏幕,MTU是1500并且发送大小为>的数据包。 2000
下面是在w4捕获的屏幕,MTU是1500并且接收尺寸大于>的数据包。 2000
答案 0 :(得分:3)
谢谢大家,我现在找到了答案。
来宾操作系统中的virtio-NIC支持TCP分段卸载(TSO),默认情况下已启用。 NIC的TSO功能是TCP层不进行帧分割,而分割是 通过NIC驱动程序或硬件执行脱机。 TSO用于在发送大数据包和卸载TCP发送程序的工作时提高性能, NIC驱动程序将在此模式下接收大数据包并将其分段为较小的有效负载,IP头和 TCP标头。这种卸载处理的好处是驱动程序可以很好地使用硬件或重用头部skb 分段期间缓冲。
以下是支持TSO功能的驱动程序代码,
在其发送功能上,它调用atl1c_tso_csum()来检查发送缓冲区的标志& SKB_GSO_TCPV4。 如果缓冲区包含SKB_GSO_TCPV4标志,则对其进行分段,添加ip标头并添加tcp标头。
然而,virtio NIC支持TSO功能,因为virtio NIC数据包正在发送到主机操作系统。它的驱动程序的tx函数只是发送出去 整个数据包,实现更高的网络带宽。
注意:在关闭来宾VM中的TSO标志后,tcpdump上没有看到大数据包。这是命令:
$ethtool -k eth0
Offload parameters for eth0:
rx-checksumming: on
tx-checksumming: on
scatter-gather: on
tcp-segmentation-offload: off
udp-fragmentation-offload: on
generic-segmentation-offload: on
generic-receive-offload: on
large-receive-offload: off
rx-vlan-offload: off
tx-vlan-offload: off
ntuple-filters: off
receive-hashing: off
$ethtool -K eth0 tso off
$