ftrace calico netns问题1

image

 

Kubernetes/CNI 网络设备删除阻塞问题 RCA 文档

——基于 Linux Netlink、Network Namespace、net_device 引用计数的分析方法


1. 问题背景

1.1 故障现象

节点持续出现:

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

同时:

  • Kubernetes Pod 网络异常;

  • Canal(Calico + Flannel)组件异常;

  • kubelet出现:

CrashLoopBackOff
failed to StartContainer calico-node

表象:

  • docker容器正常;

  • sandbox正常;

  • netns看起来正常;

  • 但是内核持续报警。


2. 核心分析思路

2.1 不从容器看问题,而从内核网络生命周期看问题

很多人看到:

calico异常
pod异常
sandbox异常

第一反应:

找异常容器。

但是这个问题不是容器层问题。

实际对象:

Container
    |
    |
Network Namespace
    |
    |
veth pair
    |
    |
Linux net_device
    |
    |
kernel reference count

最终报错对象:

struct net_device

不是:

  • container

  • pod

  • pause

  • namespace


3. 涉及的基础技术


3.1 Linux Network Namespace

定义

Network Namespace 是 Linux 内核提供的网络隔离机制。

隔离:

  • 网卡

  • IP地址

  • 路由表

  • iptables

  • socket

例如:

宿主机:

namespace A

eth0
lo
cni0

容器:

namespace B

eth0
lo

Kubernetes中的关系

一个Pod:

Pod
 |
 +-- pause container
        |
        +-- Network Namespace
                 |
                 +-- eth0

业务容器:

container
 |
共享
 |
pause network namespace

所以:

docker inspect calico-node

看到:

NetworkMode:
container:<pause id>

是正常设计。


3.2 veth Pair技术

Kubernetes容器网络依靠:

veth pair

实现。

结构:

        Host Namespace

          vethxxxx
             |
             |
          kernel
             |
             |
          eth0

        Pod Namespace

一端在宿主:

vethxxxx

一端在Pod:

eth0

删除Pod:

流程:

kubelet
 |
 CNI DEL
 |
 calico
 |
 删除veth
 |
 kernel释放net_device

3.3 Linux net_device对象

Linux所有网络设备:

eth0
vethxxx
bond0
bridge

最终都是:

struct net_device

管理。

生命周期:

alloc_netdev()
        |
        |
register_netdevice()
        |
        |
使用
        |
        |
unregister_netdevice()
        |
        |
释放

3.4 引用计数(refcount)

Linux内核大量对象使用引用计数。

目的:

防止:

对象正在使用
但是被释放

网络设备:

net_device
    |
    refcount

增加:

dev_hold()

减少:

dev_put()

正常:

创建
 |
ref=1
 |
使用
 |
释放引用
 |
ref=0
 |
free

异常:

创建
 |
ref=1
 |
某模块引用
 |
删除设备
 |
ref=1
 |
永远等待

4. unregister_netdevice报错原理

代码逻辑:

unregister_netdevice()
          |
          |
          v
判断设备是否还有引用
          |
          |
          v
netdev_wait_allrefs()
          |
          |
          v
等待refcount下降

如果:

refcount != 0

打印:

waiting for eth0 to become free
Usage count = 1

5. 为什么不是sandbox泄露

常见误判

认为:

eth0删除失败
=
残留sandbox

实际:

不一定。

sandbox泄露:

pause container存在
 |
netns存在
 |
eth0存在

当前检查:

lsns -t net

没有异常。

检查:

docker ps

没有孤儿。

说明:

问题发生在:

net_device释放阶段

而不是:

namespace阶段

6. 故障定位技术路线

整体思路:

现象
 |
 |
kernel日志
 |
 |
定位内核函数
 |
 |
确定调用入口
 |
 |
定位用户态调用者
 |
 |
定位组件

7. 第一步:确认是不是网络设备删除

日志:

unregister_netdevice

关键词:

unregister

说明:

正在删除设备。


8. 第二步:使用ftrace/kprobe定位调用栈

基础技术

Linux Kernel Trace Framework:

ftrace

能力:

  • 跟踪函数调用;

  • 动态插桩;

  • 获取kernel stack。


kprobe

动态插入探针:

kernel function
       |
       |
       +---- probe

无需重新编译内核。


9. 实际抓取过程

创建probe:

cd /sys/kernel/debug/tracing

echo > kprobe_events

echo \
'p:netmany unregister_netdevice_many' \
> kprobe_events

开启stack:

echo 1 > options/stacktrace

开启:

echo 1 > events/kprobes/netmany/enable

echo 1 > tracing_on

查看:

cat trace_pipe

10. 关键trace分析

得到:

unregister_netdevice_many

notifier_call_chain

netdev_run_todo

rtnetlink_rcv

netlink_sendmsg

SYSC_sendto

11. 这个调用链说明什么?

重点:

rtnetlink_rcv

rtnetlink是什么?

Linux网络配置接口。

用户态:

iproute2

例如:

ip link del vethxxx

底层:

NETLINK_ROUTE socket

发送:

RTM_DELLINK

进入:

rtnetlink_rcv()

因此:

调用链:

用户态
 |
sendto()
 |
NETLINK_ROUTE
 |
kernel
 |
删除网卡

证明:

不是内核主动。

而是:

某个用户态网络组件请求删除设备

12. 第三步:定位用户态调用者

trace:

<...>-188907

PID:

188907

查看:

cat /proc/188907/cmdline

结果:

/opt/cni/bin/calico

cgroup:

system.slice/kubelet.service

说明:

关系:

kubelet
 |
 |
CNI调用
 |
 |
calico binary

13. 最终调用链

完整链路:

Kubernetes Pod生命周期变化

        |
        v

kubelet

        |
        v

调用 CNI DEL

        |
        v

/opt/cni/bin/calico

        |
        v

NETLINK_ROUTE

        |
        v

RTM_DELLINK

        |
        v

unregister_netdevice_many()

        |
        v

发现eth0 refcount=1

        |
        v

等待释放

        |
        v

kernel报警

14. 为什么没有异常进程?

因为:

删除动作已经发生:

calico执行删除
        |
        v
kernel进入删除流程
        |
        v
calico退出

但是:

kernel对象还活着

所以:

ps
docker ps
lsns

可能全部正常。


15. 关闭和恢复方法


15.1 临时停止触发源

停止 kubelet:

systemctl stop kubelet

作用:

停止:

  • Pod调度

  • CNI ADD

  • CNI DEL


15.2 重启Calico

查看:

kubectl -n kube-system get pod | grep canal

删除:

kubectl -n kube-system delete pod canal-vlrk9

DaemonSet自动恢复。


15.3 重启Docker

systemctl restart docker

15.4 节点重启

如果:

Usage count=1

持续:

数分钟以上

说明:

kernel引用无法恢复。

执行:

reboot

16. 关闭trace调试

如果开启过:

进入:

cd /sys/kernel/debug/tracing

关闭:

echo 0 > tracing_on

echo 0 > events/kprobes/netmany/enable

echo > kprobe_events

echo nop > current_tracer

17. 长期治理方案

17.1 升级Calico

原因:

历史版本可能存在:

  • CNI DEL异常;

  • veth删除竞态;

  • 网络资源释放问题。


17.2 升级Kernel

重点:

老版本:

3.10
4.14
4.19早期

存在大量:

  • netns cleanup race

  • veth teardown问题

推荐:

5.4+
5.10+

17.3 升级Docker

避免组合:

旧kernel
+
旧docker
+
旧CNI

18. 故障定位方法论总结

本次采用的方法:

日志现象
    |
    v
确定内核对象(net_device)
    |
    v
分析生命周期(unregister)
    |
    v
ftrace/kprobe动态追踪
    |
    v
找到调用栈
    |
    v
确认netlink入口
    |
    v
定位用户态PID
    |
    v
定位CNI组件

核心技术:

技术作用
Network Namespace 判断容器网络隔离
veth pair 理解Pod网络
net_device 定位内核对象
refcount 理解释放阻塞
Netlink 定位用户态网络操作
rtnetlink 确认删除请求来源
ftrace 获取内核调用路径
kprobe 动态追踪函数

19. 最终RCA结论

根因:

Calico CNI在Pod网络生命周期处理过程中,通过Netlink触发网络设备删除;Linux内核在注销 net_device 时发现仍存在一个引用计数未释放,导致 unregister_netdevice_many() 阻塞,持续打印:

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

定位依据:

  1. 排除sandbox/netns泄露;

  2. kprobe确认进入 unregister_netdevice_many

  3. 调用栈确认来源:

rtnetlink_rcv
 -> netlink_sendmsg
 -> syscall
  1. PID定位:

/opt/cni/bin/calico
  1. cgroup确认:

system.slice/kubelet.service

最终确定:

kubelet -> calico CNI -> rtnetlink -> kernel net_device释放异常

该分析方法适用于所有:

  • Kubernetes CNI网络异常;

  • veth删除失败;

  • netns清理异常;

  • unregister_netdevice卡死;

  • Docker网络泄露问题。

posted on 2026-07-27 23:18  小镇-做题家  阅读(2)  评论(0)    收藏  举报

导航