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