ftrace calico netns问题9 - 小镇

ftrace calico netns问题9

image

 

下面给你一份完整排查方案,目标是定位:

kernel: unregister_netdevice: waiting for eth0 to become free. Usage count = 1

到底是:

  1. 用户态组件泄漏(kubelet / CNI / Calico / container runtime)

  2. 内核 net_device 引用泄漏

  3. 内核网络模块 bug

  4. 某个 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 在释放阶段没有返回。

这一步才能从“确认内核泄漏”推进到“定位哪个模块导致泄漏”。