关于 TP-LINK XDR6088 那些有的没的

Homelab Feb 18, 2024

事情的起因是搬家之后不能随心所欲的拉网线到 PC 上面,内网传输文件显得略慢,当时用的 Wi-Fi5 路由器最大协商速率 800M,贴脸能跑到 700M,隔一堵墙就只剩 300M 了,于是想着换个规格更高一些的,选了 XDR6088 这款出货量大的。

一般来说出货量大意味着固件支持会迅速一些,二手流转也容易一些。不过据恩山论坛网友分享,TP-LINK 的高端人才都去搞三频路由器了,剩下来的人修小 bug 几个月也不见的能修好。事实也的确如此,到现在了这破路由器还有这么多问题。

无线速率

拿到手之前,我对它的了解是

  • 2.4G 支持 4x4 MIMO,在 40MHz 频宽下最高速率 1147Mbps
  • 5G 支持 4x4 MIMO,在 160MHz 频宽下最高速率 4804Mbps

心想 5G 理论速率 4800M,我跑个 2400M 不过分吧,拿到手之后发现全都是骗人的。

802.11 standard, name, frequency Maximum PHY data rate Maximum channel bandwidth Maximum MCS index Maximum spatial streams
ax@5GHz 1200 Mbps 80MHz 11 (HE) 2/MIMO
ac@5GHz 866 Mbps 80MHz 9 (VHT) 2/MIMO
a/n@5GHz 300 Mbps 40MHz 15 (HT) 2/MIMO

根据苹果官方的文档,所有 MacBook 在 5Ghz 频率下,最多也就协商到 1200M,实际再打个折我测出来也就 800M-900M,隔一堵墙也就 500M 没比 Wi-Fi5 路由器快到哪里去,真给跪了。

IPv6 DNS 投毒

速率问题我也认了,毕竟频率越高衰减越快这个物理规律不能违背,然而用着用着发现这破玩意儿居然会投毒。

之前我用过的所有路由器,如果只设置首选 DNS,终端只会收到一个DNS,很多品牌很多型号都是这样,但是在 TP-LINK XDR6088 下,备选 DNS 还有一些很离谱的行为:

IPv4 下仅设置首选,不设置备选,终端获取到的第一个是我设置的首选,第二个 DNS 为运营商给的第一个 DNS。众所周知运营商的 DNS 多多少少也会屏蔽一些网站。

IPv6下仅设置首选,不设置备选,终端获取到的第一个为自己设置的首选,第二个为 “240c::6666”,这是个投毒 DNS,基本上所有国外网站都是胡乱解析。为了避免投毒DNS,我试过首选备选都设置成同一个(自建 adguard),和上面情况一样存在投毒问题。

注:IPv4 下会返回两个一样的 DNS 给终端,不会擅自传一个别的 DNS

联系过 TP 的技术客服,问东答西,我问他们为什么固件里会内置一个投毒的 IPv6 DNS,邮件客服问我什么是投毒,哪些网站打不开,别的网站能不能打开。不知道是装傻还是真不懂。

解决方案只能是分别填写两组 DNS 了。如果自己还有别的机器就再部署一个 adguard 把地址填到备选 DNS 就好。如果没有别的机器了,建议乱填两个不存在的 IP,冲掉投毒的那个。

Docker 默认映射端口到公网

为了解决 DNS 投毒问题,我试过在 docker 里跑了一个 adguard,有一次突然发现访问公网 IP:3000 端口可以登陆管理后台,我换了手机流量,直接访问宽带 IP:3000 还是能打开,实锤了 docker 默认直接映射到公网。

由于 TP 路由自带的 SimpleDocker 是个阉割版,没办法修改任何网络驱动的参数,当时找客服去问。结果邮件客服丝毫不理会我跟他说的网络安全问题。:

"这边联系工程师确认了,当前产品机制是这样的,是自动映射到外网的,很抱歉。"

于是我开始自己研究,因为 docker 命令行是可以写在 -p 参数后面的,比如

docker run -p 192.168.x.x:8888:8080 container_name

我想那个输入框能不能也填入 192.168.x.x:8888,发现有长度限制,后面的字被吞了

转念一想,这玩意儿就是个 UI 界面而已,长度估计是前台控制,后台不校验,于是我打开控制台

把原本的 maxlenth 16 改高一点,想输入多少就输入多少。这样就可以只把管理后台映射到内网 IP 了,也就是说只能 192.168.100.0/24 网段可以访问,避免暴露到公网导致安全问题。

官方固件 CPU 单核心占用 100%

排查别的问题的时候,意外发现路由器的 CPU 永远都有一个核心跑满 100%,即便网速 0 也有一个核心 100%。

有疑似 TP-LINK 工程师的人私信,这个核心跑满是由于指示灯关闭导致的,并且成功复现。

发现问题的时候是在 docker 中,镜像默认只有一个 top 命令,显示 16% 左右的一个整体占用,还以为路由器性能挺强的。突发奇想安装了个 htop 命令,万万没想到 16% 意思是一个核心永远被占满。

为了研究到底是哪个草台班子写的哪个玩意儿吃满单核 100% 的算力,我按照网上的反弹 shell 教程,获取了 root 权限,从 https://downloads.openwrt.org/snapshots/packages/aarch64_cortex-a53/packages/ 下载 htop 并安装。多说一句,TPLINK 的系统是基于 OpenWRT 21.x 魔改的,所以 OpenWRT 的包也能装进去。

抓出来了占用 CPU 的真凶是 dms 进程。但是他具体是个啥,就只有鬼知道了。

我有尝试 ./dms 运行过一次,日志如下,有能力的大佬可以分析下。

root@(mt7986):/bin# dms
root@(mt7986):/bin# 
    mcbAlignFromPool(235). Fail to alloc 552000 bytes from mcb Generic, alloc from heap [<0x7f823ae020>].
    mcbAlignFromPool(235). Fail to alloc 883200 bytes from mcb Generic, alloc from heap [<0x7f8235d020>].
    mcbAlignFromPool(235). Fail to alloc 1214400 bytes from mcb Generic, alloc from heap [<0x7f8230c020>].
    systemLoadSysmode(753). get workform 0
    systemLoadSysmode(761). get mngt_mode 0, work_mode 0, controller_detect_mode 0
control socket bind setSock error
    gpioRequest(203). ERROR: request gpio 8 failed
    initGmacPortInfo(304). gmac0 include port0,  support switch
    initGmacPortInfo(304). gmac0 include port1,  support switch
    initGmacPortInfo(304). gmac0 include port2,  support switch
    initGmacPortInfo(304). gmac0 include port3,  support switch
    initGmacPortInfo(304). gmac0 include port4,  support switch
    initGmacPortInfo(304). gmac1 include port5, no support switch
    gpioRequest(203). ERROR: request gpio 7 failed
### dhcp event command register. ###
### dhcpv6 event command register. ###
    gpioRequest(203). ERROR: request gpio 12 failed
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N INPUT_NOT_LAN_TO_WAN, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N INPUT_ICMP_TO_WAN, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N INPUT_ICMP_TO_WAN_IF, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N INPUT_DHCP_V4, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t filter -N INPUT_WAN_LOCAL_V6, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t filter -N INPUT_WAN_GLOBAL_V6, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t filter -N INPUT_WAN_LOCAL_IF_V6, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t filter -N INPUT_WAN_GLOBAL_IF_V6, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t filter -N INPUT_WAN_STATIC_IF_V6, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t filter -N INPUT_DHCP_V6, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t filter -N INPUT_DHCP_STATIC_V6, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t nat -N PREROUTING_DHCP_BROAD, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t nat -N POSTROUTING_WAN_IF, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t nat -N POSTROUTING_SNAT_WAN, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t nat -N POSTROUTING_WAN_STATIC_IF, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t nat -N POSTROUTING_WAN_IF_V6, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t nat -N POSTROUTING_WAN_STATIC_IF_V6, 256
    checkOrResetFactoryInfo(988). Factory Info verified
    init_sock(173). socket bind error, Address in use(98).
    insertModuleDependant(186). Kmod igmp_proxy_snooping exist, try to remove it
    removeModuleNested(276). Removing module igmp_proxy_snooping...
statsService init
RTNETLINK answers: File exists
.policy_rule_mark ADD failed ret = [netlink talk failed]
RTNETLINK answers: File exists
policy_rule_mark ADD failed ret = [netlink talk failed]
RTNETLINK answers: File exists
policy_rule_mark ADD failed ret = [netlink talk failed]
RTNETLINK answers: File exists
policy_rule_mark ADD failed ret = [netlink talk failed]
[relay_mode_config_notify:42] sysModeGetWorkMode: 0
[relay_mode_config_notify:42] sysModeGetWorkMode: 0
[wanPortDetectCheckAllLan:113] sysModeGetWorkMode: 0
    deviceInfoInit(975). softver:1.0.28 Build 231028 Rel.25584

root@(mt7986):/bin#     br_scan_ifaces(47). Scanning bridge netif...
    topology_init_self_device(4554). init mesh group id: [aa:bb:cc:dd:ee:ff]
    autoconf_business_init(2064). init wlan_dev_num:0

    autoconf_business_init(2064). init wlan_dev_num:1

init wss module.
    event_sock_enable(1204). enabled netlink socket at 23 with own pid 10285

    jsonObjectToFile(290). Trying to commit to flash...
    portManageLoadConfigToDevWithMode(4854). load config to dev aa:bb:cc:dd:ee:ff
    loadMwanConfigToDev(3128). mwan 1 is close
    loadMwanConfigToDev(3128). mwan 2 is close
    loadIptvConfigToDev(3561). cap sub func 3c
    loadIptvConfigToDev(3568). load iptv to dev aa:bb:cc:dd:ee:ff
[portManageInit:6273] sysModeGetWorkMode: 0
    mt7986_addSlaveDevtoWan(312). No WAN to NEW WAN: new wan index: 1
    system_vdev_delif(802). Sys del virtual wan if failed:Invalid argument
    system_vdev_addif(776). Sys add virtual wan failed:Resource busy
    system_bridge_addif(842). Sys add bridge failed:Resource busy
    optimizeOneFile(1054). Rules Optimized: 619

    optimizeOneFile(1055). Rules Unoptimized: 43

[<cloud_relay_client/dms>:<cloud_relay_client/iccCtl()/465>] local->1/1024, cmd 0x40004926, sendlen 4, iccctl_ret 0
[<cloud_relay_client/dms>:<cloud_relay_client/iccCtl()/465>] local->1/1024, cmd 0x40004921, sendlen 16, iccctl_ret 0
lanv6LocalIpv6: fe80::6eb1:58ff:fee0:cc1c
    insertModuleDependant(186). Kmod arp_filter exist, try to remove it
    removeModuleNested(276). Removing module arp_filter...
    insertModuleDependant(186). Kmod dn_login exist, try to remove it
    removeModuleNested(276). Removing module dn_login...
    dnsProxyParamInit(196). priDnsStr = 223.6.6.6,223.6.6.6, sndDnsStr = 0.0.0.0,0.0.0.0
    dnsProxyParamInit(238). priDns6Str = 240c::6666,240c::6666, sndDns6Str = ::,::
    dnsProxyParamInit(196). priDnsStr = 223.6.6.6,223.6.6.6, sndDnsStr = 0.0.0.0,0.0.0.0
    dnsProxyParamInit(238). priDns6Str = 240c::6666,240c::6666, sndDns6Str = ::,::
    insertModuleDependant(186). Kmod dns_proxy exist, try to remove it
    removeModuleNested(276). Removing module dns_proxy...
    devDiscoveryStart(616). Regist devDiscover socket error.

[lanDhcpcInit:1676] sysModeGetWorkMode: 0
[dhcpsParamsUpdate:1328] sysModeGetWorkMode: 0
1
1
    firewallCtxInit(560). /network/wan_status/wan_status
    firewallCtxInit(560). /network/wan_status_2/wan_status_2
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N BM_INTERNET_ALLOW, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N BM_INTERNET_DURATION, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N BM_APP_DURATION, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N BM_APP_TIMESTAMP, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N BM_APP_STATISTICS, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N BM_APPDIST, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N BM_WEBFILTER, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N BM_WEB_DNS, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N BM_WEBSEC, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N FORWARD_DMZ, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t nat -N PREROUTING_DMZ, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t filter -N FORWARD_DMZ_V6, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t nat -N PREROUTING_DMZ_V6, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N INPUT_HOSTFORBID, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t filter -N INPUT_HOSTFORBID, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N FORWARD_HOSTFORBID, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t filter -N FORWARD_HOSTFORBID, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N INPUT_LANWEB, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t filter -N INPUT_LANWEB, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N FORWARD_UPNP, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N FORWARD_UPNP_WAN, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t nat -N PREROUTING_UPNP, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t filter -N FORWARD_UPNP_V6, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t filter -N FORWARD_UPNP_WAN_V6, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t nat -N PREROUTING_UPNP_V6, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N FORWARD_VS, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t nat -N PREROUTING_VS, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t filter -N FORWARD_VS_V6, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t nat -N PREROUTING_VS_V6, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N INPUT_VPN, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N FORWARD_VPN, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t nat -N POSTROUTING_VPN, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t filter -N FORWARD_IPV6_FIREWALL_SWITCH, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N FORWARD_SETMARK, 256
ip6tables: Chain already exists.
<WARN> ipt cmd failed: ip6tables -t filter -N FORWARD_SETMARK, 256
    updateChainInputIcmpToWanIf(222). enter icmp to wanif
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N BM_WEBSEC_DOWNLOAD, 256
iptables: Chain already exists.
<WARN> ipt cmd failed: iptables -t filter -N BM_WEBSEC_SUBMIT, 256
ip6tables: No chain/target/match by that name.
<WARN> ipt cmd failed: ip6tables -w -t filter -F INPUT_VPN, 256
ip6tables: No chain/target/match by that name.
<WARN> ipt cmd failed: ip6tables -w -t filter -F FORWARD_VPN, 256
ip6tables: No chain/target/match by that name.
<WARN> ipt cmd failed: ip6tables -w -t nat -F POSTROUTING_VPN, 256
    gpioRequest(203). ERROR: request gpio 9 failed
statsService start.
===============DHCP_TIMEOUT=30
[wanStartIndex:4878] sysModeGetWorkMode:

802.11r 和 WPA3 冲突

迫于单核始终跑满也太不环保了,再加上我已经掌握了反弹 shell 获取 root 权限的技能,结合网上大家的分享,据说最新版本的稳定版 OpenWRT 23.05.2 已经没啥大问题,然后我参考网上各路大神的帖子最终成功刷成了 OP 原版系统。

过去很多年我都是把路由器 5G 和 2.4G 频段分开,好像是因为之前发现电脑不会自动切换 5G。最近研究 802.11kvr 协议,发现 mesh/漫游都是基于这三个协议。 原则上讲如果路由器支持 802.11kv,开启多频合一没啥问题,苹果的官方文档也间接佐证了这个论据。

刷完系统之后我也理所当然的给 2.4G 和 5G 共用一个 SSID。设置过程中还惊奇的发现 OpenWRT 支持 802.11r,那肯定是要打开的。

用了一下午也没发现有什么问题,以为自己又为家里网络鲁棒性做了一点点贡献,没成想到了晚上,女佣拿回自己的手机,说连不上 Wi-Fi。开始我还以为是路由器刷机导致 Wi-Fi 安全风控,需要重新输密码连接,后来发现死活连不上。这台手机比较老了,老到只支持 2.4G Wi-Fi,红米某个型号。

查看路由器日志发现这台手机曾经有过 DHCP 租约,也就是说曾经是连接成功过的,于是很快发现是 802.11r 开关导致的,关掉 2.4G 的 802.11r 即可正常连接了。

但是我不能接受回滚掉一个 “看起来有贡献” 的功能啊,搜索一圈发现是因为 WPA2-PSK/WPA3-SAE 混合模式和 802.11r 有冲突。

The combination of 802.11r with WPA2-PSK/WPA3-SAE Mixed Mode (strong security) doesn't work, when switching to WPA2-PSK (strong security) both clients (iOS and Android) can connect.
Cannot use 802.11r on both radio’s 2.4 and 5GHz with same SSID, clients unable to connect
I’m running a stable custom NSS build from @ACwifidude from September 26 on a R7800. I’ve enabled 802.11k and 802.11v on the 5GHz and 2.4 GHz radio and clients (mostly Apple) are able to connect just fine. When I enable 802.11r on the 5GHz radio, all still works just fine. However, when I configure …

于是我又心满意足的打开了 802.11r 开关,同时调整加密模式为 WPA2-PSK。

多频合一导致设备掉线

截止上面那个时间点,所有设备都是没问题的,包括 MacBook,网络摄像头,旗舰手机,低端手机。晚上老婆开始看剧,说电脑连不到 NAS,系统是 Windows 10,网卡是 AX201 160Mhz,具体表现是连接 Wi-Fi 之后过几秒钟会被踢下线,Wi-Fi图标显示一个禁止标志,再连还需要重新输密码。迫不得已关了多频合一,另外既然多频合一都关了,802.11r 自然也没啥必要。

我个人猜测是因为 802.11r 会在特定的场景把设备踢下线,Windows 电脑断连可能和这个有关系。但是不管怎么样,再怎么折腾家里网络,不能耽误老婆上网,不然就要挨揍了。

5G 频段 160Mhz 信道选择

迫于 36 信道的 5G Wi-Fi实在是太拥挤,我还是更倾向于使用 100-128 信道,干扰小,频率高,速度快。之所以干扰小,是因为新加坡的气象雷达运行在这个频段,附一段日志

Sat Mar  2 13:28:27 2024 daemon.notice hostapd: phy1-ap0: DFS-NOP-FINISHED freq=5500 ht_enabled=0 chan_offset=0 chan_width=0 cf1=5500 cf2=0
Sat Mar  2 13:28:27 2024 daemon.notice hostapd: phy1-ap0: DFS-NOP-FINISHED freq=5520 ht_enabled=0 chan_offset=0 chan_width=0 cf1=5520 cf2=0
Sat Mar  2 13:28:27 2024 daemon.notice hostapd: phy1-ap0: DFS-NOP-FINISHED freq=5540 ht_enabled=0 chan_offset=0 chan_width=0 cf1=5540 cf2=0
Sat Mar  2 13:28:27 2024 daemon.notice hostapd: phy1-ap0: DFS-NOP-FINISHED freq=5560 ht_enabled=0 chan_offset=0 chan_width=0 cf1=5560 cf2=0
Sat Mar  2 13:28:27 2024 daemon.notice hostapd: phy1-ap0: DFS-NOP-FINISHED freq=5580 ht_enabled=0 chan_offset=0 chan_width=0 cf1=5580 cf2=0
Sat Mar  2 13:28:27 2024 daemon.notice hostapd: phy1-ap0: DFS-NOP-FINISHED freq=5600 ht_enabled=0 chan_offset=0 chan_width=0 cf1=5600 cf2=0
Sat Mar  2 13:28:27 2024 daemon.notice hostapd: phy1-ap0: DFS-NOP-FINISHED freq=5620 ht_enabled=0 chan_offset=0 chan_width=0 cf1=5620 cf2=0
Sat Mar  2 13:28:27 2024 daemon.notice hostapd: phy1-ap0: DFS-NOP-FINISHED freq=5640 ht_enabled=0 chan_offset=0 chan_width=0 cf1=5640 cf2=0

根据 List of WLAN channels 可知,5500-5640 刚好对应 100-128。这也就使得默认情况下,周围邻居的路由器都会避免这个频段,干扰极其的小,基本等同于没有干扰,一人独享 160MHz 的频宽。

当然肯定有坏处,坏处就是每天气象雷达一开家里就断网,一断就是半个小时。

If no other DFS events are detected and there are no wireless clients associated to the SSID on 5GHz, the access point will revert back to the original DFS channel, usually in 30 minutes. – Dynamic Frequency Selection (DFS)

固定信道有可能会遇到 DFS start_dfs_cac() failed 问题,气象雷达 DFS 过了 30 分钟的 NOP 之后,本应该重新发射 5G 信号,这个错误暂时无解,应该是和中心频率有关,比如 100-128 信道 160Mhz 频宽下,中心频率是 114,但是信道列表要么 112 要么 116。

Thu Mar  7 14:36:04 2024 daemon.err hostapd: 20/40 MHz: center segment 0 (=114) and center freq 1 (=5590) not in sync
Thu Mar  7 14:36:04 2024 daemon.err hostapd: Can't set freq params
Thu Mar  7 14:36:04 2024 daemon.err hostapd: DFS start_dfs_cac() failed, -1

所以还是只能把 channel 设置为自动,如果你想固定在 DFS 信道就只能八仙过海各显神通了,把控制功率,信道列表挨个设置下,看看怎么组家里网络能恢复,我现在也没有完美方案。30 分钟 NOP 过了之后,要么是在 100-128 之间以 80Mhz 甚至 40Mhz 发射,要么是跑到别的很拥挤的频段,反正就是想完美回到 100-128 跑 160Mhz 实现不了,有可能得写个 cron 脚本监测并重启 5G 信号。这个方法不太优雅所以我也先不管了,80Mhz 也不是不能用。

多频合一卷土重来

于是解决方案就还是自动漫游,仍然需要把 2.4G 和 5G 的 SSID 设置为一样的,经过实测,路由器开启802.11 kvr 三个协议之后,隔一堵墙的情况下,终端们基本上都能自动回去 5G 频段。其中苹果手机电脑是秒级,三星手机稍慢也是秒级,英特尔网卡表现不一,1-3 分钟也都会陆陆续续回去 5G 信道。

之前开启 kvr 再双频合一的时候,遇到过英特尔网卡被踢下线的问题,有可能是因为参数没配置全,建议参考这篇文章 如何正确配置 OpenWrt WPA3 + 802.11kvr。几个核心点我摘出来:

  1. 必须卸载原有的 wpad-basic-xx 包,然后安装 wpad-wolfssl 否则重启之后 Wi-Fi 就挂了,会报错 unknown configuration item 'bss_transition'unknown configuration item 'wnm_sleep_mode'
  2. 参数能填的都尽量填,尤其是 mobility_domain 填个与众不同的,我之前遇到设备被踢下线可能就跟这个有关系。

802.11 kvr 配置

顺便贴一个自己的配置供参考

option ieee80211k '1'
option wnm_sleep_mode '1'
option bss_transition '1'

ieee80211r 相关的放后面
  • ieee80211k 用来开启 802.11k
  • ieee80211v 被废弃掉了,官方建议 只写 wnm_sleep_modebss_transition 。但是我不知道这俩不填是不是也能开启 802.11v,文档也没写

附赠一个配置生成器的脚本,用法如下

./802.11r.helper.py 0 --ap AA:BB:CC:DD:EE:FF --ap AA:BB:CC:DD:EE:FG --format config

---Madkodur rooming --------------------------------

Configuration for AP with BSSID AA:BB:CC:DD:EE:FF:

	option ieee80211r '1'
	option mobility_domain 'bf10'
	option pmk_r1_push '1'
	option nasid 'AABBCCDDEEFF'
	option r1_key_holder 'AABBCCDDEEFF'
	list r0kh 'AA:BB:CC:DD:EE:FF,AABBCCDDEEFF,8fd20f97d45705e51cfacd23e7df217b'
	list r0kh 'AA:BB:CC:DD:EE:FG,AABBCCDDEEFG,8fd20f97d45705e51cfacd23e7df217b'
	list r1kh 'AA:BB:CC:DD:EE:FF,AA:BB:CC:DD:EE:FF,8fd20f97d45705e51cfacd23e7df217b'
	list r1kh 'AA:BB:CC:DD:EE:FG,AA:BB:CC:DD:EE:FG,8fd20f97d45705e51cfacd23e7df217b'
---Madkodur rooming --------------------------------

Configuration for AP with BSSID AA:BB:CC:DD:EE:FG:

	option ieee80211r '1'
	option mobility_domain 'bf10'
	option pmk_r1_push '1'
	option nasid 'AABBCCDDEEFG'
	option r1_key_holder 'AABBCCDDEEFG'
	list r0kh 'AA:BB:CC:DD:EE:FF,AABBCCDDEEFF,8fd20f97d45705e51cfacd23e7df217b'
	list r0kh 'AA:BB:CC:DD:EE:FG,AABBCCDDEEFG,8fd20f97d45705e51cfacd23e7df217b'
	list r1kh 'AA:BB:CC:DD:EE:FF,AA:BB:CC:DD:EE:FF,8fd20f97d45705e51cfacd23e7df217b'
	list r1kh 'AA:BB:CC:DD:EE:FG,AA:BB:CC:DD:EE:FG,8fd20f97d45705e51cfacd23e7df217b'

Apply your settings with 'wifi restart'

其中 --ap 有几个就填几个,2.4G 和 5G 都要配置。

除了上面两个配置之外,这两个最好也加上

option ft_over_ds '0'
option ft_psk_generate_local '1'

芯片层面的妥协

刷完 OpenWRT 之后发现网口的名字很乱,显示出来 eth1, lan1, lan2, lan3, lan4, lan5 六个接口,并且路由器最右边的千兆口叫 lan4。带着这些疑问我运行了一下 ip link show 发现网卡命名更奇怪了

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1504 qdisc mq master br-lan state UP qlen 1000
link/ether ma:ca:dd:re:ss:ha brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq master br-lan state UP qlen 1000
link/ether ma:ca:dd:re:ss:hb brd ff:ff:ff:ff:ff:ff
4: lan1@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master br-lan state LOWERLAYERDOWN qlen 1000
link/ether ma:ca:dd:re:ss:ha brd ff:ff:ff:ff:ff:ff
5: lan2@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master br-lan state LOWERLAYERDOWN qlen 1000
link/ether ma:ca:dd:re:ss:ha brd ff:ff:ff:ff:ff:ff
6: lan3@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master br-lan state LOWERLAYERDOWN qlen 1000
link/ether ma:ca:dd:re:ss:ha brd ff:ff:ff:ff:ff:ff
7: lan4@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP qlen 1000
link/ether ma:ca:dd:re:ss:ha brd ff:ff:ff:ff:ff:ff
8: lan5@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master br-lan state LOWERLAYERDOWN qlen 1000
link/ether ma:ca:dd:re:ss:ha brd ff:ff:ff:ff:ff:ff

lan1-lan5 都有一个 @eth0 后缀,疑似是从 eth0 分出来的。

随后我又在 /dev/net 下发现更多迹象

eth0 -> ../../devices/platform/soc/15100000.ethernet/net/eth0
eth1 -> ../../devices/platform/soc/15100000.ethernet/net/eth1
lan1 -> ../../devices/platform/soc/15100000.ethernet/mdio_bus/mdio-bus/mdio-bus:1f/net/lan1
lan2 -> ../../devices/platform/soc/15100000.ethernet/mdio_bus/mdio-bus/mdio-bus:1f/net/lan2
lan3 -> ../../devices/platform/soc/15100000.ethernet/mdio_bus/mdio-bus/mdio-bus:1f/net/lan3
lan4 -> ../../devices/platform/soc/15100000.ethernet/mdio_bus/mdio-bus/mdio-bus:1f/net/lan4
lan5 -> ../../devices/platform/soc/15100000.ethernet/mdio_bus/mdio-bus/mdio-bus:1f/net/lan5

经过一番研究,我发现这款路由器的 CPU MT7986 只有两条 2.5G 总线,一条作为原生 2.5G 口,一条会给 MT7531A 扩展出来 4个千兆+1个2.5G,至于怎么扩展的,感谢评论区网友提供的 MT7531 芯片 Datasheet,这里直接引用官方说明:

It (MT7531) also integrated 2-port high speed SGMII interface for 2.5Gbps backbone or the external 2.5Gbps PHY.

就是说 MT7531 里面有两个 2.5Gbps 的 HSGMII,既可以作为总线通讯用,又可以扩展 2.5G 物理网口。HSGMII 作为总线使用一般就是指和上游通信,在这个例子中就是连接到 CPU 的 eth0 总线,另外一个 HSGMII 则扩展出来一个 2.5G 网口。

所以这几个物理接口可以这样理解:

2: eth0: 路由器不显示,用来对接 MT7531 的总线,承接着 5 个网口的数据流
3: eth1: 左数第一个 2.5G,CPU MT7986 原生接口
4: lan1@eth0: 左数第三个网口,第一个 1G 口,扩展自 MT7531
5: lan2@eth0: 第二个 1G 口
6: lan3@eth0: 第三个 1G 口
7: lan4@eth0: 第四个 1G 口
8: lan5@eth0: 第二个 2.5G 口
29: phy0-ap0: 2.4G Wi-Fi,CPU 原生
30: phy1-ap0: 5G Wi-Fi,CPU 原生

acwifi 的测试也从侧面证实了这个设计:

2.5G LAN到其它千兆口总带宽 2190Mpbs

应该是指 MT7531A 内部几个口之间转发数据,总带宽足够 1G lan 口同时跑满上下行。

根据我自己的测试,eth1 到 lan5 也就是这两个 2.5G 口单向的确可以跑满,双向的话总带宽大概在 2.7Gbps,测试环境是 RTL8156B 螃蟹卡 macOS 14.3.1 六类网线,不存在驱动问题,因为单独上行单独下行都跑满 2.35Gbps

# 双向
[ ID][Role] Interval           Transfer     Bitrate
[  5][TX-C]   0.00-1.01   sec   242 MBytes  2.02 Gbits/sec
[  7][RX-C]   0.00-1.01   sec  74.0 MBytes   618 Mbits/sec
[  5][TX-C]   9.01-10.01  sec   251 MBytes  2.11 Gbits/sec
[  7][RX-C]   9.01-10.01  sec  74.9 MBytes   628 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID][Role] Interval           Transfer     Bitrate         Retr
[  5][TX-C]   0.00-10.01  sec  2.39 GBytes  2.05 Gbits/sec                  sender
[  7][RX-C]   0.00-10.01  sec   740 MBytes   620 Mbits/sec    0             sender

# 下行
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.01   sec   280 MBytes  2.34 Gbits/sec
[  5]   9.00-10.01  sec   280 MBytes  2.35 Gbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.01  sec  2.73 GBytes  2.35 Gbits/sec    0             sender

# 上行
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.01   sec   270 MBytes  2.26 Gbits/sec
[  5]   9.01-10.01  sec   280 MBytes  2.35 Gbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-10.01  sec  2.72 GBytes  2.34 Gbits/sec                  sender

随后我又在路由器上装了个 iperf3,看看 CPU MT7986 和 MT7531A 交换芯片之间的速度,测试结果如下,单向测试就不放了肯定是满满的 2.35Gbps,双向大概总共能有个 4Gbps。

# 双向
[ ID][Role] Interval           Transfer     Bitrate
[  5][TX-C]   6.00-7.01   sec   231 MBytes  1.94 Gbits/sec
[  7][RX-C]   6.00-7.01   sec   276 MBytes  2.31 Gbits/sec
[  5][TX-C]   7.01-8.00   sec   241 MBytes  2.03 Gbits/sec
[  7][RX-C]   7.01-8.00   sec   275 MBytes  2.31 Gbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID][Role] Interval           Transfer     Bitrate         Retr
[  5][TX-C]   0.00-10.01  sec  2.41 GBytes  2.07 Gbits/sec                  sender
[  7][RX-C]   0.00-10.01  sec  2.29 GBytes  1.96 Gbits/sec    3             sender

说到这里,我深深的感受到工业设计里处处充满了妥协。但是消费者买路由器的时候,谁能想到两个 2.5G 口不在同一个 switch 上,并且跑不了上下行共 5G 的速率?

用法建议

如果你恰巧也使用这款路由器,恰巧也把 wan 口设置在最右边的 1G 网口,恰巧 NAS 需要接 2.5G 网口,可以参考如下,总而言之就是大量跑流量的设备放在同一个交换芯片下。

  1. 如果 NAS 主要和公网通信,Wi-Fi 终端较少,并且有线设备都接在千兆口,可以使用左数第二个 2.5G 口,毕竟在同一个交换芯片上,稍微环保一丢丢
  2. 如果 NAS 主要和 Wi-Fi 终端通信,可以使用第一个 2.5G 口,不走 MT7531 芯片

其实随便插也没问题,我测试过 600Mbps 带宽连续上传四五天,两个芯片的通信依旧稳定。当时 NAS 接在 CPU 直通口,wan 口在 MT7531 上。我们在家里上网课开视频会议也完全不受影响。

Tags

Jie Li

🚘 On-road / 📉 US Stock / 💻 Full Stack Engineer / ®️ ENTJ