aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_output.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2016-11-15 15:51:50 -0500
committerDavid S. Miller <davem@davemloft.net>2016-11-24 15:40:42 -0500
commitf8071cde7890db198201afa748efd658a8ba0fb2 (patch)
treeb237d496ebafad7eda06cdba81e50d003cdf191e /net/ipv4/tcp_output.c
parent7d381a025f01550350a1890ab782afc832399eb6 (diff)
tcp: enhance tcp_collapse_retrans() with skb_shift()
In commit 2331ccc5b323 ("tcp: enhance tcp collapsing"), we made a first step allowing copying right skb to left skb head. Since all skbs in socket write queue are headless (but possibly the very first one), this strategy often does not work. This patch extends tcp_collapse_retrans() to perform frag shifting, thanks to skb_shift() helper. This helper needs to not BUG on non headless skbs, as callers are ok with that. Tested: Following packetdrill test now passes : 0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0 bind(3, ..., ...) = 0 +0 listen(3, 1) = 0 +0 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 8> +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8> +.100 < . 1:1(0) ack 1 win 257 +0 accept(3, ..., ...) = 4 +0 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0 +0 write(4, ..., 200) = 200 +0 > P. 1:201(200) ack 1 +.001 write(4, ..., 200) = 200 +0 > P. 201:401(200) ack 1 +.001 write(4, ..., 200) = 200 +0 > P. 401:601(200) ack 1 +.001 write(4, ..., 200) = 200 +0 > P. 601:801(200) ack 1 +.001 write(4, ..., 200) = 200 +0 > P. 801:1001(200) ack 1 +.001 write(4, ..., 100) = 100 +0 > P. 1001:1101(100) ack 1 +.001 write(4, ..., 100) = 100 +0 > P. 1101:1201(100) ack 1 +.001 write(4, ..., 100) = 100 +0 > P. 1201:1301(100) ack 1 +.001 write(4, ..., 100) = 100 +0 > P. 1301:1401(100) ack 1 +.099 < . 1:1(0) ack 201 win 257 +.001 < . 1:1(0) ack 201 win 257 <nop,nop,sack 1001:1401> +0 > P. 201:1001(800) ack 1 Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Neal Cardwell <ncardwell@google.com> Cc: Yuchung Cheng <ycheng@google.com> Acked-by: Yuchung Cheng <ycheng@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_output.c')
-rw-r--r--net/ipv4/tcp_output.c22
1 files changed, 11 insertions, 11 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index f57b5aa51b59..19105b46a304 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2514,7 +2514,7 @@ void tcp_skb_collapse_tstamp(struct sk_buff *skb,
2514} 2514}
2515 2515
2516/* Collapses two adjacent SKB's during retransmission. */ 2516/* Collapses two adjacent SKB's during retransmission. */
2517static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb) 2517static bool tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb)
2518{ 2518{
2519 struct tcp_sock *tp = tcp_sk(sk); 2519 struct tcp_sock *tp = tcp_sk(sk);
2520 struct sk_buff *next_skb = tcp_write_queue_next(sk, skb); 2520 struct sk_buff *next_skb = tcp_write_queue_next(sk, skb);
@@ -2525,14 +2525,17 @@ static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb)
2525 2525
2526 BUG_ON(tcp_skb_pcount(skb) != 1 || tcp_skb_pcount(next_skb) != 1); 2526 BUG_ON(tcp_skb_pcount(skb) != 1 || tcp_skb_pcount(next_skb) != 1);
2527 2527
2528 if (next_skb_size) {
2529 if (next_skb_size <= skb_availroom(skb))
2530 skb_copy_bits(next_skb, 0, skb_put(skb, next_skb_size),
2531 next_skb_size);
2532 else if (!skb_shift(skb, next_skb, next_skb_size))
2533 return false;
2534 }
2528 tcp_highest_sack_combine(sk, next_skb, skb); 2535 tcp_highest_sack_combine(sk, next_skb, skb);
2529 2536
2530 tcp_unlink_write_queue(next_skb, sk); 2537 tcp_unlink_write_queue(next_skb, sk);
2531 2538
2532 if (next_skb_size)
2533 skb_copy_bits(next_skb, 0, skb_put(skb, next_skb_size),
2534 next_skb_size);
2535
2536 if (next_skb->ip_summed == CHECKSUM_PARTIAL) 2539 if (next_skb->ip_summed == CHECKSUM_PARTIAL)
2537 skb->ip_summed = CHECKSUM_PARTIAL; 2540 skb->ip_summed = CHECKSUM_PARTIAL;
2538 2541
@@ -2561,6 +2564,7 @@ static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb)
2561 tcp_skb_collapse_tstamp(skb, next_skb); 2564 tcp_skb_collapse_tstamp(skb, next_skb);
2562 2565
2563 sk_wmem_free_skb(sk, next_skb); 2566 sk_wmem_free_skb(sk, next_skb);
2567 return true;
2564} 2568}
2565 2569
2566/* Check if coalescing SKBs is legal. */ 2570/* Check if coalescing SKBs is legal. */
@@ -2610,16 +2614,12 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to,
2610 2614
2611 if (space < 0) 2615 if (space < 0)
2612 break; 2616 break;
2613 /* Punt if not enough space exists in the first SKB for
2614 * the data in the second
2615 */
2616 if (skb->len > skb_availroom(to))
2617 break;
2618 2617
2619 if (after(TCP_SKB_CB(skb)->end_seq, tcp_wnd_end(tp))) 2618 if (after(TCP_SKB_CB(skb)->end_seq, tcp_wnd_end(tp)))
2620 break; 2619 break;
2621 2620
2622 tcp_collapse_retrans(sk, to); 2621 if (!tcp_collapse_retrans(sk, to))
2622 break;
2623 } 2623 }
2624} 2624}
2625 2625