最近设计部报告说经常发生终端链接忽然红屏的现象。一天会发生几起。范围还挺大


这是RGS协议丢包的表现。

本来以为是服务器端带宽原因,因为以前发生过类似的情况。经过排查,发现并不是这样的。服务器端并不存在带宽瓶颈。而且出现问题的服务器分布也比较均匀。

再看接入层,发现交换机的接入端口上的output错包都是天文数字,错包类别是abort。以前看过的资料对于abort错误是这样解释的:abort错误包含了前导帧出错,以及不在其他统计类别中的所有错误的总和。

这个解释范围太大了,没什么实际意义。

怎么回事?难道是所有端口同时都坏了?这不可能啊。继续观察,发现所有端口的错包程周期性增长,每隔一段时间,大概有几十秒,错包就飙升一下。第一反应,可能是存在一个电磁干扰源,这个干扰源以特定周期发出干扰信号。上联端口是光纤,没有收到干扰。我不知道这个解释能否行得通,因为干扰应该是crc错误比较合理。因为从来没遇到过电磁干扰,不知道现象是什么样的。不过有一个简单的办法来验证这个理论,我又拿了一台交换机没做任何设置桥接在这台交换机下,并把一部分用户迁移过来。如果两台设备问题同时发生,证明这个理论可能正确,可以进行下一步诊断,否则说明这个推断错误。事实证明,电磁干扰假设是错误的。新的交换机端口并没有错误。我又把这台交换机通过trunk连接到主干路,错误激增!

很显然,是主干路的某种报文引起的接入端口的链路错误。居然有这种事情,真是匪夷所思。不过值得高兴的是,并非硬件出现故障。否则后果真的太严重了。

我又看了其他楼层的交换机,居然所有楼层不同vlan都是这个情况。又看了一下其他办公楼,问题虽然没有这么严重,但是错包的分布依然比较普遍。

是什么样的报文能够导致这样的问题出现呢?

我的一个同事打电话求助h3c。厂商工程师给出的解释是可能是千兆端口下来的突发流量让百兆端口的缓冲区容纳不下,导致丢包。听起来很合理,不过如果是发生了这种情况,错误报文应该被计入到underrun统计中,而不是abort错误。另外,h3c里面有个功能叫做burst-mode专门为了适应这种情况。这是我本来就知道的,敲一条命令不费什么事,遗憾的是,burst-mode和我们普遍采用的交换机堆叠设置有冲突。

不管怎样,如此大范围的影响应该是广播包。我和几个同事把全部接入层和核心的端口都做了广播抑制。问题似乎有了好转,错包数量下降了好几个数量级。

我们又新建了一个vlan,只放了几个用户进去。这个新的vlan果然没有错包。

虽然有还是有很多错误,但是已经红屏现象似乎得到了遏制。不过这样的结果,证明了流量说是不正确的。

这样,又产生了新的问题:

1.排除了流量原因,那么导致错包的原因是包的类型。除了bug,很难解释这是怎么发生的。这种情况也不是没发生过。以前遇到过新买的设备,总时不时的不转发arp,查了一天都没结果。后来给交换机系统升了个级,就解决了。但是升级的patchnote里面没有任何关于这个问题的描述。还有一次,某个交换机一根网线一旦插上,10秒钟之内cpu就会上升到100%,cpu都被info进程抢占。重新做了根线,问题就解决了。


2.如果是广播引起的问题,为什么所有的vlan都会受到影响。这个现象说明引起问题的根源出在核心交换机。

3.用户数据中断和端口错包是不是有必然的联系?因为红屏现象肯定是用户的tcp会话包丢失导致的。但是统计里的大部分错包应该是广播包本身,而非用户数据。

不管怎样,还是抓包看看。假设类型说是正确的,即使接入层的abort错包无法抓取,那么从千兆上行口抓到的报文一定能找到导致问题发生的报文类型。

出于方便,我先抓一下接入层的包,看看都能收到哪些类型的广播。

wireshark显示,大部分广播以arp为主,还有一些NetBIOS的报文以及其他二层报文。

有两个现象比较引人注意:

1.arp报文中有每隔一段时间就有一大批从核心交换机,也就是网关发来的arp报文。检查了一下,都是不存在的地址。说明很可能有人在对这些不存在的地址进行扫描。h3c有一个针对这种情况的解决方案,叫做arp源抑制。如果某一个ip不断地扫描不存在的地址,5秒内超过一定阈值,就会再接下来的5秒把这个ip来的报文都丢掉。治标不治本,聊胜于无吧。

2.有相当多的用户发出的arp包的校验错误。这些校验错误有个共同的特征。同样用户发出的所有包的错误校验码都是相同的,而且所有错误的校验码的最后两个字节都为0。显然这不是随机发生的现象,而是校验算法出现了问题。

首先,这些错包和output错包不是同一个概念。output错包应该是抓不到的。端口计数器证实了这个观点。

其次,这个校验算法出现的故障应该是出现在交换机端,而非用户端。因为从用户端发出来的数据如果校验出错直接就被端口丢弃了,根本不可能得到转发。在用户端抓包证明了这个观点,用户端发出去的包是没问题的。按照通常的想法,校验通过就就可以原封不动的转发了。可能是这段的程序出现了什么问题。

不管如何,既然错成这样。那么我先假设这个算法可能出现问题了。抱着试试看的想法我先假设他错的原因是crc校验的生成多项式不对。(当然,现代crc算法都是采用的查表发,而非计算法。也有可能是crc表错误,这个我先不考虑。)按照他错误的方式把crc算法的生成多项式的方程解出来,如果这个生成多项式在所有报文中一致,就证明了这个猜测。

4个字节的fcs,应该是crc32。我先试了下把crc16的生成多项式带入原报文,结果和错误不吻合。

我假设原始数据为d,生成项为m,是一个33bit的值。校验结果为r。那么对于crc32的校验方式应该是d<<32=r(mod m)。

我的目的就是在知道d和r的情况下解出m。这个问题换个表达法就是d<<32-r可以被m整除。也就是说m应该是(d<<32)-r的因子。把(d<<32)-r做因式分解,找到其中能够组合成33bit的因子就行。

可是,d<<32的数是一个10^170的巨大数字。即使两个报文的数据做差分,还是在10^150左右。。根本就无法分解。换个思路,我的假设是错误的生成多项式是相同的,那么这个m应该是两个不同的(d<<32)-r的公因子。我先用欧几里得除法解出这两个数的最大公约数。再对这个最大公约数进行因式分解就可以了。

结果,这两个数的最大公约数是65536,刚好是错误的校验的最后2字节0。除了两个字节部分,其他部分都是互质的。猜测失败。。。(本来我也没觉得能够成功)。

当时第一反应是随便找到这么大的两个数互质的概率有多大?查了一下关于欧拉函数的wiki,里面有个公式,在n接近无穷大的时候,从1...n随便找两个数互质的概率是6/pai^2。接近2/3的概率,还是挺大的。不瞎折腾了,此路不通。


故障的原因在此陷入僵局。虽然问题表面上得到了解决,但是问题的原因还是没有得到合理的解释。有些地方,错包还是在增长。感慨自己的水平和经验太有限了,也许对于一些专家和高手这个问题是很浅显的。


记得在微软technet上看过这样一个故障:windows系统崩溃的时候会把崩溃信息发给微软。让微软的工程师查看问题。其中有一个故障发生的很普遍。根据dump出来的堆栈和寄存器信息。微软的工程师发现问题发生的原因出在xor eax,eax这条命令上,这条命令是把eax置零的最快操作。在程序中存在极大量的类似指令。在故障中,xor eax,eax后,eax却不等于零。相当于计算机把1+1算成了不等于2。只能理解成cpu坏了。微软的工程师百思不得其解,因为这个故障发生的的频率非常高。后来,一个偶然的原因。微软的工程师发现,这些故障中的很多电脑都对cpu进行了超频。

原来如此。。。


把这个故障做一个记录,也许某一天能够知道是怎么回事。