mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-18 18:45:16 +00:00
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:
parent
b0a510ad2a
commit
0873b688c6
@ -2681,12 +2681,29 @@ qemu-kvm -net nic,model=? /dev/null
|
|||||||
<h6><a name="elementCharConsole">Console</a></h6>
|
<h6><a name="elementCharConsole">Console</a></h6>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This represents the primary console. This can be the paravirtualized
|
The console element is used to represent interactive consoles. Depending
|
||||||
console with Xen guests, virtio console for QEMU/KVM, or duplicates
|
on the type of guest in use, the consoles might be paravirtualized devices,
|
||||||
the primary serial port for fully virtualized guests without a
|
or they might be a clone of a serial device, according to the following
|
||||||
paravirtualized console.
|
rules:
|
||||||
</p>
|
</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><serial></code> element exists, the console
|
||||||
|
element will be copied to the serial element. If a <code><serial></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>
|
<p>
|
||||||
A virtio console device is exposed in the
|
A virtio console device is exposed in the
|
||||||
guest as /dev/hvc[0-7] (for more information, see
|
guest as /dev/hvc[0-7] (for more information, see
|
||||||
|
@ -1227,7 +1227,9 @@ void virDomainDefFree(virDomainDefPtr def)
|
|||||||
virDomainChrDefFree(def->channels[i]);
|
virDomainChrDefFree(def->channels[i]);
|
||||||
VIR_FREE(def->channels);
|
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++)
|
for (i = 0 ; i < def->nsounds ; i++)
|
||||||
virDomainSoundDefFree(def->sounds[i]);
|
virDomainSoundDefFree(def->sounds[i]);
|
||||||
@ -1618,6 +1620,9 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def,
|
|||||||
for (i = 0; i < def->nchannels ; i++)
|
for (i = 0; i < def->nchannels ; i++)
|
||||||
if (cb(def, &def->channels[i]->info, opaque) < 0)
|
if (cb(def, &def->channels[i]->info, opaque) < 0)
|
||||||
return -1;
|
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++)
|
for (i = 0; i < def->ninputs ; i++)
|
||||||
if (cb(def, &def->inputs[i]->info, opaque) < 0)
|
if (cb(def, &def->inputs[i]->info, opaque) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
@ -1630,9 +1635,6 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def,
|
|||||||
if (def->memballoon)
|
if (def->memballoon)
|
||||||
if (cb(def, &def->memballoon->info, opaque) < 0)
|
if (cb(def, &def->memballoon->info, opaque) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (def->console)
|
|
||||||
if (cb(def, &def->console->info, opaque) < 0)
|
|
||||||
return -1;
|
|
||||||
for (i = 0; i < def->nhubs ; i++)
|
for (i = 0; i < def->nhubs ; i++)
|
||||||
if (cb(def, &def->hubs[i]->info, opaque) < 0)
|
if (cb(def, &def->hubs[i]->info, opaque) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
@ -7203,20 +7205,46 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
|
|||||||
}
|
}
|
||||||
VIR_FREE(nodes);
|
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,
|
virDomainChrDefPtr chr = virDomainChrDefParseXML(caps,
|
||||||
node,
|
nodes[i],
|
||||||
flags);
|
flags);
|
||||||
if (!chr)
|
if (!chr)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
chr->target.port = 0;
|
|
||||||
/*
|
/*
|
||||||
* For HVM console actually created a serial device
|
* Some really crazy backcompat stuff for consoles
|
||||||
* while for non-HVM it was a parvirt console
|
*
|
||||||
|
* 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") &&
|
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) {
|
if (def->nserials != 0) {
|
||||||
virDomainChrDefFree(chr);
|
virDomainChrDefFree(chr);
|
||||||
} else {
|
} else {
|
||||||
@ -7224,14 +7252,24 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
|
|||||||
virDomainChrDefFree(chr);
|
virDomainChrDefFree(chr);
|
||||||
goto no_memory;
|
goto no_memory;
|
||||||
}
|
}
|
||||||
|
chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
|
||||||
def->nserials = 1;
|
def->nserials = 1;
|
||||||
def->serials[0] = chr;
|
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) {
|
if ((n = virXPathNodeSet("./devices/channel", ctxt, &nodes)) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
@ -8677,14 +8715,17 @@ bool virDomainDefCheckABIStability(virDomainDefPtr src,
|
|||||||
if (!virDomainChannelDefCheckABIStability(src->channels[i], dst->channels[i]))
|
if (!virDomainChannelDefCheckABIStability(src->channels[i], dst->channels[i]))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if ((!src->console && dst->console) ||
|
if (src->nconsoles != dst->nconsoles) {
|
||||||
(src->console && !dst->console)) {
|
|
||||||
virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
_("Target domain console count %d does not match source %d"),
|
_("Target domain console count %d does not match source %d"),
|
||||||
dst->console ? 1 : 0, src->console ? 1 : 0);
|
dst->nconsoles, src->nconsoles);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0 ; i < src->nconsoles ; i++)
|
||||||
|
if (!virDomainConsoleDefCheckABIStability(src->consoles[i], dst->consoles[i]))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
if (src->nhubs != dst->nhubs) {
|
if (src->nhubs != dst->nhubs) {
|
||||||
virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
_("Target domain hub device count %d does not match source %d"),
|
_("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]))
|
if (!virDomainHubDefCheckABIStability(src->hubs[i], dst->hubs[i]))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (src->console &&
|
|
||||||
!virDomainConsoleDefCheckABIStability(src->console, dst->console))
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if ((!src->watchdog && dst->watchdog) ||
|
if ((!src->watchdog && dst->watchdog) ||
|
||||||
(src->watchdog && !dst->watchdog)) {
|
(src->watchdog && !dst->watchdog)) {
|
||||||
@ -8820,8 +8858,8 @@ static int virDomainDefMaybeAddVirtioSerialController(virDomainDefPtr def)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (def->console) {
|
for (i = 0 ; i < def->nconsoles ; i++) {
|
||||||
virDomainChrDefPtr console = def->console;
|
virDomainChrDefPtr console = def->consoles[i];
|
||||||
|
|
||||||
if (console->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO) {
|
if (console->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO) {
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
@ -11079,15 +11117,27 @@ virDomainDefFormatInternal(virDomainDefPtr def,
|
|||||||
if (virDomainChrDefFormat(buf, def->parallels[n], flags) < 0)
|
if (virDomainChrDefFormat(buf, def->parallels[n], flags) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* If there's a PV console that's preferred.. */
|
for (n = 0 ; n < def->nconsoles ; n++) {
|
||||||
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 */
|
|
||||||
virDomainChrDef console;
|
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;
|
console.deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
|
||||||
if (virDomainChrDefFormat(buf, &console, flags) < 0)
|
if (virDomainChrDefFormat(buf, &console, flags) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -12690,9 +12740,9 @@ int virDomainChrDefForeach(virDomainDefPtr def,
|
|||||||
if (abortOnError && rc != 0)
|
if (abortOnError && rc != 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (def->console) {
|
for (i = 0 ; i < def->nconsoles ; i++) {
|
||||||
if ((iter)(def,
|
if ((iter)(def,
|
||||||
def->console,
|
def->consoles[i],
|
||||||
opaque) < 0)
|
opaque) < 0)
|
||||||
rc = -1;
|
rc = -1;
|
||||||
|
|
||||||
|
@ -1455,6 +1455,9 @@ struct _virDomainDef {
|
|||||||
int nchannels;
|
int nchannels;
|
||||||
virDomainChrDefPtr *channels;
|
virDomainChrDefPtr *channels;
|
||||||
|
|
||||||
|
int nconsoles;
|
||||||
|
virDomainChrDefPtr *consoles;
|
||||||
|
|
||||||
size_t nleases;
|
size_t nleases;
|
||||||
virDomainLeaseDefPtr *leases;
|
virDomainLeaseDefPtr *leases;
|
||||||
|
|
||||||
@ -1462,7 +1465,6 @@ struct _virDomainDef {
|
|||||||
virDomainHubDefPtr *hubs;
|
virDomainHubDefPtr *hubs;
|
||||||
|
|
||||||
/* Only 1 */
|
/* Only 1 */
|
||||||
virDomainChrDefPtr console;
|
|
||||||
virSecurityLabelDef seclabel;
|
virSecurityLabelDef seclabel;
|
||||||
virDomainWatchdogDefPtr watchdog;
|
virDomainWatchdogDefPtr watchdog;
|
||||||
virDomainMemballoonDefPtr memballoon;
|
virDomainMemballoonDefPtr memballoon;
|
||||||
|
@ -1680,10 +1680,18 @@ static int lxcVmStart(virConnectPtr conn,
|
|||||||
_("Failed to allocate tty"));
|
_("Failed to allocate tty"));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (vm->def->console &&
|
if (vm->def->nconsoles) {
|
||||||
vm->def->console->source.type == VIR_DOMAIN_CHR_TYPE_PTY) {
|
if (vm->def->nconsoles > 1) {
|
||||||
VIR_FREE(vm->def->console->source.data.file.path);
|
lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||||
vm->def->console->source.data.file.path = parentTtyPath;
|
_("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 {
|
} else {
|
||||||
VIR_FREE(parentTtyPath);
|
VIR_FREE(parentTtyPath);
|
||||||
}
|
}
|
||||||
@ -3026,8 +3034,8 @@ lxcDomainOpenConsole(virDomainPtr dom,
|
|||||||
_("Named device aliases are not supported"));
|
_("Named device aliases are not supported"));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
} else {
|
} else {
|
||||||
if (vm->def->console)
|
if (vm->def->nconsoles)
|
||||||
chr = vm->def->console;
|
chr = vm->def->consoles[0];
|
||||||
else if (vm->def->nserials)
|
else if (vm->def->nserials)
|
||||||
chr = vm->def->serials[0];
|
chr = vm->def->serials[0];
|
||||||
}
|
}
|
||||||
|
@ -716,16 +716,16 @@ qemuAssignDeviceAliases(virDomainDefPtr def, virBitmapPtr qemuCaps)
|
|||||||
if (virAsprintf(&def->channels[i]->info.alias, "channel%d", i) < 0)
|
if (virAsprintf(&def->channels[i]->info.alias, "channel%d", i) < 0)
|
||||||
goto no_memory;
|
goto no_memory;
|
||||||
}
|
}
|
||||||
for (i = 0; i < def->nsmartcards ; i++) {
|
for (i = 0; i < def->nconsoles ; i++) {
|
||||||
if (virAsprintf(&def->smartcards[i]->info.alias, "smartcard%d", i) < 0)
|
if (virAsprintf(&def->consoles[i]->info.alias, "console%d", i) < 0)
|
||||||
goto no_memory;
|
goto no_memory;
|
||||||
}
|
}
|
||||||
for (i = 0; i < def->nhubs ; i++) {
|
for (i = 0; i < def->nhubs ; i++) {
|
||||||
if (virAsprintf(&def->hubs[i]->info.alias, "hub%d", i) < 0)
|
if (virAsprintf(&def->hubs[i]->info.alias, "hub%d", i) < 0)
|
||||||
goto no_memory;
|
goto no_memory;
|
||||||
}
|
}
|
||||||
if (def->console) {
|
for (i = 0; i < def->nsmartcards ; i++) {
|
||||||
if (virAsprintf(&def->console->info.alias, "console%d", i) < 0)
|
if (virAsprintf(&def->smartcards[i]->info.alias, "smartcard%d", i) < 0)
|
||||||
goto no_memory;
|
goto no_memory;
|
||||||
}
|
}
|
||||||
if (def->watchdog) {
|
if (def->watchdog) {
|
||||||
@ -4498,8 +4498,8 @@ qemuBuildCommandLine(virConnectPtr conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Explicit console devices */
|
/* Explicit console devices */
|
||||||
if (def->console) {
|
for (i = 0 ; i < def->nconsoles ; i++) {
|
||||||
virDomainChrDefPtr console = def->console;
|
virDomainChrDefPtr console = def->consoles[i];
|
||||||
char *devstr;
|
char *devstr;
|
||||||
|
|
||||||
switch(console->targetType) {
|
switch(console->targetType) {
|
||||||
|
@ -10519,9 +10519,11 @@ qemuDomainOpenConsole(virDomainPtr dom,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dev_name) {
|
if (dev_name) {
|
||||||
if (vm->def->console &&
|
for (i = 0 ; !chr && i < vm->def->nconsoles ; i++) {
|
||||||
STREQ(dev_name, vm->def->console->info.alias))
|
if (vm->def->consoles[i]->info.alias &&
|
||||||
chr = vm->def->console;
|
STREQ(dev_name, vm->def->consoles[i]->info.alias))
|
||||||
|
chr = vm->def->consoles[i];
|
||||||
|
}
|
||||||
for (i = 0 ; !chr && i < vm->def->nserials ; i++) {
|
for (i = 0 ; !chr && i < vm->def->nserials ; i++) {
|
||||||
if (STREQ(dev_name, vm->def->serials[i]->info.alias))
|
if (STREQ(dev_name, vm->def->serials[i]->info.alias))
|
||||||
chr = vm->def->serials[i];
|
chr = vm->def->serials[i];
|
||||||
@ -10531,8 +10533,8 @@ qemuDomainOpenConsole(virDomainPtr dom,
|
|||||||
chr = vm->def->parallels[i];
|
chr = vm->def->parallels[i];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (vm->def->console)
|
if (vm->def->nconsoles)
|
||||||
chr = vm->def->console;
|
chr = vm->def->consoles[0];
|
||||||
else if (vm->def->nserials)
|
else if (vm->def->nserials)
|
||||||
chr = vm->def->serials[0];
|
chr = vm->def->serials[0];
|
||||||
}
|
}
|
||||||
|
@ -1112,8 +1112,8 @@ qemuProcessFindCharDevicePTYsMonitor(virDomainObjPtr vm,
|
|||||||
paths, chardevfmt) < 0)
|
paths, chardevfmt) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (vm->def->console &&
|
if (qemuProcessLookupPTYs(vm->def->consoles, vm->def->nconsoles,
|
||||||
qemuProcessLookupPTYs(&vm->def->console, 1, paths, chardevfmt) < 0)
|
paths, chardevfmt) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1161,8 +1161,8 @@ qemuProcessFindCharDevicePTYs(virDomainObjPtr vm,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vm->def->console) {
|
for (i = 0 ; i < vm->def->nconsoles ; i++) {
|
||||||
virDomainChrDefPtr chr = vm->def->console;
|
virDomainChrDefPtr chr = vm->def->consoles[i];
|
||||||
if (chr->source.type == VIR_DOMAIN_CHR_TYPE_PTY &&
|
if (chr->source.type == VIR_DOMAIN_CHR_TYPE_PTY &&
|
||||||
chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO) {
|
chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO) {
|
||||||
if ((ret = qemuProcessExtractTTYPath(output, &offset,
|
if ((ret = qemuProcessExtractTTYPath(output, &offset,
|
||||||
|
@ -888,6 +888,11 @@ SELinuxRestoreSecurityChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED,
|
|||||||
{
|
{
|
||||||
virDomainObjPtr vm = opaque;
|
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);
|
return SELinuxRestoreSecurityChardevLabel(vm, &dev->source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1228,6 +1233,11 @@ SELinuxSetSecurityChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED,
|
|||||||
{
|
{
|
||||||
virDomainObjPtr vm = opaque;
|
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);
|
return SELinuxSetSecurityChardevLabel(vm, &dev->source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -925,12 +925,16 @@ get_files(vahControl * ctl)
|
|||||||
ctl->def->serials[i]->source.type) != 0)
|
ctl->def->serials[i]->source.type) != 0)
|
||||||
goto clean;
|
goto clean;
|
||||||
|
|
||||||
if (ctl->def->console && ctl->def->console->source.data.file.path)
|
for (i = 0; i < ctl->def->nconsoles; i++)
|
||||||
if (vah_add_file_chardev(&buf,
|
if (ctl->def->consoles[i] &&
|
||||||
ctl->def->console->source.data.file.path,
|
(ctl->def->consoles[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY ||
|
||||||
"rw",
|
ctl->def->consoles[i]->source.type == VIR_DOMAIN_CHR_TYPE_DEV ||
|
||||||
ctl->def->console->source.type) != 0)
|
ctl->def->consoles[i]->source.type == VIR_DOMAIN_CHR_TYPE_FILE ||
|
||||||
goto clean;
|
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++)
|
for (i = 0 ; i < ctl->def->nparallels; i++)
|
||||||
if (ctl->def->parallels[i] &&
|
if (ctl->def->parallels[i] &&
|
||||||
|
@ -466,9 +466,13 @@ virCommandPtr umlBuildCommandLine(virConnectPtr conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0 ; i < UML_MAX_CHAR_DEVICE ; i++) {
|
for (i = 0 ; i < UML_MAX_CHAR_DEVICE ; i++) {
|
||||||
|
virDomainChrDefPtr chr = NULL;
|
||||||
char *ret = NULL;
|
char *ret = NULL;
|
||||||
if (i == 0 && vm->def->console)
|
for (j = 0 ; j < vm->def->nconsoles ; j++)
|
||||||
ret = umlBuildCommandLineChr(vm->def->console, "con", cmd);
|
if (vm->def->consoles[j]->target.port == i)
|
||||||
|
chr = vm->def->consoles[j];
|
||||||
|
if (chr)
|
||||||
|
ret = umlBuildCommandLineChr(chr, "con", cmd);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
if (virAsprintf(&ret, "con%d=none", i) < 0)
|
if (virAsprintf(&ret, "con%d=none", i) < 0)
|
||||||
goto no_memory;
|
goto no_memory;
|
||||||
|
@ -248,10 +248,10 @@ umlIdentifyChrPTY(struct uml_driver *driver,
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (dom->def->console &&
|
for (i = 0 ; i < dom->def->nserials; i++)
|
||||||
dom->def->console->source.type == VIR_DOMAIN_CHR_TYPE_PTY)
|
if (dom->def->consoles[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY)
|
||||||
if (umlIdentifyOneChrPTY(driver, dom,
|
if (umlIdentifyOneChrPTY(driver, dom,
|
||||||
dom->def->console, "con") < 0)
|
dom->def->consoles[i], "con") < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
for (i = 0 ; i < dom->def->nserials; i++)
|
for (i = 0 ; i < dom->def->nserials; i++)
|
||||||
@ -2390,8 +2390,8 @@ umlDomainOpenConsole(virDomainPtr dom,
|
|||||||
_("Named device aliases are not supported"));
|
_("Named device aliases are not supported"));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
} else {
|
} else {
|
||||||
if (vm->def->console)
|
if (vm->def->nconsoles)
|
||||||
chr = vm->def->console;
|
chr = vm->def->consoles[0];
|
||||||
else if (vm->def->nserials)
|
else if (vm->def->nserials)
|
||||||
chr = vm->def->serials[0];
|
chr = vm->def->serials[0];
|
||||||
}
|
}
|
||||||
|
@ -2136,8 +2136,8 @@ xenUnifiedDomainOpenConsole(virDomainPtr dom,
|
|||||||
if (!def)
|
if (!def)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (def->console)
|
if (def->nconsoles)
|
||||||
chr = def->console;
|
chr = def->consoles[0];
|
||||||
else if (def->nserials)
|
else if (def->nserials)
|
||||||
chr = def->serials[0];
|
chr = def->serials[0];
|
||||||
|
|
||||||
|
@ -202,7 +202,6 @@ xenParseSxprChar(const char *value,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compat with legacy <console tty='/dev/pts/5'/> syntax */
|
|
||||||
switch (def->source.type) {
|
switch (def->source.type) {
|
||||||
case VIR_DOMAIN_CHR_TYPE_PTY:
|
case VIR_DOMAIN_CHR_TYPE_PTY:
|
||||||
if (tty != NULL &&
|
if (tty != NULL &&
|
||||||
@ -1395,12 +1394,15 @@ xenParseSxpr(const struct sexpr *root,
|
|||||||
def->parallels[def->nparallels++] = chr;
|
def->parallels[def->nparallels++] = chr;
|
||||||
}
|
}
|
||||||
} else {
|
} 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 */
|
/* 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;
|
goto error;
|
||||||
def->console->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
|
def->consoles[0]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
|
||||||
def->console->target.port = 0;
|
def->consoles[0]->target.port = 0;
|
||||||
def->console->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
|
def->consoles[0]->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
|
||||||
}
|
}
|
||||||
VIR_FREE(tty);
|
VIR_FREE(tty);
|
||||||
|
|
||||||
@ -1613,6 +1615,11 @@ xenFormatSxprChr(virDomainChrDefPtr def,
|
|||||||
if (def->source.data.nix.listen)
|
if (def->source.data.nix.listen)
|
||||||
virBufferAddLit(buf, ",server,nowait");
|
virBufferAddLit(buf, ",server,nowait");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
|
_("unsupported chr device type '%s'"), type);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virBufferError(buf)) {
|
if (virBufferError(buf)) {
|
||||||
|
@ -1066,11 +1066,14 @@ xenParseXM(virConfPtr conf, int xendConfigVersion,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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;
|
goto cleanup;
|
||||||
def->console->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
|
def->consoles[0]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
|
||||||
def->console->target.port = 0;
|
def->consoles[0]->target.port = 0;
|
||||||
def->console->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
|
def->consoles[0]->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hvm) {
|
if (hvm) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
|
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 \
|
pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -chardev \
|
||||||
unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -device \
|
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 \
|
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 \
|
-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 \
|
virtio-serial-pci,id=virtio-serial2,bus=pci.0,addr=0x4 -hda \
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
|
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 \
|
pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -chardev \
|
||||||
unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -device \
|
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 \
|
virtio-serial-pci,id=virtio-serial1,bus=pci.0,addr=0xa -hda \
|
||||||
/dev/HostVG/QEMUGuest1 -chardev pty,id=charchannel0 -device virtserialport,\
|
/dev/HostVG/QEMUGuest1 -chardev pty,id=charchannel0 -device virtserialport,\
|
||||||
bus=virtio-serial1.0,nr=3,chardev=charchannel0,id=channel0,\
|
bus=virtio-serial1.0,nr=3,chardev=charchannel0,id=channel0,\
|
||||||
|
12
tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.args
Normal file
12
tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.args
Normal 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
|
41
tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.xml
Normal file
41
tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.xml
Normal 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>
|
@ -1,6 +1,7 @@
|
|||||||
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
|
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 \
|
pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -chardev \
|
||||||
unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -device \
|
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 \
|
virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x3 -hda \
|
||||||
/dev/HostVG/QEMUGuest1 -chardev pty,id=charconsole0 -device virtconsole,\
|
/dev/HostVG/QEMUGuest1 -chardev pty,id=charconsole0 -device virtconsole,\
|
||||||
chardev=charconsole0,id=console0 -usb -device virtio-balloon-pci,id=balloon0,\
|
chardev=charconsole0,id=console0 -usb -device virtio-balloon-pci,id=balloon0,\
|
||||||
|
@ -474,11 +474,13 @@ mymain(void)
|
|||||||
DO_TEST("channel-guestfwd", false,
|
DO_TEST("channel-guestfwd", false,
|
||||||
QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
|
QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
|
||||||
DO_TEST("channel-virtio", false,
|
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,
|
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,
|
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,
|
DO_TEST("channel-spicevmc", false,
|
||||||
QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG,
|
QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG,
|
||||||
QEMU_CAPS_SPICE, QEMU_CAPS_CHARDEV_SPICEVMC);
|
QEMU_CAPS_SPICE, QEMU_CAPS_CHARDEV_SPICEVMC);
|
||||||
|
@ -174,6 +174,7 @@ mymain(void)
|
|||||||
DO_TEST("serial-many");
|
DO_TEST("serial-many");
|
||||||
DO_TEST("parallel-tcp");
|
DO_TEST("parallel-tcp");
|
||||||
DO_TEST("console-compat");
|
DO_TEST("console-compat");
|
||||||
|
DO_TEST("console-virtio-many");
|
||||||
DO_TEST("channel-guestfwd");
|
DO_TEST("channel-guestfwd");
|
||||||
DO_TEST("channel-virtio");
|
DO_TEST("channel-virtio");
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user