阿里云开发者 2024年10月01日
内核网络小白之故障寻踪记
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文记录了一次由 skb(socket buffer)异常导致的内核故障排查过程。故障发生在集团搜索服务升级内核版本后,频繁出现内核故障,仅发生在午夜 0 点,并呈现出扩大的趋势。通过分析 vmcore 和 Aone 的历史记录,确定了故障是由 skb 结构体成员异常导致的内核恐慌问题。通过进一步分析,发现故障发生时,skb 指向的数据报文的实际长度小于其数据长度,且 len 和 data_len 总差 4 个字节。最终排查到第三方内核模块 sn_core_odd 由于内核 5.10 中 skb_make_writable 接口的变化导致了异常。

🤔 **故障现象:** 搜索服务在升级内核版本后,频繁出现内核故障,仅发生在午夜 0 点,并呈现出扩大的趋势。

🕵️ **故障定位:** 通过分析 vmcore 和 Aone 的历史记录,确定故障是由 skb 结构体成员异常导致的内核恐慌问题。

🔎 **故障排查:** 分析 vmcore 中 skb 结构体,发现 len 小于 data_len,且差值恒定为 4 个字节。通过对比正常 skb 结构体,发现 network_header 字段被错误更新。进一步分析发现,故障发生在 IP 协议栈处理完成之后,且 skb 在 IP 层处理时是正常的,因此故障被锁定在 IP 层处理和 ip_local_deliver_finish 之间。

🎯 **故障根源:** 经过排查,发现故障是由第三方内核模块 sn_core_odd 引起的,该模块在内核 5.10 中由于 skb_make_writable 接口的变化导致了异常。

💡 **解决方案:** 卸载 sn_core_odd 模块,并积极推进部分网络第三方模块的 eBPF 化和模块签名机制,降低维护成本,避免稳定性风险。

原创 不达 2024-09-10 08:30 浙江

本文记述了一次由 skb(socket buffer)异常导致的内核故障排查过程。

阿里妹导读


本文记述了一次由 skb(socket buffer)异常导致的内核故障排查过程。

起初,没有人在意这个工单。这不过是个别机器的崩溃、一些数据包的迷失、一次服务的中断。直到这场灾难开始和每个人息息相关。

零点敲响的神秘钟声

2024年5月13日,晴。急促的钉声从破旧的 macbook 中骤然响起,在钉群混乱的信息流中,强而有力且坚持不懈的 ding 展现了它的实力,不达,一位日渐肥胖的网络工程师,大致还原了事情的全貌。

从集团升级内核版本开始,集团搜索服务就开始陷入频繁的内核故障,这些故障呈现出诡异但异常明显的规律,仅发生在午夜 0 点,然后如泥牛入海,不见其踪。而 618 的钟声即将敲响,每日 300+ 例频繁的宕机,还有进一步扩大的趋势。这时,没有丰富工作经验的同学肯定会着急忙慌的开始寻根问底, 而处理故障时长长达 2 年半的不达则会告诉你:Ding is cheap, show me the Aone.

Aone 准确的展现了一个事实,这是一个老旧难的问题,最早发生在 2023/03/23,我们的同学也尝试跟踪过多轮,未果。愁云瞬间笼罩,半吊子水平的笔者并不是这种问题的一合之敌,与其解决不了被迫丢人,不如退隐江湖。但一想到嗷嗷待哺的房贷,问题或许还有其他转机。

站在前人的肩膀上,Aone 的历史记录给我们提供了第一个证据:

不难看出,这是一个由 skb 结构体成员异常导致的内核恐慌问题,和我一样的内核小白们想必会发出同样疑惑的声音,什么是 skb?

通义千问告诉我们:

skb,又叫 sk_buff,全称是 socket buffer,它是 Linux 内核网络子系统中的核心数据结构之一,用于在网络协议栈的不同层次之间传递数据包。当数据包从网络接口卡(NIC)到达时,它被封装到一个 sk_buff 结构中,并通过网络栈向上层协议传递。同样地,当上层协议需要发送数据包时,它也会创建一个 sk_buff 结构并将其传递给下层协议进行处理。

sk_buff结构包含了数据包的所有相关信息,如数据包的头部、有效载荷、长度、标志位等。此外,它还包含了一些用于网络栈内部管理的信息,如指向下一个sk_buff 结构的指针,以及一些统计信息等。

图片出处: 

https://www.minzkn.com/moniwiki/wiki.php/skbuff

让我们来稍微解释一下相关的术语,不喜欢可以跳过,这不会影响我们问题甩锅的过程。

这里的故障表明,故障发生时,skb 指向的数据报文的实际长度,小于其数据(payload)的长度。一个超集小于其子集,显然是一个内核无法处理的异常。

遇到故障不要慌,先打开 vmcore 看一看


定位 SKB 

只需要一点点汇编的小常识,我们就能找到故障的 skb。

可以看到 len 是明显小于 data_len 的,这是异常的直接原因。

当我们分析多例同样问题的 vmcore 后,我们会发现一个惊人的事实, len 和 data_len 总差 4 个字节。我们知道,正常的结构体出现异常,无非就是:

而这个新发现的规律给我们提供一个非常重要的结论, 异常的 skb 大概率不是其他模块踩踏了内存,而应该是在正常的操作中出现了处理异常,因为 skb 中数据的自洽性相当好(skb其他部分的内容也能说明),只是数据的描述信息似乎指向的不太正确,这帮助决定了后续的排查方向。


恢复 SKB

我们先尝试看看它指向的一个什么报文:

从 skb 给出的信息来看,这是一个 “IPv1” 的报文。但很可惜,没有这种东西。这说明 network_header 字段也被错误的更新了。从上一节的结论中知道,数据应该是没有被破坏的,大概率是这些描述信息被错误更新。因此,让我们回归最原始的办法,瞪眼一瞧。

从 Aone 提供的信息来看,这是一个 IPv4 的服务。回忆计算机网络教过我们IPv4的协议格式,只要在上图中找到 4500,我们就可以找到可能是正确的IP报文了。

这个结构告诉我们,这是一个 UDP (17) 的报文,IP报文总长度(46340)为 1205, 其目的地址(1520018443) , 恰好就是搜索服务的机器。这说明我们盯出来的IP报文大概率是正确的。

那么紧跟着它的应该就是 UDP 报文:

这里表明这一个从端口 62463 发向端口43122,长度 1185 的 UDP 报文,其长度恰好是 IP 报文总长度 1205 - 20 ,这再次印证了我们数据报文的猜测。

现在,我们可以找出是谁在监听端口 43122:

当我们再次分析多例同样问题的 vmcore 后,我们再次发现,触发故障的 skb 总是这个 unbound-anchor 服务。此时勤劳的 baseos 同学告诉我们:

原来如此,零点触发的秘密被解开了。因此在卸载组件后,

至此零点之谜被彻底解决......了吗?

谁杀死了内核

无论如何,应用层的任何操作都不应该导致内核的 panic,要彻底解决这个问题,我们还远远不够。

从上面的分析中,我们知道 skb 目前的 network header 指向的并不是正常的 ip 头部,但观察崩溃的异常栈,我们会发现:

观察到故障发生在 ip_local_deliver_finish 时,意味着崩溃必然发生在 IP 协议栈处理完成之后,否则异常的数据包根本无法被投递到下一层。这说明至少在IP协议层处理时,skb 一定是正常的。

因此故障基本可以被锁定在 IP层处理 和 ip_local_deliver_finish之间。内核故障的老朋友 --- netfilter ,终于粉墨登场了。接下来,我们只需找到挂载在 NF_INET_LOCAL_IN 下的钩子,就能知道到底是谁在修改 skb。

很幸运的是,当前只挂载了一个钩子。经常写 netfilter 的同学都知道,hook 是一个函数,既然符号在 vmcore 没显示出来,那么这大概率是一个内核模块,搜索内核模块的地址,我们会发现:

注意:这里输出的地址是内核模块地址而不是基地址,因此判断 func 是由何模块引入的需要再进一步判断。 

因为地址0xffffffffc0e6b260在:

[0xffffffffc0e58c00, 0xffffffffc0e702c0]之间,这意味着这个钩子要么是由 aseni_intel 模块引入或者是由sn_core_odd模块引入。

因此我们只需要检查两个模块的 base 地址即可:

很明显0xffffffffc0e6b2600xffffffffc0e6600之后,这意味着这个钩子是由 sn_core_odd 这个模块引入,其也正好是一个 netfilter 模块。自此,成功锁定第三方内核模块 sn_core_odd 为本次故障的真凶。

最终相关同学排查到是因为内核 5.10 中 skb_make_writable 接口发生了一些变化,此前会帮调用者将要访问的数据从frag区拷贝到线性区,而在内核 5.10 中相关逻辑被删去了,因此导致了第三方内核模块在内核 5.10 上触发了异常。

写在后面的话

第三方内核模块的治理一直是阿里云操作系统团队遇到的老大难问题。去年,网络小组还处理了一起因第三方商业网卡驱动模块踩内存导致的异常,避免了一场线上危机。作为一枚阿里云内核小白,这些问题由于代码不开放、针对性适配不足,测试不充分导致稳定性问题很多。对于内核团队,一起故障,四处求索,难,难,难!

为此,我们一直在积极推进部分网络第三方模块的 eBPF 化,降低维护成本的同时,利用 eBPF 来避免稳定性风险。另一方面也正在推进第三方内核模块的模块签名机制。相信未来,和笔者一样的内核小白们,再也不用在这种故障中艰难寻踪了。

快速部署定制化文生图应用


PAI Stable Diffusion WebUI 解决方案为企业提供云上快速部署定制化的文生图应用。提供了方便、高效的模型部署产品,并支持根据实际需求,配置不同的服务版本及服务参数。具有分钟级部署上线,方便快捷、开箱即用,多版本部署方案,参数可定制化调整的优势。


点击阅读原文查看详情。

阅读原文

跳转微信打开

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

内核故障 skb socket buffer 网络故障 第三方内核模块 eBPF
相关文章