Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/cc/cc_newreno.c
Show First 20 Lines • Show All 161 Lines • ▼ Show 20 Lines | if (tp->t_logstate != TCP_LOG_STATE_OFF) { | ||||
TCP_LOG_EVENTP(tp, NULL, | TCP_LOG_EVENTP(tp, NULL, | ||||
&tp->t_inpcb->inp_socket->so_rcv, | &tp->t_inpcb->inp_socket->so_rcv, | ||||
&tp->t_inpcb->inp_socket->so_snd, | &tp->t_inpcb->inp_socket->so_snd, | ||||
TCP_HYSTART, 0, | TCP_HYSTART, 0, | ||||
0, &log, false, &tv); | 0, &log, false, &tv); | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
newreno_cb_init(struct cc_var *ccv) | newreno_cb_init(struct cc_var *ccv) | ||||
{ | { | ||||
struct newreno *nreno; | struct newreno *nreno; | ||||
ccv->cc_data = NULL; | |||||
ccv->cc_data = malloc(sizeof(struct newreno), M_NEWRENO, M_NOWAIT); | ccv->cc_data = malloc(sizeof(struct newreno), M_NEWRENO, M_NOWAIT); | ||||
if (ccv->cc_data == NULL) | if (ccv->cc_data == NULL) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
nreno = (struct newreno *)ccv->cc_data; | nreno = (struct newreno *)ccv->cc_data; | ||||
/* NB: nreno is not zeroed, so initialise all fields. */ | /* NB: nreno is not zeroed, so initialise all fields. */ | ||||
nreno->beta = V_newreno_beta; | nreno->beta = V_newreno_beta; | ||||
nreno->beta_ecn = V_newreno_beta_ecn; | nreno->beta_ecn = V_newreno_beta_ecn; | ||||
/* | /* | ||||
Show All 21 Lines | newreno_cb_destroy(struct cc_var *ccv) | ||||
free(ccv->cc_data, M_NEWRENO); | free(ccv->cc_data, M_NEWRENO); | ||||
} | } | ||||
static void | static void | ||||
newreno_ack_received(struct cc_var *ccv, uint16_t type) | newreno_ack_received(struct cc_var *ccv, uint16_t type) | ||||
{ | { | ||||
struct newreno *nreno; | struct newreno *nreno; | ||||
nreno = (struct newreno *)ccv->cc_data; | /* | ||||
* Other TCP congestion controls use newreno_ack_received(), but | |||||
* with their own private cc_data. Make sure the cc_data is used | |||||
* correctly. | |||||
*/ | |||||
nreno = (CC_ALGO(ccv->ccvc.tcp) == &newreno_cc_algo) ? ccv->cc_data : NULL; | |||||
if (type == CC_ACK && !IN_RECOVERY(CCV(ccv, t_flags)) && | if (type == CC_ACK && !IN_RECOVERY(CCV(ccv, t_flags)) && | ||||
(ccv->flags & CCF_CWND_LIMITED)) { | (ccv->flags & CCF_CWND_LIMITED)) { | ||||
u_int cw = CCV(ccv, snd_cwnd); | u_int cw = CCV(ccv, snd_cwnd); | ||||
u_int incr = CCV(ccv, t_maxseg); | u_int incr = CCV(ccv, t_maxseg); | ||||
/* | /* | ||||
* Regular in-order ACK, open the congestion window. | * Regular in-order ACK, open the congestion window. | ||||
* Method depends on which congestion control state we're | * Method depends on which congestion control state we're | ||||
Show All 17 Lines | if (type == CC_ACK && !IN_RECOVERY(CCV(ccv, t_flags)) && | ||||
* | * | ||||
* cong avoid without ABC (RFC 5681): | * cong avoid without ABC (RFC 5681): | ||||
* Grow cwnd linearly by approximately maxseg per RTT using | * Grow cwnd linearly by approximately maxseg per RTT using | ||||
* maxseg^2 / cwnd per ACK as the increment. | * maxseg^2 / cwnd per ACK as the increment. | ||||
* If cwnd > maxseg^2, fix the cwnd increment at 1 byte to | * If cwnd > maxseg^2, fix the cwnd increment at 1 byte to | ||||
* avoid capping cwnd. | * avoid capping cwnd. | ||||
*/ | */ | ||||
if (cw > CCV(ccv, snd_ssthresh)) { | if (cw > CCV(ccv, snd_ssthresh)) { | ||||
if (nreno->newreno_flags & CC_NEWRENO_HYSTART_IN_CSS) { | if ((nreno != NULL) && | ||||
(nreno->newreno_flags & CC_NEWRENO_HYSTART_IN_CSS)) { | |||||
/* | /* | ||||
* We have slipped into CA with | * We have slipped into CA with | ||||
* CSS active. Deactivate all. | * CSS active. Deactivate all. | ||||
*/ | */ | ||||
/* Turn off the CSS flag */ | /* Turn off the CSS flag */ | ||||
nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS; | nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS; | ||||
/* Disable use of CSS in the future except long idle */ | /* Disable use of CSS in the future except long idle */ | ||||
nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_ENABLED; | nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_ENABLED; | ||||
Show All 17 Lines | if (cw > CCV(ccv, snd_ssthresh)) { | ||||
* doesn't rely on tcpcb vars. | * doesn't rely on tcpcb vars. | ||||
*/ | */ | ||||
uint16_t abc_val; | uint16_t abc_val; | ||||
if (ccv->flags & CCF_USE_LOCAL_ABC) | if (ccv->flags & CCF_USE_LOCAL_ABC) | ||||
abc_val = ccv->labc; | abc_val = ccv->labc; | ||||
else | else | ||||
abc_val = V_tcp_abc_l_var; | abc_val = V_tcp_abc_l_var; | ||||
if ((nreno->newreno_flags & CC_NEWRENO_HYSTART_ALLOWED) && | if ((nreno != NULL) && | ||||
(nreno->newreno_flags & CC_NEWRENO_HYSTART_ALLOWED) && | |||||
(nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED) && | (nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED) && | ||||
((nreno->newreno_flags & CC_NEWRENO_HYSTART_IN_CSS) == 0)) { | ((nreno->newreno_flags & CC_NEWRENO_HYSTART_IN_CSS) == 0)) { | ||||
/* | /* | ||||
* Hystart is allowed and still enabled and we are not yet | * Hystart is allowed and still enabled and we are not yet | ||||
* in CSS. Lets check to see if we can make a decision on | * in CSS. Lets check to see if we can make a decision on | ||||
* if we need to go into CSS. | * if we need to go into CSS. | ||||
*/ | */ | ||||
if ((nreno->css_rttsample_count >= hystart_n_rttsamples) && | if ((nreno->css_rttsample_count >= hystart_n_rttsamples) && | ||||
Show All 21 Lines | if (cw > CCV(ccv, snd_ssthresh)) { | ||||
if (CCV(ccv, snd_nxt) == CCV(ccv, snd_max)) | if (CCV(ccv, snd_nxt) == CCV(ccv, snd_max)) | ||||
incr = min(ccv->bytes_this_ack, | incr = min(ccv->bytes_this_ack, | ||||
ccv->nsegs * abc_val * | ccv->nsegs * abc_val * | ||||
CCV(ccv, t_maxseg)); | CCV(ccv, t_maxseg)); | ||||
else | else | ||||
incr = min(ccv->bytes_this_ack, CCV(ccv, t_maxseg)); | incr = min(ccv->bytes_this_ack, CCV(ccv, t_maxseg)); | ||||
/* Only if Hystart is enabled will the flag get set */ | /* Only if Hystart is enabled will the flag get set */ | ||||
if (nreno->newreno_flags & CC_NEWRENO_HYSTART_IN_CSS) { | if ((nreno != NULL) && | ||||
(nreno->newreno_flags & CC_NEWRENO_HYSTART_IN_CSS)) { | |||||
incr /= hystart_css_growth_div; | incr /= hystart_css_growth_div; | ||||
newreno_log_hystart_event(ccv, nreno, 3, incr); | newreno_log_hystart_event(ccv, nreno, 3, incr); | ||||
} | } | ||||
} | } | ||||
/* ABC is on by default, so incr equals 0 frequently. */ | /* ABC is on by default, so incr equals 0 frequently. */ | ||||
if (incr > 0) | if (incr > 0) | ||||
CCV(ccv, snd_cwnd) = min(cw + incr, | CCV(ccv, snd_cwnd) = min(cw + incr, | ||||
TCP_MAXWIN << CCV(ccv, snd_scale)); | TCP_MAXWIN << CCV(ccv, snd_scale)); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
newreno_after_idle(struct cc_var *ccv) | newreno_after_idle(struct cc_var *ccv) | ||||
{ | { | ||||
struct newreno *nreno; | struct newreno *nreno; | ||||
uint32_t rw; | uint32_t rw; | ||||
nreno = (struct newreno *)ccv->cc_data; | |||||
/* | /* | ||||
* Other TCP congestion controls use newreno_after_idle(), but | |||||
* with their own private cc_data. Make sure the cc_data is used | |||||
* correctly. | |||||
*/ | |||||
nreno = (CC_ALGO(ccv->ccvc.tcp) == &newreno_cc_algo) ? ccv->cc_data : NULL; | |||||
/* | |||||
* If we've been idle for more than one retransmit timeout the old | * If we've been idle for more than one retransmit timeout the old | ||||
* congestion window is no longer current and we have to reduce it to | * congestion window is no longer current and we have to reduce it to | ||||
* the restart window before we can transmit again. | * the restart window before we can transmit again. | ||||
* | * | ||||
* The restart window is the initial window or the last CWND, whichever | * The restart window is the initial window or the last CWND, whichever | ||||
* is smaller. | * is smaller. | ||||
* | * | ||||
* This is done to prevent us from flooding the path with a full CWND at | * This is done to prevent us from flooding the path with a full CWND at | ||||
* wirespeed, overloading router and switch buffers along the way. | * wirespeed, overloading router and switch buffers along the way. | ||||
* | * | ||||
* See RFC5681 Section 4.1. "Restarting Idle Connections". | * See RFC5681 Section 4.1. "Restarting Idle Connections". | ||||
* | * | ||||
* In addition, per RFC2861 Section 2, the ssthresh is set to the | * In addition, per RFC2861 Section 2, the ssthresh is set to the | ||||
* maximum of the former ssthresh or 3/4 of the old cwnd, to | * maximum of the former ssthresh or 3/4 of the old cwnd, to | ||||
* not exit slow-start prematurely. | * not exit slow-start prematurely. | ||||
*/ | */ | ||||
rw = tcp_compute_initwnd(tcp_maxseg(ccv->ccvc.tcp)); | rw = tcp_compute_initwnd(tcp_maxseg(ccv->ccvc.tcp)); | ||||
CCV(ccv, snd_ssthresh) = max(CCV(ccv, snd_ssthresh), | CCV(ccv, snd_ssthresh) = max(CCV(ccv, snd_ssthresh), | ||||
CCV(ccv, snd_cwnd)-(CCV(ccv, snd_cwnd)>>2)); | CCV(ccv, snd_cwnd)-(CCV(ccv, snd_cwnd)>>2)); | ||||
CCV(ccv, snd_cwnd) = min(rw, CCV(ccv, snd_cwnd)); | CCV(ccv, snd_cwnd) = min(rw, CCV(ccv, snd_cwnd)); | ||||
if ((nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED) == 0) { | if ((nreno != NULL) && | ||||
(nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED) == 0) { | |||||
if (CCV(ccv, snd_cwnd) <= (hystart_lowcwnd * tcp_fixed_maxseg(ccv->ccvc.tcp))) { | if (CCV(ccv, snd_cwnd) <= (hystart_lowcwnd * tcp_fixed_maxseg(ccv->ccvc.tcp))) { | ||||
/* | /* | ||||
* Re-enable hystart if our cwnd has fallen below | * Re-enable hystart if our cwnd has fallen below | ||||
* the hystart lowcwnd point. | * the hystart lowcwnd point. | ||||
*/ | */ | ||||
nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS; | nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS; | ||||
nreno->newreno_flags |= CC_NEWRENO_HYSTART_ENABLED; | nreno->newreno_flags |= CC_NEWRENO_HYSTART_ENABLED; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Perform any necessary tasks before we enter congestion recovery. | * Perform any necessary tasks before we enter congestion recovery. | ||||
*/ | */ | ||||
static void | static void | ||||
newreno_cong_signal(struct cc_var *ccv, uint32_t type) | newreno_cong_signal(struct cc_var *ccv, uint32_t type) | ||||
{ | { | ||||
struct newreno *nreno; | struct newreno *nreno; | ||||
uint32_t beta, beta_ecn, cwin, factor; | uint32_t beta, beta_ecn, cwin, factor; | ||||
u_int mss; | u_int mss; | ||||
cwin = CCV(ccv, snd_cwnd); | cwin = CCV(ccv, snd_cwnd); | ||||
mss = tcp_fixed_maxseg(ccv->ccvc.tcp); | mss = tcp_fixed_maxseg(ccv->ccvc.tcp); | ||||
nreno = (struct newreno *) ccv->cc_data; | |||||
beta = nreno->beta; | |||||
beta_ecn = nreno->beta_ecn; | |||||
/* | /* | ||||
* Other TCP congestion controls use newreno_cong_signal(), but | |||||
* with their own private cc_data. Make sure the cc_data is used | |||||
* correctly. | |||||
*/ | |||||
nreno = (CC_ALGO(ccv->ccvc.tcp) == &newreno_cc_algo) ? ccv->cc_data : NULL; | |||||
beta = (nreno == NULL) ? V_newreno_beta : nreno->beta;; | |||||
rrs: nit double ;; on end | |||||
beta_ecn = (nreno == NULL) ? V_newreno_beta_ecn : nreno->beta_ecn; | |||||
/* | |||||
* Note that we only change the backoff for ECN if the | * Note that we only change the backoff for ECN if the | ||||
* global sysctl V_cc_do_abe is set <or> the stack itself | * global sysctl V_cc_do_abe is set <or> the stack itself | ||||
* has set a flag in our newreno_flags (due to pacing) telling | * has set a flag in our newreno_flags (due to pacing) telling | ||||
* us to use the lower valued back-off. | * us to use the lower valued back-off. | ||||
*/ | */ | ||||
if ((type == CC_ECN) && | if ((type == CC_ECN) && | ||||
(V_cc_do_abe || | (V_cc_do_abe || | ||||
((nreno != NULL) && (nreno->newreno_flags & CC_NEWRENO_BETA_ECN_ENABLED)))) | ((nreno != NULL) && (nreno->newreno_flags & CC_NEWRENO_BETA_ECN_ENABLED)))) | ||||
factor = beta_ecn; | factor = beta_ecn; | ||||
else | else | ||||
factor = beta; | factor = beta; | ||||
/* Catch algos which mistakenly leak private signal types. */ | /* Catch algos which mistakenly leak private signal types. */ | ||||
KASSERT((type & CC_SIGPRIVMASK) == 0, | KASSERT((type & CC_SIGPRIVMASK) == 0, | ||||
("%s: congestion signal type 0x%08x is private\n", __func__, type)); | ("%s: congestion signal type 0x%08x is private\n", __func__, type)); | ||||
cwin = max(((uint64_t)cwin * (uint64_t)factor) / (100ULL * (uint64_t)mss), | cwin = max(((uint64_t)cwin * (uint64_t)factor) / (100ULL * (uint64_t)mss), | ||||
2) * mss; | 2) * mss; | ||||
switch (type) { | switch (type) { | ||||
case CC_NDUPACK: | case CC_NDUPACK: | ||||
if (nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED) { | if ((nreno != NULL) && | ||||
(nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED)) { | |||||
/* Make sure the flags are all off we had a loss */ | /* Make sure the flags are all off we had a loss */ | ||||
nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_ENABLED; | nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_ENABLED; | ||||
nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS; | nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS; | ||||
} | } | ||||
if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) { | if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) { | ||||
if (IN_CONGRECOVERY(CCV(ccv, t_flags) && | if (IN_CONGRECOVERY(CCV(ccv, t_flags) && | ||||
V_cc_do_abe && V_cc_abe_frlossreduce)) { | V_cc_do_abe && V_cc_abe_frlossreduce)) { | ||||
CCV(ccv, snd_ssthresh) = | CCV(ccv, snd_ssthresh) = | ||||
((uint64_t)CCV(ccv, snd_ssthresh) * | ((uint64_t)CCV(ccv, snd_ssthresh) * | ||||
(uint64_t)beta) / (uint64_t)beta_ecn; | (uint64_t)beta) / (uint64_t)beta_ecn; | ||||
} | } | ||||
if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) | if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) | ||||
CCV(ccv, snd_ssthresh) = cwin; | CCV(ccv, snd_ssthresh) = cwin; | ||||
ENTER_RECOVERY(CCV(ccv, t_flags)); | ENTER_RECOVERY(CCV(ccv, t_flags)); | ||||
} | } | ||||
break; | break; | ||||
case CC_ECN: | case CC_ECN: | ||||
if (nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED) { | if ((nreno != NULL) && | ||||
(nreno->newreno_flags & CC_NEWRENO_HYSTART_ENABLED)) { | |||||
/* Make sure the flags are all off we had a loss */ | /* Make sure the flags are all off we had a loss */ | ||||
nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_ENABLED; | nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_ENABLED; | ||||
nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS; | nreno->newreno_flags &= ~CC_NEWRENO_HYSTART_IN_CSS; | ||||
} | } | ||||
if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) { | if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) { | ||||
CCV(ccv, snd_ssthresh) = cwin; | CCV(ccv, snd_ssthresh) = cwin; | ||||
CCV(ccv, snd_cwnd) = cwin; | CCV(ccv, snd_cwnd) = cwin; | ||||
ENTER_CONGRECOVERY(CCV(ccv, t_flags)); | ENTER_CONGRECOVERY(CCV(ccv, t_flags)); | ||||
▲ Show 20 Lines • Show All 269 Lines • Show Last 20 Lines |
nit double ;; on end