2010-12-16 15:07:07 +00:00
|
|
|
/*
|
|
|
|
* qemu_command.c: QEMU command generation
|
|
|
|
*
|
2016-01-11 20:12:08 +00:00
|
|
|
* Copyright (C) 2006-2016 Red Hat, Inc.
|
2010-12-16 15:07:07 +00:00
|
|
|
* Copyright (C) 2006 Daniel P. Berrange
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2010-12-16 15:07:07 +00:00
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "qemu_command.h"
|
2012-08-16 15:42:48 +00:00
|
|
|
#include "qemu_hostdev.h"
|
2010-12-16 15:07:07 +00:00
|
|
|
#include "qemu_capabilities.h"
|
2016-02-15 15:26:40 +00:00
|
|
|
#include "qemu_interface.h"
|
2016-02-16 15:24:35 +00:00
|
|
|
#include "qemu_alias.h"
|
2010-12-16 15:07:07 +00:00
|
|
|
#include "cpu/cpu.h"
|
2013-08-26 22:04:19 +00:00
|
|
|
#include "dirname.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2012-12-10 22:02:41 +00:00
|
|
|
#include "virarch.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2013-04-20 09:11:25 +00:00
|
|
|
#include "virnetdev.h"
|
qemu: setup tap devices for macTableManager='libvirt'
When libvirt is managing the MAC table of a Linux host bridge, it must
turn off learning and unicast_flood for each tap device attached to
that bridge, then add a Forwarding Database (fdb) entry for the tap
device using the MAC address from the domain interface config.
Once we have disabled learning and flooding, any packet that has a
destination MAC address not present in the fdb will be dropped by the
bridge. This, along with the opportunistic disabling of promiscuous
mode[*], can result in enhanced network performance. and a potential
slight security improvement.
[*] If there is only one device on the bridge with learning/unicast_flood
enabled, then that device will automatically have promiscuous mode
disabled. If there are *no* devices with learning/unicast_flood
enabled (e.g. for a libvirt "route", "nat", or isolated network that
has no physical device attached), then all non-tap devices will have
promiscuous mode disabled (tap devices always have promiscuous mode
enabled, which may be a bug in the kernel, but in practice has 0
effect).
None of this has any effect for kernels prior to 3.15 (upstream kernel
commit 2796d0c648c940b4796f84384fbcfb0a2399db84 "bridge: Automatically
manage port promiscuous mode"). Even after that, until kernel 3.17
(upstream commit 5be5a2df40f005ea7fb7e280e87bbbcfcf1c2fc0 "bridge: Add
filtering support for default_pvid") traffic will not be properly
forwarded without manually adding vlan table entries. Unfortunately,
although the presence of the first patch is signalled by existence of
the "learning" and "unicast_flood" options in sysfs, there is no
reliable way to query whether or not the system's kernel has the
second of those patches installed, the only thing that can be done is
to try the setting and see if traffic continues to pass.
2014-11-21 22:03:14 +00:00
|
|
|
#include "virnetdevbridge.h"
|
2013-01-25 02:45:31 +00:00
|
|
|
#include "virstring.h"
|
qemu: fix RTC_CHANGE event for <clock offset='variable' basis='utc'/>
commit e31b5cf393857 attempted to fix libvirt's
VIR_DOMAIN_EVENT_ID_RTC_CHANGE, which is documentated to always
provide the new offset of the domain's real time clock from UTC. The
problem was that, in the case that qemu is provided with an "-rtc
base=x" where x is an absolute time (rather than "utc" or
"localtime"), the offset sent by qemu's RTC_CHANGE event is *not* the
new offset from UTC, but rather is the sum of all changes to the
domain's RTC since it was started with base=x.
So, despite what was said in commit e31b5cf393857, if we assume that
the original value stored in "adjustment" was the offset from UTC at
the time the domain was started, we can always determine the current
offset from UTC by simply adding the most recent (i.e. current) offset
from qemu to that original adjustment.
This patch accomplishes that by storing the initial adjustment in the
domain's status as "adjustment0". Each time a new RTC_CHANGE event is
received from qemu, we simply add adjustment0 to the value sent by
qemu, store that as the new adjustment, and forward that value on to
any event handler.
This patch (*not* e31b5cf393857, which should be reverted prior to
applying this patch) fixes:
https://bugzilla.redhat.com/show_bug.cgi?id=964177
(for the case where basis='utc'. It does not fix basis='localtime')
2014-05-21 09:54:34 +00:00
|
|
|
#include "virtime.h"
|
2012-12-13 18:01:25 +00:00
|
|
|
#include "viruuid.h"
|
2010-12-16 15:07:07 +00:00
|
|
|
#include "domain_nwfilter.h"
|
2014-05-10 16:35:24 +00:00
|
|
|
#include "domain_addr.h"
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 10:56:13 +00:00
|
|
|
#include "domain_audit.h"
|
2011-04-14 16:05:14 +00:00
|
|
|
#include "domain_conf.h"
|
2014-11-18 23:55:48 +00:00
|
|
|
#include "netdev_bandwidth_conf.h"
|
2012-08-14 00:09:12 +00:00
|
|
|
#include "snapshot_conf.h"
|
2013-07-18 10:39:55 +00:00
|
|
|
#include "storage_conf.h"
|
2014-06-24 13:46:23 +00:00
|
|
|
#include "secret_conf.h"
|
2011-07-04 06:27:12 +00:00
|
|
|
#include "network/bridge_driver.h"
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
#include "virnetdevtap.h"
|
2011-11-01 01:29:07 +00:00
|
|
|
#include "base64.h"
|
2012-08-16 15:41:06 +00:00
|
|
|
#include "device_conf.h"
|
2012-12-13 15:25:48 +00:00
|
|
|
#include "virstoragefile.h"
|
2013-04-12 20:55:46 +00:00
|
|
|
#include "virtpm.h"
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
#include "virscsi.h"
|
2014-11-04 02:44:40 +00:00
|
|
|
#include "virnuma.h"
|
2016-02-03 13:33:28 +00:00
|
|
|
#include "virgic.h"
|
2013-04-20 09:11:25 +00:00
|
|
|
#if defined(__linux__)
|
|
|
|
# include <linux/capability.h>
|
|
|
|
#endif
|
2016-02-23 13:05:09 +00:00
|
|
|
#include "logging/log_manager.h"
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("qemu.qemu_command");
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
VIR_ENUM_DECL(virDomainDiskQEMUBus)
|
|
|
|
VIR_ENUM_IMPL(virDomainDiskQEMUBus, VIR_DOMAIN_DISK_BUS_LAST,
|
|
|
|
"ide",
|
|
|
|
"floppy",
|
|
|
|
"scsi",
|
|
|
|
"virtio",
|
|
|
|
"xen",
|
|
|
|
"usb",
|
|
|
|
"uml",
|
2013-07-31 13:00:26 +00:00
|
|
|
"sata",
|
|
|
|
"sd")
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
VIR_ENUM_DECL(qemuDiskCacheV2)
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(qemuDiskCacheV2, VIR_DOMAIN_DISK_CACHE_LAST,
|
|
|
|
"default",
|
|
|
|
"none",
|
|
|
|
"writethrough",
|
2011-09-02 13:36:58 +00:00
|
|
|
"writeback",
|
2011-09-22 19:33:47 +00:00
|
|
|
"directsync",
|
|
|
|
"unsafe");
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
VIR_ENUM_IMPL(qemuVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
|
|
|
|
"std",
|
|
|
|
"cirrus",
|
|
|
|
"vmware",
|
|
|
|
"", /* no arg needed for xen */
|
|
|
|
"", /* don't support vbox */
|
2015-04-07 20:35:07 +00:00
|
|
|
"qxl",
|
2015-11-25 08:42:32 +00:00
|
|
|
"", /* don't support parallels */
|
|
|
|
"" /* no need for virtio */);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-12-14 07:08:01 +00:00
|
|
|
VIR_ENUM_DECL(qemuDeviceVideo)
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(qemuDeviceVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
|
|
|
|
"VGA",
|
|
|
|
"cirrus-vga",
|
|
|
|
"vmware-svga",
|
|
|
|
"", /* no device for xen */
|
|
|
|
"", /* don't support vbox */
|
2015-04-07 20:35:07 +00:00
|
|
|
"qxl-vga",
|
2015-11-25 08:42:32 +00:00
|
|
|
"", /* don't support parallels */
|
|
|
|
"virtio-vga");
|
2012-12-14 07:08:01 +00:00
|
|
|
|
2012-05-15 22:55:10 +00:00
|
|
|
VIR_ENUM_DECL(qemuSoundCodec)
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(qemuSoundCodec, VIR_DOMAIN_SOUND_CODEC_TYPE_LAST,
|
|
|
|
"hda-duplex",
|
|
|
|
"hda-micro");
|
|
|
|
|
2011-09-02 13:21:23 +00:00
|
|
|
VIR_ENUM_DECL(qemuControllerModelUSB)
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(qemuControllerModelUSB, VIR_DOMAIN_CONTROLLER_MODEL_USB_LAST,
|
|
|
|
"piix3-usb-uhci",
|
|
|
|
"piix4-usb-uhci",
|
|
|
|
"usb-ehci",
|
|
|
|
"ich9-usb-ehci1",
|
|
|
|
"ich9-usb-uhci1",
|
|
|
|
"ich9-usb-uhci2",
|
|
|
|
"ich9-usb-uhci3",
|
|
|
|
"vt82c686b-usb-uhci",
|
2012-06-21 13:45:25 +00:00
|
|
|
"pci-ohci",
|
2012-07-02 15:28:43 +00:00
|
|
|
"nec-usb-xhci",
|
|
|
|
"none");
|
2011-09-02 13:21:23 +00:00
|
|
|
|
2011-10-11 11:30:40 +00:00
|
|
|
VIR_ENUM_DECL(qemuDomainFSDriver)
|
|
|
|
VIR_ENUM_IMPL(qemuDomainFSDriver, VIR_DOMAIN_FS_DRIVER_TYPE_LAST,
|
|
|
|
"local",
|
|
|
|
"local",
|
2013-04-22 14:06:14 +00:00
|
|
|
"handle",
|
2013-04-22 14:06:17 +00:00
|
|
|
NULL,
|
2015-01-13 11:27:36 +00:00
|
|
|
NULL,
|
2013-04-22 14:06:14 +00:00
|
|
|
NULL);
|
2011-10-11 11:30:40 +00:00
|
|
|
|
2014-07-02 09:15:45 +00:00
|
|
|
VIR_ENUM_DECL(qemuNumaPolicy)
|
|
|
|
VIR_ENUM_IMPL(qemuNumaPolicy, VIR_DOMAIN_NUMATUNE_MEM_LAST,
|
|
|
|
"bind",
|
|
|
|
"preferred",
|
|
|
|
"interleave");
|
2011-09-02 13:21:23 +00:00
|
|
|
|
2016-02-29 12:24:40 +00:00
|
|
|
/**
|
|
|
|
* qemuVirCommandGetFDSet:
|
|
|
|
* @cmd: the command to modify
|
|
|
|
* @fd: fd to reassign to the child
|
|
|
|
*
|
|
|
|
* Get the parameters for the QEMU -add-fd command line option
|
|
|
|
* for the given file descriptor. The file descriptor must previously
|
|
|
|
* have been 'transferred' in a virCommandPassFD() call.
|
|
|
|
* This function for example returns "set=10,fd=20".
|
|
|
|
*/
|
|
|
|
static char *
|
|
|
|
qemuVirCommandGetFDSet(virCommandPtr cmd, int fd)
|
|
|
|
{
|
|
|
|
char *result = NULL;
|
|
|
|
int idx = virCommandPassFDGetFDIndex(cmd, fd);
|
|
|
|
|
|
|
|
if (idx >= 0) {
|
|
|
|
ignore_value(virAsprintf(&result, "set=%d,fd=%d", idx, fd));
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("file descriptor %d has not been transferred"), fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qemuVirCommandGetDevSet:
|
|
|
|
* @cmd: the command to modify
|
|
|
|
* @fd: fd to reassign to the child
|
|
|
|
*
|
|
|
|
* Get the parameters for the QEMU path= parameter where a file
|
|
|
|
* descriptor is accessed via a file descriptor set, for example
|
|
|
|
* /dev/fdset/10. The file descriptor must previously have been
|
|
|
|
* 'transferred' in a virCommandPassFD() call.
|
|
|
|
*/
|
|
|
|
static char *
|
|
|
|
qemuVirCommandGetDevSet(virCommandPtr cmd, int fd)
|
|
|
|
{
|
|
|
|
char *result = NULL;
|
|
|
|
int idx = virCommandPassFDGetFDIndex(cmd, fd);
|
|
|
|
|
|
|
|
if (idx >= 0) {
|
|
|
|
ignore_value(virAsprintf(&result, "/dev/fdset/%d", idx));
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("file descriptor %d has not been transferred"), fd);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-13 17:19:34 +00:00
|
|
|
static int
|
|
|
|
qemuBuildObjectCommandLinePropsInternal(const char *key,
|
|
|
|
const virJSONValue *value,
|
|
|
|
virBufferPtr buf,
|
|
|
|
bool nested)
|
|
|
|
{
|
|
|
|
virJSONValuePtr elem;
|
|
|
|
virBitmapPtr bitmap = NULL;
|
|
|
|
ssize_t pos = -1;
|
|
|
|
ssize_t end;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
switch ((virJSONType) value->type) {
|
|
|
|
case VIR_JSON_TYPE_STRING:
|
|
|
|
virBufferAsprintf(buf, ",%s=%s", key, value->data.string);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_JSON_TYPE_NUMBER:
|
|
|
|
virBufferAsprintf(buf, ",%s=%s", key, value->data.number);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_JSON_TYPE_BOOLEAN:
|
|
|
|
if (value->data.boolean)
|
|
|
|
virBufferAsprintf(buf, ",%s=yes", key);
|
|
|
|
else
|
|
|
|
virBufferAsprintf(buf, ",%s=no", key);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_JSON_TYPE_ARRAY:
|
|
|
|
if (nested) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("nested -object property arrays are not supported"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virJSONValueGetArrayAsBitmap(value, &bitmap) == 0) {
|
|
|
|
while ((pos = virBitmapNextSetBit(bitmap, pos)) > -1) {
|
|
|
|
if ((end = virBitmapNextClearBit(bitmap, pos)) < 0)
|
|
|
|
end = virBitmapLastSetBit(bitmap) + 1;
|
|
|
|
|
|
|
|
if (end - 1 > pos) {
|
|
|
|
virBufferAsprintf(buf, ",%s=%zd-%zd", key, pos, end - 1);
|
|
|
|
pos = end;
|
|
|
|
} else {
|
|
|
|
virBufferAsprintf(buf, ",%s=%zd", key, pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* fallback, treat the array as a non-bitmap, adding the key
|
|
|
|
* for each member */
|
|
|
|
for (i = 0; i < virJSONValueArraySize(value); i++) {
|
|
|
|
elem = virJSONValueArrayGet((virJSONValuePtr)value, i);
|
|
|
|
|
|
|
|
/* recurse to avoid duplicating code */
|
|
|
|
if (qemuBuildObjectCommandLinePropsInternal(key, elem, buf,
|
|
|
|
true) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_JSON_TYPE_OBJECT:
|
|
|
|
case VIR_JSON_TYPE_NULL:
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("NULL and OBJECT JSON types can't be converted to "
|
|
|
|
"commandline string"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBitmapFree(bitmap);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuBuildObjectCommandLineProps(const char *key,
|
|
|
|
const virJSONValue *value,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
return qemuBuildObjectCommandLinePropsInternal(key, value, opaque, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
qemuBuildObjectCommandlineFromJSON(const char *type,
|
|
|
|
const char *alias,
|
|
|
|
virJSONValuePtr props)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
char *ret = NULL;
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, "%s,id=%s", type, alias);
|
|
|
|
|
|
|
|
if (virJSONValueObjectForeachKeyValue(props,
|
|
|
|
qemuBuildObjectCommandLineProps,
|
|
|
|
&buf) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virBufferCheckError(&buf) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
char *qemuDeviceDriveHostAlias(virDomainDiskDefPtr disk,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
char *ret;
|
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
2013-07-04 10:14:12 +00:00
|
|
|
ignore_value(virAsprintf(&ret, "%s%s", QEMU_DRIVE_HOST_PREFIX,
|
|
|
|
disk->info.alias));
|
2010-12-16 15:07:07 +00:00
|
|
|
} else {
|
2013-05-20 09:23:13 +00:00
|
|
|
ignore_value(VIR_STRDUP(ret, disk->info.alias));
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuBuildDeviceAddressStr(virBufferPtr buf,
|
2016-02-18 13:33:39 +00:00
|
|
|
const virDomainDef *domainDef,
|
2011-02-01 16:22:01 +00:00
|
|
|
virDomainDeviceInfoPtr info,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
2013-08-02 17:48:50 +00:00
|
|
|
int ret = -1;
|
|
|
|
char *devStr = NULL;
|
2015-04-30 17:19:10 +00:00
|
|
|
const char *contAlias = NULL;
|
2013-08-02 17:48:50 +00:00
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
2013-08-02 17:48:50 +00:00
|
|
|
size_t i;
|
|
|
|
|
2014-05-13 16:10:40 +00:00
|
|
|
if (!(devStr = virDomainPCIAddressAsString(&info->addr.pci)))
|
2013-08-02 17:48:50 +00:00
|
|
|
goto cleanup;
|
|
|
|
for (i = 0; i < domainDef->ncontrollers; i++) {
|
|
|
|
virDomainControllerDefPtr cont = domainDef->controllers[i];
|
|
|
|
|
|
|
|
if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI &&
|
|
|
|
cont->idx == info->addr.pci.bus) {
|
|
|
|
contAlias = cont->info.alias;
|
|
|
|
if (!contAlias) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Device alias was not set for PCI "
|
|
|
|
"controller with index %u required "
|
|
|
|
"for device at address %s"),
|
|
|
|
info->addr.pci.bus, devStr);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!contAlias) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Could not find PCI "
|
|
|
|
"controller with index %u required "
|
|
|
|
"for device at address %s"),
|
|
|
|
info->addr.pci.bus, devStr);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-04-15 17:12:37 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_MULTIFUNCTION)) {
|
2011-05-23 06:42:21 +00:00
|
|
|
if (info->addr.pci.function != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Only PCI device addresses with function=0 "
|
|
|
|
"are supported with this QEMU binary"));
|
2013-08-02 17:48:50 +00:00
|
|
|
goto cleanup;
|
qemu: make PCI multifunction support more manual
When support for was added for PCI multifunction cards (in commit
9f8baf, first included in libvirt 0.9.3), it was done by always
turning on the multifunction bit for all PCI devices. Since that time
it has been realized that this is not an ideal solution, and that the
multifunction bit must be selectively turned on. For example, see
https://bugzilla.redhat.com/show_bug.cgi?id=728174
and the discussion before and after
https://www.redhat.com/archives/libvir-list/2011-September/msg01036.html
This patch modifies multifunction support so that the multifunction=on
option is only added to the qemu commandline for a device if its PCI
<address> definition has the attribute "multifunction='on'", e.g.:
<address type='pci' domain='0x0000' bus='0x00'
slot='0x04' function='0x0' multifunction='on'/>
In practice, the multifunction bit should only be turned on if
function='0' AND other functions will be used in the same slot - it
usually isn't needed for functions 1-7 (although there are apparently
some exceptions, e.g. the Intel X53 according to the QEMU source
code), and should never be set if only function 0 will be used in the
slot. The test cases have been changed accordingly to illustrate.
With this patch in place, if a user attempts to assign multiple
functions in a slot without setting the multifunction bit for function
0, libvirt will issue an error when the domain is defined, and the
define operation will fail. In the future, we may decide to detect
this situation and automatically add multifunction=on to avoid the
error; even then it will still be useful to have a manual method of
turning on multifunction since, as stated above, there are some
devices that excpect it to be turned on for all functions in a slot.
A side effect of this patch is that attempts to use the same PCI
address for two different devices will now log an error (previously
this would cause the domain define operation to fail, but there would
be no log message generated). Because the function doing this log was
almost completely rewritten, I didn't think it worthwhile to make a
separate patch for that fix (the entire patch would immediately be
obsoleted).
2011-09-29 17:00:32 +00:00
|
|
|
}
|
2014-06-27 15:18:53 +00:00
|
|
|
if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_ON) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("'multifunction=on' is not supported with "
|
|
|
|
"this QEMU binary"));
|
2013-08-02 17:48:50 +00:00
|
|
|
goto cleanup;
|
2011-05-23 06:42:21 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2015-04-30 17:19:10 +00:00
|
|
|
if (info->addr.pci.bus != 0 &&
|
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PCI_BRIDGE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Multiple PCI buses are not supported "
|
|
|
|
"with this QEMU binary"));
|
|
|
|
goto cleanup;
|
2013-04-19 10:38:53 +00:00
|
|
|
}
|
2015-04-30 17:19:10 +00:00
|
|
|
virBufferAsprintf(buf, ",bus=%s", contAlias);
|
|
|
|
|
2014-06-27 15:18:53 +00:00
|
|
|
if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_ON)
|
qemu: make PCI multifunction support more manual
When support for was added for PCI multifunction cards (in commit
9f8baf, first included in libvirt 0.9.3), it was done by always
turning on the multifunction bit for all PCI devices. Since that time
it has been realized that this is not an ideal solution, and that the
multifunction bit must be selectively turned on. For example, see
https://bugzilla.redhat.com/show_bug.cgi?id=728174
and the discussion before and after
https://www.redhat.com/archives/libvir-list/2011-September/msg01036.html
This patch modifies multifunction support so that the multifunction=on
option is only added to the qemu commandline for a device if its PCI
<address> definition has the attribute "multifunction='on'", e.g.:
<address type='pci' domain='0x0000' bus='0x00'
slot='0x04' function='0x0' multifunction='on'/>
In practice, the multifunction bit should only be turned on if
function='0' AND other functions will be used in the same slot - it
usually isn't needed for functions 1-7 (although there are apparently
some exceptions, e.g. the Intel X53 according to the QEMU source
code), and should never be set if only function 0 will be used in the
slot. The test cases have been changed accordingly to illustrate.
With this patch in place, if a user attempts to assign multiple
functions in a slot without setting the multifunction bit for function
0, libvirt will issue an error when the domain is defined, and the
define operation will fail. In the future, we may decide to detect
this situation and automatically add multifunction=on to avoid the
error; even then it will still be useful to have a manual method of
turning on multifunction since, as stated above, there are some
devices that excpect it to be turned on for all functions in a slot.
A side effect of this patch is that attempts to use the same PCI
address for two different devices will now log an error (previously
this would cause the domain define operation to fail, but there would
be no log message generated). Because the function doing this log was
almost completely rewritten, I didn't think it worthwhile to make a
separate patch for that fix (the entire patch would immediately be
obsoleted).
2011-09-29 17:00:32 +00:00
|
|
|
virBufferAddLit(buf, ",multifunction=on");
|
2014-06-27 15:18:53 +00:00
|
|
|
else if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_OFF)
|
qemu: make PCI multifunction support more manual
When support for was added for PCI multifunction cards (in commit
9f8baf, first included in libvirt 0.9.3), it was done by always
turning on the multifunction bit for all PCI devices. Since that time
it has been realized that this is not an ideal solution, and that the
multifunction bit must be selectively turned on. For example, see
https://bugzilla.redhat.com/show_bug.cgi?id=728174
and the discussion before and after
https://www.redhat.com/archives/libvir-list/2011-September/msg01036.html
This patch modifies multifunction support so that the multifunction=on
option is only added to the qemu commandline for a device if its PCI
<address> definition has the attribute "multifunction='on'", e.g.:
<address type='pci' domain='0x0000' bus='0x00'
slot='0x04' function='0x0' multifunction='on'/>
In practice, the multifunction bit should only be turned on if
function='0' AND other functions will be used in the same slot - it
usually isn't needed for functions 1-7 (although there are apparently
some exceptions, e.g. the Intel X53 according to the QEMU source
code), and should never be set if only function 0 will be used in the
slot. The test cases have been changed accordingly to illustrate.
With this patch in place, if a user attempts to assign multiple
functions in a slot without setting the multifunction bit for function
0, libvirt will issue an error when the domain is defined, and the
define operation will fail. In the future, we may decide to detect
this situation and automatically add multifunction=on to avoid the
error; even then it will still be useful to have a manual method of
turning on multifunction since, as stated above, there are some
devices that excpect it to be turned on for all functions in a slot.
A side effect of this patch is that attempts to use the same PCI
address for two different devices will now log an error (previously
this would cause the domain define operation to fail, but there would
be no log message generated). Because the function doing this log was
almost completely rewritten, I didn't think it worthwhile to make a
separate patch for that fix (the entire patch would immediately be
obsoleted).
2011-09-29 17:00:32 +00:00
|
|
|
virBufferAddLit(buf, ",multifunction=off");
|
|
|
|
virBufferAsprintf(buf, ",addr=0x%x", info->addr.pci.slot);
|
|
|
|
if (info->addr.pci.function != 0)
|
|
|
|
virBufferAsprintf(buf, ".0x%x", info->addr.pci.function);
|
2011-09-02 13:28:27 +00:00
|
|
|
} else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
|
2015-04-30 17:19:10 +00:00
|
|
|
if (!(contAlias = virDomainControllerAliasFind(domainDef,
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_USB,
|
|
|
|
info->addr.usb.bus)))
|
|
|
|
goto cleanup;
|
|
|
|
virBufferAsprintf(buf, ",bus=%s.0,port=%s", contAlias, info->addr.usb.port);
|
2011-12-12 23:39:31 +00:00
|
|
|
} else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO) {
|
|
|
|
if (info->addr.spaprvio.has_reg)
|
|
|
|
virBufferAsprintf(buf, ",reg=0x%llx", info->addr.spaprvio.reg);
|
2013-03-05 15:44:21 +00:00
|
|
|
} else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
|
|
|
|
if (info->addr.ccw.assigned)
|
|
|
|
virBufferAsprintf(buf, ",devno=%x.%x.%04x",
|
|
|
|
info->addr.ccw.cssid,
|
|
|
|
info->addr.ccw.ssid,
|
|
|
|
info->addr.ccw.devno);
|
2015-06-16 13:07:59 +00:00
|
|
|
} else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA) {
|
|
|
|
virBufferAsprintf(buf, ",iobase=0x%x,irq=0x%x",
|
|
|
|
info->addr.isa.iobase,
|
|
|
|
info->addr.isa.irq);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2011-09-02 13:28:27 +00:00
|
|
|
|
2013-08-02 17:48:50 +00:00
|
|
|
ret = 0;
|
2014-03-25 06:49:44 +00:00
|
|
|
cleanup:
|
2013-08-02 17:48:50 +00:00
|
|
|
VIR_FREE(devStr);
|
|
|
|
return ret;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2012-01-25 00:54:12 +00:00
|
|
|
static int
|
|
|
|
qemuBuildRomStr(virBufferPtr buf,
|
|
|
|
virDomainDeviceInfoPtr info,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2012-01-25 00:54:12 +00:00
|
|
|
{
|
2012-01-25 16:20:49 +00:00
|
|
|
if (info->rombar || info->romfile) {
|
2012-01-25 00:54:12 +00:00
|
|
|
if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("rombar and romfile are supported only for PCI devices"));
|
2012-01-25 00:54:12 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_ROMBAR)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("rombar and romfile not supported in this QEMU binary"));
|
2012-01-25 00:54:12 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (info->rombar) {
|
2014-06-27 15:18:53 +00:00
|
|
|
case VIR_TRISTATE_SWITCH_OFF:
|
2012-01-25 00:54:12 +00:00
|
|
|
virBufferAddLit(buf, ",rombar=0");
|
|
|
|
break;
|
2014-06-27 15:18:53 +00:00
|
|
|
case VIR_TRISTATE_SWITCH_ON:
|
2012-01-25 00:54:12 +00:00
|
|
|
virBufferAddLit(buf, ",rombar=1");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2012-01-25 16:20:49 +00:00
|
|
|
if (info->romfile)
|
|
|
|
virBufferAsprintf(buf, ",romfile=%s", info->romfile);
|
2012-01-25 00:54:12 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-06-20 08:26:47 +00:00
|
|
|
static int
|
|
|
|
qemuBuildIoEventFdStr(virBufferPtr buf,
|
2014-06-27 15:18:53 +00:00
|
|
|
virTristateSwitch use,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2011-06-20 08:26:47 +00:00
|
|
|
{
|
2013-02-01 13:48:58 +00:00
|
|
|
if (use && virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_IOEVENTFD))
|
2011-06-20 08:26:47 +00:00
|
|
|
virBufferAsprintf(buf, ",ioeventfd=%s",
|
2014-06-27 15:18:53 +00:00
|
|
|
virTristateSwitchTypeToString(use));
|
2011-06-20 08:26:47 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
#define QEMU_SERIAL_PARAM_ACCEPTED_CHARS \
|
2015-02-23 11:34:23 +00:00
|
|
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_ "
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
qemuSafeSerialParamValue(const char *value)
|
|
|
|
{
|
2012-10-17 09:23:12 +00:00
|
|
|
if (strspn(value, QEMU_SERIAL_PARAM_ACCEPTED_CHARS) != strlen(value)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("driver serial '%s' contains unsafe characters"),
|
|
|
|
value);
|
2010-12-16 15:07:07 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-17 13:44:42 +00:00
|
|
|
static char *
|
|
|
|
qemuGetSecretString(virConnectPtr conn,
|
|
|
|
const char *scheme,
|
|
|
|
bool encoded,
|
2014-06-24 13:46:23 +00:00
|
|
|
virStorageAuthDefPtr authdef,
|
2013-07-17 13:44:42 +00:00
|
|
|
virSecretUsageType secretUsageType)
|
|
|
|
{
|
|
|
|
size_t secret_size;
|
|
|
|
virSecretPtr sec = NULL;
|
|
|
|
char *secret = NULL;
|
2013-10-15 08:29:18 +00:00
|
|
|
char uuidStr[VIR_UUID_STRING_BUFLEN];
|
2013-07-17 13:44:42 +00:00
|
|
|
|
|
|
|
/* look up secret */
|
2014-06-24 13:46:23 +00:00
|
|
|
switch (authdef->secretType) {
|
2014-03-28 14:45:50 +00:00
|
|
|
case VIR_STORAGE_SECRET_TYPE_UUID:
|
2014-06-24 13:46:23 +00:00
|
|
|
sec = virSecretLookupByUUID(conn, authdef->secret.uuid);
|
|
|
|
virUUIDFormat(authdef->secret.uuid, uuidStr);
|
2013-07-17 13:44:42 +00:00
|
|
|
break;
|
2014-03-28 14:45:50 +00:00
|
|
|
case VIR_STORAGE_SECRET_TYPE_USAGE:
|
2014-06-24 13:46:23 +00:00
|
|
|
sec = virSecretLookupByUsage(conn, secretUsageType,
|
|
|
|
authdef->secret.usage);
|
2013-07-17 13:44:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sec) {
|
2014-06-24 13:46:23 +00:00
|
|
|
if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
|
2013-08-06 11:52:46 +00:00
|
|
|
virReportError(VIR_ERR_NO_SECRET,
|
|
|
|
_("%s no secret matches uuid '%s'"),
|
2013-10-15 08:29:18 +00:00
|
|
|
scheme, uuidStr);
|
2013-08-06 11:52:46 +00:00
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_NO_SECRET,
|
|
|
|
_("%s no secret matches usage value '%s'"),
|
2014-06-24 13:46:23 +00:00
|
|
|
scheme, authdef->secret.usage);
|
2013-08-06 11:52:46 +00:00
|
|
|
}
|
2013-07-17 13:44:42 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
secret = (char *)conn->secretDriver->secretGetValue(sec, &secret_size, 0,
|
|
|
|
VIR_SECRET_GET_VALUE_INTERNAL_CALL);
|
|
|
|
if (!secret) {
|
2014-06-24 13:46:23 +00:00
|
|
|
if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
|
2013-08-06 11:52:46 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("could not get value of the secret for "
|
|
|
|
"username '%s' using uuid '%s'"),
|
2014-06-24 13:46:23 +00:00
|
|
|
authdef->username, uuidStr);
|
2013-08-06 11:52:46 +00:00
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("could not get value of the secret for "
|
|
|
|
"username '%s' using usage value '%s'"),
|
2014-06-24 13:46:23 +00:00
|
|
|
authdef->username, authdef->secret.usage);
|
2013-08-06 11:52:46 +00:00
|
|
|
}
|
2013-07-17 13:44:42 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (encoded) {
|
|
|
|
char *base64 = NULL;
|
|
|
|
|
|
|
|
base64_encode_alloc(secret, secret_size, &base64);
|
|
|
|
VIR_FREE(secret);
|
|
|
|
if (!base64) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
secret = base64;
|
|
|
|
}
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
cleanup:
|
2013-07-17 13:44:42 +00:00
|
|
|
virObjectUnref(sec);
|
|
|
|
return secret;
|
|
|
|
}
|
2012-03-09 19:13:30 +00:00
|
|
|
|
2011-11-01 01:29:07 +00:00
|
|
|
|
2013-11-18 16:12:59 +00:00
|
|
|
static int
|
|
|
|
qemuNetworkDriveGetPort(int protocol,
|
|
|
|
const char *port)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (port) {
|
2015-02-19 15:53:13 +00:00
|
|
|
if (virStrToLong_i(port, NULL, 10, &ret) < 0 || ret < 0) {
|
2013-11-18 16:12:59 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("failed to parse port number '%s'"),
|
|
|
|
port);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-27 00:15:22 +00:00
|
|
|
switch ((virStorageNetProtocol) protocol) {
|
2014-03-27 22:47:39 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_HTTP:
|
2013-11-18 16:12:59 +00:00
|
|
|
return 80;
|
|
|
|
|
2014-03-27 22:47:39 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_HTTPS:
|
2013-11-18 16:12:59 +00:00
|
|
|
return 443;
|
|
|
|
|
2014-03-27 22:47:39 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_FTP:
|
2013-11-18 16:12:59 +00:00
|
|
|
return 21;
|
|
|
|
|
2014-03-27 22:47:39 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_FTPS:
|
2013-11-18 16:12:59 +00:00
|
|
|
return 990;
|
|
|
|
|
2014-03-27 22:47:39 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_TFTP:
|
2013-11-18 16:12:59 +00:00
|
|
|
return 69;
|
|
|
|
|
2014-03-27 22:47:39 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
|
2013-11-18 16:12:59 +00:00
|
|
|
return 7000;
|
|
|
|
|
2014-03-27 22:47:39 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_NBD:
|
2013-11-18 16:12:59 +00:00
|
|
|
return 10809;
|
|
|
|
|
2014-03-27 22:47:39 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_ISCSI:
|
|
|
|
case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
|
2013-11-18 16:12:59 +00:00
|
|
|
/* no default port specified */
|
|
|
|
return 0;
|
|
|
|
|
2014-03-27 22:47:39 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_RBD:
|
|
|
|
case VIR_STORAGE_NET_PROTOCOL_LAST:
|
2014-04-24 14:11:44 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_NONE:
|
|
|
|
/* not applicable */
|
2013-11-18 16:12:59 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-11-18 17:02:30 +00:00
|
|
|
#define QEMU_DEFAULT_NBD_PORT "10809"
|
2013-11-18 16:12:59 +00:00
|
|
|
|
2014-04-08 15:12:04 +00:00
|
|
|
static char *
|
2014-11-10 16:55:26 +00:00
|
|
|
qemuBuildNetworkDriveURI(virStorageSourcePtr src,
|
2013-11-15 15:29:35 +00:00
|
|
|
const char *username,
|
|
|
|
const char *secret)
|
|
|
|
{
|
|
|
|
char *ret = NULL;
|
2013-11-18 17:02:30 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2013-11-15 15:29:35 +00:00
|
|
|
virURIPtr uri = NULL;
|
2013-11-18 19:03:12 +00:00
|
|
|
size_t i;
|
2012-11-22 18:10:39 +00:00
|
|
|
|
2014-11-10 16:55:26 +00:00
|
|
|
switch ((virStorageNetProtocol) src->protocol) {
|
2014-03-27 22:47:39 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_NBD:
|
2014-11-10 16:55:26 +00:00
|
|
|
if (src->nhosts != 1) {
|
2013-11-18 17:02:30 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("protocol '%s' accepts only one host"),
|
2014-11-10 16:55:26 +00:00
|
|
|
virStorageNetProtocolTypeToString(src->protocol));
|
2013-11-18 17:02:30 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-11-10 16:55:26 +00:00
|
|
|
if (!((src->hosts->name && strchr(src->hosts->name, ':')) ||
|
|
|
|
(src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_TCP &&
|
|
|
|
!src->hosts->name) ||
|
|
|
|
(src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_UNIX &&
|
|
|
|
src->hosts->socket &&
|
|
|
|
src->hosts->socket[0] != '/'))) {
|
2013-11-18 17:02:30 +00:00
|
|
|
|
|
|
|
virBufferAddLit(&buf, "nbd:");
|
|
|
|
|
2014-11-10 16:55:26 +00:00
|
|
|
switch (src->hosts->transport) {
|
conf: split network host structs to util/
Continuing the refactoring of host-side storage descriptions out
of conf/domain_conf and into util/virstoragefile, this patch
focuses on details about a host name/port/transport as used by
a network storage volume.
* src/conf/domain_conf.h (virDomainDiskProtocolTransport)
(virDomainDiskHostDef, virDomainDiskHostDefClear)
(virDomainDiskHostDefFree, virDomainDiskHostDefCopy): Move...
* src/util/virstoragefile.h (virStorageNetHostTransport)
(virStorageNetHostDef, virStorageNetHostDefClear)
(virStorageNetHostDefFree, virStorageNetHostDefCopy): ...here,
with better names.
* src/util/virstoragefile.c (virStorageNetHostDefClear)
(virStorageNetHostDefFree, virStorageNetHostDefCopy): Moved from...
* src/conf/domain_conf.c (virDomainDiskHostDefClear)
(virDomainDiskHostDefFree, virDomainDiskHostDefCopy): ...here.
(virDomainDiskSourceDefClear, virDomainDiskSourceDefParse)
(virDomainDiskSourceDefFormatInternal): Adjust callers.
* src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise.
* src/conf/snapshot_conf.c (virDomainSnapshotDiskDefClear):
Likewise.
* src/qemu/qemu_command.c (qemuAddRBDHost)
(qemuParseDriveURIString, qemuParseNBDString)
(qemuBuildNetworkDriveURI, qemuParseCommandLineDisk)
(qemuParseCommandLine, qemuGetDriveSourceString): Likewise.
* src/qemu/qemu_command.h: Likewise.
* src/qemu/qemu_conf.c (qemuAddISCSIPoolSourceHost)
(qemuTranslateDiskSourcePool): Likewise.
* src/qemu/qemu_driver.c
(qemuDomainSnapshotCreateSingleDiskActive)
(qemuDomainSnapshotUndoSingleDiskActive): Likewise.
* src/storage/storage_backend_gluster.c
(virStorageFileBackendGlusterInit): Likewise.
* src/storage/storage_driver.c (virStorageFileFree)
(virStorageFileInitInternal): Likewise.
* src/storage/storage_driver.h (_virStorageFile): Likewise.
* src/libvirt_private.syms (domain_conf.h): Move symbols...
(virstoragefile.h): ...as appropriate.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-26 22:33:08 +00:00
|
|
|
case VIR_STORAGE_NET_HOST_TRANS_TCP:
|
2014-11-10 16:55:26 +00:00
|
|
|
virBufferStrcat(&buf, src->hosts->name, NULL);
|
2013-11-18 17:02:30 +00:00
|
|
|
virBufferAsprintf(&buf, ":%s",
|
2014-11-10 16:55:26 +00:00
|
|
|
src->hosts->port ? src->hosts->port :
|
2013-11-18 17:02:30 +00:00
|
|
|
QEMU_DEFAULT_NBD_PORT);
|
|
|
|
break;
|
|
|
|
|
conf: split network host structs to util/
Continuing the refactoring of host-side storage descriptions out
of conf/domain_conf and into util/virstoragefile, this patch
focuses on details about a host name/port/transport as used by
a network storage volume.
* src/conf/domain_conf.h (virDomainDiskProtocolTransport)
(virDomainDiskHostDef, virDomainDiskHostDefClear)
(virDomainDiskHostDefFree, virDomainDiskHostDefCopy): Move...
* src/util/virstoragefile.h (virStorageNetHostTransport)
(virStorageNetHostDef, virStorageNetHostDefClear)
(virStorageNetHostDefFree, virStorageNetHostDefCopy): ...here,
with better names.
* src/util/virstoragefile.c (virStorageNetHostDefClear)
(virStorageNetHostDefFree, virStorageNetHostDefCopy): Moved from...
* src/conf/domain_conf.c (virDomainDiskHostDefClear)
(virDomainDiskHostDefFree, virDomainDiskHostDefCopy): ...here.
(virDomainDiskSourceDefClear, virDomainDiskSourceDefParse)
(virDomainDiskSourceDefFormatInternal): Adjust callers.
* src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise.
* src/conf/snapshot_conf.c (virDomainSnapshotDiskDefClear):
Likewise.
* src/qemu/qemu_command.c (qemuAddRBDHost)
(qemuParseDriveURIString, qemuParseNBDString)
(qemuBuildNetworkDriveURI, qemuParseCommandLineDisk)
(qemuParseCommandLine, qemuGetDriveSourceString): Likewise.
* src/qemu/qemu_command.h: Likewise.
* src/qemu/qemu_conf.c (qemuAddISCSIPoolSourceHost)
(qemuTranslateDiskSourcePool): Likewise.
* src/qemu/qemu_driver.c
(qemuDomainSnapshotCreateSingleDiskActive)
(qemuDomainSnapshotUndoSingleDiskActive): Likewise.
* src/storage/storage_backend_gluster.c
(virStorageFileBackendGlusterInit): Likewise.
* src/storage/storage_driver.c (virStorageFileFree)
(virStorageFileInitInternal): Likewise.
* src/storage/storage_driver.h (_virStorageFile): Likewise.
* src/libvirt_private.syms (domain_conf.h): Move symbols...
(virstoragefile.h): ...as appropriate.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-26 22:33:08 +00:00
|
|
|
case VIR_STORAGE_NET_HOST_TRANS_UNIX:
|
2014-11-10 16:55:26 +00:00
|
|
|
if (!src->hosts->socket) {
|
2013-11-18 17:02:30 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("socket attribute required for "
|
|
|
|
"unix transport"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-11-10 16:55:26 +00:00
|
|
|
virBufferAsprintf(&buf, "unix:%s", src->hosts->socket);
|
2013-11-18 17:02:30 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("nbd does not support transport '%s'"),
|
2014-11-10 16:55:26 +00:00
|
|
|
virStorageNetHostTransportTypeToString(src->hosts->transport));
|
2013-11-18 17:02:30 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-11-10 16:55:26 +00:00
|
|
|
if (src->path)
|
|
|
|
virBufferAsprintf(&buf, ":exportname=%s", src->path);
|
2013-11-18 17:02:30 +00:00
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2013-11-18 17:02:30 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = virBufferContentAndReset(&buf);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
/* fallthrough */
|
|
|
|
/* NBD code uses same formatting scheme as others in some cases */
|
|
|
|
|
2014-03-27 22:47:39 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_HTTP:
|
|
|
|
case VIR_STORAGE_NET_PROTOCOL_HTTPS:
|
|
|
|
case VIR_STORAGE_NET_PROTOCOL_FTP:
|
|
|
|
case VIR_STORAGE_NET_PROTOCOL_FTPS:
|
|
|
|
case VIR_STORAGE_NET_PROTOCOL_TFTP:
|
|
|
|
case VIR_STORAGE_NET_PROTOCOL_ISCSI:
|
|
|
|
case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
|
2014-11-10 16:55:26 +00:00
|
|
|
if (src->nhosts != 1) {
|
2013-11-18 16:12:59 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("protocol '%s' accepts only one host"),
|
2014-11-10 16:55:26 +00:00
|
|
|
virStorageNetProtocolTypeToString(src->protocol));
|
2013-11-18 16:12:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-11-22 18:10:39 +00:00
|
|
|
|
2013-11-18 16:12:59 +00:00
|
|
|
if (VIR_ALLOC(uri) < 0)
|
|
|
|
goto cleanup;
|
2012-11-22 18:10:39 +00:00
|
|
|
|
2014-11-10 16:55:26 +00:00
|
|
|
if (src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_TCP) {
|
2013-11-18 16:12:59 +00:00
|
|
|
if (VIR_STRDUP(uri->scheme,
|
2014-11-10 16:55:26 +00:00
|
|
|
virStorageNetProtocolTypeToString(src->protocol)) < 0)
|
2013-11-18 16:12:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
if (virAsprintf(&uri->scheme, "%s+%s",
|
2014-11-10 16:55:26 +00:00
|
|
|
virStorageNetProtocolTypeToString(src->protocol),
|
|
|
|
virStorageNetHostTransportTypeToString(src->hosts->transport)) < 0)
|
2013-11-18 16:12:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-11-22 18:10:39 +00:00
|
|
|
|
2014-11-10 16:55:26 +00:00
|
|
|
if ((uri->port = qemuNetworkDriveGetPort(src->protocol, src->hosts->port)) < 0)
|
2013-11-18 16:12:59 +00:00
|
|
|
goto cleanup;
|
2012-11-22 18:10:39 +00:00
|
|
|
|
2014-11-10 16:55:26 +00:00
|
|
|
if (src->path) {
|
|
|
|
if (src->volume) {
|
2014-05-02 14:17:42 +00:00
|
|
|
if (virAsprintf(&uri->path, "/%s%s",
|
2014-11-10 16:55:26 +00:00
|
|
|
src->volume, src->path) < 0)
|
2014-05-02 14:17:42 +00:00
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
if (virAsprintf(&uri->path, "%s%s",
|
2014-11-10 16:55:26 +00:00
|
|
|
src->path[0] == '/' ? "" : "/",
|
|
|
|
src->path) < 0)
|
2014-05-02 14:17:42 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
2012-11-22 18:10:39 +00:00
|
|
|
|
2014-11-10 16:55:26 +00:00
|
|
|
if (src->hosts->socket &&
|
|
|
|
virAsprintf(&uri->query, "socket=%s", src->hosts->socket) < 0)
|
2013-11-15 15:29:35 +00:00
|
|
|
goto cleanup;
|
2013-11-18 16:12:59 +00:00
|
|
|
|
|
|
|
if (username) {
|
|
|
|
if (secret) {
|
|
|
|
if (virAsprintf(&uri->user, "%s:%s", username, secret) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
if (VIR_STRDUP(uri->user, username) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-10 16:55:26 +00:00
|
|
|
if (VIR_STRDUP(uri->server, src->hosts->name) < 0)
|
2013-11-15 15:29:35 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-11-18 16:12:59 +00:00
|
|
|
ret = virURIFormat(uri);
|
2013-11-15 15:29:35 +00:00
|
|
|
|
2013-11-18 16:12:59 +00:00
|
|
|
break;
|
|
|
|
|
2014-03-27 22:47:39 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
|
2014-11-10 16:55:26 +00:00
|
|
|
if (!src->path) {
|
2013-11-18 16:34:49 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("missing disk source for 'sheepdog' protocol"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-11-10 16:55:26 +00:00
|
|
|
if (src->nhosts == 0) {
|
|
|
|
if (virAsprintf(&ret, "sheepdog:%s", src->path) < 0)
|
2013-11-18 16:34:49 +00:00
|
|
|
goto cleanup;
|
2014-11-10 16:55:26 +00:00
|
|
|
} else if (src->nhosts == 1) {
|
2013-11-18 16:34:49 +00:00
|
|
|
if (virAsprintf(&ret, "sheepdog:%s:%s:%s",
|
2014-11-10 16:55:26 +00:00
|
|
|
src->hosts->name,
|
|
|
|
src->hosts->port ? src->hosts->port : "7000",
|
|
|
|
src->path) < 0)
|
2013-11-18 16:34:49 +00:00
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("protocol 'sheepdog' accepts up to one host"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2014-03-27 22:47:39 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_RBD:
|
2014-11-10 16:55:26 +00:00
|
|
|
if (strchr(src->path, ':')) {
|
2013-11-18 19:03:12 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("':' not allowed in RBD source volume name '%s'"),
|
2014-11-10 16:55:26 +00:00
|
|
|
src->path);
|
2013-11-18 19:03:12 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-11-10 16:55:26 +00:00
|
|
|
virBufferStrcat(&buf, "rbd:", src->path, NULL);
|
2013-11-18 19:03:12 +00:00
|
|
|
|
2014-11-11 10:35:25 +00:00
|
|
|
if (src->snapshot)
|
|
|
|
virBufferEscape(&buf, '\\', ":", "@%s", src->snapshot);
|
|
|
|
|
2013-11-18 19:03:12 +00:00
|
|
|
if (username) {
|
|
|
|
virBufferEscape(&buf, '\\', ":", ":id=%s", username);
|
|
|
|
virBufferEscape(&buf, '\\', ":",
|
|
|
|
":key=%s:auth_supported=cephx\\;none",
|
|
|
|
secret);
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(&buf, ":auth_supported=none");
|
|
|
|
}
|
|
|
|
|
2014-11-10 16:55:26 +00:00
|
|
|
if (src->nhosts > 0) {
|
2013-11-18 19:03:12 +00:00
|
|
|
virBufferAddLit(&buf, ":mon_host=");
|
2014-11-10 16:55:26 +00:00
|
|
|
for (i = 0; i < src->nhosts; i++) {
|
2013-11-18 19:03:12 +00:00
|
|
|
if (i)
|
|
|
|
virBufferAddLit(&buf, "\\;");
|
|
|
|
|
|
|
|
/* assume host containing : is ipv6 */
|
2014-11-10 16:55:26 +00:00
|
|
|
if (strchr(src->hosts[i].name, ':'))
|
|
|
|
virBufferEscape(&buf, '\\', ":", "[%s]",
|
|
|
|
src->hosts[i].name);
|
2013-11-18 19:03:12 +00:00
|
|
|
else
|
2014-11-10 16:55:26 +00:00
|
|
|
virBufferAsprintf(&buf, "%s", src->hosts[i].name);
|
2013-11-18 19:03:12 +00:00
|
|
|
|
2014-11-10 16:55:26 +00:00
|
|
|
if (src->hosts[i].port)
|
|
|
|
virBufferAsprintf(&buf, "\\:%s", src->hosts[i].port);
|
2013-11-18 19:03:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-11 16:31:24 +00:00
|
|
|
if (src->configFile)
|
|
|
|
virBufferEscape(&buf, '\\', ":", ":conf=%s", src->configFile);
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2013-11-18 19:03:12 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = virBufferContentAndReset(&buf);
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
2014-03-27 22:47:39 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_LAST:
|
2014-04-24 14:11:44 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_NONE:
|
2015-03-24 15:13:41 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unexpected network protocol '%s'"),
|
|
|
|
virStorageNetProtocolTypeToString(src->protocol));
|
2013-11-18 16:12:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-11-15 15:29:35 +00:00
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
cleanup:
|
2013-11-18 17:02:30 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
2013-11-15 15:29:35 +00:00
|
|
|
virURIFree(uri);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-25 17:56:24 +00:00
|
|
|
int
|
2014-04-08 15:50:50 +00:00
|
|
|
qemuGetDriveSourceString(virStorageSourcePtr src,
|
|
|
|
virConnectPtr conn,
|
|
|
|
char **source)
|
2013-11-21 17:43:59 +00:00
|
|
|
{
|
2014-04-08 15:50:50 +00:00
|
|
|
int actualType = virStorageSourceGetActualType(src);
|
|
|
|
char *secret = NULL;
|
|
|
|
char *username = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
*source = NULL;
|
|
|
|
|
2015-03-24 15:16:29 +00:00
|
|
|
/* return 1 for empty sources */
|
|
|
|
if (virStorageSourceIsEmpty(src))
|
|
|
|
return 1;
|
|
|
|
|
2014-04-08 15:50:50 +00:00
|
|
|
if (conn) {
|
|
|
|
if (actualType == VIR_STORAGE_TYPE_NETWORK &&
|
2014-06-24 13:46:23 +00:00
|
|
|
src->auth &&
|
2014-04-08 15:50:50 +00:00
|
|
|
(src->protocol == VIR_STORAGE_NET_PROTOCOL_ISCSI ||
|
|
|
|
src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD)) {
|
|
|
|
bool encode = false;
|
|
|
|
int secretType = VIR_SECRET_USAGE_TYPE_ISCSI;
|
|
|
|
const char *protocol = virStorageNetProtocolTypeToString(src->protocol);
|
2014-06-24 13:46:23 +00:00
|
|
|
username = src->auth->username;
|
2014-04-08 15:50:50 +00:00
|
|
|
|
|
|
|
if (src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD) {
|
|
|
|
/* qemu requires the secret to be encoded for RBD */
|
|
|
|
encode = true;
|
|
|
|
secretType = VIR_SECRET_USAGE_TYPE_CEPH;
|
|
|
|
}
|
2013-11-21 17:43:59 +00:00
|
|
|
|
2014-04-08 15:50:50 +00:00
|
|
|
if (!(secret = qemuGetSecretString(conn,
|
|
|
|
protocol,
|
|
|
|
encode,
|
2014-06-24 13:46:23 +00:00
|
|
|
src->auth,
|
2014-04-08 15:50:50 +00:00
|
|
|
secretType)))
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-27 00:15:22 +00:00
|
|
|
switch ((virStorageType) actualType) {
|
conf: move host disk type to util/
A continuation of the migration of disk details to virstoragefile.
This patch moves a single enum, but converting the name has quite
a bit of fallout.
* src/conf/domain_conf.h (virDomainDiskType): Move...
* src/util/virstoragefile.h (virStorageType): ...and rename.
* src/bhyve/bhyve_command.c (bhyveBuildDiskArgStr)
(virBhyveProcessBuildLoadCmd): Update clients.
* src/conf/domain_conf.c (virDomainDiskSourceDefParse)
(virDomainDiskDefParseXML, virDomainDiskSourceDefFormatInternal)
(virDomainDiskDefFormat, virDomainDiskGetActualType)
(virDomainDiskDefForeachPath, virDomainDiskSourceIsBlockType):
Likewise.
* src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise.
* src/conf/snapshot_conf.c (virDomainSnapshotDiskDefParseXML)
(virDomainSnapshotAlignDisks, virDomainSnapshotDiskDefFormat):
Likewise.
* src/esx/esx_driver.c (esxAutodetectSCSIControllerModel)
(esxDomainDefineXML): Likewise.
* src/locking/domain_lock.c (virDomainLockManagerAddDisk):
Likewise.
* src/lxc/lxc_controller.c
(virLXCControllerSetupLoopDeviceDisk)
(virLXCControllerSetupNBDDeviceDisk)
(virLXCControllerSetupLoopDevices, virLXCControllerSetupDisk):
Likewise.
* src/parallels/parallels_driver.c (parallelsGetHddInfo):
Likewise.
* src/phyp/phyp_driver.c (phypDiskType): Likewise.
* src/qemu/qemu_command.c (qemuGetDriveSourceString)
(qemuDomainDiskGetSourceString, qemuBuildDriveStr)
(qemuBuildCommandLine, qemuParseCommandLineDisk)
(qemuParseCommandLine): Likewise.
* src/qemu/qemu_conf.c (qemuCheckSharedDevice)
(qemuTranslateDiskSourcePool)
(qemuTranslateSnapshotDiskSourcePool): Likewise.
* src/qemu/qemu_domain.c (qemuDomainDeviceDefPostParse)
(qemuDomainDetermineDiskChain): Likewise.
* src/qemu/qemu_driver.c (qemuDomainGetBlockInfo)
(qemuDomainSnapshotPrepareDiskExternalBackingInactive)
(qemuDomainSnapshotPrepareDiskExternalBackingActive)
(qemuDomainSnapshotPrepareDiskExternalOverlayActive)
(qemuDomainSnapshotPrepareDiskExternalOverlayInactive)
(qemuDomainSnapshotPrepareDiskInternal)
(qemuDomainSnapshotPrepare)
(qemuDomainSnapshotCreateSingleDiskActive): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainChangeEjectableMedia):
Likewise.
* src/qemu/qemu_migration.c (qemuMigrationIsSafe): Likewise.
* src/security/security_apparmor.c
(AppArmorRestoreSecurityImageLabel)
(AppArmorSetSecurityImageLabel): Likewise.
* src/security/security_dac.c (virSecurityDACSetSecurityImageLabel)
(virSecurityDACRestoreSecurityImageLabelInt)
(virSecurityDACSetSecurityAllLabel): Likewise.
* src/security/security_selinux.c
(virSecuritySELinuxRestoreSecurityImageLabelInt)
(virSecuritySELinuxSetSecurityImageLabel)
(virSecuritySELinuxSetSecurityAllLabel): Likewise.
* src/storage/storage_backend.c (virStorageFileBackendForType):
Likewise.
* src/storage/storage_backend_fs.c (virStorageFileBackendFile)
(virStorageFileBackendBlock): Likewise.
* src/storage/storage_backend_gluster.c
(virStorageFileBackendGluster): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainGetXMLDesc, vboxAttachDrives)
(vboxDomainAttachDeviceImpl, vboxDomainDetachDevice): Likewise.
* src/vmware/vmware_conf.c (vmwareVmxPath): Likewise.
* src/vmx/vmx.c (virVMXParseDisk, virVMXFormatDisk)
(virVMXFormatFloppy): Likewise.
* src/xenxs/xen_sxpr.c (xenParseSxprDisks, xenParseSxpr)
(xenFormatSxprDisk): Likewise.
* src/xenxs/xen_xm.c (xenParseXM, xenFormatXMDisk): Likewise.
* tests/securityselinuxlabeltest.c (testSELinuxLoadDef):
Likewise.
* src/libvirt_private.syms (domain_conf.h): Move symbols...
(virstoragefile.h): ...as appropriate.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-27 21:57:49 +00:00
|
|
|
case VIR_STORAGE_TYPE_BLOCK:
|
|
|
|
case VIR_STORAGE_TYPE_FILE:
|
|
|
|
case VIR_STORAGE_TYPE_DIR:
|
2014-04-08 15:50:50 +00:00
|
|
|
if (VIR_STRDUP(*source, src->path) < 0)
|
|
|
|
goto cleanup;
|
2013-11-21 17:43:59 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
conf: move host disk type to util/
A continuation of the migration of disk details to virstoragefile.
This patch moves a single enum, but converting the name has quite
a bit of fallout.
* src/conf/domain_conf.h (virDomainDiskType): Move...
* src/util/virstoragefile.h (virStorageType): ...and rename.
* src/bhyve/bhyve_command.c (bhyveBuildDiskArgStr)
(virBhyveProcessBuildLoadCmd): Update clients.
* src/conf/domain_conf.c (virDomainDiskSourceDefParse)
(virDomainDiskDefParseXML, virDomainDiskSourceDefFormatInternal)
(virDomainDiskDefFormat, virDomainDiskGetActualType)
(virDomainDiskDefForeachPath, virDomainDiskSourceIsBlockType):
Likewise.
* src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise.
* src/conf/snapshot_conf.c (virDomainSnapshotDiskDefParseXML)
(virDomainSnapshotAlignDisks, virDomainSnapshotDiskDefFormat):
Likewise.
* src/esx/esx_driver.c (esxAutodetectSCSIControllerModel)
(esxDomainDefineXML): Likewise.
* src/locking/domain_lock.c (virDomainLockManagerAddDisk):
Likewise.
* src/lxc/lxc_controller.c
(virLXCControllerSetupLoopDeviceDisk)
(virLXCControllerSetupNBDDeviceDisk)
(virLXCControllerSetupLoopDevices, virLXCControllerSetupDisk):
Likewise.
* src/parallels/parallels_driver.c (parallelsGetHddInfo):
Likewise.
* src/phyp/phyp_driver.c (phypDiskType): Likewise.
* src/qemu/qemu_command.c (qemuGetDriveSourceString)
(qemuDomainDiskGetSourceString, qemuBuildDriveStr)
(qemuBuildCommandLine, qemuParseCommandLineDisk)
(qemuParseCommandLine): Likewise.
* src/qemu/qemu_conf.c (qemuCheckSharedDevice)
(qemuTranslateDiskSourcePool)
(qemuTranslateSnapshotDiskSourcePool): Likewise.
* src/qemu/qemu_domain.c (qemuDomainDeviceDefPostParse)
(qemuDomainDetermineDiskChain): Likewise.
* src/qemu/qemu_driver.c (qemuDomainGetBlockInfo)
(qemuDomainSnapshotPrepareDiskExternalBackingInactive)
(qemuDomainSnapshotPrepareDiskExternalBackingActive)
(qemuDomainSnapshotPrepareDiskExternalOverlayActive)
(qemuDomainSnapshotPrepareDiskExternalOverlayInactive)
(qemuDomainSnapshotPrepareDiskInternal)
(qemuDomainSnapshotPrepare)
(qemuDomainSnapshotCreateSingleDiskActive): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainChangeEjectableMedia):
Likewise.
* src/qemu/qemu_migration.c (qemuMigrationIsSafe): Likewise.
* src/security/security_apparmor.c
(AppArmorRestoreSecurityImageLabel)
(AppArmorSetSecurityImageLabel): Likewise.
* src/security/security_dac.c (virSecurityDACSetSecurityImageLabel)
(virSecurityDACRestoreSecurityImageLabelInt)
(virSecurityDACSetSecurityAllLabel): Likewise.
* src/security/security_selinux.c
(virSecuritySELinuxRestoreSecurityImageLabelInt)
(virSecuritySELinuxSetSecurityImageLabel)
(virSecuritySELinuxSetSecurityAllLabel): Likewise.
* src/storage/storage_backend.c (virStorageFileBackendForType):
Likewise.
* src/storage/storage_backend_fs.c (virStorageFileBackendFile)
(virStorageFileBackendBlock): Likewise.
* src/storage/storage_backend_gluster.c
(virStorageFileBackendGluster): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainGetXMLDesc, vboxAttachDrives)
(vboxDomainAttachDeviceImpl, vboxDomainDetachDevice): Likewise.
* src/vmware/vmware_conf.c (vmwareVmxPath): Likewise.
* src/vmx/vmx.c (virVMXParseDisk, virVMXFormatDisk)
(virVMXFormatFloppy): Likewise.
* src/xenxs/xen_sxpr.c (xenParseSxprDisks, xenParseSxpr)
(xenFormatSxprDisk): Likewise.
* src/xenxs/xen_xm.c (xenParseXM, xenFormatXMDisk): Likewise.
* tests/securityselinuxlabeltest.c (testSELinuxLoadDef):
Likewise.
* src/libvirt_private.syms (domain_conf.h): Move symbols...
(virstoragefile.h): ...as appropriate.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-27 21:57:49 +00:00
|
|
|
case VIR_STORAGE_TYPE_NETWORK:
|
2014-11-10 16:55:26 +00:00
|
|
|
if (!(*source = qemuBuildNetworkDriveURI(src, username, secret)))
|
2014-04-08 15:50:50 +00:00
|
|
|
goto cleanup;
|
2013-11-21 17:43:59 +00:00
|
|
|
break;
|
|
|
|
|
conf: move host disk type to util/
A continuation of the migration of disk details to virstoragefile.
This patch moves a single enum, but converting the name has quite
a bit of fallout.
* src/conf/domain_conf.h (virDomainDiskType): Move...
* src/util/virstoragefile.h (virStorageType): ...and rename.
* src/bhyve/bhyve_command.c (bhyveBuildDiskArgStr)
(virBhyveProcessBuildLoadCmd): Update clients.
* src/conf/domain_conf.c (virDomainDiskSourceDefParse)
(virDomainDiskDefParseXML, virDomainDiskSourceDefFormatInternal)
(virDomainDiskDefFormat, virDomainDiskGetActualType)
(virDomainDiskDefForeachPath, virDomainDiskSourceIsBlockType):
Likewise.
* src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise.
* src/conf/snapshot_conf.c (virDomainSnapshotDiskDefParseXML)
(virDomainSnapshotAlignDisks, virDomainSnapshotDiskDefFormat):
Likewise.
* src/esx/esx_driver.c (esxAutodetectSCSIControllerModel)
(esxDomainDefineXML): Likewise.
* src/locking/domain_lock.c (virDomainLockManagerAddDisk):
Likewise.
* src/lxc/lxc_controller.c
(virLXCControllerSetupLoopDeviceDisk)
(virLXCControllerSetupNBDDeviceDisk)
(virLXCControllerSetupLoopDevices, virLXCControllerSetupDisk):
Likewise.
* src/parallels/parallels_driver.c (parallelsGetHddInfo):
Likewise.
* src/phyp/phyp_driver.c (phypDiskType): Likewise.
* src/qemu/qemu_command.c (qemuGetDriveSourceString)
(qemuDomainDiskGetSourceString, qemuBuildDriveStr)
(qemuBuildCommandLine, qemuParseCommandLineDisk)
(qemuParseCommandLine): Likewise.
* src/qemu/qemu_conf.c (qemuCheckSharedDevice)
(qemuTranslateDiskSourcePool)
(qemuTranslateSnapshotDiskSourcePool): Likewise.
* src/qemu/qemu_domain.c (qemuDomainDeviceDefPostParse)
(qemuDomainDetermineDiskChain): Likewise.
* src/qemu/qemu_driver.c (qemuDomainGetBlockInfo)
(qemuDomainSnapshotPrepareDiskExternalBackingInactive)
(qemuDomainSnapshotPrepareDiskExternalBackingActive)
(qemuDomainSnapshotPrepareDiskExternalOverlayActive)
(qemuDomainSnapshotPrepareDiskExternalOverlayInactive)
(qemuDomainSnapshotPrepareDiskInternal)
(qemuDomainSnapshotPrepare)
(qemuDomainSnapshotCreateSingleDiskActive): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainChangeEjectableMedia):
Likewise.
* src/qemu/qemu_migration.c (qemuMigrationIsSafe): Likewise.
* src/security/security_apparmor.c
(AppArmorRestoreSecurityImageLabel)
(AppArmorSetSecurityImageLabel): Likewise.
* src/security/security_dac.c (virSecurityDACSetSecurityImageLabel)
(virSecurityDACRestoreSecurityImageLabelInt)
(virSecurityDACSetSecurityAllLabel): Likewise.
* src/security/security_selinux.c
(virSecuritySELinuxRestoreSecurityImageLabelInt)
(virSecuritySELinuxSetSecurityImageLabel)
(virSecuritySELinuxSetSecurityAllLabel): Likewise.
* src/storage/storage_backend.c (virStorageFileBackendForType):
Likewise.
* src/storage/storage_backend_fs.c (virStorageFileBackendFile)
(virStorageFileBackendBlock): Likewise.
* src/storage/storage_backend_gluster.c
(virStorageFileBackendGluster): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainGetXMLDesc, vboxAttachDrives)
(vboxDomainAttachDeviceImpl, vboxDomainDetachDevice): Likewise.
* src/vmware/vmware_conf.c (vmwareVmxPath): Likewise.
* src/vmx/vmx.c (virVMXParseDisk, virVMXFormatDisk)
(virVMXFormatFloppy): Likewise.
* src/xenxs/xen_sxpr.c (xenParseSxprDisks, xenParseSxpr)
(xenFormatSxprDisk): Likewise.
* src/xenxs/xen_xm.c (xenParseXM, xenFormatXMDisk): Likewise.
* tests/securityselinuxlabeltest.c (testSELinuxLoadDef):
Likewise.
* src/libvirt_private.syms (domain_conf.h): Move symbols...
(virstoragefile.h): ...as appropriate.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-27 21:57:49 +00:00
|
|
|
case VIR_STORAGE_TYPE_VOLUME:
|
2014-04-02 19:01:46 +00:00
|
|
|
case VIR_STORAGE_TYPE_NONE:
|
conf: move host disk type to util/
A continuation of the migration of disk details to virstoragefile.
This patch moves a single enum, but converting the name has quite
a bit of fallout.
* src/conf/domain_conf.h (virDomainDiskType): Move...
* src/util/virstoragefile.h (virStorageType): ...and rename.
* src/bhyve/bhyve_command.c (bhyveBuildDiskArgStr)
(virBhyveProcessBuildLoadCmd): Update clients.
* src/conf/domain_conf.c (virDomainDiskSourceDefParse)
(virDomainDiskDefParseXML, virDomainDiskSourceDefFormatInternal)
(virDomainDiskDefFormat, virDomainDiskGetActualType)
(virDomainDiskDefForeachPath, virDomainDiskSourceIsBlockType):
Likewise.
* src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise.
* src/conf/snapshot_conf.c (virDomainSnapshotDiskDefParseXML)
(virDomainSnapshotAlignDisks, virDomainSnapshotDiskDefFormat):
Likewise.
* src/esx/esx_driver.c (esxAutodetectSCSIControllerModel)
(esxDomainDefineXML): Likewise.
* src/locking/domain_lock.c (virDomainLockManagerAddDisk):
Likewise.
* src/lxc/lxc_controller.c
(virLXCControllerSetupLoopDeviceDisk)
(virLXCControllerSetupNBDDeviceDisk)
(virLXCControllerSetupLoopDevices, virLXCControllerSetupDisk):
Likewise.
* src/parallels/parallels_driver.c (parallelsGetHddInfo):
Likewise.
* src/phyp/phyp_driver.c (phypDiskType): Likewise.
* src/qemu/qemu_command.c (qemuGetDriveSourceString)
(qemuDomainDiskGetSourceString, qemuBuildDriveStr)
(qemuBuildCommandLine, qemuParseCommandLineDisk)
(qemuParseCommandLine): Likewise.
* src/qemu/qemu_conf.c (qemuCheckSharedDevice)
(qemuTranslateDiskSourcePool)
(qemuTranslateSnapshotDiskSourcePool): Likewise.
* src/qemu/qemu_domain.c (qemuDomainDeviceDefPostParse)
(qemuDomainDetermineDiskChain): Likewise.
* src/qemu/qemu_driver.c (qemuDomainGetBlockInfo)
(qemuDomainSnapshotPrepareDiskExternalBackingInactive)
(qemuDomainSnapshotPrepareDiskExternalBackingActive)
(qemuDomainSnapshotPrepareDiskExternalOverlayActive)
(qemuDomainSnapshotPrepareDiskExternalOverlayInactive)
(qemuDomainSnapshotPrepareDiskInternal)
(qemuDomainSnapshotPrepare)
(qemuDomainSnapshotCreateSingleDiskActive): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainChangeEjectableMedia):
Likewise.
* src/qemu/qemu_migration.c (qemuMigrationIsSafe): Likewise.
* src/security/security_apparmor.c
(AppArmorRestoreSecurityImageLabel)
(AppArmorSetSecurityImageLabel): Likewise.
* src/security/security_dac.c (virSecurityDACSetSecurityImageLabel)
(virSecurityDACRestoreSecurityImageLabelInt)
(virSecurityDACSetSecurityAllLabel): Likewise.
* src/security/security_selinux.c
(virSecuritySELinuxRestoreSecurityImageLabelInt)
(virSecuritySELinuxSetSecurityImageLabel)
(virSecuritySELinuxSetSecurityAllLabel): Likewise.
* src/storage/storage_backend.c (virStorageFileBackendForType):
Likewise.
* src/storage/storage_backend_fs.c (virStorageFileBackendFile)
(virStorageFileBackendBlock): Likewise.
* src/storage/storage_backend_gluster.c
(virStorageFileBackendGluster): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainGetXMLDesc, vboxAttachDrives)
(vboxDomainAttachDeviceImpl, vboxDomainDetachDevice): Likewise.
* src/vmware/vmware_conf.c (vmwareVmxPath): Likewise.
* src/vmx/vmx.c (virVMXParseDisk, virVMXFormatDisk)
(virVMXFormatFloppy): Likewise.
* src/xenxs/xen_sxpr.c (xenParseSxprDisks, xenParseSxpr)
(xenFormatSxprDisk): Likewise.
* src/xenxs/xen_xm.c (xenParseXM, xenFormatXMDisk): Likewise.
* tests/securityselinuxlabeltest.c (testSELinuxLoadDef):
Likewise.
* src/libvirt_private.syms (domain_conf.h): Move symbols...
(virstoragefile.h): ...as appropriate.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-27 21:57:49 +00:00
|
|
|
case VIR_STORAGE_TYPE_LAST:
|
2013-11-21 17:43:59 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-04-08 15:50:50 +00:00
|
|
|
ret = 0;
|
2012-11-22 18:10:39 +00:00
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
cleanup:
|
2013-04-01 17:13:31 +00:00
|
|
|
VIR_FREE(secret);
|
2012-11-22 18:10:39 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-02-25 17:44:25 +00:00
|
|
|
|
2014-07-29 13:21:05 +00:00
|
|
|
/* Perform disk definition config validity checks */
|
|
|
|
int
|
|
|
|
qemuCheckDiskConfig(virDomainDiskDefPtr disk)
|
|
|
|
{
|
|
|
|
if (virDiskNameToIndex(disk->dst) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported disk type '%s'"), disk->dst);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->wwn) {
|
|
|
|
if ((disk->bus != VIR_DOMAIN_DISK_BUS_IDE) &&
|
|
|
|
(disk->bus != VIR_DOMAIN_DISK_BUS_SCSI)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Only ide and scsi disk support wwn"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((disk->vendor || disk->product) &&
|
|
|
|
disk->bus != VIR_DOMAIN_DISK_BUS_SCSI) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Only scsi disk supports vendor and product"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
|
|
|
|
/* make sure that both the bus supports type='lun' (SG_IO). */
|
|
|
|
if (disk->bus != VIR_DOMAIN_DISK_BUS_VIRTIO &&
|
|
|
|
disk->bus != VIR_DOMAIN_DISK_BUS_SCSI) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("disk device='lun' is not supported for bus='%s'"),
|
|
|
|
virDomainDiskQEMUBusTypeToString(disk->bus));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (disk->src->type == VIR_STORAGE_TYPE_NETWORK) {
|
|
|
|
if (disk->src->protocol != VIR_STORAGE_NET_PROTOCOL_ISCSI) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("disk device='lun' is not supported "
|
|
|
|
"for protocol='%s'"),
|
|
|
|
virStorageNetProtocolTypeToString(disk->src->protocol));
|
|
|
|
goto error;
|
|
|
|
}
|
2015-07-18 11:34:34 +00:00
|
|
|
} else if (!virDomainDiskSourceIsBlockType(disk->src, true)) {
|
2014-07-29 13:21:05 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (disk->wwn) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Setting wwn is not supported for lun device"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (disk->vendor || disk->product) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Setting vendor or product is not supported "
|
|
|
|
"for lun device"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
error:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-31 15:06:42 +00:00
|
|
|
/* Check whether the device address is using either 'ccw' or default s390
|
|
|
|
* address format and whether that's "legal" for the current qemu and/or
|
|
|
|
* guest os.machine type. This is the corollary to the code which doesn't
|
|
|
|
* find the address type set using an emulator that supports either 'ccw'
|
|
|
|
* or s390 and sets the address type based on the capabilities.
|
|
|
|
*
|
|
|
|
* If the address is using 'ccw' or s390 and it's not supported, generate
|
|
|
|
* an error and return false; otherwise, return true.
|
|
|
|
*/
|
|
|
|
bool
|
2016-02-18 13:33:39 +00:00
|
|
|
qemuCheckCCWS390AddressSupport(const virDomainDef *def,
|
2015-08-31 15:06:42 +00:00
|
|
|
virDomainDeviceInfo info,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
const char *devicename)
|
|
|
|
{
|
|
|
|
if (info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
|
|
|
|
if (!qemuDomainMachineIsS390CCW(def)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("cannot use CCW address type for device "
|
|
|
|
"'%s' using machine type '%s'"),
|
|
|
|
devicename, def->os.machine);
|
|
|
|
return false;
|
|
|
|
} else if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("CCW address type is not supported by "
|
|
|
|
"this QEMU"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else if (info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_S390)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("virtio S390 address type is not supported by "
|
|
|
|
"this QEMU"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-18 15:38:32 +00:00
|
|
|
/* Qemu 1.2 and later have a binary flag -enable-fips that must be
|
|
|
|
* used for VNC auth to obey FIPS settings; but the flag only
|
|
|
|
* exists on Linux, and with no way to probe for it via QMP. Our
|
|
|
|
* solution: if FIPS mode is required, then unconditionally use
|
|
|
|
* the flag, regardless of qemu version, for the following matrix:
|
|
|
|
*
|
|
|
|
* old QEMU new QEMU
|
|
|
|
* FIPS enabled doesn't start VNC auth disabled
|
|
|
|
* FIPS disabled/missing VNC auth enabled VNC auth enabled
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
qemuCheckFips(void)
|
|
|
|
{
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
if (virFileExists("/proc/sys/crypto/fips_enabled")) {
|
|
|
|
char *buf = NULL;
|
|
|
|
|
|
|
|
if (virFileReadAll("/proc/sys/crypto/fips_enabled", 10, &buf) < 0)
|
|
|
|
return ret;
|
|
|
|
if (STREQ(buf, "1\n"))
|
|
|
|
ret = true;
|
|
|
|
VIR_FREE(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
char *
|
2013-11-21 17:43:59 +00:00
|
|
|
qemuBuildDriveStr(virConnectPtr conn,
|
2011-10-31 19:06:23 +00:00
|
|
|
virDomainDiskDefPtr disk,
|
2011-05-26 14:15:01 +00:00
|
|
|
bool bootable,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
|
|
|
const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
|
2012-08-20 13:58:51 +00:00
|
|
|
const char *trans =
|
|
|
|
virDomainDiskGeometryTransTypeToString(disk->geometry.trans);
|
2010-12-16 15:07:07 +00:00
|
|
|
int idx = virDiskNameToIndex(disk->dst);
|
|
|
|
int busid = -1, unitid = -1;
|
2013-11-21 17:43:59 +00:00
|
|
|
char *source = NULL;
|
2014-05-21 23:13:12 +00:00
|
|
|
int actualType = virStorageSourceGetActualType(disk->src);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (idx < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported disk type '%s'"), disk->dst);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (disk->bus) {
|
|
|
|
case VIR_DOMAIN_DISK_BUS_SCSI:
|
|
|
|
if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unexpected address type for scsi disk"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Setting bus= attr for SCSI drives, causes a controller
|
|
|
|
* to be created. Yes this is slightly odd. It is not possible
|
|
|
|
* to have > 1 bus on a SCSI controller (yet). */
|
|
|
|
if (disk->info.addr.drive.bus != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("SCSI controller only supports 1 bus"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
busid = disk->info.addr.drive.controller;
|
|
|
|
unitid = disk->info.addr.drive.unit;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_DISK_BUS_IDE:
|
|
|
|
if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unexpected address type for ide disk"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
/* We can only have 1 IDE controller (currently) */
|
|
|
|
if (disk->info.addr.drive.controller != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Only 1 %s controller is supported"), bus);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
busid = disk->info.addr.drive.bus;
|
|
|
|
unitid = disk->info.addr.drive.unit;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_DISK_BUS_FDC:
|
|
|
|
if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unexpected address type for fdc disk"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
/* We can only have 1 FDC controller (currently) */
|
|
|
|
if (disk->info.addr.drive.controller != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Only 1 %s controller is supported"), bus);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
/* We can only have 1 FDC bus (currently) */
|
|
|
|
if (disk->info.addr.drive.bus != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Only 1 %s bus is supported"), bus);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
if (disk->info.addr.drive.target != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("target must be 0 for controller fdc"));
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
unitid = disk->info.addr.drive.unit;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_DISK_BUS_VIRTIO:
|
|
|
|
idx = -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_DISK_BUS_XEN:
|
2013-07-31 13:00:26 +00:00
|
|
|
case VIR_DOMAIN_DISK_BUS_SD:
|
|
|
|
/* Xen and SD have no address type currently, so assign
|
|
|
|
* based on index */
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-05-21 23:13:12 +00:00
|
|
|
if (qemuGetDriveSourceString(disk->src, conn, &source) < 0)
|
2013-11-21 17:43:59 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (source &&
|
2012-03-14 15:26:48 +00:00
|
|
|
!((disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY ||
|
|
|
|
disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
|
|
|
|
disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN)) {
|
2013-11-20 09:37:31 +00:00
|
|
|
|
2013-11-21 17:43:59 +00:00
|
|
|
virBufferAddLit(&opt, "file=");
|
|
|
|
|
|
|
|
switch (actualType) {
|
conf: move host disk type to util/
A continuation of the migration of disk details to virstoragefile.
This patch moves a single enum, but converting the name has quite
a bit of fallout.
* src/conf/domain_conf.h (virDomainDiskType): Move...
* src/util/virstoragefile.h (virStorageType): ...and rename.
* src/bhyve/bhyve_command.c (bhyveBuildDiskArgStr)
(virBhyveProcessBuildLoadCmd): Update clients.
* src/conf/domain_conf.c (virDomainDiskSourceDefParse)
(virDomainDiskDefParseXML, virDomainDiskSourceDefFormatInternal)
(virDomainDiskDefFormat, virDomainDiskGetActualType)
(virDomainDiskDefForeachPath, virDomainDiskSourceIsBlockType):
Likewise.
* src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise.
* src/conf/snapshot_conf.c (virDomainSnapshotDiskDefParseXML)
(virDomainSnapshotAlignDisks, virDomainSnapshotDiskDefFormat):
Likewise.
* src/esx/esx_driver.c (esxAutodetectSCSIControllerModel)
(esxDomainDefineXML): Likewise.
* src/locking/domain_lock.c (virDomainLockManagerAddDisk):
Likewise.
* src/lxc/lxc_controller.c
(virLXCControllerSetupLoopDeviceDisk)
(virLXCControllerSetupNBDDeviceDisk)
(virLXCControllerSetupLoopDevices, virLXCControllerSetupDisk):
Likewise.
* src/parallels/parallels_driver.c (parallelsGetHddInfo):
Likewise.
* src/phyp/phyp_driver.c (phypDiskType): Likewise.
* src/qemu/qemu_command.c (qemuGetDriveSourceString)
(qemuDomainDiskGetSourceString, qemuBuildDriveStr)
(qemuBuildCommandLine, qemuParseCommandLineDisk)
(qemuParseCommandLine): Likewise.
* src/qemu/qemu_conf.c (qemuCheckSharedDevice)
(qemuTranslateDiskSourcePool)
(qemuTranslateSnapshotDiskSourcePool): Likewise.
* src/qemu/qemu_domain.c (qemuDomainDeviceDefPostParse)
(qemuDomainDetermineDiskChain): Likewise.
* src/qemu/qemu_driver.c (qemuDomainGetBlockInfo)
(qemuDomainSnapshotPrepareDiskExternalBackingInactive)
(qemuDomainSnapshotPrepareDiskExternalBackingActive)
(qemuDomainSnapshotPrepareDiskExternalOverlayActive)
(qemuDomainSnapshotPrepareDiskExternalOverlayInactive)
(qemuDomainSnapshotPrepareDiskInternal)
(qemuDomainSnapshotPrepare)
(qemuDomainSnapshotCreateSingleDiskActive): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainChangeEjectableMedia):
Likewise.
* src/qemu/qemu_migration.c (qemuMigrationIsSafe): Likewise.
* src/security/security_apparmor.c
(AppArmorRestoreSecurityImageLabel)
(AppArmorSetSecurityImageLabel): Likewise.
* src/security/security_dac.c (virSecurityDACSetSecurityImageLabel)
(virSecurityDACRestoreSecurityImageLabelInt)
(virSecurityDACSetSecurityAllLabel): Likewise.
* src/security/security_selinux.c
(virSecuritySELinuxRestoreSecurityImageLabelInt)
(virSecuritySELinuxSetSecurityImageLabel)
(virSecuritySELinuxSetSecurityAllLabel): Likewise.
* src/storage/storage_backend.c (virStorageFileBackendForType):
Likewise.
* src/storage/storage_backend_fs.c (virStorageFileBackendFile)
(virStorageFileBackendBlock): Likewise.
* src/storage/storage_backend_gluster.c
(virStorageFileBackendGluster): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainGetXMLDesc, vboxAttachDrives)
(vboxDomainAttachDeviceImpl, vboxDomainDetachDevice): Likewise.
* src/vmware/vmware_conf.c (vmwareVmxPath): Likewise.
* src/vmx/vmx.c (virVMXParseDisk, virVMXFormatDisk)
(virVMXFormatFloppy): Likewise.
* src/xenxs/xen_sxpr.c (xenParseSxprDisks, xenParseSxpr)
(xenFormatSxprDisk): Likewise.
* src/xenxs/xen_xm.c (xenParseXM, xenFormatXMDisk): Likewise.
* tests/securityselinuxlabeltest.c (testSELinuxLoadDef):
Likewise.
* src/libvirt_private.syms (domain_conf.h): Move symbols...
(virstoragefile.h): ...as appropriate.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-27 21:57:49 +00:00
|
|
|
case VIR_STORAGE_TYPE_DIR:
|
2010-12-16 15:07:07 +00:00
|
|
|
/* QEMU only supports magic FAT format for now */
|
2014-05-21 23:13:12 +00:00
|
|
|
if (disk->src->format > 0 &&
|
|
|
|
disk->src->format != VIR_STORAGE_FILE_FAT) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported disk driver type for '%s'"),
|
2014-05-21 23:13:12 +00:00
|
|
|
virStorageFileFormatTypeToString(disk->src->format));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2013-11-21 17:43:59 +00:00
|
|
|
|
2014-06-24 13:15:55 +00:00
|
|
|
if (!disk->src->readonly) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot create virtual FAT disks in read-write mode"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2013-11-21 17:43:59 +00:00
|
|
|
|
|
|
|
virBufferAddLit(&opt, "fat:");
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
|
2013-11-21 17:43:59 +00:00
|
|
|
virBufferAddLit(&opt, "floppy:");
|
2013-11-18 14:25:03 +00:00
|
|
|
|
2013-11-21 17:43:59 +00:00
|
|
|
break;
|
|
|
|
|
conf: move host disk type to util/
A continuation of the migration of disk details to virstoragefile.
This patch moves a single enum, but converting the name has quite
a bit of fallout.
* src/conf/domain_conf.h (virDomainDiskType): Move...
* src/util/virstoragefile.h (virStorageType): ...and rename.
* src/bhyve/bhyve_command.c (bhyveBuildDiskArgStr)
(virBhyveProcessBuildLoadCmd): Update clients.
* src/conf/domain_conf.c (virDomainDiskSourceDefParse)
(virDomainDiskDefParseXML, virDomainDiskSourceDefFormatInternal)
(virDomainDiskDefFormat, virDomainDiskGetActualType)
(virDomainDiskDefForeachPath, virDomainDiskSourceIsBlockType):
Likewise.
* src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise.
* src/conf/snapshot_conf.c (virDomainSnapshotDiskDefParseXML)
(virDomainSnapshotAlignDisks, virDomainSnapshotDiskDefFormat):
Likewise.
* src/esx/esx_driver.c (esxAutodetectSCSIControllerModel)
(esxDomainDefineXML): Likewise.
* src/locking/domain_lock.c (virDomainLockManagerAddDisk):
Likewise.
* src/lxc/lxc_controller.c
(virLXCControllerSetupLoopDeviceDisk)
(virLXCControllerSetupNBDDeviceDisk)
(virLXCControllerSetupLoopDevices, virLXCControllerSetupDisk):
Likewise.
* src/parallels/parallels_driver.c (parallelsGetHddInfo):
Likewise.
* src/phyp/phyp_driver.c (phypDiskType): Likewise.
* src/qemu/qemu_command.c (qemuGetDriveSourceString)
(qemuDomainDiskGetSourceString, qemuBuildDriveStr)
(qemuBuildCommandLine, qemuParseCommandLineDisk)
(qemuParseCommandLine): Likewise.
* src/qemu/qemu_conf.c (qemuCheckSharedDevice)
(qemuTranslateDiskSourcePool)
(qemuTranslateSnapshotDiskSourcePool): Likewise.
* src/qemu/qemu_domain.c (qemuDomainDeviceDefPostParse)
(qemuDomainDetermineDiskChain): Likewise.
* src/qemu/qemu_driver.c (qemuDomainGetBlockInfo)
(qemuDomainSnapshotPrepareDiskExternalBackingInactive)
(qemuDomainSnapshotPrepareDiskExternalBackingActive)
(qemuDomainSnapshotPrepareDiskExternalOverlayActive)
(qemuDomainSnapshotPrepareDiskExternalOverlayInactive)
(qemuDomainSnapshotPrepareDiskInternal)
(qemuDomainSnapshotPrepare)
(qemuDomainSnapshotCreateSingleDiskActive): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainChangeEjectableMedia):
Likewise.
* src/qemu/qemu_migration.c (qemuMigrationIsSafe): Likewise.
* src/security/security_apparmor.c
(AppArmorRestoreSecurityImageLabel)
(AppArmorSetSecurityImageLabel): Likewise.
* src/security/security_dac.c (virSecurityDACSetSecurityImageLabel)
(virSecurityDACRestoreSecurityImageLabelInt)
(virSecurityDACSetSecurityAllLabel): Likewise.
* src/security/security_selinux.c
(virSecuritySELinuxRestoreSecurityImageLabelInt)
(virSecuritySELinuxSetSecurityImageLabel)
(virSecuritySELinuxSetSecurityAllLabel): Likewise.
* src/storage/storage_backend.c (virStorageFileBackendForType):
Likewise.
* src/storage/storage_backend_fs.c (virStorageFileBackendFile)
(virStorageFileBackendBlock): Likewise.
* src/storage/storage_backend_gluster.c
(virStorageFileBackendGluster): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainGetXMLDesc, vboxAttachDrives)
(vboxDomainAttachDeviceImpl, vboxDomainDetachDevice): Likewise.
* src/vmware/vmware_conf.c (vmwareVmxPath): Likewise.
* src/vmx/vmx.c (virVMXParseDisk, virVMXFormatDisk)
(virVMXFormatFloppy): Likewise.
* src/xenxs/xen_sxpr.c (xenParseSxprDisks, xenParseSxpr)
(xenFormatSxprDisk): Likewise.
* src/xenxs/xen_xm.c (xenParseXM, xenFormatXMDisk): Likewise.
* tests/securityselinuxlabeltest.c (testSELinuxLoadDef):
Likewise.
* src/libvirt_private.syms (domain_conf.h): Move symbols...
(virstoragefile.h): ...as appropriate.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-27 21:57:49 +00:00
|
|
|
case VIR_STORAGE_TYPE_BLOCK:
|
2013-11-21 17:43:59 +00:00
|
|
|
if (disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2014-05-21 23:13:12 +00:00
|
|
|
disk->src->type == VIR_STORAGE_TYPE_VOLUME ?
|
2013-11-20 09:37:31 +00:00
|
|
|
_("tray status 'open' is invalid for block type volume") :
|
|
|
|
_("tray status 'open' is invalid for block type disk"));
|
2012-03-14 15:26:49 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2013-11-21 17:43:59 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2013-11-21 17:43:59 +00:00
|
|
|
|
|
|
|
virBufferEscape(&opt, ',', ",", "%s,", source);
|
2015-12-28 14:13:52 +00:00
|
|
|
|
|
|
|
if (disk->src->format > 0 &&
|
|
|
|
disk->src->type != VIR_STORAGE_TYPE_DIR)
|
|
|
|
virBufferAsprintf(&opt, "format=%s,",
|
|
|
|
virStorageFileFormatTypeToString(disk->src->format));
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2013-12-04 21:15:03 +00:00
|
|
|
VIR_FREE(source);
|
2013-11-21 17:43:59 +00:00
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferAddLit(&opt, "if=none");
|
|
|
|
else
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&opt, "if=%s", bus);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-04-17 09:08:05 +00:00
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
|
2013-05-02 11:35:14 +00:00
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_CD))
|
2012-04-17 09:08:05 +00:00
|
|
|
virBufferAddLit(&opt, ",media=cdrom");
|
2012-04-17 09:16:52 +00:00
|
|
|
} else if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_IDE_CD))
|
2012-04-17 09:16:52 +00:00
|
|
|
virBufferAddLit(&opt, ",media=cdrom");
|
2012-04-17 09:08:05 +00:00
|
|
|
} else {
|
|
|
|
virBufferAddLit(&opt, ",media=cdrom");
|
|
|
|
}
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&opt, ",id=%s%s", QEMU_DRIVE_HOST_PREFIX, disk->info.alias);
|
2010-12-16 15:07:07 +00:00
|
|
|
} else {
|
|
|
|
if (busid == -1 && unitid == -1) {
|
|
|
|
if (idx != -1)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&opt, ",index=%d", idx);
|
2010-12-16 15:07:07 +00:00
|
|
|
} else {
|
|
|
|
if (busid != -1)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&opt, ",bus=%d", busid);
|
2010-12-16 15:07:07 +00:00
|
|
|
if (unitid != -1)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&opt, ",unit=%d", unitid);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bootable &&
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_BOOT) &&
|
qemu: add new disk device='lun' for bus='virtio' & type='block'
In the past, generic SCSI commands issued from a guest to a virtio
disk were always passed through to the underlying disk by qemu, and
the kernel would also pass them on.
As a result of CVE-2011-4127 (see:
http://seclists.org/oss-sec/2011/q4/536), qemu now honors its
scsi=on|off device option for virtio-blk-pci (which enables/disables
passthrough of generic SCSI commands), and the kernel will only allow
the commands for physical devices (not for partitions or logical
volumes). The default behavior of qemu is still to allow sending
generic SCSI commands to physical disks that are presented to a guest
as virtio-blk-pci devices, but libvirt prefers to disable those
commands in the standard virtio block devices, enabling it only when
specifically requested (hopefully indicating that the requester
understands what they're asking for). For this purpose, a new libvirt
disk device type (device='lun') has been created.
device='lun' is identical to the default device='disk', except that:
1) It is only allowed if bus='virtio', type='block', and the qemu
version is "new enough" to support it ("new enough" == qemu 0.11 or
better), otherwise the domain will fail to start and a
CONFIG_UNSUPPORTED error will be logged).
2) The option "scsi=on" will be added to the -device arg to allow
SG_IO commands (if device !='lun', "scsi=off" will be added to the
-device arg so that SG_IO commands are specifically forbidden).
Guests which continue to use disk device='disk' (the default) will no
longer be able to use SG_IO commands on the disk; those that have
their disk device changed to device='lun' will still be able to use SG_IO
commands.
*docs/formatdomain.html.in - document the new device attribute value.
*docs/schemas/domaincommon.rng - allow it in the RNG
*tests/* - update the args of several existing tests to add scsi=off, and
add one new test that will test scsi=on.
*src/conf/domain_conf.c - update domain XML parser and formatter
*src/qemu/qemu_(command|driver|hotplug).c - treat
VIR_DOMAIN_DISK_DEVICE_LUN *almost* identically to
VIR_DOMAIN_DISK_DEVICE_DISK, except as indicated above.
Note that no support for this new device value was added to any
hypervisor drivers other than qemu, because it's unclear what it might
mean (if anything) to those drivers.
2012-01-05 03:48:38 +00:00
|
|
|
(disk->device == VIR_DOMAIN_DISK_DEVICE_DISK ||
|
|
|
|
disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) &&
|
2010-12-16 15:07:07 +00:00
|
|
|
disk->bus != VIR_DOMAIN_DISK_BUS_IDE)
|
|
|
|
virBufferAddLit(&opt, ",boot=on");
|
2014-06-24 13:15:55 +00:00
|
|
|
if (disk->src->readonly &&
|
2014-06-30 10:05:06 +00:00
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_READONLY)) {
|
2014-09-22 13:58:21 +00:00
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
|
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("readonly ide disks are not supported"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_SATA) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("readonly sata disks are not supported"));
|
|
|
|
goto error;
|
|
|
|
}
|
2014-06-30 10:05:06 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferAddLit(&opt, ",readonly=on");
|
2014-06-30 10:05:06 +00:00
|
|
|
}
|
2011-08-13 21:42:48 +00:00
|
|
|
if (disk->transient) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("transient disks not supported yet"));
|
2011-08-13 21:42:48 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-08-20 13:58:51 +00:00
|
|
|
|
|
|
|
/* generate geometry command string */
|
|
|
|
if (disk->geometry.cylinders > 0 &&
|
|
|
|
disk->geometry.heads > 0 &&
|
|
|
|
disk->geometry.sectors > 0) {
|
|
|
|
|
|
|
|
virBufferAsprintf(&opt, ",cyls=%u,heads=%u,secs=%u",
|
|
|
|
disk->geometry.cylinders,
|
|
|
|
disk->geometry.heads,
|
|
|
|
disk->geometry.sectors);
|
|
|
|
|
|
|
|
if (disk->geometry.trans != VIR_DOMAIN_DISK_TRANS_DEFAULT)
|
2015-06-08 13:42:44 +00:00
|
|
|
virBufferAsprintf(&opt, ",trans=%s", trans);
|
2012-08-20 13:58:51 +00:00
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (disk->serial &&
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_SERIAL)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
if (qemuSafeSerialParamValue(disk->serial) < 0)
|
|
|
|
goto error;
|
2015-06-09 20:49:00 +00:00
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
|
|
|
|
disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("scsi-block 'lun' devices do not support the "
|
|
|
|
"serial property"));
|
|
|
|
goto error;
|
|
|
|
}
|
2015-02-23 11:34:23 +00:00
|
|
|
virBufferAddLit(&opt, ",serial=");
|
|
|
|
virBufferEscape(&opt, '\\', " ", "%s", disk->serial);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->cachemode) {
|
2011-09-02 13:36:58 +00:00
|
|
|
const char *mode = NULL;
|
|
|
|
|
2015-11-06 17:26:08 +00:00
|
|
|
mode = qemuDiskCacheV2TypeToString(disk->cachemode);
|
2011-09-02 13:36:58 +00:00
|
|
|
|
2015-11-06 17:26:08 +00:00
|
|
|
if (disk->cachemode == VIR_DOMAIN_DISK_CACHE_DIRECTSYNC &&
|
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_CACHE_DIRECTSYNC)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("disk cache mode 'directsync' is not "
|
|
|
|
"supported by this QEMU"));
|
|
|
|
goto error;
|
|
|
|
} else if (disk->cachemode == VIR_DOMAIN_DISK_CACHE_UNSAFE &&
|
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_CACHE_UNSAFE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("disk cache mode 'unsafe' is not "
|
|
|
|
"supported by this QEMU"));
|
|
|
|
goto error;
|
2011-09-02 13:36:58 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2014-07-08 14:08:57 +00:00
|
|
|
if (disk->iomode == VIR_DOMAIN_DISK_IO_NATIVE &&
|
|
|
|
disk->cachemode != VIR_DOMAIN_DISK_CACHE_DIRECTSYNC &&
|
|
|
|
disk->cachemode != VIR_DOMAIN_DISK_CACHE_DISABLE) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("native I/O needs either no disk cache "
|
|
|
|
"or directsync cache mode, QEMU will fallback "
|
|
|
|
"to aio=threads"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&opt, ",cache=%s", mode);
|
2014-06-24 13:15:55 +00:00
|
|
|
} else if (disk->src->shared && !disk->src->readonly) {
|
2015-11-06 17:26:08 +00:00
|
|
|
virBufferAddLit(&opt, ",cache=none");
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2012-01-12 09:31:14 +00:00
|
|
|
if (disk->copy_on_read) {
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_COPY_ON_READ)) {
|
2012-01-12 09:31:14 +00:00
|
|
|
virBufferAsprintf(&opt, ",copy-on-read=%s",
|
2014-06-27 15:18:53 +00:00
|
|
|
virTristateSwitchTypeToString(disk->copy_on_read));
|
2012-01-12 09:31:14 +00:00
|
|
|
} else {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("copy_on_read is not supported by this QEMU binary"));
|
2012-01-12 09:31:14 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-14 12:44:54 +00:00
|
|
|
if (disk->discard) {
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_DISCARD)) {
|
|
|
|
virBufferAsprintf(&opt, ",discard=%s",
|
|
|
|
virDomainDiskDiscardTypeToString(disk->discard));
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("discard is not supported by this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_MONITOR_JSON)) {
|
2011-10-04 17:26:29 +00:00
|
|
|
const char *wpolicy = NULL, *rpolicy = NULL;
|
|
|
|
|
|
|
|
if (disk->error_policy)
|
|
|
|
wpolicy = virDomainDiskErrorPolicyTypeToString(disk->error_policy);
|
2011-10-04 18:17:06 +00:00
|
|
|
if (disk->rerror_policy)
|
|
|
|
rpolicy = virDomainDiskErrorPolicyTypeToString(disk->rerror_policy);
|
2011-10-04 17:26:29 +00:00
|
|
|
|
|
|
|
if (disk->error_policy == VIR_DOMAIN_DISK_ERROR_POLICY_ENOSPACE) {
|
qemu: leave rerror policy at default when enospace is requested
commit 12062ab set rerror=ignore when error_policy="enospace" was
selected (since the rerror option in qemu doesn't accept "enospc", as
the werror option does).
After that patch was already pushed, Paolo Bonzini noticed it and
commented that leaving rerror at the default ("report") would be a
better choice. This patch corrects the problem - if error_policy =
"enospace" is given, rerror is left off the qemu commandline,
effectively setting it to "report". For other values, rerror is still
set to match werror.
Additionally, the parsing of error_policy was changed to no longer
erroneously allow "default" as a choice - as with most other
attributes, if you want the default setting, just don't specify an
error_policy.
Finally, two ommissions in the first patch were corrected - a
long-dormant qemuxml2argv test for enospace was enabled, and fixed to
pass, and the argv2xml parser in qemu_command.c was updated to
recognize the different spelling on the qemu commandline.
2011-10-05 15:19:28 +00:00
|
|
|
/* in the case of enospace, the option is spelled
|
|
|
|
* differently in qemu, and it's only valid for werror,
|
|
|
|
* not for rerror, so leave leave rerror NULL.
|
2011-10-04 17:26:29 +00:00
|
|
|
*/
|
qemu: leave rerror policy at default when enospace is requested
commit 12062ab set rerror=ignore when error_policy="enospace" was
selected (since the rerror option in qemu doesn't accept "enospc", as
the werror option does).
After that patch was already pushed, Paolo Bonzini noticed it and
commented that leaving rerror at the default ("report") would be a
better choice. This patch corrects the problem - if error_policy =
"enospace" is given, rerror is left off the qemu commandline,
effectively setting it to "report". For other values, rerror is still
set to match werror.
Additionally, the parsing of error_policy was changed to no longer
erroneously allow "default" as a choice - as with most other
attributes, if you want the default setting, just don't specify an
error_policy.
Finally, two ommissions in the first patch were corrected - a
long-dormant qemuxml2argv test for enospace was enabled, and fixed to
pass, and the argv2xml parser in qemu_command.c was updated to
recognize the different spelling on the qemu commandline.
2011-10-05 15:19:28 +00:00
|
|
|
wpolicy = "enospc";
|
|
|
|
} else if (!rpolicy) {
|
|
|
|
/* for other policies, rpolicy can match wpolicy */
|
|
|
|
rpolicy = wpolicy;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2011-10-04 17:26:29 +00:00
|
|
|
|
|
|
|
if (wpolicy)
|
|
|
|
virBufferAsprintf(&opt, ",werror=%s", wpolicy);
|
|
|
|
if (rpolicy)
|
|
|
|
virBufferAsprintf(&opt, ",rerror=%s", rpolicy);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2010-04-21 14:28:21 +00:00
|
|
|
if (disk->iomode) {
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_AIO)) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&opt, ",aio=%s",
|
2010-04-21 14:28:21 +00:00
|
|
|
virDomainDiskIoTypeToString(disk->iomode));
|
|
|
|
} else {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("disk aio mode not supported with this "
|
|
|
|
"QEMU binary"));
|
2010-04-21 14:28:21 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-15 09:02:45 +00:00
|
|
|
/* block I/O throttling */
|
2012-01-18 16:42:33 +00:00
|
|
|
if ((disk->blkdeviotune.total_bytes_sec ||
|
|
|
|
disk->blkdeviotune.read_bytes_sec ||
|
|
|
|
disk->blkdeviotune.write_bytes_sec ||
|
|
|
|
disk->blkdeviotune.total_iops_sec ||
|
|
|
|
disk->blkdeviotune.read_iops_sec ||
|
|
|
|
disk->blkdeviotune.write_iops_sec) &&
|
2013-02-01 13:48:58 +00:00
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_IOTUNE)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("block I/O throttling not supported with this "
|
|
|
|
"QEMU binary"));
|
2012-01-18 16:42:33 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2014-10-29 12:16:04 +00:00
|
|
|
/* block I/O throttling 1.7 */
|
|
|
|
if ((disk->blkdeviotune.total_bytes_sec_max ||
|
|
|
|
disk->blkdeviotune.read_bytes_sec_max ||
|
|
|
|
disk->blkdeviotune.write_bytes_sec_max ||
|
|
|
|
disk->blkdeviotune.total_iops_sec_max ||
|
|
|
|
disk->blkdeviotune.read_iops_sec_max ||
|
2014-11-12 15:16:51 +00:00
|
|
|
disk->blkdeviotune.write_iops_sec_max ||
|
|
|
|
disk->blkdeviotune.size_iops_sec) &&
|
2014-10-29 12:16:04 +00:00
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_IOTUNE_MAX)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2014-11-12 15:16:51 +00:00
|
|
|
_("there are some block I/O throttling parameters "
|
|
|
|
"that are not supported with this QEMU binary"));
|
2014-10-29 12:16:04 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2014-08-26 11:29:10 +00:00
|
|
|
if (disk->blkdeviotune.total_bytes_sec > LLONG_MAX ||
|
|
|
|
disk->blkdeviotune.read_bytes_sec > LLONG_MAX ||
|
|
|
|
disk->blkdeviotune.write_bytes_sec > LLONG_MAX ||
|
|
|
|
disk->blkdeviotune.total_iops_sec > LLONG_MAX ||
|
|
|
|
disk->blkdeviotune.read_iops_sec > LLONG_MAX ||
|
2014-10-29 12:16:04 +00:00
|
|
|
disk->blkdeviotune.write_iops_sec > LLONG_MAX ||
|
|
|
|
disk->blkdeviotune.total_bytes_sec_max > LLONG_MAX ||
|
|
|
|
disk->blkdeviotune.read_bytes_sec_max > LLONG_MAX ||
|
|
|
|
disk->blkdeviotune.write_bytes_sec_max > LLONG_MAX ||
|
|
|
|
disk->blkdeviotune.total_iops_sec_max > LLONG_MAX ||
|
|
|
|
disk->blkdeviotune.read_iops_sec_max > LLONG_MAX ||
|
2014-11-12 15:16:51 +00:00
|
|
|
disk->blkdeviotune.write_iops_sec_max > LLONG_MAX ||
|
|
|
|
disk->blkdeviotune.size_iops_sec > LLONG_MAX) {
|
2014-08-26 11:29:10 +00:00
|
|
|
virReportError(VIR_ERR_OVERFLOW,
|
|
|
|
_("block I/O throttle limit must "
|
|
|
|
"be less than %llu using QEMU"), LLONG_MAX);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2011-11-15 09:02:45 +00:00
|
|
|
if (disk->blkdeviotune.total_bytes_sec) {
|
|
|
|
virBufferAsprintf(&opt, ",bps=%llu",
|
|
|
|
disk->blkdeviotune.total_bytes_sec);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->blkdeviotune.read_bytes_sec) {
|
|
|
|
virBufferAsprintf(&opt, ",bps_rd=%llu",
|
|
|
|
disk->blkdeviotune.read_bytes_sec);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->blkdeviotune.write_bytes_sec) {
|
|
|
|
virBufferAsprintf(&opt, ",bps_wr=%llu",
|
|
|
|
disk->blkdeviotune.write_bytes_sec);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->blkdeviotune.total_iops_sec) {
|
|
|
|
virBufferAsprintf(&opt, ",iops=%llu",
|
|
|
|
disk->blkdeviotune.total_iops_sec);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->blkdeviotune.read_iops_sec) {
|
|
|
|
virBufferAsprintf(&opt, ",iops_rd=%llu",
|
|
|
|
disk->blkdeviotune.read_iops_sec);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->blkdeviotune.write_iops_sec) {
|
|
|
|
virBufferAsprintf(&opt, ",iops_wr=%llu",
|
|
|
|
disk->blkdeviotune.write_iops_sec);
|
|
|
|
}
|
|
|
|
|
2014-10-29 12:16:04 +00:00
|
|
|
if (disk->blkdeviotune.total_bytes_sec_max) {
|
|
|
|
virBufferAsprintf(&opt, ",bps_max=%llu",
|
|
|
|
disk->blkdeviotune.total_bytes_sec_max);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->blkdeviotune.read_bytes_sec_max) {
|
|
|
|
virBufferAsprintf(&opt, ",bps_rd_max=%llu",
|
|
|
|
disk->blkdeviotune.read_bytes_sec_max);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->blkdeviotune.write_bytes_sec_max) {
|
|
|
|
virBufferAsprintf(&opt, ",bps_wr_max=%llu",
|
|
|
|
disk->blkdeviotune.write_bytes_sec_max);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->blkdeviotune.total_iops_sec_max) {
|
|
|
|
virBufferAsprintf(&opt, ",iops_max=%llu",
|
|
|
|
disk->blkdeviotune.total_iops_sec_max);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->blkdeviotune.read_iops_sec_max) {
|
|
|
|
virBufferAsprintf(&opt, ",iops_rd_max=%llu",
|
|
|
|
disk->blkdeviotune.read_iops_sec_max);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->blkdeviotune.write_iops_sec_max) {
|
|
|
|
virBufferAsprintf(&opt, ",iops_wr_max=%llu",
|
|
|
|
disk->blkdeviotune.write_iops_sec_max);
|
|
|
|
}
|
|
|
|
|
2014-11-12 13:04:15 +00:00
|
|
|
if (disk->blkdeviotune.size_iops_sec) {
|
2014-10-29 12:16:04 +00:00
|
|
|
virBufferAsprintf(&opt, ",iops_size=%llu",
|
|
|
|
disk->blkdeviotune.size_iops_sec);
|
|
|
|
}
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&opt) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&opt);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2013-12-04 21:15:03 +00:00
|
|
|
VIR_FREE(source);
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&opt);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-08-25 19:59:32 +00:00
|
|
|
|
|
|
|
static bool
|
2016-02-18 14:56:10 +00:00
|
|
|
qemuCheckIOThreads(const virDomainDef *def,
|
2014-08-25 19:59:32 +00:00
|
|
|
virDomainDiskDefPtr disk)
|
|
|
|
{
|
|
|
|
/* Right "type" of disk" */
|
2014-11-06 14:04:04 +00:00
|
|
|
if (disk->bus != VIR_DOMAIN_DISK_BUS_VIRTIO ||
|
2014-11-06 14:04:05 +00:00
|
|
|
(disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
|
|
|
|
disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)) {
|
2014-08-25 19:59:32 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2014-11-06 14:04:05 +00:00
|
|
|
_("IOThreads only available for virtio pci and "
|
|
|
|
"virtio ccw disk"));
|
2014-08-25 19:59:32 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-04-10 13:21:23 +00:00
|
|
|
/* Can we find the disk iothread in the iothreadid list? */
|
|
|
|
if (!virDomainIOThreadIDFind(def, disk->iothread)) {
|
2014-08-25 19:59:32 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2015-04-10 13:21:23 +00:00
|
|
|
_("Disk iothread '%u' not defined in iothreadid"),
|
|
|
|
disk->iothread);
|
2014-08-25 19:59:32 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
char *
|
2016-02-18 14:56:10 +00:00
|
|
|
qemuBuildDriveDevStr(const virDomainDef *def,
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
virDomainDiskDefPtr disk,
|
2011-05-26 14:15:01 +00:00
|
|
|
int bootindex,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
|
|
|
const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
|
2015-04-30 17:19:10 +00:00
|
|
|
const char *contAlias;
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
int controllerModel;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2014-07-29 13:21:05 +00:00
|
|
|
if (qemuCheckDiskConfig(disk) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
2012-12-06 10:23:02 +00:00
|
|
|
|
2014-07-29 13:21:05 +00:00
|
|
|
/* Live only checks */
|
qemu: add new disk device='lun' for bus='virtio' & type='block'
In the past, generic SCSI commands issued from a guest to a virtio
disk were always passed through to the underlying disk by qemu, and
the kernel would also pass them on.
As a result of CVE-2011-4127 (see:
http://seclists.org/oss-sec/2011/q4/536), qemu now honors its
scsi=on|off device option for virtio-blk-pci (which enables/disables
passthrough of generic SCSI commands), and the kernel will only allow
the commands for physical devices (not for partitions or logical
volumes). The default behavior of qemu is still to allow sending
generic SCSI commands to physical disks that are presented to a guest
as virtio-blk-pci devices, but libvirt prefers to disable those
commands in the standard virtio block devices, enabling it only when
specifically requested (hopefully indicating that the requester
understands what they're asking for). For this purpose, a new libvirt
disk device type (device='lun') has been created.
device='lun' is identical to the default device='disk', except that:
1) It is only allowed if bus='virtio', type='block', and the qemu
version is "new enough" to support it ("new enough" == qemu 0.11 or
better), otherwise the domain will fail to start and a
CONFIG_UNSUPPORTED error will be logged).
2) The option "scsi=on" will be added to the -device arg to allow
SG_IO commands (if device !='lun', "scsi=off" will be added to the
-device arg so that SG_IO commands are specifically forbidden).
Guests which continue to use disk device='disk' (the default) will no
longer be able to use SG_IO commands on the disk; those that have
their disk device changed to device='lun' will still be able to use SG_IO
commands.
*docs/formatdomain.html.in - document the new device attribute value.
*docs/schemas/domaincommon.rng - allow it in the RNG
*tests/* - update the args of several existing tests to add scsi=off, and
add one new test that will test scsi=on.
*src/conf/domain_conf.c - update domain XML parser and formatter
*src/qemu/qemu_(command|driver|hotplug).c - treat
VIR_DOMAIN_DISK_DEVICE_LUN *almost* identically to
VIR_DOMAIN_DISK_DEVICE_DISK, except as indicated above.
Note that no support for this new device value was added to any
hypervisor drivers other than qemu, because it's unclear what it might
mean (if anything) to those drivers.
2012-01-05 03:48:38 +00:00
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
|
2014-07-29 13:21:05 +00:00
|
|
|
/* make sure that the qemu binary supports type='lun' (SG_IO). */
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BLK_SG_IO)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2014-07-29 13:21:05 +00:00
|
|
|
_("disk device='lun' is not supported by "
|
|
|
|
"this QEMU"));
|
2012-12-06 10:23:02 +00:00
|
|
|
goto error;
|
|
|
|
}
|
qemu: add new disk device='lun' for bus='virtio' & type='block'
In the past, generic SCSI commands issued from a guest to a virtio
disk were always passed through to the underlying disk by qemu, and
the kernel would also pass them on.
As a result of CVE-2011-4127 (see:
http://seclists.org/oss-sec/2011/q4/536), qemu now honors its
scsi=on|off device option for virtio-blk-pci (which enables/disables
passthrough of generic SCSI commands), and the kernel will only allow
the commands for physical devices (not for partitions or logical
volumes). The default behavior of qemu is still to allow sending
generic SCSI commands to physical disks that are presented to a guest
as virtio-blk-pci devices, but libvirt prefers to disable those
commands in the standard virtio block devices, enabling it only when
specifically requested (hopefully indicating that the requester
understands what they're asking for). For this purpose, a new libvirt
disk device type (device='lun') has been created.
device='lun' is identical to the default device='disk', except that:
1) It is only allowed if bus='virtio', type='block', and the qemu
version is "new enough" to support it ("new enough" == qemu 0.11 or
better), otherwise the domain will fail to start and a
CONFIG_UNSUPPORTED error will be logged).
2) The option "scsi=on" will be added to the -device arg to allow
SG_IO commands (if device !='lun', "scsi=off" will be added to the
-device arg so that SG_IO commands are specifically forbidden).
Guests which continue to use disk device='disk' (the default) will no
longer be able to use SG_IO commands on the disk; those that have
their disk device changed to device='lun' will still be able to use SG_IO
commands.
*docs/formatdomain.html.in - document the new device attribute value.
*docs/schemas/domaincommon.rng - allow it in the RNG
*tests/* - update the args of several existing tests to add scsi=off, and
add one new test that will test scsi=on.
*src/conf/domain_conf.c - update domain XML parser and formatter
*src/qemu/qemu_(command|driver|hotplug).c - treat
VIR_DOMAIN_DISK_DEVICE_LUN *almost* identically to
VIR_DOMAIN_DISK_DEVICE_DISK, except as indicated above.
Note that no support for this new device value was added to any
hypervisor drivers other than qemu, because it's unclear what it might
mean (if anything) to those drivers.
2012-01-05 03:48:38 +00:00
|
|
|
}
|
|
|
|
|
2015-08-31 15:06:42 +00:00
|
|
|
if (!qemuCheckCCWS390AddressSupport(def, disk->info, qemuCaps, disk->dst))
|
|
|
|
goto error;
|
|
|
|
|
qemu: Fix qemu startup check for QEMU_CAPS_OBJECT_IOTHREAD
https://bugzilla.redhat.com/show_bug.cgi?id=1249981
When qemuDomainPinIOThread was added in commit id 'fb562614', a check
for the IOThread capability was not needed since a check for iothreadpids
covered the condition where the support for IOThreads was not present.
The iothreadpids array was only created if qemuProcessDetectIOThreadPIDs
was able to query the monitor for IOThreads. It would only do that if
the QEMU_CAPS_OBJECT_IOTHREAD capability was set.
However, when iothreadids were added in commit id '8d4614a5' and the
check for iothreadpids was replaced by a search through the iothreadids[]
array for the matching iothread_id that left open the possibility that
an iothreadids[] array was defined, but the entries essentially pointed
to elements with only the 'iothread_id' defined leaving the 'thread_id'
value of 0 and eventually the cpumap entry of NULL.
This was because, the original IOThreads commit id '72edaae7' only
checked if IOThreads were defined and if the emulator had the IOThreads
capability, then IOThread objects were added at startup. The "capability
failure" check was only done when a disk was assigned to an IOThread in
qemuCheckIOThreads. This was because the initial implementation had no way
to dynamically add IOThreads, but it was possible to dynamically add a
disk to the domain. So the decision was if the domain supported it, then
add the IOThread objects. Then if a disk with an IOThread defined was
added, it could check the capability and fail to add if not there. This
just meant the 'iothreads' value was essentially ignored.
Eventually commit id 'a27ed6e7' allowed for the dynamic addition and
deletion of IOThread objects. So it was no longer necessary to generate
IOThread objects to dynamically attach a disk to. However, the startup
and disk check code was not modified to reflect this.
This patch will move the capability failure check to when IOThread
objects are being added to the command line. Thus a domain that has
IOThreads defined will not be started if the emulator doesn't support
the capability. This means when qemuCheckIOThreads is called to add
a disk, it's no longer necessary to check the capability. Instead the
code can use the IOThreadFind call to indicate that the IOThread
doesn't exist.
Finally because it could be possible to have a domain running with the
iothreadids[] defined prior to this change if libvirtd is restarted each
having mostly empty elements, qemuProcessDetectIOThreadPIDs will check
if there are niothreadids when the QEMU_CAPS_OBJECT_IOTHREAD capability
check fails and remove the elements and array if it exists.
With these changes in place, it turns out the cputune-numatune test
was failing because the right bit wasn't set in the test. So used the
opportunity to fix that and create a test that would expect to fail
with some sort of iothreads defined and used, but not having the
correct capability.
2015-10-15 16:30:40 +00:00
|
|
|
if (disk->iothread && !qemuCheckIOThreads(def, disk))
|
2014-08-25 19:59:32 +00:00
|
|
|
goto error;
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
switch (disk->bus) {
|
|
|
|
case VIR_DOMAIN_DISK_BUS_IDE:
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
if (disk->info.addr.drive.target != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("target must be 0 for ide controller"));
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-04-17 09:16:52 +00:00
|
|
|
|
2012-09-11 08:57:04 +00:00
|
|
|
if (disk->wwn &&
|
2013-02-01 13:48:58 +00:00
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_IDE_DRIVE_WWN)) {
|
2012-09-11 08:57:04 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Setting wwn for ide disk is not supported "
|
|
|
|
"by this QEMU"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_IDE_CD)) {
|
2012-04-17 09:16:52 +00:00
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
|
|
|
|
virBufferAddLit(&opt, "ide-cd");
|
|
|
|
else
|
|
|
|
virBufferAddLit(&opt, "ide-hd");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(&opt, "ide-drive");
|
|
|
|
}
|
|
|
|
|
2015-04-30 17:19:10 +00:00
|
|
|
if (!(contAlias = virDomainControllerAliasFind(def, VIR_DOMAIN_CONTROLLER_TYPE_IDE,
|
|
|
|
disk->info.addr.drive.controller)))
|
|
|
|
goto error;
|
|
|
|
virBufferAsprintf(&opt, ",bus=%s.%d,unit=%d",
|
|
|
|
contAlias,
|
2010-12-16 15:07:07 +00:00
|
|
|
disk->info.addr.drive.bus,
|
|
|
|
disk->info.addr.drive.unit);
|
|
|
|
break;
|
2015-04-30 12:16:40 +00:00
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
case VIR_DOMAIN_DISK_BUS_SCSI:
|
2012-03-12 14:19:56 +00:00
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_BLOCK)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("This QEMU doesn't support scsi-block for "
|
|
|
|
"lun passthrough"));
|
2012-03-12 14:19:56 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-11 08:57:04 +00:00
|
|
|
if (disk->wwn &&
|
2013-02-01 13:48:58 +00:00
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_DISK_WWN)) {
|
2012-09-11 08:57:04 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Setting wwn for scsi disk is not supported "
|
|
|
|
"by this QEMU"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-12-06 10:23:02 +00:00
|
|
|
/* Properties wwn, vendor and product were introduced in the
|
|
|
|
* same QEMU release (1.2.0).
|
|
|
|
*/
|
|
|
|
if ((disk->vendor || disk->product) &&
|
2013-02-01 13:48:58 +00:00
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_DISK_WWN)) {
|
2012-12-06 10:23:02 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Setting vendor or product for scsi disk is not "
|
|
|
|
"supported by this QEMU"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
controllerModel =
|
2013-04-09 02:32:40 +00:00
|
|
|
virDomainDeviceFindControllerModel(def, &disk->info,
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_SCSI);
|
2016-02-15 18:08:02 +00:00
|
|
|
if ((qemuDomainSetSCSIControllerModel(def, qemuCaps,
|
|
|
|
&controllerModel)) < 0)
|
2012-08-08 07:06:33 +00:00
|
|
|
goto error;
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
|
2015-04-30 16:51:51 +00:00
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
|
|
|
|
virBufferAddLit(&opt, "scsi-block");
|
|
|
|
} else {
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_CD)) {
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
|
|
|
|
virBufferAddLit(&opt, "scsi-cd");
|
|
|
|
else
|
|
|
|
virBufferAddLit(&opt, "scsi-hd");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(&opt, "scsi-disk");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-30 17:19:10 +00:00
|
|
|
if (!(contAlias = virDomainControllerAliasFind(def, VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
|
|
|
|
disk->info.addr.drive.controller)))
|
|
|
|
goto error;
|
|
|
|
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
if (controllerModel == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC) {
|
|
|
|
if (disk->info.addr.drive.target != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("target must be 0 for controller "
|
|
|
|
"model 'lsilogic'"));
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2015-04-30 17:19:10 +00:00
|
|
|
virBufferAsprintf(&opt, ",bus=%s.%d,scsi-id=%d",
|
|
|
|
contAlias,
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
disk->info.addr.drive.bus,
|
|
|
|
disk->info.addr.drive.unit);
|
|
|
|
} else {
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_DISK_CHANNEL)) {
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
if (disk->info.addr.drive.target > 7) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("This QEMU doesn't support target "
|
|
|
|
"greater than 7"));
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2015-04-30 19:52:03 +00:00
|
|
|
if (disk->info.addr.drive.bus != 0 &&
|
|
|
|
disk->info.addr.drive.unit != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("This QEMU only supports both bus and "
|
|
|
|
"unit equal to 0"));
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-30 17:19:10 +00:00
|
|
|
virBufferAsprintf(&opt, ",bus=%s.0,channel=%d,scsi-id=%d,lun=%d",
|
|
|
|
contAlias,
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
disk->info.addr.drive.bus,
|
|
|
|
disk->info.addr.drive.target,
|
|
|
|
disk->info.addr.drive.unit);
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
2015-04-30 12:16:40 +00:00
|
|
|
|
2011-09-28 03:46:08 +00:00
|
|
|
case VIR_DOMAIN_DISK_BUS_SATA:
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
if (disk->info.addr.drive.bus != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("bus must be 0 for ide controller"));
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (disk->info.addr.drive.target != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("target must be 0 for ide controller"));
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-04-17 09:16:52 +00:00
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_IDE_CD)) {
|
2012-04-17 09:16:52 +00:00
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
|
|
|
|
virBufferAddLit(&opt, "ide-cd");
|
|
|
|
else
|
|
|
|
virBufferAddLit(&opt, "ide-hd");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(&opt, "ide-drive");
|
|
|
|
}
|
|
|
|
|
2015-04-30 17:19:10 +00:00
|
|
|
if (!(contAlias = virDomainControllerAliasFind(def, VIR_DOMAIN_CONTROLLER_TYPE_SATA,
|
|
|
|
disk->info.addr.drive.controller)))
|
|
|
|
goto error;
|
|
|
|
virBufferAsprintf(&opt, ",bus=%s.%d",
|
|
|
|
contAlias,
|
|
|
|
disk->info.addr.drive.unit);
|
2011-09-28 03:46:08 +00:00
|
|
|
break;
|
2015-04-30 12:16:40 +00:00
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
case VIR_DOMAIN_DISK_BUS_VIRTIO:
|
2013-03-05 15:44:21 +00:00
|
|
|
if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
|
|
|
|
virBufferAddLit(&opt, "virtio-blk-ccw");
|
2014-11-06 14:04:05 +00:00
|
|
|
if (disk->iothread)
|
|
|
|
virBufferAsprintf(&opt, ",iothread=iothread%u", disk->iothread);
|
2013-03-05 15:44:21 +00:00
|
|
|
} else if (disk->info.type ==
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
|
2012-06-29 15:02:05 +00:00
|
|
|
virBufferAddLit(&opt, "virtio-blk-s390");
|
2013-08-01 01:40:35 +00:00
|
|
|
} else if (disk->info.type ==
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO) {
|
|
|
|
virBufferAddLit(&opt, "virtio-blk-device");
|
2012-06-29 15:02:05 +00:00
|
|
|
} else {
|
|
|
|
virBufferAddLit(&opt, "virtio-blk-pci");
|
2014-08-25 19:59:32 +00:00
|
|
|
if (disk->iothread)
|
|
|
|
virBufferAsprintf(&opt, ",iothread=iothread%u", disk->iothread);
|
2012-06-29 15:02:05 +00:00
|
|
|
}
|
2013-02-01 13:48:58 +00:00
|
|
|
qemuBuildIoEventFdStr(&opt, disk->ioeventfd, qemuCaps);
|
2011-08-13 06:32:45 +00:00
|
|
|
if (disk->event_idx &&
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BLK_EVENT_IDX)) {
|
2011-08-13 06:32:45 +00:00
|
|
|
virBufferAsprintf(&opt, ",event_idx=%s",
|
2014-06-27 15:18:53 +00:00
|
|
|
virTristateSwitchTypeToString(disk->event_idx));
|
2011-08-13 06:32:45 +00:00
|
|
|
}
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BLK_SCSI)) {
|
qemu: add new disk device='lun' for bus='virtio' & type='block'
In the past, generic SCSI commands issued from a guest to a virtio
disk were always passed through to the underlying disk by qemu, and
the kernel would also pass them on.
As a result of CVE-2011-4127 (see:
http://seclists.org/oss-sec/2011/q4/536), qemu now honors its
scsi=on|off device option for virtio-blk-pci (which enables/disables
passthrough of generic SCSI commands), and the kernel will only allow
the commands for physical devices (not for partitions or logical
volumes). The default behavior of qemu is still to allow sending
generic SCSI commands to physical disks that are presented to a guest
as virtio-blk-pci devices, but libvirt prefers to disable those
commands in the standard virtio block devices, enabling it only when
specifically requested (hopefully indicating that the requester
understands what they're asking for). For this purpose, a new libvirt
disk device type (device='lun') has been created.
device='lun' is identical to the default device='disk', except that:
1) It is only allowed if bus='virtio', type='block', and the qemu
version is "new enough" to support it ("new enough" == qemu 0.11 or
better), otherwise the domain will fail to start and a
CONFIG_UNSUPPORTED error will be logged).
2) The option "scsi=on" will be added to the -device arg to allow
SG_IO commands (if device !='lun', "scsi=off" will be added to the
-device arg so that SG_IO commands are specifically forbidden).
Guests which continue to use disk device='disk' (the default) will no
longer be able to use SG_IO commands on the disk; those that have
their disk device changed to device='lun' will still be able to use SG_IO
commands.
*docs/formatdomain.html.in - document the new device attribute value.
*docs/schemas/domaincommon.rng - allow it in the RNG
*tests/* - update the args of several existing tests to add scsi=off, and
add one new test that will test scsi=on.
*src/conf/domain_conf.c - update domain XML parser and formatter
*src/qemu/qemu_(command|driver|hotplug).c - treat
VIR_DOMAIN_DISK_DEVICE_LUN *almost* identically to
VIR_DOMAIN_DISK_DEVICE_DISK, except as indicated above.
Note that no support for this new device value was added to any
hypervisor drivers other than qemu, because it's unclear what it might
mean (if anything) to those drivers.
2012-01-05 03:48:38 +00:00
|
|
|
/* if sg_io is true but the scsi option isn't supported,
|
|
|
|
* that means it's just always on in this version of qemu.
|
|
|
|
*/
|
|
|
|
virBufferAsprintf(&opt, ",scsi=%s",
|
|
|
|
(disk->device == VIR_DOMAIN_DISK_DEVICE_LUN)
|
|
|
|
? "on" : "off");
|
|
|
|
}
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&opt, def, &disk->info, qemuCaps) < 0)
|
2011-09-16 15:51:20 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
2015-04-30 12:16:40 +00:00
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
case VIR_DOMAIN_DISK_BUS_USB:
|
2015-04-30 12:16:40 +00:00
|
|
|
if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
|
|
|
|
disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unexpected address type for usb disk"));
|
|
|
|
goto error;
|
|
|
|
}
|
2013-08-23 10:38:10 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_USB_STORAGE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("This QEMU doesn't support '-device "
|
|
|
|
"usb-storage'"));
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferAddLit(&opt, "usb-storage");
|
2012-10-26 09:09:21 +00:00
|
|
|
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&opt, def, &disk->info, qemuCaps) < 0)
|
2012-10-26 09:09:21 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
2015-04-30 12:16:40 +00:00
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
default:
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported disk bus '%s' with device setup"), bus);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2015-04-30 12:16:40 +00:00
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&opt, ",drive=%s%s", QEMU_DRIVE_HOST_PREFIX, disk->info.alias);
|
|
|
|
virBufferAsprintf(&opt, ",id=%s", disk->info.alias);
|
2013-02-01 13:48:58 +00:00
|
|
|
if (bootindex && virQEMUCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX))
|
2011-05-26 14:15:01 +00:00
|
|
|
virBufferAsprintf(&opt, ",bootindex=%d", bootindex);
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKIO)) {
|
2012-09-04 14:30:55 +00:00
|
|
|
if (disk->blockio.logical_block_size > 0)
|
2012-08-29 15:48:31 +00:00
|
|
|
virBufferAsprintf(&opt, ",logical_block_size=%u",
|
2012-09-04 14:30:55 +00:00
|
|
|
disk->blockio.logical_block_size);
|
|
|
|
if (disk->blockio.physical_block_size > 0)
|
2012-08-29 15:48:31 +00:00
|
|
|
virBufferAsprintf(&opt, ",physical_block_size=%u",
|
2012-09-04 14:30:55 +00:00
|
|
|
disk->blockio.physical_block_size);
|
2012-08-29 15:48:31 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
qemu: Allow the disk wwn to have "0x" prefix
The recent qemu requires "0x" prefix for the disk wwn, this patch
changes virValidateWWN to allow the prefix, and prepend "0x" if
it's not specified. E.g.
qemu-kvm: -device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,\
drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,wwn=6000c60016ea71ad:
Property 'scsi-hd.wwn' doesn't take value '6000c60016ea71ad'
Though it's a qemu regression, but it's nice to allow the prefix,
and doesn't hurt for us to always output "0x".
2013-04-17 13:23:44 +00:00
|
|
|
if (disk->wwn) {
|
|
|
|
if (STRPREFIX(disk->wwn, "0x"))
|
|
|
|
virBufferAsprintf(&opt, ",wwn=%s", disk->wwn);
|
|
|
|
else
|
|
|
|
virBufferAsprintf(&opt, ",wwn=0x%s", disk->wwn);
|
|
|
|
}
|
2012-09-11 08:57:04 +00:00
|
|
|
|
2012-12-06 10:23:02 +00:00
|
|
|
if (disk->vendor)
|
|
|
|
virBufferAsprintf(&opt, ",vendor=%s", disk->vendor);
|
|
|
|
|
|
|
|
if (disk->product)
|
|
|
|
virBufferAsprintf(&opt, ",product=%s", disk->product);
|
|
|
|
|
2013-08-23 10:38:11 +00:00
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_USB_STORAGE_REMOVABLE)) {
|
2014-06-27 15:18:53 +00:00
|
|
|
if (disk->removable == VIR_TRISTATE_SWITCH_ON)
|
2013-08-23 10:38:11 +00:00
|
|
|
virBufferAddLit(&opt, ",removable=on");
|
|
|
|
else
|
|
|
|
virBufferAddLit(&opt, ",removable=off");
|
|
|
|
} else {
|
2014-06-27 15:18:53 +00:00
|
|
|
if (disk->removable != VIR_TRISTATE_SWITCH_ABSENT) {
|
2013-08-23 10:38:11 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("This QEMU doesn't support setting the "
|
|
|
|
"removable flag of USB storage devices"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&opt) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&opt);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&opt);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-18 14:56:10 +00:00
|
|
|
static int
|
|
|
|
qemuBuildDiskDriveCommandLine(virCommandPtr cmd,
|
|
|
|
virConnectPtr conn,
|
|
|
|
const virDomainDef *def,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
bool emitBootindex)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
int bootCD = 0, bootFloppy = 0, bootDisk = 0;
|
|
|
|
virBuffer fdc_opts = VIR_BUFFER_INITIALIZER;
|
|
|
|
char *fdc_opts_str = NULL;
|
|
|
|
|
|
|
|
if ((virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_BOOT) || emitBootindex)) {
|
|
|
|
/* bootDevs will get translated into either bootindex=N or boot=on
|
|
|
|
* depending on what qemu supports */
|
|
|
|
for (i = 0; i < def->os.nBootDevs; i++) {
|
|
|
|
switch (def->os.bootDevs[i]) {
|
|
|
|
case VIR_DOMAIN_BOOT_CDROM:
|
|
|
|
bootCD = i + 1;
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_BOOT_FLOPPY:
|
|
|
|
bootFloppy = i + 1;
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_BOOT_DISK:
|
|
|
|
bootDisk = i + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < def->ndisks; i++) {
|
|
|
|
char *optstr;
|
|
|
|
int bootindex = 0;
|
|
|
|
virDomainDiskDefPtr disk = def->disks[i];
|
|
|
|
bool withDeviceArg = false;
|
|
|
|
bool deviceFlagMasked = false;
|
|
|
|
|
|
|
|
/* Unless we have -device, then USB disks need special
|
|
|
|
handling */
|
|
|
|
if ((disk->bus == VIR_DOMAIN_DISK_BUS_USB) &&
|
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
|
|
|
|
virCommandAddArg(cmd, "-usbdevice");
|
|
|
|
virCommandAddArgFormat(cmd, "disk:%s", disk->src->path);
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported usb disk type for '%s'"),
|
|
|
|
disk->src->path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* PowerPC pseries based VMs do not support floppy device */
|
|
|
|
if ((disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) &&
|
|
|
|
ARCH_IS_PPC64(def->os.arch) &&
|
|
|
|
STRPREFIX(def->os.machine, "pseries")) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("PowerPC pseries machines do not support floppy device"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (disk->device) {
|
|
|
|
case VIR_DOMAIN_DISK_DEVICE_CDROM:
|
|
|
|
bootindex = bootCD;
|
|
|
|
bootCD = 0;
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
|
|
|
|
bootindex = bootFloppy;
|
|
|
|
bootFloppy = 0;
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_DEVICE_DISK:
|
|
|
|
case VIR_DOMAIN_DISK_DEVICE_LUN:
|
|
|
|
bootindex = bootDisk;
|
|
|
|
bootDisk = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-drive");
|
|
|
|
|
|
|
|
/* Unfortunately it is not possible to use
|
|
|
|
-device for floppies, xen PV, or SD
|
|
|
|
devices. Fortunately, those don't need
|
|
|
|
static PCI addresses, so we don't really
|
|
|
|
care that we can't use -device */
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
|
|
|
if (disk->bus != VIR_DOMAIN_DISK_BUS_XEN &&
|
|
|
|
disk->bus != VIR_DOMAIN_DISK_BUS_SD) {
|
|
|
|
withDeviceArg = true;
|
|
|
|
} else {
|
|
|
|
virQEMUCapsClear(qemuCaps, QEMU_CAPS_DEVICE);
|
|
|
|
deviceFlagMasked = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
optstr = qemuBuildDriveStr(conn, disk,
|
|
|
|
emitBootindex ? false : !!bootindex,
|
|
|
|
qemuCaps);
|
|
|
|
if (deviceFlagMasked)
|
|
|
|
virQEMUCapsSet(qemuCaps, QEMU_CAPS_DEVICE);
|
|
|
|
if (!optstr)
|
|
|
|
return -1;
|
|
|
|
virCommandAddArg(cmd, optstr);
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
|
|
|
|
if (!emitBootindex)
|
|
|
|
bootindex = 0;
|
|
|
|
else if (disk->info.bootIndex)
|
|
|
|
bootindex = disk->info.bootIndex;
|
|
|
|
|
|
|
|
if (withDeviceArg) {
|
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
|
|
|
|
if (virAsprintf(&optstr, "drive%c=drive-%s",
|
|
|
|
disk->info.addr.drive.unit ? 'B' : 'A',
|
|
|
|
disk->info.alias) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!qemuDomainMachineNeedsFDC(def)) {
|
|
|
|
virCommandAddArg(cmd, "-global");
|
|
|
|
virCommandAddArgFormat(cmd, "isa-fdc.%s", optstr);
|
|
|
|
} else {
|
|
|
|
virBufferAsprintf(&fdc_opts, "%s,", optstr);
|
|
|
|
}
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
|
|
|
|
if (bootindex) {
|
|
|
|
if (virAsprintf(&optstr, "bootindex%c=%d",
|
|
|
|
disk->info.addr.drive.unit
|
|
|
|
? 'B' : 'A',
|
|
|
|
bootindex) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!qemuDomainMachineNeedsFDC(def)) {
|
|
|
|
virCommandAddArg(cmd, "-global");
|
|
|
|
virCommandAddArgFormat(cmd, "isa-fdc.%s", optstr);
|
|
|
|
} else {
|
|
|
|
virBufferAsprintf(&fdc_opts, "%s,", optstr);
|
|
|
|
}
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
|
|
|
|
if (!(optstr = qemuBuildDriveDevStr(def, disk, bootindex,
|
|
|
|
qemuCaps)))
|
|
|
|
return -1;
|
|
|
|
virCommandAddArg(cmd, optstr);
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Newer Q35 machine types require an explicit FDC controller */
|
|
|
|
virBufferTrim(&fdc_opts, ",", -1);
|
|
|
|
if ((fdc_opts_str = virBufferContentAndReset(&fdc_opts))) {
|
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
virCommandAddArgFormat(cmd, "isa-fdc,%s", fdc_opts_str);
|
|
|
|
VIR_FREE(fdc_opts_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-18 15:06:14 +00:00
|
|
|
static char *
|
|
|
|
qemuBuildFSStr(virDomainFSDefPtr fs,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
2011-10-11 11:30:40 +00:00
|
|
|
const char *driver = qemuDomainFSDriverTypeToString(fs->fsdriver);
|
2012-01-17 12:44:18 +00:00
|
|
|
const char *wrpolicy = virDomainFSWrpolicyTypeToString(fs->wrpolicy);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (fs->type != VIR_DOMAIN_FS_TYPE_MOUNT) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("only supports mount filesystem type"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2011-10-11 11:30:40 +00:00
|
|
|
if (!driver) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Filesystem driver type not supported"));
|
2011-10-11 11:30:40 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAdd(&opt, driver, -1);
|
|
|
|
|
2012-01-10 12:53:31 +00:00
|
|
|
if (fs->fsdriver == VIR_DOMAIN_FS_DRIVER_TYPE_PATH ||
|
|
|
|
fs->fsdriver == VIR_DOMAIN_FS_DRIVER_TYPE_DEFAULT) {
|
|
|
|
if (fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_MAPPED) {
|
|
|
|
virBufferAddLit(&opt, ",security_model=mapped");
|
2012-10-17 09:23:12 +00:00
|
|
|
} else if (fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH) {
|
2012-01-10 12:53:31 +00:00
|
|
|
virBufferAddLit(&opt, ",security_model=passthrough");
|
2012-10-17 09:23:12 +00:00
|
|
|
} else if (fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_SQUASH) {
|
2012-01-10 12:53:31 +00:00
|
|
|
virBufferAddLit(&opt, ",security_model=none");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* For other fs drivers, default(passthru) should always
|
|
|
|
* be supported */
|
|
|
|
if (fs->accessmode != VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("only supports passthrough accessmode"));
|
2012-01-10 12:53:31 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-01-17 12:44:18 +00:00
|
|
|
|
|
|
|
if (fs->wrpolicy) {
|
2014-08-07 11:45:34 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_FSDEV_WRITEOUT)) {
|
|
|
|
virBufferAsprintf(&opt, ",writeout=%s", wrpolicy);
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("filesystem writeout not supported"));
|
|
|
|
goto error;
|
|
|
|
}
|
2012-01-17 12:44:18 +00:00
|
|
|
}
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&opt, ",id=%s%s", QEMU_FSDEV_HOST_PREFIX, fs->info.alias);
|
|
|
|
virBufferAsprintf(&opt, ",path=%s", fs->src);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-12-21 15:51:29 +00:00
|
|
|
if (fs->readonly) {
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_FSDEV_READONLY)) {
|
2011-12-21 15:51:29 +00:00
|
|
|
virBufferAddLit(&opt, ",readonly");
|
|
|
|
} else {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("readonly filesystem is not supported by this "
|
|
|
|
"QEMU binary"));
|
2011-12-21 15:51:29 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&opt) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&opt);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&opt);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-18 15:06:14 +00:00
|
|
|
static char *
|
|
|
|
qemuBuildFSDevStr(const virDomainDef *def,
|
2013-08-02 17:48:50 +00:00
|
|
|
virDomainFSDefPtr fs,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
if (fs->type != VIR_DOMAIN_FS_TYPE_MOUNT) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("can only passthrough directories"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2015-07-07 15:30:41 +00:00
|
|
|
if (fs->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)
|
|
|
|
virBufferAddLit(&opt, "virtio-9p-ccw");
|
|
|
|
else
|
|
|
|
virBufferAddLit(&opt, "virtio-9p-pci");
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&opt, ",id=%s", fs->info.alias);
|
2016-02-18 15:06:14 +00:00
|
|
|
virBufferAsprintf(&opt, ",fsdev=%s%s",
|
|
|
|
QEMU_FSDEV_HOST_PREFIX, fs->info.alias);
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&opt, ",mount_tag=%s", fs->dst);
|
2011-09-16 15:51:20 +00:00
|
|
|
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&opt, def, &fs->info, qemuCaps) < 0)
|
2011-09-16 15:51:20 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&opt) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&opt);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&opt);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-18 15:06:14 +00:00
|
|
|
static int
|
|
|
|
qemuBuildFSDevCommandLine(virCommandPtr cmd,
|
|
|
|
const virDomainDef *def,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_FSDEV) && def->nfss) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("filesystem passthrough not supported by this QEMU"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < def->nfss; i++) {
|
|
|
|
char *optstr;
|
|
|
|
virDomainFSDefPtr fs = def->fss[i];
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-fsdev");
|
|
|
|
if (!(optstr = qemuBuildFSStr(fs, qemuCaps)))
|
|
|
|
return -1;
|
|
|
|
virCommandAddArg(cmd, optstr);
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
if (!(optstr = qemuBuildFSDevStr(def, fs, qemuCaps)))
|
|
|
|
return -1;
|
|
|
|
virCommandAddArg(cmd, optstr);
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-02 13:21:23 +00:00
|
|
|
static int
|
|
|
|
qemuControllerModelUSBToCaps(int model)
|
|
|
|
{
|
|
|
|
switch (model) {
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI:
|
|
|
|
return QEMU_CAPS_PIIX3_USB_UHCI;
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX4_UHCI:
|
|
|
|
return QEMU_CAPS_PIIX4_USB_UHCI;
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_EHCI:
|
|
|
|
return QEMU_CAPS_USB_EHCI;
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1:
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1:
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2:
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3:
|
|
|
|
return QEMU_CAPS_ICH9_USB_EHCI1;
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_VT82C686B_UHCI:
|
|
|
|
return QEMU_CAPS_VT82C686B_USB_UHCI;
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI:
|
|
|
|
return QEMU_CAPS_PCI_OHCI;
|
2012-06-21 13:45:25 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_NEC_XHCI:
|
|
|
|
return QEMU_CAPS_NEC_USB_XHCI;
|
2011-09-02 13:21:23 +00:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2016-02-18 13:33:39 +00:00
|
|
|
qemuBuildUSBControllerDevStr(const virDomainDef *domainDef,
|
2012-06-19 10:21:47 +00:00
|
|
|
virDomainControllerDefPtr def,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps,
|
2011-09-02 13:21:23 +00:00
|
|
|
virBuffer *buf)
|
|
|
|
{
|
|
|
|
const char *smodel;
|
2012-08-20 16:44:14 +00:00
|
|
|
int model, flags;
|
2011-09-02 13:21:23 +00:00
|
|
|
|
|
|
|
model = def->model;
|
qemu: Build command line for the new address format
For any disk controller model which is not "lsilogic", the command
line will be like:
-drive file=/dev/sda,if=none,id=drive-scsi0-0-3-0,format=raw \
-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=3,lun=0,i\
drive=drive-scsi0-0-3-0,id=scsi0-0-3-0
The relationship between the libvirt address attrs and the qdev
properties are (controller model is not "lsilogic"; strings
inside <> represent libvirt adress attrs):
bus=scsi<controller>.0
channel=<bus>
scsi-id=<target>
lun=<unit>
* src/qemu/qemu_command.h: (New param "virDomainDefPtr def"
for function qemuBuildDriveDevStr; new param "virDomainDefPtr
vmdef" for function qemuAssignDeviceDiskAlias. Both for
virDomainDiskFindControllerModel's use).
* src/qemu/qemu_command.c:
- New param "virDomainDefPtr def" for qemuAssignDeviceDiskAliasCustom.
For virDomainDiskFindControllerModel's use, if the disk bus is "scsi"
and the controller model is not "lsilogic", "target" is one part of
the alias name.
- According change on qemuAssignDeviceDiskAlias and qemuBuildDriveDevStr
* src/qemu/qemu_hotplug.c:
- Changes to be consistent with declarations of qemuAssignDeviceDiskAlias
qemuBuildDriveDevStr, and qemuBuildControllerDevStr.
* tests/qemuxml2argvdata/qemuxml2argv-pseries-vio-user-assigned.args,
tests/qemuxml2argvdata/qemuxml2argv-pseries-vio.args: Update the
generated command line.
2012-02-28 03:39:43 +00:00
|
|
|
|
2012-06-19 10:21:47 +00:00
|
|
|
if (model == -1) {
|
2014-11-04 17:21:26 +00:00
|
|
|
if ARCH_IS_PPC64(domainDef->os.arch)
|
2012-06-19 10:21:47 +00:00
|
|
|
model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PCI_OHCI;
|
|
|
|
else
|
|
|
|
model = VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI;
|
|
|
|
}
|
2011-09-02 13:21:23 +00:00
|
|
|
|
|
|
|
smodel = qemuControllerModelUSBTypeToString(model);
|
2012-08-20 16:44:14 +00:00
|
|
|
flags = qemuControllerModelUSBToCaps(model);
|
2011-09-02 13:21:23 +00:00
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (flags == -1 || !virQEMUCapsGet(qemuCaps, flags)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("%s not supported in this QEMU binary"), smodel);
|
2011-09-02 13:21:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-09-02 14:03:51 +00:00
|
|
|
virBufferAsprintf(buf, "%s", smodel);
|
|
|
|
|
2015-04-30 17:19:10 +00:00
|
|
|
if (def->info.mastertype == VIR_DOMAIN_CONTROLLER_MASTER_USB)
|
|
|
|
virBufferAsprintf(buf, ",masterbus=%s.0,firstport=%d",
|
|
|
|
def->info.alias, def->info.master.usb.startport);
|
|
|
|
else
|
|
|
|
virBufferAsprintf(buf, ",id=%s", def->info.alias);
|
2011-09-02 14:03:51 +00:00
|
|
|
|
2011-09-02 13:21:23 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
char *
|
2016-02-18 13:33:39 +00:00
|
|
|
qemuBuildControllerDevStr(const virDomainDef *domainDef,
|
2011-12-08 06:41:24 +00:00
|
|
|
virDomainControllerDefPtr def,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps,
|
2011-09-02 13:21:23 +00:00
|
|
|
int *nusbcontroller)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2015-02-18 14:11:31 +00:00
|
|
|
int model = def->model;
|
2015-06-25 19:37:33 +00:00
|
|
|
const char *modelName = NULL;
|
2015-02-18 14:11:31 +00:00
|
|
|
|
2015-08-31 15:06:42 +00:00
|
|
|
if (!qemuCheckCCWS390AddressSupport(domainDef, def->info, qemuCaps,
|
|
|
|
"controller"))
|
|
|
|
return NULL;
|
|
|
|
|
2015-02-18 14:11:31 +00:00
|
|
|
if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
|
2016-02-15 18:08:02 +00:00
|
|
|
if ((qemuDomainSetSCSIControllerModel(domainDef, qemuCaps, &model)) < 0)
|
2015-02-18 14:11:31 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2014-05-22 18:22:52 +00:00
|
|
|
if (!(def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
|
2015-02-18 14:11:31 +00:00
|
|
|
model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI)) {
|
2014-05-22 18:22:52 +00:00
|
|
|
if (def->queues) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("'queues' is only supported by virtio-scsi controller"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (def->cmd_per_lun) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("'cmd_per_lun' is only supported by virtio-scsi controller"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (def->max_sectors) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("'max_sectors' is only supported by virtio-scsi controller"));
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-07-26 18:41:34 +00:00
|
|
|
if (def->ioeventfd) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("'ioeventfd' is only supported by virtio-scsi controller"));
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-04-05 16:21:23 +00:00
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
|
2012-02-27 09:08:23 +00:00
|
|
|
switch (model) {
|
2012-02-27 09:16:20 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI:
|
2013-03-14 18:32:25 +00:00
|
|
|
if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)
|
|
|
|
virBufferAddLit(&buf, "virtio-scsi-ccw");
|
|
|
|
else if (def->info.type ==
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390)
|
|
|
|
virBufferAddLit(&buf, "virtio-scsi-s390");
|
2013-08-01 01:40:35 +00:00
|
|
|
else if (def->info.type ==
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO)
|
|
|
|
virBufferAddLit(&buf, "virtio-scsi-device");
|
2013-03-14 18:32:25 +00:00
|
|
|
else
|
|
|
|
virBufferAddLit(&buf, "virtio-scsi-pci");
|
2012-02-27 09:16:20 +00:00
|
|
|
break;
|
2012-02-27 09:08:23 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC:
|
2012-02-13 13:37:03 +00:00
|
|
|
virBufferAddLit(&buf, "lsi");
|
2012-02-27 09:08:23 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI:
|
|
|
|
virBufferAddLit(&buf, "spapr-vscsi");
|
|
|
|
break;
|
2016-02-11 10:48:20 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068:
|
|
|
|
virBufferAddLit(&buf, "mptsas1068");
|
|
|
|
break;
|
2013-03-21 14:11:39 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1078:
|
|
|
|
virBufferAddLit(&buf, "megasas");
|
|
|
|
break;
|
2012-02-27 09:08:23 +00:00
|
|
|
default:
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unsupported controller model: %s"),
|
|
|
|
virDomainControllerModelSCSITypeToString(def->model));
|
2011-12-08 06:41:24 +00:00
|
|
|
}
|
2015-04-30 17:19:10 +00:00
|
|
|
virBufferAsprintf(&buf, ",id=%s", def->info.alias);
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
|
|
|
|
if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
|
|
|
virBufferAddLit(&buf, "virtio-serial-pci");
|
2013-03-05 15:44:21 +00:00
|
|
|
} else if (def->info.type ==
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
|
|
|
|
virBufferAddLit(&buf, "virtio-serial-ccw");
|
2012-06-29 15:02:05 +00:00
|
|
|
} else if (def->info.type ==
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
|
|
|
|
virBufferAddLit(&buf, "virtio-serial-s390");
|
2013-08-01 01:40:35 +00:00
|
|
|
} else if (def->info.type ==
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO) {
|
|
|
|
virBufferAddLit(&buf, "virtio-serial-device");
|
2010-12-16 15:07:07 +00:00
|
|
|
} else {
|
|
|
|
virBufferAddLit(&buf, "virtio-serial");
|
|
|
|
}
|
2015-04-30 17:19:10 +00:00
|
|
|
virBufferAsprintf(&buf, ",id=%s", def->info.alias);
|
2010-12-16 15:07:07 +00:00
|
|
|
if (def->opts.vioserial.ports != -1) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",max_ports=%d",
|
2010-12-16 15:07:07 +00:00
|
|
|
def->opts.vioserial.ports);
|
|
|
|
}
|
|
|
|
if (def->opts.vioserial.vectors != -1) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",vectors=%d",
|
2010-12-16 15:07:07 +00:00
|
|
|
def->opts.vioserial.vectors);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2011-01-13 00:09:45 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_CCID:
|
2015-04-30 17:19:10 +00:00
|
|
|
virBufferAsprintf(&buf, "usb-ccid,id=%s", def->info.alias);
|
2011-01-13 00:09:45 +00:00
|
|
|
break;
|
|
|
|
|
2011-09-28 03:46:08 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_SATA:
|
2015-05-14 15:10:22 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_ICH9_AHCI)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("SATA is not supported with this "
|
|
|
|
"QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
2015-04-30 17:19:10 +00:00
|
|
|
virBufferAsprintf(&buf, "ahci,id=%s", def->info.alias);
|
2011-09-28 03:46:08 +00:00
|
|
|
break;
|
|
|
|
|
2011-09-02 13:21:23 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_USB:
|
2013-02-01 13:48:58 +00:00
|
|
|
if (qemuBuildUSBControllerDevStr(domainDef, def, qemuCaps, &buf) == -1)
|
2011-09-02 13:21:23 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (nusbcontroller)
|
|
|
|
*nusbcontroller += 1;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2013-03-07 11:03:41 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
|
2015-06-16 19:22:57 +00:00
|
|
|
if (def->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT ||
|
|
|
|
def->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("wrong function called for pci-root/pcie-root"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (def->idx == 0) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("index for pci controllers of model '%s' must be > 0"),
|
|
|
|
virDomainControllerModelPCITypeToString(def->model));
|
|
|
|
goto error;
|
|
|
|
}
|
2013-03-07 11:03:41 +00:00
|
|
|
switch (def->model) {
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
|
2015-06-25 19:37:33 +00:00
|
|
|
if (def->opts.pciopts.modelName
|
2015-07-15 19:16:14 +00:00
|
|
|
== VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE ||
|
|
|
|
def->opts.pciopts.chassisNr == -1) {
|
2015-06-25 19:37:33 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("autogenerated pci-bridge options not set"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
modelName = virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
|
|
|
|
if (!modelName) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown pci-bridge model name value %d"),
|
|
|
|
def->opts.pciopts.modelName);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (def->opts.pciopts.modelName
|
|
|
|
!= VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCI_BRIDGE) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("PCI controller model name '%s' "
|
|
|
|
"is not valid for a pci-bridge"),
|
|
|
|
modelName);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PCI_BRIDGE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("the pci-bridge controller "
|
|
|
|
"is not supported in this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAsprintf(&buf, "%s,chassis_nr=%d,id=%s",
|
2015-07-15 19:16:14 +00:00
|
|
|
modelName, def->opts.pciopts.chassisNr,
|
|
|
|
def->info.alias);
|
2013-03-07 11:03:41 +00:00
|
|
|
break;
|
qemu: add dmi-to-pci-bridge controller
This PCI controller, named "dmi-to-pci-bridge" in the libvirt config,
and implemented with qemu's "i82801b11-bridge" device, connects to a
PCI Express slot (e.g. one of the slots provided by the pcie-root
controller, aka "pcie.0" on the qemu commandline), and provides 31
*non-hot-pluggable* PCI (*not* PCIe) slots, numbered 1-31.
Any time a machine is defined which has a pcie-root controller
(i.e. any q35-based machinetype), libvirt will automatically add a
dmi-to-pci-bridge controller if one doesn't exist, and also add a
pci-bridge controller. The reasoning here is that any useful domain
will have either an immediate (startup time) or eventual (subsequent
hot-plug) need for a standard PCI slot; since the pcie-root controller
only provides PCIe slots, we need to connect a dmi-to-pci-bridge
controller to it in order to get a non-hot-plug PCI slot that we can
then use to connect a pci-bridge - the slots provided by the
pci-bridge will be both standard PCI and hot-pluggable.
Since pci-bridge devices themselves can not be hot-plugged into a
running system (although you can hot-plug other devices into a
pci-bridge's slots), any new pci-bridge controller that is added can
(and will) be plugged into the dmi-to-pci-bridge as long as it has
empty slots available.
This patch is also changing the qemuxml2xml-pcie test from a "DO_TEST"
to a "DO_DIFFERENT_TEST". This is so that the "before" xml can omit
the automatically added dmi-to-pci-bridge and pci-bridge devices, and
the "after" xml can include it - this way we are testing if libvirt is
properly adding these devices.
2013-07-31 01:37:32 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
|
2015-06-25 19:37:33 +00:00
|
|
|
if (def->opts.pciopts.modelName
|
|
|
|
== VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("autogenerated dmi-to-pci-bridge options not set"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
modelName = virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
|
|
|
|
if (!modelName) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown dmi-to-pci-bridge model name value %d"),
|
|
|
|
def->opts.pciopts.modelName);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (def->opts.pciopts.modelName
|
|
|
|
!= VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_I82801B11_BRIDGE) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("PCI controller model name '%s' "
|
|
|
|
"is not valid for a dmi-to-pci-bridge"),
|
|
|
|
modelName);
|
|
|
|
goto error;
|
|
|
|
}
|
qemu: add dmi-to-pci-bridge controller
This PCI controller, named "dmi-to-pci-bridge" in the libvirt config,
and implemented with qemu's "i82801b11-bridge" device, connects to a
PCI Express slot (e.g. one of the slots provided by the pcie-root
controller, aka "pcie.0" on the qemu commandline), and provides 31
*non-hot-pluggable* PCI (*not* PCIe) slots, numbered 1-31.
Any time a machine is defined which has a pcie-root controller
(i.e. any q35-based machinetype), libvirt will automatically add a
dmi-to-pci-bridge controller if one doesn't exist, and also add a
pci-bridge controller. The reasoning here is that any useful domain
will have either an immediate (startup time) or eventual (subsequent
hot-plug) need for a standard PCI slot; since the pcie-root controller
only provides PCIe slots, we need to connect a dmi-to-pci-bridge
controller to it in order to get a non-hot-plug PCI slot that we can
then use to connect a pci-bridge - the slots provided by the
pci-bridge will be both standard PCI and hot-pluggable.
Since pci-bridge devices themselves can not be hot-plugged into a
running system (although you can hot-plug other devices into a
pci-bridge's slots), any new pci-bridge controller that is added can
(and will) be plugged into the dmi-to-pci-bridge as long as it has
empty slots available.
This patch is also changing the qemuxml2xml-pcie test from a "DO_TEST"
to a "DO_DIFFERENT_TEST". This is so that the "before" xml can omit
the automatically added dmi-to-pci-bridge and pci-bridge devices, and
the "after" xml can include it - this way we are testing if libvirt is
properly adding these devices.
2013-07-31 01:37:32 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2015-06-25 19:37:33 +00:00
|
|
|
_("the dmi-to-pci-bridge (i82801b11-bridge) "
|
qemu: add dmi-to-pci-bridge controller
This PCI controller, named "dmi-to-pci-bridge" in the libvirt config,
and implemented with qemu's "i82801b11-bridge" device, connects to a
PCI Express slot (e.g. one of the slots provided by the pcie-root
controller, aka "pcie.0" on the qemu commandline), and provides 31
*non-hot-pluggable* PCI (*not* PCIe) slots, numbered 1-31.
Any time a machine is defined which has a pcie-root controller
(i.e. any q35-based machinetype), libvirt will automatically add a
dmi-to-pci-bridge controller if one doesn't exist, and also add a
pci-bridge controller. The reasoning here is that any useful domain
will have either an immediate (startup time) or eventual (subsequent
hot-plug) need for a standard PCI slot; since the pcie-root controller
only provides PCIe slots, we need to connect a dmi-to-pci-bridge
controller to it in order to get a non-hot-plug PCI slot that we can
then use to connect a pci-bridge - the slots provided by the
pci-bridge will be both standard PCI and hot-pluggable.
Since pci-bridge devices themselves can not be hot-plugged into a
running system (although you can hot-plug other devices into a
pci-bridge's slots), any new pci-bridge controller that is added can
(and will) be plugged into the dmi-to-pci-bridge as long as it has
empty slots available.
This patch is also changing the qemuxml2xml-pcie test from a "DO_TEST"
to a "DO_DIFFERENT_TEST". This is so that the "before" xml can omit
the automatically added dmi-to-pci-bridge and pci-bridge devices, and
the "after" xml can include it - this way we are testing if libvirt is
properly adding these devices.
2013-07-31 01:37:32 +00:00
|
|
|
"controller is not supported in this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
2015-06-25 19:37:33 +00:00
|
|
|
virBufferAsprintf(&buf, "%s,id=%s", modelName, def->info.alias);
|
qemu: add dmi-to-pci-bridge controller
This PCI controller, named "dmi-to-pci-bridge" in the libvirt config,
and implemented with qemu's "i82801b11-bridge" device, connects to a
PCI Express slot (e.g. one of the slots provided by the pcie-root
controller, aka "pcie.0" on the qemu commandline), and provides 31
*non-hot-pluggable* PCI (*not* PCIe) slots, numbered 1-31.
Any time a machine is defined which has a pcie-root controller
(i.e. any q35-based machinetype), libvirt will automatically add a
dmi-to-pci-bridge controller if one doesn't exist, and also add a
pci-bridge controller. The reasoning here is that any useful domain
will have either an immediate (startup time) or eventual (subsequent
hot-plug) need for a standard PCI slot; since the pcie-root controller
only provides PCIe slots, we need to connect a dmi-to-pci-bridge
controller to it in order to get a non-hot-plug PCI slot that we can
then use to connect a pci-bridge - the slots provided by the
pci-bridge will be both standard PCI and hot-pluggable.
Since pci-bridge devices themselves can not be hot-plugged into a
running system (although you can hot-plug other devices into a
pci-bridge's slots), any new pci-bridge controller that is added can
(and will) be plugged into the dmi-to-pci-bridge as long as it has
empty slots available.
This patch is also changing the qemuxml2xml-pcie test from a "DO_TEST"
to a "DO_DIFFERENT_TEST". This is so that the "before" xml can omit
the automatically added dmi-to-pci-bridge and pci-bridge devices, and
the "after" xml can include it - this way we are testing if libvirt is
properly adding these devices.
2013-07-31 01:37:32 +00:00
|
|
|
break;
|
2015-06-17 17:27:57 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
|
|
|
|
if (def->opts.pciopts.modelName
|
|
|
|
== VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("autogenerated pcie-root-port options not set"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
modelName = virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
|
|
|
|
if (!modelName) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown pcie-root-port model name value %d"),
|
|
|
|
def->opts.pciopts.modelName);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (def->opts.pciopts.modelName
|
|
|
|
!= VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_IOH3420) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("PCI controller model name '%s' "
|
|
|
|
"is not valid for a pcie-root-port"),
|
|
|
|
modelName);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_IOH3420)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("the pcie-root-port (ioh3420) "
|
|
|
|
"controller is not supported in this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, "%s,port=0x%x,chassis=%d,id=%s",
|
|
|
|
modelName, def->opts.pciopts.port,
|
|
|
|
def->opts.pciopts.chassis, def->info.alias);
|
|
|
|
break;
|
2015-06-16 19:09:07 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
|
|
|
|
if (def->opts.pciopts.modelName
|
|
|
|
== VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("autogenerated pcie-switch-upstream-port options not set"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
modelName = virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
|
|
|
|
if (!modelName) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown pcie-switch-upstream-port model name value %d"),
|
|
|
|
def->opts.pciopts.modelName);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (def->opts.pciopts.modelName
|
|
|
|
!= VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_X3130_UPSTREAM) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("PCI controller model name '%s' "
|
|
|
|
"is not valid for a pcie-switch-upstream-port"),
|
|
|
|
modelName);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_X3130_UPSTREAM)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("the pcie-switch-upstream-port (x3130-upstream) "
|
|
|
|
"controller is not supported in this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, "%s,id=%s", modelName, def->info.alias);
|
|
|
|
break;
|
2015-06-17 21:48:28 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
|
|
|
|
if (def->opts.pciopts.modelName
|
|
|
|
== VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE ||
|
|
|
|
def->opts.pciopts.chassis == -1 ||
|
|
|
|
def->opts.pciopts.port == -1) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("autogenerated pcie-switch-downstream-port "
|
|
|
|
"options not set"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
modelName = virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
|
|
|
|
if (!modelName) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown pcie-switch-downstream-port model name value %d"),
|
|
|
|
def->opts.pciopts.modelName);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (def->opts.pciopts.modelName
|
|
|
|
!= VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_XIO3130_DOWNSTREAM) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("PCI controller model name '%s' "
|
|
|
|
"is not valid for a pcie-switch-downstream-port"),
|
|
|
|
modelName);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_XIO3130_DOWNSTREAM)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("The pcie-switch-downstream-port "
|
|
|
|
"(xio3130-downstream) controller "
|
|
|
|
"is not supported in this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAsprintf(&buf, "%s,port=0x%x,chassis=%d,id=%s",
|
|
|
|
modelName, def->opts.pciopts.port,
|
|
|
|
def->opts.pciopts.chassis, def->info.alias);
|
|
|
|
break;
|
2013-03-07 11:03:41 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
|
2015-11-21 18:58:56 +00:00
|
|
|
/* Since we currently only support the integrated IDE
|
|
|
|
* controller on various boards, if we ever get to here, it's
|
|
|
|
* because some other machinetype had an IDE controller
|
|
|
|
* specified, or one with a single IDE contraller had multiple
|
|
|
|
* ide controllers specified.
|
qemu: log error when domain has an unsupported IDE controller
We have previously effectively ignored all <controller type='ide'>
elements in a domain definition.
On the i440fx-based machinetypes there is an IDE controller that is
included in the chipset and can't be removed (which is the ide
controller with index='0'>), so it makes sense to ignore that one
controller. However, if an i440fx domain definition has a 2nd
controller, nothing catches this error (unless you also have a disk
attached to it, in which case qemu will complain that you're trying to
use the ide controller named "ide1", which doesn't exist), and if any
other type of domain has even a single controller defined, it will be
incorrectly ignored.
Ignoring a bogus controller definition isn't such a big problem, as
long as an error is logged when any disk is attached to that
non-existent controller. But in the case of q35-based machinetypes,
the hardcoded id ("alias" in libvirt terms) of its builtin SATA
controller is "ide", which happens to be the same id as the builtin
IDE controller on i440fx machinetypes. So libvirt creates a
commandline believing that it is connecting the disk to the builtin
(but actually nonexistent) IDE controller, qemu thinks that libvirt
wanted that disk connected to the builtin SATA controller, and
everybody is happy.
Until you try to connect a 2nd disk to the IDE controller. Then qemu
will complain that you're trying to set unit=1 on a controller that
requires unit=0 (SATA controllers are organized differently than IDE
controllers).
After this patch, if a domain has an IDE controller defined for a
machinetype that has no IDE controllers, libvirt will log an error
about the controller itself as it is building the qemu commandline
(rather than a (possible) error from qemu about disks attached to that
controller). This is done by adding IDE to the list of controller
types that are handled in the loop that creates controller command
strings in qemuBuildCommandline() (previously it would *always* skip
IDE controllers). Then qemuBuildControllerDevStr() is modified to log
an appropriate error in the case of IDE controllers.
In the future, if we add support for extra IDE controllers (piix3-ide
and/or piix4-ide) we can just add it into the IDE case in
qemuBuildControllerDevStr(). For now, nobody seems anxious to add
extra support for an aging and very slow controller, when there are so
many better options available.
Resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=1176071 (Fedora)
2015-04-30 20:59:04 +00:00
|
|
|
*/
|
2015-11-21 18:58:56 +00:00
|
|
|
if (qemuDomainMachineHasBuiltinIDE(domainDef))
|
qemu: log error when domain has an unsupported IDE controller
We have previously effectively ignored all <controller type='ide'>
elements in a domain definition.
On the i440fx-based machinetypes there is an IDE controller that is
included in the chipset and can't be removed (which is the ide
controller with index='0'>), so it makes sense to ignore that one
controller. However, if an i440fx domain definition has a 2nd
controller, nothing catches this error (unless you also have a disk
attached to it, in which case qemu will complain that you're trying to
use the ide controller named "ide1", which doesn't exist), and if any
other type of domain has even a single controller defined, it will be
incorrectly ignored.
Ignoring a bogus controller definition isn't such a big problem, as
long as an error is logged when any disk is attached to that
non-existent controller. But in the case of q35-based machinetypes,
the hardcoded id ("alias" in libvirt terms) of its builtin SATA
controller is "ide", which happens to be the same id as the builtin
IDE controller on i440fx machinetypes. So libvirt creates a
commandline believing that it is connecting the disk to the builtin
(but actually nonexistent) IDE controller, qemu thinks that libvirt
wanted that disk connected to the builtin SATA controller, and
everybody is happy.
Until you try to connect a 2nd disk to the IDE controller. Then qemu
will complain that you're trying to set unit=1 on a controller that
requires unit=0 (SATA controllers are organized differently than IDE
controllers).
After this patch, if a domain has an IDE controller defined for a
machinetype that has no IDE controllers, libvirt will log an error
about the controller itself as it is building the qemu commandline
(rather than a (possible) error from qemu about disks attached to that
controller). This is done by adding IDE to the list of controller
types that are handled in the loop that creates controller command
strings in qemuBuildCommandline() (previously it would *always* skip
IDE controllers). Then qemuBuildControllerDevStr() is modified to log
an appropriate error in the case of IDE controllers.
In the future, if we add support for extra IDE controllers (piix3-ide
and/or piix4-ide) we can just add it into the IDE case in
qemuBuildControllerDevStr(). For now, nobody seems anxious to add
extra support for an aging and very slow controller, when there are so
many better options available.
Resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=1176071 (Fedora)
2015-04-30 20:59:04 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2015-11-21 18:58:56 +00:00
|
|
|
_("Only a single IDE controller is supported "
|
qemu: log error when domain has an unsupported IDE controller
We have previously effectively ignored all <controller type='ide'>
elements in a domain definition.
On the i440fx-based machinetypes there is an IDE controller that is
included in the chipset and can't be removed (which is the ide
controller with index='0'>), so it makes sense to ignore that one
controller. However, if an i440fx domain definition has a 2nd
controller, nothing catches this error (unless you also have a disk
attached to it, in which case qemu will complain that you're trying to
use the ide controller named "ide1", which doesn't exist), and if any
other type of domain has even a single controller defined, it will be
incorrectly ignored.
Ignoring a bogus controller definition isn't such a big problem, as
long as an error is logged when any disk is attached to that
non-existent controller. But in the case of q35-based machinetypes,
the hardcoded id ("alias" in libvirt terms) of its builtin SATA
controller is "ide", which happens to be the same id as the builtin
IDE controller on i440fx machinetypes. So libvirt creates a
commandline believing that it is connecting the disk to the builtin
(but actually nonexistent) IDE controller, qemu thinks that libvirt
wanted that disk connected to the builtin SATA controller, and
everybody is happy.
Until you try to connect a 2nd disk to the IDE controller. Then qemu
will complain that you're trying to set unit=1 on a controller that
requires unit=0 (SATA controllers are organized differently than IDE
controllers).
After this patch, if a domain has an IDE controller defined for a
machinetype that has no IDE controllers, libvirt will log an error
about the controller itself as it is building the qemu commandline
(rather than a (possible) error from qemu about disks attached to that
controller). This is done by adding IDE to the list of controller
types that are handled in the loop that creates controller command
strings in qemuBuildCommandline() (previously it would *always* skip
IDE controllers). Then qemuBuildControllerDevStr() is modified to log
an appropriate error in the case of IDE controllers.
In the future, if we add support for extra IDE controllers (piix3-ide
and/or piix4-ide) we can just add it into the IDE case in
qemuBuildControllerDevStr(). For now, nobody seems anxious to add
extra support for an aging and very slow controller, when there are so
many better options available.
Resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=1176071 (Fedora)
2015-04-30 20:59:04 +00:00
|
|
|
"for this machine type"));
|
|
|
|
else
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("IDE controllers are unsupported for "
|
|
|
|
"this QEMU binary or machine type"));
|
|
|
|
goto error;
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
default:
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
qemu: log error when domain has an unsupported IDE controller
We have previously effectively ignored all <controller type='ide'>
elements in a domain definition.
On the i440fx-based machinetypes there is an IDE controller that is
included in the chipset and can't be removed (which is the ide
controller with index='0'>), so it makes sense to ignore that one
controller. However, if an i440fx domain definition has a 2nd
controller, nothing catches this error (unless you also have a disk
attached to it, in which case qemu will complain that you're trying to
use the ide controller named "ide1", which doesn't exist), and if any
other type of domain has even a single controller defined, it will be
incorrectly ignored.
Ignoring a bogus controller definition isn't such a big problem, as
long as an error is logged when any disk is attached to that
non-existent controller. But in the case of q35-based machinetypes,
the hardcoded id ("alias" in libvirt terms) of its builtin SATA
controller is "ide", which happens to be the same id as the builtin
IDE controller on i440fx machinetypes. So libvirt creates a
commandline believing that it is connecting the disk to the builtin
(but actually nonexistent) IDE controller, qemu thinks that libvirt
wanted that disk connected to the builtin SATA controller, and
everybody is happy.
Until you try to connect a 2nd disk to the IDE controller. Then qemu
will complain that you're trying to set unit=1 on a controller that
requires unit=0 (SATA controllers are organized differently than IDE
controllers).
After this patch, if a domain has an IDE controller defined for a
machinetype that has no IDE controllers, libvirt will log an error
about the controller itself as it is building the qemu commandline
(rather than a (possible) error from qemu about disks attached to that
controller). This is done by adding IDE to the list of controller
types that are handled in the loop that creates controller command
strings in qemuBuildCommandline() (previously it would *always* skip
IDE controllers). Then qemuBuildControllerDevStr() is modified to log
an appropriate error in the case of IDE controllers.
In the future, if we add support for extra IDE controllers (piix3-ide
and/or piix4-ide) we can just add it into the IDE case in
qemuBuildControllerDevStr(). For now, nobody seems anxious to add
extra support for an aging and very slow controller, when there are so
many better options available.
Resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=1176071 (Fedora)
2015-04-30 20:59:04 +00:00
|
|
|
_("Unsupported controller type: %s"),
|
2012-07-18 15:22:03 +00:00
|
|
|
virDomainControllerTypeToString(def->type));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2013-04-24 09:24:13 +00:00
|
|
|
if (def->queues)
|
|
|
|
virBufferAsprintf(&buf, ",num_queues=%u", def->queues);
|
2013-04-05 16:21:23 +00:00
|
|
|
|
2014-05-22 18:22:52 +00:00
|
|
|
if (def->cmd_per_lun)
|
|
|
|
virBufferAsprintf(&buf, ",cmd_per_lun=%u", def->cmd_per_lun);
|
|
|
|
|
|
|
|
if (def->max_sectors)
|
|
|
|
virBufferAsprintf(&buf, ",max_sectors=%u", def->max_sectors);
|
|
|
|
|
2015-07-26 18:41:34 +00:00
|
|
|
qemuBuildIoEventFdStr(&buf, def->ioeventfd, qemuCaps);
|
|
|
|
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, domainDef, &def->info, qemuCaps) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-18 13:33:39 +00:00
|
|
|
static int
|
|
|
|
qemuBuildControllerDevCommandLine(virCommandPtr cmd,
|
|
|
|
const virDomainDef *def,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
size_t i, j;
|
|
|
|
int usbcontroller = 0;
|
|
|
|
bool usblegacy = false;
|
|
|
|
int contOrder[] = {
|
|
|
|
/*
|
|
|
|
* List of controller types that we add commandline args for,
|
|
|
|
* *in the order we want to add them*.
|
|
|
|
*
|
|
|
|
* The floppy controller is implicit on PIIX4 and older Q35
|
|
|
|
* machines. For newer Q35 machines it is added out of the
|
|
|
|
* controllers loop, after the floppy drives.
|
|
|
|
*
|
|
|
|
* We don't add PCI/PCIe root controller either, because it's
|
|
|
|
* implicit, but we do add PCI bridges and other PCI
|
|
|
|
* controllers, so we leave that in to check each
|
|
|
|
* one. Likewise, we don't do anything for the primary IDE
|
|
|
|
* controller on an i440fx machine or primary SATA on q35, but
|
|
|
|
* we do add those beyond these two exceptions.
|
|
|
|
*/
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_PCI,
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_USB,
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_IDE,
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_SATA,
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL,
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_CCID,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))
|
|
|
|
goto check_add_usb;
|
|
|
|
|
|
|
|
for (j = 0; j < ARRAY_CARDINALITY(contOrder); j++) {
|
|
|
|
for (i = 0; i < def->ncontrollers; i++) {
|
|
|
|
virDomainControllerDefPtr cont = def->controllers[i];
|
|
|
|
char *devstr;
|
|
|
|
|
|
|
|
if (cont->type != contOrder[j])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* skip USB controllers with type none.*/
|
|
|
|
if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB &&
|
|
|
|
cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE) {
|
|
|
|
usbcontroller = -1; /* mark we don't want a controller */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* skip pci-root/pcie-root */
|
|
|
|
if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI &&
|
|
|
|
(cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT ||
|
|
|
|
cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* first SATA controller on Q35 machines is implicit */
|
|
|
|
if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_SATA &&
|
|
|
|
cont->idx == 0 && qemuDomainMachineIsQ35(def))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* first IDE controller is implicit on various machines */
|
|
|
|
if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE &&
|
|
|
|
cont->idx == 0 && qemuDomainMachineHasBuiltinIDE(def))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB &&
|
|
|
|
cont->model == -1 &&
|
|
|
|
!qemuDomainMachineIsQ35(def)) {
|
|
|
|
bool need_legacy = false;
|
|
|
|
|
|
|
|
/* We're not using legacy usb controller for q35 */
|
|
|
|
if (ARCH_IS_PPC64(def->os.arch)) {
|
|
|
|
/* For ppc64 the legacy was OHCI */
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_OHCI))
|
|
|
|
need_legacy = true;
|
|
|
|
} else {
|
|
|
|
/* For anything else, we used PIIX3_USB_UHCI */
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PIIX3_USB_UHCI))
|
|
|
|
need_legacy = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (need_legacy) {
|
|
|
|
if (usblegacy) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Multiple legacy USB controllers are "
|
|
|
|
"not supported"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
usblegacy = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
if (!(devstr = qemuBuildControllerDevStr(def, cont, qemuCaps,
|
|
|
|
&usbcontroller)))
|
|
|
|
return -1;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
check_add_usb:
|
|
|
|
if (usbcontroller == 0 &&
|
|
|
|
!qemuDomainMachineIsQ35(def) &&
|
|
|
|
!ARCH_IS_S390(def->os.arch))
|
|
|
|
virCommandAddArg(cmd, "-usb");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-09 09:34:12 +00:00
|
|
|
/**
|
|
|
|
* qemuBuildMemoryBackendStr:
|
|
|
|
* @size: size of the memory device in kibibytes
|
|
|
|
* @pagesize: size of the requested memory page in KiB, 0 for default
|
2015-10-07 12:17:43 +00:00
|
|
|
* @guestNode: NUMA node in the guest that the memory object will be attached
|
|
|
|
* to, or -1 if NUMA is not used in the guest
|
2015-01-09 09:34:12 +00:00
|
|
|
* @hostNodes: map of host nodes to alloc the memory in, NULL for default
|
|
|
|
* @autoNodeset: fallback nodeset in case of automatic numa placement
|
|
|
|
* @def: domain definition object
|
|
|
|
* @qemuCaps: qemu capabilities object
|
|
|
|
* @cfg: qemu driver config object
|
|
|
|
* @aliasPrefix: prefix string of the alias (to allow for multiple frontents)
|
|
|
|
* @id: index of the device (to construct the alias)
|
|
|
|
* @backendStr: returns the object string
|
|
|
|
*
|
|
|
|
* Formats the configuration string for the memory device backend according
|
|
|
|
* to the configuration. @pagesize and @hostNodes can be used to override the
|
|
|
|
* default source configuration, both are optional.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, 1 if only the implicit memory-device-ram with no
|
|
|
|
* other configuration was used (to detect legacy configurations). Returns
|
|
|
|
* -1 in case of an error.
|
|
|
|
*/
|
2014-10-12 22:28:58 +00:00
|
|
|
int
|
2015-01-09 09:34:12 +00:00
|
|
|
qemuBuildMemoryBackendStr(unsigned long long size,
|
|
|
|
unsigned long long pagesize,
|
|
|
|
int guestNode,
|
|
|
|
virBitmapPtr userNodeset,
|
|
|
|
virBitmapPtr autoNodeset,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
virQEMUDriverConfigPtr cfg,
|
2015-01-15 21:42:51 +00:00
|
|
|
const char **backendType,
|
|
|
|
virJSONValuePtr *backendProps,
|
2015-01-09 09:34:12 +00:00
|
|
|
bool force)
|
|
|
|
{
|
|
|
|
virDomainHugePagePtr master_hugepage = NULL;
|
|
|
|
virDomainHugePagePtr hugepage = NULL;
|
|
|
|
virDomainNumatuneMemMode mode;
|
2015-02-02 10:26:49 +00:00
|
|
|
const long system_page_size = virGetSystemPageSizeKB();
|
2015-01-09 09:40:37 +00:00
|
|
|
virNumaMemAccess memAccess = VIR_NUMA_MEM_ACCESS_DEFAULT;
|
2015-01-09 09:34:12 +00:00
|
|
|
size_t i;
|
|
|
|
char *mem_path = NULL;
|
2015-01-15 21:42:51 +00:00
|
|
|
virBitmapPtr nodemask = NULL;
|
2015-01-09 09:34:12 +00:00
|
|
|
int ret = -1;
|
2015-01-15 21:42:51 +00:00
|
|
|
virJSONValuePtr props = NULL;
|
2015-10-01 05:23:38 +00:00
|
|
|
bool nodeSpecified = virDomainNumatuneNodeSpecified(def->numa, guestNode);
|
2015-01-09 09:34:12 +00:00
|
|
|
|
2015-01-15 21:42:51 +00:00
|
|
|
*backendProps = NULL;
|
|
|
|
*backendType = NULL;
|
|
|
|
|
2015-10-07 12:17:43 +00:00
|
|
|
if (guestNode >= 0) {
|
|
|
|
/* memory devices could provide a invalid guest node */
|
|
|
|
if (guestNode >= virDomainNumaGetNodeCount(def->numa)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("can't add memory backend for guest node '%d' as "
|
|
|
|
"the guest has only '%zu' NUMA nodes configured"),
|
|
|
|
guestNode, virDomainNumaGetNodeCount(def->numa));
|
|
|
|
return -1;
|
|
|
|
}
|
2015-01-09 09:40:37 +00:00
|
|
|
|
2015-10-07 12:17:43 +00:00
|
|
|
memAccess = virDomainNumaGetNodeMemoryAccessMode(def->numa, guestNode);
|
|
|
|
}
|
2015-01-09 09:34:12 +00:00
|
|
|
|
2015-05-19 09:55:26 +00:00
|
|
|
if (virDomainNumatuneGetMode(def->numa, guestNode, &mode) < 0 &&
|
|
|
|
virDomainNumatuneGetMode(def->numa, -1, &mode) < 0)
|
|
|
|
mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT;
|
2015-01-09 09:34:12 +00:00
|
|
|
|
qemuBuildMemoryBackendStr: Honour passed @pagesize
So far the argument has not much meaning and was practically ignored.
This is not good since when doing memory hotplug, the size of desired
hugepage backing is passed in that argument. Taking closer look at the
tests I'm fixing reveals the bug. For instance, while the following is
in the test:
<memory model='dimm'>
<source>
<nodemask>1-3</nodemask>
<pagesize unit='KiB'>4096</pagesize>
</source>
<target>
<size unit='KiB'>524287</size>
<node>0</node>
</target>
<address type='dimm' slot='0' base='0x100000000'/>
</memory>
the generated commandline corresponding to this XML was:
-object memory-backend-ram,id=memdimm0,size=536870912,\
host-nodes=1-3,policy=bind
Have you noticed? Yes, memory-backend-ram! Nothing can be further away
from the right answer. The hugepage backing is requested in the XML
and we happily ignore it. This is just not right. It's
memory-backend-file which should have been used:
-object memory-backend-file,id=memdimm0,prealloc=yes,\
mem-path=/dev/hugepages4M/libvirt/qemu,size=536870912,\
host-nodes=1-3,policy=bind
The problem is, that @pagesize passed to qemuBuildMemoryBackendStr
(where this part of commandline is built) was ignored. The hugepage to
back memory was searched only and only by NUMA nodes pinning. This
works only for regular guest NUMA nodes.
Then, I'm changing the hugepages size in the test XMLs too. This is
simply because in the test suite we create dummy mount points just for
2M and 1G hugepages. And in the test 4M was requested. I'm sticking to
2M, but 1G should just work too.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2015-06-25 15:27:29 +00:00
|
|
|
if (pagesize == 0) {
|
2015-01-09 09:34:12 +00:00
|
|
|
/* Find the huge page size we want to use */
|
|
|
|
for (i = 0; i < def->mem.nhugepages; i++) {
|
|
|
|
bool thisHugepage = false;
|
|
|
|
|
|
|
|
hugepage = &def->mem.hugepages[i];
|
|
|
|
|
|
|
|
if (!hugepage->nodemask) {
|
|
|
|
master_hugepage = hugepage;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-10-07 12:17:43 +00:00
|
|
|
/* just find the master hugepage in case we don't use NUMA */
|
|
|
|
if (guestNode < 0)
|
|
|
|
continue;
|
|
|
|
|
2015-01-09 09:34:12 +00:00
|
|
|
if (virBitmapGetBit(hugepage->nodemask, guestNode,
|
|
|
|
&thisHugepage) < 0) {
|
|
|
|
/* Ignore this error. It's not an error after all. Well,
|
|
|
|
* the nodemask for this <page/> can contain lower NUMA
|
|
|
|
* nodes than we are querying in here. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (thisHugepage) {
|
|
|
|
/* Hooray, we've found the page size */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == def->mem.nhugepages) {
|
|
|
|
/* We have not found specific huge page to be used with this
|
|
|
|
* NUMA node. Use the generic setting then (<page/> without any
|
|
|
|
* @nodemask) if possible. */
|
|
|
|
hugepage = master_hugepage;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hugepage)
|
|
|
|
pagesize = hugepage->size;
|
qemuBuildMemoryBackendStr: Honour passed @pagesize
So far the argument has not much meaning and was practically ignored.
This is not good since when doing memory hotplug, the size of desired
hugepage backing is passed in that argument. Taking closer look at the
tests I'm fixing reveals the bug. For instance, while the following is
in the test:
<memory model='dimm'>
<source>
<nodemask>1-3</nodemask>
<pagesize unit='KiB'>4096</pagesize>
</source>
<target>
<size unit='KiB'>524287</size>
<node>0</node>
</target>
<address type='dimm' slot='0' base='0x100000000'/>
</memory>
the generated commandline corresponding to this XML was:
-object memory-backend-ram,id=memdimm0,size=536870912,\
host-nodes=1-3,policy=bind
Have you noticed? Yes, memory-backend-ram! Nothing can be further away
from the right answer. The hugepage backing is requested in the XML
and we happily ignore it. This is just not right. It's
memory-backend-file which should have been used:
-object memory-backend-file,id=memdimm0,prealloc=yes,\
mem-path=/dev/hugepages4M/libvirt/qemu,size=536870912,\
host-nodes=1-3,policy=bind
The problem is, that @pagesize passed to qemuBuildMemoryBackendStr
(where this part of commandline is built) was ignored. The hugepage to
back memory was searched only and only by NUMA nodes pinning. This
works only for regular guest NUMA nodes.
Then, I'm changing the hugepages size in the test XMLs too. This is
simply because in the test suite we create dummy mount points just for
2M and 1G hugepages. And in the test 4M was requested. I'm sticking to
2M, but 1G should just work too.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2015-06-25 15:27:29 +00:00
|
|
|
}
|
2015-01-09 09:34:12 +00:00
|
|
|
|
qemuBuildMemoryBackendStr: Honour passed @pagesize
So far the argument has not much meaning and was practically ignored.
This is not good since when doing memory hotplug, the size of desired
hugepage backing is passed in that argument. Taking closer look at the
tests I'm fixing reveals the bug. For instance, while the following is
in the test:
<memory model='dimm'>
<source>
<nodemask>1-3</nodemask>
<pagesize unit='KiB'>4096</pagesize>
</source>
<target>
<size unit='KiB'>524287</size>
<node>0</node>
</target>
<address type='dimm' slot='0' base='0x100000000'/>
</memory>
the generated commandline corresponding to this XML was:
-object memory-backend-ram,id=memdimm0,size=536870912,\
host-nodes=1-3,policy=bind
Have you noticed? Yes, memory-backend-ram! Nothing can be further away
from the right answer. The hugepage backing is requested in the XML
and we happily ignore it. This is just not right. It's
memory-backend-file which should have been used:
-object memory-backend-file,id=memdimm0,prealloc=yes,\
mem-path=/dev/hugepages4M/libvirt/qemu,size=536870912,\
host-nodes=1-3,policy=bind
The problem is, that @pagesize passed to qemuBuildMemoryBackendStr
(where this part of commandline is built) was ignored. The hugepage to
back memory was searched only and only by NUMA nodes pinning. This
works only for regular guest NUMA nodes.
Then, I'm changing the hugepages size in the test XMLs too. This is
simply because in the test suite we create dummy mount points just for
2M and 1G hugepages. And in the test 4M was requested. I'm sticking to
2M, but 1G should just work too.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2015-06-25 15:27:29 +00:00
|
|
|
if (pagesize == system_page_size) {
|
|
|
|
/* However, if user specified to use "huge" page
|
|
|
|
* of regular system page size, it's as if they
|
|
|
|
* hasn't specified any huge pages at all. */
|
|
|
|
pagesize = 0;
|
|
|
|
hugepage = NULL;
|
2015-01-09 09:34:12 +00:00
|
|
|
}
|
|
|
|
|
2015-10-07 12:17:43 +00:00
|
|
|
if (!(props = virJSONValueNewObject()))
|
|
|
|
return -1;
|
|
|
|
|
qemuBuildMemoryBackendStr: Honour passed @pagesize
So far the argument has not much meaning and was practically ignored.
This is not good since when doing memory hotplug, the size of desired
hugepage backing is passed in that argument. Taking closer look at the
tests I'm fixing reveals the bug. For instance, while the following is
in the test:
<memory model='dimm'>
<source>
<nodemask>1-3</nodemask>
<pagesize unit='KiB'>4096</pagesize>
</source>
<target>
<size unit='KiB'>524287</size>
<node>0</node>
</target>
<address type='dimm' slot='0' base='0x100000000'/>
</memory>
the generated commandline corresponding to this XML was:
-object memory-backend-ram,id=memdimm0,size=536870912,\
host-nodes=1-3,policy=bind
Have you noticed? Yes, memory-backend-ram! Nothing can be further away
from the right answer. The hugepage backing is requested in the XML
and we happily ignore it. This is just not right. It's
memory-backend-file which should have been used:
-object memory-backend-file,id=memdimm0,prealloc=yes,\
mem-path=/dev/hugepages4M/libvirt/qemu,size=536870912,\
host-nodes=1-3,policy=bind
The problem is, that @pagesize passed to qemuBuildMemoryBackendStr
(where this part of commandline is built) was ignored. The hugepage to
back memory was searched only and only by NUMA nodes pinning. This
works only for regular guest NUMA nodes.
Then, I'm changing the hugepages size in the test XMLs too. This is
simply because in the test suite we create dummy mount points just for
2M and 1G hugepages. And in the test 4M was requested. I'm sticking to
2M, but 1G should just work too.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2015-06-25 15:27:29 +00:00
|
|
|
if (pagesize || hugepage) {
|
|
|
|
if (pagesize) {
|
2015-06-24 16:09:57 +00:00
|
|
|
/* Now lets see, if the huge page we want to use is even mounted
|
|
|
|
* and ready to use */
|
|
|
|
for (i = 0; i < cfg->nhugetlbfs; i++) {
|
qemuBuildMemoryBackendStr: Honour passed @pagesize
So far the argument has not much meaning and was practically ignored.
This is not good since when doing memory hotplug, the size of desired
hugepage backing is passed in that argument. Taking closer look at the
tests I'm fixing reveals the bug. For instance, while the following is
in the test:
<memory model='dimm'>
<source>
<nodemask>1-3</nodemask>
<pagesize unit='KiB'>4096</pagesize>
</source>
<target>
<size unit='KiB'>524287</size>
<node>0</node>
</target>
<address type='dimm' slot='0' base='0x100000000'/>
</memory>
the generated commandline corresponding to this XML was:
-object memory-backend-ram,id=memdimm0,size=536870912,\
host-nodes=1-3,policy=bind
Have you noticed? Yes, memory-backend-ram! Nothing can be further away
from the right answer. The hugepage backing is requested in the XML
and we happily ignore it. This is just not right. It's
memory-backend-file which should have been used:
-object memory-backend-file,id=memdimm0,prealloc=yes,\
mem-path=/dev/hugepages4M/libvirt/qemu,size=536870912,\
host-nodes=1-3,policy=bind
The problem is, that @pagesize passed to qemuBuildMemoryBackendStr
(where this part of commandline is built) was ignored. The hugepage to
back memory was searched only and only by NUMA nodes pinning. This
works only for regular guest NUMA nodes.
Then, I'm changing the hugepages size in the test XMLs too. This is
simply because in the test suite we create dummy mount points just for
2M and 1G hugepages. And in the test 4M was requested. I'm sticking to
2M, but 1G should just work too.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2015-06-25 15:27:29 +00:00
|
|
|
if (cfg->hugetlbfs[i].size == pagesize)
|
2015-06-24 16:09:57 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-01-09 09:34:12 +00:00
|
|
|
|
2015-06-24 16:09:57 +00:00
|
|
|
if (i == cfg->nhugetlbfs) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to find any usable hugetlbfs mount for %llu KiB"),
|
qemuBuildMemoryBackendStr: Honour passed @pagesize
So far the argument has not much meaning and was practically ignored.
This is not good since when doing memory hotplug, the size of desired
hugepage backing is passed in that argument. Taking closer look at the
tests I'm fixing reveals the bug. For instance, while the following is
in the test:
<memory model='dimm'>
<source>
<nodemask>1-3</nodemask>
<pagesize unit='KiB'>4096</pagesize>
</source>
<target>
<size unit='KiB'>524287</size>
<node>0</node>
</target>
<address type='dimm' slot='0' base='0x100000000'/>
</memory>
the generated commandline corresponding to this XML was:
-object memory-backend-ram,id=memdimm0,size=536870912,\
host-nodes=1-3,policy=bind
Have you noticed? Yes, memory-backend-ram! Nothing can be further away
from the right answer. The hugepage backing is requested in the XML
and we happily ignore it. This is just not right. It's
memory-backend-file which should have been used:
-object memory-backend-file,id=memdimm0,prealloc=yes,\
mem-path=/dev/hugepages4M/libvirt/qemu,size=536870912,\
host-nodes=1-3,policy=bind
The problem is, that @pagesize passed to qemuBuildMemoryBackendStr
(where this part of commandline is built) was ignored. The hugepage to
back memory was searched only and only by NUMA nodes pinning. This
works only for regular guest NUMA nodes.
Then, I'm changing the hugepages size in the test XMLs too. This is
simply because in the test suite we create dummy mount points just for
2M and 1G hugepages. And in the test 4M was requested. I'm sticking to
2M, but 1G should just work too.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2015-06-25 15:27:29 +00:00
|
|
|
pagesize);
|
2015-06-24 16:09:57 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2015-01-09 09:34:12 +00:00
|
|
|
|
2015-06-24 16:09:57 +00:00
|
|
|
if (!(mem_path = qemuGetHugepagePath(&cfg->hugetlbfs[i])))
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
if (!(mem_path = qemuGetDefaultHugepath(cfg->hugetlbfs,
|
|
|
|
cfg->nhugetlbfs)))
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2015-01-09 09:34:12 +00:00
|
|
|
|
2015-01-15 21:42:51 +00:00
|
|
|
*backendType = "memory-backend-file";
|
|
|
|
|
|
|
|
if (virJSONValueObjectAdd(props,
|
|
|
|
"b:prealloc", true,
|
|
|
|
"s:mem-path", mem_path,
|
|
|
|
NULL) < 0)
|
|
|
|
goto cleanup;
|
2015-01-09 09:34:12 +00:00
|
|
|
|
|
|
|
switch (memAccess) {
|
2015-02-11 14:40:27 +00:00
|
|
|
case VIR_NUMA_MEM_ACCESS_SHARED:
|
2015-01-15 21:42:51 +00:00
|
|
|
if (virJSONValueObjectAdd(props, "b:share", true, NULL) < 0)
|
|
|
|
goto cleanup;
|
2015-01-09 09:34:12 +00:00
|
|
|
break;
|
|
|
|
|
2015-02-11 14:40:27 +00:00
|
|
|
case VIR_NUMA_MEM_ACCESS_PRIVATE:
|
2015-01-15 21:42:51 +00:00
|
|
|
if (virJSONValueObjectAdd(props, "b:share", false, NULL) < 0)
|
|
|
|
goto cleanup;
|
2015-01-09 09:34:12 +00:00
|
|
|
break;
|
|
|
|
|
2015-02-11 14:40:27 +00:00
|
|
|
case VIR_NUMA_MEM_ACCESS_DEFAULT:
|
|
|
|
case VIR_NUMA_MEM_ACCESS_LAST:
|
2015-01-09 09:34:12 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (memAccess) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Shared memory mapping is supported "
|
|
|
|
"only with hugepages"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-01-15 21:42:51 +00:00
|
|
|
*backendType = "memory-backend-ram";
|
2015-01-09 09:34:12 +00:00
|
|
|
}
|
|
|
|
|
2015-01-15 21:42:51 +00:00
|
|
|
if (virJSONValueObjectAdd(props, "U:size", size * 1024, NULL) < 0)
|
|
|
|
goto cleanup;
|
2015-01-09 09:34:12 +00:00
|
|
|
|
|
|
|
if (userNodeset) {
|
2015-01-15 21:42:51 +00:00
|
|
|
nodemask = userNodeset;
|
2015-01-09 09:34:12 +00:00
|
|
|
} else {
|
2015-02-11 13:54:59 +00:00
|
|
|
if (virDomainNumatuneMaybeGetNodeset(def->numa, autoNodeset,
|
2015-01-15 21:42:51 +00:00
|
|
|
&nodemask, guestNode) < 0)
|
2015-01-09 09:34:12 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nodemask) {
|
2015-03-25 06:34:04 +00:00
|
|
|
if (!virNumaNodesetIsAvailable(nodemask))
|
|
|
|
goto cleanup;
|
2015-01-15 21:42:51 +00:00
|
|
|
if (virJSONValueObjectAdd(props,
|
|
|
|
"m:host-nodes", nodemask,
|
|
|
|
"S:policy", qemuNumaPolicyTypeToString(mode),
|
|
|
|
NULL) < 0)
|
2015-01-09 09:34:12 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-10-01 05:34:57 +00:00
|
|
|
/* If none of the following is requested... */
|
|
|
|
if (!pagesize && !userNodeset && !memAccess && !nodeSpecified && !force) {
|
|
|
|
/* report back that using the new backend is not necessary
|
|
|
|
* to achieve the desired configuration */
|
|
|
|
ret = 1;
|
|
|
|
} else {
|
|
|
|
/* otherwise check the required capability */
|
|
|
|
if (STREQ(*backendType, "memory-backend-file") &&
|
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("this qemu doesn't support the "
|
|
|
|
"memory-backend-file object"));
|
|
|
|
goto cleanup;
|
|
|
|
} else if (STREQ(*backendType, "memory-backend-ram") &&
|
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM)) {
|
2015-01-09 09:34:12 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("this qemu doesn't support the "
|
|
|
|
"memory-backend-ram object"));
|
2015-03-17 02:34:26 +00:00
|
|
|
goto cleanup;
|
2015-01-09 09:34:12 +00:00
|
|
|
}
|
|
|
|
|
2015-10-01 05:34:57 +00:00
|
|
|
ret = 0;
|
2015-01-09 09:34:12 +00:00
|
|
|
}
|
|
|
|
|
2015-03-23 13:17:42 +00:00
|
|
|
*backendProps = props;
|
|
|
|
props = NULL;
|
2015-01-09 09:34:12 +00:00
|
|
|
|
|
|
|
cleanup:
|
2015-01-15 21:42:51 +00:00
|
|
|
virJSONValueFree(props);
|
2015-01-09 09:34:12 +00:00
|
|
|
VIR_FREE(mem_path);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuBuildMemoryCellBackendStr(virDomainDefPtr def,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
virQEMUDriverConfigPtr cfg,
|
|
|
|
size_t cell,
|
|
|
|
virBitmapPtr auto_nodeset,
|
|
|
|
char **backendStr)
|
|
|
|
{
|
2015-01-15 21:42:51 +00:00
|
|
|
virJSONValuePtr props = NULL;
|
|
|
|
char *alias = NULL;
|
|
|
|
const char *backendType;
|
|
|
|
int ret = -1;
|
|
|
|
int rc;
|
2015-10-01 05:30:39 +00:00
|
|
|
unsigned long long memsize = virDomainNumaGetNodeMemorySize(def->numa,
|
|
|
|
cell);
|
2015-01-09 09:34:12 +00:00
|
|
|
|
2015-01-15 21:42:51 +00:00
|
|
|
*backendStr = NULL;
|
2015-01-09 09:34:12 +00:00
|
|
|
|
2015-01-15 21:42:51 +00:00
|
|
|
if (virAsprintf(&alias, "ram-node%zu", cell) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-10-01 05:30:39 +00:00
|
|
|
if ((rc = qemuBuildMemoryBackendStr(memsize, 0, cell, NULL, auto_nodeset,
|
|
|
|
def, qemuCaps, cfg, &backendType,
|
|
|
|
&props, false)) < 0)
|
2015-01-15 21:42:51 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!(*backendStr = qemuBuildObjectCommandlineFromJSON(backendType,
|
|
|
|
alias,
|
|
|
|
props)))
|
|
|
|
goto cleanup;
|
|
|
|
|
qemu: command: Don't combine old and modern NUMA node creation
Change done by commit f309db1f4d51009bad0d32e12efc75530b66836b wrongly
assumes that qemu can start with a combination of NUMA nodes specified
with the "memdev" option and the appropriate backends, and the legacy
way by specifying only "mem" as a size argument. QEMU rejects such
commandline though:
$ /usr/bin/qemu-system-x86_64 -S -M pc -m 1024 -smp 2 \
-numa node,nodeid=0,cpus=0,mem=256 \
-object memory-backend-ram,id=ram-node1,size=12345 \
-numa node,nodeid=1,cpus=1,memdev=ram-node1
qemu-system-x86_64: -numa node,nodeid=1,cpus=1,memdev=ram-node1: qemu: memdev option must be specified for either all or no nodes
To fix this issue we need to check if any of the nodes requires the new
definition with the backend and if so, then all other nodes have to use
it too.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1182467
2015-01-26 12:48:02 +00:00
|
|
|
ret = rc;
|
2015-01-15 21:42:51 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(alias);
|
|
|
|
virJSONValueFree(props);
|
|
|
|
|
2015-01-09 09:34:12 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-09 09:40:37 +00:00
|
|
|
static char *
|
|
|
|
qemuBuildMemoryDimmBackendStr(virDomainMemoryDefPtr mem,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
virQEMUDriverConfigPtr cfg)
|
|
|
|
{
|
|
|
|
virJSONValuePtr props = NULL;
|
|
|
|
char *alias = NULL;
|
|
|
|
const char *backendType;
|
|
|
|
char *ret = NULL;
|
|
|
|
|
|
|
|
if (!mem->info.alias) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("memory device alias is not assigned"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&alias, "mem%s", mem->info.alias) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (qemuBuildMemoryBackendStr(mem->size, mem->pagesize,
|
|
|
|
mem->targetNode, mem->sourceNodes, NULL,
|
|
|
|
def, qemuCaps, cfg,
|
|
|
|
&backendType, &props, true) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = qemuBuildObjectCommandlineFromJSON(backendType, alias, props);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(alias);
|
|
|
|
virJSONValueFree(props);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-10-12 22:28:58 +00:00
|
|
|
char *
|
2015-10-08 05:25:32 +00:00
|
|
|
qemuBuildMemoryDeviceStr(virDomainMemoryDefPtr mem)
|
2015-01-09 09:40:37 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
if (!mem->info.alias) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("missing alias for memory device"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ((virDomainMemoryModel) mem->model) {
|
|
|
|
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
|
2015-10-13 00:02:22 +00:00
|
|
|
virBufferAddLit(&buf, "pc-dimm,");
|
|
|
|
|
|
|
|
if (mem->targetNode >= 0)
|
|
|
|
virBufferAsprintf(&buf, "node=%d,", mem->targetNode);
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, "memdev=mem%s,id=%s",
|
|
|
|
mem->info.alias, mem->info.alias);
|
2015-01-09 09:40:37 +00:00
|
|
|
|
|
|
|
if (mem->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DIMM) {
|
|
|
|
virBufferAsprintf(&buf, ",slot=%d", mem->info.addr.dimm.slot);
|
2015-03-26 06:30:56 +00:00
|
|
|
virBufferAsprintf(&buf, ",addr=%llu", mem->info.addr.dimm.base);
|
2015-01-09 09:40:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_MEMORY_MODEL_NONE:
|
|
|
|
case VIR_DOMAIN_MEMORY_MODEL_LAST:
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("invalid memory device type"));
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferCheckError(&buf) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
char *
|
|
|
|
qemuBuildNicStr(virDomainNetDefPtr net,
|
|
|
|
const char *prefix,
|
|
|
|
int vlan)
|
|
|
|
{
|
|
|
|
char *str;
|
2013-03-26 11:21:33 +00:00
|
|
|
char macaddr[VIR_MAC_STRING_BUFLEN];
|
|
|
|
|
2013-07-04 10:14:12 +00:00
|
|
|
ignore_value(virAsprintf(&str,
|
|
|
|
"%smacaddr=%s,vlan=%d%s%s%s%s",
|
|
|
|
prefix ? prefix : "",
|
|
|
|
virMacAddrFormat(&net->mac, macaddr),
|
|
|
|
vlan,
|
|
|
|
(net->model ? ",model=" : ""),
|
|
|
|
(net->model ? net->model : ""),
|
|
|
|
(net->info.alias ? ",name=" : ""),
|
|
|
|
(net->info.alias ? net->info.alias : "")));
|
2010-12-16 15:07:07 +00:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
2013-08-02 17:48:50 +00:00
|
|
|
qemuBuildNicDevStr(virDomainDefPtr def,
|
|
|
|
virDomainNetDefPtr net,
|
2011-01-12 10:33:34 +00:00
|
|
|
int vlan,
|
2011-05-26 14:15:01 +00:00
|
|
|
int bootindex,
|
2014-11-12 15:42:02 +00:00
|
|
|
size_t vhostfdSize,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2013-04-05 09:48:20 +00:00
|
|
|
const char *nic = net->model;
|
Add txmode attribute to interface XML for virtio backend
This is in response to:
https://bugzilla.redhat.com/show_bug.cgi?id=629662
Explanation
qemu's virtio-net-pci driver allows setting the algorithm used for tx
packets to either "bh" or "timer". This is done by adding ",tx=bh" or
",tx=timer" to the "-device virtio-net-pci" commandline option.
'bh' stands for 'bottom half'; when this is set, packet tx is all done
in an iothread in the bottom half of the driver. (In libvirt, this
option is called the more descriptive "iothread".)
'timer' means that tx work is done in qemu, and if there is more tx
data than can be sent at the present time, a timer is set before qemu
moves on to do other things; when the timer fires, another attempt is
made to send more data. (libvirt retains the name "timer" for this
option.)
The resulting difference, according to the qemu developer who added
the option is:
bh makes tx more asynchronous and reduces latency, but potentially
causes more processor bandwidth contention since the cpu doing the
tx isn't necessarily the cpu where the guest generated the
packets.
Solution
This patch provides a libvirt domain xml knob to change the option on
the qemu commandline, by adding a new attribute "txmode" to the
<driver> element that can be placed inside any <interface> element in
a domain definition. It's use would be something like this:
<interface ...>
...
<model type='virtio'/>
<driver txmode='iothread'/>
...
</interface>
I chose to put this setting as an attribute to <driver> rather than as
a sub-element to <tune> because it is specific to the virtio-net
driver, not something that is generally usable by all network drivers.
(note that this is the same placement as the "driver name=..."
attribute used to choose kernel vs. userland backend for the
virtio-net driver.)
Actually adding the tx=xxx option to the qemu commandline is only done
if the version of qemu being used advertises it in the output of
qemu -device virtio-net-pci,?
If a particular txmode is requested in the XML, and the option isn't
listed in that help output, an UNSUPPORTED_CONFIG error is logged, and
the domain fails to start.
2011-02-03 20:20:01 +00:00
|
|
|
bool usingVirtio = false;
|
2013-03-26 11:21:33 +00:00
|
|
|
char macaddr[VIR_MAC_STRING_BUFLEN];
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2013-04-05 09:48:20 +00:00
|
|
|
if (STREQ(net->model, "virtio")) {
|
|
|
|
if (net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)
|
2013-03-05 15:44:21 +00:00
|
|
|
nic = "virtio-net-ccw";
|
2013-04-05 09:48:20 +00:00
|
|
|
else if (net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390)
|
2012-06-29 15:02:05 +00:00
|
|
|
nic = "virtio-net-s390";
|
2013-08-01 01:40:35 +00:00
|
|
|
else if (net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO)
|
|
|
|
nic = "virtio-net-device";
|
2013-04-05 09:48:20 +00:00
|
|
|
else
|
2012-06-29 15:02:05 +00:00
|
|
|
nic = "virtio-net-pci";
|
2013-04-05 09:48:20 +00:00
|
|
|
|
Add txmode attribute to interface XML for virtio backend
This is in response to:
https://bugzilla.redhat.com/show_bug.cgi?id=629662
Explanation
qemu's virtio-net-pci driver allows setting the algorithm used for tx
packets to either "bh" or "timer". This is done by adding ",tx=bh" or
",tx=timer" to the "-device virtio-net-pci" commandline option.
'bh' stands for 'bottom half'; when this is set, packet tx is all done
in an iothread in the bottom half of the driver. (In libvirt, this
option is called the more descriptive "iothread".)
'timer' means that tx work is done in qemu, and if there is more tx
data than can be sent at the present time, a timer is set before qemu
moves on to do other things; when the timer fires, another attempt is
made to send more data. (libvirt retains the name "timer" for this
option.)
The resulting difference, according to the qemu developer who added
the option is:
bh makes tx more asynchronous and reduces latency, but potentially
causes more processor bandwidth contention since the cpu doing the
tx isn't necessarily the cpu where the guest generated the
packets.
Solution
This patch provides a libvirt domain xml knob to change the option on
the qemu commandline, by adding a new attribute "txmode" to the
<driver> element that can be placed inside any <interface> element in
a domain definition. It's use would be something like this:
<interface ...>
...
<model type='virtio'/>
<driver txmode='iothread'/>
...
</interface>
I chose to put this setting as an attribute to <driver> rather than as
a sub-element to <tune> because it is specific to the virtio-net
driver, not something that is generally usable by all network drivers.
(note that this is the same placement as the "driver name=..."
attribute used to choose kernel vs. userland backend for the
virtio-net driver.)
Actually adding the tx=xxx option to the qemu commandline is only done
if the version of qemu being used advertises it in the output of
qemu -device virtio-net-pci,?
If a particular txmode is requested in the XML, and the option isn't
listed in that help output, an UNSUPPORTED_CONFIG error is logged, and
the domain fails to start.
2011-02-03 20:20:01 +00:00
|
|
|
usingVirtio = true;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2013-04-05 09:48:20 +00:00
|
|
|
virBufferAdd(&buf, nic, -1);
|
Add txmode attribute to interface XML for virtio backend
This is in response to:
https://bugzilla.redhat.com/show_bug.cgi?id=629662
Explanation
qemu's virtio-net-pci driver allows setting the algorithm used for tx
packets to either "bh" or "timer". This is done by adding ",tx=bh" or
",tx=timer" to the "-device virtio-net-pci" commandline option.
'bh' stands for 'bottom half'; when this is set, packet tx is all done
in an iothread in the bottom half of the driver. (In libvirt, this
option is called the more descriptive "iothread".)
'timer' means that tx work is done in qemu, and if there is more tx
data than can be sent at the present time, a timer is set before qemu
moves on to do other things; when the timer fires, another attempt is
made to send more data. (libvirt retains the name "timer" for this
option.)
The resulting difference, according to the qemu developer who added
the option is:
bh makes tx more asynchronous and reduces latency, but potentially
causes more processor bandwidth contention since the cpu doing the
tx isn't necessarily the cpu where the guest generated the
packets.
Solution
This patch provides a libvirt domain xml knob to change the option on
the qemu commandline, by adding a new attribute "txmode" to the
<driver> element that can be placed inside any <interface> element in
a domain definition. It's use would be something like this:
<interface ...>
...
<model type='virtio'/>
<driver txmode='iothread'/>
...
</interface>
I chose to put this setting as an attribute to <driver> rather than as
a sub-element to <tune> because it is specific to the virtio-net
driver, not something that is generally usable by all network drivers.
(note that this is the same placement as the "driver name=..."
attribute used to choose kernel vs. userland backend for the
virtio-net driver.)
Actually adding the tx=xxx option to the qemu commandline is only done
if the version of qemu being used advertises it in the output of
qemu -device virtio-net-pci,?
If a particular txmode is requested in the XML, and the option isn't
listed in that help output, an UNSUPPORTED_CONFIG error is logged, and
the domain fails to start.
2011-02-03 20:20:01 +00:00
|
|
|
if (usingVirtio && net->driver.virtio.txmode) {
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_TX_ALG)) {
|
Add txmode attribute to interface XML for virtio backend
This is in response to:
https://bugzilla.redhat.com/show_bug.cgi?id=629662
Explanation
qemu's virtio-net-pci driver allows setting the algorithm used for tx
packets to either "bh" or "timer". This is done by adding ",tx=bh" or
",tx=timer" to the "-device virtio-net-pci" commandline option.
'bh' stands for 'bottom half'; when this is set, packet tx is all done
in an iothread in the bottom half of the driver. (In libvirt, this
option is called the more descriptive "iothread".)
'timer' means that tx work is done in qemu, and if there is more tx
data than can be sent at the present time, a timer is set before qemu
moves on to do other things; when the timer fires, another attempt is
made to send more data. (libvirt retains the name "timer" for this
option.)
The resulting difference, according to the qemu developer who added
the option is:
bh makes tx more asynchronous and reduces latency, but potentially
causes more processor bandwidth contention since the cpu doing the
tx isn't necessarily the cpu where the guest generated the
packets.
Solution
This patch provides a libvirt domain xml knob to change the option on
the qemu commandline, by adding a new attribute "txmode" to the
<driver> element that can be placed inside any <interface> element in
a domain definition. It's use would be something like this:
<interface ...>
...
<model type='virtio'/>
<driver txmode='iothread'/>
...
</interface>
I chose to put this setting as an attribute to <driver> rather than as
a sub-element to <tune> because it is specific to the virtio-net
driver, not something that is generally usable by all network drivers.
(note that this is the same placement as the "driver name=..."
attribute used to choose kernel vs. userland backend for the
virtio-net driver.)
Actually adding the tx=xxx option to the qemu commandline is only done
if the version of qemu being used advertises it in the output of
qemu -device virtio-net-pci,?
If a particular txmode is requested in the XML, and the option isn't
listed in that help output, an UNSUPPORTED_CONFIG error is logged, and
the domain fails to start.
2011-02-03 20:20:01 +00:00
|
|
|
virBufferAddLit(&buf, ",tx=");
|
|
|
|
switch (net->driver.virtio.txmode) {
|
|
|
|
case VIR_DOMAIN_NET_VIRTIO_TX_MODE_IOTHREAD:
|
|
|
|
virBufferAddLit(&buf, "bh");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_VIRTIO_TX_MODE_TIMER:
|
|
|
|
virBufferAddLit(&buf, "timer");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* this should never happen, if it does, we need
|
|
|
|
* to add another case to this switch.
|
|
|
|
*/
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unrecognized virtio-net-pci 'tx' option"));
|
Add txmode attribute to interface XML for virtio backend
This is in response to:
https://bugzilla.redhat.com/show_bug.cgi?id=629662
Explanation
qemu's virtio-net-pci driver allows setting the algorithm used for tx
packets to either "bh" or "timer". This is done by adding ",tx=bh" or
",tx=timer" to the "-device virtio-net-pci" commandline option.
'bh' stands for 'bottom half'; when this is set, packet tx is all done
in an iothread in the bottom half of the driver. (In libvirt, this
option is called the more descriptive "iothread".)
'timer' means that tx work is done in qemu, and if there is more tx
data than can be sent at the present time, a timer is set before qemu
moves on to do other things; when the timer fires, another attempt is
made to send more data. (libvirt retains the name "timer" for this
option.)
The resulting difference, according to the qemu developer who added
the option is:
bh makes tx more asynchronous and reduces latency, but potentially
causes more processor bandwidth contention since the cpu doing the
tx isn't necessarily the cpu where the guest generated the
packets.
Solution
This patch provides a libvirt domain xml knob to change the option on
the qemu commandline, by adding a new attribute "txmode" to the
<driver> element that can be placed inside any <interface> element in
a domain definition. It's use would be something like this:
<interface ...>
...
<model type='virtio'/>
<driver txmode='iothread'/>
...
</interface>
I chose to put this setting as an attribute to <driver> rather than as
a sub-element to <tune> because it is specific to the virtio-net
driver, not something that is generally usable by all network drivers.
(note that this is the same placement as the "driver name=..."
attribute used to choose kernel vs. userland backend for the
virtio-net driver.)
Actually adding the tx=xxx option to the qemu commandline is only done
if the version of qemu being used advertises it in the output of
qemu -device virtio-net-pci,?
If a particular txmode is requested in the XML, and the option isn't
listed in that help output, an UNSUPPORTED_CONFIG error is logged, and
the domain fails to start.
2011-02-03 20:20:01 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("virtio-net-pci 'tx' option not supported in this QEMU binary"));
|
Add txmode attribute to interface XML for virtio backend
This is in response to:
https://bugzilla.redhat.com/show_bug.cgi?id=629662
Explanation
qemu's virtio-net-pci driver allows setting the algorithm used for tx
packets to either "bh" or "timer". This is done by adding ",tx=bh" or
",tx=timer" to the "-device virtio-net-pci" commandline option.
'bh' stands for 'bottom half'; when this is set, packet tx is all done
in an iothread in the bottom half of the driver. (In libvirt, this
option is called the more descriptive "iothread".)
'timer' means that tx work is done in qemu, and if there is more tx
data than can be sent at the present time, a timer is set before qemu
moves on to do other things; when the timer fires, another attempt is
made to send more data. (libvirt retains the name "timer" for this
option.)
The resulting difference, according to the qemu developer who added
the option is:
bh makes tx more asynchronous and reduces latency, but potentially
causes more processor bandwidth contention since the cpu doing the
tx isn't necessarily the cpu where the guest generated the
packets.
Solution
This patch provides a libvirt domain xml knob to change the option on
the qemu commandline, by adding a new attribute "txmode" to the
<driver> element that can be placed inside any <interface> element in
a domain definition. It's use would be something like this:
<interface ...>
...
<model type='virtio'/>
<driver txmode='iothread'/>
...
</interface>
I chose to put this setting as an attribute to <driver> rather than as
a sub-element to <tune> because it is specific to the virtio-net
driver, not something that is generally usable by all network drivers.
(note that this is the same placement as the "driver name=..."
attribute used to choose kernel vs. userland backend for the
virtio-net driver.)
Actually adding the tx=xxx option to the qemu commandline is only done
if the version of qemu being used advertises it in the output of
qemu -device virtio-net-pci,?
If a particular txmode is requested in the XML, and the option isn't
listed in that help output, an UNSUPPORTED_CONFIG error is logged, and
the domain fails to start.
2011-02-03 20:20:01 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
2011-08-13 06:32:45 +00:00
|
|
|
if (usingVirtio) {
|
2013-02-01 13:48:58 +00:00
|
|
|
qemuBuildIoEventFdStr(&buf, net->driver.virtio.ioeventfd, qemuCaps);
|
2011-08-13 06:32:45 +00:00
|
|
|
if (net->driver.virtio.event_idx &&
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_NET_EVENT_IDX)) {
|
2011-08-13 06:32:45 +00:00
|
|
|
virBufferAsprintf(&buf, ",event_idx=%s",
|
2014-06-27 15:18:53 +00:00
|
|
|
virTristateSwitchTypeToString(net->driver.virtio.event_idx));
|
2011-08-13 06:32:45 +00:00
|
|
|
}
|
2014-09-11 10:58:04 +00:00
|
|
|
if (net->driver.virtio.host.csum) {
|
|
|
|
virBufferAsprintf(&buf, ",csum=%s",
|
|
|
|
virTristateSwitchTypeToString(net->driver.virtio.host.csum));
|
|
|
|
}
|
|
|
|
if (net->driver.virtio.host.gso) {
|
|
|
|
virBufferAsprintf(&buf, ",gso=%s",
|
|
|
|
virTristateSwitchTypeToString(net->driver.virtio.host.gso));
|
|
|
|
}
|
|
|
|
if (net->driver.virtio.host.tso4) {
|
|
|
|
virBufferAsprintf(&buf, ",host_tso4=%s",
|
|
|
|
virTristateSwitchTypeToString(net->driver.virtio.host.tso4));
|
|
|
|
}
|
|
|
|
if (net->driver.virtio.host.tso6) {
|
|
|
|
virBufferAsprintf(&buf, ",host_tso6=%s",
|
|
|
|
virTristateSwitchTypeToString(net->driver.virtio.host.tso6));
|
|
|
|
}
|
|
|
|
if (net->driver.virtio.host.ecn) {
|
|
|
|
virBufferAsprintf(&buf, ",host_ecn=%s",
|
|
|
|
virTristateSwitchTypeToString(net->driver.virtio.host.ecn));
|
|
|
|
}
|
|
|
|
if (net->driver.virtio.host.ufo) {
|
|
|
|
virBufferAsprintf(&buf, ",host_ufo=%s",
|
|
|
|
virTristateSwitchTypeToString(net->driver.virtio.host.ufo));
|
|
|
|
}
|
2015-02-06 14:40:19 +00:00
|
|
|
if (net->driver.virtio.host.mrg_rxbuf) {
|
|
|
|
virBufferAsprintf(&buf, ",mrg_rxbuf=%s",
|
|
|
|
virTristateSwitchTypeToString(net->driver.virtio.host.mrg_rxbuf));
|
|
|
|
}
|
2014-09-11 10:58:04 +00:00
|
|
|
if (net->driver.virtio.guest.csum) {
|
|
|
|
virBufferAsprintf(&buf, ",guest_csum=%s",
|
|
|
|
virTristateSwitchTypeToString(net->driver.virtio.guest.csum));
|
|
|
|
}
|
|
|
|
if (net->driver.virtio.guest.tso4) {
|
|
|
|
virBufferAsprintf(&buf, ",guest_tso4=%s",
|
|
|
|
virTristateSwitchTypeToString(net->driver.virtio.guest.tso4));
|
|
|
|
}
|
|
|
|
if (net->driver.virtio.guest.tso6) {
|
|
|
|
virBufferAsprintf(&buf, ",guest_tso6=%s",
|
|
|
|
virTristateSwitchTypeToString(net->driver.virtio.guest.tso6));
|
|
|
|
}
|
|
|
|
if (net->driver.virtio.guest.ecn) {
|
|
|
|
virBufferAsprintf(&buf, ",guest_ecn=%s",
|
|
|
|
virTristateSwitchTypeToString(net->driver.virtio.guest.ecn));
|
|
|
|
}
|
|
|
|
if (net->driver.virtio.guest.ufo) {
|
|
|
|
virBufferAsprintf(&buf, ",guest_ufo=%s",
|
|
|
|
virTristateSwitchTypeToString(net->driver.virtio.guest.ufo));
|
|
|
|
}
|
2011-08-13 06:32:45 +00:00
|
|
|
}
|
2013-08-23 07:48:24 +00:00
|
|
|
if (usingVirtio && vhostfdSize > 1) {
|
2015-05-06 14:07:40 +00:00
|
|
|
if (net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
|
|
|
|
/* ccw provides a one to one relation of fds to queues and
|
|
|
|
* does not support the vectors option
|
|
|
|
*/
|
|
|
|
virBufferAddLit(&buf, ",mq=on");
|
|
|
|
} else {
|
|
|
|
/* As advised at http://www.linux-kvm.org/page/Multiqueue
|
|
|
|
* we should add vectors=2*N+2 where N is the vhostfdSize
|
|
|
|
*/
|
|
|
|
virBufferAsprintf(&buf, ",mq=on,vectors=%zu", 2 * vhostfdSize + 2);
|
|
|
|
}
|
2013-08-23 07:48:24 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
if (vlan == -1)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",netdev=host%s", net->info.alias);
|
2010-12-16 15:07:07 +00:00
|
|
|
else
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",vlan=%d", vlan);
|
|
|
|
virBufferAsprintf(&buf, ",id=%s", net->info.alias);
|
2013-03-26 11:21:33 +00:00
|
|
|
virBufferAsprintf(&buf, ",mac=%s",
|
|
|
|
virMacAddrFormat(&net->mac, macaddr));
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, def, &net->info, qemuCaps) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
2013-02-01 13:48:58 +00:00
|
|
|
if (qemuBuildRomStr(&buf, &net->info, qemuCaps) < 0)
|
2015-03-17 02:34:26 +00:00
|
|
|
goto error;
|
2013-02-01 13:48:58 +00:00
|
|
|
if (bootindex && virQEMUCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX))
|
2011-05-26 14:15:01 +00:00
|
|
|
virBufferAsprintf(&buf, ",bootindex=%d", bootindex);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
qemuBuildHostNetStr(virDomainNetDefPtr net,
|
2012-11-28 16:43:10 +00:00
|
|
|
virQEMUDriverPtr driver,
|
2010-12-16 15:07:07 +00:00
|
|
|
char type_sep,
|
|
|
|
int vlan,
|
2013-05-21 13:50:09 +00:00
|
|
|
char **tapfd,
|
2014-11-12 15:42:02 +00:00
|
|
|
size_t tapfdSize,
|
2013-05-21 13:50:09 +00:00
|
|
|
char **vhostfd,
|
2014-11-12 15:42:02 +00:00
|
|
|
size_t vhostfdSize)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
2011-01-12 19:38:01 +00:00
|
|
|
bool is_tap = false;
|
2010-12-16 15:07:07 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2014-06-01 00:22:30 +00:00
|
|
|
virDomainNetType netType = virDomainNetGetActualType(net);
|
2013-01-10 21:03:14 +00:00
|
|
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
config: report error when script given for inappropriate interface type
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=638633
Although scripts are not used by interfaces of type other than
"ethernet" in qemu, due to the fact that the parser stores the script
name in a union that is only valid when type is ethernet or bridge,
there is no way for anyone except the parser itself to catch the
problem of specifying an interface script for an inappropriate
interface type (by the time the parsed data gets back to the code that
called the parser, all evidence that a script was specified is
forgotten).
Since the parser itself should be agnostic to which type of interface
allows scripts (an example of why: a script specified for an interface
of type bridge is valid for xen domains, but not for qemu domains),
the solution here is to move the script out of the union(s) in the
DomainNetDef, always populate it when specified (regardless of
interface type), and let the driver decide whether or not it is
appropriate.
Currently the qemu, xen, libxml, and uml drivers recognize the script
parameter and do something with it (the uml driver only to report that
it isn't supported). Those drivers have been updated to log a
CONFIG_UNSUPPORTED error when a script is specified for an interface
type that's inappropriate for that particular hypervisor.
(NB: There was earlier discussion of solving this problem by adding a
VALIDATE flag to all libvirt APIs that accept XML, which would cause
the XML to be validated against the RNG files. One statement during
that discussion was that the RNG shouldn't contain hypervisor-specific
things, though, and a proper solution to this problem would require
that (again, because a script for an interface of type "bridge" is
accepted by xen, but not by qemu).
2012-01-06 17:59:47 +00:00
|
|
|
if (net->script && netType != VIR_DOMAIN_NET_TYPE_ETHERNET) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("scripts are not supported on interfaces of type %s"),
|
|
|
|
virDomainNetTypeToString(netType));
|
2013-01-10 21:03:14 +00:00
|
|
|
virObjectUnref(cfg);
|
config: report error when script given for inappropriate interface type
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=638633
Although scripts are not used by interfaces of type other than
"ethernet" in qemu, due to the fact that the parser stores the script
name in a union that is only valid when type is ethernet or bridge,
there is no way for anyone except the parser itself to catch the
problem of specifying an interface script for an inappropriate
interface type (by the time the parsed data gets back to the code that
called the parser, all evidence that a script was specified is
forgotten).
Since the parser itself should be agnostic to which type of interface
allows scripts (an example of why: a script specified for an interface
of type bridge is valid for xen domains, but not for qemu domains),
the solution here is to move the script out of the union(s) in the
DomainNetDef, always populate it when specified (regardless of
interface type), and let the driver decide whether or not it is
appropriate.
Currently the qemu, xen, libxml, and uml drivers recognize the script
parameter and do something with it (the uml driver only to report that
it isn't supported). Those drivers have been updated to log a
CONFIG_UNSUPPORTED error when a script is specified for an interface
type that's inappropriate for that particular hypervisor.
(NB: There was earlier discussion of solving this problem by adding a
VALIDATE flag to all libvirt APIs that accept XML, which would cause
the XML to be validated against the RNG files. One statement during
that discussion was that the RNG shouldn't contain hypervisor-specific
things, though, and a proper solution to this problem would require
that (again, because a script for an interface of type "bridge" is
accepted by xen, but not by qemu).
2012-01-06 17:59:47 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (netType) {
|
2012-08-03 20:33:06 +00:00
|
|
|
/*
|
|
|
|
* If type='bridge', and we're running as privileged user
|
|
|
|
* or -netdev bridge is not supported then it will fall
|
|
|
|
* through, -net tap,fd
|
|
|
|
*/
|
2010-12-16 15:07:07 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
2012-08-03 20:33:06 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
2010-12-16 15:07:07 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
2013-05-21 13:50:09 +00:00
|
|
|
virBufferAsprintf(&buf, "tap%c", type_sep);
|
|
|
|
/* for one tapfd 'fd=' shall be used,
|
|
|
|
* for more than one 'fds=' is the right choice */
|
|
|
|
if (tapfdSize == 1) {
|
|
|
|
virBufferAsprintf(&buf, "fd=%s", tapfd[0]);
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(&buf, "fds=");
|
|
|
|
for (i = 0; i < tapfdSize; i++) {
|
|
|
|
if (i)
|
|
|
|
virBufferAddChar(&buf, ':');
|
|
|
|
virBufferAdd(&buf, tapfd[i], -1);
|
|
|
|
}
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
type_sep = ',';
|
2011-01-12 19:38:01 +00:00
|
|
|
is_tap = true;
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
|
|
|
virBufferAddLit(&buf, "tap");
|
|
|
|
if (net->ifname) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "%cifname=%s", type_sep, net->ifname);
|
2010-12-16 15:07:07 +00:00
|
|
|
type_sep = ',';
|
|
|
|
}
|
config: report error when script given for inappropriate interface type
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=638633
Although scripts are not used by interfaces of type other than
"ethernet" in qemu, due to the fact that the parser stores the script
name in a union that is only valid when type is ethernet or bridge,
there is no way for anyone except the parser itself to catch the
problem of specifying an interface script for an inappropriate
interface type (by the time the parsed data gets back to the code that
called the parser, all evidence that a script was specified is
forgotten).
Since the parser itself should be agnostic to which type of interface
allows scripts (an example of why: a script specified for an interface
of type bridge is valid for xen domains, but not for qemu domains),
the solution here is to move the script out of the union(s) in the
DomainNetDef, always populate it when specified (regardless of
interface type), and let the driver decide whether or not it is
appropriate.
Currently the qemu, xen, libxml, and uml drivers recognize the script
parameter and do something with it (the uml driver only to report that
it isn't supported). Those drivers have been updated to log a
CONFIG_UNSUPPORTED error when a script is specified for an interface
type that's inappropriate for that particular hypervisor.
(NB: There was earlier discussion of solving this problem by adding a
VALIDATE flag to all libvirt APIs that accept XML, which would cause
the XML to be validated against the RNG files. One statement during
that discussion was that the RNG shouldn't contain hypervisor-specific
things, though, and a proper solution to this problem would require
that (again, because a script for an interface of type "bridge" is
accepted by xen, but not by qemu).
2012-01-06 17:59:47 +00:00
|
|
|
if (net->script) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "%cscript=%s", type_sep,
|
config: report error when script given for inappropriate interface type
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=638633
Although scripts are not used by interfaces of type other than
"ethernet" in qemu, due to the fact that the parser stores the script
name in a union that is only valid when type is ethernet or bridge,
there is no way for anyone except the parser itself to catch the
problem of specifying an interface script for an inappropriate
interface type (by the time the parsed data gets back to the code that
called the parser, all evidence that a script was specified is
forgotten).
Since the parser itself should be agnostic to which type of interface
allows scripts (an example of why: a script specified for an interface
of type bridge is valid for xen domains, but not for qemu domains),
the solution here is to move the script out of the union(s) in the
DomainNetDef, always populate it when specified (regardless of
interface type), and let the driver decide whether or not it is
appropriate.
Currently the qemu, xen, libxml, and uml drivers recognize the script
parameter and do something with it (the uml driver only to report that
it isn't supported). Those drivers have been updated to log a
CONFIG_UNSUPPORTED error when a script is specified for an interface
type that's inappropriate for that particular hypervisor.
(NB: There was earlier discussion of solving this problem by adding a
VALIDATE flag to all libvirt APIs that accept XML, which would cause
the XML to be validated against the RNG files. One statement during
that discussion was that the RNG shouldn't contain hypervisor-specific
things, though, and a proper solution to this problem would require
that (again, because a script for an interface of type "bridge" is
accepted by xen, but not by qemu).
2012-01-06 17:59:47 +00:00
|
|
|
net->script);
|
2010-12-16 15:07:07 +00:00
|
|
|
type_sep = ',';
|
|
|
|
}
|
2011-01-12 19:38:01 +00:00
|
|
|
is_tap = true;
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
2012-03-28 17:06:37 +00:00
|
|
|
virBufferAsprintf(&buf, "socket%cconnect=%s:%d",
|
|
|
|
type_sep,
|
|
|
|
net->data.socket.address,
|
|
|
|
net->data.socket.port);
|
|
|
|
type_sep = ',';
|
|
|
|
break;
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_SERVER:
|
2012-03-28 17:06:37 +00:00
|
|
|
virBufferAsprintf(&buf, "socket%clisten=%s:%d",
|
|
|
|
type_sep,
|
2015-01-20 12:34:10 +00:00
|
|
|
net->data.socket.address ? net->data.socket.address
|
|
|
|
: "",
|
2012-03-28 17:06:37 +00:00
|
|
|
net->data.socket.port);
|
|
|
|
type_sep = ',';
|
|
|
|
break;
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_MCAST:
|
2012-03-28 17:06:37 +00:00
|
|
|
virBufferAsprintf(&buf, "socket%cmcast=%s:%d",
|
|
|
|
type_sep,
|
|
|
|
net->data.socket.address,
|
|
|
|
net->data.socket.port);
|
|
|
|
type_sep = ',';
|
|
|
|
break;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2015-08-29 20:19:10 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_UDP:
|
|
|
|
virBufferAsprintf(&buf, "socket%cudp=%s:%d,localaddr=%s:%d",
|
|
|
|
type_sep,
|
|
|
|
net->data.socket.address,
|
|
|
|
net->data.socket.port,
|
|
|
|
net->data.socket.localaddr,
|
|
|
|
net->data.socket.localport);
|
|
|
|
type_sep = ',';
|
|
|
|
break;
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_USER:
|
|
|
|
default:
|
|
|
|
virBufferAddLit(&buf, "user");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vlan >= 0) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "%cvlan=%d", type_sep, vlan);
|
2010-12-16 15:07:07 +00:00
|
|
|
if (net->info.alias)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",name=host%s",
|
2010-12-16 15:07:07 +00:00
|
|
|
net->info.alias);
|
|
|
|
} else {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "%cid=host%s",
|
2010-12-16 15:07:07 +00:00
|
|
|
type_sep, net->info.alias);
|
|
|
|
}
|
|
|
|
|
2011-01-12 19:38:01 +00:00
|
|
|
if (is_tap) {
|
2013-05-21 13:50:09 +00:00
|
|
|
if (vhostfdSize) {
|
|
|
|
virBufferAddLit(&buf, ",vhost=on,");
|
|
|
|
if (vhostfdSize == 1) {
|
|
|
|
virBufferAsprintf(&buf, "vhostfd=%s", vhostfd[0]);
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(&buf, "vhostfds=");
|
|
|
|
for (i = 0; i < vhostfdSize; i++) {
|
|
|
|
if (i)
|
|
|
|
virBufferAddChar(&buf, ':');
|
|
|
|
virBufferAdd(&buf, vhostfd[i], -1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-01-12 19:38:01 +00:00
|
|
|
if (net->tune.sndbuf_specified)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",sndbuf=%lu", net->tune.sndbuf);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
virObjectUnref(cfg);
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
2013-08-02 17:48:50 +00:00
|
|
|
qemuBuildWatchdogDevStr(virDomainDefPtr def,
|
|
|
|
virDomainWatchdogDefPtr dev,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
const char *model = virDomainWatchdogModelTypeToString(dev->model);
|
|
|
|
if (!model) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("missing watchdog model"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "%s,id=%s", model, dev->info.alias);
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, def, &dev->info, qemuCaps) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
2013-08-02 17:48:50 +00:00
|
|
|
qemuBuildMemballoonDevStr(virDomainDefPtr def,
|
|
|
|
virDomainMemballoonDefPtr dev,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
2013-03-05 15:44:21 +00:00
|
|
|
switch (dev->info.type) {
|
|
|
|
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
|
|
|
|
virBufferAddLit(&buf, "virtio-balloon-pci");
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW:
|
|
|
|
virBufferAddLit(&buf, "virtio-balloon-ccw");
|
|
|
|
break;
|
2013-08-01 01:40:35 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
|
|
|
|
virBufferAddLit(&buf, "virtio-balloon-device");
|
|
|
|
break;
|
2013-03-05 15:44:21 +00:00
|
|
|
default:
|
2013-04-29 18:01:19 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("memballoon unsupported with address type '%s'"),
|
|
|
|
virDomainDeviceAddressTypeToString(dev->info.type));
|
2013-03-05 15:44:21 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",id=%s", dev->info.alias);
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, def, &dev->info, qemuCaps) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
2016-01-08 10:45:07 +00:00
|
|
|
if (dev->autodeflate != VIR_TRISTATE_SWITCH_ABSENT) {
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BALLOON_AUTODEFLATE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("deflate-on-oom is not supported by this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, ",deflate-on-oom=%s",
|
|
|
|
virTristateSwitchTypeToString(dev->autodeflate));
|
|
|
|
}
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-04-25 08:46:04 +00:00
|
|
|
static char *
|
|
|
|
qemuBuildNVRAMDevStr(virDomainNVRAMDefPtr dev)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
if (dev->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO &&
|
|
|
|
dev->info.addr.spaprvio.has_reg) {
|
|
|
|
virBufferAsprintf(&buf, "spapr-nvram.reg=0x%llx",
|
|
|
|
dev->info.addr.spaprvio.reg);
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("nvram address type must be spaprvio"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2013-04-25 08:46:04 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2013-04-25 08:46:04 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2015-11-13 10:38:07 +00:00
|
|
|
static char *
|
|
|
|
qemuBuildVirtioInputDevStr(virDomainDefPtr def,
|
|
|
|
virDomainInputDefPtr dev,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
const char *suffix;
|
|
|
|
|
|
|
|
if (dev->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
|
|
|
suffix = "-pci";
|
|
|
|
} else if (dev->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO) {
|
|
|
|
suffix = "-device";
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported address type %s for virtio input device"),
|
|
|
|
virDomainDeviceAddressTypeToString(dev->info.type));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ((virDomainInputType) dev->type) {
|
|
|
|
case VIR_DOMAIN_INPUT_TYPE_MOUSE:
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_MOUSE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("virtio-mouse is not supported by this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAsprintf(&buf, "virtio-mouse%s,id=%s", suffix, dev->info.alias);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_INPUT_TYPE_TABLET:
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_TABLET)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("virtio-tablet is not supported by this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAsprintf(&buf, "virtio-tablet%s,id=%s", suffix, dev->info.alias);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_INPUT_TYPE_KBD:
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_KEYBOARD)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("virtio-keyboard is not supported by this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAsprintf(&buf, "virtio-keyboard%s,id=%s", suffix, dev->info.alias);
|
|
|
|
break;
|
2015-11-16 08:36:12 +00:00
|
|
|
case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
|
2015-11-20 07:57:16 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_INPUT_HOST)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("virtio-input-host is not supported by this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAsprintf(&buf, "virtio-input-host%s,id=%s,evdev=", suffix, dev->info.alias);
|
|
|
|
virBufferEscape(&buf, ',', ",", "%s", dev->source.evdev);
|
|
|
|
break;
|
2015-11-13 10:38:07 +00:00
|
|
|
case VIR_DOMAIN_INPUT_TYPE_LAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuBuildDeviceAddressStr(&buf, def, &dev->info, qemuCaps) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virBufferCheckError(&buf) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
char *
|
2013-08-02 17:48:50 +00:00
|
|
|
qemuBuildUSBInputDevStr(virDomainDefPtr def,
|
|
|
|
virDomainInputDefPtr dev,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
2014-02-17 10:17:56 +00:00
|
|
|
switch (dev->type) {
|
|
|
|
case VIR_DOMAIN_INPUT_TYPE_MOUSE:
|
|
|
|
virBufferAsprintf(&buf, "usb-mouse,id=%s", dev->info.alias);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_INPUT_TYPE_TABLET:
|
|
|
|
virBufferAsprintf(&buf, "usb-tablet,id=%s", dev->info.alias);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_INPUT_TYPE_KBD:
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_USB_KBD))
|
|
|
|
goto error;
|
|
|
|
virBufferAsprintf(&buf, "usb-kbd,id=%s", dev->info.alias);
|
|
|
|
break;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, def, &dev->info, qemuCaps) < 0)
|
2011-09-02 13:28:27 +00:00
|
|
|
goto error;
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
2013-08-02 17:48:50 +00:00
|
|
|
qemuBuildSoundDevStr(virDomainDefPtr def,
|
|
|
|
virDomainSoundDefPtr sound,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2014-07-28 09:38:35 +00:00
|
|
|
const char *model = NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2013-09-24 13:38:32 +00:00
|
|
|
/* Hack for devices with different names in QEMU and libvirt */
|
2014-07-25 08:24:40 +00:00
|
|
|
switch ((virDomainSoundModel) sound->model) {
|
2013-09-24 13:38:32 +00:00
|
|
|
case VIR_DOMAIN_SOUND_MODEL_ES1370:
|
2010-12-16 15:07:07 +00:00
|
|
|
model = "ES1370";
|
2013-09-24 13:38:32 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_SOUND_MODEL_AC97:
|
2010-12-16 15:07:07 +00:00
|
|
|
model = "AC97";
|
2013-09-24 13:38:32 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_SOUND_MODEL_ICH6:
|
2011-01-13 14:15:11 +00:00
|
|
|
model = "intel-hda";
|
2013-09-24 13:38:32 +00:00
|
|
|
break;
|
2014-07-24 15:32:31 +00:00
|
|
|
case VIR_DOMAIN_SOUND_MODEL_USB:
|
|
|
|
model = "usb-audio";
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_USB_AUDIO)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("usb-audio controller is not supported "
|
|
|
|
"by this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
break;
|
2013-09-24 14:17:38 +00:00
|
|
|
case VIR_DOMAIN_SOUND_MODEL_ICH9:
|
|
|
|
model = "ich9-intel-hda";
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_ICH9_INTEL_HDA)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("The ich9-intel-hda audio controller "
|
|
|
|
"is not supported in this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
break;
|
2014-07-25 08:24:40 +00:00
|
|
|
case VIR_DOMAIN_SOUND_MODEL_SB16:
|
|
|
|
model = "sb16";
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_SOUND_MODEL_PCSPK: /* pc-speaker is handled separately */
|
|
|
|
case VIR_DOMAIN_SOUND_MODEL_LAST:
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("sound card model '%s' is not supported by qemu"),
|
|
|
|
virDomainSoundModelTypeToString(sound->model));
|
|
|
|
goto error;
|
2013-09-24 13:38:32 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "%s,id=%s", model, sound->info.alias);
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, def, &sound->info, qemuCaps) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-05-15 22:55:10 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
qemuSoundCodecTypeToCaps(int type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case VIR_DOMAIN_SOUND_CODEC_TYPE_DUPLEX:
|
|
|
|
return QEMU_CAPS_HDA_DUPLEX;
|
|
|
|
case VIR_DOMAIN_SOUND_CODEC_TYPE_MICRO:
|
|
|
|
return QEMU_CAPS_HDA_MICRO;
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-13 14:15:11 +00:00
|
|
|
static char *
|
|
|
|
qemuBuildSoundCodecStr(virDomainSoundDefPtr sound,
|
2012-05-15 22:55:10 +00:00
|
|
|
virDomainSoundCodecDefPtr codec,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2011-01-13 14:15:11 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2012-05-15 22:55:10 +00:00
|
|
|
const char *stype;
|
2012-08-20 16:44:14 +00:00
|
|
|
int type, flags;
|
2011-01-13 14:15:11 +00:00
|
|
|
|
2012-05-15 22:55:10 +00:00
|
|
|
type = codec->type;
|
|
|
|
stype = qemuSoundCodecTypeToString(type);
|
2012-08-20 16:44:14 +00:00
|
|
|
flags = qemuSoundCodecTypeToCaps(type);
|
2011-01-13 14:15:11 +00:00
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (flags == -1 || !virQEMUCapsGet(qemuCaps, flags)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("%s not supported in this QEMU binary"), stype);
|
2011-01-13 14:15:11 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-05-15 22:55:10 +00:00
|
|
|
virBufferAsprintf(&buf, "%s,id=%s-codec%d,bus=%s.0,cad=%d",
|
|
|
|
stype, sound->info.alias, codec->cad, sound->info.alias, codec->cad);
|
|
|
|
|
2011-01-13 14:15:11 +00:00
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2011-01-13 14:15:11 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
static char *
|
2013-08-02 17:48:50 +00:00
|
|
|
qemuBuildDeviceVideoStr(virDomainDefPtr def,
|
|
|
|
virDomainVideoDefPtr video,
|
2016-02-23 12:00:24 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2012-12-14 07:08:01 +00:00
|
|
|
const char *model;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2016-02-23 12:00:24 +00:00
|
|
|
if (video->primary) {
|
2012-12-14 07:08:01 +00:00
|
|
|
model = qemuDeviceVideoTypeToString(video->type);
|
|
|
|
if (!model || STREQ(model, "")) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("video type %s is not supported with QEMU"),
|
|
|
|
virDomainVideoTypeToString(video->type));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (video->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("non-primary video device must be type of 'qxl'"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_QXL)) {
|
2012-12-14 07:08:01 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("only one video card is currently supported"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
model = "qxl";
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "%s,id=%s", model, video->info.alias);
|
qemu: Support vram for video of qxl type
For qemu names the primary vga as "qxl-vga":
1) if vram is specified for 2nd qxl device:
-vga qxl -global qxl-vga.vram_size=$SIZE \
-device qxl,id=video1,vram_size=$SIZE,...
2) if vram is not specified for 2nd qxl device, (use the default
set by global):
-vga qxl -global qxl-vga.vram_size=$SIZE \
-device qxl,id=video1,...
For qemu names all qxl devices as "qxl":
1) if vram is specified for 2nd qxl device:
-vga qxl -global qxl.vram_size=$SIZE \
-device qxl,id=video1,vram_size=$SIZE ...
2) if vram is not specified for 2nd qxl device:
-vga qxl -global qxl-vga.vram_size=$SIZE \
-device qxl,id=video1,...
"-global" is the only way to define vram_size for the primary qxl
device, regardless of how qemu names it, (It's not good a good
way, as original idea of "-global" is to set a global default for
a driver property, but to specify vram for first qxl device, we
have to use it).
For other qxl devices, as they are represented by "-device", could
specify it directly and seperately for each, and it overrides the
default set by "-global" if specified.
v1 - v2:
* modify "virDomainVideoDefaultRAM" so that it returns 16M as the
default vram_size for qxl device.
* vram_size * 1024 (qemu accepts bytes for vram_size).
* apply default vram_size for qxl device for which vram_size is
not specified.
* modify "graphics-spice" tests (more sensiable vram_size)
* Add an argument of virDomainDefPtr type for qemuBuildVideoDevStr,
to use virDomainVideoDefaultRAM in qemuBuildVideoDevStr).
v2 - v3:
* Modify default video memory size for qxl device from 16M to 24M
* Update codes to be consistent with changes on qemu_capabilities.*
2011-03-06 14:00:27 +00:00
|
|
|
|
2015-11-25 08:42:33 +00:00
|
|
|
if (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO) {
|
|
|
|
if (video->accel && video->accel->accel3d) {
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIRTIO_GPU_VIRGL)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("virtio-gpu 3d acceleration is not supported"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, ",virgl=%s",
|
|
|
|
virTristateSwitchTypeToString(video->accel->accel3d));
|
|
|
|
}
|
|
|
|
} else if (video->type == VIR_DOMAIN_VIDEO_TYPE_QXL) {
|
2011-03-15 03:50:09 +00:00
|
|
|
if (video->vram > (UINT_MAX / 1024)) {
|
2013-01-18 18:36:36 +00:00
|
|
|
virReportError(VIR_ERR_OVERFLOW,
|
2012-07-18 15:22:03 +00:00
|
|
|
_("value for 'vram' must be less than '%u'"),
|
|
|
|
UINT_MAX / 1024);
|
2011-03-15 03:50:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2013-01-18 18:36:36 +00:00
|
|
|
if (video->ram > (UINT_MAX / 1024)) {
|
|
|
|
virReportError(VIR_ERR_OVERFLOW,
|
|
|
|
_("value for 'ram' must be less than '%u'"),
|
|
|
|
UINT_MAX / 1024);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2014-11-24 10:58:53 +00:00
|
|
|
if (video->ram) {
|
|
|
|
/* QEMU accepts bytes for ram_size. */
|
|
|
|
virBufferAsprintf(&buf, ",ram_size=%u", video->ram * 1024);
|
|
|
|
}
|
2011-03-15 03:50:09 +00:00
|
|
|
|
2014-11-24 10:58:53 +00:00
|
|
|
if (video->vram) {
|
|
|
|
/* QEMU accepts bytes for vram_size. */
|
|
|
|
virBufferAsprintf(&buf, ",vram_size=%u", video->vram * 1024);
|
|
|
|
}
|
2014-11-20 18:52:00 +00:00
|
|
|
|
2016-02-23 16:04:19 +00:00
|
|
|
if ((video->primary &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_QXL_VGA_VRAM64)) ||
|
|
|
|
(!video->primary &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_QXL_VRAM64))) {
|
|
|
|
/* QEMU accepts mebibytes for vram64_size_mb. */
|
|
|
|
virBufferAsprintf(&buf, ",vram64_size_mb=%u", video->vram64 / 1024);
|
|
|
|
}
|
|
|
|
|
2016-02-23 12:00:24 +00:00
|
|
|
if ((video->primary &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_QXL_VGA_VGAMEM)) ||
|
|
|
|
(!video->primary &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_QXL_VGAMEM))) {
|
2014-11-20 18:52:00 +00:00
|
|
|
/* QEMU accepts mebibytes for vgamem_mb. */
|
|
|
|
virBufferAsprintf(&buf, ",vgamem_mb=%u", video->vgamem / 1024);
|
|
|
|
}
|
2014-11-20 18:51:12 +00:00
|
|
|
} else if (video->vram &&
|
|
|
|
((video->type == VIR_DOMAIN_VIDEO_TYPE_VGA &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_VGA_VGAMEM)) ||
|
|
|
|
(video->type == VIR_DOMAIN_VIDEO_TYPE_VMVGA &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_VMWARE_SVGA_VGAMEM)))) {
|
|
|
|
|
|
|
|
if (video->vram < 1024) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("value for 'vram' must be at least 1 MiB "
|
|
|
|
"(1024 KiB)"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, ",vgamem_mb=%u", video->vram / 1024);
|
qemu: Support vram for video of qxl type
For qemu names the primary vga as "qxl-vga":
1) if vram is specified for 2nd qxl device:
-vga qxl -global qxl-vga.vram_size=$SIZE \
-device qxl,id=video1,vram_size=$SIZE,...
2) if vram is not specified for 2nd qxl device, (use the default
set by global):
-vga qxl -global qxl-vga.vram_size=$SIZE \
-device qxl,id=video1,...
For qemu names all qxl devices as "qxl":
1) if vram is specified for 2nd qxl device:
-vga qxl -global qxl.vram_size=$SIZE \
-device qxl,id=video1,vram_size=$SIZE ...
2) if vram is not specified for 2nd qxl device:
-vga qxl -global qxl-vga.vram_size=$SIZE \
-device qxl,id=video1,...
"-global" is the only way to define vram_size for the primary qxl
device, regardless of how qemu names it, (It's not good a good
way, as original idea of "-global" is to set a global default for
a driver property, but to specify vram for first qxl device, we
have to use it).
For other qxl devices, as they are represented by "-device", could
specify it directly and seperately for each, and it overrides the
default set by "-global" if specified.
v1 - v2:
* modify "virDomainVideoDefaultRAM" so that it returns 16M as the
default vram_size for qxl device.
* vram_size * 1024 (qemu accepts bytes for vram_size).
* apply default vram_size for qxl device for which vram_size is
not specified.
* modify "graphics-spice" tests (more sensiable vram_size)
* Add an argument of virDomainDefPtr type for qemuBuildVideoDevStr,
to use virDomainVideoDefaultRAM in qemuBuildVideoDevStr).
v2 - v3:
* Modify default video memory size for qxl device from 16M to 24M
* Update codes to be consistent with changes on qemu_capabilities.*
2011-03-06 14:00:27 +00:00
|
|
|
}
|
|
|
|
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, def, &video->info, qemuCaps) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuOpenPCIConfig(virDomainHostdevDefPtr dev)
|
|
|
|
{
|
2014-07-03 20:31:39 +00:00
|
|
|
virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci;
|
2010-12-16 15:07:07 +00:00
|
|
|
char *path = NULL;
|
|
|
|
int configfd = -1;
|
|
|
|
|
|
|
|
if (virAsprintf(&path, "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/config",
|
2014-07-03 20:31:39 +00:00
|
|
|
pcisrc->addr.domain, pcisrc->addr.bus,
|
|
|
|
pcisrc->addr.slot, pcisrc->addr.function) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
configfd = open(path, O_RDWR, 0);
|
|
|
|
|
|
|
|
if (configfd < 0)
|
|
|
|
virReportSystemError(errno, _("Failed opening %s"), path);
|
|
|
|
|
|
|
|
VIR_FREE(path);
|
|
|
|
|
|
|
|
return configfd;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
2013-08-02 17:48:50 +00:00
|
|
|
qemuBuildPCIHostdevDevStr(virDomainDefPtr def,
|
|
|
|
virDomainHostdevDefPtr dev,
|
qemu: add bootindex option to hostdev network interface commandline
when appropriate, of course. If the config for a domain specifies boot
order with <boot dev='blah'/> elements, e.g.:
<os>
...
<boot dev='hd'/>
<boot dev='network'/>
</os>
Then the first disk device in the config will have ",bootindex=1"
appended to its qemu commandline -device options, and the first (and
*only* the first) network interface device will get ",bootindex=2".
However, if the first network interface device is a "hostdev" device
(an SRIOV Virtual Function (VF) being assigned to the domain with
vfio), then the bootindex option will *not* be appended. This happens
because the bootindex=n option corresponding to the order of "<boot
dev='network'/>" is added to the -device for the first network device
when network device commandline args are constructed, but if it's a
hostdev network device, its commandline arg is instead constructed in
the loop for hostdevs.
This patch fixes that omission by noticing (in bootHostdevNet) if the
first network device was a hostdev, and if so passing on the proper
bootindex to the commandline generator for hostdev devices - the
result is that ",bootindex=2" will be properly appended to the first
"network" device in the config even if it is really a hostdev
(including if it is assigned from a libvirt network pool). (note that
this is only the case if there is no <bootmenu enabled='yes'/> element
in the config ("-boot menu-on" in qemu) , since the two are mutually
exclusive - when the bootmenu is enabled, the individual per-device
bootindex options can't be used by qemu, and we revert to using "-boot
order=xyz" instead).
If a greater level of control over boot order is desired (e.g., more
than one network device should be tried, or a network device other
than the first one encountered in the config), then <boot
dev='network'/> in the <os> element should not be used; instead, the
individual device elements in the config should be given a "<boot
order='n'/>
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1278421
2015-11-30 22:40:44 +00:00
|
|
|
int bootIndex, /* used iff dev->info->bootIndex == 0 */
|
2013-08-02 17:48:50 +00:00
|
|
|
const char *configfd,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2014-07-03 20:31:39 +00:00
|
|
|
virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci;
|
|
|
|
int backend = pcisrc->backend;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2013-09-20 08:39:51 +00:00
|
|
|
/* caller has to assign proper passthrough backend type */
|
2014-03-13 11:59:32 +00:00
|
|
|
switch ((virDomainHostdevSubsysPCIBackendType) backend) {
|
2013-09-19 14:48:23 +00:00
|
|
|
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
|
2013-04-25 11:58:37 +00:00
|
|
|
virBufferAddLit(&buf, "pci-assign");
|
|
|
|
if (configfd && *configfd)
|
|
|
|
virBufferAsprintf(&buf, ",configfd=%s", configfd);
|
2013-09-19 14:48:23 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
|
|
|
|
virBufferAddLit(&buf, "vfio-pci");
|
|
|
|
break;
|
|
|
|
|
2014-03-06 08:44:22 +00:00
|
|
|
default:
|
2013-09-20 08:39:51 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("invalid PCI passthrough type '%s'"),
|
2014-03-13 11:59:32 +00:00
|
|
|
virDomainHostdevSubsysPCIBackendTypeToString(backend));
|
2014-07-28 08:45:23 +00:00
|
|
|
goto error;
|
2013-04-25 11:58:37 +00:00
|
|
|
}
|
2013-09-19 14:48:23 +00:00
|
|
|
|
2014-04-30 11:32:19 +00:00
|
|
|
virBufferAddLit(&buf, ",host=");
|
2014-07-03 20:31:39 +00:00
|
|
|
if (pcisrc->addr.domain) {
|
2014-04-30 11:32:19 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_HOST_PCI_MULTIDOMAIN)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("non-zero domain='%.4x' in host device PCI address "
|
|
|
|
"not supported in this QEMU binary"),
|
2014-07-03 20:31:39 +00:00
|
|
|
pcisrc->addr.domain);
|
2014-04-30 11:32:19 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2014-07-03 20:31:39 +00:00
|
|
|
virBufferAsprintf(&buf, "%.4x:", pcisrc->addr.domain);
|
2014-04-30 11:32:19 +00:00
|
|
|
}
|
|
|
|
virBufferAsprintf(&buf, "%.2x:%.2x.%.1x",
|
2014-07-03 20:31:39 +00:00
|
|
|
pcisrc->addr.bus, pcisrc->addr.slot,
|
|
|
|
pcisrc->addr.function);
|
2012-01-31 09:16:54 +00:00
|
|
|
virBufferAsprintf(&buf, ",id=%s", dev->info->alias);
|
|
|
|
if (dev->info->bootIndex)
|
qemu: add bootindex option to hostdev network interface commandline
when appropriate, of course. If the config for a domain specifies boot
order with <boot dev='blah'/> elements, e.g.:
<os>
...
<boot dev='hd'/>
<boot dev='network'/>
</os>
Then the first disk device in the config will have ",bootindex=1"
appended to its qemu commandline -device options, and the first (and
*only* the first) network interface device will get ",bootindex=2".
However, if the first network interface device is a "hostdev" device
(an SRIOV Virtual Function (VF) being assigned to the domain with
vfio), then the bootindex option will *not* be appended. This happens
because the bootindex=n option corresponding to the order of "<boot
dev='network'/>" is added to the -device for the first network device
when network device commandline args are constructed, but if it's a
hostdev network device, its commandline arg is instead constructed in
the loop for hostdevs.
This patch fixes that omission by noticing (in bootHostdevNet) if the
first network device was a hostdev, and if so passing on the proper
bootindex to the commandline generator for hostdev devices - the
result is that ",bootindex=2" will be properly appended to the first
"network" device in the config even if it is really a hostdev
(including if it is assigned from a libvirt network pool). (note that
this is only the case if there is no <bootmenu enabled='yes'/> element
in the config ("-boot menu-on" in qemu) , since the two are mutually
exclusive - when the bootmenu is enabled, the individual per-device
bootindex options can't be used by qemu, and we revert to using "-boot
order=xyz" instead).
If a greater level of control over boot order is desired (e.g., more
than one network device should be tried, or a network device other
than the first one encountered in the config), then <boot
dev='network'/> in the <os> element should not be used; instead, the
individual device elements in the config should be given a "<boot
order='n'/>
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1278421
2015-11-30 22:40:44 +00:00
|
|
|
bootIndex = dev->info->bootIndex;
|
|
|
|
if (bootIndex)
|
|
|
|
virBufferAsprintf(&buf, ",bootindex=%d", bootIndex);
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, def, dev->info, qemuCaps) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
2013-02-01 13:48:58 +00:00
|
|
|
if (qemuBuildRomStr(&buf, dev->info, qemuCaps) < 0)
|
2015-03-17 02:34:26 +00:00
|
|
|
goto error;
|
2011-09-20 17:31:52 +00:00
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
2014-04-30 11:32:19 +00:00
|
|
|
qemuBuildPCIHostdevPCIDevStr(virDomainHostdevDefPtr dev,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
char *ret = NULL;
|
2014-07-03 20:31:39 +00:00
|
|
|
virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2014-07-03 20:31:39 +00:00
|
|
|
if (pcisrc->addr.domain) {
|
2014-04-30 11:32:19 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_HOST_PCI_MULTIDOMAIN)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("non-zero domain='%.4x' in host device PCI address "
|
|
|
|
"not supported in this QEMU binary"),
|
2014-07-03 20:31:39 +00:00
|
|
|
pcisrc->addr.domain);
|
2014-04-30 11:32:19 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
ignore_value(virAsprintf(&ret, "host=%.4x:%.2x:%.2x.%.1x",
|
2014-07-03 20:31:39 +00:00
|
|
|
pcisrc->addr.domain, pcisrc->addr.bus,
|
|
|
|
pcisrc->addr.slot, pcisrc->addr.function));
|
2014-04-30 11:32:19 +00:00
|
|
|
} else {
|
|
|
|
ignore_value(virAsprintf(&ret, "host=%.2x:%.2x.%.1x",
|
2014-07-03 20:31:39 +00:00
|
|
|
pcisrc->addr.bus, pcisrc->addr.slot,
|
|
|
|
pcisrc->addr.function));
|
2014-04-30 11:32:19 +00:00
|
|
|
}
|
|
|
|
cleanup:
|
2010-12-16 15:07:07 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-02 15:09:14 +00:00
|
|
|
char *
|
2012-09-13 07:25:46 +00:00
|
|
|
qemuBuildRedirdevDevStr(virDomainDefPtr def,
|
|
|
|
virDomainRedirdevDefPtr dev,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2011-09-02 15:09:14 +00:00
|
|
|
{
|
2012-09-13 07:25:46 +00:00
|
|
|
size_t i;
|
2011-09-02 15:09:14 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2012-09-13 07:25:46 +00:00
|
|
|
virDomainRedirFilterDefPtr redirfilter = def->redirfilter;
|
2011-09-02 15:09:14 +00:00
|
|
|
|
|
|
|
if (dev->bus != VIR_DOMAIN_REDIRDEV_BUS_USB) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Redirection bus %s is not supported by QEMU"),
|
|
|
|
virDomainRedirdevBusTypeToString(dev->bus));
|
2011-09-02 15:09:14 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_USB_REDIR)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("USB redirection is not supported "
|
|
|
|
"by this version of QEMU"));
|
2011-09-02 15:09:14 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, "usb-redir,chardev=char%s,id=%s",
|
2015-03-17 02:34:26 +00:00
|
|
|
dev->info.alias, dev->info.alias);
|
2011-09-02 15:09:14 +00:00
|
|
|
|
2012-09-13 07:25:46 +00:00
|
|
|
if (redirfilter && redirfilter->nusbdevs) {
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_USB_REDIR_FILTER)) {
|
2012-09-13 07:25:46 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("USB redirection filter is not "
|
|
|
|
"supported by this version of QEMU"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(&buf, ",filter=");
|
2012-09-13 07:25:46 +00:00
|
|
|
|
|
|
|
for (i = 0; i < redirfilter->nusbdevs; i++) {
|
2014-03-13 11:58:17 +00:00
|
|
|
virDomainRedirFilterUSBDevDefPtr usbdev = redirfilter->usbdevs[i];
|
2012-09-13 07:25:46 +00:00
|
|
|
if (usbdev->usbClass >= 0)
|
|
|
|
virBufferAsprintf(&buf, "0x%02X:", usbdev->usbClass);
|
|
|
|
else
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(&buf, "-1:");
|
2012-09-13 07:25:46 +00:00
|
|
|
|
|
|
|
if (usbdev->vendor >= 0)
|
|
|
|
virBufferAsprintf(&buf, "0x%04X:", usbdev->vendor);
|
|
|
|
else
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(&buf, "-1:");
|
2012-09-13 07:25:46 +00:00
|
|
|
|
|
|
|
if (usbdev->product >= 0)
|
|
|
|
virBufferAsprintf(&buf, "0x%04X:", usbdev->product);
|
|
|
|
else
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(&buf, "-1:");
|
2012-09-13 07:25:46 +00:00
|
|
|
|
|
|
|
if (usbdev->version >= 0)
|
|
|
|
virBufferAsprintf(&buf, "0x%04X:", usbdev->version);
|
|
|
|
else
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(&buf, "-1:");
|
2012-09-13 07:25:46 +00:00
|
|
|
|
|
|
|
virBufferAsprintf(&buf, "%u", usbdev->allow);
|
|
|
|
if (i < redirfilter->nusbdevs -1)
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(&buf, "|");
|
2012-09-13 07:25:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-14 14:51:30 +00:00
|
|
|
if (dev->info.bootIndex) {
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_USB_REDIR_BOOTINDEX)) {
|
2012-11-14 14:51:30 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("USB redirection booting is not "
|
|
|
|
"supported by this version of QEMU"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAsprintf(&buf, ",bootindex=%d", dev->info.bootIndex);
|
|
|
|
}
|
|
|
|
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, def, &dev->info, qemuCaps) < 0)
|
2011-09-02 15:09:14 +00:00
|
|
|
goto error;
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2011-09-02 15:09:14 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2011-09-02 15:09:14 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
char *
|
2013-08-02 17:48:50 +00:00
|
|
|
qemuBuildUSBHostdevDevStr(virDomainDefPtr def,
|
|
|
|
virDomainHostdevDefPtr dev,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
2011-09-02 13:28:27 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2014-07-03 19:43:05 +00:00
|
|
|
virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2014-07-03 19:43:05 +00:00
|
|
|
if (!dev->missing && !usbsrc->bus && !usbsrc->device) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("USB host device is missing bus/device information"));
|
2010-12-16 15:07:07 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-10-04 14:18:16 +00:00
|
|
|
virBufferAddLit(&buf, "usb-host");
|
|
|
|
if (!dev->missing) {
|
|
|
|
virBufferAsprintf(&buf, ",hostbus=%d,hostaddr=%d",
|
2014-07-03 19:43:05 +00:00
|
|
|
usbsrc->bus, usbsrc->device);
|
2012-10-04 14:18:16 +00:00
|
|
|
}
|
|
|
|
virBufferAsprintf(&buf, ",id=%s", dev->info->alias);
|
2012-11-14 14:51:30 +00:00
|
|
|
if (dev->info->bootIndex)
|
|
|
|
virBufferAsprintf(&buf, ",bootindex=%d", dev->info->bootIndex);
|
2011-09-02 13:28:27 +00:00
|
|
|
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, def, dev->info, qemuCaps) < 0)
|
2011-09-02 13:28:27 +00:00
|
|
|
goto error;
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2011-09-02 13:28:27 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-09-02 13:28:27 +00:00
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2011-09-02 13:28:27 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-18 14:30:28 +00:00
|
|
|
static char *
|
|
|
|
qemuBuildHubDevStr(const virDomainDef *def,
|
2013-08-02 17:48:50 +00:00
|
|
|
virDomainHubDefPtr dev,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2011-09-02 14:20:40 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
if (dev->type != VIR_DOMAIN_HUB_TYPE_USB) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("hub type %s not supported"),
|
|
|
|
virDomainHubTypeToString(dev->type));
|
2011-09-02 14:20:40 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_USB_HUB)) {
|
maint: don't permit format strings without %
Any time we have a string with no % passed through gettext, a
translator can inject a % to cause a stack overread. When there
is nothing to format, it's easier to ask for a string that cannot
be used as a formatter, by using a trivial "%s" format instead.
In the past, we have used --disable-nls to catch some of the
offenders, but that doesn't get run very often, and many more
uses have crept in. Syntax check to the rescue!
The syntax check can catch uses such as
virReportError(code,
_("split "
"string"));
by using a sed script to fold context lines into one pattern
space before checking for a string without %.
This patch is just mechanical insertion of %s; there are probably
several messages touched by this patch where we would be better
off giving the user more information than a fixed string.
* cfg.mk (sc_prohibit_diagnostic_without_format): New rule.
* src/datatypes.c (virUnrefConnect, virGetDomain)
(virUnrefDomain, virGetNetwork, virUnrefNetwork, virGetInterface)
(virUnrefInterface, virGetStoragePool, virUnrefStoragePool)
(virGetStorageVol, virUnrefStorageVol, virGetNodeDevice)
(virGetSecret, virUnrefSecret, virGetNWFilter, virUnrefNWFilter)
(virGetDomainSnapshot, virUnrefDomainSnapshot): Add %s wrapper.
* src/lxc/lxc_driver.c (lxcDomainSetBlkioParameters)
(lxcDomainGetBlkioParameters): Likewise.
* src/conf/domain_conf.c (virSecurityDeviceLabelDefParseXML)
(virDomainDiskDefParseXML, virDomainGraphicsDefParseXML):
Likewise.
* src/conf/network_conf.c (virNetworkDNSHostsDefParseXML)
(virNetworkDefParseXML): Likewise.
* src/conf/nwfilter_conf.c (virNWFilterIsValidChainName):
Likewise.
* src/conf/nwfilter_params.c (virNWFilterVarValueCreateSimple)
(virNWFilterVarAccessParse): Likewise.
* src/libvirt.c (virDomainSave, virDomainSaveFlags)
(virDomainRestore, virDomainRestoreFlags)
(virDomainSaveImageGetXMLDesc, virDomainSaveImageDefineXML)
(virDomainCoreDump, virDomainGetXMLDesc)
(virDomainMigrateVersion1, virDomainMigrateVersion2)
(virDomainMigrateVersion3, virDomainMigrate, virDomainMigrate2)
(virStreamSendAll, virStreamRecvAll)
(virDomainSnapshotGetXMLDesc): Likewise.
* src/nwfilter/nwfilter_dhcpsnoop.c (virNWFilterSnoopReqLeaseDel)
(virNWFilterDHCPSnoopReq): Likewise.
* src/openvz/openvz_driver.c (openvzUpdateDevice): Likewise.
* src/openvz/openvz_util.c (openvzKBPerPages): Likewise.
* src/qemu/qemu_cgroup.c (qemuSetupCgroup): Likewise.
* src/qemu/qemu_command.c (qemuBuildHubDevStr, qemuBuildChrChardevStr)
(qemuBuildCommandLine): Likewise.
* src/qemu/qemu_driver.c (qemuDomainGetPercpuStats): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
* src/rpc/virnetsaslcontext.c (virNetSASLSessionGetIdentity):
Likewise.
* src/rpc/virnetsocket.c (virNetSocketNewConnectUNIX)
(virNetSocketSendFD, virNetSocketRecvFD): Likewise.
* src/storage/storage_backend_disk.c
(virStorageBackendDiskBuildPool): Likewise.
* src/storage/storage_backend_fs.c
(virStorageBackendFileSystemProbe)
(virStorageBackendFileSystemBuild): Likewise.
* src/storage/storage_backend_rbd.c
(virStorageBackendRBDOpenRADOSConn): Likewise.
* src/storage/storage_driver.c (storageVolumeResize): Likewise.
* src/test/test_driver.c (testInterfaceChangeBegin)
(testInterfaceChangeCommit, testInterfaceChangeRollback):
Likewise.
* src/vbox/vbox_tmpl.c (vboxListAllDomains): Likewise.
* src/xenxs/xen_sxpr.c (xenFormatSxprDisk, xenFormatSxpr):
Likewise.
* src/xenxs/xen_xm.c (xenXMConfigGetUUID, xenFormatXMDisk)
(xenFormatXM): Likewise.
2012-07-23 20:33:08 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2012-07-18 15:22:03 +00:00
|
|
|
_("usb-hub not supported by QEMU binary"));
|
2011-09-02 14:20:40 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "usb-hub");
|
|
|
|
virBufferAsprintf(&buf, ",id=%s", dev->info.alias);
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, def, &dev->info, qemuCaps) < 0)
|
2011-09-02 14:20:40 +00:00
|
|
|
goto error;
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2011-09-02 14:20:40 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2011-09-02 14:20:40 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-18 14:30:28 +00:00
|
|
|
static int
|
|
|
|
qemuBuildHubCommandLine(virCommandPtr cmd,
|
|
|
|
const virDomainDef *def,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < def->nhubs; i++) {
|
|
|
|
virDomainHubDefPtr hub = def->hubs[i];
|
|
|
|
char *optstr;
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
if (!(optstr = qemuBuildHubDevStr(def, hub, qemuCaps)))
|
|
|
|
return -1;
|
|
|
|
virCommandAddArg(cmd, optstr);
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
char *
|
2014-03-13 11:58:17 +00:00
|
|
|
qemuBuildUSBHostdevUSBDevStr(virDomainHostdevDefPtr dev)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
char *ret = NULL;
|
2014-07-03 19:43:05 +00:00
|
|
|
virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-10-04 14:18:16 +00:00
|
|
|
if (dev->missing) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("This QEMU doesn't not support missing USB devices"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-07-03 19:43:05 +00:00
|
|
|
if (!usbsrc->bus && !usbsrc->device) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("USB host device is missing bus/device information"));
|
2010-12-16 15:07:07 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-07-03 19:43:05 +00:00
|
|
|
ignore_value(virAsprintf(&ret, "host:%d.%d", usbsrc->bus, usbsrc->device));
|
2010-12-16 15:07:07 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-07-09 13:31:38 +00:00
|
|
|
static char *
|
|
|
|
qemuBuildSCSIHostHostdevDrvStr(virDomainHostdevDefPtr dev,
|
|
|
|
virQEMUCapsPtr qemuCaps ATTRIBUTE_UNUSED,
|
|
|
|
qemuBuildCommandLineCallbacksPtr callbacks)
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
{
|
2014-07-03 21:01:10 +00:00
|
|
|
virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi;
|
2014-06-20 15:35:46 +00:00
|
|
|
virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
char *sg = NULL;
|
|
|
|
|
2014-01-30 07:05:59 +00:00
|
|
|
sg = (callbacks->qemuGetSCSIDeviceSgName)(NULL,
|
2014-06-20 15:35:46 +00:00
|
|
|
scsihostsrc->adapter,
|
|
|
|
scsihostsrc->bus,
|
|
|
|
scsihostsrc->target,
|
|
|
|
scsihostsrc->unit);
|
2014-07-09 13:31:38 +00:00
|
|
|
return sg;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
qemuBuildSCSIiSCSIHostdevDrvStr(virConnectPtr conn,
|
|
|
|
virDomainHostdevDefPtr dev)
|
|
|
|
{
|
|
|
|
char *source = NULL;
|
|
|
|
char *secret = NULL;
|
|
|
|
char *username = NULL;
|
2014-11-10 16:55:26 +00:00
|
|
|
virStorageSource src;
|
|
|
|
|
|
|
|
memset(&src, 0, sizeof(src));
|
|
|
|
|
2014-07-09 13:31:38 +00:00
|
|
|
virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi;
|
|
|
|
virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi;
|
|
|
|
|
|
|
|
if (conn && iscsisrc->auth) {
|
|
|
|
const char *protocol =
|
|
|
|
virStorageNetProtocolTypeToString(VIR_STORAGE_NET_PROTOCOL_ISCSI);
|
|
|
|
bool encode = false;
|
|
|
|
int secretType = VIR_SECRET_USAGE_TYPE_ISCSI;
|
|
|
|
|
|
|
|
username = iscsisrc->auth->username;
|
|
|
|
if (!(secret = qemuGetSecretString(conn, protocol, encode,
|
|
|
|
iscsisrc->auth, secretType)))
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-11-10 16:55:26 +00:00
|
|
|
src.protocol = VIR_STORAGE_NET_PROTOCOL_ISCSI;
|
|
|
|
src.path = iscsisrc->path;
|
|
|
|
src.hosts = iscsisrc->hosts;
|
|
|
|
src.nhosts = iscsisrc->nhosts;
|
|
|
|
|
2014-07-09 13:31:38 +00:00
|
|
|
/* Rather than pull what we think we want - use the network disk code */
|
2014-11-10 16:55:26 +00:00
|
|
|
source = qemuBuildNetworkDriveURI(&src, username, secret);
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
|
2014-07-09 13:31:38 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(secret);
|
|
|
|
return source;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
qemuBuildSCSIHostdevDrvStr(virConnectPtr conn,
|
|
|
|
virDomainHostdevDefPtr dev,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
qemuBuildCommandLineCallbacksPtr callbacks)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
char *source = NULL;
|
|
|
|
virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi;
|
|
|
|
|
|
|
|
if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
|
|
|
|
if (!(source = qemuBuildSCSIiSCSIHostdevDrvStr(conn, dev)))
|
|
|
|
goto error;
|
|
|
|
virBufferAsprintf(&buf, "file=%s,if=none,format=raw", source);
|
|
|
|
} else {
|
|
|
|
if (!(source = qemuBuildSCSIHostHostdevDrvStr(dev, qemuCaps,
|
|
|
|
callbacks)))
|
|
|
|
goto error;
|
|
|
|
virBufferAsprintf(&buf, "file=/dev/%s,if=none", source);
|
|
|
|
}
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
virBufferAsprintf(&buf, ",id=%s-%s",
|
|
|
|
virDomainDeviceAddressTypeToString(dev->info->type),
|
|
|
|
dev->info->alias);
|
|
|
|
|
2013-05-03 18:07:25 +00:00
|
|
|
if (dev->readonly) {
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_READONLY)) {
|
|
|
|
virBufferAddLit(&buf, ",readonly=on");
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("this qemu doesn't support 'readonly' "
|
|
|
|
"for -drive"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
goto error;
|
|
|
|
|
2014-07-09 13:31:38 +00:00
|
|
|
VIR_FREE(source);
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
return virBufferContentAndReset(&buf);
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2014-07-09 13:31:38 +00:00
|
|
|
VIR_FREE(source);
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
qemuBuildSCSIHostdevDevStr(virDomainDefPtr def,
|
|
|
|
virDomainHostdevDefPtr dev,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
int model = -1;
|
2015-04-30 17:19:10 +00:00
|
|
|
const char *contAlias;
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
|
|
|
|
model = virDomainDeviceFindControllerModel(def, dev->info,
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_SCSI);
|
|
|
|
|
2016-02-15 18:08:02 +00:00
|
|
|
if (qemuDomainSetSCSIControllerModel(def, qemuCaps, &model) < 0)
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC) {
|
|
|
|
if (dev->info->addr.drive.target != 0) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("target must be 0 for scsi host device "
|
|
|
|
"if its controller model is 'lsilogic'"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->info->addr.drive.unit > 7) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("unit must be not more than 7 for scsi host "
|
|
|
|
"device if its controller model is 'lsilogic'"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "scsi-generic");
|
|
|
|
|
2015-04-30 17:19:10 +00:00
|
|
|
if (!(contAlias = virDomainControllerAliasFind(def, VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
|
|
|
|
dev->info->addr.drive.controller)))
|
|
|
|
goto error;
|
|
|
|
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
if (model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC) {
|
2015-04-30 17:19:10 +00:00
|
|
|
virBufferAsprintf(&buf, ",bus=%s.%d,scsi-id=%d",
|
|
|
|
contAlias,
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
dev->info->addr.drive.bus,
|
|
|
|
dev->info->addr.drive.unit);
|
|
|
|
} else {
|
2015-04-30 17:19:10 +00:00
|
|
|
virBufferAsprintf(&buf, ",bus=%s.0,channel=%d,scsi-id=%d,lun=%d",
|
|
|
|
contAlias,
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
dev->info->addr.drive.bus,
|
|
|
|
dev->info->addr.drive.target,
|
|
|
|
dev->info->addr.drive.unit);
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
virBufferAsprintf(&buf, ",drive=%s-%s,id=%s",
|
|
|
|
virDomainDeviceAddressTypeToString(dev->info->type),
|
|
|
|
dev->info->alias, dev->info->alias);
|
|
|
|
|
2013-05-03 18:07:26 +00:00
|
|
|
if (dev->info->bootIndex)
|
|
|
|
virBufferAsprintf(&buf, ",bootindex=%d", dev->info->bootIndex);
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2016-02-23 13:05:09 +00:00
|
|
|
static int
|
|
|
|
qemuBuildChrChardevFileStr(virLogManagerPtr logManager,
|
|
|
|
virCommandPtr cmd,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
virBufferPtr buf,
|
|
|
|
const char *filearg, const char *fileval,
|
|
|
|
const char *appendarg, int appendval)
|
|
|
|
{
|
|
|
|
if (logManager) {
|
|
|
|
char *fdset, *fdpath;
|
|
|
|
int flags = 0;
|
|
|
|
int logfd;
|
|
|
|
|
|
|
|
if (appendval == VIR_TRISTATE_SWITCH_OFF)
|
|
|
|
flags |= VIR_LOG_MANAGER_PROTOCOL_DOMAIN_OPEN_LOG_FILE_TRUNCATE;
|
|
|
|
|
|
|
|
if ((logfd = virLogManagerDomainOpenLogFile(logManager,
|
|
|
|
"qemu",
|
|
|
|
def->uuid,
|
|
|
|
def->name,
|
|
|
|
fileval,
|
|
|
|
flags,
|
|
|
|
NULL, NULL)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
virCommandPassFD(cmd, logfd, VIR_COMMAND_PASS_FD_CLOSE_PARENT);
|
|
|
|
if (!(fdset = qemuVirCommandGetFDSet(cmd, logfd)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-add-fd");
|
|
|
|
virCommandAddArg(cmd, fdset);
|
|
|
|
VIR_FREE(fdset);
|
|
|
|
|
|
|
|
if (!(fdpath = qemuVirCommandGetDevSet(cmd, logfd)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
virBufferAsprintf(buf, ",%s=%s,%s=on", filearg, fdpath, appendarg);
|
|
|
|
VIR_FREE(fdpath);
|
|
|
|
} else {
|
|
|
|
virBufferAsprintf(buf, ",%s=%s", filearg, fileval);
|
|
|
|
if (appendval != VIR_TRISTATE_SWITCH_ABSENT) {
|
|
|
|
virBufferAsprintf(buf, ",%s=%s", appendarg,
|
|
|
|
virTristateSwitchTypeToString(appendval));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
/* This function outputs a -chardev command line option which describes only the
|
|
|
|
* host side of the character device */
|
domain_conf: split source data out from ChrDef
This opens up the possibility of reusing the smaller ChrSourceDef
for both qemu monitor and a passthrough smartcard device.
* src/conf/domain_conf.h (_virDomainChrDef): Factor host
details...
(_virDomainChrSourceDef): ...into new struct.
(virDomainChrSourceDefFree): New prototype.
* src/conf/domain_conf.c (virDomainChrDefFree)
(virDomainChrDefParseXML, virDomainChrDefFormat): Split...
(virDomainChrSourceDefClear, virDomainChrSourceDefFree)
(virDomainChrSourceDefParseXML, virDomainChrSourceDefFormat):
...into new functions.
(virDomainChrDefParseTargetXML): Update clients to reflect type
split.
* src/vmx/vmx.c (virVMXParseSerial, virVMXParseParallel)
(virVMXFormatSerial, virVMXFormatParallel): Likewise.
* src/xen/xen_driver.c (xenUnifiedDomainOpenConsole): Likewise.
* src/xen/xend_internal.c (xenDaemonParseSxprChar)
(xenDaemonFormatSxprChr): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainDumpXML, vboxAttachSerial)
(vboxAttachParallel): Likewise.
* src/security/security_dac.c (virSecurityDACSetChardevLabel)
(virSecurityDACSetChardevCallback)
(virSecurityDACRestoreChardevLabel)
(virSecurityDACRestoreChardevCallback): Likewise.
* src/security/security_selinux.c (SELinuxSetSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback)
(SELinuxRestoreSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback): Likewise.
* src/security/virt-aa-helper.c (get_files): Likewise.
* src/lxc/lxc_driver.c (lxcVmStart, lxcDomainOpenConsole):
Likewise.
* src/uml/uml_conf.c (umlBuildCommandLineChr): Likewise.
* src/uml/uml_driver.c (umlIdentifyOneChrPTY, umlIdentifyChrPTY)
(umlDomainOpenConsole): Likewise.
* src/qemu/qemu_command.c (qemuBuildChrChardevStr)
(qemuBuildChrArgStr, qemuBuildCommandLine)
(qemuParseCommandLineChr): Likewise.
* src/qemu/qemu_domain.c (qemuDomainObjPrivateXMLFormat)
(qemuDomainObjPrivateXMLParse): Likewise.
* src/qemu/qemu_cgroup.c (qemuSetupChardevCgroup): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
* src/qemu/qemu_driver.c (qemudFindCharDevicePTYsMonitor)
(qemudFindCharDevicePTYs, qemuPrepareChardevDevice)
(qemuPrepareMonitorChr, qemudShutdownVMDaemon)
(qemuDomainOpenConsole): Likewise.
* src/qemu/qemu_command.h (qemuBuildChrChardevStr)
(qemuBuildChrArgStr): Delete, now that they are static.
* src/libvirt_private.syms (domain_conf.h): New exports.
* cfg.mk (useless_free_options): Update list.
* tests/qemuxml2argvtest.c (testCompareXMLToArgvFiles): Update
tests.
2011-01-07 22:45:01 +00:00
|
|
|
static char *
|
2016-02-23 13:05:09 +00:00
|
|
|
qemuBuildChrChardevStr(virLogManagerPtr logManager,
|
|
|
|
virCommandPtr cmd,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
const virDomainChrSourceDef *dev,
|
2016-02-17 22:27:21 +00:00
|
|
|
const char *alias,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
bool telnet;
|
|
|
|
|
2012-10-17 09:23:12 +00:00
|
|
|
switch (dev->type) {
|
2010-12-16 15:07:07 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_NULL:
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "null,id=char%s", alias);
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_VC:
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "vc,id=char%s", alias);
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_PTY:
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "pty,id=char%s", alias);
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_DEV:
|
2012-05-23 05:50:02 +00:00
|
|
|
virBufferAsprintf(&buf, "%s,id=char%s,path=%s",
|
|
|
|
STRPREFIX(alias, "parallel") ? "parport" : "tty",
|
|
|
|
alias, dev->data.file.path);
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_FILE:
|
2016-02-23 13:41:57 +00:00
|
|
|
virBufferAsprintf(&buf, "file,id=char%s", alias);
|
2015-12-24 14:27:55 +00:00
|
|
|
|
2016-02-23 13:41:57 +00:00
|
|
|
if (dev->data.file.append != VIR_TRISTATE_SWITCH_ABSENT &&
|
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CHARDEV_FILE_APPEND)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("append not supported in this QEMU binary"));
|
|
|
|
goto error;
|
2015-12-24 14:27:55 +00:00
|
|
|
}
|
2016-02-23 13:41:57 +00:00
|
|
|
if (qemuBuildChrChardevFileStr(virQEMUCapsGet(qemuCaps, QEMU_CAPS_CHARDEV_FILE_APPEND) ?
|
|
|
|
logManager : NULL, cmd, def, &buf,
|
|
|
|
"path", dev->data.file.path,
|
|
|
|
"append", dev->data.file.append) < 0)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_PIPE:
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "pipe,id=char%s,path=%s", alias,
|
domain_conf: split source data out from ChrDef
This opens up the possibility of reusing the smaller ChrSourceDef
for both qemu monitor and a passthrough smartcard device.
* src/conf/domain_conf.h (_virDomainChrDef): Factor host
details...
(_virDomainChrSourceDef): ...into new struct.
(virDomainChrSourceDefFree): New prototype.
* src/conf/domain_conf.c (virDomainChrDefFree)
(virDomainChrDefParseXML, virDomainChrDefFormat): Split...
(virDomainChrSourceDefClear, virDomainChrSourceDefFree)
(virDomainChrSourceDefParseXML, virDomainChrSourceDefFormat):
...into new functions.
(virDomainChrDefParseTargetXML): Update clients to reflect type
split.
* src/vmx/vmx.c (virVMXParseSerial, virVMXParseParallel)
(virVMXFormatSerial, virVMXFormatParallel): Likewise.
* src/xen/xen_driver.c (xenUnifiedDomainOpenConsole): Likewise.
* src/xen/xend_internal.c (xenDaemonParseSxprChar)
(xenDaemonFormatSxprChr): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainDumpXML, vboxAttachSerial)
(vboxAttachParallel): Likewise.
* src/security/security_dac.c (virSecurityDACSetChardevLabel)
(virSecurityDACSetChardevCallback)
(virSecurityDACRestoreChardevLabel)
(virSecurityDACRestoreChardevCallback): Likewise.
* src/security/security_selinux.c (SELinuxSetSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback)
(SELinuxRestoreSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback): Likewise.
* src/security/virt-aa-helper.c (get_files): Likewise.
* src/lxc/lxc_driver.c (lxcVmStart, lxcDomainOpenConsole):
Likewise.
* src/uml/uml_conf.c (umlBuildCommandLineChr): Likewise.
* src/uml/uml_driver.c (umlIdentifyOneChrPTY, umlIdentifyChrPTY)
(umlDomainOpenConsole): Likewise.
* src/qemu/qemu_command.c (qemuBuildChrChardevStr)
(qemuBuildChrArgStr, qemuBuildCommandLine)
(qemuParseCommandLineChr): Likewise.
* src/qemu/qemu_domain.c (qemuDomainObjPrivateXMLFormat)
(qemuDomainObjPrivateXMLParse): Likewise.
* src/qemu/qemu_cgroup.c (qemuSetupChardevCgroup): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
* src/qemu/qemu_driver.c (qemudFindCharDevicePTYsMonitor)
(qemudFindCharDevicePTYs, qemuPrepareChardevDevice)
(qemuPrepareMonitorChr, qemudShutdownVMDaemon)
(qemuDomainOpenConsole): Likewise.
* src/qemu/qemu_command.h (qemuBuildChrChardevStr)
(qemuBuildChrArgStr): Delete, now that they are static.
* src/libvirt_private.syms (domain_conf.h): New exports.
* cfg.mk (useless_free_options): Update list.
* tests/qemuxml2argvtest.c (testCompareXMLToArgvFiles): Update
tests.
2011-01-07 22:45:01 +00:00
|
|
|
dev->data.file.path);
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_STDIO:
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "stdio,id=char%s", alias);
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
|
2011-08-11 07:19:51 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_UDP: {
|
|
|
|
const char *connectHost = dev->data.udp.connectHost;
|
|
|
|
const char *bindHost = dev->data.udp.bindHost;
|
|
|
|
const char *bindService = dev->data.udp.bindService;
|
|
|
|
|
|
|
|
if (connectHost == NULL)
|
|
|
|
connectHost = "";
|
|
|
|
if (bindHost == NULL)
|
|
|
|
bindHost = "";
|
|
|
|
if (bindService == NULL)
|
|
|
|
bindService = "0";
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf,
|
2011-01-25 21:59:50 +00:00
|
|
|
"udp,id=char%s,host=%s,port=%s,localaddr=%s,"
|
|
|
|
"localport=%s",
|
domain_conf: split source data out from ChrDef
This opens up the possibility of reusing the smaller ChrSourceDef
for both qemu monitor and a passthrough smartcard device.
* src/conf/domain_conf.h (_virDomainChrDef): Factor host
details...
(_virDomainChrSourceDef): ...into new struct.
(virDomainChrSourceDefFree): New prototype.
* src/conf/domain_conf.c (virDomainChrDefFree)
(virDomainChrDefParseXML, virDomainChrDefFormat): Split...
(virDomainChrSourceDefClear, virDomainChrSourceDefFree)
(virDomainChrSourceDefParseXML, virDomainChrSourceDefFormat):
...into new functions.
(virDomainChrDefParseTargetXML): Update clients to reflect type
split.
* src/vmx/vmx.c (virVMXParseSerial, virVMXParseParallel)
(virVMXFormatSerial, virVMXFormatParallel): Likewise.
* src/xen/xen_driver.c (xenUnifiedDomainOpenConsole): Likewise.
* src/xen/xend_internal.c (xenDaemonParseSxprChar)
(xenDaemonFormatSxprChr): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainDumpXML, vboxAttachSerial)
(vboxAttachParallel): Likewise.
* src/security/security_dac.c (virSecurityDACSetChardevLabel)
(virSecurityDACSetChardevCallback)
(virSecurityDACRestoreChardevLabel)
(virSecurityDACRestoreChardevCallback): Likewise.
* src/security/security_selinux.c (SELinuxSetSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback)
(SELinuxRestoreSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback): Likewise.
* src/security/virt-aa-helper.c (get_files): Likewise.
* src/lxc/lxc_driver.c (lxcVmStart, lxcDomainOpenConsole):
Likewise.
* src/uml/uml_conf.c (umlBuildCommandLineChr): Likewise.
* src/uml/uml_driver.c (umlIdentifyOneChrPTY, umlIdentifyChrPTY)
(umlDomainOpenConsole): Likewise.
* src/qemu/qemu_command.c (qemuBuildChrChardevStr)
(qemuBuildChrArgStr, qemuBuildCommandLine)
(qemuParseCommandLineChr): Likewise.
* src/qemu/qemu_domain.c (qemuDomainObjPrivateXMLFormat)
(qemuDomainObjPrivateXMLParse): Likewise.
* src/qemu/qemu_cgroup.c (qemuSetupChardevCgroup): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
* src/qemu/qemu_driver.c (qemudFindCharDevicePTYsMonitor)
(qemudFindCharDevicePTYs, qemuPrepareChardevDevice)
(qemuPrepareMonitorChr, qemudShutdownVMDaemon)
(qemuDomainOpenConsole): Likewise.
* src/qemu/qemu_command.h (qemuBuildChrChardevStr)
(qemuBuildChrArgStr): Delete, now that they are static.
* src/libvirt_private.syms (domain_conf.h): New exports.
* cfg.mk (useless_free_options): Update list.
* tests/qemuxml2argvtest.c (testCompareXMLToArgvFiles): Update
tests.
2011-01-07 22:45:01 +00:00
|
|
|
alias,
|
2011-08-11 07:19:51 +00:00
|
|
|
connectHost,
|
2010-12-16 15:07:07 +00:00
|
|
|
dev->data.udp.connectService,
|
2011-08-11 07:19:51 +00:00
|
|
|
bindHost, bindService);
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
2011-08-11 07:19:51 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_TCP:
|
|
|
|
telnet = dev->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf,
|
2011-01-25 21:59:50 +00:00
|
|
|
"socket,id=char%s,host=%s,port=%s%s%s",
|
domain_conf: split source data out from ChrDef
This opens up the possibility of reusing the smaller ChrSourceDef
for both qemu monitor and a passthrough smartcard device.
* src/conf/domain_conf.h (_virDomainChrDef): Factor host
details...
(_virDomainChrSourceDef): ...into new struct.
(virDomainChrSourceDefFree): New prototype.
* src/conf/domain_conf.c (virDomainChrDefFree)
(virDomainChrDefParseXML, virDomainChrDefFormat): Split...
(virDomainChrSourceDefClear, virDomainChrSourceDefFree)
(virDomainChrSourceDefParseXML, virDomainChrSourceDefFormat):
...into new functions.
(virDomainChrDefParseTargetXML): Update clients to reflect type
split.
* src/vmx/vmx.c (virVMXParseSerial, virVMXParseParallel)
(virVMXFormatSerial, virVMXFormatParallel): Likewise.
* src/xen/xen_driver.c (xenUnifiedDomainOpenConsole): Likewise.
* src/xen/xend_internal.c (xenDaemonParseSxprChar)
(xenDaemonFormatSxprChr): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainDumpXML, vboxAttachSerial)
(vboxAttachParallel): Likewise.
* src/security/security_dac.c (virSecurityDACSetChardevLabel)
(virSecurityDACSetChardevCallback)
(virSecurityDACRestoreChardevLabel)
(virSecurityDACRestoreChardevCallback): Likewise.
* src/security/security_selinux.c (SELinuxSetSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback)
(SELinuxRestoreSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback): Likewise.
* src/security/virt-aa-helper.c (get_files): Likewise.
* src/lxc/lxc_driver.c (lxcVmStart, lxcDomainOpenConsole):
Likewise.
* src/uml/uml_conf.c (umlBuildCommandLineChr): Likewise.
* src/uml/uml_driver.c (umlIdentifyOneChrPTY, umlIdentifyChrPTY)
(umlDomainOpenConsole): Likewise.
* src/qemu/qemu_command.c (qemuBuildChrChardevStr)
(qemuBuildChrArgStr, qemuBuildCommandLine)
(qemuParseCommandLineChr): Likewise.
* src/qemu/qemu_domain.c (qemuDomainObjPrivateXMLFormat)
(qemuDomainObjPrivateXMLParse): Likewise.
* src/qemu/qemu_cgroup.c (qemuSetupChardevCgroup): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
* src/qemu/qemu_driver.c (qemudFindCharDevicePTYsMonitor)
(qemudFindCharDevicePTYs, qemuPrepareChardevDevice)
(qemuPrepareMonitorChr, qemudShutdownVMDaemon)
(qemuDomainOpenConsole): Likewise.
* src/qemu/qemu_command.h (qemuBuildChrChardevStr)
(qemuBuildChrArgStr): Delete, now that they are static.
* src/libvirt_private.syms (domain_conf.h): New exports.
* cfg.mk (useless_free_options): Update list.
* tests/qemuxml2argvtest.c (testCompareXMLToArgvFiles): Update
tests.
2011-01-07 22:45:01 +00:00
|
|
|
alias,
|
2010-12-16 15:07:07 +00:00
|
|
|
dev->data.tcp.host,
|
|
|
|
dev->data.tcp.service,
|
|
|
|
telnet ? ",telnet" : "",
|
|
|
|
dev->data.tcp.listen ? ",server,nowait" : "");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf,
|
2011-01-25 21:59:50 +00:00
|
|
|
"socket,id=char%s,path=%s%s",
|
domain_conf: split source data out from ChrDef
This opens up the possibility of reusing the smaller ChrSourceDef
for both qemu monitor and a passthrough smartcard device.
* src/conf/domain_conf.h (_virDomainChrDef): Factor host
details...
(_virDomainChrSourceDef): ...into new struct.
(virDomainChrSourceDefFree): New prototype.
* src/conf/domain_conf.c (virDomainChrDefFree)
(virDomainChrDefParseXML, virDomainChrDefFormat): Split...
(virDomainChrSourceDefClear, virDomainChrSourceDefFree)
(virDomainChrSourceDefParseXML, virDomainChrSourceDefFormat):
...into new functions.
(virDomainChrDefParseTargetXML): Update clients to reflect type
split.
* src/vmx/vmx.c (virVMXParseSerial, virVMXParseParallel)
(virVMXFormatSerial, virVMXFormatParallel): Likewise.
* src/xen/xen_driver.c (xenUnifiedDomainOpenConsole): Likewise.
* src/xen/xend_internal.c (xenDaemonParseSxprChar)
(xenDaemonFormatSxprChr): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainDumpXML, vboxAttachSerial)
(vboxAttachParallel): Likewise.
* src/security/security_dac.c (virSecurityDACSetChardevLabel)
(virSecurityDACSetChardevCallback)
(virSecurityDACRestoreChardevLabel)
(virSecurityDACRestoreChardevCallback): Likewise.
* src/security/security_selinux.c (SELinuxSetSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback)
(SELinuxRestoreSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback): Likewise.
* src/security/virt-aa-helper.c (get_files): Likewise.
* src/lxc/lxc_driver.c (lxcVmStart, lxcDomainOpenConsole):
Likewise.
* src/uml/uml_conf.c (umlBuildCommandLineChr): Likewise.
* src/uml/uml_driver.c (umlIdentifyOneChrPTY, umlIdentifyChrPTY)
(umlDomainOpenConsole): Likewise.
* src/qemu/qemu_command.c (qemuBuildChrChardevStr)
(qemuBuildChrArgStr, qemuBuildCommandLine)
(qemuParseCommandLineChr): Likewise.
* src/qemu/qemu_domain.c (qemuDomainObjPrivateXMLFormat)
(qemuDomainObjPrivateXMLParse): Likewise.
* src/qemu/qemu_cgroup.c (qemuSetupChardevCgroup): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
* src/qemu/qemu_driver.c (qemudFindCharDevicePTYsMonitor)
(qemudFindCharDevicePTYs, qemuPrepareChardevDevice)
(qemuPrepareMonitorChr, qemudShutdownVMDaemon)
(qemuDomainOpenConsole): Likewise.
* src/qemu/qemu_command.h (qemuBuildChrChardevStr)
(qemuBuildChrArgStr): Delete, now that they are static.
* src/libvirt_private.syms (domain_conf.h): New exports.
* cfg.mk (useless_free_options): Update list.
* tests/qemuxml2argvtest.c (testCompareXMLToArgvFiles): Update
tests.
2011-01-07 22:45:01 +00:00
|
|
|
alias,
|
2010-12-16 15:07:07 +00:00
|
|
|
dev->data.nix.path,
|
|
|
|
dev->data.nix.listen ? ",server,nowait" : "");
|
|
|
|
break;
|
2011-02-03 04:09:44 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CHARDEV_SPICEVMC)) {
|
maint: don't permit format strings without %
Any time we have a string with no % passed through gettext, a
translator can inject a % to cause a stack overread. When there
is nothing to format, it's easier to ask for a string that cannot
be used as a formatter, by using a trivial "%s" format instead.
In the past, we have used --disable-nls to catch some of the
offenders, but that doesn't get run very often, and many more
uses have crept in. Syntax check to the rescue!
The syntax check can catch uses such as
virReportError(code,
_("split "
"string"));
by using a sed script to fold context lines into one pattern
space before checking for a string without %.
This patch is just mechanical insertion of %s; there are probably
several messages touched by this patch where we would be better
off giving the user more information than a fixed string.
* cfg.mk (sc_prohibit_diagnostic_without_format): New rule.
* src/datatypes.c (virUnrefConnect, virGetDomain)
(virUnrefDomain, virGetNetwork, virUnrefNetwork, virGetInterface)
(virUnrefInterface, virGetStoragePool, virUnrefStoragePool)
(virGetStorageVol, virUnrefStorageVol, virGetNodeDevice)
(virGetSecret, virUnrefSecret, virGetNWFilter, virUnrefNWFilter)
(virGetDomainSnapshot, virUnrefDomainSnapshot): Add %s wrapper.
* src/lxc/lxc_driver.c (lxcDomainSetBlkioParameters)
(lxcDomainGetBlkioParameters): Likewise.
* src/conf/domain_conf.c (virSecurityDeviceLabelDefParseXML)
(virDomainDiskDefParseXML, virDomainGraphicsDefParseXML):
Likewise.
* src/conf/network_conf.c (virNetworkDNSHostsDefParseXML)
(virNetworkDefParseXML): Likewise.
* src/conf/nwfilter_conf.c (virNWFilterIsValidChainName):
Likewise.
* src/conf/nwfilter_params.c (virNWFilterVarValueCreateSimple)
(virNWFilterVarAccessParse): Likewise.
* src/libvirt.c (virDomainSave, virDomainSaveFlags)
(virDomainRestore, virDomainRestoreFlags)
(virDomainSaveImageGetXMLDesc, virDomainSaveImageDefineXML)
(virDomainCoreDump, virDomainGetXMLDesc)
(virDomainMigrateVersion1, virDomainMigrateVersion2)
(virDomainMigrateVersion3, virDomainMigrate, virDomainMigrate2)
(virStreamSendAll, virStreamRecvAll)
(virDomainSnapshotGetXMLDesc): Likewise.
* src/nwfilter/nwfilter_dhcpsnoop.c (virNWFilterSnoopReqLeaseDel)
(virNWFilterDHCPSnoopReq): Likewise.
* src/openvz/openvz_driver.c (openvzUpdateDevice): Likewise.
* src/openvz/openvz_util.c (openvzKBPerPages): Likewise.
* src/qemu/qemu_cgroup.c (qemuSetupCgroup): Likewise.
* src/qemu/qemu_command.c (qemuBuildHubDevStr, qemuBuildChrChardevStr)
(qemuBuildCommandLine): Likewise.
* src/qemu/qemu_driver.c (qemuDomainGetPercpuStats): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
* src/rpc/virnetsaslcontext.c (virNetSASLSessionGetIdentity):
Likewise.
* src/rpc/virnetsocket.c (virNetSocketNewConnectUNIX)
(virNetSocketSendFD, virNetSocketRecvFD): Likewise.
* src/storage/storage_backend_disk.c
(virStorageBackendDiskBuildPool): Likewise.
* src/storage/storage_backend_fs.c
(virStorageBackendFileSystemProbe)
(virStorageBackendFileSystemBuild): Likewise.
* src/storage/storage_backend_rbd.c
(virStorageBackendRBDOpenRADOSConn): Likewise.
* src/storage/storage_driver.c (storageVolumeResize): Likewise.
* src/test/test_driver.c (testInterfaceChangeBegin)
(testInterfaceChangeCommit, testInterfaceChangeRollback):
Likewise.
* src/vbox/vbox_tmpl.c (vboxListAllDomains): Likewise.
* src/xenxs/xen_sxpr.c (xenFormatSxprDisk, xenFormatSxpr):
Likewise.
* src/xenxs/xen_xm.c (xenXMConfigGetUUID, xenFormatXMDisk)
(xenFormatXM): Likewise.
2012-07-23 20:33:08 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2012-07-18 15:22:03 +00:00
|
|
|
_("spicevmc not supported in this QEMU binary"));
|
2011-02-03 04:09:44 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "spicevmc,id=char%s,name=%s", alias,
|
2011-02-04 02:23:31 +00:00
|
|
|
virDomainChrSpicevmcTypeToString(dev->data.spicevmc));
|
2011-02-03 04:09:44 +00:00
|
|
|
break;
|
|
|
|
|
2014-01-30 11:19:12 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CHARDEV_SPICEPORT)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("spiceport not supported in this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAsprintf(&buf, "spiceport,id=char%s,name=%s", alias,
|
|
|
|
dev->data.spiceport.channel);
|
|
|
|
break;
|
|
|
|
|
2011-02-03 04:09:44 +00:00
|
|
|
default:
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported chardev '%s'"),
|
|
|
|
virDomainChrTypeToString(dev->type));
|
2011-02-03 04:09:44 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2016-02-23 11:56:34 +00:00
|
|
|
if (dev->logfile) {
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CHARDEV_LOGFILE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("logfile not supported in this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
2016-02-23 13:05:09 +00:00
|
|
|
if (qemuBuildChrChardevFileStr(logManager, cmd, def, &buf,
|
|
|
|
"logfile", dev->logfile,
|
|
|
|
"logappend", dev->logappend) < 0)
|
|
|
|
goto error;
|
2016-02-23 11:56:34 +00:00
|
|
|
}
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
domain_conf: split source data out from ChrDef
This opens up the possibility of reusing the smaller ChrSourceDef
for both qemu monitor and a passthrough smartcard device.
* src/conf/domain_conf.h (_virDomainChrDef): Factor host
details...
(_virDomainChrSourceDef): ...into new struct.
(virDomainChrSourceDefFree): New prototype.
* src/conf/domain_conf.c (virDomainChrDefFree)
(virDomainChrDefParseXML, virDomainChrDefFormat): Split...
(virDomainChrSourceDefClear, virDomainChrSourceDefFree)
(virDomainChrSourceDefParseXML, virDomainChrSourceDefFormat):
...into new functions.
(virDomainChrDefParseTargetXML): Update clients to reflect type
split.
* src/vmx/vmx.c (virVMXParseSerial, virVMXParseParallel)
(virVMXFormatSerial, virVMXFormatParallel): Likewise.
* src/xen/xen_driver.c (xenUnifiedDomainOpenConsole): Likewise.
* src/xen/xend_internal.c (xenDaemonParseSxprChar)
(xenDaemonFormatSxprChr): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainDumpXML, vboxAttachSerial)
(vboxAttachParallel): Likewise.
* src/security/security_dac.c (virSecurityDACSetChardevLabel)
(virSecurityDACSetChardevCallback)
(virSecurityDACRestoreChardevLabel)
(virSecurityDACRestoreChardevCallback): Likewise.
* src/security/security_selinux.c (SELinuxSetSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback)
(SELinuxRestoreSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback): Likewise.
* src/security/virt-aa-helper.c (get_files): Likewise.
* src/lxc/lxc_driver.c (lxcVmStart, lxcDomainOpenConsole):
Likewise.
* src/uml/uml_conf.c (umlBuildCommandLineChr): Likewise.
* src/uml/uml_driver.c (umlIdentifyOneChrPTY, umlIdentifyChrPTY)
(umlDomainOpenConsole): Likewise.
* src/qemu/qemu_command.c (qemuBuildChrChardevStr)
(qemuBuildChrArgStr, qemuBuildCommandLine)
(qemuParseCommandLineChr): Likewise.
* src/qemu/qemu_domain.c (qemuDomainObjPrivateXMLFormat)
(qemuDomainObjPrivateXMLParse): Likewise.
* src/qemu/qemu_cgroup.c (qemuSetupChardevCgroup): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
* src/qemu/qemu_driver.c (qemudFindCharDevicePTYsMonitor)
(qemudFindCharDevicePTYs, qemuPrepareChardevDevice)
(qemuPrepareMonitorChr, qemudShutdownVMDaemon)
(qemuDomainOpenConsole): Likewise.
* src/qemu/qemu_command.h (qemuBuildChrChardevStr)
(qemuBuildChrArgStr): Delete, now that they are static.
* src/libvirt_private.syms (domain_conf.h): New exports.
* cfg.mk (useless_free_options): Update list.
* tests/qemuxml2argvtest.c (testCompareXMLToArgvFiles): Update
tests.
2011-01-07 22:45:01 +00:00
|
|
|
static char *
|
2016-02-17 22:27:21 +00:00
|
|
|
qemuBuildChrArgStr(const virDomainChrSourceDef *dev,
|
|
|
|
const char *prefix)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
2016-02-23 11:56:34 +00:00
|
|
|
if (dev->logfile) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("logfile not supported in this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (prefix)
|
|
|
|
virBufferAdd(&buf, prefix, strlen(prefix));
|
|
|
|
|
2014-06-01 00:22:30 +00:00
|
|
|
switch ((virDomainChrType)dev->type) {
|
2010-12-16 15:07:07 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_NULL:
|
|
|
|
virBufferAddLit(&buf, "null");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_VC:
|
|
|
|
virBufferAddLit(&buf, "vc");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_PTY:
|
|
|
|
virBufferAddLit(&buf, "pty");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_DEV:
|
|
|
|
virBufferStrcat(&buf, dev->data.file.path, NULL);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_FILE:
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "file:%s", dev->data.file.path);
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_PIPE:
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "pipe:%s", dev->data.file.path);
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_STDIO:
|
|
|
|
virBufferAddLit(&buf, "stdio");
|
|
|
|
break;
|
|
|
|
|
2011-08-11 07:19:51 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_UDP: {
|
|
|
|
const char *connectHost = dev->data.udp.connectHost;
|
|
|
|
const char *bindHost = dev->data.udp.bindHost;
|
|
|
|
const char *bindService = dev->data.udp.bindService;
|
|
|
|
|
|
|
|
if (connectHost == NULL)
|
|
|
|
connectHost = "";
|
|
|
|
if (bindHost == NULL)
|
|
|
|
bindHost = "";
|
|
|
|
if (bindService == NULL)
|
|
|
|
bindService = "0";
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "udp:%s:%s@%s:%s",
|
2011-08-11 07:19:51 +00:00
|
|
|
connectHost,
|
2010-12-16 15:07:07 +00:00
|
|
|
dev->data.udp.connectService,
|
2011-08-11 07:19:51 +00:00
|
|
|
bindHost,
|
|
|
|
bindService);
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
2011-08-11 07:19:51 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_TCP:
|
|
|
|
if (dev->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "telnet:%s:%s%s",
|
2010-12-16 15:07:07 +00:00
|
|
|
dev->data.tcp.host,
|
|
|
|
dev->data.tcp.service,
|
|
|
|
dev->data.tcp.listen ? ",server,nowait" : "");
|
|
|
|
} else {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "tcp:%s:%s%s",
|
2010-12-16 15:07:07 +00:00
|
|
|
dev->data.tcp.host,
|
|
|
|
dev->data.tcp.service,
|
|
|
|
dev->data.tcp.listen ? ",server,nowait" : "");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "unix:%s%s",
|
2010-12-16 15:07:07 +00:00
|
|
|
dev->data.nix.path,
|
|
|
|
dev->data.nix.listen ? ",server,nowait" : "");
|
|
|
|
break;
|
2014-01-30 11:19:12 +00:00
|
|
|
|
2014-03-07 16:21:51 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
|
2014-01-30 11:19:12 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
|
2014-03-15 12:30:01 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_NMDM:
|
2014-03-07 16:21:51 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_LAST:
|
2014-01-30 11:19:12 +00:00
|
|
|
break;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-17 22:27:21 +00:00
|
|
|
static int
|
2016-02-23 13:05:09 +00:00
|
|
|
qemuBuildMonitorCommandLine(virLogManagerPtr logManager,
|
|
|
|
virCommandPtr cmd,
|
|
|
|
virDomainDefPtr def,
|
2016-02-17 22:27:21 +00:00
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
const virDomainChrSourceDef *monitor_chr,
|
|
|
|
bool monitor_json)
|
|
|
|
{
|
|
|
|
char *chrdev;
|
|
|
|
|
|
|
|
if (!monitor_chr)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Use -chardev if it's available */
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_CHARDEV)) {
|
|
|
|
|
2016-02-23 13:05:09 +00:00
|
|
|
if (!(chrdev = qemuBuildChrChardevStr(logManager, cmd, def,
|
|
|
|
monitor_chr, "monitor",
|
2016-02-17 22:27:21 +00:00
|
|
|
qemuCaps)))
|
|
|
|
return -1;
|
2016-02-29 12:21:14 +00:00
|
|
|
virCommandAddArg(cmd, "-chardev");
|
2016-02-17 22:27:21 +00:00
|
|
|
virCommandAddArg(cmd, chrdev);
|
|
|
|
VIR_FREE(chrdev);
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-mon");
|
|
|
|
virCommandAddArgFormat(cmd,
|
|
|
|
"chardev=charmonitor,id=monitor,mode=%s",
|
|
|
|
monitor_json ? "control" : "readline");
|
|
|
|
} else {
|
|
|
|
const char *prefix = NULL;
|
|
|
|
if (monitor_json)
|
|
|
|
prefix = "control,";
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-monitor");
|
|
|
|
if (!(chrdev = qemuBuildChrArgStr(monitor_chr, prefix)))
|
|
|
|
return -1;
|
|
|
|
virCommandAddArg(cmd, chrdev);
|
|
|
|
VIR_FREE(chrdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-04 15:43:32 +00:00
|
|
|
static char *
|
2015-04-30 17:19:10 +00:00
|
|
|
qemuBuildVirtioSerialPortDevStr(virDomainDefPtr def,
|
|
|
|
virDomainChrDefPtr dev,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2015-04-30 17:19:10 +00:00
|
|
|
const char *contAlias;
|
|
|
|
|
2011-10-19 10:45:10 +00:00
|
|
|
switch (dev->deviceType) {
|
|
|
|
case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferAddLit(&buf, "virtconsole");
|
2011-10-19 10:45:10 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
|
|
|
|
/* Legacy syntax '-device spicevmc' */
|
|
|
|
if (dev->source.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC &&
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SPICEVMC)) {
|
2011-10-19 10:45:10 +00:00
|
|
|
virBufferAddLit(&buf, "spicevmc");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(&buf, "virtserialport");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Cannot use virtio serial for parallel/serial devices"));
|
2011-10-19 10:45:10 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-06-29 15:02:05 +00:00
|
|
|
if (dev->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
|
2013-03-05 15:44:21 +00:00
|
|
|
dev->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
|
2012-06-29 15:02:05 +00:00
|
|
|
dev->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
|
2010-12-16 15:07:07 +00:00
|
|
|
/* Check it's a virtio-serial address */
|
|
|
|
if (dev->info.type !=
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL)
|
|
|
|
{
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("virtio serial device has invalid address type"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2015-04-30 17:19:10 +00:00
|
|
|
contAlias = virDomainControllerAliasFind(def, VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL,
|
|
|
|
dev->info.addr.vioserial.controller);
|
|
|
|
if (!contAlias)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, ",bus=%s.%d,nr=%d", contAlias,
|
|
|
|
dev->info.addr.vioserial.bus,
|
2010-12-16 15:07:07 +00:00
|
|
|
dev->info.addr.vioserial.port);
|
|
|
|
}
|
|
|
|
|
2011-10-19 10:45:10 +00:00
|
|
|
if (dev->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
|
|
|
|
dev->source.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC &&
|
2014-01-31 10:53:25 +00:00
|
|
|
dev->target.name &&
|
|
|
|
STRNEQ(dev->target.name, "com.redhat.spice.0")) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unsupported spicevmc target name '%s'"),
|
|
|
|
dev->target.name);
|
2011-02-03 04:09:44 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2011-10-19 10:45:10 +00:00
|
|
|
|
|
|
|
if (!(dev->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
|
|
|
|
dev->source.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC &&
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SPICEVMC))) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",chardev=char%s,id=%s",
|
2011-02-04 15:43:32 +00:00
|
|
|
dev->info.alias, dev->info.alias);
|
2015-06-30 08:21:21 +00:00
|
|
|
if (dev->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
|
|
|
|
(dev->source.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC ||
|
|
|
|
dev->target.name)) {
|
2012-03-30 07:16:23 +00:00
|
|
|
virBufferAsprintf(&buf, ",name=%s", dev->target.name
|
|
|
|
? dev->target.name : "com.redhat.spice.0");
|
2011-02-04 15:43:32 +00:00
|
|
|
}
|
2011-10-19 10:45:10 +00:00
|
|
|
} else {
|
|
|
|
virBufferAsprintf(&buf, ",id=%s", dev->info.alias);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-01-07 17:17:15 +00:00
|
|
|
static char *
|
|
|
|
qemuBuildSclpDevStr(virDomainChrDefPtr dev)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
if (dev->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE) {
|
|
|
|
switch (dev->targetType) {
|
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SCLP:
|
|
|
|
virBufferAddLit(&buf, "sclpconsole");
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SCLPLM:
|
|
|
|
virBufferAddLit(&buf, "sclplmconsole");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Cannot use slcp with devices other than console"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAsprintf(&buf, ",chardev=char%s,id=%s",
|
|
|
|
dev->info.alias, dev->info.alias);
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2013-01-07 17:17:15 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2013-01-07 17:17:15 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-01-11 16:48:21 +00:00
|
|
|
|
|
|
|
static int
|
2016-02-23 13:05:09 +00:00
|
|
|
qemuBuildRNGBackendChrdevStr(virLogManagerPtr logManager,
|
|
|
|
virCommandPtr cmd,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
virDomainRNGDefPtr rng,
|
2015-02-03 09:31:33 +00:00
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
char **chr)
|
2013-01-11 16:48:21 +00:00
|
|
|
{
|
2015-02-03 09:31:33 +00:00
|
|
|
*chr = NULL;
|
|
|
|
|
|
|
|
switch ((virDomainRNGBackend) rng->backend) {
|
|
|
|
case VIR_DOMAIN_RNG_BACKEND_RANDOM:
|
|
|
|
case VIR_DOMAIN_RNG_BACKEND_LAST:
|
|
|
|
/* no chardev backend is needed */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_RNG_BACKEND_EGD:
|
2016-02-23 13:05:09 +00:00
|
|
|
if (!(*chr = qemuBuildChrChardevStr(logManager, cmd, def,
|
|
|
|
rng->source.chardev,
|
2015-02-03 09:31:33 +00:00
|
|
|
rng->info.alias, qemuCaps)))
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-17 05:09:37 +00:00
|
|
|
int
|
2015-02-03 09:31:33 +00:00
|
|
|
qemuBuildRNGBackendProps(virDomainRNGDefPtr rng,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
const char **type,
|
|
|
|
virJSONValuePtr *props)
|
|
|
|
{
|
|
|
|
char *charBackendAlias = NULL;
|
2013-01-11 16:48:21 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
2015-02-03 09:31:33 +00:00
|
|
|
switch ((virDomainRNGBackend) rng->backend) {
|
2013-01-11 16:48:21 +00:00
|
|
|
case VIR_DOMAIN_RNG_BACKEND_RANDOM:
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_RNG_RANDOM)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("this qemu doesn't support the rng-random "
|
2013-08-14 14:50:33 +00:00
|
|
|
"backend"));
|
2013-01-11 16:48:21 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-02-03 09:31:33 +00:00
|
|
|
*type = "rng-random";
|
2013-01-11 16:48:21 +00:00
|
|
|
|
2015-02-03 09:31:33 +00:00
|
|
|
if (virJSONValueObjectCreate(props, "s:filename", rng->source.file,
|
|
|
|
NULL) < 0)
|
|
|
|
goto cleanup;
|
2013-01-11 16:48:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_RNG_BACKEND_EGD:
|
2013-02-13 10:22:23 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_RNG_EGD)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("this qemu doesn't support the rng-egd "
|
|
|
|
"backend"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-02-03 09:31:33 +00:00
|
|
|
*type = "rng-egd";
|
|
|
|
|
|
|
|
if (virAsprintf(&charBackendAlias, "char%s", rng->info.alias) < 0)
|
2013-02-13 10:22:23 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2015-02-03 09:31:33 +00:00
|
|
|
if (virJSONValueObjectCreate(props, "s:chardev", charBackendAlias,
|
|
|
|
NULL) < 0)
|
|
|
|
goto cleanup;
|
2013-02-13 10:22:23 +00:00
|
|
|
|
2013-01-11 16:48:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_RNG_BACKEND_LAST:
|
2015-05-05 10:53:24 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("unknown rng-random backend"));
|
|
|
|
goto cleanup;
|
2013-01-11 16:48:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
cleanup:
|
2015-02-03 09:31:33 +00:00
|
|
|
VIR_FREE(charBackendAlias);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
qemuBuildRNGBackendStr(virDomainRNGDefPtr rng,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
const char *type = NULL;
|
|
|
|
char *alias = NULL;
|
|
|
|
virJSONValuePtr props = NULL;
|
|
|
|
char *ret = NULL;
|
|
|
|
|
|
|
|
if (virAsprintf(&alias, "obj%s", rng->info.alias) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (qemuBuildRNGBackendProps(rng, qemuCaps, &type, &props) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = qemuBuildObjectCommandlineFromJSON(type, alias, props);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(alias);
|
|
|
|
virJSONValueFree(props);
|
2013-01-11 16:48:21 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-17 05:09:31 +00:00
|
|
|
char *
|
|
|
|
qemuBuildRNGDevStr(virDomainDefPtr def,
|
|
|
|
virDomainRNGDefPtr dev,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
2013-01-11 16:48:21 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
if (dev->model != VIR_DOMAIN_RNG_MODEL_VIRTIO ||
|
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIRTIO_RNG)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("this qemu doesn't support RNG device type '%s'"),
|
|
|
|
virDomainRNGModelTypeToString(dev->model));
|
2015-01-17 05:09:31 +00:00
|
|
|
goto error;
|
2013-01-11 16:48:21 +00:00
|
|
|
}
|
|
|
|
|
2015-08-31 15:06:42 +00:00
|
|
|
if (!qemuCheckCCWS390AddressSupport(def, dev->info, qemuCaps,
|
|
|
|
dev->source.file))
|
|
|
|
goto error;
|
|
|
|
|
2013-03-14 18:32:25 +00:00
|
|
|
if (dev->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)
|
2015-02-03 09:26:40 +00:00
|
|
|
virBufferAsprintf(&buf, "virtio-rng-ccw,rng=obj%s,id=%s",
|
|
|
|
dev->info.alias, dev->info.alias);
|
2013-03-14 18:32:25 +00:00
|
|
|
else if (dev->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390)
|
2015-02-03 09:26:40 +00:00
|
|
|
virBufferAsprintf(&buf, "virtio-rng-s390,rng=obj%s,id=%s",
|
|
|
|
dev->info.alias, dev->info.alias);
|
2013-08-01 01:40:35 +00:00
|
|
|
else if (dev->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO)
|
2015-02-03 09:26:40 +00:00
|
|
|
virBufferAsprintf(&buf, "virtio-rng-device,rng=obj%s,id=%s",
|
|
|
|
dev->info.alias, dev->info.alias);
|
2013-03-14 18:32:25 +00:00
|
|
|
else
|
2015-02-03 09:26:40 +00:00
|
|
|
virBufferAsprintf(&buf, "virtio-rng-pci,rng=obj%s,id=%s",
|
|
|
|
dev->info.alias, dev->info.alias);
|
2013-01-11 16:48:21 +00:00
|
|
|
|
2013-02-13 14:37:39 +00:00
|
|
|
if (dev->rate > 0) {
|
|
|
|
virBufferAsprintf(&buf, ",max-bytes=%u", dev->rate);
|
|
|
|
if (dev->period)
|
|
|
|
virBufferAsprintf(&buf, ",period=%u", dev->period);
|
|
|
|
else
|
|
|
|
virBufferAddLit(&buf, ",period=1000");
|
|
|
|
}
|
|
|
|
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, def, &dev->info, qemuCaps) < 0)
|
2015-01-17 05:09:31 +00:00
|
|
|
goto error;
|
|
|
|
if (virBufferCheckError(&buf) < 0)
|
|
|
|
goto error;
|
2013-01-11 16:48:21 +00:00
|
|
|
|
2015-01-17 05:09:31 +00:00
|
|
|
return virBufferContentAndReset(&buf);
|
2013-01-11 16:48:21 +00:00
|
|
|
|
2015-01-17 05:09:31 +00:00
|
|
|
error:
|
2013-01-11 16:48:21 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
2015-01-17 05:09:31 +00:00
|
|
|
return NULL;
|
2013-01-11 16:48:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-12 10:02:29 +00:00
|
|
|
static char *qemuBuildSmbiosBiosStr(virSysinfoBIOSDefPtr def)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
2015-05-12 10:02:29 +00:00
|
|
|
if (!def)
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
virBufferAddLit(&buf, "type=0");
|
|
|
|
|
|
|
|
/* 0:Vendor */
|
2015-05-12 10:02:29 +00:00
|
|
|
if (def->vendor)
|
|
|
|
virBufferAsprintf(&buf, ",vendor=%s", def->vendor);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 0:BIOS Version */
|
2015-05-12 10:02:29 +00:00
|
|
|
if (def->version)
|
|
|
|
virBufferAsprintf(&buf, ",version=%s", def->version);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 0:BIOS Release Date */
|
2015-05-12 10:02:29 +00:00
|
|
|
if (def->date)
|
|
|
|
virBufferAsprintf(&buf, ",date=%s", def->date);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 0:System BIOS Major Release and 0:System BIOS Minor Release */
|
2015-05-12 10:02:29 +00:00
|
|
|
if (def->release)
|
|
|
|
virBufferAsprintf(&buf, ",release=%s", def->release);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2015-05-12 12:33:12 +00:00
|
|
|
static char *qemuBuildSmbiosSystemStr(virSysinfoSystemDefPtr def,
|
|
|
|
bool skip_uuid)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
2015-05-12 12:33:12 +00:00
|
|
|
if (!def ||
|
|
|
|
(!def->manufacturer && !def->product && !def->version &&
|
|
|
|
!def->serial && (!def->uuid || skip_uuid) &&
|
|
|
|
def->sku && !def->family))
|
2010-12-16 15:07:07 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "type=1");
|
|
|
|
|
|
|
|
/* 1:Manufacturer */
|
2015-05-12 12:33:12 +00:00
|
|
|
if (def->manufacturer)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",manufacturer=%s",
|
2015-05-12 12:33:12 +00:00
|
|
|
def->manufacturer);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 1:Product Name */
|
2015-05-12 12:33:12 +00:00
|
|
|
if (def->product)
|
|
|
|
virBufferAsprintf(&buf, ",product=%s", def->product);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 1:Version */
|
2015-05-12 12:33:12 +00:00
|
|
|
if (def->version)
|
|
|
|
virBufferAsprintf(&buf, ",version=%s", def->version);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 1:Serial Number */
|
2015-05-12 12:33:12 +00:00
|
|
|
if (def->serial)
|
|
|
|
virBufferAsprintf(&buf, ",serial=%s", def->serial);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 1:UUID */
|
2015-05-12 12:33:12 +00:00
|
|
|
if (def->uuid && !skip_uuid)
|
|
|
|
virBufferAsprintf(&buf, ",uuid=%s", def->uuid);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 1:SKU Number */
|
2015-05-12 12:33:12 +00:00
|
|
|
if (def->sku)
|
|
|
|
virBufferAsprintf(&buf, ",sku=%s", def->sku);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 1:Family */
|
2015-05-12 12:33:12 +00:00
|
|
|
if (def->family)
|
|
|
|
virBufferAsprintf(&buf, ",family=%s", def->family);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2015-05-12 14:47:49 +00:00
|
|
|
static char *qemuBuildSmbiosBaseBoardStr(virSysinfoBaseBoardDefPtr def)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
if (!def)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "type=2");
|
|
|
|
|
|
|
|
/* 2:Manufacturer */
|
|
|
|
if (def->manufacturer)
|
|
|
|
virBufferAsprintf(&buf, ",manufacturer=%s",
|
|
|
|
def->manufacturer);
|
|
|
|
/* 2:Product Name */
|
|
|
|
if (def->product)
|
|
|
|
virBufferAsprintf(&buf, ",product=%s", def->product);
|
|
|
|
/* 2:Version */
|
|
|
|
if (def->version)
|
|
|
|
virBufferAsprintf(&buf, ",version=%s", def->version);
|
|
|
|
/* 2:Serial Number */
|
|
|
|
if (def->serial)
|
|
|
|
virBufferAsprintf(&buf, ",serial=%s", def->serial);
|
|
|
|
/* 2:Asset Tag */
|
|
|
|
if (def->asset)
|
|
|
|
virBufferAsprintf(&buf, ",asset=%s", def->asset);
|
|
|
|
/* 2:Location */
|
|
|
|
if (def->location)
|
|
|
|
virBufferAsprintf(&buf, ",location=%s", def->location);
|
|
|
|
|
|
|
|
if (virBufferCheckError(&buf) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-02-17 22:10:37 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
qemuBuildSmbiosCommandLine(virCommandPtr cmd,
|
|
|
|
virQEMUDriverPtr driver,
|
|
|
|
const virDomainDef *def,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
virSysinfoDefPtr source = NULL;
|
|
|
|
bool skip_uuid = false;
|
|
|
|
|
|
|
|
if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_NONE ||
|
|
|
|
def->os.smbios_mode == VIR_DOMAIN_SMBIOS_EMULATE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SMBIOS_TYPE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("the QEMU binary %s does not support smbios settings"),
|
|
|
|
def->emulator);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* should we really error out or just warn in those cases ? */
|
|
|
|
if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_HOST) {
|
|
|
|
if (driver->hostsysinfo == NULL) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Host SMBIOS information is not available"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
source = driver->hostsysinfo;
|
|
|
|
/* Host and guest uuid must differ, by definition of UUID. */
|
|
|
|
skip_uuid = true;
|
|
|
|
} else if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_SYSINFO) {
|
|
|
|
if (def->sysinfo == NULL) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("Domain '%s' sysinfo are not available"),
|
|
|
|
def->name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
source = def->sysinfo;
|
|
|
|
/* domain_conf guaranteed that system_uuid matches guest uuid. */
|
|
|
|
}
|
|
|
|
if (source != NULL) {
|
|
|
|
char *smbioscmd;
|
|
|
|
|
|
|
|
smbioscmd = qemuBuildSmbiosBiosStr(source->bios);
|
|
|
|
if (smbioscmd != NULL) {
|
|
|
|
virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL);
|
|
|
|
VIR_FREE(smbioscmd);
|
|
|
|
}
|
|
|
|
smbioscmd = qemuBuildSmbiosSystemStr(source->system, skip_uuid);
|
|
|
|
if (smbioscmd != NULL) {
|
|
|
|
virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL);
|
|
|
|
VIR_FREE(smbioscmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (source->nbaseBoard > 1) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("qemu does not support more than "
|
|
|
|
"one entry to Type 2 in SMBIOS table"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < source->nbaseBoard; i++) {
|
|
|
|
if (!(smbioscmd =
|
|
|
|
qemuBuildSmbiosBaseBoardStr(source->baseBoard + i)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL);
|
|
|
|
VIR_FREE(smbioscmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-17 22:19:00 +00:00
|
|
|
static int
|
|
|
|
qemuBuildSgaCommandLine(virCommandPtr cmd,
|
|
|
|
const virDomainDef *def,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
/* Serial graphics adapter */
|
|
|
|
if (def->os.bios.useserial == VIR_TRISTATE_BOOL_YES) {
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("qemu does not support -device"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SGA)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("qemu does not support SGA"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!def->nserials) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("need at least one serial port to use SGA"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
virCommandAddArgList(cmd, "-device", "sga", NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
static char *
|
|
|
|
qemuBuildClockArgStr(virDomainClockDefPtr def)
|
|
|
|
{
|
2016-02-18 11:42:45 +00:00
|
|
|
size_t i;
|
2010-12-16 15:07:07 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
switch (def->offset) {
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_UTC:
|
|
|
|
virBufferAddLit(&buf, "base=utc");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
|
|
|
|
virBufferAddLit(&buf, "base=localtime");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE: {
|
|
|
|
time_t now = time(NULL);
|
|
|
|
struct tm nowbits;
|
|
|
|
|
qemu: fix <clock offset='variable' basis='localtime'/>
For a clock element as above, libvirt simply converts current system
time with localtime_r(), then starts qemu with a time string that
doesn't contain any timezone information. So, from qemu's point of
view, the -rtc string it gets for:
<clock offset='variable' basis='utc' adjustment='10800'/>
is identical to the -rtc string it gets for:
<clock offset='variable' basis='localtime' adjustment='0'/>
(assuming the host is in a timezone that is 10800 seconds ahead of
UTC, as is the case on the machine where this message is being
written).
Since the commandlines are identical, qemu will behave identically
after this point in either case.
There are two problems in the case of basis='localtime' though:
Problem 1) If the guest modifies its RTC, for example to add 20
seconds, the RTC_CHANGE event from qemu will then contain offset:20 in
both cases. But libvirt will have saved the original adjustment into
adjustment0, and will add that value onto the offset in the
event. This means that in the case of basis=;utc', it will properly
emit an event with offset:10820, but in the case of basis='localtime'
the event will contain offset:20, which is *not* the new offset of the
RTC from UTC (as the event it documented to provide).
Problem 2) If the guest is migrated to another host that is in a
different timezone, or if it is migrated or saved/restored after the
DST status has changed from what it was when the guest was originally
started, the newly restarted guest will have a different RTC (since it
will be based on the new localtime, which could have shifted by
several hours).
The solution to both of these problems is simple - rather than
maintaining the original adjustment value along with
"basis='localtime'" in the domain status, when the domain is started
we convert the adjustment offset to one relative to UTC, and set the
status to "basis='utc'". Thus, whatever the RTC offset was from UTC
when it was initially started, that offset will be maintained when
migrating across timezones and DST settings, and the RTC_CHANGE events
will automatically contain the proper offset (which should by
definition always be relative to UTC).
This fixes a problem that was implied but not openly stated in:
https://bugzilla.redhat.com/show_bug.cgi?id=964177
2014-05-21 14:20:50 +00:00
|
|
|
if (def->data.variable.basis == VIR_DOMAIN_CLOCK_BASIS_LOCALTIME) {
|
|
|
|
long localOffset;
|
|
|
|
|
|
|
|
/* in the case of basis='localtime', rather than trying to
|
|
|
|
* keep that basis (and associated offset from UTC) in the
|
|
|
|
* status and deal with adding in the difference each time
|
|
|
|
* there is an RTC_CHANGE event, it is simpler and less
|
|
|
|
* error prone to just convert the adjustment an offset
|
|
|
|
* from UTC right now (and change the status to
|
|
|
|
* "basis='utc' to reflect this). This eliminates
|
|
|
|
* potential errors in both RTC_CHANGE events and in
|
|
|
|
* migration (in the case that the status of DST, or the
|
|
|
|
* timezone of the destination host, changed relative to
|
|
|
|
* startup).
|
|
|
|
*/
|
|
|
|
if (virTimeLocalOffsetFromUTC(&localOffset) < 0)
|
|
|
|
goto error;
|
|
|
|
def->data.variable.adjustment += localOffset;
|
|
|
|
def->data.variable.basis = VIR_DOMAIN_CLOCK_BASIS_UTC;
|
2012-02-06 13:59:16 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
qemu: fix <clock offset='variable' basis='localtime'/>
For a clock element as above, libvirt simply converts current system
time with localtime_r(), then starts qemu with a time string that
doesn't contain any timezone information. So, from qemu's point of
view, the -rtc string it gets for:
<clock offset='variable' basis='utc' adjustment='10800'/>
is identical to the -rtc string it gets for:
<clock offset='variable' basis='localtime' adjustment='0'/>
(assuming the host is in a timezone that is 10800 seconds ahead of
UTC, as is the case on the machine where this message is being
written).
Since the commandlines are identical, qemu will behave identically
after this point in either case.
There are two problems in the case of basis='localtime' though:
Problem 1) If the guest modifies its RTC, for example to add 20
seconds, the RTC_CHANGE event from qemu will then contain offset:20 in
both cases. But libvirt will have saved the original adjustment into
adjustment0, and will add that value onto the offset in the
event. This means that in the case of basis=;utc', it will properly
emit an event with offset:10820, but in the case of basis='localtime'
the event will contain offset:20, which is *not* the new offset of the
RTC from UTC (as the event it documented to provide).
Problem 2) If the guest is migrated to another host that is in a
different timezone, or if it is migrated or saved/restored after the
DST status has changed from what it was when the guest was originally
started, the newly restarted guest will have a different RTC (since it
will be based on the new localtime, which could have shifted by
several hours).
The solution to both of these problems is simple - rather than
maintaining the original adjustment value along with
"basis='localtime'" in the domain status, when the domain is started
we convert the adjustment offset to one relative to UTC, and set the
status to "basis='utc'". Thus, whatever the RTC offset was from UTC
when it was initially started, that offset will be maintained when
migrating across timezones and DST settings, and the RTC_CHANGE events
will automatically contain the proper offset (which should by
definition always be relative to UTC).
This fixes a problem that was implied but not openly stated in:
https://bugzilla.redhat.com/show_bug.cgi?id=964177
2014-05-21 14:20:50 +00:00
|
|
|
now += def->data.variable.adjustment;
|
|
|
|
gmtime_r(&now, &nowbits);
|
|
|
|
|
qemu: fix RTC_CHANGE event for <clock offset='variable' basis='utc'/>
commit e31b5cf393857 attempted to fix libvirt's
VIR_DOMAIN_EVENT_ID_RTC_CHANGE, which is documentated to always
provide the new offset of the domain's real time clock from UTC. The
problem was that, in the case that qemu is provided with an "-rtc
base=x" where x is an absolute time (rather than "utc" or
"localtime"), the offset sent by qemu's RTC_CHANGE event is *not* the
new offset from UTC, but rather is the sum of all changes to the
domain's RTC since it was started with base=x.
So, despite what was said in commit e31b5cf393857, if we assume that
the original value stored in "adjustment" was the offset from UTC at
the time the domain was started, we can always determine the current
offset from UTC by simply adding the most recent (i.e. current) offset
from qemu to that original adjustment.
This patch accomplishes that by storing the initial adjustment in the
domain's status as "adjustment0". Each time a new RTC_CHANGE event is
received from qemu, we simply add adjustment0 to the value sent by
qemu, store that as the new adjustment, and forward that value on to
any event handler.
This patch (*not* e31b5cf393857, which should be reverted prior to
applying this patch) fixes:
https://bugzilla.redhat.com/show_bug.cgi?id=964177
(for the case where basis='utc'. It does not fix basis='localtime')
2014-05-21 09:54:34 +00:00
|
|
|
/* when an RTC_CHANGE event is received from qemu, we need to
|
|
|
|
* have the adjustment used at domain start time available to
|
|
|
|
* compute the new offset from UTC. As this new value is
|
|
|
|
* itself stored in def->data.variable.adjustment, we need to
|
|
|
|
* save a copy of it now.
|
|
|
|
*/
|
|
|
|
def->data.variable.adjustment0 = def->data.variable.adjustment;
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "base=%d-%02d-%02dT%02d:%02d:%02d",
|
2010-12-16 15:07:07 +00:00
|
|
|
nowbits.tm_year + 1900,
|
|
|
|
nowbits.tm_mon + 1,
|
|
|
|
nowbits.tm_mday,
|
|
|
|
nowbits.tm_hour,
|
|
|
|
nowbits.tm_min,
|
|
|
|
nowbits.tm_sec);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default:
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported clock offset '%s'"),
|
|
|
|
virDomainClockOffsetTypeToString(def->offset));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2016-02-18 11:42:45 +00:00
|
|
|
/* Look for an 'rtc' timer element, and add in appropriate
|
|
|
|
* clock= and driftfix= */
|
2010-12-16 15:07:07 +00:00
|
|
|
for (i = 0; i < def->ntimers; i++) {
|
|
|
|
if (def->timers[i]->name == VIR_DOMAIN_TIMER_NAME_RTC) {
|
|
|
|
switch (def->timers[i]->track) {
|
|
|
|
case -1: /* unspecified - use hypervisor default */
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_TIMER_TRACK_BOOT:
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported rtc timer track '%s'"),
|
|
|
|
virDomainTimerTrackTypeToString(def->timers[i]->track));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
case VIR_DOMAIN_TIMER_TRACK_GUEST:
|
|
|
|
virBufferAddLit(&buf, ",clock=vm");
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_TIMER_TRACK_WALL:
|
|
|
|
virBufferAddLit(&buf, ",clock=host");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (def->timers[i]->tickpolicy) {
|
|
|
|
case -1:
|
|
|
|
case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
|
|
|
|
/* This is the default - missed ticks delivered when
|
|
|
|
next scheduled, at normal rate */
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
|
|
|
|
/* deliver ticks at a faster rate until caught up */
|
|
|
|
virBufferAddLit(&buf, ",driftfix=slew");
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
|
|
|
|
case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported rtc timer tickpolicy '%s'"),
|
|
|
|
virDomainTimerTickpolicyTypeToString(def->timers[i]->tickpolicy));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
break; /* no need to check other timers - there is only one rtc */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-02-18 11:42:45 +00:00
|
|
|
|
|
|
|
/* NOTE: Building of commands can change def->clock->data.* values, so
|
|
|
|
* virDomainDef is not const here.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
qemuBuildClockCommandLine(virCommandPtr cmd,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_RTC)) {
|
|
|
|
char *rtcopt;
|
|
|
|
virCommandAddArg(cmd, "-rtc");
|
|
|
|
if (!(rtcopt = qemuBuildClockArgStr(&def->clock)))
|
|
|
|
return -1;
|
|
|
|
virCommandAddArg(cmd, rtcopt);
|
|
|
|
VIR_FREE(rtcopt);
|
|
|
|
} else {
|
|
|
|
switch (def->clock.offset) {
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
|
|
|
|
virCommandAddArg(cmd, "-localtime");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_UTC:
|
|
|
|
/* Nothing, its the default */
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported clock offset '%s'"),
|
|
|
|
virDomainClockOffsetTypeToString(def->clock.offset));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE &&
|
|
|
|
def->clock.data.timezone) {
|
|
|
|
virCommandAddEnvPair(cmd, "TZ", def->clock.data.timezone);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < def->clock.ntimers; i++) {
|
|
|
|
switch ((virDomainTimerNameType) def->clock.timers[i]->name) {
|
|
|
|
case VIR_DOMAIN_TIMER_NAME_PLATFORM:
|
|
|
|
case VIR_DOMAIN_TIMER_NAME_TSC:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported timer type (name) '%s'"),
|
|
|
|
virDomainTimerNameTypeToString(def->clock.timers[i]->name));
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_TIMER_NAME_KVMCLOCK:
|
|
|
|
case VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK:
|
|
|
|
/* Timers above are handled when building -cpu. */
|
|
|
|
case VIR_DOMAIN_TIMER_NAME_LAST:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_TIMER_NAME_RTC:
|
|
|
|
/* This has already been taken care of (in qemuBuildClockArgStr)
|
|
|
|
if QEMU_CAPS_RTC is set (mutually exclusive with
|
|
|
|
QEMUD_FLAG_RTC_TD_HACK) */
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_RTC_TD_HACK)) {
|
|
|
|
switch (def->clock.timers[i]->tickpolicy) {
|
|
|
|
case -1:
|
|
|
|
case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
|
|
|
|
/* the default - do nothing */
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
|
|
|
|
virCommandAddArg(cmd, "-rtc-td-hack");
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
|
|
|
|
case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported rtc tickpolicy '%s'"),
|
|
|
|
virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_RTC) &&
|
|
|
|
(def->clock.timers[i]->tickpolicy
|
|
|
|
!= VIR_DOMAIN_TIMER_TICKPOLICY_DELAY) &&
|
|
|
|
(def->clock.timers[i]->tickpolicy != -1)) {
|
|
|
|
/* a non-default rtc policy was given, but there is no
|
|
|
|
way to implement it in this version of qemu */
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported rtc tickpolicy '%s'"),
|
|
|
|
virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_TIMER_NAME_PIT:
|
|
|
|
switch (def->clock.timers[i]->tickpolicy) {
|
|
|
|
case -1:
|
|
|
|
case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
|
|
|
|
/* delay is the default if we don't have kernel
|
|
|
|
(-no-kvm-pit), otherwise, the default is catchup. */
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM_PIT_TICK_POLICY))
|
|
|
|
virCommandAddArgList(cmd, "-global",
|
|
|
|
"kvm-pit.lost_tick_policy=discard", NULL);
|
|
|
|
else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NO_KVM_PIT))
|
|
|
|
virCommandAddArg(cmd, "-no-kvm-pit-reinjection");
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NO_KVM_PIT) ||
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM_PIT_TICK_POLICY)) {
|
|
|
|
/* do nothing - this is default for kvm-pit */
|
|
|
|
} else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDF)) {
|
|
|
|
/* -tdf switches to 'catchup' with userspace pit. */
|
|
|
|
virCommandAddArg(cmd, "-tdf");
|
|
|
|
} else {
|
|
|
|
/* can't catchup if we have neither pit mode */
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported pit tickpolicy '%s'"),
|
|
|
|
virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
|
|
|
|
case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
|
|
|
|
/* no way to support these modes for pit in qemu */
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported pit tickpolicy '%s'"),
|
|
|
|
virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_TIMER_NAME_HPET:
|
|
|
|
/* the only meaningful attribute for hpet is "present". If
|
|
|
|
* present is -1, that means it wasn't specified, and
|
|
|
|
* should be left at the default for the
|
|
|
|
* hypervisor. "default" when -no-hpet exists is "yes",
|
|
|
|
* and when -no-hpet doesn't exist is "no". "confusing"?
|
|
|
|
* "yes"! */
|
|
|
|
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NO_HPET)) {
|
|
|
|
if (def->clock.timers[i]->present == 0)
|
|
|
|
virCommandAddArg(cmd, "-no-hpet");
|
|
|
|
} else {
|
|
|
|
/* no hpet timer available. The only possible action
|
|
|
|
is to raise an error if present="yes" */
|
|
|
|
if (def->clock.timers[i]->present == 1) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("hpet timer is not supported"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-18 13:06:17 +00:00
|
|
|
static int
|
|
|
|
qemuBuildPMCommandLine(virCommandPtr cmd,
|
|
|
|
const virDomainDef *def,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
bool monitor_json)
|
|
|
|
{
|
|
|
|
bool allowReboot = true;
|
|
|
|
|
|
|
|
/* Only add -no-reboot option if each event destroys domain */
|
|
|
|
if (def->onReboot == VIR_DOMAIN_LIFECYCLE_DESTROY &&
|
|
|
|
def->onPoweroff == VIR_DOMAIN_LIFECYCLE_DESTROY &&
|
|
|
|
(def->onCrash == VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY ||
|
|
|
|
def->onCrash == VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_DESTROY)) {
|
|
|
|
allowReboot = false;
|
|
|
|
virCommandAddArg(cmd, "-no-reboot");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If JSON monitor is enabled, we can receive an event
|
|
|
|
* when QEMU stops. If we use no-shutdown, then we can
|
|
|
|
* watch for this event and do a soft/warm reboot.
|
|
|
|
*/
|
|
|
|
if (monitor_json && allowReboot &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_NO_SHUTDOWN)) {
|
|
|
|
virCommandAddArg(cmd, "-no-shutdown");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NO_ACPI)) {
|
|
|
|
if (def->features[VIR_DOMAIN_FEATURE_ACPI] != VIR_TRISTATE_SWITCH_ON)
|
|
|
|
virCommandAddArg(cmd, "-no-acpi");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We fall back to PIIX4_PM even for q35, since it's what we did
|
|
|
|
pre-q35-pm support. QEMU starts up fine (with a warning) if
|
|
|
|
mixing PIIX PM and -M q35. Starting to reject things here
|
|
|
|
could mean we refuse to start existing configs in the wild.*/
|
|
|
|
if (def->pm.s3) {
|
|
|
|
const char *pm_object = "PIIX4_PM";
|
|
|
|
|
|
|
|
if (qemuDomainMachineIsQ35(def) &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_ICH9_DISABLE_S3)) {
|
|
|
|
pm_object = "ICH9-LPC";
|
|
|
|
} else if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PIIX_DISABLE_S3)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("setting ACPI S3 not supported"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-global");
|
|
|
|
virCommandAddArgFormat(cmd, "%s.disable_s3=%d",
|
|
|
|
pm_object, def->pm.s3 == VIR_TRISTATE_BOOL_NO);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->pm.s4) {
|
|
|
|
const char *pm_object = "PIIX4_PM";
|
|
|
|
|
|
|
|
if (qemuDomainMachineIsQ35(def) &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_ICH9_DISABLE_S4)) {
|
|
|
|
pm_object = "ICH9-LPC";
|
|
|
|
} else if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PIIX_DISABLE_S4)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("setting ACPI S4 not supported"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-global");
|
|
|
|
virCommandAddArgFormat(cmd, "%s.disable_s4=%d",
|
|
|
|
pm_object, def->pm.s4 == VIR_TRISTATE_BOOL_NO);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-18 13:15:10 +00:00
|
|
|
static int
|
|
|
|
qemuBuildBootCommandLine(virCommandPtr cmd,
|
|
|
|
const virDomainDef *def,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
bool *emitBootindex)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
virBuffer boot_buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
char *boot_order_str = NULL, *boot_opts_str = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We prefer using explicit bootindex=N parameters for predictable
|
|
|
|
* results even though domain XML doesn't use per device boot elements.
|
|
|
|
* However, we can't use bootindex if boot menu was requested.
|
|
|
|
*/
|
|
|
|
if (!def->os.nBootDevs) {
|
|
|
|
/* def->os.nBootDevs is guaranteed to be > 0 unless per-device boot
|
|
|
|
* configuration is used
|
|
|
|
*/
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("hypervisor lacks deviceboot feature"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
*emitBootindex = true;
|
|
|
|
} else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX) &&
|
|
|
|
(def->os.bootmenu != VIR_TRISTATE_BOOL_YES ||
|
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_BOOT_MENU))) {
|
|
|
|
*emitBootindex = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!*emitBootindex) {
|
|
|
|
char boot[VIR_DOMAIN_BOOT_LAST+1];
|
|
|
|
|
|
|
|
for (i = 0; i < def->os.nBootDevs; i++) {
|
|
|
|
switch (def->os.bootDevs[i]) {
|
|
|
|
case VIR_DOMAIN_BOOT_CDROM:
|
|
|
|
boot[i] = 'd';
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_BOOT_FLOPPY:
|
|
|
|
boot[i] = 'a';
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_BOOT_DISK:
|
|
|
|
boot[i] = 'c';
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_BOOT_NET:
|
|
|
|
boot[i] = 'n';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
boot[i] = 'c';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
boot[def->os.nBootDevs] = '\0';
|
|
|
|
|
|
|
|
virBufferAsprintf(&boot_buf, "%s", boot);
|
|
|
|
if (virBufferCheckError(&boot_buf) < 0)
|
|
|
|
goto error;
|
|
|
|
boot_order_str = virBufferContentAndReset(&boot_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->os.bootmenu) {
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BOOT_MENU)) {
|
|
|
|
if (def->os.bootmenu == VIR_TRISTATE_BOOL_YES)
|
|
|
|
virBufferAddLit(&boot_buf, "menu=on,");
|
|
|
|
else
|
|
|
|
virBufferAddLit(&boot_buf, "menu=off,");
|
|
|
|
} else {
|
|
|
|
/* We cannot emit an error when bootmenu is enabled but
|
|
|
|
* unsupported because of backward compatibility */
|
|
|
|
VIR_WARN("bootmenu is enabled but not "
|
|
|
|
"supported by this QEMU binary");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->os.bios.rt_set) {
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_REBOOT_TIMEOUT)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("reboot timeout is not supported "
|
|
|
|
"by this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(&boot_buf,
|
|
|
|
"reboot-timeout=%d,",
|
|
|
|
def->os.bios.rt_delay);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->os.bm_timeout_set) {
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPLASH_TIMEOUT)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("splash timeout is not supported "
|
|
|
|
"by this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(&boot_buf, "splash-time=%u,", def->os.bm_timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BOOT_STRICT))
|
|
|
|
virBufferAddLit(&boot_buf, "strict=on,");
|
|
|
|
|
|
|
|
virBufferTrim(&boot_buf, ",", -1);
|
|
|
|
|
|
|
|
if (virBufferCheckError(&boot_buf) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
boot_opts_str = virBufferContentAndReset(&boot_buf);
|
|
|
|
if (boot_order_str || boot_opts_str) {
|
|
|
|
virCommandAddArg(cmd, "-boot");
|
|
|
|
|
|
|
|
if (boot_order_str && boot_opts_str) {
|
|
|
|
virCommandAddArgFormat(cmd, "order=%s,%s",
|
|
|
|
boot_order_str, boot_opts_str);
|
|
|
|
} else if (boot_order_str) {
|
|
|
|
virCommandAddArg(cmd, boot_order_str);
|
|
|
|
} else if (boot_opts_str) {
|
|
|
|
virCommandAddArg(cmd, boot_opts_str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VIR_FREE(boot_opts_str);
|
|
|
|
VIR_FREE(boot_order_str);
|
|
|
|
|
|
|
|
if (def->os.kernel)
|
|
|
|
virCommandAddArgList(cmd, "-kernel", def->os.kernel, NULL);
|
|
|
|
if (def->os.initrd)
|
|
|
|
virCommandAddArgList(cmd, "-initrd", def->os.initrd, NULL);
|
|
|
|
if (def->os.cmdline)
|
|
|
|
virCommandAddArgList(cmd, "-append", def->os.cmdline, NULL);
|
|
|
|
if (def->os.dtb) {
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DTB)) {
|
|
|
|
virCommandAddArgList(cmd, "-dtb", def->os.dtb, NULL);
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("dtb is not supported with this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(boot_order_str);
|
|
|
|
VIR_FREE(boot_opts_str);
|
|
|
|
virBufferFreeAndReset(&boot_buf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-18 13:18:18 +00:00
|
|
|
static int
|
|
|
|
qemuBuildGlobalControllerCommandLine(virCommandPtr cmd,
|
|
|
|
const virDomainDef *def,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < def->ncontrollers; i++) {
|
|
|
|
virDomainControllerDefPtr cont = def->controllers[i];
|
|
|
|
if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI &&
|
|
|
|
cont->opts.pciopts.pcihole64) {
|
|
|
|
const char *hoststr = NULL;
|
|
|
|
bool cap = false;
|
|
|
|
bool machine = false;
|
|
|
|
|
|
|
|
switch (cont->model) {
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
|
|
|
|
hoststr = "i440FX-pcihost";
|
|
|
|
cap = virQEMUCapsGet(qemuCaps, QEMU_CAPS_I440FX_PCI_HOLE64_SIZE);
|
|
|
|
machine = qemuDomainMachineIsI440FX(def);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
|
|
|
|
hoststr = "q35-pcihost";
|
|
|
|
cap = virQEMUCapsGet(qemuCaps, QEMU_CAPS_Q35_PCI_HOLE64_SIZE);
|
|
|
|
machine = qemuDomainMachineIsQ35(def);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("64-bit PCI hole setting is only for root"
|
|
|
|
" PCI controllers"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!machine) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Setting the 64-bit PCI hole size is not "
|
|
|
|
"supported for machine '%s'"), def->os.machine);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!cap) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("64-bit PCI hole size setting is not supported "
|
|
|
|
"with this QEMU binary"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-global");
|
|
|
|
virCommandAddArgFormat(cmd, "%s.pci-hole64-size=%luK", hoststr,
|
|
|
|
cont->opts.pciopts.pcihole64size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
static int
|
2014-09-23 15:35:57 +00:00
|
|
|
qemuBuildCpuModelArgStr(virQEMUDriverPtr driver,
|
|
|
|
const virDomainDef *def,
|
|
|
|
virBufferPtr buf,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
bool *hasHwVirt,
|
|
|
|
bool migrating)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
2014-09-23 15:35:57 +00:00
|
|
|
int ret = -1;
|
|
|
|
size_t i;
|
2013-02-01 17:04:15 +00:00
|
|
|
virCPUDefPtr host = NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
virCPUDefPtr guest = NULL;
|
2011-12-21 12:47:17 +00:00
|
|
|
virCPUDefPtr cpu = NULL;
|
2015-01-05 16:03:58 +00:00
|
|
|
virCPUDefPtr featCpu = NULL;
|
2012-08-22 10:56:11 +00:00
|
|
|
size_t ncpus = 0;
|
2012-08-22 15:28:55 +00:00
|
|
|
char **cpus = NULL;
|
2012-12-18 18:44:23 +00:00
|
|
|
virCPUDataPtr data = NULL;
|
2015-03-24 13:12:07 +00:00
|
|
|
virCPUDataPtr hostData = NULL;
|
2012-04-17 13:24:47 +00:00
|
|
|
char *compare_msg = NULL;
|
2014-09-23 15:35:57 +00:00
|
|
|
virCPUCompareResult cmp;
|
|
|
|
const char *preferred;
|
2013-02-01 17:04:15 +00:00
|
|
|
virCapsPtr caps = NULL;
|
2015-01-05 16:03:58 +00:00
|
|
|
bool compareAgainstHost = ((def->virtType == VIR_DOMAIN_VIRT_KVM ||
|
|
|
|
def->cpu->mode != VIR_CPU_MODE_CUSTOM) &&
|
|
|
|
def->cpu->mode != VIR_CPU_MODE_HOST_PASSTHROUGH);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2013-02-01 17:04:15 +00:00
|
|
|
if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
host = caps->host.cpu;
|
|
|
|
|
2014-09-23 15:35:57 +00:00
|
|
|
if (!host ||
|
|
|
|
!host->model ||
|
|
|
|
(ncpus = virQEMUCapsGetCPUDefinitions(qemuCaps, &cpus)) == 0) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("CPU specification not supported by hypervisor"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-01-27 13:49:52 +00:00
|
|
|
|
2014-09-23 15:35:57 +00:00
|
|
|
if (!(cpu = virCPUDefCopy(def->cpu)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-01-05 16:03:58 +00:00
|
|
|
if (cpu->mode == VIR_CPU_MODE_HOST_MODEL &&
|
2014-09-23 15:35:57 +00:00
|
|
|
!migrating &&
|
|
|
|
cpuUpdate(cpu, host) < 0)
|
|
|
|
goto cleanup;
|
2011-12-21 12:47:17 +00:00
|
|
|
|
2014-09-23 17:07:09 +00:00
|
|
|
/* For non-KVM, CPU features are emulated, so host compat doesn't matter */
|
|
|
|
if (compareAgainstHost) {
|
2015-03-24 13:12:07 +00:00
|
|
|
bool noTSX = false;
|
|
|
|
|
2014-09-23 17:07:09 +00:00
|
|
|
cmp = cpuGuestData(host, cpu, &data, &compare_msg);
|
|
|
|
switch (cmp) {
|
|
|
|
case VIR_CPU_COMPARE_INCOMPATIBLE:
|
2015-03-24 13:12:07 +00:00
|
|
|
if (cpuEncode(host->arch, host, NULL, &hostData,
|
|
|
|
NULL, NULL, NULL, NULL) == 0 &&
|
|
|
|
(!cpuHasFeature(hostData, "hle") ||
|
|
|
|
!cpuHasFeature(hostData, "rtm")) &&
|
|
|
|
(STREQ_NULLABLE(cpu->model, "Haswell") ||
|
|
|
|
STREQ_NULLABLE(cpu->model, "Broadwell")))
|
|
|
|
noTSX = true;
|
|
|
|
|
2014-09-23 17:07:09 +00:00
|
|
|
if (compare_msg) {
|
2015-03-24 13:12:07 +00:00
|
|
|
if (noTSX) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("guest and host CPU are not compatible: "
|
|
|
|
"%s; try using '%s-noTSX' CPU model"),
|
|
|
|
compare_msg, cpu->model);
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("guest and host CPU are not compatible: "
|
|
|
|
"%s"),
|
|
|
|
compare_msg);
|
|
|
|
}
|
2014-09-23 17:07:09 +00:00
|
|
|
} else {
|
2015-03-24 13:12:07 +00:00
|
|
|
if (noTSX) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("guest CPU is not compatible with host "
|
|
|
|
"CPU; try using '%s-noTSX' CPU model"),
|
|
|
|
cpu->model);
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("guest CPU is not compatible with host "
|
|
|
|
"CPU"));
|
|
|
|
}
|
2014-09-23 17:07:09 +00:00
|
|
|
}
|
|
|
|
/* fall through */
|
|
|
|
case VIR_CPU_COMPARE_ERROR:
|
|
|
|
goto cleanup;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2014-09-23 17:07:09 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2014-09-23 15:35:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Only 'svm' requires --enable-nesting. The nested
|
|
|
|
* 'vmx' patches now simply hook off the CPU features
|
|
|
|
*/
|
2014-09-23 17:07:09 +00:00
|
|
|
if ((def->os.arch == VIR_ARCH_X86_64 || def->os.arch == VIR_ARCH_I686) &&
|
|
|
|
compareAgainstHost) {
|
2014-09-23 15:35:57 +00:00
|
|
|
int hasSVM = cpuHasFeature(data, "svm");
|
|
|
|
if (hasSVM < 0)
|
2012-02-15 11:18:25 +00:00
|
|
|
goto cleanup;
|
2014-09-23 15:35:57 +00:00
|
|
|
*hasHwVirt = hasSVM > 0 ? true : false;
|
|
|
|
}
|
2012-02-15 11:18:25 +00:00
|
|
|
|
2014-11-04 17:22:44 +00:00
|
|
|
if ((cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) ||
|
|
|
|
((cpu->mode == VIR_CPU_MODE_HOST_MODEL) &&
|
|
|
|
ARCH_IS_PPC64(def->os.arch))) {
|
2014-09-23 15:35:57 +00:00
|
|
|
const char *mode = virCPUModeTypeToString(cpu->mode);
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CPU_HOST)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("CPU mode '%s' is not supported by QEMU"
|
|
|
|
" binary"), mode);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (def->virtType != VIR_DOMAIN_VIRT_KVM) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("CPU mode '%s' is only supported with kvm"),
|
|
|
|
mode);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
virBufferAddLit(buf, "host");
|
2014-11-04 17:22:44 +00:00
|
|
|
|
2015-05-21 22:18:20 +00:00
|
|
|
if (def->os.arch == VIR_ARCH_ARMV7L &&
|
|
|
|
host->arch == VIR_ARCH_AARCH64) {
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CPU_AARCH64_OFF)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("QEMU binary does not support CPU "
|
|
|
|
"host-passthrough for armv7l on "
|
|
|
|
"aarch64 host"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(buf, ",aarch64=off");
|
|
|
|
}
|
|
|
|
|
2014-11-04 17:22:44 +00:00
|
|
|
if (ARCH_IS_PPC64(def->os.arch) &&
|
2015-02-15 04:24:15 +00:00
|
|
|
cpu->mode == VIR_CPU_MODE_HOST_MODEL &&
|
|
|
|
def->cpu->model != NULL) {
|
2014-11-04 17:22:44 +00:00
|
|
|
virBufferAsprintf(buf, ",compat=%s", def->cpu->model);
|
2015-01-05 16:03:58 +00:00
|
|
|
} else {
|
|
|
|
featCpu = cpu;
|
2014-11-04 17:22:44 +00:00
|
|
|
}
|
|
|
|
|
2014-09-23 15:35:57 +00:00
|
|
|
} else {
|
|
|
|
if (VIR_ALLOC(guest) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
if (VIR_STRDUP(guest->vendor_id, cpu->vendor_id) < 0)
|
2012-02-15 11:18:25 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2014-09-23 17:07:09 +00:00
|
|
|
if (compareAgainstHost) {
|
|
|
|
guest->arch = host->arch;
|
|
|
|
if (cpu->match == VIR_CPU_MATCH_MINIMUM)
|
|
|
|
preferred = host->model;
|
|
|
|
else
|
|
|
|
preferred = cpu->model;
|
2014-09-23 15:35:57 +00:00
|
|
|
|
2014-09-23 17:07:09 +00:00
|
|
|
guest->type = VIR_CPU_TYPE_GUEST;
|
|
|
|
guest->fallback = cpu->fallback;
|
|
|
|
if (cpuDecode(guest, data,
|
|
|
|
(const char **)cpus, ncpus, preferred) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
guest->arch = def->os.arch;
|
|
|
|
if (VIR_STRDUP(guest->model, cpu->model) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2014-09-23 15:35:57 +00:00
|
|
|
virBufferAdd(buf, guest->model, -1);
|
|
|
|
if (guest->vendor_id)
|
|
|
|
virBufferAsprintf(buf, ",vendor=%s", guest->vendor_id);
|
2015-01-05 16:03:58 +00:00
|
|
|
featCpu = guest;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (featCpu) {
|
|
|
|
for (i = 0; i < featCpu->nfeatures; i++) {
|
2014-09-23 15:35:57 +00:00
|
|
|
char sign;
|
2015-01-05 16:03:58 +00:00
|
|
|
if (featCpu->features[i].policy == VIR_CPU_FEATURE_DISABLE)
|
2014-09-23 15:35:57 +00:00
|
|
|
sign = '-';
|
|
|
|
else
|
|
|
|
sign = '+';
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2015-01-05 16:03:58 +00:00
|
|
|
virBufferAsprintf(buf, ",%c%s", sign, featCpu->features[i].name);
|
2013-09-03 06:28:23 +00:00
|
|
|
}
|
2014-09-23 15:35:57 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2014-09-23 15:35:57 +00:00
|
|
|
ret = 0;
|
2014-09-23 17:07:09 +00:00
|
|
|
cleanup:
|
2014-09-23 15:35:57 +00:00
|
|
|
virObjectUnref(caps);
|
|
|
|
VIR_FREE(compare_msg);
|
|
|
|
cpuDataFree(data);
|
2015-03-24 13:12:07 +00:00
|
|
|
cpuDataFree(hostData);
|
2014-09-23 15:35:57 +00:00
|
|
|
virCPUDefFree(guest);
|
|
|
|
virCPUDefFree(cpu);
|
|
|
|
return ret;
|
|
|
|
}
|
2011-12-21 12:47:17 +00:00
|
|
|
|
2014-09-23 15:35:57 +00:00
|
|
|
static int
|
2016-02-17 21:12:49 +00:00
|
|
|
qemuBuildCpuCommandLine(virCommandPtr cmd,
|
|
|
|
virQEMUDriverPtr driver,
|
|
|
|
const virDomainDef *def,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
bool migrating)
|
2014-09-23 15:35:57 +00:00
|
|
|
{
|
2016-02-17 21:12:49 +00:00
|
|
|
virArch hostarch = virArchFromHost();
|
|
|
|
char *cpu = NULL;
|
|
|
|
bool hasHwVirt = false;
|
2014-09-23 15:35:57 +00:00
|
|
|
const char *default_model;
|
|
|
|
bool have_cpu = false;
|
|
|
|
int ret = -1;
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
size_t i;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2014-09-23 15:35:57 +00:00
|
|
|
if (def->os.arch == VIR_ARCH_I686)
|
|
|
|
default_model = "qemu32";
|
|
|
|
else
|
|
|
|
default_model = "qemu64";
|
|
|
|
|
|
|
|
if (def->cpu &&
|
|
|
|
(def->cpu->mode != VIR_CPU_MODE_CUSTOM || def->cpu->model)) {
|
|
|
|
if (qemuBuildCpuModelArgStr(driver, def, &buf, qemuCaps,
|
2016-02-17 21:12:49 +00:00
|
|
|
&hasHwVirt, migrating) < 0)
|
2014-09-23 15:35:57 +00:00
|
|
|
goto cleanup;
|
2012-01-27 13:49:52 +00:00
|
|
|
have_cpu = true;
|
2011-12-21 12:47:17 +00:00
|
|
|
} else {
|
2010-12-16 15:07:07 +00:00
|
|
|
/*
|
|
|
|
* Need to force a 32-bit guest CPU type if
|
|
|
|
*
|
|
|
|
* 1. guest OS is i686
|
|
|
|
* 2. host OS is x86_64
|
|
|
|
* 3. emulator is qemu-kvm or kvm
|
|
|
|
*
|
|
|
|
* Or
|
|
|
|
*
|
|
|
|
* 1. guest OS is i686
|
|
|
|
* 2. emulator is qemu-system-x86_64
|
|
|
|
*/
|
2012-12-10 22:28:09 +00:00
|
|
|
if (def->os.arch == VIR_ARCH_I686 &&
|
2012-12-10 22:02:41 +00:00
|
|
|
((hostarch == VIR_ARCH_X86_64 &&
|
2016-02-15 21:23:28 +00:00
|
|
|
strstr(def->emulator, "kvm")) ||
|
|
|
|
strstr(def->emulator, "x86_64"))) {
|
2012-01-27 13:49:52 +00:00
|
|
|
virBufferAdd(&buf, default_model, -1);
|
|
|
|
have_cpu = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-21 17:50:12 +00:00
|
|
|
/* Handle paravirtual timers */
|
2012-01-27 13:49:52 +00:00
|
|
|
for (i = 0; i < def->clock.ntimers; i++) {
|
2014-01-21 17:50:12 +00:00
|
|
|
virDomainTimerDefPtr timer = def->clock.timers[i];
|
|
|
|
|
|
|
|
if (timer->present == -1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (timer->name == VIR_DOMAIN_TIMER_NAME_KVMCLOCK) {
|
2012-01-27 13:49:52 +00:00
|
|
|
virBufferAsprintf(&buf, "%s,%ckvmclock",
|
|
|
|
have_cpu ? "" : default_model,
|
2014-01-21 17:50:12 +00:00
|
|
|
timer->present ? '+' : '-');
|
|
|
|
have_cpu = true;
|
|
|
|
} else if (timer->name == VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK &&
|
|
|
|
timer->present) {
|
|
|
|
virBufferAsprintf(&buf, "%s,hv_time",
|
|
|
|
have_cpu ? "" : default_model);
|
2012-10-08 16:51:57 +00:00
|
|
|
have_cpu = true;
|
2012-01-27 13:49:52 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2012-09-13 13:27:07 +00:00
|
|
|
if (def->apic_eoi) {
|
|
|
|
char sign;
|
2014-06-27 15:18:53 +00:00
|
|
|
if (def->apic_eoi == VIR_TRISTATE_SWITCH_ON)
|
2012-09-13 13:27:07 +00:00
|
|
|
sign = '+';
|
|
|
|
else
|
|
|
|
sign = '-';
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, "%s,%ckvm_pv_eoi",
|
|
|
|
have_cpu ? "" : default_model,
|
|
|
|
sign);
|
2012-10-08 16:51:57 +00:00
|
|
|
have_cpu = true;
|
2012-09-13 13:27:07 +00:00
|
|
|
}
|
|
|
|
|
2013-09-23 16:32:11 +00:00
|
|
|
if (def->features[VIR_DOMAIN_FEATURE_PVSPINLOCK]) {
|
|
|
|
char sign;
|
2016-02-17 21:12:49 +00:00
|
|
|
if (def->features[VIR_DOMAIN_FEATURE_PVSPINLOCK] ==
|
|
|
|
VIR_TRISTATE_SWITCH_ON)
|
2013-09-23 16:32:11 +00:00
|
|
|
sign = '+';
|
|
|
|
else
|
|
|
|
sign = '-';
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, "%s,%ckvm_pv_unhalt",
|
|
|
|
have_cpu ? "" : default_model,
|
|
|
|
sign);
|
|
|
|
have_cpu = true;
|
|
|
|
}
|
|
|
|
|
2014-06-27 15:18:53 +00:00
|
|
|
if (def->features[VIR_DOMAIN_FEATURE_HYPERV] == VIR_TRISTATE_SWITCH_ON) {
|
2012-10-17 12:55:18 +00:00
|
|
|
if (!have_cpu) {
|
|
|
|
virBufferAdd(&buf, default_model, -1);
|
|
|
|
have_cpu = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_DOMAIN_HYPERV_LAST; i++) {
|
2014-06-01 00:22:30 +00:00
|
|
|
switch ((virDomainHyperv) i) {
|
2012-10-17 12:55:18 +00:00
|
|
|
case VIR_DOMAIN_HYPERV_RELAXED:
|
2013-06-21 10:22:18 +00:00
|
|
|
case VIR_DOMAIN_HYPERV_VAPIC:
|
2014-06-27 15:18:53 +00:00
|
|
|
if (def->hyperv_features[i] == VIR_TRISTATE_SWITCH_ON)
|
2012-10-17 12:55:18 +00:00
|
|
|
virBufferAsprintf(&buf, ",hv_%s",
|
|
|
|
virDomainHypervTypeToString(i));
|
|
|
|
break;
|
|
|
|
|
2013-06-21 10:20:12 +00:00
|
|
|
case VIR_DOMAIN_HYPERV_SPINLOCKS:
|
2014-06-27 15:18:53 +00:00
|
|
|
if (def->hyperv_features[i] == VIR_TRISTATE_SWITCH_ON)
|
2013-06-21 10:22:18 +00:00
|
|
|
virBufferAsprintf(&buf, ",hv_spinlocks=0x%x",
|
|
|
|
def->hyperv_spinlocks);
|
2013-06-21 10:20:12 +00:00
|
|
|
break;
|
|
|
|
|
2014-08-27 20:33:12 +00:00
|
|
|
/* coverity[dead_error_begin] */
|
2012-10-17 12:55:18 +00:00
|
|
|
case VIR_DOMAIN_HYPERV_LAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-24 12:26:36 +00:00
|
|
|
for (i = 0; i < def->npanics; i++) {
|
|
|
|
if (def->panics[i]->model == VIR_DOMAIN_PANIC_MODEL_HYPERV) {
|
|
|
|
if (!have_cpu) {
|
|
|
|
virBufferAdd(&buf, default_model, -1);
|
|
|
|
have_cpu = true;
|
|
|
|
}
|
2015-11-24 12:26:33 +00:00
|
|
|
|
2015-11-24 12:26:36 +00:00
|
|
|
virBufferAddLit(&buf, ",hv_crash");
|
|
|
|
break;
|
|
|
|
}
|
2015-11-24 12:26:33 +00:00
|
|
|
}
|
|
|
|
|
2014-08-21 17:04:45 +00:00
|
|
|
if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) {
|
|
|
|
if (!have_cpu) {
|
|
|
|
virBufferAdd(&buf, default_model, -1);
|
|
|
|
have_cpu = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_DOMAIN_KVM_LAST; i++) {
|
|
|
|
switch ((virDomainKVM) i) {
|
|
|
|
case VIR_DOMAIN_KVM_HIDDEN:
|
|
|
|
if (def->kvm_features[i] == VIR_TRISTATE_SWITCH_ON)
|
|
|
|
virBufferAddLit(&buf, ",kvm=off");
|
|
|
|
break;
|
|
|
|
|
2014-09-04 19:19:47 +00:00
|
|
|
/* coverity[dead_error_begin] */
|
2014-08-21 17:04:45 +00:00
|
|
|
case VIR_DOMAIN_KVM_LAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-05 15:52:18 +00:00
|
|
|
if (def->features[VIR_DOMAIN_FEATURE_PMU]) {
|
|
|
|
virTristateSwitch pmu = def->features[VIR_DOMAIN_FEATURE_PMU];
|
|
|
|
if (!have_cpu)
|
|
|
|
virBufferAdd(&buf, default_model, -1);
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, ",pmu=%s",
|
|
|
|
virTristateSwitchTypeToString(pmu));
|
|
|
|
have_cpu = true;
|
|
|
|
}
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2013-05-20 09:23:13 +00:00
|
|
|
goto cleanup;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2016-02-17 21:12:49 +00:00
|
|
|
cpu = virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
if (cpu) {
|
|
|
|
virCommandAddArgList(cmd, "-cpu", cpu, NULL);
|
|
|
|
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NESTING) && hasHwVirt)
|
|
|
|
virCommandAddArg(cmd, "-enable-nesting");
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
cleanup:
|
2016-02-17 21:12:49 +00:00
|
|
|
VIR_FREE(cpu);
|
2010-12-16 15:07:07 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-02-17 21:12:49 +00:00
|
|
|
|
2013-04-23 14:17:08 +00:00
|
|
|
static int
|
|
|
|
qemuBuildObsoleteAccelArg(virCommandPtr cmd,
|
2013-10-08 17:07:53 +00:00
|
|
|
const virDomainDef *def,
|
2013-04-23 14:17:08 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
2013-05-24 10:14:02 +00:00
|
|
|
bool disableKVM = false;
|
|
|
|
bool enableKVM = false;
|
2013-04-23 14:17:08 +00:00
|
|
|
|
|
|
|
switch (def->virtType) {
|
|
|
|
case VIR_DOMAIN_VIRT_QEMU:
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM))
|
2013-05-24 10:14:02 +00:00
|
|
|
disableKVM = true;
|
2013-04-23 14:17:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_VIRT_KQEMU:
|
2015-11-05 11:49:40 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("the QEMU binary does not support kqemu"));
|
2013-04-23 14:17:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_VIRT_KVM:
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_ENABLE_KVM)) {
|
2013-05-24 10:14:02 +00:00
|
|
|
enableKVM = true;
|
2013-04-23 14:17:08 +00:00
|
|
|
} else if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("the QEMU binary does not support kvm"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_VIRT_XEN:
|
|
|
|
/* XXX better check for xenner */
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("the QEMU binary does not support %s"),
|
|
|
|
virDomainVirtTypeToString(def->virtType));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disableKVM)
|
|
|
|
virCommandAddArg(cmd, "-no-kvm");
|
|
|
|
if (enableKVM)
|
|
|
|
virCommandAddArg(cmd, "-enable-kvm");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-27 21:57:29 +00:00
|
|
|
static bool
|
|
|
|
qemuAppendKeyWrapMachineParm(virBuffer *buf, virQEMUCapsPtr qemuCaps,
|
|
|
|
int flag, const char *pname, int pstate)
|
|
|
|
{
|
|
|
|
if (pstate != VIR_TRISTATE_SWITCH_ABSENT) {
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, flag)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("%s is not available with this QEMU binary"), pname);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(buf, ",%s=%s", pname,
|
|
|
|
virTristateSwitchTypeToString(pstate));
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
qemuAppendKeyWrapMachineParms(virBuffer *buf, virQEMUCapsPtr qemuCaps,
|
|
|
|
const virDomainKeyWrapDef *keywrap)
|
|
|
|
{
|
|
|
|
if (!qemuAppendKeyWrapMachineParm(buf, qemuCaps, QEMU_CAPS_AES_KEY_WRAP,
|
|
|
|
"aes-key-wrap", keywrap->aes))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!qemuAppendKeyWrapMachineParm(buf, qemuCaps, QEMU_CAPS_DEA_KEY_WRAP,
|
|
|
|
"dea-key-wrap", keywrap->dea))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-03-10 19:46:39 +00:00
|
|
|
static int
|
|
|
|
qemuBuildNameCommandLine(virCommandPtr cmd,
|
|
|
|
virQEMUDriverConfigPtr cfg,
|
|
|
|
const virDomainDef *def,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-name");
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, "%s", def->name);
|
|
|
|
|
|
|
|
if (cfg->setProcessName &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_NAME_PROCESS))
|
|
|
|
virBufferAsprintf(&buf, ",process=qemu:%s", def->name);
|
|
|
|
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NAME_DEBUG_THREADS))
|
|
|
|
virBufferAddLit(&buf, ",debug-threads=on");
|
|
|
|
|
|
|
|
virCommandAddArgBuffer(cmd, &buf);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-15 07:59:24 +00:00
|
|
|
static int
|
2016-02-17 21:04:17 +00:00
|
|
|
qemuBuildMachineCommandLine(virCommandPtr cmd,
|
|
|
|
const virDomainDef *def,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
2012-08-15 07:59:24 +00:00
|
|
|
{
|
2013-04-23 14:17:08 +00:00
|
|
|
bool obsoleteAccel = false;
|
|
|
|
|
2012-08-15 07:59:24 +00:00
|
|
|
/* This should *never* be NULL, since we always provide
|
|
|
|
* a machine in the capabilities data for QEMU. So this
|
|
|
|
* check is just here as a safety in case the unexpected
|
|
|
|
* happens */
|
|
|
|
if (!def->os.machine)
|
|
|
|
return 0;
|
|
|
|
|
2013-03-29 05:22:46 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_OPT)) {
|
2012-08-15 07:59:24 +00:00
|
|
|
/* if no parameter to the machine type is needed, we still use
|
|
|
|
* '-M' to keep the most of the compatibility with older versions.
|
|
|
|
*/
|
|
|
|
virCommandAddArgList(cmd, "-M", def->os.machine, NULL);
|
2013-03-29 05:22:46 +00:00
|
|
|
if (def->mem.dump_core) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("dump-guest-core is not available "
|
|
|
|
"with this QEMU binary"));
|
2012-08-15 07:59:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2013-05-14 05:25:50 +00:00
|
|
|
|
|
|
|
if (def->mem.nosharepages) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("disable shared memory is not available "
|
|
|
|
"with this QEMU binary"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-04-23 14:17:08 +00:00
|
|
|
obsoleteAccel = true;
|
2015-04-27 21:57:29 +00:00
|
|
|
|
|
|
|
if (def->keywrap) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("key wrap support is not available "
|
|
|
|
"with this QEMU binary"));
|
|
|
|
return -1;
|
|
|
|
}
|
2013-03-29 05:22:46 +00:00
|
|
|
} else {
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2015-04-02 16:44:08 +00:00
|
|
|
virTristateSwitch vmport = def->features[VIR_DOMAIN_FEATURE_VMPORT];
|
2012-08-15 07:59:24 +00:00
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-machine");
|
2013-03-29 05:22:46 +00:00
|
|
|
virBufferAdd(&buf, def->os.machine, -1);
|
|
|
|
|
2013-04-23 14:17:08 +00:00
|
|
|
if (def->virtType == VIR_DOMAIN_VIRT_QEMU)
|
|
|
|
virBufferAddLit(&buf, ",accel=tcg");
|
|
|
|
else if (def->virtType == VIR_DOMAIN_VIRT_KVM)
|
|
|
|
virBufferAddLit(&buf, ",accel=kvm");
|
|
|
|
else
|
|
|
|
obsoleteAccel = true;
|
|
|
|
|
2013-04-07 08:31:57 +00:00
|
|
|
/* To avoid the collision of creating USB controllers when calling
|
|
|
|
* machine->init in QEMU, it needs to set usb=off
|
|
|
|
*/
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_USB_OPT))
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(&buf, ",usb=off");
|
2013-04-07 08:31:57 +00:00
|
|
|
|
2015-04-02 16:44:08 +00:00
|
|
|
if (vmport) {
|
|
|
|
if (!virQEMUCapsSupportsVmport(qemuCaps, def)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("vmport is not available "
|
|
|
|
"with this QEMU binary"));
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, ",vmport=%s",
|
|
|
|
virTristateSwitchTypeToString(vmport));
|
|
|
|
}
|
|
|
|
|
2013-03-29 05:22:46 +00:00
|
|
|
if (def->mem.dump_core) {
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DUMP_GUEST_CORE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("dump-guest-core is not available "
|
|
|
|
"with this QEMU binary"));
|
2013-04-03 17:26:41 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
2013-03-29 05:22:46 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, ",dump-guest-core=%s",
|
2014-06-27 15:18:53 +00:00
|
|
|
virTristateSwitchTypeToString(def->mem.dump_core));
|
2013-03-29 05:22:46 +00:00
|
|
|
}
|
|
|
|
|
2013-05-14 05:25:50 +00:00
|
|
|
if (def->mem.nosharepages) {
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_MEM_MERGE)) {
|
|
|
|
virBufferAddLit(&buf, ",mem-merge=off");
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("disable shared memory is not available "
|
|
|
|
"with this QEMU binary"));
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-27 21:57:29 +00:00
|
|
|
if (def->keywrap &&
|
|
|
|
!qemuAppendKeyWrapMachineParms(&buf, qemuCaps, def->keywrap)) {
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return -1;
|
|
|
|
}
|
2015-09-30 11:04:10 +00:00
|
|
|
|
|
|
|
if (def->features[VIR_DOMAIN_FEATURE_GIC] == VIR_TRISTATE_SWITCH_ON) {
|
2016-02-03 13:33:28 +00:00
|
|
|
if (def->gic_version != VIR_GIC_VERSION_NONE) {
|
2015-09-30 11:04:10 +00:00
|
|
|
if ((def->os.arch != VIR_ARCH_ARMV7L &&
|
|
|
|
def->os.arch != VIR_ARCH_AARCH64) ||
|
|
|
|
(STRNEQ(def->os.machine, "virt") &&
|
|
|
|
!STRPREFIX(def->os.machine, "virt-"))) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("gic-version option is available "
|
|
|
|
"only for ARM virt machine"));
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-02-18 15:13:42 +00:00
|
|
|
/* The default GIC version should not be specified on the
|
|
|
|
* QEMU commandline for backwards compatibility reasons */
|
|
|
|
if (def->gic_version != VIR_GIC_VERSION_DEFAULT) {
|
2015-09-30 11:04:10 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps,
|
|
|
|
QEMU_CAPS_MACH_VIRT_GIC_VERSION)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("gic-version option is not available "
|
|
|
|
"with this QEMU binary"));
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-02-03 13:33:28 +00:00
|
|
|
virBufferAsprintf(&buf, ",gic-version=%s",
|
|
|
|
virGICVersionTypeToString(def->gic_version));
|
2015-09-30 11:04:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-04-27 21:57:29 +00:00
|
|
|
|
2013-03-29 05:22:46 +00:00
|
|
|
virCommandAddArgBuffer(cmd, &buf);
|
2012-08-15 07:59:24 +00:00
|
|
|
}
|
|
|
|
|
2013-04-23 14:17:08 +00:00
|
|
|
if (obsoleteAccel &&
|
|
|
|
qemuBuildObsoleteAccelArg(cmd, def, qemuCaps) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2012-08-15 07:59:24 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-02-17 21:23:46 +00:00
|
|
|
static int
|
|
|
|
qemuBuildSmpCommandLine(virCommandPtr cmd,
|
|
|
|
const virDomainDef *def,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
2016-02-17 21:23:46 +00:00
|
|
|
char *smp;
|
2010-12-16 15:07:07 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
2016-02-17 21:23:46 +00:00
|
|
|
virCommandAddArg(cmd, "-smp");
|
|
|
|
|
2015-10-22 12:59:03 +00:00
|
|
|
virBufferAsprintf(&buf, "%u", virDomainDefGetVcpus(def));
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SMP_TOPOLOGY)) {
|
2015-10-19 16:23:23 +00:00
|
|
|
if (virDomainDefHasVcpusOffline(def))
|
2016-02-17 21:23:46 +00:00
|
|
|
virBufferAsprintf(&buf, ",maxcpus=%u",
|
|
|
|
virDomainDefGetVcpusMax(def));
|
2010-12-16 15:07:07 +00:00
|
|
|
/* sockets, cores, and threads are either all zero
|
|
|
|
* or all non-zero, thus checking one of them is enough */
|
|
|
|
if (def->cpu && def->cpu->sockets) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",sockets=%u", def->cpu->sockets);
|
|
|
|
virBufferAsprintf(&buf, ",cores=%u", def->cpu->cores);
|
|
|
|
virBufferAsprintf(&buf, ",threads=%u", def->cpu->threads);
|
2014-09-03 19:32:36 +00:00
|
|
|
} else {
|
2016-02-17 21:23:46 +00:00
|
|
|
virBufferAsprintf(&buf, ",sockets=%u",
|
|
|
|
virDomainDefGetVcpusMax(def));
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",cores=%u", 1);
|
|
|
|
virBufferAsprintf(&buf, ",threads=%u", 1);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2015-10-19 16:23:23 +00:00
|
|
|
} else if (virDomainDefHasVcpusOffline(def)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
/* FIXME - consider hot-unplugging cpus after boot for older qemu */
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("setting current vcpu count less than maximum is "
|
|
|
|
"not supported with this QEMU binary"));
|
2016-02-17 21:23:46 +00:00
|
|
|
return -1;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2016-02-17 21:23:46 +00:00
|
|
|
return -1;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2016-02-17 21:23:46 +00:00
|
|
|
smp = virBufferContentAndReset(&buf);
|
|
|
|
virCommandAddArg(cmd, smp);
|
|
|
|
VIR_FREE(smp);
|
|
|
|
|
|
|
|
return 0;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2016-02-17 21:23:46 +00:00
|
|
|
|
2015-10-01 05:47:39 +00:00
|
|
|
static int
|
|
|
|
qemuBuildMemPathStr(virQEMUDriverConfigPtr cfg,
|
2016-02-17 21:19:26 +00:00
|
|
|
const virDomainDef *def,
|
2015-10-01 05:47:39 +00:00
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
virCommandPtr cmd)
|
|
|
|
{
|
|
|
|
const long system_page_size = virGetSystemPageSizeKB();
|
|
|
|
char *mem_path = NULL;
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* No-op if hugepages were not requested.
|
|
|
|
*/
|
|
|
|
if (!def->mem.nhugepages)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* There is one special case: if user specified "huge"
|
|
|
|
* pages of regular system pages size.
|
|
|
|
* And there is nothing to do in this case.
|
|
|
|
*/
|
|
|
|
if (def->mem.hugepages[0].size == system_page_size)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!cfg->nhugetlbfs) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("hugetlbfs filesystem is not mounted "
|
|
|
|
"or disabled by administrator config"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MEM_PATH)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("hugepage backing not supported by '%s'"),
|
|
|
|
def->emulator);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!def->mem.hugepages[0].size) {
|
|
|
|
if (!(mem_path = qemuGetDefaultHugepath(cfg->hugetlbfs,
|
|
|
|
cfg->nhugetlbfs)))
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < cfg->nhugetlbfs; i++) {
|
|
|
|
if (cfg->hugetlbfs[i].size == def->mem.hugepages[0].size)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == cfg->nhugetlbfs) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to find any usable hugetlbfs "
|
|
|
|
"mount for %llu KiB"),
|
|
|
|
def->mem.hugepages[0].size);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(mem_path = qemuGetHugepagePath(&cfg->hugetlbfs[i])))
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArgList(cmd, "-mem-prealloc", "-mem-path", mem_path, NULL);
|
|
|
|
VIR_FREE(mem_path);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-02-17 21:19:26 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
qemuBuildMemCommandLine(virCommandPtr cmd,
|
|
|
|
virQEMUDriverConfigPtr cfg,
|
|
|
|
const virDomainDef *def,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
if (qemuDomainDefValidateMemoryHotplug(def, qemuCaps, NULL) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-m");
|
|
|
|
|
|
|
|
if (virDomainDefHasMemoryHotplug(def)) {
|
|
|
|
/* Use the 'k' suffix to let qemu handle the units */
|
|
|
|
virCommandAddArgFormat(cmd, "size=%lluk,slots=%u,maxmem=%lluk",
|
|
|
|
virDomainDefGetMemoryInitial(def),
|
|
|
|
def->mem.memory_slots,
|
|
|
|
def->mem.max_memory);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
virCommandAddArgFormat(cmd, "%llu",
|
|
|
|
virDomainDefGetMemoryInitial(def) / 1024);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add '-mem-path' (and '-mem-prealloc') parameter here only if
|
|
|
|
* there is no numa node specified.
|
|
|
|
*/
|
|
|
|
if (!virDomainNumaGetNodeCount(def->numa) &&
|
|
|
|
qemuBuildMemPathStr(cfg, def, qemuCaps, cmd) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (def->mem.locked && !virQEMUCapsGet(qemuCaps, QEMU_CAPS_MLOCK)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("memory locking not supported by QEMU binary"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_MLOCK)) {
|
|
|
|
virCommandAddArg(cmd, "-realtime");
|
|
|
|
virCommandAddArgFormat(cmd, "mlock=%s",
|
|
|
|
def->mem.locked ? "on" : "off");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-17 21:27:30 +00:00
|
|
|
static int
|
|
|
|
qemuBuildIOThreadCommandLine(virCommandPtr cmd,
|
|
|
|
const virDomainDef *def,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (def->niothreadids == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_IOTHREAD)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("IOThreads not supported for this QEMU"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create iothread objects using the defined iothreadids list
|
|
|
|
* and the defined id and name from the list. These may be used
|
|
|
|
* by a disk definition which will associate to an iothread by
|
|
|
|
* supplying a value of an id from the list
|
|
|
|
*/
|
|
|
|
for (i = 0; i < def->niothreadids; i++) {
|
|
|
|
virCommandAddArg(cmd, "-object");
|
|
|
|
virCommandAddArgFormat(cmd, "iothread,id=iothread%u",
|
|
|
|
def->iothreadids[i]->iothread_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-11 12:53:04 +00:00
|
|
|
static int
|
2014-07-23 15:37:21 +00:00
|
|
|
qemuBuildNumaArgStr(virQEMUDriverConfigPtr cfg,
|
2015-01-09 14:47:10 +00:00
|
|
|
virDomainDefPtr def,
|
2014-06-17 12:16:59 +00:00
|
|
|
virCommandPtr cmd,
|
2014-10-30 06:34:30 +00:00
|
|
|
virQEMUCapsPtr qemuCaps,
|
2015-01-09 09:34:12 +00:00
|
|
|
virBitmapPtr auto_nodeset)
|
2011-11-11 12:53:04 +00:00
|
|
|
{
|
2015-01-09 09:34:12 +00:00
|
|
|
size_t i;
|
2011-11-11 12:53:04 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2014-06-17 12:16:59 +00:00
|
|
|
char *cpumask = NULL, *tmpmask = NULL, *next = NULL;
|
qemu: command: Don't combine old and modern NUMA node creation
Change done by commit f309db1f4d51009bad0d32e12efc75530b66836b wrongly
assumes that qemu can start with a combination of NUMA nodes specified
with the "memdev" option and the appropriate backends, and the legacy
way by specifying only "mem" as a size argument. QEMU rejects such
commandline though:
$ /usr/bin/qemu-system-x86_64 -S -M pc -m 1024 -smp 2 \
-numa node,nodeid=0,cpus=0,mem=256 \
-object memory-backend-ram,id=ram-node1,size=12345 \
-numa node,nodeid=1,cpus=1,memdev=ram-node1
qemu-system-x86_64: -numa node,nodeid=1,cpus=1,memdev=ram-node1: qemu: memdev option must be specified for either all or no nodes
To fix this issue we need to check if any of the nodes requires the new
definition with the backend and if so, then all other nodes have to use
it too.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1182467
2015-01-26 12:48:02 +00:00
|
|
|
char **nodeBackends = NULL;
|
|
|
|
bool needBackend = false;
|
|
|
|
int rc;
|
2013-02-27 00:43:12 +00:00
|
|
|
int ret = -1;
|
2015-02-16 16:28:48 +00:00
|
|
|
size_t ncells = virDomainNumaGetNodeCount(def->numa);
|
2015-02-02 10:26:49 +00:00
|
|
|
const long system_page_size = virGetSystemPageSizeKB();
|
2011-11-11 12:53:04 +00:00
|
|
|
|
2015-02-11 13:54:59 +00:00
|
|
|
if (virDomainNumatuneHasPerNodeBinding(def->numa) &&
|
2014-07-23 15:37:21 +00:00
|
|
|
!(virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM) ||
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE))) {
|
2014-07-02 09:15:45 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Per-node memory binding is not supported "
|
|
|
|
"with this QEMU"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-12-12 09:37:35 +00:00
|
|
|
if (def->mem.nhugepages &&
|
|
|
|
def->mem.hugepages[0].size != system_page_size &&
|
2014-07-23 15:37:21 +00:00
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("huge pages per NUMA node are not "
|
|
|
|
"supported with this QEMU"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-02-11 13:54:59 +00:00
|
|
|
if (!virDomainNumatuneNodesetIsAvailable(def->numa, auto_nodeset))
|
2014-11-04 02:44:40 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2014-09-15 09:59:09 +00:00
|
|
|
for (i = 0; i < def->mem.nhugepages; i++) {
|
|
|
|
ssize_t next_bit, pos = 0;
|
|
|
|
|
|
|
|
if (!def->mem.hugepages[i].nodemask) {
|
|
|
|
/* This is the master hugepage to use. Skip it as it has no
|
|
|
|
* nodemask anyway. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-02-16 16:55:50 +00:00
|
|
|
if (ncells) {
|
2014-09-15 09:59:09 +00:00
|
|
|
/* Fortunately, we allow only guest NUMA nodes to be continuous
|
|
|
|
* starting from zero. */
|
2015-02-16 16:55:50 +00:00
|
|
|
pos = ncells - 1;
|
2014-09-15 09:59:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
next_bit = virBitmapNextSetBit(def->mem.hugepages[i].nodemask, pos);
|
|
|
|
if (next_bit >= 0) {
|
|
|
|
virReportError(VIR_ERR_XML_DETAIL,
|
|
|
|
_("hugepages: node %zd not found"),
|
|
|
|
next_bit);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-16 16:55:50 +00:00
|
|
|
if (VIR_ALLOC_N(nodeBackends, ncells) < 0)
|
qemu: command: Don't combine old and modern NUMA node creation
Change done by commit f309db1f4d51009bad0d32e12efc75530b66836b wrongly
assumes that qemu can start with a combination of NUMA nodes specified
with the "memdev" option and the appropriate backends, and the legacy
way by specifying only "mem" as a size argument. QEMU rejects such
commandline though:
$ /usr/bin/qemu-system-x86_64 -S -M pc -m 1024 -smp 2 \
-numa node,nodeid=0,cpus=0,mem=256 \
-object memory-backend-ram,id=ram-node1,size=12345 \
-numa node,nodeid=1,cpus=1,memdev=ram-node1
qemu-system-x86_64: -numa node,nodeid=1,cpus=1,memdev=ram-node1: qemu: memdev option must be specified for either all or no nodes
To fix this issue we need to check if any of the nodes requires the new
definition with the backend and if so, then all other nodes have to use
it too.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1182467
2015-01-26 12:48:02 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* using of -numa memdev= cannot be combined with -numa mem=, thus we
|
|
|
|
* need to check which approach to use */
|
2015-02-16 16:55:50 +00:00
|
|
|
for (i = 0; i < ncells; i++) {
|
2014-07-23 15:37:21 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM) ||
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE)) {
|
qemu: command: Don't combine old and modern NUMA node creation
Change done by commit f309db1f4d51009bad0d32e12efc75530b66836b wrongly
assumes that qemu can start with a combination of NUMA nodes specified
with the "memdev" option and the appropriate backends, and the legacy
way by specifying only "mem" as a size argument. QEMU rejects such
commandline though:
$ /usr/bin/qemu-system-x86_64 -S -M pc -m 1024 -smp 2 \
-numa node,nodeid=0,cpus=0,mem=256 \
-object memory-backend-ram,id=ram-node1,size=12345 \
-numa node,nodeid=1,cpus=1,memdev=ram-node1
qemu-system-x86_64: -numa node,nodeid=1,cpus=1,memdev=ram-node1: qemu: memdev option must be specified for either all or no nodes
To fix this issue we need to check if any of the nodes requires the new
definition with the backend and if so, then all other nodes have to use
it too.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1182467
2015-01-26 12:48:02 +00:00
|
|
|
if ((rc = qemuBuildMemoryCellBackendStr(def, qemuCaps, cfg, i,
|
|
|
|
auto_nodeset,
|
|
|
|
&nodeBackends[i])) < 0)
|
2014-07-02 09:15:45 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
qemu: command: Don't combine old and modern NUMA node creation
Change done by commit f309db1f4d51009bad0d32e12efc75530b66836b wrongly
assumes that qemu can start with a combination of NUMA nodes specified
with the "memdev" option and the appropriate backends, and the legacy
way by specifying only "mem" as a size argument. QEMU rejects such
commandline though:
$ /usr/bin/qemu-system-x86_64 -S -M pc -m 1024 -smp 2 \
-numa node,nodeid=0,cpus=0,mem=256 \
-object memory-backend-ram,id=ram-node1,size=12345 \
-numa node,nodeid=1,cpus=1,memdev=ram-node1
qemu-system-x86_64: -numa node,nodeid=1,cpus=1,memdev=ram-node1: qemu: memdev option must be specified for either all or no nodes
To fix this issue we need to check if any of the nodes requires the new
definition with the backend and if so, then all other nodes have to use
it too.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1182467
2015-01-26 12:48:02 +00:00
|
|
|
if (rc == 0)
|
|
|
|
needBackend = true;
|
2014-09-08 09:36:09 +00:00
|
|
|
} else {
|
2015-02-16 16:28:48 +00:00
|
|
|
if (virDomainNumaGetNodeMemoryAccessMode(def->numa, i)) {
|
2014-09-08 09:36:09 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Shared memory mapping is not supported "
|
|
|
|
"with this QEMU"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2014-07-02 09:15:45 +00:00
|
|
|
}
|
qemu: command: Don't combine old and modern NUMA node creation
Change done by commit f309db1f4d51009bad0d32e12efc75530b66836b wrongly
assumes that qemu can start with a combination of NUMA nodes specified
with the "memdev" option and the appropriate backends, and the legacy
way by specifying only "mem" as a size argument. QEMU rejects such
commandline though:
$ /usr/bin/qemu-system-x86_64 -S -M pc -m 1024 -smp 2 \
-numa node,nodeid=0,cpus=0,mem=256 \
-object memory-backend-ram,id=ram-node1,size=12345 \
-numa node,nodeid=1,cpus=1,memdev=ram-node1
qemu-system-x86_64: -numa node,nodeid=1,cpus=1,memdev=ram-node1: qemu: memdev option must be specified for either all or no nodes
To fix this issue we need to check if any of the nodes requires the new
definition with the backend and if so, then all other nodes have to use
it too.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1182467
2015-01-26 12:48:02 +00:00
|
|
|
}
|
|
|
|
|
2015-10-01 06:15:48 +00:00
|
|
|
if (!needBackend &&
|
|
|
|
qemuBuildMemPathStr(cfg, def, qemuCaps, cmd) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-02-16 16:55:50 +00:00
|
|
|
for (i = 0; i < ncells; i++) {
|
qemu: command: Don't combine old and modern NUMA node creation
Change done by commit f309db1f4d51009bad0d32e12efc75530b66836b wrongly
assumes that qemu can start with a combination of NUMA nodes specified
with the "memdev" option and the appropriate backends, and the legacy
way by specifying only "mem" as a size argument. QEMU rejects such
commandline though:
$ /usr/bin/qemu-system-x86_64 -S -M pc -m 1024 -smp 2 \
-numa node,nodeid=0,cpus=0,mem=256 \
-object memory-backend-ram,id=ram-node1,size=12345 \
-numa node,nodeid=1,cpus=1,memdev=ram-node1
qemu-system-x86_64: -numa node,nodeid=1,cpus=1,memdev=ram-node1: qemu: memdev option must be specified for either all or no nodes
To fix this issue we need to check if any of the nodes requires the new
definition with the backend and if so, then all other nodes have to use
it too.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1182467
2015-01-26 12:48:02 +00:00
|
|
|
VIR_FREE(cpumask);
|
2015-02-16 16:28:48 +00:00
|
|
|
if (!(cpumask = virBitmapFormat(virDomainNumaGetNodeCpumask(def->numa, i))))
|
qemu: command: Don't combine old and modern NUMA node creation
Change done by commit f309db1f4d51009bad0d32e12efc75530b66836b wrongly
assumes that qemu can start with a combination of NUMA nodes specified
with the "memdev" option and the appropriate backends, and the legacy
way by specifying only "mem" as a size argument. QEMU rejects such
commandline though:
$ /usr/bin/qemu-system-x86_64 -S -M pc -m 1024 -smp 2 \
-numa node,nodeid=0,cpus=0,mem=256 \
-object memory-backend-ram,id=ram-node1,size=12345 \
-numa node,nodeid=1,cpus=1,memdev=ram-node1
qemu-system-x86_64: -numa node,nodeid=1,cpus=1,memdev=ram-node1: qemu: memdev option must be specified for either all or no nodes
To fix this issue we need to check if any of the nodes requires the new
definition with the backend and if so, then all other nodes have to use
it too.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1182467
2015-01-26 12:48:02 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (strchr(cpumask, ',') &&
|
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_NUMA)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("disjoint NUMA cpu ranges are not supported "
|
|
|
|
"with this QEMU"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (needBackend)
|
|
|
|
virCommandAddArgList(cmd, "-object", nodeBackends[i], NULL);
|
2014-07-02 09:15:45 +00:00
|
|
|
|
2011-11-11 12:53:04 +00:00
|
|
|
virCommandAddArg(cmd, "-numa");
|
2014-05-22 07:13:05 +00:00
|
|
|
virBufferAsprintf(&buf, "node,nodeid=%zu", i);
|
2013-09-23 16:43:47 +00:00
|
|
|
|
2014-06-17 12:16:59 +00:00
|
|
|
for (tmpmask = cpumask; tmpmask; tmpmask = next) {
|
|
|
|
if ((next = strchr(tmpmask, ',')))
|
|
|
|
*(next++) = '\0';
|
|
|
|
virBufferAddLit(&buf, ",cpus=");
|
|
|
|
virBufferAdd(&buf, tmpmask, -1);
|
|
|
|
}
|
|
|
|
|
qemu: command: Don't combine old and modern NUMA node creation
Change done by commit f309db1f4d51009bad0d32e12efc75530b66836b wrongly
assumes that qemu can start with a combination of NUMA nodes specified
with the "memdev" option and the appropriate backends, and the legacy
way by specifying only "mem" as a size argument. QEMU rejects such
commandline though:
$ /usr/bin/qemu-system-x86_64 -S -M pc -m 1024 -smp 2 \
-numa node,nodeid=0,cpus=0,mem=256 \
-object memory-backend-ram,id=ram-node1,size=12345 \
-numa node,nodeid=1,cpus=1,memdev=ram-node1
qemu-system-x86_64: -numa node,nodeid=1,cpus=1,memdev=ram-node1: qemu: memdev option must be specified for either all or no nodes
To fix this issue we need to check if any of the nodes requires the new
definition with the backend and if so, then all other nodes have to use
it too.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1182467
2015-01-26 12:48:02 +00:00
|
|
|
if (needBackend)
|
2014-07-02 09:15:45 +00:00
|
|
|
virBufferAsprintf(&buf, ",memdev=ram-node%zu", i);
|
qemu: Create memory-backend-{ram,file} iff needed
Libvirt BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1175397
QEMU BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1170093
In qemu there are two interesting arguments:
1) -numa to create a guest NUMA node
2) -object memory-backend-{ram,file} to tell qemu which memory
region on which host's NUMA node it should allocate the guest
memory from.
Combining these two together we can instruct qemu to create a
guest NUMA node that is tied to a host NUMA node. And it works
just fine. However, depending on machine type used, there might
be some issued during migration when OVMF is enabled (see QEMU
BZ). While this truly is a QEMU bug, we can help avoiding it. The
problem lies within the memory backend objects somewhere. Having
said that, fix on our side consists on putting those objects on
the command line if and only if needed. For instance, while
previously we would construct this (in all ways correct) command
line:
-object memory-backend-ram,size=256M,id=ram-node0 \
-numa node,nodeid=0,cpus=0,memdev=ram-node0
now we create just:
-numa node,nodeid=0,cpus=0,mem=256
because the backend object is obviously not tied to any specific
host NUMA node.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2014-12-18 11:36:48 +00:00
|
|
|
else
|
2015-02-16 18:14:23 +00:00
|
|
|
virBufferAsprintf(&buf, ",mem=%llu",
|
2015-02-16 16:28:48 +00:00
|
|
|
virDomainNumaGetNodeMemorySize(def->numa, i) / 1024);
|
2011-11-11 12:53:04 +00:00
|
|
|
|
|
|
|
virCommandAddArgBuffer(cmd, &buf);
|
|
|
|
}
|
2013-02-27 00:43:12 +00:00
|
|
|
ret = 0;
|
2011-11-11 12:53:04 +00:00
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
cleanup:
|
2013-02-27 00:43:12 +00:00
|
|
|
VIR_FREE(cpumask);
|
qemu: command: Don't combine old and modern NUMA node creation
Change done by commit f309db1f4d51009bad0d32e12efc75530b66836b wrongly
assumes that qemu can start with a combination of NUMA nodes specified
with the "memdev" option and the appropriate backends, and the legacy
way by specifying only "mem" as a size argument. QEMU rejects such
commandline though:
$ /usr/bin/qemu-system-x86_64 -S -M pc -m 1024 -smp 2 \
-numa node,nodeid=0,cpus=0,mem=256 \
-object memory-backend-ram,id=ram-node1,size=12345 \
-numa node,nodeid=1,cpus=1,memdev=ram-node1
qemu-system-x86_64: -numa node,nodeid=1,cpus=1,memdev=ram-node1: qemu: memdev option must be specified for either all or no nodes
To fix this issue we need to check if any of the nodes requires the new
definition with the backend and if so, then all other nodes have to use
it too.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1182467
2015-01-26 12:48:02 +00:00
|
|
|
|
|
|
|
if (nodeBackends) {
|
2015-02-16 16:55:50 +00:00
|
|
|
for (i = 0; i < ncells; i++)
|
qemu: command: Don't combine old and modern NUMA node creation
Change done by commit f309db1f4d51009bad0d32e12efc75530b66836b wrongly
assumes that qemu can start with a combination of NUMA nodes specified
with the "memdev" option and the appropriate backends, and the legacy
way by specifying only "mem" as a size argument. QEMU rejects such
commandline though:
$ /usr/bin/qemu-system-x86_64 -S -M pc -m 1024 -smp 2 \
-numa node,nodeid=0,cpus=0,mem=256 \
-object memory-backend-ram,id=ram-node1,size=12345 \
-numa node,nodeid=1,cpus=1,memdev=ram-node1
qemu-system-x86_64: -numa node,nodeid=1,cpus=1,memdev=ram-node1: qemu: memdev option must be specified for either all or no nodes
To fix this issue we need to check if any of the nodes requires the new
definition with the backend and if so, then all other nodes have to use
it too.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1182467
2015-01-26 12:48:02 +00:00
|
|
|
VIR_FREE(nodeBackends[i]);
|
|
|
|
|
|
|
|
VIR_FREE(nodeBackends);
|
|
|
|
}
|
|
|
|
|
2011-11-11 12:53:04 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
2013-02-27 00:43:12 +00:00
|
|
|
return ret;
|
2011-11-11 12:53:04 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2013-04-22 12:39:46 +00:00
|
|
|
|
2016-02-17 21:56:37 +00:00
|
|
|
static int
|
|
|
|
qemuBuildNumaCommandLine(virCommandPtr cmd,
|
|
|
|
virQEMUDriverConfigPtr cfg,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
virBitmapPtr nodeset)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (virDomainNumaGetNodeCount(def->numa) &&
|
|
|
|
qemuBuildNumaArgStr(cfg, def, cmd, qemuCaps, nodeset) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* memory hotplug requires NUMA to be enabled - we already checked
|
|
|
|
* that memory devices are present only when NUMA is */
|
|
|
|
for (i = 0; i < def->nmems; i++) {
|
|
|
|
char *backStr;
|
|
|
|
char *dimmStr;
|
|
|
|
|
|
|
|
if (!(backStr = qemuBuildMemoryDimmBackendStr(def->mems[i], def,
|
|
|
|
qemuCaps, cfg)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!(dimmStr = qemuBuildMemoryDeviceStr(def->mems[i]))) {
|
|
|
|
VIR_FREE(backStr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArgList(cmd, "-object", backStr, "-device", dimmStr, NULL);
|
|
|
|
|
|
|
|
VIR_FREE(backStr);
|
|
|
|
VIR_FREE(dimmStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-22 12:39:46 +00:00
|
|
|
static int
|
|
|
|
qemuBuildGraphicsVNCCommandLine(virQEMUDriverConfigPtr cfg,
|
|
|
|
virCommandPtr cmd,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
2016-02-26 08:15:55 +00:00
|
|
|
virDomainGraphicsDefPtr graphics,
|
|
|
|
const char *domainLibDir)
|
2013-04-22 12:39:46 +00:00
|
|
|
{
|
|
|
|
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
|
|
|
const char *listenNetwork;
|
|
|
|
const char *listenAddr = NULL;
|
|
|
|
char *netAddr = NULL;
|
|
|
|
bool escapeAddr;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VNC)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("vnc graphics are not supported with this QEMU"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (graphics->data.vnc.socket || cfg->vncAutoUnixSocket) {
|
|
|
|
if (!graphics->data.vnc.socket &&
|
|
|
|
virAsprintf(&graphics->data.vnc.socket,
|
2016-02-26 08:15:55 +00:00
|
|
|
"%s/vnc.sock", domainLibDir) == -1)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-04-22 12:39:46 +00:00
|
|
|
|
|
|
|
virBufferAsprintf(&opt, "unix:%s", graphics->data.vnc.socket);
|
|
|
|
|
2015-05-12 16:18:14 +00:00
|
|
|
} else {
|
|
|
|
if (!graphics->data.vnc.autoport &&
|
|
|
|
(graphics->data.vnc.port < 5900 ||
|
|
|
|
graphics->data.vnc.port > 65535)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("vnc port must be in range [5900,65535]"));
|
|
|
|
goto error;
|
|
|
|
}
|
2013-04-22 12:39:46 +00:00
|
|
|
|
2015-11-05 11:56:47 +00:00
|
|
|
switch (virDomainGraphicsListenGetType(graphics, 0)) {
|
|
|
|
case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS:
|
|
|
|
listenAddr = virDomainGraphicsListenGetAddress(graphics, 0);
|
|
|
|
break;
|
2013-04-22 12:39:46 +00:00
|
|
|
|
2015-11-05 11:56:47 +00:00
|
|
|
case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK:
|
|
|
|
listenNetwork = virDomainGraphicsListenGetNetwork(graphics, 0);
|
|
|
|
if (!listenNetwork)
|
2015-05-12 16:18:14 +00:00
|
|
|
break;
|
2015-11-05 11:56:47 +00:00
|
|
|
ret = networkGetNetworkAddress(listenNetwork, &netAddr);
|
|
|
|
if (ret <= -2) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("network-based listen not possible, "
|
|
|
|
"network driver not present"));
|
|
|
|
goto error;
|
2015-05-12 16:18:14 +00:00
|
|
|
}
|
2015-11-05 11:56:47 +00:00
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
2013-04-22 12:39:46 +00:00
|
|
|
|
2015-11-05 11:56:47 +00:00
|
|
|
listenAddr = netAddr;
|
|
|
|
/* store the address we found in the <graphics> element so it
|
|
|
|
* will show up in status. */
|
|
|
|
if (virDomainGraphicsListenSetAddress(graphics, 0,
|
|
|
|
listenAddr, -1, false) < 0)
|
|
|
|
goto error;
|
|
|
|
break;
|
|
|
|
}
|
2013-04-22 12:39:46 +00:00
|
|
|
|
2015-11-05 11:56:47 +00:00
|
|
|
if (!listenAddr)
|
|
|
|
listenAddr = cfg->vncListen;
|
2015-05-12 16:18:14 +00:00
|
|
|
|
2015-11-05 11:56:47 +00:00
|
|
|
escapeAddr = strchr(listenAddr, ':') != NULL;
|
|
|
|
if (escapeAddr)
|
|
|
|
virBufferAsprintf(&opt, "[%s]", listenAddr);
|
|
|
|
else
|
|
|
|
virBufferAdd(&opt, listenAddr, -1);
|
|
|
|
virBufferAsprintf(&opt, ":%d",
|
|
|
|
graphics->data.vnc.port - 5900);
|
|
|
|
|
|
|
|
VIR_FREE(netAddr);
|
2013-04-22 12:39:46 +00:00
|
|
|
}
|
|
|
|
|
2015-11-05 11:56:47 +00:00
|
|
|
if (!graphics->data.vnc.socket &&
|
|
|
|
graphics->data.vnc.websocket) {
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VNC_WEBSOCKET)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("VNC WebSockets are not supported "
|
|
|
|
"with this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAsprintf(&opt, ",websocket=%d", graphics->data.vnc.websocket);
|
|
|
|
}
|
2013-04-30 14:26:43 +00:00
|
|
|
|
2015-11-05 11:56:47 +00:00
|
|
|
if (graphics->data.vnc.sharePolicy) {
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VNC_SHARE_POLICY)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("vnc display sharing policy is not "
|
|
|
|
"supported with this QEMU"));
|
|
|
|
goto error;
|
|
|
|
}
|
2013-05-21 14:31:49 +00:00
|
|
|
|
2015-11-05 11:56:47 +00:00
|
|
|
virBufferAsprintf(&opt, ",share=%s",
|
|
|
|
virDomainGraphicsVNCSharePolicyTypeToString(
|
2013-05-21 14:31:49 +00:00
|
|
|
graphics->data.vnc.sharePolicy));
|
2015-11-05 11:56:47 +00:00
|
|
|
}
|
2013-05-21 14:31:49 +00:00
|
|
|
|
2015-11-05 11:56:47 +00:00
|
|
|
if (graphics->data.vnc.auth.passwd || cfg->vncPassword)
|
|
|
|
virBufferAddLit(&opt, ",password");
|
2013-04-22 12:39:46 +00:00
|
|
|
|
2015-11-05 11:56:47 +00:00
|
|
|
if (cfg->vncTLS) {
|
|
|
|
virBufferAddLit(&opt, ",tls");
|
|
|
|
if (cfg->vncTLSx509verify)
|
|
|
|
virBufferAsprintf(&opt, ",x509verify=%s", cfg->vncTLSx509certdir);
|
|
|
|
else
|
|
|
|
virBufferAsprintf(&opt, ",x509=%s", cfg->vncTLSx509certdir);
|
|
|
|
}
|
2013-04-22 12:39:46 +00:00
|
|
|
|
2015-11-05 11:56:47 +00:00
|
|
|
if (cfg->vncSASL) {
|
|
|
|
virBufferAddLit(&opt, ",sasl");
|
2013-04-22 12:39:46 +00:00
|
|
|
|
2015-11-05 11:56:47 +00:00
|
|
|
if (cfg->vncSASLdir)
|
|
|
|
virCommandAddEnvPair(cmd, "SASL_CONF_PATH", cfg->vncSASLdir);
|
2013-04-22 12:39:46 +00:00
|
|
|
|
2015-11-05 11:56:47 +00:00
|
|
|
/* TODO: Support ACLs later */
|
2013-04-22 12:39:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-vnc");
|
|
|
|
virCommandAddArgBuffer(cmd, &opt);
|
|
|
|
if (graphics->data.vnc.keymap)
|
|
|
|
virCommandAddArgList(cmd, "-k", graphics->data.vnc.keymap, NULL);
|
|
|
|
|
|
|
|
/* Unless user requested it, set the audio backend to none, to
|
|
|
|
* prevent it opening the host OS audio devices, since that causes
|
|
|
|
* security issues and might not work when using VNC.
|
|
|
|
*/
|
|
|
|
if (cfg->vncAllowHostAudio)
|
2013-10-09 10:03:02 +00:00
|
|
|
virCommandAddEnvPassBlockSUID(cmd, "QEMU_AUDIO_DRV", NULL);
|
2013-04-22 12:39:46 +00:00
|
|
|
else
|
|
|
|
virCommandAddEnvString(cmd, "QEMU_AUDIO_DRV=none");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2013-04-22 12:39:46 +00:00
|
|
|
VIR_FREE(netAddr);
|
|
|
|
virBufferFreeAndReset(&opt);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-22 12:39:46 +00:00
|
|
|
static int
|
|
|
|
qemuBuildGraphicsSPICECommandLine(virQEMUDriverConfigPtr cfg,
|
|
|
|
virCommandPtr cmd,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
virDomainGraphicsDefPtr graphics)
|
|
|
|
{
|
|
|
|
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
|
|
|
const char *listenNetwork;
|
|
|
|
const char *listenAddr = NULL;
|
|
|
|
char *netAddr = NULL;
|
|
|
|
int ret;
|
|
|
|
int defaultMode = graphics->data.spice.defaultMode;
|
|
|
|
int port = graphics->data.spice.port;
|
|
|
|
int tlsPort = graphics->data.spice.tlsPort;
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2013-04-22 12:39:46 +00:00
|
|
|
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPICE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("spice graphics are not supported with this QEMU"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (port > 0 || tlsPort <= 0)
|
|
|
|
virBufferAsprintf(&opt, "port=%u", port);
|
|
|
|
|
|
|
|
if (tlsPort > 0) {
|
|
|
|
if (!cfg->spiceTLS) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("spice TLS port set in XML configuration,"
|
|
|
|
" but TLS is disabled in qemu.conf"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (port > 0)
|
|
|
|
virBufferAddChar(&opt, ',');
|
|
|
|
virBufferAsprintf(&opt, "tls-port=%u", tlsPort);
|
|
|
|
}
|
|
|
|
|
2012-02-24 14:13:06 +00:00
|
|
|
if (cfg->spiceSASL) {
|
|
|
|
virBufferAddLit(&opt, ",sasl");
|
|
|
|
|
|
|
|
if (cfg->spiceSASLdir)
|
|
|
|
virCommandAddEnvPair(cmd, "SASL_CONF_PATH",
|
|
|
|
cfg->spiceSASLdir);
|
|
|
|
|
|
|
|
/* TODO: Support ACLs later */
|
|
|
|
}
|
|
|
|
|
2013-04-22 12:39:46 +00:00
|
|
|
switch (virDomainGraphicsListenGetType(graphics, 0)) {
|
|
|
|
case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS:
|
|
|
|
listenAddr = virDomainGraphicsListenGetAddress(graphics, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK:
|
|
|
|
listenNetwork = virDomainGraphicsListenGetNetwork(graphics, 0);
|
|
|
|
if (!listenNetwork)
|
|
|
|
break;
|
|
|
|
ret = networkGetNetworkAddress(listenNetwork, &netAddr);
|
|
|
|
if (ret <= -2) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("network-based listen not possible, "
|
|
|
|
"network driver not present"));
|
|
|
|
goto error;
|
|
|
|
}
|
2015-02-28 09:08:34 +00:00
|
|
|
if (ret < 0)
|
2013-04-22 12:39:46 +00:00
|
|
|
goto error;
|
2015-02-28 09:08:34 +00:00
|
|
|
|
2013-04-22 12:39:46 +00:00
|
|
|
listenAddr = netAddr;
|
|
|
|
/* store the address we found in the <graphics> element so it will
|
|
|
|
* show up in status. */
|
|
|
|
if (virDomainGraphicsListenSetAddress(graphics, 0,
|
|
|
|
listenAddr, -1, false) < 0)
|
|
|
|
goto error;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!listenAddr)
|
|
|
|
listenAddr = cfg->spiceListen;
|
|
|
|
if (listenAddr)
|
|
|
|
virBufferAsprintf(&opt, ",addr=%s", listenAddr);
|
|
|
|
|
|
|
|
VIR_FREE(netAddr);
|
|
|
|
|
|
|
|
if (graphics->data.spice.mousemode) {
|
|
|
|
switch (graphics->data.spice.mousemode) {
|
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_SERVER:
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(&opt, ",agent-mouse=off");
|
2013-04-22 12:39:46 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_CLIENT:
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(&opt, ",agent-mouse=on");
|
2013-04-22 12:39:46 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* In the password case we set it via monitor command, to avoid
|
|
|
|
* making it visible on CLI, so there's no use of password=XXX
|
|
|
|
* in this bit of the code */
|
|
|
|
if (!graphics->data.spice.auth.passwd &&
|
|
|
|
!cfg->spicePassword)
|
|
|
|
virBufferAddLit(&opt, ",disable-ticketing");
|
|
|
|
|
2013-04-23 12:23:30 +00:00
|
|
|
if (tlsPort > 0)
|
|
|
|
virBufferAsprintf(&opt, ",x509-dir=%s", cfg->spiceTLSx509certdir);
|
2013-04-22 12:39:46 +00:00
|
|
|
|
|
|
|
switch (defaultMode) {
|
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_SECURE:
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(&opt, ",tls-channel=default");
|
2013-04-22 12:39:46 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_INSECURE:
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(&opt, ",plaintext-channel=default");
|
2013-04-22 12:39:46 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY:
|
|
|
|
/* nothing */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST; i++) {
|
2013-04-23 12:23:30 +00:00
|
|
|
switch (graphics->data.spice.channels[i]) {
|
2013-04-22 12:39:46 +00:00
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_SECURE:
|
2013-04-23 12:23:30 +00:00
|
|
|
if (tlsPort <= 0) {
|
2013-04-22 12:39:46 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("spice secure channels set in XML configuration, "
|
2013-04-23 12:23:30 +00:00
|
|
|
"but TLS port is not provided"));
|
2013-04-22 12:39:46 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAsprintf(&opt, ",tls-channel=%s",
|
|
|
|
virDomainGraphicsSpiceChannelNameTypeToString(i));
|
|
|
|
break;
|
2013-04-23 12:23:30 +00:00
|
|
|
|
2013-04-22 12:39:46 +00:00
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_INSECURE:
|
2013-04-23 12:23:30 +00:00
|
|
|
if (port <= 0) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("spice insecure channels set in XML "
|
|
|
|
"configuration, but plain port is not provided"));
|
|
|
|
goto error;
|
|
|
|
}
|
2013-04-22 12:39:46 +00:00
|
|
|
virBufferAsprintf(&opt, ",plaintext-channel=%s",
|
|
|
|
virDomainGraphicsSpiceChannelNameTypeToString(i));
|
|
|
|
break;
|
2013-04-23 12:23:30 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY:
|
|
|
|
switch (defaultMode) {
|
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_SECURE:
|
|
|
|
if (tlsPort <= 0) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("spice defaultMode secure requested in XML "
|
|
|
|
"configuration but TLS port not provided"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_INSECURE:
|
|
|
|
if (port <= 0) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("spice defaultMode insecure requested in XML "
|
|
|
|
"configuration but plain port not provided"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY:
|
|
|
|
/* don't care */
|
|
|
|
break;
|
|
|
|
}
|
2013-04-22 12:39:46 +00:00
|
|
|
}
|
|
|
|
}
|
2013-04-23 12:23:30 +00:00
|
|
|
|
2013-04-22 12:39:46 +00:00
|
|
|
if (graphics->data.spice.image)
|
|
|
|
virBufferAsprintf(&opt, ",image-compression=%s",
|
|
|
|
virDomainGraphicsSpiceImageCompressionTypeToString(graphics->data.spice.image));
|
|
|
|
if (graphics->data.spice.jpeg)
|
|
|
|
virBufferAsprintf(&opt, ",jpeg-wan-compression=%s",
|
|
|
|
virDomainGraphicsSpiceJpegCompressionTypeToString(graphics->data.spice.jpeg));
|
|
|
|
if (graphics->data.spice.zlib)
|
|
|
|
virBufferAsprintf(&opt, ",zlib-glz-wan-compression=%s",
|
|
|
|
virDomainGraphicsSpiceZlibCompressionTypeToString(graphics->data.spice.zlib));
|
|
|
|
if (graphics->data.spice.playback)
|
|
|
|
virBufferAsprintf(&opt, ",playback-compression=%s",
|
2014-06-27 15:18:53 +00:00
|
|
|
virTristateSwitchTypeToString(graphics->data.spice.playback));
|
2013-04-22 12:39:46 +00:00
|
|
|
if (graphics->data.spice.streaming)
|
|
|
|
virBufferAsprintf(&opt, ",streaming-video=%s",
|
|
|
|
virDomainGraphicsSpiceStreamingModeTypeToString(graphics->data.spice.streaming));
|
2014-06-27 15:16:54 +00:00
|
|
|
if (graphics->data.spice.copypaste == VIR_TRISTATE_BOOL_NO)
|
2013-04-22 12:39:46 +00:00
|
|
|
virBufferAddLit(&opt, ",disable-copy-paste");
|
2014-06-27 15:16:54 +00:00
|
|
|
if (graphics->data.spice.filetransfer == VIR_TRISTATE_BOOL_NO) {
|
2014-01-16 16:11:15 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPICE_FILE_XFER_DISABLE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("This QEMU can't disable file transfers through spice"));
|
|
|
|
goto error;
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(&opt, ",disable-agent-file-xfer");
|
|
|
|
}
|
|
|
|
}
|
2013-04-22 12:39:46 +00:00
|
|
|
|
2016-02-19 14:30:15 +00:00
|
|
|
if (graphics->data.spice.gl == VIR_TRISTATE_SWITCH_ON) {
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPICE_GL)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("This QEMU doesn't support spice OpenGL"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* spice.gl is a TristateBool, but qemu expects on/off: use
|
|
|
|
* TristateSwitch helper */
|
|
|
|
virBufferAsprintf(&opt, ",gl=%s",
|
|
|
|
virTristateSwitchTypeToString(graphics->data.spice.gl));
|
|
|
|
}
|
|
|
|
|
2013-04-22 12:39:46 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SEAMLESS_MIGRATION)) {
|
|
|
|
/* If qemu supports seamless migration turn it
|
|
|
|
* unconditionally on. If migration destination
|
|
|
|
* doesn't support it, it fallbacks to previous
|
|
|
|
* migration algorithm silently. */
|
|
|
|
virBufferAddLit(&opt, ",seamless-migration=on");
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-spice");
|
|
|
|
virCommandAddArgBuffer(cmd, &opt);
|
|
|
|
if (graphics->data.spice.keymap)
|
|
|
|
virCommandAddArgList(cmd, "-k",
|
|
|
|
graphics->data.spice.keymap, NULL);
|
|
|
|
/* SPICE includes native support for tunnelling audio, so we
|
|
|
|
* set the audio backend to point at SPICE's own driver
|
|
|
|
*/
|
|
|
|
virCommandAddEnvString(cmd, "QEMU_AUDIO_DRV=spice");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2013-04-22 12:39:46 +00:00
|
|
|
VIR_FREE(netAddr);
|
|
|
|
virBufferFreeAndReset(&opt);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
static int
|
2013-01-10 21:03:14 +00:00
|
|
|
qemuBuildGraphicsCommandLine(virQEMUDriverConfigPtr cfg,
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandPtr cmd,
|
|
|
|
virDomainDefPtr def,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps,
|
2016-02-26 08:15:55 +00:00
|
|
|
virDomainGraphicsDefPtr graphics,
|
|
|
|
const char *domainLibDir)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
2014-06-01 00:22:30 +00:00
|
|
|
switch ((virDomainGraphicsType) graphics->type) {
|
2013-04-22 13:13:46 +00:00
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
|
2015-11-09 16:20:08 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SDL)) {
|
2012-11-10 01:40:23 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2013-04-22 13:13:46 +00:00
|
|
|
_("sdl not supported by '%s'"), def->emulator);
|
|
|
|
return -1;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (graphics->data.sdl.xauth)
|
2013-04-22 13:13:46 +00:00
|
|
|
virCommandAddEnvPair(cmd, "XAUTHORITY", graphics->data.sdl.xauth);
|
2012-11-10 01:40:23 +00:00
|
|
|
if (graphics->data.sdl.display)
|
2013-04-22 13:13:46 +00:00
|
|
|
virCommandAddEnvPair(cmd, "DISPLAY", graphics->data.sdl.display);
|
2012-11-10 01:40:23 +00:00
|
|
|
if (graphics->data.sdl.fullscreen)
|
|
|
|
virCommandAddArg(cmd, "-full-screen");
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/* If using SDL for video, then we should just let it
|
|
|
|
* use QEMU's host audio drivers, possibly SDL too
|
|
|
|
* User can set these two before starting libvirtd
|
|
|
|
*/
|
2013-10-09 10:03:02 +00:00
|
|
|
virCommandAddEnvPassBlockSUID(cmd, "QEMU_AUDIO_DRV", NULL);
|
|
|
|
virCommandAddEnvPassBlockSUID(cmd, "SDL_AUDIODRIVER", NULL);
|
2011-11-11 12:53:04 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/* New QEMU has this flag to let us explicitly ask for
|
|
|
|
* SDL graphics. This is better than relying on the
|
|
|
|
* default, since the default changes :-( */
|
2015-11-09 16:20:08 +00:00
|
|
|
virCommandAddArg(cmd, "-sdl");
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2013-04-22 13:13:46 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
|
2016-02-26 08:15:55 +00:00
|
|
|
return qemuBuildGraphicsVNCCommandLine(cfg, cmd, qemuCaps,
|
|
|
|
graphics, domainLibDir);
|
2013-04-22 13:13:46 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
|
|
|
|
return qemuBuildGraphicsSPICECommandLine(cfg, cmd, qemuCaps, graphics);
|
|
|
|
|
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
|
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
|
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_LAST:
|
2012-11-10 01:40:23 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported graphics type '%s'"),
|
|
|
|
virDomainGraphicsTypeToString(graphics->type));
|
2013-04-22 13:13:46 +00:00
|
|
|
return -1;
|
2012-11-10 01:40:23 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2014-07-11 17:47:31 +00:00
|
|
|
static int
|
|
|
|
qemuBuildVhostuserCommandLine(virCommandPtr cmd,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
virDomainNetDefPtr net,
|
2015-03-13 09:17:46 +00:00
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
int bootindex)
|
2014-07-11 17:47:31 +00:00
|
|
|
{
|
|
|
|
virBuffer chardev_buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
virBuffer netdev_buf = VIR_BUFFER_INITIALIZER;
|
2015-02-26 11:45:57 +00:00
|
|
|
unsigned int queues = net->driver.virtio.queues;
|
2014-07-11 17:47:31 +00:00
|
|
|
char *nic = NULL;
|
|
|
|
|
|
|
|
if (!qemuDomainSupportsNetdev(def, qemuCaps, net)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("Netdev support unavailable"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ((virDomainChrType) net->data.vhostuser->type) {
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
|
|
|
virBufferAsprintf(&chardev_buf, "socket,id=char%s,path=%s%s",
|
|
|
|
net->info.alias, net->data.vhostuser->data.nix.path,
|
|
|
|
net->data.vhostuser->data.nix.listen ? ",server" : "");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_NULL:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_VC:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_PTY:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_DEV:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_FILE:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_PIPE:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_STDIO:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UDP:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_TCP:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_NMDM:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_LAST:
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("vhost-user type '%s' not supported"),
|
|
|
|
virDomainChrTypeToString(net->data.vhostuser->type));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(&netdev_buf, "type=vhost-user,id=host%s,chardev=char%s",
|
|
|
|
net->info.alias, net->info.alias);
|
|
|
|
|
2015-02-26 11:45:57 +00:00
|
|
|
if (queues > 1) {
|
2015-06-15 08:38:21 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VHOSTUSER_MULTIQUEUE)) {
|
2015-02-26 11:45:57 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("multi-queue is not supported for vhost-user "
|
|
|
|
"with this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAsprintf(&netdev_buf, ",queues=%u", queues);
|
|
|
|
}
|
|
|
|
|
2014-07-11 17:47:31 +00:00
|
|
|
virCommandAddArg(cmd, "-chardev");
|
|
|
|
virCommandAddArgBuffer(cmd, &chardev_buf);
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-netdev");
|
|
|
|
virCommandAddArgBuffer(cmd, &netdev_buf);
|
|
|
|
|
2015-02-26 11:45:57 +00:00
|
|
|
if (!(nic = qemuBuildNicDevStr(def, net, -1, bootindex,
|
|
|
|
queues, qemuCaps))) {
|
2014-07-11 17:47:31 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("Error generating NIC -device string"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArgList(cmd, "-device", nic, NULL);
|
|
|
|
VIR_FREE(nic);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&chardev_buf);
|
|
|
|
virBufferFreeAndReset(&netdev_buf);
|
|
|
|
VIR_FREE(nic);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-05-13 15:31:06 +00:00
|
|
|
static int
|
|
|
|
qemuBuildInterfaceCommandLine(virCommandPtr cmd,
|
|
|
|
virQEMUDriverPtr driver,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
virDomainNetDefPtr net,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
int vlan,
|
|
|
|
int bootindex,
|
2014-04-27 00:15:22 +00:00
|
|
|
virNetDevVPortProfileOp vmop,
|
2015-01-16 11:25:50 +00:00
|
|
|
bool standalone,
|
2015-02-20 19:52:37 +00:00
|
|
|
size_t *nnicindexes,
|
|
|
|
int **nicindexes)
|
2013-05-13 15:31:06 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
char *nic = NULL, *host = NULL;
|
2013-05-21 13:50:09 +00:00
|
|
|
int *tapfd = NULL;
|
2014-11-12 15:42:02 +00:00
|
|
|
size_t tapfdSize = 0;
|
2013-05-21 13:50:09 +00:00
|
|
|
int *vhostfd = NULL;
|
2014-11-12 15:42:02 +00:00
|
|
|
size_t vhostfdSize = 0;
|
2013-05-21 13:50:09 +00:00
|
|
|
char **tapfdName = NULL;
|
|
|
|
char **vhostfdName = NULL;
|
2013-05-13 15:31:06 +00:00
|
|
|
int actualType = virDomainNetGetActualType(net);
|
2015-04-03 18:58:20 +00:00
|
|
|
virQEMUDriverConfigPtr cfg = NULL;
|
2015-01-07 14:52:21 +00:00
|
|
|
virNetDevBandwidthPtr actualBandwidth;
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2013-05-13 15:31:06 +00:00
|
|
|
|
2015-03-13 09:17:46 +00:00
|
|
|
|
|
|
|
if (!bootindex)
|
|
|
|
bootindex = net->info.bootIndex;
|
|
|
|
|
2014-07-11 17:47:31 +00:00
|
|
|
if (actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER)
|
2015-03-13 09:17:46 +00:00
|
|
|
return qemuBuildVhostuserCommandLine(cmd, def, net, qemuCaps, bootindex);
|
2014-07-11 17:47:31 +00:00
|
|
|
|
2013-05-13 15:31:06 +00:00
|
|
|
if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
|
|
|
|
/* NET_TYPE_HOSTDEV devices are really hostdev devices, so
|
|
|
|
* their commandlines are constructed with other hostdevs.
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-18 08:47:01 +00:00
|
|
|
/* Currently nothing besides TAP devices supports multiqueue. */
|
|
|
|
if (net->driver.virtio.queues > 0 &&
|
|
|
|
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
2015-12-04 10:47:22 +00:00
|
|
|
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
|
|
|
|
actualType == VIR_DOMAIN_NET_TYPE_DIRECT)) {
|
2013-04-18 08:47:01 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Multiqueue network is not supported for: %s"),
|
|
|
|
virDomainNetTypeToString(actualType));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-08-10 06:05:29 +00:00
|
|
|
/* and only TAP devices support nwfilter rules */
|
|
|
|
if (net->filter &&
|
|
|
|
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
|
|
|
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("filterref is not supported for "
|
|
|
|
"network interfaces of type %s"),
|
|
|
|
virDomainNetTypeToString(actualType));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-02-05 12:40:11 +00:00
|
|
|
if (net->backend.tap &&
|
|
|
|
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
|
|
|
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Custom tap device path is not supported for: %s"),
|
|
|
|
virDomainNetTypeToString(actualType));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-04-03 18:58:20 +00:00
|
|
|
cfg = virQEMUDriverGetConfig(driver);
|
|
|
|
|
2013-05-13 15:31:06 +00:00
|
|
|
if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
|
|
|
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
|
2013-04-18 08:47:01 +00:00
|
|
|
tapfdSize = net->driver.virtio.queues;
|
|
|
|
if (!tapfdSize)
|
|
|
|
tapfdSize = 1;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(tapfd, tapfdSize) < 0 ||
|
2013-07-04 10:14:12 +00:00
|
|
|
VIR_ALLOC_N(tapfdName, tapfdSize) < 0)
|
2013-05-21 13:50:09 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-09-02 14:06:14 +00:00
|
|
|
memset(tapfd, -1, tapfdSize * sizeof(tapfd[0]));
|
|
|
|
|
2016-02-15 15:52:50 +00:00
|
|
|
if (qemuInterfaceBridgeConnect(def, driver, net,
|
|
|
|
tapfd, &tapfdSize) < 0)
|
2013-05-13 15:31:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
} else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
|
2015-12-04 10:47:22 +00:00
|
|
|
tapfdSize = net->driver.virtio.queues;
|
|
|
|
if (!tapfdSize)
|
|
|
|
tapfdSize = 1;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(tapfd, tapfdSize) < 0 ||
|
|
|
|
VIR_ALLOC_N(tapfdName, tapfdSize) < 0)
|
2013-05-21 13:50:09 +00:00
|
|
|
goto cleanup;
|
2015-12-04 10:47:22 +00:00
|
|
|
|
|
|
|
memset(tapfd, -1, tapfdSize * sizeof(tapfd[0]));
|
|
|
|
|
2016-02-15 15:26:40 +00:00
|
|
|
if (qemuInterfaceDirectConnect(def, driver, net,
|
|
|
|
tapfd, tapfdSize, vmop) < 0)
|
2013-05-13 15:31:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-02-20 19:52:37 +00:00
|
|
|
/* For types whose implementations use a netdev on the host, add
|
|
|
|
* an entry to nicindexes for passing on to systemd.
|
|
|
|
*/
|
|
|
|
switch ((virDomainNetType)actualType) {
|
|
|
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
|
|
|
{
|
|
|
|
int nicindex;
|
|
|
|
|
|
|
|
/* network and bridge use a tap device, and direct uses a
|
|
|
|
* macvtap device
|
|
|
|
*/
|
2015-06-15 18:59:58 +00:00
|
|
|
if (virQEMUDriverIsPrivileged(driver) && nicindexes && nnicindexes &&
|
|
|
|
net->ifname) {
|
2015-02-20 19:52:37 +00:00
|
|
|
if (virNetDevGetIndex(net->ifname, &nicindex) < 0 ||
|
|
|
|
VIR_APPEND_ELEMENT(*nicindexes, *nnicindexes, nicindex) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_USER:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_SERVER:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_MCAST:
|
2015-08-29 20:19:10 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_UDP:
|
2015-02-20 19:52:37 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_INTERNAL:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_HOSTDEV:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_LAST:
|
|
|
|
/* These types don't use a network device on the host, but
|
|
|
|
* instead use some other type of connection to the emulated
|
|
|
|
* device in the qemu process.
|
|
|
|
*
|
|
|
|
* (Note that hostdev can't be considered as "using a network
|
|
|
|
* device", because by the time it is being used, it has been
|
|
|
|
* detached from the hostside network driver so it doesn't show
|
|
|
|
* up in the list of interfaces on the host - it's just some
|
|
|
|
* PCI device.)
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-01-07 14:52:21 +00:00
|
|
|
/* Set bandwidth or warn if requested and not supported. */
|
|
|
|
actualBandwidth = virDomainNetGetActualBandwidth(net);
|
|
|
|
if (actualBandwidth) {
|
|
|
|
if (virNetDevSupportBandwidth(actualType)) {
|
|
|
|
if (virNetDevBandwidthSet(net->ifname, actualBandwidth, false) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
VIR_WARN("setting bandwidth on interfaces of "
|
|
|
|
"type '%s' is not implemented yet",
|
|
|
|
virDomainNetTypeToString(actualType));
|
|
|
|
}
|
|
|
|
}
|
2014-11-18 23:55:48 +00:00
|
|
|
|
2014-03-13 19:10:09 +00:00
|
|
|
if ((actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
|
|
|
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
|
|
|
|
actualType == VIR_DOMAIN_NET_TYPE_ETHERNET ||
|
|
|
|
actualType == VIR_DOMAIN_NET_TYPE_DIRECT) &&
|
|
|
|
!standalone) {
|
2013-05-13 15:31:06 +00:00
|
|
|
/* Attempt to use vhost-net mode for these types of
|
|
|
|
network device */
|
2013-04-18 08:47:01 +00:00
|
|
|
vhostfdSize = net->driver.virtio.queues;
|
|
|
|
if (!vhostfdSize)
|
|
|
|
vhostfdSize = 1;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0 ||
|
2013-07-04 10:14:12 +00:00
|
|
|
VIR_ALLOC_N(vhostfdName, vhostfdSize))
|
2013-05-21 13:50:09 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-09-02 14:06:14 +00:00
|
|
|
memset(vhostfd, -1, vhostfdSize * sizeof(vhostfd[0]));
|
|
|
|
|
2016-02-15 16:51:48 +00:00
|
|
|
if (qemuInterfaceOpenVhostNet(def, net, qemuCaps,
|
|
|
|
vhostfd, &vhostfdSize) < 0)
|
2013-05-13 15:31:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-05-21 13:50:09 +00:00
|
|
|
for (i = 0; i < tapfdSize; i++) {
|
2014-08-13 14:08:03 +00:00
|
|
|
if (virSecurityManagerSetTapFDLabel(driver->securityManager,
|
|
|
|
def, tapfd[i]) < 0)
|
|
|
|
goto cleanup;
|
2013-07-11 10:31:56 +00:00
|
|
|
virCommandPassFD(cmd, tapfd[i],
|
|
|
|
VIR_COMMAND_PASS_FD_CLOSE_PARENT);
|
2013-07-04 10:14:12 +00:00
|
|
|
if (virAsprintf(&tapfdName[i], "%d", tapfd[i]) < 0)
|
2013-05-13 15:31:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-05-21 13:50:09 +00:00
|
|
|
for (i = 0; i < vhostfdSize; i++) {
|
2013-07-11 10:31:56 +00:00
|
|
|
virCommandPassFD(cmd, vhostfd[i],
|
|
|
|
VIR_COMMAND_PASS_FD_CLOSE_PARENT);
|
2013-07-04 10:14:12 +00:00
|
|
|
if (virAsprintf(&vhostfdName[i], "%d", vhostfd[i]) < 0)
|
2013-05-24 12:45:06 +00:00
|
|
|
goto cleanup;
|
2013-05-13 15:31:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Possible combinations:
|
|
|
|
*
|
|
|
|
* 1. Old way: -net nic,model=e1000,vlan=1 -net tap,vlan=1
|
|
|
|
* 2. Semi-new: -device e1000,vlan=1 -net tap,vlan=1
|
|
|
|
* 3. Best way: -netdev type=tap,id=netdev1 -device e1000,id=netdev1
|
|
|
|
*
|
|
|
|
* NB, no support for -netdev without use of -device
|
|
|
|
*/
|
2013-08-01 01:40:35 +00:00
|
|
|
if (qemuDomainSupportsNetdev(def, qemuCaps, net)) {
|
2013-05-13 15:31:06 +00:00
|
|
|
if (!(host = qemuBuildHostNetStr(net, driver,
|
2013-05-21 13:50:09 +00:00
|
|
|
',', vlan,
|
|
|
|
tapfdName, tapfdSize,
|
|
|
|
vhostfdName, vhostfdSize)))
|
2013-05-13 15:31:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
virCommandAddArgList(cmd, "-netdev", host, NULL);
|
|
|
|
}
|
2013-08-01 01:40:35 +00:00
|
|
|
if (qemuDomainSupportsNicdev(def, qemuCaps, net)) {
|
2013-08-22 08:19:08 +00:00
|
|
|
if (!(nic = qemuBuildNicDevStr(def, net, vlan, bootindex,
|
2013-08-23 07:48:24 +00:00
|
|
|
vhostfdSize, qemuCaps)))
|
2013-05-13 15:31:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
virCommandAddArgList(cmd, "-device", nic, NULL);
|
|
|
|
} else {
|
|
|
|
if (!(nic = qemuBuildNicStr(net, "nic,", vlan)))
|
|
|
|
goto cleanup;
|
|
|
|
virCommandAddArgList(cmd, "-net", nic, NULL);
|
|
|
|
}
|
2013-08-01 01:40:35 +00:00
|
|
|
if (!qemuDomainSupportsNetdev(def, qemuCaps, net)) {
|
2013-05-13 15:31:06 +00:00
|
|
|
if (!(host = qemuBuildHostNetStr(net, driver,
|
2013-05-21 13:50:09 +00:00
|
|
|
',', vlan,
|
|
|
|
tapfdName, tapfdSize,
|
|
|
|
vhostfdName, vhostfdSize)))
|
2013-05-13 15:31:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
virCommandAddArgList(cmd, "-net", host, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
2014-03-25 06:49:44 +00:00
|
|
|
cleanup:
|
2014-03-31 11:25:17 +00:00
|
|
|
if (ret < 0) {
|
|
|
|
virErrorPtr saved_err = virSaveLastError();
|
2013-05-13 15:31:06 +00:00
|
|
|
virDomainConfNWFilterTeardown(net);
|
2014-03-31 11:25:17 +00:00
|
|
|
virSetError(saved_err);
|
|
|
|
virFreeError(saved_err);
|
|
|
|
}
|
2013-09-02 14:06:14 +00:00
|
|
|
for (i = 0; tapfd && i < tapfdSize && tapfd[i] >= 0; i++) {
|
2013-05-21 13:50:09 +00:00
|
|
|
if (ret < 0)
|
|
|
|
VIR_FORCE_CLOSE(tapfd[i]);
|
2013-04-18 08:47:01 +00:00
|
|
|
if (tapfdName)
|
|
|
|
VIR_FREE(tapfdName[i]);
|
2013-05-21 13:50:09 +00:00
|
|
|
}
|
2013-09-02 14:06:14 +00:00
|
|
|
for (i = 0; vhostfd && i < vhostfdSize && vhostfd[i] >= 0; i++) {
|
2013-05-21 13:50:09 +00:00
|
|
|
if (ret < 0)
|
|
|
|
VIR_FORCE_CLOSE(vhostfd[i]);
|
2013-04-18 08:47:01 +00:00
|
|
|
if (vhostfdName)
|
|
|
|
VIR_FREE(vhostfdName[i]);
|
2013-05-21 13:50:09 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(tapfd);
|
|
|
|
VIR_FREE(vhostfd);
|
2013-05-13 15:31:06 +00:00
|
|
|
VIR_FREE(nic);
|
|
|
|
VIR_FREE(host);
|
|
|
|
VIR_FREE(tapfdName);
|
|
|
|
VIR_FREE(vhostfdName);
|
2015-04-03 18:58:20 +00:00
|
|
|
virObjectUnref(cfg);
|
2013-05-13 15:31:06 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-02-18 15:32:07 +00:00
|
|
|
|
|
|
|
/* NOTE: Not using const virDomainDef here since eventually a call is made
|
|
|
|
* into virSecurityManagerSetTapFDLabel which calls it's driver
|
|
|
|
* API domainSetSecurityTapFDLabel that doesn't use the const format.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
qemuBuildNetCommandLine(virCommandPtr cmd,
|
|
|
|
virQEMUDriverPtr driver,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
virNetDevVPortProfileOp vmop,
|
|
|
|
bool standalone,
|
|
|
|
bool emitBootindex,
|
|
|
|
size_t *nnicindexes,
|
|
|
|
int **nicindexes,
|
|
|
|
int *bootHostdevNet)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
int last_good_net = -1;
|
|
|
|
|
|
|
|
if (!def->nnets) {
|
|
|
|
/* If we have -device, then we set -nodefault already */
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))
|
|
|
|
virCommandAddArgList(cmd, "-net", "none", NULL);
|
|
|
|
} else {
|
|
|
|
int bootNet = 0;
|
|
|
|
|
|
|
|
if (emitBootindex) {
|
|
|
|
/* convert <boot dev='network'/> to bootindex since we didn't emit
|
|
|
|
* -boot n
|
|
|
|
*/
|
|
|
|
for (i = 0; i < def->os.nBootDevs; i++) {
|
|
|
|
if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_NET) {
|
|
|
|
bootNet = i + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < def->nnets; i++) {
|
|
|
|
virDomainNetDefPtr net = def->nets[i];
|
|
|
|
int vlan;
|
|
|
|
|
|
|
|
/* VLANs are not used with -netdev, so don't record them */
|
|
|
|
if (qemuDomainSupportsNetdev(def, qemuCaps, net))
|
|
|
|
vlan = -1;
|
|
|
|
else
|
|
|
|
vlan = i;
|
|
|
|
|
|
|
|
if (qemuBuildInterfaceCommandLine(cmd, driver, def, net,
|
|
|
|
qemuCaps, vlan, bootNet, vmop,
|
|
|
|
standalone, nnicindexes,
|
|
|
|
nicindexes) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
last_good_net = i;
|
|
|
|
/* if this interface is a type='hostdev' interface and we
|
|
|
|
* haven't yet added a "bootindex" parameter to an
|
|
|
|
* emulated network device, save the bootindex - hostdev
|
|
|
|
* interface commandlines will be built later on when we
|
|
|
|
* cycle through all the hostdevs, and we'll use it then.
|
|
|
|
*/
|
|
|
|
if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_HOSTDEV &&
|
|
|
|
*bootHostdevNet == 0) {
|
|
|
|
*bootHostdevNet = bootNet;
|
|
|
|
}
|
|
|
|
bootNet = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
for (i = 0; last_good_net != -1 && i <= last_good_net; i++)
|
|
|
|
virDomainConfNWFilterTeardown(def->nets[i]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-06-17 03:56:14 +00:00
|
|
|
char *
|
|
|
|
qemuBuildShmemDevStr(virDomainDefPtr def,
|
2014-09-25 07:00:47 +00:00
|
|
|
virDomainShmemDefPtr shmem,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("ivshmem device is not supported "
|
|
|
|
"with this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "ivshmem");
|
|
|
|
if (shmem->size) {
|
|
|
|
/*
|
|
|
|
* Thanks to our parsing code, we have a guarantee that the
|
|
|
|
* size is power of two and is at least a mebibyte in size.
|
2014-10-04 08:46:22 +00:00
|
|
|
* But because it may change in the future, the checks are
|
2014-09-25 07:00:47 +00:00
|
|
|
* doubled in here.
|
|
|
|
*/
|
|
|
|
if (shmem->size & (shmem->size - 1)) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("shmem size must be a power of two"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (shmem->size < 1024 * 1024) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
2014-11-20 18:51:12 +00:00
|
|
|
_("shmem size must be at least 1 MiB (1024 KiB)"));
|
2014-09-25 07:00:47 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2014-10-04 08:46:22 +00:00
|
|
|
virBufferAsprintf(&buf, ",size=%llum", shmem->size >> 20);
|
2014-09-25 07:00:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!shmem->server.enabled) {
|
2015-06-17 03:56:13 +00:00
|
|
|
virBufferAsprintf(&buf, ",shm=%s,id=%s", shmem->name, shmem->info.alias);
|
2014-09-25 07:00:47 +00:00
|
|
|
} else {
|
2015-06-17 03:56:13 +00:00
|
|
|
virBufferAsprintf(&buf, ",chardev=char%s,id=%s", shmem->info.alias, shmem->info.alias);
|
2014-09-25 07:00:47 +00:00
|
|
|
if (shmem->msi.enabled) {
|
|
|
|
virBufferAddLit(&buf, ",msi=on");
|
|
|
|
if (shmem->msi.vectors)
|
|
|
|
virBufferAsprintf(&buf, ",vectors=%u", shmem->msi.vectors);
|
|
|
|
if (shmem->msi.ioeventfd)
|
|
|
|
virBufferAsprintf(&buf, ",ioeventfd=%s",
|
|
|
|
virTristateSwitchTypeToString(shmem->msi.ioeventfd));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-17 03:56:21 +00:00
|
|
|
if (shmem->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("only 'pci' addresses are supported for the "
|
|
|
|
"shared memory device"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2014-09-25 07:00:47 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, def, &shmem->info, qemuCaps) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virBufferCheckError(&buf) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2015-06-17 03:56:14 +00:00
|
|
|
return virBufferContentAndReset(&buf);
|
2014-09-25 07:00:47 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
2015-06-17 03:56:14 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
2016-02-23 13:05:09 +00:00
|
|
|
qemuBuildShmemBackendStr(virLogManagerPtr logManager,
|
|
|
|
virCommandPtr cmd,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
virDomainShmemDefPtr shmem,
|
2015-06-17 03:56:14 +00:00
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
char *devstr = NULL;
|
|
|
|
|
2015-06-17 03:56:15 +00:00
|
|
|
if (!shmem->server.chr.data.nix.path &&
|
|
|
|
virAsprintf(&shmem->server.chr.data.nix.path,
|
2015-06-17 03:56:14 +00:00
|
|
|
"/var/lib/libvirt/shmem-%s-sock",
|
|
|
|
shmem->name) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2016-02-23 13:05:09 +00:00
|
|
|
devstr = qemuBuildChrChardevStr(logManager, cmd, def,
|
|
|
|
&shmem->server.chr,
|
|
|
|
shmem->info.alias, qemuCaps);
|
2015-06-17 03:56:14 +00:00
|
|
|
|
|
|
|
return devstr;
|
2014-09-25 07:00:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2016-02-23 13:05:09 +00:00
|
|
|
qemuBuildShmemCommandLine(virLogManagerPtr logManager,
|
|
|
|
virCommandPtr cmd,
|
2014-09-25 07:00:47 +00:00
|
|
|
virDomainDefPtr def,
|
|
|
|
virDomainShmemDefPtr shmem,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
2015-06-17 03:56:14 +00:00
|
|
|
char *devstr = NULL;
|
|
|
|
|
|
|
|
if (!(devstr = qemuBuildShmemDevStr(def, shmem, qemuCaps)))
|
2014-09-25 07:00:47 +00:00
|
|
|
return -1;
|
2015-06-17 03:56:14 +00:00
|
|
|
virCommandAddArgList(cmd, "-device", devstr, NULL);
|
|
|
|
VIR_FREE(devstr);
|
2014-09-25 07:00:47 +00:00
|
|
|
|
|
|
|
if (shmem->server.enabled) {
|
2016-02-23 13:05:09 +00:00
|
|
|
if (!(devstr = qemuBuildShmemBackendStr(logManager, cmd, def,
|
|
|
|
shmem, qemuCaps)))
|
2014-09-25 07:00:47 +00:00
|
|
|
return -1;
|
|
|
|
|
2015-06-17 03:56:14 +00:00
|
|
|
virCommandAddArgList(cmd, "-chardev", devstr, NULL);
|
2014-09-25 07:00:47 +00:00
|
|
|
VIR_FREE(devstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-13 15:20:34 +00:00
|
|
|
static int
|
|
|
|
qemuBuildChrDeviceCommandLine(virCommandPtr cmd,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
virDomainChrDefPtr chr,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
char *devstr = NULL;
|
|
|
|
|
|
|
|
if (qemuBuildChrDeviceStr(&devstr, def, chr, qemuCaps) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
virCommandAddArgList(cmd, "-device", devstr, NULL);
|
2013-07-12 17:18:29 +00:00
|
|
|
VIR_FREE(devstr);
|
2013-03-13 15:20:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-08-07 11:50:00 +00:00
|
|
|
static int
|
|
|
|
qemuBuildDomainLoaderCommandLine(virCommandPtr cmd,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
virDomainLoaderDefPtr loader = def->os.loader;
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
int unit = 0;
|
|
|
|
|
|
|
|
if (!loader)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch ((virDomainLoader) loader->type) {
|
|
|
|
case VIR_DOMAIN_LOADER_TYPE_ROM:
|
|
|
|
virCommandAddArg(cmd, "-bios");
|
|
|
|
virCommandAddArg(cmd, loader->path);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_LOADER_TYPE_PFLASH:
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NO_ACPI) &&
|
|
|
|
def->features[VIR_DOMAIN_FEATURE_ACPI] != VIR_TRISTATE_SWITCH_ON) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("ACPI must be enabled in order to use UEFI"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf,
|
|
|
|
"file=%s,if=pflash,format=raw,unit=%d",
|
|
|
|
loader->path, unit);
|
|
|
|
unit++;
|
|
|
|
|
|
|
|
if (loader->readonly) {
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_READONLY)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("this qemu doesn't support passing "
|
|
|
|
"readonly attribute"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, ",readonly=%s",
|
|
|
|
virTristateSwitchTypeToString(loader->readonly));
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-drive");
|
|
|
|
virCommandAddArgBuffer(cmd, &buf);
|
|
|
|
|
|
|
|
if (loader->nvram) {
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
virBufferAsprintf(&buf,
|
|
|
|
"file=%s,if=pflash,format=raw,unit=%d",
|
|
|
|
loader->nvram, unit);
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-drive");
|
|
|
|
virCommandAddArgBuffer(cmd, &buf);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_LOADER_TYPE_LAST:
|
|
|
|
/* nada */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-02-15 14:26:41 +00:00
|
|
|
|
2016-02-15 14:32:23 +00:00
|
|
|
static char *
|
|
|
|
qemuBuildTPMDevStr(const virDomainDef *def,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
const char *emulator)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
const virDomainTPMDef *tpm = def->tpm;
|
|
|
|
const char *model = virDomainTPMModelTypeToString(tpm->model);
|
|
|
|
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_TPM_TIS)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("The QEMU executable %s does not support TPM "
|
|
|
|
"model %s"),
|
|
|
|
emulator, model);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, "%s,tpmdev=tpm-%s,id=%s",
|
|
|
|
model, tpm->info.alias, tpm->info.alias);
|
|
|
|
|
|
|
|
if (virBufferCheckError(&buf) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-15 14:26:41 +00:00
|
|
|
static char *
|
|
|
|
qemuBuildTPMBackendStr(const virDomainDef *def,
|
|
|
|
virCommandPtr cmd,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
const char *emulator,
|
|
|
|
int *tpmfd,
|
|
|
|
int *cancelfd)
|
|
|
|
{
|
|
|
|
const virDomainTPMDef *tpm = def->tpm;
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
const char *type = virDomainTPMBackendTypeToString(tpm->type);
|
|
|
|
char *cancel_path = NULL, *devset = NULL;
|
|
|
|
const char *tpmdev;
|
|
|
|
|
|
|
|
*tpmfd = -1;
|
|
|
|
*cancelfd = -1;
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, "%s,id=tpm-%s", type, tpm->info.alias);
|
|
|
|
|
|
|
|
switch (tpm->type) {
|
|
|
|
case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_TPM_PASSTHROUGH))
|
|
|
|
goto no_support;
|
|
|
|
|
|
|
|
tpmdev = tpm->data.passthrough.source.data.file.path;
|
|
|
|
if (!(cancel_path = virTPMCreateCancelPath(tpmdev)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_ADD_FD)) {
|
|
|
|
*tpmfd = open(tpmdev, O_RDWR);
|
|
|
|
if (*tpmfd < 0) {
|
|
|
|
virReportSystemError(errno, _("Could not open TPM device %s"),
|
|
|
|
tpmdev);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandPassFD(cmd, *tpmfd,
|
|
|
|
VIR_COMMAND_PASS_FD_CLOSE_PARENT);
|
|
|
|
devset = qemuVirCommandGetDevSet(cmd, *tpmfd);
|
|
|
|
if (devset == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
*cancelfd = open(cancel_path, O_WRONLY);
|
|
|
|
if (*cancelfd < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Could not open TPM device's cancel "
|
|
|
|
"path %s"), cancel_path);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(cancel_path);
|
|
|
|
|
|
|
|
virCommandPassFD(cmd, *cancelfd,
|
|
|
|
VIR_COMMAND_PASS_FD_CLOSE_PARENT);
|
|
|
|
cancel_path = qemuVirCommandGetDevSet(cmd, *cancelfd);
|
|
|
|
if (cancel_path == NULL)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAddLit(&buf, ",path=");
|
|
|
|
virBufferEscape(&buf, ',', ",", "%s", devset ? devset : tpmdev);
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, ",cancel-path=");
|
|
|
|
virBufferEscape(&buf, ',', ",", "%s", cancel_path);
|
|
|
|
|
|
|
|
VIR_FREE(devset);
|
|
|
|
VIR_FREE(cancel_path);
|
|
|
|
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_TPM_TYPE_LAST:
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferCheckError(&buf) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
no_support:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("The QEMU executable %s does not support TPM "
|
|
|
|
"backend type %s"),
|
|
|
|
emulator, type);
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(devset);
|
|
|
|
VIR_FREE(cancel_path);
|
|
|
|
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-05 23:57:06 +00:00
|
|
|
static int
|
|
|
|
qemuBuildTPMCommandLine(virDomainDefPtr def,
|
|
|
|
virCommandPtr cmd,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
const char *emulator)
|
|
|
|
{
|
|
|
|
char *optstr;
|
2015-03-05 23:57:06 +00:00
|
|
|
int tpmfd = -1;
|
|
|
|
int cancelfd = -1;
|
|
|
|
char *fdset;
|
2015-03-05 23:57:06 +00:00
|
|
|
|
2015-03-05 23:57:06 +00:00
|
|
|
if (!(optstr = qemuBuildTPMBackendStr(def, cmd, qemuCaps, emulator,
|
|
|
|
&tpmfd, &cancelfd)))
|
2015-03-05 23:57:06 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
virCommandAddArgList(cmd, "-tpmdev", optstr, NULL);
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
|
2015-03-05 23:57:06 +00:00
|
|
|
if (tpmfd >= 0) {
|
|
|
|
fdset = qemuVirCommandGetFDSet(cmd, tpmfd);
|
|
|
|
if (!fdset)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
virCommandAddArgList(cmd, "-add-fd", fdset, NULL);
|
|
|
|
VIR_FREE(fdset);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cancelfd >= 0) {
|
|
|
|
fdset = qemuVirCommandGetFDSet(cmd, cancelfd);
|
|
|
|
if (!fdset)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
virCommandAddArgList(cmd, "-add-fd", fdset, NULL);
|
|
|
|
VIR_FREE(fdset);
|
|
|
|
}
|
|
|
|
|
2015-03-05 23:57:06 +00:00
|
|
|
if (!(optstr = qemuBuildTPMDevStr(def, qemuCaps, emulator)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
virCommandAddArgList(cmd, "-device", optstr, NULL);
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-15 21:55:08 +00:00
|
|
|
/**
|
|
|
|
* qemuBuildCommandLineValidate:
|
|
|
|
*
|
|
|
|
* Prior to taking the plunge and building a long command line only
|
|
|
|
* to find some configuration option isn't valid, let's do a couple
|
|
|
|
* of checks and fail early.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, returns -1 and messages what the issue is.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
qemuBuildCommandLineValidate(virQEMUDriverPtr driver,
|
|
|
|
const virDomainDef *def)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
int sdl = 0;
|
|
|
|
int vnc = 0;
|
|
|
|
int spice = 0;
|
|
|
|
|
|
|
|
if (!virQEMUDriverIsPrivileged(driver)) {
|
|
|
|
/* If we have no cgroups then we can have no tunings that
|
|
|
|
* require them */
|
|
|
|
|
|
|
|
if (virMemoryLimitIsSet(def->mem.hard_limit) ||
|
|
|
|
virMemoryLimitIsSet(def->mem.soft_limit) ||
|
|
|
|
def->mem.min_guarantee ||
|
|
|
|
virMemoryLimitIsSet(def->mem.swap_hard_limit)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Memory tuning is not available in session mode"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->blkio.weight) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Block I/O tuning is not available in session mode"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->cputune.sharesSpecified || def->cputune.period ||
|
2016-02-16 13:43:35 +00:00
|
|
|
def->cputune.quota || def->cputune.global_period ||
|
|
|
|
def->cputune.global_quota || def->cputune.emulator_period ||
|
2016-02-15 21:55:08 +00:00
|
|
|
def->cputune.emulator_quota) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("CPU tuning is not available in session mode"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < def->ngraphics; ++i) {
|
|
|
|
switch (def->graphics[i]->type) {
|
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
|
|
|
|
++sdl;
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
|
|
|
|
++vnc;
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
|
|
|
|
++spice;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sdl > 1 || vnc > 1 || spice > 1) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("only 1 graphics device of each type "
|
|
|
|
"(sdl, vnc, spice) is supported"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->virtType == VIR_DOMAIN_VIRT_XEN ||
|
|
|
|
def->os.type == VIR_DOMAIN_OSTYPE_XEN ||
|
|
|
|
def->os.type == VIR_DOMAIN_OSTYPE_LINUX) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("qemu emulator '%s' does not support xen"),
|
|
|
|
def->emulator);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < def->ndisks; i++) {
|
|
|
|
virDomainDiskDefPtr disk = def->disks[i];
|
|
|
|
|
|
|
|
if (disk->src->driverName != NULL &&
|
|
|
|
STRNEQ(disk->src->driverName, "qemu")) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported driver name '%s' for disk '%s'"),
|
|
|
|
disk->src->driverName, disk->src->path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-17 10:34:24 +00:00
|
|
|
qemuBuildCommandLineCallbacks buildCommandLineCallbacks = {
|
|
|
|
.qemuGetSCSIDeviceSgName = virSCSIDeviceGetSgName,
|
|
|
|
};
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/*
|
|
|
|
* Constructs a argv suitable for launching qemu with config defined
|
|
|
|
* for a given virtual machine.
|
|
|
|
*
|
|
|
|
* XXX 'conn' is only required to resolve network -> bridge name
|
|
|
|
* figure out how to remove this requirement some day
|
|
|
|
*/
|
|
|
|
virCommandPtr
|
|
|
|
qemuBuildCommandLine(virConnectPtr conn,
|
2012-11-28 16:43:10 +00:00
|
|
|
virQEMUDriverPtr driver,
|
2016-02-23 13:05:09 +00:00
|
|
|
virLogManagerPtr logManager,
|
2012-11-10 01:40:23 +00:00
|
|
|
virDomainDefPtr def,
|
|
|
|
virDomainChrSourceDefPtr monitor_chr,
|
|
|
|
bool monitor_json,
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps,
|
2015-10-20 11:51:01 +00:00
|
|
|
const char *migrateURI,
|
2012-11-10 01:40:23 +00:00
|
|
|
virDomainSnapshotObjPtr snapshot,
|
2014-04-27 00:15:22 +00:00
|
|
|
virNetDevVPortProfileOp vmop,
|
2014-03-13 18:23:56 +00:00
|
|
|
qemuBuildCommandLineCallbacksPtr callbacks,
|
2014-09-18 15:38:32 +00:00
|
|
|
bool standalone,
|
2014-10-30 06:34:30 +00:00
|
|
|
bool enableFips,
|
2015-01-16 11:25:50 +00:00
|
|
|
virBitmapPtr nodeset,
|
|
|
|
size_t *nnicindexes,
|
2016-02-26 08:15:55 +00:00
|
|
|
int **nicindexes,
|
|
|
|
const char *domainLibDir,
|
|
|
|
const char *domainChannelTargetDir)
|
2012-11-10 01:40:23 +00:00
|
|
|
{
|
2013-04-24 12:06:40 +00:00
|
|
|
virErrorPtr originalError = NULL;
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i, j;
|
2012-11-10 01:40:23 +00:00
|
|
|
char uuid[VIR_UUID_STRING_BUFLEN];
|
2016-02-15 21:55:08 +00:00
|
|
|
bool havespice = false;
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandPtr cmd = NULL;
|
|
|
|
bool emitBootindex = false;
|
2014-02-10 10:33:19 +00:00
|
|
|
int actualSerials = 0;
|
2013-01-10 21:03:14 +00:00
|
|
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
2016-02-18 14:56:10 +00:00
|
|
|
int bootHostdevNet = 0;
|
qemu: add bootindex option to hostdev network interface commandline
when appropriate, of course. If the config for a domain specifies boot
order with <boot dev='blah'/> elements, e.g.:
<os>
...
<boot dev='hd'/>
<boot dev='network'/>
</os>
Then the first disk device in the config will have ",bootindex=1"
appended to its qemu commandline -device options, and the first (and
*only* the first) network interface device will get ",bootindex=2".
However, if the first network interface device is a "hostdev" device
(an SRIOV Virtual Function (VF) being assigned to the domain with
vfio), then the bootindex option will *not* be appended. This happens
because the bootindex=n option corresponding to the order of "<boot
dev='network'/>" is added to the -device for the first network device
when network device commandline args are constructed, but if it's a
hostdev network device, its commandline arg is instead constructed in
the loop for hostdevs.
This patch fixes that omission by noticing (in bootHostdevNet) if the
first network device was a hostdev, and if so passing on the proper
bootindex to the commandline generator for hostdev devices - the
result is that ",bootindex=2" will be properly appended to the first
"network" device in the config even if it is really a hostdev
(including if it is assigned from a libvirt network pool). (note that
this is only the case if there is no <bootmenu enabled='yes'/> element
in the config ("-boot menu-on" in qemu) , since the two are mutually
exclusive - when the bootmenu is enabled, the individual per-device
bootindex options can't be used by qemu, and we revert to using "-boot
order=xyz" instead).
If a greater level of control over boot order is desired (e.g., more
than one network device should be tried, or a network device other
than the first one encountered in the config), then <boot
dev='network'/> in the <os> element should not be used; instead, the
individual device elements in the config should be given a "<boot
order='n'/>
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1278421
2015-11-30 22:40:44 +00:00
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
VIR_DEBUG("conn=%p driver=%p def=%p mon=%p json=%d "
|
2015-10-20 11:51:01 +00:00
|
|
|
"qemuCaps=%p migrateURI=%s snapshot=%p vmop=%d",
|
2012-11-10 01:40:23 +00:00
|
|
|
conn, driver, def, monitor_chr, monitor_json,
|
2015-10-20 11:51:01 +00:00
|
|
|
qemuCaps, migrateURI, snapshot, vmop);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2016-02-15 21:55:08 +00:00
|
|
|
if (qemuBuildCommandLineValidate(driver, def) < 0)
|
|
|
|
goto error;
|
2014-01-30 11:19:12 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/*
|
|
|
|
* do not use boot=on for drives when not using KVM since this
|
|
|
|
* is not supported at all in upstream QEmu.
|
|
|
|
*/
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM) &&
|
2012-11-10 01:40:23 +00:00
|
|
|
(def->virtType == VIR_DOMAIN_VIRT_QEMU))
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsClear(qemuCaps, QEMU_CAPS_DRIVE_BOOT);
|
2012-11-10 01:40:23 +00:00
|
|
|
|
2016-02-15 21:23:28 +00:00
|
|
|
cmd = virCommandNew(def->emulator);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddEnvPassCommon(cmd);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2016-03-10 19:46:39 +00:00
|
|
|
if (qemuBuildNameCommandLine(cmd, cfg, def, qemuCaps) < 0)
|
|
|
|
goto error;
|
2014-03-13 18:23:56 +00:00
|
|
|
|
|
|
|
if (!standalone)
|
|
|
|
virCommandAddArg(cmd, "-S"); /* freeze CPU */
|
|
|
|
|
2014-09-18 15:38:32 +00:00
|
|
|
if (enableFips)
|
qemu: ask for -enable-fips when FIPS is required
On a system that is enforcing FIPS, most libraries honor the
current mode by default. Qemu, on the other hand, refused to
honor FIPS mode unless you add the '-enable-fips' command
line option; worse, this option is not discoverable via QMP,
and is only present on binaries built for Linux. So, if we
detect FIPS mode, then we unconditionally ask for FIPS; either
qemu is new enough to have the option and then correctly
cripple insecure VNC passwords, or it is so old that we are
correctly avoiding a FIPS violation by preventing qemu from
starting. Meanwhile, if we don't detect FIPS mode, then
omitting the argument is safe whether the qemu has the option
(but it would do nothing because FIPS is disabled) or whether
qemu lacks the option (including in the case where we are not
running on Linux).
The testsuite was a bit interesting: we don't want our test
to depend on whether it is being run in FIPS mode, so I had
to tweak things to set the capability bit outside of our
normal interaction with capability parsing.
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=1035474
* src/qemu/qemu_capabilities.h (QEMU_CAPS_ENABLE_FIPS): New bit.
* src/qemu/qemu_capabilities.c (virQEMUCapsInitQMP): Conditionally
set capability according to detection of FIPS mode.
* src/qemu/qemu_command.c (qemuBuildCommandLine): Use it.
* tests/qemucapabilitiestest.c (testQemuCaps): Conditionally set
capability to test expected output.
* tests/qemucapabilitiesdata/caps_1.2.2-1.caps: Update list.
* tests/qemucapabilitiesdata/caps_1.6.0-1.caps: Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-12-05 21:47:09 +00:00
|
|
|
virCommandAddArg(cmd, "-enable-fips");
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2016-02-17 21:04:17 +00:00
|
|
|
if (qemuBuildMachineCommandLine(cmd, def, qemuCaps) < 0)
|
2012-11-10 01:40:23 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2016-02-17 21:12:49 +00:00
|
|
|
if (qemuBuildCpuCommandLine(cmd, driver, def, qemuCaps, !!migrateURI) < 0)
|
2012-11-10 01:40:23 +00:00
|
|
|
goto error;
|
2011-06-15 16:49:58 +00:00
|
|
|
|
2014-08-07 11:50:00 +00:00
|
|
|
if (qemuBuildDomainLoaderCommandLine(cmd, def, qemuCaps) < 0)
|
|
|
|
goto error;
|
2012-11-10 01:40:23 +00:00
|
|
|
|
2016-02-17 21:19:26 +00:00
|
|
|
if (!migrateURI && !snapshot && qemuDomainAlignMemorySizes(def) < 0)
|
2015-10-01 05:47:39 +00:00
|
|
|
goto error;
|
2012-11-10 01:40:23 +00:00
|
|
|
|
2016-02-17 21:19:26 +00:00
|
|
|
if (qemuBuildMemCommandLine(cmd, cfg, def, qemuCaps) < 0)
|
2013-05-16 20:01:05 +00:00
|
|
|
goto error;
|
|
|
|
|
2016-02-17 21:23:46 +00:00
|
|
|
if (qemuBuildSmpCommandLine(cmd, def, qemuCaps) < 0)
|
2012-11-10 01:40:23 +00:00
|
|
|
goto error;
|
|
|
|
|
2016-02-17 21:27:30 +00:00
|
|
|
if (qemuBuildIOThreadCommandLine(cmd, def, qemuCaps) < 0)
|
|
|
|
goto error;
|
2014-08-22 22:15:30 +00:00
|
|
|
|
2016-02-17 21:56:37 +00:00
|
|
|
if (qemuBuildNumaCommandLine(cmd, cfg, def, qemuCaps, nodeset) < 0)
|
|
|
|
goto error;
|
2015-01-09 09:40:37 +00:00
|
|
|
|
2016-02-17 22:10:37 +00:00
|
|
|
virUUIDFormat(def->uuid, uuid);
|
2015-11-06 14:29:52 +00:00
|
|
|
virCommandAddArgList(cmd, "-uuid", uuid, NULL);
|
2012-08-02 10:14:39 +00:00
|
|
|
|
2016-02-17 22:10:37 +00:00
|
|
|
if (qemuBuildSmbiosCommandLine(cmd, driver, def, qemuCaps) < 0)
|
|
|
|
goto error;
|
2012-09-18 09:38:18 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/*
|
|
|
|
* NB, -nographic *MUST* come before any serial, or monitor
|
|
|
|
* or parallel port flags due to QEMU craziness, where it
|
|
|
|
* decides to change the serial port & monitor to be on stdout
|
|
|
|
* if you ask for nographic. So we have to make sure we override
|
|
|
|
* these defaults ourselves...
|
|
|
|
*/
|
2016-02-23 08:38:26 +00:00
|
|
|
if (!def->ngraphics) {
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-nographic");
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2013-08-17 19:30:47 +00:00
|
|
|
if (cfg->nogfxAllowHostAudio)
|
2013-10-09 10:03:02 +00:00
|
|
|
virCommandAddEnvPassBlockSUID(cmd, "QEMU_AUDIO_DRV", NULL);
|
2013-08-17 19:30:47 +00:00
|
|
|
else
|
|
|
|
virCommandAddEnvString(cmd, "QEMU_AUDIO_DRV=none");
|
|
|
|
}
|
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
2012-11-10 01:40:23 +00:00
|
|
|
/* Disable global config files and default devices */
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NO_USER_CONFIG))
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-no-user-config");
|
2013-02-01 13:48:58 +00:00
|
|
|
else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NODEFCONFIG))
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-nodefconfig");
|
|
|
|
virCommandAddArg(cmd, "-nodefaults");
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2016-02-17 22:19:00 +00:00
|
|
|
if (qemuBuildSgaCommandLine(cmd, def, qemuCaps) < 0)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2016-02-23 13:05:09 +00:00
|
|
|
if (qemuBuildMonitorCommandLine(logManager, cmd, def,
|
|
|
|
qemuCaps, monitor_chr,
|
2016-02-17 22:27:21 +00:00
|
|
|
monitor_json) < 0)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2016-02-18 11:42:45 +00:00
|
|
|
if (qemuBuildClockCommandLine(cmd, def, qemuCaps) < 0)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2016-02-18 13:06:17 +00:00
|
|
|
if (qemuBuildPMCommandLine(cmd, def, qemuCaps, monitor_json) < 0)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2016-02-18 13:15:10 +00:00
|
|
|
if (qemuBuildBootCommandLine(cmd, def, qemuCaps, &emitBootindex) < 0)
|
2015-02-18 16:25:10 +00:00
|
|
|
goto error;
|
2015-02-18 15:08:40 +00:00
|
|
|
|
2016-02-18 13:18:18 +00:00
|
|
|
if (qemuBuildGlobalControllerCommandLine(cmd, def, qemuCaps) < 0)
|
|
|
|
goto error;
|
2013-08-12 11:48:34 +00:00
|
|
|
|
2016-02-18 13:33:39 +00:00
|
|
|
if (qemuBuildControllerDevCommandLine(cmd, def, qemuCaps) < 0)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2016-02-18 14:30:28 +00:00
|
|
|
if (qemuBuildHubCommandLine(cmd, def, qemuCaps) < 0)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2016-02-18 14:56:10 +00:00
|
|
|
if (qemuBuildDiskDriveCommandLine(cmd, conn, def, qemuCaps,
|
|
|
|
emitBootindex) < 0)
|
|
|
|
goto error;
|
2011-01-13 00:09:45 +00:00
|
|
|
|
2016-02-18 15:06:14 +00:00
|
|
|
if (qemuBuildFSDevCommandLine(cmd, def, qemuCaps) < 0)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2016-02-18 15:32:07 +00:00
|
|
|
if (qemuBuildNetCommandLine(cmd, driver, def, qemuCaps, vmop, standalone,
|
|
|
|
emitBootindex, nnicindexes, nicindexes,
|
|
|
|
&bootHostdevNet) < 0)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (def->nsmartcards) {
|
|
|
|
/* -device usb-ccid was already emitted along with other
|
|
|
|
* controllers. For now, qemu handles only one smartcard. */
|
|
|
|
virDomainSmartcardDefPtr smartcard = def->smartcards[0];
|
|
|
|
char *devstr;
|
2010-12-16 15:07:07 +00:00
|
|
|
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
2012-11-10 01:40:23 +00:00
|
|
|
const char *database;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (def->nsmartcards > 1 ||
|
|
|
|
smartcard->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID ||
|
|
|
|
smartcard->info.addr.ccid.controller != 0 ||
|
|
|
|
smartcard->info.addr.ccid.slot != 0) {
|
2012-10-19 19:40:52 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2012-11-10 01:40:23 +00:00
|
|
|
_("this QEMU binary lacks multiple smartcard "
|
|
|
|
"support"));
|
|
|
|
virBufferFreeAndReset(&opt);
|
2012-10-19 19:40:52 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
switch (smartcard->type) {
|
|
|
|
case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CHARDEV) ||
|
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CCID_EMULATED)) {
|
2012-11-10 01:40:23 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("this QEMU binary lacks smartcard host "
|
|
|
|
"mode support"));
|
|
|
|
goto error;
|
2011-01-12 04:44:11 +00:00
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virBufferAddLit(&opt, "ccid-card-emulated,backend=nss-emulated");
|
|
|
|
break;
|
qemu: support type=network in domain graphics <listen>
The domain XML now understands the <listen> subelement of its
<graphics> element (including when listen type='network'), and the
network driver has an internal API that will turn a network name into
an IP address, so the final logical step is to put the glue into the
qemu driver so that when it is starting up a domain, if it finds
<listen type='network' network='xyz'/> in the XML, it will call the
network driver to get an IPv4 address associated with network xyz, and
tell qemu to listen for vnc (or spice) on that address rather than the
default address (localhost).
The motivation for this is that a large installation may want the
guests' VNC servers listening on physical interfaces rather than
localhost, so that users can connect directly from the outside; this
requires sending qemu the appropriate IP address to listen on. But
this address will of course be different for each host, and if a guest
might be migrated around from one host to another, it's important that
the guest's config not have any information embedded in it that is
specific to one particular host. <listen type='network.../> can solve
this problem in the following manner:
1) on each host, define a libvirt network of the same name,
associated with the interface on that host that should be used
for listening (for example, a simple macvtap network: <forward
mode='bridge' dev='eth0'/>, or host bridge network: <forward
mode='bridge'/> <bridge name='br0'/>
2) in the <graphics> element of each guest's domain xml, tell vnc to
listen on the network name used in step 1:
<graphics type='vnc' port='5922'>
<listen type='network'network='example-net'/>
</graphics>
(all the above also applies for graphics type='spice').
2011-07-07 06:12:04 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES:
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CHARDEV) ||
|
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CCID_EMULATED)) {
|
2012-11-10 01:40:23 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("this QEMU binary lacks smartcard host "
|
|
|
|
"mode support"));
|
|
|
|
goto error;
|
|
|
|
}
|
qemu: support type=network in domain graphics <listen>
The domain XML now understands the <listen> subelement of its
<graphics> element (including when listen type='network'), and the
network driver has an internal API that will turn a network name into
an IP address, so the final logical step is to put the glue into the
qemu driver so that when it is starting up a domain, if it finds
<listen type='network' network='xyz'/> in the XML, it will call the
network driver to get an IPv4 address associated with network xyz, and
tell qemu to listen for vnc (or spice) on that address rather than the
default address (localhost).
The motivation for this is that a large installation may want the
guests' VNC servers listening on physical interfaces rather than
localhost, so that users can connect directly from the outside; this
requires sending qemu the appropriate IP address to listen on. But
this address will of course be different for each host, and if a guest
might be migrated around from one host to another, it's important that
the guest's config not have any information embedded in it that is
specific to one particular host. <listen type='network.../> can solve
this problem in the following manner:
1) on each host, define a libvirt network of the same name,
associated with the interface on that host that should be used
for listening (for example, a simple macvtap network: <forward
mode='bridge' dev='eth0'/>, or host bridge network: <forward
mode='bridge'/> <bridge name='br0'/>
2) in the <graphics> element of each guest's domain xml, tell vnc to
listen on the network name used in step 1:
<graphics type='vnc' port='5922'>
<listen type='network'network='example-net'/>
</graphics>
(all the above also applies for graphics type='spice').
2011-07-07 06:12:04 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virBufferAddLit(&opt, "ccid-card-emulated,backend=certificates");
|
|
|
|
for (j = 0; j < VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES; j++) {
|
|
|
|
if (strchr(smartcard->data.cert.file[j], ',')) {
|
|
|
|
virBufferFreeAndReset(&opt);
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2012-11-10 01:40:23 +00:00
|
|
|
_("invalid certificate name: %s"),
|
|
|
|
smartcard->data.cert.file[j]);
|
qemu: support type=network in domain graphics <listen>
The domain XML now understands the <listen> subelement of its
<graphics> element (including when listen type='network'), and the
network driver has an internal API that will turn a network name into
an IP address, so the final logical step is to put the glue into the
qemu driver so that when it is starting up a domain, if it finds
<listen type='network' network='xyz'/> in the XML, it will call the
network driver to get an IPv4 address associated with network xyz, and
tell qemu to listen for vnc (or spice) on that address rather than the
default address (localhost).
The motivation for this is that a large installation may want the
guests' VNC servers listening on physical interfaces rather than
localhost, so that users can connect directly from the outside; this
requires sending qemu the appropriate IP address to listen on. But
this address will of course be different for each host, and if a guest
might be migrated around from one host to another, it's important that
the guest's config not have any information embedded in it that is
specific to one particular host. <listen type='network.../> can solve
this problem in the following manner:
1) on each host, define a libvirt network of the same name,
associated with the interface on that host that should be used
for listening (for example, a simple macvtap network: <forward
mode='bridge' dev='eth0'/>, or host bridge network: <forward
mode='bridge'/> <bridge name='br0'/>
2) in the <graphics> element of each guest's domain xml, tell vnc to
listen on the network name used in step 1:
<graphics type='vnc' port='5922'>
<listen type='network'network='example-net'/>
</graphics>
(all the above also applies for graphics type='spice').
2011-07-07 06:12:04 +00:00
|
|
|
goto error;
|
|
|
|
}
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
virBufferAsprintf(&opt, ",cert%zu=%s", j + 1,
|
2012-11-10 01:40:23 +00:00
|
|
|
smartcard->data.cert.file[j]);
|
|
|
|
}
|
|
|
|
if (smartcard->data.cert.database) {
|
|
|
|
if (strchr(smartcard->data.cert.database, ',')) {
|
|
|
|
virBufferFreeAndReset(&opt);
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("invalid database name: %s"),
|
|
|
|
smartcard->data.cert.database);
|
qemu: support type=network in domain graphics <listen>
The domain XML now understands the <listen> subelement of its
<graphics> element (including when listen type='network'), and the
network driver has an internal API that will turn a network name into
an IP address, so the final logical step is to put the glue into the
qemu driver so that when it is starting up a domain, if it finds
<listen type='network' network='xyz'/> in the XML, it will call the
network driver to get an IPv4 address associated with network xyz, and
tell qemu to listen for vnc (or spice) on that address rather than the
default address (localhost).
The motivation for this is that a large installation may want the
guests' VNC servers listening on physical interfaces rather than
localhost, so that users can connect directly from the outside; this
requires sending qemu the appropriate IP address to listen on. But
this address will of course be different for each host, and if a guest
might be migrated around from one host to another, it's important that
the guest's config not have any information embedded in it that is
specific to one particular host. <listen type='network.../> can solve
this problem in the following manner:
1) on each host, define a libvirt network of the same name,
associated with the interface on that host that should be used
for listening (for example, a simple macvtap network: <forward
mode='bridge' dev='eth0'/>, or host bridge network: <forward
mode='bridge'/> <bridge name='br0'/>
2) in the <graphics> element of each guest's domain xml, tell vnc to
listen on the network name used in step 1:
<graphics type='vnc' port='5922'>
<listen type='network'network='example-net'/>
</graphics>
(all the above also applies for graphics type='spice').
2011-07-07 06:12:04 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
database = smartcard->data.cert.database;
|
|
|
|
} else {
|
|
|
|
database = VIR_DOMAIN_SMARTCARD_DEFAULT_DATABASE;
|
qemu: support type=network in domain graphics <listen>
The domain XML now understands the <listen> subelement of its
<graphics> element (including when listen type='network'), and the
network driver has an internal API that will turn a network name into
an IP address, so the final logical step is to put the glue into the
qemu driver so that when it is starting up a domain, if it finds
<listen type='network' network='xyz'/> in the XML, it will call the
network driver to get an IPv4 address associated with network xyz, and
tell qemu to listen for vnc (or spice) on that address rather than the
default address (localhost).
The motivation for this is that a large installation may want the
guests' VNC servers listening on physical interfaces rather than
localhost, so that users can connect directly from the outside; this
requires sending qemu the appropriate IP address to listen on. But
this address will of course be different for each host, and if a guest
might be migrated around from one host to another, it's important that
the guest's config not have any information embedded in it that is
specific to one particular host. <listen type='network.../> can solve
this problem in the following manner:
1) on each host, define a libvirt network of the same name,
associated with the interface on that host that should be used
for listening (for example, a simple macvtap network: <forward
mode='bridge' dev='eth0'/>, or host bridge network: <forward
mode='bridge'/> <bridge name='br0'/>
2) in the <graphics> element of each guest's domain xml, tell vnc to
listen on the network name used in step 1:
<graphics type='vnc' port='5922'>
<listen type='network'network='example-net'/>
</graphics>
(all the above also applies for graphics type='spice').
2011-07-07 06:12:04 +00:00
|
|
|
}
|
2013-04-01 22:54:31 +00:00
|
|
|
virBufferAsprintf(&opt, ",db=%s", database);
|
2012-11-10 01:40:23 +00:00
|
|
|
break;
|
conf: add <listen> subelement to domain <graphics> element
Once it's plugged in, the <listen> element will be an optional
replacement for the "listen" attribute that graphics elements already
have. If the <listen> element is type='address', it will have an
attribute called 'address' which will contain an IP address or dns
name that the guest's display server should listen on. If, however,
type='network', the <listen> element should have an attribute called
'network' that will be set to the name of a network configuration to
get the IP address from.
* docs/schemas/domain.rng: updated to allow the <listen> element
* docs/formatdomain.html.in: document the <listen> element and its
attributes.
* src/conf/domain_conf.[hc]:
1) The domain parser, formatter, and data structure are modified to
support 0 or more <listen> subelements to each <graphics>
element. The old style "legacy" listen attribute is also still
accepted, and will be stored internally just as if it were a
separate <listen> element. On output (i.e. format), the address
attribute of the first <listen> element of type 'address' will be
duplicated in the legacy "listen" attribute of the <graphic>
element.
2) The "listenAddr" attribute has been removed from the unions in
virDomainGRaphicsDef for graphics types vnc, rdp, and spice.
This attribute is now in the <listen> subelement (aka
virDomainGraphicsListenDef)
3) Helper functions were written to provide simple access
(both Get and Set) to the listen elements and their attributes.
* src/libvirt_private.syms: export the listen helper functions
* src/qemu/qemu_command.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/vbox/vbox_tmpl.c,
src/vmx/vmx.c, src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c
Modify all these files to use the listen helper functions rather
than directly referencing the (now missing) listenAddr
attribute. There can be multiple <listen> elements to a single
<graphics>, but the drivers all currently only support one, so all
replacements of direct access with a helper function indicate index
"0".
* tests/* - only 3 of these are new files added explicitly to test the
new <listen> element. All the others have been modified to reflect
the fact that any legacy "listen" attributes passed in to the domain
parse will be saved in a <listen> element (i.e. one of the
virDomainGraphicsListenDefs), and during the domain format function,
both the <listen> element as well as the legacy attributes will be
output.
2011-07-07 04:20:28 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CHARDEV) ||
|
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CCID_PASSTHRU)) {
|
2012-11-10 01:40:23 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("this QEMU binary lacks smartcard "
|
|
|
|
"passthrough mode support"));
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2016-02-23 13:05:09 +00:00
|
|
|
if (!(devstr = qemuBuildChrChardevStr(logManager, cmd, def,
|
|
|
|
&smartcard->data.passthru,
|
2012-11-10 01:40:23 +00:00
|
|
|
smartcard->info.alias,
|
2013-02-01 13:48:58 +00:00
|
|
|
qemuCaps))) {
|
2012-11-10 01:40:23 +00:00
|
|
|
virBufferFreeAndReset(&opt);
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2016-02-29 12:21:14 +00:00
|
|
|
virCommandAddArg(cmd, "-chardev");
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virBufferAsprintf(&opt, "ccid-card-passthru,chardev=char%s",
|
|
|
|
smartcard->info.alias);
|
|
|
|
break;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected smartcard type %d"),
|
|
|
|
smartcard->type);
|
|
|
|
virBufferFreeAndReset(&opt);
|
2011-01-12 14:44:00 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
virBufferAsprintf(&opt, ",id=%s,bus=ccid0.0", smartcard->info.alias);
|
|
|
|
virCommandAddArgBuffer(cmd, &opt);
|
|
|
|
}
|
2011-01-12 14:44:00 +00:00
|
|
|
|
2016-02-15 21:55:08 +00:00
|
|
|
if (def->nserials) {
|
|
|
|
for (i = 0; i < def->ngraphics; i++) {
|
|
|
|
if (def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
|
|
|
|
havespice = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-10 10:45:28 +00:00
|
|
|
for (i = 0; i < def->nserials; i++) {
|
|
|
|
virDomainChrDefPtr serial = def->serials[i];
|
|
|
|
char *devstr;
|
2012-11-10 01:40:23 +00:00
|
|
|
|
2016-02-15 21:55:08 +00:00
|
|
|
if (serial->source.type == VIR_DOMAIN_CHR_TYPE_SPICEPORT && !havespice)
|
2014-01-30 11:19:12 +00:00
|
|
|
continue;
|
|
|
|
|
2014-02-10 10:45:28 +00:00
|
|
|
/* Use -chardev with -device if they are available */
|
|
|
|
if (virQEMUCapsSupportsChardev(def, qemuCaps, serial)) {
|
2016-02-23 13:05:09 +00:00
|
|
|
if (!(devstr = qemuBuildChrChardevStr(logManager, cmd, def,
|
|
|
|
&serial->source,
|
2014-02-10 10:45:28 +00:00
|
|
|
serial->info.alias,
|
|
|
|
qemuCaps)))
|
|
|
|
goto error;
|
2016-02-29 12:21:14 +00:00
|
|
|
virCommandAddArg(cmd, "-chardev");
|
2014-02-10 10:45:28 +00:00
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
|
|
|
|
if (qemuBuildChrDeviceCommandLine(cmd, def, serial, qemuCaps) < 0)
|
|
|
|
goto error;
|
|
|
|
} else {
|
|
|
|
virCommandAddArg(cmd, "-serial");
|
|
|
|
if (!(devstr = qemuBuildChrArgStr(&serial->source, NULL)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
2012-11-10 01:40:23 +00:00
|
|
|
}
|
2014-02-10 10:45:28 +00:00
|
|
|
actualSerials++;
|
2012-11-10 01:40:23 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2014-02-10 10:33:19 +00:00
|
|
|
/* If we have -device, then we set -nodefault already */
|
|
|
|
if (!actualSerials && !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))
|
|
|
|
virCommandAddArgList(cmd, "-serial", "none", NULL);
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (!def->nparallels) {
|
|
|
|
/* If we have -device, then we set -nodefault already */
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArgList(cmd, "-parallel", "none", NULL);
|
|
|
|
} else {
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < def->nparallels; i++) {
|
2012-11-10 01:40:23 +00:00
|
|
|
virDomainChrDefPtr parallel = def->parallels[i];
|
|
|
|
char *devstr;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/* Use -chardev with -device if they are available */
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_CHARDEV) &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
2016-02-23 13:05:09 +00:00
|
|
|
if (!(devstr = qemuBuildChrChardevStr(logManager, cmd, def,
|
|
|
|
¶llel->source,
|
2012-11-10 01:40:23 +00:00
|
|
|
parallel->info.alias,
|
2013-02-01 13:48:58 +00:00
|
|
|
qemuCaps)))
|
2012-11-10 01:40:23 +00:00
|
|
|
goto error;
|
2016-02-29 12:21:14 +00:00
|
|
|
virCommandAddArg(cmd, "-chardev");
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2013-03-13 15:20:34 +00:00
|
|
|
if (qemuBuildChrDeviceCommandLine(cmd, def, parallel, qemuCaps) < 0)
|
|
|
|
goto error;
|
2012-11-10 01:40:23 +00:00
|
|
|
} else {
|
|
|
|
virCommandAddArg(cmd, "-parallel");
|
|
|
|
if (!(devstr = qemuBuildChrArgStr(¶llel->source, NULL)))
|
2015-03-17 02:34:26 +00:00
|
|
|
goto error;
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < def->nchannels; i++) {
|
2012-11-10 01:40:23 +00:00
|
|
|
virDomainChrDefPtr channel = def->channels[i];
|
|
|
|
char *devstr;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
switch (channel->targetType) {
|
|
|
|
case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD:
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CHARDEV) ||
|
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
2012-11-10 01:40:23 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("guestfwd requires QEMU to support -chardev & -device"));
|
2012-02-24 10:34:45 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2016-02-23 13:05:09 +00:00
|
|
|
if (!(devstr = qemuBuildChrChardevStr(logManager, cmd, def,
|
|
|
|
&channel->source,
|
2012-11-10 01:40:23 +00:00
|
|
|
channel->info.alias,
|
2013-02-01 13:48:58 +00:00
|
|
|
qemuCaps)))
|
2012-11-10 01:40:23 +00:00
|
|
|
goto error;
|
2016-02-29 12:21:14 +00:00
|
|
|
virCommandAddArg(cmd, "-chardev");
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
|
2013-03-13 15:20:34 +00:00
|
|
|
if (qemuBuildChrDeviceStr(&devstr, def, channel, qemuCaps) < 0)
|
2012-11-10 01:40:23 +00:00
|
|
|
goto error;
|
2013-03-13 15:20:34 +00:00
|
|
|
virCommandAddArgList(cmd, "-netdev", devstr, NULL);
|
|
|
|
VIR_FREE(devstr);
|
qemu: support type=network in domain graphics <listen>
The domain XML now understands the <listen> subelement of its
<graphics> element (including when listen type='network'), and the
network driver has an internal API that will turn a network name into
an IP address, so the final logical step is to put the glue into the
qemu driver so that when it is starting up a domain, if it finds
<listen type='network' network='xyz'/> in the XML, it will call the
network driver to get an IPv4 address associated with network xyz, and
tell qemu to listen for vnc (or spice) on that address rather than the
default address (localhost).
The motivation for this is that a large installation may want the
guests' VNC servers listening on physical interfaces rather than
localhost, so that users can connect directly from the outside; this
requires sending qemu the appropriate IP address to listen on. But
this address will of course be different for each host, and if a guest
might be migrated around from one host to another, it's important that
the guest's config not have any information embedded in it that is
specific to one particular host. <listen type='network.../> can solve
this problem in the following manner:
1) on each host, define a libvirt network of the same name,
associated with the interface on that host that should be used
for listening (for example, a simple macvtap network: <forward
mode='bridge' dev='eth0'/>, or host bridge network: <forward
mode='bridge'/> <bridge name='br0'/>
2) in the <graphics> element of each guest's domain xml, tell vnc to
listen on the network name used in step 1:
<graphics type='vnc' port='5922'>
<listen type='network'network='example-net'/>
</graphics>
(all the above also applies for graphics type='spice').
2011-07-07 06:12:04 +00:00
|
|
|
break;
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO:
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
2012-11-10 01:40:23 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("virtio channel requires QEMU to support -device"));
|
qemu: support type=network in domain graphics <listen>
The domain XML now understands the <listen> subelement of its
<graphics> element (including when listen type='network'), and the
network driver has an internal API that will turn a network name into
an IP address, so the final logical step is to put the glue into the
qemu driver so that when it is starting up a domain, if it finds
<listen type='network' network='xyz'/> in the XML, it will call the
network driver to get an IPv4 address associated with network xyz, and
tell qemu to listen for vnc (or spice) on that address rather than the
default address (localhost).
The motivation for this is that a large installation may want the
guests' VNC servers listening on physical interfaces rather than
localhost, so that users can connect directly from the outside; this
requires sending qemu the appropriate IP address to listen on. But
this address will of course be different for each host, and if a guest
might be migrated around from one host to another, it's important that
the guest's config not have any information embedded in it that is
specific to one particular host. <listen type='network.../> can solve
this problem in the following manner:
1) on each host, define a libvirt network of the same name,
associated with the interface on that host that should be used
for listening (for example, a simple macvtap network: <forward
mode='bridge' dev='eth0'/>, or host bridge network: <forward
mode='bridge'/> <bridge name='br0'/>
2) in the <graphics> element of each guest's domain xml, tell vnc to
listen on the network name used in step 1:
<graphics type='vnc' port='5922'>
<listen type='network'network='example-net'/>
</graphics>
(all the above also applies for graphics type='spice').
2011-07-07 06:12:04 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
|
2016-01-06 16:35:04 +00:00
|
|
|
/*
|
|
|
|
* TODO: Refactor so that we generate this (and onther
|
|
|
|
* things) somewhere else then where we are building the
|
|
|
|
* command line.
|
|
|
|
*/
|
|
|
|
if (channel->source.type == VIR_DOMAIN_CHR_TYPE_UNIX &&
|
|
|
|
!channel->source.data.nix.path) {
|
|
|
|
if (virAsprintf(&channel->source.data.nix.path,
|
2016-02-26 08:15:55 +00:00
|
|
|
"%s/%s", domainChannelTargetDir,
|
2016-01-06 16:35:04 +00:00
|
|
|
channel->target.name ? channel->target.name
|
|
|
|
: "unknown.sock") < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
channel->source.data.nix.listen = true;
|
|
|
|
}
|
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SPICEVMC) &&
|
2012-11-10 01:40:23 +00:00
|
|
|
channel->source.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) {
|
|
|
|
/* spicevmc was originally introduced via a -device
|
|
|
|
* with a backend internal to qemu; although we prefer
|
|
|
|
* the newer -chardev interface. */
|
|
|
|
;
|
|
|
|
} else {
|
2016-02-23 13:05:09 +00:00
|
|
|
if (!(devstr = qemuBuildChrChardevStr(logManager, cmd, def,
|
|
|
|
&channel->source,
|
2012-11-10 01:40:23 +00:00
|
|
|
channel->info.alias,
|
2013-02-01 13:48:58 +00:00
|
|
|
qemuCaps)))
|
2012-11-10 01:40:23 +00:00
|
|
|
goto error;
|
2016-02-29 12:21:14 +00:00
|
|
|
virCommandAddArg(cmd, "-chardev");
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
qemu: support type=network in domain graphics <listen>
The domain XML now understands the <listen> subelement of its
<graphics> element (including when listen type='network'), and the
network driver has an internal API that will turn a network name into
an IP address, so the final logical step is to put the glue into the
qemu driver so that when it is starting up a domain, if it finds
<listen type='network' network='xyz'/> in the XML, it will call the
network driver to get an IPv4 address associated with network xyz, and
tell qemu to listen for vnc (or spice) on that address rather than the
default address (localhost).
The motivation for this is that a large installation may want the
guests' VNC servers listening on physical interfaces rather than
localhost, so that users can connect directly from the outside; this
requires sending qemu the appropriate IP address to listen on. But
this address will of course be different for each host, and if a guest
might be migrated around from one host to another, it's important that
the guest's config not have any information embedded in it that is
specific to one particular host. <listen type='network.../> can solve
this problem in the following manner:
1) on each host, define a libvirt network of the same name,
associated with the interface on that host that should be used
for listening (for example, a simple macvtap network: <forward
mode='bridge' dev='eth0'/>, or host bridge network: <forward
mode='bridge'/> <bridge name='br0'/>
2) in the <graphics> element of each guest's domain xml, tell vnc to
listen on the network name used in step 1:
<graphics type='vnc' port='5922'>
<listen type='network'network='example-net'/>
</graphics>
(all the above also applies for graphics type='spice').
2011-07-07 06:12:04 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
|
2013-03-13 15:20:34 +00:00
|
|
|
if (qemuBuildChrDeviceCommandLine(cmd, def, channel, qemuCaps) < 0)
|
2012-11-10 01:40:23 +00:00
|
|
|
goto error;
|
qemu: support type=network in domain graphics <listen>
The domain XML now understands the <listen> subelement of its
<graphics> element (including when listen type='network'), and the
network driver has an internal API that will turn a network name into
an IP address, so the final logical step is to put the glue into the
qemu driver so that when it is starting up a domain, if it finds
<listen type='network' network='xyz'/> in the XML, it will call the
network driver to get an IPv4 address associated with network xyz, and
tell qemu to listen for vnc (or spice) on that address rather than the
default address (localhost).
The motivation for this is that a large installation may want the
guests' VNC servers listening on physical interfaces rather than
localhost, so that users can connect directly from the outside; this
requires sending qemu the appropriate IP address to listen on. But
this address will of course be different for each host, and if a guest
might be migrated around from one host to another, it's important that
the guest's config not have any information embedded in it that is
specific to one particular host. <listen type='network.../> can solve
this problem in the following manner:
1) on each host, define a libvirt network of the same name,
associated with the interface on that host that should be used
for listening (for example, a simple macvtap network: <forward
mode='bridge' dev='eth0'/>, or host bridge network: <forward
mode='bridge'/> <bridge name='br0'/>
2) in the <graphics> element of each guest's domain xml, tell vnc to
listen on the network name used in step 1:
<graphics type='vnc' port='5922'>
<listen type='network'network='example-net'/>
</graphics>
(all the above also applies for graphics type='spice').
2011-07-07 06:12:04 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
}
|
qemu: support type=network in domain graphics <listen>
The domain XML now understands the <listen> subelement of its
<graphics> element (including when listen type='network'), and the
network driver has an internal API that will turn a network name into
an IP address, so the final logical step is to put the glue into the
qemu driver so that when it is starting up a domain, if it finds
<listen type='network' network='xyz'/> in the XML, it will call the
network driver to get an IPv4 address associated with network xyz, and
tell qemu to listen for vnc (or spice) on that address rather than the
default address (localhost).
The motivation for this is that a large installation may want the
guests' VNC servers listening on physical interfaces rather than
localhost, so that users can connect directly from the outside; this
requires sending qemu the appropriate IP address to listen on. But
this address will of course be different for each host, and if a guest
might be migrated around from one host to another, it's important that
the guest's config not have any information embedded in it that is
specific to one particular host. <listen type='network.../> can solve
this problem in the following manner:
1) on each host, define a libvirt network of the same name,
associated with the interface on that host that should be used
for listening (for example, a simple macvtap network: <forward
mode='bridge' dev='eth0'/>, or host bridge network: <forward
mode='bridge'/> <bridge name='br0'/>
2) in the <graphics> element of each guest's domain xml, tell vnc to
listen on the network name used in step 1:
<graphics type='vnc' port='5922'>
<listen type='network'network='example-net'/>
</graphics>
(all the above also applies for graphics type='spice').
2011-07-07 06:12:04 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/* Explicit console devices */
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < def->nconsoles; i++) {
|
2012-11-10 01:40:23 +00:00
|
|
|
virDomainChrDefPtr console = def->consoles[i];
|
|
|
|
char *devstr;
|
qemu: support type=network in domain graphics <listen>
The domain XML now understands the <listen> subelement of its
<graphics> element (including when listen type='network'), and the
network driver has an internal API that will turn a network name into
an IP address, so the final logical step is to put the glue into the
qemu driver so that when it is starting up a domain, if it finds
<listen type='network' network='xyz'/> in the XML, it will call the
network driver to get an IPv4 address associated with network xyz, and
tell qemu to listen for vnc (or spice) on that address rather than the
default address (localhost).
The motivation for this is that a large installation may want the
guests' VNC servers listening on physical interfaces rather than
localhost, so that users can connect directly from the outside; this
requires sending qemu the appropriate IP address to listen on. But
this address will of course be different for each host, and if a guest
might be migrated around from one host to another, it's important that
the guest's config not have any information embedded in it that is
specific to one particular host. <listen type='network.../> can solve
this problem in the following manner:
1) on each host, define a libvirt network of the same name,
associated with the interface on that host that should be used
for listening (for example, a simple macvtap network: <forward
mode='bridge' dev='eth0'/>, or host bridge network: <forward
mode='bridge'/> <bridge name='br0'/>
2) in the <graphics> element of each guest's domain xml, tell vnc to
listen on the network name used in step 1:
<graphics type='vnc' port='5922'>
<listen type='network'network='example-net'/>
</graphics>
(all the above also applies for graphics type='spice').
2011-07-07 06:12:04 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
switch (console->targetType) {
|
2013-01-07 17:17:15 +00:00
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SCLP:
|
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SCLPLM:
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
2013-01-07 17:17:15 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("sclp console requires QEMU to support -device"));
|
|
|
|
goto error;
|
|
|
|
}
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCLP_S390)) {
|
2013-01-07 17:17:15 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("sclp console requires QEMU to support s390-sclp"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2016-02-23 13:05:09 +00:00
|
|
|
if (!(devstr = qemuBuildChrChardevStr(logManager, cmd, def,
|
|
|
|
&console->source,
|
2013-01-07 17:17:15 +00:00
|
|
|
console->info.alias,
|
2013-02-01 13:48:58 +00:00
|
|
|
qemuCaps)))
|
2013-01-07 17:17:15 +00:00
|
|
|
goto error;
|
2016-02-29 12:21:14 +00:00
|
|
|
virCommandAddArg(cmd, "-chardev");
|
2013-01-07 17:17:15 +00:00
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
|
2013-03-13 15:20:34 +00:00
|
|
|
if (qemuBuildChrDeviceCommandLine(cmd, def, console, qemuCaps) < 0)
|
2013-01-07 17:17:15 +00:00
|
|
|
goto error;
|
|
|
|
break;
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO:
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
2012-11-10 01:40:23 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("virtio channel requires QEMU to support -device"));
|
|
|
|
goto error;
|
2012-03-09 07:26:24 +00:00
|
|
|
}
|
|
|
|
|
2016-02-23 13:05:09 +00:00
|
|
|
if (!(devstr = qemuBuildChrChardevStr(logManager, cmd, def,
|
|
|
|
&console->source,
|
2012-11-10 01:40:23 +00:00
|
|
|
console->info.alias,
|
2013-02-01 13:48:58 +00:00
|
|
|
qemuCaps)))
|
2012-11-10 01:40:23 +00:00
|
|
|
goto error;
|
2016-02-29 12:21:14 +00:00
|
|
|
virCommandAddArg(cmd, "-chardev");
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2013-03-13 15:20:34 +00:00
|
|
|
if (qemuBuildChrDeviceCommandLine(cmd, def, console, qemuCaps) < 0)
|
2012-11-10 01:40:23 +00:00
|
|
|
goto error;
|
2012-05-08 17:42:44 +00:00
|
|
|
break;
|
2012-11-10 01:40:23 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL:
|
2012-05-08 17:42:44 +00:00
|
|
|
break;
|
2012-11-10 01:40:23 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported console target type %s"),
|
|
|
|
NULLSTR(virDomainChrConsoleTargetTypeToString(console->targetType)));
|
|
|
|
goto error;
|
2012-05-08 17:42:44 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
}
|
2012-05-08 17:42:44 +00:00
|
|
|
|
2013-04-12 20:55:46 +00:00
|
|
|
if (def->tpm) {
|
2016-02-15 21:23:28 +00:00
|
|
|
if (qemuBuildTPMCommandLine(def, cmd, qemuCaps, def->emulator) < 0)
|
2013-04-12 20:55:46 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < def->ninputs; i++) {
|
2012-11-10 01:40:23 +00:00
|
|
|
virDomainInputDefPtr input = def->inputs[i];
|
|
|
|
|
|
|
|
if (input->bus == VIR_DOMAIN_INPUT_BUS_USB) {
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
2012-11-10 01:40:23 +00:00
|
|
|
char *optstr;
|
|
|
|
virCommandAddArg(cmd, "-device");
|
2013-08-02 17:48:50 +00:00
|
|
|
if (!(optstr = qemuBuildUSBInputDevStr(def, input, qemuCaps)))
|
2012-02-24 10:34:45 +00:00
|
|
|
goto error;
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, optstr);
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
} else {
|
2014-02-17 10:17:56 +00:00
|
|
|
switch (input->type) {
|
|
|
|
case VIR_DOMAIN_INPUT_TYPE_MOUSE:
|
|
|
|
virCommandAddArgList(cmd, "-usbdevice", "mouse", NULL);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_INPUT_TYPE_TABLET:
|
|
|
|
virCommandAddArgList(cmd, "-usbdevice", "tablet", NULL);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_INPUT_TYPE_KBD:
|
|
|
|
virCommandAddArgList(cmd, "-usbdevice", "keyboard", NULL);
|
|
|
|
break;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2015-11-13 10:38:07 +00:00
|
|
|
} else if (input->bus == VIR_DOMAIN_INPUT_BUS_VIRTIO) {
|
|
|
|
char *optstr;
|
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
if (!(optstr = qemuBuildVirtioInputDevStr(def, input, qemuCaps)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, optstr);
|
|
|
|
VIR_FREE(optstr);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < def->ngraphics; ++i) {
|
2013-02-01 13:48:58 +00:00
|
|
|
if (qemuBuildGraphicsCommandLine(cfg, cmd, def, qemuCaps,
|
2016-02-26 08:15:55 +00:00
|
|
|
def->graphics[i], domainLibDir) < 0)
|
2012-11-10 01:40:23 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2013-08-17 19:30:47 +00:00
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (def->nvideos > 0) {
|
2012-12-14 07:08:01 +00:00
|
|
|
int primaryVideoType = def->videos[0]->type;
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIDEO_PRIMARY) &&
|
2012-12-14 07:08:01 +00:00
|
|
|
((primaryVideoType == VIR_DOMAIN_VIDEO_TYPE_VGA &&
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VGA)) ||
|
2012-12-14 07:08:01 +00:00
|
|
|
(primaryVideoType == VIR_DOMAIN_VIDEO_TYPE_CIRRUS &&
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_CIRRUS_VGA)) ||
|
2012-12-14 07:08:01 +00:00
|
|
|
(primaryVideoType == VIR_DOMAIN_VIDEO_TYPE_VMVGA &&
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VMWARE_SVGA)) ||
|
2012-12-14 07:08:01 +00:00
|
|
|
(primaryVideoType == VIR_DOMAIN_VIDEO_TYPE_QXL &&
|
2015-11-25 08:42:32 +00:00
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_QXL_VGA)) ||
|
|
|
|
(primaryVideoType == VIR_DOMAIN_VIDEO_TYPE_VIRTIO &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIRTIO_GPU)))
|
|
|
|
) {
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < def->nvideos; i++) {
|
2012-12-14 07:08:01 +00:00
|
|
|
char *str;
|
|
|
|
virCommandAddArg(cmd, "-device");
|
2016-02-23 12:00:24 +00:00
|
|
|
if (!(str = qemuBuildDeviceVideoStr(def, def->videos[i],
|
|
|
|
qemuCaps)))
|
2012-12-14 07:08:01 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, str);
|
|
|
|
VIR_FREE(str);
|
|
|
|
}
|
2015-11-09 15:39:54 +00:00
|
|
|
} else {
|
2012-12-14 07:08:01 +00:00
|
|
|
if (primaryVideoType == VIR_DOMAIN_VIDEO_TYPE_XEN) {
|
2010-12-16 15:07:07 +00:00
|
|
|
/* nothing - vga has no effect on Xen pvfb */
|
|
|
|
} else {
|
2012-12-14 07:08:01 +00:00
|
|
|
if ((primaryVideoType == VIR_DOMAIN_VIDEO_TYPE_QXL) &&
|
2013-02-01 13:48:58 +00:00
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VGA_QXL)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("This QEMU does not support QXL graphics adapters"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-12-14 07:08:01 +00:00
|
|
|
const char *vgastr = qemuVideoTypeToString(primaryVideoType);
|
2010-12-16 15:07:07 +00:00
|
|
|
if (!vgastr || STREQ(vgastr, "")) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("video type %s is not supported with QEMU"),
|
2012-12-14 07:08:01 +00:00
|
|
|
virDomainVideoTypeToString(primaryVideoType));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArgList(cmd, "-vga", vgastr, NULL);
|
qemu: Support vram for video of qxl type
For qemu names the primary vga as "qxl-vga":
1) if vram is specified for 2nd qxl device:
-vga qxl -global qxl-vga.vram_size=$SIZE \
-device qxl,id=video1,vram_size=$SIZE,...
2) if vram is not specified for 2nd qxl device, (use the default
set by global):
-vga qxl -global qxl-vga.vram_size=$SIZE \
-device qxl,id=video1,...
For qemu names all qxl devices as "qxl":
1) if vram is specified for 2nd qxl device:
-vga qxl -global qxl.vram_size=$SIZE \
-device qxl,id=video1,vram_size=$SIZE ...
2) if vram is not specified for 2nd qxl device:
-vga qxl -global qxl-vga.vram_size=$SIZE \
-device qxl,id=video1,...
"-global" is the only way to define vram_size for the primary qxl
device, regardless of how qemu names it, (It's not good a good
way, as original idea of "-global" is to set a global default for
a driver property, but to specify vram for first qxl device, we
have to use it).
For other qxl devices, as they are represented by "-device", could
specify it directly and seperately for each, and it overrides the
default set by "-global" if specified.
v1 - v2:
* modify "virDomainVideoDefaultRAM" so that it returns 16M as the
default vram_size for qxl device.
* vram_size * 1024 (qemu accepts bytes for vram_size).
* apply default vram_size for qxl device for which vram_size is
not specified.
* modify "graphics-spice" tests (more sensiable vram_size)
* Add an argument of virDomainDefPtr type for qemuBuildVideoDevStr,
to use virDomainVideoDefaultRAM in qemuBuildVideoDevStr).
v2 - v3:
* Modify default video memory size for qxl device from 16M to 24M
* Update codes to be consistent with changes on qemu_capabilities.*
2011-03-06 14:00:27 +00:00
|
|
|
|
2014-11-18 16:21:48 +00:00
|
|
|
/* If we cannot use --device option to specify the video device
|
|
|
|
* in QEMU we will fallback to the old --vga option. To get the
|
|
|
|
* correct device name for the --vga option the 'qemuVideo' is
|
|
|
|
* used, but to set some device attributes we need to use the
|
|
|
|
* --global option and for that we need to specify the device
|
|
|
|
* name the same as for --device option and for that we need to
|
|
|
|
* use 'qemuDeviceVideo'.
|
|
|
|
*
|
|
|
|
* See 'Graphics Devices' section in docs/qdev-device-use.txt in
|
|
|
|
* QEMU repository.
|
|
|
|
*/
|
|
|
|
const char *dev = qemuDeviceVideoTypeToString(primaryVideoType);
|
|
|
|
|
2013-01-18 18:36:36 +00:00
|
|
|
if (def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_QXL &&
|
|
|
|
(def->videos[0]->vram || def->videos[0]->ram) &&
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
2014-11-24 10:58:53 +00:00
|
|
|
unsigned int ram = def->videos[0]->ram;
|
|
|
|
unsigned int vram = def->videos[0]->vram;
|
2016-02-23 16:04:19 +00:00
|
|
|
unsigned int vram64 = def->videos[0]->vram64;
|
2014-11-20 18:52:00 +00:00
|
|
|
unsigned int vgamem = def->videos[0]->vgamem;
|
2013-01-18 18:36:36 +00:00
|
|
|
|
|
|
|
if (vram > (UINT_MAX / 1024)) {
|
|
|
|
virReportError(VIR_ERR_OVERFLOW,
|
|
|
|
_("value for 'vram' must be less than '%u'"),
|
|
|
|
UINT_MAX / 1024);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (ram > (UINT_MAX / 1024)) {
|
|
|
|
virReportError(VIR_ERR_OVERFLOW,
|
|
|
|
_("value for 'ram' must be less than '%u'"),
|
|
|
|
UINT_MAX / 1024);
|
|
|
|
goto error;
|
|
|
|
}
|
2011-03-15 03:50:09 +00:00
|
|
|
|
2013-01-18 18:36:36 +00:00
|
|
|
if (ram) {
|
2011-03-11 16:59:32 +00:00
|
|
|
virCommandAddArg(cmd, "-global");
|
2013-01-18 18:36:36 +00:00
|
|
|
virCommandAddArgFormat(cmd, "%s.ram_size=%u",
|
|
|
|
dev, ram * 1024);
|
|
|
|
}
|
|
|
|
if (vram) {
|
|
|
|
virCommandAddArg(cmd, "-global");
|
|
|
|
virCommandAddArgFormat(cmd, "%s.vram_size=%u",
|
|
|
|
dev, vram * 1024);
|
qemu: Support vram for video of qxl type
For qemu names the primary vga as "qxl-vga":
1) if vram is specified for 2nd qxl device:
-vga qxl -global qxl-vga.vram_size=$SIZE \
-device qxl,id=video1,vram_size=$SIZE,...
2) if vram is not specified for 2nd qxl device, (use the default
set by global):
-vga qxl -global qxl-vga.vram_size=$SIZE \
-device qxl,id=video1,...
For qemu names all qxl devices as "qxl":
1) if vram is specified for 2nd qxl device:
-vga qxl -global qxl.vram_size=$SIZE \
-device qxl,id=video1,vram_size=$SIZE ...
2) if vram is not specified for 2nd qxl device:
-vga qxl -global qxl-vga.vram_size=$SIZE \
-device qxl,id=video1,...
"-global" is the only way to define vram_size for the primary qxl
device, regardless of how qemu names it, (It's not good a good
way, as original idea of "-global" is to set a global default for
a driver property, but to specify vram for first qxl device, we
have to use it).
For other qxl devices, as they are represented by "-device", could
specify it directly and seperately for each, and it overrides the
default set by "-global" if specified.
v1 - v2:
* modify "virDomainVideoDefaultRAM" so that it returns 16M as the
default vram_size for qxl device.
* vram_size * 1024 (qemu accepts bytes for vram_size).
* apply default vram_size for qxl device for which vram_size is
not specified.
* modify "graphics-spice" tests (more sensiable vram_size)
* Add an argument of virDomainDefPtr type for qemuBuildVideoDevStr,
to use virDomainVideoDefaultRAM in qemuBuildVideoDevStr).
v2 - v3:
* Modify default video memory size for qxl device from 16M to 24M
* Update codes to be consistent with changes on qemu_capabilities.*
2011-03-06 14:00:27 +00:00
|
|
|
}
|
2016-02-23 16:04:19 +00:00
|
|
|
if (vram64 &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_QXL_VGA_VRAM64)) {
|
|
|
|
virCommandAddArg(cmd, "-global");
|
|
|
|
virCommandAddArgFormat(cmd, "%s.vram64_size_mb=%u",
|
|
|
|
dev, vram64 / 1024);
|
|
|
|
}
|
2014-11-20 18:52:00 +00:00
|
|
|
if (vgamem &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_QXL_VGA_VGAMEM)) {
|
|
|
|
virCommandAddArg(cmd, "-global");
|
|
|
|
virCommandAddArgFormat(cmd, "%s.vgamem_mb=%u",
|
|
|
|
dev, vgamem / 1024);
|
|
|
|
}
|
qemu: Support vram for video of qxl type
For qemu names the primary vga as "qxl-vga":
1) if vram is specified for 2nd qxl device:
-vga qxl -global qxl-vga.vram_size=$SIZE \
-device qxl,id=video1,vram_size=$SIZE,...
2) if vram is not specified for 2nd qxl device, (use the default
set by global):
-vga qxl -global qxl-vga.vram_size=$SIZE \
-device qxl,id=video1,...
For qemu names all qxl devices as "qxl":
1) if vram is specified for 2nd qxl device:
-vga qxl -global qxl.vram_size=$SIZE \
-device qxl,id=video1,vram_size=$SIZE ...
2) if vram is not specified for 2nd qxl device:
-vga qxl -global qxl-vga.vram_size=$SIZE \
-device qxl,id=video1,...
"-global" is the only way to define vram_size for the primary qxl
device, regardless of how qemu names it, (It's not good a good
way, as original idea of "-global" is to set a global default for
a driver property, but to specify vram for first qxl device, we
have to use it).
For other qxl devices, as they are represented by "-device", could
specify it directly and seperately for each, and it overrides the
default set by "-global" if specified.
v1 - v2:
* modify "virDomainVideoDefaultRAM" so that it returns 16M as the
default vram_size for qxl device.
* vram_size * 1024 (qemu accepts bytes for vram_size).
* apply default vram_size for qxl device for which vram_size is
not specified.
* modify "graphics-spice" tests (more sensiable vram_size)
* Add an argument of virDomainDefPtr type for qemuBuildVideoDevStr,
to use virDomainVideoDefaultRAM in qemuBuildVideoDevStr).
v2 - v3:
* Modify default video memory size for qxl device from 16M to 24M
* Update codes to be consistent with changes on qemu_capabilities.*
2011-03-06 14:00:27 +00:00
|
|
|
}
|
2014-11-20 18:51:12 +00:00
|
|
|
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE) &&
|
|
|
|
def->videos[0]->vram &&
|
|
|
|
((primaryVideoType == VIR_DOMAIN_VIDEO_TYPE_VGA &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_VGA_VGAMEM)) ||
|
|
|
|
(primaryVideoType == VIR_DOMAIN_VIDEO_TYPE_VMVGA &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_VMWARE_SVGA_VGAMEM)))) {
|
|
|
|
unsigned int vram = def->videos[0]->vram;
|
|
|
|
|
|
|
|
if (vram < 1024) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("value for 'vgamem' must be at "
|
|
|
|
"least 1 MiB (1024 KiB)"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-global");
|
|
|
|
virCommandAddArgFormat(cmd, "%s.vgamem_mb=%u",
|
|
|
|
dev, vram / 1024);
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-12-14 07:08:01 +00:00
|
|
|
|
|
|
|
if (def->nvideos > 1) {
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 1; i < def->nvideos; i++) {
|
2012-12-14 07:08:01 +00:00
|
|
|
char *str;
|
|
|
|
if (def->videos[i]->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("video type %s is only valid as primary video card"),
|
|
|
|
virDomainVideoTypeToString(def->videos[0]->type));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
|
2016-02-23 12:00:24 +00:00
|
|
|
if (!(str = qemuBuildDeviceVideoStr(def, def->videos[i],
|
|
|
|
qemuCaps)))
|
2012-12-14 07:08:01 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, str);
|
|
|
|
VIR_FREE(str);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("only one video card is currently supported"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/* If we have -device, then we set -nodefault already */
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE) &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_VGA_NONE))
|
2010-12-16 15:07:07 +00:00
|
|
|
virCommandAddArgList(cmd, "-vga", "none", NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add sound hardware */
|
|
|
|
if (def->nsounds) {
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < def->nsounds; i++) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virDomainSoundDefPtr sound = def->sounds[i];
|
|
|
|
char *str = NULL;
|
|
|
|
|
|
|
|
/* Sadly pcspk device doesn't use -device syntax. Fortunately
|
|
|
|
* we don't need to set any PCI address on it, so we don't
|
|
|
|
* mind too much */
|
|
|
|
if (sound->model == VIR_DOMAIN_SOUND_MODEL_PCSPK) {
|
|
|
|
virCommandAddArgList(cmd, "-soundhw", "pcspk", NULL);
|
|
|
|
} else {
|
|
|
|
virCommandAddArg(cmd, "-device");
|
2013-08-02 17:48:50 +00:00
|
|
|
if (!(str = qemuBuildSoundDevStr(def, sound, qemuCaps)))
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, str);
|
2013-09-24 15:26:18 +00:00
|
|
|
VIR_FREE(str);
|
2013-09-24 14:17:38 +00:00
|
|
|
if (sound->model == VIR_DOMAIN_SOUND_MODEL_ICH6 ||
|
|
|
|
sound->model == VIR_DOMAIN_SOUND_MODEL_ICH9) {
|
2011-01-13 14:15:11 +00:00
|
|
|
char *codecstr = NULL;
|
|
|
|
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
for (j = 0; j < sound->ncodecs; j++) {
|
2012-05-15 22:55:10 +00:00
|
|
|
virCommandAddArg(cmd, "-device");
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
if (!(codecstr = qemuBuildSoundCodecStr(sound, sound->codecs[j], qemuCaps))) {
|
2012-05-15 22:55:10 +00:00
|
|
|
goto error;
|
2011-01-13 14:15:11 +00:00
|
|
|
|
2012-05-15 22:55:10 +00:00
|
|
|
}
|
|
|
|
virCommandAddArg(cmd, codecstr);
|
|
|
|
VIR_FREE(codecstr);
|
|
|
|
}
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
if (j == 0) {
|
2012-05-15 22:55:10 +00:00
|
|
|
virDomainSoundCodecDef codec = {
|
|
|
|
VIR_DOMAIN_SOUND_CODEC_TYPE_DUPLEX,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
virCommandAddArg(cmd, "-device");
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!(codecstr = qemuBuildSoundCodecStr(sound, &codec, qemuCaps))) {
|
2012-05-15 22:55:10 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
}
|
|
|
|
virCommandAddArg(cmd, codecstr);
|
|
|
|
VIR_FREE(codecstr);
|
|
|
|
}
|
2011-01-13 14:15:11 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int size = 100;
|
|
|
|
char *modstr;
|
2013-07-04 10:14:12 +00:00
|
|
|
if (VIR_ALLOC_N(modstr, size+1) < 0)
|
2013-05-20 09:23:13 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < def->nsounds && size > 0; i++) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virDomainSoundDefPtr sound = def->sounds[i];
|
|
|
|
const char *model = virDomainSoundModelTypeToString(sound->model);
|
|
|
|
if (!model) {
|
|
|
|
VIR_FREE(modstr);
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("invalid sound model"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2011-01-13 14:15:11 +00:00
|
|
|
|
2013-09-24 14:17:38 +00:00
|
|
|
if (sound->model == VIR_DOMAIN_SOUND_MODEL_ICH6 ||
|
|
|
|
sound->model == VIR_DOMAIN_SOUND_MODEL_ICH9) {
|
2011-10-29 17:12:56 +00:00
|
|
|
VIR_FREE(modstr);
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("this QEMU binary lacks hda support"));
|
2011-01-13 14:15:11 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
strncat(modstr, model, size);
|
|
|
|
size -= strlen(model);
|
|
|
|
if (i < (def->nsounds - 1))
|
|
|
|
strncat(modstr, ",", size--);
|
|
|
|
}
|
|
|
|
virCommandAddArgList(cmd, "-soundhw", modstr, NULL);
|
|
|
|
VIR_FREE(modstr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add watchdog hardware */
|
|
|
|
if (def->watchdog) {
|
|
|
|
virDomainWatchdogDefPtr watchdog = def->watchdog;
|
|
|
|
char *optstr;
|
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
|
2013-08-02 17:48:50 +00:00
|
|
|
optstr = qemuBuildWatchdogDevStr(def, watchdog, qemuCaps);
|
2010-12-16 15:07:07 +00:00
|
|
|
if (!optstr)
|
|
|
|
goto error;
|
|
|
|
} else {
|
|
|
|
virCommandAddArg(cmd, "-watchdog");
|
|
|
|
|
|
|
|
const char *model = virDomainWatchdogModelTypeToString(watchdog->model);
|
|
|
|
if (!model) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("missing watchdog model"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2013-05-20 09:23:13 +00:00
|
|
|
if (VIR_STRDUP(optstr, model) < 0)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
virCommandAddArg(cmd, optstr);
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
|
|
|
|
int act = watchdog->action;
|
|
|
|
if (act == VIR_DOMAIN_WATCHDOG_ACTION_DUMP)
|
|
|
|
act = VIR_DOMAIN_WATCHDOG_ACTION_PAUSE;
|
|
|
|
const char *action = virDomainWatchdogActionTypeToString(act);
|
|
|
|
if (!action) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("invalid watchdog action"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virCommandAddArgList(cmd, "-watchdog-action", action, NULL);
|
|
|
|
}
|
|
|
|
|
2011-09-02 15:09:14 +00:00
|
|
|
/* Add redirected devices */
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < def->nredirdevs; i++) {
|
2011-09-02 15:09:14 +00:00
|
|
|
virDomainRedirdevDefPtr redirdev = def->redirdevs[i];
|
|
|
|
char *devstr;
|
|
|
|
|
2016-02-23 13:05:09 +00:00
|
|
|
if (!(devstr = qemuBuildChrChardevStr(logManager, cmd, def,
|
|
|
|
&redirdev->source.chr,
|
2011-09-02 15:09:14 +00:00
|
|
|
redirdev->info.alias,
|
2013-02-01 13:48:58 +00:00
|
|
|
qemuCaps))) {
|
2011-09-02 15:09:14 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2016-02-29 12:21:14 +00:00
|
|
|
virCommandAddArg(cmd, "-chardev");
|
2011-09-02 15:09:14 +00:00
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
|
2014-12-16 15:29:00 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("redirected devices are not supported by this QEMU"));
|
2011-09-02 15:09:14 +00:00
|
|
|
goto error;
|
2014-12-16 15:29:00 +00:00
|
|
|
}
|
|
|
|
|
2011-09-02 15:09:14 +00:00
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-device");
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!(devstr = qemuBuildRedirdevDevStr(def, redirdev, qemuCaps)))
|
2011-09-02 15:09:14 +00:00
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
/* Add host passthrough hardware */
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < def->nhostdevs; i++) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virDomainHostdevDefPtr hostdev = def->hostdevs[i];
|
|
|
|
char *devstr;
|
|
|
|
|
2012-01-31 09:16:54 +00:00
|
|
|
if (hostdev->info->bootIndex) {
|
2011-02-03 14:09:17 +00:00
|
|
|
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
|
2012-11-14 14:51:30 +00:00
|
|
|
(hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB &&
|
|
|
|
hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2013-04-25 11:58:37 +00:00
|
|
|
_("booting from assigned devices is only "
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
"supported for PCI, USB and SCSI devices"));
|
2011-02-03 14:09:17 +00:00
|
|
|
goto error;
|
2012-11-14 14:51:30 +00:00
|
|
|
} else {
|
2013-04-25 11:58:37 +00:00
|
|
|
if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
|
|
|
|
if (hostdev->source.subsys.u.pci.backend
|
2013-04-26 20:44:05 +00:00
|
|
|
== VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
|
2013-04-25 11:58:37 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VFIO_PCI_BOOTINDEX)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("booting from PCI devices assigned with VFIO "
|
|
|
|
"is not supported with this version of qemu"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_BOOTINDEX)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("booting from assigned PCI devices is not "
|
|
|
|
"supported with this version of qemu"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
2012-11-14 14:51:30 +00:00
|
|
|
}
|
|
|
|
if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB &&
|
2013-02-01 13:48:58 +00:00
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_USB_HOST_BOOTINDEX)) {
|
2012-11-14 14:51:30 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2013-04-25 11:58:37 +00:00
|
|
|
_("booting from assigned USB devices is not "
|
|
|
|
"supported with this version of qemu"));
|
2012-11-14 14:51:30 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2013-05-03 18:07:26 +00:00
|
|
|
if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
|
|
|
|
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC_BOOTINDEX)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("booting from assigned SCSI devices is not"
|
|
|
|
" supported with this version of qemu"));
|
|
|
|
goto error;
|
|
|
|
}
|
2011-02-03 14:09:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
/* USB */
|
|
|
|
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
|
|
|
hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
|
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virCommandAddArg(cmd, "-device");
|
2013-08-02 17:48:50 +00:00
|
|
|
if (!(devstr = qemuBuildUSBHostdevDevStr(def, hostdev, qemuCaps)))
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
} else {
|
|
|
|
virCommandAddArg(cmd, "-usbdevice");
|
2014-03-13 11:58:17 +00:00
|
|
|
if (!(devstr = qemuBuildUSBHostdevUSBDevStr(hostdev)))
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* PCI */
|
|
|
|
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
|
|
|
hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
|
2013-09-19 14:48:23 +00:00
|
|
|
int backend = hostdev->source.subsys.u.pci.backend;
|
2013-04-25 11:58:37 +00:00
|
|
|
|
2013-09-19 14:48:23 +00:00
|
|
|
if (backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
|
2013-04-25 16:45:55 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("VFIO PCI device assignment is not "
|
|
|
|
"supported by this version of qemu"));
|
|
|
|
goto error;
|
|
|
|
}
|
2013-04-25 11:58:37 +00:00
|
|
|
}
|
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
char *configfd_name = NULL;
|
qemu: add bootindex option to hostdev network interface commandline
when appropriate, of course. If the config for a domain specifies boot
order with <boot dev='blah'/> elements, e.g.:
<os>
...
<boot dev='hd'/>
<boot dev='network'/>
</os>
Then the first disk device in the config will have ",bootindex=1"
appended to its qemu commandline -device options, and the first (and
*only* the first) network interface device will get ",bootindex=2".
However, if the first network interface device is a "hostdev" device
(an SRIOV Virtual Function (VF) being assigned to the domain with
vfio), then the bootindex option will *not* be appended. This happens
because the bootindex=n option corresponding to the order of "<boot
dev='network'/>" is added to the -device for the first network device
when network device commandline args are constructed, but if it's a
hostdev network device, its commandline arg is instead constructed in
the loop for hostdevs.
This patch fixes that omission by noticing (in bootHostdevNet) if the
first network device was a hostdev, and if so passing on the proper
bootindex to the commandline generator for hostdev devices - the
result is that ",bootindex=2" will be properly appended to the first
"network" device in the config even if it is really a hostdev
(including if it is assigned from a libvirt network pool). (note that
this is only the case if there is no <bootmenu enabled='yes'/> element
in the config ("-boot menu-on" in qemu) , since the two are mutually
exclusive - when the bootmenu is enabled, the individual per-device
bootindex options can't be used by qemu, and we revert to using "-boot
order=xyz" instead).
If a greater level of control over boot order is desired (e.g., more
than one network device should be tried, or a network device other
than the first one encountered in the config), then <boot
dev='network'/> in the <os> element should not be used; instead, the
individual device elements in the config should be given a "<boot
order='n'/>
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1278421
2015-11-30 22:40:44 +00:00
|
|
|
int bootIndex = hostdev->info->bootIndex;
|
|
|
|
|
|
|
|
/* bootNet will be non-0 if boot order was set and no other
|
|
|
|
* net devices were encountered
|
|
|
|
*/
|
|
|
|
if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
|
|
|
|
bootIndex == 0) {
|
|
|
|
bootIndex = bootHostdevNet;
|
|
|
|
bootHostdevNet = 0;
|
|
|
|
}
|
2013-09-19 14:48:23 +00:00
|
|
|
if ((backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) &&
|
2013-04-25 11:58:37 +00:00
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCI_CONFIGFD)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
int configfd = qemuOpenPCIConfig(hostdev);
|
|
|
|
|
|
|
|
if (configfd >= 0) {
|
|
|
|
if (virAsprintf(&configfd_name, "%d", configfd) < 0) {
|
|
|
|
VIR_FORCE_CLOSE(configfd);
|
2013-05-20 09:23:13 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2013-07-11 10:31:56 +00:00
|
|
|
virCommandPassFD(cmd, configfd,
|
|
|
|
VIR_COMMAND_PASS_FD_CLOSE_PARENT);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
virCommandAddArg(cmd, "-device");
|
qemu: add bootindex option to hostdev network interface commandline
when appropriate, of course. If the config for a domain specifies boot
order with <boot dev='blah'/> elements, e.g.:
<os>
...
<boot dev='hd'/>
<boot dev='network'/>
</os>
Then the first disk device in the config will have ",bootindex=1"
appended to its qemu commandline -device options, and the first (and
*only* the first) network interface device will get ",bootindex=2".
However, if the first network interface device is a "hostdev" device
(an SRIOV Virtual Function (VF) being assigned to the domain with
vfio), then the bootindex option will *not* be appended. This happens
because the bootindex=n option corresponding to the order of "<boot
dev='network'/>" is added to the -device for the first network device
when network device commandline args are constructed, but if it's a
hostdev network device, its commandline arg is instead constructed in
the loop for hostdevs.
This patch fixes that omission by noticing (in bootHostdevNet) if the
first network device was a hostdev, and if so passing on the proper
bootindex to the commandline generator for hostdev devices - the
result is that ",bootindex=2" will be properly appended to the first
"network" device in the config even if it is really a hostdev
(including if it is assigned from a libvirt network pool). (note that
this is only the case if there is no <bootmenu enabled='yes'/> element
in the config ("-boot menu-on" in qemu) , since the two are mutually
exclusive - when the bootmenu is enabled, the individual per-device
bootindex options can't be used by qemu, and we revert to using "-boot
order=xyz" instead).
If a greater level of control over boot order is desired (e.g., more
than one network device should be tried, or a network device other
than the first one encountered in the config), then <boot
dev='network'/> in the <os> element should not be used; instead, the
individual device elements in the config should be given a "<boot
order='n'/>
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1278421
2015-11-30 22:40:44 +00:00
|
|
|
devstr = qemuBuildPCIHostdevDevStr(def, hostdev, bootIndex,
|
|
|
|
configfd_name, qemuCaps);
|
2010-12-16 15:07:07 +00:00
|
|
|
VIR_FREE(configfd_name);
|
|
|
|
if (!devstr)
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
2013-02-01 13:48:58 +00:00
|
|
|
} else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCIDEVICE)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virCommandAddArg(cmd, "-pcidevice");
|
2014-04-30 11:32:19 +00:00
|
|
|
if (!(devstr = qemuBuildPCIHostdevPCIDevStr(hostdev, qemuCaps)))
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
} else {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("PCI device assignment is not supported by this version of qemu"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
|
|
|
|
/* SCSI */
|
|
|
|
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
|
|
|
hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) {
|
2015-11-06 14:28:57 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE) &&
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) {
|
|
|
|
char *drvstr;
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-drive");
|
2014-07-10 15:16:15 +00:00
|
|
|
if (!(drvstr = qemuBuildSCSIHostdevDrvStr(conn, hostdev, qemuCaps, callbacks)))
|
qemu: Build qemu command line for scsi host device
Except the scsi host device's controller is "lsilogic", mapping
between the libvirt attributes and scsi-generic properties is:
libvirt qemu
-----------------------------------------
controller bus ($libvirt_controller.0)
bus channel
target scsi-id
unit lun
For scsi host device with "lsilogic" controller, the mapping is:
('target (libvirt)' must be 0, as it's not used; 'unit (libvirt)
must <= 7).
libvirt qemu
----------------------------------------------------------
controller && bus bus ($libvirt_controller.$libvirt_bus)
unit scsi-id
It's not good to hardcode/hard-check limits of these attributes,
and even worse, these limits are not documented, one has to find
out by either testing or reading the qemu code, I'm looking forward
to qemu expose limits like these one day). For example, exposing
"max_target", "max_lun" for megasas:
static const struct SCSIBusInfo megasas_scsi_info = {
.tcq = true,
.max_target = MFI_MAX_LD,
.max_lun = 255,
.transfer_data = megasas_xfer_complete,
.get_sg_list = megasas_get_sg_list,
.complete = megasas_command_complete,
.cancel = megasas_command_cancel,
};
Example of the qemu command line (lsilogic controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,scsi-id=8,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Example of the qemu command line (virtio-scsi controller):
-drive file=/dev/sg2,if=none,id=drive-hostdev-scsi_host7-0-0-0 \
-device scsi-generic,bus=scsi0.0,channel=0,scsi-id=128,lun=128,\
drive=drive-hostdev-scsi_host7-0-0-0,id=hostdev-scsi_host7-0-0-0
Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang@redhat.com>
2013-05-03 18:07:23 +00:00
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, drvstr);
|
|
|
|
VIR_FREE(drvstr);
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
if (!(devstr = qemuBuildSCSIHostdevDevStr(def, hostdev, qemuCaps)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("SCSI passthrough is not supported by this version of qemu"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2015-10-20 11:51:01 +00:00
|
|
|
if (migrateURI)
|
2015-10-16 15:01:39 +00:00
|
|
|
virCommandAddArgList(cmd, "-incoming", migrateURI, NULL);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
/* QEMU changed its default behavior to not include the virtio balloon
|
|
|
|
* device. Explicitly request it to ensure it will be present.
|
|
|
|
*
|
|
|
|
* NB: Earlier we declared that VirtIO balloon will always be in
|
|
|
|
* slot 0x3 on bus 0x0
|
|
|
|
*/
|
2013-03-05 15:44:21 +00:00
|
|
|
if (STREQLEN(def->os.machine, "s390-virtio", 10) &&
|
|
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_S390) && def->memballoon)
|
2013-01-11 15:30:07 +00:00
|
|
|
def->memballoon->model = VIR_DOMAIN_MEMBALLOON_MODEL_NONE;
|
|
|
|
|
|
|
|
if (def->memballoon &&
|
|
|
|
def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE) {
|
2010-12-16 15:07:07 +00:00
|
|
|
if (def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Memory balloon device type '%s' is not supported by this version of qemu"),
|
|
|
|
virDomainMemballoonModelTypeToString(def->memballoon->model));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
char *optstr;
|
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
|
2013-08-02 17:48:50 +00:00
|
|
|
optstr = qemuBuildMemballoonDevStr(def, def->memballoon, qemuCaps);
|
2010-12-16 15:07:07 +00:00
|
|
|
if (!optstr)
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, optstr);
|
|
|
|
VIR_FREE(optstr);
|
2013-02-01 13:48:58 +00:00
|
|
|
} else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BALLOON)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virCommandAddArgList(cmd, "-balloon", "virtio", NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-25 22:31:11 +00:00
|
|
|
for (i = 0; i < def->nrngs; i++) {
|
2015-02-03 09:31:33 +00:00
|
|
|
virDomainRNGDefPtr rng = def->rngs[i];
|
|
|
|
char *tmp;
|
|
|
|
|
|
|
|
if (!rng->info.alias) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("RNG device is missing alias"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* possibly add character device for backend */
|
2016-02-23 13:05:09 +00:00
|
|
|
if (qemuBuildRNGBackendChrdevStr(logManager, cmd, def,
|
|
|
|
rng, qemuCaps, &tmp) < 0)
|
2015-02-03 09:31:33 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (tmp) {
|
|
|
|
virCommandAddArgList(cmd, "-chardev", tmp, NULL);
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
}
|
|
|
|
|
2013-01-11 16:48:21 +00:00
|
|
|
/* add the RNG source backend */
|
2015-02-03 09:31:33 +00:00
|
|
|
if (!(tmp = qemuBuildRNGBackendStr(rng, qemuCaps)))
|
2013-01-11 16:48:21 +00:00
|
|
|
goto error;
|
|
|
|
|
2015-02-03 09:31:33 +00:00
|
|
|
virCommandAddArgList(cmd, "-object", tmp, NULL);
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
|
2013-01-11 16:48:21 +00:00
|
|
|
/* add the device */
|
2015-02-03 09:31:33 +00:00
|
|
|
if (!(tmp = qemuBuildRNGDevStr(def, rng, qemuCaps)))
|
2013-01-11 16:48:21 +00:00
|
|
|
goto error;
|
2015-02-03 09:31:33 +00:00
|
|
|
virCommandAddArgList(cmd, "-device", tmp, NULL);
|
|
|
|
VIR_FREE(tmp);
|
2013-01-11 16:48:21 +00:00
|
|
|
}
|
|
|
|
|
2013-04-25 08:46:04 +00:00
|
|
|
if (def->nvram) {
|
2014-11-04 17:21:26 +00:00
|
|
|
if (ARCH_IS_PPC64(def->os.arch) &&
|
2014-09-13 15:28:58 +00:00
|
|
|
STRPREFIX(def->os.machine, "pseries")) {
|
2013-04-25 08:46:04 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_NVRAM)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("nvram device is not supported by "
|
|
|
|
"this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *optstr;
|
|
|
|
virCommandAddArg(cmd, "-global");
|
|
|
|
optstr = qemuBuildNVRAMDevStr(def->nvram);
|
|
|
|
if (!optstr)
|
|
|
|
goto error;
|
|
|
|
if (optstr)
|
|
|
|
virCommandAddArg(cmd, optstr);
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("nvram device is only supported for PPC64"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
2011-08-25 20:44:48 +00:00
|
|
|
if (snapshot)
|
|
|
|
virCommandAddArgList(cmd, "-loadvm", snapshot->def->name, NULL);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (def->namespaceData) {
|
|
|
|
qemuDomainCmdlineDefPtr qemucmd;
|
|
|
|
|
|
|
|
qemucmd = def->namespaceData;
|
|
|
|
for (i = 0; i < qemucmd->num_args; i++)
|
|
|
|
virCommandAddArg(cmd, qemucmd->args[i]);
|
|
|
|
for (i = 0; i < qemucmd->num_env; i++)
|
|
|
|
virCommandAddEnvPair(cmd, qemucmd->env_name[i],
|
|
|
|
qemucmd->env_value[i]
|
|
|
|
? qemucmd->env_value[i] : "");
|
|
|
|
}
|
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SECCOMP_SANDBOX)) {
|
2013-01-10 21:03:14 +00:00
|
|
|
if (cfg->seccompSandbox == 0)
|
2012-09-17 07:59:54 +00:00
|
|
|
virCommandAddArgList(cmd, "-sandbox", "off", NULL);
|
2013-01-10 21:03:14 +00:00
|
|
|
else if (cfg->seccompSandbox > 0)
|
2012-09-17 07:59:54 +00:00
|
|
|
virCommandAddArgList(cmd, "-sandbox", "on", NULL);
|
2013-01-10 21:03:14 +00:00
|
|
|
} else if (cfg->seccompSandbox > 0) {
|
2012-09-17 07:59:54 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("QEMU does not support seccomp sandboxes"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2015-11-24 12:26:36 +00:00
|
|
|
for (i = 0; i < def->npanics; i++) {
|
|
|
|
switch ((virDomainPanicModel) def->panics[i]->model) {
|
2015-11-24 12:26:33 +00:00
|
|
|
case VIR_DOMAIN_PANIC_MODEL_HYPERV:
|
|
|
|
/* Panic with model 'hyperv' is not a device, it should
|
|
|
|
* be configured in cpu commandline. The address
|
|
|
|
* cannot be configured by the user */
|
|
|
|
if (!ARCH_IS_X86(def->os.arch)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("only i686 and x86_64 guests support "
|
|
|
|
"panic device of model 'hyperv'"));
|
|
|
|
goto error;
|
|
|
|
}
|
2015-11-24 12:26:36 +00:00
|
|
|
if (def->panics[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
|
2015-11-24 12:26:33 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("setting the panic device address is not "
|
|
|
|
"supported for model 'hyperv'"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_PANIC_MODEL_PSERIES:
|
2015-05-28 14:39:12 +00:00
|
|
|
/* For pSeries guests, the firmware provides the same
|
|
|
|
* functionality as the pvpanic device. The address
|
|
|
|
* cannot be configured by the user */
|
2015-11-24 12:26:33 +00:00
|
|
|
if (!ARCH_IS_PPC64(def->os.arch) ||
|
|
|
|
!STRPREFIX(def->os.machine, "pseries")) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("only pSeries guests support panic device "
|
|
|
|
"of model 'pseries'"));
|
|
|
|
goto error;
|
|
|
|
}
|
2015-11-24 12:26:36 +00:00
|
|
|
if (def->panics[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
|
2015-05-28 14:39:12 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("setting the panic device address is not "
|
2015-11-24 12:26:33 +00:00
|
|
|
"supported for model 'pseries'"));
|
2015-05-28 14:39:12 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2015-11-24 12:26:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_PANIC_MODEL_ISA:
|
2015-05-28 14:39:12 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PANIC)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("the QEMU binary does not support the "
|
|
|
|
"panic device"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2015-11-24 12:26:36 +00:00
|
|
|
switch (def->panics[i]->info.type) {
|
2015-05-28 14:39:12 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA:
|
2013-12-09 09:11:15 +00:00
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
virCommandAddArgFormat(cmd, "pvpanic,ioport=%d",
|
2015-11-24 12:26:36 +00:00
|
|
|
def->panics[i]->info.addr.isa.iobase);
|
2015-05-28 14:39:12 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE:
|
2013-12-09 09:11:15 +00:00
|
|
|
virCommandAddArgList(cmd, "-device", "pvpanic", NULL);
|
2015-05-28 14:39:12 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2014-09-08 10:27:23 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("panic is supported only "
|
|
|
|
"with ISA address type"));
|
|
|
|
goto error;
|
2013-12-09 09:11:15 +00:00
|
|
|
}
|
2015-11-24 12:26:33 +00:00
|
|
|
|
|
|
|
/* default model value was changed before in post parse */
|
|
|
|
case VIR_DOMAIN_PANIC_MODEL_DEFAULT:
|
|
|
|
case VIR_DOMAIN_PANIC_MODEL_LAST:
|
|
|
|
break;
|
2013-12-09 09:11:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-25 07:00:47 +00:00
|
|
|
for (i = 0; i < def->nshmems; i++) {
|
2016-02-23 13:05:09 +00:00
|
|
|
if (qemuBuildShmemCommandLine(logManager, cmd,
|
|
|
|
def, def->shmems[i], qemuCaps))
|
2014-09-25 07:00:47 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2015-11-12 15:32:53 +00:00
|
|
|
/* In some situations, eg. VFIO passthrough, QEMU might need to lock a
|
|
|
|
* significant amount of memory, so we need to set the limit accordingly */
|
2015-11-24 12:51:11 +00:00
|
|
|
if (qemuDomainRequiresMemLock(def))
|
|
|
|
virCommandSetMaxMemLock(cmd, qemuDomainGetMemLockLimitBytes(def));
|
2013-06-28 14:54:38 +00:00
|
|
|
|
2014-04-09 13:23:45 +00:00
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_MSG_TIMESTAMP) &&
|
|
|
|
cfg->logTimestamp)
|
|
|
|
virCommandAddArgList(cmd, "-msg", "timestamp=on", NULL);
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
virObjectUnref(cfg);
|
2010-12-16 15:07:07 +00:00
|
|
|
return cmd;
|
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2013-01-10 21:03:14 +00:00
|
|
|
virObjectUnref(cfg);
|
2013-04-24 12:06:40 +00:00
|
|
|
/* free up any resources in the network driver
|
|
|
|
* but don't overwrite the original error */
|
|
|
|
originalError = virSaveLastError();
|
|
|
|
virSetError(originalError);
|
2013-04-29 11:52:49 +00:00
|
|
|
virFreeError(originalError);
|
2010-12-16 15:07:07 +00:00
|
|
|
virCommandFree(cmd);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-11-21 12:50:42 +00:00
|
|
|
/* This function generates the correct '-device' string for character
|
|
|
|
* devices of each architecture.
|
|
|
|
*/
|
2013-03-13 15:20:34 +00:00
|
|
|
static int
|
|
|
|
qemuBuildSerialChrDeviceStr(char **deviceStr,
|
2013-08-02 17:48:50 +00:00
|
|
|
virDomainDefPtr def,
|
2013-03-13 15:20:34 +00:00
|
|
|
virDomainChrDefPtr serial,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
virArch arch,
|
|
|
|
char *machine)
|
2011-11-21 12:50:42 +00:00
|
|
|
{
|
|
|
|
virBuffer cmd = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
2014-11-04 17:21:26 +00:00
|
|
|
if (ARCH_IS_PPC64(arch) && STRPREFIX(machine, "pseries")) {
|
2012-05-29 08:35:17 +00:00
|
|
|
if (serial->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
|
|
|
|
serial->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO) {
|
|
|
|
virBufferAsprintf(&cmd, "spapr-vty,chardev=char%s",
|
|
|
|
serial->info.alias);
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&cmd, def, &serial->info, qemuCaps) < 0)
|
2012-05-29 08:35:17 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2013-01-05 05:25:36 +00:00
|
|
|
} else {
|
|
|
|
virBufferAsprintf(&cmd, "%s,chardev=char%s,id=%s",
|
|
|
|
virDomainChrSerialTargetTypeToString(serial->targetType),
|
2011-11-21 12:50:42 +00:00
|
|
|
serial->info.alias, serial->info.alias);
|
|
|
|
|
2015-03-04 07:58:02 +00:00
|
|
|
switch (serial->targetType) {
|
|
|
|
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB:
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_USB_SERIAL)) {
|
2013-01-05 05:25:36 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("usb-serial is not supported in this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (serial->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
|
|
|
|
serial->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("usb-serial requires address of usb type"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2013-08-02 17:48:50 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&cmd, def, &serial->info, qemuCaps) < 0)
|
2013-03-13 15:20:34 +00:00
|
|
|
goto error;
|
2015-03-04 07:58:02 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA:
|
2015-06-16 13:07:59 +00:00
|
|
|
if (serial->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
|
|
|
|
serial->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA) {
|
2015-03-04 07:58:02 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2015-06-16 13:07:59 +00:00
|
|
|
_("isa-serial requires address of isa type"));
|
2015-03-04 07:58:02 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2015-06-16 13:07:59 +00:00
|
|
|
|
|
|
|
if (qemuBuildDeviceAddressStr(&cmd, def, &serial->info, qemuCaps) < 0)
|
|
|
|
goto error;
|
2015-03-04 07:58:02 +00:00
|
|
|
break;
|
2015-05-06 15:50:03 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI:
|
|
|
|
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PCI_SERIAL)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("pci-serial is not supported with this QEMU binary"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (serial->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
|
|
|
|
serial->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("pci-serial requires address of pci type"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuBuildDeviceAddressStr(&cmd, def, &serial->info, qemuCaps) < 0)
|
|
|
|
goto error;
|
|
|
|
break;
|
2013-01-05 05:25:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&cmd) < 0)
|
2011-11-21 12:50:42 +00:00
|
|
|
goto error;
|
|
|
|
|
2013-03-13 15:20:34 +00:00
|
|
|
*deviceStr = virBufferContentAndReset(&cmd);
|
|
|
|
return 0;
|
2011-11-21 12:50:42 +00:00
|
|
|
|
2014-03-25 06:49:44 +00:00
|
|
|
error:
|
2011-11-21 12:50:42 +00:00
|
|
|
virBufferFreeAndReset(&cmd);
|
2013-03-13 15:20:34 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuBuildParallelChrDeviceStr(char **deviceStr,
|
|
|
|
virDomainChrDefPtr chr)
|
|
|
|
{
|
|
|
|
if (virAsprintf(deviceStr, "isa-parallel,chardev=char%s,id=%s",
|
2014-06-27 06:44:15 +00:00
|
|
|
chr->info.alias, chr->info.alias) < 0)
|
2013-03-13 15:20:34 +00:00
|
|
|
return -1;
|
|
|
|
return 0;
|
2011-11-21 12:50:42 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2013-03-13 15:20:34 +00:00
|
|
|
static int
|
|
|
|
qemuBuildChannelChrDeviceStr(char **deviceStr,
|
2015-04-30 17:19:10 +00:00
|
|
|
virDomainDefPtr def,
|
2013-03-13 15:20:34 +00:00
|
|
|
virDomainChrDefPtr chr,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
char *addr = NULL;
|
|
|
|
int port;
|
|
|
|
|
2014-06-01 00:22:30 +00:00
|
|
|
switch ((virDomainChrChannelTargetType) chr->targetType) {
|
2013-03-13 15:20:34 +00:00
|
|
|
case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD:
|
|
|
|
|
|
|
|
addr = virSocketAddrFormat(chr->target.addr);
|
|
|
|
if (!addr)
|
|
|
|
return ret;
|
|
|
|
port = virSocketAddrGetPort(chr->target.addr);
|
|
|
|
|
|
|
|
if (virAsprintf(deviceStr,
|
2014-06-26 14:09:46 +00:00
|
|
|
"user,guestfwd=tcp:%s:%i-chardev:char%s,id=user-%s",
|
2014-06-27 06:44:15 +00:00
|
|
|
addr, port, chr->info.alias, chr->info.alias) < 0)
|
2013-03-13 15:20:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO:
|
2015-04-30 17:19:10 +00:00
|
|
|
if (!(*deviceStr = qemuBuildVirtioSerialPortDevStr(def, chr, qemuCaps)))
|
2015-03-17 02:34:26 +00:00
|
|
|
goto cleanup;
|
2013-03-13 15:20:34 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_NONE:
|
|
|
|
case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_LAST:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
2014-03-25 06:49:44 +00:00
|
|
|
cleanup:
|
2013-03-13 15:20:34 +00:00
|
|
|
VIR_FREE(addr);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuBuildConsoleChrDeviceStr(char **deviceStr,
|
2015-04-30 17:19:10 +00:00
|
|
|
virDomainDefPtr def,
|
2013-03-13 15:20:34 +00:00
|
|
|
virDomainChrDefPtr chr,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
|
2014-06-01 00:22:30 +00:00
|
|
|
switch ((virDomainChrConsoleTargetType) chr->targetType) {
|
2013-03-13 15:20:34 +00:00
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SCLP:
|
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SCLPLM:
|
|
|
|
if (!(*deviceStr = qemuBuildSclpDevStr(chr)))
|
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO:
|
2015-04-30 17:19:10 +00:00
|
|
|
if (!(*deviceStr = qemuBuildVirtioSerialPortDevStr(def, chr, qemuCaps)))
|
2013-03-13 15:20:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL:
|
2015-01-22 02:28:18 +00:00
|
|
|
break;
|
|
|
|
|
2013-03-13 15:20:34 +00:00
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE:
|
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN:
|
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_UML:
|
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_LXC:
|
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_OPENVZ:
|
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_LAST:
|
2015-01-22 02:28:18 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported console target type %s"),
|
|
|
|
NULLSTR(virDomainChrConsoleTargetTypeToString(chr->targetType)));
|
|
|
|
goto cleanup;
|
2013-03-13 15:20:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
2014-03-25 06:49:44 +00:00
|
|
|
cleanup:
|
2013-03-13 15:20:34 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuBuildChrDeviceStr(char **deviceStr,
|
|
|
|
virDomainDefPtr vmdef,
|
|
|
|
virDomainChrDefPtr chr,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
|
2014-06-01 00:22:30 +00:00
|
|
|
switch ((virDomainChrDeviceType) chr->deviceType) {
|
2013-03-13 15:20:34 +00:00
|
|
|
case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
|
2013-08-02 17:48:50 +00:00
|
|
|
ret = qemuBuildSerialChrDeviceStr(deviceStr, vmdef, chr, qemuCaps,
|
2013-03-13 15:20:34 +00:00
|
|
|
vmdef->os.arch,
|
|
|
|
vmdef->os.machine);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
|
|
|
|
ret = qemuBuildParallelChrDeviceStr(deviceStr, chr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
|
2015-04-30 17:19:10 +00:00
|
|
|
ret = qemuBuildChannelChrDeviceStr(deviceStr, vmdef, chr, qemuCaps);
|
2013-03-13 15:20:34 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
|
2015-04-30 17:19:10 +00:00
|
|
|
ret = qemuBuildConsoleChrDeviceStr(deviceStr, vmdef, chr, qemuCaps);
|
2013-03-13 15:20:34 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_DEVICE_TYPE_LAST:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|