[libvirt] [PATCH v3 00/21] LXC configuration conversion

Here is an updated version of the patch set fixing comments from Daniel. It also adds 3 commits: * One adding conversion for the newly supported blkio throttle tune in lxc driver. * One actually using the state of the veth network device in lxc driver. * One adding the ability to give major:minor numbers instead of a path for blkio tune devices. The last one is a way to address Daniel's comment on the /dev/block/... paths. Cédric Bosdonnat (21): Improve virConf parse to handle LXC config format LXC driver: started implementing connectDomainXMLFromNative LXC from native: import rootfs LXC from native: migrate fstab and lxc.mount.entry LXC from native: implement no network conversion LXC from native: migrate veth network configuration LXC from native: convert phys network types to net hostdev devices LXC from native: convert lxc.tty to console devices LXC from native: convert macvlan network configuration LXC from native: convert lxc.id_map into <idmap> LXC from native: migrate memory tuning LXC from native: map lxc.cgroup.cpu.* LXC from native: map lxc.cgroup.cpuset.* LXC from native: add lxc.cgroup.blkio.* mapping LXC from native: map lxc.arch to /domain/os/type@arch LXC from native: map block filesystems LXC from native: map vlan network type LXC: added some doc on domxml-from-native with mention of limitations LXC from native: convert blkio throttle config lxc: honor link state=up for veth interfaces blkiotune: allow <node major='' minor=''/> in place of <path> .gitignore | 1 + docs/drvlxc.html.in | 34 +- docs/formatdomain.html.in | 10 +- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/conf/domain_conf.c | 45 +- src/conf/domain_conf.h | 2 + src/libvirt_private.syms | 1 + src/lxc/lxc_cgroup.c | 5 + src/lxc/lxc_container.c | 2 +- src/lxc/lxc_container.h | 2 + src/lxc/lxc_driver.c | 41 + src/lxc/lxc_native.c | 952 +++++++++++++++++++++ src/lxc/lxc_native.h | 32 + src/lxc/lxc_process.c | 5 + src/qemu/qemu_cgroup.c | 5 + src/qemu/qemu_driver.c | 10 + src/util/vircgroup.c | 126 ++- src/util/vircgroup.h | 10 + src/util/virconf.c | 46 +- src/util/virconf.h | 10 + tests/Makefile.am | 7 +- tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config | 11 + tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 39 + .../lxcconf2xmldata/lxcconf2xml-cpusettune.config | 6 + tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml | 27 + tests/lxcconf2xmldata/lxcconf2xml-cputune.config | 7 + tests/lxcconf2xmldata/lxcconf2xml-cputune.xml | 29 + tests/lxcconf2xmldata/lxcconf2xml-fstab.config | 37 + tests/lxcconf2xmldata/lxcconf2xml-idmap.config | 5 + tests/lxcconf2xmldata/lxcconf2xml-idmap.xml | 28 + .../lxcconf2xml-macvlannetwork.config | 13 + .../lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml | 26 + tests/lxcconf2xmldata/lxcconf2xml-memtune.config | 10 + tests/lxcconf2xmldata/lxcconf2xml-memtune.xml | 29 + .../lxcconf2xmldata/lxcconf2xml-nonenetwork.config | 4 + tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml | 21 + tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config | 3 + tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml | 24 + .../lxcconf2xmldata/lxcconf2xml-physnetwork.config | 6 + tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml | 26 + tests/lxcconf2xmldata/lxcconf2xml-simple.config | 41 + tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 41 + .../lxcconf2xmldata/lxcconf2xml-vlannetwork.config | 12 + tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml | 26 + tests/lxcconf2xmltest.c | 131 +++ 46 files changed, 1865 insertions(+), 85 deletions(-) create mode 100644 src/lxc/lxc_native.c create mode 100644 src/lxc/lxc_native.h create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cpusettune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cputune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cputune.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-fstab.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-memtune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-memtune.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-physnetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-simple.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-simple.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml create mode 100644 tests/lxcconf2xmltest.c -- 1.8.5.2

virConf now honours a VIR_CONF_FLAG_LXC_FORMAT flag to handle LXC configuration files. The differences are that property names can contain '.' character and values are all strings without any bounding quotes. Provide a new virConfWalk function calling a handler on all non-comment values. This function will be used by the LXC conversion code to loop over LXC configuration lines. --- src/libvirt_private.syms | 1 + src/util/virconf.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- src/util/virconf.h | 10 ++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c5a7637..ba10b4e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1128,6 +1128,7 @@ virConfNew; virConfReadFile; virConfReadMem; virConfSetValue; +virConfWalk; virConfWriteFile; virConfWriteMem; diff --git a/src/util/virconf.c b/src/util/virconf.c index e882d15..63aa569 100644 --- a/src/util/virconf.c +++ b/src/util/virconf.c @@ -429,6 +429,16 @@ virConfParseString(virConfParserCtxtPtr ctxt) if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; NEXT; + } else if (ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT) { + base = ctxt->cur; + /* LXC config format doesn't support comments after the value */ + while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) + NEXT; + /* Reverse to exclude the trailing blanks from the value */ + while ((ctxt->cur > base) && (c_isblank(CUR))) + ctxt->cur--; + if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) + return NULL; } return ret; } @@ -454,7 +464,8 @@ virConfParseValue(virConfParserCtxtPtr ctxt) virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value")); return NULL; } - if ((CUR == '"') || (CUR == '\'')) { + if ((CUR == '"') || (CUR == '\'') || + (ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT)) { type = VIR_CONF_STRING; str = virConfParseString(ctxt); if (str == NULL) @@ -561,7 +572,9 @@ virConfParseName(virConfParserCtxtPtr ctxt) while ((ctxt->cur < ctxt->end) && (c_isalnum(CUR) || (CUR == '_') || ((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && - ((CUR == ':') || (CUR == '.') || (CUR == '-'))))) + ((CUR == ':') || (CUR == '.') || (CUR == '-'))) || + ((ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT) && + (CUR == '.')))) NEXT; if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; @@ -905,6 +918,35 @@ virConfSetValue(virConfPtr conf, return 0; } +/** + * virConfWalk: + * @conf: a configuration file handle + * @callback: the function to call to process each entry + * @data: obscure data passed to callback + * + * Walk over all entries of the configuration file and run the callback + * for each with entry name, value and the obscure data. + * + * Returns 0 on success, or -1 on failure. + */ +int virConfWalk(virConfPtr conf, + virConfWalkCallback callback, + void *opaque) +{ + virConfEntryPtr cur; + + if (!conf) + return 0; + + cur = conf->entries; + while (cur != NULL) { + if (cur->name && cur->value && + callback(cur->name, cur->value, opaque) < 0) + return -1; + cur = cur->next; + } + return 0; +} /** * virConfWriteFile: diff --git a/src/util/virconf.h b/src/util/virconf.h index 577af8c..2a6b050 100644 --- a/src/util/virconf.h +++ b/src/util/virconf.h @@ -40,6 +40,9 @@ typedef enum { VIR_CONF_FLAG_VMX_FORMAT = 1, /* allow ':', '.' and '-' in names for compatibility with VMware VMX configuration file, but restrict allowed value types to string only */ + VIR_CONF_FLAG_LXC_FORMAT = 2, /* allow '.' in names for compatibility with LXC + configuration file, restricts allowed value types + to string only and don't expect quotes for values */ } virConfFlags; static inline const char * @@ -79,6 +82,10 @@ struct _virConfValue { typedef struct _virConf virConf; typedef virConf *virConfPtr; +typedef int (*virConfWalkCallback)(const char* name, + virConfValuePtr value, + void *opaque); + virConfPtr virConfNew (void); virConfPtr virConfReadFile (const char *filename, unsigned int flags); virConfPtr virConfReadMem (const char *memory, @@ -91,6 +98,9 @@ virConfValuePtr virConfGetValue (virConfPtr conf, int virConfSetValue (virConfPtr conf, const char *setting, virConfValuePtr value); +int virConfWalk(virConfPtr conf, + virConfWalkCallback callback, + void *opaque); int virConfWriteFile (const char *filename, virConfPtr conf); int virConfWriteMem (char *memory, -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:09:59PM +0100, Cédric Bosdonnat wrote:
virConf now honours a VIR_CONF_FLAG_LXC_FORMAT flag to handle LXC configuration files. The differences are that property names can contain '.' character and values are all strings without any bounding quotes.
Provide a new virConfWalk function calling a handler on all non-comment values. This function will be used by the LXC conversion code to loop over LXC configuration lines. --- src/libvirt_private.syms | 1 + src/util/virconf.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- src/util/virconf.h | 10 ++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

This function aims at converting LXC configuration into a libvirt domain XML description to help users migrate from LXC to libvirt. Here is an example of how the lxc configuration works: virsh -c lxc:/// domxml-from-native lxc-tools /var/lib/lxc/migrate_test/config It is possible that some parts couldn't be properly mapped into a domain XML fragment, so users should carefully review the result before creating the domain. fstab files in lxc.mount lines will need to be merged into the configuration file as lxc.mount.entry. As we can't know the amount of memory of the host, we have to set a default value for max_balloon that users will probably want to adjust. --- .gitignore | 1 + po/POTFILES.in | 1 + src/Makefile.am | 1 + src/lxc/lxc_driver.c | 31 +++++++ src/lxc/lxc_native.c | 86 +++++++++++++++++++ src/lxc/lxc_native.h | 32 +++++++ tests/Makefile.am | 7 +- tests/lxcconf2xmldata/lxcconf2xml-simple.config | 38 +++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 17 ++++ tests/lxcconf2xmltest.c | 107 ++++++++++++++++++++++++ 10 files changed, 320 insertions(+), 1 deletion(-) create mode 100644 src/lxc/lxc_native.c create mode 100644 src/lxc/lxc_native.h create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-simple.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-simple.xml create mode 100644 tests/lxcconf2xmltest.c diff --git a/.gitignore b/.gitignore index 757dfed..65b6763 100644 --- a/.gitignore +++ b/.gitignore @@ -157,6 +157,7 @@ /tests/hashtest /tests/jsontest /tests/libvirtdconftest +/tests/lxcconf2xmltest /tests/metadatatest /tests/networkxml2argvtest /tests/nodeinfotest diff --git a/po/POTFILES.in b/po/POTFILES.in index 0359b2f..fd36bc5 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -62,6 +62,7 @@ src/locking/sanlock_helper.c src/lxc/lxc_cgroup.c src/lxc/lxc_fuse.c src/lxc/lxc_hostdev.c +src/lxc/lxc_native.c src/lxc/lxc_container.c src/lxc/lxc_conf.c src/lxc/lxc_controller.c diff --git a/src/Makefile.am b/src/Makefile.am index 3f8d22f..4ac31e2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -619,6 +619,7 @@ LXC_DRIVER_SOURCES = \ lxc/lxc_monitor.c lxc/lxc_monitor.h \ lxc/lxc_process.c lxc/lxc_process.h \ lxc/lxc_fuse.c lxc/lxc_fuse.h \ + lxc/lxc_native.c lxc/lxc_native.h \ lxc/lxc_driver.c lxc/lxc_driver.h LXC_CONTROLLER_SOURCES = \ diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 138c706..dc0e8e0 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -44,6 +44,7 @@ #include "lxc_container.h" #include "lxc_domain.h" #include "lxc_driver.h" +#include "lxc_native.h" #include "lxc_process.h" #include "viralloc.h" #include "virnetdevbridge.h" @@ -988,6 +989,35 @@ cleanup: return ret; } +static char *lxcConnectDomainXMLFromNative(virConnectPtr conn, + const char *nativeFormat, + const char *nativeConfig, + unsigned int flags) +{ + char *xml = NULL; + virDomainDefPtr def = NULL; + + virCheckFlags(0, NULL); + + if (virConnectDomainXMLFromNativeEnsureACL(conn) < 0) + goto cleanup; + + if (STRNEQ(nativeFormat, LXC_CONFIG_FORMAT)) { + virReportError(VIR_ERR_INVALID_ARG, + _("unsupported config type %s"), nativeFormat); + goto cleanup; + } + + if (!(def = lxcParseConfigString(nativeConfig))) + goto cleanup; + + xml = virDomainDefFormat(def, 0); + +cleanup: + virDomainDefFree(def); + return xml; +} + /** * lxcDomainCreateWithFiles: * @dom: domain to start @@ -5376,6 +5406,7 @@ static virDriver lxcDriver = { .domainGetSecurityLabel = lxcDomainGetSecurityLabel, /* 0.9.10 */ .nodeGetSecurityModel = lxcNodeGetSecurityModel, /* 0.9.10 */ .domainGetXMLDesc = lxcDomainGetXMLDesc, /* 0.4.2 */ + .connectDomainXMLFromNative = lxcConnectDomainXMLFromNative, /* 1.2.2 */ .connectListDefinedDomains = lxcConnectListDefinedDomains, /* 0.4.2 */ .connectNumOfDefinedDomains = lxcConnectNumOfDefinedDomains, /* 0.4.2 */ .domainCreate = lxcDomainCreate, /* 0.4.4 */ diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c new file mode 100644 index 0000000..723ebcf --- /dev/null +++ b/src/lxc/lxc_native.c @@ -0,0 +1,86 @@ +/* + * lxc_native.c: LXC native configuration import + * + * 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 "internal.h" +#include "lxc_native.h" +#include "util/viralloc.h" +#include "util/virlog.h" +#include "util/virstring.h" +#include "util/virconf.h" + +#define VIR_FROM_THIS VIR_FROM_LXC + +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; + + if (VIR_STRDUP(vmdef->os.type, "exe") < 0) + goto error; + + 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; + + goto cleanup; + +error: + virDomainDefFree(vmdef); + vmdef = NULL; + +cleanup: + virConfFree(properties); + + return vmdef; +} diff --git a/src/lxc/lxc_native.h b/src/lxc/lxc_native.h new file mode 100644 index 0000000..a80f2b1 --- /dev/null +++ b/src/lxc/lxc_native.h @@ -0,0 +1,32 @@ +/* + * lxc_native.h: LXC native configuration import + * + * 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> + */ + +#ifndef __LXC_NATIVE_H__ +# define __LXC_NATIVE_H__ + +# include "domain_conf.h" + +# define LXC_CONFIG_FORMAT "lxc-tools" + +virDomainDefPtr lxcParseConfigString(const char *config); + +#endif /* __LXC_NATIVE_H__ */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 30cdd1d..734c9d9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -199,7 +199,7 @@ test_programs += qemuxml2argvtest qemuxml2xmltest qemuxmlnstest \ endif WITH_QEMU if WITH_LXC -test_programs += lxcxml2xmltest +test_programs += lxcxml2xmltest lxcconf2xmltest endif WITH_LXC if WITH_OPENVZ @@ -515,6 +515,11 @@ lxcxml2xmltest_SOURCES = \ lxcxml2xmltest.c testutilslxc.c testutilslxc.h \ testutils.c testutils.h lxcxml2xmltest_LDADD = $(lxc_LDADDS) + +lxcconf2xmltest_SOURCES = \ + lxcconf2xmltest.c \ + testutils.c testutils.h +lxcconf2xmltest_LDADD = $(lxc_LDADDS) else ! WITH_LXC EXTRA_DIST += lxcxml2xmltest.c testutilslxc.c testutilslxc.h endif ! WITH_LXC diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.config b/tests/lxcconf2xmldata/lxcconf2xml-simple.config new file mode 100644 index 0000000..12428bb --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.config @@ -0,0 +1,38 @@ +# Template used to create this container: opensuse +# Template script checksum (SHA-1): 27307e0a95bd81b2c0bd82d6f87fdbe83be075ef + +lxc.network.type = veth +lxc.network.flags = up +lxc.network.link = virbr0 +lxc.network.hwaddr = 02:00:15:8f:05:c1 +lxc.network.name = eth0 + +#remove next line if host DNS configuration should not be available to container +lxc.mount.entry = /etc/resolv.conf etc/resolv.conf none bind,ro 0 0 +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 +lxc.tty = 2 +lxc.pts = 1024 +lxc.mount = /var/lib/lxc/migrate_test/fstab +lxc.cap.drop = sys_module mac_admin mac_override mknod + +# When using LXC with apparmor, uncomment the next line to run unconfined: +#lxc.aa_profile = unconfined + +lxc.cgroup.devices.deny = a +# /dev/null and zero +lxc.cgroup.devices.allow = c 1:3 rwm +lxc.cgroup.devices.allow = c 1:5 rwm +# consoles +lxc.cgroup.devices.allow = c 5:1 rwm +lxc.cgroup.devices.allow = c 5:0 rwm +lxc.cgroup.devices.allow = c 4:0 rwm +lxc.cgroup.devices.allow = c 4:1 rwm +# /dev/{,u}random +lxc.cgroup.devices.allow = c 1:9 rwm +lxc.cgroup.devices.allow = c 1:8 rwm +lxc.cgroup.devices.allow = c 136:* rwm +lxc.cgroup.devices.allow = c 5:2 rwm +# rtc +lxc.cgroup.devices.allow = c 254:0 rwm diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml new file mode 100644 index 0000000..641e624 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml @@ -0,0 +1,17 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c new file mode 100644 index 0000000..9a840f9 --- /dev/null +++ b/tests/lxcconf2xmltest.c @@ -0,0 +1,107 @@ +#include <config.h> + +#include "testutils.h" + +#ifdef WITH_LXC + +# include "lxc/lxc_native.h" + +# define VIR_FROM_THIS VIR_FROM_NONE + +static int +blankProblemElements(char *data) +{ + if (virtTestClearLineRegex("<uuid>([[:alnum:]]|-)+</uuid>", data) < 0) + return -1; + return 0; +} + +static int +testCompareXMLToConfigFiles(const char *xml, + const char *configfile) +{ + int ret = -1; + char *config = NULL; + char *expectxml = NULL; + char *actualxml = NULL; + virDomainDefPtr vmdef = NULL; + + if (virtTestLoadFile(configfile, &config) < 0) + goto fail; + if (virtTestLoadFile(xml, &expectxml) < 0) + goto fail; + + if (!(vmdef = lxcParseConfigString(config))) + goto fail; + + if (!(actualxml = virDomainDefFormat(vmdef, 0))) + goto fail; + + if (blankProblemElements(expectxml) < 0 || + blankProblemElements(actualxml) < 0) + goto fail; + + if (STRNEQ(expectxml, actualxml)) { + virtTestDifference(stderr, expectxml, actualxml); + goto fail; + } + + ret = 0; + +fail: + VIR_FREE(expectxml); + VIR_FREE(actualxml); + VIR_FREE(config); + virDomainDefFree(vmdef); + return ret; +} + +static int +testCompareXMLToConfigHelper(const void *data) +{ + int result = -1; + const char *name = data; + char *xml = NULL; + char *config = NULL; + + if (virAsprintf(&xml, "%s/lxcconf2xmldata/lxcconf2xml-%s.xml", + abs_srcdir, name) < 0 || + virAsprintf(&config, "%s/lxcconf2xmldata/lxcconf2xml-%s.config", + abs_srcdir, name) < 0) + goto cleanup; + + result = testCompareXMLToConfigFiles(xml, config); + +cleanup: + VIR_FREE(xml); + VIR_FREE(config); + return result; +} + +static int +mymain(void) +{ + int ret = EXIT_SUCCESS; + +# define DO_TEST(name) \ + if (virtTestRun("LXC Native-2-XML " name, \ + testCompareXMLToConfigHelper, \ + name) < 0) \ + ret = EXIT_FAILURE + + DO_TEST("simple"); + + return ret; +} + +VIRT_TEST_MAIN(mymain) + +#else + +int +main(void) +{ + return EXIT_AM_SKIP; +} + +#endif /* WITH_LXC */ -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:00PM +0100, Cédric Bosdonnat wrote:
This function aims at converting LXC configuration into a libvirt domain XML description to help users migrate from LXC to libvirt.
Here is an example of how the lxc configuration works: virsh -c lxc:/// domxml-from-native lxc-tools /var/lib/lxc/migrate_test/config
It is possible that some parts couldn't be properly mapped into a domain XML fragment, so users should carefully review the result before creating the domain.
fstab files in lxc.mount lines will need to be merged into the configuration file as lxc.mount.entry.
As we can't know the amount of memory of the host, we have to set a default value for max_balloon that users will probably want to adjust. --- .gitignore | 1 + po/POTFILES.in | 1 + src/Makefile.am | 1 + src/lxc/lxc_driver.c | 31 +++++++ src/lxc/lxc_native.c | 86 +++++++++++++++++++ src/lxc/lxc_native.h | 32 +++++++ tests/Makefile.am | 7 +- tests/lxcconf2xmldata/lxcconf2xml-simple.config | 38 +++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 17 ++++ tests/lxcconf2xmltest.c | 107 ++++++++++++++++++++++++ 10 files changed, 320 insertions(+), 1 deletion(-) create mode 100644 src/lxc/lxc_native.c create mode 100644 src/lxc/lxc_native.h create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-simple.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-simple.xml create mode 100644 tests/lxcconf2xmltest.c
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

LXC rootfs can be either a directory or a block device or an image file. The first two types have been implemented, but the image file is still to be done since LXC auto-guesses the file format at mount time and the LXC driver doesn't support the 'auto' format. --- src/lxc/lxc_native.c | 69 ++++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 4 ++ 2 files changed, 73 insertions(+) diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 723ebcf..86d0dd3 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -31,6 +31,72 @@ #define VIR_FROM_THIS VIR_FROM_LXC + +static virDomainFSDefPtr +lxcCreateFSDef(int type, char *src, char* dst) +{ + virDomainFSDefPtr def; + + if (VIR_ALLOC(def) < 0) + return NULL; + + def->type = type; + def->accessmode = VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH; + def->src = src; + def->dst = dst; + + return def; +} + +static int +lxcAddFSDef(virDomainDefPtr def, int type, char *src, char *dst) +{ + virDomainFSDefPtr fsDef = NULL; + + if (!(fsDef = lxcCreateFSDef(type, src, dst))) + 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) +{ + char *fssrc = NULL; + char *fsdst = NULL; + int type = VIR_DOMAIN_FS_TYPE_MOUNT; + virConfValuePtr value; + + if (!(value = virConfGetValue(properties, "lxc.rootfs")) || + !value->str || + (VIR_STRDUP(fssrc, value->str) < 0) || + VIR_STRDUP(fsdst, "/") < 0) + goto error; + + if (STRPREFIX(fssrc, "/dev/")) + type = VIR_DOMAIN_FS_TYPE_BLOCK; + + + if (lxcAddFSDef(def, type, fssrc, fsdst) < 0) + goto error; + + return 0; + +error: + VIR_FREE(fssrc); + VIR_FREE(fsdst); + return -1; +} + virDomainDefPtr lxcParseConfigString(const char *config) { @@ -73,6 +139,9 @@ lxcParseConfigString(const char *config) if (!vmdef->name && (VIR_STRDUP(vmdef->name, "unnamed") < 0)) goto error; + if (lxcSetRootfs(vmdef, properties) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml index 641e624..eebcb4e 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml @@ -13,5 +13,9 @@ <on_reboot>restart</on_reboot> <on_crash>destroy</on_crash> <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> </devices> </domain> -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:01PM +0100, Cédric Bosdonnat wrote:
LXC rootfs can be either a directory or a block device or an image file. The first two types have been implemented, but the image file is still to be done since LXC auto-guesses the file format at mount time and the LXC driver doesn't support the 'auto' format. --- src/lxc/lxc_native.c | 69 ++++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 4 ++ 2 files changed, 73 insertions(+)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Wed, Feb 12, 2014 at 05:23:39PM +0000, Daniel P. Berrange wrote:
On Wed, Feb 05, 2014 at 03:10:01PM +0100, Cédric Bosdonnat wrote:
LXC rootfs can be either a directory or a block device or an image file. The first two types have been implemented, but the image file is still to be done since LXC auto-guesses the file format at mount time and the LXC driver doesn't support the 'auto' format. --- src/lxc/lxc_native.c | 69 ++++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 4 ++ 2 files changed, 73 insertions(+)
ACK
Actually there's a crash on OOM in this patch due to a double-free of the 'src' and 'dst' strings. I'm going to squash the following change in before pushing it Daniel diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 86d0dd3..af9d34e 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -33,7 +33,9 @@ static virDomainFSDefPtr -lxcCreateFSDef(int type, char *src, char* dst) +lxcCreateFSDef(int type, + const char *src, + const char* dst) { virDomainFSDefPtr def; @@ -42,14 +44,23 @@ lxcCreateFSDef(int type, char *src, char* dst) def->type = type; def->accessmode = VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH; - def->src = src; - def->dst = dst; + if (src && VIR_STRDUP(def->src, src) < 0) + goto error; + if (VIR_STRDUP(def->dst, dst) < 0) + goto error; return def; + + error: + virDomainFSDefFree(def); + return NULL; } static int -lxcAddFSDef(virDomainDefPtr def, int type, char *src, char *dst) +lxcAddFSDef(virDomainDefPtr def, + int type, + const char *src, + const char *dst) { virDomainFSDefPtr fsDef = NULL; @@ -71,30 +82,23 @@ static int lxcSetRootfs(virDomainDefPtr def, virConfPtr properties) { - char *fssrc = NULL; - char *fsdst = NULL; int type = VIR_DOMAIN_FS_TYPE_MOUNT; virConfValuePtr value; if (!(value = virConfGetValue(properties, "lxc.rootfs")) || - !value->str || - (VIR_STRDUP(fssrc, value->str) < 0) || - VIR_STRDUP(fsdst, "/") < 0) - goto error; + !value->str) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Missing lxc.rootfs configuration")); + return -1; + } - if (STRPREFIX(fssrc, "/dev/")) + if (STRPREFIX(value->str, "/dev/")) type = VIR_DOMAIN_FS_TYPE_BLOCK; - - if (lxcAddFSDef(def, type, fssrc, fsdst) < 0) - goto error; + if (lxcAddFSDef(def, type, value->str, "/") < 0) + return -1; return 0; - -error: - VIR_FREE(fssrc); - VIR_FREE(fsdst); - return -1; } virDomainDefPtr -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Tmpfs relative size and default 50% size values aren't supported as we have no idea of the available memory at the conversion time. --- src/lxc/lxc_container.c | 2 +- src/lxc/lxc_container.h | 2 + src/lxc/lxc_native.c | 251 +++++++++++++++++++++++- tests/lxcconf2xmldata/lxcconf2xml-fstab.config | 37 ++++ tests/lxcconf2xmldata/lxcconf2xml-simple.config | 4 +- tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 9 + tests/lxcconf2xmltest.c | 60 +++--- 7 files changed, 336 insertions(+), 29 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-fstab.config diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index c6bdc8c..f08dbc2 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -744,7 +744,7 @@ static const virLXCBasicMountInfo lxcBasicMounts[] = { }; -static bool lxcIsBasicMountLocation(const char *path) +bool lxcIsBasicMountLocation(const char *path) { size_t i; diff --git a/src/lxc/lxc_container.h b/src/lxc/lxc_container.h index e74a7d7..67292ab 100644 --- a/src/lxc/lxc_container.h +++ b/src/lxc/lxc_container.h @@ -71,4 +71,6 @@ virArch lxcContainerGetAlt32bitArch(virArch arch); int lxcContainerChown(virDomainDefPtr def, const char *path); +bool lxcIsBasicMountLocation(const char *path); + #endif /* LXC_CONTAINER_H */ diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 86d0dd3..acd68db 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -21,10 +21,13 @@ */ #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" @@ -33,7 +36,11 @@ static virDomainFSDefPtr -lxcCreateFSDef(int type, char *src, char* dst) +lxcCreateFSDef(int type, + char *src, + char* dst, + bool readonly, + unsigned long long usage) { virDomainFSDefPtr def; @@ -44,16 +51,124 @@ lxcCreateFSDef(int type, char *src, char* dst) def->accessmode = VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH; def->src = src; def->dst = dst; + def->readonly = readonly; + def->usage = usage; return def; } +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] = ' '; + } + + parts = virStringSplit(tmp, " ", 0); + 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-1], parts[i]) < 0) + goto error; + } + + /* Append NULL element */ + if (VIR_EXPAND_N(result, ntokens, 1) < 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; + + parts = lxcStringSplit(fstabLine); + + 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, char *src, char *dst) +lxcAddFSDef(virDomainDefPtr def, + int type, + char *src, + char *dst, + bool readonly, + unsigned long long usage) { virDomainFSDefPtr fsDef = NULL; - if (!(fsDef = lxcCreateFSDef(type, src, dst))) + if (!(fsDef = lxcCreateFSDef(type, src, dst, readonly, usage))) goto error; if (VIR_EXPAND_N(def->fss, def->nfss, 1) < 0) @@ -86,7 +201,7 @@ lxcSetRootfs(virDomainDefPtr def, type = VIR_DOMAIN_FS_TYPE_BLOCK; - if (lxcAddFSDef(def, type, fssrc, fsdst) < 0) + if (lxcAddFSDef(def, type, fssrc, fsdst, false, 0) < 0) goto error; return 0; @@ -97,6 +212,119 @@ error: return -1; } +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) +{ + 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; + + if (fstab->dst[0] != '/') { + if (virAsprintf(&dst, "/%s", fstab->dst) < 0) + goto error; + } else { + if (VIR_STRDUP(dst, fstab->dst) < 0) + goto error; + } + + /* Check that we don't add basic mounts */ + if (lxcIsBasicMountLocation(dst)) { + VIR_FREE(dst); + return 0; + } + + 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 error; + break; + } + } + if (!sizeStr) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing tmpfs size, set the size option")); + goto error; + } + } else { + if (VIR_STRDUP(src, fstab->src) < 0) + goto error; + } + + /* Do we have ro in options? */ + readonly = virStringArrayHasString(options, "ro"); + + if (lxcAddFSDef(def, type, src, dst, readonly, usage) < 0) + goto error; + + + return 1; + +error: + VIR_FREE(dst); + VIR_FREE(src); + virStringFreeList(options); + return -1; +} + +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; +} + virDomainDefPtr lxcParseConfigString(const char *config) { @@ -115,6 +343,7 @@ lxcParseConfigString(const char *config) _("failed to generate uuid")); goto error; } + vmdef->id = -1; vmdef->mem.max_balloon = 64 * 1024; @@ -127,6 +356,8 @@ lxcParseConfigString(const char *config) * minimum required to make XML parsing pass */ vmdef->maxvcpus = 1; + vmdef->nfss = 0; + if (VIR_STRDUP(vmdef->os.type, "exe") < 0) goto error; @@ -142,6 +373,18 @@ lxcParseConfigString(const char *config) 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 */ + value = virConfGetValue(properties, "lxc.mount.entry"); + if (virConfWalk(properties, lxcFstabWalkCallback, vmdef) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-fstab.config b/tests/lxcconf2xmldata/lxcconf2xml-fstab.config new file mode 100644 index 0000000..8c03c22 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-fstab.config @@ -0,0 +1,37 @@ +# Template used to create this container: opensuse +# Template script checksum (SHA-1): 27307e0a95bd81b2c0bd82d6f87fdbe83be075ef + +lxc.network.type = veth +lxc.network.flags = up +lxc.network.link = virbr0 +lxc.network.hwaddr = 02:00:15:8f:05:c1 +lxc.network.name = eth0 + +#remove next line if host DNS configuration should not be available to container +lxc.mount = /var/lib/lxc/migrate_test/fstab +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 +lxc.tty = 2 +lxc.pts = 1024 +lxc.cap.drop = sys_module mac_admin mac_override mknod + +# When using LXC with apparmor, uncomment the next line to run unconfined: +#lxc.aa_profile = unconfined + +lxc.cgroup.devices.deny = a +# /dev/null and zero +lxc.cgroup.devices.allow = c 1:3 rwm +lxc.cgroup.devices.allow = c 1:5 rwm +# consoles +lxc.cgroup.devices.allow = c 5:1 rwm +lxc.cgroup.devices.allow = c 5:0 rwm +lxc.cgroup.devices.allow = c 4:0 rwm +lxc.cgroup.devices.allow = c 4:1 rwm +# /dev/{,u}random +lxc.cgroup.devices.allow = c 1:9 rwm +lxc.cgroup.devices.allow = c 1:8 rwm +lxc.cgroup.devices.allow = c 136:* rwm +lxc.cgroup.devices.allow = c 5:2 rwm +# rtc +lxc.cgroup.devices.allow = c 254:0 rwm diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.config b/tests/lxcconf2xmldata/lxcconf2xml-simple.config index 12428bb..f75e8fc 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-simple.config +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.config @@ -8,13 +8,15 @@ lxc.network.hwaddr = 02:00:15:8f:05:c1 lxc.network.name = eth0 #remove next line if host DNS configuration should not be available to container +lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0 +lxc.mount.entry = sysfs sys sysfs defaults 0 0 +lxc.mount.entry = tmpfs run tmpfs size=8m,mode=0755,nodev,nosuid 0 0 lxc.mount.entry = /etc/resolv.conf etc/resolv.conf none bind,ro 0 0 lxc.rootfs = /var/lib/lxc/migrate_test/rootfs lxc.utsname = migrate_test lxc.autodev=1 lxc.tty = 2 lxc.pts = 1024 -lxc.mount = /var/lib/lxc/migrate_test/fstab lxc.cap.drop = sys_module mac_admin mac_override mknod # When using LXC with apparmor, uncomment the next line to run unconfined: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml index eebcb4e..fadbdca 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml @@ -17,5 +17,14 @@ <source dir='/var/lib/lxc/migrate_test/rootfs'/> <target dir='/'/> </filesystem> + <filesystem type='ram' accessmode='passthrough'> + <source usage='8192' units='KiB'/> + <target dir='/run'/> + </filesystem> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/etc/resolv.conf'/> + <target dir='/etc/resolv.conf'/> + <readonly/> + </filesystem> </devices> </domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 9a840f9..c4b21ec 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -18,7 +18,8 @@ blankProblemElements(char *data) static int testCompareXMLToConfigFiles(const char *xml, - const char *configfile) + const char *configfile, + bool expectError) { int ret = -1; char *config = NULL; @@ -28,22 +29,26 @@ testCompareXMLToConfigFiles(const char *xml, if (virtTestLoadFile(configfile, &config) < 0) goto fail; - if (virtTestLoadFile(xml, &expectxml) < 0) - goto fail; - if (!(vmdef = lxcParseConfigString(config))) + vmdef = lxcParseConfigString(config); + if ((vmdef && expectError) || (!vmdef && !expectError)) goto fail; - if (!(actualxml = virDomainDefFormat(vmdef, 0))) - goto fail; + if (vmdef) { + if (!(actualxml = virDomainDefFormat(vmdef, 0))) + goto fail; - if (blankProblemElements(expectxml) < 0 || - blankProblemElements(actualxml) < 0) - goto fail; + if (virtTestLoadFile(xml, &expectxml) < 0) + goto fail; - if (STRNEQ(expectxml, actualxml)) { - virtTestDifference(stderr, expectxml, actualxml); - goto fail; + if (blankProblemElements(expectxml) < 0 || + blankProblemElements(actualxml) < 0) + goto fail; + + if (STRNEQ(expectxml, actualxml)) { + virtTestDifference(stderr, expectxml, actualxml); + goto fail; + } } ret = 0; @@ -56,21 +61,26 @@ fail: return ret; } +struct testInfo { + const char *name; + bool expectError; +}; + static int testCompareXMLToConfigHelper(const void *data) { int result = -1; - const char *name = data; + const struct testInfo *info = data; char *xml = NULL; char *config = NULL; if (virAsprintf(&xml, "%s/lxcconf2xmldata/lxcconf2xml-%s.xml", - abs_srcdir, name) < 0 || + abs_srcdir, info->name) < 0 || virAsprintf(&config, "%s/lxcconf2xmldata/lxcconf2xml-%s.config", - abs_srcdir, name) < 0) + abs_srcdir, info->name) < 0) goto cleanup; - result = testCompareXMLToConfigFiles(xml, config); + result = testCompareXMLToConfigFiles(xml, config, info->expectError); cleanup: VIR_FREE(xml); @@ -83,13 +93,17 @@ mymain(void) { int ret = EXIT_SUCCESS; -# define DO_TEST(name) \ - if (virtTestRun("LXC Native-2-XML " name, \ - testCompareXMLToConfigHelper, \ - name) < 0) \ - ret = EXIT_FAILURE - - DO_TEST("simple"); +# define DO_TEST(name, expectError) \ + do { \ + const struct testInfo info = { name, expectError }; \ + if (virtTestRun("LXC Native-2-XML " name, \ + testCompareXMLToConfigHelper, \ + &info) < 0) \ + ret = EXIT_FAILURE; \ + } while (0) + + DO_TEST("simple", false); + DO_TEST("fstab", true); return ret; } -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:02PM +0100, Cédric Bosdonnat wrote:
Tmpfs relative size and default 50% size values aren't supported as we have no idea of the available memory at the conversion time. --- src/lxc/lxc_container.c | 2 +- src/lxc/lxc_container.h | 2 + src/lxc/lxc_native.c | 251 +++++++++++++++++++++++- tests/lxcconf2xmldata/lxcconf2xml-fstab.config | 37 ++++ tests/lxcconf2xmldata/lxcconf2xml-simple.config | 4 +- tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 9 + tests/lxcconf2xmltest.c | 60 +++--- 7 files changed, 336 insertions(+), 29 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-fstab.config
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index c6bdc8c..f08dbc2 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -744,7 +744,7 @@ static const virLXCBasicMountInfo lxcBasicMounts[] = { };
-static bool lxcIsBasicMountLocation(const char *path) +bool lxcIsBasicMountLocation(const char *path) { size_t i;
diff --git a/src/lxc/lxc_container.h b/src/lxc/lxc_container.h index e74a7d7..67292ab 100644 --- a/src/lxc/lxc_container.h +++ b/src/lxc/lxc_container.h @@ -71,4 +71,6 @@ virArch lxcContainerGetAlt32bitArch(virArch arch);
int lxcContainerChown(virDomainDefPtr def, const char *path);
+bool lxcIsBasicMountLocation(const char *path); + #endif /* LXC_CONTAINER_H */ diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 86d0dd3..acd68db 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -21,10 +21,13 @@ */
#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" @@ -33,7 +36,11 @@
static virDomainFSDefPtr -lxcCreateFSDef(int type, char *src, char* dst) +lxcCreateFSDef(int type, + char *src, + char* dst, + bool readonly, + unsigned long long usage) { virDomainFSDefPtr def;
@@ -44,16 +51,124 @@ lxcCreateFSDef(int type, char *src, char* dst) def->accessmode = VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH; def->src = src; def->dst = dst; + def->readonly = readonly; + def->usage = usage;
return def; }
+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] = ' '; + } + + parts = virStringSplit(tmp, " ", 0);
Not checking parts for NULL
+ 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-1], parts[i]) < 0) + goto error; + } + + /* Append NULL element */ + if (VIR_EXPAND_N(result, ntokens, 1) < 0) + goto error;
A really subtle problem here - we need results to be NULL terminated at all times, not only when the loop is finished. If the VIR_EXPAND_N or VIR_STRDUP calls in the loop body fail, we jump to error where we call virStringFreeList which expects NULL termination. As it stands we have array out of bounds access on OOM.
+ + 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; + + parts = lxcStringSplit(fstabLine);
Not checking for NULL
+ + 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, char *src, char *dst) +lxcAddFSDef(virDomainDefPtr def, + int type, + char *src, + char *dst, + bool readonly, + unsigned long long usage) { virDomainFSDefPtr fsDef = NULL;
- if (!(fsDef = lxcCreateFSDef(type, src, dst))) + if (!(fsDef = lxcCreateFSDef(type, src, dst, readonly, usage))) goto error;
if (VIR_EXPAND_N(def->fss, def->nfss, 1) < 0) @@ -86,7 +201,7 @@ lxcSetRootfs(virDomainDefPtr def, type = VIR_DOMAIN_FS_TYPE_BLOCK;
- if (lxcAddFSDef(def, type, fssrc, fsdst) < 0) + if (lxcAddFSDef(def, type, fssrc, fsdst, false, 0) < 0) goto error;
return 0;
+static int +lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab) +{ + 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;
This method leaks 'options' array.
+ + if (fstab->dst[0] != '/') { + if (virAsprintf(&dst, "/%s", fstab->dst) < 0) + goto error; + } else { + if (VIR_STRDUP(dst, fstab->dst) < 0) + goto error; + } + + /* Check that we don't add basic mounts */ + if (lxcIsBasicMountLocation(dst)) { + VIR_FREE(dst); + return 0; + } + + 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 error; + break; + } + } + if (!sizeStr) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing tmpfs size, set the size option")); + goto error; + } + } else { + if (VIR_STRDUP(src, fstab->src) < 0) + goto error; + } + + /* Do we have ro in options? */ + readonly = virStringArrayHasString(options, "ro"); + + if (lxcAddFSDef(def, type, src, dst, readonly, usage) < 0) + goto error; + + + return 1; + +error: + VIR_FREE(dst); + VIR_FREE(src); + virStringFreeList(options); + return -1; +}
ACK, I'm going to push and squash in 2 fixes For the memory leaks: diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index acd68db..c740e9f 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -249,19 +249,20 @@ lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab) bool readonly; int type = VIR_DOMAIN_FS_TYPE_MOUNT; unsigned long long usage = 0; + int ret = -1; if (fstab->dst[0] != '/') { if (virAsprintf(&dst, "/%s", fstab->dst) < 0) - goto error; + goto cleanup; } else { if (VIR_STRDUP(dst, fstab->dst) < 0) - goto error; + goto cleanup; } /* Check that we don't add basic mounts */ if (lxcIsBasicMountLocation(dst)) { - VIR_FREE(dst); - return 0; + ret = 0; + goto cleanup; } if (STREQ(fstab->type, "tmpfs")) { @@ -272,34 +273,34 @@ lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab) for (i = 0; options[i]; i++) { if ((sizeStr = STRSKIP(options[i], "size="))) { if (lxcConvertSize(sizeStr, &usage) < 0) - goto error; + goto cleanup; break; } } if (!sizeStr) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing tmpfs size, set the size option")); - goto error; + goto cleanup; } } else { if (VIR_STRDUP(src, fstab->src) < 0) - goto error; + goto cleanup; } /* Do we have ro in options? */ readonly = virStringArrayHasString(options, "ro"); if (lxcAddFSDef(def, type, src, dst, readonly, usage) < 0) - goto error; - + goto cleanup; - return 1; + src = dst = NULL; + ret = 1; -error: + cleanup: VIR_FREE(dst); VIR_FREE(src); virStringFreeList(options); - return -1; + return ret; } static int And then for the OOM fixes diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 3e6c2bc..66be361 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -107,7 +107,13 @@ static char ** lxcStringSplit(const char *string) tmp[i] = ' '; } - parts = virStringSplit(tmp, " ", 0); + 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; @@ -115,14 +121,10 @@ static char ** lxcStringSplit(const char *string) if (VIR_EXPAND_N(result, ntokens, 1) < 0) goto error; - if (VIR_STRDUP(result[ntokens-1], parts[i]) < 0) + if (VIR_STRDUP(result[ntokens-2], parts[i]) < 0) goto error; } - /* Append NULL element */ - if (VIR_EXPAND_N(result, ntokens, 1) < 0) - goto error; - VIR_FREE(tmp); virStringFreeList(parts); return result; @@ -143,7 +145,8 @@ lxcParseFstabLine(char *fstabLine) if (!fstabLine || VIR_ALLOC(fstab) < 0) return NULL; - parts = lxcStringSplit(fstabLine); + if (!(parts = lxcStringSplit(fstabLine))) + goto error; if (!parts[0] || !parts[1] || !parts[2] || !parts[3]) goto error; @@ -250,6 +253,9 @@ lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab) 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; @@ -291,7 +297,6 @@ lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab) if (lxcAddFSDef(def, type, src, dst, readonly, usage) < 0) goto cleanup; - dst = NULL; ret = 1; cleanup: -- |: Http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

New Coverity complaint regarding this change ... <...snip...>
virDomainDefPtr lxcParseConfigString(const char *config) { @@ -115,6 +343,7 @@ lxcParseConfigString(const char *config) _("failed to generate uuid")); goto error; } + vmdef->id = -1; vmdef->mem.max_balloon = 64 * 1024;
@@ -127,6 +356,8 @@ lxcParseConfigString(const char *config) * minimum required to make XML parsing pass */ vmdef->maxvcpus = 1;
+ vmdef->nfss = 0; + if (VIR_STRDUP(vmdef->os.type, "exe") < 0) goto error;
@@ -142,6 +373,18 @@ lxcParseConfigString(const char *config) 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 */ + value = virConfGetValue(properties, "lxc.mount.entry");
(1) Event returned_pointer: Pointer "value" returned by "virConfGetValue(properties, "lxc.mount.entry")" is never used. 'value' is set, but never used. John
+ if (virConfWalk(properties, lxcFstabWalkCallback, vmdef) < 0) + goto error; + goto cleanup;

On Thu, 2014-02-13 at 06:34 -0500, John Ferlan wrote:
New Coverity complaint regarding this change ...
<...snip...>
virDomainDefPtr lxcParseConfigString(const char *config) { @@ -115,6 +343,7 @@ lxcParseConfigString(const char *config) _("failed to generate uuid")); goto error; } + vmdef->id = -1; vmdef->mem.max_balloon = 64 * 1024;
@@ -127,6 +356,8 @@ lxcParseConfigString(const char *config) * minimum required to make XML parsing pass */ vmdef->maxvcpus = 1;
+ vmdef->nfss = 0; + if (VIR_STRDUP(vmdef->os.type, "exe") < 0) goto error;
@@ -142,6 +373,18 @@ lxcParseConfigString(const char *config) 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 */ + value = virConfGetValue(properties, "lxc.mount.entry");
(1) Event returned_pointer: Pointer "value" returned by "virConfGetValue(properties, "lxc.mount.entry")" is never used.
'value' is set, but never used.
Oops, that one line is the remaining of a refactoring I made between 2 versions of the patchset. I'll submit a patch to fix that. -- Cedric

If no network configuration is provided, LXC only provides the loopback interface. To match this, we need to use the privnet feature. LXC will also define a 'none' network type in its 1.0.0 version that fits libvirt LXC driver's default. --- src/lxc/lxc_native.c | 55 ++++++++++++++++++++++ .../lxcconf2xmldata/lxcconf2xml-nonenetwork.config | 4 ++ tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml | 21 +++++++++ tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config | 3 ++ tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml | 24 ++++++++++ tests/lxcconf2xmltest.c | 2 + 6 files changed, 109 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index acd68db..bc14d69 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -325,6 +325,57 @@ lxcFstabWalkCallback(const char* name, virConfValuePtr value, void * data) return ret; } +typedef struct { + char *type; + bool privnet; + size_t networks; +} lxcNetworkParseData; + +static int +lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) +{ + lxcNetworkParseData *parseData = data; + + if (STREQ(name, "lxc.network.type")) { + if (parseData->type != NULL && STREQ(parseData->type, "none")) + parseData->privnet = false; + else if ((parseData->type != NULL) && + STRNEQ(parseData->type, "empty") && + STRNEQ(parseData->type, "")) { + parseData->networks++; + } + + /* Start a new network interface config */ + parseData->type = NULL; + + /* Keep the new value */ + parseData->type = value->str; + } + return 0; +} + +static int +lxcConvertNetworkSettings(virDomainDefPtr def, virConfPtr properties) +{ + lxcNetworkParseData data = {NULL, true, 0}; + + virConfWalk(properties, lxcNetworkWalkCallback, &data); + + if ((data.type != NULL) && STREQ(data.type, "none")) + data.privnet = false; + else if ((data.type != NULL) && STRNEQ(data.type, "empty") && + STRNEQ(data.type, "")) { + data.networks++; + } + + 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; +} + virDomainDefPtr lxcParseConfigString(const char *config) { @@ -385,6 +436,10 @@ lxcParseConfigString(const char *config) if (virConfWalk(properties, lxcFstabWalkCallback, vmdef) < 0) goto error; + /* Network configuration */ + if (lxcConvertNetworkSettings(vmdef, properties) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.config b/tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.config new file mode 100644 index 0000000..c1bb9a6 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.config @@ -0,0 +1,4 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 +lxc.network.type = none diff --git a/tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml b/tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml new file mode 100644 index 0000000..eebcb4e --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml @@ -0,0 +1,21 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + </devices> +</domain> diff --git a/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config b/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config new file mode 100644 index 0000000..b6fbe1d --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config @@ -0,0 +1,3 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml b/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml new file mode 100644 index 0000000..511e3dd --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml @@ -0,0 +1,24 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <features> + <privnet/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index c4b21ec..50041a5 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -104,6 +104,8 @@ mymain(void) DO_TEST("simple", false); DO_TEST("fstab", true); + DO_TEST("nonetwork", false); + DO_TEST("nonenetwork", false); return ret; } -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:03PM +0100, Cédric Bosdonnat wrote:
If no network configuration is provided, LXC only provides the loopback interface. To match this, we need to use the privnet feature. LXC will also define a 'none' network type in its 1.0.0 version that fits libvirt LXC driver's default. --- src/lxc/lxc_native.c | 55 ++++++++++++++++++++++ .../lxcconf2xmldata/lxcconf2xml-nonenetwork.config | 4 ++ tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml | 21 +++++++++ tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config | 3 ++ tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml | 24 ++++++++++ tests/lxcconf2xmltest.c | 2 + 6 files changed, 109 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Some of the LXC configuration properties aren't migrated since they would only cause problems in libvirt-lxc: * lxc.network.ipv[46]: LXC driver doesn't setup IP address of guests, see rhbz#1059624 * lxc.network.name, see rhbz#1059630 --- src/lxc/lxc_native.c | 114 ++++++++++++++++++++++++--- tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 5 ++ 2 files changed, 107 insertions(+), 12 deletions(-) diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index bc14d69..42eccfc 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -325,8 +325,80 @@ lxcFstabWalkCallback(const char* name, virConfValuePtr value, void * data) return ret; } +static virDomainNetDefPtr +lxcCreateNetDef(const char *type, + const char *link, + const char *mac, + const char *flag) +{ + virDomainNetDefPtr net = NULL; + + 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 (STREQ(type, "veth")) { + virMacAddr macAddr; + + if (!link) + goto error; + + net->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + + if (VIR_STRDUP(net->data.bridge.brname, link) < 0) + goto error; + + if (mac && virMacAddrParse(mac, &macAddr) == 0) + net->mac = macAddr; + + } + + return net; + +error: + virDomainNetDefFree(net); + return NULL; +} + +static int +lxcAddNetworkDefinition(virDomainDefPtr def, + const char *type, + const char *link, + const char *mac, + const char *flag) +{ + virDomainNetDefPtr net = NULL; + + if ((type == NULL) || STREQ(type, "empty") || STREQ(type, "") || + STREQ(type, "none")) + return 0; + + if (!(net = lxcCreateNetDef(type, link, mac, flag))) + 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); + return -1; +} + typedef struct { + virDomainDefPtr def; char *type; + char *link; + char *mac; + char *flag; bool privnet; size_t networks; } lxcNetworkParseData; @@ -335,38 +407,56 @@ static int lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) { lxcNetworkParseData *parseData = data; + int status; if (STREQ(name, "lxc.network.type")) { - if (parseData->type != NULL && STREQ(parseData->type, "none")) - parseData->privnet = false; - else if ((parseData->type != NULL) && - STRNEQ(parseData->type, "empty") && - STRNEQ(parseData->type, "")) { + /* Store the previous NIC */ + status = lxcAddNetworkDefinition(parseData->def, parseData->type, + parseData->link, parseData->mac, + parseData->flag); + 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; /* 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; + return 0; } static int lxcConvertNetworkSettings(virDomainDefPtr def, virConfPtr properties) { - lxcNetworkParseData data = {NULL, true, 0}; + int status; + lxcNetworkParseData data = {def, NULL, NULL, NULL, NULL, true, 0}; virConfWalk(properties, lxcNetworkWalkCallback, &data); - if ((data.type != NULL) && STREQ(data.type, "none")) - data.privnet = false; - else if ((data.type != NULL) && STRNEQ(data.type, "empty") && - STRNEQ(data.type, "")) { + /* Add the last network definition found */ + status = lxcAddNetworkDefinition(def, data.type, data.link, + data.mac, data.flag); + 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 */ diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml index fadbdca..75c3b28 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml @@ -26,5 +26,10 @@ <target dir='/etc/resolv.conf'/> <readonly/> </filesystem> + <interface type='bridge'> + <mac address='02:00:15:8f:05:c1'/> + <source bridge='virbr0'/> + <link state='up'/> + </interface> </devices> </domain> -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:04PM +0100, Cédric Bosdonnat wrote:
Some of the LXC configuration properties aren't migrated since they would only cause problems in libvirt-lxc: * lxc.network.ipv[46]: LXC driver doesn't setup IP address of guests, see rhbz#1059624 * lxc.network.name, see rhbz#1059630 --- src/lxc/lxc_native.c | 114 ++++++++++++++++++++++++--- tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 5 ++ 2 files changed, 107 insertions(+), 12 deletions(-)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 44 +++++++++++++++++++--- .../lxcconf2xmldata/lxcconf2xml-physnetwork.config | 6 +++ tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml | 26 +++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-physnetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 42eccfc..7997fda 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -366,6 +366,26 @@ error: 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, @@ -374,22 +394,36 @@ lxcAddNetworkDefinition(virDomainDefPtr def, const char *flag) { virDomainNetDefPtr net = NULL; + virDomainHostdevDefPtr hostdev = NULL; if ((type == NULL) || STREQ(type, "empty") || STREQ(type, "") || STREQ(type, "none")) return 0; - if (!(net = lxcCreateNetDef(type, link, mac, flag))) - goto error; + if (type != NULL && STREQ(type, "phys")) { + if (!link || + !(hostdev = lxcCreateHostdevDef(VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES, + VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET, + link))) + goto error; - if (VIR_EXPAND_N(def->nets, def->nnets, 1) < 0) - goto error; - def->nets[def->nnets - 1] = net; + if (VIR_EXPAND_N(def->hostdevs, def->nhostdevs, 1) < 0) + goto error; + def->hostdevs[def->nhostdevs - 1] = hostdev; + } else { + if (!(net = lxcCreateNetDef(type, link, mac, flag))) + 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; } diff --git a/tests/lxcconf2xmldata/lxcconf2xml-physnetwork.config b/tests/lxcconf2xmldata/lxcconf2xml-physnetwork.config new file mode 100644 index 0000000..63a4aa1 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-physnetwork.config @@ -0,0 +1,6 @@ +lxc.network.type = phys +lxc.network.link = eth0 + +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml b/tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml new file mode 100644 index 0000000..35a2a96 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml @@ -0,0 +1,26 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + <hostdev mode='capabilities' type='net'> + <source> + <interface>eth0</interface> + </source> + </hostdev> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 50041a5..c888b42 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -106,6 +106,7 @@ mymain(void) DO_TEST("fstab", true); DO_TEST("nonetwork", false); DO_TEST("nonenetwork", false); + DO_TEST("physnetwork", false); return ret; } -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:05PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 44 +++++++++++++++++++--- .../lxcconf2xmldata/lxcconf2xml-physnetwork.config | 6 +++ tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml | 26 +++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-physnetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 44 ++++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 6 ++++ 2 files changed, 50 insertions(+) diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 7997fda..96523c4 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -500,6 +500,46 @@ lxcConvertNetworkSettings(virDomainDefPtr def, virConfPtr properties) 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; +} + virDomainDefPtr lxcParseConfigString(const char *config) { @@ -564,6 +604,10 @@ lxcParseConfigString(const char *config) if (lxcConvertNetworkSettings(vmdef, properties) < 0) goto error; + /* Consoles */ + if (lxcCreateConsoles(vmdef, properties) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml index 75c3b28..711e0d9 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml @@ -31,5 +31,11 @@ <source bridge='virbr0'/> <link state='up'/> </interface> + <console type='pty'> + <target type='lxc' port='0'/> + </console> + <console type='pty'> + <target type='lxc' port='1'/> + </console> </devices> </domain> -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:06PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 44 ++++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 6 ++++ 2 files changed, 50 insertions(+)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 47 +++++++++++++++++----- .../lxcconf2xml-macvlannetwork.config | 13 ++++++ .../lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml | 26 ++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 96523c4..b413e42 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -329,9 +329,11 @@ static virDomainNetDefPtr lxcCreateNetDef(const char *type, const char *link, const char *mac, - const char *flag) + const char *flag, + const char *macvlanmode) { virDomainNetDefPtr net = NULL; + virMacAddr macAddr; if (VIR_ALLOC(net) < 0) goto error; @@ -343,9 +345,11 @@ lxcCreateNetDef(const char *type, net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN; } - if (STREQ(type, "veth")) { - virMacAddr macAddr; + if (mac && virMacAddrParse(mac, &macAddr) == 0) + net->mac = macAddr; + + if (STREQ(type, "veth")) { if (!link) goto error; @@ -354,9 +358,20 @@ lxcCreateNetDef(const char *type, if (VIR_STRDUP(net->data.bridge.brname, link) < 0) goto error; - if (mac && virMacAddrParse(mac, &macAddr) == 0) - net->mac = macAddr; + } else if (STREQ(type, "macvlan")) { + net->type = VIR_DOMAIN_NET_TYPE_DIRECT; + if (!link || VIR_STRDUP(net->data.direct.linkdev, link) < 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; @@ -391,7 +406,8 @@ lxcAddNetworkDefinition(virDomainDefPtr def, const char *type, const char *link, const char *mac, - const char *flag) + const char *flag, + const char *macvlanmode) { virDomainNetDefPtr net = NULL; virDomainHostdevDefPtr hostdev = NULL; @@ -411,7 +427,7 @@ lxcAddNetworkDefinition(virDomainDefPtr def, goto error; def->hostdevs[def->nhostdevs - 1] = hostdev; } else { - if (!(net = lxcCreateNetDef(type, link, mac, flag))) + if (!(net = lxcCreateNetDef(type, link, mac, flag, macvlanmode))) goto error; if (VIR_EXPAND_N(def->nets, def->nnets, 1) < 0) @@ -433,6 +449,7 @@ typedef struct { char *link; char *mac; char *flag; + char *macvlanmode; bool privnet; size_t networks; } lxcNetworkParseData; @@ -447,7 +464,9 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) /* Store the previous NIC */ status = lxcAddNetworkDefinition(parseData->def, parseData->type, parseData->link, parseData->mac, - parseData->flag); + parseData->flag, + parseData->macvlanmode); + if (status < 0) return -1; else if (status > 0) @@ -460,6 +479,7 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) parseData->link = NULL; parseData->mac = NULL; parseData->flag = NULL; + parseData->macvlanmode = NULL; /* Keep the new value */ parseData->type = value->str; @@ -470,6 +490,12 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) 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 (STRPREFIX(name, "lxc.network")) + VIR_WARN("Unhandled network property: %s = %s", + name, + value->str); return 0; } @@ -478,13 +504,14 @@ static int lxcConvertNetworkSettings(virDomainDefPtr def, virConfPtr properties) { int status; - lxcNetworkParseData data = {def, NULL, NULL, NULL, NULL, true, 0}; + lxcNetworkParseData data = {def, 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.mac, data.flag, + data.macvlanmode); if (status < 0) return -1; else if (status > 0) diff --git a/tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.config b/tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.config new file mode 100644 index 0000000..7c96bfa --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.config @@ -0,0 +1,13 @@ +# Template used to create this container: opensuse +# Template script checksum (SHA-1): 27307e0a95bd81b2c0bd82d6f87fdbe83be075ef + +lxc.network.type = macvlan +lxc.network.flags = up +lxc.network.link = eth0 +lxc.network.hwaddr = 02:00:15:8f:05:c1 +lxc.network.macvlan.mode = vepa + +#remove next line if host DNS configuration should not be available to container +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml b/tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml new file mode 100644 index 0000000..aa0683a --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml @@ -0,0 +1,26 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + <interface type='direct'> + <mac address='02:00:15:8f:05:c1'/> + <source dev='eth0' mode='vepa'/> + <link state='up'/> + </interface> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index c888b42..4e7dd58 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -107,6 +107,7 @@ mymain(void) DO_TEST("nonetwork", false); DO_TEST("nonenetwork", false); DO_TEST("physnetwork", false); + DO_TEST("macvlannetwork", false); return ret; } -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:07PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 47 +++++++++++++++++----- .../lxcconf2xml-macvlannetwork.config | 13 ++++++ .../lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml | 26 ++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 44 ++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-idmap.config | 5 +++ tests/lxcconf2xmldata/lxcconf2xml-idmap.xml | 28 ++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 78 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index b413e42..dd706f8 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -567,6 +567,46 @@ error: 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 (VIR_ALLOC(idmap) < 0) + 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; +} + virDomainDefPtr lxcParseConfigString(const char *config) { @@ -635,6 +675,10 @@ lxcParseConfigString(const char *config) if (lxcCreateConsoles(vmdef, properties) < 0) goto error; + /* lxc.id_map */ + if (virConfWalk(properties, lxcIdmapWalkCallback, vmdef) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-idmap.config b/tests/lxcconf2xmldata/lxcconf2xml-idmap.config new file mode 100644 index 0000000..4c3657a --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-idmap.config @@ -0,0 +1,5 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test + +lxc.id_map = u 10000 0 2000 +lxc.id_map = g 10000 0 1000 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-idmap.xml b/tests/lxcconf2xmldata/lxcconf2xml-idmap.xml new file mode 100644 index 0000000..576c903 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-idmap.xml @@ -0,0 +1,28 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <idmap> + <uid start='0' target='10000' count='2000'/> + <gid start='0' target='10000' count='1000'/> + </idmap> + <features> + <privnet/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 4e7dd58..7042bdf 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -108,6 +108,7 @@ mymain(void) DO_TEST("nonenetwork", false); DO_TEST("physnetwork", false); DO_TEST("macvlannetwork", false); + DO_TEST("idmap", false); return ret; } -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:08PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 44 ++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-idmap.config | 5 +++ tests/lxcconf2xmldata/lxcconf2xml-idmap.xml | 28 ++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 78 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.xml
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Wed, Feb 05, 2014 at 03:10:08PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 44 ++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-idmap.config | 5 +++ tests/lxcconf2xmldata/lxcconf2xml-idmap.xml | 28 ++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 78 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.xml
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index b413e42..dd706f8 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c
+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 (VIR_ALLOC(idmap) < 0) + return -1;
This alloc is bogus since we assign to 'idmap' a few lines later. I'm removing it when i push.
+ + 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; +}
Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 40 ++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-memtune.config | 10 ++++++ tests/lxcconf2xmldata/lxcconf2xml-memtune.xml | 29 +++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 80 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-memtune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-memtune.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index dd706f8..d430abc 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -607,6 +607,42 @@ lxcIdmapWalkCallback(const char *name, virConfValuePtr value, void *data) 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; +} + virDomainDefPtr lxcParseConfigString(const char *config) { @@ -679,6 +715,10 @@ lxcParseConfigString(const char *config) if (virConfWalk(properties, lxcIdmapWalkCallback, vmdef) < 0) goto error; + /* lxc.cgroup.memory.* */ + if (lxcSetMemTune(vmdef, properties) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-memtune.config b/tests/lxcconf2xmldata/lxcconf2xml-memtune.config new file mode 100644 index 0000000..ef07a51 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-memtune.config @@ -0,0 +1,10 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 + +# 1GiB +lxc.cgroup.memory.limit_in_bytes = 1073741824 +# 128MiB +lxc.cgroup.memory.soft_limit_in_bytes = 134217728 +# 2GiB +lxc.cgroup.memory.memsw.limit_in_bytes = 2147483648 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-memtune.xml b/tests/lxcconf2xmldata/lxcconf2xml-memtune.xml new file mode 100644 index 0000000..0264356 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-memtune.xml @@ -0,0 +1,29 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>1048576</memory> + <currentMemory unit='KiB'>0</currentMemory> + <memtune> + <hard_limit unit='KiB'>1048576</hard_limit> + <soft_limit unit='KiB'>131072</soft_limit> + <swap_hard_limit unit='KiB'>2097152</swap_hard_limit> + </memtune> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <features> + <privnet/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 7042bdf..3dd0a0b 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -109,6 +109,7 @@ mymain(void) DO_TEST("physnetwork", false); DO_TEST("macvlannetwork", false); DO_TEST("idmap", false); + DO_TEST("memtune", false); return ret; } -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:09PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 40 ++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-memtune.config | 10 ++++++ tests/lxcconf2xmldata/lxcconf2xml-memtune.xml | 29 +++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 80 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-memtune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-memtune.xml
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 34 ++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-cputune.config | 7 +++++ tests/lxcconf2xmldata/lxcconf2xml-cputune.xml | 29 ++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 71 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cputune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cputune.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index d430abc..65a1d0d 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -643,6 +643,36 @@ lxcSetMemTune(virDomainDefPtr def, virConfPtr properties) return 0; } +static int +lxcSetCpuTune(virDomainDefPtr def, virConfPtr properties) +{ + virConfValuePtr value; + + if ((value = virConfGetValue(properties, "lxc.cgroup.cpu.shares")) && + value->str && virStrToLong_ul(value->str, NULL, 10, + &def->cputune.shares) < 0) + goto error; + + 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; +} + virDomainDefPtr lxcParseConfigString(const char *config) { @@ -719,6 +749,10 @@ lxcParseConfigString(const char *config) if (lxcSetMemTune(vmdef, properties) < 0) goto error; + /* lxc.cgroup.cpu.* */ + if (lxcSetCpuTune(vmdef, properties) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-cputune.config b/tests/lxcconf2xmldata/lxcconf2xml-cputune.config new file mode 100644 index 0000000..9797dec --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-cputune.config @@ -0,0 +1,7 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 + +lxc.cgroup.cpu.shares = 1024 +lxc.cgroup.cpu.cfs_quota_us = -1 +lxc.cgroup.cpu.cfs_period_us = 500000 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-cputune.xml b/tests/lxcconf2xmldata/lxcconf2xml-cputune.xml new file mode 100644 index 0000000..a511dcf --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-cputune.xml @@ -0,0 +1,29 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' current='0'>1</vcpu> + <cputune> + <shares>1024</shares> + <period>500000</period> + <quota>-1</quota> + </cputune> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <features> + <privnet/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 3dd0a0b..1148cd3 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -110,6 +110,7 @@ mymain(void) DO_TEST("macvlannetwork", false); DO_TEST("idmap", false); DO_TEST("memtune", false); + DO_TEST("cputune", false); return ret; } -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:10PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 34 ++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-cputune.config | 7 +++++ tests/lxcconf2xmldata/lxcconf2xml-cputune.xml | 29 ++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 71 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cputune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cputune.xml
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 30 ++++++++++++++++++++++ .../lxcconf2xmldata/lxcconf2xml-cpusettune.config | 6 +++++ tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml | 27 +++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 64 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cpusettune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 65a1d0d..ee8fa75 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -673,6 +673,32 @@ error: return -1; } +static int +lxcSetCpusetTune(virDomainDefPtr def, virConfPtr properties) +{ + virConfValuePtr value; + + 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) { + def->numatune.memory.placement_mode = VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC; + def->numatune.memory.mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT; + if (virBitmapParse(value->str, 0, &def->numatune.memory.nodemask, + VIR_DOMAIN_CPUMASK_LEN) < 0) + return -1; + } + + return 0; +} + virDomainDefPtr lxcParseConfigString(const char *config) { @@ -753,6 +779,10 @@ lxcParseConfigString(const char *config) if (lxcSetCpuTune(vmdef, properties) < 0) goto error; + /* lxc.cgroup.cpuset.* */ + if (lxcSetCpusetTune(vmdef, properties) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-cpusettune.config b/tests/lxcconf2xmldata/lxcconf2xml-cpusettune.config new file mode 100644 index 0000000..a550f57 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-cpusettune.config @@ -0,0 +1,6 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 + +lxc.cgroup.cpuset.cpus = 1,2,5-7 +lxc.cgroup.cpuset.mems = 1-4 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml b/tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml new file mode 100644 index 0000000..1b8fb0c --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml @@ -0,0 +1,27 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' cpuset='1-2,5-7' current='0'>1</vcpu> + <numatune> + <memory mode='strict' nodeset='1-4'/> + </numatune> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <features> + <privnet/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 1148cd3..6bee5c5 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -111,6 +111,7 @@ mymain(void) DO_TEST("idmap", false); DO_TEST("memtune", false); DO_TEST("cputune", false); + DO_TEST("cpusettune", false); return ret; } -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:11PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 30 ++++++++++++++++++++++ .../lxcconf2xmldata/lxcconf2xml-cpusettune.config | 6 +++++ tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml | 27 +++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 64 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cpusettune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 63 ++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config | 7 +++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 35 ++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 106 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index ee8fa75..15c03f2 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -699,6 +699,65 @@ lxcSetCpusetTune(virDomainDefPtr def, virConfPtr properties) return 0; } +static int +lxcBlkioDeviceWalkCallback(const char *name, virConfValuePtr value, void *data) +{ + char **parts = NULL; + virBlkioDevicePtr device = NULL; + virDomainDefPtr def = data; + + if (STRNEQ(name, "lxc.cgroup.blkio.device_weight") || !value->str) + return 0; + + if ((!(parts = lxcStringSplit(value->str)) && (!parts[0] || !parts[1]))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("invalid blkio.device_weight value: '%s'"), + value->str); + goto error; + } + + if (VIR_EXPAND_N(def->blkio.devices, def->blkio.ndevices, 1) < 0) + goto error; + device = &def->blkio.devices[def->blkio.ndevices - 1]; + + if (virAsprintf(&device->path, "/dev/block/%s", parts[0]) < 0) + goto error; + + if (virStrToLong_ui(parts[1], NULL, 10, &device->weight) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse integer: '%s'"), parts[1]); + goto error; + } + + virStringFreeList(parts); + + return 0; + +error: + if (parts) + virStringFreeList(parts); + return -1; +} + +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) { @@ -783,6 +842,10 @@ lxcParseConfigString(const char *config) if (lxcSetCpusetTune(vmdef, properties) < 0) goto error; + /* lxc.cgroup.blkio.* */ + if (lxcSetBlkioTune(vmdef, properties) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config new file mode 100644 index 0000000..8083c71 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config @@ -0,0 +1,7 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 + +lxc.cgroup.blkio.weight = 500 +lxc.cgroup.blkio.device_weight = 8:16 1000 +lxc.cgroup.blkio.device_weight = 8:0 300 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml new file mode 100644 index 0000000..d2408f4 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml @@ -0,0 +1,35 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</memory> + <currentMemory unit='KiB'>0</currentMemory> + <blkiotune> + <weight>500</weight> + <device> + <path>/dev/block/8:16</path> + <weight>1000</weight> + </device> + <device> + <path>/dev/block/8:0</path> + <weight>300</weight> + </device> + </blkiotune> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <features> + <privnet/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 6bee5c5..77baf20 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -112,6 +112,7 @@ mymain(void) DO_TEST("memtune", false); DO_TEST("cputune", false); DO_TEST("cpusettune", false); + DO_TEST("blkiotune", false); return ret; } -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:12PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 63 ++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config | 7 +++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 35 ++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 106 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml
+ if ((!(parts = lxcStringSplit(value->str)) && (!parts[0] || !parts[1]))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("invalid blkio.device_weight value: '%s'"), + value->str); + goto error; + }
The conditional here is wrong and crashes if lxcStringSplit returns NULL. ACK and will add the following @@ -709,7 +709,10 @@ lxcBlkioDeviceWalkCallback(const char *name, virConfValuePtr value, void *data) if (STRNEQ(name, "lxc.cgroup.blkio.device_weight") || !value->str) return 0; - if ((!(parts = lxcStringSplit(value->str)) && (!parts[0] || !parts[1]))) { + if (!(parts = lxcStringSplit(value->str))) + return -1; + + if (!parts[0] || !parts[1]) { virReportError(VIR_ERR_INTERNAL_ERROR, _("invalid blkio.device_weight value: '%s'"), value->str); -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 9 +++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.config | 1 + tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 15c03f2..1997370 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -794,6 +794,15 @@ lxcParseConfigString(const char *config) 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; diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.config b/tests/lxcconf2xmldata/lxcconf2xml-simple.config index f75e8fc..b90abc1 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-simple.config +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.config @@ -14,6 +14,7 @@ lxc.mount.entry = tmpfs run tmpfs size=8m,mode=0755,nodev,nosuid 0 0 lxc.mount.entry = /etc/resolv.conf etc/resolv.conf none bind,ro 0 0 lxc.rootfs = /var/lib/lxc/migrate_test/rootfs lxc.utsname = migrate_test +lxc.arch = x86 lxc.autodev=1 lxc.tty = 2 lxc.pts = 1024 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml index 711e0d9..6ec0f17 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml @@ -5,7 +5,7 @@ <currentMemory unit='KiB'>0</currentMemory> <vcpu placement='static' current='0'>1</vcpu> <os> - <type>exe</type> + <type arch='i686'>exe</type> <init>/sbin/init</init> </os> <clock offset='utc'/> -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:13PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 9 +++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.config | 1 + tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 1997370..9a16523 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -286,6 +286,10 @@ lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab) goto error; } + /* 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"); -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:14PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 4 ++++ 1 file changed, 4 insertions(+)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

The problem with VLAN is that the user still has to manually create the vlan interface on the host. Then the generated configuration will use it as a nerwork hostdev device. So the generated configurations of the following two fragments are equivalent (see rhbz#1059637). lxc.network.type = phys lxc.network.link = eth0.5 lxc.network.type = vlan lxc.network.link = eth0 lxc.network.vlan.id = 5 --- src/lxc/lxc_native.c | 28 ++++++++++++++++++---- .../lxcconf2xmldata/lxcconf2xml-vlannetwork.config | 12 ++++++++++ tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml | 26 ++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 9a16523..8d8c50a 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -411,22 +411,33 @@ lxcAddNetworkDefinition(virDomainDefPtr def, const char *link, const char *mac, const char *flag, - const char *macvlanmode) + 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; - if (type != NULL && STREQ(type, "phys")) { + isPhys = STREQ(type, "phys"); + isVlan = STREQ(type, "vlan"); + if (type != NULL && (isPhys || isVlan)) { if (!link || !(hostdev = lxcCreateHostdevDef(VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES, VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET, link))) goto error; + /* This still requires the user to manually setup the vlan interface + * on the host */ + if (isVlan && !(link && vlanid && + virAsprintf(&hostdev->source.caps.u.net.iface, + "%s.%s", link, vlanid) >= 0)) + goto error; + if (VIR_EXPAND_N(def->hostdevs, def->nhostdevs, 1) < 0) goto error; def->hostdevs[def->nhostdevs - 1] = hostdev; @@ -454,6 +465,7 @@ typedef struct { char *mac; char *flag; char *macvlanmode; + char *vlanid; bool privnet; size_t networks; } lxcNetworkParseData; @@ -469,7 +481,8 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) status = lxcAddNetworkDefinition(parseData->def, parseData->type, parseData->link, parseData->mac, parseData->flag, - parseData->macvlanmode); + parseData->macvlanmode, + parseData->vlanid); if (status < 0) return -1; @@ -484,6 +497,7 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) parseData->mac = NULL; parseData->flag = NULL; parseData->macvlanmode = NULL; + parseData->vlanid = NULL; /* Keep the new value */ parseData->type = value->str; @@ -496,6 +510,8 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) 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, @@ -508,14 +524,16 @@ static int lxcConvertNetworkSettings(virDomainDefPtr def, virConfPtr properties) { int status; - lxcNetworkParseData data = {def, NULL, NULL, NULL, NULL, NULL, true, 0}; + 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.macvlanmode, + data.vlanid); if (status < 0) return -1; else if (status > 0) diff --git a/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config b/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config new file mode 100644 index 0000000..327202c --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config @@ -0,0 +1,12 @@ +# Template used to create this container: opensuse +# Template script checksum (SHA-1): 27307e0a95bd81b2c0bd82d6f87fdbe83be075ef + +lxc.network.type = vlan +lxc.network.flags = up +lxc.network.link = eth0 +lxc.network.hwaddr = 02:00:15:8f:05:c1 +lxc.network.vlan.id = 2 + +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml b/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml new file mode 100644 index 0000000..7d6d51b --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml @@ -0,0 +1,26 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + <hostdev mode='capabilities' type='net'> + <source> + <interface>eth0.2</interface> + </source> + </hostdev> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 77baf20..e799893 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -108,6 +108,7 @@ mymain(void) DO_TEST("nonenetwork", false); DO_TEST("physnetwork", false); DO_TEST("macvlannetwork", false); + DO_TEST("vlannetwork", false); DO_TEST("idmap", false); DO_TEST("memtune", false); DO_TEST("cputune", false); -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:15PM +0100, Cédric Bosdonnat wrote:
The problem with VLAN is that the user still has to manually create the vlan interface on the host. Then the generated configuration will use it as a nerwork hostdev device. So the generated configurations of the following two fragments are equivalent (see rhbz#1059637).
lxc.network.type = phys lxc.network.link = eth0.5
lxc.network.type = vlan lxc.network.link = eth0 lxc.network.vlan.id = 5 --- src/lxc/lxc_native.c | 28 ++++++++++++++++++---- .../lxcconf2xmldata/lxcconf2xml-vlannetwork.config | 12 ++++++++++ tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml | 26 ++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Wed, Feb 05, 2014 at 03:10:15PM +0100, Cédric Bosdonnat wrote:
The problem with VLAN is that the user still has to manually create the vlan interface on the host. Then the generated configuration will use it as a nerwork hostdev device. So the generated configurations of the following two fragments are equivalent (see rhbz#1059637).
lxc.network.type = phys lxc.network.link = eth0.5
lxc.network.type = vlan lxc.network.link = eth0 lxc.network.vlan.id = 5 --- src/lxc/lxc_native.c | 28 ++++++++++++++++++---- .../lxcconf2xmldata/lxcconf2xml-vlannetwork.config | 12 ++++++++++ tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml | 26 ++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 9a16523..8d8c50a 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -411,22 +411,33 @@ lxcAddNetworkDefinition(virDomainDefPtr def, const char *link, const char *mac, const char *flag, - const char *macvlanmode) + 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;
- if (type != NULL && STREQ(type, "phys")) { + isPhys = STREQ(type, "phys"); + isVlan = STREQ(type, "vlan"); + if (type != NULL && (isPhys || isVlan)) { if (!link || !(hostdev = lxcCreateHostdevDef(VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES, VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET, link))) goto error;
+ /* This still requires the user to manually setup the vlan interface + * on the host */ + if (isVlan && !(link && vlanid && + virAsprintf(&hostdev->source.caps.u.net.iface, + "%s.%s", link, vlanid) >= 0)) + goto error;
Small memory leak as this virAsprintf overwrites memory allocated by lxcCreateHostdevDef. Will fx that when pushing Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- docs/drvlxc.html.in | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/docs/drvlxc.html.in b/docs/drvlxc.html.in index 0f3efb0..fc4bc20 100644 --- a/docs/drvlxc.html.in +++ b/docs/drvlxc.html.in @@ -555,7 +555,7 @@ and LXC. For further details about usage of virsh consult its manual page. </p> -<h3><a name="usageSave">Defining (saving) container configuration></a></h3> +<h3><a name="usageSave">Defining (saving) container configuration</a></h3> <p> The <code>virsh define</code> command takes an XML configuration @@ -702,5 +702,37 @@ host # virt-top -c lxc:/// </pre> +<h3><a name="usageConvert">Converting LXC container configuration</a></h3> + +<p> +The <code>virsh domxml-from-native</code> command can be used to convert +most of the LXC container configuration into a domain XML fragment +</p> + +<pre> +# virsh -c lxc:/// domxml-from-native lxc-tools /var/lib/lxc/myguest/config +</pre> + +<p> +This conversion has some limitations due to the fact that the +domxml-from-native command output has to be independent of the host. Here +are a few things to take care of before converting: +</p> + +<ul> +<li> +Replace the fstab file referenced by <tt>lxc.mount</tt> by the corresponding +lxc.mount.entry lines. +</li> +<li> +Replace all relative sizes of tmpfs mount entries to absolute sizes. Also +make sure that tmpfs entries all have a size option (default is 50%). +</li> +<li> +Define <tt>lxc.cgroup.memory.limit_in_bytes</tt> to properly limit the memory +available to the container. The conversion will use 64MiB as the default. +</li> +</ul> + </body> </html> -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:16PM +0100, Cédric Bosdonnat wrote:
--- docs/drvlxc.html.in | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 68 ++++++++++++++++++---- tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config | 4 ++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 4 ++ 3 files changed, 65 insertions(+), 11 deletions(-) diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 8d8c50a..675883c 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -727,28 +727,73 @@ lxcBlkioDeviceWalkCallback(const char *name, virConfValuePtr value, void *data) char **parts = NULL; virBlkioDevicePtr device = NULL; virDomainDefPtr def = data; + size_t i = 0; + char *path = NULL; - if (STRNEQ(name, "lxc.cgroup.blkio.device_weight") || !value->str) + if (!STRPREFIX(name, "lxc.cgroup.blkio.") || + STREQ(name, "lxc.cgroup.blkio.weight")|| !value->str) return 0; if ((!(parts = lxcStringSplit(value->str)) && (!parts[0] || !parts[1]))) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("invalid blkio.device_weight value: '%s'"), - value->str); + _("invalid %s value: '%s'"), + name, value->str); goto error; } - if (VIR_EXPAND_N(def->blkio.devices, def->blkio.ndevices, 1) < 0) + if (virAsprintf(&path, "/dev/block/%s", parts[0]) < 0) goto error; - device = &def->blkio.devices[def->blkio.ndevices - 1]; - if (virAsprintf(&device->path, "/dev/block/%s", parts[0]) < 0) - goto error; + /* 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 error; + device = &def->blkio.devices[def->blkio.ndevices - 1]; + device->path = path; + } - if (virStrToLong_ui(parts[1], NULL, 10, &device->weight) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("failed to parse integer: '%s'"), parts[1]); - goto error; + /* 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 error; + } + } 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 error; + } + } 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 error; + } + } 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 error; + } + } 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 error; + } + } else { + VIR_WARN("Unhandled blkio tune config: %s", name); } virStringFreeList(parts); @@ -758,6 +803,7 @@ lxcBlkioDeviceWalkCallback(const char *name, virConfValuePtr value, void *data) error: if (parts) virStringFreeList(parts); + VIR_FREE(path); return -1; } diff --git a/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config index 8083c71..b19d9a5 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config +++ b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config @@ -5,3 +5,7 @@ lxc.autodev=1 lxc.cgroup.blkio.weight = 500 lxc.cgroup.blkio.device_weight = 8:16 1000 lxc.cgroup.blkio.device_weight = 8:0 300 +lxc.cgroup.blkio.throttle.read_bps_device = 8:16 1234 +lxc.cgroup.blkio.throttle.write_bps_device = 8:16 5678 +lxc.cgroup.blkio.throttle.read_iops_device = 8:16 4321 +lxc.cgroup.blkio.throttle.write_iops_device = 8:16 8765 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml index d2408f4..628798d 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml +++ b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml @@ -8,6 +8,10 @@ <device> <path>/dev/block/8:16</path> <weight>1000</weight> + <read_iops_sec>4321</read_iops_sec> + <write_iops_sec>8765</write_iops_sec> + <read_bytes_sec>1234</read_bytes_sec> + <write_bytes_sec>5678</write_bytes_sec> </device> <device> <path>/dev/block/8:0</path> -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:17PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 68 ++++++++++++++++++---- tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config | 4 ++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 4 ++ 3 files changed, 65 insertions(+), 11 deletions(-)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

direct interfaces are already brought up when creating them. --- src/lxc/lxc_process.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index ed729f6..6f7ff74 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -245,6 +245,7 @@ char *virLXCProcessSetupInterfaceBridged(virConnectPtr conn, char *parentVeth; char *containerVeth = NULL; virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(net); + bool vethUp = false; VIR_DEBUG("calling vethCreate()"); parentVeth = net->ifname; @@ -283,6 +284,10 @@ char *virLXCProcessSetupInterfaceBridged(virConnectPtr conn, virDomainConfNWFilterInstantiate(conn, vm->uuid, net) < 0) goto cleanup; + vethUp = net->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP; + if (virNetDevSetOnline(containerVeth, vethUp) < 0) + goto cleanup; + ret = containerVeth; cleanup: -- 1.8.5.2

On Wed, 2014-02-05 at 15:10 +0100, Cédric Bosdonnat wrote:
direct interfaces are already brought up when creating them.
Just ignore (and drop) this patch, veth interfaces are already up when starting the container... even thought I couldn't ifdown it ;) -- Cedric
--- src/lxc/lxc_process.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index ed729f6..6f7ff74 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -245,6 +245,7 @@ char *virLXCProcessSetupInterfaceBridged(virConnectPtr conn, char *parentVeth; char *containerVeth = NULL; virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(net); + bool vethUp = false;
VIR_DEBUG("calling vethCreate()"); parentVeth = net->ifname; @@ -283,6 +284,10 @@ char *virLXCProcessSetupInterfaceBridged(virConnectPtr conn, virDomainConfNWFilterInstantiate(conn, vm->uuid, net) < 0) goto cleanup;
+ vethUp = net->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP; + if (virNetDevSetOnline(containerVeth, vethUp) < 0) + goto cleanup; + ret = containerVeth;
cleanup:

To ease LXC configuration conversion, allow blkiotune device XML fragments to define the device using its major:minor numbers. --- docs/formatdomain.html.in | 10 +- src/conf/domain_conf.c | 45 ++++++++- src/conf/domain_conf.h | 2 + src/lxc/lxc_cgroup.c | 5 + src/lxc/lxc_driver.c | 10 ++ src/lxc/lxc_native.c | 24 ++++- src/qemu/qemu_cgroup.c | 5 + src/qemu/qemu_driver.c | 10 ++ src/util/vircgroup.c | 126 ++++++++++-------------- src/util/vircgroup.h | 10 ++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 4 +- 11 files changed, 165 insertions(+), 86 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index fd02864..2ab7d39 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -761,6 +761,10 @@ <path>/dev/sdb</path> <weight>500</weight> </device> + <device> + <node major='8' minor='0'/> + <weight>500</weight> + </device> </blkiotune> ... </domain> @@ -794,7 +798,11 @@ absolute path of the device, and <code>weight</code> giving the relative weight of that device, in the range [100, 1000]. After kernel 2.6.39, the value could be in the - range [10, 1000].<span class="since">Since 0.9.8</span></dd> + range [10, 1000].<span class="since">Since 0.9.8</span>. + <span class="since">Since 1.2.2</span> each <code>device</code> + element can replace the mandatory <code>path</code> sub-element + by a <code>node</code> one. <code>node</code> has two mandatory + attributes <code>major</code> and <code>minor</code>.</dd> </dl> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 28e24f9..65192df 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -905,6 +905,7 @@ virBlkioDeviceArrayClear(virBlkioDevicePtr devices, * * <device> * <path>/fully/qualified/device/path</path> + * <node major='8' minor='0/> * <weight>weight</weight> * <read_bytes_sec>bps</read_bytes_sec> * <write_bytes_sec>bps</write_bytes_sec> @@ -920,12 +921,38 @@ virDomainBlkioDeviceParseXML(xmlNodePtr root, { char *c = NULL; xmlNodePtr node; + char *major = NULL; + char *minor = NULL; + bool hasNumbers = false; node = root->children; while (node) { if (node->type == XML_ELEMENT_NODE) { if (xmlStrEqual(node->name, BAD_CAST "path") && !dev->path) { dev->path = (char *)xmlNodeGetContent(node); + } else if (xmlStrEqual(node->name, BAD_CAST "node") && + !hasNumbers){ + if (!(major = virXMLPropString(node, "major")) || + (!(minor = virXMLPropString(node, "minor")))) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("node missing major or minor attribute")); + goto error; + } + if (virStrToLong_ui(major, NULL, 10, &dev->major) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("could not parse major %s"), + major); + goto error; + } + if (virStrToLong_ui(major, NULL, 10, &dev->minor) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("could not parse minor %s"), + minor); + goto error; + } + hasNumbers = true; + VIR_FREE(major); + VIR_FREE(minor); } else if (xmlStrEqual(node->name, BAD_CAST "weight")) { c = (char *)xmlNodeGetContent(node); if (virStrToLong_ui(c, NULL, 10, &dev->weight) < 0) { @@ -975,9 +1002,13 @@ virDomainBlkioDeviceParseXML(xmlNodePtr root, } node = node->next; } - if (!dev->path) { + if (!dev->path && !hasNumbers) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("missing per-device path")); + _("missing per-device path or major/minor")); + return -1; + } else if (dev->path && hasNumbers) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("cannot have both per-device path and major/minor")); return -1; } @@ -985,6 +1016,8 @@ virDomainBlkioDeviceParseXML(xmlNodePtr root, error: VIR_FREE(c); + VIR_FREE(major); + VIR_FREE(minor); VIR_FREE(dev->path); return -1; } @@ -16855,8 +16888,12 @@ virDomainDefFormatInternal(virDomainDefPtr def, !dev->rbps && !dev->wbps) continue; virBufferAddLit(buf, " <device>\n"); - virBufferEscapeString(buf, " <path>%s</path>\n", - dev->path); + if (dev->path) + virBufferEscapeString(buf, " <path>%s</path>\n", + dev->path); + else + virBufferAsprintf(buf, " <node major='%u' minor='%u'/>\n", + dev->major, dev->minor); if (dev->weight) virBufferAsprintf(buf, " <weight>%u</weight>\n", dev->weight); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index d8f2e49..24cc00c 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1890,6 +1890,8 @@ struct _virBlkioDevice { unsigned int wiops; unsigned long long rbps; unsigned long long wbps; + unsigned int major; + unsigned int minor; }; enum virDomainRNGModel { diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c index cc0d5e8..aabd4f8 100644 --- a/src/lxc/lxc_cgroup.c +++ b/src/lxc/lxc_cgroup.c @@ -116,26 +116,31 @@ static int virLXCCgroupSetupBlkioTune(virDomainDefPtr def, if (dev->weight && (virCgroupSetBlkioDeviceWeight(cgroup, dev->path, + dev->major, dev->minor, dev->weight) < 0)) return -1; if (dev->riops && (virCgroupSetBlkioDeviceReadIops(cgroup, dev->path, + dev->major, dev->minor, dev->riops) < 0)) return -1; if (dev->wiops && (virCgroupSetBlkioDeviceWriteIops(cgroup, dev->path, + dev->major, dev->minor, dev->wiops) < 0)) return -1; if (dev->rbps && (virCgroupSetBlkioDeviceReadBps(cgroup, dev->path, + dev->major, dev->minor, dev->rbps) < 0)) return -1; if (dev->wbps && (virCgroupSetBlkioDeviceWriteBps(cgroup, dev->path, + dev->major, dev->minor, dev->wbps) < 0)) return -1; } diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index dc0e8e0..057214a 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2323,6 +2323,8 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceWeight(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].weight) < 0) { ret = -1; break; @@ -2332,6 +2334,8 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceReadIops(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].riops) < 0) { ret = -1; break; @@ -2341,6 +2345,8 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceWriteIops(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].wiops) < 0) { ret = -1; break; @@ -2350,6 +2356,8 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceReadBps(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].rbps) < 0) { ret = -1; break; @@ -2359,6 +2367,8 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceWriteBps(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].wbps) < 0) { ret = -1; break; diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 675883c..c7ebfb2 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -725,36 +725,52 @@ static int lxcBlkioDeviceWalkCallback(const char *name, virConfValuePtr value, void *data) { char **parts = NULL; + char **numbers = NULL; virBlkioDevicePtr device = NULL; virDomainDefPtr def = data; size_t i = 0; char *path = NULL; + unsigned int major, minor = 0; if (!STRPREFIX(name, "lxc.cgroup.blkio.") || STREQ(name, "lxc.cgroup.blkio.weight")|| !value->str) return 0; - if ((!(parts = lxcStringSplit(value->str)) && (!parts[0] || !parts[1]))) { + if ((!(parts = lxcStringSplit(value->str))) || virStringListLength(parts) != 2 || + (!(numbers = virStringSplit(parts[0], ":", 2))) || + virStringListLength(numbers) != 2) { virReportError(VIR_ERR_INTERNAL_ERROR, _("invalid %s value: '%s'"), name, value->str); goto error; } - if (virAsprintf(&path, "/dev/block/%s", parts[0]) < 0) + /* *Get the major:minor numbers */ + if (virStrToLong_ui(numbers[0], NULL, 10, &major) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse major: '%s'"), numbers[0]); goto error; + } + if (virStrToLong_ui(numbers[1], NULL, 10, &minor) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse minor: '%s'"), numbers[1]); + goto error; + } /* 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)) + if (def->blkio.devices[i].major == major && + def->blkio.devices[i].minor == minor) device = &def->blkio.devices[i]; } if (!device) { if (VIR_EXPAND_N(def->blkio.devices, def->blkio.ndevices, 1) < 0) goto error; device = &def->blkio.devices[def->blkio.ndevices - 1]; - device->path = path; + device->major = major; + device->minor = minor; + device->path = NULL; } /* Set the value */ diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index a97f184..2808749 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -404,26 +404,31 @@ qemuSetupBlkioCgroup(virDomainObjPtr vm) virBlkioDevicePtr dev = &vm->def->blkio.devices[i]; if (dev->weight && (virCgroupSetBlkioDeviceWeight(priv->cgroup, dev->path, + dev->major, dev->minor, dev->weight) < 0)) return -1; if (dev->riops && (virCgroupSetBlkioDeviceReadIops(priv->cgroup, dev->path, + dev->major, dev->minor, dev->riops) < 0)) return -1; if (dev->wiops && (virCgroupSetBlkioDeviceWriteIops(priv->cgroup, dev->path, + dev->major, dev->minor, dev->wiops) < 0)) return -1; if (dev->rbps && (virCgroupSetBlkioDeviceReadBps(priv->cgroup, dev->path, + dev->major, dev->minor, dev->rbps) < 0)) return -1; if (dev->wbps && (virCgroupSetBlkioDeviceWriteBps(priv->cgroup, dev->path, + dev->major, dev->minor, dev->wbps) < 0)) return -1; } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0128356..f73d942 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7691,6 +7691,8 @@ qemuDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceWeight(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].weight) < 0) { ret = -1; break; @@ -7700,6 +7702,8 @@ qemuDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceReadIops(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].riops) < 0) { ret = -1; break; @@ -7709,6 +7713,8 @@ qemuDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceWriteIops(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].wiops) < 0) { ret = -1; break; @@ -7718,6 +7724,8 @@ qemuDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceReadBps(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].rbps) < 0) { ret = -1; break; @@ -7727,6 +7735,8 @@ qemuDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceWriteBps(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].wbps) < 0) { ret = -1; break; diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c index a6d60c5..e29d7c3 100644 --- a/src/util/vircgroup.c +++ b/src/util/vircgroup.c @@ -1824,6 +1824,37 @@ virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight) return ret; } +static int +virCgroupGetBlkioDeviceNumbers(const char *path, + unsigned int *major, + unsigned int *minor) +{ + struct stat sb; + + if (!major || !minor) + return -1; + + if (path) { + if (stat(path, &sb) < 0) { + virReportSystemError(errno, + _("Path '%s' is not accessible"), + path); + return -1; + } + + if (!S_ISBLK(sb.st_mode)) { + virReportSystemError(EINVAL, + _("Path '%s' must be a block device"), + path); + return -1; + } + + *major = major(sb.st_rdev); + *minor = minor(sb.st_rdev); + } + return 0; +} + /** * virCgroupSetBlkioDeviceReadIops: * @group: The cgroup to change block io setting for @@ -1835,28 +1866,17 @@ virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight) int virCgroupSetBlkioDeviceReadIops(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned int riops) { char *str; - struct stat sb; int ret; - if (stat(path, &sb) < 0) { - virReportSystemError(errno, - _("Path '%s' is not accessible"), - path); + if (virCgroupGetBlkioDeviceNumbers(path, &major, &minor) < 0) return -1; - } - if (!S_ISBLK(sb.st_mode)) { - virReportSystemError(EINVAL, - _("Path '%s' must be a block device"), - path); - return -1; - } - - if (virAsprintf(&str, "%d:%d %u", major(sb.st_rdev), - minor(sb.st_rdev), riops) < 0) + if (virAsprintf(&str, "%u:%u %u", major, minor, riops) < 0) return -1; ret = virCgroupSetValueStr(group, @@ -1880,28 +1900,17 @@ virCgroupSetBlkioDeviceReadIops(virCgroupPtr group, int virCgroupSetBlkioDeviceWriteIops(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned int wiops) { char *str; - struct stat sb; int ret; - if (stat(path, &sb) < 0) { - virReportSystemError(errno, - _("Path '%s' is not accessible"), - path); + if (virCgroupGetBlkioDeviceNumbers(path, &major, &minor) < 0) return -1; - } - if (!S_ISBLK(sb.st_mode)) { - virReportSystemError(EINVAL, - _("Path '%s' must be a block device"), - path); - return -1; - } - - if (virAsprintf(&str, "%d:%d %u", major(sb.st_rdev), - minor(sb.st_rdev), wiops) < 0) + if (virAsprintf(&str, "%u:%u %u", major, minor, wiops) < 0) return -1; ret = virCgroupSetValueStr(group, @@ -1925,28 +1934,17 @@ virCgroupSetBlkioDeviceWriteIops(virCgroupPtr group, int virCgroupSetBlkioDeviceReadBps(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned long long rbps) { char *str; - struct stat sb; int ret; - if (stat(path, &sb) < 0) { - virReportSystemError(errno, - _("Path '%s' is not accessible"), - path); + if (virCgroupGetBlkioDeviceNumbers(path, &major, &minor) < 0) return -1; - } - if (!S_ISBLK(sb.st_mode)) { - virReportSystemError(EINVAL, - _("Path '%s' must be a block device"), - path); - return -1; - } - - if (virAsprintf(&str, "%d:%d %llu", major(sb.st_rdev), - minor(sb.st_rdev), rbps) < 0) + if (virAsprintf(&str, "%u:%u %llu", major, minor, rbps) < 0) return -1; ret = virCgroupSetValueStr(group, @@ -1969,28 +1967,17 @@ virCgroupSetBlkioDeviceReadBps(virCgroupPtr group, int virCgroupSetBlkioDeviceWriteBps(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned long long wbps) { char *str; - struct stat sb; int ret; - if (stat(path, &sb) < 0) { - virReportSystemError(errno, - _("Path '%s' is not accessible"), - path); - return -1; - } - - if (!S_ISBLK(sb.st_mode)) { - virReportSystemError(EINVAL, - _("Path '%s' must be a block device"), - path); + if (virCgroupGetBlkioDeviceNumbers(path, &major, &minor) < 0) return -1; - } - if (virAsprintf(&str, "%d:%d %llu", major(sb.st_rdev), - minor(sb.st_rdev), wbps) < 0) + if (virAsprintf(&str, "%u:%u %llu", major, minor, wbps) < 0) return -1; ret = virCgroupSetValueStr(group, @@ -2018,28 +2005,17 @@ virCgroupSetBlkioDeviceWriteBps(virCgroupPtr group, int virCgroupSetBlkioDeviceWeight(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned int weight) { char *str; - struct stat sb; int ret; - if (stat(path, &sb) < 0) { - virReportSystemError(errno, - _("Path '%s' is not accessible"), - path); - return -1; - } - - if (!S_ISBLK(sb.st_mode)) { - virReportSystemError(EINVAL, - _("Path '%s' must be a block device"), - path); + if (virCgroupGetBlkioDeviceNumbers(path, &major, &minor) < 0) return -1; - } - if (virAsprintf(&str, "%d:%d %d", major(sb.st_rdev), minor(sb.st_rdev), - weight) < 0) + if (virAsprintf(&str, "%u:%u %d", major, minor, weight) < 0) return -1; ret = virCgroupSetValueStr(group, diff --git a/src/util/vircgroup.h b/src/util/vircgroup.h index a70eb18..2258b36 100644 --- a/src/util/vircgroup.h +++ b/src/util/vircgroup.h @@ -124,22 +124,32 @@ int virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight); int virCgroupSetBlkioDeviceWeight(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned int weight); int virCgroupSetBlkioDeviceReadIops(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned int riops); int virCgroupSetBlkioDeviceWriteIops(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned int wiops); int virCgroupSetBlkioDeviceReadBps(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned long long rbps); int virCgroupSetBlkioDeviceWriteBps(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned long long wbps); int virCgroupSetMemory(virCgroupPtr group, unsigned long long kb); diff --git a/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml index 628798d..73f90ef 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml +++ b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml @@ -6,7 +6,7 @@ <blkiotune> <weight>500</weight> <device> - <path>/dev/block/8:16</path> + <node major='8' minor='16'/> <weight>1000</weight> <read_iops_sec>4321</read_iops_sec> <write_iops_sec>8765</write_iops_sec> @@ -14,7 +14,7 @@ <write_bytes_sec>5678</write_bytes_sec> </device> <device> - <path>/dev/block/8:0</path> + <node major='8' minor='0'/> <weight>300</weight> </device> </blkiotune> -- 1.8.5.2

On Wed, Feb 05, 2014 at 03:10:19PM +0100, Cédric Bosdonnat wrote:
To ease LXC configuration conversion, allow blkiotune device XML fragments to define the device using its major:minor numbers. --- docs/formatdomain.html.in | 10 +- src/conf/domain_conf.c | 45 ++++++++- src/conf/domain_conf.h | 2 + src/lxc/lxc_cgroup.c | 5 + src/lxc/lxc_driver.c | 10 ++ src/lxc/lxc_native.c | 24 ++++- src/qemu/qemu_cgroup.c | 5 + src/qemu/qemu_driver.c | 10 ++ src/util/vircgroup.c | 126 ++++++++++-------------- src/util/vircgroup.h | 10 ++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 4 +- 11 files changed, 165 insertions(+), 86 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index fd02864..2ab7d39 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -761,6 +761,10 @@ <path>/dev/sdb</path> <weight>500</weight> </device> + <device> + <node major='8' minor='0'/> + <weight>500</weight> + </device> </blkiotune>
I realize this is helping the conversion of existing configs, but personally I'm pretty loathe to add this syntax. With device paths it is possible to have stable paths ie using /dev/disk/by*. With major/minor the XML configuration is not portable across hosts or even stable within a host since major numbers are fairly arbitrarily assigned with hotpluggable SCSI or networked iSCSI. Personally I'd list this as one of the things an admin has to fixup manually post conversion. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Hi Daniel, On Tue, 2014-02-11 at 14:55 +0000, Daniel P. Berrange wrote:
I realize this is helping the conversion of existing configs, but personally I'm pretty loathe to add this syntax. With device paths it is possible to have stable paths ie using /dev/disk/by*. With major/minor the XML configuration is not portable across hosts or even stable within a host since major numbers are fairly arbitrarily assigned with hotpluggable SCSI or networked iSCSI.
Personally I'd list this as one of the things an admin has to fixup manually post conversion.
Ok, then let's drop that patch from the serie: it was just a way to communicate on that topic ;) -- Cedric

On Wed, Feb 05, 2014 at 03:09:58PM +0100, Cédric Bosdonnat wrote:
Here is an updated version of the patch set fixing comments from Daniel. It also adds 3 commits: * One adding conversion for the newly supported blkio throttle tune in lxc driver. * One actually using the state of the veth network device in lxc driver. * One adding the ability to give major:minor numbers instead of a path for blkio tune devices.
The last one is a way to address Daniel's comment on the /dev/block/... paths.
Cédric Bosdonnat (21): Improve virConf parse to handle LXC config format LXC driver: started implementing connectDomainXMLFromNative LXC from native: import rootfs LXC from native: migrate fstab and lxc.mount.entry LXC from native: implement no network conversion LXC from native: migrate veth network configuration LXC from native: convert phys network types to net hostdev devices LXC from native: convert lxc.tty to console devices LXC from native: convert macvlan network configuration LXC from native: convert lxc.id_map into <idmap> LXC from native: migrate memory tuning LXC from native: map lxc.cgroup.cpu.* LXC from native: map lxc.cgroup.cpuset.* LXC from native: add lxc.cgroup.blkio.* mapping LXC from native: map lxc.arch to /domain/os/type@arch LXC from native: map block filesystems LXC from native: map vlan network type LXC: added some doc on domxml-from-native with mention of limitations LXC from native: convert blkio throttle config lxc: honor link state=up for veth interfaces blkiotune: allow <node major='' minor=''/> in place of <path>
.gitignore | 1 + docs/drvlxc.html.in | 34 +- docs/formatdomain.html.in | 10 +- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/conf/domain_conf.c | 45 +- src/conf/domain_conf.h | 2 + src/libvirt_private.syms | 1 + src/lxc/lxc_cgroup.c | 5 + src/lxc/lxc_container.c | 2 +- src/lxc/lxc_container.h | 2 + src/lxc/lxc_driver.c | 41 + src/lxc/lxc_native.c | 952 +++++++++++++++++++++ src/lxc/lxc_native.h | 32 + src/lxc/lxc_process.c | 5 + src/qemu/qemu_cgroup.c | 5 + src/qemu/qemu_driver.c | 10 + src/util/vircgroup.c | 126 ++- src/util/vircgroup.h | 10 + src/util/virconf.c | 46 +- src/util/virconf.h | 10 + tests/Makefile.am | 7 +- tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config | 11 + tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 39 + .../lxcconf2xmldata/lxcconf2xml-cpusettune.config | 6 + tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml | 27 + tests/lxcconf2xmldata/lxcconf2xml-cputune.config | 7 + tests/lxcconf2xmldata/lxcconf2xml-cputune.xml | 29 + tests/lxcconf2xmldata/lxcconf2xml-fstab.config | 37 + tests/lxcconf2xmldata/lxcconf2xml-idmap.config | 5 + tests/lxcconf2xmldata/lxcconf2xml-idmap.xml | 28 + .../lxcconf2xml-macvlannetwork.config | 13 + .../lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml | 26 + tests/lxcconf2xmldata/lxcconf2xml-memtune.config | 10 + tests/lxcconf2xmldata/lxcconf2xml-memtune.xml | 29 + .../lxcconf2xmldata/lxcconf2xml-nonenetwork.config | 4 + tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml | 21 + tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config | 3 + tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml | 24 + .../lxcconf2xmldata/lxcconf2xml-physnetwork.config | 6 + tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml | 26 + tests/lxcconf2xmldata/lxcconf2xml-simple.config | 41 + tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 41 + .../lxcconf2xmldata/lxcconf2xml-vlannetwork.config | 12 + tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml | 26 + tests/lxcconf2xmltest.c | 131 +++ 46 files changed, 1865 insertions(+), 85 deletions(-) create mode 100644 src/lxc/lxc_native.c create mode 100644 src/lxc/lxc_native.h create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cpusettune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cputune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cputune.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-fstab.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-memtune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-memtune.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-physnetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-simple.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-simple.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml create mode 100644 tests/lxcconf2xmltest.c
This series is now pushed, except patches 20/21, with the various OOM crash and memory leak bugs I discovered during testing. Thanks for this great new feature! Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 02/05/2014 03:09 PM, Cédric Bosdonnat wrote:
Here is an updated version of the patch set fixing comments from Daniel. It also adds 3 commits: * One adding conversion for the newly supported blkio throttle tune in lxc driver. * One actually using the state of the veth network device in lxc driver. * One adding the ability to give major:minor numbers instead of a path for blkio tune devices.
The last one is a way to address Daniel's comment on the /dev/block/... paths.
Cédric Bosdonnat (21): Improve virConf parse to handle LXC config format LXC driver: started implementing connectDomainXMLFromNative LXC from native: import rootfs LXC from native: migrate fstab and lxc.mount.entry LXC from native: implement no network conversion LXC from native: migrate veth network configuration LXC from native: convert phys network types to net hostdev devices LXC from native: convert lxc.tty to console devices LXC from native: convert macvlan network configuration LXC from native: convert lxc.id_map into <idmap> LXC from native: migrate memory tuning LXC from native: map lxc.cgroup.cpu.* LXC from native: map lxc.cgroup.cpuset.* LXC from native: add lxc.cgroup.blkio.* mapping LXC from native: map lxc.arch to /domain/os/type@arch LXC from native: map block filesystems LXC from native: map vlan network type LXC: added some doc on domxml-from-native with mention of limitations LXC from native: convert blkio throttle config lxc: honor link state=up for veth interfaces blkiotune: allow <node major='' minor=''/> in place of <path>
...
src/lxc/lxc_native.c | 952 +++++++++++++++++++++
Hi, The use of 'link' as a function parameter breaks the build on RHEL-6.4: cc1: warnings being treated as errors ../../src/lxc/lxc_native.c: In function 'lxcCreateNetDef': ../../src/lxc/lxc_native.c:337: error: declaration of 'link' shadows a global declaration [-Wshadow] /usr/include/unistd.h:809: error: shadowed declaration is here [-Wshadow] ../../src/lxc/lxc_native.c: In function 'lxcAddNetworkDefinition': ../../src/lxc/lxc_native.c:414: error: declaration of 'link' shadows a global declaration [-Wshadow] /usr/include/unistd.h:809: error: shadowed declaration is here [-Wshadow] make[3]: *** [lxc/libvirt_driver_lxc_impl_la-lxc_native.lo] Error 1 Jan
participants (5)
-
Cedric Bosdonnat
-
Cédric Bosdonnat
-
Daniel P. Berrange
-
John Ferlan
-
Ján Tomko