From ffc0ed6a7cb2f00a6022aca00f725cb634bc7373 Mon Sep 17 00:00:00 2001 From: Rolf Neugebauer Date: Wed, 3 May 2017 11:23:12 +0100 Subject: [PATCH 1/3] kernel: Fix kernel header build Add more files to 'kernel-dev.tar' to enable building kernel modules against the kernel. Signed-off-by: Rolf Neugebauer --- kernel/Dockerfile | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/kernel/Dockerfile b/kernel/Dockerfile index 7cbf93542..da1051f27 100644 --- a/kernel/Dockerfile +++ b/kernel/Dockerfile @@ -53,9 +53,13 @@ RUN DVER=$(basename $(find /tmp/kernel-modules/lib/modules/ -mindepth 1 -maxdept dir=/tmp/usr/src/linux-headers-$DVER && \ mkdir -p $dir && \ cp /linux/.config $dir && \ - cd /linux && \ - cp -a include "$dir" && \ - mkdir -p "$dir"/arch/x86 && cp -a arch/x86/include "$dir"/arch/x86/ && \ + cp /linux/Module.symvers $dir && \ + find . -path './include/*' -prune -o \ + -path './arch/*/include' -prune -o \ + -path './scripts/*' -prune -o \ + -type f \( -name 'Makefile*' -o -name 'Kconfig*' -o -name 'Kbuild*' -o \ + -name '*.lds' -o -name '*.pl' -o -name '*.sh' \) | \ + tar cf - -T - | (cd $dir; tar xf -) && \ ( cd /tmp && tar cf /out/kernel-dev.tar usr/src ) RUN printf "KERNEL_SOURCE=${KERNEL_SOURCE}\n" > /out/kernel-source-info From 6cfadcd26e64d335193365e0b167707d7d3e9bac Mon Sep 17 00:00:00 2001 From: Rolf Neugebauer Date: Wed, 3 May 2017 12:09:30 +0100 Subject: [PATCH 2/3] test: Add a simple test/example for compiling a kernel module The test is currently not hooked up, but it pulls the latest 4.9.x kernel image, builds a simple kernel module against it and then creates a test package containing the kernel module and a shell script. The shell script prints out the 'modinfo' and then tries to 'insmod' the module. It checks the output of 'dmesg' of the load succeeded. Signed-off-by: Rolf Neugebauer --- test/kmod/Dockerfile | 21 +++++++++++++++++++++ test/kmod/check.sh | 15 +++++++++++++++ test/kmod/kmod.yml | 17 +++++++++++++++++ test/kmod/run_test.sh | 10 ++++++++++ test/kmod/src/Makefile | 6 ++++++ test/kmod/src/hello_world.c | 22 ++++++++++++++++++++++ 6 files changed, 91 insertions(+) create mode 100644 test/kmod/Dockerfile create mode 100755 test/kmod/check.sh create mode 100644 test/kmod/kmod.yml create mode 100755 test/kmod/run_test.sh create mode 100644 test/kmod/src/Makefile create mode 100644 test/kmod/src/hello_world.c diff --git a/test/kmod/Dockerfile b/test/kmod/Dockerfile new file mode 100644 index 000000000..7b45e112a --- /dev/null +++ b/test/kmod/Dockerfile @@ -0,0 +1,21 @@ +# This Dockerfile extracts the kernel headers from the kernel image +# and then compiles a simple hello world kernel module against them. +# In the last stage, it creates a package, which can be used for +# testing. + +FROM linuxkit/kernel:4.9.x AS ksrc + +# Extract headers and compile module +FROM linuxkit/kernel-compile:1b396c221af673757703258159ddc8539843b02b@sha256:6b32d205bfc6407568324337b707d195d027328dbfec554428ea93e7b0a8299b AS build +COPY --from=ksrc /kernel-dev.tar / +RUN tar xf kernel-dev.tar + +WORKDIR /kmod +COPY ./src/* ./ +RUN make all + +# Package +FROM alpine:3.5 +COPY --from=build /kmod/hello_world.ko / +COPY check.sh /check.sh +ENTRYPOINT ["/bin/sh", "/check.sh"] diff --git a/test/kmod/check.sh b/test/kmod/check.sh new file mode 100755 index 000000000..02e491624 --- /dev/null +++ b/test/kmod/check.sh @@ -0,0 +1,15 @@ +#!/bin/sh +function failed { + printf "Kernel module test suite FAILED\n" + /sbin/poweroff -f +} + +uname -a +modinfo hello_world.ko || failed +insmod hello_world.ko || failed +[ -n "$(dmesg | grep -o 'Hello LinuxKit')" ] || failed +rmmod hello_world || failed + +printf "Kernel module test suite PASSED\n" + +/sbin/poweroff -f diff --git a/test/kmod/kmod.yml b/test/kmod/kmod.yml new file mode 100644 index 000000000..ff554c1e5 --- /dev/null +++ b/test/kmod/kmod.yml @@ -0,0 +1,17 @@ +kernel: + image: "linuxkit/kernel:4.9.x" + cmdline: "console=ttyS0" +init: + - linuxkit/init:63eed9ca7a09d2ce4c0c5e7238ac005fa44f564b + - linuxkit/runc:b0fb122e10dbb7e4e45115177a61a3f8d68c19a9 + - linuxkit/containerd:18eaf72f3f4f9a9f29ca1951f66df701f873060b +onboot: + - name: check + image: "kmod-test" + binds: + - /dev:/dev + - /lib/modules:/lib/modules + capabilities: + - all +outputs: + - format: kernel+initrd diff --git a/test/kmod/run_test.sh b/test/kmod/run_test.sh new file mode 100755 index 000000000..f0ffe7f27 --- /dev/null +++ b/test/kmod/run_test.sh @@ -0,0 +1,10 @@ +#! /bin/sh + +# Make sure we have the latest kernel image +docker pull linuxkit/kernel:4.9.x +# Build a package +docker build -t kmod-test . +# Build a LinuxKit image with kernel module (and test script) +moby build kmod +# Run it +linuxkit run kmod diff --git a/test/kmod/src/Makefile b/test/kmod/src/Makefile new file mode 100644 index 000000000..31c8215dd --- /dev/null +++ b/test/kmod/src/Makefile @@ -0,0 +1,6 @@ +obj-m += hello_world.o +KVER=$(shell basename /usr/src/linux-headers-*) +all: + make -C /usr/src/$(KVER) M=$(PWD) modules +clean: + make -C /usr/src/$(KVER) M=$(PWD) clean diff --git a/test/kmod/src/hello_world.c b/test/kmod/src/hello_world.c new file mode 100644 index 000000000..7dd6d3ee2 --- /dev/null +++ b/test/kmod/src/hello_world.c @@ -0,0 +1,22 @@ +/* + * A simple Hello World kernel module + */ +#include +#include + +int init_hello(void) +{ + printk(KERN_INFO "Hello LinuxKit\n"); + return 0; +} + +void exit_hello(void) +{ + printk(KERN_INFO "Goodbye LinuxKit.\n"); +} + +module_init(init_hello); +module_exit(exit_hello); +MODULE_AUTHOR("Rolf Neugebauer "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("A simple Hello World kernel module for testing"); From c9c0c164909ad26217ece4379b0448c241cb69b6 Mon Sep 17 00:00:00 2001 From: Rolf Neugebauer Date: Wed, 3 May 2017 16:43:28 +0100 Subject: [PATCH 3/3] docs: Add a section on how to compile kernel modules Signed-off-by: Rolf Neugebauer --- docs/kernels.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/kernels.md b/docs/kernels.md index 5adf7500d..c7376abef 100644 --- a/docs/kernels.md +++ b/docs/kernels.md @@ -36,6 +36,35 @@ In summary, LinuxKit offers a choice of the following kernels: - [linuxkit/kernel-fedora](https://hub.docker.com/r/linuxkit/kernel-fedora/): Selected Fedora kernels. +## Compiling kernel modules + +The LinuxKit kernel packages include `kernel-dev.tar` which contains +the headers and other files required to compile kernel modules against +the specific version of the kernel. Currently, the headers are not +included in the initial RAM disk, but it is possible to compile custom +modules offline and include then include the modules in the initial +RAM disk. + +There is a [example](../tests/kmod), but basically one can use a +multi-stage build to compile the kernel modules: +``` +FROM linuxkit/kernel:4.9.x AS ksrc +# Extract headers and compile module +FROM linuxkit/kernel-compile:1b396c221af673757703258159ddc8539843b02b@sha256:6b32d205bfc6407568324337b707d195d027328dbfec554428ea93e7b0a8299b AS build +COPY --from=ksrc /kernel-dev.tar / +RUN tar xf kernel-dev.tar + +# copy module source code and compile +``` + +To use the kernel module, we recommend adding a final stage to the +Dockerfile above, which copies the kernel module from the `build` +stage and performs a `insmod` as the entry point. You can add this +package to the `onboot` section in your YAML +file. [kmod.yml](../tests/kmod/kmod.yml) contains an example for the +configuration. + + ## Working with Linux kernel patches for LinuxKit We may apply patches to the Linux kernel used in LinuxKit, primarily to