PERFORCE change 166228 for review

Andre Oppermann andre at FreeBSD.org
Sat Jul 18 14:32:56 UTC 2009


http://perforce.freebsd.org/chv.cgi?CH=166228

Change 166228 by andre at andre_t61 on 2009/07/18 14:32:22

	Add and improve comments.
	Complete tcp_sack_nextseg().
	Adapt tcp_retransmit() to new sack semantics.

Affected files ...

.. //depot/projects/tcp_new/netinet/tcp_output.c#13 edit
.. //depot/projects/tcp_new/netinet/tcp_sack.c#9 edit

Differences ...

==== //depot/projects/tcp_new/netinet/tcp_output.c#13 (text+ko) ====

@@ -793,23 +793,37 @@
 	 *  5. TCP congestion window validation RFC2861
 	 */
 
-	/* Limited transmit */
-	if (tp->snd_dupack < tcp_dupthresh && dlen > *len)
+	/*
+	 * Limited transmit: transmit new data upon the arrival of the
+	 * first two consecutive duplicate ACKs.
+	 *  RFC3042: section 2
+	 */
+	if (tp->snd_dupack < tcp_dupthresh && dlen > *len) {
 		*len = min(dlen, tp->snd_mss);	/* up to one mss above cwnd */
-
-	if (tp->snd_dupack < tcp_dupthresh)
 		return (0);
+	}
 
-	/* Remember the highest byte sent. */
-	if (SEQ_LEQ(tp->snd_recover, tp->snd_una)) {
+	/*
+	 * Remember the highest byte sent yet
+	 * and set snd_rxmit to snd_una.
+	 */
+	if (tp->snd_dupack == tcp_dupthresh) {
 		tp->snd_recover = tp->snd_nxt;
-		//tcp_cc_fr_enter(tp);
 		tp->snd_rxmit = tp->snd_una;
+		rlen = tcp_sack_firsthole(tp, &rexmit);
+	} else {
+		rlen = tcp_sack_nextseg(tp, &tp->snd_rexmit, dlen);
 	}
 
-	rlen = tcp_sack_nextseg(tp, &tp->snd_rexmit);
+	if (rlen == 0)
+		if (dlen)
+			*len = dlen;	/* XXXAO: pipe! */
+		else
+			*len = 0;
+		return (0);
+	} else
+		rlen = min(rlen, pipe);	/* XXXAO: pipe! */
 
-	rlen = min(so->so_snd.sb_cc - SEQ_DELTA(tp->snd_una, tp->snd_rxmit), tp->snd_mss);
 
 	/*
 	 * Fill in headers.

==== //depot/projects/tcp_new/netinet/tcp_sack.c#9 (text+ko) ====

@@ -185,7 +185,13 @@
 	struct tcp_sack_block *tsb, *tsbn;
 	struct tcp_sack_block sack;
 
-	/* Remove any blocks from the scoreboard when full acked. */
+	/*
+	 * Remove any blocks from the scoreboard when fully acked.
+	 * When a partial ACK cuts into a sackblock we remove that
+	 * full block.  The receiver has either sent incorrect SACK 
+	 * information or has flushed data from its reassembly queue
+	 * so that a retransmit has become necessary.
+	 */
 	RB_FOREACH_SAFE(tsb, tcp_sackblocks, &tp->snd_sackblocks, tsbn) {
 		if (SEQ_LT(th_ack, tsb->tsb_blk.start))
 			break;
@@ -193,7 +199,10 @@
 			tcp_sack_free(tp, tsb);
 	}
 
-	/* SACK header but no blocks. */
+	/*
+	 * SACK header but no blocks or no SACK information even though
+	 * it was sent before.
+	 */
 	if ((to->to_flags & TOF_SACK) && to->to_nsacks == 0)
 		return (0);
 	else if (!(to->to_flags & TOF_SACK))
@@ -234,7 +243,10 @@
 		    SEQ_GT(sack.tsb_blk.end, tp->snd_nxt))
 			continue;
 
-		/* Return match that has at least partial overlap to either side. */
+		/*
+		 * Return match that has at least partial overlap to either side or
+		 * insert a new sackblock.
+		 */
 		if ((tsb = RB_FIND(tcp_sackblocks, &tp->snd_sackblocks, &sack)) != NULL) {
 			/* Within an already known block, common case. */
 			if (SEQ_GEQ(sack.tsb_blk.start, tsb->tsb_blk.start) &&
@@ -242,6 +254,7 @@
 				/*
 				 * D-SACK, was a duplicate retransmit.
 				 *  RFC2883: section 5
+				 * XXXAO: Adjust pipe.
 				 */
 				if (i == 0 && SEQ_DELTA(sack.tsb_blk.start, sack.tsb_blk.end) <= tp->snd_mss) {
 					//TCPSTAT_INC();
@@ -290,30 +303,91 @@
 }
 
 /*
- * Determine the next start and length of the next hole relative
- * to rexmit.
+ * Determine the start and length of the next hole relative to rexmit.
+ *  RFC3517: section 4 and 5
+ *
+ * NB: When we return zero it is the responseability of the caller
+ * to test whether more previously unsent data is available.
+ *  RFC3517: section 4, NextSeg() test (2) and (4)
+ *
+ * NB: We return the full size of the current hole to avoid looping
+ * over the same hole when pipe allows more than one segment to be
+ * sent.
+ *  RFC3517: section 5, (C.1) and (C.5)
  */
 int
-tcp_sack_nextseg(struct tcpcb *tp, tcp_seq *rexmit)
+tcp_sack_nextseg(struct tcpcb *tp, tcp_seq *rexmit, int dlen)
 {
-	int len = 0;
-	struct tcp_sack_block *tsb, *tsbn;
+	int len = 0, blocks = 0, islost = 0, sacked = 0;
+	struct tcp_sack_block *tsb, *tsbp;
 	struct tcp_sack_block sack;
 
 	sack.tsb_blk.start = rexmit;
 	sack.tsb_blk.end = rexmit;
 
-	if ((tsb = RB_NFIND(tcp_sackblocks, &tp->snd_sackblocks, &sack)) != NULL) {
-		if (*rexmit < tsb->tsb_blk.start) {
-			len = SEQ_DELTA(*rexmit, tsb->tsb_blk.start);
-		} else if ((tsbn = RB_NEXT(tcp_sackblocks, &tp->snd_sackblocks, tsb)) != NULL) {
-			*rexmit = tsb->tsb_blk.end;
-			len = SEQ_DELTA(tsb->tsb_blk.end, tsbn->tsb_blk.start);
-		} else {
-			*rexmit = tsb->tsb_blk.end;
-			len = (SEQ_DELTA(tsb->tsb_blk.end, tp->snd_nxt);
+	/*
+	 * Find the sackblock that covers rexmit, or the first one above it.
+	 *  RFC3517: section 4, NextSeg() Test 4 is automatically fulfilled.
+	 */
+	if ((tsb = RB_NFIND(tcp_sackblocks, &tp->snd_sackblocks, &sack)) != NULL)
+		return (0);
+
+	/*
+	 * If rexmit is below the first sackblock start from there,
+	 * otherwise move rexmit to the end of it (ie. the start of the next hole).
+	 */
+	if (SEQ_LT(*rexmit, tsb->tsb_blk.start)) {
+		len = SEQ_DELTA(*rexmit, tsb->tsb_blk.start);
+		sacked = SEQ_DELTA(*rexmit, tsb->tsb_blk.end);
+	} else
+		*rexmit = tsb->tsb_blk.end;
+
+	/*
+	 * Determine whether all conditions for a retransmit are fulfilled:
+	 * DupThresh * SMSS bytes above 'SeqNum' have been SACKed -or-
+	 * DupThresh discontiguous sackblocks have arrived above 'SeqNum'.
+	 *  RFC3517: section 4, IsLost() processing
+	 *  RFC3517: section 5, NextSeg() test (1.a-c) processing
+	 */
+	RB_FOREACH_FROM(tsbp, tcp_sackblocks, tsb) {
+		/* Get the size of this hole, if the first. */
+		if (len == 0)
+			len = SEQ_DELTA(tsbp->tsb_blk.end, tsb->tsb_blk.start);
+		sacked += SEQ_DELTA(tsb->tsb_blk.start, tsb->tsb_blk.end);
+		if (sacked > 3 * tp->snd_mss || blocks++ > 2) {
+			islost = 1;
+			break;
 		}
 	}
+
+	/*
+	 * Disambiguate between NextSeg() test (2) and (3).
+	 * If there is more previously unsent data available
+	 * and we don't fulfill tests (1.a-c) then test (2)
+	 * is true and we return zero.  Otherwise test (3)
+	 * is true, if len is set, and we get a retransmit.
+	 *  RFC3517: section 4, NextSeg() processing
+	 */
+	if (!islost && dlen > 0)
+		len = 0;
+
+	return (len);
+}
+
+/*
+ * Return the start and length of the first sack hole.
+ */
+int
+tcp_sack_firsthole(struct tcpcb *tp, tcp_seq *rexmit)
+{
+	int len = 0;
+	struct tcp_sack_block *tsb;
+
+	*rexmit = tp->snd_una;
+
+	if ((tsb = RB_MIN(tcp_sackblocks, &tp->snd_sackblocks)) != NULL)
+		len = SEQ_DELTA(*rexmit, tsb->tsb_blk.start);
+
 	return (len);
 }
 


More information about the p4-projects mailing list