☰
海光网卡驱动安装:从内核匹配到性能调优的完整指南
2026/10/13 2:45:48 网站建设 项目流程

简介:成都海光网卡驱动安装包内包含驱动源码与编译脚本,面向需要在服务器或桌面环境中部署海光网卡的系统运维与驱动编译人员,解决操作系统无法识别或无法充分发挥网卡性能的问题。压缩包共22个文件,以C语言源码文件(14个.c、3个.h)为主,配套Makefile与.mk构建脚本、Shell辅助脚本,以及readme和txt说明文档,可指导完成驱动的编译、安装与基础配置。整个压缩包仅146KB,体积小巧,便于快速下载与分发。目前已有658人学习使用。使用者可获得完整的驱动源码头文件、构建配置与部署说明,据此适配不同内核版本并完成本地化编译;其中包含的配置及诊断相关内容,也有助于排查网卡未被识别、链路速率异常等常见故障,避免仅依赖官方二进制包时的兼容性局限。

1. 海光网卡驱动安装包:为什么国产服务器装完系统先要解决“没网”的十几个小时

拿到一台预装某国产操作系统的服务器,随手敲ip a,发现只有lo没有eth0,这时候第一反应不是查网线,而是查驱动是否被正确加载。海光网卡驱动安装包解决的就是国产化服务器装完系统后网卡不被识别、上不了内网的问题,适合运维工程师、系统集成商和做国产化适配的开发者在离线或半离线环境下快速恢复网络。很多人在这一步卡过十几个小时:系统起来了,但网卡黑匣子一样不工作,SSH 连不上,内网进不去,想下个依赖包都没通道。这份驱动包的价值就是省掉那段“睁眼瞎”的时间——只要按流程走,从解包到网卡亮灯,通常在半小时内收工。

2. 从解包到编译:驱动包里的三个组件分别负责什么

拿到驱动包之后,不要急着make,先把包结构看明白。这类网卡驱动包通常不是单一文件,里面至少包含三样东西:驱动源码、固件文件、编译脚本或配置文件。搞清楚谁是谁,后面排查问题才能定位到具体环节。

2.1 驱动包内部的三个组件

驱动包解压后的典型目录结构如下(以 tar.gz 压缩包为例):

hgu-netdriver/ ├── src/ # 驱动源码主目录 │ ├── hgu_main.c # 网络设备注册、探测入口 │ ├── hgu_ethtool.c # ethtool 接口实现 │ └── Makefile # 编译规则 ├── firmware/ # 固件文件,放在 /lib/firmware 下 │ └── hgu_fw.bin ├── docs/ # 官方说明和发行注记 ├── scripts/ # 辅助脚本,比如安装、卸载、绑定队列 └── README.md

这里面的角色分配是这样的:src/是驱动模块本体,最终编译产出.ko文件;firmware/是网卡固件,负责底层 PHY、MAC 的微码逻辑,没有它驱动加载时会在dmesg里报firmware not found;scripts/里通常有install.sh和uninstall.sh,它们不是必须用,但能帮你少写几行命令。常见做法是先看 README 再动手——至少确认驱动支持的内核版本范围,免得后面编译翻车。

2.2 先确认编译工具链

如果目标机器能联网,这一步很简单;如果是离线内网,就需要提前准备依赖包。驱动编译需要三样东西:gcc、make、kernel-devel(或kernel-headers)。它们的版本要和当前运行的内核匹配,否则编出来的模块加载不进内核。

# 检查编译器和构建工具 gcc --version make --version # 检查当前内核版本 uname -r # 检查内核开发包是否安装,注意版本号要和 uname -r 一致 rpm -qa | grep kernel-devel ls -d /usr/src/kernels/$(uname -r)

ls -d /usr/src/kernels/$(uname -r)这一步很关键:目录存在代表内核头文件就位,不存在则说明kernel-devel没装或者版本不对。很多人在这一步省略了检查,直接跳到编译,然后被一屏的fatal error: linux/version.h: No such file or directory打回原形,这就属于可以提前避开的坑。

2.3 编译安装的完整命令序列

驱动包的编译安装流程相对固定,下面的命令序列在一台干净的内网服务器上可以直接照抄:

# 1. 解压驱动包并进入源码目录 tar -xzf hgu-netdriver.tar.gz cd hgu-netdriver/src # 2. 清理历史编译产物,避免上次残留的 .o 干扰 make clean # 3. 编译驱动模块,生成 .ko 文件 make # 4. 安装模块到系统内核模块目录 make install # 5. 刷新模块依赖关系,这一步不能省 depmod -a # 6. 加载驱动模块 modprobe hgu

每条命令的角色说明一下:make clean不是洁癖,如果之前用旧内核编译过,残留的.o文件会让make误判依赖关系,出现“编译成功但加载失败”的诡异现象;depmod -a是重建modules.dep文件,让modprobe能根据依赖自动加载模块,跳过它直接modprobe hgu很可能报module not found。到这里如果网卡仍然不亮,先看dmesg | tail -50,里面通常会写明原因,后面第 5 章专门讨论这些报错。

2.4 把驱动写进开机自动加载

编译安装只能保证这一次重启前能用,如果重启后网卡又消失了,说明模块没有进入开机加载流程。常见做法有两种,推荐用modprobe.conf的方式:

# 在 modprobe.d 目录下新建配置文件,写入自动加载指令 cat > /etc/modprobe.d/hgu.conf << 'EOF' alias eth0 hgu options hgu num_rx_queues=8 num_tx_queues=8 EOF # 重新生成 initramfs,让内核在早期启动阶段就能加载驱动 dracut -f --add-drivers hgu

alias eth0 hgu是告诉系统第一个以太网口对应的驱动模块是谁,options行用来传参数——队列数这个参数按 CPU 核数设,后面第 4 章会展开讲。dracut -f是重建 initramfs,如果不跑这一步,某些系统重启后驱动加载顺序不对,网卡还是会掉。dracut只在 RedHat/CentOS 系可用,Debian/Ubuntu 系对应的是update-initramfs -u,如果系统是 Debian 体系,把最后一条命令替换成update-initramfs -u即可。

3. 内核版本匹配:三个命令确认编译环境再动手

驱动源码本质上是一段直接和内核内部 API 打交道的代码,内核版本一变,函数签名、结构体布局都可能动。这也是为什么同样一份驱动包,在这台机器上编译一把过,换个内核版本的机器就报错。与其事后看报错猜原因,不如编译前用三个命令把环境锁死。

3.1 为什么驱动必须跟内核版本走

uname -r输出的内核版本号(比如6.1.76)决定了两件事:第一,编译时链接的kernel-devel必须和它完全一致,小版本号对不上都会出问题;第二,编译产出的.ko模块文件在insmod时会被内核做版本校验,如果模块的vermagic和当前内核不匹配,内核会直接拒绝加载,报invalid module format。这不是玄学,是内核的安全机制:新版内核收紧了对未导出的EXPORT_SYMBOL符号的访问权限,老接口被移除后旧驱动自然编不过。所以最稳的路径是“先确认版本,再决定用哪个驱动包”,而不是拿着包逐个试。

3.2 三个确认命令,一个都不能少

# 命令一:当前内核版本号 uname -r # 命令二:安装的 kernel-devel 版本 rpm -qa | grep kernel-devel # 命令三:内核头文件目录是否存在 ls -d /usr/src/kernels/$(uname -r)

把这三条命令的输出对齐来看:uname -r的值应该等于kernel-devel包版本里的后半部分,同时等于/usr/src/kernels/下目录名的后半部分。三者一致,环境才干净。如果rpm -qa输出了多个版本的kernel-devel,建议只保留和当前内核一致的,避免链接时找错头文件。另外,ls那个命令用$(uname -r)自动取值,比手打版本号靠谱,手滑打错一个字符就是浪费十分钟。

3.3 离线环境没有 kernel-devel 的备选方案

内网机器装kernel-devel是最容易卡壳的环节。如果手头没有对应版本的 rpm 包,有两条路可走:

第一条,从同版本内核的构建机上直接把/usr/src/kernels/$(uname -r)目录打包拷贝过来,注意目录权限和软链接要保留。这种方法适合环境批量交付,构建一次,拷贝到所有同内核版本机器。第二条,如果连构建机都没有,可以尝试用yum --downloadonly在有网的机器上下载kernel-devel和kernel-headers的 rpm 包,再拷贝到内网安装:

# 在能联网的机器上下载 rpm 包,注意指定和服务器相同的内核版本 yum install --downloadonly --downloaddir=/tmp/kernel-rpms \ kernel-devel-$(uname -r) kernel-headers-$(uname -r) # 拷贝到内网机器后,本地安装 rpm -ivh /tmp/kernel-rpms/*.rpm

--downloaddir指定下载目录,--downloadonly只下载不安装;版本号通过$(uname -r)动态获取,保证和服务器一致。这个方案的坑在于:yum解析依赖时可能下载多个版本的包,务必核对目录下 rpm 包的实际版本,装错版本后面编译时还是找不到头文件。

3.4 版本不匹配时的典型报错与处理

驱动编译最常见的三类报错都和信息配对有关。第一类:fatal error: linux/compiler-version.h: No such file or directory,原因是kernel-devel没装或者头文件路径没做软链接,解决方法是重新安装和uname -r一致的开发包,再检查/usr/src/kernels是否存在。第二类:fatal error: generated/autoconf.h: No such file or directory,原因同上。第三类:unknown type name 'struct __kernel_sockaddr_storage',这是头文件版本老于内核版本导致的接口漂移,需要把kernel-headers一起升级对齐。处理这些报错的通用步骤是先跑rpm -qa | grep kernel列出所有内核相关包,确认版本清单后再重装,不要盲目去改源码里的头文件引用。

4. 装完不算完:验证、队列调优与服务化配置

驱动加载成功不等于网卡稳定跑满带宽。一次完整的安装流程,在modprobe hgu之后还必须做三件事:确认驱动真正接管了网卡、检查中断与多队列配置、跑一次压测把性能基线摸出来。

4.1 用 lspci 和 ethtool 确认驱动接管网卡

# 查看 PCI 设备列表中网卡是否已被驱动绑定 lspci -nn | grep -i ethernet # 查看驱动绑定的具体设备信息 lspci -k -s $(lspci | grep -i ethernet | cut -d ' ' -f1) # 用 ethtool 查看网卡当前速率和协商状态 ethtool eth0

lspci -k的-k参数会显示内核驱动名称,如果输出里Kernel driver in use: hgu,说明驱动接管成功;如果显示Kernel modules: hgu但Kernel driver in use的字段缺失,说明模块已加载但设备绑定失败,这时候要看dmesg里有没有probe阶段的报错。ethtool eth0主要看Speed和Duplex两项,正常应该显示10000Mb/s和Full,如果显示Unknown或Half,检查网线、对端设备协商设置以及固件版本。

4.2 多队列与中断亲和的必要配置

网卡的多队列能力决定高并发小包场景下 CPU 是否被单个核拖死。不配置的话,所有中断都可能落在CPU0上,压测时能看到一个核跑满,其他核闲着。

# 查看当前网卡队列数和中断号 ethtool -l eth0 # 查看中断分布情况 cat /proc/interrupts | grep hgu # 如果队列数没到最大值,先调整队列数量 ethtool -L eth0 combined 8

队列数设置规则:物理核数除以网卡中断所在 NUMA 节点的 CPU 数,简单做法是先设成物理核数的一半,压测后再调整。ethtool -L的combined 8只是把队列数提到 8。接下来要做中断亲和绑定,把每个队列的中断均匀分配到不同 CPU 核上。有个常见做法是用irqbalance服务自动分配,但在高性能场景下不如手动精确:

# 把 8 个中断号分别绑定到 CPU 0-7(示例) for i in $(ls /proc/irq/ | grep -E '^[0-9]+$'); do cpu=$((i % 8)) echo $((1 << cpu)) > /proc/irq/$i/smp_affinity done

这个脚本的思路是把每个中断号按模 8 映射到对应 CPU。$((1 << cpu))生成的是 CPU 掩码,比如 CPU2 对应4。生产环境建议用ethtool -U eth0 rx-flow-hash tcp4这类 RSS 哈希配置来提升多流负载均衡,后面在调优文件里统一配置。

4.3 压测验证:iperf3 前后对比

调优前先跑一次基线压测,调优后再跑一次,用数据说话。

# 服务端(iperf3 -s 监听默认端口 5201) iperf3 -s -i 1 # 客户端(-c 指定服务端 IP,-t 指定测试时长 30 秒,-P 4 用 4 个并行流) iperf3 -c 192.168.10.20 -t 30 -P 4

测试时注意两点:一是用-P 4以上的并行流才看得出多队列调优效果,单流测的是单核上限,说明不了全卡性能;二是-R参数可以测反向带宽,TCP 双向传输和单向传输的瓶颈位置不同,建议两组都跑。如果调优后Retr列的重传数明显下降,同时带宽提升一二成,说明中断绑定和队列配置生效了。

4.4 开机自启与参数固化

第 2 章提过modprobe.conf写入参数,这里给一份完整的规范化配置,把前面调优的队列参数和中断设置固化下来:

cat > /etc/modprobe.d/hgu.conf << 'EOF' options hgu num_rx_queues=8 num_tx_queues=8 EOF # 把中断亲和绑定写成 systemd service,开机自动执行 cat > /etc/systemd/system/irq-affinity.service << 'EOF' [Unit] Description=Set HGU IRQ affinity After=network.target [Service] Type=oneshot ExecStart=/usr/local/bin/hgu_irq_affinity.sh [Install] WantedBy=multi-user.target EOF # 启用服务 systemctl daemon-reload systemctl enable irq-affinity.service

Type=oneshot表示这个服务只跑一次脚本,不常驻;After=network.target保证网络配置完成后脚本才执行,不会因为网卡还没就绪而报找不到中断文件。脚本内容就是把 4.2 节那个for循环存到/usr/local/bin/hgu_irq_affinity.sh并加执行权限。这套配置的好处是:以后重启机器,驱动参数和中断绑定自动生效,不用人工干预。

5. 避坑:五条安装海光网卡驱动的实战翻车记录

这一章把我在多台国产化服务器上安装驱动过程中遇到的高频问题列出来,每条都按“现象 → 原因 → 解决”的顺序写,希望你看完能少走弯路。

5.1 编译报错:找不到内核头文件

现象:执行make时,屏幕上滚过大量fatal error: linux/version.h: No such file or directory,编译直接中断。

原因:kernel-devel未安装,或者安装了但版本号与uname -r不一致。很多时候是安装系统时勾选的开发工具集不完整,默认只带了gcc,没带内核头文件。

解决:先跑uname -r和rpm -qa | grep kernel-devel对比版本号,然后通过本地镜像源或离线 rpm 包安装完全一致的kernel-devel。装完后确认/usr/src/kernels/$(uname -r)目录存在再回去编译。

5.2 模块加载失败:invalid module format

现象:modprobe hgu报Error: could not insert module: Invalid module format。

原因:内核编译环境变了,比如系统内核小版本从 6.1.76 升级到 6.1.80,但你用的驱动还是旧源码编译出来的.ko。新内核拒绝加载vermagic不匹配的模块。

解决:切换内核后必须重新make clean && make && make install,然后depmod -a。如果机器上保留了多版本内核,务必在编译前确认/lib/modules/$(uname -r)/build软链接指向正确的头文件目录。

5.3 网卡灯亮但 IP 起不来

现象:ethtool eth0显示Link detected: yes,但配置了静态 IP 之后ping不通网关。

原因:多半是 NetworkManager 和 network 服务重复管理同一块网卡,配置冲突;也可能是网卡的ONBOOT参数没改成yes。还有一种情况是网卡设备名和配置文件不一致,比如系统识别成ens3,但配置文件写的是eth0。

解决:先ip a看系统实际分配给网卡的设备名,然后编辑对应的/etc/sysconfig/network-scripts/ifcfg-*文件,把ONBOOT设为yes,并注释掉 NetworkManager 对这个接口的管理权限。如果是双服务并存的环境,干脆systemctl disable NetworkManager,只用 network 服务。

5.4 重启后驱动丢失

现象:配置全部完成后重启,ip a里又只剩下lo,网卡消失。

原因:忘执行第 2.4 节的dracut -f --add-drivers hgu。驱动模块装上了,modprobe也能手动加载,但 initramfs 里没有打包驱动,导致内核在挂载根文件系统前找不到模块。

解决:重建 initramfs 并加入驱动,命令是dracut -f --add-drivers hgu。如果你用的是 Debian/Ubuntu 系,对应执行update-initramfs -u -k all。重启前先跑一遍验证恢复步骤,别等重启完再后悔。

5.5 高负载下网卡丢包或断流

现象:并发连接上来后,dmesg刷出NETDEV WATCHDOG: CPU stuck for X seconds,网卡间歇性假死。

原因:多半是中断亲和配置缺失,所有中断压在单个 CPU 上,软中断处理不过来;另一原因是收发队列数没有按 CPU 核数配置,默认队列太少导致环形缓冲区溢出。

解决:参考 4.2 节把中断绑定到多个 CPU 上,同时用ethtool -G eth0 rx 4096 tx 4096把环形缓冲区加大。改完后跑一轮iperf3 -P 8压测,如果dmesg里不再出现 watchdog 报错,说明问题解决。

6. 把驱动打进装机镜像:离线环境的一次性交付

如果你手头不是一台机器,而是一整批同型号服务器,逐台编译安装驱动的方式就太低效了。把驱动直接打进制好的装机镜像,新机器装完系统网卡就能用,这才是批量交付的正确姿势。

6.1 用 dracut 把驱动预先打进 initramfs

在构建机上安装好驱动后,可以生成一个专用的 initramfs 文件:

dracut -f --add-drivers hgu /boot/initramfs-$(uname -r)-hgu.img $(uname -r)

这一步生成独立命名的 initramfs 镜像文件,不影响系统原有的 initramfs。装机时把生成的.img文件放到装机服务器的boot分区,并把引导配置指向它,新机器启动时内核就会提前加载hgu驱动。

6.2 把驱动打成 rpm 实现批量安装

更体系化的做法是把编译好的驱动模块和配置打包成 rpm 包,交付时一条命令装完:

# 用 rpmbuild 打一个包含 .ko 和 modprobe.conf 的简单 rpm rpmbuild -bb /tmp/hgu-driver.spec

spec 文件的核心段定义要包含的文件列表:/lib/modules/$(uname -r)/extra/hgu.ko、/etc/modprobe.d/hgu.conf。%post脚本段执行depmod -a,%postun段做反向清理工作,确保卸载时不留残留。

6.3 从那以后养成的习惯

第一次在没网环境里折腾这个驱动,我在编译、加载、重启三个环节各翻了一次车,前后折腾到夜里两点。从那以后,我每次在新环境装机,都会强制自己走一遍三行确认:uname -r、rpm -qa | grep kernel-devel、ls -d /usr/src/kernels/$(uname -r),三个输出对齐了才动make。事实证明这个习惯帮我省掉了很多无意义的报错排查时间。如果你也要在内网环境批量交付,建议按 6.2 的方式提前把驱动包打好,别到现场再一台台编译。希望这份笔记能帮到你。

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

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

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

立即咨询