Note that all code showed in this article is licensed under GPL-2.0 and MPL-2.0.
Recently, I am interested in Linux kernel space and want to develop some simple kernel module. Although Rust for Linux is merging into the main line of Linux git repository, and will become available at Linux 6.1 release. I still want to let it be in C, and it’s more native and doesn’t need to pay attention to type conversion.
What we will do is create a custom char device and this device will send all written data to a remote cloud server in UDP protocol.
First, I assume you are running an Ubuntu or Debian distribution, other Linux flavors are also supported. But you should ensure Linux kernel header package is available. In my test, Debian in Windows Subsystem for Linux and Debian for Raspberry Pi is incapable. You may install the packages need by the following command:
|
|
And then let’s create the following file:
Makefile
|
|
chardev.h
|
|
repipe.c
|
|
There are about 160 lines of code, and the main logic is concentrated on repipe.c
. The first lines we defined the license, author name and description of this module using macro. And then there are two parameters it takes: the remote host and port. That’s fairly straight and simple, those macros are defined at include/linux/module.h. The third parameter of module_param
function is the permission of accordant file located at sysfs. In this example, you can find the parameter also available at /sys/module/repipe/parameters/remote_host
.
|
|
The repipe_init
function is called when loading the module, it will be responsible for creating the char device and initialize the socket. On Linux, devices have a major number and a minor number, here is a list for it. We use 0 as our major number, so Linux would assign one for us. That’s could avoid conflict.
|
|
Another important function is device_write
. When we write data into /dev/repipe
, device_open
is called first, and then is device_write
. device_open
ensure there is only one process is writing data. device_write
will copy data from user space to kernel space and send data. The struct msghdr
is used to describe the message to send, the most essential fields are msg_name
(remote address) and its length. And the kvec
struct is quite like iovec
but it’s for kernel space. Finally, we can send our data:
|
|
Here is a screenshot from a real machine.
By the way, seems that VM in Hyper-V has a very high UDP loss rate. Or it could not send UDP data gram at all. If you want to send data to other machines, don’t use Hyper-V VM. I tested on my VPS, it works fine.
That’s all for today. Thanks for reading. Hopefully, I will share more knowledge about Linux.