一个存在三年的内核 bug 引发大量的容器系统出现网络故障

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介:

一个存在三年的内核 bug 引发大量的容器系统出现网络故障

最近发现的一个 Linux 内核 bug,会造成使用 veth 设备进行路由的容器(例如 Docker on IPv6、Kubernetes、Google Container Engine 和 Mesos)不检查 TCP 校验码checksum,这会造成应用在某些场合下,例如坏的网络设备,接收错误数据。这个 bug 可以在我们测试过的三年内的任何一个内核版本中发现。

这个问题的补丁已经被整合进核心代码,正在回迁入3.14之前的多个发行版中(例如SuSE,Canonical)。如果在自己环境中使用容器,强烈建议打上此补丁,或者等发布后,部署已经打上补丁的核心版本。

注:Docker 默认的 NAT 网络并不受影响,而实际上,Google Container Engine 也通过自己的虚拟网络防止了硬件错误。

编者:Jake Bower 指出这个 bug 跟一段时间前发现的另外一个 bug 很相似。有趣!

起因

​十一月的某个周末,一组 Twitter 负责服务的工程师收到值班通知,每个受影响的应用都报出 “impossible” 错误,看起来像奇怪的字符出现在字符串中,或者丢失了必须的字段。这些错误之间的联系并不很明确指向 Twitter 分布式架构。问题加剧表现为:任何分布式系统,数据,一旦出问题,将会引起更长的字段出问题(他们都存在缓存中,写入日志磁盘中,等等...)。经过一整天应用层的排错,团队可以将问题定位到某几个机柜内的设备。团队继续深入调查,发现在第一次影响开始前,进入的 TCP纠错码错误大幅度升高;这个调查结果将应用从问题中摘了出来,因为应用只可能引起网络拥塞而不会引起底层包问题。

编者:用“团队”这个词可能费解,是不是很多人来解决这个问题。公司内部很多工程师参与排错,很难列出每个人名字,但是主要贡献者包括:Brian Martin、David Robinson、Ken Kawamoto、Mahak Patidar、Manuel Cabalquinto、Sandy Strong、Zach Kiehl、Will Campbell、Ramin Khatibi、Yao Yue、Berk Demir、David Barr、Gopal Rajpurohit、Joseph Smith、Rohith Menon、Alex Lambert and Ian Downes、Cong Wang。

一旦机柜被移走,应用失效问题就解决了。当然,很多因素可以造成网络层失效,例如各种奇怪的硬件故障,线缆问题,电源问题,等....;TCP/IP 纠错码就是为保护这些错误而设计的,而且实际上,从这些设备的统计证据表明错误都可以检测到---那么为什么这些应用也开始失效呢?

隔离特定交换机后,尝试减少这些错误(大部分复杂的工作是由 SRE Brain Martin 完成的)。通过发送大量数据到这些机柜可以很容易复现失效数据被接收。在某些交换机,大约~10%的包失效。然而,失效总是由于核心的 TCP 纠错码造成的(通过netstat -a 返回的 TcpInCsumError 参数报告),而并不发送给应用。(在 Linux 中,IPv4 UDP 包可以通过设置隐含参数 SO_NO_CHECK,以禁止纠错码方式发送;用这种方式,我们可以发现数据失效)。

Evan Jones(@epcjones)有一个理论,说的是假如两个 bit 刚好各自翻转(例如0->1和1->0)失效数据有可能有有效的纠错码,对于16位序字节,TCP 纠错码会刚好抵消各自的错误(TCP 纠错码是逐位求和)。当失效数据一直在消息体固定的位置(对32位求模),事实是附着码(0->1)消除了这种可能性。因为纠错码在存储之前就无效了,一个纠错码 bit 翻转外加一个数据 bit 翻转,也会抵消各自的错误。然而,我们发现出问题的 bit 并不在 TCP 纠错码内,因此这种解释不可能发生。

很快,团队意识到测试是在正常的 linux 系统上进行的,许多 Twitter 服务是运行在 Mesos 上,使用 Linux 容器隔离不同应用。特别的,Twitter 的配置创建了 veth(虚拟以太网virtual ethernet)设备,然后将应用的包转发到设备中。可以很确定,当把测试应用跑在 Mesos 容器内后,立即发现不管 TCP 纠错码是否有效(通过 TcpInCsumErrors 增多来确认),TCP 链接都会有很多失效数据。有人建议激活 veth 以太设备上的 “checksum offloading” 配置,通过这种方法解决了问题,失效数据被正确的丢弃了。

到这儿,有了一个临时解决办法,Twitter Mesos 团队很快就将解决办法作为 fix 推给了 Mesos 项目组,将新配置部署到所有 Twiter 的生产容器中。

排错

当 Evan 和我讨论这个 bug 时,我们觉得由于 TCP/IP 是在 OS 层出现问题,不可能是 Mesos 不正确配置造成的,一定应该是核心内部网络栈未被发现 bug 的问题。

为了继续查找 bug,我们设计了最简单的测试流程:

  1. 单客户端打开一个 socket,每秒发送一个简单且长的报文​
  2. 单服务端(使用处于侦听模式的 nc)在 socket 端侦听,打印输出收到的消息。
  3. 网络工具,tc,可以用于发送前,任意修改包内容。
  4. 一旦客户端和服务端对接上,用网络工具失效所有发出包,发送10秒钟。

可以在一个台式机上运行客户端,服务器在另外一个台式机上。通过以太交换机连接两台设备,如果不用容器运行,结果和我们预想一致,并没有失效数据被接收到,也就是10秒内没有失效包被接收到。客户端停止修改包后,所有10条报文会立刻发出;这确认Linux端TCP栈,如果没有容器,工作是正常的,失效包会被丢弃并重新发送直到被正确接收为止。


这样是工作的:错误的数据不会接收,TCP转发数据

Linux 和容器

现在让我们快速回顾一下 Linux 网络栈如何在容器环境下工作会很有帮助。容器技术使得用户空间user-space应用可以在机器内共存,因此带来了虚拟环境下的很多益处(减少或者消除应用之间的干扰,允许多应用运行在不同环境,或者不同库)而不需要虚拟化环境下的消耗。理想地,任何资源之间竞争都应该被隔离,场景包括磁盘请求队列,缓存和网络。

Linux 下,veth 设备用于隔离同一设备中运行的容器。Linux 网络栈很复杂,但是一个 veth 设备本质上应该是用户角度看来的一个标准以太设备。

为了构建一个拥有虚拟以太设备的容器,必须:

  1. 创建一个虚机,
  2. 创建一个 veth,
  3. 将 veth 绑定与容器端,
  4. 给 veth 指定一个 IP 地址,
  5. 设置路由,用于 Linux 流量控制,这样包就可以进出容器了。

为什么是虚拟造成了问题

我们重建了如上测试场景,除了服务端运行于容器中。然后,当开始运行时,我们发现了很多不同:失效数据并未被丢弃,而是被转递给应用!通过一个简单测试(两个台式机,和非常简单的程序)就重现了错误。

video2.gif
失效数据被转递给应用,参见左侧窗口。

我们可以在云平台重建此测试环境。k8s 的默认配置触发了此问题(也就是说,跟 Google Container Engine 中使用的一样),Docker 的默认配置(NAT)是安全的,但是 Docker 的 IPv6 配置不是。​

修复问题

重新检查 Linux 核心网络代码,很明显 bug 是在 veth 核心模块中。在核心中,从硬件设备中接收的包有 ip_summed 字段,如果硬件检测纠错码,就会被设置为 CHECKSUM_UNNECESSARY,如果包失效或者不能验证,者会被设置为 CHECKSUM_NONE。

veth.c 中的代码用 CHECKSUM_UNNECESSARY 代替了 CHECKSUM_NONE,这造成了应该由软件验证或者拒绝的纠错码被默认忽略了。移除此代码后,包从一个栈转发到另外一个(如预期,tcpdump 在两端都显示无效纠错码),然后被正确传递(或者丢弃)给应用层。我们不想测试每个不同的网络配置,但是可以尝试不少通用项,例如桥接容器,在容器和主机之间使用 NAT,从硬件设备到容器见路由。我们在 Twitter 生产系统中部署了这些配置(通过在每个 veth 设备上禁止 RX checksum offloading)。

还不确定为什么代码会这样设计,但是我们相信这是优化设计的一个尝试。很多时候,veth 设备用于连接统一物理机器中的不同容器。

逻辑上,包在同一物理主机不同容器间传递(或者在虚机之间)不需要计算或者验证纠错码:唯一可能失效的是主机的 RAM,因为包并未经过线缆传递。不幸的是,这项优化并不像预想的那样工作:本地产生的包,ip_summed 字段会被预设为CHECKSUM_PARTIAL,而不是 CHECKSUM_NONE。

这段代码可以回溯到该驱动程序第一次提交(commit e314dbdc1c0dc6a548ecf [NET]: Virtual ethernet device driver)。 Commit 0b7967503dc97864f283a net/veth: Fix packet checksumming (in December 2010)修复了本地产生,然后发往硬件设备的包,默认不改变CHECKSUM_PARTIAL的问题。然而,此问题仍然对进入硬件设备的包生效。

核心修复补丁如下:


  
  
  1. diff - git a/drivers/net/veth.c b/drivers/net/veth.c
  2. index 0ef4a5a..ba21d07 100644
  3. - - a/drivers/net/veth.c
  4. +++ b/drivers/net/veth.c
  5. @@ -117,12 +117,6 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
  6. kfree_skb(skb);
  7. goto drop;
  8. }
  9. - /* don’t change ip_summed == CHECKSUM_PARTIAL, as that
  10. - * will cause bad checksum on forwarded packets
  11. - */
  12. - if (skb->ip_summed == CHECKSUM_NONE &&
  13. - rcv->features & NETIF_F_RXCSUM)
  14. - skb->ip_summed = CHECKSUM_UNNECESSARY;
  15. if (likely(dev_forward_skb(rcv, skb) == NET_RX_SUCCESS)) {
  16. struct pcpu_vstats *stats = this_cpu_ptr(dev->vstats);

结论

我对 Linux netdev 和核心维护团队的工作很钦佩;代码确认非常迅速,不到几个星期补丁就被整合,不到一个月就被回溯到以前的(3.14+)稳定发行版本中(Canonical,SuSE)。在容器化环境占优势的今天,很惊讶这样的bug居然存在了很久而没被发现。很难想象因为这个 bug 引发多少应用崩溃和不可知的行为!如果确信由此引发问题请及时跟我联系。




本文来自云栖社区合作伙伴“Linux中国”

原文发布时间为:2013-04-02.


相关文章
|
3天前
|
机器学习/深度学习 人工智能 算法
猫狗宠物识别系统Python+TensorFlow+人工智能+深度学习+卷积网络算法
宠物识别系统使用Python和TensorFlow搭建卷积神经网络,基于37种常见猫狗数据集训练高精度模型,并保存为h5格式。通过Django框架搭建Web平台,用户上传宠物图片即可识别其名称,提供便捷的宠物识别服务。
92 55
|
6天前
|
人工智能 弹性计算 运维
ACK Edge与IDC:高效容器网络通信新突破
本文介绍如何基于ACK Edge以及高效的容器网络插件管理IDC进行容器化。
|
1月前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
69 2
|
12天前
|
机器学习/深度学习 人工智能 算法
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
宠物识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了37种常见的猫狗宠物种类数据集【'阿比西尼亚猫(Abyssinian)', '孟加拉猫(Bengal)', '暹罗猫(Birman)', '孟买猫(Bombay)', '英国短毛猫(British Shorthair)', '埃及猫(Egyptian Mau)', '缅因猫(Maine Coon)', '波斯猫(Persian)', '布偶猫(Ragdoll)', '俄罗斯蓝猫(Russian Blue)', '暹罗猫(Siamese)', '斯芬克斯猫(Sphynx)', '美国斗牛犬
83 29
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
|
25天前
|
安全 Windows
【Azure Cloud Service】在Windows系统中抓取网络包 ( 不需要另外安全抓包工具)
通常,在生产环境中,为了保证系统环境的安全和纯粹,是不建议安装其它软件或排查工具(如果可以安装,也是需要走审批流程)。 本文将介绍一种,不用安装Wireshark / tcpdump 等工具,使用Windows系统自带的 netsh trace 命令来获取网络包的步骤
65 32
|
17天前
|
存储 缓存 监控
Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
本文介绍了Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
50 7
|
17天前
|
负载均衡 网络协议 算法
Docker容器环境中服务发现与负载均衡的技术与方法,涵盖环境变量、DNS、集中式服务发现系统等方式
本文探讨了Docker容器环境中服务发现与负载均衡的技术与方法,涵盖环境变量、DNS、集中式服务发现系统等方式,以及软件负载均衡器、云服务负载均衡、容器编排工具等实现手段,强调两者结合的重要性及面临挑战的应对措施。
44 3
|
22天前
|
弹性计算 监控 数据库
制造企业ERP系统迁移至阿里云ECS的实例,详细介绍了从需求分析、数据迁移、应用部署、网络配置到性能优化的全过程
本文通过一个制造企业ERP系统迁移至阿里云ECS的实例,详细介绍了从需求分析、数据迁移、应用部署、网络配置到性能优化的全过程,展示了企业级应用上云的实践方法与显著优势,包括弹性计算资源、高可靠性、数据安全及降低维护成本等,为企业数字化转型提供参考。
44 5
|
25天前
|
存储 数据可视化 API
重磅干货,免费三方网络验证[用户系统+CDK]全套API接口分享教程。
本套网络验证系统提供全面的API接口,支持用户注册、登录、数据查询与修改、留言板管理等功能,适用于不想自建用户系统的APP开发者。系统还包含CDK管理功能,如生成、使用、查询和删除CDK等。支持高自定义性,包括20个自定义字段,满足不同需求。详细接口参数及示例请参考官方文档。
|
1月前
|
监控 安全 测试技术
网络信息系统的整个生命周期
网络信息系统规划、设计、集成与实现、运行维护及废弃各阶段介绍。从企业需求出发,经过可行性研究和技术评估,详细设计系统架构,完成设备安装调试和系统集成测试,确保稳定运行,最终安全退役。
40 1
网络信息系统的整个生命周期