The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/8007

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===

From e1e86a1d38e28c6c8d95aae6b5feb6cd2bf74dae Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.h...@canonical.com>
Date: Thu, 8 Oct 2020 10:57:55 +0200
Subject: [PATCH 1/7] lxd/device/usb: Allow USB devices for VMs

This removes the container-only restriction, and allows USB devices for
VMs.

Signed-off-by: Thomas Hipp <thomas.h...@canonical.com>
---
 lxd/device/usb.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/device/usb.go b/lxd/device/usb.go
index 6e5c09aab9..519da70edb 100644
--- a/lxd/device/usb.go
+++ b/lxd/device/usb.go
@@ -45,7 +45,7 @@ func (d *usb) isRequired() bool {
 
 // validateConfig checks the supplied config for correctness.
 func (d *usb) validateConfig(instConf instance.ConfigReader) error {
-       if !instanceSupported(instConf.Type(), instancetype.Container) {
+       if !instanceSupported(instConf.Type(), instancetype.Container, 
instancetype.VM) {
                return ErrUnsupportedDevType
        }
 

From eadab2d3d214010edeaf8c4c04df59caf94858fb Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.h...@canonical.com>
Date: Thu, 8 Oct 2020 16:30:22 +0200
Subject: [PATCH 2/7] lxd/device: Add bus and dev number to USBEvent

This adds two new public fields BusNum and DevNum to the USBEvent
struct.

Signed-off-by: Thomas Hipp <thomas.h...@canonical.com>
---
 lxd/device/device_utils_usb_events.go | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/lxd/device/device_utils_usb_events.go 
b/lxd/device/device_utils_usb_events.go
index a0a2f01e11..18840eafb2 100644
--- a/lxd/device/device_utils_usb_events.go
+++ b/lxd/device/device_utils_usb_events.go
@@ -26,6 +26,9 @@ type USBEvent struct {
        Minor       uint32
        UeventParts []string
        UeventLen   int
+
+       BusNum int
+       DevNum int
 }
 
 // usbHandlers stores the event handler callbacks for USB events.
@@ -106,14 +109,16 @@ func USBNewEvent(action string, vendor string, product 
string, major string, min
                return USBEvent{}, err
        }
 
+       busnumInt := 0
+       devnumInt := 0
        path := devname
        if devname == "" {
-               busnumInt, err := strconv.Atoi(busnum)
+               busnumInt, err = strconv.Atoi(busnum)
                if err != nil {
                        return USBEvent{}, err
                }
 
-               devnumInt, err := strconv.Atoi(devnum)
+               devnumInt, err = strconv.Atoi(devnum)
                if err != nil {
                        return USBEvent{}, err
                }
@@ -133,5 +138,7 @@ func USBNewEvent(action string, vendor string, product 
string, major string, min
                uint32(minorInt),
                ueventParts,
                ueventLen,
+               busnumInt,
+               devnumInt,
        }, nil
 }

From bf3c02d11b68ee13da5eca32e61a926adf216eff Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.h...@canonical.com>
Date: Fri, 9 Oct 2020 16:36:25 +0200
Subject: [PATCH 3/7] lxd/apparmor: Allow USB specific paths

This adds some paths to the AppArmor profile which need to be accessible
when using USB pass through.

Signed-off-by: Thomas Hipp <thomas.h...@canonical.com>
---
 lxd/apparmor/instance_qemu.go | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/lxd/apparmor/instance_qemu.go b/lxd/apparmor/instance_qemu.go
index c529e76ffc..a1183e27e4 100644
--- a/lxd/apparmor/instance_qemu.go
+++ b/lxd/apparmor/instance_qemu.go
@@ -27,9 +27,13 @@ profile "{{ .name }}" 
flags=(attach_disconnected,mediate_deleted) {
   /dev/vhost-net                            rw,
   /dev/vhost-vsock                          rw,
   /etc/ceph/**                              r,
+  /run/udev/data/*                          r,
+  /sys/bus/                                 r,
   /sys/bus/nd/devices/                      r,
-  /sys/devices/system/node/                 r,
-  /sys/devices/system/node/**               r,
+  /sys/bus/usb/devices/                     r,
+  /sys/bus/usb/devices/**                   r,
+  /sys/class/                               r,
+  /sys/devices/**                           r,
   /sys/module/vhost/**                      r,
   /{,usr/}bin/qemu*                         mrix,
   /usr/share/OVMF/OVMF_CODE.fd              kr,

From 1a811e7e7ca3f82d3b507d7b5462c1ccd3de579a Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.h...@canonical.com>
Date: Fri, 9 Oct 2020 16:37:07 +0200
Subject: [PATCH 4/7] lxd/device/config: Add USBDevice to RunConfig

Signed-off-by: Thomas Hipp <thomas.h...@canonical.com>
---
 lxd/device/config/device_runconfig.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lxd/device/config/device_runconfig.go 
b/lxd/device/config/device_runconfig.go
index eba388047a..f68d77b27e 100644
--- a/lxd/device/config/device_runconfig.go
+++ b/lxd/device/config/device_runconfig.go
@@ -42,4 +42,5 @@ type RunConfig struct {
        Uevents          [][]string       // Uevents to inject.
        PostHooks        []func() error   // Functions to be run after device 
attach/detach.
        GPUDevice        []RunConfigItem  // GPU device configuration settings.
+       USBDevice        []RunConfigItem  // USB device configuration settings.
 }

From e1cd9f34e268837d932c8842dfbe39cfe85962ac Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.h...@canonical.com>
Date: Fri, 9 Oct 2020 16:38:01 +0200
Subject: [PATCH 5/7] lxd/device: Handle USB devices for VMs

Signed-off-by: Thomas Hipp <thomas.h...@canonical.com>
---
 lxd/device/usb.go | 57 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 51 insertions(+), 6 deletions(-)

diff --git a/lxd/device/usb.go b/lxd/device/usb.go
index 519da70edb..be646839fd 100644
--- a/lxd/device/usb.go
+++ b/lxd/device/usb.go
@@ -118,6 +118,14 @@ func (d *usb) Register() error {
 
 // Start is run when the device is added to the instance.
 func (d *usb) Start() (*deviceConfig.RunConfig, error) {
+       if d.inst.Type() == instancetype.VM {
+               return d.startVM()
+       }
+
+       return d.startContainer()
+}
+
+func (d *usb) startContainer() (*deviceConfig.RunConfig, error) {
        usbs, err := d.loadUsb()
        if err != nil {
                return nil, err
@@ -144,18 +152,48 @@ func (d *usb) Start() (*deviceConfig.RunConfig, error) {
        return &runConf, nil
 }
 
+func (d *usb) startVM() (*deviceConfig.RunConfig, error) {
+       usbs, err := d.loadUsb()
+       if err != nil {
+               return nil, err
+       }
+
+       runConf := deviceConfig.RunConfig{}
+       runConf.PostHooks = []func() error{d.Register}
+
+       for _, usb := range usbs {
+               if !usbIsOurDevice(d.config, &usb) {
+                       continue
+               }
+
+               runConf.USBDevice = append(runConf.USBDevice, 
[]deviceConfig.RunConfigItem{
+                       {Key: "devName", Value: d.name},
+                       {Key: "hostBus", Value: fmt.Sprintf("%d", usb.BusNum)},
+                       {Key: "hostAddr", Value: fmt.Sprintf("%d", usb.DevNum)},
+               }...)
+       }
+
+       if d.isRequired() && len(runConf.Mounts) <= 0 {
+               return nil, fmt.Errorf("Required USB device not found")
+       }
+
+       return &runConf, nil
+}
+
 // Stop is run when the device is removed from the instance.
 func (d *usb) Stop() (*deviceConfig.RunConfig, error) {
-       // Unregister any USB event handlers for this device.
-       usbUnregisterHandler(d.inst, d.name)
-
        runConf := deviceConfig.RunConfig{
                PostHooks: []func() error{d.postStop},
        }
 
-       err := unixDeviceRemove(d.inst.DevicesPath(), "unix", d.name, "", 
&runConf)
-       if err != nil {
-               return nil, err
+       if d.inst.Type() == instancetype.Container {
+               // Unregister any USB event handlers for this device.
+               usbUnregisterHandler(d.inst, d.name)
+
+               err := unixDeviceRemove(d.inst.DevicesPath(), "unix", d.name, 
"", &runConf)
+               if err != nil {
+                       return nil, err
+               }
        }
 
        return &runConf, nil
@@ -246,3 +284,10 @@ func (d *usb) loadRawValues(p string) (map[string]string, 
error) {
 
        return values, nil
 }
+
+// CanHotPlug returns true if attached to a container, otherwise false. It also
+// returns a list of fields that can be updated without triggering a device 
remove & add (in this
+// case an empty list).
+// func (d *usb) CanHotPlug() (bool, []string) {
+//     return d.inst.Type() == instancetype.Container, []string{}
+// }

From c1a959117631fd0177c66c28fd1ad7f6cf1dd562 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.h...@canonical.com>
Date: Fri, 9 Oct 2020 16:38:45 +0200
Subject: [PATCH 6/7] lxd/instance/drivers: Add qemuUSBDev template

This adds a device template for USB devices.

Signed-off-by: Thomas Hipp <thomas.h...@canonical.com>
---
 lxd/instance/drivers/driver_qemu_templates.go | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/lxd/instance/drivers/driver_qemu_templates.go 
b/lxd/instance/drivers/driver_qemu_templates.go
index c1b383bc6b..f1f77eb231 100644
--- a/lxd/instance/drivers/driver_qemu_templates.go
+++ b/lxd/instance/drivers/driver_qemu_templates.go
@@ -508,3 +508,12 @@ addr = "{{.devAddr}}"
 multifunction = "on"
 {{- end }}
 `))
+
+var qemuUSBDev = template.Must(template.New("qemuUSBDev").Parse(`
+# USB host device ("{{.devName}}" device)
+[device "dev-lxd_{{.devName}}"]
+driver = "usb-host"
+bus = "qemu_usb.0"
+hostaddr = "{{.hostAddr}}"
+hostbus = "{{.hostBus}}"
+`))

From b45f0198c757029860340522eef3443e3a71f376 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.h...@canonical.com>
Date: Fri, 9 Oct 2020 16:39:41 +0200
Subject: [PATCH 7/7] lxd/instance/drivers: Add USB devices to qemu config

This adds configured USB devices to the qemu config file.

Signed-off-by: Thomas Hipp <thomas.h...@canonical.com>
---
 lxd/instance/drivers/driver_qemu.go | 49 +++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/lxd/instance/drivers/driver_qemu.go 
b/lxd/instance/drivers/driver_qemu.go
index 0b697cbf58..0d17257419 100644
--- a/lxd/instance/drivers/driver_qemu.go
+++ b/lxd/instance/drivers/driver_qemu.go
@@ -1842,6 +1842,14 @@ func (vm *qemu) generateQemuConfigFile(busName string, 
devConfs []*deviceConfig.
                                return "", err
                        }
                }
+
+               // Add USB device.
+               if len(runConf.USBDevice) > 0 {
+                       err = vm.addUSBDeviceConfig(sb, bus, runConf.USBDevice)
+                       if err != nil {
+                               return "", err
+                       }
+               }
        }
 
        // Write the agent mount config.
@@ -2256,6 +2264,47 @@ func (vm *qemu) addGPUDevConfig(sb *strings.Builder, bus 
*qemuBus, gpuConfig []d
        return nil
 }
 
+func (vm *qemu) addUSBDeviceConfig(sb *strings.Builder, bus *qemuBus, 
usbConfig []deviceConfig.RunConfigItem) error {
+       var devName, hostBus, hostAddr string
+
+       for _, usbItem := range usbConfig {
+               if usbItem.Key == "devName" {
+                       devName = usbItem.Value
+               } else if usbItem.Key == "hostBus" {
+                       hostBus = usbItem.Value
+               } else if usbItem.Key == "hostAddr" {
+                       hostAddr = usbItem.Value
+               }
+       }
+
+       tplFields := map[string]interface{}{
+               "hostBus":  hostBus,
+               "hostAddr": hostAddr,
+               "devName":  devName,
+       }
+
+       // Add main GPU device in VGA mode to qemu config.
+       err := qemuUSBDev.Execute(sb, tplFields)
+       if err != nil {
+               return err
+       }
+
+       hostBusInt, err := strconv.Atoi(hostBus)
+       if err != nil {
+               return err
+       }
+
+       hostAddrInt, err := strconv.Atoi(hostAddr)
+       if err != nil {
+               return err
+       }
+
+       // Add path to devPaths. This way, the path will be included in the 
apparmor profile.
+       vm.devPaths = append(vm.devPaths, fmt.Sprintf("/dev/bus/usb/%03d/%03d", 
hostBusInt, hostAddrInt))
+
+       return nil
+}
+
 // pidFilePath returns the path where the qemu process should write its PID.
 func (vm *qemu) pidFilePath() string {
        return filepath.Join(vm.LogPath(), "qemu.pid")
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to