Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
LXC USB Passthrough (Proxmox)
1. Plug USB device
root@proxmox01:~# lsusb
[...]
Bus 004 Device 005: ID 0658:0200 Sigma Designs, Inc.
[...]
2. Take a look of device
root@proxmox01:~# ls -l /dev/bus/usb/004/005
crw-rw-r-- 1 root root 189, 388 Oct 25 16:19 /dev/bus/usb/004/005
Take note of ID (example: 189, 388)
3. Edit lxc configuration
root@proxmox01:~# nano /etc/pve/nodes/proxmox01/lxc/101.conf
lxc.cgroup.devices.allow: c 189:388 rwm
lxc.mount.entry: /dev/bus/usb/004/005 dev/bus/usb/004/005 none bind,optional,create=file
@hablutzel1

This comment has been minimized.

Copy link

@hablutzel1 hablutzel1 commented Jun 21, 2018

A little bit more detailed version of the same:

  1. Stop the LXC CT.

# pct stop 102

  1. Then inspect log for this CT.

# cat /var/log/lxc/102.log

  1. Now, disconnect USB device from host and then:
# lsusb 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 002: ID 80ee:0021 VirtualBox USB Tablet
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

  1. Now connect device and list devices again, here my device is Bus 002 Device 005: ID 0c4b:0600 Reiner SCT Kartensysteme GmbH.
# lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 005: ID 0c4b:0600 Reiner SCT Kartensysteme GmbH
Bus 002 Device 002: ID 80ee:0021 VirtualBox USB Tablet
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

5. Now, by taking the Bus and Device from the previous output.

# ls -l /dev/bus/usb/002/005
crw-rw-rw- 1 root root 189, 132 Jun 20 22:39 /dev/bus/usb/002/005
  1. Edit the following file, appending the following at the end. Here 002, 005 and 189 were taken from the previous outputs.
# cat /etc/pve/lxc/102.conf
...
lxc.cgroup.devices.allow: c 189:* rwm
lxc.mount.entry: /dev/bus/usb/002/005 dev/bus/usb/002/005 none bind,optional,create=file
  1. Start the CT with the following command:

# pct start 102

  1. Then inspect the log again. If there are no new errors there the passthrough worked.

# cat /var/log/lxc/102.log

@schannall

This comment has been minimized.

Copy link

@schannall schannall commented Jan 10, 2019

Hi,
would you mind adding the source for the gistfile1.txt ? Thanks.

@bugsysiegals

This comment has been minimized.

Copy link

@bugsysiegals bugsysiegals commented Jan 14, 2019

And how exactly do we access the USB? After these steps, I don't see anything using fdisk -l in order to mount it to a directory.

@Dayve67

This comment has been minimized.

Copy link

@Dayve67 Dayve67 commented Apr 21, 2019

i followed the instructions above and my will bind with the CT just fine. But if I happen to shutdown or restart the Host for any reason the device number will change to something different. Then I need to edit the "conf" file with the new device number and also allow permission to the Host with "chmod o+rw /dev/ttyACM0" again to get it working. Is this normal for this to happen?

Wonder if a cron job could be done to update the device ID on a restart of the Host to solve this?

@mhaluska

This comment has been minimized.

Copy link

@mhaluska mhaluska commented Aug 25, 2019

i followed the instructions above and my will bind with the CT just fine. But if I happen to shutdown or restart the Host for any reason the device number will change to something different. Then I need to edit the "conf" file with the new device number and also allow permission to the Host with "chmod o+rw /dev/ttyACM0" again to get it working. Is this normal for this to happen?

Wonder if a cron job could be done to update the device ID on a restart of the Host to solve this?

Hey, I did it little bit different way and it's working with persistent path using udev rules...

On Proxmox:

Get USB idProduct and idVendor:

# lsusb
...
Bus 001 Device 005: ID 12d1:1001 Huawei Technologies Co., Ltd. E161/E169/E620/E800 HSDPA Modem
...

Create udev rule:

# vi /etc/udev/rules.d/98-sms-modem.rules
SUBSYSTEMS=="usb", KERNEL=="ttyUSB*", ATTRS{idProduct}=="1001", ATTRS{idVendor}=="12d1", SYMLINK+="sms", MODE="0660", GROUP="dialout"

Reload and trigger udev:

# service udev reload
# udevadm trigger

Get cgroup config:

# ls -l /dev/sms
lrwxrwxrwx 1 root root 7 Aug 25 11:22 /dev/sms -> ttyUSB2

# ls -l /dev/ttyUSB2
crw-rw---- 1 root dialout 188, 2 Aug 25 12:13 /dev/ttyUSB2

Update your LXC config:

# vi /etc/pve/lxc/113.conf

...
lxc.cgroup.devices.allow: c 188:* rwm
lxc.mount.entry: /dev/sms dev/sms none bind,optional,create=file

On your LXC container:

In my case I'm using this modem with smstools, so in config I pointed smstools to /dev/sms.

It works like a charm ;-)

@hydra

This comment has been minimized.

Copy link

@hydra hydra commented Oct 27, 2020

Since I found some info here useful, and this was linked from the proxmox forum I'm just gonna raw-dump some info on how I went about adding a USB camera to a Xpenology NAS VM running Surveillance Station.

Use USB webcam in Surveillance Station, without installing additional packages in the Synology NAS.

Although there is a way to use Camera via the Linux installation in the Synology NAS VM the method of doing so is not up-to-date and adds a un-contained dependency to the solution. - If you want to go this route see here: https://community.synology.com/enu/forum/3/post/119524

The reason I don't want to use it is that I never want to have the lack of current webcam drivers in the NAS VM preventing me from an upgrade of the NAS OS.

Host: Proxmox 6.2
VM: NAS, Xpenology.
LXC: Runs docker containers (nested).

Assign webcam consistent linux device name so any USB port can be used

Camera: Logitech C270

https://www.logitech.com/en-us/products/webcams/c270-hd-webcam.960-000694.html
https://support.logi.com/hc/en-us/articles/360024320953

Connect camera to a USB port.

https://wiki.openrobotino.org/index.php?title=USB_cameras

root@proxmox:/etc/udev/rules.d# udevadm info -a -p $(udevadm info -q path -n /dev/video0)

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '//devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0/video4linux/video0':
    KERNEL=="video0"
    SUBSYSTEM=="video4linux"
    DRIVER==""
    ATTR{dev_debug}=="0"
    ATTR{name}=="UVC Camera (046d:0825)"
    ATTR{index}=="0"

  looking at parent device '//devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0':
    KERNELS=="1-3:1.0"
    SUBSYSTEMS=="usb"
    DRIVERS=="uvcvideo"
    ATTRS{authorized}=="1"
    ATTRS{iad_bFunctionClass}=="0e"
    ATTRS{iad_bFunctionSubClass}=="03"
    ATTRS{iad_bFirstInterface}=="00"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bInterfaceClass}=="0e"
    ATTRS{iad_bFunctionProtocol}=="00"
    ATTRS{bInterfaceProtocol}=="00"
    ATTRS{iad_bInterfaceCount}=="02"
    ATTRS{supports_autosuspend}=="1"
    ATTRS{bNumEndpoints}=="01"
    ATTRS{bInterfaceNumber}=="00"
    ATTRS{bInterfaceSubClass}=="01"

  looking at parent device '//devices/pci0000:00/0000:00:14.0/usb1/1-3':
    KERNELS=="1-3"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{bDeviceSubClass}=="02"
    ATTRS{devnum}=="4"
    ATTRS{rx_lanes}=="1"
    ATTRS{bcdDevice}=="0012"
    ATTRS{bDeviceProtocol}=="01"
    ATTRS{idVendor}=="046d"
    ATTRS{bmAttributes}=="80"
    ATTRS{quirks}=="0x2"
    ATTRS{idProduct}=="0825"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{authorized}=="1"
    ATTRS{speed}=="480"
    ATTRS{bNumInterfaces}==" 4"
    ATTRS{configuration}==""
    ATTRS{serial}=="8B992520"
    ATTRS{version}==" 2.00"
    ATTRS{bDeviceClass}=="ef"
    ATTRS{devpath}=="3"
    ATTRS{ltm_capable}=="no"
    ATTRS{maxchild}=="0"
    ATTRS{urbnum}=="2049"
    ATTRS{busnum}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{bMaxPower}=="500mA"
    ATTRS{tx_lanes}=="1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{removable}=="removable"

  looking at parent device '//devices/pci0000:00/0000:00:14.0/usb1':
    KERNELS=="usb1"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{manufacturer}=="Linux 5.4.65-1-pve xhci-hcd"
    ATTRS{bmAttributes}=="e0"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{authorized}=="1"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{idProduct}=="0002"
    ATTRS{authorized_default}=="1"
    ATTRS{speed}=="480"
    ATTRS{devnum}=="1"
    ATTRS{ltm_capable}=="no"
    ATTRS{serial}=="0000:00:14.0"
    ATTRS{busnum}=="1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{configuration}==""
    ATTRS{devpath}=="0"
    ATTRS{version}==" 2.00"
    ATTRS{interface_authorized_default}=="1"
    ATTRS{bMaxPower}=="0mA"
    ATTRS{maxchild}=="16"
    ATTRS{product}=="xHCI Host Controller"
    ATTRS{tx_lanes}=="1"
    ATTRS{bDeviceClass}=="09"
    ATTRS{idVendor}=="1d6b"
    ATTRS{bDeviceProtocol}=="01"
    ATTRS{urbnum}=="252"
    ATTRS{rx_lanes}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{quirks}=="0x0"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{removable}=="unknown"
    ATTRS{bcdDevice}=="0504"

  looking at parent device '//devices/pci0000:00/0000:00:14.0':
    KERNELS=="0000:00:14.0"
    SUBSYSTEMS=="pci"
    DRIVERS=="xhci_hcd"
    ATTRS{dma_mask_bits}=="64"
    ATTRS{index}=="3"
    ATTRS{driver_override}=="(null)"
    ATTRS{vendor}=="0x8086"
    ATTRS{dbc}=="disabled"
    ATTRS{consistent_dma_mask_bits}=="64"
    ATTRS{subsystem_vendor}=="0x1849"
    ATTRS{device}=="0x06ed"
    ATTRS{msi_bus}=="1"
    ATTRS{subsystem_device}=="0x06ed"
    ATTRS{numa_node}=="-1"
    ATTRS{local_cpus}=="ff"
    ATTRS{d3cold_allowed}=="1"
    ATTRS{irq}=="137"
    ATTRS{revision}=="0x00"
    ATTRS{local_cpulist}=="0-7"
    ATTRS{broken_parity_status}=="0"
    ATTRS{enable}=="1"
    ATTRS{class}=="0x0c0330"
    ATTRS{ari_enabled}=="0"
    ATTRS{label}=="Onboard - Other"

  looking at parent device '//devices/pci0000:00':
    KERNELS=="pci0000:00"
    SUBSYSTEMS==""
    DRIVERS==""
root@proxmox:~# vi /etc/udev/rules.d/50-camera0.rules

add

KERNEL=="video[0-9]*", SUBSYSTEM=="video4linux",ATTRS{idVendor}=="046d", ATTRS{idProduct}=="0825", ATTRS{serial}=="8B992520", SYMLINK+="camera0"

then

root@proxmox:~# udevadm control --reload-rules
root@proxmox:~# udevadm trigger
root@proxmox:~# ls -al /dev/cam*
lrwxrwxrwx 1 root root 6 Oct 27 14:01 /dev/camera0 -> video0

test camera

apt-get install fswebcam

root@proxmox:~# fswebcam -r 640x480 --jpeg 85 -D 1 -d /dev/camera0 test1.jpg
--- Opening /dev/camera0...
Trying source module v4l2...
/dev/camera0 opened.
No input was specified, using the first.
Delaying 1 seconds.
--- Capturing frame...
Captured frame in 0.00 seconds.
--- Processing captured image...
Setting output format to JPEG, quality 85
Writing JPEG image to 'test1.jpg'.

add camera to LXC container

root@proxmox:~# lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 046d:0825 Logitech, Inc. Webcam C270
Bus 001 Device 003: ID 8087:0aa7 Intel Corp.
Bus 001 Device 002: ID 26ce:01a2
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

root@proxmox:~# ls -al /dev/camera0
lrwxrwxrwx 1 root root 6 Oct 27 14:01 /dev/camera0 -> video0
root@proxmox:~# ls -al /dev/bus/usb/001/004
crw-rw-rw- 1 root video 189, 3 Oct 27 14:01 /dev/bus/usb/001/004

root@proxmox:~# vi /etc/pve/nodes/proxmox/lxc/103.conf

Add

lxc.cgroup.devices.allow: c 189:3 rwm
lxc.cgroup.devices.allow: c 81:0 rwm
lxc.mount.entry: /dev/bus/usb/001/004 dev/bus/usb/001/004 none bind,optional,create=file
lxc.mount.entry: /dev/camera0 dev/camera0 none bind,optional,create=file
lxc.mount.entry: /dev/video0 dev/video0 none bind,optional,create=file

^^^ not sure if the USB mount entry is really needed...

camera streaming software

https://github.com/jacksonliam/mjpg-streamer
https://hub.docker.com/r/kvaps/mjpg-streamer/

docker run \
    --device /dev/video0 \
    --entrypoint mjpg_streamer \
    -p 8090:8090 \
    kvaps/mjpg-streamer \
    -i "/usr/lib64/input_uvc.so -y -d /dev/video0 -r 1920x960 -f 15" \
    -o "/usr/lib64/output_http.so -p 8090 -w /usr/share/mjpeg-streamer/www/ -c admin:admin"

add camera to synology

Brand: [user define]
Type: Streaming - HTTP
Path: http://admin:admin@192.168.18.5:8090/?action=stream

settings

Success!

Next steps

  • update the docker instance to use the /dev/camera0 instance, tried but didn't work...
  • remove any unneeded config.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment