KVM USB Auto-Passthrough

I do all of my PC gaming on a Windows VM which I run on a Linux host running KVM. With a new gaming monitor on the way, I got the idea of using a DisplayPort/USB switcher to switch my keyboard, mouse, and monitor between my laptop and Windows VM (via KVM's USB passthrough). That way I can connect the monitor directly to the Windows VM and use its 144 Hz refresh rate instead of being stuck at what Linux is displaying along with the 30 or 60 fps provided by Parsec.

Before I buy that USB switcher, I need to make sure that I can have my USB devices to auto-connect to the VM when they get connected to my Linux host.

Through my cursory searching I couldn't find a way native to libvirt/qemu to do this, so udev to the rescue! Through udev rules, I'm able to detect when a device matching some parameters is connected, and then run a command. This command will get a bunch of environment variables set from udev. The interesting ones to us are:

  • ACTION - add, remove, etc.
  • ID_VENDOR_ID - the USB vendor ID
  • ID_MODEL_ID - the USB model ID.

To test this idea out, I set up a simple rule that matches against my keyboard and saved this as /etc/udev/rules.d/90-libvirt-usb.rules:

ACTION=="bind", \
  SUBSYSTEM=="usb", \
  ENV{ID_VENDOR_ID}=="6b62", \
  ENV{ID_MODEL_ID}=="6869", \
  RUN+="/usr/local/bin/kvm-udev attach steam"
ACTION=="remove", \
  SUBSYSTEM=="usb", \
  ENV{ID_VENDOR_ID}=="6b62", \
  ENV{ID_MODEL_ID}=="6869", \
  RUN+="/usr/local/bin/kvm-udev detach steam"

The VENDOR_ID and MODEL_ID can be found by running the lsusb command, which shows this as "ID vendor_id:model_id", for example "ID 6b62:6869".

And of course, here's the script /usr/local/bin/kvm-udev which takes care of the auto-connecting. It takes two parameters, first either being "attach" or "detach" and the second being the name of the KVM domain (aka VM).


# Usage: ./kvm-udev.sh attach|detach <domain>

set -e


CONF_FILE=$(mktemp --suffix=.kvm-udev)
cat << EOF >$CONF_FILE
<hostdev mode='subsystem' type='usb'>
    <vendor id='0x${ID_VENDOR_ID}' />
    <product id='0x${ID_MODEL_ID}' />

virsh "${ACTION}-device" "$DOMAIN" "$conf_file"

This writes out a temporary file which contains some libvirt XML config for doing device passthrough, picking details from the environment variables that udev sets. It then calls virsh to attach/detach the device to the given domain using that temporary config file.

And with that, every time I plug my keyboard into my KVM host, it automatically routes it to my Windows VM! Now that this works, I can add an additional rule for my mouse, so that switching these devices between computers works smoothly.

read more

Home VPN with Wireguard

If you have an interest in Linux networking, by now you've probably heard of Wireguard. In case you haven't, it's a newer cross-platform VPN whose main attraction is that it's way way easier to set up on Linux than other VPNs that have come before it. If you've ever had to set up an IPSec VPN using Racoon or Openswan or StrongSwan or any other weird animal-based tool, then you know how much of a royal pain in the ass it is.

While I was on a tear improving my home network, I decided to finally bite the bullet and set Wireguard up on my router and laptop, allowing me to securely connect to my home network from anywhere. This post outlines what I did to make that happen, in case you want to replicate it in your own home network.

Fair bit of warning though: I'm assuming that you already have basic knowledge of networking: subnetting, routing, that kind of stuff.

read more


Here's a Linux utility that I recently learned about: Anacron

Simliar to cron, it runs tasks on a periodic basis, but it will ensure the task runs when the computer is on.

My use case is that I want my backup repository integrity check to run once a week on my laptop, but when a cron @weekly task is going fire (midnight on Sunday) my laptop's going to be turned off. Anacron to the rescue!

So what I did is set up an anacron task to run my backup check script once a week, and then set up cron to run anacron every 10 minutes:

*/10 * * * *  /usr/sbin/anacron -s -t $HOME/.anacron/tab -S $HOME/.anacron/spool

And here's what my anacrontab looks like:


# period  delay  job-id  command
# # (days)  (min)
7 0 backup-check  $HOME/bin/backup.check
read more

Visualizing Web Design Evolution Using Git

My website here, as of the time of writing this, is still based on a design I made back in 2010, and is rendered using my static site generator that I haven't touched in nearly as long. The site's served its purpose pretty well, but it's kind of a mess; It's unreadable on mobile devices, the CSS causes some weird inconsistencies, and the static site generator is no where near my current standards. So since this is a personal project I have the liberty of throwing it all in the trash and starting over (and learning new things along the way!).

read more