就我所了解的IPv6碎片而言,路由器不会执行碎片,只有端到端的节点才能执行碎片。 当path上的任何一台路由器收到一个大于下一跳链路MTU的数据包时,它将丢弃它,并用一个ICMPv6“Packet too big”回复源IP。
以下是我在我的设置中观察到的:
最初在我的本地以太网链路启动后,我访问一个HTTP页面,请求发送一个大的(1965字节)数据包。 我的路由器回复ICMPv6,说数据包太大,我的MTU是1492(ADSL链路的)。 然后,我的机器将TCP数据包分成两个较小的数据包(1492和545字节),然后再次尝试(而不是将扩展头添加到IPv6以进行分段,这是我所期望的)。
到现在为止还挺好。 令我感到困惑的是,从那以后,路由器不再发回“分组太大”的响应,尽pipe一些传出分组的大小大于2K(例如2399字节),并且一切看起来都很好(即,不使用较小分组进行重传) 。
任何想法发生了什么?
我在Linux 3.14.23和我的路由器的番茄基础。 目前我的路由器上没有数据包监控function。
标准允许在IPv6和物理层之间进行逐层分段。 实际上,如果物理层的MTU小于1280字节,则这种逐跳分段甚至是强制性的。 IPv6层之下的这种碎片的确切工作超出了IPv6标准的范围。 RFC 2460中的确切措辞是这样的:
在任何不能传送1280个八位字节数据包的链路中,必须在低于IPv6的层上提供特定于链路的分段和重组。
您想到的碎片是IPv6中的端到端碎片。 而这种碎片只能由始发于数据包的节点执行。 不允许中间路由器对正在转发的数据包执行这种分段。
就我的问题而言,你的情况并不是那么分散。
如果您能够首先从HTTP客户端发送一个2KB的数据包到路由器,这意味着您的LANconfiguration为使用jumboframe。 另一种可能性是HTTP客户端在支持TCP分段卸载的主机上运行。 如果是这样的话,在发送主机上使用tcpdump观察时,第一个数据包可能看起来是2KB,但在networking上,它实际上可能是一个包含前1500个字节的数据包,剩下的数据包可能是另一个数据包。
对于ADSL链路上的MTU来说,1500字节仍然太大。 在客户端计算机上,通过使用适当的工具(例如Wireshark)检查错误消息,可以看到实际大小的数据包是否触发了太大的错误消息。
一旦客户端的TCP堆栈收到太大的错误,会发生什么情况取决于正在使用哪个TCP堆栈。 有些会使用IPv6碎片重新传输相同的TCP段,另一些会将TCP段拆分成两个较小的TCP段。 IPv6标准说:
为了发送大于path的MTU的分组,节点可以使用IPv6分段报头在源处对分组进行分段并且在目的地重新组装。 但是,在任何能够调整其数据包以适应测量的pathMTU(即,低至1280个八位字节)的应用中,不鼓励使用这种分段。
我认为这是因为build议将TCP段重新传输为两个较小的段而不是使用IPv6分段。 TCP分段优先于分段的原因有多种。
路由器可能会限制太大的错误信息。 因此,如果您发送多个TCP段(每个段大于2KB),则可能只会收到第一个错误消息。 TCP堆栈应该能够通过使用较小的MTU来解决这个问题,一旦它重新发送超过MTU的数据包,第一次。
你所看到的可能只是一个低于你预期的比率限制。 您可以尝试衡量实际使用的费率限额,然后只有在发现不合理的低限时才采取进一步措施。
一旦确定了初始碎片大小。 它应该坚持链接。 初始数据包最初将失败。 在发送之前,更多的数据包将在IPv6堆栈中被分段。 在客户端转储stream量并检查数据包大小。 在传输之前,您应该看到较大的数据包(响应)被分段。
你指出在第一次分裂之后一切都有效。 这表明数据包被正确地分段,否则它们可能会失败,进一步沿着路由进行分段。