MTU 怎么设置:用 ping 测出合适值,再在 Linux、Windows 和交换机上修改
MTU 怎么设置分两步:先用禁止分片的 ping 测出这条路径能通过的最大包,再把发包一端的网卡 MTU 改成这个值。普通以太网服务器保持 1500 不用动,需要改的是 PPPoE 拨号、GRE/VXLAN/WireGuard 隧道和存储网巨帧;Linux 用 ip link 临时修改、写进网络配置才永久生效,Windows 用 netsh 一条命令改完并保存。
MTU 怎么设置,第一步是确定“设成多少”。这个数不靠经验值,而是测出来的:在 Windows 上用 ping -f -l 载荷 目标、在 Linux 上用 ping -M do -s 载荷 目标 发送禁止分片的包,从 1472 开始往下减,能收到回复的最大载荷加上 28 字节(IPv4 首部 20 + ICMP 首部 8),就是这条路径的 MTU。第二步是在发包的那一端修改网卡:Linux 用 ip link set dev eth0 mtu 1450 立即生效、重启后失效,要永久生效得写进 NetworkManager、netplan 或 ifcfg 配置;Windows 用 netsh interface ipv4 set subinterface 一条命令修改并保存。交换机一般不动 IP 层的 MTU,而是放大端口允许通过的最大帧长,也就是开巨帧。下面按“定值、测试、修改、验证”的顺序给出每一步的命令。
MTU 设置多少合适:先看是什么场景
绝大多数情况下的答案是:不用改,保持 1500。服务器、交换机和宽带的以太网接口默认就是 1500,公网上绝大多数链路也是 1500,单方面改大没有意义,改小只会让每个包多一点首部开销。真正需要动 MTU 的,是包外面又套了一层封装,或者想在内网用巨帧的场景:
| 场景 | 在哪台设备、哪个接口上改 | 常用值 | 备注 |
|---|---|---|---|
| 普通服务器的公网口、内网口 | 不改 | 1500 | 默认值 |
| PPPoE 拨号 | 路由器或光猫的拨号(WAN)接口 | 1492 | 内网电脑保持 1500,由路由器做 MSS 钳制 |
| GRE 隧道 | 隧道接口,如 gre1 | 1476 | 物理口不动 |
| WireGuard | wg0 接口 | 出口网卡 MTU 减 80,出口为 1500 时是 1420 | wg-quick 默认就按这个规则计算 |
| VXLAN | 虚拟机、容器的网卡 | 1450 | 也可以把承载网调到 1550 以上,内层保持 1500 |
| 存储网、虚拟化迁移网 | 该网段所有主机网卡,加上沿途交换机端口 | 主机 9000,交换机帧长 9216 | 只在封闭的二层网段里用 |
| 云服务器、虚拟机 | 一般不改 | 平台下发的值 | 不同平台默认值不同,以平台文档为准,不要擅自改回 1500 |
网上常见“把 MTU 从 1500 改成 1497 能提速、降低游戏延迟”的说法,值得单独说一句。1497 不对应任何一种常见的封装:PPPoE 少的是 8 字节(1492),GRE 少的是 24 字节(1476)。从 1500 改到 1497,每个满长度的包只少装 3 字节数据,带宽利用率的变化不到千分之三,延迟的变化也小到无法察觉。如果改完以后某些网页反而能打开了,说明这条路径本来就存在 MTU 问题,正确的做法是用下一节的方法测出实际值,而不是猜一个数字。
用 ping 测出合适的 MTU:Windows 与 Linux 步骤
原理是给 ping 包打上“禁止分片”(DF)标志。包比路径上某一段的 MTU 大时,路由器不会把它切小转发,而是丢弃并回一条“需要分片”的 ICMP 消息。逐步减小载荷,第一个能正常回复的大小就是上限。
ping 命令里的大小参数指的是 ICMP 数据部分,不含首部,换算关系如下:
| 协议 | 线路上的 IP 包长度 | MTU 1500 对应的载荷 | MTU 9000 对应的载荷 |
|---|---|---|---|
| IPv4 | 载荷 + 8(ICMP 首部)+ 20(IPv4 首部) | 1472 | 8972 |
| IPv6 | 载荷 + 8(ICMPv6 首部)+ 40(IPv6 首部) | 1452 | 8952 |
Windows:ping -f -l
- 打开命令提示符或 PowerShell,普通权限即可。
- 先发 1472 字节的载荷:
ping -f -l 1472 -n 2 203.0.113.10
- 读结果:
来自 203.0.113.10 的回复: 字节=1472 时间=35ms TTL=52:1500 能完整通过,不需要调整。需要拆分数据包但是设置 DF。:包太大,被本机或沿途设备拒绝,继续减小载荷。请求超时。:可能是目标不回 ping,也可能是沿途设备丢了大包却没有发回通知。先用ping -l 64 203.0.113.10确认小包能通,再继续减小载荷。
- 先以 10 为步长往下减(1462、1452……),找到能通的区间后再以 1 为步长细找。
- 能通过的最大载荷加 28 就是路径 MTU。例如 1422 能通、1423 不通,MTU 就是 1450。
逐个手工试比较慢,可以交给 PowerShell 循环:
$dst = "203.0.113.10"
foreach ($size in 1472..1200) {
$out = ping -n 1 -w 1000 -f -l $size $dst
if ($out -match "TTL=") { "最大载荷 $size 字节,路径 MTU = $($size + 28)"; break }
}
脚本用回复里的 TTL= 判断是否通过,中文和英文系统都适用。Windows 的 -f 只对 IPv4 有效,测 IPv6 的路径 MTU 建议到 Linux 上用 ping -6 -M do -s 1452 目标。
Linux:ping -M do -s
ping -M do -s 1472 -c 3 203.0.113.10
-M do 表示设置 DF、本机也不分片,-s 指定载荷大小。可能看到三种输出:
| 输出 | 含义 |
|---|---|
1480 bytes from 203.0.113.10: icmp_seq=1 ttl=52 time=35.2 ms |
通过;1480 是 ICMP 部分,即 1472 + 8 |
ping: local error: message too long, mtu=1500 |
本机网卡的 MTU,或者内核已经记下的这条路径的 MTU 比这个包小,包没有发出去 |
From 192.0.2.9 icmp_seq=1 Frag needed and DF set (mtu = 1476) |
沿途的 192.0.2.9 放不下这个包,并告诉你它的 MTU 是 1476 |
第三种最省事:路由器已经把答案告诉你了,1476 − 28 = 1448,再用 -s 1448 验证一次即可。什么回应都没有时,用二分法让脚本自己找:
#!/bin/bash
# 用法:bash pmtu.sh 目标地址
dst=$1; lo=1200; hi=1472
ping -M do -s $lo -c 2 -W 1 -q "$dst" >/dev/null 2>&1 || { echo "1200 字节都不通,先检查连通性"; exit 1; }
while [ $lo -lt $hi ]; do
mid=$(( (lo + hi + 1) / 2 ))
if ping -M do -s $mid -c 2 -W 1 -q "$dst" >/dev/null 2>&1; then lo=$mid; else hi=$((mid - 1)); fi
done
echo "最大载荷 $lo 字节,路径 MTU = $((lo + 28))"
测试时注意三点:
- 两个方向都要测。去程和回程可能走不同的路由,MTU 也可能不同,在两端各跑一次。
- 目标要选对。测隧道就 ping 隧道对端的内层地址,测存储网就 ping 同网段的另一台主机,测公网就选业务真正要访问的对端。
- 测出来比 1500 小,不一定要改本机。如果卡住的是公网上别人的一段链路,改服务器网卡会影响它的全部流量;能在隧道网关上做 MSS 钳制,或者让沿途放行 ICMP“需要分片”消息的,优先这样处理。
Linux 修改 MTU:ip link 临时生效,写进配置才永久
先看当前值:
ip link show dev eth0 # 输出中的 mtu 1500
临时修改,立即生效,重启或网络服务重新加载配置后恢复原值:
ip link set dev eth0 mtu 1450
# 没有 ip 命令的老系统:ifconfig eth0 mtu 1450
永久修改要按系统使用的网络管理方式来写,改错地方就会出现“重启后又变回 1500”:
| 系统 | 配置位置 | 写法 | 让它生效 |
|---|---|---|---|
| RHEL、Rocky、AlmaLinux 8/9 等(NetworkManager) | nmcli 连接配置 | nmcli connection modify eth0 802-3-ethernet.mtu 1450 |
nmcli connection up eth0 |
| Ubuntu 18.04 及以后(netplan) | /etc/netplan/ 下的 yaml 文件,对应网卡下 | mtu: 1450 |
netplan try,确认无误后回车 |
| CentOS 7(network-scripts) | /etc/sysconfig/network-scripts/ifcfg-eth0 | MTU=1450 |
systemctl restart network |
| Debian(ifupdown) | /etc/network/interfaces 对应的 iface 段(static 方式) | mtu 1450 |
ifdown eth0 && ifup eth0 |
nmcli 命令里的 eth0 是连接名,不一定等于网卡名,先用 nmcli -g NAME,DEVICE connection show 查出来;部分系统上连接名是 System eth0 这类带空格的名字,命令里要加引号。netplan 的写法示例:
network:
version: 2
ethernets:
eth0:
addresses: [203.0.113.10/24]
mtu: 1450
netplan try 会先应用新配置,120 秒内不按回车确认就自动回滚,远程修改时比 netplan apply 稳妥。
服务器上有 bond、VLAN 子接口或网桥时,要从下往上改,规则是上层不能比下层大:
- 物理网卡 eth0、eth1 设为 9000;
- bond0 设为 9000,bond 会把 MTU 同步给成员网卡;
- VLAN 子接口 bond0.100 设为 9000,它不能超过 bond0;
- 网桥 br100 设为 9000,Linux 网桥默认取所连端口里最小的 MTU,一个端口没改,整个网桥就卡在 1500。
只改了最上层的网桥,或者只改了物理口,巨帧都会在某一层被卡住。
Windows 修改 MTU:netsh 一条命令
Windows 网卡属性的图形界面里没有 IP 层 MTU 这一项,“MTU 值在哪里修改”的答案是命令行。以管理员身份打开 PowerShell(netsh 在 PowerShell 里同样可用):
# 查看各接口的名称和当前 MTU
netsh interface ipv4 show subinterfaces
# 修改并永久保存;改成 store=active 则只在本次开机期间有效
netsh interface ipv4 set subinterface "以太网" mtu=1450 store=persistent
# IPv6 要单独设置
netsh interface ipv6 set subinterface "以太网" mtu=1450 store=persistent
接口名以第一条命令的输出为准,英文系统一般是 Ethernet。也可以用 PowerShell 自带的命令:
Get-NetIPInterface | Select-Object InterfaceAlias, AddressFamily, NlMtu
Set-NetIPInterface -InterfaceAlias "以太网" -AddressFamily IPv4 -NlMtuBytes 1450
要用 9000 巨帧时,只改 netsh 不够:IP 层的 MTU 不能超过网卡驱动允许的帧长,要先在网卡的高级属性里打开“巨型帧”(Jumbo Packet,各驱动的叫法不同),再回头确认 MTU:
Get-NetAdapterAdvancedProperty -Name "以太网" -RegistryKeyword "*JumboPacket"
Set-NetAdapterAdvancedProperty -Name "以太网" -RegistryKeyword "*JumboPacket" -RegistryValue 9014
9014 是包含 14 字节以太网头的帧长,对应 IP 层的 9000;可选的数值由网卡驱动决定,各厂商不同,可以在设备管理器里该网卡属性的“高级”选项卡中查看。修改高级属性会让网卡重新初始化,网络断开几秒。
交换机上怎么设置 MTU 与巨帧
交换机上有两种“MTU”,配置时不要混在一起:
- 二层端口的最大帧长,也就是巨帧:决定多大的以太网帧能从这个端口进出。主机开了 9000,沿途每个端口都要放大。
- 三层接口的 IP MTU:VLANIF、路由口发送 IP 包的上限,影响交换机自己发出的包和需要它分片的包,一般保持 1500。
主流厂商的写法如下,取值范围和默认值随型号、版本不同,以设备文档为准:
| 厂商 | 二层巨帧 | 三层接口 IP MTU | 查看 |
|---|---|---|---|
| 华为 S 系列 | 接口视图 jumboframe enable 9216 |
VLANIF 接口视图 mtu 1500 |
display interface GigabitEthernet0/0/1,看 Maximum Frame Length |
| H3C Comware V7 | 接口视图 jumboframe enable 9216 |
VLAN 接口视图 mtu 1500 |
display interface GigabitEthernet1/0/1 |
| 思科 Catalyst 9000 | 全局 system mtu 9198 |
三层接口下 ip mtu 1500 |
show system mtu |
| 思科 Nexus | 接口下 mtu 9216,部分型号要通过 network-qos 策略设置 |
三层接口下 mtu 1500 |
show interface ethernet1/1 |
华为交换机上把接存储服务器的一组端口放开到 9216 字节:
system-view
port-group group-member GigabitEthernet0/0/1 to GigabitEthernet0/0/24
jumboframe enable 9216
交换机设 9216、主机设 9000 是有意留出余量:交换机的数值通常按帧长计算,要装下 9000 字节的 IP 包,还得加上以太网头和 VLAN 标签。Catalyst 9000 的 system mtu 是全局设置,作用于所有接口;部分老型号(如 Catalyst 2960、3750 系列)的千兆口用 system mtu jumbo 9000,改完要重启交换机才生效,要放在维护窗口里做。上联运营商的端口和公网接口保持 1500,不要跟着放大。
改完怎么验证,改错了怎么回退
改完按下面三项逐一确认:
- 用新值反向验证。MTU 改为 1450,就用
ping -M do -s 1422测到对端;开了巨帧,就在同网段每一对需要通信的主机之间测ping -M do -s 8972。只测一对不够,漏改了一台主机或一个交换机端口,那一对就不通。 - 跑一次大包业务。
scp一个几百 MB 的文件,或curl一个大页面,看能否顺利传完、速率是否正常。 - 看错误计数。主机上
ip -s link show dev eth0的 errors、dropped;交换机端口的超长帧计数(思科show interfaces里的 giants,其他厂商的字段名以设备为准)。计数在涨,说明有超过端口允许值的帧被丢弃。
远程修改服务器 MTU 有一个风险:值改错了,SSH 会话本身可能卡住,敲命令正常,一输出大段内容就挂起,想改回去也改不了。动手前给自己留一条退路:
# 先挂一个 5 分钟后自动恢复 1500 的任务,用 nohup 让它脱离当前 SSH 会话
nohup sh -c 'sleep 300; ip link set dev eth0 mtu 1500' >/dev/null 2>&1 &
echo $! > /tmp/mtu-rollback.pid
ip link set dev eth0 mtu 9000
# 验证无误后,取消自动恢复
kill "$(cat /tmp/mtu-rollback.pid)"
不要用普通的 ( ... ) & 后台任务代替 nohup:SSH 连接一旦断开,shell 会把挂断信号转发给自己的后台任务,回退任务恰好在最需要它的时候被一起结束。
另外,部分网卡驱动修改 MTU 时会重置链路,网络中断几秒,做了 bond 的服务器还可能触发一次主备切换。生产服务器的 MTU 调整,和交换机巨帧一样放在维护窗口里做。
在管理系统里怎么落地
MTU 改错最棘手的情况,是服务器自己的网络出了问题、远程登录不上。Toplink DCIM 的 IPMI 远程管理通过 BMC 通道打开 VNC 控制台,不经过服务器的业务网卡,MTU 改坏了也能从控制台登录进去改回来。巨帧要求沿途的交换机端口一起修改,交换机管理的服务器列表直接列出每台服务器接在哪台交换机的哪个端口、端口速率和 VLAN,一个存储网段涉及哪些端口,不用再到现场翻线核对;需要执行 jumboframe enable 或检查帧长时,可以在浏览器里打开交换机的 SSH 终端,会话全程录像并记录命令日志,哪个端口在什么时候被谁改过,事后都查得到。
常见问题
修改 MTU 需要重启服务器吗?
不需要。Linux 的 ip link 和 Windows 的 netsh 改完立即生效,nmcli 改完执行一次 nmcli connection up 即可,只是部分网卡驱动会重置链路,网络断开几秒。需要重启的可能是交换机:部分老型号(如思科 Catalyst 2960、3750 系列)修改 system mtu jumbo 后要重启才生效,以设备文档为准。
Docker 容器的 MTU 怎么设置?
默认网桥上的容器,在 /etc/docker/daemon.json 里把 mtu 键设为需要的值(如 1450),重启 Docker 后对新建的容器生效;自定义网络在创建时指定,例如 docker network create -o com.docker.network.driver.mtu=1450 mynet。宿主机出口在 VXLAN 或隧道里、MTU 小于 1500 时,容器的 MTU 不能超过宿主机出口网卡的值。
MTU 最小能设成多少?
IPv4 只要求链路至少能传 68 字节,但实际不要低于 1280:IPv6 规定链路 MTU 不得小于 1280 字节(RFC 8200),Linux 上把网卡 MTU 设到 1280 以下,这块网卡上的 IPv6 会被停用。测出来的路径 MTU 低于 1280 时,先复查测试目标和方法,再查链路上是否叠了多层封装。