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

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

[TCP]: Create tcp_sacktag_one().



Worker function that implements the main logic of
the inner-most loop of tcp_sacktag_write_queue().

Idea was originally presented by David S. Miller.

Signed-off-by: default avatarIlpo Järvinen <ilpo.jarvinen@helsinki.fi>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b7d4815f
Loading
Loading
Loading
Loading
+96 −96
Original line number Diff line number Diff line
@@ -1240,6 +1240,99 @@ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb,
	return in_sack;
}

static int tcp_sacktag_one(struct sk_buff *skb, struct tcp_sock *tp,
			   int *reord, int dup_sack, int fack_count)
{
	u8 sacked = TCP_SKB_CB(skb)->sacked;
	int flag = 0;

	/* Account D-SACK for retransmitted packet. */
	if (dup_sack && (sacked & TCPCB_RETRANS)) {
		if (after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker))
			tp->undo_retrans--;
		if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una) &&
		    (sacked & TCPCB_SACKED_ACKED))
			*reord = min(fack_count, *reord);
	}

	/* Nothing to do; acked frame is about to be dropped (was ACKed). */
	if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una))
		return flag;

	if (!(sacked & TCPCB_SACKED_ACKED)) {
		if (sacked & TCPCB_SACKED_RETRANS) {
			/* If the segment is not tagged as lost,
			 * we do not clear RETRANS, believing
			 * that retransmission is still in flight.
			 */
			if (sacked & TCPCB_LOST) {
				TCP_SKB_CB(skb)->sacked &=
					~(TCPCB_LOST|TCPCB_SACKED_RETRANS);
				tp->lost_out -= tcp_skb_pcount(skb);
				tp->retrans_out -= tcp_skb_pcount(skb);

				/* clear lost hint */
				tp->retransmit_skb_hint = NULL;
			}
		} else {
			if (!(sacked & TCPCB_RETRANS)) {
				/* New sack for not retransmitted frame,
				 * which was in hole. It is reordering.
				 */
				if (before(TCP_SKB_CB(skb)->seq,
					   tcp_highest_sack_seq(tp)))
					*reord = min(fack_count, *reord);

				/* SACK enhanced F-RTO (RFC4138; Appendix B) */
				if (!after(TCP_SKB_CB(skb)->end_seq, tp->frto_highmark))
					flag |= FLAG_ONLY_ORIG_SACKED;
			}

			if (sacked & TCPCB_LOST) {
				TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
				tp->lost_out -= tcp_skb_pcount(skb);

				/* clear lost hint */
				tp->retransmit_skb_hint = NULL;
			}
		}

		TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED;
		flag |= FLAG_DATA_SACKED;
		tp->sacked_out += tcp_skb_pcount(skb);

		fack_count += tcp_skb_pcount(skb);

		/* Lost marker hint past SACKed? Tweak RFC3517 cnt */
		if (!tcp_is_fack(tp) && (tp->lost_skb_hint != NULL) &&
		    before(TCP_SKB_CB(skb)->seq,
			   TCP_SKB_CB(tp->lost_skb_hint)->seq))
			tp->lost_cnt_hint += tcp_skb_pcount(skb);

		if (fack_count > tp->fackets_out)
			tp->fackets_out = fack_count;

		if (after(TCP_SKB_CB(skb)->seq, tcp_highest_sack_seq(tp)))
			tp->highest_sack = skb;

	} else {
		if (dup_sack && (sacked & TCPCB_RETRANS))
			*reord = min(fack_count, *reord);
	}

	/* D-SACK. We can detect redundant retransmission in S|R and plain R
	 * frames and clear it. undo_retrans is decreased above, L|R frames
	 * are accounted above as well.
	 */
	if (dup_sack && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)) {
		TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
		tp->retrans_out -= tcp_skb_pcount(skb);
		tp->retransmit_skb_hint = NULL;
	}

	return flag;
}

static int
tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_una)
{
@@ -1375,7 +1468,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_

		tcp_for_write_queue_from(skb, sk) {
			int in_sack = 0;
			u8 sacked;

			if (skb == tcp_send_head(sk))
				break;
@@ -1413,102 +1505,10 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
			if (unlikely(in_sack < 0))
				break;

			if (!in_sack) {
				fack_count += tcp_skb_pcount(skb);
				continue;
			}

			sacked = TCP_SKB_CB(skb)->sacked;

			/* Account D-SACK for retransmitted packet. */
			if (dup_sack && (sacked & TCPCB_RETRANS)) {
				if (after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker))
					tp->undo_retrans--;
				if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una) &&
				    (sacked & TCPCB_SACKED_ACKED))
					reord = min(fack_count, reord);
			}


			/* Nothing to do; acked frame is about to be dropped (was ACKed). */
			if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) {
				fack_count += tcp_skb_pcount(skb);
				continue;
			}

			if (!(sacked&TCPCB_SACKED_ACKED)) {
				if (sacked & TCPCB_SACKED_RETRANS) {
					/* If the segment is not tagged as lost,
					 * we do not clear RETRANS, believing
					 * that retransmission is still in flight.
					 */
					if (sacked & TCPCB_LOST) {
						TCP_SKB_CB(skb)->sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS);
						tp->lost_out -= tcp_skb_pcount(skb);
						tp->retrans_out -= tcp_skb_pcount(skb);

						/* clear lost hint */
						tp->retransmit_skb_hint = NULL;
					}
				} else {
					if (!(sacked & TCPCB_RETRANS)) {
						/* New sack for not retransmitted frame,
						 * which was in hole. It is reordering.
						 */
						if (before(TCP_SKB_CB(skb)->seq,
							   tcp_highest_sack_seq(tp)))
							reord = min(fack_count, reord);

						/* SACK enhanced F-RTO (RFC4138; Appendix B) */
						if (!after(TCP_SKB_CB(skb)->end_seq, tp->frto_highmark))
							flag |= FLAG_ONLY_ORIG_SACKED;
					}

					if (sacked & TCPCB_LOST) {
						TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
						tp->lost_out -= tcp_skb_pcount(skb);

						/* clear lost hint */
						tp->retransmit_skb_hint = NULL;
					}
				}

				TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED;
				flag |= FLAG_DATA_SACKED;
				tp->sacked_out += tcp_skb_pcount(skb);
			if (in_sack)
				flag |= tcp_sacktag_one(skb, tp, &reord, dup_sack, fack_count);

			fack_count += tcp_skb_pcount(skb);

				/* Lost marker hint past SACKed? Tweak RFC3517 cnt */
				if (!tcp_is_fack(tp) && (tp->lost_skb_hint != NULL) &&
				    before(TCP_SKB_CB(skb)->seq,
					   TCP_SKB_CB(tp->lost_skb_hint)->seq))
					tp->lost_cnt_hint += tcp_skb_pcount(skb);

				if (fack_count > tp->fackets_out)
					tp->fackets_out = fack_count;

				if (after(TCP_SKB_CB(skb)->seq, tcp_highest_sack_seq(tp)))
					tp->highest_sack = skb;

			} else {
				if (dup_sack && (sacked&TCPCB_RETRANS))
					reord = min(fack_count, reord);

				fack_count += tcp_skb_pcount(skb);
			}

			/* D-SACK. We can detect redundant retransmission
			 * in S|R and plain R frames and clear it.
			 * undo_retrans is decreased above, L|R frames
			 * are accounted above as well.
			 */
			if (dup_sack &&
			    (TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_RETRANS)) {
				TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
				tp->retrans_out -= tcp_skb_pcount(skb);
				tp->retransmit_skb_hint = NULL;
			}
		}

		/* SACK enhanced FRTO (RFC4138, Appendix B): Clearing correct