Files
x1pro/docs/project_v46_v461_development_and_failures.md
zhangxiaokun 29cf67154a v46.1-ui-mt76: Argon theme + hardened WG tunnel + Link Health dashboard
基于 v46 正式版(mt76)只恢复 UI 层:
- luci-theme-argon 2.4.3: local-background-wins 登录页 + bg1.jpg fallback
- luci-app-argon-config: 去 ui.changes.apply, ACL mutator 移 write
- luci-app-wgtunnel: rpcd ucode 后端(get/status/prepare/apply/rollback/reconnect),
  JSONMap 前端, 60s 一次性 token, 快照回滚, 无全局 network ACL
- luci-app-tr3000-status: 只读 rpcd ucode + 5s 轮询仪表盘
- tools/: audit_ui_packages.py + install_preview.sh + rollback_watchdog.sh
- docs/: 开发经历与翻车记录 + 固件哈希记录

固件本体(含烤入 WG 私钥/PSK)不入 git, 仅 K 盘保存.
kernel 成员与 v46 byte-identical; 尚未刷机.
2026-08-19 15:04:02 +08:00

150 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# v46 / v46.1 换固件开发经历与翻车记录
> 2026-08-17 → 2026-08-19Cudy TR3000 (MT7981B, ImmortalWrt 24.10, mt76, Linux 6.6.151)。
> 本文记录从 mt_wifi 私有驱动迁到 mt76 开源驱动、最终落地 v46 正式版 + v46.1 UI-only 恢复的完整经历,以及每一处翻车的根因。
---
## 一、为什么换固件(动机)
老固件(Gzxhwq mt_wifi 系)在 2026-07 的整个 DBDC/HE160 战役后,数据面仍不稳定:
- **mt_wifi 私有驱动**`wifi reload` 卡死、重启后数据面时好时坏(assoc 正常但 0 数据包)、计数器说谎(Tx=0 但流量在跑)、UCI 状态与物理广播不一致。
- **DBDC merge 字段 swap**UCI 必须反向写才能广播正确,LuCI 显示天然错位,每次开机 ra0/rax0 ↔ dat 绑定还随机。
- **无法 LuCI 完全接管**:改无线要么不生效、要么重启盒子,v25 更是直接变砖(见下)。
用户评估后拍板:**「评估开源的吧」「用官方树重编(干净)」**。
---
## 二、v25 教训(先把它钉死,别让历史重演)
> 用户特别要求把 v25 的教训记进来。它来自 2026-07-20 的 mt_wifi 时代,但教训完全适用 mt76。
**现象**`sysupgrade-v25.bin` 刷入后**无限重启**,必须 U-Boot 回刷 v11 恢复。
**根因**`files/etc/hotplug.d/net/99-wifi-band-sync` 这个脚本,在 `ra*/rax*` netdev up 事件里 `uci commit``netifd reload wifi` → 新的 netdev up 事件 → hotplug 再触发 → **commit→reload→event 死循环**
**三条铁律(对一切新固件生效)**
1. **任何会触发 wifi reload 的逻辑,绝对不允许放进 `hotplug.d/net`**。netdev 事件是 reload 的直接结果,一放进去就是自激回路。
2. **uCI commit 本身不触发 netifd**,结构上不可能循环——只有在 hotplug 事件里主动调 reload 才会。要让状态稳定,要么 commit-only,要么 log-only,绝不 reload。
3. 检测类逻辑要「连续两次读数一致才算稳定」(v24 教训:在驱动 init 中途 30s 抓到瞬态 2.4G 读数把 UCI 改反)。v27 的 commit-only verifier 仍会在 reload 间反复翻 UCI,最终 v28 改 log-only + 显示层 patch 才根治。
---
## 三、mt76 迁移评估(2026-08-17
先做研究(`project_mt76_migration_research.md`):
- **mt76 就是 TR3000 的官方驱动**`DEVICE_PACKAGES=kmod-mt7915e`),Cudy 官方即 mt76。
- **下载腰斩 bug**openwrt/mt76#980):5G 侧已被 commit `0d6eaa4`2025-09-18precal-data offset)修复,构建树的 mt76 `PKG_SOURCE_DATE=2025-11-06` 已包含。2.4G 可能略慢于原厂。
- **WED bug**openwrt/openwrt#20473):WED 开启时可能掉到 ~140Mbps,需要关注。
- **关键决策:不用「嫁接」**——在 mt_wifi 树上恢复 mt76+mac80211-scripts+wifi-scripts 会撞无底洞 patch 冲突(mt_wifi 树用 backports 6.12.6,官方 24.10 用 6.12.96)。**全新克隆官方 `openwrt-24.10``immortalwrt-mt76`**mt76 原生无冲突。
---
## 四、v45.1 六连翻车(2026-08-17 一天六个版本,五个假说全证伪)
### v45.1 — mt76 CLEAN 官方树(md5 `202e4a15...`
干净 mt76 基线 + 移植 WG/VXLAN/隧道。发现 **mt76 macaddr bug**:驱动读到 multicast 位 MAC`d1:fd`)→ hostapd 拒 UP。解法:`wifi-iface` 设合法单播 MAC`fc:a0`),`wifi-device` 层无效。已固化。
### v45.2 — ip-full 修 VXLAN 空壳(md5 `4dd520ac...`
**症状**:刷 v45.1 后「办公室服务完全访问不了」。**真根因**:v45 用了 `ip-tiny``ip link add x type vxlan id 10` 直接报错,netifd vxlan proto 有 bug 建出**空壳 vxlan0**vni/remote/dstport 全空,帧封装不进 VXLAN)。老 mt_wifi 固件有 `ip-full` 所以 20-vxlan 脚本能跑。**修复**`CONFIG_PACKAGE_ip-full=y` + 关 ip-tiny + ip-bridge=y。
### v45.3 — vxlan BUILT-IN 内核(md5 `2b4980ba...`,假说一)
**症状**:仍 RX=0。**假说**`CONFIG_NET_UDP_TUNNEL`/`CONFIG_NET_IP_TUNNEL`/`CONFIG_VXLAN``=m`module),built-in 保证 udp_tunnel encap 基础设施先就绪。**修复尝试**:强制 `=y` built-in,去 kmod-vxlan。另烤入两 iface `uapsd=0`(手机 WiFi 51→2ms,这个保留了下来)。
### v45.6 — 关 JUMP_LABELmd5 `330c923a...`,假说二)
**症状**:仍 RX=0。**kprobe/ftrace 铁证**VXLAN 回程帧到 wg0 后 `udp_queue_rcv_one_skb` 被调 23×,`udp_encap_enable()` 执行(static_branch_inc++),但 `vxlan_rcv` 从不执行 0× → ARM64 6.6.151 的 jump-label patch 没生效(老 6.6.95 没这 bug)。**修复尝试**:关 `CONFIG_JUMP_LABEL` 让 static_branch_unlikely 退化成普通运行时读 key。**仍失败**。
> 假说三(v45.4/997 VXLAN GRO patch、v45.5-dbg/ftrace+kprobe、v45.6/998 WG GRO bypass)全是内核方向,现场抓取证,最终全部证伪,这些实验 patch 在 v46 全清。
### 最终真根因(2026-08-18,v46 前夕)—— 不是内核!
`vxlan0 RX=0` 的真根因是:**`/etc/config/firewall` 只把 `lan` 放 LAN zone、`wan wan6` 放 WAN zone`wg0` 不属于任何 zone**。办公室回程的 VXLAN 包从 wg0 进 INPUTfw4 只接受 br-lan/eth0`10.99.0.2:4789` 落入 `handle_reject`。所以 WG handshake/transfer 正常、wg0 抓得到 ARP Reply,但 vxlan0 RX 恒 0。
**修复**(授权后现场):`uci add_list firewall.@zone[0].network='wg0'` + 重载 fw4。立即 ping 192.168.1.1 8/8、RX +54、HTTP/HTTPS/DNS 正常、OpenClash fake-IP `198.18.25.135`
**血泪总结**v45.1→v45.6 六个版本,两个是环境工具(ip-tiny、macaddr),三个是内核假说(built-in、JUMP_LABEL、GRO/GRO-bypass**全部证伪**,真凶是**防火墙 zone 归属**——`/etc/config/firewall` 里少写一个 `wg0` 的**最普通的一行配置**。**先查配置,再怀疑内核。**
**讽刺的是:为查这个「最简单的地方」,我们把调试下探到了最深——改内核内存**。v45.3 把 `NET_UDP_TUNNEL`/`VXLAN` 强制 built-inv45.6 关 `CONFIG_JUMP_LABEL` 让 jump-label 不再 patch 内核内存里的代码(ARM64 6.6.151 的 static_branch 代码补丁疑似失效);v45.5-dbg 用 kprobe/ftrace 在内核内存里插桩取证据(`udp_queue_rcv_one_skb` 被调 23×、`vxlan_rcv` 0×)。也就是说,从 `uci add_list` 这一行就能修好的问题,我们一路干到动内核内存——**越简单的根因越容易藏在最深的地方,排查顺序应当反过来:先配置、后路由、再 nft、最后才内核。**
---
## 五、v46 正式版落地(2026-08-18
全量 `make dirclean` 构建(kernel 6.6.151`fa661850` 主树 + `350d41da` LuCI feed):
- LAN `br-lan`+`eth1`,管理 IP `192.168.1.2/24`WAN `eth0` DHCP 仅承载自身 + WG underlay
- WG `10.99.0.2/32` ↔ 办公室 `10.99.0.1/32`VXLAN VNI 10/UDP 4789/`nolearning` 入 br-lan
- **`wg0``lan` 同属 LAN zone**(上面真根因的固化)
- 零 forwarding、WAN 无 masq、flow offload 关、`kmod-br-netfilter` + MSS clamp 1330
- 小路由 DHCP/RA/DHCPv6/DNS redirect 全关,客户端由办公室 192.168.1.1 供
- 两路 mt76 AP 保留合法单播 MAC + `uapsd=0`
- `/etc/config/{network,firewall,dhcp,wireless}` 打包权限 `0600`
**产物**`sysupgrade-v46-formal-mt76.bin`14,388,023 bytes, SHA-256 `261bcb92...`)。**已刷机、已实机验收**(WG/VXLAN、防泄漏、MSS 1330、mt76 HE160、1GbE 全达标)。
---
## 六、v46.1 UI-only 恢复(2026-08-19)—— 第二轮翻车
v46 是纯 Bootstrap 基线。用户要恢复 Argon + Bing 壁纸 + WG 隧道插件 + 只读 Link Health 仪表盘。约束:**不恢复 turboacc/HNAT/WARP/BBR/mt_wifi/wrtbwmon 或任何可写加速开关**。
### 翻车 1:`=m` 只编译不进镜像(本轮最坑)
```
首次 make → rootfs 与 v46 完全同尺寸 (10000384 bytes),新增文件 0
```
`.config` 里 5 个 UI 包都是 `=m`module)。**`=m` 只是「编译成 .ipk 但不装入镜像」,进镜像的包必须是 `=y`**。改成 `=y` + `make defconfig` 重编 → rootfs +408KB,新增 70 文件全 UI。
**教训**`make` 成功 ≠ 包进镜像。增量构建后用 `diff -rq` 对比新旧 rootfs 清单,0 新增就该立刻警觉。
### 翻车 2theme-argon 的 6 张图片被源树「删掉」
feeds/luci 工作区里 `argon.svg` logo、**`bg1.jpg` 壁纸 fallback159KB**、`blank.png`、volume×2 全部消失——这就是「登录页背景不显示」的真根因,不是 upstream 没 ship。`git checkout` 恢复。Bing 失败后的本地 `bg1.jpg` fallback 由此生效。
### 翻车 3:前端 `ReferenceError: push is not defined`
Link Health 页面「健康检测全没数据」。根因:后端 ucode 用全局 `push()`,前端 JS 我沿用了 `push(rows, ...)`,但**浏览器 JS 里 `push` 不是全局函数**,必须 `rows.push(...)`。全量扫了三个前端 JS,只此一处。
### 翻车 4(预览期,已修):两个状态解析 bug
- **路由 present=false**:真实路由 `10.99.0.1 dev wg0 scope link` 是正常 host 路由,但 `ip -j` 输出 `dst:"10.99.0.1"`(省略 `/32`),后端只比对 `10.99.0.1/32` 漏判。改为同时接受裸地址与 `/32`
- **vxlan destination_port=null**:真实 `dstport 4789`,但 iproute2 在 JSON 里**省略默认端口字段**。缺省即等于 4789,缺省按 REQUIRED_VXLAN_PORT 处理。
### v46.1 产物与验收(全过)
- `sysupgrade-v46.1-ui-mt76.bin`14,797,623 bytes, SHA-256 `629cc6a3...`),K 盘双份 hash 复核一致
- **kernel 成员与 v46 byte-identical**`366f1c78...`4,375,268 bytes)——增量构建复用 v46 kernel object,绝不 dirclean
- rootfs +408KB:新增 70 文件全 UI,0 删除,**共享文件内容变化 0**
- denylist 零变化:`/etc/config/{network,firewall,dhcp,wireless}`0600)、rc.local、20-vxlan、30-mss-clamp、mss nft 全 hash 一致
- manifest 无禁项:无 turboacc/wrtbwmon/mtkhnat/WARP/mt_wifi/BBR`iw` 6.9-r1 进镜像(Link Health 依赖)
- 烤入的均为硬化版:`rows.push``which_bin` 后端、`handleSaveApply:null` 禁用、sysauth local-wins、无 `ui.changes.apply`
**状态**:增量构建 + 静态验收通过,**尚未刷机/实机验收**。
---
## 七、方法论沉淀
1. **先查配置,再怀疑内核**。v45 的三个内核假说全错,真凶是防火墙 zone 里少写一行 `wg0`——**最简单的地方**。为了修这一行,我们下探到改内核内存(built-in、JUMP_LABEL、kprobe 插桩)全白费。排查顺序永远从浅到深:`/etc/config/*` → 路由表 → nft 规则 → 内核。越简单的根因越藏得深。
2. **`=y` 才进镜像,`=m` 只是 .ipk**。构建完必须解包对比 rootfs 清单,0 增删=没烤进去。
3. **前端 JS 别抄 ucode 语法**`push()`/`match()`/`length()` 在浏览器 JS 里语义完全不同,跨层复用代码前先想清楚运行环境。
4. **netdev/hotplug 里绝不 reload wifi**v25 铁律)。commit-only / log-only 才安全。
5. **内核验证靠对比,不靠直觉**。kernel 成员 byte-identical 是「没动内核」的唯一可靠证据。
6. **预览期就在 live overlay 上验证前端**,bug 修复后立即烤进固件,避免「预览 OK / 固件又坏」的二次翻车。
---
## 八、附:v46.1 提交内容(git)
仓库:`K:\SynologyDrive\学习\Openwrt\.v46.1-ui-src\`commit `ae721f8`
- `luci-theme-argon`local-wins 登录背景 + bg1.jpg fallback
- `luci-app-argon-config`(去 `ui.changes.apply`、ACL mutator 移 write
- `luci-app-wgtunnel`rpcd ucode 后端 get/status/prepare/apply/rollback/reconnect + JSONMap 前端 + 60s 一次性 token + 快照回滚,无全局 network ACL
- `luci-app-tr3000-status`(只读 rpcd ucode + 5s 轮询仪表盘 + which_bin + expect-permissive + rows.push
- `audit_ui_packages.py` + `install_preview.sh` + `rollback_watchdog.sh`