ftrace calico netns问题9

下面给你一份完整排查方案,目标是定位:
kernel: unregister_netdevice: waiting for eth0 to become free. Usage count = 1
到底是:
-
用户态组件泄漏(kubelet / CNI / Calico / container runtime)
-
内核 net_device 引用泄漏
-
内核网络模块 bug
-
某个 notifier / driver 持有 eth0 引用
1. 问题原理
1.1 内核网络设备删除流程
Kubernetes 删除 Pod 网络:
kubectl delete pod||kubelet||CNI DEL||calico CNI binary||netlink||rtnetlink_rcv()||netdev_run_todo()||unregister_netdevice_many()||unregister_netdevice()||netdev_wait_allrefs()||dev->refcnt != 0||
打印:
unregister_netdevice:
waiting for eth0 to become free
Usage count = 1
2. 第一阶段:确认是不是 CNI/IPAM 问题
2.1 查看 CNI cache
目录:
ls -al /var/lib/cni/networks/k8s-pod-network/
检查目标 IP:
例如:
172.18.105.238
查看:
cat /var/lib/cni/networks/k8s-pod-network/172.18.105.238
正常:
container-id
表示:
IPAM知道是谁占用。
2.2 查询 Pod
控制节点:
kubectl get pod -A -o wide | grep 172.18.105.238
如果:
pod exists
正常。
如果:
没有pod
但是:
CNI cache存在
说明:
IPAM泄漏。
3. 第二阶段:确认 veth 是否残留
节点:
ip link | grep cali
找到:
例如:
cali71340cd83ea
查询:
ip addr show cali71340cd83ea
确认:
172.18.105.238
如果:
Pod不存在
但是:
cali设备存在
属于:
CNI DEL失败。
4. 第三阶段:确认是不是 kernel refcount
查看设备:
ip link show eth0
查看:
state UP
然后:
cat /proc/net/dev
确认eth0存在。
5. ftrace定位删除来源
你的内核不支持:
dev_hold
dev_put
netdev_wait_allrefs
所以不能直接抓。
抓入口。
5.1 清空 ftrace
进入:
cd /sys/kernel/debug/tracing
关闭:
echo 0 > tracing_on
清理:
echo > traceecho > kprobe_events
恢复:
echo nop > current_tracer
6. 抓 unregister 调用栈
创建kprobe:
echo 'p:netdel unregister_netdevice_many' > kprobe_events
开启stack:
echo 1 > options/stacktrace
开启:
echo 1 > events/kprobes/netdel/enable
启动:
echo 1 > tracing_on
查看:
cat trace_pipe
正常看到:
类似:
unregister_netdevice_many
notifier_call_chain
call_netdevice_notifiers_info
netdev_run_todo
rtnetlink_rcv
netlink_sendmsg
sys_sendto
说明:
删除来自 netlink。
你的结果已经证明:
calico CNI-> netlink-> kernel
7. 抓是谁触发 netlink 删除
继续增加:
echo 'p:rtnl rtnetlink_rcv' > kprobe_events
开启:
mkdir -p events/kprobes/rtnlecho 1 > events/kprobes/rtnl/enable
查看:
cat trace_pipe
重点:
PID。
例如:
<...>-188907
查询:
cat /proc/188907/cmdline
你的结果:
/opt/cni/bin/calico
说明:
来源:
calico CNI DEL
8. 判断是不是 Calico 问题
检查:
8.1 calico daemon
kubectl get pod -n kube-system -o wide | grep calico
检查:
kubectl logs calico-node-xxx -n kube-system
8.2 CNI DEL日志
查看:
journalctl -u kubelet | grep CNI
关注:
DEL
ADD
GC
failed
9. 判断 GC 问题还是 kernel bug
用户态泄漏特征
满足:
Pod不存在
+
container不存在
+
netns不存在
+
cni cache存在
+
cali设备存在
处理:
清理:
CNI cache
+
残留veth
内核bug特征
满足:
Pod正常
+
IPAM正常
+
cali正常
+
没有残留netns
+
持续:unregister_netdevice
Usage count=1
你的情况:
符合:
内核引用未释放
10. 查 eth0 谁持有引用
方法A:检查 notifier
创建:
echo > kprobe_eventsecho 'p:notifier call_netdevice_notifiers_info' > kprobe_events
开启:
echo 1 > events/kprobes/notifier/enable
观察:
cat trace_pipe
方法B:抓 unregister_queue
echo > kprobe_eventsecho 'p:queue unregister_netdevice_queue' > kprobe_eventsecho 1 > events/kprobes/queue/enable
11. 最终修复措施
临时恢复
删除异常pod
kubectl delete pod xxx -n xxx
删除残留cali
确认:
ip link show | grep cali
删除:
ip link delete calixxxxx
重启 kubelet
systemctl restart kubelet
如果仍然:
Usage count=1
只能:
reboot
原因:
net_device refcount 已经泄漏。
用户态无法减少。
12. 长期解决
12.1 检查内核版本
uname -r
重点:
老内核:
3.10
4.14
4.18
存在大量:
net_device refcount
veth
namespace teardown
问题。
12.2 升级组件
建议:
| 组件 | 建议 |
|---|---|
| kernel | 升级最新稳定LTS |
| Calico | 升级 >= 3.26 |
| CNI plugins | 升级 |
| containerd/docker | 升级 |
| kubelet | 保持一致版本 |
13. 当前你的结论
根据已有证据:
CNI IPAM cache 正常
Pod IP 正常
ARP 正常
Calico daemon 非根因
kubelet 调用CNI DEL
calico binary 触发netlink删除
kernel unregister 卡住
eth0 refcount 泄漏1
最终链路:
Pod删除|
kubelet|
calico CNI DEL|
rtnetlink|
unregister_netdevice_many|
eth0 refcount !=0|
kernel warning
下一步最关键抓:
echo 'p:notifier call_netdevice_notifiers_info' > kprobe_events
看哪个网络 notifier 在释放阶段没有返回。
这一步才能从“确认内核泄漏”推进到“定位哪个模块导致泄漏”。