2010-12-16 15:07:07 +00:00
|
|
|
/*
|
|
|
|
* qemu_command.c: QEMU command generation
|
|
|
|
*
|
2012-01-10 12:53:31 +00:00
|
|
|
* Copyright (C) 2006-2012 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"
|
|
|
|
#include "qemu_bridge_filter.h"
|
|
|
|
#include "cpu/cpu.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "logging.h"
|
|
|
|
#include "virterror_internal.h"
|
|
|
|
#include "util.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2010-12-16 15:07:07 +00:00
|
|
|
#include "uuid.h"
|
|
|
|
#include "c-ctype.h"
|
|
|
|
#include "domain_nwfilter.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"
|
2012-08-14 00:09:12 +00:00
|
|
|
#include "snapshot_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-10-15 21:47:42 +00:00
|
|
|
#include "storage_file.h"
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
#include <sys/utsname.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
|
|
|
|
|
|
|
|
|
VIR_ENUM_DECL(virDomainDiskQEMUBus)
|
|
|
|
VIR_ENUM_IMPL(virDomainDiskQEMUBus, VIR_DOMAIN_DISK_BUS_LAST,
|
|
|
|
"ide",
|
|
|
|
"floppy",
|
|
|
|
"scsi",
|
|
|
|
"virtio",
|
|
|
|
"xen",
|
|
|
|
"usb",
|
|
|
|
"uml",
|
|
|
|
"sata")
|
|
|
|
|
|
|
|
|
|
|
|
VIR_ENUM_DECL(qemuDiskCacheV1)
|
|
|
|
VIR_ENUM_DECL(qemuDiskCacheV2)
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(qemuDiskCacheV1, VIR_DOMAIN_DISK_CACHE_LAST,
|
|
|
|
"default",
|
|
|
|
"off",
|
2011-09-02 13:36:58 +00:00
|
|
|
"off", /* writethrough not supported, so for safety, disable */
|
|
|
|
"on", /* Old 'on' was equivalent to 'writeback' */
|
2011-09-22 19:33:47 +00:00
|
|
|
"off", /* directsync not supported, for safety, disable */
|
|
|
|
"off"); /* unsafe not supported, for safety, disable */
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
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_DECL(qemuVideo)
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(qemuVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
|
|
|
|
"std",
|
|
|
|
"cirrus",
|
|
|
|
"vmware",
|
|
|
|
"", /* no arg needed for xen */
|
|
|
|
"", /* don't support vbox */
|
|
|
|
"qxl");
|
|
|
|
|
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",
|
|
|
|
"handle");
|
|
|
|
|
2011-09-02 13:21:23 +00:00
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
static void
|
2012-10-17 09:23:12 +00:00
|
|
|
uname_normalize(struct utsname *ut)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
uname(ut);
|
|
|
|
|
|
|
|
/* Map i386, i486, i586 to i686. */
|
|
|
|
if (ut->machine[0] == 'i' &&
|
|
|
|
ut->machine[1] != '\0' &&
|
|
|
|
ut->machine[2] == '8' &&
|
|
|
|
ut->machine[3] == '6' &&
|
|
|
|
ut->machine[4] == '\0')
|
|
|
|
ut->machine[1] = '6';
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qemuPhysIfaceConnect:
|
audit: audit use of /dev/net/tun, /dev/tapN, /dev/vhost-net
Opening raw network devices with the intent of passing those fds to
qemu is worth an audit point. This makes a multi-part audit: first,
we audit the device(s) that libvirt opens on behalf of the MAC address
of a to-be-created interface (which can independently succeed or
fail), then we audit whether qemu actually started the network device
with the same MAC (so searching backwards for successful audits with
the same MAC will show which fd(s) qemu is actually using). Note that
it is possible for the fd to be successfully opened but no attempt
made to pass the fd to qemu (for example, because intermediate
nwfilter operations failed) - no interface start audit will occur in
that case; so the audit for a successful opened fd does not imply
rights given to qemu unless there is a followup audit about the
attempt to start a new interface.
Likewise, when a network device is hot-unplugged, there is only one
audit message about the MAC being discontinued; again, searching back
to the earlier device open audits will show which fds that qemu quits
using (and yes, I checked via /proc/<qemu-pid>/fd that qemu _does_
close out the fds associated with an interface on hot-unplug). The
code would require much more refactoring to be able to definitively
state which device(s) were discontinued at that point, since we
currently don't record anywhere in the XML whether /dev/vhost-net was
opened for a given interface.
* src/qemu/qemu_audit.h (qemuAuditNetDevice): New prototype.
* src/qemu/qemu_audit.c (qemuAuditNetDevice): New function.
* src/qemu/qemu_command.h (qemuNetworkIfaceConnect)
(qemuPhysIfaceConnect, qemuOpenVhostNet): Adjust prototype.
* src/qemu/qemu_command.c (qemuNetworkIfaceConnect)
(qemuPhysIfaceConnect, qemuOpenVhostNet): Add audit points and
adjust parameters.
(qemuBuildCommandLine): Adjust caller.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
2011-03-08 18:00:59 +00:00
|
|
|
* @def: the definition of the VM (needed by 802.1Qbh and audit)
|
2012-11-28 16:43:10 +00:00
|
|
|
* @driver: pointer to the driver instance
|
2010-12-16 15:07:07 +00:00
|
|
|
* @net: pointer to he VM's interface description with direct device type
|
2011-02-08 14:28:53 +00:00
|
|
|
* @qemuCaps: flags for qemu
|
2011-11-12 11:39:17 +00:00
|
|
|
* @vmop: VM operation type
|
2010-12-16 15:07:07 +00:00
|
|
|
*
|
|
|
|
* Returns a filedescriptor on success or -1 in case of error.
|
|
|
|
*/
|
|
|
|
int
|
audit: audit use of /dev/net/tun, /dev/tapN, /dev/vhost-net
Opening raw network devices with the intent of passing those fds to
qemu is worth an audit point. This makes a multi-part audit: first,
we audit the device(s) that libvirt opens on behalf of the MAC address
of a to-be-created interface (which can independently succeed or
fail), then we audit whether qemu actually started the network device
with the same MAC (so searching backwards for successful audits with
the same MAC will show which fd(s) qemu is actually using). Note that
it is possible for the fd to be successfully opened but no attempt
made to pass the fd to qemu (for example, because intermediate
nwfilter operations failed) - no interface start audit will occur in
that case; so the audit for a successful opened fd does not imply
rights given to qemu unless there is a followup audit about the
attempt to start a new interface.
Likewise, when a network device is hot-unplugged, there is only one
audit message about the MAC being discontinued; again, searching back
to the earlier device open audits will show which fds that qemu quits
using (and yes, I checked via /proc/<qemu-pid>/fd that qemu _does_
close out the fds associated with an interface on hot-unplug). The
code would require much more refactoring to be able to definitively
state which device(s) were discontinued at that point, since we
currently don't record anywhere in the XML whether /dev/vhost-net was
opened for a given interface.
* src/qemu/qemu_audit.h (qemuAuditNetDevice): New prototype.
* src/qemu/qemu_audit.c (qemuAuditNetDevice): New function.
* src/qemu/qemu_command.h (qemuNetworkIfaceConnect)
(qemuPhysIfaceConnect, qemuOpenVhostNet): Adjust prototype.
* src/qemu/qemu_command.c (qemuNetworkIfaceConnect)
(qemuPhysIfaceConnect, qemuOpenVhostNet): Add audit points and
adjust parameters.
(qemuBuildCommandLine): Adjust caller.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
2011-03-08 18:00:59 +00:00
|
|
|
qemuPhysIfaceConnect(virDomainDefPtr def,
|
2012-11-28 16:43:10 +00:00
|
|
|
virQEMUDriverPtr driver,
|
2010-12-16 15:07:07 +00:00
|
|
|
virDomainNetDefPtr net,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps,
|
Rename Macvtap management APIs
In preparation for code re-organization, rename the Macvtap
management APIs to have the following patterns
virNetDevMacVLanXXXXX - macvlan/macvtap interface management
virNetDevVPortProfileXXXX - virtual port profile management
* src/util/macvtap.c, src/util/macvtap.h: Rename APIs
* src/conf/domain_conf.c, src/network/bridge_driver.c,
src/qemu/qemu_command.c, src/qemu/qemu_command.h,
src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/qemu/qemu_process.h: Update for renamed APIs
2011-11-02 16:51:01 +00:00
|
|
|
enum virNetDevVPortProfileOp vmop)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
char *res_ifname = NULL;
|
|
|
|
int vnet_hdr = 0;
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_VNET_HDR) &&
|
2010-12-16 15:07:07 +00:00
|
|
|
net->model && STREQ(net->model, "virtio"))
|
|
|
|
vnet_hdr = 1;
|
|
|
|
|
2011-11-02 17:19:48 +00:00
|
|
|
rc = virNetDevMacVLanCreateWithVPortProfile(
|
2012-07-17 12:07:59 +00:00
|
|
|
net->ifname, &net->mac,
|
2011-11-02 17:19:48 +00:00
|
|
|
virDomainNetGetActualDirectDev(net),
|
|
|
|
virDomainNetGetActualDirectMode(net),
|
2011-11-10 10:29:09 +00:00
|
|
|
true, vnet_hdr, def->uuid,
|
2012-02-15 19:19:32 +00:00
|
|
|
virDomainNetGetActualVirtPortProfile(net),
|
2011-11-02 17:19:48 +00:00
|
|
|
&res_ifname,
|
|
|
|
vmop, driver->stateDir,
|
|
|
|
virDomainNetGetActualBandwidth(net));
|
2010-12-16 15:07:07 +00:00
|
|
|
if (rc >= 0) {
|
2012-10-19 08:44:30 +00:00
|
|
|
if (virSecurityManagerSetTapFDLabel(driver->securityManager,
|
|
|
|
def, rc) < 0)
|
|
|
|
goto error;
|
|
|
|
|
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
|
|
|
virDomainAuditNetDevice(def, net, res_ifname, true);
|
2010-12-16 15:07:07 +00:00
|
|
|
VIR_FREE(net->ifname);
|
|
|
|
net->ifname = res_ifname;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
2012-10-19 08:44:30 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
ignore_value(virNetDevMacVLanDeleteWithVPortProfile(
|
|
|
|
res_ifname, &net->mac,
|
|
|
|
virDomainNetGetActualDirectDev(net),
|
|
|
|
virDomainNetGetActualDirectMode(net),
|
|
|
|
virDomainNetGetActualVirtPortProfile(net),
|
|
|
|
driver->stateDir));
|
|
|
|
VIR_FREE(res_ifname);
|
|
|
|
return -1;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
audit: audit use of /dev/net/tun, /dev/tapN, /dev/vhost-net
Opening raw network devices with the intent of passing those fds to
qemu is worth an audit point. This makes a multi-part audit: first,
we audit the device(s) that libvirt opens on behalf of the MAC address
of a to-be-created interface (which can independently succeed or
fail), then we audit whether qemu actually started the network device
with the same MAC (so searching backwards for successful audits with
the same MAC will show which fd(s) qemu is actually using). Note that
it is possible for the fd to be successfully opened but no attempt
made to pass the fd to qemu (for example, because intermediate
nwfilter operations failed) - no interface start audit will occur in
that case; so the audit for a successful opened fd does not imply
rights given to qemu unless there is a followup audit about the
attempt to start a new interface.
Likewise, when a network device is hot-unplugged, there is only one
audit message about the MAC being discontinued; again, searching back
to the earlier device open audits will show which fds that qemu quits
using (and yes, I checked via /proc/<qemu-pid>/fd that qemu _does_
close out the fds associated with an interface on hot-unplug). The
code would require much more refactoring to be able to definitively
state which device(s) were discontinued at that point, since we
currently don't record anywhere in the XML whether /dev/vhost-net was
opened for a given interface.
* src/qemu/qemu_audit.h (qemuAuditNetDevice): New prototype.
* src/qemu/qemu_audit.c (qemuAuditNetDevice): New function.
* src/qemu/qemu_command.h (qemuNetworkIfaceConnect)
(qemuPhysIfaceConnect, qemuOpenVhostNet): Adjust prototype.
* src/qemu/qemu_command.c (qemuNetworkIfaceConnect)
(qemuPhysIfaceConnect, qemuOpenVhostNet): Add audit points and
adjust parameters.
(qemuBuildCommandLine): Adjust caller.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
2011-03-08 18:00:59 +00:00
|
|
|
qemuNetworkIfaceConnect(virDomainDefPtr def,
|
|
|
|
virConnectPtr conn,
|
2012-11-28 16:43:10 +00:00
|
|
|
virQEMUDriverPtr driver,
|
2010-12-16 15:07:07 +00:00
|
|
|
virDomainNetDefPtr net,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
char *brname = NULL;
|
|
|
|
int err;
|
|
|
|
int tapfd = -1;
|
2012-03-01 20:35:30 +00:00
|
|
|
unsigned int tap_create_flags = VIR_NETDEV_TAP_CREATE_IFUP;
|
2011-07-29 15:36:17 +00:00
|
|
|
bool template_ifname = false;
|
2011-07-04 01:57:45 +00:00
|
|
|
int actualType = virDomainNetGetActualType(net);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-07-04 01:57:45 +00:00
|
|
|
if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK) {
|
2010-12-16 15:07:07 +00:00
|
|
|
int active, fail = 0;
|
|
|
|
virErrorPtr errobj;
|
|
|
|
virNetworkPtr network = virNetworkLookupByName(conn,
|
|
|
|
net->data.network.name);
|
|
|
|
if (!network)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
active = virNetworkIsActive(network);
|
|
|
|
if (active != 1) {
|
|
|
|
fail = 1;
|
|
|
|
|
|
|
|
if (active == 0)
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Network '%s' is not active."),
|
|
|
|
net->data.network.name);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!fail) {
|
|
|
|
brname = virNetworkGetBridgeName(network);
|
|
|
|
if (brname == NULL)
|
|
|
|
fail = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure any above failure is preserved */
|
|
|
|
errobj = virSaveLastError();
|
|
|
|
virNetworkFree(network);
|
|
|
|
virSetError(errobj);
|
|
|
|
virFreeError(errobj);
|
|
|
|
|
|
|
|
if (fail)
|
|
|
|
return -1;
|
|
|
|
|
2011-07-04 01:57:45 +00:00
|
|
|
} else if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
|
|
|
|
if (!(brname = strdup(virDomainNetGetActualBridgeName(net)))) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Network type %d is not supported"),
|
|
|
|
virDomainNetGetActualType(net));
|
2010-12-16 15:07:07 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!net->ifname ||
|
2011-07-29 15:36:17 +00:00
|
|
|
STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) ||
|
2010-12-16 15:07:07 +00:00
|
|
|
strchr(net->ifname, '%')) {
|
|
|
|
VIR_FREE(net->ifname);
|
2011-07-29 15:36:17 +00:00
|
|
|
if (!(net->ifname = strdup(VIR_NET_GENERATED_PREFIX "%d"))) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-05-06 19:53:10 +00:00
|
|
|
/* avoid exposing vnet%d in getXMLDesc or error outputs */
|
2011-07-29 15:36:17 +00:00
|
|
|
template_ifname = true;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_VNET_HDR) &&
|
2012-03-01 20:35:30 +00:00
|
|
|
net->model && STREQ(net->model, "virtio")) {
|
|
|
|
tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-07-17 12:07:59 +00:00
|
|
|
err = virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac,
|
2012-03-07 07:15:36 +00:00
|
|
|
def->uuid, &tapfd,
|
2012-03-01 20:35:30 +00:00
|
|
|
virDomainNetGetActualVirtPortProfile(net),
|
2012-08-30 09:14:32 +00:00
|
|
|
virDomainNetGetActualVlan(net),
|
2012-03-01 20:35:30 +00:00
|
|
|
tap_create_flags);
|
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
|
|
|
virDomainAuditNetDevice(def, net, "/dev/net/tun", tapfd >= 0);
|
2011-11-02 12:00:28 +00:00
|
|
|
if (err < 0) {
|
2010-12-16 15:07:07 +00:00
|
|
|
if (template_ifname)
|
|
|
|
VIR_FREE(net->ifname);
|
|
|
|
tapfd = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (driver->macFilter) {
|
2012-07-17 12:07:59 +00:00
|
|
|
if ((err = networkAllowMacOnPort(driver, net->ifname, &net->mac))) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virReportSystemError(err,
|
2012-07-18 23:45:34 +00:00
|
|
|
_("failed to add ebtables rule to allow MAC address on '%s'"),
|
2010-12-16 15:07:07 +00:00
|
|
|
net->ifname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-22 14:07:27 +00:00
|
|
|
if (tapfd >= 0 &&
|
Adjust naming of network device bandwidth management APIs
Rename virBandwidth to virNetDevBandwidth, and virRate to
virNetDevBandwidthRate.
* src/util/network.c, src/util/network.h: Rename bandwidth
structs and APIs
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/conf/network_conf.c, src/conf/network_conf.h,
src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/qemu/qemu_command.c, src/util/macvtap.c,
src/util/macvtap.h, tools/virsh.c: Update for API changes.
2011-11-02 14:29:05 +00:00
|
|
|
virNetDevBandwidthSet(net->ifname,
|
2012-11-16 10:36:02 +00:00
|
|
|
virDomainNetGetActualBandwidth(net),
|
|
|
|
false) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot set bandwidth limits on %s"),
|
|
|
|
net->ifname);
|
2011-07-22 14:07:27 +00:00
|
|
|
VIR_FORCE_CLOSE(tapfd);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (tapfd >= 0) {
|
|
|
|
if ((net->filter) && (net->ifname)) {
|
2011-12-09 02:35:20 +00:00
|
|
|
if (virDomainConfNWFilterInstantiate(conn, def->uuid, net) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
VIR_FORCE_CLOSE(tapfd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(brname);
|
|
|
|
|
|
|
|
return tapfd;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-09 04:43:33 +00:00
|
|
|
int
|
audit: audit use of /dev/net/tun, /dev/tapN, /dev/vhost-net
Opening raw network devices with the intent of passing those fds to
qemu is worth an audit point. This makes a multi-part audit: first,
we audit the device(s) that libvirt opens on behalf of the MAC address
of a to-be-created interface (which can independently succeed or
fail), then we audit whether qemu actually started the network device
with the same MAC (so searching backwards for successful audits with
the same MAC will show which fd(s) qemu is actually using). Note that
it is possible for the fd to be successfully opened but no attempt
made to pass the fd to qemu (for example, because intermediate
nwfilter operations failed) - no interface start audit will occur in
that case; so the audit for a successful opened fd does not imply
rights given to qemu unless there is a followup audit about the
attempt to start a new interface.
Likewise, when a network device is hot-unplugged, there is only one
audit message about the MAC being discontinued; again, searching back
to the earlier device open audits will show which fds that qemu quits
using (and yes, I checked via /proc/<qemu-pid>/fd that qemu _does_
close out the fds associated with an interface on hot-unplug). The
code would require much more refactoring to be able to definitively
state which device(s) were discontinued at that point, since we
currently don't record anywhere in the XML whether /dev/vhost-net was
opened for a given interface.
* src/qemu/qemu_audit.h (qemuAuditNetDevice): New prototype.
* src/qemu/qemu_audit.c (qemuAuditNetDevice): New function.
* src/qemu/qemu_command.h (qemuNetworkIfaceConnect)
(qemuPhysIfaceConnect, qemuOpenVhostNet): Adjust prototype.
* src/qemu/qemu_command.c (qemuNetworkIfaceConnect)
(qemuPhysIfaceConnect, qemuOpenVhostNet): Add audit points and
adjust parameters.
(qemuBuildCommandLine): Adjust caller.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
2011-03-08 18:00:59 +00:00
|
|
|
qemuOpenVhostNet(virDomainDefPtr def,
|
|
|
|
virDomainNetDefPtr net,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps,
|
2011-01-12 04:18:49 +00:00
|
|
|
int *vhostfd)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
2011-01-12 04:18:49 +00:00
|
|
|
*vhostfd = -1; /* assume we won't use vhost */
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-01-12 04:18:49 +00:00
|
|
|
/* If the config says explicitly to not use vhost, return now */
|
Restructure domain struct interface "driver" data for easier expansion
When the <driver> element (and its "name" attribute) was added to the
domain XML's interface element, a "backend" enum was simply added to
the toplevel of the virDomainNetDef struct.
Ignoring the naming inconsistency ("name" vs. "backend"), this is fine
when there's only a single item contained in the driver element of the
XML, but doesn't scale well as we add more attributes that apply to
the backend of the virtio-net driver, or add attributes applicable to
other drivers.
This patch changes virDomainNetDef in two ways:
1) Rename the item in the struct from "backend" to "name", so that
it's the same in the XML and in the struct, hopefully avoiding
confusion for someone unfamiliar with the function of the
attribute.
2) Create a "driver" union within virDomainNetDef, and a "virtio"
struct in that struct, which contains the "name" enum value.
3) Move around the virDomainNetParse and virDomainNetFormat functions
to allow for simple plugin of new attributes without disturbing
existing code. (you'll note that this results in a seemingly
redundant if() in the format function, but that will no longer be
the case as soon as a 2nd attribute is added).
In the future, new attributes for the virtio driver backend can be
added to the "virtio" struct, and any other network device backend that
needs an attribute will have its own struct added to the "driver"
union.
2011-02-03 18:52:08 +00:00
|
|
|
if (net->driver.virtio.name == VIR_DOMAIN_NET_BACKEND_TYPE_QEMU) {
|
2011-01-12 04:18:49 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If qemu doesn't support vhost-net mode (including the -netdev command
|
|
|
|
* option), don't try to open the device.
|
|
|
|
*/
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!(qemuCapsGet(caps, QEMU_CAPS_VHOST_NET) &&
|
|
|
|
qemuCapsGet(caps, QEMU_CAPS_NETDEV) &&
|
|
|
|
qemuCapsGet(caps, QEMU_CAPS_DEVICE))) {
|
Restructure domain struct interface "driver" data for easier expansion
When the <driver> element (and its "name" attribute) was added to the
domain XML's interface element, a "backend" enum was simply added to
the toplevel of the virDomainNetDef struct.
Ignoring the naming inconsistency ("name" vs. "backend"), this is fine
when there's only a single item contained in the driver element of the
XML, but doesn't scale well as we add more attributes that apply to
the backend of the virtio-net driver, or add attributes applicable to
other drivers.
This patch changes virDomainNetDef in two ways:
1) Rename the item in the struct from "backend" to "name", so that
it's the same in the XML and in the struct, hopefully avoiding
confusion for someone unfamiliar with the function of the
attribute.
2) Create a "driver" union within virDomainNetDef, and a "virtio"
struct in that struct, which contains the "name" enum value.
3) Move around the virDomainNetParse and virDomainNetFormat functions
to allow for simple plugin of new attributes without disturbing
existing code. (you'll note that this results in a seemingly
redundant if() in the format function, but that will no longer be
the case as soon as a 2nd attribute is added).
In the future, new attributes for the virtio driver backend can be
added to the "virtio" struct, and any other network device backend that
needs an attribute will have its own struct added to the "driver"
union.
2011-02-03 18:52:08 +00:00
|
|
|
if (net->driver.virtio.name == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("vhost-net is not supported with "
|
|
|
|
"this QEMU binary"));
|
2011-01-12 04:18:49 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-01-12 04:18:49 +00:00
|
|
|
/* If the nic model isn't virtio, don't try to open. */
|
|
|
|
if (!(net->model && STREQ(net->model, "virtio"))) {
|
Restructure domain struct interface "driver" data for easier expansion
When the <driver> element (and its "name" attribute) was added to the
domain XML's interface element, a "backend" enum was simply added to
the toplevel of the virDomainNetDef struct.
Ignoring the naming inconsistency ("name" vs. "backend"), this is fine
when there's only a single item contained in the driver element of the
XML, but doesn't scale well as we add more attributes that apply to
the backend of the virtio-net driver, or add attributes applicable to
other drivers.
This patch changes virDomainNetDef in two ways:
1) Rename the item in the struct from "backend" to "name", so that
it's the same in the XML and in the struct, hopefully avoiding
confusion for someone unfamiliar with the function of the
attribute.
2) Create a "driver" union within virDomainNetDef, and a "virtio"
struct in that struct, which contains the "name" enum value.
3) Move around the virDomainNetParse and virDomainNetFormat functions
to allow for simple plugin of new attributes without disturbing
existing code. (you'll note that this results in a seemingly
redundant if() in the format function, but that will no longer be
the case as soon as a 2nd attribute is added).
In the future, new attributes for the virtio driver backend can be
added to the "virtio" struct, and any other network device backend that
needs an attribute will have its own struct added to the "driver"
union.
2011-02-03 18:52:08 +00:00
|
|
|
if (net->driver.virtio.name == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("vhost-net is only supported for "
|
|
|
|
"virtio network interfaces"));
|
2011-01-12 04:18:49 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
*vhostfd = open("/dev/vhost-net", O_RDWR);
|
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
|
|
|
virDomainAuditNetDevice(def, net, "/dev/vhost-net", *vhostfd >= 0);
|
2011-01-12 04:18:49 +00:00
|
|
|
|
|
|
|
/* If the config says explicitly to use vhost and we couldn't open it,
|
|
|
|
* report an error.
|
|
|
|
*/
|
|
|
|
if ((*vhostfd < 0) &&
|
Restructure domain struct interface "driver" data for easier expansion
When the <driver> element (and its "name" attribute) was added to the
domain XML's interface element, a "backend" enum was simply added to
the toplevel of the virDomainNetDef struct.
Ignoring the naming inconsistency ("name" vs. "backend"), this is fine
when there's only a single item contained in the driver element of the
XML, but doesn't scale well as we add more attributes that apply to
the backend of the virtio-net driver, or add attributes applicable to
other drivers.
This patch changes virDomainNetDef in two ways:
1) Rename the item in the struct from "backend" to "name", so that
it's the same in the XML and in the struct, hopefully avoiding
confusion for someone unfamiliar with the function of the
attribute.
2) Create a "driver" union within virDomainNetDef, and a "virtio"
struct in that struct, which contains the "name" enum value.
3) Move around the virDomainNetParse and virDomainNetFormat functions
to allow for simple plugin of new attributes without disturbing
existing code. (you'll note that this results in a seemingly
redundant if() in the format function, but that will no longer be
the case as soon as a 2nd attribute is added).
In the future, new attributes for the virtio driver backend can be
added to the "virtio" struct, and any other network device backend that
needs an attribute will have its own struct added to the "driver"
union.
2011-02-03 18:52:08 +00:00
|
|
|
(net->driver.virtio.name == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("vhost-net was requested for an interface, "
|
|
|
|
"but is unavailable"));
|
2011-01-12 04:18:49 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int qemuDomainDeviceAliasIndex(virDomainDeviceInfoPtr info,
|
|
|
|
const char *prefix)
|
|
|
|
{
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
if (!info->alias)
|
|
|
|
return -1;
|
|
|
|
if (!STRPREFIX(info->alias, prefix))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virStrToLong_i(info->alias + strlen(prefix), NULL, 10, &idx) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int qemuDomainNetVLAN(virDomainNetDefPtr def)
|
|
|
|
{
|
|
|
|
return qemuDomainDeviceAliasIndex(&def->info, "net");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Names used before -drive existed */
|
|
|
|
static int qemuAssignDeviceDiskAliasLegacy(virDomainDiskDefPtr disk)
|
|
|
|
{
|
2011-09-16 12:05:58 +00:00
|
|
|
char *dev_name;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
|
|
|
|
STREQ(disk->dst, "hdc"))
|
2011-09-16 12:05:58 +00:00
|
|
|
dev_name = strdup("cdrom");
|
2010-12-16 15:07:07 +00:00
|
|
|
else
|
2011-09-16 12:05:58 +00:00
|
|
|
dev_name = strdup(disk->dst);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-09-16 12:05:58 +00:00
|
|
|
if (!dev_name) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-09-16 12:05:58 +00:00
|
|
|
disk->info.alias = dev_name;
|
2010-12-16 15:07:07 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *qemuDeviceDriveHostAlias(virDomainDiskDefPtr disk,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
char *ret;
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
if (virAsprintf(&ret, "%s%s", QEMU_DRIVE_HOST_PREFIX, disk->info.alias) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!(ret = strdup(disk->info.alias))) {
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Names used before -drive supported the id= option */
|
|
|
|
static int qemuAssignDeviceDiskAliasFixed(virDomainDiskDefPtr disk)
|
|
|
|
{
|
|
|
|
int busid, devid;
|
|
|
|
int ret;
|
2011-09-16 12:05:58 +00:00
|
|
|
char *dev_name;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (virDiskNameToBusDeviceIndex(disk, &busid, &devid) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot convert disk '%s' to bus/device index"),
|
|
|
|
disk->dst);
|
2010-12-16 15:07:07 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (disk->bus) {
|
|
|
|
case VIR_DOMAIN_DISK_BUS_IDE:
|
|
|
|
if (disk->device== VIR_DOMAIN_DISK_DEVICE_DISK)
|
2011-09-16 12:05:58 +00:00
|
|
|
ret = virAsprintf(&dev_name, "ide%d-hd%d", busid, devid);
|
2010-12-16 15:07:07 +00:00
|
|
|
else
|
2011-09-16 12:05:58 +00:00
|
|
|
ret = virAsprintf(&dev_name, "ide%d-cd%d", busid, devid);
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_BUS_SCSI:
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK)
|
2011-09-16 12:05:58 +00:00
|
|
|
ret = virAsprintf(&dev_name, "scsi%d-hd%d", busid, devid);
|
2010-12-16 15:07:07 +00:00
|
|
|
else
|
2011-09-16 12:05:58 +00:00
|
|
|
ret = virAsprintf(&dev_name, "scsi%d-cd%d", busid, devid);
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_BUS_FDC:
|
2011-09-16 12:05:58 +00:00
|
|
|
ret = virAsprintf(&dev_name, "floppy%d", devid);
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_BUS_VIRTIO:
|
2011-09-16 12:05:58 +00:00
|
|
|
ret = virAsprintf(&dev_name, "virtio%d", devid);
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_BUS_XEN:
|
2011-09-16 12:05:58 +00:00
|
|
|
ret = virAsprintf(&dev_name, "xenblk%d", devid);
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
default:
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unsupported disk name mapping for bus '%s'"),
|
|
|
|
virDomainDiskBusTypeToString(disk->bus));
|
2010-12-16 15:07:07 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == -1) {
|
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-09-16 12:05:58 +00:00
|
|
|
disk->info.alias = dev_name;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-02-27 09:08:23 +00:00
|
|
|
static int
|
2012-08-08 15:13:23 +00:00
|
|
|
qemuSetScsiControllerModel(virDomainDefPtr def,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps,
|
2012-08-08 15:13:23 +00:00
|
|
|
int *model)
|
2012-08-08 07:06:33 +00:00
|
|
|
{
|
|
|
|
if (*model > 0) {
|
|
|
|
switch (*model) {
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC:
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_SCSI_LSI)) {
|
2012-08-08 07:06:33 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("This QEMU doesn't support "
|
|
|
|
"lsi scsi controller"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI:
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_VIRTIO_SCSI_PCI)) {
|
2012-08-08 07:06:33 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("This QEMU doesn't support "
|
|
|
|
"virtio scsi controller"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI:
|
|
|
|
/*TODO: need checking work here if necessary */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unsupported controller model: %s"),
|
|
|
|
virDomainControllerModelSCSITypeToString(*model));
|
|
|
|
return -1;
|
|
|
|
}
|
2012-02-27 09:08:23 +00:00
|
|
|
} else {
|
2012-08-08 07:06:33 +00:00
|
|
|
if (STREQ(def->os.arch, "ppc64") &&
|
|
|
|
STREQ(def->os.machine, "pseries")) {
|
|
|
|
*model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI;
|
2012-08-20 16:44:14 +00:00
|
|
|
} else if (qemuCapsGet(caps, QEMU_CAPS_SCSI_LSI)) {
|
2012-08-08 07:06:33 +00:00
|
|
|
*model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC;
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Unable to determine model for scsi controller"));
|
|
|
|
return -1;
|
|
|
|
}
|
2012-02-27 09:08:23 +00:00
|
|
|
}
|
2012-08-08 07:06:33 +00:00
|
|
|
|
|
|
|
return 0;
|
2012-02-27 09:08:23 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
/* Our custom -drive naming scheme used with id= */
|
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
|
|
|
static int
|
|
|
|
qemuAssignDeviceDiskAliasCustom(virDomainDefPtr def,
|
2012-08-08 07:06:33 +00:00
|
|
|
virDomainDiskDefPtr disk,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
const char *prefix = virDomainDiskBusTypeToString(disk->bus);
|
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 = -1;
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
|
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->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
|
|
|
|
controllerModel =
|
|
|
|
virDomainDiskFindControllerModel(def, disk,
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_SCSI);
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if ((qemuSetScsiControllerModel(def, caps, &controllerModel)) < 0)
|
2012-08-08 07:06:33 +00:00
|
|
|
return -1;
|
|
|
|
}
|
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->bus != VIR_DOMAIN_DISK_BUS_SCSI ||
|
|
|
|
controllerModel == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC) {
|
|
|
|
if (virAsprintf(&disk->info.alias, "%s%d-%d-%d", prefix,
|
|
|
|
disk->info.addr.drive.controller,
|
|
|
|
disk->info.addr.drive.bus,
|
|
|
|
disk->info.addr.drive.unit) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
} else {
|
|
|
|
if (virAsprintf(&disk->info.alias, "%s%d-%d-%d-%d", prefix,
|
|
|
|
disk->info.addr.drive.controller,
|
|
|
|
disk->info.addr.drive.bus,
|
|
|
|
disk->info.addr.drive.target,
|
|
|
|
disk->info.addr.drive.unit) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
} else {
|
|
|
|
int idx = virDiskNameToIndex(disk->dst);
|
|
|
|
if (virAsprintf(&disk->info.alias, "%s-disk%d", prefix, idx) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
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
|
|
|
qemuAssignDeviceDiskAlias(virDomainDefPtr vmdef,
|
|
|
|
virDomainDiskDefPtr def,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DRIVE)) {
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DEVICE))
|
|
|
|
return qemuAssignDeviceDiskAliasCustom(vmdef, def, caps);
|
2010-12-16 15:07:07 +00:00
|
|
|
else
|
|
|
|
return qemuAssignDeviceDiskAliasFixed(def);
|
|
|
|
} else {
|
|
|
|
return qemuAssignDeviceDiskAliasLegacy(def);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuAssignDeviceNetAlias(virDomainDefPtr def, virDomainNetDefPtr net, int idx)
|
|
|
|
{
|
|
|
|
if (idx == -1) {
|
|
|
|
int i;
|
|
|
|
idx = 0;
|
|
|
|
for (i = 0 ; i < def->nnets ; i++) {
|
|
|
|
int thisidx;
|
2012-06-01 16:50:37 +00:00
|
|
|
|
|
|
|
if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
|
|
|
|
/* type='hostdev' interfaces have a hostdev%d alias */
|
|
|
|
continue;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
if ((thisidx = qemuDomainDeviceAliasIndex(&def->nets[i]->info, "net")) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Unable to determine device index for network device"));
|
2010-12-16 15:07:07 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (thisidx >= idx)
|
|
|
|
idx = thisidx + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&net->info.alias, "net%d", idx) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr hostdev, int idx)
|
|
|
|
{
|
|
|
|
if (idx == -1) {
|
|
|
|
int i;
|
|
|
|
idx = 0;
|
|
|
|
for (i = 0 ; i < def->nhostdevs ; i++) {
|
|
|
|
int thisidx;
|
2012-01-31 09:16:54 +00:00
|
|
|
if ((thisidx = qemuDomainDeviceAliasIndex(def->hostdevs[i]->info, "hostdev")) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Unable to determine device index for hostdev device"));
|
2010-12-16 15:07:07 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (thisidx >= idx)
|
|
|
|
idx = thisidx + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-31 09:16:54 +00:00
|
|
|
if (virAsprintf(&hostdev->info->alias, "hostdev%d", idx) < 0) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-02 15:09:14 +00:00
|
|
|
int
|
|
|
|
qemuAssignDeviceRedirdevAlias(virDomainDefPtr def, virDomainRedirdevDefPtr redirdev, int idx)
|
|
|
|
{
|
|
|
|
if (idx == -1) {
|
|
|
|
int i;
|
|
|
|
idx = 0;
|
|
|
|
for (i = 0 ; i < def->nredirdevs ; i++) {
|
|
|
|
int thisidx;
|
|
|
|
if ((thisidx = qemuDomainDeviceAliasIndex(&def->redirdevs[i]->info, "redir")) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Unable to determine device index for redirected device"));
|
2011-09-02 15:09:14 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (thisidx >= idx)
|
|
|
|
idx = thisidx + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&redirdev->info.alias, "redir%d", idx) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
int
|
|
|
|
qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller)
|
|
|
|
{
|
|
|
|
const char *prefix = virDomainControllerTypeToString(controller->type);
|
|
|
|
|
|
|
|
if (virAsprintf(&controller->info.alias, "%s%d", prefix,
|
|
|
|
controller->idx) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-20 12:45:12 +00:00
|
|
|
int
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuAssignDeviceAliases(virDomainDefPtr def, qemuCapsPtr caps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < def->ndisks ; i++) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuAssignDeviceDiskAlias(def, def->disks[i], caps) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_NET_NAME) ||
|
|
|
|
qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
for (i = 0; i < def->nnets ; i++) {
|
qemu: support type='hostdev' network devices at domain start
This patch makes sure that each network device ("interface") of
type='hostdev' appears on both the hostdevs list and the nets list of
the virDomainDef, and it modifies the qemu driver startup code so that
these devices will be presented to qemu on the commandline as hostdevs
rather than as network devices.
It does not add support for hotplug of these type of devices, or code
to honor the <mac address> or <virtualport> given in the config (both
of those will be done in separate patches).
Once each device is placed on both lists, much of what this patch does
is modify places in the code that traverse all the device lists so
that these hybrid devices are only acted on once - either along with
the other hostdevs, or along with the other network interfaces. (In
many cases, only one of the lists is traversed / a specific operation
is performed on only one type of device. In those instances, the code
can remain unchanged.)
There is one special case - when building the commandline, interfaces
are allowed to proceed all the way through
networkAllocateActualDevice() before deciding to skip the rest of
netdev-specific processing - this is so that (once we have support for
networks with pools of hostdev devices) we can get the actual device
allocated, then rely on the loop processing all hostdevs to generate
the correct commandline.
(NB: <interface type='hostdev'> is only supported for PCI network
devices that are SR-IOV Virtual Functions (VF). Standard PCI[e] and
USB devices, and even the Physical Functions (PF) of SR-IOV devices
can only be assigned to a guest using the more basic <hostdev> device
entry. This limitation is mostly due to the fact that non-SR-IOV
ethernet devices tend to lose mac address configuration whenever the
card is reset, which happens when a card is assigned to a guest;
SR-IOV VFs fortunately don't suffer the same problem.)
2012-02-23 15:45:35 +00:00
|
|
|
/* type='hostdev' interfaces are also on the hostdevs list,
|
|
|
|
* and will have their alias assigned with other hostdevs.
|
|
|
|
*/
|
|
|
|
if ((def->nets[i]->type != VIR_DOMAIN_NET_TYPE_HOSTDEV) &&
|
|
|
|
(qemuAssignDeviceNetAlias(def, def->nets[i], i) < 0)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
return -1;
|
qemu: support type='hostdev' network devices at domain start
This patch makes sure that each network device ("interface") of
type='hostdev' appears on both the hostdevs list and the nets list of
the virDomainDef, and it modifies the qemu driver startup code so that
these devices will be presented to qemu on the commandline as hostdevs
rather than as network devices.
It does not add support for hotplug of these type of devices, or code
to honor the <mac address> or <virtualport> given in the config (both
of those will be done in separate patches).
Once each device is placed on both lists, much of what this patch does
is modify places in the code that traverse all the device lists so
that these hybrid devices are only acted on once - either along with
the other hostdevs, or along with the other network interfaces. (In
many cases, only one of the lists is traversed / a specific operation
is performed on only one type of device. In those instances, the code
can remain unchanged.)
There is one special case - when building the commandline, interfaces
are allowed to proceed all the way through
networkAllocateActualDevice() before deciding to skip the rest of
netdev-specific processing - this is so that (once we have support for
networks with pools of hostdev devices) we can get the actual device
allocated, then rely on the loop processing all hostdevs to generate
the correct commandline.
(NB: <interface type='hostdev'> is only supported for PCI network
devices that are SR-IOV Virtual Functions (VF). Standard PCI[e] and
USB devices, and even the Physical Functions (PF) of SR-IOV devices
can only be assigned to a guest using the more basic <hostdev> device
entry. This limitation is mostly due to the fact that non-SR-IOV
ethernet devices tend to lose mac address configuration whenever the
card is reset, which happens when a card is assigned to a guest;
SR-IOV VFs fortunately don't suffer the same problem.)
2012-02-23 15:45:35 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_DEVICE))
|
2010-12-16 15:07:07 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; i < def->nfss ; i++) {
|
|
|
|
if (virAsprintf(&def->fss[i]->info.alias, "fs%d", i) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nsounds ; i++) {
|
|
|
|
if (virAsprintf(&def->sounds[i]->info.alias, "sound%d", i) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nhostdevs ; i++) {
|
|
|
|
if (qemuAssignDeviceHostdevAlias(def, def->hostdevs[i], i) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
2011-09-02 15:09:14 +00:00
|
|
|
for (i = 0; i < def->nredirdevs ; i++) {
|
|
|
|
if (qemuAssignDeviceRedirdevAlias(def, def->redirdevs[i], i) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
for (i = 0; i < def->nvideos ; i++) {
|
|
|
|
if (virAsprintf(&def->videos[i]->info.alias, "video%d", i) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->ncontrollers ; i++) {
|
|
|
|
if (qemuAssignDeviceControllerAlias(def->controllers[i]) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->ninputs ; i++) {
|
|
|
|
if (virAsprintf(&def->inputs[i]->info.alias, "input%d", i) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nparallels ; i++) {
|
|
|
|
if (virAsprintf(&def->parallels[i]->info.alias, "parallel%d", i) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nserials ; i++) {
|
|
|
|
if (virAsprintf(&def->serials[i]->info.alias, "serial%d", i) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nchannels ; i++) {
|
|
|
|
if (virAsprintf(&def->channels[i]->info.alias, "channel%d", i) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
Allow multiple consoles per virtual guest
While Xen only has a single paravirt console, UML, and
QEMU both support multiple paravirt consoles. The LXC
driver can also be trivially made to support multiple
consoles. This patch extends the XML to allow multiple
<console> elements in the XML. It also makes the UML
and QEMU drivers support this config.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Allow
multiple <console> devices
* src/lxc/lxc_driver.c, src/xen/xen_driver.c,
src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c: Update for
internal API changes
* src/security/security_selinux.c, src/security/virt-aa-helper.c:
Only label consoles that aren't a copy of the serial device
* src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_process.c, src/uml/uml_conf.c,
src/uml/uml_driver.c: Support multiple console devices
* tests/qemuxml2xmltest.c, tests/qemuxml2argvtest.c: Extra
tests for multiple virtio consoles. Set QEMU_CAPS_CHARDEV
for all console /channel tests
* tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-auto.args,
tests/qemuxml2argvdata/qemuxml2argv-channel-virtio.args
tests/qemuxml2argvdata/qemuxml2argv-console-virtio.args: Update
for correct chardev syntax
* tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.args,
tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.xml: New
test file
2011-02-23 18:27:23 +00:00
|
|
|
for (i = 0; i < def->nconsoles ; i++) {
|
|
|
|
if (virAsprintf(&def->consoles[i]->info.alias, "console%d", i) < 0)
|
2011-01-13 00:09:45 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
2011-09-02 14:20:40 +00:00
|
|
|
for (i = 0; i < def->nhubs ; i++) {
|
|
|
|
if (virAsprintf(&def->hubs[i]->info.alias, "hub%d", i) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
Allow multiple consoles per virtual guest
While Xen only has a single paravirt console, UML, and
QEMU both support multiple paravirt consoles. The LXC
driver can also be trivially made to support multiple
consoles. This patch extends the XML to allow multiple
<console> elements in the XML. It also makes the UML
and QEMU drivers support this config.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Allow
multiple <console> devices
* src/lxc/lxc_driver.c, src/xen/xen_driver.c,
src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c: Update for
internal API changes
* src/security/security_selinux.c, src/security/virt-aa-helper.c:
Only label consoles that aren't a copy of the serial device
* src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_process.c, src/uml/uml_conf.c,
src/uml/uml_driver.c: Support multiple console devices
* tests/qemuxml2xmltest.c, tests/qemuxml2argvtest.c: Extra
tests for multiple virtio consoles. Set QEMU_CAPS_CHARDEV
for all console /channel tests
* tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-auto.args,
tests/qemuxml2argvdata/qemuxml2argv-channel-virtio.args
tests/qemuxml2argvdata/qemuxml2argv-console-virtio.args: Update
for correct chardev syntax
* tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.args,
tests/qemuxml2argvdata/qemuxml2argv-console-virtio-many.xml: New
test file
2011-02-23 18:27:23 +00:00
|
|
|
for (i = 0; i < def->nsmartcards ; i++) {
|
|
|
|
if (virAsprintf(&def->smartcards[i]->info.alias, "smartcard%d", i) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
if (def->watchdog) {
|
|
|
|
if (virAsprintf(&def->watchdog->info.alias, "watchdog%d", 0) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
if (def->memballoon) {
|
|
|
|
if (virAsprintf(&def->memballoon->info.alias, "balloon%d", 0) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2012-11-10 01:40:25 +00:00
|
|
|
no_memory:
|
2010-12-16 15:07:07 +00:00
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-06-29 15:02:05 +00:00
|
|
|
static void
|
|
|
|
qemuDomainPrimeS390VirtioDevices(virDomainDefPtr def,
|
|
|
|
enum virDomainDeviceAddressType type)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
declare address-less virtio devices to be of address type 'type'
|
|
|
|
only disks, networks, consoles and controllers for now
|
|
|
|
*/
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < def->ndisks ; i++) {
|
|
|
|
if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_VIRTIO &&
|
|
|
|
def->disks[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
|
|
|
|
def->disks[i]->info.type = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < def->nnets ; i++) {
|
2012-12-10 10:00:05 +00:00
|
|
|
if (STRPREFIX(def->os.arch, "s390") &&
|
|
|
|
def->nets[i]->model == NULL) {
|
|
|
|
def->nets[i]->model = strdup("virtio");
|
|
|
|
}
|
2012-06-29 15:02:05 +00:00
|
|
|
if (STREQ(def->nets[i]->model,"virtio") &&
|
2012-12-10 10:00:05 +00:00
|
|
|
def->nets[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
|
2012-06-29 15:02:05 +00:00
|
|
|
def->nets[i]->info.type = type;
|
2012-12-10 10:00:05 +00:00
|
|
|
}
|
2012-06-29 15:02:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < def->ncontrollers ; i++) {
|
|
|
|
if (def->controllers[i]->type ==
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL &&
|
|
|
|
def->controllers[i]->info.type ==
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
|
|
|
|
def->controllers[i]->info.type = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-08-22 14:39:54 +00:00
|
|
|
static void
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuDomainAssignS390Addresses(virDomainDefPtr def, qemuCapsPtr caps)
|
2012-06-29 15:02:05 +00:00
|
|
|
{
|
2012-08-22 14:39:54 +00:00
|
|
|
/* deal with legacy virtio-s390 */
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_VIRTIO_S390))
|
2012-06-29 15:02:05 +00:00
|
|
|
qemuDomainPrimeS390VirtioDevices(
|
|
|
|
def, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390);
|
|
|
|
}
|
|
|
|
|
2011-12-12 23:39:32 +00:00
|
|
|
static int
|
|
|
|
qemuSpaprVIOFindByReg(virDomainDefPtr def ATTRIBUTE_UNUSED,
|
2012-02-22 21:06:10 +00:00
|
|
|
virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
|
2011-12-12 23:39:32 +00:00
|
|
|
virDomainDeviceInfoPtr info, void *opaque)
|
|
|
|
{
|
|
|
|
virDomainDeviceInfoPtr target = opaque;
|
|
|
|
|
|
|
|
if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Match a dev that has a reg, is not us, and has a matching reg */
|
|
|
|
if (info->addr.spaprvio.has_reg && info != target &&
|
|
|
|
info->addr.spaprvio.reg == target->addr.spaprvio.reg)
|
|
|
|
/* Has to be < 0 so virDomainDeviceInfoIterate() will exit */
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuAssignSpaprVIOAddress(virDomainDefPtr def, virDomainDeviceInfoPtr info,
|
|
|
|
unsigned long long default_reg)
|
|
|
|
{
|
|
|
|
bool user_reg;
|
2012-08-22 14:39:54 +00:00
|
|
|
int ret;
|
2011-12-12 23:39:32 +00:00
|
|
|
|
|
|
|
if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Check if the user has assigned the reg already, if so use it */
|
|
|
|
user_reg = info->addr.spaprvio.has_reg;
|
|
|
|
if (!user_reg) {
|
|
|
|
info->addr.spaprvio.reg = default_reg;
|
|
|
|
info->addr.spaprvio.has_reg = true;
|
|
|
|
}
|
|
|
|
|
2012-08-22 14:39:54 +00:00
|
|
|
ret = virDomainDeviceInfoIterate(def, qemuSpaprVIOFindByReg, info);
|
|
|
|
while (ret != 0) {
|
2011-12-12 23:39:32 +00:00
|
|
|
if (user_reg) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("spapr-vio address %#llx already in use"),
|
|
|
|
info->addr.spaprvio.reg);
|
2011-12-12 23:39:32 +00:00
|
|
|
return -EEXIST;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We assigned the reg, so try a new value */
|
|
|
|
info->addr.spaprvio.reg += 0x1000;
|
2012-08-22 14:39:54 +00:00
|
|
|
ret = virDomainDeviceInfoIterate(def, qemuSpaprVIOFindByReg, info);
|
2011-12-12 23:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-08 07:06:33 +00:00
|
|
|
int qemuDomainAssignSpaprVIOAddresses(virDomainDefPtr def,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2011-12-12 23:39:32 +00:00
|
|
|
{
|
2012-08-22 14:39:54 +00:00
|
|
|
int i, ret = -1;
|
2012-05-14 06:16:37 +00:00
|
|
|
int model;
|
2011-12-12 23:39:32 +00:00
|
|
|
|
|
|
|
/* Default values match QEMU. See spapr_(llan|vscsi|vty).c */
|
|
|
|
|
|
|
|
for (i = 0 ; i < def->nnets; i++) {
|
2012-05-29 08:35:17 +00:00
|
|
|
if (def->nets[i]->model &&
|
|
|
|
STREQ(def->nets[i]->model, "spapr-vlan"))
|
|
|
|
def->nets[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO;
|
2012-08-22 14:39:54 +00:00
|
|
|
if (qemuAssignSpaprVIOAddress(def, &def->nets[i]->info,
|
|
|
|
0x1000ul) < 0)
|
2012-08-08 07:06:33 +00:00
|
|
|
goto cleanup;
|
2011-12-12 23:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0 ; i < def->ncontrollers; i++) {
|
2012-05-14 06:16:37 +00:00
|
|
|
model = def->controllers[i]->model;
|
2012-08-08 07:06:33 +00:00
|
|
|
if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
|
2012-08-22 14:39:54 +00:00
|
|
|
if (qemuSetScsiControllerModel(def, caps, &model) < 0)
|
2012-08-08 07:06:33 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-05-14 06:16:37 +00:00
|
|
|
if (model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI &&
|
2012-05-29 08:35:17 +00:00
|
|
|
def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
|
2012-05-14 06:16:37 +00:00
|
|
|
def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO;
|
2012-08-22 14:39:54 +00:00
|
|
|
if (qemuAssignSpaprVIOAddress(def, &def->controllers[i]->info,
|
|
|
|
0x2000ul) < 0)
|
2012-08-08 07:06:33 +00:00
|
|
|
goto cleanup;
|
2011-12-12 23:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0 ; i < def->nserials; i++) {
|
2012-05-29 08:35:17 +00:00
|
|
|
if (def->serials[i]->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
|
|
|
|
def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY &&
|
|
|
|
STREQ(def->os.arch, "ppc64") &&
|
|
|
|
STREQ(def->os.machine, "pseries"))
|
|
|
|
def->serials[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO;
|
2012-08-22 14:39:54 +00:00
|
|
|
if (qemuAssignSpaprVIOAddress(def, &def->serials[i]->info,
|
|
|
|
0x30000000ul) < 0)
|
2012-08-08 07:06:33 +00:00
|
|
|
goto cleanup;
|
2011-12-12 23:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* No other devices are currently supported on spapr-vio */
|
|
|
|
|
2012-08-22 14:39:54 +00:00
|
|
|
ret = 0;
|
2012-08-08 07:06:33 +00:00
|
|
|
|
|
|
|
cleanup:
|
2012-08-22 14:39:54 +00:00
|
|
|
return ret;
|
2011-12-12 23:39:32 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
#define QEMU_PCI_ADDRESS_LAST_SLOT 31
|
2011-05-24 05:23:39 +00:00
|
|
|
#define QEMU_PCI_ADDRESS_LAST_FUNCTION 8
|
2010-12-16 15:07:07 +00:00
|
|
|
struct _qemuDomainPCIAddressSet {
|
|
|
|
virHashTablePtr used;
|
|
|
|
int nextslot;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static char *qemuPCIAddressAsString(virDomainDeviceInfoPtr dev)
|
|
|
|
{
|
|
|
|
char *addr;
|
|
|
|
|
|
|
|
if (dev->addr.pci.domain != 0 ||
|
|
|
|
dev->addr.pci.bus != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Only PCI domain 0 and bus 0 are available"));
|
2010-12-16 15:07:07 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-05-23 03:22:54 +00:00
|
|
|
if (virAsprintf(&addr, "%d:%d:%d.%d",
|
2010-12-16 15:07:07 +00:00
|
|
|
dev->addr.pci.domain,
|
|
|
|
dev->addr.pci.bus,
|
2011-05-23 03:22:54 +00:00
|
|
|
dev->addr.pci.slot,
|
|
|
|
dev->addr.pci.function) < 0) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
|
qemu: support type='hostdev' network devices at domain start
This patch makes sure that each network device ("interface") of
type='hostdev' appears on both the hostdevs list and the nets list of
the virDomainDef, and it modifies the qemu driver startup code so that
these devices will be presented to qemu on the commandline as hostdevs
rather than as network devices.
It does not add support for hotplug of these type of devices, or code
to honor the <mac address> or <virtualport> given in the config (both
of those will be done in separate patches).
Once each device is placed on both lists, much of what this patch does
is modify places in the code that traverse all the device lists so
that these hybrid devices are only acted on once - either along with
the other hostdevs, or along with the other network interfaces. (In
many cases, only one of the lists is traversed / a specific operation
is performed on only one type of device. In those instances, the code
can remain unchanged.)
There is one special case - when building the commandline, interfaces
are allowed to proceed all the way through
networkAllocateActualDevice() before deciding to skip the rest of
netdev-specific processing - this is so that (once we have support for
networks with pools of hostdev devices) we can get the actual device
allocated, then rely on the loop processing all hostdevs to generate
the correct commandline.
(NB: <interface type='hostdev'> is only supported for PCI network
devices that are SR-IOV Virtual Functions (VF). Standard PCI[e] and
USB devices, and even the Physical Functions (PF) of SR-IOV devices
can only be assigned to a guest using the more basic <hostdev> device
entry. This limitation is mostly due to the fact that non-SR-IOV
ethernet devices tend to lose mac address configuration whenever the
card is reset, which happens when a card is assigned to a guest;
SR-IOV VFs fortunately don't suffer the same problem.)
2012-02-23 15:45:35 +00:00
|
|
|
virDomainDeviceDefPtr device,
|
2012-02-23 17:59:21 +00:00
|
|
|
virDomainDeviceInfoPtr info,
|
2010-12-16 15:07:07 +00:00
|
|
|
void *opaque)
|
|
|
|
{
|
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
|
|
|
int ret = -1;
|
|
|
|
char *addr = NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
qemuDomainPCIAddressSetPtr addrs = opaque;
|
|
|
|
|
qemu: support type='hostdev' network devices at domain start
This patch makes sure that each network device ("interface") of
type='hostdev' appears on both the hostdevs list and the nets list of
the virDomainDef, and it modifies the qemu driver startup code so that
these devices will be presented to qemu on the commandline as hostdevs
rather than as network devices.
It does not add support for hotplug of these type of devices, or code
to honor the <mac address> or <virtualport> given in the config (both
of those will be done in separate patches).
Once each device is placed on both lists, much of what this patch does
is modify places in the code that traverse all the device lists so
that these hybrid devices are only acted on once - either along with
the other hostdevs, or along with the other network interfaces. (In
many cases, only one of the lists is traversed / a specific operation
is performed on only one type of device. In those instances, the code
can remain unchanged.)
There is one special case - when building the commandline, interfaces
are allowed to proceed all the way through
networkAllocateActualDevice() before deciding to skip the rest of
netdev-specific processing - this is so that (once we have support for
networks with pools of hostdev devices) we can get the actual device
allocated, then rely on the loop processing all hostdevs to generate
the correct commandline.
(NB: <interface type='hostdev'> is only supported for PCI network
devices that are SR-IOV Virtual Functions (VF). Standard PCI[e] and
USB devices, and even the Physical Functions (PF) of SR-IOV devices
can only be assigned to a guest using the more basic <hostdev> device
entry. This limitation is mostly due to the fact that non-SR-IOV
ethernet devices tend to lose mac address configuration whenever the
card is reset, which happens when a card is assigned to a guest;
SR-IOV VFs fortunately don't suffer the same problem.)
2012-02-23 15:45:35 +00:00
|
|
|
if ((info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
|
|
|
|
|| ((device->type == VIR_DOMAIN_DEVICE_HOSTDEV) &&
|
|
|
|
(device->data.hostdev->parent.type != VIR_DOMAIN_DEVICE_NONE))) {
|
|
|
|
/* If a hostdev has a parent, its info will be a part of the
|
|
|
|
* parent, and will have its address collected during the scan
|
|
|
|
* of the parent's device type.
|
|
|
|
*/
|
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
|
|
|
return 0;
|
qemu: support type='hostdev' network devices at domain start
This patch makes sure that each network device ("interface") of
type='hostdev' appears on both the hostdevs list and the nets list of
the virDomainDef, and it modifies the qemu driver startup code so that
these devices will be presented to qemu on the commandline as hostdevs
rather than as network devices.
It does not add support for hotplug of these type of devices, or code
to honor the <mac address> or <virtualport> given in the config (both
of those will be done in separate patches).
Once each device is placed on both lists, much of what this patch does
is modify places in the code that traverse all the device lists so
that these hybrid devices are only acted on once - either along with
the other hostdevs, or along with the other network interfaces. (In
many cases, only one of the lists is traversed / a specific operation
is performed on only one type of device. In those instances, the code
can remain unchanged.)
There is one special case - when building the commandline, interfaces
are allowed to proceed all the way through
networkAllocateActualDevice() before deciding to skip the rest of
netdev-specific processing - this is so that (once we have support for
networks with pools of hostdev devices) we can get the actual device
allocated, then rely on the loop processing all hostdevs to generate
the correct commandline.
(NB: <interface type='hostdev'> is only supported for PCI network
devices that are SR-IOV Virtual Functions (VF). Standard PCI[e] and
USB devices, and even the Physical Functions (PF) of SR-IOV devices
can only be assigned to a guest using the more basic <hostdev> device
entry. This limitation is mostly due to the fact that non-SR-IOV
ethernet devices tend to lose mac address configuration whenever the
card is reset, which happens when a card is assigned to a guest;
SR-IOV VFs fortunately don't suffer the same problem.)
2012-02-23 15:45:35 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-02-23 17:59:21 +00:00
|
|
|
addr = qemuPCIAddressAsString(info);
|
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
|
|
|
if (!addr)
|
|
|
|
goto cleanup;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
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
|
|
|
if (virHashLookup(addrs->used, addr)) {
|
2012-02-23 17:59:21 +00:00
|
|
|
if (info->addr.pci.function != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("Attempted double use of PCI Address '%s' "
|
|
|
|
"(may need \"multifunction='on'\" for device on function 0)"),
|
|
|
|
addr);
|
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
|
|
|
} else {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("Attempted double use of PCI Address '%s'"), addr);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
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
|
|
|
goto cleanup;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
VIR_DEBUG("Remembering PCI addr %s", addr);
|
|
|
|
if (virHashAddEntry(addrs->used, addr, addr) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
addr = NULL;
|
|
|
|
|
2012-02-23 17:59:21 +00:00
|
|
|
if ((info->addr.pci.function == 0) &&
|
2012-08-16 15:41:06 +00:00
|
|
|
(info->addr.pci.multi != VIR_DEVICE_ADDRESS_PCI_MULTI_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
|
|
|
/* a function 0 w/o multifunction=on must reserve the entire slot */
|
|
|
|
int function;
|
2012-02-23 17:59:21 +00:00
|
|
|
virDomainDeviceInfo temp_info = *info;
|
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
|
|
|
|
|
|
|
for (function = 1; function < QEMU_PCI_ADDRESS_LAST_FUNCTION; function++) {
|
2012-02-23 17:59:21 +00:00
|
|
|
temp_info.addr.pci.function = function;
|
|
|
|
addr = qemuPCIAddressAsString(&temp_info);
|
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
|
|
|
if (!addr)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virHashLookup(addrs->used, addr)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
2012-09-12 16:54:42 +00:00
|
|
|
_("Attempted double use of PCI Address '%s' "
|
|
|
|
"(need \"multifunction='off'\" for device "
|
|
|
|
"on function 0)"),
|
2012-07-18 15:22:03 +00:00
|
|
|
addr);
|
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
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_DEBUG("Remembering PCI addr %s (multifunction=off for function 0)", addr);
|
|
|
|
if (virHashAddEntry(addrs->used, addr, addr))
|
|
|
|
goto cleanup;
|
|
|
|
addr = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(addr);
|
|
|
|
return ret;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-14 16:09:39 +00:00
|
|
|
int
|
2012-06-29 15:02:03 +00:00
|
|
|
qemuDomainAssignPCIAddresses(virDomainDefPtr def,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps,
|
2012-06-29 15:02:03 +00:00
|
|
|
virDomainObjPtr obj)
|
2011-02-14 16:09:39 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
qemuDomainPCIAddressSetPtr addrs = NULL;
|
2012-06-29 15:02:03 +00:00
|
|
|
qemuDomainObjPrivatePtr priv = NULL;
|
2011-02-14 16:09:39 +00:00
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
2011-02-14 16:09:39 +00:00
|
|
|
if (!(addrs = qemuDomainPCIAddressSetCreate(def)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (qemuAssignDevicePCISlots(def, addrs) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-06-29 15:02:03 +00:00
|
|
|
if (obj && obj->privateData) {
|
|
|
|
priv = obj->privateData;
|
|
|
|
if (addrs) {
|
|
|
|
/* if this is the live domain object, we persist the PCI addresses*/
|
|
|
|
qemuDomainPCIAddressSetFree(priv->pciaddrs);
|
|
|
|
priv->persistentAddrs = 1;
|
|
|
|
priv->pciaddrs = addrs;
|
|
|
|
addrs = NULL;
|
|
|
|
} else {
|
|
|
|
priv->persistentAddrs = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-14 16:09:39 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
qemuDomainPCIAddressSetFree(addrs);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-06-29 15:02:03 +00:00
|
|
|
int qemuDomainAssignAddresses(virDomainDefPtr def,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps,
|
2012-06-29 15:02:03 +00:00
|
|
|
virDomainObjPtr obj)
|
2011-12-08 06:41:26 +00:00
|
|
|
{
|
2011-12-12 23:39:32 +00:00
|
|
|
int rc;
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
rc = qemuDomainAssignSpaprVIOAddresses(def, caps);
|
2011-12-12 23:39:32 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2012-08-22 14:39:54 +00:00
|
|
|
qemuDomainAssignS390Addresses(def, caps);
|
2012-06-29 15:02:05 +00:00
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
return qemuDomainAssignPCIAddresses(def, caps, obj);
|
2011-12-08 06:41:26 +00:00
|
|
|
}
|
2011-02-14 16:09:39 +00:00
|
|
|
|
2011-02-18 21:30:24 +00:00
|
|
|
static void
|
|
|
|
qemuDomainPCIAddressSetFreeEntry(void *payload,
|
Allow hash tables to use generic pointers as keys
Relax the restriction that the hash table key must be a string
by allowing an arbitrary hash code generator + comparison func
to be provided
* util/hash.c, util/hash.h: Allow any pointer as a key
* internal.h: Include stdbool.h as standard.
* conf/domain_conf.c, conf/domain_conf.c,
conf/nwfilter_params.c, nwfilter/nwfilter_gentech_driver.c,
nwfilter/nwfilter_gentech_driver.h, nwfilter/nwfilter_learnipaddr.c,
qemu/qemu_command.c, qemu/qemu_driver.c,
qemu/qemu_process.c, uml/uml_driver.c,
xen/xm_internal.c: s/char */void */ in hash callbacks
2011-02-22 15:11:59 +00:00
|
|
|
const void *name ATTRIBUTE_UNUSED)
|
2011-02-18 21:30:24 +00:00
|
|
|
{
|
|
|
|
VIR_FREE(payload);
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def)
|
|
|
|
{
|
|
|
|
qemuDomainPCIAddressSetPtr addrs;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(addrs) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
2011-02-18 21:30:24 +00:00
|
|
|
if (!(addrs->used = virHashCreate(10, qemuDomainPCIAddressSetFreeEntry)))
|
2011-02-17 21:14:58 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (virDomainDeviceInfoIterate(def, qemuCollectPCIAddress, addrs) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
return addrs;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
error:
|
|
|
|
qemuDomainPCIAddressSetFree(addrs);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-05-23 07:50:13 +00:00
|
|
|
/* check whether the slot is used by the other device
|
|
|
|
* Return 0 if the slot is not used by the other device, or -1 if the slot
|
|
|
|
* is used by the other device.
|
|
|
|
*/
|
|
|
|
static int qemuDomainPCIAddressCheckSlot(qemuDomainPCIAddressSetPtr addrs,
|
|
|
|
virDomainDeviceInfoPtr dev)
|
|
|
|
{
|
|
|
|
char *addr;
|
|
|
|
virDomainDeviceInfo temp_dev;
|
|
|
|
int function;
|
|
|
|
|
|
|
|
temp_dev = *dev;
|
|
|
|
for (function = 0; function < QEMU_PCI_ADDRESS_LAST_FUNCTION; function++) {
|
|
|
|
temp_dev.addr.pci.function = function;
|
|
|
|
addr = qemuPCIAddressAsString(&temp_dev);
|
|
|
|
if (!addr)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virHashLookup(addrs->used, addr)) {
|
|
|
|
VIR_FREE(addr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
|
|
|
|
virDomainDeviceInfoPtr dev)
|
|
|
|
{
|
|
|
|
char *addr;
|
|
|
|
|
|
|
|
addr = qemuPCIAddressAsString(dev);
|
|
|
|
if (!addr)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
VIR_DEBUG("Reserving PCI addr %s", addr);
|
|
|
|
|
|
|
|
if (virHashLookup(addrs->used, addr)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unable to reserve PCI address %s"), addr);
|
2010-12-16 15:07:07 +00:00
|
|
|
VIR_FREE(addr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virHashAddEntry(addrs->used, addr, addr)) {
|
|
|
|
VIR_FREE(addr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->addr.pci.slot > addrs->nextslot) {
|
|
|
|
addrs->nextslot = dev->addr.pci.slot + 1;
|
|
|
|
if (QEMU_PCI_ADDRESS_LAST_SLOT < addrs->nextslot)
|
|
|
|
addrs->nextslot = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-05-24 05:23:39 +00:00
|
|
|
int qemuDomainPCIAddressReserveFunction(qemuDomainPCIAddressSetPtr addrs,
|
|
|
|
int slot, int function)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virDomainDeviceInfo dev;
|
|
|
|
|
|
|
|
dev.addr.pci.domain = 0;
|
|
|
|
dev.addr.pci.bus = 0;
|
|
|
|
dev.addr.pci.slot = slot;
|
2011-05-24 05:23:39 +00:00
|
|
|
dev.addr.pci.function = function;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
return qemuDomainPCIAddressReserveAddr(addrs, &dev);
|
|
|
|
}
|
|
|
|
|
2011-05-24 05:23:39 +00:00
|
|
|
int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
|
|
|
|
int slot)
|
|
|
|
{
|
|
|
|
int function;
|
|
|
|
|
2011-08-24 15:31:48 +00:00
|
|
|
for (function = 0; function < QEMU_PCI_ADDRESS_LAST_FUNCTION; function++) {
|
2011-05-24 05:23:39 +00:00
|
|
|
if (qemuDomainPCIAddressReserveFunction(addrs, slot, function) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
for (function--; function >= 0; function--) {
|
|
|
|
qemuDomainPCIAddressReleaseFunction(addrs, slot, function);
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs,
|
|
|
|
virDomainDeviceInfoPtr dev)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
2011-05-23 07:43:35 +00:00
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
|
|
|
/* We do not support hotplug multi-function PCI device now, so we should
|
|
|
|
* reserve the whole slot. The function of the PCI device must be 0.
|
|
|
|
*/
|
|
|
|
if (dev->addr.pci.function != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Only PCI device addresses with function=0"
|
|
|
|
" are supported"));
|
2011-05-23 07:43:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = qemuDomainPCIAddressReserveSlot(addrs, dev->addr.pci.slot);
|
|
|
|
} else {
|
2010-12-16 15:07:07 +00:00
|
|
|
ret = qemuDomainPCIAddressSetNextAddr(addrs, dev);
|
2011-05-23 07:43:35 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int qemuDomainPCIAddressReleaseAddr(qemuDomainPCIAddressSetPtr addrs,
|
|
|
|
virDomainDeviceInfoPtr dev)
|
|
|
|
{
|
|
|
|
char *addr;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
addr = qemuPCIAddressAsString(dev);
|
|
|
|
if (!addr)
|
|
|
|
return -1;
|
|
|
|
|
2011-02-22 15:11:59 +00:00
|
|
|
ret = virHashRemoveEntry(addrs->used, addr);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
VIR_FREE(addr);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-05-24 05:23:39 +00:00
|
|
|
int qemuDomainPCIAddressReleaseFunction(qemuDomainPCIAddressSetPtr addrs,
|
|
|
|
int slot, int function)
|
|
|
|
{
|
|
|
|
virDomainDeviceInfo dev;
|
|
|
|
|
|
|
|
dev.addr.pci.domain = 0;
|
|
|
|
dev.addr.pci.bus = 0;
|
|
|
|
dev.addr.pci.slot = slot;
|
|
|
|
dev.addr.pci.function = function;
|
|
|
|
|
|
|
|
return qemuDomainPCIAddressReleaseAddr(addrs, &dev);
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-05-23 07:43:35 +00:00
|
|
|
int qemuDomainPCIAddressReleaseSlot(qemuDomainPCIAddressSetPtr addrs, int slot)
|
|
|
|
{
|
|
|
|
virDomainDeviceInfo dev;
|
|
|
|
char *addr;
|
|
|
|
int ret = 0;
|
2011-06-30 14:01:54 +00:00
|
|
|
unsigned int *function = &dev.addr.pci.function;
|
2011-05-23 07:43:35 +00:00
|
|
|
|
|
|
|
dev.addr.pci.domain = 0;
|
|
|
|
dev.addr.pci.bus = 0;
|
|
|
|
dev.addr.pci.slot = slot;
|
|
|
|
|
2011-08-24 15:31:48 +00:00
|
|
|
for (*function = 0; *function < QEMU_PCI_ADDRESS_LAST_FUNCTION; (*function)++) {
|
2011-05-23 07:43:35 +00:00
|
|
|
addr = qemuPCIAddressAsString(&dev);
|
|
|
|
if (!addr)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!virHashLookup(addrs->used, addr)) {
|
|
|
|
VIR_FREE(addr);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(addr);
|
|
|
|
|
2011-06-30 14:01:54 +00:00
|
|
|
if (qemuDomainPCIAddressReleaseFunction(addrs, slot, *function) < 0)
|
2011-05-23 07:43:35 +00:00
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs)
|
|
|
|
{
|
|
|
|
if (!addrs)
|
|
|
|
return;
|
|
|
|
|
2011-02-18 21:30:24 +00:00
|
|
|
virHashFree(addrs->used);
|
2010-12-16 15:07:07 +00:00
|
|
|
VIR_FREE(addrs);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-14 10:16:22 +00:00
|
|
|
static int qemuDomainPCIAddressGetNextSlot(qemuDomainPCIAddressSetPtr addrs)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int iteration;
|
|
|
|
|
|
|
|
for (i = addrs->nextslot, iteration = 0;
|
|
|
|
iteration <= QEMU_PCI_ADDRESS_LAST_SLOT; i++, iteration++) {
|
|
|
|
virDomainDeviceInfo maybe;
|
|
|
|
char *addr;
|
|
|
|
|
|
|
|
if (QEMU_PCI_ADDRESS_LAST_SLOT < i)
|
|
|
|
i = 0;
|
|
|
|
memset(&maybe, 0, sizeof(maybe));
|
|
|
|
maybe.addr.pci.domain = 0;
|
|
|
|
maybe.addr.pci.bus = 0;
|
|
|
|
maybe.addr.pci.slot = i;
|
2011-05-23 03:22:54 +00:00
|
|
|
maybe.addr.pci.function = 0;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (!(addr = qemuPCIAddressAsString(&maybe)))
|
|
|
|
return -1;
|
|
|
|
|
2011-05-23 07:50:13 +00:00
|
|
|
if (qemuDomainPCIAddressCheckSlot(addrs, &maybe) < 0) {
|
2010-12-16 15:07:07 +00:00
|
|
|
VIR_DEBUG("PCI addr %s already in use", addr);
|
|
|
|
VIR_FREE(addr);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-05-14 10:16:22 +00:00
|
|
|
VIR_DEBUG("Found free PCI addr %s", addr);
|
2011-05-23 07:50:13 +00:00
|
|
|
VIR_FREE(addr);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-05-14 10:16:22 +00:00
|
|
|
return i;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("No more available PCI addresses"));
|
2010-12-16 15:07:07 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-05-14 10:16:22 +00:00
|
|
|
int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
|
|
|
|
virDomainDeviceInfoPtr dev)
|
|
|
|
{
|
|
|
|
int slot = qemuDomainPCIAddressGetNextSlot(addrs);
|
|
|
|
|
|
|
|
if (slot < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (qemuDomainPCIAddressReserveSlot(addrs, slot) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
dev->addr.pci.bus = 0;
|
|
|
|
dev->addr.pci.domain = 0;
|
|
|
|
dev->addr.pci.slot = slot;
|
|
|
|
dev->addr.pci.function = 0;
|
|
|
|
|
|
|
|
addrs->nextslot = slot + 1;
|
|
|
|
if (QEMU_PCI_ADDRESS_LAST_SLOT < addrs->nextslot)
|
|
|
|
addrs->nextslot = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define IS_USB2_CONTROLLER(ctrl) \
|
|
|
|
(((ctrl)->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) && \
|
|
|
|
((ctrl)->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1 || \
|
|
|
|
(ctrl)->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1 || \
|
|
|
|
(ctrl)->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2 || \
|
|
|
|
(ctrl)->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3))
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
/*
|
|
|
|
* This assigns static PCI slots to all configured devices.
|
|
|
|
* The ordering here is chosen to match the ordering used
|
|
|
|
* with old QEMU < 0.12, so that if a user updates a QEMU
|
|
|
|
* host from old QEMU to QEMU >= 0.12, their guests should
|
|
|
|
* get PCI addresses in the same order as before.
|
|
|
|
*
|
|
|
|
* NB, if they previously hotplugged devices then all bets
|
|
|
|
* are off. Hotplug for old QEMU was unfixably broken wrt
|
|
|
|
* to stable PCI addressing.
|
|
|
|
*
|
|
|
|
* Order is:
|
|
|
|
*
|
|
|
|
* - Host bridge (slot 0)
|
|
|
|
* - PIIX3 ISA bridge, IDE controller, something else unknown, USB controller (slot 1)
|
|
|
|
* - Video (slot 2)
|
|
|
|
*
|
|
|
|
* Incrementally assign slots from 3 onwards:
|
|
|
|
*
|
|
|
|
* - Net
|
|
|
|
* - Sound
|
|
|
|
* - SCSI controllers
|
|
|
|
* - VirtIO block
|
|
|
|
* - VirtIO balloon
|
|
|
|
* - Host device passthrough
|
2011-01-11 13:37:52 +00:00
|
|
|
* - Watchdog (not IB700)
|
2010-12-16 15:07:07 +00:00
|
|
|
*
|
|
|
|
* Prior to this function being invoked, qemuCollectPCIAddress() will have
|
|
|
|
* added all existing PCI addresses from the 'def' to 'addrs'. Thus this
|
|
|
|
* function must only try to reserve addresses if info.type == NONE and
|
|
|
|
* skip over info.type == PCI
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs)
|
|
|
|
{
|
2012-05-14 10:16:22 +00:00
|
|
|
size_t i, j;
|
2010-12-16 15:07:07 +00:00
|
|
|
bool reservedIDE = false;
|
2011-09-02 14:42:09 +00:00
|
|
|
bool reservedUSB = false;
|
2011-08-24 02:47:39 +00:00
|
|
|
int function;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
/* Host bridge */
|
|
|
|
if (qemuDomainPCIAddressReserveSlot(addrs, 0) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2011-09-02 14:49:42 +00:00
|
|
|
/* Verify that first IDE and USB controllers (if any) is on the PIIX3, fn 1 */
|
2010-12-16 15:07:07 +00:00
|
|
|
for (i = 0; i < def->ncontrollers ; i++) {
|
|
|
|
/* First IDE controller lives on the PIIX3 at slot=1, function=1 */
|
|
|
|
if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE &&
|
|
|
|
def->controllers[i]->idx == 0) {
|
|
|
|
if (def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
|
|
|
if (def->controllers[i]->info.addr.pci.domain != 0 ||
|
|
|
|
def->controllers[i]->info.addr.pci.bus != 0 ||
|
|
|
|
def->controllers[i]->info.addr.pci.slot != 1 ||
|
|
|
|
def->controllers[i]->info.addr.pci.function != 1) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Primary IDE controller must have PCI address 0:0:1.1"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2011-04-05 13:49:58 +00:00
|
|
|
/* If TYPE==PCI, then qemuCollectPCIAddress() function
|
2010-12-16 15:07:07 +00:00
|
|
|
* has already reserved the address, so we must skip */
|
|
|
|
reservedIDE = true;
|
|
|
|
} else {
|
|
|
|
def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
def->controllers[i]->info.addr.pci.domain = 0;
|
|
|
|
def->controllers[i]->info.addr.pci.bus = 0;
|
|
|
|
def->controllers[i]->info.addr.pci.slot = 1;
|
|
|
|
def->controllers[i]->info.addr.pci.function = 1;
|
|
|
|
}
|
2011-09-02 14:42:09 +00:00
|
|
|
} else if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB &&
|
|
|
|
def->controllers[i]->idx == 0 &&
|
2011-09-05 07:03:27 +00:00
|
|
|
(def->controllers[i]->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI ||
|
|
|
|
def->controllers[i]->model == -1)) {
|
2011-09-02 14:49:42 +00:00
|
|
|
if (def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
|
|
|
if (def->controllers[i]->info.addr.pci.domain != 0 ||
|
|
|
|
def->controllers[i]->info.addr.pci.bus != 0 ||
|
|
|
|
def->controllers[i]->info.addr.pci.slot != 1 ||
|
|
|
|
def->controllers[i]->info.addr.pci.function != 2) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("PIIX3 USB controller must have PCI address 0:0:1.2"));
|
2011-09-02 14:49:42 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
reservedUSB = true;
|
|
|
|
} else {
|
|
|
|
def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
def->controllers[i]->info.addr.pci.domain = 0;
|
|
|
|
def->controllers[i]->info.addr.pci.bus = 0;
|
|
|
|
def->controllers[i]->info.addr.pci.slot = 1;
|
|
|
|
def->controllers[i]->info.addr.pci.function = 2;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* PIIX3 (ISA bridge, IDE controller, something else unknown, USB controller)
|
|
|
|
* hardcoded slot=1, multifunction device
|
|
|
|
*/
|
2011-08-24 02:47:39 +00:00
|
|
|
for (function = 0; function < QEMU_PCI_ADDRESS_LAST_FUNCTION; function++) {
|
2011-09-05 06:48:56 +00:00
|
|
|
if ((function == 1 && reservedIDE) ||
|
|
|
|
(function == 2 && reservedUSB))
|
2011-08-24 02:47:39 +00:00
|
|
|
/* we have reserved this pci address */
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (qemuDomainPCIAddressReserveFunction(addrs, 1, function) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
/* First VGA is hardcoded slot=2 */
|
|
|
|
if (def->nvideos > 0) {
|
|
|
|
if (def->videos[0]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
|
|
|
if (def->videos[0]->info.addr.pci.domain != 0 ||
|
|
|
|
def->videos[0]->info.addr.pci.bus != 0 ||
|
|
|
|
def->videos[0]->info.addr.pci.slot != 2 ||
|
|
|
|
def->videos[0]->info.addr.pci.function != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Primary video card must have PCI address 0:0:2.0"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2011-04-05 13:49:58 +00:00
|
|
|
/* If TYPE==PCI, then qemuCollectPCIAddress() function
|
|
|
|
* has already reserved the address, so we must skip */
|
2010-12-16 15:07:07 +00:00
|
|
|
} else {
|
|
|
|
def->videos[0]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
def->videos[0]->info.addr.pci.domain = 0;
|
|
|
|
def->videos[0]->info.addr.pci.bus = 0;
|
|
|
|
def->videos[0]->info.addr.pci.slot = 2;
|
|
|
|
def->videos[0]->info.addr.pci.function = 0;
|
2012-01-17 15:21:38 +00:00
|
|
|
if (qemuDomainPCIAddressReserveSlot(addrs, 2) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virDomainDeviceInfo dev;
|
|
|
|
memset(&dev, 0, sizeof(dev));
|
|
|
|
dev.addr.pci.slot = 2;
|
|
|
|
|
|
|
|
if (qemuDomainPCIAddressCheckSlot(addrs, &dev) < 0) {
|
|
|
|
VIR_DEBUG("PCI address 0:0:2.0 in use, future addition of a video"
|
|
|
|
" device will not be possible without manual"
|
|
|
|
" intervention");
|
|
|
|
virResetLastError();
|
|
|
|
} else if (qemuDomainPCIAddressReserveSlot(addrs, 2) < 0) {
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
2011-04-05 13:49:58 +00:00
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
for (i = 0; i < def->nfss ; i++) {
|
|
|
|
if (def->fss[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Only support VirtIO-9p-pci so far. If that changes,
|
|
|
|
* we might need to skip devices here */
|
|
|
|
if (qemuDomainPCIAddressSetNextAddr(addrs, &def->fss[i]->info) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Network interfaces */
|
|
|
|
for (i = 0; i < def->nnets ; i++) {
|
qemu: support type='hostdev' network devices at domain start
This patch makes sure that each network device ("interface") of
type='hostdev' appears on both the hostdevs list and the nets list of
the virDomainDef, and it modifies the qemu driver startup code so that
these devices will be presented to qemu on the commandline as hostdevs
rather than as network devices.
It does not add support for hotplug of these type of devices, or code
to honor the <mac address> or <virtualport> given in the config (both
of those will be done in separate patches).
Once each device is placed on both lists, much of what this patch does
is modify places in the code that traverse all the device lists so
that these hybrid devices are only acted on once - either along with
the other hostdevs, or along with the other network interfaces. (In
many cases, only one of the lists is traversed / a specific operation
is performed on only one type of device. In those instances, the code
can remain unchanged.)
There is one special case - when building the commandline, interfaces
are allowed to proceed all the way through
networkAllocateActualDevice() before deciding to skip the rest of
netdev-specific processing - this is so that (once we have support for
networks with pools of hostdev devices) we can get the actual device
allocated, then rely on the loop processing all hostdevs to generate
the correct commandline.
(NB: <interface type='hostdev'> is only supported for PCI network
devices that are SR-IOV Virtual Functions (VF). Standard PCI[e] and
USB devices, and even the Physical Functions (PF) of SR-IOV devices
can only be assigned to a guest using the more basic <hostdev> device
entry. This limitation is mostly due to the fact that non-SR-IOV
ethernet devices tend to lose mac address configuration whenever the
card is reset, which happens when a card is assigned to a guest;
SR-IOV VFs fortunately don't suffer the same problem.)
2012-02-23 15:45:35 +00:00
|
|
|
/* type='hostdev' network devices might be USB, and are also
|
|
|
|
* in hostdevs list anyway, so handle them with other hostdevs
|
|
|
|
* instead of here.
|
|
|
|
*/
|
|
|
|
if ((def->nets[i]->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) ||
|
|
|
|
(def->nets[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
continue;
|
qemu: support type='hostdev' network devices at domain start
This patch makes sure that each network device ("interface") of
type='hostdev' appears on both the hostdevs list and the nets list of
the virDomainDef, and it modifies the qemu driver startup code so that
these devices will be presented to qemu on the commandline as hostdevs
rather than as network devices.
It does not add support for hotplug of these type of devices, or code
to honor the <mac address> or <virtualport> given in the config (both
of those will be done in separate patches).
Once each device is placed on both lists, much of what this patch does
is modify places in the code that traverse all the device lists so
that these hybrid devices are only acted on once - either along with
the other hostdevs, or along with the other network interfaces. (In
many cases, only one of the lists is traversed / a specific operation
is performed on only one type of device. In those instances, the code
can remain unchanged.)
There is one special case - when building the commandline, interfaces
are allowed to proceed all the way through
networkAllocateActualDevice() before deciding to skip the rest of
netdev-specific processing - this is so that (once we have support for
networks with pools of hostdev devices) we can get the actual device
allocated, then rely on the loop processing all hostdevs to generate
the correct commandline.
(NB: <interface type='hostdev'> is only supported for PCI network
devices that are SR-IOV Virtual Functions (VF). Standard PCI[e] and
USB devices, and even the Physical Functions (PF) of SR-IOV devices
can only be assigned to a guest using the more basic <hostdev> device
entry. This limitation is mostly due to the fact that non-SR-IOV
ethernet devices tend to lose mac address configuration whenever the
card is reset, which happens when a card is assigned to a guest;
SR-IOV VFs fortunately don't suffer the same problem.)
2012-02-23 15:45:35 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
if (qemuDomainPCIAddressSetNextAddr(addrs, &def->nets[i]->info) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sound cards */
|
|
|
|
for (i = 0; i < def->nsounds ; i++) {
|
|
|
|
if (def->sounds[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
|
|
|
|
continue;
|
|
|
|
/* Skip ISA sound card, and PCSPK */
|
|
|
|
if (def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_SB16 ||
|
|
|
|
def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_PCSPK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (qemuDomainPCIAddressSetNextAddr(addrs, &def->sounds[i]->info) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-05-14 10:16:22 +00:00
|
|
|
/* Device controllers (SCSI, USB, but not IDE, FDC or CCID) */
|
2010-12-16 15:07:07 +00:00
|
|
|
for (i = 0; i < def->ncontrollers ; i++) {
|
2011-01-13 00:09:45 +00:00
|
|
|
/* FDC lives behind the ISA bridge; CCID is a usb device */
|
|
|
|
if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC ||
|
|
|
|
def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_CCID)
|
2010-12-16 15:07:07 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* First IDE controller lives on the PIIX3 at slot=1, function=1,
|
|
|
|
dealt with earlier on*/
|
|
|
|
if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE &&
|
|
|
|
def->controllers[i]->idx == 0)
|
|
|
|
continue;
|
|
|
|
|
2011-12-12 23:39:31 +00:00
|
|
|
if (def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO)
|
|
|
|
continue;
|
2010-12-16 15:07:07 +00:00
|
|
|
if (def->controllers[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
|
|
|
|
continue;
|
2012-05-14 10:16:22 +00:00
|
|
|
|
|
|
|
/* USB2 needs special handling to put all companions in the same slot */
|
|
|
|
if (IS_USB2_CONTROLLER(def->controllers[i])) {
|
2012-08-16 15:41:06 +00:00
|
|
|
virDevicePCIAddress addr = { 0, 0, 0, 0, false };
|
2012-05-14 10:16:22 +00:00
|
|
|
for (j = 0 ; j < i ; j++) {
|
|
|
|
if (IS_USB2_CONTROLLER(def->controllers[j]) &&
|
|
|
|
def->controllers[j]->idx == def->controllers[i]->idx) {
|
|
|
|
addr = def->controllers[j]->info.addr.pci;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (def->controllers[i]->model) {
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1:
|
|
|
|
addr.function = 7;
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1:
|
|
|
|
addr.function = 0;
|
2012-08-16 15:41:06 +00:00
|
|
|
addr.multi = VIR_DEVICE_ADDRESS_PCI_MULTI_ON;
|
2012-05-14 10:16:22 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2:
|
|
|
|
addr.function = 1;
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3:
|
|
|
|
addr.function = 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr.slot == 0) {
|
|
|
|
/* This is the first part of the controller, so need
|
|
|
|
* to find a free slot & then reserve a function */
|
|
|
|
int slot = qemuDomainPCIAddressGetNextSlot(addrs);
|
|
|
|
if (slot < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
addr.slot = slot;
|
|
|
|
addrs->nextslot = addr.slot + 1;
|
|
|
|
if (QEMU_PCI_ADDRESS_LAST_SLOT < addrs->nextslot)
|
|
|
|
addrs->nextslot = 0;
|
|
|
|
}
|
|
|
|
/* Finally we can reserve the slot+function */
|
|
|
|
if (qemuDomainPCIAddressReserveFunction(addrs,
|
|
|
|
addr.slot,
|
|
|
|
addr.function) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
def->controllers[i]->info.addr.pci = addr;
|
|
|
|
} else {
|
|
|
|
if (qemuDomainPCIAddressSetNextAddr(addrs, &def->controllers[i]->info) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2011-10-28 09:57:21 +00:00
|
|
|
/* Disks (VirtIO only for now) */
|
2010-12-16 15:07:07 +00:00
|
|
|
for (i = 0; i < def->ndisks ; i++) {
|
|
|
|
/* Only VirtIO disks use PCI addrs */
|
|
|
|
if (def->disks[i]->bus != VIR_DOMAIN_DISK_BUS_VIRTIO)
|
|
|
|
continue;
|
|
|
|
|
2012-06-29 15:02:05 +00:00
|
|
|
/* don't touch s390 devices */
|
|
|
|
if (def->disks[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI ||
|
|
|
|
def->disks[i]->info.type ==
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390)
|
2011-10-28 09:57:21 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (def->disks[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("virtio only support device address type 'PCI'"));
|
2011-10-28 09:57:21 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (qemuDomainPCIAddressSetNextAddr(addrs, &def->disks[i]->info) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Host PCI devices */
|
|
|
|
for (i = 0; i < def->nhostdevs ; i++) {
|
2012-01-31 09:16:54 +00:00
|
|
|
if (def->hostdevs[i]->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
|
2010-12-16 15:07:07 +00:00
|
|
|
continue;
|
|
|
|
if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
|
|
|
|
def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
|
|
|
|
continue;
|
|
|
|
|
2012-01-31 09:16:54 +00:00
|
|
|
if (qemuDomainPCIAddressSetNextAddr(addrs, def->hostdevs[i]->info) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* VirtIO balloon */
|
|
|
|
if (def->memballoon &&
|
|
|
|
def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO &&
|
|
|
|
def->memballoon->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
|
|
|
|
if (qemuDomainPCIAddressSetNextAddr(addrs, &def->memballoon->info) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2011-01-11 13:37:52 +00:00
|
|
|
/* A watchdog - skip IB700, it is not a PCI device */
|
2010-12-16 15:07:07 +00:00
|
|
|
if (def->watchdog &&
|
2011-01-11 13:37:52 +00:00
|
|
|
def->watchdog->model != VIR_DOMAIN_WATCHDOG_MODEL_IB700 &&
|
2010-12-16 15:07:07 +00:00
|
|
|
def->watchdog->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
|
|
|
|
if (qemuDomainPCIAddressSetNextAddr(addrs, &def->watchdog->info) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Further non-primary video cards */
|
|
|
|
for (i = 1; i < def->nvideos ; i++) {
|
|
|
|
if (def->videos[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
|
|
|
|
continue;
|
|
|
|
if (qemuDomainPCIAddressSetNextAddr(addrs, &def->videos[i]->info) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->ninputs ; i++) {
|
|
|
|
/* Nada - none are PCI based (yet) */
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nparallels ; i++) {
|
|
|
|
/* Nada - none are PCI based (yet) */
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nserials ; i++) {
|
|
|
|
/* Nada - none are PCI based (yet) */
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nchannels ; i++) {
|
|
|
|
/* Nada - none are PCI based (yet) */
|
|
|
|
}
|
2011-09-02 14:20:40 +00:00
|
|
|
for (i = 0; i < def->nhubs ; i++) {
|
|
|
|
/* Nada - none are PCI based (yet) */
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-09-02 14:49:42 +00:00
|
|
|
static void
|
|
|
|
qemuUsbId(virBufferPtr buf, int idx)
|
|
|
|
{
|
|
|
|
if (idx == 0)
|
|
|
|
virBufferAsprintf(buf, "usb");
|
|
|
|
else
|
|
|
|
virBufferAsprintf(buf, "usb%d", idx);
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
qemuBuildDeviceAddressStr(virBufferPtr buf,
|
2011-02-01 16:22:01 +00:00
|
|
|
virDomainDeviceInfoPtr info,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
|
|
|
if (info->addr.pci.domain != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Only PCI device addresses with domain=0 are supported"));
|
2010-12-16 15:07:07 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (info->addr.pci.bus != 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Only PCI device addresses with bus=0 are supported"));
|
2010-12-16 15:07:07 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_PCI_MULTIFUNCTION)) {
|
2011-05-23 06:42:21 +00:00
|
|
|
if (info->addr.pci.function > 7) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("The function of PCI device addresses must "
|
|
|
|
"less than 8"));
|
2011-05-23 06:42:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
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"));
|
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
|
|
|
return -1;
|
|
|
|
}
|
2012-08-16 15:41:06 +00:00
|
|
|
if (info->addr.pci.multi == VIR_DEVICE_ADDRESS_PCI_MULTI_ON) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("'multifunction=on' is not supported with "
|
|
|
|
"this QEMU binary"));
|
2011-05-23 06:42:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX
|
|
|
|
* When QEMU grows support for > 1 PCI bus, then pci.0 changes
|
|
|
|
* to pci.1, pci.2, etc
|
|
|
|
* When QEMU grows support for > 1 PCI domain, then pci.0 change
|
|
|
|
* to pciNN.0 where NN is the domain number
|
|
|
|
*/
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_PCI_MULTIBUS))
|
2011-05-23 06:42:21 +00:00
|
|
|
virBufferAsprintf(buf, ",bus=pci.0");
|
|
|
|
else
|
|
|
|
virBufferAsprintf(buf, ",bus=pci");
|
2012-08-16 15:41:06 +00:00
|
|
|
if (info->addr.pci.multi == VIR_DEVICE_ADDRESS_PCI_MULTI_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");
|
2012-08-16 15:41:06 +00:00
|
|
|
else if (info->addr.pci.multi == VIR_DEVICE_ADDRESS_PCI_MULTI_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) {
|
2011-09-02 14:49:42 +00:00
|
|
|
virBufferAsprintf(buf, ",bus=");
|
|
|
|
qemuUsbId(buf, info->addr.usb.bus);
|
|
|
|
virBufferAsprintf(buf, ".0,port=%s", 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);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2011-09-02 13:28:27 +00:00
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-01-25 00:54:12 +00:00
|
|
|
static int
|
|
|
|
qemuBuildRomStr(virBufferPtr buf,
|
|
|
|
virDomainDeviceInfoPtr info,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
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;
|
|
|
|
}
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, 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) {
|
|
|
|
case VIR_DOMAIN_PCI_ROMBAR_OFF:
|
|
|
|
virBufferAddLit(buf, ",rombar=0");
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_PCI_ROMBAR_ON:
|
|
|
|
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,
|
|
|
|
enum virDomainIoEventFd use,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2011-06-20 08:26:47 +00:00
|
|
|
{
|
2012-08-20 16:44:14 +00:00
|
|
|
if (use && qemuCapsGet(caps, QEMU_CAPS_VIRTIO_IOEVENTFD))
|
2011-06-20 08:26:47 +00:00
|
|
|
virBufferAsprintf(buf, ",ioeventfd=%s",
|
|
|
|
virDomainIoEventFdTypeToString(use));
|
|
|
|
return 0;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
#define QEMU_SERIAL_PARAM_ACCEPTED_CHARS \
|
|
|
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-03-09 19:13:30 +00:00
|
|
|
|
2011-11-01 01:29:07 +00:00
|
|
|
static int
|
|
|
|
qemuBuildRBDString(virConnectPtr conn,
|
|
|
|
virDomainDiskDefPtr disk,
|
|
|
|
virBufferPtr opt)
|
|
|
|
{
|
|
|
|
int i, ret = 0;
|
|
|
|
virSecretPtr sec = NULL;
|
|
|
|
char *secret = NULL;
|
|
|
|
size_t secret_size;
|
|
|
|
|
2012-03-09 19:13:30 +00:00
|
|
|
virBufferEscape(opt, ',', ",", "rbd:%s", disk->src);
|
2011-11-01 01:29:07 +00:00
|
|
|
if (disk->auth.username) {
|
2012-03-09 19:13:30 +00:00
|
|
|
virBufferEscape(opt, '\\', ":", ":id=%s", disk->auth.username);
|
2011-11-01 01:29:07 +00:00
|
|
|
/* look up secret */
|
|
|
|
switch (disk->auth.secretType) {
|
|
|
|
case VIR_DOMAIN_DISK_SECRET_TYPE_UUID:
|
|
|
|
sec = virSecretLookupByUUID(conn,
|
|
|
|
disk->auth.secret.uuid);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_SECRET_TYPE_USAGE:
|
|
|
|
sec = virSecretLookupByUsage(conn,
|
|
|
|
VIR_SECRET_USAGE_TYPE_CEPH,
|
|
|
|
disk->auth.secret.usage);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sec) {
|
|
|
|
char *base64 = NULL;
|
|
|
|
|
|
|
|
secret = (char *)conn->secretDriver->getValue(sec, &secret_size, 0,
|
|
|
|
VIR_SECRET_GET_VALUE_INTERNAL_CALL);
|
|
|
|
if (secret == NULL) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("could not get the value of the secret for username %s"),
|
|
|
|
disk->auth.username);
|
2011-11-01 01:29:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
/* qemu/librbd wants it base64 encoded */
|
|
|
|
base64_encode_alloc(secret, secret_size, &base64);
|
|
|
|
if (!base64) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
2012-03-09 19:13:30 +00:00
|
|
|
virBufferEscape(opt, '\\', ":",
|
2012-05-01 05:56:08 +00:00
|
|
|
":key=%s:auth_supported=cephx\\;none",
|
2011-11-01 01:29:07 +00:00
|
|
|
base64);
|
|
|
|
VIR_FREE(base64);
|
|
|
|
} else {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("rbd username '%s' specified but secret not found"),
|
|
|
|
disk->auth.username);
|
2011-11-01 01:29:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-06-25 15:44:01 +00:00
|
|
|
} else {
|
|
|
|
virBufferAddLit(opt, ":auth_supported=none");
|
2011-11-01 01:29:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->nhosts > 0) {
|
|
|
|
virBufferAddLit(opt, ":mon_host=");
|
|
|
|
for (i = 0; i < disk->nhosts; ++i) {
|
|
|
|
if (i) {
|
|
|
|
virBufferAddLit(opt, "\\;");
|
|
|
|
}
|
|
|
|
if (disk->hosts[i].port) {
|
|
|
|
virBufferAsprintf(opt, "%s\\:%s",
|
|
|
|
disk->hosts[i].name,
|
|
|
|
disk->hosts[i].port);
|
|
|
|
} else {
|
|
|
|
virBufferAsprintf(opt, "%s", disk->hosts[i].name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(secret);
|
Convert public datatypes to inherit from virObject
This converts the following public API datatypes to use the
virObject infrastructure:
virConnectPtr
virDomainPtr
virDomainSnapshotPtr
virInterfacePtr
virNetworkPtr
virNodeDevicePtr
virNWFilterPtr
virSecretPtr
virStreamPtr
virStorageVolPtr
virStoragePoolPtr
The code is significantly simplified, since the mutex in the
virConnectPtr object now only needs to be held when accessing
the per-connection virError object instance. All other operations
are completely lock free.
* src/datatypes.c, src/datatypes.h, src/libvirt.c: Convert
public datatypes to use virObject
* src/conf/domain_event.c, src/phyp/phyp_driver.c,
src/qemu/qemu_command.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c, src/storage/storage_driver.c,
src/vbox/vbox_tmpl.c, src/xen/xend_internal.c,
tests/qemuxml2argvtest.c, tests/qemuxmlnstest.c,
tests/sexpr2xmltest.c, tests/xmconfigtest.c: Convert
to use virObjectUnref/virObjectRef
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2012-07-31 16:55:36 +00:00
|
|
|
virObjectUnref(sec);
|
2011-11-01 01:29:07 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
error:
|
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int qemuAddRBDHost(virDomainDiskDefPtr disk, char *hostport)
|
|
|
|
{
|
|
|
|
char *port;
|
|
|
|
|
|
|
|
disk->nhosts++;
|
|
|
|
if (VIR_REALLOC_N(disk->hosts, disk->nhosts) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
port = strstr(hostport, "\\:");
|
|
|
|
if (port) {
|
|
|
|
*port = '\0';
|
|
|
|
port += 2;
|
|
|
|
disk->hosts[disk->nhosts-1].port = strdup(port);
|
|
|
|
if (!disk->hosts[disk->nhosts-1].port)
|
|
|
|
goto no_memory;
|
|
|
|
} else {
|
|
|
|
disk->hosts[disk->nhosts-1].port = strdup("6789");
|
|
|
|
if (!disk->hosts[disk->nhosts-1].port)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
disk->hosts[disk->nhosts-1].name = strdup(hostport);
|
|
|
|
if (!disk->hosts[disk->nhosts-1].name)
|
|
|
|
goto no_memory;
|
2012-11-22 18:10:38 +00:00
|
|
|
|
|
|
|
disk->hosts[disk->nhosts-1].transport = VIR_DOMAIN_DISK_PROTO_TRANS_TCP;
|
|
|
|
disk->hosts[disk->nhosts-1].socket = NULL;
|
|
|
|
|
2011-11-01 01:29:07 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
VIR_FREE(disk->hosts[disk->nhosts-1].port);
|
|
|
|
VIR_FREE(disk->hosts[disk->nhosts-1].name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* disk->src initially has everything after the rbd: prefix */
|
|
|
|
static int qemuParseRBDString(virDomainDiskDefPtr disk)
|
|
|
|
{
|
|
|
|
char *options = NULL;
|
|
|
|
char *p, *e, *next;
|
|
|
|
|
|
|
|
p = strchr(disk->src, ':');
|
|
|
|
if (p) {
|
|
|
|
options = strdup(p + 1);
|
|
|
|
if (!options)
|
|
|
|
goto no_memory;
|
|
|
|
*p = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
/* options */
|
|
|
|
if (!options)
|
|
|
|
return 0; /* all done */
|
|
|
|
|
|
|
|
p = options;
|
|
|
|
while (*p) {
|
|
|
|
/* find : delimiter or end of string */
|
|
|
|
for (e = p; *e && *e != ':'; ++e) {
|
|
|
|
if (*e == '\\') {
|
|
|
|
e++;
|
|
|
|
if (*e == '\0')
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (*e == '\0') {
|
|
|
|
next = e; /* last kv pair */
|
|
|
|
} else {
|
|
|
|
next = e + 1;
|
|
|
|
*e = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (STRPREFIX(p, "id=")) {
|
|
|
|
disk->auth.username = strdup(p + strlen("id="));
|
|
|
|
if (!disk->auth.username)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
if (STRPREFIX(p, "mon_host=")) {
|
|
|
|
char *h, *sep;
|
|
|
|
|
|
|
|
h = p + strlen("mon_host=");
|
|
|
|
while (h < e) {
|
|
|
|
for (sep = h; sep < e; ++sep) {
|
|
|
|
if (*sep == '\\' && (sep[1] == ',' ||
|
|
|
|
sep[1] == ';' ||
|
|
|
|
sep[1] == ' ')) {
|
|
|
|
*sep = '\0';
|
|
|
|
sep += 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (qemuAddRBDHost(disk, h) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
h = sep;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p = next;
|
|
|
|
}
|
2012-01-06 06:36:34 +00:00
|
|
|
VIR_FREE(options);
|
2011-11-01 01:29:07 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
no_memory:
|
2012-01-06 06:36:34 +00:00
|
|
|
VIR_FREE(options);
|
2011-11-01 01:29:07 +00:00
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-22 18:10:39 +00:00
|
|
|
static int
|
|
|
|
qemuParseGlusterString(virDomainDiskDefPtr def)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
char *transp = NULL;
|
|
|
|
char *sock = NULL;
|
|
|
|
char *volimg = NULL;
|
|
|
|
virURIPtr uri = NULL;
|
|
|
|
|
|
|
|
if (!(uri = virURIParse(def->src))) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def->hosts) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (STREQ(uri->scheme, "gluster")) {
|
|
|
|
def->hosts->transport = VIR_DOMAIN_DISK_PROTO_TRANS_TCP;
|
|
|
|
} else if (STRPREFIX(uri->scheme, "gluster+")) {
|
|
|
|
transp = strchr(uri->scheme, '+') + 1;
|
|
|
|
def->hosts->transport = virDomainDiskProtocolTransportTypeFromString(transp);
|
|
|
|
if (def->hosts->transport < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Invalid gluster transport type '%s'"), transp);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Invalid transport/scheme '%s'"), uri->scheme);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
def->nhosts = 0; /* set to 1 once everything succeeds */
|
|
|
|
|
|
|
|
if (def->hosts->transport != VIR_DOMAIN_DISK_PROTO_TRANS_UNIX) {
|
|
|
|
def->hosts->name = strdup(uri->server);
|
|
|
|
if (!def->hosts->name)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (virAsprintf(&def->hosts->port, "%d", uri->port) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
} else {
|
|
|
|
def->hosts->name = NULL;
|
|
|
|
def->hosts->port = 0;
|
|
|
|
if (uri->query) {
|
|
|
|
if (STRPREFIX(uri->query, "socket=")) {
|
|
|
|
sock = strchr(uri->query, '=') + 1;
|
|
|
|
def->hosts->socket = strdup(sock);
|
|
|
|
if (!def->hosts->socket)
|
|
|
|
goto no_memory;
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Invalid query parameter '%s'"), uri->query);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
volimg = uri->path + 1; /* skip the prefix slash */
|
|
|
|
def->src = strdup(volimg);
|
|
|
|
if (!def->src)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
def->nhosts = 1;
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virURIFree(uri);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
error:
|
|
|
|
virDomainDiskHostDefFree(def->hosts);
|
|
|
|
VIR_FREE(def->hosts);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuBuildGlusterString(virDomainDiskDefPtr disk, virBufferPtr opt)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
int port = 0;
|
|
|
|
char *tmpscheme = NULL;
|
|
|
|
char *volimg = NULL;
|
|
|
|
char *sock = NULL;
|
|
|
|
char *builturi = NULL;
|
|
|
|
const char *transp = NULL;
|
|
|
|
virURI uri = {
|
|
|
|
.port = port /* just to clear rest of bits */
|
|
|
|
};
|
|
|
|
|
|
|
|
if (disk->nhosts != 1) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("gluster accepts only one host"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(opt, "file=");
|
|
|
|
transp = virDomainDiskProtocolTransportTypeToString(disk->hosts->transport);
|
|
|
|
|
|
|
|
if (virAsprintf(&tmpscheme, "gluster+%s", transp) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (virAsprintf(&volimg, "/%s", disk->src) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (disk->hosts->port) {
|
|
|
|
port = atoi(disk->hosts->port);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->hosts->socket &&
|
|
|
|
virAsprintf(&sock, "socket=%s", disk->hosts->socket) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
uri.scheme = tmpscheme; /* gluster+<transport> */
|
|
|
|
uri.server = disk->hosts->name;
|
|
|
|
uri.port = port;
|
|
|
|
uri.path = volimg;
|
|
|
|
uri.query = sock;
|
|
|
|
|
|
|
|
builturi = virURIFormat(&uri);
|
|
|
|
virBufferEscape(opt, ',', ",", "%s", builturi);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(builturi);
|
|
|
|
VIR_FREE(tmpscheme);
|
|
|
|
VIR_FREE(volimg);
|
|
|
|
VIR_FREE(sock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
char *
|
2011-10-31 19:06:23 +00:00
|
|
|
qemuBuildDriveStr(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
virDomainDiskDefPtr disk,
|
2011-05-26 14:15:01 +00:00
|
|
|
bool bootable,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
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;
|
|
|
|
|
|
|
|
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:
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_VIRTIO_S390) &&
|
2012-06-29 15:02:05 +00:00
|
|
|
(disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390)) {
|
|
|
|
/* Paranoia - leave in here for now */
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unexpected address type for s390-virtio disk"));
|
2012-06-29 15:02:05 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
idx = -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_DISK_BUS_XEN:
|
|
|
|
/* Xen has no address type currently, so assign based on index */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* disk->src is NULL when we use nbd disks */
|
2012-03-14 15:26:48 +00:00
|
|
|
if ((disk->src ||
|
|
|
|
(disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
|
|
|
|
disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_NBD)) &&
|
|
|
|
!((disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY ||
|
|
|
|
disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
|
|
|
|
disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
if (disk->type == VIR_DOMAIN_DISK_TYPE_DIR) {
|
|
|
|
/* QEMU only supports magic FAT format for now */
|
2012-10-15 21:47:42 +00:00
|
|
|
if (disk->format > 0 && disk->format != VIR_STORAGE_FILE_FAT) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported disk driver type for '%s'"),
|
2012-10-15 21:47:42 +00:00
|
|
|
virStorageFileFormatTypeToString(disk->format));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!disk->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;
|
|
|
|
}
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
|
2012-03-09 19:13:30 +00:00
|
|
|
virBufferEscape(&opt, ',', ",", "file=fat:floppy:%s,",
|
|
|
|
disk->src);
|
2010-12-16 15:07:07 +00:00
|
|
|
else
|
2012-03-09 19:13:30 +00:00
|
|
|
virBufferEscape(&opt, ',', ",", "file=fat:%s,", disk->src);
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) {
|
|
|
|
switch (disk->protocol) {
|
|
|
|
case VIR_DOMAIN_DISK_PROTOCOL_NBD:
|
|
|
|
if (disk->nhosts != 1) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("NBD accepts only one host"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&opt, "file=nbd:%s:%s,",
|
2010-12-16 15:07:07 +00:00
|
|
|
disk->hosts->name, disk->hosts->port);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_PROTOCOL_RBD:
|
2011-11-01 01:29:07 +00:00
|
|
|
virBufferAddLit(&opt, "file=");
|
|
|
|
if (qemuBuildRBDString(conn, disk, &opt) < 0)
|
|
|
|
goto error;
|
|
|
|
virBufferAddChar(&opt, ',');
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
2012-11-22 18:10:39 +00:00
|
|
|
case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER:
|
|
|
|
if (qemuBuildGlusterString(disk, &opt) < 0)
|
|
|
|
goto error;
|
|
|
|
virBufferAddChar(&opt, ',');
|
|
|
|
break;
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
|
2012-03-09 19:13:30 +00:00
|
|
|
if (disk->nhosts == 0) {
|
|
|
|
virBufferEscape(&opt, ',', ",", "file=sheepdog:%s,",
|
|
|
|
disk->src);
|
|
|
|
} else {
|
2010-12-16 15:07:07 +00:00
|
|
|
/* only one host is supported now */
|
2012-03-09 19:13:30 +00:00
|
|
|
virBufferAsprintf(&opt, "file=sheepdog:%s:%s:",
|
|
|
|
disk->hosts->name, disk->hosts->port);
|
|
|
|
virBufferEscape(&opt, ',', ",", "%s,", disk->src);
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2012-03-14 15:26:49 +00:00
|
|
|
if ((disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) &&
|
|
|
|
(disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("tray status 'open' is invalid for "
|
|
|
|
"block type disk"));
|
2012-03-14 15:26:49 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-03-09 19:13:30 +00:00
|
|
|
virBufferEscape(&opt, ',', ",", "file=%s,", disk->src);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, 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) {
|
|
|
|
if ((disk->bus == VIR_DOMAIN_DISK_BUS_SCSI)) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, 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) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, 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
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, 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 &&
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsGet(caps, 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");
|
|
|
|
if (disk->readonly &&
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsGet(caps, QEMU_CAPS_DRIVE_READONLY))
|
2010-12-16 15:07:07 +00:00
|
|
|
virBufferAddLit(&opt, ",readonly=on");
|
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-10-15 21:47:42 +00:00
|
|
|
if (disk->format > 0 &&
|
2010-12-16 15:07:07 +00:00
|
|
|
disk->type != VIR_DOMAIN_DISK_TYPE_DIR &&
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsGet(caps, QEMU_CAPS_DRIVE_FORMAT))
|
2012-10-15 21:47:42 +00:00
|
|
|
virBufferAsprintf(&opt, ",format=%s",
|
|
|
|
virStorageFileFormatTypeToString(disk->format));
|
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)
|
|
|
|
virBufferEscapeString(&opt, ",trans=%s", trans);
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (disk->serial &&
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsGet(caps, QEMU_CAPS_DRIVE_SERIAL)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
if (qemuSafeSerialParamValue(disk->serial) < 0)
|
|
|
|
goto error;
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&opt, ",serial=%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;
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DRIVE_CACHE_V2)) {
|
2011-09-02 13:36:58 +00:00
|
|
|
mode = qemuDiskCacheV2TypeToString(disk->cachemode);
|
|
|
|
|
|
|
|
if (disk->cachemode == VIR_DOMAIN_DISK_CACHE_DIRECTSYNC &&
|
2012-08-20 16:44:14 +00:00
|
|
|
!qemuCapsGet(caps, QEMU_CAPS_DRIVE_CACHE_DIRECTSYNC)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("disk cache mode 'directsync' is not "
|
|
|
|
"supported by this QEMU"));
|
2011-09-02 13:36:58 +00:00
|
|
|
goto error;
|
2011-09-22 19:33:47 +00:00
|
|
|
} else if (disk->cachemode == VIR_DOMAIN_DISK_CACHE_UNSAFE &&
|
2012-08-20 16:44:14 +00:00
|
|
|
!qemuCapsGet(caps, QEMU_CAPS_DRIVE_CACHE_UNSAFE)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("disk cache mode 'unsafe' is not "
|
|
|
|
"supported by this QEMU"));
|
2011-09-22 19:33:47 +00:00
|
|
|
goto error;
|
2011-09-02 13:36:58 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
mode = qemuDiskCacheV1TypeToString(disk->cachemode);
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&opt, ",cache=%s", mode);
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (disk->shared && !disk->readonly) {
|
|
|
|
virBufferAddLit(&opt, ",cache=off");
|
|
|
|
}
|
|
|
|
|
2012-01-12 09:31:14 +00:00
|
|
|
if (disk->copy_on_read) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DRIVE_COPY_ON_READ)) {
|
2012-01-12 09:31:14 +00:00
|
|
|
virBufferAsprintf(&opt, ",copy-on-read=%s",
|
|
|
|
virDomainDiskCopyOnReadTypeToString(disk->copy_on_read));
|
|
|
|
} 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, 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) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, 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) &&
|
2012-08-20 16:44:14 +00:00
|
|
|
!qemuCapsGet(caps, 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;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (virBufferError(&opt)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&opt);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&opt);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
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
|
|
|
qemuBuildDriveDevStr(virDomainDefPtr def,
|
|
|
|
virDomainDiskDefPtr disk,
|
2011-05-26 14:15:01 +00:00
|
|
|
int bootindex,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
|
|
|
const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
|
|
|
|
int idx = virDiskNameToIndex(disk->dst);
|
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
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-09-11 08:57:04 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-06 10:23:02 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
/* make sure that both the bus and the qemu binary support
|
|
|
|
* type='lun' (SG_IO).
|
|
|
|
*/
|
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->bus != VIR_DOMAIN_DISK_BUS_VIRTIO &&
|
|
|
|
disk->bus != VIR_DOMAIN_DISK_BUS_SCSI) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("disk device='lun' is not supported for bus='%s'"),
|
|
|
|
bus);
|
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
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (disk->type != VIR_DOMAIN_DISK_TYPE_BLOCK) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("disk device='lun' is not supported for type='%s'"),
|
|
|
|
virDomainDiskTypeToString(disk->type));
|
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
|
|
|
goto error;
|
|
|
|
}
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_VIRTIO_BLK_SG_IO)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("disk device='lun' is not supported by this QEMU"));
|
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
|
|
|
goto error;
|
|
|
|
}
|
2012-09-11 08:57:04 +00:00
|
|
|
if (disk->wwn) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Setting wwn is not supported for lun device"));
|
|
|
|
goto error;
|
|
|
|
}
|
2012-12-06 10:23:02 +00:00
|
|
|
if (disk->vendor || disk->product) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Setting vendor or product is not supported "
|
|
|
|
"for lun device"));
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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 &&
|
|
|
|
!qemuCapsGet(caps, QEMU_CAPS_IDE_DRIVE_WWN)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Setting wwn for ide disk is not supported "
|
|
|
|
"by this QEMU"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, 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");
|
|
|
|
}
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&opt, ",bus=ide.%d,unit=%d",
|
2010-12-16 15:07:07 +00:00
|
|
|
disk->info.addr.drive.bus,
|
|
|
|
disk->info.addr.drive.unit);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_BUS_SCSI:
|
2012-03-12 14:19:56 +00:00
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, 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 &&
|
|
|
|
!qemuCapsGet(caps, QEMU_CAPS_SCSI_DISK_WWN)) {
|
|
|
|
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) &&
|
|
|
|
!qemuCapsGet(caps, QEMU_CAPS_SCSI_DISK_WWN)) {
|
|
|
|
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 =
|
|
|
|
virDomainDiskFindControllerModel(def, disk,
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_SCSI);
|
2012-08-20 16:44:14 +00:00
|
|
|
if ((qemuSetScsiControllerModel(def, caps, &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
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-04-17 09:08:05 +00:00
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
|
2012-03-12 14:19:56 +00:00
|
|
|
virBufferAddLit(&opt, "scsi-block");
|
2012-04-17 09:08:05 +00:00
|
|
|
} else {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_SCSI_CD)) {
|
2012-04-17 09:08:05 +00:00
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
|
|
|
|
virBufferAddLit(&opt, "scsi-cd");
|
|
|
|
else
|
|
|
|
virBufferAddLit(&opt, "scsi-hd");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(&opt, "scsi-disk");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
virBufferAsprintf(&opt, ",bus=scsi%d.%d,scsi-id=%d",
|
|
|
|
disk->info.addr.drive.controller,
|
|
|
|
disk->info.addr.drive.bus,
|
|
|
|
disk->info.addr.drive.unit);
|
|
|
|
} else {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((disk->info.addr.drive.bus != disk->info.addr.drive.unit) &&
|
|
|
|
(disk->info.addr.drive.bus != 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-17 09:08:05 +00:00
|
|
|
if (disk->device != VIR_DOMAIN_DISK_DEVICE_LUN) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_SCSI_CD)) {
|
2012-04-17 09:08:05 +00:00
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
|
|
|
|
virBufferAddLit(&opt, "scsi-cd");
|
|
|
|
else
|
|
|
|
virBufferAddLit(&opt, "scsi-hd");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(&opt, "scsi-disk");
|
|
|
|
}
|
|
|
|
} else {
|
2012-03-12 14:19:56 +00:00
|
|
|
virBufferAddLit(&opt, "scsi-block");
|
2012-04-17 09:08:05 +00:00
|
|
|
}
|
2012-03-12 14:19:56 +00:00
|
|
|
|
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
|
|
|
virBufferAsprintf(&opt, ",bus=scsi%d.0,channel=%d,scsi-id=%d,lun=%d",
|
|
|
|
disk->info.addr.drive.controller,
|
|
|
|
disk->info.addr.drive.bus,
|
|
|
|
disk->info.addr.drive.target,
|
|
|
|
disk->info.addr.drive.unit);
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
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
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, 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");
|
|
|
|
}
|
|
|
|
|
2011-09-28 03:46:08 +00:00
|
|
|
virBufferAsprintf(&opt, ",bus=ahci%d.%d",
|
|
|
|
disk->info.addr.drive.controller,
|
|
|
|
disk->info.addr.drive.unit);
|
|
|
|
break;
|
2010-12-16 15:07:07 +00:00
|
|
|
case VIR_DOMAIN_DISK_BUS_VIRTIO:
|
2012-06-29 15:02:05 +00:00
|
|
|
if (disk->info.type ==
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
|
|
|
|
virBufferAddLit(&opt, "virtio-blk-s390");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(&opt, "virtio-blk-pci");
|
|
|
|
}
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuBuildIoEventFdStr(&opt, disk->ioeventfd, caps);
|
2011-08-13 06:32:45 +00:00
|
|
|
if (disk->event_idx &&
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsGet(caps, QEMU_CAPS_VIRTIO_BLK_EVENT_IDX)) {
|
2011-08-13 06:32:45 +00:00
|
|
|
virBufferAsprintf(&opt, ",event_idx=%s",
|
|
|
|
virDomainVirtioEventIdxTypeToString(disk->event_idx));
|
|
|
|
}
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, 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");
|
|
|
|
}
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&opt, &disk->info, caps) < 0)
|
2011-09-16 15:51:20 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_BUS_USB:
|
|
|
|
virBufferAddLit(&opt, "usb-storage");
|
2012-10-26 09:09:21 +00:00
|
|
|
|
|
|
|
if (qemuBuildDeviceAddressStr(&opt, &disk->info, caps) < 0)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
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;
|
|
|
|
}
|
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);
|
2012-08-20 16:44:14 +00:00
|
|
|
if (bootindex && qemuCapsGet(caps, QEMU_CAPS_BOOTINDEX))
|
2011-05-26 14:15:01 +00:00
|
|
|
virBufferAsprintf(&opt, ",bootindex=%d", bootindex);
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, 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
|
|
|
|
2012-09-11 08:57:04 +00:00
|
|
|
if (disk->wwn)
|
|
|
|
virBufferAsprintf(&opt, ",wwn=%s", disk->wwn);
|
|
|
|
|
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);
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (virBufferError(&opt)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&opt);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&opt);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *qemuBuildFSStr(virDomainFSDefPtr fs,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps ATTRIBUTE_UNUSED)
|
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) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_FSDEV_WRITEOUT)) {
|
2012-01-17 12:44:18 +00:00
|
|
|
virBufferAsprintf(&opt, ",writeout=%s", wrpolicy);
|
|
|
|
} else {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2012-01-17 12:44:18 +00:00
|
|
|
_("filesystem writeout not supported"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (virBufferError(&opt)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&opt);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&opt);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
2011-02-01 16:22:01 +00:00
|
|
|
qemuBuildFSDevStr(virDomainFSDefPtr fs,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(&opt, "virtio-9p-pci");
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&opt, ",id=%s", fs->info.alias);
|
|
|
|
virBufferAsprintf(&opt, ",fsdev=%s%s", QEMU_FSDEV_HOST_PREFIX, fs->info.alias);
|
|
|
|
virBufferAsprintf(&opt, ",mount_tag=%s", fs->dst);
|
2011-09-16 15:51:20 +00:00
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&opt, &fs->info, caps) < 0)
|
2011-09-16 15:51:20 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (virBufferError(&opt)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&opt);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&opt);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
2012-06-19 10:21:47 +00:00
|
|
|
qemuBuildUSBControllerDevStr(virDomainDefPtr domainDef,
|
|
|
|
virDomainControllerDefPtr def,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps,
|
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) {
|
|
|
|
if (STREQ(domainDef->os.arch, "ppc64"))
|
|
|
|
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
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (flags == -1 || !qemuCapsGet(caps, 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);
|
|
|
|
|
|
|
|
if (def->info.mastertype == VIR_DOMAIN_CONTROLLER_MASTER_USB) {
|
2011-09-02 14:49:42 +00:00
|
|
|
virBufferAsprintf(buf, ",masterbus=");
|
|
|
|
qemuUsbId(buf, def->idx);
|
|
|
|
virBufferAsprintf(buf, ".0,firstport=%d", def->info.master.usb.startport);
|
2011-09-02 14:03:51 +00:00
|
|
|
} else {
|
2011-09-02 14:49:42 +00:00
|
|
|
virBufferAsprintf(buf, ",id=");
|
|
|
|
qemuUsbId(buf, def->idx);
|
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 *
|
2011-12-08 06:41:24 +00:00
|
|
|
qemuBuildControllerDevStr(virDomainDefPtr domainDef,
|
|
|
|
virDomainControllerDefPtr def,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps,
|
2011-09-02 13:21:23 +00:00
|
|
|
int *nusbcontroller)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2012-02-27 09:08:23 +00:00
|
|
|
int model;
|
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
|
|
|
model = def->model;
|
2012-08-20 16:44:14 +00:00
|
|
|
if ((qemuSetScsiControllerModel(domainDef, caps, &model)) < 0)
|
2012-08-08 07:06:33 +00:00
|
|
|
return NULL;
|
|
|
|
|
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:
|
|
|
|
virBufferAddLit(&buf, "virtio-scsi-pci");
|
|
|
|
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;
|
|
|
|
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
|
|
|
}
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",id=scsi%d", def->idx);
|
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");
|
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");
|
2010-12-16 15:07:07 +00:00
|
|
|
} else {
|
|
|
|
virBufferAddLit(&buf, "virtio-serial");
|
|
|
|
}
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",id=" QEMU_VIRTIO_SERIAL_PREFIX "%d",
|
2010-12-16 15:07:07 +00:00
|
|
|
def->idx);
|
|
|
|
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:
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "usb-ccid,id=ccid%d", def->idx);
|
2011-01-13 00:09:45 +00:00
|
|
|
break;
|
|
|
|
|
2011-09-28 03:46:08 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_SATA:
|
|
|
|
virBufferAsprintf(&buf, "ahci,id=ahci%d", def->idx);
|
|
|
|
break;
|
|
|
|
|
2011-09-02 13:21:23 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_USB:
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildUSBControllerDevStr(domainDef, def, caps, &buf) == -1)
|
2011-09-02 13:21:23 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (nusbcontroller)
|
|
|
|
*nusbcontroller += 1;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
/* We always get an IDE controller, whether we want it or not. */
|
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
|
|
|
|
default:
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unknown controller type: %s"),
|
|
|
|
virDomainControllerTypeToString(def->type));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, &def->info, caps) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
qemuBuildNicStr(virDomainNetDefPtr net,
|
|
|
|
const char *prefix,
|
|
|
|
int vlan)
|
|
|
|
{
|
|
|
|
char *str;
|
|
|
|
if (virAsprintf(&str,
|
|
|
|
"%smacaddr=%02x:%02x:%02x:%02x:%02x:%02x,vlan=%d%s%s%s%s",
|
|
|
|
prefix ? prefix : "",
|
2012-07-17 12:07:59 +00:00
|
|
|
net->mac.addr[0], net->mac.addr[1],
|
|
|
|
net->mac.addr[2], net->mac.addr[3],
|
|
|
|
net->mac.addr[4], net->mac.addr[5],
|
2010-12-16 15:07:07 +00:00
|
|
|
vlan,
|
|
|
|
(net->model ? ",model=" : ""),
|
|
|
|
(net->model ? net->model : ""),
|
|
|
|
(net->info.alias ? ",name=" : ""),
|
|
|
|
(net->info.alias ? net->info.alias : "")) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
2011-01-12 10:33:34 +00:00
|
|
|
qemuBuildNicDevStr(virDomainNetDefPtr net,
|
|
|
|
int vlan,
|
2011-05-26 14:15:01 +00:00
|
|
|
int bootindex,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
const char *nic;
|
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;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (!net->model) {
|
|
|
|
nic = "rtl8139";
|
|
|
|
} else if (STREQ(net->model, "virtio")) {
|
2012-06-29 15:02:05 +00:00
|
|
|
if (net->info.type ==
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
|
|
|
|
nic = "virtio-net-s390";
|
|
|
|
} else {
|
|
|
|
nic = "virtio-net-pci";
|
|
|
|
}
|
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
|
|
|
} else {
|
|
|
|
nic = net->model;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAdd(&buf, nic, strlen(nic));
|
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) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, 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) {
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuBuildIoEventFdStr(&buf, net->driver.virtio.ioeventfd, caps);
|
2011-08-13 06:32:45 +00:00
|
|
|
if (net->driver.virtio.event_idx &&
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsGet(caps, QEMU_CAPS_VIRTIO_NET_EVENT_IDX)) {
|
2011-08-13 06:32:45 +00:00
|
|
|
virBufferAsprintf(&buf, ",event_idx=%s",
|
|
|
|
virDomainVirtioEventIdxTypeToString(net->driver.virtio.event_idx));
|
|
|
|
}
|
|
|
|
}
|
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);
|
|
|
|
virBufferAsprintf(&buf, ",mac=%02x:%02x:%02x:%02x:%02x:%02x",
|
2012-07-17 12:07:59 +00:00
|
|
|
net->mac.addr[0], net->mac.addr[1],
|
|
|
|
net->mac.addr[2], net->mac.addr[3],
|
|
|
|
net->mac.addr[4], net->mac.addr[5]);
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, &net->info, caps) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildRomStr(&buf, &net->info, caps) < 0)
|
2012-01-25 00:54:12 +00:00
|
|
|
goto error;
|
2012-08-20 16:44:14 +00:00
|
|
|
if (bootindex && qemuCapsGet(caps, QEMU_CAPS_BOOTINDEX))
|
2011-05-26 14:15:01 +00:00
|
|
|
virBufferAsprintf(&buf, ",bootindex=%d", bootindex);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
qemuBuildHostNetStr(virDomainNetDefPtr net,
|
2012-11-28 16:43:10 +00:00
|
|
|
virQEMUDriverPtr driver,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps,
|
2010-12-16 15:07:07 +00:00
|
|
|
char type_sep,
|
|
|
|
int vlan,
|
|
|
|
const char *tapfd,
|
|
|
|
const char *vhostfd)
|
|
|
|
{
|
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;
|
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
|
|
|
enum virDomainNetType netType = virDomainNetGetActualType(net);
|
2012-08-03 20:33:06 +00:00
|
|
|
const char *brname = NULL;
|
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));
|
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
|
|
|
if (!driver->privileged &&
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsGet(caps, QEMU_CAPS_NETDEV_BRIDGE)) {
|
2012-08-03 20:33:06 +00:00
|
|
|
brname = virDomainNetGetActualBridgeName(net);
|
|
|
|
virBufferAsprintf(&buf, "bridge%cbr=%s", type_sep, brname);
|
|
|
|
type_sep = ',';
|
|
|
|
is_tap = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
2010-12-16 15:07:07 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
2012-03-28 17:06:37 +00:00
|
|
|
virBufferAsprintf(&buf, "tap%cfd=%s", type_sep, tapfd);
|
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,
|
|
|
|
net->data.socket.address,
|
|
|
|
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
|
|
|
|
|
|
|
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) {
|
|
|
|
if (vhostfd && *vhostfd)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",vhost=on,vhostfd=%s", vhostfd);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
2011-02-01 16:22:01 +00:00
|
|
|
qemuBuildWatchdogDevStr(virDomainWatchdogDefPtr dev,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
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);
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, &dev->info, caps) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
2011-02-01 16:22:01 +00:00
|
|
|
qemuBuildMemballoonDevStr(virDomainMemballoonDefPtr dev,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "virtio-balloon-pci");
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",id=%s", dev->info.alias);
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, &dev->info, caps) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
2011-09-02 13:28:27 +00:00
|
|
|
qemuBuildUSBInputDevStr(virDomainInputDefPtr dev,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "%s,id=%s",
|
2010-12-16 15:07:07 +00:00
|
|
|
dev->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ?
|
2011-04-14 19:27:47 +00:00
|
|
|
"usb-mouse" : "usb-tablet", dev->info.alias);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, &dev->info, caps) < 0)
|
2011-09-02 13:28:27 +00:00
|
|
|
goto error;
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
2011-02-01 16:22:01 +00:00
|
|
|
qemuBuildSoundDevStr(virDomainSoundDefPtr sound,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
const char *model = virDomainSoundModelTypeToString(sound->model);
|
|
|
|
|
|
|
|
if (!model) {
|
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
|
|
|
/* Hack for weirdly unusual devices name in QEMU */
|
2010-12-16 15:07:07 +00:00
|
|
|
if (STREQ(model, "es1370"))
|
|
|
|
model = "ES1370";
|
|
|
|
else if (STREQ(model, "ac97"))
|
|
|
|
model = "AC97";
|
2011-01-13 14:15:11 +00:00
|
|
|
else if (STREQ(model, "ich6"))
|
|
|
|
model = "intel-hda";
|
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);
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, &sound->info, caps) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
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,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
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
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (flags == -1 || !qemuCapsGet(caps, 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);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
static char *
|
2011-02-01 16:22:01 +00:00
|
|
|
qemuBuildVideoDevStr(virDomainVideoDefPtr video,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
const char *model = qemuVideoTypeToString(video->type);
|
|
|
|
|
|
|
|
if (!model) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("invalid video 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, 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
|
|
|
|
|
|
|
if (video->type == VIR_DOMAIN_VIDEO_TYPE_QXL) {
|
2011-03-15 03:50:09 +00:00
|
|
|
if (video->vram > (UINT_MAX / 1024)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("value for 'vram' must be less than '%u'"),
|
|
|
|
UINT_MAX / 1024);
|
2011-03-15 03:50:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
/* QEMU accepts bytes for vram_size. */
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",vram_size=%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
|
|
|
}
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, &video->info, caps) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuOpenPCIConfig(virDomainHostdevDefPtr dev)
|
|
|
|
{
|
|
|
|
char *path = NULL;
|
|
|
|
int configfd = -1;
|
|
|
|
|
|
|
|
if (virAsprintf(&path, "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/config",
|
|
|
|
dev->source.subsys.u.pci.domain,
|
|
|
|
dev->source.subsys.u.pci.bus,
|
|
|
|
dev->source.subsys.u.pci.slot,
|
|
|
|
dev->source.subsys.u.pci.function) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
configfd = open(path, O_RDWR, 0);
|
|
|
|
|
|
|
|
if (configfd < 0)
|
|
|
|
virReportSystemError(errno, _("Failed opening %s"), path);
|
|
|
|
|
|
|
|
VIR_FREE(path);
|
|
|
|
|
|
|
|
return configfd;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
2011-02-01 16:22:01 +00:00
|
|
|
qemuBuildPCIHostdevDevStr(virDomainHostdevDefPtr dev, const char *configfd,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "pci-assign");
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",host=%.2x:%.2x.%.1x",
|
2010-12-16 15:07:07 +00:00
|
|
|
dev->source.subsys.u.pci.bus,
|
|
|
|
dev->source.subsys.u.pci.slot,
|
|
|
|
dev->source.subsys.u.pci.function);
|
2012-01-31 09:16:54 +00:00
|
|
|
virBufferAsprintf(&buf, ",id=%s", dev->info->alias);
|
2010-12-16 15:07:07 +00:00
|
|
|
if (configfd && *configfd)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",configfd=%s", configfd);
|
2012-01-31 09:16:54 +00:00
|
|
|
if (dev->info->bootIndex)
|
|
|
|
virBufferAsprintf(&buf, ",bootindex=%d", dev->info->bootIndex);
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, dev->info, caps) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildRomStr(&buf, dev->info, caps) < 0)
|
2012-01-25 00:54:12 +00:00
|
|
|
goto error;
|
2011-09-20 17:31:52 +00:00
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
qemuBuildPCIHostdevPCIDevStr(virDomainHostdevDefPtr dev)
|
|
|
|
{
|
|
|
|
char *ret = NULL;
|
|
|
|
|
|
|
|
if (virAsprintf(&ret, "host=%.2x:%.2x.%.1x",
|
|
|
|
dev->source.subsys.u.pci.bus,
|
|
|
|
dev->source.subsys.u.pci.slot,
|
|
|
|
dev->source.subsys.u.pci.function) < 0)
|
|
|
|
virReportOOMError();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-02 15:09:14 +00:00
|
|
|
char *
|
2012-09-13 07:25:46 +00:00
|
|
|
qemuBuildRedirdevDevStr(virDomainDefPtr def,
|
|
|
|
virDomainRedirdevDefPtr dev,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
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;
|
|
|
|
}
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, 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",
|
|
|
|
dev->info.alias,
|
|
|
|
dev->info.alias);
|
|
|
|
|
2012-09-13 07:25:46 +00:00
|
|
|
if (redirfilter && redirfilter->nusbdevs) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, ",filter=");
|
|
|
|
|
|
|
|
for (i = 0; i < redirfilter->nusbdevs; i++) {
|
|
|
|
virDomainRedirFilterUsbDevDefPtr usbdev = redirfilter->usbdevs[i];
|
|
|
|
if (usbdev->usbClass >= 0)
|
|
|
|
virBufferAsprintf(&buf, "0x%02X:", usbdev->usbClass);
|
|
|
|
else
|
|
|
|
virBufferAsprintf(&buf, "-1:");
|
|
|
|
|
|
|
|
if (usbdev->vendor >= 0)
|
|
|
|
virBufferAsprintf(&buf, "0x%04X:", usbdev->vendor);
|
|
|
|
else
|
|
|
|
virBufferAsprintf(&buf, "-1:");
|
|
|
|
|
|
|
|
if (usbdev->product >= 0)
|
|
|
|
virBufferAsprintf(&buf, "0x%04X:", usbdev->product);
|
|
|
|
else
|
|
|
|
virBufferAsprintf(&buf, "-1:");
|
|
|
|
|
|
|
|
if (usbdev->version >= 0)
|
|
|
|
virBufferAsprintf(&buf, "0x%04X:", usbdev->version);
|
|
|
|
else
|
|
|
|
virBufferAsprintf(&buf, "-1:");
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, "%u", usbdev->allow);
|
|
|
|
if (i < redirfilter->nusbdevs -1)
|
|
|
|
virBufferAsprintf(&buf, "|");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-14 14:51:30 +00:00
|
|
|
if (dev->info.bootIndex) {
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_USB_REDIR_BOOTINDEX)) {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, &dev->info, caps) < 0)
|
2011-09-02 15:09:14 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
char *
|
2011-09-02 13:28:27 +00:00
|
|
|
qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
2011-09-02 13:28:27 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-10-04 14:18:16 +00:00
|
|
|
if (!dev->missing &&
|
|
|
|
!dev->source.subsys.u.usb.bus &&
|
2010-12-16 15:07:07 +00:00
|
|
|
!dev->source.subsys.u.usb.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",
|
|
|
|
dev->source.subsys.u.usb.bus,
|
|
|
|
dev->source.subsys.u.usb.device);
|
|
|
|
}
|
|
|
|
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
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, dev->info, caps) < 0)
|
2011-09-02 13:28:27 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virReportOOMError();
|
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);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-02 14:20:40 +00:00
|
|
|
char *
|
|
|
|
qemuBuildHubDevStr(virDomainHubDefPtr dev,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
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;
|
|
|
|
}
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, 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);
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&buf, &dev->info, caps) < 0)
|
2011-09-02 14:20:40 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
char *
|
|
|
|
qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev)
|
|
|
|
{
|
|
|
|
char *ret = NULL;
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (!dev->source.subsys.u.usb.bus &&
|
|
|
|
!dev->source.subsys.u.usb.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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&ret, "host:%d.%d",
|
|
|
|
dev->source.subsys.u.usb.bus,
|
|
|
|
dev->source.subsys.u.usb.device) < 0)
|
|
|
|
virReportOOMError();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 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 *
|
2011-02-03 04:09:44 +00:00
|
|
|
qemuBuildChrChardevStr(virDomainChrSourceDefPtr dev, const char *alias,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
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:
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "file,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_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:
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, 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;
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
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 *
|
|
|
|
qemuBuildChrArgStr(virDomainChrSourceDefPtr dev, const char *prefix)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
if (prefix)
|
|
|
|
virBufferAdd(&buf, prefix, strlen(prefix));
|
|
|
|
|
|
|
|
switch (dev->type) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-04 15:43:32 +00:00
|
|
|
static char *
|
|
|
|
qemuBuildVirtioSerialPortDevStr(virDomainChrDefPtr dev,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
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 &&
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsGet(caps, 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 &&
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf,
|
2010-12-16 15:07:07 +00:00
|
|
|
",bus=" QEMU_VIRTIO_SERIAL_PREFIX "%d.%d",
|
|
|
|
dev->info.addr.vioserial.controller,
|
|
|
|
dev->info.addr.vioserial.bus);
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf,
|
2010-12-16 15:07:07 +00:00
|
|
|
",nr=%d",
|
|
|
|
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 &&
|
2012-03-30 07:16:23 +00:00
|
|
|
STRNEQ_NULLABLE(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 &&
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsGet(caps, 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);
|
2012-03-30 07:16:23 +00:00
|
|
|
if (dev->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL) {
|
|
|
|
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
|
|
|
}
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *qemuBuildSmbiosBiosStr(virSysinfoDefPtr def)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
if ((def->bios_vendor == NULL) && (def->bios_version == NULL) &&
|
|
|
|
(def->bios_date == NULL) && (def->bios_release == NULL))
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
virBufferAddLit(&buf, "type=0");
|
|
|
|
|
|
|
|
/* 0:Vendor */
|
|
|
|
if (def->bios_vendor)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",vendor=%s", def->bios_vendor);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 0:BIOS Version */
|
|
|
|
if (def->bios_version)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",version=%s", def->bios_version);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 0:BIOS Release Date */
|
|
|
|
if (def->bios_date)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",date=%s", def->bios_date);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 0:System BIOS Major Release and 0:System BIOS Minor Release */
|
|
|
|
if (def->bios_release)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",release=%s", def->bios_release);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static char *qemuBuildSmbiosSystemStr(virSysinfoDefPtr def, bool skip_uuid)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
if ((def->system_manufacturer == NULL) && (def->system_sku == NULL) &&
|
|
|
|
(def->system_product == NULL) && (def->system_version == NULL) &&
|
|
|
|
(def->system_serial == NULL) && (def->system_family == NULL) &&
|
|
|
|
(def->system_uuid == NULL || skip_uuid))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "type=1");
|
|
|
|
|
|
|
|
/* 1:Manufacturer */
|
|
|
|
if (def->system_manufacturer)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",manufacturer=%s",
|
2010-12-16 15:07:07 +00:00
|
|
|
def->system_manufacturer);
|
|
|
|
/* 1:Product Name */
|
|
|
|
if (def->system_product)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",product=%s", def->system_product);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 1:Version */
|
|
|
|
if (def->system_version)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",version=%s", def->system_version);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 1:Serial Number */
|
|
|
|
if (def->system_serial)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",serial=%s", def->system_serial);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 1:UUID */
|
|
|
|
if (def->system_uuid && !skip_uuid)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",uuid=%s", def->system_uuid);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 1:SKU Number */
|
|
|
|
if (def->system_sku)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",sku=%s", def->system_sku);
|
2010-12-16 15:07:07 +00:00
|
|
|
/* 1:Family */
|
|
|
|
if (def->system_family)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",family=%s", def->system_family);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
qemuBuildClockArgStr(virDomainClockDefPtr def)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2012-02-06 13:59:16 +00:00
|
|
|
if (def->data.variable.basis != VIR_DOMAIN_CLOCK_BASIS_UTC) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported clock basis '%s'"),
|
|
|
|
virDomainClockBasisTypeToString(def->data.variable.basis));
|
2012-02-06 13:59:16 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
now += def->data.variable.adjustment;
|
2010-12-16 15:07:07 +00:00
|
|
|
gmtime_r(&now, &nowbits);
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Look for an 'rtc' timer element, and add in appropriate clock= and driftfix= */
|
|
|
|
int i;
|
|
|
|
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 */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuBuildCpuArgStr(const virQEMUDriverPtr driver,
|
2010-12-16 15:07:07 +00:00
|
|
|
const virDomainDefPtr def,
|
|
|
|
const char *emulator,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps,
|
2010-12-16 15:07:07 +00:00
|
|
|
const struct utsname *ut,
|
|
|
|
char **opt,
|
2011-12-21 12:47:17 +00:00
|
|
|
bool *hasHwVirt,
|
|
|
|
bool migrating)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
const virCPUDefPtr host = driver->caps->host.cpu;
|
|
|
|
virCPUDefPtr guest = NULL;
|
2011-12-21 12:47:17 +00:00
|
|
|
virCPUDefPtr cpu = 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-01-27 13:49:52 +00:00
|
|
|
const char *default_model;
|
2010-12-16 15:07:07 +00:00
|
|
|
union cpuData *data = NULL;
|
2012-01-27 13:49:52 +00:00
|
|
|
bool have_cpu = false;
|
2012-04-17 13:24:47 +00:00
|
|
|
char *compare_msg = NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
int ret = -1;
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
*hasHwVirt = false;
|
|
|
|
|
2012-01-27 13:49:52 +00:00
|
|
|
if (STREQ(def->os.arch, "i686"))
|
|
|
|
default_model = "qemu32";
|
|
|
|
else
|
|
|
|
default_model = "qemu64";
|
|
|
|
|
2012-02-15 11:18:25 +00:00
|
|
|
if (def->cpu &&
|
|
|
|
(def->cpu->mode != VIR_CPU_MODE_CUSTOM || def->cpu->model)) {
|
2011-12-21 12:47:17 +00:00
|
|
|
virCPUCompareResult cmp;
|
|
|
|
const char *preferred;
|
|
|
|
int hasSVM;
|
|
|
|
|
2012-08-22 15:28:55 +00:00
|
|
|
if (!host ||
|
2012-10-16 19:11:29 +00:00
|
|
|
!host->model ||
|
2012-08-22 15:28:55 +00:00
|
|
|
(ncpus = qemuCapsGetCPUDefinitions(caps, &cpus)) == 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("CPU specification not supported by hypervisor"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-02-15 11:18:25 +00:00
|
|
|
if (!(cpu = virCPUDefCopy(def->cpu)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (cpu->mode != VIR_CPU_MODE_CUSTOM &&
|
|
|
|
!migrating &&
|
|
|
|
cpuUpdate(cpu, host) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2012-04-17 13:24:47 +00:00
|
|
|
cmp = cpuGuestData(host, cpu, &data, &compare_msg);
|
2010-12-16 15:07:07 +00:00
|
|
|
switch (cmp) {
|
|
|
|
case VIR_CPU_COMPARE_INCOMPATIBLE:
|
2012-04-17 13:24:47 +00:00
|
|
|
if (compare_msg) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("guest and host CPU are not compatible: %s"),
|
|
|
|
compare_msg);
|
2012-04-17 13:24:47 +00:00
|
|
|
} else {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("guest CPU is not compatible with host CPU"));
|
2012-04-17 13:24:47 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
/* fall through */
|
|
|
|
case VIR_CPU_COMPARE_ERROR:
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Only 'svm' requires --enable-nesting. The nested
|
|
|
|
* 'vmx' patches now simply hook off the CPU features
|
|
|
|
*/
|
2011-12-21 12:47:17 +00:00
|
|
|
hasSVM = cpuHasFeature(host->arch, data, "svm");
|
2010-12-16 15:07:07 +00:00
|
|
|
if (hasSVM < 0)
|
|
|
|
goto cleanup;
|
|
|
|
*hasHwVirt = hasSVM > 0 ? true : false;
|
|
|
|
|
2011-12-21 12:47:17 +00:00
|
|
|
if (cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) {
|
|
|
|
const char *mode = virCPUModeTypeToString(cpu->mode);
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_CPU_HOST)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("CPU mode '%s' is not supported by QEMU"
|
|
|
|
" binary"), mode);
|
2011-12-21 12:47:17 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (def->virtType != VIR_DOMAIN_VIRT_KVM) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("CPU mode '%s' is only supported with kvm"),
|
|
|
|
mode);
|
2011-12-21 12:47:17 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
virBufferAddLit(&buf, "host");
|
|
|
|
} else {
|
2012-06-28 10:21:17 +00:00
|
|
|
if (VIR_ALLOC(guest) < 0 ||
|
|
|
|
!(guest->arch = strdup(host->arch)) ||
|
|
|
|
(cpu->vendor_id && !(guest->vendor_id = strdup(cpu->vendor_id))))
|
2011-12-21 12:47:17 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (cpu->match == VIR_CPU_MATCH_MINIMUM)
|
|
|
|
preferred = host->model;
|
2010-12-16 15:07:07 +00:00
|
|
|
else
|
2011-12-21 12:47:17 +00:00
|
|
|
preferred = cpu->model;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-12-21 12:47:17 +00:00
|
|
|
guest->type = VIR_CPU_TYPE_GUEST;
|
|
|
|
guest->fallback = cpu->fallback;
|
2012-08-22 15:28:55 +00:00
|
|
|
if (cpuDecode(guest, data, (const char **)cpus, ncpus, preferred) < 0)
|
2011-12-21 12:47:17 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
virBufferAdd(&buf, guest->model, -1);
|
2012-06-28 10:21:17 +00:00
|
|
|
if (guest->vendor_id)
|
|
|
|
virBufferAsprintf(&buf, ",vendor=%s", guest->vendor_id);
|
2011-12-21 12:47:17 +00:00
|
|
|
for (i = 0; i < guest->nfeatures; i++) {
|
|
|
|
char sign;
|
|
|
|
if (guest->features[i].policy == VIR_CPU_FEATURE_DISABLE)
|
|
|
|
sign = '-';
|
|
|
|
else
|
|
|
|
sign = '+';
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, ",%c%s", sign, guest->features[i].name);
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
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
|
|
|
|
*/
|
|
|
|
if (STREQ(def->os.arch, "i686") &&
|
|
|
|
((STREQ(ut->machine, "x86_64") &&
|
|
|
|
strstr(emulator, "kvm")) ||
|
2012-01-27 13:49:52 +00:00
|
|
|
strstr(emulator, "x86_64"))) {
|
|
|
|
virBufferAdd(&buf, default_model, -1);
|
|
|
|
have_cpu = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now force kvmclock on/off based on the corresponding <timer> element. */
|
|
|
|
for (i = 0; i < def->clock.ntimers; i++) {
|
|
|
|
if (def->clock.timers[i]->name == VIR_DOMAIN_TIMER_NAME_KVMCLOCK &&
|
|
|
|
def->clock.timers[i]->present != -1) {
|
|
|
|
char sign;
|
|
|
|
if (def->clock.timers[i]->present)
|
|
|
|
sign = '+';
|
|
|
|
else
|
|
|
|
sign = '-';
|
|
|
|
virBufferAsprintf(&buf, "%s,%ckvmclock",
|
|
|
|
have_cpu ? "" : default_model,
|
|
|
|
sign);
|
2012-10-08 16:51:57 +00:00
|
|
|
have_cpu = true;
|
2012-01-27 13:49:52 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2012-09-13 13:27:07 +00:00
|
|
|
if (def->apic_eoi) {
|
|
|
|
char sign;
|
2012-10-16 14:28:22 +00:00
|
|
|
if (def->apic_eoi == VIR_DOMAIN_FEATURE_STATE_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
|
|
|
}
|
|
|
|
|
2012-10-17 12:55:18 +00:00
|
|
|
if (def->features & (1 << VIR_DOMAIN_FEATURE_HYPERV)) {
|
|
|
|
if (!have_cpu) {
|
|
|
|
virBufferAdd(&buf, default_model, -1);
|
|
|
|
have_cpu = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_DOMAIN_HYPERV_LAST; i++) {
|
|
|
|
switch ((enum virDomainHyperv) i) {
|
|
|
|
case VIR_DOMAIN_HYPERV_RELAXED:
|
|
|
|
if (def->hyperv_features[i] == VIR_DOMAIN_FEATURE_STATE_ON)
|
|
|
|
virBufferAsprintf(&buf, ",hv_%s",
|
|
|
|
virDomainHypervTypeToString(i));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_HYPERV_LAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (virBufferError(&buf))
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
*opt = virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
2012-04-17 13:24:47 +00:00
|
|
|
VIR_FREE(compare_msg);
|
2012-02-15 11:18:25 +00:00
|
|
|
if (host)
|
|
|
|
cpuDataFree(host->arch, data);
|
2010-12-16 15:07:07 +00:00
|
|
|
virCPUDefFree(guest);
|
2011-12-21 12:47:17 +00:00
|
|
|
virCPUDefFree(cpu);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-08-15 07:59:24 +00:00
|
|
|
static int
|
|
|
|
qemuBuildMachineArgStr(virCommandPtr cmd,
|
|
|
|
const virDomainDefPtr def,
|
|
|
|
qemuCapsPtr caps)
|
|
|
|
{
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
if (!def->mem.dump_core) {
|
|
|
|
/* 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);
|
|
|
|
} else {
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_DUMP_GUEST_CORE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("dump-guest-core is not available "
|
|
|
|
" with this QEMU binary"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* However, in case there is a parameter to be added, we need to
|
|
|
|
* use the "-machine" parameter because qemu is not parsing the
|
|
|
|
* "-M" correctly */
|
|
|
|
virCommandAddArg(cmd, "-machine");
|
|
|
|
virCommandAddArgFormat(cmd,
|
|
|
|
"%s,dump-guest-core=%s",
|
|
|
|
def->os.machine,
|
|
|
|
virDomainMemDumpTypeToString(def->mem.dump_core));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
static char *
|
|
|
|
qemuBuildSmpArgStr(const virDomainDefPtr def,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "%u", def->vcpus);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_SMP_TOPOLOGY)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
if (def->vcpus != def->maxvcpus)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",maxcpus=%u", def->maxvcpus);
|
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);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, ",sockets=%u", def->maxvcpus);
|
|
|
|
virBufferAsprintf(&buf, ",cores=%u", 1);
|
|
|
|
virBufferAsprintf(&buf, ",threads=%u", 1);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
} else if (def->vcpus != def->maxvcpus) {
|
|
|
|
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"));
|
2010-12-16 15:07:07 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
|
2011-11-11 12:53:04 +00:00
|
|
|
static int
|
|
|
|
qemuBuildNumaArgStr(const virDomainDefPtr def, virCommandPtr cmd)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2012-09-14 07:47:02 +00:00
|
|
|
char *cpumask;
|
2011-11-11 12:53:04 +00:00
|
|
|
|
|
|
|
for (i = 0; i < def->cpu->ncells; i++) {
|
|
|
|
virCommandAddArg(cmd, "-numa");
|
|
|
|
virBufferAsprintf(&buf, "node,nodeid=%d", def->cpu->cells[i].cellid);
|
|
|
|
virBufferAddLit(&buf, ",cpus=");
|
2012-09-14 07:47:02 +00:00
|
|
|
cpumask = virBitmapFormat(def->cpu->cells[i].cpumask);
|
|
|
|
if (cpumask) {
|
|
|
|
virBufferAsprintf(&buf, "%s", cpumask);
|
|
|
|
VIR_FREE(cpumask);
|
|
|
|
}
|
2012-03-30 15:40:09 +00:00
|
|
|
def->cpu->cells[i].mem = VIR_DIV_UP(def->cpu->cells[i].mem,
|
|
|
|
1024) * 1024;
|
2012-09-14 07:47:02 +00:00
|
|
|
virBufferAsprintf(&buf, ",mem=%d", def->cpu->cells[i].mem / 1024);
|
2011-11-11 12:53:04 +00:00
|
|
|
|
|
|
|
if (virBufferError(&buf))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virCommandAddArgBuffer(cmd, &buf);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
static int
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuBuildGraphicsCommandLine(virQEMUDriverPtr driver,
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandPtr cmd,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
qemuCapsPtr caps,
|
|
|
|
virDomainGraphicsDefPtr graphics)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
2012-11-26 16:25:21 +00:00
|
|
|
int i;
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
|
|
|
|
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_VNC)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("vnc graphics are not supported with this QEMU"));
|
2012-09-11 13:44:40 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (graphics->data.vnc.socket ||
|
|
|
|
driver->vncAutoUnixSocket) {
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (!graphics->data.vnc.socket &&
|
|
|
|
virAsprintf(&graphics->data.vnc.socket,
|
|
|
|
"%s/%s.vnc", driver->libDir, def->name) == -1) {
|
|
|
|
goto no_memory;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virBufferAsprintf(&opt, "unix:%s",
|
|
|
|
graphics->data.vnc.socket);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
} else if (qemuCapsGet(caps, QEMU_CAPS_VNC_COLON)) {
|
|
|
|
const char *listenNetwork;
|
|
|
|
const char *listenAddr = NULL;
|
|
|
|
char *netAddr = NULL;
|
|
|
|
bool escapeAddr;
|
|
|
|
int ret;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
switch (virDomainGraphicsListenGetType(graphics, 0)) {
|
|
|
|
case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS:
|
|
|
|
listenAddr = virDomainGraphicsListenGetAddress(graphics, 0);
|
|
|
|
break;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
if (ret < 0) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("listen network '%s' had no usable address"),
|
|
|
|
listenNetwork);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (!listenAddr)
|
|
|
|
listenAddr = driver->vncListen;
|
|
|
|
|
|
|
|
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);
|
2012-06-01 16:25:33 +00:00
|
|
|
} else {
|
2012-11-10 01:40:23 +00:00
|
|
|
virBufferAsprintf(&opt, "%d",
|
|
|
|
graphics->data.vnc.port - 5900);
|
2012-06-01 16:25:33 +00:00
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_VNC_COLON)) {
|
|
|
|
if (graphics->data.vnc.auth.passwd ||
|
|
|
|
driver->vncPassword)
|
|
|
|
virBufferAddLit(&opt, ",password");
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (driver->vncTLS) {
|
|
|
|
virBufferAddLit(&opt, ",tls");
|
|
|
|
if (driver->vncTLSx509verify) {
|
|
|
|
virBufferAsprintf(&opt, ",x509verify=%s",
|
|
|
|
driver->vncTLSx509certdir);
|
|
|
|
} else {
|
|
|
|
virBufferAsprintf(&opt, ",x509=%s",
|
|
|
|
driver->vncTLSx509certdir);
|
|
|
|
}
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (driver->vncSASL) {
|
|
|
|
virBufferAddLit(&opt, ",sasl");
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (driver->vncSASLdir)
|
|
|
|
virCommandAddEnvPair(cmd, "SASL_CONF_DIR",
|
|
|
|
driver->vncSASLdir);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/* TODO: Support ACLs later */
|
|
|
|
}
|
|
|
|
}
|
2012-04-10 14:02:13 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-vnc");
|
|
|
|
virCommandAddArgBuffer(cmd, &opt);
|
|
|
|
if (graphics->data.vnc.keymap) {
|
|
|
|
virCommandAddArgList(cmd, "-k", graphics->data.vnc.keymap,
|
|
|
|
NULL);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
|
|
|
|
/* 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 (driver->vncAllowHostAudio) {
|
|
|
|
virCommandAddEnvPass(cmd, "QEMU_AUDIO_DRV");
|
|
|
|
} else {
|
|
|
|
virCommandAddEnvString(cmd, "QEMU_AUDIO_DRV=none");
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
} else if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_0_10) &&
|
|
|
|
!qemuCapsGet(caps, QEMU_CAPS_SDL)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("sdl not supported by '%s'"),
|
2012-07-18 15:22:03 +00:00
|
|
|
def->emulator);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (graphics->data.sdl.xauth)
|
|
|
|
virCommandAddEnvPair(cmd, "XAUTHORITY",
|
|
|
|
graphics->data.sdl.xauth);
|
|
|
|
if (graphics->data.sdl.display)
|
|
|
|
virCommandAddEnvPair(cmd, "DISPLAY",
|
|
|
|
graphics->data.sdl.display);
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
virCommandAddEnvPass(cmd, "QEMU_AUDIO_DRV");
|
|
|
|
virCommandAddEnvPass(cmd, "SDL_AUDIODRIVER");
|
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 :-( */
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_SDL))
|
|
|
|
virCommandAddArg(cmd, "-sdl");
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
} else if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
|
|
|
|
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;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_SPICE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("spice graphics are not supported with this QEMU"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (port > 0 || tlsPort <= 0)
|
|
|
|
virBufferAsprintf(&opt, "port=%u", port);
|
|
|
|
|
|
|
|
if (tlsPort > 0) {
|
|
|
|
if (!driver->spiceTLS) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2012-11-10 01:40:23 +00:00
|
|
|
_("spice TLS port set in XML configuration,"
|
|
|
|
" but TLS is disabled in qemu.conf"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
if (port > 0)
|
|
|
|
virBufferAddChar(&opt, ',');
|
|
|
|
virBufferAsprintf(&opt, "tls-port=%u", tlsPort);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
if (ret < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
2012-11-10 01:40:23 +00:00
|
|
|
_("listen network '%s' had no usable address"),
|
|
|
|
listenNetwork);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-11-10 01:40:23 +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;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (!listenAddr)
|
|
|
|
listenAddr = driver->spiceListen;
|
|
|
|
if (listenAddr)
|
|
|
|
virBufferAsprintf(&opt, ",addr=%s", listenAddr);
|
|
|
|
|
|
|
|
VIR_FREE(netAddr);
|
|
|
|
|
|
|
|
int mm = graphics->data.spice.mousemode;
|
|
|
|
if (mm) {
|
|
|
|
switch (mm) {
|
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_SERVER:
|
|
|
|
virBufferAsprintf(&opt, ",agent-mouse=off");
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_CLIENT:
|
|
|
|
virBufferAsprintf(&opt, ",agent-mouse=on");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/* 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 &&
|
|
|
|
!driver->spicePassword)
|
|
|
|
virBufferAddLit(&opt, ",disable-ticketing");
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (driver->spiceTLS)
|
|
|
|
virBufferAsprintf(&opt, ",x509-dir=%s",
|
|
|
|
driver->spiceTLSx509certdir);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
switch (defaultMode) {
|
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_SECURE:
|
|
|
|
virBufferAsprintf(&opt, ",tls-channel=default");
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_INSECURE:
|
|
|
|
virBufferAsprintf(&opt, ",plaintext-channel=default");
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY:
|
|
|
|
/* nothing */
|
|
|
|
break;
|
2011-07-08 07:56:17 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
|
2012-11-26 16:25:21 +00:00
|
|
|
for (i = 0 ; i < VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST ; i++) {
|
2012-11-10 01:40:23 +00:00
|
|
|
int mode = graphics->data.spice.channels[i];
|
|
|
|
switch (mode) {
|
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_SECURE:
|
|
|
|
if (!driver->spiceTLS) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("spice secure channels set in XML configuration, but TLS is disabled in qemu.conf"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAsprintf(&opt, ",tls-channel=%s",
|
|
|
|
virDomainGraphicsSpiceChannelNameTypeToString(i));
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_INSECURE:
|
|
|
|
virBufferAsprintf(&opt, ",plaintext-channel=%s",
|
|
|
|
virDomainGraphicsSpiceChannelNameTypeToString(i));
|
|
|
|
break;
|
|
|
|
}
|
2011-07-08 07:56:17 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +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",
|
|
|
|
virDomainGraphicsSpicePlaybackCompressionTypeToString(graphics->data.spice.playback));
|
|
|
|
if (graphics->data.spice.streaming)
|
|
|
|
virBufferAsprintf(&opt, ",streaming-video=%s",
|
|
|
|
virDomainGraphicsSpiceStreamingModeTypeToString(graphics->data.spice.streaming));
|
|
|
|
if (graphics->data.spice.copypaste == VIR_DOMAIN_GRAPHICS_SPICE_CLIPBOARD_COPYPASTE_NO)
|
|
|
|
virBufferAddLit(&opt, ",disable-copy-paste");
|
|
|
|
|
|
|
|
if (qemuCapsGet(caps, 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");
|
2011-07-08 07:56:17 +00:00
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
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");
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported graphics type '%s'"),
|
|
|
|
virDomainGraphicsTypeToString(graphics->type));
|
|
|
|
goto error;
|
|
|
|
}
|
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
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
error:
|
|
|
|
return -1;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
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,
|
2012-11-10 01:40:23 +00:00
|
|
|
virDomainDefPtr def,
|
|
|
|
virDomainChrSourceDefPtr monitor_chr,
|
|
|
|
bool monitor_json,
|
|
|
|
qemuCapsPtr caps,
|
|
|
|
const char *migrateFrom,
|
|
|
|
int migrateFd,
|
|
|
|
virDomainSnapshotObjPtr snapshot,
|
|
|
|
enum virNetDevVPortProfileOp vmop)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
struct utsname ut;
|
|
|
|
int disableKQEMU = 0;
|
|
|
|
int enableKQEMU = 0;
|
|
|
|
int disableKVM = 0;
|
|
|
|
int enableKVM = 0;
|
|
|
|
const char *emulator;
|
|
|
|
char uuid[VIR_UUID_STRING_BUFLEN];
|
|
|
|
char *cpu;
|
|
|
|
char *smp;
|
|
|
|
int last_good_net = -1;
|
|
|
|
bool hasHwVirt = false;
|
|
|
|
virCommandPtr cmd = NULL;
|
|
|
|
bool emitBootindex = false;
|
2012-11-10 01:40:24 +00:00
|
|
|
int sdl = 0;
|
|
|
|
int vnc = 0;
|
|
|
|
int spice = 0;
|
2012-11-10 01:40:23 +00:00
|
|
|
int usbcontroller = 0;
|
|
|
|
bool usblegacy = false;
|
|
|
|
uname_normalize(&ut);
|
|
|
|
int contOrder[] = {
|
|
|
|
/* We don't add an explicit IDE or FD controller because the
|
|
|
|
* provided PIIX4 device already includes one. It isn't possible to
|
|
|
|
* remove the PIIX4. */
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_USB,
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_SATA,
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL,
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_CCID,
|
|
|
|
};
|
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 "
|
|
|
|
"caps=%p migrateFrom=%s migrateFD=%d "
|
|
|
|
"snapshot=%p vmop=%d",
|
|
|
|
conn, driver, def, monitor_chr, monitor_json,
|
|
|
|
caps, migrateFrom, migrateFd, snapshot, vmop);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virUUIDFormat(def->uuid, uuid);
|
|
|
|
|
|
|
|
emulator = def->emulator;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* do not use boot=on for drives when not using KVM since this
|
|
|
|
* is not supported at all in upstream QEmu.
|
|
|
|
*/
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_KVM) &&
|
|
|
|
(def->virtType == VIR_DOMAIN_VIRT_QEMU))
|
|
|
|
qemuCapsClear(caps, QEMU_CAPS_DRIVE_BOOT);
|
|
|
|
|
|
|
|
switch (def->virtType) {
|
|
|
|
case VIR_DOMAIN_VIRT_QEMU:
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_KQEMU))
|
|
|
|
disableKQEMU = 1;
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_KVM))
|
|
|
|
disableKVM = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_VIRT_KQEMU:
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_KVM))
|
|
|
|
disableKVM = 1;
|
|
|
|
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_ENABLE_KQEMU)) {
|
|
|
|
enableKQEMU = 1;
|
|
|
|
} else if (!qemuCapsGet(caps, QEMU_CAPS_KQEMU)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2012-11-10 01:40:23 +00:00
|
|
|
_("the QEMU binary %s does not support kqemu"),
|
|
|
|
emulator);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
break;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
case VIR_DOMAIN_VIRT_KVM:
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_KQEMU))
|
|
|
|
disableKQEMU = 1;
|
|
|
|
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_ENABLE_KVM)) {
|
|
|
|
enableKVM = 1;
|
|
|
|
} else if (!qemuCapsGet(caps, QEMU_CAPS_KVM)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2012-11-10 01:40:23 +00:00
|
|
|
_("the QEMU binary %s does not support kvm"),
|
|
|
|
emulator);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
2012-11-10 01:40:23 +00:00
|
|
|
}
|
|
|
|
break;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
case VIR_DOMAIN_VIRT_XEN:
|
|
|
|
/* XXX better check for xenner */
|
|
|
|
break;
|
2012-01-27 13:49:52 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("the QEMU binary %s does not support %s"),
|
|
|
|
emulator, virDomainVirtTypeToString(def->virtType));
|
|
|
|
break;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
cmd = virCommandNew(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
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_NAME)) {
|
|
|
|
virCommandAddArg(cmd, "-name");
|
|
|
|
if (driver->setProcessName &&
|
|
|
|
qemuCapsGet(caps, QEMU_CAPS_NAME_PROCESS)) {
|
|
|
|
virCommandAddArgFormat(cmd, "%s,process=qemu:%s",
|
|
|
|
def->name, def->name);
|
|
|
|
} else {
|
|
|
|
virCommandAddArg(cmd, def->name);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-S"); /* freeze CPU */
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (qemuBuildMachineArgStr(cmd, def, caps) < 0)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (qemuBuildCpuArgStr(driver, def, emulator, caps,
|
|
|
|
&ut, &cpu, &hasHwVirt, !!migrateFrom) < 0)
|
|
|
|
goto error;
|
2011-06-15 16:49:58 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (cpu) {
|
|
|
|
virCommandAddArgList(cmd, "-cpu", cpu, NULL);
|
|
|
|
VIR_FREE(cpu);
|
|
|
|
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_NESTING) &&
|
|
|
|
hasHwVirt)
|
|
|
|
virCommandAddArg(cmd, "-enable-nesting");
|
2011-12-20 01:08:29 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (disableKQEMU)
|
|
|
|
virCommandAddArg(cmd, "-no-kqemu");
|
|
|
|
else if (enableKQEMU)
|
|
|
|
virCommandAddArgList(cmd, "-enable-kqemu", "-kernel-kqemu", NULL);
|
|
|
|
if (disableKVM)
|
|
|
|
virCommandAddArg(cmd, "-no-kvm");
|
|
|
|
if (enableKVM)
|
|
|
|
virCommandAddArg(cmd, "-enable-kvm");
|
|
|
|
|
|
|
|
if (def->os.loader) {
|
|
|
|
virCommandAddArg(cmd, "-bios");
|
|
|
|
virCommandAddArg(cmd, def->os.loader);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set '-m MB' based on maxmem, because the lower 'memory' limit
|
|
|
|
* is set post-startup using the balloon driver. If balloon driver
|
|
|
|
* is not supported, then they're out of luck anyway. Update the
|
|
|
|
* XML to reflect our rounding.
|
|
|
|
*/
|
|
|
|
virCommandAddArg(cmd, "-m");
|
|
|
|
def->mem.max_balloon = VIR_DIV_UP(def->mem.max_balloon, 1024) * 1024;
|
|
|
|
virCommandAddArgFormat(cmd, "%llu", def->mem.max_balloon / 1024);
|
|
|
|
if (def->mem.hugepage_backed) {
|
|
|
|
if (!driver->hugetlbfs_mount) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("hugetlbfs filesystem is not mounted"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!driver->hugepage_path) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("hugepages are disabled by administrator config"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_MEM_PATH)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("hugepage backing not supported by '%s'"),
|
|
|
|
def->emulator);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virCommandAddArgList(cmd, "-mem-prealloc", "-mem-path",
|
|
|
|
driver->hugepage_path, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-smp");
|
|
|
|
if (!(smp = qemuBuildSmpArgStr(def, caps)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, smp);
|
|
|
|
VIR_FREE(smp);
|
|
|
|
|
|
|
|
if (def->cpu && def->cpu->ncells)
|
|
|
|
if (qemuBuildNumaArgStr(def, cmd) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_UUID))
|
|
|
|
virCommandAddArgList(cmd, "-uuid", uuid, NULL);
|
|
|
|
if (def->virtType == VIR_DOMAIN_VIRT_XEN ||
|
|
|
|
STREQ(def->os.type, "xen") ||
|
|
|
|
STREQ(def->os.type, "linux")) {
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DOMID)) {
|
|
|
|
virCommandAddArg(cmd, "-domid");
|
|
|
|
virCommandAddArgFormat(cmd, "%d", def->id);
|
|
|
|
} else if (qemuCapsGet(caps, QEMU_CAPS_XEN_DOMID)) {
|
|
|
|
virCommandAddArg(cmd, "-xen-attach");
|
|
|
|
virCommandAddArg(cmd, "-xen-domid");
|
|
|
|
virCommandAddArgFormat(cmd, "%d", def->id);
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("qemu emulator '%s' does not support xen"),
|
|
|
|
def->emulator);
|
2012-08-02 10:14:39 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if ((def->os.smbios_mode != VIR_DOMAIN_SMBIOS_NONE) &&
|
|
|
|
(def->os.smbios_mode != VIR_DOMAIN_SMBIOS_EMULATE)) {
|
|
|
|
virSysinfoDefPtr source = NULL;
|
|
|
|
bool skip_uuid = false;
|
|
|
|
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_SMBIOS_TYPE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("the QEMU binary %s does not support smbios settings"),
|
|
|
|
emulator);
|
2012-08-02 10:14:39 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/* should we really error out or just warn in those cases ? */
|
|
|
|
if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_HOST) {
|
|
|
|
if (driver->hostsysinfo == NULL) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2012-11-10 01:40:23 +00:00
|
|
|
_("Host SMBIOS information is not available"));
|
2011-05-26 14:15:01 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
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);
|
|
|
|
goto error;
|
2011-05-26 14:15:01 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
source = def->sysinfo;
|
|
|
|
/* domain_conf guaranteed that system_uuid matches guest uuid. */
|
2012-09-18 09:38:18 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
if (source != NULL) {
|
|
|
|
char *smbioscmd;
|
2012-09-18 09:38:18 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
smbioscmd = qemuBuildSmbiosBiosStr(source);
|
|
|
|
if (smbioscmd != NULL) {
|
|
|
|
virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL);
|
|
|
|
VIR_FREE(smbioscmd);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
smbioscmd = qemuBuildSmbiosSystemStr(source, skip_uuid);
|
|
|
|
if (smbioscmd != NULL) {
|
|
|
|
virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL);
|
|
|
|
VIR_FREE(smbioscmd);
|
2012-09-18 10:31:30 +00:00
|
|
|
}
|
2012-09-18 09:38:18 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
}
|
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...
|
|
|
|
*/
|
|
|
|
if (!def->graphics)
|
|
|
|
virCommandAddArg(cmd, "-nographic");
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
|
|
|
/* Disable global config files and default devices */
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_NO_USER_CONFIG))
|
|
|
|
virCommandAddArg(cmd, "-no-user-config");
|
|
|
|
else if (qemuCapsGet(caps, QEMU_CAPS_NODEFCONFIG))
|
|
|
|
virCommandAddArg(cmd, "-nodefconfig");
|
|
|
|
virCommandAddArg(cmd, "-nodefaults");
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/* Serial graphics adapter */
|
|
|
|
if (def->os.bios.useserial == VIR_DOMAIN_BIOS_USESERIAL_YES) {
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("qemu does not support -device"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_SGA)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("qemu does not support SGA"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!def->nserials) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("need at least one serial port to use SGA"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArgList(cmd, "-device", "sga", NULL);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (monitor_chr) {
|
|
|
|
char *chrdev;
|
|
|
|
/* Use -chardev if it's available */
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_CHARDEV)) {
|
2011-09-28 03:46:08 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-chardev");
|
|
|
|
if (!(chrdev = qemuBuildChrChardevStr(monitor_chr, "monitor",
|
|
|
|
caps)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, chrdev);
|
|
|
|
VIR_FREE(chrdev);
|
2012-11-05 10:42:51 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
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,";
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-monitor");
|
|
|
|
if (!(chrdev = qemuBuildChrArgStr(monitor_chr, prefix)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, chrdev);
|
|
|
|
VIR_FREE(chrdev);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_RTC)) {
|
|
|
|
const char *rtcopt;
|
|
|
|
virCommandAddArg(cmd, "-rtc");
|
|
|
|
if (!(rtcopt = qemuBuildClockArgStr(&def->clock)))
|
|
|
|
goto error;
|
|
|
|
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;
|
2012-10-26 09:09:22 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_UTC:
|
|
|
|
/* Nothing, its the default */
|
|
|
|
break;
|
2012-10-26 09:09:22 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported clock offset '%s'"),
|
|
|
|
virDomainClockOffsetTypeToString(def->clock.offset));
|
2012-10-26 09:09:22 +00:00
|
|
|
goto error;
|
2012-11-10 01:40:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE &&
|
|
|
|
def->clock.data.timezone) {
|
|
|
|
virCommandAddEnvPair(cmd, "TZ", def->clock.data.timezone);
|
2012-10-26 09:09:22 +00:00
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
for (i = 0; i < def->clock.ntimers; i++) {
|
|
|
|
switch (def->clock.timers[i]->name) {
|
|
|
|
default:
|
|
|
|
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));
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
case VIR_DOMAIN_TIMER_NAME_KVMCLOCK:
|
|
|
|
/* This is handled when building -cpu. */
|
|
|
|
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 (qemuCapsGet(caps, QEMU_CAPS_RTC_TD_HACK)) {
|
|
|
|
switch (def->clock.timers[i]->tickpolicy) {
|
|
|
|
case -1:
|
|
|
|
case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
|
|
|
|
/* the default - do nothing */
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
2012-11-10 01:40:23 +00:00
|
|
|
case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
|
|
|
|
virCommandAddArg(cmd, "-rtc-td-hack");
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
2012-11-10 01:40:23 +00:00
|
|
|
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));
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
} else if (!qemuCapsGet(caps, 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));
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
break;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
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 (qemuCapsGet(caps, QEMU_CAPS_NO_KVM_PIT))
|
|
|
|
virCommandAddArg(cmd, "-no-kvm-pit-reinjection");
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_NO_KVM_PIT)) {
|
|
|
|
/* do nothing - this is default for kvm-pit */
|
|
|
|
} else if (qemuCapsGet(caps, QEMU_CAPS_TDF)) {
|
|
|
|
/* -tdf switches to 'catchup' with userspace pit. */
|
|
|
|
virCommandAddArg(cmd, "-tdf");
|
2010-12-16 15:07:07 +00:00
|
|
|
} else {
|
2012-11-10 01:40:23 +00:00
|
|
|
/* can't catchup if we have neither pit mode */
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported pit tickpolicy '%s'"),
|
|
|
|
virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
break;
|
2012-11-10 01:40:23 +00:00
|
|
|
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));
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
break;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
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"! */
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (qemuCapsGet(caps, 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", _("pit timer is not supported"));
|
2011-02-08 14:08:12 +00:00
|
|
|
}
|
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_NO_REBOOT) &&
|
|
|
|
def->onReboot != VIR_DOMAIN_LIFECYCLE_RESTART)
|
|
|
|
virCommandAddArg(cmd, "-no-reboot");
|
2011-05-26 14:15:01 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/* 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 && qemuCapsGet(caps, QEMU_CAPS_NO_SHUTDOWN))
|
|
|
|
virCommandAddArg(cmd, "-no-shutdown");
|
2011-01-12 10:33:34 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_NO_ACPI)) {
|
|
|
|
if (!(def->features & (1 << VIR_DOMAIN_FEATURE_ACPI)))
|
|
|
|
virCommandAddArg(cmd, "-no-acpi");
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (def->pm.s3) {
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_DISABLE_S3)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("setting ACPI S3 not supported"));
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-global");
|
|
|
|
virCommandAddArgFormat(cmd, "PIIX4_PM.disable_s3=%d",
|
|
|
|
def->pm.s3 == VIR_DOMAIN_PM_STATE_DISABLED);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->pm.s4) {
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_DISABLE_S4)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("setting ACPI S4 not supported"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virCommandAddArg(cmd, "-global");
|
|
|
|
virCommandAddArgFormat(cmd, "PIIX4_PM.disable_s4=%d",
|
|
|
|
def->pm.s4 == VIR_DOMAIN_PM_STATE_DISABLED);
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (!def->os.bootloader) {
|
|
|
|
int boot_nparams = 0;
|
|
|
|
virBuffer boot_buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
/*
|
|
|
|
* 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 (!qemuCapsGet(caps, QEMU_CAPS_BOOTINDEX)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2012-11-10 01:40:23 +00:00
|
|
|
_("hypervisor lacks deviceboot feature"));
|
2012-03-14 15:26:49 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
emitBootindex = true;
|
|
|
|
} else if (qemuCapsGet(caps, QEMU_CAPS_BOOTINDEX) &&
|
|
|
|
(def->os.bootmenu != VIR_DOMAIN_BOOT_MENU_ENABLED ||
|
|
|
|
!qemuCapsGet(caps, QEMU_CAPS_BOOT_MENU))) {
|
|
|
|
emitBootindex = true;
|
|
|
|
}
|
2012-03-14 15:26:49 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (!emitBootindex) {
|
|
|
|
char boot[VIR_DOMAIN_BOOT_LAST+1];
|
2011-04-03 09:21:28 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
for (i = 0 ; i < def->os.nBootDevs ; i++) {
|
|
|
|
switch (def->os.bootDevs[i]) {
|
|
|
|
case VIR_DOMAIN_BOOT_CDROM:
|
|
|
|
boot[i] = 'd';
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
2012-11-10 01:40:23 +00:00
|
|
|
case VIR_DOMAIN_BOOT_FLOPPY:
|
|
|
|
boot[i] = 'a';
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
2012-11-10 01:40:23 +00:00
|
|
|
case VIR_DOMAIN_BOOT_DISK:
|
|
|
|
boot[i] = 'c';
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_BOOT_NET:
|
|
|
|
boot[i] = 'n';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
boot[i] = 'c';
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
2011-04-03 09:21:28 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
boot[def->os.nBootDevs] = '\0';
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virBufferAsprintf(&boot_buf, "%s", boot);
|
|
|
|
boot_nparams++;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (def->os.bootmenu) {
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_BOOT_MENU)) {
|
|
|
|
if (boot_nparams++)
|
|
|
|
virBufferAddChar(&boot_buf, ',');
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (def->os.bootmenu == VIR_DOMAIN_BOOT_MENU_ENABLED)
|
|
|
|
virBufferAsprintf(&boot_buf, "menu=on");
|
|
|
|
else
|
|
|
|
virBufferAsprintf(&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");
|
|
|
|
}
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (def->os.bios.rt_set) {
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_REBOOT_TIMEOUT)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("reboot timeout is not supported "
|
|
|
|
"by this QEMU binary"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
2012-11-10 01:40:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (boot_nparams++)
|
|
|
|
virBufferAddChar(&boot_buf, ',');
|
|
|
|
|
|
|
|
virBufferAsprintf(&boot_buf,
|
|
|
|
"reboot-timeout=%d",
|
|
|
|
def->os.bios.rt_delay);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (boot_nparams > 0) {
|
|
|
|
virCommandAddArg(cmd, "-boot");
|
2011-05-26 14:15:01 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (boot_nparams < 2 || emitBootindex) {
|
|
|
|
virCommandAddArgBuffer(cmd, &boot_buf);
|
|
|
|
} else {
|
|
|
|
virCommandAddArgFormat(cmd,
|
|
|
|
"order=%s",
|
|
|
|
virBufferContentAndReset(&boot_buf));
|
2011-05-26 14:15:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
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);
|
|
|
|
} else {
|
|
|
|
virCommandAddArgList(cmd, "-bootloader", def->os.bootloader, NULL);
|
|
|
|
}
|
2011-05-26 14:15:01 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
for (i = 0 ; i < def->ndisks ; i++) {
|
|
|
|
virDomainDiskDefPtr disk = def->disks[i];
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (disk->driverName != NULL &&
|
|
|
|
!STREQ(disk->driverName, "qemu")) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported driver name '%s' for disk '%s'"),
|
|
|
|
disk->driverName, disk->src);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
|
|
|
for (j = 0; j < ARRAY_CARDINALITY(contOrder); j++) {
|
|
|
|
for (i = 0; i < def->ncontrollers; i++) {
|
|
|
|
virDomainControllerDefPtr cont = def->controllers[i];
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (cont->type != contOrder[j])
|
|
|
|
continue;
|
2011-07-04 06:27:12 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/* Also, 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Only recent QEMU implements a SATA (AHCI) controller */
|
|
|
|
if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_SATA) {
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_ICH9_AHCI)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("SATA is not supported with this "
|
|
|
|
"QEMU binary"));
|
2012-08-16 15:42:48 +00:00
|
|
|
goto error;
|
2012-11-10 01:40:23 +00:00
|
|
|
} else {
|
|
|
|
char *devstr;
|
2012-08-16 15:42:48 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
if (!(devstr = qemuBuildControllerDevStr(def, cont,
|
|
|
|
caps, NULL)))
|
2012-08-16 15:42:48 +00:00
|
|
|
goto error;
|
2012-11-10 01:40:23 +00:00
|
|
|
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
2012-08-16 15:42:48 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
} else if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB &&
|
|
|
|
cont->model == -1 &&
|
|
|
|
!qemuCapsGet(caps, QEMU_CAPS_PIIX3_USB_UHCI)) {
|
|
|
|
if (usblegacy) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Multiple legacy USB controllers are "
|
|
|
|
"not supported"));
|
2012-08-16 15:42:48 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
usblegacy = true;
|
|
|
|
} else {
|
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
|
|
|
|
char *devstr;
|
|
|
|
if (!(devstr = qemuBuildControllerDevStr(def, cont, caps,
|
|
|
|
&usbcontroller)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
2012-08-16 15:42:48 +00:00
|
|
|
}
|
qemu: support type='hostdev' network devices at domain start
This patch makes sure that each network device ("interface") of
type='hostdev' appears on both the hostdevs list and the nets list of
the virDomainDef, and it modifies the qemu driver startup code so that
these devices will be presented to qemu on the commandline as hostdevs
rather than as network devices.
It does not add support for hotplug of these type of devices, or code
to honor the <mac address> or <virtualport> given in the config (both
of those will be done in separate patches).
Once each device is placed on both lists, much of what this patch does
is modify places in the code that traverse all the device lists so
that these hybrid devices are only acted on once - either along with
the other hostdevs, or along with the other network interfaces. (In
many cases, only one of the lists is traversed / a specific operation
is performed on only one type of device. In those instances, the code
can remain unchanged.)
There is one special case - when building the commandline, interfaces
are allowed to proceed all the way through
networkAllocateActualDevice() before deciding to skip the rest of
netdev-specific processing - this is so that (once we have support for
networks with pools of hostdev devices) we can get the actual device
allocated, then rely on the loop processing all hostdevs to generate
the correct commandline.
(NB: <interface type='hostdev'> is only supported for PCI network
devices that are SR-IOV Virtual Functions (VF). Standard PCI[e] and
USB devices, and even the Physical Functions (PF) of SR-IOV devices
can only be assigned to a guest using the more basic <hostdev> device
entry. This limitation is mostly due to the fact that non-SR-IOV
ethernet devices tend to lose mac address configuration whenever the
card is reset, which happens when a card is assigned to a guest;
SR-IOV VFs fortunately don't suffer the same problem.)
2012-02-23 15:45:35 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
}
|
|
|
|
}
|
qemu: support type='hostdev' network devices at domain start
This patch makes sure that each network device ("interface") of
type='hostdev' appears on both the hostdevs list and the nets list of
the virDomainDef, and it modifies the qemu driver startup code so that
these devices will be presented to qemu on the commandline as hostdevs
rather than as network devices.
It does not add support for hotplug of these type of devices, or code
to honor the <mac address> or <virtualport> given in the config (both
of those will be done in separate patches).
Once each device is placed on both lists, much of what this patch does
is modify places in the code that traverse all the device lists so
that these hybrid devices are only acted on once - either along with
the other hostdevs, or along with the other network interfaces. (In
many cases, only one of the lists is traversed / a specific operation
is performed on only one type of device. In those instances, the code
can remain unchanged.)
There is one special case - when building the commandline, interfaces
are allowed to proceed all the way through
networkAllocateActualDevice() before deciding to skip the rest of
netdev-specific processing - this is so that (once we have support for
networks with pools of hostdev devices) we can get the actual device
allocated, then rely on the loop processing all hostdevs to generate
the correct commandline.
(NB: <interface type='hostdev'> is only supported for PCI network
devices that are SR-IOV Virtual Functions (VF). Standard PCI[e] and
USB devices, and even the Physical Functions (PF) of SR-IOV devices
can only be assigned to a guest using the more basic <hostdev> device
entry. This limitation is mostly due to the fact that non-SR-IOV
ethernet devices tend to lose mac address configuration whenever the
card is reset, which happens when a card is assigned to a guest;
SR-IOV VFs fortunately don't suffer the same problem.)
2012-02-23 15:45:35 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (usbcontroller == 0)
|
|
|
|
virCommandAddArg(cmd, "-usb");
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
for (i = 0 ; i < def->nhubs ; i++) {
|
|
|
|
virDomainHubDefPtr hub = def->hubs[i];
|
|
|
|
char *optstr;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
if (!(optstr = qemuBuildHubDevStr(hub, caps)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, optstr);
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/* If QEMU supports -drive param instead of old -hda, -hdb, -cdrom .. */
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DRIVE)) {
|
|
|
|
int bootCD = 0, bootFloppy = 0, bootDisk = 0;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if ((qemuCapsGet(caps, 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;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
for (i = 0 ; i < def->ndisks ; i++) {
|
|
|
|
char *optstr;
|
|
|
|
int bootindex = 0;
|
|
|
|
virDomainDiskDefPtr disk = def->disks[i];
|
|
|
|
int withDeviceArg = 0;
|
|
|
|
bool deviceFlagMasked = false;
|
2011-01-12 04:18:49 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/* Unless we have -device, then USB disks need special
|
|
|
|
handling */
|
|
|
|
if ((disk->bus == VIR_DOMAIN_DISK_BUS_USB) &&
|
|
|
|
!qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
|
|
|
|
virCommandAddArg(cmd, "-usbdevice");
|
|
|
|
virCommandAddArgFormat(cmd, "disk:%s", disk->src);
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported usb disk type for '%s'"),
|
|
|
|
disk->src);
|
2011-01-12 04:18:49 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
continue;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
|
|
|
|
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;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-drive");
|
|
|
|
|
|
|
|
/* Unfortunately it is not possible to use
|
|
|
|
-device for floppies, or Xen paravirt
|
|
|
|
devices. Fortunately, those don't need
|
|
|
|
static PCI addresses, so we don't really
|
|
|
|
care that we can't use -device */
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
2012-11-10 01:40:23 +00:00
|
|
|
if (disk->bus != VIR_DOMAIN_DISK_BUS_XEN) {
|
|
|
|
withDeviceArg = 1;
|
|
|
|
} else {
|
|
|
|
qemuCapsClear(caps, QEMU_CAPS_DEVICE);
|
|
|
|
deviceFlagMasked = true;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
optstr = qemuBuildDriveStr(conn, disk,
|
|
|
|
emitBootindex ? false : !!bootindex,
|
|
|
|
caps);
|
|
|
|
if (deviceFlagMasked)
|
|
|
|
qemuCapsSet(caps, QEMU_CAPS_DEVICE);
|
|
|
|
if (!optstr)
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, optstr);
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
|
|
|
|
if (!emitBootindex)
|
|
|
|
bootindex = 0;
|
|
|
|
else if (disk->info.bootIndex)
|
|
|
|
bootindex = disk->info.bootIndex;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (withDeviceArg) {
|
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
|
|
|
|
virCommandAddArg(cmd, "-global");
|
|
|
|
virCommandAddArgFormat(cmd, "isa-fdc.drive%c=drive-%s",
|
|
|
|
disk->info.addr.drive.unit
|
|
|
|
? 'B' : 'A',
|
|
|
|
disk->info.alias);
|
2011-01-13 00:09:45 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (bootindex) {
|
|
|
|
virCommandAddArg(cmd, "-global");
|
|
|
|
virCommandAddArgFormat(cmd, "isa-fdc.bootindex%c=%d",
|
|
|
|
disk->info.addr.drive.unit
|
|
|
|
? 'B' : 'A',
|
|
|
|
bootindex);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virCommandAddArg(cmd, "-device");
|
2011-01-13 00:09:45 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (!(optstr = qemuBuildDriveDevStr(def, disk, bootindex,
|
|
|
|
caps)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, optstr);
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
}
|
2011-01-13 00:09:45 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (i = 0 ; i < def->ndisks ; i++) {
|
|
|
|
char dev[NAME_MAX];
|
|
|
|
char *file;
|
|
|
|
const char *fmt;
|
|
|
|
virDomainDiskDefPtr disk = def->disks[i];
|
2011-01-13 00:09:45 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if ((disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) &&
|
|
|
|
(disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2012-11-10 01:40:23 +00:00
|
|
|
_("tray status 'open' is invalid for "
|
|
|
|
"block type disk"));
|
2011-01-13 00:09:45 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
|
|
|
|
virCommandAddArg(cmd, "-usbdevice");
|
|
|
|
virCommandAddArgFormat(cmd, "disk:%s", disk->src);
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported usb disk type for '%s'"),
|
|
|
|
disk->src);
|
2011-01-13 00:09:45 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
continue;
|
2011-01-13 00:09:45 +00:00
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
|
|
|
|
if (STREQ(disk->dst, "hdc") &&
|
|
|
|
disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
|
|
|
|
if (disk->src) {
|
|
|
|
snprintf(dev, NAME_MAX, "-%s", "cdrom");
|
|
|
|
} else {
|
|
|
|
continue;
|
2011-01-13 00:09:45 +00:00
|
|
|
}
|
|
|
|
} else {
|
2012-11-10 01:40:23 +00:00
|
|
|
if (STRPREFIX(disk->dst, "hd") ||
|
|
|
|
STRPREFIX(disk->dst, "fd")) {
|
|
|
|
snprintf(dev, NAME_MAX, "-%s", disk->dst);
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported disk type '%s'"), disk->dst);
|
|
|
|
goto error;
|
|
|
|
}
|
2011-01-13 00:09:45 +00:00
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (disk->type == VIR_DOMAIN_DISK_TYPE_DIR) {
|
|
|
|
/* QEMU only supports magic FAT format for now */
|
|
|
|
if (disk->format > 0 && disk->format != VIR_STORAGE_FILE_FAT) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported disk driver type for '%s'"),
|
|
|
|
virStorageFileFormatTypeToString(disk->format));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!disk->readonly) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot create virtual FAT disks in read-write mode"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
|
|
|
|
fmt = "fat:floppy:%s";
|
|
|
|
else
|
|
|
|
fmt = "fat:%s";
|
2011-01-13 00:09:45 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (virAsprintf(&file, fmt, disk->src) < 0) {
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
} else if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) {
|
|
|
|
switch (disk->protocol) {
|
|
|
|
case VIR_DOMAIN_DISK_PROTOCOL_NBD:
|
|
|
|
if (disk->nhosts != 1) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("NBD accepts only one host"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (virAsprintf(&file, "nbd:%s:%s,", disk->hosts->name,
|
|
|
|
disk->hosts->port) < 0) {
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_PROTOCOL_RBD:
|
|
|
|
{
|
|
|
|
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
|
|
|
if (qemuBuildRBDString(conn, disk, &opt) < 0)
|
|
|
|
goto error;
|
|
|
|
if (virBufferError(&opt)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
file = virBufferContentAndReset(&opt);
|
|
|
|
}
|
|
|
|
break;
|
2012-11-22 18:10:39 +00:00
|
|
|
case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER:
|
|
|
|
{
|
|
|
|
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
|
|
|
if (qemuBuildGlusterString(disk, &opt) < 0)
|
|
|
|
goto error;
|
|
|
|
if (virBufferError(&opt)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
file = virBufferContentAndReset(&opt);
|
|
|
|
}
|
|
|
|
break;
|
2012-11-10 01:40:23 +00:00
|
|
|
case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
|
|
|
|
if (disk->nhosts == 0) {
|
|
|
|
if (virAsprintf(&file, "sheepdog:%s,", disk->src) < 0) {
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* only one host is supported now */
|
|
|
|
if (virAsprintf(&file, "sheepdog:%s:%s:%s,",
|
|
|
|
disk->hosts->name, disk->hosts->port,
|
|
|
|
disk->src) < 0) {
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!(file = strdup(disk->src))) {
|
|
|
|
goto no_memory;
|
|
|
|
}
|
2011-01-13 00:09:45 +00:00
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/* Don't start with source if the tray is open for
|
|
|
|
* CDROM and Floppy device.
|
|
|
|
*/
|
|
|
|
if (!((disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY ||
|
|
|
|
disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
|
|
|
|
disk->tray_status == VIR_DOMAIN_DISK_TRAY_OPEN))
|
|
|
|
virCommandAddArgList(cmd, dev, file, NULL);
|
|
|
|
VIR_FREE(file);
|
2011-01-13 00:09:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_FSDEV)) {
|
|
|
|
for (i = 0 ; i < def->nfss ; i++) {
|
|
|
|
char *optstr;
|
|
|
|
virDomainFSDefPtr fs = def->fss[i];
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-fsdev");
|
|
|
|
if (!(optstr = qemuBuildFSStr(fs, caps)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, optstr);
|
|
|
|
VIR_FREE(optstr);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
if (!(optstr = qemuBuildFSDevStr(fs, caps)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, optstr);
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (def->nfss) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("filesystem passthrough not supported by this QEMU"));
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (!def->nnets) {
|
2010-12-16 15:07:07 +00:00
|
|
|
/* If we have -device, then we set -nodefault already */
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_DEVICE))
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArgList(cmd, "-net", "none", NULL);
|
2010-12-16 15:07:07 +00:00
|
|
|
} else {
|
2012-11-10 01:40:23 +00:00
|
|
|
int bootNet = 0;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
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;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
for (i = 0 ; i < def->nnets ; i++) {
|
|
|
|
virDomainNetDefPtr net = def->nets[i];
|
|
|
|
char *nic, *host;
|
|
|
|
char tapfd_name[50] = "";
|
|
|
|
char vhostfd_name[50] = "";
|
|
|
|
int vlan;
|
|
|
|
int bootindex = bootNet;
|
|
|
|
int actualType;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
bootNet = 0;
|
|
|
|
if (!bootindex)
|
|
|
|
bootindex = net->info.bootIndex;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/* VLANs are not used with -netdev, so don't record them */
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_NETDEV) &&
|
|
|
|
qemuCapsGet(caps, QEMU_CAPS_DEVICE))
|
|
|
|
vlan = -1;
|
|
|
|
else
|
|
|
|
vlan = i;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
/* If appropriate, grab a physical device from the configured
|
|
|
|
* network's pool of devices, or resolve bridge device name
|
|
|
|
* to the one defined in the network definition.
|
|
|
|
*/
|
|
|
|
if (networkAllocateActualDevice(net) < 0)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
actualType = virDomainNetGetActualType(net);
|
|
|
|
if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
|
|
|
|
if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
|
|
|
|
virDomainHostdevDefPtr hostdev = virDomainNetGetActualHostdev(net);
|
|
|
|
virDomainHostdevDefPtr found;
|
|
|
|
/* For a network with <forward mode='hostdev'>, there is a need to
|
|
|
|
* add the newly minted hostdev to the hostdevs array.
|
|
|
|
*/
|
|
|
|
if (qemuAssignDeviceHostdevAlias(def, hostdev,
|
|
|
|
(def->nhostdevs-1)) < 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (virDomainHostdevFind(def, hostdev, &found) < 0) {
|
|
|
|
if (virDomainHostdevInsert(def, hostdev) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid,
|
|
|
|
&hostdev, 1) < 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("PCI device %04x:%02x:%02x.%x "
|
|
|
|
"allocated from network %s is already "
|
|
|
|
"in use by domain %s"),
|
|
|
|
hostdev->source.subsys.u.pci.domain,
|
|
|
|
hostdev->source.subsys.u.pci.bus,
|
|
|
|
hostdev->source.subsys.u.pci.slot,
|
|
|
|
hostdev->source.subsys.u.pci.function,
|
|
|
|
net->data.network.name,
|
|
|
|
def->name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
2011-02-04 15:43:32 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
|
|
|
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
|
|
|
|
/*
|
|
|
|
* If type='bridge' then we attempt to allocate the tap fd here only if
|
|
|
|
* running under a privilged user or -netdev bridge option is not
|
|
|
|
* supported.
|
|
|
|
*/
|
|
|
|
if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
|
|
|
driver->privileged ||
|
|
|
|
(!qemuCapsGet(caps, QEMU_CAPS_NETDEV_BRIDGE))) {
|
|
|
|
int tapfd = qemuNetworkIfaceConnect(def, conn, driver, net,
|
|
|
|
caps);
|
|
|
|
if (tapfd < 0)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
last_good_net = i;
|
|
|
|
virCommandTransferFD(cmd, tapfd);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (snprintf(tapfd_name, sizeof(tapfd_name), "%d",
|
|
|
|
tapfd) >= sizeof(tapfd_name))
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
} else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
|
|
|
|
int tapfd = qemuPhysIfaceConnect(def, driver, net,
|
|
|
|
caps, vmop);
|
|
|
|
if (tapfd < 0)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
last_good_net = i;
|
|
|
|
virCommandTransferFD(cmd, tapfd);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (snprintf(tapfd_name, sizeof(tapfd_name), "%d",
|
|
|
|
tapfd) >= sizeof(tapfd_name))
|
|
|
|
goto no_memory;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
|
|
|
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
|
|
|
|
actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
|
|
|
|
/* Attempt to use vhost-net mode for these types of
|
|
|
|
network device */
|
|
|
|
int vhostfd;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (qemuOpenVhostNet(def, net, caps, &vhostfd) < 0)
|
|
|
|
goto error;
|
|
|
|
if (vhostfd >= 0) {
|
|
|
|
virCommandTransferFD(cmd, vhostfd);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (snprintf(vhostfd_name, sizeof(vhostfd_name), "%d",
|
|
|
|
vhostfd) >= sizeof(vhostfd_name))
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* 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
|
|
|
|
*/
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_NETDEV) &&
|
|
|
|
qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
|
|
|
virCommandAddArg(cmd, "-netdev");
|
|
|
|
if (!(host = qemuBuildHostNetStr(net, driver, caps,
|
|
|
|
',', vlan, tapfd_name,
|
|
|
|
vhostfd_name)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, host);
|
|
|
|
VIR_FREE(host);
|
|
|
|
}
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virCommandAddArg(cmd, "-device");
|
2012-11-10 01:40:23 +00:00
|
|
|
nic = qemuBuildNicDevStr(net, vlan, bootindex, caps);
|
|
|
|
if (!nic)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, nic);
|
|
|
|
VIR_FREE(nic);
|
2010-12-16 15:07:07 +00:00
|
|
|
} else {
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-net");
|
|
|
|
if (!(nic = qemuBuildNicStr(net, "nic,", vlan)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, nic);
|
|
|
|
VIR_FREE(nic);
|
|
|
|
}
|
|
|
|
if (!(qemuCapsGet(caps, QEMU_CAPS_NETDEV) &&
|
|
|
|
qemuCapsGet(caps, QEMU_CAPS_DEVICE))) {
|
|
|
|
virCommandAddArg(cmd, "-net");
|
|
|
|
if (!(host = qemuBuildHostNetStr(net, driver, caps,
|
|
|
|
',', vlan, tapfd_name,
|
|
|
|
vhostfd_name)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, host);
|
|
|
|
VIR_FREE(host);
|
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:
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_CHARDEV) ||
|
|
|
|
!qemuCapsGet(caps, QEMU_CAPS_CCID_EMULATED)) {
|
|
|
|
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:
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_CHARDEV) ||
|
|
|
|
!qemuCapsGet(caps, QEMU_CAPS_CCID_EMULATED)) {
|
|
|
|
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;
|
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
virBufferAsprintf(&opt, ",cert%d=%s", j + 1,
|
|
|
|
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
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
virBufferAsprintf(&opt, ",database=%s", database);
|
|
|
|
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:
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_CHARDEV) ||
|
|
|
|
!qemuCapsGet(caps, QEMU_CAPS_CCID_PASSTHRU)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("this QEMU binary lacks smartcard "
|
|
|
|
"passthrough mode support"));
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-chardev");
|
|
|
|
if (!(devstr = qemuBuildChrChardevStr(&smartcard->data.passthru,
|
|
|
|
smartcard->info.alias,
|
|
|
|
caps))) {
|
|
|
|
virBufferFreeAndReset(&opt);
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
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
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (!def->nserials) {
|
|
|
|
/* If we have -device, then we set -nodefault already */
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_DEVICE))
|
|
|
|
virCommandAddArgList(cmd, "-serial", "none", NULL);
|
|
|
|
} else {
|
|
|
|
for (i = 0 ; i < def->nserials ; i++) {
|
|
|
|
virDomainChrDefPtr serial = def->serials[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 */
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_CHARDEV) &&
|
|
|
|
qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
|
|
|
virCommandAddArg(cmd, "-chardev");
|
|
|
|
if (!(devstr = qemuBuildChrChardevStr(&serial->source,
|
|
|
|
serial->info.alias,
|
|
|
|
caps)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
if (!(devstr = qemuBuildChrDeviceStr(serial, caps,
|
|
|
|
def->os.arch,
|
|
|
|
def->os.machine)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
} else {
|
|
|
|
virCommandAddArg(cmd, "-serial");
|
|
|
|
if (!(devstr = qemuBuildChrArgStr(&serial->source, NULL)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
if (!def->nparallels) {
|
|
|
|
/* If we have -device, then we set -nodefault already */
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_DEVICE))
|
|
|
|
virCommandAddArgList(cmd, "-parallel", "none", NULL);
|
|
|
|
} else {
|
|
|
|
for (i = 0 ; i < def->nparallels ; i++) {
|
|
|
|
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 */
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_CHARDEV) &&
|
|
|
|
qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
|
|
|
virCommandAddArg(cmd, "-chardev");
|
|
|
|
if (!(devstr = qemuBuildChrChardevStr(¶llel->source,
|
|
|
|
parallel->info.alias,
|
|
|
|
caps)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
virCommandAddArgFormat(cmd, "isa-parallel,chardev=char%s,id=%s",
|
|
|
|
parallel->info.alias,
|
|
|
|
parallel->info.alias);
|
|
|
|
} else {
|
|
|
|
virCommandAddArg(cmd, "-parallel");
|
|
|
|
if (!(devstr = qemuBuildChrArgStr(¶llel->source, NULL)))
|
|
|
|
goto error;
|
|
|
|
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
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
for (i = 0 ; i < def->nchannels ; i++) {
|
|
|
|
virDomainChrDefPtr channel = def->channels[i];
|
|
|
|
char *devstr;
|
|
|
|
char *addr;
|
|
|
|
int port;
|
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:
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_CHARDEV) ||
|
|
|
|
!qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
|
|
|
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
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-chardev");
|
|
|
|
if (!(devstr = qemuBuildChrChardevStr(&channel->source,
|
|
|
|
channel->info.alias,
|
|
|
|
caps)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
|
|
|
|
addr = virSocketAddrFormat(channel->target.addr);
|
|
|
|
if (!addr)
|
|
|
|
goto error;
|
|
|
|
port = virSocketAddrGetPort(channel->target.addr);
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-netdev");
|
|
|
|
virCommandAddArgFormat(cmd,
|
|
|
|
"user,guestfwd=tcp:%s:%i,chardev=char%s,id=user-%s",
|
|
|
|
addr, port, channel->info.alias,
|
|
|
|
channel->info.alias);
|
|
|
|
VIR_FREE(addr);
|
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:
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
|
|
|
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
|
|
|
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DEVICE_SPICEVMC) &&
|
|
|
|
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 {
|
|
|
|
virCommandAddArg(cmd, "-chardev");
|
|
|
|
if (!(devstr = qemuBuildChrChardevStr(&channel->source,
|
|
|
|
channel->info.alias,
|
|
|
|
caps)))
|
|
|
|
goto error;
|
|
|
|
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
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
if (!(devstr = qemuBuildVirtioSerialPortDevStr(channel,
|
|
|
|
caps)))
|
|
|
|
goto error;
|
|
|
|
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
|
|
|
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 */
|
|
|
|
for (i = 0 ; i < def->nconsoles ; i++) {
|
|
|
|
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) {
|
|
|
|
case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO:
|
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("virtio channel requires QEMU to support -device"));
|
|
|
|
goto error;
|
2012-03-09 07:26:24 +00:00
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-chardev");
|
|
|
|
if (!(devstr = qemuBuildChrChardevStr(&console->source,
|
|
|
|
console->info.alias,
|
|
|
|
caps)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
if (!(devstr = qemuBuildVirtioSerialPortDevStr(console,
|
|
|
|
caps)))
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
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
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
for (i = 0 ; i < def->ninputs ; i++) {
|
|
|
|
virDomainInputDefPtr input = def->inputs[i];
|
|
|
|
|
|
|
|
if (input->bus == VIR_DOMAIN_INPUT_BUS_USB) {
|
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
|
|
|
char *optstr;
|
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
if (!(optstr = qemuBuildUSBInputDevStr(input, caps)))
|
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 {
|
|
|
|
virCommandAddArgList(cmd, "-usbdevice",
|
|
|
|
input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE
|
|
|
|
? "mouse" : "tablet", NULL);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
2012-11-10 01:40:23 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-11-10 01:40:24 +00:00
|
|
|
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 (!qemuCapsGet(caps, QEMU_CAPS_0_10) && sdl + vnc + spice > 1) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("only 1 graphics device is supported"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
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"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-11-10 01:40:23 +00:00
|
|
|
for (i = 0 ; i < def->ngraphics ; ++i) {
|
|
|
|
if (qemuBuildGraphicsCommandLine(driver, cmd, def, caps,
|
|
|
|
def->graphics[i]) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
if (def->nvideos > 0) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_VGA)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
if (def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_XEN) {
|
|
|
|
/* nothing - vga has no effect on Xen pvfb */
|
|
|
|
} else {
|
|
|
|
if ((def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_QXL) &&
|
2012-08-20 16:44:14 +00:00
|
|
|
!qemuCapsGet(caps, 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *vgastr = qemuVideoTypeToString(def->videos[0]->type);
|
|
|
|
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"),
|
|
|
|
virDomainVideoTypeToString(def->videos[0]->type));
|
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
|
|
|
|
|
|
|
if (def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_QXL) {
|
|
|
|
if (def->videos[0]->vram &&
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
2011-03-15 03:50:09 +00:00
|
|
|
if (def->videos[0]->vram > (UINT_MAX / 1024)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("value for 'vram' must be less than '%u'"),
|
|
|
|
UINT_MAX / 1024);
|
2011-03-15 03:50:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2011-03-11 16:59:32 +00:00
|
|
|
virCommandAddArg(cmd, "-global");
|
2011-03-15 03:50:09 +00:00
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DEVICE_QXL_VGA))
|
2011-03-11 16:59:32 +00:00
|
|
|
virCommandAddArgFormat(cmd, "qxl-vga.vram_size=%u",
|
|
|
|
def->videos[0]->vram * 1024);
|
|
|
|
else
|
|
|
|
virCommandAddArgFormat(cmd, "qxl.vram_size=%u",
|
|
|
|
def->videos[0]->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
|
|
|
}
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
|
|
switch (def->videos[0]->type) {
|
|
|
|
case VIR_DOMAIN_VIDEO_TYPE_VGA:
|
|
|
|
virCommandAddArg(cmd, "-std-vga");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
|
|
|
|
virCommandAddArg(cmd, "-vmwarevga");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_VIDEO_TYPE_XEN:
|
|
|
|
case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
|
|
|
|
/* No special args - this is the default */
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("video type %s is not supported with this QEMU"),
|
|
|
|
virDomainVideoTypeToString(def->videos[0]->type));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->nvideos > 1) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
for (i = 1 ; i < def->nvideos ; i++) {
|
|
|
|
char *str;
|
|
|
|
if (def->videos[i]->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("video type %s is only valid as primary video card"),
|
|
|
|
virDomainVideoTypeToString(def->videos[0]->type));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!(str = qemuBuildVideoDevStr(def->videos[i], caps)))
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, str);
|
|
|
|
VIR_FREE(str);
|
|
|
|
}
|
|
|
|
} else {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("only one video card is currently supported"));
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/* If we have -device, then we set -nodefault already */
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_DEVICE) &&
|
|
|
|
qemuCapsGet(caps, QEMU_CAPS_VGA) &&
|
|
|
|
qemuCapsGet(caps, QEMU_CAPS_VGA_NONE))
|
2010-12-16 15:07:07 +00:00
|
|
|
virCommandAddArgList(cmd, "-vga", "none", NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add sound hardware */
|
|
|
|
if (def->nsounds) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
for (i = 0 ; i < def->nsounds ; i++) {
|
|
|
|
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");
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!(str = qemuBuildSoundDevStr(sound, caps)))
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, str);
|
2011-01-13 14:15:11 +00:00
|
|
|
|
|
|
|
if (sound->model == VIR_DOMAIN_SOUND_MODEL_ICH6) {
|
|
|
|
char *codecstr = NULL;
|
2012-05-15 22:55:10 +00:00
|
|
|
int ii;
|
2011-01-13 14:15:11 +00:00
|
|
|
|
2012-05-15 22:55:10 +00:00
|
|
|
for (ii = 0 ; ii < sound->ncodecs ; ii++) {
|
|
|
|
virCommandAddArg(cmd, "-device");
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!(codecstr = qemuBuildSoundCodecStr(sound, sound->codecs[ii], caps))) {
|
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);
|
|
|
|
}
|
|
|
|
if (ii == 0) {
|
|
|
|
virDomainSoundCodecDef codec = {
|
|
|
|
VIR_DOMAIN_SOUND_CODEC_TYPE_DUPLEX,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
virCommandAddArg(cmd, "-device");
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!(codecstr = qemuBuildSoundCodecStr(sound, &codec, caps))) {
|
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
|
|
|
VIR_FREE(str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int size = 100;
|
|
|
|
char *modstr;
|
|
|
|
if (VIR_ALLOC_N(modstr, size+1) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
for (i = 0 ; i < def->nsounds && size > 0 ; i++) {
|
|
|
|
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
|
|
|
|
|
|
|
if (sound->model == VIR_DOMAIN_SOUND_MODEL_ICH6) {
|
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;
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
optstr = qemuBuildWatchdogDevStr(watchdog, caps);
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(optstr = strdup(model)))
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
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 */
|
|
|
|
for (i = 0 ; i < def->nredirdevs ; i++) {
|
|
|
|
virDomainRedirdevDefPtr redirdev = def->redirdevs[i];
|
|
|
|
char *devstr;
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-chardev");
|
|
|
|
if (!(devstr = qemuBuildChrChardevStr(&redirdev->source.chr,
|
|
|
|
redirdev->info.alias,
|
2012-08-20 16:44:14 +00:00
|
|
|
caps))) {
|
2011-09-02 15:09:14 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_DEVICE))
|
2011-09-02 15:09:14 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-device");
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!(devstr = qemuBuildRedirdevDevStr(def, redirdev, caps)))
|
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 */
|
|
|
|
for (i = 0 ; i < def->nhostdevs ; i++) {
|
|
|
|
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 &&
|
|
|
|
hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("booting from assigned devices is only"
|
2012-11-14 14:51:30 +00:00
|
|
|
" supported for PCI and USB devices"));
|
2011-02-03 14:09:17 +00:00
|
|
|
goto error;
|
2012-11-14 14:51:30 +00:00
|
|
|
} else {
|
|
|
|
if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
|
|
|
|
!qemuCapsGet(caps, 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;
|
|
|
|
}
|
|
|
|
if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB &&
|
|
|
|
!qemuCapsGet(caps, QEMU_CAPS_USB_HOST_BOOTINDEX)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("booting from assigned USB 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) {
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virCommandAddArg(cmd, "-device");
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev, caps)))
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
} else {
|
|
|
|
virCommandAddArg(cmd, "-usbdevice");
|
|
|
|
if (!(devstr = qemuBuildUSBHostdevUsbDevStr(hostdev)))
|
|
|
|
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) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
char *configfd_name = NULL;
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, 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);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandTransferFD(cmd, configfd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
virCommandAddArg(cmd, "-device");
|
2012-08-20 16:44:14 +00:00
|
|
|
devstr = qemuBuildPCIHostdevDevStr(hostdev, configfd_name, caps);
|
2010-12-16 15:07:07 +00:00
|
|
|
VIR_FREE(configfd_name);
|
|
|
|
if (!devstr)
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, devstr);
|
|
|
|
VIR_FREE(devstr);
|
2012-08-20 16:44:14 +00:00
|
|
|
} else if (qemuCapsGet(caps, QEMU_CAPS_PCIDEVICE)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virCommandAddArg(cmd, "-pcidevice");
|
|
|
|
if (!(devstr = qemuBuildPCIHostdevPCIDevStr(hostdev)))
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-22 22:13:29 +00:00
|
|
|
/* Migration is very annoying due to wildly varying syntax &
|
|
|
|
* capabilities over time of KVM / QEMU codebases.
|
|
|
|
*/
|
|
|
|
if (migrateFrom) {
|
|
|
|
virCommandAddArg(cmd, "-incoming");
|
|
|
|
if (STRPREFIX(migrateFrom, "tcp")) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_MIGRATE_QEMU_TCP)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("TCP migration is not supported with "
|
|
|
|
"this QEMU binary"));
|
2010-12-22 22:13:29 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virCommandAddArg(cmd, migrateFrom);
|
|
|
|
} else if (STREQ(migrateFrom, "stdio")) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_MIGRATE_QEMU_FD)) {
|
2010-12-22 22:13:29 +00:00
|
|
|
virCommandAddArgFormat(cmd, "fd:%d", migrateFd);
|
|
|
|
virCommandPreserveFD(cmd, migrateFd);
|
2012-08-20 16:44:14 +00:00
|
|
|
} else if (qemuCapsGet(caps, QEMU_CAPS_MIGRATE_QEMU_EXEC)) {
|
2010-12-22 22:13:29 +00:00
|
|
|
virCommandAddArg(cmd, "exec:cat");
|
|
|
|
virCommandSetInputFD(cmd, migrateFd);
|
2012-08-20 16:44:14 +00:00
|
|
|
} else if (qemuCapsGet(caps, QEMU_CAPS_MIGRATE_KVM_STDIO)) {
|
2010-12-22 22:13:29 +00:00
|
|
|
virCommandAddArg(cmd, migrateFrom);
|
|
|
|
virCommandSetInputFD(cmd, migrateFd);
|
|
|
|
} else {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("STDIO migration is not supported "
|
|
|
|
"with this QEMU binary"));
|
2010-12-22 22:13:29 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else if (STRPREFIX(migrateFrom, "exec")) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_MIGRATE_QEMU_EXEC)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("EXEC migration is not supported "
|
|
|
|
"with this QEMU binary"));
|
2010-12-22 22:13:29 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virCommandAddArg(cmd, migrateFrom);
|
|
|
|
} else if (STRPREFIX(migrateFrom, "fd")) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_MIGRATE_QEMU_FD)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("FD migration is not supported "
|
|
|
|
"with this QEMU binary"));
|
2010-12-22 22:13:29 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virCommandAddArg(cmd, migrateFrom);
|
|
|
|
virCommandPreserveFD(cmd, migrateFd);
|
2011-02-01 08:33:34 +00:00
|
|
|
} else if (STRPREFIX(migrateFrom, "unix")) {
|
2012-08-20 16:44:14 +00:00
|
|
|
if (!qemuCapsGet(caps, QEMU_CAPS_MIGRATE_QEMU_UNIX)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("UNIX migration is not supported "
|
|
|
|
"with this QEMU binary"));
|
2011-02-01 08:33:34 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virCommandAddArg(cmd, migrateFrom);
|
2010-12-22 22:13:29 +00:00
|
|
|
} else {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("unknown migration protocol"));
|
2010-12-22 22:13:29 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
|
*/
|
|
|
|
if ((def->memballoon) &&
|
|
|
|
(def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
|
|
|
|
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;
|
|
|
|
}
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_DEVICE)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
char *optstr;
|
|
|
|
virCommandAddArg(cmd, "-device");
|
|
|
|
|
2012-08-20 16:44:14 +00:00
|
|
|
optstr = qemuBuildMemballoonDevStr(def->memballoon, caps);
|
2010-12-16 15:07:07 +00:00
|
|
|
if (!optstr)
|
|
|
|
goto error;
|
|
|
|
virCommandAddArg(cmd, optstr);
|
|
|
|
VIR_FREE(optstr);
|
2012-08-20 16:44:14 +00:00
|
|
|
} else if (qemuCapsGet(caps, QEMU_CAPS_BALLOON)) {
|
2010-12-16 15:07:07 +00:00
|
|
|
virCommandAddArgList(cmd, "-balloon", "virtio", NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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] : "");
|
|
|
|
}
|
|
|
|
|
2012-09-17 07:59:54 +00:00
|
|
|
if (qemuCapsGet(caps, QEMU_CAPS_SECCOMP_SANDBOX)) {
|
|
|
|
if (driver->seccompSandbox == 0)
|
|
|
|
virCommandAddArgList(cmd, "-sandbox", "off", NULL);
|
|
|
|
else if (driver->seccompSandbox > 0)
|
|
|
|
virCommandAddArgList(cmd, "-sandbox", "on", NULL);
|
|
|
|
} else if (driver->seccompSandbox > 0) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("QEMU does not support seccomp sandboxes"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
return cmd;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
error:
|
2011-07-04 06:27:12 +00:00
|
|
|
/* free up any resources in the network driver */
|
2010-12-16 15:07:07 +00:00
|
|
|
for (i = 0; i <= last_good_net; i++)
|
|
|
|
virDomainConfNWFilterTeardown(def->nets[i]);
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
qemuBuildChrDeviceStr(virDomainChrDefPtr serial,
|
2012-08-20 16:44:14 +00:00
|
|
|
qemuCapsPtr caps,
|
2011-11-21 12:50:42 +00:00
|
|
|
char *os_arch,
|
|
|
|
char *machine)
|
|
|
|
{
|
|
|
|
virBuffer cmd = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
2011-12-08 06:41:25 +00:00
|
|
|
if (STREQ(os_arch, "ppc64") && STREQ(machine, "pseries")) {
|
2012-05-29 08:35:17 +00:00
|
|
|
if (serial->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
|
|
|
|
serial->source.type == VIR_DOMAIN_CHR_TYPE_PTY &&
|
|
|
|
serial->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO) {
|
|
|
|
virBufferAsprintf(&cmd, "spapr-vty,chardev=char%s",
|
|
|
|
serial->info.alias);
|
2012-08-20 16:44:14 +00:00
|
|
|
if (qemuBuildDeviceAddressStr(&cmd, &serial->info, caps) < 0)
|
2012-05-29 08:35:17 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2011-12-08 06:41:25 +00:00
|
|
|
} else
|
2011-11-21 12:50:42 +00:00
|
|
|
virBufferAsprintf(&cmd, "isa-serial,chardev=char%s,id=%s",
|
|
|
|
serial->info.alias, serial->info.alias);
|
|
|
|
|
|
|
|
if (virBufferError(&cmd)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&cmd);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&cmd);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This method takes a string representing a QEMU command line ARGV set
|
|
|
|
* optionally prefixed by a list of environment variables. It then tries
|
|
|
|
* to split it up into a NULL terminated list of env & argv, splitting
|
|
|
|
* on space
|
|
|
|
*/
|
|
|
|
static int qemuStringToArgvEnv(const char *args,
|
|
|
|
const char ***retenv,
|
|
|
|
const char ***retargv)
|
|
|
|
{
|
|
|
|
char **arglist = NULL;
|
|
|
|
int argcount = 0;
|
|
|
|
int argalloc = 0;
|
|
|
|
int envend;
|
|
|
|
int i;
|
|
|
|
const char *curr = args;
|
|
|
|
const char *start;
|
|
|
|
const char **progenv = NULL;
|
|
|
|
const char **progargv = NULL;
|
|
|
|
|
|
|
|
/* Iterate over string, splitting on sequences of ' ' */
|
|
|
|
while (curr && *curr != '\0') {
|
|
|
|
char *arg;
|
|
|
|
const char *next;
|
|
|
|
|
|
|
|
start = curr;
|
|
|
|
/* accept a space in CEPH_ARGS */
|
|
|
|
if (STRPREFIX(curr, "CEPH_ARGS=-m ")) {
|
|
|
|
start += strlen("CEPH_ARGS=-m ");
|
|
|
|
}
|
|
|
|
if (*start == '\'') {
|
|
|
|
if (start == curr)
|
|
|
|
curr++;
|
|
|
|
next = strchr(start + 1, '\'');
|
|
|
|
} else if (*start == '"') {
|
|
|
|
if (start == curr)
|
|
|
|
curr++;
|
|
|
|
next = strchr(start + 1, '"');
|
|
|
|
} else {
|
|
|
|
next = strchr(start, ' ');
|
|
|
|
}
|
|
|
|
if (!next)
|
|
|
|
next = strchr(curr, '\n');
|
|
|
|
|
|
|
|
if (next) {
|
|
|
|
arg = strndup(curr, next-curr);
|
|
|
|
if (*next == '\'' ||
|
|
|
|
*next == '"')
|
|
|
|
next++;
|
|
|
|
} else {
|
|
|
|
arg = strdup(curr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!arg)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (argalloc == argcount) {
|
|
|
|
if (VIR_REALLOC_N(arglist, argalloc+10) < 0) {
|
|
|
|
VIR_FREE(arg);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
argalloc+=10;
|
|
|
|
}
|
|
|
|
|
|
|
|
arglist[argcount++] = arg;
|
|
|
|
|
|
|
|
while (next && c_isspace(*next))
|
|
|
|
next++;
|
|
|
|
|
|
|
|
curr = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Iterate over list of args, finding first arg not containing
|
|
|
|
* the '=' character (eg, skip over env vars FOO=bar) */
|
|
|
|
for (envend = 0 ; ((envend < argcount) &&
|
|
|
|
(strchr(arglist[envend], '=') != NULL));
|
|
|
|
envend++)
|
|
|
|
; /* nada */
|
|
|
|
|
|
|
|
/* Copy the list of env vars */
|
|
|
|
if (envend > 0) {
|
|
|
|
if (VIR_REALLOC_N(progenv, envend+1) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
for (i = 0 ; i < envend ; i++) {
|
|
|
|
progenv[i] = arglist[i];
|
|
|
|
arglist[i] = NULL;
|
|
|
|
}
|
|
|
|
progenv[i] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy the list of argv */
|
|
|
|
if (VIR_REALLOC_N(progargv, argcount-envend + 1) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
for (i = envend ; i < argcount ; i++)
|
|
|
|
progargv[i-envend] = arglist[i];
|
|
|
|
progargv[i-envend] = NULL;
|
|
|
|
|
|
|
|
VIR_FREE(arglist);
|
|
|
|
|
|
|
|
*retenv = progenv;
|
|
|
|
*retargv = progargv;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
for (i = 0 ; progenv && progenv[i] ; i++)
|
|
|
|
VIR_FREE(progenv[i]);
|
|
|
|
VIR_FREE(progenv);
|
|
|
|
for (i = 0 ; i < argcount ; i++)
|
|
|
|
VIR_FREE(arglist[i]);
|
|
|
|
VIR_FREE(arglist);
|
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Search for a named env variable, and return the value part
|
|
|
|
*/
|
|
|
|
static const char *qemuFindEnv(const char **progenv,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int len = strlen(name);
|
|
|
|
|
|
|
|
for (i = 0 ; progenv && progenv[i] ; i++) {
|
|
|
|
if (STREQLEN(progenv[i], name, len) &&
|
|
|
|
progenv[i][len] == '=')
|
|
|
|
return progenv[i] + len + 1;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Takes a string containing a set of key=value,key=value,key...
|
|
|
|
* parameters and splits them up, returning two arrays with
|
|
|
|
* the individual keys and values. If allowEmptyValue is nonzero,
|
|
|
|
* the "=value" part is optional and if a key with no value is found,
|
|
|
|
* NULL is be placed into corresponding place in retvalues.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
qemuParseKeywords(const char *str,
|
|
|
|
char ***retkeywords,
|
|
|
|
char ***retvalues,
|
|
|
|
int allowEmptyValue)
|
|
|
|
{
|
|
|
|
int keywordCount = 0;
|
|
|
|
int keywordAlloc = 0;
|
|
|
|
char **keywords = NULL;
|
|
|
|
char **values = NULL;
|
|
|
|
const char *start = str;
|
|
|
|
const char *end;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
*retkeywords = NULL;
|
|
|
|
*retvalues = NULL;
|
|
|
|
end = start + strlen(str);
|
|
|
|
|
|
|
|
while (start) {
|
|
|
|
const char *separator;
|
|
|
|
const char *endmark;
|
|
|
|
char *keyword;
|
|
|
|
char *value = NULL;
|
|
|
|
|
2012-03-09 19:13:30 +00:00
|
|
|
endmark = start;
|
|
|
|
do {
|
|
|
|
/* Qemu accepts ',,' as an escape for a literal comma;
|
|
|
|
* skip past those here while searching for the end of the
|
|
|
|
* value, then strip them down below */
|
|
|
|
endmark = strchr(endmark, ',');
|
|
|
|
} while (endmark && endmark[1] == ',' && (endmark += 2));
|
|
|
|
if (!endmark)
|
2010-12-16 15:07:07 +00:00
|
|
|
endmark = end;
|
|
|
|
if (!(separator = strchr(start, '=')))
|
|
|
|
separator = end;
|
|
|
|
|
|
|
|
if (separator >= endmark) {
|
|
|
|
if (!allowEmptyValue) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("malformed keyword arguments in '%s'"), str);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
separator = endmark;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(keyword = strndup(start, separator - start)))
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (separator < endmark) {
|
|
|
|
separator++;
|
|
|
|
if (!(value = strndup(separator, endmark - separator))) {
|
|
|
|
VIR_FREE(keyword);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
2012-03-09 19:13:30 +00:00
|
|
|
if (strchr(value, ',')) {
|
|
|
|
char *p = strchr(value, ',') + 1;
|
|
|
|
char *q = p + 1;
|
|
|
|
while (*q) {
|
|
|
|
if (*q == ',')
|
|
|
|
q++;
|
|
|
|
*p++ = *q++;
|
|
|
|
}
|
|
|
|
*p = '\0';
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (keywordAlloc == keywordCount) {
|
|
|
|
if (VIR_REALLOC_N(keywords, keywordAlloc + 10) < 0 ||
|
|
|
|
VIR_REALLOC_N(values, keywordAlloc + 10) < 0) {
|
|
|
|
VIR_FREE(keyword);
|
|
|
|
VIR_FREE(value);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
keywordAlloc += 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
keywords[keywordCount] = keyword;
|
|
|
|
values[keywordCount] = value;
|
|
|
|
keywordCount++;
|
|
|
|
|
|
|
|
start = endmark < end ? endmark + 1 : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*retkeywords = keywords;
|
|
|
|
*retvalues = values;
|
|
|
|
|
|
|
|
return keywordCount;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
error:
|
|
|
|
for (i = 0 ; i < keywordCount ; i++) {
|
|
|
|
VIR_FREE(keywords[i]);
|
|
|
|
VIR_FREE(values[i]);
|
|
|
|
}
|
|
|
|
VIR_FREE(keywords);
|
|
|
|
VIR_FREE(values);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Tries to parse new style QEMU -drive args.
|
|
|
|
*
|
|
|
|
* eg -drive file=/dev/HostVG/VirtData1,if=ide,index=1
|
|
|
|
*
|
|
|
|
* Will fail if not using the 'index' keyword
|
|
|
|
*/
|
|
|
|
static virDomainDiskDefPtr
|
|
|
|
qemuParseCommandLineDisk(virCapsPtr caps,
|
|
|
|
const char *val,
|
2011-11-01 01:29:07 +00:00
|
|
|
int nvirtiodisk,
|
|
|
|
bool old_style_ceph_args)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virDomainDiskDefPtr def = NULL;
|
|
|
|
char **keywords;
|
|
|
|
char **values;
|
|
|
|
int nkeywords;
|
|
|
|
int i;
|
|
|
|
int idx = -1;
|
|
|
|
int busid = -1;
|
|
|
|
int unitid = -1;
|
2012-08-20 13:58:51 +00:00
|
|
|
int trans = VIR_DOMAIN_DISK_TRANS_DEFAULT;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if ((nkeywords = qemuParseKeywords(val,
|
|
|
|
&keywords,
|
|
|
|
&values, 0)) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->bus = VIR_DOMAIN_DISK_BUS_IDE;
|
|
|
|
def->device = VIR_DOMAIN_DISK_DEVICE_DISK;
|
|
|
|
def->type = VIR_DOMAIN_DISK_TYPE_FILE;
|
|
|
|
|
|
|
|
for (i = 0 ; i < nkeywords ; i++) {
|
|
|
|
if (STREQ(keywords[i], "file")) {
|
|
|
|
if (values[i] && STRNEQ(values[i], "")) {
|
|
|
|
def->src = values[i];
|
|
|
|
values[i] = NULL;
|
|
|
|
if (STRPREFIX(def->src, "/dev/"))
|
|
|
|
def->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
|
|
|
|
else if (STRPREFIX(def->src, "nbd:")) {
|
|
|
|
char *host, *port;
|
|
|
|
|
|
|
|
def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
|
|
|
|
def->protocol = VIR_DOMAIN_DISK_PROTOCOL_NBD;
|
|
|
|
host = def->src + strlen("nbd:");
|
|
|
|
port = strchr(host, ':');
|
|
|
|
if (!port) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse nbd filename '%s'"),
|
|
|
|
def->src);
|
2011-02-15 00:34:05 +00:00
|
|
|
def = NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
*port++ = '\0';
|
|
|
|
if (VIR_ALLOC(def->hosts) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
def->nhosts = 1;
|
|
|
|
def->hosts->name = strdup(host);
|
|
|
|
if (!def->hosts->name) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
def->hosts->port = strdup(port);
|
|
|
|
if (!def->hosts->port) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-11-22 18:10:38 +00:00
|
|
|
def->hosts->transport = VIR_DOMAIN_DISK_PROTO_TRANS_TCP;
|
|
|
|
def->hosts->socket = NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
VIR_FREE(def->src);
|
|
|
|
def->src = NULL;
|
|
|
|
} else if (STRPREFIX(def->src, "rbd:")) {
|
|
|
|
char *p = def->src;
|
|
|
|
|
|
|
|
def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
|
|
|
|
def->protocol = VIR_DOMAIN_DISK_PROTOCOL_RBD;
|
|
|
|
def->src = strdup(p + strlen("rbd:"));
|
|
|
|
if (!def->src) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-11-01 01:29:07 +00:00
|
|
|
/* old-style CEPH_ARGS env variable is parsed later */
|
|
|
|
if (!old_style_ceph_args && qemuParseRBDString(def) < 0)
|
|
|
|
goto cleanup;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
VIR_FREE(p);
|
2012-11-22 18:10:39 +00:00
|
|
|
} else if (STRPREFIX(def->src, "gluster")) {
|
|
|
|
def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
|
|
|
|
def->protocol = VIR_DOMAIN_DISK_PROTOCOL_GLUSTER;
|
|
|
|
|
|
|
|
if (qemuParseGlusterString(def) < 0)
|
|
|
|
goto cleanup;
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (STRPREFIX(def->src, "sheepdog:")) {
|
|
|
|
char *p = def->src;
|
|
|
|
char *port, *vdi;
|
|
|
|
|
|
|
|
def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
|
|
|
|
def->protocol = VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG;
|
|
|
|
def->src = strdup(p + strlen("sheepdog:"));
|
|
|
|
if (!def->src) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* def->src must be [vdiname] or [host]:[port]:[vdiname] */
|
|
|
|
port = strchr(def->src, ':');
|
|
|
|
if (port) {
|
|
|
|
*port++ = '\0';
|
|
|
|
vdi = strchr(port, ':');
|
|
|
|
if (!vdi) {
|
|
|
|
def = NULL;
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse sheepdog filename '%s'"), p);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
*vdi++ = '\0';
|
|
|
|
if (VIR_ALLOC(def->hosts) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
def->nhosts = 1;
|
|
|
|
def->hosts->name = def->src;
|
|
|
|
def->hosts->port = strdup(port);
|
|
|
|
if (!def->hosts->port) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-11-22 18:10:38 +00:00
|
|
|
def->hosts->transport = VIR_DOMAIN_DISK_PROTO_TRANS_TCP;
|
|
|
|
def->hosts->socket = NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
def->src = strdup(vdi);
|
|
|
|
if (!def->src) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(p);
|
|
|
|
} else
|
|
|
|
def->type = VIR_DOMAIN_DISK_TYPE_FILE;
|
|
|
|
} else {
|
|
|
|
def->type = VIR_DOMAIN_DISK_TYPE_FILE;
|
|
|
|
}
|
|
|
|
} else if (STREQ(keywords[i], "if")) {
|
|
|
|
if (STREQ(values[i], "ide"))
|
|
|
|
def->bus = VIR_DOMAIN_DISK_BUS_IDE;
|
|
|
|
else if (STREQ(values[i], "scsi"))
|
|
|
|
def->bus = VIR_DOMAIN_DISK_BUS_SCSI;
|
|
|
|
else if (STREQ(values[i], "virtio"))
|
|
|
|
def->bus = VIR_DOMAIN_DISK_BUS_VIRTIO;
|
|
|
|
else if (STREQ(values[i], "xen"))
|
|
|
|
def->bus = VIR_DOMAIN_DISK_BUS_XEN;
|
|
|
|
} else if (STREQ(keywords[i], "media")) {
|
|
|
|
if (STREQ(values[i], "cdrom")) {
|
|
|
|
def->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
|
|
|
|
def->readonly = 1;
|
|
|
|
} else if (STREQ(values[i], "floppy"))
|
|
|
|
def->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
|
|
|
|
} else if (STREQ(keywords[i], "format")) {
|
|
|
|
def->driverName = strdup("qemu");
|
|
|
|
if (!def->driverName) {
|
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-10-15 21:47:42 +00:00
|
|
|
def->format = virStorageFileFormatTypeFromString(values[i]);
|
2010-12-16 15:07:07 +00:00
|
|
|
values[i] = NULL;
|
|
|
|
} else if (STREQ(keywords[i], "cache")) {
|
|
|
|
if (STREQ(values[i], "off") ||
|
|
|
|
STREQ(values[i], "none"))
|
|
|
|
def->cachemode = VIR_DOMAIN_DISK_CACHE_DISABLE;
|
|
|
|
else if (STREQ(values[i], "writeback") ||
|
|
|
|
STREQ(values[i], "on"))
|
|
|
|
def->cachemode = VIR_DOMAIN_DISK_CACHE_WRITEBACK;
|
|
|
|
else if (STREQ(values[i], "writethrough"))
|
|
|
|
def->cachemode = VIR_DOMAIN_DISK_CACHE_WRITETHRU;
|
2011-09-02 13:36:58 +00:00
|
|
|
else if (STREQ(values[i], "directsync"))
|
|
|
|
def->cachemode = VIR_DOMAIN_DISK_CACHE_DIRECTSYNC;
|
2011-09-22 19:33:47 +00:00
|
|
|
else if (STREQ(values[i], "unsafe"))
|
|
|
|
def->cachemode = VIR_DOMAIN_DISK_CACHE_UNSAFE;
|
2011-10-04 18:17:06 +00:00
|
|
|
} else if (STREQ(keywords[i], "werror")) {
|
2010-12-16 15:07:07 +00:00
|
|
|
if (STREQ(values[i], "stop"))
|
|
|
|
def->error_policy = VIR_DOMAIN_DISK_ERROR_POLICY_STOP;
|
2011-10-04 18:17:06 +00:00
|
|
|
else if (STREQ(values[i], "report"))
|
|
|
|
def->error_policy = VIR_DOMAIN_DISK_ERROR_POLICY_REPORT;
|
2010-12-16 15:07:07 +00:00
|
|
|
else if (STREQ(values[i], "ignore"))
|
|
|
|
def->error_policy = VIR_DOMAIN_DISK_ERROR_POLICY_IGNORE;
|
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
|
|
|
else if (STREQ(values[i], "enospc"))
|
2010-12-16 15:07:07 +00:00
|
|
|
def->error_policy = VIR_DOMAIN_DISK_ERROR_POLICY_ENOSPACE;
|
2011-10-04 18:17:06 +00:00
|
|
|
} else if (STREQ(keywords[i], "rerror")) {
|
|
|
|
if (STREQ(values[i], "stop"))
|
|
|
|
def->rerror_policy = VIR_DOMAIN_DISK_ERROR_POLICY_STOP;
|
|
|
|
else if (STREQ(values[i], "report"))
|
|
|
|
def->rerror_policy = VIR_DOMAIN_DISK_ERROR_POLICY_REPORT;
|
|
|
|
else if (STREQ(values[i], "ignore"))
|
|
|
|
def->rerror_policy = VIR_DOMAIN_DISK_ERROR_POLICY_IGNORE;
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (STREQ(keywords[i], "index")) {
|
|
|
|
if (virStrToLong_i(values[i], NULL, 10, &idx) < 0) {
|
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse drive index '%s'"), val);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else if (STREQ(keywords[i], "bus")) {
|
|
|
|
if (virStrToLong_i(values[i], NULL, 10, &busid) < 0) {
|
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse drive bus '%s'"), val);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else if (STREQ(keywords[i], "unit")) {
|
|
|
|
if (virStrToLong_i(values[i], NULL, 10, &unitid) < 0) {
|
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse drive unit '%s'"), val);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else if (STREQ(keywords[i], "readonly")) {
|
|
|
|
if ((values[i] == NULL) || STREQ(values[i], "on"))
|
|
|
|
def->readonly = 1;
|
2010-04-21 14:28:21 +00:00
|
|
|
} else if (STREQ(keywords[i], "aio")) {
|
|
|
|
if ((def->iomode = virDomainDiskIoTypeFromString(values[i])) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse io mode '%s'"), values[i]);
|
2010-04-21 14:28:21 +00:00
|
|
|
}
|
2012-08-20 13:58:51 +00:00
|
|
|
} else if (STREQ(keywords[i], "cyls")) {
|
|
|
|
if (virStrToLong_ui(values[i], NULL, 10,
|
|
|
|
&(def->geometry.cylinders)) < 0) {
|
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse cylinders value'%s'"),
|
|
|
|
values[i]);
|
|
|
|
}
|
|
|
|
} else if (STREQ(keywords[i], "heads")) {
|
|
|
|
if (virStrToLong_ui(values[i], NULL, 10,
|
|
|
|
&(def->geometry.heads)) < 0) {
|
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse heads value'%s'"),
|
|
|
|
values[i]);
|
|
|
|
}
|
|
|
|
} else if (STREQ(keywords[i], "secs")) {
|
|
|
|
if (virStrToLong_ui(values[i], NULL, 10,
|
|
|
|
&(def->geometry.sectors)) < 0) {
|
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse sectors value'%s'"),
|
|
|
|
values[i]);
|
|
|
|
}
|
|
|
|
} else if (STREQ(keywords[i], "trans")) {
|
|
|
|
def->geometry.trans =
|
|
|
|
virDomainDiskGeometryTransTypeFromString(values[i]);
|
|
|
|
if ((trans < VIR_DOMAIN_DISK_TRANS_DEFAULT) ||
|
|
|
|
(trans >= VIR_DOMAIN_DISK_TRANS_LAST)) {
|
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse translation value'%s'"),
|
|
|
|
values[i]);
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-04 18:17:06 +00:00
|
|
|
if (def->rerror_policy == def->error_policy)
|
|
|
|
def->rerror_policy = 0;
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (!def->src &&
|
|
|
|
def->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
|
|
|
|
def->type != VIR_DOMAIN_DISK_TYPE_NETWORK) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("missing file parameter in drive '%s'"), val);
|
2010-12-16 15:07:07 +00:00
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (idx == -1 &&
|
|
|
|
def->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
|
|
|
|
idx = nvirtiodisk;
|
|
|
|
|
|
|
|
if (idx == -1 &&
|
|
|
|
unitid == -1 &&
|
|
|
|
busid == -1) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("missing index/unit/bus parameter in drive '%s'"), val);
|
2010-12-16 15:07:07 +00:00
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (idx == -1) {
|
|
|
|
if (unitid == -1)
|
|
|
|
unitid = 0;
|
|
|
|
if (busid == -1)
|
|
|
|
busid = 0;
|
|
|
|
switch (def->bus) {
|
|
|
|
case VIR_DOMAIN_DISK_BUS_IDE:
|
|
|
|
idx = (busid * 2) + unitid;
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_BUS_SCSI:
|
|
|
|
idx = (busid * 7) + unitid;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
idx = unitid;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) {
|
|
|
|
def->dst = strdup("hda");
|
|
|
|
} else if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
|
|
|
|
def->dst = strdup("sda");
|
|
|
|
} else if (def->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
|
|
|
|
def->dst = strdup("vda");
|
|
|
|
} else if (def->bus == VIR_DOMAIN_DISK_BUS_XEN) {
|
|
|
|
def->dst = strdup("xvda");
|
|
|
|
} else {
|
|
|
|
def->dst = strdup("hda");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!def->dst) {
|
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (STREQ(def->dst, "xvda"))
|
|
|
|
def->dst[3] = 'a' + idx;
|
|
|
|
else
|
|
|
|
def->dst[2] = 'a' + idx;
|
|
|
|
|
|
|
|
if (virDomainDiskDefAssignAddress(caps, def) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("invalid device name '%s'"), def->dst);
|
2010-12-16 15:07:07 +00:00
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
/* fall through to "cleanup" */
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
for (i = 0 ; i < nkeywords ; i++) {
|
|
|
|
VIR_FREE(keywords[i]);
|
|
|
|
VIR_FREE(values[i]);
|
|
|
|
}
|
|
|
|
VIR_FREE(keywords);
|
|
|
|
VIR_FREE(values);
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Tries to find a NIC definition matching a vlan we want
|
|
|
|
*/
|
|
|
|
static const char *
|
|
|
|
qemuFindNICForVLAN(int nnics,
|
|
|
|
const char **nics,
|
|
|
|
int wantvlan)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0 ; i < nnics ; i++) {
|
|
|
|
int gotvlan;
|
|
|
|
const char *tmp = strstr(nics[i], "vlan=");
|
|
|
|
char *end;
|
|
|
|
if (!tmp)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
tmp += strlen("vlan=");
|
|
|
|
|
|
|
|
if (virStrToLong_i(tmp, &end, 10, &gotvlan) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse NIC vlan in '%s'"), nics[i]);
|
2010-12-16 15:07:07 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gotvlan == wantvlan)
|
|
|
|
return nics[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wantvlan == 0 && nnics > 0)
|
|
|
|
return nics[0];
|
|
|
|
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot find NIC definition for vlan %d"), wantvlan);
|
2010-12-16 15:07:07 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Tries to parse a QEMU -net backend argument. Gets given
|
|
|
|
* a list of all known -net frontend arguments to try and
|
|
|
|
* match up against. Horribly complicated stuff
|
|
|
|
*/
|
|
|
|
static virDomainNetDefPtr
|
|
|
|
qemuParseCommandLineNet(virCapsPtr caps,
|
|
|
|
const char *val,
|
|
|
|
int nnics,
|
|
|
|
const char **nics)
|
|
|
|
{
|
|
|
|
virDomainNetDefPtr def = NULL;
|
|
|
|
char **keywords = NULL;
|
|
|
|
char **values = NULL;
|
|
|
|
int nkeywords;
|
|
|
|
const char *nic;
|
|
|
|
int wantvlan = 0;
|
|
|
|
const char *tmp;
|
|
|
|
int genmac = 1;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
tmp = strchr(val, ',');
|
|
|
|
|
|
|
|
if (tmp) {
|
|
|
|
if ((nkeywords = qemuParseKeywords(tmp+1,
|
|
|
|
&keywords,
|
|
|
|
&values, 0)) < 0)
|
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
nkeywords = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 'tap' could turn into libvirt type=ethernet, type=bridge or
|
|
|
|
* type=network, but we can't tell, so use the generic config */
|
|
|
|
if (STRPREFIX(val, "tap,"))
|
|
|
|
def->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
|
|
|
|
else if (STRPREFIX(val, "socket"))
|
|
|
|
def->type = VIR_DOMAIN_NET_TYPE_CLIENT;
|
|
|
|
else if (STRPREFIX(val, "user"))
|
|
|
|
def->type = VIR_DOMAIN_NET_TYPE_USER;
|
|
|
|
else
|
|
|
|
def->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
|
|
|
|
|
|
|
|
for (i = 0 ; i < nkeywords ; i++) {
|
|
|
|
if (STREQ(keywords[i], "vlan")) {
|
|
|
|
if (virStrToLong_i(values[i], NULL, 10, &wantvlan) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse vlan in '%s'"), val);
|
2010-12-16 15:07:07 +00:00
|
|
|
virDomainNetDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else if (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
|
|
|
|
STREQ(keywords[i], "script") && STRNEQ(values[i], "")) {
|
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
|
|
|
def->script = values[i];
|
2010-12-16 15:07:07 +00:00
|
|
|
values[i] = NULL;
|
|
|
|
} else if (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
|
|
|
|
STREQ(keywords[i], "ifname")) {
|
|
|
|
def->ifname = values[i];
|
|
|
|
values[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Done parsing the nic backend. Now to try and find corresponding
|
|
|
|
* frontend, based off vlan number. NB this assumes a 1-1 mapping
|
|
|
|
*/
|
|
|
|
|
|
|
|
nic = qemuFindNICForVLAN(nnics, nics, wantvlan);
|
|
|
|
if (!nic) {
|
|
|
|
virDomainNetDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!STRPREFIX(nic, "nic")) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse NIC definition '%s'"), nic);
|
2010-12-16 15:07:07 +00:00
|
|
|
virDomainNetDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0 ; i < nkeywords ; i++) {
|
|
|
|
VIR_FREE(keywords[i]);
|
|
|
|
VIR_FREE(values[i]);
|
|
|
|
}
|
|
|
|
VIR_FREE(keywords);
|
|
|
|
VIR_FREE(values);
|
|
|
|
|
|
|
|
if (STRPREFIX(nic, "nic,")) {
|
|
|
|
if ((nkeywords = qemuParseKeywords(nic + strlen("nic,"),
|
|
|
|
&keywords,
|
|
|
|
&values, 0)) < 0) {
|
|
|
|
virDomainNetDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
nkeywords = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0 ; i < nkeywords ; i++) {
|
|
|
|
if (STREQ(keywords[i], "macaddr")) {
|
|
|
|
genmac = 0;
|
2012-07-17 12:07:59 +00:00
|
|
|
if (virMacAddrParse(values[i], &def->mac) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unable to parse mac address '%s'"),
|
|
|
|
values[i]);
|
2010-12-16 15:07:07 +00:00
|
|
|
virDomainNetDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else if (STREQ(keywords[i], "model")) {
|
|
|
|
def->model = values[i];
|
|
|
|
values[i] = NULL;
|
2011-01-12 04:18:49 +00:00
|
|
|
} else if (STREQ(keywords[i], "vhost")) {
|
|
|
|
if ((values[i] == NULL) || STREQ(values[i], "on")) {
|
Restructure domain struct interface "driver" data for easier expansion
When the <driver> element (and its "name" attribute) was added to the
domain XML's interface element, a "backend" enum was simply added to
the toplevel of the virDomainNetDef struct.
Ignoring the naming inconsistency ("name" vs. "backend"), this is fine
when there's only a single item contained in the driver element of the
XML, but doesn't scale well as we add more attributes that apply to
the backend of the virtio-net driver, or add attributes applicable to
other drivers.
This patch changes virDomainNetDef in two ways:
1) Rename the item in the struct from "backend" to "name", so that
it's the same in the XML and in the struct, hopefully avoiding
confusion for someone unfamiliar with the function of the
attribute.
2) Create a "driver" union within virDomainNetDef, and a "virtio"
struct in that struct, which contains the "name" enum value.
3) Move around the virDomainNetParse and virDomainNetFormat functions
to allow for simple plugin of new attributes without disturbing
existing code. (you'll note that this results in a seemingly
redundant if() in the format function, but that will no longer be
the case as soon as a 2nd attribute is added).
In the future, new attributes for the virtio driver backend can be
added to the "virtio" struct, and any other network device backend that
needs an attribute will have its own struct added to the "driver"
union.
2011-02-03 18:52:08 +00:00
|
|
|
def->driver.virtio.name = VIR_DOMAIN_NET_BACKEND_TYPE_VHOST;
|
2011-01-12 04:18:49 +00:00
|
|
|
} else if (STREQ(keywords[i], "off")) {
|
Restructure domain struct interface "driver" data for easier expansion
When the <driver> element (and its "name" attribute) was added to the
domain XML's interface element, a "backend" enum was simply added to
the toplevel of the virDomainNetDef struct.
Ignoring the naming inconsistency ("name" vs. "backend"), this is fine
when there's only a single item contained in the driver element of the
XML, but doesn't scale well as we add more attributes that apply to
the backend of the virtio-net driver, or add attributes applicable to
other drivers.
This patch changes virDomainNetDef in two ways:
1) Rename the item in the struct from "backend" to "name", so that
it's the same in the XML and in the struct, hopefully avoiding
confusion for someone unfamiliar with the function of the
attribute.
2) Create a "driver" union within virDomainNetDef, and a "virtio"
struct in that struct, which contains the "name" enum value.
3) Move around the virDomainNetParse and virDomainNetFormat functions
to allow for simple plugin of new attributes without disturbing
existing code. (you'll note that this results in a seemingly
redundant if() in the format function, but that will no longer be
the case as soon as a 2nd attribute is added).
In the future, new attributes for the virtio driver backend can be
added to the "virtio" struct, and any other network device backend that
needs an attribute will have its own struct added to the "driver"
union.
2011-02-03 18:52:08 +00:00
|
|
|
def->driver.virtio.name = VIR_DOMAIN_NET_BACKEND_TYPE_QEMU;
|
2011-01-12 04:18:49 +00:00
|
|
|
}
|
2011-01-12 19:38:01 +00:00
|
|
|
} else if (STREQ(keywords[i], "sndbuf") && values[i]) {
|
|
|
|
if (virStrToLong_ul(values[i], NULL, 10, &def->tune.sndbuf) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse sndbuf size in '%s'"), val);
|
2011-01-12 19:38:01 +00:00
|
|
|
virDomainNetDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
def->tune.sndbuf_specified = true;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (genmac)
|
2012-07-17 12:07:59 +00:00
|
|
|
virCapabilitiesGenerateMac(caps, &def->mac);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
for (i = 0 ; i < nkeywords ; i++) {
|
|
|
|
VIR_FREE(keywords[i]);
|
|
|
|
VIR_FREE(values[i]);
|
|
|
|
}
|
|
|
|
VIR_FREE(keywords);
|
|
|
|
VIR_FREE(values);
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Tries to parse a QEMU PCI device
|
|
|
|
*/
|
|
|
|
static virDomainHostdevDefPtr
|
|
|
|
qemuParseCommandLinePCI(const char *val)
|
|
|
|
{
|
|
|
|
int bus = 0, slot = 0, func = 0;
|
|
|
|
const char *start;
|
|
|
|
char *end;
|
2012-01-31 09:16:54 +00:00
|
|
|
virDomainHostdevDefPtr def = virDomainHostdevDefAlloc();
|
|
|
|
|
|
|
|
if (!def)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (!STRPREFIX(val, "host=")) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown PCI device syntax '%s'"), val);
|
2012-01-31 09:16:54 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
start = val + strlen("host=");
|
|
|
|
if (virStrToLong_i(start, &end, 16, &bus) < 0 || *end != ':') {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot extract PCI device bus '%s'"), val);
|
2012-01-31 09:16:54 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
start = end + 1;
|
|
|
|
if (virStrToLong_i(start, &end, 16, &slot) < 0 || *end != '.') {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot extract PCI device slot '%s'"), val);
|
2012-01-31 09:16:54 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
start = end + 1;
|
|
|
|
if (virStrToLong_i(start, NULL, 16, &func) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot extract PCI device function '%s'"), val);
|
2012-01-31 09:16:54 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
def->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
|
|
|
|
def->managed = 1;
|
|
|
|
def->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
|
|
|
|
def->source.subsys.u.pci.bus = bus;
|
|
|
|
def->source.subsys.u.pci.slot = slot;
|
|
|
|
def->source.subsys.u.pci.function = func;
|
|
|
|
return def;
|
2012-01-31 09:16:54 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainHostdevDefFree(def);
|
|
|
|
return NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Tries to parse a QEMU USB device
|
|
|
|
*/
|
|
|
|
static virDomainHostdevDefPtr
|
|
|
|
qemuParseCommandLineUSB(const char *val)
|
|
|
|
{
|
2012-01-31 09:16:54 +00:00
|
|
|
virDomainHostdevDefPtr def = virDomainHostdevDefAlloc();
|
2010-12-16 15:07:07 +00:00
|
|
|
int first = 0, second = 0;
|
|
|
|
const char *start;
|
|
|
|
char *end;
|
|
|
|
|
2012-01-31 09:16:54 +00:00
|
|
|
if (!def)
|
|
|
|
goto error;
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (!STRPREFIX(val, "host:")) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown USB device syntax '%s'"), val);
|
2012-01-31 09:16:54 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
start = val + strlen("host:");
|
|
|
|
if (strchr(start, ':')) {
|
|
|
|
if (virStrToLong_i(start, &end, 16, &first) < 0 || *end != ':') {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot extract USB device vendor '%s'"), val);
|
2012-01-31 09:16:54 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
start = end + 1;
|
|
|
|
if (virStrToLong_i(start, NULL, 16, &second) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot extract USB device product '%s'"), val);
|
2012-01-31 09:16:54 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (virStrToLong_i(start, &end, 10, &first) < 0 || *end != '.') {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot extract USB device bus '%s'"), val);
|
2012-01-31 09:16:54 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
start = end + 1;
|
|
|
|
if (virStrToLong_i(start, NULL, 10, &second) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot extract USB device address '%s'"), val);
|
2012-01-31 09:16:54 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
def->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
|
|
|
|
def->managed = 0;
|
|
|
|
def->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB;
|
|
|
|
if (*end == '.') {
|
|
|
|
def->source.subsys.u.usb.bus = first;
|
|
|
|
def->source.subsys.u.usb.device = second;
|
|
|
|
} else {
|
|
|
|
def->source.subsys.u.usb.vendor = first;
|
|
|
|
def->source.subsys.u.usb.product = second;
|
|
|
|
}
|
|
|
|
return def;
|
2012-01-31 09:16:54 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainHostdevDefFree(def);
|
|
|
|
return NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Tries to parse a QEMU serial/parallel device
|
|
|
|
*/
|
2011-06-17 14:31:02 +00:00
|
|
|
static int
|
|
|
|
qemuParseCommandLineChr(virDomainChrSourceDefPtr source,
|
|
|
|
const char *val)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
if (STREQ(val, "null")) {
|
2011-06-17 14:31:02 +00:00
|
|
|
source->type = VIR_DOMAIN_CHR_TYPE_NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (STREQ(val, "vc")) {
|
2011-06-17 14:31:02 +00:00
|
|
|
source->type = VIR_DOMAIN_CHR_TYPE_VC;
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (STREQ(val, "pty")) {
|
2011-06-17 14:31:02 +00:00
|
|
|
source->type = VIR_DOMAIN_CHR_TYPE_PTY;
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (STRPREFIX(val, "file:")) {
|
2011-06-17 14:31:02 +00:00
|
|
|
source->type = VIR_DOMAIN_CHR_TYPE_FILE;
|
|
|
|
source->data.file.path = strdup(val+strlen("file:"));
|
|
|
|
if (!source->data.file.path)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
} else if (STRPREFIX(val, "pipe:")) {
|
2011-06-17 14:31:02 +00:00
|
|
|
source->type = VIR_DOMAIN_CHR_TYPE_PIPE;
|
|
|
|
source->data.file.path = strdup(val+strlen("pipe:"));
|
|
|
|
if (!source->data.file.path)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
} else if (STREQ(val, "stdio")) {
|
2011-06-17 14:31:02 +00:00
|
|
|
source->type = VIR_DOMAIN_CHR_TYPE_STDIO;
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (STRPREFIX(val, "udp:")) {
|
|
|
|
const char *svc1, *host2, *svc2;
|
2011-06-17 14:31:02 +00:00
|
|
|
source->type = VIR_DOMAIN_CHR_TYPE_UDP;
|
2010-12-16 15:07:07 +00:00
|
|
|
val += strlen("udp:");
|
|
|
|
svc1 = strchr(val, ':');
|
|
|
|
host2 = svc1 ? strchr(svc1, '@') : NULL;
|
|
|
|
svc2 = host2 ? strchr(host2, ':') : NULL;
|
|
|
|
|
2011-08-11 07:19:51 +00:00
|
|
|
if (svc1 && (svc1 != val)) {
|
2011-06-17 14:31:02 +00:00
|
|
|
source->data.udp.connectHost = strndup(val, svc1-val);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-08-11 07:19:51 +00:00
|
|
|
if (!source->data.udp.connectHost)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (svc1) {
|
|
|
|
svc1++;
|
|
|
|
if (host2)
|
2011-06-17 14:31:02 +00:00
|
|
|
source->data.udp.connectService = strndup(svc1, host2-svc1);
|
2010-12-16 15:07:07 +00:00
|
|
|
else
|
2011-06-17 14:31:02 +00:00
|
|
|
source->data.udp.connectService = strdup(svc1);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-06-17 14:31:02 +00:00
|
|
|
if (!source->data.udp.connectService)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (host2) {
|
|
|
|
host2++;
|
2011-08-11 07:19:51 +00:00
|
|
|
if (svc2 && (svc2 != host2)) {
|
2011-06-17 14:31:02 +00:00
|
|
|
source->data.udp.bindHost = strndup(host2, svc2-host2);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-08-11 07:19:51 +00:00
|
|
|
if (!source->data.udp.bindHost)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2011-08-11 07:19:51 +00:00
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (svc2) {
|
|
|
|
svc2++;
|
2011-08-11 07:19:51 +00:00
|
|
|
if (STRNEQ(svc2, "0")) {
|
|
|
|
source->data.udp.bindService = strdup(svc2);
|
|
|
|
if (!source->data.udp.bindService)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
} else if (STRPREFIX(val, "tcp:") ||
|
|
|
|
STRPREFIX(val, "telnet:")) {
|
|
|
|
const char *opt, *svc;
|
2011-06-17 14:31:02 +00:00
|
|
|
source->type = VIR_DOMAIN_CHR_TYPE_TCP;
|
2010-12-16 15:07:07 +00:00
|
|
|
if (STRPREFIX(val, "tcp:")) {
|
|
|
|
val += strlen("tcp:");
|
|
|
|
} else {
|
|
|
|
val += strlen("telnet:");
|
2011-06-17 14:31:02 +00:00
|
|
|
source->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
svc = strchr(val, ':');
|
|
|
|
if (!svc) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot find port number in character device %s"), val);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
opt = strchr(svc, ',');
|
|
|
|
if (opt && strstr(opt, "server"))
|
2011-06-17 14:31:02 +00:00
|
|
|
source->data.tcp.listen = true;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-06-17 14:31:02 +00:00
|
|
|
source->data.tcp.host = strndup(val, svc-val);
|
|
|
|
if (!source->data.tcp.host)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
svc++;
|
|
|
|
if (opt) {
|
2011-06-17 14:31:02 +00:00
|
|
|
source->data.tcp.service = strndup(svc, opt-svc);
|
2010-12-16 15:07:07 +00:00
|
|
|
} else {
|
2011-06-17 14:31:02 +00:00
|
|
|
source->data.tcp.service = strdup(svc);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2011-06-17 14:31:02 +00:00
|
|
|
if (!source->data.tcp.service)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
} else if (STRPREFIX(val, "unix:")) {
|
|
|
|
const char *opt;
|
|
|
|
val += strlen("unix:");
|
|
|
|
opt = strchr(val, ',');
|
2011-06-17 14:31:02 +00:00
|
|
|
source->type = VIR_DOMAIN_CHR_TYPE_UNIX;
|
2010-12-16 15:07:07 +00:00
|
|
|
if (opt) {
|
|
|
|
if (strstr(opt, "listen"))
|
2011-06-17 14:31:02 +00:00
|
|
|
source->data.nix.listen = true;
|
|
|
|
source->data.nix.path = strndup(val, opt-val);
|
2010-12-16 15:07:07 +00:00
|
|
|
} else {
|
2011-06-17 14:31:02 +00:00
|
|
|
source->data.nix.path = strdup(val);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2011-06-17 14:31:02 +00:00
|
|
|
if (!source->data.nix.path)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
} else if (STRPREFIX(val, "/dev")) {
|
2011-06-17 14:31:02 +00:00
|
|
|
source->type = VIR_DOMAIN_CHR_TYPE_DEV;
|
|
|
|
source->data.file.path = strdup(val);
|
|
|
|
if (!source->data.file.path)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
} else {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown character device syntax %s"), val);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2011-06-17 14:31:02 +00:00
|
|
|
return 0;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
error:
|
2011-06-17 14:31:02 +00:00
|
|
|
return -1;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static virCPUDefPtr
|
|
|
|
qemuInitGuestCPU(virDomainDefPtr dom)
|
|
|
|
{
|
|
|
|
if (!dom->cpu) {
|
|
|
|
virCPUDefPtr cpu;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(cpu) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cpu->type = VIR_CPU_TYPE_GUEST;
|
|
|
|
cpu->match = VIR_CPU_MATCH_EXACT;
|
|
|
|
dom->cpu = cpu;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dom->cpu;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuParseCommandLineCPU(virDomainDefPtr dom,
|
|
|
|
const char *val)
|
|
|
|
{
|
2012-01-27 13:49:50 +00:00
|
|
|
virCPUDefPtr cpu = NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
const char *p = val;
|
|
|
|
const char *next;
|
2012-01-27 13:49:50 +00:00
|
|
|
char *model = NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
if (*p == '\0' || *p == ',')
|
|
|
|
goto syntax;
|
|
|
|
|
|
|
|
if ((next = strchr(p, ',')))
|
|
|
|
next++;
|
|
|
|
|
2012-01-27 13:49:50 +00:00
|
|
|
if (p == val) {
|
2010-12-16 15:07:07 +00:00
|
|
|
if (next)
|
2012-01-27 13:49:50 +00:00
|
|
|
model = strndup(p, next - p - 1);
|
2010-12-16 15:07:07 +00:00
|
|
|
else
|
2012-01-27 13:49:50 +00:00
|
|
|
model = strdup(p);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2012-01-27 13:49:50 +00:00
|
|
|
if (!model)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto no_memory;
|
2012-01-27 13:49:50 +00:00
|
|
|
|
|
|
|
if (!STREQ(model, "qemu32") && !STREQ(model, "qemu64")) {
|
|
|
|
if (!(cpu = qemuInitGuestCPU(dom)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
cpu->model = model;
|
|
|
|
model = NULL;
|
|
|
|
}
|
2012-10-17 12:55:18 +00:00
|
|
|
} else if (*p == '+' || *p == '-') {
|
2010-12-16 15:07:07 +00:00
|
|
|
char *feature;
|
|
|
|
int policy;
|
2012-09-14 12:50:51 +00:00
|
|
|
int ret = 0;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (*p == '+')
|
|
|
|
policy = VIR_CPU_FEATURE_REQUIRE;
|
|
|
|
else
|
|
|
|
policy = VIR_CPU_FEATURE_DISABLE;
|
|
|
|
|
|
|
|
p++;
|
|
|
|
if (*p == '\0' || *p == ',')
|
|
|
|
goto syntax;
|
|
|
|
|
|
|
|
if (next)
|
|
|
|
feature = strndup(p, next - p - 1);
|
|
|
|
else
|
|
|
|
feature = strdup(p);
|
|
|
|
|
2011-07-08 15:13:54 +00:00
|
|
|
if (!feature)
|
|
|
|
goto no_memory;
|
|
|
|
|
2012-01-27 13:49:52 +00:00
|
|
|
if (STREQ(feature, "kvmclock")) {
|
|
|
|
bool present = (policy == VIR_CPU_FEATURE_REQUIRE);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < dom->clock.ntimers; i++) {
|
|
|
|
if (dom->clock.timers[i]->name == VIR_DOMAIN_TIMER_NAME_KVMCLOCK) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == dom->clock.ntimers) {
|
|
|
|
if (VIR_REALLOC_N(dom->clock.timers, i+1) < 0 ||
|
|
|
|
VIR_ALLOC(dom->clock.timers[i]) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
dom->clock.timers[i]->name = VIR_DOMAIN_TIMER_NAME_KVMCLOCK;
|
|
|
|
dom->clock.timers[i]->present = -1;
|
|
|
|
dom->clock.timers[i]->tickpolicy = -1;
|
|
|
|
dom->clock.timers[i]->track = -1;
|
|
|
|
dom->clock.ntimers++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dom->clock.timers[i]->present != -1 &&
|
|
|
|
dom->clock.timers[i]->present != present) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("conflicting occurrences of kvmclock feature"));
|
2012-01-27 13:49:50 +00:00
|
|
|
goto error;
|
2012-01-27 13:49:52 +00:00
|
|
|
}
|
|
|
|
dom->clock.timers[i]->present = present;
|
2012-09-13 13:27:07 +00:00
|
|
|
} else if (STREQ(feature, "kvm_pv_eoi")) {
|
|
|
|
if (policy == VIR_CPU_FEATURE_REQUIRE)
|
2012-10-16 14:28:22 +00:00
|
|
|
dom->apic_eoi = VIR_DOMAIN_FEATURE_STATE_ON;
|
2012-09-13 13:27:07 +00:00
|
|
|
else
|
2012-10-16 14:28:22 +00:00
|
|
|
dom->apic_eoi = VIR_DOMAIN_FEATURE_STATE_OFF;
|
2012-01-27 13:49:52 +00:00
|
|
|
} else {
|
|
|
|
if (!cpu) {
|
|
|
|
if (!(cpu = qemuInitGuestCPU(dom)))
|
|
|
|
goto error;
|
2012-01-27 13:49:50 +00:00
|
|
|
|
2012-01-27 13:49:52 +00:00
|
|
|
cpu->model = model;
|
|
|
|
model = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = virCPUDefAddFeature(cpu, feature, policy);
|
2012-01-27 13:49:50 +00:00
|
|
|
}
|
2012-01-27 13:49:52 +00:00
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
VIR_FREE(feature);
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
2012-10-17 12:55:18 +00:00
|
|
|
} else if (STRPREFIX(p, "hv_")) {
|
|
|
|
char *feature;
|
|
|
|
int f;
|
|
|
|
p += 3; /* "hv_" */
|
|
|
|
|
|
|
|
if (*p == '\0' || *p == ',')
|
|
|
|
goto syntax;
|
|
|
|
|
|
|
|
if (next)
|
|
|
|
feature = strndup(p, next - p - 1);
|
|
|
|
else
|
|
|
|
feature = strdup(p);
|
|
|
|
|
|
|
|
if (!feature)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
dom->features |= (1 << VIR_DOMAIN_FEATURE_HYPERV);
|
|
|
|
|
|
|
|
if ((f = virDomainHypervTypeFromString(feature)) < 0) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported HyperV Enlightenment feature "
|
|
|
|
"'%s'"), feature);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ((enum virDomainHyperv) f) {
|
|
|
|
case VIR_DOMAIN_HYPERV_RELAXED:
|
|
|
|
dom->hyperv_features[f] = VIR_DOMAIN_FEATURE_STATE_ON;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_HYPERV_LAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(feature);
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
} while ((p = next));
|
|
|
|
|
2012-01-27 13:49:49 +00:00
|
|
|
if (STREQ(dom->os.arch, "x86_64")) {
|
|
|
|
bool is_32bit = false;
|
2012-01-27 13:49:50 +00:00
|
|
|
if (cpu) {
|
|
|
|
union cpuData *cpuData = NULL;
|
|
|
|
int ret;
|
2012-01-27 13:49:49 +00:00
|
|
|
|
2012-01-27 13:49:50 +00:00
|
|
|
ret = cpuEncode("x86_64", cpu, NULL, &cpuData,
|
|
|
|
NULL, NULL, NULL, NULL);
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
2012-01-27 13:49:49 +00:00
|
|
|
|
2012-01-27 13:49:50 +00:00
|
|
|
is_32bit = (cpuHasFeature("x86_64", cpuData, "lm") != 1);
|
|
|
|
cpuDataFree("x86_64", cpuData);
|
|
|
|
} else if (model) {
|
|
|
|
is_32bit = STREQ(model, "qemu32");
|
|
|
|
}
|
2012-01-27 13:49:49 +00:00
|
|
|
|
|
|
|
if (is_32bit) {
|
|
|
|
VIR_FREE(dom->os.arch);
|
|
|
|
dom->os.arch = strdup("i686");
|
|
|
|
}
|
|
|
|
}
|
2012-01-27 13:49:50 +00:00
|
|
|
VIR_FREE(model);
|
2010-12-16 15:07:07 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
syntax:
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown CPU syntax '%s'"), val);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
error:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuParseCommandLineSmp(virDomainDefPtr dom,
|
|
|
|
const char *val)
|
|
|
|
{
|
|
|
|
unsigned int sockets = 0;
|
|
|
|
unsigned int cores = 0;
|
|
|
|
unsigned int threads = 0;
|
|
|
|
unsigned int maxcpus = 0;
|
|
|
|
int i;
|
|
|
|
int nkws;
|
|
|
|
char **kws;
|
|
|
|
char **vals;
|
|
|
|
int n;
|
|
|
|
char *end;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
nkws = qemuParseKeywords(val, &kws, &vals, 1);
|
|
|
|
if (nkws < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (i = 0; i < nkws; i++) {
|
|
|
|
if (vals[i] == NULL) {
|
|
|
|
if (i > 0 ||
|
|
|
|
virStrToLong_i(kws[i], &end, 10, &n) < 0 || *end != '\0')
|
|
|
|
goto syntax;
|
|
|
|
dom->vcpus = n;
|
|
|
|
} else {
|
|
|
|
if (virStrToLong_i(vals[i], &end, 10, &n) < 0 || *end != '\0')
|
|
|
|
goto syntax;
|
|
|
|
if (STREQ(kws[i], "sockets"))
|
|
|
|
sockets = n;
|
|
|
|
else if (STREQ(kws[i], "cores"))
|
|
|
|
cores = n;
|
|
|
|
else if (STREQ(kws[i], "threads"))
|
|
|
|
threads = n;
|
|
|
|
else if (STREQ(kws[i], "maxcpus"))
|
|
|
|
maxcpus = n;
|
|
|
|
else
|
|
|
|
goto syntax;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dom->maxvcpus = maxcpus ? maxcpus : dom->vcpus;
|
|
|
|
|
|
|
|
if (sockets && cores && threads) {
|
|
|
|
virCPUDefPtr cpu;
|
|
|
|
|
|
|
|
if (!(cpu = qemuInitGuestCPU(dom)))
|
|
|
|
goto error;
|
|
|
|
cpu->sockets = sockets;
|
|
|
|
cpu->cores = cores;
|
|
|
|
cpu->threads = threads;
|
|
|
|
} else if (sockets || cores || threads)
|
|
|
|
goto syntax;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
for (i = 0; i < nkws; i++) {
|
|
|
|
VIR_FREE(kws[i]);
|
|
|
|
VIR_FREE(vals[i]);
|
|
|
|
}
|
|
|
|
VIR_FREE(kws);
|
|
|
|
VIR_FREE(vals);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
syntax:
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse CPU topology '%s'"), val);
|
2010-12-16 15:07:07 +00:00
|
|
|
error:
|
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-18 09:38:18 +00:00
|
|
|
static void
|
|
|
|
qemuParseCommandLineBootDevs(virDomainDefPtr def, const char *str) {
|
|
|
|
int n, b = 0;
|
|
|
|
|
|
|
|
for (n = 0 ; str[n] && b < VIR_DOMAIN_BOOT_LAST ; n++) {
|
|
|
|
if (str[n] == 'a')
|
|
|
|
def->os.bootDevs[b++] = VIR_DOMAIN_BOOT_FLOPPY;
|
|
|
|
else if (str[n] == 'c')
|
|
|
|
def->os.bootDevs[b++] = VIR_DOMAIN_BOOT_DISK;
|
|
|
|
else if (str[n] == 'd')
|
|
|
|
def->os.bootDevs[b++] = VIR_DOMAIN_BOOT_CDROM;
|
|
|
|
else if (str[n] == 'n')
|
|
|
|
def->os.bootDevs[b++] = VIR_DOMAIN_BOOT_NET;
|
|
|
|
else if (str[n] == ',')
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
def->os.nBootDevs = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
/*
|
|
|
|
* Analyse the env and argv settings and reconstruct a
|
|
|
|
* virDomainDefPtr representing these settings as closely
|
|
|
|
* as is practical. This is not an exact science....
|
|
|
|
*/
|
|
|
|
virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
|
|
|
|
const char **progenv,
|
2011-06-17 14:31:02 +00:00
|
|
|
const char **progargv,
|
|
|
|
char **pidfile,
|
|
|
|
virDomainChrSourceDefPtr *monConfig,
|
|
|
|
bool *monJSON)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
virDomainDefPtr def;
|
|
|
|
int i;
|
|
|
|
int nographics = 0;
|
|
|
|
int fullscreen = 0;
|
|
|
|
char *path;
|
|
|
|
int nnics = 0;
|
|
|
|
const char **nics = NULL;
|
|
|
|
int video = VIR_DOMAIN_VIDEO_TYPE_CIRRUS;
|
|
|
|
int nvirtiodisk = 0;
|
2011-07-04 06:00:28 +00:00
|
|
|
qemuDomainCmdlineDefPtr cmd = NULL;
|
2011-08-02 20:07:25 +00:00
|
|
|
virDomainDiskDefPtr disk = NULL;
|
2011-11-01 01:29:07 +00:00
|
|
|
const char *ceph_args = qemuFindEnv(progenv, "CEPH_ARGS");
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-06-17 14:31:02 +00:00
|
|
|
if (pidfile)
|
|
|
|
*pidfile = NULL;
|
|
|
|
if (monConfig)
|
|
|
|
*monConfig = NULL;
|
|
|
|
if (monJSON)
|
|
|
|
*monJSON = false;
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (!progargv[0]) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("no emulator path found"));
|
2010-12-16 15:07:07 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
/* allocate the cmdlinedef up-front; if it's unused, we'll free it later */
|
|
|
|
if (VIR_ALLOC(cmd) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
2011-07-04 02:23:46 +00:00
|
|
|
if (virUUIDGenerate(def->uuid) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("failed to generate uuid"));
|
2011-07-04 02:23:46 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
def->id = -1;
|
|
|
|
def->mem.cur_balloon = def->mem.max_balloon = 64 * 1024;
|
|
|
|
def->maxvcpus = 1;
|
|
|
|
def->vcpus = 1;
|
|
|
|
def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
|
2011-11-21 12:50:42 +00:00
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART;
|
|
|
|
def->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY;
|
|
|
|
def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY;
|
|
|
|
def->virtType = VIR_DOMAIN_VIRT_QEMU;
|
|
|
|
if (!(def->emulator = strdup(progargv[0])))
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (strstr(def->emulator, "kvm")) {
|
|
|
|
def->virtType = VIR_DOMAIN_VIRT_KVM;
|
|
|
|
def->features |= (1 << VIR_DOMAIN_FEATURE_PAE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (strstr(def->emulator, "xenner")) {
|
|
|
|
def->virtType = VIR_DOMAIN_VIRT_KVM;
|
|
|
|
def->os.type = strdup("xen");
|
|
|
|
} else {
|
|
|
|
def->os.type = strdup("hvm");
|
|
|
|
}
|
|
|
|
if (!def->os.type)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (STRPREFIX(def->emulator, "qemu"))
|
|
|
|
path = def->emulator;
|
|
|
|
else
|
|
|
|
path = strstr(def->emulator, "qemu");
|
2012-01-27 13:49:48 +00:00
|
|
|
if (def->virtType == VIR_DOMAIN_VIRT_KVM)
|
|
|
|
def->os.arch = strdup(caps->host.cpu->arch);
|
|
|
|
else if (path &&
|
|
|
|
STRPREFIX(path, "qemu-system-"))
|
2010-12-16 15:07:07 +00:00
|
|
|
def->os.arch = strdup(path + strlen("qemu-system-"));
|
|
|
|
else
|
|
|
|
def->os.arch = strdup("i686");
|
|
|
|
if (!def->os.arch)
|
|
|
|
goto no_memory;
|
|
|
|
|
2011-11-21 12:50:42 +00:00
|
|
|
if (STREQ(def->os.arch, "i686")||STREQ(def->os.arch, "x86_64"))
|
2012-07-10 10:02:10 +00:00
|
|
|
def->features |= (1 << VIR_DOMAIN_FEATURE_ACPI)
|
2011-11-21 12:50:42 +00:00
|
|
|
/*| (1 << VIR_DOMAIN_FEATURE_APIC)*/;
|
2010-12-16 15:07:07 +00:00
|
|
|
#define WANT_VALUE() \
|
|
|
|
const char *val = progargv[++i]; \
|
|
|
|
if (!val) { \
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, \
|
|
|
|
_("missing value for %s argument"), arg); \
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error; \
|
|
|
|
}
|
|
|
|
|
|
|
|
/* One initial loop to get list of NICs, so we
|
|
|
|
* can correlate them later */
|
|
|
|
for (i = 1 ; progargv[i] ; i++) {
|
|
|
|
const char *arg = progargv[i];
|
|
|
|
/* Make sure we have a single - for all options to
|
|
|
|
simplify next logic */
|
|
|
|
if (STRPREFIX(arg, "--"))
|
|
|
|
arg++;
|
|
|
|
|
|
|
|
if (STREQ(arg, "-net")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (STRPREFIX(val, "nic")) {
|
|
|
|
if (VIR_REALLOC_N(nics, nnics+1) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
nics[nnics++] = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now the real processing loop */
|
|
|
|
for (i = 1 ; progargv[i] ; i++) {
|
|
|
|
const char *arg = progargv[i];
|
|
|
|
/* Make sure we have a single - for all options to
|
|
|
|
simplify next logic */
|
|
|
|
if (STRPREFIX(arg, "--"))
|
|
|
|
arg++;
|
|
|
|
|
|
|
|
if (STREQ(arg, "-vnc")) {
|
|
|
|
virDomainGraphicsDefPtr vnc;
|
|
|
|
char *tmp;
|
|
|
|
WANT_VALUE();
|
|
|
|
if (VIR_ALLOC(vnc) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
vnc->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
|
|
|
|
|
2011-01-07 21:03:07 +00:00
|
|
|
if (STRPREFIX(val, "unix:")) {
|
2011-05-19 10:39:35 +00:00
|
|
|
/* -vnc unix:/some/big/path */
|
2011-01-07 21:03:07 +00:00
|
|
|
vnc->data.vnc.socket = strdup(val + 5);
|
|
|
|
if (!vnc->data.vnc.socket) {
|
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
|
|
|
virDomainGraphicsDefFree(vnc);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
} else {
|
2011-05-19 10:39:35 +00:00
|
|
|
/*
|
|
|
|
* -vnc 127.0.0.1:4
|
|
|
|
* -vnc [2001:1:2:3:4:5:1234:1234]:4
|
|
|
|
* -vnc some.host.name:4
|
|
|
|
*/
|
|
|
|
char *opts;
|
|
|
|
const char *sep = ":";
|
|
|
|
if (val[0] == '[')
|
|
|
|
sep = "]:";
|
|
|
|
tmp = strstr(val, sep);
|
|
|
|
if (!tmp) {
|
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
|
|
|
virDomainGraphicsDefFree(vnc);
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("missing VNC port number in '%s'"), val);
|
2011-05-19 10:39:35 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (virStrToLong_i(tmp+strlen(sep), &opts, 10,
|
|
|
|
&vnc->data.vnc.port) < 0) {
|
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
|
|
|
virDomainGraphicsDefFree(vnc);
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse VNC port '%s'"), tmp+1);
|
2011-05-19 10:39:35 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (val[0] == '[')
|
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
|
|
|
virDomainGraphicsListenSetAddress(vnc, 0,
|
|
|
|
val+1, tmp-(val+1), true);
|
2011-05-19 10:39:35 +00:00
|
|
|
else
|
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
|
|
|
virDomainGraphicsListenSetAddress(vnc, 0,
|
|
|
|
val, tmp-val, true);
|
|
|
|
if (!virDomainGraphicsListenGetAddress(vnc, 0)) {
|
|
|
|
virDomainGraphicsDefFree(vnc);
|
2011-05-19 10:39:35 +00:00
|
|
|
goto no_memory;
|
2011-01-07 21:03:07 +00:00
|
|
|
}
|
2011-05-19 10:39:35 +00:00
|
|
|
vnc->data.vnc.port += 5900;
|
|
|
|
vnc->data.vnc.autoport = 0;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(def->graphics, def->ngraphics+1) < 0) {
|
|
|
|
virDomainGraphicsDefFree(vnc);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
def->graphics[def->ngraphics++] = vnc;
|
|
|
|
} else if (STREQ(arg, "-m")) {
|
|
|
|
int mem;
|
|
|
|
WANT_VALUE();
|
|
|
|
if (virStrToLong_i(val, NULL, 10, &mem) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, \
|
|
|
|
_("cannot parse memory level '%s'"), val);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
def->mem.cur_balloon = def->mem.max_balloon = mem * 1024;
|
|
|
|
} else if (STREQ(arg, "-smp")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (qemuParseCommandLineSmp(def, val) < 0)
|
|
|
|
goto error;
|
|
|
|
} else if (STREQ(arg, "-uuid")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (virUUIDParse(val, def->uuid) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, \
|
|
|
|
_("cannot parse UUID '%s'"), val);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else if (STRPREFIX(arg, "-hd") ||
|
|
|
|
STRPREFIX(arg, "-sd") ||
|
|
|
|
STRPREFIX(arg, "-fd") ||
|
|
|
|
STREQ(arg, "-cdrom")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (VIR_ALLOC(disk) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (STRPREFIX(val, "/dev/"))
|
|
|
|
disk->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
|
|
|
|
else if (STRPREFIX(val, "nbd:")) {
|
|
|
|
disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
|
|
|
|
disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_NBD;
|
|
|
|
val += strlen("nbd:");
|
|
|
|
} else if (STRPREFIX(val, "rbd:")) {
|
|
|
|
disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
|
|
|
|
disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_RBD;
|
|
|
|
val += strlen("rbd:");
|
2012-11-22 18:10:39 +00:00
|
|
|
} else if (STRPREFIX(val, "gluster")) {
|
|
|
|
disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
|
|
|
|
disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_GLUSTER;
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (STRPREFIX(val, "sheepdog:")) {
|
|
|
|
disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
|
|
|
|
disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG;
|
|
|
|
val += strlen("sheepdog:");
|
|
|
|
} else
|
|
|
|
disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
|
|
|
|
if (STREQ(arg, "-cdrom")) {
|
|
|
|
disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
|
|
|
|
disk->dst = strdup("hdc");
|
2011-07-08 15:13:54 +00:00
|
|
|
if (!disk->dst)
|
|
|
|
goto no_memory;
|
2010-12-16 15:07:07 +00:00
|
|
|
disk->readonly = 1;
|
|
|
|
} else {
|
|
|
|
if (STRPREFIX(arg, "-fd")) {
|
|
|
|
disk->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
|
|
|
|
disk->bus = VIR_DOMAIN_DISK_BUS_FDC;
|
|
|
|
} else {
|
|
|
|
disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
|
|
|
|
if (STRPREFIX(arg, "-hd"))
|
|
|
|
disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
|
|
|
|
else
|
|
|
|
disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
|
|
|
|
}
|
|
|
|
disk->dst = strdup(arg + 1);
|
2011-07-08 15:13:54 +00:00
|
|
|
if (!disk->dst)
|
|
|
|
goto no_memory;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
disk->src = strdup(val);
|
2011-07-08 15:13:54 +00:00
|
|
|
if (!disk->src)
|
|
|
|
goto no_memory;
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) {
|
|
|
|
char *host, *port;
|
|
|
|
|
|
|
|
switch (disk->protocol) {
|
|
|
|
case VIR_DOMAIN_DISK_PROTOCOL_NBD:
|
|
|
|
host = disk->src;
|
|
|
|
port = strchr(host, ':');
|
|
|
|
if (!port) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse nbd filename '%s'"), disk->src);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
*port++ = '\0';
|
2011-07-08 15:13:54 +00:00
|
|
|
if (VIR_ALLOC(disk->hosts) < 0)
|
|
|
|
goto no_memory;
|
2010-12-16 15:07:07 +00:00
|
|
|
disk->nhosts = 1;
|
|
|
|
disk->hosts->name = host;
|
|
|
|
disk->hosts->port = strdup(port);
|
2011-07-08 15:13:54 +00:00
|
|
|
if (!disk->hosts->port)
|
|
|
|
goto no_memory;
|
|
|
|
VIR_FREE(disk->src);
|
2010-12-16 15:07:07 +00:00
|
|
|
disk->src = NULL;
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_PROTOCOL_RBD:
|
2011-11-01 01:29:07 +00:00
|
|
|
/* old-style CEPH_ARGS env variable is parsed later */
|
|
|
|
if (!ceph_args && qemuParseRBDString(disk) < 0)
|
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
|
|
|
|
/* disk->src must be [vdiname] or [host]:[port]:[vdiname] */
|
|
|
|
port = strchr(disk->src, ':');
|
|
|
|
if (port) {
|
|
|
|
char *vdi;
|
|
|
|
|
|
|
|
*port++ = '\0';
|
|
|
|
vdi = strchr(port, ':');
|
|
|
|
if (!vdi) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse sheepdog filename '%s'"), val);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
*vdi++ = '\0';
|
2011-07-08 15:13:54 +00:00
|
|
|
if (VIR_ALLOC(disk->hosts) < 0)
|
|
|
|
goto no_memory;
|
2010-12-16 15:07:07 +00:00
|
|
|
disk->nhosts = 1;
|
|
|
|
disk->hosts->name = disk->src;
|
|
|
|
disk->hosts->port = strdup(port);
|
2011-07-08 15:13:54 +00:00
|
|
|
if (!disk->hosts->port)
|
|
|
|
goto no_memory;
|
2010-12-16 15:07:07 +00:00
|
|
|
disk->src = strdup(vdi);
|
2011-07-08 15:13:54 +00:00
|
|
|
if (!disk->src)
|
|
|
|
goto no_memory;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
break;
|
2012-11-22 18:10:39 +00:00
|
|
|
case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER:
|
|
|
|
if (qemuParseGlusterString(disk) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
break;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(disk->src || disk->nhosts > 0) ||
|
2011-08-02 20:07:25 +00:00
|
|
|
!disk->dst)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2012-11-20 13:45:56 +00:00
|
|
|
if (virDomainDiskDefAssignAddress(caps, disk) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Cannot assign address for device name '%s'"),
|
|
|
|
disk->dst);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
2012-11-20 13:45:56 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-08-02 20:07:25 +00:00
|
|
|
if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
def->disks[def->ndisks++] = disk;
|
2011-08-02 20:07:25 +00:00
|
|
|
disk = NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (STREQ(arg, "-no-acpi")) {
|
|
|
|
def->features &= ~(1 << VIR_DOMAIN_FEATURE_ACPI);
|
|
|
|
} else if (STREQ(arg, "-no-reboot")) {
|
|
|
|
def->onReboot = VIR_DOMAIN_LIFECYCLE_DESTROY;
|
|
|
|
} else if (STREQ(arg, "-no-kvm")) {
|
|
|
|
def->virtType = VIR_DOMAIN_VIRT_QEMU;
|
2012-01-27 13:49:46 +00:00
|
|
|
} else if (STREQ(arg, "-enable-kvm")) {
|
|
|
|
def->virtType = VIR_DOMAIN_VIRT_KVM;
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (STREQ(arg, "-nographic")) {
|
|
|
|
nographics = 1;
|
|
|
|
} else if (STREQ(arg, "-full-screen")) {
|
|
|
|
fullscreen = 1;
|
|
|
|
} else if (STREQ(arg, "-localtime")) {
|
|
|
|
def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
|
|
|
|
} else if (STREQ(arg, "-kernel")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (!(def->os.kernel = strdup(val)))
|
|
|
|
goto no_memory;
|
2012-04-10 14:02:13 +00:00
|
|
|
} else if (STREQ(arg, "-bios")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (!(def->os.loader = strdup(val)))
|
|
|
|
goto no_memory;
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (STREQ(arg, "-initrd")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (!(def->os.initrd = strdup(val)))
|
|
|
|
goto no_memory;
|
|
|
|
} else if (STREQ(arg, "-append")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (!(def->os.cmdline = strdup(val)))
|
|
|
|
goto no_memory;
|
|
|
|
} else if (STREQ(arg, "-boot")) {
|
2012-09-18 09:38:18 +00:00
|
|
|
const char *token = NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
WANT_VALUE();
|
|
|
|
|
2012-09-18 09:38:18 +00:00
|
|
|
if (!strchr(val, ','))
|
|
|
|
qemuParseCommandLineBootDevs(def, val);
|
|
|
|
else {
|
|
|
|
token = val;
|
|
|
|
while (token && *token) {
|
|
|
|
if (STRPREFIX(token, "order=")) {
|
|
|
|
token += strlen("order=");
|
|
|
|
qemuParseCommandLineBootDevs(def, token);
|
|
|
|
} else if (STRPREFIX(token, "menu=on")) {
|
|
|
|
def->os.bootmenu = 1;
|
2012-09-18 10:31:30 +00:00
|
|
|
} else if (STRPREFIX(token, "reboot-timeout=")) {
|
|
|
|
int num;
|
|
|
|
char *endptr;
|
|
|
|
if (virStrToLong_i(token + strlen("reboot-timeout="),
|
|
|
|
&endptr, 10, &num) < 0 ||
|
|
|
|
(*endptr != '\0' && endptr != strchr(token, ','))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot parse reboot-timeout value"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (num > 65535)
|
|
|
|
num = 65535;
|
|
|
|
else if (num < -1)
|
|
|
|
num = -1;
|
|
|
|
def->os.bios.rt_delay = num;
|
|
|
|
def->os.bios.rt_set = true;
|
2012-09-18 09:38:18 +00:00
|
|
|
}
|
|
|
|
token = strchr(token, ',');
|
|
|
|
/* This incrementation has to be done here in order to make it
|
|
|
|
* possible to pass the token pointer properly into the loop */
|
|
|
|
if (token)
|
|
|
|
token++;
|
|
|
|
}
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (STREQ(arg, "-name")) {
|
|
|
|
char *process;
|
|
|
|
WANT_VALUE();
|
|
|
|
process = strstr(val, ",process=");
|
|
|
|
if (process == NULL) {
|
|
|
|
if (!(def->name = strdup(val)))
|
|
|
|
goto no_memory;
|
|
|
|
} else {
|
|
|
|
if (!(def->name = strndup(val, process - val)))
|
|
|
|
goto no_memory;
|
|
|
|
}
|
2011-05-05 16:32:21 +00:00
|
|
|
if (STREQ(def->name, ""))
|
|
|
|
VIR_FREE(def->name);
|
2012-08-15 07:59:24 +00:00
|
|
|
} else if (STREQ(arg, "-M") ||
|
|
|
|
STREQ(arg, "-machine")) {
|
|
|
|
char *params;
|
2010-12-16 15:07:07 +00:00
|
|
|
WANT_VALUE();
|
2012-08-15 07:59:24 +00:00
|
|
|
params = strchr(val, ',');
|
|
|
|
if (params == NULL) {
|
|
|
|
if (!(def->os.machine = strdup(val)))
|
|
|
|
goto no_memory;
|
|
|
|
} else {
|
|
|
|
if (!(def->os.machine = strndup(val, params - val)))
|
|
|
|
goto no_memory;
|
|
|
|
|
2012-10-17 09:23:12 +00:00
|
|
|
while (params++) {
|
2012-08-15 07:59:24 +00:00
|
|
|
/* prepared for more "-machine" parameters */
|
|
|
|
char *tmp = params;
|
|
|
|
params = strchr(params, ',');
|
|
|
|
|
|
|
|
if (STRPREFIX(tmp, "dump-guest-core=")) {
|
|
|
|
tmp += strlen("dump-guest-core=");
|
|
|
|
if (params) {
|
|
|
|
tmp = strndup(tmp, params - tmp);
|
|
|
|
if (tmp == NULL)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
def->mem.dump_core = virDomainMemDumpTypeFromString(tmp);
|
|
|
|
if (def->mem.dump_core <= 0)
|
|
|
|
def->mem.dump_core = VIR_DOMAIN_MEM_DUMP_DEFAULT;
|
|
|
|
if (params)
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (STREQ(arg, "-serial")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (STRNEQ(val, "none")) {
|
|
|
|
virDomainChrDefPtr chr;
|
2011-06-17 14:31:02 +00:00
|
|
|
|
|
|
|
if (!(chr = virDomainChrDefNew()))
|
|
|
|
goto error;
|
|
|
|
|
2011-08-02 20:07:25 +00:00
|
|
|
if (qemuParseCommandLineChr(&chr->source, val) < 0) {
|
|
|
|
virDomainChrDefFree(chr);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
2011-08-02 20:07:25 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0) {
|
|
|
|
virDomainChrDefFree(chr);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
|
|
|
|
chr->target.port = def->nserials;
|
|
|
|
def->serials[def->nserials++] = chr;
|
|
|
|
}
|
|
|
|
} else if (STREQ(arg, "-parallel")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (STRNEQ(val, "none")) {
|
|
|
|
virDomainChrDefPtr chr;
|
2011-06-17 14:31:02 +00:00
|
|
|
|
|
|
|
if (!(chr = virDomainChrDefNew()))
|
|
|
|
goto error;
|
|
|
|
|
2011-08-02 20:07:25 +00:00
|
|
|
if (qemuParseCommandLineChr(&chr->source, val) < 0) {
|
|
|
|
virDomainChrDefFree(chr);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
2011-08-02 20:07:25 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
if (VIR_REALLOC_N(def->parallels, def->nparallels+1) < 0) {
|
|
|
|
virDomainChrDefFree(chr);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
|
|
|
|
chr->target.port = def->nparallels;
|
|
|
|
def->parallels[def->nparallels++] = chr;
|
|
|
|
}
|
|
|
|
} else if (STREQ(arg, "-usbdevice")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (STREQ(val, "tablet") ||
|
|
|
|
STREQ(val, "mouse")) {
|
|
|
|
virDomainInputDefPtr input;
|
|
|
|
if (VIR_ALLOC(input) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
input->bus = VIR_DOMAIN_INPUT_BUS_USB;
|
|
|
|
if (STREQ(val, "tablet"))
|
|
|
|
input->type = VIR_DOMAIN_INPUT_TYPE_TABLET;
|
|
|
|
else
|
|
|
|
input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
|
|
|
|
if (VIR_REALLOC_N(def->inputs, def->ninputs+1) < 0) {
|
|
|
|
virDomainInputDefFree(input);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
def->inputs[def->ninputs++] = input;
|
|
|
|
} else if (STRPREFIX(val, "disk:")) {
|
|
|
|
if (VIR_ALLOC(disk) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
disk->src = strdup(val + strlen("disk:"));
|
2011-08-02 20:07:25 +00:00
|
|
|
if (!disk->src)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
if (STRPREFIX(disk->src, "/dev/"))
|
|
|
|
disk->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
|
|
|
|
else
|
|
|
|
disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
|
|
|
|
disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
|
|
|
|
disk->bus = VIR_DOMAIN_DISK_BUS_USB;
|
2011-08-02 20:07:25 +00:00
|
|
|
if (!(disk->dst = strdup("sda")) ||
|
|
|
|
VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
def->disks[def->ndisks++] = disk;
|
2011-08-02 20:07:25 +00:00
|
|
|
disk = NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
} else {
|
|
|
|
virDomainHostdevDefPtr hostdev;
|
|
|
|
if (!(hostdev = qemuParseCommandLineUSB(val)))
|
|
|
|
goto error;
|
|
|
|
if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs+1) < 0) {
|
|
|
|
virDomainHostdevDefFree(hostdev);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
def->hostdevs[def->nhostdevs++] = hostdev;
|
|
|
|
}
|
|
|
|
} else if (STREQ(arg, "-net")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (!STRPREFIX(val, "nic") && STRNEQ(val, "none")) {
|
|
|
|
virDomainNetDefPtr net;
|
|
|
|
if (!(net = qemuParseCommandLineNet(caps, val, nnics, nics)))
|
|
|
|
goto error;
|
|
|
|
if (VIR_REALLOC_N(def->nets, def->nnets+1) < 0) {
|
|
|
|
virDomainNetDefFree(net);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
def->nets[def->nnets++] = net;
|
|
|
|
}
|
|
|
|
} else if (STREQ(arg, "-drive")) {
|
|
|
|
WANT_VALUE();
|
2011-11-01 01:29:07 +00:00
|
|
|
if (!(disk = qemuParseCommandLineDisk(caps, val, nvirtiodisk,
|
|
|
|
ceph_args != NULL)))
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
2011-08-02 20:07:25 +00:00
|
|
|
if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
|
2010-12-16 15:07:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
|
|
|
|
nvirtiodisk++;
|
2011-08-02 20:07:25 +00:00
|
|
|
|
|
|
|
def->disks[def->ndisks++] = disk;
|
|
|
|
disk = NULL;
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (STREQ(arg, "-pcidevice")) {
|
|
|
|
virDomainHostdevDefPtr hostdev;
|
|
|
|
WANT_VALUE();
|
|
|
|
if (!(hostdev = qemuParseCommandLinePCI(val)))
|
|
|
|
goto error;
|
|
|
|
if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs+1) < 0) {
|
|
|
|
virDomainHostdevDefFree(hostdev);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
def->hostdevs[def->nhostdevs++] = hostdev;
|
|
|
|
} else if (STREQ(arg, "-soundhw")) {
|
|
|
|
const char *start;
|
|
|
|
WANT_VALUE();
|
|
|
|
start = val;
|
|
|
|
while (start) {
|
|
|
|
const char *tmp = strchr(start, ',');
|
|
|
|
int type = -1;
|
|
|
|
if (STRPREFIX(start, "pcspk")) {
|
|
|
|
type = VIR_DOMAIN_SOUND_MODEL_PCSPK;
|
|
|
|
} else if (STRPREFIX(start, "sb16")) {
|
|
|
|
type = VIR_DOMAIN_SOUND_MODEL_SB16;
|
|
|
|
} else if (STRPREFIX(start, "es1370")) {
|
|
|
|
type = VIR_DOMAIN_SOUND_MODEL_ES1370;
|
|
|
|
} else if (STRPREFIX(start, "ac97")) {
|
|
|
|
type = VIR_DOMAIN_SOUND_MODEL_AC97;
|
2011-01-13 14:15:11 +00:00
|
|
|
} else if (STRPREFIX(start, "hda")) {
|
|
|
|
type = VIR_DOMAIN_SOUND_MODEL_ICH6;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (type != -1) {
|
|
|
|
virDomainSoundDefPtr snd;
|
|
|
|
if (VIR_ALLOC(snd) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
snd->model = type;
|
|
|
|
if (VIR_REALLOC_N(def->sounds, def->nsounds+1) < 0) {
|
|
|
|
VIR_FREE(snd);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
def->sounds[def->nsounds++] = snd;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = tmp ? tmp + 1 : NULL;
|
|
|
|
}
|
|
|
|
} else if (STREQ(arg, "-watchdog")) {
|
|
|
|
WANT_VALUE();
|
2012-10-17 09:23:12 +00:00
|
|
|
int model = virDomainWatchdogModelTypeFromString(val);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (model != -1) {
|
|
|
|
virDomainWatchdogDefPtr wd;
|
|
|
|
if (VIR_ALLOC(wd) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
wd->model = model;
|
|
|
|
wd->action = VIR_DOMAIN_WATCHDOG_ACTION_RESET;
|
|
|
|
def->watchdog = wd;
|
|
|
|
}
|
|
|
|
} else if (STREQ(arg, "-watchdog-action") && def->watchdog) {
|
|
|
|
WANT_VALUE();
|
2012-10-17 09:23:12 +00:00
|
|
|
int action = virDomainWatchdogActionTypeFromString(val);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
if (action != -1)
|
|
|
|
def->watchdog->action = action;
|
|
|
|
} else if (STREQ(arg, "-bootloader")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
def->os.bootloader = strdup(val);
|
|
|
|
if (!def->os.bootloader)
|
|
|
|
goto no_memory;
|
|
|
|
} else if (STREQ(arg, "-vmwarevga")) {
|
|
|
|
video = VIR_DOMAIN_VIDEO_TYPE_VMVGA;
|
|
|
|
} else if (STREQ(arg, "-std-vga")) {
|
|
|
|
video = VIR_DOMAIN_VIDEO_TYPE_VGA;
|
|
|
|
} else if (STREQ(arg, "-vga")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (STRNEQ(val, "none")) {
|
|
|
|
video = qemuVideoTypeFromString(val);
|
|
|
|
if (video < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown video adapter type '%s'"), val);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (STREQ(arg, "-cpu")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (qemuParseCommandLineCPU(def, val) < 0)
|
|
|
|
goto error;
|
|
|
|
} else if (STREQ(arg, "-domid")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
/* ignore, generted on the fly */
|
|
|
|
} else if (STREQ(arg, "-usb")) {
|
2012-02-08 00:48:25 +00:00
|
|
|
virDomainControllerDefPtr ctldef;
|
|
|
|
if (VIR_ALLOC(ctldef) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
ctldef->type = VIR_DOMAIN_CONTROLLER_TYPE_USB;
|
|
|
|
ctldef->idx = 0;
|
|
|
|
ctldef->model = -1;
|
|
|
|
virDomainControllerInsert(def, ctldef);
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (STREQ(arg, "-pidfile")) {
|
|
|
|
WANT_VALUE();
|
2011-06-17 14:31:02 +00:00
|
|
|
if (pidfile)
|
|
|
|
if (!(*pidfile = strdup(val)))
|
|
|
|
goto no_memory;
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (STREQ(arg, "-incoming")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
/* ignore, used via restore/migrate APIs */
|
|
|
|
} else if (STREQ(arg, "-monitor")) {
|
|
|
|
WANT_VALUE();
|
2011-06-17 14:31:02 +00:00
|
|
|
if (monConfig) {
|
|
|
|
virDomainChrSourceDefPtr chr;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(chr) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
2011-08-02 20:07:25 +00:00
|
|
|
if (qemuParseCommandLineChr(chr, val) < 0) {
|
|
|
|
virDomainChrSourceDefFree(chr);
|
2011-06-17 14:31:02 +00:00
|
|
|
goto error;
|
2011-08-02 20:07:25 +00:00
|
|
|
}
|
2011-06-17 14:31:02 +00:00
|
|
|
|
|
|
|
*monConfig = chr;
|
|
|
|
}
|
2012-08-02 10:14:39 +00:00
|
|
|
} else if (STREQ(arg, "-global") &&
|
|
|
|
STRPREFIX(progargv[i + 1], "PIIX4_PM.disable_s3=")) {
|
|
|
|
/* We want to parse only the known "-global" parameters,
|
|
|
|
* so the ones that we don't know are still added to the
|
|
|
|
* namespace */
|
|
|
|
WANT_VALUE();
|
|
|
|
|
|
|
|
val += strlen("PIIX4_PM.disable_s3=");
|
|
|
|
if (STREQ(val, "0"))
|
|
|
|
def->pm.s3 = VIR_DOMAIN_PM_STATE_ENABLED;
|
|
|
|
else if (STREQ(val, "1"))
|
|
|
|
def->pm.s3 = VIR_DOMAIN_PM_STATE_DISABLED;
|
|
|
|
else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("invalid value for disable_s3 parameter: "
|
|
|
|
"'%s'"), val);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (STREQ(arg, "-global") &&
|
|
|
|
STRPREFIX(progargv[i + 1], "PIIX4_PM.disable_s4=")) {
|
|
|
|
|
|
|
|
WANT_VALUE();
|
|
|
|
|
|
|
|
val += strlen("PIIX4_PM.disable_s4=");
|
|
|
|
if (STREQ(val, "0"))
|
|
|
|
def->pm.s4 = VIR_DOMAIN_PM_STATE_ENABLED;
|
|
|
|
else if (STREQ(val, "1"))
|
|
|
|
def->pm.s4 = VIR_DOMAIN_PM_STATE_DISABLED;
|
|
|
|
else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("invalid value for disable_s4 parameter: "
|
|
|
|
"'%s'"), val);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
} else if (STREQ(arg, "-S")) {
|
|
|
|
/* ignore, always added by libvirt */
|
|
|
|
} else {
|
|
|
|
/* something we can't yet parse. Add it to the qemu namespace
|
|
|
|
* cmdline/environment advanced options and hope for the best
|
|
|
|
*/
|
|
|
|
VIR_WARN("unknown QEMU argument '%s', adding to the qemu namespace",
|
|
|
|
arg);
|
|
|
|
if (VIR_REALLOC_N(cmd->args, cmd->num_args+1) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
cmd->args[cmd->num_args] = strdup(arg);
|
|
|
|
if (cmd->args[cmd->num_args] == NULL)
|
|
|
|
goto no_memory;
|
|
|
|
cmd->num_args++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef WANT_VALUE
|
2011-11-01 01:29:07 +00:00
|
|
|
if (def->ndisks > 0 && ceph_args) {
|
|
|
|
char *hosts, *port, *saveptr = NULL, *token;
|
|
|
|
virDomainDiskDefPtr first_rbd_disk = NULL;
|
|
|
|
for (i = 0 ; i < def->ndisks ; i++) {
|
|
|
|
if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
|
|
|
|
def->disks[i]->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD) {
|
|
|
|
first_rbd_disk = def->disks[i];
|
|
|
|
break;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2011-11-01 01:29:07 +00:00
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-11-01 01:29:07 +00:00
|
|
|
if (!first_rbd_disk) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("CEPH_ARGS was set without an rbd disk"));
|
2011-11-01 01:29:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2010-12-16 15:07:07 +00:00
|
|
|
|
2011-11-01 01:29:07 +00:00
|
|
|
/* CEPH_ARGS should be: -m host1[:port1][,host2[:port2]]... */
|
|
|
|
if (!STRPREFIX(ceph_args, "-m ")) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("could not parse CEPH_ARGS '%s'"), ceph_args);
|
2011-11-01 01:29:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
hosts = strdup(strchr(ceph_args, ' ') + 1);
|
|
|
|
if (!hosts)
|
|
|
|
goto no_memory;
|
|
|
|
first_rbd_disk->nhosts = 0;
|
|
|
|
token = strtok_r(hosts, ",", &saveptr);
|
|
|
|
while (token != NULL) {
|
|
|
|
if (VIR_REALLOC_N(first_rbd_disk->hosts, first_rbd_disk->nhosts + 1) < 0) {
|
|
|
|
VIR_FREE(hosts);
|
2010-12-16 15:07:07 +00:00
|
|
|
goto no_memory;
|
2011-11-01 01:29:07 +00:00
|
|
|
}
|
|
|
|
port = strchr(token, ':');
|
|
|
|
if (port) {
|
|
|
|
*port++ = '\0';
|
|
|
|
port = strdup(port);
|
|
|
|
if (!port) {
|
2010-12-16 15:07:07 +00:00
|
|
|
VIR_FREE(hosts);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
}
|
2011-11-01 01:29:07 +00:00
|
|
|
first_rbd_disk->hosts[first_rbd_disk->nhosts].port = port;
|
|
|
|
first_rbd_disk->hosts[first_rbd_disk->nhosts].name = strdup(token);
|
|
|
|
if (!first_rbd_disk->hosts[first_rbd_disk->nhosts].name) {
|
|
|
|
VIR_FREE(hosts);
|
|
|
|
goto no_memory;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
2012-11-22 18:10:38 +00:00
|
|
|
first_rbd_disk->hosts[first_rbd_disk->nhosts].transport = VIR_DOMAIN_DISK_PROTO_TRANS_TCP;
|
|
|
|
first_rbd_disk->hosts[first_rbd_disk->nhosts].socket = NULL;
|
|
|
|
|
2011-11-01 01:29:07 +00:00
|
|
|
first_rbd_disk->nhosts++;
|
|
|
|
token = strtok_r(NULL, ",", &saveptr);
|
|
|
|
}
|
|
|
|
VIR_FREE(hosts);
|
|
|
|
|
|
|
|
if (first_rbd_disk->nhosts == 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("found no rbd hosts in CEPH_ARGS '%s'"), ceph_args);
|
2011-11-01 01:29:07 +00:00
|
|
|
goto error;
|
2010-12-16 15:07:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-01 11:43:03 +00:00
|
|
|
if (!def->os.machine) {
|
|
|
|
const char *defaultMachine =
|
|
|
|
virCapabilitiesDefaultGuestMachine(caps,
|
|
|
|
def->os.type,
|
|
|
|
def->os.arch,
|
|
|
|
virDomainVirtTypeToString(def->virtType));
|
|
|
|
if (defaultMachine != NULL)
|
|
|
|
if (!(def->os.machine = strdup(defaultMachine)))
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:07:07 +00:00
|
|
|
if (!nographics && def->ngraphics == 0) {
|
|
|
|
virDomainGraphicsDefPtr sdl;
|
|
|
|
const char *display = qemuFindEnv(progenv, "DISPLAY");
|
|
|
|
const char *xauth = qemuFindEnv(progenv, "XAUTHORITY");
|
|
|
|
if (VIR_ALLOC(sdl) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
sdl->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
|
|
|
|
sdl->data.sdl.fullscreen = fullscreen;
|
|
|
|
if (display &&
|
|
|
|
!(sdl->data.sdl.display = strdup(display))) {
|
|
|
|
VIR_FREE(sdl);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
if (xauth &&
|
|
|
|
!(sdl->data.sdl.xauth = strdup(xauth))) {
|
|
|
|
VIR_FREE(sdl);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(def->graphics, def->ngraphics+1) < 0) {
|
|
|
|
virDomainGraphicsDefFree(sdl);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
def->graphics[def->ngraphics++] = sdl;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->ngraphics) {
|
|
|
|
virDomainVideoDefPtr vid;
|
|
|
|
if (VIR_ALLOC(vid) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
if (def->virtType == VIR_DOMAIN_VIRT_XEN)
|
|
|
|
vid->type = VIR_DOMAIN_VIDEO_TYPE_XEN;
|
|
|
|
else
|
|
|
|
vid->type = video;
|
|
|
|
vid->vram = virDomainVideoDefaultRAM(def, vid->type);
|
|
|
|
vid->heads = 1;
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(def->videos, def->nvideos+1) < 0) {
|
|
|
|
virDomainVideoDefFree(vid);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
def->videos[def->nvideos++] = vid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* having a balloon is the default, define one with type="none" to avoid it
|
|
|
|
*/
|
|
|
|
if (!def->memballoon) {
|
|
|
|
virDomainMemballoonDefPtr memballoon;
|
|
|
|
if (VIR_ALLOC(memballoon) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
memballoon->model = VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO;
|
|
|
|
|
|
|
|
def->memballoon = memballoon;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(nics);
|
|
|
|
|
|
|
|
if (virDomainDefAddImplicitControllers(def) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (cmd->num_args || cmd->num_env) {
|
|
|
|
def->ns = caps->ns;
|
|
|
|
def->namespaceData = cmd;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
error:
|
2011-08-02 20:07:25 +00:00
|
|
|
virDomainDiskDefFree(disk);
|
2010-12-16 15:07:07 +00:00
|
|
|
VIR_FREE(cmd);
|
|
|
|
virDomainDefFree(def);
|
|
|
|
VIR_FREE(nics);
|
2011-06-17 14:31:02 +00:00
|
|
|
if (monConfig) {
|
|
|
|
virDomainChrSourceDefFree(*monConfig);
|
|
|
|
*monConfig = NULL;
|
|
|
|
}
|
|
|
|
if (pidfile)
|
|
|
|
VIR_FREE(*pidfile);
|
2010-12-16 15:07:07 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virDomainDefPtr qemuParseCommandLineString(virCapsPtr caps,
|
2011-06-17 14:31:02 +00:00
|
|
|
const char *args,
|
|
|
|
char **pidfile,
|
|
|
|
virDomainChrSourceDefPtr *monConfig,
|
|
|
|
bool *monJSON)
|
2010-12-16 15:07:07 +00:00
|
|
|
{
|
|
|
|
const char **progenv = NULL;
|
|
|
|
const char **progargv = NULL;
|
|
|
|
virDomainDefPtr def = NULL;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (qemuStringToArgvEnv(args, &progenv, &progargv) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2011-06-17 14:31:02 +00:00
|
|
|
def = qemuParseCommandLine(caps, progenv, progargv,
|
|
|
|
pidfile, monConfig, monJSON);
|
2010-12-16 15:07:07 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
for (i = 0 ; progargv && progargv[i] ; i++)
|
|
|
|
VIR_FREE(progargv[i]);
|
|
|
|
VIR_FREE(progargv);
|
|
|
|
|
|
|
|
for (i = 0 ; progenv && progenv[i] ; i++)
|
|
|
|
VIR_FREE(progenv[i]);
|
|
|
|
VIR_FREE(progenv);
|
|
|
|
|
|
|
|
return def;
|
|
|
|
}
|
2011-06-17 14:34:00 +00:00
|
|
|
|
|
|
|
|
build: use correct type for pid and similar types
No thanks to 64-bit windows, with 64-bit pid_t, we have to avoid
constructs like 'int pid'. Our API in libvirt-qemu cannot be
changed without breaking ABI; but then again, libvirt-qemu can
only be used on systems that support UNIX sockets, which rules
out Windows (even if qemu could be compiled there) - so for all
points on the call chain that interact with this API decision,
we require a different variable name to make it clear that we
audited the use for safety.
Adding a syntax-check rule only solves half the battle; anywhere
that uses printf on a pid_t still needs to be converted, but that
will be a separate patch.
* cfg.mk (sc_correct_id_types): New syntax check.
* src/libvirt-qemu.c (virDomainQemuAttach): Document why we didn't
use pid_t for pid, and validate for overflow.
* include/libvirt/libvirt-qemu.h (virDomainQemuAttach): Tweak name
for syntax check.
* src/vmware/vmware_conf.c (vmwareExtractPid): Likewise.
* src/driver.h (virDrvDomainQemuAttach): Likewise.
* tools/virsh.c (cmdQemuAttach): Likewise.
* src/remote/qemu_protocol.x (qemu_domain_attach_args): Likewise.
* src/qemu_protocol-structs (qemu_domain_attach_args): Likewise.
* src/util/cgroup.c (virCgroupPidCode, virCgroupKillInternal):
Likewise.
* src/qemu/qemu_command.c(qemuParseProcFileStrings): Likewise.
(qemuParseCommandLinePid): Use pid_t for pid.
* daemon/libvirtd.c (daemonForkIntoBackground): Likewise.
* src/conf/domain_conf.h (_virDomainObj): Likewise.
* src/probes.d (rpc_socket_new): Likewise.
* src/qemu/qemu_command.h (qemuParseCommandLinePid): Likewise.
* src/qemu/qemu_driver.c (qemudGetProcessInfo, qemuDomainAttach):
Likewise.
* src/qemu/qemu_process.c (qemuProcessAttach): Likewise.
* src/qemu/qemu_process.h (qemuProcessAttach): Likewise.
* src/uml/uml_driver.c (umlGetProcessInfo): Likewise.
* src/util/virnetdev.h (virNetDevSetNamespace): Likewise.
* src/util/virnetdev.c (virNetDevSetNamespace): Likewise.
* tests/testutils.c (virtTestCaptureProgramOutput): Likewise.
* src/conf/storage_conf.h (_virStoragePerms): Use mode_t, uid_t,
and gid_t rather than int.
* src/security/security_dac.c (virSecurityDACSetOwnership): Likewise.
* src/conf/storage_conf.c (virStorageDefParsePerms): Avoid
compiler warning.
2012-02-10 23:08:11 +00:00
|
|
|
static int qemuParseProcFileStrings(int pid_value,
|
2011-06-17 14:34:00 +00:00
|
|
|
const char *name,
|
|
|
|
const char ***list)
|
|
|
|
{
|
|
|
|
char *path = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
char *data = NULL;
|
|
|
|
ssize_t len;
|
|
|
|
char *tmp;
|
|
|
|
size_t nstr = 0;
|
|
|
|
const char **str = NULL;
|
|
|
|
int i;
|
|
|
|
|
build: use correct type for pid and similar types
No thanks to 64-bit windows, with 64-bit pid_t, we have to avoid
constructs like 'int pid'. Our API in libvirt-qemu cannot be
changed without breaking ABI; but then again, libvirt-qemu can
only be used on systems that support UNIX sockets, which rules
out Windows (even if qemu could be compiled there) - so for all
points on the call chain that interact with this API decision,
we require a different variable name to make it clear that we
audited the use for safety.
Adding a syntax-check rule only solves half the battle; anywhere
that uses printf on a pid_t still needs to be converted, but that
will be a separate patch.
* cfg.mk (sc_correct_id_types): New syntax check.
* src/libvirt-qemu.c (virDomainQemuAttach): Document why we didn't
use pid_t for pid, and validate for overflow.
* include/libvirt/libvirt-qemu.h (virDomainQemuAttach): Tweak name
for syntax check.
* src/vmware/vmware_conf.c (vmwareExtractPid): Likewise.
* src/driver.h (virDrvDomainQemuAttach): Likewise.
* tools/virsh.c (cmdQemuAttach): Likewise.
* src/remote/qemu_protocol.x (qemu_domain_attach_args): Likewise.
* src/qemu_protocol-structs (qemu_domain_attach_args): Likewise.
* src/util/cgroup.c (virCgroupPidCode, virCgroupKillInternal):
Likewise.
* src/qemu/qemu_command.c(qemuParseProcFileStrings): Likewise.
(qemuParseCommandLinePid): Use pid_t for pid.
* daemon/libvirtd.c (daemonForkIntoBackground): Likewise.
* src/conf/domain_conf.h (_virDomainObj): Likewise.
* src/probes.d (rpc_socket_new): Likewise.
* src/qemu/qemu_command.h (qemuParseCommandLinePid): Likewise.
* src/qemu/qemu_driver.c (qemudGetProcessInfo, qemuDomainAttach):
Likewise.
* src/qemu/qemu_process.c (qemuProcessAttach): Likewise.
* src/qemu/qemu_process.h (qemuProcessAttach): Likewise.
* src/uml/uml_driver.c (umlGetProcessInfo): Likewise.
* src/util/virnetdev.h (virNetDevSetNamespace): Likewise.
* src/util/virnetdev.c (virNetDevSetNamespace): Likewise.
* tests/testutils.c (virtTestCaptureProgramOutput): Likewise.
* src/conf/storage_conf.h (_virStoragePerms): Use mode_t, uid_t,
and gid_t rather than int.
* src/security/security_dac.c (virSecurityDACSetOwnership): Likewise.
* src/conf/storage_conf.c (virStorageDefParsePerms): Avoid
compiler warning.
2012-02-10 23:08:11 +00:00
|
|
|
if (virAsprintf(&path, "/proc/%d/%s", pid_value, name) < 0) {
|
2011-06-17 14:34:00 +00:00
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((len = virFileReadAll(path, 1024*128, &data)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
tmp = data;
|
|
|
|
while (tmp < (data + len)) {
|
|
|
|
if (VIR_EXPAND_N(str, nstr, 1) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(str[nstr-1] = strdup(tmp))) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
/* Skip arg */
|
|
|
|
tmp += strlen(tmp);
|
|
|
|
/* Skip \0 separator */
|
|
|
|
tmp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_EXPAND_N(str, nstr, 1) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
str[nstr-1] = NULL;
|
|
|
|
|
|
|
|
ret = nstr-1;
|
|
|
|
*list = str;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (ret < 0) {
|
|
|
|
for (i = 0 ; str && str[i] ; i++)
|
|
|
|
VIR_FREE(str[i]);
|
|
|
|
VIR_FREE(str);
|
|
|
|
}
|
|
|
|
VIR_FREE(data);
|
|
|
|
VIR_FREE(path);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
virDomainDefPtr qemuParseCommandLinePid(virCapsPtr caps,
|
build: use correct type for pid and similar types
No thanks to 64-bit windows, with 64-bit pid_t, we have to avoid
constructs like 'int pid'. Our API in libvirt-qemu cannot be
changed without breaking ABI; but then again, libvirt-qemu can
only be used on systems that support UNIX sockets, which rules
out Windows (even if qemu could be compiled there) - so for all
points on the call chain that interact with this API decision,
we require a different variable name to make it clear that we
audited the use for safety.
Adding a syntax-check rule only solves half the battle; anywhere
that uses printf on a pid_t still needs to be converted, but that
will be a separate patch.
* cfg.mk (sc_correct_id_types): New syntax check.
* src/libvirt-qemu.c (virDomainQemuAttach): Document why we didn't
use pid_t for pid, and validate for overflow.
* include/libvirt/libvirt-qemu.h (virDomainQemuAttach): Tweak name
for syntax check.
* src/vmware/vmware_conf.c (vmwareExtractPid): Likewise.
* src/driver.h (virDrvDomainQemuAttach): Likewise.
* tools/virsh.c (cmdQemuAttach): Likewise.
* src/remote/qemu_protocol.x (qemu_domain_attach_args): Likewise.
* src/qemu_protocol-structs (qemu_domain_attach_args): Likewise.
* src/util/cgroup.c (virCgroupPidCode, virCgroupKillInternal):
Likewise.
* src/qemu/qemu_command.c(qemuParseProcFileStrings): Likewise.
(qemuParseCommandLinePid): Use pid_t for pid.
* daemon/libvirtd.c (daemonForkIntoBackground): Likewise.
* src/conf/domain_conf.h (_virDomainObj): Likewise.
* src/probes.d (rpc_socket_new): Likewise.
* src/qemu/qemu_command.h (qemuParseCommandLinePid): Likewise.
* src/qemu/qemu_driver.c (qemudGetProcessInfo, qemuDomainAttach):
Likewise.
* src/qemu/qemu_process.c (qemuProcessAttach): Likewise.
* src/qemu/qemu_process.h (qemuProcessAttach): Likewise.
* src/uml/uml_driver.c (umlGetProcessInfo): Likewise.
* src/util/virnetdev.h (virNetDevSetNamespace): Likewise.
* src/util/virnetdev.c (virNetDevSetNamespace): Likewise.
* tests/testutils.c (virtTestCaptureProgramOutput): Likewise.
* src/conf/storage_conf.h (_virStoragePerms): Use mode_t, uid_t,
and gid_t rather than int.
* src/security/security_dac.c (virSecurityDACSetOwnership): Likewise.
* src/conf/storage_conf.c (virStorageDefParsePerms): Avoid
compiler warning.
2012-02-10 23:08:11 +00:00
|
|
|
pid_t pid,
|
2011-06-17 14:34:00 +00:00
|
|
|
char **pidfile,
|
|
|
|
virDomainChrSourceDefPtr *monConfig,
|
|
|
|
bool *monJSON)
|
|
|
|
{
|
|
|
|
virDomainDefPtr def = NULL;
|
|
|
|
const char **progargv = NULL;
|
|
|
|
const char **progenv = NULL;
|
|
|
|
char *exepath = NULL;
|
|
|
|
char *emulator;
|
|
|
|
int i;
|
|
|
|
|
build: use correct type for pid and similar types
No thanks to 64-bit windows, with 64-bit pid_t, we have to avoid
constructs like 'int pid'. Our API in libvirt-qemu cannot be
changed without breaking ABI; but then again, libvirt-qemu can
only be used on systems that support UNIX sockets, which rules
out Windows (even if qemu could be compiled there) - so for all
points on the call chain that interact with this API decision,
we require a different variable name to make it clear that we
audited the use for safety.
Adding a syntax-check rule only solves half the battle; anywhere
that uses printf on a pid_t still needs to be converted, but that
will be a separate patch.
* cfg.mk (sc_correct_id_types): New syntax check.
* src/libvirt-qemu.c (virDomainQemuAttach): Document why we didn't
use pid_t for pid, and validate for overflow.
* include/libvirt/libvirt-qemu.h (virDomainQemuAttach): Tweak name
for syntax check.
* src/vmware/vmware_conf.c (vmwareExtractPid): Likewise.
* src/driver.h (virDrvDomainQemuAttach): Likewise.
* tools/virsh.c (cmdQemuAttach): Likewise.
* src/remote/qemu_protocol.x (qemu_domain_attach_args): Likewise.
* src/qemu_protocol-structs (qemu_domain_attach_args): Likewise.
* src/util/cgroup.c (virCgroupPidCode, virCgroupKillInternal):
Likewise.
* src/qemu/qemu_command.c(qemuParseProcFileStrings): Likewise.
(qemuParseCommandLinePid): Use pid_t for pid.
* daemon/libvirtd.c (daemonForkIntoBackground): Likewise.
* src/conf/domain_conf.h (_virDomainObj): Likewise.
* src/probes.d (rpc_socket_new): Likewise.
* src/qemu/qemu_command.h (qemuParseCommandLinePid): Likewise.
* src/qemu/qemu_driver.c (qemudGetProcessInfo, qemuDomainAttach):
Likewise.
* src/qemu/qemu_process.c (qemuProcessAttach): Likewise.
* src/qemu/qemu_process.h (qemuProcessAttach): Likewise.
* src/uml/uml_driver.c (umlGetProcessInfo): Likewise.
* src/util/virnetdev.h (virNetDevSetNamespace): Likewise.
* src/util/virnetdev.c (virNetDevSetNamespace): Likewise.
* tests/testutils.c (virtTestCaptureProgramOutput): Likewise.
* src/conf/storage_conf.h (_virStoragePerms): Use mode_t, uid_t,
and gid_t rather than int.
* src/security/security_dac.c (virSecurityDACSetOwnership): Likewise.
* src/conf/storage_conf.c (virStorageDefParsePerms): Avoid
compiler warning.
2012-02-10 23:08:11 +00:00
|
|
|
/* The parser requires /proc/pid, which only exists on platforms
|
|
|
|
* like Linux where pid_t fits in int. */
|
|
|
|
if ((int) pid != pid ||
|
|
|
|
qemuParseProcFileStrings(pid, "cmdline", &progargv) < 0 ||
|
2011-06-17 14:34:00 +00:00
|
|
|
qemuParseProcFileStrings(pid, "environ", &progenv) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!(def = qemuParseCommandLine(caps, progenv, progargv,
|
|
|
|
pidfile, monConfig, monJSON)))
|
|
|
|
goto cleanup;
|
|
|
|
|
build: use correct type for pid and similar types
No thanks to 64-bit windows, with 64-bit pid_t, we have to avoid
constructs like 'int pid'. Our API in libvirt-qemu cannot be
changed without breaking ABI; but then again, libvirt-qemu can
only be used on systems that support UNIX sockets, which rules
out Windows (even if qemu could be compiled there) - so for all
points on the call chain that interact with this API decision,
we require a different variable name to make it clear that we
audited the use for safety.
Adding a syntax-check rule only solves half the battle; anywhere
that uses printf on a pid_t still needs to be converted, but that
will be a separate patch.
* cfg.mk (sc_correct_id_types): New syntax check.
* src/libvirt-qemu.c (virDomainQemuAttach): Document why we didn't
use pid_t for pid, and validate for overflow.
* include/libvirt/libvirt-qemu.h (virDomainQemuAttach): Tweak name
for syntax check.
* src/vmware/vmware_conf.c (vmwareExtractPid): Likewise.
* src/driver.h (virDrvDomainQemuAttach): Likewise.
* tools/virsh.c (cmdQemuAttach): Likewise.
* src/remote/qemu_protocol.x (qemu_domain_attach_args): Likewise.
* src/qemu_protocol-structs (qemu_domain_attach_args): Likewise.
* src/util/cgroup.c (virCgroupPidCode, virCgroupKillInternal):
Likewise.
* src/qemu/qemu_command.c(qemuParseProcFileStrings): Likewise.
(qemuParseCommandLinePid): Use pid_t for pid.
* daemon/libvirtd.c (daemonForkIntoBackground): Likewise.
* src/conf/domain_conf.h (_virDomainObj): Likewise.
* src/probes.d (rpc_socket_new): Likewise.
* src/qemu/qemu_command.h (qemuParseCommandLinePid): Likewise.
* src/qemu/qemu_driver.c (qemudGetProcessInfo, qemuDomainAttach):
Likewise.
* src/qemu/qemu_process.c (qemuProcessAttach): Likewise.
* src/qemu/qemu_process.h (qemuProcessAttach): Likewise.
* src/uml/uml_driver.c (umlGetProcessInfo): Likewise.
* src/util/virnetdev.h (virNetDevSetNamespace): Likewise.
* src/util/virnetdev.c (virNetDevSetNamespace): Likewise.
* tests/testutils.c (virtTestCaptureProgramOutput): Likewise.
* src/conf/storage_conf.h (_virStoragePerms): Use mode_t, uid_t,
and gid_t rather than int.
* src/security/security_dac.c (virSecurityDACSetOwnership): Likewise.
* src/conf/storage_conf.c (virStorageDefParsePerms): Avoid
compiler warning.
2012-02-10 23:08:11 +00:00
|
|
|
if (virAsprintf(&exepath, "/proc/%d/exe", (int) pid) < 0) {
|
2011-06-17 14:34:00 +00:00
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virFileResolveLink(exepath, &emulator) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to resolve %s for pid %u"),
|
build: use correct type for pid and similar types
No thanks to 64-bit windows, with 64-bit pid_t, we have to avoid
constructs like 'int pid'. Our API in libvirt-qemu cannot be
changed without breaking ABI; but then again, libvirt-qemu can
only be used on systems that support UNIX sockets, which rules
out Windows (even if qemu could be compiled there) - so for all
points on the call chain that interact with this API decision,
we require a different variable name to make it clear that we
audited the use for safety.
Adding a syntax-check rule only solves half the battle; anywhere
that uses printf on a pid_t still needs to be converted, but that
will be a separate patch.
* cfg.mk (sc_correct_id_types): New syntax check.
* src/libvirt-qemu.c (virDomainQemuAttach): Document why we didn't
use pid_t for pid, and validate for overflow.
* include/libvirt/libvirt-qemu.h (virDomainQemuAttach): Tweak name
for syntax check.
* src/vmware/vmware_conf.c (vmwareExtractPid): Likewise.
* src/driver.h (virDrvDomainQemuAttach): Likewise.
* tools/virsh.c (cmdQemuAttach): Likewise.
* src/remote/qemu_protocol.x (qemu_domain_attach_args): Likewise.
* src/qemu_protocol-structs (qemu_domain_attach_args): Likewise.
* src/util/cgroup.c (virCgroupPidCode, virCgroupKillInternal):
Likewise.
* src/qemu/qemu_command.c(qemuParseProcFileStrings): Likewise.
(qemuParseCommandLinePid): Use pid_t for pid.
* daemon/libvirtd.c (daemonForkIntoBackground): Likewise.
* src/conf/domain_conf.h (_virDomainObj): Likewise.
* src/probes.d (rpc_socket_new): Likewise.
* src/qemu/qemu_command.h (qemuParseCommandLinePid): Likewise.
* src/qemu/qemu_driver.c (qemudGetProcessInfo, qemuDomainAttach):
Likewise.
* src/qemu/qemu_process.c (qemuProcessAttach): Likewise.
* src/qemu/qemu_process.h (qemuProcessAttach): Likewise.
* src/uml/uml_driver.c (umlGetProcessInfo): Likewise.
* src/util/virnetdev.h (virNetDevSetNamespace): Likewise.
* src/util/virnetdev.c (virNetDevSetNamespace): Likewise.
* tests/testutils.c (virtTestCaptureProgramOutput): Likewise.
* src/conf/storage_conf.h (_virStoragePerms): Use mode_t, uid_t,
and gid_t rather than int.
* src/security/security_dac.c (virSecurityDACSetOwnership): Likewise.
* src/conf/storage_conf.c (virStorageDefParsePerms): Avoid
compiler warning.
2012-02-10 23:08:11 +00:00
|
|
|
exepath, (int) pid);
|
2011-06-17 14:34:00 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
VIR_FREE(def->emulator);
|
|
|
|
def->emulator = emulator;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(exepath);
|
|
|
|
for (i = 0 ; progargv && progargv[i] ; i++)
|
|
|
|
VIR_FREE(progargv[i]);
|
|
|
|
VIR_FREE(progargv);
|
|
|
|
for (i = 0 ; progenv && progenv[i] ; i++)
|
|
|
|
VIR_FREE(progenv[i]);
|
|
|
|
VIR_FREE(progenv);
|
|
|
|
return def;
|
|
|
|
}
|