☰
银河麒麟V10双网卡驱动编译:e1000e与rtl8125落地排错
2026/11/6 7:55:27 网站建设 项目流程

简介:面向银河麒麟V10环境下需要适配Intel e1000e与Realtek RTL8125网卡的运维人员和驱动开发者,这份源码包提供两款网卡驱动在国产Linux内核上编译通过的可参考版本,重点解决源码重复定义、函数参数不匹配等兼容性问题。压缩包共56个文件、约483KB,以C源文件和头文件为主体,辅以Makefile、README、spec打包描述及脚本等,便于按模块查阅编译入口、内核接口与安装说明。资源已有2750人学习,说明其在国产系统网卡适配场景中具有一定参考价值。读者可从中获得e1000e与RTL8125驱动的完整源码结构、针对银河麒麟V10的改动思路、编译脚本与排错线索,用于对照排查驱动加载、网卡识别和稳定性验证等问题,适合具备一定Linux内核与驱动基础的人员研读。

1. 网口不见了:银河麒麟 V10 上 e1000e 与 rtl8125 的编译起点

一块 e1000e 的千兆网卡、一块 rtl8125 的 2.5G 网卡,插在同一台银河麒麟 V10 的机器上,lspci能把两个设备都列得清清楚楚,ip link里却只剩一个 lo。这种"设备在、网口不在"的场面,我这两年见得比任何报错都多。更让人误判的是,从别处拷来一个编好的.ko,insmod当时能过,重启之后网卡又变回系统自带的老驱动——银河麒麟 V10 的内核小版本在 SP1、SP2、SP3 之间来回变,vermagic 对不上,模块要么加载失败,要么加载了但没接管设备。这套环境适合手里有麒麟 V10 物理机、需要让 e1000e 千兆口和 rtl8125 2.5G 口同时跑起来的运维和适配人员,下面按"环境钉死 → 分别编译 → 排错 → 验证"的顺序走一遍。

2. 环境先钉死:内核小版本、kernel-devel 与 gcc 的对照清单

在银河麒麟 V10 上编网卡驱动,失败的原因有一大半不在驱动源码本身,而在环境没对齐。同一份 e1000e 源码,在 4.19.90-24 上编得出来,换个 4.19.90-11 的机器可能连make都过不去,因为内核头文件里的函数签名和宏定义变了。所以动手之前,先把三件事确认死:运行内核的完整版本号、与它严格对应的 kernel-devel、以及编译器版本。这三样任何一样错位,后面所有步骤都是白费。

2.1 先读内核版本,别急着解压

很多人拿到驱动包第一反应是tar -zxvf,解压完再回头找内核版本,结果 Makefile 里的路径全要返工。我的习惯是先跑三条命令,把版本号抄到记事本上。

# 运行内核的完整版本,注意尾部还有发行版标识 uname -r # 输出类似:4.19.90-24.4.v2101.ky10.x86_64 # 已安装的内核开发包,看是否与 uname -r 完全一致 rpm -qa | grep -E 'kernel-devel|kernel-headers' # 看系统自带网卡模块的 vermagic,作为编译目标的基准 modinfo e1000e | grep vermagic modinfo r8169 | grep vermagic

uname -r的输出不是随便一串字符,4.19.90-24.4.v2101.ky10.x86_64里,4.19.90是上游基线,24.4是发行版打的补丁序号,v2101标识版本分支,x86_64是架构。驱动编译时生成的vermagic字符串会把这些信息全部带上,加载时内核逐字符比对,差一个补丁号就报Invalid module format。modinfo那条命令的作用是拿到"标准答案"——你编出来的模块,vermagic 必须和系统自带模块的完全一样,否则不用往下走。

还有一个容易忽略的点:如果机器上装过多个内核,uname -r是当前运行的,但kernel-devel可能装的是最新的那一个,两者不是同一个。这种情况编译不会立刻报错,而是在make的中间阶段提示找不到某个头文件,或者更隐蔽地编出一个 vermagic 不对的模块,等到modprobe才暴露。

2.2 kernel-devel 与编译工具:装错一个就白干

银河麒麟 V10 用 yum 管包,装开发环境本身不难,难在版本号要精确指定。

# 编译工具链,elfutils-libelf-devel 是内核模块编译时解析符号必需的 sudo yum install -y gcc gcc-c++ make elfutils-libelf-devel # 关键:带 $(uname -r) 精确安装,不要装成最新版 sudo yum install -y kernel-devel-$(uname -r) kernel-headers-$(uname -r) # 验证 build 软链接是否指向正确目录 ls -l /lib/modules/$(uname -r)/build # 期望指向 /usr/src/kernels/4.19.90-24.4.v2101.ky10.x86_64

这里每个包的用途要分清:gcc和make是编译主体;elfutils-libelf-devel提供libelf,内核构建系统在生成模块的.mod信息时要用,缺了它会在modpost阶段报ERROR: modpost: "..." [..] Error 1,报错信息完全看不出是缺包;kernel-devel提供/lib/modules/$(uname -r)/build指向的完整内核头文件和构建脚本;kernel-headers提供用户态可见的头文件。kernel-devel不装或者装错版本,是所有失败里最常见的一种,占我处理过的案例一半以上。

编译器版本也要看一眼:

gcc --version # 银河麒麟 V10 一般是 7.3.x 或 8.3.x

7.x 和 8.x 对老驱动源码的宽容度不同。8.x 默认把更多警告升级为错误,很多厂商在 2018 年前后发布的 e1000e 独立包,在 8.3 下会冒出一堆-Werror=相关的失败。这不是代码有 bug,是编译器的默认策略变了,处理办法在 3.1 节里说。

2.3 源码包与内核版本的对应关系

两个驱动的源码来源和目录结构完全不同,混着用会出问题。

驱动常见包形态解压后结构生成模块依赖
e1000ee1000e-3.8.x.tar.gz顶层 Makefile +src/src/e1000e.kokernel-devel、gcc
rtl8125r8125-9.00x.tar.bz2顶层 Makefile +src/src/r8125.kokernel-devel、gcc

包名里的版本号各家给的都不一样,不要照着网上的文章硬套。判断实际版本的可靠办法是解压后看顶层 Makefile 里的EXTRAVERSION变量,或者看src/下主文件的头部注释。这两个包都是"独立构建"模式:顶层 Makefile 只负责算出内核路径,真正的编译由内核构建系统在src/目录里完成,所以src/不能单独拿出来编译。

提示:如果手上只有内核源码树,drivers/net/ethernet/intel/e1000e/下面那份源码不建议单独抠出来编译,它依赖内核树里的很多公共头文件,脱离源码树基本编不过。老老实实用厂商发布的独立 tar 包。

3. 编译 e1000e:从解压改 Makefile 到 modprobe 生效

e1000e 相对简单,代码成熟、依赖少,只要环境对,一般一次就能过。真正费时间的是"编出来了但没生效"这一段——模块装到了错误目录、被系统自带的那份抢先加载、initramfs 里还留着旧副本。这一章把编译和落地分成两段讲,前半段保证出.ko,后半段保证这个.ko真的在跑。

3.1 解压后先改哪几行

tar -zxvf e1000e-3.8.x.tar.gz cd e1000e-3.8.x ls # 一般能看到 Makefile、README、COPYING、src/

进去之后先别急着make,打开顶层 Makefile 看两处。第一处是编译选项里的-Werror,第二处是EXTRAVERSION。

# 修改前,某些版本里是这两种写法之一 CFLAGS += -Werror ccflags-y += -Werror # 修改后:降级为警告,避免高版本 gcc 的严格检查直接中断编译 CFLAGS += -Wno-error ccflags-y += -Wno-error

-Werror的意思是"把警告当错误",只要有任何一个 warning 就终止。内核 4.19 的 API 和这个驱动包发布时的内核 API 之间可能存在细微差异,比如某些函数参数加了__maybe_unused,gcc 8.3 会报警告,加上-Werror就直接 fail。改成-Wno-error之后,同样的警告只会打印出来,不影响生成.ko。这个改动不改变任何运行时逻辑,纯粹是让编译过程能走完。

EXTRAVERSION一般不需要动。它的作用是给模块版本号加后缀,影响的是modinfo里显示的version,不影响 vermagic。只有在同名的两个版本驱动共存、需要区分时才有意义。

需要改 Makefile 里的另一个地方是内核路径,但通常不用手改,Makefile 会自动取/lib/modules/$(shell uname -r)/build。如果要给别的内核编译,用环境变量覆盖:

# 显式指定内核构建目录,交叉或离线场景用 make KSRC=/usr/src/kernels/4.19.90-24.4.v2101.ky10.x86_64

KSRC是这类厂商包里通用的变量名,少数包用KERNELDIR。传错变量名不会有任何提示,Makefile 会安静地用默认路径,编出来的东西可能不是你要的。判断办法是看make输出的第一行,通常会打印make -C <路径> M=<源码路径> modules,路径对不对一眼就能看出来。

3.2 make 与 make install 到底做了什么

# 编译,成功后在 src/ 下生成 e1000e.ko make # 确认产物存在并看基本信息 ls -lh src/e1000e.ko modinfo src/e1000e.ko | head -8 # 安装(把 ko 复制到模块目录并执行 depmod) sudo make install

modinfo这一步很关键,编完先自检一遍:vermagic是不是和 2.1 节里记下来的标准答案一致,filename是不是指向src/e1000e.ko,version是不是你预期的那个。三个都对,再谈安装。

make install在不同版本的包里行为不一样,有的装到/lib/modules/$(uname -r)/kernel/drivers/net/ethernet/intel/e1000e/,有的装到/lib/modules/$(uname -r)/updates/...,还有的只复制文件不跑depmod。我一般不用它,改成手动装,路径可控、回滚也方便:

# 手动安装到 updates 目录,这个目录在 depmod 搜索顺序里优先于 kernel/ sudo install -D -m 644 src/e1000e.ko \ /lib/modules/$(uname -r)/updates/drivers/net/ethernet/intel/e1000e/e1000e.ko # 重建模块依赖关系 sudo depmod -a # 确认 depmod 认到了新模块 modinfo -n e1000e # 期望输出 .../updates/drivers/net/ethernet/intel/e1000e/e1000e.ko

为什么非要放updates/?因为depmod查找同名模块时按目录优先级排序,默认顺序是updates→extra→built-in→kernel,这个顺序定义在/etc/depmod.d/下的配置里。放在updates/意味着不动系统自带的那个.ko文件,将来要回退,直接删掉updates/下的文件再depmod -a就恢复原状。装到kernel/目录下会覆盖原文件,系统升级时还可能被包管理器重新盖回去,属于给自己埋雷。

3.3 让新模块顶掉系统自带的那一份

文件放对位置只是第一步,内核里可能已经加载了旧模块,得先卸再装。

# 1. 卸载当前加载的 e1000e(网口会短暂断开,远程操作要小心) sudo modprobe -r e1000e # 2. 重新加载,此时 modprobe 会按 depmod 的顺序选中 updates 下的新模块 sudo modprobe e1000e # 3. 确认加载的到底是哪一份 lsmod | grep e1000e modinfo -n e1000e ethtool -i eth0 | grep -E 'driver|version|firmware'

ethtool -i的输出是最终判据:driver: e1000e,version:后面应该是你刚编的那个版本号。如果版本号没变,说明加载的还是旧的,回到modinfo -n看路径,十有八九是updates目录的层级写错了,或者depmod没跑成功。

远程操作时卸载网卡驱动会直接断连,这一点必须有预案。我一般要求现场有人,或者提前配好带外管理,再不然就用一个定时任务兜底:

# 兜底:5 分钟后无论如何重新加载一次驱动,防止远程操作把自己踢下线 echo 'sleep 300; modprobe e1000e' | at now

最后一步是处理 initramfs。如果根文件系统不在本地盘上,或者希望系统启动早期就能用这张网卡,必须把新模块打进 initramfs,否则启动时加载的还是里面那份旧的。

# 备份现有 initramfs,血泪经验,别省这一步 sudo cp /boot/initramfs-$(uname -r).img /boot/initramfs-$(uname -r).img.bak # 重建 sudo dracut -f /boot/initramfs-$(uname -r).img $(uname -r)

dracut -f的-f是强制覆盖,不加会提示文件已存在。第二个参数指定内核版本,不写的话默认用当前运行内核,问题不大但显式写更稳。重建完可以用lsinitrd /boot/initramfs-$(uname -r).img | grep e1000e检查新模块有没有被打进去。

4. 编译 rtl8125:绕开 r8169 抢占与 2.5G 协商

rtl8125 的编译过程比 e1000e 顺,但落地环节坑更多,核心矛盾在于内核自带的r8169驱动。较新的 4.19 内核里,r8169已经加进了对 2.5G 芯片的识别,设备一上电就被它 probe 走了,你编的r8125根本没机会接管。表现是驱动装好了、lsmod里也有r8125,但网口用的还是r8169,速率卡在 1G 甚至协商不上。这一章的重点不在编译,在抢设备。

4.1 解压与 Makefile 里的路径修正

tar -jxvf r8125-9.00x.tar.bz2 cd r8125-9.00x ls # 一般能看到 Makefile、README、src/、dkms-install.sh

注意.tar.bz2用-j不是-z,这是个小细节但经常有人敲错,报bzip2: (stdin) is not a bzip2 file。

顶层 Makefile 里要确认的是BASEDIR:

# 内核构建目录,正常情况下这一行不用改 BASEDIR := /lib/modules/$(shell uname -r)/build # 编译目标目录 KERNELDIR := $(BASEDIR)

如果make一上来就报*** /lib/modules/4.19.90-xx/build: No such file or directory. Stop.,说明BASEDIR指向的软链接不存在,回到 2.2 节检查kernel-devel装没装对。这个报错信息很直白,但很多人第一反应是去改 Makefile 里的路径,改成手工拼的/usr/src/kernels/...,结果因为缺少Module.symvers而编出无法加载的模块。正确做法永远是补装kernel-devel,不要改路径。

编译命令和 e1000e 基本一致:

make # 生成 src/r8125.ko modinfo src/r8125.ko | grep -E 'version|vermagic'

如果报一堆implicit declaration of function,说明驱动源码和当前内核版本差得比较远,某个内核 API 改了签名。这种情况在麒麟 V10 的 SP 版本之间偶有出现。能改的改,改不动的找厂商要适配该内核小版本的新包,硬改容易改出运行时崩溃。

安装同样走手动路径:

sudo install -D -m 644 src/r8125.ko \ /lib/modules/$(uname -r)/updates/drivers/net/ethernet/realtek/r8125/r8125.ko sudo depmod -a modinfo -n r8125

4.2 黑名单 r8169 与模块冲突处理

这一步是 rtl8125 落地成败的关键。做法是让r8169不要自动加载,把设备让给r8125。

# 新建黑名单配置 sudo tee /etc/modprobe.d/blacklist-r8169.conf > /dev/null <<'EOF' # 禁止内核自带 r8169 自动加载,避免抢占 rtl8125 设备 blacklist r8169 # 更彻底:任何加载 r8169 的请求都直接返回成功但不做事 install r8169 /bin/true EOF

两行的作用不同。blacklist只是让udev在自动探测设备时跳过这个模块,手动modprobe r8169还是能加载;install r8169 /bin/true是把加载动作整个替换成/bin/true,任何途径的加载请求都变成空操作,更彻底。两个一起写,双保险。

配置写完后要重建 initramfs,否则早期启动阶段还是会把r8169拉起来:

sudo cp /boot/initramfs-$(uname -r).img /boot/initramfs-$(uname -r).img.bak sudo dracut -f /boot/initramfs-$(uname -r).img $(uname -r) # 卸载已加载的 r8169,加载 r8125 sudo modprobe -r r8169 sudo modprobe r8125 # 确认设备归属 lspci -k | grep -A 3 -i ethernet # 期望看到 Kernel driver in use: r8125 ethtool -i eth0 # driver: r8125

如果modprobe -r r8169报Module r8169 is in use,说明网口正在被使用。先ip link set eth0 down,再卸。还是不行就说明有 NetworkManager 或者别的服务抓着不放,临时停掉再操作。

还有一种情况:r8125加载了,lspci -k里显示的却是Kernel driver in use: r8169。这说明r8169在r8125之前就已经 probe 了设备,时序问题。解决办法是确保黑名单在 initramfs 重建之前就写好,让r8169从头到尾没机会加载。

4.3 安装后确认 2.5G 链路真的协商上了

驱动接管了不代表链路正常。rtl8125 的 2.5G 协商依赖对端设备、网线规格和 EEE 设置,任何一环不对都会掉到 1G 甚至 100M。

# 看链路状态和协商速率 ethtool eth0 | grep -E 'Speed|Duplex|Link detected' # 期望:Speed: 2500Mb/s Duplex: Full Link detected: yes # 看支持的速率模式 ethtool eth0 | grep -A 2 'Supported link modes' # 关闭 EEE,部分交换机对 EEE 支持不好会导致链路反复 up/down sudo ethtool --set-eee eth0 eee off

Speed: Unknown!一般意味着协商失败,先换一根超五类以上的网线,再确认对端端口是不是 2.5G。只协商到 1000Mb/s 的话,多半是对端只支持千兆,或者网线是超五类以下。Link detected: no就是物理层没通,跟驱动无关了。

EEE 这个参数值得单独说。它本来是省电特性,但在一些老旧交换机上会导致链路抖动,表现为dmesg里反复出现r8125: link up/link down。关掉之后稳定很多。要持久化的话,把options r8125 eee=0写进/etc/modprobe.d/r8125.conf。

另外 r8125 有个aspm参数控制 PCIe 的活动状态电源管理,某些主板上开启 ASPM 会导致丢包或者设备消失,遇到这类玄学问题可以试试options r8125 aspm=0。

5. 排查清单:编译通过但网卡起不来的五种现场

编译成功只是及格线,能不能跑起来是另一回事。下面这五种情况是我在麒麟 V10 上反复遇到的,按出现频率排。

5.1 报错找不到 build 目录

现象:make第一行就失败,提示/lib/modules/4.19.90-xx.x/build: No such file or directory. Stop.

原因:kernel-devel没装,或者装的版本和uname -r不一致。麒麟 V10 的镜像里默认不带开发包,很多人yum install kernel-devel不带版本号,装上了最新的,和运行内核差一个补丁号,软链接就断在那里。

解决:rpm -qa | grep kernel-devel看装的是哪个版本,对不上就yum remove掉重装kernel-devel-$(uname -r)。装完ls -l /lib/modules/$(uname -r)/build必须能看到指向/usr/src/kernels/<完整版本号>的软链接。离线环境的话,从安装镜像的Packages/目录里找对应版本的 rpm 手动装。

5.2 模块加载报 Invalid module format

现象:insmod或modprobe报ERROR: could not insert module e1000e.ko: Invalid module format,dmesg里跟着一行e1000e: version magic '4.19.90-11 ...' should be '4.19.90-24 ...'。

原因:模块的 vermagic 和当前内核不匹配。两种可能,一是模块在别的机器上编的,二是本机内核升级过但驱动没重编。vermagic 里含有内核版本、SMP 状态、抢占模式、模块卸载支持等标志位,任何一项不同都会拒绝加载。

解决:在目标机器上重新编译,不要跨机器拷.ko。如果确实需要一份模块给多台机器用,那这些机器的内核小版本必须完全一致。用modinfo xxx.ko | grep vermagic和目标机uname -r对比,能立刻定位差异。

5.3 重启后驱动又变回旧的

现象:手动modprobe之后ethtool -i显示新版本,重启一遍又变回旧版本号。

原因:updates/目录下的模块没被打进 initramfs,启动早期用的是 initramfs 里的旧副本;或者模块装到了kernel/目录,被包管理器的更新覆盖回去了。

解决:先确认模块位置,modinfo -n e1000e应该指向updates/而不是kernel/。然后dracut -f重建 initramfs,重建完用lsinitrd /boot/initramfs-$(uname -r).img | grep e1000e确认新模块在里面。这一步不做,前面全白干,我吃过这个亏之后每次都强制走一遍。

5.4 安全启动下模块加载被拒绝

现象:modprobe报ERROR: could not insert module: Required key not available,dmesg里有Loading of unsigned module is rejected。

原因:机器开了安全启动,内核只加载有合法签名的模块。自己编的.ko没有签名,直接被拒。

解决:两条路。一是进固件设置把安全启动关掉,最省事;二是给模块签名,用内核源码树里的scripts/sign-file,需要一对密钥:

# 生成自签名密钥(只做一次) openssl req -new -x509 -newkey rsa:2048 -keyout MOK.key -out MOK.crt \ -nodes -days 3650 -subj "/CN=Local Module Signing/" # 给模块签名 sudo /usr/src/kernels/$(uname -r)/scripts/sign-file sha256 \ MOK.key MOK.crt \ /lib/modules/$(uname -r)/updates/drivers/net/ethernet/intel/e1000e/e1000e.ko

签名之后还要把公钥导入固件的 MOK 列表,mokutil --import MOK.crt,重启时在蓝色界面里确认。流程比较长,机器数量少的话关安全启动更实际。

5.5 网口出现了但拿不到地址

现象:ip link能看到 eth0,状态是DOWN或者UP但没有 IP,nmcli device status显示unmanaged。

原因:换了驱动之后网口的 MAC 地址或者设备名变了,NetworkManager 里还留着旧的连接配置,按 MAC 匹配不上就跳过管理;或者配置文件里写死了旧设备名。

解决:先ip link set eth0 up看能不能起来,然后nmcli device status确认管理状态。如果是unmanaged,检查/etc/NetworkManager/NetworkManager.conf里有没有把这个接口排除掉,以及/etc/udev/rules.d/下有没有旧的网卡命名规则。最干脆的办法是删掉旧连接重建:nmcli connection delete <名字>,再nmcli connection add type ethernet ifname eth0。

6. 装完怎么验证:三组命令确认驱动真的在跑

驱动装完,lsmod里有、ip link里有,不代表它在正常工作。我习惯用三组命令交叉验证,从"内核认了"到"链路通了"到"数据真的在走",任何一层不对都能立刻定位到是哪一环。

第一组看设备归属和驱动版本。lspci -k列出每个 PCI 设备当前绑定的内核驱动,ethtool -i给出驱动名、版本、固件版本和总线地址。两个命令的结果必须一致,如果lspci -k显示r8169而ethtool -i显示r8125,说明有多个网口,你查的不是同一个。

lspci -k | grep -A 3 -i 'ethernet' ethtool -i eth0

第二组看加载的到底是哪一份文件。lsmod只能告诉你模块加载了,modinfo -n才能告诉你从哪个路径加载的。

lsmod | grep -E 'e1000e|r8125|r8169' modinfo -n e1000e modinfo -n r8125

第三条命令是实际跑流量,这是唯一能证明驱动真的在工作的证据。ethtool -S的收发包计数在ping前后应该有增长,如果没有增长,说明包压根没进出网卡。

# 记录初始计数 ethtool -S eth0 | grep -E 'tx_packets|rx_packets' # 打一轮流量,-c 指定次数,-s 指定包大小 ping -c 100 -s 1400 -i 0.01 <对端地址> # 再看计数,两个数字都应该明显增长 ethtool -S eth0 | grep -E 'tx_packets|rx_packets'

把三组结果整理成一张检查表,对照着看最直观:

检查项命令合格标准
驱动绑定lspci -kKernel driver in use是 e1000e 或 r8125
驱动版本ethtool -i eth0version 与编译产物一致
模块路径modinfo -n e1000e指向updates/目录
链路状态ethtool eth0Link detected: yes,速率符合预期
收发计数ethtool -S eth0ping 前后计数增长
启动持久性重启后重跑以上五项全部保持不变

最后一项最容易被跳过,但恰恰最重要。所有验证做完,重启一次,把上面五项完整重跑。只有重启后依然全部通过,才算真正装好了。我见过太多次当场验证全绿、重启回到解放前的案例,问题无一例外都出在 initramfs 没重建或者模块装错目录。

从那以后我每次给麒麟 V10 装网卡驱动,都会在最后强制走一遍"重启 →lspci -k→ethtool -i→ethtool -S打流量"这套动作,不管前面多顺利都不省略。网卡驱动这东西,当场跑通和长期稳定是两回事,多花五分钟验证,能省掉后面半夜被叫起来排查的时间。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询