diff --git a/pkg/nvpci/logger.go b/pkg/nvpci/logger.go index 8b7b5ab..ff77976 100644 --- a/pkg/nvpci/logger.go +++ b/pkg/nvpci/logger.go @@ -25,5 +25,5 @@ type logger interface { type simpleLogger struct{} func (l simpleLogger) Warningf(format string, v ...interface{}) { - log.Printf("WARNING: "+format, v) + log.Printf("WARNING: "+format, v...) } diff --git a/pkg/nvpci/logger_test.go b/pkg/nvpci/logger_test.go new file mode 100644 index 0000000..aa88249 --- /dev/null +++ b/pkg/nvpci/logger_test.go @@ -0,0 +1,41 @@ +/** +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package nvpci + +import ( + "bytes" + "log" + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSimpleLoggerWarningf(t *testing.T) { + var buf bytes.Buffer + flags := log.Flags() + log.SetOutput(&buf) + log.SetFlags(0) + defer func() { + log.SetOutput(os.Stderr) + log.SetFlags(flags) + }() + + simpleLogger{}.Warningf("unable to detect IOMMU FD for %s: %v", "0000:01:00.0", "no such file or directory") + + require.Equal(t, "WARNING: unable to detect IOMMU FD for 0000:01:00.0: no such file or directory\n", buf.String()) +} diff --git a/pkg/nvpci/nvpci.go b/pkg/nvpci/nvpci.go index f1fd841..06ea79f 100644 --- a/pkg/nvpci/nvpci.go +++ b/pkg/nvpci/nvpci.go @@ -566,6 +566,12 @@ func getDriver(devicePath string) (string, error) { func getIOMMUFD(devicePath string) (string, error) { content, err := os.ReadDir(path.Join(devicePath, "vfio-dev")) + // The vfio-dev directory only exists for devices that are bound to a VFIO + // driver on a kernel with VFIO device cdev support. For every other device, + // such as a GPU bound to the nvidia driver, there is no IOMMU FD to report. + if errors.Is(err, os.ErrNotExist) { + return "", nil + } if err != nil { return "", err } diff --git a/pkg/nvpci/nvpci_test.go b/pkg/nvpci/nvpci_test.go index 6963919..cc1b9dd 100644 --- a/pkg/nvpci/nvpci_test.go +++ b/pkg/nvpci/nvpci_test.go @@ -17,6 +17,7 @@ package nvpci import ( + "fmt" "os" "path/filepath" "testing" @@ -196,6 +197,57 @@ func TestNvpciIOMMUFD(t *testing.T) { } } +type recordingLogger struct { + warnings []string +} + +func (l *recordingLogger) Warningf(format string, v ...interface{}) { + l.warnings = append(l.warnings, fmt.Sprintf(format, v...)) +} + +func TestNvpciIOMMUFDNotBoundToVFIO(t *testing.T) { + nvpci, err := NewMockNvpci() + require.Nil(t, err, "Error creating NewMockNvpci") + defer nvpci.Cleanup() + + logger := &recordingLogger{} + nvpci.logger = logger + + err = nvpci.AddMockA100("0000:80:05.1", 0, nil) + require.Nil(t, err, "Error adding Mock A100 device to MockNvpci") + + // A GPU that is bound to the nvidia driver has no vfio-dev directory. + deviceDir := filepath.Join(nvpci.pciDevicesRoot, "0000:80:05.1") + require.NoError(t, os.RemoveAll(filepath.Join(deviceDir, "vfio-dev"))) + + devices, err := nvpci.GetGPUs() + require.Nil(t, err, "Error getting GPUs") + require.Equal(t, 1, len(devices), "Wrong number of GPU devices") + require.Equal(t, "", devices[0].IommuFD, "IOMMUFD should be empty without a vfio-dev directory") + require.Empty(t, logger.warnings, "No warning expected for a device without a vfio-dev directory") +} + +func TestNvpciIOMMUFDEmptyVFIODev(t *testing.T) { + nvpci, err := NewMockNvpci() + require.Nil(t, err, "Error creating NewMockNvpci") + defer nvpci.Cleanup() + + logger := &recordingLogger{} + nvpci.logger = logger + + err = nvpci.AddMockA100("0000:80:05.1", 0, nil) + require.Nil(t, err, "Error adding Mock A100 device to MockNvpci") + + deviceDir := filepath.Join(nvpci.pciDevicesRoot, "0000:80:05.1") + require.NoError(t, os.RemoveAll(filepath.Join(deviceDir, "vfio-dev", "vfio8"))) + + devices, err := nvpci.GetGPUs() + require.Nil(t, err, "Error getting GPUs") + require.Equal(t, 1, len(devices), "Wrong number of GPU devices") + require.Equal(t, "", devices[0].IommuFD, "IOMMUFD should be empty without a vfio device entry") + require.Equal(t, []string{"unable to detect IOMMU FD for 0000:80:05.1: no iommufd device found"}, logger.warnings) +} + func TestNvpciNUMANode(t *testing.T) { testCases := []struct { Description string