5. 数据报包化层 PMTUD (DPLPMTUD)
本节规定数据报包化层 MTU 发现 (Datagram Packetization Layer PMTUD, DPLPMTUD). 该方法可以在 IP 协议栈的多个位置引入, 用于发现 PLPMTU, 从而让应用能够为当前网络路径使用合适的最大包大小 (MPS).
DPLPMTUD 应当只在一对端点之间的一层执行. 因此, 当较低层已启用 DPLPMTUD 时, 上层 PL 或应用应当避免再使用 DPLPMTUD. PL 必须调整 DPLPMTUD 指示的 MPS, 以计入 PL 自身引入的任何额外开销.
DPLPMTUD 实现位置示例
Application Data *
↓
QUIC/RTP * (Can implement DPLPMTUD)
↓
UDP * (Can implement DPLPMTUD)
↓
IP Layer
↓
Network Interface
DPLPMTUD 的核心思想是由发送方进行探测. 发送方通过发送探测包, 找出能够从发送方完整传送到目的端的用户消息的最大尺寸.
以下各节给出实现所需的组件, 概述各个运行阶段, 并规定状态机与搜索算法.
5.1. DPLPMTUD 组件
本节描述 DPLPMTUD 使用的计时器 (Timers), 常量 (Constants) 和变量 (Variables).
5.1.1. 计时器
该方法最多使用三个计时器:
PROBE_TIMER
- 配置: 超时值应大于等待探测包得到确认的最大时长
- 最小值: 禁止小于 1 秒
- 建议值: 应当大于 15 秒
- 参考: UDP 使用指南 [BCP145] 的 3.1.1 节提供了选择计时器取值的指导
PMTU_RAISE_TIMER
- 功能: 发送方继续使用当前 PLPMTU 的时长, 该时长结束后重新进入搜索阶段
- 周期: 600 秒, 即 PLPMTUD [RFC4821] 推荐的值
- 优化: 当自上一个探测包发出后没有应用数据发送时, DPLPMTUD 可以抑制发送探测包. 倾向于在再次发送用户数据时使用最新 PMTU 的 PL, 可以选择对每条路径持续执行 PMTU 发现, 但这会导致发送额外的数据包
CONFIRMATION_TIMER
- 适用性: 使用可确认 (Acknowledged) PL 时禁止使用
- 功能: 对于其他 PL, 配置为 PL 发送方在确认当前 PLPMTU 仍受支持之前等待的周期
- 关系: 小于 PMTU_RAISE_TIMER, 用于降低 PLPMTU (例如在遇到黑洞时)
- 频率: 确认需要足够频繁, 使得在数据流动时发送方 PL 不会让大量流量陷入黑洞
- 参考: UDP 使用指南 [BCP145] 的 3.1.1 节提供了选择计时器取值的指导
- 优化: 当自上一个探测包发出后没有应用数据发送时, DPLPMTUD 可以抑制发送探测包
注意: DPLPMTUD 规定了多个计时器; 但实现可以选择用单一计时器来实现这些计时器功能.
5.1.2. 常量
DPLPMTUD 定义以下常量:
MAX_PROBES
- 定义: PROBE_COUNT 计数器的最大值
- 含义: 表示对任意大小的连续探测尝试次数的限制
- 益处: MAX_PROBES 取大于 1 的值可以为孤立的丢包提供健壮性
- 默认值: 3
MIN_PLPMTU
- 定义: DPLPMTUD 将尝试使用的最小 PLPMTU 尺寸
- 配置: 端点可能需要配置 MIN_PLPMTU, 为 PL 之下各层的扩展头及其他封装预留空间
- 路径相关性: 该值可能与接口和路径相关
- IPv6: 该尺寸大于或等于在 PL 处产生 1280 字节 IPv6 数据包的尺寸, 见 [RFC8200] 的规定
- IPv4: 该尺寸大于或等于在 PL 处产生 68 字节 IPv4 数据包的尺寸
- 注意: IPv4 路由器要求能够转发 68 字节的数据报而无需进一步分片. 这是 IPv4 头与最小分片尺寸 8 字节之和. 此外, 接收方要求能够重组至少 576 字节大小的分片数据报, 见 [RFC1122] 的 3.3.3 节
MAX_PLPMTU
- 定义: 最大的 PLPMTU 尺寸
- 限制: 必须小于或等于可以在出接口上发送的 PL 数据包的最大尺寸 (受本地接口 MTU 约束)
- 考量: 当远端端点的最大可接收尺寸 (受 EMTU_R 约束) 已知时, 还应当小于远端端点能够接收的 PL 数据包的最大尺寸
- 设计限制: 可能受所使用 PL 的设计或配置的限制
- 应用限制: 当不需要发送大于某个特定尺寸的数据包时, 应用或 PL 可以选择一个更小的 MAX_PLPMTU
BASE_PLPMTU
- 定义: 一个配置的尺寸, 预期在大多数路径上都能工作
- 范围: 大于或等于 MIN_PLPMTU, 且小于 MAX_PLPMTU
- 建议值: 对大多数 PL 而言, 合适的 BASE_PLPMTU 应大于 1200 字节
- IPv4: 使用 IPv4 时, 目前没有规定等价尺寸, 建议 (RECOMMENDED) 的默认 BASE_PLPMTU 为 1200 字节
5.1.3. 变量
DPLPMTUD 方法使用以下一组变量:
PROBED_SIZE
- 定义: 由 PL 确定的当前探测包的尺寸
- 性质: 这是 PLPMTU 的一个暂定值, 等待确认
PROBE_COUNT
- 定义: 已连续发送的未成功探测包数量的计数
- 复位: 每当一个探测包得到确认时, 该值被置零
- 注意: 搜索过程中预期会有一定比例的探测包丢失, 因此单个探测包的丢失并不代表存在 PMTU 问题
包大小关系图
MAX_PLPMTU ────────┐
│
↓
PROBED_SIZE ───────┤ (Under Probe)
│
↓
PLPMTU ────────────┤ (Currently Used)
│
↓
BASE_PLPMTU ───────┤ (Baseline)
│
↓
MIN_PLPMTU ────────┘ (Minimum)
上图展示了 DPLPMTUD 算法执行路径探测以增大 PLPMTU 时, 各包大小常量与变量之间的关系. 此时已发出尺寸为 PROBED_SIZE 的探测包. 一旦得到确认, PLPMTU 将提升为 PROBED_SIZE, 使 DPLPMTUD 算法能够进一步增大 PROBED_SIZE, 逐步朝着发送实际 PMTU 尺寸的探测包靠近.
5.1.4. DPLPMTUD 阶段总览
本节通过描述该方法在若干运行阶段之间的迁移, 提供 DPLPMTUD 方法的一个高层次的资料性 (informative) 概览. 更多细节见状态机 (5.2 节).
DPLPMTUD 阶段流程图
Initial → Base Phase → Search Phase → Search Complete Phase
↓ ↑
└──────→ Error Phase ←──────────────┘
基础阶段 (Base Phase)
- 目的: 基础阶段使用尺寸为 BASE_PLPMTU 的数据包来确认与远端对端的连通性
- 连接确认: 对于面向连接的 PL, 连接确认是隐式的 (可以在 PL 连接握手中完成). 无连接的 PL 则发送探测包, 并利用对该探测包的确认来确认远端对端可达
- PLPMTU 确认: 发送方还确认网络路径支持 BASE_PLPMTU. 这可以借助 PL 机制实现 (例如使用大小为 BASE_PLPMTU 的握手包), 也可以通过发送一个 BASE_PLPMTU 尺寸的探测包并确认收到该探测包来实现
- 探测时机: 进入基础阶段后 (完成连接检查后), 可以立即发送一个 BASE_PLPMTU 尺寸的探测包. 不希望支持 PLPMTU 小于 BASE_PLPMTU 的路径的 PL, 可以用 BASE_PLPMTU 尺寸的探测完成连接检查, 从而把该阶段简化为单一步骤
- 成功: 一旦得到确认, DPLPMTUD 进入搜索阶段
- 失败: 如果基础阶段未能确认 BASE_PLPMTU, DPLPMTUD 进入错误阶段
搜索阶段 (Search Phase)
- 目的: 搜索阶段利用搜索算法发送探测包, 力求增大 PLPMTU
- 终止: 当找到合适的 PLPMTU 时, 算法结束并进入搜索完成阶段
- PTB 响应: PL 可以利用 PTB (Packet Too Big) 消息来推进或终止搜索, 见 4.6 节
搜索完成阶段 (Search Complete Phase)
- 状态: 当网络路径支持该 PLPMTU 时进入搜索完成阶段
- 周期性确认: PL 可以利用 CONFIRMATION_TIMER 周期性地重复发送当前 PLPMTU 尺寸的探测包
- 黑洞检测: 如果发送方无法确认可达性 (例如 CONFIRMATION_TIMER 超时), 或 PL 信号指示不可达, 则检测到黑洞, DPLPMTUD 进入基础阶段
- 周期性搜索: PMTU_RAISE_TIMER 用于周期性地恢复搜索阶段, 以发现 PLPMTU 是否能够提升
错误阶段 (Error Phase)
- 触发条件: 当某条路径的 PLPMTU 信息相互冲突或无效时 (例如无法支持 BASE_PLPMTU), 进入错误阶段, 此时 DPLPMTUD 无法继续并降低 PLPMTU
- 缓解措施: 该状态实现了一种缓解状态事件引擎振荡的方法
- 保守取值: 它通过 PL 向更高层信号一个保守的 MPS 值
- 退出: 当探测包不再检测到错误时退出该状态. 随后 PL 发送方进入搜索状态 (SEARCHING)
健壮性: 仅把 PLPMTU 降到合适尺寸的方法就足以保证可靠运行, 但当实际 PMTU 发生变化, 或该方法 (无论出于何种原因) 为 PLPMTU 做出次优选择时, 可能非常低效.
完整实现: DPLPMTUD 的完整实现提供一个算法, 使 DPLPMTUD 发送方能够在路径特征发生变化后增大 PLPMTU, 例如链路被重新配置为更大的 MTU, 或端到端流所经过的链路集合发生变化时 (例如路由或路径故障切换决策之后).
5.2. 状态机
DPLPMTUD 的状态机如下图所示. 如果支持多路径 (multipath) 或多归属 (multihoming), 则每条路径都需要一个状态机.
注意: 为清晰起见, 状态机图并未展示所有可能的状态迁移.
状态机图
[DISABLED]
↓ ↑
Connection Established/Lost
↓ ↑
[BASE] ←──────────────┐
↓ │
Probe Success Black Hole Detection
↓ │
[SEARCHING] ─────────────┤
↓ │
Probe Complete/Fail │
↓ │
[SEARCH_COMPLETE] ──────────┘
↑ ↓
Periodic Raise/Black Hole Detection
[ERROR]
(Error Handling)
状态定义
DISABLED
- 初始状态: 探测开始之前的初始状态
- 进入条件: 当 PL 指示失去连通性时, 从任何其他状态进入该状态
- 退出条件: 一旦 PL 指示与远端 PL 之间存在连通性, 即离开该状态
- 迁移: 迁移到 BASE 状态时, 可以立即发送一个 BASE_PLPMTU 尺寸的探测包
BASE
- 目的: 用于确认网络路径支持 BASE_PLPMTU 尺寸, 目的是让应用在实际 PMTU 暂时降低时仍能继续工作. 它还力求避免使用 DPLPMTUD 的发送方在长时间搜索更大 PLPMTU 期间, 因数据包或 ICMP 黑洞而不知道数据包未被送达
- 进入时: PROBED_SIZE 被设置为 BASE_PLPMTU 尺寸, PROBE_COUNT 被置零
- 探测: 每次发送探测包时都会启动 PROBE_TIMER
- 成功退出: 当探测包得到确认时退出该状态, PL 发送方进入 SEARCHING 状态
- 失败退出: 当 PROBE_COUNT 达到 MAX_PROBES, 或收到一条经过验证的 PTB 消息时, 也会离开该状态. 这使 PL 发送方进入 ERROR 状态
SEARCHING
- 主要状态: 这是主要的探测状态
- 进入条件: 在 BASE_PLPMTU 的探测完成后进入该状态
- 探测成功: 每当一个探测包得到确认, PROBE_COUNT 被置零, PLPMTU 被设置为 PROBED_SIZE, 随后按搜索算法 (5.3 节 所述) 增大 PROBED_SIZE
- 探测失败: 当探测包在 PROBE_TIMER 周期内未得到确认时, PROBE_COUNT 递增, 并发送一个新的探测包
- 退出条件: 当 PROBE_COUNT 达到 MAX_PROBES 时退出该状态并进入 SEARCH_COMPLETE; 或收到一条与最后一次成功探测尺寸相对应的经过验证的 PTB (PL_PTB_SIZE = PLPMTU); 或 MAX_PLPMTU 尺寸的探测包得到确认 (PLPMTU = MAX_PLPMTU)
- 黑洞检测: 在 SEARCHING 状态中检测到黑洞时, PL 发送方进入 BASE 状态
SEARCH_COMPLETE
- 完成标志: 表示搜索已完成. 这是正常的维护状态, PL 不再为更新 PLPMTU 而探测
- 持续时长: DPLPMTUD 保持在该状态, 直到 PMTU_RAISE_TIMER 超时或检测到黑洞
- 不可确认 PL: 当 DPLPMTUD 使用不可确认 (Unacknowledged) PL 且处于 SEARCH_COMPLETE 状态时, CONFIRMATION_TIMER 周期性地将 PROBE_COUNT 置零, 并调度一个尺寸为 PLPMTU 的探测包. 如果连续 MAX_PROBES 个 PLPMTU 尺寸的探测包都未能得到确认, 该方法进入 BASE 状态
- 可确认 PL: 与可确认 PL (例如 SCTP) 一起使用时, DPLPMTUD 不应 (SHOULD NOT) 在该状态下继续生成 PLPMTU 探测
ERROR
- 失败情形: 表示网络路径尚不支持至少 BASE_PLPMTU 尺寸的 PLPMTU, 或存在关于网络路径的矛盾信息, 否则这些信息可能导致向更高层的 MPS 信号过度振荡
- 振荡缓解: 该状态实现了一种缓解状态事件引擎振荡的方法
- 保守取值: 它通过 PL 向更高层信号一个保守的 MPS 值
- 退出: 当探测包不再检测到错误时退出该状态. 随后 PL 发送方进入 SEARCHING 状态
- 端点分片: 如果 DPLPMTUD 在 PROBE_COUNT 次探测内无法验证 MIN_PLPMTU, 实现允许启用端点分片
- 禁用: 如果 DPLPMTUD 无法验证 MIN_PLPMTU, 实现将迁移到 DISABLED 状态
- 注意: MIN_PLPMTU 可以与 BASE_PLPMTU 相同, 从而简化该状态的操作
5.3. 搜索以增大 PLPMTU
本节描述 DPLPMTUD 用于搜索更大 PLPMTU 的算法.
5.3.1. 探测更大的 PLPMTU
实现使用一个搜索算法在整个搜索范围 (search range) 内判定网络路径能否支持更大的 PLPMTU.
该方法先确认最小 PLPMTU 来发现搜索范围, 再通过探测选择一个小于或等于 MAX_PLPMTU 的 PROBED_SIZE. MAX_PLPMTU 是本地 MTU 与 EMTU_R (当从远端端点获知时) 两者中的较小值. 设置了其将发送的数据报尺寸上限的应用可以调低 MAX_PLPMTU.
当发送第一个尺寸大于或等于 PLPMTU 的探测时, PROBE_COUNT 被初始化为零. 每个成功发送到远端对端的探测包都由来自 PL 的确认来证实 (见 4.1 节).
每次向目的端发送探测包时, 都会启动 PROBE_TIMER. 当 PL 收到探测包已成功穿越路径的确认时, 该计时器被取消 (4.1 节). 这证实了 PROBED_SIZE 受到支持, 随后 PROBED_SIZE 的值被赋给 PLPMTU. 搜索算法可以继续发送更大尺寸的后续探测.
如果计时器在探测包得到确认之前超时, 则该探测未能证实 PROBED_SIZE. PROBE_TIMER 每次超时, PROBE_COUNT 都会递增, PROBE_TIMER 被重新初始化, 并且可以发送一个相同尺寸或任意其他尺寸 (由搜索算法决定) 的新探测. 实现会配置一个连续失败探测的最大次数 (MAX_PROBES). 如果 PROBE_COUNT 的值达到 MAX_PROBES, 探测将停止, PL 发送方进入 SEARCH_COMPLETE 状态.
5.3.2. 探测尺寸的选择
搜索算法确定 PLPMTU 的最小有效增量. 让 PL 发送方尝试探测所有尺寸是没有意义的, 这会给路径施加不必要的负载. 实现应当选择一组探测包尺寸, 使每一步搜索获得的 PLPMTU 增益最大化.
实现可以通过从常见 PMTU 尺寸表中选择步长来优化搜索过程. 在选择合适的下一个探测尺寸时, 实现者还应当考虑应用可能希望使用的常见 MPS 尺寸, 以及网络中可能存在的常见 MTU 尺寸.
5.3.3. 对不一致路径信息的韧性
增大 PLPMTU 的决策需要对已获知的网络路径信息出现不一致的可能性保持韧性. 当探测包因与包尺寸无关的原因丢失 (即非尺寸相关的丢包), 或因频繁的路径变化时, 路径可能出现不一致. 频繁的路径变化可能由意外的 "抖动" (jitter) 造成 -- 即来自同一个流的某些数据包沿一条路径传递, 而其他数据包则沿着具有不同特性的另一条路径传递.
PL 发送方能够从一系列得到确认的 PLPMTU 探测或从收到的一系列 PTB 消息中发现不一致. 当检测到不一致的路径信息时, PL 发送方可以使用一种替代的搜索模式, 即在一段时间内将提供的 MPS 限制为一个较小的值. 这可以避免不必要的丢包.
5.4. 对不一致路径的健壮性
有些路径可能无法承载尺寸为 BASE_PLPMTU 的数据包. 可以实现错误 (Error) 状态来为这类路径提供健壮性. 这允许回退到一个小于期望值的 PLPMTU, 而不是遭受连接失败. 这可以利用端点 IP 分片等方法, 使 PL 发送方能够使用小于 BASE_PLPMTU 的数据包进行通信.
算法总结
以下列出 DPLPMTUD 算法的关键要素:
- 保守起步: 从 BASE_PLPMTU 开始
- 渐进探测: 逐步增大探测尺寸
- 确认机制: 验证每个尺寸可用
- 黑洞检测: 快速响应路径问题
- 周期性维护: 保持 PLPMTU 处于最新状态
- 错误恢复: 处理异常情况
这些机制共同确保 DPLPMTUD 能够在各种网络条件下可靠且高效地工作.