跳到主要内容

7. 探测方法

本节描述 MTU 探测方法的细节, 包括如何发送 probe, 以及如何处理搜索 Path MTU 所需的错误指示.

7.1. 分组大小范围

本文使用三个状态变量来描述探测方法:

search_low: 最小有用 probe size 减一. 预期网络能够递送大小为 search_low 的分组.

search_high: 最大有用 probe size. 预期大小为 search_high 的分组过大, 网络无法递送.

eff_pmtu: 该 flow 的有效 PMTU. 这是 PLPMTUD 允许该路径使用的最大非 probe packet.

search_low          eff_pmtu         search_high
| | |
...------------------------>
non-probe size range
<-------------------------------------->
probe size range

传输非 probe 时, Packetization Layer 应该 创建大小小于或等于 eff_pmtu 的分组.

传输 probe 时, Packetization Layer 必须 选择大于 search_low 且小于或等于 search_high 的 probe size.

向上探测时, eff_pmtu 始终等于 search_low. 在其他状态下, 例如初始条件下, 处理 ICMP PTB 消息后, 或者在共享同一路径表示的另一个 flow 上执行 PLPMTUD 之后, eff_pmtu 可能不同于 search_low. 通常, eff_pmtu 将大于或等于 search_low 且小于 search_high. 一般预期 probe size 会大于 eff_pmtu, 但这不是必需条件.

对于没有路径信息的初始条件, eff_pmtu 可以大于 search_low. search_low 的初始值 应该 保守地取低值, 但如果 eff_pmtu 从较高且不那么保守的值开始, 性能可能更好. 见第 7.2 节.

如果 eff_pmtu 大于 search_low, 则明确允许发送大于 search_low 的非 probe packet. 当这样的分组得到确认时, 它实际上是一个 "implicit probe", 并且 search_low 应该 提升到被确认分组的大小. 然而, 如果一个 "implicit probe" 丢失, 则 不得 像真正 probe 那样将其视为 probe failure. 如果 eff_pmtu 过大, 这种情况只能通过 ICMP PTB 消息或 black hole discovery 检测到 (见第 7.7 节).

7.2. 选择初始值

search_high 的初始值 应该 是该 flow 可能支持的最大分组. 这可能受本地接口 MTU 限制, 受显式协议机制限制 (例如 TCP MSS option), 或受协议 length field 大小等内在限制. 此外, search_high 的初始值 可以 受配置选项限制, 以防止探测超过某个最大大小. Search_high 很可能与经典 Path MTU Discovery 算法计算出的初始 Path MTU 相同.

推荐将 search_low 初始设置为一个很可能能在极广泛环境中工作的 MTU 大小. 按当前技术情况, 1024 字节的值可能足够安全. search_low 的初始值应该可配置.

正常工作的 Path MTU Discovery 对 Internet 的健壮高效运行至关重要. 任何重大变更 (如本文所述) 如果导致协议行为出现任何意外变化, 都可能造成很大的破坏性. eff_pmtu 初始值的选择决定了在经典方法足够使用的情况下, PLPMTUD 实现的行为在多大程度上类似经典 PMTUD.

一种保守配置是将 eff_pmtu 设置为 search_high, 并依赖 ICMP PTB 消息按需下调 eff_pmtu. 在这种配置中, 经典 PMTUD 完全可用, PLPMTUD 仅用于通过第 7.7 节所述过程从 ICMP black hole 中恢复.

在某些情况下, 如果已知经典 PMTUD 很可能失败 (例如出于安全原因在管理上禁用了 ICMP PTB 消息), 使用较小的初始 eff_pmtu 将避免 black hole detection 所需的高成本 timeout. 代价是, 使用小于必要值的初始 eff_pmtu 可能导致性能降低.

注意, 初始 eff_pmtu 可以是 search_low 到 search_high 范围内的任意值. 1400 字节的初始 eff_pmtu 可能是一个不错的折中, 因为它对几乎所有常见网络设备上的几乎所有隧道都是安全的, 同时又接近当今 Internet 中大多数路径的最佳 MTU. 还可以使用其他近期 flow 的统计信息改进这一点: 例如, 某个 flow 的初始 eff_pmtu 可以设置为所有近期成功 probe 的 probe size 中位数.

由于 PLPMTUD 的成本主要由生成和处理 probe 的协议特定开销决定, 因此每种协议最好拥有自己的启发式方法来选择初始 eff_pmtu. 对无连接协议以及其他可能无法获得明确 ICMP black hole 指示的协议而言, 使用保守的 (较小的) eff_pmtu 初始值尤其重要, 如第 10.3 节所述.

应该 提供按协议和按路由的配置选项, 用于覆盖 eff_pmtu 以及其他 PLPMTUD 状态变量的初始值.

7.3. 选择 Probe Size

probe 可以采用上述 "probe size range" 内的任意大小. 然而, 许多因素会影响合适大小的选择. 一种简单策略可能是执行二分搜索, 每次 probe 都将 probe size range 减半. 但是, 对某些协议 (例如 TCP) 而言, 失败 probe 比成功 probe 成本更高, 因为失败 probe 中的数据需要重传. 对这类协议, 以较小增量提高 probe size 的策略可能开销更低. 对许多协议而言, 无论是在 Packetization Layer 还是其上层, 增大 MTU 的收益可能遵循阶跃函数, 因而完全不值得在某些区间内探测.

作为一种优化, 在某些常见或预期 MTU 大小处探测可能是合适的, 例如标准 Ethernet 的 1500 字节, 或隧道协议中的 1500 字节减去 header 大小.

某些协议可能使用其他机制来选择 probe size. 例如, 具有某些自然数据块大小的协议可以简单地由若干块组装消息, 直到总大小小于 search_high, 并且如有可能大于 search_low.

每个 Packetization Layer 必须决定探测何时已经收敛, 即 probe size range 已小到继续探测不再值得其成本. 当探测收敛时, 应该设置一个 timer. 当 timer 过期时, search_high 应该重置为其初始值 (如上所述), 以便恢复探测. 因此, 如果路径变化并提高了 Path MTU, 该 flow 最终会利用它. 根据 RFC 1981, 该 timer 的值不得小于 5 分钟, 推荐值为 10 分钟.

7.4. 探测前置条件

发送 probe 之前, flow 必须 至少满足以下条件:

  • 没有未完成的 probe 或丢失.
  • 如果上一次 probe 失败或结论不确定, 则 probe timeout 已过期 (见第 7.6.2 节).
  • 可用窗口大于 probe size.
  • 对使用 in-band data 进行探测的协议, 有足够数据可用于发送 probe.

此外, 大多数协议中的及时丢失检测算法都有一些前置条件, 这些条件 应该 在发送 probe 之前满足. 例如, 除非 probe 后面有足够 segment, TCP Fast Retransmit 并不健壮; 也就是说, 发送方 应该 已排队足够数据并拥有足够接收窗口, 以发送 probe 加上至少 Tcprexmtthresh [RFC2760] 个额外 segment. 这一限制可能会在某些协议状态中抑制探测, 例如过于接近连接结束时, 或窗口过小时.

协议 可以 延迟发送非 probe, 以积累足够数据满足探测前置条件. 延迟发送算法 应该 使用某种自缩放技术, 以适当限制数据被延迟的时间. 例如, 返回的 ACK 可用于防止窗口下降超过 probe 所需的数据量.

7.5. 执行 Probe

一旦选择了适当范围内的 probe size, 并且满足上述前置条件, Packetization Layer 可以 执行 probe. 为此, 它创建一个 probe packet, 使其大小 (包括最外层 IP header) 等于 probe size. 发送 probe 后, 它等待响应, 该响应将产生以下结果之一:

Success: probe 被确认为已由远端主机接收.

Failure: 协议机制指示 probe 已丢失, 但前导窗口或尾随窗口中没有分组丢失.

Timeout failure: 协议机制指示 probe 已丢失, 且前导窗口中没有分组丢失, 但无法确定尾随窗口中是否有分组丢失. 例如, 通过 timeout 检测到丢失, 并使用 go-back-n 重传.

Inconclusive: probe 丢失, 同时前导窗口或尾随窗口中还有其他分组丢失.

7.6. 对 Probe 结果的响应

当 probe 完成时, 应该 根据 probe 的结果类型按如下方式处理结果.

7.6.1. Probe 成功

当 probe 被递送时, 这表明 Path MTU 至少与 probe size 一样大. 将 search_low 设置为 probe size. 如果 probe size 大于 eff_pmtu, 则将 eff_pmtu 提升到 probe size. 如果 flow 尚未使用路径的完整 MTU, 因为它受某些其他限制约束 (例如交互式会话中的可用数据), 则 probe size 可能小于 eff_pmtu.

注意, 如果一个 flow 的分组经由多条路径路由, 或经过具有非确定性 MTU 的路径, 单个 probe packet 的递送并不表示该大小的所有分组都会被递送. 为了在这种情况下保持健壮, Packetization Layer 应该 执行第 7.8 节所述的 MTU verification.

7.6.2. Probe 失败

当只有 probe 丢失时, 这被视为 Path MTU 小于 probe size 的指示. 仅在这种情况下, 该丢失 不应该 被解释为拥塞信号.

在没有其他指示的情况下, 将 search_high 设置为 probe size 减一. 如果 flow 尚未使用路径的完整 MTU, 因为它受某些其他限制约束 (例如交互式会话中的可用数据), 则 eff_pmtu 可能大于 probe size. 如果 eff_pmtu 大于 probe size, eff_pmtu 必须 降低到不大于 search_high, 并且 应该 降低到 search_low, 因为 eff_pmtu 已被确定无效, 类似 full-stop timeout 之后的情况 (见第 7.7 节).

如果收到与 probe packet 匹配的 ICMP PTB 消息, 则 search_high 和 eff_pmtu 可以 根据该消息中指示的 MTU 值设置. 注意, ICMP 消息可能在协议丢失指示之前或之后收到.

probe failure event 是 Packetization Layer 应该 将丢失忽略为拥塞信号的唯一情况. 由于抑制拥塞控制存在小风险, 可能产生意外后果 (即使只是一次孤立丢失), 因此 要求 probe failure event 的发生频率低于标准拥塞控制下的正常丢失周期. 具体而言, 在一次 probe failure event 并抑制拥塞控制之后, PLPMTUD 不得 再次探测, 直到经过一个大于预期拥塞控制事件间隔的时间. 详情见第 4 节. 对下一次拥塞事件间隔最简单的估计, 是与当前以分组数计的 congestion window 相同数量的 round trip.

7.6.3. Probe Timeout Failure

如果丢失通过 timeout 检测到并通过 go-back-n 重传修复, 则需要降低 congestion window. 在这种情况下, 失败 probe 的代价相对较高, 可能值得在下一次 probe 之前使用更长时间间隔. 推荐使用非 timeout failure 情况 (第 7.6.2 节) 五倍的时间间隔.

7.6.4. Probe 结论不确定

probe 丢失附近存在其他丢失可能表示 probe 是因拥塞而非 MTU 限制而丢失. 在这种情况下, 状态变量 eff_pmtu, search_low 和 search_high 不应该 更新, 并且一旦满足探测前置条件 (即 packetization layer 没有未恢复的未完成丢失), 应该 尽快再次尝试相同大小的 probe. 此时重新探测尤其合适, 因为 flow 的 congestion window 将处于最低点, 从而使拥塞性丢失的概率最小.

7.7. Full-Stop Timeout

在所有条件下, full-stop timeout (在其他文档中也称为 "persistent timeout") 应该 被视为网络中某种严重破坏性事件的指示, 例如路由器故障或路由变化到 MTU 更小的路径. 对 TCP 而言, 当 [RFC1122] 描述的 R1 timeout threshold 过期时会发生这种情况.

如果发生 full-stop timeout, 且没有 ICMP 消息指示原因 (PTB, Net unreachable 等, 或 ICMP 消息因某种原因被忽略), 则 推荐 的首个恢复动作是将其视为 [RFC2923] 中定义的已检测到 ICMP black hole.

对检测到的 black hole 的响应取决于 search_low 和 eff_pmtu 的当前值. 如果 eff_pmtu 大于 search_low, 则将 eff_pmtu 设置为 search_low. 否则, 将 eff_pmtu 和 search_low 都设置为 search_low 的初始值. 在额外的连续 timeout 之后, search_low 和 eff_pmtu 应该 减半, 其下限为 IPv4 的 68 字节和 IPv6 的 1280 字节. 为支持在 MTU 小于 IP 规范允许值的链路上进行受限操作, 可以 允许更低的下限.

7.8. MTU 验证

一个 flow 可能同时穿越多条路径, 但实现只能为该 flow 保留一个路径表示. 如果这些路径具有不同 MTU, 在 flow 的路径表示中存储所有路径中的最小 MTU 将产生正确行为. 如果 ICMP PTB 消息能够递送, 则经典 PMTUD 在这种情况下会正确工作.

如果 ICMP 递送失败, 破坏了经典 PMTUD, 连接将仅依赖 PLPMTUD. 在这种情况下, PLPMTUD 也可能失败, 因为它假设一个 flow 穿越具有单一 MTU 的路径. 大小大于最小 Path MTU 但小于最大 Path MTU 的 probe 可能成功. 然而, 一旦提高该 flow 的有效 PMTU, 丢失率将显著上升. 该 flow 仍可能取得进展, 但由此产生的丢失率很可能不可接受. 例如, 使用双向 round-robin striping 时, 50% 的 full-sized packet 将被丢弃.

以这种方式进行 striping 通常也因其他原因在操作上不理想 (例如由于 packet reordering), 并且通常会通过将每个 flow 哈希到一条路径来避免. 然而, 为提高健壮性, 实现 应该 实现某种形式的 MTU verification, 这样如果提高 eff_pmtu 导致丢失率急剧上升, 它就会回退到使用较低 MTU.

推荐策略是在提升 eff_pmtu 之前保存其值. 然后, 如果丢失率在一段时间内升高到某个阈值以上 (例如, 在多个 retransmission timeout (RTO) 间隔内丢失率高于 10%), 则认为新的 MTU 不正确. 应该恢复保存的 eff_pmtu 值, 并以与 probe failure 相同的方式降低 search_high. PLPMTUD 实现应该实现 MTU verification.