Moved SEXPR formatting functions to xenxs

This commit is contained in:
Markus Groß 2011-02-21 14:40:09 +01:00 committed by Eric Blake
parent 07129039cc
commit 2f2a88b998
6 changed files with 900 additions and 888 deletions

View File

@ -59,35 +59,8 @@
#define XEN_SCHED_SEDF_NPARAM 6
#define XEN_SCHED_CRED_NPARAM 2
#ifdef WITH_RHEL5_API
# define XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU 0
# define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 2
#else
# define XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU 3
# define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 3
#endif
#define XEND_RCV_BUF_MAX_LEN 65536
static int
xenDaemonFormatSxprDisk(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainDiskDefPtr def,
virBufferPtr buf,
int hvm,
int xendConfigVersion,
int isAttach);
static int
xenDaemonFormatSxprNet(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainNetDefPtr def,
virBufferPtr buf,
int hvm,
int xendConfigVersion,
int isAttach);
static int
xenDaemonFormatSxprOnePCI(virDomainHostdevDefPtr def,
virBufferPtr buf,
int detach);
static int
virDomainXMLDevID(virDomainPtr domain,
virDomainDeviceDefPtr dev,
@ -3872,854 +3845,6 @@ struct xenUnifiedDriver xenDaemonDriver = {
xenDaemonSetSchedulerParameters, /* domainSetSchedulerParameters */
};
/************************************************************************
* *
* Converter functions to go from the XML tree to an S-Expr for Xen *
* *
************************************************************************/
/**
* virtDomainParseXMLGraphicsDescVFB:
* @conn: pointer to the hypervisor connection
* @node: node containing graphics description
* @buf: a buffer for the result S-Expr
*
* Parse the graphics part of the XML description and add it to the S-Expr
* in buf. This is a temporary interface as the S-Expr interface will be
* replaced by XML-RPC in the future. However the XML format should stay
* valid over time.
*
* Returns 0 in case of success, -1 in case of error
*/
static int
xenDaemonFormatSxprGraphicsNew(virDomainGraphicsDefPtr def,
virBufferPtr buf)
{
if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_SDL &&
def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
virXendError(VIR_ERR_INTERNAL_ERROR,
_("unexpected graphics type %d"),
def->type);
return -1;
}
virBufferAddLit(buf, "(device (vkbd))");
virBufferAddLit(buf, "(device (vfb ");
if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
virBufferAddLit(buf, "(type sdl)");
if (def->data.sdl.display)
virBufferVSprintf(buf, "(display '%s')", def->data.sdl.display);
if (def->data.sdl.xauth)
virBufferVSprintf(buf, "(xauthority '%s')", def->data.sdl.xauth);
} else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
virBufferAddLit(buf, "(type vnc)");
if (def->data.vnc.autoport) {
virBufferAddLit(buf, "(vncunused 1)");
} else {
virBufferAddLit(buf, "(vncunused 0)");
virBufferVSprintf(buf, "(vncdisplay %d)", def->data.vnc.port-5900);
}
if (def->data.vnc.listenAddr)
virBufferVSprintf(buf, "(vnclisten '%s')", def->data.vnc.listenAddr);
if (def->data.vnc.auth.passwd)
virBufferVSprintf(buf, "(vncpasswd '%s')", def->data.vnc.auth.passwd);
if (def->data.vnc.keymap)
virBufferVSprintf(buf, "(keymap '%s')", def->data.vnc.keymap);
}
virBufferAddLit(buf, "))");
return 0;
}
static int
xenDaemonFormatSxprGraphicsOld(virDomainGraphicsDefPtr def,
virBufferPtr buf,
int xendConfigVersion)
{
if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_SDL &&
def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
virXendError(VIR_ERR_INTERNAL_ERROR,
_("unexpected graphics type %d"),
def->type);
return -1;
}
if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
virBufferAddLit(buf, "(sdl 1)");
if (def->data.sdl.display)
virBufferVSprintf(buf, "(display '%s')", def->data.sdl.display);
if (def->data.sdl.xauth)
virBufferVSprintf(buf, "(xauthority '%s')", def->data.sdl.xauth);
} else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
virBufferAddLit(buf, "(vnc 1)");
if (xendConfigVersion >= 2) {
if (def->data.vnc.autoport) {
virBufferAddLit(buf, "(vncunused 1)");
} else {
virBufferAddLit(buf, "(vncunused 0)");
virBufferVSprintf(buf, "(vncdisplay %d)", def->data.vnc.port-5900);
}
if (def->data.vnc.listenAddr)
virBufferVSprintf(buf, "(vnclisten '%s')", def->data.vnc.listenAddr);
if (def->data.vnc.auth.passwd)
virBufferVSprintf(buf, "(vncpasswd '%s')", def->data.vnc.auth.passwd);
if (def->data.vnc.keymap)
virBufferVSprintf(buf, "(keymap '%s')", def->data.vnc.keymap);
}
}
return 0;
}
int
xenDaemonFormatSxprChr(virDomainChrDefPtr def,
virBufferPtr buf)
{
const char *type = virDomainChrTypeToString(def->source.type);
if (!type) {
virXendError(VIR_ERR_INTERNAL_ERROR,
"%s", _("unexpected chr device type"));
return -1;
}
switch (def->source.type) {
case VIR_DOMAIN_CHR_TYPE_NULL:
case VIR_DOMAIN_CHR_TYPE_STDIO:
case VIR_DOMAIN_CHR_TYPE_VC:
case VIR_DOMAIN_CHR_TYPE_PTY:
virBufferVSprintf(buf, "%s", type);
break;
case VIR_DOMAIN_CHR_TYPE_FILE:
case VIR_DOMAIN_CHR_TYPE_PIPE:
virBufferVSprintf(buf, "%s:", type);
virBufferEscapeSexpr(buf, "%s", def->source.data.file.path);
break;
case VIR_DOMAIN_CHR_TYPE_DEV:
virBufferEscapeSexpr(buf, "%s", def->source.data.file.path);
break;
case VIR_DOMAIN_CHR_TYPE_TCP:
virBufferVSprintf(buf, "%s:%s:%s%s",
(def->source.data.tcp.protocol
== VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW ?
"tcp" : "telnet"),
(def->source.data.tcp.host ?
def->source.data.tcp.host : ""),
(def->source.data.tcp.service ?
def->source.data.tcp.service : ""),
(def->source.data.tcp.listen ?
",server,nowait" : ""));
break;
case VIR_DOMAIN_CHR_TYPE_UDP:
virBufferVSprintf(buf, "%s:%s:%s@%s:%s", type,
(def->source.data.udp.connectHost ?
def->source.data.udp.connectHost : ""),
(def->source.data.udp.connectService ?
def->source.data.udp.connectService : ""),
(def->source.data.udp.bindHost ?
def->source.data.udp.bindHost : ""),
(def->source.data.udp.bindService ?
def->source.data.udp.bindService : ""));
break;
case VIR_DOMAIN_CHR_TYPE_UNIX:
virBufferVSprintf(buf, "%s:", type);
virBufferEscapeSexpr(buf, "%s", def->source.data.nix.path);
if (def->source.data.nix.listen)
virBufferAddLit(buf, ",server,nowait");
break;
}
if (virBufferError(buf)) {
virReportOOMError();
return -1;
}
return 0;
}
/**
* virDomainParseXMLDiskDesc:
* @node: node containing disk description
* @conn: pointer to the hypervisor connection
* @buf: a buffer for the result S-Expr
* @xendConfigVersion: xend configuration file format
*
* Parse the one disk in the XML description and add it to the S-Expr in buf
* This is a temporary interface as the S-Expr interface
* will be replaced by XML-RPC in the future. However the XML format should
* stay valid over time.
*
* Returns 0 in case of success, -1 in case of error.
*/
static int
xenDaemonFormatSxprDisk(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainDiskDefPtr def,
virBufferPtr buf,
int hvm,
int xendConfigVersion,
int isAttach)
{
/* Xend (all versions) put the floppy device config
* under the hvm (image (os)) block
*/
if (hvm &&
def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
if (isAttach) {
virXendError(VIR_ERR_INVALID_ARG,
_("Cannot directly attach floppy %s"), def->src);
return -1;
}
return 0;
}
/* Xend <= 3.0.2 doesn't include cdrom config here */
if (hvm &&
def->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
xendConfigVersion == 1) {
if (isAttach) {
virXendError(VIR_ERR_INVALID_ARG,
_("Cannot directly attach CDROM %s"), def->src);
return -1;
}
return 0;
}
if (!isAttach)
virBufferAddLit(buf, "(device ");
/* Normally disks are in a (device (vbd ...)) block
* but blktap disks ended up in a differently named
* (device (tap ....)) block.... */
if (def->driverName && STREQ(def->driverName, "tap")) {
virBufferAddLit(buf, "(tap ");
} else if (def->driverName && STREQ(def->driverName, "tap2")) {
virBufferAddLit(buf, "(tap2 ");
} else {
virBufferAddLit(buf, "(vbd ");
}
if (hvm) {
/* Xend <= 3.0.2 wants a ioemu: prefix on devices for HVM */
if (xendConfigVersion == 1) {
virBufferEscapeSexpr(buf, "(dev 'ioemu:%s')", def->dst);
} else {
/* But newer does not */
virBufferEscapeSexpr(buf, "(dev '%s:", def->dst);
virBufferVSprintf(buf, "%s')",
def->device == VIR_DOMAIN_DISK_DEVICE_CDROM ?
"cdrom" : "disk");
}
} else if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
virBufferEscapeSexpr(buf, "(dev '%s:cdrom')", def->dst);
} else {
virBufferEscapeSexpr(buf, "(dev '%s')", def->dst);
}
if (def->src) {
if (def->driverName) {
if (STREQ(def->driverName, "tap") ||
STREQ(def->driverName, "tap2")) {
virBufferEscapeSexpr(buf, "(uname '%s:", def->driverName);
virBufferEscapeSexpr(buf, "%s:",
def->driverType ? def->driverType : "aio");
virBufferEscapeSexpr(buf, "%s')", def->src);
} else {
virBufferEscapeSexpr(buf, "(uname '%s:", def->driverName);
virBufferEscapeSexpr(buf, "%s')", def->src);
}
} else {
if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) {
virBufferEscapeSexpr(buf, "(uname 'file:%s')", def->src);
} else if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
if (def->src[0] == '/')
virBufferEscapeSexpr(buf, "(uname 'phy:%s')", def->src);
else
virBufferEscapeSexpr(buf, "(uname 'phy:/dev/%s')",
def->src);
} else {
virXendError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported disk type %s"),
virDomainDiskTypeToString(def->type));
return -1;
}
}
}
if (def->readonly)
virBufferAddLit(buf, "(mode 'r')");
else if (def->shared)
virBufferAddLit(buf, "(mode 'w!')");
else
virBufferAddLit(buf, "(mode 'w')");
if (!isAttach)
virBufferAddLit(buf, ")");
virBufferAddLit(buf, ")");
return 0;
}
/**
* xenDaemonFormatSxprNet
* @conn: pointer to the hypervisor connection
* @node: node containing the interface description
* @buf: a buffer for the result S-Expr
* @xendConfigVersion: xend configuration file format
*
* Parse the one interface the XML description and add it to the S-Expr in buf
* This is a temporary interface as the S-Expr interface
* will be replaced by XML-RPC in the future. However the XML format should
* stay valid over time.
*
* Returns 0 in case of success, -1 in case of error.
*/
static int
xenDaemonFormatSxprNet(virConnectPtr conn,
virDomainNetDefPtr def,
virBufferPtr buf,
int hvm,
int xendConfigVersion,
int isAttach)
{
const char *script = DEFAULT_VIF_SCRIPT;
if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
def->type != VIR_DOMAIN_NET_TYPE_NETWORK &&
def->type != VIR_DOMAIN_NET_TYPE_ETHERNET) {
virXendError(VIR_ERR_INTERNAL_ERROR,
_("unsupported network type %d"), def->type);
return -1;
}
if (!isAttach)
virBufferAddLit(buf, "(device ");
virBufferAddLit(buf, "(vif ");
virBufferVSprintf(buf,
"(mac '%02x:%02x:%02x:%02x:%02x:%02x')",
def->mac[0], def->mac[1], def->mac[2],
def->mac[3], def->mac[4], def->mac[5]);
switch (def->type) {
case VIR_DOMAIN_NET_TYPE_BRIDGE:
virBufferEscapeSexpr(buf, "(bridge '%s')", def->data.bridge.brname);
if (def->data.bridge.script)
script = def->data.bridge.script;
virBufferEscapeSexpr(buf, "(script '%s')", script);
if (def->data.bridge.ipaddr != NULL)
virBufferEscapeSexpr(buf, "(ip '%s')", def->data.bridge.ipaddr);
break;
case VIR_DOMAIN_NET_TYPE_NETWORK:
{
virNetworkPtr network =
virNetworkLookupByName(conn, def->data.network.name);
char *bridge;
if (!network) {
virXendError(VIR_ERR_NO_NETWORK, "%s",
def->data.network.name);
return -1;
}
bridge = virNetworkGetBridgeName(network);
virNetworkFree(network);
if (!bridge) {
virXendError(VIR_ERR_INTERNAL_ERROR,
_("network %s is not active"),
def->data.network.name);
return -1;
}
virBufferEscapeSexpr(buf, "(bridge '%s')", bridge);
virBufferEscapeSexpr(buf, "(script '%s')", script);
VIR_FREE(bridge);
}
break;
case VIR_DOMAIN_NET_TYPE_ETHERNET:
if (def->data.ethernet.script)
virBufferEscapeSexpr(buf, "(script '%s')",
def->data.ethernet.script);
if (def->data.ethernet.ipaddr != NULL)
virBufferEscapeSexpr(buf, "(ip '%s')", def->data.ethernet.ipaddr);
break;
case VIR_DOMAIN_NET_TYPE_USER:
case VIR_DOMAIN_NET_TYPE_SERVER:
case VIR_DOMAIN_NET_TYPE_CLIENT:
case VIR_DOMAIN_NET_TYPE_MCAST:
case VIR_DOMAIN_NET_TYPE_INTERNAL:
case VIR_DOMAIN_NET_TYPE_DIRECT:
case VIR_DOMAIN_NET_TYPE_LAST:
break;
}
if (def->ifname != NULL &&
!STRPREFIX(def->ifname, "vif"))
virBufferEscapeSexpr(buf, "(vifname '%s')", def->ifname);
if (!hvm) {
if (def->model != NULL)
virBufferEscapeSexpr(buf, "(model '%s')", def->model);
}
else if (def->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(def->model, "netfront")) {
virBufferAddLit(buf, "(type netfront)");
}
else {
virBufferEscapeSexpr(buf, "(model '%s')", def->model);
virBufferAddLit(buf, "(type ioemu)");
}
if (!isAttach)
virBufferAddLit(buf, ")");
virBufferAddLit(buf, ")");
return 0;
}
static void
xenDaemonFormatSxprPCI(virDomainHostdevDefPtr def,
virBufferPtr buf)
{
virBufferVSprintf(buf, "(dev (domain 0x%04x)(bus 0x%02x)(slot 0x%02x)(func 0x%x))",
def->source.subsys.u.pci.domain,
def->source.subsys.u.pci.bus,
def->source.subsys.u.pci.slot,
def->source.subsys.u.pci.function);
}
static int
xenDaemonFormatSxprOnePCI(virDomainHostdevDefPtr def,
virBufferPtr buf,
int detach)
{
if (def->managed) {
virXendError(VIR_ERR_NO_SUPPORT, "%s",
_("managed PCI devices not supported with XenD"));
return -1;
}
virBufferAddLit(buf, "(pci ");
xenDaemonFormatSxprPCI(def, buf);
if (detach)
virBufferAddLit(buf, "(state 'Closing')");
else
virBufferAddLit(buf, "(state 'Initialising')");
virBufferAddLit(buf, ")");
return 0;
}
static int
xenDaemonFormatSxprAllPCI(virDomainDefPtr def,
virBufferPtr buf)
{
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;
/*
* With the (domain ...) block we have the following odd setup
*
* (device
* (pci
* (dev (domain 0x0000) (bus 0x00) (slot 0x1b) (func 0x0))
* (dev (domain 0x0000) (bus 0x00) (slot 0x13) (func 0x0))
* )
* )
*
* Normally there is one (device ...) block per device, but in the
* weird world of Xen PCI, one (device ...) covers multiple devices.
*/
virBufferAddLit(buf, "(device (pci ");
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) {
if (def->hostdevs[i]->managed) {
virXendError(VIR_ERR_NO_SUPPORT, "%s",
_("managed PCI devices not supported with XenD"));
return -1;
}
xenDaemonFormatSxprPCI(def->hostdevs[i], buf);
}
}
virBufferAddLit(buf, "))");
return 0;
}
int
xenDaemonFormatSxprSound(virDomainDefPtr def,
virBufferPtr buf)
{
const char *str;
int i;
for (i = 0 ; i < def->nsounds ; i++) {
if (!(str = virDomainSoundModelTypeToString(def->sounds[i]->model))) {
virXendError(VIR_ERR_INTERNAL_ERROR,
_("unexpected sound model %d"),
def->sounds[i]->model);
return -1;
}
if (i)
virBufferAddChar(buf, ',');
virBufferEscapeSexpr(buf, "%s", str);
}
if (virBufferError(buf)) {
virReportOOMError();
return -1;
}
return 0;
}
static int
xenDaemonFormatSxprInput(virDomainInputDefPtr input,
virBufferPtr buf)
{
if (input->bus != VIR_DOMAIN_INPUT_BUS_USB)
return 0;
if (input->type != VIR_DOMAIN_INPUT_TYPE_MOUSE &&
input->type != VIR_DOMAIN_INPUT_TYPE_TABLET) {
virXendError(VIR_ERR_INTERNAL_ERROR,
_("unexpected input type %d"), input->type);
return -1;
}
virBufferVSprintf(buf, "(usbdevice %s)",
input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ?
"mouse" : "tablet");
return 0;
}
/* 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);
/**
* xenDaemonFormatSxpr:
* @conn: pointer to the hypervisor connection
* @def: domain config definition
* @xendConfigVersion: xend configuration file format
*
* Generate an SEXPR representing the domain configuration.
*
* Returns the 0 terminated S-Expr string or NULL in case of error.
* the caller must free() the returned value.
*/
char *
xenDaemonFormatSxpr(virConnectPtr conn,
virDomainDefPtr def,
int xendConfigVersion)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
char uuidstr[VIR_UUID_STRING_BUFLEN];
const char *tmp;
char *bufout;
int hvm = 0, i;
VIR_DEBUG0("Formatting domain sexpr");
virBufferAddLit(&buf, "(vm ");
virBufferEscapeSexpr(&buf, "(name '%s')", def->name);
virBufferVSprintf(&buf, "(memory %lu)(maxmem %lu)",
VIR_DIV_UP(def->mem.cur_balloon, 1024),
VIR_DIV_UP(def->mem.max_balloon, 1024));
virBufferVSprintf(&buf, "(vcpus %u)", def->maxvcpus);
/* 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)
virBufferVSprintf(&buf, "(vcpu_avail %lu)", (1UL << def->vcpus) - 1);
if (def->cpumask) {
char *ranges = virDomainCpuSetFormat(def->cpumask, def->cpumasklen);
if (ranges == NULL)
goto error;
virBufferEscapeSexpr(&buf, "(cpus '%s')", ranges);
VIR_FREE(ranges);
}
virUUIDFormat(def->uuid, uuidstr);
virBufferVSprintf(&buf, "(uuid '%s')", uuidstr);
if (def->description)
virBufferEscapeSexpr(&buf, "(description '%s')", def->description);
if (def->os.bootloader) {
if (def->os.bootloader[0])
virBufferEscapeSexpr(&buf, "(bootloader '%s')", def->os.bootloader);
else
virBufferAddLit(&buf, "(bootloader)");
if (def->os.bootloaderArgs)
virBufferEscapeSexpr(&buf, "(bootloader_args '%s')", def->os.bootloaderArgs);
}
if (!(tmp = virDomainLifecycleTypeToString(def->onPoweroff))) {
virXendError(VIR_ERR_INTERNAL_ERROR,
_("unexpected lifecycle value %d"), def->onPoweroff);
goto error;
}
virBufferVSprintf(&buf, "(on_poweroff '%s')", tmp);
if (!(tmp = virDomainLifecycleTypeToString(def->onReboot))) {
virXendError(VIR_ERR_INTERNAL_ERROR,
_("unexpected lifecycle value %d"), def->onReboot);
goto error;
}
virBufferVSprintf(&buf, "(on_reboot '%s')", tmp);
if (!(tmp = virDomainLifecycleCrashTypeToString(def->onCrash))) {
virXendError(VIR_ERR_INTERNAL_ERROR,
_("unexpected lifecycle value %d"), def->onCrash);
goto error;
}
virBufferVSprintf(&buf, "(on_crash '%s')", tmp);
/* Set localtime here for current XenD (both PV & HVM) */
if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME) {
if (def->clock.data.timezone) {
virXendError(VIR_ERR_CONFIG_UNSUPPORTED,
"%s", _("configurable timezones are not supported"));
goto error;
}
virBufferAddLit(&buf, "(localtime 1)");
} else if (def->clock.offset != VIR_DOMAIN_CLOCK_OFFSET_UTC) {
virXendError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported clock offset '%s'"),
virDomainClockOffsetTypeToString(def->clock.offset));
goto error;
}
if (!def->os.bootloader) {
if (STREQ(def->os.type, "hvm"))
hvm = 1;
if (hvm)
virBufferAddLit(&buf, "(image (hvm ");
else
virBufferAddLit(&buf, "(image (linux ");
if (hvm &&
def->os.loader == NULL) {
virXendError(VIR_ERR_INTERNAL_ERROR,
"%s",_("no HVM domain loader"));
goto error;
}
if (def->os.kernel)
virBufferEscapeSexpr(&buf, "(kernel '%s')", def->os.kernel);
if (def->os.initrd)
virBufferEscapeSexpr(&buf, "(ramdisk '%s')", def->os.initrd);
if (def->os.root)
virBufferEscapeSexpr(&buf, "(root '%s')", def->os.root);
if (def->os.cmdline)
virBufferEscapeSexpr(&buf, "(args '%s')", def->os.cmdline);
if (hvm) {
char bootorder[VIR_DOMAIN_BOOT_LAST+1];
if (def->os.kernel)
virBufferEscapeSexpr(&buf, "(loader '%s')", def->os.loader);
else
virBufferEscapeSexpr(&buf, "(kernel '%s')", def->os.loader);
virBufferVSprintf(&buf, "(vcpus %u)", def->maxvcpus);
if (def->vcpus < def->maxvcpus)
virBufferVSprintf(&buf, "(vcpu_avail %lu)",
(1UL << def->vcpus) - 1);
for (i = 0 ; i < def->os.nBootDevs ; i++) {
switch (def->os.bootDevs[i]) {
case VIR_DOMAIN_BOOT_FLOPPY:
bootorder[i] = 'a';
break;
default:
case VIR_DOMAIN_BOOT_DISK:
bootorder[i] = 'c';
break;
case VIR_DOMAIN_BOOT_CDROM:
bootorder[i] = 'd';
break;
case VIR_DOMAIN_BOOT_NET:
bootorder[i] = 'n';
break;
}
}
if (def->os.nBootDevs == 0) {
bootorder[0] = 'c';
bootorder[1] = '\0';
} else {
bootorder[def->os.nBootDevs] = '\0';
}
virBufferVSprintf(&buf, "(boot %s)", bootorder);
/* some disk devices are defined here */
for (i = 0 ; i < def->ndisks ; i++) {
switch (def->disks[i]->device) {
case VIR_DOMAIN_DISK_DEVICE_CDROM:
/* Only xend <= 3.0.2 wants cdrom config here */
if (xendConfigVersion != 1)
break;
if (!STREQ(def->disks[i]->dst, "hdc") ||
def->disks[i]->src == NULL)
break;
virBufferEscapeSexpr(&buf, "(cdrom '%s')",
def->disks[i]->src);
break;
case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
/* all xend versions define floppies here */
virBufferEscapeSexpr(&buf, "(%s ", def->disks[i]->dst);
virBufferEscapeSexpr(&buf, "'%s')", def->disks[i]->src);
break;
default:
break;
}
}
if (def->features & (1 << VIR_DOMAIN_FEATURE_ACPI))
virBufferAddLit(&buf, "(acpi 1)");
if (def->features & (1 << VIR_DOMAIN_FEATURE_APIC))
virBufferAddLit(&buf, "(apic 1)");
if (def->features & (1 << VIR_DOMAIN_FEATURE_PAE))
virBufferAddLit(&buf, "(pae 1)");
if (def->features & (1 << VIR_DOMAIN_FEATURE_HAP))
virBufferAddLit(&buf, "(hap 1)");
virBufferAddLit(&buf, "(usb 1)");
for (i = 0 ; i < def->ninputs ; i++)
if (xenDaemonFormatSxprInput(def->inputs[i], &buf) < 0)
goto error;
if (def->parallels) {
virBufferAddLit(&buf, "(parallel ");
if (xenDaemonFormatSxprChr(def->parallels[0], &buf) < 0)
goto error;
virBufferAddLit(&buf, ")");
} else {
virBufferAddLit(&buf, "(parallel none)");
}
if (def->serials) {
virBufferAddLit(&buf, "(serial ");
if (xenDaemonFormatSxprChr(def->serials[0], &buf) < 0)
goto error;
virBufferAddLit(&buf, ")");
} else {
virBufferAddLit(&buf, "(serial none)");
}
/* Set localtime here to keep old XenD happy for HVM */
if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME)
virBufferAddLit(&buf, "(localtime 1)");
if (def->sounds) {
virBufferAddLit(&buf, "(soundhw '");
if (xenDaemonFormatSxprSound(def, &buf) < 0)
goto error;
virBufferAddLit(&buf, "')");
}
}
/* get the device emulation model */
if (def->emulator && (hvm || xendConfigVersion >= 3))
virBufferEscapeSexpr(&buf, "(device_model '%s')", def->emulator);
/* PV graphics for xen <= 3.0.4, or HVM graphics for xen <= 3.1.0 */
if ((!hvm && xendConfigVersion < XEND_CONFIG_MIN_VERS_PVFB_NEWCONF) ||
(hvm && xendConfigVersion < 4)) {
if ((def->ngraphics == 1) &&
xenDaemonFormatSxprGraphicsOld(def->graphics[0],
&buf, xendConfigVersion) < 0)
goto error;
}
virBufferAddLit(&buf, "))");
}
for (i = 0 ; i < def->ndisks ; i++)
if (xenDaemonFormatSxprDisk(conn, def->disks[i],
&buf, hvm, xendConfigVersion, 0) < 0)
goto error;
for (i = 0 ; i < def->nnets ; i++)
if (xenDaemonFormatSxprNet(conn, def->nets[i],
&buf, hvm, xendConfigVersion, 0) < 0)
goto error;
if (xenDaemonFormatSxprAllPCI(def, &buf) < 0)
goto error;
/* New style PV graphics config xen >= 3.0.4,
* or HVM graphics config xen >= 3.0.5 */
if ((xendConfigVersion >= XEND_CONFIG_MIN_VERS_PVFB_NEWCONF && !hvm) ||
(xendConfigVersion >= 4 && hvm)) {
if ((def->ngraphics == 1) &&
xenDaemonFormatSxprGraphicsNew(def->graphics[0], &buf) < 0)
goto error;
}
virBufferAddLit(&buf, ")"); /* closes (vm */
if (virBufferError(&buf)) {
virReportOOMError();
goto error;
}
bufout = virBufferContentAndReset(&buf);
VIR_DEBUG("Formatted sexpr: \n%s", bufout);
return bufout;
error:
virBufferFreeAndReset(&buf);
return NULL;
}
/**
* virDomainXMLDevID:

View File

@ -91,18 +91,6 @@ xenDaemonDomainFetch(virConnectPtr xend,
const char *cpus);
int
xenDaemonFormatSxprChr(virDomainChrDefPtr def,
virBufferPtr buf);
int
xenDaemonFormatSxprSound(virDomainDefPtr def,
virBufferPtr buf);
char *
xenDaemonFormatSxpr(virConnectPtr conn,
virDomainDefPtr def,
int xendConfigVersion);
int is_sound_model_valid(const char *model);
int is_sound_model_conflict(const char *model, const char *soundstr);

View File

@ -1348,4 +1348,852 @@ xenDaemonParseSxprString(const char *sexpr,
sexpr_free(root);
return def;
}
}
/************************************************************************
* *
* Converter functions to go from the XML tree to an S-Expr for Xen *
* *
************************************************************************/
/**
* virtDomainParseXMLGraphicsDescVFB:
* @conn: pointer to the hypervisor connection
* @node: node containing graphics description
* @buf: a buffer for the result S-Expr
*
* Parse the graphics part of the XML description and add it to the S-Expr
* in buf. This is a temporary interface as the S-Expr interface will be
* replaced by XML-RPC in the future. However the XML format should stay
* valid over time.
*
* Returns 0 in case of success, -1 in case of error
*/
static int
xenDaemonFormatSxprGraphicsNew(virDomainGraphicsDefPtr def,
virBufferPtr buf)
{
if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_SDL &&
def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("unexpected graphics type %d"),
def->type);
return -1;
}
virBufferAddLit(buf, "(device (vkbd))");
virBufferAddLit(buf, "(device (vfb ");
if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
virBufferAddLit(buf, "(type sdl)");
if (def->data.sdl.display)
virBufferVSprintf(buf, "(display '%s')", def->data.sdl.display);
if (def->data.sdl.xauth)
virBufferVSprintf(buf, "(xauthority '%s')", def->data.sdl.xauth);
} else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
virBufferAddLit(buf, "(type vnc)");
if (def->data.vnc.autoport) {
virBufferAddLit(buf, "(vncunused 1)");
} else {
virBufferAddLit(buf, "(vncunused 0)");
virBufferVSprintf(buf, "(vncdisplay %d)", def->data.vnc.port-5900);
}
if (def->data.vnc.listenAddr)
virBufferVSprintf(buf, "(vnclisten '%s')", def->data.vnc.listenAddr);
if (def->data.vnc.auth.passwd)
virBufferVSprintf(buf, "(vncpasswd '%s')", def->data.vnc.auth.passwd);
if (def->data.vnc.keymap)
virBufferVSprintf(buf, "(keymap '%s')", def->data.vnc.keymap);
}
virBufferAddLit(buf, "))");
return 0;
}
static int
xenDaemonFormatSxprGraphicsOld(virDomainGraphicsDefPtr def,
virBufferPtr buf,
int xendConfigVersion)
{
if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_SDL &&
def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("unexpected graphics type %d"),
def->type);
return -1;
}
if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
virBufferAddLit(buf, "(sdl 1)");
if (def->data.sdl.display)
virBufferVSprintf(buf, "(display '%s')", def->data.sdl.display);
if (def->data.sdl.xauth)
virBufferVSprintf(buf, "(xauthority '%s')", def->data.sdl.xauth);
} else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
virBufferAddLit(buf, "(vnc 1)");
if (xendConfigVersion >= 2) {
if (def->data.vnc.autoport) {
virBufferAddLit(buf, "(vncunused 1)");
} else {
virBufferAddLit(buf, "(vncunused 0)");
virBufferVSprintf(buf, "(vncdisplay %d)", def->data.vnc.port-5900);
}
if (def->data.vnc.listenAddr)
virBufferVSprintf(buf, "(vnclisten '%s')", def->data.vnc.listenAddr);
if (def->data.vnc.auth.passwd)
virBufferVSprintf(buf, "(vncpasswd '%s')", def->data.vnc.auth.passwd);
if (def->data.vnc.keymap)
virBufferVSprintf(buf, "(keymap '%s')", def->data.vnc.keymap);
}
}
return 0;
}
int
xenDaemonFormatSxprChr(virDomainChrDefPtr def,
virBufferPtr buf)
{
const char *type = virDomainChrTypeToString(def->source.type);
if (!type) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
"%s", _("unexpected chr device type"));
return -1;
}
switch (def->source.type) {
case VIR_DOMAIN_CHR_TYPE_NULL:
case VIR_DOMAIN_CHR_TYPE_STDIO:
case VIR_DOMAIN_CHR_TYPE_VC:
case VIR_DOMAIN_CHR_TYPE_PTY:
virBufferVSprintf(buf, "%s", type);
break;
case VIR_DOMAIN_CHR_TYPE_FILE:
case VIR_DOMAIN_CHR_TYPE_PIPE:
virBufferVSprintf(buf, "%s:", type);
virBufferEscapeSexpr(buf, "%s", def->source.data.file.path);
break;
case VIR_DOMAIN_CHR_TYPE_DEV:
virBufferEscapeSexpr(buf, "%s", def->source.data.file.path);
break;
case VIR_DOMAIN_CHR_TYPE_TCP:
virBufferVSprintf(buf, "%s:%s:%s%s",
(def->source.data.tcp.protocol
== VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW ?
"tcp" : "telnet"),
(def->source.data.tcp.host ?
def->source.data.tcp.host : ""),
(def->source.data.tcp.service ?
def->source.data.tcp.service : ""),
(def->source.data.tcp.listen ?
",server,nowait" : ""));
break;
case VIR_DOMAIN_CHR_TYPE_UDP:
virBufferVSprintf(buf, "%s:%s:%s@%s:%s", type,
(def->source.data.udp.connectHost ?
def->source.data.udp.connectHost : ""),
(def->source.data.udp.connectService ?
def->source.data.udp.connectService : ""),
(def->source.data.udp.bindHost ?
def->source.data.udp.bindHost : ""),
(def->source.data.udp.bindService ?
def->source.data.udp.bindService : ""));
break;
case VIR_DOMAIN_CHR_TYPE_UNIX:
virBufferVSprintf(buf, "%s:", type);
virBufferEscapeSexpr(buf, "%s", def->source.data.nix.path);
if (def->source.data.nix.listen)
virBufferAddLit(buf, ",server,nowait");
break;
}
if (virBufferError(buf)) {
virReportOOMError();
return -1;
}
return 0;
}
/**
* virDomainParseXMLDiskDesc:
* @node: node containing disk description
* @conn: pointer to the hypervisor connection
* @buf: a buffer for the result S-Expr
* @xendConfigVersion: xend configuration file format
*
* Parse the one disk in the XML description and add it to the S-Expr in buf
* This is a temporary interface as the S-Expr interface
* will be replaced by XML-RPC in the future. However the XML format should
* stay valid over time.
*
* Returns 0 in case of success, -1 in case of error.
*/
int
xenDaemonFormatSxprDisk(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainDiskDefPtr def,
virBufferPtr buf,
int hvm,
int xendConfigVersion,
int isAttach)
{
/* Xend (all versions) put the floppy device config
* under the hvm (image (os)) block
*/
if (hvm &&
def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
if (isAttach) {
XENXS_ERROR(VIR_ERR_INVALID_ARG,
_("Cannot directly attach floppy %s"), def->src);
return -1;
}
return 0;
}
/* Xend <= 3.0.2 doesn't include cdrom config here */
if (hvm &&
def->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
xendConfigVersion == 1) {
if (isAttach) {
XENXS_ERROR(VIR_ERR_INVALID_ARG,
_("Cannot directly attach CDROM %s"), def->src);
return -1;
}
return 0;
}
if (!isAttach)
virBufferAddLit(buf, "(device ");
/* Normally disks are in a (device (vbd ...)) block
* but blktap disks ended up in a differently named
* (device (tap ....)) block.... */
if (def->driverName && STREQ(def->driverName, "tap")) {
virBufferAddLit(buf, "(tap ");
} else if (def->driverName && STREQ(def->driverName, "tap2")) {
virBufferAddLit(buf, "(tap2 ");
} else {
virBufferAddLit(buf, "(vbd ");
}
if (hvm) {
/* Xend <= 3.0.2 wants a ioemu: prefix on devices for HVM */
if (xendConfigVersion == 1) {
virBufferEscapeSexpr(buf, "(dev 'ioemu:%s')", def->dst);
} else {
/* But newer does not */
virBufferEscapeSexpr(buf, "(dev '%s:", def->dst);
virBufferVSprintf(buf, "%s')",
def->device == VIR_DOMAIN_DISK_DEVICE_CDROM ?
"cdrom" : "disk");
}
} else if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
virBufferEscapeSexpr(buf, "(dev '%s:cdrom')", def->dst);
} else {
virBufferEscapeSexpr(buf, "(dev '%s')", def->dst);
}
if (def->src) {
if (def->driverName) {
if (STREQ(def->driverName, "tap") ||
STREQ(def->driverName, "tap2")) {
virBufferEscapeSexpr(buf, "(uname '%s:", def->driverName);
virBufferEscapeSexpr(buf, "%s:",
def->driverType ? def->driverType : "aio");
virBufferEscapeSexpr(buf, "%s')", def->src);
} else {
virBufferEscapeSexpr(buf, "(uname '%s:", def->driverName);
virBufferEscapeSexpr(buf, "%s')", def->src);
}
} else {
if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) {
virBufferEscapeSexpr(buf, "(uname 'file:%s')", def->src);
} else if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
if (def->src[0] == '/')
virBufferEscapeSexpr(buf, "(uname 'phy:%s')", def->src);
else
virBufferEscapeSexpr(buf, "(uname 'phy:/dev/%s')",
def->src);
} else {
XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported disk type %s"),
virDomainDiskTypeToString(def->type));
return -1;
}
}
}
if (def->readonly)
virBufferAddLit(buf, "(mode 'r')");
else if (def->shared)
virBufferAddLit(buf, "(mode 'w!')");
else
virBufferAddLit(buf, "(mode 'w')");
if (!isAttach)
virBufferAddLit(buf, ")");
virBufferAddLit(buf, ")");
return 0;
}
/**
* xenDaemonFormatSxprNet
* @conn: pointer to the hypervisor connection
* @node: node containing the interface description
* @buf: a buffer for the result S-Expr
* @xendConfigVersion: xend configuration file format
*
* Parse the one interface the XML description and add it to the S-Expr in buf
* This is a temporary interface as the S-Expr interface
* will be replaced by XML-RPC in the future. However the XML format should
* stay valid over time.
*
* Returns 0 in case of success, -1 in case of error.
*/
int
xenDaemonFormatSxprNet(virConnectPtr conn,
virDomainNetDefPtr def,
virBufferPtr buf,
int hvm,
int xendConfigVersion,
int isAttach)
{
const char *script = DEFAULT_VIF_SCRIPT;
if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
def->type != VIR_DOMAIN_NET_TYPE_NETWORK &&
def->type != VIR_DOMAIN_NET_TYPE_ETHERNET) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("unsupported network type %d"), def->type);
return -1;
}
if (!isAttach)
virBufferAddLit(buf, "(device ");
virBufferAddLit(buf, "(vif ");
virBufferVSprintf(buf,
"(mac '%02x:%02x:%02x:%02x:%02x:%02x')",
def->mac[0], def->mac[1], def->mac[2],
def->mac[3], def->mac[4], def->mac[5]);
switch (def->type) {
case VIR_DOMAIN_NET_TYPE_BRIDGE:
virBufferEscapeSexpr(buf, "(bridge '%s')", def->data.bridge.brname);
if (def->data.bridge.script)
script = def->data.bridge.script;
virBufferEscapeSexpr(buf, "(script '%s')", script);
if (def->data.bridge.ipaddr != NULL)
virBufferEscapeSexpr(buf, "(ip '%s')", def->data.bridge.ipaddr);
break;
case VIR_DOMAIN_NET_TYPE_NETWORK:
{
virNetworkPtr network =
virNetworkLookupByName(conn, def->data.network.name);
char *bridge;
if (!network) {
XENXS_ERROR(VIR_ERR_NO_NETWORK, "%s",
def->data.network.name);
return -1;
}
bridge = virNetworkGetBridgeName(network);
virNetworkFree(network);
if (!bridge) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("network %s is not active"),
def->data.network.name);
return -1;
}
virBufferEscapeSexpr(buf, "(bridge '%s')", bridge);
virBufferEscapeSexpr(buf, "(script '%s')", script);
VIR_FREE(bridge);
}
break;
case VIR_DOMAIN_NET_TYPE_ETHERNET:
if (def->data.ethernet.script)
virBufferEscapeSexpr(buf, "(script '%s')",
def->data.ethernet.script);
if (def->data.ethernet.ipaddr != NULL)
virBufferEscapeSexpr(buf, "(ip '%s')", def->data.ethernet.ipaddr);
break;
case VIR_DOMAIN_NET_TYPE_USER:
case VIR_DOMAIN_NET_TYPE_SERVER:
case VIR_DOMAIN_NET_TYPE_CLIENT:
case VIR_DOMAIN_NET_TYPE_MCAST:
case VIR_DOMAIN_NET_TYPE_INTERNAL:
case VIR_DOMAIN_NET_TYPE_DIRECT:
case VIR_DOMAIN_NET_TYPE_LAST:
break;
}
if (def->ifname != NULL &&
!STRPREFIX(def->ifname, "vif"))
virBufferEscapeSexpr(buf, "(vifname '%s')", def->ifname);
if (!hvm) {
if (def->model != NULL)
virBufferEscapeSexpr(buf, "(model '%s')", def->model);
}
else if (def->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(def->model, "netfront")) {
virBufferAddLit(buf, "(type netfront)");
}
else {
virBufferEscapeSexpr(buf, "(model '%s')", def->model);
virBufferAddLit(buf, "(type ioemu)");
}
if (!isAttach)
virBufferAddLit(buf, ")");
virBufferAddLit(buf, ")");
return 0;
}
static void
xenDaemonFormatSxprPCI(virDomainHostdevDefPtr def,
virBufferPtr buf)
{
virBufferVSprintf(buf, "(dev (domain 0x%04x)(bus 0x%02x)(slot 0x%02x)(func 0x%x))",
def->source.subsys.u.pci.domain,
def->source.subsys.u.pci.bus,
def->source.subsys.u.pci.slot,
def->source.subsys.u.pci.function);
}
int
xenDaemonFormatSxprOnePCI(virDomainHostdevDefPtr def,
virBufferPtr buf,
int detach)
{
if (def->managed) {
XENXS_ERROR(VIR_ERR_NO_SUPPORT, "%s",
_("managed PCI devices not supported with XenD"));
return -1;
}
virBufferAddLit(buf, "(pci ");
xenDaemonFormatSxprPCI(def, buf);
if (detach)
virBufferAddLit(buf, "(state 'Closing')");
else
virBufferAddLit(buf, "(state 'Initialising')");
virBufferAddLit(buf, ")");
return 0;
}
static int
xenDaemonFormatSxprAllPCI(virDomainDefPtr def,
virBufferPtr buf)
{
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;
/*
* With the (domain ...) block we have the following odd setup
*
* (device
* (pci
* (dev (domain 0x0000) (bus 0x00) (slot 0x1b) (func 0x0))
* (dev (domain 0x0000) (bus 0x00) (slot 0x13) (func 0x0))
* )
* )
*
* Normally there is one (device ...) block per device, but in the
* weird world of Xen PCI, one (device ...) covers multiple devices.
*/
virBufferAddLit(buf, "(device (pci ");
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) {
if (def->hostdevs[i]->managed) {
XENXS_ERROR(VIR_ERR_NO_SUPPORT, "%s",
_("managed PCI devices not supported with XenD"));
return -1;
}
xenDaemonFormatSxprPCI(def->hostdevs[i], buf);
}
}
virBufferAddLit(buf, "))");
return 0;
}
int
xenDaemonFormatSxprSound(virDomainDefPtr def,
virBufferPtr buf)
{
const char *str;
int i;
for (i = 0 ; i < def->nsounds ; i++) {
if (!(str = virDomainSoundModelTypeToString(def->sounds[i]->model))) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("unexpected sound model %d"),
def->sounds[i]->model);
return -1;
}
if (i)
virBufferAddChar(buf, ',');
virBufferEscapeSexpr(buf, "%s", str);
}
if (virBufferError(buf)) {
virReportOOMError();
return -1;
}
return 0;
}
static int
xenDaemonFormatSxprInput(virDomainInputDefPtr input,
virBufferPtr buf)
{
if (input->bus != VIR_DOMAIN_INPUT_BUS_USB)
return 0;
if (input->type != VIR_DOMAIN_INPUT_TYPE_MOUSE &&
input->type != VIR_DOMAIN_INPUT_TYPE_TABLET) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("unexpected input type %d"), input->type);
return -1;
}
virBufferVSprintf(buf, "(usbdevice %s)",
input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ?
"mouse" : "tablet");
return 0;
}
/* 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);
/**
* xenDaemonFormatSxpr:
* @conn: pointer to the hypervisor connection
* @def: domain config definition
* @xendConfigVersion: xend configuration file format
*
* Generate an SEXPR representing the domain configuration.
*
* Returns the 0 terminated S-Expr string or NULL in case of error.
* the caller must free() the returned value.
*/
char *
xenDaemonFormatSxpr(virConnectPtr conn,
virDomainDefPtr def,
int xendConfigVersion)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
char uuidstr[VIR_UUID_STRING_BUFLEN];
const char *tmp;
char *bufout;
int hvm = 0, i;
VIR_DEBUG0("Formatting domain sexpr");
virBufferAddLit(&buf, "(vm ");
virBufferEscapeSexpr(&buf, "(name '%s')", def->name);
virBufferVSprintf(&buf, "(memory %lu)(maxmem %lu)",
VIR_DIV_UP(def->mem.cur_balloon, 1024),
VIR_DIV_UP(def->mem.max_balloon, 1024));
virBufferVSprintf(&buf, "(vcpus %u)", def->maxvcpus);
/* 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)
virBufferVSprintf(&buf, "(vcpu_avail %lu)", (1UL << def->vcpus) - 1);
if (def->cpumask) {
char *ranges = virDomainCpuSetFormat(def->cpumask, def->cpumasklen);
if (ranges == NULL)
goto error;
virBufferEscapeSexpr(&buf, "(cpus '%s')", ranges);
VIR_FREE(ranges);
}
virUUIDFormat(def->uuid, uuidstr);
virBufferVSprintf(&buf, "(uuid '%s')", uuidstr);
if (def->description)
virBufferEscapeSexpr(&buf, "(description '%s')", def->description);
if (def->os.bootloader) {
if (def->os.bootloader[0])
virBufferEscapeSexpr(&buf, "(bootloader '%s')", def->os.bootloader);
else
virBufferAddLit(&buf, "(bootloader)");
if (def->os.bootloaderArgs)
virBufferEscapeSexpr(&buf, "(bootloader_args '%s')", def->os.bootloaderArgs);
}
if (!(tmp = virDomainLifecycleTypeToString(def->onPoweroff))) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("unexpected lifecycle value %d"), def->onPoweroff);
goto error;
}
virBufferVSprintf(&buf, "(on_poweroff '%s')", tmp);
if (!(tmp = virDomainLifecycleTypeToString(def->onReboot))) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("unexpected lifecycle value %d"), def->onReboot);
goto error;
}
virBufferVSprintf(&buf, "(on_reboot '%s')", tmp);
if (!(tmp = virDomainLifecycleCrashTypeToString(def->onCrash))) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
_("unexpected lifecycle value %d"), def->onCrash);
goto error;
}
virBufferVSprintf(&buf, "(on_crash '%s')", tmp);
/* Set localtime here for current XenD (both PV & HVM) */
if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME) {
if (def->clock.data.timezone) {
XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
"%s", _("configurable timezones are not supported"));
goto error;
}
virBufferAddLit(&buf, "(localtime 1)");
} else if (def->clock.offset != VIR_DOMAIN_CLOCK_OFFSET_UTC) {
XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported clock offset '%s'"),
virDomainClockOffsetTypeToString(def->clock.offset));
goto error;
}
if (!def->os.bootloader) {
if (STREQ(def->os.type, "hvm"))
hvm = 1;
if (hvm)
virBufferAddLit(&buf, "(image (hvm ");
else
virBufferAddLit(&buf, "(image (linux ");
if (hvm &&
def->os.loader == NULL) {
XENXS_ERROR(VIR_ERR_INTERNAL_ERROR,
"%s",_("no HVM domain loader"));
goto error;
}
if (def->os.kernel)
virBufferEscapeSexpr(&buf, "(kernel '%s')", def->os.kernel);
if (def->os.initrd)
virBufferEscapeSexpr(&buf, "(ramdisk '%s')", def->os.initrd);
if (def->os.root)
virBufferEscapeSexpr(&buf, "(root '%s')", def->os.root);
if (def->os.cmdline)
virBufferEscapeSexpr(&buf, "(args '%s')", def->os.cmdline);
if (hvm) {
char bootorder[VIR_DOMAIN_BOOT_LAST+1];
if (def->os.kernel)
virBufferEscapeSexpr(&buf, "(loader '%s')", def->os.loader);
else
virBufferEscapeSexpr(&buf, "(kernel '%s')", def->os.loader);
virBufferVSprintf(&buf, "(vcpus %u)", def->maxvcpus);
if (def->vcpus < def->maxvcpus)
virBufferVSprintf(&buf, "(vcpu_avail %lu)",
(1UL << def->vcpus) - 1);
for (i = 0 ; i < def->os.nBootDevs ; i++) {
switch (def->os.bootDevs[i]) {
case VIR_DOMAIN_BOOT_FLOPPY:
bootorder[i] = 'a';
break;
default:
case VIR_DOMAIN_BOOT_DISK:
bootorder[i] = 'c';
break;
case VIR_DOMAIN_BOOT_CDROM:
bootorder[i] = 'd';
break;
case VIR_DOMAIN_BOOT_NET:
bootorder[i] = 'n';
break;
}
}
if (def->os.nBootDevs == 0) {
bootorder[0] = 'c';
bootorder[1] = '\0';
} else {
bootorder[def->os.nBootDevs] = '\0';
}
virBufferVSprintf(&buf, "(boot %s)", bootorder);
/* some disk devices are defined here */
for (i = 0 ; i < def->ndisks ; i++) {
switch (def->disks[i]->device) {
case VIR_DOMAIN_DISK_DEVICE_CDROM:
/* Only xend <= 3.0.2 wants cdrom config here */
if (xendConfigVersion != 1)
break;
if (!STREQ(def->disks[i]->dst, "hdc") ||
def->disks[i]->src == NULL)
break;
virBufferEscapeSexpr(&buf, "(cdrom '%s')",
def->disks[i]->src);
break;
case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
/* all xend versions define floppies here */
virBufferEscapeSexpr(&buf, "(%s ", def->disks[i]->dst);
virBufferEscapeSexpr(&buf, "'%s')", def->disks[i]->src);
break;
default:
break;
}
}
if (def->features & (1 << VIR_DOMAIN_FEATURE_ACPI))
virBufferAddLit(&buf, "(acpi 1)");
if (def->features & (1 << VIR_DOMAIN_FEATURE_APIC))
virBufferAddLit(&buf, "(apic 1)");
if (def->features & (1 << VIR_DOMAIN_FEATURE_PAE))
virBufferAddLit(&buf, "(pae 1)");
if (def->features & (1 << VIR_DOMAIN_FEATURE_HAP))
virBufferAddLit(&buf, "(hap 1)");
virBufferAddLit(&buf, "(usb 1)");
for (i = 0 ; i < def->ninputs ; i++)
if (xenDaemonFormatSxprInput(def->inputs[i], &buf) < 0)
goto error;
if (def->parallels) {
virBufferAddLit(&buf, "(parallel ");
if (xenDaemonFormatSxprChr(def->parallels[0], &buf) < 0)
goto error;
virBufferAddLit(&buf, ")");
} else {
virBufferAddLit(&buf, "(parallel none)");
}
if (def->serials) {
virBufferAddLit(&buf, "(serial ");
if (xenDaemonFormatSxprChr(def->serials[0], &buf) < 0)
goto error;
virBufferAddLit(&buf, ")");
} else {
virBufferAddLit(&buf, "(serial none)");
}
/* Set localtime here to keep old XenD happy for HVM */
if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME)
virBufferAddLit(&buf, "(localtime 1)");
if (def->sounds) {
virBufferAddLit(&buf, "(soundhw '");
if (xenDaemonFormatSxprSound(def, &buf) < 0)
goto error;
virBufferAddLit(&buf, "')");
}
}
/* get the device emulation model */
if (def->emulator && (hvm || xendConfigVersion >= 3))
virBufferEscapeSexpr(&buf, "(device_model '%s')", def->emulator);
/* PV graphics for xen <= 3.0.4, or HVM graphics for xen <= 3.1.0 */
if ((!hvm && xendConfigVersion < XEND_CONFIG_MIN_VERS_PVFB_NEWCONF) ||
(hvm && xendConfigVersion < 4)) {
if ((def->ngraphics == 1) &&
xenDaemonFormatSxprGraphicsOld(def->graphics[0],
&buf, xendConfigVersion) < 0)
goto error;
}
virBufferAddLit(&buf, "))");
}
for (i = 0 ; i < def->ndisks ; i++)
if (xenDaemonFormatSxprDisk(conn, def->disks[i],
&buf, hvm, xendConfigVersion, 0) < 0)
goto error;
for (i = 0 ; i < def->nnets ; i++)
if (xenDaemonFormatSxprNet(conn, def->nets[i],
&buf, hvm, xendConfigVersion, 0) < 0)
goto error;
if (xenDaemonFormatSxprAllPCI(def, &buf) < 0)
goto error;
/* New style PV graphics config xen >= 3.0.4,
* or HVM graphics config xen >= 3.0.5 */
if ((xendConfigVersion >= XEND_CONFIG_MIN_VERS_PVFB_NEWCONF && !hvm) ||
(xendConfigVersion >= 4 && hvm)) {
if ((def->ngraphics == 1) &&
xenDaemonFormatSxprGraphicsNew(def->graphics[0], &buf) < 0)
goto error;
}
virBufferAddLit(&buf, ")"); /* closes (vm */
if (virBufferError(&buf)) {
virReportOOMError();
goto error;
}
bufout = virBufferContentAndReset(&buf);
VIR_DEBUG("Formatted sexpr: \n%s", bufout);
return bufout;
error:
virBufferFreeAndReset(&buf);
return NULL;
}

View File

@ -59,4 +59,36 @@ virDomainChrDefPtr
xenDaemonParseSxprChar(const char *value,
const char *tty);
int
xenDaemonFormatSxprDisk(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainDiskDefPtr def,
virBufferPtr buf,
int hvm,
int xendConfigVersion,
int isAttach);
int
xenDaemonFormatSxprNet(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainNetDefPtr def,
virBufferPtr buf,
int hvm,
int xendConfigVersion,
int isAttach);
int
xenDaemonFormatSxprOnePCI(virDomainHostdevDefPtr def,
virBufferPtr buf,
int detach);
int
xenDaemonFormatSxprChr(virDomainChrDefPtr def,
virBufferPtr buf);
int
xenDaemonFormatSxprSound(virDomainDefPtr def,
virBufferPtr buf);
char *
xenDaemonFormatSxpr(virConnectPtr conn,
virDomainDefPtr def,
int xendConfigVersion);
#endif /* __VIR_XEN_SXPR_H__ */

View File

@ -27,6 +27,24 @@
# include "internal.h"
# include <stdint.h>
# include <xen/xen.h>
/* xen-unstable changeset 19788 removed MAX_VIRT_CPUS from public
* headers. Its semantic was retained with XEN_LEGACY_MAX_VCPUS.
* Ensure MAX_VIRT_CPUS is defined accordingly.
*/
# if !defined(MAX_VIRT_CPUS) && defined(XEN_LEGACY_MAX_VCPUS)
# define MAX_VIRT_CPUS XEN_LEGACY_MAX_VCPUS
# endif
# ifdef WITH_RHEL5_API
# define XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU 0
# define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 2
# else
# define XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU 3
# define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 3
# endif
# define VIR_FROM_THIS VIR_FROM_NONE

View File

@ -10,6 +10,7 @@
#include "internal.h"
#include "xen/xend_internal.h"
#include "xenxs/xen_sxpr.h"
#include "testutils.h"
#include "testutilsxen.h"