4. DPLPMTUD 机制
本节列出本规范中所使用的各种协议机制.
4.1. PLPMTUD 探测包
DPLPMTUD 方法依赖于 PL 发送方能够生成具有特定大小的探测包. TCP 能够通过选择一段正在发送的合适数据段来生成这类探测包 [RFC4821]. 与之相对, 一个构造探测包的数据报型 PL 必须要么请求应用发送一个比应用本身所生成的数据块更大的数据块, 要么利用填充功能将数据报扩展到超出应用数据块的大小. 允许交换控制消息(不带应用数据块)的协议可以通过在控制消息后面附加填充数据来生成一个探测包. 一个探测包的总大小包括了为被发送的载荷数据所添加的全部头部和填充(例如, 包括协议选项字段, 诸如 AEAD tag 之类的安全相关字段, 以及 TLS 记录层填充).
REQUIRED: 接收方需要能够区分带内数据块与任何被添加的填充. 这样做是为了确保任何被添加的填充不会被传递给接收方的应用程序.
创建探测包的三种方法
1. 使用填充数据探测
这类探测包只包含控制信息, 以及为把数据报的长度扩展到探测包大小所需要的填充. 由于这类探测包不携带由应用提供的数据块, 它们通常不需要重传, 不过它们仍然会消耗网络容量, 并带来端点上的处理开销.
2. 使用应用数据和填充数据探测
这类探测包包含一个由应用提供的数据块, 该数据块与填充组合在一起, 把数据报的长度扩展到探测包的大小.
3. 使用应用数据探测
这类探测包包含一个由应用提供的数据块, 该数据块的大小与探测包的大小相一致. 这一方法会请求应用发出一个具有期望探测大小的数据块.
探测包保护
对于使用携带应用数据的探测包, 并且需要对探测包的丢失具备韧性的 PL, 可以对该数据块执行传输层的重传/修复(例如, 在检测到丢失发生之后进行重传, 或者在不带填充数据的数据报中复制一份该数据块). 被重传的数据块可能需要使用更小的 PLPMTU 来发送, 这可能会迫使 PL 使用更小的包大小来穿越端到端路径. (这可以利用端点上的网络层分片来实现, 也可以由 PL 将该数据块分割成多个数据报. )
DPLPMTUD 可以选择只使用这些方法中的某一种, 以此来简化其实现.
探测包标识
由 PL 发送的探测消息必须包含足够的信息, 以便能够在最大段生存期(Maximum Segment Lifetime)之内唯一地标识该探测(例如, 包含一个来自 PL 或来自 DPLPMTUD 实现的唯一标识符), 并且对于探测响应和 PTB 消息的重排序与重放要具备健壮性.
4.2. 探测包大小的确认
PL 需要一种方法来确定(即确认)一个探测包何时已经沿着一条网络路径被端到端地成功接收.
传输协议可以包含这样的端到端方法: 它们能够检测并报告自己所发送的特定数据报已经被接收(例如, DCCP, SCTP 和 QUIC 都提供了 keep-alive/heartbeat 功能). 在得到支持的情况下, 这一机制也可以被 DPLPMTUD 用来确认一个探测包的接收.
那些不对数据接收进行确认的 PL(例如 UDP 和 UDP-Lite)自身无法检测到它们所发送的包会因为其大小大于实际 PMTU 而被丢弃. 这类 PL 需要依赖某个应用协议来检测这种丢失的发生.
第 6 节为一系列由 IETF 规定的协议指定了这一功能.
4.3. 黑洞检测与 PLPMTU 的降低
下面的描述使用了第 5.1.2 节中定义的常量集合, 以及第 5.1.3 节中定义的变量集合.
黑洞检测由一个表明网络路径可能无法支持当前 PLPMTU 大小的指示所触发. 这类指示有三种可能的来源.
三种黑洞检测指示
1. PTB 消息指示
可以接收到一条经过验证的 PTB 消息, 它所指示的 PL_PTB_SIZE 小于当前的 PLPMTU. DPLPMTUD 方法禁止仅仅依赖这一种方法.
2. 周期性探测
PL 可以利用 DPLPMTUD 的探测机制, 周期性地生成具有当前 PLPMTU 大小的探测包(例如, 使用 CONFIRMATION_TIMER, 第 5.1.1 节). 由一个计时器来跟踪是否收到了确认. 接连不断的探测丢失是一个迹象, 表明当前路径已经不再能够维持该 PLPMTU(例如, 当已发送但未收到确认的探测包数量 PROBE_COUNT 变得大于 MAX_PROBES 时).
3. PL 事件指示
PL 可以利用某个事件来表明网络路径已经不再能够维持发送方的 PLPMTU 大小. 这可以通过在 PL 内部实现的机制来检测: 先检测到以特定包大小发送的数据出现了过量的丢失, 然后推断这种过量的丢失可能是由于一个无效的 PLPMTU 所导致的(就像 TCP 的 PLPMTUD [RFC4821] 那样).
探测模式的差异
这三种方法会导致被用作探测的包呈现出各不相同的传输模式, 并且在一条路径的真实 PMTU 发生变化之后, 预期这三者在检测到该变化并作出响应的速度上也会有所不同.
探测抑制
可以: 当应用自上一个探测包被发送之后一直没有再发送任何数据时, PL 可以抑制探测包的发送.
一个恢复了用户数据发送的 PL 可以继续针对每一条路径执行 PLPMTU 发现. 这样一来, 它就能够使用最新的 PLPMTU. 然而, 这样做可能会导致额外的包被发送出去.
PLPMTU 降低
当该方法检测到当前的 PLPMTU 已经不被支持时, DPLPMTUD 会设置一个更低的 PLPMTU 以及一个更低的 MPS. 随后 PL 会确认新的 PLPMTU 能够在这条路径上被成功使用. 探测包可能需要小于由应用所生成的数据块的大小.
4.4. 最大包大小 (MPS)
探测的结果确定了可用的 PLPMTU, 该 PLPMTU 被用来设置应用所使用的 MPS. MPS 小于 PLPMTU, 因为它被减去了 PL 头部的大小(包括诸如 AEAD tag 和 TLS 记录层填充等安全相关字段所带来的开销).
MPS 与 PLPMTU 的关系
|<----- PLPMTU ----->|
|<-- MPS -->| PL Headers | IP Headers |
| App Data | Transport | Security | Network |
PL 禁止(即不能)在网络层发送大小大于当前 PLPMTU 的包(探测包除外). 为了避免出现这种情况, PL 可以被设计为把大于 MPS 的数据块分割成多个数据报来发送.
DPLPMTUD 力求避免 IP 分片. 如果 PL 无法对数据进行分割, 那么发送一个大于 MPS 的数据块的尝试将会失败. 为了确定能够发送的最大数据块的大小, PL 应当向应用提供一个原语, 该原语返回由当前 PLPMTU 所导出的 MPS.
MPS 变化的处理
如果 DPLPMTUD 的结果导致 MPS 发生了变化, 应用就需要适应新的 MPS. 当发送出去的包的大小小于 MPS, 而 PLPMTU 随后被降低时, 会出现一种特殊情况. 如果这些包发生了丢失, PL 可以使用新的 MPS 对这些数据重新进行分割.
如果 PL 无法对一个先前已经发送出去的数据报进行重新分段(例如 [RFC4960]), 发送方要么丢弃该数据报, 要么利用网络层分片来执行重传, 从而形成多个不大于 PLPMTU 的 IP 包. 对于 IPv4, 发送方优先使用端点分片, 而不是清除 IPv4 头部中的 DF 位. 运营经验表明, IP 分片会降低互联网通信的可靠性 [RFC8900], 这可能会降低数据重传获得成功的概率.
4.5. 禁用 PMTUD 的影响
实现了本规范的 PL 必须针对每一个使用 DPLPMTUD 的流, 挂起 [RFC1191] [RFC8201] 中针对出向包网络层处理的 PMTU 强制执行, 转而使用 DPLPMTUD 来控制该流所发送的包的大小. 这就消除了网络层需要去丢弃或分片那些大小大于 PMTU 的已发送包的需求.
4.6. 对 PTB 消息的响应
该方法要求 DPLPMTUD 发送方在使用 PTB 信息之前, 先对任何收到的 PTB 消息进行验证. 对一条 PTB 消息的响应取决于这样几个因素: 由 PTB 消息中的 PTB_SIZE 所计算得出的 PL_PTB_SIZE, PLPMTUD 状态机当前所处的状态, 以及当前正在使用的 IP 协议.
第 4.6.1 节描述了对 IPv4 ICMP Unreachable 消息(Type 3)以及 ICMPv6 Packet Too Big 消息的验证, 本文档将这两类消息均称为 PTB 消息.
4.6.1. PTB 消息的验证
本节规定 PTB 消息的使用方式与验证方式.
实现选项
-
简单实现: 可以忽略收到的 PTB 消息, 在这种情况下, 当收到 PTB 消息时 PLPMTU 不会得到更新.
-
支持 PTB 的 PL: 在进行进一步处理之前必须先验证这些消息.
验证过程
从路由器或中间盒收到一条 PTB 消息的 PL 需要执行 ICMP 验证(参见 [RFC8201] 第 4 节以及 [BCP145] 第 5.2 节). 由于 DPLPMTUD 工作在 PL 这一层, PL 需要检查每一条收到的 PTB 消息, 以确定它是否是对执行 DPLPMTUD 的那个端点 PL 所发出的包作出的响应.
PL 必须检查 ICMP PTB 消息载荷中所携带的被引用包(quoted packet)里的协议信息, 以验证该消息是否源自发送节点. 这一验证包括确定 IP 地址, 协议, 源端口和目的端口的组合, 是否与被引用包中所返回的组合相匹配 —— 对于要让该 PTB 消息被传递给相应的 PL 而言, 这一步也是必需的.
验证应当利用那些离路径攻击者不容易获得的信息 [BCP145]. 例如, 它可以检查只有两个 PL 端点才知道其取值的协议头部字段. 使用众所周知的源端口和目的端口的数据报应用, 还应当依赖其他的信息来完成这一验证.
这些检查旨在针对那些并非源自网络路径上节点的包提供保护. 尚未完成验证的 PTB 消息禁止被 DPLPMTUD 方法进一步使用, 正如安全性考量一节(第 8 节)中所讨论的那样.
第 4.6.2 节描述 PTB 消息的处理.
4.6.2. PTB 消息的使用
一条经过验证的 PTB 消息可以被 DPLPMTUD 算法所利用, 但禁止被直接用来设置 PLPMTU 的取值.
在使用 PTB 消息中所报告的大小之前, 必须先把它转换为一个 PL_PTB_SIZE. PL_PTB_SIZE 小于 PTB_SIZE, 因为它被减去了位于 PL 之下的那些头部, 包括被添加到 PL 包上的任何 IP 选项或扩展.
与那些仅仅依赖基于计时器的搜索算法的方法相比, 利用这些 PTB 消息的方法可以通过触发一次针对 PL_PTB_SIZE(对应的网络层包大小为 PTB_SIZE)的立即探测, 来提升算法发现合适 PLPMTU 的速度.
有一组检查旨在针对路由器报告非预期 PTB_SIZE 的情况提供保护. PL 还需要检查所指示的 PL_PTB_SIZE 是否小于探测包所使用的大小, 并且至少不小于最小可接受的大小.
PTB 消息处理小结
本节使用第 5.1.2 节中定义的常量集合, 对 PTB 消息的使用方式进行一个总结. 这一处理过程取决于 PL_PTB_SIZE 的取值, 以及一组变量的当前值:
PL_PTB_SIZE < MIN_PLPMTU
- 无效的 PL_PTB_SIZE, 见第 4.6.1 节
- 这条 PTB 消息应当被丢弃, 不做进一步的处理(即 PLPMTU 不被修改)
- 这一信息可以作为一项输入, 用于触发启用韧性模式(见第 5.3.3 节)
MIN_PLPMTU < PL_PTB_SIZE < BASE_PLPMTU
- 对于 IPv4 路径, 当 PTB 消息中报告的 PL_PTB_SIZE 大于等于 68 字节 [RFC0791] 且小于 BASE_PLPMTU 时, 健壮的 PL 可以进入 Error State(见第 5.2 节)
- 对于 IPv6 路径, 当 PTB 消息中报告的 PL_PTB_SIZE 大于等于 1280 字节 [RFC8200] 且小于 BASE_PLPMTU 时, 健壮的 PL 可以进入 Error State(见第 5.2 节)
BASE_PLPMTU <= PL_PTB_SIZE < PLPMTU
- 这可能是出现黑洞的一个征兆. PLPMTU 应当被设置为 BASE_PLPMTU(将 PLPMTU 降低到 BASE_PLPMTU, 以便在遭遇黑洞时避免不必要的丢包)
- PL 应当启动一次搜索, 以便快速地发现新的 PLPMTU 值. PTB 消息中报告的 PL_PTB_SIZE 可以用来对这个搜索算法进行初始化
PLPMTU < PL_PTB_SIZE < PROBED_SIZE
- PLPMTU 仍然保持有效, 但搜索所使用的大小(PROBED_SIZE)大于实际的 PMTU
- PLPMTU 不会被更新
- 当恢复搜索算法时, PL 可以把 PTB 消息中报告的 PL_PTB_SIZE 用作下一个搜索点
PL_PTB_SIZE >= PROBED_SIZE
- 不一致的网络信号
- 这条 PTB 消息应当被丢弃, 不做进一步的处理(即 PLPMTU 不被修改)
- 这一信息可以作为一项触发启用韧性模式的输入
这些机制共同确保了 DPLPMTUD 能够可靠地发现并维持一个合适的路径 MTU(路径最大传输单元).