Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_sack.c
Show First 20 Lines • Show All 491 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Insert new SACK hole into scoreboard. | * Insert new SACK hole into scoreboard. | ||||
*/ | */ | ||||
static struct sackhole * | static struct sackhole * | ||||
tcp_sackhole_insert(struct tcpcb *tp, tcp_seq start, tcp_seq end, | tcp_sackhole_insert(struct tcpcb *tp, tcp_seq start, tcp_seq end, | ||||
struct sackhole *after) | struct sackhole *after) | ||||
{ | { | ||||
struct sackhole *hole, *tail; | struct sackhole *hole; | ||||
/* Allocate a new SACK hole. */ | /* Allocate a new SACK hole. */ | ||||
hole = tcp_sackhole_alloc(tp, start, end); | hole = tcp_sackhole_alloc(tp, start, end); | ||||
if (hole == NULL) | if (hole == NULL) | ||||
return NULL; | return NULL; | ||||
/* Insert the new SACK hole into scoreboard. */ | /* Insert the new SACK hole into scoreboard. */ | ||||
if (after != NULL) | if (after != NULL) | ||||
TAILQ_INSERT_AFTER(&tp->snd_holes, after, hole, scblink); | TAILQ_INSERT_AFTER(&tp->snd_holes, after, hole, scblink); | ||||
else | else | ||||
/* | |||||
* With Rescue Retransmission, new holes may need to | |||||
* be inserted just before the tail. | |||||
*/ | |||||
if (((tail = TAILQ_LAST_FAST(&tp->snd_holes, sackhole, | |||||
scblink)) != NULL) && SEQ_LEQ(end, tail->start)) | |||||
TAILQ_INSERT_BEFORE(tail, hole, scblink); | |||||
else | |||||
TAILQ_INSERT_TAIL(&tp->snd_holes, hole, scblink); | TAILQ_INSERT_TAIL(&tp->snd_holes, hole, scblink); | ||||
/* Update SACK hint. */ | /* Update SACK hint. */ | ||||
if (tp->sackhint.nexthole == NULL) | if (tp->sackhint.nexthole == NULL) | ||||
tp->sackhint.nexthole = hole; | tp->sackhint.nexthole = hole; | ||||
return hole; | return hole; | ||||
} | } | ||||
Show All 40 Lines | tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack) | ||||
* If SND.UNA will be advanced by SEG.ACK, and if SACK holes exist, | * If SND.UNA will be advanced by SEG.ACK, and if SACK holes exist, | ||||
* treat [SND.UNA, SEG.ACK) as if it is a SACK block. | * treat [SND.UNA, SEG.ACK) as if it is a SACK block. | ||||
* Account changes to SND.UNA always in delivered data. | * Account changes to SND.UNA always in delivered data. | ||||
*/ | */ | ||||
if (SEQ_LT(tp->snd_una, th_ack) && !TAILQ_EMPTY(&tp->snd_holes)) { | if (SEQ_LT(tp->snd_una, th_ack) && !TAILQ_EMPTY(&tp->snd_holes)) { | ||||
left_edge_delta = th_ack - tp->snd_una; | left_edge_delta = th_ack - tp->snd_una; | ||||
sack_blocks[num_sack_blks].start = tp->snd_una; | sack_blocks[num_sack_blks].start = tp->snd_una; | ||||
sack_blocks[num_sack_blks++].end = th_ack; | sack_blocks[num_sack_blks++].end = th_ack; | ||||
/* | |||||
* Pulling snd_fack forward if we got here | |||||
* due to DSACK blocks | |||||
*/ | |||||
if (SEQ_LT(tp->snd_fack, th_ack)) { | |||||
delivered_data += th_ack - tp->snd_una; | |||||
tp->snd_fack = th_ack; | |||||
sack_changed = 1; | |||||
} | } | ||||
} | |||||
/* | /* | ||||
* Append received valid SACK blocks to sack_blocks[], but only if we | * Append received valid SACK blocks to sack_blocks[], but only if we | ||||
* received new blocks from the other side. | * received new blocks from the other side. | ||||
*/ | */ | ||||
if (to->to_flags & TOF_SACK) { | if (to->to_flags & TOF_SACK) { | ||||
for (i = 0; i < to->to_nsacks; i++) { | for (i = 0; i < to->to_nsacks; i++) { | ||||
bcopy((to->to_sacks + i * TCPOLEN_SACK), | bcopy((to->to_sacks + i * TCPOLEN_SACK), | ||||
&sack, sizeof(sack)); | &sack, sizeof(sack)); | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack) | ||||
* In the second RTT, if retransmitted data segments are not lost, | * In the second RTT, if retransmitted data segments are not lost, | ||||
* the highest three or four SACK blocks with ack number advancing | * the highest three or four SACK blocks with ack number advancing | ||||
* are received. | * are received. | ||||
*/ | */ | ||||
sblkp = &sack_blocks[num_sack_blks - 1]; /* Last SACK block */ | sblkp = &sack_blocks[num_sack_blks - 1]; /* Last SACK block */ | ||||
tp->sackhint.last_sack_ack = sblkp->end; | tp->sackhint.last_sack_ack = sblkp->end; | ||||
if (SEQ_LT(tp->snd_fack, sblkp->start)) { | if (SEQ_LT(tp->snd_fack, sblkp->start)) { | ||||
/* | /* | ||||
* The highest SACK block is beyond fack. Append new SACK | * The highest SACK block is beyond fack. First, | ||||
* hole at the tail. If the second or later highest SACK | * check if there was a successful Rescue Retransmission, | ||||
* blocks are also beyond the current fack, they will be | * and move this hole left. With normal holes, snd_fack | ||||
* inserted by way of hole splitting in the while-loop below. | * is always to the right of the end. | ||||
*/ | */ | ||||
if (((temp = TAILQ_LAST(&tp->snd_holes, sackhole_head)) != NULL) && | |||||
SEQ_LEQ(tp->snd_fack,temp->end)) { | |||||
temp->start = SEQ_MAX(tp->snd_fack, SEQ_MAX(tp->snd_una, th_ack)); | |||||
temp->end = sblkp->start; | |||||
temp->rxmit = temp->start; | |||||
delivered_data += sblkp->end - sblkp->start; | |||||
tp->snd_fack = sblkp->end; | |||||
sblkp--; | |||||
sack_changed = 1; | |||||
} else { | |||||
/* | |||||
* Append a 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); | temp = tcp_sackhole_insert(tp, tp->snd_fack,sblkp->start,NULL); | ||||
if (temp != NULL) { | if (temp != NULL) { | ||||
delivered_data += sblkp->end - sblkp->start; | delivered_data += sblkp->end - sblkp->start; | ||||
tp->snd_fack = sblkp->end; | tp->snd_fack = sblkp->end; | ||||
/* Go to the previous sack block. */ | /* Go to the previous sack block. */ | ||||
sblkp--; | sblkp--; | ||||
sack_changed = 1; | sack_changed = 1; | ||||
} else { | } else { | ||||
/* | /* | ||||
* We failed to add a new hole based on the current | * We failed to add a new hole based on the current | ||||
* sack block. Skip over all the sack blocks that | * sack block. Skip over all the sack blocks that | ||||
* fall completely to the right of snd_fack and | * fall completely to the right of snd_fack and | ||||
* proceed to trim the scoreboard based on the | * proceed to trim the scoreboard based on the | ||||
* remaining sack blocks. This also trims the | * remaining sack blocks. This also trims the | ||||
* scoreboard for th_ack (which is sack_blocks[0]). | * scoreboard for th_ack (which is sack_blocks[0]). | ||||
*/ | */ | ||||
while (sblkp >= sack_blocks && | while (sblkp >= sack_blocks && | ||||
SEQ_LT(tp->snd_fack, sblkp->start)) | SEQ_LT(tp->snd_fack, sblkp->start)) | ||||
sblkp--; | sblkp--; | ||||
if (sblkp >= sack_blocks && | if (sblkp >= sack_blocks && | ||||
SEQ_LT(tp->snd_fack, sblkp->end)) { | SEQ_LT(tp->snd_fack, sblkp->end)) { | ||||
delivered_data += sblkp->end - tp->snd_fack; | delivered_data += sblkp->end - tp->snd_fack; | ||||
tp->snd_fack = sblkp->end; | tp->snd_fack = sblkp->end; | ||||
sack_changed = 1; | sack_changed = 1; | ||||
} | |||||
} | } | ||||
} | } | ||||
} else if (SEQ_LT(tp->snd_fack, sblkp->end)) { | } else if (SEQ_LT(tp->snd_fack, sblkp->end)) { | ||||
/* fack is advanced. */ | /* fack is advanced. */ | ||||
delivered_data += sblkp->end - tp->snd_fack; | delivered_data += sblkp->end - tp->snd_fack; | ||||
tp->snd_fack = sblkp->end; | tp->snd_fack = sblkp->end; | ||||
sack_changed = 1; | sack_changed = 1; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 279 Lines • Show Last 20 Lines |