mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-10-14 10:09:22 +00:00
516 lines
15 KiB
C
516 lines
15 KiB
C
|
/*
|
||
|
* xen_xl.c: Xen XL parsing functions
|
||
|
*
|
||
|
* Copyright (c) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany.
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 2.1 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public
|
||
|
* License along with this library. If not, see
|
||
|
* <http://www.gnu.org/licenses/>.
|
||
|
*
|
||
|
* Author: Kiarie Kahurani <davidkiarie4@gmail.com>
|
||
|
* Author: Jim Fehlig <jfehlig@suse.com>
|
||
|
*/
|
||
|
|
||
|
#include <config.h>
|
||
|
|
||
|
#include <libxl.h>
|
||
|
|
||
|
#include "virconf.h"
|
||
|
#include "virerror.h"
|
||
|
#include "domain_conf.h"
|
||
|
#include "viralloc.h"
|
||
|
#include "virstring.h"
|
||
|
#include "virstoragefile.h"
|
||
|
#include "xen_xl.h"
|
||
|
|
||
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
||
|
|
||
|
/*
|
||
|
* Xen provides a libxl utility library, with several useful functions,
|
||
|
* specifically xlu_disk_parse for parsing xl disk config strings.
|
||
|
* Although the libxlutil library is installed, until recently the
|
||
|
* corresponding header file wasn't. Use the header file if detected during
|
||
|
* configure, otherwise provide extern declarations for any functions used.
|
||
|
*/
|
||
|
#ifdef HAVE_LIBXLUTIL_H
|
||
|
# include <libxlutil.h>
|
||
|
#else
|
||
|
typedef struct XLU_Config XLU_Config;
|
||
|
|
||
|
extern XLU_Config *xlu_cfg_init(FILE *report,
|
||
|
const char *report_filename);
|
||
|
|
||
|
extern void xlu_cfg_destroy(XLU_Config*);
|
||
|
|
||
|
extern int xlu_disk_parse(XLU_Config *cfg,
|
||
|
int nspecs,
|
||
|
const char *const *specs,
|
||
|
libxl_device_disk *disk);
|
||
|
#endif
|
||
|
|
||
|
static int
|
||
|
xenParseXLSpice(virConfPtr conf, virDomainDefPtr def)
|
||
|
{
|
||
|
virDomainGraphicsDefPtr graphics = NULL;
|
||
|
unsigned long port;
|
||
|
char *listenAddr = NULL;
|
||
|
int val;
|
||
|
|
||
|
if (STREQ(def->os.type, "hvm")) {
|
||
|
if (xenConfigGetBool(conf, "spice", &val, 0) < 0)
|
||
|
return -1;
|
||
|
|
||
|
if (val) {
|
||
|
if (VIR_ALLOC(graphics) < 0)
|
||
|
return -1;
|
||
|
|
||
|
graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SPICE;
|
||
|
if (xenConfigCopyStringOpt(conf, "spicehost", &listenAddr) < 0)
|
||
|
goto cleanup;
|
||
|
if (listenAddr &&
|
||
|
virDomainGraphicsListenSetAddress(graphics, 0, listenAddr,
|
||
|
-1, true) < 0) {
|
||
|
goto cleanup;
|
||
|
}
|
||
|
VIR_FREE(listenAddr);
|
||
|
|
||
|
if (xenConfigGetULong(conf, "spicetls_port", &port, 0) < 0)
|
||
|
goto cleanup;
|
||
|
graphics->data.spice.tlsPort = (int)port;
|
||
|
|
||
|
if (xenConfigGetULong(conf, "spiceport", &port, 0) < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
graphics->data.spice.port = (int)port;
|
||
|
|
||
|
if (!graphics->data.spice.tlsPort &&
|
||
|
!graphics->data.spice.port)
|
||
|
graphics->data.spice.autoport = 1;
|
||
|
|
||
|
if (xenConfigGetBool(conf, "spicedisable_ticketing", &val, 0) < 0)
|
||
|
goto cleanup;
|
||
|
if (val) {
|
||
|
if (xenConfigCopyStringOpt(conf, "spicepasswd",
|
||
|
&graphics->data.spice.auth.passwd) < 0)
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
if (xenConfigGetBool(conf, "spiceagent_mouse",
|
||
|
&graphics->data.spice.mousemode, 0) < 0)
|
||
|
goto cleanup;
|
||
|
if (xenConfigGetBool(conf, "spicedvagent", &val, 0) < 0)
|
||
|
goto cleanup;
|
||
|
if (val) {
|
||
|
if (xenConfigGetBool(conf, "spice_clipboard_sharing",
|
||
|
&graphics->data.spice.copypaste,
|
||
|
0) < 0)
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
if (VIR_ALLOC_N(def->graphics, 1) < 0)
|
||
|
goto cleanup;
|
||
|
def->graphics[0] = graphics;
|
||
|
def->ngraphics = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
cleanup:
|
||
|
virDomainGraphicsDefFree(graphics);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* For details on xl disk config syntax, see
|
||
|
* docs/misc/xl-disk-configuration.txt in the Xen sources. The important
|
||
|
* section of text is:
|
||
|
*
|
||
|
* More formally, the string is a series of comma-separated keyword/value
|
||
|
* pairs, flags and positional parameters. Parameters which are not bare
|
||
|
* keywords and which do not contain "=" symbols are assigned to the
|
||
|
* so-far-unspecified positional parameters, in the order below. The
|
||
|
* positional parameters may also be specified explicitly by name.
|
||
|
*
|
||
|
* Each parameter may be specified at most once, either as a positional
|
||
|
* parameter or a named parameter. Default values apply if the parameter
|
||
|
* is not specified, or if it is specified with an empty value (whether
|
||
|
* positionally or explicitly).
|
||
|
*
|
||
|
* Whitespace may appear before each parameter and will be ignored.
|
||
|
*
|
||
|
* The order of the positional parameters mentioned in the quoted text is:
|
||
|
*
|
||
|
* target,format,vdev,access
|
||
|
*
|
||
|
* The following options must be specified by key=value:
|
||
|
*
|
||
|
* devtype=<devtype>
|
||
|
* backendtype=<backend-type>
|
||
|
*
|
||
|
* The following options are currently not supported:
|
||
|
*
|
||
|
* backend=<domain-name>
|
||
|
* script=<script>
|
||
|
* direct-io-safe
|
||
|
*
|
||
|
*/
|
||
|
static int
|
||
|
xenParseXLDisk(virConfPtr conf, virDomainDefPtr def)
|
||
|
{
|
||
|
int ret = -1;
|
||
|
virConfValuePtr list = virConfGetValue(conf, "disk");
|
||
|
XLU_Config *xluconf;
|
||
|
libxl_device_disk *libxldisk;
|
||
|
virDomainDiskDefPtr disk = NULL;
|
||
|
|
||
|
if (VIR_ALLOC(libxldisk) < 0)
|
||
|
return -1;
|
||
|
|
||
|
if (!(xluconf = xlu_cfg_init(stderr, "command line")))
|
||
|
goto cleanup;
|
||
|
|
||
|
if (list && list->type == VIR_CONF_LIST) {
|
||
|
list = list->list;
|
||
|
while (list) {
|
||
|
const char *disk_spec = list->str;
|
||
|
|
||
|
if (list->type != VIR_CONF_STRING || list->str == NULL)
|
||
|
goto skipdisk;
|
||
|
|
||
|
libxl_device_disk_init(libxldisk);
|
||
|
|
||
|
if (xlu_disk_parse(xluconf, 1, &disk_spec, libxldisk))
|
||
|
goto fail;
|
||
|
|
||
|
if (!(disk = virDomainDiskDefNew()))
|
||
|
goto fail;
|
||
|
|
||
|
if (VIR_STRDUP(disk->dst, libxldisk->vdev) < 0)
|
||
|
goto fail;
|
||
|
|
||
|
if (virDomainDiskSetSource(disk, libxldisk->pdev_path) < 0)
|
||
|
goto fail;
|
||
|
|
||
|
disk->src->readonly = !libxldisk->readwrite;
|
||
|
disk->removable = libxldisk->removable;
|
||
|
|
||
|
if (libxldisk->is_cdrom) {
|
||
|
if (virDomainDiskSetDriver(disk, "qemu") < 0)
|
||
|
goto fail;
|
||
|
|
||
|
virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
|
||
|
disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
|
||
|
if (!disk->src->path || STREQ(disk->src->path, ""))
|
||
|
disk->src->format = VIR_STORAGE_FILE_NONE;
|
||
|
else
|
||
|
disk->src->format = VIR_STORAGE_FILE_RAW;
|
||
|
} else {
|
||
|
switch (libxldisk->format) {
|
||
|
case LIBXL_DISK_FORMAT_QCOW:
|
||
|
disk->src->format = VIR_STORAGE_FILE_QCOW;
|
||
|
break;
|
||
|
|
||
|
case LIBXL_DISK_FORMAT_QCOW2:
|
||
|
disk->src->format = VIR_STORAGE_FILE_QCOW2;
|
||
|
break;
|
||
|
|
||
|
case LIBXL_DISK_FORMAT_VHD:
|
||
|
disk->src->format = VIR_STORAGE_FILE_VHD;
|
||
|
break;
|
||
|
|
||
|
case LIBXL_DISK_FORMAT_RAW:
|
||
|
case LIBXL_DISK_FORMAT_UNKNOWN:
|
||
|
disk->src->format = VIR_STORAGE_FILE_RAW;
|
||
|
break;
|
||
|
|
||
|
case LIBXL_DISK_FORMAT_EMPTY:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (libxldisk->backend) {
|
||
|
case LIBXL_DISK_BACKEND_QDISK:
|
||
|
case LIBXL_DISK_BACKEND_UNKNOWN:
|
||
|
if (virDomainDiskSetDriver(disk, "qemu") < 0)
|
||
|
goto fail;
|
||
|
virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
|
||
|
break;
|
||
|
|
||
|
case LIBXL_DISK_BACKEND_TAP:
|
||
|
if (virDomainDiskSetDriver(disk, "tap") < 0)
|
||
|
goto fail;
|
||
|
virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
|
||
|
break;
|
||
|
|
||
|
case LIBXL_DISK_BACKEND_PHY:
|
||
|
if (virDomainDiskSetDriver(disk, "phy") < 0)
|
||
|
goto fail;
|
||
|
virDomainDiskSetType(disk, VIR_STORAGE_TYPE_BLOCK);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (STRPREFIX(libxldisk->vdev, "xvd") || !STREQ(def->os.type, "hvm"))
|
||
|
disk->bus = VIR_DOMAIN_DISK_BUS_XEN;
|
||
|
else if (STRPREFIX(libxldisk->vdev, "sd"))
|
||
|
disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
|
||
|
else
|
||
|
disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
|
||
|
|
||
|
if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0)
|
||
|
goto fail;
|
||
|
|
||
|
libxl_device_disk_dispose(libxldisk);
|
||
|
|
||
|
skipdisk:
|
||
|
list = list->next;
|
||
|
}
|
||
|
}
|
||
|
ret = 0;
|
||
|
|
||
|
cleanup:
|
||
|
virDomainDiskDefFree(disk);
|
||
|
xlu_cfg_destroy(xluconf);
|
||
|
VIR_FREE(libxldisk);
|
||
|
return ret;
|
||
|
|
||
|
fail:
|
||
|
libxl_device_disk_dispose(libxldisk);
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
|
||
|
virDomainDefPtr
|
||
|
xenParseXL(virConfPtr conf, virCapsPtr caps, int xendConfigVersion)
|
||
|
{
|
||
|
virDomainDefPtr def = NULL;
|
||
|
|
||
|
if (VIR_ALLOC(def) < 0)
|
||
|
return NULL;
|
||
|
|
||
|
def->virtType = VIR_DOMAIN_VIRT_XEN;
|
||
|
def->id = -1;
|
||
|
|
||
|
if (xenParseConfigCommon(conf, def, caps, xendConfigVersion) < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
if (xenParseXLDisk(conf, def) < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
if (xenParseXLSpice(conf, def) < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
return def;
|
||
|
|
||
|
cleanup:
|
||
|
virDomainDefFree(def);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int
|
||
|
xenFormatXLDisk(virConfValuePtr list, virDomainDiskDefPtr disk)
|
||
|
{
|
||
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||
|
virConfValuePtr val, tmp;
|
||
|
const char *src = virDomainDiskGetSource(disk);
|
||
|
int format = virDomainDiskGetFormat(disk);
|
||
|
const char *driver = virDomainDiskGetDriver(disk);
|
||
|
|
||
|
/* target */
|
||
|
virBufferAsprintf(&buf, "%s,", src);
|
||
|
/* format */
|
||
|
switch (format) {
|
||
|
case VIR_STORAGE_FILE_RAW:
|
||
|
virBufferAddLit(&buf, "raw,");
|
||
|
break;
|
||
|
case VIR_STORAGE_FILE_VHD:
|
||
|
virBufferAddLit(&buf, "xvhd,");
|
||
|
break;
|
||
|
case VIR_STORAGE_FILE_QCOW:
|
||
|
virBufferAddLit(&buf, "qcow,");
|
||
|
break;
|
||
|
case VIR_STORAGE_FILE_QCOW2:
|
||
|
virBufferAddLit(&buf, "qcow2,");
|
||
|
break;
|
||
|
/* set default */
|
||
|
default:
|
||
|
virBufferAddLit(&buf, "raw,");
|
||
|
}
|
||
|
|
||
|
/* device */
|
||
|
virBufferAdd(&buf, disk->dst, -1);
|
||
|
|
||
|
virBufferAddLit(&buf, ",");
|
||
|
|
||
|
if (disk->src->readonly)
|
||
|
virBufferAddLit(&buf, "r,");
|
||
|
else if (disk->src->shared)
|
||
|
virBufferAddLit(&buf, "!,");
|
||
|
else
|
||
|
virBufferAddLit(&buf, "w,");
|
||
|
if (disk->transient) {
|
||
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||
|
_("transient disks not supported yet"));
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
if (STREQ_NULLABLE(driver, "qemu"))
|
||
|
virBufferAddLit(&buf, "backendtype=qdisk");
|
||
|
else if (STREQ_NULLABLE(driver, "tap"))
|
||
|
virBufferAddLit(&buf, "backendtype=tap");
|
||
|
else if (STREQ_NULLABLE(driver, "phy"))
|
||
|
virBufferAddLit(&buf, "backendtype=phy");
|
||
|
|
||
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
|
||
|
virBufferAddLit(&buf, ",devtype=cdrom");
|
||
|
|
||
|
if (virBufferCheckError(&buf) < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
if (VIR_ALLOC(val) < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
val->type = VIR_CONF_STRING;
|
||
|
val->str = virBufferContentAndReset(&buf);
|
||
|
tmp = list->list;
|
||
|
while (tmp && tmp->next)
|
||
|
tmp = tmp->next;
|
||
|
if (tmp)
|
||
|
tmp->next = val;
|
||
|
else
|
||
|
list->list = val;
|
||
|
return 0;
|
||
|
|
||
|
cleanup:
|
||
|
virBufferFreeAndReset(&buf);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int
|
||
|
xenFormatXLDomainDisks(virConfPtr conf, virDomainDefPtr def)
|
||
|
{
|
||
|
int ret = -1;
|
||
|
virConfValuePtr diskVal;
|
||
|
size_t i;
|
||
|
|
||
|
if (VIR_ALLOC(diskVal) < 0)
|
||
|
return -1;
|
||
|
|
||
|
diskVal->type = VIR_CONF_LIST;
|
||
|
diskVal->list = NULL;
|
||
|
|
||
|
for (i = 0; i < def->ndisks; i++) {
|
||
|
if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
|
||
|
continue;
|
||
|
|
||
|
if (xenFormatXLDisk(diskVal, def->disks[i]) < 0)
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
if (diskVal->list != NULL)
|
||
|
if (virConfSetValue(conf, "disk", diskVal) == 0)
|
||
|
diskVal = NULL;
|
||
|
|
||
|
ret = 0;
|
||
|
|
||
|
cleanup:
|
||
|
virConfFreeValue(diskVal);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int
|
||
|
xenFormatXLSpice(virConfPtr conf, virDomainDefPtr def)
|
||
|
{
|
||
|
const char *listenAddr = NULL;
|
||
|
|
||
|
if (STREQ(def->os.type, "hvm")) {
|
||
|
if (def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
|
||
|
/* set others to false but may not be necessary */
|
||
|
if (xenConfigSetInt(conf, "sdl", 0) < 0)
|
||
|
return -1;
|
||
|
|
||
|
if (xenConfigSetInt(conf, "vnc", 0) < 0)
|
||
|
return -1;
|
||
|
|
||
|
if (xenConfigSetInt(conf, "spice", 1) < 0)
|
||
|
return -1;
|
||
|
|
||
|
if (xenConfigSetInt(conf, "spiceport",
|
||
|
def->graphics[0]->data.spice.port) < 0)
|
||
|
return -1;
|
||
|
|
||
|
if (xenConfigSetInt(conf, "spicetls_port",
|
||
|
def->graphics[0]->data.spice.tlsPort) < 0)
|
||
|
return -1;
|
||
|
|
||
|
if (def->graphics[0]->data.spice.auth.passwd) {
|
||
|
if (xenConfigSetInt(conf, "spicedisable_ticketing", 1) < 0)
|
||
|
return -1;
|
||
|
|
||
|
if (def->graphics[0]->data.spice.auth.passwd &&
|
||
|
xenConfigSetString(conf, "spicepasswd",
|
||
|
def->graphics[0]->data.spice.auth.passwd) < 0)
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
listenAddr = virDomainGraphicsListenGetAddress(def->graphics[0], 0);
|
||
|
if (listenAddr &&
|
||
|
xenConfigSetString(conf, "spicehost", listenAddr) < 0)
|
||
|
return -1;
|
||
|
|
||
|
if (xenConfigSetInt(conf, "spiceagent_mouse",
|
||
|
def->graphics[0]->data.spice.mousemode) < 0)
|
||
|
return -1;
|
||
|
|
||
|
if (def->graphics[0]->data.spice.copypaste) {
|
||
|
if (xenConfigSetInt(conf, "spicedvagent", 1) < 0)
|
||
|
return -1;
|
||
|
if (xenConfigSetInt(conf, "spice_clipboard_sharing",
|
||
|
def->graphics[0]->data.spice.copypaste) < 0)
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
virConfPtr
|
||
|
xenFormatXL(virDomainDefPtr def, virConnectPtr conn, int xendConfigVersion)
|
||
|
{
|
||
|
virConfPtr conf = NULL;
|
||
|
|
||
|
if (!(conf = virConfNew()))
|
||
|
goto cleanup;
|
||
|
|
||
|
if (xenFormatConfigCommon(conf, def, conn, xendConfigVersion) < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
if (xenFormatXLDomainDisks(conf, def) < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
if (xenFormatXLSpice(conf, def) < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
return conf;
|
||
|
|
||
|
cleanup:
|
||
|
if (conf)
|
||
|
virConfFree(conf);
|
||
|
return NULL;
|
||
|
}
|