2014-08-15 20:52:15 -06:00
|
|
|
/*
|
|
|
|
* xen_common.c: Parsing and formatting functions for config common
|
|
|
|
* between XM and XL
|
|
|
|
*
|
|
|
|
* Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
|
2016-04-06 09:46:49 -04:00
|
|
|
* Copyright (C) 2006-2007, 2009-2016 Red Hat, Inc.
|
2014-08-15 20:52:15 -06:00
|
|
|
* Copyright (C) 2011 Univention GmbH
|
|
|
|
* Copyright (C) 2006 Daniel P. Berrange
|
|
|
|
*
|
|
|
|
* 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/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "internal.h"
|
|
|
|
#include "virerror.h"
|
|
|
|
#include "virconf.h"
|
|
|
|
#include "viralloc.h"
|
|
|
|
#include "viruuid.h"
|
|
|
|
#include "xenxs_private.h"
|
|
|
|
#include "domain_conf.h"
|
|
|
|
#include "virstring.h"
|
|
|
|
#include "xen_common.h"
|
|
|
|
|
2016-01-20 11:36:26 -07:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_XEN
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Convenience method to grab a long int from the config file object
|
|
|
|
*/
|
2014-09-11 07:10:32 +03:00
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenConfigGetBool(virConf *conf,
|
2014-08-15 20:52:15 -06:00
|
|
|
const char *name,
|
|
|
|
int *value,
|
|
|
|
int def)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virConfValue *val;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
*value = 0;
|
|
|
|
if (!(val = virConfGetValue(conf, name))) {
|
|
|
|
*value = def;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-07-15 17:36:32 +02:00
|
|
|
if (val->type == VIR_CONF_ULLONG) {
|
2014-08-15 20:52:15 -06:00
|
|
|
*value = val->l ? 1 : 0;
|
|
|
|
} else if (val->type == VIR_CONF_STRING) {
|
|
|
|
*value = STREQ(val->str, "1") ? 1 : 0;
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("config value %s was malformed"), name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convenience method to grab a int from the config file object
|
|
|
|
*/
|
2014-09-11 07:10:32 +03:00
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenConfigGetULong(virConf *conf,
|
2014-08-15 20:52:15 -06:00
|
|
|
const char *name,
|
|
|
|
unsigned long *value,
|
|
|
|
unsigned long def)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virConfValue *val;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
*value = 0;
|
|
|
|
if (!(val = virConfGetValue(conf, name))) {
|
|
|
|
*value = def;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-07-15 17:36:32 +02:00
|
|
|
if (val->type == VIR_CONF_ULLONG) {
|
2014-08-15 20:52:15 -06:00
|
|
|
*value = val->l;
|
|
|
|
} else if (val->type == VIR_CONF_STRING) {
|
|
|
|
if (virStrToLong_ul(val->str, NULL, 10, value) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("config value %s was malformed"), name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("config value %s was malformed"), name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convenience method to grab a int from the config file object
|
|
|
|
*/
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenConfigGetULongLong(virConf *conf,
|
2014-08-15 20:52:15 -06:00
|
|
|
const char *name,
|
|
|
|
unsigned long long *value,
|
|
|
|
unsigned long long def)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virConfValue *val;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
*value = 0;
|
|
|
|
if (!(val = virConfGetValue(conf, name))) {
|
|
|
|
*value = def;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-07-15 17:36:32 +02:00
|
|
|
if (val->type == VIR_CONF_ULLONG) {
|
2014-08-15 20:52:15 -06:00
|
|
|
*value = val->l;
|
|
|
|
} else if (val->type == VIR_CONF_STRING) {
|
|
|
|
if (virStrToLong_ull(val->str, NULL, 10, value) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("config value %s was malformed"), name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("config value %s was malformed"), name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenConfigCopyStringInternal(virConf *conf,
|
2014-08-15 20:52:15 -06:00
|
|
|
const char *name,
|
|
|
|
char **value,
|
|
|
|
int allowMissing)
|
|
|
|
{
|
2018-09-20 15:28:47 +02:00
|
|
|
int rc;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
*value = NULL;
|
2018-09-20 15:28:47 +02:00
|
|
|
if ((rc = virConfGetValueString(conf, name, value)) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2018-09-20 15:28:47 +02:00
|
|
|
if (rc == 0) {
|
2014-08-15 20:52:15 -06:00
|
|
|
if (allowMissing)
|
|
|
|
return 0;
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("config value %s was missing"), name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-09-20 15:28:47 +02:00
|
|
|
return 1;
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-19 17:29:38 -06:00
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenConfigCopyString(virConf *conf, const char *name, char **value)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
|
|
|
return xenConfigCopyStringInternal(conf, name, value, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-11 07:10:32 +03:00
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenConfigCopyStringOpt(virConf *conf, const char *name, char **value)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
|
|
|
return xenConfigCopyStringInternal(conf, name, value, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convenience method to grab a string UUID from the config file object
|
|
|
|
*/
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenConfigGetUUID(virConf *conf, const char *name, unsigned char *uuid)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2019-10-15 15:16:31 +02:00
|
|
|
g_autofree char *string = NULL;
|
2018-09-20 15:28:48 +02:00
|
|
|
int rc;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
if (!uuid || !name || !conf) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("Arguments must be non null"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-09-20 15:28:48 +02:00
|
|
|
|
|
|
|
if ((rc = virConfGetValueString(conf, name, &string)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (rc == 0) {
|
2018-04-09 16:30:10 -04:00
|
|
|
if (virUUIDGenerate(uuid) < 0) {
|
2014-08-15 20:52:15 -06:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("Failed to generate UUID"));
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-20 15:28:48 +02:00
|
|
|
if (!string) {
|
2014-08-15 20:52:15 -06:00
|
|
|
virReportError(VIR_ERR_CONF_SYNTAX,
|
|
|
|
_("%s can't be empty"), name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-09-20 15:28:48 +02:00
|
|
|
if (virUUIDParse(string, uuid) < 0) {
|
2014-08-15 20:52:15 -06:00
|
|
|
virReportError(VIR_ERR_CONF_SYNTAX,
|
2018-09-20 15:28:48 +02:00
|
|
|
_("%s not parseable"), string);
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convenience method to grab a string from the config file object
|
|
|
|
*/
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenConfigGetString(virConf *conf,
|
2014-08-15 20:52:15 -06:00
|
|
|
const char *name,
|
2018-09-20 15:28:49 +02:00
|
|
|
char **value,
|
2014-08-15 20:52:15 -06:00
|
|
|
const char *def)
|
|
|
|
{
|
2018-09-20 15:28:49 +02:00
|
|
|
char *string = NULL;
|
|
|
|
int rc;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
*value = NULL;
|
2018-09-20 15:28:49 +02:00
|
|
|
if ((rc = virConfGetValueString(conf, name, &string)) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
2018-09-20 15:28:49 +02:00
|
|
|
|
|
|
|
if (rc == 0 || !string) {
|
2019-10-20 13:49:46 +02:00
|
|
|
*value = g_strdup(def);
|
2018-09-20 15:28:49 +02:00
|
|
|
} else {
|
|
|
|
*value = string;
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
2018-09-20 15:28:49 +02:00
|
|
|
|
2014-08-15 20:52:15 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-11 07:10:32 +03:00
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenConfigSetInt(virConf *conf, const char *setting, long long l)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virConfValue *value = NULL;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2018-04-25 14:42:34 +02:00
|
|
|
if ((long)l != l) {
|
2014-08-15 20:52:15 -06:00
|
|
|
virReportError(VIR_ERR_OVERFLOW, _("failed to store %lld to %s"),
|
|
|
|
l, setting);
|
|
|
|
return -1;
|
|
|
|
}
|
2020-09-23 20:43:09 +02:00
|
|
|
value = g_new0(virConfValue, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2016-07-15 17:36:32 +02:00
|
|
|
value->type = VIR_CONF_LLONG;
|
2014-08-15 20:52:15 -06:00
|
|
|
value->next = NULL;
|
|
|
|
value->l = l;
|
|
|
|
|
|
|
|
return virConfSetValue(conf, setting, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-11 07:10:32 +03:00
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenConfigSetString(virConf *conf, const char *setting, const char *str)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virConfValue *value = NULL;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
value = g_new0(virConfValue, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
value->type = VIR_CONF_STRING;
|
|
|
|
value->next = NULL;
|
2019-10-20 13:49:46 +02:00
|
|
|
value->str = g_strdup(str);
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
return virConfSetValue(conf, setting, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenParseMem(virConf *conf, virDomainDef *def)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2015-02-17 18:01:09 +01:00
|
|
|
unsigned long long memory;
|
|
|
|
|
2014-08-15 20:52:15 -06:00
|
|
|
if (xenConfigGetULongLong(conf, "memory", &def->mem.cur_balloon,
|
|
|
|
MIN_XEN_GUEST_SIZE * 2) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2015-02-17 18:01:09 +01:00
|
|
|
if (xenConfigGetULongLong(conf, "maxmem", &memory,
|
2014-08-15 20:52:15 -06:00
|
|
|
def->mem.cur_balloon) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
def->mem.cur_balloon *= 1024;
|
2015-09-16 14:25:42 +02:00
|
|
|
virDomainDefSetMemoryTotal(def, memory * 1024);
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenParseTimeOffset(virConf *conf, virDomainDef *def)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
|
|
|
int vmlocaltime;
|
|
|
|
|
|
|
|
if (xenConfigGetBool(conf, "localtime", &vmlocaltime, 0) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2015-04-16 20:11:06 -04:00
|
|
|
if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
|
2015-12-04 16:08:59 -07:00
|
|
|
unsigned long rtc_timeoffset;
|
|
|
|
def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_VARIABLE;
|
|
|
|
if (xenConfigGetULong(conf, "rtc_timeoffset", &rtc_timeoffset, 0) < 0)
|
|
|
|
return -1;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2015-12-04 16:08:59 -07:00
|
|
|
def->clock.data.variable.adjustment = (int)rtc_timeoffset;
|
|
|
|
def->clock.data.variable.basis = vmlocaltime ?
|
|
|
|
VIR_DOMAIN_CLOCK_BASIS_LOCALTIME :
|
|
|
|
VIR_DOMAIN_CLOCK_BASIS_UTC;
|
2014-08-15 20:52:15 -06:00
|
|
|
} else {
|
|
|
|
/* PV domains do not have an emulated RTC and the offset is fixed. */
|
|
|
|
def->clock.offset = vmlocaltime ?
|
|
|
|
VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME :
|
|
|
|
VIR_DOMAIN_CLOCK_OFFSET_UTC;
|
|
|
|
def->clock.data.utc_reset = true;
|
|
|
|
} /* !hvm */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenParseEventsActions(virConf *conf, virDomainDef *def)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2019-10-15 15:16:31 +02:00
|
|
|
g_autofree char *on_poweroff = NULL;
|
|
|
|
g_autofree char *on_reboot = NULL;
|
|
|
|
g_autofree char *on_crash = NULL;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2018-09-20 15:28:49 +02:00
|
|
|
if (xenConfigGetString(conf, "on_poweroff", &on_poweroff, "destroy") < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2018-09-20 15:28:49 +02:00
|
|
|
if ((def->onPoweroff = virDomainLifecycleActionTypeFromString(on_poweroff)) < 0) {
|
2014-08-15 20:52:15 -06:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2018-09-20 15:28:49 +02:00
|
|
|
_("unexpected value %s for on_poweroff"), on_poweroff);
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-09-20 15:28:49 +02:00
|
|
|
if (xenConfigGetString(conf, "on_reboot", &on_reboot, "restart") < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2018-09-20 15:28:49 +02:00
|
|
|
if ((def->onReboot = virDomainLifecycleActionTypeFromString(on_reboot)) < 0) {
|
2014-08-15 20:52:15 -06:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2018-09-20 15:28:49 +02:00
|
|
|
_("unexpected value %s for on_reboot"), on_reboot);
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-09-20 15:28:49 +02:00
|
|
|
if (xenConfigGetString(conf, "on_crash", &on_crash, "restart") < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2018-09-20 15:28:49 +02:00
|
|
|
if ((def->onCrash = virDomainLifecycleActionTypeFromString(on_crash)) < 0) {
|
2014-08-15 20:52:15 -06:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2018-09-20 15:28:49 +02:00
|
|
|
_("unexpected value %s for on_crash"), on_crash);
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
static virDomainHostdevDef *
|
2018-05-28 00:28:23 +02:00
|
|
|
xenParsePCI(char *entry)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainHostdevDef *hostdev = NULL;
|
2020-12-01 09:21:32 +01:00
|
|
|
g_auto(GStrv) tokens = NULL;
|
|
|
|
g_auto(GStrv) options = NULL;
|
2020-08-10 16:58:59 -06:00
|
|
|
size_t nexttoken = 0;
|
2020-08-14 14:47:09 -06:00
|
|
|
char *str;
|
|
|
|
char *nextstr;
|
2020-08-10 16:58:59 -06:00
|
|
|
int domain = 0x0;
|
|
|
|
int bus;
|
|
|
|
int slot;
|
|
|
|
int func;
|
2020-08-14 14:47:09 -06:00
|
|
|
virTristateBool filtered = VIR_TRISTATE_BOOL_ABSENT;
|
2020-08-10 16:58:59 -06:00
|
|
|
|
2020-08-14 14:47:09 -06:00
|
|
|
/* pci=['00:1b.0','0000:00:13.0,permissive=1'] */
|
2021-04-01 15:33:22 +02:00
|
|
|
if (!(tokens = g_strsplit(entry, ":", 3)))
|
2018-05-28 00:28:23 +02:00
|
|
|
return NULL;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2020-08-10 16:58:59 -06:00
|
|
|
/* domain */
|
2021-04-01 15:33:22 +02:00
|
|
|
if (g_strv_length(tokens) == 3) {
|
2020-08-10 16:58:59 -06:00
|
|
|
if (virStrToLong_i(tokens[nexttoken], NULL, 16, &domain) < 0)
|
|
|
|
return NULL;
|
|
|
|
nexttoken++;
|
2018-05-28 00:28:23 +02:00
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2020-08-10 16:58:59 -06:00
|
|
|
/* bus */
|
|
|
|
if (virStrToLong_i(tokens[nexttoken], NULL, 16, &bus) < 0)
|
2018-05-28 00:28:23 +02:00
|
|
|
return NULL;
|
2020-08-10 16:58:59 -06:00
|
|
|
nexttoken++;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2020-08-14 14:47:09 -06:00
|
|
|
/* slot, function, and options */
|
|
|
|
str = tokens[nexttoken];
|
|
|
|
if (!(nextstr = strchr(str, '.'))) {
|
2018-05-28 00:28:23 +02:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2020-08-14 14:47:09 -06:00
|
|
|
_("Malformed PCI address %s"), str);
|
2018-05-28 00:28:23 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2020-08-14 14:47:09 -06:00
|
|
|
*nextstr = '\0';
|
|
|
|
nextstr++;
|
|
|
|
if (virStrToLong_i(str, NULL, 16, &slot) < 0)
|
2018-05-28 00:28:23 +02:00
|
|
|
return NULL;
|
2020-08-14 14:47:09 -06:00
|
|
|
str = nextstr++;
|
|
|
|
|
|
|
|
nextstr = strchr(str, ',');
|
|
|
|
if (nextstr) {
|
|
|
|
*nextstr = '\0';
|
|
|
|
nextstr++;
|
|
|
|
}
|
|
|
|
if (virStrToLong_i(str, NULL, 16, &func) < 0)
|
2018-05-28 00:28:23 +02:00
|
|
|
return NULL;
|
|
|
|
|
2020-08-14 14:47:09 -06:00
|
|
|
str = nextstr;
|
2021-02-05 18:35:07 +01:00
|
|
|
if (str && (options = g_strsplit(str, ",", 0))) {
|
2020-08-14 14:47:09 -06:00
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; options[i] != NULL; i++) {
|
|
|
|
char *val;
|
|
|
|
|
|
|
|
if (!(val = strchr(options[i], '='))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Malformed PCI options %s"), str);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
*val = '\0';
|
|
|
|
val++;
|
|
|
|
if (STREQ(options[i], "permissive")) {
|
|
|
|
int intval;
|
|
|
|
|
|
|
|
/* xl.cfg(5) specifies false as 0 and true as any other numeric value */
|
|
|
|
if (virStrToLong_i(val, NULL, 10, &intval) < 0)
|
|
|
|
return NULL;
|
|
|
|
filtered = intval ? VIR_TRISTATE_BOOL_NO : VIR_TRISTATE_BOOL_YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-28 00:28:23 +02:00
|
|
|
if (!(hostdev = virDomainHostdevDefNew()))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
hostdev->managed = false;
|
2020-08-14 14:47:09 -06:00
|
|
|
hostdev->writeFiltering = filtered;
|
2018-05-28 00:28:23 +02:00
|
|
|
hostdev->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
|
2020-08-10 16:58:59 -06:00
|
|
|
hostdev->source.subsys.u.pci.addr.domain = domain;
|
|
|
|
hostdev->source.subsys.u.pci.addr.bus = bus;
|
|
|
|
hostdev->source.subsys.u.pci.addr.slot = slot;
|
|
|
|
hostdev->source.subsys.u.pci.addr.function = func;
|
2018-05-28 00:28:23 +02:00
|
|
|
|
|
|
|
return hostdev;
|
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
|
2018-09-20 15:28:50 +02:00
|
|
|
static int
|
|
|
|
xenHandleConfGetValueStringListErrors(int ret)
|
|
|
|
{
|
|
|
|
if (ret < 0) {
|
|
|
|
/* It means virConfGetValueStringList() didn't fail because the
|
|
|
|
* cval->type switch fell through - since we're passing
|
|
|
|
* @compatString == false - assumes failures for memory allocation
|
|
|
|
* and VIR_CONF_LIST traversal failure should cause -1 to be
|
|
|
|
* returned to the caller with the error message set. */
|
|
|
|
if (virGetLastErrorCode() != VIR_ERR_INTERNAL_ERROR)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* If we did fall through the switch, then ignore and clear the
|
|
|
|
* last error. */
|
|
|
|
virResetLastError();
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-05-28 00:28:23 +02:00
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenParsePCIList(virConf *conf, virDomainDef *def)
|
2018-05-28 00:28:23 +02:00
|
|
|
{
|
2020-12-01 09:21:32 +01:00
|
|
|
g_auto(GStrv) pcis = NULL;
|
2019-02-26 16:17:54 +01:00
|
|
|
char **entries = NULL;
|
2018-09-20 15:28:50 +02:00
|
|
|
int rc;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2018-09-20 15:28:50 +02:00
|
|
|
if ((rc = virConfGetValueStringList(conf, "pci", false, &pcis)) <= 0)
|
|
|
|
return xenHandleConfGetValueStringListErrors(rc);
|
2018-05-28 00:28:23 +02:00
|
|
|
|
2018-09-20 15:28:50 +02:00
|
|
|
for (entries = pcis; *entries; entries++) {
|
2019-02-26 16:17:54 +01:00
|
|
|
char *entry = *entries;
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainHostdevDef *hostdev;
|
2018-05-28 00:28:23 +02:00
|
|
|
|
2018-09-20 15:28:50 +02:00
|
|
|
if (!(hostdev = xenParsePCI(entry)))
|
2018-05-28 00:28:23 +02:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (VIR_APPEND_ELEMENT(def->hostdevs, def->nhostdevs, hostdev) < 0) {
|
|
|
|
virDomainHostdevDefFree(hostdev);
|
|
|
|
return -1;
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenParseCPU(virConf *conf,
|
|
|
|
virDomainDef *def,
|
|
|
|
virDomainXMLOption *xmlopt)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
|
|
|
unsigned long count = 0;
|
2019-10-15 15:16:31 +02:00
|
|
|
g_autofree char *cpus = NULL;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2015-12-15 14:47:40 -07:00
|
|
|
if (xenConfigGetULong(conf, "vcpus", &count, 1) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2016-06-29 14:55:24 +02:00
|
|
|
if (virDomainDefSetVcpusMax(def, count, xmlopt) < 0)
|
2015-10-16 16:10:27 +02:00
|
|
|
return -1;
|
|
|
|
|
2015-12-15 14:47:40 -07:00
|
|
|
if (virDomainDefSetVcpus(def, count) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2015-12-15 14:47:40 -07:00
|
|
|
if (virConfGetValue(conf, "maxvcpus")) {
|
|
|
|
if (xenConfigGetULong(conf, "maxvcpus", &count, 0) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2016-06-29 14:55:24 +02:00
|
|
|
if (virDomainDefSetVcpusMax(def, count, xmlopt) < 0)
|
2015-12-15 14:47:40 -07:00
|
|
|
return -1;
|
|
|
|
}
|
2015-10-22 10:52:05 +02:00
|
|
|
|
2018-09-20 15:28:49 +02:00
|
|
|
if (xenConfigGetString(conf, "cpus", &cpus, NULL) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2018-09-20 15:28:49 +02:00
|
|
|
if (cpus && (virBitmapParse(cpus, &def->cpumask, 4096) < 0))
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2020-04-15 21:48:42 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenParseHypervisorFeatures(virConf *conf, virDomainDef *def)
|
2020-04-15 21:48:42 -06:00
|
|
|
{
|
2021-04-19 13:54:11 +02:00
|
|
|
g_autofree char *tscmode = NULL;
|
|
|
|
g_autofree char *passthrough = NULL;
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainTimerDef *timer;
|
2020-04-15 21:48:42 -06:00
|
|
|
int val = 0;
|
|
|
|
|
2021-04-19 13:54:11 +02:00
|
|
|
if (xenConfigGetString(conf, "tsc_mode", &tscmode, NULL) < 0)
|
2017-01-19 16:51:05 -07:00
|
|
|
return -1;
|
|
|
|
|
2021-04-19 13:54:11 +02:00
|
|
|
if (tscmode) {
|
2021-03-20 00:37:03 +01:00
|
|
|
VIR_EXPAND_N(def->clock.timers, def->clock.ntimers, 1);
|
2017-01-19 16:51:05 -07:00
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
timer = g_new0(virDomainTimerDef, 1);
|
2017-01-19 16:51:05 -07:00
|
|
|
timer->name = VIR_DOMAIN_TIMER_NAME_TSC;
|
|
|
|
timer->present = 1;
|
|
|
|
timer->tickpolicy = -1;
|
|
|
|
timer->mode = VIR_DOMAIN_TIMER_MODE_AUTO;
|
|
|
|
timer->track = -1;
|
2021-04-19 13:54:11 +02:00
|
|
|
if (STREQ_NULLABLE(tscmode, "always_emulate"))
|
2017-01-19 16:51:05 -07:00
|
|
|
timer->mode = VIR_DOMAIN_TIMER_MODE_EMULATE;
|
2021-04-19 13:54:11 +02:00
|
|
|
else if (STREQ_NULLABLE(tscmode, "native"))
|
2017-01-19 16:51:05 -07:00
|
|
|
timer->mode = VIR_DOMAIN_TIMER_MODE_NATIVE;
|
2021-04-19 13:54:11 +02:00
|
|
|
else if (STREQ_NULLABLE(tscmode, "native_paravirt"))
|
2017-01-19 16:51:05 -07:00
|
|
|
timer->mode = VIR_DOMAIN_TIMER_MODE_PARAVIRT;
|
|
|
|
|
|
|
|
def->clock.timers[def->clock.ntimers - 1] = timer;
|
|
|
|
}
|
|
|
|
|
2021-04-19 13:54:11 +02:00
|
|
|
if (xenConfigGetString(conf, "passthrough", &passthrough, NULL) < 0)
|
2020-04-16 08:31:48 -06:00
|
|
|
return -1;
|
|
|
|
|
2021-04-19 13:54:11 +02:00
|
|
|
if (passthrough) {
|
|
|
|
if (STREQ(passthrough, "disabled")) {
|
2020-04-16 08:31:48 -06:00
|
|
|
def->features[VIR_DOMAIN_FEATURE_XEN] = VIR_TRISTATE_SWITCH_OFF;
|
|
|
|
def->xen_features[VIR_DOMAIN_XEN_PASSTHROUGH] = VIR_TRISTATE_SWITCH_OFF;
|
2021-04-19 13:54:11 +02:00
|
|
|
} else if (STREQ(passthrough, "enabled")) {
|
2020-04-16 08:31:48 -06:00
|
|
|
def->features[VIR_DOMAIN_FEATURE_XEN] = VIR_TRISTATE_SWITCH_ON;
|
|
|
|
def->xen_features[VIR_DOMAIN_XEN_PASSTHROUGH] = VIR_TRISTATE_SWITCH_ON;
|
2021-04-19 13:54:11 +02:00
|
|
|
} else if (STREQ(passthrough, "sync_pt")) {
|
2020-04-16 08:31:48 -06:00
|
|
|
def->features[VIR_DOMAIN_FEATURE_XEN] = VIR_TRISTATE_SWITCH_ON;
|
|
|
|
def->xen_features[VIR_DOMAIN_XEN_PASSTHROUGH] = VIR_TRISTATE_SWITCH_ON;
|
|
|
|
def->xen_passthrough_mode = VIR_DOMAIN_XEN_PASSTHROUGH_MODE_SYNC_PT;
|
2021-04-19 13:54:11 +02:00
|
|
|
} else if (STREQ(passthrough, "share_pt")) {
|
2020-04-16 08:31:48 -06:00
|
|
|
def->features[VIR_DOMAIN_FEATURE_XEN] = VIR_TRISTATE_SWITCH_ON;
|
|
|
|
def->xen_features[VIR_DOMAIN_XEN_PASSTHROUGH] = VIR_TRISTATE_SWITCH_ON;
|
|
|
|
def->xen_passthrough_mode = VIR_DOMAIN_XEN_PASSTHROUGH_MODE_SHARE_PT;
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONF_SYNTAX,
|
2021-04-19 13:54:11 +02:00
|
|
|
_("Invalid passthrough mode %s"), passthrough);
|
2020-04-16 08:31:48 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-16 20:11:06 -04:00
|
|
|
if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
|
2014-12-23 14:36:04 +08:00
|
|
|
if (xenConfigGetBool(conf, "pae", &val, 1) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
else if (val)
|
|
|
|
def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_TRISTATE_SWITCH_ON;
|
2020-04-15 21:48:42 -06:00
|
|
|
|
2014-12-23 14:36:04 +08:00
|
|
|
if (xenConfigGetBool(conf, "acpi", &val, 1) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
else if (val)
|
|
|
|
def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_TRISTATE_SWITCH_ON;
|
2020-04-15 21:48:42 -06:00
|
|
|
|
2014-12-23 14:36:04 +08:00
|
|
|
if (xenConfigGetBool(conf, "apic", &val, 1) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
else if (val)
|
|
|
|
def->features[VIR_DOMAIN_FEATURE_APIC] = VIR_TRISTATE_SWITCH_ON;
|
2020-04-15 21:48:42 -06:00
|
|
|
|
2016-02-22 18:50:19 -07:00
|
|
|
if (xenConfigGetBool(conf, "hap", &val, 1) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
2016-02-22 18:50:19 -07:00
|
|
|
else if (!val)
|
|
|
|
def->features[VIR_DOMAIN_FEATURE_HAP] = VIR_TRISTATE_SWITCH_OFF;
|
2020-04-15 21:48:42 -06:00
|
|
|
|
2014-08-15 20:52:15 -06:00
|
|
|
if (xenConfigGetBool(conf, "viridian", &val, 0) < 0)
|
|
|
|
return -1;
|
|
|
|
else if (val)
|
|
|
|
def->features[VIR_DOMAIN_FEATURE_VIRIDIAN] = VIR_TRISTATE_SWITCH_ON;
|
|
|
|
|
|
|
|
if (xenConfigGetBool(conf, "hpet", &val, -1) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2014-09-03 13:04:59 -06:00
|
|
|
if (val != -1) {
|
2021-03-20 00:37:03 +01:00
|
|
|
VIR_EXPAND_N(def->clock.timers, def->clock.ntimers, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
timer = g_new0(virDomainTimerDef, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
timer->name = VIR_DOMAIN_TIMER_NAME_HPET;
|
|
|
|
timer->present = val;
|
|
|
|
timer->tickpolicy = -1;
|
2015-11-28 07:18:29 +01:00
|
|
|
timer->mode = -1;
|
|
|
|
timer->track = -1;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2017-01-19 16:51:05 -07:00
|
|
|
def->clock.timers[def->clock.ntimers - 1] = timer;
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
2020-04-14 04:37:06 +02:00
|
|
|
} else {
|
|
|
|
if (xenConfigGetBool(conf, "e820_host", &val, 0) < 0) {
|
|
|
|
return -1;
|
|
|
|
} else if (val) {
|
|
|
|
def->features[VIR_DOMAIN_FEATURE_XEN] = VIR_TRISTATE_SWITCH_ON;
|
|
|
|
def->xen_features[VIR_DOMAIN_XEN_E820_HOST] = VIR_TRISTATE_SWITCH_ON;
|
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define MAX_VFB 1024
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenParseVfb(virConf *conf, virDomainDef *def)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
|
|
|
int val;
|
|
|
|
char *listenAddr = NULL;
|
2015-04-16 20:11:06 -04:00
|
|
|
int hvm = def->os.type == VIR_DOMAIN_OSTYPE_HVM;
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainGraphicsDef *graphics = NULL;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2015-12-04 16:08:59 -07:00
|
|
|
if (hvm) {
|
2014-08-15 20:52:15 -06:00
|
|
|
if (xenConfigGetBool(conf, "vnc", &val, 0) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
if (val) {
|
2020-09-23 20:43:09 +02:00
|
|
|
graphics = g_new0(virDomainGraphicsDef, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
|
|
|
|
if (xenConfigGetBool(conf, "vncunused", &val, 1) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
graphics->data.vnc.autoport = val ? 1 : 0;
|
|
|
|
if (!graphics->data.vnc.autoport) {
|
|
|
|
unsigned long vncdisplay;
|
|
|
|
if (xenConfigGetULong(conf, "vncdisplay", &vncdisplay, 0) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
graphics->data.vnc.port = (int)vncdisplay + 5900;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xenConfigCopyStringOpt(conf, "vnclisten", &listenAddr) < 0)
|
|
|
|
goto cleanup;
|
2016-05-09 15:50:54 +02:00
|
|
|
if (virDomainGraphicsListenAppendAddress(graphics, listenAddr) < 0)
|
2016-03-23 08:55:46 +01:00
|
|
|
goto cleanup;
|
2014-08-15 20:52:15 -06:00
|
|
|
VIR_FREE(listenAddr);
|
2016-03-23 08:55:46 +01:00
|
|
|
|
2014-08-15 20:52:15 -06:00
|
|
|
if (xenConfigCopyStringOpt(conf, "vncpasswd", &graphics->data.vnc.auth.passwd) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
if (xenConfigCopyStringOpt(conf, "keymap", &graphics->data.vnc.keymap) < 0)
|
|
|
|
goto cleanup;
|
2021-03-11 08:16:13 +01:00
|
|
|
def->graphics = g_new0(virDomainGraphicsDef *, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
def->graphics[0] = graphics;
|
|
|
|
def->ngraphics = 1;
|
|
|
|
graphics = NULL;
|
|
|
|
} else {
|
|
|
|
if (xenConfigGetBool(conf, "sdl", &val, 0) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
if (val) {
|
2020-09-23 20:43:09 +02:00
|
|
|
graphics = g_new0(virDomainGraphicsDef, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
|
|
|
|
if (xenConfigCopyStringOpt(conf, "display", &graphics->data.sdl.display) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
if (xenConfigCopyStringOpt(conf, "xauthority", &graphics->data.sdl.xauth) < 0)
|
|
|
|
goto cleanup;
|
2021-03-11 08:16:13 +01:00
|
|
|
def->graphics = g_new0(virDomainGraphicsDef *, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
def->graphics[0] = graphics;
|
|
|
|
def->ngraphics = 1;
|
|
|
|
graphics = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hvm && def->graphics == NULL) { /* New PV guests use this format */
|
2020-12-01 09:21:32 +01:00
|
|
|
g_auto(GStrv) vfbs = NULL;
|
2018-09-20 15:28:51 +02:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
if ((rc = virConfGetValueStringList(conf, "vfb", false, &vfbs)) == 1) {
|
2014-08-15 20:52:15 -06:00
|
|
|
char vfb[MAX_VFB];
|
|
|
|
char *key = vfb;
|
|
|
|
|
2018-09-20 15:28:51 +02:00
|
|
|
if (virStrcpyStatic(vfb, *vfbs) < 0) {
|
2014-08-15 20:52:15 -06:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("VFB %s too big for destination"),
|
2018-09-20 15:28:51 +02:00
|
|
|
*vfbs);
|
2014-08-15 20:52:15 -06:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
graphics = g_new0(virDomainGraphicsDef, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
if (strstr(key, "type=sdl"))
|
|
|
|
graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
|
|
|
|
else
|
|
|
|
graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
|
|
|
|
while (key) {
|
|
|
|
char *nextkey = strchr(key, ',');
|
|
|
|
char *end = nextkey;
|
|
|
|
if (nextkey) {
|
|
|
|
*end = '\0';
|
|
|
|
nextkey++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strchr(key, '='))
|
|
|
|
break;
|
|
|
|
if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
|
|
|
|
if (STRPREFIX(key, "vncunused=")) {
|
|
|
|
if (STREQ(key + 10, "1"))
|
|
|
|
graphics->data.vnc.autoport = true;
|
|
|
|
} else if (STRPREFIX(key, "vnclisten=")) {
|
2019-10-20 13:49:46 +02:00
|
|
|
listenAddr = g_strdup(key + 10);
|
2014-08-15 20:52:15 -06:00
|
|
|
} else if (STRPREFIX(key, "vncpasswd=")) {
|
2019-10-20 13:49:46 +02:00
|
|
|
graphics->data.vnc.auth.passwd = g_strdup(key + 10);
|
2014-08-15 20:52:15 -06:00
|
|
|
} else if (STRPREFIX(key, "keymap=")) {
|
2019-10-20 13:49:46 +02:00
|
|
|
graphics->data.vnc.keymap = g_strdup(key + 7);
|
2014-08-15 20:52:15 -06:00
|
|
|
} else if (STRPREFIX(key, "vncdisplay=")) {
|
|
|
|
if (virStrToLong_i(key + 11, NULL, 10,
|
|
|
|
&graphics->data.vnc.port) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("invalid vncdisplay value '%s'"),
|
|
|
|
key + 11);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
graphics->data.vnc.port += 5900;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (STRPREFIX(key, "display=")) {
|
2019-10-20 13:49:46 +02:00
|
|
|
graphics->data.sdl.display = g_strdup(key + 8);
|
2014-08-15 20:52:15 -06:00
|
|
|
} else if (STRPREFIX(key, "xauthority=")) {
|
2019-10-20 13:49:46 +02:00
|
|
|
graphics->data.sdl.xauth = g_strdup(key + 11);
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (nextkey && (nextkey[0] == ',' ||
|
|
|
|
nextkey[0] == ' ' ||
|
|
|
|
nextkey[0] == '\t'))
|
|
|
|
nextkey++;
|
|
|
|
key = nextkey;
|
|
|
|
}
|
2016-05-09 15:50:54 +02:00
|
|
|
if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
|
|
|
|
if (virDomainGraphicsListenAppendAddress(graphics,
|
|
|
|
listenAddr) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
VIR_FREE(listenAddr);
|
|
|
|
}
|
2021-03-11 08:16:13 +01:00
|
|
|
def->graphics = g_new0(virDomainGraphicsDef *, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
def->graphics[0] = graphics;
|
|
|
|
def->ngraphics = 1;
|
|
|
|
graphics = NULL;
|
2018-09-20 15:28:51 +02:00
|
|
|
} else {
|
|
|
|
if (xenHandleConfGetValueStringListErrors(rc) < 0)
|
|
|
|
goto cleanup;
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virDomainGraphicsDefFree(graphics);
|
|
|
|
VIR_FREE(listenAddr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-03 09:44:51 +02:00
|
|
|
/**
|
|
|
|
* xenParseSxprChar:
|
|
|
|
* @value: A string describing a character device.
|
|
|
|
* @tty: the console pty path
|
|
|
|
*
|
|
|
|
* Parse the xend S-expression for description of a character device.
|
|
|
|
*
|
|
|
|
* Returns a character device object or NULL in case of failure.
|
|
|
|
*/
|
2021-03-11 08:16:13 +01:00
|
|
|
static virDomainChrDef *
|
2019-07-03 09:44:51 +02:00
|
|
|
xenParseSxprChar(const char *value,
|
|
|
|
const char *tty)
|
|
|
|
{
|
|
|
|
const char *prefix;
|
|
|
|
char *tmp;
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainChrDef *def;
|
2019-07-03 09:44:51 +02:00
|
|
|
|
|
|
|
if (!(def = virDomainChrDefNew(NULL)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
prefix = value;
|
|
|
|
|
2021-04-20 12:44:12 +08:00
|
|
|
if (g_path_is_absolute(value)) {
|
2019-07-03 09:44:51 +02:00
|
|
|
def->source->type = VIR_DOMAIN_CHR_TYPE_DEV;
|
2019-10-20 13:49:46 +02:00
|
|
|
def->source->data.file.path = g_strdup(value);
|
2019-07-03 09:44:51 +02:00
|
|
|
} else {
|
|
|
|
if ((tmp = strchr(value, ':')) != NULL) {
|
|
|
|
*tmp = '\0';
|
|
|
|
value = tmp + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (STRPREFIX(prefix, "telnet")) {
|
|
|
|
def->source->type = VIR_DOMAIN_CHR_TYPE_TCP;
|
|
|
|
def->source->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
|
|
|
|
} else {
|
|
|
|
if ((def->source->type = virDomainChrTypeFromString(prefix)) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown chr device type '%s'"), prefix);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (def->source->type) {
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_PTY:
|
2019-10-20 13:49:46 +02:00
|
|
|
def->source->data.file.path = g_strdup(tty);
|
2019-07-03 09:44:51 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_FILE:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_PIPE:
|
2019-10-20 13:49:46 +02:00
|
|
|
def->source->data.file.path = g_strdup(value);
|
2019-07-03 09:44:51 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_TCP:
|
|
|
|
{
|
|
|
|
const char *offset = strchr(value, ':');
|
|
|
|
const char *offset2;
|
|
|
|
|
|
|
|
if (offset == NULL) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("malformed char device string"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2019-10-24 19:34:57 +02:00
|
|
|
if (offset != value)
|
|
|
|
def->source->data.tcp.host = g_strndup(value, offset - value);
|
2019-07-03 09:44:51 +02:00
|
|
|
|
|
|
|
offset2 = strchr(offset, ',');
|
|
|
|
offset++;
|
2019-10-25 00:05:28 +02:00
|
|
|
if (offset2)
|
|
|
|
def->source->data.tcp.service = g_strndup(offset,
|
|
|
|
offset2 - offset);
|
|
|
|
else
|
|
|
|
def->source->data.tcp.service = g_strdup(offset);
|
2019-07-03 09:44:51 +02:00
|
|
|
|
|
|
|
if (offset2 && strstr(offset2, ",server"))
|
|
|
|
def->source->data.tcp.listen = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UDP:
|
|
|
|
{
|
|
|
|
const char *offset = strchr(value, ':');
|
|
|
|
const char *offset2, *offset3;
|
|
|
|
|
|
|
|
if (offset == NULL) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("malformed char device string"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2019-10-24 19:34:57 +02:00
|
|
|
if (offset != value)
|
|
|
|
def->source->data.udp.connectHost = g_strndup(value,
|
|
|
|
offset - value);
|
2019-07-03 09:44:51 +02:00
|
|
|
|
|
|
|
offset2 = strchr(offset, '@');
|
|
|
|
if (offset2 != NULL) {
|
2019-10-24 19:41:34 +02:00
|
|
|
def->source->data.udp.connectService = g_strndup(offset + 1,
|
|
|
|
offset2 - offset - 1);
|
2019-07-03 09:44:51 +02:00
|
|
|
|
|
|
|
offset3 = strchr(offset2, ':');
|
|
|
|
if (offset3 == NULL) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("malformed char device string"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2019-10-24 19:34:57 +02:00
|
|
|
if (offset3 > (offset2 + 1))
|
|
|
|
def->source->data.udp.bindHost = g_strndup(offset2 + 1,
|
|
|
|
offset3 - offset2 - 1);
|
2019-07-03 09:44:51 +02:00
|
|
|
|
2019-10-20 13:49:46 +02:00
|
|
|
def->source->data.udp.bindService = g_strdup(offset3 + 1);
|
2019-07-03 09:44:51 +02:00
|
|
|
} else {
|
2019-10-20 13:49:46 +02:00
|
|
|
def->source->data.udp.connectService = g_strdup(offset + 1);
|
2019-07-03 09:44:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
|
|
|
{
|
|
|
|
const char *offset = strchr(value, ',');
|
2019-10-25 00:05:28 +02:00
|
|
|
if (offset)
|
|
|
|
def->source->data.nix.path = g_strndup(value, offset - value);
|
|
|
|
else
|
|
|
|
def->source->data.nix.path = g_strdup(value);
|
2019-07-03 09:44:51 +02:00
|
|
|
|
|
|
|
if (offset != NULL &&
|
|
|
|
strstr(offset, ",server") != NULL)
|
|
|
|
def->source->data.nix.listen = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainChrDefFree(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-08-15 20:52:15 -06:00
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenParseCharDev(virConf *conf, virDomainDef *def, const char *nativeFormat)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2020-12-01 09:21:32 +01:00
|
|
|
g_auto(GStrv) serials = NULL;
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainChrDef *chr = NULL;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2015-04-16 20:11:06 -04:00
|
|
|
if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
|
2019-10-15 15:16:31 +02:00
|
|
|
g_autofree char *parallel = NULL;
|
2018-09-20 15:28:52 +02:00
|
|
|
int rc;
|
|
|
|
|
2018-09-20 15:28:49 +02:00
|
|
|
if (xenConfigGetString(conf, "parallel", ¶llel, NULL) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
goto cleanup;
|
2018-09-20 15:28:49 +02:00
|
|
|
if (parallel && STRNEQ(parallel, "none") &&
|
|
|
|
!(chr = xenParseSxprChar(parallel, NULL)))
|
2014-08-15 20:52:15 -06:00
|
|
|
goto cleanup;
|
|
|
|
if (chr) {
|
2021-03-11 08:16:13 +01:00
|
|
|
def->parallels = g_new0(virDomainChrDef *, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
|
|
|
|
chr->target.port = 0;
|
|
|
|
def->parallels[0] = chr;
|
|
|
|
def->nparallels++;
|
|
|
|
chr = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to get the list of values to support multiple serial ports */
|
2018-09-20 15:28:52 +02:00
|
|
|
if ((rc = virConfGetValueStringList(conf, "serial", false, &serials)) == 1) {
|
2019-02-26 16:17:54 +01:00
|
|
|
char **entries;
|
2014-08-15 20:52:15 -06:00
|
|
|
int portnum = -1;
|
|
|
|
|
2016-08-18 10:20:49 +08:00
|
|
|
if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XM)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Multiple serial devices are not supported by xen-xm"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2018-09-20 15:28:52 +02:00
|
|
|
for (entries = serials; *entries; entries++) {
|
2019-02-26 16:17:54 +01:00
|
|
|
char *port = *entries;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
portnum++;
|
2018-09-20 15:28:52 +02:00
|
|
|
if (STREQ(port, "none"))
|
2014-08-15 20:52:15 -06:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!(chr = xenParseSxprChar(port, NULL)))
|
|
|
|
goto cleanup;
|
|
|
|
chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
|
|
|
|
chr->target.port = portnum;
|
2014-11-13 15:29:45 +01:00
|
|
|
if (VIR_APPEND_ELEMENT(def->serials, def->nserials, chr) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
2019-10-15 15:16:31 +02:00
|
|
|
g_autofree char *serial = NULL;
|
2018-09-20 15:28:52 +02:00
|
|
|
|
|
|
|
if (xenHandleConfGetValueStringListErrors(rc) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2014-08-15 20:52:15 -06:00
|
|
|
/* If domain is not using multiple serial ports we parse data old way */
|
2018-09-20 15:28:49 +02:00
|
|
|
if (xenConfigGetString(conf, "serial", &serial, NULL) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
goto cleanup;
|
2018-09-20 15:28:49 +02:00
|
|
|
if (serial && STRNEQ(serial, "none") &&
|
|
|
|
!(chr = xenParseSxprChar(serial, NULL)))
|
2014-08-15 20:52:15 -06:00
|
|
|
goto cleanup;
|
|
|
|
if (chr) {
|
2021-03-11 08:16:13 +01:00
|
|
|
def->serials = g_new0(virDomainChrDef *, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
|
|
|
|
chr->target.port = 0;
|
|
|
|
def->serials[0] = chr;
|
|
|
|
def->nserials++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2021-03-11 08:16:13 +01:00
|
|
|
def->consoles = g_new0(virDomainChrDef *, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
def->nconsoles = 1;
|
|
|
|
if (!(def->consoles[0] = xenParseSxprChar("pty", NULL)))
|
|
|
|
goto cleanup;
|
|
|
|
def->consoles[0]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
|
|
|
|
def->consoles[0]->target.port = 0;
|
|
|
|
def->consoles[0]->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virDomainChrDefFree(chr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-16 13:08:23 -07:00
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenParseVifBridge(virDomainNetDef *net, const char *bridge)
|
2018-11-16 13:08:23 -07:00
|
|
|
{
|
|
|
|
char *vlanstr;
|
|
|
|
unsigned int tag;
|
|
|
|
|
|
|
|
if ((vlanstr = strchr(bridge, '.'))) {
|
|
|
|
/* 'bridge' string contains a bridge name and single vlan tag */
|
2019-10-24 19:41:34 +02:00
|
|
|
net->data.bridge.brname = g_strndup(bridge, vlanstr - bridge);
|
2018-11-16 13:08:23 -07:00
|
|
|
|
|
|
|
vlanstr++;
|
|
|
|
if (virStrToLong_ui(vlanstr, NULL, 10, &tag) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
net->vlan.tag = g_new0(unsigned int, 1);
|
2018-11-16 13:08:23 -07:00
|
|
|
net->vlan.tag[0] = tag;
|
|
|
|
net->vlan.nTags = 1;
|
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
net->virtPortProfile = g_new0(virNetDevVPortProfile, 1);
|
2018-11-16 13:08:23 -07:00
|
|
|
net->virtPortProfile->virtPortType = VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH;
|
|
|
|
return 0;
|
|
|
|
} else if ((vlanstr = strchr(bridge, ':'))) {
|
|
|
|
/* 'bridge' string contains a bridge name and one or more vlan trunks */
|
|
|
|
size_t i;
|
|
|
|
size_t nvlans = 0;
|
2021-02-05 18:35:07 +01:00
|
|
|
char **vlanstr_list = g_strsplit(bridge, ":", 0);
|
2018-11-16 13:08:23 -07:00
|
|
|
|
|
|
|
if (!vlanstr_list)
|
|
|
|
return -1;
|
|
|
|
|
2019-10-20 13:49:46 +02:00
|
|
|
net->data.bridge.brname = g_strdup(vlanstr_list[0]);
|
2018-11-16 13:08:23 -07:00
|
|
|
|
|
|
|
for (i = 1; vlanstr_list[i]; i++)
|
|
|
|
nvlans++;
|
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
net->vlan.tag = g_new0(unsigned int, nvlans);
|
2018-11-16 13:08:23 -07:00
|
|
|
|
|
|
|
for (i = 1; i <= nvlans; i++) {
|
|
|
|
if (virStrToLong_ui(vlanstr_list[i], NULL, 10, &tag) < 0) {
|
2020-08-02 19:36:03 +02:00
|
|
|
g_strfreev(vlanstr_list);
|
2018-11-16 13:08:23 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
net->vlan.tag[i - 1] = tag;
|
|
|
|
}
|
|
|
|
net->vlan.nTags = nvlans;
|
|
|
|
net->vlan.trunk = true;
|
2020-08-02 19:36:03 +02:00
|
|
|
g_strfreev(vlanstr_list);
|
2018-11-16 13:08:23 -07:00
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
net->virtPortProfile = g_new0(virNetDevVPortProfile, 1);
|
2018-11-16 13:08:23 -07:00
|
|
|
net->virtPortProfile->virtPortType = VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH;
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
/* 'bridge' string only contains the bridge name */
|
2019-10-20 13:49:46 +02:00
|
|
|
net->data.bridge.brname = g_strdup(bridge);
|
2018-11-16 13:08:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-03 09:44:51 +02:00
|
|
|
static const char *vif_bytes_per_sec_re = "^[0-9]+[GMK]?[Bb]/s$";
|
|
|
|
|
|
|
|
static int
|
|
|
|
xenParseSxprVifRate(const char *rate, unsigned long long *kbytes_per_sec)
|
|
|
|
{
|
2019-11-13 13:08:14 +01:00
|
|
|
g_autoptr(GRegex) regex = NULL;
|
|
|
|
g_autoptr(GError) err = NULL;
|
2019-11-13 12:59:29 +01:00
|
|
|
g_autofree char *trate = NULL;
|
2019-07-03 09:44:51 +02:00
|
|
|
char *p;
|
|
|
|
char *suffix;
|
|
|
|
unsigned long long tmp;
|
|
|
|
|
2019-10-20 13:49:46 +02:00
|
|
|
trate = g_strdup(rate);
|
2019-07-03 09:44:51 +02:00
|
|
|
|
|
|
|
p = strchr(trate, '@');
|
|
|
|
if (p != NULL)
|
|
|
|
*p = 0;
|
|
|
|
|
2019-11-13 13:08:14 +01:00
|
|
|
regex = g_regex_new(vif_bytes_per_sec_re, 0, 0, &err);
|
|
|
|
if (!regex) {
|
2019-07-03 09:44:51 +02:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2019-11-13 13:08:14 +01:00
|
|
|
_("Failed to compile regex %s"), err->message);
|
|
|
|
return -1;
|
2019-07-03 09:44:51 +02:00
|
|
|
}
|
|
|
|
|
2019-11-13 13:08:14 +01:00
|
|
|
if (!g_regex_match(regex, trate, 0, NULL)) {
|
2019-07-03 09:44:51 +02:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Invalid rate '%s' specified"), rate);
|
2019-11-13 13:09:11 +01:00
|
|
|
return -1;
|
2019-07-03 09:44:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virStrToLong_ull(rate, &suffix, 10, &tmp)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Failed to parse rate '%s'"), rate);
|
2019-11-13 13:09:11 +01:00
|
|
|
return -1;
|
2019-07-03 09:44:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (*suffix == 'G')
|
|
|
|
tmp *= 1024 * 1024;
|
|
|
|
else if (*suffix == 'M')
|
|
|
|
tmp *= 1024;
|
|
|
|
|
|
|
|
if (*suffix == 'b' || *(suffix + 1) == 'b')
|
|
|
|
tmp /= 8;
|
|
|
|
|
|
|
|
*kbytes_per_sec = tmp;
|
2019-11-13 13:09:11 +01:00
|
|
|
return 0;
|
2019-07-03 09:44:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
static virDomainNetDef *
|
2018-06-14 06:59:52 +02:00
|
|
|
xenParseVif(char *entry, const char *vif_typename)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainNetDef *net = NULL;
|
|
|
|
virDomainNetDef *ret = NULL;
|
2021-03-02 11:49:34 +01:00
|
|
|
g_auto(GStrv) keyvals = NULL;
|
|
|
|
GStrv keyval;
|
|
|
|
const char *script = NULL;
|
|
|
|
const char *model = NULL;
|
|
|
|
const char *type = NULL;
|
|
|
|
const char *ip = NULL;
|
|
|
|
const char *mac = NULL;
|
|
|
|
const char *bridge = NULL;
|
|
|
|
const char *vifname = NULL;
|
|
|
|
const char *rate = NULL;
|
|
|
|
|
|
|
|
keyvals = g_strsplit(entry, ",", 0);
|
|
|
|
|
|
|
|
for (keyval = keyvals; keyval && *keyval; keyval++) {
|
|
|
|
const char *key = *keyval;
|
|
|
|
char *val = strchr(key, '=');
|
|
|
|
|
|
|
|
virSkipSpaces(&key);
|
|
|
|
|
|
|
|
if (!val)
|
2018-06-14 06:59:52 +02:00
|
|
|
return NULL;
|
2021-03-02 11:49:34 +01:00
|
|
|
|
|
|
|
val++;
|
2018-06-14 06:59:52 +02:00
|
|
|
|
|
|
|
if (STRPREFIX(key, "mac=")) {
|
2021-03-02 11:49:34 +01:00
|
|
|
mac = val;
|
2018-06-14 06:59:52 +02:00
|
|
|
} else if (STRPREFIX(key, "bridge=")) {
|
2021-03-02 11:49:34 +01:00
|
|
|
bridge = val;
|
2018-06-14 06:59:52 +02:00
|
|
|
} else if (STRPREFIX(key, "script=")) {
|
2021-03-02 11:49:34 +01:00
|
|
|
script = val;
|
2018-06-14 06:59:52 +02:00
|
|
|
} else if (STRPREFIX(key, "model=")) {
|
2021-03-02 11:49:34 +01:00
|
|
|
model = val;
|
2018-06-14 06:59:52 +02:00
|
|
|
} else if (STRPREFIX(key, "type=")) {
|
2021-03-02 11:49:34 +01:00
|
|
|
type = val;
|
2018-06-14 06:59:52 +02:00
|
|
|
} else if (STRPREFIX(key, "vifname=")) {
|
2021-03-02 11:49:34 +01:00
|
|
|
vifname = val;
|
2018-06-14 06:59:52 +02:00
|
|
|
} else if (STRPREFIX(key, "ip=")) {
|
2021-03-02 11:49:34 +01:00
|
|
|
ip = val;
|
2018-06-14 06:59:52 +02:00
|
|
|
} else if (STRPREFIX(key, "rate=")) {
|
2021-03-02 11:49:34 +01:00
|
|
|
rate = val;
|
2018-06-14 06:59:52 +02:00
|
|
|
}
|
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2019-08-08 18:55:01 +04:00
|
|
|
if (!(net = virDomainNetDefNew(NULL)))
|
2018-06-14 06:59:52 +02:00
|
|
|
goto cleanup;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2021-03-02 11:49:34 +01:00
|
|
|
if (mac) {
|
2018-06-14 06:59:52 +02:00
|
|
|
if (virMacAddrParse(mac, &net->mac) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("malformed mac address '%s'"), mac);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2021-03-02 11:49:34 +01:00
|
|
|
if (bridge || STREQ_NULLABLE(script, "vif-bridge") ||
|
2018-06-14 06:59:52 +02:00
|
|
|
STREQ_NULLABLE(script, "vif-vnic")) {
|
|
|
|
net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
|
|
|
|
} else {
|
|
|
|
net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
|
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2021-03-02 11:49:34 +01:00
|
|
|
if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE && bridge) {
|
2018-11-16 13:08:23 -07:00
|
|
|
if (xenParseVifBridge(net, bridge) < 0)
|
2018-06-14 06:59:52 +02:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2021-03-02 11:49:34 +01:00
|
|
|
if (ip) {
|
2021-02-05 18:35:07 +01:00
|
|
|
char **ip_list = g_strsplit(ip, " ", 0);
|
2018-06-14 06:59:52 +02:00
|
|
|
size_t i;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2018-06-14 06:59:52 +02:00
|
|
|
if (!ip_list)
|
|
|
|
goto cleanup;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2018-06-14 06:59:52 +02:00
|
|
|
for (i = 0; ip_list[i]; i++) {
|
|
|
|
if (virDomainNetAppendIPAddress(net, ip_list[i], 0, 0) < 0) {
|
2020-08-02 19:36:03 +02:00
|
|
|
g_strfreev(ip_list);
|
2018-06-14 06:59:52 +02:00
|
|
|
goto cleanup;
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
2018-06-14 06:59:52 +02:00
|
|
|
}
|
2020-08-02 19:36:03 +02:00
|
|
|
g_strfreev(ip_list);
|
2018-06-14 06:59:52 +02:00
|
|
|
}
|
2017-12-07 03:27:46 +01:00
|
|
|
|
2019-10-20 13:49:46 +02:00
|
|
|
if (script && script[0])
|
|
|
|
net->script = g_strdup(script);
|
2017-12-13 20:15:49 +01:00
|
|
|
|
2021-03-02 11:49:34 +01:00
|
|
|
if (model) {
|
2019-01-17 19:12:27 -05:00
|
|
|
if (virDomainNetSetModelString(net, model) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
2021-03-02 11:49:34 +01:00
|
|
|
if (type && STREQ(type, vif_typename))
|
2019-01-17 19:12:27 -05:00
|
|
|
net->model = VIR_DOMAIN_NET_MODEL_NETFRONT;
|
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2021-03-02 11:49:34 +01:00
|
|
|
if (vifname && vifname[0])
|
2019-10-20 13:49:46 +02:00
|
|
|
net->ifname = g_strdup(vifname);
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2021-03-02 11:49:34 +01:00
|
|
|
if (rate) {
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetDevBandwidth *bandwidth;
|
2018-06-14 06:59:52 +02:00
|
|
|
unsigned long long kbytes_per_sec;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2018-06-14 06:59:52 +02:00
|
|
|
if (xenParseSxprVifRate(rate, &kbytes_per_sec) < 0)
|
|
|
|
goto cleanup;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
bandwidth = g_new0(virNetDevBandwidth, 1);
|
|
|
|
bandwidth->out = g_new0(virNetDevBandwidthRate, 1);
|
2018-06-14 06:59:52 +02:00
|
|
|
bandwidth->out->average = kbytes_per_sec;
|
|
|
|
net->bandwidth = bandwidth;
|
|
|
|
}
|
2015-12-28 15:26:17 -07:00
|
|
|
|
2019-10-16 13:45:15 +02:00
|
|
|
ret = g_steal_pointer(&net);
|
2015-12-28 15:26:17 -07:00
|
|
|
|
2018-06-14 06:59:52 +02:00
|
|
|
cleanup:
|
|
|
|
virDomainNetDefFree(net);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenParseVifList(virConf *conf, virDomainDef *def, const char *vif_typename)
|
2018-06-14 06:59:52 +02:00
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virConfValue *list = virConfGetValue(conf, "vif");
|
2018-06-14 06:59:52 +02:00
|
|
|
|
|
|
|
if (!list || list->type != VIR_CONF_LIST)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (list = list->list; list; list = list->next) {
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainNetDef *net = NULL;
|
2018-06-14 06:59:52 +02:00
|
|
|
int rc;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2018-06-14 06:59:52 +02:00
|
|
|
if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!(net = xenParseVif(list->str, vif_typename)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
rc = VIR_APPEND_ELEMENT(def->nets, def->nnets, net);
|
|
|
|
if (rc < 0) {
|
2014-08-15 20:52:15 -06:00
|
|
|
virDomainNetDefFree(net);
|
2018-06-14 06:59:52 +02:00
|
|
|
return -1;
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-03 09:30:11 +02:00
|
|
|
/**
|
|
|
|
* xenParseSxprSound:
|
|
|
|
* @def: the domain config
|
|
|
|
* @str: comma separated list of sound models
|
|
|
|
*
|
|
|
|
* This parses out sound devices from the domain S-expression
|
|
|
|
*
|
|
|
|
* Returns 0 if successful or -1 if failed.
|
|
|
|
*/
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenParseSxprSound(virDomainDef *def,
|
2019-07-03 09:30:11 +02:00
|
|
|
const char *str)
|
|
|
|
{
|
|
|
|
if (STREQ(str, "all")) {
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Special compatibility code for Xen with a bogus
|
|
|
|
* sound=all in config.
|
|
|
|
*
|
|
|
|
* NB deliberately, don't include all possible
|
|
|
|
* sound models anymore, just the 2 that were
|
|
|
|
* historically present in Xen's QEMU.
|
|
|
|
*
|
|
|
|
* ie just es1370 + sb16.
|
|
|
|
*
|
|
|
|
* Hence use of MODEL_ES1370 + 1, instead of MODEL_LAST
|
|
|
|
*/
|
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
def->sounds = g_new0(virDomainSoundDef *,
|
2020-09-23 20:43:09 +02:00
|
|
|
VIR_DOMAIN_SOUND_MODEL_ES1370 + 1);
|
2019-07-03 09:30:11 +02:00
|
|
|
|
|
|
|
for (i = 0; i < (VIR_DOMAIN_SOUND_MODEL_ES1370 + 1); i++) {
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainSoundDef *sound = g_new0(virDomainSoundDef, 1);
|
2019-07-03 09:30:11 +02:00
|
|
|
sound->model = i;
|
|
|
|
def->sounds[def->nsounds++] = sound;
|
|
|
|
}
|
|
|
|
} else {
|
2021-03-02 12:04:41 +01:00
|
|
|
g_autofree char *sounds = g_strdup(str);
|
|
|
|
char *sound = sounds;
|
|
|
|
int model;
|
2019-07-03 09:30:11 +02:00
|
|
|
|
2021-03-02 12:04:41 +01:00
|
|
|
while (*sound != '\0') {
|
|
|
|
char *next = strchr(sound, ',');
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainSoundDef *snddef;
|
2019-07-03 09:30:11 +02:00
|
|
|
|
2021-03-02 12:04:41 +01:00
|
|
|
if (next)
|
|
|
|
*next = '\0';
|
2019-07-03 09:30:11 +02:00
|
|
|
|
2021-03-02 12:04:41 +01:00
|
|
|
if ((model = virDomainSoundModelTypeFromString(sound)) < 0)
|
2019-07-03 09:30:11 +02:00
|
|
|
return -1;
|
|
|
|
|
2021-03-02 12:04:41 +01:00
|
|
|
snddef = g_new0(virDomainSoundDef, 1);
|
|
|
|
snddef->model = model;
|
|
|
|
|
|
|
|
ignore_value(VIR_APPEND_ELEMENT(def->sounds, def->nsounds, snddef));
|
|
|
|
|
|
|
|
if (!next)
|
|
|
|
break;
|
|
|
|
|
|
|
|
sound = next + 1;
|
|
|
|
}
|
2019-07-03 09:30:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-08-15 20:52:15 -06:00
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenParseEmulatedDevices(virConf *conf, virDomainDef *def)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2019-10-15 15:16:31 +02:00
|
|
|
g_autofree char *str = NULL;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2015-04-16 20:11:06 -04:00
|
|
|
if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
|
2014-08-15 20:52:15 -06:00
|
|
|
if (xenConfigGetString(conf, "soundhw", &str, NULL) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (str &&
|
|
|
|
xenParseSxprSound(def, str) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenParseGeneralMeta(virConf *conf, virDomainDef *def, virCaps *caps)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virCapsDomainData *capsdata = NULL;
|
2019-10-15 15:16:31 +02:00
|
|
|
g_autofree char *str = NULL;
|
2018-11-26 20:34:40 +01:00
|
|
|
int ret = -1;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
if (xenConfigCopyString(conf, "name", &def->name) < 0)
|
2015-04-17 20:15:25 -04:00
|
|
|
goto out;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
if (xenConfigGetUUID(conf, "uuid", def->uuid) < 0)
|
2015-04-17 20:15:25 -04:00
|
|
|
goto out;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2018-11-26 20:34:40 +01:00
|
|
|
def->os.type = VIR_DOMAIN_OSTYPE_XEN;
|
|
|
|
|
2018-11-26 20:34:39 +01:00
|
|
|
if (xenConfigGetString(conf, "type", &str, NULL) == 0 && str) {
|
|
|
|
if (STREQ(str, "pv")) {
|
2018-11-26 20:34:40 +01:00
|
|
|
def->os.type = VIR_DOMAIN_OSTYPE_XEN;
|
|
|
|
} else if (STREQ(str, "pvh")) {
|
|
|
|
def->os.type = VIR_DOMAIN_OSTYPE_XENPVH;
|
2018-11-26 20:34:39 +01:00
|
|
|
} else if (STREQ(str, "hvm")) {
|
2018-11-26 20:34:40 +01:00
|
|
|
def->os.type = VIR_DOMAIN_OSTYPE_HVM;
|
2018-11-26 20:34:39 +01:00
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("type %s is not supported"), str);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((xenConfigGetString(conf, "builder", &str, "linux") == 0) &&
|
2018-11-26 20:34:40 +01:00
|
|
|
STREQ(str, "hvm")) {
|
|
|
|
def->os.type = VIR_DOMAIN_OSTYPE_HVM;
|
|
|
|
}
|
2018-11-26 20:34:39 +01:00
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2015-04-17 20:15:25 -04:00
|
|
|
if (!(capsdata = virCapabilitiesDomainDataLookup(caps, def->os.type,
|
|
|
|
VIR_ARCH_NONE, def->virtType, NULL, NULL)))
|
|
|
|
goto out;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2015-04-17 20:15:25 -04:00
|
|
|
def->os.arch = capsdata->arch;
|
2019-10-20 13:49:46 +02:00
|
|
|
def->os.machine = g_strdup(capsdata->machinetype);
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2015-04-17 20:15:25 -04:00
|
|
|
ret = 0;
|
|
|
|
out:
|
|
|
|
VIR_FREE(capsdata);
|
|
|
|
return ret;
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A convenience function for parsing all config common to both XM and XL
|
|
|
|
*/
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenParseConfigCommon(virConf *conf,
|
|
|
|
virDomainDef *def,
|
|
|
|
virCaps *caps,
|
2016-06-29 14:55:24 +02:00
|
|
|
const char *nativeFormat,
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainXMLOption *xmlopt)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
|
|
|
if (xenParseGeneralMeta(conf, def, caps) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (xenParseMem(conf, def) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (xenParseEventsActions(conf, def) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2020-04-15 21:48:42 -06:00
|
|
|
if (xenParseCPU(conf, def, xmlopt) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (xenParseHypervisorFeatures(conf, def) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2015-12-04 16:08:59 -07:00
|
|
|
if (xenParseTimeOffset(conf, def) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2020-11-20 13:29:14 +01:00
|
|
|
if (xenConfigCopyStringOpt(conf, "device_model_override", &def->emulator) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2016-05-17 17:34:45 +08:00
|
|
|
if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XL)) {
|
2018-06-14 06:59:52 +02:00
|
|
|
if (xenParseVifList(conf, def, "vif") < 0)
|
2016-05-17 17:34:45 +08:00
|
|
|
return -1;
|
|
|
|
} else if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XM)) {
|
2018-06-14 06:59:52 +02:00
|
|
|
if (xenParseVifList(conf, def, "netfront") < 0)
|
2016-05-17 17:34:45 +08:00
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("unsupported config type %s"), nativeFormat);
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
2016-05-17 17:34:45 +08:00
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2018-05-28 00:28:23 +02:00
|
|
|
if (xenParsePCIList(conf, def) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (xenParseEmulatedDevices(conf, def) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2015-12-04 16:08:59 -07:00
|
|
|
if (xenParseVfb(conf, def) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2016-08-18 10:20:49 +08:00
|
|
|
if (xenParseCharDev(conf, def, nativeFormat) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-03 09:15:37 +02:00
|
|
|
/**
|
|
|
|
* xenFormatSxprChr:
|
|
|
|
* @def: the domain config
|
|
|
|
* @buf: a buffer for the result S-expression
|
|
|
|
*
|
|
|
|
* Convert the character device part of the domain config into a S-expression
|
|
|
|
* in buf.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, -1 in case of error
|
|
|
|
*/
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenFormatSxprChr(virDomainChrDef *def,
|
|
|
|
virBuffer *buf)
|
2019-07-03 09:15:37 +02:00
|
|
|
{
|
|
|
|
const char *type = virDomainChrTypeToString(def->source->type);
|
|
|
|
|
|
|
|
if (!type) {
|
|
|
|
virReportError(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:
|
|
|
|
virBufferAdd(buf, type, -1);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_FILE:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_PIPE:
|
|
|
|
virBufferAsprintf(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:
|
|
|
|
virBufferAsprintf(buf, "%s:%s:%s%s",
|
|
|
|
(def->source->data.tcp.protocol
|
|
|
|
== VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW ?
|
|
|
|
"tcp" : "telnet"),
|
|
|
|
NULLSTR_EMPTY(def->source->data.tcp.host),
|
|
|
|
NULLSTR_EMPTY(def->source->data.tcp.service),
|
|
|
|
(def->source->data.tcp.listen ?
|
|
|
|
",server,nowait" : ""));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UDP:
|
|
|
|
virBufferAsprintf(buf, "%s:%s:%s@%s:%s", type,
|
|
|
|
NULLSTR_EMPTY(def->source->data.udp.connectHost),
|
|
|
|
NULLSTR_EMPTY(def->source->data.udp.connectService),
|
|
|
|
NULLSTR_EMPTY(def->source->data.udp.bindHost),
|
|
|
|
NULLSTR_EMPTY(def->source->data.udp.bindService));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
|
|
|
virBufferAsprintf(buf, "%s:", type);
|
|
|
|
virBufferEscapeSexpr(buf, "%s", def->source->data.nix.path);
|
|
|
|
if (def->source->data.nix.listen)
|
|
|
|
virBufferAddLit(buf, ",server,nowait");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported chr device type '%s'"), type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-08-15 20:52:15 -06:00
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenFormatSerial(virConfValue *list, virDomainChrDef *serial)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2020-07-02 18:21:30 -04:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2021-03-11 08:16:13 +01:00
|
|
|
virConfValue *val;
|
|
|
|
virConfValue *tmp;
|
2014-08-15 20:52:15 -06:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (serial) {
|
|
|
|
ret = xenFormatSxprChr(serial, &buf);
|
|
|
|
if (ret < 0)
|
2020-07-02 23:19:45 -04:00
|
|
|
return -1;
|
2014-08-15 20:52:15 -06:00
|
|
|
} else {
|
|
|
|
virBufferAddLit(&buf, "none");
|
|
|
|
}
|
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
val = g_new0(virConfValue, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-12-07 03:27:45 +01:00
|
|
|
char *
|
2021-03-11 08:16:13 +01:00
|
|
|
xenMakeIPList(virNetDevIPInfo *guestIP)
|
2017-12-07 03:27:45 +01:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
char **address_array;
|
|
|
|
char *ret = NULL;
|
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
address_array = g_new0(char *, guestIP->nips + 1);
|
2017-12-07 03:27:45 +01:00
|
|
|
|
|
|
|
for (i = 0; i < guestIP->nips; i++) {
|
|
|
|
address_array[i] = virSocketAddrFormat(&guestIP->ips[i]->address);
|
|
|
|
if (!address_array[i])
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2021-02-05 21:33:47 +01:00
|
|
|
ret = g_strjoinv(" ", address_array);
|
2017-12-07 03:27:45 +01:00
|
|
|
|
|
|
|
cleanup:
|
2020-08-02 19:36:03 +02:00
|
|
|
g_strfreev(address_array);
|
2017-12-07 03:27:45 +01:00
|
|
|
return ret;
|
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
static int
|
|
|
|
xenFormatNet(virConnectPtr conn,
|
2021-03-11 08:16:13 +01:00
|
|
|
virConfValue *list,
|
|
|
|
virDomainNetDef *net,
|
2016-05-17 17:34:45 +08:00
|
|
|
int hvm,
|
|
|
|
const char *vif_typename)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2020-07-02 18:21:30 -04:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2021-03-11 08:16:13 +01:00
|
|
|
virConfValue *val;
|
|
|
|
virConfValue *tmp;
|
2014-08-15 20:52:15 -06:00
|
|
|
char macaddr[VIR_MAC_STRING_BUFLEN];
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, "mac=%s", virMacAddrFormat(&net->mac, macaddr));
|
|
|
|
|
|
|
|
switch (net->type) {
|
|
|
|
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
2018-11-16 13:08:23 -07:00
|
|
|
{
|
2019-10-01 13:56:35 -04:00
|
|
|
const virNetDevVPortProfile *port_profile = virDomainNetGetActualVirtPortProfile(net);
|
2019-10-01 12:25:47 -04:00
|
|
|
const virNetDevVlan *virt_vlan = virDomainNetGetActualVlan(net);
|
2018-11-16 13:08:23 -07:00
|
|
|
const char *script = net->script;
|
|
|
|
size_t i;
|
|
|
|
|
2014-08-15 20:52:15 -06:00
|
|
|
virBufferAsprintf(&buf, ",bridge=%s", net->data.bridge.brname);
|
2018-11-16 13:08:23 -07:00
|
|
|
if (port_profile &&
|
|
|
|
port_profile->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
|
|
|
|
if (!script)
|
|
|
|
script = "vif-openvswitch";
|
|
|
|
/*
|
|
|
|
* libxl_device_nic->bridge supports an extended format for
|
|
|
|
* specifying VLAN tags and trunks
|
|
|
|
*
|
|
|
|
* BRIDGE_NAME[.VLAN][:TRUNK:TRUNK]
|
|
|
|
*/
|
|
|
|
if (virt_vlan && virt_vlan->nTags > 0) {
|
|
|
|
if (virt_vlan->trunk) {
|
|
|
|
for (i = 0; i < virt_vlan->nTags; i++)
|
|
|
|
virBufferAsprintf(&buf, ":%d", virt_vlan->tag[i]);
|
|
|
|
} else {
|
|
|
|
virBufferAsprintf(&buf, ".%d", virt_vlan->tag[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-07 03:27:46 +01:00
|
|
|
if (net->guestIP.nips > 0) {
|
|
|
|
char *ipStr = xenMakeIPList(&net->guestIP);
|
2014-07-22 11:09:48 +02:00
|
|
|
virBufferAsprintf(&buf, ",ip=%s", ipStr);
|
|
|
|
VIR_FREE(ipStr);
|
|
|
|
}
|
2018-11-16 13:08:23 -07:00
|
|
|
virBufferAsprintf(&buf, ",script=%s", script ? script : DEFAULT_VIF_SCRIPT);
|
|
|
|
}
|
|
|
|
break;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
|
|
|
if (net->script)
|
|
|
|
virBufferAsprintf(&buf, ",script=%s", net->script);
|
2017-12-07 03:27:46 +01:00
|
|
|
if (net->guestIP.nips > 0) {
|
|
|
|
char *ipStr = xenMakeIPList(&net->guestIP);
|
2014-07-22 11:09:48 +02:00
|
|
|
virBufferAsprintf(&buf, ",ip=%s", ipStr);
|
|
|
|
VIR_FREE(ipStr);
|
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
|
|
|
{
|
|
|
|
virNetworkPtr network = virNetworkLookupByName(conn, net->data.network.name);
|
|
|
|
char *bridge;
|
|
|
|
if (!network) {
|
|
|
|
virReportError(VIR_ERR_NO_NETWORK, "%s",
|
|
|
|
net->data.network.name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
bridge = virNetworkGetBridgeName(network);
|
2014-11-25 07:42:58 -05:00
|
|
|
virObjectUnref(network);
|
2014-08-15 20:52:15 -06:00
|
|
|
if (!bridge) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("network %s is not active"),
|
|
|
|
net->data.network.name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, ",bridge=%s", bridge);
|
|
|
|
virBufferAsprintf(&buf, ",script=%s", DEFAULT_VIF_SCRIPT);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2018-02-14 09:43:59 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
|
|
|
|
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_HOSTDEV:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_UDP:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_USER:
|
2020-10-14 12:08:25 -05:00
|
|
|
case VIR_DOMAIN_NET_TYPE_VDPA:
|
2018-02-14 09:43:59 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported net type '%s'"),
|
|
|
|
virDomainNetTypeToString(net->type));
|
2020-07-02 23:19:45 -04:00
|
|
|
return -1;
|
2018-02-14 09:43:59 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_LAST:
|
2014-08-15 20:52:15 -06:00
|
|
|
default:
|
2018-02-14 09:43:59 +00:00
|
|
|
virReportEnumRangeError(virDomainNetType, net->type);
|
2020-07-02 23:19:45 -04:00
|
|
|
return -1;
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
|
|
|
|
2019-01-17 17:06:28 -05:00
|
|
|
if (virDomainNetGetModelString(net)) {
|
|
|
|
if (!hvm) {
|
|
|
|
virBufferAsprintf(&buf, ",model=%s",
|
|
|
|
virDomainNetGetModelString(net));
|
2014-09-03 13:04:59 -06:00
|
|
|
} else {
|
2019-01-17 19:12:27 -05:00
|
|
|
if (net->model == VIR_DOMAIN_NET_MODEL_NETFRONT)
|
2019-01-17 17:06:28 -05:00
|
|
|
virBufferAsprintf(&buf, ",type=%s", vif_typename);
|
|
|
|
else
|
|
|
|
virBufferAsprintf(&buf, ",model=%s",
|
|
|
|
virDomainNetGetModelString(net));
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net->ifname)
|
|
|
|
virBufferAsprintf(&buf, ",vifname=%s",
|
|
|
|
net->ifname);
|
|
|
|
|
2015-12-28 15:26:17 -07:00
|
|
|
if (net->bandwidth && net->bandwidth->out && net->bandwidth->out->average)
|
|
|
|
virBufferAsprintf(&buf, ",rate=%lluKB/s", net->bandwidth->out->average);
|
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
val = g_new0(virConfValue, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenFormatPCI(virConf *conf, virDomainDef *def)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virConfValue *pciVal = NULL;
|
2014-08-15 20:52:15 -06:00
|
|
|
int hasPCI = 0;
|
|
|
|
size_t 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;
|
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
pciVal = g_new0(virConfValue, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
pciVal->type = VIR_CONF_LIST;
|
|
|
|
pciVal->list = NULL;
|
|
|
|
|
|
|
|
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) {
|
2021-03-11 08:16:13 +01:00
|
|
|
virConfValue *val;
|
|
|
|
virConfValue *tmp;
|
2014-08-15 20:52:15 -06:00
|
|
|
char *buf;
|
2020-08-14 14:47:09 -06:00
|
|
|
const char *permissive_str = NULL;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2020-08-14 14:47:09 -06:00
|
|
|
switch (def->hostdevs[i]->writeFiltering) {
|
|
|
|
case VIR_TRISTATE_BOOL_YES:
|
|
|
|
permissive_str = ",permissive=0";
|
|
|
|
break;
|
|
|
|
case VIR_TRISTATE_BOOL_NO:
|
|
|
|
permissive_str = ",permissive=1";
|
|
|
|
break;
|
|
|
|
case VIR_TRISTATE_BOOL_ABSENT:
|
|
|
|
case VIR_TRISTATE_BOOL_LAST:
|
|
|
|
permissive_str = "";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = g_strdup_printf("%04x:%02x:%02x.%x%s",
|
2019-10-22 15:26:14 +02:00
|
|
|
def->hostdevs[i]->source.subsys.u.pci.addr.domain,
|
|
|
|
def->hostdevs[i]->source.subsys.u.pci.addr.bus,
|
|
|
|
def->hostdevs[i]->source.subsys.u.pci.addr.slot,
|
2020-08-14 14:47:09 -06:00
|
|
|
def->hostdevs[i]->source.subsys.u.pci.addr.function,
|
|
|
|
permissive_str);
|
|
|
|
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
val = g_new0(virConfValue, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
val->type = VIR_CONF_STRING;
|
|
|
|
val->str = buf;
|
|
|
|
tmp = pciVal->list;
|
|
|
|
while (tmp && tmp->next)
|
|
|
|
tmp = tmp->next;
|
|
|
|
if (tmp)
|
|
|
|
tmp->next = val;
|
|
|
|
else
|
|
|
|
pciVal->list = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pciVal->list != NULL) {
|
|
|
|
int ret = virConfSetValue(conf, "pci", pciVal);
|
|
|
|
pciVal = NULL;
|
|
|
|
if (ret < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
VIR_FREE(pciVal);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenFormatGeneralMeta(virConf *conf, virDomainDef *def)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
|
|
|
char uuid[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetString(conf, "name", def->name) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
virUUIDFormat(def->uuid, uuid);
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetString(conf, "uuid", uuid) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenFormatMem(virConf *conf, virDomainDef *def)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetInt(conf, "maxmem",
|
2016-06-15 15:34:04 +02:00
|
|
|
VIR_DIV_UP(virDomainDefGetMemoryTotal(def), 1024)) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetInt(conf, "memory",
|
|
|
|
VIR_DIV_UP(def->mem.cur_balloon, 1024)) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenFormatTimeOffset(virConf *conf, virDomainDef *def)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
|
|
|
int vmlocaltime;
|
|
|
|
|
2015-12-04 16:08:59 -07:00
|
|
|
if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
|
|
|
|
/* >=3.1 HV: VARIABLE */
|
|
|
|
int rtc_timeoffset;
|
|
|
|
|
2014-08-15 20:52:15 -06:00
|
|
|
switch (def->clock.offset) {
|
2015-12-04 16:08:59 -07:00
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
|
|
|
|
vmlocaltime = (int)def->clock.data.variable.basis;
|
|
|
|
rtc_timeoffset = def->clock.data.variable.adjustment;
|
|
|
|
break;
|
2014-08-15 20:52:15 -06:00
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_UTC:
|
2015-12-04 16:08:59 -07:00
|
|
|
if (def->clock.data.utc_reset) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("unsupported clock adjustment='reset'"));
|
|
|
|
return -1;
|
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
vmlocaltime = 0;
|
2015-12-04 16:08:59 -07:00
|
|
|
rtc_timeoffset = 0;
|
2014-08-15 20:52:15 -06:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
|
2015-12-04 16:08:59 -07:00
|
|
|
if (def->clock.data.utc_reset) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("unsupported clock adjustment='reset'"));
|
|
|
|
return -1;
|
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
vmlocaltime = 1;
|
2015-12-04 16:08:59 -07:00
|
|
|
rtc_timeoffset = 0;
|
2014-08-15 20:52:15 -06:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported clock offset='%s'"),
|
|
|
|
virDomainClockOffsetTypeToString(def->clock.offset));
|
|
|
|
return -1;
|
|
|
|
}
|
2015-12-04 16:08:59 -07:00
|
|
|
if (xenConfigSetInt(conf, "rtc_timeoffset", rtc_timeoffset) < 0)
|
|
|
|
return -1;
|
2014-08-15 20:52:15 -06:00
|
|
|
} else {
|
2015-12-04 16:08:59 -07:00
|
|
|
/* PV: UTC and LOCALTIME */
|
|
|
|
switch (def->clock.offset) {
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_UTC:
|
|
|
|
vmlocaltime = 0;
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
|
|
|
|
vmlocaltime = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported clock offset='%s'"),
|
|
|
|
virDomainClockOffsetTypeToString(def->clock.offset));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} /* !hvm */
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetInt(conf, "localtime", vmlocaltime) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenFormatEventActions(virConf *conf, virDomainDef *def)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
|
|
|
const char *lifecycle = NULL;
|
|
|
|
|
2017-10-10 14:32:58 +02:00
|
|
|
if (!(lifecycle = virDomainLifecycleActionTypeToString(def->onPoweroff))) {
|
2014-08-15 20:52:15 -06:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected lifecycle action %d"), def->onPoweroff);
|
|
|
|
return -1;
|
|
|
|
}
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetString(conf, "on_poweroff", lifecycle) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
2017-10-10 14:32:58 +02:00
|
|
|
if (!(lifecycle = virDomainLifecycleActionTypeToString(def->onReboot))) {
|
2014-08-15 20:52:15 -06:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected lifecycle action %d"), def->onReboot);
|
|
|
|
return -1;
|
|
|
|
}
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetString(conf, "on_reboot", lifecycle) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
2017-10-10 14:51:38 +02:00
|
|
|
if (!(lifecycle = virDomainLifecycleActionTypeToString(def->onCrash))) {
|
2014-08-15 20:52:15 -06:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected lifecycle action %d"), def->onCrash);
|
|
|
|
return -1;
|
|
|
|
}
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetString(conf, "on_crash", lifecycle) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenFormatCharDev(virConf *conf, virDomainDef *def,
|
2016-08-18 10:20:49 +08:00
|
|
|
const char *nativeFormat)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
2015-04-16 20:11:06 -04:00
|
|
|
if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
|
2014-08-15 20:52:15 -06:00
|
|
|
if (def->nparallels) {
|
2020-07-02 18:21:30 -04:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2014-08-15 20:52:15 -06:00
|
|
|
char *str;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = xenFormatSxprChr(def->parallels[0], &buf);
|
|
|
|
str = virBufferContentAndReset(&buf);
|
|
|
|
if (ret == 0)
|
2014-09-11 07:10:32 +03:00
|
|
|
ret = xenConfigSetString(conf, "parallel", str);
|
2014-08-15 20:52:15 -06:00
|
|
|
VIR_FREE(str);
|
|
|
|
if (ret < 0)
|
|
|
|
return -1;
|
|
|
|
} else {
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetString(conf, "parallel", "none") < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->nserials) {
|
|
|
|
if ((def->nserials == 1) && (def->serials[0]->target.port == 0)) {
|
2020-07-02 18:21:30 -04:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2014-08-15 20:52:15 -06:00
|
|
|
char *str;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = xenFormatSxprChr(def->serials[0], &buf);
|
|
|
|
str = virBufferContentAndReset(&buf);
|
|
|
|
if (ret == 0)
|
2014-09-11 07:10:32 +03:00
|
|
|
ret = xenConfigSetString(conf, "serial", str);
|
2014-08-15 20:52:15 -06:00
|
|
|
VIR_FREE(str);
|
|
|
|
if (ret < 0)
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
size_t j = 0;
|
|
|
|
int maxport = -1, port;
|
2021-03-11 08:16:13 +01:00
|
|
|
virConfValue *serialVal = NULL;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2016-08-18 10:20:49 +08:00
|
|
|
if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XM)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Multiple serial devices are not supported by xen-xm"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
serialVal = g_new0(virConfValue, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
serialVal->type = VIR_CONF_LIST;
|
|
|
|
serialVal->list = NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < def->nserials; i++)
|
|
|
|
if (def->serials[i]->target.port > maxport)
|
|
|
|
maxport = def->serials[i]->target.port;
|
|
|
|
|
|
|
|
for (port = 0; port <= maxport; port++) {
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainChrDef *chr = NULL;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
for (j = 0; j < def->nserials; j++) {
|
|
|
|
if (def->serials[j]->target.port == port) {
|
|
|
|
chr = def->serials[j];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xenFormatSerial(serialVal, chr) < 0) {
|
|
|
|
VIR_FREE(serialVal);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (serialVal->list != NULL) {
|
|
|
|
int ret = virConfSetValue(conf, "serial", serialVal);
|
|
|
|
|
|
|
|
serialVal = NULL;
|
|
|
|
if (ret < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
VIR_FREE(serialVal);
|
|
|
|
}
|
|
|
|
} else {
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetString(conf, "serial", "none") < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenFormatCPUAllocation(virConf *conf, virDomainDef *def)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2021-02-16 18:37:09 -07:00
|
|
|
g_autofree char *cpus = NULL;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2015-12-15 14:47:40 -07:00
|
|
|
if (virDomainDefGetVcpus(def) < virDomainDefGetVcpusMax(def) &&
|
|
|
|
xenConfigSetInt(conf, "maxvcpus", virDomainDefGetVcpusMax(def)) < 0)
|
2021-02-16 18:37:09 -07:00
|
|
|
return -1;
|
2015-12-15 14:47:40 -07:00
|
|
|
if (xenConfigSetInt(conf, "vcpus", virDomainDefGetVcpus(def)) < 0)
|
2021-02-16 18:37:09 -07:00
|
|
|
return -1;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
if ((def->cpumask != NULL) &&
|
|
|
|
((cpus = virBitmapFormat(def->cpumask)) == NULL)) {
|
2021-02-16 18:37:09 -07:00
|
|
|
return -1;
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cpus &&
|
2014-09-11 07:10:32 +03:00
|
|
|
xenConfigSetString(conf, "cpus", cpus) < 0)
|
2021-02-16 18:37:09 -07:00
|
|
|
return -1;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2021-02-16 18:37:09 -07:00
|
|
|
return 0;
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenFormatHypervisorFeatures(virConf *conf, virDomainDef *def)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
|
|
|
size_t i;
|
2017-01-19 16:51:05 -07:00
|
|
|
bool hvm = !!(def->os.type == VIR_DOMAIN_OSTYPE_HVM);
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2017-01-19 16:51:05 -07:00
|
|
|
if (hvm) {
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetInt(conf, "pae",
|
|
|
|
(def->features[VIR_DOMAIN_FEATURE_PAE] ==
|
|
|
|
VIR_TRISTATE_SWITCH_ON) ? 1 : 0) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetInt(conf, "acpi",
|
|
|
|
(def->features[VIR_DOMAIN_FEATURE_ACPI] ==
|
|
|
|
VIR_TRISTATE_SWITCH_ON) ? 1 : 0) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetInt(conf, "apic",
|
|
|
|
(def->features[VIR_DOMAIN_FEATURE_APIC] ==
|
|
|
|
VIR_TRISTATE_SWITCH_ON) ? 1 : 0) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2016-02-22 18:50:19 -07:00
|
|
|
if (def->features[VIR_DOMAIN_FEATURE_HAP] == VIR_TRISTATE_SWITCH_OFF) {
|
|
|
|
if (xenConfigSetInt(conf, "hap", 0) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2015-12-04 16:08:59 -07:00
|
|
|
if (xenConfigSetInt(conf, "viridian",
|
|
|
|
(def->features[VIR_DOMAIN_FEATURE_VIRIDIAN] ==
|
|
|
|
VIR_TRISTATE_SWITCH_ON) ? 1 : 0) < 0)
|
|
|
|
return -1;
|
2020-04-14 04:37:06 +02:00
|
|
|
} else {
|
|
|
|
if (def->features[VIR_DOMAIN_FEATURE_XEN] == VIR_TRISTATE_SWITCH_ON) {
|
|
|
|
if (def->xen_features[VIR_DOMAIN_XEN_E820_HOST] == VIR_TRISTATE_SWITCH_ON)
|
|
|
|
if (xenConfigSetInt(conf, "e820_host", 1) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
2017-01-19 16:51:05 -07:00
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2020-04-16 08:31:48 -06:00
|
|
|
if (def->features[VIR_DOMAIN_FEATURE_XEN] == VIR_TRISTATE_SWITCH_ON) {
|
|
|
|
if (def->xen_features[VIR_DOMAIN_XEN_PASSTHROUGH] == VIR_TRISTATE_SWITCH_ON) {
|
|
|
|
if (def->xen_passthrough_mode == VIR_DOMAIN_XEN_PASSTHROUGH_MODE_SYNC_PT ||
|
|
|
|
def->xen_passthrough_mode == VIR_DOMAIN_XEN_PASSTHROUGH_MODE_SHARE_PT) {
|
|
|
|
if (xenConfigSetString(conf, "passthrough",
|
|
|
|
virDomainXenPassthroughModeTypeToString(def->xen_passthrough_mode)) < 0)
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
if (xenConfigSetString(conf, "passthrough", "enabled") < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-19 16:51:05 -07:00
|
|
|
for (i = 0; i < def->clock.ntimers; i++) {
|
2018-04-25 14:42:34 +02:00
|
|
|
switch ((virDomainTimerNameType)def->clock.timers[i]->name) {
|
2017-01-19 16:51:05 -07:00
|
|
|
case VIR_DOMAIN_TIMER_NAME_TSC:
|
|
|
|
switch (def->clock.timers[i]->mode) {
|
|
|
|
case VIR_DOMAIN_TIMER_MODE_NATIVE:
|
|
|
|
if (xenConfigSetString(conf, "tsc_mode", "native") < 0)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_TIMER_MODE_PARAVIRT:
|
|
|
|
if (xenConfigSetString(conf, "tsc_mode", "native_paravirt") < 0)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_TIMER_MODE_EMULATE:
|
|
|
|
if (xenConfigSetString(conf, "tsc_mode", "always_emulate") < 0)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (xenConfigSetString(conf, "tsc_mode", "default") < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_TIMER_NAME_HPET:
|
|
|
|
if (hvm) {
|
|
|
|
int enable_hpet = def->clock.timers[i]->present != 0;
|
|
|
|
|
|
|
|
/* disable hpet if 'present' is 0, enable otherwise */
|
|
|
|
if (xenConfigSetInt(conf, "hpet", enable_hpet) < 0)
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported timer type (name) '%s'"),
|
|
|
|
virDomainTimerNameTypeToString(def->clock.timers[i]->name));
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
2017-01-19 16:51:05 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_TIMER_NAME_PLATFORM:
|
|
|
|
case VIR_DOMAIN_TIMER_NAME_KVMCLOCK:
|
|
|
|
case VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK:
|
|
|
|
case VIR_DOMAIN_TIMER_NAME_RTC:
|
|
|
|
case VIR_DOMAIN_TIMER_NAME_PIT:
|
2020-02-06 16:54:45 +01:00
|
|
|
case VIR_DOMAIN_TIMER_NAME_ARMVTIMER:
|
2017-01-19 16:51:05 -07:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unsupported timer type (name) '%s'"),
|
|
|
|
virDomainTimerNameTypeToString(def->clock.timers[i]->name));
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_TIMER_NAME_LAST:
|
|
|
|
break;
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenFormatEmulator(virConf *conf, virDomainDef *def)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
|
|
|
if (def->emulator &&
|
2020-11-20 13:29:14 +01:00
|
|
|
xenConfigSetString(conf, "device_model_override", def->emulator) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenFormatVfb(virConf *conf, virDomainDef *def)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2015-04-16 20:11:06 -04:00
|
|
|
int hvm = def->os.type == VIR_DOMAIN_OSTYPE_HVM ? 1 : 0;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
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>
2015-01-09 17:12:52 -07:00
|
|
|
if (def->ngraphics == 1 &&
|
|
|
|
def->graphics[0]->type != VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
|
2015-12-04 16:08:59 -07:00
|
|
|
if (hvm) {
|
2014-08-15 20:52:15 -06:00
|
|
|
if (def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetInt(conf, "sdl", 1) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetInt(conf, "vnc", 0) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (def->graphics[0]->data.sdl.display &&
|
2014-09-11 07:10:32 +03:00
|
|
|
xenConfigSetString(conf, "display",
|
|
|
|
def->graphics[0]->data.sdl.display) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (def->graphics[0]->data.sdl.xauth &&
|
2014-09-11 07:10:32 +03:00
|
|
|
xenConfigSetString(conf, "xauthority",
|
|
|
|
def->graphics[0]->data.sdl.xauth) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
} else {
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainGraphicsListenDef *glisten;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetInt(conf, "sdl", 0) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetInt(conf, "vnc", 1) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2014-09-11 07:10:32 +03:00
|
|
|
if (xenConfigSetInt(conf, "vncunused",
|
2014-08-15 20:52:15 -06:00
|
|
|
def->graphics[0]->data.vnc.autoport ? 1 : 0) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!def->graphics[0]->data.vnc.autoport &&
|
2014-09-11 07:10:32 +03:00
|
|
|
xenConfigSetInt(conf, "vncdisplay",
|
|
|
|
def->graphics[0]->data.vnc.port - 5900) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2016-05-17 14:55:55 +02:00
|
|
|
if ((glisten = virDomainGraphicsGetListen(def->graphics[0], 0)) &&
|
|
|
|
glisten->address &&
|
|
|
|
xenConfigSetString(conf, "vnclisten", glisten->address) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (def->graphics[0]->data.vnc.auth.passwd &&
|
2014-09-11 07:10:32 +03:00
|
|
|
xenConfigSetString(conf, "vncpasswd",
|
|
|
|
def->graphics[0]->data.vnc.auth.passwd) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (def->graphics[0]->data.vnc.keymap &&
|
2014-09-11 07:10:32 +03:00
|
|
|
xenConfigSetString(conf, "keymap",
|
|
|
|
def->graphics[0]->data.vnc.keymap) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
2021-03-11 08:16:13 +01:00
|
|
|
virConfValue *vfb;
|
|
|
|
virConfValue *disp;
|
2014-08-15 20:52:15 -06:00
|
|
|
char *vfbstr = NULL;
|
2020-07-02 18:21:30 -04:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
if (def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
|
|
|
|
virBufferAddLit(&buf, "type=sdl");
|
|
|
|
if (def->graphics[0]->data.sdl.display)
|
|
|
|
virBufferAsprintf(&buf, ",display=%s",
|
|
|
|
def->graphics[0]->data.sdl.display);
|
|
|
|
if (def->graphics[0]->data.sdl.xauth)
|
|
|
|
virBufferAsprintf(&buf, ",xauthority=%s",
|
|
|
|
def->graphics[0]->data.sdl.xauth);
|
|
|
|
} else {
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainGraphicsListenDef *glisten
|
2016-03-23 09:27:56 +01:00
|
|
|
= virDomainGraphicsGetListen(def->graphics[0], 0);
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
virBufferAddLit(&buf, "type=vnc");
|
|
|
|
virBufferAsprintf(&buf, ",vncunused=%d",
|
|
|
|
def->graphics[0]->data.vnc.autoport ? 1 : 0);
|
|
|
|
if (!def->graphics[0]->data.vnc.autoport)
|
|
|
|
virBufferAsprintf(&buf, ",vncdisplay=%d",
|
|
|
|
def->graphics[0]->data.vnc.port - 5900);
|
2016-05-17 14:55:55 +02:00
|
|
|
if (glisten && glisten->address)
|
|
|
|
virBufferAsprintf(&buf, ",vnclisten=%s", glisten->address);
|
2014-08-15 20:52:15 -06:00
|
|
|
if (def->graphics[0]->data.vnc.auth.passwd)
|
|
|
|
virBufferAsprintf(&buf, ",vncpasswd=%s",
|
|
|
|
def->graphics[0]->data.vnc.auth.passwd);
|
|
|
|
if (def->graphics[0]->data.vnc.keymap)
|
|
|
|
virBufferAsprintf(&buf, ",keymap=%s",
|
|
|
|
def->graphics[0]->data.vnc.keymap);
|
|
|
|
}
|
|
|
|
|
|
|
|
vfbstr = virBufferContentAndReset(&buf);
|
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
vfb = g_new0(virConfValue, 1);
|
|
|
|
disp = g_new0(virConfValue, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
vfb->type = VIR_CONF_LIST;
|
|
|
|
vfb->list = disp;
|
|
|
|
disp->type = VIR_CONF_STRING;
|
|
|
|
disp->str = vfbstr;
|
|
|
|
|
|
|
|
if (virConfSetValue(conf, "vfb", vfb) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenFormatSound(virConf *conf, virDomainDef *def)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2019-10-15 14:47:50 +02:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2019-07-03 09:04:01 +02:00
|
|
|
const char * model;
|
2019-10-15 15:16:31 +02:00
|
|
|
g_autofree char *str = NULL;
|
2019-07-03 09:04:01 +02:00
|
|
|
size_t i;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2019-07-03 09:04:01 +02:00
|
|
|
if (def->os.type != VIR_DOMAIN_OSTYPE_HVM ||
|
|
|
|
!def->sounds)
|
|
|
|
return 0;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2019-07-03 09:04:01 +02:00
|
|
|
for (i = 0; i < def->nsounds; i++) {
|
|
|
|
if (!(model = virDomainSoundModelTypeToString(def->sounds[i]->model))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected sound model %d"),
|
|
|
|
def->sounds[i]->model);
|
|
|
|
return -1;
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
2019-07-03 09:04:01 +02:00
|
|
|
if (i)
|
|
|
|
virBufferAddChar(&buf, ',');
|
|
|
|
virBufferEscapeSexpr(&buf, "%s", model);
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
|
|
|
|
2019-07-03 09:04:01 +02:00
|
|
|
str = virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
return xenConfigSetString(conf, "soundhw", str);
|
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenFormatVif(virConf *conf,
|
2014-08-15 20:52:15 -06:00
|
|
|
virConnectPtr conn,
|
2021-03-11 08:16:13 +01:00
|
|
|
virDomainDef *def,
|
2016-05-17 17:34:45 +08:00
|
|
|
const char *vif_typename)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virConfValue *netVal = NULL;
|
2018-09-13 16:55:20 +08:00
|
|
|
size_t i;
|
|
|
|
int hvm = def->os.type == VIR_DOMAIN_OSTYPE_HVM;
|
2014-08-15 20:52:15 -06:00
|
|
|
|
2020-09-23 20:43:09 +02:00
|
|
|
netVal = g_new0(virConfValue, 1);
|
2014-08-15 20:52:15 -06:00
|
|
|
netVal->type = VIR_CONF_LIST;
|
|
|
|
netVal->list = NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < def->nnets; i++) {
|
|
|
|
if (xenFormatNet(conn, netVal, def->nets[i],
|
2016-05-17 17:34:45 +08:00
|
|
|
hvm, vif_typename) < 0)
|
2018-09-13 16:55:20 +08:00
|
|
|
goto cleanup;
|
2014-08-15 20:52:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if (netVal->list != NULL) {
|
|
|
|
int ret = virConfSetValue(conf, "vif", netVal);
|
|
|
|
netVal = NULL;
|
|
|
|
if (ret < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(netVal);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virConfFreeValue(netVal);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A convenience function for formatting all config common to both XM and XL
|
|
|
|
*/
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenFormatConfigCommon(virConf *conf,
|
|
|
|
virDomainDef *def,
|
2016-05-17 17:34:45 +08:00
|
|
|
virConnectPtr conn,
|
|
|
|
const char *nativeFormat)
|
2014-08-15 20:52:15 -06:00
|
|
|
{
|
|
|
|
if (xenFormatGeneralMeta(conf, def) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (xenFormatMem(conf, def) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (xenFormatCPUAllocation(conf, def) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2020-04-15 21:48:42 -06:00
|
|
|
if (xenFormatHypervisorFeatures(conf, def) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2015-12-04 16:08:59 -07:00
|
|
|
if (xenFormatTimeOffset(conf, def) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (xenFormatEventActions(conf, def) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (xenFormatEmulator(conf, def) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2015-12-04 16:08:59 -07:00
|
|
|
if (xenFormatVfb(conf, def) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
2016-05-17 17:34:45 +08:00
|
|
|
if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XL)) {
|
|
|
|
if (xenFormatVif(conf, conn, def, "vif") < 0)
|
|
|
|
return -1;
|
|
|
|
} else if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XM)) {
|
|
|
|
if (xenFormatVif(conf, conn, def, "netfront") < 0)
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("unsupported config type %s"), nativeFormat);
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
2016-05-17 17:34:45 +08:00
|
|
|
}
|
2014-08-15 20:52:15 -06:00
|
|
|
|
|
|
|
if (xenFormatPCI(conf, def) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2016-08-18 10:20:49 +08:00
|
|
|
if (xenFormatCharDev(conf, def, nativeFormat) < 0)
|
2014-08-15 20:52:15 -06:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (xenFormatSound(conf, def) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2016-01-11 12:40:32 +01:00
|
|
|
|
|
|
|
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
xenDomainDefAddImplicitInputDevice(virDomainDef *def)
|
2016-01-11 12:40:32 +01:00
|
|
|
{
|
|
|
|
virDomainInputBus implicitInputBus = VIR_DOMAIN_INPUT_BUS_XEN;
|
|
|
|
|
|
|
|
if (def->os.type == VIR_DOMAIN_OSTYPE_HVM)
|
|
|
|
implicitInputBus = VIR_DOMAIN_INPUT_BUS_PS2;
|
|
|
|
|
|
|
|
if (virDomainDefMaybeAddInput(def,
|
|
|
|
VIR_DOMAIN_INPUT_TYPE_MOUSE,
|
|
|
|
implicitInputBus) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virDomainDefMaybeAddInput(def,
|
|
|
|
VIR_DOMAIN_INPUT_TYPE_KBD,
|
|
|
|
implicitInputBus) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|