[NET]: Avoid copying TCP packets unnecessarily
[deliverable/linux.git] / net / core / dev.c
index 13a1bc5d3bfdf3ea0b4443d6997d66a542dd70e4..38b03da5c1ca93d061cfe250195bbfc8898b9da6 100644 (file)
@@ -557,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
@@ -581,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
@@ -604,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
@@ -629,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
@@ -651,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
  *
@@ -709,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
  *
@@ -948,6 +954,7 @@ void netdev_state_change(struct net_device *dev)
 
 /**
  *     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
@@ -1185,7 +1192,7 @@ 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().
@@ -1355,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:
@@ -1942,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_RTTL(skb->tc_verd, ttl);
+       skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS);
 
-               skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_INGRESS);
+       spin_lock(&dev->ingress_lock);
+       if ((q = dev->qdisc_ingress) != NULL)
+               result = q->enqueue(skb, q);
+       spin_unlock(&dev->ingress_lock);
 
-               spin_lock(&dev->ingress_lock);
-               if ((q = dev->qdisc_ingress) != NULL)
-                       result = q->enqueue(skb, q);
-               spin_unlock(&dev->ingress_lock);
+       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;
+
+       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);
        }
 
-       return result;
+       switch (ing_filter(skb)) {
+       case TC_ACT_SHOT:
+       case TC_ACT_STOLEN:
+               kfree_skb(skb);
+               return NULL;
+       }
+
+out:
+       skb->tc_verd = 0;
+       return skb;
 }
 #endif
 
@@ -2014,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
 
@@ -2097,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
  */
@@ -2611,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;
 
@@ -2636,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);
 
@@ -2645,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,
 };
@@ -3083,9 +3101,9 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa)
 }
 
 /*
- *     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);
@@ -3098,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);
@@ -3126,6 +3134,61 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
                        ifr->ifr_hwaddr.sa_family = dev->type;
                        return 0;
 
+               case SIOCGIFSLAVE:
+                       err = -EINVAL;
+                       break;
+
+               case SIOCGIFMAP:
+                       ifr->ifr_map.mem_start = dev->mem_start;
+                       ifr->ifr_map.mem_end   = dev->mem_end;
+                       ifr->ifr_map.base_addr = dev->base_addr;
+                       ifr->ifr_map.irq       = dev->irq;
+                       ifr->ifr_map.dma       = dev->dma;
+                       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);
 
@@ -3137,15 +3200,6 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
                        call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
                        return 0;
 
-               case SIOCGIFMAP:
-                       ifr->ifr_map.mem_start = dev->mem_start;
-                       ifr->ifr_map.mem_end   = dev->mem_end;
-                       ifr->ifr_map.base_addr = dev->base_addr;
-                       ifr->ifr_map.irq       = dev->irq;
-                       ifr->ifr_map.dma       = dev->dma;
-                       ifr->ifr_map.port      = dev->if_port;
-                       return 0;
-
                case SIOCSIFMAP:
                        if (dev->set_config) {
                                if (!netif_device_present(dev))
@@ -3172,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;
@@ -3231,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
  *
@@ -3290,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)
@@ -3408,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
@@ -3865,8 +3913,7 @@ 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. */
        unlist_netdevice(dev);
@@ -3990,8 +4037,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
         */
 
        /* If device is running close it first. */
-       if (dev->flags & IFF_UP)
-               dev_close(dev);
+       dev_close(dev);
 
        /* And unlink it from device chain */
        err = -ENODEV;
@@ -4250,7 +4296,7 @@ static struct hlist_head *netdev_create_hash(void)
 }
 
 /* Initialize per network namespace state */
-static int netdev_init(struct net *net)
+static int __net_init netdev_init(struct net *net)
 {
        INIT_LIST_HEAD(&net->dev_base_head);
        rwlock_init(&dev_base_lock);
@@ -4271,18 +4317,18 @@ 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 default_device_exit(struct net *net)
+static void __net_exit default_device_exit(struct net *net)
 {
        struct net_device *dev, *next;
        /*
@@ -4308,7 +4354,7 @@ static void default_device_exit(struct net *net)
        rtnl_unlock();
 }
 
-static struct pernet_operations default_device_ops = {
+static struct pernet_operations __net_initdata default_device_ops = {
        .exit = default_device_exit,
 };
 
This page took 0.031264 seconds and 5 git commands to generate.