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 netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to