1. Overview
Once a custom kernel module is compiled, it needs to be loaded to the kernel at run-time. The modprobe command is the preferred command for loading modules. However, just passing the module name to modprobe isn’t sufficient for adding a module to the kernel.
In this tutorial, we’ll discuss how to load custom modules using modprobe. We’ll first see an example of a custom module. Then, we’ll learn the steps for adding this module to the kernel.
2. Example Module
In this section, we’ll discuss the example module we use.
2.1. The Source Code of the Module
Our simple module’s code is in the C program, custom_module.c:
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
int custom_init_module(void)
{
return 0;
}
void custom_exit_module(void)
{
}
module_init(custom_init_module);
module_exit(custom_exit_module);
Let’s discuss the source code briefly.
The MODULE_LICENSE() macro sets the license of the module to GPL. Calling this macro is necessary for a successful build.
A kernel module must have at least two functions. One of them is for initialization, whereas the other one is for clean-up. The custom_init_module() and custom_exit_module() functions in our example are for initialization and clean-up, respectively. As we’re only interested in adding a module using modprobe, these functions are empty.
The module_init(custom_init_module) and module_exit(custom_exit_module) function calls at the end tell the kernel which functions are the initialization and clean-up functions, respectively.
2.2. Compilation of the Module
Let’s create a Makefile for building the module:
obj-m += custom_module.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
In our Makefile, obj-m is a special variable that specifies custom_module.o to be built as a kernel module.
The all rule is for building the module. The -C option of make specifies that we should build the module in the /lib/modules/$(shell uname -r)/build directory. The Makefile of the kernel build system resides in this directory. The uname -r command gives the kernel release.
The M=$(PWD) part of the all rule specifies the location of the Makefile of our module. In our case, it’s in the current directory. The modules directive, on the other hand, tells make to build the module.
The clean rule cleans the built module.
Let’s build the module using make:
$ ls
custom_module.c Makefile
$ make >& /dev/null
$ ls custom_module.ko
custom_module.ko
We direct the output of make to /dev/null to skip the details of the building process. The module file, custom_module.ko, is generated as the output of the build process, in addition to some other files. We’ll try to add this module file to the kernel in the next section.
2.3. Adding the Module
The modprobe command is used for adding modules to the kernel. We can also use it for removing modules from the kernel.
Having compiled our module, let’s add it to the kernel using modprobe:
$ sudo modprobe custom_module
modprobe: FATAL: Module custom_module not found in directory /lib/modules/5.14.0-22.el9.x86_64
Loading a module requires root privileges. So, we used the sudo command together with modprobe. We passed the module name as a parameter to modprobe.
However, we weren’t successful in loading our module, custom_module, as is apparent from the output. modprobe couldn’t find the module.
Another method for adding modules to the kernel is via the insmod command. Let’s try to load our module using insmod:
$ sudo insmod custom_module.ko
$ echo $?
0
There aren’t any error messages in the output of insmod. Additionally, the exit status returned by insmod is 0 according to the output of echo $?, which means success.
Let’s check if custom_module is loaded using the lsmod command:
$ lsmod | grep custom_module
custom_module 16384 0
The lsmod command shows the status of modules in the kernel. Since the list might be long, we filter its output using grep custom_module. As we can see from the output, we’re successful in adding the module to the kernel. 16384 in the output is the size of the module in bytes, whereas 0 in the output shows the usage. The value is 0 as there aren’t any programs using our module.
Although we can load a module using insmod, we would need to load it again when we reboot our system. It’s generally better to load a module using modprobe if we want our module to be automatically loaded during reboot. Additionally, modprobe can handle module dependencies.
3. Configuration of modprobe
When we tried to load our module using modprobe in the previous section, modprobe searched for the module in the /lib/modules/5.14.0-22.el9.x86_64 directory and, hence, couldn’t find it. That’s because modprobe looks for the modules in the /lib/modules/`uname -r` directory by default. The kernel release is 5.14.0-22.el9.x86_64 in our system:
$ uname -r
5.14.0-22.el9.x86_64
Therefore, we must copy custom_module.ko to the /lib/modules/`uname -r` directory. Copying to this directory requires root privileges:
$ sudo cp ./custom_module.ko /lib/modules/5.14.0-22.el9.x86_64
Additionally, we must call the depmod command. It also needs root privileges:
$ sudo depmod
The depmod command generates a list of module dependencies between the modules in the /lib/modules/`uname -r` directory. It writes the generated list to the /lib/modules/`uname -r`/modules.dep file.
Now, it’s time to add our module using modprobe:
$ sudo modprobe custom_module
$ echo $?
0
We didn’t get an error message this time. Additionally, the exit status returned by modprobe is 0.
Let’s check if custom_module is loaded using the lsmod command:
$ lsmod | grep custom_module
custom_module 16384 0
We were successful in adding our module using modprobe this time.
If we want to load our module automatically during boot, we must also add it to a configuration file in the /etc/modules-load.d directory. The systemd-modules-load service reads the kernel modules it loads during boot from configuration files in several directories, and /etc/modules-load.d is one of those directories. The configuration files must have the .conf extension.
Therefore, creating a configuration file, such as my_modules.conf, and adding the name of our module to this file are sufficient for automatic loading of our module during boot:
$ cat /etc/modules-load.d/my_modules.conf
custom_module
Now, our module will load at boot time.
4. Conclusion
In this article, we discussed how to load custom modules using modprobe. First, we saw a simple custom kernel module. We discussed briefly how to build the module.
Then, we learned the steps for configuring the custom module. Additionally, we saw how to load the module automatically during boot.