使用 DKMS 管理内核模块

引言

在《VPN 新宠 WireGuard 搭建》一文中提到,Ubuntu 系统上安装 WireGuard 使用如下命令:

$ sudo add-apt-repository ppa:wireguard/wireguard
$ sudo apt-get update
$ sudo apt-get install wireguard

实际上安装的一共有三个包:wireguardwireguard-dkmswireguard-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.hdkms.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

另有 mkrpmmkdeb 等命令可用于制作对应的软件包。例如:

$ 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 使用的 wgwg-quick 属于用户态的工具(wireguard-tools 包的内容),可使用如下命令编译安装:

$ cd /home/yestyle/code/WireGuard/src/tools/
$ make
$ sudo make install

以上。

comments powered by Disqus