mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-11 09:17:52 +03:00
Moved SEXPR formatting functions to xenxs
This commit is contained in:
parent
07129039cc
commit
2f2a88b998
@ -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:
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -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
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "internal.h"
|
||||
#include "xen/xend_internal.h"
|
||||
#include "xenxs/xen_sxpr.h"
|
||||
#include "testutils.h"
|
||||
#include "testutilsxen.h"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user