来自网关虚拟机的神秘“碎片要求”拒绝

我一直在解决一个严重的广域网速度问题。 我固定它,但为了别人的利益:

通过WireShark,日志logging和简化configuration,我把它缩小到了从DNAT到内部networking上的服务器的一个奇怪的行为。 网关(一个CentOS盒)和服务器都运行在同一台VMware ESXi 5主机上(事实certificate这很重要)。

当我试图从DNAT后面的HTTP服务器上下载一个文件时,使用一个直接连接到网关WAN侧的testing客户端(绕过这里通常使用的实际的Internet连接) :

  1. 通常的TCP连接build立(SYN,SYN ACK,ACK)正常进行; 网关正确地重新映射服务器的IP。

  2. 客户端使用HTTP GET发送单个TCP段,并且这也正确地被DNATted到目标服务器。

  3. 服务器通过网关发送一个1460字节的带有200响应和部分文件的TCP段。 线路上的帧的大小是1514字节 – 有效载荷是1500。 这部分应该通过网关,但没有。

  4. 服务器通过网关发送第二个1460字节的TCP段,继续文件。 同样,链路有效载荷是1500字节。 这个细分市场也没有穿过网关,也从来没有考虑过。

  5. 网关向服务器发送一个ICMP Type 3 Code 4(目标不可达 – 分片需要)数据包,引用事件3中发送的数据包.ICMP数据包指示下一个中继站MTU为1500. 这看起来是无意义的 ,因为networking是干净的1500字节,并且3和4中的链路负载已经在规定的1500字节限制内 。 服务器可以理解,忽略了这个回应。 (原来,ICMP被一个过分热心的防火墙所淹没,但是这个问题已经解决了。)

  6. 经过相当长的时间(并且在一些configuration中,来自服务器的重复ACK)之后,服务器决定单独从事件3重新发送段。 除了IP标识字段和校验和之外,帧与事件3中的帧是相同的。它们长度相同 ,新的帧仍然设置了不分片标志。 但是,这一次,网关将网段快速传递给客户端,而不是发送一个ICMP拒绝。

  7. 客户确认这一点,转移仍在继续,虽然慢得令人难以置信 ,因为随后的分段经历了大致相同的被拒绝,超时,重新发送和接通的模式。

如果客户端移动到局域网以便直接访问服务器,则客户端和服务器正常协同工作。

这个奇怪的行为根据目标服务器的看似不相关的细节而不可预知地变化。

例如,在Server 2003 R2上,如果启用Windows防火墙(即使允许HTTP和所有ICMP),7MBtesting文件将花费7小时以上传输,而问题根本不会出现,而矛盾的是拒绝将永远不会如果Windows防火墙被禁用,首先由网关发送 。 另一方面,在Server 2008 R2上,禁用Windows防火墙并没有任何效果,但是在传输过程中仍会受到影响,比启用防火墙的Server 2003 R2快得多。 (我想这是因为2008 R2使用更智能的超时启发式和TCP快速重传。)

更奇怪的是,如果WireShark安装在目标服务器上,问题就会消失。 因此,为了诊断这个问题,我必须在单独的虚拟机上安装WireShark来观察LAN端的networkingstream量(由于其他原因,可能是一个更好的主意)。

ESXi主机是版本5.0 U2。

您不能删除ICMP碎片所需的消息。 它们是pMTU发现所必需的,这是TCP正常工作所必需的。 请LART防火墙pipe理员。

通过透明性规则,一个作为防火墙的包过滤路由器允许带有不分段(DF)位的传出IP数据包不能阻止为响应出站数据包而发送的ICMP目的地不可到达/碎片化需要的错误主机在防火墙内,因为这将打破主机生成合法stream量的pathMTU发现的符合标准的使用。 – 防火墙要求 – RFC2979 (强调原文)

这是一个十多年来被认为已经基本被破坏的configuration。 ICMP不是可选的。

我终于明白了这一点。 事实certificate,VMware在目标服务器的虚拟网卡中实施了TCP分段卸载。

服务器的TCP / IP堆栈会将一个大的块一起发送到NIC,并期望NIC将其分解为限于链路的MTU的TCP段。 但是,VMware决定把这个放在一个很大的领域,直到我不确定什么时候。

当它到达网关虚拟机的TCP / IP协议栈时,似乎实际上停留在一个很大的部分,这引起了拒绝。

一个重要的线索隐藏在ICMP数据包中:拒绝数据包的IP头指示了2960字节的大小 – 比看起来被拒绝的实际数据包大。 如果将TCP数据段中的数据合并到一起,这也是TCP段的大小。

有一件事使得这个问题非常难以诊断,传输的数据实际上被拆分为1500字节的帧,只要WireShark运行在另一个虚拟机(连接到单独的,混杂的端口组上的同一个vSwitch)上就可以看到。 我真的不知道为什么网关虚拟机看到一个数据包,而WireShark虚拟机看到两个。 FWIW,网关没有大的接收卸载启用 – 我可以理解,如果是的话。 WireShark VM正在运行Windows 7。

我认为VMware推迟分割的逻辑是,如果数据要从物理网卡出去,那么可以利用网卡的实际硬件卸载。 但是,它看起来有点儿麻烦,在发送到另一个虚拟机之前将无法分割,并且不一致。 我已经将其他地方提到的这种行为看作是一个VMware的bug。

该解决scheme仅仅是closures目标服务器中的TCP分段卸载。 程序因操作系统而异,但是fww:

在Windows中,在连接的属性,常规选项卡或networking选项卡上,单击适配器旁边的“configuration…”,然后查看“高级”选项卡。 对于Server 2003 R2,它以“IPv4 TCP分段卸载”的forms给出。 对于Server 2008 R2,它是“大量发送卸载(IPv4)”。

这个解决scheme有点混乱,可以想象会在一些环境中影响性能,所以我仍然会接受更好的答案。

我有相同的症状,问题原来是这个内核错误: https : //bugs.debian.org/cgi-bin/bugreport.cgi? bug =754294

我在Linux主机上看到了同样的问题。

解决scheme是closures网关机器networking驱动程序(vmxnet)上的大量接收卸载(LRO)。

引用VMware KB:

LRO将传入的networking数据包重组为更大的缓冲区,并将生成的较大但较less的数据包传输到主机或虚拟机的networking堆栈。 与禁用LRO时相比,CPU必须处理更less的数据包,这会降低networking的使用率。

请参阅http://kb.vmware.com/kb/2055140

因此,在网关机器上到达的数据包被networking驱动器合并并发送到networking堆栈,这使得它们比MTU大。