Allow multiple consoles per virtual guest

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
This commit is contained in:
Daniel P. Berrange 2011-02-23 18:27:23 +00:00
parent b0a510ad2a
commit 0873b688c6
21 changed files with 256 additions and 90 deletions

View 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

View 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)
goto cleanup;
} else if (def->nserials != 0) {
/* ..else for legacy compat duplicate the first serial device as a
* console */
for (n = 0 ; n < def->nconsoles ; n++) {
virDomainChrDef console;
memcpy(&console, def->serials[0], sizeof(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;
}
if (STREQ(def->os.type, "hvm") &&
def->nconsoles == 0 &&
def->nserials > 0) {
virDomainChrDef 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;

View 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;

View 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];
}

View 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) {

View 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];
}

View 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,

View 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);
}

View 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] &&

View 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;

View 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];
}

View 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];

View 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)) {

View 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) {

View 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 \

View 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,\

View File

@ -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

View File

@ -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>

View 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,\

View 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);

View 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");