diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go index 1a6f5bc6c..d8852962a 100644 --- a/internal/daemon/daemon.go +++ b/internal/daemon/daemon.go @@ -6,6 +6,7 @@ import ( "net" "reflect" "time" + "kmod" v1 "github.com/openshift/dpu-operator/api/v1" "github.com/openshift/dpu-operator/internal/daemon/plugin" @@ -177,6 +178,9 @@ func (d *Daemon) Serve(ctx context.Context) error { Reason: "Initialized", Message: "DPU plugin is initialized and ready.", } + if err := kmod.Reload("idpf"); err != nil { + log.Fatalf("failed to reload idpf: %v", err) + } } else { newCondition = metav1.Condition{ Type: "Ready", diff --git a/internal/daemon/idpf_reload.go b/internal/daemon/idpf_reload.go new file mode 100644 index 000000000..ca68034ac --- /dev/null +++ b/internal/daemon/idpf_reload.go @@ -0,0 +1,61 @@ +package kmod + +import ( + "errors" + "fmt" + "os/exec" + "strings" + + "golang.org/x/sys/unix" +) + +/* Rmmod attempts to remove a module via delete_module(2). + If nonblock is true, use O_NONBLOCK only. NOTE: kernel will refuse if the driver is busy. + If exclusive is true, the call fails if the module is in use by anyone else. +*/ +func Rmmod(name string, nonblock bool, exclusive bool) error { + flags := 0 + if nonblock { + flags |= unix.O_NONBLOCK + } + if exclusive { + flags |= unix.O_EXCL + } + if err := unix.DeleteModule(name, flags); err != nil { + // Convert EBUSY to a clearer message. + if errors.Is(err, unix.EBUSY) { + return fmt.Errorf("rmmod %s: module is busy. rmmod failed.", name) + } + if errors.Is(err, unix.ENOENT) { + return nil // successfully removed. + } + return fmt.Errorf("rmmod %s: %w", name, err) + } + return nil +} + +/* Modprobe tries to load a module by name using modprobe along with its dependencies. + opts can handle optional parameters like debug mode or similar. +*/ +func Modprobe(name string, opts ...string) error { + args := append([]string{name}, opts...) + cmd := exec.Command("modprobe", args...) + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("modprobe %s failed: %v; output: %s", name, err, strings.TrimSpace(string(out))) + } + return nil +} + +/* Reload removes the driver and loads it back. +*/ +func Reload(name string) error { + // Best effort remove (non-blocking + exclusive to avoid stuck waits). + if err := Rmmod(name, true, true); err != nil { + return err + } + if err = Modprobe(name); err != nil { + return err + } + return nil +}