Thursday, May 14, 2015

USB Passthrough in KVM/libvirt: How to talk to a UPS

I was writing an article about how to connect an Arduino to a kvm vm host so a vm guest can access it. Since there were some issues I would like to share, I decided to break it down in two parts. First would be this very article, dealing with setting up USB passthrough. In a future article we will talk about issues using Arduino with USB passthrough.

Last time I talked about passthrough was in a post about using grep to look for a vm client which uses PCI passthrough. I never really mentioned how to do the deed there because I assumed everyone knew how to do that in KVM. Should we talk about how to set that up? You tell me. Since I will be talking about using USB passthrough here, you can see if it is enough to understand and use PCI passthrough. If not, let me know and I will write a few lies about it.

Since I kept talking about the Arduino, I will not use it as the example here. Instead, an APC-brand UPS is chosen for the unbiased version that it is what I have here. Here's the idea: let's say you have a vm client running something like Nagios or Icinga in it. Why not use it to monitor the UPS and let us know (or initiate some automated operation) if it is in use and/or the remaining charge drops below a certain level?

We will be adding the APC to the vm client scan, which is an CentOS vm client/guest in the KVM-based with libvirt vm host called, for reasons the go beyond the topic of this article, vmhost.

Install and Setup

  1. The UPS in question has a USB cable that is used to monitor/talk to it. Now I know as matter of fact that apcupsd works well with that setup, so we should install it in our nagios (I am using this as the vm client's name for the sake of lazyness) server. To make a long story short, since this is RedHat-based distro we can get it by
    yum install apcupsd --enablerepo=epel
  2. Let's make sure the vm can see the APC box. To do so, we first need to see if the vm host, affectionately known as vmhost because of some unexplained reason, know we plugged the console USB cable from the APC:
    [root@vmhost tmp]# lsusb
    Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
    Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
    Bus 003 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 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
    Bus 006 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
    Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
    Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
    Bus 002 Device 003: ID 051d:0002 American Power Conversion Uninterruptible Power Supply
    [root@vmhost tmp]#
    You have to agree the line
    Bus 002 Device 003: ID 051d:0002 American Power Conversion Uninterruptible Power Supply
    is a dead giveaway that this is the APC-brad UPS. Now we identified the entry, we want to get the USB vendor and product IDs. That will be the 051d:0002, respectively.
  3. Next we need to reconfigure scan so it knows it has a new USB device attached to it. A USB device is a seen by KVM as hostdev element. From the libvirt docs, a hostdev is the container that describe host devices. We could shutdown scan and edit its config file, but we should/better be able to do it live. First we create a little file containing the hostdev definition:
    cat > apc.xml << 'EOF'
        <hostdev mode='subsystem' type='usb' managed='yes'>
          <source startupPolicy='optional'>
            <vendor id='0x051d'/>
            <product id='0x0002'/>
          </source>
        </hostdev>
    EOF
    You can see the vendor and product IDs, which we gathered from last step. The reason for the startupPolicy='optional' is that if the machine needs to reboot, or come back from being saved, it will do so even if the usb device is no longer reachable. Now, we should let the vm client know about the UPS:
    [root@vmhost tmp]# virsh attach-device nagios apc.xml
    Device attached successfully
    
    [root@vmhost tmp]# 
  4. Does our vm client see it now?
    [raub@scan ~]$ lsusb
    Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
    Bus 001 Device 002: ID 0627:0001 Adomax Technology Co., Ltd
    Bus 001 Device 003: ID 0409:55aa NEC Corp. Hub
    Bus 001 Device 004: ID 051d:0002 American Power Conversion Uninterruptible Power Supply
    [raub@scan ~]$
    It seems it is there, so we should test the connection using apcupsd
    [root@scan ~]# service apcupsd start
    grep: /etc/nologin: No such file or directory
    Starting UPS monitoring:                                   [  OK  ]
    [root@scan ~]# service apcupsd status
    apcupsd (pid  19373) is running...
    APC      : 001,036,0917
    DATE     : 2015-05-14 12:30:43 -0400
    HOSTNAME : scan.in.example.com
    VERSION  : 3.14.10 (13 September 2011) redhat
    UPSNAME  : ups1
    CABLE    : USB Cable
    DRIVER   : USB UPS Driver
    UPSMODE  : Stand Alone
    STARTTIME: 2015-05-14 12:30:42 -0400
    MODEL    : Back-UPS RS 1500G
    STATUS   : ONLINE
    LINEV    : 124.0 Volts
    LOADPCT  :  21.0 Percent Load Capacity
    BCHARGE  : 100.0 Percent
    TIMELEFT :  38.4 Minutes
    MBATTCHG : 5 Percent
    MINTIMEL : 3 Minutes
    MAXTIME  : 0 Seconds
    SENSE    : Medium
    LOTRANS  : 088.0 Volts
    HITRANS  : 147.0 Volts
    ALARMDEL : 30 seconds
    BATTV    : 27.0 Volts
    LASTXFER : Automatic or explicit self test
    NUMXFERS : 0
    TONBATT  : 0 seconds
    CUMONBATT: 0 seconds
    XOFFBATT : N/A
    SELFTEST : NO
    STATFLAG : 0x07000008 Status Flag
    SERIALNO : 3B1416X00241
    BATTDATE : 2014-04-14
    NOMINV   : 120 Volts
    NOMBATTV :  24.0 Volts
    NOMPOWER : 865 Watts
    FIRMWARE : 865.L5 .D USB FW:L5
    END APC  : 2015-05-14 12:30:47 -0400
    [root@scan ~]#
    Smells like our USB passthrough adventure worked.
We could go on and configure Nagios to do the UPS monitoring, but that will be left for another article; if you want to get ahead, a starting point would be to search for "nagios apcupsd". Remember, all we wanted here is to get the USB passthrough part working. For the next article we will talk about when things do not work as peachy.

Removing the USB device from the vm guest

  1. If you want to remove it programatically,
    virsh detach-device nagios apc.xml
    will remove it from nagios's config. lsusb on the vm client (nagios) will show it is gone.
  2. If you just physically pluck the USB device from vmhost, the client will report it as gone However, it will still be in the vm client's config file. Here is an example of a USB device with vendor ID=2341 that I physically plucked from more than once (and then put it back and added to the client):
    [root@vmhost tmp]# virsh dumpxml desktop|grep 2341
            <vendor id='0x2341'/>
            <vendor id='0x2341'/>
    [root@vmhost tmp]#

    The solution for that is to keep removing it (virsh detach-device nagios apc.xml) until virsh dumpxml stops reporting it is there. And then add it again.

    Let me show this step-by-step with the AUP example:

    1. We start by not seeing the APC UPS in the vm client:
      [root@scan ~]# lsusb
      Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
      Bus 001 Device 002: ID 0627:0001 Adomax Technology Co., Ltd
      Bus 001 Device 003: ID 0409:55aa NEC Corp. Hub
      [root@scan ~]#
    2. The vm host tells us there are 3 entries in the vm client's config:
      [root@vmhost tmp]# virsh dumpxml nagios|grep  051d
              <vendor id='0x051d'/>
              <vendor id='0x051d'/>
              <vendor id='0x051d'/>
      [root@vmhost tmp]#
    3. Let's start removing them:
      [root@vmhost tmp]# virsh detach-device nagios apc.xml
      Device detached successfully
      
      [root@vmhost tmp]# virsh detach-device nagios apc.xml
      Device detached successfully
      
      [root@vmhost tmp]# virsh dumpxml nagios|grep  051d
              <vendor id='0x051d'/>
      [root@vmhost tmp]# 
    4. Sounds like we can't count. We need to do the deed 3 times, so we do it one last time and see if the device is finally gone:
      [root@vmhost tmp]# virsh detach-device nagios apc.xml
      Device detached successfully
      
      [root@vmhost tmp]# virsh dumpxml nagios|grep  051d
      [root@vmhost tmp]# 
    5. Success! Now we add it
      [root@vmhost tmp]# virsh attach-device nagios apc.xml
      Device attached successfully
      
      [root@vmhost tmp]#
    6. And check in the vm client if it is back
      [root@scan ~]# lsusb
      Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
      Bus 001 Device 002: ID 0627:0001 Adomax Technology Co., Ltd
      Bus 001 Device 003: ID 0409:55aa NEC Corp. Hub
      Bus 001 Device 009: ID 051d:0002 American Power Conversion Uninterruptible Power Supply
      [root@scan ~]#
  3. If you save the vm client (virhs managedsave or virsh save), exciting things will happen.

No comments: