Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_sack.c
Show First 20 Lines • Show All 113 Lines • ▼ Show 20 Lines | |||||
#include <netinet6/in6_pcb.h> | #include <netinet6/in6_pcb.h> | ||||
#include <netinet/tcp.h> | #include <netinet/tcp.h> | ||||
#include <netinet/tcp_fsm.h> | #include <netinet/tcp_fsm.h> | ||||
#include <netinet/tcp_seq.h> | #include <netinet/tcp_seq.h> | ||||
#include <netinet/tcp_timer.h> | #include <netinet/tcp_timer.h> | ||||
#include <netinet/tcp_var.h> | #include <netinet/tcp_var.h> | ||||
#include <netinet6/tcp6_var.h> | #include <netinet6/tcp6_var.h> | ||||
#include <netinet/tcpip.h> | #include <netinet/tcpip.h> | ||||
#include <netinet/cc/cc.h> | |||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
#include <netinet/tcp_debug.h> | #include <netinet/tcp_debug.h> | ||||
#endif /* TCPDEBUG */ | #endif /* TCPDEBUG */ | ||||
#include <machine/in_cksum.h> | #include <machine/in_cksum.h> | ||||
VNET_DECLARE(struct uma_zone *, sack_hole_zone); | VNET_DECLARE(struct uma_zone *, sack_hole_zone); | ||||
#define V_sack_hole_zone VNET(sack_hole_zone) | #define V_sack_hole_zone VNET(sack_hole_zone) | ||||
▲ Show 20 Lines • Show All 595 Lines • ▼ Show 20 Lines | while (sblkp >= sack_blocks && cur != NULL) { | ||||
if (SEQ_LEQ(sblkp->end, cur->start)) { | if (SEQ_LEQ(sblkp->end, cur->start)) { | ||||
/* | /* | ||||
* SACKs data before the current hole. Go to the | * SACKs data before the current hole. Go to the | ||||
* previous hole. | * previous hole. | ||||
*/ | */ | ||||
cur = TAILQ_PREV(cur, sackhole_head, scblink); | cur = TAILQ_PREV(cur, sackhole_head, scblink); | ||||
continue; | continue; | ||||
} | } | ||||
tp->sackhint.sack_bytes_rexmit -= (cur->rxmit - cur->start); | tp->sackhint.sack_bytes_rexmit -= | ||||
(SEQ_MIN(cur->rxmit, cur->end) - cur->start); | |||||
KASSERT(tp->sackhint.sack_bytes_rexmit >= 0, | KASSERT(tp->sackhint.sack_bytes_rexmit >= 0, | ||||
("sackhint bytes rtx >= 0")); | ("sackhint bytes rtx >= 0")); | ||||
sack_changed = 1; | sack_changed = 1; | ||||
if (SEQ_LEQ(sblkp->start, cur->start)) { | 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)) { | if (SEQ_GEQ(sblkp->end, cur->end)) { | ||||
/* Acks entire hole, so delete hole. */ | /* Acks entire hole, so delete hole. */ | ||||
delivered_data += (cur->end - cur->start); | delivered_data += (cur->end - cur->start); | ||||
Show All 14 Lines | if (SEQ_LEQ(sblkp->start, cur->start)) { | ||||
} | } | ||||
} else { | } else { | ||||
/* Data acks at least the end of hole. */ | /* Data acks at least the end of hole. */ | ||||
if (SEQ_GEQ(sblkp->end, cur->end)) { | if (SEQ_GEQ(sblkp->end, cur->end)) { | ||||
/* Move end of hole backward. */ | /* Move end of hole backward. */ | ||||
delivered_data += (cur->end - sblkp->start); | delivered_data += (cur->end - sblkp->start); | ||||
cur->end = sblkp->start; | cur->end = sblkp->start; | ||||
cur->rxmit = SEQ_MIN(cur->rxmit, cur->end); | cur->rxmit = SEQ_MIN(cur->rxmit, cur->end); | ||||
if ((tp->t_flags & TF_LRD) && SEQ_GEQ(cur->rxmit, cur->end)) | |||||
cur->rxmit = tp->snd_recover; | |||||
} else { | } else { | ||||
/* | /* | ||||
* ACKs some data in middle of a hole; need | * ACKs some data in middle of a hole; need | ||||
* to split current hole | * to split current hole | ||||
*/ | */ | ||||
temp = tcp_sackhole_insert(tp, sblkp->end, | temp = tcp_sackhole_insert(tp, sblkp->end, | ||||
cur->end, cur); | cur->end, cur); | ||||
if (temp != NULL) { | if (temp != NULL) { | ||||
if (SEQ_GT(cur->rxmit, temp->rxmit)) { | if (SEQ_GT(cur->rxmit, temp->rxmit)) { | ||||
temp->rxmit = cur->rxmit; | temp->rxmit = cur->rxmit; | ||||
tp->sackhint.sack_bytes_rexmit | tp->sackhint.sack_bytes_rexmit += | ||||
+= (temp->rxmit | (SEQ_MIN(temp->rxmit, | ||||
- temp->start); | temp->end) - temp->start); | ||||
tuexen: You might want to put `+=` at the end of the line before. | |||||
} | } | ||||
cur->end = sblkp->start; | cur->end = sblkp->start; | ||||
cur->rxmit = SEQ_MIN(cur->rxmit, | cur->rxmit = SEQ_MIN(cur->rxmit, | ||||
cur->end); | cur->end); | ||||
if ((tp->t_flags & TF_LRD) && SEQ_GEQ(cur->rxmit, cur->end)) | |||||
cur->rxmit = tp->snd_recover; | |||||
delivered_data += (sblkp->end - sblkp->start); | delivered_data += (sblkp->end - sblkp->start); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
tp->sackhint.sack_bytes_rexmit += (cur->rxmit - cur->start); | tp->sackhint.sack_bytes_rexmit += | ||||
(SEQ_MIN(cur->rxmit, cur->end) - cur->start); | |||||
/* | /* | ||||
* Testing sblkp->start against cur->start tells us whether | * Testing sblkp->start against cur->start tells us whether | ||||
* we're done with the sack block or the sack hole. | * we're done with the sack block or the sack hole. | ||||
* Accordingly, we advance one or the other. | * Accordingly, we advance one or the other. | ||||
*/ | */ | ||||
if (SEQ_LEQ(sblkp->start, cur->start)) | if (SEQ_LEQ(sblkp->start, cur->start)) | ||||
cur = TAILQ_PREV(cur, sackhole_head, scblink); | cur = TAILQ_PREV(cur, sackhole_head, scblink); | ||||
else | else | ||||
▲ Show 20 Lines • Show All 113 Lines • ▼ Show 20 Lines | tcp_sack_output_debug(struct tcpcb *tp, int *sack_bytes_rexmt) | ||||
TAILQ_FOREACH(p, &tp->snd_holes, scblink) { | TAILQ_FOREACH(p, &tp->snd_holes, scblink) { | ||||
if (SEQ_LT(p->rxmit, p->end)) { | if (SEQ_LT(p->rxmit, p->end)) { | ||||
if (SEQ_LT(p->rxmit, tp->snd_una)) {/* old SACK hole */ | if (SEQ_LT(p->rxmit, tp->snd_una)) {/* old SACK hole */ | ||||
continue; | continue; | ||||
} | } | ||||
*sack_bytes_rexmt += (p->rxmit - p->start); | *sack_bytes_rexmt += (p->rxmit - p->start); | ||||
break; | break; | ||||
} | } | ||||
*sack_bytes_rexmt += (p->rxmit - p->start); | *sack_bytes_rexmt += (SEQ_MIN(p->rxmit, p->end) - p->start); | ||||
} | } | ||||
return (p); | return (p); | ||||
} | } | ||||
#endif | #endif | ||||
/* | /* | ||||
* Returns the next hole to retransmit and the number of retransmitted bytes | * 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 | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | while ((p = TAILQ_NEXT(cur, scblink)) != NULL) { | ||||
else { | else { | ||||
tp->snd_nxt = p->start; | tp->snd_nxt = p->start; | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
if (SEQ_LT(tp->snd_nxt, cur->end)) | if (SEQ_LT(tp->snd_nxt, cur->end)) | ||||
return; | return; | ||||
tp->snd_nxt = tp->snd_fack; | tp->snd_nxt = tp->snd_fack; | ||||
} | |||||
/* | |||||
* Lost Retransmission Detection | |||||
* Check is FACK is beyond the rexmit of the leftmost hole. | |||||
* If yes, we restart sending from still existing holes, | |||||
* and adjust cwnd via the congestion control module. | |||||
*/ | |||||
void | |||||
tcp_sack_lost_retransmission(struct tcpcb *tp, struct tcphdr *th) | |||||
{ | |||||
struct sackhole *temp; | |||||
uint32_t prev_cwnd; | |||||
if (IN_RECOVERY(tp->t_flags) && | |||||
SEQ_GT(tp->snd_fack, tp->snd_recover) && | |||||
((temp = TAILQ_FIRST(&tp->snd_holes)) != NULL) && | |||||
SEQ_GEQ(temp->rxmit, temp->end) && | |||||
SEQ_GEQ(tp->snd_fack, temp->rxmit)) { | |||||
TCPSTAT_INC(tcps_sack_lostrexmt); | |||||
/* | |||||
* Start retransmissions from the first hole, and | |||||
* subsequently all other remaining holes, including | |||||
* those, which had been sent completely before. | |||||
*/ | |||||
tp->sackhint.nexthole = temp; | |||||
TAILQ_FOREACH(temp, &tp->snd_holes, scblink) { | |||||
if (SEQ_GEQ(tp->snd_fack, temp->rxmit) && | |||||
SEQ_GEQ(temp->rxmit, temp->end)) | |||||
temp->rxmit = temp->start; | |||||
} | |||||
/* | |||||
* Remember the old ssthresh, to deduct the beta factor used | |||||
* by the CC module. Finally, set cwnd to ssthresh just | |||||
* prior to invoking another cwnd reduction by the CC | |||||
* module, to not shrink it excessively. | |||||
*/ | |||||
prev_cwnd = tp->snd_cwnd; | |||||
tp->snd_cwnd = tp->snd_ssthresh; | |||||
/* | |||||
* Formally exit recovery, and let the CC module adjust | |||||
* ssthresh as intended. | |||||
*/ | |||||
EXIT_RECOVERY(tp->t_flags); | |||||
cc_cong_signal(tp, th, CC_NDUPACK); | |||||
/* | |||||
* For PRR, adjust recover_fs as if this new reduction | |||||
* initialized this variable. | |||||
* cwnd will be adjusted by SACK or PRR processing | |||||
* subsequently, only set it to a safe value here. | |||||
*/ | |||||
tp->snd_cwnd = tcp_maxseg(tp); | |||||
tp->sackhint.recover_fs = (tp->snd_max - tp->snd_una) - | |||||
tp->sackhint.recover_fs; | |||||
} | |||||
} | } |
You might want to put += at the end of the line before.