Merge branch 'cpus4096' into irq/threaded
[safe/jmp/linux-2.6] / net / ipv4 / af_inet.c
index b1462e8..3a3dad8 100644 (file)
@@ -94,6 +94,7 @@
 #include <linux/igmp.h>
 #include <linux/inetdevice.h>
 #include <linux/netdevice.h>
+#include <net/checksum.h>
 #include <net/ip.h>
 #include <net/protocol.h>
 #include <net/arp.h>
@@ -245,7 +246,7 @@ static inline int inet_netns_ok(struct net *net, int protocol)
        int hash;
        struct net_protocol *ipprot;
 
-       if (net == &init_net)
+       if (net_eq(net, &init_net))
                return 1;
 
        hash = protocol & (MAX_INET_PROTOS - 1);
@@ -272,10 +273,9 @@ static int inet_create(struct net *net, struct socket *sock, int protocol)
        int try_loading_module = 0;
        int err;
 
-       if (sock->type != SOCK_RAW &&
-           sock->type != SOCK_DGRAM &&
-           !inet_ehash_secret)
-               build_ehash_secret();
+       if (unlikely(!inet_ehash_secret))
+               if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)
+                       build_ehash_secret();
 
        sock->state = SS_UNCONNECTED;
 
@@ -1242,6 +1242,100 @@ out:
        return segs;
 }
 
+static struct sk_buff **inet_gro_receive(struct sk_buff **head,
+                                        struct sk_buff *skb)
+{
+       struct net_protocol *ops;
+       struct sk_buff **pp = NULL;
+       struct sk_buff *p;
+       struct iphdr *iph;
+       int flush = 1;
+       int proto;
+       int id;
+
+       if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
+               goto out;
+
+       iph = ip_hdr(skb);
+       proto = iph->protocol & (MAX_INET_PROTOS - 1);
+
+       rcu_read_lock();
+       ops = rcu_dereference(inet_protos[proto]);
+       if (!ops || !ops->gro_receive)
+               goto out_unlock;
+
+       if (iph->version != 4 || iph->ihl != 5)
+               goto out_unlock;
+
+       if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
+               goto out_unlock;
+
+       flush = ntohs(iph->tot_len) != skb->len ||
+               iph->frag_off != htons(IP_DF);
+       id = ntohs(iph->id);
+
+       for (p = *head; p; p = p->next) {
+               struct iphdr *iph2;
+
+               if (!NAPI_GRO_CB(p)->same_flow)
+                       continue;
+
+               iph2 = ip_hdr(p);
+
+               if (iph->protocol != iph2->protocol ||
+                   iph->tos != iph2->tos ||
+                   memcmp(&iph->saddr, &iph2->saddr, 8)) {
+                       NAPI_GRO_CB(p)->same_flow = 0;
+                       continue;
+               }
+
+               /* All fields must match except length and checksum. */
+               NAPI_GRO_CB(p)->flush |=
+                       memcmp(&iph->frag_off, &iph2->frag_off, 4) ||
+                       (u16)(ntohs(iph2->id) + NAPI_GRO_CB(p)->count) != id;
+
+               NAPI_GRO_CB(p)->flush |= flush;
+       }
+
+       NAPI_GRO_CB(skb)->flush |= flush;
+       __skb_pull(skb, sizeof(*iph));
+       skb_reset_transport_header(skb);
+
+       pp = ops->gro_receive(head, skb);
+
+out_unlock:
+       rcu_read_unlock();
+
+out:
+       NAPI_GRO_CB(skb)->flush |= flush;
+
+       return pp;
+}
+
+static int inet_gro_complete(struct sk_buff *skb)
+{
+       struct net_protocol *ops;
+       struct iphdr *iph = ip_hdr(skb);
+       int proto = iph->protocol & (MAX_INET_PROTOS - 1);
+       int err = -ENOSYS;
+       __be16 newlen = htons(skb->len - skb_network_offset(skb));
+
+       csum_replace2(&iph->check, iph->tot_len, newlen);
+       iph->tot_len = newlen;
+
+       rcu_read_lock();
+       ops = rcu_dereference(inet_protos[proto]);
+       if (WARN_ON(!ops || !ops->gro_complete))
+               goto out_unlock;
+
+       err = ops->gro_complete(skb);
+
+out_unlock:
+       rcu_read_unlock();
+
+       return err;
+}
+
 int inet_ctl_sock_create(struct sock **sk, unsigned short family,
                         unsigned short type, unsigned char protocol,
                         struct net *net)
@@ -1281,10 +1375,10 @@ EXPORT_SYMBOL_GPL(snmp_fold_field);
 int snmp_mib_init(void *ptr[2], size_t mibsize)
 {
        BUG_ON(ptr == NULL);
-       ptr[0] = __alloc_percpu(mibsize);
+       ptr[0] = __alloc_percpu(mibsize, __alignof__(unsigned long long));
        if (!ptr[0])
                goto err0;
-       ptr[1] = __alloc_percpu(mibsize);
+       ptr[1] = __alloc_percpu(mibsize, __alignof__(unsigned long long));
        if (!ptr[1])
                goto err1;
        return 0;
@@ -1308,6 +1402,7 @@ EXPORT_SYMBOL_GPL(snmp_mib_free);
 #ifdef CONFIG_IP_MULTICAST
 static struct net_protocol igmp_protocol = {
        .handler =      igmp_rcv,
+       .netns_ok =     1,
 };
 #endif
 
@@ -1316,6 +1411,8 @@ static struct net_protocol tcp_protocol = {
        .err_handler =  tcp_v4_err,
        .gso_send_check = tcp_v4_gso_send_check,
        .gso_segment =  tcp_tso_segment,
+       .gro_receive =  tcp4_gro_receive,
+       .gro_complete = tcp4_gro_complete,
        .no_policy =    1,
        .netns_ok =     1,
 };
@@ -1408,6 +1505,8 @@ static struct packet_type ip_packet_type = {
        .func = ip_rcv,
        .gso_send_check = inet_gso_send_check,
        .gso_segment = inet_gso_segment,
+       .gro_receive = inet_gro_receive,
+       .gro_complete = inet_gro_complete,
 };
 
 static int __init inet_init(void)