devices.go 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. package daemon // import "github.com/docker/docker/daemon"
  2. import (
  3. "github.com/docker/docker/api/types/container"
  4. "github.com/docker/docker/pkg/capabilities"
  5. specs "github.com/opencontainers/runtime-spec/specs-go"
  6. )
  7. var deviceDrivers = map[string]*deviceDriver{}
  8. type deviceDriver struct {
  9. capset capabilities.Set
  10. updateSpec func(*specs.Spec, *deviceInstance) error
  11. }
  12. type deviceInstance struct {
  13. req container.DeviceRequest
  14. selectedCaps []string
  15. }
  16. func registerDeviceDriver(name string, d *deviceDriver) {
  17. deviceDrivers[name] = d
  18. }
  19. func (daemon *Daemon) handleDevice(req container.DeviceRequest, spec *specs.Spec) error {
  20. if req.Driver == "" {
  21. for _, dd := range deviceDrivers {
  22. if selected := dd.capset.Match(req.Capabilities); selected != nil {
  23. return dd.updateSpec(spec, &deviceInstance{req: req, selectedCaps: selected})
  24. }
  25. }
  26. } else if dd := deviceDrivers[req.Driver]; dd != nil {
  27. // We add a special case for the CDI driver here as the cdi driver does
  28. // not distinguish between capabilities.
  29. // Furthermore, the "OR" and "AND" matching logic for the capability
  30. // sets requires that a dummy capability be specified when constructing a
  31. // DeviceRequest.
  32. // This workaround can be removed once these device driver are
  33. // refactored to be plugins, with each driver implementing its own
  34. // matching logic, for example.
  35. if req.Driver == "cdi" {
  36. return dd.updateSpec(spec, &deviceInstance{req: req})
  37. }
  38. if selected := dd.capset.Match(req.Capabilities); selected != nil {
  39. return dd.updateSpec(spec, &deviceInstance{req: req, selectedCaps: selected})
  40. }
  41. }
  42. return incompatibleDeviceRequest{req.Driver, req.Capabilities}
  43. }