diff --git a/clab/config.go b/clab/config.go index e45f9e761..3fd2f482c 100644 --- a/clab/config.go +++ b/clab/config.go @@ -389,9 +389,11 @@ func (c *CLab) verifyLinks(ctx context.Context) error { } // LoadKernelModules loads containerlab-required kernel modules. -func (c *CLab) loadKernelModules() error { +func (*CLab) loadKernelModules() error { modules := []string{"ip_tables", "ip6_tables"} - + opts := []kmod.Option{ + kmod.SetInitFunc(utils.ModInitFunc), + } for _, m := range modules { isLoaded, err := utils.IsKernelModuleLoaded(m) if err != nil { @@ -406,7 +408,7 @@ func (c *CLab) loadKernelModules() error { log.Debugf("kernel module %q is not loaded. Trying to load", m) // trying to load the kernel modules. - km, err := kmod.New() + km, err := kmod.New(opts...) if err != nil { log.Warnf("Unable to init module loader: %v. Skipping...", err) diff --git a/go.mod b/go.mod index 8b638c49d..5a124e97f 100644 --- a/go.mod +++ b/go.mod @@ -237,7 +237,7 @@ require ( github.com/josharian/native v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/compress v1.17.9 github.com/klauspost/pgzip v1.2.6 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -275,7 +275,7 @@ require ( github.com/sylabs/sif/v2 v2.18.0 // indirect github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect github.com/ugorji/go/codec v1.2.12 // indirect - github.com/ulikunitz/xz v0.5.12 // indirect + github.com/ulikunitz/xz v0.5.12 github.com/vbatts/tar-split v0.11.5 // indirect github.com/vishvananda/netns v0.0.4 // indirect github.com/weaveworks/libgitops v0.0.0-20200611103311-2c871bbbbf0c // indirect diff --git a/utils/kernel_module.go b/utils/kernel_module.go index 93686ae85..a39e502f4 100644 --- a/utils/kernel_module.go +++ b/utils/kernel_module.go @@ -2,13 +2,19 @@ package utils import ( "bufio" + "compress/gzip" "fmt" + "io" "os" + "path/filepath" "regexp" "strconv" "strings" + "github.com/klauspost/compress/zstd" log "github.com/sirupsen/logrus" + "github.com/ulikunitz/xz" + "golang.org/x/sys/unix" ) // IsKernelModuleLoaded checks if a kernel module is loaded by parsing /proc/modules file. @@ -95,3 +101,61 @@ func (kv *KernelVersion) GreaterOrEqual(cmpKv *KernelVersion) bool { return true } + +// ModInitFunc supports uncompressed files and gzip and xz compressed files. +func ModInitFunc(path, params string, _ int) error { + f, err := os.Open(path) + if err != nil { + return err + } + defer f.Close() // skipcq: GO-S2307 + + switch filepath.Ext(path) { + case ".gz": + rd, err := gzip.NewReader(f) + if err != nil { + return err + } + defer rd.Close() + + return initModule(rd, params) + case ".xz": + rd, err := xz.NewReader(f) + if err != nil { + return err + } + + return initModule(rd, params) + case ".zst": + rd, err := zstd.NewReader(f) + if err != nil { + return err + } + defer rd.Close() + + return initModule(rd, params) + } + + // uncompressed file, first try finitModule then initModule + if err := finitModule(int(f.Fd()), params); err != nil { + if err == unix.ENOSYS { + return initModule(f, params) + } + } + + return nil +} + +// finitModule inserts a module file via syscall finit_module(2). +func finitModule(fd int, params string) error { + return unix.FinitModule(fd, params, 0) +} + +// initModule inserts a module via syscall init_module(2). +func initModule(rd io.Reader, params string) error { + buf, err := io.ReadAll(rd) + if err != nil { + return err + } + return unix.InitModule(buf, params) +}