Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7363a5b2 authored by Ilpo Järvinen's avatar Ilpo Järvinen Committed by David S. Miller
Browse files

tcp: separate timeout marking loop to it's own function



Some comment about its current state added. So far I have
seen very few cases where the thing is actually useful,
usually just marginally (though admittedly I don't usually
see top of window losses where it seems possible that there
could be some gain), instead, more often the cases suffer
from L-marking spike which is certainly not desirable
(I'll bury improving it to my todo list, but on a low
prio position).

Signed-off-by: default avatarIlpo Järvinen <ilpo.jarvinen@helsinki.fi>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d0af4160
Loading
Loading
Loading
Loading
+39 −24
Original line number Diff line number Diff line
@@ -2461,6 +2461,44 @@ static int tcp_time_to_recover(struct sock *sk)
	return 0;
}

/* New heuristics: it is possible only after we switched to restart timer
 * each time when something is ACKed. Hence, we can detect timed out packets
 * during fast retransmit without falling to slow start.
 *
 * Usefulness of this as is very questionable, since we should know which of
 * the segments is the next to timeout which is relatively expensive to find
 * in general case unless we add some data structure just for that. The
 * current approach certainly won't find the right one too often and when it
 * finally does find _something_ it usually marks large part of the window
 * right away (because a retransmission with a larger timestamp blocks the
 * loop from advancing). -ij
 */
static void tcp_timeout_skbs(struct sock *sk)
{
	struct tcp_sock *tp = tcp_sk(sk);
	struct sk_buff *skb;

	if (!tcp_is_fack(tp) || !tcp_head_timedout(sk))
		return;

	skb = tp->scoreboard_skb_hint;
	if (tp->scoreboard_skb_hint == NULL)
		skb = tcp_write_queue_head(sk);

	tcp_for_write_queue_from(skb, sk) {
		if (skb == tcp_send_head(sk))
			break;
		if (!tcp_skb_timedout(sk, skb))
			break;

		tcp_skb_mark_lost(tp, skb);
	}

	tp->scoreboard_skb_hint = skb;

	tcp_verify_left_out(tp);
}

/* Mark head of queue up as lost. With RFC3517 SACK, the packets is
 * is against sacked "cnt", otherwise it's against facked "cnt"
 */
@@ -2533,30 +2571,7 @@ static void tcp_update_scoreboard(struct sock *sk, int fast_rexmit)
		tcp_mark_head_lost(sk, sacked_upto);
	}

	/* New heuristics: it is possible only after we switched
	 * to restart timer each time when something is ACKed.
	 * Hence, we can detect timed out packets during fast
	 * retransmit without falling to slow start.
	 */
	if (tcp_is_fack(tp) && tcp_head_timedout(sk)) {
		struct sk_buff *skb;

		skb = tp->scoreboard_skb_hint ? tp->scoreboard_skb_hint
			: tcp_write_queue_head(sk);

		tcp_for_write_queue_from(skb, sk) {
			if (skb == tcp_send_head(sk))
				break;
			if (!tcp_skb_timedout(sk, skb))
				break;

			tcp_skb_mark_lost(tp, skb);
		}

		tp->scoreboard_skb_hint = skb;

		tcp_verify_left_out(tp);
	}
	tcp_timeout_skbs(sk);
}

/* CWND moderation, preventing bursts due to too big ACKs