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

dlezcano
2006-06-09T21:06:34Z

[-- Attachment #1: net_ns.patch --]
[-- Type: text/plain, Size: 11607 bytes --]

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 <dlezcano@fr.ibm.com>
--
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 <dlezcano@fr.ibm.com>
+ *
+ * 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";

--