libvirt-hotplug-usb
A daemon that watches Linux USB hot-plug events and passes matching devices through to a libvirt guest. No udev rules or other host configuration are required.
Building
$ cargo build --release
By default the binary loads libvirt.so.0 at runtime, so building does not require libvirt headers.
To link against libvirt at build time instead (requires libvirt-dev/pkg-config), build with the link-virt feature:
$ cargo build --release --features link-virt
Usage
libvirt-hotplug-usb [OPTIONS] --domain <NAME> --rule <EXPR>...
-c, --connect <URI> libvirt URI (default qemu:///system)
-d, --domain <NAME> target domain (required)
-r, --rule <EXPR> match rule, repeatable (rules are ORed)
--detach-on-exit detach devices this process attached on exit
--dry-run log matching devices without attaching
-v, --verbose increase verbosity (repeatable)
Rule grammar
rule := criterion (',' criterion)*
criterion := 'id=' (HEX ':' | ':' HEX | HEX ':' HEX)
| 'serial=' STR
| 'bus=' (DEC | PATH)
| 'port=' (DEC | DEC ('.' DEC)*)
| 'hub(' rule ')'
Criteria within a rule are ANDed, separate --rule arguments are ORed.
id=1234:: any device with VID1234id=:abcd: any device with PIDabcdid=1234:abcd: exact VID:PID pairserial=12345678: exact serial numberbus=3: devices on USB bus 3bus=/sys/bus/usb/devices/usb3: same, but by sysfs pathport=1: devices under top-level port 1 of the busport=1.4: devices under the1.4port path (i.e. behind the hub on port 1)hub(...): devices with any ancestor hub matching the nested rule
Examples:
# All bus-3 devices with VID 1234
$ libvirt-hotplug-usb -d myvm -r 'bus=3,id=1234:'
# Devices under a 1234:abcd hub that is itself on bus 2
$ libvirt-hotplug-usb -d myvm -r 'hub(id=1234:abcd,bus=2)'
# Union: exact pair, VID-only, or a serial number
$ libvirt-hotplug-usb -d myvm -r 'id=5678:1234' -r 'id=cafe:' -r 'serial=11111111'
bus= accepts either a bus number or a path to the bus/root hub, which is resolved once at startup.
Privileges
qemu:///systemnormally requires root or membership in thelibvirtgroup (plus a polkit rule).- Subscribing to kernel uevents may also require elevated privileges depending on the kernel/net-namespace configuration.
Either run the daemon as root, or with sufficient privileges to both access libvirt's system socket and receive kernel uevents.
Example systemd unit
See contrib/libvirt-hotplug-usb.service.
How it works
At startup the daemon scans /sys/bus/usb/devices and processes every device that already matches.
It then subscribes to kernel uevents via a NETLINK_KOBJECT_UEVENT socket and attaches matching devices as soon as they are connected.
Hubs (bDeviceClass == 0x09) are never passed through--only devices connected through them.
Matching devices are hot-plugged into the target domain with libvirt's virDomainAttachDeviceFlags(..., VIR_DOMAIN_AFFECT_LIVE), using:
Known limitations
- No configuration file yet (command line only).
- The daemon needs to be restarted to add/remove rules.
- One target domain per process.
- The daemon is single-threaded--a slow libvirt call briefly delays event handling.
- A physically re-plugged device that the domain still references may require a detach before re-attach.