一 背景
現場Dell R740xd2機器使用網路卡Broadcom 57412 10Gb SFP+,韌體版本22.21.06.80。bnxt_en.ko核心模組是該網路卡的驅動,我們預設的驅動版本為1.8.0,而韌體版本22.21.06.80需要1.10.2的driver。
本文主要是記錄一些操作步驟,後續出現類似驅動過舊的問題可以快速解決。
二 臨時解決
- 現場透過下載Broadcom官方提供的tar包在生產節點上直接make編譯出新的bnxt_en.ko
- 替換/lib/modules/$(uname -r)/kernel/drivers/net/ethernet/broadcom/bnxt/bnxt_en.ko
- 透過
modprobe -r bnxt_en
和modprobe bnxt_en
重新載入新的模組,可以透過modinfo bnxt_en
檢視module的資訊 - 使用
depmod -a
更新module載入的依賴 - bnxt_en.ko是網路驅動,在核心init on initramfs 階段就需要載入,因此還要執行
update-initramfs -u
來更新initramfs image。
三 長久解決
3.1 backport核心程式碼(失敗)
- 1.10.2的驅動在linux核心6.1中才有支援,而我們的核心版本是4.14,嘗試直接cherry-pick,衝突過多失敗。
- 下載並解壓紅帽4.10核心的iso,替換broadcom/bnxt_en目錄下相關檔案進行編譯。這裡記錄下編譯方式,整體編譯核心速度過慢,我們可以在編譯環境編譯某一個modules:
- 複製/usr/src/$(uname -r)/Module.symvers到編譯的核心目錄drivers/net/ethernet/broadcom/bnxt/下面
- 執行
make modules SUBDIRS=drivers/net/ethernet/broadcom/bnxt
就可以編譯啦
結果同樣差距太多,很多改動涉及到公共檔案的介面,故放棄。
3.2 dkms(成功)
既然使用原始碼包可以直接在4.14核心環境上進行編譯,那使用dkms(Dynamic Kernel Module Support)來在需要的時候編譯安裝是一個不錯的選擇,而且bnxt_en體量小,編譯很快,安裝系統時不會佔用太多時間。
製作dkms的deb包
解壓netxtreme-bnxt_en-1.10.2-224.0.157.0.tar原始碼包,目錄結構如下:
drwxrwxr-x 4 18896 dialout 4096 Mar 29 11:59 ./
drwxr-xr-x 18 root root 4096 Mar 27 18:03 ../
lrwxrwxrwx 1 18896 dialout 27 Nov 3 04:25 bnxt_en -> bnxt_en-1.10.2-224.0.157.0//
drwxrwxr-x 5 18896 dialout 4096 Mar 30 10:01 bnxt_en-1.10.2-224.0.157.0/
lrwxrwxrwx 1 18896 dialout 20 Nov 3 04:25 bnxt_re -> bnxt_re-224.0.157.0//
drwxrwxr-x 2 18896 dialout 4096 Mar 27 19:08 bnxt_re-224.0.157.0/
-rw-r--r-- 1 root root 309 Mar 27 19:12 dkms.conf
-rw-rw-r-- 1 18896 dialout 537 Mar 27 17:18 Makefile
其中dkms.conf是我們建立並加入的,內容如下:
PACKAGE_NAME="netxtreme-bnxt_en"
PACKAGE_VERSION="1.10.2"
CLEAN="make clean"
MAKE="make"
BUILT_MODULE_NAME[0]="bnxt_en"
BUILT_MODULE_NAME[1]="bnxt_re"
BUILT_MODULE_LOCATION[0]="bnxt_en"
BUILT_MODULE_LOCATION[1]="bnxt_re"
DEST_MODULE_LOCATION[0]="/updates"
DEST_MODULE_LOCATION[1]="/updates"
AUTOINSTALL="yes"
根據dkms的要求,我們需要將原始碼包移到/usr/src目錄下,即當前原始碼包路徑/usr/src/netxtreme-bnxt_en-1.10.2
- PACKAGE_NAME:指定要編譯和安裝的模組的名稱
- PACKAGE_VERSION:模組版本
- CLEAN:刪除先前編譯生成的核心模組檔案和相關構建檔案
- MAKE:根據Makefile編譯
- BUILT_MODULE_NAME:模組名,也就是編譯出來的bnxt_en.ko
- BUILT_MODULE_LOCATION:存放的位置,這裡是/usr/src/netxtreme-bnxt_en-1.10.2/bnxt_en/
- DEST_MODULE_LOCATION:將模組放到核心目錄的哪個資料夾下,這裡是/lib/modules/$(uname -r)/updates
- AUTOINSTALL:安裝完畢後自動載入該模組
接下來就可以驗證dkms是否可以使用了,以下指令:
# 可以檢視當前的dkms模組的情況
dkms status
# 新增到dkms樹,此時是added狀態
dkms add -m netxtreme-bnxt_en -v 1.10.2
# 編譯,成功是built狀態
dkms build -m netxtreme-bnxt_en -v 1.10.2
# 安裝,成功是installed狀態
dkms install -m netxtreme-bnxt_en -v 1.10.2
# 其他指令
# 移除
dkms remove netxtreme-bnxt_en/1.10.2 --all
# 打包deb
dkms mkdeb netxtreme-bnxt_en/1.10.2
# 檢視module資訊
modinfo bnxt_en
# 重新生成module載入依賴關係
depmod -a
# 載入module
modprobe bnxt_en
# 移除module
modprobe -r bnxt_en
根據dkms status確定dkms安裝沒有問題,再透過modinfo確認module的資訊沒問題後,我們就可以將dkms模組打包成deb(ubuntu)了,指令dkms mkdeb netxtreme-bnxt_en/1.10.2
,我們可以得到一個名為netxtreme-bnxt-en-dkms_1.10.2_all.deb的deb,這樣就可以在安裝系統或升級階段進行安裝了。
其他問題
如果製作好的deb存在問題,需要在安裝前後做一些清理或載入的工作後才能工作。這個時候可以將netxtreme-bnxt-en-dkms_1.10.2_all.deb解開,具體操作如下:
# 建立工作目錄
mkdir -p extract/DEBIAN && mkdir build
# 提取deb控制檔案
dpkg -e netxtreme-bnxt-en-dkms_1.10.2_all.deb extract/DEBIAN
# 提取原始檔
dpkg -x netxtreme-bnxt-en-dkms_1.10.2_all.deb extract/
提取後extract目錄結構如下:
.
├── DEBIAN
│ ├── control
│ ├── md5sums
│ ├── postinst
│ └── prerm
└── usr
├── share
│ └── netxtreme-bnxt_en-dkms
│ ├── netxtreme-bnxt_en-1.10.2.dkms.tar.gz
│ └── postinst
└── src
我們透過DEBIAN內的檔案對deb安裝前或安裝後進行配置,常用的有preinst、postinst、prerm 和 postrm
- preinst 指令碼在軟體包被安裝之前執行,通常用來檢查一些先決條件或配置
- postinst 指令碼在軟體包安裝完成後執行,通常進行配置更新載入等操作
- prerm和postrm指令碼通常對軟體包解除安裝前後做停止服務,清除資訊等操作
製作好控制檔案後使用指令dpkg-deb -b extract/ build
在build目錄下重新生成netxtreme-bnxt-en-dkms_1.10.2_all.deb軟體包。