问题更新:除了下面的问题,似乎我们使用 Linux PLPMTUD 机制的客户端/服务器应用程序获得了太大的路径 MTU。有没有人看到这一点,即实际路径 MTU 为 1500,但getsockopt()
返回TCP_MAXSEG
端点的 MTU:s,在我们的例子中为 3000?我曾尝试使用 ethtool 切换 GRO、GSO 和 TSO,但错误仍然存在。正常 ping 只能设法通过 1472 字节或更小的数据包。另外值得一提的是 PLPMTUD 非常适合较小的 MTU:s。例如,w 个端点为 1500 MTU,中间路由器的一个接口设置为例如 1200 MTU,内核 TCP 探测并报告正确TCP_MAXSEG
(1200 - 标头)。
我在应用程序中使用符合 Linux RFC4821 的分组层路径 MTU 发现。基本上,客户端在 TCP 套接字上执行 setsockopt:
setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &sopt, sizeof(sopt));
选项值设置为IP_PMTUDISC_PROBE
. setsockopt()
不返回错误。
客户端将大的 tcp 数据包发送到丢弃服务器,并且路径 MTU 由 Linux 内核校准 - tcpdump 显示正在发送设置了 DF 位的 tcp 数据包,数据包大小会变化,直到内核知道路径 MTU。但是,要让它在另一个方向上工作(监听服务器接受:来自客户端的连接,发送数据并在从服务器到客户端的方向校准 PMTU)我必须为 tcp 路径 mtu 发现设置全局选项,/proc/sys/net/ipv4/tcp_mtu_probing
. 如果我不这样做,服务器将愚蠢地继续发送太大的数据包,这些数据包会被中间路由器丢弃而没有返回 ICMP。两个端点都将 MTU 设置为 3000,而中间跃点的 MTU 设置为 1500。
我希望有人知道出了什么问题。如果需要更多信息,请告诉我,我会编辑问题。Linux 内核 4.2.0 和 3.19.0 都存在问题,它们都是库存的 Kubuntu LTS 内核。(x86/x86-64)
在反向发送数据之前,我确实在所有接受:ed 套接字上设置了相同的套接字选项服务器端。