]> err.no Git - linux-2.6/blobdiff - net/core/dev.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[linux-2.6] / net / core / dev.c
index 520ef7b20862ca208c66b0b3ab3b4b8f62cf21fe..872658927e47cc619f7f82759e1487892fc20fa0 100644 (file)
@@ -208,6 +208,34 @@ static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex)
        return &net->dev_index_head[ifindex & ((1 << NETDEV_HASHBITS) - 1)];
 }
 
+/* Device list insertion */
+static int list_netdevice(struct net_device *dev)
+{
+       struct net *net = dev->nd_net;
+
+       ASSERT_RTNL();
+
+       write_lock_bh(&dev_base_lock);
+       list_add_tail(&dev->dev_list, &net->dev_base_head);
+       hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name));
+       hlist_add_head(&dev->index_hlist, dev_index_hash(net, dev->ifindex));
+       write_unlock_bh(&dev_base_lock);
+       return 0;
+}
+
+/* Device list removal */
+static void unlist_netdevice(struct net_device *dev)
+{
+       ASSERT_RTNL();
+
+       /* Unlink dev from the device chain */
+       write_lock_bh(&dev_base_lock);
+       list_del(&dev->dev_list);
+       hlist_del(&dev->name_hlist);
+       hlist_del(&dev->index_hlist);
+       write_unlock_bh(&dev_base_lock);
+}
+
 /*
  *     Our notifier list
  */
@@ -221,15 +249,9 @@ static RAW_NOTIFIER_HEAD(netdev_chain);
 
 DEFINE_PER_CPU(struct softnet_data, softnet_data);
 
-#ifdef CONFIG_SYSFS
-extern int netdev_sysfs_init(void);
-extern int netdev_register_sysfs(struct net_device *);
-extern void netdev_unregister_sysfs(struct net_device *);
-#else
-#define netdev_sysfs_init()            (0)
-#define netdev_register_sysfs(dev)     (0)
-#define        netdev_unregister_sysfs(dev)    do { } while(0)
-#endif
+extern int netdev_kobject_init(void);
+extern int netdev_register_kobject(struct net_device *);
+extern void netdev_unregister_kobject(struct net_device *);
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 /*
@@ -535,6 +557,7 @@ __setup("netdev=", netdev_boot_setup);
 
 /**
  *     __dev_get_by_name       - find a device by its name
+ *     @net: the applicable net namespace
  *     @name: name to find
  *
  *     Find an interface by name. Must be called under RTNL semaphore
@@ -559,6 +582,7 @@ struct net_device *__dev_get_by_name(struct net *net, const char *name)
 
 /**
  *     dev_get_by_name         - find a device by its name
+ *     @net: the applicable net namespace
  *     @name: name to find
  *
  *     Find an interface by name. This can be called from any
@@ -582,6 +606,7 @@ struct net_device *dev_get_by_name(struct net *net, const char *name)
 
 /**
  *     __dev_get_by_index - find a device by its ifindex
+ *     @net: the applicable net namespace
  *     @ifindex: index of device
  *
  *     Search for an interface by index. Returns %NULL if the device
@@ -607,6 +632,7 @@ struct net_device *__dev_get_by_index(struct net *net, int ifindex)
 
 /**
  *     dev_get_by_index - find a device by its ifindex
+ *     @net: the applicable net namespace
  *     @ifindex: index of device
  *
  *     Search for an interface by index. Returns NULL if the device
@@ -629,6 +655,7 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex)
 
 /**
  *     dev_getbyhwaddr - find a device by its hardware address
+ *     @net: the applicable net namespace
  *     @type: media type of device
  *     @ha: hardware address
  *
@@ -687,6 +714,7 @@ EXPORT_SYMBOL(dev_getfirstbyhwtype);
 
 /**
  *     dev_get_by_flags - find any device with given flags
+ *     @net: the applicable net namespace
  *     @if_flags: IFF_* values
  *     @mask: bitmask of bits in if_flags to check
  *
@@ -758,7 +786,7 @@ static int __dev_alloc_name(struct net *net, const char *name, char *buf)
        int i = 0;
        const char *p;
        const int max_netdevices = 8*PAGE_SIZE;
-       long *inuse;
+       unsigned long *inuse;
        struct net_device *d;
 
        p = strnchr(name, IFNAMSIZ-1, '%');
@@ -772,7 +800,7 @@ static int __dev_alloc_name(struct net *net, const char *name, char *buf)
                        return -EINVAL;
 
                /* Use one page as a bit array of possible slots */
-               inuse = (long *) get_zeroed_page(GFP_ATOMIC);
+               inuse = (unsigned long *) get_zeroed_page(GFP_ATOMIC);
                if (!inuse)
                        return -ENOMEM;
 
@@ -878,7 +906,7 @@ rollback:
        hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name));
        write_unlock_bh(&dev_base_lock);
 
-       ret = raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
+       ret = call_netdevice_notifiers(NETDEV_CHANGENAME, dev);
        ret = notifier_to_errno(ret);
 
        if (ret) {
@@ -904,7 +932,7 @@ rollback:
  */
 void netdev_features_change(struct net_device *dev)
 {
-       raw_notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev);
+       call_netdevice_notifiers(NETDEV_FEAT_CHANGE, dev);
 }
 EXPORT_SYMBOL(netdev_features_change);
 
@@ -919,14 +947,14 @@ EXPORT_SYMBOL(netdev_features_change);
 void netdev_state_change(struct net_device *dev)
 {
        if (dev->flags & IFF_UP) {
-               raw_notifier_call_chain(&netdev_chain,
-                               NETDEV_CHANGE, dev);
+               call_netdevice_notifiers(NETDEV_CHANGE, dev);
                rtmsg_ifinfo(RTM_NEWLINK, dev, 0);
        }
 }
 
 /**
  *     dev_load        - load a network module
+ *     @net: the applicable net namespace
  *     @name: name of interface
  *
  *     If a network interface is not present and the process has suitable
@@ -946,14 +974,6 @@ void dev_load(struct net *net, const char *name)
                request_module("%s", name);
 }
 
-static int default_rebuild_header(struct sk_buff *skb)
-{
-       printk(KERN_DEBUG "%s: default_rebuild_header called -- BUG!\n",
-              skb->dev ? skb->dev->name : "NULL!!!");
-       kfree_skb(skb);
-       return 1;
-}
-
 /**
  *     dev_open        - prepare an interface for use.
  *     @dev:   device to open
@@ -1016,7 +1036,7 @@ int dev_open(struct net_device *dev)
                /*
                 *      ... and announce new interface.
                 */
-               raw_notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
+               call_netdevice_notifiers(NETDEV_UP, dev);
        }
        return ret;
 }
@@ -1032,6 +1052,8 @@ int dev_open(struct net_device *dev)
  */
 int dev_close(struct net_device *dev)
 {
+       might_sleep();
+
        if (!(dev->flags & IFF_UP))
                return 0;
 
@@ -1039,7 +1061,7 @@ int dev_close(struct net_device *dev)
         *      Tell people we are going down, so that they can
         *      prepare to death, when device is still operating.
         */
-       raw_notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev);
+       call_netdevice_notifiers(NETDEV_GOING_DOWN, dev);
 
        dev_deactivate(dev);
 
@@ -1072,7 +1094,7 @@ int dev_close(struct net_device *dev)
        /*
         * Tell people we are down
         */
-       raw_notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);
+       call_netdevice_notifiers(NETDEV_DOWN, dev);
 
        return 0;
 }
@@ -1170,15 +1192,15 @@ int unregister_netdevice_notifier(struct notifier_block *nb)
 /**
  *     call_netdevice_notifiers - call all network notifier blocks
  *      @val: value passed unmodified to notifier function
- *      @v:   pointer passed unmodified to notifier function
+ *      @dev: net_device pointer passed unmodified to notifier function
  *
  *     Call all network notifier blocks.  Parameters and return value
  *     are as for raw_notifier_call_chain().
  */
 
-int call_netdevice_notifiers(unsigned long val, void *v)
+int call_netdevice_notifiers(unsigned long val, struct net_device *dev)
 {
-       return raw_notifier_call_chain(&netdev_chain, val, v);
+       return raw_notifier_call_chain(&netdev_chain, val, dev);
 }
 
 /* When > 0 there are consumers of rx skb time stamps */
@@ -1340,22 +1362,21 @@ int skb_checksum_help(struct sk_buff *skb)
                goto out_set_summed;
        }
 
-       if (skb_cloned(skb)) {
+       offset = skb->csum_start - skb_headroom(skb);
+       BUG_ON(offset >= skb_headlen(skb));
+       csum = skb_checksum(skb, offset, skb->len - offset, 0);
+
+       offset += skb->csum_offset;
+       BUG_ON(offset + sizeof(__sum16) > skb_headlen(skb));
+
+       if (skb_cloned(skb) &&
+           !skb_clone_writable(skb, offset + sizeof(__sum16))) {
                ret = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
                if (ret)
                        goto out;
        }
 
-       offset = skb->csum_start - skb_headroom(skb);
-       BUG_ON(offset > (int)skb->len);
-       csum = skb_checksum(skb, offset, skb->len-offset, 0);
-
-       offset = skb_headlen(skb) - offset;
-       BUG_ON(offset <= 0);
-       BUG_ON(skb->csum_offset + 2 > offset);
-
-       *(__sum16 *)(skb->head + skb->csum_start + skb->csum_offset) =
-               csum_fold(csum);
+       *(__sum16 *)(skb->data + offset) = csum_fold(csum);
 out_set_summed:
        skb->ip_summed = CHECKSUM_NONE;
 out:
@@ -1532,7 +1553,7 @@ gso:
                        return rc;
                }
                if (unlikely((netif_queue_stopped(dev) ||
-                            netif_subqueue_stopped(dev, skb->queue_mapping)) &&
+                            netif_subqueue_stopped(dev, skb)) &&
                             skb->next))
                        return NETDEV_TX_BUSY;
        } while (skb->next);
@@ -1544,18 +1565,6 @@ out_kfree_skb:
        return 0;
 }
 
-#define HARD_TX_LOCK(dev, cpu) {                       \
-       if ((dev->features & NETIF_F_LLTX) == 0) {      \
-               netif_tx_lock(dev);                     \
-       }                                               \
-}
-
-#define HARD_TX_UNLOCK(dev) {                          \
-       if ((dev->features & NETIF_F_LLTX) == 0) {      \
-               netif_tx_unlock(dev);                   \
-       }                                               \
-}
-
 /**
  *     dev_queue_xmit - transmit a buffer
  *     @skb: buffer to transmit
@@ -1652,7 +1661,7 @@ gso:
                q = dev->qdisc;
                if (q->enqueue) {
                        /* reset queue_mapping to zero */
-                       skb->queue_mapping = 0;
+                       skb_set_queue_mapping(skb, 0);
                        rc = q->enqueue(skb, q);
                        qdisc_run(dev);
                        spin_unlock(&dev->queue_lock);
@@ -1683,7 +1692,7 @@ gso:
                        HARD_TX_LOCK(dev, cpu);
 
                        if (!netif_queue_stopped(dev) &&
-                           !netif_subqueue_stopped(dev, skb->queue_mapping)) {
+                           !netif_subqueue_stopped(dev, skb)) {
                                rc = 0;
                                if (!dev_hard_start_xmit(skb, dev)) {
                                        HARD_TX_UNLOCK(dev);
@@ -1939,27 +1948,51 @@ static int ing_filter(struct sk_buff *skb)
        struct Qdisc *q;
        struct net_device *dev = skb->dev;
        int result = TC_ACT_OK;
+       u32 ttl = G_TC_RTTL(skb->tc_verd);
 
-       if (dev->qdisc_ingress) {
-               __u32 ttl = (__u32) G_TC_RTTL(skb->tc_verd);
-               if (MAX_RED_LOOP < ttl++) {
-                       printk(KERN_WARNING "Redir loop detected Dropping packet (%d->%d)\n",
-                               skb->iif, skb->dev->ifindex);
-                       return TC_ACT_SHOT;
-               }
+       if (MAX_RED_LOOP < ttl++) {
+               printk(KERN_WARNING
+                      "Redir loop detected Dropping packet (%d->%d)\n",
+                      skb->iif, dev->ifindex);
+               return TC_ACT_SHOT;
+       }
+
+       skb->tc_verd = SET_TC_RTTL(skb->tc_verd, ttl);
+       skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS);
 
-               skb->tc_verd = SET_TC_RTTL(skb->tc_verd,ttl);
+       spin_lock(&dev->ingress_lock);
+       if ((q = dev->qdisc_ingress) != NULL)
+               result = q->enqueue(skb, q);
+       spin_unlock(&dev->ingress_lock);
 
-               skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_INGRESS);
+       return result;
+}
+
+static inline struct sk_buff *handle_ing(struct sk_buff *skb,
+                                        struct packet_type **pt_prev,
+                                        int *ret, struct net_device *orig_dev)
+{
+       if (!skb->dev->qdisc_ingress)
+               goto out;
 
-               spin_lock(&dev->ingress_lock);
-               if ((q = dev->qdisc_ingress) != NULL)
-                       result = q->enqueue(skb, q);
-               spin_unlock(&dev->ingress_lock);
+       if (*pt_prev) {
+               *ret = deliver_skb(skb, *pt_prev, orig_dev);
+               *pt_prev = NULL;
+       } else {
+               /* Huh? Why does turning on AF_PACKET affect this? */
+               skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
+       }
 
+       switch (ing_filter(skb)) {
+       case TC_ACT_SHOT:
+       case TC_ACT_STOLEN:
+               kfree_skb(skb);
+               return NULL;
        }
 
-       return result;
+out:
+       skb->tc_verd = 0;
+       return skb;
 }
 #endif
 
@@ -2011,21 +2044,9 @@ int netif_receive_skb(struct sk_buff *skb)
        }
 
 #ifdef CONFIG_NET_CLS_ACT
-       if (pt_prev) {
-               ret = deliver_skb(skb, pt_prev, orig_dev);
-               pt_prev = NULL; /* noone else should process this after*/
-       } else {
-               skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
-       }
-
-       ret = ing_filter(skb);
-
-       if (ret == TC_ACT_SHOT || (ret == TC_ACT_STOLEN)) {
-               kfree_skb(skb);
+       skb = handle_ing(skb, &pt_prev, &ret, orig_dev);
+       if (!skb)
                goto out;
-       }
-
-       skb->tc_verd = 0;
 ncls:
 #endif
 
@@ -2094,7 +2115,7 @@ static int process_backlog(struct napi_struct *napi, int quota)
 
 /**
  * __napi_schedule - schedule for receive
- * @napi: entry to schedule
+ * @n: entry to schedule
  *
  * The entry's receive function will be scheduled to run
  */
@@ -2434,7 +2455,11 @@ static int dev_seq_open(struct inode *inode, struct file *file)
        res =  seq_open(file, &dev_seq_ops);
        if (!res) {
                seq = file->private_data;
-               seq->private = get_net(PROC_NET(inode));
+               seq->private = get_proc_net(inode);
+               if (!seq->private) {
+                       seq_release(inode, file);
+                       res = -ENXIO;
+               }
        }
        return res;
 }
@@ -2604,7 +2629,7 @@ static const struct file_operations ptype_seq_fops = {
 };
 
 
-static int dev_proc_net_init(struct net *net)
+static int __net_init dev_proc_net_init(struct net *net)
 {
        int rc = -ENOMEM;
 
@@ -2629,7 +2654,7 @@ out_dev:
        goto out;
 }
 
-static void dev_proc_net_exit(struct net *net)
+static void __net_exit dev_proc_net_exit(struct net *net)
 {
        wext_proc_exit(net);
 
@@ -2638,7 +2663,7 @@ static void dev_proc_net_exit(struct net *net)
        proc_net_remove(net, "dev");
 }
 
-static struct pernet_operations dev_proc_ops = {
+static struct pernet_operations __net_initdata dev_proc_ops = {
        .init = dev_proc_net_init,
        .exit = dev_proc_net_exit,
 };
@@ -3009,8 +3034,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
        if (dev->flags & IFF_UP &&
            ((old_flags ^ dev->flags) &~ (IFF_UP | IFF_PROMISC | IFF_ALLMULTI |
                                          IFF_VOLATILE)))
-               raw_notifier_call_chain(&netdev_chain,
-                               NETDEV_CHANGE, dev);
+               call_netdevice_notifiers(NETDEV_CHANGE, dev);
 
        if ((flags ^ dev->gflags) & IFF_PROMISC) {
                int inc = (flags & IFF_PROMISC) ? +1 : -1;
@@ -3056,8 +3080,7 @@ int dev_set_mtu(struct net_device *dev, int new_mtu)
        else
                dev->mtu = new_mtu;
        if (!err && dev->flags & IFF_UP)
-               raw_notifier_call_chain(&netdev_chain,
-                               NETDEV_CHANGEMTU, dev);
+               call_netdevice_notifiers(NETDEV_CHANGEMTU, dev);
        return err;
 }
 
@@ -3073,15 +3096,14 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa)
                return -ENODEV;
        err = dev->set_mac_address(dev, sa);
        if (!err)
-               raw_notifier_call_chain(&netdev_chain,
-                               NETDEV_CHANGEADDR, dev);
+               call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
        return err;
 }
 
 /*
- *     Perform the SIOCxIFxxx calls.
+ *     Perform the SIOCxIFxxx calls, inside read_lock(dev_base_lock)
  */
-static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
+static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cmd)
 {
        int err;
        struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
@@ -3094,25 +3116,15 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
                        ifr->ifr_flags = dev_get_flags(dev);
                        return 0;
 
-               case SIOCSIFFLAGS:      /* Set interface flags */
-                       return dev_change_flags(dev, ifr->ifr_flags);
-
                case SIOCGIFMETRIC:     /* Get the metric on the interface
                                           (currently unused) */
                        ifr->ifr_metric = 0;
                        return 0;
 
-               case SIOCSIFMETRIC:     /* Set the metric on the interface
-                                          (currently unused) */
-                       return -EOPNOTSUPP;
-
                case SIOCGIFMTU:        /* Get the MTU of a device */
                        ifr->ifr_mtu = dev->mtu;
                        return 0;
 
-               case SIOCSIFMTU:        /* Set the MTU of a device */
-                       return dev_set_mtu(dev, ifr->ifr_mtu);
-
                case SIOCGIFHWADDR:
                        if (!dev->addr_len)
                                memset(ifr->ifr_hwaddr.sa_data, 0, sizeof ifr->ifr_hwaddr.sa_data);
@@ -3122,17 +3134,9 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
                        ifr->ifr_hwaddr.sa_family = dev->type;
                        return 0;
 
-               case SIOCSIFHWADDR:
-                       return dev_set_mac_address(dev, &ifr->ifr_hwaddr);
-
-               case SIOCSIFHWBROADCAST:
-                       if (ifr->ifr_hwaddr.sa_family != dev->type)
-                               return -EINVAL;
-                       memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data,
-                              min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len));
-                       raw_notifier_call_chain(&netdev_chain,
-                                           NETDEV_CHANGEADDR, dev);
-                       return 0;
+               case SIOCGIFSLAVE:
+                       err = -EINVAL;
+                       break;
 
                case SIOCGIFMAP:
                        ifr->ifr_map.mem_start = dev->mem_start;
@@ -3143,6 +3147,59 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
                        ifr->ifr_map.port      = dev->if_port;
                        return 0;
 
+               case SIOCGIFINDEX:
+                       ifr->ifr_ifindex = dev->ifindex;
+                       return 0;
+
+               case SIOCGIFTXQLEN:
+                       ifr->ifr_qlen = dev->tx_queue_len;
+                       return 0;
+
+               default:
+                       /* dev_ioctl() should ensure this case
+                        * is never reached
+                        */
+                       WARN_ON(1);
+                       err = -EINVAL;
+                       break;
+
+       }
+       return err;
+}
+
+/*
+ *     Perform the SIOCxIFxxx calls, inside rtnl_lock()
+ */
+static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
+{
+       int err;
+       struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
+
+       if (!dev)
+               return -ENODEV;
+
+       switch (cmd) {
+               case SIOCSIFFLAGS:      /* Set interface flags */
+                       return dev_change_flags(dev, ifr->ifr_flags);
+
+               case SIOCSIFMETRIC:     /* Set the metric on the interface
+                                          (currently unused) */
+                       return -EOPNOTSUPP;
+
+               case SIOCSIFMTU:        /* Set the MTU of a device */
+                       return dev_set_mtu(dev, ifr->ifr_mtu);
+
+               case SIOCSIFHWADDR:
+                       return dev_set_mac_address(dev, &ifr->ifr_hwaddr);
+
+               case SIOCSIFHWBROADCAST:
+                       if (ifr->ifr_hwaddr.sa_family != dev->type)
+                               return -EINVAL;
+                       memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data,
+                              min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len));
+                       call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
+                       return 0;
+
                case SIOCSIFMAP:
                        if (dev->set_config) {
                                if (!netif_device_present(dev))
@@ -3169,14 +3226,6 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
                        return dev_mc_delete(dev, ifr->ifr_hwaddr.sa_data,
                                             dev->addr_len, 1);
 
-               case SIOCGIFINDEX:
-                       ifr->ifr_ifindex = dev->ifindex;
-                       return 0;
-
-               case SIOCGIFTXQLEN:
-                       ifr->ifr_qlen = dev->tx_queue_len;
-                       return 0;
-
                case SIOCSIFTXQLEN:
                        if (ifr->ifr_qlen < 0)
                                return -EINVAL;
@@ -3228,6 +3277,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
 
 /**
  *     dev_ioctl       -       network device ioctl
+ *     @net: the applicable net namespace
  *     @cmd: command to issue
  *     @arg: pointer to a struct ifreq in user space
  *
@@ -3287,7 +3337,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
                case SIOCGIFTXQLEN:
                        dev_load(net, ifr.ifr_name);
                        read_lock(&dev_base_lock);
-                       ret = dev_ifsioc(net, &ifr, cmd);
+                       ret = dev_ifsioc_locked(net, &ifr, cmd);
                        read_unlock(&dev_base_lock);
                        if (!ret) {
                                if (colon)
@@ -3405,6 +3455,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
 
 /**
  *     dev_new_index   -       allocate an ifindex
+ *     @net: the applicable net namespace
  *
  *     Returns a suitable unique value for a new device interface
  *     number.  The caller must hold the rtnl semaphore or the
@@ -3550,15 +3601,7 @@ int register_netdevice(struct net_device *dev)
                }
        }
 
-       /*
-        *      nil rebuild_header routine,
-        *      that should be never called and used as just bug trap.
-        */
-
-       if (!dev->rebuild_header)
-               dev->rebuild_header = default_rebuild_header;
-
-       ret = netdev_register_sysfs(dev);
+       ret = netdev_register_kobject(dev);
        if (ret)
                goto err_uninit;
        dev->reg_state = NETREG_REGISTERED;
@@ -3571,15 +3614,11 @@ int register_netdevice(struct net_device *dev)
        set_bit(__LINK_STATE_PRESENT, &dev->state);
 
        dev_init_scheduler(dev);
-       write_lock_bh(&dev_base_lock);
-       list_add_tail(&dev->dev_list, &net->dev_base_head);
-       hlist_add_head(&dev->name_hlist, head);
-       hlist_add_head(&dev->index_hlist, dev_index_hash(net, dev->ifindex));
        dev_hold(dev);
-       write_unlock_bh(&dev_base_lock);
+       list_netdevice(dev);
 
        /* Notify protocols, that a new device appeared. */
-       ret = raw_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
+       ret = call_netdevice_notifiers(NETDEV_REGISTER, dev);
        ret = notifier_to_errno(ret);
        if (ret)
                unregister_netdevice(dev);
@@ -3650,8 +3689,7 @@ static void netdev_wait_allrefs(struct net_device *dev)
                        rtnl_lock();
 
                        /* Rebroadcast unregister notification */
-                       raw_notifier_call_chain(&netdev_chain,
-                                           NETDEV_UNREGISTER, dev);
+                       call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
 
                        if (test_bit(__LINK_STATE_LINKWATCH_PENDING,
                                     &dev->state)) {
@@ -3826,7 +3864,6 @@ EXPORT_SYMBOL(alloc_netdev_mq);
  */
 void free_netdev(struct net_device *dev)
 {
-#ifdef CONFIG_SYSFS
        /*  Compatibility with error handling in drivers */
        if (dev->reg_state == NETREG_UNINITIALIZED) {
                kfree((char *)dev - dev->padded);
@@ -3838,9 +3875,6 @@ void free_netdev(struct net_device *dev)
 
        /* will free via device release */
        put_device(&dev->dev);
-#else
-       kfree((char *)dev - dev->padded);
-#endif
 }
 
 /* Synchronize with packet receive processing. */
@@ -3879,15 +3913,10 @@ void unregister_netdevice(struct net_device *dev)
        BUG_ON(dev->reg_state != NETREG_REGISTERED);
 
        /* If device is running, close it first. */
-       if (dev->flags & IFF_UP)
-               dev_close(dev);
+       dev_close(dev);
 
        /* And unlink it from device chain. */
-       write_lock_bh(&dev_base_lock);
-       list_del(&dev->dev_list);
-       hlist_del(&dev->name_hlist);
-       hlist_del(&dev->index_hlist);
-       write_unlock_bh(&dev_base_lock);
+       unlist_netdevice(dev);
 
        dev->reg_state = NETREG_UNREGISTERING;
 
@@ -3900,7 +3929,7 @@ void unregister_netdevice(struct net_device *dev)
        /* Notify protocols, that we are about to destroy
           this device. They should clean all the things.
        */
-       raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
+       call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
 
        /*
         *      Flush the unicast and multicast chains
@@ -3913,8 +3942,8 @@ void unregister_netdevice(struct net_device *dev)
        /* Notifier chain MUST detach us from master device. */
        BUG_TRAP(!dev->master);
 
-       /* Remove entries from sysfs */
-       netdev_unregister_sysfs(dev);
+       /* Remove entries from kobject tree */
+       netdev_unregister_kobject(dev);
 
        /* Finish processing unregister after unlock */
        net_set_todo(dev);
@@ -3945,6 +3974,121 @@ void unregister_netdev(struct net_device *dev)
 
 EXPORT_SYMBOL(unregister_netdev);
 
+/**
+ *     dev_change_net_namespace - move device to different nethost namespace
+ *     @dev: device
+ *     @net: network namespace
+ *     @pat: If not NULL name pattern to try if the current device name
+ *           is already taken in the destination network namespace.
+ *
+ *     This function shuts down a device interface and moves it
+ *     to a new network namespace. On success 0 is returned, on
+ *     a failure a netagive errno code is returned.
+ *
+ *     Callers must hold the rtnl semaphore.
+ */
+
+int dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat)
+{
+       char buf[IFNAMSIZ];
+       const char *destname;
+       int err;
+
+       ASSERT_RTNL();
+
+       /* Don't allow namespace local devices to be moved. */
+       err = -EINVAL;
+       if (dev->features & NETIF_F_NETNS_LOCAL)
+               goto out;
+
+       /* Ensure the device has been registrered */
+       err = -EINVAL;
+       if (dev->reg_state != NETREG_REGISTERED)
+               goto out;
+
+       /* Get out if there is nothing todo */
+       err = 0;
+       if (dev->nd_net == net)
+               goto out;
+
+       /* Pick the destination device name, and ensure
+        * we can use it in the destination network namespace.
+        */
+       err = -EEXIST;
+       destname = dev->name;
+       if (__dev_get_by_name(net, destname)) {
+               /* We get here if we can't use the current device name */
+               if (!pat)
+                       goto out;
+               if (!dev_valid_name(pat))
+                       goto out;
+               if (strchr(pat, '%')) {
+                       if (__dev_alloc_name(net, pat, buf) < 0)
+                               goto out;
+                       destname = buf;
+               } else
+                       destname = pat;
+               if (__dev_get_by_name(net, destname))
+                       goto out;
+       }
+
+       /*
+        * And now a mini version of register_netdevice unregister_netdevice.
+        */
+
+       /* If device is running close it first. */
+       dev_close(dev);
+
+       /* And unlink it from device chain */
+       err = -ENODEV;
+       unlist_netdevice(dev);
+
+       synchronize_net();
+
+       /* Shutdown queueing discipline. */
+       dev_shutdown(dev);
+
+       /* Notify protocols, that we are about to destroy
+          this device. They should clean all the things.
+       */
+       call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
+
+       /*
+        *      Flush the unicast and multicast chains
+        */
+       dev_addr_discard(dev);
+
+       /* Actually switch the network namespace */
+       dev->nd_net = net;
+
+       /* Assign the new device name */
+       if (destname != dev->name)
+               strcpy(dev->name, destname);
+
+       /* If there is an ifindex conflict assign a new one */
+       if (__dev_get_by_index(net, dev->ifindex)) {
+               int iflink = (dev->iflink == dev->ifindex);
+               dev->ifindex = dev_new_index(net);
+               if (iflink)
+                       dev->iflink = dev->ifindex;
+       }
+
+       /* Fixup kobjects */
+       err = device_rename(&dev->dev, dev->name);
+       WARN_ON(err);
+
+       /* Add the device back in the hashes */
+       list_netdevice(dev);
+
+       /* Notify protocols, that a new device appeared. */
+       call_netdevice_notifiers(NETDEV_REGISTER, dev);
+
+       synchronize_net();
+       err = 0;
+out:
+       return err;
+}
+
 static int dev_cpu_callback(struct notifier_block *nfb,
                            unsigned long action,
                            void *ocpu)
@@ -4138,45 +4282,82 @@ int netdev_compute_features(unsigned long all, unsigned long one)
 }
 EXPORT_SYMBOL(netdev_compute_features);
 
-/* Initialize per network namespace state */
-static int netdev_init(struct net *net)
+static struct hlist_head *netdev_create_hash(void)
 {
        int i;
-       INIT_LIST_HEAD(&net->dev_base_head);
-       rwlock_init(&dev_base_lock);
+       struct hlist_head *hash;
 
-       net->dev_name_head = kmalloc(
-               sizeof(*net->dev_name_head)*NETDEV_HASHENTRIES, GFP_KERNEL);
-       if (!net->dev_name_head)
-               return -ENOMEM;
+       hash = kmalloc(sizeof(*hash) * NETDEV_HASHENTRIES, GFP_KERNEL);
+       if (hash != NULL)
+               for (i = 0; i < NETDEV_HASHENTRIES; i++)
+                       INIT_HLIST_HEAD(&hash[i]);
 
-       net->dev_index_head = kmalloc(
-               sizeof(*net->dev_index_head)*NETDEV_HASHENTRIES, GFP_KERNEL);
-       if (!net->dev_index_head) {
-               kfree(net->dev_name_head);
-               return -ENOMEM;
-       }
+       return hash;
+}
 
-       for (i = 0; i < NETDEV_HASHENTRIES; i++)
-               INIT_HLIST_HEAD(&net->dev_name_head[i]);
+/* Initialize per network namespace state */
+static int __net_init netdev_init(struct net *net)
+{
+       INIT_LIST_HEAD(&net->dev_base_head);
+       rwlock_init(&dev_base_lock);
 
-       for (i = 0; i < NETDEV_HASHENTRIES; i++)
-               INIT_HLIST_HEAD(&net->dev_index_head[i]);
+       net->dev_name_head = netdev_create_hash();
+       if (net->dev_name_head == NULL)
+               goto err_name;
+
+       net->dev_index_head = netdev_create_hash();
+       if (net->dev_index_head == NULL)
+               goto err_idx;
 
        return 0;
+
+err_idx:
+       kfree(net->dev_name_head);
+err_name:
+       return -ENOMEM;
 }
 
-static void netdev_exit(struct net *net)
+static void __net_exit netdev_exit(struct net *net)
 {
        kfree(net->dev_name_head);
        kfree(net->dev_index_head);
 }
 
-static struct pernet_operations netdev_net_ops = {
+static struct pernet_operations __net_initdata netdev_net_ops = {
        .init = netdev_init,
        .exit = netdev_exit,
 };
 
+static void __net_exit default_device_exit(struct net *net)
+{
+       struct net_device *dev, *next;
+       /*
+        * Push all migratable of the network devices back to the
+        * initial network namespace
+        */
+       rtnl_lock();
+       for_each_netdev_safe(net, dev, next) {
+               int err;
+
+               /* Ignore unmoveable devices (i.e. loopback) */
+               if (dev->features & NETIF_F_NETNS_LOCAL)
+                       continue;
+
+               /* Push remaing network devices to init_net */
+               err = dev_change_net_namespace(dev, &init_net, "dev%d");
+               if (err) {
+                       printk(KERN_WARNING "%s: failed to move %s to init_net: %d\n",
+                               __func__, dev->name, err);
+                       unregister_netdevice(dev);
+               }
+       }
+       rtnl_unlock();
+}
+
+static struct pernet_operations __net_initdata default_device_ops = {
+       .exit = default_device_exit,
+};
+
 /*
  *     Initialize the DEV module. At boot time this walks the device list and
  *     unhooks any devices that fail to initialise (normally hardware not
@@ -4197,7 +4378,7 @@ static int __init net_dev_init(void)
        if (dev_proc_init())
                goto out;
 
-       if (netdev_sysfs_init())
+       if (netdev_kobject_init())
                goto out;
 
        INIT_LIST_HEAD(&ptype_all);
@@ -4207,6 +4388,9 @@ static int __init net_dev_init(void)
        if (register_pernet_subsys(&netdev_net_ops))
                goto out;
 
+       if (register_pernet_device(&default_device_ops))
+               goto out;
+
        /*
         *      Initialise the packet receive queues.
         */