Automatically installing Linux kernel modules with the DKMS framework is a convenient way of distributing drivers that are maintained outside of the official kernel. However, while DKMS is included in many popular Linux distributions and supports most kernel modules, it can’t always guarantee proper installation of a third-party module.
In this article, we discuss the pros and cons of using DKMS and explain in which cases it’s not the best solution for Linux driver installation. This article will be useful for driver developers who are debating whether to use DKMS to distribute their software.
What is DKMS?
What is DKMS? Dynamic Kernel Module Support (DKMS) is a framework developed by Dell to automatically distribute kernel module updates to its customers. It simplifies both driver development and system administration, increasing overall system stability.
This framework allows developers to provide users with drivers that aren’t included in the official kernel release. DKMS also significantly increases the quality of module source code, as developers can test their drivers simultaneously on numerous machines.
DKMS also has advantages for system administrators, as it automatically installs device driver updates to the existing version of the kernel without introducing any changes to the kernel. So system administrators no longer have to wait for a new kernel version to be released.
Keep in mind that DKMS is not the only solution for installing kernel modules. There are also DKMS alternatives such as:
- AKMOD, a Fedora solution which relies on tools including GNU Compiler Collection and auto-make
- module-assistant (often abbreviated as m-a), a tool for manually compiling kernel modules
DKMS and AKMOD are similar, as they both rebuild modules for new kernel installation, while m-a requires manual execution and can build modules only for a currently running kernel. But this can be inconvenient, for example when installing a graphics driver.
Understanding the DKMS lifecycle
Let’s look closer at how DKMS works. DKMS duplicates the module tree outside of the kernel tree. This module tree includes module source code and its compiled binaries. When a new Linux kernel or driver version is released, DKMS uses a standardized approach to collect and build its source code.
Specifically, DKMS is a universal tool that can build driver code into loadable compiled module binary files, then install and uninstall those modules on any Linux kernel.
In addition, the framework provides special features for managing and maintaining modules across multiple systems, showing which module version is installed on which kernel version.
When considering whether to use DKMS, it’s necessary to understand its module lifecycle. Here is the flow of DKMS and its main commands for executing and managing a kernel module.
As you can see, there’s a special set of commands for performing the main actions with Linux drivers.
You can see the current status of modules by running:
This command shows the name, version, and state of each kernel module. Using this command, you can quickly understand if a device driver has been updated.
To add a module and its version to the existing DKMS tree, run the following:
dkms add [-m MODULE_NAME] [-v VERSION] [/path/to/module-src/]
If -m or -v options are omitted, DKMS will look up
/usr/src/module-module-version for sources as well as the dkms.conf file, or copy the passed
After the module is placed in the tree, you can build the module using the build command:
dkms build -m MODULE -v VERSION -k $(uname -r)
This command allows developers and system administrators to compile a previously added module for the current kernel. It also lets developers check a driver for bugs during development. After this, your module will be compiled but not installed.
If you want to copy compiled modules to the kernel tree, use the install command:
dkms install -m MODULE -v VERSION -k $(uname -r)
If there are two modules with the same name, the previously installed module will be backed up in
/var/dkms/MODULE/original-module directory. It will be saved as an original module so it can be restored if the newer module is uninstalled.
There are two commands for deleting a module from the DKMS tree:
uninstall command will delete the installed module and, if possible, replace it with a backup copy:
dkms uninstall -m MODULE -v VERSION -k $(uname –r)
remove the module from the kernel tree for the passed -k kernel version and architecture, run:
dkms remove -m MODULE -v VERSION -k $(uname -r)
If you want to remove a module from all installed kernels, add
dkms remove -m MODULE -v VERSION –all
The difference between the remove and uninstall commands is that
uninstall only deletes a module from the kernel tree, leaving the module in the
built state, while
remove also checks if other instances of the module exist for other kernels and, if there are none, cleans up the DKMS tree. After the tree is cleaned, the Linux user must add the module again to use it with DKMS.
Other noteworthy commands are match and auto-installer. The
match command is useful when you need to use one module for several kernels. In this case,
match uses the configuration from the module installed on one kernel and applies it to another.
Auto-installer checks if the configuration file contains the AUTOINSTALL parameter and, if it does, DKMS will rebuild and install the module for this kernel when booting on a new kernel.
To use DKMS, you should provide a
dkms.conf file like this one:
The use of DKMS depends on the form in which a Linux driver is provided to its users. Below, we’ll explain why.
Main forms of Linux driver distribution
Linux driver developers can distribute their software in the following forms:
- As a precompiled kernel module
In this case, Linux users don’t have to worry about requirements for building the driver. Precompiled modules are released with the Linux kernel and require support for different flavors of Linux and different configuration options. However, it can take some time between the release of a new kernel and the release of the necessary version of a module.
- As full-module source code
With full-module source code, a user can build a driver on their own. But this method relies on an installed compiler, additional build tools, and the appropriate kernel header files.
- As a kernel module with closed-source binary parts and source code for a kernel interface layer
This type of kernel module is often used as a workaround for license infringement or distributions such as Free/Net BSD (Berkeley Software Distribution) and some Linux distributions in which combined binary firmware is accepted along with open-source interface parts.
DKMS expects that kernel modules will be supplied with open-source code, but sometimes drivers come with closed-source binary parts (like NVIDIA video drivers). In this case, the main part of the driver includes a closed-source binary linked object, also called a binary blob, and the source code for the kernel interface layer. The kernel interface, compiled as a general module, must be linked with the closed-source parts and must be compiled specifically for each kernel.
Building modules from source code usually requires a kernel-headers package, a compiler (like the GNU Compiler Collection), and a linker (usually
/usr/bin/ld from the binutils package). These components are necessary in case any changes are made to the closed-source part or just a module source code. In case any changes are made to the kernel application binary interface (ABI), such as changes to function signatures, the number of parameters, or their types, the correct kernel interface is required to support the interface code linked with the blob part.
DKMS benefits and limitations
Though DKMS is undoubtedly a useful tool for Linux kernel driver distribution, it has limitations that can make driver developers shy away from it. So let’s look closer at the pros and cons of DKMS.
Pros of using DKMS:
- It’s a convenient framework for building, installing, and removing various Linux kernel modules.
- It ensures that a Linux driver will be properly updated and installed in the right place.
- It allows you to manage installed modules and check their status.
- It lets you add a custom step, such as adding a customer driver digital signature via POST_BUILD and POST_INSTALL. This guarantees the safety of module installation.
- It supports the installation of deb and rpm packages out of the box.
- It’s available for many Linux distributions.
- Linux users can update their drivers immediately after they’re fixed. Therefore, they don’t need to wait for a new kernel version from the vendor.
- With this framework, it’s hard to forget to install the module for a newly installed kernel because all processes are automated.
Cons of using DKMS:
- Additional handling is required for resident modules.
- Source code for NVIDIA-like modules with blob parts aren’t convenient to deliver with DKMS, as they require source code for the kernel interface compiled for each kernel version.
- There’s a risk that a module won’t be built by DKMS if its function names have changed or if there are changes in the ways the kernel interacts with its components.
- DKMS doesn’t guarantee proper installation in case of changes to the kernel application binary interface, as kernel interface and module source support are still required.
Driver distribution without DKMS
In one of our Linux driver development projects, we were tasked with creating a driver that would be protected against module unloading and attempts to prevent its loading. Our client wanted to be sure of the module’s persistence and the boot sequence.
To achieve this goal, we decided to distribute the driver with precompiled modules. As our driver had closed-source binary parts, using DKMS wouldn’t have guaranteed proper installation.
However, the first issue that we faced was a wide range of Linux kernel versions and supported distributions. So we had to choose which to add our driver to.
Additionally, we encountered some issues while implementing our own system for module building and installation:
- Linux users may use different package managers, and the names of common build tools and kernel header packages can vary across distributions. So there’s a risk that our driver won’t be built properly.
- Some kernel versions don’t have available packages for kernel headers (for example, on Fedora) as they were taken out of public access.
- Some Linux kernels don’t support the PKCS7 digital signature algorithm, so we had to use the default signing mechanism instead.
- There’s an ambiguous and distribution-dependent approach for obtaining an installed kernel list, which confirms the presence of the kernel header package.
- We had issues with module building on some specific distributions/configurations. These issues can also appear in case of an automated build with DKMS or other similar tools.
Below, we provide some tips on how developers can verify the installation of their Linux module to the kernel without using DKMS.
When implementing a custom installer, a driver developer has to choose when and how their module should start, how to detect already installed modules, and how to verify if modules are signed properly.
These decisions should be made even if you decide to use modprobe for adding or removing your module from the Linux kernel.
If you’re considering using insmod for inserting your module into the kernel, you should take care to protect against blacklisting. However, in this case, you’ll need to implement the init system module from scratch.
In the cases of eager loading or a resident module, driver developers may choose run-level script instead of user-defined auto start scripts, which are typically used for software. With all the variety of initial Linux boot systems (INIT Sys-V scripts, upstart, systemd, and others), the best choice is to implement a custom init.d script and rely on installed utilities (such as update-rc.d or chkconfing) to handle per-runlevel links. Runlevel is the concept for operating systems with Sys-V style initialization describing which processes, daemons, and drivers should be loaded or started for each mode.
However, there’s no standard that defines the link location, structure, or even the complete list of such links. Also, the utilities mentioned above have different package versions across distributions with different functionality. For example, an earlier version of update-rc.d on Mint 17 allows specifying the boot priority, but the same utility on Mint 18 does not have this option, relying on module loading dependencies alone.
Thanks to continuous development by the Linux community, great tools such as DKMS appear. With DKMS, Linux users can automatically build and manage kernel modules without needing to wait for delivery of a new driver package. In addition, driver developers can verify the installation of their modules at the development stage. There is also a wide range of useful tools for Linux driver developers, so we’ll continue to share our experience on this topic. Linux driver development requires a comprehensive approach, and our team of driver developers is always at your disposal.