Hotplugger: Real USB Port Passthrough for VFIO/QEMU!

Related tags

Hardwarehotplugger
Overview

Hotplugger: Real USB Port Passthrough for VFIO/QEMU!

Welcome to Hotplugger! This app, as the name might tell you, is a combination of some scripts (python, yaml, udev rules and some QEMU args) to allow you to pass through an actual USB port into a VM. Instead of passing the USB root hub (which could have the side effect of passing all the ports, including the ones you didn't want to) or another PCIe hub or something, you can just pass a specific USB port to a VM and have the others free for anything else. Plus, it saves you from using the vfio-pci driver for the USB root hub, so you can keep using it for evdev or other things on the VM host.

Requirements

  • monitor.py and hotplugger.py require Python 3
  • Only tested with QEMU 5.0.0. Untested with older or newer versions.

Quick start (Ubuntu 20.10)

  1. git clone https://github.com/darkguy2008/hotplugger.git

  2. (Optional) run python3 monitor.py and follow the prompts. Basically once you hit Enter you have to plug and unplug an USB device (a thumbdrive or audio device preferred) into the USB ports that you want to know their DEVPATH route from. This will help you identify them so you can write them into config.yaml in the ports array. This array only accepts DEVPATH routes that UDEV generates.

  3. Edit config.yaml. It must stay in the same folder as monitor.py and hotplugger.py. Look at the current example: It's set for a Windows VM (the name doesn't matter, as long as it's unique within the entries of the same file). Make sure the socket property matches the file path of the QEMU chardev device pointing to an Unix domain socket file and in the ports array put the list of the udev DEVPATH of the USB ports you want to pass through to that VM:

    virtual_machines:
    
      windows:
        socket: /home/dragon/vm/test/qmp-sock
        ports:
          - /devices/pci0000:00/0000:00:14.0/usb3/3-1
          - /devices/pci0000:00/0000:00:14.0/usb3/3-2
          - /devices/pci0000:00/0000:00:14.0/usb4/4-1
          - /devices/pci0000:00/0000:00:14.0/usb4/4-2
    
  4. Create an /etc/udev/rules.d/99-zzz-local.rules file with the following content:

    SUBSYSTEM=="usb", ACTION=="add", RUN+="/bin/bash -c 'python3 /path-to-hotplugger/hotplugger.py >> /tmp/hotplugger.log' 2>&1"
    SUBSYSTEM=="usb", ACTION=="remove", RUN+="/bin/bash -c 'python3 /path-to-hotplugger/hotplugger.py >> /tmp/hotplugger.log' 2>&1"
    

    Make sure to change path-to-hotplugger with the path where you cloned the repo to, or installed the package. It can be simplified, but this one is useful in case you want to debug and see what's going on. Otherwise, proceed with a simpler file:

    SUBSYSTEM=="usb", ACTION=="add", RUN+="/bin/bash -c 'python3 /path-to-hotplugger/hotplugger.py'"
    SUBSYSTEM=="usb", ACTION=="remove", RUN+="/bin/bash -c 'python3 /path-to-hotplugger/hotplugger.py'"
    
  5. Create the QMP monitor Unix domain socket if you haven't already in your QEMU args. I use this:

    -chardev socket,id=mon1,server,nowait,path=./qmp-sock
    -mon chardev=mon1,mode=control,pretty=on
    
  6. Have a coffee!

Libvirt setup

This is a work in progress, but here's some steps to get you started:

  1. Edit your VM's XML config like this:

    1. <domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
        <name>QEMUGuest1name>
        <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809uuid>
        ...
        <qemu:commandline>
          <qemu:arg value='-chardev'/>
          <qemu:arg value='socket,id=mon1,server,nowait,path=/tmp/my-vm-sock'/>
          <qemu:arg value='-mon'/>
          <qemu:arg value='chardev=mon1,mode=control,pretty=on'/>
        qemu:commandline>
      domain>

      Add the xmlns attribute and the QEMU commandline arguments like that. The /tmp/my-vm-sock is the name of an unix domain socket. You can use any, just make sure to also put the same path in the config.yaml file.

  2. If you get a permissions issue, edit /etc/libvirt/qemu.conf and add security_driver = "none"to it to fix apparmor being annoying about it.

How it works

  1. The udev rule launches the script on every USB event. For each USB add/remove action there's around 3 to 5+ events. This allows the app to act at any step in the action lifecycle.
  2. In the first step it gets the kernel environment variables from udev and stores them in a temp file. In those variables, the DEVPATH, the DEVNUM (host address in QEMU, it seems to change and is sequential...) and the BUSNUM (bus address in QEMU) are captured. For the subsequent events, the following steps are run:
    1. It requests QEMU through the Unix socket and the info usbhost QMP command the USB info from the host. This gives it an extra field: The host port where the device is also connected to. Since I got the host and bus addresses in the first event, I can use that to parse through the info usbhost command's output and find the port connected to the device.
    2. If the port is found, using the device_add command, a new usb-host device is added using the USB bus and port we got in the previous step, and assigns it a predictable ID that it can use to unplug the device afterwards. To add this of course, the VM should have a usb-xhci device I think. Not sure if it's required or not, but I prefer to add it as I have USB 3.0 ports and devices.
    3. The temp file is cleared once the device_add command has run successfully.

Steps 2.1, 2.2 and 2.3 are run on every udev event. For instance, for an audio device it gets 3 or 4 events: One for the HID device, and two or so for the audio devices. My audio device (Corsair Void Elite Wireless) has both stereo audio and a communications device (mono audio, for mic) so for a single dongle like that I get those many events. Since these steps are ran on all the events, there's multiple chances to do the hotplug action. When one of them succeeds, the others will silently fail as QEMU will say that the same device ID is being used, so all is good.

Troubleshooting

If for some reason the app doesn't seem to work, try these methods:

  • Remove the /tmp folder where hotplugger.py is located
  • Reboot the computer
  • Reboot udev: sudo udevadm control --reload-rules && sudo udevadm trigger
  • View udev's logfile: sudo service udev restart && sudo udevadm control --log-priority=debug && journalctl -f | grep -i hotplugger
  • If you want to see what will be run when you plug a device, try with this command to simulate an udev event: udevadm test $(udevadm info -a --path=/devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1:1.0) --action=add replacing --path with the path of the USB port down to the device itself (in this case, I had a device connected to the usb3/3-1 port, identified as 3-1:1.0.

Thank you!

A lot of work and sleepless nights were involved in this procedure, so if this app helps you in any way or another, please consider sending a small donation, it helps a lot in these tough times!

Changelog

(2020-02-05)

  • Initial changelog writing
  • App was refactored a bit with improved python mad skillz. It also seems to be a bit more stable and robust, it doesn't hang much anymore and USB detection seems to work better. This is due to the fact that I added a stupid 1-second delay after all the USB UDEV events have gone through. Since there's no way to know when UDEV has "finished" sending all the events (and there could be a lot more) the commands being sent to QEMU to add the device will have to wait 1 second now. While it's not ideal, it should be enough to avoid a VM hanging up and I can live with that.
Owner
DARKGuy (Alemar)
DARKGuy (Alemar)
A flexible data historian based on InfluxDB, Grafana, MQTT and more. Free, open, simple.

Kotori Telemetry data acquisition and sensor networks for humans. Documentation: https://getkotori.org/ Source Code: https://github.com/daq-tools/koto

83 Nov 26, 2022
A circle of LEDs

This repository contains all the design files, production files and example code for a simple circular LED display.

Pim de Groot 15 Aug 21, 2022
BMP180 sensor driver for Home Assistant used in Raspberry Pi

BMP180 sensor driver for Home Assistant used in Raspberry Pi Custom component BMP180 sensor for Home Assistant. Copy the content of this directory to

747Developments 1 Dec 17, 2021
Pi-hole with Inky pHAT ePaper display

Pi-hole with Inky pHAT ePaper display This is my Pi-hole with an ePaper display.

11 Sep 13, 2022
This is the remake of the program PYOBD. It works on Python3 and all new libraries. It was tested on Linux, Windows, and it should work on MAC too.

This is the remake of the program PYOBD. It works on Python3 and all new libraries. It was tested on Linux, Windows, and it should work on MAC too. You just need an ELM327 USB or bluetooth device and

127 Jan 06, 2023
Simple Python script to decode and verify an European Health Certificate QR-code

A simple Python script to decode and verify an European Health Certificate QR-code.

Mathias Panzenböck 61 Oct 05, 2022
Christmasvillage-rpi - Raspberry Pi relay controller for ChristmasVillage.io

ChristmasVillage.io Relay Controller Links ChristmasVillage.io - Live Stream & Controls Youtube Instagram About This repository controls the light rel

Grant Windes 2 Feb 15, 2022
A Raspberry Pi Pico powered Macro board, like a Streamdeck but cheaper and simpler.

Env-MCRO A Raspberry Pi Pico powered Macro board, like a Streamdeck but cheaper and simpler. (btw this image is a bit outdated, some of the silkscreen

EnviousData 68 Oct 14, 2022
Simples Keylogger para Windows com um autoboot implementado no sistema

MKW Keylogger Keylogger simples para Windos com um autoboot implementado no sistema, o malware irá capturar pressionamentos de tecla e armazená-lo em

3 Jul 03, 2021
Turns a compatible Raspberry Pi device into a smart USB drive for PS4/PS5.

PSBerry A WIP project for Raspberry Pi, which turns a compatible RPI device into a smart USB drive for PS4/PS5. Allows for save management of PS4 game

Filip Tomaszewski 2 Jan 15, 2022
My self-hosting infrastructure, fully automated from empty disk to operating services

Khue's Homelab Current status: ALPHA This project utilizes Infrastructure as Code to automate provisioning, operating, and updating self-hosted servic

Khue Doan 6.4k Dec 31, 2022
Code for the onshape macropad.

Onshape_Macropad Code for the onshape macropad. This is a macropad built using the Pimoroni Keybow and the KPrepublic Enclosure. pimoroni_keybow kprep

Justin Cole 1 Nov 23, 2021
Robot Framework keyword library wrapper for atlassian-python-api

Robot Framework keyword library wrapper for atlassian-python-api

Marcin Koperski 3 Jul 29, 2022
Resmed_myair_sensors - This is a Home Assistant custom component to pull daily CPAP data from ResMed's myAir service using an undocumented API

resmed_myair This component will set up the following platforms. Platform Description sensor Show info from the myAir API. Installation Using the tool

Preston Tamkin 17 Dec 29, 2022
Raspberry Pi Pico and LoRaWAN from CircuitPython

Raspberry Pi Pico and LoRaWAN from CircuitPython Enable LoRaWAN communications on your Raspberry Pi Pico or any RP2040-based board using CircuitPython

Alasdair Allan 15 Oct 08, 2022
ArduinoWaterHeaterIOT - IoT Probe of a solar PV water heating system - Arduino, Python, MQTT, MySQL

ArduinoWaterHeaterIOT IoT Probe of a solar PV water heating system - Arduino, Raspberry Pi, Python, MQTT, MySQL The Arduino sends the AC and DC watts

Jacques Fourie 1 Jan 11, 2022
Run this code to blink your ThinkPad LED with a hidden mysterious Morse code! ;)

TMorse Run this code to blink your ThinkPad LED with a hidden mysterious Morse code! ;) Compatible with python3.9+. No third-party library is required

Mahyar 2 Jul 11, 2022
CircuitPython Driver for Adafruit 24LC32 I2C EEPROM Breakout 32Kbit / 4 KB

Introduction CircuitPython driver for Adafruit 24LC32 I2C EEPROM Breakout Dependencies This driver depends on: Adafruit CircuitPython Bus Device Regis

foamyguy 0 Dec 20, 2021
The PicoEMP is a low-cost Electromagnetic Fault Injection (EMFI) tool,

ChipSHOUTER-PicoEMP The PicoEMP is a low-cost Electromagnetic Fault Injection (EMFI) tool, designed specifically for self-study and hobbiest research.

NewAE Technology Inc. 312 Jan 07, 2023
HomeAssistant - Polyaire AirTouch 4 Integration

HomeAssistant - Polyaire AirTouch 4 Integration Custom integration to add an AirTouch 4 AC Controller Installation: Copy contents of custom_components

7 Aug 05, 2022