Introduce support for parsing/formatting Xen xl config format

Introduce a parser/formatter for the xl config format.  Since the
deprecation of xm/xend, the VM config file format has diverged as
new features are added to libxl.  This patch adds support for parsing
and formating the xl config format.  It supports the existing xm config
format, plus adds support for spice graphics and xl disk config syntax.

Disk config is specified a bit differently in xl as compared to xm.  In
xl, disk config consists of comma-separated positional parameters and
keyword/value pairs separated by commas. Positional parameters are
specified as follows

   target, format, vdev, access

Supported keys for key=value options are

  devtype, backendtype

The positional paramters can also be specified in key/value form.  For
example the following xl disk config are equivalent

    /dev/vg/guest-volume,,hda
    /dev/vg/guest-volume,raw,hda,rw
    format=raw, vdev=hda, access=rw, target=/dev/vg/guest-volume

See $xen_sources/docs/misc/xl-disk-configuration.txt for more details.

xl disk config is parsed with the help of xlu_disk_parse() from
libxlutil, libxl's utility library.  Although the library exists
in all Xen versions supported by the libxl virt driver, only
recently has the corresponding header file been included.  A check
for the header is done in configure.ac.  If not found, xlu_disk_parse()
is declared externally.

Signed-off-by: Kiarie Kahurani <davidkiarie4@gmail.com>
Signed-off-by: Jim Fehlig <jfehlig@suse.com>
This commit is contained in:
Jim Fehlig 2015-01-09 17:12:52 -07:00
parent ce745914b3
commit 4689cdf779
7 changed files with 579 additions and 1 deletions

View File

@ -891,6 +891,9 @@ if test $fail = 1; then
fi
if test "$with_libxl" = "yes"; then
dnl If building with libxl, use the libxl utility header and lib too
AC_CHECK_HEADERS([libxlutil.h])
LIBXL_LIBS="$LIBXL_LIBS -lxlutil"
AC_DEFINE_UNQUOTED([WITH_LIBXL], 1, [whether libxenlight driver is enabled])
fi
AM_CONDITIONAL([WITH_LIBXL], [test "$with_libxl" = "yes"])

View File

@ -247,6 +247,7 @@ src/xenapi/xenapi_driver.c
src/xenapi/xenapi_utils.c
src/xenconfig/xen_common.c
src/xenconfig/xen_sxpr.c
src/xenconfig/xen_xl.c
src/xenconfig/xen_xm.c
tests/virpolkittest.c
tools/libvirt-guests.sh.in

View File

@ -1005,6 +1005,10 @@ XENCONFIG_SOURCES = \
xenconfig/xen_common.c xenconfig/xen_common.h \
xenconfig/xen_sxpr.c xenconfig/xen_sxpr.h \
xenconfig/xen_xm.c xenconfig/xen_xm.h
if WITH_LIBXL
XENCONFIG_SOURCES += \
xenconfig/xen_xl.c xenconfig/xen_xl.h
endif WITH_LIBXL
pkgdata_DATA = cpu/cpu_map.xml
@ -1061,6 +1065,7 @@ endif WITH_VMX
if WITH_XENCONFIG
noinst_LTLIBRARIES += libvirt_xenconfig.la
libvirt_la_BUILT_LIBADD += libvirt_xenconfig.la
libvirt_la_LIBADD += $(LIBXL_LIBS)
libvirt_xenconfig_la_CFLAGS = \
-I$(srcdir)/conf $(AM_CFLAGS)
libvirt_xenconfig_la_SOURCES = $(XENCONFIG_SOURCES)
@ -1979,6 +1984,12 @@ else ! WITH_XENCONFIG
SYM_FILES += $(srcdir)/libvirt_xenconfig.syms
endif ! WITH_XENCONFIG
if WITH_LIBXL
USED_SYM_FILES += $(srcdir)/libvirt_xenxlconfig.syms
else ! WITH_LIBXL
SYM_FILES += $(srcdir)/libvirt_xenxlconfig.syms
endif ! WITH_LIBXL
if WITH_SASL
USED_SYM_FILES += $(srcdir)/libvirt_sasl.syms
else ! WITH_SASL

View File

@ -0,0 +1,12 @@
#
# These symbols are dependent upon --with-libxl via WITH_LIBXL.
#
#xenconfig/xen_xl.h
xenFormatXL;
xenParseXL;
# Let emacs know we want case-insensitive sorting
# Local Variables:
# sort-fold-case: t
# End:

View File

@ -1812,7 +1812,8 @@ xenFormatVfb(virConfPtr conf, virDomainDefPtr def, int xendConfigVersion)
{
int hvm = STREQ(def->os.type, "hvm") ? 1 : 0;
if (def->ngraphics == 1) {
if (def->ngraphics == 1 &&
def->graphics[0]->type != VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
if (hvm || (xendConfigVersion < XEND_CONFIG_MIN_VERS_PVFB_NEWCONF)) {
if (def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
if (xenConfigSetInt(conf, "sdl", 1) < 0)

515
src/xenconfig/xen_xl.c Normal file
View File

@ -0,0 +1,515 @@
/*
* 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;
}

35
src/xenconfig/xen_xl.h Normal file
View File

@ -0,0 +1,35 @@
/*
* xen_xl.h: 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>
*/
#ifndef __VIR_XEN_XL_H__
# define __VIR_XEN_XL_H__
# include "virconf.h"
# include "domain_conf.h"
# include "xen_common.h"
virDomainDefPtr xenParseXL(virConfPtr conn, virCapsPtr caps,
int xendConfigVersion);
virConfPtr xenFormatXL(virDomainDefPtr def,
virConnectPtr, int xendConfigVersion);
#endif /* __VIR_XEN_XL_H__ */