From 2f2a88b9983384789c5f8be35a60ef425e3cf685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gro=C3=9F?= Date: Mon, 21 Feb 2011 14:40:09 +0100 Subject: [PATCH] Moved SEXPR formatting functions to xenxs --- src/xen/xend_internal.c | 875 -------------------------------------- src/xen/xend_internal.h | 12 - src/xenxs/xen_sxpr.c | 850 +++++++++++++++++++++++++++++++++++- src/xenxs/xen_sxpr.h | 32 ++ src/xenxs/xenxs_private.h | 18 + tests/xml2sexprtest.c | 1 + 6 files changed, 900 insertions(+), 888 deletions(-) diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 466c749ce8..9b228c4339 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -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: diff --git a/src/xen/xend_internal.h b/src/xen/xend_internal.h index 8603a082ff..c90c57268e 100644 --- a/src/xen/xend_internal.h +++ b/src/xen/xend_internal.h @@ -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); diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c index edd0fb41b9..d0b28c9281 100644 --- a/src/xenxs/xen_sxpr.c +++ b/src/xenxs/xen_sxpr.c @@ -1348,4 +1348,852 @@ xenDaemonParseSxprString(const char *sexpr, sexpr_free(root); return def; -} \ No newline at end of file +} + +/************************************************************************ + * * + * 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; +} diff --git a/src/xenxs/xen_sxpr.h b/src/xenxs/xen_sxpr.h index c0c6a53b51..0861c4bf7b 100644 --- a/src/xenxs/xen_sxpr.h +++ b/src/xenxs/xen_sxpr.h @@ -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__ */ diff --git a/src/xenxs/xenxs_private.h b/src/xenxs/xenxs_private.h index 1acabfbcd8..cb69805724 100644 --- a/src/xenxs/xenxs_private.h +++ b/src/xenxs/xenxs_private.h @@ -27,6 +27,24 @@ # include "internal.h" +# include +# include + +/* 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 diff --git a/tests/xml2sexprtest.c b/tests/xml2sexprtest.c index 8a5d115cb8..05fc676e09 100644 --- a/tests/xml2sexprtest.c +++ b/tests/xml2sexprtest.c @@ -10,6 +10,7 @@ #include "internal.h" #include "xen/xend_internal.h" +#include "xenxs/xen_sxpr.h" #include "testutils.h" #include "testutilsxen.h"