]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/core/dev.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/czankel/xtensa-2.6
[linux-2.6-omap-h63xx.git] / net / core / dev.c
index daca72e6b37b12e7c8ea4d4ee5fa59e01cac1b59..382df6c09eecece6771b09a9e3fa93315798728b 100644 (file)
 /* Instead of increasing this, you should create a hash table. */
 #define MAX_GRO_SKBS 8
 
+/* This should be increased if a protocol with a bigger head is added. */
+#define GRO_MAX_HEAD (MAX_HEADER + 128)
+
 /*
  *     The list of packet types we will receive (as opposed to discard)
  *     and the routines to invoke.
@@ -2345,7 +2348,7 @@ static int napi_gro_complete(struct sk_buff *skb)
        struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK];
        int err = -ENOENT;
 
-       if (!skb_shinfo(skb)->frag_list)
+       if (NAPI_GRO_CB(skb)->count == 1)
                goto out;
 
        rcu_read_lock();
@@ -2365,6 +2368,7 @@ static int napi_gro_complete(struct sk_buff *skb)
        }
 
 out:
+       skb_shinfo(skb)->gso_size = 0;
        __skb_push(skb, -skb_network_offset(skb));
        return netif_receive_skb(skb);
 }
@@ -2383,14 +2387,16 @@ void napi_gro_flush(struct napi_struct *napi)
 }
 EXPORT_SYMBOL(napi_gro_flush);
 
-int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
+static int __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
 {
        struct sk_buff **pp = NULL;
        struct packet_type *ptype;
        __be16 type = skb->protocol;
        struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK];
        int count = 0;
+       int same_flow;
        int mac_len;
+       int free;
 
        if (!(skb->dev->features & NETIF_F_GRO))
                goto normal;
@@ -2407,6 +2413,7 @@ int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
                skb->mac_len = mac_len;
                NAPI_GRO_CB(skb)->same_flow = 0;
                NAPI_GRO_CB(skb)->flush = 0;
+               NAPI_GRO_CB(skb)->free = 0;
 
                for (p = napi->gro_list; p; p = p->next) {
                        count++;
@@ -2425,6 +2432,9 @@ int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
        if (&ptype->list == head)
                goto normal;
 
+       same_flow = NAPI_GRO_CB(skb)->same_flow;
+       free = NAPI_GRO_CB(skb)->free;
+
        if (pp) {
                struct sk_buff *nskb = *pp;
 
@@ -2434,7 +2444,7 @@ int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
                count--;
        }
 
-       if (NAPI_GRO_CB(skb)->same_flow)
+       if (same_flow)
                goto ok;
 
        if (NAPI_GRO_CB(skb)->flush || count >= MAX_GRO_SKBS) {
@@ -2443,17 +2453,91 @@ int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
        }
 
        NAPI_GRO_CB(skb)->count = 1;
+       skb_shinfo(skb)->gso_size = skb->len;
        skb->next = napi->gro_list;
        napi->gro_list = skb;
 
 ok:
-       return NET_RX_SUCCESS;
+       return free;
 
 normal:
-       return netif_receive_skb(skb);
+       return -1;
+}
+
+int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
+{
+       switch (__napi_gro_receive(napi, skb)) {
+       case -1:
+               return netif_receive_skb(skb);
+
+       case 1:
+               kfree_skb(skb);
+               break;
+       }
+
+       return NET_RX_SUCCESS;
 }
 EXPORT_SYMBOL(napi_gro_receive);
 
+int napi_gro_frags(struct napi_struct *napi, struct napi_gro_fraginfo *info)
+{
+       struct net_device *dev = napi->dev;
+       struct sk_buff *skb = napi->skb;
+       int err = NET_RX_DROP;
+
+       napi->skb = NULL;
+
+       if (!skb) {
+               skb = netdev_alloc_skb(dev, GRO_MAX_HEAD + NET_IP_ALIGN);
+               if (!skb)
+                       goto out;
+
+               skb_reserve(skb, NET_IP_ALIGN);
+       }
+
+       BUG_ON(info->nr_frags > MAX_SKB_FRAGS);
+       skb_shinfo(skb)->nr_frags = info->nr_frags;
+       memcpy(skb_shinfo(skb)->frags, info->frags, sizeof(info->frags));
+
+       skb->data_len = info->len;
+       skb->len += info->len;
+       skb->truesize += info->len;
+
+       if (!pskb_may_pull(skb, ETH_HLEN))
+               goto reuse;
+
+       err = NET_RX_SUCCESS;
+
+       skb->protocol = eth_type_trans(skb, dev);
+
+       skb->ip_summed = info->ip_summed;
+       skb->csum = info->csum;
+
+       switch (__napi_gro_receive(napi, skb)) {
+       case -1:
+               return netif_receive_skb(skb);
+
+       case 0:
+               goto out;
+       }
+
+reuse:
+       skb_shinfo(skb)->nr_frags = 0;
+
+       skb->len -= skb->data_len;
+       skb->truesize -= skb->data_len;
+       skb->data_len = 0;
+
+       __skb_pull(skb, skb_headlen(skb));
+       skb_reserve(skb, NET_IP_ALIGN - skb_headroom(skb));
+
+       napi->skb = skb;
+
+out:
+       return err;
+}
+EXPORT_SYMBOL(napi_gro_frags);
+
 static int process_backlog(struct napi_struct *napi, int quota)
 {
        int work = 0;
@@ -2532,11 +2616,12 @@ void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
 {
        INIT_LIST_HEAD(&napi->poll_list);
        napi->gro_list = NULL;
+       napi->skb = NULL;
        napi->poll = poll;
        napi->weight = weight;
        list_add(&napi->dev_list, &dev->napi_list);
-#ifdef CONFIG_NETPOLL
        napi->dev = dev;
+#ifdef CONFIG_NETPOLL
        spin_lock_init(&napi->poll_lock);
        napi->poll_owner = -1;
 #endif
@@ -2548,7 +2633,8 @@ void netif_napi_del(struct napi_struct *napi)
 {
        struct sk_buff *skb, *next;
 
-       list_del(&napi->dev_list);
+       list_del_init(&napi->dev_list);
+       kfree(napi->skb);
 
        for (skb = napi->gro_list; skb; skb = next) {
                next = skb->next;
@@ -3126,6 +3212,8 @@ static void dev_change_rx_flags(struct net_device *dev, int flags)
 static int __dev_set_promiscuity(struct net_device *dev, int inc)
 {
        unsigned short old_flags = dev->flags;
+       uid_t uid;
+       gid_t gid;
 
        ASSERT_RTNL();
 
@@ -3150,15 +3238,17 @@ static int __dev_set_promiscuity(struct net_device *dev, int inc)
                printk(KERN_INFO "device %s %s promiscuous mode\n",
                       dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
                                                               "left");
-               if (audit_enabled)
+               if (audit_enabled) {
+                       current_uid_gid(&uid, &gid);
                        audit_log(current->audit_context, GFP_ATOMIC,
                                AUDIT_ANOM_PROMISCUOUS,
                                "dev=%s prom=%d old_prom=%d auid=%u uid=%u gid=%u ses=%u",
                                dev->name, (dev->flags & IFF_PROMISC),
                                (old_flags & IFF_PROMISC),
                                audit_get_loginuid(current),
-                               current->uid, current->gid,
+                               uid, gid,
                                audit_get_sessionid(current));
+               }
 
                dev_change_rx_flags(dev, IFF_PROMISC);
        }
@@ -5059,13 +5149,14 @@ static struct pernet_operations __net_initdata netdev_net_ops = {
 
 static void __net_exit default_device_exit(struct net *net)
 {
-       struct net_device *dev, *next;
+       struct net_device *dev;
        /*
         * Push all migratable of the network devices back to the
         * initial network namespace
         */
        rtnl_lock();
-       for_each_netdev_safe(net, dev, next) {
+restart:
+       for_each_netdev(net, dev) {
                int err;
                char fb_name[IFNAMSIZ];
 
@@ -5076,7 +5167,7 @@ static void __net_exit default_device_exit(struct net *net)
                /* Delete virtual devices */
                if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) {
                        dev->rtnl_link_ops->dellink(dev);
-                       continue;
+                       goto restart;
                }
 
                /* Push remaing network devices to init_net */
@@ -5087,6 +5178,7 @@ static void __net_exit default_device_exit(struct net *net)
                                __func__, dev->name, err);
                        BUG();
                }
+               goto restart;
        }
        rtnl_unlock();
 }