package daemon // import "github.com/docker/docker/daemon" import ( "github.com/docker/docker/api/types/container" "github.com/docker/docker/pkg/capabilities" specs "github.com/opencontainers/runtime-spec/specs-go" ) var deviceDrivers = map[string]*deviceDriver{} type deviceDriver struct { capset capabilities.Set updateSpec func(*specs.Spec, *deviceInstance) error } type deviceInstance struct { req container.DeviceRequest selectedCaps []string } func registerDeviceDriver(name string, d *deviceDriver) { deviceDrivers[name] = d } func (daemon *Daemon) handleDevice(req container.DeviceRequest, spec *specs.Spec) error { if req.Driver == "" { for _, dd := range deviceDrivers { if selected := dd.capset.Match(req.Capabilities); selected != nil { return dd.updateSpec(spec, &deviceInstance{req: req, selectedCaps: selected}) } } } else if dd := deviceDrivers[req.Driver]; dd != nil { // We add a special case for the CDI driver here as the cdi driver does // not distinguish between capabilities. // Furthermore, the "OR" and "AND" matching logic for the capability // sets requires that a dummy capability be specified when constructing a // DeviceRequest. // This workaround can be removed once these device driver are // refactored to be plugins, with each driver implementing its own // matching logic, for example. if req.Driver == "cdi" { return dd.updateSpec(spec, &deviceInstance{req: req}) } if selected := dd.capset.Match(req.Capabilities); selected != nil { return dd.updateSpec(spec, &deviceInstance{req: req, selectedCaps: selected}) } } return incompatibleDeviceRequest{req.Driver, req.Capabilities} }