一、问题现象
设备采用 RK3572 + Buildroot,存在两个有线网口:
text
eth0 = 192.168.6.92/24
eth1 = 192.168.6.204/24
gateway = 192.168.6.1

正常开机时:
text
default via 192.168.6.1 dev eth1
default via 192.168.6.1 dev eth0

两个网口均可以独立访问外网:
bash
ping -c 4 www.baidu.com -I eth0
ping -c 4 www.baidu.com -I eth1

但经过:
bash
echo mem > /sys/power/state

休眠唤醒后出现:
text
eth0:公网正常
eth1:局域网正常,但无法访问公网

后续还发现域名解析存在约 7 秒额外等待,甚至出现:
text
ping: www.baidu.com: Temporary failure in name resolution
最终确认存在两个相互独立的问题:
text
问题1:
ConnMan 与 udhcpc 同时管理 eth0/eth1
→ ConnMan 在 resume 后删除 eth1 默认路由
问题2:
ConnMan 与 udhcpc 同时维护 /etc/resolv.conf
→ ConnMan 覆盖有线 DHCP 获取的 DNS
→ 域名解析变慢或失败
二、第一步:先确认是不是物理链路问题
休眠唤醒后先检查:
bash
ifconfig
cat /sys/class/net/eth0/carrier
cat /sys/class/net/eth1/carrier

如果:
text
eth0 carrier = 1
eth1 carrier = 1
同时内核日志有:
text
eth0: Link is Up - 1Gbps/Full
eth1: Link is Up - 1Gbps/Full

说明:
text
PHY恢复正常
GMAC恢复正常
RGMII链路正常
125MHz时钟基本正常
此时不要继续优先排查 YT8531、GMAC、RGMII。
再测试局域网:
bash
ping -c 4 192.168.6.1 -I eth1

如果网关可以正常 ping 通,则进一步说明:
text
eth1 TX/RX正常
ARP正常
局域网路由正常
问题应该继续往三层路由查。
三、第二步:对比休眠前后的路由
正常启动时:
bash
ip route

例如:
text
default via 192.168.6.1 dev eth1
default via 192.168.6.1 dev eth0
192.168.6.0/24 dev eth0 ...
192.168.6.0/24 dev eth1 ...
休眠唤醒后再次执行:
bash
ip route

故障状态发现:
text
default via 192.168.6.1 dev eth0
192.168.6.0/24 dev eth0 ...
192.168.6.0/24 dev eth1 ...
192.168.6.1 dev eth0
192.168.6.1 dev eth1
关键区别:
text
default via 192.168.6.1 dev eth1
消失。
但仍存在:
text
192.168.6.0/24 dev eth1
192.168.6.1 dev eth1
因此可以解释:
text
局域网:
192.168.6.0/24
→ 有直连路由
→ 正常
公网:
0.0.0.0/0
→ 没有 eth1 default
→ 无法访问
到这里就可以把故障定位为:
eth1 默认路由丢失,而不是 eth1 本身无法发送数据。
四、第三步:使用 ip monitor 找出路由什么时候消失
执行:
bash
ip monitor link address route rule
保持该终端运行,然后另一个终端:
bash
echo mem > /sys/power/state
唤醒后查看输出。

本次问题抓到了非常关键的过程:
text
eth1: Link is Up - 1Gbps/Full
192.168.6.204/24 dev eth1
192.168.6.0/24 dev eth1
192.168.6.1 dev eth1
default via 192.168.6.1 dev eth1 metric 4294962175
Deleted default via 192.168.6.1 dev eth1 metric 4294962175
也就是说:
text
eth1 default不是没有恢复
而是:
恢复成功
→ 随后被某个用户空间程序删除
这一点非常重要。
eth1 的 Link、地址、本地路由和 default 都曾经正常恢复,然后 default 被明确删除。
因此排查方向由:
text
驱动为什么没有恢复路由?
转为:
text
哪个用户空间程序把路由删掉了?
五、第四步:确认是不是 udhcpc 删除
首先检查 udhcpc:
bash
ps -ef | grep '[u]dhcpc'

正常看到:
text
udhcpc ... -i eth0
udhcpc ... -i eth1
说明每个接口只有一个 DHCP Client,没有重复启动。
然后确认 udhcpc 使用的脚本:
bash
udhcpc --help

可以看到:
text
-s PROG
Run PROG at DHCP events
(default /usr/share/udhcpc/default.script)
再查看:
bash
/usr/share/udhcpc/default.script

重点关注:
sh
while route del default gw 0.0.0.0 dev $interface
do
:
done
for i in $router
do
route add default gw $i dev $interface
done
为了确认休眠时脚本是否执行,可以在脚本开头加入:
sh
echo "$(date) event=$1 interface=$interface router=$router" \
>> /tmp/udhcpc-debug.log

然后:
bash
rm -f /tmp/udhcpc-debug.log
echo mem > /sys/power/state
cat /tmp/udhcpc-debug.log
实际结果:

text
/tmp/udhcpc-debug.log 不存在
说明:
suspend/resume 过程中 udhcpc 并没有产生 renew/bound 事件。
所以不是 default.script 在 resume 后主动删除 eth1 路由。
六、第五步:手动触发 DHCP renew 验证
BusyBox udhcpc 支持:
SIGUSR1 → Renew lease
因此执行:
bash
kill -USR1 "$(cat /var/run/udhcpc.eth1.pid)"

调试日志显示:
bash
event=[renew]
interface=[eth1]
ip=[192.168.6.204]
router=[192.168.6.1]
staticroutes=[]
最终:
bash
ip route

恢复:
bash
default via 192.168.6.1 dev eth1
default via 192.168.6.1 dev eth0
这证明:
- DHCP服务器正常
- udhcpc正常
- default.script正常
- gateway正常
并进一步确定:
原问题是另一个网络管理组件在操作 eth1 路由。
七、第六步:检查是否存在多个网络管理器
查看启动服务:
bash
ls /etc/init.d/

发现同时存在:
text
S40network
S45connman
系统架构实际上是:
text
S40network
↓
udhcpc
↓
eth0 / eth1
同时:
S45connman
↓
ConnMan
↓
也在管理 eth0 / eth1
也就是说:
text
eth0 / eth1
↑ ↑
│ │
udhcpc ConnMan
│ │
└─冲突─┘
这是一个明显的网络管理所有权冲突。
八、第七步:通过异常 metric 锁定 ConnMan
ip monitor 中还有一条非常关键的信息:
text
default via 192.168.6.1 dev eth1 metric 4294962175

eth1 的 ifindex:

text
5: eth1
计算:
text
UINT32_MAX - ifindex × 1024
即:
text
4294967295 - 5 × 1024
= 4294962175
正好与日志完全一致。
因此这条低优先级默认路由具有明显的 ConnMan 特征。
可以进一步验证:
bash
/etc/init.d/S45connman stop

执行后观察到:
text
eth1: Link is Down
eth0: Link is Down
说明:
ConnMan 确实已经接管 eth0 和 eth1。
最终可以确认路由问题根因:
text
S40network/udhcpc
+
ConnMan
同时管理 eth0/eth1
↓
ConnMan选择一个default service
↓
另一个网口变成低优先级default
↓
resume重新选择service
↓
删除eth1 default
↓
eth1无法访问公网
九、路由问题最终解决方案
让 ConnMan 永久忽略 eth0、eth1。
创建:
text
/etc/connman/main.conf

内容:
ini
[General]
NetworkInterfaceBlacklist=eth0,eth1,vmnet,vboxnet,virbr,ifb,ve-,vb-,ham,veth
最终职责:
text
eth0/eth1
↓
S40network + udhcpc
wlan0
↓
ConnMan
重启后重新测试:
bash
ip route
ping -c 4 www.baidu.com -I eth0
ping -c 4 www.baidu.com -I eth1

再:
bash
echo mem > /sys/power/state

唤醒后确认:
text
default via 192.168.6.1 dev eth0
default via 192.168.6.1 dev eth1
均仍存在。
十、第八步:发现域名访问明显变慢
解决路由冲突以后,又发现:
bash
time ping -c 4 www.baidu.com -I eth0

实际 RTT:
text
3~4 ms
但总耗时:
text
约18秒
首先绕过 DNS:
bash
time ping -n -c 4 -I eth0 183.2.172.177
time ping -n -c 4 -I eth1 183.2.172.177

结果:
text
real ≈ 3.0s
这说明:
text
PHY正常
路由正常
公网正常
ICMP正常
额外约7秒:
发生在DNS解析阶段
十一、第九步:检查 resolv.conf
执行:
bash
cat /etc/resolv.conf

发现:
text
# Generated by Connection Manager
nameserver ::1
nameserver 127.0.0.1
nameserver 192.168.6.1 # eth0
nameserver 192.168.6.1 # eth1
其中:
text
::1
127.0.0.1
是 ConnMan DNS Proxy。
临时测试:
bash
echo "nameserver 192.168.6.1" > /etc/resolv.conf

重新:
bash
time ping -c 4 www.baidu.com -I eth0
time ping -c 4 www.baidu.com -I eth1
结果从:
text
≈18秒
恢复到:
text
≈3秒
因此确认:
localhost DNS proxy 是第一次 DNS 延迟的直接原因。
十二、第十步:关闭 ConnMan DNS Proxy
S45connman 中有:
sh
CONNMAND_ARGS="-n"
[ -r "/etc/default/$DAEMON" ] && \
. "/etc/default/$DAEMON"

因此无需修改 init 脚本。
创建:
text
/etc/default/connmand

内容:
sh
CONNMAND_ARGS="-n --nodnsproxy"
重启以后:
bash
ps -ef | grep '[c]onnmand'

确认:
text
connmand -n --nodnsproxy
然后:
bash
cat /etc/resolv.conf

localhost:
text
::1
127.0.0.1
已经消失。

域名 ping 恢复约 3 秒。
十三、第十一步:继续稳定性测试发现 resolv.conf 仍被覆盖
进行多次网络测试后,两个有线口连续 20 次访问均正常,RTT 基本在 3.5~4.5 ms,未出现丢包。
但后续又出现:
bash
cat /etc/resolv.conf

变成:
text
# Generated by Connection Manager
nameserver fe80::6a1:51ff:fe94:5969
原来的:
text
nameserver 192.168.6.1 # eth0
nameserver 192.168.6.1 # eth1
全部消失。
然后:
bash
ping www.baidu.com -I eth0
ping www.baidu.com -I eth1
均报:
text
Temporary failure in name resolution
但 eth0、eth1 IP 地址仍然正常。
这说明:
text
路由问题已经解决
但是:
ConnMan
+
udhcpc
仍然同时写:
/etc/resolv.conf
所以:
text
--nodnsproxy
只是关闭 DNS Proxy,
并不等于:
text
ConnMan 不修改 resolv.conf
十四、DNS问题最终解决方案
最终必须让 /etc/resolv.conf 也只有一个管理者。
由于 eth0/eth1 已经交给:
text
S40network + udhcpc
因此 DNS 也统一由 udhcpc 维护。
最终 /etc/connman/main.conf:
ini
[General]
NetworkInterfaceBlacklist=eth0,eth1,vmnet,vboxnet,virbr,ifb,ve-,vb-,ham,veth
ResolvConf=/dev/null
其中:
text
NetworkInterfaceBlacklist
解决:
text
ConnMan 与 udhcpc 路由冲突
而:
text
ResolvConf=/dev/null
解决:
text
ConnMan 与 udhcpc 同时修改 /etc/resolv.conf
/etc/default/connmand:
sh
CONNMAND_ARGS="-n --nodnsproxy"
最终结构:
text
RK3572
│
┌────────────┴────────────┐
│ │
eth0 / eth1 wlan0
│ │
▼ ▼
S40network + udhcpc ConnMan
│ │
IP / Route / DNS Wi-Fi管理
│
▼
/etc/resolv.conf
ConnMan:
× 不管理 eth0
× 不管理 eth1
× 不启用 DNS Proxy
× 不修改 /etc/resolv.conf
十五、最终排查思路总结
遇到"休眠唤醒后某个网口无法联网"时,不要直接修改驱动,可以按以下顺序判断:
- 检查 Link
bash
ifconfig
cat /sys/class/net/eth1/carrier
Link 正常则继续。
- 测试网关
bash
ping 192.168.6.1 -I eth1
网关正常而公网失败,优先检查路由。
- 检查路由
bash
ip route
检查是否缺:
text
default via ... dev eth1
- 使用 ip monitor
bash
ip monitor link address route rule
观察到底是:
text
default根本没有添加
还是:
text
default添加后又被删除
这两类问题完全不同。
- 确认是谁管理网络
bash
ps -ef | grep '[u]dhcpc'
ls /etc/init.d/
ps -ef | grep '[c]onnman'
如果发现:
text
udhcpc + ConnMan
同时管理同一个接口,就要优先解决所有权冲突。
- IP访问正常、域名访问慢
先:
bash
time ping -n -c 4 183.2.172.177
再:
bash
time ping -c 4 www.baidu.com
如果 IP 快、域名慢:
text
直接查 DNS
- 检查 DNS 所有权
bash
cat /etc/resolv.conf
再确认:
text
谁写这个文件?
最终应该遵守一个原则:
同一个网络资源尽量只有一个管理者。
本次问题最终就是因为:
text
路由:
udhcpc + ConnMan 双管理
DNS:
udhcpc + ConnMan 双管理
导致两个不同阶段的网络异常。
最终通过明确管理边界解决:
text
Ethernet → S40network/udhcpc
Wi-Fi → ConnMan
DNS → udhcpc