summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2007-05-11 11:21:43 +0000
committerrwatson <rwatson@FreeBSD.org>2007-05-11 11:21:43 +0000
commit05369787fc24d7238acc7d9c05e0d6edbf1dc716 (patch)
tree662e5457edccd09fc4115437f48a7628c1d1411c
parent719c87d1eefd84c258ae95fba843c7e46fe3ee9d (diff)
downloadFreeBSD-src-05369787fc24d7238acc7d9c05e0d6edbf1dc716.zip
FreeBSD-src-05369787fc24d7238acc7d9c05e0d6edbf1dc716.tar.gz
Coalesce two identical UCB licenses into a single license instance with
one set of copyright years. White space and comment cleanup. Export $FreeBSD$ via __FBSDID.
-rw-r--r--sys/netinet/tcp_sack.c195
1 files changed, 87 insertions, 108 deletions
diff --git a/sys/netinet/tcp_sack.c b/sys/netinet/tcp_sack.c
index 807526f..aa0849c 100644
--- a/sys/netinet/tcp_sack.c
+++ b/sys/netinet/tcp_sack.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995
- * The Regents of the University of California. All rights reserved.
+ * The Regents of the University of California.
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,37 +28,9 @@
* SUCH DAMAGE.
*
* @(#)tcp_sack.c 8.12 (Berkeley) 5/24/95
- * $FreeBSD$
*/
/*-
- * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
* @@(#)COPYRIGHT 1.1 (NRL) 17 January 1995
*
* NRL grants permission for redistribution and use in source and binary
@@ -96,6 +69,10 @@
* official policies, either expressed or implied, of the US Naval
* Research Laboratory (NRL).
*/
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_tcpdebug.h"
@@ -168,8 +145,8 @@ SYSCTL_INT(_net_inet_tcp_sack, OID_AUTO, globalholes, CTLFLAG_RD,
"Global number of TCP SACK holes currently allocated");
/*
- * This function is called upon receipt of new valid data (while not in header
- * prediction mode), and it updates the ordered list of sacks.
+ * This function is called upon receipt of new valid data (while not in
+ * header prediction mode), and it updates the ordered list of sacks.
*/
void
tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_start, tcp_seq rcv_end)
@@ -185,7 +162,7 @@ tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_start, tcp_seq rcv_end)
INP_LOCK_ASSERT(tp->t_inpcb);
- /* Check arguments */
+ /* Check arguments. */
KASSERT(SEQ_LT(rcv_start, rcv_end), ("rcv_start < rcv_end"));
/* SACK block for the received segment. */
@@ -193,9 +170,9 @@ tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_start, tcp_seq rcv_end)
head_blk.end = rcv_end;
/*
- * Merge updated SACK blocks into head_blk, and
- * save unchanged SACK blocks into saved_blks[].
- * num_saved will have the number of the saved SACK blocks.
+ * Merge updated SACK blocks into head_blk, and save unchanged SACK
+ * blocks into saved_blks[]. num_saved will have the number of the
+ * saved SACK blocks.
*/
num_saved = 0;
for (i = 0; i < tp->rcv_numsacks; i++) {
@@ -208,8 +185,8 @@ tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_start, tcp_seq rcv_end)
} else if (SEQ_LEQ(head_blk.start, end) &&
SEQ_GEQ(head_blk.end, start)) {
/*
- * Merge this SACK block into head_blk.
- * This SACK block itself will be discarded.
+ * Merge this SACK block into head_blk. This SACK
+ * block itself will be discarded.
*/
if (SEQ_GT(head_blk.start, start))
head_blk.start = start;
@@ -231,8 +208,8 @@ tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_start, tcp_seq rcv_end)
num_head = 0;
if (SEQ_GT(head_blk.start, tp->rcv_nxt)) {
/*
- * The received data segment is an out-of-order segment.
- * Put head_blk at the top of SACK list.
+ * The received data segment is an out-of-order segment. Put
+ * head_blk at the top of SACK list.
*/
tp->sackblks[0] = head_blk;
num_head = 1;
@@ -303,6 +280,7 @@ tcp_sackhole_alloc(struct tcpcb *tp, tcp_seq start, tcp_seq end)
static void
tcp_sackhole_free(struct tcpcb *tp, struct sackhole *hole)
{
+
uma_zfree(sack_hole_zone, hole);
tp->snd_numholes--;
@@ -326,7 +304,7 @@ tcp_sackhole_insert(struct tcpcb *tp, tcp_seq start, tcp_seq end,
if (hole == NULL)
return NULL;
- /* Insert the new SACK hole into scoreboard */
+ /* Insert the new SACK hole into scoreboard. */
if (after != NULL)
TAILQ_INSERT_AFTER(&tp->snd_holes, after, hole, scblink);
else
@@ -345,6 +323,7 @@ tcp_sackhole_insert(struct tcpcb *tp, tcp_seq start, tcp_seq end,
static void
tcp_sackhole_remove(struct tcpcb *tp, struct sackhole *hole)
{
+
/* Update SACK hint. */
if (tp->sackhint.nexthole == hole)
tp->sackhint.nexthole = TAILQ_NEXT(hole, scblink);
@@ -380,8 +359,8 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
sack_blocks[num_sack_blks++].end = th_ack;
}
/*
- * Append received valid SACK blocks to sack_blocks[], but only
- * if we received new blocks from the other side.
+ * Append received valid SACK blocks to sack_blocks[], but only if we
+ * received new blocks from the other side.
*/
if (to->to_flags & TOF_SACK) {
for (i = 0; i < to->to_nsacks; i++) {
@@ -399,16 +378,16 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
}
}
/*
- * Return if SND.UNA is not advanced and no valid SACK block
- * is received.
+ * Return if SND.UNA is not advanced and no valid SACK block is
+ * received.
*/
if (num_sack_blks == 0)
return;
/*
- * Sort the SACK blocks so we can update the scoreboard
- * with just one pass. The overhead of sorting upto 4+1 elements
- * is less than making upto 4+1 passes over the scoreboard.
+ * Sort the SACK blocks so we can update the scoreboard with just one
+ * pass. The overhead of sorting upto 4+1 elements is less than
+ * making upto 4+1 passes over the scoreboard.
*/
for (i = 0; i < num_sack_blks; i++) {
for (j = i + 1; j < num_sack_blks; j++) {
@@ -423,15 +402,17 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
/*
* Empty scoreboard. Need to initialize snd_fack (it may be
* uninitialized or have a bogus value). Scoreboard holes
- * (from the sack blocks received) are created later below (in
- * the logic that adds holes to the tail of the scoreboard).
+ * (from the sack blocks received) are created later below
+ * (in the logic that adds holes to the tail of the
+ * scoreboard).
*/
tp->snd_fack = SEQ_MAX(tp->snd_una, th_ack);
/*
- * In the while-loop below, incoming SACK blocks (sack_blocks[])
- * and SACK holes (snd_holes) are traversed from their tails with
- * just one pass in order to reduce the number of compares especially
- * when the bandwidth-delay product is large.
+ * In the while-loop below, incoming SACK blocks (sack_blocks[]) and
+ * SACK holes (snd_holes) are traversed from their tails with just
+ * one pass in order to reduce the number of compares especially when
+ * the bandwidth-delay product is large.
+ *
* Note: Typically, in the first RTT of SACK recovery, the highest
* three or four SACK blocks with the same ack number are received.
* In the second RTT, if retransmitted data segments are not lost,
@@ -441,11 +422,10 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
sblkp = &sack_blocks[num_sack_blks - 1]; /* Last SACK block */
if (SEQ_LT(tp->snd_fack, sblkp->start)) {
/*
- * The highest SACK block is beyond fack.
- * Append new SACK hole at the tail.
- * If the second or later highest SACK blocks are also
- * beyond the current fack, they will be inserted by
- * way of hole splitting in the while-loop below.
+ * The highest SACK block is beyond fack. Append new SACK
+ * hole at the tail. If the second or later highest SACK
+ * blocks are also beyond the current fack, they will be
+ * inserted by way of hole splitting in the while-loop below.
*/
temp = tcp_sackhole_insert(tp, tp->snd_fack,sblkp->start,NULL);
if (temp != NULL) {
@@ -456,10 +436,10 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
/*
* We failed to add a new hole based on the current
* sack block. Skip over all the sack blocks that
- * fall completely to the right of snd_fack and proceed
- * to trim the scoreboard based on the remaining sack
- * blocks. This also trims the scoreboard for th_ack
- * (which is sack_blocks[0]).
+ * fall completely to the right of snd_fack and
+ * proceed to trim the scoreboard based on the
+ * remaining sack blocks. This also trims the
+ * scoreboard for th_ack (which is sack_blocks[0]).
*/
while (sblkp >= sack_blocks &&
SEQ_LT(tp->snd_fack, sblkp->start))
@@ -471,9 +451,10 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
} else if (SEQ_LT(tp->snd_fack, sblkp->end))
/* fack is advanced. */
tp->snd_fack = sblkp->end;
- /* We must have at least one SACK hole in scoreboard */
- KASSERT(!TAILQ_EMPTY(&tp->snd_holes), ("SACK scoreboard must not be empty"));
- cur = TAILQ_LAST(&tp->snd_holes, sackhole_head); /* Last SACK hole */
+ /* We must have at least one SACK hole in scoreboard. */
+ KASSERT(!TAILQ_EMPTY(&tp->snd_holes),
+ ("SACK scoreboard must not be empty"));
+ cur = TAILQ_LAST(&tp->snd_holes, sackhole_head); /* Last SACK hole. */
/*
* Since the incoming sack blocks are sorted, we can process them
* making one sweep of the scoreboard.
@@ -481,63 +462,64 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
while (sblkp >= sack_blocks && cur != NULL) {
if (SEQ_GEQ(sblkp->start, cur->end)) {
/*
- * SACKs data beyond the current hole.
- * Go to the previous sack block.
+ * SACKs data beyond the current hole. Go to the
+ * previous sack block.
*/
sblkp--;
continue;
}
if (SEQ_LEQ(sblkp->end, cur->start)) {
/*
- * SACKs data before the current hole.
- * Go to the previous hole.
+ * SACKs data before the current hole. Go to the
+ * previous hole.
*/
cur = TAILQ_PREV(cur, sackhole_head, scblink);
continue;
}
tp->sackhint.sack_bytes_rexmit -= (cur->rxmit - cur->start);
KASSERT(tp->sackhint.sack_bytes_rexmit >= 0,
- ("sackhint bytes rtx >= 0"));
+ ("sackhint bytes rtx >= 0"));
if (SEQ_LEQ(sblkp->start, cur->start)) {
- /* Data acks at least the beginning of hole */
+ /* Data acks at least the beginning of hole. */
if (SEQ_GEQ(sblkp->end, cur->end)) {
- /* Acks entire hole, so delete hole */
+ /* Acks entire hole, so delete hole. */
temp = cur;
cur = TAILQ_PREV(cur, sackhole_head, scblink);
tcp_sackhole_remove(tp, temp);
/*
- * The sack block may ack all or part of the next
- * hole too, so continue onto the next hole.
+ * The sack block may ack all or part of the
+ * next hole too, so continue onto the next
+ * hole.
*/
continue;
} else {
- /* Move start of hole forward */
+ /* Move start of hole forward. */
cur->start = sblkp->end;
cur->rxmit = SEQ_MAX(cur->rxmit, cur->start);
}
} else {
- /* Data acks at least the end of hole */
+ /* Data acks at least the end of hole. */
if (SEQ_GEQ(sblkp->end, cur->end)) {
- /* Move end of hole backward */
+ /* Move end of hole backward. */
cur->end = sblkp->start;
cur->rxmit = SEQ_MIN(cur->rxmit, cur->end);
} else {
/*
- * ACKs some data in middle of a hole; need to
- * split current hole
+ * ACKs some data in middle of a hole; need
+ * to split current hole
*/
temp = tcp_sackhole_insert(tp, sblkp->end,
- cur->end, cur);
+ cur->end, cur);
if (temp != NULL) {
if (SEQ_GT(cur->rxmit, temp->rxmit)) {
temp->rxmit = cur->rxmit;
tp->sackhint.sack_bytes_rexmit
- += (temp->rxmit
- - temp->start);
+ += (temp->rxmit
+ - temp->start);
}
cur->end = sblkp->start;
cur->rxmit = SEQ_MIN(cur->rxmit,
- cur->end);
+ cur->end);
}
}
}
@@ -573,14 +555,12 @@ tcp_free_sackholes(struct tcpcb *tp)
}
/*
- * Partial ack handling within a sack recovery episode.
- * Keeping this very simple for now. When a partial ack
- * is received, force snd_cwnd to a value that will allow
- * the sender to transmit no more than 2 segments.
- * If necessary, a better scheme can be adopted at a
- * later point, but for now, the goal is to prevent the
- * sender from bursting a large amount of data in the midst
- * of sack recovery.
+ * Partial ack handling within a sack recovery episode. Keeping this very
+ * simple for now. When a partial ack is received, force snd_cwnd to a value
+ * that will allow the sender to transmit no more than 2 segments. If
+ * necessary, a better scheme can be adopted at a later point, but for now,
+ * the goal is to prevent the sender from bursting a large amount of data in
+ * the midst of sack recovery.
*/
void
tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th)
@@ -590,12 +570,11 @@ tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th)
INP_LOCK_ASSERT(tp->t_inpcb);
tcp_timer_activate(tp, TT_REXMT, 0);
tp->t_rtttime = 0;
- /* send one or 2 segments based on how much new data was acked */
+ /* Send one or 2 segments based on how much new data was acked. */
if (((th->th_ack - tp->snd_una) / tp->t_maxseg) > 2)
num_segs = 2;
tp->snd_cwnd = (tp->sackhint.sack_bytes_rexmit +
- (tp->snd_nxt - tp->sack_newdata) +
- num_segs * tp->t_maxseg);
+ (tp->snd_nxt - tp->sack_newdata) + num_segs * tp->t_maxseg);
if (tp->snd_cwnd > tp->snd_ssthresh)
tp->snd_cwnd = tp->snd_ssthresh;
tp->t_flags |= TF_ACKNOW;
@@ -604,7 +583,7 @@ tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th)
#if 0
/*
- * Debug version of tcp_sack_output() that walks the scoreboard. Used for
+ * Debug version of tcp_sack_output() that walks the scoreboard. Used for
* now to sanity check the hint.
*/
static struct sackhole *
@@ -630,20 +609,20 @@ tcp_sack_output_debug(struct tcpcb *tp, int *sack_bytes_rexmt)
/*
* Returns the next hole to retransmit and the number of retransmitted bytes
- * from the scoreboard. We store both the next hole and the number of
+ * from the scoreboard. We store both the next hole and the number of
* retransmitted bytes as hints (and recompute these on the fly upon SACK/ACK
- * reception). This avoids scoreboard traversals completely.
+ * reception). This avoids scoreboard traversals completely.
*
- * The loop here will traverse *at most* one link. Here's the argument.
- * For the loop to traverse more than 1 link before finding the next hole to
- * retransmit, we would need to have at least 1 node following the current hint
- * with (rxmit == end). But, for all holes following the current hint,
- * (start == rxmit), since we have not yet retransmitted from them. Therefore,
- * in order to traverse more 1 link in the loop below, we need to have at least
- * one node following the current hint with (start == rxmit == end).
- * But that can't happen, (start == end) means that all the data in that hole
- * has been sacked, in which case, the hole would have been removed from the
- * scoreboard.
+ * The loop here will traverse *at most* one link. Here's the argument. For
+ * the loop to traverse more than 1 link before finding the next hole to
+ * retransmit, we would need to have at least 1 node following the current
+ * hint with (rxmit == end). But, for all holes following the current hint,
+ * (start == rxmit), since we have not yet retransmitted from them.
+ * Therefore, in order to traverse more 1 link in the loop below, we need to
+ * have at least one node following the current hint with (start == rxmit ==
+ * end). But that can't happen, (start == end) means that all the data in
+ * that hole has been sacked, in which case, the hole would have been removed
+ * from the scoreboard.
*/
struct sackhole *
tcp_sack_output(struct tcpcb *tp, int *sack_bytes_rexmt)
@@ -680,7 +659,7 @@ tcp_sack_adjust(struct tcpcb *tp)
return; /* No holes */
if (SEQ_GEQ(tp->snd_nxt, tp->snd_fack))
return; /* We're already beyond any SACKed blocks */
- /*
+ /*-
* Two cases for which we want to advance snd_nxt:
* i) snd_nxt lies between end of one hole and beginning of another
* ii) snd_nxt lies between end of last hole and snd_fack
OpenPOWER on IntegriCloud