当前位置: 首页 > news >正文

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,而中间的路由设备的 MTU576 ,也就是说,数据经过的各种传输媒介,它们各自可能拥有不同的 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) 协议只适用于 TCPUDP 协议。

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完成兼容性认证。测试结果显示,双方产品相互兼容,功能正常&#xf…...

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…...

Allegro等长设置翻车实录:拓扑模板法的3个坑与手工PinPair的救赎

Allegro等长设计避坑指南:从拓扑模板到精准PinPair的实战演进在高速PCB设计中,等长匹配如同精密钟表里的齿轮啮合,差之毫厘便可能导致整个系统时序崩塌。当设计从简单的点对点结构升级到多负载复杂拓扑时,Allegro用户常陷入两种典…...

从分立逻辑到单片机:基于ATmega8的MIDI通道分析仪设计与实现

1. 项目概述:从分立逻辑到单片机的MIDI通道分析仪进化史二十年前,当我在《Elektor》杂志上发表第一版MIDI通道分析仪时,整个数字音乐世界还处于一个相当“硬核”的阶段。那个版本的设计,用今天的话来说,简直就是一场“…...

Sora 2 MOV导出画质崩坏真相:HDR10元数据丢失、BT.2020色域截断、帧率标志位误写——3大隐性缺陷紧急修复方案

更多请点击: https://intelliparadigm.com 第一章:Sora 2 MOV导出画质崩坏的系统性认知 Sora 2 在生成高保真视频后,导出为 MOV 格式时频繁出现色度抽样失真、动态范围压缩、帧间伪影加剧等现象,其本质并非单一环节失效&#xff…...

CSharpVerbalExpressions常见问题解答:解决开发者遇到的10个典型挑战

CSharpVerbalExpressions常见问题解答:解决开发者遇到的10个典型挑战 【免费下载链接】CSharpVerbalExpressions 项目地址: https://gitcode.com/gh_mirrors/cs/CSharpVerbalExpressions CSharpVerbalExpressions是一个强大的C#库,它通过类自然语…...

航空发动机叶片三维扫描-诺斯顿

航空发动机叶片作为发动机的核心动力部件,其精度与性能直接决定发动机的推力、燃油效率及运行安全性,三维扫描技术作为航空制造领域的核心数字化手段,已广泛应用于叶片全生命周期的多个关键环节。其应用涵盖叶片研发设计阶段的逆向工程&#…...

告别手动预约:i茅台自动预约系统5分钟部署指南

告别手动预约:i茅台自动预约系统5分钟部署指南 【免费下载链接】campus-imaotai i茅台app自动预约,每日自动预约,支持docker一键部署(本项目不提供成品,使用的是已淘汰的算法) 项目地址: https://gitcode…...

通用物联网开发板设计:基于ESP8266的硬件集成与开发实践

1. 项目概述:为什么我们需要一块“通用”的物联网开发板?在捣鼓了几年物联网项目之后,我发现自己桌面上堆满了各种开发板:ESP8266、ESP32、Arduino Uno、STM32 Nucleo……每个项目都要重新连线、配置电源、焊接传感器接口&#xf…...

ComfyUI-Manager完全指南:掌握AI工作流管理的核心技术

ComfyUI-Manager完全指南:掌握AI工作流管理的核心技术 【免费下载链接】ComfyUI-Manager ComfyUI-Manager is an extension designed to enhance the usability of ComfyUI. It offers management functions to install, remove, disable, and enable various custo…...

Unity中实现深度遮挡:LingBot-Depth实战接入与优化

1. 这不是“加个插件就完事”的AR效果——为什么LingBot-Depth在Unity里值得专门写一篇实战教程你肯定见过那种AR应用:虚拟椅子摆在真实地板上,但当你绕到椅子后面,它依然完整显示,完全无视身后那堵真实的墙;或者一只3…...

观察Taotoken在多模型聚合调用下的路由与失败重试效果

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 观察Taotoken在多模型聚合调用下的路由与失败重试效果 在构建依赖大模型能力的应用时,服务的稳定性是开发者关注的核心…...