Commit 1fdb9361 authored by Ilpo Järvinen's avatar Ilpo Järvinen Committed by David S. Miller

tcp: sack lost marking fixes

When only fast rexmit should be done, tcp_mark_head_lost marks
L too far. Also, sacked_upto below 1 is perfectly valid number,
the packets == 0 then needs to be trapped elsewhere.
Signed-off-by: default avatarIlpo Järvinen <ilpo.jarvinen@helsinki.fi>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f3e85df8
...@@ -2495,7 +2495,7 @@ static void tcp_timeout_skbs(struct sock *sk) ...@@ -2495,7 +2495,7 @@ static void tcp_timeout_skbs(struct sock *sk)
/* Mark head of queue up as lost. With RFC3517 SACK, the packets is /* Mark head of queue up as lost. With RFC3517 SACK, the packets is
* is against sacked "cnt", otherwise it's against facked "cnt" * is against sacked "cnt", otherwise it's against facked "cnt"
*/ */
static void tcp_mark_head_lost(struct sock *sk, int packets) static void tcp_mark_head_lost(struct sock *sk, int packets, int mark_head)
{ {
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb; struct sk_buff *skb;
...@@ -2503,13 +2503,13 @@ static void tcp_mark_head_lost(struct sock *sk, int packets) ...@@ -2503,13 +2503,13 @@ static void tcp_mark_head_lost(struct sock *sk, int packets)
int err; int err;
unsigned int mss; unsigned int mss;
if (packets == 0)
return;
WARN_ON(packets > tp->packets_out); WARN_ON(packets > tp->packets_out);
if (tp->lost_skb_hint) { if (tp->lost_skb_hint) {
skb = tp->lost_skb_hint; skb = tp->lost_skb_hint;
cnt = tp->lost_cnt_hint; cnt = tp->lost_cnt_hint;
/* Head already handled? */
if (mark_head && skb != tcp_write_queue_head(sk))
return;
} else { } else {
skb = tcp_write_queue_head(sk); skb = tcp_write_queue_head(sk);
cnt = 0; cnt = 0;
...@@ -2544,6 +2544,9 @@ static void tcp_mark_head_lost(struct sock *sk, int packets) ...@@ -2544,6 +2544,9 @@ static void tcp_mark_head_lost(struct sock *sk, int packets)
} }
tcp_skb_mark_lost(tp, skb); tcp_skb_mark_lost(tp, skb);
if (mark_head)
break;
} }
tcp_verify_left_out(tp); tcp_verify_left_out(tp);
} }
...@@ -2555,17 +2558,18 @@ static void tcp_update_scoreboard(struct sock *sk, int fast_rexmit) ...@@ -2555,17 +2558,18 @@ static void tcp_update_scoreboard(struct sock *sk, int fast_rexmit)
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
if (tcp_is_reno(tp)) { if (tcp_is_reno(tp)) {
tcp_mark_head_lost(sk, 1); tcp_mark_head_lost(sk, 1, 1);
} else if (tcp_is_fack(tp)) { } else if (tcp_is_fack(tp)) {
int lost = tp->fackets_out - tp->reordering; int lost = tp->fackets_out - tp->reordering;
if (lost <= 0) if (lost <= 0)
lost = 1; lost = 1;
tcp_mark_head_lost(sk, lost); tcp_mark_head_lost(sk, lost, 0);
} else { } else {
int sacked_upto = tp->sacked_out - tp->reordering; int sacked_upto = tp->sacked_out - tp->reordering;
if (sacked_upto < fast_rexmit) if (sacked_upto >= 0)
sacked_upto = fast_rexmit; tcp_mark_head_lost(sk, sacked_upto, 0);
tcp_mark_head_lost(sk, sacked_upto); else if (fast_rexmit)
tcp_mark_head_lost(sk, 1, 1);
} }
tcp_timeout_skbs(sk); tcp_timeout_skbs(sk);
...@@ -2971,7 +2975,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag) ...@@ -2971,7 +2975,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag)
before(tp->snd_una, tp->high_seq) && before(tp->snd_una, tp->high_seq) &&
icsk->icsk_ca_state != TCP_CA_Open && icsk->icsk_ca_state != TCP_CA_Open &&
tp->fackets_out > tp->reordering) { tp->fackets_out > tp->reordering) {
tcp_mark_head_lost(sk, tp->fackets_out - tp->reordering); tcp_mark_head_lost(sk, tp->fackets_out - tp->reordering, 0);
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSS); NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSS);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment