CONFIG_NET_NS and net_namespace structure are introduced.
List of network devices is made per-namespace.
Each namespace gets its own loopback device.

Task's net_namespace pointer is not incorporated into nsproxy structure,
since current namespace changes temporarily for processing of packets
in softirq.

Signed-off-by: Andrey Savochkin <[EMAIL PROTECTED]>
---
 drivers/net/loopback.c    |   70 +++++++++++--------
 include/linux/init_task.h |    9 ++
 include/linux/net_ns.h    |   88 ++++++++++++++++++++++++
 include/linux/netdevice.h |   20 ++++-
 include/linux/nsproxy.h   |    3 
 include/linux/sched.h     |    3 
 kernel/nsproxy.c          |   14 +++
 net/Kconfig               |    7 +
 net/core/dev.c            |  162 +++++++++++++++++++++++++++++++++++++++++++++-
 net/core/net-sysfs.c      |   24 ++++++
 net/ipv4/devinet.c        |    2 
 net/ipv6/addrconf.c       |    2 
 net/ipv6/route.c          |    3 
 13 files changed, 371 insertions, 36 deletions

--- ./drivers/net/loopback.c.venshd     Wed Jun 21 18:50:39 2006
+++ ./drivers/net/loopback.c    Fri Jun 23 11:48:09 2006
@@ -196,42 +196,56 @@ static struct ethtool_ops loopback_ethto
        .set_tso                = ethtool_op_set_tso,
 };
 
-struct net_device loopback_dev = {
-       .name                   = "lo",
-       .mtu                    = (16 * 1024) + 20 + 20 + 12,
-       .hard_start_xmit        = loopback_xmit,
-       .hard_header            = eth_header,
-       .hard_header_cache      = eth_header_cache,
-       .header_cache_update    = eth_header_cache_update,
-       .hard_header_len        = ETH_HLEN,     /* 14   */
-       .addr_len               = ETH_ALEN,     /* 6    */
-       .tx_queue_len           = 0,
-       .type                   = ARPHRD_LOOPBACK,      /* 0x0001*/
-       .rebuild_header         = eth_rebuild_header,
-       .flags                  = IFF_LOOPBACK,
-       .features               = NETIF_F_SG | NETIF_F_FRAGLIST
+struct net_device loopback_dev_static;
+EXPORT_SYMBOL(loopback_dev_static);
+
+void loopback_dev_dtor(struct net_device *dev)
+{
+       if (dev->priv) {
+               kfree(dev->priv);
+               dev->priv = NULL;
+       }
+       free_netdev(dev);
+}
+
+void loopback_dev_ctor(struct net_device *dev)
+{
+       struct net_device_stats *stats;
+
+       memset(dev, 0, sizeof(*dev));
+       strcpy(dev->name, "lo");
+       dev->mtu                = (16 * 1024) + 20 + 20 + 12;
+       dev->hard_start_xmit    = loopback_xmit;
+       dev->hard_header        = eth_header;
+       dev->hard_header_cache  = eth_header_cache;
+       dev->header_cache_update = eth_header_cache_update;
+       dev->hard_header_len    = ETH_HLEN;     /* 14   */
+       dev->addr_len           = ETH_ALEN;     /* 6    */
+       dev->tx_queue_len       = 0;
+       dev->type               = ARPHRD_LOOPBACK;      /* 0x0001*/
+       dev->rebuild_header     = eth_rebuild_header;
+       dev->flags              = IFF_LOOPBACK;
+       dev->features           = NETIF_F_SG | NETIF_F_FRAGLIST
 #ifdef LOOPBACK_TSO
                                  | NETIF_F_TSO
 #endif
                                  | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA
-                                 | NETIF_F_LLTX,
-       .ethtool_ops            = &loopback_ethtool_ops,
-};
-
-/* Setup and register the loopback device. */
-int __init loopback_init(void)
-{
-       struct net_device_stats *stats;
+                                 | NETIF_F_LLTX
+                                 | NETIF_F_NSOK;
+       dev->ethtool_ops        = &loopback_ethtool_ops;
 
        /* Can survive without statistics */
        stats = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
        if (stats) {
                memset(stats, 0, sizeof(struct net_device_stats));
-               loopback_dev.priv = stats;
-               loopback_dev.get_stats = &get_stats;
+               dev->priv = stats;
+               dev->get_stats = &get_stats;
        }
-       
-       return register_netdev(&loopback_dev);
-};
+}
 
-EXPORT_SYMBOL(loopback_dev);
+/* Setup and register the loopback device. */
+int __init loopback_init(void)
+{
+       loopback_dev_ctor(&loopback_dev_static);
+       return register_netdev(&loopback_dev_static);
+};
--- ./include/linux/init_task.h.venshd  Wed Jun 21 18:53:16 2006
+++ ./include/linux/init_task.h Fri Jun 23 11:48:09 2006
@@ -87,6 +87,14 @@ extern struct nsproxy init_nsproxy;
 
 extern struct group_info init_groups;
 
+#ifdef CONFIG_NET_NS
+extern struct net_namespace init_net_ns;
+#define INIT_NET_NS \
+       .net_context    = &init_net_ns,
+#else
+#define INIT_NET_NS
+#endif
+
 /*
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -129,6 +137,7 @@ extern struct group_info init_groups;
        .signal         = &init_signals,                                \
        .sighand        = &init_sighand,                                \
        .nsproxy        = &init_nsproxy,                                \
+       INIT_NET_NS                                                     \
        .pending        = {                                             \
                .list = LIST_HEAD_INIT(tsk.pending.list),               \
                .signal = {{0}}},                                       \
--- ./include/linux/net_ns.h.venshd     Thu Jun 22 12:10:13 2006
+++ ./include/linux/net_ns.h    Fri Jun 23 11:49:42 2006
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2006  SWsoft
+ */
+#ifndef __LINUX_NET_NS__
+#define __LINUX_NET_NS__
+
+#ifdef CONFIG_NET_NS
+
+#include <asm/atomic.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+
+struct net_namespace {
+       atomic_t                active_ref, use_ref;
+       struct list_head        dev_base;
+       struct net_device       *loopback;
+       unsigned int            hash;
+       struct execute_work     destroy_work;
+};
+
+static inline struct net_namespace *get_net_ns(struct net_namespace *ns)
+{
+       atomic_inc(&ns->active_ref);
+       return ns;
+}
+
+extern void net_ns_stop(struct net_namespace *ns);
+static inline void put_net_ns(struct net_namespace *ns)
+{
+       if (atomic_dec_and_test(&ns->active_ref))
+               net_ns_stop(ns);
+}
+
+static inline struct net_namespace *ref_net_ns(struct net_namespace *ns)
+{
+       atomic_inc(&ns->use_ref);
+       return ns;
+}
+
+extern void net_ns_free(struct net_namespace *ns);
+static inline void unref_net_ns(struct net_namespace *ns)
+{
+       if (atomic_dec_and_test(&ns->use_ref))
+               net_ns_free(ns);
+}
+
+extern struct net_namespace init_net_ns;
+#define current_net_ns         (current->net_context)
+
+#define push_net_ns(to, orig)  do { \
+                                       task_t *__cur; \
+                                       __cur = current; \
+                                       orig = __cur->net_context; \
+                                       __cur->net_context = ref_net_ns(to); \
+                               } while (0)
+#define pop_net_ns(orig)       do { \
+                                       task_t *__cur; \
+                                       struct net_namespace *__cur_ns; \
+                                       __cur = current; \
+                                       __cur_ns = __cur->net_context; \
+                                       __cur->net_context = orig; \
+                                       unref_net_ns(__cur_ns); \
+                               } while (0)
+#define switch_net_ns(to)      do { \
+                                       task_t *__cur; \
+                                       struct net_namespace *__cur_ns; \
+                                       __cur = current; \
+                                       __cur_ns = __cur->net_context; \
+                                       __cur->net_context = ref_net_ns(to); \
+                                       unref_net_ns(__cur_ns); \
+                               } while (0)
+
+#define net_ns_same(target, context) ((target) == (context))
+
+#else /* CONFIG_NET_NS */
+
+struct net_namespace;
+
+#define get_net_ns(x)          NULL
+#define put_net_ns(x)          ((void)0)
+
+#define current_net_ns         NULL
+
+#define net_ns_same(target, context) 1
+
+#endif /* CONFIG_NET_NS */
+
+#endif /* __LINUX_NET_NS__ */
--- ./include/linux/netdevice.h.venshd  Thu Jun 22 18:57:50 2006
+++ ./include/linux/netdevice.h Fri Jun 23 11:48:15 2006
@@ -311,6 +311,7 @@ struct net_device
 #define NETIF_F_TSO            2048    /* Can offload TCP/IP segmentation */
 #define NETIF_F_LLTX           4096    /* LockLess TX */
 #define NETIF_F_UFO             8192    /* Can offload UDP Large Send*/
+#define NETIF_F_NSOK           16384   /* OK for namespaces */
 
 #define NETIF_F_GEN_CSUM       (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
 #define NETIF_F_ALL_CSUM       (NETIF_F_IP_CSUM | NETIF_F_GEN_CSUM)
@@ -366,6 +367,10 @@ struct net_device
        int                     promiscuity;
        int                     allmulti;
 
+#ifdef CONFIG_NET_NS
+       struct net_namespace    *net_ns;
+#endif
+
 
        /* Protocol specific pointers */
        
@@ -542,17 +547,26 @@ struct packet_type {
 
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
+#include <linux/net_ns.h>
 
-extern struct net_device       loopback_dev;           /* The loopback */
+extern struct net_device       loopback_dev_static;
+#ifndef CONFIG_NET_NS
+#define loopback_dev           loopback_dev_static     /* The loopback */
 extern struct list_head                dev_base_head;          /* All devices 
*/
+#else
+#define loopback_dev           (*current_net_ns->loopback)
+#define dev_base_head          (current_net_ns->dev_base)
+#endif
 extern rwlock_t                        dev_base_lock;          /* Device list 
lock */
 
 #define for_each_netdev(p)     list_for_each_entry(p, &dev_base_head, dev_list)
 
 /* DO NOT USE first_netdev/next_netdev, use loop defined above */
 #define first_netdev()         ({ \
-                                       list_empty(&dev_base_head) ? NULL : \
-                                               list_entry(dev_base_head.next, \
+                                       struct list_head *__base; \
+                                       __base = &dev_base_head; \
+                                       list_empty(__base) ? NULL : \
+                                               list_entry(__base->next, \
                                                        struct net_device, \
                                                        dev_list); \
                                 })
--- ./include/linux/nsproxy.h.venshd    Wed Jun 21 18:53:17 2006
+++ ./include/linux/nsproxy.h   Fri Jun 23 11:48:15 2006
@@ -33,6 +33,7 @@ struct nsproxy *dup_namespaces(struct ns
 int copy_namespaces(int flags, struct task_struct *tsk);
 void get_task_namespaces(struct task_struct *tsk);
 void free_nsproxy(struct nsproxy *ns);
+void release_net_context(struct task_struct *tsk);
 
 static inline void put_nsproxy(struct nsproxy *ns)
 {
@@ -48,5 +49,7 @@ static inline void exit_task_namespaces(
                put_nsproxy(ns);
                p->nsproxy = NULL;
        }
+       release_net_context(p);
 }
+
 #endif
--- ./include/linux/sched.h.venshd      Wed Jun 21 18:53:17 2006
+++ ./include/linux/sched.h     Fri Jun 23 11:48:15 2006
@@ -887,6 +887,9 @@ struct task_struct {
        struct files_struct *files;
 /* namespaces */
        struct nsproxy *nsproxy;
+#ifdef CONFIG_NET_NS
+       struct net_namespace *net_context;
+#endif
 /* signal handlers */
        struct signal_struct *signal;
        struct sighand_struct *sighand;
--- ./kernel/nsproxy.c.venshd   Wed Jun 21 18:53:17 2006
+++ ./kernel/nsproxy.c  Fri Jun 23 11:48:15 2006
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/nsproxy.h>
+#include <linux/net_ns.h>
 #include <linux/namespace.h>
 #include <linux/utsname.h>
 
@@ -84,6 +85,7 @@ int copy_namespaces(int flags, struct ta
                return 0;
 
        get_nsproxy(old_ns);
+       (void) get_net_ns(tsk->net_context); /* for pointer copied by memcpy */
 
        if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC)))
                return 0;
@@ -134,3 +136,15 @@ void free_nsproxy(struct nsproxy *ns)
                        put_ipc_ns(ns->ipc_ns);
                kfree(ns);
 }
+
+void release_net_context(struct task_struct *tsk)
+{
+#ifdef CONFIG_NET_NS
+       struct net_namespace *net_ns;
+
+       net_ns = tsk->net_context;
+       /* do not get refcounter here, nobody can put it later */
+       tsk->net_context = &init_net_ns;
+       put_net_ns(net_ns);
+#endif
+}
--- ./net/Kconfig.venshd        Wed Jun 21 18:53:22 2006
+++ ./net/Kconfig       Fri Jun 23 11:48:15 2006
@@ -66,6 +66,13 @@ source "net/ipv6/Kconfig"
 
 endif # if INET
 
+config NET_NS
+       bool "Network Namespaces"
+       help
+         This option enables multiple independent network namespaces,
+         each having own network devices, IP addresses, routes, and so on.
+         If unsure, answer N.
+
 config NETWORK_SECMARK
        bool "Security Marking"
        help
--- ./net/core/dev.c.venshd     Thu Jun 22 17:40:13 2006
+++ ./net/core/dev.c    Fri Jun 23 11:48:15 2006
@@ -91,6 +91,7 @@
 #include <linux/if_ether.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/net_ns.h>
 #include <linux/notifier.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
@@ -177,8 +178,10 @@ static spinlock_t net_dma_event_lock;
 DEFINE_RWLOCK(dev_base_lock);
 EXPORT_SYMBOL(dev_base_lock);
 
+#ifndef CONFIG_NET_NS
 LIST_HEAD(dev_base_head);
 EXPORT_SYMBOL(dev_base_head);
+#endif
 
 #define NETDEV_HASHBITS        8
 static struct hlist_head dev_name_head[1<<NETDEV_HASHBITS];
@@ -187,6 +190,9 @@ static struct hlist_head dev_index_head[
 static inline struct hlist_head *dev_name_hash(const char *name)
 {
        unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ));
+#ifdef CONFIG_NET_NS
+       hash ^= current_net_ns->hash;
+#endif
        return &dev_name_head[hash & ((1<<NETDEV_HASHBITS)-1)];
 }
 
@@ -211,10 +217,12 @@ DEFINE_PER_CPU(struct softnet_data, soft
 extern int netdev_sysfs_init(void);
 extern int netdev_register_sysfs(struct net_device *);
 extern void netdev_unregister_sysfs(struct net_device *);
+extern int netdev_rename_sysfs(struct net_device *);
 #else
 #define netdev_sysfs_init()            (0)
 #define netdev_register_sysfs(dev)     (0)
 #define        netdev_unregister_sysfs(dev)    do { } while(0)
+#define netdev_rename_sysfs(dev)       (0)
 #endif
 
 
@@ -474,10 +482,13 @@ __setup("netdev=", netdev_boot_setup);
 struct net_device *__dev_get_by_name(const char *name)
 {
        struct hlist_node *p;
+       struct net_namespace *ns __attribute_used__ = current_net_ns;
 
        hlist_for_each(p, dev_name_hash(name)) {
                struct net_device *dev
                        = hlist_entry(p, struct net_device, name_hlist);
+               if (!net_ns_same(dev->net_ns, ns))
+                       continue;
                if (!strncmp(dev->name, name, IFNAMSIZ))
                        return dev;
        }
@@ -740,7 +751,7 @@ int dev_change_name(struct net_device *d
        else
                strlcpy(dev->name, newname, IFNAMSIZ);
 
-       err = class_device_rename(&dev->class_dev, dev->name);
+       err = netdev_rename_sysfs(dev);
        if (!err) {
                hlist_del(&dev->name_hlist);
                hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
@@ -1531,7 +1542,14 @@ static void net_tx_action(struct softirq
                        clear_bit(__LINK_STATE_SCHED, &dev->state);
 
                        if (spin_trylock(&dev->queue_lock)) {
+#ifdef CONFIG_NET_NS
+                               struct net_namespace *orig_net_ns;
+                               push_net_ns(dev->net_ns, orig_net_ns);
+#endif
                                qdisc_run(dev);
+#ifdef CONFIG_NET_NS
+                               pop_net_ns(orig_net_ns);
+#endif
                                spin_unlock(&dev->queue_lock);
                        } else {
                                netif_schedule(dev);
@@ -1618,6 +1636,7 @@ int netif_receive_skb(struct sk_buff *sk
 {
        struct packet_type *ptype, *pt_prev;
        struct net_device *orig_dev;
+       struct net_namespace *orig_net_ns __attribute_used__;
        int ret = NET_RX_DROP;
        unsigned short type;
 
@@ -1636,6 +1655,10 @@ int netif_receive_skb(struct sk_buff *sk
        if (!orig_dev)
                return NET_RX_DROP;
 
+#ifdef CONFIG_NET_NS
+       push_net_ns(skb->dev->net_ns, orig_net_ns);
+#endif
+
        __get_cpu_var(netdev_rx_stat).total++;
 
        skb->h.raw = skb->nh.raw = skb->data;
@@ -1706,6 +1729,9 @@ ncls:
 
 out:
        rcu_read_unlock();
+#ifdef CONFIG_NET_NS
+       pop_net_ns(orig_net_ns);
+#endif
        return ret;
 }
 
@@ -2732,6 +2758,7 @@ int register_netdevice(struct net_device
 {
        struct hlist_head *head;
        struct hlist_node *p;
+       struct net_namespace *ns __attribute_used__ = current_net_ns;
        int ret;
 
        BUG_ON(dev_boot_phase);
@@ -2749,9 +2776,19 @@ int register_netdevice(struct net_device
        spin_lock_init(&dev->ingress_lock);
 #endif
 
+#ifdef CONFIG_NET_NS
+       dev->net_ns = ref_net_ns(ns);
+       /*
+        * loopback device doesn't hold active reference: it doesn't prevent
+        * stopping of net_namespace
+        */
+       if (dev != ns->loopback)
+               get_net_ns(ns);
+#endif
+
        ret = alloc_divert_blk(dev);
        if (ret)
-               goto out;
+               goto out_divert;
 
        dev->iflink = -1;
 
@@ -2779,6 +2816,8 @@ int register_netdevice(struct net_device
        hlist_for_each(p, head) {
                struct net_device *d
                        = hlist_entry(p, struct net_device, name_hlist);
+               if (!net_ns_same(d->net_ns, ns))
+                       continue;
                if (!strncmp(d->name, dev->name, IFNAMSIZ)) {
                        ret = -EEXIST;
                        goto out_err;
@@ -2852,6 +2891,13 @@ out:
        return ret;
 out_err:
        free_divert_blk(dev);
+out_divert:
+#ifdef CONFIG_NET_NS
+       unref_net_ns(ns);
+       if (dev != ns->loopback)
+               put_net_ns(ns);
+       dev->net_ns = NULL;
+#endif
        goto out;
 }
 
@@ -2977,9 +3023,13 @@ static DEFINE_MUTEX(net_todo_run_mutex);
 void netdev_run_todo(void)
 {
        struct list_head list;
+       struct net_namespace *orig_net_ns __attribute_used__;
 
        /* Need to guard against multiple cpu's getting out of order. */
        mutex_lock(&net_todo_run_mutex);
+#ifdef CONFIG_NET_NS
+       push_net_ns(current_net_ns, orig_net_ns);
+#endif
 
        /* Not safe to do outside the semaphore.  We must not return
         * until all unregister events invoked by the local processor
@@ -3006,6 +3056,9 @@ void netdev_run_todo(void)
                        continue;
                }
 
+#ifdef CONFIG_NET_NS
+               switch_net_ns(dev->net_ns);
+#endif
                netdev_unregister_sysfs(dev);
                dev->reg_state = NETREG_UNREGISTERED;
 
@@ -3025,6 +3078,9 @@ void netdev_run_todo(void)
        }
 
 out:
+#ifdef CONFIG_NET_NS
+       pop_net_ns(orig_net_ns);
+#endif
        mutex_unlock(&net_todo_run_mutex);
 }
 
@@ -3077,6 +3133,17 @@ EXPORT_SYMBOL(alloc_netdev);
  */
 void free_netdev(struct net_device *dev)
 {
+#ifdef CONFIG_NET_NS
+       struct net_namespace *ns;
+
+       ns = dev->net_ns;
+       if (ns != NULL) {
+               unref_net_ns(ns);
+               if (dev != ns->loopback)
+                       put_net_ns(ns);
+               dev->net_ns = NULL;
+       }
+#endif
 #ifdef CONFIG_SYSFS
        /*  Compatibility with error handling in drivers */
        if (dev->reg_state == NETREG_UNINITIALIZED) {
@@ -3087,6 +3154,13 @@ void free_netdev(struct net_device *dev)
        BUG_ON(dev->reg_state != NETREG_UNREGISTERED);
        dev->reg_state = NETREG_RELEASED;
 
+#ifdef CONFIG_NET_NS
+       if (ns != NULL && ns != &init_net_ns) {
+               kfree((char *)dev - dev->padded);
+               return;
+       }
+#endif
+
        /* will free via class release */
        class_device_put(&dev->class_dev);
 #else
@@ -3323,6 +3397,90 @@ static int __init netdev_dma_register(vo
 static int __init netdev_dma_register(void) { return -ENODEV; }
 #endif /* CONFIG_NET_DMA */
 
+#ifdef CONFIG_NET_NS
+struct net_namespace init_net_ns = {
+       .active_ref     = ATOMIC_INIT(2),
+                         /* one for init_task->net_context,
+                            one not to let init_net_ns go away */
+       .use_ref        = ATOMIC_INIT(1), /* for active references */
+       .dev_base       = LIST_HEAD_INIT(init_net_ns.dev_base),
+       .loopback       = &loopback_dev_static,
+};
+
+extern void loopback_dev_ctor(struct net_device *dev);
+extern void loopback_dev_dtor(struct net_device *dev);
+int net_ns_start(void)
+{
+       struct net_namespace *ns, *orig_ns;
+       struct net_device *dev;
+       task_t *task;
+       int err;
+
+       err = -ENOMEM;
+       ns = kmalloc(sizeof(*ns), GFP_KERNEL);
+       if (ns == NULL)
+               goto out_ns;
+       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL)
+               goto out_dev;
+       loopback_dev_ctor(dev);
+       dev->destructor = loopback_dev_dtor;
+
+       memset(ns, 0, sizeof(*ns));
+       atomic_set(&ns->active_ref, 1);
+       atomic_set(&ns->use_ref, 1);
+       INIT_LIST_HEAD(&ns->dev_base);
+       ns->hash = net_random();
+       ns->loopback = dev;
+
+       task = current;
+       orig_ns = task->net_context;
+       task->net_context = ns;
+       err = register_netdev(dev);
+       if (err)
+               goto out_register;
+       put_net_ns(orig_ns);
+       return 0;
+
+out_register:
+       dev->destructor(dev);
+       task->net_context = orig_ns;
+       BUG_ON(atomic_read(&ns->active_ref) != 1);
+out_dev:
+       kfree(ns);
+out_ns:
+       return err;
+}
+EXPORT_SYMBOL(net_ns_start);
+
+void net_ns_free(struct net_namespace *ns)
+{
+       kfree(ns);
+}
+EXPORT_SYMBOL(net_ns_free);
+
+/* destroy loopback device and protocol datastructures in process context */
+static void net_ns_destroy(void *data)
+{
+       struct net_namespace *ns, *orig_ns;
+
+       ns = data;
+       push_net_ns(ns, orig_ns);
+       unregister_netdev(ns->loopback);
+       BUG_ON(!list_empty(&ns->dev_base));
+       pop_net_ns(orig_ns);
+
+       /* drop (hopefully) final reference */
+       unref_net_ns(ns);
+}
+
+void net_ns_stop(struct net_namespace *ns)
+{
+       execute_in_process_context(net_ns_destroy, ns, &ns->destroy_work);
+}
+EXPORT_SYMBOL(net_ns_stop);
+#endif
+
 /*
  *     Initialize the DEV module. At boot time this walks the device list and
  *     unhooks any devices that fail to initialise (normally hardware not
--- ./net/core/net-sysfs.c.venshd       Wed Jun 21 18:51:08 2006
+++ ./net/core/net-sysfs.c      Fri Jun 23 11:48:15 2006
@@ -13,6 +13,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
+#include <linux/net_ns.h>
 #include <linux/if_arp.h>
 #include <net/sock.h>
 #include <linux/rtnetlink.h>
@@ -445,6 +446,12 @@ static struct class net_class = {
 
 void netdev_unregister_sysfs(struct net_device * net)
 {
+#ifdef CONFIG_NET_NS
+       if (current_net_ns != &init_net_ns)
+               /* not supported yet: sysfs virtualization is required */
+               return;
+#endif
+
        class_device_del(&(net->class_dev));
 }
 
@@ -454,6 +461,12 @@ int netdev_register_sysfs(struct net_dev
        struct class_device *class_dev = &(net->class_dev);
        struct attribute_group **groups = net->sysfs_groups;
 
+#ifdef CONFIG_NET_NS
+       if (current_net_ns != &init_net_ns)
+               /* not supported yet: sysfs virtualization is required */
+               return 0;
+#endif
+
        class_device_initialize(class_dev);
        class_dev->class = &net_class;
        class_dev->class_data = net;
@@ -474,6 +487,17 @@ int netdev_register_sysfs(struct net_dev
        return class_device_add(class_dev);
 }
 
+int netdev_rename_sysfs(struct net_device *dev)
+{
+#ifdef CONFIG_NET_NS
+       if (current_net_ns != &init_net_ns)
+               /* not supported yet: sysfs virtualization is required */
+               return 0;
+#endif
+
+       return class_device_rename(&dev->class_dev, dev->name);
+}
+
 int netdev_sysfs_init(void)
 {
        return class_register(&net_class);
--- ./net/ipv4/devinet.c.venshd Thu Jun 22 12:03:08 2006
+++ ./net/ipv4/devinet.c        Fri Jun 23 11:48:15 2006
@@ -190,7 +190,7 @@ static void inetdev_destroy(struct in_de
        ASSERT_RTNL();
 
        dev = in_dev->dev;
-       if (dev == &loopback_dev)
+       if (dev == &loopback_dev_static)
                return;
 
        in_dev->dead = 1;
--- ./net/ipv6/addrconf.c.venshd        Thu Jun 22 12:03:08 2006
+++ ./net/ipv6/addrconf.c       Fri Jun 23 11:48:15 2006
@@ -2277,7 +2277,7 @@ static int addrconf_ifdown(struct net_de
 
        ASSERT_RTNL();
 
-       if (dev == &loopback_dev && how == 1)
+       if (dev == &loopback_dev_static && how == 1)
                how = 0;
 
        rt6_ifdown(dev);
--- ./net/ipv6/route.c.venshd   Wed Jun 21 18:53:20 2006
+++ ./net/ipv6/route.c  Fri Jun 23 11:48:15 2006
@@ -125,7 +125,7 @@ struct rt6_info ip6_null_entry = {
                .dst = {
                        .__refcnt       = ATOMIC_INIT(1),
                        .__use          = 1,
-                       .dev            = &loopback_dev,
+                       /* .dev         = &loopback_dev, */
                        .obsolete       = -1,
                        .error          = -ENETUNREACH,
                        .metrics        = { [RTAX_HOPLIMIT - 1] = 255, },
@@ -2268,6 +2268,7 @@ void __init ip6_route_init(void)
 #ifdef CONFIG_XFRM
        xfrm6_init();
 #endif
+       ip6_null_entry.u.dst.dev = &loopback_dev;
 }
 
 void ip6_route_cleanup(void)
-
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