我正在尝试使用 scp 通过 MTU 为 552 的网关从主机发送文件。我预计连接会中断,因为 ssh 应该发送设置了 DF 位标志的数据包,而当前的 MTU 太小。相反,数据包被分割成碎片,吞吐量只是变慢了。从主机的 tcp 转储中可以看到,DF 标志未设置。
为什么会发生这种情况?我是否遗漏了什么?
如果它有用的话,我正在使用 Debian 20,但是这种行为也会发生在其他发行版中。
答案1
通常,Linux 内核倾向于使用路径 MTU 发现来发现主机的 MTU,因此会在 IPv4 数据包上设置 DF 标志。但是,在您的例子中,MTU 为 552 个八位字节。IPv4 要求“主机必须准备好接受最大 576 个八位字节的数据报(无论它们是完整到达还是分段到达)。”这是因为非常小的数据包效率低下。
因此,几乎每个使用 IPv4 的程序都可以安全地假设,无论实际 MTU 是多少,最多 576 个八位字节(包括标头)的数据包都可以安全地传输和处理。这对于 DNS 等协议至关重要,这些协议希望发送 UDP 数据报,并且不希望它们仅仅因为有人使用了具有微小 MTU 的奇怪硬件而被丢弃。
由于您的 MTU 低于最低阈值,路径 MTU 发现并不总是有效,并且一些数据包最终需要被分段。另一种情况是,这些连接在很多情况下都无法工作,这显然不太理想,并且会让很多人感到恼火,所以这不是实施的行为。
请注意,您的 MTU 也低于 IPv6 的阈值(即 1280),并且此链接对于 IPv6 根本不起作用。
答案2
你正在遇到 路径 MTU 发现 (PMTUD)。
TCP 数据包设置了 DF 标志,如果中间路由器因为数据包太大而不得不丢弃该数据包,则会导致返回“ICMP Fragmentation Needed”数据包。然后,发送方将减少其对连接路径 MTU(最大传输单元)的估计,并以较小的段重新发送。
如果没有设置 DF,发送方就永远不会知道它发送的段太大。
在您设置 DF 的情况下,唯一的效果是发送方会减小其发送的数据包的大小。这不会阻止使用较小 MTU 的传输成功。