[libvirt] [PATCH] Inherit namespace feature 2

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.w --- docs/drvlxc.html.in | 21 +++++ docs/schemas/domaincommon.rng | 42 +++++++++ src/Makefile.am | 2 +- src/lxc/lxc_conf.c | 2 +- src/lxc/lxc_conf.h | 15 ++++ src/lxc/lxc_container.c | 145 ++++++++++++++++++++++++++++-- src/lxc/lxc_container.h | 1 + src/lxc/lxc_controller.c | 42 ++++++++- src/lxc/lxc_domain.c | 164 +++++++++++++++++++++++++++++++++- src/lxc/lxc_domain.h | 1 + src/lxc/lxc_process.c | 111 +++++++++++++++++++++++ tests/lxcxml2xmldata/lxc-sharenet.xml | 33 +++++++ tests/lxcxml2xmltest.c | 1 + 13 files changed, 570 insertions(+), 10 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 1120003..803b327 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> @@ -5012,6 +5015,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/src/Makefile.am b/src/Makefile.am index c4d49a5..b2ceda3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1320,7 +1320,7 @@ 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) libvirt-lxc.la $(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_conf.h b/src/lxc/lxc_conf.h index 8340b1f..72b1d44 100644 --- a/src/lxc/lxc_conf.h +++ b/src/lxc/lxc_conf.h @@ -67,6 +67,21 @@ struct _virLXCDriverConfig { bool securityRequireConfined; }; + +typedef enum { + VIR_DOMAIN_NAMESPACE_SHARENET = 0, + VIR_DOMAIN_NAMESPACE_SHAREIPC, + VIR_DOMAIN_NAMESPACE_SHAREUTS, + VIR_DOMAIN_NAMESPACE_LAST, +} virDomainNamespace; + +typedef struct _lxcDomainDef lxcDomainDef; +typedef lxcDomainDef *lxcDomainDefPtr; +struct _lxcDomainDef { + char *ns_type[VIR_DOMAIN_NAMESPACE_LAST]; + char *ns_val[VIR_DOMAIN_NAMESPACE_LAST]; +}; + struct _virLXCDriver { virMutex lock; diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 11e9514..103e9bc 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> @@ -2321,6 +2321,96 @@ virArch lxcContainerGetAlt32bitArch(virArch arch) return VIR_ARCH_NONE; } +struct lxcNSInfo { + const char *proc_name; + int clone_flag; +}nsInfoLocal[VIR_DOMAIN_NAMESPACE_LAST] = { + [VIR_DOMAIN_NAMESPACE_SHARENET] = {"net", CLONE_NEWNET}, + [VIR_DOMAIN_NAMESPACE_SHAREIPC] = {"ipc", CLONE_NEWIPC}, + [VIR_DOMAIN_NAMESPACE_SHAREUTS] = {"uts", CLONE_NEWUTS} +}; + + +static void lxcClose_ns(int ns_fd[VIR_DOMAIN_NAMESPACE_LAST]) +{ + int i; + for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) { + if (ns_fd[i] > -1) { + if (VIR_CLOSE(ns_fd[i]) < 0) + virReportSystemError(errno, "%s", _("failed to close file")); + ns_fd[i] = -1; + } + } +} + + +/** + * lxcPreserve_ns: + * @ns_fd: array to store current namespace + * @clone_flags: namespaces that need to be preserved + */ +static int lxcPreserve_ns(int ns_fd[VIR_DOMAIN_NAMESPACE_LAST], int clone_flags) +{ + int i, saved_errno; + char *path = NULL; + + for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) + ns_fd[i] = -1; + + if (!virFileExists("/proc/self/ns")) { + virReportSystemError(errno, "%s", + _("Kernel does not support attach; preserve_ns ignored")); + return -1; + } + + for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) { + if ((clone_flags & nsInfoLocal[i].clone_flag) == 0) + continue; + if (virAsprintf(&path, "/proc/self/ns/%s", + nsInfoLocal[i].proc_name) < 0) + goto error; + ns_fd[i] = open(path, O_RDONLY | O_CLOEXEC); + if (ns_fd[i] < 0) + goto error; + VIR_FREE(path); + } + return 0; + error: + saved_errno = errno; + lxcClose_ns(ns_fd); + errno = saved_errno; + virReportSystemError(errno, _("lxcPreserve_ns failed for '%s'"), path); + VIR_FREE(path); + return -1; +} + +/** + * lxcAttach_ns: + * @ns_fd: array of namespaces to attach + */ +static int lxcAttach_ns(const int ns_fd[VIR_DOMAIN_NAMESPACE_LAST]) +{ + int i; + + for (i = 0; i < VIR_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'") + , nsInfoLocal[i].proc_name); + return -1; + } + } + return 0; +} + /** * lxcContainerStart: @@ -2342,13 +2432,17 @@ int lxcContainerStart(virDomainDefPtr def, int *passFDs, int control, int handshakefd, + int nsInheritFDs[VIR_DOMAIN_NAMESPACE_LAST], size_t nttyPaths, char **ttyPaths) { pid_t pid; - int cflags; + int cflags, i; int stacksize = getpagesize() * 4; char *stack, *stacktop; + int savedNsFDs[VIR_DOMAIN_NAMESPACE_LAST]; + int preserve_mask = 0; + lxcDomainDefPtr lxcDef; lxc_child_argv_t args = { .config = def, .securityDriver = securityDriver, @@ -2368,7 +2462,12 @@ int lxcContainerStart(virDomainDefPtr def, stacktop = stack + stacksize; - cflags = CLONE_NEWPID|CLONE_NEWNS|CLONE_NEWUTS|CLONE_NEWIPC|SIGCHLD; + lxcDef = def->namespaceData; + for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) + if (lxcDef && lxcDef->ns_type[i]) + preserve_mask |= nsInfoLocal[i].clone_flag; + + cflags = CLONE_NEWPID|CLONE_NEWNS|SIGCHLD; if (userns_required(def)) { if (userns_supported()) { @@ -2381,10 +2480,37 @@ int lxcContainerStart(virDomainDefPtr def, return -1; } } + if (!lxcDef || !lxcDef->ns_type[VIR_DOMAIN_NAMESPACE_SHARENET]) { + if (lxcNeedNetworkNamespace(def)) { + VIR_DEBUG("Enable network namespaces"); + cflags |= CLONE_NEWNET; + } + } else { + VIR_DEBUG("Inheriting a net namespace"); + } - if (lxcNeedNetworkNamespace(def)) { - VIR_DEBUG("Enable network namespaces"); - cflags |= CLONE_NEWNET; + if (!lxcDef || !lxcDef->ns_type[VIR_DOMAIN_NAMESPACE_SHAREIPC]) { + cflags |= CLONE_NEWIPC; + } else { + VIR_DEBUG("Inheriting an IPC namespace"); + } + + if (!lxcDef || !lxcDef->ns_type[VIR_DOMAIN_NAMESPACE_SHAREUTS]) { + cflags |= CLONE_NEWUTS; + } else { + VIR_DEBUG("Inheriting a UTS namespace"); + } + + if (lxcDef && lxcPreserve_ns(savedNsFDs, preserve_mask) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, "%s", + _("failed to preserve the namespace")); + return -1; + } + + if (lxcDef && lxcAttach_ns(nsInheritFDs) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, "%s", + _("failed to attach the namespace")); + return -1; } VIR_DEBUG("Cloning container init process"); @@ -2397,7 +2523,14 @@ int lxcContainerStart(virDomainDefPtr def, _("Failed to run clone container")); return -1; } + if (lxcDef && lxcAttach_ns(savedNsFDs)) { + virReportError(VIR_ERR_SYSTEM_ERROR, "%s", + _("failed to restore saved namespaces")); + } + /* clean up */ + if (lxcDef) + lxcClose_ns(nsInheritFDs); return pid; } diff --git a/src/lxc/lxc_container.h b/src/lxc/lxc_container.h index 67292ab..f585a35 100644 --- a/src/lxc/lxc_container.h +++ b/src/lxc/lxc_container.h @@ -60,6 +60,7 @@ int lxcContainerStart(virDomainDefPtr def, int *passFDs, int control, int handshakefd, + int nsInheritFDs[VIR_DOMAIN_NAMESPACE_LAST], size_t nttyPaths, char **ttyPaths); diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 110a556..1cbe0b3 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[VIR_DOMAIN_NAMESPACE_LAST]; + size_t nconsoles; virLXCControllerConsolePtr consoles; char *devptmx; @@ -2391,6 +2393,7 @@ virLXCControllerRun(virLXCControllerPtr ctrl) ctrl->passFDs, control[1], containerhandshake[1], + ctrl->nsFDs, ctrl->nconsoles, containerTTYPaths)) < 0) goto cleanup; @@ -2468,6 +2471,7 @@ int main(int argc, char *argv[]) const char *name = NULL; size_t nveths = 0; char **veths = NULL; + int ns_fd[VIR_DOMAIN_NAMESPACE_LAST]; int handshakeFd = -1; bool bg = false; const struct option options[] = { @@ -2478,6 +2482,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 +2496,9 @@ int main(int argc, char *argv[]) size_t i; const char *securityDriver = "none"; + for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) + ns_fd[i] = -1; + if (setlocale(LC_ALL, "") == NULL || bindtextdomain(PACKAGE, LOCALEDIR) == NULL || textdomain(PACKAGE) == NULL || @@ -2504,7 +2514,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 +2562,30 @@ int main(int argc, char *argv[]) } break; + case 'N': + if (virStrToLong_i(optarg, NULL, 10, &ns_fd[VIR_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_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_DOMAIN_NAMESPACE_SHAREUTS]) < 0) { + fprintf(stderr, "malformed --share-uts argument '%s'", + optarg); + goto cleanup; + } + break; + case 'S': securityDriver = optarg; break; @@ -2569,6 +2603,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 +2658,9 @@ int main(int argc, char *argv[]) ctrl->passFDs = passFDs; ctrl->npassFDs = npassFDs; + for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) + 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 70606f3..5e63969 100644 --- a/src/lxc/lxc_domain.c +++ b/src/lxc/lxc_domain.c @@ -26,8 +26,14 @@ #include "viralloc.h" #include "virlog.h" #include "virerror.h" +#include <fcntl.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 +47,163 @@ static void *virLXCDomainObjPrivateAlloc(void) return priv; } +VIR_ENUM_DECL(virDomainNamespace) +VIR_ENUM_IMPL(virDomainNamespace, VIR_DOMAIN_NAMESPACE_LAST, + N_("sharenet"), + N_("shareipc"), + N_("shareuts")) + +static void +lxcDomainDefNamespaceFree(void *nsdata) +{ + int j; + lxcDomainDefPtr lxcDef = nsdata; + for (j = 0; j < VIR_DOMAIN_NAMESPACE_LAST; j++) { + VIR_FREE(lxcDef->ns_type[j]); + VIR_FREE(lxcDef->ns_val[j]); + } + 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; + /* Init ns_herit_fd for namespaces */ + for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) { + lxcDef->ns_type[i] = NULL; + lxcDef->ns_val[i] = NULL; + } + + node = ctxt->node; + if ((n = virXPathNodeSet("./lxc:namespace/*", ctxt, &nodes)) < 0) + goto error; + uses_lxc_ns |= n > 0; + + for (i = 0; i < n; i++) { + feature = + virDomainNamespaceTypeFromString((const char *) nodes[i]->name); + if (feature < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unsupported Namespace feature: %s"), + nodes[i]->name); + goto error; + } + + ctxt->node = nodes[i]; + + switch ((virDomainNamespace) feature) { + case VIR_DOMAIN_NAMESPACE_SHARENET: + case VIR_DOMAIN_NAMESPACE_SHAREIPC: + case VIR_DOMAIN_NAMESPACE_SHAREUTS: + { + tmp = virXMLPropString(nodes[i], "type"); + if (tmp == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("No lxc environment type specified")); + goto error; + } + /* save the tmp so that its needed while writing to xml */ + lxcDef->ns_type[feature] = tmp; + tmp = virXMLPropString(nodes[i], "value"); + if (tmp == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("No lxc environment type specified")); + goto error; + } + lxcDef->ns_val[feature] = tmp; + } + break; + case VIR_DOMAIN_NAMESPACE_LAST: + break; + } + } + 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 j; + + if (!lxcDef) + return 0; + + virBufferAddLit(buf, "<lxc:namespace>\n"); + virBufferAdjustIndent(buf, 2); + + for (j = 0; j < VIR_DOMAIN_NAMESPACE_LAST; j++) { + switch ((virDomainNamespace) j) { + case VIR_DOMAIN_NAMESPACE_SHAREIPC: + case VIR_DOMAIN_NAMESPACE_SHAREUTS: + case VIR_DOMAIN_NAMESPACE_SHARENET: + { + if (lxcDef->ns_type[j]) { + virBufferAsprintf(buf, "<lxc:%s type='%s' value='%s'/>\n", + virDomainNamespaceTypeToString(j), + lxcDef->ns_type[j], + lxcDef->ns_val[j]); + } + } + break; + case VIR_DOMAIN_NAMESPACE_LAST: + break; + } + } + + 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; @@ -77,7 +240,6 @@ virLXCDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, } else { priv->initpid = thepid; } - return 0; } diff --git a/src/lxc/lxc_domain.h b/src/lxc/lxc_domain.h index 751aece..25df999 100644 --- a/src/lxc/lxc_domain.h +++ b/src/lxc/lxc_domain.h @@ -41,6 +41,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..ead7f67 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -359,6 +359,97 @@ char *virLXCProcessSetupInterfaceDirect(virConnectPtr conn, return ret; } +static const char *nsInfoLocal[] = { "net", "ipc", "uts" }; +/** + * 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[VIR_DOMAIN_NAMESPACE_LAST]) +{ + int i, n, rc = 0; + virDomainPtr dom = NULL; + pid_t pid; + int nfdlist; + int *fdlist; + char *path = NULL; + char *eptr; + + for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) + nsFDs[i] = -1; + /*If there are no namespace to be opened just return success*/ + if (lxcDef == NULL) return 0; + + if (STREQ_NULLABLE("netns", lxcDef->ns_type[VIR_DOMAIN_NAMESPACE_SHARENET])) { + if (virAsprintf(&path, "/var/run/netns/%s", lxcDef->ns_val[VIR_DOMAIN_NAMESPACE_SHARENET]) < 0) + return -1; + nsFDs[VIR_DOMAIN_NAMESPACE_SHARENET] = open(path, O_RDONLY); + VIR_FREE(path); + if (nsFDs[VIR_DOMAIN_NAMESPACE_SHARENET] < 0) { + virReportSystemError(errno, + _("failed to open netns %s"), lxcDef->ns_val[VIR_DOMAIN_NAMESPACE_SHARENET]); + return -1; + } + } + for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) { + /* If not yet intialized by above: netns*/ + if (lxcDef->ns_type[i] && nsFDs[i] == -1) { + pid = strtol(lxcDef->ns_val[i], &eptr, 10); + if (*eptr != '\0' || pid < 1) { + /* check if the domain is running, then set the namespaces + * to that container + */ + const char *ns[] = { "user", "ipc", "uts", "net", "pid", "mnt" }; + dom = virDomainLookupByName(conn, lxcDef->ns_val[i]); + if (!dom) { + virReportError(virGetLastError()->code, + _("Unable to lookup peer container %s"), + lxcDef->ns_val[i]); + rc = -1; + goto cleanup; + } + if ((nfdlist = virDomainLxcOpenNamespace(dom, &fdlist, 0)) < 0) { + virReportError(virGetLastError()->code, + _("Unable to open %s"), lxcDef->ns_val[i]); + rc = -1; + goto cleanup; + } + for (n = 0; n < ARRAY_CARDINALITY(ns); n++) { + if (STREQ(ns[n], nsInfoLocal[i])) { + nsFDs[i] = fdlist[n]; + } else { + if (VIR_CLOSE(fdlist[n]) < 0) + VIR_ERROR(_("failed to close fd. ignoring..")); + } + } + if (nfdlist > 0) + VIR_FREE(fdlist); + } else { + if (virAsprintf(&path, "/proc/%d/ns/%s", pid, nsInfoLocal[i]) < 0) + return -1; + nsFDs[i] = open(path, O_RDONLY); + VIR_FREE(path); + if (nsFDs[i] < 0) { + virReportSystemError(errno, + _("failed to open ns %s"), lxcDef->ns_val[i]); + return -1; + } + } + } + } + cleanup: + if (dom) + virDomainFree(dom); + return rc; +} /** * virLXCProcessSetupInterfaces: @@ -764,6 +855,7 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver, char **veths, int *ttyFDs, size_t nttyFDs, + int nsInheritFDs[VIR_DOMAIN_NAMESPACE_LAST], int *files, size_t nfiles, int handshakefd, @@ -825,6 +917,19 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver, virCommandPassFD(cmd, files[i], 0); } + for (i = 0; i < VIR_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 +1137,7 @@ int virLXCProcessStart(virConnectPtr conn, off_t pos = -1; char ebuf[1024]; char *timestamp; + int nsInheritFDs[VIR_DOMAIN_NAMESPACE_LAST]; virCommandPtr cmd = NULL; virLXCDomainObjPrivatePtr priv = vm->privateData; virCapsPtr caps = NULL; @@ -1204,6 +1310,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 +1333,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

On Sun, Aug 09, 2015 at 12:09:32AM +0530, ik.nitk wrote:
diff --git a/src/Makefile.am b/src/Makefile.am index c4d49a5..b2ceda3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1320,7 +1320,7 @@ 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) libvirt-lxc.la $(FUSE_LIBS)
I understand why you needed libvirt-lxc.la in your v1 of this patch, but with the code moved into lxc_process.c this is no longer needed. Only LIBXML_LIBS needs adding.
diff --git a/src/lxc/lxc_conf.h b/src/lxc/lxc_conf.h index 8340b1f..72b1d44 100644 --- a/src/lxc/lxc_conf.h +++ b/src/lxc/lxc_conf.h @@ -67,6 +67,21 @@ struct _virLXCDriverConfig { bool securityRequireConfined; };
+ +typedef enum { + VIR_DOMAIN_NAMESPACE_SHARENET = 0, + VIR_DOMAIN_NAMESPACE_SHAREIPC, + VIR_DOMAIN_NAMESPACE_SHAREUTS, + VIR_DOMAIN_NAMESPACE_LAST, +} virDomainNamespace;
We shold really have LXC in the name, eg virLXCDomainNamespace and VIR_LXC_DOMAIN_NAMESPACE_* constants.
+ +typedef struct _lxcDomainDef lxcDomainDef; +typedef lxcDomainDef *lxcDomainDefPtr; +struct _lxcDomainDef { + char *ns_type[VIR_DOMAIN_NAMESPACE_LAST];
There are only 3 value types, so we should just have an enum for them too, instead of comparing strings everywhere
+ char *ns_val[VIR_DOMAIN_NAMESPACE_LAST]; +}; +
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 11e9514..103e9bc 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c
/** * lxcContainerStart: @@ -2342,13 +2432,17 @@ int lxcContainerStart(virDomainDefPtr def, int *passFDs, int control, int handshakefd, + int nsInheritFDs[VIR_DOMAIN_NAMESPACE_LAST], size_t nttyPaths, char **ttyPaths) { pid_t pid; - int cflags; + int cflags, i; int stacksize = getpagesize() * 4; char *stack, *stacktop; + int savedNsFDs[VIR_DOMAIN_NAMESPACE_LAST]; + int preserve_mask = 0; + lxcDomainDefPtr lxcDef; lxc_child_argv_t args = { .config = def, .securityDriver = securityDriver, @@ -2368,7 +2462,12 @@ int lxcContainerStart(virDomainDefPtr def,
stacktop = stack + stacksize;
- cflags = CLONE_NEWPID|CLONE_NEWNS|CLONE_NEWUTS|CLONE_NEWIPC|SIGCHLD; + lxcDef = def->namespaceData; + for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) + if (lxcDef && lxcDef->ns_type[i]) + preserve_mask |= nsInfoLocal[i].clone_flag; + + cflags = CLONE_NEWPID|CLONE_NEWNS|SIGCHLD;
if (userns_required(def)) { if (userns_supported()) { @@ -2381,10 +2480,37 @@ int lxcContainerStart(virDomainDefPtr def, return -1; } } + if (!lxcDef || !lxcDef->ns_type[VIR_DOMAIN_NAMESPACE_SHARENET]) {
We don't actually need lxcDef here at all - we should just look at the nsInheritFDs list, eg if (nsInheritFDs[VIR_DOMAIN_NAMESPACE_SHARENET] != -1) { ...
+ if (lxcNeedNetworkNamespace(def)) { + VIR_DEBUG("Enable network namespaces"); + cflags |= CLONE_NEWNET; + } + } else { + VIR_DEBUG("Inheriting a net namespace");
We should report an error in this branch if lxcNeedNetworkNamespace returns true, as that indicates a contradictory XML config.
+ }
- if (lxcNeedNetworkNamespace(def)) { - VIR_DEBUG("Enable network namespaces"); - cflags |= CLONE_NEWNET; + if (!lxcDef || !lxcDef->ns_type[VIR_DOMAIN_NAMESPACE_SHAREIPC]) { + cflags |= CLONE_NEWIPC; + } else { + VIR_DEBUG("Inheriting an IPC namespace"); + } + + if (!lxcDef || !lxcDef->ns_type[VIR_DOMAIN_NAMESPACE_SHAREUTS]) { + cflags |= CLONE_NEWUTS; + } else { + VIR_DEBUG("Inheriting a UTS namespace"); + } + + if (lxcDef && lxcPreserve_ns(savedNsFDs, preserve_mask) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, "%s", + _("failed to preserve the namespace")); + return -1; + } + + if (lxcDef && lxcAttach_ns(nsInheritFDs) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, "%s", + _("failed to attach the namespace")); + return -1; }
VIR_DEBUG("Cloning container init process"); @@ -2397,7 +2523,14 @@ int lxcContainerStart(virDomainDefPtr def, _("Failed to run clone container")); return -1; } + if (lxcDef && lxcAttach_ns(savedNsFDs)) { + virReportError(VIR_ERR_SYSTEM_ERROR, "%s", + _("failed to restore saved namespaces")); + }
You are in libvirt_lxc controller context here, so I see why you have to preserve & re-attach the original namespace. If we push the lxcAttach_ns call down into the lxcContainreChild method, then we're in the container context so can skip the preserve & re-attach part entirely
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 110a556..1cbe0b3 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c
diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c index 70606f3..5e63969 100644 --- a/src/lxc/lxc_domain.c +++ b/src/lxc/lxc_domain.c @@ -26,8 +26,14 @@ #include "viralloc.h" #include "virlog.h" #include "virerror.h" +#include <fcntl.h> +#include <libxml/xpathInternals.h> +#include "virstring.h" +#include "virutil.h" +#include "virfile.h"
+ for (i = 0; i < n; i++) { + feature = + virDomainNamespaceTypeFromString((const char *) nodes[i]->name); + if (feature < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unsupported Namespace feature: %s"), + nodes[i]->name); + goto error; + } + + ctxt->node = nodes[i]; + + switch ((virDomainNamespace) feature) { + case VIR_DOMAIN_NAMESPACE_SHARENET: + case VIR_DOMAIN_NAMESPACE_SHAREIPC: + case VIR_DOMAIN_NAMESPACE_SHAREUTS: + { + tmp = virXMLPropString(nodes[i], "type"); + if (tmp == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("No lxc environment type specified")); + goto error; + } + /* save the tmp so that its needed while writing to xml */ + lxcDef->ns_type[feature] = tmp; + tmp = virXMLPropString(nodes[i], "value"); + if (tmp == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("No lxc environment type specified")); + goto error; + } + lxcDef->ns_val[feature] = tmp; + } + break; + case VIR_DOMAIN_NAMESPACE_LAST:
The switch() is pretty pointless, because this case is impossible to reach, so you only ever execute the first case. Thus switch() can be removed entirely. Also, this is where we should be converting ns_type to an enum
+static int +lxcDomainDefNamespaceFormatXML(virBufferPtr buf, + void *nsdata) +{ + lxcDomainDefPtr lxcDef = nsdata; + size_t j; + + if (!lxcDef) + return 0; + + virBufferAddLit(buf, "<lxc:namespace>\n"); + virBufferAdjustIndent(buf, 2); + + for (j = 0; j < VIR_DOMAIN_NAMESPACE_LAST; j++) { + switch ((virDomainNamespace) j) { + case VIR_DOMAIN_NAMESPACE_SHAREIPC: + case VIR_DOMAIN_NAMESPACE_SHAREUTS: + case VIR_DOMAIN_NAMESPACE_SHARENET: + { + if (lxcDef->ns_type[j]) { + virBufferAsprintf(buf, "<lxc:%s type='%s' value='%s'/>\n", + virDomainNamespaceTypeToString(j), + lxcDef->ns_type[j], + lxcDef->ns_val[j]); + } + } + break; + case VIR_DOMAIN_NAMESPACE_LAST: + break; + }
Again the switch is not required as the _LAST case is impossible due to the terminating condition of your for() loop/.
+ } + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</lxc:namespace>\n"); + return 0; +}
diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index e99b039..ead7f67 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -359,6 +359,97 @@ char *virLXCProcessSetupInterfaceDirect(virConnectPtr conn, return ret; }
+static const char *nsInfoLocal[] = { "net", "ipc", "uts" }; +/** + * 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[VIR_DOMAIN_NAMESPACE_LAST]) +{ + int i, n, rc = 0; + virDomainPtr dom = NULL; + pid_t pid; + int nfdlist; + int *fdlist; + char *path = NULL; + char *eptr; + + for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) + nsFDs[i] = -1; + /*If there are no namespace to be opened just return success*/ + if (lxcDef == NULL) return 0; + + if (STREQ_NULLABLE("netns", lxcDef->ns_type[VIR_DOMAIN_NAMESPACE_SHARENET])) { + if (virAsprintf(&path, "/var/run/netns/%s", lxcDef->ns_val[VIR_DOMAIN_NAMESPACE_SHARENET]) < 0) + return -1; + nsFDs[VIR_DOMAIN_NAMESPACE_SHARENET] = open(path, O_RDONLY); + VIR_FREE(path); + if (nsFDs[VIR_DOMAIN_NAMESPACE_SHARENET] < 0) { + virReportSystemError(errno, + _("failed to open netns %s"), lxcDef->ns_val[VIR_DOMAIN_NAMESPACE_SHARENET]); + return -1; + } + } + for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) { + /* If not yet intialized by above: netns*/ + if (lxcDef->ns_type[i] && nsFDs[i] == -1) { + pid = strtol(lxcDef->ns_val[i], &eptr, 10); + if (*eptr != '\0' || pid < 1) {
Here you are converting the ns_val to an int and if it fails you're doing the name based code path. It would be better if you actually checked the ns_type field since we have it available.
+ /* check if the domain is running, then set the namespaces + * to that container + */ + const char *ns[] = { "user", "ipc", "uts", "net", "pid", "mnt" }; + dom = virDomainLookupByName(conn, lxcDef->ns_val[i]); + if (!dom) { + virReportError(virGetLastError()->code, + _("Unable to lookup peer container %s"), + lxcDef->ns_val[i]); + rc = -1; + goto cleanup; + } + if ((nfdlist = virDomainLxcOpenNamespace(dom, &fdlist, 0)) < 0) { + virReportError(virGetLastError()->code, + _("Unable to open %s"), lxcDef->ns_val[i]); + rc = -1; + goto cleanup; + } + for (n = 0; n < ARRAY_CARDINALITY(ns); n++) { + if (STREQ(ns[n], nsInfoLocal[i])) { + nsFDs[i] = fdlist[n]; + } else { + if (VIR_CLOSE(fdlist[n]) < 0) + VIR_ERROR(_("failed to close fd. ignoring..")); + } + } + if (nfdlist > 0) + VIR_FREE(fdlist); + } else { + if (virAsprintf(&path, "/proc/%d/ns/%s", pid, nsInfoLocal[i]) < 0) + return -1; + nsFDs[i] = open(path, O_RDONLY); + VIR_FREE(path); + if (nsFDs[i] < 0) { + virReportSystemError(errno, + _("failed to open ns %s"), lxcDef->ns_val[i]); + return -1; + } + }
In general I think these would be better broken into separate methods There are also misc errors reported from 'make syntax-check' such as using 'int i' instead of 'size_t i' Broadly speaking this patch is conceptually good. I've got a variety of cleanups suggested, and rather than waste your time trying to fix it up, I've just done them myself. I'll send a v3 patch which I'd like you to test to ensure I didn't break anything you did. The differences are po/POTFILES.in | 1 + src/Makefile.am | 6 +- src/lxc/lxc_conf.h | 15 ---- src/lxc/lxc_container.c | 172 +++++++++++++------------------------------ src/lxc/lxc_container.h | 3 +- src/lxc/lxc_controller.c | 17 +++-- src/lxc/lxc_domain.c | 109 ++++++++++++--------------- src/lxc/lxc_domain.h | 25 +++++++ src/lxc/lxc_process.c | 186 ++++++++++++++++++++++++++++------------------- 9 files changed, 252 insertions(+), 282 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index c58a7c1..dcabcc8 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 b2ceda3..fde11ff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1320,7 +1320,11 @@ libvirt_driver_lxc_impl_la_CFLAGS = \ -I$(srcdir)/access \ -I$(srcdir)/conf \ $(AM_CFLAGS) -libvirt_driver_lxc_impl_la_LIBADD = $(CAPNG_LIBS) $(LIBNL_LIBS) $(LIBXML_LIBS) libvirt-lxc.la $(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.h b/src/lxc/lxc_conf.h index 72b1d44..8340b1f 100644 --- a/src/lxc/lxc_conf.h +++ b/src/lxc/lxc_conf.h @@ -67,21 +67,6 @@ struct _virLXCDriverConfig { bool securityRequireConfined; }; - -typedef enum { - VIR_DOMAIN_NAMESPACE_SHARENET = 0, - VIR_DOMAIN_NAMESPACE_SHAREIPC, - VIR_DOMAIN_NAMESPACE_SHAREUTS, - VIR_DOMAIN_NAMESPACE_LAST, -} virDomainNamespace; - -typedef struct _lxcDomainDef lxcDomainDef; -typedef lxcDomainDef *lxcDomainDefPtr; -struct _lxcDomainDef { - char *ns_type[VIR_DOMAIN_NAMESPACE_LAST]; - char *ns_val[VIR_DOMAIN_NAMESPACE_LAST]; -}; - struct _virLXCDriver { virMutex lock; diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 103e9bc..d52f57e 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -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; + + 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 */ @@ -2321,96 +2357,6 @@ virArch lxcContainerGetAlt32bitArch(virArch arch) return VIR_ARCH_NONE; } -struct lxcNSInfo { - const char *proc_name; - int clone_flag; -}nsInfoLocal[VIR_DOMAIN_NAMESPACE_LAST] = { - [VIR_DOMAIN_NAMESPACE_SHARENET] = {"net", CLONE_NEWNET}, - [VIR_DOMAIN_NAMESPACE_SHAREIPC] = {"ipc", CLONE_NEWIPC}, - [VIR_DOMAIN_NAMESPACE_SHAREUTS] = {"uts", CLONE_NEWUTS} -}; - - -static void lxcClose_ns(int ns_fd[VIR_DOMAIN_NAMESPACE_LAST]) -{ - int i; - for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) { - if (ns_fd[i] > -1) { - if (VIR_CLOSE(ns_fd[i]) < 0) - virReportSystemError(errno, "%s", _("failed to close file")); - ns_fd[i] = -1; - } - } -} - - -/** - * lxcPreserve_ns: - * @ns_fd: array to store current namespace - * @clone_flags: namespaces that need to be preserved - */ -static int lxcPreserve_ns(int ns_fd[VIR_DOMAIN_NAMESPACE_LAST], int clone_flags) -{ - int i, saved_errno; - char *path = NULL; - - for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) - ns_fd[i] = -1; - - if (!virFileExists("/proc/self/ns")) { - virReportSystemError(errno, "%s", - _("Kernel does not support attach; preserve_ns ignored")); - return -1; - } - - for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) { - if ((clone_flags & nsInfoLocal[i].clone_flag) == 0) - continue; - if (virAsprintf(&path, "/proc/self/ns/%s", - nsInfoLocal[i].proc_name) < 0) - goto error; - ns_fd[i] = open(path, O_RDONLY | O_CLOEXEC); - if (ns_fd[i] < 0) - goto error; - VIR_FREE(path); - } - return 0; - error: - saved_errno = errno; - lxcClose_ns(ns_fd); - errno = saved_errno; - virReportSystemError(errno, _("lxcPreserve_ns failed for '%s'"), path); - VIR_FREE(path); - return -1; -} - -/** - * lxcAttach_ns: - * @ns_fd: array of namespaces to attach - */ -static int lxcAttach_ns(const int ns_fd[VIR_DOMAIN_NAMESPACE_LAST]) -{ - int i; - - for (i = 0; i < VIR_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'") - , nsInfoLocal[i].proc_name); - return -1; - } - } - return 0; -} - /** * lxcContainerStart: @@ -2432,17 +2378,14 @@ int lxcContainerStart(virDomainDefPtr def, int *passFDs, int control, int handshakefd, - int nsInheritFDs[VIR_DOMAIN_NAMESPACE_LAST], + int *nsInheritFDs, size_t nttyPaths, char **ttyPaths) { pid_t pid; - int cflags, i; + int cflags; int stacksize = getpagesize() * 4; char *stack, *stacktop; - int savedNsFDs[VIR_DOMAIN_NAMESPACE_LAST]; - int preserve_mask = 0; - lxcDomainDefPtr lxcDef; lxc_child_argv_t args = { .config = def, .securityDriver = securityDriver, @@ -2453,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 */ @@ -2462,11 +2406,6 @@ int lxcContainerStart(virDomainDefPtr def, stacktop = stack + stacksize; - lxcDef = def->namespaceData; - for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) - if (lxcDef && lxcDef->ns_type[i]) - preserve_mask |= nsInfoLocal[i].clone_flag; - cflags = CLONE_NEWPID|CLONE_NEWNS|SIGCHLD; if (userns_required(def)) { @@ -2480,39 +2419,33 @@ int lxcContainerStart(virDomainDefPtr def, return -1; } } - if (!lxcDef || !lxcDef->ns_type[VIR_DOMAIN_NAMESPACE_SHARENET]) { + if (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 (!lxcDef || !lxcDef->ns_type[VIR_DOMAIN_NAMESPACE_SHAREIPC]) { + if (nsInheritFDs[VIR_LXC_DOMAIN_NAMESPACE_SHAREIPC] == -1) { cflags |= CLONE_NEWIPC; } else { VIR_DEBUG("Inheriting an IPC namespace"); } - if (!lxcDef || !lxcDef->ns_type[VIR_DOMAIN_NAMESPACE_SHAREUTS]) { + if (nsInheritFDs[VIR_LXC_DOMAIN_NAMESPACE_SHAREUTS] == -1) { cflags |= CLONE_NEWUTS; } else { VIR_DEBUG("Inheriting a UTS namespace"); } - if (lxcDef && lxcPreserve_ns(savedNsFDs, preserve_mask) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, "%s", - _("failed to preserve the namespace")); - return -1; - } - - if (lxcDef && lxcAttach_ns(nsInheritFDs) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, "%s", - _("failed to attach the namespace")); - return -1; - } - VIR_DEBUG("Cloning container init process"); pid = clone(lxcContainerChild, stacktop, cflags, &args); VIR_FREE(stack); @@ -2523,14 +2456,7 @@ int lxcContainerStart(virDomainDefPtr def, _("Failed to run clone container")); return -1; } - if (lxcDef && lxcAttach_ns(savedNsFDs)) { - virReportError(VIR_ERR_SYSTEM_ERROR, "%s", - _("failed to restore saved namespaces")); - } - /* clean up */ - if (lxcDef) - lxcClose_ns(nsInheritFDs); return pid; } diff --git a/src/lxc/lxc_container.h b/src/lxc/lxc_container.h index f585a35..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,7 +61,7 @@ int lxcContainerStart(virDomainDefPtr def, int *passFDs, int control, int handshakefd, - int nsInheritFDs[VIR_DOMAIN_NAMESPACE_LAST], + int *nsInheritFDs, size_t nttyPaths, char **ttyPaths); diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 3755ca0..19190dd 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -119,7 +119,7 @@ struct _virLXCController { size_t npassFDs; int *passFDs; - int nsFDs[VIR_DOMAIN_NAMESPACE_LAST]; + int *nsFDs; size_t nconsoles; virLXCControllerConsolePtr consoles; @@ -2403,6 +2403,9 @@ virLXCControllerRun(virLXCControllerPtr ctrl) for (i = 0; i < ctrl->npassFDs; i++) VIR_FORCE_CLOSE(ctrl->passFDs[i]); + for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) + VIR_FORCE_CLOSE(ctrl->nsFDs[i]); + if (virLXCControllerSetupCgroupLimits(ctrl) < 0) goto cleanup; @@ -2471,7 +2474,7 @@ int main(int argc, char *argv[]) const char *name = NULL; size_t nveths = 0; char **veths = NULL; - int ns_fd[VIR_DOMAIN_NAMESPACE_LAST]; + int ns_fd[VIR_LXC_DOMAIN_NAMESPACE_LAST]; int handshakeFd = -1; bool bg = false; const struct option options[] = { @@ -2496,7 +2499,7 @@ int main(int argc, char *argv[]) size_t i; const char *securityDriver = "none"; - for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) + for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) ns_fd[i] = -1; if (setlocale(LC_ALL, "") == NULL || @@ -2563,7 +2566,7 @@ int main(int argc, char *argv[]) break; case 'N': - if (virStrToLong_i(optarg, NULL, 10, &ns_fd[VIR_DOMAIN_NAMESPACE_SHARENET]) < 0) { + if (virStrToLong_i(optarg, NULL, 10, &ns_fd[VIR_LXC_DOMAIN_NAMESPACE_SHARENET]) < 0) { fprintf(stderr, "malformed --share-net argument '%s'", optarg); goto cleanup; @@ -2571,7 +2574,7 @@ int main(int argc, char *argv[]) break; case 'I': - if (virStrToLong_i(optarg, NULL, 10, &ns_fd[VIR_DOMAIN_NAMESPACE_SHAREIPC]) < 0) { + if (virStrToLong_i(optarg, NULL, 10, &ns_fd[VIR_LXC_DOMAIN_NAMESPACE_SHAREIPC]) < 0) { fprintf(stderr, "malformed --share-ipc argument '%s'", optarg); goto cleanup; @@ -2579,7 +2582,7 @@ int main(int argc, char *argv[]) break; case 'U': - if (virStrToLong_i(optarg, NULL, 10, &ns_fd[VIR_DOMAIN_NAMESPACE_SHAREUTS]) < 0) { + if (virStrToLong_i(optarg, NULL, 10, &ns_fd[VIR_LXC_DOMAIN_NAMESPACE_SHAREUTS]) < 0) { fprintf(stderr, "malformed --share-uts argument '%s'", optarg); goto cleanup; @@ -2658,7 +2661,7 @@ int main(int argc, char *argv[]) ctrl->passFDs = passFDs; ctrl->npassFDs = npassFDs; - for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) + for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) ctrl->nsFDs[i] = ns_fd[i]; for (i = 0; i < nttyFDs; i++) { diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c index ca9da7b..e3da9f0 100644 --- a/src/lxc/lxc_domain.c +++ b/src/lxc/lxc_domain.c @@ -26,7 +26,6 @@ #include "viralloc.h" #include "virlog.h" #include "virerror.h" -#include <fcntl.h> #include <libxml/xpathInternals.h> #include "virstring.h" #include "virutil.h" @@ -47,21 +46,26 @@ static void *virLXCDomainObjPrivateAlloc(void) return priv; } -VIR_ENUM_DECL(virDomainNamespace) -VIR_ENUM_IMPL(virDomainNamespace, VIR_DOMAIN_NAMESPACE_LAST, - N_("sharenet"), - N_("shareipc"), - N_("shareuts")) +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) { - int j; + size_t i; lxcDomainDefPtr lxcDef = nsdata; - for (j = 0; j < VIR_DOMAIN_NAMESPACE_LAST; j++) { - VIR_FREE(lxcDef->ns_type[j]); - VIR_FREE(lxcDef->ns_val[j]); - } + for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) + VIR_FREE(lxcDef->ns_val[i]); VIR_FREE(nsdata); } @@ -89,11 +93,6 @@ lxcDomainDefNamespaceParse(xmlDocPtr xml ATTRIBUTE_UNUSED, if (VIR_ALLOC(lxcDef) < 0) return -1; - /* Init ns_herit_fd for namespaces */ - for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) { - lxcDef->ns_type[i] = NULL; - lxcDef->ns_val[i] = NULL; - } node = ctxt->node; if ((n = virXPathNodeSet("./lxc:namespace/*", ctxt, &nodes)) < 0) @@ -101,9 +100,8 @@ lxcDomainDefNamespaceParse(xmlDocPtr xml ATTRIBUTE_UNUSED, uses_lxc_ns |= n > 0; for (i = 0; i < n; i++) { - feature = - virDomainNamespaceTypeFromString((const char *) nodes[i]->name); - if (feature < 0) { + if ((feature = virLXCDomainNamespaceTypeFromString( + (const char *) nodes[i]->name)) < 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("unsupported Namespace feature: %s"), nodes[i]->name); @@ -112,30 +110,26 @@ lxcDomainDefNamespaceParse(xmlDocPtr xml ATTRIBUTE_UNUSED, ctxt->node = nodes[i]; - switch ((virDomainNamespace) feature) { - case VIR_DOMAIN_NAMESPACE_SHARENET: - case VIR_DOMAIN_NAMESPACE_SHAREIPC: - case VIR_DOMAIN_NAMESPACE_SHAREUTS: - { - tmp = virXMLPropString(nodes[i], "type"); - if (tmp == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("No lxc environment type specified")); - goto error; - } - /* save the tmp so that its needed while writing to xml */ - lxcDef->ns_type[feature] = tmp; - tmp = virXMLPropString(nodes[i], "value"); - if (tmp == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("No lxc environment type specified")); - goto error; - } - lxcDef->ns_val[feature] = tmp; - } - break; - case VIR_DOMAIN_NAMESPACE_LAST: - break; + 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); @@ -157,7 +151,7 @@ lxcDomainDefNamespaceFormatXML(virBufferPtr buf, void *nsdata) { lxcDomainDefPtr lxcDef = nsdata; - size_t j; + size_t i; if (!lxcDef) return 0; @@ -165,23 +159,15 @@ lxcDomainDefNamespaceFormatXML(virBufferPtr buf, virBufferAddLit(buf, "<lxc:namespace>\n"); virBufferAdjustIndent(buf, 2); - for (j = 0; j < VIR_DOMAIN_NAMESPACE_LAST; j++) { - switch ((virDomainNamespace) j) { - case VIR_DOMAIN_NAMESPACE_SHAREIPC: - case VIR_DOMAIN_NAMESPACE_SHAREUTS: - case VIR_DOMAIN_NAMESPACE_SHARENET: - { - if (lxcDef->ns_type[j]) { - virBufferAsprintf(buf, "<lxc:%s type='%s' value='%s'/>\n", - virDomainNamespaceTypeToString(j), - lxcDef->ns_type[j], - lxcDef->ns_val[j]); - } - } - break; - case VIR_DOMAIN_NAMESPACE_LAST: - break; - } + 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); @@ -241,6 +227,7 @@ virLXCDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, } else { priv->initpid = thepid; } + return 0; } diff --git a/src/lxc/lxc_domain.h b/src/lxc/lxc_domain.h index 25df999..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; diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index ead7f67..9699377 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -359,7 +359,91 @@ char *virLXCProcessSetupInterfaceDirect(virConnectPtr conn, return ret; } -static const char *nsInfoLocal[] = { "net", "ipc", "uts" }; +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; + char *path; + + vm = virDomainObjListFindByName(driver->domains, name); + if (!vm) { + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching name '%s'"), name); + return -1; + } + + if (virAsprintf(&path, "/proc/%lld/ns/%s", + (long long int)vm->pid, + 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 @@ -373,82 +457,36 @@ static const char *nsInfoLocal[] = { "net", "ipc", "uts" }; */ static int virLXCProcessSetupNamespaces(virConnectPtr conn, lxcDomainDefPtr lxcDef, - int nsFDs[VIR_DOMAIN_NAMESPACE_LAST]) + int *nsFDs) { - int i, n, rc = 0; - virDomainPtr dom = NULL; - pid_t pid; - int nfdlist; - int *fdlist; - char *path = NULL; - char *eptr; + size_t i; - for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; 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; - - if (STREQ_NULLABLE("netns", lxcDef->ns_type[VIR_DOMAIN_NAMESPACE_SHARENET])) { - if (virAsprintf(&path, "/var/run/netns/%s", lxcDef->ns_val[VIR_DOMAIN_NAMESPACE_SHARENET]) < 0) - return -1; - nsFDs[VIR_DOMAIN_NAMESPACE_SHARENET] = open(path, O_RDONLY); - VIR_FREE(path); - if (nsFDs[VIR_DOMAIN_NAMESPACE_SHARENET] < 0) { - virReportSystemError(errno, - _("failed to open netns %s"), lxcDef->ns_val[VIR_DOMAIN_NAMESPACE_SHARENET]); - return -1; - } - } - for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) { - /* If not yet intialized by above: netns*/ - if (lxcDef->ns_type[i] && nsFDs[i] == -1) { - pid = strtol(lxcDef->ns_val[i], &eptr, 10); - if (*eptr != '\0' || pid < 1) { - /* check if the domain is running, then set the namespaces - * to that container - */ - const char *ns[] = { "user", "ipc", "uts", "net", "pid", "mnt" }; - dom = virDomainLookupByName(conn, lxcDef->ns_val[i]); - if (!dom) { - virReportError(virGetLastError()->code, - _("Unable to lookup peer container %s"), - lxcDef->ns_val[i]); - rc = -1; - goto cleanup; - } - if ((nfdlist = virDomainLxcOpenNamespace(dom, &fdlist, 0)) < 0) { - virReportError(virGetLastError()->code, - _("Unable to open %s"), lxcDef->ns_val[i]); - rc = -1; - goto cleanup; - } - for (n = 0; n < ARRAY_CARDINALITY(ns); n++) { - if (STREQ(ns[n], nsInfoLocal[i])) { - nsFDs[i] = fdlist[n]; - } else { - if (VIR_CLOSE(fdlist[n]) < 0) - VIR_ERROR(_("failed to close fd. ignoring..")); - } - } - if (nfdlist > 0) - VIR_FREE(fdlist); - } else { - if (virAsprintf(&path, "/proc/%d/ns/%s", pid, nsInfoLocal[i]) < 0) - return -1; - nsFDs[i] = open(path, O_RDONLY); - VIR_FREE(path); - if (nsFDs[i] < 0) { - virReportSystemError(errno, - _("failed to open ns %s"), lxcDef->ns_val[i]); - return -1; - } - } + 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; } } - cleanup: - if (dom) - virDomainFree(dom); - return rc; + + return 0; } /** @@ -855,7 +893,7 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver, char **veths, int *ttyFDs, size_t nttyFDs, - int nsInheritFDs[VIR_DOMAIN_NAMESPACE_LAST], + int *nsInheritFDs, int *files, size_t nfiles, int handshakefd, @@ -917,7 +955,7 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver, virCommandPassFD(cmd, files[i], 0); } - for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) { + for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) { if (nsInheritFDs[i] > 0) { char *tmp = NULL; if (virAsprintf(&tmp, "--share-%s", @@ -1137,7 +1175,7 @@ int virLXCProcessStart(virConnectPtr conn, off_t pos = -1; char ebuf[1024]; char *timestamp; - int nsInheritFDs[VIR_DOMAIN_NAMESPACE_LAST]; + int nsInheritFDs[VIR_LXC_DOMAIN_NAMESPACE_LAST]; virCommandPtr cmd = NULL; virLXCDomainObjPrivatePtr priv = vm->privateData; virCapsPtr caps = NULL; -- 2.4.3 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 :|
participants (2)
-
Daniel P. Berrange
-
ik.nitk