我的环境
设备:NanoPi R5C(暂未查出 Armbian 还是 NanoPi 有坑,见附录)
Linux发行版:openmediavault 7.4.10-1(在 Armbian 12 上使用脚本构建)(自己埋了坑,见附录)
网卡:RTL8125BG 两张,分别接口名为 eth0 和 eth1
我直接在 root 用户下操作
折腾目标
虽然没有需要处理大量并发连接的需求,但是重在折腾
- 使用新版本的 r8125 驱动
- 每次更新内核之后,自动重新生成对应的内核驱动模块
- 开启网卡的 硬件多收发队列 功能(使用 ethtool -l 功能验证)
- 开启网卡的 Receive-Side Scaling (RSS) 接收端缩放 功能(使用 ethtool -x 功能验证)
- 关闭网卡的 Active-state power management (ASPM) 活动状态电源管理 功能(使用 lspci -vv -s 功能验证)
- 关闭网卡的 Energy Efficient Ethernet (EEE) 节能以太网 功能
Dynamic Kernel Module Support (DKMS) 介绍
内核模块是需要和内核版本对应的
这也就意味着,如果你要安装额外的内核模块,例如网卡驱动,那么每次升级内核之后,都要重复做一次模块编译动作
DKMS 的一个基本功能是,如果安装了新内核版本,它会自动重新编译所有 DKMS 模块。这允许主线内核之外的驱动程序和设备在 Linux 内核升级后继续工作。
https://en.wikipedia.org/wiki/Dynamic_Kernel_Module_Support
风险提示
做好无法使用这张网卡的准备,特别是无头系统
例如,你可以准备一个使用其他驱动的网卡,以确保你的能通过网络连上设备
或者对于嵌入式设备,直接上TTL线等调试端口
获取 dkms 驱动
既然已经知道 dkms 这种好东西,那么这里列出三种常见方法
找到别人造好的轮子
对于热门网卡硬件,很容易找到别人造好的轮子
像我需要 r8125 驱动,找到这两个项目
https://github.com/awesometic/realtek-r8125-dkms
https://github.com/devome/r8125-dkms
从发行版仓库获取
取决于发行版的软件仓库策略,可能版本会稍微老一点
这是我在 Debian 12 官方仓库的搜索结果
root@xxx:~# apt search r8125
Sorting... Done
Full Text Search... Done
r8125-dkms/stable 9.011.00-3 all
  dkms source for the r8125 network driver
未测试各项特性
手搓 dkms 驱动包
https://wiki.archlinux.org/title/DKMS_package_guidelines
准备工作
检查目前正在使用的驱动版本
这是我折腾过以后的了,有些人还在使用 r8169 驱动
遇到卡在 r8169 驱动问题的朋友请看本文最后面的常见问题
root@xxx:~# ethtool -i eth0
driver: r8125
version: 9.010.01-NAPI
firmware-version: 
expansion-rom-version: 
bus-info: 0002:21:00.0
supports-statistics: yes
supports-test: no
supports-eeprom-access: no
supports-register-dump: yes
supports-priv-flags: no
安装 DKMS
apt install dkms
内核头文件
检查内核头文件有没有安装
root@xxx:~# dpkg-query -s linux-headers-$(uname -r) 
dpkg-query: package 'linux-headers-6.1.25' is not installed and no information is available
Use dpkg --info (= dpkg-deb --info) to examine archive files.
安装内核头文件
Armbian
https://docs.armbian.com/User-Guide_Armbian-Config/System/#kernel-headers
Debian
如果你没有手动更换到奇怪的内核,那么大概率能直接使用这个命令安装
apt install linux-headers-$(uname -r)
或者参考你的设备的文档
安装方法1:通过 deb 包安装
例如使用这个项目
https://github.com/devome/r8125-dkms
正常情况下,先下载软件包,然后只要一条命令就能安装好
wget https://github.com/devome/r8125-dkms/releases/download/9.013.02-2/r8125-dkms_9.013.02-2_all.deb
dpkg -i r8125-dkms_9.013.02-2_all.deb
先不重启,先验证内核模块有没有装上
root@nanopi-r5c:~# lspci | grep RTL8125
0001:01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller (rev 05)
0002:01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller (rev 05)
root@nanopi-r5c:~# lspci -s 0001:01:00.0 -k
0001:01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller (rev 05)
        Subsystem: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller
        Kernel driver in use: r8169
        Kernel modules: r8169, r8125
如果 Kernel modules 里没有显示需要的模块,跳到本文最后的常见问题
重启
安装方法2:通过自行构建安装
那么问题来了,在某些时候,你希望可以自行构建这个软件包
例如,我需要改动一下驱动的配置或者源码
这时候就需要自己构建
准备
安装构建环境
apt install devscripts debmake debhelper build-essential dh-dkms
准备项目源码
https://github.com/awesometic/realtek-r8125-dkms 项目包含了驱动源码,相比之下比较好操作
下载相应版本的驱动源码存档
wget https://github.com/awesometic/realtek-r8125-dkms/archive/refs/tags/9.013.02-2.zip
解压压缩包,并进入项目目录
unzip ./9.013.02-2.zip
cd realtek-r8125-dkms-9.013.02-2/
检查 Realtek 的官方驱动在不在
xxx@xxx:~/r8125-dkms-9.012.03-2# ls ./src/
Makefile	   r8125_firmware.c  r8125_ptp.h      rtl_eeprom.c
Makefile_linux24x  r8125_firmware.h  r8125_realwow.h  rtl_eeprom.h
r8125.h		   r8125_n.c	     r8125_rss.c      rtltool.c
r8125_dash.h	   r8125_ptp.c	     r8125_rss.h      rtltool.h
为了实现我的目标,还需要编辑 Makefile 文件,指定编译驱动时的参数
nano ./src/Makefile
并作以下修改
# 关闭网卡的 Active-state power management (ASPM) 活动状态电源管理 功能
CONFIG_ASPM = n
# 关闭网卡的 Energy Efficient Ethernet (EEE) 节能以太网 功能
ENABLE_EEE = n
# 开启网卡的 Multiple Tx Queue 多队列发送 功能
ENABLE_MULTIPLE_TX_QUEUE = y
# 开启网卡的 Receive-Side Scaling (RSS) 多队列接收 功能
ENABLE_RSS_SUPPORT = y
开始构建
dpkg-buildpackage -b -rfakeroot -us -uc
构建成功的话,就能在上级目录找到生成的软件包
../realtek-r8125-dkms_9.013.02-2_arm64.deb
安装
dpkg -i realtek-r8125-dkms_9.013.02-2_arm64.deb
先不重启,验证内核模块有没有装上
root@nanopi-r5c:~# lspci | grep RTL8125
0001:01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller (rev 05)
0002:01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller (rev 05)
root@nanopi-r5c:~# lspci -s 0001:01:00.0 -k
0001:01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller (rev 05)
        Subsystem: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller
        Kernel driver in use: r8169
        Kernel modules: r8169, r8125
如果 Kernel modules 里没有显示需要的模块,跳到本文最后的常见问题
重启
验证
回到一开始我们的折腾目标
一定要检查,因为我遇到了多队列未能按预期启用的情况
检查 dkms 状态
root@xxx:~# dkms status
Deprecated feature: REMAKE_INITRD (/var/lib/dkms/realtek-r8125/9.013.02/source/dkms.conf)
realtek-r8125/9.013.02, 6.1.25, arm64: installed
检查网卡正在使用的驱动
root@xxx:~# ethtool -i eth0
driver: r8125
version: 9.013.02-NAPI-RSS
firmware-version: 
expansion-rom-version: 
bus-info: 0002:21:00.0
supports-statistics: yes
supports-test: no
supports-eeprom-access: no
supports-register-dump: yes
supports-priv-flags: no
检查驱动的硬件多队列功能
root@bb-nanopi-r5c:~# ethtool -l eth0
Channel parameters for eth0:
Pre-set maximums:
RX:		4
TX:		2
Other:		n/a
Combined:	n/a
Current hardware settings:
RX:		2
TX:		2
Other:		n/a
Combined:	n/a
这里可以看到 Current hardware settings 里面 RX 和 TX 都分别开启了2个硬件队列
如果 Pre-set maximums 显示1以外的值,但是 Current hardware settings 却都只设置成1的话,跳到附录
检查多队列有没有启用
虽然驱动支持多队列,但是实际上有没有启用,需要额外的检查
以下是成功启用的网卡在中断计数表中的输出
root@nanopi-r5c:~# grep eth1 /proc/interrupts
 78:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0   0 Edge      eth1-0
 79:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0   1 Edge      eth1-1
 80:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0   2 Edge      eth1-2
 81:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0   3 Edge      eth1-3
 82:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0   4 Edge      eth1-4
 83:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0   5 Edge      eth1-5
 84:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0   6 Edge      eth1-6
 85:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0   7 Edge      eth1-7
 86:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0   8 Edge      eth1-8
 87:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0   9 Edge      eth1-9
 88:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0  10 Edge      eth1-10
 89:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0  11 Edge      eth1-11
 90:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0  12 Edge      eth1-12
 91:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0  13 Edge      eth1-13
 92:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0  14 Edge      eth1-14
 93:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0  15 Edge      eth1-15
 94:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0  16 Edge      eth1-16
 95:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0  17 Edge      eth1-17
 96:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0  18 Edge      eth1-18
 97:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0  19 Edge      eth1-19
 98:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0  20 Edge      eth1-20
 99:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0  21 Edge      eth1-21
100:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0  22 Edge      eth1-22
101:          0          0          0          0  MBI-PCI-MSIX-0001:01:00.0  23 Edge      eth1-23
RSS 状态
root@nanopi-r5c:~# ethtool -x eth1
RX flow hash indirection table for eth1 with 2 RX ring(s):
    0:      0     1     0     1     0     1     0     1
    8:      0     1     0     1     0     1     0     1
   16:      0     1     0     1     0     1     0     1
   24:      0     1     0     1     0     1     0     1
   32:      0     1     0     1     0     1     0     1
   40:      0     1     0     1     0     1     0     1
   48:      0     1     0     1     0     1     0     1
   56:      0     1     0     1     0     1     0     1
   64:      0     1     0     1     0     1     0     1
   72:      0     1     0     1     0     1     0     1
   80:      0     1     0     1     0     1     0     1
   88:      0     1     0     1     0     1     0     1
   96:      0     1     0     1     0     1     0     1
  104:      0     1     0     1     0     1     0     1
  112:      0     1     0     1     0     1     0     1
  120:      0     1     0     1     0     1     0     1
RSS hash key:
9e:14:c7:77:95:05:00:cf:4a:27:04:a3:2c:94:de:1e:7c:7a:4a:55:0b:28:33:7d:e9:5d:e1:31:9f:db:d0:88:0a:92:1d:83:eb:f3:5c:40
RSS hash function:
    toeplitz: on
    xor: off
    crc32: off
如果报错或者显示很大区别的其他内容,跳到附录
检查 ASPM 状态
这里我知道我的网卡的 PCI 地址是 0002:01:00.0
root@nanopi-r5c:~# lspci -vv -s 0002:01:00.0 | grep -E "LnkCtl"                
                pcilib: sysfs_read_vpd: read failed: No such device
                LnkCtl: ASPM Disabled; RCB 64 bytes, Disabled- CommClk+
                LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
LnkCtl 后面接着 ASPM Disabled 证明关闭成功
折腾结束
有其他情况请看附录
附录1:卸载 DKMS 驱动
分两种情况
如果是软件包安装
确认包名
root@bb-nanopi-r5c:~# dpkg -l | grep r8125
ii  realtek-r8125-dkms               9.013.02-2                              arm64        Realtek RTL8125 driver in DKMS format
直接卸载这个软件包即可
apt purge realtek-r8125-dkms
重启
如果是手动安装
确认 dkms 模块名和版本
root@xxx:~# dkms status
Deprecated feature: REMAKE_INITRD (/var/lib/dkms/realtek-r8125/9.013.02/source/dkms.conf)
realtek-r8125/9.013.02, 6.1.25, arm64: installed
卸载
dkms remove realtek-r8125/9.013.02
重启
附录2:折腾前后对比
正在使用的驱动
xxx@xxx:~# ethtool -i eth0
driver: r8125
version: 9.010.01-NAPI
firmware-version: 
expansion-rom-version: 
bus-info: 0002:21:00.0
supports-statistics: yes
supports-test: no
supports-eeprom-access: no
supports-register-dump: yes
supports-priv-flags: no
root@bb-nanopi-r5c:~# ethtool -i eth0
driver: r8125
version: 9.013.02-NAPI-RSS
firmware-version: 
expansion-rom-version: 
bus-info: 0002:21:00.0
supports-statistics: yes
supports-test: no
supports-eeprom-access: no
supports-register-dump: yes
supports-priv-flags: no
硬件收发队列
root@bb-nanopi-r5c:~# ethtool -l eth0
netlink error: Operation not supported
root@bb-nanopi-r5c:~# ethtool -l eth0
Channel parameters for eth0:
Pre-set maximums:
RX:		4
TX:		2
Other:		n/a
Combined:	n/a
Current hardware settings:
RX:		2
TX:		2
Other:		n/a
Combined:	n/a
RSS 状态
root@nanopi-r5c:~# ethtool -x eth0
Cannot get RX ring count: Operation not supported
root@nanopi-r5c:~# ethtool -x eth0
RX flow hash indirection table for eth1 with 2 RX ring(s):
    0:      0     1     0     1     0     1     0     1
    8:      0     1     0     1     0     1     0     1
   16:      0     1     0     1     0     1     0     1
   24:      0     1     0     1     0     1     0     1
   32:      0     1     0     1     0     1     0     1
   40:      0     1     0     1     0     1     0     1
   48:      0     1     0     1     0     1     0     1
   56:      0     1     0     1     0     1     0     1
   64:      0     1     0     1     0     1     0     1
   72:      0     1     0     1     0     1     0     1
   80:      0     1     0     1     0     1     0     1
   88:      0     1     0     1     0     1     0     1
   96:      0     1     0     1     0     1     0     1
  104:      0     1     0     1     0     1     0     1
  112:      0     1     0     1     0     1     0     1
  120:      0     1     0     1     0     1     0     1
RSS hash key:
9e:14:c7:77:95:05:00:cf:4a:27:04:a3:2c:94:de:1e:7c:7a:4a:55:0b:28:33:7d:e9:5d:e1:31:9f:db:d0:88:0a:92:1d:83:eb:f3:5c:40
RSS hash function:
    toeplitz: on
    xor: off
    crc32: off
附录3:常见问题
重启后发现驱动加载正常,但没有获取 IP 地址等
openmediavault 在主安装脚本之前,有另外一个脚本是用来固定网卡接口名称为 eth0
虽然那脚本的兼容性存疑,但无论你用什么方法,都应该照着他的思路把网卡接口名固定为 eth0
如果你没有这么做,那么就会遇上驱动更换以后,网卡接口名称改变的情况
这时候,openmediavault 配置文件还是旧的接口名称,就不会自动设置新接口的DHCP
解决方法
使用 omv-firstaid 命令,或者 WEB 控制面板重新配置网络接口
构建时没有安装 dh-dkms
dh: error: unable to load addon dkms: Can't locate Debian/Debhelper/Sequence/dkms.pm in @INC (you may need to install the Debian::Debhelper::Sequence::dkms module)
解决方法
安装 dh-dkms
apt install dh-dkms
安装后还是在使用 r8169 驱动
参考
https://www.cnblogs.com/klzy/p/18266961
linux-headers 没有安装或者不匹配内核
参考 https://blog.im.ci/study-notes/linux-notes/1222
在没有安装 linux-headers 的情况下,dkms 的驱动包依然是可以安装的
这个时候 dkms 驱动不会编译成内核模块
如果已经安装了 dkms 驱动包,但是发现存在 linux-headers 问题的话
在解决了 linux-headers 的问题后,需要重新让 dkms 重新编译并安装一次内核模块
首先获取名称
root@nanopi-r5c:~# dkms status
r8125/9.015.00: added
然后重新安装
root@nanopi-r5c:~# dkms install r8125/9.015.00
The kernel is built without module signing facility, modules won't be signed
Building module(s)................... done.
Installing /lib/modules/6.12.55-current-rockchip64/updates/dkms/r8125.ko
Running depmod.... done.
重新检查驱动安装状态
root@nanopi-r5c:~# lspci | grep RTL8125
0001:01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller (rev 05)
0002:01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller (rev 05)
root@nanopi-r5c:~# lspci -s 0001:01:00.0 -k
0001:01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller (rev 05)
        Subsystem: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller
        Kernel driver in use: r8169
        Kernel modules: r8169, r8125
确认 Kernel modules 里显示了想要的驱动模块后
重启
reboot -n
多队列无法启用
查看网卡 RSS 状态,报错
root@nanopi-r5c:~# ethtool -x eth0
Cannot get RX ring count: Operation not supported
查看中断记数
root@nanopi-r5c:~# grep eth0 /proc/interrupts
103:     198832          0          0          0      INTx   0 Edge      PCIe PME, aerdrv, eth0-0
这里显示 eth0 的网卡跑在 INTx 中断模式下,肯定不对
通过日志查找原因
root@nanopi-r5c:~# dmesg | grep -i msi
[    5.418074] r8125 0002:01:00.0: no MSI/MSI-X. Back to INTx.
啊?最后检查出来只有 PCI 地址 0002:01:00.0 的网卡不行?
未完待续,目前把另一张网卡改成 eth0 在用