Hi There,
a quick hotwo on how to use Linux’s usbip package to connect a remote USB device to a linux host in a way that is transparent to apps expecting the USB connection to be local
┌─────────────────────────────┐ ┌────────────────────────────────┐
│ │ │ │
│ │ │ │
│ ┌──────────────────┐ │ │ ┌───────────────────┐ │
│ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │
│ │ Server ◄───┼───────────────────┼─► Raspberry │ │
│ │ │ │ Ethernet │ │ │ │
│ │ │ │ │ │ │ │
│ └──────────────────┘ │ │ └────────▲──────────┘ │
│ │ │ │ │
│ │ │ │ │
│ │ │ │ USB │
│ Attic │ │ │ │
└─────────────────────────────┘ │ │ │
│ ┌───┬───┐▼──┬───┬───┐ │
│ │ │ │ │ │ │ │
│ ├───┼───┼───┼───┼───┤ │
│ │ │ │ │ │ │ │
│ ├───┼───┼───┼───┼───┤ │
│ │ │ │ │ │ │ │
│ └───┴───┴───┴───┴───┘ │
│ Streamdeck │
│ │
│ Desk │
└────────────────────────────────┘
WHAT ?
this post would like to explain how to use Linux’s usbip package to attach an USB peripheral physically connected to an USB port of a remote host and have it appear as a standard, local USB device
WHY ?
My use case, I am using an Elgato Streamdeck as a control surface to operate a headless proxmox server that has been moved in my attic, so that I can start VMs, stop VMs, check the server status without needing a remote session/laptop to do it. SInce the distance between the attic and my desk is over 10M (and I don’t have space in my conduits) I used a raspberry Pi I had Lying around to keep the streamdeck on my desk, but have it presented as a physical usb device to the server in the attic
HOW?
USB Server - Raspberry Pi2, connected to the streamdeck using a standard USB cable:
root@deckmaster01:~# lsusb
Bus 001 Device 004: ID 0fd9:0060 Elgato Systems GmbH Stream Deck
Install the usbip package
apt-get install usbip
In my case it’s already installed
root@deckmaster01:~# apt-cache policy usbip
usbip:
Installed: 2.0+5.10.103-1+rpi1
Candidate: 2.0+5.10.103-1+rpi1
Version table:
*** 2.0+5.10.103-1+rpi1 500
500 http://raspbian.raspberrypi.org/raspbian bullseye/main armhf Packages
100 /var/lib/dpkg/status
Load the usbip_host module and make sure it survives reboots:
root@deckmaster01:~# modprobe usbip_host
root@deckmaster01:~# echo usbip_host >> /etc/modules-load.d/modules.conf
Check that the peripheral you want to share is supported
root@deckmaster01:~# usbip list -l
usbip: error: Protocol spec without prior Class and Subclass spec at line 23299
- busid 1-1.1 (0424:ec00)
Microchip Technology, Inc. (formerly SMSC) : SMSC9512/9514 Fast Ethernet Adapter (0424:ec00)
- busid 1-1.2 (0fd9:0060)
Elgato Systems GmbH : Stream Deck (0fd9:0060)
Create a generic service for the usbip host module(I use raspbian so systemd):
root@deckmaster01:~# cat /etc/systemd/system/[email protected]
[Unit]
Description=USB-IP Binding on bus id %I
After=network-online.target usbipd.service
Wants=network-online.target
Requires=usbipd.service
#DefaultInstance=1-1.5
[Service]
Type=simple
ExecStart=/usr/sbin/usbip bind -b %i
RemainAfterExit=yes
ExecStop=/usr/sbin/usbip unbind -b %i
Restart=on-failure
[Install]
WantedBy=multi-user.target
Enable the service using the port id of the peripheral you want to share (in my case 1-1.2):
root@deckmaster01:~# systemctl enable [email protected]
root@deckmaster01:~# systemctl status [email protected]
● [email protected] - USB-IP Binding on bus id 1/1.2
Loaded: loaded (/etc/systemd/system/[email protected]; enabled; vendor preset: enabled)
Active: active (exited) since Fri 2022-05-20 06:23:56 BST; 3 days ago
Process: 543 ExecStart=/usr/sbin/usbip bind -b 1-1.2 (code=exited, status=0/SUCCESS)
Main PID: 543 (code=exited, status=0/SUCCESS)
May 20 06:23:56 deckmaster01 systemd[1]: Started USB-IP Binding on bus id 1/1.2.
May 20 06:23:57 deckmaster01 usbip[543]: usbip: info: bind device on busid 1-1.2: complete
Test that the device has been exported as expected:
root@deckmaster01:~# usbip list --remote=127.0.0.1
Exportable USB devices
======================
- 127.0.0.1
1-1.2: Elgato Systems GmbH : Stream Deck (0fd9:0060)
: /sys/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2
: (Defined at Interface level) (00/00/00)
root@deckmaster01:~#
This should complete the configuration on the USB server host
USB Client - In my case a proxmox server running an instance of deckmaster, a linux go client for the streamdeck that allows configuring specific actions for each streamdeck button
Install the usbip package:
apt-get install usbip
Check that the remote USB host is reachable and has a device available to share:
root@pve:~# usbip list -r 172.30.2.208
usbip: error: Protocol spec without prior Class and Subclass spec at line 23299
Exportable USB devices
======================
- 172.30.2.208
1-1.2: Elgato Systems GmbH : Stream Deck (0fd9:0060)
: /sys/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2
: (Defined at Interface level) (00/00/00)
List your local usb bus attached devices:
root@pve:~# lsusb
Bus 009 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 010 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 006 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 005 Device 005: ID 046b:ff10 American Megatrends, Inc. Virtual Keyboard and Mouse
Bus 005 Device 004: ID 046b:ffb0 American Megatrends, Inc. Virtual Ethernet
Bus 005 Device 006: ID 046b:ff20 American Megatrends, Inc. Virtual Cdrom Device
Bus 005 Device 003: ID 046b:ff01 American Megatrends, Inc. Virtual Hub
Bus 005 Device 002: ID 05e3:0610 Genesys Logic, Inc. Hub
Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 008 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 007 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Manually attach the remote device - testing phase:
Syntax is: usbip attach -r -b
root@pve:~# usbip attach -r 172.30.2.208 -b 1-1.2
root@pve:~# lsusb
Bus 009 Device 011: ID 0fd9:0060 Elgato Systems GmbH Stream Deck
Test that whatever local software is expected to see/use the USB device works as expected
Once you are satisfied and ready to make the config permanent:
Detach the USB device:
/usr/sbin/usbip detach --port=0
create a local service to connect the device at every start of the client:
(note I have kept it dumb and hardcoded the remote server IP
root@pve:~# cat /etc/systemd/system/[email protected]
[Unit]
Description=USB/IP bind service
After=network.target
Requires=
[Service]
Type=simple
ExecStart=/usr/sbin/usbip attach -r 172.30.2.208 --busid %i
ExecStop=/usr/sbin/usbip detach --port=0
RemainAfterExit=yes
Restart=on-failure
[Install]
WantedBy=multi-user.target
Enable the service
systemctl enable [email protected]
Check that the service started properly:
root@pve:~# systemctl start [email protected]
root@pve:~# !jo
journalctl -u [email protected] -f
-- Journal begins at Thu 2022-04-28 09:32:45 CEST. --
May 23 14:15:13 pve systemd[1]: Started USB/IP bind service.
Make sure you still have the proper local usb device
root@pve:~# !lsusb
lsusb
Bus 009 Device 012: ID 0fd9:0060 Elgato Systems GmbH Stream Deck
And … you’re good to go (in my case, starting the deckmaster service)
journalctl -u deckmaster -f
-- Journal begins at Thu 2022-04-28 09:32:45 CEST. --
May 23 14:06:08 pve systemd[1]: deckmaster.service: Succeeded.
May 23 14:16:39 pve systemd[1]: Started Deckmaster.
May 23 14:16:39 pve dbus-daemon[442301]: [session uid=0 pid=442299] AppArmor D-Bus mediation is enabled
May 23 14:16:39 pve appgoservice[442290]: Found device with serial AL31H1B07920 (firmware 1.0.191203
May 23 14:16:39 pve appgoservice[442290]: )
May 23 14:16:48 pve appgoservice[442290]: Mqtt update skip
May 23 14:16:48 pve appgoservice[442290]: 2022/05/23 14:16:48 MEROSS Init
May 23 14:16:48 pve appgoservice[442290]: 2022/05/23 14:16:48 Handling TOPIC: /app/pve-streamdeck/publish