Add USB device passthrough design document
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0f52236f80
commit
a5582f4b29
1 changed files with 119 additions and 0 deletions
119
docs/plans/2026-03-17-usb-passthrough-design.md
Normal file
119
docs/plans/2026-03-17-usb-passthrough-design.md
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
# USB Device Passthrough Design
|
||||
|
||||
## Overview
|
||||
|
||||
USB device passthrough for vmsilo VMs via crosvm's USB hotplug interface. Supports both persistent attachment (declared in VM config, attached at VM start) and runtime attachment via `vmsilo-usb` CLI.
|
||||
|
||||
## Identifiers
|
||||
|
||||
- **Persistent config:** VID:PID (required) + optional serial number
|
||||
- **Runtime CLI:** VID:PID or devpath (physical USB port path like `1-3`)
|
||||
|
||||
When VID:PID matches multiple physical devices, all are attached (unless narrowed by serial).
|
||||
|
||||
## NixOS Options
|
||||
|
||||
New per-VM option in `programs.vmsilo.nixosVms.<vm>`:
|
||||
|
||||
```nix
|
||||
usbDevices = [
|
||||
{ vendorId = "17ef"; productId = "60e0"; }
|
||||
{ vendorId = "046d"; productId = "c52b"; serial = "A02019100900"; }
|
||||
];
|
||||
```
|
||||
|
||||
A NixOS assertion ensures no two VMs declare the same VID:PID+serial combination.
|
||||
|
||||
## State File
|
||||
|
||||
`/run/vmsilo/usb-state.json` — single global file tracking all USB attachments:
|
||||
|
||||
```json
|
||||
{
|
||||
"1-3": {
|
||||
"vid": "17ef",
|
||||
"pid": "60e0",
|
||||
"serial": null,
|
||||
"busnum": 1,
|
||||
"devnum": 2,
|
||||
"vm": "banking",
|
||||
"port": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Keyed by devpath. All operations acquire an exclusive `flock` on `/run/vmsilo/usb-state.lock` for the full read-modify-crosvm call-write cycle.
|
||||
|
||||
Ephemeral (lives in `/run`), matching the VM lifecycle.
|
||||
|
||||
## Runtime CLI — `vmsilo-usb`
|
||||
|
||||
### `vmsilo-usb` (no args) — list devices
|
||||
|
||||
Displays all host USB devices with attachment status:
|
||||
|
||||
```
|
||||
VID:PID Port Serial Manufacturer Product VM
|
||||
17ef:60ee 1-3 - Lenovo TrackPoint Keyboard II -
|
||||
05e3:0610 1-6 - - USB2.0 Hub -
|
||||
26ce:01a2 9-1 A02019100900 ASRock LED Controller untrusted
|
||||
```
|
||||
|
||||
Reads sysfs for device info, merges with state file for VM assignments. No root required.
|
||||
|
||||
### `vmsilo-usb attach <vm> <vid:pid|devpath>`
|
||||
|
||||
1. Resolve identifier to physical device(s) via sysfs
|
||||
2. Acquire lock, read state file
|
||||
3. For each matching device: if attached to another VM, detach from old VM first (`crosvm usb detach`)
|
||||
4. Call `crosvm usb attach` on target VM
|
||||
5. Update state file, release lock
|
||||
|
||||
Runs via polkit — invokes a systemd oneshot template that runs as root.
|
||||
|
||||
### `vmsilo-usb detach <vm> <vid:pid|devpath>`
|
||||
|
||||
1. Acquire lock, read state file
|
||||
2. Find matching entries for that VM
|
||||
3. Call `crosvm usb detach`
|
||||
4. Remove entries from state file, release lock
|
||||
|
||||
Same polkit mechanism as attach.
|
||||
|
||||
## Persistent Attachment
|
||||
|
||||
### On VM Start
|
||||
|
||||
`vmsilo-<vm>-usb-attach.service` — a oneshot unit with `After=` and `Requires=` on the VM service:
|
||||
|
||||
1. Wait for the crosvm control socket to appear
|
||||
2. For each configured `usbDevices` entry: scan sysfs for matching VID:PID (+ serial if specified)
|
||||
3. Attach all matches via `crosvm usb attach`, update state file under lock
|
||||
4. If a device isn't plugged in, log a warning and continue
|
||||
|
||||
### On VM Stop
|
||||
|
||||
ExecStopPost in the VM service removes that VM's entries from the state file under lock. No `crosvm usb detach` needed since the VM is shutting down.
|
||||
|
||||
## Permission Model
|
||||
|
||||
- `vmsilo-usb attach/detach` use polkit, same as `vm-start`/`vm-stop`
|
||||
- Implemented as systemd oneshot template services authorized via existing vmsilo polkit rules
|
||||
- `crosvm usb attach` runs as root (needs USB device fd + control socket access)
|
||||
- `vmsilo-usb` (listing) needs no privileges — reads sysfs and the state file
|
||||
|
||||
## crosvm Interface
|
||||
|
||||
- `crosvm usb attach BUS_ID:ADDR:BUS_NUM:DEV_NUM DEV_PATH SOCKET_PATH` — opens device fd, passes to VM over control socket
|
||||
- `crosvm usb detach PORT SOCKET_PATH` — detaches by crosvm port number
|
||||
- `crosvm usb list SOCKET_PATH` — returns `{port, vendor_id, product_id}` per device
|
||||
- Control socket at `/run/vmsilo/<vm>-crosvm-control.socket`
|
||||
- USB enabled by default in crosvm (no extra flags needed)
|
||||
|
||||
## Files Modified
|
||||
|
||||
- `modules/options.nix` — `usbDevices` option
|
||||
- `modules/assertions.nix` — duplicate VID:PID+serial assertion
|
||||
- `modules/scripts.nix` — `vmsilo-usb` script, USB helper functions (sysfs enumeration, state file with flock, resolution logic)
|
||||
- `modules/services.nix` — `vmsilo-<vm>-usb-attach.service`, ExecStopPost state cleanup, polkit oneshot templates for runtime
|
||||
- `modules/package.nix` — symlink `vmsilo-usb` into `$out/bin/`
|
||||
Loading…
Add table
Add a link
Reference in a new issue