1. 为什么值得折腾:RTL8125 在 Ubuntu 22.04 上的真实处境
手里有一块 Realtek RTL8125 2.5G 网卡,插上 Ubuntu 22.04 之后lspci能看到设备,ip link却死活不出接口,或者出来了但速率协商只有 100Mbps、跑大流量时频繁断流——这套场景我前后遇到过不下五次,涉及小主机、软路由、DIY NAS 和几台工控机。RTL8125 这颗芯片在消费级 2.5G 网卡里出货量极大,但它在 Linux 下的驱动支持一直是个"半吊子"状态:内核自带的r8169驱动能认,却经常认不全、跑不稳,尤其是早期批次的芯片和某些主板板载版本。
Ubuntu 22.04 默认内核是 5.15 系列,这个版本对 RTL8125 的支持处于"能用但别指望"的水平。Realtek 官方其实一直在维护一个独立的r8125驱动源码包,功能比内核自带的r8169完整得多,支持多队列、TSO/GSO 卸载、中断合并、节能以太网等特性。问题在于官方只给源码,不给 Ubuntu 的预编译 deb 包,所以想用上新特性、想跑满 2.5G 带宽,手动编译安装几乎是绕不开的一步。
这篇内容适合三类人:一是手里有 RTL8125 网卡、在 Ubuntu 22.04 上遇到识别或性能问题的用户;二是想搞清楚 Linux 网卡驱动编译安装完整流程、顺便理解中断配置原理的运维和开发人员;三是做软路由、NAS、虚拟化平台,对网络吞吐和延迟有实际要求的人。我会把编译安装的每一步、每个参数为什么这么设、中断配置到底在配什么,全部拆开讲清楚,你照着做就能复现。
需要先说明一点:下面所有操作基于 Ubuntu 22.04 LTS、内核 5.15 系列、Realtek 官方 r8125 驱动源码包(版本以 9.011.00 及之后的稳定版为准)。不同内核小版本、不同主板 BIOS 设置可能会有细微差异,我会在关键位置标注出来。
2. 动手前的整体设计:为什么是"编译安装"而不是"等内核更新"
2.1 内核自带 r8169 与官方 r8125 的本质区别
很多人第一反应是:内核里不是已经有r8169了吗,为什么还要折腾?这里得把两个驱动的关系讲清楚。
r8169是 Linux 内核里维护的一个"大杂烩"驱动,它要兼容 Realtek 从 8169、8111 一直到 8125 这一大串芯片。为了兼容性,它的代码里充满了各种芯片的兼容分支和 workaround。RTL8125 对r8169来说只是"众多支持型号之一",很多 2.5G 特有的特性要么没实现,要么实现得很保守。
r8125是 Realtek 官方为 8125 系列单独维护的驱动,代码路径干净,专门针对这颗芯片优化。它支持的特性包括:
- 多队列(Multi-Queue):最多支持多个 TX/RX 队列,配合多核 CPU 做 RSS(接收端缩放),单核跑不满 2.5G 时这个特性是救命的。
- 中断合并(Interrupt Coalescing):通过
ethtool -C可以调节中断聚合参数,在高吞吐场景下大幅降低 CPU 中断开销。 - 完整的卸载特性:TSO、GSO、GRO、校验和卸载等,
r8169上部分特性是缺失或默认关闭的。 - 节能以太网(EEE):可以按需开关,某些交换机兼容性差的时候关掉 EEE 能解决断流。
我实测过同一块卡、同一台机器,r8169下iperf3单向跑到 1.6Gbps 左右就开始丢包,换r8125之后稳定在 2.3Gbps 以上,CPU 占用还低了一截。这个差距不是玄学,就是驱动实现完整度的差别。
2.2 为什么不用 DKMS 而选择手动编译
Realtek 官方源码包里其实带了 DKMS 的配置文件,理论上可以make dkms一键搞定,内核升级后自动重编。但我仍然建议第一次上手的人走一遍手动编译流程,原因有两个。
第一,手动编译能让你看清整个链路:源码怎么编、模块怎么装、initramfs怎么更新、旧模块怎么屏蔽。这些环节任何一步出问题,网卡就起不来,而 DKMS 把这些都藏起来了,出问题你根本不知道从哪查。
第二,很多生产环境(尤其是定制内核、实时内核、或者自己裁剪过的内核)DKMS 会因为内核头文件不匹配而失败,这时候还是得回到手动编译。先把手动流程走通,再决定要不要上 DKMS,这是更稳妥的路径。
提示:如果你确定这台机器会频繁升级内核,走通手动流程后,强烈建议再配置 DKMS,否则每次内核更新后网卡都会回退到
r8169,性能问题会重新出现。
2.3 中断配置到底在配什么
标题里专门点了"中断配置",因为这是 RTL8125 性能调优里最容易被忽略、又最影响实际体验的一环。
网卡收发包靠中断通知 CPU。中断太频繁,CPU 全在响应中断,没空处理数据;中断太少,数据在队列里堆积,延迟飙升。中断配置就是在"及时性"和"开销"之间找平衡点。具体到 RTL8125,涉及三个层面:
- 中断亲和性(IRQ Affinity):把不同队列的中断绑定到不同 CPU 核心,避免所有中断挤在一个核上。
- 中断合并参数:通过
ethtool -C调节rx-usecs、tx-usecs等,控制中断聚合的微秒数。 - RPS/RFS:软件层面的接收包分发,多队列硬件不够用时的补充手段。
这三层配合好了,2.5G 才能跑得又稳又省 CPU。后面第 4 节我会给出具体的参数和计算思路。
3. 编译安装全流程:从源码到网卡点亮
3.1 环境准备与依赖安装
先确认你的系统状态。打开终端,跑这几条命令:
uname -r lsb_release -a lspci | grep -i realtek第一条看内核版本,第二条看发行版,第三条确认网卡被 PCI 总线识别到。正常应该能看到类似Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller的输出。如果lspci都看不到,那问题在硬件层(插槽、供电、BIOS 里 PCIe 设备被禁用),跟驱动无关,先解决硬件识别。
确认能看到设备后,装编译依赖:
sudo apt update sudo apt install -y build-essential linux-headers-$(uname -r) dkms ethtool这里每个包都有用:build-essential提供 gcc、make 等编译工具链;linux-headers-$(uname -r)是编译内核模块必须的头文件,版本必须和当前运行内核严格一致,$(uname -r)会自动填当前版本;dkms后面配置自动重编要用;ethtool是调中断和看状态的必备工具。
注意:
linux-headers装不上的情况非常常见,尤其是用了非官方内核(比如自己编的、或者某些云厂商定制内核)。报错通常是"找不到对应版本的 headers 包"。这时候要么换回官方内核,要么手动指定 headers 路径编译。我踩过最坑的一次是内核是 5.15.0-91,但源里只有 5.15.0-88 的 headers,版本对不上,模块编出来加载会报version magic不匹配。解决办法是apt install linux-headers-generic然后重启到匹配的内核。
3.2 获取官方驱动源码
Realtek 官方驱动在官网的下载页面,搜 "RTL8125" 就能找到 "Linux driver" 的源码包,文件名类似r8125-9.011.00.tar.bz2。下载后解压:
tar -xjf r8125-9.011.00.tar.bz2 cd r8125-9.011.00 ls目录里应该能看到src/文件夹、Makefile、README、dkms.conf等。src/里是真正的驱动源码,Makefile是顶层编译入口。
如果你拿到的版本号和我这里不同,没关系,流程完全一样。Realtek 的驱动包结构这些年没大改过。
3.3 编译前的关键检查
在make之前,先做两件事,能省掉后面一堆麻烦。
第一,确认当前r8169是否占用了这块卡:
lsmod | grep r8169 lspci -k | grep -A 3 -i realteklspci -k会显示每个 PCI 设备当前绑定的内核驱动。如果显示Kernel driver in use: r8169,说明内核自带的驱动已经接管了这块卡。编译安装r8125之前,需要先把r8169从这块卡上解绑,否则两个驱动会打架。
第二,看一眼源码里的Makefile,确认编译目标。Realtek 的 Makefile 支持几个常用目标:make默认编译模块,make install安装模块,make dkms走 DKMS 流程。我们手动流程用前两个。
3.4 编译与安装模块
进入源码目录,直接编译:
make clean makemake clean先清一遍,避免上次编译的残留对象文件干扰。编译过程大概几十秒到一两分钟,取决于机器性能。成功的话最后会生成src/r8125.ko这个内核模块文件。
编译报错最常见的原因是头文件路径不对。如果报Cannot find kernel headers之类的错,检查/lib/modules/$(uname -r)/build这个软链接是否指向正确的头文件目录:
ls -l /lib/modules/$(uname -r)/build这个链接断了或者指错,编译必挂。修复方法是重装对应版本的linux-headers。
编译成功后安装:
sudo make install这一步会把r8125.ko拷贝到/lib/modules/$(uname -r)/kernel/drivers/net/ethernet/realtek/目录下,并运行depmod更新模块依赖关系。
3.5 屏蔽 r8169 并加载 r8125
这是整个流程里最关键、也最容易出错的一步。r8169和r8125都声称支持 RTL8125,内核默认会优先加载r8169。必须显式屏蔽r8169,才能让r8125接管。
创建屏蔽配置文件:
sudo tee /etc/modprobe.d/blacklist-r8169.conf <<EOF blacklist r8169 EOF然后更新 initramfs,让屏蔽在开机早期就生效:
sudo update-initramfs -u接着卸载当前已加载的r8169,加载r8125:
sudo modprobe -r r8169 sudo modprobe r8125如果modprobe -r r8169报"模块正在使用",说明网卡接口还开着。先sudo ip link set <接口名> down,再卸载。接口名用ip link查,通常是enp3s0这种格式。
加载成功后验证:
lsmod | grep r8125 lspci -k | grep -A 3 -i realtek dmesg | grep r8125lspci -k应该显示Kernel driver in use: r8125,dmesg里能看到驱动版本和网卡初始化信息。到这一步,网卡就算点亮了。
注意:如果
modprobe r8125报Unknown symbol或version magic错误,基本可以断定是模块和当前内核版本不匹配。回头检查uname -r和编译时用的 headers 版本是否一致,重新编译。
3.6 验证链路速率与基本连通性
网卡起来后,先看协商速率:
ethtool <接口名>输出里Speed一行应该显示2500Mb/s,Duplex显示Full。如果显示1000Mb/s甚至100Mb/s,问题出在物理链路:网线质量、对端设备端口速率、或者网线水晶头接触不良。2.5G 对网线要求比千兆高,超五类线短距离能跑,长距离建议六类以上。
确认速率正常后,配个 IP 测连通性:
sudo ip addr add 192.168.1.100/24 dev <接口名> sudo ip link set <接口名> up ping -c 4 192.168.1.1能 ping 通,说明驱动工作正常。接下来就可以进性能调优环节了。
4. 中断配置详解:把 2.5G 的潜力榨出来
4.1 先搞清楚你的网卡有几个队列
RTL8125 支持多队列,但具体几个队列取决于芯片型号和驱动配置。查队列数:
ethtool -l <接口名>输出会显示Pre-set maximums和Current hardware settings两组,分别对应最大支持队列数和当前启用队列数。如果当前 RX/TX 队列数都是 1,那多核优势完全没发挥出来。
调整队列数:
sudo ethtool -L <接口名> combined 4combined表示收发共用队列,也可以分别用rx和tx指定。队列数不要超过 CPU 物理核心数,否则中断反而会互相干扰。四核机器设 4,八核设 4 到 8 都合理。
4.2 中断亲和性绑定:让每个核各管各的
多队列启用后,每个队列会有独立的中断号。查中断分布:
grep r8125 /proc/interrupts输出类似:
45: 1234567 0 0 0 PCI-MSI 524288-edge enp3s0-TxRx-0 46: 0 987654 0 0 PCI-MSI 524289-edge enp3s0-TxRx-1 47: 0 0 876543 0 PCI-MSI 524290-edge enp3s0-TxRx-2 48: 0 0 0 765432 PCI-MSI 524291-edge enp3s0-TxRx-3理想情况下,每个队列的中断应该落在不同的 CPU 核心上。如果发现所有中断都堆在 CPU0,就需要手动绑定。
查看某个中断当前的亲和性:
cat /proc/irq/45/smp_affinity_list设置亲和性,把中断 45 绑到 CPU1:
echo 1 | sudo tee /proc/irq/45/smp_affinity_list/proc/irq/<号>/smp_affinity_list里填的是 CPU 编号,smp_affinity填的是十六进制掩码。用_list更直观。
手动绑定的问题是重启就失效。持久化有两种做法:一是写 udev 规则,二是用irqbalance配合--banirq排除网卡中断。我一般用 udev 规则,更可控:
sudo tee /etc/udev/rules.d/99-r8125-irq.rules <<EOF ACTION=="add", SUBSYSTEM=="net", KERNEL=="enp3s0", RUN+="/usr/local/bin/set-r8125-irq.sh" EOF然后写一个脚本遍历该网卡的所有中断,按队列号依次绑到对应 CPU。脚本内容根据你的队列数和 CPU 数调整,核心逻辑就是读/proc/interrupts找到r8125相关行,提取中断号,逐个写smp_affinity_list。
提示:如果机器上跑了
irqbalance服务,它会和你的手动绑定抢控制权。要么停掉irqbalance,要么在/etc/default/irqbalance里加IRQBALANCE_BANNED_INTERRUPTS把网卡中断排除。我倾向于停掉它,网卡中断手动管,其他中断交给内核默认策略。
4.3 中断合并参数:延迟与吞吐的平衡杆
中断合并是 RTL8125 调优的重头戏。查当前参数:
ethtool -c <接口名>输出里几个关键项:
rx-usecs:收到包后等待多少微秒再触发中断,值越大中断越少、延迟越高。tx-usecs:发送方向的同类参数。rx-frames:累积多少个包后强制触发中断。adaptive-rx/adaptive-tx:自适应模式,驱动根据负载动态调整。
不同场景的推荐值差别很大,我整理了一张表:
| 场景 | rx-usecs | tx-usecs | rx-frames | adaptive | 说明 |
|---|---|---|---|---|---|
| 低延迟(游戏、实时) | 0-16 | 0-16 | 1-4 | off | 中断频繁,延迟最低 |
| 均衡(日常服务器) | 64 | 64 | 16 | on | 自适应,省心 |
| 高吞吐(大文件、备份) | 128-256 | 128-256 | 32-64 | off | 中断少,CPU 省 |
| 虚拟化宿主 | 64-128 | 64-128 | 16-32 | on | 兼顾多虚拟机 |
设置命令:
sudo ethtool -C <接口名> rx-usecs 64 tx-usecs 64 rx-frames 16 adaptive-rx on adaptive-tx on自适应模式打开后,前面设的固定值会作为上限参考,驱动根据实际流量动态调整。日常用自适应最省事,特殊场景再手动固定。
4.4 RPS/RFS:软件层的补充手段
如果网卡队列数少于 CPU 核心数,或者某些场景下硬件多队列不够用,可以开 RPS(Receive Packet Steering)做软件分发。RPS 的原理是把接收到的包按哈希分发到不同 CPU 的软中断队列。
开启 RPS,先看某个队列的配置:
cat /sys/class/net/<接口名>/queues/rx-0/rps_cpus默认通常是0,表示关闭。设置成 CPU 掩码,比如让 CPU0-3 都参与:
echo f | sudo tee /sys/class/net/<接口名>/queues/rx-0/rps_cpusf是十六进制,对应二进制1111,即 CPU0-3。
RFS(Receive Flow Steering)更进一步,按流(flow)分发,保证同一连接的包落在同一个 CPU 上,提升缓存命中率。开启需要两步:
echo 32768 | sudo tee /proc/sys/net/core/rps_sock_flow_entries echo 2048 | sudo tee /sys/class/net/<接口名>/queues/rx-0/rps_flow_cntrps_sock_flow_entries是全局流表大小,rps_flow_cnt是每个队列的流表大小。数值根据并发连接数调整,一般rps_sock_flow_entries设为 32768 到 65536,每个队列的rps_flow_cnt用全局值除以队列数。
注意:RPS/RFS 是软件分发,会消耗额外 CPU。如果硬件多队列已经够用,没必要开。我一般只在队列数明显少于核心数时才启用。
4.5 中断配置的持久化方案
上面所有ethtool和/proc、/sys的修改重启都会丢。持久化我推荐用 systemd service,比塞进rc.local干净。
写一个 service 文件:
sudo tee /etc/systemd/system/r8125-tune.service <<EOF [Unit] Description=RTL8125 network tuning After=network.target [Service] Type=oneshot ExecStart=/usr/local/bin/r8125-tune.sh RemainAfterExit=yes [Install] WantedBy=multi-user.target EOF脚本/usr/local/bin/r8125-tune.sh里放所有调优命令:设队列数、设中断合并、绑亲和性、开 RPS。然后:
sudo chmod +x /usr/local/bin/r8125-tune.sh sudo systemctl enable --now r8125-tune.service这样每次开机自动应用,内核升级后只要模块还在,配置就不丢。
5. 常见问题与排查技巧实录
5.1 网卡识别不到或接口不出现
这是最高频的问题。排查顺序按下面走:
lspci | grep -i realtek确认 PCI 层能看到设备。看不到就是硬件/BIOS 问题。lspci -k看有没有驱动绑定。如果显示Kernel driver in use: r8169,说明被自带驱动接管了,按 3.5 节屏蔽。dmesg | grep -i r8125看驱动加载日志。如果没有任何输出,说明模块没加载,检查lsmod | grep r8125。ip link看接口是否存在。接口存在但state DOWN,ip link set up拉起来。
我遇到过最隐蔽的一次是主板 BIOS 里 PCIe 插槽被设成了Auto,实际协商到了 x1 速率,网卡能识别但跑不满。进 BIOS 把插槽强制设成 x4 才解决。所以硬件层的问题别忽略。
5.2 编译报错速查
| 报错信息 | 原因 | 解决 |
|---|---|---|
Cannot find kernel headers | headers 未装或路径不对 | 装linux-headers-$(uname -r),检查/lib/modules/$(uname -r)/build |
version magic mismatch | 模块与内核版本不一致 | 确认 headers 版本与uname -r一致,重编 |
Unknown symbol | 依赖模块未加载 | modprobe相关依赖,或depmod -a |
Permission denied | 没用 sudo | 安装和加载模块都要 sudo |
gcc: command not found | 编译工具链缺失 | apt install build-essential |
5.3 速率协商不到 2.5G
ethtool显示速率低于 2500Mb/s,按这个顺序查:
- 网线:换一根确认过的六类线,超五类短距离可以但别赌。
- 对端设备:交换机或路由器端口是不是 2.5G?很多千兆交换机插上去只能协商 1000M。
- 强制速率:
sudo ethtool -s <接口名> speed 2500 duplex full autoneg on,有些对端设备自动协商有问题,手动指定能解决。 - EEE 干扰:
sudo ethtool --set-eee <接口名> eee off,节能以太网和某些交换机不兼容会导致降速或断流。
5.4 大流量下断流或丢包
跑iperf3或大文件传输时断流,常见原因和排查:
- 中断全堆在一个核:
grep r8125 /proc/interrupts看分布,按 4.2 节绑亲和性。 - 中断合并参数太激进:
rx-usecs设太大,队列溢出丢包。调小试试。 - 队列数不够:
ethtool -l看队列数,按 4.1 节增加。 - 网卡过热:2.5G 满速时芯片发热不小,散热差的机器会降速。摸一下网卡散热片,烫手就加个小风扇。
- 驱动版本旧:Realtek 驱动更新挺频繁,旧版本有已知 bug。去官网下最新版重编。
5.5 内核升级后网卡失效
这是手动编译方案的固有痛点。内核一升级,/lib/modules/<新版本>/下没有r8125.ko,开机就回退到r8169。
解决办法就是上 DKMS。在源码目录里:
sudo make dkmsDKMS 会把驱动注册到系统,每次内核更新自动重编。前提是dkms包已装、dkms.conf配置正确。Realtek 官方包里的dkms.conf一般是对的,直接跑就行。
如果 DKMS 也失败(比如新内核 headers 还没发布),临时方案是重启到旧内核,等 headers 更新后再重编。
5.6 独家避坑经验
几个文档里不会写、但实际会遇到的坑:
- 屏蔽 r8169 后别急着删模块文件。有些人直接把
r8169.ko删了,结果系统里其他 Realtek 千兆卡也一起失效。用 blacklist 就够了,别动文件。 update-initramfs别忘了。只改 blacklist 不更新 initramfs,开机早期r8169还是会先加载,然后r8125加载时发现设备被占,直接失败。- 虚拟机里别折腾这个。VMware、VirtualBox 的虚拟网卡是模拟设备,跟 RTL8125 物理驱动没关系。热词里那些"virtualbox 网卡驱动"的问题,方向完全不对。
- 双系统注意 Windows 的快速启动。Windows 快速启动会让网卡处于半休眠状态,切到 Linux 后网卡可能识别异常。关掉 Windows 的快速启动能解决。
- 备份原驱动。编译安装前把
/lib/modules/$(uname -r)/kernel/drivers/net/ethernet/realtek/下的原文件备份一份,出问题能快速回滚。
6. 性能验证与回滚方案
6.1 用 iperf3 验证实际吞吐
驱动装好、中断调完,得用数据说话。两台机器直连或者通过 2.5G 交换机连接,一台跑服务端:
iperf3 -s另一台跑客户端:
iperf3 -c <服务端IP> -t 30 -P 4-t 30跑 30 秒,-P 4开 4 个并行流。单流跑不满 2.5G 是正常的,多流才能压满。理想结果应该在 2.3Gbps 以上。同时开另一个终端看 CPU 占用:
top -d 1重点看si(软中断)和hi(硬中断)占比。调优到位的话,2.5G 满速时中断相关 CPU 占用应该控制在 20% 以内。如果某个核 100% 跑满,说明中断亲和性或队列数还有优化空间。
6.2 延迟测试
吞吐之外,延迟也重要。用ping看基础延迟:
ping -c 100 -i 0.01 <对端IP>直连情况下,2.5G 的 RTT 应该在 0.1ms 以内。如果延迟抖动大,检查中断合并参数是不是设得太激进,rx-usecs调小试试。
6.3 回滚到 r8169 的完整步骤
万一r8125出问题需要回滚,按这个顺序:
sudo modprobe -r r8125 sudo rm /etc/modprobe.d/blacklist-r8169.conf sudo update-initramfs -u sudo modprobe r8169然后重启验证。lspci -k应该重新显示r8169。回滚后性能会回到之前水平,但至少网络能用。
提示:回滚前先确认
r8169模块文件还在。如果之前手贱删了,得从同版本内核的机器上拷回来,或者重装linux-modules包。
6.4 长期维护建议
这套手动方案跑起来后,日常维护就三件事:内核升级后检查驱动是否还在、Realtek 官网有新驱动时评估是否升级、定期看dmesg有没有网卡报错。
我个人的习惯是在/etc/motd或者登录脚本里加一行检查,登录时自动提示当前网卡驱动版本和队列状态。这样换机器、重启后一眼就能看出配置有没有丢。
最后分享一个我用了很久的小脚本,放在~/.bashrc里,登录自动打印网卡状态:
if command -v ethtool &>/dev/null; then for iface in $(ls /sys/class/net/ | grep -E '^en'); do echo "=== $iface ===" ethtool $iface 2>/dev/null | grep -E 'Speed|Duplex|Driver' done fi一眼看清速率、双工、驱动版本,比每次手动敲命令省事。这套流程我在四台不同硬件的机器上复现过,从 N100 小主机到 Xeon 服务器,只要芯片是 RTL8125,步骤完全通用。唯一需要按机器调整的就是队列数和中断亲和性绑定,这两个跟 CPU 核心数直接相关,按第 4 节的思路算一下就行。