| 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} |
| } |