Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 51 additions & 15 deletions internal/discover/graphics.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,29 +55,58 @@ func NewGraphicsMountsDiscoverer(logger logger.Interface, driver *root.Driver, h
return nil, fmt.Errorf("failed to construct discoverer for graphics libraries: %w", err)
}

configs := NewMounts(
binaries := NewMounts(
logger,
driver.Configs(),
lookup.NewExecutableLocator(logger, driver.Root),
driver.Root,
[]string{
"nvidia-xconfig",
},
)

discover := Merge(
libraries,
binaries,
newGraphicsConfigsDiscoverer(logger, driver),
newVulkanConfigsDiscover(logger, driver),
)

return discover, nil
}

// newGraphicsConfigsDiscoverer creates a discoverer for graphics-related config
// files such as the EGL vendor and external platform ICD files.
// The config files are mounted at the standard locations in the container so
// that they are discovered by the loaders in the container even if they are
// installed at non-standard locations on the host.
func newGraphicsConfigsDiscoverer(logger logger.Interface, driver *root.Driver) Discover {
shareConfigs := WithCache(&mountsToContainerPath{
logger: logger,
locator: driver.Configs(),
required: []string{
"glvnd/egl_vendor.d/10_nvidia.json",
"egl/egl_external_platform.d/15_nvidia_gbm.json",
"egl/egl_external_platform.d/10_nvidia_wayland.json",
"egl/egl_external_platform.d/09_nvidia_wayland2.json",
"egl/egl_external_platform.d/20_nvidia_xcb.json",
"egl/egl_external_platform.d/20_nvidia_xlib.json",
"nvidia/nvoptix.bin",
"X11/xorg.conf.d/10-nvidia.conf",
"X11/xorg.conf.d/nvidia-drm-outputclass.conf",
"OpenCL/vendors/nvidia.icd",
},
)
containerRoot: "/usr/share",
})

discover := Merge(
libraries,
configs,
newVulkanConfigsDiscover(logger, driver),
)
etcConfigs := WithCache(&mountsToContainerPath{
logger: logger,
locator: driver.Configs(),
required: []string{
"OpenCL/vendors/nvidia.icd",
},
containerRoot: "/etc",
})

return discover, nil
return Merge(shareConfigs, etcConfigs)
}

// newVulkanConfigsDiscover creates a discoverer for vulkan ICD files.
Expand All @@ -101,12 +130,12 @@ func newVulkanConfigsDiscover(logger logger.Interface, driver *root.Driver) Disc
case "arm64":
required = append(required, "vulkan/icd.d/nvidia_icd.aarch64.json")
}
return &mountsToContainerPath{
return WithCache(&mountsToContainerPath{
logger: logger,
locator: locator,
required: required,
containerRoot: "/etc",
}
})
}

type graphicsDriverLibraries struct {
Expand Down Expand Up @@ -135,11 +164,14 @@ func newGraphicsLibrariesDiscoverer(logger logger.Interface, driver *root.Driver
driver.Libraries(),
driver.Root,
[]string{
// The libnvidia-egl-gbm and libnvidia-egl-wayland libraries do not
// have the RM version. Use the *.* pattern to match X.Y.Z versions.
// The EGL platform libraries such as libnvidia-egl-gbm and
// libnvidia-egl-wayland do not have the RM version. Use the *.*
// pattern to match X.Y.Z versions.
"libnvidia-egl-gbm.so.*.*",
"libnvidia-egl-wayland.so.*.*",
"libnvidia-egl-wayland2.so.*.*",
"libnvidia-egl-xcb.so.*.*",
"libnvidia-egl-xlib.so.*.*",
// We include the following libraries to have them available for
// symlink creation below:
// If CDI injection is used, these should already be detected as:
Expand All @@ -151,6 +183,10 @@ func newGraphicsLibrariesDiscoverer(logger logger.Interface, driver *root.Driver
},
)

// The X.Org driver modules are mounted at their host paths. This keeps any
// ModulePath specified in the xorg.conf.d config file that is mounted into
// the container valid and means that modules installed to the default X.Org
// module path on the host are also found there in the container.
xorgLibraries := NewMounts(
logger,
lookup.NewFileLocator(
Expand Down Expand Up @@ -231,7 +267,7 @@ func (d graphicsDriverLibraries) Hooks() ([]Hook, error) {
return nil, nil
}

hook := d.hookCreator.Create("create-symlinks", links...)
hook := d.hookCreator.Create(CreateSymlinksHook, links...)

return hook.Hooks()
}
Expand Down
74 changes: 74 additions & 0 deletions internal/discover/graphics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package discover

import (
"os"
"path/filepath"
"strings"
"testing"
Expand All @@ -25,6 +26,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/NVIDIA/nvidia-container-toolkit/internal/devices"
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root"
"github.com/NVIDIA/nvidia-container-toolkit/internal/test"
)

Expand Down Expand Up @@ -189,6 +191,78 @@ func TestGraphicsLibrariesDiscoverer(t *testing.T) {
}
}

func TestGraphicsConfigsDiscoverer(t *testing.T) {
logger, _ := testlog.NewNullLogger()

testCases := []struct {
description string
files []string
// expected maps the path of the file in the driver root to the path
// that it is expected to be mounted at in the container.
expected map[string]string
}{
{
description: "config files in the standard locations",
files: []string{
"/usr/share/glvnd/egl_vendor.d/10_nvidia.json",
"/usr/share/egl/egl_external_platform.d/20_nvidia_xcb.json",
"/usr/share/X11/xorg.conf.d/10-nvidia.conf",
"/etc/OpenCL/vendors/nvidia.icd",
},
expected: map[string]string{
"/usr/share/glvnd/egl_vendor.d/10_nvidia.json": "/usr/share/glvnd/egl_vendor.d/10_nvidia.json",
"/usr/share/egl/egl_external_platform.d/20_nvidia_xcb.json": "/usr/share/egl/egl_external_platform.d/20_nvidia_xcb.json",
"/usr/share/X11/xorg.conf.d/10-nvidia.conf": "/usr/share/X11/xorg.conf.d/10-nvidia.conf",
"/etc/OpenCL/vendors/nvidia.icd": "/etc/OpenCL/vendors/nvidia.icd",
},
},
{
description: "config files in non-standard locations are mounted at the standard locations",
files: []string{
"/usr/local/share/glvnd/egl_vendor.d/10_nvidia.json",
"/usr/local/share/egl/egl_external_platform.d/20_nvidia_xlib.json",
"/etc/X11/xorg.conf.d/nvidia-drm-outputclass.conf",
},
expected: map[string]string{
"/usr/local/share/glvnd/egl_vendor.d/10_nvidia.json": "/usr/share/glvnd/egl_vendor.d/10_nvidia.json",
"/usr/local/share/egl/egl_external_platform.d/20_nvidia_xlib.json": "/usr/share/egl/egl_external_platform.d/20_nvidia_xlib.json",
"/etc/X11/xorg.conf.d/nvidia-drm-outputclass.conf": "/usr/share/X11/xorg.conf.d/nvidia-drm-outputclass.conf",
},
},
}

for _, tc := range testCases {
t.Run(tc.description, func(t *testing.T) {
// The config search paths include the XDG data dirs. These are
// set explicitly to ensure that the test is not affected by the
// environment that it is run in.
t.Setenv("XDG_DATA_DIRS", "/usr/local/share:/usr/share")

driverRoot := t.TempDir()
for _, f := range tc.files {
path := filepath.Join(driverRoot, f)
require.NoError(t, os.MkdirAll(filepath.Dir(path), 0755))
require.NoError(t, os.WriteFile(path, []byte{}, 0600))
}

driver := root.New(
root.WithLogger(logger),
root.WithDriverRoot(driverRoot),
)

mounts, err := newGraphicsConfigsDiscoverer(logger, driver).Mounts()
require.NoError(t, err)

discovered := make(map[string]string)
for _, mount := range mounts {
hostPath := strings.TrimPrefix(mount.HostPath, driverRoot)
discovered[hostPath] = mount.Path
}
require.EqualValues(t, tc.expected, discovered)
})
}
}

func TestDrmDevicesByPath(t *testing.T) {
defer devices.SetAllForTest()()
moduleRoot, err := test.GetModuleRoot()
Expand Down
Loading