Page MenuHomeFreeBSD

D18985.id79774.diff
No OneTemporary

D18985.id79774.diff

Index: sys/netinet/tcp_input.c
===================================================================
--- sys/netinet/tcp_input.c
+++ sys/netinet/tcp_input.c
@@ -1497,6 +1497,7 @@
struct mbuf *mfree;
struct tcpopt to;
int tfo_syn;
+ u_int maxseg;
#ifdef TCPDEBUG
/*
@@ -2488,8 +2489,6 @@
#endif
if (SEQ_LEQ(th->th_ack, tp->snd_una)) {
- u_int maxseg;
-
maxseg = tcp_maxseg(tp);
if (tlen == 0 &&
(tiwin == tp->snd_wnd ||
@@ -2579,7 +2578,21 @@
tp->snd_cwnd += maxseg;
(void) tp->t_fb->tfb_tcp_output(tp);
goto drop;
- } else if (tp->t_dupacks == tcprexmtthresh) {
+ } else if (tp->t_dupacks == tcprexmtthresh ||
+ (tp->t_flags & TF_SACK_PERMIT &&
+ V_tcp_do_rfc6675_pipe &&
+ tp->sackhint.sacked_bytes >
+ (tcprexmtthresh - 1) * maxseg)) {
+enter_recovery:
+ /*
+ * Above is the RFC6675 trigger condition of
+ * more than (dupthresh-1)*maxseg sacked data.
+ * If the count of holes in the
+ * scoreboard is >= dupthresh, we could
+ * also enter loss recovery, but don't
+ * have that value readily available.
+ */
+ tp->t_dupacks = tcprexmtthresh;
tcp_seq onxt = tp->snd_nxt;
/*
@@ -2613,6 +2626,8 @@
tp->snd_recover = tp->snd_nxt;
tp->snd_cwnd = maxseg;
(void) tp->t_fb->tfb_tcp_output(tp);
+ if (SEQ_GT(th->th_ack, tp->snd_una))
+ goto resume_partialack;
goto drop;
}
tp->snd_nxt = th->th_ack;
@@ -2699,10 +2714,19 @@
*/
if ((tp->t_flags & TF_SACK_PERMIT) &&
(to.to_flags & TOF_SACK) &&
- sack_changed)
+ sack_changed) {
tp->t_dupacks++;
+ /* limit overhead by setting maxseg last */
+ if (!IN_FASTRECOVERY(tp->t_flags) &&
+ (tp->sackhint.sacked_bytes >
+ ((tcprexmtthresh - 1) *
+ (maxseg = tcp_maxseg(tp))))) {
+ goto enter_recovery;
+ }
+ }
}
+resume_partialack:
KASSERT(SEQ_GT(th->th_ack, tp->snd_una),
("%s: th_ack <= snd_una", __func__));
Index: sys/netinet/tcp_sack.c
===================================================================
--- sys/netinet/tcp_sack.c
+++ sys/netinet/tcp_sack.c
@@ -750,6 +750,16 @@
else
sblkp--;
}
+ if (!(to->to_flags & TOF_SACK))
+ /*
+ * If this ACK did not contain any
+ * SACK blocks, any only moved the
+ * left edge right, it is a pure
+ * cumulative ACK. Do not count
+ * DupAck for this. Also required
+ * for RFC6675 rescue retransmission.
+ */
+ sack_changed = 0;
tp->sackhint.delivered_data = delivered_data;
tp->sackhint.sacked_bytes += delivered_data - left_edge_delta;
KASSERT((delivered_data >= 0), ("delivered_data < 0"));
@@ -800,6 +810,31 @@
if (tp->snd_cwnd > tp->snd_ssthresh)
tp->snd_cwnd = tp->snd_ssthresh;
tp->t_flags |= TF_ACKNOW;
+ /*
+ * RFC6675 rescue retransmission
+ * Add a hole between th_ack (snd_una is not yet set) and snd_max,
+ * if this was a pure cumulative ACK and no data was send beyond
+ * recovery point. Since the data in the socket has not been freed
+ * at this point, we check if the scoreboard is empty, and the ACK
+ * delivered some new data, indicating a full ACK. Also, if the
+ * recovery point is still at snd_max, we are probably application
+ * limited. However, this inference might not always be true. The
+ * rescue retransmission may rarely be slightly premature
+ * compared to RFC6675.
+ * The corresponding ACK+SACK will cause any further outstanding
+ * segments to be retransmitted. This addresses a corner case, when
+ * the trailing packets of a window are lost and no further data
+ * is available for sending.
+ */
+ if ((V_tcp_do_rfc6675_pipe) &&
+ SEQ_LT(th->th_ack, tp->snd_recover) &&
+ (tp->snd_recover == tp->snd_max) &&
+ TAILQ_EMPTY(&tp->snd_holes) &&
+ (tp->sackhint.delivered_data > 0)) {
+ struct sackhole *hole;
+ int maxseg = tcp_maxseg(tp);
+ hole = tcp_sackhole_insert(tp, SEQ_MAX(th->th_ack, tp->snd_max - maxseg), tp->snd_max, NULL);
+ }
(void) tp->t_fb->tfb_tcp_output(tp);
}

File Metadata

Mime Type
text/plain
Expires
Thu, Mar 13, 4:37 AM (15 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17130057
Default Alt Text
D18985.id79774.diff (3 KB)

Event Timeline