5.2 Storing PMTU Information (存储 PMTU 信息)
5.2 Storing PMTU Information (存储 PMTU 信息)
理想情况下, PMTU 值应该与源节点和目的节点之间交换的数据包所经过的特定路径相关联。然而, 在大多数情况下, 节点没有足够的信息来完整且准确地标识这样的路径。相反, 节点必须将 PMTU 值与路径的某种本地表示 (local representation) 相关联。由实现来选择路径的本地表示。对于具有多个接口的节点, 应该为每个 IPv6 链路维护路径 MTU 信息。
在多播目的地址的情况下, 数据包的副本可能会经过许多不同的路径到达许多不同的节点。到多播目的地的 "路径" 的本地表示必须代表一个潜在的大型路径集合。
最低限度, 实现可以维护一个单一的 PMTU 值, 用于从节点发出的所有数据包。这个 PMTU 值将是节点使用的所有路径集合中学到的最小 PMTU。这种方法可能会导致对许多路径使用比必要更小的数据包。在多路径路由 (multipath routing) 的情况下 (例如, 等价多路径路由, Equal-Cost Multipath Routing, ECMP), 即使对于单个源和目的地对, 也可以存在一组路径。
实现可以使用目的地址作为路径的本地表示。与目的地相关联的 PMTU 值将是到达该目的地使用的所有路径集合中学到的最小 PMTU。这种方法将导致在每个目的地的基础上使用最优大小的数据包。这种方法与 [ND] 中描述的主机概念模型很好地集成: PMTU 值可以与目的地缓存 (destination cache) 中的相应条目一起存储。
如果使用流 (flows) [RFC8200], 实现可以使用流 ID (flow id) 作为路径的本地表示。发送到特定目的地但属于不同流的数据包可能使用不同的路径, 如同 ECMP, 其中路径的选择可能取决于流 ID。这种方法可能会导致在每个流的基础上使用最优大小的数据包, 提供比在每个目的地的基础上维护 PMTU 值更精细的粒度 (granularity)。
对于源路由数据包 (即包含 IPv6 路由头部 [RFC8200] 的数据包), 源路由可能进一步限定路径的本地表示。
最初, 路径的 PMTU 值被假定为第一跳链路的 (已知) MTU。
当收到 Packet Too Big 消息时, 节点根据 Packet Too Big 消息的内容确定该消息适用于哪个路径。例如, 如果目的地址被用作路径的本地表示, 则原始数据包中的目的地址将用于确定消息适用于哪个路径。
注意: 如果原始数据包包含路由头部 (Routing header), 应该使用路由头部来确定目的地址在原始数据包中的位置。如果 Segments Left 等于零, 则目的地址位于 IPv6 头部的目的地址字段 (Destination Address field) 中。如果 Segments Left 大于零, 则目的地址是路由头部中的最后一个地址 (Address[n])。
然后, 节点将 Packet Too Big 消息中 MTU 字段的值用作暂定 PMTU 值 (tentative PMTU value), 或者如果 IPv6 最小链路 MTU 更大则使用 IPv6 最小链路 MTU, 并将暂定 PMTU 与现有 PMTU 进行比较。如果暂定 PMTU 小于现有 PMTU 估计, 则暂定 PMTU 将替换现有 PMTU 作为路径的 PMTU 值。
必须将 PMTU 的降低通知给分组层。任何正在积极使用该路径的分组层实例 (例如, TCP 连接) 必须在 PMTU 估计降低时得到通知。
注意: 即使 Packet Too Big 消息包含引用 UDP 数据包的原始数据包头部 (Original Packet Header), 如果任何 TCP 连接使用给定的路径, 也必须通知 TCP 层。
此外, 发送引发 Packet Too Big 消息的数据包的实例应该被通知其数据包已被丢弃, 即使 PMTU 估计没有改变, 以便它可以重传被丢弃的数据。
注意: 实现可以通过将通知推迟到下一次尝试发送大于 PMTU 估计的数据包时, 来避免使用 PMTU 降低的异步通知机制。在这种方法中, 当尝试发送 (SEND) 大于 PMTU 估计的数据包时, SEND 函数应该失败并返回适当的错误指示。这种方法可能更适合无连接的分组层 (例如使用 UDP 的分组层), 在某些实现中, 可能很难从 ICMPv6 层 "通知" 它。在这种情况下, 将使用正常的基于超时的重传机制来从被丢弃的数据包中恢复。
重要的是要理解, 通知使用该路径的分组层实例关于 PMTU 变化的通知与通知特定实例数据包已被丢弃的通知是不同的。后者应该尽快完成 (即, 从分组层实例的角度来看是异步的), 而前者可以延迟到分组层实例想要创建数据包时。