[libvirt] [PATCH 1/7] Allow multiple consoles per virtual guest

Daniel P. Berrange berrange at redhat.com
Thu Oct 20 14:47:21 UTC 2011


From: "Daniel P. Berrange" <berrange at redhat.com>

While Xen only has a single paravirt console, UML, and
QEMU both support multiple paravirt consoles. The LXC
driver can also be trivially made to support multiple
consoles. This patch extends the XML to allow multiple
<console> elements in the XML. It also makes the UML
and QEMU drivers support this config.

* src/conf/domain_conf.c, src/conf/domain_conf.h: Allow
  multiple <console> devices
* src/lxc/lxc_driver.c, src/xen/xen_driver.c,
  src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c: Update for
  internal API changes
* src/security/security_selinux.c, src/security/virt-aa-helper.c:
  Only label consoles that aren't a copy of the serial device
* src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
  src/qemu/qemu_process.c, src/uml/uml_conf.c,
  src/uml/uml_driver.c: Support multiple console devices
* tests/qemuxml2xmltest.c, tests/qemuxml2argvtest.c: Extra
  tests for multiple virtio consoles. Set QEMU_CAPS_CHARDEV
  for all console /channel tests
* tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-auto.args,
  tests/qemuxml2argvdata/qemuxml2argv-channel-virtio.args
  tests/qemuxml2argvdata/qemuxml2argv-console-virtio.args: Update
  for correct chardev syntax
* tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.args,
  tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.xml: New
  test file
---
 src/conf/domain_conf.c                             |  110 ++++++++++++++------
 src/conf/domain_conf.h                             |    4 +-
 src/lxc/lxc_driver.c                               |   20 +++-
 src/qemu/qemu_command.c                            |   12 +-
 src/qemu/qemu_driver.c                             |   11 +-
 src/qemu/qemu_process.c                            |    8 +-
 src/security/security_selinux.c                    |   10 ++
 src/security/virt-aa-helper.c                      |   16 ++-
 src/uml/uml_conf.c                                 |    8 +-
 src/uml/uml_driver.c                               |   10 +-
 src/xen/xen_driver.c                               |    4 +-
 src/xenxs/xen_sxpr.c                               |   17 ++-
 src/xenxs/xen_xm.c                                 |   11 ++-
 .../qemuxml2argv-channel-virtio-auto.args          |    5 +-
 .../qemuxml2argv-channel-virtio.args               |    5 +-
 .../qemuxml2argv-console-virtio-many.args          |   12 ++
 .../qemuxml2argv-console-virtio-many.xml           |   41 +++++++
 .../qemuxml2argv-console-virtio.args               |    5 +-
 tests/qemuxml2argvtest.c                           |    8 +-
 tests/qemuxml2xmltest.c                            |    1 +
 20 files changed, 233 insertions(+), 85 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.xml

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 5959593..f90bece 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1208,7 +1208,9 @@ void virDomainDefFree(virDomainDefPtr def)
         virDomainChrDefFree(def->channels[i]);
     VIR_FREE(def->channels);
 
-    virDomainChrDefFree(def->console);
+    for (i = 0 ; i < def->nconsoles ; i++)
+        virDomainChrDefFree(def->consoles[i]);
+    VIR_FREE(def->consoles);
 
     for (i = 0 ; i < def->nsounds ; i++)
         virDomainSoundDefFree(def->sounds[i]);
@@ -1599,6 +1601,9 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def,
     for (i = 0; i < def->nchannels ; i++)
         if (cb(def, &def->channels[i]->info, opaque) < 0)
             return -1;
+    for (i = 0; i < def->nconsoles ; i++)
+        if (cb(def, &def->consoles[i]->info, opaque) < 0)
+            return -1;
     for (i = 0; i < def->ninputs ; i++)
         if (cb(def, &def->inputs[i]->info, opaque) < 0)
             return -1;
@@ -1611,9 +1616,6 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def,
     if (def->memballoon)
         if (cb(def, &def->memballoon->info, opaque) < 0)
             return -1;
-    if (def->console)
-        if (cb(def, &def->console->info, opaque) < 0)
-            return -1;
     for (i = 0; i < def->nhubs ; i++)
         if (cb(def, &def->hubs[i]->info, opaque) < 0)
             return -1;
@@ -7059,20 +7061,46 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
     }
     VIR_FREE(nodes);
 
-    if ((node = virXPathNode("./devices/console[1]", ctxt)) != NULL) {
+    if ((n = virXPathNodeSet("./devices/console", ctxt, &nodes)) < 0) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("cannot extract console devices"));
+        goto error;
+    }
+    if (n && VIR_ALLOC_N(def->consoles, n) < 0)
+        goto no_memory;
+
+    for (i = 0 ; i < n ; i++) {
         virDomainChrDefPtr chr = virDomainChrDefParseXML(caps,
-                                                         node,
+                                                         nodes[i],
                                                          flags);
         if (!chr)
             goto error;
 
-        chr->target.port = 0;
         /*
-         * For HVM console actually created a serial device
-         * while for non-HVM it was a parvirt console
+         * Some really crazy backcompat stuff for consoles
+         *
+         * Historically the first (and only) '<console>'
+         * element in an HVM guest was treated as being
+         * an alias for a <serial> device.
+         *
+         * So if we see that this console device should
+         * be a serial device, then we move the config
+         * over to def->serials[0] (or discard it if
+         * that already exists
+         *
+         * We then fill def->consoles[0] with a stub
+         * just so we get sequencing correct for consoles
+         * > 0
          */
         if (STREQ(def->os.type, "hvm") &&
-            chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL) {
+            (chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)) {
+            if (i != 0) {
+                virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                                     _("Only the first console can be a serial port"));
+                goto error;
+            }
+
+            /* Either discard or move this chr to the serial config */
             if (def->nserials != 0) {
                 virDomainChrDefFree(chr);
             } else {
@@ -7080,14 +7108,24 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
                     virDomainChrDefFree(chr);
                     goto no_memory;
                 }
+                chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
                 def->nserials = 1;
                 def->serials[0] = chr;
-                chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
+                chr->target.port = 0;
             }
-        } else {
-            def->console = chr;
+
+            /* And create a stub placeholder */
+            if (VIR_ALLOC(chr) < 0)
+                goto no_memory;
+            chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
+            chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
         }
+
+        chr->target.port = i;
+
+        def->consoles[def->nconsoles++] = chr;
     }
+    VIR_FREE(nodes);
 
     if ((n = virXPathNodeSet("./devices/channel", ctxt, &nodes)) < 0) {
         goto error;
@@ -8533,14 +8571,17 @@ bool virDomainDefCheckABIStability(virDomainDefPtr src,
         if (!virDomainChannelDefCheckABIStability(src->channels[i], dst->channels[i]))
             goto cleanup;
 
-    if ((!src->console && dst->console) ||
-        (src->console && !dst->console)) {
+    if (src->nconsoles != dst->nconsoles) {
         virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                              _("Target domain console count %d does not match source %d"),
-                             dst->console ? 1 : 0, src->console ? 1 : 0);
+                             dst->nconsoles, src->nconsoles);
         goto cleanup;
     }
 
+    for (i = 0 ; i < src->nconsoles ; i++)
+        if (!virDomainConsoleDefCheckABIStability(src->consoles[i], dst->consoles[i]))
+            goto cleanup;
+
     if (src->nhubs != dst->nhubs) {
         virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                              _("Target domain hub device count %d does not match source %d"),
@@ -8552,9 +8593,6 @@ bool virDomainDefCheckABIStability(virDomainDefPtr src,
         if (!virDomainHubDefCheckABIStability(src->hubs[i], dst->hubs[i]))
             goto cleanup;
 
-    if (src->console &&
-        !virDomainConsoleDefCheckABIStability(src->console, dst->console))
-        goto cleanup;
 
     if ((!src->watchdog && dst->watchdog) ||
         (src->watchdog && !dst->watchdog)) {
@@ -8676,8 +8714,8 @@ static int virDomainDefMaybeAddVirtioSerialController(virDomainDefPtr def)
         }
     }
 
-    if (def->console) {
-        virDomainChrDefPtr console = def->console;
+    for (i = 0 ; i < def->nconsoles ; i++) {
+        virDomainChrDefPtr console = def->consoles[i];
 
         if (console->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO) {
             int idx = 0;
@@ -10904,15 +10942,27 @@ virDomainDefFormatInternal(virDomainDefPtr def,
         if (virDomainChrDefFormat(buf, def->parallels[n], flags) < 0)
             goto cleanup;
 
-    /* If there's a PV console that's preferred.. */
-    if (def->console) {
-        if (virDomainChrDefFormat(buf, def->console, flags) < 0)
+    for (n = 0 ; n < def->nconsoles ; n++) {
+        virDomainChrDef console;
+        /* Back compat, ignore the console element for hvm guests
+         * if it is type == serial
+         */
+        if (STREQ(def->os.type, "hvm") &&
+            (def->consoles[n]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL) &&
+            (n < def->nserials)) {
+            memcpy(&console, def->serials[n], sizeof(console));
+            console.deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
+        } else {
+            memcpy(&console, def->consoles[n], sizeof(console));
+        }
+        if (virDomainChrDefFormat(buf, &console, flags) < 0)
             goto cleanup;
-    } else if (def->nserials != 0) {
-        /* ..else for legacy compat duplicate the first serial device as a
-         * console */
+    }
+    if (STREQ(def->os.type, "hvm") &&
+        def->nconsoles == 0 &&
+        def->nserials > 0) {
         virDomainChrDef console;
-        memcpy(&console, def->serials[0], sizeof(console));
+        memcpy(&console, def->serials[n], sizeof(console));
         console.deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
         if (virDomainChrDefFormat(buf, &console, flags) < 0)
             goto cleanup;
@@ -12533,9 +12583,9 @@ int virDomainChrDefForeach(virDomainDefPtr def,
         if (abortOnError && rc != 0)
             goto done;
     }
-    if (def->console) {
+    for (i = 0 ; i < def->nconsoles ; i++) {
         if ((iter)(def,
-                   def->console,
+                   def->consoles[i],
                    opaque) < 0)
             rc = -1;
 
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 2119b5a..a78b3ab 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1403,6 +1403,9 @@ struct _virDomainDef {
     int nchannels;
     virDomainChrDefPtr *channels;
 
+    int nconsoles;
+    virDomainChrDefPtr *consoles;
+
     size_t nleases;
     virDomainLeaseDefPtr *leases;
 
@@ -1410,7 +1413,6 @@ struct _virDomainDef {
     virDomainHubDefPtr *hubs;
 
     /* Only 1 */
-    virDomainChrDefPtr console;
     virSecurityLabelDef seclabel;
     virDomainWatchdogDefPtr watchdog;
     virDomainMemballoonDefPtr memballoon;
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index f08e8d1..9b5c9db 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -1683,10 +1683,18 @@ static int lxcVmStart(virConnectPtr conn,
                              _("Failed to allocate tty"));
         goto cleanup;
     }
-    if (vm->def->console &&
-        vm->def->console->source.type == VIR_DOMAIN_CHR_TYPE_PTY) {
-        VIR_FREE(vm->def->console->source.data.file.path);
-        vm->def->console->source.data.file.path = parentTtyPath;
+    if (vm->def->nconsoles) {
+        if (vm->def->nconsoles > 1) {
+            lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                     _("Only one console supported"));
+            goto cleanup;
+        }
+        if (vm->def->consoles[0]->source.type == VIR_DOMAIN_CHR_TYPE_PTY) {
+            VIR_FREE(vm->def->consoles[0]->source.data.file.path);
+            vm->def->consoles[0]->source.data.file.path = parentTtyPath;
+        } else {
+            VIR_FREE(parentTtyPath);
+        }
     } else {
         VIR_FREE(parentTtyPath);
     }
@@ -3022,8 +3030,8 @@ lxcDomainOpenConsole(virDomainPtr dom,
                  _("Named device aliases are not supported"));
         goto cleanup;
     } else {
-        if (vm->def->console)
-            chr = vm->def->console;
+        if (vm->def->nconsoles)
+            chr = vm->def->consoles[0];
         else if (vm->def->nserials)
             chr = vm->def->serials[0];
     }
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 30c0be6..bfa0b63 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -716,16 +716,16 @@ qemuAssignDeviceAliases(virDomainDefPtr def, virBitmapPtr qemuCaps)
         if (virAsprintf(&def->channels[i]->info.alias, "channel%d", i) < 0)
             goto no_memory;
     }
-    for (i = 0; i < def->nsmartcards ; i++) {
-        if (virAsprintf(&def->smartcards[i]->info.alias, "smartcard%d", i) < 0)
+    for (i = 0; i < def->nconsoles ; i++) {
+        if (virAsprintf(&def->consoles[i]->info.alias, "console%d", i) < 0)
             goto no_memory;
     }
     for (i = 0; i < def->nhubs ; i++) {
         if (virAsprintf(&def->hubs[i]->info.alias, "hub%d", i) < 0)
             goto no_memory;
     }
-    if (def->console) {
-        if (virAsprintf(&def->console->info.alias, "console%d", i) < 0)
+    for (i = 0; i < def->nsmartcards ; i++) {
+        if (virAsprintf(&def->smartcards[i]->info.alias, "smartcard%d", i) < 0)
             goto no_memory;
     }
     if (def->watchdog) {
@@ -4493,8 +4493,8 @@ qemuBuildCommandLine(virConnectPtr conn,
     }
 
     /* Explicit console devices */
-    if (def->console) {
-        virDomainChrDefPtr console = def->console;
+    for (i = 0 ; i < def->nconsoles ; i++) {
+        virDomainChrDefPtr console = def->consoles[i];
         char *devstr;
 
         switch(console->targetType) {
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 84ef4dd..3d84bac 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -10481,9 +10481,10 @@ qemuDomainOpenConsole(virDomainPtr dom,
     }
 
     if (dev_name) {
-        if (vm->def->console &&
-            STREQ(dev_name, vm->def->console->info.alias))
-            chr = vm->def->console;
+        for (i = 0 ; !chr && i < vm->def->nconsoles ; i++) {
+            if (STREQ(dev_name, vm->def->consoles[i]->info.alias))
+                chr = vm->def->consoles[i];
+        }
         for (i = 0 ; !chr && i < vm->def->nserials ; i++) {
             if (STREQ(dev_name, vm->def->serials[i]->info.alias))
                 chr = vm->def->serials[i];
@@ -10493,8 +10494,8 @@ qemuDomainOpenConsole(virDomainPtr dom,
                 chr = vm->def->parallels[i];
         }
     } else {
-        if (vm->def->console)
-            chr = vm->def->console;
+        if (vm->def->nconsoles)
+            chr = vm->def->consoles[0];
         else if (vm->def->nserials)
             chr = vm->def->serials[0];
     }
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index a7fe86c..5cdd954 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1112,8 +1112,8 @@ qemuProcessFindCharDevicePTYsMonitor(virDomainObjPtr vm,
                               paths, chardevfmt) < 0)
         return -1;
 
-    if (vm->def->console &&
-        qemuProcessLookupPTYs(&vm->def->console, 1, paths, chardevfmt) < 0)
+    if (qemuProcessLookupPTYs(vm->def->consoles, vm->def->nconsoles,
+                              paths, chardevfmt) < 0)
         return -1;
 
     return 0;
@@ -1161,8 +1161,8 @@ qemuProcessFindCharDevicePTYs(virDomainObjPtr vm,
         }
     }
 
-    if (vm->def->console) {
-        virDomainChrDefPtr chr = vm->def->console;
+    for (i = 0 ; i < vm->def->nconsoles ; i++) {
+        virDomainChrDefPtr chr = vm->def->consoles[i];
         if (chr->source.type == VIR_DOMAIN_CHR_TYPE_PTY &&
             chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO) {
             if ((ret = qemuProcessExtractTTYPath(output, &offset,
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index e1a257d..78c0d45 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -888,6 +888,11 @@ SELinuxRestoreSecurityChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED,
 {
     virDomainObjPtr vm = opaque;
 
+    /* This is taken care of by processing of def->serials */
+    if (dev->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
+        dev->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)
+        return 0;
+
     return SELinuxRestoreSecurityChardevLabel(vm, &dev->source);
 }
 
@@ -1228,6 +1233,11 @@ SELinuxSetSecurityChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED,
 {
     virDomainObjPtr vm = opaque;
 
+    /* This is taken care of by processing of def->serials */
+    if (dev->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
+        dev->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)
+        return 0;
+
     return SELinuxSetSecurityChardevLabel(vm, &dev->source);
 }
 
diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
index ad4b8a7..71a4586 100644
--- a/src/security/virt-aa-helper.c
+++ b/src/security/virt-aa-helper.c
@@ -925,12 +925,16 @@ get_files(vahControl * ctl)
                                      ctl->def->serials[i]->source.type) != 0)
                 goto clean;
 
-    if (ctl->def->console && ctl->def->console->source.data.file.path)
-        if (vah_add_file_chardev(&buf,
-                                 ctl->def->console->source.data.file.path,
-                                 "rw",
-                                 ctl->def->console->source.type) != 0)
-            goto clean;
+    for (i = 0; i < ctl->def->nconsoles; i++)
+        if (ctl->def->consoles[i] &&
+            (ctl->def->consoles[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY ||
+             ctl->def->consoles[i]->source.type == VIR_DOMAIN_CHR_TYPE_DEV ||
+             ctl->def->consoles[i]->source.type == VIR_DOMAIN_CHR_TYPE_FILE ||
+             ctl->def->consoles[i]->source.type == VIR_DOMAIN_CHR_TYPE_PIPE) &&
+            ctl->def->consoles[i]->source.data.file.path)
+            if (vah_add_file(&buf,
+                             ctl->def->consoles[i]->source.data.file.path, "rw") != 0)
+                goto clean;
 
     for (i = 0 ; i < ctl->def->nparallels; i++)
         if (ctl->def->parallels[i] &&
diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
index 7b5e094..4459a2a 100644
--- a/src/uml/uml_conf.c
+++ b/src/uml/uml_conf.c
@@ -466,9 +466,13 @@ virCommandPtr umlBuildCommandLine(virConnectPtr conn,
     }
 
     for (i = 0 ; i < UML_MAX_CHAR_DEVICE ; i++) {
+        virDomainChrDefPtr chr = NULL;
         char *ret = NULL;
-        if (i == 0 && vm->def->console)
-            ret = umlBuildCommandLineChr(vm->def->console, "con", cmd);
+        for (j = 0 ; j < vm->def->nconsoles ; j++)
+            if (vm->def->consoles[j]->target.port == i)
+                chr = vm->def->consoles[j];
+        if (chr)
+            ret = umlBuildCommandLineChr(chr, "con", cmd);
         if (!ret)
             if (virAsprintf(&ret, "con%d=none", i) < 0)
                 goto no_memory;
diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
index 16ab73a..44529f0 100644
--- a/src/uml/uml_driver.c
+++ b/src/uml/uml_driver.c
@@ -248,10 +248,10 @@ umlIdentifyChrPTY(struct uml_driver *driver,
 {
     int i;
 
-    if (dom->def->console &&
-        dom->def->console->source.type == VIR_DOMAIN_CHR_TYPE_PTY)
+    for (i = 0 ; i < dom->def->nserials; i++)
+        if (dom->def->consoles[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY)
         if (umlIdentifyOneChrPTY(driver, dom,
-                                 dom->def->console, "con") < 0)
+                                 dom->def->consoles[i], "con") < 0)
             return -1;
 
     for (i = 0 ; i < dom->def->nserials; i++)
@@ -2390,8 +2390,8 @@ umlDomainOpenConsole(virDomainPtr dom,
                        _("Named device aliases are not supported"));
         goto cleanup;
     } else {
-        if (vm->def->console)
-            chr = vm->def->console;
+        if (vm->def->nconsoles)
+            chr = vm->def->consoles[0];
         else if (vm->def->nserials)
             chr = vm->def->serials[0];
     }
diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c
index b3e7782..beb2ba3 100644
--- a/src/xen/xen_driver.c
+++ b/src/xen/xen_driver.c
@@ -2136,8 +2136,8 @@ xenUnifiedDomainOpenConsole(virDomainPtr dom,
     if (!def)
         goto cleanup;
 
-    if (def->console)
-        chr = def->console;
+    if (def->nconsoles)
+        chr = def->consoles[0];
     else if (def->nserials)
         chr = def->serials[0];
 
diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c
index d44b0dc..e0bc043 100644
--- a/src/xenxs/xen_sxpr.c
+++ b/src/xenxs/xen_sxpr.c
@@ -202,7 +202,6 @@ xenParseSxprChar(const char *value,
         }
     }
 
-    /* Compat with legacy  <console tty='/dev/pts/5'/> syntax */
     switch (def->source.type) {
     case VIR_DOMAIN_CHR_TYPE_PTY:
         if (tty != NULL &&
@@ -1395,12 +1394,15 @@ xenParseSxpr(const struct sexpr *root,
             def->parallels[def->nparallels++] = chr;
         }
     } else {
+        def->nconsoles = 1;
+        if (VIR_ALLOC_N(def->consoles, 1) < 0)
+            goto no_memory;
         /* Fake a paravirt console, since that's not in the sexpr */
-        if (!(def->console = xenParseSxprChar("pty", tty)))
+        if (!(def->consoles[0] = xenParseSxprChar("pty", tty)))
             goto error;
-        def->console->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
-        def->console->target.port = 0;
-        def->console->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
+        def->consoles[0]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
+        def->consoles[0]->target.port = 0;
+        def->consoles[0]->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
     }
     VIR_FREE(tty);
 
@@ -1613,6 +1615,11 @@ xenFormatSxprChr(virDomainChrDefPtr def,
         if (def->source.data.nix.listen)
             virBufferAddLit(buf, ",server,nowait");
         break;
+
+    default:
+        XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
+                    _("unsupported chr device type '%s'"), type);
+        return -1;
     }
 
     if (virBufferError(buf)) {
diff --git a/src/xenxs/xen_xm.c b/src/xenxs/xen_xm.c
index ff173d8..a2ef8c8 100644
--- a/src/xenxs/xen_xm.c
+++ b/src/xenxs/xen_xm.c
@@ -1066,11 +1066,14 @@ xenParseXM(virConfPtr conf, int xendConfigVersion,
             }
         }
     } else {
-        if (!(def->console = xenParseSxprChar("pty", NULL)))
+        def->nconsoles = 1;
+        if (VIR_ALLOC_N(def->consoles, 1) < 0)
+            goto no_memory;
+        if (!(def->consoles[0] = xenParseSxprChar("pty", NULL)))
             goto cleanup;
-        def->console->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
-        def->console->target.port = 0;
-        def->console->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
+        def->consoles[0]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
+        def->consoles[0]->target.port = 0;
+        def->consoles[0]->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
     }
 
     if (hvm) {
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-auto.args b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-auto.args
index e3fbc24..715bda6 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-auto.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-auto.args
@@ -1,6 +1,7 @@
 LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
-pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -monitor \
-unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -device \
+pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -chardev \
+socket,id=charmonitor,path=/tmp/test-monitor,server,nowait -mon \
+chardev=charmonitor,id=monitor,mode=readline -no-acpi -boot c -device \
 virtio-serial-pci,id=virtio-serial0,max_ports=16,vectors=4,bus=pci.0,addr=0x3 \
 -device virtio-serial-pci,id=virtio-serial1,bus=pci.0,addr=0xa -device \
 virtio-serial-pci,id=virtio-serial2,bus=pci.0,addr=0x4 -hda \
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio.args b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio.args
index 5356bcc..d46ed67 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-channel-virtio.args
@@ -1,6 +1,7 @@
 LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
-pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -monitor \
-unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -device \
+pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -chardev \
+socket,id=charmonitor,path=/tmp/test-monitor,server,nowait -mon \
+chardev=charmonitor,id=monitor,mode=readline -no-acpi -boot c -device \
 virtio-serial-pci,id=virtio-serial1,bus=pci.0,addr=0xa -hda \
 /dev/HostVG/QEMUGuest1 -chardev pty,id=charchannel0 -device virtserialport,\
 bus=virtio-serial1.0,nr=3,chardev=charchannel0,id=channel0,\
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.args b/tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.args
new file mode 100644
index 0000000..8af2549
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.args
@@ -0,0 +1,12 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
+pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -chardev \
+socket,id=charmonitor,path=/tmp/test-monitor,server,nowait -mon \
+chardev=charmonitor,id=monitor,mode=readline -no-acpi -boot c -device \
+virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x3 -hda \
+/dev/HostVG/QEMUGuest1 -chardev pty,id=charserial0 \
+-device isa-serial,chardev=charserial0,id=serial0 -chardev pty,id=charconsole1 \
+-device virtconsole,chardev=charconsole1,id=console1 -chardev \
+pty,id=charconsole2 -device virtconsole,chardev=charconsole2,id=console2 \
+-chardev pty,id=charconsole3 -device virtconsole,chardev=charconsole3,\
+id=console3 -usb -device virtio-balloon-pci,id=balloon0,\
+bus=pci.0,addr=0x4
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.xml b/tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.xml
new file mode 100644
index 0000000..e65fb74
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.xml
@@ -0,0 +1,41 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219100</memory>
+  <currentMemory>219100</currentMemory>
+  <vcpu cpuset='1-4,8-20,525'>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' unit='0'/>
+    </disk>
+    <controller type='ide' index='0'/>
+    <controller type='virtio-serial' index='0'/>
+    <serial type='pty'>
+      <target port='0'/>
+    </serial>
+    <console type='pty'>
+      <target type='serial' port='0'/>
+    </console>
+    <console type='pty'>
+      <target type='virtio' port='1'/>
+    </console>
+    <console type='pty'>
+      <target type='virtio' port='2'/>
+    </console>
+    <console type='pty'>
+      <target type='virtio' port='3'/>
+    </console>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-console-virtio.args b/tests/qemuxml2argvdata/qemuxml2argv-console-virtio.args
index 7e852ff..9f23c27 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-console-virtio.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-console-virtio.args
@@ -1,6 +1,7 @@
 LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
-pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -monitor \
-unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -device \
+pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -chardev \
+socket,id=charmonitor,path=/tmp/test-monitor,server,nowait -mon \
+chardev=charmonitor,id=monitor,mode=readline -no-acpi -boot c -device \
 virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x3 -hda \
 /dev/HostVG/QEMUGuest1 -chardev pty,id=charconsole0 -device virtconsole,\
 chardev=charconsole0,id=console0 -usb -device virtio-balloon-pci,id=balloon0,\
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index a7ae925..2d158cf 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -471,11 +471,13 @@ mymain(void)
     DO_TEST("channel-guestfwd", false,
             QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
     DO_TEST("channel-virtio", false,
-            QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
+            QEMU_CAPS_DEVICE, QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG);
     DO_TEST("channel-virtio-auto", false,
-            QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
+            QEMU_CAPS_DEVICE, QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG);
     DO_TEST("console-virtio", false,
-            QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
+            QEMU_CAPS_DEVICE, QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG);
+    DO_TEST("console-virtio-many", false,
+            QEMU_CAPS_DEVICE, QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG);
     DO_TEST("channel-spicevmc", false,
             QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG,
             QEMU_CAPS_SPICE, QEMU_CAPS_CHARDEV_SPICEVMC);
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index af635d9..3f37520 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -174,6 +174,7 @@ mymain(void)
     DO_TEST("serial-many");
     DO_TEST("parallel-tcp");
     DO_TEST("console-compat");
+    DO_TEST("console-virtio-many");
     DO_TEST("channel-guestfwd");
     DO_TEST("channel-virtio");
 
-- 
1.7.6.4




More information about the libvir-list mailing list