用于个人记录,方便以后排查。
我的环境是 ImmortalWrt 24.10.5 x86_64 firewall4 ,遇到的问题是:
1 | /cgi-bin/luci/admin/services/nlbw |
页面能打开,但是一直没有任何统计数据。
问题现象
一开始怀疑是 LuCI 页面问题,或者是编译固件时包没带全,但实际上:
nlbwmon服务是正常运行的luci-app-nlbwmon也已经安装/proc/net/nf_conntrack里能看到大量连接- 但
nlbw -c show和页面里都没有任何数据
检查版本时,设备信息如下:
1 | ImmortalWrt 24.10.5 r33805-7c4e882aaf6f |
初步排查
先确认服务本身是不是正常:
1 | service nlbwmon status |
这一步看下来没有明显异常,nlbwmon 的确在运行。
再看统计结果:
1 | nlbw -c show |
返回是空的:
1 | {"columns":["family","proto","port","mac","ip","conns","rx_bytes","rx_pkts","tx_bytes","tx_pkts","layer7"],"data":[]} |
但与此同时,系统连接跟踪表不是空的:
1 | wc -l /proc/net/nf_conntrack |
这说明不是没有流量,也不是内核没记录连接,而是 nlbwmon 没有把这些连接转成自己的统计数据。
先处理两个常见干扰项
先检查防火墙里是否开启了流量分载:
1 | uci show firewall | grep flow_offloading |
如果有下面这种配置:
1 | firewall.@defaults[0].flow_offloading='1' |
建议先关掉,因为这类按主机统计的工具很容易受快速转发影响。
1 | uci set firewall.@defaults[0].flow_offloading='0' |
另外我这台机器里,nlbwmon 的 local_network 默认配置也有问题。
原配置包含:
1 | 192.168.0.0/16 |
而实际 WAN 地址是 10.250.4.238 ,属于运营商 CGNAT 的 10.x.x.x 网段。
这样一来,10.0.0.0/8 会把 WAN 地址也误判成本地地址,导致部分连接判断出错。
所以我把 local_network 收窄成只保留真正要统计的接口:
1 | uci -q delete nlbwmon.@nlbwmon[0].local_network |
这两步是必要修正,但还不是最终根因。
最终定位
后来参考了社区 issue,尝试执行下面这组命令:
1 | service nlbwmon stop |
结果这一次统计立刻出来了,直接能看到内网设备的流量:
1 | IPv4 10.10.10.104 HTTPS |
到这里就可以基本确认:
- 不是 LuCI 页面坏了
- 不是
nlbwmon没启动 - 问题核心在
nf_conntrack_netlink
为什么会有这个问题
nlbwmon 依赖的是 conntrack 事件,而不是简单扫一次页面或者扫一次 IP 列表。
也就是说,nlbwmon 要想正常建立和更新统计数据,需要从内核的 nf_conntrack_netlink 收到新连接、连接销毁、连接统计变化之类的事件。
这台机器上的实际情况是:
/proc/net/nf_conntrack有数据nf_conntrack_acct=1nf_conntrack_events=1nlbwmon进程本身也在运行
但 nlbwmon 启动后,拿不到正常可用的 nf_conntrack_netlink 事件,所以最终表现就是:
- 数据库长期是空的
- 新设备不会建立统计记录
- LuCI 页面一直没有数据
结合这次实机验证,以及 ImmortalWrt 相关 issue 的讨论,比较合理的结论是:
ImmortalWrt某些版本下,nf_conntrack_netlink在firewall4环境中的初始化状态异常,导致nlbwmon启动后无法正常接收或处理连接跟踪事件。
所以这不是单纯配置写错,而是一类已经有人复现过的兼容性回归问题。
解决方法
我的处理方式分三步:
第一步,关闭 offloading:
1 | uci set firewall.@defaults[0].flow_offloading='0' |
第二步,修正 local_network:
1 | uci -q delete nlbwmon.@nlbwmon[0].local_network |
第三步,重载 nf_conntrack_netlink:
1 | service nlbwmon stop |
执行后等待 30 到 60 秒,再刷新:
1 | /cgi-bin/luci/admin/services/nlbw |
一般就可以看到数据出来了。
持久化修复
如果只是手工执行一次上面的命令,当前这次开机是正常的,但以后升级固件时,之前直接修改的包文件很可能会被覆盖。
比如直接修改下面这个文件:
1 | /etc/init.d/nlbwmon |
这种方式虽然短期有效,但它属于包自带脚本,系统升级后通常会恢复成新固件里的默认版本,不适合作为长期持久化方案。
更稳妥的做法是:
- 不再直接修改
/etc/init.d/nlbwmon - 新建一个自己的启动脚本
- 再把这个脚本加入
sysupgrade保留列表
我实际采用的是下面这个方案。
先新建:
1 | /etc/init.d/nlbwmon-fix |
内容如下:
1 |
|
然后赋予执行权限并启用:
1 | chmod +x /etc/init.d/nlbwmon-fix |
接着把它加入:
1 | /etc/sysupgrade.conf |
追加这一行:
1 | /etc/init.d/nlbwmon-fix |
也可以直接用命令完成:
1 | if ! grep -qx '/etc/init.d/nlbwmon-fix' /etc/sysupgrade.conf 2>/dev/null; then |
这样做的好处是:
- 重启时会自动执行修复逻辑
- 升级固件时,只要保留配置,这个脚本也会一起保留下来
- 不依赖包内部实现,后续
nlbwmon包更新时也不容易被冲掉
相比直接修改 /etc/init.d/nlbwmon,这个方式更适合长期使用。
一键修复命令
如果只是想快速修复,可以直接执行下面这一组:
1 | uci set firewall.@defaults[0].flow_offloading='0' |
如果想长期稳定使用,建议继续按上面的方式创建 /etc/init.d/nlbwmon-fix 并加入 /etc/sysupgrade.conf。
注意事项
flow offloading和hardware flow offloading可能会影响这类按主机统计的插件,建议关闭。- 如果 WAN 走的是 CGNAT,比如
10.x.x.x,不要直接把10.0.0.0/8这种大私网段留在local_network里。 - 这个问题不是你一个人遇到,ImmortalWrt 的多个版本、多个设备上都有人复现。
- 如果系统升级后再次失效,通常重新执行下面这组命令就能恢复:
1 | rmmod nf_conntrack_netlink |
- 根据 issue 里的反馈,即使临时恢复,IPv6 新地址统计在某些场景下仍然可能不完全稳定。
- 如果想让修复在固件升级后依旧保留,建议把自定义脚本加入
/etc/sysupgrade.conf,不要只手改包自带的/etc/init.d/nlbwmon。