m/p/kmod: init
This adds a package for working with Linux kernel loadable modules in
Go. It contains syscall wrappers for loading and unloading modules, a
metadata format for fast lookup of modules handling devices using a
custom radix tree, parsers for module info metadata and various utility
functions and data structures.
A significant amount of the code in here has no formal spec and is
written against behavior and information extracted from the reference
kmod code as well as the Linux kernel itself.
Change-Id: I3d527f3631f4dd1832b9cfba2d50aeb03a2b88a8
Reviewed-on: https://review.monogon.dev/c/monogon/+/1789
Reviewed-by: Serge Bazanski <serge@monogon.tech>
Tested-by: Jenkins CI
diff --git a/metropolis/pkg/kmod/manager_test.go b/metropolis/pkg/kmod/manager_test.go
new file mode 100644
index 0000000..4f06d17
--- /dev/null
+++ b/metropolis/pkg/kmod/manager_test.go
@@ -0,0 +1,49 @@
+package kmod
+
+import (
+ "errors"
+ "os"
+ "testing"
+)
+
+func TestManagerIntegration(t *testing.T) {
+ if os.Getenv("IN_KTEST") != "true" {
+ t.Skip("Not in ktest")
+ }
+ t.Skip("Only works from the final CL in the stack as it has a dep on the new kernel config")
+ mgr, err := NewManagerFromPath("/lib/modules")
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Run("LoadExampleModule", func(t *testing.T) {
+ if err := mgr.LoadModule("r8169"); err != nil {
+ t.Error(err)
+ }
+ if _, err := os.Stat("/sys/module/r8169"); err != nil {
+ t.Error("module load returned success, but module not in sysfs")
+ }
+ })
+ t.Run("LoadNonexistentModule", func(t *testing.T) {
+ err := mgr.LoadModule("definitelynomodule")
+ var notFoundErr *ErrNotFound
+ if !errors.As(err, ¬FoundErr) {
+ t.Errorf("expected ErrNotFound, got %v", err)
+ }
+ })
+ t.Run("LoadModuleTwice", func(t *testing.T) {
+ if err := mgr.LoadModule("r8169"); err != nil {
+ t.Error(err)
+ }
+ })
+ // TODO(lorenz): Should test loading dependencies here, but we currently
+ // have none in the kernel config and I'm not about to build another kernel
+ // just for this.
+ t.Run("LoadDeviceModule", func(t *testing.T) {
+ if err := mgr.LoadModulesForDevice("pci:v00008086d00001591sv00001043sd000085F0bc02sc00i00"); err != nil {
+ t.Error(err)
+ }
+ if _, err := os.Stat("/sys/module/ice"); err != nil {
+ t.Error("module load returned success, but module not in sysfs")
+ }
+ })
+}