Skip to content

Commit

Permalink
tcp6: Add GRO support
Browse files Browse the repository at this point in the history
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.

Note that I've removed the unused tcphdr argument from tcp_v6_check
rather than invent a bogus value for GRO.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Herbert Xu authored and David S. Miller committed Jan 8, 2009
1 parent 787e920 commit 684f217
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 4 deletions.
2 changes: 2 additions & 0 deletions net/ipv4/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -2542,6 +2542,7 @@ struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb)

return pp;
}
EXPORT_SYMBOL(tcp_gro_receive);

int tcp_gro_complete(struct sk_buff *skb)
{
Expand All @@ -2558,6 +2559,7 @@ int tcp_gro_complete(struct sk_buff *skb)

return 0;
}
EXPORT_SYMBOL(tcp_gro_complete);

#ifdef CONFIG_TCP_MD5SIG
static unsigned long tcp_md5sig_users;
Expand Down
45 changes: 41 additions & 4 deletions net/ipv6/tcp_ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ static void tcp_v6_hash(struct sock *sk)
}
}

static __inline__ __sum16 tcp_v6_check(struct tcphdr *th, int len,
static __inline__ __sum16 tcp_v6_check(int len,
struct in6_addr *saddr,
struct in6_addr *daddr,
__wsum base)
Expand Down Expand Up @@ -501,7 +501,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req)
if (skb) {
struct tcphdr *th = tcp_hdr(skb);

th->check = tcp_v6_check(th, skb->len,
th->check = tcp_v6_check(skb->len,
&treq->loc_addr, &treq->rmt_addr,
csum_partial(th, skb->len, skb->csum));

Expand Down Expand Up @@ -942,6 +942,41 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb)
return 0;
}

struct sk_buff **tcp6_gro_receive(struct sk_buff **head, struct sk_buff *skb)
{
struct ipv6hdr *iph = ipv6_hdr(skb);

switch (skb->ip_summed) {
case CHECKSUM_COMPLETE:
if (!tcp_v6_check(skb->len, &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);
}
EXPORT_SYMBOL(tcp6_gro_receive);

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(skb->len - skb_transport_offset(skb),
&iph->saddr, &iph->daddr, 0);
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;

return tcp_gro_complete(skb);
}
EXPORT_SYMBOL(tcp6_gro_complete);

static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
u32 ts, struct tcp_md5sig_key *key, int rst)
{
Expand Down Expand Up @@ -1429,14 +1464,14 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
static __sum16 tcp_v6_checksum_init(struct sk_buff *skb)
{
if (skb->ip_summed == CHECKSUM_COMPLETE) {
if (!tcp_v6_check(tcp_hdr(skb), skb->len, &ipv6_hdr(skb)->saddr,
if (!tcp_v6_check(skb->len, &ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr, skb->csum)) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
return 0;
}
}

skb->csum = ~csum_unfold(tcp_v6_check(tcp_hdr(skb), skb->len,
skb->csum = ~csum_unfold(tcp_v6_check(skb->len,
&ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr, 0));

Expand Down Expand Up @@ -2062,6 +2097,8 @@ static struct inet6_protocol tcpv6_protocol = {
.err_handler = tcp_v6_err,
.gso_send_check = tcp_v6_gso_send_check,
.gso_segment = tcp_tso_segment,
.gro_receive = tcp6_gro_receive,
.gro_complete = tcp6_gro_complete,
.flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
};

Expand Down

0 comments on commit 684f217

Please sign in to comment.