2007-02-14 01:40:09 +00:00
|
|
|
/*
|
2009-05-21 14:16:55 +00:00
|
|
|
* qemu_conf.c: QEMU configuration management
|
2007-02-14 01:40:09 +00:00
|
|
|
*
|
2010-01-18 15:51:52 +00:00
|
|
|
* Copyright (C) 2006, 2007, 2008, 2009, 2010 Red Hat, Inc.
|
2007-02-14 01:40:09 +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
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
2008-01-29 18:15:54 +00:00
|
|
|
#include <config.h>
|
2007-11-26 11:50:16 +00:00
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
#include <dirent.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2008-10-10 16:52:20 +00:00
|
|
|
#include <stdlib.h>
|
2007-02-14 01:40:09 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
2007-02-23 17:15:18 +00:00
|
|
|
#include <sys/wait.h>
|
2007-04-10 23:17:46 +00:00
|
|
|
#include <arpa/inet.h>
|
2007-04-16 13:14:28 +00:00
|
|
|
#include <sys/utsname.h>
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 14:05:18 +00:00
|
|
|
#include <mntent.h>
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-05-21 14:16:55 +00:00
|
|
|
#include "c-ctype.h"
|
2008-11-04 22:30:33 +00:00
|
|
|
#include "virterror_internal.h"
|
2007-06-27 00:12:29 +00:00
|
|
|
#include "qemu_conf.h"
|
2009-11-03 22:41:23 +00:00
|
|
|
#include "qemu_bridge_filter.h"
|
2007-02-26 15:32:27 +00:00
|
|
|
#include "uuid.h"
|
2007-06-27 00:12:29 +00:00
|
|
|
#include "buf.h"
|
2007-10-12 16:05:44 +00:00
|
|
|
#include "conf.h"
|
2007-12-03 14:30:46 +00:00
|
|
|
#include "util.h"
|
2008-05-22 15:29:50 +00:00
|
|
|
#include "memory.h"
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
#include "verify.h"
|
2008-12-20 13:09:45 +00:00
|
|
|
#include "datatypes.h"
|
|
|
|
#include "xml.h"
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
#include "nodeinfo.h"
|
2009-03-03 11:40:08 +00:00
|
|
|
#include "logging.h"
|
2009-11-05 14:31:03 +00:00
|
|
|
#include "network.h"
|
2010-02-15 16:41:14 +00:00
|
|
|
#include "macvtap.h"
|
2009-12-18 15:24:14 +00:00
|
|
|
#include "cpu/cpu.h"
|
2008-07-11 19:34:11 +00:00
|
|
|
|
2009-01-23 16:22:20 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
VIR_ENUM_DECL(virDomainDiskQEMUBus)
|
|
|
|
VIR_ENUM_IMPL(virDomainDiskQEMUBus, VIR_DOMAIN_DISK_BUS_LAST,
|
|
|
|
"ide",
|
|
|
|
"floppy",
|
|
|
|
"scsi",
|
|
|
|
"virtio",
|
2008-08-08 15:03:00 +00:00
|
|
|
"xen",
|
2008-11-19 16:58:23 +00:00
|
|
|
"usb",
|
2009-11-12 14:45:18 +00:00
|
|
|
"uml",
|
|
|
|
"sata")
|
2008-07-11 19:34:11 +00:00
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
|
2009-01-30 17:15:39 +00:00
|
|
|
VIR_ENUM_DECL(qemuDiskCacheV1)
|
|
|
|
VIR_ENUM_DECL(qemuDiskCacheV2)
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(qemuDiskCacheV1, VIR_DOMAIN_DISK_CACHE_LAST,
|
|
|
|
"default",
|
|
|
|
"off",
|
|
|
|
"off", /* writethrough not supported, so for safety, disable */
|
|
|
|
"on"); /* Old 'on' was equivalent to 'writeback' */
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(qemuDiskCacheV2, VIR_DOMAIN_DISK_CACHE_LAST,
|
|
|
|
"default",
|
|
|
|
"none",
|
|
|
|
"writethrough",
|
|
|
|
"writeback");
|
|
|
|
|
2009-07-06 13:59:19 +00:00
|
|
|
VIR_ENUM_DECL(qemuVideo)
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(qemuVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
|
|
|
|
"std",
|
|
|
|
"cirrus",
|
|
|
|
"vmware",
|
2009-12-21 22:38:05 +00:00
|
|
|
"", /* no arg needed for xen */
|
|
|
|
"" /* don't support vbox */);
|
2009-07-06 13:59:19 +00:00
|
|
|
|
2007-10-12 16:05:44 +00:00
|
|
|
int qemudLoadDriverConfig(struct qemud_driver *driver,
|
|
|
|
const char *filename) {
|
|
|
|
virConfPtr conf;
|
|
|
|
virConfValuePtr p;
|
2009-07-15 21:25:01 +00:00
|
|
|
char *user;
|
|
|
|
char *group;
|
2009-07-22 15:08:04 +00:00
|
|
|
int i;
|
2007-10-12 16:05:44 +00:00
|
|
|
|
2010-01-13 17:41:36 +00:00
|
|
|
/* Setup critical defaults */
|
|
|
|
driver->dynamicOwnership = 1;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (!(driver->vncListen = strdup("127.0.0.1"))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-07-11 19:34:11 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-10-12 16:05:44 +00:00
|
|
|
if (!(driver->vncTLSx509certdir = strdup(SYSCONF_DIR "/pki/libvirt-vnc"))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2007-10-12 16:05:44 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 14:05:18 +00:00
|
|
|
#ifdef HAVE_MNTENT_H
|
|
|
|
/* For privileged driver, try and find hugepage mount automatically.
|
|
|
|
* Non-privileged driver requires admin to create a dir for the
|
|
|
|
* user, chown it, and then let user configure it manually */
|
|
|
|
if (driver->privileged &&
|
|
|
|
!(driver->hugetlbfs_mount = virFileFindMountPoint("hugetlbfs"))) {
|
|
|
|
if (errno != ENOENT) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno, "%s",
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 14:05:18 +00:00
|
|
|
_("unable to find hugetlbfs mountpoint"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2007-10-12 16:05:44 +00:00
|
|
|
/* Just check the file is readable before opening it, otherwise
|
|
|
|
* libvirt emits an error.
|
|
|
|
*/
|
|
|
|
if (access (filename, R_OK) == -1) return 0;
|
|
|
|
|
2009-06-19 12:34:30 +00:00
|
|
|
conf = virConfReadFile (filename, 0);
|
2007-10-12 16:05:44 +00:00
|
|
|
if (!conf) return 0;
|
|
|
|
|
|
|
|
|
|
|
|
#define CHECK_TYPE(name,typ) if (p && p->type != (typ)) { \
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, \
|
2007-10-12 16:05:44 +00:00
|
|
|
"remoteReadConfigFile: %s: %s: expected type " #typ "\n", \
|
|
|
|
filename, (name)); \
|
|
|
|
virConfFree(conf); \
|
|
|
|
return -1; \
|
|
|
|
}
|
|
|
|
|
|
|
|
p = virConfGetValue (conf, "vnc_tls");
|
|
|
|
CHECK_TYPE ("vnc_tls", VIR_CONF_LONG);
|
|
|
|
if (p) driver->vncTLS = p->l;
|
|
|
|
|
|
|
|
p = virConfGetValue (conf, "vnc_tls_x509_verify");
|
|
|
|
CHECK_TYPE ("vnc_tls_x509_verify", VIR_CONF_LONG);
|
|
|
|
if (p) driver->vncTLSx509verify = p->l;
|
|
|
|
|
|
|
|
p = virConfGetValue (conf, "vnc_tls_x509_cert_dir");
|
|
|
|
CHECK_TYPE ("vnc_tls_x509_cert_dir", VIR_CONF_STRING);
|
|
|
|
if (p && p->str) {
|
2008-05-29 19:20:22 +00:00
|
|
|
VIR_FREE(driver->vncTLSx509certdir);
|
2007-10-12 16:05:44 +00:00
|
|
|
if (!(driver->vncTLSx509certdir = strdup(p->str))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2007-10-12 16:05:44 +00:00
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p = virConfGetValue (conf, "vnc_listen");
|
|
|
|
CHECK_TYPE ("vnc_listen", VIR_CONF_STRING);
|
|
|
|
if (p && p->str) {
|
2008-11-05 14:24:21 +00:00
|
|
|
VIR_FREE(driver->vncListen);
|
2008-07-11 19:34:11 +00:00
|
|
|
if (!(driver->vncListen = strdup(p->str))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-07-11 19:34:11 +00:00
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
2007-10-12 16:05:44 +00:00
|
|
|
}
|
|
|
|
|
2009-01-29 17:50:00 +00:00
|
|
|
p = virConfGetValue (conf, "vnc_password");
|
|
|
|
CHECK_TYPE ("vnc_password", VIR_CONF_STRING);
|
|
|
|
if (p && p->str) {
|
|
|
|
VIR_FREE(driver->vncPassword);
|
|
|
|
if (!(driver->vncPassword = strdup(p->str))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-01-29 17:50:00 +00:00
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-03 12:03:44 +00:00
|
|
|
p = virConfGetValue (conf, "security_driver");
|
2009-03-03 15:12:30 +00:00
|
|
|
CHECK_TYPE ("security_driver", VIR_CONF_STRING);
|
2009-03-03 12:03:44 +00:00
|
|
|
if (p && p->str) {
|
|
|
|
if (!(driver->securityDriverName = strdup(p->str))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-03-03 12:03:44 +00:00
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-16 13:54:26 +00:00
|
|
|
p = virConfGetValue (conf, "vnc_sasl");
|
|
|
|
CHECK_TYPE ("vnc_sasl", VIR_CONF_LONG);
|
|
|
|
if (p) driver->vncSASL = p->l;
|
|
|
|
|
|
|
|
p = virConfGetValue (conf, "vnc_sasl_dir");
|
|
|
|
CHECK_TYPE ("vnc_sasl_dir", VIR_CONF_STRING);
|
|
|
|
if (p && p->str) {
|
|
|
|
VIR_FREE(driver->vncSASLdir);
|
|
|
|
if (!(driver->vncSASLdir = strdup(p->str))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-03-16 13:54:26 +00:00
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-15 21:25:01 +00:00
|
|
|
p = virConfGetValue (conf, "user");
|
|
|
|
CHECK_TYPE ("user", VIR_CONF_STRING);
|
|
|
|
if (!(user = strdup(p && p->str ? p->str : QEMU_USER))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-07-15 21:25:01 +00:00
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
2010-02-04 22:41:52 +00:00
|
|
|
if (virGetUserID(user, &driver->user) < 0) {
|
2009-07-15 21:25:01 +00:00
|
|
|
VIR_FREE(user);
|
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
VIR_FREE(user);
|
|
|
|
|
2010-01-13 17:41:36 +00:00
|
|
|
|
2009-07-15 21:25:01 +00:00
|
|
|
p = virConfGetValue (conf, "group");
|
|
|
|
CHECK_TYPE ("group", VIR_CONF_STRING);
|
|
|
|
if (!(group = strdup(p && p->str ? p->str : QEMU_GROUP))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-07-15 21:25:01 +00:00
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
2010-02-04 22:41:52 +00:00
|
|
|
if (virGetGroupID(group, &driver->group) < 0) {
|
2009-07-15 21:25:01 +00:00
|
|
|
VIR_FREE(group);
|
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
VIR_FREE(group);
|
|
|
|
|
2010-01-13 17:41:36 +00:00
|
|
|
|
|
|
|
p = virConfGetValue (conf, "dynamic_ownership");
|
|
|
|
CHECK_TYPE ("dynamic_ownership", VIR_CONF_LONG);
|
|
|
|
if (p) driver->dynamicOwnership = p->l;
|
|
|
|
|
|
|
|
|
2009-07-22 15:08:04 +00:00
|
|
|
p = virConfGetValue (conf, "cgroup_controllers");
|
|
|
|
CHECK_TYPE ("cgroup_controllers", VIR_CONF_LIST);
|
|
|
|
if (p) {
|
|
|
|
virConfValuePtr pp;
|
|
|
|
for (i = 0, pp = p->list; pp; ++i, pp = pp->next) {
|
|
|
|
int ctl;
|
|
|
|
if (pp->type != VIR_CONF_STRING) {
|
2009-10-22 15:41:57 +00:00
|
|
|
VIR_ERROR("%s", _("cgroup_controllers must be a list of strings"));
|
2009-07-22 15:08:04 +00:00
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
ctl = virCgroupControllerTypeFromString(pp->str);
|
|
|
|
if (ctl < 0) {
|
|
|
|
VIR_ERROR("Unknown cgroup controller '%s'", pp->str);
|
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
driver->cgroupControllers |= (1 << ctl);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
driver->cgroupControllers =
|
|
|
|
(1 << VIR_CGROUP_CONTROLLER_CPU) |
|
|
|
|
(1 << VIR_CGROUP_CONTROLLER_DEVICES);
|
|
|
|
}
|
|
|
|
for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
|
|
|
|
if (driver->cgroupControllers & (1 << i)) {
|
|
|
|
VIR_INFO("Configured cgroup controller '%s'",
|
|
|
|
virCgroupControllerTypeToString(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p = virConfGetValue (conf, "cgroup_device_acl");
|
|
|
|
CHECK_TYPE ("cgroup_device_acl", VIR_CONF_LIST);
|
|
|
|
if (p) {
|
|
|
|
int len = 0;
|
|
|
|
virConfValuePtr pp;
|
|
|
|
for (pp = p->list; pp; pp = pp->next)
|
|
|
|
len++;
|
|
|
|
if (VIR_ALLOC_N(driver->cgroupDeviceACL, 1+len) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-07-22 15:08:04 +00:00
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0, pp = p->list; pp; ++i, pp = pp->next) {
|
|
|
|
if (pp->type != VIR_CONF_STRING) {
|
|
|
|
VIR_ERROR("%s", _("cgroup_device_acl must be a list of strings"));
|
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
driver->cgroupDeviceACL[i] = strdup (pp->str);
|
|
|
|
if (driver->cgroupDeviceACL[i] == NULL) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-07-22 15:08:04 +00:00
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
driver->cgroupDeviceACL[i] = NULL;
|
|
|
|
}
|
|
|
|
|
Compressed save image format for Qemu.
Implement a compressed save image format for qemu. While ideally
we would have the choice between compressed/non-compressed
available to the libvirt API, unfortunately there is no "flags"
parameter to the virDomainSave() API. Therefore, implement this
as a qemu.conf option. gzip, bzip2, and lzma are implemented, and
it should be very easy to implement additional compression
methods.
One open question is if/how we should detect the compression
binaries. One way to do it is to do compile-time setting of the
paths (via configure.in), but that doesn't seem like a great thing
to do. My preferred solution is not to detect at all;
when we go to run the commands that need them, if they
aren't available, or aren't available in one of the standard paths,
then we'll fail. That's also the solution implemented in this patch.
In the future, we'll have a more robust (managed) save/restore API,
at which time we can expose this functionality properly in the API.
V2: get rid of redundant dd command and just use >> to append data.
V3: Add back the missing pieces for the enum and bumping the save version.
V4: Make the compressed field in the save_header an int.
Implement LZMA compression.
Signed-off-by: Chris Lalancette <clalance@redhat.com>
2009-08-07 11:34:05 +00:00
|
|
|
p = virConfGetValue (conf, "save_image_format");
|
|
|
|
CHECK_TYPE ("save_image_format", VIR_CONF_STRING);
|
|
|
|
if (p && p->str) {
|
|
|
|
VIR_FREE(driver->saveImageFormat);
|
|
|
|
if (!(driver->saveImageFormat = strdup(p->str))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
Compressed save image format for Qemu.
Implement a compressed save image format for qemu. While ideally
we would have the choice between compressed/non-compressed
available to the libvirt API, unfortunately there is no "flags"
parameter to the virDomainSave() API. Therefore, implement this
as a qemu.conf option. gzip, bzip2, and lzma are implemented, and
it should be very easy to implement additional compression
methods.
One open question is if/how we should detect the compression
binaries. One way to do it is to do compile-time setting of the
paths (via configure.in), but that doesn't seem like a great thing
to do. My preferred solution is not to detect at all;
when we go to run the commands that need them, if they
aren't available, or aren't available in one of the standard paths,
then we'll fail. That's also the solution implemented in this patch.
In the future, we'll have a more robust (managed) save/restore API,
at which time we can expose this functionality properly in the API.
V2: get rid of redundant dd command and just use >> to append data.
V3: Add back the missing pieces for the enum and bumping the save version.
V4: Make the compressed field in the save_header an int.
Implement LZMA compression.
Signed-off-by: Chris Lalancette <clalance@redhat.com>
2009-08-07 11:34:05 +00:00
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 14:05:18 +00:00
|
|
|
p = virConfGetValue (conf, "hugetlbfs_mount");
|
|
|
|
CHECK_TYPE ("hugetlbfs_mount", VIR_CONF_STRING);
|
|
|
|
if (p && p->str) {
|
|
|
|
VIR_FREE(driver->hugetlbfs_mount);
|
|
|
|
if (!(driver->hugetlbfs_mount = strdup(p->str))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 14:05:18 +00:00
|
|
|
virConfFree(conf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-03 22:41:23 +00:00
|
|
|
p = virConfGetValue (conf, "mac_filter");
|
|
|
|
CHECK_TYPE ("mac_filter", VIR_CONF_LONG);
|
2009-11-11 11:59:54 +00:00
|
|
|
if (p && p->l) {
|
2009-11-03 22:41:23 +00:00
|
|
|
driver->macFilter = p->l;
|
|
|
|
if (!(driver->ebtables = ebtablesContextNew("qemu"))) {
|
|
|
|
driver->macFilter = 0;
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2010-02-19 14:41:30 +00:00
|
|
|
_("failed to enable mac filter in '%s'"),
|
2009-11-03 22:41:23 +00:00
|
|
|
__FILE__);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((errno = networkDisableAllFrames(driver))) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-11-03 22:41:23 +00:00
|
|
|
_("failed to add rule to drop all frames in '%s'"),
|
|
|
|
__FILE__);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-22 17:21:16 +00:00
|
|
|
p = virConfGetValue (conf, "relaxed_acs_check");
|
|
|
|
CHECK_TYPE ("relaxed_acs_check", VIR_CONF_LONG);
|
|
|
|
if (p) driver->relaxedACS = p->l;
|
|
|
|
|
2007-10-12 16:05:44 +00:00
|
|
|
virConfFree (conf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
struct qemu_feature_flags {
|
|
|
|
const char *name;
|
|
|
|
const int default_on;
|
|
|
|
const int toggle;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct qemu_arch_info {
|
|
|
|
const char *arch;
|
|
|
|
int wordsize;
|
2009-07-23 17:31:34 +00:00
|
|
|
const char *machine;
|
2008-02-27 04:35:08 +00:00
|
|
|
const char *binary;
|
2009-03-20 11:20:26 +00:00
|
|
|
const char *altbinary;
|
2008-02-27 04:35:08 +00:00
|
|
|
const struct qemu_feature_flags *flags;
|
|
|
|
int nflags;
|
2007-02-14 01:40:09 +00:00
|
|
|
};
|
|
|
|
|
2007-07-30 09:59:05 +00:00
|
|
|
/* Feature flags for the architecture info */
|
2008-01-14 14:05:25 +00:00
|
|
|
static const struct qemu_feature_flags const arch_info_i686_flags [] = {
|
2008-02-27 04:35:08 +00:00
|
|
|
{ "pae", 1, 0 },
|
|
|
|
{ "nonpae", 1, 0 },
|
2007-07-30 09:59:05 +00:00
|
|
|
{ "acpi", 1, 1 },
|
|
|
|
{ "apic", 1, 0 },
|
|
|
|
};
|
|
|
|
|
2008-01-14 14:05:25 +00:00
|
|
|
static const struct qemu_feature_flags const arch_info_x86_64_flags [] = {
|
2007-07-30 09:59:05 +00:00
|
|
|
{ "acpi", 1, 1 },
|
|
|
|
{ "apic", 1, 0 },
|
|
|
|
};
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
/* The archicture tables for supported QEMU archs */
|
2008-02-27 04:35:08 +00:00
|
|
|
static const struct qemu_arch_info const arch_info_hvm[] = {
|
2010-01-19 23:24:47 +00:00
|
|
|
{ "i686", 32, NULL, "qemu",
|
|
|
|
"qemu-system-x86_64", arch_info_i686_flags, 4 },
|
|
|
|
{ "x86_64", 64, NULL, "qemu-system-x86_64",
|
2009-07-23 17:31:34 +00:00
|
|
|
NULL, arch_info_x86_64_flags, 2 },
|
2010-01-19 23:24:47 +00:00
|
|
|
{ "arm", 32, NULL, "qemu-system-arm", NULL, NULL, 0 },
|
|
|
|
{ "mips", 32, NULL, "qemu-system-mips", NULL, NULL, 0 },
|
|
|
|
{ "mipsel", 32, NULL, "qemu-system-mipsel", NULL, NULL, 0 },
|
|
|
|
{ "sparc", 32, NULL, "qemu-system-sparc", NULL, NULL, 0 },
|
|
|
|
{ "ppc", 32, NULL, "qemu-system-ppc", NULL, NULL, 0 },
|
2010-02-18 15:48:51 +00:00
|
|
|
{ "itanium", 64, NULL, "qemu-system-ia64", NULL, NULL, 0 },
|
2007-02-14 01:40:09 +00:00
|
|
|
};
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
static const struct qemu_arch_info const arch_info_xen[] = {
|
2010-01-19 23:24:47 +00:00
|
|
|
{ "i686", 32, "xenner", "xenner", NULL, arch_info_i686_flags, 4 },
|
|
|
|
{ "x86_64", 64, "xenner", "xenner", NULL, arch_info_x86_64_flags, 2 },
|
2008-02-27 04:35:08 +00:00
|
|
|
};
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-07-23 17:31:34 +00:00
|
|
|
|
|
|
|
/* Format is:
|
2009-07-23 17:31:34 +00:00
|
|
|
* <machine> <desc> [(default)|(alias of <canonical>)]
|
2009-07-23 17:31:34 +00:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
qemudParseMachineTypesStr(const char *output,
|
2009-07-23 17:31:34 +00:00
|
|
|
virCapsGuestMachinePtr **machines,
|
2009-07-23 17:31:34 +00:00
|
|
|
int *nmachines)
|
|
|
|
{
|
|
|
|
const char *p = output;
|
|
|
|
const char *next;
|
2009-07-23 17:31:34 +00:00
|
|
|
virCapsGuestMachinePtr *list = NULL;
|
|
|
|
int nitems = 0;
|
2009-07-23 17:31:34 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
const char *t;
|
2009-07-23 17:31:34 +00:00
|
|
|
virCapsGuestMachinePtr machine;
|
2009-07-23 17:31:34 +00:00
|
|
|
|
|
|
|
if ((next = strchr(p, '\n')))
|
|
|
|
++next;
|
|
|
|
|
|
|
|
if (STRPREFIX(p, "Supported machines are:"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!(t = strchr(p, ' ')) || (next && t >= next))
|
|
|
|
continue;
|
|
|
|
|
2009-07-23 17:31:34 +00:00
|
|
|
if (VIR_ALLOC(machine) < 0)
|
2009-11-08 21:08:54 +00:00
|
|
|
goto no_memory;
|
2009-07-23 17:31:34 +00:00
|
|
|
|
2009-07-23 17:31:34 +00:00
|
|
|
if (!(machine->name = strndup(p, t - p))) {
|
|
|
|
VIR_FREE(machine);
|
2009-11-08 21:08:54 +00:00
|
|
|
goto no_memory;
|
2009-07-23 17:31:34 +00:00
|
|
|
}
|
|
|
|
|
2009-07-23 17:31:34 +00:00
|
|
|
if (VIR_REALLOC_N(list, nitems + 1) < 0) {
|
2009-07-23 17:31:34 +00:00
|
|
|
VIR_FREE(machine->name);
|
2009-07-23 17:31:34 +00:00
|
|
|
VIR_FREE(machine);
|
2009-11-08 21:08:54 +00:00
|
|
|
goto no_memory;
|
2009-07-23 17:31:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
p = t;
|
|
|
|
if (!(t = strstr(p, "(default)")) || (next && t >= next)) {
|
|
|
|
list[nitems++] = machine;
|
|
|
|
} else {
|
|
|
|
/* put the default first in the list */
|
|
|
|
memmove(list + 1, list, sizeof(*list) * nitems);
|
|
|
|
list[0] = machine;
|
|
|
|
nitems++;
|
|
|
|
}
|
2009-07-23 17:31:34 +00:00
|
|
|
|
|
|
|
if ((t = strstr(p, "(alias of ")) && (!next || t < next)) {
|
|
|
|
p = t + strlen("(alias of ");
|
|
|
|
if (!(t = strchr(p, ')')) || (next && t >= next))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!(machine->canonical = strndup(p, t - p)))
|
2009-11-08 21:08:54 +00:00
|
|
|
goto no_memory;
|
2009-07-23 17:31:34 +00:00
|
|
|
}
|
2009-07-23 17:31:34 +00:00
|
|
|
} while ((p = next));
|
|
|
|
|
|
|
|
*machines = list;
|
|
|
|
*nmachines = nitems;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2009-11-08 21:08:54 +00:00
|
|
|
no_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-07-23 17:31:34 +00:00
|
|
|
virCapabilitiesFreeMachines(list, nitems);
|
2009-07-23 17:31:34 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-07-23 17:31:34 +00:00
|
|
|
int
|
2009-07-23 17:31:34 +00:00
|
|
|
qemudProbeMachineTypes(const char *binary,
|
2009-07-23 17:31:34 +00:00
|
|
|
virCapsGuestMachinePtr **machines,
|
2009-07-23 17:31:34 +00:00
|
|
|
int *nmachines)
|
|
|
|
{
|
|
|
|
const char *const qemuarg[] = { binary, "-M", "?", NULL };
|
|
|
|
const char *const qemuenv[] = { "LC_ALL=C", NULL };
|
|
|
|
char *output;
|
|
|
|
enum { MAX_MACHINES_OUTPUT_SIZE = 1024*4 };
|
|
|
|
pid_t child;
|
|
|
|
int newstdout = -1, len;
|
|
|
|
int ret = -1, status;
|
|
|
|
|
2010-02-04 22:41:52 +00:00
|
|
|
if (virExec(qemuarg, qemuenv, NULL,
|
2009-07-23 17:31:34 +00:00
|
|
|
&child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
len = virFileReadLimFD(newstdout, MAX_MACHINES_OUTPUT_SIZE, &output);
|
|
|
|
if (len < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno, "%s",
|
2009-07-23 17:31:34 +00:00
|
|
|
_("Unable to read 'qemu -M ?' output"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemudParseMachineTypesStr(output, machines, nmachines) < 0)
|
|
|
|
goto cleanup2;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup2:
|
|
|
|
VIR_FREE(output);
|
|
|
|
cleanup:
|
|
|
|
if (close(newstdout) < 0)
|
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
rewait:
|
|
|
|
if (waitpid(child, &status, 0) != child) {
|
|
|
|
if (errno == EINTR)
|
|
|
|
goto rewait;
|
|
|
|
|
|
|
|
VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
|
|
|
|
WEXITSTATUS(status), (unsigned long)child);
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
/* Check & log unexpected exit status, but don't fail,
|
|
|
|
* as there's really no need to throw an error if we did
|
|
|
|
* actually read a valid version number above */
|
|
|
|
if (WEXITSTATUS(status) != 0) {
|
|
|
|
VIR_WARN(_("Unexpected exit status '%d', qemu probably failed"),
|
|
|
|
WEXITSTATUS(status));
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-09-07 11:12:42 +00:00
|
|
|
static int
|
|
|
|
qemudGetOldMachinesFromInfo(virCapsGuestDomainInfoPtr info,
|
|
|
|
const char *emulator,
|
|
|
|
time_t emulator_mtime,
|
|
|
|
virCapsGuestMachinePtr **machines,
|
|
|
|
int *nmachines)
|
|
|
|
{
|
|
|
|
virCapsGuestMachinePtr *list;
|
|
|
|
int i;
|
|
|
|
|
2009-10-15 11:09:17 +00:00
|
|
|
if (!info->nmachines)
|
|
|
|
return 0;
|
|
|
|
|
2009-09-07 11:12:42 +00:00
|
|
|
if (!info->emulator || !STREQ(emulator, info->emulator))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (emulator_mtime != info->emulator_mtime) {
|
|
|
|
VIR_DEBUG("mtime on %s has changed, refreshing machine types",
|
|
|
|
info->emulator);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-11-08 21:08:54 +00:00
|
|
|
if (VIR_ALLOC_N(list, info->nmachines) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-09-07 11:12:42 +00:00
|
|
|
return 0;
|
2009-11-08 21:08:54 +00:00
|
|
|
}
|
2009-09-07 11:12:42 +00:00
|
|
|
|
|
|
|
for (i = 0; i < info->nmachines; i++) {
|
|
|
|
if (VIR_ALLOC(list[i]) < 0) {
|
2009-11-08 21:08:54 +00:00
|
|
|
goto no_memory;
|
2009-09-07 11:12:42 +00:00
|
|
|
}
|
|
|
|
if (info->machines[i]->name &&
|
|
|
|
!(list[i]->name = strdup(info->machines[i]->name))) {
|
2009-11-08 21:08:54 +00:00
|
|
|
goto no_memory;
|
2009-09-07 11:12:42 +00:00
|
|
|
}
|
|
|
|
if (info->machines[i]->canonical &&
|
|
|
|
!(list[i]->canonical = strdup(info->machines[i]->canonical))) {
|
2009-11-08 21:08:54 +00:00
|
|
|
goto no_memory;
|
2009-09-07 11:12:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*machines = list;
|
|
|
|
*nmachines = info->nmachines;
|
|
|
|
|
|
|
|
return 1;
|
2009-11-08 21:08:54 +00:00
|
|
|
|
|
|
|
no_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-11-08 21:08:54 +00:00
|
|
|
virCapabilitiesFreeMachines(list, info->nmachines);
|
|
|
|
return 0;
|
2009-09-07 11:12:42 +00:00
|
|
|
}
|
|
|
|
|
2009-07-24 11:34:20 +00:00
|
|
|
static int
|
|
|
|
qemudGetOldMachines(const char *ostype,
|
|
|
|
const char *arch,
|
|
|
|
int wordsize,
|
|
|
|
const char *emulator,
|
|
|
|
time_t emulator_mtime,
|
|
|
|
virCapsPtr old_caps,
|
|
|
|
virCapsGuestMachinePtr **machines,
|
|
|
|
int *nmachines)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < old_caps->nguests; i++) {
|
|
|
|
virCapsGuestPtr guest = old_caps->guests[i];
|
2009-09-07 11:50:36 +00:00
|
|
|
int j;
|
2009-07-24 11:34:20 +00:00
|
|
|
|
|
|
|
if (!STREQ(ostype, guest->ostype) ||
|
|
|
|
!STREQ(arch, guest->arch.name) ||
|
2009-09-07 11:12:42 +00:00
|
|
|
wordsize != guest->arch.wordsize)
|
2009-07-24 11:34:20 +00:00
|
|
|
continue;
|
|
|
|
|
2009-09-07 11:50:36 +00:00
|
|
|
for (j = 0; j < guest->arch.ndomains; j++) {
|
|
|
|
virCapsGuestDomainPtr dom = guest->arch.domains[j];
|
|
|
|
|
|
|
|
if (qemudGetOldMachinesFromInfo(&dom->info,
|
|
|
|
emulator, emulator_mtime,
|
|
|
|
machines, nmachines))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-09-07 11:12:42 +00:00
|
|
|
if (qemudGetOldMachinesFromInfo(&guest->arch.defaultInfo,
|
|
|
|
emulator, emulator_mtime,
|
|
|
|
machines, nmachines))
|
|
|
|
return 1;
|
2009-07-24 11:34:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-12-18 15:24:14 +00:00
|
|
|
|
|
|
|
typedef int
|
|
|
|
(*qemudParseCPUModels)(const char *output,
|
|
|
|
unsigned int *retcount,
|
|
|
|
const char ***retcpus);
|
|
|
|
|
|
|
|
/* Format:
|
|
|
|
* <arch> <model>
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
qemudParseX86Models(const char *output,
|
|
|
|
unsigned int *retcount,
|
|
|
|
const char ***retcpus)
|
|
|
|
{
|
|
|
|
const char *p = output;
|
|
|
|
const char *next;
|
|
|
|
unsigned int count = 0;
|
|
|
|
const char **cpus = NULL;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
do {
|
|
|
|
const char *t;
|
|
|
|
|
|
|
|
if ((next = strchr(p, '\n')))
|
|
|
|
next++;
|
|
|
|
|
|
|
|
if (!(t = strchr(p, ' ')) || (next && t >= next))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!STRPREFIX(p, "x86"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
p = t;
|
|
|
|
while (*p == ' ')
|
|
|
|
p++;
|
|
|
|
|
|
|
|
if (*p == '\0' || *p == '\n')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (retcpus) {
|
|
|
|
if (VIR_REALLOC_N(cpus, count + 1) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (next)
|
|
|
|
cpus[count] = strndup(p, next - p - 1);
|
|
|
|
else
|
|
|
|
cpus[count] = strdup(p);
|
|
|
|
|
|
|
|
if (!cpus[count])
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
count++;
|
|
|
|
} while ((p = next));
|
|
|
|
|
|
|
|
if (retcount)
|
|
|
|
*retcount = count;
|
|
|
|
if (retcpus)
|
|
|
|
*retcpus = cpus;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (cpus) {
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
VIR_FREE(cpus[i]);
|
|
|
|
}
|
|
|
|
VIR_FREE(cpus);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemudProbeCPUModels(const char *qemu,
|
|
|
|
const char *arch,
|
|
|
|
unsigned int *count,
|
|
|
|
const char ***cpus)
|
|
|
|
{
|
|
|
|
const char *const qemuarg[] = { qemu, "-cpu", "?", NULL };
|
|
|
|
const char *const qemuenv[] = { "LC_ALL=C", NULL };
|
|
|
|
enum { MAX_MACHINES_OUTPUT_SIZE = 1024*4 };
|
|
|
|
char *output = NULL;
|
|
|
|
int newstdout = -1;
|
|
|
|
int ret = -1;
|
|
|
|
pid_t child;
|
|
|
|
int status;
|
|
|
|
int len;
|
|
|
|
qemudParseCPUModels parse;
|
|
|
|
|
|
|
|
if (count)
|
|
|
|
*count = 0;
|
|
|
|
if (cpus)
|
|
|
|
*cpus = NULL;
|
|
|
|
|
|
|
|
if (STREQ(arch, "i686") || STREQ(arch, "x86_64"))
|
|
|
|
parse = qemudParseX86Models;
|
|
|
|
else {
|
|
|
|
VIR_DEBUG(_("don't know how to parse %s CPU models"), arch);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-02-04 22:41:52 +00:00
|
|
|
if (virExec(qemuarg, qemuenv, NULL,
|
2009-12-18 15:24:14 +00:00
|
|
|
&child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
len = virFileReadLimFD(newstdout, MAX_MACHINES_OUTPUT_SIZE, &output);
|
|
|
|
if (len < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno, "%s",
|
2009-12-18 15:24:14 +00:00
|
|
|
_("Unable to read QEMU supported CPU models"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parse(output, count, cpus) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-12-18 15:24:14 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(output);
|
|
|
|
if (close(newstdout) < 0)
|
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
rewait:
|
|
|
|
if (waitpid(child, &status, 0) != child) {
|
|
|
|
if (errno == EINTR)
|
|
|
|
goto rewait;
|
|
|
|
|
|
|
|
VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
|
|
|
|
WEXITSTATUS(status), (unsigned long)child);
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
/* Check & log unexpected exit status, but don't fail,
|
|
|
|
* as there's really no need to throw an error if we did
|
|
|
|
* actually read a valid version number above */
|
|
|
|
if (WEXITSTATUS(status) != 0) {
|
|
|
|
VIR_WARN(_("Unexpected exit status '%d', qemu probably failed"),
|
|
|
|
WEXITSTATUS(status));
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
static int
|
|
|
|
qemudCapsInitGuest(virCapsPtr caps,
|
2009-07-24 11:34:20 +00:00
|
|
|
virCapsPtr old_caps,
|
2008-02-27 04:35:08 +00:00
|
|
|
const char *hostmachine,
|
|
|
|
const struct qemu_arch_info *info,
|
|
|
|
int hvm) {
|
|
|
|
virCapsGuestPtr guest;
|
2009-03-20 11:20:26 +00:00
|
|
|
int i;
|
|
|
|
int haskvm = 0;
|
|
|
|
int haskqemu = 0;
|
2010-01-19 23:24:47 +00:00
|
|
|
char *kvmbin = NULL;
|
|
|
|
char *binary = NULL;
|
2009-07-24 11:34:20 +00:00
|
|
|
time_t binary_mtime;
|
2009-07-23 17:31:34 +00:00
|
|
|
virCapsGuestMachinePtr *machines = NULL;
|
2009-07-23 17:31:34 +00:00
|
|
|
int nmachines = 0;
|
2009-07-24 11:34:20 +00:00
|
|
|
struct stat st;
|
2009-12-18 15:24:14 +00:00
|
|
|
unsigned int ncpus;
|
2010-01-19 23:24:47 +00:00
|
|
|
int ret = -1;
|
2008-09-02 15:00:09 +00:00
|
|
|
|
2009-03-20 11:20:26 +00:00
|
|
|
/* Check for existance of base emulator, or alternate base
|
|
|
|
* which can be used with magic cpu choice
|
|
|
|
*/
|
2010-01-19 23:24:47 +00:00
|
|
|
binary = virFindFileInPath(info->binary);
|
|
|
|
|
|
|
|
if (binary == NULL || access(binary, X_OK) != 0) {
|
|
|
|
VIR_FREE(binary);
|
|
|
|
binary = virFindFileInPath(info->altbinary);
|
|
|
|
|
|
|
|
if (binary != NULL && access(binary, X_OK) != 0)
|
|
|
|
VIR_FREE(binary);
|
|
|
|
}
|
2008-09-02 15:00:09 +00:00
|
|
|
|
2009-03-20 11:20:26 +00:00
|
|
|
/* Can use acceleration for KVM/KQEMU if
|
|
|
|
* - host & guest arches match
|
|
|
|
* Or
|
|
|
|
* - hostarch is x86_64 and guest arch is i686
|
|
|
|
* The latter simply needs "-cpu qemu32"
|
|
|
|
*/
|
|
|
|
if (STREQ(info->arch, hostmachine) ||
|
|
|
|
(STREQ(hostmachine, "x86_64") && STREQ(info->arch, "i686"))) {
|
2010-01-19 23:24:47 +00:00
|
|
|
if (access("/dev/kvm", F_OK) == 0) {
|
2010-01-25 15:01:15 +00:00
|
|
|
const char *const kvmbins[] = { "/usr/libexec/qemu-kvm", /* RHEL */
|
|
|
|
"qemu-kvm", /* Fedora */
|
2010-01-19 23:24:47 +00:00
|
|
|
"kvm" }; /* Upstream .spec */
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_CARDINALITY(kvmbins); ++i) {
|
|
|
|
kvmbin = virFindFileInPath(kvmbins[i]);
|
|
|
|
|
|
|
|
if (kvmbin == NULL || access(kvmbin, X_OK) != 0) {
|
|
|
|
VIR_FREE(kvmbin);
|
|
|
|
continue;
|
|
|
|
}
|
2008-09-02 15:00:09 +00:00
|
|
|
|
2009-03-20 11:20:26 +00:00
|
|
|
haskvm = 1;
|
2009-07-23 17:31:34 +00:00
|
|
|
if (!binary)
|
|
|
|
binary = kvmbin;
|
2010-01-19 23:24:47 +00:00
|
|
|
|
2008-09-02 15:00:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-03-20 11:20:26 +00:00
|
|
|
|
|
|
|
if (access("/dev/kqemu", F_OK) == 0)
|
|
|
|
haskqemu = 1;
|
2008-09-02 15:00:09 +00:00
|
|
|
}
|
|
|
|
|
2009-07-23 17:31:34 +00:00
|
|
|
if (!binary)
|
2008-09-02 15:00:09 +00:00
|
|
|
return 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-07-24 11:34:20 +00:00
|
|
|
if (stat(binary, &st) == 0) {
|
|
|
|
binary_mtime = st.st_mtime;
|
|
|
|
} else {
|
|
|
|
char ebuf[1024];
|
|
|
|
VIR_WARN(_("Failed to stat %s, most peculiar : %s"),
|
|
|
|
binary, virStrerror(errno, ebuf, sizeof(ebuf)));
|
|
|
|
binary_mtime = 0;
|
|
|
|
}
|
|
|
|
|
2009-07-23 17:31:34 +00:00
|
|
|
if (info->machine) {
|
2009-07-23 17:31:34 +00:00
|
|
|
virCapsGuestMachinePtr machine;
|
|
|
|
|
2009-11-08 21:08:54 +00:00
|
|
|
if (VIR_ALLOC(machine) < 0) {
|
2010-01-19 23:24:47 +00:00
|
|
|
goto no_memory;
|
2009-11-08 21:08:54 +00:00
|
|
|
}
|
2009-07-23 17:31:34 +00:00
|
|
|
|
2009-07-23 17:31:34 +00:00
|
|
|
if (!(machine->name = strdup(info->machine))) {
|
|
|
|
VIR_FREE(machine);
|
2010-01-19 23:24:47 +00:00
|
|
|
goto no_memory;
|
2009-07-23 17:31:34 +00:00
|
|
|
}
|
2009-07-23 17:31:34 +00:00
|
|
|
|
2010-01-19 21:39:37 +00:00
|
|
|
nmachines = 1;
|
|
|
|
|
2009-07-23 17:31:34 +00:00
|
|
|
if (VIR_ALLOC_N(machines, nmachines) < 0) {
|
2009-07-23 17:31:34 +00:00
|
|
|
VIR_FREE(machine->name);
|
2009-07-23 17:31:34 +00:00
|
|
|
VIR_FREE(machine);
|
2010-01-19 23:24:47 +00:00
|
|
|
goto no_memory;
|
2009-07-23 17:31:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
machines[0] = machine;
|
2009-07-24 11:34:20 +00:00
|
|
|
} else {
|
|
|
|
int probe = 1;
|
|
|
|
if (old_caps && binary_mtime)
|
|
|
|
probe = !qemudGetOldMachines(hvm ? "hvm" : "xen", info->arch,
|
|
|
|
info->wordsize, binary, binary_mtime,
|
|
|
|
old_caps, &machines, &nmachines);
|
|
|
|
if (probe &&
|
|
|
|
qemudProbeMachineTypes(binary, &machines, &nmachines) < 0)
|
2010-01-19 23:24:47 +00:00
|
|
|
goto error;
|
2009-07-24 11:34:20 +00:00
|
|
|
}
|
2009-07-23 17:31:34 +00:00
|
|
|
|
2009-03-20 11:20:26 +00:00
|
|
|
/* We register kvm as the base emulator too, since we can
|
|
|
|
* just give -no-kvm to disable acceleration if required */
|
2008-02-27 04:35:08 +00:00
|
|
|
if ((guest = virCapabilitiesAddGuest(caps,
|
|
|
|
hvm ? "hvm" : "xen",
|
|
|
|
info->arch,
|
|
|
|
info->wordsize,
|
2009-07-23 17:31:34 +00:00
|
|
|
binary,
|
2008-02-27 04:35:08 +00:00
|
|
|
NULL,
|
2009-07-23 17:31:34 +00:00
|
|
|
nmachines,
|
2010-01-19 23:24:47 +00:00
|
|
|
machines)) == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
machines = NULL;
|
|
|
|
nmachines = 0;
|
2009-07-23 17:31:34 +00:00
|
|
|
|
2009-07-24 11:34:20 +00:00
|
|
|
guest->arch.defaultInfo.emulator_mtime = binary_mtime;
|
|
|
|
|
2009-12-18 15:24:14 +00:00
|
|
|
if (qemudProbeCPUModels(binary, info->arch, &ncpus, NULL) == 0
|
|
|
|
&& ncpus > 0
|
|
|
|
&& !virCapabilitiesAddGuestFeature(guest, "cpuselection", 1, 0))
|
2010-01-19 23:24:47 +00:00
|
|
|
goto error;
|
2009-12-18 15:24:14 +00:00
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
if (hvm) {
|
2009-03-20 11:20:26 +00:00
|
|
|
if (virCapabilitiesAddGuestDomain(guest,
|
2008-02-27 04:35:08 +00:00
|
|
|
"qemu",
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL) == NULL)
|
2010-01-19 23:24:47 +00:00
|
|
|
goto error;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-03-20 11:20:26 +00:00
|
|
|
if (haskqemu &&
|
|
|
|
virCapabilitiesAddGuestDomain(guest,
|
|
|
|
"kqemu",
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL) == NULL)
|
2010-01-19 23:24:47 +00:00
|
|
|
goto error;
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2009-09-07 11:52:12 +00:00
|
|
|
if (haskvm) {
|
|
|
|
virCapsGuestDomainPtr dom;
|
|
|
|
|
|
|
|
if (stat(kvmbin, &st) == 0) {
|
|
|
|
binary_mtime = st.st_mtime;
|
|
|
|
} else {
|
|
|
|
char ebuf[1024];
|
|
|
|
VIR_WARN(_("Failed to stat %s, most peculiar : %s"),
|
|
|
|
binary, virStrerror(errno, ebuf, sizeof(ebuf)));
|
|
|
|
binary_mtime = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!STREQ(binary, kvmbin)) {
|
|
|
|
int probe = 1;
|
|
|
|
if (old_caps && binary_mtime)
|
|
|
|
probe = !qemudGetOldMachines("hvm", info->arch, info->wordsize,
|
|
|
|
kvmbin, binary_mtime,
|
|
|
|
old_caps, &machines, &nmachines);
|
|
|
|
if (probe &&
|
|
|
|
qemudProbeMachineTypes(kvmbin, &machines, &nmachines) < 0)
|
2010-01-19 23:24:47 +00:00
|
|
|
goto error;
|
2009-09-07 11:52:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((dom = virCapabilitiesAddGuestDomain(guest,
|
|
|
|
"kvm",
|
|
|
|
kvmbin,
|
|
|
|
NULL,
|
|
|
|
nmachines,
|
|
|
|
machines)) == NULL) {
|
2010-01-19 23:24:47 +00:00
|
|
|
goto error;
|
2009-09-07 11:52:12 +00:00
|
|
|
}
|
|
|
|
|
2010-01-19 23:24:47 +00:00
|
|
|
machines = NULL;
|
|
|
|
nmachines = 0;
|
|
|
|
|
2009-09-07 11:52:12 +00:00
|
|
|
dom->info.emulator_mtime = binary_mtime;
|
|
|
|
}
|
2008-02-27 04:35:08 +00:00
|
|
|
} else {
|
|
|
|
if (virCapabilitiesAddGuestDomain(guest,
|
|
|
|
"kvm",
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL) == NULL)
|
2010-01-19 23:24:47 +00:00
|
|
|
goto error;
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
if (info->nflags) {
|
|
|
|
for (i = 0 ; i < info->nflags ; i++) {
|
|
|
|
if (virCapabilitiesAddGuestFeature(guest,
|
|
|
|
info->flags[i].name,
|
|
|
|
info->flags[i].default_on,
|
|
|
|
info->flags[i].toggle) == NULL)
|
2010-01-19 23:24:47 +00:00
|
|
|
goto error;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-19 23:24:47 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (binary == kvmbin) {
|
|
|
|
/* don't double free */
|
|
|
|
VIR_FREE(binary);
|
|
|
|
} else {
|
|
|
|
VIR_FREE(binary);
|
|
|
|
VIR_FREE(kvmbin);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
no_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-01-19 23:24:47 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
virCapabilitiesFreeMachines(machines, nmachines);
|
|
|
|
|
|
|
|
goto cleanup;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2009-12-18 15:24:14 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
qemudCapsInitCPU(virCapsPtr caps,
|
|
|
|
const char *arch)
|
|
|
|
{
|
|
|
|
virCPUDefPtr cpu = NULL;
|
|
|
|
union cpuData *data = NULL;
|
|
|
|
virNodeInfo nodeinfo;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(cpu) < 0
|
|
|
|
|| !(cpu->arch = strdup(arch))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-12-18 15:24:14 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nodeGetInfo(NULL, &nodeinfo))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
cpu->type = VIR_CPU_TYPE_HOST;
|
|
|
|
cpu->sockets = nodeinfo.sockets;
|
|
|
|
cpu->cores = nodeinfo.cores;
|
|
|
|
cpu->threads = nodeinfo.threads;
|
|
|
|
|
2010-02-10 12:22:36 +00:00
|
|
|
if (!(data = cpuNodeData(arch))
|
2010-02-11 09:47:43 +00:00
|
|
|
|| cpuDecode(cpu, data, NULL, 0) < 0)
|
2009-12-18 15:24:14 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
caps->host.cpu = cpu;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
2010-02-10 12:22:36 +00:00
|
|
|
cpuDataFree(arch, data);
|
2009-12-18 15:24:14 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virCPUDefFree(cpu);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-24 11:34:20 +00:00
|
|
|
virCapsPtr qemudCapsInit(virCapsPtr old_caps) {
|
2008-02-27 04:35:08 +00:00
|
|
|
struct utsname utsname;
|
|
|
|
virCapsPtr caps;
|
|
|
|
int i;
|
2010-01-19 23:24:47 +00:00
|
|
|
char *xenner = NULL;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
/* Really, this never fails - look at the man-page. */
|
|
|
|
uname (&utsname);
|
|
|
|
|
|
|
|
if ((caps = virCapabilitiesNew(utsname.machine,
|
2009-05-18 15:10:51 +00:00
|
|
|
1, 1)) == NULL)
|
2008-02-27 04:35:08 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2008-10-24 11:20:08 +00:00
|
|
|
/* Using KVM's mac prefix for QEMU too */
|
|
|
|
virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x52, 0x54, 0x00 });
|
|
|
|
|
2009-06-29 10:41:56 +00:00
|
|
|
/* Some machines have problematic NUMA toplogy causing
|
|
|
|
* unexpected failures. We don't want to break the QEMU
|
|
|
|
* driver in this scenario, so log errors & carry on
|
|
|
|
*/
|
|
|
|
if (nodeCapsInitNUMA(caps) < 0) {
|
|
|
|
virCapabilitiesFreeNUMAInfo(caps);
|
|
|
|
VIR_WARN0("Failed to query host NUMA topology, disabling NUMA capabilities");
|
|
|
|
}
|
2008-05-22 15:29:50 +00:00
|
|
|
|
2009-12-18 15:24:14 +00:00
|
|
|
if (old_caps == NULL || old_caps->host.cpu == NULL) {
|
|
|
|
if (qemudCapsInitCPU(caps, utsname.machine) < 0)
|
|
|
|
VIR_WARN0("Failed to get host CPU");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
caps->host.cpu = old_caps->host.cpu;
|
|
|
|
old_caps->host.cpu = NULL;
|
|
|
|
}
|
|
|
|
|
2009-05-18 15:10:51 +00:00
|
|
|
virCapabilitiesAddHostMigrateTransport(caps,
|
|
|
|
"tcp");
|
|
|
|
|
2009-03-20 11:20:26 +00:00
|
|
|
/* First the pure HVM guests */
|
2008-10-28 17:43:24 +00:00
|
|
|
for (i = 0 ; i < ARRAY_CARDINALITY(arch_info_hvm) ; i++)
|
2009-07-24 11:34:20 +00:00
|
|
|
if (qemudCapsInitGuest(caps, old_caps,
|
2008-02-27 04:35:08 +00:00
|
|
|
utsname.machine,
|
|
|
|
&arch_info_hvm[i], 1) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
2009-03-20 11:20:26 +00:00
|
|
|
/* Then possibly the Xen paravirt guests (ie Xenner */
|
2010-01-19 23:24:47 +00:00
|
|
|
xenner = virFindFileInPath("xenner");
|
|
|
|
|
|
|
|
if (xenner != NULL && access(xenner, X_OK) == 0 &&
|
2008-02-27 04:35:08 +00:00
|
|
|
access("/dev/kvm", F_OK) == 0) {
|
2008-10-28 17:43:24 +00:00
|
|
|
for (i = 0 ; i < ARRAY_CARDINALITY(arch_info_xen) ; i++)
|
2008-02-27 04:35:08 +00:00
|
|
|
/* Allow Xen 32-on-32, 32-on-64 and 64-on-64 */
|
|
|
|
if (STREQ(arch_info_xen[i].arch, utsname.machine) ||
|
|
|
|
(STREQ(utsname.machine, "x86_64") &&
|
|
|
|
STREQ(arch_info_xen[i].arch, "i686"))) {
|
2009-07-24 11:34:20 +00:00
|
|
|
if (qemudCapsInitGuest(caps, old_caps,
|
2008-02-27 04:35:08 +00:00
|
|
|
utsname.machine,
|
|
|
|
&arch_info_xen[i], 0) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2010-01-19 23:24:47 +00:00
|
|
|
VIR_FREE(xenner);
|
|
|
|
|
2009-06-16 15:27:33 +00:00
|
|
|
/* QEMU Requires an emulator in the XML */
|
|
|
|
virCapabilitiesSetEmulatorRequired(caps);
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
return caps;
|
|
|
|
|
|
|
|
no_memory:
|
2010-01-19 23:24:47 +00:00
|
|
|
VIR_FREE(xenner);
|
2008-02-27 04:35:08 +00:00
|
|
|
virCapabilitiesFree(caps);
|
|
|
|
return NULL;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2010-02-09 13:06:56 +00:00
|
|
|
static unsigned long long qemudComputeCmdFlags(const char *help,
|
|
|
|
unsigned int version,
|
|
|
|
unsigned int is_kvm,
|
|
|
|
unsigned int kvm_version)
|
2009-06-11 14:12:30 +00:00
|
|
|
{
|
2010-02-09 13:06:56 +00:00
|
|
|
unsigned long long flags = 0;
|
2008-08-29 07:11:15 +00:00
|
|
|
|
|
|
|
if (strstr(help, "-no-kqemu"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_KQEMU;
|
2009-03-20 11:20:26 +00:00
|
|
|
if (strstr(help, "-no-kvm"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_KVM;
|
2009-11-20 14:41:05 +00:00
|
|
|
if (strstr(help, "-enable-kvm"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_ENABLE_KVM;
|
2008-08-29 07:11:15 +00:00
|
|
|
if (strstr(help, "-no-reboot"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_NO_REBOOT;
|
|
|
|
if (strstr(help, "-name"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_NAME;
|
2008-11-04 22:15:30 +00:00
|
|
|
if (strstr(help, "-uuid"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_UUID;
|
2009-08-25 13:17:29 +00:00
|
|
|
if (strstr(help, "-xen-domid"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_XEN_DOMID;
|
|
|
|
else if (strstr(help, "-domid"))
|
2008-11-04 22:15:30 +00:00
|
|
|
flags |= QEMUD_CMD_FLAG_DOMID;
|
2009-01-30 17:15:39 +00:00
|
|
|
if (strstr(help, "-drive")) {
|
2008-08-29 07:11:15 +00:00
|
|
|
flags |= QEMUD_CMD_FLAG_DRIVE;
|
2009-01-30 17:15:39 +00:00
|
|
|
if (strstr(help, "cache=writethrough|writeback|none"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_DRIVE_CACHE_V2;
|
2009-06-16 15:17:10 +00:00
|
|
|
if (strstr(help, "format="))
|
|
|
|
flags |= QEMUD_CMD_FLAG_DRIVE_FORMAT;
|
2009-01-30 17:15:39 +00:00
|
|
|
}
|
2009-07-06 13:59:19 +00:00
|
|
|
if (strstr(help, "-vga") && !strstr(help, "-std-vga"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_VGA;
|
2008-08-29 07:11:15 +00:00
|
|
|
if (strstr(help, "boot=on"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_DRIVE_BOOT;
|
2009-08-14 11:22:01 +00:00
|
|
|
if (strstr(help, "serial=s"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_DRIVE_SERIAL;
|
2009-08-14 07:31:11 +00:00
|
|
|
if (strstr(help, "-pcidevice"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_PCIDEVICE;
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 14:05:18 +00:00
|
|
|
if (strstr(help, "-mem-path"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_MEM_PATH;
|
2009-11-05 13:41:24 +00:00
|
|
|
if (strstr(help, "-chardev"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_CHARDEV;
|
2010-01-06 17:01:51 +00:00
|
|
|
if (strstr(help, "-balloon"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_BALLOON;
|
2009-12-21 20:36:32 +00:00
|
|
|
if (strstr(help, "-device"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_DEVICE;
|
2010-02-02 18:07:12 +00:00
|
|
|
/* The trailing ' ' is important to avoid a bogus match */
|
|
|
|
if (strstr(help, "-rtc "))
|
|
|
|
flags |= QEMUD_CMD_FLAG_RTC;
|
2010-01-29 18:07:04 +00:00
|
|
|
/* Keep disabled till we're actually ready to turn on netdev mode
|
|
|
|
* The plan is todo it in 0.13.0 QEMU, but lets wait & see... */
|
|
|
|
#if 0
|
|
|
|
if (strstr(help, "-netdev")) {
|
|
|
|
/* Disable -netdev on 0.12 since although it exists,
|
|
|
|
* the corresponding netdev_add/remove monitor commands
|
|
|
|
* do not, and we need them to be able todo hotplug */
|
|
|
|
if (version >= 13000)
|
|
|
|
flags |= QEMUD_CMD_FLAG_NETDEV;
|
|
|
|
}
|
|
|
|
#endif
|
2009-12-21 20:23:55 +00:00
|
|
|
if (strstr(help, "-sdl"))
|
|
|
|
flags |= QEMUD_CMD_FLAG_SDL;
|
2010-01-18 15:51:52 +00:00
|
|
|
if (strstr(help, "cores=") &&
|
|
|
|
strstr(help, "threads=") &&
|
|
|
|
strstr(help, "sockets="))
|
|
|
|
flags |= QEMUD_CMD_FLAG_SMP_TOPOLOGY;
|
2009-08-14 07:31:11 +00:00
|
|
|
|
2008-08-29 07:11:15 +00:00
|
|
|
if (version >= 9000)
|
|
|
|
flags |= QEMUD_CMD_FLAG_VNC_COLON;
|
2009-06-11 14:15:49 +00:00
|
|
|
|
|
|
|
if (is_kvm && (version >= 10000 || kvm_version >= 74))
|
2009-01-27 11:12:05 +00:00
|
|
|
flags |= QEMUD_CMD_FLAG_VNET_HDR;
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2009-01-29 17:27:54 +00:00
|
|
|
/*
|
|
|
|
* Handling of -incoming arg with varying features
|
2009-05-08 10:07:15 +00:00
|
|
|
* -incoming tcp (kvm >= 79, qemu >= 0.10.0)
|
|
|
|
* -incoming exec (kvm >= 80, qemu >= 0.10.0)
|
2009-01-29 17:27:54 +00:00
|
|
|
* -incoming stdio (all earlier kvm)
|
|
|
|
*
|
|
|
|
* NB, there was a pre-kvm-79 'tcp' support, but it
|
|
|
|
* was broken, because it blocked the monitor console
|
|
|
|
* while waiting for data, so pretend it doesn't exist
|
|
|
|
*/
|
2009-06-11 14:15:49 +00:00
|
|
|
if (version >= 10000) {
|
|
|
|
flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP;
|
|
|
|
flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC;
|
2009-09-30 10:52:34 +00:00
|
|
|
if (version >= 12000)
|
|
|
|
flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX;
|
2009-06-11 14:15:49 +00:00
|
|
|
} else if (kvm_version >= 79) {
|
2009-01-29 17:27:54 +00:00
|
|
|
flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP;
|
|
|
|
if (kvm_version >= 80)
|
|
|
|
flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC;
|
|
|
|
} else if (kvm_version > 0) {
|
|
|
|
flags |= QEMUD_CMD_FLAG_MIGRATE_KVM_STDIO;
|
|
|
|
}
|
|
|
|
|
2009-07-17 21:08:33 +00:00
|
|
|
if (version >= 10000)
|
|
|
|
flags |= QEMUD_CMD_FLAG_0_10;
|
|
|
|
|
2009-12-21 20:49:43 +00:00
|
|
|
/* Keep disabled till we're actually ready to turn on JSON mode
|
|
|
|
* The plan is todo it in 0.13.0 QEMU, but lets wait & see... */
|
|
|
|
#if 0
|
|
|
|
if (version >= 13000)
|
|
|
|
flags |= QEMUD_CMD_FLAG_MONITOR_JSON;
|
|
|
|
#endif
|
2009-11-03 18:59:18 +00:00
|
|
|
|
2009-06-11 14:12:30 +00:00
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We parse the output of 'qemu -help' to get the QEMU
|
|
|
|
* version number. The first bit is easy, just parse
|
|
|
|
* 'QEMU PC emulator version x.y.z'.
|
|
|
|
*
|
2009-06-11 14:15:49 +00:00
|
|
|
* With qemu-kvm, however, that is followed by a string
|
|
|
|
* in parenthesis as follows:
|
|
|
|
* - qemu-kvm-x.y.z in stable releases
|
|
|
|
* - kvm-XX for kvm versions up to kvm-85
|
|
|
|
* - qemu-kvm-devel-XX for kvm version kvm-86 and later
|
|
|
|
*
|
|
|
|
* For qemu-kvm versions before 0.10.z, we need to detect
|
|
|
|
* the KVM version number for some features. With 0.10.z
|
|
|
|
* and later, we just need the QEMU version number and
|
|
|
|
* whether it is KVM QEMU or mainline QEMU.
|
2009-06-11 14:12:30 +00:00
|
|
|
*/
|
|
|
|
#define QEMU_VERSION_STR "QEMU PC emulator version"
|
2009-06-11 14:15:49 +00:00
|
|
|
#define QEMU_KVM_VER_PREFIX "(qemu-kvm-"
|
2009-06-11 14:12:30 +00:00
|
|
|
#define KVM_VER_PREFIX "(kvm-"
|
|
|
|
|
|
|
|
#define SKIP_BLANKS(p) do { while ((*(p) == ' ') || (*(p) == '\t')) (p)++; } while (0)
|
|
|
|
|
2010-02-24 16:44:36 +00:00
|
|
|
int qemudParseHelpStr(const char *qemu,
|
|
|
|
const char *help,
|
2010-02-09 13:06:56 +00:00
|
|
|
unsigned long long *flags,
|
2009-06-11 14:17:42 +00:00
|
|
|
unsigned int *version,
|
|
|
|
unsigned int *is_kvm,
|
|
|
|
unsigned int *kvm_version)
|
2009-06-11 14:12:30 +00:00
|
|
|
{
|
|
|
|
unsigned major, minor, micro;
|
|
|
|
const char *p = help;
|
|
|
|
|
2009-06-11 14:15:49 +00:00
|
|
|
*flags = *version = *is_kvm = *kvm_version = 0;
|
2009-06-11 14:12:30 +00:00
|
|
|
|
|
|
|
if (!STRPREFIX(p, QEMU_VERSION_STR))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
p += strlen(QEMU_VERSION_STR);
|
|
|
|
|
|
|
|
SKIP_BLANKS(p);
|
|
|
|
|
|
|
|
major = virParseNumber(&p);
|
|
|
|
if (major == -1 || *p != '.')
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
++p;
|
|
|
|
|
|
|
|
minor = virParseNumber(&p);
|
|
|
|
if (major == -1 || *p != '.')
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
++p;
|
|
|
|
|
|
|
|
micro = virParseNumber(&p);
|
|
|
|
if (major == -1)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
SKIP_BLANKS(p);
|
|
|
|
|
2009-06-11 14:15:49 +00:00
|
|
|
if (STRPREFIX(p, QEMU_KVM_VER_PREFIX)) {
|
|
|
|
*is_kvm = 1;
|
|
|
|
p += strlen(QEMU_KVM_VER_PREFIX);
|
|
|
|
} else if (STRPREFIX(p, KVM_VER_PREFIX)) {
|
2009-06-11 14:12:30 +00:00
|
|
|
int ret;
|
|
|
|
|
2009-06-11 14:15:49 +00:00
|
|
|
*is_kvm = 1;
|
2009-06-11 14:12:30 +00:00
|
|
|
p += strlen(KVM_VER_PREFIX);
|
|
|
|
|
|
|
|
ret = virParseNumber(&p);
|
|
|
|
if (ret == -1)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
*kvm_version = ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
*version = (major * 1000 * 1000) + (minor * 1000) + micro;
|
|
|
|
|
2009-06-11 14:15:49 +00:00
|
|
|
*flags = qemudComputeCmdFlags(help, *version, *is_kvm, *kvm_version);
|
2009-06-11 14:12:30 +00:00
|
|
|
|
|
|
|
qemudDebug("Version %u.%u.%u, cooked version %u, flags %u",
|
|
|
|
major, minor, micro, *version, *flags);
|
|
|
|
if (*kvm_version)
|
2009-06-11 14:15:49 +00:00
|
|
|
qemudDebug("KVM version %d detected", *kvm_version);
|
|
|
|
else if (*is_kvm)
|
|
|
|
qemudDebug("qemu-kvm version %u.%u.%u detected", major, minor, micro);
|
2009-06-11 14:12:30 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
p = strchr(help, '\n');
|
|
|
|
if (p)
|
|
|
|
p = strndup(help, p - help);
|
|
|
|
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
2010-02-24 16:44:36 +00:00
|
|
|
_("cannot parse %s version number in '%s'"),
|
|
|
|
qemu, p ? p : help);
|
2009-06-11 14:12:30 +00:00
|
|
|
|
|
|
|
VIR_FREE(p);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int qemudExtractVersionInfo(const char *qemu,
|
|
|
|
unsigned int *retversion,
|
2010-02-09 13:06:56 +00:00
|
|
|
unsigned long long *retflags) {
|
2009-06-11 14:12:30 +00:00
|
|
|
const char *const qemuarg[] = { qemu, "-help", NULL };
|
|
|
|
const char *const qemuenv[] = { "LC_ALL=C", NULL };
|
|
|
|
pid_t child;
|
|
|
|
int newstdout = -1;
|
|
|
|
int ret = -1, status;
|
2009-06-11 14:15:49 +00:00
|
|
|
unsigned int version, is_kvm, kvm_version;
|
2010-02-09 13:06:56 +00:00
|
|
|
unsigned long long flags = 0;
|
2009-06-11 14:12:30 +00:00
|
|
|
|
|
|
|
if (retflags)
|
|
|
|
*retflags = 0;
|
|
|
|
if (retversion)
|
|
|
|
*retversion = 0;
|
|
|
|
|
2010-02-04 22:41:52 +00:00
|
|
|
if (virExec(qemuarg, qemuenv, NULL,
|
2009-06-29 17:00:52 +00:00
|
|
|
&child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
|
2009-06-11 14:12:30 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
char *help = NULL;
|
|
|
|
enum { MAX_HELP_OUTPUT_SIZE = 1024*64 };
|
|
|
|
int len = virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help);
|
|
|
|
if (len < 0) {
|
2010-02-24 16:44:36 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to read %s help output"), qemu);
|
2009-06-11 14:12:30 +00:00
|
|
|
goto cleanup2;
|
|
|
|
}
|
|
|
|
|
2010-02-24 16:44:36 +00:00
|
|
|
if (qemudParseHelpStr(qemu, help, &flags,
|
|
|
|
&version, &is_kvm, &kvm_version) == -1)
|
2009-06-11 14:12:30 +00:00
|
|
|
goto cleanup2;
|
|
|
|
|
2008-08-29 07:11:15 +00:00
|
|
|
if (retversion)
|
|
|
|
*retversion = version;
|
|
|
|
if (retflags)
|
|
|
|
*retflags = flags;
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2008-08-29 07:11:15 +00:00
|
|
|
ret = 0;
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2008-08-29 07:11:15 +00:00
|
|
|
cleanup2:
|
2008-09-02 10:30:40 +00:00
|
|
|
VIR_FREE(help);
|
2008-08-29 07:11:15 +00:00
|
|
|
if (close(newstdout) < 0)
|
|
|
|
ret = -1;
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2008-08-29 07:11:15 +00:00
|
|
|
rewait:
|
|
|
|
if (waitpid(child, &status, 0) != child) {
|
|
|
|
if (errno == EINTR)
|
|
|
|
goto rewait;
|
|
|
|
|
2009-03-03 11:40:08 +00:00
|
|
|
VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
|
|
|
|
WEXITSTATUS(status), (unsigned long)child);
|
2008-08-29 07:11:15 +00:00
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
/* Check & log unexpected exit status, but don't fail,
|
|
|
|
* as there's really no need to throw an error if we did
|
|
|
|
* actually read a valid version number above */
|
|
|
|
if (WEXITSTATUS(status) != 0) {
|
2009-03-03 11:40:08 +00:00
|
|
|
VIR_WARN(_("Unexpected exit status '%d', qemu probably failed"),
|
2008-08-29 07:11:15 +00:00
|
|
|
WEXITSTATUS(status));
|
2007-02-23 17:15:18 +00:00
|
|
|
}
|
2008-08-29 07:11:15 +00:00
|
|
|
|
|
|
|
return ret;
|
2007-02-23 17:15:18 +00:00
|
|
|
}
|
|
|
|
|
2009-01-30 19:57:20 +00:00
|
|
|
static void
|
|
|
|
uname_normalize (struct utsname *ut)
|
|
|
|
{
|
|
|
|
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';
|
|
|
|
}
|
|
|
|
|
2010-02-04 20:02:58 +00:00
|
|
|
int qemudExtractVersion(struct qemud_driver *driver) {
|
2008-02-27 04:35:08 +00:00
|
|
|
const char *binary;
|
2007-04-16 13:14:28 +00:00
|
|
|
struct stat sb;
|
2009-01-30 19:57:20 +00:00
|
|
|
struct utsname ut;
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if (driver->qemuVersion > 0)
|
2007-02-23 17:15:18 +00:00
|
|
|
return 0;
|
|
|
|
|
2009-01-30 19:57:20 +00:00
|
|
|
uname_normalize(&ut);
|
2008-02-27 04:35:08 +00:00
|
|
|
if ((binary = virCapabilitiesDefaultGuestEmulator(driver->caps,
|
|
|
|
"hvm",
|
2009-01-30 19:57:20 +00:00
|
|
|
ut.machine,
|
2008-07-11 19:34:11 +00:00
|
|
|
"qemu")) == NULL)
|
|
|
|
return -1;
|
2007-07-18 21:08:22 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (stat(binary, &sb) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-10-27 16:20:22 +00:00
|
|
|
_("Cannot find QEMU binary %s"), binary);
|
2008-07-11 19:34:11 +00:00
|
|
|
return -1;
|
2007-07-18 21:08:22 +00:00
|
|
|
}
|
|
|
|
|
2008-08-29 07:11:15 +00:00
|
|
|
if (qemudExtractVersionInfo(binary, &driver->qemuVersion, NULL) < 0) {
|
2008-07-11 19:34:11 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
return 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2010-02-15 16:41:14 +00:00
|
|
|
/**
|
|
|
|
* qemudPhysIfaceConnect:
|
|
|
|
* @conn: pointer to virConnect object
|
|
|
|
* @net: pointer to he VM's interface description with direct device type
|
|
|
|
* @linkdev: The name of the physical interface to link the macvtap to
|
|
|
|
* @brmode: The mode to put the macvtap device into
|
|
|
|
*
|
|
|
|
* Returns a filedescriptor on success or -1 in case of error.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
qemudPhysIfaceConnect(virConnectPtr conn,
|
2010-02-19 14:41:30 +00:00
|
|
|
struct qemud_driver *driver,
|
2010-02-15 16:41:14 +00:00
|
|
|
virDomainNetDefPtr net,
|
|
|
|
char *linkdev,
|
2010-02-19 10:38:57 +00:00
|
|
|
int brmode,
|
|
|
|
unsigned long long qemuCmdFlags)
|
2010-02-15 16:41:14 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
#if WITH_MACVTAP
|
|
|
|
char *res_ifname = NULL;
|
2010-02-19 10:38:57 +00:00
|
|
|
int vnet_hdr = 0;
|
2010-02-19 14:41:30 +00:00
|
|
|
int err;
|
2010-02-19 10:38:57 +00:00
|
|
|
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_VNET_HDR &&
|
|
|
|
net->model && STREQ(net->model, "virtio"))
|
|
|
|
vnet_hdr = 1;
|
2010-02-15 16:41:14 +00:00
|
|
|
|
|
|
|
rc = openMacvtapTap(conn, net->ifname, net->mac, linkdev, brmode,
|
2010-02-19 10:38:57 +00:00
|
|
|
&res_ifname, vnet_hdr);
|
2010-02-15 16:41:14 +00:00
|
|
|
if (rc >= 0) {
|
|
|
|
VIR_FREE(net->ifname);
|
|
|
|
net->ifname = res_ifname;
|
|
|
|
}
|
2010-02-19 14:41:30 +00:00
|
|
|
|
|
|
|
if (rc >=0 && driver->macFilter) {
|
|
|
|
if ((err = networkAllowMacOnPort(driver, net->ifname, net->mac))) {
|
|
|
|
virReportSystemError(err,
|
|
|
|
_("failed to add ebtables rule to allow MAC address on '%s'"),
|
|
|
|
net->ifname);
|
|
|
|
}
|
|
|
|
}
|
2010-02-15 16:41:14 +00:00
|
|
|
#else
|
|
|
|
(void)conn;
|
|
|
|
(void)net;
|
|
|
|
(void)linkdev;
|
|
|
|
(void)brmode;
|
2010-02-19 10:38:57 +00:00
|
|
|
(void)qemuCmdFlags;
|
2010-02-19 14:41:30 +00:00
|
|
|
(void)driver;
|
2010-02-15 16:41:14 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("No support for macvtap device"));
|
|
|
|
rc = -1;
|
|
|
|
#endif
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-07-22 19:17:13 +00:00
|
|
|
int
|
2007-07-12 15:09:01 +00:00
|
|
|
qemudNetworkIfaceConnect(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2008-07-11 19:34:11 +00:00
|
|
|
virDomainNetDefPtr net,
|
2010-02-09 13:06:56 +00:00
|
|
|
unsigned long long qemuCmdFlags)
|
2007-02-14 16:09:37 +00:00
|
|
|
{
|
2009-09-04 13:56:32 +00:00
|
|
|
char *brname = NULL;
|
2007-02-14 16:09:37 +00:00
|
|
|
int err;
|
|
|
|
int tapfd = -1;
|
2009-07-22 19:17:13 +00:00
|
|
|
int vnet_hdr = 0;
|
2009-08-18 12:32:42 +00:00
|
|
|
int template_ifname = 0;
|
2007-02-14 16:09:37 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
|
2010-02-16 18:11:27 +00:00
|
|
|
int active, fail = 0;
|
|
|
|
virErrorPtr errobj;
|
2008-10-10 13:57:13 +00:00
|
|
|
virNetworkPtr network = virNetworkLookupByName(conn,
|
2010-02-16 18:11:27 +00:00
|
|
|
net->data.network.name);
|
2009-07-17 21:08:33 +00:00
|
|
|
if (!network)
|
|
|
|
return -1;
|
|
|
|
|
2010-02-16 18:11:27 +00:00
|
|
|
active = virNetworkIsActive(network);
|
|
|
|
if (active != 1) {
|
|
|
|
fail = 1;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2010-02-16 18:11:27 +00:00
|
|
|
if (active == 0)
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Network '%s' is not active."),
|
|
|
|
net->data.network.name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!fail) {
|
|
|
|
brname = virNetworkGetBridgeName(network);
|
|
|
|
if (brname == NULL)
|
|
|
|
fail = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure any above failure is preserved */
|
|
|
|
errobj = virSaveLastError();
|
2008-10-10 13:57:13 +00:00
|
|
|
virNetworkFree(network);
|
2010-02-16 18:11:27 +00:00
|
|
|
virSetError(errobj);
|
|
|
|
virFreeError(errobj);
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2010-02-16 18:11:27 +00:00
|
|
|
if (fail)
|
2009-07-17 21:08:33 +00:00
|
|
|
return -1;
|
2010-02-16 18:11:27 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
} else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
|
2009-11-08 21:08:54 +00:00
|
|
|
if (!(brname = strdup(net->data.bridge.brname))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-11-08 21:08:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-03-13 22:43:22 +00:00
|
|
|
} else {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Network type %d is not supported"), net->type);
|
2009-07-17 21:08:33 +00:00
|
|
|
return -1;
|
2007-02-14 16:09:37 +00:00
|
|
|
}
|
|
|
|
|
2009-08-18 12:32:42 +00:00
|
|
|
if (!driver->brctl && (err = brInit(&driver->brctl))) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(err, "%s",
|
2009-08-18 13:15:58 +00:00
|
|
|
_("cannot initialize bridge support"));
|
2009-09-04 13:56:32 +00:00
|
|
|
goto cleanup;
|
2009-08-18 12:32:42 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (!net->ifname ||
|
|
|
|
STRPREFIX(net->ifname, "vnet") ||
|
|
|
|
strchr(net->ifname, '%')) {
|
|
|
|
VIR_FREE(net->ifname);
|
|
|
|
if (!(net->ifname = strdup("vnet%d"))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-09-04 13:56:32 +00:00
|
|
|
goto cleanup;
|
2008-07-11 19:34:11 +00:00
|
|
|
}
|
2009-08-18 12:32:42 +00:00
|
|
|
/* avoid exposing vnet%d in dumpxml or error outputs */
|
|
|
|
template_ifname = 1;
|
2007-05-14 15:41:57 +00:00
|
|
|
}
|
|
|
|
|
2009-07-22 19:17:13 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_VNET_HDR &&
|
|
|
|
net->model && STREQ(net->model, "virtio"))
|
|
|
|
vnet_hdr = 1;
|
|
|
|
|
2007-06-26 22:13:21 +00:00
|
|
|
if ((err = brAddTap(driver->brctl, brname,
|
2009-01-27 11:12:05 +00:00
|
|
|
&net->ifname, vnet_hdr, &tapfd))) {
|
2008-07-09 05:24:08 +00:00
|
|
|
if (errno == ENOTSUP) {
|
|
|
|
/* In this particular case, give a better diagnostic. */
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Failed to add tap interface to bridge. "
|
|
|
|
"%s is not a bridge device"), brname);
|
2009-08-18 12:32:42 +00:00
|
|
|
} else if (template_ifname) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(err,
|
2009-08-18 13:15:58 +00:00
|
|
|
_("Failed to add tap interface to bridge '%s'"),
|
|
|
|
brname);
|
2008-07-09 05:24:08 +00:00
|
|
|
} else {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(err,
|
2009-08-18 13:15:58 +00:00
|
|
|
_("Failed to add tap interface '%s' to bridge '%s'"),
|
|
|
|
net->ifname, brname);
|
2008-07-09 05:24:08 +00:00
|
|
|
}
|
2009-08-18 12:32:42 +00:00
|
|
|
if (template_ifname)
|
|
|
|
VIR_FREE(net->ifname);
|
2009-09-04 13:56:32 +00:00
|
|
|
tapfd = -1;
|
2007-02-14 16:09:37 +00:00
|
|
|
}
|
|
|
|
|
2009-11-03 22:41:23 +00:00
|
|
|
if (driver->macFilter) {
|
2010-02-04 20:02:58 +00:00
|
|
|
if ((err = networkAllowMacOnPort(driver, net->ifname, net->mac))) {
|
|
|
|
virReportSystemError(err,
|
2009-11-03 22:41:23 +00:00
|
|
|
_("failed to add ebtables rule to allow MAC address on '%s'"),
|
|
|
|
net->ifname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-04 13:56:32 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(brname);
|
|
|
|
|
2009-07-17 21:08:33 +00:00
|
|
|
return tapfd;
|
2007-02-14 16:09:37 +00:00
|
|
|
}
|
|
|
|
|
2010-01-06 12:11:26 +00:00
|
|
|
|
2010-02-01 15:06:36 +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");
|
|
|
|
}
|
|
|
|
|
2010-02-01 15:58:38 +00:00
|
|
|
|
|
|
|
/* Names used before -drive existed */
|
|
|
|
static int qemuAssignDeviceDiskAliasLegacy(virDomainDiskDefPtr disk)
|
|
|
|
{
|
|
|
|
char *devname;
|
|
|
|
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
|
|
|
|
STREQ(disk->dst, "hdc"))
|
|
|
|
devname = strdup("cdrom");
|
|
|
|
else
|
|
|
|
devname = strdup(disk->dst);
|
|
|
|
|
|
|
|
if (!devname) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-02-01 15:58:38 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
disk->info.alias = devname;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Names used before -drive supported the id= option */
|
|
|
|
static int qemuAssignDeviceDiskAliasFixed(virDomainDiskDefPtr disk)
|
|
|
|
{
|
|
|
|
int busid, devid;
|
|
|
|
int ret;
|
|
|
|
char *devname;
|
|
|
|
|
|
|
|
if (virDiskNameToBusDeviceIndex(disk, &busid, &devid) < 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot convert disk '%s' to bus/device index"),
|
|
|
|
disk->dst);
|
2010-02-01 15:58:38 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (disk->bus) {
|
|
|
|
case VIR_DOMAIN_DISK_BUS_IDE:
|
|
|
|
if (disk->device== VIR_DOMAIN_DISK_DEVICE_DISK)
|
|
|
|
ret = virAsprintf(&devname, "ide%d-hd%d", busid, devid);
|
|
|
|
else
|
|
|
|
ret = virAsprintf(&devname, "ide%d-cd%d", busid, devid);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_BUS_SCSI:
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK)
|
|
|
|
ret = virAsprintf(&devname, "scsi%d-hd%d", busid, devid);
|
|
|
|
else
|
|
|
|
ret = virAsprintf(&devname, "scsi%d-cd%d", busid, devid);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_BUS_FDC:
|
|
|
|
ret = virAsprintf(&devname, "floppy%d", devid);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_BUS_VIRTIO:
|
|
|
|
ret = virAsprintf(&devname, "virtio%d", devid);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_BUS_XEN:
|
|
|
|
ret = virAsprintf(&devname, "xenblk%d", devid);
|
|
|
|
break;
|
|
|
|
default:
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
_("Unsupported disk name mapping for bus '%s'"),
|
|
|
|
virDomainDiskBusTypeToString(disk->bus));
|
2010-02-01 15:58:38 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == -1) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-02-01 15:58:38 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
disk->info.alias = devname;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Our custom -drive naming scheme used with id= */
|
|
|
|
static int qemuAssignDeviceDiskAliasCustom(virDomainDiskDefPtr disk)
|
|
|
|
{
|
|
|
|
const char *prefix = virDomainDiskBusTypeToString(disk->bus);
|
|
|
|
if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
|
|
|
|
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 {
|
|
|
|
int idx = virDiskNameToIndex(disk->dst);
|
|
|
|
if (virAsprintf(&disk->info.alias, "%s-disk%d", prefix, idx) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
no_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-02-01 15:58:38 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-01 16:28:46 +00:00
|
|
|
int
|
2010-02-09 13:06:56 +00:00
|
|
|
qemuAssignDeviceDiskAlias(virDomainDiskDefPtr def, unsigned long long qemuCmdFlags)
|
2010-02-01 15:58:38 +00:00
|
|
|
{
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE) {
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
|
|
|
|
return qemuAssignDeviceDiskAliasCustom(def);
|
|
|
|
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;
|
|
|
|
if ((thisidx = qemuDomainDeviceAliasIndex(&def->nets[i]->info, "net")) < 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Unable to determine device index for network device"));
|
2010-02-01 15:58:38 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (thisidx >= idx)
|
|
|
|
idx = thisidx + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&net->info.alias, "net%d", idx) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-02-01 15:58:38 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-02-01 16:28:46 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr hostdev, int idx)
|
|
|
|
{
|
|
|
|
if (idx == -1) {
|
|
|
|
int i;
|
|
|
|
idx = 0;
|
|
|
|
for (i = 0 ; i < def->nhostdevs ; i++) {
|
|
|
|
int thisidx;
|
|
|
|
if ((thisidx = qemuDomainDeviceAliasIndex(&def->hostdevs[i]->info, "hostdev")) < 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Unable to determine device index for hostdevwork device"));
|
2010-02-01 16:28:46 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (thisidx >= idx)
|
|
|
|
idx = thisidx + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&hostdev->info.alias, "hostdev%d", idx) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-02-01 16:28:46 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller)
|
|
|
|
{
|
|
|
|
const char *prefix = virDomainControllerTypeToString(controller->type);
|
|
|
|
|
|
|
|
if (virAsprintf(&controller->info.alias, "%s%d", prefix,
|
|
|
|
controller->idx) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-02-01 16:28:46 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-01 15:58:38 +00:00
|
|
|
static int
|
2010-02-09 13:06:56 +00:00
|
|
|
qemuAssignDeviceAliases(virDomainDefPtr def, unsigned long long qemuCmdFlags)
|
2010-01-06 12:11:26 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < def->ndisks ; i++) {
|
2010-02-01 15:58:38 +00:00
|
|
|
if (qemuAssignDeviceDiskAlias(def->disks[i], qemuCmdFlags) < 0)
|
|
|
|
return -1;
|
2010-01-06 12:11:26 +00:00
|
|
|
}
|
2010-02-01 15:58:38 +00:00
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_NET_NAME) ||
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
|
|
|
for (i = 0; i < def->nnets ; i++) {
|
|
|
|
if (qemuAssignDeviceNetAlias(def, def->nets[i], i) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
2010-01-06 12:11:26 +00:00
|
|
|
}
|
|
|
|
|
2010-02-01 15:58:38 +00:00
|
|
|
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))
|
|
|
|
return 0;
|
|
|
|
|
2010-01-06 12:11:26 +00:00
|
|
|
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++) {
|
2010-02-01 16:28:46 +00:00
|
|
|
if (qemuAssignDeviceHostdevAlias(def, def->hostdevs[i], i) < 0)
|
|
|
|
return -1;
|
2010-01-06 12:11:26 +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++) {
|
2010-02-01 16:28:46 +00:00
|
|
|
if (qemuAssignDeviceControllerAlias(def->controllers[i]) < 0)
|
|
|
|
return -1;
|
2010-01-06 12:11:26 +00:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
if (def->watchdog) {
|
|
|
|
if (virAsprintf(&def->watchdog->info.alias, "watchdog%d", 0) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
no_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-01-06 12:11:26 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-27 17:03:54 +00:00
|
|
|
#define QEMU_PCI_ADDRESS_LAST_SLOT 31
|
|
|
|
struct _qemuDomainPCIAddressSet {
|
|
|
|
virHashTablePtr used;
|
|
|
|
int nextslot;
|
|
|
|
/* XXX add domain, bus later when QEMU allows > 1 */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static char *qemuPCIAddressAsString(virDomainDeviceInfoPtr dev)
|
2010-01-07 19:25:41 +00:00
|
|
|
{
|
2010-01-27 17:03:54 +00:00
|
|
|
char *addr;
|
|
|
|
|
2010-02-03 16:11:29 +00:00
|
|
|
if (dev->addr.pci.domain != 0 ||
|
|
|
|
dev->addr.pci.bus != 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Only PCI domain 0 and bus 0 are available"));
|
2010-02-03 16:11:29 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-01-27 17:03:54 +00:00
|
|
|
if (virAsprintf(&addr, "%d:%d:%d",
|
|
|
|
dev->addr.pci.domain,
|
|
|
|
dev->addr.pci.bus,
|
|
|
|
dev->addr.pci.slot) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-01-27 17:03:54 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return addr;
|
2010-01-07 19:25:41 +00:00
|
|
|
}
|
|
|
|
|
2010-01-27 17:03:54 +00:00
|
|
|
|
|
|
|
static int qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
|
|
|
|
virDomainDeviceInfoPtr dev,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
qemuDomainPCIAddressSetPtr addrs = opaque;
|
|
|
|
|
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
|
|
|
char *addr = qemuPCIAddressAsString(dev);
|
|
|
|
|
2010-02-03 16:11:29 +00:00
|
|
|
VIR_DEBUG("Remembering PCI addr %s", addr);
|
|
|
|
|
2010-01-27 17:03:54 +00:00
|
|
|
if (virHashAddEntry(addrs->used, addr, addr) < 0) {
|
|
|
|
VIR_FREE(addr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def)
|
|
|
|
{
|
|
|
|
qemuDomainPCIAddressSetPtr addrs;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(addrs) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (!(addrs->used = virHashCreate(10)))
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (virDomainDeviceInfoIterate(def, qemuCollectPCIAddress, addrs) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
return addrs;
|
|
|
|
|
|
|
|
no_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-01-27 17:03:54 +00:00
|
|
|
error:
|
|
|
|
qemuDomainPCIAddressSetFree(addrs);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-01-27 17:49:19 +00:00
|
|
|
int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
|
|
|
|
virDomainDeviceInfoPtr dev)
|
2010-01-27 17:03:54 +00:00
|
|
|
{
|
|
|
|
char *addr;
|
|
|
|
|
2010-01-27 17:49:19 +00:00
|
|
|
addr = qemuPCIAddressAsString(dev);
|
2010-01-27 17:03:54 +00:00
|
|
|
if (!addr)
|
|
|
|
return -1;
|
|
|
|
|
2010-02-03 16:11:29 +00:00
|
|
|
VIR_DEBUG("Reserving PCI addr %s", addr);
|
|
|
|
|
2010-01-27 17:03:54 +00:00
|
|
|
if (virHashLookup(addrs->used, addr)) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unable to reserve PCI address %s"), addr);
|
2010-01-27 17:03:54 +00:00
|
|
|
VIR_FREE(addr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virHashAddEntry(addrs->used, addr, addr)) {
|
|
|
|
VIR_FREE(addr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-02-03 16:11:29 +00:00
|
|
|
if (dev->addr.pci.slot > addrs->nextslot)
|
|
|
|
addrs->nextslot = dev->addr.pci.slot + 1;
|
|
|
|
|
2010-01-27 17:03:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-01-27 17:49:19 +00:00
|
|
|
int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
|
|
|
|
int slot)
|
|
|
|
{
|
|
|
|
virDomainDeviceInfo dev;
|
|
|
|
|
|
|
|
dev.addr.pci.domain = 0;
|
|
|
|
dev.addr.pci.bus = 0;
|
|
|
|
dev.addr.pci.slot = slot;
|
|
|
|
|
|
|
|
return qemuDomainPCIAddressReserveAddr(addrs, &dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs,
|
|
|
|
virDomainDeviceInfoPtr dev)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
|
|
|
|
ret = qemuDomainPCIAddressReserveAddr(addrs, dev);
|
|
|
|
else
|
|
|
|
ret = qemuDomainPCIAddressSetNextAddr(addrs, dev);
|
|
|
|
return ret;
|
|
|
|
}
|
2010-01-27 17:03:54 +00:00
|
|
|
|
|
|
|
static void qemuDomainPCIAddressSetFreeEntry(void *payload, const char *name ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
VIR_FREE(payload);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-27 17:49:19 +00:00
|
|
|
int qemuDomainPCIAddressReleaseAddr(qemuDomainPCIAddressSetPtr addrs,
|
|
|
|
virDomainDeviceInfoPtr dev)
|
|
|
|
{
|
|
|
|
char *addr;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
addr = qemuPCIAddressAsString(dev);
|
|
|
|
if (!addr)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ret = virHashRemoveEntry(addrs->used, addr, qemuDomainPCIAddressSetFreeEntry);
|
|
|
|
|
|
|
|
VIR_FREE(addr);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-27 17:03:54 +00:00
|
|
|
void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs)
|
|
|
|
{
|
|
|
|
if (!addrs)
|
|
|
|
return;
|
|
|
|
|
|
|
|
virHashFree(addrs->used, qemuDomainPCIAddressSetFreeEntry);
|
|
|
|
addrs->used = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
|
|
|
|
virDomainDeviceInfoPtr dev)
|
2010-01-07 19:25:41 +00:00
|
|
|
{
|
|
|
|
int i;
|
2010-01-27 17:03:54 +00:00
|
|
|
|
|
|
|
for (i = addrs->nextslot ; i <= QEMU_PCI_ADDRESS_LAST_SLOT ; i++) {
|
|
|
|
virDomainDeviceInfo maybe;
|
|
|
|
char *addr;
|
|
|
|
|
|
|
|
memset(&maybe, 0, sizeof(maybe));
|
|
|
|
maybe.addr.pci.domain = 0;
|
|
|
|
maybe.addr.pci.bus = 0;
|
|
|
|
maybe.addr.pci.slot = i;
|
|
|
|
|
|
|
|
addr = qemuPCIAddressAsString(&maybe);
|
|
|
|
|
2010-02-03 16:11:29 +00:00
|
|
|
VIR_DEBUG("Allocating PCI addr %s", addr);
|
|
|
|
|
2010-01-27 17:03:54 +00:00
|
|
|
if (virHashLookup(addrs->used, addr)) {
|
|
|
|
VIR_FREE(addr);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virHashAddEntry(addrs->used, addr, addr) < 0) {
|
|
|
|
VIR_FREE(addr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
dev->addr.pci.domain = 0;
|
|
|
|
dev->addr.pci.bus = 0;
|
|
|
|
dev->addr.pci.slot = i;
|
|
|
|
|
|
|
|
addrs->nextslot = i + 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("No more available PCI addresses"));
|
2010-01-27 17:03:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Host bridge */
|
2010-01-27 17:49:19 +00:00
|
|
|
if (qemuDomainPCIAddressReserveSlot(addrs, 0) < 0)
|
2010-01-27 17:03:54 +00:00
|
|
|
goto error;
|
2010-02-03 16:11:29 +00:00
|
|
|
|
|
|
|
/* PIIX3 (ISA bridge, IDE controller, something else unknown, USB controller)
|
|
|
|
* at slot 1....reserve it later
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* VGA at slot 2.... reserve it later */
|
|
|
|
|
2010-01-27 17:03:54 +00:00
|
|
|
/* VirtIO Balloon */
|
2010-01-27 17:49:19 +00:00
|
|
|
if (qemuDomainPCIAddressReserveSlot(addrs, 3) < 0)
|
2010-01-27 17:03:54 +00:00
|
|
|
goto error;
|
2010-01-07 19:25:41 +00:00
|
|
|
|
|
|
|
for (i = 0; i < def->ndisks ; i++) {
|
|
|
|
if (def->disks[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Only VirtIO disks use PCI addrs */
|
|
|
|
if (def->disks[i]->bus != VIR_DOMAIN_DISK_BUS_VIRTIO)
|
|
|
|
continue;
|
|
|
|
|
2010-01-27 17:03:54 +00:00
|
|
|
if (qemuDomainPCIAddressSetNextAddr(addrs, &def->disks[i]->info) < 0)
|
|
|
|
goto error;
|
2010-01-07 19:25:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < def->nnets ; i++) {
|
|
|
|
if (def->nets[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
|
|
|
|
continue;
|
2010-01-27 17:03:54 +00:00
|
|
|
if (qemuDomainPCIAddressSetNextAddr(addrs, &def->nets[i]->info) < 0)
|
|
|
|
goto error;
|
2010-01-07 19:25:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2010-01-27 17:03:54 +00:00
|
|
|
if (qemuDomainPCIAddressSetNextAddr(addrs, &def->sounds[i]->info) < 0)
|
|
|
|
goto error;
|
2010-01-07 19:25:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < def->nhostdevs ; i++) {
|
|
|
|
if (def->hostdevs[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
|
|
|
|
continue;
|
|
|
|
if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
|
|
|
|
def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
|
|
|
|
continue;
|
|
|
|
|
2010-01-27 17:03:54 +00:00
|
|
|
if (qemuDomainPCIAddressSetNextAddr(addrs, &def->hostdevs[i]->info) < 0)
|
|
|
|
goto error;
|
2010-01-07 19:25:41 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < def->nvideos ; i++) {
|
|
|
|
/* First VGA is hardcoded slot=2 */
|
2010-01-27 17:03:54 +00:00
|
|
|
if (i == 0) {
|
2010-02-03 16:11:29 +00:00
|
|
|
if (def->videos[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
|
|
|
if (def->videos[i]->info.addr.pci.domain != 0 ||
|
|
|
|
def->videos[i]->info.addr.pci.bus != 0 ||
|
|
|
|
def->videos[i]->info.addr.pci.slot != 2 ||
|
|
|
|
def->videos[i]->info.addr.pci.function != 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Primary video card must have PCI address 0:0:2.0"));
|
2010-02-03 16:11:29 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
def->videos[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
def->videos[i]->info.addr.pci.domain = 0;
|
|
|
|
def->videos[i]->info.addr.pci.bus = 0;
|
|
|
|
def->videos[i]->info.addr.pci.slot = 2;
|
|
|
|
def->videos[i]->info.addr.pci.function = 0;
|
|
|
|
if (qemuDomainPCIAddressReserveSlot(addrs, 2) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
2010-01-27 17:03:54 +00:00
|
|
|
} else {
|
2010-02-03 16:11:29 +00:00
|
|
|
if (def->videos[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
|
|
|
|
continue;
|
2010-01-27 17:03:54 +00:00
|
|
|
if (qemuDomainPCIAddressSetNextAddr(addrs, &def->videos[i]->info) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
2010-01-07 19:25:41 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < def->ncontrollers ; i++) {
|
|
|
|
/* FDC lives behind the ISA bridge */
|
|
|
|
if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* 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) {
|
2010-02-03 16:11:29 +00:00
|
|
|
if (def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
2010-02-15 14:37:04 +00:00
|
|
|
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) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Primary IDE controller must have PCI address 0:0:1.1"));
|
2010-02-03 16:11:29 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} 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;
|
|
|
|
if (qemuDomainPCIAddressReserveSlot(addrs, 1) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
2010-01-07 19:25:41 +00:00
|
|
|
} else {
|
2010-02-03 16:11:29 +00:00
|
|
|
if (def->controllers[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
|
|
|
|
continue;
|
2010-01-27 17:03:54 +00:00
|
|
|
if (qemuDomainPCIAddressSetNextAddr(addrs, &def->controllers[i]->info) < 0)
|
|
|
|
goto error;
|
2010-01-07 19:25:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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) */
|
|
|
|
}
|
2010-01-27 17:03:54 +00:00
|
|
|
if (def->watchdog &&
|
|
|
|
def->watchdog->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
|
|
|
|
if (qemuDomainPCIAddressSetNextAddr(addrs, &def->watchdog->info) < 0)
|
|
|
|
goto error;
|
2010-01-07 19:25:41 +00:00
|
|
|
}
|
2010-01-27 17:03:54 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
return -1;
|
2010-01-07 19:25:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-14 18:06:23 +00:00
|
|
|
static int
|
|
|
|
qemuBuildDeviceAddressStr(virBufferPtr buf,
|
|
|
|
virDomainDeviceInfoPtr info)
|
|
|
|
{
|
|
|
|
if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
|
|
|
if (info->addr.pci.domain != 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Only PCI device addresses with domain=0 are supported"));
|
2009-12-14 18:06:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (info->addr.pci.bus != 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Only PCI device addresses with bus=0 are supported"));
|
2009-12-14 18:06:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (info->addr.pci.function != 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Only PCI device addresses with function=0 are supported"));
|
2009-12-14 18:06:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
*/
|
|
|
|
virBufferVSprintf(buf, ",bus=pci.0,addr=0x%x", info->addr.pci.slot);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-01-06 12:11:26 +00:00
|
|
|
|
2009-12-10 21:11:56 +00:00
|
|
|
#define QEMU_SERIAL_PARAM_ACCEPTED_CHARS \
|
|
|
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
|
|
|
|
|
|
|
|
static int
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuSafeSerialParamValue(const char *value)
|
2009-12-10 21:11:56 +00:00
|
|
|
{
|
|
|
|
if (strspn(value, QEMU_SERIAL_PARAM_ACCEPTED_CHARS) != strlen (value)) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("driver serial '%s' contains unsafe characters"),
|
|
|
|
value);
|
2009-12-10 21:11:56 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
qemuBuildDriveStr(virDomainDiskDefPtr disk,
|
|
|
|
int bootable,
|
2010-02-09 13:06:56 +00:00
|
|
|
unsigned long long qemuCmdFlags)
|
2009-12-10 21:11:56 +00:00
|
|
|
{
|
|
|
|
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
|
|
|
const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
|
|
|
|
int idx = virDiskNameToIndex(disk->dst);
|
2009-12-10 19:07:16 +00:00
|
|
|
int busid = -1, unitid = -1;
|
2009-12-10 21:11:56 +00:00
|
|
|
|
|
|
|
if (idx < 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported disk type '%s'"), disk->dst);
|
2009-12-10 21:11:56 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-12-10 19:07:16 +00:00
|
|
|
switch (disk->bus) {
|
|
|
|
case VIR_DOMAIN_DISK_BUS_SCSI:
|
|
|
|
if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unexpected address type for scsi disk"));
|
2009-12-10 19:07:16 +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) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("SCSI controller only supports 1 bus"));
|
2009-12-10 19:07:16 +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) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unexpected address type for ide disk"));
|
2009-12-10 19:07:16 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
/* We can only have 1 IDE controller (currently) */
|
|
|
|
if (disk->info.addr.drive.controller != 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Only 1 %s controller is supported"), bus);
|
2009-12-10 19:07:16 +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) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unexpected address type for fdc disk"));
|
2009-12-10 19:07:16 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
/* We can only have 1 FDC controller (currently) */
|
|
|
|
if (disk->info.addr.drive.controller != 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Only 1 %s controller is supported"), bus);
|
2009-12-10 19:07:16 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
/* We can only have 1 FDC bus (currently) */
|
|
|
|
if (disk->info.addr.drive.bus != 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Only 1 %s bus is supported"), bus);
|
2009-12-10 19:07:16 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
unitid = disk->info.addr.drive.unit;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_DISK_BUS_VIRTIO:
|
|
|
|
/* Each virtio drive is a separate PCI device, no unit/busid or index */
|
|
|
|
idx = -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_DISK_BUS_XEN:
|
|
|
|
/* Xen has no address type currently, so assign based on index */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-12-10 21:11:56 +00:00
|
|
|
if (disk->src) {
|
|
|
|
if (disk->type == VIR_DOMAIN_DISK_TYPE_DIR) {
|
|
|
|
/* QEMU only supports magic FAT format for now */
|
|
|
|
if (disk->driverType &&
|
|
|
|
STRNEQ(disk->driverType, "fat")) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported disk driver type for '%s'"),
|
|
|
|
disk->driverType);
|
2009-12-10 21:11:56 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!disk->readonly) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot create virtual FAT disks in read-write mode"));
|
2009-12-10 21:11:56 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
|
|
|
|
virBufferVSprintf(&opt, "file=fat:floppy:%s,", disk->src);
|
|
|
|
else
|
|
|
|
virBufferVSprintf(&opt, "file=fat:%s,", disk->src);
|
|
|
|
} else {
|
|
|
|
virBufferVSprintf(&opt, "file=%s,", disk->src);
|
|
|
|
}
|
|
|
|
}
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
|
|
|
|
virBufferAddLit(&opt, "if=none");
|
|
|
|
else
|
|
|
|
virBufferVSprintf(&opt, "if=%s", bus);
|
|
|
|
|
2009-12-10 21:11:56 +00:00
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
|
|
|
|
virBufferAddLit(&opt, ",media=cdrom");
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
2010-02-10 17:46:44 +00:00
|
|
|
virBufferVSprintf(&opt, ",id=%s%s", QEMU_DRIVE_HOST_PREFIX, disk->info.alias);
|
2009-12-10 19:07:16 +00:00
|
|
|
} else {
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
if (busid == -1 && unitid == -1) {
|
|
|
|
if (idx != -1)
|
|
|
|
virBufferVSprintf(&opt, ",index=%d", idx);
|
|
|
|
} else {
|
|
|
|
if (busid != -1)
|
|
|
|
virBufferVSprintf(&opt, ",bus=%d", busid);
|
|
|
|
if (unitid != -1)
|
|
|
|
virBufferVSprintf(&opt, ",unit=%d", unitid);
|
|
|
|
}
|
2009-12-10 19:07:16 +00:00
|
|
|
}
|
2009-12-10 21:11:56 +00:00
|
|
|
if (bootable &&
|
|
|
|
disk->device == VIR_DOMAIN_DISK_DEVICE_DISK)
|
|
|
|
virBufferAddLit(&opt, ",boot=on");
|
|
|
|
if (disk->driverType &&
|
|
|
|
disk->type != VIR_DOMAIN_DISK_TYPE_DIR &&
|
|
|
|
qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_FORMAT)
|
|
|
|
virBufferVSprintf(&opt, ",format=%s", disk->driverType);
|
|
|
|
if (disk->serial &&
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_SERIAL)) {
|
2010-02-09 18:15:41 +00:00
|
|
|
if (qemuSafeSerialParamValue(disk->serial) < 0)
|
2009-12-10 21:11:56 +00:00
|
|
|
goto error;
|
|
|
|
virBufferVSprintf(&opt, ",serial=%s", disk->serial);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->cachemode) {
|
|
|
|
const char *mode =
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_CACHE_V2) ?
|
|
|
|
qemuDiskCacheV2TypeToString(disk->cachemode) :
|
|
|
|
qemuDiskCacheV1TypeToString(disk->cachemode);
|
|
|
|
|
|
|
|
virBufferVSprintf(&opt, ",cache=%s", mode);
|
|
|
|
} else if (disk->shared && !disk->readonly) {
|
|
|
|
virBufferAddLit(&opt, ",cache=off");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferError(&opt)) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-12-10 21:11:56 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&opt);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&opt);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-01-26 13:00:18 +00:00
|
|
|
|
|
|
|
char *
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuBuildDriveDevStr(virDomainDiskDefPtr disk)
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
{
|
|
|
|
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
|
|
|
const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
|
|
|
|
int idx = virDiskNameToIndex(disk->dst);
|
|
|
|
|
|
|
|
if (idx < 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported disk type '%s'"), disk->dst);
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (disk->bus) {
|
|
|
|
case VIR_DOMAIN_DISK_BUS_IDE:
|
|
|
|
virBufferAddLit(&opt, "ide-drive");
|
|
|
|
virBufferVSprintf(&opt, ",bus=ide.%d,unit=%d",
|
|
|
|
disk->info.addr.drive.bus,
|
|
|
|
disk->info.addr.drive.unit);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_BUS_SCSI:
|
|
|
|
virBufferAddLit(&opt, "scsi-disk");
|
|
|
|
virBufferVSprintf(&opt, ",bus=scsi%d.%d,scsi-id=%d",
|
|
|
|
disk->info.addr.drive.controller,
|
|
|
|
disk->info.addr.drive.bus,
|
|
|
|
disk->info.addr.drive.unit);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_BUS_VIRTIO:
|
|
|
|
virBufferAddLit(&opt, "virtio-blk-pci");
|
|
|
|
qemuBuildDeviceAddressStr(&opt, &disk->info);
|
|
|
|
break;
|
2009-12-14 19:15:05 +00:00
|
|
|
case VIR_DOMAIN_DISK_BUS_USB:
|
|
|
|
virBufferAddLit(&opt, "usb-storage");
|
|
|
|
break;
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
default:
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported disk bus '%s' with device setup"), bus);
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2010-02-10 17:46:44 +00:00
|
|
|
virBufferVSprintf(&opt, ",drive=%s%s", QEMU_DRIVE_HOST_PREFIX, disk->info.alias);
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
virBufferVSprintf(&opt, ",id=%s", disk->info.alias);
|
|
|
|
|
2010-01-26 13:00:18 +00:00
|
|
|
if (virBufferError(&opt)) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-01-26 13:00:18 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&opt);
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&opt);
|
2010-01-26 13:00:18 +00:00
|
|
|
return NULL;
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-26 13:00:18 +00:00
|
|
|
char *
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
qemuBuildControllerDevStr(virDomainControllerDefPtr def)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
|
|
|
|
virBufferAddLit(&buf, "lsi");
|
|
|
|
virBufferVSprintf(&buf, ",id=scsi%d", def->idx);
|
|
|
|
break;
|
|
|
|
|
2010-02-18 16:56:50 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
|
|
|
|
if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
|
|
|
virBufferAddLit(&buf, "virtio-serial-pci");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(&buf, "virtio-serial");
|
|
|
|
}
|
|
|
|
virBufferVSprintf(&buf, ",id=" QEMU_VIRTIO_SERIAL_PREFIX "%d",
|
|
|
|
def->idx);
|
|
|
|
if (def->opts.vioserial.ports != -1) {
|
|
|
|
virBufferVSprintf(&buf, ",max_ports=%d",
|
|
|
|
def->opts.vioserial.ports);
|
|
|
|
}
|
|
|
|
if (def->opts.vioserial.vectors != -1) {
|
|
|
|
virBufferVSprintf(&buf, ",vectors=%d",
|
|
|
|
def->opts.vioserial.vectors);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-02-01 15:08:36 +00:00
|
|
|
/* We always get an IDE controller, whether we want it or not. */
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
|
|
|
|
default:
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuBuildDeviceAddressStr(&buf, &def->info) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2010-01-26 13:00:18 +00:00
|
|
|
if (virBufferError(&buf)) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
goto error;
|
2010-01-26 13:00:18 +00:00
|
|
|
}
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-12-10 21:11:56 +00:00
|
|
|
|
2010-01-26 13:00:18 +00:00
|
|
|
char *
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuBuildNicStr(virDomainNetDefPtr net,
|
2009-07-17 21:08:33 +00:00
|
|
|
const char *prefix,
|
2010-01-26 13:00:18 +00:00
|
|
|
int vlan)
|
2009-07-17 21:08:33 +00:00
|
|
|
{
|
2010-01-26 13:00:18 +00:00
|
|
|
char *str;
|
|
|
|
if (virAsprintf(&str,
|
2009-09-23 16:01:39 +00:00
|
|
|
"%smacaddr=%02x:%02x:%02x:%02x:%02x:%02x,vlan=%d%s%s%s%s",
|
2009-07-17 21:08:33 +00:00
|
|
|
prefix ? prefix : "",
|
|
|
|
net->mac[0], net->mac[1],
|
|
|
|
net->mac[2], net->mac[3],
|
|
|
|
net->mac[4], net->mac[5],
|
|
|
|
vlan,
|
|
|
|
(net->model ? ",model=" : ""),
|
2009-07-17 21:08:33 +00:00
|
|
|
(net->model ? net->model : ""),
|
2010-01-08 15:53:53 +00:00
|
|
|
(net->info.alias ? ",name=" : ""),
|
|
|
|
(net->info.alias ? net->info.alias : "")) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-01-26 13:00:18 +00:00
|
|
|
return NULL;
|
2009-07-17 21:08:33 +00:00
|
|
|
}
|
|
|
|
|
2010-01-26 13:00:18 +00:00
|
|
|
return str;
|
2009-07-17 21:08:33 +00:00
|
|
|
}
|
2009-01-30 17:15:39 +00:00
|
|
|
|
2010-01-26 13:00:18 +00:00
|
|
|
|
|
|
|
char *
|
2010-02-01 15:06:36 +00:00
|
|
|
qemuBuildNicDevStr(virDomainNetDefPtr net, int vlan)
|
Convert NICs over to use -device & -netdev where possible
The current syntax uses a pair of args
-net nic,macaddr=52:54:00:56:6c:55,vlan=3,model=pcnet,name=pcnet.0
-net user,vlan=3,name=user.0
The new syntax does not need the vlan craziness anymore, and
so has a simplified pair of args
-netdev user,id=user.0
-device pcnet,netdev=user.0,id=pcnet.0,mac=52:54:00:56:6c:55,addr=<PCI SLOT>
2009-12-14 19:09:40 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
const char *nic;
|
|
|
|
|
|
|
|
if (!net->model) {
|
|
|
|
nic = "rtl8139";
|
|
|
|
} else if (STREQ(net->model, "virtio")) {
|
|
|
|
nic = "virtio-net-pci";
|
|
|
|
} else {
|
|
|
|
nic = net->model;
|
|
|
|
}
|
|
|
|
|
2010-01-29 18:07:04 +00:00
|
|
|
virBufferAdd(&buf, nic, strlen(nic));
|
2010-02-01 15:06:36 +00:00
|
|
|
if (vlan == -1)
|
|
|
|
virBufferVSprintf(&buf, ",netdev=host%s", net->info.alias);
|
2010-01-29 18:07:04 +00:00
|
|
|
else
|
2010-02-01 15:06:36 +00:00
|
|
|
virBufferVSprintf(&buf, ",vlan=%d", vlan);
|
Convert NICs over to use -device & -netdev where possible
The current syntax uses a pair of args
-net nic,macaddr=52:54:00:56:6c:55,vlan=3,model=pcnet,name=pcnet.0
-net user,vlan=3,name=user.0
The new syntax does not need the vlan craziness anymore, and
so has a simplified pair of args
-netdev user,id=user.0
-device pcnet,netdev=user.0,id=pcnet.0,mac=52:54:00:56:6c:55,addr=<PCI SLOT>
2009-12-14 19:09:40 +00:00
|
|
|
virBufferVSprintf(&buf, ",id=%s", net->info.alias);
|
|
|
|
virBufferVSprintf(&buf, ",mac=%02x:%02x:%02x:%02x:%02x:%02x",
|
|
|
|
net->mac[0], net->mac[1],
|
|
|
|
net->mac[2], net->mac[3],
|
|
|
|
net->mac[4], net->mac[5]);
|
|
|
|
if (qemuBuildDeviceAddressStr(&buf, &net->info) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
Convert NICs over to use -device & -netdev where possible
The current syntax uses a pair of args
-net nic,macaddr=52:54:00:56:6c:55,vlan=3,model=pcnet,name=pcnet.0
-net user,vlan=3,name=user.0
The new syntax does not need the vlan craziness anymore, and
so has a simplified pair of args
-netdev user,id=user.0
-device pcnet,netdev=user.0,id=pcnet.0,mac=52:54:00:56:6c:55,addr=<PCI SLOT>
2009-12-14 19:09:40 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-01-26 13:00:18 +00:00
|
|
|
|
|
|
|
char *
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuBuildHostNetStr(virDomainNetDefPtr net,
|
2009-07-17 21:08:33 +00:00
|
|
|
char type_sep,
|
|
|
|
int vlan,
|
2010-01-26 13:00:18 +00:00
|
|
|
const char *tapfd)
|
2009-07-17 21:08:33 +00:00
|
|
|
{
|
2010-02-01 15:06:36 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2010-01-26 13:00:18 +00:00
|
|
|
|
2009-07-17 21:08:33 +00:00
|
|
|
switch (net->type) {
|
|
|
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
2010-02-15 16:41:14 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
2010-02-01 15:06:36 +00:00
|
|
|
virBufferAddLit(&buf, "tap");
|
|
|
|
virBufferVSprintf(&buf, "%cfd=%s", type_sep, tapfd);
|
|
|
|
type_sep = ',';
|
2009-07-17 21:08:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
2010-02-01 15:06:36 +00:00
|
|
|
virBufferAddLit(&buf, "tap");
|
|
|
|
if (net->ifname) {
|
|
|
|
virBufferVSprintf(&buf, "%cifname=%s", type_sep, net->ifname);
|
|
|
|
type_sep = ',';
|
|
|
|
}
|
|
|
|
if (net->data.ethernet.script) {
|
|
|
|
virBufferVSprintf(&buf, "%cscript=%s", type_sep,
|
|
|
|
net->data.ethernet.script);
|
|
|
|
type_sep = ',';
|
2009-07-17 21:08:33 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_SERVER:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_MCAST:
|
2010-02-01 15:06:36 +00:00
|
|
|
virBufferAddLit(&buf, "socket");
|
|
|
|
switch (net->type) {
|
|
|
|
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
|
|
|
virBufferVSprintf(&buf, "%cconnect=%s:%d",
|
|
|
|
type_sep,
|
|
|
|
net->data.socket.address,
|
|
|
|
net->data.socket.port);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_NET_TYPE_SERVER:
|
|
|
|
virBufferVSprintf(&buf, "%clisten=%s:%d",
|
|
|
|
type_sep,
|
|
|
|
net->data.socket.address,
|
|
|
|
net->data.socket.port);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_NET_TYPE_MCAST:
|
|
|
|
virBufferVSprintf(&buf, "%cmcast=%s:%d",
|
|
|
|
type_sep,
|
|
|
|
net->data.socket.address,
|
|
|
|
net->data.socket.port);
|
|
|
|
break;
|
2009-07-17 21:08:33 +00:00
|
|
|
}
|
2010-02-01 15:06:36 +00:00
|
|
|
type_sep = ',';
|
2009-07-17 21:08:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_USER:
|
|
|
|
default:
|
2010-02-01 15:06:36 +00:00
|
|
|
virBufferAddLit(&buf, "user");
|
2009-07-17 21:08:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-02-01 15:06:36 +00:00
|
|
|
if (vlan >= 0) {
|
|
|
|
virBufferVSprintf(&buf, "%cvlan=%d", type_sep, vlan);
|
|
|
|
if (net->info.alias)
|
|
|
|
virBufferVSprintf(&buf, ",name=host%s",
|
|
|
|
net->info.alias);
|
|
|
|
} else {
|
|
|
|
virBufferVSprintf(&buf, "%cid=host%s",
|
|
|
|
type_sep, net->info.alias);
|
|
|
|
}
|
Convert NICs over to use -device & -netdev where possible
The current syntax uses a pair of args
-net nic,macaddr=52:54:00:56:6c:55,vlan=3,model=pcnet,name=pcnet.0
-net user,vlan=3,name=user.0
The new syntax does not need the vlan craziness anymore, and
so has a simplified pair of args
-netdev user,id=user.0
-device pcnet,netdev=user.0,id=pcnet.0,mac=52:54:00:56:6c:55,addr=<PCI SLOT>
2009-12-14 19:09:40 +00:00
|
|
|
|
2010-02-01 15:06:36 +00:00
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virBufferFreeAndReset(&buf);
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-02-01 15:06:36 +00:00
|
|
|
return NULL;
|
Convert NICs over to use -device & -netdev where possible
The current syntax uses a pair of args
-net nic,macaddr=52:54:00:56:6c:55,vlan=3,model=pcnet,name=pcnet.0
-net user,vlan=3,name=user.0
The new syntax does not need the vlan craziness anymore, and
so has a simplified pair of args
-netdev user,id=user.0
-device pcnet,netdev=user.0,id=pcnet.0,mac=52:54:00:56:6c:55,addr=<PCI SLOT>
2009-12-14 19:09:40 +00:00
|
|
|
}
|
|
|
|
|
2010-02-01 15:06:36 +00:00
|
|
|
return virBufferContentAndReset(&buf);
|
Convert NICs over to use -device & -netdev where possible
The current syntax uses a pair of args
-net nic,macaddr=52:54:00:56:6c:55,vlan=3,model=pcnet,name=pcnet.0
-net user,vlan=3,name=user.0
The new syntax does not need the vlan craziness anymore, and
so has a simplified pair of args
-netdev user,id=user.0
-device pcnet,netdev=user.0,id=pcnet.0,mac=52:54:00:56:6c:55,addr=<PCI SLOT>
2009-12-14 19:09:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-26 13:00:18 +00:00
|
|
|
char *
|
|
|
|
qemuBuildWatchdogDevStr(virDomainWatchdogDefPtr dev)
|
2009-12-14 18:06:23 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
const char *model = virDomainWatchdogModelTypeToString(dev->model);
|
|
|
|
if (!model) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("missing watchdog model"));
|
2009-12-14 18:06:23 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferVSprintf(&buf, "%s", model);
|
|
|
|
virBufferVSprintf(&buf, ",id=%s", dev->info.alias);
|
|
|
|
if (qemuBuildDeviceAddressStr(&buf, &dev->info) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-12-14 18:06:23 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-12-14 18:16:10 +00:00
|
|
|
|
2010-01-26 13:00:18 +00:00
|
|
|
char *
|
|
|
|
qemuBuildUSBInputDevStr(virDomainInputDefPtr dev)
|
2010-01-06 18:31:00 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
virBufferVSprintf(&buf, "%s",
|
|
|
|
dev->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ?
|
|
|
|
"usb-mouse" : "usb-tablet");
|
|
|
|
virBufferVSprintf(&buf, ",id=%s", dev->info.alias);
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-01-06 18:31:00 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-26 13:00:18 +00:00
|
|
|
char *
|
2009-12-14 18:16:10 +00:00
|
|
|
qemuBuildSoundDevStr(virDomainSoundDefPtr sound)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
const char *model = virDomainSoundModelTypeToString(sound->model);
|
|
|
|
|
|
|
|
if (!model) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("invalid sound model"));
|
2009-12-14 18:16:10 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Hack for 2 wierdly unusal devices name in QEMU */
|
|
|
|
if (STREQ(model, "es1370"))
|
|
|
|
model = "ES1370";
|
|
|
|
else if (STREQ(model, "ac97"))
|
|
|
|
model = "AC97";
|
|
|
|
|
|
|
|
virBufferVSprintf(&buf, "%s", model);
|
|
|
|
virBufferVSprintf(&buf, ",id=%s", sound->info.alias);
|
|
|
|
if (qemuBuildDeviceAddressStr(&buf, &sound->info) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-12-14 18:16:10 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-26 13:00:18 +00:00
|
|
|
char *
|
2009-12-14 19:36:42 +00:00
|
|
|
qemuBuildPCIHostdevDevStr(virDomainHostdevDefPtr dev)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "pci-assign");
|
|
|
|
virBufferVSprintf(&buf, ",host=%.2x:%.2x.%.1x",
|
|
|
|
dev->source.subsys.u.pci.bus,
|
|
|
|
dev->source.subsys.u.pci.slot,
|
|
|
|
dev->source.subsys.u.pci.function);
|
|
|
|
virBufferVSprintf(&buf, ",id=%s", dev->info.alias);
|
|
|
|
if (qemuBuildDeviceAddressStr(&buf, &dev->info) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-12-14 19:36:42 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-01-26 13:00:18 +00:00
|
|
|
|
2010-01-26 13:44:12 +00:00
|
|
|
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)
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-01-26 13:44:12 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev)
|
|
|
|
{
|
|
|
|
char *ret = NULL;
|
|
|
|
|
|
|
|
if (!dev->source.subsys.u.usb.bus &&
|
|
|
|
!dev->source.subsys.u.usb.device) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("USB host device is missing bus/device information"));
|
2010-01-26 13:44:12 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&ret, "usb-host,hostbus=%.3d,hostaddr=%.3d,id=%s",
|
|
|
|
dev->source.subsys.u.usb.bus,
|
|
|
|
dev->source.subsys.u.usb.device,
|
|
|
|
dev->info.alias) < 0)
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-01-26 13:44:12 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev)
|
|
|
|
{
|
|
|
|
char *ret = NULL;
|
|
|
|
|
|
|
|
if (!dev->source.subsys.u.usb.bus &&
|
|
|
|
!dev->source.subsys.u.usb.device) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("USB host device is missing bus/device information"));
|
2010-01-26 13:44:12 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&ret, "host:%.3d.%.3d",
|
|
|
|
dev->source.subsys.u.usb.bus,
|
|
|
|
dev->source.subsys.u.usb.device) < 0)
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-01-26 13:44:12 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-12-14 18:16:10 +00:00
|
|
|
/* This function outputs a -chardev command line option which describes only the
|
2009-11-05 14:31:03 +00:00
|
|
|
* host side of the character device */
|
2010-01-26 13:00:18 +00:00
|
|
|
char *
|
|
|
|
qemuBuildChrChardevStr(virDomainChrDefPtr dev)
|
2009-11-05 14:31:03 +00:00
|
|
|
{
|
2010-01-26 13:00:18 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2009-11-05 14:31:03 +00:00
|
|
|
bool telnet;
|
2010-01-26 13:00:18 +00:00
|
|
|
|
2009-11-05 14:31:03 +00:00
|
|
|
switch(dev->type) {
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_NULL:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferVSprintf(&buf, "null,id=%s", dev->info.alias);
|
2009-11-05 14:31:03 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_VC:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferVSprintf(&buf, "vc,id=%s", dev->info.alias);
|
2009-11-05 14:31:03 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_PTY:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferVSprintf(&buf, "pty,id=%s", dev->info.alias);
|
2009-11-05 14:31:03 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_DEV:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferVSprintf(&buf, "tty,id=%s,path=%s", dev->info.alias, dev->data.file.path);
|
2009-11-05 14:31:03 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_FILE:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferVSprintf(&buf, "file,id=%s,path=%s", dev->info.alias, dev->data.file.path);
|
2009-11-05 14:31:03 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_PIPE:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferVSprintf(&buf, "pipe,id=%s,path=%s", dev->info.alias, dev->data.file.path);
|
2009-11-05 14:31:03 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_STDIO:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferVSprintf(&buf, "stdio,id=%s", dev->info.alias);
|
2009-11-05 14:31:03 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UDP:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferVSprintf(&buf,
|
2009-11-05 14:31:03 +00:00
|
|
|
"udp,id=%s,host=%s,port=%s,localaddr=%s,localport=%s",
|
Convert character devices over to use -device
The current character device syntax uses either
-serial tty,path=/dev/ttyS2
Or
-chardev tty,id=serial0,path=/dev/ttyS2 -serial chardev:serial0
With the new -device support, we now prefer
-chardev file,id=serial0,path=/tmp/serial.log -device isa-serial,chardev=serial0
This patch changes the existing -chardev syntax to use this new
scheme, and fallbacks to the old plain -serial syntax for old
QEMU.
The monitor device changes to
-chardev socket,id=monitor,path=/tmp/test-monitor,server,nowait -mon chardev=monitor
In addition, this patch adds --nodefaults, which kills off the
default serial, parallel, vga and nic devices. THis avoids the
need for us to explicitly turn each off
2009-12-14 18:04:35 +00:00
|
|
|
dev->info.alias,
|
2009-11-05 14:31:03 +00:00
|
|
|
dev->data.udp.connectHost,
|
|
|
|
dev->data.udp.connectService,
|
|
|
|
dev->data.udp.bindHost,
|
|
|
|
dev->data.udp.bindService);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_TCP:
|
|
|
|
telnet = dev->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferVSprintf(&buf,
|
2009-11-05 14:31:03 +00:00
|
|
|
"socket,id=%s,host=%s,port=%s%s%s",
|
Convert character devices over to use -device
The current character device syntax uses either
-serial tty,path=/dev/ttyS2
Or
-chardev tty,id=serial0,path=/dev/ttyS2 -serial chardev:serial0
With the new -device support, we now prefer
-chardev file,id=serial0,path=/tmp/serial.log -device isa-serial,chardev=serial0
This patch changes the existing -chardev syntax to use this new
scheme, and fallbacks to the old plain -serial syntax for old
QEMU.
The monitor device changes to
-chardev socket,id=monitor,path=/tmp/test-monitor,server,nowait -mon chardev=monitor
In addition, this patch adds --nodefaults, which kills off the
default serial, parallel, vga and nic devices. THis avoids the
need for us to explicitly turn each off
2009-12-14 18:04:35 +00:00
|
|
|
dev->info.alias,
|
2009-11-05 14:31:03 +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:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferVSprintf(&buf,
|
2009-11-05 14:31:03 +00:00
|
|
|
"socket,id=%s,path=%s%s",
|
Convert character devices over to use -device
The current character device syntax uses either
-serial tty,path=/dev/ttyS2
Or
-chardev tty,id=serial0,path=/dev/ttyS2 -serial chardev:serial0
With the new -device support, we now prefer
-chardev file,id=serial0,path=/tmp/serial.log -device isa-serial,chardev=serial0
This patch changes the existing -chardev syntax to use this new
scheme, and fallbacks to the old plain -serial syntax for old
QEMU.
The monitor device changes to
-chardev socket,id=monitor,path=/tmp/test-monitor,server,nowait -mon chardev=monitor
In addition, this patch adds --nodefaults, which kills off the
default serial, parallel, vga and nic devices. THis avoids the
need for us to explicitly turn each off
2009-12-14 18:04:35 +00:00
|
|
|
dev->info.alias,
|
2009-11-05 14:31:03 +00:00
|
|
|
dev->data.nix.path,
|
|
|
|
dev->data.nix.listen ? ",server,nowait" : "");
|
|
|
|
break;
|
|
|
|
}
|
2010-01-26 13:00:18 +00:00
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-01-26 13:00:18 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
2009-11-05 14:31:03 +00:00
|
|
|
}
|
|
|
|
|
2010-01-26 13:00:18 +00:00
|
|
|
|
|
|
|
char *
|
|
|
|
qemuBuildChrArgStr(virDomainChrDefPtr dev, const char *prefix)
|
2008-04-25 20:46:13 +00:00
|
|
|
{
|
2010-01-26 13:00:18 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
if (prefix)
|
|
|
|
virBufferAdd(&buf, prefix, strlen(prefix));
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
switch (dev->type) {
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_NULL:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferAddLit(&buf, "null");
|
2008-04-25 20:46:13 +00:00
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_VC:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferAddLit(&buf, "vc");
|
2008-04-25 20:46:13 +00:00
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_PTY:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferAddLit(&buf, "pty");
|
2008-04-25 20:46:13 +00:00
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_DEV:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferStrcat(&buf, dev->data.file.path, NULL);
|
2008-04-25 20:46:13 +00:00
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_FILE:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferVSprintf(&buf, "file:%s", dev->data.file.path);
|
2008-04-25 20:46:13 +00:00
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_PIPE:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferVSprintf(&buf, "pipe:%s", dev->data.file.path);
|
2008-04-25 20:46:13 +00:00
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_STDIO:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferAddLit(&buf, "stdio");
|
2008-04-25 20:46:13 +00:00
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_UDP:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferVSprintf(&buf, "udp:%s:%s@%s:%s",
|
2009-11-06 13:44:25 +00:00
|
|
|
dev->data.udp.connectHost,
|
|
|
|
dev->data.udp.connectService,
|
|
|
|
dev->data.udp.bindHost,
|
|
|
|
dev->data.udp.bindService);
|
2008-04-25 20:46:13 +00:00
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_TCP:
|
2008-08-15 10:02:33 +00:00
|
|
|
if (dev->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET) {
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferVSprintf(&buf, "telnet:%s:%s%s",
|
2009-11-06 13:44:25 +00:00
|
|
|
dev->data.tcp.host,
|
|
|
|
dev->data.tcp.service,
|
|
|
|
dev->data.tcp.listen ? ",server,nowait" : "");
|
2008-08-15 10:02:33 +00:00
|
|
|
} else {
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferVSprintf(&buf, "tcp:%s:%s%s",
|
2009-11-06 13:44:25 +00:00
|
|
|
dev->data.tcp.host,
|
|
|
|
dev->data.tcp.service,
|
|
|
|
dev->data.tcp.listen ? ",server,nowait" : "");
|
2008-08-15 10:02:33 +00:00
|
|
|
}
|
2008-04-25 20:46:13 +00:00
|
|
|
break;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
2010-01-26 13:00:18 +00:00
|
|
|
virBufferVSprintf(&buf, "unix:%s%s",
|
2009-11-06 13:44:25 +00:00
|
|
|
dev->data.nix.path,
|
|
|
|
dev->data.nix.listen ? ",server,nowait" : "");
|
2008-04-25 20:46:13 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-01-26 13:00:18 +00:00
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-01-26 13:00:18 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
2008-04-25 20:46:13 +00:00
|
|
|
}
|
|
|
|
|
2009-12-18 15:24:14 +00:00
|
|
|
|
2010-02-18 16:56:50 +00:00
|
|
|
char *
|
|
|
|
qemuBuildVirtioSerialPortDevStr(virDomainChrDefPtr dev)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
virBufferAddLit(&buf, "virtserialport");
|
|
|
|
|
|
|
|
if (dev->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
|
|
|
|
/* Check it's a virtio-serial address */
|
|
|
|
if (dev->info.type !=
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL)
|
|
|
|
{
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("virtio serial device has invalid address type"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferVSprintf(&buf,
|
|
|
|
",bus=" QEMU_VIRTIO_SERIAL_PREFIX "%d.%d",
|
|
|
|
dev->info.addr.vioserial.controller,
|
|
|
|
dev->info.addr.vioserial.bus);
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferVSprintf(&buf, ",chardev=%s", dev->info.alias);
|
|
|
|
if (dev->target.name) {
|
|
|
|
virBufferVSprintf(&buf, ",name=%s", dev->target.name);
|
|
|
|
}
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-02 18:07:12 +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:
|
2010-02-02 18:37:33 +00:00
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
|
2010-02-02 18:07:12 +00:00
|
|
|
virBufferAddLit(&buf, "base=localtime");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE: {
|
|
|
|
time_t now = time(NULL);
|
|
|
|
struct tm nowbits;
|
|
|
|
|
|
|
|
now += def->data.adjustment;
|
|
|
|
gmtime_r(&now, &nowbits);
|
|
|
|
|
|
|
|
virBufferVSprintf(&buf, "base=%d-%d-%dT%d:%d:%d",
|
|
|
|
nowbits.tm_year + 1900,
|
|
|
|
nowbits.tm_mon,
|
|
|
|
nowbits.tm_mday,
|
|
|
|
nowbits.tm_hour,
|
|
|
|
nowbits.tm_min,
|
|
|
|
nowbits.tm_sec);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported clock offset '%s'"),
|
|
|
|
virDomainClockOffsetTypeToString(def->offset));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-18 15:24:14 +00:00
|
|
|
static int
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuBuildCpuArgStr(const struct qemud_driver *driver,
|
2010-01-26 13:00:18 +00:00
|
|
|
const virDomainDefPtr def,
|
|
|
|
const char *emulator,
|
|
|
|
const struct utsname *ut,
|
|
|
|
char **opt)
|
2009-12-18 15:24:14 +00:00
|
|
|
{
|
|
|
|
const virCPUDefPtr host = driver->caps->host.cpu;
|
|
|
|
virCPUDefPtr guest = NULL;
|
2009-12-22 11:23:56 +00:00
|
|
|
unsigned int ncpus = 0;
|
2009-12-18 15:24:14 +00:00
|
|
|
const char **cpus = NULL;
|
|
|
|
union cpuData *data = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
int i;
|
|
|
|
|
2009-12-22 11:23:56 +00:00
|
|
|
if (def->cpu && def->cpu->model
|
|
|
|
&& qemudProbeCPUModels(emulator, ut->machine, &ncpus, &cpus) < 0)
|
2009-12-18 15:24:14 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2009-12-22 11:23:56 +00:00
|
|
|
if (ncpus > 0 && host) {
|
2009-12-18 15:24:14 +00:00
|
|
|
virCPUCompareResult cmp;
|
|
|
|
|
2010-02-10 12:22:36 +00:00
|
|
|
cmp = cpuGuestData(host, def->cpu, &data);
|
2009-12-18 15:24:14 +00:00
|
|
|
switch (cmp) {
|
|
|
|
case VIR_CPU_COMPARE_INCOMPATIBLE:
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("guest CPU is not compatible with host CPU"));
|
2009-12-18 15:24:14 +00:00
|
|
|
/* fall through */
|
|
|
|
case VIR_CPU_COMPARE_ERROR:
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(guest) < 0 || !(guest->arch = strdup(ut->machine)))
|
|
|
|
goto no_memory;
|
|
|
|
|
2010-02-11 09:47:43 +00:00
|
|
|
if (cpuDecode(guest, data, cpus, ncpus) < 0)
|
2009-12-18 15:24:14 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
virBufferVSprintf(&buf, "%s", guest->model);
|
|
|
|
for (i = 0; i < guest->nfeatures; i++)
|
|
|
|
virBufferVSprintf(&buf, ",+%s", guest->features[i].name);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* 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")) ||
|
|
|
|
strstr(emulator, "x86_64")))
|
|
|
|
virBufferAddLit(&buf, "qemu32");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferError(&buf))
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
*opt = virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virCPUDefFree(guest);
|
2010-02-10 12:22:36 +00:00
|
|
|
cpuDataFree(ut->machine, data);
|
2009-12-18 15:24:14 +00:00
|
|
|
|
|
|
|
if (cpus) {
|
|
|
|
for (i = 0; i < ncpus; i++)
|
|
|
|
VIR_FREE(cpus[i]);
|
|
|
|
VIR_FREE(cpus);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
no_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-12-18 15:24:14 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-01-18 15:51:52 +00:00
|
|
|
static char *
|
2010-02-04 18:19:08 +00:00
|
|
|
qemuBuildSmpArgStr(const virDomainDefPtr def,
|
2010-02-09 13:06:56 +00:00
|
|
|
unsigned long long qemuCmdFlags)
|
2010-01-18 15:51:52 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
virBufferVSprintf(&buf, "%lu", def->vcpus);
|
|
|
|
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_SMP_TOPOLOGY)) {
|
|
|
|
/* 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) {
|
|
|
|
virBufferVSprintf(&buf, ",sockets=%u", def->cpu->sockets);
|
|
|
|
virBufferVSprintf(&buf, ",cores=%u", def->cpu->cores);
|
|
|
|
virBufferVSprintf(&buf, ",threads=%u", def->cpu->threads);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
virBufferVSprintf(&buf, ",sockets=%lu", def->vcpus);
|
|
|
|
virBufferVSprintf(&buf, ",cores=%u", 1);
|
|
|
|
virBufferVSprintf(&buf, ",threads=%u", 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virBufferFreeAndReset(&buf);
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-01-18 15:51:52 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
|
2009-12-18 15:24:14 +00:00
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
/*
|
|
|
|
* Constructs a argv suitable for launching qemu with config defined
|
|
|
|
* for a given virtual machine.
|
2010-02-09 18:15:41 +00:00
|
|
|
*
|
|
|
|
* XXX 'conn' is only required to resolve network -> bridge name
|
|
|
|
* figure out how to remove this requirement some day
|
2007-02-14 01:40:09 +00:00
|
|
|
*/
|
2007-07-12 15:09:01 +00:00
|
|
|
int qemudBuildCommandLine(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
2009-04-19 14:50:01 +00:00
|
|
|
virDomainDefPtr def,
|
2009-07-09 17:06:38 +00:00
|
|
|
virDomainChrDefPtr monitor_chr,
|
2009-11-03 18:59:18 +00:00
|
|
|
int monitor_json,
|
2010-02-09 13:06:56 +00:00
|
|
|
unsigned long long qemuCmdFlags,
|
2008-08-08 15:43:38 +00:00
|
|
|
const char ***retargv,
|
2008-10-10 16:52:20 +00:00
|
|
|
const char ***retenv,
|
2008-07-11 19:34:11 +00:00
|
|
|
int **tapfds,
|
|
|
|
int *ntapfds,
|
|
|
|
const char *migrateFrom) {
|
2008-05-22 23:45:09 +00:00
|
|
|
int i;
|
2007-02-14 01:40:09 +00:00
|
|
|
char memory[50];
|
2008-07-11 19:34:11 +00:00
|
|
|
char boot[VIR_DOMAIN_BOOT_LAST];
|
2007-04-16 13:14:28 +00:00
|
|
|
struct utsname ut;
|
|
|
|
int disableKQEMU = 0;
|
2009-03-20 11:20:26 +00:00
|
|
|
int disableKVM = 0;
|
2009-11-20 14:41:05 +00:00
|
|
|
int enableKVM = 0;
|
2008-05-22 23:45:09 +00:00
|
|
|
int qargc = 0, qarga = 0;
|
2008-08-08 15:43:38 +00:00
|
|
|
const char **qargv = NULL;
|
2008-10-10 16:52:20 +00:00
|
|
|
int qenvc = 0, qenva = 0;
|
|
|
|
const char **qenv = NULL;
|
2008-09-05 11:52:12 +00:00
|
|
|
const char *emulator;
|
2008-11-04 22:15:30 +00:00
|
|
|
char uuid[VIR_UUID_STRING_BUFLEN];
|
|
|
|
char domid[50];
|
2009-12-18 15:24:14 +00:00
|
|
|
char *cpu;
|
2010-01-18 15:51:52 +00:00
|
|
|
char *smp;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-01-30 19:57:20 +00:00
|
|
|
uname_normalize(&ut);
|
2007-04-16 13:14:28 +00:00
|
|
|
|
2010-02-01 15:58:38 +00:00
|
|
|
if (qemuAssignDeviceAliases(def, qemuCmdFlags) < 0)
|
|
|
|
return -1;
|
2010-01-06 12:11:26 +00:00
|
|
|
|
2009-04-19 14:50:01 +00:00
|
|
|
virUUIDFormat(def->uuid, uuid);
|
2008-11-04 22:15:30 +00:00
|
|
|
|
2009-01-29 17:27:54 +00:00
|
|
|
/* Migration is very annoying due to wildly varying syntax & capabilities
|
|
|
|
* over time of KVM / QEMU codebases
|
|
|
|
*/
|
|
|
|
if (migrateFrom) {
|
|
|
|
if (STRPREFIX(migrateFrom, "tcp")) {
|
|
|
|
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP)) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
"%s", _("TCP migration is not supported with this QEMU binary"));
|
2009-01-29 17:27:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else if (STREQ(migrateFrom, "stdio")) {
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC) {
|
|
|
|
migrateFrom = "exec:cat";
|
|
|
|
} else if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_KVM_STDIO)) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
"%s", _("STDIO migration is not supported with this QEMU binary"));
|
2009-01-29 17:27:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else if (STRPREFIX(migrateFrom, "exec")) {
|
|
|
|
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC)) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
"%s", _("STDIO migration is not supported with this QEMU binary"));
|
2009-01-29 17:27:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-19 14:50:01 +00:00
|
|
|
emulator = def->emulator;
|
2009-03-20 11:20:26 +00:00
|
|
|
|
2007-04-16 13:14:28 +00:00
|
|
|
/* Need to explicitly disable KQEMU if
|
2009-07-22 18:51:28 +00:00
|
|
|
* 1. Guest domain is 'qemu'
|
|
|
|
* 2. The qemu binary has the -no-kqemu flag
|
2007-04-16 13:14:28 +00:00
|
|
|
*/
|
2008-07-11 19:34:11 +00:00
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU) &&
|
2009-04-19 14:50:01 +00:00
|
|
|
def->virtType == VIR_DOMAIN_VIRT_QEMU)
|
2007-04-16 13:14:28 +00:00
|
|
|
disableKQEMU = 1;
|
|
|
|
|
2009-03-20 11:20:26 +00:00
|
|
|
/* Need to explicitly disable KVM if
|
2009-07-22 18:51:28 +00:00
|
|
|
* 1. Guest domain is 'qemu'
|
|
|
|
* 2. The qemu binary has the -no-kvm flag
|
2009-03-20 11:20:26 +00:00
|
|
|
*/
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_KVM) &&
|
2009-04-19 14:50:01 +00:00
|
|
|
def->virtType == VIR_DOMAIN_VIRT_QEMU)
|
2009-03-20 11:20:26 +00:00
|
|
|
disableKVM = 1;
|
|
|
|
|
2009-11-20 14:41:05 +00:00
|
|
|
/* Should explicitly enable KVM if
|
|
|
|
* 1. Guest domain is 'kvm'
|
|
|
|
* 2. The qemu binary has the -enable-kvm flag
|
|
|
|
* NOTE: user must be responsible for loading the kvm modules
|
|
|
|
*/
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_ENABLE_KVM) &&
|
|
|
|
def->virtType == VIR_DOMAIN_VIRT_KVM)
|
|
|
|
enableKVM = 1;
|
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
#define ADD_ARG_SPACE \
|
|
|
|
do { \
|
|
|
|
if (qargc == qarga) { \
|
|
|
|
qarga += 10; \
|
|
|
|
if (VIR_REALLOC_N(qargv, qarga) < 0) \
|
|
|
|
goto no_memory; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define ADD_ARG(thisarg) \
|
|
|
|
do { \
|
|
|
|
ADD_ARG_SPACE; \
|
|
|
|
qargv[qargc++] = thisarg; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define ADD_ARG_LIT(thisarg) \
|
|
|
|
do { \
|
|
|
|
ADD_ARG_SPACE; \
|
|
|
|
if ((qargv[qargc++] = strdup(thisarg)) == NULL) \
|
|
|
|
goto no_memory; \
|
|
|
|
} while (0)
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-08-08 15:03:00 +00:00
|
|
|
#define ADD_USBDISK(thisarg) \
|
|
|
|
do { \
|
|
|
|
ADD_ARG_LIT("-usbdevice"); \
|
|
|
|
ADD_ARG_SPACE; \
|
2008-12-23 13:03:29 +00:00
|
|
|
if ((virAsprintf((char **)&(qargv[qargc++]), \
|
|
|
|
"disk:%s", thisarg)) == -1) { \
|
2008-08-08 15:03:00 +00:00
|
|
|
goto no_memory; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2008-10-10 16:52:20 +00:00
|
|
|
#define ADD_ENV_SPACE \
|
|
|
|
do { \
|
|
|
|
if (qenvc == qenva) { \
|
|
|
|
qenva += 10; \
|
|
|
|
if (VIR_REALLOC_N(qenv, qenva) < 0) \
|
|
|
|
goto no_memory; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define ADD_ENV(thisarg) \
|
|
|
|
do { \
|
|
|
|
ADD_ENV_SPACE; \
|
|
|
|
qenv[qenvc++] = thisarg; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define ADD_ENV_LIT(thisarg) \
|
|
|
|
do { \
|
|
|
|
ADD_ENV_SPACE; \
|
|
|
|
if ((qenv[qenvc++] = strdup(thisarg)) == NULL) \
|
|
|
|
goto no_memory; \
|
|
|
|
} while (0)
|
|
|
|
|
2009-03-16 13:54:26 +00:00
|
|
|
#define ADD_ENV_PAIR(envname, val) \
|
2008-10-10 16:52:20 +00:00
|
|
|
do { \
|
|
|
|
char *envval; \
|
|
|
|
ADD_ENV_SPACE; \
|
2009-03-16 13:54:26 +00:00
|
|
|
if (virAsprintf(&envval, "%s=%s", envname, val) < 0) \
|
|
|
|
goto no_memory; \
|
|
|
|
qenv[qenvc++] = envval; \
|
|
|
|
} while (0)
|
|
|
|
|
2009-12-28 15:21:15 +00:00
|
|
|
/* Make sure to unset or set all envvars in qemuxml2argvtest.c that
|
|
|
|
* are copied here using this macro, otherwise the test may fail */
|
2009-03-16 13:54:26 +00:00
|
|
|
#define ADD_ENV_COPY(envname) \
|
|
|
|
do { \
|
|
|
|
char *val = getenv(envname); \
|
2008-10-10 16:52:20 +00:00
|
|
|
if (val != NULL) { \
|
2009-03-16 13:54:26 +00:00
|
|
|
ADD_ENV_PAIR(envname, val); \
|
2008-10-10 16:52:20 +00:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2009-03-27 11:44:29 +00:00
|
|
|
/* 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
|
|
|
|
*/
|
2009-04-19 14:50:01 +00:00
|
|
|
snprintf(memory, sizeof(memory), "%lu", def->maxmem/1024);
|
|
|
|
snprintf(domid, sizeof(domid), "%d", def->id);
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-10-10 16:52:20 +00:00
|
|
|
ADD_ENV_LIT("LC_ALL=C");
|
|
|
|
|
|
|
|
ADD_ENV_COPY("LD_PRELOAD");
|
|
|
|
ADD_ENV_COPY("LD_LIBRARY_PATH");
|
|
|
|
ADD_ENV_COPY("PATH");
|
|
|
|
ADD_ENV_COPY("HOME");
|
|
|
|
ADD_ENV_COPY("USER");
|
|
|
|
ADD_ENV_COPY("LOGNAME");
|
|
|
|
ADD_ENV_COPY("TMPDIR");
|
|
|
|
|
2008-09-09 13:44:42 +00:00
|
|
|
ADD_ARG_LIT(emulator);
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-S");
|
2009-01-30 17:12:28 +00:00
|
|
|
|
|
|
|
/* This should *never* be NULL, since we always provide
|
|
|
|
* a machine in the capabilities data for QEMU. So this
|
|
|
|
* check is just here as a safety in case the unexpected
|
|
|
|
* happens */
|
2009-04-19 14:50:01 +00:00
|
|
|
if (def->os.machine) {
|
2009-01-30 17:12:28 +00:00
|
|
|
ADD_ARG_LIT("-M");
|
2009-04-19 14:50:01 +00:00
|
|
|
ADD_ARG_LIT(def->os.machine);
|
2009-01-30 17:12:28 +00:00
|
|
|
}
|
2009-12-18 15:24:14 +00:00
|
|
|
|
2010-02-09 18:15:41 +00:00
|
|
|
if (qemuBuildCpuArgStr(driver, def, emulator, &ut, &cpu) < 0)
|
2009-12-18 15:24:14 +00:00
|
|
|
goto error;
|
|
|
|
|
2009-03-20 11:20:26 +00:00
|
|
|
if (cpu) {
|
|
|
|
ADD_ARG_LIT("-cpu");
|
|
|
|
ADD_ARG_LIT(cpu);
|
2009-12-18 15:24:14 +00:00
|
|
|
VIR_FREE(cpu);
|
2009-03-20 11:20:26 +00:00
|
|
|
}
|
2009-01-30 17:12:28 +00:00
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
if (disableKQEMU)
|
|
|
|
ADD_ARG_LIT("-no-kqemu");
|
2009-03-20 11:20:26 +00:00
|
|
|
if (disableKVM)
|
|
|
|
ADD_ARG_LIT("-no-kvm");
|
2009-11-20 14:41:05 +00:00
|
|
|
if (enableKVM)
|
|
|
|
ADD_ARG_LIT("-enable-kvm");
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-m");
|
|
|
|
ADD_ARG_LIT(memory);
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 14:05:18 +00:00
|
|
|
if (def->hugepage_backed) {
|
|
|
|
if (!driver->hugetlbfs_mount) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("hugetlbfs filesystem is not mounted"));
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 14:05:18 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!driver->hugepage_path) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("hugepages are disabled by administrator config"));
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 14:05:18 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MEM_PATH)) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("hugepage backing not supported by '%s'"),
|
|
|
|
def->emulator);
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 14:05:18 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2010-01-07 13:48:06 +00:00
|
|
|
ADD_ARG_LIT("-mem-prealloc");
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 14:05:18 +00:00
|
|
|
ADD_ARG_LIT("-mem-path");
|
|
|
|
ADD_ARG_LIT(driver->hugepage_path);
|
|
|
|
}
|
2010-01-18 15:51:52 +00:00
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-smp");
|
2010-02-04 18:19:08 +00:00
|
|
|
if (!(smp = qemuBuildSmpArgStr(def, qemuCmdFlags)))
|
2010-01-18 15:51:52 +00:00
|
|
|
goto error;
|
|
|
|
ADD_ARG(smp);
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_NAME) {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-name");
|
2009-04-19 14:50:01 +00:00
|
|
|
ADD_ARG_LIT(def->name);
|
2008-05-15 16:15:17 +00:00
|
|
|
}
|
2008-11-04 22:15:30 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_UUID) {
|
|
|
|
ADD_ARG_LIT("-uuid");
|
|
|
|
ADD_ARG_LIT(uuid);
|
|
|
|
}
|
2009-08-25 13:17:29 +00:00
|
|
|
if (def->virtType == VIR_DOMAIN_VIRT_XEN ||
|
|
|
|
STREQ(def->os.type, "xen") ||
|
|
|
|
STREQ(def->os.type, "linux")) {
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DOMID) {
|
|
|
|
ADD_ARG_LIT("-domid");
|
|
|
|
ADD_ARG_LIT(domid);
|
|
|
|
} else if (qemuCmdFlags & QEMUD_CMD_FLAG_XEN_DOMID) {
|
|
|
|
ADD_ARG_LIT("-xen-attach");
|
|
|
|
ADD_ARG_LIT("-xen-domid");
|
|
|
|
ADD_ARG_LIT(domid);
|
|
|
|
} else {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("qemu emulator '%s' does not support xen"),
|
|
|
|
def->emulator);
|
2009-08-25 13:17:29 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2008-11-04 22:15:30 +00:00
|
|
|
}
|
|
|
|
|
2007-07-24 14:30:05 +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...
|
|
|
|
*/
|
2009-04-19 14:50:01 +00:00
|
|
|
if (!def->graphics)
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-nographic");
|
2007-07-24 14:30:05 +00:00
|
|
|
|
2009-12-21 20:36:32 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
|
|
|
|
ADD_ARG_LIT("-nodefaults");
|
|
|
|
|
2009-07-09 17:06:38 +00:00
|
|
|
if (monitor_chr) {
|
2010-01-26 13:00:18 +00:00
|
|
|
char *chrdev;
|
2009-12-14 09:38:44 +00:00
|
|
|
/* Use -chardev if it's available */
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) {
|
|
|
|
|
|
|
|
ADD_ARG_LIT("-chardev");
|
2010-01-26 13:00:18 +00:00
|
|
|
if (!(chrdev = qemuBuildChrChardevStr(monitor_chr)))
|
|
|
|
goto error;
|
|
|
|
ADD_ARG(chrdev);
|
2009-12-14 09:38:44 +00:00
|
|
|
|
Convert character devices over to use -device
The current character device syntax uses either
-serial tty,path=/dev/ttyS2
Or
-chardev tty,id=serial0,path=/dev/ttyS2 -serial chardev:serial0
With the new -device support, we now prefer
-chardev file,id=serial0,path=/tmp/serial.log -device isa-serial,chardev=serial0
This patch changes the existing -chardev syntax to use this new
scheme, and fallbacks to the old plain -serial syntax for old
QEMU.
The monitor device changes to
-chardev socket,id=monitor,path=/tmp/test-monitor,server,nowait -mon chardev=monitor
In addition, this patch adds --nodefaults, which kills off the
default serial, parallel, vga and nic devices. THis avoids the
need for us to explicitly turn each off
2009-12-14 18:04:35 +00:00
|
|
|
ADD_ARG_LIT("-mon");
|
|
|
|
if (monitor_json)
|
|
|
|
ADD_ARG_LIT("chardev=monitor,mode=control");
|
|
|
|
else
|
|
|
|
ADD_ARG_LIT("chardev=monitor,mode=readline");
|
|
|
|
} else {
|
2010-01-26 13:00:18 +00:00
|
|
|
const char *prefix = NULL;
|
2009-12-14 09:38:44 +00:00
|
|
|
if (monitor_json)
|
2010-01-26 13:00:18 +00:00
|
|
|
prefix = "control,";
|
2009-07-09 17:06:38 +00:00
|
|
|
|
Convert character devices over to use -device
The current character device syntax uses either
-serial tty,path=/dev/ttyS2
Or
-chardev tty,id=serial0,path=/dev/ttyS2 -serial chardev:serial0
With the new -device support, we now prefer
-chardev file,id=serial0,path=/tmp/serial.log -device isa-serial,chardev=serial0
This patch changes the existing -chardev syntax to use this new
scheme, and fallbacks to the old plain -serial syntax for old
QEMU.
The monitor device changes to
-chardev socket,id=monitor,path=/tmp/test-monitor,server,nowait -mon chardev=monitor
In addition, this patch adds --nodefaults, which kills off the
default serial, parallel, vga and nic devices. THis avoids the
need for us to explicitly turn each off
2009-12-14 18:04:35 +00:00
|
|
|
ADD_ARG_LIT("-monitor");
|
2010-01-26 13:00:18 +00:00
|
|
|
if (!(chrdev = qemuBuildChrArgStr(monitor_chr, prefix)))
|
|
|
|
goto error;
|
|
|
|
ADD_ARG(chrdev);
|
Convert character devices over to use -device
The current character device syntax uses either
-serial tty,path=/dev/ttyS2
Or
-chardev tty,id=serial0,path=/dev/ttyS2 -serial chardev:serial0
With the new -device support, we now prefer
-chardev file,id=serial0,path=/tmp/serial.log -device isa-serial,chardev=serial0
This patch changes the existing -chardev syntax to use this new
scheme, and fallbacks to the old plain -serial syntax for old
QEMU.
The monitor device changes to
-chardev socket,id=monitor,path=/tmp/test-monitor,server,nowait -mon chardev=monitor
In addition, this patch adds --nodefaults, which kills off the
default serial, parallel, vga and nic devices. THis avoids the
need for us to explicitly turn each off
2009-12-14 18:04:35 +00:00
|
|
|
}
|
2009-07-09 17:06:38 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2010-02-02 18:07:12 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_RTC) {
|
|
|
|
const char *rtcopt;
|
|
|
|
ADD_ARG_LIT("-rtc");
|
|
|
|
if (!(rtcopt = qemuBuildClockArgStr(&def->clock)))
|
|
|
|
goto error;
|
|
|
|
ADD_ARG(rtcopt);
|
|
|
|
} else {
|
|
|
|
switch (def->clock.offset) {
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
|
2010-02-02 18:37:33 +00:00
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
|
2010-02-02 18:07:12 +00:00
|
|
|
ADD_ARG_LIT("-localtime");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_UTC:
|
|
|
|
/* Nothing, its the default */
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported clock offset '%s'"),
|
|
|
|
virDomainClockOffsetTypeToString(def->clock.offset));
|
|
|
|
goto error;
|
|
|
|
}
|
2010-02-02 17:22:03 +00:00
|
|
|
}
|
2010-02-02 18:37:33 +00:00
|
|
|
if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE &&
|
|
|
|
def->clock.data.timezone) {
|
|
|
|
ADD_ENV_PAIR("TZ", def->clock.data.timezone);
|
|
|
|
}
|
2007-07-16 21:30:30 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_NO_REBOOT) &&
|
2009-04-19 14:50:01 +00:00
|
|
|
def->onReboot != VIR_DOMAIN_LIFECYCLE_RESTART)
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-no-reboot");
|
2007-05-03 16:10:40 +00:00
|
|
|
|
2009-04-19 14:50:01 +00:00
|
|
|
if (!(def->features & (1 << VIR_DOMAIN_FEATURE_ACPI)))
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-no-acpi");
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-04-19 14:50:01 +00:00
|
|
|
if (!def->os.bootloader) {
|
|
|
|
for (i = 0 ; i < def->os.nBootDevs ; i++) {
|
|
|
|
switch (def->os.bootDevs[i]) {
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_BOOT_CDROM:
|
2008-05-15 16:21:11 +00:00
|
|
|
boot[i] = 'd';
|
|
|
|
break;
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_BOOT_FLOPPY:
|
2008-05-15 16:21:11 +00:00
|
|
|
boot[i] = 'a';
|
|
|
|
break;
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_BOOT_DISK:
|
2008-05-15 16:21:11 +00:00
|
|
|
boot[i] = 'c';
|
|
|
|
break;
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_BOOT_NET:
|
2008-05-15 16:21:11 +00:00
|
|
|
boot[i] = 'n';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
boot[i] = 'c';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-08-25 13:17:29 +00:00
|
|
|
if (def->os.nBootDevs) {
|
|
|
|
boot[def->os.nBootDevs] = '\0';
|
|
|
|
ADD_ARG_LIT("-boot");
|
|
|
|
ADD_ARG_LIT(boot);
|
|
|
|
}
|
2008-05-15 16:21:11 +00:00
|
|
|
|
2009-04-19 14:50:01 +00:00
|
|
|
if (def->os.kernel) {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-kernel");
|
2009-04-19 14:50:01 +00:00
|
|
|
ADD_ARG_LIT(def->os.kernel);
|
2008-05-15 16:21:11 +00:00
|
|
|
}
|
2009-04-19 14:50:01 +00:00
|
|
|
if (def->os.initrd) {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-initrd");
|
2009-04-19 14:50:01 +00:00
|
|
|
ADD_ARG_LIT(def->os.initrd);
|
2008-05-15 16:21:11 +00:00
|
|
|
}
|
2009-04-19 14:50:01 +00:00
|
|
|
if (def->os.cmdline) {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-append");
|
2009-04-19 14:50:01 +00:00
|
|
|
ADD_ARG_LIT(def->os.cmdline);
|
2008-05-15 16:21:11 +00:00
|
|
|
}
|
|
|
|
} else {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-bootloader");
|
2009-04-19 14:50:01 +00:00
|
|
|
ADD_ARG_LIT(def->os.bootloader);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2009-04-19 14:50:01 +00:00
|
|
|
for (i = 0 ; i < def->ndisks ; i++) {
|
|
|
|
virDomainDiskDefPtr disk = def->disks[i];
|
2009-01-23 16:22:20 +00:00
|
|
|
|
|
|
|
if (disk->driverName != NULL &&
|
|
|
|
!STREQ(disk->driverName, "qemu")) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported driver name '%s' for disk '%s'"),
|
|
|
|
disk->driverName, disk->src);
|
2009-01-23 16:22:20 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
for (i = 0 ; i < def->ncontrollers ; i++) {
|
2010-02-01 15:08:36 +00:00
|
|
|
virDomainControllerDefPtr cont = def->controllers[i];
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE ||
|
|
|
|
cont->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC)
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
continue;
|
|
|
|
|
2010-02-01 15:08:36 +00:00
|
|
|
/* QEMU doesn't implement a SATA driver */
|
|
|
|
if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_SATA) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
"%s", _("SATA is not supported with this QEMU binary"));
|
2010-02-01 15:08:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
ADD_ARG_LIT("-device");
|
|
|
|
|
2010-02-01 15:08:36 +00:00
|
|
|
char *devstr;
|
|
|
|
if (!(devstr = qemuBuildControllerDevStr(def->controllers[i])))
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2010-02-01 15:08:36 +00:00
|
|
|
ADD_ARG(devstr);
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-09 16:41:19 +00:00
|
|
|
/* If QEMU supports -drive param instead of old -hda, -hdb, -cdrom .. */
|
2008-07-11 19:34:11 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE) {
|
2008-05-09 16:41:19 +00:00
|
|
|
int bootCD = 0, bootFloppy = 0, bootDisk = 0;
|
|
|
|
|
|
|
|
/* If QEMU supports boot=on for -drive param... */
|
2008-07-11 19:34:11 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_BOOT) {
|
2009-04-19 14:50:01 +00:00
|
|
|
for (i = 0 ; i < def->os.nBootDevs ; i++) {
|
|
|
|
switch (def->os.bootDevs[i]) {
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_BOOT_CDROM:
|
2008-05-09 16:41:19 +00:00
|
|
|
bootCD = 1;
|
|
|
|
break;
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_BOOT_FLOPPY:
|
2008-05-09 16:41:19 +00:00
|
|
|
bootFloppy = 1;
|
|
|
|
break;
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_BOOT_DISK:
|
2008-05-09 16:41:19 +00:00
|
|
|
bootDisk = 1;
|
|
|
|
break;
|
|
|
|
}
|
2008-03-13 09:17:45 +00:00
|
|
|
}
|
2008-05-09 16:41:19 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-04-19 14:50:01 +00:00
|
|
|
for (i = 0 ; i < def->ndisks ; i++) {
|
2009-01-23 16:22:20 +00:00
|
|
|
char *optstr;
|
2008-05-09 16:41:19 +00:00
|
|
|
int bootable = 0;
|
2009-04-19 14:50:01 +00:00
|
|
|
virDomainDiskDefPtr disk = def->disks[i];
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
int withDeviceArg = 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-12-14 19:15:05 +00:00
|
|
|
/* Unless we have -device, then USB disks need special
|
|
|
|
handling */
|
|
|
|
if ((disk->bus == VIR_DOMAIN_DISK_BUS_USB) &&
|
|
|
|
!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
2008-08-08 15:03:00 +00:00
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
|
|
|
|
ADD_USBDISK(disk->src);
|
|
|
|
} else {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported usb disk type for '%s'"), disk->src);
|
2008-08-08 15:03:00 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-05-09 16:41:19 +00:00
|
|
|
switch (disk->device) {
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_DISK_DEVICE_CDROM:
|
2008-05-09 16:41:19 +00:00
|
|
|
bootable = bootCD;
|
|
|
|
bootCD = 0;
|
|
|
|
break;
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
|
2008-05-09 16:41:19 +00:00
|
|
|
bootable = bootFloppy;
|
|
|
|
bootFloppy = 0;
|
|
|
|
break;
|
2008-07-11 19:34:11 +00:00
|
|
|
case VIR_DOMAIN_DISK_DEVICE_DISK:
|
2008-05-09 16:41:19 +00:00
|
|
|
bootable = bootDisk;
|
|
|
|
bootDisk = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-12-10 21:11:56 +00:00
|
|
|
ADD_ARG_LIT("-drive");
|
2009-01-23 16:22:20 +00:00
|
|
|
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
/* Unfortunately it is nt possible to use
|
|
|
|
-device for floppys, or Xen paravirt
|
|
|
|
devices. Fortunately, those don't need
|
|
|
|
static PCI addresses, so we don't really
|
|
|
|
care that we can't use -device */
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
|
|
|
|
(disk->bus != VIR_DOMAIN_DISK_BUS_XEN))
|
|
|
|
withDeviceArg = 1;
|
|
|
|
if (!(optstr = qemuBuildDriveStr(disk, bootable,
|
|
|
|
(withDeviceArg ? qemuCmdFlags :
|
|
|
|
(qemuCmdFlags & ~QEMUD_CMD_FLAG_DEVICE)))))
|
2009-12-10 21:11:56 +00:00
|
|
|
goto error;
|
2009-01-23 16:22:20 +00:00
|
|
|
ADD_ARG(optstr);
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
|
|
|
|
if (withDeviceArg) {
|
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
|
|
|
|
char *fdc;
|
|
|
|
ADD_ARG_LIT("-global");
|
|
|
|
|
2010-02-10 09:22:42 +00:00
|
|
|
if (virAsprintf(&fdc, "isa-fdc.drive%c=drive-%s",
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
disk->info.addr.drive.unit ? 'B' : 'A',
|
|
|
|
disk->info.alias) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
ADD_ARG(fdc);
|
|
|
|
} else {
|
|
|
|
ADD_ARG_LIT("-device");
|
|
|
|
|
2010-02-09 18:15:41 +00:00
|
|
|
if (!(optstr = qemuBuildDriveDevStr(disk)))
|
Convert disk drive over to use -device where available
The current preferred syntax for disk drives uses
-drive file=/vms/plain.qcow,if=virtio,index=0,boot=on,format=qcow
The new syntax splits this up into a pair of linked args
-drive file=/vms/plain.qcow,if=none,id=drive-virtio-0,format=qcow2
-device virtio-blk-pci,drive=drive-virtio-0,id=virtio-0,addr=<PCI SLOT>
SCSI/IDE devices also get a bus property linking them to the
controller
-device scsi-disk,drive=drive-scsi0-0-0,id=scsi0-0-0,bus=scsi0.0,scsi-id=0
-device ide-drive,drive=drive-ide0-0-0,id=ide0-0-0,bus=ide0,unit=0
2009-12-14 18:30:09 +00:00
|
|
|
goto error;
|
|
|
|
ADD_ARG(optstr);
|
|
|
|
}
|
|
|
|
}
|
2008-05-09 16:41:19 +00:00
|
|
|
}
|
|
|
|
} else {
|
2009-04-19 14:50:01 +00:00
|
|
|
for (i = 0 ; i < def->ndisks ; i++) {
|
2008-05-09 16:41:19 +00:00
|
|
|
char dev[NAME_MAX];
|
|
|
|
char file[PATH_MAX];
|
2009-04-19 14:50:01 +00:00
|
|
|
virDomainDiskDefPtr disk = def->disks[i];
|
2008-05-09 16:41:19 +00:00
|
|
|
|
2008-08-08 15:03:00 +00:00
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
|
|
|
|
ADD_USBDISK(disk->src);
|
|
|
|
} else {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported usb disk type for '%s'"), disk->src);
|
2008-08-08 15:03:00 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-05-09 16:41:19 +00:00
|
|
|
if (STREQ(disk->dst, "hdc") &&
|
2008-07-11 19:34:11 +00:00
|
|
|
disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
|
|
|
|
if (disk->src) {
|
2008-05-09 16:41:19 +00:00
|
|
|
snprintf(dev, NAME_MAX, "-%s", "cdrom");
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (STRPREFIX(disk->dst, "hd") ||
|
|
|
|
STRPREFIX(disk->dst, "fd")) {
|
|
|
|
snprintf(dev, NAME_MAX, "-%s", disk->dst);
|
|
|
|
} else {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported disk type '%s'"), disk->dst);
|
2008-05-09 16:41:19 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-16 18:08:29 +00:00
|
|
|
if (disk->type == VIR_DOMAIN_DISK_TYPE_DIR) {
|
|
|
|
/* QEMU only supports magic FAT format for now */
|
|
|
|
if (disk->driverType &&
|
|
|
|
STRNEQ(disk->driverType, "fat")) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported disk driver type for '%s'"),
|
|
|
|
disk->driverType);
|
2009-11-16 18:08:29 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!disk->readonly) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot create virtual FAT disks in read-write mode"));
|
2009-11-16 18:08:29 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
|
|
|
|
snprintf(file, PATH_MAX, "fat:floppy:%s", disk->src);
|
|
|
|
else
|
|
|
|
snprintf(file, PATH_MAX, "fat:%s", disk->src);
|
|
|
|
} else {
|
|
|
|
snprintf(file, PATH_MAX, "%s", disk->src);
|
|
|
|
}
|
2008-05-09 16:41:19 +00:00
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT(dev);
|
|
|
|
ADD_ARG_LIT(file);
|
2008-05-09 16:41:19 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2009-04-19 14:50:01 +00:00
|
|
|
if (!def->nnets) {
|
2009-12-21 20:36:32 +00:00
|
|
|
/* If we have -device, then we set -nodefault already */
|
|
|
|
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
|
|
|
ADD_ARG_LIT("-net");
|
|
|
|
ADD_ARG_LIT("none");
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
} else {
|
2009-04-19 14:50:01 +00:00
|
|
|
for (i = 0 ; i < def->nnets ; i++) {
|
|
|
|
virDomainNetDefPtr net = def->nets[i];
|
2009-07-17 21:08:33 +00:00
|
|
|
char *nic, *host;
|
Convert NICs over to use -device & -netdev where possible
The current syntax uses a pair of args
-net nic,macaddr=52:54:00:56:6c:55,vlan=3,model=pcnet,name=pcnet.0
-net user,vlan=3,name=user.0
The new syntax does not need the vlan craziness anymore, and
so has a simplified pair of args
-netdev user,id=user.0
-device pcnet,netdev=user.0,id=pcnet.0,mac=52:54:00:56:6c:55,addr=<PCI SLOT>
2009-12-14 19:09:40 +00:00
|
|
|
char tapfd_name[50];
|
2010-02-01 15:06:36 +00:00
|
|
|
int vlan;
|
2007-02-14 15:51:53 +00:00
|
|
|
|
2010-01-29 18:07:04 +00:00
|
|
|
/* VLANs are not used with -netdev, so don't record them */
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))
|
2010-02-01 15:06:36 +00:00
|
|
|
vlan = -1;
|
2010-01-29 18:07:04 +00:00
|
|
|
else
|
2010-02-01 15:06:36 +00:00
|
|
|
vlan = i;
|
2009-07-17 21:08:34 +00:00
|
|
|
|
2009-07-17 21:08:33 +00:00
|
|
|
if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
|
|
|
net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
|
2009-07-22 19:17:14 +00:00
|
|
|
int tapfd = qemudNetworkIfaceConnect(conn, driver, net, qemuCmdFlags);
|
2009-07-17 21:08:33 +00:00
|
|
|
if (tapfd < 0)
|
|
|
|
goto error;
|
2007-03-13 22:43:22 +00:00
|
|
|
|
2009-07-17 21:08:33 +00:00
|
|
|
if (VIR_REALLOC_N(*tapfds, (*ntapfds)+1) < 0) {
|
|
|
|
close(tapfd);
|
|
|
|
goto no_memory;
|
2007-03-13 22:43:22 +00:00
|
|
|
}
|
|
|
|
|
2009-07-17 21:08:33 +00:00
|
|
|
(*tapfds)[(*ntapfds)++] = tapfd;
|
2009-07-22 19:17:14 +00:00
|
|
|
|
2010-02-15 16:41:14 +00:00
|
|
|
if (snprintf(tapfd_name, sizeof(tapfd_name), "%d", tapfd) >= sizeof(tapfd_name))
|
|
|
|
goto no_memory;
|
|
|
|
} else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
|
2010-02-19 14:41:30 +00:00
|
|
|
int tapfd = qemudPhysIfaceConnect(conn, driver, net,
|
2010-02-15 16:41:14 +00:00
|
|
|
net->data.direct.linkdev,
|
2010-02-19 10:38:57 +00:00
|
|
|
net->data.direct.mode,
|
|
|
|
qemuCmdFlags);
|
2010-02-15 16:41:14 +00:00
|
|
|
if (tapfd < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(*tapfds, (*ntapfds)+1) < 0) {
|
|
|
|
close(tapfd);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*tapfds)[(*ntapfds)++] = tapfd;
|
|
|
|
|
Convert NICs over to use -device & -netdev where possible
The current syntax uses a pair of args
-net nic,macaddr=52:54:00:56:6c:55,vlan=3,model=pcnet,name=pcnet.0
-net user,vlan=3,name=user.0
The new syntax does not need the vlan craziness anymore, and
so has a simplified pair of args
-netdev user,id=user.0
-device pcnet,netdev=user.0,id=pcnet.0,mac=52:54:00:56:6c:55,addr=<PCI SLOT>
2009-12-14 19:09:40 +00:00
|
|
|
if (snprintf(tapfd_name, sizeof(tapfd_name), "%d", tapfd) >= sizeof(tapfd_name))
|
2009-07-22 19:17:14 +00:00
|
|
|
goto no_memory;
|
2007-02-14 16:09:37 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2010-01-29 18:07:04 +00:00
|
|
|
/* Possible combinations:
|
|
|
|
*
|
|
|
|
* 1. Old way: -net nic,model=e1000,vlan=1 -net tap,vlan=1
|
|
|
|
* 2. Semi-new: -device e1000,vlan=1 -net tap,vlan=1
|
|
|
|
* 3. Best way: -netdev type=tap,id=netdev1 -device e1000,id=netdev1
|
|
|
|
*
|
|
|
|
* NB, no support for -netdev without use of -device
|
|
|
|
*/
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
Convert NICs over to use -device & -netdev where possible
The current syntax uses a pair of args
-net nic,macaddr=52:54:00:56:6c:55,vlan=3,model=pcnet,name=pcnet.0
-net user,vlan=3,name=user.0
The new syntax does not need the vlan craziness anymore, and
so has a simplified pair of args
-netdev user,id=user.0
-device pcnet,netdev=user.0,id=pcnet.0,mac=52:54:00:56:6c:55,addr=<PCI SLOT>
2009-12-14 19:09:40 +00:00
|
|
|
ADD_ARG_LIT("-netdev");
|
2010-02-09 18:15:41 +00:00
|
|
|
if (!(host = qemuBuildHostNetStr(net, ',',
|
2010-02-01 15:06:36 +00:00
|
|
|
vlan, tapfd_name)))
|
Convert NICs over to use -device & -netdev where possible
The current syntax uses a pair of args
-net nic,macaddr=52:54:00:56:6c:55,vlan=3,model=pcnet,name=pcnet.0
-net user,vlan=3,name=user.0
The new syntax does not need the vlan craziness anymore, and
so has a simplified pair of args
-netdev user,id=user.0
-device pcnet,netdev=user.0,id=pcnet.0,mac=52:54:00:56:6c:55,addr=<PCI SLOT>
2009-12-14 19:09:40 +00:00
|
|
|
goto error;
|
|
|
|
ADD_ARG(host);
|
2010-01-29 18:07:04 +00:00
|
|
|
}
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
Convert NICs over to use -device & -netdev where possible
The current syntax uses a pair of args
-net nic,macaddr=52:54:00:56:6c:55,vlan=3,model=pcnet,name=pcnet.0
-net user,vlan=3,name=user.0
The new syntax does not need the vlan craziness anymore, and
so has a simplified pair of args
-netdev user,id=user.0
-device pcnet,netdev=user.0,id=pcnet.0,mac=52:54:00:56:6c:55,addr=<PCI SLOT>
2009-12-14 19:09:40 +00:00
|
|
|
ADD_ARG_LIT("-device");
|
2010-02-01 15:06:36 +00:00
|
|
|
if (!(nic = qemuBuildNicDevStr(net, vlan)))
|
Convert NICs over to use -device & -netdev where possible
The current syntax uses a pair of args
-net nic,macaddr=52:54:00:56:6c:55,vlan=3,model=pcnet,name=pcnet.0
-net user,vlan=3,name=user.0
The new syntax does not need the vlan craziness anymore, and
so has a simplified pair of args
-netdev user,id=user.0
-device pcnet,netdev=user.0,id=pcnet.0,mac=52:54:00:56:6c:55,addr=<PCI SLOT>
2009-12-14 19:09:40 +00:00
|
|
|
goto error;
|
|
|
|
ADD_ARG(nic);
|
|
|
|
} else {
|
|
|
|
ADD_ARG_LIT("-net");
|
2010-02-09 18:15:41 +00:00
|
|
|
if (!(nic = qemuBuildNicStr(net, "nic,", vlan)))
|
Convert NICs over to use -device & -netdev where possible
The current syntax uses a pair of args
-net nic,macaddr=52:54:00:56:6c:55,vlan=3,model=pcnet,name=pcnet.0
-net user,vlan=3,name=user.0
The new syntax does not need the vlan craziness anymore, and
so has a simplified pair of args
-netdev user,id=user.0
-device pcnet,netdev=user.0,id=pcnet.0,mac=52:54:00:56:6c:55,addr=<PCI SLOT>
2009-12-14 19:09:40 +00:00
|
|
|
goto error;
|
|
|
|
ADD_ARG(nic);
|
2010-01-29 18:07:04 +00:00
|
|
|
}
|
|
|
|
if (!((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))) {
|
Convert NICs over to use -device & -netdev where possible
The current syntax uses a pair of args
-net nic,macaddr=52:54:00:56:6c:55,vlan=3,model=pcnet,name=pcnet.0
-net user,vlan=3,name=user.0
The new syntax does not need the vlan craziness anymore, and
so has a simplified pair of args
-netdev user,id=user.0
-device pcnet,netdev=user.0,id=pcnet.0,mac=52:54:00:56:6c:55,addr=<PCI SLOT>
2009-12-14 19:09:40 +00:00
|
|
|
ADD_ARG_LIT("-net");
|
2010-02-09 18:15:41 +00:00
|
|
|
if (!(host = qemuBuildHostNetStr(net, ',',
|
2010-02-01 15:06:36 +00:00
|
|
|
vlan, tapfd_name)))
|
Convert NICs over to use -device & -netdev where possible
The current syntax uses a pair of args
-net nic,macaddr=52:54:00:56:6c:55,vlan=3,model=pcnet,name=pcnet.0
-net user,vlan=3,name=user.0
The new syntax does not need the vlan craziness anymore, and
so has a simplified pair of args
-netdev user,id=user.0
-device pcnet,netdev=user.0,id=pcnet.0,mac=52:54:00:56:6c:55,addr=<PCI SLOT>
2009-12-14 19:09:40 +00:00
|
|
|
goto error;
|
|
|
|
ADD_ARG(host);
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-19 14:50:01 +00:00
|
|
|
if (!def->nserials) {
|
2009-12-21 20:36:32 +00:00
|
|
|
/* If we have -device, then we set -nodefault already */
|
|
|
|
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
|
|
|
ADD_ARG_LIT("-serial");
|
|
|
|
ADD_ARG_LIT("none");
|
|
|
|
}
|
2008-04-25 20:46:13 +00:00
|
|
|
} else {
|
2009-04-19 14:50:01 +00:00
|
|
|
for (i = 0 ; i < def->nserials ; i++) {
|
|
|
|
virDomainChrDefPtr serial = def->serials[i];
|
2010-01-26 13:00:18 +00:00
|
|
|
char *devstr;
|
2008-04-25 20:46:13 +00:00
|
|
|
|
Convert character devices over to use -device
The current character device syntax uses either
-serial tty,path=/dev/ttyS2
Or
-chardev tty,id=serial0,path=/dev/ttyS2 -serial chardev:serial0
With the new -device support, we now prefer
-chardev file,id=serial0,path=/tmp/serial.log -device isa-serial,chardev=serial0
This patch changes the existing -chardev syntax to use this new
scheme, and fallbacks to the old plain -serial syntax for old
QEMU.
The monitor device changes to
-chardev socket,id=monitor,path=/tmp/test-monitor,server,nowait -mon chardev=monitor
In addition, this patch adds --nodefaults, which kills off the
default serial, parallel, vga and nic devices. THis avoids the
need for us to explicitly turn each off
2009-12-14 18:04:35 +00:00
|
|
|
/* Use -chardev with -device if they are available */
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) &&
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
2009-12-14 09:38:44 +00:00
|
|
|
ADD_ARG_LIT("-chardev");
|
2010-01-26 13:00:18 +00:00
|
|
|
if (!(devstr = qemuBuildChrChardevStr(serial)))
|
|
|
|
goto error;
|
|
|
|
ADD_ARG(devstr);
|
2009-12-14 09:38:44 +00:00
|
|
|
|
Convert character devices over to use -device
The current character device syntax uses either
-serial tty,path=/dev/ttyS2
Or
-chardev tty,id=serial0,path=/dev/ttyS2 -serial chardev:serial0
With the new -device support, we now prefer
-chardev file,id=serial0,path=/tmp/serial.log -device isa-serial,chardev=serial0
This patch changes the existing -chardev syntax to use this new
scheme, and fallbacks to the old plain -serial syntax for old
QEMU.
The monitor device changes to
-chardev socket,id=monitor,path=/tmp/test-monitor,server,nowait -mon chardev=monitor
In addition, this patch adds --nodefaults, which kills off the
default serial, parallel, vga and nic devices. THis avoids the
need for us to explicitly turn each off
2009-12-14 18:04:35 +00:00
|
|
|
ADD_ARG_LIT("-device");
|
2010-01-26 13:00:18 +00:00
|
|
|
if (virAsprintf(&devstr, "isa-serial,chardev=%s", serial->info.alias) < 0)
|
2009-12-14 09:38:44 +00:00
|
|
|
goto no_memory;
|
2010-01-26 13:00:18 +00:00
|
|
|
ADD_ARG(devstr);
|
|
|
|
} else {
|
2009-12-14 09:38:44 +00:00
|
|
|
ADD_ARG_LIT("-serial");
|
2010-01-26 13:00:18 +00:00
|
|
|
if (!(devstr = qemuBuildChrArgStr(serial, NULL)))
|
|
|
|
goto error;
|
|
|
|
ADD_ARG(devstr);
|
2009-12-14 09:38:44 +00:00
|
|
|
}
|
2008-04-25 20:46:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-19 14:50:01 +00:00
|
|
|
if (!def->nparallels) {
|
2009-12-21 20:36:32 +00:00
|
|
|
/* If we have -device, then we set -nodefault already */
|
|
|
|
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
|
|
|
ADD_ARG_LIT("-parallel");
|
|
|
|
ADD_ARG_LIT("none");
|
|
|
|
}
|
2008-04-25 20:46:13 +00:00
|
|
|
} else {
|
2009-04-19 14:50:01 +00:00
|
|
|
for (i = 0 ; i < def->nparallels ; i++) {
|
|
|
|
virDomainChrDefPtr parallel = def->parallels[i];
|
2010-01-26 13:00:18 +00:00
|
|
|
char *devstr;
|
2008-04-25 20:46:13 +00:00
|
|
|
|
Convert character devices over to use -device
The current character device syntax uses either
-serial tty,path=/dev/ttyS2
Or
-chardev tty,id=serial0,path=/dev/ttyS2 -serial chardev:serial0
With the new -device support, we now prefer
-chardev file,id=serial0,path=/tmp/serial.log -device isa-serial,chardev=serial0
This patch changes the existing -chardev syntax to use this new
scheme, and fallbacks to the old plain -serial syntax for old
QEMU.
The monitor device changes to
-chardev socket,id=monitor,path=/tmp/test-monitor,server,nowait -mon chardev=monitor
In addition, this patch adds --nodefaults, which kills off the
default serial, parallel, vga and nic devices. THis avoids the
need for us to explicitly turn each off
2009-12-14 18:04:35 +00:00
|
|
|
/* Use -chardev with -device if they are available */
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) &&
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
2009-12-14 09:38:44 +00:00
|
|
|
ADD_ARG_LIT("-chardev");
|
2010-01-26 13:00:18 +00:00
|
|
|
if (!(devstr = qemuBuildChrChardevStr(parallel)))
|
|
|
|
goto error;
|
|
|
|
ADD_ARG(devstr);
|
2009-12-14 09:38:44 +00:00
|
|
|
|
Convert character devices over to use -device
The current character device syntax uses either
-serial tty,path=/dev/ttyS2
Or
-chardev tty,id=serial0,path=/dev/ttyS2 -serial chardev:serial0
With the new -device support, we now prefer
-chardev file,id=serial0,path=/tmp/serial.log -device isa-serial,chardev=serial0
This patch changes the existing -chardev syntax to use this new
scheme, and fallbacks to the old plain -serial syntax for old
QEMU.
The monitor device changes to
-chardev socket,id=monitor,path=/tmp/test-monitor,server,nowait -mon chardev=monitor
In addition, this patch adds --nodefaults, which kills off the
default serial, parallel, vga and nic devices. THis avoids the
need for us to explicitly turn each off
2009-12-14 18:04:35 +00:00
|
|
|
ADD_ARG_LIT("-device");
|
2010-01-26 13:00:18 +00:00
|
|
|
if (virAsprintf(&devstr, "isa-parallel,chardev=%s", parallel->info.alias) < 0)
|
2009-12-14 09:38:44 +00:00
|
|
|
goto no_memory;
|
2010-01-26 13:00:18 +00:00
|
|
|
ADD_ARG(devstr);
|
|
|
|
} else {
|
2009-12-14 09:38:44 +00:00
|
|
|
ADD_ARG_LIT("-parallel");
|
2010-01-26 13:00:18 +00:00
|
|
|
if (!(devstr = qemuBuildChrArgStr(parallel, NULL)))
|
|
|
|
goto error;
|
|
|
|
ADD_ARG(devstr);
|
2009-12-14 09:38:44 +00:00
|
|
|
}
|
2008-04-25 20:46:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-05 14:31:03 +00:00
|
|
|
for (i = 0 ; i < def->nchannels ; i++) {
|
|
|
|
virDomainChrDefPtr channel = def->channels[i];
|
2010-01-26 13:00:18 +00:00
|
|
|
char *devstr;
|
2009-11-05 14:31:03 +00:00
|
|
|
|
|
|
|
switch(channel->targetType) {
|
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD:
|
2009-12-14 19:47:47 +00:00
|
|
|
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) ||
|
|
|
|
!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
"%s", _("guestfwd requires QEMU to support -chardev & -device"));
|
2009-11-05 14:31:03 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ADD_ARG_LIT("-chardev");
|
2010-01-26 13:00:18 +00:00
|
|
|
if (!(devstr = qemuBuildChrChardevStr(channel)))
|
|
|
|
goto error;
|
|
|
|
ADD_ARG(devstr);
|
2009-11-05 14:31:03 +00:00
|
|
|
|
2010-01-26 13:00:18 +00:00
|
|
|
char *addr = virSocketFormatAddr(channel->target.addr);
|
2009-11-13 15:05:27 +00:00
|
|
|
int port = virSocketGetPort(channel->target.addr);
|
|
|
|
|
2009-12-14 19:47:47 +00:00
|
|
|
ADD_ARG_LIT("-netdev");
|
2010-01-26 13:00:18 +00:00
|
|
|
if (virAsprintf(&devstr, "user,guestfwd=tcp:%s:%i,chardev=%s,id=user-%s",
|
|
|
|
addr, port, channel->info.alias, channel->info.alias) < 0) {
|
|
|
|
VIR_FREE(addr);
|
2009-12-09 23:00:50 +00:00
|
|
|
goto no_memory;
|
|
|
|
}
|
2010-01-26 13:00:18 +00:00
|
|
|
VIR_FREE(addr);
|
|
|
|
ADD_ARG(devstr);
|
2010-02-18 16:56:50 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_VIRTIO:
|
|
|
|
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("virtio channel requires QEMU to support -device"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ADD_ARG_LIT("-chardev");
|
|
|
|
if (!(devstr = qemuBuildChrChardevStr(channel)))
|
|
|
|
goto error;
|
|
|
|
ADD_ARG(devstr);
|
|
|
|
|
|
|
|
ADD_ARG_LIT("-device");
|
|
|
|
if (!(devstr = qemuBuildVirtioSerialPortDevStr(channel)))
|
|
|
|
goto error;
|
|
|
|
ADD_ARG(devstr);
|
|
|
|
break;
|
2009-11-05 14:31:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-usb");
|
2009-04-19 14:50:01 +00:00
|
|
|
for (i = 0 ; i < def->ninputs ; i++) {
|
|
|
|
virDomainInputDefPtr input = def->inputs[i];
|
2008-10-10 16:08:01 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (input->bus == VIR_DOMAIN_INPUT_BUS_USB) {
|
2010-01-06 18:31:00 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
char *optstr;
|
|
|
|
ADD_ARG_LIT("-device");
|
|
|
|
if (!(optstr = qemuBuildUSBInputDevStr(input)))
|
|
|
|
goto error;
|
|
|
|
ADD_ARG(optstr);
|
|
|
|
} else {
|
|
|
|
ADD_ARG_LIT("-usbdevice");
|
|
|
|
ADD_ARG_LIT(input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ? "mouse" : "tablet");
|
|
|
|
}
|
2007-07-18 21:08:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-07 07:27:49 +00:00
|
|
|
if ((def->ngraphics == 1) &&
|
|
|
|
def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
|
2009-01-29 17:50:00 +00:00
|
|
|
virBuffer opt = VIR_BUFFER_INITIALIZER;
|
|
|
|
char *optstr;
|
2007-10-12 16:05:44 +00:00
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_VNC_COLON) {
|
2009-05-07 07:27:49 +00:00
|
|
|
if (def->graphics[0]->data.vnc.listenAddr)
|
|
|
|
virBufferAdd(&opt, def->graphics[0]->data.vnc.listenAddr, -1);
|
2009-01-29 17:50:00 +00:00
|
|
|
else if (driver->vncListen)
|
|
|
|
virBufferAdd(&opt, driver->vncListen, -1);
|
|
|
|
|
|
|
|
virBufferVSprintf(&opt, ":%d",
|
2009-05-07 07:27:49 +00:00
|
|
|
def->graphics[0]->data.vnc.port - 5900);
|
2009-01-29 17:50:00 +00:00
|
|
|
|
2009-05-07 07:27:49 +00:00
|
|
|
if (def->graphics[0]->data.vnc.passwd ||
|
2009-01-29 17:50:00 +00:00
|
|
|
driver->vncPassword)
|
|
|
|
virBufferAddLit(&opt, ",password");
|
|
|
|
|
2007-10-12 16:05:44 +00:00
|
|
|
if (driver->vncTLS) {
|
2009-01-29 17:50:00 +00:00
|
|
|
virBufferAddLit(&opt, ",tls");
|
2007-10-12 16:05:44 +00:00
|
|
|
if (driver->vncTLSx509verify) {
|
2009-01-29 17:50:00 +00:00
|
|
|
virBufferVSprintf(&opt, ",x509verify=%s",
|
|
|
|
driver->vncTLSx509certdir);
|
2007-10-12 16:05:44 +00:00
|
|
|
} else {
|
2009-01-29 17:50:00 +00:00
|
|
|
virBufferVSprintf(&opt, ",x509=%s",
|
|
|
|
driver->vncTLSx509certdir);
|
2007-10-12 16:05:44 +00:00
|
|
|
}
|
|
|
|
}
|
2009-03-16 13:54:26 +00:00
|
|
|
|
|
|
|
if (driver->vncSASL) {
|
|
|
|
virBufferAddLit(&opt, ",sasl");
|
|
|
|
|
|
|
|
if (driver->vncSASLdir)
|
|
|
|
ADD_ENV_PAIR("SASL_CONF_DIR", driver->vncSASLdir);
|
|
|
|
|
|
|
|
/* TODO: Support ACLs later */
|
|
|
|
}
|
2007-10-12 16:05:44 +00:00
|
|
|
} else {
|
2009-01-29 17:50:00 +00:00
|
|
|
virBufferVSprintf(&opt, "%d",
|
2009-05-07 07:27:49 +00:00
|
|
|
def->graphics[0]->data.vnc.port - 5900);
|
2007-10-12 16:05:44 +00:00
|
|
|
}
|
2009-12-09 23:00:50 +00:00
|
|
|
if (virBufferError(&opt)) {
|
|
|
|
virBufferFreeAndReset(&opt);
|
2009-01-29 17:50:00 +00:00
|
|
|
goto no_memory;
|
2009-12-09 23:00:50 +00:00
|
|
|
}
|
2009-01-29 17:50:00 +00:00
|
|
|
|
|
|
|
optstr = virBufferContentAndReset(&opt);
|
2007-02-23 17:15:18 +00:00
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-vnc");
|
2009-01-29 17:50:00 +00:00
|
|
|
ADD_ARG(optstr);
|
2009-05-07 07:27:49 +00:00
|
|
|
if (def->graphics[0]->data.vnc.keymap) {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-k");
|
2009-05-07 07:27:49 +00:00
|
|
|
ADD_ARG_LIT(def->graphics[0]->data.vnc.keymap);
|
2008-01-15 15:18:33 +00:00
|
|
|
}
|
2009-09-14 10:23:20 +00:00
|
|
|
|
|
|
|
/* QEMU implements a VNC extension for providing audio, so we
|
|
|
|
* set the audio backend to none, to prevent it opening the
|
|
|
|
* host OS audio devices since that causes security issues
|
|
|
|
* and is non-sensical when using VNC.
|
|
|
|
*/
|
|
|
|
ADD_ENV_LIT("QEMU_AUDIO_DRV=none");
|
2009-05-07 07:27:49 +00:00
|
|
|
} else if ((def->ngraphics == 1) &&
|
|
|
|
def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
|
2008-10-10 16:52:20 +00:00
|
|
|
char *xauth = NULL;
|
|
|
|
char *display = NULL;
|
|
|
|
|
2009-05-07 07:27:49 +00:00
|
|
|
if (def->graphics[0]->data.sdl.xauth &&
|
2008-12-23 13:03:29 +00:00
|
|
|
virAsprintf(&xauth, "XAUTHORITY=%s",
|
2009-05-07 07:27:49 +00:00
|
|
|
def->graphics[0]->data.sdl.xauth) < 0)
|
2008-10-10 16:52:20 +00:00
|
|
|
goto no_memory;
|
2009-05-07 07:27:49 +00:00
|
|
|
if (def->graphics[0]->data.sdl.display &&
|
2008-12-23 13:03:29 +00:00
|
|
|
virAsprintf(&display, "DISPLAY=%s",
|
2009-05-07 07:27:49 +00:00
|
|
|
def->graphics[0]->data.sdl.display) < 0) {
|
2008-10-10 16:52:20 +00:00
|
|
|
VIR_FREE(xauth);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xauth)
|
|
|
|
ADD_ENV(xauth);
|
|
|
|
if (display)
|
|
|
|
ADD_ENV(display);
|
2009-05-07 07:27:49 +00:00
|
|
|
if (def->graphics[0]->data.sdl.fullscreen)
|
2008-12-11 11:44:30 +00:00
|
|
|
ADD_ARG_LIT("-full-screen");
|
2009-09-14 10:23:20 +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
|
|
|
|
*/
|
|
|
|
ADD_ENV_COPY("QEMU_AUDIO_DRV");
|
|
|
|
ADD_ENV_COPY("SDL_AUDIODRIVER");
|
2009-12-21 20:23:55 +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 (qemuCmdFlags & QEMUD_CMD_FLAG_SDL)
|
|
|
|
ADD_ARG_LIT("-sdl");
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2009-07-06 13:59:19 +00:00
|
|
|
if (def->nvideos) {
|
|
|
|
if (def->nvideos > 1) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("only one video card is currently supported"));
|
2009-07-06 13:59:19 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_VGA) {
|
|
|
|
if (def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_XEN) {
|
|
|
|
/* nothing - vga has no effect on Xen pvfb */
|
|
|
|
} else {
|
|
|
|
const char *vgastr = qemuVideoTypeToString(def->videos[0]->type);
|
2009-12-21 22:38:05 +00:00
|
|
|
if (!vgastr || STREQ(vgastr, "")) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("video type %s is not supported with QEMU"),
|
|
|
|
virDomainVideoTypeToString(def->videos[0]->type));
|
2009-07-06 13:59:19 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ADD_ARG_LIT("-vga");
|
|
|
|
ADD_ARG_LIT(vgastr);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
|
|
switch (def->videos[0]->type) {
|
|
|
|
case VIR_DOMAIN_VIDEO_TYPE_VGA:
|
|
|
|
ADD_ARG_LIT("-std-vga");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
|
|
|
|
ADD_ARG_LIT("-vmwarevga");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_VIDEO_TYPE_XEN:
|
|
|
|
case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
|
|
|
|
/* No special args - this is the default */
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("video type %s is not supported with QEMU"),
|
|
|
|
virDomainVideoTypeToString(def->videos[0]->type));
|
2009-07-06 13:59:19 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
2009-12-21 22:38:05 +00:00
|
|
|
} else {
|
|
|
|
/* If we have -device, then we set -nodefault already */
|
|
|
|
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_VGA)) {
|
|
|
|
ADD_ARG_LIT("-vga");
|
|
|
|
ADD_ARG_LIT("none");
|
|
|
|
}
|
2009-07-06 13:59:19 +00:00
|
|
|
}
|
|
|
|
|
2008-05-07 14:04:40 +00:00
|
|
|
/* Add sound hardware */
|
2009-04-19 14:50:01 +00:00
|
|
|
if (def->nsounds) {
|
2009-12-14 18:16:10 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
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) {
|
|
|
|
ADD_ARG_LIT("-soundhw");
|
|
|
|
ADD_ARG_LIT("pcspk");
|
|
|
|
} else {
|
|
|
|
ADD_ARG_LIT("-device");
|
2008-05-07 14:04:40 +00:00
|
|
|
|
2009-12-14 18:16:10 +00:00
|
|
|
if (!(str = qemuBuildSoundDevStr(sound)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
ADD_ARG(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);
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("invalid sound model"));
|
2009-12-14 18:16:10 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
strncat(modstr, model, size);
|
|
|
|
size -= strlen(model);
|
|
|
|
if (i < (def->nsounds - 1))
|
|
|
|
strncat(modstr, ",", size--);
|
2008-05-07 14:04:40 +00:00
|
|
|
}
|
2009-12-14 18:16:10 +00:00
|
|
|
ADD_ARG_LIT("-soundhw");
|
|
|
|
ADD_ARG(modstr);
|
2008-05-07 14:04:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-21 12:26:38 +00:00
|
|
|
/* Add watchdog hardware */
|
|
|
|
if (def->watchdog) {
|
|
|
|
virDomainWatchdogDefPtr watchdog = def->watchdog;
|
2009-12-14 18:06:23 +00:00
|
|
|
char *optstr;
|
|
|
|
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
ADD_ARG_LIT("-device");
|
|
|
|
|
|
|
|
optstr = qemuBuildWatchdogDevStr(watchdog);
|
|
|
|
if (!optstr)
|
|
|
|
goto error;
|
|
|
|
} else {
|
|
|
|
ADD_ARG_LIT("-watchdog");
|
|
|
|
|
|
|
|
const char *model = virDomainWatchdogModelTypeToString(watchdog->model);
|
|
|
|
if (!model) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("missing watchdog model"));
|
2009-12-14 18:06:23 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(optstr = strdup(model)))
|
|
|
|
goto no_memory;
|
2009-10-21 12:26:38 +00:00
|
|
|
}
|
2009-12-14 18:06:23 +00:00
|
|
|
ADD_ARG(optstr);
|
2009-10-21 12:26:38 +00:00
|
|
|
|
|
|
|
const char *action = virDomainWatchdogActionTypeToString(watchdog->action);
|
|
|
|
if (!action) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("invalid watchdog action"));
|
2009-10-21 12:26:38 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
ADD_ARG_LIT("-watchdog-action");
|
|
|
|
ADD_ARG_LIT(action);
|
|
|
|
}
|
|
|
|
|
2008-08-08 14:27:05 +00:00
|
|
|
/* Add host passthrough hardware */
|
2009-04-19 14:50:01 +00:00
|
|
|
for (i = 0 ; i < def->nhostdevs ; i++) {
|
|
|
|
virDomainHostdevDefPtr hostdev = def->hostdevs[i];
|
2010-01-26 13:44:12 +00:00
|
|
|
char *devstr;
|
2008-08-08 14:27:05 +00:00
|
|
|
|
2009-01-07 12:56:13 +00:00
|
|
|
/* USB */
|
2008-08-08 14:27:05 +00:00
|
|
|
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
|
|
|
hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
|
|
|
|
|
2009-12-14 19:32:32 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
ADD_ARG_LIT("-device");
|
2010-01-26 13:44:12 +00:00
|
|
|
if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev)))
|
|
|
|
goto error;
|
|
|
|
ADD_ARG(devstr);
|
2008-08-08 14:27:05 +00:00
|
|
|
} else {
|
2009-12-14 19:32:32 +00:00
|
|
|
ADD_ARG_LIT("-usbdevice");
|
2010-01-26 13:44:12 +00:00
|
|
|
if (!(devstr = qemuBuildUSBHostdevUsbDevStr(hostdev)))
|
|
|
|
goto error;
|
|
|
|
ADD_ARG(devstr);
|
2008-08-08 14:27:05 +00:00
|
|
|
}
|
|
|
|
}
|
2009-01-07 12:56:13 +00:00
|
|
|
|
|
|
|
/* PCI */
|
|
|
|
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
|
|
|
hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
|
2009-12-14 19:36:42 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
ADD_ARG_LIT("-device");
|
2010-01-26 13:44:12 +00:00
|
|
|
if (!(devstr = qemuBuildPCIHostdevDevStr(hostdev)))
|
2009-12-14 19:36:42 +00:00
|
|
|
goto error;
|
2010-01-26 13:44:12 +00:00
|
|
|
ADD_ARG(devstr);
|
2009-12-14 19:36:42 +00:00
|
|
|
} else if (qemuCmdFlags & QEMUD_CMD_FLAG_PCIDEVICE) {
|
|
|
|
ADD_ARG_LIT("-pcidevice");
|
2010-01-26 13:44:12 +00:00
|
|
|
if (!(devstr = qemuBuildPCIHostdevPCIDevStr(hostdev)))
|
|
|
|
goto error;
|
|
|
|
ADD_ARG(devstr);
|
2009-12-14 19:36:42 +00:00
|
|
|
} else {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("PCI device assignment is not supported by this version of qemu"));
|
2009-08-14 07:31:11 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2009-01-07 12:56:13 +00:00
|
|
|
}
|
2009-03-02 16:40:30 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (migrateFrom) {
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG_LIT("-incoming");
|
2008-07-11 19:34:11 +00:00
|
|
|
ADD_ARG_LIT(migrateFrom);
|
2007-08-14 01:28:47 +00:00
|
|
|
}
|
|
|
|
|
2010-01-06 17:01:51 +00:00
|
|
|
/* QEMU changed its default behavior to not include the virtio balloon
|
|
|
|
* device. Explicitly request it to ensure it will be present.
|
2010-01-08 16:32:10 +00:00
|
|
|
*
|
|
|
|
* NB: Earlier we declared that VirtIO balloon will always be in
|
|
|
|
* slot 0x3 on bus 0x0
|
2010-01-06 17:01:51 +00:00
|
|
|
*/
|
2010-01-08 16:32:10 +00:00
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
ADD_ARG_LIT("-device");
|
|
|
|
ADD_ARG_LIT("virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3");
|
|
|
|
} else if (qemuCmdFlags & QEMUD_CMD_FLAG_BALLOON) {
|
2010-01-06 17:01:51 +00:00
|
|
|
ADD_ARG_LIT("-balloon");
|
|
|
|
ADD_ARG_LIT("virtio");
|
|
|
|
}
|
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
ADD_ARG(NULL);
|
2008-10-10 16:52:20 +00:00
|
|
|
ADD_ENV(NULL);
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-05-22 23:45:09 +00:00
|
|
|
*retargv = qargv;
|
2008-10-10 16:52:20 +00:00
|
|
|
*retenv = qenv;
|
2007-02-14 01:40:09 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
no_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2007-02-14 16:09:37 +00:00
|
|
|
error:
|
2008-07-11 19:34:11 +00:00
|
|
|
if (tapfds &&
|
|
|
|
*tapfds) {
|
2008-10-06 19:36:46 +00:00
|
|
|
for (i = 0; i < *ntapfds; i++)
|
2008-07-11 19:34:11 +00:00
|
|
|
close((*tapfds)[i]);
|
|
|
|
VIR_FREE(*tapfds);
|
|
|
|
*ntapfds = 0;
|
2007-02-14 16:09:37 +00:00
|
|
|
}
|
2008-05-22 23:45:09 +00:00
|
|
|
if (qargv) {
|
|
|
|
for (i = 0 ; i < qargc ; i++)
|
2008-05-29 19:20:22 +00:00
|
|
|
VIR_FREE((qargv)[i]);
|
|
|
|
VIR_FREE(qargv);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
2008-10-10 16:52:20 +00:00
|
|
|
if (qenv) {
|
|
|
|
for (i = 0 ; i < qenvc ; i++)
|
|
|
|
VIR_FREE((qenv)[i]);
|
|
|
|
VIR_FREE(qenv);
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
2008-05-22 23:45:09 +00:00
|
|
|
|
|
|
|
#undef ADD_ARG
|
|
|
|
#undef ADD_ARG_LIT
|
|
|
|
#undef ADD_ARG_SPACE
|
2008-10-10 16:52:20 +00:00
|
|
|
#undef ADD_USBDISK
|
|
|
|
#undef ADD_ENV
|
|
|
|
#undef ADD_ENV_COPY
|
|
|
|
#undef ADD_ENV_LIT
|
|
|
|
#undef ADD_ENV_SPACE
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
2008-12-20 13:09:45 +00:00
|
|
|
|
|
|
|
|
2009-05-21 14:16:55 +00:00
|
|
|
/*
|
|
|
|
* This method takes a string representing a QEMU command line ARGV set
|
2010-02-10 21:11:42 +00:00
|
|
|
* optionally prefixed by a list of environment variables. It then tries
|
2009-05-21 14:16:55 +00:00
|
|
|
* 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 **progenv = NULL;
|
|
|
|
const char **progargv = NULL;
|
|
|
|
|
|
|
|
/* Iterate over string, splitting on sequences of ' ' */
|
|
|
|
while (curr && *curr != '\0') {
|
|
|
|
char *arg;
|
2009-05-28 13:21:19 +00:00
|
|
|
const char *next;
|
|
|
|
if (*curr == '\'') {
|
|
|
|
curr++;
|
|
|
|
next = strchr(curr, '\'');
|
|
|
|
} else if (*curr == '"') {
|
|
|
|
curr++;
|
|
|
|
next = strchr(curr, '"');
|
|
|
|
} else {
|
|
|
|
next = strchr(curr, ' ');
|
|
|
|
}
|
2009-05-21 14:16:55 +00:00
|
|
|
if (!next)
|
|
|
|
next = strchr(curr, '\n');
|
|
|
|
|
2009-05-28 13:21:19 +00:00
|
|
|
if (next) {
|
2009-05-21 14:16:55 +00:00
|
|
|
arg = strndup(curr, next-curr);
|
2009-05-28 13:21:19 +00:00
|
|
|
if (*next == '\'' ||
|
|
|
|
*next == '"')
|
|
|
|
next++;
|
|
|
|
} else {
|
2009-05-21 14:16:55 +00:00
|
|
|
arg = strdup(curr);
|
2009-05-28 13:21:19 +00:00
|
|
|
}
|
2009-05-21 14:16:55 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-09-06 13:55:49 +00:00
|
|
|
/* Iterate over list of args, finding first arg not containing
|
2009-05-21 14:16:55 +00:00
|
|
|
* 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];
|
2009-09-03 16:37:45 +00:00
|
|
|
arglist[i] = NULL;
|
2009-05-21 14:16:55 +00:00
|
|
|
}
|
|
|
|
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);
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-05-21 14:16:55 +00:00
|
|
|
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);
|
|
|
|
|
2009-05-28 13:21:19 +00:00
|
|
|
for (i = 0 ; progenv && progenv[i] ; i++) {
|
2009-05-21 14:16:55 +00:00
|
|
|
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
|
Enhance qemuParseCommandLineKeywords
Current version expects name=value,... list and when an incorrect string
such as "a,b,c=d" would be parsed as "a,b,c" keyword with "d" value
without reporting any error, which is probably not the expected
behavior.
This patch adds an extra argument called allowEmptyValue, which if
non-zero will permit keywords with no value; "a,b=c,,d=" will be parsed
as follows:
keyword value
"a" NULL
"b" "c"
"" NULL
"d" ""
In case allowEmptyValue is zero, the string is required to contain
name=value pairs only; retvalues is guaranteed to contain non-NULL
pointers. Now, "a,b,c=d" will result in an error.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
2010-01-13 15:48:30 +00:00
|
|
|
* 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.
|
2009-05-21 14:16:55 +00:00
|
|
|
*/
|
|
|
|
static int
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuParseCommandLineKeywords(const char *str,
|
2009-05-21 14:16:55 +00:00
|
|
|
char ***retkeywords,
|
Enhance qemuParseCommandLineKeywords
Current version expects name=value,... list and when an incorrect string
such as "a,b,c=d" would be parsed as "a,b,c" keyword with "d" value
without reporting any error, which is probably not the expected
behavior.
This patch adds an extra argument called allowEmptyValue, which if
non-zero will permit keywords with no value; "a,b=c,,d=" will be parsed
as follows:
keyword value
"a" NULL
"b" "c"
"" NULL
"d" ""
In case allowEmptyValue is zero, the string is required to contain
name=value pairs only; retvalues is guaranteed to contain non-NULL
pointers. Now, "a,b,c=d" will result in an error.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
2010-01-13 15:48:30 +00:00
|
|
|
char ***retvalues,
|
|
|
|
int allowEmptyValue)
|
2009-05-21 14:16:55 +00:00
|
|
|
{
|
|
|
|
int keywordCount = 0;
|
|
|
|
int keywordAlloc = 0;
|
|
|
|
char **keywords = NULL;
|
|
|
|
char **values = NULL;
|
|
|
|
const char *start = str;
|
Enhance qemuParseCommandLineKeywords
Current version expects name=value,... list and when an incorrect string
such as "a,b,c=d" would be parsed as "a,b,c" keyword with "d" value
without reporting any error, which is probably not the expected
behavior.
This patch adds an extra argument called allowEmptyValue, which if
non-zero will permit keywords with no value; "a,b=c,,d=" will be parsed
as follows:
keyword value
"a" NULL
"b" "c"
"" NULL
"d" ""
In case allowEmptyValue is zero, the string is required to contain
name=value pairs only; retvalues is guaranteed to contain non-NULL
pointers. Now, "a,b,c=d" will result in an error.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
2010-01-13 15:48:30 +00:00
|
|
|
const char *end;
|
2009-05-21 14:16:55 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
*retkeywords = NULL;
|
|
|
|
*retvalues = NULL;
|
Enhance qemuParseCommandLineKeywords
Current version expects name=value,... list and when an incorrect string
such as "a,b,c=d" would be parsed as "a,b,c" keyword with "d" value
without reporting any error, which is probably not the expected
behavior.
This patch adds an extra argument called allowEmptyValue, which if
non-zero will permit keywords with no value; "a,b=c,,d=" will be parsed
as follows:
keyword value
"a" NULL
"b" "c"
"" NULL
"d" ""
In case allowEmptyValue is zero, the string is required to contain
name=value pairs only; retvalues is guaranteed to contain non-NULL
pointers. Now, "a,b,c=d" will result in an error.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
2010-01-13 15:48:30 +00:00
|
|
|
end = start + strlen(str);
|
2009-05-21 14:16:55 +00:00
|
|
|
|
|
|
|
while (start) {
|
|
|
|
const char *separator;
|
|
|
|
const char *endmark;
|
|
|
|
char *keyword;
|
Enhance qemuParseCommandLineKeywords
Current version expects name=value,... list and when an incorrect string
such as "a,b,c=d" would be parsed as "a,b,c" keyword with "d" value
without reporting any error, which is probably not the expected
behavior.
This patch adds an extra argument called allowEmptyValue, which if
non-zero will permit keywords with no value; "a,b=c,,d=" will be parsed
as follows:
keyword value
"a" NULL
"b" "c"
"" NULL
"d" ""
In case allowEmptyValue is zero, the string is required to contain
name=value pairs only; retvalues is guaranteed to contain non-NULL
pointers. Now, "a,b,c=d" will result in an error.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
2010-01-13 15:48:30 +00:00
|
|
|
char *value = NULL;
|
2009-05-21 14:16:55 +00:00
|
|
|
|
Enhance qemuParseCommandLineKeywords
Current version expects name=value,... list and when an incorrect string
such as "a,b,c=d" would be parsed as "a,b,c" keyword with "d" value
without reporting any error, which is probably not the expected
behavior.
This patch adds an extra argument called allowEmptyValue, which if
non-zero will permit keywords with no value; "a,b=c,,d=" will be parsed
as follows:
keyword value
"a" NULL
"b" "c"
"" NULL
"d" ""
In case allowEmptyValue is zero, the string is required to contain
name=value pairs only; retvalues is guaranteed to contain non-NULL
pointers. Now, "a,b,c=d" will result in an error.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
2010-01-13 15:48:30 +00:00
|
|
|
if (!(endmark = strchr(start, ',')))
|
|
|
|
endmark = end;
|
|
|
|
if (!(separator = strchr(start, '=')))
|
|
|
|
separator = end;
|
|
|
|
|
|
|
|
if (separator >= endmark) {
|
|
|
|
if (!allowEmptyValue) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("malformed keyword arguments in '%s'"), str);
|
Enhance qemuParseCommandLineKeywords
Current version expects name=value,... list and when an incorrect string
such as "a,b,c=d" would be parsed as "a,b,c" keyword with "d" value
without reporting any error, which is probably not the expected
behavior.
This patch adds an extra argument called allowEmptyValue, which if
non-zero will permit keywords with no value; "a,b=c,,d=" will be parsed
as follows:
keyword value
"a" NULL
"b" "c"
"" NULL
"d" ""
In case allowEmptyValue is zero, the string is required to contain
name=value pairs only; retvalues is guaranteed to contain non-NULL
pointers. Now, "a,b,c=d" will result in an error.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
2010-01-13 15:48:30 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
separator = endmark;
|
2009-05-21 14:16:55 +00:00
|
|
|
}
|
Enhance qemuParseCommandLineKeywords
Current version expects name=value,... list and when an incorrect string
such as "a,b,c=d" would be parsed as "a,b,c" keyword with "d" value
without reporting any error, which is probably not the expected
behavior.
This patch adds an extra argument called allowEmptyValue, which if
non-zero will permit keywords with no value; "a,b=c,,d=" will be parsed
as follows:
keyword value
"a" NULL
"b" "c"
"" NULL
"d" ""
In case allowEmptyValue is zero, the string is required to contain
name=value pairs only; retvalues is guaranteed to contain non-NULL
pointers. Now, "a,b,c=d" will result in an error.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
2010-01-13 15:48:30 +00:00
|
|
|
|
2009-05-21 14:16:55 +00:00
|
|
|
if (!(keyword = strndup(start, separator - start)))
|
|
|
|
goto no_memory;
|
|
|
|
|
Enhance qemuParseCommandLineKeywords
Current version expects name=value,... list and when an incorrect string
such as "a,b,c=d" would be parsed as "a,b,c" keyword with "d" value
without reporting any error, which is probably not the expected
behavior.
This patch adds an extra argument called allowEmptyValue, which if
non-zero will permit keywords with no value; "a,b=c,,d=" will be parsed
as follows:
keyword value
"a" NULL
"b" "c"
"" NULL
"d" ""
In case allowEmptyValue is zero, the string is required to contain
name=value pairs only; retvalues is guaranteed to contain non-NULL
pointers. Now, "a,b,c=d" will result in an error.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
2010-01-13 15:48:30 +00:00
|
|
|
if (separator < endmark) {
|
|
|
|
separator++;
|
|
|
|
if (!(value = strndup(separator, endmark - separator))) {
|
|
|
|
VIR_FREE(keyword);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
2009-05-21 14:16:55 +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++;
|
|
|
|
|
Enhance qemuParseCommandLineKeywords
Current version expects name=value,... list and when an incorrect string
such as "a,b,c=d" would be parsed as "a,b,c" keyword with "d" value
without reporting any error, which is probably not the expected
behavior.
This patch adds an extra argument called allowEmptyValue, which if
non-zero will permit keywords with no value; "a,b=c,,d=" will be parsed
as follows:
keyword value
"a" NULL
"b" "c"
"" NULL
"d" ""
In case allowEmptyValue is zero, the string is required to contain
name=value pairs only; retvalues is guaranteed to contain non-NULL
pointers. Now, "a,b,c=d" will result in an error.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
2010-01-13 15:48:30 +00:00
|
|
|
start = endmark < end ? endmark + 1 : NULL;
|
2009-05-21 14:16:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*retkeywords = keywords;
|
|
|
|
*retvalues = values;
|
|
|
|
|
|
|
|
return keywordCount;
|
|
|
|
|
|
|
|
no_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-05-21 14:16:55 +00:00
|
|
|
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
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuParseCommandLineDisk(const char *val,
|
2009-12-10 19:07:16 +00:00
|
|
|
int nvirtiodisk)
|
2009-05-21 14:16:55 +00:00
|
|
|
{
|
|
|
|
virDomainDiskDefPtr def = NULL;
|
|
|
|
char **keywords;
|
|
|
|
char **values;
|
|
|
|
int nkeywords;
|
|
|
|
int i;
|
|
|
|
int idx = -1;
|
2009-12-10 19:07:16 +00:00
|
|
|
int busid = -1;
|
|
|
|
int unitid = -1;
|
2009-05-21 14:16:55 +00:00
|
|
|
|
2010-02-09 18:15:41 +00:00
|
|
|
if ((nkeywords = qemuParseCommandLineKeywords(val,
|
2009-05-21 14:16:55 +00:00
|
|
|
&keywords,
|
Enhance qemuParseCommandLineKeywords
Current version expects name=value,... list and when an incorrect string
such as "a,b,c=d" would be parsed as "a,b,c" keyword with "d" value
without reporting any error, which is probably not the expected
behavior.
This patch adds an extra argument called allowEmptyValue, which if
non-zero will permit keywords with no value; "a,b=c,,d=" will be parsed
as follows:
keyword value
"a" NULL
"b" "c"
"" NULL
"d" ""
In case allowEmptyValue is zero, the string is required to contain
name=value pairs only; retvalues is guaranteed to contain non-NULL
pointers. Now, "a,b,c=d" will result in an error.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
2010-01-13 15:48:30 +00:00
|
|
|
&values, 0)) < 0)
|
2009-05-21 14:16:55 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-05-21 14:16:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->bus = VIR_DOMAIN_DISK_BUS_IDE;
|
|
|
|
def->device = VIR_DOMAIN_DISK_DEVICE_DISK;
|
2009-11-24 10:58:08 +00:00
|
|
|
def->type = VIR_DOMAIN_DISK_TYPE_FILE;
|
2009-05-21 14:16:55 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
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;
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-05-21 14:16:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
def->driverType = values[i];
|
|
|
|
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;
|
|
|
|
} else if (STREQ(keywords[i], "index")) {
|
|
|
|
if (virStrToLong_i(values[i], NULL, 10, &idx) < 0) {
|
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse drive index '%s'"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-12-10 19:07:16 +00:00
|
|
|
} else if (STREQ(keywords[i], "bus")) {
|
|
|
|
if (virStrToLong_i(values[i], NULL, 10, &busid) < 0) {
|
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse drive bus '%s'"), val);
|
2009-12-10 19:07:16 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else if (STREQ(keywords[i], "unit")) {
|
|
|
|
if (virStrToLong_i(values[i], NULL, 10, &unitid) < 0) {
|
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse drive unit '%s'"), val);
|
2009-12-10 19:07:16 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-05-21 14:16:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!def->src &&
|
|
|
|
def->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("missing file parameter in drive '%s'"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-12-10 19:07:16 +00:00
|
|
|
if (idx == -1 &&
|
|
|
|
def->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
|
|
|
|
idx = nvirtiodisk;
|
|
|
|
|
|
|
|
if (idx == -1 &&
|
|
|
|
unitid == -1 &&
|
|
|
|
busid == -1) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("missing index/unit/bus parameter in drive '%s'"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-12-10 19:07:16 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-21 14:16:55 +00:00
|
|
|
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;
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-05-21 14:16:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (STREQ(def->dst, "xvda"))
|
|
|
|
def->dst[3] = 'a' + idx;
|
|
|
|
else
|
|
|
|
def->dst[2] = 'a' + idx;
|
|
|
|
|
2009-12-22 16:53:20 +00:00
|
|
|
virDomainDiskDefAssignAddress(def);
|
|
|
|
|
2009-05-21 14:16:55 +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 find a NIC definition matching a vlan we want
|
|
|
|
*/
|
|
|
|
static const char *
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuFindNICForVLAN(int nnics,
|
2009-05-21 14:16:55 +00:00
|
|
|
const char **nics,
|
|
|
|
int wantvlan)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0 ; i < nnics ; i++) {
|
|
|
|
int gotvlan;
|
|
|
|
const char *tmp = strstr(nics[i], "vlan=");
|
|
|
|
char *end;
|
2009-05-28 13:21:19 +00:00
|
|
|
if (!tmp)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
tmp += strlen("vlan=");
|
2009-05-21 14:16:55 +00:00
|
|
|
|
|
|
|
if (virStrToLong_i(tmp, &end, 10, &gotvlan) < 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse NIC vlan in '%s'"), nics[i]);
|
2009-05-21 14:16:55 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gotvlan == wantvlan)
|
|
|
|
return nics[i];
|
|
|
|
}
|
|
|
|
|
2009-05-28 13:21:19 +00:00
|
|
|
if (wantvlan == 0 && nnics > 0)
|
|
|
|
return nics[0];
|
|
|
|
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot find NIC definition for vlan %d"), wantvlan);
|
2009-05-21 14:16:55 +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
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuParseCommandLineNet(virCapsPtr caps,
|
2009-05-21 14:16:55 +00:00
|
|
|
const char *val,
|
|
|
|
int nnics,
|
|
|
|
const char **nics)
|
|
|
|
{
|
|
|
|
virDomainNetDefPtr def = NULL;
|
2009-05-28 13:21:19 +00:00
|
|
|
char **keywords = NULL;
|
|
|
|
char **values = NULL;
|
2009-05-21 14:16:55 +00:00
|
|
|
int nkeywords;
|
|
|
|
const char *nic;
|
|
|
|
int wantvlan = 0;
|
|
|
|
const char *tmp;
|
2009-05-28 13:21:19 +00:00
|
|
|
int genmac = 1;
|
2009-05-21 14:16:55 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
tmp = strchr(val, ',');
|
|
|
|
|
2009-05-28 13:21:19 +00:00
|
|
|
if (tmp) {
|
2010-02-09 18:15:41 +00:00
|
|
|
if ((nkeywords = qemuParseCommandLineKeywords(tmp+1,
|
2009-05-28 13:21:19 +00:00
|
|
|
&keywords,
|
Enhance qemuParseCommandLineKeywords
Current version expects name=value,... list and when an incorrect string
such as "a,b,c=d" would be parsed as "a,b,c" keyword with "d" value
without reporting any error, which is probably not the expected
behavior.
This patch adds an extra argument called allowEmptyValue, which if
non-zero will permit keywords with no value; "a,b=c,,d=" will be parsed
as follows:
keyword value
"a" NULL
"b" "c"
"" NULL
"d" ""
In case allowEmptyValue is zero, the string is required to contain
name=value pairs only; retvalues is guaranteed to contain non-NULL
pointers. Now, "a,b,c=d" will result in an error.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
2010-01-13 15:48:30 +00:00
|
|
|
&values, 0)) < 0)
|
2009-05-28 13:21:19 +00:00
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
nkeywords = 0;
|
|
|
|
}
|
2009-05-21 14:16:55 +00:00
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-05-21 14:16:55 +00:00
|
|
|
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) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse vlan in '%s'"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
virDomainNetDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else if (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
|
|
|
|
STREQ(keywords[i], "script") && STRNEQ(values[i], "")) {
|
|
|
|
def->data.ethernet.script = values[i];
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
|
2010-02-09 18:15:41 +00:00
|
|
|
nic = qemuFindNICForVLAN(nnics, nics, wantvlan);
|
2009-05-21 14:16:55 +00:00
|
|
|
if (!nic) {
|
|
|
|
virDomainNetDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-05-28 13:21:19 +00:00
|
|
|
if (!STRPREFIX(nic, "nic")) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse NIC definition '%s'"), nic);
|
2009-05-21 14:16:55 +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);
|
|
|
|
|
2009-05-28 13:21:19 +00:00
|
|
|
if (STRPREFIX(nic, "nic,")) {
|
2010-02-09 18:15:41 +00:00
|
|
|
if ((nkeywords = qemuParseCommandLineKeywords(nic + strlen("nic,"),
|
2009-05-28 13:21:19 +00:00
|
|
|
&keywords,
|
Enhance qemuParseCommandLineKeywords
Current version expects name=value,... list and when an incorrect string
such as "a,b,c=d" would be parsed as "a,b,c" keyword with "d" value
without reporting any error, which is probably not the expected
behavior.
This patch adds an extra argument called allowEmptyValue, which if
non-zero will permit keywords with no value; "a,b=c,,d=" will be parsed
as follows:
keyword value
"a" NULL
"b" "c"
"" NULL
"d" ""
In case allowEmptyValue is zero, the string is required to contain
name=value pairs only; retvalues is guaranteed to contain non-NULL
pointers. Now, "a,b,c=d" will result in an error.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
2010-01-13 15:48:30 +00:00
|
|
|
&values, 0)) < 0) {
|
2009-05-28 13:21:19 +00:00
|
|
|
virDomainNetDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
nkeywords = 0;
|
2009-05-21 14:16:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0 ; i < nkeywords ; i++) {
|
|
|
|
if (STREQ(keywords[i], "macaddr")) {
|
2009-05-28 13:21:19 +00:00
|
|
|
genmac = 0;
|
2009-10-16 10:09:13 +00:00
|
|
|
if (virParseMacAddr(values[i], def->mac) < 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unable to parse mac address '%s'"),
|
|
|
|
values[i]);
|
2009-10-16 10:09:13 +00:00
|
|
|
virDomainNetDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-05-21 14:16:55 +00:00
|
|
|
} else if (STREQ(keywords[i], "model")) {
|
|
|
|
def->model = values[i];
|
|
|
|
values[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-28 13:21:19 +00:00
|
|
|
if (genmac)
|
|
|
|
virCapabilitiesGenerateMac(caps, def->mac);
|
|
|
|
|
2009-05-21 14:16:55 +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
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuParseCommandLinePCI(const char *val)
|
2009-05-21 14:16:55 +00:00
|
|
|
{
|
|
|
|
virDomainHostdevDefPtr def = NULL;
|
|
|
|
int bus = 0, slot = 0, func = 0;
|
|
|
|
const char *start;
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
if (!STRPREFIX(val, "host=")) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown PCI device syntax '%s'"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = val + strlen("host=");
|
|
|
|
if (virStrToLong_i(start, &end, 16, &bus) < 0 || !end || *end != ':') {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot extract PCI device bus '%s'"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
start = end + 1;
|
|
|
|
if (virStrToLong_i(start, &end, 16, &slot) < 0 || !end || *end != '.') {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot extract PCI device slot '%s'"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
start = end + 1;
|
|
|
|
if (virStrToLong_i(start, NULL, 16, &func) < 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot extract PCI device function '%s'"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-05-21 14:16:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Tries to parse a QEMU USB device
|
|
|
|
*/
|
|
|
|
static virDomainHostdevDefPtr
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuParseCommandLineUSB(const char *val)
|
2009-05-21 14:16:55 +00:00
|
|
|
{
|
|
|
|
virDomainHostdevDefPtr def = NULL;
|
|
|
|
int first = 0, second = 0;
|
|
|
|
const char *start;
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
if (!STRPREFIX(val, "host:")) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
2010-03-01 21:00:37 +00:00
|
|
|
_("unknown USB device syntax '%s'"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = val + strlen("host:");
|
|
|
|
if (strchr(start, ':')) {
|
|
|
|
if (virStrToLong_i(start, &end, 16, &first) < 0 || !end || *end != ':') {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot extract USB device vendor '%s'"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
start = end + 1;
|
|
|
|
if (virStrToLong_i(start, NULL, 16, &second) < 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
2010-03-01 21:00:37 +00:00
|
|
|
_("cannot extract USB device product '%s'"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (virStrToLong_i(start, &end, 10, &first) < 0 || !end || *end != '.') {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
2010-03-01 21:00:37 +00:00
|
|
|
_("cannot extract USB device bus '%s'"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
start = end + 1;
|
|
|
|
if (virStrToLong_i(start, NULL, 10, &second) < 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
2010-03-01 21:00:37 +00:00
|
|
|
_("cannot extract USB device address '%s'"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-05-21 14:16:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Tries to parse a QEMU serial/parallel device
|
|
|
|
*/
|
|
|
|
static virDomainChrDefPtr
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuParseCommandLineChr(const char *val)
|
2009-05-21 14:16:55 +00:00
|
|
|
{
|
|
|
|
virDomainChrDefPtr def;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (STREQ(val, "null")) {
|
|
|
|
def->type = VIR_DOMAIN_CHR_TYPE_NULL;
|
|
|
|
} else if (STREQ(val, "vc")) {
|
|
|
|
def->type = VIR_DOMAIN_CHR_TYPE_VC;
|
|
|
|
} else if (STREQ(val, "pty")) {
|
|
|
|
def->type = VIR_DOMAIN_CHR_TYPE_PTY;
|
|
|
|
} else if (STRPREFIX(val, "file:")) {
|
|
|
|
def->type = VIR_DOMAIN_CHR_TYPE_FILE;
|
|
|
|
def->data.file.path = strdup(val+strlen("file:"));
|
|
|
|
if (!def->data.file.path)
|
|
|
|
goto no_memory;
|
|
|
|
} else if (STRPREFIX(val, "pipe:")) {
|
|
|
|
def->type = VIR_DOMAIN_CHR_TYPE_PIPE;
|
|
|
|
def->data.file.path = strdup(val+strlen("pipe:"));
|
|
|
|
if (!def->data.file.path)
|
|
|
|
goto no_memory;
|
|
|
|
} else if (STREQ(val, "stdio")) {
|
|
|
|
def->type = VIR_DOMAIN_CHR_TYPE_STDIO;
|
|
|
|
} else if (STRPREFIX(val, "udp:")) {
|
|
|
|
const char *svc1, *host2, *svc2;
|
|
|
|
def->type = VIR_DOMAIN_CHR_TYPE_UDP;
|
|
|
|
val += strlen("udp:");
|
|
|
|
svc1 = strchr(val, ':');
|
|
|
|
host2 = svc1 ? strchr(svc1, '@') : NULL;
|
|
|
|
svc2 = host2 ? strchr(host2, ':') : NULL;
|
|
|
|
|
|
|
|
if (svc1)
|
|
|
|
def->data.udp.connectHost = strndup(val, svc1-val);
|
|
|
|
else
|
|
|
|
def->data.udp.connectHost = strdup(val);
|
2009-11-08 21:08:54 +00:00
|
|
|
|
|
|
|
if (!def->data.udp.connectHost)
|
|
|
|
goto no_memory;
|
|
|
|
|
2009-05-21 14:16:55 +00:00
|
|
|
if (svc1) {
|
|
|
|
svc1++;
|
|
|
|
if (host2)
|
|
|
|
def->data.udp.connectService = strndup(svc1, host2-svc1);
|
|
|
|
else
|
|
|
|
def->data.udp.connectService = strdup(svc1);
|
2009-11-08 21:08:54 +00:00
|
|
|
|
|
|
|
if (!def->data.udp.connectService)
|
|
|
|
goto no_memory;
|
2009-05-21 14:16:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (host2) {
|
|
|
|
host2++;
|
|
|
|
if (svc2)
|
|
|
|
def->data.udp.bindHost = strndup(host2, svc2-host2);
|
|
|
|
else
|
|
|
|
def->data.udp.bindHost = strdup(host2);
|
2009-11-08 21:08:54 +00:00
|
|
|
|
|
|
|
if (!def->data.udp.bindHost)
|
|
|
|
goto no_memory;
|
2009-05-21 14:16:55 +00:00
|
|
|
}
|
|
|
|
if (svc2) {
|
|
|
|
svc2++;
|
|
|
|
def->data.udp.bindService = strdup(svc2);
|
2009-11-08 21:08:54 +00:00
|
|
|
if (!def->data.udp.bindService)
|
|
|
|
goto no_memory;
|
2009-05-21 14:16:55 +00:00
|
|
|
}
|
|
|
|
} else if (STRPREFIX(val, "tcp:") ||
|
|
|
|
STRPREFIX(val, "telnet:")) {
|
|
|
|
const char *opt, *svc;
|
|
|
|
def->type = VIR_DOMAIN_CHR_TYPE_TCP;
|
|
|
|
if (STRPREFIX(val, "tcp:")) {
|
|
|
|
val += strlen("tcp:");
|
|
|
|
} else {
|
|
|
|
val += strlen("telnet:");
|
|
|
|
def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
|
|
|
|
}
|
|
|
|
svc = strchr(val, ':');
|
|
|
|
if (!svc) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot find port number in character device %s"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
opt = strchr(svc, ',');
|
|
|
|
if (opt && strstr(opt, "server"))
|
|
|
|
def->data.tcp.listen = 1;
|
|
|
|
|
|
|
|
def->data.tcp.host = strndup(val, svc-val);
|
2009-11-08 21:08:54 +00:00
|
|
|
if (!def->data.tcp.host)
|
|
|
|
goto no_memory;
|
2009-05-21 14:16:55 +00:00
|
|
|
svc++;
|
|
|
|
if (opt) {
|
|
|
|
def->data.tcp.service = strndup(svc, opt-svc);
|
|
|
|
} else {
|
|
|
|
def->data.tcp.service = strdup(svc);
|
|
|
|
}
|
2009-11-08 21:08:54 +00:00
|
|
|
if (!def->data.tcp.service)
|
|
|
|
goto no_memory;
|
2009-05-21 14:16:55 +00:00
|
|
|
} else if (STRPREFIX(val, "unix:")) {
|
|
|
|
const char *opt;
|
|
|
|
val += strlen("unix:");
|
|
|
|
opt = strchr(val, ',');
|
|
|
|
def->type = VIR_DOMAIN_CHR_TYPE_UNIX;
|
|
|
|
if (opt) {
|
|
|
|
if (strstr(opt, "listen"))
|
|
|
|
def->data.nix.listen = 1;
|
|
|
|
def->data.nix.path = strndup(val, opt-val);
|
|
|
|
} else {
|
|
|
|
def->data.nix.path = strdup(val);
|
|
|
|
}
|
|
|
|
if (!def->data.nix.path)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
} else if (STRPREFIX(val, "/dev")) {
|
|
|
|
def->type = VIR_DOMAIN_CHR_TYPE_DEV;
|
|
|
|
def->data.file.path = strdup(val);
|
|
|
|
if (!def->data.file.path)
|
|
|
|
goto no_memory;
|
|
|
|
} else {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown character device syntax %s"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
no_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-05-21 14:16:55 +00:00
|
|
|
error:
|
|
|
|
virDomainChrDefFree(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-12-18 15:24:14 +00:00
|
|
|
|
2010-01-18 15:51:52 +00:00
|
|
|
static virCPUDefPtr
|
2010-02-04 18:19:08 +00:00
|
|
|
qemuInitGuestCPU(virDomainDefPtr dom)
|
2010-01-18 15:51:52 +00:00
|
|
|
{
|
|
|
|
if (!dom->cpu) {
|
|
|
|
virCPUDefPtr cpu;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(cpu) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-01-18 15:51:52 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cpu->type = VIR_CPU_TYPE_GUEST;
|
|
|
|
cpu->match = VIR_CPU_MATCH_EXACT;
|
|
|
|
dom->cpu = cpu;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dom->cpu;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-18 15:24:14 +00:00
|
|
|
static int
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuParseCommandLineCPU(virDomainDefPtr dom,
|
2009-12-18 15:24:14 +00:00
|
|
|
const char *val)
|
|
|
|
{
|
|
|
|
virCPUDefPtr cpu;
|
|
|
|
const char *p = val;
|
|
|
|
const char *next;
|
|
|
|
|
2010-02-04 18:19:08 +00:00
|
|
|
if (!(cpu = qemuInitGuestCPU(dom)))
|
2010-01-18 15:51:52 +00:00
|
|
|
goto error;
|
2009-12-18 15:24:14 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
if (*p == '\0' || *p == ',')
|
|
|
|
goto syntax;
|
|
|
|
|
|
|
|
if ((next = strchr(p, ',')))
|
|
|
|
next++;
|
|
|
|
|
|
|
|
if (!cpu->model) {
|
|
|
|
if (next)
|
|
|
|
cpu->model = strndup(p, next - p - 1);
|
|
|
|
else
|
|
|
|
cpu->model = strdup(p);
|
|
|
|
|
|
|
|
if (!cpu->model)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
else if (*p == '+' || *p == '-') {
|
|
|
|
char *feature;
|
|
|
|
int policy;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2010-02-10 12:22:36 +00:00
|
|
|
ret = virCPUDefAddFeature(cpu, feature, policy);
|
2009-12-18 15:24:14 +00:00
|
|
|
VIR_FREE(feature);
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} while ((p = next));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
syntax:
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown CPU syntax '%s'"), val);
|
2009-12-18 15:24:14 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
no_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-12-18 15:24:14 +00:00
|
|
|
error:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-18 15:51:52 +00:00
|
|
|
static int
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuParseCommandLineSmp(virDomainDefPtr dom,
|
2010-01-18 15:51:52 +00:00
|
|
|
const char *val)
|
|
|
|
{
|
|
|
|
unsigned int sockets = 0;
|
|
|
|
unsigned int cores = 0;
|
|
|
|
unsigned int threads = 0;
|
|
|
|
int i;
|
|
|
|
int nkws;
|
|
|
|
char **kws;
|
|
|
|
char **vals;
|
|
|
|
int n;
|
|
|
|
char *end;
|
|
|
|
int ret;
|
|
|
|
|
2010-02-09 18:15:41 +00:00
|
|
|
nkws = qemuParseCommandLineKeywords(val, &kws, &vals, 1);
|
2010-01-18 15:51:52 +00:00
|
|
|
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 || *end != '\0')
|
|
|
|
goto syntax;
|
|
|
|
dom->vcpus = n;
|
|
|
|
} else {
|
|
|
|
if (virStrToLong_i(vals[i], &end, 10, &n) < 0 ||
|
|
|
|
!end || *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
|
|
|
|
goto syntax;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sockets && cores && threads) {
|
|
|
|
virCPUDefPtr cpu;
|
|
|
|
|
2010-02-04 18:19:08 +00:00
|
|
|
if (!(cpu = qemuInitGuestCPU(dom)))
|
2010-01-18 15:51:52 +00:00
|
|
|
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:
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse CPU topology '%s'"), val);
|
2010-01-18 15:51:52 +00:00
|
|
|
error:
|
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-21 14:16:55 +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....
|
|
|
|
*/
|
2010-02-09 18:15:41 +00:00
|
|
|
virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
|
2009-05-21 14:16:55 +00:00
|
|
|
const char **progenv,
|
|
|
|
const char **progargv)
|
|
|
|
{
|
|
|
|
virDomainDefPtr def;
|
|
|
|
int i;
|
|
|
|
int nographics = 0;
|
|
|
|
int fullscreen = 0;
|
|
|
|
char *path;
|
|
|
|
int nnics = 0;
|
|
|
|
const char **nics = NULL;
|
2009-07-06 13:59:19 +00:00
|
|
|
int video = VIR_DOMAIN_VIDEO_TYPE_CIRRUS;
|
2009-12-10 19:07:16 +00:00
|
|
|
int nvirtiodisk = 0;
|
2009-05-21 14:16:55 +00:00
|
|
|
|
|
|
|
if (!progargv[0]) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("no emulator path found"));
|
2009-05-21 14:16:55 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
2009-05-28 13:21:19 +00:00
|
|
|
virUUIDGenerate(def->uuid);
|
|
|
|
|
2009-05-21 14:16:55 +00:00
|
|
|
def->id = -1;
|
|
|
|
def->memory = def->maxmem = 64 * 1024;
|
|
|
|
def->vcpus = 1;
|
2010-02-02 17:22:03 +00:00
|
|
|
def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
|
2009-05-21 14:16:55 +00:00
|
|
|
def->features = (1 << VIR_DOMAIN_FEATURE_ACPI)
|
|
|
|
/*| (1 << VIR_DOMAIN_FEATURE_APIC)*/;
|
|
|
|
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");
|
|
|
|
if (path &&
|
|
|
|
STRPREFIX(path, "qemu-system-"))
|
|
|
|
def->os.arch = strdup(path + strlen("qemu-system-"));
|
|
|
|
else
|
|
|
|
def->os.arch = strdup("i686");
|
|
|
|
if (!def->os.arch)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
#define WANT_VALUE() \
|
|
|
|
const char *val = progargv[++i]; \
|
|
|
|
if (!val) { \
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, \
|
|
|
|
_("missing value for %s argument"), arg); \
|
2009-05-21 14:16:55 +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;
|
|
|
|
|
|
|
|
tmp = strchr(val, ':');
|
|
|
|
if (tmp) {
|
|
|
|
char *opts;
|
|
|
|
if (virStrToLong_i(tmp+1, &opts, 10, &vnc->data.vnc.port) < 0) {
|
|
|
|
VIR_FREE(vnc);
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, \
|
|
|
|
_("cannot parse VNC port '%s'"), tmp+1);
|
2009-05-21 14:16:55 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
vnc->data.vnc.listenAddr = strndup(val, tmp-val);
|
|
|
|
if (!vnc->data.vnc.listenAddr) {
|
|
|
|
VIR_FREE(vnc);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
vnc->data.vnc.port += 5900;
|
|
|
|
vnc->data.vnc.autoport = 0;
|
|
|
|
} else {
|
|
|
|
vnc->data.vnc.autoport = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, \
|
|
|
|
_("cannot parse memory level '%s'"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
def->memory = def->maxmem = mem * 1024;
|
|
|
|
} else if (STREQ(arg, "-smp")) {
|
|
|
|
WANT_VALUE();
|
2010-02-09 18:15:41 +00:00
|
|
|
if (qemuParseCommandLineSmp(def, val) < 0)
|
2009-05-21 14:16:55 +00:00
|
|
|
goto error;
|
|
|
|
} else if (STREQ(arg, "-uuid")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (virUUIDParse(val, def->uuid) < 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, \
|
|
|
|
_("cannot parse UUID '%s'"), val);
|
2009-05-21 14:16:55 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else if (STRPREFIX(arg, "-hd") ||
|
|
|
|
STRPREFIX(arg, "-sd") ||
|
|
|
|
STRPREFIX(arg, "-fd") ||
|
|
|
|
STREQ(arg, "-cdrom")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
virDomainDiskDefPtr disk;
|
|
|
|
if (VIR_ALLOC(disk) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (STRPREFIX(val, "/dev/"))
|
|
|
|
disk->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
|
|
|
|
else
|
|
|
|
disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
|
|
|
|
if (STREQ(arg, "-cdrom")) {
|
|
|
|
disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
|
|
|
|
disk->dst = strdup("hdc");
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
disk->src = strdup(val);
|
|
|
|
if (!disk->src ||
|
|
|
|
!disk->dst) {
|
|
|
|
virDomainDiskDefFree(disk);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
2009-12-22 16:53:20 +00:00
|
|
|
virDomainDiskDefAssignAddress(disk);
|
|
|
|
|
2009-05-21 14:16:55 +00:00
|
|
|
if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) {
|
|
|
|
virDomainDiskDefFree(disk);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
def->disks[def->ndisks++] = disk;
|
|
|
|
} 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;
|
|
|
|
} else if (STREQ(arg, "-nographic")) {
|
|
|
|
nographics = 1;
|
|
|
|
} else if (STREQ(arg, "-full-screen")) {
|
|
|
|
fullscreen = 1;
|
|
|
|
} else if (STREQ(arg, "-localtime")) {
|
2010-02-02 17:22:03 +00:00
|
|
|
def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
|
2009-05-21 14:16:55 +00:00
|
|
|
} else if (STREQ(arg, "-kernel")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (!(def->os.kernel = strdup(val)))
|
|
|
|
goto no_memory;
|
|
|
|
} 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")) {
|
|
|
|
int n, b = 0;
|
|
|
|
WANT_VALUE();
|
|
|
|
for (n = 0 ; val[n] && b < VIR_DOMAIN_BOOT_LAST ; n++) {
|
|
|
|
if (val[n] == 'a')
|
|
|
|
def->os.bootDevs[b++] = VIR_DOMAIN_BOOT_FLOPPY;
|
|
|
|
else if (val[n] == 'c')
|
|
|
|
def->os.bootDevs[b++] = VIR_DOMAIN_BOOT_DISK;
|
|
|
|
else if (val[n] == 'd')
|
|
|
|
def->os.bootDevs[b++] = VIR_DOMAIN_BOOT_CDROM;
|
|
|
|
else if (val[n] == 'n')
|
|
|
|
def->os.bootDevs[b++] = VIR_DOMAIN_BOOT_NET;
|
|
|
|
}
|
|
|
|
def->os.nBootDevs = b;
|
|
|
|
} else if (STREQ(arg, "-name")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (!(def->name = strdup(val)))
|
|
|
|
goto no_memory;
|
|
|
|
} else if (STREQ(arg, "-M")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (!(def->os.machine = strdup(val)))
|
|
|
|
goto no_memory;
|
|
|
|
} else if (STREQ(arg, "-serial")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (STRNEQ(val, "none")) {
|
|
|
|
virDomainChrDefPtr chr;
|
2010-02-09 18:15:41 +00:00
|
|
|
if (!(chr = qemuParseCommandLineChr(val)))
|
2009-05-21 14:16:55 +00:00
|
|
|
goto error;
|
|
|
|
if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0) {
|
|
|
|
virDomainChrDefFree(chr);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
2009-11-05 13:19:14 +00:00
|
|
|
chr->targetType = VIR_DOMAIN_CHR_TARGET_TYPE_SERIAL;
|
|
|
|
chr->target.port = def->nserials;
|
2009-05-21 14:16:55 +00:00
|
|
|
def->serials[def->nserials++] = chr;
|
|
|
|
}
|
|
|
|
} else if (STREQ(arg, "-parallel")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
if (STRNEQ(val, "none")) {
|
|
|
|
virDomainChrDefPtr chr;
|
2010-02-09 18:15:41 +00:00
|
|
|
if (!(chr = qemuParseCommandLineChr(val)))
|
2009-05-21 14:16:55 +00:00
|
|
|
goto error;
|
|
|
|
if (VIR_REALLOC_N(def->parallels, def->nparallels+1) < 0) {
|
|
|
|
virDomainChrDefFree(chr);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
2009-11-05 13:19:14 +00:00
|
|
|
chr->targetType = VIR_DOMAIN_CHR_TARGET_TYPE_PARALLEL;
|
|
|
|
chr->target.port = def->nparallels;
|
2009-05-21 14:16:55 +00:00
|
|
|
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:")) {
|
|
|
|
virDomainDiskDefPtr disk;
|
|
|
|
if (VIR_ALLOC(disk) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
disk->src = strdup(val + strlen("disk:"));
|
|
|
|
if (!disk->src) {
|
|
|
|
virDomainDiskDefFree(disk);
|
|
|
|
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;
|
|
|
|
if (!(disk->dst = strdup("sda"))) {
|
|
|
|
virDomainDiskDefFree(disk);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) {
|
|
|
|
virDomainDiskDefFree(disk);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
def->disks[def->ndisks++] = disk;
|
|
|
|
} else {
|
|
|
|
virDomainHostdevDefPtr hostdev;
|
2010-02-09 18:15:41 +00:00
|
|
|
if (!(hostdev = qemuParseCommandLineUSB(val)))
|
2009-05-21 14:16:55 +00:00
|
|
|
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;
|
2010-02-09 18:15:41 +00:00
|
|
|
if (!(net = qemuParseCommandLineNet(caps, val, nnics, nics)))
|
2009-05-21 14:16:55 +00:00
|
|
|
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")) {
|
|
|
|
virDomainDiskDefPtr disk;
|
|
|
|
WANT_VALUE();
|
2010-02-09 18:15:41 +00:00
|
|
|
if (!(disk = qemuParseCommandLineDisk(val, nvirtiodisk)))
|
2009-05-21 14:16:55 +00:00
|
|
|
goto error;
|
|
|
|
if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) {
|
|
|
|
virDomainDiskDefFree(disk);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
def->disks[def->ndisks++] = disk;
|
2009-12-10 19:07:16 +00:00
|
|
|
|
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
|
|
|
|
nvirtiodisk++;
|
2009-05-21 14:16:55 +00:00
|
|
|
} else if (STREQ(arg, "-pcidevice")) {
|
|
|
|
virDomainHostdevDefPtr hostdev;
|
|
|
|
WANT_VALUE();
|
2010-02-09 18:15:41 +00:00
|
|
|
if (!(hostdev = qemuParseCommandLinePCI(val)))
|
2009-05-21 14:16:55 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2009-10-21 12:26:38 +00:00
|
|
|
} else if (STREQ(arg, "-watchdog")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
int model = virDomainWatchdogModelTypeFromString (val);
|
|
|
|
|
|
|
|
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();
|
|
|
|
int action = virDomainWatchdogActionTypeFromString (val);
|
|
|
|
|
|
|
|
if (action != -1)
|
|
|
|
def->watchdog->action = action;
|
2009-05-21 14:16:55 +00:00
|
|
|
} else if (STREQ(arg, "-bootloader")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
def->os.bootloader = strdup(val);
|
|
|
|
if (!def->os.bootloader)
|
|
|
|
goto no_memory;
|
2009-07-06 13:59:19 +00:00
|
|
|
} 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();
|
2009-12-21 22:38:05 +00:00
|
|
|
if (STRNEQ(val, "none")) {
|
|
|
|
video = qemuVideoTypeFromString(val);
|
|
|
|
if (video < 0) {
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown video adapter type '%s'"), val);
|
2009-12-21 22:38:05 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2009-07-06 13:59:19 +00:00
|
|
|
}
|
2009-12-18 15:24:14 +00:00
|
|
|
} else if (STREQ(arg, "-cpu")) {
|
|
|
|
WANT_VALUE();
|
2010-02-09 18:15:41 +00:00
|
|
|
if (qemuParseCommandLineCPU(def, val) < 0)
|
2009-12-18 15:24:14 +00:00
|
|
|
goto error;
|
2009-05-21 14:16:55 +00:00
|
|
|
} else if (STREQ(arg, "-domid")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
/* ignore, generted on the fly */
|
|
|
|
} else if (STREQ(arg, "-usb")) {
|
|
|
|
/* ignore, always added by libvirt */
|
|
|
|
} else if (STREQ(arg, "-pidfile")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
/* ignore, used by libvirt as needed */
|
|
|
|
} else if (STREQ(arg, "-incoming")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
/* ignore, used via restore/migrate APIs */
|
|
|
|
} else if (STREQ(arg, "-monitor")) {
|
|
|
|
WANT_VALUE();
|
|
|
|
/* ignore, used internally by libvirt */
|
|
|
|
} else if (STREQ(arg, "-S")) {
|
|
|
|
/* ignore, always added by libvirt */
|
|
|
|
} else {
|
|
|
|
VIR_WARN(_("unknown QEMU argument '%s' during conversion"), arg);
|
|
|
|
#if 0
|
2010-02-09 18:15:41 +00:00
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown argument '%s'"), arg);
|
2009-05-21 14:16:55 +00:00
|
|
|
goto error;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef WANT_VALUE
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-07-06 13:59:19 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-05-21 14:16:55 +00:00
|
|
|
VIR_FREE(nics);
|
|
|
|
|
|
|
|
if (!def->name) {
|
|
|
|
if (!(def->name = strdup("unnamed")))
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
2010-02-18 16:52:03 +00:00
|
|
|
if (virDomainDefAddImplicitControllers(def) < 0)
|
2010-01-05 13:31:20 +00:00
|
|
|
goto error;
|
|
|
|
|
2009-05-21 14:16:55 +00:00
|
|
|
return def;
|
|
|
|
|
|
|
|
no_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-05-21 14:16:55 +00:00
|
|
|
error:
|
|
|
|
virDomainDefFree(def);
|
|
|
|
VIR_FREE(nics);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-09 18:15:41 +00:00
|
|
|
virDomainDefPtr qemuParseCommandLineString(virCapsPtr caps,
|
2009-05-21 14:16:55 +00:00
|
|
|
const char *args)
|
|
|
|
{
|
|
|
|
const char **progenv = NULL;
|
|
|
|
const char **progargv = NULL;
|
|
|
|
virDomainDefPtr def = NULL;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (qemuStringToArgvEnv(args, &progenv, &progargv) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2010-02-09 18:15:41 +00:00
|
|
|
def = qemuParseCommandLine(caps, progenv, progargv);
|
2009-05-21 14:16:55 +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;
|
|
|
|
}
|