mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 05:35:25 +00:00
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:
parent
f674dc6794
commit
c27553b6e2
@ -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>
|
||||
|
@ -67,6 +67,9 @@
|
||||
<optional>
|
||||
<ref name='qemucmdline'/>
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name='lxcsharens'/>
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name='keywrap'/>
|
||||
</optional>
|
||||
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -213,7 +213,7 @@ lxcDomainXMLConfInit(void)
|
||||
{
|
||||
return virDomainXMLOptionNew(&virLXCDriverDomainDefParserConfig,
|
||||
&virLXCDriverPrivateDataCallbacks,
|
||||
NULL);
|
||||
&virLXCDriverDomainXMLNamespace);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
@ -2143,6 +2144,35 @@ static int lxcContainerDropCapabilities(virDomainDefPtr def ATTRIBUTE_UNUSED,
|
||||
#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:
|
||||
* @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 (lxcNeedNetworkNamespace(def)) {
|
||||
VIR_DEBUG("Enable network namespaces");
|
||||
cflags |= CLONE_NEWNET;
|
||||
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");
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
33
tests/lxcxml2xmldata/lxc-sharenet.xml
Normal file
33
tests/lxcxml2xmldata/lxc-sharenet.xml
Normal 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>
|
@ -133,6 +133,7 @@ mymain(void)
|
||||
DO_TEST("filesystem-root");
|
||||
DO_TEST("idmap");
|
||||
DO_TEST("capabilities");
|
||||
DO_TEST("sharenet");
|
||||
|
||||
virObjectUnref(caps);
|
||||
virObjectUnref(xmlopt);
|
||||
|
Loading…
Reference in New Issue
Block a user