pmtu概述


难度 中等

发表于 2017-12-19 更新于 2019-04-17 分类于 c 评论数: 0 Comments

Path MTU 简述。

结论

  • 概念

    • PMTU,Path MTU,以路由为单位,作为路由表的属性信息缓存于路由表。
    • PMTU发现机制,若网络设备收到超MTU IP报文且该IP报文不允许分片,则返回一个ICMP type 3 code 4报文(The datagram is too big. Packet fragmentation is required but the 'don't fragment' (DF) flag is on.),将网络设备支持的MTU大小附在ICMP报文中,返回给报文源主机,由报文源主机调整该路径的PMTU。该机制利用IP头部flags中的Don't fragment位,为1时表示不允许分片。
  • 影响。在GRE IP隧道叠加网中,报文将在IP头部后添加上24字节GRE IP头部。以默认IP MTU为1500字节为例,原先一个1514字节大小的报文(IP头部 + 数据刚好为IP MTU 1500字节)在公网上可以正常传输,若此时将路径切换到GRE IP隧道叠加网,则报文长度将变成1528字节(IP头部 + 数据 = 1524字节),将超过默认IP MTU。
    详见 H3C 文章 看招MTU!!!——高端路由器GRE组网中需要注意的问题

    • 如果分片发生在旁挂设备,则将导致GRE IP报文被分片,无法在隧道终结处重组,因为第二个分片不带GRE头部。
    • IP报文不允许分片
      • 对于TCP报文
        • 将通过PMTU发现机制,调整主机PMTU
        • 通过快速重传机制,迅速恢复
        • 主机调整TCP报文大小,以适应PMTU
      • 对于UDP报文
        • 将通过PMTU发现机制,调整主机PMTU
        • 丢弃该报文
        • 后续传输时,对超过PMTU的报文,在主机处主动进行分片。
        • 若有需要,超时重传、调整报文大小的机制由UDP的上层协议支持。
      • 对于其他IP报文(以ping报文为例)
        • 将通过PMTU发现机制,调整主机PMTU
        • 丢弃该报文
        • 后续传输时,在主机处主动分片(以Linux为例)
    • IP报文允许分片
      • 如果业务开始前,主机已经调整PMTU,则分片在主机进行,业务可正常运行。
      • 如果主机未调整PMTU,则分片在旁挂设备进行,将导致业务中断。此问题将影响整个方案。
  • 规避手段

    • 规避目标:将分片的行为转移至主机上,不允许旁挂设备上进行任何分片行为。
    • 方案:对所有超IP MTU送旁挂设备CPU的报文,皆返回ICMP type 3 code 4。需验证此规避对允许分片IP报文的影响。
    • 风险:对控制面和管理面的影响待评估。
  • 分析

    • Linux

      • PMTU发现机制默认为IP_PMTUDISC_WANT,如果报文不超过PMTU,默认开启PMTU发现机制,如果报文超过PMTU,则主动在终端进行分片处理。(will fragment a datagram if needed according to the path MTU, or will set the don’t-fragment flag otherwise.
    • Windows

      • TCP报文,默认不允许分片
      • 其他报文,默认允许分片
      • 对允许分片的报文,如果报文长度超过PMTU,则主动在终端处进行分片
    • 不能假定网络上的所有的TCP报文都不允许分片(如新浪网,默认TCP报文允许分片)

实验结果

系统 协议 默认是否加DF 默认对超PMTU的处理
Linux TCP 调整TCP段长度
Linux UDP 不做处理,用户程序处理
Linux RTSP(UDP) 丢掉ICMP packet too big的那几个包,后续分片
Linux TFTP(UDP) 等不到ACK,timeout退出
Linux ping 不重传报文,主机提示From 3.3.3.3 icmp_seq=93 Frag needed and DF set (mtu = 0),后开始在主机对ping报文进行分片,分片后的报文DF=0;如果强制设置DF:-M = do,则提示ping: local error: Message too long, mtu=552
Linux TCP(自己构造) 默认在交换机中送CPU分片,如果此时有一个ICMP packet too big返回至主机(比如由ping触发),则会转在主机分片
Windows TCP 调整TCP段长度
Windows UDP 被路由器分片或被主机分片
Windows ping 无处理,在交换机中分片,如果此时有ICMP packet too big(如TCP触发),则会主动在终端分片。如果强制设置DF:-f,则提示Packet needs to be fragmented but DF set.

如上实验结果,得出以下结论:

  1. Linux下,TCP/UDP报文默认都置上DF位;
  2. Windows下,TCP报文默认置上DF位,UDP报文默认不置DF位;
  3. Linux下,UDP的对ICMP packet too big报文的处理取决于用户,Linux内核不进行处理
  4. 不管Linux还是Windows下,如果要发出的UDP报文大于PMTU,则会主动在HOST端进行分片。
  5. PMTU以路由(SIP + DIP + TOS)为单位影响系统,UDP虽然没有主动调整数据报的大小,但是因UDP报文返回的ICMP packet too big报文会影响对应路由的PMTU。

标准

按RFC 1191的定义,PMTU发现机制为Packetization Protocol服务,TCP是这种可调节报文大小的协议,因此可直接使用;而UDP协议需要靠上层协议来实现报文大小调整。

RFC 1191 第6章“Host Implementation”讲述PMTU Discovery对终端的建议(仅仅是suggestion,不是specification):

  • 在哪个或哪些层次实现PMTU发现机制;
    • 由IP以上层次决定报文要发多大;
    • Pakcetization Protocol必须能影响PMTU变化,含更新报文大小、控制DF位。(IP层不控制DF位)
  • PMTU信息缓存在哪;
    • 把PMTU做为路由表项的一个属性成员。
    • 对于UDP这种无连接的报文,若返回ICMP packet too big,需要其上层协议通过超时重传机制,重传被dropped的报文。
  • 旧PMTU信息如何被老化;
  • PMTU如何上涨;

Linux的处理

Linux Kernel的实现参考:man 7 ip 中关于IP_MTU_DISCOVER的描述。

IP_MTU_DISCOVER (since Linux 2.2)
Set or receive the Path MTU Discovery setting for a socket. When enabled, Linux will perform Path MTU Discovery as defined in RFC 1191 on SOCK_STREAM sockets. For non-SOCK_STREAM sockets, IP_PMTUDISC_DO forces the don’t-fragment flag to be set on all outgoing packets. It is the user’s responsibility to packetize the data in MTU-sized chunks and to do the retransmits if necessary. The kernel will reject (with EMSGSIZE) datagrams that are bigger than the known path MTU. IP_PMTUDISC_WANT will fragment a datagram if needed according to the path MTU, or will set the don’t-fragment flag otherwise.
The system-wide default can be toggled between IP_PMTUDISC_WANT and IP_PMTUDISC_DONT by writing (respectively, zero and nonzero values) to the /proc/sys/net/ipv4/ip_no_pmtu_disc file.

When PMTU discovery is enabled, the kernel automatically keeps track of the path MTU per destination host. When it is connected to a specific peer with connect(2), the currently known path MTU can be retrieved conveniently using the IP_MTU socket option (e.g., after an EMSGSIZE error occurred). The path MTU may change over time. For connectionless sockets with many destinations, the new MTU for a given destination can also be accessed using the error queue (see IP_RECVERR). A new error will be queued for every incoming MTU update.

While MTU discovery is in progress, initial packets from datagram sockets may be dropped. Applications using UDP should be aware of this and not take it into account for their packet retransmit strategy.

To bootstrap the path MTU discovery process on unconnected sockets, it is possible to start with a big datagram size (up to 64K-headers bytes long) and let it shrink by updates of the path MTU.

To get an initial estimate of the path MTU, connect a datagram socket to the destination address using connect(2) and retrieve the MTU by calling getsockopt(2) with the IP_MTU option.

It is possible to implement RFC 4821 MTU probing with SOCK_DGRAM or SOCK_RAW sockets by setting a value of IP_PMTUDISC_PROBE (available since Linux 2.6.22). This is also particularly useful for diagnostic tools such as tracepath(8) that wish to deliberately send probe packets larger than the observed Path MTU.


文章作者: growdu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 growdu !
  目录
分类导航
随笔2 AI27 算法1 计算机基础13 博客搭建7 ChatGPT2 集群63 计算机通信1 数据库34 数据库深入80 DPDK26 Docker11 Elasticsearch4 编辑工具4 FAQ1 Go Web1 hometown2 编程语言16 网络9 OPC1 Linux38 openGauss4 页面12 PostgreSQL54 程序员自我修养1 协议11 成长之路1 stock1 存储5 工具20 VPP18 视频作品1 Vue13 Web1 代码示例11 数据库15 BenchmarkSQL1 PostgreSQL 源码修炼之路14
最热文章
1
13 逻辑复制深入
数据库深入🔥 1570
2
0 Postgresql存储、索引及系统优化、主备切换
PostgreSQL🔥 1495
3
一文读懂openguass dcf网络模块
集群🔥 1420
4
逻辑复制源码分析
数据库深入🔥 1327
5
PostgreSQL 分区表:从一行 `PARTITION BY` 到路由热路径的全链路拆解
数据库🔥 1094
6
applyparallelworker.c 之 LA 端源码深度解析:Leader Apply Worker 的指挥中枢
数据库深入🔥 1082
7
PostgreSQL Background Worker 全解:从 `RegisterBackgroundWorker` 到逻辑复制 4 类 worker 的全生命周期
数据库🔥 1078
8
PostgreSQL的后台进程walsender分析 - 关系型数据库 - 亿速云
PostgreSQL🔥 1033
9
PostgreSQL 逻辑复制的监控:六张视图 + 一组可执行 SQL,把 publisher/subscriber 的速率与健康度彻底看透
数据库🔥 1032
10
PostgreSQL 逻辑复制支持 DDL 之后:DDL 与 DML 的时序难题(重点:分区表)
数据库🔥 999
11
reorderbuffer.c 源码深度解析:PostgreSQL 逻辑复制的"事务重组引擎
数据库深入🔥 953
12
PostgreSQL 内核开发:读取一张表的 9 步标准流程与缓存全景
数据库🔥 938
13
从 `postgres` 二进制到生产级守护 —— PostgreSQL 最外层模块与启动全流程拆解
数据库🔥 936
14
支持逻辑复制同步 DDL 适配 SQL Server 方案
数据库深入🔥 934
15
PostgreSQL 逻辑复制的 ReorderBuffer 与事务机制:从一行 WAL 到一致性变更流的全链路绑定
数据库🔥 913
16
DDL同步架构(美化版)
数据库深入🔥 908
17
PostgreSQL Latch 机制详解:从一行 SetLatch 到 epoll 的内核之旅
数据库🔥 871
18
pgbench 源码全解:一个 C 文件如何撑起 PostgreSQL 官方压测工具
数据库🔥 860
19
PostgreSQL libpq 机制与缓冲区详解
数据库🔥 850
20
PostgreSQL 逻辑复制 spill 文件深度剖析:从 `xid-*.spill` 到 TPC-C 的增长方程
数据库🔥 845