libvirt/src/lxc/lxc_native.c
Martin Kletzander 93e82727ec numatune: Encapsulate numatune configuration in order to unify results
There were numerous places where numatune configuration (and thus
domain config as well) was changed in different ways.  On some
places this even resulted in persistent domain definition not to be
stable (it would change with daemon's restart).

In order to uniformly change how numatune config is dealt with, all
the internals are now accessible directly only in numatune_conf.c and
outside this file accessors must be used.

Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
2014-07-16 20:15:45 +02:00

954 lines
26 KiB
C

/*
* lxc_native.c: LXC native configuration import
*
* Copyright (c) 2014 Red Hat, Inc.
* Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
* Author: Cedric Bosdonnat <cbosdonnat@suse.com>
*/
#include <config.h>
#include <stdio.h>
#include "internal.h"
#include "lxc_container.h"
#include "lxc_native.h"
#include "util/viralloc.h"
#include "util/virfile.h"
#include "util/virlog.h"
#include "util/virstring.h"
#include "util/virconf.h"
#define VIR_FROM_THIS VIR_FROM_LXC
VIR_LOG_INIT("lxc.lxc_native");
static virDomainFSDefPtr
lxcCreateFSDef(int type,
const char *src,
const char* dst,
bool readonly,
unsigned long long usage)
{
virDomainFSDefPtr def;
if (VIR_ALLOC(def) < 0)
return NULL;
def->type = type;
def->accessmode = VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH;
if (src && VIR_STRDUP(def->src, src) < 0)
goto error;
if (VIR_STRDUP(def->dst, dst) < 0)
goto error;
def->readonly = readonly;
def->usage = usage;
return def;
error:
virDomainFSDefFree(def);
return NULL;
}
typedef struct _lxcFstab lxcFstab;
typedef lxcFstab *lxcFstabPtr;
struct _lxcFstab {
lxcFstabPtr next;
char *src;
char *dst;
char *type;
char *options;
};
static void
lxcFstabFree(lxcFstabPtr fstab)
{
while (fstab) {
lxcFstabPtr next = NULL;
next = fstab->next;
VIR_FREE(fstab->src);
VIR_FREE(fstab->dst);
VIR_FREE(fstab->type);
VIR_FREE(fstab->options);
VIR_FREE(fstab);
fstab = next;
}
}
static char ** lxcStringSplit(const char *string)
{
char *tmp;
size_t i;
size_t ntokens = 0;
char **parts;
char **result = NULL;
if (VIR_STRDUP(tmp, string) < 0)
return NULL;
/* Replace potential \t by a space */
for (i = 0; tmp[i]; i++) {
if (tmp[i] == '\t')
tmp[i] = ' ';
}
if (!(parts = virStringSplit(tmp, " ", 0)))
goto error;
/* Append NULL element */
if (VIR_EXPAND_N(result, ntokens, 1) < 0)
goto error;
for (i = 0; parts[i]; i++) {
if (STREQ(parts[i], ""))
continue;
if (VIR_EXPAND_N(result, ntokens, 1) < 0)
goto error;
if (VIR_STRDUP(result[ntokens-2], parts[i]) < 0)
goto error;
}
VIR_FREE(tmp);
virStringFreeList(parts);
return result;
error:
VIR_FREE(tmp);
virStringFreeList(parts);
virStringFreeList(result);
return NULL;
}
static lxcFstabPtr
lxcParseFstabLine(char *fstabLine)
{
lxcFstabPtr fstab = NULL;
char **parts;
if (!fstabLine || VIR_ALLOC(fstab) < 0)
return NULL;
if (!(parts = lxcStringSplit(fstabLine)))
goto error;
if (!parts[0] || !parts[1] || !parts[2] || !parts[3])
goto error;
if (VIR_STRDUP(fstab->src, parts[0]) < 0 ||
VIR_STRDUP(fstab->dst, parts[1]) < 0 ||
VIR_STRDUP(fstab->type, parts[2]) < 0 ||
VIR_STRDUP(fstab->options, parts[3]) < 0)
goto error;
virStringFreeList(parts);
return fstab;
error:
lxcFstabFree(fstab);
virStringFreeList(parts);
return NULL;
}
static int
lxcAddFSDef(virDomainDefPtr def,
int type,
const char *src,
const char *dst,
bool readonly,
unsigned long long usage)
{
virDomainFSDefPtr fsDef = NULL;
if (!(fsDef = lxcCreateFSDef(type, src, dst, readonly, usage)))
goto error;
if (VIR_EXPAND_N(def->fss, def->nfss, 1) < 0)
goto error;
def->fss[def->nfss - 1] = fsDef;
return 0;
error:
virDomainFSDefFree(fsDef);
return -1;
}
static int
lxcSetRootfs(virDomainDefPtr def,
virConfPtr properties)
{
int type = VIR_DOMAIN_FS_TYPE_MOUNT;
virConfValuePtr value;
if (!(value = virConfGetValue(properties, "lxc.rootfs")) ||
!value->str) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Missing lxc.rootfs configuration"));
return -1;
}
if (STRPREFIX(value->str, "/dev/"))
type = VIR_DOMAIN_FS_TYPE_BLOCK;
if (lxcAddFSDef(def, type, value->str, "/", false, 0) < 0)
return -1;
return 0;
}
static int
lxcConvertSize(const char *size, unsigned long long *value)
{
char *unit = NULL;
/* Split the string into value and unit */
if (virStrToLong_ull(size, &unit, 10, value) < 0)
goto error;
if (STREQ(unit, "%")) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("can't convert relative size: '%s'"),
size);
return -1;
} else {
if (virScaleInteger(value, unit, 1, ULLONG_MAX) < 0)
goto error;
}
return 0;
error:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to convert size: '%s'"),
size);
return -1;
}
static int
lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab)
{
const char *src = NULL;
char *dst = NULL;
char **options = virStringSplit(fstab->options, ",", 0);
bool readonly;
int type = VIR_DOMAIN_FS_TYPE_MOUNT;
unsigned long long usage = 0;
int ret = -1;
if (!options)
return -1;
if (fstab->dst[0] != '/') {
if (virAsprintf(&dst, "/%s", fstab->dst) < 0)
goto cleanup;
} else {
if (VIR_STRDUP(dst, fstab->dst) < 0)
goto cleanup;
}
/* Check that we don't add basic mounts */
if (lxcIsBasicMountLocation(dst)) {
ret = 0;
goto cleanup;
}
if (STREQ(fstab->type, "tmpfs")) {
char *sizeStr = NULL;
size_t i;
type = VIR_DOMAIN_FS_TYPE_RAM;
for (i = 0; options[i]; i++) {
if ((sizeStr = STRSKIP(options[i], "size="))) {
if (lxcConvertSize(sizeStr, &usage) < 0)
goto cleanup;
break;
}
}
if (!sizeStr) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("missing tmpfs size, set the size option"));
goto cleanup;
}
} else {
src = fstab->src;
}
/* Is it a block device that needs special favor? */
if (STRPREFIX(fstab->src, "/dev/"))
type = VIR_DOMAIN_FS_TYPE_BLOCK;
/* Do we have ro in options? */
readonly = virStringArrayHasString(options, "ro");
if (lxcAddFSDef(def, type, src, dst, readonly, usage) < 0)
goto cleanup;
ret = 1;
cleanup:
VIR_FREE(dst);
virStringFreeList(options);
return ret;
}
static int
lxcFstabWalkCallback(const char* name, virConfValuePtr value, void * data)
{
int ret = 0;
lxcFstabPtr fstabLine;
virDomainDefPtr def = data;
/* We only care about lxc.mount.entry lines */
if (STRNEQ(name, "lxc.mount.entry"))
return 0;
fstabLine = lxcParseFstabLine(value->str);
if (!fstabLine)
return -1;
if (lxcAddFstabLine(def, fstabLine) < 0)
ret = -1;
lxcFstabFree(fstabLine);
return ret;
}
static virDomainNetDefPtr
lxcCreateNetDef(const char *type,
const char *linkdev,
const char *mac,
const char *flag,
const char *macvlanmode)
{
virDomainNetDefPtr net = NULL;
virMacAddr macAddr;
if (VIR_ALLOC(net) < 0)
goto error;
if (flag) {
if (STREQ(flag, "up"))
net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP;
else
net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN;
}
if (mac && virMacAddrParse(mac, &macAddr) == 0)
net->mac = macAddr;
if (STREQ(type, "veth")) {
if (!linkdev)
goto error;
net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
if (VIR_STRDUP(net->data.bridge.brname, linkdev) < 0)
goto error;
} else if (STREQ(type, "macvlan")) {
net->type = VIR_DOMAIN_NET_TYPE_DIRECT;
if (!linkdev || VIR_STRDUP(net->data.direct.linkdev, linkdev) < 0)
goto error;
if (!macvlanmode || STREQ(macvlanmode, "private"))
net->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PRIVATE;
else if (STREQ(macvlanmode, "vepa"))
net->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_VEPA;
else if (STREQ(macvlanmode, "bridge"))
net->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_BRIDGE;
else
VIR_WARN("Unknown macvlan type: %s", macvlanmode);
}
return net;
error:
virDomainNetDefFree(net);
return NULL;
}
static virDomainHostdevDefPtr
lxcCreateHostdevDef(int mode, int type, const char *data)
{
virDomainHostdevDefPtr hostdev = virDomainHostdevDefAlloc();
if (!hostdev)
return NULL;
hostdev->mode = mode;
hostdev->source.caps.type = type;
if (type == VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET &&
VIR_STRDUP(hostdev->source.caps.u.net.iface, data) < 0) {
virDomainHostdevDefFree(hostdev);
hostdev = NULL;
}
return hostdev;
}
static int
lxcAddNetworkDefinition(virDomainDefPtr def,
const char *type,
const char *linkdev,
const char *mac,
const char *flag,
const char *macvlanmode,
const char *vlanid)
{
virDomainNetDefPtr net = NULL;
virDomainHostdevDefPtr hostdev = NULL;
bool isPhys, isVlan = false;
if ((type == NULL) || STREQ(type, "empty") || STREQ(type, "") ||
STREQ(type, "none"))
return 0;
isPhys = STREQ(type, "phys");
isVlan = STREQ(type, "vlan");
if (type != NULL && (isPhys || isVlan)) {
if (!linkdev) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Missing 'link' attribute for NIC"));
goto error;
}
if (!(hostdev = lxcCreateHostdevDef(VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES,
VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET,
linkdev)))
goto error;
/* This still requires the user to manually setup the vlan interface
* on the host */
if (isVlan && vlanid) {
VIR_FREE(hostdev->source.caps.u.net.iface);
if (virAsprintf(&hostdev->source.caps.u.net.iface,
"%s.%s", linkdev, vlanid) < 0)
goto error;
}
if (VIR_EXPAND_N(def->hostdevs, def->nhostdevs, 1) < 0)
goto error;
def->hostdevs[def->nhostdevs - 1] = hostdev;
} else {
if (!(net = lxcCreateNetDef(type, linkdev, mac, flag, macvlanmode)))
goto error;
if (VIR_EXPAND_N(def->nets, def->nnets, 1) < 0)
goto error;
def->nets[def->nnets - 1] = net;
}
return 1;
error:
virDomainNetDefFree(net);
virDomainHostdevDefFree(hostdev);
return -1;
}
typedef struct {
virDomainDefPtr def;
char *type;
char *link;
char *mac;
char *flag;
char *macvlanmode;
char *vlanid;
bool privnet;
size_t networks;
} lxcNetworkParseData;
static int
lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data)
{
lxcNetworkParseData *parseData = data;
int status;
if (STREQ(name, "lxc.network.type")) {
/* Store the previous NIC */
status = lxcAddNetworkDefinition(parseData->def, parseData->type,
parseData->link, parseData->mac,
parseData->flag,
parseData->macvlanmode,
parseData->vlanid);
if (status < 0)
return -1;
else if (status > 0)
parseData->networks++;
else if (parseData->type != NULL && STREQ(parseData->type, "none"))
parseData->privnet = false;
/* Start a new network interface config */
parseData->type = NULL;
parseData->link = NULL;
parseData->mac = NULL;
parseData->flag = NULL;
parseData->macvlanmode = NULL;
parseData->vlanid = NULL;
/* Keep the new value */
parseData->type = value->str;
}
else if (STREQ(name, "lxc.network.link"))
parseData->link = value->str;
else if (STREQ(name, "lxc.network.hwaddr"))
parseData->mac = value->str;
else if (STREQ(name, "lxc.network.flags"))
parseData->flag = value->str;
else if (STREQ(name, "lxc.network.macvlan.mode"))
parseData->macvlanmode = value->str;
else if (STREQ(name, "lxc.network.vlan.id"))
parseData->vlanid = value->str;
else if (STRPREFIX(name, "lxc.network"))
VIR_WARN("Unhandled network property: %s = %s",
name,
value->str);
return 0;
}
static int
lxcConvertNetworkSettings(virDomainDefPtr def, virConfPtr properties)
{
int status;
lxcNetworkParseData data = {def, NULL, NULL, NULL, NULL,
NULL, NULL, true, 0};
virConfWalk(properties, lxcNetworkWalkCallback, &data);
/* Add the last network definition found */
status = lxcAddNetworkDefinition(def, data.type, data.link,
data.mac, data.flag,
data.macvlanmode,
data.vlanid);
if (status < 0)
return -1;
else if (status > 0)
data.networks++;
else if (data.type != NULL && STREQ(data.type, "none"))
data.privnet = false;
if (data.networks == 0 && data.privnet) {
/* When no network type is provided LXC only adds loopback */
def->features[VIR_DOMAIN_FEATURE_PRIVNET] = VIR_DOMAIN_FEATURE_STATE_ON;
}
return 0;
}
static int
lxcCreateConsoles(virDomainDefPtr def, virConfPtr properties)
{
virConfValuePtr value;
int nbttys = 0;
virDomainChrDefPtr console;
size_t i;
if (!(value = virConfGetValue(properties, "lxc.tty")) || !value->str)
return 0;
if (virStrToLong_i(value->str, NULL, 10, &nbttys) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to parse int: '%s'"),
value->str);
return -1;
}
if (VIR_ALLOC_N(def->consoles, nbttys) < 0)
return -1;
def->nconsoles = nbttys;
for (i = 0; i < nbttys; i++) {
if (!(console = virDomainChrDefNew()))
goto error;
console->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
console->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_LXC;
console->target.port = i;
console->source.type = VIR_DOMAIN_CHR_TYPE_PTY;
def->consoles[i] = console;
}
return 0;
error:
virDomainChrDefFree(console);
return -1;
}
static int
lxcIdmapWalkCallback(const char *name, virConfValuePtr value, void *data)
{
virDomainDefPtr def = data;
virDomainIdMapEntryPtr idmap = NULL;
char type;
unsigned long start, target, count;
if (STRNEQ(name, "lxc.id_map") || !value->str)
return 0;
if (sscanf(value->str, "%c %lu %lu %lu", &type,
&target, &start, &count) != 4) {
virReportError(VIR_ERR_INTERNAL_ERROR, _("invalid lxc.id_map: '%s'"),
value->str);
return -1;
}
if (type == 'u') {
if (VIR_EXPAND_N(def->idmap.uidmap, def->idmap.nuidmap, 1) < 0)
return -1;
idmap = &def->idmap.uidmap[def->idmap.nuidmap - 1];
} else if (type == 'g') {
if (VIR_EXPAND_N(def->idmap.gidmap, def->idmap.ngidmap, 1) < 0)
return -1;
idmap = &def->idmap.gidmap[def->idmap.ngidmap - 1];
} else {
return -1;
}
idmap->start = start;
idmap->target = target;
idmap->count = count;
return 0;
}
static int
lxcSetMemTune(virDomainDefPtr def, virConfPtr properties)
{
virConfValuePtr value;
unsigned long long size = 0;
if ((value = virConfGetValue(properties,
"lxc.cgroup.memory.limit_in_bytes")) &&
value->str && STRNEQ(value->str, "-1")) {
if (lxcConvertSize(value->str, &size) < 0)
return -1;
size = size / 1024;
def->mem.max_balloon = size;
def->mem.hard_limit = size;
}
if ((value = virConfGetValue(properties,
"lxc.cgroup.memory.soft_limit_in_bytes")) &&
value->str && STRNEQ(value->str, "-1")) {
if (lxcConvertSize(value->str, &size) < 0)
return -1;
def->mem.soft_limit = size / 1024;
}
if ((value = virConfGetValue(properties,
"lxc.cgroup.memory.memsw.limit_in_bytes")) &&
value->str && STRNEQ(value->str, "-1")) {
if (lxcConvertSize(value->str, &size) < 0)
return -1;
def->mem.swap_hard_limit = size / 1024;
}
return 0;
}
static int
lxcSetCpuTune(virDomainDefPtr def, virConfPtr properties)
{
virConfValuePtr value;
if ((value = virConfGetValue(properties, "lxc.cgroup.cpu.shares")) &&
value->str) {
if (virStrToLong_ul(value->str, NULL, 10, &def->cputune.shares) < 0)
goto error;
def->cputune.sharesSpecified = true;
}
if ((value = virConfGetValue(properties,
"lxc.cgroup.cpu.cfs_quota_us")) &&
value->str && virStrToLong_ll(value->str, NULL, 10,
&def->cputune.quota) < 0)
goto error;
if ((value = virConfGetValue(properties,
"lxc.cgroup.cpu.cfs_period_us")) &&
value->str && virStrToLong_ull(value->str, NULL, 10,
&def->cputune.period) < 0)
goto error;
return 0;
error:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to parse integer: '%s'"), value->str);
return -1;
}
static int
lxcSetCpusetTune(virDomainDefPtr def, virConfPtr properties)
{
virConfValuePtr value;
virBitmapPtr nodeset = NULL;
if ((value = virConfGetValue(properties, "lxc.cgroup.cpuset.cpus")) &&
value->str) {
if (virBitmapParse(value->str, 0, &def->cpumask,
VIR_DOMAIN_CPUMASK_LEN) < 0)
return -1;
def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC;
}
if ((value = virConfGetValue(properties, "lxc.cgroup.cpuset.mems")) &&
value->str) {
if (virBitmapParse(value->str, 0, &nodeset, VIR_DOMAIN_CPUMASK_LEN) < 0)
return -1;
if (virDomainNumatuneSet(def, VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC,
VIR_DOMAIN_NUMATUNE_MEM_STRICT, nodeset) < 0) {
virBitmapFree(nodeset);
return -1;
}
virBitmapFree(nodeset);
}
return 0;
}
static int
lxcBlkioDeviceWalkCallback(const char *name, virConfValuePtr value, void *data)
{
char **parts = NULL;
virBlkioDevicePtr device = NULL;
virDomainDefPtr def = data;
size_t i = 0;
char *path = NULL;
int ret = -1;
if (!STRPREFIX(name, "lxc.cgroup.blkio.") ||
STREQ(name, "lxc.cgroup.blkio.weight")|| !value->str)
return 0;
if (!(parts = lxcStringSplit(value->str)))
return -1;
if (!parts[0] || !parts[1]) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("invalid %s value: '%s'"),
name, value->str);
goto cleanup;
}
if (virAsprintf(&path, "/dev/block/%s", parts[0]) < 0)
goto cleanup;
/* Do we already have a device definition for this path?
* Get that device or create a new one */
for (i = 0; !device && i < def->blkio.ndevices; i++) {
if (STREQ(def->blkio.devices[i].path, path))
device = &def->blkio.devices[i];
}
if (!device) {
if (VIR_EXPAND_N(def->blkio.devices, def->blkio.ndevices, 1) < 0)
goto cleanup;
device = &def->blkio.devices[def->blkio.ndevices - 1];
device->path = path;
path = NULL;
}
/* Set the value */
if (STREQ(name, "lxc.cgroup.blkio.device_weight")) {
if (virStrToLong_ui(parts[1], NULL, 10, &device->weight) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to parse device weight: '%s'"), parts[1]);
goto cleanup;
}
} else if (STREQ(name, "lxc.cgroup.blkio.throttle.read_bps_device")) {
if (virStrToLong_ull(parts[1], NULL, 10, &device->rbps) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to parse read_bps_device: '%s'"),
parts[1]);
goto cleanup;
}
} else if (STREQ(name, "lxc.cgroup.blkio.throttle.write_bps_device")) {
if (virStrToLong_ull(parts[1], NULL, 10, &device->wbps) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to parse write_bps_device: '%s'"),
parts[1]);
goto cleanup;
}
} else if (STREQ(name, "lxc.cgroup.blkio.throttle.read_iops_device")) {
if (virStrToLong_ui(parts[1], NULL, 10, &device->riops) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to parse read_iops_device: '%s'"),
parts[1]);
goto cleanup;
}
} else if (STREQ(name, "lxc.cgroup.blkio.throttle.write_iops_device")) {
if (virStrToLong_ui(parts[1], NULL, 10, &device->wiops) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to parse write_iops_device: '%s'"),
parts[1]);
goto cleanup;
}
} else {
VIR_WARN("Unhandled blkio tune config: %s", name);
}
ret = 0;
cleanup:
virStringFreeList(parts);
VIR_FREE(path);
return ret;
}
static int
lxcSetBlkioTune(virDomainDefPtr def, virConfPtr properties)
{
virConfValuePtr value;
if ((value = virConfGetValue(properties, "lxc.cgroup.blkio.weight")) &&
value->str && virStrToLong_ui(value->str, NULL, 10,
&def->blkio.weight) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to parse integer: '%s'"), value->str);
return -1;
}
if (virConfWalk(properties, lxcBlkioDeviceWalkCallback, def) < 0)
return -1;
return 0;
}
virDomainDefPtr
lxcParseConfigString(const char *config)
{
virDomainDefPtr vmdef = NULL;
virConfPtr properties = NULL;
virConfValuePtr value;
if (!(properties = virConfReadMem(config, 0, VIR_CONF_FLAG_LXC_FORMAT)))
return NULL;
if (VIR_ALLOC(vmdef) < 0)
goto error;
if (virUUIDGenerate(vmdef->uuid) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("failed to generate uuid"));
goto error;
}
vmdef->id = -1;
vmdef->mem.max_balloon = 64 * 1024;
vmdef->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART;
vmdef->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY;
vmdef->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY;
vmdef->virtType = VIR_DOMAIN_VIRT_LXC;
/* Value not handled by the LXC driver, setting to
* minimum required to make XML parsing pass */
vmdef->maxvcpus = 1;
vmdef->vcpus = 1;
vmdef->nfss = 0;
if (VIR_STRDUP(vmdef->os.type, "exe") < 0)
goto error;
if ((value = virConfGetValue(properties, "lxc.arch")) && value->str) {
virArch arch = virArchFromString(value->str);
if (arch == VIR_ARCH_NONE && STREQ(value->str, "x86"))
arch = VIR_ARCH_I686;
else if (arch == VIR_ARCH_NONE && STREQ(value->str, "amd64"))
arch = VIR_ARCH_X86_64;
vmdef->os.arch = arch;
}
if (VIR_STRDUP(vmdef->os.init, "/sbin/init") < 0)
goto error;
if (!(value = virConfGetValue(properties, "lxc.utsname")) ||
!value->str || (VIR_STRDUP(vmdef->name, value->str) < 0))
goto error;
if (!vmdef->name && (VIR_STRDUP(vmdef->name, "unnamed") < 0))
goto error;
if (lxcSetRootfs(vmdef, properties) < 0)
goto error;
/* Look for fstab: we shouldn't have it */
if (virConfGetValue(properties, "lxc.mount")) {
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
_("lxc.mount found, use lxc.mount.entry lines instead"));
goto error;
}
/* Loop over lxc.mount.entry to add filesystem devices for them */
if (virConfWalk(properties, lxcFstabWalkCallback, vmdef) < 0)
goto error;
/* Network configuration */
if (lxcConvertNetworkSettings(vmdef, properties) < 0)
goto error;
/* Consoles */
if (lxcCreateConsoles(vmdef, properties) < 0)
goto error;
/* lxc.id_map */
if (virConfWalk(properties, lxcIdmapWalkCallback, vmdef) < 0)
goto error;
/* lxc.cgroup.memory.* */
if (lxcSetMemTune(vmdef, properties) < 0)
goto error;
/* lxc.cgroup.cpu.* */
if (lxcSetCpuTune(vmdef, properties) < 0)
goto error;
/* lxc.cgroup.cpuset.* */
if (lxcSetCpusetTune(vmdef, properties) < 0)
goto error;
/* lxc.cgroup.blkio.* */
if (lxcSetBlkioTune(vmdef, properties) < 0)
goto error;
goto cleanup;
error:
virDomainDefFree(vmdef);
vmdef = NULL;
cleanup:
virConfFree(properties);
return vmdef;
}