From 9a361bbba8c8d3ea3f1a1d56912851d509179fa9 Mon Sep 17 00:00:00 2001
From: Chunyan Liu <cyliu@suse.com>
Date: Wed, 15 Jun 2016 14:00:12 +0800
Subject: [PATCH 5/6] xenconfig: add conversion of usb controller config to and
 from xml

libxl configuration files conversion can now handle USB controllers.
When parting libxl config file, USB controllers with type PV are
ignored as those aren't handled.

Signed-off-by: Chunyan Liu <cyliu@suse.com>
---
 src/xenconfig/xen_xl.c              | 190 ++++++++++++++++++++++++++++++++++++
 tests/xlconfigdata/test-usbctrl.cfg |  13 +++
 tests/xlconfigdata/test-usbctrl.xml |  31 ++++++
 tests/xlconfigtest.c                |   1 +
 4 files changed, 235 insertions(+)
 create mode 100644 tests/xlconfigdata/test-usbctrl.cfg
 create mode 100644 tests/xlconfigdata/test-usbctrl.xml

Index: libvirt-2.0.0/src/xenconfig/xen_xl.c
===================================================================
--- libvirt-2.0.0.orig/src/xenconfig/xen_xl.c
+++ libvirt-2.0.0/src/xenconfig/xen_xl.c
@@ -503,6 +503,110 @@ xenParseXLInputDevs(virConfPtr conf, vir
 }
 
 static int
+xenParseXLUSBController(virConfPtr conf, virDomainDefPtr def)
+{
+    virConfValuePtr list = virConfGetValue(conf, "usbctrl");
+    virDomainControllerDefPtr controller = NULL;
+
+    if (list && list->type == VIR_CONF_LIST) {
+        list = list->list;
+        while (list) {
+            char type[8];
+            char version[4];
+            char ports[4];
+            char *key;
+            int usbctrl_version = 2; /* by default USB 2.0 */
+            int usbctrl_ports = 8; /* by default 8 ports */
+            int usbctrl_type = -1;
+
+            type[0] = version[0] = ports[0] = '\0';
+
+            if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
+                goto skipusbctrl;
+            /* usbctrl=['type=pv,version=2,ports=8'] */
+            key = list->str;
+            while (key) {
+                char *data;
+                char *nextkey = strchr(key, ',');
+
+                if (!(data = strchr(key, '=')))
+                    goto skipusbctrl;
+                data++;
+
+                if (STRPREFIX(key, "type=")) {
+                    int len = nextkey ? (nextkey - data) : sizeof(type) - 1;
+                    if (virStrncpy(type, data, len, sizeof(type)) == NULL) {
+                        virReportError(VIR_ERR_INTERNAL_ERROR,
+                                       _("type %s invalid"),
+                                       data);
+                        goto skipusbctrl;
+                    }
+                } else if (STRPREFIX(key, "version=")) {
+                    int len = nextkey ? (nextkey - data) : sizeof(version) - 1;
+                    if (virStrncpy(version, data, len, sizeof(version)) == NULL) {
+                        virReportError(VIR_ERR_INTERNAL_ERROR,
+                                       _("version %s invalid"),
+                                       data);
+                        goto skipusbctrl;
+                    }
+                    if (virStrToLong_i(version, NULL, 16, &usbctrl_version) < 0)
+                        goto skipusbctrl;
+                } else if (STRPREFIX(key, "ports=")) {
+                    int len = nextkey ? (nextkey - data) : sizeof(ports) - 1;
+                    if (virStrncpy(ports, data, len, sizeof(ports)) == NULL) {
+                        virReportError(VIR_ERR_INTERNAL_ERROR,
+                                       _("version %s invalid"),
+                                       data);
+                        goto skipusbctrl;
+                    }
+                    if (virStrToLong_i(ports, NULL, 16, &usbctrl_ports) < 0)
+                        goto skipusbctrl;
+                }
+
+                while (nextkey && (nextkey[0] == ',' ||
+                                   nextkey[0] == ' ' ||
+                                   nextkey[0] == '\t'))
+                    nextkey++;
+                key = nextkey;
+            }
+
+            if (type[0] == '\0') {
+                if (usbctrl_version == 1)
+                    usbctrl_type = VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB1;
+                else
+                    usbctrl_type = VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB2;
+            } else {
+                if (STREQLEN(type, "qusb", 4)) {
+                    if (usbctrl_version == 1)
+                        usbctrl_type = VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB1;
+                    else
+                        usbctrl_type = VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB2;
+                } else {
+                    goto skipusbctrl;
+                }
+            }
+
+            if (!(controller = virDomainControllerDefNew(VIR_DOMAIN_CONTROLLER_TYPE_USB)))
+                return -1;
+
+            controller->type = VIR_DOMAIN_CONTROLLER_TYPE_USB;
+            controller->model = usbctrl_type;
+            controller->opts.usbopts.ports = usbctrl_ports;
+
+            if (VIR_APPEND_ELEMENT(def->controllers, def->ncontrollers, controller) < 0) {
+                virDomainControllerDefFree(controller);
+                return -1;
+            }
+
+        skipusbctrl:
+            list = list->next;
+        }
+    }
+
+    return 0;
+}
+
+static int
 xenParseXLUSB(virConfPtr conf, virDomainDefPtr def)
 {
     virConfValuePtr list = virConfGetValue(conf, "usbdev");
@@ -612,6 +716,9 @@ xenParseXL(virConfPtr conf,
     if (xenParseXLUSB(conf, def) < 0)
         goto cleanup;
 
+    if (xenParseXLUSBController(conf, def) < 0)
+        goto cleanup;
+
     if (virDomainDefPostParse(def, caps, VIR_DOMAIN_DEF_PARSE_ABI_UPDATE,
                               xmlopt) < 0)
         goto cleanup;
@@ -1092,6 +1199,86 @@ xenFormatXLInputDevs(virConfPtr conf, vi
 }
 
 static int
+xenFormatXLUSBController(virConfPtr conf,
+                         virDomainDefPtr def)
+{
+    virConfValuePtr usbctrlVal = NULL;
+    int hasUSBCtrl = 0;
+    size_t i;
+
+    for (i = 0; i < def->ncontrollers; i++) {
+        if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) {
+            hasUSBCtrl = 1;
+            break;
+        }
+    }
+
+    if (!hasUSBCtrl)
+        return 0;
+
+    if (VIR_ALLOC(usbctrlVal) < 0)
+        return -1;
+
+    usbctrlVal->type = VIR_CONF_LIST;
+    usbctrlVal->list = NULL;
+
+    for (i = 0; i < def->ncontrollers; i++) {
+        if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) {
+            virConfValuePtr val, tmp;
+            virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+            if (def->controllers[i]->model != -1) {
+                switch (def->controllers[i]->model) {
+                case VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB1:
+                    virBufferAddLit(&buf, "type=qusb,version=1,");
+                    break;
+
+                case VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB2:
+                    virBufferAddLit(&buf, "type=qusb,version=2,");
+                    break;
+
+                default:
+                    goto error;
+                }
+            }
+
+            if (def->controllers[i]->opts.usbopts.ports != -1)
+                virBufferAsprintf(&buf, "ports=%x",
+                                  def->controllers[i]->opts.usbopts.ports);
+
+            if (VIR_ALLOC(val) < 0) {
+                virBufferFreeAndReset(&buf);
+                goto error;
+            }
+            val->type = VIR_CONF_STRING;
+            val->str = virBufferContentAndReset(&buf);
+            tmp = usbctrlVal->list;
+            while (tmp && tmp->next)
+                tmp = tmp->next;
+            if (tmp)
+                tmp->next = val;
+            else
+                usbctrlVal->list = val;
+        }
+    }
+
+    if (usbctrlVal->list != NULL) {
+        int ret = virConfSetValue(conf, "usbctrl", usbctrlVal);
+        usbctrlVal = NULL;
+        if (ret < 0)
+            return -1;
+    }
+    VIR_FREE(usbctrlVal);
+
+    return 0;
+
+ error:
+    virConfFreeValue(usbctrlVal);
+    return -1;
+}
+
+
+static int
 xenFormatXLUSB(virConfPtr conf,
                virDomainDefPtr def)
 {
@@ -1184,6 +1371,9 @@ xenFormatXL(virDomainDefPtr def, virConn
     if (xenFormatXLUSB(conf, def) < 0)
         goto cleanup;
 
+    if (xenFormatXLUSBController(conf, def) < 0)
+        goto cleanup;
+
     return conf;
 
  cleanup:
Index: libvirt-2.0.0/tests/xlconfigdata/test-usbctrl.cfg
===================================================================
--- /dev/null
+++ libvirt-2.0.0/tests/xlconfigdata/test-usbctrl.cfg
@@ -0,0 +1,13 @@
+name = "XenGuest1"
+uuid = "45b60f51-88a9-47a8-a3b3-5e66d71b2283"
+maxmem = 512
+memory = 512
+vcpus = 1
+localtime = 0
+on_poweroff = "preserve"
+on_reboot = "restart"
+on_crash = "preserve"
+vif = [ "mac=5a:36:0e:be:00:09" ]
+bootloader = "/usr/bin/pygrub"
+disk = [ "format=qcow2,vdev=xvda,access=rw,backendtype=qdisk,target=/var/lib/xen/images/debian/disk.qcow2" ]
+usbctrl = [ "type=qusb,version=2,ports=6" ]
Index: libvirt-2.0.0/tests/xlconfigdata/test-usbctrl.xml
===================================================================
--- /dev/null
+++ libvirt-2.0.0/tests/xlconfigdata/test-usbctrl.xml
@@ -0,0 +1,31 @@
+<domain type='xen'>
+  <name>XenGuest1</name>
+  <uuid>45b60f51-88a9-47a8-a3b3-5e66d71b2283</uuid>
+  <memory unit='KiB'>524288</memory>
+  <currentMemory unit='KiB'>524288</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <bootloader>/usr/bin/pygrub</bootloader>
+  <os>
+    <type arch='x86_64' machine='xenpv'>linux</type>
+  </os>
+  <clock offset='utc' adjustment='reset'/>
+  <on_poweroff>preserve</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>preserve</on_crash>
+  <devices>
+    <disk type='file' device='disk'>
+      <driver name='qemu' type='qcow2'/>
+      <source file='/var/lib/xen/images/debian/disk.qcow2'/>
+      <target dev='xvda' bus='xen'/>
+    </disk>
+    <controller type='usb' index='0' model='qusb2' ports='6'/>
+    <interface type='ethernet'>
+      <mac address='5a:36:0e:be:00:09'/>
+    </interface>
+    <console type='pty'>
+      <target type='xen' port='0'/>
+    </console>
+    <input type='mouse' bus='xen'/>
+    <input type='keyboard' bus='xen'/>
+  </devices>
+</domain>
Index: libvirt-2.0.0/tests/xlconfigtest.c
===================================================================
--- libvirt-2.0.0.orig/tests/xlconfigtest.c
+++ libvirt-2.0.0/tests/xlconfigtest.c
@@ -278,6 +278,7 @@ mymain(void)
 #endif
     DO_TEST("vif-typename");
     DO_TEST("usb");
+    DO_TEST("usbctrl");
 
     virObjectUnref(caps);
     virObjectUnref(xmlopt);
