Path MTU Discovery
This RFC is release on 1990.11 obsoletes RFC1063 which is released on 1988.07
1. Protocol Overview
通过设置IP header 的 DF
bit 来动态发现一个路径的PMTU1:
以第一跳2的MTU为初始值(已知的),如果收到ICMP code 3-434
由于网络拓扑会随时间改变,PMTU的减少,仍然可以通过DTB meessage得知,只要DF bit 被设置,而PMTU的增加,可以通过主机上的定期任务5来检测。
2. Host(主机)specification
当Host探索PMTU的减少时,速度必须尽可能地快,而探索PMTU的增加时,探索的时间间隔不能频繁(infrequent)6。
更具体地,当探索PMTU的增加时,增加失败的间隔不少于5min,增加成功的间隔不小于1min,建议的间隔分别是是10min和2min。
Host必须向下兼容不包含next-hop MTU的旧风格的DTB message7。
Host估值的PMTU应该不低于68 octets8
3. TCP MSS9 Option
除非被允许,Host进行PMTUD时发送IP包的长度不应该超过 536 + 40 = 576 octets。
而很多TCP实现总是设置MSS选项并且将值设为536,如果目的连接是非本地的。这种行为是对的,因为互联网上到处都是不遵守规则,发送超过576 octets10的的host。
一个host可能根据MTU设置MMS,这不应该对PMTUD造成问题,并且可以劝阻同层发送巨大的数据报
4. Router(路由器) specification
DTB message(ICMP code 3-4) format, 提供额外的origin header,next-hop MTU 不赘叙
5. 处理旧风格的message
即如果message本身没有提供PMTU的信息。
最简单的方式是取当前估计的PMTU与576之间的最小值,并且取消DF
bit。
更复杂的方式需要“搜索”准确的PMTU估计值。有几个可能方法,它们根据一个之前的估计值产生一个新的估计值。
比如乘以一个常数比如0.75,但这样收敛又慢,产生的估计值又低于实际的值。所以不推荐。
再比如进行二分搜索,它收敛快一点,但从FDDI11 MTU落到Ethernet12 MTU仍然需要4-5步,而有一个非常的劣势是识别数据报到达另一端的时间是一个复杂实现。因此也不推荐。
有一个看起来效果似乎很好方法是比起盲搜,搜索一组可能出现的值,因为设计者们倾向于用类似的方式选择MTUs,使用其中的最小值13。使用下表的搜索,
Table Common MTUs in the Internet:
Plateau | MTU | Comments | Reference |
---|---|---|---|
65535 | 65535 | Official maximum MTU | RFC 791 |
32004 | 65535 | Hyperchannel | RFC 1044 |
17914 | 17914 | 16Mb IBM Token Ring | |
8166 | 8166 | IEEE 802.4 | RFC 1042 |
4464 | IEEE 802.5 (4Mb max) | RFC 1042 | |
4352 | 4352 | FDDI (Revised) | RFC 1188 |
2048 | Wideband Network | RFC 907 | |
2002 | 2002 | IEEE 802.5 (4Mb recommended) | RFC 1042 |
1536 | Exp. Ethernet Nets | RFC 895 | |
1500 | Ethernet Networks | RFC 894 | |
1500 | Point-to-Point (default) | RFC 1134 | |
1492 | 1492 | IEEE 802.3 | RFC 1042 |
1006 | SLIP | RFC 1055 | |
1006 | 1006 | ARPANET | BBN 1822 |
576 | X.25 Networks | RFC 877 | |
544 | DEC IP Portal | ||
512 | NETBIOS | RFC 1088 | |
508 | IEEE 802/Source-Rt Bridge | RFC 1042 | |
508 | 508 | ARCNET | RFC 1051 |
296 | 296 | Point-to-Point (low delay) | RFC 1144 |
68 | 68 | Official minimum MTU | RFC 791 |
使用这个表的收敛性最坏情况也比二分搜索相当,因为plateau几乎是2的幂,而如果值不在表中,被低估的值也不会超过2倍。
所有ICMP code 3 都包含源IP header,可以直接使用其中的Total Length字段的值作为输入,生成下一个估计值14。
该表仅是建议参考,应该保持更新,添加一些2的幂加40(IP header + TCP header)的项,作为过渡,也可以包含稍微比2的幂稍小一些的项。但不管怎样,plateau的数量不应该太多,而实现者应该给无源代码客户提供一种方便的更新表值的工具15
6. Host implementation
提供一组关于PMTUD在主机软件上实现的建议。
6.1 Layering(分层)
IP层应该存储PMTU信息,并且ICMP层应该处理DTB message。而分包层16应该能反映PMTU的变化,通过改变发送数据报的大小,并且必须能指定DF
bit。我们不希望IP层简单地为每个包设定DF
bit,因为分包层可能无法改变它的数据报的大小17
6.2 Storing PMTU Information
存储信息的明显位置是将其作为一个字段,存储在路由表项中。一个主机不会为每一个目标地址有一个路由信息,但应该能为每个活跃目标地址缓存路由18。
使用同一路径的所有的分包层都应该被通知,如果该路径PMTU减少了。这种通知应该区别于普通的包的丢失。
6.3 Purging stale PMTU information
由于没有机制能实现发现当前的使用的PMTU因为它太小而过时了,所以需要一个实现能够老化缓存的值,以便有机会发现的新的更大的PMTU19。而上层协议绝对不能因为PMTU的增加而重发,因为这没有包的丢失。
一个实现PMTU老化的方法是给路由表项添加时间戳字段,这个字段初始化为一个保留值,表明这个PMTU没有改变。当PMTU减少时,时间戳更新为当前时间。计时器驱动的程序扫描整个路由表,当一个表项的时间戳不是保留值时,如果超时了,则:
- 将估计的PMTU设置为关联的第一跳的MTU
- 使用这个路由的分包层被通知PMTU的增加
PMTU估计值可能从路由表消失,如果路由表项被移除掉20,一个解决方法是当ICMP 重定向消息导致路有变化或者当路由被删除的时候通知分包层
6.4 TCP layer actions
TCP数据报的大小受PMTU和MSS的双重制约。
当DTB message到达的时候,特定连接的特定于DTB message的数据报立刻重传,当然需要使用新的PMTU。
现代TCP实现包含拥塞控制和慢启动算法,DTB message不应该影响拥塞窗口,但是应该触发慢启动机制21。
TCP的性能可能会下降,如果发送方的最大窗口大小22不是精确的分片(segment)大小的几倍。如果使用了PMTUD,分片的大小发生改变,就会出现这种情况。因此应该根据新PMTU的大小调整最大窗口大小,来适应新的分片的大小,使保持一个整数倍的关系。
PMTUD不应该影响MSS选项的数值。
6.5. Issues for other transport protocols
像原始NFS协议这种如果有难处,还是分片传输吧。
6.6. Management interface
一个PMTUD的实现应该为系统工具程序提供:
- 指定不在给定路由上做PMTUD23
- 改变给定路由的PMTU
- 改变PMTU老化的时间间隔
7. Likely values for Path MTUs
合并到第五章
8. Security considerations
通过发送恶意DTB message可以实现两种DOS攻击:
- 提供过于小的PMTU,使得连接变慢
- 提供过于大的PMTU,这可能会造成暂时的阻塞,因为受害者的包会被路由器丢弃,在一个往返的时间里,主机会发现错误,但频繁的重复攻击会导致大量的数据报被丢弃。而一个主机永远不能根据DTB message提供的PMTU来提高估计值的上限,因为这会使得面对这种攻击变得很脆弱。
-
Path MTU ↩
-
First Hop ↩
-
Fragmentation required, and DF flag set, carrying next-hop MTU and IP header and first 8 bytes of original datagram’s data ↩
-
也就是PTB(Packet Too Big) message,或者DTB(Datagram Too Big) message ↩
-
发送更高的PMTU假设的数据包,看是否能通过,大多数情况下PMTU不会改变,因此不应该太频繁地启用。 ↩
-
因为需要发送比当前估计的PMTU更大的数据报,并且PMTU不太可能增加 ↩
-
可以通过检测next-hop MTU字段是否为0,来识别旧风格的DTB,根据ICMP的规定,未使用的字段必须为0 ↩
-
1 octect = 1 byte in CPU = 8 bit ↩
-
Max Segment Size, IP datagram size minus IP header and TCP header (40 bytes, totally) ↩
-
576 is safe max IP datagram size for TCP, or 536 for MSS ↩
-
Fiber Distributed Data Interface, 光纤网,用于校园网、广域网 ↩
-
比起FDDI,高带宽效率低,但延迟也低 ↩
-
as “plateau” ↩
-
基于4.2BSD实现的路由器会发送错误的Total length,它额外加上了origin header length,而且以octets而不是4xoctets的形式表现 ↩
-
BSD 派生的Unix内核提供
ioctl
来做这件事 ↩ -
在IP结构里,发送多大的数据报是由IP上层的协议决定的,我们称这样的协议为分包层(Packetization Layer) ↩
-
比如一个内核外的UDP应用, 比如最原始版本的NFS协议,一个跨网络管理文件的系统,这种情况下应该允许分片(fragmentation) ↩
-
这个需求已经被处理ICMP重定向消息的需要强制满足了 ↩
-
这个时间从上一次PMTU不减开始,以10min为标准 ↩
-
这可能发生在ICMP重定向消息或者特定的路由守护进程几分钟后删除了旧的路由信息,还可能是在一个多网卡(multi-homed host)的主机上拓扑的变化可能导致不同网卡的使用 ↩
-
也就是只重传第一个分段,直到收到ACK ↩
-
最大窗口区别于拥塞窗口,拥塞窗口的大小总是分片大小的几倍,而最大窗口(send space)在很多系统(比如从4.2BSD衍生出来的)通常是1024 octets的几倍,是固定的 ↩
-
可以在路由项上设置一个标志位,当有这个标志位时,
DF
bit一定会被清除,不管上层请求是什么 ↩