如果你跟我一样在某宝上淘了一块 Realtek RTL8125BG 的 2.5GbE 网卡或者新主板板载了螃蟹家的 2.5G 网口装完 Ubuntu 之后大概率会碰到同一个问题系统认得出网卡但速率死活锁死在 1000Mb/siperf3 一打就只有九百多兆甚至偶尔还会直接断流。这口锅十有八九要扣到内核自带驱动 r8169 头上。在 Ubuntu 上做驱动升级最稳的不是手动make make install而是走 DKMS 这套自动化编译体系。DKMS 的直白解释就是给驱动装个“自动适配器”以后内核一升级它会自动替你把驱动重新编译一遍不用你每次升级完内核都手动折腾。今天就把我这套“告别 r8169换 Realtek 官方驱动 DKMS 管理”的完整实战记录下来全程可复现也把踩过的坑一并列出来省得你反复折腾几个晚上。1. 为什么要跟 r8169 说再见问题现象与根因分析1.1 先看现场那块“看起来能用”的网卡事情得从一块 RTL8125BG 单口 2.5GbE 网卡说起。插上 PCIe 槽位、开机进 Ubuntu 22.04系统很顺利就识别到了网络接口ip link能看到 eth0ping网关也不丢包。乍一看一切正常但当我准备从 NAS 拷贝几个大文件时速度稳定在 110MB/s 左右——这明摆着是千兆速度根本不是 2.5G 应该有的水平。再用ethtool eth0一看输出里面的 Speed 赫然写着1000Mb/s。更离谱的是有时候重启之后甚至会出现掉到100Mb/s的情况排查了交换机端口和网线之后都没问题问题范围一下子缩小到了驱动层。这种“能用但不完全能用”的状态才是最磨人的。1.2 根因r8169 只是“能用”不是“好用”Ubuntu 内核里自带的r8169驱动严格来说是一个通用型驱动模块它要照顾的是一大票 Realtek 千兆网卡RTL8111/8168/8411 等对后来才出的 RTL8125 / RTL8126 这代 2.5GbE 芯片的支持只能算是“兼容级别”。realtek 2.5GbE 系列网卡有不少私有特性和寄存器控制逻辑官方闭源驱动里做了大量针对性的适配和优化而内核自带的 r8169 驱动在这方面的处理相对“朴素”。结果就是速率协商经常不准、高负载下 CPU 占用偏高、偶尔出现断流或者Tx/Rx丢包。尤其当你用 2.5G 交换机、2.5G NAS、或者两台 2.5G 网卡直连时r8169 的表现会非常不稳定。1.3 为什么最终的方案选型是“官方驱动 DKMS”网上关于这个问题的解决办法不少大概有这么几条路手动编译官方驱动然后make make install安到系统里。这个方式最简单直接但代价是每次内核升级后驱动就要重编一次哪天忘了编译网卡就罢工了。修改内核参数强制 r8169 开启 2.5G 协商。这个偶尔能奏效但治标不治本换块网卡、换个交换机可能就拉了。禁用 r8169用官方驱动并注册进 DKMS。这是我这几年用下来最省心的一套流程。DKMSDynamic Kernel Module Support本质上是帮你管理“第三方内核模块”的自动化系统。你把驱动源码交给它它负责在当前内核下编译并安装模块以后系统自动升级了新内核它会在新内核环境下自动重新编译一次。对家用服务器、NAS、长期跑着的 Ubuntu 机器来说这几乎是最优解一劳永逸又不用手动干预。2. 动手前的一小时准备识别芯片与下载驱动2.1 先确认你的网卡芯片究竟是谁动手之前首要任务是确认你手里的网卡芯片具体型号。别嫌这一步啰嗦Realtek 家的网卡命名虽然都带“螃蟹”但同样是 2.5GRTL8125 和 RTL8126 对应的驱动包并不完全一样装错了会直接编译失败。在终端里执行lspci | grep -i ethernet lspci -v -s $(lspci | grep -i ethernet | awk {print $1} | head -n1)第一行命令输出的是设备列表比如下面这样02:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller (rev 05)RTL8125基本就是 2.5G 家族的主力部分新卡会显示 RTL8126如果显示的是 RTL8168 或 RTL8111那是千兆芯片本文的驱动方式同样适用只是要下载对应的 r8168 驱动包。另外再强调一点系统里ethtool -i eth0可以看到当前正在使用的驱动模块名。如果显示driver: r8169说明你正被通用驱动接管这基本就是问题的根源之一。2.2 从 Realtek 官网下对驱动包Realtek 官方驱动下载页面需要一点耐心找这里我按常见路径给你捋一下。打开 Realtek 官网的下载中心搜索型号时建议直接搜RTL8125找到名为 “Unix driver (autoload) for RTL8125” 的压缩包。解压后你会看到目录名类似r8125-9.012.04-1核心就是r8125这个包名和对应版本号。这里有个容易混淆的点标题里说的 r8169 是内核模块名而官方针对老芯片的驱动包叫 r8168针对 2.5G 芯片的驱动包叫 r8125。如果你买的是 USB 外置 2.5G 网卡那驱动可能是 r8152/r8156 系列不能一概而论。先用lspci或lsusb确认好总线类型再决定下载哪个包。下载完成后在 Ubuntu 里解压并确认内容tar -xvf r8125-*.tar.bz2 cd r8125-*/ ls目录里通常有src/、autorun.sh、Makefile等文件这些是后面 DKMS 要用的核心源码。2.3 环境依赖与安全备份在开始安装之前我强烈建议先做两件事第一件事保证系统里有完整的编译工具链和内核头文件。如果你用的是服务器或者平时不怎么装软件包的桌面版 Ubuntu直接执行sudo apt update sudo apt install -y build-essential dkms linux-headers-$(uname -r)linux-headers-$(uname -r)是内核模块编译的“脚手架”系统内核对模块进行链接时依赖这些头文件。漏装的话后面dkms build阶段大概率会报“找不到内核源码树”的错误。第二件事备份网卡当前的网络配置。特别是你在用 SSH 远程操作服务器一旦驱动切换过程中网卡断连你至少还得有办法恢复。我常用的做法是把/etc/netplan/和/etc/NetworkManager/下的关键配置复制到本地顺手把当前接口名、IP 地址记下来防止改完驱动后网口名变了连不上。提示如果是远程服务器尽量确保有 IPMI、带外管理或者物理控制台兜底否则驱动重装期间 SSH 断掉就非常尴尬。3. DKMS 驱动的完整安装实战3.1 一键安装编译工具链与 DKMS前面已经提到需要build-essential、dkms和内核头文件这里我再单独把 DKMS 讲透一点。DKMS 在 Ubuntu 的软件源里就有直接apt install dkms会把它以及依赖的dpkg-dev一起装好。安装完成后检查一下dkms status此时应该没有任何模块记录或者只有系统自带的第三方模块比如某些显卡驱动。这一步的目标是确保 DKMS 命令本身可用以及/usr/src目录存在后面驱动源码会被链接到这里统一管理。如果dkms status报错说 DKMS 版本过低或者内核头文件对不上请先sudo apt upgrade把系统整体更新一遍。我在 Ubuntu 20.04 上遇到过旧内核头文件残留导致 DKMS 编译失败的问题解决办法是手动装好当前内核版本对应的 linux-headers再继续。3.2 把官方驱动安装进 DKMS 体系假设你已经解压好了驱动源码目录名是r8125-9.012.04-1接下来进入最关键的一步注册进 DKMS。首先把源码放到/usr/src下并按 “包名-版本号” 的规范命名。这一步不能省略DKMS 就是依据/usr/src下的目录名来识别模块的sudo cp -r r8125-9.012.04-1 /usr/src/然后添加并安装sudo dkms add -m r8125 -v 9.012.04-1 sudo dkms build -m r8125 -v 9.012.04-1 sudo dkms install -m r8125 -v 9.012.04-1dkms build这一步实际上就是在执行make只是把目标路径指向了 DKMS 管理的目录。编译输出会在屏幕上滚一大段看到Building module: ...和DKMS: build completed.就说明编译成功了。编译成功后dkms status会显示r8125/9.012.04-1: installed这就说明模块已经安装在当前内核的kernel/drivers/net/ethernet/realtek/目录下并且会在未来内核升级时自动触发重编。3.3 禁用 r8169 与配置模块参数这一步非常关键。即使你把官方 r8125 驱动装好了如果内核里的 r8169 模块还在并且modprobe的加载顺序优先那系统启动时照样会先加载 r8169。两个驱动同时尝试管理同一块网卡轻则网卡设备名错乱重则直接无法识别。最简单的办法是添加一个黑名单文件sudo tee /etc/modprobe.d/blacklist-r8169.conf EOF blacklist r8169 EOF然后在/etc/modprobe.d/r8125.conf里写入模块参数可选建议加上options r8125 speed2500speed2500参数是让驱动优先把协商速率锁定在 2.5G这能避免某些交换机因为自动协商逻辑问题导致降级到千兆。不过要注意如果你连接的设备只支持千兆硬性指定 2500 可能导致无法协商成功。更稳妥的做法是先在默认参数下测试再按需调整。最后刷新一下内存镜像确保重启后生效sudo update-initramfs -u sudo rebootupdate-initramfs -u会把黑名单和新的内核模块一并打包进启动镜像这是很多人容易漏掉的一步。不执行的话重启后系统可能仍然加载旧的 initramfs 内容等于白忙一场。3.4 重启后的验证流程重启完成后先用几条命令确认驱动是否真的切换成功lsmod | grep r8125 lsmod | grep r8169 ethtool -i eth0理想状态下r8125出现r8169干净得像从没存在过一样。ethtool -i eth0的输出里driver: r8125就是最好的证明。接着用ethtool eth0看协商速率Settings for eth0: Supported ports: [ TP ] Supported link modes: 100baseT/Full 1000baseT/Full 2500baseT/Full Speed: 2500Mb/s看到Speed: 2500Mb/s时心头的石头才真正落地。如果这里显示的还是1000Mb/s别急后面第 5 章会专门讲这类的排查思路。最后别忘了测一下连通性iperf3 -c 192.168.2.1 -P 4 -t 30这一步直接决定驱动切换有没有实质提升。正常情况下局域网客户端到 2.5G NAS 的 TCP 吞吐应该能到 1.8Gbps 以上具体数值取决于小包处理能力和交换机性能。4. 用数据说话性能实测与参数调优4.1 iperf3 打了 10 轮结果出乎意料驱动切换这件事最怕的就是“感觉上快了”但没数据佐证。我在同一台 Ubuntu 服务器上分别用 r8169 和 r8125 各跑了 10 轮 iperf3 测试固定端口、固定网线、固定交换机端口尽量减少变量。测试命令我放在这里方便你以后复现服务端另一台机器iperf3 -s -p 5201客户端被测机器iperf3 -c 192.168.2.10 -p 5201 -P 4 -t 30 -O 5-P 4是开 4 个并发流用来压 TCP 多流场景-O 5表示忽略前 5 秒的“暖机数据”避免 TCP 慢启动阶段拉低平均值。每轮测试间隔 10 秒连续测 10 轮之后取中位数比单跑一次要有说服力得多。4.2 性能对比表与解读我自己实测下来r8169 和 r8125 的差距主要体现在这几个维度测试项r8169内核自带r8125DKMS 官方驱动协商速率默认1000Mb/s2500Mb/sTCP 单流吞吐935Mbps1.82GbpsTCP 4 流并发吞吐945Mbps2.13GbpsCPU 占用iperf3 压测25% 左右18% 左右长时间大文件传输稳定性偶发断流稳定不掉速这个结果符合我的预期r8169 驱动虽然也能“跑起来”但似乎在中断处理、descriptor ring 缓冲区管理、以及硬件 offload 特性的利用上做了不少妥协。换成官方 r8125 驱动后多队列中断和 GMII 协商被正确识别整卡才真正发挥出 2.5G 该有的水平。注意CPU 占用数据仅代表我这一块 RTL8125BG 在 iperf3 压力下的表现不同主板、不同内核版本会有差异。但整体趋势是明确的——官方驱动的收包路径更高效中断处理更平滑。4.3 网卡高级参数的调优建议驱动切换之后还可以再压榨一点性能空间。我通常会在/etc/sysctl.conf或单独在 netplan 配置里调整以下几项加大环形缓冲区ring bufferethtool -G eth0 rx 4096 tx 4096Realtek 2.5G 网卡默认的 rx/tx ring 比较保守在高并发下ring 满了就会触发丢包。改成 4096 项能显著提高突发流量的缓存能力。开启硬件 offloadethtool -K eth0 gro on gso on tso onGROGeneric Receive Offload和 TSOTCP Segmentation Offload是把原本要 CPU 处理的封包聚合/分段工作交给网卡硬件完成。对于 2.5G 这种速率开启后 CPU 占用能再降一截。注意如果你后面要用 tcpdump 抓包建议临时关掉 GRO否则抓到的是聚合后的大包分析会非常痛苦。调整中断合并ethtool -C eth0 rx-usecs 100 tx-usecs 100这个参数控制网卡攒多少微秒的中断再统一上报 CPU。值太小时 CPU 会被频繁打断值太大则延迟变高。100 微秒是我实测局域网延迟和 CPU 占用之间的一个比较平衡的点适合大多数家用/小型办公场景。需要说明的是ethtool的修改在重启后会失效想要持久化要么写进 netplan 的post-up命令里要么像我一样写一个 systemd service 开机执行。配置文件写法我放在第 5 章一并给个参考。5. 那些年踩过的坑常见问题与排障实录5.1 DKMS 编译失败的 3 个高频原因DKMS 这条路虽然稳但也不是每次都能一次通过。我遇到过的编译失败原因基本逃不开这三类。第一类内核头文件缺失或版本不匹配。报错信息通常是*** /lib/modules/5.15.0-xxx/build: No such file or directory。解决办法就是确认 linux-headers 版本和当前内核一致uname -r然后apt install linux-headers-$(uname -r)。第二类GCC 版本太新老驱动源码编译报错。比如内核 6.5 搭配 GCC 13某些旧版 r8125 驱动会因为参数类型不匹配报 warning 被当成 error。这种情况要么换新版驱动包要么在 DKMS 编译时临时加CFLAGS宽松处理但更推荐前者。Realtek 官方其实一直有在维护驱动包下载最新版通常能解决这类兼容问题。第三类Secure Boot 导致模块签名不过。UEFI 安全启动开启时内核只加载有签名验证的模块。DKMS 编译出来的模块没有签名启动时会被拒绝加载。解决办法有两个一是进 BIOS 关闭 Secure Boot二是在 Ubuntu 里用mokutil --import导入生成的签名密钥。我自己图省事直接关了但要提醒一下关 Secure Boot 会降低系统启动链的完整性验证请根据自身风险接受度判断。# 查看当前是否启用了 Secure Boot mokutil --sb-state5.2 重启后还是 r8169 的“幽灵”问题这是新手最容易踩的坑驱动明明装好了dkms status也显示 installed但重启之后网卡被 r8169 接管了。先说原因r8169 是内核自带的模块它很可能被内建进内核而不是以独立.ko文件存在。这种情况下单纯加 blacklist 文件是没用的因为内建模块不经过 modprobe 加载。解决思路是先确认/etc/modprobe.d/blacklist-r8169.conf内容正确再执行sudo update-initramfs -u sudo reboot如果重启后依然不行可以试试把 r8169 模块重命名成占位模块不推荐新手操作或者在/etc/default/grub的内核命令行里加入module_blacklistr8169然后sudo update-grub并重启。这个方法能阻止内核早期加载该模块但同样是修改系统启动链路的操作要谨慎一点。5.3 速率上不去但驱动已经换对了驱动显示是 r8125ethtool eth0也认出了接口但 Speed 依然是 1000Mb/s这时候问题大概率不在驱动而在协商链路。我用过一个笨办法来圈定问题范围把网线两端都拔下来换一根已知能跑 2.5G 的网线直连交换机上标注支持 2.5G 的端口。如果速率还是上不去再查交换机的端口配置看看端口速率是否被锁定或者是否有流控/EEE 节能以太网的影响。提示2.5G 对网线要求比千兆高不少至少建议用 Cat5e 以上线缆长距离或屏蔽环境直接上 Cat6。我遇到过一根“祖传”网线跑千兆稳如老狗一协商 2.5G 就疯狂降速到百兆最后换线才解决。另外可以用ethtool eth0看Advertised link modes和Speed确认驱动和交换机两侧都通告了 2500baseT/Full。如果有一侧只通告 1000baseT协商结果自然只有千兆。5.4 联网中断与 IP 获取异常的处理切换驱动后网卡名可能从原来的eth0变成enp2s0或者ens1f0特别是 Ubuntu 的 systemd 命名规则下接口名跟硬件 PCI 槽位强相关。如果你原来配置的 netplan 里写死了“eth0”或者某个旧接口名驱动切换后接口名变了IP 就起不来。我推荐在 netplan 里用 MAC 地址绑定而不是接口名这样不管接口名怎么变都稳定network: version: 2 ethernets: enp2s0: match: macaddress: xx:xx:xx:xx:xx:xx dhcp4: true dhcp6: true set-name: eth0这里把真实网卡 MAC 填进去配合set-name: eth0强制改名为 eth0配合之前切换的驱动重启后基本不会再出现找不到网络的情况。DHCP 获取不到 IP 的另一个常见原因是 NetworkManager 和 systemd-networkd 同时管着同一个接口。建议还是二选一桌面版 Ubuntu 用 NetworkManager 更顺手服务器版用 systemd-networkd 更干净。切换前先停掉另一个服务避免接口状态互相打架。5.5 切换驱动的持久化配置参考最后把我一直用的持久化配置放一个完整的示例方便你一次性照抄。除了 netplan 之外我还用 systemd service 保证 ethtool 的 ring buffer 和 offload 参数开机自动生效sudo tee /etc/systemd/system/ethtool-tune.service EOF [Unit] DescriptionEthtool tuning for r8125 Afternetwork.target [Service] Typeoneshot ExecStart/usr/sbin/ethtool -G eth0 rx 4096 tx 4096 ExecStart/usr/sbin/ethtool -K eth0 gro on gso on tso on ExecStart/usr/sbin/ethtool -C eth0 rx-usecs 100 tx-usecs 100 RemainAfterExityes [Install] WantedBymulti-user.target EOF sudo systemctl daemon-reload sudo systemctl enable --now ethtool-tune.service注意ExecStart里写的 eth0 要和 netplan 里set-name后的接口名保持一致否则 service 启动时会因为找不到接口而报错。这个写法我也用了挺久稳定可靠。6. 写在最后的几点个人体会这套流程我从 Ubuntu 20.04 一直用到 24.04内核从 5.4 升到 6.8每次升级都没有再手动折腾过网卡驱动DKMS 在后台自动把 r8125 模块重新编译好了。你可能会觉得“只是换了个驱动而已”但对我来说省下的不是一次两次手动编译的时间而是“每回内核一升级就担心网卡挂掉”的那种心理负担。如果让我给一个新人最直接的建议那就是换驱动之前先把 lspci 和 ethtool -i 的输出截图存好再把 netplan 的配置备份一份。这两步做到位哪怕中间出岔子你也能快速回到原点。不要一上来就照着命令敲先理解这套 “DKMS 黑名单 initramfs” 的组合到底在干什么——它本质上就是一套“让第三方驱动的生命周期和内核生命周期自动同步”的机制理解了这一点以后遇到任何网卡、显卡、虚拟化驱动的问题思路都是相通的。最后再分享一个小技巧Realtek 官方驱动包解压后通常带一个autorun.sh它确实能一键安装驱动但它不自动注册 DKMS也不帮你做黑名单管理。我个人强烈建议无视它老老实实按 DKMS 流程走一遍。毕竟省事的最高境界不是今天少敲几条命令而是以后都不用再敲。