blob: fc5d458544204a178bd162e0871cb56c1e067796 [file] [edit]
package daemon
import (
"context"
"errors"
"slices"
"github.com/containerd/log"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/system"
"github.com/moby/moby/v2/daemon/config"
"github.com/moby/moby/v2/daemon/internal/capabilities"
"github.com/opencontainers/runtime-spec/specs-go"
)
var deviceDrivers = map[string]*deviceDriver{}
type deviceListing struct {
Devices []system.DeviceInfo
Warnings []string
}
type deviceDriver struct {
capset capabilities.Set
updateSpec func(*specs.Spec, *deviceInstance) error
// ListDevices returns a list of discoverable devices provided by this
// driver, any warnings encountered during the discovery, and an error if
// the overall listing operation failed.
// Can be nil if the driver does not provide a device listing.
ListDevices func(ctx context.Context, cfg *config.Config) (deviceListing, error)
}
type deviceInstance struct {
req container.DeviceRequest
selectedCaps []string
}
func registerDeviceDriver(name string, d *deviceDriver) {
deviceDrivers[name] = d
}
func getFirstAvailableVendor(vendorList []string) (string, error) {
knownVendors := []string{"nvidia.com", "amd.com"}
for _, vendor := range knownVendors {
if slices.Contains(vendorList, vendor) {
return vendor, nil
}
}
return "", errors.New("no known GPU vendor found")
}
func (daemon *Daemon) handleDevice(req container.DeviceRequest, spec *specs.Spec) error {
if req.Driver == "" {
// If no driver is explicitly requested, we iterate over the registered
// drivers and attempt to match on capabilities.
for driver, dd := range deviceDrivers {
if selected := dd.capset.Match(req.Capabilities); selected != nil {
log.G(context.TODO()).WithFields(log.Fields{
"driver": driver,
"capabilities": map[string]any{
"requested": req.Capabilities,
"selected": selected,
},
}).Debug("Selecting device driver by capabilities")
return dd.updateSpec(spec, &deviceInstance{req: req, selectedCaps: selected})
}
}
} else if dd := deviceDrivers[req.Driver]; dd != nil {
selected := dd.capset.Match(req.Capabilities)
// If a driver is explicitly requested and registered, then we use the
// specified driver, ignoring the capabilities.
log.G(context.TODO()).WithFields(log.Fields{
"driver": req.Driver,
"capabilities": map[string]any{
"requested": req.Capabilities,
"selected": selected,
},
}).Debug("Selecting device driver by driver name; possibly ignoring capabilities")
return dd.updateSpec(spec, &deviceInstance{req: req, selectedCaps: selected})
}
return incompatibleDeviceRequest{req.Driver, req.Capabilities}
}