A Rust library to run a USB/IP server to simulate USB devices and share real USB devices over a network.
USB/IP is a network protocol that allows USB devices to be shared between computers over a network. It enables:
- Device simulation: Create virtual USB devices that can be accessed remotely
- Device sharing: Share physical USB devices from one machine to another
- Cross-platform: Works across different operating systems (Linux, etc.)
Install Rust from the official documentation.
git clone https://github.com/jiegec/usbip.git
cd usbip
cargo build --releaseThe examples/ directory contains four example programs:
- hid_keyboard: Simulate a HID keyboard that types something every second
- cdc_acm_serial: Simulate a CDC ACM serial device that receives a character every second
- host: Act as a USB/IP server, sharing physical devices from the host machine to remote clients
- demo: Simulate a HID keyboard and a CDC ACM serial device together (used by the QEMU test)
cargo run --example hid_keyboardOn the client machine (e.g. Linux with USB/IP support):
# List available devices
usbip list -r $remote_ip
# Attach to a device
usbip attach -r $remote_ip -b $bus_idThe simulated devices can be verified against a real Linux kernel booted under
QEMU. The test assembles a minimal initramfs (busybox + usbip tool + the demo
server + the kernel's usbip/vhci/cdc/hid modules), boots it, then uses vhci-hcd
to attach the simulated keyboard and serial device. Inside the guest it confirms
the serial port emits 'a' and that the keyboard generates a KEY_1 input
event.
Run it locally (requires qemu-system-x86, a static busybox, cpio, and the
usbip tool):
./scripts/qemu/run-qemu-test.sh --build --dump-logIt runs under KVM when available and falls back to QEMU TCG otherwise. The
kernel, vmlinuz and module tree used can be overridden via the KERNEL, VMLINUZ
and MODTREE environment variables (useful to reproduce a CI kernel locally).
In CI (scripts/qemu + .github/workflows/qemu.yml) the Ubuntu generic kernel
is installed and booted. This matters because the GitHub runner's Azure kernel
has CONFIG_USB_HID disabled, so it cannot enumerate a simulated USB keyboard;
the generic kernel ships the hid/hid-generic/usbhid modules which are loaded
in the guest so both the serial device and the keyboard are verified.
The host example is tested the same way, with emulated devices: a SuperSpeed
UAS device (usb-uas) and a SuperSpeed bulk-only device (usb-bot) on an
emulated xHCI controller, plus a high-speed usb-storage device on an emulated
EHCI controller. Inside the guest the example exports them over USB/IP -- first
with the nusb backend, then with libusb/rusb -- and the guest attaches them back
through vhci-hcd. The test checks that each virtual copy enumerates at the same
speed, with the same bMaxPacketSize0 (the exponent 9, i.e. 512 bytes, at
SuperSpeed) and the same bcdUSB as the real device, and it writes and reads back
a block through both bulk-only devices, exercising bulk IN/OUT and the
SuperSpeed endpoint companion descriptors. The UAS device is only enumerated:
vhci-hcd does not support streams, which the Linux UAS driver requires at
SuperSpeed.
./scripts/qemu/run-qemu-passthrough-test.sh --build --dump-logMIT License - see LICENSE file for details.