lxc: Inherit namespace feature

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.

Co-authored: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
ik.nitk 2015-08-20 19:16:17 +05:30 committed by Daniel P. Berrange
parent f674dc6794
commit c27553b6e2
13 changed files with 560 additions and 9 deletions

View File

@ -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. affect the security of the container and the host.
</p> </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>
&lt;domain type='lxc' xmlns:lxc='http://libvirt.org/schemas/domain/lxc/1.0'&gt;
...
&lt;lxc:namespace&gt;
&lt;lxc:sharenet type='netns' value='red'/&gt;
&lt;lxc:shareuts type='name' value='container1'/&gt;
&lt;lxc:shareipc type='pid' value='12345'/&gt;
&lt;/lxc:namespace&gt;
&lt;/domain&gt;
</pre>
<h2><a name="usage">Container usage / management</a></h2> <h2><a name="usage">Container usage / management</a></h2>
<p> <p>

View File

@ -67,6 +67,9 @@
<optional> <optional>
<ref name='qemucmdline'/> <ref name='qemucmdline'/>
</optional> </optional>
<optional>
<ref name='lxcsharens'/>
</optional>
<optional> <optional>
<ref name='keywrap'/> <ref name='keywrap'/>
</optional> </optional>
@ -5057,6 +5060,45 @@
</element> </element>
</define> </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"> <define name="metadata">
<element name="metadata"> <element name="metadata">
<zeroOrMore> <zeroOrMore>

View File

@ -85,6 +85,7 @@ src/lxc/lxc_native.c
src/lxc/lxc_container.c src/lxc/lxc_container.c
src/lxc/lxc_conf.c src/lxc/lxc_conf.c
src/lxc/lxc_controller.c src/lxc/lxc_controller.c
src/lxc/lxc_domain.c
src/lxc/lxc_driver.c src/lxc/lxc_driver.c
src/lxc/lxc_process.c src/lxc/lxc_process.c
src/libxl/libxl_domain.c src/libxl/libxl_domain.c

View File

@ -1320,7 +1320,12 @@ libvirt_driver_lxc_impl_la_CFLAGS = \
-I$(srcdir)/access \ -I$(srcdir)/access \
-I$(srcdir)/conf \ -I$(srcdir)/conf \
$(AM_CFLAGS) $(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 if WITH_BLKID
libvirt_driver_lxc_impl_la_CFLAGS += $(BLKID_CFLAGS) libvirt_driver_lxc_impl_la_CFLAGS += $(BLKID_CFLAGS)
libvirt_driver_lxc_impl_la_LIBADD += $(BLKID_LIBS) libvirt_driver_lxc_impl_la_LIBADD += $(BLKID_LIBS)

View File

@ -213,7 +213,7 @@ lxcDomainXMLConfInit(void)
{ {
return virDomainXMLOptionNew(&virLXCDriverDomainDefParserConfig, return virDomainXMLOptionNew(&virLXCDriverDomainDefParserConfig,
&virLXCDriverPrivateDataCallbacks, &virLXCDriverPrivateDataCallbacks,
NULL); &virLXCDriverDomainXMLNamespace);
} }

View File

@ -27,6 +27,7 @@
#include <config.h> #include <config.h>
#include <fcntl.h> #include <fcntl.h>
#include <sched.h>
#include <limits.h> #include <limits.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -38,7 +39,6 @@
#include <mntent.h> #include <mntent.h>
#include <sys/reboot.h> #include <sys/reboot.h>
#include <linux/reboot.h> #include <linux/reboot.h>
/* Yes, we want linux private one, for _syscall2() macro */ /* Yes, we want linux private one, for _syscall2() macro */
#include <linux/unistd.h> #include <linux/unistd.h>
@ -111,6 +111,7 @@ struct __lxc_child_argv {
size_t nttyPaths; size_t nttyPaths;
char **ttyPaths; char **ttyPaths;
int handshakefd; int handshakefd;
int *nsInheritFDs;
}; };
static int lxcContainerMountFSBlock(virDomainFSDefPtr fs, static int lxcContainerMountFSBlock(virDomainFSDefPtr fs,
@ -2143,6 +2144,35 @@ static int lxcContainerDropCapabilities(virDomainDefPtr def ATTRIBUTE_UNUSED,
#endif #endif
/**
* 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: * lxcContainerChild:
* @data: pointer to container arguments * @data: pointer to container arguments
@ -2172,6 +2202,12 @@ static int lxcContainerChild(void *data)
goto cleanup; 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 /* Wait for controller to finish setup tasks, including
* things like move of network interfaces, uid/gid mapping * things like move of network interfaces, uid/gid mapping
*/ */
@ -2342,6 +2378,7 @@ int lxcContainerStart(virDomainDefPtr def,
int *passFDs, int *passFDs,
int control, int control,
int handshakefd, int handshakefd,
int *nsInheritFDs,
size_t nttyPaths, size_t nttyPaths,
char **ttyPaths) char **ttyPaths)
{ {
@ -2359,7 +2396,8 @@ int lxcContainerStart(virDomainDefPtr def,
.monitor = control, .monitor = control,
.nttyPaths = nttyPaths, .nttyPaths = nttyPaths,
.ttyPaths = ttyPaths, .ttyPaths = ttyPaths,
.handshakefd = handshakefd .handshakefd = handshakefd,
.nsInheritFDs = nsInheritFDs,
}; };
/* allocate a stack for the container */ /* allocate a stack for the container */
@ -2368,7 +2406,7 @@ int lxcContainerStart(virDomainDefPtr def,
stacktop = stack + stacksize; 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_required(def)) {
if (userns_supported()) { if (userns_supported()) {
@ -2381,11 +2419,32 @@ int lxcContainerStart(virDomainDefPtr def,
return -1; return -1;
} }
} }
if (!nsInheritFDs || nsInheritFDs[VIR_LXC_DOMAIN_NAMESPACE_SHARENET] == -1) {
if (lxcNeedNetworkNamespace(def)) { if (lxcNeedNetworkNamespace(def)) {
VIR_DEBUG("Enable network namespaces"); VIR_DEBUG("Enable network namespaces");
cflags |= CLONE_NEWNET; 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 (!nsInheritFDs || nsInheritFDs[VIR_LXC_DOMAIN_NAMESPACE_SHAREUTS] == -1) {
cflags |= CLONE_NEWUTS;
} else {
VIR_DEBUG("Inheriting a UTS namespace");
}
VIR_DEBUG("Cloning container init process"); VIR_DEBUG("Cloning container init process");
pid = clone(lxcContainerChild, stacktop, cflags, &args); pid = clone(lxcContainerChild, stacktop, cflags, &args);

View File

@ -25,6 +25,7 @@
# define LXC_CONTAINER_H # define LXC_CONTAINER_H
# include "lxc_conf.h" # include "lxc_conf.h"
# include "lxc_domain.h"
# include "security/security_manager.h" # include "security/security_manager.h"
enum { enum {
@ -60,6 +61,7 @@ int lxcContainerStart(virDomainDefPtr def,
int *passFDs, int *passFDs,
int control, int control,
int handshakefd, int handshakefd,
int *nsInheritFDs,
size_t nttyPaths, size_t nttyPaths,
char **ttyPaths); char **ttyPaths);

View File

@ -119,6 +119,8 @@ struct _virLXCController {
size_t npassFDs; size_t npassFDs;
int *passFDs; int *passFDs;
int *nsFDs;
size_t nconsoles; size_t nconsoles;
virLXCControllerConsolePtr consoles; virLXCControllerConsolePtr consoles;
char *devptmx; char *devptmx;
@ -287,6 +289,7 @@ static void virLXCControllerFree(virLXCControllerPtr ctrl)
VIR_FREE(ctrl->nbdpids); VIR_FREE(ctrl->nbdpids);
VIR_FREE(ctrl->nsFDs);
virCgroupFree(&ctrl->cgroup); virCgroupFree(&ctrl->cgroup);
/* This must always be the last thing to be closed */ /* This must always be the last thing to be closed */
@ -2391,6 +2394,7 @@ virLXCControllerRun(virLXCControllerPtr ctrl)
ctrl->passFDs, ctrl->passFDs,
control[1], control[1],
containerhandshake[1], containerhandshake[1],
ctrl->nsFDs,
ctrl->nconsoles, ctrl->nconsoles,
containerTTYPaths)) < 0) containerTTYPaths)) < 0)
goto cleanup; goto cleanup;
@ -2400,6 +2404,10 @@ virLXCControllerRun(virLXCControllerPtr ctrl)
for (i = 0; i < ctrl->npassFDs; i++) for (i = 0; i < ctrl->npassFDs; i++)
VIR_FORCE_CLOSE(ctrl->passFDs[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) if (virLXCControllerSetupCgroupLimits(ctrl) < 0)
goto cleanup; goto cleanup;
@ -2468,6 +2476,7 @@ int main(int argc, char *argv[])
const char *name = NULL; const char *name = NULL;
size_t nveths = 0; size_t nveths = 0;
char **veths = NULL; char **veths = NULL;
int ns_fd[VIR_LXC_DOMAIN_NAMESPACE_LAST];
int handshakeFd = -1; int handshakeFd = -1;
bool bg = false; bool bg = false;
const struct option options[] = { const struct option options[] = {
@ -2478,6 +2487,9 @@ int main(int argc, char *argv[])
{ "passfd", 1, NULL, 'p' }, { "passfd", 1, NULL, 'p' },
{ "handshakefd", 1, NULL, 's' }, { "handshakefd", 1, NULL, 's' },
{ "security", 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' }, { "help", 0, NULL, 'h' },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 },
}; };
@ -2489,6 +2501,9 @@ int main(int argc, char *argv[])
size_t i; size_t i;
const char *securityDriver = "none"; const char *securityDriver = "none";
for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++)
ns_fd[i] = -1;
if (setlocale(LC_ALL, "") == NULL || if (setlocale(LC_ALL, "") == NULL ||
bindtextdomain(PACKAGE, LOCALEDIR) == NULL || bindtextdomain(PACKAGE, LOCALEDIR) == NULL ||
textdomain(PACKAGE) == NULL || textdomain(PACKAGE) == NULL ||
@ -2504,7 +2519,7 @@ int main(int argc, char *argv[])
while (1) { while (1) {
int c; 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); options, NULL);
if (c == -1) if (c == -1)
@ -2552,6 +2567,30 @@ int main(int argc, char *argv[])
} }
break; 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': case 'S':
securityDriver = optarg; securityDriver = optarg;
break; break;
@ -2569,6 +2608,9 @@ int main(int argc, char *argv[])
fprintf(stderr, " -v VETH, --veth VETH\n"); fprintf(stderr, " -v VETH, --veth VETH\n");
fprintf(stderr, " -s FD, --handshakefd FD\n"); fprintf(stderr, " -s FD, --handshakefd FD\n");
fprintf(stderr, " -S NAME, --security NAME\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, " -h, --help\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
goto cleanup; goto cleanup;
@ -2621,6 +2663,19 @@ int main(int argc, char *argv[])
ctrl->passFDs = passFDs; ctrl->passFDs = passFDs;
ctrl->npassFDs = npassFDs; 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++) { for (i = 0; i < nttyFDs; i++) {
if (virLXCControllerAddConsole(ctrl, ttyFDs[i]) < 0) if (virLXCControllerAddConsole(ctrl, ttyFDs[i]) < 0)
goto cleanup; goto cleanup;

View File

@ -26,8 +26,13 @@
#include "viralloc.h" #include "viralloc.h"
#include "virlog.h" #include "virlog.h"
#include "virerror.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 VIR_FROM_THIS VIR_FROM_LXC
#define LXC_NAMESPACE_HREF "http://libvirt.org/schemas/domain/lxc/1.0"
VIR_LOG_INIT("lxc.lxc_domain"); VIR_LOG_INIT("lxc.lxc_domain");
@ -41,6 +46,150 @@ static void *virLXCDomainObjPrivateAlloc(void)
return priv; 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) static void virLXCDomainObjPrivateFree(void *data)
{ {
virLXCDomainObjPrivatePtr priv = data; virLXCDomainObjPrivatePtr priv = data;

View File

@ -27,6 +27,31 @@
# include "lxc_conf.h" # include "lxc_conf.h"
# include "lxc_monitor.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 struct _virLXCDomainObjPrivate virLXCDomainObjPrivate;
typedef virLXCDomainObjPrivate *virLXCDomainObjPrivatePtr; typedef virLXCDomainObjPrivate *virLXCDomainObjPrivatePtr;
@ -41,6 +66,7 @@ struct _virLXCDomainObjPrivate {
virCgroupPtr cgroup; virCgroupPtr cgroup;
}; };
extern virDomainXMLNamespace virLXCDriverDomainXMLNamespace;
extern virDomainXMLPrivateDataCallbacks virLXCDriverPrivateDataCallbacks; extern virDomainXMLPrivateDataCallbacks virLXCDriverPrivateDataCallbacks;
extern virDomainDefParserConfig virLXCDriverDomainDefParserConfig; extern virDomainDefParserConfig virLXCDriverDomainDefParserConfig;

View File

@ -359,6 +359,143 @@ char *virLXCProcessSetupInterfaceDirect(virConnectPtr conn,
return ret; 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: * virLXCProcessSetupInterfaces:
@ -764,6 +901,7 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver,
char **veths, char **veths,
int *ttyFDs, int *ttyFDs,
size_t nttyFDs, size_t nttyFDs,
int *nsInheritFDs,
int *files, int *files,
size_t nfiles, size_t nfiles,
int handshakefd, int handshakefd,
@ -825,6 +963,19 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver,
virCommandPassFD(cmd, files[i], 0); 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", virCommandAddArgPair(cmd, "--security",
virSecurityManagerGetModel(driver->securityManager)); virSecurityManagerGetModel(driver->securityManager));
@ -1032,6 +1183,7 @@ int virLXCProcessStart(virConnectPtr conn,
off_t pos = -1; off_t pos = -1;
char ebuf[1024]; char ebuf[1024];
char *timestamp; char *timestamp;
int nsInheritFDs[VIR_LXC_DOMAIN_NAMESPACE_LAST];
virCommandPtr cmd = NULL; virCommandPtr cmd = NULL;
virLXCDomainObjPrivatePtr priv = vm->privateData; virLXCDomainObjPrivatePtr priv = vm->privateData;
virCapsPtr caps = NULL; virCapsPtr caps = NULL;
@ -1204,6 +1356,10 @@ int virLXCProcessStart(virConnectPtr conn,
if (virLXCProcessSetupInterfaces(conn, vm->def, &nveths, &veths) < 0) if (virLXCProcessSetupInterfaces(conn, vm->def, &nveths, &veths) < 0)
goto cleanup; goto cleanup;
VIR_DEBUG("Setting up namespaces if any");
if (virLXCProcessSetupNamespaces(conn, vm->def->namespaceData, nsInheritFDs) < 0)
goto cleanup;
VIR_DEBUG("Preparing to launch"); VIR_DEBUG("Preparing to launch");
if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT,
S_IRUSR|S_IWUSR)) < 0) { S_IRUSR|S_IWUSR)) < 0) {
@ -1223,6 +1379,7 @@ int virLXCProcessStart(virConnectPtr conn,
vm, vm,
nveths, veths, nveths, veths,
ttyFDs, nttyFDs, ttyFDs, nttyFDs,
nsInheritFDs,
files, nfiles, files, nfiles,
handshakefds[1], handshakefds[1],
&logfd, &logfd,

View File

@ -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>

View File

@ -133,6 +133,7 @@ mymain(void)
DO_TEST("filesystem-root"); DO_TEST("filesystem-root");
DO_TEST("idmap"); DO_TEST("idmap");
DO_TEST("capabilities"); DO_TEST("capabilities");
DO_TEST("sharenet");
virObjectUnref(caps); virObjectUnref(caps);
virObjectUnref(xmlopt); virObjectUnref(xmlopt);