libvirt/src/xenxs/xen_xm.c

2029 lines
67 KiB
C
Raw Normal View History

2011-02-21 13:40:10 +00:00
/*
* xen_xm.c: Xen XM parsing functions
*
xml: use better types for memory values Using 'unsigned long' for memory values is risky on 32-bit platforms, as a PAE guest can have more than 4GiB memory. Our API is (unfortunately) locked at 'unsigned long' and a scale of 1024, but the rest of our system should consistently use 64-bit values, especially since the previous patch centralized overflow checking. * src/conf/domain_conf.h (_virDomainDef): Always use 64-bit values for memory. Change hugepage_backed to a bool. * src/conf/domain_conf.c (virDomainDefParseXML) (virDomainDefCheckABIStability, virDomainDefFormatInternal): Fix clients. * src/vmx/vmx.c (virVMXFormatConfig): Likewise. * src/xenxs/xen_sxpr.c (xenParseSxpr, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetULongLong): New function. (xenXMConfigGetULong, xenXMConfigSetInt): Avoid truncation. (xenParseXM, xenFormatXM): Fix clients. * src/phyp/phyp_driver.c (phypBuildLpar): Likewise. * src/openvz/openvz_driver.c (openvzDomainSetMemoryInternal): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainDefineXML): Likewise. * src/qemu/qemu_command.c (qemuBuildCommandLine): Likewise. * src/qemu/qemu_process.c (qemuProcessStart): Likewise. * src/qemu/qemu_monitor.h (qemuMonitorGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.h (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.c (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetInfo) (qemuDomainGetXMLDesc): Likewise. * src/uml/uml_conf.c (umlBuildCommandLine): Likewise.
2012-03-02 20:27:39 +00:00
* Copyright (C) 2006-2007, 2009-2010, 2012 Red Hat, Inc.
2011-02-21 13:40:10 +00:00
* Copyright (C) 2011 Univention GmbH
* 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>
* Author: Markus Groß <gross@univention.de>
*/
#include <config.h>
#include "internal.h"
#include "virterror_internal.h"
#include "conf.h"
#include "memory.h"
#include "verify.h"
#include "uuid.h"
#include "sexpr.h"
#include "count-one-bits.h"
#include "xenxs_private.h"
#include "xen_xm.h"
#include "xen_sxpr.h"
#include "domain_conf.h"
2011-02-21 13:40:10 +00:00
xml: use better types for memory values Using 'unsigned long' for memory values is risky on 32-bit platforms, as a PAE guest can have more than 4GiB memory. Our API is (unfortunately) locked at 'unsigned long' and a scale of 1024, but the rest of our system should consistently use 64-bit values, especially since the previous patch centralized overflow checking. * src/conf/domain_conf.h (_virDomainDef): Always use 64-bit values for memory. Change hugepage_backed to a bool. * src/conf/domain_conf.c (virDomainDefParseXML) (virDomainDefCheckABIStability, virDomainDefFormatInternal): Fix clients. * src/vmx/vmx.c (virVMXFormatConfig): Likewise. * src/xenxs/xen_sxpr.c (xenParseSxpr, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetULongLong): New function. (xenXMConfigGetULong, xenXMConfigSetInt): Avoid truncation. (xenParseXM, xenFormatXM): Fix clients. * src/phyp/phyp_driver.c (phypBuildLpar): Likewise. * src/openvz/openvz_driver.c (openvzDomainSetMemoryInternal): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainDefineXML): Likewise. * src/qemu/qemu_command.c (qemuBuildCommandLine): Likewise. * src/qemu/qemu_process.c (qemuProcessStart): Likewise. * src/qemu/qemu_monitor.h (qemuMonitorGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.h (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.c (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetInfo) (qemuDomainGetXMLDesc): Likewise. * src/uml/uml_conf.c (umlBuildCommandLine): Likewise.
2012-03-02 20:27:39 +00:00
/* Convenience method to grab a long int from the config file object */
2011-02-21 13:40:10 +00:00
static int xenXMConfigGetBool(virConfPtr conf,
const char *name,
int *value,
int def) {
virConfValuePtr val;
*value = 0;
if (!(val = virConfGetValue(conf, name))) {
*value = def;
return 0;
}
if (val->type == VIR_CONF_LONG) {
*value = val->l ? 1 : 0;
} else if (val->type == VIR_CONF_STRING) {
*value = STREQ(val->str, "1") ? 1 : 0;
} else {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("config value %s was malformed"), name);
return -1;
}
return 0;
}
/* Convenience method to grab a int from the config file object */
static int xenXMConfigGetULong(virConfPtr conf,
const char *name,
unsigned long *value,
xml: use better types for memory values Using 'unsigned long' for memory values is risky on 32-bit platforms, as a PAE guest can have more than 4GiB memory. Our API is (unfortunately) locked at 'unsigned long' and a scale of 1024, but the rest of our system should consistently use 64-bit values, especially since the previous patch centralized overflow checking. * src/conf/domain_conf.h (_virDomainDef): Always use 64-bit values for memory. Change hugepage_backed to a bool. * src/conf/domain_conf.c (virDomainDefParseXML) (virDomainDefCheckABIStability, virDomainDefFormatInternal): Fix clients. * src/vmx/vmx.c (virVMXFormatConfig): Likewise. * src/xenxs/xen_sxpr.c (xenParseSxpr, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetULongLong): New function. (xenXMConfigGetULong, xenXMConfigSetInt): Avoid truncation. (xenParseXM, xenFormatXM): Fix clients. * src/phyp/phyp_driver.c (phypBuildLpar): Likewise. * src/openvz/openvz_driver.c (openvzDomainSetMemoryInternal): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainDefineXML): Likewise. * src/qemu/qemu_command.c (qemuBuildCommandLine): Likewise. * src/qemu/qemu_process.c (qemuProcessStart): Likewise. * src/qemu/qemu_monitor.h (qemuMonitorGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.h (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.c (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetInfo) (qemuDomainGetXMLDesc): Likewise. * src/uml/uml_conf.c (umlBuildCommandLine): Likewise.
2012-03-02 20:27:39 +00:00
unsigned long def) {
2011-02-21 13:40:10 +00:00
virConfValuePtr val;
*value = 0;
if (!(val = virConfGetValue(conf, name))) {
*value = def;
return 0;
}
if (val->type == VIR_CONF_LONG) {
*value = val->l;
} else if (val->type == VIR_CONF_STRING) {
char *ret;
*value = strtol(val->str, &ret, 10);
if (ret == val->str) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("config value %s was malformed"), name);
return -1;
}
} else {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("config value %s was malformed"), name);
return -1;
}
return 0;
}
xml: use better types for memory values Using 'unsigned long' for memory values is risky on 32-bit platforms, as a PAE guest can have more than 4GiB memory. Our API is (unfortunately) locked at 'unsigned long' and a scale of 1024, but the rest of our system should consistently use 64-bit values, especially since the previous patch centralized overflow checking. * src/conf/domain_conf.h (_virDomainDef): Always use 64-bit values for memory. Change hugepage_backed to a bool. * src/conf/domain_conf.c (virDomainDefParseXML) (virDomainDefCheckABIStability, virDomainDefFormatInternal): Fix clients. * src/vmx/vmx.c (virVMXFormatConfig): Likewise. * src/xenxs/xen_sxpr.c (xenParseSxpr, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetULongLong): New function. (xenXMConfigGetULong, xenXMConfigSetInt): Avoid truncation. (xenParseXM, xenFormatXM): Fix clients. * src/phyp/phyp_driver.c (phypBuildLpar): Likewise. * src/openvz/openvz_driver.c (openvzDomainSetMemoryInternal): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainDefineXML): Likewise. * src/qemu/qemu_command.c (qemuBuildCommandLine): Likewise. * src/qemu/qemu_process.c (qemuProcessStart): Likewise. * src/qemu/qemu_monitor.h (qemuMonitorGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.h (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.c (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetInfo) (qemuDomainGetXMLDesc): Likewise. * src/uml/uml_conf.c (umlBuildCommandLine): Likewise.
2012-03-02 20:27:39 +00:00
/* Convenience method to grab a int from the config file object */
static int xenXMConfigGetULongLong(virConfPtr conf,
const char *name,
unsigned long long *value,
unsigned long long def) {
virConfValuePtr val;
*value = 0;
if (!(val = virConfGetValue(conf, name))) {
*value = def;
return 0;
}
if (val->type == VIR_CONF_LONG) {
*value = val->l;
} else if (val->type == VIR_CONF_STRING) {
char *ret;
*value = strtoll(val->str, &ret, 10);
if (ret == val->str) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("config value %s was malformed"), name);
return -1;
}
} else {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("config value %s was malformed"), name);
return -1;
}
return 0;
}
2011-02-21 13:40:10 +00:00
/* Convenience method to grab a string from the config file object */
static int xenXMConfigGetString(virConfPtr conf,
const char *name,
const char **value,
const char *def) {
virConfValuePtr val;
*value = NULL;
if (!(val = virConfGetValue(conf, name))) {
*value = def;
return 0;
}
if (val->type != VIR_CONF_STRING) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("config value %s was malformed"), name);
return -1;
}
if (!val->str)
*value = def;
else
*value = val->str;
return 0;
}
static int xenXMConfigCopyStringInternal(virConfPtr conf,
const char *name,
char **value,
int allowMissing) {
virConfValuePtr val;
*value = NULL;
if (!(val = virConfGetValue(conf, name))) {
if (allowMissing)
return 0;
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("config value %s was missing"), name);
return -1;
}
if (val->type != VIR_CONF_STRING) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("config value %s was not a string"), name);
return -1;
}
if (!val->str) {
if (allowMissing)
return 0;
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("config value %s was missing"), name);
return -1;
}
if (!(*value = strdup(val->str))) {
virReportOOMError();
return -1;
}
return 0;
}
static int xenXMConfigCopyString(virConfPtr conf,
const char *name,
char **value) {
return xenXMConfigCopyStringInternal(conf, name, value, 0);
}
static int xenXMConfigCopyStringOpt(virConfPtr conf,
const char *name,
char **value) {
return xenXMConfigCopyStringInternal(conf, name, value, 1);
}
/* Convenience method to grab a string UUID from the config file object */
static int xenXMConfigGetUUID(virConfPtr conf, const char *name, unsigned char *uuid) {
virConfValuePtr val;
if (!uuid || !name || !conf) {
XENXS_ERROR(VIR_ERR_INVALID_ARG,
_("Arguments must be non null"));
return -1;
}
2011-02-21 13:40:10 +00:00
if (!(val = virConfGetValue(conf, name))) {
XENXS_ERROR(VIR_ERR_CONF_SYNTAX,
_("config value %s was missing"), name);
return -1;
2011-02-21 13:40:10 +00:00
}
if (val->type != VIR_CONF_STRING) {
XENXS_ERROR(VIR_ERR_CONF_SYNTAX,
_("config value %s not a string"), name);
return -1;
}
if (!val->str) {
XENXS_ERROR(VIR_ERR_CONF_SYNTAX,
_("%s can't be empty"), name);
return -1;
}
2011-02-21 13:40:10 +00:00
if (virUUIDParse(val->str, uuid) < 0) {
XENXS_ERROR(VIR_ERR_CONF_SYNTAX,
_("%s not parseable"), val->str);
return -1;
}
2011-02-21 13:40:10 +00:00
return 0;
2011-02-21 13:40:10 +00:00
}
#define MAX_VFB 1024
/*
* Turn a config record into a lump of XML describing the
* domain, suitable for later feeding for virDomainCreateXML
*/
virDomainDefPtr
2011-02-21 13:40:12 +00:00
xenParseXM(virConfPtr conf, int xendConfigVersion,
2011-02-21 13:40:10 +00:00
virCapsPtr caps) {
const char *str;
int hvm = 0;
int val;
virConfValuePtr list;
virDomainDefPtr def = NULL;
virDomainDiskDefPtr disk = NULL;
virDomainNetDefPtr net = NULL;
virDomainGraphicsDefPtr graphics = NULL;
virDomainHostdevDefPtr hostdev = NULL;
int i;
const char *defaultArch, *defaultMachine;
int vmlocaltime = 0;
unsigned long count;
char *script = NULL;
conf: add <listen> subelement to domain <graphics> element Once it's plugged in, the <listen> element will be an optional replacement for the "listen" attribute that graphics elements already have. If the <listen> element is type='address', it will have an attribute called 'address' which will contain an IP address or dns name that the guest's display server should listen on. If, however, type='network', the <listen> element should have an attribute called 'network' that will be set to the name of a network configuration to get the IP address from. * docs/schemas/domain.rng: updated to allow the <listen> element * docs/formatdomain.html.in: document the <listen> element and its attributes. * src/conf/domain_conf.[hc]: 1) The domain parser, formatter, and data structure are modified to support 0 or more <listen> subelements to each <graphics> element. The old style "legacy" listen attribute is also still accepted, and will be stored internally just as if it were a separate <listen> element. On output (i.e. format), the address attribute of the first <listen> element of type 'address' will be duplicated in the legacy "listen" attribute of the <graphic> element. 2) The "listenAddr" attribute has been removed from the unions in virDomainGRaphicsDef for graphics types vnc, rdp, and spice. This attribute is now in the <listen> subelement (aka virDomainGraphicsListenDef) 3) Helper functions were written to provide simple access (both Get and Set) to the listen elements and their attributes. * src/libvirt_private.syms: export the listen helper functions * src/qemu/qemu_command.c, src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c, src/vbox/vbox_tmpl.c, src/vmx/vmx.c, src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c Modify all these files to use the listen helper functions rather than directly referencing the (now missing) listenAddr attribute. There can be multiple <listen> elements to a single <graphics>, but the drivers all currently only support one, so all replacements of direct access with a helper function indicate index "0". * tests/* - only 3 of these are new files added explicitly to test the new <listen> element. All the others have been modified to reflect the fact that any legacy "listen" attributes passed in to the domain parse will be saved in a <listen> element (i.e. one of the virDomainGraphicsListenDefs), and during the domain format function, both the <listen> element as well as the legacy attributes will be output.
2011-07-07 04:20:28 +00:00
char *listenAddr = NULL;
2011-02-21 13:40:10 +00:00
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
return NULL;
}
def->virtType = VIR_DOMAIN_VIRT_XEN;
def->id = -1;
if (xenXMConfigCopyString(conf, "name", &def->name) < 0)
goto cleanup;
if (xenXMConfigGetUUID(conf, "uuid", def->uuid) < 0)
goto cleanup;
if ((xenXMConfigGetString(conf, "builder", &str, "linux") == 0) &&
STREQ(str, "hvm"))
hvm = 1;
if (!(def->os.type = strdup(hvm ? "hvm" : "xen")))
goto no_memory;
defaultArch = virCapabilitiesDefaultGuestArch(caps, def->os.type, virDomainVirtTypeToString(def->virtType));
if (defaultArch == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("no supported architecture for os type '%s'"),
def->os.type);
goto cleanup;
}
if (!(def->os.arch = strdup(defaultArch)))
goto no_memory;
defaultMachine = virCapabilitiesDefaultGuestMachine(caps,
def->os.type,
def->os.arch,
virDomainVirtTypeToString(def->virtType));
if (defaultMachine != NULL) {
if (!(def->os.machine = strdup(defaultMachine)))
goto no_memory;
}
if (hvm) {
const char *boot;
if (xenXMConfigCopyString(conf, "kernel", &def->os.loader) < 0)
goto cleanup;
if (xenXMConfigGetString(conf, "boot", &boot, "c") < 0)
goto cleanup;
for (i = 0 ; i < VIR_DOMAIN_BOOT_LAST && boot[i] ; i++) {
switch (*boot) {
case 'a':
def->os.bootDevs[i] = VIR_DOMAIN_BOOT_FLOPPY;
break;
case 'd':
def->os.bootDevs[i] = VIR_DOMAIN_BOOT_CDROM;
break;
case 'n':
def->os.bootDevs[i] = VIR_DOMAIN_BOOT_NET;
break;
case 'c':
default:
def->os.bootDevs[i] = VIR_DOMAIN_BOOT_DISK;
break;
}
def->os.nBootDevs++;
}
} else {
if (xenXMConfigCopyStringOpt(conf, "bootloader", &def->os.bootloader) < 0)
goto cleanup;
if (xenXMConfigCopyStringOpt(conf, "bootargs", &def->os.bootloaderArgs) < 0)
goto cleanup;
if (xenXMConfigCopyStringOpt(conf, "kernel", &def->os.kernel) < 0)
goto cleanup;
if (xenXMConfigCopyStringOpt(conf, "ramdisk", &def->os.initrd) < 0)
goto cleanup;
if (xenXMConfigCopyStringOpt(conf, "extra", &def->os.cmdline) < 0)
goto cleanup;
}
xml: use better types for memory values Using 'unsigned long' for memory values is risky on 32-bit platforms, as a PAE guest can have more than 4GiB memory. Our API is (unfortunately) locked at 'unsigned long' and a scale of 1024, but the rest of our system should consistently use 64-bit values, especially since the previous patch centralized overflow checking. * src/conf/domain_conf.h (_virDomainDef): Always use 64-bit values for memory. Change hugepage_backed to a bool. * src/conf/domain_conf.c (virDomainDefParseXML) (virDomainDefCheckABIStability, virDomainDefFormatInternal): Fix clients. * src/vmx/vmx.c (virVMXFormatConfig): Likewise. * src/xenxs/xen_sxpr.c (xenParseSxpr, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetULongLong): New function. (xenXMConfigGetULong, xenXMConfigSetInt): Avoid truncation. (xenParseXM, xenFormatXM): Fix clients. * src/phyp/phyp_driver.c (phypBuildLpar): Likewise. * src/openvz/openvz_driver.c (openvzDomainSetMemoryInternal): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainDefineXML): Likewise. * src/qemu/qemu_command.c (qemuBuildCommandLine): Likewise. * src/qemu/qemu_process.c (qemuProcessStart): Likewise. * src/qemu/qemu_monitor.h (qemuMonitorGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.h (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.c (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetInfo) (qemuDomainGetXMLDesc): Likewise. * src/uml/uml_conf.c (umlBuildCommandLine): Likewise.
2012-03-02 20:27:39 +00:00
if (xenXMConfigGetULongLong(conf, "memory", &def->mem.cur_balloon,
MIN_XEN_GUEST_SIZE * 2) < 0)
2011-02-21 13:40:10 +00:00
goto cleanup;
xml: use better types for memory values Using 'unsigned long' for memory values is risky on 32-bit platforms, as a PAE guest can have more than 4GiB memory. Our API is (unfortunately) locked at 'unsigned long' and a scale of 1024, but the rest of our system should consistently use 64-bit values, especially since the previous patch centralized overflow checking. * src/conf/domain_conf.h (_virDomainDef): Always use 64-bit values for memory. Change hugepage_backed to a bool. * src/conf/domain_conf.c (virDomainDefParseXML) (virDomainDefCheckABIStability, virDomainDefFormatInternal): Fix clients. * src/vmx/vmx.c (virVMXFormatConfig): Likewise. * src/xenxs/xen_sxpr.c (xenParseSxpr, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetULongLong): New function. (xenXMConfigGetULong, xenXMConfigSetInt): Avoid truncation. (xenParseXM, xenFormatXM): Fix clients. * src/phyp/phyp_driver.c (phypBuildLpar): Likewise. * src/openvz/openvz_driver.c (openvzDomainSetMemoryInternal): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainDefineXML): Likewise. * src/qemu/qemu_command.c (qemuBuildCommandLine): Likewise. * src/qemu/qemu_process.c (qemuProcessStart): Likewise. * src/qemu/qemu_monitor.h (qemuMonitorGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.h (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.c (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetInfo) (qemuDomainGetXMLDesc): Likewise. * src/uml/uml_conf.c (umlBuildCommandLine): Likewise.
2012-03-02 20:27:39 +00:00
if (xenXMConfigGetULongLong(conf, "maxmem", &def->mem.max_balloon,
def->mem.cur_balloon) < 0)
2011-02-21 13:40:10 +00:00
goto cleanup;
def->mem.cur_balloon *= 1024;
def->mem.max_balloon *= 1024;
if (xenXMConfigGetULong(conf, "vcpus", &count, 1) < 0 ||
MAX_VIRT_CPUS < count)
goto cleanup;
def->maxvcpus = count;
if (xenXMConfigGetULong(conf, "vcpu_avail", &count, -1) < 0)
goto cleanup;
def->vcpus = MIN(count_one_bits_l(count), def->maxvcpus);
if (xenXMConfigGetString(conf, "cpus", &str, NULL) < 0)
goto cleanup;
if (str) {
def->cpumasklen = 4096;
if (VIR_ALLOC_N(def->cpumask, def->cpumasklen) < 0)
goto no_memory;
if (virDomainCpuSetParse(str, 0,
2011-02-21 13:40:10 +00:00
def->cpumask, def->cpumasklen) < 0)
goto cleanup;
}
if (xenXMConfigGetString(conf, "on_poweroff", &str, "destroy") < 0)
goto cleanup;
if ((def->onPoweroff = virDomainLifecycleTypeFromString(str)) < 0) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("unexpected value %s for on_poweroff"), str);
goto cleanup;
}
if (xenXMConfigGetString(conf, "on_reboot", &str, "restart") < 0)
goto cleanup;
if ((def->onReboot = virDomainLifecycleTypeFromString(str)) < 0) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("unexpected value %s for on_reboot"), str);
goto cleanup;
}
if (xenXMConfigGetString(conf, "on_crash", &str, "restart") < 0)
goto cleanup;
if ((def->onCrash = virDomainLifecycleCrashTypeFromString(str)) < 0) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("unexpected value %s for on_crash"), str);
goto cleanup;
}
if (hvm) {
if (xenXMConfigGetBool(conf, "pae", &val, 0) < 0)
goto cleanup;
else if (val)
def->features |= (1 << VIR_DOMAIN_FEATURE_PAE);
if (xenXMConfigGetBool(conf, "acpi", &val, 0) < 0)
goto cleanup;
else if (val)
def->features |= (1 << VIR_DOMAIN_FEATURE_ACPI);
if (xenXMConfigGetBool(conf, "apic", &val, 0) < 0)
goto cleanup;
else if (val)
def->features |= (1 << VIR_DOMAIN_FEATURE_APIC);
if (xenXMConfigGetBool(conf, "hap", &val, 0) < 0)
goto cleanup;
else if (val)
def->features |= (1 << VIR_DOMAIN_FEATURE_HAP);
if (xenXMConfigGetBool(conf, "viridian", &val, 0) < 0)
goto cleanup;
else if (val)
def->features |= (1 << VIR_DOMAIN_FEATURE_VIRIDIAN);
if (xenXMConfigGetBool(conf, "hpet", &val, -1) < 0)
goto cleanup;
else if (val != -1) {
virDomainTimerDefPtr timer;
if (VIR_ALLOC_N(def->clock.timers, 1) < 0 ||
VIR_ALLOC(timer) < 0) {
virReportOOMError();
goto cleanup;
}
timer->name = VIR_DOMAIN_TIMER_NAME_HPET;
timer->present = val;
timer->tickpolicy = -1;
def->clock.ntimers = 1;
def->clock.timers[0] = timer;
}
2011-02-21 13:40:10 +00:00
}
if (xenXMConfigGetBool(conf, "localtime", &vmlocaltime, 0) < 0)
goto cleanup;
Xen: Fix <clock> handling XenD-3.1 introduced managed domains. HV-domains have rtc_timeoffset (hgd24f37b31030 from 2007-04-03), which tracks the offset between the hypervisors clock and the domains RTC, and is persisted by XenD. In combination with localtime=1 this had a bug until XenD-3.4 (hg5d701be7c37b from 2009-04-01) (I'm not 100% sure how that bug manifests, but at least for me in TZ=Europe/Berlin I see the previous offset relative to utc being applied to localtime again, which manifests in an extra hour being added) XenD implements the following variants for clock/@offset: - PV domains don't have a RTC → 'localtime' | 'utc' - <3.1: no managed domains → 'localtime' | 'utc' - ≥3.1: the offset is tracked for HV → 'variable' due to the localtime=1 bug → 'localtime' | 'utc' - ≥3.4: the offset is tracked for HV → 'variable' Current libvirtd still thinks XenD only implements <clock offset='utc'/> and <clock offset='localtime'/>, which is wrong, since the semantic of 'utc' and 'localtime' specifies, that the offset will be reset on domain-restart, while with 'variable' the offset is kept. (keeping the offset over "virsh edit" is important, since otherwise the clock might jump, which confuses certain guest OSs) xendConfigVersion was last incremented to 4 by the xen-folks for xen-3.1.0. I know of no way to reliably detect the version of XenD (user space tools), which may be different from the version of the hypervisor (kernel) version! Because of this only the change from 'utc'/'localtime' to 'variable' in XenD-3.1 is handled, not the buggy behaviour of XenD-3.1 until XenD-3.4. For backward compatibility with previous versions of libvirt Xen-HV still accepts 'utc' and 'localtime', but they are returned as 'variable' on the next read-back from Xend to libvirt, since this is what XenD implements: The RTC is NOT reset back to the specified time on next restart, but the previous offset is kept. This behaviour can be turned off by adding the additional attribute adjustment='reset', in which case libvirt will report an error instead of doing the conversion. The attribute can also be used as a shortcut to offset='variable' with basis='...'. With these changes, it is also necessary to adjust the xen tests: "localtime = 0" is always inserted, because otherwise on updates the value is not changed within XenD. adjustment='reset' is inserted for all cases, since they're all < XEND_CONFIG_VERSION_3_1_0, only 3.1 introduced persistent rtc_timeoffset. Some statements change their order because code was moved around. Signed-off-by: Philipp Hahn <hahn@univention.de>
2012-02-08 16:32:34 +00:00
if (hvm) {
/* only managed HVM domains since 3.1.0 have persistent rtc_timeoffset */
if (xendConfigVersion < XEND_CONFIG_VERSION_3_1_0) {
if (vmlocaltime)
def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
else
def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
def->clock.data.utc_reset = true;
} else {
unsigned long rtc_timeoffset;
def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_VARIABLE;
if (xenXMConfigGetULong(conf, "rtc_timeoffset", &rtc_timeoffset, 0) < 0)
goto cleanup;
def->clock.data.variable.adjustment = (int)rtc_timeoffset;
def->clock.data.variable.basis = vmlocaltime ?
VIR_DOMAIN_CLOCK_BASIS_LOCALTIME :
VIR_DOMAIN_CLOCK_BASIS_UTC;
}
} else {
/* PV domains do not have an emulated RTC and the offset is fixed. */
def->clock.offset = vmlocaltime ?
VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME :
VIR_DOMAIN_CLOCK_OFFSET_UTC;
def->clock.data.utc_reset = true;
} /* !hvm */
2011-02-21 13:40:10 +00:00
if (xenXMConfigCopyStringOpt(conf, "device_model", &def->emulator) < 0)
goto cleanup;
list = virConfGetValue(conf, "disk");
if (list && list->type == VIR_CONF_LIST) {
list = list->list;
while (list) {
char *head;
char *offset;
char *tmp;
if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
goto skipdisk;
head = list->str;
if (VIR_ALLOC(disk) < 0)
goto no_memory;
/*
* Disks have 3 components, SOURCE,DEST-DEVICE,MODE
* eg, phy:/dev/HostVG/XenGuest1,xvda,w
* The SOURCE is usually prefixed with a driver type,
* and optionally driver sub-type
* The DEST-DEVICE is optionally post-fixed with disk type
*/
/* Extract the source file path*/
if (!(offset = strchr(head, ',')))
goto skipdisk;
if ((offset - head) >= (PATH_MAX-1))
goto skipdisk;
if (offset == head) {
disk->src = NULL; /* No source file given, eg CDROM with no media */
} else {
if (VIR_ALLOC_N(disk->src, (offset - head) + 1) < 0)
goto no_memory;
if (virStrncpy(disk->src, head, offset - head,
(offset - head) + 1) == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Source file %s too big for destination"),
head);
goto cleanup;
}
}
head = offset + 1;
/* Remove legacy ioemu: junk */
if (STRPREFIX(head, "ioemu:"))
head = head + 6;
/* Extract the dest device name */
if (!(offset = strchr(head, ',')))
goto skipdisk;
if (VIR_ALLOC_N(disk->dst, (offset - head) + 1) < 0)
goto no_memory;
if (virStrncpy(disk->dst, head, offset - head,
(offset - head) + 1) == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Dest file %s too big for destination"), head);
goto cleanup;
}
head = offset + 1;
/* Extract source driver type */
if (disk->src) {
/* The main type phy:, file:, tap: ... */
if ((tmp = strchr(disk->src, ':')) != NULL) {
if (VIR_ALLOC_N(disk->driverName, (tmp - disk->src) + 1) < 0)
goto no_memory;
if (virStrncpy(disk->driverName, disk->src,
(tmp - disk->src),
(tmp - disk->src) + 1) == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Driver name %s too big for destination"),
disk->src);
goto cleanup;
}
/* Strip the prefix we found off the source file name */
memmove(disk->src, disk->src+(tmp-disk->src)+1,
strlen(disk->src)-(tmp-disk->src));
}
/* And the sub-type for tap:XXX: type */
if (disk->driverName &&
STREQ(disk->driverName, "tap")) {
if (!(tmp = strchr(disk->src, ':')))
goto skipdisk;
if (VIR_ALLOC_N(disk->driverType, (tmp - disk->src) + 1) < 0)
goto no_memory;
if (virStrncpy(disk->driverType, disk->src,
(tmp - disk->src),
(tmp - disk->src) + 1) == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Driver type %s too big for destination"),
disk->src);
goto cleanup;
}
/* Strip the prefix we found off the source file name */
memmove(disk->src, disk->src+(tmp-disk->src)+1,
strlen(disk->src)-(tmp-disk->src));
}
}
/* No source, or driver name, so fix to phy: */
if (!disk->driverName &&
!(disk->driverName = strdup("phy")))
goto no_memory;
/* phy: type indicates a block device */
disk->type = STREQ(disk->driverName, "phy") ?
VIR_DOMAIN_DISK_TYPE_BLOCK : VIR_DOMAIN_DISK_TYPE_FILE;
/* Check for a :cdrom/:disk postfix */
disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
if ((tmp = strchr(disk->dst, ':')) != NULL) {
if (STREQ(tmp, ":cdrom"))
disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
tmp[0] = '\0';
}
if (STRPREFIX(disk->dst, "xvd") || !hvm) {
disk->bus = VIR_DOMAIN_DISK_BUS_XEN;
} else if (STRPREFIX(disk->dst, "sd")) {
disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
} else {
disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
}
if (STREQ(head, "r") ||
STREQ(head, "ro"))
disk->readonly = 1;
else if ((STREQ(head, "w!")) ||
(STREQ(head, "!")))
disk->shared = 1;
/* Maintain list in sorted order according to target device name */
if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
goto no_memory;
def->disks[def->ndisks++] = disk;
disk = NULL;
skipdisk:
list = list->next;
virDomainDiskDefFree(disk);
}
}
if (hvm && xendConfigVersion == XEND_CONFIG_VERSION_3_0_2) {
2011-02-21 13:40:10 +00:00
if (xenXMConfigGetString(conf, "cdrom", &str, NULL) < 0)
goto cleanup;
if (str) {
if (VIR_ALLOC(disk) < 0)
goto no_memory;
disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
if (!(disk->driverName = strdup("file")))
goto no_memory;
if (!(disk->src = strdup(str)))
goto no_memory;
if (!(disk->dst = strdup("hdc")))
goto no_memory;
disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
disk->readonly = 1;
if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
goto no_memory;
def->disks[def->ndisks++] = disk;
disk = NULL;
}
}
list = virConfGetValue(conf, "vif");
if (list && list->type == VIR_CONF_LIST) {
list = list->list;
while (list) {
char model[10];
char type[10];
char ip[16];
char mac[18];
char bridge[50];
char vifname[50];
char *key;
bridge[0] = '\0';
mac[0] = '\0';
ip[0] = '\0';
model[0] = '\0';
type[0] = '\0';
vifname[0] = '\0';
if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
goto skipnic;
key = list->str;
while (key) {
char *data;
char *nextkey = strchr(key, ',');
if (!(data = strchr(key, '=')))
goto skipnic;
data++;
if (STRPREFIX(key, "mac=")) {
int len = nextkey ? (nextkey - data) : sizeof(mac) - 1;
if (virStrncpy(mac, data, len, sizeof(mac)) == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("MAC address %s too big for destination"),
data);
goto skipnic;
}
} else if (STRPREFIX(key, "bridge=")) {
int len = nextkey ? (nextkey - data) : sizeof(bridge) - 1;
if (virStrncpy(bridge, data, len, sizeof(bridge)) == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Bridge %s too big for destination"),
data);
goto skipnic;
}
} else if (STRPREFIX(key, "script=")) {
int len = nextkey ? (nextkey - data) : strlen(data);
VIR_FREE(script);
if (!(script = strndup(data, len))) {
goto no_memory;
2011-02-21 13:40:10 +00:00
}
} else if (STRPREFIX(key, "model=")) {
int len = nextkey ? (nextkey - data) : sizeof(model) - 1;
if (virStrncpy(model, data, len, sizeof(model)) == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Model %s too big for destination"), data);
goto skipnic;
}
} else if (STRPREFIX(key, "type=")) {
int len = nextkey ? (nextkey - data) : sizeof(type) - 1;
if (virStrncpy(type, data, len, sizeof(type)) == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Type %s too big for destination"), data);
goto skipnic;
}
} else if (STRPREFIX(key, "vifname=")) {
int len = nextkey ? (nextkey - data) : sizeof(vifname) - 1;
if (virStrncpy(vifname, data, len, sizeof(vifname)) == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Vifname %s too big for destination"),
data);
goto skipnic;
}
} else if (STRPREFIX(key, "ip=")) {
int len = nextkey ? (nextkey - data) : sizeof(ip) - 1;
if (virStrncpy(ip, data, len, sizeof(ip)) == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("IP %s too big for destination"), data);
goto skipnic;
}
}
while (nextkey && (nextkey[0] == ',' ||
nextkey[0] == ' ' ||
nextkey[0] == '\t'))
nextkey++;
key = nextkey;
}
if (VIR_ALLOC(net) < 0)
goto no_memory;
if (mac[0]) {
if (virMacAddrParse(mac, net->mac) < 0) {
2011-02-21 13:40:10 +00:00
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("malformed mac address '%s'"), mac);
goto cleanup;
}
}
if (bridge[0] || STREQ_NULLABLE(script, "vif-bridge") ||
STREQ_NULLABLE(script, "vif-vnic")) {
2011-02-21 13:40:10 +00:00
net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
} else {
net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
}
if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
if (bridge[0] &&
!(net->data.bridge.brname = strdup(bridge)))
goto no_memory;
if (ip[0] &&
!(net->data.bridge.ipaddr = strdup(ip)))
goto no_memory;
} else {
if (ip[0] &&
!(net->data.ethernet.ipaddr = strdup(ip)))
goto no_memory;
}
config: report error when script given for inappropriate interface type This fixes https://bugzilla.redhat.com/show_bug.cgi?id=638633 Although scripts are not used by interfaces of type other than "ethernet" in qemu, due to the fact that the parser stores the script name in a union that is only valid when type is ethernet or bridge, there is no way for anyone except the parser itself to catch the problem of specifying an interface script for an inappropriate interface type (by the time the parsed data gets back to the code that called the parser, all evidence that a script was specified is forgotten). Since the parser itself should be agnostic to which type of interface allows scripts (an example of why: a script specified for an interface of type bridge is valid for xen domains, but not for qemu domains), the solution here is to move the script out of the union(s) in the DomainNetDef, always populate it when specified (regardless of interface type), and let the driver decide whether or not it is appropriate. Currently the qemu, xen, libxml, and uml drivers recognize the script parameter and do something with it (the uml driver only to report that it isn't supported). Those drivers have been updated to log a CONFIG_UNSUPPORTED error when a script is specified for an interface type that's inappropriate for that particular hypervisor. (NB: There was earlier discussion of solving this problem by adding a VALIDATE flag to all libvirt APIs that accept XML, which would cause the XML to be validated against the RNG files. One statement during that discussion was that the RNG shouldn't contain hypervisor-specific things, though, and a proper solution to this problem would require that (again, because a script for an interface of type "bridge" is accepted by xen, but not by qemu).
2012-01-06 17:59:47 +00:00
if (script && script[0] &&
!(net->script = strdup(script)))
goto no_memory;
2011-02-21 13:40:10 +00:00
if (model[0] &&
!(net->model = strdup(model)))
goto no_memory;
if (!model[0] && type[0] &&
STREQ(type, "netfront") &&
!(net->model = strdup("netfront")))
goto no_memory;
if (vifname[0] &&
!(net->ifname = strdup(vifname)))
goto no_memory;
if (VIR_REALLOC_N(def->nets, def->nnets+1) < 0)
goto no_memory;
def->nets[def->nnets++] = net;
net = NULL;
skipnic:
list = list->next;
virDomainNetDefFree(net);
}
}
list = virConfGetValue(conf, "pci");
if (list && list->type == VIR_CONF_LIST) {
list = list->list;
while (list) {
char domain[5];
char bus[3];
char slot[3];
char func[2];
char *key, *nextkey;
int domainID;
int busID;
int slotID;
int funcID;
domain[0] = bus[0] = slot[0] = func[0] = '\0';
if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
goto skippci;
/* pci=['0000:00:1b.0','0000:00:13.0'] */
if (!(key = list->str))
goto skippci;
if (!(nextkey = strchr(key, ':')))
goto skippci;
if (virStrncpy(domain, key, (nextkey - key), sizeof(domain)) == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Domain %s too big for destination"), key);
goto skippci;
}
key = nextkey + 1;
if (!(nextkey = strchr(key, ':')))
goto skippci;
if (virStrncpy(bus, key, (nextkey - key), sizeof(bus)) == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Bus %s too big for destination"), key);
goto skippci;
}
key = nextkey + 1;
if (!(nextkey = strchr(key, '.')))
goto skippci;
if (virStrncpy(slot, key, (nextkey - key), sizeof(slot)) == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Slot %s too big for destination"), key);
goto skippci;
}
key = nextkey + 1;
if (strlen(key) != 1)
goto skippci;
if (virStrncpy(func, key, 1, sizeof(func)) == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Function %s too big for destination"), key);
goto skippci;
}
if (virStrToLong_i(domain, NULL, 16, &domainID) < 0)
goto skippci;
if (virStrToLong_i(bus, NULL, 16, &busID) < 0)
goto skippci;
if (virStrToLong_i(slot, NULL, 16, &slotID) < 0)
goto skippci;
if (virStrToLong_i(func, NULL, 16, &funcID) < 0)
goto skippci;
if (!(hostdev = virDomainHostdevDefAlloc()))
goto cleanup;
2011-02-21 13:40:10 +00:00
hostdev->managed = 0;
hostdev->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
hostdev->source.subsys.u.pci.domain = domainID;
hostdev->source.subsys.u.pci.bus = busID;
hostdev->source.subsys.u.pci.slot = slotID;
hostdev->source.subsys.u.pci.function = funcID;
if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs+1) < 0) {
virDomainHostdevDefFree(hostdev);
2011-02-21 13:40:10 +00:00
goto no_memory;
}
2011-02-21 13:40:10 +00:00
def->hostdevs[def->nhostdevs++] = hostdev;
hostdev = NULL;
skippci:
list = list->next;
}
}
if (hvm) {
if (xenXMConfigGetString(conf, "usbdevice", &str, NULL) < 0)
goto cleanup;
if (str &&
(STREQ(str, "tablet") ||
STREQ(str, "mouse"))) {
virDomainInputDefPtr input;
if (VIR_ALLOC(input) < 0)
goto no_memory;
input->bus = VIR_DOMAIN_INPUT_BUS_USB;
input->type = STREQ(str, "tablet") ?
VIR_DOMAIN_INPUT_TYPE_TABLET :
VIR_DOMAIN_INPUT_TYPE_MOUSE;
if (VIR_ALLOC_N(def->inputs, 1) < 0) {
virDomainInputDefFree(input);
goto no_memory;
}
def->inputs[0] = input;
def->ninputs = 1;
}
}
/* HVM guests, or old PV guests use this config format */
if (hvm || xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) {
2011-02-21 13:40:10 +00:00
if (xenXMConfigGetBool(conf, "vnc", &val, 0) < 0)
goto cleanup;
if (val) {
if (VIR_ALLOC(graphics) < 0)
goto no_memory;
graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
if (xenXMConfigGetBool(conf, "vncunused", &val, 1) < 0)
goto cleanup;
graphics->data.vnc.autoport = val ? 1 : 0;
if (!graphics->data.vnc.autoport) {
unsigned long vncdisplay;
if (xenXMConfigGetULong(conf, "vncdisplay", &vncdisplay, 0) < 0)
goto cleanup;
graphics->data.vnc.port = (int)vncdisplay + 5900;
}
conf: add <listen> subelement to domain <graphics> element Once it's plugged in, the <listen> element will be an optional replacement for the "listen" attribute that graphics elements already have. If the <listen> element is type='address', it will have an attribute called 'address' which will contain an IP address or dns name that the guest's display server should listen on. If, however, type='network', the <listen> element should have an attribute called 'network' that will be set to the name of a network configuration to get the IP address from. * docs/schemas/domain.rng: updated to allow the <listen> element * docs/formatdomain.html.in: document the <listen> element and its attributes. * src/conf/domain_conf.[hc]: 1) The domain parser, formatter, and data structure are modified to support 0 or more <listen> subelements to each <graphics> element. The old style "legacy" listen attribute is also still accepted, and will be stored internally just as if it were a separate <listen> element. On output (i.e. format), the address attribute of the first <listen> element of type 'address' will be duplicated in the legacy "listen" attribute of the <graphic> element. 2) The "listenAddr" attribute has been removed from the unions in virDomainGRaphicsDef for graphics types vnc, rdp, and spice. This attribute is now in the <listen> subelement (aka virDomainGraphicsListenDef) 3) Helper functions were written to provide simple access (both Get and Set) to the listen elements and their attributes. * src/libvirt_private.syms: export the listen helper functions * src/qemu/qemu_command.c, src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c, src/vbox/vbox_tmpl.c, src/vmx/vmx.c, src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c Modify all these files to use the listen helper functions rather than directly referencing the (now missing) listenAddr attribute. There can be multiple <listen> elements to a single <graphics>, but the drivers all currently only support one, so all replacements of direct access with a helper function indicate index "0". * tests/* - only 3 of these are new files added explicitly to test the new <listen> element. All the others have been modified to reflect the fact that any legacy "listen" attributes passed in to the domain parse will be saved in a <listen> element (i.e. one of the virDomainGraphicsListenDefs), and during the domain format function, both the <listen> element as well as the legacy attributes will be output.
2011-07-07 04:20:28 +00:00
if (xenXMConfigCopyStringOpt(conf, "vnclisten", &listenAddr) < 0)
2011-02-21 13:40:10 +00:00
goto cleanup;
conf: add <listen> subelement to domain <graphics> element Once it's plugged in, the <listen> element will be an optional replacement for the "listen" attribute that graphics elements already have. If the <listen> element is type='address', it will have an attribute called 'address' which will contain an IP address or dns name that the guest's display server should listen on. If, however, type='network', the <listen> element should have an attribute called 'network' that will be set to the name of a network configuration to get the IP address from. * docs/schemas/domain.rng: updated to allow the <listen> element * docs/formatdomain.html.in: document the <listen> element and its attributes. * src/conf/domain_conf.[hc]: 1) The domain parser, formatter, and data structure are modified to support 0 or more <listen> subelements to each <graphics> element. The old style "legacy" listen attribute is also still accepted, and will be stored internally just as if it were a separate <listen> element. On output (i.e. format), the address attribute of the first <listen> element of type 'address' will be duplicated in the legacy "listen" attribute of the <graphic> element. 2) The "listenAddr" attribute has been removed from the unions in virDomainGRaphicsDef for graphics types vnc, rdp, and spice. This attribute is now in the <listen> subelement (aka virDomainGraphicsListenDef) 3) Helper functions were written to provide simple access (both Get and Set) to the listen elements and their attributes. * src/libvirt_private.syms: export the listen helper functions * src/qemu/qemu_command.c, src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c, src/vbox/vbox_tmpl.c, src/vmx/vmx.c, src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c Modify all these files to use the listen helper functions rather than directly referencing the (now missing) listenAddr attribute. There can be multiple <listen> elements to a single <graphics>, but the drivers all currently only support one, so all replacements of direct access with a helper function indicate index "0". * tests/* - only 3 of these are new files added explicitly to test the new <listen> element. All the others have been modified to reflect the fact that any legacy "listen" attributes passed in to the domain parse will be saved in a <listen> element (i.e. one of the virDomainGraphicsListenDefs), and during the domain format function, both the <listen> element as well as the legacy attributes will be output.
2011-07-07 04:20:28 +00:00
if (listenAddr &&
virDomainGraphicsListenSetAddress(graphics, 0, listenAddr,
-1, true) < 0) {
goto cleanup;
}
VIR_FREE(listenAddr);
2011-02-21 13:40:10 +00:00
if (xenXMConfigCopyStringOpt(conf, "vncpasswd", &graphics->data.vnc.auth.passwd) < 0)
goto cleanup;
if (xenXMConfigCopyStringOpt(conf, "keymap", &graphics->data.vnc.keymap) < 0)
goto cleanup;
if (VIR_ALLOC_N(def->graphics, 1) < 0)
goto no_memory;
def->graphics[0] = graphics;
def->ngraphics = 1;
graphics = NULL;
} else {
if (xenXMConfigGetBool(conf, "sdl", &val, 0) < 0)
goto cleanup;
if (val) {
if (VIR_ALLOC(graphics) < 0)
goto no_memory;
graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
if (xenXMConfigCopyStringOpt(conf, "display", &graphics->data.sdl.display) < 0)
goto cleanup;
if (xenXMConfigCopyStringOpt(conf, "xauthority", &graphics->data.sdl.xauth) < 0)
goto cleanup;
if (VIR_ALLOC_N(def->graphics, 1) < 0)
goto no_memory;
def->graphics[0] = graphics;
def->ngraphics = 1;
graphics = NULL;
}
}
}
if (!hvm && def->graphics == NULL) { /* New PV guests use this format */
list = virConfGetValue(conf, "vfb");
if (list && list->type == VIR_CONF_LIST &&
list->list && list->list->type == VIR_CONF_STRING &&
list->list->str) {
char vfb[MAX_VFB];
char *key = vfb;
if (virStrcpyStatic(vfb, list->list->str) == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("VFB %s too big for destination"),
list->list->str);
goto cleanup;
}
if (VIR_ALLOC(graphics) < 0)
goto no_memory;
if (strstr(key, "type=sdl"))
graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
else
graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
while (key) {
char *nextkey = strchr(key, ',');
char *end = nextkey;
if (nextkey) {
*end = '\0';
nextkey++;
}
if (!strchr(key, '='))
break;
if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
if (STRPREFIX(key, "vncunused=")) {
if (STREQ(key + 10, "1"))
graphics->data.vnc.autoport = 1;
} else if (STRPREFIX(key, "vnclisten=")) {
conf: add <listen> subelement to domain <graphics> element Once it's plugged in, the <listen> element will be an optional replacement for the "listen" attribute that graphics elements already have. If the <listen> element is type='address', it will have an attribute called 'address' which will contain an IP address or dns name that the guest's display server should listen on. If, however, type='network', the <listen> element should have an attribute called 'network' that will be set to the name of a network configuration to get the IP address from. * docs/schemas/domain.rng: updated to allow the <listen> element * docs/formatdomain.html.in: document the <listen> element and its attributes. * src/conf/domain_conf.[hc]: 1) The domain parser, formatter, and data structure are modified to support 0 or more <listen> subelements to each <graphics> element. The old style "legacy" listen attribute is also still accepted, and will be stored internally just as if it were a separate <listen> element. On output (i.e. format), the address attribute of the first <listen> element of type 'address' will be duplicated in the legacy "listen" attribute of the <graphic> element. 2) The "listenAddr" attribute has been removed from the unions in virDomainGRaphicsDef for graphics types vnc, rdp, and spice. This attribute is now in the <listen> subelement (aka virDomainGraphicsListenDef) 3) Helper functions were written to provide simple access (both Get and Set) to the listen elements and their attributes. * src/libvirt_private.syms: export the listen helper functions * src/qemu/qemu_command.c, src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c, src/vbox/vbox_tmpl.c, src/vmx/vmx.c, src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c Modify all these files to use the listen helper functions rather than directly referencing the (now missing) listenAddr attribute. There can be multiple <listen> elements to a single <graphics>, but the drivers all currently only support one, so all replacements of direct access with a helper function indicate index "0". * tests/* - only 3 of these are new files added explicitly to test the new <listen> element. All the others have been modified to reflect the fact that any legacy "listen" attributes passed in to the domain parse will be saved in a <listen> element (i.e. one of the virDomainGraphicsListenDefs), and during the domain format function, both the <listen> element as well as the legacy attributes will be output.
2011-07-07 04:20:28 +00:00
if (virDomainGraphicsListenSetAddress(graphics, 0, key+10,
-1, true) < 0)
goto cleanup;
2011-02-21 13:40:10 +00:00
} else if (STRPREFIX(key, "vncpasswd=")) {
if (!(graphics->data.vnc.auth.passwd = strdup(key + 10)))
goto no_memory;
} else if (STRPREFIX(key, "keymap=")) {
if (!(graphics->data.vnc.keymap = strdup(key + 7)))
goto no_memory;
} else if (STRPREFIX(key, "vncdisplay=")) {
graphics->data.vnc.port = strtol(key+11, NULL, 10) + 5900;
}
} else {
if (STRPREFIX(key, "display=")) {
if (!(graphics->data.sdl.display = strdup(key + 8)))
goto no_memory;
} else if (STRPREFIX(key, "xauthority=")) {
if (!(graphics->data.sdl.xauth = strdup(key + 11)))
goto no_memory;
}
}
while (nextkey && (nextkey[0] == ',' ||
nextkey[0] == ' ' ||
nextkey[0] == '\t'))
nextkey++;
key = nextkey;
}
if (VIR_ALLOC_N(def->graphics, 1) < 0)
goto no_memory;
def->graphics[0] = graphics;
def->ngraphics = 1;
graphics = NULL;
}
}
if (hvm) {
virDomainChrDefPtr chr = NULL;
if (xenXMConfigGetString(conf, "parallel", &str, NULL) < 0)
goto cleanup;
if (str && STRNEQ(str, "none") &&
2011-02-21 13:40:12 +00:00
!(chr = xenParseSxprChar(str, NULL)))
2011-02-21 13:40:10 +00:00
goto cleanup;
if (chr) {
if (VIR_ALLOC_N(def->parallels, 1) < 0) {
virDomainChrDefFree(chr);
goto no_memory;
}
chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
chr->target.port = 0;
2011-02-21 13:40:10 +00:00
def->parallels[0] = chr;
def->nparallels++;
chr = NULL;
}
/* Try to get the list of values to support multiple serial ports */
list = virConfGetValue(conf, "serial");
if (list && list->type == VIR_CONF_LIST) {
int portnum = -1;
2011-02-21 13:40:10 +00:00
list = list->list;
while (list) {
char *port = NULL;
if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
goto cleanup;
port = list->str;
portnum++;
if (STREQ(port, "none")) {
list = list->next;
continue;
}
if (!(chr = xenParseSxprChar(port, NULL)))
goto cleanup;
if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0)
goto no_memory;
chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
chr->target.port = portnum;
def->serials[def->nserials++] = chr;
chr = NULL;
list = list->next;
}
} else {
/* If domain is not using multiple serial ports we parse data old way */
if (xenXMConfigGetString(conf, "serial", &str, NULL) < 0)
goto cleanup;
if (str && STRNEQ(str, "none") &&
!(chr = xenParseSxprChar(str, NULL)))
goto cleanup;
if (chr) {
if (VIR_ALLOC_N(def->serials, 1) < 0) {
virDomainChrDefFree(chr);
goto no_memory;
}
chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
chr->target.port = 0;
def->serials[0] = chr;
def->nserials++;
2011-02-21 13:40:10 +00:00
}
}
} else {
def->nconsoles = 1;
if (VIR_ALLOC_N(def->consoles, 1) < 0)
goto no_memory;
if (!(def->consoles[0] = xenParseSxprChar("pty", NULL)))
2011-02-21 13:40:10 +00:00
goto cleanup;
def->consoles[0]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
def->consoles[0]->target.port = 0;
def->consoles[0]->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
2011-02-21 13:40:10 +00:00
}
if (hvm) {
if (xenXMConfigGetString(conf, "soundhw", &str, NULL) < 0)
goto cleanup;
if (str &&
2011-02-21 13:40:12 +00:00
xenParseSxprSound(def, str) < 0)
2011-02-21 13:40:10 +00:00
goto cleanup;
}
VIR_FREE(script);
2011-02-21 13:40:10 +00:00
return def;
no_memory:
virReportOOMError();
/* fallthrough */
cleanup:
virDomainGraphicsDefFree(graphics);
virDomainNetDefFree(net);
virDomainDiskDefFree(disk);
virDomainDefFree(def);
VIR_FREE(script);
conf: add <listen> subelement to domain <graphics> element Once it's plugged in, the <listen> element will be an optional replacement for the "listen" attribute that graphics elements already have. If the <listen> element is type='address', it will have an attribute called 'address' which will contain an IP address or dns name that the guest's display server should listen on. If, however, type='network', the <listen> element should have an attribute called 'network' that will be set to the name of a network configuration to get the IP address from. * docs/schemas/domain.rng: updated to allow the <listen> element * docs/formatdomain.html.in: document the <listen> element and its attributes. * src/conf/domain_conf.[hc]: 1) The domain parser, formatter, and data structure are modified to support 0 or more <listen> subelements to each <graphics> element. The old style "legacy" listen attribute is also still accepted, and will be stored internally just as if it were a separate <listen> element. On output (i.e. format), the address attribute of the first <listen> element of type 'address' will be duplicated in the legacy "listen" attribute of the <graphic> element. 2) The "listenAddr" attribute has been removed from the unions in virDomainGRaphicsDef for graphics types vnc, rdp, and spice. This attribute is now in the <listen> subelement (aka virDomainGraphicsListenDef) 3) Helper functions were written to provide simple access (both Get and Set) to the listen elements and their attributes. * src/libvirt_private.syms: export the listen helper functions * src/qemu/qemu_command.c, src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c, src/vbox/vbox_tmpl.c, src/vmx/vmx.c, src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c Modify all these files to use the listen helper functions rather than directly referencing the (now missing) listenAddr attribute. There can be multiple <listen> elements to a single <graphics>, but the drivers all currently only support one, so all replacements of direct access with a helper function indicate index "0". * tests/* - only 3 of these are new files added explicitly to test the new <listen> element. All the others have been modified to reflect the fact that any legacy "listen" attributes passed in to the domain parse will be saved in a <listen> element (i.e. one of the virDomainGraphicsListenDefs), and during the domain format function, both the <listen> element as well as the legacy attributes will be output.
2011-07-07 04:20:28 +00:00
VIR_FREE(listenAddr);
2011-02-21 13:40:10 +00:00
return NULL;
}
2011-02-21 13:40:11 +00:00
static
xml: use better types for memory values Using 'unsigned long' for memory values is risky on 32-bit platforms, as a PAE guest can have more than 4GiB memory. Our API is (unfortunately) locked at 'unsigned long' and a scale of 1024, but the rest of our system should consistently use 64-bit values, especially since the previous patch centralized overflow checking. * src/conf/domain_conf.h (_virDomainDef): Always use 64-bit values for memory. Change hugepage_backed to a bool. * src/conf/domain_conf.c (virDomainDefParseXML) (virDomainDefCheckABIStability, virDomainDefFormatInternal): Fix clients. * src/vmx/vmx.c (virVMXFormatConfig): Likewise. * src/xenxs/xen_sxpr.c (xenParseSxpr, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetULongLong): New function. (xenXMConfigGetULong, xenXMConfigSetInt): Avoid truncation. (xenParseXM, xenFormatXM): Fix clients. * src/phyp/phyp_driver.c (phypBuildLpar): Likewise. * src/openvz/openvz_driver.c (openvzDomainSetMemoryInternal): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainDefineXML): Likewise. * src/qemu/qemu_command.c (qemuBuildCommandLine): Likewise. * src/qemu/qemu_process.c (qemuProcessStart): Likewise. * src/qemu/qemu_monitor.h (qemuMonitorGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.h (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.c (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetInfo) (qemuDomainGetXMLDesc): Likewise. * src/uml/uml_conf.c (umlBuildCommandLine): Likewise.
2012-03-02 20:27:39 +00:00
int xenXMConfigSetInt(virConfPtr conf, const char *setting, long long l) {
2011-02-21 13:40:11 +00:00
virConfValuePtr value = NULL;
xml: use better types for memory values Using 'unsigned long' for memory values is risky on 32-bit platforms, as a PAE guest can have more than 4GiB memory. Our API is (unfortunately) locked at 'unsigned long' and a scale of 1024, but the rest of our system should consistently use 64-bit values, especially since the previous patch centralized overflow checking. * src/conf/domain_conf.h (_virDomainDef): Always use 64-bit values for memory. Change hugepage_backed to a bool. * src/conf/domain_conf.c (virDomainDefParseXML) (virDomainDefCheckABIStability, virDomainDefFormatInternal): Fix clients. * src/vmx/vmx.c (virVMXFormatConfig): Likewise. * src/xenxs/xen_sxpr.c (xenParseSxpr, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetULongLong): New function. (xenXMConfigGetULong, xenXMConfigSetInt): Avoid truncation. (xenParseXM, xenFormatXM): Fix clients. * src/phyp/phyp_driver.c (phypBuildLpar): Likewise. * src/openvz/openvz_driver.c (openvzDomainSetMemoryInternal): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainDefineXML): Likewise. * src/qemu/qemu_command.c (qemuBuildCommandLine): Likewise. * src/qemu/qemu_process.c (qemuProcessStart): Likewise. * src/qemu/qemu_monitor.h (qemuMonitorGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.h (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.c (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetInfo) (qemuDomainGetXMLDesc): Likewise. * src/uml/uml_conf.c (umlBuildCommandLine): Likewise.
2012-03-02 20:27:39 +00:00
if ((long) l != l) {
XENXS_ERROR(VIR_ERR_OVERFLOW, _("failed to store %lld to %s"),
l, setting);
return -1;
}
2011-02-21 13:40:11 +00:00
if (VIR_ALLOC(value) < 0) {
virReportOOMError();
return -1;
}
value->type = VIR_CONF_LONG;
value->next = NULL;
value->l = l;
return virConfSetValue(conf, setting, value);
}
static
int xenXMConfigSetString(virConfPtr conf, const char *setting, const char *str) {
virConfValuePtr value = NULL;
if (VIR_ALLOC(value) < 0) {
virReportOOMError();
return -1;
}
value->type = VIR_CONF_STRING;
value->next = NULL;
if (!(value->str = strdup(str))) {
VIR_FREE(value);
virReportOOMError();
return -1;
}
return virConfSetValue(conf, setting, value);
}
2011-02-21 13:40:12 +00:00
static int xenFormatXMDisk(virConfValuePtr list,
2011-02-21 13:40:11 +00:00
virDomainDiskDefPtr disk,
int hvm,
int xendConfigVersion)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
virConfValuePtr val, tmp;
if(disk->src) {
if (disk->driverName) {
virBufferAsprintf(&buf, "%s:", disk->driverName);
2011-02-21 13:40:11 +00:00
if (STREQ(disk->driverName, "tap"))
virBufferAsprintf(&buf, "%s:", disk->driverType ? disk->driverType : "aio");
2011-02-21 13:40:11 +00:00
} else {
switch (disk->type) {
case VIR_DOMAIN_DISK_TYPE_FILE:
virBufferAddLit(&buf, "file:");
break;
case VIR_DOMAIN_DISK_TYPE_BLOCK:
virBufferAddLit(&buf, "phy:");
break;
default:
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("unsupported disk type %s"),
virDomainDiskTypeToString(disk->type));
goto cleanup;
}
}
virBufferAdd(&buf, disk->src, -1);
2011-02-21 13:40:11 +00:00
}
virBufferAddLit(&buf, ",");
if (hvm && xendConfigVersion == XEND_CONFIG_VERSION_3_0_2)
2011-02-21 13:40:11 +00:00
virBufferAddLit(&buf, "ioemu:");
virBufferAdd(&buf, disk->dst, -1);
2011-02-21 13:40:11 +00:00
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
virBufferAddLit(&buf, ":cdrom");
if (disk->readonly)
virBufferAddLit(&buf, ",r");
else if (disk->shared)
virBufferAddLit(&buf, ",!");
else
virBufferAddLit(&buf, ",w");
if (disk->transient) {
XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
_("transient disks not supported yet"));
return -1;
}
2011-02-21 13:40:11 +00:00
if (virBufferError(&buf)) {
virReportOOMError();
goto cleanup;
}
if (VIR_ALLOC(val) < 0) {
virReportOOMError();
goto cleanup;
}
val->type = VIR_CONF_STRING;
val->str = virBufferContentAndReset(&buf);
tmp = list->list;
while (tmp && tmp->next)
tmp = tmp->next;
if (tmp)
tmp->next = val;
else
list->list = val;
return 0;
cleanup:
virBufferFreeAndReset(&buf);
return -1;
}
static int xenFormatXMSerial(virConfValuePtr list,
virDomainChrDefPtr serial)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
virConfValuePtr val, tmp;
int ret;
if (serial) {
ret = xenFormatSxprChr(serial, &buf);
if (ret < 0) {
virReportOOMError();
goto cleanup;
}
} else {
virBufferAddLit(&buf, "none");
}
if (virBufferError(&buf)) {
virReportOOMError();
goto cleanup;
}
if (VIR_ALLOC(val) < 0) {
virReportOOMError();
goto cleanup;
}
val->type = VIR_CONF_STRING;
val->str = virBufferContentAndReset(&buf);
tmp = list->list;
while (tmp && tmp->next)
tmp = tmp->next;
if (tmp)
tmp->next = val;
else
list->list = val;
return 0;
cleanup:
virBufferFreeAndReset(&buf);
return -1;
}
2011-02-21 13:40:12 +00:00
static int xenFormatXMNet(virConnectPtr conn,
2011-02-21 13:40:11 +00:00
virConfValuePtr list,
virDomainNetDefPtr net,
int hvm, int xendConfigVersion)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
virConfValuePtr val, tmp;
virBufferAsprintf(&buf, "mac=%02x:%02x:%02x:%02x:%02x:%02x",
2011-02-21 13:40:11 +00:00
net->mac[0], net->mac[1],
net->mac[2], net->mac[3],
net->mac[4], net->mac[5]);
switch (net->type) {
case VIR_DOMAIN_NET_TYPE_BRIDGE:
virBufferAsprintf(&buf, ",bridge=%s", net->data.bridge.brname);
2011-02-21 13:40:11 +00:00
if (net->data.bridge.ipaddr)
virBufferAsprintf(&buf, ",ip=%s", net->data.bridge.ipaddr);
virBufferAsprintf(&buf, ",script=%s", DEFAULT_VIF_SCRIPT);
2011-02-21 13:40:11 +00:00
break;
case VIR_DOMAIN_NET_TYPE_ETHERNET:
config: report error when script given for inappropriate interface type This fixes https://bugzilla.redhat.com/show_bug.cgi?id=638633 Although scripts are not used by interfaces of type other than "ethernet" in qemu, due to the fact that the parser stores the script name in a union that is only valid when type is ethernet or bridge, there is no way for anyone except the parser itself to catch the problem of specifying an interface script for an inappropriate interface type (by the time the parsed data gets back to the code that called the parser, all evidence that a script was specified is forgotten). Since the parser itself should be agnostic to which type of interface allows scripts (an example of why: a script specified for an interface of type bridge is valid for xen domains, but not for qemu domains), the solution here is to move the script out of the union(s) in the DomainNetDef, always populate it when specified (regardless of interface type), and let the driver decide whether or not it is appropriate. Currently the qemu, xen, libxml, and uml drivers recognize the script parameter and do something with it (the uml driver only to report that it isn't supported). Those drivers have been updated to log a CONFIG_UNSUPPORTED error when a script is specified for an interface type that's inappropriate for that particular hypervisor. (NB: There was earlier discussion of solving this problem by adding a VALIDATE flag to all libvirt APIs that accept XML, which would cause the XML to be validated against the RNG files. One statement during that discussion was that the RNG shouldn't contain hypervisor-specific things, though, and a proper solution to this problem would require that (again, because a script for an interface of type "bridge" is accepted by xen, but not by qemu).
2012-01-06 17:59:47 +00:00
if (net->script)
virBufferAsprintf(&buf, ",script=%s", net->script);
2011-02-21 13:40:11 +00:00
if (net->data.ethernet.ipaddr)
virBufferAsprintf(&buf, ",ip=%s", net->data.ethernet.ipaddr);
2011-02-21 13:40:11 +00:00
break;
case VIR_DOMAIN_NET_TYPE_NETWORK:
{
virNetworkPtr network = virNetworkLookupByName(conn, net->data.network.name);
char *bridge;
if (!network) {
XENXS_ERROR(VIR_ERR_NO_NETWORK, "%s",
net->data.network.name);
return -1;
}
bridge = virNetworkGetBridgeName(network);
virNetworkFree(network);
if (!bridge) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("network %s is not active"),
net->data.network.name);
return -1;
}
virBufferAsprintf(&buf, ",bridge=%s", bridge);
virBufferAsprintf(&buf, ",script=%s", DEFAULT_VIF_SCRIPT);
2011-02-21 13:40:11 +00:00
}
break;
default:
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("unsupported network type %d"),
net->type);
goto cleanup;
}
if (!hvm) {
if (net->model != NULL)
virBufferAsprintf(&buf, ",model=%s", net->model);
2011-02-21 13:40:11 +00:00
}
else if (net->model == NULL) {
/*
* apparently type ioemu breaks paravirt drivers on HVM so skip this
* from XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU
*/
if (xendConfigVersion <= XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU)
virBufferAddLit(&buf, ",type=ioemu");
}
else if (STREQ(net->model, "netfront")) {
virBufferAddLit(&buf, ",type=netfront");
}
else {
virBufferAsprintf(&buf, ",model=%s", net->model);
2011-02-21 13:40:11 +00:00
virBufferAddLit(&buf, ",type=ioemu");
}
if (net->ifname)
virBufferAsprintf(&buf, ",vifname=%s",
2011-02-21 13:40:11 +00:00
net->ifname);
if (virBufferError(&buf)) {
virReportOOMError();
goto cleanup;
}
if (VIR_ALLOC(val) < 0) {
virReportOOMError();
goto cleanup;
}
val->type = VIR_CONF_STRING;
val->str = virBufferContentAndReset(&buf);
tmp = list->list;
while (tmp && tmp->next)
tmp = tmp->next;
if (tmp)
tmp->next = val;
else
list->list = val;
return 0;
cleanup:
virBufferFreeAndReset(&buf);
return -1;
}
static int
2011-02-21 13:40:12 +00:00
xenFormatXMPCI(virConfPtr conf,
2011-02-21 13:40:11 +00:00
virDomainDefPtr def)
{
virConfValuePtr pciVal = NULL;
int hasPCI = 0;
int i;
for (i = 0 ; i < def->nhostdevs ; i++)
if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
hasPCI = 1;
if (!hasPCI)
return 0;
if (VIR_ALLOC(pciVal) < 0) {
virReportOOMError();
return -1;
}
pciVal->type = VIR_CONF_LIST;
pciVal->list = NULL;
for (i = 0 ; i < def->nhostdevs ; i++) {
if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
virConfValuePtr val, tmp;
char *buf;
if (virAsprintf(&buf, "%04x:%02x:%02x.%x",
def->hostdevs[i]->source.subsys.u.pci.domain,
def->hostdevs[i]->source.subsys.u.pci.bus,
def->hostdevs[i]->source.subsys.u.pci.slot,
def->hostdevs[i]->source.subsys.u.pci.function) < 0) {
virReportOOMError();
goto error;
}
if (VIR_ALLOC(val) < 0) {
VIR_FREE(buf);
virReportOOMError();
goto error;
}
val->type = VIR_CONF_STRING;
val->str = buf;
tmp = pciVal->list;
while (tmp && tmp->next)
tmp = tmp->next;
if (tmp)
tmp->next = val;
else
pciVal->list = val;
}
}
if (pciVal->list != NULL) {
int ret = virConfSetValue(conf, "pci", pciVal);
pciVal = NULL;
if (ret < 0)
return -1;
}
VIR_FREE(pciVal);
return 0;
error:
virConfFreeValue(pciVal);
return -1;
}
/* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is
either 32, or 64 on a platform where long is big enough. */
verify(MAX_VIRT_CPUS <= sizeof(1UL) * CHAR_BIT);
2011-02-21 13:40:12 +00:00
virConfPtr xenFormatXM(virConnectPtr conn,
2011-02-21 13:40:11 +00:00
virDomainDefPtr def,
int xendConfigVersion) {
virConfPtr conf = NULL;
Xen: Fix <clock> handling XenD-3.1 introduced managed domains. HV-domains have rtc_timeoffset (hgd24f37b31030 from 2007-04-03), which tracks the offset between the hypervisors clock and the domains RTC, and is persisted by XenD. In combination with localtime=1 this had a bug until XenD-3.4 (hg5d701be7c37b from 2009-04-01) (I'm not 100% sure how that bug manifests, but at least for me in TZ=Europe/Berlin I see the previous offset relative to utc being applied to localtime again, which manifests in an extra hour being added) XenD implements the following variants for clock/@offset: - PV domains don't have a RTC → 'localtime' | 'utc' - <3.1: no managed domains → 'localtime' | 'utc' - ≥3.1: the offset is tracked for HV → 'variable' due to the localtime=1 bug → 'localtime' | 'utc' - ≥3.4: the offset is tracked for HV → 'variable' Current libvirtd still thinks XenD only implements <clock offset='utc'/> and <clock offset='localtime'/>, which is wrong, since the semantic of 'utc' and 'localtime' specifies, that the offset will be reset on domain-restart, while with 'variable' the offset is kept. (keeping the offset over "virsh edit" is important, since otherwise the clock might jump, which confuses certain guest OSs) xendConfigVersion was last incremented to 4 by the xen-folks for xen-3.1.0. I know of no way to reliably detect the version of XenD (user space tools), which may be different from the version of the hypervisor (kernel) version! Because of this only the change from 'utc'/'localtime' to 'variable' in XenD-3.1 is handled, not the buggy behaviour of XenD-3.1 until XenD-3.4. For backward compatibility with previous versions of libvirt Xen-HV still accepts 'utc' and 'localtime', but they are returned as 'variable' on the next read-back from Xend to libvirt, since this is what XenD implements: The RTC is NOT reset back to the specified time on next restart, but the previous offset is kept. This behaviour can be turned off by adding the additional attribute adjustment='reset', in which case libvirt will report an error instead of doing the conversion. The attribute can also be used as a shortcut to offset='variable' with basis='...'. With these changes, it is also necessary to adjust the xen tests: "localtime = 0" is always inserted, because otherwise on updates the value is not changed within XenD. adjustment='reset' is inserted for all cases, since they're all < XEND_CONFIG_VERSION_3_1_0, only 3.1 introduced persistent rtc_timeoffset. Some statements change their order because code was moved around. Signed-off-by: Philipp Hahn <hahn@univention.de>
2012-02-08 16:32:34 +00:00
int hvm = 0, i, vmlocaltime = 0;
2011-02-21 13:40:11 +00:00
char *cpus = NULL;
const char *lifecycle;
char uuid[VIR_UUID_STRING_BUFLEN];
virConfValuePtr diskVal = NULL;
virConfValuePtr netVal = NULL;
if (!(conf = virConfNew()))
goto cleanup;
if (xenXMConfigSetString(conf, "name", def->name) < 0)
goto no_memory;
virUUIDFormat(def->uuid, uuid);
if (xenXMConfigSetString(conf, "uuid", uuid) < 0)
goto no_memory;
xml: use better types for memory values Using 'unsigned long' for memory values is risky on 32-bit platforms, as a PAE guest can have more than 4GiB memory. Our API is (unfortunately) locked at 'unsigned long' and a scale of 1024, but the rest of our system should consistently use 64-bit values, especially since the previous patch centralized overflow checking. * src/conf/domain_conf.h (_virDomainDef): Always use 64-bit values for memory. Change hugepage_backed to a bool. * src/conf/domain_conf.c (virDomainDefParseXML) (virDomainDefCheckABIStability, virDomainDefFormatInternal): Fix clients. * src/vmx/vmx.c (virVMXFormatConfig): Likewise. * src/xenxs/xen_sxpr.c (xenParseSxpr, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetULongLong): New function. (xenXMConfigGetULong, xenXMConfigSetInt): Avoid truncation. (xenParseXM, xenFormatXM): Fix clients. * src/phyp/phyp_driver.c (phypBuildLpar): Likewise. * src/openvz/openvz_driver.c (openvzDomainSetMemoryInternal): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainDefineXML): Likewise. * src/qemu/qemu_command.c (qemuBuildCommandLine): Likewise. * src/qemu/qemu_process.c (qemuProcessStart): Likewise. * src/qemu/qemu_monitor.h (qemuMonitorGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.h (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.c (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetInfo) (qemuDomainGetXMLDesc): Likewise. * src/uml/uml_conf.c (umlBuildCommandLine): Likewise.
2012-03-02 20:27:39 +00:00
if (xenXMConfigSetInt(conf, "maxmem",
VIR_DIV_UP(def->mem.max_balloon, 1024)) < 0)
2011-02-21 13:40:11 +00:00
goto no_memory;
xml: use better types for memory values Using 'unsigned long' for memory values is risky on 32-bit platforms, as a PAE guest can have more than 4GiB memory. Our API is (unfortunately) locked at 'unsigned long' and a scale of 1024, but the rest of our system should consistently use 64-bit values, especially since the previous patch centralized overflow checking. * src/conf/domain_conf.h (_virDomainDef): Always use 64-bit values for memory. Change hugepage_backed to a bool. * src/conf/domain_conf.c (virDomainDefParseXML) (virDomainDefCheckABIStability, virDomainDefFormatInternal): Fix clients. * src/vmx/vmx.c (virVMXFormatConfig): Likewise. * src/xenxs/xen_sxpr.c (xenParseSxpr, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetULongLong): New function. (xenXMConfigGetULong, xenXMConfigSetInt): Avoid truncation. (xenParseXM, xenFormatXM): Fix clients. * src/phyp/phyp_driver.c (phypBuildLpar): Likewise. * src/openvz/openvz_driver.c (openvzDomainSetMemoryInternal): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainDefineXML): Likewise. * src/qemu/qemu_command.c (qemuBuildCommandLine): Likewise. * src/qemu/qemu_process.c (qemuProcessStart): Likewise. * src/qemu/qemu_monitor.h (qemuMonitorGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.h (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.c (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetInfo) (qemuDomainGetXMLDesc): Likewise. * src/uml/uml_conf.c (umlBuildCommandLine): Likewise.
2012-03-02 20:27:39 +00:00
if (xenXMConfigSetInt(conf, "memory",
VIR_DIV_UP(def->mem.cur_balloon, 1024)) < 0)
2011-02-21 13:40:11 +00:00
goto no_memory;
if (xenXMConfigSetInt(conf, "vcpus", def->maxvcpus) < 0)
goto no_memory;
/* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is
either 32, or 64 on a platform where long is big enough. */
if (def->vcpus < def->maxvcpus &&
xenXMConfigSetInt(conf, "vcpu_avail", (1UL << def->vcpus) - 1) < 0)
goto no_memory;
if ((def->cpumask != NULL) &&
((cpus = virDomainCpuSetFormat(def->cpumask,
def->cpumasklen)) == NULL))
goto cleanup;
if (cpus &&
xenXMConfigSetString(conf, "cpus", cpus) < 0)
goto no_memory;
VIR_FREE(cpus);
hvm = STREQ(def->os.type, "hvm") ? 1 : 0;
if (hvm) {
char boot[VIR_DOMAIN_BOOT_LAST+1];
if (xenXMConfigSetString(conf, "builder", "hvm") < 0)
goto no_memory;
if (def->os.loader &&
xenXMConfigSetString(conf, "kernel", def->os.loader) < 0)
goto no_memory;
for (i = 0 ; i < def->os.nBootDevs ; i++) {
switch (def->os.bootDevs[i]) {
case VIR_DOMAIN_BOOT_FLOPPY:
boot[i] = 'a';
break;
case VIR_DOMAIN_BOOT_CDROM:
boot[i] = 'd';
break;
case VIR_DOMAIN_BOOT_NET:
boot[i] = 'n';
break;
case VIR_DOMAIN_BOOT_DISK:
default:
boot[i] = 'c';
break;
}
}
if (!def->os.nBootDevs) {
boot[0] = 'c';
boot[1] = '\0';
} else {
boot[def->os.nBootDevs] = '\0';
}
if (xenXMConfigSetString(conf, "boot", boot) < 0)
goto no_memory;
if (xenXMConfigSetInt(conf, "pae",
(def->features &
(1 << VIR_DOMAIN_FEATURE_PAE)) ? 1 : 0) < 0)
goto no_memory;
if (xenXMConfigSetInt(conf, "acpi",
(def->features &
(1 << VIR_DOMAIN_FEATURE_ACPI)) ? 1 : 0) < 0)
goto no_memory;
if (xenXMConfigSetInt(conf, "apic",
(def->features &
(1 << VIR_DOMAIN_FEATURE_APIC)) ? 1 : 0) < 0)
goto no_memory;
if (xendConfigVersion >= XEND_CONFIG_VERSION_3_0_4) {
2011-02-21 13:40:11 +00:00
if (xenXMConfigSetInt(conf, "hap",
(def->features &
(1 << VIR_DOMAIN_FEATURE_HAP)) ? 1 : 0) < 0)
goto no_memory;
if (xenXMConfigSetInt(conf, "viridian",
(def->features &
(1 << VIR_DOMAIN_FEATURE_VIRIDIAN)) ? 1 : 0) < 0)
goto no_memory;
}
for (i = 0; i < def->clock.ntimers; i++) {
if (def->clock.timers[i]->name == VIR_DOMAIN_TIMER_NAME_HPET &&
def->clock.timers[i]->present != -1 &&
xenXMConfigSetInt(conf, "hpet", def->clock.timers[i]->present) < 0)
break;
}
if (xendConfigVersion == XEND_CONFIG_VERSION_3_0_2) {
2011-02-21 13:40:11 +00:00
for (i = 0 ; i < def->ndisks ; i++) {
if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
def->disks[i]->dst &&
STREQ(def->disks[i]->dst, "hdc") &&
def->disks[i]->src) {
if (xenXMConfigSetString(conf, "cdrom",
def->disks[i]->src) < 0)
goto no_memory;
break;
}
}
}
/* XXX floppy disks */
} else {
if (def->os.bootloader &&
xenXMConfigSetString(conf, "bootloader", def->os.bootloader) < 0)
goto no_memory;
if (def->os.bootloaderArgs &&
xenXMConfigSetString(conf, "bootargs", def->os.bootloaderArgs) < 0)
goto no_memory;
if (def->os.kernel &&
xenXMConfigSetString(conf, "kernel", def->os.kernel) < 0)
goto no_memory;
if (def->os.initrd &&
xenXMConfigSetString(conf, "ramdisk", def->os.initrd) < 0)
goto no_memory;
if (def->os.cmdline &&
xenXMConfigSetString(conf, "extra", def->os.cmdline) < 0)
goto no_memory;
Xen: Fix <clock> handling XenD-3.1 introduced managed domains. HV-domains have rtc_timeoffset (hgd24f37b31030 from 2007-04-03), which tracks the offset between the hypervisors clock and the domains RTC, and is persisted by XenD. In combination with localtime=1 this had a bug until XenD-3.4 (hg5d701be7c37b from 2009-04-01) (I'm not 100% sure how that bug manifests, but at least for me in TZ=Europe/Berlin I see the previous offset relative to utc being applied to localtime again, which manifests in an extra hour being added) XenD implements the following variants for clock/@offset: - PV domains don't have a RTC → 'localtime' | 'utc' - <3.1: no managed domains → 'localtime' | 'utc' - ≥3.1: the offset is tracked for HV → 'variable' due to the localtime=1 bug → 'localtime' | 'utc' - ≥3.4: the offset is tracked for HV → 'variable' Current libvirtd still thinks XenD only implements <clock offset='utc'/> and <clock offset='localtime'/>, which is wrong, since the semantic of 'utc' and 'localtime' specifies, that the offset will be reset on domain-restart, while with 'variable' the offset is kept. (keeping the offset over "virsh edit" is important, since otherwise the clock might jump, which confuses certain guest OSs) xendConfigVersion was last incremented to 4 by the xen-folks for xen-3.1.0. I know of no way to reliably detect the version of XenD (user space tools), which may be different from the version of the hypervisor (kernel) version! Because of this only the change from 'utc'/'localtime' to 'variable' in XenD-3.1 is handled, not the buggy behaviour of XenD-3.1 until XenD-3.4. For backward compatibility with previous versions of libvirt Xen-HV still accepts 'utc' and 'localtime', but they are returned as 'variable' on the next read-back from Xend to libvirt, since this is what XenD implements: The RTC is NOT reset back to the specified time on next restart, but the previous offset is kept. This behaviour can be turned off by adding the additional attribute adjustment='reset', in which case libvirt will report an error instead of doing the conversion. The attribute can also be used as a shortcut to offset='variable' with basis='...'. With these changes, it is also necessary to adjust the xen tests: "localtime = 0" is always inserted, because otherwise on updates the value is not changed within XenD. adjustment='reset' is inserted for all cases, since they're all < XEND_CONFIG_VERSION_3_1_0, only 3.1 introduced persistent rtc_timeoffset. Some statements change their order because code was moved around. Signed-off-by: Philipp Hahn <hahn@univention.de>
2012-02-08 16:32:34 +00:00
} /* !hvm */
if (xendConfigVersion < XEND_CONFIG_VERSION_3_1_0) {
/* <3.1: UTC and LOCALTIME */
switch (def->clock.offset) {
case VIR_DOMAIN_CLOCK_OFFSET_UTC:
vmlocaltime = 0;
break;
case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
vmlocaltime = 1;
break;
default:
XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported clock offset='%s'"),
virDomainClockOffsetTypeToString(def->clock.offset));
goto cleanup;
}
} else {
if (hvm) {
/* >=3.1 HV: VARIABLE */
int rtc_timeoffset;
switch (def->clock.offset) {
case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
vmlocaltime = (int)def->clock.data.variable.basis;
rtc_timeoffset = def->clock.data.variable.adjustment;
break;
case VIR_DOMAIN_CLOCK_OFFSET_UTC:
if (def->clock.data.utc_reset) {
XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported clock adjustment='reset'"));
goto cleanup;
}
vmlocaltime = 0;
rtc_timeoffset = 0;
break;
case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
if (def->clock.data.utc_reset) {
XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported clock adjustment='reset'"));
goto cleanup;
}
vmlocaltime = 1;
rtc_timeoffset = 0;
break;
default:
XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported clock offset='%s'"),
virDomainClockOffsetTypeToString(def->clock.offset));
goto cleanup;
}
if (xenXMConfigSetInt(conf, "rtc_timeoffset", rtc_timeoffset) < 0)
goto no_memory;
} else {
/* >=3.1 PV: UTC and LOCALTIME */
switch (def->clock.offset) {
case VIR_DOMAIN_CLOCK_OFFSET_UTC:
vmlocaltime = 0;
break;
case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
vmlocaltime = 1;
break;
default:
XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported clock offset='%s'"),
virDomainClockOffsetTypeToString(def->clock.offset));
goto cleanup;
}
} /* !hvm */
2011-02-21 13:40:11 +00:00
}
Xen: Fix <clock> handling XenD-3.1 introduced managed domains. HV-domains have rtc_timeoffset (hgd24f37b31030 from 2007-04-03), which tracks the offset between the hypervisors clock and the domains RTC, and is persisted by XenD. In combination with localtime=1 this had a bug until XenD-3.4 (hg5d701be7c37b from 2009-04-01) (I'm not 100% sure how that bug manifests, but at least for me in TZ=Europe/Berlin I see the previous offset relative to utc being applied to localtime again, which manifests in an extra hour being added) XenD implements the following variants for clock/@offset: - PV domains don't have a RTC → 'localtime' | 'utc' - <3.1: no managed domains → 'localtime' | 'utc' - ≥3.1: the offset is tracked for HV → 'variable' due to the localtime=1 bug → 'localtime' | 'utc' - ≥3.4: the offset is tracked for HV → 'variable' Current libvirtd still thinks XenD only implements <clock offset='utc'/> and <clock offset='localtime'/>, which is wrong, since the semantic of 'utc' and 'localtime' specifies, that the offset will be reset on domain-restart, while with 'variable' the offset is kept. (keeping the offset over "virsh edit" is important, since otherwise the clock might jump, which confuses certain guest OSs) xendConfigVersion was last incremented to 4 by the xen-folks for xen-3.1.0. I know of no way to reliably detect the version of XenD (user space tools), which may be different from the version of the hypervisor (kernel) version! Because of this only the change from 'utc'/'localtime' to 'variable' in XenD-3.1 is handled, not the buggy behaviour of XenD-3.1 until XenD-3.4. For backward compatibility with previous versions of libvirt Xen-HV still accepts 'utc' and 'localtime', but they are returned as 'variable' on the next read-back from Xend to libvirt, since this is what XenD implements: The RTC is NOT reset back to the specified time on next restart, but the previous offset is kept. This behaviour can be turned off by adding the additional attribute adjustment='reset', in which case libvirt will report an error instead of doing the conversion. The attribute can also be used as a shortcut to offset='variable' with basis='...'. With these changes, it is also necessary to adjust the xen tests: "localtime = 0" is always inserted, because otherwise on updates the value is not changed within XenD. adjustment='reset' is inserted for all cases, since they're all < XEND_CONFIG_VERSION_3_1_0, only 3.1 introduced persistent rtc_timeoffset. Some statements change their order because code was moved around. Signed-off-by: Philipp Hahn <hahn@univention.de>
2012-02-08 16:32:34 +00:00
if (xenXMConfigSetInt(conf, "localtime", vmlocaltime) < 0)
goto no_memory;
2011-02-21 13:40:11 +00:00
if (!(lifecycle = virDomainLifecycleTypeToString(def->onPoweroff))) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("unexpected lifecycle action %d"), def->onPoweroff);
goto cleanup;
}
if (xenXMConfigSetString(conf, "on_poweroff", lifecycle) < 0)
goto no_memory;
if (!(lifecycle = virDomainLifecycleTypeToString(def->onReboot))) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("unexpected lifecycle action %d"), def->onReboot);
goto cleanup;
}
if (xenXMConfigSetString(conf, "on_reboot", lifecycle) < 0)
goto no_memory;
if (!(lifecycle = virDomainLifecycleCrashTypeToString(def->onCrash))) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("unexpected lifecycle action %d"), def->onCrash);
goto cleanup;
}
if (xenXMConfigSetString(conf, "on_crash", lifecycle) < 0)
goto no_memory;
if (hvm) {
if (def->emulator &&
xenXMConfigSetString(conf, "device_model", def->emulator) < 0)
goto no_memory;
for (i = 0 ; i < def->ninputs ; i++) {
if (def->inputs[i]->bus == VIR_DOMAIN_INPUT_BUS_USB) {
if (xenXMConfigSetInt(conf, "usb", 1) < 0)
goto no_memory;
if (xenXMConfigSetString(conf, "usbdevice",
def->inputs[i]->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ?
"mouse" : "tablet") < 0)
goto no_memory;
break;
}
}
}
if (def->ngraphics == 1) {
if (hvm || (xendConfigVersion < XEND_CONFIG_MIN_VERS_PVFB_NEWCONF)) {
2011-02-21 13:40:11 +00:00
if (def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
if (xenXMConfigSetInt(conf, "sdl", 1) < 0)
goto no_memory;
if (xenXMConfigSetInt(conf, "vnc", 0) < 0)
goto no_memory;
if (def->graphics[0]->data.sdl.display &&
xenXMConfigSetString(conf, "display",
def->graphics[0]->data.sdl.display) < 0)
goto no_memory;
if (def->graphics[0]->data.sdl.xauth &&
xenXMConfigSetString(conf, "xauthority",
def->graphics[0]->data.sdl.xauth) < 0)
goto no_memory;
} else {
conf: add <listen> subelement to domain <graphics> element Once it's plugged in, the <listen> element will be an optional replacement for the "listen" attribute that graphics elements already have. If the <listen> element is type='address', it will have an attribute called 'address' which will contain an IP address or dns name that the guest's display server should listen on. If, however, type='network', the <listen> element should have an attribute called 'network' that will be set to the name of a network configuration to get the IP address from. * docs/schemas/domain.rng: updated to allow the <listen> element * docs/formatdomain.html.in: document the <listen> element and its attributes. * src/conf/domain_conf.[hc]: 1) The domain parser, formatter, and data structure are modified to support 0 or more <listen> subelements to each <graphics> element. The old style "legacy" listen attribute is also still accepted, and will be stored internally just as if it were a separate <listen> element. On output (i.e. format), the address attribute of the first <listen> element of type 'address' will be duplicated in the legacy "listen" attribute of the <graphic> element. 2) The "listenAddr" attribute has been removed from the unions in virDomainGRaphicsDef for graphics types vnc, rdp, and spice. This attribute is now in the <listen> subelement (aka virDomainGraphicsListenDef) 3) Helper functions were written to provide simple access (both Get and Set) to the listen elements and their attributes. * src/libvirt_private.syms: export the listen helper functions * src/qemu/qemu_command.c, src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c, src/vbox/vbox_tmpl.c, src/vmx/vmx.c, src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c Modify all these files to use the listen helper functions rather than directly referencing the (now missing) listenAddr attribute. There can be multiple <listen> elements to a single <graphics>, but the drivers all currently only support one, so all replacements of direct access with a helper function indicate index "0". * tests/* - only 3 of these are new files added explicitly to test the new <listen> element. All the others have been modified to reflect the fact that any legacy "listen" attributes passed in to the domain parse will be saved in a <listen> element (i.e. one of the virDomainGraphicsListenDefs), and during the domain format function, both the <listen> element as well as the legacy attributes will be output.
2011-07-07 04:20:28 +00:00
const char *listenAddr;
2011-02-21 13:40:11 +00:00
if (xenXMConfigSetInt(conf, "sdl", 0) < 0)
goto no_memory;
if (xenXMConfigSetInt(conf, "vnc", 1) < 0)
goto no_memory;
if (xenXMConfigSetInt(conf, "vncunused",
def->graphics[0]->data.vnc.autoport ? 1 : 0) < 0)
goto no_memory;
if (!def->graphics[0]->data.vnc.autoport &&
xenXMConfigSetInt(conf, "vncdisplay",
def->graphics[0]->data.vnc.port - 5900) < 0)
goto no_memory;
conf: add <listen> subelement to domain <graphics> element Once it's plugged in, the <listen> element will be an optional replacement for the "listen" attribute that graphics elements already have. If the <listen> element is type='address', it will have an attribute called 'address' which will contain an IP address or dns name that the guest's display server should listen on. If, however, type='network', the <listen> element should have an attribute called 'network' that will be set to the name of a network configuration to get the IP address from. * docs/schemas/domain.rng: updated to allow the <listen> element * docs/formatdomain.html.in: document the <listen> element and its attributes. * src/conf/domain_conf.[hc]: 1) The domain parser, formatter, and data structure are modified to support 0 or more <listen> subelements to each <graphics> element. The old style "legacy" listen attribute is also still accepted, and will be stored internally just as if it were a separate <listen> element. On output (i.e. format), the address attribute of the first <listen> element of type 'address' will be duplicated in the legacy "listen" attribute of the <graphic> element. 2) The "listenAddr" attribute has been removed from the unions in virDomainGRaphicsDef for graphics types vnc, rdp, and spice. This attribute is now in the <listen> subelement (aka virDomainGraphicsListenDef) 3) Helper functions were written to provide simple access (both Get and Set) to the listen elements and their attributes. * src/libvirt_private.syms: export the listen helper functions * src/qemu/qemu_command.c, src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c, src/vbox/vbox_tmpl.c, src/vmx/vmx.c, src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c Modify all these files to use the listen helper functions rather than directly referencing the (now missing) listenAddr attribute. There can be multiple <listen> elements to a single <graphics>, but the drivers all currently only support one, so all replacements of direct access with a helper function indicate index "0". * tests/* - only 3 of these are new files added explicitly to test the new <listen> element. All the others have been modified to reflect the fact that any legacy "listen" attributes passed in to the domain parse will be saved in a <listen> element (i.e. one of the virDomainGraphicsListenDefs), and during the domain format function, both the <listen> element as well as the legacy attributes will be output.
2011-07-07 04:20:28 +00:00
listenAddr = virDomainGraphicsListenGetAddress(def->graphics[0], 0);
if (listenAddr &&
xenXMConfigSetString(conf, "vnclisten", listenAddr) < 0)
2011-02-21 13:40:11 +00:00
goto no_memory;
if (def->graphics[0]->data.vnc.auth.passwd &&
xenXMConfigSetString(conf, "vncpasswd",
def->graphics[0]->data.vnc.auth.passwd) < 0)
goto no_memory;
if (def->graphics[0]->data.vnc.keymap &&
xenXMConfigSetString(conf, "keymap",
def->graphics[0]->data.vnc.keymap) < 0)
goto no_memory;
}
} else {
virConfValuePtr vfb, disp;
char *vfbstr = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
virBufferAddLit(&buf, "type=sdl");
if (def->graphics[0]->data.sdl.display)
virBufferAsprintf(&buf, ",display=%s",
2011-02-21 13:40:11 +00:00
def->graphics[0]->data.sdl.display);
if (def->graphics[0]->data.sdl.xauth)
virBufferAsprintf(&buf, ",xauthority=%s",
2011-02-21 13:40:11 +00:00
def->graphics[0]->data.sdl.xauth);
} else {
conf: add <listen> subelement to domain <graphics> element Once it's plugged in, the <listen> element will be an optional replacement for the "listen" attribute that graphics elements already have. If the <listen> element is type='address', it will have an attribute called 'address' which will contain an IP address or dns name that the guest's display server should listen on. If, however, type='network', the <listen> element should have an attribute called 'network' that will be set to the name of a network configuration to get the IP address from. * docs/schemas/domain.rng: updated to allow the <listen> element * docs/formatdomain.html.in: document the <listen> element and its attributes. * src/conf/domain_conf.[hc]: 1) The domain parser, formatter, and data structure are modified to support 0 or more <listen> subelements to each <graphics> element. The old style "legacy" listen attribute is also still accepted, and will be stored internally just as if it were a separate <listen> element. On output (i.e. format), the address attribute of the first <listen> element of type 'address' will be duplicated in the legacy "listen" attribute of the <graphic> element. 2) The "listenAddr" attribute has been removed from the unions in virDomainGRaphicsDef for graphics types vnc, rdp, and spice. This attribute is now in the <listen> subelement (aka virDomainGraphicsListenDef) 3) Helper functions were written to provide simple access (both Get and Set) to the listen elements and their attributes. * src/libvirt_private.syms: export the listen helper functions * src/qemu/qemu_command.c, src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c, src/vbox/vbox_tmpl.c, src/vmx/vmx.c, src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c Modify all these files to use the listen helper functions rather than directly referencing the (now missing) listenAddr attribute. There can be multiple <listen> elements to a single <graphics>, but the drivers all currently only support one, so all replacements of direct access with a helper function indicate index "0". * tests/* - only 3 of these are new files added explicitly to test the new <listen> element. All the others have been modified to reflect the fact that any legacy "listen" attributes passed in to the domain parse will be saved in a <listen> element (i.e. one of the virDomainGraphicsListenDefs), and during the domain format function, both the <listen> element as well as the legacy attributes will be output.
2011-07-07 04:20:28 +00:00
const char *listenAddr
= virDomainGraphicsListenGetAddress(def->graphics[0], 0);
2011-02-21 13:40:11 +00:00
virBufferAddLit(&buf, "type=vnc");
virBufferAsprintf(&buf, ",vncunused=%d",
2011-02-21 13:40:11 +00:00
def->graphics[0]->data.vnc.autoport ? 1 : 0);
if (!def->graphics[0]->data.vnc.autoport)
virBufferAsprintf(&buf, ",vncdisplay=%d",
2011-02-21 13:40:11 +00:00
def->graphics[0]->data.vnc.port - 5900);
conf: add <listen> subelement to domain <graphics> element Once it's plugged in, the <listen> element will be an optional replacement for the "listen" attribute that graphics elements already have. If the <listen> element is type='address', it will have an attribute called 'address' which will contain an IP address or dns name that the guest's display server should listen on. If, however, type='network', the <listen> element should have an attribute called 'network' that will be set to the name of a network configuration to get the IP address from. * docs/schemas/domain.rng: updated to allow the <listen> element * docs/formatdomain.html.in: document the <listen> element and its attributes. * src/conf/domain_conf.[hc]: 1) The domain parser, formatter, and data structure are modified to support 0 or more <listen> subelements to each <graphics> element. The old style "legacy" listen attribute is also still accepted, and will be stored internally just as if it were a separate <listen> element. On output (i.e. format), the address attribute of the first <listen> element of type 'address' will be duplicated in the legacy "listen" attribute of the <graphic> element. 2) The "listenAddr" attribute has been removed from the unions in virDomainGRaphicsDef for graphics types vnc, rdp, and spice. This attribute is now in the <listen> subelement (aka virDomainGraphicsListenDef) 3) Helper functions were written to provide simple access (both Get and Set) to the listen elements and their attributes. * src/libvirt_private.syms: export the listen helper functions * src/qemu/qemu_command.c, src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c, src/vbox/vbox_tmpl.c, src/vmx/vmx.c, src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c Modify all these files to use the listen helper functions rather than directly referencing the (now missing) listenAddr attribute. There can be multiple <listen> elements to a single <graphics>, but the drivers all currently only support one, so all replacements of direct access with a helper function indicate index "0". * tests/* - only 3 of these are new files added explicitly to test the new <listen> element. All the others have been modified to reflect the fact that any legacy "listen" attributes passed in to the domain parse will be saved in a <listen> element (i.e. one of the virDomainGraphicsListenDefs), and during the domain format function, both the <listen> element as well as the legacy attributes will be output.
2011-07-07 04:20:28 +00:00
if (listenAddr)
virBufferAsprintf(&buf, ",vnclisten=%s", listenAddr);
2011-02-21 13:40:11 +00:00
if (def->graphics[0]->data.vnc.auth.passwd)
virBufferAsprintf(&buf, ",vncpasswd=%s",
2011-02-21 13:40:11 +00:00
def->graphics[0]->data.vnc.auth.passwd);
if (def->graphics[0]->data.vnc.keymap)
virBufferAsprintf(&buf, ",keymap=%s",
2011-02-21 13:40:11 +00:00
def->graphics[0]->data.vnc.keymap);
}
if (virBufferError(&buf)) {
virBufferFreeAndReset(&buf);
goto no_memory;
}
vfbstr = virBufferContentAndReset(&buf);
if (VIR_ALLOC(vfb) < 0) {
VIR_FREE(vfbstr);
goto no_memory;
}
if (VIR_ALLOC(disp) < 0) {
VIR_FREE(vfb);
VIR_FREE(vfbstr);
goto no_memory;
}
vfb->type = VIR_CONF_LIST;
vfb->list = disp;
disp->type = VIR_CONF_STRING;
disp->str = vfbstr;
if (virConfSetValue(conf, "vfb", vfb) < 0)
goto no_memory;
}
}
/* analyze of the devices */
if (VIR_ALLOC(diskVal) < 0)
goto no_memory;
diskVal->type = VIR_CONF_LIST;
diskVal->list = NULL;
for (i = 0 ; i < def->ndisks ; i++) {
if (xendConfigVersion == XEND_CONFIG_VERSION_3_0_2 &&
2011-02-21 13:40:11 +00:00
def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
def->disks[i]->dst &&
STREQ(def->disks[i]->dst, "hdc")) {
continue;
}
if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
continue;
2011-02-21 13:40:12 +00:00
if (xenFormatXMDisk(diskVal, def->disks[i],
hvm, xendConfigVersion) < 0)
2011-02-21 13:40:11 +00:00
goto cleanup;
}
if (diskVal->list != NULL) {
int ret = virConfSetValue(conf, "disk", diskVal);
diskVal = NULL;
if (ret < 0)
goto no_memory;
}
VIR_FREE(diskVal);
if (VIR_ALLOC(netVal) < 0)
goto no_memory;
netVal->type = VIR_CONF_LIST;
netVal->list = NULL;
for (i = 0 ; i < def->nnets ; i++) {
2011-02-21 13:40:12 +00:00
if (xenFormatXMNet(conn, netVal,def->nets[i],
hvm, xendConfigVersion) < 0)
2011-02-21 13:40:11 +00:00
goto cleanup;
}
if (netVal->list != NULL) {
int ret = virConfSetValue(conf, "vif", netVal);
netVal = NULL;
if (ret < 0)
goto no_memory;
}
VIR_FREE(netVal);
2011-02-21 13:40:12 +00:00
if (xenFormatXMPCI(conf, def) < 0)
2011-02-21 13:40:11 +00:00
goto cleanup;
if (hvm) {
if (def->nparallels) {
virBuffer buf = VIR_BUFFER_INITIALIZER;
char *str;
int ret;
2011-02-21 13:40:12 +00:00
ret = xenFormatSxprChr(def->parallels[0], &buf);
2011-02-21 13:40:11 +00:00
str = virBufferContentAndReset(&buf);
if (ret == 0)
ret = xenXMConfigSetString(conf, "parallel", str);
VIR_FREE(str);
if (ret < 0)
goto no_memory;
} else {
if (xenXMConfigSetString(conf, "parallel", "none") < 0)
goto no_memory;
}
if (def->nserials) {
if ((def->nserials == 1) && (def->serials[0]->target.port == 0)) {
virBuffer buf = VIR_BUFFER_INITIALIZER;
char *str;
int ret;
ret = xenFormatSxprChr(def->serials[0], &buf);
str = virBufferContentAndReset(&buf);
if (ret == 0)
ret = xenXMConfigSetString(conf, "serial", str);
VIR_FREE(str);
if (ret < 0)
goto no_memory;
} else {
int j = 0;
int maxport = -1;
virConfValuePtr serialVal = NULL;
2011-02-21 13:40:11 +00:00
if (VIR_ALLOC(serialVal) < 0)
goto no_memory;
serialVal->type = VIR_CONF_LIST;
serialVal->list = NULL;
for (i = 0; i < def->nserials; i++)
if (def->serials[i]->target.port > maxport)
maxport = def->serials[i]->target.port;
for (i = 0; i <= maxport; i++) {
virDomainChrDefPtr chr = NULL;
for (j = 0; j < def->nserials; j++) {
if (def->serials[j]->target.port == i) {
chr = def->serials[j];
break;
}
}
if (xenFormatXMSerial(serialVal, chr) < 0)
goto cleanup;
}
if (serialVal->list != NULL) {
int ret = virConfSetValue(conf, "serial", serialVal);
serialVal = NULL;
if (ret < 0)
goto no_memory;
}
VIR_FREE(serialVal);
}
2011-02-21 13:40:11 +00:00
} else {
if (xenXMConfigSetString(conf, "serial", "none") < 0)
goto no_memory;
}
if (def->sounds) {
virBuffer buf = VIR_BUFFER_INITIALIZER;
char *str = NULL;
2011-02-21 13:40:12 +00:00
int ret = xenFormatSxprSound(def, &buf);
2011-02-21 13:40:11 +00:00
str = virBufferContentAndReset(&buf);
if (ret == 0)
ret = xenXMConfigSetString(conf, "soundhw", str);
VIR_FREE(str);
if (ret < 0)
goto no_memory;
}
}
return conf;
no_memory:
virReportOOMError();
cleanup:
virConfFreeValue(diskVal);
virConfFreeValue(netVal);
VIR_FREE(cpus);
if (conf)
virConfFree(conf);
return NULL;
}