使用 DKMS 管理内核模块
引言
在《VPN 新宠 WireGuard 搭建》一文中提到,Ubuntu 系统上安装 WireGuard 使用如下命令:
$ sudo add-apt-repository ppa:wireguard/wireguard
$ sudo apt-get update
$ sudo apt-get install wireguard
实际上安装的一共有三个包:wireguard
、wireguard-dkms
和 wireguard-tools
,其中的 wireguard-dkms
即用于 DKMS。
DKMS(Dynamic Kernel Module Support)是由 Dell 公司开发的一套内核模块管理框架,被大多数 Linux 发行版采用。 DKMS 在内核源码树之外做了个拷贝,每当内核更新时可自动重新编译内核模块,对于多个不同的内核版本、模块版本的管理非常便利。
在 WireGuard 正式并入 Linux 内核主线之前,使用 DKMS 管理模块代码是最理想的选择。本文通过以 DKMS 方式从源码编译、安装 WireGuard,简单介绍 DKMS 的使用方法。
准备工作
前几步与 WireGuard 官网安装页面的说明相同:
安装工具链
安装编译 WireGuard 需要的工具链和信赖包:
$ sudo apt-get install libmnl-dev libelf-dev linux-headers-$(uname -r) build-essential pkg-config
除此之外,还需要安装 dkms
包:
$ sudo apt-get install dkms
下载源码
克隆最新的 WireGuard 源码库到 /home/yestyle/code
目录:
$ cd /home/yestyle/code
$ git clone https://git.zx2c4.com/WireGuard
满足 DKMS 要求
使用 DKMS 管理内核模块,需要满足两个要求:
- 将源码放在
/usr/src/<module_name>-<module_version>
目录下; - 在源码根目录下存在合法的
dkms.conf
配置文件。
第二点要求已在源码 WireGuard/src
目录下提供。对于第一点要求,WireGuard/src/Makefile
中的 dkms-install
目标可用于此目的:
$ cd WireGuard/src
$ sudo make dkms-install
此命令将使用源码版本信息更新 version.h
和 dkms.conf
,同时将更新后的源码目录拷贝到 /usr/src/wireguard
中。更新之后的 dkms.conf
类似这样:
PACKAGE_NAME="wireguard"
PACKAGE_VERSION="0.0.20181115-1-gab873cd"
AUTOINSTALL=yes
BUILT_MODULE_NAME="wireguard"
DEST_MODULE_LOCATION="/kernel/net"
# requires kernel 3.10 or greater:
BUILD_EXCLUSIVE_KERNEL="^(([^1230]\.)|(3\.1[0-9]))"
注意其中的 PACKAGE_VERSION
的值,在后面会使用到。
另外,由 WireGuard/src/Makefile
可知,更新 dkms.conf
文件的内容时,会使用 git update-index --assume-unchanged dkms.conf
更新 dkms.conf
文件的 Git 索引,因此 git status
看不到 dkms.conf
有修改,version.h
类似。
之后,DKMS 就可以派上用场啦。
玩转 DKMS
上述 make dkms-install
时生成的目录 /usr/src/wireguard
并不带版本号,因此使用 dkms add
时也不带版本号:
$ cd /usr/src
$ sudo dkms add wireguard
Creating symlink /var/lib/dkms/wireguard/0.0.20181115-1-gab873cd/source ->
/usr/src/wireguard-0.0.20181115-1-gab873cd
DKMS: add completed.
$ dkms status
wireguard, 0.0.20181115-1-gab873cd: added
DKMS 将读取 wireguard/dkms.conf
中的版本信息,并将源码再次拷贝到 /usr/src/wireguard-0.0.20181115-1-gab873cd
目录。
dkms build
用于编译特定版本的源码:
$ sudo dkms build wireguard/0.0.20181115-1-gab873cd
Kernel preparation unnecessary for this kernel. Skipping...
Building module:
cleaning build area...
make -j4 KERNELRELEASE=4.18.0-10-generic -C /lib/modules/4.18.0-10-generic/build M=/var/lib/dkms/wireguard/0.0.20181115-1-gab873cd/build......
cleaning build area...
DKMS: build completed.
$ dkms status
wireguard, 0.0.20181115-1-gab873cd, 4.18.0-10-generic, x86_64: built
安装则使用 dkms install
命令:
$ sudo dkms install wireguard/0.0.20181115-1-gab873cd
wireguard:
Running module version sanity check.
- Original module
- No original module exists within this kernel
- Installation
- Installing to /lib/modules/4.18.0-10-generic/updates/dkms/
depmod...
DKMS: install completed.
$ dkms status
wireguard, 0.0.20181115-1-gab873cd, 4.18.0-10-generic, x86_64: installed
此后可使用 locate
命令看到 wireguard.ko
拷贝到了两个目录下:
$ sudo updatedb
$ locate wireguard.ko
/lib/modules/4.18.0-10-generic/updates/dkms/wireguard.ko
/var/lib/dkms/wireguard/0.0.20181115-1-gab873cd/4.18.0-10-generic/x86_64/module/wireguard.ko
之所以有两个拷贝,是因为所有 dkms build
的版本都会拷贝到对应的 /var/lib/dkms/<module_name>/<module_version>/<kernel_version>/<arch>/module/
目录下,而只有 dkms install
的版本会拷贝到当前运行内核对应的 /lib/modules/<kernel_version>/updates/dkms/
目录。
假如此时 WireGuard 源码更新了,使用 git pull
获取到最新代码后,重复上述 DKMS 的各个步骤(省略部分命令输出):
$ cd /home/yestyle/code/WireGuard/src
$ git pull
$ sudo make dkms-install
$ cd /usr/src/
$ sudo dkms add wireguard
$ dkms status
wireguard, 0.0.20181115-1-gab873cd, 4.18.0-10-generic, x86_64: installed
wireguard, 0.0.20181115-5-ge2b2f34: added
$ sudo dkms build wireguard/0.0.20181115-5-ge2b2f34
$ sudo dkms install wireguard/0.0.20181115-5-ge2b2f34
$ dkms status
wireguard, 0.0.20181115-1-gab873cd, 4.18.0-10-generic, x86_64: built
wireguard, 0.0.20181115-5-ge2b2f34, 4.18.0-10-generic, x86_64: installed
最后一步执行 dkms status
中看到之前版本的状态回退到 built,而最新安装的版本状态变为 installed。
将已安装的新版本模块使用 dkms uninstall
卸载:
$ sudo dkms uninstall wireguard/0.0.20181115-5-ge2b2f34
$ dkms status
wireguard, 0.0.20181115-1-gab873cd, 4.18.0-10-generic, x86_64: built
wireguard, 0.0.20181115-5-ge2b2f34, 4.18.0-10-generic, x86_64: built
不再需要的旧版本模块可使用 dkms remove
移除:
$ sudo dkms remove wireguard/0.0.20181115-1-gab873cd --all
$ dkms status
wireguard, 0.0.20181115-5-ge2b2f34, 4.18.0-10-generic, x86_64: built
另有 mkrpm
、mkdeb
等命令可用于制作对应的软件包。例如:
$ sudo dkms mkdeb wireguard/0.0.20181115-5-ge2b2f34
...
DKMS: mkdeb completed.
Moving built files to /var/lib/dkms/wireguard/0.0.20181115-5-ge2b2f34/deb...
Cleaning up temporary files...
$ ls -l /var/lib/dkms/wireguard/0.0.20181115-5-ge2b2f34/deb
total 352
-rw-r--r-- 1 root root 356380 Nov 16 15:02 wireguard-dkms_0.0.20181115-5-ge2b2f34_amd64.deb
需要特别说明的是,DKMS 仅可用于内核模块代码的管理,WireGuard 使用的 wg
和 wg-quick
属于用户态的工具(wireguard-tools
包的内容),可使用如下命令编译安装:
$ cd /home/yestyle/code/WireGuard/src/tools/
$ make
$ sudo make install
以上。