<div dir="ltr">Gentle reminder for the experts out there. Need some of your valuable inputs. <br><div><br>-imran<br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jul 1, 2015 at 11:07 PM, ik.nitk <span dir="ltr"><<a href="mailto:ik.nitk@gmail.com" target="_blank">ik.nitk@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">This patch adds feature for lxc containers to inherit namespaces. This is very similar to what<br>
lxc-tools or docker provides. Look for "man lxc-start" and you will find that you can pass command args as<br>
[ --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.<br>
<br>
>From this patch you can add extra libvirt option to share namespace in following way.<br>
<lxc:namespace><br>
<lxc:sharenet type='netns' value='red'/><br>
<lxc:shareipc type='pid' value='12345'/><br>
<lxc:shareuts type='name' value='container1'/><br>
</lxc:namespace><br>
<br>
<br>
---<br>
docs/<a href="http://drvlxc.html.in" rel="noreferrer" target="_blank">drvlxc.html.in</a> | 18 +++<br>
docs/schemas/domaincommon.rng | 42 ++++++<br>
src/Makefile.am | 4 +-<br>
src/lxc/lxc_conf.c | 2 +-<br>
src/lxc/lxc_conf.h | 15 +++<br>
src/lxc/lxc_container.c | 236 +++++++++++++++++++++++++++++++++-<br>
src/lxc/lxc_domain.c | 164 ++++++++++++++++++++++-<br>
src/lxc/lxc_domain.h | 1 +<br>
tests/lxcxml2xmldata/lxc-sharenet.xml | 33 +++++<br>
tests/lxcxml2xmltest.c | 1 +<br>
10 files changed, 507 insertions(+), 9 deletions(-)<br>
create mode 100644 tests/lxcxml2xmldata/lxc-sharenet.xml<br>
<br>
diff --git a/docs/<a href="http://drvlxc.html.in" rel="noreferrer" target="_blank">drvlxc.html.in</a> b/docs/<a href="http://drvlxc.html.in" rel="noreferrer" target="_blank">drvlxc.html.in</a><br>
index a094bd9..d14d4c7 100644<br>
--- a/docs/<a href="http://drvlxc.html.in" rel="noreferrer" target="_blank">drvlxc.html.in</a><br>
+++ b/docs/<a href="http://drvlxc.html.in" rel="noreferrer" target="_blank">drvlxc.html.in</a><br>
@@ -590,6 +590,24 @@ Note that allowing capabilities that are normally dropped by default can serious<br>
affect the security of the container and the host.<br>
</p><br>
<br>
+<h2><a name="share">Inherit namespaces</a></h2><br>
+<br>
+<p><br>
+Libvirt allows you to inherit the namespace from container/process just like lxc tools<br>
+or docker provides to share the network namespace. The following can be used to share<br>
+required namespaces. If we want to share only one then the other namespaces can be ignored.<br>
+</p><br>
+<pre><br>
+<domain type='lxc' xmlns:lxc='<a href="http://libvirt.org/schemas/domain/lxc/1.0'>" rel="noreferrer" target="_blank">http://libvirt.org/schemas/domain/lxc/1.0'></a>;<br>
+...<br>
+<lxc:namespace><br>
+ <lxc:sharenet type='netns' value='red'/><br>
+ <lxc:shareuts type='name' value='container1'/><br>
+ <lxc:shareipc type='pid' value='12345'/><br>
+</lxc:namespace><br>
+</domain><br>
+</pre><br>
+<br>
<h2><a name="usage">Container usage / management</a></h2><br>
<br>
<p><br>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng<br>
index 1120003..803b327 100644<br>
--- a/docs/schemas/domaincommon.rng<br>
+++ b/docs/schemas/domaincommon.rng<br>
@@ -68,6 +68,9 @@<br>
<ref name='qemucmdline'/><br>
</optional><br>
<optional><br>
+ <ref name='lxcsharens'/><br>
+ </optional><br>
+ <optional><br>
<ref name='keywrap'/><br>
</optional><br>
</interleave><br>
@@ -5012,6 +5015,45 @@<br>
</element><br>
</define><br>
<br>
+ <!--<br>
+ Optional hypervisor extensions in their own namespace:<br>
+ LXC<br>
+ --><br>
+ <define name="lxcsharens"><br>
+ <element name="namespace" ns="<a href="http://libvirt.org/schemas/domain/lxc/1.0" rel="noreferrer" target="_blank">http://libvirt.org/schemas/domain/lxc/1.0</a>"><br>
+ <zeroOrMore><br>
+ <element name="sharenet"><br>
+ <attribute name="type"><br>
+ <choice><br>
+ <value>netns</value><br>
+ <value>name</value><br>
+ <value>pid</value><br>
+ </choice><br>
+ </attribute><br>
+ <attribute name='value'/><br>
+ </element><br>
+ <element name="shareipc"><br>
+ <attribute name="type"><br>
+ <choice><br>
+ <value>name</value><br>
+ <value>pid</value><br>
+ </choice><br>
+ </attribute><br>
+ <attribute name='value'/><br>
+ </element><br>
+ <element name="shareuts"><br>
+ <attribute name="type"><br>
+ <choice><br>
+ <value>name</value><br>
+ <value>pid</value><br>
+ </choice><br>
+ </attribute><br>
+ <attribute name='value'/><br>
+ </element><br>
+ </zeroOrMore><br>
+ </element><br>
+ </define><br>
+<br>
<define name="metadata"><br>
<element name="metadata"><br>
<zeroOrMore><br>
diff --git a/src/Makefile.am b/src/Makefile.am<br>
index be63e26..ef96a5a 100644<br>
--- a/src/Makefile.am<br>
+++ b/src/Makefile.am<br>
@@ -1319,7 +1319,7 @@ libvirt_driver_lxc_impl_la_CFLAGS = \<br>
-I$(srcdir)/access \<br>
-I$(srcdir)/conf \<br>
$(AM_CFLAGS)<br>
-libvirt_driver_lxc_impl_la_LIBADD = $(CAPNG_LIBS) $(LIBNL_LIBS) $(FUSE_LIBS)<br>
+libvirt_driver_lxc_impl_la_LIBADD = $(CAPNG_LIBS) $(LIBNL_LIBS) $(LIBXML_LIBS) <a href="http://libvirt-lxc.la" rel="noreferrer" target="_blank">libvirt-lxc.la</a> $(FUSE_LIBS)<br>
if WITH_BLKID<br>
libvirt_driver_lxc_impl_la_CFLAGS += $(BLKID_CFLAGS)<br>
libvirt_driver_lxc_impl_la_LIBADD += $(BLKID_LIBS)<br>
@@ -2709,6 +2709,8 @@ libvirt_lxc_LDADD = \<br>
<a href="http://libvirt-net-rpc.la" rel="noreferrer" target="_blank">libvirt-net-rpc.la</a> \<br>
<a href="http://libvirt_security_manager.la" rel="noreferrer" target="_blank">libvirt_security_manager.la</a> \<br>
<a href="http://libvirt_conf.la" rel="noreferrer" target="_blank">libvirt_conf.la</a> \<br>
+ <a href="http://libvirt.la" rel="noreferrer" target="_blank">libvirt.la</a> \<br>
+ <a href="http://libvirt-lxc.la" rel="noreferrer" target="_blank">libvirt-lxc.la</a> \<br>
<a href="http://libvirt_util.la" rel="noreferrer" target="_blank">libvirt_util.la</a> \<br>
../gnulib/lib/<a href="http://libgnu.la" rel="noreferrer" target="_blank">libgnu.la</a><br>
if WITH_DTRACE_PROBES<br>
diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c<br>
index c393cb5..96a0f47 100644<br>
--- a/src/lxc/lxc_conf.c<br>
+++ b/src/lxc/lxc_conf.c<br>
@@ -213,7 +213,7 @@ lxcDomainXMLConfInit(void)<br>
{<br>
return virDomainXMLOptionNew(&virLXCDriverDomainDefParserConfig,<br>
&virLXCDriverPrivateDataCallbacks,<br>
- NULL);<br>
+ &virLXCDriverDomainXMLNamespace);<br>
}<br>
<br>
<br>
diff --git a/src/lxc/lxc_conf.h b/src/lxc/lxc_conf.h<br>
index 8340b1f..72b1d44 100644<br>
--- a/src/lxc/lxc_conf.h<br>
+++ b/src/lxc/lxc_conf.h<br>
@@ -67,6 +67,21 @@ struct _virLXCDriverConfig {<br>
bool securityRequireConfined;<br>
};<br>
<br>
+<br>
+typedef enum {<br>
+ VIR_DOMAIN_NAMESPACE_SHARENET = 0,<br>
+ VIR_DOMAIN_NAMESPACE_SHAREIPC,<br>
+ VIR_DOMAIN_NAMESPACE_SHAREUTS,<br>
+ VIR_DOMAIN_NAMESPACE_LAST,<br>
+} virDomainNamespace;<br>
+<br>
+typedef struct _lxcDomainDef lxcDomainDef;<br>
+typedef lxcDomainDef *lxcDomainDefPtr;<br>
+struct _lxcDomainDef {<br>
+ char *ns_type[VIR_DOMAIN_NAMESPACE_LAST];<br>
+ char *ns_val[VIR_DOMAIN_NAMESPACE_LAST];<br>
+};<br>
+<br>
struct _virLXCDriver {<br>
virMutex lock;<br>
<br>
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c<br>
index 11e9514..d8362ab 100644<br>
--- a/src/lxc/lxc_container.c<br>
+++ b/src/lxc/lxc_container.c<br>
@@ -27,6 +27,7 @@<br>
#include <config.h><br>
<br>
#include <fcntl.h><br>
+#include <sched.h><br>
#include <limits.h><br>
#include <stdlib.h><br>
#include <stdio.h><br>
@@ -38,7 +39,6 @@<br>
#include <mntent.h><br>
#include <sys/reboot.h><br>
#include <linux/reboot.h><br>
-<br>
/* Yes, we want linux private one, for _syscall2() macro */<br>
#include <linux/unistd.h><br>
<br>
@@ -2321,6 +2321,181 @@ virArch lxcContainerGetAlt32bitArch(virArch arch)<br>
return VIR_ARCH_NONE;<br>
}<br>
<br>
+struct ns_info {<br>
+ const char *proc_name;<br>
+ int clone_flag;<br>
+}ns_info_local[VIR_DOMAIN_NAMESPACE_LAST] = {<br>
+ [VIR_DOMAIN_NAMESPACE_SHARENET] = {"net", CLONE_NEWNET},<br>
+ [VIR_DOMAIN_NAMESPACE_SHAREIPC] = {"ipc", CLONE_NEWIPC},<br>
+ [VIR_DOMAIN_NAMESPACE_SHAREUTS] = {"uts", CLONE_NEWUTS}<br>
+};<br>
+<br>
+static int lxcOpen_ns(lxcDomainDefPtr lxcDef, int ns_fd[VIR_DOMAIN_NAMESPACE_LAST])<br>
+{<br>
+ int i, n, rc = 0;<br>
+ virDomainPtr dom = NULL;<br>
+ virConnectPtr conn = NULL;<br>
+ pid_t pid;<br>
+ int nfdlist;<br>
+ int *fdlist;<br>
+ char *path = NULL;<br>
+ char *eptr;<br>
+ for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++)<br>
+ ns_fd[i] = -1;<br>
+<br>
+ if (STREQ_NULLABLE("netns", lxcDef->ns_type[VIR_DOMAIN_NAMESPACE_SHARENET])) {<br>
+ if (virAsprintf(&path, "/var/run/netns/%s", lxcDef->ns_val[VIR_DOMAIN_NAMESPACE_SHARENET]) < 0)<br>
+ return -1;<br>
+ ns_fd[VIR_DOMAIN_NAMESPACE_SHARENET] = open(path, O_RDONLY);<br>
+ VIR_FREE(path);<br>
+ if (ns_fd[VIR_DOMAIN_NAMESPACE_SHARENET] < 0) {<br>
+ virReportSystemError(errno,<br>
+ _("failed to open netns %s"), lxcDef->ns_val[VIR_DOMAIN_NAMESPACE_SHARENET]);<br>
+ return -1;<br>
+ }<br>
+ }<br>
+ for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) {<br>
+ /* If not yet intialized by above: netns*/<br>
+ if (lxcDef->ns_type[i] && ns_fd[i] == -1) {<br>
+ pid = strtol(lxcDef->ns_val[i], &eptr, 10);<br>
+ if (*eptr != '\0' || pid < 1) {<br>
+ /* check if the domain is running, then set the namespaces<br>
+ * to that container<br>
+ */<br>
+ const char *ns[] = { "user", "ipc", "uts", "net", "pid", "mnt" };<br>
+ conn = virConnectOpen("lxc:///");<br>
+ if (!conn) {<br>
+ virReportError(virGetLastError()->code,<br>
+ _("unable to get connect to lxc %s"), lxcDef->ns_val[i]);<br>
+ rc = -1;<br>
+ goto cleanup;<br>
+ }<br>
+ dom = virDomainLookupByName(conn, lxcDef->ns_val[i]);<br>
+ if (!dom) {<br>
+ virReportError(virGetLastError()->code,<br>
+ _("Unable to lookup peer containeri %s"),<br>
+ lxcDef->ns_val[i]);<br>
+ rc = -1;<br>
+ goto cleanup;<br>
+ }<br>
+ if ((nfdlist = virDomainLxcOpenNamespace(dom, &fdlist, 0)) < 0) {<br>
+ virReportError(virGetLastError()->code,<br>
+ _("Unable to open %s"), lxcDef->ns_val[i]);<br>
+ rc = -1;<br>
+ goto cleanup;<br>
+ }<br>
+ for (n = 0; n < ARRAY_CARDINALITY(ns); n++) {<br>
+ if (STREQ(ns[n], ns_info_local[i].proc_name)) {<br>
+ ns_fd[i] = fdlist[n];<br>
+ } else {<br>
+ if (VIR_CLOSE(fdlist[n]) < 0)<br>
+ VIR_ERROR(_("failed to close fd. ignoring.."));<br>
+ }<br>
+ }<br>
+ if (nfdlist > 0)<br>
+ VIR_FREE(fdlist);<br>
+ } else {<br>
+ if (virAsprintf(&path, "/proc/%d/ns/%s", pid, ns_info_local[i].proc_name) < 0)<br>
+ return -1;<br>
+ ns_fd[i] = open(path, O_RDONLY);<br>
+ VIR_FREE(path);<br>
+ if (ns_fd[i] < 0) {<br>
+ virReportSystemError(errno,<br>
+ _("failed to open ns %s"), lxcDef->ns_val[i]);<br>
+ return -1;<br>
+ }<br>
+ }<br>
+ }<br>
+ }<br>
+ cleanup:<br>
+ if (dom)<br>
+ virDomainFree(dom);<br>
+ if (conn)<br>
+ virConnectClose(conn);<br>
+ return rc;<br>
+}<br>
+<br>
+<br>
+static void lxcClose_ns(int ns_fd[VIR_DOMAIN_NAMESPACE_LAST])<br>
+{<br>
+ int i;<br>
+ for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) {<br>
+ if (ns_fd[i] > -1) {<br>
+ if (VIR_CLOSE(ns_fd[i]) < 0)<br>
+ virReportSystemError(errno, "%s", _("failed to close file"));<br>
+ ns_fd[i] = -1;<br>
+ }<br>
+ }<br>
+}<br>
+<br>
+<br>
+/**<br>
+ * lxcPreserve_ns:<br>
+ * @ns_fd: array to store current namespace<br>
+ * @clone_flags: namespaces that need to be preserved<br>
+ */<br>
+static int lxcPreserve_ns(int ns_fd[VIR_DOMAIN_NAMESPACE_LAST], int clone_flags)<br>
+{<br>
+ int i, saved_errno;<br>
+ char *path = NULL;<br>
+<br>
+ for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++)<br>
+ ns_fd[i] = -1;<br>
+<br>
+ if (!virFileExists("/proc/self/ns")) {<br>
+ virReportSystemError(errno, "%s",<br>
+ _("Kernel does not support attach; preserve_ns ignored"));<br>
+ return -1;<br>
+ }<br>
+<br>
+ for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) {<br>
+ if ((clone_flags & ns_info_local[i].clone_flag) == 0)<br>
+ continue;<br>
+ if (virAsprintf(&path, "/proc/self/ns/%s",<br>
+ ns_info_local[i].proc_name) < 0)<br>
+ goto error;<br>
+ ns_fd[i] = open(path, O_RDONLY | O_CLOEXEC);<br>
+ if (ns_fd[i] < 0)<br>
+ goto error;<br>
+ VIR_FREE(path);<br>
+ }<br>
+ return 0;<br>
+ error:<br>
+ saved_errno = errno;<br>
+ lxcClose_ns(ns_fd);<br>
+ errno = saved_errno;<br>
+ virReportSystemError(errno, _("lxcPreserve_ns failed for '%s'"), path);<br>
+ VIR_FREE(path);<br>
+ return -1;<br>
+}<br>
+<br>
+/**<br>
+ * lxcAttach_ns:<br>
+ * @ns_fd: array of namespaces to attach<br>
+ */<br>
+static int lxcAttach_ns(const int ns_fd[VIR_DOMAIN_NAMESPACE_LAST])<br>
+{<br>
+ int i;<br>
+<br>
+ for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) {<br>
+ if (ns_fd[i] < 0)<br>
+ continue;<br>
+ VIR_DEBUG("Setting into namespace\n");<br>
+ /* We get EINVAL if new NS is same as the current<br>
+ * NS, or if the fd namespace doesn't match the<br>
+ * type passed to setns()'s second param. Since we<br>
+ * pass 0, we know the EINVAL is harmless<br>
+ */<br>
+ if (setns(ns_fd[i], 0) < 0 &&<br>
+ errno != EINVAL) {<br>
+ virReportSystemError(errno, _("failed to set namespace '%s'")<br>
+ , ns_info_local[i].proc_name);<br>
+ return -1;<br>
+ }<br>
+ }<br>
+ return 0;<br>
+}<br>
+<br>
<br>
/**<br>
* lxcContainerStart:<br>
@@ -2346,9 +2521,13 @@ int lxcContainerStart(virDomainDefPtr def,<br>
char **ttyPaths)<br>
{<br>
pid_t pid;<br>
- int cflags;<br>
+ int cflags, i;<br>
int stacksize = getpagesize() * 4;<br>
char *stack, *stacktop;<br>
+ int saved_ns_fd[VIR_DOMAIN_NAMESPACE_LAST];<br>
+ int ns_inherit_fd[VIR_DOMAIN_NAMESPACE_LAST];<br>
+ int preserve_mask = 0;<br>
+ lxcDomainDefPtr lxcDef;<br>
lxc_child_argv_t args = {<br>
.config = def,<br>
.securityDriver = securityDriver,<br>
@@ -2368,7 +2547,12 @@ int lxcContainerStart(virDomainDefPtr def,<br>
<br>
stacktop = stack + stacksize;<br>
<br>
- cflags = CLONE_NEWPID|CLONE_NEWNS|CLONE_NEWUTS|CLONE_NEWIPC|SIGCHLD;<br>
+ lxcDef = def->namespaceData;<br>
+ for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++)<br>
+ if (lxcDef && lxcDef->ns_type[i])<br>
+ preserve_mask |= ns_info_local[i].clone_flag;<br>
+<br>
+ cflags = CLONE_NEWPID|CLONE_NEWNS|SIGCHLD;<br>
<br>
if (userns_required(def)) {<br>
if (userns_supported()) {<br>
@@ -2381,10 +2565,43 @@ int lxcContainerStart(virDomainDefPtr def,<br>
return -1;<br>
}<br>
}<br>
+ if (!lxcDef || !lxcDef->ns_type[VIR_DOMAIN_NAMESPACE_SHARENET]) {<br>
+ if (lxcNeedNetworkNamespace(def)) {<br>
+ VIR_DEBUG("Enable network namespaces");<br>
+ cflags |= CLONE_NEWNET;<br>
+ }<br>
+ } else {<br>
+ VIR_DEBUG("Inheriting a net namespace");<br>
+ }<br>
+<br>
+ if (!lxcDef || !lxcDef->ns_type[VIR_DOMAIN_NAMESPACE_SHAREIPC]) {<br>
+ cflags |= CLONE_NEWIPC;<br>
+ } else {<br>
+ VIR_DEBUG("Inheriting an IPC namespace");<br>
+ }<br>
+<br>
+ if (!lxcDef || !lxcDef->ns_type[VIR_DOMAIN_NAMESPACE_SHAREUTS]) {<br>
+ cflags |= CLONE_NEWUTS;<br>
+ } else {<br>
+ VIR_DEBUG("Inheriting a UTS namespace");<br>
+ }<br>
+<br>
+ if (lxcDef && lxcPreserve_ns(saved_ns_fd, preserve_mask) < 0) {<br>
+ virReportError(VIR_ERR_SYSTEM_ERROR, "%s",<br>
+ _("failed to preserve the namespace"));<br>
+ return -1;<br>
+ }<br>
<br>
- if (lxcNeedNetworkNamespace(def)) {<br>
- VIR_DEBUG("Enable network namespaces");<br>
- cflags |= CLONE_NEWNET;<br>
+ if (lxcDef && lxcOpen_ns(lxcDef, ns_inherit_fd)) {<br>
+ virReportError(VIR_ERR_SYSTEM_ERROR, "%s",<br>
+ _("failed to open the namespace"));<br>
+ return -1;<br>
+ }<br>
+<br>
+ if (lxcDef && lxcAttach_ns(ns_inherit_fd) < 0) {<br>
+ virReportError(VIR_ERR_SYSTEM_ERROR, "%s",<br>
+ _("failed to attach the namespace"));<br>
+ return -1;<br>
}<br>
<br>
VIR_DEBUG("Cloning container init process");<br>
@@ -2397,7 +2614,14 @@ int lxcContainerStart(virDomainDefPtr def,<br>
_("Failed to run clone container"));<br>
return -1;<br>
}<br>
+ if (lxcDef && lxcAttach_ns(saved_ns_fd)) {<br>
+ virReportError(VIR_ERR_SYSTEM_ERROR, "%s",<br>
+ _("failed to restore saved namespaces"));<br>
+ }<br>
<br>
+ /* clean up */<br>
+ if (lxcDef)<br>
+ lxcClose_ns(ns_inherit_fd);<br>
return pid;<br>
}<br>
<br>
diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c<br>
index 70606f3..5e63969 100644<br>
--- a/src/lxc/lxc_domain.c<br>
+++ b/src/lxc/lxc_domain.c<br>
@@ -26,8 +26,14 @@<br>
#include "viralloc.h"<br>
#include "virlog.h"<br>
#include "virerror.h"<br>
+#include <fcntl.h><br>
+#include <libxml/xpathInternals.h><br>
+#include "virstring.h"<br>
+#include "virutil.h"<br>
+#include "virfile.h"<br>
<br>
#define VIR_FROM_THIS VIR_FROM_LXC<br>
+#define LXC_NAMESPACE_HREF "<a href="http://libvirt.org/schemas/domain/lxc/1.0" rel="noreferrer" target="_blank">http://libvirt.org/schemas/domain/lxc/1.0</a>"<br>
<br>
VIR_LOG_INIT("lxc.lxc_domain");<br>
<br>
@@ -41,6 +47,163 @@ static void *virLXCDomainObjPrivateAlloc(void)<br>
return priv;<br>
}<br>
<br>
+VIR_ENUM_DECL(virDomainNamespace)<br>
+VIR_ENUM_IMPL(virDomainNamespace, VIR_DOMAIN_NAMESPACE_LAST,<br>
+ N_("sharenet"),<br>
+ N_("shareipc"),<br>
+ N_("shareuts"))<br>
+<br>
+static void<br>
+lxcDomainDefNamespaceFree(void *nsdata)<br>
+{<br>
+ int j;<br>
+ lxcDomainDefPtr lxcDef = nsdata;<br>
+ for (j = 0; j < VIR_DOMAIN_NAMESPACE_LAST; j++) {<br>
+ VIR_FREE(lxcDef->ns_type[j]);<br>
+ VIR_FREE(lxcDef->ns_val[j]);<br>
+ }<br>
+ VIR_FREE(nsdata);<br>
+}<br>
+<br>
+static int<br>
+lxcDomainDefNamespaceParse(xmlDocPtr xml ATTRIBUTE_UNUSED,<br>
+ xmlNodePtr root ATTRIBUTE_UNUSED,<br>
+ xmlXPathContextPtr ctxt,<br>
+ void **data)<br>
+{<br>
+ lxcDomainDefPtr lxcDef = NULL;<br>
+ xmlNodePtr *nodes = NULL;<br>
+ bool uses_lxc_ns = false;<br>
+ xmlNodePtr node;<br>
+ int feature;<br>
+ int n;<br>
+ char *tmp = NULL;<br>
+ size_t i;<br>
+<br>
+ if (xmlXPathRegisterNs(ctxt, BAD_CAST "lxc", BAD_CAST LXC_NAMESPACE_HREF) < 0) {<br>
+ virReportError(VIR_ERR_INTERNAL_ERROR,<br>
+ _("Failed to register xml namespace '%s'"),<br>
+ LXC_NAMESPACE_HREF);<br>
+ return -1;<br>
+ }<br>
+<br>
+ if (VIR_ALLOC(lxcDef) < 0)<br>
+ return -1;<br>
+ /* Init ns_herit_fd for namespaces */<br>
+ for (i = 0; i < VIR_DOMAIN_NAMESPACE_LAST; i++) {<br>
+ lxcDef->ns_type[i] = NULL;<br>
+ lxcDef->ns_val[i] = NULL;<br>
+ }<br>
+<br>
+ node = ctxt->node;<br>
+ if ((n = virXPathNodeSet("./lxc:namespace/*", ctxt, &nodes)) < 0)<br>
+ goto error;<br>
+ uses_lxc_ns |= n > 0;<br>
+<br>
+ for (i = 0; i < n; i++) {<br>
+ feature =<br>
+ virDomainNamespaceTypeFromString((const char *) nodes[i]->name);<br>
+ if (feature < 0) {<br>
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,<br>
+ _("unsupported Namespace feature: %s"),<br>
+ nodes[i]->name);<br>
+ goto error;<br>
+ }<br>
+<br>
+ ctxt->node = nodes[i];<br>
+<br>
+ switch ((virDomainNamespace) feature) {<br>
+ case VIR_DOMAIN_NAMESPACE_SHARENET:<br>
+ case VIR_DOMAIN_NAMESPACE_SHAREIPC:<br>
+ case VIR_DOMAIN_NAMESPACE_SHAREUTS:<br>
+ {<br>
+ tmp = virXMLPropString(nodes[i], "type");<br>
+ if (tmp == NULL) {<br>
+ virReportError(VIR_ERR_INTERNAL_ERROR,<br>
+ "%s", _("No lxc environment type specified"));<br>
+ goto error;<br>
+ }<br>
+ /* save the tmp so that its needed while writing to xml */<br>
+ lxcDef->ns_type[feature] = tmp;<br>
+ tmp = virXMLPropString(nodes[i], "value");<br>
+ if (tmp == NULL) {<br>
+ virReportError(VIR_ERR_INTERNAL_ERROR,<br>
+ "%s", _("No lxc environment type specified"));<br>
+ goto error;<br>
+ }<br>
+ lxcDef->ns_val[feature] = tmp;<br>
+ }<br>
+ break;<br>
+ case VIR_DOMAIN_NAMESPACE_LAST:<br>
+ break;<br>
+ }<br>
+ }<br>
+ VIR_FREE(nodes);<br>
+ ctxt->node = node;<br>
+ if (uses_lxc_ns)<br>
+ *data = lxcDef;<br>
+ else<br>
+ VIR_FREE(lxcDef);<br>
+ return 0;<br>
+ error:<br>
+ VIR_FREE(nodes);<br>
+ lxcDomainDefNamespaceFree(lxcDef);<br>
+ return -1;<br>
+}<br>
+<br>
+<br>
+static int<br>
+lxcDomainDefNamespaceFormatXML(virBufferPtr buf,<br>
+ void *nsdata)<br>
+{<br>
+ lxcDomainDefPtr lxcDef = nsdata;<br>
+ size_t j;<br>
+<br>
+ if (!lxcDef)<br>
+ return 0;<br>
+<br>
+ virBufferAddLit(buf, "<lxc:namespace>\n");<br>
+ virBufferAdjustIndent(buf, 2);<br>
+<br>
+ for (j = 0; j < VIR_DOMAIN_NAMESPACE_LAST; j++) {<br>
+ switch ((virDomainNamespace) j) {<br>
+ case VIR_DOMAIN_NAMESPACE_SHAREIPC:<br>
+ case VIR_DOMAIN_NAMESPACE_SHAREUTS:<br>
+ case VIR_DOMAIN_NAMESPACE_SHARENET:<br>
+ {<br>
+ if (lxcDef->ns_type[j]) {<br>
+ virBufferAsprintf(buf, "<lxc:%s type='%s' value='%s'/>\n",<br>
+ virDomainNamespaceTypeToString(j),<br>
+ lxcDef->ns_type[j],<br>
+ lxcDef->ns_val[j]);<br>
+ }<br>
+ }<br>
+ break;<br>
+ case VIR_DOMAIN_NAMESPACE_LAST:<br>
+ break;<br>
+ }<br>
+ }<br>
+<br>
+ virBufferAdjustIndent(buf, -2);<br>
+ virBufferAddLit(buf, "</lxc:namespace>\n");<br>
+ return 0;<br>
+}<br>
+<br>
+static const char *<br>
+lxcDomainDefNamespaceHref(void)<br>
+{<br>
+ return "xmlns:lxc='" LXC_NAMESPACE_HREF "'";<br>
+}<br>
+<br>
+<br>
+virDomainXMLNamespace virLXCDriverDomainXMLNamespace = {<br>
+ .parse = lxcDomainDefNamespaceParse,<br>
+ .free = lxcDomainDefNamespaceFree,<br>
+ .format = lxcDomainDefNamespaceFormatXML,<br>
+ .href = lxcDomainDefNamespaceHref,<br>
+};<br>
+<br>
+<br>
static void virLXCDomainObjPrivateFree(void *data)<br>
{<br>
virLXCDomainObjPrivatePtr priv = data;<br>
@@ -77,7 +240,6 @@ virLXCDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt,<br>
} else {<br>
priv->initpid = thepid;<br>
}<br>
-<br>
return 0;<br>
}<br>
<br>
diff --git a/src/lxc/lxc_domain.h b/src/lxc/lxc_domain.h<br>
index 751aece..25df999 100644<br>
--- a/src/lxc/lxc_domain.h<br>
+++ b/src/lxc/lxc_domain.h<br>
@@ -41,6 +41,7 @@ struct _virLXCDomainObjPrivate {<br>
virCgroupPtr cgroup;<br>
};<br>
<br>
+extern virDomainXMLNamespace virLXCDriverDomainXMLNamespace;<br>
extern virDomainXMLPrivateDataCallbacks virLXCDriverPrivateDataCallbacks;<br>
extern virDomainDefParserConfig virLXCDriverDomainDefParserConfig;<br>
<br>
diff --git a/tests/lxcxml2xmldata/lxc-sharenet.xml b/tests/lxcxml2xmldata/lxc-sharenet.xml<br>
new file mode 100644<br>
index 0000000..a2b8d1b<br>
--- /dev/null<br>
+++ b/tests/lxcxml2xmldata/lxc-sharenet.xml<br>
@@ -0,0 +1,33 @@<br>
+<domain type='lxc' xmlns:lxc='<a href="http://libvirt.org/schemas/domain/lxc/1.0" rel="noreferrer" target="_blank">http://libvirt.org/schemas/domain/lxc/1.0</a>'><br>
+ <name>jessie</name><br>
+ <uuid>e21987a5-e98e-9c99-0e35-803e4d9ad1fe</uuid><br>
+ <memory unit='KiB'>1048576</memory><br>
+ <currentMemory unit='KiB'>1048576</currentMemory><br>
+ <vcpu placement='static'>1</vcpu><br>
+ <resource><br>
+ <partition>/machine</partition><br>
+ </resource><br>
+ <os><br>
+ <type arch='x86_64'>exe</type><br>
+ <init>/sbin/init</init><br>
+ </os><br>
+ <clock offset='utc'/><br>
+ <on_poweroff>destroy</on_poweroff><br>
+ <on_reboot>restart</on_reboot><br>
+ <on_crash>restart</on_crash><br>
+ <devices><br>
+ <emulator>/usr/libexec/libvirt_lxc</emulator><br>
+ <filesystem type='mount' accessmode='passthrough'><br>
+ <source dir='/mach/jessie'/><br>
+ <target dir='/'/><br>
+ </filesystem><br>
+ <console type='pty'><br>
+ <target type='lxc' port='0'/><br>
+ </console><br>
+ </devices><br>
+ <lxc:namespace><br>
+ <lxc:sharenet type='netns' value='red'/><br>
+ <lxc:shareipc type='pid' value='12345'/><br>
+ <lxc:shareuts type='name' value='container1'/><br>
+ </lxc:namespace><br>
+</domain><br>
diff --git a/tests/lxcxml2xmltest.c b/tests/lxcxml2xmltest.c<br>
index 3e00347..8d824b9 100644<br>
--- a/tests/lxcxml2xmltest.c<br>
+++ b/tests/lxcxml2xmltest.c<br>
@@ -133,6 +133,7 @@ mymain(void)<br>
DO_TEST("filesystem-root");<br>
DO_TEST("idmap");<br>
DO_TEST("capabilities");<br>
+ DO_TEST("sharenet");<br>
<br>
virObjectUnref(caps);<br>
virObjectUnref(xmlopt);<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.9.1<br>
<br>
</font></span></blockquote></div><br></div>