
简介面向银河麒麟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。这种设备在、网口不在的场面我这两年见得比任何报错都多。更让人误判的是从别处拷来一个编好的.koinsmod当时能过重启之后网卡又变回系统自带的老驱动——银河麒麟 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 vermagicuname -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.x7.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、gccrtl8125r8125-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_unusedgcc 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_64KSRC是这类厂商包里通用的变量名少数包用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 installmodinfo这一步很关键编完先自检一遍vermagic是不是和 2.1 节里记下来的标准答案一致filename是不是指向src/e1000e.koversion是不是你预期的那个。三个都对再谈安装。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|firmwareethtool -i的输出是最终判据driver: e1000eversion:后面应该是你刚编的那个版本号。如果版本号没变说明加载的还是旧的回到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 r81254.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 offSpeed: Unknown!一般意味着协商失败先换一根超五类以上的网线再确认对端端口是不是 2.5G。只协商到 1000Mb/s 的话多半是对端只支持千兆或者网线是超五类以下。Link detected: no就是物理层没通跟驱动无关了。EEE 这个参数值得单独说。它本来是省电特性但在一些老旧交换机上会导致链路抖动表现为dmesg里反复出现r8125: link up/link down。关掉之后稳定很多。要持久化的话把options r8125 eee0写进/etc/modprobe.d/r8125.conf。另外 r8125 有个aspm参数控制 PCIe 的活动状态电源管理某些主板上开启 ASPM 会导致丢包或者设备消失遇到这类玄学问题可以试试options r8125 aspm0。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 formatdmesg里跟着一行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 availabledmesg里有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 /CNLocal 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但没有 IPnmcli 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打流量这套动作不管前面多顺利都不省略。网卡驱动这东西当场跑通和长期稳定是两回事多花五分钟验证能省掉后面半夜被叫起来排查的时间。希望帮到你。本文还有配套的精品资源点击获取