kern/140597: Lost Retransmission Detection

Scheffenegger, Richard rs at netapp.com
Tue May 31 08:56:39 UTC 2011


Hi,

please review the following patch, which enables the detection and
recovery of lost retransmissions for SACK. This patch address the second
most prominent cause of retransmission timeouts (after the failure to
initiate loss recovery for small window sessions - e.g. Early
Retransmit).

The idea behind this patch is the same one that is emergent behavior in
the linux stack: 1RTT after sending a retransmission, that
retransmission should have made it to the receiver; the 1RTT signal is a
newly sent segment (snd.fack advances) being acknowledged by the
receiver...

The pointer indicating where a retransmission is to be started, is set
to snd.nxt (new segment after this loss window) - outside the boundaries
of the hole itself - to remember when a hole needs to be retransmitted.
If all retransmissions are proceeding in-order, these holes would close
and eventually be evicted from the scoreboard, before the first new
transmission after the loss window is SACKed by the receiver.

Over the first instance of this patch, it addresses a slight oversight,
when retransmitted segments from multiple holes became lost - it
traverses all the holes from the sackhint forward to the beginning of
the scoreboard when snd.fack is adjusted, and resets the pointer (and
sackhint) where the next transmission should come from accordingly.

However - just like Linux - there is no congestion control reaction
(even though the papers discussing lost retransmission all mention that
another reduction of cwnd would be appropriate).


Richard Scheffenegger


diff -u netinet.orig/tcp_output.c netinet/tcp_output.c
--- netinet.orig/tcp_output.c   2009-10-25 02:10:29.000000000 +0100
+++ netinet/tcp_output.c        2010-04-02 16:55:14.000000000 +0200
@@ -953,6 +953,10 @@
        } else {
                th->th_seq = htonl(p->rxmit);
                p->rxmit += len;
+               /* lost again detection */
+               if (SEQ_GEQ(p->rxmit, p->end)) {
+                       p->rxmit = tp->snd_nxt;
+               }
                tp->sackhint.sack_bytes_rexmit += len;
        }
        th->th_ack = htonl(tp->rcv_nxt);
diff -u netinet.orig/tcp_sack.c netinet.simple_mod/tcp_sack.c
--- netinet.orig/tcp_sack.c     2009-10-25 02:10:29.000000000 +0100
+++ netinet/tcp_sack.c          2010-04-21 00:48:23.000000000 +0200
@@ -508,7 +508,9 @@
                        if (SEQ_GEQ(sblkp->end, cur->end)) {
                                /* Move end of hole backward. */
                                cur->end = sblkp->start;
-                               cur->rxmit = SEQ_MIN(cur->rxmit,
cur->end);
+                               if (SEQ_GEQ(cur->rxmit, cur->end)) {
+                                       cur->rxmit = tp->snd_nxt;
+                               }
                        } else {
                                /*
                                 * ACKs some data in middle of a hole;
need
@@ -524,8 +526,9 @@
                                                    - temp->start);
                                        }
                                        cur->end = sblkp->start;
-                                       cur->rxmit = SEQ_MIN(cur->rxmit,
-                                           cur->end);
+                                       if (SEQ_GEQ(cur->rxmit,
cur->end)) {
+                                               cur->rxmit =
tp->snd_nxt;
+                                       }
                                }
                        }
                }
@@ -540,6 +543,15 @@
                else
                        sblkp--;
        }
+       /* retransmission lost again - then restart */
+       if ((temp = tp->sackhint.nexthole) != NULL) {
+               do {
+                       if (SEQ_GT(tp->snd_fack, temp->rxmit)) {
+                               temp->rxmit = temp->start;
+                               tp->sackhint.nexthole = temp;
+                       }
+               } while ((temp = TAILQ_PREV(temp, sackhole_head,
scblink)) != NULL);
+       }
 }

 /*



More information about the freebsd-net mailing list