V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
raysonx
V2EX  ›  宽带症候群

开启 IPv6 后网速变得很慢?可能是 PMTU 黑洞的问题

  raysonx · 2021-09-05 22:23:38 +08:00 · 21099 次点击
这是一个创建于 925 天前的主题,其中的信息可能已经有所发展或是发生改变。

发现最近经常有人提到开启 IPv6 连接速度慢的问题。目前国内确实存在支持 IPv6 的服务器、CDN 节点不够多,IPv6 国际带宽比 IPv4 带宽小的问题,但也不至于会打开国内网站都卡。通常情况下遇到这个问题说明你到目标服务器的链路上存在 PMTU 黑洞。

关于 PMTU 黑洞

MTU (Maximum transmission unit) 是一条链路上可以通过的三层数据包的最大尺寸(包含 IP 包头)。以太网上默认的 MTU 是 1500 字节,但是你和目标服务器之间的路径上可能存在小于 MTU 1500 的链路。这条路径上最小的 MTU 值就是整条路径的 PMTU 值。路由器在转发包时,超过 MTU 大小的包会被分片( Fragmentation ),也就是一个大包会被分切为多个不超过 MTU 的小包进行传输,传输效率会下降。

终端设备在发包时,也可以设置 DF ( Don't Fragment )标记来告诉路由器不要分片。这时中间路由器会丢掉超过 MTU 的包,回复一条 ICMP Fragmentation Needed 消息。发送者收到这个包后,下次就会发小一点的包,这个过程叫做 PMTU Discovery 。现实中可以看到 HTTPS ( TLS )的流量大都是带 DF 标记的。

然而,互联网上有大量的中间设备为了所谓的“安全”或者没有正确配置,不回应 ICMP Fragmentation Needed 包,这使得访问某些网站时如果某个包的大小超过了 PMTU,会被无声地丢弃,直到 TCP 协议发现超时丢包进行重传,这非常缓慢。遇到这种情况,我们可以说你和目标服务器的路径上存在 PMTU 黑洞。

此外,IPv6 不支持分片,换句话说可以理解为 IPv6 下所有的包都是带 DF 标记的。中间路由器在遇到包尺寸大于 MTU 的情况时,应该回应 ICMPv6 Packet Too Big 消息。同样的,由于种种原因,某些中间设备可能会直接丢包而不回应 ICMPv6 Packet Too Big 消息,直到 TCP 协议发现超时丢包进行重传。。。

为什么 IPv4 没有这个问题

其实 IPv4 也有这个问题,我不只一次见网友说自己搭的软路由访问某些网站非常慢,而换回硬路由就正常。这是因为多数家用路由器默认对 IPv4 下的 TCP 开启了 MSS (maximum segment size) Clamping (使用 OpenWRT 软路由的朋友们可以在防火墙设置中找到 MSS Clamping 开关)。MSS Clamping 是针对 PMTU 黑洞的 Workaround,简单来说就是 TCP 握手时有个 MSS 字段决定单个 TCP 包的最大尺寸。路由器可以通过嗅探 TCP 握手包,把 MSS 值改小,使最终的三层 IP 包的尺寸( MSS+TCP 头大小+IP 头大小)不超过某个特定的值。

总结

现在国内 ISP 一般都是通过 PPPoE 虚拟拨号建立 WAN 口连接的。Ethernet 的默认 MTU 是 1500,但是 PPPoE 隧道有 8 个 bytes 的开销,所以 PPPoE 虚连接的 MTU 就是 1500-8=1492,减掉 IPv4 包头( 20 字节)和 TCP 包头( 20 字节),可以得知 IPv4 下需要把 MSS 设为 1452 以下。

IPv6 的包头是 40 字节,所以 IPv6 下需要把 MSS 设为 1432 以下。

这时问题来了,目前很多光猫、家用路由器对 IPv6 的优化很差,不支持对 IPv6 下的 TCP 包进行 MSS Clamping,这就导致访问 IPv6 网站时,若路径中存在 PMTU 黑洞,则打开很慢。

我前段时间帮朋友配置 IPv6 时发现了很多光猫、家用路由器的固件问题,使得国内使用 IPv6 的体验不太理想。我打算抽空专门开一个帖子去讨论这些问题,声讨那些垃圾厂家。目前来看,要想在国内比较理想地体验 IPv6,你需要把光猫改为桥接模式,并使用 OpenWRT 或者 VyOS 这类对 IPv6 支持较好的软路由。

第 1 条附言  ·  2021-09-06 00:04:28 +08:00

附:在基于 Linux 的路由器启用MSS Clamping的命令:

# 自动MSS,假设PPPOE虚接口是pppoe0
iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o pppoe0 -j TCPMSS --clamp-mss-to-pmtu
ip6tables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o pppoe0 -j TCPMSS --clamp-mss-to-pmtu

# 手动指定MSS,假设PPPOE虚接口是pppoe0
$ iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o pppoe0 -j TCPMSS --set-mss 1452
$ ip6tables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o pppoe0 -j TCPMSS --set-mss 1432
第 2 条附言  ·  2021-09-07 21:37:56 +08:00

感谢 @Danswerme 提供RouterOS里设置MSS的命令。其中pppoe-out1是wan口,1420是要MSS值,请根据需要修改。

/ipv6 firewall mangle add chain=forward out-interface=pppoe-out1 protocol=tcp tcp-flags=syn action=change-mss new-mss=1420
第 3 条附言  ·  2021-09-10 11:43:13 +08:00

感谢 @PublicDNS 分享 UBNT Edgerouter 系列的MSS设置方法:

set firewall options mss-clamp6 interface-type pppoe
set firewall options mss-clamp6 mss 1420
54 条回复    2023-09-01 16:01:38 +08:00
yov123456
    1
yov123456  
   2021-09-05 23:49:52 +08:00
赞,当时 erx 的时候也折腾了很久
vwxc
    2
vwxc  
   2021-09-06 00:38:45 +08:00 via Android
谢谢分享,有空试试看,之前都是直接关掉 v6 下发
icegaze
    3
icegaze  
   2021-09-06 00:54:48 +08:00 via Android
学习了,
openwrt 在防火墙里没有找到 MSS clamping 的设置,望楼主指点迷津。
icegaze
    4
icegaze  
   2021-09-06 00:58:34 +08:00 via Android   ❤️ 1
找到了,

在 网络--防火墙--区域 那里,可以打勾,设置上。

多谢多谢。
samondlee
    5
samondlee  
   2021-09-06 09:00:35 +08:00
az,华硕路由默认推荐的 1492 需不需要改成 1452
wszgrcy
    6
wszgrcy  
   2021-09-06 10:00:03 +08:00
感谢.原来是这样,我就是开 ipv6 后有些网站死慢的....
xiaooloong
    7
xiaooloong  
   2021-09-06 10:13:41 +08:00
pfsense 的 ipv6 遇到这个问题了。家里是联通的宽带,装机的时候直接让师傅改了桥接,这边联通又默认给了公网 ip 就一直没折腾 ipv6 。后来换了 openwrt 用了一下发现居然有 ipv6 。才知道 ipv6 是直接跑在 pppoe 里用 dhcpv6 client 获取的。开启之后 ipv6 测试网直接就说我 v6 的 mtu 有问题。往上查了一下说是因为 pfsense 计算 v6 的 mss 直接用了 v4 的参数导致的 bug 。虽然官方说已经在 2.5.1 修复但是我遇到问题的正式 2.5.1 。最后还是手动改了 mss 才这正常的。
raysonx
    8
raysonx  
OP
   2021-09-06 11:39:11 +08:00 via iPad
@xiaooloong pfSense 好多年没有用了,不知道现在情况怎么样,好像开发不怎么频繁的样子。我看国外很多老用户都转向了 OPNsense,你可以试试看。
phxsuns
    9
phxsuns  
   2021-09-06 13:02:29 +08:00
谢谢分享。
我是无奈才关了 IPv6 的,开了就是慢。看起来就是这个原因。
thtznet
    10
thtznet  
   2021-09-06 13:13:40 +08:00
现阶段用 IPv6 也没什么好处,业界既然不成熟,就不开了。
raysonx
    11
raysonx  
OP
   2021-09-06 13:53:38 +08:00
@thtznet 其实协议和技术本身都很成熟,IPv6 在设计之初也顺带解决了一些 IPv4 的设计缺陷(比如组播、广播风暴等),主流操作系统的支持也没问题,但小厂商的设备真的是一言难尽。
xhcnb
    12
xhcnb  
   2021-09-06 14:25:58 +08:00
谢谢分享! 之前没有考虑到这一层
这就去把 ipv6 再打开试试
Unclev21x
    13
Unclev21x  
   2021-09-06 15:49:08 +08:00
贴主求教。
光猫桥接,路由器刷了梅林固件,路由器开启 IPv6,ipv6-test 测试结果正常,各设备都能拿到 IPv6 的地址。手机上用 Safari 看一些 IPTV 的时候,浏览器地址栏的域名自动切换到了 IPv6 地址。
问题(举例说明):
有个在线广播电台合集的网站(必须科学上网才能听),不管是通过浏览器,还是官方 App 去收听节目的时候,如果开启了 IPv6,就听不了。如果关掉 IPv6,马上就可以收听。

这个问题的原因我现在不知道是什么,可能的原因如下:
1. 代理问题。路由器上开启了代理,但是 IPv6 访问的时候没有走代理(如果是这样,怎么强制让 IPV6 的流量走代理?);
2. IPv6 问题。如果走了 IPv6,就是不能收听。
Unclev21x
    14
Unclev21x  
   2021-09-06 15:49:58 +08:00
@Unclev21x 好几个网站都遇到这样的情况了。似乎设备上的 IPv6 的地址默认就是公网地址了。
raysonx
    15
raysonx  
OP
   2021-09-06 16:16:09 +08:00
@Unclev21x 仅凭你的描述我也无法断定问题所在,但能肯定的是这个在线广播的域名解析到了一个你不能访问的 IPv6 。如果你的代理不支持 IPv6,你可能需要屏蔽这个域名的 AAAA 记录和 TYPE65 记录。
KnightNic
    16
KnightNic  
   2021-09-06 21:00:18 +08:00
我们这儿天翼网关要是改成桥接,千兆宽带就只剩 500 兆了,不知道什么原因。
raysonx
    17
raysonx  
OP
   2021-09-06 21:46:06 +08:00
@KnightNic 光猫的的问题。你的光猫可能是软桥接,无硬件加速,CPU 性能不足以支持千兆。
KnightNic
    18
KnightNic  
   2021-09-06 22:05:39 +08:00
@raysonx 可能还不一定是性能问题呢,早前 500 兆的宽带,改桥接可以 500 兆满速,后来从某段时间开始就不行了,只要改了桥接就变成半速。500 兆变 250 兆,千兆变 500 兆。
guanyin9cn
    19
guanyin9cn  
   2021-09-07 00:23:26 +08:00
1412

[root@x6 /mnt/jffs2/hw/bin] # iptables-save | grep MSS
-A PREROUTING -i ppp257 -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -m tcpmss --mss 1412:65535 -j TCPMSS --set-mss 1412
guanyin9cn
    20
guanyin9cn  
   2021-09-07 00:25:21 +08:00
hw 光猫 默认都是 1412.
guanyin9cn
    21
guanyin9cn  
   2021-09-07 00:28:57 +08:00
更正下,上面贴的是 v4 的

v6

[root@x6 /mnt/jffs2/hw/bin] # ip6tables-save | grep MSS
-A PREROUTING -i ppp257 -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -m tcpmss --mss 1392:65535 -j TCPMSS --set-mss 1392
guanyin9cn
    22
guanyin9cn  
   2021-09-07 00:31:35 +08:00
@Unclev21x

dnsmasq 里添加一行。

address=/电台域名 /::
tankren
    23
tankren  
   2021-09-07 09:23:01 +08:00
@xiaooloong #7 本来就是要手动设置 MTU 和 MSS 的啊 默认是 1500 全都放 1492 就可以,WAN 的 ipv6 用 track interface,然后 RA 设置 Assisted
tankren
    24
tankren  
   2021-09-07 09:24:32 +08:00
@xiaooloong #7 2.5.1 改的那个 bug 是对于 IPV6 MSS 的设置值减的是 IPV4 的 40 不是 60 原来要设置成 1472 才没问题
Unclev21x
    25
Unclev21x  
   2021-09-07 09:38:36 +08:00
@guanyin9cn 谢谢。我晚上回去就试试。
但我还是有些不明白。路由器开启科学上网(手机不开启)+IPv6 的情况下,手机拿到的 IPv6 地址是公网地址,这个时候访问电台,无法收听。打开 https://ifconfig.co/这个网站,显示的是 IPv6 地址。ping 这个域名的时候,解析出来的地址也是 IPv6 地址。接着,我在手机上也打开小火煎,之后就可以收听了。刷新 https://ifconfig.co/ ,显示的 IPv4 地址了。所以我就怀疑 IPv6 没有走代理(不知道是不是因为代理服务器不支持 IPv6 )。
Exin
    26
Exin  
   2021-09-07 15:08:20 +08:00
学习了,讲得好清楚
Danswerme
    27
Danswerme  
   2021-09-07 20:00:45 +08:00   ❤️ 2
感谢楼主分享,因为 IPv6 下打不开简书,本来我都把 IPv6 关掉了。想起来你提到的 MTU 的问题,刚才到家后用 wireshark 抓包看了下,发现其中有一条是这样的:`tcp previous segment not captured`。
然后在防火墙里把 MSS 改成 1420,果然就恢复正常了,再次感谢楼主。

分享下 RouterOS 里修改 MSS 的脚本: `/ipv6 firewall mangle add chain=forward out-interface=pppoe
-out1 protocol=tcp tcp-flags=syn action=change-mss new-mss=1420`
raysonx
    28
raysonx  
OP
   2021-09-07 21:33:45 +08:00
@Danswerme 感谢分享 RouterOS 的设置命令
PublicDNS
    29
PublicDNS  
   2021-09-09 01:40:54 +08:00 via Android   ❤️ 4
erx 用户

set firewall options mss-clamp6 interface-type pppoe
set firewall options mss-clamp6 mss 1420
littlewing
    30
littlewing  
   2021-09-09 17:17:33 +08:00
@Danswerme 我也是 IPv6 打不开简书,然后没找到原因,感谢
darrh00
    31
darrh00  
   2021-09-09 23:54:03 +08:00
讨论过好多次了吧?

https://www.v2ex.com/t/688028
raysonx
    32
raysonx  
OP
   2021-09-10 11:40:50 +08:00
@PublicDNS 感谢分享。
ppbaozi
    33
ppbaozi  
   2021-11-15 21:28:28 +08:00
routeros 似乎只需要设置 ipv6 > nd 里面的 mtu 值就行了
microka
    34
microka  
   2021-11-24 01:26:23 +08:00
@Danswerme #27 非常感谢,刚给 RouterOS 开启了 IPv6 ,发现无法访问简书,按照您的指导操作完马上可以了!
Danswerme
    35
Danswerme  
   2021-11-24 10:13:02 +08:00
@microka 客气了,也要谢谢楼主的分享,能帮到大家就是最好的。
microka
    36
microka  
   2021-12-12 11:26:50 +08:00
由于 MikroTik hAP ac² 不支持 IPv6 fasttrack ,换为尝试华为 B610-4E 光猫路由拨号一体,只设置了 PPPoE MRU 1492 ,可正常访问知乎和简书,用 Chrome F12 看到访问知乎是走 v6 ,简书走 v4 。
pengkaiwei
    37
pengkaiwei  
   2022-01-11 10:10:29 +08:00
请问老毛子 padavan 怎么 操作 MTU Clamping
droidmax61
    38
droidmax61  
   2022-11-02 19:52:23 +08:00 via Android
@pengkaiwei 设置自动 mss 没用,我是手动指定 mss
azure2023us
    39
azure2023us  
   2023-01-26 21:58:40 +08:00
某为光猫,只有 v4 ,v6 的没有
```
WAP(Dopra Linux) # iptables-save | grep mss
-A PREROUTING -i ppp257 -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -m tcpmss --mss 1412:65535 -j TCPMSS --set-mss 1412
-A PREROUTING -i ppp257 -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN,ACK -m tcpmss --mss 1412:65535 -j TCPMSS --set-mss 1412
-A POSTROUTING -o ppp257 -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -m tcpmss --mss 1412:65535 -j TCPMSS --set-mss 1412
-A POSTROUTING -o ppp257 -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN,ACK -m tcpmss --mss 1412:65535 -j TCPMSS --set-mss 1412
WAP(Dopra Linux) # ip6tables-save | grep mss
```

按照 v4 的套下

```
# firewall iptables
# v6 pmtu
ip6tables -t mangle -A PREROUTING -i ppp257 -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -m tcpmss --mss 1412:65535 -j TCPMSS --set-mss 1412
ip6tables -t mangle -A PREROUTING -i ppp257 -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN,ACK -m tcpmss --mss 1412:65535 -j TCPMSS --set-mss 1412
ip6tables -t mangle -A POSTROUTING -o ppp257 -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -m tcpmss --mss 1412:65535 -j TCPMSS --set-mss 1412
ip6tables -t mangle -A POSTROUTING -o ppp257 -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN,ACK -m tcpmss --mss 1412:65535 -j TCPMSS --set-mss 1412
```
lerry
    40
lerry  
   328 天前
赞,正好用的 ros ,都准备把 ipv6 禁用了。。
goodokgood1
    41
goodokgood1  
   326 天前
华硕路由器刷了梅林固件,也可以这样改吗?
fox233
    42
fox233  
   326 天前
只要是在 1452 以下就可以是吧 1360 可以吗
raysonx
    43
raysonx  
OP
   326 天前
@fox233 1452 是 ipv4 的,ipv6 不能超过 1432 。MTU 更小一些也可以,不过理论上因为传输效率低了网速要慢一点点。

@goodokgood1 不清楚梅林,但只要固件提供这个功能都可以试试。
fox233
    44
fox233  
   326 天前
@raysonx 能慢多少
letmefly
    45
letmefly  
   321 天前
今天发现 https://zhuanlan.zhihu.com/p/435392896 有个更简单的方法。
letmefly
    46
letmefly  
   321 天前   ❤️ 1
经过实践,还是这样设置快
RouterOS 里设置 MSS 的命令。其中 pppoe-out1 是 wan 口,1420 是要 MSS 值,请根据需要修改。

/ipv6 firewall mangle add chain=forward out-interface=pppoe-out1 protocol=tcp tcp-flags=syn action=change-mss new-mss=1420
zent00
    47
zent00  
   314 天前   ❤️ 1
最近在折腾 VyOS 1.4 ,发现和 1.3 设置 MSS 有点不一样,在这里把两个版本的配置方法都贴一下:

VyOS v1.3
set firewall options interface pppoe0 adjust-mss6 1432

VyOS v1.4
set interfaces pppoe pppoe0 ipv6 adjust-mss 1432
JimmyChan1506
    48
JimmyChan1506  
   256 天前 via Android
最近 ipv4 公网被取消了,只能用 ipv6 的公网 ip, 用的就是 openwrt 拨号的方案,但不是很确定里面的设置有没有问题,只能是能用,但感觉网速下了一个台阶,楼主有没有兴趣搞一个完整点的 openwrt 下拨号 ipv6 的教程?网上找的感觉都是片面的…
raysonx
    49
raysonx  
OP
   255 天前
@JimmyChan1506 我本来打算几篇文章系统讲一下配置家庭 IPv6 网络的最佳实践的,可惜这一拖就是两年。我下午写点简单的东西吧。
JimmyChan1506
    50
JimmyChan1506  
   253 天前
@raysonx 感恩, 期待
letmefly
    51
letmefly  
   253 天前
@JimmyChan1506 最近 ipv4 公网被取消了,只能用 ipv6 的公网 ip, 用的就是 openwrt 拨号的方案,但不是很确定里面的设置有没有问题,只能是能用,但感觉网速下了一个台阶,楼主有没有兴趣搞一个完整点的 openwrt 下拨号 ipv6 的教程?网上找的感觉都是片面的…

昨天在 er-x 路由器上又又又刷了 openwrt 22.03.5 固件,就是为了用 ipv6 。之前来回在原厂固件和 openwrt 之间反复,但是原厂固件不论我怎么样设置都会生成很多临时地址,openwrt 就不会。原版的 openwrt 对 ipv6 的支持是很好的,只需要简单的配置成 pppoe 协议,填上正确的用户和密码就能获得 ipv6 地址了。但是因为我会用 zerotier ,所以当我配置 zerotier 重启后,就会发现按照默认配置的 ipv6 不能用了,具体表现就是 win10 的电脑 ping ipv6 的地址没反应,ipv6 测试也没 v6 地址。昨天我先是在接口-->wan--> 高级设置--> 获取 IPv6 地址--> 已禁用;然后在接口把系统创建的 wan6 接口删除了,然后再重建了一个接口,还是叫 WAN6 ,协议先 DHCPv6 客户端,设置就选择"@wan" ,然后用了一天了,我的 win10 电脑还是只有一个临时地址,跑 ipv6 网页测试也是非常畅通的。
raysonx
    52
raysonx  
OP
   252 天前
@letmefly 关于很多临时地址的问题,操作系统只会为同一个前缀生成一个临时地址,所以出现这种情况时是不是被分配了多个前缀呢?可能是重新拨号后前缀变化导致旧的前缀没有移除。请看我的这篇文章 https://v2ex.com/t/955636#reply0

此外我曾经用过一段时间 EdgeOS ,它的固件不能正确的移除失效的旧前缀,你可以关闭 DHCPv6 并参考 https://community.ui.com/questions/Feature-request-correct-handling-of-IPv6-router-advertisements-for-dial-up-connections/1a2b7d1d-90f4-4273-8c8e-8021384d6959 修改原厂固件的部分代码来解决。

关于速度问题,请先检查 MTU 。关于完整点的 openwrt 的教程,已经在计划中。关于 Zerotier 的问题,这不是几句话就能调试清楚的,建议你开个新帖询问。
zbowen66
    53
zbowen66  
   252 天前
@icegaze #4 感谢楼主,感谢层主,真的有用!
sdc6882278
    54
sdc6882278  
   200 天前
关于 IPv6 的分片问题这里可能有所误区,IPv6 是支持分片的,不支持的是中间设备分片而是支持发起以及接受者分片,否则对于一个小于 1280 的隧道,就不能传输 IPv6 了?显然是不可能的,所以请作者勘误一下。
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3387 人在线   最高记录 6543   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 28ms · UTC 11:46 · PVG 19:46 · LAX 04:46 · JFK 07:46
Developed with CodeLauncher
♥ Do have faith in what you're doing.