Skip to content

Using USB-IP

Sharing USB device over IP.

Installing USB IP

To install usbip the package needs linux-tools-common be installed.

apt install linux-tools-common usb.ids

Fix for missing usb.ids file

To fix an error like usbip: error: failed to open /usr/share/hwdata//usb.ids Create the missing directory and symbolic link.

On Ubuntu 20.04 perform the following to fix it.

ln -s -t /usr/share/hwdata/ /var/lib/usbutils/usb.ids 

Install Kernel Module from Source (optional)

The Armbian distro has no usbip_host kernel module available and need to be compiled from source.
To build the kernel module and accompanied libraries from source additional packages are needed to be installed.

Tool and Source Packages

Packages to allow building from source.

apt install libtool libudev-dev

Kernel source packages (Armbian only)

Get the installed kernel version using uname.

  • linux-headers-current-sunxi
  • linux-source-<?ver-num?>-current-sunxi

Automated command (Armbian only)

apt install \
"linux-source-$(uname -r | sed 's/^\([0-9.]*\)-\([a-z]*\)$/\1-current-\2/')" \
"linux-headers-current-$(uname -r | sed 's/^\([0-9.]*\)-\([a-z]*\)$/\2/')" 

Source Unpacking

Unpacking the compressed kernel source using all cores to speed things up.

mkdir -p "/usr/src/linux-source-$(uname -r)" & \
tar -I 'xz -dT0' -C "/usr/src/linux-source-$(uname -r)" -xf "/usr/src/linux-source-$(uname -r).tar.xz"  

Preparation & Compiling

Move to the usbip source directory and execute the autogen.sh script.

cd "/usr/src/linux-source-$(uname -r)/tools/usb/usbip"
./autogen.sh

Configure before compiling omitting TCP wrappers in this case

./configure --with-tcp-wrappers=no

Compile and install using this one command.

make install
Cleanup after building (optional)

./cleanup.sh

Fix Finding the Library

Since dynamic loadable library is stored in /usr/local/lib the usbip command must be guided to the library location.

LD_LIBRARY_PATH=/usr/local/lib/libusbip.so.0 usbip
Another way is to create a symlink in the /usr/lib or use '/etc/ld.so.conf.d/' and run the ldconfig command. Probably no additional config file is required since /usr/local/lib/ is mostly already configured and only the ldconfig command needs to be executed.

Configuring Client

The client is the system which gets a virtual USB assigned to it.

Load the next needed kernel modules.

modprobe -a usbip_core vhci_hcd

Binding the USB device by ID.

usbip attach --remote <host-name/ip-address> --busid=<device-id>

Listing the bound devices.

usbip port

Detaching a bound device where port is the number found using the previous command.

usbip detach --port=<port>

Configuring Host/Server

The host/server is the system which has the actual physical connected USB device.

Load the next needed kernel modules.

modprobe usbip_core 
modprobe usbip_host

Starting the daemon to open a default listing port on ipv4.

usbipd --ipv4 --debug

Or start as daemon.

pusbipd --ipv4 --debug --daemon

List available devices with their bus-ids.

usbip list --local

Binding the USB device using the bus-id form the previous command. When the USB-device is disconnected from the system the bind is remove automatically.

usbip bind --busid=1-1

Unbinding the USB device.

 usbip unbind -b <device-id>

Attaching remote device.

usbip attach -r <server IP address> -b <Device bus ID>

Detaching remote device.

usbip detach -r <server IP address> -b <Device bus ID>

Daemonizing

Install Host USB device event handler

Creating trigger when any device is plugged in. A rule is added in directory /etc/udev/rules.d/. Create a file 99-device-plugged.rules

ACTION=="add"\
, ATTRS{idVendor}=="****" \
, ATTRS{idProduct}=="****" \
, SUBSYSTEMS=="usb" \
, RUN+="/usr/local/bin/usbip_dev_binding.sh"

The script /usr/local/bin/usbip_dev_binding.sh.

#!/bin/bash

# For debugging purposes write the environment to a file.
#env > /tmp/env.out

# Give the system some time.
sleep 2
# Bind the usb port using the bus-id.
usbip bind --busid=1-1

# Prevent service from stumbling on a non-zero exit code.
exit 0

Do not forget to make the file executable (chmod +x).

Install Host Systemd Service

Create file /etc/systemd/system/usbip.service.

[Unit]
Description=USB over IP
After=network-online.target

[Service]
Type=simple
User=root
Group=root
UMask=027
PIDFile=/var/run/usbipd.pid

ExecStartPre=/usr/sbin/modprobe -a usbip_core usbip_host
ExecStart=/usr/bin/usbipd --ipv4 --debug --daemon --pid /var/run/usbipd.pid
ExecStartPost=/usr/local/bin/usbip_dev_binding.sh
Restart=on-failure

[Install]
WantedBy=multi-user.target

Enable it to start up on boot, start the service and verify it is running.

systemctl daemon-reload
systemctl enable usbip.service
systemctl start usbip
systemctl status usbip

Run Client Script to Attach

Create a file usbip-attach.sh

#!/bin/bash

SERVER="finsh"
BUS_ID="1-1"

modprobe -a usbip_core vhci_hcd

# Loop infinite
while [ true ]; do 

  # Check if the server is present checking the ssh port.
  if nc -z ${SERVER} 22 2> /dev/null; then
    usbip attach --remote ${SERVER} --busid=${BUS_ID} 2> /dev/null
  fi

  # Do not loop like crazy
  sleep 3

done

Run the script in the background forever using nohup

nohup usbip-attach.sh &