Lab Session 15
Lab Session 15
15.1 Introduction
Kernel modules are pieces of code that can be loaded and unloaded into the kernel upon
demand.
They extend the functionality of the kernel without the need to reboot the system. Custom
codes can be added to Linux kernels via two methods.
The basic way is to add the code to the kernel source tree and recompile the kernel.
A more efficient way is to do this is by adding code to the kernel while it is running. This
process is called loading the module, where module refers to the code that we want to add to
the kernel.
Since we are loading these codes at runtime and they are not part of the official Linux kernel,
these are called loadable kernel module (LKM), which is different from the “base kernel”. Base
kernel is located in /boot directory and is always loaded when we boot our machine whereas
LKMs are loaded after the base kernel is already loaded. Nonetheless, these LKM are very much
part of our kernel and they communicate with base kernel to complete their functions.
LKMs can perform a variety of task, but they come under three main categories,
A monolithic kernel, though faster than a microkernel, has the disadvantage of lack of
modularity and extensibility. On modern monolithic kernels, this has been solved by using
kernel modules. A kernel module (or loadable kernel mode) is an object file that contains
code that can extend the kernel functionality at runtime (it is loaded as needed); When a
kernel module is no longer needed, it can be unloaded. Most of the device drivers are used in
the form of kernel modules.
For the development of Linux device drivers, it is recommended to download the kernel
sources, configure and compile them and then install the compiled version on the test
/development tool machine.
Below is a very simple example of a kernel module. When loading into the kernel, it will
generate the message "Hi". When unloading the kernel module, the "Bye" message will be
generated.
Lab Session: 15 Kernel Modules
Example:
include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
MODULE_DESCRIPTION("My kernel module");
MODULE_AUTHOR("Me");
MODULE_LICENSE("GPL");
static int dummy_init(void)
{
printk("Hi\n");
return 0;
}
static void dummy_exit(void)
{
printk("By\n");
}
module_init(dum my_init);
module_exit(dummy_exit);
The generated messages will not be displayed on the console but will be saved in a
specially reserved memory area for this, from where they will be extracted by the logging daemon
(syslog). To display kernel messages, you can use the dmesg command or inspect the logs:
Compiling a kernel module differs from compiling an user program. First, other headers should be
used. Also, the module should not be linked to libraries. And, last but not least, the module must be
compiled with the same options as the kernel in which we load the module. For these reasons, there
is a standard compilation method (kbuild). This method requires the use of two files: a
Makefile and a Kbuild file.
Below is an example of a Makefile:
KDIR = /lib/modules/`uname –r`/build kbuild:
Lab Session: 15 Kernel Modules
make -C $(KDIR) M=`pwd`clean:
make -C $(KDIR) M=`pwd` clean
And the example of a Kbuild file used to compile a module:
EXTRA_CFLAGS = -Wall –g obj-m = modul.o
You can see, calling make on the Makefile file in the example shown will result in the make
invocation in the kernel source directory (/lib/modules/`uname -r`/build) and referring to the
current directory (M = `pwd`). This process ultimately leads to reading the Kbuild file from the
current directory and compiling the module as instructed in this file.
Note
For labs we will configure different KDIR, according to the virtual machine specifications:
KDIR = /home/student/so2/linux
[...]
A Kbuild file contains one or more directives for compiling a kernel module. The easiest
example of such a directive is obj-m = module.o. Following this directive, a kernel module (ko -
kernel object) will be created,
Starting from the module.o file. module.o will be created starting from module.c or module.S.
All of these files can be found in the Kbuild’s directory.
EXTRA_CFLAGS = -Wall -g
obj-m= supermodule.o
supermodule-y = module-a.o module-b.o
compile the module-a.c and module-b.c sources, resulting in module-a.o and module-
b.o objects module-a.o and module-b.o will then be linked in supermodule.o
from supermodule.o will be created supermodule.ko module
The suffix of targets in Kbuild determines how they are used, as follows:
which features are added to the kernel at build time. For example, when adding BTRFS support
with make menuconfig, add the line CONFIG_BTRFS_FS = y to the .config file. The BTRFS
kbuild contains the line obj-
$(CONFIG_BTRFS_FS):= btrfs.o, which becomes obj-y:= btrfs.o. This will compile the
btrfs.o object and
will be linked to the kernel. Before the variable was set, the line became obj:=btrfs.o and so it
was ignored, and the kernel was build without BTRFS support.
To load a kernel module, use the insmod utility. This utility receives as a parameter the path to
the *.ko file in which the module was compiled and linked. Unloading the module from the
kernel is done using the rmmod command, which receives the module name as a parameter.
$ insmod module.ko
$ rmmod module.ko
When loading the kernel module, the routine specified as a parameter of the module_init
macro will be
executed. Similarly, when the module is unloaded the routine specified as a parameter of the
module_exit will be executed.
Information about modules loaded into the kernel can be found using the lsmod command or by
inspecting the /proc/modules, /sys/module directories.
modul.mod.o modul.o
14.3 Debugging
Troubleshooting a kernel module is much more complicated than debugging a regular program.
First, a mistake in a kernel module can lead to blocking the entire system. Troubleshooting is
therefore much slowed down. To avoid reboot, it is recommended to use a virtual machine
(qemu, virtualbox, vmware).
When a module containing bugs is inserted into the kernel, it will eventually generate a kernel
oops. A kernel oops is an invalid operation detected by the kernel and can only be generated by
the kernel. For a stable kernel version, it almost certainly means that the module contains a bug.
After the oops appears, the kernel will continue to work.
Very important to the appearance of a kernel oops is saving the generated message. As noted
Lab Session: 15 Kernel Modules
above, messages generated by the kernel are saved in logs and can be displayed with
the dmesg command. To make sure that no kernel message is lost, it is recommended to
insert/test
the kernel directly from the console, or periodically check the kernel messages. Noteworthy is
that an oops can occur because of a programming error, but also a because of hardware error.
If a fatal error occurs, after which the system cannot return to a stable state, a kernel panic is
generated.
Look at the kernel module below that contains a bug that generates an oops:
/*
* Oops generating kernel
module */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
MODULE_DESCRIPTION (“Oops”);
MODULE_LICENSE (“GPL”);
MODULE_AUTHOR (“PSO”);
Minicom:
Minicom (or other equivalent utilities, eg picocom, screen) is a utility that can be used to connect
and interact with a serial port. The serial port is the basic method for analyzing kernel messages
or interacting with an embedded system in the development phase. There are two more common
ways to connect:
For the virtual machine used in the lab, the device that we need to use is displayed after the
virtual machine starts:
Minicom use:
Lab Session: 15 Kernel Modules
#for connecting via COM1 and using a speed of 115,200 characters per
second minicom –b 115200 –D /dev/ttyS0
You have been asked to enable connection tracking timeflow stamping in the Linux kernel of a
particular host. This change should take effect immediately, as well as persist upon reboot.
The kernel module to change is nf_conntrack, you need to modify the parameter that enables
time stamping.
Start by logging in to the lab servers using the credentials provided on the hands-on lab page:
ssh cloud_user@PUBLIC_IP_ADDRESS
sudo su -
modinfo nf_conntrack
cat /sys/module/nf_conntrack/parameters/tstamp
cat /sys/module/nf_conntrack/parameters/tstamp
LAB EXERCISE:
Q1.What is debugging?
b) Mod probe
nf_conntrack
tstamp=1
c) Sudo su