mt76 速率控制:为什么客户端会被钉在 MCS0(以及如何证明)
作者 Wu Jun · 更新于 2026-10-29 · 约 5 分钟
如果一台 OpenWrt + mt76 的 AP 只对某一个客户端发 MCS0,而其他客户端一切正常,那不是错觉——
而且通常不是信号问题。下面是这次的实测调查。
1. 先看对计数器
iw dev <ap> station dump | grep -E "Station|tx bitrate|rx bitrate|tx failed|tx retries|expected"
| 字段 | 含义 | 陷阱 |
|---|---|---|
tx bitrate |
AP→客户端最后一次用的速率 | 它是采样值、不是均值——要反复采样 |
rx bitrate |
客户端→AP 的最后速率 | 下行塌陷时它通常仍然正常 |
tx failed / tx retries |
链路层结果 | 要和"移动的字节数"对比,不能只看帧数 |
还要用一次廉价的内网传输确认方向,并在两端统计字节数(见第 3 节)。 如果 AP 发出的字节远多于客户端收到的,那是重传风暴;如果两边差不多,那只是空口空闲。
2. mt76 的速率控制在哪里
cat /sys/kernel/debug/ieee80211/phy*/rate_ctrl_alg # -> hw/driver
cat /sys/kernel/debug/ieee80211/phy*/hwflags # -> HAS_RATE_CONTROL
hw/driver 加上 HAS_RATE_CONTROL 意味着速率由固件/SoC 决定——mac80211 的软件速率控制(minstrel)
并不负责。所以"换个速率算法"不是选项;你只能间接影响它。
实践中有两个 debugfs 开关值得关注:
for f in /sys/kernel/debug/ieee80211/phy*/mt76/vow_atf; do
printf '%s: ' "$f"; cat "$f" # 固件空口公平性
done
for f in /sys/kernel/debug/ieee80211/phy*/mt76/aql_enable; do
printf '%s: ' "$f"; cat "$f" # 空口队列上限
done
不要直接重定向到带通配符的路径。路由器可能暴露多个 PHY,此时 shell 会因为目标不唯一而拒绝重定向。 应当遍历匹配到的文件,并且只修改证据清单里记录过的那一个射频。
3. 定位到缺陷的那次测量
同一客户端、同一时段,只改 vow_atf(E 级证据——原始抓包与产生它们的脚本已公开
[1] [2])。空闲 60 秒,然后连续 6 次 6 秒的内网下载:
vow_atf |
结果 | 行为 |
|---|---|---|
| 1(默认) | 9.5 / 7.3 / 9.5 / 7.4 / 9.6 / 7.2 Mbps | 连续 36 秒满载也完全不恢复 |
| 0 | 7.8 / 8.8 / 20 / 146 / 387 / 393 Mbps | 约 15 秒内爬回满速 |
| 0 + 客户端重新关联 | 369 / 374 / 376 / 390 / 409 / 397 Mbps | 第一次突发就满速 |
塌陷状态下的字节对账:12 秒传输,AP 发出 12.87MB,客户端收到 12.4MB。 几乎没有重传浪费——速率很低、信道大部分空闲。这就排除了"客户端收不到",指向速率选择。
4. 当前证据支持的触发条件
两个互相独立的触发条件,在 MT7986 + mt76 上都能复现:
- 客户端空闲/省电行为:约 1 秒空闲就足以让 AP 的发送速率掉到
MCS0 1SS。 在vow_atf=1下,即使随后持续满载,它也一直待在那里。 - 窄带客户端在宽带 BSS 里:只支持 40MHz 的客户端放进 80MHz BSS 会周期性塌陷,与 ATF 开关独立。 用它的原生带宽(40MHz BSS)运行则稳定在 380–420Mbps。这里只确认可复现条件,不宣称已经定位到某个 固件寄存器。
5. 该怎么做
# 1) 关掉那个阻止速率恢复的固件特性(并持久化)
for f in /sys/kernel/debug/ieee80211/phy*/mt76/vow_atf; do
echo 0 >"$f"
done
# 2) 如果客户端只支持 40MHz,就让射频宽度与它一致
sh /usr/bin/wifi-htmode HE40 # CSI 分辨率下降;客户端恢复可用
# 3) 最后一招:强制一次全新关联(重置速率状态)
iw dev <ap> station del <client-mac>
第 1 步持久化很重要:debugfs 的值会在驱动重载后丢失。本项目工具箱提供了开机初始化脚本与
每分钟重放的 watchdog(scripts/mt76-wifi-tune、scripts/csi-watchdog.sh)。
可直接下载:Router CSI Toolkit v0.1.3 与 SHA-256。
6. 可复现的 20 分钟 A/B 测试
只改一个 debugfs 数值不算证据。测试前先记录射频、客户端、距离、信道、带宽、固件,以及你愿意接受的 最低恢复标准。本文把基线定义为客户端已关联并预热后的 6 次传输中位数;通过条件可设为“20 秒内恢复到 基线的至少 70%”。这个阈值只是示例,但必须在看到结果前确定,不能事后挑一个有利的数字。
先保存一组只读证据:
AP=csi0
CLIENT_MAC='<client-mac>'
OUT="/tmp/mt76-ab-$(date +%s)"
mkdir -p "$OUT"
{
date +%Y-%m-%dT%H:%M:%S%z
uname -a
ubus call system board
iw dev "$AP" info
iw phy "$(cat /sys/class/ieee80211/phy*/name 2>/dev/null | head -n1)" info 2>/dev/null || true
cat /sys/kernel/debug/ieee80211/phy*/rate_ctrl_alg
cat /sys/kernel/debug/ieee80211/phy*/hwflags
for f in /sys/kernel/debug/ieee80211/phy*/mt76/vow_atf; do
printf '%s: ' "$f"; cat "$f"
done
dmesg | tail -n 120
} >"$OUT/context.txt" 2>&1
测试负载必须走内网,不要使用公网测速站。客户端静默 60 秒后,连续做 6 次、每次 6 秒的传输, 两次之间停 2 秒;传输期间每秒采样一次站点信息:
for i in $(seq 1 36); do
printf '\n--- sample %s ---\n' "$i" >>"$OUT/station.log"
date +%Y-%m-%dT%H:%M:%S%z >>"$OUT/station.log"
iw dev "$AP" station dump |
sed -n "/Station $CLIENT_MAC/,/^$/p" >>"$OUT/station.log"
sleep 1
done
负载可用 iperf3、内网 HTTP 大文件或其他工具,但两组必须完全一致。客户端记录每次吞吐,AP 记录同一时段
收发的字节数。只改变 vow_atf,重复完整流程:
# A 组:写回 context.txt 中记录的原始值
ORIGINAL_VOW_ATF='<original-value>'
for f in /sys/kernel/debug/ieee80211/phy*/mt76/vow_atf; do
echo "$ORIGINAL_VOW_ATF" >"$f"
done
# B 组:只改变这一个变量
for f in /sys/kernel/debug/ieee80211/phy*/mt76/vow_atf; do
echo 0 >"$f"
done
两组之间不要改变省电设置、信道、BSS 带宽、天线方向、客户端位置或后台流量。如果客户端只支持 40MHz, 还要另做 HE80 与 HE40 的带宽 A/B。测试结束后恢复原值,除非你明确要用工具箱里的开机脚本和 watchdog 持久化新设置。
| 证据 | 为什么需要 | 何时判测试无效 |
|---|---|---|
| 每组 6 个吞吐值 | 判断恢复是否重复出现 | 只保留最好的一次 |
带时间的 station dump |
看见速率如何变化 | 只采样一次速率 |
| AP/客户端字节数 | 区分低物理速率与重传丢包 | 超过约 5% 的差异无法解释 |
| 射频与客户端带宽 | 排除 40MHz 客户端进 80MHz BSS 的混杂因素 | 中途换了带宽或信道 |
| 固件和驱动标识 | 让结论能对应到具体构建 | 测试过程中换了固件 |
预期结果不一定是“B 组每次都从 0 变 400Mbps”。在本次实测里,vow_atf=0 的前几次传输仍然很慢,
约 15 秒后才逐步收敛。真正要验证的是:持续负载下速率是否会收敛,以及这种收敛能否重复。
如果两组都一直快、都一直慢,或者改回一个变量后结果完全不随之变化,只能判为“不确定”,
不能宣称已经找到根因。
7. 不该下的结论
- 别相信单次
tx bitrate采样(它是最后速率,不是均值); - 没做方向测试就别怪客户端(本例上行物理层 600Mbps、实测 188Mbps,完全正常);
- 别用公网镜像做测试:宽带本身的波动会伪装成 Wi-Fi 行为。
相关:80MHz vs 40MHz · OpenWrt 空闲后变慢 · 路由器 CSI 复现
参考与数据来源
本文的每条外部结论都标注来源与证据等级(分级标准);标注 E 级的是本项目可复现的实测数据。
- E 级 · 本项目实测
本项目 10 分钟实测抓包(57,293 条 / 600.0 s,SHA-256 00373f83…95e2)
Router CSI Lab · 2026
okwujun.pw/zh/datasets/ · 核实: 分片重组逐字节校验通过(2026-10-11) · 本地原始母片 SHA-256 为 00373f83…95e2;公开下载的是去标识派生文件,SHA-256 为 527466ce…a440,两者不可混用。 - E 级 · 本项目实测
Router CSI Toolkit — 采集/分析/守护脚本(MIT,公开仓库)
Router CSI Lab · 2026
github.com/jjjwu/router-csi-toolkit · 核实: GitHub API 于 2026-11-02 核实公开仓库、抓包质量预检、成功 CI 与 v0.1.3 Release;归档 SHA-256 为 59f144c0…adea7 · 公开版含无第三方依赖的抓包质量预检;网页端检查器使用同一容器定义和边界口径。