From mboxrd@z Thu Jan 1 00:00:00 1970 From: George Dunlap Subject: [PATCH v2 2/2] xl: Add hvm-host-usb-add and hvm-host-usb-del commands Date: Wed, 20 Mar 2013 16:41:37 +0000 Message-ID: <1363797697-27179-2-git-send-email-george.dunlap@eu.citrix.com> References: <1363797697-27179-1-git-send-email-george.dunlap@eu.citrix.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1363797697-27179-1-git-send-email-george.dunlap@eu.citrix.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: xen-devel@lists.xen.org Cc: George Dunlap , Ian Jackson , Ian Campbell , Roger Pau Monne List-Id: xen-devel@lists.xenproject.org Add commands to add and remove host USB to HVM guests. v2: - Ported to suggested libxl interface - Allow user to specify either host-device-spec or devname on remove - Options specified with -d, -v, and -i, rather than implicit ordering Signed-off-by: George Dunlap --- docs/man/xl.pod.1 | 51 +++++++++ tools/libxl/xl.h | 2 + tools/libxl/xl_cmdimpl.c | 267 +++++++++++++++++++++++++++++++++++++++++++++ tools/libxl/xl_cmdtable.c | 10 ++ 4 files changed, 330 insertions(+) diff --git a/docs/man/xl.pod.1 b/docs/man/xl.pod.1 index a0e298e..2b5e6d7 100644 --- a/docs/man/xl.pod.1 +++ b/docs/man/xl.pod.1 @@ -1110,6 +1110,57 @@ List virtual network interfaces for a domain. =back +=head2 HVM DEVICES + +=over 4 + +=item B I<-d domain-id> I<-v host-device-spec> [I<-i devname>] + +Passes through the host USB device specified by I to the +HVM domain I. Host-device-spec can be one of the following: + +=over 4 + +=item . + +=item : + +=item .:: + +=back + +The best way to find out the information for the device is typically using +lsusb. + +Using the I<-i> option, you can specify a I for the +device. This is an arbitrary string that can be used by +I to remove the device later. If no name is +specified, then one will be chosen automatically. In any case the +devname will be printed to stdout if the device is successfully added. + +If the I<-i> option is used, then it must be used on device removal; +I cannot be used. + +This command is only available for domains using qemu-xen, not +qemu-traditional. + +=item B I<-d domain-id> (I<-i devname> | I<-v host-device-spec>) + +Remove the host USB device from I which is specified either +by I or I. Exactly one of the two must be +specified. I is a string that was specified when the device +was inserted by B. I can only be +used if no name I was specified when the device was added, +and it must match exactly the specification given at that time. + +Devices specified in the config file do not have an associated +devname, and thus cannot be removed using this command. + +This command is only available for domains using qemu-xen, not +qemu-traditional. + +=back + =head2 VTPM DEVICES =over 4 diff --git a/tools/libxl/xl.h b/tools/libxl/xl.h index b881f92..8eb368c 100644 --- a/tools/libxl/xl.h +++ b/tools/libxl/xl.h @@ -35,6 +35,8 @@ int main_info(int argc, char **argv); int main_sharing(int argc, char **argv); int main_cd_eject(int argc, char **argv); int main_cd_insert(int argc, char **argv); +int main_hvm_host_usb_add(int argc, char **argv); +int main_hvm_host_usb_del(int argc, char **argv); int main_console(int argc, char **argv); int main_vncviewer(int argc, char **argv); int main_pcilist(int argc, char **argv); diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 2d40f8f..721343b 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -2584,6 +2584,273 @@ int main_cd_insert(int argc, char **argv) return 0; } + + +static int parse_usb_specifier_hbhavipi(libxl_device_host_usb *dev, const char *s) +{ + const char * vid, *pid, *p; + const char * hostbus, *hostaddr; + + hostbus = s; + hostaddr = vid = pid = NULL; + +#define is_dec(_c) ((_c) >= '0' && (_c) <= '9') +#define is_hex(_c) (is_dec(_c) || ((_c) >= 'a' && (_c) <= 'f')) + + /* Match [0-9]+\.[0-9]:[0-9a-f]+:[0-9a-f] */ + + /* First look for [0-9]+\.[0-9]:*/ + if ( !is_dec(*hostbus) ) + return -1; + + for(p=s; *p; p++) { + if(*p == '.') { + if ( !hostaddr ) + hostaddr = p+1; + else { + return -1; + } + } else if (*p == ':') { + break; + } else if (!is_dec(*p)) { + return -1; + } + } + if ( !hostaddr || !is_dec(*hostaddr) ) + return -1; + if ( *p != ':' ) + return -1; + + p++; + /* Now match [0-9a-f]+:[0-9a-f] */ + vid = p; + if ( !is_hex(*vid) ) + return -1; + + for(; *p; p++) { + if(*p == ':') { + if ( !pid ) + pid = p+1; + else + return -1; + } else if (!is_hex(*p)) { + return -1; + } + } + if (!pid || !is_hex(*pid)) + return -1; + + dev->hostbus = strtoul(hostbus, NULL, 10); + dev->hostaddr = strtoul(hostaddr, NULL, 10); + dev->vendorid = strtoul(vid, NULL, 16); + dev->productid = strtoul(pid, NULL, 16); + + return 0; +} + +static int parse_usb_specifier_vipi(libxl_device_host_usb *dev, const char *s) +{ + const char * vid, *pid, *p; + + vid = s; + pid = NULL; + + /* Match [0-9a-f]+:[0-9a-f] */ + if ( !is_hex(*vid) ) + return -1; + + for(p=s; *p; p++) { + if(*p == ':') { + if ( !pid ) + pid = p+1; + else + return -1; + } else if (!is_hex(*p)) { + return -1; + } + } + if (!pid || !is_hex(*pid)) + return -1; + dev->vendorid = strtoul(vid, NULL, 16); + dev->productid = strtoul(pid, NULL, 16); + + return 0; +} + +static int parse_usb_specifier_hbha(libxl_device_host_usb *dev, const char *s) +{ + const char * hostbus, *hostaddr, *p; + + hostbus = s; + hostaddr=NULL; + + /* Match [0-9]+\.[0-9] */ + if (!is_dec(*hostbus)) + return -1; + + for(p=s; *p; p++) { + if(*p == '.') { + if ( !hostaddr ) + hostaddr = p+1; + else { + return -1; + } + } else if (!is_dec(*p)) { + return -1; + } + } + if (!hostaddr || !is_dec(*hostaddr)) + return -1; + dev->hostbus = strtoul(hostbus, NULL, 10); + dev->hostaddr = strtoul(hostaddr, NULL, 10); + + return 0; +} + +static int parse_usb_specifier(libxl_device_host_usb *dev, const char *s) +{ + /* + * Acceptable formats: + * - hostbus.hostaddr + * - vendorid:productid + * - hostbus.hostaddr:vendorid:productid + */ + if ( !parse_usb_specifier_hbha(dev, s) ) + return 0; + if ( !parse_usb_specifier_vipi(dev, s) ) + return 0; + if ( !parse_usb_specifier_hbhavipi(dev, s) ) + return 0; + + return -1; +} + +#undef is_dec +#undef is_hex + +static int hvm_host_usb_add(uint32_t domid, const char * device, + const char * id) +{ + libxl_device_host_usb usbdev; + int rc; + + libxl_device_host_usb_init(&usbdev); + + if ( id ) + usbdev.id = strdup(id); + + if ( parse_usb_specifier(&usbdev, device) < 0 ) + return -1; + + if ( (rc = libxl_hvm_host_usb_add(ctx, domid, &usbdev, NULL)) >= 0 ) + printf("Added device with name %s\n", usbdev.id); + + libxl_device_host_usb_dispose(&usbdev); + + return rc; +} + +int main_hvm_host_usb_add(int argc, char **argv) +{ + uint32_t domid = -1; + int opt = 0, rc; + const char *id = NULL, *device = NULL; + + SWITCH_FOREACH_OPT(opt, "d:v:i:", NULL, "hvm-host-usb-add", 0) { + case 'd': + domid = find_domain(optarg); + break; + case 'v': + device = optarg; + break; + case 'i': + id = optarg; + break; + } + + if ( domid == -1 ) { + fprintf(stderr, "Must specify domid\n\n"); + help("hvm-host-usb-add"); + return 2; + } + + if ( !device ) { + fprintf(stderr, "Must specify a device\n\n"); + help("hvm-host-usb-add"); + return 2; + } + + rc = hvm_host_usb_add(domid, device, id); + if ( rc < 0 ) + return 1; + else + return 0; +} + +static int hvm_host_usb_del(uint32_t domid, const char * device, + const char * id) +{ + libxl_device_host_usb usbdev; + int rc; + + libxl_device_host_usb_init(&usbdev); + + if ( id ) { + usbdev.id = strdup(id); + } else if ( device && (parse_usb_specifier(&usbdev, device) < 0) ) { + return -1; + } + + rc = libxl_hvm_host_usb_del(ctx, domid, &usbdev, NULL); + + libxl_device_host_usb_dispose(&usbdev); + + return rc; +} + +int main_hvm_host_usb_del(int argc, char **argv) +{ + uint32_t domid = -1; + int opt = 0, rc; + const char *id = NULL, *device = NULL; + + SWITCH_FOREACH_OPT(opt, "d:v:i:", NULL, "hvm-host-usb-add", 0) { + case 'd': + domid = find_domain(optarg); + break; + case 'v': + device = optarg; + break; + case 'i': + id = optarg; + break; + } + + if ( domid == -1 ) { + fprintf(stderr, "Must specify domid\n\n"); + help("hvm-host-usb-del"); + return 2; + } + + if ( device && id ) { + fprintf(stderr, "Cannot specify both device and device-id\n\n"); + help("hvm-host-usb-del"); + return 2; + } + + if ( !device && !id ) { + help("hvm-host-usb-del"); + fprintf(stderr, "Must specify either device or device-id\n\n"); + return 2; + } + + rc = hvm_host_usb_del(domid, device, id); + if ( rc < 0 ) + return 1; + else + return 0; +} + int main_console(int argc, char **argv) { uint32_t domid; diff --git a/tools/libxl/xl_cmdtable.c b/tools/libxl/xl_cmdtable.c index b4a87ca..62ba4f2 100644 --- a/tools/libxl/xl_cmdtable.c +++ b/tools/libxl/xl_cmdtable.c @@ -187,6 +187,16 @@ struct cmd_spec cmd_table[] = { "Eject a cdrom from a guest's cd drive", " ", }, + { "hvm-host-usb-add", + &main_hvm_host_usb_add, 1, 1, + "Hot-plug a host usb device to an HVM domain.", + "-d -v [-i ] ", + }, + { "hvm-host-usb-del", + &main_hvm_host_usb_del, 1, 1, + "Hot-unplug the named host device from an HVM domain.", + "-d (-i | -v )", + }, { "mem-max", &main_memmax, 0, 1, "Set the maximum amount reservation for a domain", -- 1.7.9.5