| From foo@baz Wed May 31 09:13:34 JST 2017 |
| From: Yuchung Cheng <ycheng@google.com> |
| Date: Wed, 10 May 2017 17:01:27 -0700 |
| Subject: tcp: avoid fragmenting peculiar skbs in SACK |
| |
| From: Yuchung Cheng <ycheng@google.com> |
| |
| |
| [ Upstream commit b451e5d24ba6687c6f0e7319c727a709a1846c06 ] |
| |
| This patch fixes a bug in splitting an SKB during SACK |
| processing. Specifically if an skb contains multiple |
| packets and is only partially sacked in the higher sequences, |
| tcp_match_sack_to_skb() splits the skb and marks the second fragment |
| as SACKed. |
| |
| The current code further attempts rounding up the first fragment |
| to MSS boundaries. But it misses a boundary condition when the |
| rounded-up fragment size (pkt_len) is exactly skb size. Spliting |
| such an skb is pointless and causses a kernel warning and aborts |
| the SACK processing. This patch universally checks such over-split |
| before calling tcp_fragment to prevent these unnecessary warnings. |
| |
| Fixes: adb92db857ee ("tcp: Make SACK code to split only at mss boundaries") |
| Signed-off-by: Yuchung Cheng <ycheng@google.com> |
| Signed-off-by: Eric Dumazet <edumazet@google.com> |
| Signed-off-by: Soheil Hassas Yeganeh <soheil@google.com> |
| Acked-by: Neal Cardwell <ncardwell@google.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ipv4/tcp_input.c | 9 +++++---- |
| 1 file changed, 5 insertions(+), 4 deletions(-) |
| |
| --- a/net/ipv4/tcp_input.c |
| +++ b/net/ipv4/tcp_input.c |
| @@ -1177,13 +1177,14 @@ static int tcp_match_skb_to_sack(struct |
| */ |
| if (pkt_len > mss) { |
| unsigned int new_len = (pkt_len / mss) * mss; |
| - if (!in_sack && new_len < pkt_len) { |
| + if (!in_sack && new_len < pkt_len) |
| new_len += mss; |
| - if (new_len >= skb->len) |
| - return 0; |
| - } |
| pkt_len = new_len; |
| } |
| + |
| + if (pkt_len >= skb->len && !in_sack) |
| + return 0; |
| + |
| err = tcp_fragment(sk, skb, pkt_len, mss, GFP_ATOMIC); |
| if (err < 0) |
| return err; |