[RFC] [patch 1/6] [Network namespace] Network namespace structure

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds to the nsproxy the network namespace and a set of
functions to unshare it. The network namespace structure should be
filled later with the identified network ressources needed for more
isolation.

Replace-Subject: [Network namespace] Network namespace structure
Signed-off-by: Daniel Lezcano <[email protected]> 
--
 include/linux/init_task.h |    2 
 include/linux/net_ns.h    |   59 ++++++++++++++++++++++++++++
 include/linux/nsproxy.h   |    2 
 include/linux/sched.h     |    1 
 init/version.c            |    8 +++
 kernel/fork.c             |   24 +++++++++--
 kernel/nsproxy.c          |   38 +++++++++++-------
 net/Kconfig               |    9 ++++
 net/Makefile              |    1 
 net/net_ns.c              |   96 ++++++++++++++++++++++++++++++++++++++++++++++
 10 files changed, 222 insertions(+), 18 deletions(-)

Index: 2.6-mm/include/linux/net_ns.h
===================================================================
--- /dev/null
+++ 2.6-mm/include/linux/net_ns.h
@@ -0,0 +1,59 @@
+#ifndef _LINUX_NET_NS_H
+#define _LINUX_NET_NS_H
+
+#include <linux/kref.h>
+#include <linux/sched.h>
+#include <linux/nsproxy.h>
+
+struct net_namespace {
+	struct kref kref;
+};
+
+extern struct net_namespace init_net_ns;
+
+#ifdef CONFIG_NET_NS
+
+extern int unshare_network(unsigned long unshare_flags,
+			   struct net_namespace **new_net);
+
+extern int copy_network(int flags, struct task_struct *tsk);
+
+static inline void get_net_ns(struct net_namespace *ns)
+{
+	kref_get(&ns->kref);
+}
+
+void free_net_ns(struct kref *kref);
+
+static inline void put_net_ns(struct net_namespace *ns)
+{
+	kref_put(&ns->kref, free_net_ns);
+}
+
+static inline void exit_network(struct task_struct *p)
+{
+	struct net_namespace *net_ns = p->nsproxy->net_ns;
+	if (net_ns)
+		put_net_ns(net_ns);
+}
+#else /* !CONFIG_NET_NS */
+static inline int unshare_network(unsigned long unshare_flags,
+				  struct net_namespace **new_net)
+{
+	return -EINVAL;
+}
+static inline int copy_network(int flags, struct task_struct *tsk)
+{
+	return 0;
+}
+static inline void get_net_ns(struct net_namespace *ns) {}
+static inline void put_net_ns(struct net_namespace *ns) {}
+static inline void exit_network(struct task_struct *p) {}
+#endif /* CONFIG_NET_NS */
+
+static inline struct net_namespace *net_ns(void)
+{
+	return current->nsproxy->net_ns;
+}
+
+#endif
Index: 2.6-mm/net/net_ns.c
===================================================================
--- /dev/null
+++ 2.6-mm/net/net_ns.c
@@ -0,0 +1,96 @@
+/*
+ *  net_ns.c - adds support for network namespace
+ *
+ *  Copyright (C) 2006 IBM
+ *
+ *  Author: Daniel Lezcano <[email protected]>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation, version 2 of the
+ *     License.
+ */
+
+#include <linux/net_ns.h>
+#include <linux/module.h>
+
+/*
+ * Clone a new ns copying an original, setting refcount to 1
+ * Cloned process will have
+ * @old_ns: namespace to clone
+ * Return NULL on error (failure to kmalloc), new ns otherwise
+ */
+struct net_namespace *clone_net_ns(struct net_namespace *old_ns)
+{
+	struct net_namespace *new_ns;
+
+	new_ns = kmalloc(sizeof(*new_ns), GFP_KERNEL);
+ 	if (!new_ns)
+ 		return NULL;
+ 	kref_init(&new_ns->kref);
+	return new_ns;
+}
+
+/*
+ * unshare the current process' network namespace.
+ * called only in sys_unshare()
+ */
+int unshare_network(unsigned long unshare_flags,
+		    struct net_namespace **new_net)
+{
+ 	if (!(unshare_flags & CLONE_NEWNET))
+ 		return 0;
+
+ 	if (!capable(CAP_SYS_ADMIN))
+ 		return -EPERM;
+
+ 	*new_net = clone_net_ns(current->nsproxy->net_ns);
+ 	if (!*new_net)
+ 		return -ENOMEM;
+
+	return 0;
+}
+
+/*
+ * Copy task tsk's network namespace, or clone it if flags specifies
+ * CLONE_NEWNET.  In latter case, changes to the network ressources of
+ * this process won't be seen by parent, and vice versa.
+ */
+int copy_network(int flags, struct task_struct *tsk)
+{
+	struct net_namespace *old_ns = tsk->nsproxy->net_ns;
+	struct net_namespace *new_ns;
+	int err = 0;
+
+	if (!old_ns)
+		return 0;
+
+	get_net_ns(old_ns);
+
+	if (!(flags & CLONE_NEWNET))
+		return 0;
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		err = -EPERM;
+		goto out;
+	}
+
+	new_ns = clone_net_ns(old_ns);
+	if (!new_ns) {
+		err = -ENOMEM;
+		goto out;
+	}
+	tsk->nsproxy->net_ns = new_ns;
+
+out:
+	put_net_ns(old_ns);
+	return err;
+}
+
+void free_net_ns(struct kref *kref)
+{
+	struct net_namespace *ns;
+
+	ns = container_of(kref, struct net_namespace, kref);
+	kfree(ns);
+}
Index: 2.6-mm/include/linux/nsproxy.h
===================================================================
--- 2.6-mm.orig/include/linux/nsproxy.h
+++ 2.6-mm/include/linux/nsproxy.h
@@ -6,6 +6,7 @@
 
 struct namespace;
 struct uts_namespace;
+struct net_namespace;
 
 /*
  * A structure to contain pointers to all per-process
@@ -23,6 +24,7 @@ struct nsproxy {
 	atomic_t count;
 	spinlock_t nslock;
 	struct uts_namespace *uts_ns;
+	struct net_namespace *net_ns;
 	struct namespace *namespace;
 };
 extern struct nsproxy init_nsproxy;
Index: 2.6-mm/kernel/nsproxy.c
===================================================================
--- 2.6-mm.orig/kernel/nsproxy.c
+++ 2.6-mm/kernel/nsproxy.c
@@ -14,6 +14,7 @@
 #include <linux/nsproxy.h>
 #include <linux/namespace.h>
 #include <linux/utsname.h>
+#include <linux/net_ns.h>
 
 static inline void get_nsproxy(struct nsproxy *ns)
 {
@@ -59,6 +60,8 @@ struct nsproxy *dup_namespaces(struct ns
 			get_namespace(ns->namespace);
 		if (ns->uts_ns)
 			get_uts_ns(ns->uts_ns);
+		if (ns->net_ns)
+			get_net_ns(ns->net_ns);
 	}
 
 	return ns;
@@ -79,7 +82,7 @@ int copy_namespaces(int flags, struct ta
 
 	get_nsproxy(old_ns);
 
-	if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS)))
+	if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWNET)))
 		return 0;
 
 	new_ns = clone_namespaces(old_ns);
@@ -91,21 +94,28 @@ int copy_namespaces(int flags, struct ta
 	tsk->nsproxy = new_ns;
 
 	err = copy_namespace(flags, tsk);
-	if (err) {
-		tsk->nsproxy = old_ns;
-		put_nsproxy(new_ns);
-		goto out;
-	}
+	if (err)
+		goto bad_copy_namespace;
 
 	err = copy_utsname(flags, tsk);
-	if (err) {
-		if (new_ns->namespace)
-			put_namespace(new_ns->namespace);
-		tsk->nsproxy = old_ns;
-		put_nsproxy(new_ns);
-		goto out;
-	}
+	if (err)
+		goto bad_copy_utsname;
 
+  	err = copy_network(flags, tsk);
+  	if (err)
+ 		goto bad_copy_network;
+
+  	goto out;
+
+bad_copy_network:
+	if (new_ns->uts_ns)
+		put_uts_ns(new_ns->uts_ns);
+bad_copy_utsname:
+	if (new_ns->namespace)
+		put_namespace(new_ns->namespace);
+bad_copy_namespace:
+	tsk->nsproxy = old_ns;
+	put_nsproxy(new_ns);
 out:
 	put_nsproxy(old_ns);
 	return err;
@@ -117,5 +127,7 @@ void free_nsproxy(struct nsproxy *ns)
 			put_namespace(ns->namespace);
 		if (ns->uts_ns)
 			put_uts_ns(ns->uts_ns);
+		if (ns->net_ns)
+			put_net_ns(ns->net_ns);
 		kfree(ns);
 }
Index: 2.6-mm/include/linux/sched.h
===================================================================
--- 2.6-mm.orig/include/linux/sched.h
+++ 2.6-mm/include/linux/sched.h
@@ -25,6 +25,7 @@
 #define CLONE_CHILD_SETTID	0x01000000	/* set the TID in the child */
 #define CLONE_STOPPED		0x02000000	/* Start in stopped state */
 #define CLONE_NEWUTS		0x04000000	/* New utsname group? */
+#define CLONE_NEWNET		0x08000000	/* New network namespace */
 
 /*
  * Scheduling policies
Index: 2.6-mm/net/Kconfig
===================================================================
--- 2.6-mm.orig/net/Kconfig
+++ 2.6-mm/net/Kconfig
@@ -60,6 +60,15 @@ config INET
 
 	  Short answer: say Y.
 
+config NET_NS
+	bool "Network namespaces"
+	depends on NET
+	default n
+	---help---
+	  Support for network namespaces.  This allows containers, i.e.
+	  vservers, to use network namespaces to provide isolated
+	  network for different servers.  If unsure, say N.
+
 if INET
 source "net/ipv4/Kconfig"
 source "net/ipv6/Kconfig"
Index: 2.6-mm/net/Makefile
===================================================================
--- 2.6-mm.orig/net/Makefile
+++ 2.6-mm/net/Makefile
@@ -50,3 +50,4 @@ obj-$(CONFIG_TIPC)		+= tipc/
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)		+= sysctl_net.o
 endif
+obj-$(CONFIG_NET_NS)            += net_ns.o
Index: 2.6-mm/include/linux/init_task.h
===================================================================
--- 2.6-mm.orig/include/linux/init_task.h
+++ 2.6-mm/include/linux/init_task.h
@@ -4,6 +4,7 @@
 #include <linux/file.h>
 #include <linux/rcupdate.h>
 #include <linux/utsname.h>
+#include <linux/net_ns.h>
 #include <linux/interrupt.h>
 
 #define INIT_FDTABLE \
@@ -73,6 +74,7 @@ extern struct nsproxy init_nsproxy;
 	.count		= ATOMIC_INIT(1),				\
 	.nslock		= SPIN_LOCK_UNLOCKED,				\
 	.uts_ns		= &init_uts_ns,					\
+	.net_ns         = &init_net_ns,                                 \
 	.namespace	= NULL,						\
 }
 
Index: 2.6-mm/kernel/fork.c
===================================================================
--- 2.6-mm.orig/kernel/fork.c
+++ 2.6-mm/kernel/fork.c
@@ -1592,13 +1592,15 @@ asmlinkage long sys_unshare(unsigned lon
 	struct sem_undo_list *new_ulist = NULL;
 	struct nsproxy *new_nsproxy = NULL, *old_nsproxy = NULL;
 	struct uts_namespace *uts, *new_uts = NULL;
+	struct net_namespace *net, *new_net = NULL;
 
 	check_unshare_flags(&unshare_flags);
 
 	/* Return -EINVAL for all unsupported flags */
 	err = -EINVAL;
 	if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
-				CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|CLONE_NEWUTS))
+				CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|CLONE_NEWUTS|
+			        CLONE_NEWNET))
 		goto bad_unshare_out;
 
 	if ((err = unshare_thread(unshare_flags)))
@@ -1617,18 +1619,20 @@ asmlinkage long sys_unshare(unsigned lon
 		goto bad_unshare_cleanup_fd;
 	if ((err = unshare_utsname(unshare_flags, &new_uts)))
 		goto bad_unshare_cleanup_semundo;
+ 	if ((err = unshare_network(unshare_flags, &new_net)))
+ 		goto bad_unshare_cleanup_utsname;
 
-	if (new_ns || new_uts) {
+	if (new_ns || new_uts || new_net) {
 		old_nsproxy = current->nsproxy;
 		new_nsproxy = dup_namespaces(old_nsproxy);
 		if (!new_nsproxy) {
 			err = -ENOMEM;
-			goto bad_unshare_cleanup_uts;
+			goto bad_unshare_cleanup_net;
 		}
 	}
 
 	if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist ||
-				new_uts) {
+				new_uts || new_net) {
 
 		task_lock(current);
 
@@ -1676,13 +1680,23 @@ asmlinkage long sys_unshare(unsigned lon
 			new_uts = uts;
 		}
 
+ 		if (new_net) {
+ 			net = current->nsproxy->net_ns;
+ 			current->nsproxy->net_ns = new_net;
+			new_net = net;
+ 		}
+
 		task_unlock(current);
 	}
 
 	if (new_nsproxy)
 		put_nsproxy(new_nsproxy);
 
-bad_unshare_cleanup_uts:
+bad_unshare_cleanup_net:
+	if (new_net)
+		put_net_ns(new_net);
+
+bad_unshare_cleanup_utsname:
 	if (new_uts)
 		put_uts_ns(new_uts);
 
Index: 2.6-mm/init/version.c
===================================================================
--- 2.6-mm.orig/init/version.c
+++ 2.6-mm/init/version.c
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/uts.h>
 #include <linux/utsname.h>
+#include <linux/net_ns.h>
 #include <linux/version.h>
 #include <linux/sched.h>
 
@@ -33,6 +34,13 @@ struct uts_namespace init_uts_ns = {
 };
 EXPORT_SYMBOL_GPL(init_uts_ns);
 
+struct net_namespace init_net_ns = {
+	.kref = {
+		.refcount	= ATOMIC_INIT(2),
+	},
+};
+EXPORT_SYMBOL_GPL(init_net_ns);
+
 const char linux_banner[] =
 	"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
 	LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";

--
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux