searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Linux namespace bug导致上不了网问题排查过程

2023-04-28 06:13:35
142
0

Linux namespace bug导致上不了网问题排查过程

 

1问题现象

 

计算节点的namespace出问题了,系统卡住了,导致这台上的所有虚机都上不了网

 

2分析过程

 

sudo ip netns list 有报错

TNETLINK answers: Invalid argument

 

sudo strace ip netns list发现 有

Peer netns reference is invalid

 

2.1添加ns 卡住——拿不到锁

sudo ip netns add mmm

 

 

打印进程调用栈看到卡在copy_net_ns函数:

 

进一步分析是卡在net_mutex锁的获取那里。可能别的进程拥有了这个锁迟迟不释放,导致程序一致卡住这里。

 

2.2 Kworker进程cpu 100%

 

同事xx发现出问题的节点中必有一个kworker cpu为100%

 

 

上工具,通过perf性能剖析工具看看热点在哪里?

 

初看这个函数是协议栈中ip分片功能的函数,感觉和netns没有什么关联啊。一开始也觉得这里没有什么问题,后来排查其他功能也没有收获之后,又回到这里来分析。

 

2.3 Kprobe调试内核函数调用链

 

用kprobe工具(不做介绍自行搜索了解),看看到底是谁调用了inet_evict_bucket函数,具体代码见下面这两个文件:

 

 

直接make生成ko文件,如果编译有问题请百度

insmod xx.ko,动态加载模块到内核

在dmesg会看到相应的内核调用栈信息,如下:

[Tue Jun  2 16:04:34 2020] CPU: 7 PID: 29371 Comm: kworker/u128:1 Tainted: G           O     4.16.13-1.el7.elrepo.x86_64 #1

[Tue Jun  2 16:04:34 2020] Workqueue: netns cleanup_net

[Tue Jun  2 16:04:34 2020] Call Trace:

[Tue Jun  2 16:04:34 2020]  dump_stack+0x63/0x88

[Tue Jun  2 16:04:34 2020]  ? inet_evict_bucket.isra.8+0x1/0x120

[Tue Jun  2 16:04:34 2020]  handler_pre+0x35/0x39 [kprobe_demo]

[Tue Jun  2 16:04:34 2020]  kprobe_ftrace_handler+0x90/0xf0

[Tue Jun  2 16:04:34 2020]  ftrace_ops_assist_func+0x62/0xf0

[Tue Jun  2 16:04:34 2020]  ? inet_evict_bucket.isra.8+0x1/0x120

[Tue Jun  2 16:04:34 2020]  ? inet_evict_bucket.isra.8+0x5/0x120

[Tue Jun  2 16:04:34 2020]  ? inet_frags_exit_net+0x51/0xa0

[Tue Jun  2 16:04:34 2020]  ? inet_evict_bucket.isra.8+0x5/0x120

[Tue Jun  2 16:04:34 2020]  ? inet_frags_exit_net+0x51/0xa0

[Tue Jun  2 16:04:34 2020]  ? ipv4_frags_exit_net+0x3a/0x40

[Tue Jun  2 16:04:34 2020]  ? ops_exit_list.isra.6+0x3b/0x70

[Tue Jun  2 16:04:34 2020]  ? cleanup_net+0x212/0x320

[Tue Jun  2 16:04:34 2020]  ? process_one_work+0x15f/0x370

[Tue Jun  2 16:04:34 2020]  ? worker_thread+0x4d/0x3e0

[Tue Jun  2 16:04:34 2020]  ? kthread+0x105/0x140

[Tue Jun  2 16:04:34 2020]  ? max_active_store+0x80/0x80

[Tue Jun  2 16:04:34 2020]  ? kthread_bind+0x20/0x20

[Tue Jun  2 16:04:34 2020]  ? do_syscall_64+0x79/0x1b0

[Tue Jun  2 16:04:34 2020]  ? ret_from_fork+0x35/0x40

[Tue Jun  2 16:04:34 2020] <inet_evict_bucket.isra.8> post_handler: p->addr = inet_evict_bucket.isra.8+0x0/0x120, flags = 0x206

 

2.4 cleanup_net函数——持锁不放

看了cleanup_net函数的代码来解释现象:

因为cleanup_net函数拥有了net_mutex锁,并且在这个锁里做了很耗时的操作(类似死循环),导致锁迟迟等不到释放。而新建的netns是要成功获取到锁以后才可以,现在锁被别人占用了,只能一直等一直等就好像卡死了一样。这就解释了为什么出现问题的节点上,新建netns卡住了。

 

接下来我们就要搞清楚cleanup net为什么要那么耗时,拿住锁一直不释放。

ops_free_list辗转调用到inet_frags_exit_net 函数 inet_evict_bucket

 

结合之前的kprobe信息,这里确实有一个死循环

 

每次239行的if都为真,直接goto evict_again,所以变成的死循环。

1)要么顺序锁的writer一直在操作,所以这里的顺序锁reader一直要retry,但是前面perf看到的调用里面顺序锁并不是热点,所以排除顺序锁的问题。

2)那就怀疑sum_frag_mem_limit(nf)试试?sum_frag_mem_limit(nf)是干什么的?简单来说,就是看看所有分片是不是都处理完,如果是那就返回0,否则返回非0.

 

本来我们想在出现问题的机器上,通过kprobe去打印nf的值看看是不是不为0.但是由于此时已经死循环了,好像也没有什么办法。

 

然后在一台虚机上,把内核源码的239行sum_frag_mem_limit(nf)直接用1替代,重编以后。系统启动以后kworker cpu 100%,新建netns为空,坎函数调用栈、perf热点,现象一致,我们更加相信是协议栈分片的问题导致的了。但是要花时间去搞懂分片的原理,这个估计很花时间不太现实。

 

2.5 协议栈分片重组有问题导致bug

基于上面的分析,接下里我们就是漫长的搜索和查看提交记录,找到确实有这样的bug并且有了patch。

 

简单来说就是分片重组有问题导致即使分片处理完了sum_frag_mem_limit(nf) 不为0,当del netns的时候inet_frags_exit_net进入死循环。

 

The underlying issue is that a kworker thread (executing cleanup_net) spins in inet_frags_exit_net, waiting for sum_frag_mem_limit(nf) to become zero, which never happens becacuse it has underflowed to some negative multiple of 64. That kworker thread keeps holding net_mutex and therefore blocks any further

https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1765980

 

 

https://github.com/torvalds/linux/commit/ebaf39e6032faf77218220707fc3fa22487784e0

 

https://cdn.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.19.10

 

 

4结论

Kernel 4.16 是否有这个bug?存在

 

解决办法:

直接升级到内核4.19.10以后

 

0条评论
0 / 1000
阿莫西林的杂货铺
12文章数
0粉丝数
阿莫西林的杂货铺
12 文章 | 0 粉丝
原创

Linux namespace bug导致上不了网问题排查过程

2023-04-28 06:13:35
142
0

Linux namespace bug导致上不了网问题排查过程

 

1问题现象

 

计算节点的namespace出问题了,系统卡住了,导致这台上的所有虚机都上不了网

 

2分析过程

 

sudo ip netns list 有报错

TNETLINK answers: Invalid argument

 

sudo strace ip netns list发现 有

Peer netns reference is invalid

 

2.1添加ns 卡住——拿不到锁

sudo ip netns add mmm

 

 

打印进程调用栈看到卡在copy_net_ns函数:

 

进一步分析是卡在net_mutex锁的获取那里。可能别的进程拥有了这个锁迟迟不释放,导致程序一致卡住这里。

 

2.2 Kworker进程cpu 100%

 

同事xx发现出问题的节点中必有一个kworker cpu为100%

 

 

上工具,通过perf性能剖析工具看看热点在哪里?

 

初看这个函数是协议栈中ip分片功能的函数,感觉和netns没有什么关联啊。一开始也觉得这里没有什么问题,后来排查其他功能也没有收获之后,又回到这里来分析。

 

2.3 Kprobe调试内核函数调用链

 

用kprobe工具(不做介绍自行搜索了解),看看到底是谁调用了inet_evict_bucket函数,具体代码见下面这两个文件:

 

 

直接make生成ko文件,如果编译有问题请百度

insmod xx.ko,动态加载模块到内核

在dmesg会看到相应的内核调用栈信息,如下:

[Tue Jun  2 16:04:34 2020] CPU: 7 PID: 29371 Comm: kworker/u128:1 Tainted: G           O     4.16.13-1.el7.elrepo.x86_64 #1

[Tue Jun  2 16:04:34 2020] Workqueue: netns cleanup_net

[Tue Jun  2 16:04:34 2020] Call Trace:

[Tue Jun  2 16:04:34 2020]  dump_stack+0x63/0x88

[Tue Jun  2 16:04:34 2020]  ? inet_evict_bucket.isra.8+0x1/0x120

[Tue Jun  2 16:04:34 2020]  handler_pre+0x35/0x39 [kprobe_demo]

[Tue Jun  2 16:04:34 2020]  kprobe_ftrace_handler+0x90/0xf0

[Tue Jun  2 16:04:34 2020]  ftrace_ops_assist_func+0x62/0xf0

[Tue Jun  2 16:04:34 2020]  ? inet_evict_bucket.isra.8+0x1/0x120

[Tue Jun  2 16:04:34 2020]  ? inet_evict_bucket.isra.8+0x5/0x120

[Tue Jun  2 16:04:34 2020]  ? inet_frags_exit_net+0x51/0xa0

[Tue Jun  2 16:04:34 2020]  ? inet_evict_bucket.isra.8+0x5/0x120

[Tue Jun  2 16:04:34 2020]  ? inet_frags_exit_net+0x51/0xa0

[Tue Jun  2 16:04:34 2020]  ? ipv4_frags_exit_net+0x3a/0x40

[Tue Jun  2 16:04:34 2020]  ? ops_exit_list.isra.6+0x3b/0x70

[Tue Jun  2 16:04:34 2020]  ? cleanup_net+0x212/0x320

[Tue Jun  2 16:04:34 2020]  ? process_one_work+0x15f/0x370

[Tue Jun  2 16:04:34 2020]  ? worker_thread+0x4d/0x3e0

[Tue Jun  2 16:04:34 2020]  ? kthread+0x105/0x140

[Tue Jun  2 16:04:34 2020]  ? max_active_store+0x80/0x80

[Tue Jun  2 16:04:34 2020]  ? kthread_bind+0x20/0x20

[Tue Jun  2 16:04:34 2020]  ? do_syscall_64+0x79/0x1b0

[Tue Jun  2 16:04:34 2020]  ? ret_from_fork+0x35/0x40

[Tue Jun  2 16:04:34 2020] <inet_evict_bucket.isra.8> post_handler: p->addr = inet_evict_bucket.isra.8+0x0/0x120, flags = 0x206

 

2.4 cleanup_net函数——持锁不放

看了cleanup_net函数的代码来解释现象:

因为cleanup_net函数拥有了net_mutex锁,并且在这个锁里做了很耗时的操作(类似死循环),导致锁迟迟等不到释放。而新建的netns是要成功获取到锁以后才可以,现在锁被别人占用了,只能一直等一直等就好像卡死了一样。这就解释了为什么出现问题的节点上,新建netns卡住了。

 

接下来我们就要搞清楚cleanup net为什么要那么耗时,拿住锁一直不释放。

ops_free_list辗转调用到inet_frags_exit_net 函数 inet_evict_bucket

 

结合之前的kprobe信息,这里确实有一个死循环

 

每次239行的if都为真,直接goto evict_again,所以变成的死循环。

1)要么顺序锁的writer一直在操作,所以这里的顺序锁reader一直要retry,但是前面perf看到的调用里面顺序锁并不是热点,所以排除顺序锁的问题。

2)那就怀疑sum_frag_mem_limit(nf)试试?sum_frag_mem_limit(nf)是干什么的?简单来说,就是看看所有分片是不是都处理完,如果是那就返回0,否则返回非0.

 

本来我们想在出现问题的机器上,通过kprobe去打印nf的值看看是不是不为0.但是由于此时已经死循环了,好像也没有什么办法。

 

然后在一台虚机上,把内核源码的239行sum_frag_mem_limit(nf)直接用1替代,重编以后。系统启动以后kworker cpu 100%,新建netns为空,坎函数调用栈、perf热点,现象一致,我们更加相信是协议栈分片的问题导致的了。但是要花时间去搞懂分片的原理,这个估计很花时间不太现实。

 

2.5 协议栈分片重组有问题导致bug

基于上面的分析,接下里我们就是漫长的搜索和查看提交记录,找到确实有这样的bug并且有了patch。

 

简单来说就是分片重组有问题导致即使分片处理完了sum_frag_mem_limit(nf) 不为0,当del netns的时候inet_frags_exit_net进入死循环。

 

The underlying issue is that a kworker thread (executing cleanup_net) spins in inet_frags_exit_net, waiting for sum_frag_mem_limit(nf) to become zero, which never happens becacuse it has underflowed to some negative multiple of 64. That kworker thread keeps holding net_mutex and therefore blocks any further

https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1765980

 

 

https://github.com/torvalds/linux/commit/ebaf39e6032faf77218220707fc3fa22487784e0

 

https://cdn.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.19.10

 

 

4结论

Kernel 4.16 是否有这个bug?存在

 

解决办法:

直接升级到内核4.19.10以后

 

文章来自个人专栏
网络疑难杂症
12 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0