]> xenbits.xensource.com Git - libvirt.git/commitdiff
Allow multiple consoles per virtual guest
authorDaniel P. Berrange <berrange@redhat.com>
Wed, 23 Feb 2011 18:27:23 +0000 (18:27 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Thu, 3 Nov 2011 12:01:05 +0000 (12:01 +0000)
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

21 files changed:
docs/formatdomain.html.in
src/conf/domain_conf.c
src/conf/domain_conf.h
src/lxc/lxc_driver.c
src/qemu/qemu_command.c
src/qemu/qemu_driver.c
src/qemu/qemu_process.c
src/security/security_selinux.c
src/security/virt-aa-helper.c
src/uml/uml_conf.c
src/uml/uml_driver.c
src/xen/xen_driver.c
src/xenxs/xen_sxpr.c
src/xenxs/xen_xm.c
tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-auto.args
tests/qemuxml2argvdata/qemuxml2argv-channel-virtio.args
tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.args [new file with mode: 0644]
tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.xml [new file with mode: 0644]
tests/qemuxml2argvdata/qemuxml2argv-console-virtio.args
tests/qemuxml2argvtest.c
tests/qemuxml2xmltest.c

index c3e7752f8b99121f69ec02951e57a26b6b4d7c2d..cbad196d9b25a990c0f6a5e24293e6edf8510e3f 100644 (file)
@@ -2681,12 +2681,29 @@ qemu-kvm -net nic,model=? /dev/null
     <h6><a name="elementCharConsole">Console</a></h6>
 
     <p>
-      This represents the primary console. This can be the paravirtualized
-      console with Xen guests, virtio console for QEMU/KVM, or duplicates
-      the primary serial port for fully virtualized guests without a
-      paravirtualized console.
+      The console element is used to represent interactive consoles. Depending
+      on the type of guest in use, the consoles might be paravirtualized devices,
+      or they might be a clone of a serial device, according to the following
+      rules:
     </p>
 
+    <ul>
+      <li>If no <code>targetType</code> attribue is set, then the default
+        device type is according to the hypervisor's rules. The default
+        type will be added when re-querying the XML fed into libvirt.
+        For fully virtualized guests, the default device type will usually
+        be a serial port.</li>
+      <li>If the <code>targetType</code> attribute is <code>serial</code>,
+        then if no <code>&lt;serial&gt;</code> element exists, the console
+        element will be copied to the serial element. If a <code>&lt;serial&gt;</code>
+        element does already exist, the console element will be ignored.</li>
+      <li>If the <code>targetType</code> attribute is not <code>serial</code>,
+        it will be treated normally.</li>
+      <li>Only the first <code>console</code> element may use a <code>targetType</code>
+        of <code>serial</code>. Secondary consoles must all be paravirtualized.
+      </li>
+    </ul>
+
     <p>
       A virtio console device is exposed in the
       guest as /dev/hvc[0-7] (for more information, see
index 6e2d421527fdf941eea8088dd405f72a5f27b5c8..e88a1cfdac229f90ab2f4fd2473bf5b2d41b6f58 100644 (file)
@@ -1227,7 +1227,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]);
@@ -1618,6 +1620,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;
@@ -1630,9 +1635,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;
@@ -7203,20 +7205,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 {
@@ -7224,14 +7252,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;
@@ -8677,14 +8715,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"),
@@ -8696,9 +8737,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)) {
@@ -8820,8 +8858,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;
@@ -11079,15 +11117,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;
@@ -12690,9 +12740,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;
 
index f74f4bb7b65b772a741d877210fd8435b63968c7..c33e25321376326e7a51beb8451f3a78f711873f 100644 (file)
@@ -1455,6 +1455,9 @@ struct _virDomainDef {
     int nchannels;
     virDomainChrDefPtr *channels;
 
+    int nconsoles;
+    virDomainChrDefPtr *consoles;
+
     size_t nleases;
     virDomainLeaseDefPtr *leases;
 
@@ -1462,7 +1465,6 @@ struct _virDomainDef {
     virDomainHubDefPtr *hubs;
 
     /* Only 1 */
-    virDomainChrDefPtr console;
     virSecurityLabelDef seclabel;
     virDomainWatchdogDefPtr watchdog;
     virDomainMemballoonDefPtr memballoon;
index 409662661331d40d305a023b6ead12f8a101e3a9..45ef3bd21261ea8577a1132c5af50ee4aa10f776 100644 (file)
@@ -1680,10 +1680,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);
     }
@@ -3026,8 +3034,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];
     }
index dc92fa3ebd2672013726f4a489396a78a9f2aa8d..826c1d37a06a3a5a62938348fd1495a35c9db6ed 100644 (file)
@@ -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) {
@@ -4498,8 +4498,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) {
index 5e49ff458b5edf3836322b2eeda29dfe8a7b51ae..118197a05e70ebeda7af7243346c02b2d324bbb1 100644 (file)
@@ -10519,9 +10519,11 @@ 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 (vm->def->consoles[i]->info.alias &&
+                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];
@@ -10531,8 +10533,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];
     }
index 47164f7b476845be871a637e20fd3a2abbc63156..2882ef8f6b15eaeb65b9abb76965ea4ba947b9d1 100644 (file)
@@ -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,
index e1a257d183c222db94dc4718e6829221577627b1..78c0d45643c212bf0eb5007e4e89f92481bd86e7 100644 (file)
@@ -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);
 }
 
index ad4b8a7cfd4dee95b904cdbde8b650c6f6d751a9..71a4586f31bfd4ccb75a7dd8434fbf27529dcc20 100644 (file)
@@ -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] &&
index 7b5e094c4df855b0df5e39564b8f9cb45c41bb37..4459a2a3edfe72bb5bd693a304616b8339736f3d 100644 (file)
@@ -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;
index 16ab73a17066c67724e3a1eb9c562e3a76ce17d6..44529f0eca3228493cced75308a9b8a063cc652c 100644 (file)
@@ -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];
     }
index b3e7782890258a5536219e6f23f920d23dff30c7..beb2ba31af8830f5c5148341d2717e305c2f6275 100644 (file)
@@ -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];
 
index d44b0dc55ab539740c42bad9bc0d1f6e998a72f0..e0bc043a233bcc03b7a1d798a4d02831743c2d6b 100644 (file)
@@ -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)) {
index ff173d8de3bae95542fe8b06a87551348f90922e..a2ef8c8d7b33c8fa53ff77eb0dbd7e367acac472 100644 (file)
@@ -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) {
index e3fbc248087f350659d5d99286b88e3c04890167..715bda6843b648333749030c0dc8161904f06e6b 100644 (file)
@@ -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 \
index 5356bccc31434b7d81b075b82b3870e404194e76..d46ed67e0150187129e87ce0b7362114a99134c6 100644 (file)
@@ -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 (file)
index 0000000..8af2549
--- /dev/null
@@ -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 (file)
index 0000000..e65fb74
--- /dev/null
@@ -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>
index 7e852ff7b9d4cd994afb5fbd903f89916d19fcd9..9f23c27f22dd96f584c3b7c57706592e3e107c1f 100644 (file)
@@ -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,\
index 4d6db01925f718b2d96fe679e2ce6213ec7d48ed..d9a6e8da5ba9867251d243ffd0ebe00e6cf76319 100644 (file)
@@ -474,11 +474,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);
index af635d9596f770df8363ca57042adfc288f6999b..3f375209a42c2f67fe595d258e3d43c942319883 100644 (file)
@@ -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");