银河麒麟V10网卡驱动编译通过却不通?e1000e与RTL8125排查指南
简介:面向在银河麒麟V10上进行网卡适配的运维与驱动开发人员,这份资源提供已在该系统上编译通过的e1000e与RTL8125两款网卡驱动源码,可解决国产化平台下Intel与Realtek网卡无法正常加载、编译报错等适配难题。压缩包共56个文件,以C源文件与头文件为主体,辅以Makefile、README、spec及校验文件等,整体约483KB,结构完整、便于直接编译验证。资源中针对源码重复定义与函数参数做了适配调整,读者可据此理解内核兼容性修改思路,快速完成编译、加载与网卡功能验证。目前已有2747人学习下载,适合需要排查驱动兼容问题或积累国产系统移植经验的技术人员参考。
1. 装完驱动网卡还是没起来:银河麒麟 V10 上 e1000e 与 RTL8125 编译通过却不通的坑
在银河麒麟 V10 上折腾网卡驱动,最让人抓狂的不是编译报错,而是make一路绿灯、insmod也没报错,结果ip link里压根看不到那块网卡,或者看到了却死活拿不到地址。e1000e 和 RTL8125 这两颗芯片在国产化桌面和工控机上出现频率极高,前者是 Intel 千兆有线,后者是 Realtek 2.5G 有线,很多整机出厂预装的驱动版本偏老,或者内核里只带了半残的模块,于是大家第一反应就是去下源码自己编。编过的人都知道,银河麒麟 V10 的内核是深度定制过的,头文件路径、CONFIG_*开关、GCC 版本都跟上游主线有出入,编译通过只是万里长征第一步。这篇笔记面向的是已经卡在“驱动装上了但网卡不工作”这一步的开发者,也适合刚接手国产化适配、被网卡问题反复折腾的新手,下面按故障现象一层层往下拆。
2. 编译阶段就翻车:内核头文件与 GCC 版本对不上导致的报错
银河麒麟 V10 上编 e1000e 和 RTL8125,十有八九会先栽在编译环节。报错五花八门,但根子基本就两个:一是找不到当前运行内核对应的头文件,二是编译器版本和内核构建时用的不一致。这一章把最常见的几类编译报错摆出来,逐个说清触发条件和处理办法。
2.1 报错 “找不到 kernel headers”:/lib/modules/$(uname -r)/build 是空链接
最典型的报错长这样:
make: *** /lib/modules/5.4.18-xxx-generic/build: No such file or directory. Stop.或者进到驱动目录执行make时提示Kernel build directory not found。这个报错的触发条件很明确:系统里装了内核,但没装与之完全匹配的linux-headers包,或者/lib/modules/$(uname -r)/build这个软链接指向了一个不存在的目录。银河麒麟 V10 的内核版本号带厂商后缀,很多人直接apt install linux-headers-$(uname -r)会失败,因为软件源里根本没有这个精确版本。
先确认现状:
# 看当前运行内核版本 uname -r # 看 build 链接指向哪里,是否断链 ls -l /lib/modules/$(uname -r)/build # 查软件源里有哪些可用的头文件包 apt list --installed 2>/dev/null | grep -i headers apt-cache search linux-headers | grep $(uname -r)如果build是断链,或者apt-cache search查不到精确版本,常见做法是去系统安装镜像或厂商提供的软件源里找对应版本的linux-headers和linux-devel包手动安装。装完后重新确认链接:
# 安装匹配的头文件包后,重建 build 软链接(路径按实际内核版本替换) sudo ln -sfn /usr/src/linux-headers-$(uname -r) /lib/modules/$(uname -r)/build # 验证头文件目录里确实有 Makefile 和 include ls /lib/modules/$(uname -r)/build/Makefile这里ln -sfn的-f是强制覆盖已有链接,-n是把已存在的目录链接当普通文件处理,避免在目标目录里再建一层。链接修好后make才能找到内核构建树。需要提醒的是,头文件版本必须和uname -r完全一致,差一个小版本号都可能编出加载不上的模块,这是后面insmod报Invalid module format的伏笔。
2.2 报错 “error: implicit declaration of function”:GCC 版本与内核构建链不匹配
第二类高频报错是编译中途大量函数隐式声明警告升级成错误:
error: implicit declaration of function ‘xxx’; did you mean ‘yyy’? error: ‘struct xxx’ has no member named ‘yyy’这类报错看着像驱动源码写错了,其实多半是编译器版本和内核构建时用的 GCC 不一致。银河麒麟 V10 不同更新批次带的内核,可能是用 GCC 7、GCC 8 或更高版本编的,而系统默认gcc可能被切到了别的版本。内核模块对编译器版本敏感,头文件里的内联函数、宏展开在不同 GCC 下行为不同,于是出现结构体成员对不上、函数找不到声明的情况。
先看内核是用哪个编译器编的:
# 内核构建时会记录编译器版本 cat /proc/version # 看当前默认 gcc 版本 gcc --version | head -1 # 看系统里装了哪些 gcc ls /usr/bin/gcc*如果/proc/version里显示的是gcc version 7.x,而gcc --version是 9 或 10,就要把编译用的编译器切回去。常见做法是用update-alternatives管理多版本,或者直接在make时指定CC:
# 指定与内核匹配的编译器版本编译驱动 make CC=/usr/bin/gcc-7 KDIR=/lib/modules/$(uname -r)/buildCC指定编译器,KDIR显式指向内核构建目录,避免驱动 Makefile 自己猜路径猜错。如果系统里没有对应版本的 gcc,需要从软件源补装。编完用modinfo看模块的vermagic是否和当前内核一致:
modinfo ./e1000e.ko | grep vermagic uname -r两边的内核版本串必须对得上,后面带的内核配置标记(比如SMP mod_unload)也要一致,否则加载时直接拒绝。这一步是很多人忽略的,编完不验证vermagic,等到insmod才报错,又得回头重编。
2.3 RTL8125 特有的 “unknown symbol” 与内核符号导出问题
RTL8125 的驱动源码在较新版本里依赖一些内核网络子系统导出的符号,在银河麒麟 V10 这种定制内核上,部分符号可能没导出,编译能过但加载时报:
insmod: ERROR: could not insert module r8125.ko: Unknown symbol in module用dmesg能看到具体缺哪个符号:
# 加载失败后立刻看内核日志,定位缺失的符号名 sudo insmod r8125.ko dmesg | tail -20日志里会写Unknown symbol xxx (err -2)。err -2表示符号未找到。这种情况要么是内核配置里对应功能没开,要么是驱动版本和内核版本不匹配。处理思路是先确认符号是否真的存在于当前内核:
# 在内核符号表里查这个符号是否存在 grep xxx /proc/kallsyms如果/proc/kallsyms里查不到,说明内核根本没编进这个功能,换驱动版本也没用,得换内核或找厂商要适配版。如果查得到但驱动仍报未知符号,多半是符号没有EXPORT_SYMBOL导出,模块无法引用,这种只能改驱动源码绕开该接口,或者退回不依赖该符号的旧版驱动。RTL8125 的驱动分支比较多,选版本时优先选和内核年代接近的那一支,别盲目追最新。
3. 模块加载成功但网卡不出现:设备识别与 PCI 层面的排查
编译过了、insmod也不报错,lsmod里能看到e1000e或r8125,但ip link里就是没有对应的eth或enp接口。这个阶段的问题已经不在编译,而在设备识别、PCI 枚举和驱动绑定上。这一章按从硬件到驱动的顺序排查。
3.1 先确认硬件是否被 PCI 总线识别:lspci 看不到设备就别谈驱动
驱动再对,硬件没被枚举也是白搭。第一步永远是看 PCI 总线有没有认到这块网卡:
# 列出所有网络控制器,确认厂商和设备 ID lspci -nn | grep -i -E 'ethernet|network'正常应该看到类似Ethernet controller [0200]: Intel Corporation ... [8086:xxxx]或Realtek Semiconductor Co., Ltd. ... [10ec:8125]的行。如果lspci里压根没有网卡,问题在硬件层:网卡没插好、PCIe 插槽供电异常、BIOS 里禁用了板载网卡,或者设备被pci=noacpi之类的启动参数挡掉了。这种情况驱动怎么装都没用,先回硬件和 BIOS 排查。
如果lspci能看到设备,但后面跟的是Kernel driver in use: xxx为空或者显示的是别的驱动,说明设备在,但没绑到目标驱动上:
# 看某块网卡当前绑定的驱动和内核模块 lspci -k -s <总线地址>-k会显示Kernel driver in use和Kernel modules两行。如果in use是空的,说明没有驱动接管;如果显示的是r8169而你装的是r8125,那就是驱动冲突,下一节细说。
3.2 驱动绑定失败:modprobe 成功但设备没被 probe
lsmod有模块、lspci有设备,但接口不出现,最常见的原因是驱动的 probe 函数执行失败。看内核日志是唯一可靠的手段:
# 清空环形缓冲区后重新加载模块,抓取 probe 阶段的日志 sudo dmesg -C sudo modprobe -r e1000e 2>/dev/null sudo modprobe e1000e dmesg | grep -i -E 'e1000e|eth'日志里如果出现probe of xxxx failed with error -xx,错误码就是线索。-19通常是ENODEV,设备 ID 不在驱动支持列表里;-12是ENOMEM,内存分配失败;-16是EBUSY,设备已被别的驱动占用。针对设备 ID 不匹配的情况,可以查驱动支持的 ID 列表:
# 查看模块支持的设备 ID modinfo e1000e | grep alias如果lspci里的设备 ID 不在 alias 列表里,说明这个驱动版本不认识你的芯片型号,需要换更新的驱动源码,或者在驱动源码的 PCI ID 表里手动补一行。补 ID 是最后手段,补之前先确认芯片型号确实属于该驱动家族,别把不同代的芯片硬塞进去。
3.3 接口命名规则变化:网卡起来了但名字不是 eth0
还有一种“假故障”:网卡其实工作正常,只是接口名不叫eth0。银河麒麟 V10 默认启用可预测网络接口命名,接口可能叫enp3s0、eno1之类。很多人ifconfig看不到eth0就以为驱动没装上,其实ip link里接口一直在。
# 用 ip 命令看所有接口,包括未启用的 ip link show # 只看有线网卡,按类型过滤 ip -brief link show type etherip -brief输出更紧凑,一眼能看出哪些接口是DOWN状态。如果接口在但状态是DOWN,ip link set <接口名> up启用即可。如果确实想让接口回到eth0这种传统命名,可以改内核启动参数加net.ifnames=0 biosdevname=0,但这会影响整机所有网卡命名,生产环境改之前要评估,别为了顺手把别的网卡配置搞乱。
4. 网卡识别了却连不上:链路、速率与驱动参数的坑
接口出现在ip link里、状态也UP了,但ping不通、拿不到 DHCP 地址,或者链路时断时续。这一层的问题集中在物理链路协商、驱动参数和 2.5G 速率兼容性上,RTL8125 尤其容易在这里翻车。
4.1 链路显示 NO-CARRIER:先分清是线的问题还是协商问题
ip link里接口状态是NO-CARRIER,意思是物理层没检测到对端信号。先排除最朴素的可能:网线没插紧、网线是坏的、对端交换机端口没开。这些排除掉之后,再看协商结果:
# 查看接口的链路检测和协商状态 sudo ethtool <接口名> # 查看支持的链路模式和当前协商模式 sudo ethtool <接口名> | grep -A 20 'Supported link modes'ethtool输出里Link detected: no就是没链路。如果Supported link modes里有 2500baseT 但Advertised link modes里没有,说明驱动没把 2.5G 模式广播出去,对端只认千兆就可能协商不上。RTL8125 在部分交换机上需要手动指定速率:
# 强制指定速率和双工模式,绕过自动协商 sudo ethtool -s <接口名> speed 1000 duplex full autoneg offspeed和duplex按对端能力填,autoneg off关闭自动协商。强制模式是排查手段,不是长期方案,协商正常后应该改回autoneg on,否则换根线或换个交换机端口又得手动改。如果强制千兆能通、自动协商不通,基本可以锁定是 2.5G 协商兼容性问题,考虑升级驱动或换交换机端口。
4.2 RTL8125 的 2.5G 速率在千兆交换机上反复重连
这是 RTL8125 最经典的坑:网卡支持 2.5G,插到只支持千兆的交换机上,自动协商在 2.5G 和 1G 之间反复横跳,表现为链路频繁 up/down,dmesg里刷屏:
# 观察链路抖动,连续看几秒 dmesg -w | grep -i -E 'link|r8125'日志里会看到Link is Up和Link is Down交替出现。根因是驱动默认优先广播最高速率,对端不支持时协商过程不稳定。处理办法有两个方向:一是升级到较新的 r8125 驱动,新版本对协商回退处理更稳;二是在驱动加载参数里限制速率。r8125 支持通过模块参数控制:
# 加载时限制最高协商速率(具体参数名以驱动源码为准,常见为 speed_mode) sudo modprobe r8125 speed_mode=1参数含义要对照驱动源码里的module_param定义,不同分支参数名可能不同,别照抄。更稳妥的做法是写进/etc/modprobe.d/下的配置文件,让每次开机自动生效:
# 写入模块参数配置,开机自动应用 echo "options r8125 speed_mode=1" | sudo tee /etc/modprobe.d/r8125.conf # 重建 initramfs 让配置在早期启动阶段生效 sudo update-initramfs -uupdate-initramfs -u这一步很多人漏掉,导致配置只在手动modprobe时生效,重启后又回到老样子。改完重启验证dmesg里链路是否稳定。
4.3 e1000e 的 “Detected Hardware Unit Hang” 与中断问题
e1000e 在银河麒麟 V10 上偶发Detected Hardware Unit Hang,表现为网络卡顿几秒后恢复,dmesg里有:
e1000e 0000:00:1f.6: Detected Hardware Unit Hang这个报错根因通常是 TSO(TCP Segmentation Offload)或中断合并在高负载下和某些硬件版本配合不好。先确认是不是 offload 引起的:
# 临时关闭 TSO 和 GSO 验证 sudo ethtool -K <接口名> tso off gso off如果关闭后不再 hang,说明问题在 offload。长期方案是写进网络配置或 udev 规则,开机自动关闭。另一种常见处理是调整中断合并参数:
# 查看当前中断合并设置 sudo ethtool -c <接口名> # 关闭自适应中断合并,固定合并参数 sudo ethtool -C <接口名> adaptive-rx off adaptive-tx off rx-usecs 0 tx-usecs 0adaptive-rx/tx off关掉自适应,rx-usecs 0表示不延迟收包中断。这些参数对吞吐和 CPU 占用有影响,调完要压测验证,别在生产机上随手改。e1000e 的 hang 有时也和电源管理有关,BIOS 里关掉 PCIe ASPM 能缓解一部分,这属于硬件层手段,放在最后试。
5. 避坑与常见问题:那些让我返工三次的细节
这一章记录的是实际适配过程中反复踩到的坑,每条都按现象、原因、解决三段写,都是血泪经验,照着避开能省不少时间。
5.1 现象:编好的 .ko 换台机器就加载失败
原因:模块的vermagic绑定了编译时的内核版本和配置,两台机器内核小版本不同,或者一台开了 SMP 一台没开,模块就不兼容。很多人以为同是银河麒麟 V10 就能通用,实际不同更新批次内核版本号差很多。
解决:每台目标机器上单独编译,或者用modinfo xxx.ko | grep vermagic对比目标机uname -r,不一致就重编。批量部署时把编译产物和内核版本绑定管理,别混用。
5.2 现象:r8125 和系统自带 r8169 抢同一块网卡
原因:Realtek 的 r8169 是内核自带驱动,会优先绑定部分 RTL8125 设备,导致你装的 r8125 加载了但设备被 r8169 占着,lspci -k里Kernel driver in use显示 r8169。
解决:把 r8169 加入黑名单,阻止它自动加载:
# 黑名单屏蔽 r8169,避免抢占 RTL8125 设备 echo "blacklist r8169" | sudo tee /etc/modprobe.d/blacklist-r8169.conf # 重建 initramfs 后重启 sudo update-initramfs -u重启后确认lsmod | grep r8169为空,lspci -k里驱动变成 r8125。注意黑名单只对自动加载生效,如果 r8169 已经被编进内核(built-in)而非模块,黑名单无效,得靠内核启动参数或换内核解决。
5.3 现象:驱动装好后重启又失效
原因:手动insmod加载的模块重启后不会自动加载,或者模块参数没写进配置文件。很多人装完当场能用,第二天开机又回到没网的状态。
解决:把模块名写进/etc/modules或/etc/modules-load.d/下的配置文件,参数写进/etc/modprobe.d/,然后update-initramfs -u。三步缺一不可,只写模块名不写参数,参数会丢;只写参数不重建 initramfs,早期启动阶段加载的还是旧配置。
5.4 现象:dmesg 里 probe 报 -16 EBUSY
原因:设备已被其他驱动占用,常见于 r8169 先绑定了设备,或者上一次insmod的模块没卸干净。rmmod报Module in use也是同一类问题。
解决:先lsmod看谁占着,lspci -k确认当前绑定驱动,卸载占用驱动后再加载目标驱动。如果rmmod卸不掉,用lsof或fuser查是否有进程持有网络接口,停掉相关服务再卸。
5.5 现象:编译警告一堆,以为没事,加载后行为异常
原因:内核模块编译时的警告不能当耳旁风,尤其是implicit declaration和类型不匹配的警告,编出来的模块可能能加载但运行时行为不可预期,比如收包丢包、中断处理异常。
解决:编译时加W=1打开更多警告,把警告当错误看:
# 打开额外警告编译,暴露潜在问题 make W=1 KDIR=/lib/modules/$(uname -r)/build有警告先查清楚再加载,别抱着“能跑就行”的心态,网卡驱动跑在中断上下文里,一个未定义行为可能就是随机丢包,排查起来极其痛苦。
6. 快速定位这类问题的顺序:从 lspci 到 dmesg 的一条线
网卡驱动问题看着杂,其实排查有一条固定主线,按顺序走能少绕很多路。我一般从硬件枚举开始,一层层往上确认,每层都有明确的判断依据,不靠猜。
第一步永远是lspci -nn | grep -i ethernet,确认设备在总线上。设备不在,后面全是空谈,直接查硬件和 BIOS。设备在,记下总线地址,用lspci -k -s <地址>看当前绑定的驱动,这一步能立刻区分“没驱动”和“驱动绑错”两种情况。
第二步看模块状态,lsmod | grep -E 'e1000e|r8125|r8169'确认目标模块是否加载、有没有冲突模块共存。模块没加载就modprobe,加载失败看dmesg里的错误码,-2查符号、-19查设备 ID、-16查占用,错误码基本能定位到具体环节。
第三步看接口,ip -brief link show type ether列出所有有线接口和状态。接口不在,回第二步查 probe;接口在但DOWN,ip link set up;接口UP但NO-CARRIER,转ethtool查链路协商。
第四步看链路和收发包,ethtool <接口>看Link detected和协商速率,ethtool -S <接口>看收发包计数和错误计数。错误计数持续增长说明物理层或驱动收包路径有问题,结合dmesg里的 hang、reset 日志一起看。
把这条线整理成一张对照表,排查时对着填:
| 检查层 | 命令 | 正常表现 | 异常时的下一步 |
|---|---|---|---|
| PCI 枚举 | lspci -nn | grep -i ethernet | 能看到网卡和厂商 ID | 查硬件、BIOS、插槽 |
| 驱动绑定 | lspci -k -s <地址> | Kernel driver in use为目标驱动 | 查黑名单、模块冲突 |
| 模块加载 | lsmod | grep 驱动名 | 模块在列表中 | 看dmesg错误码 |
| 接口存在 | ip -brief link show type ether | 有对应接口且状态符合预期 | 查 probe 日志 |
| 链路状态 | ethtool <接口> | Link detected: yes | 查网线、协商、强制速率 |
| 收发包 | ethtool -S <接口> | 错误计数不增长 | 查 offload、中断、硬件 |
最后一步是验证,别只看“能 ping 通”就收工。用iperf3或dd走网络传大文件压几分钟,同时dmesg -w盯着有没有 hang、reset、link down 的日志,ethtool -S看错误计数有没有涨。很多问题在空闲时看不出来,一上负载就暴露,压测是唯一的后悔药。
从那以后我每次在银河麒麟 V10 上装网卡驱动,都强制走一遍“lspci 确认设备、lspci -k 确认绑定、dmesg 确认 probe、ethtool 确认链路、压测确认稳定”这五步,一步不跳。这套流程看着笨,但能把绝大多数“编译通过却不通”的问题挡在交付之前。希望帮到你。
本文还有配套的精品资源,点击获取