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 !
  目录
分类导航
随笔3 AI29 计算机基础13 算法1 博客搭建7 ChatGPT2 集群63 计算机通信1 数据库59 数据库深入93 数据库93 Docker11 DPDK26 编辑工具4 Elasticsearch4 FAQ1 Go Web1 hometown2 编程语言16 人生11 网络9 Linux38 OPC1 openGauss4 页面12 PostgreSQL54 程序员自我修养1 协议11 stock1 存储5 成长之路1 工具20 视频作品1 VPP18 Vue13 Web1 代码示例11 BenchmarkSQL1 PostgreSQL 源码修炼之路14
最热文章
1
PostgreSQL 逻辑复制全链路:以一个真实事务为例,从 `INSERT` 到 `apply` 的源码级旅程
数据库🔥 2162
2
PostgreSQL 逻辑复制 Stream 执行逻辑源码级拆解:从 reorderbuffer 触发到订阅端落盘回放
数据库🔥 1765
3
PostgreSQL 行锁机制源码级深度拆解:4 种锁模式 + xmax + MultiXact 的完整链路
数据库🔥 1656
4
PostgreSQL reorderbuffer.c 函数级源码全集:5615 行 / 95 个函数的逐函数解析
数据库深入🔥 1650
5
PostgreSQL 目录快照源码级深度拆解:系统表读取的 MVCC 真相与失效机制
数据库🔥 1604
6
13 逻辑复制深入
数据库深入🔥 1570
7
0 Postgresql存储、索引及系统优化、主备切换
PostgreSQL🔥 1495
8
PostgreSQL 读一行数据源码级深度拆解:MVCC 在每个环节的落点
数据库🔥 1464
9
PostgreSQL WAL 记录类型完全指南:21 个 RMGR × 80+ 种记录的源码级拆解
数据库🔥 1431
10
一文读懂openguass dcf网络模块
集群🔥 1420
11
PostgreSQL 元数据存储机制:从磁盘文件到内存缓存,`pg_class` 撑起的整个系统表体系
数据库🔥 1411
12
openGauss 并行解码设计原理深度拆解:reader + 多 worker + CSN 三层架构的源码级剖析
数据库深入🔥 1344
13
逻辑复制源码分析
数据库深入🔥 1327
14
PostgreSQL 逻辑复制:catalog 改动、可见性判定与 xmin/xmax 推进全景
数据库深入🔥 1317
15
自托管服务全家桶:从原文方案到可复制实操手册
人生🔥 1278
16
PostgreSQL CREATE_REPLICATION_SLOT 端到端源码分析:从 SQL 到 snapbuild 状态机的完整链路(每个函数每个参数)
数据库深入🔥 1277
17
PostgreSQL syscache 模块源码深度拆解:CatCache 数据结构、LRU 哈希表、cache invalidation 全链路
数据库深入🔥 1216
18
PostgreSQL 18 内核数据结构全景:RangeVar 与 20+ 个核心数据结构源码级拆解
数据库🔥 1158
19
PostgreSQL 逻辑复制里 `RUNNING_XACTS` 写入机制与快照 `xmin / xmax / xip` 的演化:源码级深度拆解
数据库🔥 1119
20
PostgreSQL 分区表:从一行 `PARTITION BY` 到路由热路径的全链路拆解
数据库🔥 1094