netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Regression with commit 971f10eca186 ("tcp: better TCP_SKB_CB layout to reduce cache line misses")
@ 2014-12-22 15:17 Nicolas Dichtel
  2014-12-22 16:15 ` Eric Dumazet
  0 siblings, 1 reply; 5+ messages in thread
From: Nicolas Dichtel @ 2014-12-22 15:17 UTC (permalink / raw)
  To: netdev, Eric Dumazet

One of our engineer (Huaibin Wang <huaibin.wang@6wind.com>) has reported and
analysed this bug:

This commit introduces a regression with IPv6 + IPsec transport + TCP.

In TCP (net/ipv6/tcp_ipv6.c), xfrm6_policy_check() is called and thus, after
some intermediate functions, _decode_session6() is also called.

This function uses IP6CB() (u8 nexthdr = nh[IP6CB(skb)->nhoff]), which is wrong
becauses it has been moved to the end of TCP_SKB_CB().

Not sure what is the best way to fix this, any suggestion?

Regards,
Nicolas

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Regression with commit 971f10eca186 ("tcp: better TCP_SKB_CB layout to reduce cache line misses")
  2014-12-22 15:17 Regression with commit 971f10eca186 ("tcp: better TCP_SKB_CB layout to reduce cache line misses") Nicolas Dichtel
@ 2014-12-22 16:15 ` Eric Dumazet
  2014-12-22 16:54   ` Nicolas Dichtel
  2014-12-22 17:22   ` [PATCH net] tcp6: don't move IP6CB before xfrm6_policy_check() Nicolas Dichtel
  0 siblings, 2 replies; 5+ messages in thread
From: Eric Dumazet @ 2014-12-22 16:15 UTC (permalink / raw)
  To: nicolas.dichtel; +Cc: netdev, Eric Dumazet

On Mon, 2014-12-22 at 16:17 +0100, Nicolas Dichtel wrote:
> One of our engineer (Huaibin Wang <huaibin.wang@6wind.com>) has reported and
> analysed this bug:
> 
> This commit introduces a regression with IPv6 + IPsec transport + TCP.
> 
> In TCP (net/ipv6/tcp_ipv6.c), xfrm6_policy_check() is called and thus, after
> some intermediate functions, _decode_session6() is also called.
> 
> This function uses IP6CB() (u8 nexthdr = nh[IP6CB(skb)->nhoff]), which is wrong
> becauses it has been moved to the end of TCP_SKB_CB().
> 
> Not sure what is the best way to fix this, any suggestion?

Thanks for the report

Presumably tcp_v6_rcv() needs to be reordered so that
xfrm6_policy_check() calls are done before the CB swap.

swap should probably be done right before bh_lock_sock_nested()

I am currently traveling and I am not sure if I can get Internet access
to post a patch soon.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Regression with commit 971f10eca186 ("tcp: better TCP_SKB_CB layout to reduce cache line misses")
  2014-12-22 16:15 ` Eric Dumazet
@ 2014-12-22 16:54   ` Nicolas Dichtel
  2014-12-22 17:22   ` [PATCH net] tcp6: don't move IP6CB before xfrm6_policy_check() Nicolas Dichtel
  1 sibling, 0 replies; 5+ messages in thread
From: Nicolas Dichtel @ 2014-12-22 16:54 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: netdev, Eric Dumazet

Le 22/12/2014 17:15, Eric Dumazet a écrit :
> On Mon, 2014-12-22 at 16:17 +0100, Nicolas Dichtel wrote:
>> One of our engineer (Huaibin Wang <huaibin.wang@6wind.com>) has reported and
>> analysed this bug:
>>
>> This commit introduces a regression with IPv6 + IPsec transport + TCP.
>>
>> In TCP (net/ipv6/tcp_ipv6.c), xfrm6_policy_check() is called and thus, after
>> some intermediate functions, _decode_session6() is also called.
>>
>> This function uses IP6CB() (u8 nexthdr = nh[IP6CB(skb)->nhoff]), which is wrong
>> becauses it has been moved to the end of TCP_SKB_CB().
>>
>> Not sure what is the best way to fix this, any suggestion?
>
> Thanks for the report
>
> Presumably tcp_v6_rcv() needs to be reordered so that
> xfrm6_policy_check() calls are done before the CB swap.
>
> swap should probably be done right before bh_lock_sock_nested()
>
> I am currently traveling and I am not sure if I can get Internet access
> to post a patch soon.
Ok, thank you for the tip. I will try to cook a patch.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH net] tcp6: don't move IP6CB before xfrm6_policy_check()
  2014-12-22 16:15 ` Eric Dumazet
  2014-12-22 16:54   ` Nicolas Dichtel
@ 2014-12-22 17:22   ` Nicolas Dichtel
  2014-12-22 21:48     ` David Miller
  1 sibling, 1 reply; 5+ messages in thread
From: Nicolas Dichtel @ 2014-12-22 17:22 UTC (permalink / raw)
  To: davem, eric.dumazet; +Cc: netdev, Nicolas Dichtel

When xfrm6_policy_check() is used, _decode_session6() is called after some
intermediate functions. This function uses IP6CB(), thus TCP_SKB_CB() must be
prepared after the call of xfrm6_policy_check().

Before this patch, scenarii with IPv6 + TCP + IPsec Transport are broken.

Fixes: 971f10eca186 ("tcp: better TCP_SKB_CB layout to reduce cache line misses")
Reported-by: Huaibin Wang <huaibin.wang@6wind.com>
Suggested-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 net/ipv6/tcp_ipv6.c | 45 +++++++++++++++++++++++++++++----------------
 1 file changed, 29 insertions(+), 16 deletions(-)

diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 5ff87805258e..9c0b54e87b47 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1387,6 +1387,28 @@ ipv6_pktoptions:
 	return 0;
 }
 
+static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr,
+			   const struct tcphdr *th)
+{
+	/* This is tricky: we move IP6CB at its correct location into
+	 * TCP_SKB_CB(). It must be done after xfrm6_policy_check(), because
+	 * _decode_session6() uses IP6CB().
+	 * barrier() makes sure compiler won't play aliasing games.
+	 */
+	memmove(&TCP_SKB_CB(skb)->header.h6, IP6CB(skb),
+		sizeof(struct inet6_skb_parm));
+	barrier();
+
+	TCP_SKB_CB(skb)->seq = ntohl(th->seq);
+	TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
+				    skb->len - th->doff*4);
+	TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
+	TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th);
+	TCP_SKB_CB(skb)->tcp_tw_isn = 0;
+	TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr);
+	TCP_SKB_CB(skb)->sacked = 0;
+}
+
 static int tcp_v6_rcv(struct sk_buff *skb)
 {
 	const struct tcphdr *th;
@@ -1418,24 +1440,9 @@ static int tcp_v6_rcv(struct sk_buff *skb)
 
 	th = tcp_hdr(skb);
 	hdr = ipv6_hdr(skb);
-	/* This is tricky : We move IPCB at its correct location into TCP_SKB_CB()
-	 * barrier() makes sure compiler wont play fool^Waliasing games.
-	 */
-	memmove(&TCP_SKB_CB(skb)->header.h6, IP6CB(skb),
-		sizeof(struct inet6_skb_parm));
-	barrier();
-
-	TCP_SKB_CB(skb)->seq = ntohl(th->seq);
-	TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
-				    skb->len - th->doff*4);
-	TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
-	TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th);
-	TCP_SKB_CB(skb)->tcp_tw_isn = 0;
-	TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr);
-	TCP_SKB_CB(skb)->sacked = 0;
 
 	sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest,
-				tcp_v6_iif(skb));
+				inet6_iif(skb));
 	if (!sk)
 		goto no_tcp_socket;
 
@@ -1451,6 +1458,8 @@ process:
 	if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
 		goto discard_and_relse;
 
+	tcp_v6_fill_cb(skb, hdr, th);
+
 #ifdef CONFIG_TCP_MD5SIG
 	if (tcp_v6_inbound_md5_hash(sk, skb))
 		goto discard_and_relse;
@@ -1482,6 +1491,8 @@ no_tcp_socket:
 	if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
 		goto discard_it;
 
+	tcp_v6_fill_cb(skb, hdr, th);
+
 	if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
 csum_error:
 		TCP_INC_STATS_BH(net, TCP_MIB_CSUMERRORS);
@@ -1505,6 +1516,8 @@ do_time_wait:
 		goto discard_it;
 	}
 
+	tcp_v6_fill_cb(skb, hdr, th);
+
 	if (skb->len < (th->doff<<2)) {
 		inet_twsk_put(inet_twsk(sk));
 		goto bad_packet;
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH net] tcp6: don't move IP6CB before xfrm6_policy_check()
  2014-12-22 17:22   ` [PATCH net] tcp6: don't move IP6CB before xfrm6_policy_check() Nicolas Dichtel
@ 2014-12-22 21:48     ` David Miller
  0 siblings, 0 replies; 5+ messages in thread
From: David Miller @ 2014-12-22 21:48 UTC (permalink / raw)
  To: nicolas.dichtel; +Cc: eric.dumazet, netdev

From: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Date: Mon, 22 Dec 2014 18:22:48 +0100

> When xfrm6_policy_check() is used, _decode_session6() is called after some
> intermediate functions. This function uses IP6CB(), thus TCP_SKB_CB() must be
> prepared after the call of xfrm6_policy_check().
> 
> Before this patch, scenarii with IPv6 + TCP + IPsec Transport are broken.
> 
> Fixes: 971f10eca186 ("tcp: better TCP_SKB_CB layout to reduce cache line misses")
> Reported-by: Huaibin Wang <huaibin.wang@6wind.com>
> Suggested-by: Eric Dumazet <edumazet@google.com>
> Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>

Applied and queued up for -stable, thanks everyone.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2014-12-22 21:48 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-12-22 15:17 Regression with commit 971f10eca186 ("tcp: better TCP_SKB_CB layout to reduce cache line misses") Nicolas Dichtel
2014-12-22 16:15 ` Eric Dumazet
2014-12-22 16:54   ` Nicolas Dichtel
2014-12-22 17:22   ` [PATCH net] tcp6: don't move IP6CB before xfrm6_policy_check() Nicolas Dichtel
2014-12-22 21:48     ` David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).