简介面向CentOS 7离线环境下的运维人员压缩包内完整覆盖R8125网卡驱动安装所需的全部组件。包内不仅包含r8125-9.007.01驱动源码、autorun.sh一键安装脚本及编译生成的ko模块还专门收集了14个rpm离线依赖包从gcc、gcc-c到glibc、kernel-headers等一应俱全并针对官网驱动在CentOS 7下的编译报错做了修正省去因缺失开发工具链而反复折腾的麻烦。整个压缩包共52个文件大小约46MB除rpm外还有c/h源码、Makefile、命令记录、txt说明及模块符号文件等类型齐全目录结构也按驱动源码与gcc依赖分开整理便于对照检查。目前已有3268人学习下载适合需要在内网或无外网环境中快速为R8125网卡装载驱动的用户按包内说明依次执行即可完成离线编译安装并能理解常见依赖错误的解决方法。1. 装完CentOS 7才发现板载网卡不亮R8125离线安装到底卡在哪新买的板子自带2.5G网口系统装好后发现ip link里只有一个lo网卡灯根本不亮。查lspci能看到设备但dmesg里没有任何驱动加载记录这类板载2.5G网卡绝大多数用的就是R8125芯片CentOS 7自带内核里只有老旧的r8169模块它对R8125的支持极不完整。更要命的是目标是台离线机器yum没有网络可用想临时装个编译工具链都成了问题。这篇笔记解决的就是这个完整链路离线状态下把gcc和 kernel-devel 给你备齐拿到官网R8125驱动源码后现场改掉两个编译坑最终让网卡稳定撑过多次内核升级。整个过程不需要外网只需要一台同版本CentOS 7的在线机器帮你拉rpm包加一个U盘。适合所有做内网部署、机房交付或者手里只剩一台断网服务器的运维工程师参考。2. 离线环境装R8125的三个前置条件内核驱动、依赖链和工具链2.1 内核里没有R8125只有R8152先确认你的网卡是PCIe还是USB很多人在这一步就搞混了。内核里自带的r8152驱动是针对USB接口的2.5G网卡芯片的比如USB转2.5G的网卡适配器它和主板板载的PCIe网卡走的完全是两条路。R8125是PCIe接口的以太网控制器内核自带模块列表中并不存在对应的原生驱动所以系统装完自然找不到它。确认网卡属于哪一类直接用最朴素的命令# 查看PCI总线上所有以太网控制器 lspci -nn | grep -i ethernet # 查看当前设备被哪个驱动接管 lspci -k | grep -A2 -i ethernet第一行输出的设备名里如果明确写着RTL8125或R8125字样的就是PCIe版R8125。第二行的Kernel driver in use如果显示的是r8169说明当前是老驱动在硬扛虽然能识别到设备但无法发挥2.5G速率甚至可能出现不定时断流。如果这一行是空的说明没有任何驱动绑定它。这个确认步骤不要跳过。曾经有人把USB的R8152和PCIe的R8125混为一谈最后折腾了整整两天还以为是gcc装坏了。网卡芯片型号不同后续下载的驱动源码完全不同官网针对R8152和R8125分别提供独立的驱动包下错一个编译到天亮也起不来。2.2 在线能一条yum搞定离线必须凑齐依赖链在线安装R8125的标准做法非常简单yum装上gcc和kernel-devel解压驱动源码makeinsmod完事。但离线环境的麻烦在于——目标机器连网卡驱动都没有自然不联网yum源形同虚设。你需要在另一台同版本CentOS 7的在线机器上把编译驱动所需的全套rpm包拉下来用U盘或内网传输到目标机再本地安装。这里的核心问题是依赖链。gcc本身依赖cpp、glibc-devel、libmpc等一系列包kernel-devel又依赖kernel-headers、elfutils-libelf-devel。如果只是单独下载一个gcc的rpm拷过去安装时会直接被依赖检查卡死。网上很多教程让你直接rpm -Uvh gcc.rpm --nodeps这是能装上但将来编译别的内核模块时大概率翻车因为关键头文件根本没配齐。所以离线安装的思路应该是以编译R8125驱动为最终目标反向列出完整工具链用repotrack把所有依赖于包全部拉到一个目录里整体搬运整体安装。而不是缺一个装一个那样依赖图永远补不完。2.3 编译驱动真正需要的工具链与内核头文件清单以下是我在CentOS 7.9 x86_64环境下编译R8125驱动实际用到的软件包清单给离线环境用的机器上必须确保都有对应版本的rpm文件软件包用途是否必须gccC编译器编译驱动主代码必须gcc-c部分源码段含C代码时使用建议make执行Makefile构建流程必须kernel-devel提供内核头文件、生成module所需build目录必须kernel-headers提供用户态与内核交互头文件必须elfutils-libelf-devel部分内核模块编译会用到libelf符号建议有一个关键点必须记住kernel-devel的版本必须和目标机器上uname -r的输出完全一致。比如目标机内核是3.10.0-1160.el7.x86_64那kernel-devel也必须是这个精确版本连小版本号都不能差。原因是驱动编译时会到/lib/modules/$(uname -r)/build这个目录里找内核头文件如果这个目录指向的版本和实际运行内核不一致编出来的模块即使加载成功也会因为符号表不匹配而在insmod时直接报Unknown symbol错误。3. 离线构建gcc与开发工具链rpm打包到本地安装3.1 在一台同版本CentOS 7机器上把依赖rpm全部拉下来准备一台能够联网、且系统版本与目标机一致的CentOS 7机器。版本必须一致因为不同小版本的rpm可能有依赖差异尤其glibc和libgcc这类底层包混用版本轻则装不上重则把系统搞坏。在在线机器上执行下面的命令把整套工具链打成一个目录# 安装yum-utils以获取repotrack工具 yum install -y yum-utils # 创建存放rpm的目录 mkdir -p /tmp/r8125-toolchain # 拉取所有依赖包不安装只下载 repotrack gcc gcc-c make kernel-devel kernel-headers elfutils-libelf-devel \ --archx86_64 --destdir/tmp/r8125-toolchain # 查看拉下来的包数量 ls /tmp/r8125-toolchain | wc -l这里的repotrack比yumdownloader --resolve更彻底它会把指定包及其所有依赖全部下载到--destdir指定目录而且不做安装。--archx86_64限定架构避免拉到i686的包造成混淆。如果在线机器的yum源里没有kernel-devel对应版本可以提前在/etc/yum.repos.d/里配置[base]源指向镜像站然后yum clean all yum makecache刷新缓存。下载完成后把整个目录拷贝到U盘。注意最后复制到目标机的时候保留目录内所有rpm文件不要只挑其中几个因为你无法预知目标机上哪些基础包已经是老版本、哪些缺失。全量搬运到目标机再做取舍。3.2 目标机本地安装gcc、make与kernel-devel目标机上没有任何yum源可用安装时不能走yum install而要改用yum localinstall。这个命令会把当前目录下的rpm文件当作本地源自动解析依赖关系并在本地rpm集合中找依赖。如果依赖的包正好也在目录里就能顺利完成安装。# 进入存放rpm的目录 cd /tmp/r8125-toolchain # 先安装kernel相关包确保内核头文件先就位 rpm -Uvh kernel-headers-*.rpm kernel-devel-*.rpm # 再安装gcc和make rpm -Uvh gcc-*.rpm gcc-c-*.rpm make-*.rpm libmpc-*.rpm cpp-*.rpm # 验证工具链 gcc --version make --version先装kernel再装gcc是有讲究的。kernel-devel的rpm在安装时不会要求gcc一定存在但反过来gcc的某些依赖包可能要求内核头文件版本匹配这个顺序能减少不必要的依赖冲突。装完后检查/lib/modules/$(uname -r)/build是否存在且是一个软链接或目录这一步决定了后续驱动编译能不能找到内核头文件。如果机器之前装过旧版本gcc这里可能提示file conflicts或package gcc-xxx already installed先rpm -e gcc --nodeps再装新的但代价是旧gcc的依赖也会被留下不影响编译结果只是目录里会多一些冗余文件。3.3 升级到gcc 7.3.1解决驱动对编译器版本的硬性要求CentOS 7默认gcc版本是4.8.5这个版本编译旧版R8125驱动没问题但较新的官网驱动在Makefile里使用了部分新语法或者对C标准要求更高gcc 4.8.5下编译会冒出一堆warning: implicit declaration of function之类的告警甚至直接报错中断。标题里提到的“gcc”实际工作中最常见的高版本gcc方案是用devtoolset-7可以把gcc升到7.3.1这个版本对内核模块编译非常稳定。先在在线机器上准备devtoolset-7的rpm包# 启用SCL软件集仓库 yum install -y centos-release-scl-rh # 下载devtoolset-7相关包 mkdir -p /tmp/dts7 yumdownloader --destdir/tmp/dts7 --resolve devtoolset-7-gcc devtoolset-7-gcc-c然后把/tmp/dts7里的rpm全部拷到目标机执行安装cd /tmp/dts7 rpm -Uvh *.rpm # 启用高版本gcc环境 source /opt/rh/devtoolset-7/enable # 确认当前gcc版本 gcc --version这里的关键点是source /opt/rh/devtoolset-7/enable只是临时修改当前shell的环境变量把gcc、g的路径切换到7.3.1。新开终端或者重启后默认的gcc还是4.8.5。所以在后面编译R8125驱动之前必须先执行这个source命令或者直接把这一行写进/etc/profile.d/下新建的脚本里让每次登录shell都自动启用。选择devtoolset而不是下载gcc源码自己编的原因很简单源码编译gcc需要gcc这是一个鸡生蛋问题。更麻烦的是编译gcc还依赖gmp、mpfr、mpc等库离线状态下凑齐这些库的编译依赖已经够跑完一遍R8125驱动了。devtoolset的rpm是官方预编译好的依赖关系清晰离线安装最省事。4. 编译R8125驱动与官网源码的两个必改点Werror和头文件4.1 解压驱动源码并确认Makefile会用哪个内核目录从官网下载对应R8125芯片的驱动源码包文件名通常是r8125-版本号.tar.bz2的形式。把它拷贝到目标机解压到/usr/src目录下# 解压源码包注意文件名中的版本号要替换成实际值 tar xjf r8125-9.xxx.tar.bz2 -C /usr/src # 进入源码目录 cd /usr/src/r8125-9.xxx # 查看Makefile里的内核目录指向 grep -n KSRC\|KERNELDIR\|KDIR Makefile | head -20解压后第一件事不是急着执行make而是确认Makefile支持的内核路径是/lib/modules/$(shell uname -r)/build这种动态写法还是写死了某个路径。很多版本的官网驱动默认用KSRC : /lib/modules/$(shell uname -r)/build这种写法最省心。但也看到过某些老版本写的是绝对路径/usr/src/kernels/2.6.32-xxx这种路径在CentOS 7下完全不存在必须手动改成上面的动态形式。检查完Makefile后执行ls /lib/modules/$(uname -r)/build确认目录存在。如果这一步报错说明前面kernel-devel没装好回去查uname -r的版本号与你安装的kernel-devel版本是否一致。这个目录是编译的核心依赖它里面包含了Makefile、Kconfig、generated/autoconf.h等一整套内核构建系统文件。4.2 用gcc 7.3.1编译时必改的-Werror问题在正式编译前先把编译器的版本切换到位source /opt/rh/devtoolset-7/enable # 执行编译 make clean make -j4如果这一段编译直接报错最常见的是两类问题。第一类是与-Werror相关官网驱动部分版本在Makefile里加了-Werror把所有warning都升级为error。在gcc 7.3.1下内核模块编译时经常会有少量的无害告警比如变量未使用、隐式函数声明等这些在gcc 4.8.5下只是warning到gcc 7.3.1下依然只是warning但只要Makefile带-Werror就会直接中断编译。修改方式是找到Makefile里MOD_CFLAGS相关的行追加两个编译参数# 在Makefile中追加-Wno-error让warning不再终止编译 sed -i s/^MOD_CFLAGS.*/ -Wno-error -Wno-implicit-function-declaration/ Makefile # 确认修改结果 grep MOD_CFLAGS Makefile-Wno-error表示即使出现warning也继续编译-Wno-implicit-function-declaration则专门屏蔽隐式函数声明的告警。这两个参数对内核模块编译是安全的不会影响最终生成的模块质量。改完后重新执行make -j4大部分情况下都能顺利通过。4.3 头文件缺失或隐式声明正确补include的两种姿势第二类常见编译错误是头文件缺失导致的implicit declaration of function或unknown type name。这类错误在gcc 7.3.1下会显示具体是哪个函数或类型出了问题。比如内核模块源码用到vmalloc却没包含linux/vmalloc.h或者用到VLAN相关接口却没包含linux/if_vlan.h。处理办法是在驱动源码的主头文件通常是src/r8125.h顶部补齐include# 先看当前包含的头文件 head -50 src/r8125.h # 用vim或sed在#include区域追加缺失头文件 sed -i /#include linux\/kernel.h/a #include linux/vmalloc.h\n#include linux/if_vlan.h src/r8125.h # 再次编译 make -j4这里补include都要加在源码文件开头部分确保在用到这些函数前都完成声明。不同内核版本对头文件的组织方式有差异CentOS 7的内核比较老很多在新内核里已经自动包含的头文件在这里需要手动加。这是老驱动放在新系统上编译时的普遍现象。如果头文件缺失但不确定具体缺哪个最直接的定位方式是把编译输出重定向到文件里然后greperror: invalid use of undefined type这类关键字每一个报错对应一个缺失的头文件。一次补齐后再编译比反复试错效率高得多。4.4 insmod加载驱动并让网卡名出现在ip link里编译通过后会生成src/r8125.ko文件。先手动加载看效果# 加载驱动模块 insmod src/r8125.ko # 查看加载日志 dmesg | tail -20 # 查看网卡是否出现 ip link正常情况下dmesg里会出现类似r8125: probe device with 00:xx:xx:xx:xx:xx的日志ip link里会多出一张网卡名称可能是eth0也可能是enp3s0这类基于PCI总线位置的命名。如果ip link里没有任何新网卡先别急下一章会讲这个现象对应的排查点。加载成功后再设置IP测试连通性# 将网卡启用并通过DHCP获取地址 ip link set dev eth0 up dhclient eth0 # 查看IP ip addr show eth0拿到IP说明驱动已经正常工作。但此时驱动还只是临时的重启即失效需要做持久化和后续的DKMS收尾这些内容放在第5、6章展开。5. R8125离线安装避坑五条实操踩坑记录5.1 insmod报Unknown symbol内核开发包版本对不上现象编译一切顺利执行insmod src/r8125.ko时却弹出insmod: ERROR: could not insert module r8125.ko: Unknown symbol in module。后面跟着一长串Unknown symbol列表。原因驱动编译时使用的内核头文件与当前实际运行的内核版本不匹配。最常见的是目标机uname -r显示3.10.0-1160.el7.x86_64但安装的kernel-devel是3.10.0-1127.el7版本编译和运行时内核模块符号表对不上。另一种可能是在线机器打包rpm时顺手把自己的kernel-devel也打进去了版本比目标机内核新很多。解决重新核对版本必须完全一致后再重编。目标机器上执行uname -r在线机器上按这个版本搜索对应的kernel-devel rpm重新打包。装好后检查ls -ld /lib/modules/$(uname -r)/build确认软链接存在且指向正确目录再重新make clean make。5.2 驱动装好网卡却不出现r8169模块抢占的锅现象insmod成功了没有报错但ip link里死活看不到新网卡或者看到网卡被识别为r8169且协商速率只有100Mbps。原因内核自带的r8169模块在系统启动时提前加载并且成功绑定了网卡设备。R8125驱动无法同时接管已经被r8169占用的设备两个驱动的probe顺序决定了谁最后控制网卡。解决把r8169加入黑名单然后卸载并重新加载R8125驱动。# 编辑黑名单配置 cat /etc/modprobe.d/blacklist-r8169.conf EOF blacklist r8169 EOF # 卸载r8169并移除当前已加载的r8125再重新加载 modprobe -r r8169 rmmod r8125 modprobe r8125这里注意modprobe和insmod的区别modprobe会自动处理模块依赖并在/lib/modules/$(uname -r)目录下搜索模块文件insmod只加载指定路径文件不做依赖解析。黑名单写入后需要重建模块依赖关系执行depmod -a然后重启再验证一次。5.3 yum localinstall装依赖时版本冲突现象在目标机执行rpm -Uvh gcc-*.rpm时提示package gcc-4.8.5-44.el7.x86_64 conflicts with file from package gcc-4.8.5-44.el7.x86_64或者报Protected multilib versions错误。原因目标机原本就带有一个老版本的gcc本地rpm目录里又有一个不同小版本的gcc两个包的文件互相覆盖。另一种情况是打包时混用了官方base源和EPEL源导致依赖链内部的glibc版本要求冲突。解决先把目标机上已有的编译器相关包卸载干净再统一安装新的一整套。用rpm -qa | grep -E ^(gcc|gcc-c)查出现有包逐个rpm -e移除。之后重新安装。如果仍顽固报冲突可以退一步用rpm -Uvh *.rpm --nodeps --force但前提是你自己清楚这个目录里的所有依赖是完整配套的否则后续编译时缺失符号会非常难排查。5.4 重启后网卡回原形没有持久化加载模块现象调试完一切正常重启后网卡又消失ip link只剩lo。需要手动insmod才能恢复。原因insmod加载的是临时模块它没有进入内核模块系统管理范围。系统启动时不会自动加载这个模块除非你把模块文件拷贝到标准模块目录并执行depmod。解决做一次完整的持久化操作。# 拷贝模块到系统模块目录 cp src/r8125.ko /lib/modules/$(uname -r)/extra/ # 重建模块依赖 depmod -a # 创建自动加载配置 echo r8125 /etc/modules-load.d/r8125.conf # 如果网络服务依赖此网卡需要把模块塞进initramfs dracut -f这里重点说一下dracut -fCentOS 7默认网络服务启动时内核模块需要在initramfs阶段就已经加载完成。如果没有把r8125放进initramfs某些依赖网络文件系统启动的场景下还是会出现启动后网络起不来的情况。执行dracut -f会重建initramfs镜像把当前内核模块目录里的所有模块重新打包进去花费时间较长但值得做。5.5 升级内核后驱动立刻失效没有走DKMS现象后续某天执行了yum update kernel*重启后网卡消失modprobe r8125提示找不到模块。原因手动拷贝到/lib/modules/$(uname -r)/extra/的模块只匹配当时的那个内核版本。内核升级后uname -r变成了新版本模块目录整体换新旧的r8125.ko自然不在新目录里。解决长期维护的机器不应该靠手动拷贝模块过日子应该把驱动注册进DKMS系统。DKMS会在每次内核安装后自动重新编译并安装外部模块彻底告别手动维护。具体做法下一章展开。更保守的临时方案是在yum更新时排除内核包yum update --excludekernel*但这只是拖延内核安全更新积累起来还是要面对。6. 验证驱动生效并让它在内核升级后仍然存活DKMS收尾6.1 用dmesg与ethtool确认驱动真正接管网卡装完驱动后用几条命令就能确认是否真正接管了网卡。不要只看网卡能不能上网2.5G速率能不能跑满才是关键。# 确认模块加载和链路状态 dmesg | grep -i r8125 # 确认驱动名称与支持的速率 ethtool -i eth0 ethtool eth0ethtool -i eth0会输出driver: r8125ethtool eth0会显示Speed: 2500Mb/s。如果速度显示的是1000Mb/s先检查网线压制是否为4对8芯全通很多六类线只通了4芯2.5G协商不下会退回1G。再配合lspci -k确认Kernel driver in use后面是r8125而不是r8169这几条全部通过驱动才算真正接管。6.2 用DKMS把驱动交给内核维护避免每次升级后重编DKMSDynamic Kernel Module Support是解决内核升级后模块失效的标准手段。把R8125驱动注册到DKMS后每次内核更新DKMS都会在安装阶段自动编译并安装对应版本模块不再需要手动干预。# 先在目标机上安装dkms rpm -Uvh /tmp/r8125-toolchain/dkms-*.rpm 2/dev/null # 如果没有提前打包dkms可以从在线机器上用yumdownloader拉取 yumdownloader --destdir/tmp/dkms-rpm --resolve dkms给驱动源码添加dkms.conf配置文件# 在源码目录下创建dkms.conf cat /usr/src/r8125-9.xxx/dkms.conf EOF PACKAGE_NAMEr8125 PACKAGE_VERSION9.xxx BUILT_MODULE_NAME[0]r8125 DEST_MODULE_LOCATION[0]/kernel/drivers/net/ethernet/r8125 AUTOINSTALLyes EOF注册并编译安装到DKMS# 添加驱动源码到DKMS系统 dkms add -m r8125 -v 9.xxx # 编译并安装 dkms build -m r8125 -v 9.xxx dkms install -m r8125 -v 9.xxx这里PACKAGE_VERSION必须和dkms add -v后面的版本号严格一致同时也要和源码目录名的版本号对应。AUTOINSTALLyes表示新内核安装后自动触发编译安装这行参数不能漏。DEST_MODULE_LOCATION建议保持/kernel/drivers/net/ethernet/r8125这是内核模块目录的标准层次结构。做完DKMS注册后之前的/etc/modules-load.d/r8125.conf和黑名单配置继续保留。验证是否生效的方法是执行dkms status看到r8125/9.xxx: installed即表示注册成功。以后每次内核升级时盯一次dkms status如果报Error! Build of r8125 failed多半是编译环境缺了新内核版本的kernel-devel补齐后运行dkms build -m r8125 -v 9.xxx即可。以前我有一台跑着业务的内网服务器就是吃了没做DKMS的亏每次内核升级都要半夜爬起来重新编译网卡驱动连编译环境都重新配一遍那段时间一看到自动更新就神经紧张。后来花十分钟把驱动交给DKMS管升级流程彻底安静了。希望这篇笔记能帮你少走这一段弯路离线环境折腾网卡驱动真正麻烦的不是编译本身而是把工具链和模块维护机制一次想清楚。希望帮到你。本文还有配套的精品资源点击获取