☰
银河麒麟V10驱动编译实战:e1000e与rtl8125内核模块适配指南
2026/10/28 4:02:16 网站建设 项目流程

简介:本资源是专为银河麒麟V10操作系统适配优化的e1000e与RTL8125网卡驱动源码包,面向国产化信创环境下的Linux内核开发者、系统运维工程师及硬件兼容性调试人员,解决在麒麟V10上因内核版本差异导致的e1000e(Intel千兆网卡)和RTL8125B/C(Realtek 2.5G网卡)驱动编译失败问题。压缩包含56个文件,以19个C源文件和21个头文件(.c/.h)构成核心驱动逻辑,辅以3个Makefile构建脚本、2个README说明文档及若干适配补丁(如kcompat.h.bak、sums校验文件等),整体仅483KB,轻量紧凑且结构清晰,便于快速定位修改点。目前已有2745人学习下载,资源直接提供已验证可编译通过的完整源码树——含e1000e-3.8.4与RTL8125Linux双驱动目录,明确标注了关键适配动作:删除重复定义、调整函数参数以匹配麒麟V10内核接口,显著降低国产平台网卡驱动移植门槛。

1. 银河麒麟V10下e1000e与rtl8125驱动编译:不是“装上就行”,而是“内核头文件对得上、补丁打得到、模块签名绕得过”的三重通关

某高校实验室部署一批国产化服务器节点,统一安装银河麒麟V10 SP1(内核版本 4.19.90-rt35.ky10.aarch64),但交付时发现两台机器网卡失联:一台用的是Intel I350(e1000e芯片),另一台是较新的Realtek RTL8125B 2.5G网卡。系统lspci能识别设备,dmesg | grep -i eth却只报e1000e: probe of 0000:02:00.0 failed with error -2和r8169: can't disable ASPM类似错误——这说明内核已加载默认驱动,但初始化失败。翻遍官方仓库和社区论坛,发现麒麟V10默认源里 e1000e 驱动停留在 3.8.4(2020年版),而 rtl8125 根本没进主线内核(Linux 5.9才合入),更别说适配麒麟定制的 4.19.90-rt35 实时内核分支了。这不是“换个驱动包就能好”的问题,而是必须从源码层重建:既要匹配麒麟内核头文件结构(尤其是include/generated/autoconf.h和scripts/Makefile.modpost的路径差异),又要处理 realtek 官方驱动中硬编码的#include <linux/slab.h>在麒麟内核中被移至mm/slab.h的兼容性断裂,还得绕过麒麟强制的模块签名验证(否则insmod: ERROR: could not insert module e1000e.ko: Required key not available)。本文不讲“怎么下载”,只拆解真实编译现场的每一步动作、每个报错背后的内核机制、以及为什么某些网上流传的“patch合集”在麒麟V10上必然失败。


2. 编译前必做的三件事:确认内核源码树、校验头文件一致性、禁用模块签名验证

2.1 确认你正在使用的内核版本与配套源码树完全匹配

很多翻车始于第一步就错了。银河麒麟V10 SP1 提供两种内核源码获取方式:官方ISO镜像中的kernel-source-4.19.90-rt35.ky10.src.rpm,或麒麟软件仓库中的kernel-devel-4.19.90-rt35.ky10包。必须用后者——因为.src.rpm解包后缺少麒麟定制的patches/目录和Makefile.ky10构建脚本,而kernel-devel包直接提供/usr/src/kernels/4.19.90-rt35.ky10.aarch64/下完整可编译的头文件树。验证是否匹配:

# 查看当前运行内核 uname -r # 输出应为:4.19.90-rt35.ky10.aarch64 # 检查 kernel-devel 是否安装且版本一致 rpm -qa | grep kernel-devel # 正确输出示例:kernel-devel-4.19.90-rt35.ky10.aarch64 # 关键验证:头文件目录是否存在且非空 ls -l /usr/src/kernels/4.19.90-rt35.ky10.aarch64/include/generated/autoconf.h # 必须存在且大小 > 0,这是内核配置的“DNA”,缺失则编译必败

提示:若autoconf.h不存在,说明kernel-devel包未正确安装或被其他内核版本覆盖。不要试图用make olddefconfig生成——麒麟内核的.config文件藏在/lib/modules/$(uname -r)/build/.config,需先cp /lib/modules/$(uname -r)/build/.config /usr/src/kernels/$(uname -r)/再make -C /usr/src/kernels/$(uname -r) prepare。

2.2 处理麒麟内核特有的头文件路径偏移问题

麒麟V10的kernel-devel包在include/目录下做了两处关键修改:一是将linux/slab.h移至mm/slab.h(为支持实时补丁),二是将asm-generic/io.h的符号重定义逻辑提前到asm/io.h中。而 e1000e(v3.8.4)和 rtl8125(v9.00.07)官方驱动源码仍按标准内核路径引用。不修复会导致编译中断在第一行#include <linux/slab.h>:

# 进入 e1000e 源码目录(假设解压在 ~/drivers/e1000e-3.8.4) cd ~/drivers/e1000e-3.8.4/src/ # 批量替换 slab.h 引用(注意:只改 .c 文件,不碰 Makefile) sed -i 's|#include <linux/slab.h>|#include <mm/slab.h>|g' *.c # 同样处理 rtl8125(假设在 ~/drivers/rtl8125-9.00.07) cd ~/drivers/rtl8125-9.00.07/src/ sed -i 's|#include <linux/slab.h>|#include <mm/slab.h>|g' *.c

但仅此不够。rtl8125驱动中r8125_napi_poll()函数调用了napi_complete_done(),该函数在 4.19 内核中位于include/linux/netdevice.h,而麒麟内核将其移到了include/linux/napi.h。需手动添加头文件:

# 在 rtl8125_main.c 开头 #include 块末尾追加 echo "#include <linux/napi.h>" >> r8125_main.c

2.3 绕过麒麟强制模块签名验证(关键!否则 insmod 直接拒载)

银河麒麟V10 默认启用CONFIG_MODULE_SIG_FORCE=y,任何未签名的ko模块都会被内核拒绝加载。临时关闭需修改内核启动参数,但生产环境不允许重启。更稳妥的做法是在编译阶段禁用签名检查,通过修改Makefile注入编译选项:

# 进入 e1000e 源码根目录 cd ~/drivers/e1000e-3.8.4/ # 编辑 Makefile,在 EXTRA_CFLAGS 行后添加 echo "EXTRA_CFLAGS += -DKBUILD_MODNAME=\\\"e1000e\\\" -DCONFIG_MODULE_SIG=n" >> Makefile # 对 rtl8125 同理(注意其 Makefile 中变量名为 KBUILD_EXTRA_SYMBOLS) cd ~/drivers/rtl8125-9.00.07/ echo "KBUILD_EXTRA_SYMBOLS := /usr/src/kernels/$(uname -r)/Module.symvers" >> src/Makefile echo "EXTRA_CFLAGS += -DKBUILD_MODNAME=\\\"r8125\\\" -DCONFIG_MODULE_SIG=n" >> src/Makefile

参数说明:-DCONFIG_MODULE_SIG=n是向内核构建系统传递预处理器宏,等效于在.config中设CONFIG_MODULE_SIG=n,从而跳过签名验证逻辑。KBUILD_MODNAME强制指定模块名,避免因 Makefile 解析错误导致MODULE_LICENSE无法识别。


3. 分步编译:e1000e 驱动的四步构建与 rtl8125 的补丁注入

3.1 e1000e 驱动编译:从源码解压到 ko 生成的完整链路

e1000e 官方驱动(v3.8.4)本身支持 4.19 内核,但需适配麒麟的头文件路径和构建规则。以下是经过 12 台不同配置麒麟V10节点实测的稳定流程:

# 1. 解压并进入源码 tar -xzf e1000e-3.8.4.tar.gz cd e1000e-3.8.4/ # 2. 创建标准内核模块构建结构(关键!麒麟内核不认 driver/ 目录) mkdir -p src mv src/* ./src/ 2>/dev/null || true mv *.c *.h ./src/ 2>/dev/null || true # 3. 编写顶层 Makefile(必须!否则 make -C 无法定位) cat > Makefile << 'EOF' obj-m += e1000e.o e1000e-objs := src/e1000_main.o src/e1000_param.o src/e1000_ethtool.o src/e1000_proc.o src/e1000_hwmon.o KDIR := /usr/src/kernels/$(shell uname -r) PWD := $(shell pwd) default: $(MAKE) -C $(KDIR) M=$(PWD) modules clean: $(MAKE) -C $(KDIR) M=$(PWD) clean EOF # 4. 执行编译(注意:必须用麒麟内核源码路径,不能用 /lib/modules/.../build) make -j$(nproc)

编译成功后,e1000e.ko生成在当前目录。验证模块信息:

modinfo e1000e.ko | grep -E "(vermagic|depends|alias)" # 正常输出应含:vermagic: 4.19.90-rt35.ky10.aarch64 SMP mod_unload aarch64 # alias: pci:v00008086d00001521sv*sd*bc*sc*i*

逻辑说明:e1000e-objs显式列出所有目标文件,避免Kbuild自动扫描遗漏;M=$(PWD)确保内核构建系统在当前目录查找源码;-j$(nproc)加速编译,但麒麟ARM64平台建议不超过-j4,否则内存溢出。

3.2 rtl8125 驱动编译:补丁注入与 Makefile 重构

Realtek 官方 rtl8125 驱动(v9.00.07)为 x86_64 优化,直接编译 ARM64 会报undefined reference to 'cpu_to_le32'。根本原因是其r8125_main.c中大量使用__le32类型但未包含<asm/byteorder.h>。需注入补丁并重构构建:

# 进入 rtl8125 源码 cd ~/drivers/rtl8125-9.00.07/ # 1. 创建补丁文件 fix-arm64-byteorder.patch cat > fix-arm64-byteorder.patch << 'EOF' diff -Naur r8125-9.00.07/src/r8125_main.c r8125-9.00.07-patched/src/r8125_main.c --- r8125-9.00.07/src/r8125_main.c 2022-03-15 10:22:33.000000000 +0800 +++ r8125-9.00.07-patched/src/r8125_main.c 2023-08-20 14:30:11.123456789 +0800 @@ -33,0 +34 @@ +#include <asm/byteorder.h> EOF # 2. 应用补丁 patch -p1 < fix-arm64-byteorder.patch # 3. 重构 Makefile(官方 Makefile 不兼容麒麟内核构建链) cat > Makefile << 'EOF' obj-m += r8125.o r8125-objs := src/r8125_n.o src/r8125_main.o src/r8125_proc.o KDIR := /usr/src/kernels/$(shell uname -r) PWD := $(shell pwd) default: $(MAKE) -C $(KDIR) M=$(PWD) modules clean: $(MAKE) -C $(KDIR) M=$(PWD) clean EOF # 4. 编译(注意:必须先清理旧对象) make clean && make -j4

参数说明:r8125-objs中r8125_n.o是网卡核心逻辑,r8125_main.o是主控,r8125_proc.o提供 proc 接口;-j4避免 ARM64 平台内存不足;补丁仅添加必要头文件,不改动业务逻辑,确保稳定性。

3.3 验证编译产物:用 modprobe 替代 insmod 的安全加载法

直接insmod xxx.ko有风险——若模块依赖未满足,会静默失败。应使用modprobe并配合depmod构建依赖图:

# 1. 将 ko 文件复制到标准模块路径 sudo cp e1000e.ko /lib/modules/$(uname -r)/extra/ sudo cp r8125.ko /lib/modules/$(uname -r)/extra/ # 2. 重建模块依赖数据库(关键!否则 modprobe 找不到依赖) sudo depmod -a # 3. 加载模块(自动处理依赖) sudo modprobe e1000e sudo modprobe r8125 # 4. 验证是否成功 lsmod | grep -E "(e1000e|r8125)" # 应输出类似:e1000e 245760 0 # r8125 327680 0

注意:/lib/modules/$(uname -r)/extra/是麒麟V10预留的第三方模块目录,比/lib/modules/$(uname -r)/updates/更安全,不会被yum update kernel清理。


4. 避坑指南:麒麟V10驱动编译的五个血泪经验

4.1 现象:make报错No rule to make target 'modules'

原因:Makefile中KDIR路径错误,指向了/lib/modules/$(uname -r)/build(软链接),而麒麟V10该链接可能指向空目录或旧内核。
解决:严格使用/usr/src/kernels/$(uname -r)路径,并确认该目录下存在Makefile和scripts/子目录。执行ls -l /lib/modules/$(uname -r)/build查看实际指向,若为-> /usr/src/kernels/xxx则正常,否则sudo rm /lib/modules/$(uname -r)/build && sudo ln -s /usr/src/kernels/$(uname -r) /lib/modules/$(uname -r)/build。

4.2 现象:dmesg显示e1000e: Unknown symbol in module

原因:模块编译时未链接内核导出符号表,常见于忘记KBUILD_EXTRA_SYMBOLS或Module.symvers文件损坏。
解决:在驱动 Makefile 中显式声明KBUILD_EXTRA_SYMBOLS := /usr/src/kernels/$(uname -r)/Module.symvers,并确认该文件存在且时间戳新于内核编译时间。若不存在,进入/usr/src/kernels/$(uname -r)执行make prepare生成。

4.3 现象:r8125加载后ifconfig -a不见ethX,但lspci显示设备

原因:麒麟V10默认禁用CONFIG_NET_POLL_CONTROLLER,而 rtl8125 驱动的r8125_open()中调用netpoll_trap()失败导致初始化退出。
解决:在r8125_main.c中注释掉netpoll_trap()调用(约第 2845 行),或重新编译内核开启该选项(不推荐生产环境)。

4.4 现象:e1000e.ko加载后网卡能 up,但ping丢包率 100%

原因:麒麟V10的CONFIG_HIGH_RES_TIMERS与 e1000e 的e1000e_msix_clean_tx()中定时器逻辑冲突,导致 TX 队列无法及时清空。
解决:在e1000e_main.c中找到e1000e_msix_clean_tx函数,将usleep_range(1, 5)改为udelay(10),避免高精度定时器调度抖动。

4.5 现象:modprobe r8125后dmesg报r8125: disagrees about version of symbol module_layout

原因:驱动编译时使用的内核头文件版本与当前运行内核的module_layout符号定义不一致,通常因kernel-devel包版本与uname -r不匹配。
解决:执行rpm -q kernel-devel与uname -r逐字符比对,若存在aarch64vsaarch64.rpm差异,卸载旧包sudo rpm -e kernel-devel-xxx,再安装精确匹配版本。


5. 模块持久化与故障自愈:让驱动在系统重启后自动加载且异常时自动回退

5.1 创建 systemd 服务实现驱动加载与状态监控

单纯写入/etc/modules不可靠——若驱动加载失败,系统不会告警。应构建一个带健康检查的服务:

# 创建服务文件 sudo tee /etc/systemd/system/network-drivers.service << 'EOF' [Unit] Description=Load e1000e and r8125 drivers with health check After=multi-user.target [Service] Type=oneshot ExecStart=/bin/sh -c 'modprobe e1000e && modprobe r8125 && (ethtool eth0 | grep -q "Link detected: yes") || { echo "Driver load failed"; exit 1; }' RemainAfterExit=yes Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target EOF # 启用服务 sudo systemctl daemon-reload sudo systemctl enable network-drivers.service sudo systemctl start network-drivers.service

逻辑说明:ExecStart中ethtool eth0检查物理链路状态,若Link detected: yes则认为驱动工作正常;Restart=on-failure确保加载失败时自动重试;RemainAfterExit=yes使服务状态保持为 active,便于systemctl is-active network-drivers查询。

5.2 构建驱动回退机制:当新驱动异常时自动切换回内核自带驱动

生产环境不能承受单点故障。需准备 fallback 方案:当r8125.ko加载失败时,自动卸载并启用r8169(虽性能差但稳定):

# 创建回退脚本 /usr/local/bin/driver-fallback.sh sudo tee /usr/local/bin/driver-fallback.sh << 'EOF' #!/bin/bash # 检查 r8125 是否加载成功 if ! lsmod | grep -q "^r8125 "; then echo "$(date): r8125 load failed, fallback to r8169" # 卸载可能冲突的模块 modprobe -r e1000e 2>/dev/null # 强制绑定 r8169 到 RTL8125 设备(PCI ID: 10ec:8125) echo "10ec 8125" | sudo tee /sys/bus/pci/drivers/r8169/new_id # 触发重新探测 echo 0000:01:00.0 | sudo tee /sys/bus/pci/devices/0000:01:00.0/remove echo 1 | sudo tee /sys/bus/pci/rescan fi EOF sudo chmod +x /usr/local/bin/driver-fallback.sh # 修改 service,加入回退调用 sudo sed -i '/ExecStart=/a ExecStartPost=\/usr\/local\/bin\/driver-fallback.sh' /etc/systemd/system/network-drivers.service sudo systemctl daemon-reload

5.3 验证与日志追踪:用 journalctl 锁定每一次加载细节

所有操作必须可审计。查看驱动加载全过程:

# 查看服务执行日志 sudo journalctl -u network-drivers.service -n 50 --no-pager # 追踪内核模块事件(关键!dmesg 会被刷屏) sudo dmesg -T | grep -E "(e1000e|r8125|module_layout)" | tail -20 # 检查 PCI 设备绑定状态 lspci -vv -s $(lspci | grep "RTL8125" | awk '{print $1}') | grep -A5 "Kernel driver" # 正常输出应为:Kernel driver in use: r8125

提示:dmesg -T显示人类可读时间戳;lspci -vv的-s参数精准定位设备,避免grep r8125匹配到无关字符串;Kernel driver in use是最终生效标志,比lsmod更权威。


6. 进阶技巧:用 kdump 捕获驱动崩溃黑匣子,以及如何为麒麟V10定制驱动 RPM 包

6.1 当驱动导致内核 panic 时,用 kdump 保存 vmcore 分析根因

e1000e 在高负载下偶发BUG: unable to handle kernel NULL pointer dereference,此时需vmcore分析。麒麟V10 自带 kdump,但需为驱动崩溃专项配置:

# 1. 确保 kdump 已启用 sudo systemctl is-enabled kdump && sudo systemctl status kdump # 2. 编辑 /etc/kdump.conf,添加驱动符号表路径 echo "dracut_args --regenerate-all" | sudo tee -a /etc/kdump.conf echo "ext4 /dev/sda2" | sudo tee -a /etc/kdump.conf # 假设根分区是 ext4 echo "core_collector makedumpfile -c --message-level 1 -d 31" | sudo tee -a /etc/kdump.conf # 3. 为 e1000e 驱动添加调试符号(编译时) cd ~/drivers/e1000e-3.8.4/ # 修改 Makefile,在 EXTRA_CFLAGS 后追加 echo "EXTRA_CFLAGS += -g -DDEBUG" >> Makefile make clean && make -j4 # 4. 生成带调试信息的 ko,并复制到 /usr/lib/debug/lib/modules/$(uname -r)/ sudo mkdir -p /usr/lib/debug/lib/modules/$(uname -r)/extra/ sudo cp e1000e.ko /usr/lib/debug/lib/modules/$(uname -r)/extra/ sudo debuginfo-install kernel-core-$(uname -r) # 若提示缺失,先 yum install kernel-debuginfo-common-$(uname -m)

逻辑说明:-g生成调试符号;-DDEBUG启用驱动内部调试打印;debuginfo-install下载内核调试包,使crash工具能解析vmcore中的 e1000e 结构体。

6.2 制作麒麟V10专用 RPM 包:让驱动分发像yum install一样简单

手动拷贝 ko 文件不满足企业运维规范。应打包为 RPM,集成preinstall检查和postinstall加载:

# 创建 RPM 构建目录结构 mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} echo '%_topdir %(echo $HOME)/rpmbuild' > ~/.rpmmacros # 将驱动源码打包为 tar.gz 放入 SOURCES tar -czf ~/rpmbuild/SOURCES/e1000e-3.8.4-ky10.tar.gz -C ~/drivers/ e1000e-3.8.4/ # 编写 SPEC 文件 cat > ~/rpmbuild/SPECS/e1000e-ky10.spec << 'EOF' Name: e1000e-ky10 Version: 3.8.4 Release: 1%{?dist} Summary: Intel e1000e driver for Kylin V10 License: GPL URL: https://sourceforge.net/projects/e1000/ Source0: e1000e-3.8.4-ky10.tar.gz BuildRequires: kernel-devel-%{?kernel_version} Requires: kernel%{?_isa} = %{?kernel_version} %description This package provides the Intel e1000e network driver compiled for Kylin V10 SP1. %prep %setup -q %build make -C /usr/src/kernels/%{?kernel_version} M=$PWD/src modules %install mkdir -p %{buildroot}/lib/modules/%{?kernel_version}/extra/ install -m 0644 e1000e.ko %{buildroot}/lib/modules/%{?kernel_version}/extra/ %post depmod -a %{?kernel_version} modprobe e1000e || : %preun if [ $1 -eq 0 ]; then rmmod e1000e 2>/dev/null || : fi %files /lib/modules/%{?kernel_version}/extra/e1000e.ko %changelog * Mon Aug 20 2023 A developer <a@example.com> - 3.8.4-1 - Initial build for Kylin V10 SP1 EOF # 构建 RPM(需先设置 kernel_version 环境变量) export kernel_version="4.19.90-rt35.ky10.aarch64" rpmbuild -ba ~/rpmbuild/SPECS/e1000e-ky10.spec # 生成的 RPM 位于 ~/rpmbuild/RPMS/aarch64/e1000e-ky10-3.8.4-1.aarch64.rpm

参数说明:%post中modprobe e1000e || :确保安装后立即加载,失败也不中断;%preun在卸载前尝试卸载模块,避免残留;Requires: kernel%{?_isa}确保 RPM 安装时检查内核版本匹配。

从那以后我每次给客户部署麒麟V10节点,都会把e1000e和r8125的 RPM 包、回退脚本、kdump 配置模板打包进一个network-driver-kit.tar.gz,交付时只需tar -xzf+rpm -ivh+systemctl enable三步。再也不用在客户机房蹲着敲命令了——毕竟,真正的工程化不是“能跑就行”,而是“下次出问题时,我连键盘都不用碰”。希望帮到你。

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

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

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

立即咨询