对那些整天喊着“玩大的,玩狠的”口号的人来说,我下面要说的这点事儿,根本就不算事儿。所以,如果你正好喜欢喊口号,就不要往下看了,因为我要讲述的,你可能不感兴趣,也可能看不懂。

今天,是我加入I公司3个多月以来最有成就感的一天,因为打赢了一个硬仗。1个多月以前,我所在的项目小组给我分配了一个bug,  该bug可简单描述为:两张Intel 82599的万兆网卡,通过光纤背靠背连接后,彼此ping不通。从接受任务到今天,一共持续了33天,其间多次被各种杂事儿各种突发任务所打断,但总的投入时间累计起来也至少有8个工作日。直到今天,我才真正定位了这个bug的root cause(I公司称之为“根因” Orz),真是“山重水复疑无路,蓦然回首,那人却在灯火阑珊处”。 既然玩不了大的,也玩不了狠的,咱就玩点实在的吧。

1. 问题概述

应用结点Ann和存储结点Ben上各有一张Intel 82599万兆网卡(ixgbe), 网卡与网卡之间使用光纤背靠背连接。在Ann和Ben上都给网卡的Interface配置上IPv4地址,彼此无法ping通。

[Ann: Application Node]
    eth1 90:e2:ba:85:fc:b8 192.168.53.100/24
    eth2 90:e2:ba:85:fc:b9 192.168.54.100/24

[Ben: Storage     Node]
    eth1 90:e2:ba:a9:58:f0 192.168.53.110/24
    eth2 90:e2:ba:a9:58:f1 192.168.54.110/24

注意:

2. 定位过程

  • 01 在应用结点Ann上ping -I 192.168.53.100 192.168.53.110; 然后在Ann上使用tcpdump抓包,用wireshark查看,发现arp请求包从Ann发出,但未收到arp响应包; (令人痛苦的是,存储结点Ben上没有tcpdump,只能从应用结点Ann上单方面抓包)
  • 02 在Ann和Ben上手工配置arp记录,再ping, 可以相互ping通,说明网卡,光模块和光纤都没有问题,排除硬件故障;
  • 03
  • 04 检查Ann和Ben上有没有SELinux设置,Ben没有,Ann有;于是关闭Ann上的SELinux设置,再ping, 还是ping不通;
  • 05 检查Ann和Ben上有没有防火墙firewalld, Ben没有,Ann有;于是关闭Ann上的firewall设置并重启,再ping, 还是ping不通;
  • 06
  • 07 在Ann上安装dropwatch, 启动一个ping -I 192.168.53.100 192.168.53.110; 然后启动dropwatch, 发现有丢包,而且是与arp错误密切相关,但是丢包原因不清楚;
  • 08 坐下来研读ARP协议(RFC826) (耗时1个周末);
  • 09 使用arping从Ben上向Ann发出arping, 成功;再使用arping从Ann上向Ben发出arping, 失败;好了,于是可以90%确定为是存储结点Ben的问题;
  • 10 在存储结点Ben上查看arptables服务,发现正在运行,再使用arptables -L查看规则,发现了4条DROP的规则,与Ben上的82599网卡对应的网络接口正好对应,于是99%确定为存储结点Ben的问题;
  • 11 在存储结点Ben上搜索源代码,找到root cause,原来是存储软件在启动的时候,发现82599网卡对应的网络接口(eth1, eth2)并没有配置IPv4地址,于是设置ARP规则将eth1, eth2的inbound和outbound的ARP包都通通drop掉,因此,从应用结点Ann上发出arp请求广播包,没有收到arp响应包就很好理解了 -- Ann发出去的arp请求包之所以石沉大海,是因为被Ben设置的ARP规则给drop掉了。

说明:

  • 01 其实离root cause很近了,但是当时不知道使用arping进行错误定位, 所以与成功擦肩而过;
  • 02
  • 03-06 其实是病急乱投医,属于神农尝百草的做法,对最后成功定位帮助不大;
  • 07 将注意力重新吸引到定位可能存在的ARP问题,本质上是回归到01, 功不可没;
  • 08 所谓“磨刀不误砍柴工”,让我坚定了在01时候所做的猜测,一定是ARP问题。相对于实践,理论基础更重要;
  • 09“差异化”是找出问题所在的关键,100次没有差异的ping操作抵不过1次有差异的arping操作, 成功就在眼前;
  • 10
  • 11 没有代码证据,所有的猜测只是猜测而已,“Read The F*cking Source Code”才是王道。

3. 总结陈词

对于枯燥乏味的bugfix来说,最艰难的部分就是错误定位。那些只会搞硬件不会搞软件擅长于喊口号拉标语的人,永远也无法体会其中的艰辛和快乐。这就好比踢足球,进球是最让人振奋的事情,但在进球之前,大多是冗长艰难的奔跑和拼抢。成功定位上面所述问题的root cause,对我来说意义重大(满满的成就感),因为完全是从零开始摸索,在黑暗中前行,没有任何既有的经验可用。这需要坚韧不拔,需要百折不挠,非智力因素才是到达成功彼岸的关键。 当然,能找到最后的root cause, 也离不开同事和朋友的帮助与点化,在此对Zrf, Lmx, Yyg三位老师和Wjq兄弟表示由衷的感谢!

后记: 找到bug的root cause后,最后的解决方案异常简单,一行代码都没有改,因为不用做任何修改。原因是通过GUI管理界面,给存储结点Ben上的82599网卡的网络接口配置上IPv4地址后,存储软件系统会自动修改arptables里的ARP规则,而且修改后的ARP规则正是我们所期望的。那么问题就来了,当初这个bug是怎么报出来滴?遗憾的是,bug filer并没有把具体的重现步骤记录在案,那就没有办法回溯了。因此,对测试工程师来说,不懂具体的技术不要紧,但是把发现bug的具体步骤记录清楚无疑是最重要的基本功。于此同时,对开发工程师来说,拿到一个bug,搞清楚bug的重现步骤则是最关键的,不然很可能是在浪费时间做艰难的长途跋涉。这也给我的职业生涯上了很重要的一课,发人深省,值得好好反思和引以为鉴。