Skip to content

Commit 82ae2e6

Browse files
committed
Add creation of select driver symlinks to CDI spec
This change aligns the creation of symlinks under CDI with the implementation in libnvidia-container. If the driver libraries are present, the following symlinks are created: * {{ .LibRoot }}/libcuda.so -> libcuda.so.1 * {{ .LibRoot }}/libnvidia-opticalflow.so -> libnvidia-opticalflow.so.1 * {{ .LibRoot }}/libGLX_indirect.so.0 -> libGLX_nvidia.so.{{ .Version }} Signed-off-by: Evan Lezar <[email protected]>
1 parent 006aebf commit 82ae2e6

File tree

7 files changed

+464
-70
lines changed

7 files changed

+464
-70
lines changed

internal/discover/none.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ var _ Discover = (*None)(nil)
2424

2525
// Devices returns an empty list of devices
2626
func (e None) Devices() ([]Device, error) {
27-
return []Device{}, nil
27+
return nil, nil
2828
}
2929

3030
// Mounts returns an empty list of mounts
3131
func (e None) Mounts() ([]Mount, error) {
32-
return []Mount{}, nil
32+
return nil, nil
3333
}
3434

3535
// Hooks returns an empty list of hooks
3636
func (e None) Hooks() ([]Hook, error) {
37-
return []Hook{}, nil
37+
return nil, nil
3838
}

internal/discover/symlinks.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/**
2+
# Copyright 2024 NVIDIA CORPORATION
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
**/
16+
17+
package discover
18+
19+
import (
20+
"fmt"
21+
"path/filepath"
22+
)
23+
24+
type additionalSymlinks struct {
25+
Discover
26+
version string
27+
nvidiaCDIHookPath string
28+
}
29+
30+
// WithDriverDotSoSymlinks decorates the provided discoverer.
31+
// A hook is added that checks for specific driver symlinks that need to be created.
32+
func WithDriverDotSoSymlinks(mounts Discover, version string, nvidiaCDIHookPath string) Discover {
33+
if version == "" {
34+
version = "*.*"
35+
}
36+
return &additionalSymlinks{
37+
Discover: mounts,
38+
nvidiaCDIHookPath: nvidiaCDIHookPath,
39+
version: version,
40+
}
41+
}
42+
43+
// Hooks returns a hook to create the additional symlinks based on the mounts.
44+
func (d *additionalSymlinks) Hooks() ([]Hook, error) {
45+
mounts, err := d.Discover.Mounts()
46+
if err != nil {
47+
return nil, fmt.Errorf("failed to get library mounts: %v", err)
48+
}
49+
hooks, err := d.Discover.Hooks()
50+
if err != nil {
51+
return nil, fmt.Errorf("failed to get hooks: %v", err)
52+
}
53+
54+
var links []string
55+
processedPaths := make(map[string]bool)
56+
processedLinks := make(map[string]bool)
57+
for _, mount := range mounts {
58+
if processedPaths[mount.Path] {
59+
continue
60+
}
61+
processedPaths[mount.Path] = true
62+
63+
for _, link := range d.getLinksForMount(mount.Path) {
64+
if processedLinks[link] {
65+
continue
66+
}
67+
processedLinks[link] = true
68+
links = append(links, link)
69+
}
70+
}
71+
72+
if len(links) == 0 {
73+
return hooks, nil
74+
}
75+
76+
hook := CreateCreateSymlinkHook(d.nvidiaCDIHookPath, links).(Hook)
77+
return append(hooks, hook), nil
78+
}
79+
80+
// getLinksForMount maps the path to created links if any.
81+
func (d additionalSymlinks) getLinksForMount(path string) []string {
82+
dir, filename := filepath.Split(path)
83+
switch {
84+
case d.isDriverLibrary("libcuda.so", filename):
85+
// XXX Many applications wrongly assume that libcuda.so exists (e.g. with dlopen).
86+
// create libcuda.so -> libcuda.so.1 symlink
87+
link := fmt.Sprintf("%s::%s", "libcuda.so.1", filepath.Join(dir, "libcuda.so"))
88+
return []string{link}
89+
case d.isDriverLibrary("libGLX_nvidia.so", filename):
90+
// XXX GLVND requires this symlink for indirect GLX support.
91+
// create libGLX_indirect.so.0 -> libGLX_nvidia.so.VERSION symlink
92+
link := fmt.Sprintf("%s::%s", filename, filepath.Join(dir, "libGLX_indirect.so.0"))
93+
return []string{link}
94+
case d.isDriverLibrary("libnvidia-opticalflow.so", filename):
95+
// XXX Fix missing symlink for libnvidia-opticalflow.so.
96+
// create libnvidia-opticalflow.so -> libnvidia-opticalflow.so.1 symlink
97+
link := fmt.Sprintf("%s::%s", "libnvidia-opticalflow.so.1", filepath.Join(dir, "libnvidia-opticalflow.so"))
98+
return []string{link}
99+
}
100+
return nil
101+
}
102+
103+
// isDriverLibrary checks whether the specified filename is a specific driver library.
104+
func (d additionalSymlinks) isDriverLibrary(libraryName string, filename string) bool {
105+
pattern := libraryName + "." + d.version
106+
match, _ := filepath.Match(pattern, filename)
107+
return match
108+
}

0 commit comments

Comments
 (0)