diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c5fd23f..751986b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ * Add option to create device nodes when creating `/dev/char` symlinks * Create ouput folders if required when running `nvidia-ctk runtime configure` * Generate default config as post-install step. +* Added support for detecting GSP firmware at custom paths when generating CDI specifications. * [libnvidia-container] Support OpenSSL 3 with the Encrypt/Decrypt library diff --git a/pkg/nvcdi/driver-nvml.go b/pkg/nvcdi/driver-nvml.go index 17456779..bc8171a3 100644 --- a/pkg/nvcdi/driver-nvml.go +++ b/pkg/nvcdi/driver-nvml.go @@ -18,6 +18,7 @@ package nvcdi import ( "fmt" + "os" "path/filepath" "strings" @@ -26,6 +27,7 @@ import ( "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup" "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/cuda" "gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml" + "golang.org/x/sys/unix" ) // NewDriverDiscoverer creates a discoverer for the libraries and binaries associated with a driver installation. @@ -55,7 +57,10 @@ func newDriverVersionDiscoverer(logger logger.Interface, driverRoot string, nvid return nil, fmt.Errorf("failed to create discoverer for IPC sockets: %v", err) } - firmwares := NewDriverFirmwareDiscoverer(logger, driverRoot, version) + firmwares, err := NewDriverFirmwareDiscoverer(logger, driverRoot, version) + if err != nil { + return nil, fmt.Errorf("failed to create discoverer for GSP firmware: %v", err) + } binaries := NewDriverBinariesDiscoverer(logger, driverRoot) @@ -96,18 +101,65 @@ func NewDriverLibraryDiscoverer(logger logger.Interface, driverRoot string, nvid return d, nil } +func getUTSRelease() (string, error) { + utsname := &unix.Utsname{} + if err := unix.Uname(utsname); err != nil { + return "", err + } + return unix.ByteSliceToString(utsname.Release[:]), nil +} + +func getFirmwareSearchPaths(logger logger.Interface) ([]string, error) { + + var firmwarePaths []string + if p := getCustomFirmwareClassPath(logger); p != "" { + logger.Debugf("using custom firmware class path: %s", p) + firmwarePaths = append(firmwarePaths, p) + } + + utsRelease, err := getUTSRelease() + if err != nil { + return nil, fmt.Errorf("failed to get UTS_RELEASE: %v", err) + } + + standardPaths := []string{ + filepath.Join("/lib/firmware/updates/", utsRelease), + filepath.Join("/lib/firmware/updates/"), + filepath.Join("/lib/firmware/", utsRelease), + filepath.Join("/lib/firmware/"), + } + + return append(firmwarePaths, standardPaths...), nil +} + +// getCustomFirmwareClassPath returns the custom firmware class path if it exists. +func getCustomFirmwareClassPath(logger logger.Interface) string { + customFirmwareClassPath, err := os.ReadFile("/sys/module/firmware_class/parameters/path") + if err != nil { + logger.Warningf("failed to get custom firmware class path: %v", err) + return "" + } + + return strings.TrimSpace(string(customFirmwareClassPath)) +} + // NewDriverFirmwareDiscoverer creates a discoverer for GSP firmware associated with the specified driver version. -func NewDriverFirmwareDiscoverer(logger logger.Interface, driverRoot string, version string) discover.Discover { - gspFirmwarePath := filepath.Join("/lib/firmware/nvidia", version, "gsp*.bin") +func NewDriverFirmwareDiscoverer(logger logger.Interface, driverRoot string, version string) (discover.Discover, error) { + gspFirmwareSearchPaths, err := getFirmwareSearchPaths(logger) + if err != nil { + return nil, fmt.Errorf("failed to get firmware search paths: %v", err) + } + gspFirmwarePaths := filepath.Join("nvidia", version, "gsp*.bin") return discover.NewMounts( logger, lookup.NewFileLocator( lookup.WithLogger(logger), lookup.WithRoot(driverRoot), + lookup.WithSearchPaths(gspFirmwareSearchPaths...), ), driverRoot, - []string{gspFirmwarePath}, - ) + []string{gspFirmwarePaths}, + ), nil } // NewDriverBinariesDiscoverer creates a discoverer for GSP firmware associated with the GPU driver.