CentOS 7下Realtek 2.5G网卡驱动编译与调优实战 1. 为什么2.5G网卡在CentOS 7上是个“硬骨头”手里有一块Realtek 3000系列的2.5G网卡插上CentOS 7的机器满心欢喜地敲下ip a结果只看到一个孤零零的lo或者网卡是认出来了但死活跑不到2.5G的速率——这事儿我遇到过不止一次。CentOS 7的内核版本停留在3.10这个内核对于2.5G以太网PHY的支持几乎为零而Realtek 3000系列包括RTL8125、RTL8156等常见型号的官方驱动又偏偏不给你省心源码包里藏着一堆需要手动处理的坑。所以这篇内容就是写给那些手里有2.5G网卡、系统是CentOS 7、又不想升级整个操作系统内核的同行看的。我会把从确认硬件ID、准备编译环境、处理源码兼容性问题到最终调优跑满2.5G速率的完整链路拆开讲中间踩过的坑和绕过的弯一个不落。先说清楚一个基本事实CentOS 7自带的r8169驱动能识别一部分Realtek网卡但它对2.5G模式的支持是残缺的。你可能会发现网卡能亮灯、能获取IP但ethtool里显示的速率始终是1000Mb/s或者干脆在dmesg里报一堆link up/down的循环。这不是网卡坏了是驱动没对上。Realtek官方为Linux提供的驱动包通常命名为r8125-x.x.x.tar.bz2这类格式里面包含了针对不同内核版本的适配代码但默认的Makefile并不会自动帮你处理CentOS 7这种老内核的编译问题。你需要手动介入的地方比想象中多。另外要提醒一句在开始折腾之前确认你的主板PCIe插槽带宽足够。2.5G网卡需要PCIe 2.0 x1以上的通道如果你插在了一个老旧的PCIe 1.1 x1插槽上理论带宽只有250MB/s换算下来刚好卡在2Gbps左右跑不满2.5G。这个细节很多人会忽略然后对着驱动折腾半天最后发现是插槽的锅。用lspci -vv查看LnkCap和LnkSta字段就能确认当前协商的PCIe速率和宽度。提示在动手装驱动之前先用lspci -nn | grep -i ethernet拿到网卡的PCI ID比如10ec:8125这种格式。这个ID在后面判断驱动是否真正接管了硬件时非常关键。2. 动手之前确认硬件身份与系统底子2.1 用lspci和ethtool摸清网卡的真实状态很多人拿到网卡直接就开始找驱动连网卡具体是哪个型号都没搞清楚。Realtek 3000系列下面有多个子型号RTL8125、RTL8125B、RTL8156USB接口等等不同型号对应的驱动源码包是不一样的。第一步永远是lspci -nn | grep -i ethernet输出会类似这样03:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. Device [10ec:8125]记下方括号里的10ec:8125这是厂商ID和设备ID的组合。如果系统当前已经加载了r8169驱动你还会看到Kernel driver in use: r8169这一行。这时候再用ethtool看看网卡的状态ethtool eth0重点看Speed和Duplex两行。如果显示Speed: 1000Mb/s而你的交换机和网线都支持2.5G那基本可以确定是驱动的问题。如果显示Speed: Unknown或者直接报错说设备不支持那可能是驱动压根没正确初始化PHY。还有一个容易被忽略的点检查dmesg里有没有关于r8169的报错信息。常见的错误包括PHY not ready、Link is Up和Link is Down反复横跳、以及Timeout waiting for PHY之类的。这些信息能帮你判断问题是出在驱动层面还是硬件层面。2.2 CentOS 7的编译环境准备别漏了kernel-develCentOS 7最小化安装默认是不带编译工具的你需要手动补齐。这里有一个关键点kernel-devel的版本必须和当前运行的内核版本完全一致否则编译出来的模块加载时会报version magic错误。先确认当前内核版本uname -r然后安装对应版本的开发包yum install -y kernel-devel-$(uname -r) kernel-headers-$(uname -r) gcc make如果你执行yum install kernel-devel而不指定版本yum可能会给你装一个比当前运行内核更新的版本导致编译出来的驱动模块无法加载。这个坑我踩过当时uname -r显示的是3.10.0-1160.el7.x86_64但yum默认装的是3.10.0-1160.90.1.el7.x86_64的devel包结果insmod的时候直接报invalid module format。所以务必带上版本号。另外确认/usr/src/kernels/$(uname -r)这个目录存在里面应该有完整的内核头文件。如果不存在说明kernel-devel没装对。还有一个隐藏依赖是elfutils-libelf-devel某些情况下编译Realtek驱动时需要它来处理模块签名相关的逻辑虽然CentOS 7默认不强制签名但装上能避免一些莫名其妙的编译错误。注意如果你的CentOS 7开启了Secure Boot加载第三方编译的驱动模块会被拒绝。要么在BIOS里关掉Secure Boot要么对模块进行签名。生产环境建议走签名流程测试环境直接关掉省事。3. Realtek 3000驱动源码的获取与预处理3.1 从官方渠道拿到正确的源码包Realtek的Linux驱动通常发布在他们的官网下载页面文件名类似r8125-9.011.00.tar.bz2。注意不要从第三方镜像站随便下载有些站点提供的包被人改过Makefile编译出来的模块可能带一些你不想要的东西。下载下来之后先解压tar -xjf r8125-9.011.00.tar.bz2 cd r8125-9.011.00解压后你会看到src目录下有一堆.c和.h文件以及一个Makefile。在编译之前先看一眼Makefile里的EXTRA_CFLAGS和KERNELDIR变量。KERNELDIR默认指向/lib/modules/$(shell uname -r)/build这个路径在装好kernel-devel之后应该是一个指向/usr/src/kernels/$(uname -r)的软链接。确认一下ls -l /lib/modules/$(uname -r)/build如果这个软链接断了或者指向了错误的版本编译必然失败。3.2 处理CentOS 7老内核的兼容性补丁Realtek的驱动源码主要是为较新内核写的在CentOS 7的3.10内核上编译经常会遇到几个典型错误。第一个是struct ethtool_ops结构体成员不匹配新内核里的一些字段在老内核里不存在。第二个是netif_napi_add函数的参数数量差异。第三个是skb_frag_size相关的API变更。这些错误在编译输出里会以error: ‘struct ethtool_ops’ has no member named ‘xxx’的形式出现。处理方式有两种一是手动修改源码把不兼容的字段用#if LINUX_VERSION_CODE宏包起来二是找社区已经打好补丁的版本。我倾向于第一种因为你能清楚知道改了什么东西。以ethtool_ops为例找到源码里定义r8125_ethtool_ops的地方把老内核不支持的字段注释掉并在初始化函数里做条件编译。具体来说像get_link_ksettings和set_link_ksettings这两个回调在3.10内核里是不存在的需要替换成老的get_settings和set_settings。还有一个常见的编译错误是implicit declaration of function ‘skb_frag_size’这是因为3.10内核里这个函数可能叫别的名字或者需要包含额外的头文件。解决办法是在源码文件顶部加上#include linux/skbuff.h如果还不行就自己写一个内联函数包装一下。提示每次修改源码后先执行make clean再make否则增量编译可能会漏掉你改过的文件。这个习惯能帮你省下大量排查时间。4. 编译、加载与验证的完整链路4.1 编译参数的选择与模块命名Realtek的Makefile通常支持几个编译选项比如ENABLE_RSS多队列支持、ENABLE_PTP精确时间协议、ENABLE_8125B针对B版芯片的优化。对于2.5G场景我建议至少开启RSS这样在多核CPU上能充分利用多队列减少单核瓶颈。编译命令make clean make -j$(nproc) ENABLE_RSS1编译成功后会在src目录下生成r8125.ko文件。用modinfo检查一下模块信息modinfo src/r8125.ko确认vermagic字段里的内核版本和uname -r一致。如果不一致说明编译时用的内核头文件版本不对需要回去检查KERNELDIR。接下来是加载模块。先卸载系统自带的r8169驱动否则它会抢占设备rmmod r8169 insmod src/r8125.ko如果insmod报错用dmesg | tail -20看具体原因。常见的错误包括Unknown symbol依赖模块没加载和Invalid module format版本不匹配。前者用modprobe加载依赖即可后者只能重新编译。4.2 用ethtool和iperf3验证2.5G速率模块加载成功后ip a应该能看到新的网络接口通常命名为eth0或enp3s0。这时候再用ethtool看速率ethtool eth0 | grep -E Speed|Duplex如果显示Speed: 2500Mb/s恭喜你驱动层面已经通了。但别急着庆祝实际吞吐量还得用iperf3测。找另一台同样支持2.5G的机器做服务端iperf3 -s客户端iperf3 -c 服务端IP -t 30 -P 4-P 4表示开4个并行流这样能更好地压满带宽。如果单流只能跑到1.5Gbps左右多流能到2.3Gbps以上说明RSS起作用了。如果多流也上不去检查一下ethtool -S eth0里的丢包统计和ethtool -g eth0里的ring buffer大小。CentOS 7默认的ring buffer可能偏小适当调大ethtool -G eth0 rx 4096 tx 40964.3 让驱动在重启后自动加载insmod只是临时加载重启后就没了。要让驱动持久化需要把r8125.ko复制到/lib/modules/$(uname -r)/kernel/drivers/net/ethernet/realtek/目录下然后执行depmod -a echo blacklist r8169 /etc/modprobe.d/blacklist.conf echo r8125 /etc/modules-load.d/r8125.confblacklist r8169是为了防止系统在启动时自动加载老驱动抢占设备。modules-load.d里的配置会让systemd在启动阶段自动加载r8125。做完这些之后重启一次再用lsmod | grep r8125确认模块已经加载ethtool确认速率正常。注意有些CentOS 7的initramfs里包含了r8169驱动即使blacklist了也可能在早期启动阶段被加载。如果遇到这种情况需要重建initramfsdracut -f然后再重启。5. 那些文档里不会写的踩坑记录5.1 网卡灯亮但链路反复up/down这个问题我遇到过两次一次是因为网线质量不行。2.5G对线缆的要求比千兆高得多Cat5e在短距离内勉强能跑但超过30米就容易出现链路震荡。换Cat6之后问题消失。另一次是因为交换机的节能以太网功能EEE和Realtek网卡的兼容性问题。ethtool --show-eee eth0可以看到EEE状态如果显示enabled试着关掉ethtool --set-eee eth0 eee off关掉之后链路立刻稳定。这个坑的隐蔽性在于dmesg里只会报Link is Up和Link is Down不会告诉你原因你得自己去猜。5.2 编译时提示缺少asm/types.h这是CentOS 7上编译Realtek驱动的一个经典错误。原因是内核头文件的包含路径没有正确传递给编译器。解决办法是在Makefile的EXTRA_CFLAGS里加上EXTRA_CFLAGS -I$(KERNELDIR)/arch/x86/include/uapi EXTRA_CFLAGS -I$(KERNELDIR)/arch/x86/include/generated/uapi这两行能解决大部分头文件找不到的问题。如果还报别的头文件缺失用find /usr/src/kernels/$(uname -r) -name 缺失的头文件名定位一下然后把对应目录加到EXTRA_CFLAGS里。5.3 大流量下CPU软中断飙升2.5G速率下如果所有网络中断都集中在CPU0上top里能看到si软中断占用率飙升到70%以上实际吞吐量反而上不去。解决办法是开启RSS并把中断分散到多个CPU核心。先确认驱动编译时开了ENABLE_RSS1然后检查/proc/interrupts里网卡的中断分布。如果都集中在某一个CPU上可以用irqbalance服务自动均衡或者手动设置中断亲和性echo 1 /proc/irq/中断号/smp_affinity更彻底的做法是启用多队列ethtool -L eth0 combined 4这会把队列数设为4对应4个中断分别绑定到不同的CPU核心。实测下来开启多队列后同样的硬件配置下iperf3多流成绩能从1.8Gbps提升到2.35Gbps。6. 长期维护与版本升级的注意事项6.1 内核更新后驱动需要重新编译CentOS 7偶尔会推送内核安全更新一旦内核版本变了之前编译的r8125.ko就会因为vermagic不匹配而无法加载。这时候你需要重新安装对应新内核的kernel-devel然后重新编译驱动。为了避免每次手动操作可以写一个简单的脚本放在/usr/local/bin/下内容大致是#!/bin/bash KVER$(uname -r) yum install -y kernel-devel-$KVER kernel-headers-$KVER cd /root/r8125-9.011.00 make clean make -j$(nproc) ENABLE_RSS1 cp src/r8125.ko /lib/modules/$KVER/kernel/drivers/net/ethernet/realtek/ depmod -a modprobe -r r8125 modprobe r8125每次内核更新后跑一遍就行。注意脚本里的源码路径要根据实际情况调整。6.2 驱动版本与芯片版本的匹配Realtek 3000系列里RTL8125和RTL8125B的驱动源码是不通用的。如果你用的是B版芯片但装了非B版的驱动可能会出现链路能起来但速率跑不满的情况。判断芯片版本的方法是看lspci -vv输出里的Device字段或者直接看网卡PCB上的丝印。驱动源码包的README里通常会写明支持的芯片列表下载前先核对一下。另外Realtek的驱动更新频率不算高但偶尔会修复一些PHY初始化的问题。如果你当前版本用着稳定没必要追新。我一般只在遇到明确bug时才升级驱动比如之前有个版本在特定交换机下会出现TX timeout升级到9.011.00之后就没再复现过。6.3 备份原始驱动和配置在替换驱动之前建议把系统自带的r8169.ko备份一份cp /lib/modules/$(uname -r)/kernel/drivers/net/ethernet/realtek/r8169.ko /root/r8169.ko.bak万一新驱动出问题还能快速回滚。回滚步骤就是删掉blacklist配置把r8169.ko放回原位depmod -a然后重启。这个备份习惯在关键时刻能救你一命尤其是在远程操作的服务器上驱动装挂了可能直接失联。我个人在实际操作中的体会是CentOS 7上折腾2.5G网卡驱动这件事难点不在技术本身而在细节的堆叠。每一个环节——内核版本匹配、源码兼容性、中断分配、线缆质量——单独看都不复杂但任何一个出问题都会让你卡住。把上面这些步骤按顺序走一遍大部分情况下都能顺利跑满2.5G。如果遇到特别诡异的问题先回到dmesg和ethtool -S的输出那里通常藏着答案。