In this series of posts, we look at four methods of attaching or passing-through a USB drive to a Xen Project paravirtualized (“PV”) virtual machine.
The four methods discussed in this series include:
- using the DomU .cfg file to pass-through a formatted drive containing an existing filesystem;
- using the DomU .cfg file and LVM to pass-through a previously unformatted drive;
- using the xl usbctrl-attach and xl usbdev-attach commands; and,
- using the xl block-attach command to pass-through a drive to a running DomU.
As the first two USB pass-through methods were covered in previous posts, linked above, we now move on to the third method: the first of two methods that use the xl toolstack.
Using the xl usbctrl-attach and xl usbdev-attach Commands
Before we get started, I’m going to come right out and admit that this method didn’t work for me. I wish it did because, along with the fourth method, it appears to be the easiest way to pass-through a USB disk device to a running DomU virtual machine.
In simple terms, this method didn’t work for me because of my particular Dom0 and Xen Project hypervisor setup, which consists of Xen version 4.8.5-pre and Debian 9 Stretch. This setup is great, but it doesn’t come with the kernel modules needed to get the xl usbctrl-attach and xl usbdev-attach commands working.
Per the Xen Project wiki, there are two kernel modules required to get the above-mentioned xl commands working: the modules are xen-usbback and xen-usbfront.
To check whether you have these modules loaded on your Dom0, use the lsmod command:
$ lsmod
For more precise results, the output of lsmod may be piped through grep to search for modules with “xen” in their filename:
$ lsmod | grep xen xen_netback 57344 2 xen_blkback 45056 0 xen_gntdev 20480 2 xen_evtchn 16384 3 xenfs 16384 1 xen_privcmd 16384 16 xenfs
As you can see from the lsmod output generated on my Dom0, the xen-usbback and xen-usbfront modules are not loaded. Note that you wouldn’t normally see “front” kernel modules loaded in the Dom0 anyway. Xen kernel modules with the suffix “back” are intended for Dom0, whereas kernel modules with the suffix “front” are intended for the DomU.
If xen-usbback is not currently loaded in your Dom0 kernel, you can check to see if it’s available to be manually loaded. Available kernel modules are typically stored in the /lib/modules/ directory.
Use ls -R to recursively list the contents of the /lib/modules/ directory, and grep to filter the results:
$ ls -R /lib/modules | grep xen[[:punct:][:alnum:]]*ko$ xen-blkfront.ko xen-blkback.ko xen-tpmfront.ko xen-netfront.ko netxen_nic.ko xen-netback.ko xen-pcifront.ko xen-scsifront.ko xen_wdt.ko xen-acpi-processor.ko xen-evtchn.ko xen-gntalloc.ko xen-gntdev.ko xen-privcmd.ko xen-scsiback.ko xenfs.ko xen-pciback.ko
As listed above, 17 kernel modules containing “xen” in their name were found on my Dom0.[1] Unfortunately, xen-usbback and xen-usbfront were not in the output and, therefore, are not available to be loaded into my Dom0 kernel.
If you find the required modules in your /lib/modules/ directory, check out the modprobe command for loading xen-usbback into the Dom0 kernel.
Let’s ignore my configuration issues for now and imagine that we have the kernel modules required to pass-through a USB drive using the xl usbctrl-attach and xl usbdev-attach commands.
1. Using xl usbctrl-attach to Create USB Controller for the DomU
In the first step, we need to create a USB controller for the DomU that’s going to be using the USB drive. To create the controller, the command we execute is xl usbctrl-attach. More information on this and other xl commands may be found in both the xl and xl.cfg manpages.
# xl usbctrl-attach {name-of-domu} type=pv version=2 ports=8
When executing the above command, make sure to use the name of your DomU. Also, remember that this command is intended to be directed at a currently running DomU.
Note that type=pv was the only type that worked in my setup. The version=2 key/value pair instructs the system to use USB version 2 (USB version 3 is not available for type=pv).[2] Also, it’s my understanding that the ports key is equivalent to how many physical USB ports you want to emulate for the DomU (don’t quote me on this!).
Executing the xl usbctrl-attach command on my Dom0 resulted in the following output to terminal:
# xl usbctrl-attach {name-of-domu} type=pv version=2 ports=8 libxl: error: libxl_device.c:1086:device_backend_callback: unable to add device with path /local/domain/0/backend/vusb/2/0 libxl: error: libxl.c:2009:device_addrm_aocomplete: unable to add vusb with id 0 libxl_device_usbctrl_add failed.
In spite of this error message, executing the xl usb-list command, which lists the devices passed-through to the DomU, returned the following result:
# xl usb-list {name-of-domu} Devid Type BE state usb-ver ports 0 pv 0 1 2 8 Port 1: Port 2: Port 3: Port 4: Port 5: Port 6: Port 7: Port 8:
Executing xl usbctrl-attach on my Dom0 appears to have created a USB controller with Devid “0” for the specified DomU. Note as well that the new controller is configured with the key/value pairs as passed on the command line.
Now that we know how to attach a USB controller, if you need to detach a controller from the DomU, the command to use is xl usbctrl-detach. For best results, specify the controller you’d like to detach using the Device ID (“Devid”) found in the output of xl usb-list.
For example, to detach a USB controller with Devid “0”, the following command is used:
# xl usbctrl-detach {name-of-domu} 0
Executing this command on my Dom0 resulted in the following output to terminal:
# xl usbctrl-detach {name-of-domu} 0 libxl: error: libxl_device.c:1086:device_backend_callback: unable to remove device with path /local/domain/0/backend/vusb/2/0 libxl: error: libxl.c:2009:device_addrm_aocomplete: unable to remove vusb with id 0 libxl_device_usbctrl_remove failed.
However, the command appears to have worked since executing xl usb-list now returns nothing.
2. Using xl usbdev-attach to Pass-Through USB Device to the DomU
Assuming that you’ve successfully created a USB controller for the DomU using xl usbctrl-attach, the next step is to pass-through the USB device using xl usbdev-attach.
To avoid confusion, take note of the subtle differences in the command names used in steps 1 and 2: xl usbctrl-attach versus xl usbdev-attach. Despite the similarity in name, the commands do very different things: one creates a USB controller (think “creating physical USB ports”), whereas the other attaches a USB device to that controller (think “plugging device in to physical USB port”).
When passing-through the USB drive using xl usbdev-attach, you need to figure out which bus the drive is attached to on the Dom0, and also the drive’s assigned device number. This information can be found with the lsusb utility.
$ lsusb
The above command generated the following output on my Dom0 after a SanDisk USB drive was physically inserted into the computer’s USB port:
$ lsusb Bus 002 Device 002: ID 8087:8000 Intel Corp. Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 001 Device 002: ID 8087:8008 Intel Corp. Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 003 Device 006: ID 0781:5591 SanDisk Corp. Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Note that the USB drive shown in the output above is attached to bus 003 and has the device number 006. Make sure to drop the preceding zeros when using the bus/device numbers in the xl usbdev-attach command, otherwise the numbers may be interpreted as octal.
With this information, we can now put together the xl usbdev-attach command as follows:
# xl usbdev-attach {name-of-domu} hostbus=3 hostaddr=6
Executing the above command on my Dom0 resulted in the following errors:
# xl usbdev-attach {name-of-domu} hostbus=3 hostaddr=6 libxl: error: libxl_usb.c:1333:bind_usbintf: open file failed: '/sys/bus/usb/drivers/usbback/bind': No such file or directory libxl: error: libxl_usb.c:1563:usbback_dev_assign: Couldn't bind 3-7:1.0 to /sys/bus/usb/drivers/usbback libxl: error: libxl.c:2012:device_addrm_aocomplete: unable to add device libxl_device_usbdev_add failed.
Conclusion
Ideally, the above xl commands would successfully create a USB controller and pass-through the USB drive to the intended DomU. From there, you would log in to the DomU, see the passed-through device, and mount the drive. Of course, all this depends on the kernel modules available in your Dom0.
What else can I say? I hope you had better luck with this method than I did! If not, don’t worry because the last method in this series also uses the xl toolstack and can pass-through a USB drive to a running DomU.
Notes:
1. Note that the Xen kernel module “tmem.ko” is also available on the Dom0, but does not appear in the output due to the regular expression requirement of having “xen” in the filename.
2. As supported by the following result:
# xl usbctrl-attach {name-of-domu} type=pv version=3 ports=8 libxl: error: libxl_usb.c:67:libxl__device_usbctrl_setdefault: USB version for paravirtualized devices must be 1 or 2 libxl: error: libxl.c:2012:device_addrm_aocomplete: unable to add device libxl_device_usbctrl_add failed.