Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 3156

kernel-2.6.18-238.el5.src.rpm

From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Wed, 27 May 2009 15:31:22 +1000
Subject: [net] tcp6: add GRO support
Message-id: E1M9BjW-0002Cj-OR@gondolin.me.apana.org.au
O-Subject: [PATCH 17/17] tcp6: Add GRO support
Bugzilla: 499347
RH-Acked-by: David Miller <davem@redhat.com>
RH-Acked-by: Neil Horman <nhorman@redhat.com>
RH-Acked-by: Thomas Graf <tgraf@redhat.com>

RHEL5 bugzilla #499347

tcp6: Add GRO support

This patch adds GRO support for TCP over IPv6.  The code is exactly
the same as the IPv4 version except for the pseudo-header checksum
computation.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>

diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index d525846..38840ff 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -578,6 +578,40 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb)
 	return 0;
 }
 
+static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
+					 struct sk_buff *skb)
+{
+	struct ipv6hdr *iph = skb_gro_network_header(skb);
+
+	switch (skb->ip_summed) {
+	case CHECKSUM_COMPLETE:
+		if (!tcp_v6_check(NULL, skb_gro_len(skb), &iph->saddr,
+				  &iph->daddr, skb->csum)) {
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+			break;
+		}
+
+		/* fall through */
+	case CHECKSUM_NONE:
+		NAPI_GRO_CB(skb)->flush = 1;
+		return NULL;
+	}
+
+	return tcp_gro_receive(head, skb);
+}
+
+static int tcp6_gro_complete(struct sk_buff *skb)
+{
+	struct ipv6hdr *iph = ipv6_hdr(skb);
+	struct tcphdr *th = tcp_hdr(skb);
+
+	th->check = ~tcp_v6_check(NULL, skb->len - skb_transport_offset(skb),
+				  &iph->saddr, &iph->daddr, 0);
+	skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+
+	return tcp_gro_complete(skb);
+}
+
 static void tcp_v6_send_reset(struct sk_buff *skb)
 {
 	struct tcphdr *th = skb->h.th, *t1; 
@@ -1638,6 +1672,11 @@ static struct inet6_protocol tcpv6_protocol = {
 	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
+static struct inet6_gro_protocol tcpv6_gro_protocol = {
+	.gro_receive	=	tcp6_gro_receive,
+	.gro_complete	=	tcp6_gro_complete,
+};
+
 static struct inet_protosw tcpv6_protosw = {
 	.type		=	SOCK_STREAM,
 	.protocol	=	IPPROTO_TCP,
@@ -1654,6 +1693,8 @@ void __init tcpv6_init(void)
 	/* register inet6 protocol */
 	if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0)
 		printk(KERN_ERR "tcpv6_init: Could not register protocol\n");
+	if (inet6_add_gro_protocol(&tcpv6_gro_protocol, IPPROTO_TCP) < 0)
+		panic("tcpv6_init: Could not register protocol\n");
 	inet6_register_protosw(&tcpv6_protosw);
 
 	if (inet_csk_ctl_sock_create(&tcp6_socket, PF_INET6, SOCK_RAW,