您好、欢迎来到现金彩票网!
当前位置:手机棋牌游戏平台 > 系统内核 >

「内核模块auth_rpcgss」netns引用计数泄露导致容器弹性网卡残留

发布时间:2019-06-19 22:33 来源:未知 编辑:admin

  原标题:「内核模块auth_rpcgss」netns引用计数泄露导致容器弹性网卡残留

  我们不久前定位了一个Linux内核bug,这个bug会影响所有在特权容器中启用了use-gss-proxy的Linux环境,表现为容器的网络命名空间(net namespace)无法彻底释放,导致容器终止后关联的虚拟网卡未能自动清除,运行时间长的机器上会观察到内存泄露。目前upstream还没有对这个bug的修复,我们内部已经做好了patch待测。

  在k8s环境里,容器终止之后概率性地发生弹性网卡残留现象,而且只有privileged容器才有问题,不加privileged就没问题:

  这个问题在客户的环境里可以稳定复现,但是在容器团队的测试环境无法复现,给排查问题的过程增加了不少障碍。

  思路是这样的:因为测试发现残留的弹性网卡是可以通过ip link del ...命令手工删除的,内核中删除弹性网卡的函数是veth_dellink(),我们可以利用ftrace跟踪veth_dellink()调用,对比正常情况和发生残留的情况,试图搞清楚发生残留的时候有什么异常。ftrace脚本如下:

  以上ftrace脚本观察到正常场景下,tke-eni-cni进程有主动删除网卡的动作,而发生残留的场景下则没有。主动删除网卡的call trace是这样的:

  tke-eni-cni进程不主动删除网卡的原因是net namespace已经被删除了,lsns -t net已经看不到了,在/var/run/docker/netns下也没了。而且net namespace被删除不应该导致虚拟网卡残留,恰恰相反,理论上net namespace销毁的过程中会自动删除关联的弹性网卡,可以通过以下的简单测试来验证,在客户的系统上验证也是没问题的:

  阅读源代码,看到netns的内核数据结构是struct net,其中的count字段表示引用计数,只有当netns的引用计数归零之后才能执行销毁动作:

  用crash工具查看内核,可以看到struct net的引用计数确实没有归零,难怪没有触发销毁动作:

  由于弹性网卡残留现象只出现在privileged容器,那么加不加privileged有什么区别呢?

  对比发现,privileged容器里多了很多后台服务,怀疑是其中某个服务导致了netns引用计数泄露。我们一个一个依次排除,最终找到了直接导致netns泄露的后台服务是:gssproxy。

  可是,容器终止后,在gssproxy后台进程也消失的情况下,netns引用计数仍然不能归零,这就很难解释了,因为用户态进程退出之后应该会释放它占用的所有资源,不应该影响内核,说明问题没那么简单,很可能内核有bug。

  之前容器团队在测试环境里复现不出问题,是因为信息量不够,我们定位到这一步,得到的信息已经可以复现问题了,步骤如下。

  然后创建镜像,并运行它,注意以下第一条命令是执行特权容器,第二条是非特权容器

  然后创建镜像,并运行它,注意以下第一条命令是执行特权容器,第二条是非特权容器

  内核里修改引用计数的函数是get_net和put_net,一个递增,一个递减,通过追踪这两个函数就可以找到导致netns泄露的代码,但是由于它们都是inline函数,所以无法用ftrace或systemtap等工具进行动态追踪,只能自制debug kernel来调试。我们在get_net和put_net中添加了如下代码:

  捕捉到可疑的调用栈如下,auth_rpcgss内核模块中,write_gssp()产生了两次get_net引用,但是容器终止的过程中没有相应的put_net:

  分析源代码,这个问题的根本原因是内核模块auth_rpcgss通过gssp_rpc_create()创建了一个rpc client,因为用到了网络命名空间,所以要递增引用计数。代码路径如下:

  当rpc client关闭的时候,引用计数会相应递减,负责的函数是rpcsec_gss_exit_net(),这是一个回调函数,它什么时候被调用呢?它的调用路径如下:

http://naukritech.com/xitongnahe/205.html
锟斤拷锟斤拷锟斤拷QQ微锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷微锟斤拷
关于我们|联系我们|版权声明|网站地图|
Copyright © 2002-2019 现金彩票 版权所有