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. 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>
This commit is contained in:
parent
787e920836
commit
684f217601
|
@ -2542,6 +2542,7 @@ out:
|
|||
|
||||
return pp;
|
||||
}
|
||||
EXPORT_SYMBOL(tcp_gro_receive);
|
||||
|
||||
int tcp_gro_complete(struct sk_buff *skb)
|
||||
{
|
||||
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -1429,14 +1464,14 @@ out:
|
|||
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));
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue