[libvirt] [PATCH 6/9] Introduce an LXC specific public API & library

Daniel P. Berrange berrange at redhat.com
Fri Dec 21 17:08:29 UTC 2012


From: "Daniel P. Berrange" <berrange at redhat.com>

This patch introduces support for LXC specific public APIs. In
common with what was done for QEMU, this creates a libvirt_lxc.so
library and libvirt/libvirt-lxc.h header file.

The actual APIs are

  int virDomainLxcOpenNamespace(virDomainPtr domain,
                                int **fdlist,
                                unsigned int flags);

  int virDomainLxcEnterNamespace(virDomainPtr domain,
                                 unsigned int flags);

which provide a way to use the setns() system call to move the
calling process into the container's namespace. This is not
practical to write in a generically applicable manner. The
nearest that we could get to such an API would be an API which
allows to pass a command + argv to be executed inside a
container. Even if we had such a generic API, this LXC specific
API is still useful, because it allows the caller to maintain
the current process context, in particular any I/O streams they
have open.

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 .gitignore                          |   4 +
 cfg.mk                              |   3 +-
 configure.ac                        |   5 +-
 daemon/remote.c                     |   1 +
 docs/Makefile.am                    |  21 ++++-
 docs/apibuild.py                    |  10 ++-
 docs/hvsupport.pl                   |  40 +++++++++
 include/libvirt/Makefile.am         |   1 +
 include/libvirt/libvirt-lxc.h       |  50 +++++++++++
 libvirt.spec.in                     |   1 +
 mingw-libvirt.spec.in               |  10 +++
 python/Makefile.am                  |  35 ++++++--
 python/generator.py                 | 172 +++++++++++++++++++++++++++++++++++-
 python/libvirt-lxc-override-api.xml |  19 ++++
 python/libvirt-lxc-override.c       | 141 +++++++++++++++++++++++++++++
 src/Makefile.am                     |  18 +++-
 src/driver.h                        |   6 ++
 src/internal.h                      |   1 +
 src/libvirt-lxc.c                   | 165 ++++++++++++++++++++++++++++++++++
 src/libvirt_lxc.syms                |  17 ++++
 src/lxc/lxc_driver.c                |   1 +
 tools/virsh.c                       |   1 +
 22 files changed, 708 insertions(+), 14 deletions(-)
 create mode 100644 include/libvirt/libvirt-lxc.h
 create mode 100644 python/libvirt-lxc-override-api.xml
 create mode 100644 python/libvirt-lxc-override.c
 create mode 100644 src/libvirt-lxc.c
 create mode 100644 src/libvirt_lxc.syms

diff --git a/.gitignore b/.gitignore
index 882ae4c..579b324 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,6 +64,7 @@
 /docs/hvsupport.html.in
 /docs/libvirt-api.xml
 /docs/libvirt-qemu-*.xml
+/docs/libvirt-lxc-*.xml
 /docs/libvirt-refs.xml
 /docs/search.php
 /docs/todo.html.in
@@ -92,10 +93,13 @@
 /python/generated.stamp
 /python/generator.py.stamp
 /python/libvirt-export.c
+/python/libvirt-lxc-export.c
+/python/libvirt-lxc.[ch]
 /python/libvirt-qemu-export.c
 /python/libvirt-qemu.[ch]
 /python/libvirt.[ch]
 /python/libvirt.py
+/python/libvirt_lxc.py
 /python/libvirt_qemu.py
 /run
 /sc_*
diff --git a/cfg.mk b/cfg.mk
index f9270b0..a98b3f1 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -302,6 +302,7 @@ sc_flags_usage:
 	@test "$$(cat $(srcdir)/include/libvirt/libvirt.h.in		\
 	    $(srcdir)/include/libvirt/virterror.h			\
 	    $(srcdir)/include/libvirt/libvirt-qemu.h			\
+	    $(srcdir)/include/libvirt/libvirt-lxc.h			\
 	  | grep -c '\(long\|unsigned\) flags')" != 4 &&		\
 	  { echo '$(ME): new API should use "unsigned int flags"' 1>&2;	\
 	    exit 1; } || :
@@ -767,7 +768,7 @@ exclude_file_name_regexp--sc_prohibit_VIR_ERR_NO_MEMORY = \
 exclude_file_name_regexp--sc_prohibit_access_xok = ^src/util/virutil\.c$$
 
 exclude_file_name_regexp--sc_prohibit_always_true_header_tests = \
-  ^python/(libvirt-(qemu-)?override|typewrappers)\.c$$
+  ^python/(libvirt-(lxc-|qemu-)?override|typewrappers)\.c$$
 
 exclude_file_name_regexp--sc_prohibit_asprintf = \
   ^(bootstrap.conf$$|src/util/virutil\.c$$|examples/domain-events/events-c/event-test\.c$$)
diff --git a/configure.ac b/configure.ac
index 3c97e4f..5a15531 100644
--- a/configure.ac
+++ b/configure.ac
@@ -174,7 +174,7 @@ dnl Availability of various common functions (non-fatal if missing),
 dnl and various less common threadsafe functions
 AC_CHECK_FUNCS_ONCE([cfmakeraw geteuid getgid getgrnam_r getmntent_r \
   getpwuid_r getuid initgroups kill mmap newlocale posix_fallocate \
-  posix_memalign regexec sched_getaffinity])
+  posix_memalign regexec sched_getaffinity setns])
 
 dnl Availability of pthread functions (if missing, win32 threading is
 dnl assumed).  Because of $LIB_PTHREAD, we cannot use AC_CHECK_FUNCS_ONCE.
@@ -2639,6 +2639,7 @@ CYGWIN_EXTRA_PYTHON_LIBADD=
 MINGW_EXTRA_LDFLAGS=
 WIN32_EXTRA_CFLAGS=
 LIBVIRT_SYMBOL_FILE=libvirt.syms
+LIBVIRT_LXC_SYMBOL_FILE='$(srcdir)/libvirt_lxc.syms'
 LIBVIRT_QEMU_SYMBOL_FILE='$(srcdir)/libvirt_qemu.syms'
 MSCOM_LIBS=
 case "$host" in
@@ -2672,6 +2673,7 @@ case "$host" in
     # Also set the symbol file to .def, so src/Makefile generates libvirt.def
     # from libvirt.syms and passes libvirt.def instead of libvirt.syms to the linker
     LIBVIRT_SYMBOL_FILE=libvirt.def
+    LIBVIRT_LXC_SYMBOL_FILE=libvirt_lxc.def
     LIBVIRT_QEMU_SYMBOL_FILE=libvirt_qemu.def
     # mingw's ld has the --version-script parameter, but it requires a .def file
     # instead to work properly, therefore clear --version-script here and use
@@ -2687,6 +2689,7 @@ AC_SUBST([CYGWIN_EXTRA_PYTHON_LIBADD])
 AC_SUBST([MINGW_EXTRA_LDFLAGS])
 AC_SUBST([WIN32_EXTRA_CFLAGS])
 AC_SUBST([LIBVIRT_SYMBOL_FILE])
+AC_SUBST([LIBVIRT_LXC_SYMBOL_FILE])
 AC_SUBST([LIBVIRT_QEMU_SYMBOL_FILE])
 AC_SUBST([VERSION_SCRIPT_FLAGS])
 AC_SUBST([MSCOM_LIBS])
diff --git a/daemon/remote.c b/daemon/remote.c
index 8767c18..a69dc5d 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -39,6 +39,7 @@
 #include "stream.h"
 #include "viruuid.h"
 #include "libvirt/libvirt-qemu.h"
+#include "libvirt/libvirt-lxc.h"
 #include "vircommand.h"
 #include "intprops.h"
 #include "virnetserverservice.h"
diff --git a/docs/Makefile.am b/docs/Makefile.am
index cba9d4b..6bd5681 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -95,8 +95,12 @@ qemu_xml = \
   libvirt-qemu-api.xml \
   libvirt-qemu-refs.xml
 
+lxc_xml = \
+  libvirt-lxc-api.xml \
+  libvirt-lxc-refs.xml
+
 apidir = $(pkgdatadir)/api
-api_DATA = libvirt-api.xml libvirt-qemu-api.xml
+api_DATA = libvirt-api.xml libvirt-qemu-api.xml libvirt-lxc-api.xml
 
 fig = \
   libvirt-net-logical.fig \
@@ -133,6 +137,7 @@ all-am: web
 
 api: $(srcdir)/libvirt-api.xml $(srcdir)/libvirt-refs.xml
 qemu_api: $(srcdir)/libvirt-qemu-api.xml $(srcdir)/libvirt-qemu-refs.xml
+lxc_api: $(srcdir)/libvirt-lxc-api.xml $(srcdir)/libvirt-lxc-refs.xml
 
 web: $(dot_html) $(internals_html) html/index.html devhelp/index.html \
   $(dot_php)
@@ -152,7 +157,8 @@ todo:
 	$(MAKE) todo.html
 
 hvsupport.html.in: $(srcdir)/hvsupport.pl $(srcdir)/../src/libvirt_public.syms \
-	 $(srcdir)/../src/libvirt_qemu.syms $(srcdir)/../src/driver.h
+	 $(srcdir)/../src/libvirt_qemu.syms $(srcdir)/../src/libvirt_lxc.syms \
+	$(srcdir)/../src/driver.h
 	$(AM_V_GEN)$(PERL) $(srcdir)/hvsupport.pl $(srcdir)/../src > $@ || { rm $@ && exit 1; }
 
 .PHONY: todo
@@ -220,12 +226,16 @@ $(addprefix $(srcdir)/,$(devhelphtml)): $(srcdir)/libvirt-api.xml $(devhelpxsl)
 
 python_generated_files = \
 		$(srcdir)/html/libvirt-libvirt.html \
+		$(srcdir)/html/libvirt-libvirt-lxc.html \
 		$(srcdir)/html/libvirt-libvirt-qemu.html \
 		$(srcdir)/html/libvirt-virterror.html \
 		$(srcdir)/libvirt-api.xml \
 		$(srcdir)/libvirt-refs.xml \
+		$(srcdir)/libvirt-lxc-api.xml \
+		$(srcdir)/libvirt-lxc-refs.xml \
 		$(srcdir)/libvirt-qemu-api.xml \
-		$(srcdir)/libvirt-qemu-refs.xml
+		$(srcdir)/libvirt-qemu-refs.xml \
+		$(NULL)
 
 APIBUILD=$(srcdir)/apibuild.py
 APIBUILD_STAMP=$(APIBUILD).stamp
@@ -235,9 +245,11 @@ $(python_generated_files): $(APIBUILD_STAMP)
 
 $(APIBUILD_STAMP): $(srcdir)/apibuild.py \
 		$(srcdir)/../include/libvirt/libvirt.h.in \
+		$(srcdir)/../include/libvirt/libvirt-lxc.h \
 		$(srcdir)/../include/libvirt/libvirt-qemu.h \
 		$(srcdir)/../include/libvirt/virterror.h \
 		$(srcdir)/../src/libvirt.c \
+		$(srcdir)/../src/libvirt-lxc.c \
 		$(srcdir)/../src/libvirt-qemu.c \
 		$(srcdir)/../src/util/virerror.c
 	$(AM_V_GEN)srcdir=$(srcdir) $(PYTHON) $(APIBUILD)
@@ -252,9 +264,10 @@ clean-local:
 maintainer-clean-local: clean-local
 	rm -rf $(srcdir)/libvirt-api.xml $(srcdir)/libvirt-refs.xml todo.html.in hvsupport.html.in
 	rm -rf $(srcdir)/libvirt-qemu-api.xml $(srcdir)/libvirt-qemu-refs.xml
+	rm -rf $(srcdir)/libvirt-lxc-api.xml $(srcdir)/libvirt-lxc-refs.xml
 	rm -rf $(APIBUILD_STAMP)
 
-rebuild: api qemu_api all
+rebuild: api qemu_api lxc_api all
 
 install-data-local:
 	$(mkinstalldirs) $(DESTDIR)$(HTML_DIR)
diff --git a/docs/apibuild.py b/docs/apibuild.py
index e73a85d..eb8ddb2 100755
--- a/docs/apibuild.py
+++ b/docs/apibuild.py
@@ -32,6 +32,11 @@ qemu_included_files = {
   "libvirt-qemu.c": "Implementations for the QEMU specific APIs",
 }
 
+lxc_included_files = {
+  "libvirt-lxc.h": "header with LXC specific API definitions",
+  "libvirt-lxc.c": "Implementations for the LXC specific APIs",
+}
+
 ignored_words = {
   "ATTRIBUTE_UNUSED": (0, "macro keyword"),
   "ATTRIBUTE_SENTINEL": (0, "macro keyword"),
@@ -1955,6 +1960,8 @@ class docBuilder:
             self.includes = includes + included_files.keys()
         elif name == "libvirt-qemu":
             self.includes = includes + qemu_included_files.keys()
+        elif name == "libvirt-lxc":
+            self.includes = includes + lxc_included_files.keys()
         self.modules = {}
         self.headers = {}
         self.idx = index()
@@ -2473,7 +2480,7 @@ class docBuilder:
 
 
 def rebuild(name):
-    if name not in ["libvirt", "libvirt-qemu"]:
+    if name not in ["libvirt", "libvirt-qemu", "libvirt-lxc"]:
         self.warning("rebuild() failed, unknown module %s") % name
         return None
     builder = None
@@ -2516,6 +2523,7 @@ if __name__ == "__main__":
     else:
         rebuild("libvirt")
         rebuild("libvirt-qemu")
+        rebuild("libvirt-lxc")
     if warnings > 0:
         sys.exit(2)
     else:
diff --git a/docs/hvsupport.pl b/docs/hvsupport.pl
index 4871739..6230e3c 100755
--- a/docs/hvsupport.pl
+++ b/docs/hvsupport.pl
@@ -11,6 +11,7 @@ my $srcdir = shift @ARGV;
 
 my $symslibvirt = "$srcdir/libvirt_public.syms";
 my $symsqemu = "$srcdir/libvirt_qemu.syms";
+my $symslxc = "$srcdir/libvirt_lxc.syms";
 my $drivertable = "$srcdir/driver.h";
 
 my %groupheaders = (
@@ -112,6 +113,45 @@ while (defined($line = <FILE>)) {
 close FILE;
 
 
+# And the same for the LXC specific APIs
+
+open FILE, "<$symslxc"
+    or die "cannot read $symslxc: $!";
+
+$prevvers = undef;
+$vers = undef;
+while (defined($line = <FILE>)) {
+    chomp $line;
+    next if $line =~ /^\s*#/;
+    next if $line =~ /^\s*$/;
+    next if $line =~ /^\s*(global|local):/;
+    if ($line =~ /^\s*LIBVIRT_LXC_(\d+\.\d+\.\d+)\s*{\s*$/) {
+        if (defined $vers) {
+            die "malformed syms file";
+        }
+        $vers = $1;
+    } elsif ($line =~ /\s*}\s*;\s*$/) {
+        if (defined $prevvers) {
+            die "malformed syms file";
+        }
+        $prevvers = $vers;
+        $vers = undef;
+    } elsif ($line =~ /\s*}\s*LIBVIRT_LXC_(\d+\.\d+\.\d+)\s*;\s*$/) {
+        if ($1 ne $prevvers) {
+            die "malformed syms file $1 != $vers";
+        }
+        $prevvers = $vers;
+        $vers = undef;
+    } elsif ($line =~ /\s*(\w+)\s*;\s*$/) {
+        $apis{$1} = $vers;
+    } else {
+        die "unexpected data $line\n";
+    }
+}
+
+close FILE;
+
+
 # Some special things which aren't public APIs,
 # but we want to report
 $apis{virConnectDrvSupportsFeature} = "0.3.2";
diff --git a/include/libvirt/Makefile.am b/include/libvirt/Makefile.am
index 8f36ae8..0ec7f04 100644
--- a/include/libvirt/Makefile.am
+++ b/include/libvirt/Makefile.am
@@ -6,6 +6,7 @@
 virincdir = $(includedir)/libvirt
 
 virinc_HEADERS = libvirt.h		\
+		 libvirt-lxc.h		\
 		 libvirt-qemu.h		\
 		 virterror.h
 
diff --git a/include/libvirt/libvirt-lxc.h b/include/libvirt/libvirt-lxc.h
new file mode 100644
index 0000000..f21538f
--- /dev/null
+++ b/include/libvirt/libvirt-lxc.h
@@ -0,0 +1,50 @@
+/* -*- c -*-
+ * libvirt-lxc.h: Interfaces specific for LXC driver
+ * Summary: lxc specific interfaces
+ * Description: Provides the interfaces of the libvirt library to handle
+ *              LXC specific methods
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#ifndef __VIR_LXC_H__
+# define __VIR_LXC_H__
+
+# include "libvirt/libvirt.h"
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+int virDomainLxcOpenNamespace(virDomainPtr domain,
+                              int **fdlist,
+                              unsigned int flags);
+
+int virDomainLxcEnterNamespace(virDomainPtr domain,
+                               unsigned int nfdlist,
+                               int *fdlist,
+                               unsigned int *noldfdlist,
+                               int **oldfdlist,
+                               unsigned int flags);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif /* __VIR_LXC_H__ */
diff --git a/libvirt.spec.in b/libvirt.spec.in
index 3aaef02..e76c4db 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -1970,6 +1970,7 @@ rm -f $RPM_BUILD_ROOT%{_sysconfdir}/sysctl.d/libvirtd
 %dir %{_datadir}/libvirt/api/
 %{_datadir}/libvirt/api/libvirt-api.xml
 %{_datadir}/libvirt/api/libvirt-qemu-api.xml
+%{_datadir}/libvirt/api/libvirt-lxc-api.xml
 
 %doc docs/*.html docs/html docs/*.gif
 %doc docs/libvirt-api.xml
diff --git a/mingw-libvirt.spec.in b/mingw-libvirt.spec.in
index 4695895..eaccfe6 100644
--- a/mingw-libvirt.spec.in
+++ b/mingw-libvirt.spec.in
@@ -189,10 +189,12 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt_iohelper.exe
 %{mingw32_bindir}/virt-xml-validate
 %{mingw32_bindir}/virt-pki-validate
 %{mingw32_bindir}/virt-host-validate.exe
+%{mingw32_bindir}/libvirt-lxc-0.dll
 %{mingw32_bindir}/libvirt-qemu-0.dll
 
 %{mingw32_libdir}/libvirt.dll.a
 %{mingw32_libdir}/pkgconfig/libvirt.pc
+%{mingw32_libdir}/libvirt-lxc.dll.a
 %{mingw32_libdir}/libvirt-qemu.dll.a
 
 %dir %{mingw32_datadir}/libvirt/
@@ -213,6 +215,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt_iohelper.exe
 %{mingw32_datadir}/libvirt/schemas/storagevol.rng
 %dir %{mingw32_datadir}/libvirt/api/
 %{mingw32_datadir}/libvirt/api/libvirt-api.xml
+%{mingw32_datadir}/libvirt/api/libvirt-lxc-api.xml
 %{mingw32_datadir}/libvirt/api/libvirt-qemu-api.xml
 
 %{mingw32_datadir}/libvirt/cpu_map.xml
@@ -222,6 +225,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt_iohelper.exe
 %dir %{mingw32_includedir}/libvirt
 %{mingw32_includedir}/libvirt/libvirt.h
 %{mingw32_includedir}/libvirt/virterror.h
+%{mingw32_includedir}/libvirt/libvirt-lxc.h
 %{mingw32_includedir}/libvirt/libvirt-qemu.h
 
 %{mingw32_mandir}/man1/virsh.1*
@@ -231,6 +235,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt_iohelper.exe
 
 %files -n mingw32-libvirt-static
 %{mingw32_libdir}/libvirt.a
+%{mingw32_libdir}/libvirt-lxc.a
 %{mingw32_libdir}/libvirt-qemu.a
 
 # Mingw64
@@ -243,10 +248,12 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt_iohelper.exe
 %{mingw64_bindir}/virt-xml-validate
 %{mingw64_bindir}/virt-pki-validate
 %{mingw64_bindir}/virt-host-validate.exe
+%{mingw64_bindir}/libvirt-lxc-0.dll
 %{mingw64_bindir}/libvirt-qemu-0.dll
 
 %{mingw64_libdir}/libvirt.dll.a
 %{mingw64_libdir}/pkgconfig/libvirt.pc
+%{mingw64_libdir}/libvirt-lxc.dll.a
 %{mingw64_libdir}/libvirt-qemu.dll.a
 
 %dir %{mingw64_datadir}/libvirt/
@@ -267,6 +274,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt_iohelper.exe
 %{mingw64_datadir}/libvirt/schemas/storagevol.rng
 %dir %{mingw64_datadir}/libvirt/api/
 %{mingw64_datadir}/libvirt/api/libvirt-api.xml
+%{mingw64_datadir}/libvirt/api/libvirt-lxc-api.xml
 %{mingw64_datadir}/libvirt/api/libvirt-qemu-api.xml
 
 %{mingw64_datadir}/libvirt/cpu_map.xml
@@ -276,6 +284,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt_iohelper.exe
 %dir %{mingw64_includedir}/libvirt
 %{mingw64_includedir}/libvirt/libvirt.h
 %{mingw64_includedir}/libvirt/virterror.h
+%{mingw64_includedir}/libvirt/libvirt-lxc.h
 %{mingw64_includedir}/libvirt/libvirt-qemu.h
 
 %{mingw64_mandir}/man1/virsh.1*
@@ -285,6 +294,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt_iohelper.exe
 
 %files -n mingw64-libvirt-static
 %{mingw64_libdir}/libvirt.a
+%{mingw64_libdir}/libvirt-lxc.a
 %{mingw64_libdir}/libvirt-qemu.a
 
 
diff --git a/python/Makefile.am b/python/Makefile.am
index 97f21c3..dd69600 100644
--- a/python/Makefile.am
+++ b/python/Makefile.am
@@ -35,6 +35,8 @@ EXTRA_DIST =			\
 	libvirt-override.c	\
 	libvirt-override.py	\
 	libvirt-override-api.xml \
+	libvirt-lxc-override.c	\
+	libvirt-lxc-override-api.xml \
 	libvirt-qemu-override.c	\
 	libvirt-qemu-override-api.xml \
 	$(CLASSES_EXTRA) \
@@ -47,10 +49,13 @@ mylibs = \
 myqemulibs = \
 	$(top_builddir)/src/libvirt-qemu.la \
 	$(top_builddir)/gnulib/lib/libgnu.la
+mylxclibs = \
+	$(top_builddir)/src/libvirt-lxc.la \
+	$(top_builddir)/gnulib/lib/libgnu.la
 
-all-local: libvirt.py libvirt_qemu.py
+all-local: libvirt.py libvirt_qemu.py libvirt_lxc.py
 
-pyexec_LTLIBRARIES = libvirtmod.la libvirtmod_qemu.la
+pyexec_LTLIBRARIES = libvirtmod.la libvirtmod_qemu.la libvirtmod_lxc.la
 
 libvirtmod_la_SOURCES = libvirt-override.c typewrappers.c
 nodist_libvirtmod_la_SOURCES = libvirt.c libvirt.h
@@ -74,6 +79,17 @@ libvirtmod_qemu_la_LDFLAGS = -module -avoid-version -shared -L$(top_builddir)/sr
 libvirtmod_qemu_la_LIBADD = $(myqemulibs) \
 	$(CYGWIN_EXTRA_LIBADD) $(CYGWIN_EXTRA_PYTHON_LIBADD)
 
+libvirtmod_lxc_la_SOURCES = libvirt-lxc-override.c typewrappers.c
+nodist_libvirtmod_lxc_la_SOURCES = libvirt-lxc.c libvirt-lxc.h
+# Python <= 2.4 header files contain a redundant decl, hence we
+# need extra flags here
+libvirtmod_lxc_la_CFLAGS = $(WARN_PYTHON_CFLAGS)
+
+libvirtmod_lxc_la_LDFLAGS = -module -avoid-version -shared -L$(top_builddir)/src/.libs \
+	$(CYGWIN_EXTRA_LDFLAGS)
+libvirtmod_lxc_la_LIBADD = $(mylxclibs) \
+	$(CYGWIN_EXTRA_LIBADD) $(CYGWIN_EXTRA_PYTHON_LIBADD)
+
 GENERATE = generator.py
 API_DESC = $(top_srcdir)/docs/libvirt-api.xml $(srcdir)/libvirt-override-api.xml
 GENERATED= libvirt-export.c \
@@ -87,18 +103,26 @@ QEMU_GENERATED= libvirt-qemu-export.c \
 	   libvirt-qemu.h \
 	   libvirt_qemu.py
 
-$(GENERATE).stamp: $(srcdir)/$(GENERATE) $(API_DESC) $(QEMU_API_DESC)
+LXC_API_DESC = $(top_srcdir)/docs/libvirt-lxc-api.xml $(srcdir)/libvirt-lxc-override-api.xml
+LXC_GENERATED= libvirt-lxc-export.c \
+	   libvirt-lxc.c \
+	   libvirt-lxc.h \
+	   libvirt_lxc.py
+
+$(GENERATE).stamp: $(srcdir)/$(GENERATE) $(API_DESC) $(QEMU_API_DESC) $(LXC_API_DESC)
 	$(AM_V_GEN)$(PYTHON) $(srcdir)/$(GENERATE) $(PYTHON) && \
 	touch $@
 
-$(GENERATED) $(QEMU_GENERATED): $(GENERATE).stamp
+$(GENERATED) $(QEMU_GENERATED) $(LXC_GENERATED): $(GENERATE).stamp
 
 $(libvirtmod_la_OBJECTS): $(GENERATED)
 $(libvirtmod_qemu_la_OBJECTS): $(QEMU_GENERATED)
+$(libvirtmod_lxc_la_OBJECTS): $(LXC_GENERATED)
 
 install-data-local:
 	$(mkinstalldirs) $(DESTDIR)$(pyexecdir)
 	$(INSTALL) -m 0644 libvirt.py $(DESTDIR)$(pyexecdir)
+	$(INSTALL) -m 0644 libvirt_lxc.py $(DESTDIR)$(pyexecdir)
 	$(INSTALL) -m 0644 libvirt_qemu.py $(DESTDIR)$(pyexecdir)
 	$(mkinstalldirs) $(DESTDIR)$(DOCS_DIR)
 	@(for doc in $(DOCS) ; \
@@ -106,9 +130,10 @@ install-data-local:
 
 uninstall-local:
 	rm -f $(DESTDIR)$(pyexecdir)/libvirt.py
+	rm -f $(DESTDIR)$(pyexecdir)/libvirt_lxc.py
 	rm -f $(DESTDIR)$(pyexecdir)/libvirt_qemu.py
 
-CLEANFILES= $(GENERATED) $(QEMU_GENERATED) $(GENERATE).stamp
+CLEANFILES= $(GENERATED) $(QEMU_GENERATED) $(LXC_GENERATED) $(GENERATE).stamp
 
 else
 all:
diff --git a/python/generator.py b/python/generator.py
index e9b9270..902d5d0 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -4,8 +4,10 @@
 #
 
 functions = {}
+lxc_functions = {}
 qemu_functions = {}
 enums = {} # { enumType: { enumConstant: enumValue } }
+lxc_enums = {} # { enumType: { enumConstant: enumValue } }
 qemu_enums = {} # { enumType: { enumConstant: enumValue } }
 
 import os
@@ -123,6 +125,8 @@ class docParser(xml.sax.handler.ContentHandler):
             if (attrs['file'] == "libvirt" or
                 attrs['file'] == "virterror"):
                 enum(attrs['type'],attrs['name'],attrs['value'])
+            elif attrs['file'] == "libvirt-lxc":
+                lxc_enum(attrs['type'],attrs['name'],attrs['value'])
             elif attrs['file'] == "libvirt-qemu":
                 qemu_enum(attrs['type'],attrs['name'],attrs['value'])
 
@@ -138,6 +142,11 @@ class docParser(xml.sax.handler.ContentHandler):
                              self.function_return, self.function_args,
                              self.function_file, self.function_module,
                              self.function_cond)
+                elif self.function_module == "libvirt-lxc":
+                    lxc_function(self.function, self.function_descr,
+                             self.function_return, self.function_args,
+                             self.function_file, self.function_module,
+                             self.function_cond)
                 elif self.function_module == "libvirt-qemu":
                     qemu_function(self.function, self.function_descr,
                              self.function_return, self.function_args,
@@ -148,6 +157,11 @@ class docParser(xml.sax.handler.ContentHandler):
                              self.function_return, self.function_args,
                              self.function_file, self.function_module,
                              self.function_cond)
+                elif self.function_file == "python-lxc":
+                    lxc_function(self.function, self.function_descr,
+                                  self.function_return, self.function_args,
+                                  self.function_file, self.function_module,
+                                  self.function_cond)
                 elif self.function_file == "python-qemu":
                     qemu_function(self.function, self.function_descr,
                                   self.function_return, self.function_args,
@@ -184,6 +198,9 @@ def function(name, desc, ret, args, file, module, cond):
 def qemu_function(name, desc, ret, args, file, module, cond):
     qemu_functions[name] = (desc, ret, args, file, module, cond)
 
+def lxc_function(name, desc, ret, args, file, module, cond):
+    lxc_functions[name] = (desc, ret, args, file, module, cond)
+
 def enum(type, name, value):
     if not enums.has_key(type):
         enums[type] = {}
@@ -208,6 +225,11 @@ def enum(type, name, value):
     if name[-5:] != '_LAST':
         enums[type][name] = value
 
+def lxc_enum(type, name, value):
+    if not lxc_enums.has_key(type):
+        lxc_enums[type] = {}
+    lxc_enums[type][name] = value
+
 def qemu_enum(type, name, value):
     if not qemu_enums.has_key(type):
         qemu_enums[type] = {}
@@ -222,10 +244,12 @@ def qemu_enum(type, name, value):
 #######################################################################
 
 functions_failed = []
+lxc_functions_failed = []
 qemu_functions_failed = []
 functions_skipped = [
     "virConnectListDomains",
 ]
+lxc_functions_skipped = []
 qemu_functions_skipped = []
 
 skipped_modules = {
@@ -430,6 +454,10 @@ skip_impl = (
     'virNodeGetCPUMap',
 )
 
+lxc_skip_impl = (
+    'virDomainLxcOpenNamespace',
+)
+
 qemu_skip_impl = (
     'virDomainQemuMonitorCommand',
     'virDomainQemuAgentCommand',
@@ -501,6 +529,8 @@ skip_function = (
     "virStorageVolGetConnect",
 )
 
+lxc_skip_function = (
+)
 qemu_skip_function = (
     #"virDomainQemuAttach",
 )
@@ -511,6 +541,7 @@ function_skip_python_impl = (
                      # be exposed in bindings
 )
 
+lxc_function_skip_python_impl = ()
 qemu_function_skip_python_impl = ()
 
 function_skip_index_one = (
@@ -521,6 +552,7 @@ def print_function_wrapper(module, name, output, export, include):
     global py_types
     global unknown_types
     global functions
+    global lxc_functions
     global qemu_functions
     global skipped_modules
     global function_skip_python_impl
@@ -528,6 +560,8 @@ def print_function_wrapper(module, name, output, export, include):
     try:
         if module == "libvirt":
             (desc, ret, args, file, mod, cond) = functions[name]
+        if module == "libvirt-lxc":
+            (desc, ret, args, file, mod, cond) = lxc_functions[name]
         if module == "libvirt-qemu":
             (desc, ret, args, file, mod, cond) = qemu_functions[name]
     except:
@@ -543,6 +577,12 @@ def print_function_wrapper(module, name, output, export, include):
         if name in skip_impl:
             # Don't delete the function entry in the caller.
             return 1
+    elif module == "libvirt-lxc":
+        if name in lxc_skip_function:
+            return 0
+        if name in lxc_skip_impl:
+            # Don't delete the function entry in the caller.
+            return 1
     elif module == "libvirt-qemu":
         if name in qemu_skip_function:
             return 0
@@ -643,6 +683,10 @@ def print_function_wrapper(module, name, output, export, include):
         include.write("libvirt_%s(PyObject *self, PyObject *args);\n" % (name));
         export.write("    { (char *)\"%s\", libvirt_%s, METH_VARARGS, NULL },\n" %
                      (name, name))
+    elif module == "libvirt-lxc":
+        include.write("libvirt_lxc_%s(PyObject *self, PyObject *args);\n" % (name));
+        export.write("    { (char *)\"%s\", libvirt_lxc_%s, METH_VARARGS, NULL },\n" %
+                     (name, name))
     elif module == "libvirt-qemu":
         include.write("libvirt_qemu_%s(PyObject *self, PyObject *args);\n" % (name));
         export.write("    { (char *)\"%s\", libvirt_qemu_%s, METH_VARARGS, NULL },\n" %
@@ -666,6 +710,8 @@ def print_function_wrapper(module, name, output, export, include):
     output.write("PyObject *\n")
     if module == "libvirt":
         output.write("libvirt_%s(PyObject *self ATTRIBUTE_UNUSED," % (name))
+    elif module == "libvirt-lxc":
+        output.write("libvirt_lxc_%s(PyObject *self ATTRIBUTE_UNUSED," % (name))
     elif module == "libvirt-qemu":
         output.write("libvirt_qemu_%s(PyObject *self ATTRIBUTE_UNUSED," % (name))
     output.write(" PyObject *args")
@@ -698,6 +744,9 @@ def print_function_wrapper(module, name, output, export, include):
     if module == "libvirt":
         if name in function_skip_python_impl:
             return 0
+    elif module == "libvirt-lxc":
+        if name in lxc_function_skip_python_impl:
+            return 0
     elif module == "libvirt-qemu":
         if name in qemu_function_skip_python_impl:
             return 0
@@ -708,7 +757,7 @@ def buildStubs(module):
     global py_return_types
     global unknown_types
 
-    if module not in ["libvirt", "libvirt-qemu"]:
+    if module not in ["libvirt", "libvirt-qemu", "libvirt-lxc"]:
         print "ERROR: Unknown module type: %s" % module
         return None
 
@@ -716,6 +765,10 @@ def buildStubs(module):
         funcs = functions
         funcs_failed = functions_failed
         funcs_skipped = functions_skipped
+    elif module == "libvirt-lxc":
+        funcs = lxc_functions
+        funcs_failed = lxc_functions_failed
+        funcs_skipped = functions_skipped
     elif module == "libvirt-qemu":
         funcs = qemu_functions
         funcs_failed = qemu_functions_failed
@@ -1111,6 +1164,8 @@ def functionCompare(info1, info2):
 def writeDoc(module, name, args, indent, output):
      if module == "libvirt":
          funcs = functions
+     elif module == "libvirt-lxc":
+         funcs = lxc_functions
      elif module == "libvirt-qemu":
          funcs = qemu_functions
      if funcs[name][0] is None or funcs[name][0] == "":
@@ -1762,11 +1817,126 @@ def qemuBuildWrappers(module):
     fd.close()
 
 
+def lxcBuildWrappers(module):
+    global lxc_functions
+
+    if not module == "libvirt-lxc":
+        print "ERROR: only libvirt-lxc is supported"
+        return None
+
+    extra_file = os.path.join(srcPref, "%s-override.py" % module)
+    extra = None
+
+    fd = open("libvirt_lxc.py", "w")
+
+    if os.path.exists(extra_file):
+        extra = open(extra_file, "r")
+    fd.write("#! " + python + " -i\n")
+    fd.write("#\n")
+    fd.write("# WARNING WARNING WARNING WARNING\n")
+    fd.write("#\n")
+    fd.write("# This file is automatically written by generator.py. Any changes\n")
+    fd.write("# made here will be lost.\n")
+    fd.write("#\n")
+    fd.write("# To change the manually written methods edit " + module + "-override.py\n")
+    fd.write("# To change the automatically written methods edit generator.py\n")
+    fd.write("#\n")
+    fd.write("# WARNING WARNING WARNING WARNING\n")
+    fd.write("#\n")
+    if extra != None:
+        fd.writelines(extra.readlines())
+    fd.write("#\n")
+    fd.write("# WARNING WARNING WARNING WARNING\n")
+    fd.write("#\n")
+    fd.write("# Automatically written part of python bindings for libvirt\n")
+    fd.write("#\n")
+    fd.write("# WARNING WARNING WARNING WARNING\n")
+    if extra != None:
+        extra.close()
+
+    fd.write("try:\n")
+    fd.write("    import libvirtmod_lxc\n")
+    fd.write("except ImportError, lib_e:\n")
+    fd.write("    try:\n")
+    fd.write("        import cygvirtmod_lxc as libvirtmod_lxc\n")
+    fd.write("    except ImportError, cyg_e:\n")
+    fd.write("        if str(cyg_e).count(\"No module named\"):\n")
+    fd.write("            raise lib_e\n\n")
+
+    fd.write("import libvirt\n\n");
+    fd.write("#\n# Functions from module %s\n#\n\n" % module)
+    #
+    # Generate functions directly, no classes
+    #
+    for name in lxc_functions.keys():
+        func = nameFixup(name, 'None', None, None)
+        (desc, ret, args, file, mod, cond) = lxc_functions[name]
+        fd.write("def %s(" % func)
+        n = 0
+        for arg in args:
+            if n != 0:
+                fd.write(", ")
+            fd.write("%s" % arg[0])
+            n = n + 1
+        fd.write("):\n")
+        writeDoc(module, name, args, '    ', fd);
+
+        if ret[0] != "void":
+            fd.write("    ret = ");
+        else:
+            fd.write("    ");
+        fd.write("libvirtmod_lxc.%s(" % name)
+        n = 0
+
+        conn = None
+
+        for arg in args:
+            if arg[1] == "virConnectPtr":
+                conn = arg[0]
+
+            if n != 0:
+                fd.write(", ");
+            if arg[1] in ["virDomainPtr", "virConnectPtr"]:
+                # FIXME: This might have problem if the function
+                # has multiple args which are objects.
+                fd.write("%s.%s" % (arg[0], "_o"))
+            else:
+                fd.write("%s" % arg[0])
+            n = n + 1
+        fd.write(")\n");
+
+        if ret[0] != "void":
+            fd.write("    if ret is None: raise libvirt.libvirtError('" + name + "() failed')\n")
+            if ret[0] == "virDomainPtr":
+                fd.write("    __tmp = virDomain(" + conn + ",_obj=ret)\n")
+                fd.write("    return __tmp\n")
+            else:
+                fd.write("    return ret\n")
+
+        fd.write("\n")
+
+    #
+    # Generate enum constants
+    #
+    for type,enum in lxc_enums.items():
+        fd.write("# %s\n" % type)
+        items = enum.items()
+        items.sort(lambda i1,i2: cmp(long(i1[1]),long(i2[1])))
+        for name,value in items:
+            fd.write("%s = %s\n" % (name,value))
+        fd.write("\n");
+
+    fd.close()
+
+
 quiet = 0
 if buildStubs("libvirt") < 0:
     sys.exit(1)
+if buildStubs("libvirt-lxc") < 0:
+    sys.exit(1)
 if buildStubs("libvirt-qemu") < 0:
     sys.exit(1)
 buildWrappers("libvirt")
+lxcBuildWrappers("libvirt-lxc")
 qemuBuildWrappers("libvirt-qemu")
 sys.exit(0)
diff --git a/python/libvirt-lxc-override-api.xml b/python/libvirt-lxc-override-api.xml
new file mode 100644
index 0000000..db0d45d
--- /dev/null
+++ b/python/libvirt-lxc-override-api.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<api name='libvir-lxc-python'>
+  <symbols>
+    <function name='virDomainLxcOpenNamespace' file='python-lxc'>
+      <info><![CDATA[This API is LXC specific, so it will only work with hypervisor
+connections to the LXC driver.
+
+Open the namespaces associated with the container @domain
+and return a list of file descriptors associated with the
+container.
+
+The returned file descriptors are intended to be used with
+the setns() system call.]]></info>
+      <return type='int' info='the list of open file descriptors, or -1 on error'/>
+      <arg name='domain' type='virDomainPtr' info='a domain object'/>
+      <arg name='flags' type='unsigned int' info='currently unused, pass 0'/>
+    </function>
+  </symbols>
+</api>
diff --git a/python/libvirt-lxc-override.c b/python/libvirt-lxc-override.c
new file mode 100644
index 0000000..33c9c0a
--- /dev/null
+++ b/python/libvirt-lxc-override.c
@@ -0,0 +1,141 @@
+/*
+ * libvir.c: this modules implements the main part of the glue of the
+ *           libvir library and the Python interpreter. It provides the
+ *           entry points where an automatically generated stub is
+ *           unpractical
+ *
+ * Copyright (C) 2011-2012 Red Hat, Inc.
+ *
+ * Daniel Veillard <veillard at redhat.com>
+ */
+
+#include <config.h>
+
+/* Horrible kludge to work around even more horrible name-space pollution
+   via Python.h.  That file includes /usr/include/python2.5/pyconfig*.h,
+   which has over 180 autoconf-style HAVE_* definitions.  Shame on them.  */
+#undef HAVE_PTHREAD_H
+
+#include <Python.h>
+#include "libvirt/libvirt-lxc.h"
+#include "libvirt/virterror.h"
+#include "typewrappers.h"
+#include "libvirt-lxc.h"
+#include "viralloc.h"
+#include "virfile.h"
+
+#ifndef __CYGWIN__
+extern void initlibvirtmod_lxc(void);
+#else
+extern void initcygvirtmod_lxc(void);
+#endif
+
+#if 0
+# define DEBUG_ERROR 1
+#endif
+
+#if DEBUG_ERROR
+# define DEBUG(fmt, ...)            \
+   printf(fmt, __VA_ARGS__)
+#else
+# define DEBUG(fmt, ...)            \
+   do {} while (0)
+#endif
+
+/* The two-statement sequence "Py_INCREF(Py_None); return Py_None;"
+   is so common that we encapsulate it here.  Now, each use is simply
+   return VIR_PY_NONE;  */
+#define VIR_PY_NONE (Py_INCREF (Py_None), Py_None)
+#define VIR_PY_INT_FAIL (libvirt_intWrap(-1))
+#define VIR_PY_INT_SUCCESS (libvirt_intWrap(0))
+
+/************************************************************************
+ *									*
+ *		Statistics						*
+ *									*
+ ************************************************************************/
+
+static PyObject *
+libvirt_lxc_virDomainLxcOpenNamespace(PyObject *self ATTRIBUTE_UNUSED,
+                                      PyObject *args) {
+    PyObject *py_retval;
+    virDomainPtr domain;
+    PyObject *pyobj_domain;
+    unsigned int flags;
+    int c_retval;
+    int *fdlist = NULL;
+    int i;
+
+    if (!PyArg_ParseTuple(args, (char *)"Oi:virDomainLxcOpenNamespace",
+                          &pyobj_domain, &flags))
+        return NULL;
+    domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+    if (domain == NULL)
+        return VIR_PY_NONE;
+    LIBVIRT_BEGIN_ALLOW_THREADS;
+    c_retval = virDomainLxcOpenNamespace(domain, &fdlist, flags);
+    LIBVIRT_END_ALLOW_THREADS;
+
+    if (c_retval < 0)
+        return VIR_PY_NONE;
+
+    py_retval = PyList_New(c_retval);
+    for (i = 0 ; i < c_retval ; i++) {
+        PyObject *item = NULL;
+
+        if ((item = PyInt_FromLong(fdlist[i])) == NULL)
+            goto error;
+
+        if (PyList_Append(py_retval, item) < 0) {
+            Py_DECREF(item);
+            goto error;
+        }
+    }
+    return py_retval;
+
+error:
+    for (i = 0 ; i < c_retval ; i++) {
+        VIR_FORCE_CLOSE(fdlist[i]);
+    }
+    VIR_FREE(fdlist);
+    return VIR_PY_NONE;
+}
+/************************************************************************
+ *									*
+ *			The registration stuff				*
+ *									*
+ ************************************************************************/
+static PyMethodDef libvirtLxcMethods[] = {
+#include "libvirt-lxc-export.c"
+    {(char *) "virDomainLxcOpenNamespace", libvirt_lxc_virDomainLxcOpenNamespace, METH_VARARGS, NULL},
+    {NULL, NULL, 0, NULL}
+};
+
+void
+#ifndef __CYGWIN__
+initlibvirtmod_lxc
+#else
+initcygvirtmod_lxc
+#endif
+  (void)
+{
+    static int initialized = 0;
+
+    if (initialized != 0)
+        return;
+
+    if (virInitialize() < 0)
+        return;
+
+    /* initialize the python extension module */
+    Py_InitModule((char *)
+#ifndef __CYGWIN__
+                  "libvirtmod_lxc"
+#else
+                  "cygvirtmod_lxc"
+#endif
+                  , libvirtLxcMethods);
+
+    initialized = 1;
+}
diff --git a/src/Makefile.am b/src/Makefile.am
index 494c184..13b7e30 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -36,7 +36,7 @@ if WITH_NETWORK
 UUID=$(shell uuidgen 2>/dev/null)
 endif
 
-lib_LTLIBRARIES = libvirt.la libvirt-qemu.la
+lib_LTLIBRARIES = libvirt.la libvirt-qemu.la libvirt-lxc.la
 
 moddir = $(libdir)/libvirt/connection-driver
 mod_LTLIBRARIES =
@@ -1480,6 +1480,13 @@ libvirt_qemu.def: $(srcdir)/libvirt_qemu.syms
 	chmod a-w $@-tmp && \
 	mv $@-tmp libvirt_qemu.def
 
+libvirt_lxc.def: $(srcdir)/libvirt_lxc.syms
+	$(AM_V_GEN)rm -f -- $@-tmp $@ ; \
+	printf 'EXPORTS\n' > $@-tmp && \
+	sed -e '/^$$/d; /#/d; /:/d; /}/d; /\*/d; /LIBVIRT_/d; s/[	 ]*\(.*\)\;/    \1/g' $^ >> $@-tmp && \
+	chmod a-w $@-tmp && \
+	mv $@-tmp libvirt_lxc.def
+
 # Empty source list - it merely links a bunch of convenience libs together
 libvirt_la_SOURCES =
 libvirt_la_LDFLAGS = $(VERSION_SCRIPT_FLAGS)$(LIBVIRT_SYMBOL_FILE) \
@@ -1566,6 +1573,15 @@ libvirt_qemu_la_CFLAGS = $(AM_CFLAGS)
 libvirt_qemu_la_LIBADD = libvirt.la $(CYGWIN_EXTRA_LIBADD)
 EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE)
 
+libvirt_lxc_la_SOURCES = libvirt-lxc.c
+libvirt_lxc_la_LDFLAGS = $(VERSION_SCRIPT_FLAGS)$(LIBVIRT_LXC_SYMBOL_FILE) \
+			  -version-info $(LIBVIRT_VERSION_INFO) \
+			  $(CYGWIN_EXTRA_LDFLAGS) $(MINGW_EXTRA_LDFLAGS) \
+			  $(AM_LDFLAGS)
+libvirt_lxc_la_CFLAGS = $(AM_CFLAGS)
+libvirt_lxc_la_LIBADD = libvirt.la $(CYGWIN_EXTRA_LIBADD)
+EXTRA_DIST += $(LIBVIRT_LXC_SYMBOL_FILE)
+
 lockdriverdir = $(libdir)/libvirt/lock-driver
 lockdriver_LTLIBRARIES =
 
diff --git a/src/driver.h b/src/driver.h
index 64d652f..80f06bd 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -915,6 +915,11 @@ typedef int
                           unsigned long long minimum,
                           unsigned int flags);
 
+typedef int
+    (*virDrvDomainLxcOpenNamespace)(virDomainPtr dom,
+                                    int **fdlist,
+                                    unsigned int flags);
+
 /**
  * _virDriver:
  *
@@ -1107,6 +1112,7 @@ struct _virDriver {
     virDrvNodeGetCPUMap                 nodeGetCPUMap;
     virDrvDomainFSTrim                  domainFSTrim;
     virDrvDomainSendProcessSignal       domainSendProcessSignal;
+    virDrvDomainLxcOpenNamespace        domainLxcOpenNamespace;
 };
 
 typedef int
diff --git a/src/internal.h b/src/internal.h
index 8d96660..ebc91c7 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -40,6 +40,7 @@
 # define N_(str) str
 
 # include "libvirt/libvirt.h"
+# include "libvirt/libvirt-lxc.h"
 # include "libvirt/libvirt-qemu.h"
 # include "libvirt/virterror.h"
 
diff --git a/src/libvirt-lxc.c b/src/libvirt-lxc.c
new file mode 100644
index 0000000..0de498b
--- /dev/null
+++ b/src/libvirt-lxc.c
@@ -0,0 +1,165 @@
+/*
+ * libvirt-lxc.c: Interfaces for the libvirt library to handle lxc-specific
+ *                 APIs.
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#include <config.h>
+
+#include "viralloc.h"
+#include "virerror.h"
+#include "virfile.h"
+#include "virlog.h"
+#include "virprocess.h"
+#include "datatypes.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+#define virLibConnError(conn, error, info)                               \
+    virReportErrorHelper(VIR_FROM_NONE, error, NULL, __FUNCTION__,       \
+                         __LINE__, info)
+
+#define virLibDomainError(domain, error, info)                          \
+    virReportErrorHelper(VIR_FROM_DOM, error, NULL, __FUNCTION__,       \
+                         __LINE__, info)
+
+/**
+ * virDomainLxcOpenNamespace:
+ * @domain: a domain object
+ * @fdlist: pointer to an array to be filled with FDs
+ * @flags: currently unused, pass 0
+ *
+ * This API is LXC specific, so it will only work with hypervisor
+ * connections to the LXC driver.
+ *
+ * Open the namespaces associated with the container @domain.
+ * The @fdlist array will be allocated to a suitable size,
+ * and filled with file descriptors for the namespaces. It
+ * is the caller's responsibility to close the file descriptors
+ *
+ * The returned file descriptors are intended to be used with
+ * the setns() system call.
+ *
+ * Returns the number of opened file descriptors, or -1 on error
+ */
+int
+virDomainLxcOpenNamespace(virDomainPtr domain,
+                          int **fdlist,
+                          unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DEBUG("domain=%p, fdlist=%p flags=%x",
+              domain, fdlist, flags);
+
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        virDispatchError(NULL);
+        return -1;
+    }
+
+    conn = domain->conn;
+
+    virCheckNonNullArgGoto(fdlist, error);
+
+    if (conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainLxcOpenNamespace) {
+        int ret;
+        ret = conn->driver->domainLxcOpenNamespace(domain,
+                                                   fdlist,
+                                                   flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainLxcEnterNamespace:
+ * @domain: a domain object
+ * @nfdlist: number of FDs in @fdlist
+ * @fdlist: list of namespace file descriptors
+ * @noldfdlist: filled with number of old FDs
+ * @oldfdlist: pointer to hold list of old namespace file descriptors
+ * @flags: currently unused, pass 0
+ *
+ * This API is LXC specific, so it will only work with hypervisor
+ * connections to the LXC driver.
+ *
+ * Attaches the process to the namespaces associated
+ * with the FDs in @fdlist
+ *
+ * If @oldfdlist is non-NULL, it will be populated with file
+ * descriptors representing the old namespace. This allows
+ * the caller to switch back to its current namespace later
+ *
+ * Returns 0 on success, -1 on error
+ */
+int
+virDomainLxcEnterNamespace(virDomainPtr domain,
+                           unsigned int nfdlist,
+                           int *fdlist,
+                           unsigned int *noldfdlist,
+                           int **oldfdlist,
+                           unsigned int flags)
+{
+    int i;
+
+    virCheckFlags(0, -1);
+
+    if (noldfdlist && oldfdlist) {
+        size_t nfds;
+        if (virProcessGetNamespaces(getpid(),
+                                    &nfds,
+                                    oldfdlist) < 0)
+            goto error;
+        *noldfdlist = nfds;
+    }
+
+    if (virProcessSetNamespaces(nfdlist, fdlist) < 0) {
+        if (oldfdlist && noldfdlist) {
+            for (i = 0 ; i < *noldfdlist ; i++) {
+                VIR_FORCE_CLOSE((*oldfdlist)[i]);
+            }
+            VIR_FREE(*oldfdlist);
+            *noldfdlist = 0;
+        }
+        goto error;
+    }
+
+    return 0;
+
+error:
+    virDispatchError(domain->conn);
+    return -1;
+}
diff --git a/src/libvirt_lxc.syms b/src/libvirt_lxc.syms
new file mode 100644
index 0000000..b5be18b
--- /dev/null
+++ b/src/libvirt_lxc.syms
@@ -0,0 +1,17 @@
+#
+# Officially exported symbols, for which header
+# file definitions are installed in /usr/include/libvirt
+# from libvirt-lxc.h
+#
+# Versions here are *fixed* to match the libvirt version
+# at which the symbol was introduced. This ensures that
+# a new client app requiring symbol foo() can't accidentally
+# run with old libvirt-lxc.so not providing foo() - the global
+# soname version info can't enforce this since we never
+# change the soname
+#
+LIBVIRT_LXC_1.0.2 {
+    global:
+        virDomainLxcEnterNamespace;
+        virDomainLxcOpenNamespace;
+};
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 8050ce6..025c35f 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -4544,6 +4544,7 @@ static virDriver lxcDriver = {
     .domainShutdown = lxcDomainShutdown, /* 1.0.1 */
     .domainShutdownFlags = lxcDomainShutdownFlags, /* 1.0.1 */
     .domainReboot = lxcDomainReboot, /* 1.0.1 */
+    .domainLxcOpenNamespace = lxcDomainOpenNamespace, /* 1.0.2 */
 };
 
 static virStateDriver lxcStateDriver = {
diff --git a/tools/virsh.c b/tools/virsh.c
index 283194a..51615ec 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -62,6 +62,7 @@
 #include "viralloc.h"
 #include "virxml.h"
 #include "libvirt/libvirt-qemu.h"
+#include "libvirt/libvirt-lxc.h"
 #include "virfile.h"
 #include "configmake.h"
 #include "virthread.h"
-- 
1.7.11.7




More information about the libvir-list mailing list