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