tcp: fix false reordering signal in tcp_shifted_skb
When tcp_shifted_skb() shifts bytes from the skb that is currently pointed to by 'highest_sack' then the increment of TCP_SKB_CB(skb)->seq implicitly advances tcp_highest_sack_seq(). This implicit advancement, combined with the recent fix to pass the correct SACKed range into tcp_sacktag_one(), caused tcp_sacktag_one() to think that the newly SACKed range was before the tcp_highest_sack_seq(), leading to a call to tcp_update_reordering() with a degree of reordering matching the size of the newly SACKed range (typically just 1 packet, which is a NOP, but potentially larger). This commit fixes this by simply calling tcp_sacktag_one() before the TCP_SKB_CB(skb)->seq advancement that can advance our notion of the highest SACKed sequence. Correspondingly, we can simplify the code a little now that tcp_shifted_skb() should update the lost_cnt_hint in all cases where skb == tp->lost_skb_hint. Signed-off-by: Neal Cardwell <ncardwell@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ecb9719236
commit
4c90d3b303
@ -1403,8 +1403,16 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
|
||||
|
||||
BUG_ON(!pcount);
|
||||
|
||||
/* Adjust hint for FACK. Non-FACK is handled in tcp_sacktag_one(). */
|
||||
if (tcp_is_fack(tp) && (skb == tp->lost_skb_hint))
|
||||
/* Adjust counters and hints for the newly sacked sequence
|
||||
* range but discard the return value since prev is already
|
||||
* marked. We must tag the range first because the seq
|
||||
* advancement below implicitly advances
|
||||
* tcp_highest_sack_seq() when skb is highest_sack.
|
||||
*/
|
||||
tcp_sacktag_one(sk, state, TCP_SKB_CB(skb)->sacked,
|
||||
start_seq, end_seq, dup_sack, pcount);
|
||||
|
||||
if (skb == tp->lost_skb_hint)
|
||||
tp->lost_cnt_hint += pcount;
|
||||
|
||||
TCP_SKB_CB(prev)->end_seq += shifted;
|
||||
@ -1430,12 +1438,6 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
|
||||
skb_shinfo(skb)->gso_type = 0;
|
||||
}
|
||||
|
||||
/* Adjust counters and hints for the newly sacked sequence range but
|
||||
* discard the return value since prev is already marked.
|
||||
*/
|
||||
tcp_sacktag_one(sk, state, TCP_SKB_CB(skb)->sacked,
|
||||
start_seq, end_seq, dup_sack, pcount);
|
||||
|
||||
/* Difference in this won't matter, both ACKed by the same cumul. ACK */
|
||||
TCP_SKB_CB(prev)->sacked |= (TCP_SKB_CB(skb)->sacked & TCPCB_EVER_RETRANS);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user