This patch adds feature for lxc containers to inherit namespaces. This is very similar to what lxc-tools or docker provides. Look for "man lxc-start" and you will find that you can pass command args as [ --share-[net|ipc|uts] name|pid ]. Or check out docker networking option in which you can give --net=container:NAME_or_ID as an option for sharing +namespace. >From this patch you can add extra libvirt option to share namespace in following way. <lxc:namespace> <lxc:sharenet type='netns' value='red'/> <lxc:shareipc type='pid' value='12345'/> <lxc:shareuts type='name' value='container1'/> </lxc:namespace> The netns option is specific to sharenet. It can be used to inherit from existing network namespace. --- docs/drvlxc.html.in | 21 +++++ docs/schemas/domaincommon.rng | 42 +++++++++ po/POTFILES.in | 1 + src/Makefile.am | 7 +- src/lxc/lxc_conf.c | 2 +- src/lxc/lxc_container.c | 71 +++++++++++++-- src/lxc/lxc_container.h | 2 + src/lxc/lxc_controller.c | 57 +++++++++++- src/lxc/lxc_domain.c | 149 ++++++++++++++++++++++++++++++++ src/lxc/lxc_domain.h | 26 ++++++ src/lxc/lxc_process.c | 157 ++++++++++++++++++++++++++++++++++ tests/lxcxml2xmldata/lxc-sharenet.xml | 33 +++++++ tests/lxcxml2xmltest.c | 1 + 13 files changed, 560 insertions(+), 9 deletions(-) create mode 100644 tests/lxcxml2xmldata/lxc-sharenet.xml diff --git a/docs/drvlxc.html.in b/docs/drvlxc.html.in index a094bd9..d6c57c4 100644 --- a/docs/drvlxc.html.in +++ b/docs/drvlxc.html.in @@ -590,6 +590,27 @@ Note that allowing capabilities that are normally dropped by default can serious affect the security of the container and the host. </p> +<h2><a name="share">Inherit namespaces</a></h2> + +<p> +Libvirt allows you to inherit the namespace from container/process just like lxc tools +or docker provides to share the network namespace. The following can be used to share +required namespaces. If we want to share only one then the other namespaces can be ignored. +The netns option is specific to sharenet. It can be used in cases we want to use existing network namespace +rather than creating new network namespace for the container. In this case privnet option will be +ignored. +</p> +<pre> +<domain type='lxc' xmlns:lxc='http://libvirt.org/schemas/domain/lxc/1.0'> +... +<lxc:namespace> + <lxc:sharenet type='netns' value='red'/> + <lxc:shareuts type='name' value='container1'/> + <lxc:shareipc type='pid' value='12345'/> +</lxc:namespace> +</domain> +</pre> + <h2><a name="usage">Container usage / management</a></h2> <p> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 043c975..fa026cd 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -68,6 +68,9 @@ <ref name='qemucmdline'/> </optional> <optional> + <ref name='lxcsharens'/> + </optional> + <optional> <ref name='keywrap'/> </optional> </interleave> @@ -5057,6 +5060,45 @@ </element> </define> + <!-- + Optional hypervisor extensions in their own namespace: + LXC + --> + <define name="lxcsharens"> + <element name="namespace" ns="http://libvirt.org/schemas/domain/lxc/1.0"> + <zeroOrMore> + <element name="sharenet"> + <attribute name="type"> + <choice> + <value>netns</value> + <value>name</value> + <value>pid</value> + </choice> + </attribute> + <attribute name='value'/> + </element> + <element name="shareipc"> + <attribute name="type"> + <choice> + <value>name</value> + <value>pid</value> + </choice> + </attribute> + <attribute name='value'/> + </element> + <element name="shareuts"> + <attribute name="type"> + <choice> + <value>name</value> + <value>pid</value> + </choice> + </attribute> + <attribute name='value'/> + </element> + </zeroOrMore> + </element> + </define> + <define name="metadata"> <element name="metadata"> <zeroOrMore> diff --git a/po/POTFILES.in b/po/POTFILES.in index 1e52e6a..46220f7 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -85,6 +85,7 @@ src/lxc/lxc_native.c src/lxc/lxc_container.c src/lxc/lxc_conf.c src/lxc/lxc_controller.c +src/lxc/lxc_domain.c src/lxc/lxc_driver.c src/lxc/lxc_process.c src/libxl/libxl_domain.c diff --git a/src/Makefile.am b/src/Makefile.am index c4d49a5..24d31e1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1320,7 +1320,12 @@ libvirt_driver_lxc_impl_la_CFLAGS = \ -I$(srcdir)/access \ -I$(srcdir)/conf \ $(AM_CFLAGS) -libvirt_driver_lxc_impl_la_LIBADD = $(CAPNG_LIBS) $(LIBNL_LIBS) $(FUSE_LIBS) +libvirt_driver_lxc_impl_la_LIBADD = \ + $(CAPNG_LIBS) \ + $(LIBNL_LIBS) \ + $(LIBXML_LIBS) \ + $(FUSE_LIBS) + if WITH_BLKID libvirt_driver_lxc_impl_la_CFLAGS += $(BLKID_CFLAGS) libvirt_driver_lxc_impl_la_LIBADD += $(BLKID_LIBS) diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c index b689b92..8ada531 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -213,7 +213,7 @@ lxcDomainXMLConfInit(void) { return virDomainXMLOptionNew(&virLXCDriverDomainDefParserConfig, &virLXCDriverPrivateDataCallbacks, - NULL); + &virLXCDriverDomainXMLNamespace); } diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 11e9514..8011ed0 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -27,6 +27,7 @@ #include <config.h> #include <fcntl.h> +#include <sched.h> #include <limits.h> #include <stdlib.h> #include <stdio.h> @@ -38,7 +39,6 @@ #include <mntent.h> #include <sys/reboot.h> #include <linux/reboot.h> - /* Yes, we want linux private one, for _syscall2() macro */ #include <linux/unistd.h> @@ -111,6 +111,7 @@ struct __lxc_child_argv { size_t nttyPaths; char **ttyPaths; int handshakefd; + int *nsInheritFDs; }; static int lxcContainerMountFSBlock(virDomainFSDefPtr fs, @@ -2144,6 +2145,35 @@ static int lxcContainerDropCapabilities(virDomainDefPtr def ATTRIBUTE_UNUSED, /** + * lxcAttach_ns: + * @ns_fd: array of namespaces to attach + */ +static int lxcAttachNS(int *ns_fd) +{ + size_t i; + if (ns_fd) + for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) { + if (ns_fd[i] < 0) + continue; + VIR_DEBUG("Setting into namespace\n"); + /* We get EINVAL if new NS is same as the current + * NS, or if the fd namespace doesn't match the + * type passed to setns()'s second param. Since we + * pass 0, we know the EINVAL is harmless + */ + if (setns(ns_fd[i], 0) < 0 && + errno != EINVAL) { + virReportSystemError(errno, _("failed to set namespace '%s'"), + virLXCDomainNamespaceTypeToString(i)); + return -1; + } + VIR_FORCE_CLOSE(ns_fd[i]); + } + return 0; +} + + +/** * lxcContainerChild: * @data: pointer to container arguments * @@ -2172,6 +2202,12 @@ static int lxcContainerChild(void *data) goto cleanup; } + if (lxcAttachNS(argv->nsInheritFDs) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, "%s", + _("failed to attach the namespace")); + return -1; + } + /* Wait for controller to finish setup tasks, including * things like move of network interfaces, uid/gid mapping */ @@ -2342,6 +2378,7 @@ int lxcContainerStart(virDomainDefPtr def, int *passFDs, int control, int handshakefd, + int *nsInheritFDs, size_t nttyPaths, char **ttyPaths) { @@ -2359,7 +2396,8 @@ int lxcContainerStart(virDomainDefPtr def, .monitor = control, .nttyPaths = nttyPaths, .ttyPaths = ttyPaths, - .handshakefd = handshakefd + .handshakefd = handshakefd, + .nsInheritFDs = nsInheritFDs, }; /* allocate a stack for the container */ @@ -2368,7 +2406,7 @@ int lxcContainerStart(virDomainDefPtr def, stacktop = stack + stacksize; - cflags = CLONE_NEWPID|CLONE_NEWNS|CLONE_NEWUTS|CLONE_NEWIPC|SIGCHLD; + cflags = CLONE_NEWPID|CLONE_NEWNS|SIGCHLD; if (userns_required(def)) { if (userns_supported()) { @@ -2381,10 +2419,31 @@ int lxcContainerStart(virDomainDefPtr def, return -1; } } + if (!nsInheritFDs || nsInheritFDs[VIR_LXC_DOMAIN_NAMESPACE_SHARENET] == -1) { + if (lxcNeedNetworkNamespace(def)) { + VIR_DEBUG("Enable network namespaces"); + cflags |= CLONE_NEWNET; + } + } else { + if (lxcNeedNetworkNamespace(def)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Config askes for inherit net namespace " + "as well as private network interfaces")); + return -1; + } + VIR_DEBUG("Inheriting a net namespace"); + } + + if (!nsInheritFDs || nsInheritFDs[VIR_LXC_DOMAIN_NAMESPACE_SHAREIPC] == -1) { + cflags |= CLONE_NEWIPC; + } else { + VIR_DEBUG("Inheriting an IPC namespace"); + } - if (lxcNeedNetworkNamespace(def)) { - VIR_DEBUG("Enable network namespaces"); - cflags |= CLONE_NEWNET; + if (!nsInheritFDs || nsInheritFDs[VIR_LXC_DOMAIN_NAMESPACE_SHAREUTS] == -1) { + cflags |= CLONE_NEWUTS; + } else { + VIR_DEBUG("Inheriting a UTS namespace"); } VIR_DEBUG("Cloning container init process"); diff --git a/src/lxc/lxc_container.h b/src/lxc/lxc_container.h index 67292ab..33eaab4 100644 --- a/src/lxc/lxc_container.h +++ b/src/lxc/lxc_container.h @@ -25,6 +25,7 @@ # define LXC_CONTAINER_H # include "lxc_conf.h" +# include "lxc_domain.h" # include "security/security_manager.h" enum { @@ -60,6 +61,7 @@ int lxcContainerStart(virDomainDefPtr def, int *passFDs, int control, int handshakefd, + int *nsInheritFDs, size_t nttyPaths, char **ttyPaths); diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 48a3597..a94e819 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -119,6 +119,8 @@ struct _virLXCController { size_t npassFDs; int *passFDs; + int *nsFDs; + size_t nconsoles; virLXCControllerConsolePtr consoles; char *devptmx; @@ -287,6 +289,7 @@ static void virLXCControllerFree(virLXCControllerPtr ctrl) VIR_FREE(ctrl->nbdpids); + VIR_FREE(ctrl->nsFDs); virCgroupFree(&ctrl->cgroup); /* This must always be the last thing to be closed */ @@ -2391,6 +2394,7 @@ virLXCControllerRun(virLXCControllerPtr ctrl) ctrl->passFDs, control[1], containerhandshake[1], + ctrl->nsFDs, ctrl->nconsoles, containerTTYPaths)) < 0) goto cleanup; @@ -2400,6 +2404,10 @@ virLXCControllerRun(virLXCControllerPtr ctrl) for (i = 0; i < ctrl->npassFDs; i++) VIR_FORCE_CLOSE(ctrl->passFDs[i]); + if (ctrl->nsFDs) + for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) + VIR_FORCE_CLOSE(ctrl->nsFDs[i]); + if (virLXCControllerSetupCgroupLimits(ctrl) < 0) goto cleanup; @@ -2468,6 +2476,7 @@ int main(int argc, char *argv[]) const char *name = NULL; size_t nveths = 0; char **veths = NULL; + int ns_fd[VIR_LXC_DOMAIN_NAMESPACE_LAST]; int handshakeFd = -1; bool bg = false; const struct option options[] = { @@ -2478,6 +2487,9 @@ int main(int argc, char *argv[]) { "passfd", 1, NULL, 'p' }, { "handshakefd", 1, NULL, 's' }, { "security", 1, NULL, 'S' }, + { "share-net", 1, NULL, 'N' }, + { "share-ipc", 1, NULL, 'I' }, + { "share-uts", 1, NULL, 'U' }, { "help", 0, NULL, 'h' }, { 0, 0, 0, 0 }, }; @@ -2489,6 +2501,9 @@ int main(int argc, char *argv[]) size_t i; const char *securityDriver = "none"; + for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) + ns_fd[i] = -1; + if (setlocale(LC_ALL, "") == NULL || bindtextdomain(PACKAGE, LOCALEDIR) == NULL || textdomain(PACKAGE) == NULL || @@ -2504,7 +2519,7 @@ int main(int argc, char *argv[]) while (1) { int c; - c = getopt_long(argc, argv, "dn:v:p:m:c:s:h:S:", + c = getopt_long(argc, argv, "dn:v:p:m:c:s:h:S:N:I:U:", options, NULL); if (c == -1) @@ -2552,6 +2567,30 @@ int main(int argc, char *argv[]) } break; + case 'N': + if (virStrToLong_i(optarg, NULL, 10, &ns_fd[VIR_LXC_DOMAIN_NAMESPACE_SHARENET]) < 0) { + fprintf(stderr, "malformed --share-net argument '%s'", + optarg); + goto cleanup; + } + break; + + case 'I': + if (virStrToLong_i(optarg, NULL, 10, &ns_fd[VIR_LXC_DOMAIN_NAMESPACE_SHAREIPC]) < 0) { + fprintf(stderr, "malformed --share-ipc argument '%s'", + optarg); + goto cleanup; + } + break; + + case 'U': + if (virStrToLong_i(optarg, NULL, 10, &ns_fd[VIR_LXC_DOMAIN_NAMESPACE_SHAREUTS]) < 0) { + fprintf(stderr, "malformed --share-uts argument '%s'", + optarg); + goto cleanup; + } + break; + case 'S': securityDriver = optarg; break; @@ -2569,6 +2608,9 @@ int main(int argc, char *argv[]) fprintf(stderr, " -v VETH, --veth VETH\n"); fprintf(stderr, " -s FD, --handshakefd FD\n"); fprintf(stderr, " -S NAME, --security NAME\n"); + fprintf(stderr, " -N FD, --share-net FD\n"); + fprintf(stderr, " -I FD, --share-ipc FD\n"); + fprintf(stderr, " -U FD, --share-uts FD\n"); fprintf(stderr, " -h, --help\n"); fprintf(stderr, "\n"); goto cleanup; @@ -2621,6 +2663,19 @@ int main(int argc, char *argv[]) ctrl->passFDs = passFDs; ctrl->npassFDs = npassFDs; + for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) { + if (ns_fd[i] != -1) { + if (!ctrl->nsFDs) {/*allocate only once */ + size_t j = 0; + if (VIR_ALLOC_N(ctrl->nsFDs, VIR_LXC_DOMAIN_NAMESPACE_LAST) < 0) + goto cleanup; + for (j = 0; j < VIR_LXC_DOMAIN_NAMESPACE_LAST; j++) + ctrl->nsFDs[j] = -1; + } + ctrl->nsFDs[i] = ns_fd[i]; + } + } + for (i = 0; i < nttyFDs; i++) { if (virLXCControllerAddConsole(ctrl, ttyFDs[i]) < 0) goto cleanup; diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c index 2f377d8..e3da9f0 100644 --- a/src/lxc/lxc_domain.c +++ b/src/lxc/lxc_domain.c @@ -26,8 +26,13 @@ #include "viralloc.h" #include "virlog.h" #include "virerror.h" +#include <libxml/xpathInternals.h> +#include "virstring.h" +#include "virutil.h" +#include "virfile.h" #define VIR_FROM_THIS VIR_FROM_LXC +#define LXC_NAMESPACE_HREF "http://libvirt.org/schemas/domain/lxc/1.0" VIR_LOG_INIT("lxc.lxc_domain"); @@ -41,6 +46,150 @@ static void *virLXCDomainObjPrivateAlloc(void) return priv; } +VIR_ENUM_IMPL(virLXCDomainNamespace, + VIR_LXC_DOMAIN_NAMESPACE_LAST, + "sharenet", + "shareipc", + "shareuts") + +VIR_ENUM_IMPL(virLXCDomainNamespaceSource, + VIR_LXC_DOMAIN_NAMESPACE_SOURCE_LAST, + "none", + "name", + "pid", + "netns") + +static void +lxcDomainDefNamespaceFree(void *nsdata) +{ + size_t i; + lxcDomainDefPtr lxcDef = nsdata; + for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) + VIR_FREE(lxcDef->ns_val[i]); + VIR_FREE(nsdata); +} + +static int +lxcDomainDefNamespaceParse(xmlDocPtr xml ATTRIBUTE_UNUSED, + xmlNodePtr root ATTRIBUTE_UNUSED, + xmlXPathContextPtr ctxt, + void **data) +{ + lxcDomainDefPtr lxcDef = NULL; + xmlNodePtr *nodes = NULL; + bool uses_lxc_ns = false; + xmlNodePtr node; + int feature; + int n; + char *tmp = NULL; + size_t i; + + if (xmlXPathRegisterNs(ctxt, BAD_CAST "lxc", BAD_CAST LXC_NAMESPACE_HREF) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to register xml namespace '%s'"), + LXC_NAMESPACE_HREF); + return -1; + } + + if (VIR_ALLOC(lxcDef) < 0) + return -1; + + node = ctxt->node; + if ((n = virXPathNodeSet("./lxc:namespace/*", ctxt, &nodes)) < 0) + goto error; + uses_lxc_ns |= n > 0; + + for (i = 0; i < n; i++) { + if ((feature = virLXCDomainNamespaceTypeFromString( + (const char *) nodes[i]->name)) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unsupported Namespace feature: %s"), + nodes[i]->name); + goto error; + } + + ctxt->node = nodes[i]; + + if (!(tmp = virXMLPropString(nodes[i], "type"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("No lxc environment type specified")); + goto error; + } + if ((lxcDef->ns_source[feature] = + virLXCDomainNamespaceSourceTypeFromString(tmp)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown LXC namespace source '%s'"), + tmp); + VIR_FREE(tmp); + goto error; + } + VIR_FREE(tmp); + + if (!(lxcDef->ns_val[feature] = + virXMLPropString(nodes[i], "value"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("No lxc environment type specified")); + goto error; + } + } + VIR_FREE(nodes); + ctxt->node = node; + if (uses_lxc_ns) + *data = lxcDef; + else + VIR_FREE(lxcDef); + return 0; + error: + VIR_FREE(nodes); + lxcDomainDefNamespaceFree(lxcDef); + return -1; +} + + +static int +lxcDomainDefNamespaceFormatXML(virBufferPtr buf, + void *nsdata) +{ + lxcDomainDefPtr lxcDef = nsdata; + size_t i; + + if (!lxcDef) + return 0; + + virBufferAddLit(buf, "<lxc:namespace>\n"); + virBufferAdjustIndent(buf, 2); + + for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) { + if (lxcDef->ns_source[i] == VIR_LXC_DOMAIN_NAMESPACE_SOURCE_NONE) + continue; + + virBufferAsprintf(buf, "<lxc:%s type='%s' value='%s'/>\n", + virLXCDomainNamespaceTypeToString(i), + virLXCDomainNamespaceSourceTypeToString( + lxcDef->ns_source[i]), + lxcDef->ns_val[i]); + } + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</lxc:namespace>\n"); + return 0; +} + +static const char * +lxcDomainDefNamespaceHref(void) +{ + return "xmlns:lxc='" LXC_NAMESPACE_HREF "'"; +} + + +virDomainXMLNamespace virLXCDriverDomainXMLNamespace = { + .parse = lxcDomainDefNamespaceParse, + .free = lxcDomainDefNamespaceFree, + .format = lxcDomainDefNamespaceFormatXML, + .href = lxcDomainDefNamespaceHref, +}; + + static void virLXCDomainObjPrivateFree(void *data) { virLXCDomainObjPrivatePtr priv = data; diff --git a/src/lxc/lxc_domain.h b/src/lxc/lxc_domain.h index 751aece..2119c78 100644 --- a/src/lxc/lxc_domain.h +++ b/src/lxc/lxc_domain.h @@ -27,6 +27,31 @@ # include "lxc_conf.h" # include "lxc_monitor.h" +typedef enum { + VIR_LXC_DOMAIN_NAMESPACE_SHARENET = 0, + VIR_LXC_DOMAIN_NAMESPACE_SHAREIPC, + VIR_LXC_DOMAIN_NAMESPACE_SHAREUTS, + VIR_LXC_DOMAIN_NAMESPACE_LAST, +} virLXCDomainNamespace; + +typedef enum { + VIR_LXC_DOMAIN_NAMESPACE_SOURCE_NONE, + VIR_LXC_DOMAIN_NAMESPACE_SOURCE_NAME, + VIR_LXC_DOMAIN_NAMESPACE_SOURCE_PID, + VIR_LXC_DOMAIN_NAMESPACE_SOURCE_NETNS, + + VIR_LXC_DOMAIN_NAMESPACE_SOURCE_LAST, +} virLXCDomainNamespaceSource; + +VIR_ENUM_DECL(virLXCDomainNamespace) +VIR_ENUM_DECL(virLXCDomainNamespaceSource) + +typedef struct _lxcDomainDef lxcDomainDef; +typedef lxcDomainDef *lxcDomainDefPtr; +struct _lxcDomainDef { + int ns_source[VIR_LXC_DOMAIN_NAMESPACE_LAST]; /* virLXCDomainNamespaceSource */ + char *ns_val[VIR_LXC_DOMAIN_NAMESPACE_LAST]; +}; typedef struct _virLXCDomainObjPrivate virLXCDomainObjPrivate; typedef virLXCDomainObjPrivate *virLXCDomainObjPrivatePtr; @@ -41,6 +66,7 @@ struct _virLXCDomainObjPrivate { virCgroupPtr cgroup; }; +extern virDomainXMLNamespace virLXCDriverDomainXMLNamespace; extern virDomainXMLPrivateDataCallbacks virLXCDriverPrivateDataCallbacks; extern virDomainDefParserConfig virLXCDriverDomainDefParserConfig; diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index e99b039..ade0ed7 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -359,6 +359,143 @@ char *virLXCProcessSetupInterfaceDirect(virConnectPtr conn, return ret; } +static const char *nsInfoLocal[VIR_LXC_DOMAIN_NAMESPACE_LAST] = { + [VIR_LXC_DOMAIN_NAMESPACE_SHARENET] = "net", + [VIR_LXC_DOMAIN_NAMESPACE_SHAREIPC] = "ipc", + [VIR_LXC_DOMAIN_NAMESPACE_SHAREUTS] = "uts", +}; + +static int virLXCProcessSetupNamespaceName(virConnectPtr conn, int ns_type, const char *name) +{ + virLXCDriverPtr driver = conn->privateData; + int fd = -1; + virDomainObjPtr vm; + virLXCDomainObjPrivatePtr priv; + char *path; + + vm = virDomainObjListFindByName(driver->domains, name); + if (!vm) { + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching name '%s'"), name); + return -1; + } + + priv = vm->privateData; + if (!priv->initpid) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Init pid is not yet available")); + goto cleanup; + } + + if (virAsprintf(&path, "/proc/%lld/ns/%s", + (long long int)priv->initpid, + nsInfoLocal[ns_type]) < 0) + goto cleanup; + + if ((fd = open(path, O_RDONLY)) < 0) { + virReportSystemError(errno, + _("failed to open ns %s"), + virLXCDomainNamespaceTypeToString(ns_type)); + goto cleanup; + } + + cleanup: + VIR_FREE(path); + virObjectUnlock(vm); + virObjectUnref(vm); + return fd; +} + + +static int virLXCProcessSetupNamespacePID(int ns_type, const char *name) +{ + int fd; + char *path; + + if (virAsprintf(&path, "/proc/%s/ns/%s", + name, + nsInfoLocal[ns_type]) < 0) + return -1; + fd = open(path, O_RDONLY); + VIR_FREE(path); + if (fd < 0) { + virReportSystemError(errno, + _("failed to open ns %s"), + virLXCDomainNamespaceTypeToString(ns_type)); + return -1; + } + return fd; +} + + +static int virLXCProcessSetupNamespaceNet(int ns_type, const char *name) +{ + char *path; + int fd; + if (ns_type != VIR_LXC_DOMAIN_NAMESPACE_SHARENET) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("'netns' namespace source can only be " + "used with sharenet")); + return -1; + } + + if (virAsprintf(&path, "/var/run/netns/%s", name) < 0) + return -1; + fd = open(path, O_RDONLY); + VIR_FREE(path); + if (fd < 0) { + virReportSystemError(errno, + _("failed to open netns %s"), name); + return -1; + } + return fd; +} + + +/** + * virLXCProcessSetupNamespaces: + * @conn: pointer to connection + * @def: pointer to virtual machines namespaceData + * @nsFDs: out parameter to store the namespace FD + * + * Opens the specified namespace that needs to be shared and + * will moved into the container namespace later after clone has been called. + * + * Returns 0 on success or -1 in case of error + */ +static int virLXCProcessSetupNamespaces(virConnectPtr conn, + lxcDomainDefPtr lxcDef, + int *nsFDs) +{ + size_t i; + + for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) + nsFDs[i] = -1; + /*If there are no namespace to be opened just return success*/ + if (lxcDef == NULL) + return 0; + + for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) { + switch (lxcDef->ns_source[i]) { + case VIR_LXC_DOMAIN_NAMESPACE_SOURCE_NONE: + continue; + case VIR_LXC_DOMAIN_NAMESPACE_SOURCE_NAME: + if ((nsFDs[i] = virLXCProcessSetupNamespaceName(conn, i, lxcDef->ns_val[i])) < 0) + return -1; + break; + case VIR_LXC_DOMAIN_NAMESPACE_SOURCE_PID: + if ((nsFDs[i] = virLXCProcessSetupNamespacePID(i, lxcDef->ns_val[i])) < 0) + return -1; + break; + case VIR_LXC_DOMAIN_NAMESPACE_SOURCE_NETNS: + if ((nsFDs[i] = virLXCProcessSetupNamespaceNet(i, lxcDef->ns_val[i])) < 0) + return -1; + break; + } + } + + return 0; +} /** * virLXCProcessSetupInterfaces: @@ -764,6 +901,7 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver, char **veths, int *ttyFDs, size_t nttyFDs, + int *nsInheritFDs, int *files, size_t nfiles, int handshakefd, @@ -825,6 +963,19 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver, virCommandPassFD(cmd, files[i], 0); } + for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) { + if (nsInheritFDs[i] > 0) { + char *tmp = NULL; + if (virAsprintf(&tmp, "--share-%s", + nsInfoLocal[i]) < 0) + goto cleanup; + virCommandAddArg(cmd, tmp); + virCommandAddArgFormat(cmd, "%d", nsInheritFDs[i]); + virCommandPassFD(cmd, nsInheritFDs[i], 0); + VIR_FREE(tmp); + } + } + virCommandAddArgPair(cmd, "--security", virSecurityManagerGetModel(driver->securityManager)); @@ -1032,6 +1183,7 @@ int virLXCProcessStart(virConnectPtr conn, off_t pos = -1; char ebuf[1024]; char *timestamp; + int nsInheritFDs[VIR_LXC_DOMAIN_NAMESPACE_LAST]; virCommandPtr cmd = NULL; virLXCDomainObjPrivatePtr priv = vm->privateData; virCapsPtr caps = NULL; @@ -1204,6 +1356,10 @@ int virLXCProcessStart(virConnectPtr conn, if (virLXCProcessSetupInterfaces(conn, vm->def, &nveths, &veths) < 0) goto cleanup; + VIR_DEBUG("Setting up namespaces if any"); + if (virLXCProcessSetupNamespaces(conn, vm->def->namespaceData, nsInheritFDs) < 0) + goto cleanup; + VIR_DEBUG("Preparing to launch"); if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR|S_IWUSR)) < 0) { @@ -1223,6 +1379,7 @@ int virLXCProcessStart(virConnectPtr conn, vm, nveths, veths, ttyFDs, nttyFDs, + nsInheritFDs, files, nfiles, handshakefds[1], &logfd, diff --git a/tests/lxcxml2xmldata/lxc-sharenet.xml b/tests/lxcxml2xmldata/lxc-sharenet.xml new file mode 100644 index 0000000..a2b8d1b --- /dev/null +++ b/tests/lxcxml2xmldata/lxc-sharenet.xml @@ -0,0 +1,33 @@ +<domain type='lxc' xmlns:lxc='http://libvirt.org/schemas/domain/lxc/1.0'> + <name>jessie</name> + <uuid>e21987a5-e98e-9c99-0e35-803e4d9ad1fe</uuid> + <memory unit='KiB'>1048576</memory> + <currentMemory unit='KiB'>1048576</currentMemory> + <vcpu placement='static'>1</vcpu> + <resource> + <partition>/machine</partition> + </resource> + <os> + <type arch='x86_64'>exe</type> + <init>/sbin/init</init> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>restart</on_crash> + <devices> + <emulator>/usr/libexec/libvirt_lxc</emulator> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/mach/jessie'/> + <target dir='/'/> + </filesystem> + <console type='pty'> + <target type='lxc' port='0'/> + </console> + </devices> + <lxc:namespace> + <lxc:sharenet type='netns' value='red'/> + <lxc:shareipc type='pid' value='12345'/> + <lxc:shareuts type='name' value='container1'/> + </lxc:namespace> +</domain> diff --git a/tests/lxcxml2xmltest.c b/tests/lxcxml2xmltest.c index 3e00347..8d824b9 100644 --- a/tests/lxcxml2xmltest.c +++ b/tests/lxcxml2xmltest.c @@ -133,6 +133,7 @@ mymain(void) DO_TEST("filesystem-root"); DO_TEST("idmap"); DO_TEST("capabilities"); + DO_TEST("sharenet"); virObjectUnref(caps); virObjectUnref(xmlopt); -- 1.9.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list