来自网关 VM 的神秘“需要分段”拒绝

Kev*_*vin 6 networking gateway linux-networking vmware-esxi

我一直在解决严重的 WAN 速度问题。我修复了它,但为了他人的利益:

通过 WireShark、日志记录和简化配置,我将其范围缩小到一些奇怪的行为,从执行 DNAT 的网关到内部网络上的服务器。网关(一个 CentOS 机器)和服务器都运行在同一个 VMware ESXi 5 主机上(事实证明这很重要)。

这是发生的事件序列 - 非常一致 - 当我尝试从 DNAT 后面的 HTTP 服务器下载文件时,使用直接连接到网关 WAN 端的测试客户端(绕过此处通常使用的实际 Internet 连接) :

  1. 通常的TCP连接建立(SYN、SYN ACK、ACK)正常进行;网关以两种方式正确地重新映射服务器的 IP。

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

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

  4. 服务器通过网关发送第二个 1460 字节 TCP 段,继续该文件。同样,链接有效载荷为 1500 字节。该段也不会跨越网关并且永远不会被考虑在内。

  5. 网关将 ICMP 类型 3 代码 4(目标不可达 - 需要分段)数据包发送回服务器,引用事件 3 中发送的数据包。ICMP 数据包指示下一跳 MTU 为 1500。 这似乎是无意义的,因为网络是 1500 字节干净的,并且 3 和 4 中的链接有效载荷已经在规定的 1500 字节限制内。服务器忽略此响应是可以理解的。(最初,ICMP 已被过度热情的防火墙丢弃,但已修复。)

  6. 经过相当长的延迟(并且在某些配置中,来自服务器的重复 ACK),服务器决定重新发送来自事件 3 的段,这一次是单独的。除了 IP 标识字段和校验和之外,该帧与事件 3 中的帧相同。它们的长度相同,并且新的帧仍然设置了 Don't Fragment 标志。 然而,这一次,网关很高兴地将段传递给客户端 - 一件式地 - 而不是发送 ICMP 拒绝。

  7. 客户端确认这一点,然后传输继续进行,尽管速度非常慢,因为后续段经历了大致相同的被拒绝、超时、重新发送然后通过的模式。

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

根据目标服务器看似无关的细节,这种奇怪的行为会发生不可预测的变化。

例如,在 Server 2003 R2 上,如果启用了 Windows 防火墙(即使它允许 HTTP 和所有 ICMP),7MB 的测试文件将需要 7 小时才能传输,而根本不会出现问题,而且矛盾的是,拒绝永远不会如果 Windows 防火墙被禁用,则首先由网关发送。另一方面,在 Server 2008 R2 上,禁用 Windows 防火墙没有任何影响,但传输虽然仍然受到损害,但比启用防火墙的 Server 2003 R2 快得多。(我认为这是因为 2008 R2 使用了更智能的超时启发式和 TCP 快速重传。)

更奇怪的是,如果目标服务器上安装了WireShark,问题就会消失。因此,为了诊断问题,我必须在单独的 VM 上安装 WireShark 以观察 LAN 端网络流量(无论如何,出于其他原因,这可能是一个更好的主意。)

ESXi 主机版本为 5.0 U2。

Dav*_*rtz 7

您不能丢弃需要 ICMP 分段的消息。它们是 pMTU 发现所必需的,这是 TCP 正常工作所必需的。请LART防火墙管理员。

根据透明规则,充当防火墙的包过滤路由器允许带有不分段 (DF) 位设置的传出 IP 数据包不得阻止传入 ICMP 目标不可达 / 分段需要错误发送以响应出站数据包到达防火墙内的主机,因为这会破坏生成合法流量的主机对路径 MTU 发现的符合标准的使用。-- 防火墙要求 - RFC2979(强调原文)

十多年来,这种配置已被公认为从根本上被破坏。ICMP 不是可选的。

  • 我唯一遗憾的是我只有一票赞成来给出这个答案。我希望我能收回在会议上说服非技术 IT 经理在阅读了一些有关 Ping of Death 攻击的古老社论并阻止整个协议后重新打开 ICMP 的时间。 (2认同)

Kev*_*vin 3

我终于弄清楚了这件事的真相。事实证明,这是 VMware 在目标服务器的虚拟网卡中实现 TCP 分段卸载的问题。

服务器的 TCP/IP 堆栈将向 NIC 发送一个大数据块,并期望 NIC 会将其分解为仅限于链路 MTU 的 TCP 段。然而,VMware 决定将其保留在一个大的细分市场中,直到 - 好吧,我不确定什么时候。

当它到达网关虚拟机的 TCP/IP 堆栈时,它似乎实际上停留了一大段,从而引发了拒绝。

生成的 ICMP 数据包中隐藏着一条重要线索:被拒绝数据包的 IP 标头指示大小为 2960 字节 - 比它似乎要拒绝的实际数据包大得多。如果 TCP 段合并了迄今为止发送的两个段中的数据,那么这也正是 TCP 段在网络上的大小。

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

我认为VMware延迟分段的逻辑是,如果数据要从物理NIC发出,则可以利用NIC的实际硬件卸载。然而,它确实看起来有问题,因为它在发送到另一个虚拟机之前无法进行分段,并且就这一点而言,不一致。我在其他地方看到过这种行为被称为 VMware bug。

解决方案很简单,就是关闭目标服务器中的 TCP 分段卸载。该过程因操作系统而异,但 fwiw:

在 Windows 中,在连接属性的“常规”选项卡或“网络”选项卡上,单击适配器旁边的“配置...”,然后查看“高级”选项卡。对于 Server 2003 R2,它被指定为“IPv4 TCP 分段卸载”。对于 Server 2008 R2,它是“大量发送卸载 (IPv4)”。

这个解决方案有点混乱,可能会影响某些环境中的性能,所以我仍然会接受任何更好的答案。