6. 特定协议方法的规范
DPLPMTUD 要求为每一个使用它的 PL 规定其特定于协议的细节.
第一个子节提供了如何在使用 UDP 或 UDP-Lite 的应用中实现 DPLPMTUD 方法的指导. 这一指导同样适用于其他不包含特定传输协议的数据报服务(例如隧道封装). 后续的几个子节描述了如何把 DPLPMTUD 作为传输服务的一部分加以实现, 使得使用该服务的应用无需自行实现这一方法, 就能在使用 SCTP 和 QUIC 时从 PLPMTU 的发现中获益.
6.1. 基于 UDP 或 UDP-Lite 的 DPLPMTUD 应用支持
UDP [RFC0768] 与 UDP-Lite [RFC3828] 目前的规范中, RFC 系列并未定义支持 PLPMTUD 的方法. 特别是, UDP 传输并不提供实现数据报 PLPMTUD 所需的传输层功能.
DPLPMTUD 方法可以作为直接或间接构建于 UDP 或 UDP-Lite 之上的应用的一部分来实现, 但它依赖于较高层协议的功能来完成这一方法 [BCP145].
DPLPMTUD 所使用的某些原语可能无法通过数据报 API 获得(例如, 访问 IP 层缓存中 PLPMTU 的能力, 或者解读收到的 PTB 消息的能力).
此外, 推荐不由多个协议层同时执行 PMTU 发现. 当底层传输系统已经提供这一功能时, 应用应当避免使用 DPLPMTUD. 拥有一个管理 PLPMTU 的通用方法是有好处的, 这既体现在进程之间共享状态上, 也体现在为不同的 PL 实例协调探测上.
6.1.1. 应用请求
应用需要一种应用层协议机制(例如消息确认方法)来向目的端点请求响应. 该方法应当允许发送方检查响应中返回的值, 以提供针对路径外数据注入的额外保护 [BCP145]. 合适的方法包括仅由两个端点知道的参数, 例如会话 ID 或一个已初始化的序列号.
6.1.2. 应用响应
应用需要一种应用层协议机制来传递来自目的端点的响应. 该响应可以表明一个探测包已成功穿越路径, 但也可以表明部分(或全部)包未能到达目的地.
6.1.3. 发送应用探测包
探测包可以携带应用数据块, 但当数据被用于探测时, 这些数据能否成功传输就存在风险. 一些应用可能更愿意使用不携带应用数据块的探测包, 以避免对数据传输造成干扰.
6.1.4. 初始连通性
没有其他较高层信息可确认与远端对等体的连通性的应用, 应当实现一种使用带确认的探测包进行连接的机制, 然后再进入 BASE 状态.
6.1.5. 验证路径
没有其他较高层信息可确认数据报被正确交付的应用, 应当实现 CONFIRMATION_TIMER, 在处于 SEARCH_COMPLETE 状态时周期性地发送探测包.
6.1.6. PTB 消息的处理
能够并且希望接收 PTB 消息的应用必须执行 [BCP145] 第 5.2 节中规定的 ICMP 验证. 这要求应用检查每一条收到的 PTB 消息, 验证它是对已发送流量作出的响应, 并且所报告的 PL_PTB_SIZE 小于当前正在探测的大小(见第 4.6.2 节). 经过验证的 PTB 消息可以被用作 DPLPMTUD 算法的一个输入, 但禁止被直接用来设置 PLPMTU.
6.2. SCTP 的 DPLPMTUD
[RFC4821] 的第 10.2 节为 SCTP 规定了一种推荐的 PLPMTUD 探测方法, 并且 [RFC4960] 的第 7.3 节建议端点按目的地址逐一应用 RFC 4821 中的技术. DPLPMTUD 规范延续了由 PL 发现 PMTU 的做法, 但更新了 RFC 4960, 以推荐使用本文档规定的方法: 生成探测包的推荐方法是向一个 SCTP 消息添加一个仅由填充构成的 chunk. [RFC4820] 中定义的 PAD chunk 应当被附在一个最小长度的 HEARTBEAT (HB) chunk 上, 以构成一个探测包. 这使得探测独立于用户消息的传输, 也独立于拥塞控制或流量控制. 相比使用 DATA chunk(必要时与其他控制 chunk 捆绑在一起)作为路径探测包, 这一方式更为可取.
[RFC4960] 的第 6.9 节描述了使用 SCTP 时 PL 发送方将用户消息分割为 DATA chunk 的过程. 其中指出, 一旦一个 SCTP 消息被发送, 它就不能被重新分割. [RFC4960] 描述了当 MPS 减小时重传 DATA chunk 的方法, 并且 [RFC4960] 的第 6.9 节描述了在这种情况下使用 IP 分片. 本文档不对此作任何修改.
6.2.1. SCTP/IPv4 与 SCTP/IPv6
6.2.1.1. 初始连通性
基础协议在 [RFC4960] 中规定. 它提供一个得到确认的 PL (Acknowledged PL). 因此, 一旦关联 (association) 得到确认, 发送方就可以进入 BASE 状态.
6.2.1.2. 发送 SCTP 探测包
探测包由一个 SCTP 公共头部、一个 HEARTBEAT chunk 和一个 PAD chunk 组成. PAD chunk 用来控制探测包的长度. HEARTBEAT chunk 用来触发 HEARTBEAT ACK chunk 的发送. 收到 HEARTBEAT ACK chunk 即确认了一个成功探测包的接收. 成功的探测包会更新关联计数器与路径计数器, 而不成功的探测包则被忽略(假定其原因是选择了过大的 PLPMTU).
SCTP 发送方需要能够确定探测包的总大小. HEARTBEAT chunk 可以携带一个 Heartbeat Information 参数, 它除了 [RFC4960] 中建议的信息之外, 还包括探测包的大小, 以帮助实现将 HEARTBEAT ACK 与所发送探测包的大小关联起来. 也可以采用其他方法, 例如发送一个随机数, 并验证返回的信息中同样包含相应的随机数.
PAD chunk 的长度通过从探测包大小中减去 SCTP 公共头部和 HEARTBEAT chunk 的大小来计算得出. PAD chunk 的载荷包含任意数据. 当通过 IP 传输时, PMTU 大小还包括 IPv4 或 IPv6 头部.
探测可以在 PL 握手之后直接开始; 这可以在发送任何数据之前完成. 假定这一行为(即 PMTU 小于或等于接口 MTU), 该过程将需要若干个往返时间周期, 具体取决于所发送 DPLPMTUD 探测包的数量. Heartbeat 计时器可以被用来实现 PROBE_TIMER.
6.2.1.3. 使用 SCTP 验证路径
由于 SCTP 提供的是一个得到确认的 PL, 发送方在处于 SEARCH_COMPLETE 状态时禁止实现 CONFIRMATION_TIMER.
6.2.1.4. SCTP 对 PTB 消息的处理
必须按照 [RFC4960] 附录 C 的规定执行正常的 ICMP 验证. 这要求在 PTB 消息的载荷中引用 SCTP 公共头部的前 8 个字节, 对 ICMPv4 来说情况可能是这样, 对 ICMPv6 来说通常是这样.
当一条 PTB 消息通过验证后, 由 PTB 消息中报告的 PTB_SIZE 计算出的 PL_PTB_SIZE 应当与 DPLPMTUD 算法配合使用, 前提是所报告的 PL_PTB_SIZE 小于当前探测包的大小(见第 4.6 节).
6.2.2. SCTP/UDP 的 DPLPMTUD
SCTP 的 UDP 封装在 [RFC6951] 中规定.
本规范将 RFC 6951 第 5.6 节中对 RFC 4821 的引用更新为指向本文档(RFC 8899). 通过在 RFC 6951 第 5.6 节的末尾添加如下句子来更新 RFC 6951:
确定 PMTU 的推荐方法在 RFC 8899 中规定.
6.2.2.1. 初始连通性
一旦 SCTP 关联得到确认, 发送方就可以进入 BASE 状态.
6.2.2.2. 发送 SCTP/UDP 探测包
数据报探测可以按照第 6.2.1.2 节的规定执行. 探测包的大小包括 8 字节的 UDP 头部. 在使用 PAD chunk 对探测包进行填充时, 必须将这一点考虑在内.
6.2.2.3. 使用 SCTP/UDP 验证路径
SCTP 提供的是一个得到确认的 PL; 因此, 发送方在处于 SEARCH_COMPLETE 状态时不实现 CONFIRMATION_TIMER.
6.2.2.4. SCTP/UDP 对 PTB 消息的处理
必须按照 [RFC4960] 附录 C 的规定对 PTB 消息执行 ICMP 验证. 这要求在 PTB 消息中存在 SCTP 公共头部的前 8 个字节, 对 ICMPv4 来说情况可能是这样(但注意 UDP 头部占用了被引用包头的一部分), 对 ICMPv6 来说通常是这样. 当验证完成后, 由 PTB 消息中的 PTB_SIZE 计算出的 PL_PTB_SIZE 应当与 DPLPMTUD 配合使用, 前提是所报告的 PL_PTB_SIZE 小于当前探测包的大小.
6.2.3. SCTP/DTLS 的 DPLPMTUD
SCTP 的 DTLS 封装在 [RFC8261] 中规定. 它被用于 WebRTC 实现中的数据通道 (data channel). 本规范将 RFC 8261 第 5 节中对 RFC 4821 的引用更新为指向本文档(RFC 8899).
6.2.3.1. 初始连通性
一旦 SCTP 关联得到确认, 发送方就可以进入 BASE 状态.
6.2.3.2. 发送 SCTP/DTLS 探测包
数据报探测可以按照第 6.2.1.2 节的规定执行. 最大载荷会减去 DTLS 头部的大小, 在使用 PAD chunk 进行填充时必须将这一点考虑在内. 探测包的大小包括 DTLS PL 头部. 在使用 PAD chunk 对探测包进行填充时, 必须将这一点考虑在内.
6.2.3.3. 使用 SCTP/DTLS 验证路径
由于 SCTP 提供的是一个得到确认的 PL, 发送方在处于 SEARCH_COMPLETE 状态时禁止实现 CONFIRMATION_TIMER.
6.2.3.4. SCTP/DTLS 对 PTB 消息的处理
[RFC4960] 并未规定验证 SCTP/DTLS ICMP 消息载荷的方法, 本文档也没有规定. 这使得 PL 无法处理 PTB 消息.
6.3. QUIC 的 DPLPMTUD
QUIC [QUIC] 是一个基于 UDP 且提供接收反馈的 PL. UDP 载荷包括一个 QUIC 包头部、一个受保护的载荷以及任何认证字段. 它支持填充和包合并 (packet coalescing), 这两者都可以用来构造探测包. 从 DPLPMTUD 的角度来看, QUIC 可以作为一个得到确认的 PL 来运作. [QUIC] 描述了将 DPLPMTUD 与 QUIC 包配合使用的方法.
实现考虑事项
为特定协议实现 DPLPMTUD 时:
- 选择合适的探测方法 - 根据协议特性选择最高效的探测包类型
- 利用现有机制 - 尽可能使用内建的确认和心跳 (heartbeat) 机制
- 考虑封装开销 - 正确计算每一层头部的大小
- 协调状态管理 - 确保 PLPMTU 状态与协议连接状态同步
- 处理协议特定的限制 - 考虑每种协议独有的约束和要求
这些特定于协议的实现指导确保 DPLPMTUD 能够与各种传输协议有效地集成.