Linux 网络:PMTUD 简介
文章目录
- 1. 前言
- 2. Path MTU Discovery(PMTUD) 协议
- 2.1 PMTUD 发现最小 MTU 的过程
- 3. Linux 的 PMTUD 简析
- 3.1 创建 socket 时初始化 PMTUD 模式
- 3.2 数据发送时 PMTUD 相关处理
- 3.2.1 源头主机发送过程中 PMTU 处理
- 3.2.2 转发过程中 PMTUD 处理
- 4. PMTUD 观察
- 5. 参考链接
1. 前言
限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。
2. Path MTU Discovery(PMTUD) 协议
在说明 Path MTU Discovery(PMTUD) 之前,先得说说 MTU(Maximum Transmission Unit) 。什么是 MTU(Maximum Transmission Unit) ?MTU 是网卡的最大传输单元,即网卡最多一次传输数据的字节数,这是一个网卡硬件的参数。当数据从 IP 层 向下传递 数据链路层 时,如果发现 IP 数据包的长度 大于 网卡的 MTU 时,就需要将 IP 数据包 进程 分片(在 IP 协议没有设置 DF 标志位时),以适应网卡的 MTU。需要知道的是,MTU 限定的仅指 IP 层 向下传递数据的最大长度,这并不包含以太网帧头和帧尾长度在内。
说完了 MTU ,接下来说说本篇的主角 Path MTU Discovery(PMTUD) 。数据在传输过程中,可能经过多个各种类型的网络数据的传输介质,如交换机、路由器等,下图给出一个简单的示例:

从上图中看到,数据的源头和目的设备的 MTU 均为 1500,而中间的路由设备的 MTU 为 576 ,也就是说,数据经过的各种传输媒介,它们各自可能拥有不同的 MTU 值,这就意味着数据帧经过不同 MTU 的设备时,要进行分片(从 更大 MTU 设备 到 更小 MTU 的设备)、组包(从更小 MTU 设备 到 更大 MTU 设备)。这样的不停分片、组包,需要开辟额外的缓存进行数据排队,通常来说对于网络传输效率是不利的(尤其是交换机这类设备),更不要说丢包等情形的处理。为了适应这种不同设备具有 MTU 的情形,引入了 Path MTU Discovery(PMTUD) 协议,协议 RFC 编号为 RFC1191 ,该协议用来发现网络数据传输整个路径中的最小 MTU,然后数据传输路径中所有设备使用这个最小 MTU 来传输数据,因此所有的 IP 数据 都可以不用进行分片,以期达到更大的传输效率。这个 最小 MTU 有个名目,叫做 PMTU(Path MTU) 。
2.1 PMTUD 发现最小 MTU 的过程
上面说了,Path MTU Discovery(PMTUD) 用来发现传输路径中的 最小 MTU ,那是如何发现的呢?过程也不复杂,就是在传输 IP 数据 的时候数据发送端设置 DF(Don't Fragment) 标记,如下图:

然后数据接收端如果发现接收的 IP 数据的长度超过自己的 MTU ,则回复发送端一个 Type=3,Code=4 的 ICMP 消息,表示 Destination Unreachable Message, fragmentation needed and DF set ,告知发送端数据太长,需要进行分片,同时带上接收端的自己 MTU;发送端接收到 ICMP 消息后,缓存接收端会送的 MTU 值,然后调整数据重新进行发送。更多关于 ICMP(Internet Control Message Protocol) 的细节可参考 RFC792 。
应该了解的是,Path MTU Discovery(PMTUD) 协议只适用于 TCP 和 UDP 协议。
3. Linux 的 PMTUD 简析
首先,本文分析以 Linux 4.14 内核代码为背景进行分析。Linux 下默认开启 Path MTU Discovery(PMTUD) 功能。另外,可以通过文件节点 /proc/sys/net/ipv4/ip_no_pmtu_disc 来开启或关闭 Path MTU Discovery(PMTUD) :向文件写 0 开启 PMTUD,写非零值(1-3)关闭 PMTUD 。
本文只讨论 IPv4 协议栈下 Path MTU Discovery(PMTUD) 开启的情形,对其它情形感兴趣的读者可自行阅读源码进行分析。
3.1 创建 socket 时初始化 PMTUD 模式
socket()...inet_create() // net/ipv4/af_inet.c...if (net->ipv4.sysctl_ip_no_pmtu_disc)...else /* 开启 PMTUD 的情形 */inet->pmtudisc = IP_PMTUDISC_WANT;...
当然,内核也提供了接口修改 socket 的 PMTUD 的配置。如:
on = IP_PMTUDISC_PROBE;
setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &on, sizeof(on));
3.2 数据发送时 PMTUD 相关处理
要发送的数据,当前可能有两种情形:
情形1:当前正从源头主机往外发送
情形2:当前数据正经过某中间设备(譬如路由器)往外转发
下面分别对这两种情形下,和 PMTUD 协议相关的处理部分。
3.2.1 源头主机发送过程中 PMTU 处理
// net/ipv4/ip_output.cip_queue_xmit()...
packet_routed:if (ip_dont_fragment(sk, &rt->dst) && !skb->ignore_df) /* 不允许对 IP 数据分片 */iph->frag_off = htons(IP_DF); /* 标记 DF */else......res = ip_local_out(net, sk, skb); /* 将数据包传递给网络设备 */...
接收端设备收到数据后,如果发现大于自己的 MTU ,且设置了 DF(Don't Fragment) 标记,则会送 Type=3,Code=4 的 ICMP 消息 :
// net/ipv4/ip_output.cip_finish_output().../* 包长度大于本机 MTU, 进行分片处理 */if (skb->len > mtu || (IPCB(skb)->flags & IPSKB_FRAG_PMTU))return ip_fragment(net, sk, skb, mtu, ip_finish_output2);struct iphdr *iph = ip_hdr(skb);if ((iph->frag_off & htons(IP_DF)) == 0) /* 允许 IP 数据 分片 */.../* 不允许 IP 数据 分片(设置了 IP_DF 标记) */if (unlikely(!skb->ignore_df ||(IPCB(skb)->frag_max_size &&IPCB(skb)->frag_max_size > mtu)/*IP 分片 的 长度大于 MTU*/)) {IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS);/** IP 分片长度 超过 MTU && 禁止分片, * 则给本地 socket 发送 ICMP 的 {ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED} 包,* 告知其包将不被发送 (IP 数据 由本地 socket 往外发送,发不出去就回送* 给 socket 回 ICMP 的 {ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED} 包 告知 socket).*/icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));kfree_skb(skb);return -EMSGSIZE;}...
发送端收到 Type=3,Code=4 的 ICMP 消息 后更新缓存 PMTU:
// net/ipv4/icmp.c
static bool icmp_unreach(struct sk_buff *skb)
{const struct iphdr *iph;struct icmphdr *icmph;...icmph = icmp_hdr(skb);iph = (const struct iphdr *)skb->data;...switch (icmph->type) {case ICMP_DEST_UNREACH:switch (icmph->code & 15) {...case ICMP_FRAG_NEEDED:switch (net->ipv4.sysctl_ip_no_pmtu_disc) {...case 0:info = ntohs(icmph->un.frag.mtu); /* 解析 接收端回传 的 MTU */}}}...icmp_socket_deliver(skb, info);...ipprot = rcu_dereference(inet_protos[protocol]);if (ipprot && ipprot->err_handler)ipprot->err_handler(skb, info); /* tcp_v4_err() */tcp_v4_err()...
}// net/ipv4/tcp_ipv4.c
void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
{...const int type = icmp_hdr(icmp_skb)->type;const int code = icmp_hdr(icmp_skb)->code;...switch (type) {...case ICMP_DEST_UNREACH:...if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */...tp->mtu_info = info;if (!sock_owned_by_user(sk)) {tcp_v4_mtu_reduced(sk);} else {...}goto out;}...}...
out:...
}void tcp_v4_mtu_reduced(struct sock *sk)
{...u32 mtu;...mtu = tcp_sk(sk)->mtu_info; /* 接收端 回送 的 MTU */dst = inet_csk_update_pmtu(sk, mtu);...mtu = dst_mtu(dst);if (inet->pmtudisc != IP_PMTUDISC_DONT &&ip_sk_accept_pmtu(sk) &&inet_csk(sk)->icsk_pmtu_cookie > mtu) {tcp_sync_mss(sk, mtu); /* MSS 同步 *//* Resend the TCP packet because it's* clear that the old packet has been* dropped. This is the new "fast" path mtu* discovery.*/tcp_simple_retransmit(sk); /* 数据重传 */}
}
3.2.2 转发过程中 PMTUD 处理
// net/ipv4/ip_forward.cint ip_forward(struct sk_buff *skb)
{...IPCB(skb)->flags |= IPSKB_FORWARDED;mtu = ip_dst_mtu_maybe_forward(&rt->dst, true);if (ip_exceeds_mtu(skb, mtu)) { /* 转发的 @skb 的 数据长度 超过 MTU */IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS);/* * 当前 @skb 正经过 【交换机】 或 【路由器 上】 进行 转发, 当* 【 @skb 的 数据长度 超过 MTU 】 && 【 数据源头设定不允许分片(DF=1) 】 * 时, 给数据发送源头回送 ICMP 包 {ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED}* 数据将被丢弃.*/icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));goto drop;}
}
数据发送源收到 Type=3,Code=4 的 ICMP 消息 后的处理和 3.2.1 处理一样。
4. PMTUD 观察
ifconfig 等工具可看到网卡配置的 MTU:
$ ifconfig ens33
ens33 Link encap:Ethernet HWaddr 00:0c:29:4f:b1:e7 inet addr:192.168.0.9 Bcast:192.168.0.255 Mask:255.255.255.0inet6 addr: fe80::bbc7:b835:be2a:a578/64 Scope:LinkUP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1RX packets:2077 errors:0 dropped:0 overruns:0 frame:0TX packets:775 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000 RX bytes:1684142 (1.6 MB) TX bytes:74056 (74.0 KB)
用 ping 发送超过 MTU 的数据包,且禁止 IP 分片:
$ ping www.baidu.com -s 2000 -M do
PING www.baidu.com (183.2.172.185) 2000(2028) bytes of data.
ping: local error: Message too long, mtu=1500
我们可以通过 tracepath 工具来跟踪数据发送超 MTU 时接收设备回送的 ICMP 包:
$ tracepath www.baidu.com1?: [LOCALHOST] pmtu 15001: 192.168.0.1 43.888ms 1: 192.168.0.1 2.902ms 2: 192.168.1.1 37.109ms 3: 192.168.1.1 117.816ms pmtu 14923: 100.64.0.1 33.586ms 4: 61.146.242.189 33.665ms 5: 177.107.38.59.broad.fs.gd.dynamic.163data.com.cn 39.025ms 6: 113.96.5.38 54.439ms 7: no reply8: 121.14.67.174 64.413ms 9: 182.61.216.71 39.233ms
用 tcpdump 工具抓回送的 ICMP 包:
$ sudo tcpdump icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
......
16:17:26.350958 IP 192.168.1.1 > 192.168.0.9: ICMP time exceeded in-transit, length 556
16:17:26.421870 IP 192.168.1.1 > 192.168.0.9: ICMP 183.2.172.185 unreachable - need to frag (mtu 1492), length 556
再来用 WireShark 的观察一下抓到的数据包:

5. 参考链接
[1] https://packetlife.net/blog/2008/aug/18/path-mtu-discovery/#:~:text=RFC%201191%20defines%20path%20MTU%20discovery%2C%20a%20simple,of%20the%20ICMP%20Destination%20Unreachable%20message%2C%20Fragmentation%20Needed.
[2] https://www.rfc-editor.org/rfc/rfc1191
[3] https://datatracker.ietf.org/doc/html/rfc792
相关文章:
Linux 网络:PMTUD 简介
文章目录 1. 前言2. Path MTU Discovery(PMTUD) 协议2.1 PMTUD 发现最小 MTU 的过程 3. Linux 的 PMTUD 简析3.1 创建 socket 时初始化 PMTUD 模式3.2 数据发送时 PMTUD 相关处理3.2.1 源头主机发送过程中 PMTU 处理3.2.2 转发过程中 PMTUD 处理 4. PMTUD 观察5. 参考链接 1. 前…...
BatchNormalization:解决神经网络中的内部协变量偏移问题
ICML2015 截至目前51172引 论文链接 代码连接(planing) 文章提出的问题 减少神经网络隐藏层中的”内部协变量偏移”问题。 在机器学习领域存在“协变量偏移”问题,问题的前提是我们划分数据集的时候,训练集和测试集往往假设是独立同分布(i.i.d)的,这种独立同分布更有利于…...
DAC实验(DAC 输出三角波实验)(DAC 输出正弦波实验)
DAC 输出三角波实验 本实验我们来学习使用如何让 DAC 输出三角波,DAC 初始化部分还是用 DAC 输出实验 的,所以做本实验的前提是先学习 DAC 输出实验。 使用 DAC 输出三角波,通过 KEY0/KEY1 两个按键,控制 DAC1 的通道 1 输出两种…...
许多网友可能还不知道,升级到Windows 11其实没那么复杂,只要符合几个条件可以了
如果你的Windows 10电脑可以升级Windows 11,现在怎么办?有几种方法可以免费安装新的操作系统。以下是你的选择。 如果你想升级到Windows 11,你可以随时购买一台已经安装了操作系统的新电脑。然而,如果你目前的Windows 10 PC满足所有必要的升级要求,那么在Windows 11免费的…...
ubuntu下载conda
系统:Ubuntu18.04 (1)下载安装包 wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2021.11-Linux-x86_64.sh 报错错误 403:Forbidden 解决方法 wget -U NoSuchBrowser/1.0 https://mirrors.tuna.tsingh…...
重磅 | 进一步夯实生态建设,朗思科技与阿里龙蜥完成兼容性认证
近日,北京朗思智能科技有限公司(以下简称“朗思科技”)自主研发的数字员工产品与OpenAnolis龙蜥社区龙蜥操作系统(Anolis OS)8完成兼容性认证。测试结果显示,双方产品相互兼容,功能正常…...
Qt给控件添加图片
双击qrc文件,选择下面的addFiles,将图片添加进来,然后选中图片右键Select All 设置控件字符: ui.btnSet->setText(""); 设置资源: ui.btnSet->setStyleSheet("QPushButton{background-image:…...
3.6-Dockerfile语法梳理及最佳实践
WORKDIR是设置当前docker的工作目录 ADD 和 COPY 为了将本地的一些文件添加到docker image里面,ADD 和 COPY的作用特别像,但是ADD 和 COPY还有一些区别,ADD不仅可以添加本地文件到docker里面,还可以将文件在添加到docker image里面…...
springboot集成nacos并实现自动刷新
目录 1.说明 2.示例 3.自动刷新的注意点 1.说明 springboot项目中存在好多配置文件,比如配置数据信息,redis信息等等,配置文件可以直接放在代码,也可以放在像nacos这样的组件中,实现动态的管理,修改配置…...
java面试八股文2023完整版详解110题附带答案
以下是一份Java面试八股文2023,涵盖了Java编程语言的核心概念和常用技术,帮助你更好地准备面试。 1. Java语言有哪些特点? Java语言是一种面向对象的编程语言,具有简单、面向对象、分布式、多线程、动态等优点。它是一种跨平台的…...
微服务实战系列之Token
前言 什么是“Token”? 它是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便返回给客户端;以后客户端只携带此Token请求数据即可。 简言之,Token其实就是用户身…...
DRF纯净版项目搭建和配置
一、安装模块和项目 1.安装模块 pip install django pip install djangorestframework pip install django-redis # 按需安装 2.开启项目和api (venv) PS D:\pythonProject\env_api> django-admin startproject drf . (venv) PS D:\pythonProject\env_api> python ma…...
AUTODL云服务器使用大致步骤(适合本人版)
(一)在官网上创建一个服务器 (二)远程连接指令: 改为: (三)连接后,可在中进行代码运行 输入一些指令 python .........
无需云盘,不限流量实现Zotero跨平台同步:内网穿透+私有WebDAV服务器
🔥博客主页: 小羊失眠啦. 🎥系列专栏:《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞👍收藏⭐评论✍️ 无需云盘,不限流量实现Zotero跨平台同步:内网穿透私有WebDAV服务器 文章目…...
简朴博客系统测试报告
文章目录 一. 项目简介二. 测试概要三. 测试环境四. 测试执行概况及功能测试1. 手工测试1.1 手动测试用例编写1.2 执行的部分测试用例 2. 自动化测试Selenium2.1 编写测试用例2.2 自动化测试代码 3. 测试结果 五. 发现的问题 一. 项目简介 简朴博客系统是采用前后端分离的方式…...
Qt遇到常见问题记录
1.Qt版本选择 Qt4.8.7是Qt4的终结版本,是Qt4系列版本中最稳定最经典的 (很多嵌入式板子还是用Qt4.8),其实该版本是和Qt5.5差不多时间发布的。 参考链接 Qt 5.5 Released Qt5.6.3最最后支持xp系统的长期支持版本,Q…...
pm2在Windows环境中的使用
pm2 进程管理工具可以Windows操作系统上运行,当一台Windows电脑上需要运行多个进程时,或者运维时需要运行多个进程以提供服务时。可以使用pm2,而不再是使用脚本。 1. 使用PM2管理进程 1.1. 启动PM2项目 1.1.1. 直接启动项目 参数说明&…...
使用百度翻译API或腾讯翻译API做一个小翻译工具
前言 书到用时方恨少,只能临时抱佛脚。英文pdf看不懂,压根看不懂。正好有百度翻译API和腾讯翻译API,就利用两个API自己写一个简单的翻译工具,充分利用资源,用的也放心。 前期准备 关键肯定是两大厂的翻译API&#x…...
Flutter笔记:桌面应用 窗口定制库 bitsdojo_window
Flutter笔记 桌面应用窗口管理库 bitsdojo_window 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址:https://blog.csdn.net/qq_28550263/article/details/13446…...
iOS_折叠展开 FoldTextView
1. 显示效果 Test1:直接使用: Test2:在 cell 里使用: 2. 使用 2.1 直接使用 // 1.1 init view private lazy var mooFoldTextView: MOOFoldTextView {let view MOOFoldTextView(frame: .zero)view.backgroundColor .cyanvie…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...
