最近我的家用服务器兼虚拟机宿主机开始随机断网。从外面看,它似乎还在正常运行,可我却无法通过任何远程方式访问它。根据交换机的显示,以太网适配器好像是开着的,所以问题肯定出在软件层面。

驱动问题导致网络连接卡死,这可不是第一次了。过去我就被 Linux 和 Windows 电脑上有 bug 的 WiFi 驱动坑过。

在系统日志里翻了一阵之后,我偶然发现了下面这些内容:

vmhost kernel: e1000e 0000:00:1f.6 eth0: Detected Hardware Unit Hang:
vmhost kernel: TDH <0>
vmhost kernel: TDT <1>
vmhost kernel: next_to_use <1>
vmhost kernel: next_to_clean <0>
vmhost kernel: buffer_info[next_to_clean]:
vmhost kernel: time_stamp <10fbc2f81>
vmhost kernel: next_to_watch <0>
vmhost kernel: jiffies <10fbc3871>
vmhost kernel: next_to_watch.status <0>
vmhost kernel: MAC Status <40080083>
vmhost kernel: PHY Status <796d>
vmhost kernel: PHY 1000BASE-T Status <7800>
vmhost kernel: PHY Extended Status <3000>
vmhost kernel: PCI Status <10>
vmhost kernel: e1000e 0000:00:1f.6 eth0: Reset adapter unexpectedly
vmhost kernel: vmbr0: port 1(eth0) entered disabled state

然后它会重置网络适配器,过一会儿又来一遍,直到机器彻底掉线。

我在网上找答案时,偶然发现了这个 ServerFault 帖子。

原因

翻了不少资料和 bug 报告列表后,复现这个问题最好的办法似乎是让设备处于高带宽场景,也就是传输大量数据把网卡接口跑满。

我的情况通常发生在从本地 Plex 服务器向某个设备串流媒体的时候。由于网络的搭建方式,运行 Plex 实例的 Windows 虚拟机必须先从另一台设备的 NFS 网络共享中取得媒体文件,在虚拟机里转码,再发送给播放设备。

这样加起来网络流量相当大,通常在 ~40-100mbit/s 左右,取决于播放媒体文件的设备以及源媒体文件的质量。

通过 Steam Link 向我们的 Apple TV 串流游戏时,也出现过同样的问题。连接是有线的,但网络掉线并不少见。我觉得这和上面是同一个问题,不过之后我会留意修复后是否还会发生。

可能的修复方法

看来一个可行的办法是在网络接口上关闭 GSO (Generic Segmentation Offload,通用分段卸载)、TSO (TCP Segmentation Offload,TCP 分段卸载) 和 GRO (Generic Receive Offload,通用接收卸载)*:

ethtool -K eth0 gso off gro off tso off

我已经在自己的环境里应用了这个设置,正在观察长期来看它是否真的能解决问题。

脚注

* 这些选项与把数据包分段工作卸载给网络接口控制器有关,目的是降低机器的 CPU 占用。更多细节可以参考这篇维基百科文章。