Bối cảnh & Lý do: Sống sót qua các đợt nâng cấp Kernel với Out-of-Tree Driver
Trong quá trình bảo trì định kỳ trên cụm 45 edge server của chúng tôi, các bản cập nhật bảo mật kernel nhỏ liên tục gây ra một sự cố phiền toái: hỏng các driver phần cứng out-of-tree. Hệ thống khởi động lại mà không nhận card mạng 2.5GbE Realtek hoặc các bộ tăng tốc FPGA chuyên dụng. Điều này khiến các kỹ sư trực on-call phải tất bật biên dịch lại mã nguồn thủ công với kernel header mới giữa đêm khuya.
Vấn đề này bắt nguồn trực tiếp từ cách Linux kernel xử lý các interface nội bộ. Không giống như Windows hay macOS, Linux chủ ý không duy trì một Application Binary Interface (ABI) nội bộ ổn định.
Khi các nhà phát triển kernel thay đổi cấu trúc dữ liệu nội bộ hoặc chữ ký hàm giữa các bản phát hành vá lỗi, các loadable kernel module (file .ko) được build cho kernel 5.15.0-80 sẽ không thể load trên 5.15.0-84. Nếu bạn đang chạy card RAID độc quyền, card mạng tùy chỉnh, ZFS hoặc driver VirtualBox, mã nguồn của bạn nằm ngoài upstream kernel tree và cần được biên dịch lại sau mỗi lần cập nhật kernel.
Dynamic Kernel Module Support (DKMS) tự động hóa toàn bộ quy trình này. Nó gắn trực tiếp vào trình quản lý gói của bản phân phối thông qua các post-install trigger. Bất cứ khi nào apt, dnf, hoặc pacman tải về kernel mới cùng các header tương ứng, DKMS sẽ tiếp quản. Nó lấy mã nguồn module từ /usr/src/<module>-<version>/, biên dịch nó với kernel header mới chỉ trong khoảng 15 đến 30 giây, và đặt file binary .ko mới vào cây module.
Kết hợp DKMS với modprobe—tiện ích chuẩn để giải quyết phụ thuộc và load driver—bạn sẽ loại bỏ hoàn toàn việc phải rebuild driver thủ công.
Cài đặt: Chuẩn bị môi trường Build
DKMS yêu cầu một toolchain trình biên dịch C hoạt động hoàn chỉnh và các kernel development header tương ứng với kernel đang hoạt động hoặc kernel đích.
1. Hệ thống Debian và Ubuntu
Cập nhật danh sách gói phần mềm và cài đặt các công cụ build, DKMS cùng kernel header hiện tại:
sudo apt update
sudo apt install -y build-essential dkms linux-headers-$(uname -r)
2. RHEL, Rocky Linux và AlmaLinux
Bật repository EPEL trước trên các bản phân phối doanh nghiệp dựa trên RPM, sau đó cài đặt các gói phát triển cần thiết:
sudo dnf install -y epel-release
sudo dnf install -y gcc make dkms kernel-devel-$(uname -r) kernel-headers
Kiểm tra xem symlink build có trỏ đến đúng thư mục header đã cài đặt hay không:
ls -ld /lib/modules/$(uname -r)/build
Nếu đường dẫn này trỏ tới một thư mục hợp lệ trong /usr/src/kernels/ hoặc /usr/src/linux-headers-*/, toolchain build của bạn đã sẵn sàng.
Cấu hình: Đăng ký Module và Tinh chỉnh modprobe
Để thiết lập một module tự động hóa hoàn chỉnh cần qua hai bước: viết file manifest dkms.conf và định nghĩa các quy tắc nạp runtime bằng modprobe.
Bước 1: Thiết lập mã nguồn DKMS và dkms.conf
DKMS tìm kiếm cây mã nguồn bên trong /usr/src/<module_name>-<module_version>/. File cấu hình có tên dkms.conf trong thư mục đó sẽ xác định các lệnh build và đường dẫn đích cho file binary.
Ví dụ: để đóng gói một driver mạng tùy chỉnh có tên custom_nic phiên bản 1.0.0, hãy tạo đường dẫn nguồn đích:
sudo mkdir -p /usr/src/custom_nic-1.0.0
Đặt các file nguồn C và Makefile vào thư mục đó, sau đó tạo file /usr/src/custom_nic-1.0.0/dkms.conf:
PACKAGE_NAME="custom_nic"
PACKAGE_VERSION="1.0.0"
CLEAN="make clean"
MAKE[0]="make -C /lib/modules/${kernelver}/build M=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build modules"
BUILT_MODULE_NAME[0]="custom_nic"
DEST_MODULE_LOCATION[0]="/updates/dkms"
AUTOINSTALL="yes"
Các chỉ thị quan trọng cần lưu ý:
AUTOINSTALL="yes": Hướng dẫn DKMS tự động rebuild module này bất cứ khi nào trình quản lý gói cài đặt một kernel mới.${kernelver}: Biến môi trường do DKMS truyền vào, chứa chuỗi phiên bản kernel đích (ví dụ:5.15.0-88-generic).DEST_MODULE_LOCATION[0]: Chỉ định vị trí cài đặt file binary.kođã biên dịch bên dưới/lib/modules/<kernel_version>/.
Bây giờ hãy đăng ký, biên dịch và cài đặt module bằng 3 lệnh nhanh sau:
sudo dkms add -m custom_nic -v 1.0.0
sudo dkms build -m custom_nic -v 1.0.0
sudo dkms install -m custom_nic -v 1.0.0
Bước 2: Cấu hình tự động nạp lâu dài và tùy chọn với modprobe
Sau khi DKMS chuyển file binary vào /lib/modules/$(uname -r)/updates/dkms/, hãy tạo lại bản đồ phụ thuộc module mới:
sudo depmod -a
Để tự động nạp module khi hệ thống khởi động, hãy đăng ký trong /etc/modules-load.d/:
echo "custom_nic" | sudo tee /etc/modules-load.d/custom_nic.conf
Nếu driver của bạn cần các tham số phần cứng cụ thể hoặc phải ghi đè một module xung đột, hãy cấu hình chúng trong /etc/modprobe.d/:
sudo tee /etc/modprobe.d/custom_nic.conf << 'EOF'
# Các tham số runtime cho custom_nic
options custom_nic debug=1 rx_buffer_size=4096
# Ngăn chặn driver xung đột in-tree nạp vào hệ thống
blacklist generic_legacy_nic
EOF
Trên các máy chủ Ubuntu 22.04 LTS của chúng tôi, quá trình tự động hóa này đã giảm thời gian downtime sau bảo trì kernel xuống bằng không. Các bản vá bảo mật chạy ngầm sẽ tự động rebuild và đăng ký driver ngay trong bước nâng cấp gói, trước khi bất kỳ thao tác reboot nào diễn ra.
Xác minh & Giám sát: Quản lý Vòng đời Driver
Sau khi cấu hình xong, hãy kiểm tra trạng thái module trên các kernel đã cài đặt và rà soát log trong /var/lib/dkms/.
1. Kiểm tra trạng thái đăng ký DKMS
Chạy lệnh dkms status để liệt kê mọi module đã đăng ký và trạng thái build của chúng trên toàn bộ kernel cục bộ:
dkms status
Một module được cài đặt chính xác sẽ hiển thị kết quả tương tự như sau:
custom_nic/1.0.0, 5.15.0-84-generic, x86_64: installed
custom_nic/1.0.0, 5.15.0-88-generic, x86_64: installed
Nếu trạng thái hiển thị là added hoặc built thay vì installed, file binary của driver vẫn chưa được sao chép vào thư mục module và modprobe sẽ không thể tìm thấy nó.
2. Xác minh và nạp Module với modprobe
Nạp module vào kernel đang hoạt động với chế độ hiển thị chi tiết (verbose):
sudo modprobe -v custom_nic
Kiểm tra thông tin chi tiết của module đã biên dịch, metadata tác giả và thông tin license:
modinfo custom_nic
Xác nhận kernel đã nạp module và kiểm tra dung lượng bộ nhớ đang sử dụng:
lsmod | grep custom_nic
Kiểm tra kernel ring buffer để xác nhận các tham số khởi tạo đã được tiếp nhận:
sudo dmesg | grep -i custom_nic
3. Thử nghiệm quy trình Gỡ bỏ và Dọn dẹp
Khi phát hành phiên bản 1.0.1 cho driver của bạn, hãy unload module đang hoạt động khỏi bộ nhớ và xóa các build artifact cũ của DKMS:
# Gỡ bỏ an toàn module đang chạy khỏi bộ nhớ
sudo modprobe -r custom_nic
# Hủy đăng ký phiên bản 1.0.0 khỏi tất cả các kernel đã cài đặt
sudo dkms remove -m custom_nic -v 1.0.0 --all
Nếu quá trình build bị lỗi khi nâng cấp kernel, hãy kiểm tra /var/lib/dkms/custom_nic/1.0.0/build/make.log. File log này sẽ chỉ rõ chính xác file header C, struct member hay lệnh gọi hàm bị deprecated nào đã gây ra lỗi biên dịch.

