1171440Srrs/*- 2171440Srrs * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 3235828Stuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. 4235828Stuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. 5171440Srrs * 6171440Srrs * Redistribution and use in source and binary forms, with or without 7171440Srrs * modification, are permitted provided that the following conditions are met: 8171440Srrs * 9171440Srrs * a) Redistributions of source code must retain the above copyright notice, 10228653Stuexen * this list of conditions and the following disclaimer. 11171440Srrs * 12171440Srrs * b) Redistributions in binary form must reproduce the above copyright 13171440Srrs * notice, this list of conditions and the following disclaimer in 14228653Stuexen * the documentation and/or other materials provided with the distribution. 15171440Srrs * 16171440Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its 17171440Srrs * contributors may be used to endorse or promote products derived 18171440Srrs * from this software without specific prior written permission. 19171440Srrs * 20171440Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21171440Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22171440Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23171440Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24171440Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25171440Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26171440Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27171440Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28171440Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29171440Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30171440Srrs * THE POSSIBILITY OF SUCH DAMAGE. 31171440Srrs */ 32171440Srrs 33235828Stuexen#include <sys/cdefs.h> 34235828Stuexen__FBSDID("$FreeBSD: stable/11/sys/netinet/sctp_cc_functions.c 360758 2020-05-07 03:01:01Z tuexen $"); 35235828Stuexen 36171440Srrs#include <netinet/sctp_os.h> 37171440Srrs#include <netinet/sctp_var.h> 38171440Srrs#include <netinet/sctp_sysctl.h> 39171440Srrs#include <netinet/sctp_pcb.h> 40171440Srrs#include <netinet/sctp_header.h> 41171440Srrs#include <netinet/sctputil.h> 42171440Srrs#include <netinet/sctp_output.h> 43171440Srrs#include <netinet/sctp_input.h> 44171440Srrs#include <netinet/sctp_indata.h> 45171440Srrs#include <netinet/sctp_uio.h> 46171440Srrs#include <netinet/sctp_timer.h> 47171440Srrs#include <netinet/sctp_auth.h> 48171440Srrs#include <netinet/sctp_asconf.h> 49215817Srrs#include <netinet/sctp_dtrace_declare.h> 50212800Stuexen 51221460Stuexen#define SHIFT_MPTCP_MULTI_N 40 52221460Stuexen#define SHIFT_MPTCP_MULTI_Z 16 53221460Stuexen#define SHIFT_MPTCP_MULTI 8 54221460Stuexen 55217611Stuexenstatic void 56279859Stuexensctp_enforce_cwnd_limit(struct sctp_association *assoc, struct sctp_nets *net) 57279859Stuexen{ 58279859Stuexen if ((assoc->max_cwnd > 0) && 59279859Stuexen (net->cwnd > assoc->max_cwnd) && 60279859Stuexen (net->cwnd > (net->mtu - sizeof(struct sctphdr)))) { 61279859Stuexen net->cwnd = assoc->max_cwnd; 62279859Stuexen if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) { 63279859Stuexen net->cwnd = net->mtu - sizeof(struct sctphdr); 64279859Stuexen } 65279859Stuexen } 66279859Stuexen} 67279859Stuexen 68279859Stuexenstatic void 69171440Srrssctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) 70171440Srrs{ 71212800Stuexen struct sctp_association *assoc; 72212800Stuexen uint32_t cwnd_in_mtu; 73212800Stuexen 74212800Stuexen assoc = &stcb->asoc; 75212800Stuexen cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd); 76216672Stuexen if (cwnd_in_mtu == 0) { 77216672Stuexen /* Using 0 means that the value of RFC 4960 is used. */ 78216672Stuexen net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 79216672Stuexen } else { 80216672Stuexen /* 81216672Stuexen * We take the minimum of the burst limit and the initial 82216672Stuexen * congestion window. 83216672Stuexen */ 84216672Stuexen if ((assoc->max_burst > 0) && (cwnd_in_mtu > assoc->max_burst)) 85216672Stuexen cwnd_in_mtu = assoc->max_burst; 86216672Stuexen net->cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu; 87216672Stuexen } 88221460Stuexen if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) || 89221460Stuexen (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2)) { 90217469Stuexen /* In case of resource pooling initialize appropriately */ 91217469Stuexen net->cwnd /= assoc->numnets; 92217469Stuexen if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) { 93217469Stuexen net->cwnd = net->mtu - sizeof(struct sctphdr); 94217469Stuexen } 95217469Stuexen } 96279859Stuexen sctp_enforce_cwnd_limit(assoc, net); 97212800Stuexen net->ssthresh = assoc->peers_rwnd; 98292384Smarkj SDT_PROBE5(sctp, cwnd, net, init, 99215817Srrs stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, 100215817Srrs 0, net->cwnd); 101212800Stuexen if (SCTP_BASE_SYSCTL(sctp_logging_level) & 102212800Stuexen (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { 103171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); 104171440Srrs } 105171440Srrs} 106171440Srrs 107217611Stuexenstatic void 108171440Srrssctp_cwnd_update_after_fr(struct sctp_tcb *stcb, 109171440Srrs struct sctp_association *asoc) 110171440Srrs{ 111171440Srrs struct sctp_nets *net; 112217469Stuexen uint32_t t_ssthresh, t_cwnd; 113221460Stuexen uint64_t t_ucwnd_sbw; 114171440Srrs 115217469Stuexen /* MT FIXME: Don't compute this over and over again */ 116217469Stuexen t_ssthresh = 0; 117217469Stuexen t_cwnd = 0; 118221460Stuexen t_ucwnd_sbw = 0; 119221460Stuexen if ((asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) || 120221460Stuexen (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2)) { 121217469Stuexen TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 122217469Stuexen t_ssthresh += net->ssthresh; 123217469Stuexen t_cwnd += net->cwnd; 124221460Stuexen if (net->lastsa > 0) { 125310773Stuexen t_ucwnd_sbw += (uint64_t)net->cwnd / (uint64_t)net->lastsa; 126221460Stuexen } 127217469Stuexen } 128221460Stuexen if (t_ucwnd_sbw == 0) { 129221460Stuexen t_ucwnd_sbw = 1; 130221460Stuexen } 131217469Stuexen } 132347154Stuexen 133171440Srrs /*- 134216669Stuexen * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) && 135171440Srrs * (net->fast_retran_loss_recovery == 0))) 136171440Srrs */ 137171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 138211944Stuexen if ((asoc->fast_retran_loss_recovery == 0) || 139216669Stuexen (asoc->sctp_cmt_on_off > 0)) { 140171440Srrs /* out of a RFC2582 Fast recovery window? */ 141171440Srrs if (net->net_ack > 0) { 142171440Srrs /* 143171440Srrs * per section 7.2.3, are there any 144171440Srrs * destinations that had a fast retransmit 145171440Srrs * to them. If so what we need to do is 146171440Srrs * adjust ssthresh and cwnd. 147171440Srrs */ 148171440Srrs struct sctp_tmit_chunk *lchk; 149171440Srrs int old_cwnd = net->cwnd; 150171440Srrs 151221460Stuexen if ((asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) || 152221460Stuexen (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2)) { 153221460Stuexen if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) { 154310773Stuexen net->ssthresh = (uint32_t)(((uint64_t)4 * 155310773Stuexen (uint64_t)net->mtu * 156310773Stuexen (uint64_t)net->ssthresh) / 157310773Stuexen (uint64_t)t_ssthresh); 158221460Stuexen 159221460Stuexen } 160221460Stuexen if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2) { 161221460Stuexen uint32_t srtt; 162221460Stuexen 163221460Stuexen srtt = net->lastsa; 164310773Stuexen /* 165310773Stuexen * lastsa>>3; we don't need 166310773Stuexen * to devide ... 167310773Stuexen */ 168221460Stuexen if (srtt == 0) { 169221460Stuexen srtt = 1; 170221460Stuexen } 171310773Stuexen /* 172310773Stuexen * Short Version => Equal to 173310773Stuexen * Contel Version MBe 174310773Stuexen */ 175310773Stuexen net->ssthresh = (uint32_t)(((uint64_t)4 * 176310773Stuexen (uint64_t)net->mtu * 177310773Stuexen (uint64_t)net->cwnd) / 178310773Stuexen ((uint64_t)srtt * 179221460Stuexen t_ucwnd_sbw)); 180221460Stuexen /* INCREASE FACTOR */ ; 181221460Stuexen } 182217469Stuexen if ((net->cwnd > t_cwnd / 2) && 183217469Stuexen (net->ssthresh < net->cwnd - t_cwnd / 2)) { 184217469Stuexen net->ssthresh = net->cwnd - t_cwnd / 2; 185217469Stuexen } 186217469Stuexen if (net->ssthresh < net->mtu) { 187217469Stuexen net->ssthresh = net->mtu; 188217469Stuexen } 189217469Stuexen } else { 190217469Stuexen net->ssthresh = net->cwnd / 2; 191217469Stuexen if (net->ssthresh < (net->mtu * 2)) { 192217469Stuexen net->ssthresh = 2 * net->mtu; 193217469Stuexen } 194171440Srrs } 195171440Srrs net->cwnd = net->ssthresh; 196279859Stuexen sctp_enforce_cwnd_limit(asoc, net); 197292384Smarkj SDT_PROBE5(sctp, cwnd, net, fr, 198215817Srrs stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, 199215817Srrs old_cwnd, net->cwnd); 200179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 201171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 202171440Srrs SCTP_CWND_LOG_FROM_FR); 203171440Srrs } 204171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 205171440Srrs 206171440Srrs net->partial_bytes_acked = 0; 207171440Srrs /* Turn on fast recovery window */ 208171440Srrs asoc->fast_retran_loss_recovery = 1; 209171440Srrs if (lchk == NULL) { 210171440Srrs /* Mark end of the window */ 211171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 212171440Srrs } else { 213310219Stuexen asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1; 214171440Srrs } 215171440Srrs 216171440Srrs /* 217171440Srrs * CMT fast recovery -- per destination 218171440Srrs * recovery variable. 219171440Srrs */ 220171440Srrs net->fast_retran_loss_recovery = 1; 221171440Srrs 222171440Srrs if (lchk == NULL) { 223171440Srrs /* Mark end of the window */ 224171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 225171440Srrs } else { 226310219Stuexen net->fast_recovery_tsn = lchk->rec.data.tsn - 1; 227171440Srrs } 228171440Srrs 229171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 230283650Stuexen stcb->sctp_ep, stcb, net, 231283650Stuexen SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_1); 232171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 233171440Srrs stcb->sctp_ep, stcb, net); 234171440Srrs } 235171440Srrs } else if (net->net_ack > 0) { 236171440Srrs /* 237171440Srrs * Mark a peg that we WOULD have done a cwnd 238171440Srrs * reduction but RFC2582 prevented this action. 239171440Srrs */ 240171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 241171440Srrs } 242171440Srrs } 243171440Srrs} 244171440Srrs 245219397Srrs/* Defines for instantaneous bw decisions */ 246298942Spfg#define SCTP_INST_LOOSING 1 /* Losing to other flows */ 247219397Srrs#define SCTP_INST_NEUTRAL 2 /* Neutral, no indication */ 248219397Srrs#define SCTP_INST_GAINING 3 /* Gaining, step down possible */ 249219120Srrs 250219397Srrs 251219397Srrsstatic int 252219397Srrscc_bw_same(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, 253219397Srrs uint64_t rtt_offset, uint64_t vtag, uint8_t inst_ind) 254219397Srrs{ 255219397Srrs uint64_t oth, probepoint; 256219397Srrs 257310773Stuexen probepoint = (((uint64_t)net->cwnd) << 32); 258219397Srrs if (net->rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) { 259219397Srrs /* 260219397Srrs * rtt increased we don't update bw.. so we don't update the 261219397Srrs * rtt either. 262219397Srrs */ 263219397Srrs /* Probe point 5 */ 264219397Srrs probepoint |= ((5 << 16) | 1); 265292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 266219397Srrs vtag, 267219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 268219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 269219397Srrs net->flight_size, 270219397Srrs probepoint); 271219397Srrs if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) { 272219397Srrs if (net->cc_mod.rtcc.last_step_state == 5) 273219397Srrs net->cc_mod.rtcc.step_cnt++; 274219397Srrs else 275219397Srrs net->cc_mod.rtcc.step_cnt = 1; 276219397Srrs net->cc_mod.rtcc.last_step_state = 5; 277219397Srrs if ((net->cc_mod.rtcc.step_cnt == net->cc_mod.rtcc.steady_step) || 278219397Srrs ((net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step) && 279219397Srrs ((net->cc_mod.rtcc.step_cnt % net->cc_mod.rtcc.steady_step) == 0))) { 280219397Srrs /* Try a step down */ 281219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 282219397Srrs oth <<= 16; 283219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 284219397Srrs oth <<= 16; 285219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 286292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttstep, 287219397Srrs vtag, 288219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 289219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 290219397Srrs oth, 291219397Srrs probepoint); 292219397Srrs if (net->cwnd > (4 * net->mtu)) { 293219397Srrs net->cwnd -= net->mtu; 294219397Srrs net->cc_mod.rtcc.vol_reduce++; 295219397Srrs } else { 296219397Srrs net->cc_mod.rtcc.step_cnt = 0; 297219397Srrs } 298219397Srrs } 299219397Srrs } 300219397Srrs return (1); 301219397Srrs } 302219397Srrs if (net->rtt < net->cc_mod.rtcc.lbw_rtt - rtt_offset) { 303219397Srrs /* 304219397Srrs * rtt decreased, there could be more room. we update both 305219397Srrs * the bw and the rtt here to lock this in as a good step 306219397Srrs * down. 307219397Srrs */ 308219397Srrs /* Probe point 6 */ 309219397Srrs probepoint |= ((6 << 16) | 0); 310292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 311219397Srrs vtag, 312219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 313219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 314219397Srrs net->flight_size, 315219397Srrs probepoint); 316219397Srrs if (net->cc_mod.rtcc.steady_step) { 317219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 318219397Srrs oth <<= 16; 319219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 320219397Srrs oth <<= 16; 321219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 322292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttstep, 323219397Srrs vtag, 324219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 325219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 326219397Srrs oth, 327219397Srrs probepoint); 328219397Srrs if ((net->cc_mod.rtcc.last_step_state == 5) && 329219397Srrs (net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step)) { 330219397Srrs /* Step down worked */ 331219397Srrs net->cc_mod.rtcc.step_cnt = 0; 332219397Srrs return (1); 333219397Srrs } else { 334219397Srrs net->cc_mod.rtcc.last_step_state = 6; 335219397Srrs net->cc_mod.rtcc.step_cnt = 0; 336219397Srrs } 337219397Srrs } 338219397Srrs net->cc_mod.rtcc.lbw = nbw; 339219397Srrs net->cc_mod.rtcc.lbw_rtt = net->rtt; 340219397Srrs net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd; 341219397Srrs if (inst_ind == SCTP_INST_GAINING) 342219397Srrs return (1); 343219397Srrs else if (inst_ind == SCTP_INST_NEUTRAL) 344219397Srrs return (1); 345219397Srrs else 346219397Srrs return (0); 347219397Srrs } 348219397Srrs /* 349219397Srrs * Ok bw and rtt remained the same .. no update to any 350219397Srrs */ 351219397Srrs /* Probe point 7 */ 352219397Srrs probepoint |= ((7 << 16) | net->cc_mod.rtcc.ret_from_eq); 353292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 354219397Srrs vtag, 355219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 356219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 357219397Srrs net->flight_size, 358219397Srrs probepoint); 359219397Srrs if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) { 360219397Srrs if (net->cc_mod.rtcc.last_step_state == 5) 361219397Srrs net->cc_mod.rtcc.step_cnt++; 362219397Srrs else 363219397Srrs net->cc_mod.rtcc.step_cnt = 1; 364219397Srrs net->cc_mod.rtcc.last_step_state = 5; 365219397Srrs if ((net->cc_mod.rtcc.step_cnt == net->cc_mod.rtcc.steady_step) || 366219397Srrs ((net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step) && 367219397Srrs ((net->cc_mod.rtcc.step_cnt % net->cc_mod.rtcc.steady_step) == 0))) { 368219397Srrs /* Try a step down */ 369219397Srrs if (net->cwnd > (4 * net->mtu)) { 370219397Srrs net->cwnd -= net->mtu; 371219397Srrs net->cc_mod.rtcc.vol_reduce++; 372219397Srrs return (1); 373219397Srrs } else { 374219397Srrs net->cc_mod.rtcc.step_cnt = 0; 375219397Srrs } 376219397Srrs } 377219397Srrs } 378219397Srrs if (inst_ind == SCTP_INST_GAINING) 379219397Srrs return (1); 380219397Srrs else if (inst_ind == SCTP_INST_NEUTRAL) 381219397Srrs return (1); 382219397Srrs else 383219397Srrs return ((int)net->cc_mod.rtcc.ret_from_eq); 384219397Srrs} 385219397Srrs 386219397Srrsstatic int 387219397Srrscc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t rtt_offset, 388219397Srrs uint64_t vtag, uint8_t inst_ind) 389219397Srrs{ 390219397Srrs uint64_t oth, probepoint; 391219397Srrs 392219397Srrs /* Bandwidth decreased. */ 393310773Stuexen probepoint = (((uint64_t)net->cwnd) << 32); 394219397Srrs if (net->rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) { 395219397Srrs /* rtt increased */ 396219397Srrs /* Did we add more */ 397219397Srrs if ((net->cwnd > net->cc_mod.rtcc.cwnd_at_bw_set) && 398219397Srrs (inst_ind != SCTP_INST_LOOSING)) { 399219397Srrs /* We caused it maybe.. back off? */ 400219397Srrs /* PROBE POINT 1 */ 401219397Srrs probepoint |= ((1 << 16) | 1); 402292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 403219397Srrs vtag, 404219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 405219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 406219397Srrs net->flight_size, 407219397Srrs probepoint); 408219397Srrs if (net->cc_mod.rtcc.ret_from_eq) { 409310773Stuexen /* 410310773Stuexen * Switch over to CA if we are less 411310773Stuexen * aggressive 412310773Stuexen */ 413219397Srrs net->ssthresh = net->cwnd - 1; 414219397Srrs net->partial_bytes_acked = 0; 415219397Srrs } 416219397Srrs return (1); 417219397Srrs } 418219397Srrs /* Probe point 2 */ 419219397Srrs probepoint |= ((2 << 16) | 0); 420292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 421219397Srrs vtag, 422219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 423219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 424219397Srrs net->flight_size, 425219397Srrs probepoint); 426219397Srrs /* Someone else - fight for more? */ 427219397Srrs if (net->cc_mod.rtcc.steady_step) { 428219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 429219397Srrs oth <<= 16; 430219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 431219397Srrs oth <<= 16; 432219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 433292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttstep, 434219397Srrs vtag, 435219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 436219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 437219397Srrs oth, 438219397Srrs probepoint); 439219397Srrs /* 440219397Srrs * Did we voluntarily give up some? if so take one 441219397Srrs * back please 442219397Srrs */ 443219397Srrs if ((net->cc_mod.rtcc.vol_reduce) && 444219397Srrs (inst_ind != SCTP_INST_GAINING)) { 445219397Srrs net->cwnd += net->mtu; 446279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 447219397Srrs net->cc_mod.rtcc.vol_reduce--; 448219397Srrs } 449219397Srrs net->cc_mod.rtcc.last_step_state = 2; 450219397Srrs net->cc_mod.rtcc.step_cnt = 0; 451219397Srrs } 452219397Srrs goto out_decision; 453219397Srrs } else if (net->rtt < net->cc_mod.rtcc.lbw_rtt - rtt_offset) { 454219397Srrs /* bw & rtt decreased */ 455219397Srrs /* Probe point 3 */ 456219397Srrs probepoint |= ((3 << 16) | 0); 457292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 458219397Srrs vtag, 459219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 460219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 461219397Srrs net->flight_size, 462219397Srrs probepoint); 463219397Srrs if (net->cc_mod.rtcc.steady_step) { 464219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 465219397Srrs oth <<= 16; 466219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 467219397Srrs oth <<= 16; 468219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 469292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttstep, 470219397Srrs vtag, 471219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 472219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 473219397Srrs oth, 474219397Srrs probepoint); 475219397Srrs if ((net->cc_mod.rtcc.vol_reduce) && 476219397Srrs (inst_ind != SCTP_INST_GAINING)) { 477219397Srrs net->cwnd += net->mtu; 478279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 479219397Srrs net->cc_mod.rtcc.vol_reduce--; 480219397Srrs } 481219397Srrs net->cc_mod.rtcc.last_step_state = 3; 482219397Srrs net->cc_mod.rtcc.step_cnt = 0; 483219397Srrs } 484219397Srrs goto out_decision; 485219397Srrs } 486219397Srrs /* The bw decreased but rtt stayed the same */ 487219397Srrs /* Probe point 4 */ 488219397Srrs probepoint |= ((4 << 16) | 0); 489292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 490219397Srrs vtag, 491219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 492219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 493219397Srrs net->flight_size, 494219397Srrs probepoint); 495219397Srrs if (net->cc_mod.rtcc.steady_step) { 496219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 497219397Srrs oth <<= 16; 498219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 499219397Srrs oth <<= 16; 500219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 501292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttstep, 502219397Srrs vtag, 503219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 504219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 505219397Srrs oth, 506219397Srrs probepoint); 507219397Srrs if ((net->cc_mod.rtcc.vol_reduce) && 508219397Srrs (inst_ind != SCTP_INST_GAINING)) { 509219397Srrs net->cwnd += net->mtu; 510279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 511219397Srrs net->cc_mod.rtcc.vol_reduce--; 512219397Srrs } 513219397Srrs net->cc_mod.rtcc.last_step_state = 4; 514219397Srrs net->cc_mod.rtcc.step_cnt = 0; 515219397Srrs } 516219397Srrsout_decision: 517219397Srrs net->cc_mod.rtcc.lbw = nbw; 518219397Srrs net->cc_mod.rtcc.lbw_rtt = net->rtt; 519219397Srrs net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd; 520219397Srrs if (inst_ind == SCTP_INST_GAINING) { 521219397Srrs return (1); 522219397Srrs } else { 523219397Srrs return (0); 524219397Srrs } 525219397Srrs} 526219397Srrs 527219397Srrsstatic int 528228653Stuexencc_bw_increase(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t vtag) 529219397Srrs{ 530219397Srrs uint64_t oth, probepoint; 531219397Srrs 532219397Srrs /* 533219397Srrs * BW increased, so update and return 0, since all actions in our 534219397Srrs * table say to do the normal CC update. Note that we pay no 535219397Srrs * attention to the inst_ind since our overall sum is increasing. 536219397Srrs */ 537219397Srrs /* PROBE POINT 0 */ 538310773Stuexen probepoint = (((uint64_t)net->cwnd) << 32); 539292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 540219397Srrs vtag, 541219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 542219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 543219397Srrs net->flight_size, 544219397Srrs probepoint); 545219397Srrs if (net->cc_mod.rtcc.steady_step) { 546219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 547219397Srrs oth <<= 16; 548219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 549219397Srrs oth <<= 16; 550219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 551292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttstep, 552219397Srrs vtag, 553219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 554219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 555219397Srrs oth, 556219397Srrs probepoint); 557219397Srrs net->cc_mod.rtcc.last_step_state = 0; 558219397Srrs net->cc_mod.rtcc.step_cnt = 0; 559219397Srrs net->cc_mod.rtcc.vol_reduce = 0; 560219397Srrs } 561219397Srrs net->cc_mod.rtcc.lbw = nbw; 562219397Srrs net->cc_mod.rtcc.lbw_rtt = net->rtt; 563219397Srrs net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd; 564219397Srrs return (0); 565219397Srrs} 566219397Srrs 567298942Spfg/* RTCC Algorithm to limit growth of cwnd, return 568219120Srrs * true if you want to NOT allow cwnd growth 569219120Srrs */ 570219120Srrsstatic int 571219120Srrscc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw) 572219120Srrs{ 573228907Stuexen uint64_t bw_offset, rtt_offset; 574228907Stuexen uint64_t probepoint, rtt, vtag; 575219397Srrs uint64_t bytes_for_this_rtt, inst_bw; 576219397Srrs uint64_t div, inst_off; 577219397Srrs int bw_shift; 578219397Srrs uint8_t inst_ind; 579219397Srrs int ret; 580219120Srrs 581219120Srrs /*- 582219120Srrs * Here we need to see if we want 583219120Srrs * to limit cwnd growth due to increase 584219120Srrs * in overall rtt but no increase in bw. 585219120Srrs * We use the following table to figure 586219120Srrs * out what we should do. When we return 587219120Srrs * 0, cc update goes on as planned. If we 588219120Srrs * return 1, then no cc update happens and cwnd 589219120Srrs * stays where it is at. 590219120Srrs * ---------------------------------- 591219120Srrs * BW | RTT | Action 592219120Srrs * ********************************* 593219120Srrs * INC | INC | return 0 594219120Srrs * ---------------------------------- 595219120Srrs * INC | SAME | return 0 596219120Srrs * ---------------------------------- 597219120Srrs * INC | DECR | return 0 598219120Srrs * ---------------------------------- 599219120Srrs * SAME | INC | return 1 600219120Srrs * ---------------------------------- 601219120Srrs * SAME | SAME | return 1 602219120Srrs * ---------------------------------- 603219120Srrs * SAME | DECR | return 0 604219120Srrs * ---------------------------------- 605219120Srrs * DECR | INC | return 0 or 1 based on if we caused. 606219120Srrs * ---------------------------------- 607219120Srrs * DECR | SAME | return 0 608219120Srrs * ---------------------------------- 609219120Srrs * DECR | DECR | return 0 610219120Srrs * ---------------------------------- 611219120Srrs * 612219120Srrs * We are a bit fuzz on what an increase or 613219120Srrs * decrease is. For BW it is the same if 614219120Srrs * it did not change within 1/64th. For 615219120Srrs * RTT it stayed the same if it did not 616219120Srrs * change within 1/32nd 617219120Srrs */ 618219397Srrs bw_shift = SCTP_BASE_SYSCTL(sctp_rttvar_bw); 619219120Srrs rtt = stcb->asoc.my_vtag; 620310773Stuexen vtag = (rtt << 32) | (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | (stcb->rport); 621310773Stuexen probepoint = (((uint64_t)net->cwnd) << 32); 622219120Srrs rtt = net->rtt; 623219397Srrs if (net->cc_mod.rtcc.rtt_set_this_sack) { 624219397Srrs net->cc_mod.rtcc.rtt_set_this_sack = 0; 625219397Srrs bytes_for_this_rtt = net->cc_mod.rtcc.bw_bytes - net->cc_mod.rtcc.bw_bytes_at_last_rttc; 626219397Srrs net->cc_mod.rtcc.bw_bytes_at_last_rttc = net->cc_mod.rtcc.bw_bytes; 627219397Srrs if (net->rtt) { 628219397Srrs div = net->rtt / 1000; 629219397Srrs if (div) { 630219397Srrs inst_bw = bytes_for_this_rtt / div; 631219397Srrs inst_off = inst_bw >> bw_shift; 632219397Srrs if (inst_bw > nbw) 633219397Srrs inst_ind = SCTP_INST_GAINING; 634219397Srrs else if ((inst_bw + inst_off) < nbw) 635219397Srrs inst_ind = SCTP_INST_LOOSING; 636219397Srrs else 637219397Srrs inst_ind = SCTP_INST_NEUTRAL; 638219397Srrs probepoint |= ((0xb << 16) | inst_ind); 639219397Srrs } else { 640228907Stuexen inst_ind = net->cc_mod.rtcc.last_inst_ind; 641310773Stuexen inst_bw = bytes_for_this_rtt / (uint64_t)(net->rtt); 642219397Srrs /* Can't determine do not change */ 643219397Srrs probepoint |= ((0xc << 16) | inst_ind); 644219397Srrs } 645219397Srrs } else { 646228907Stuexen inst_ind = net->cc_mod.rtcc.last_inst_ind; 647219397Srrs inst_bw = bytes_for_this_rtt; 648219397Srrs /* Can't determine do not change */ 649219397Srrs probepoint |= ((0xd << 16) | inst_ind); 650219397Srrs } 651292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 652219120Srrs vtag, 653219397Srrs ((nbw << 32) | inst_bw), 654219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | rtt), 655219397Srrs net->flight_size, 656219120Srrs probepoint); 657219397Srrs } else { 658219397Srrs /* No rtt measurement, use last one */ 659219397Srrs inst_ind = net->cc_mod.rtcc.last_inst_ind; 660219120Srrs } 661219397Srrs bw_offset = net->cc_mod.rtcc.lbw >> bw_shift; 662219397Srrs if (nbw > net->cc_mod.rtcc.lbw + bw_offset) { 663228653Stuexen ret = cc_bw_increase(stcb, net, nbw, vtag); 664219397Srrs goto out; 665219397Srrs } 666219120Srrs rtt_offset = net->cc_mod.rtcc.lbw_rtt >> SCTP_BASE_SYSCTL(sctp_rttvar_rtt); 667219120Srrs if (nbw < net->cc_mod.rtcc.lbw - bw_offset) { 668219397Srrs ret = cc_bw_decrease(stcb, net, nbw, rtt_offset, vtag, inst_ind); 669219397Srrs goto out; 670219120Srrs } 671219120Srrs /* 672219120Srrs * If we reach here then we are in a situation where the bw stayed 673219120Srrs * the same. 674219120Srrs */ 675219397Srrs ret = cc_bw_same(stcb, net, nbw, rtt_offset, vtag, inst_ind); 676219397Srrsout: 677219397Srrs net->cc_mod.rtcc.last_inst_ind = inst_ind; 678219397Srrs return (ret); 679219120Srrs} 680219120Srrs 681217611Stuexenstatic void 682219120Srrssctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, 683171440Srrs struct sctp_association *asoc, 684228653Stuexen int accum_moved, int reneged_all SCTP_UNUSED, int will_exit, int use_rtcc) 685171440Srrs{ 686171440Srrs struct sctp_nets *net; 687215817Srrs int old_cwnd; 688217469Stuexen uint32_t t_ssthresh, t_cwnd, incr; 689221460Stuexen uint64_t t_ucwnd_sbw; 690221460Stuexen uint64_t t_path_mptcp; 691221460Stuexen uint64_t mptcp_like_alpha; 692221460Stuexen uint32_t srtt; 693221460Stuexen uint64_t max_path; 694171440Srrs 695217469Stuexen /* MT FIXME: Don't compute this over and over again */ 696217469Stuexen t_ssthresh = 0; 697217469Stuexen t_cwnd = 0; 698221460Stuexen t_ucwnd_sbw = 0; 699221460Stuexen t_path_mptcp = 0; 700221460Stuexen mptcp_like_alpha = 1; 701221460Stuexen if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) || 702221460Stuexen (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2) || 703221460Stuexen (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_MPTCP)) { 704221460Stuexen max_path = 0; 705217469Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 706217469Stuexen t_ssthresh += net->ssthresh; 707217469Stuexen t_cwnd += net->cwnd; 708221460Stuexen /* lastsa>>3; we don't need to devide ... */ 709221460Stuexen srtt = net->lastsa; 710221460Stuexen if (srtt > 0) { 711221460Stuexen uint64_t tmp; 712221460Stuexen 713310773Stuexen t_ucwnd_sbw += (uint64_t)net->cwnd / (uint64_t)srtt; 714310773Stuexen t_path_mptcp += (((uint64_t)net->cwnd) << SHIFT_MPTCP_MULTI_Z) / 715310773Stuexen (((uint64_t)net->mtu) * (uint64_t)srtt); 716310773Stuexen tmp = (((uint64_t)net->cwnd) << SHIFT_MPTCP_MULTI_N) / 717310773Stuexen ((uint64_t)net->mtu * (uint64_t)(srtt * srtt)); 718221460Stuexen if (tmp > max_path) { 719221460Stuexen max_path = tmp; 720221460Stuexen } 721221460Stuexen } 722217469Stuexen } 723221460Stuexen if (t_path_mptcp > 0) { 724221460Stuexen mptcp_like_alpha = max_path / (t_path_mptcp * t_path_mptcp); 725221460Stuexen } else { 726221460Stuexen mptcp_like_alpha = 1; 727221460Stuexen } 728217469Stuexen } 729228907Stuexen if (t_ssthresh == 0) { 730228907Stuexen t_ssthresh = 1; 731228907Stuexen } 732228907Stuexen if (t_ucwnd_sbw == 0) { 733228907Stuexen t_ucwnd_sbw = 1; 734228907Stuexen } 735171440Srrs /******************************/ 736171440Srrs /* update cwnd and Early FR */ 737171440Srrs /******************************/ 738171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 739171440Srrs 740171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 741171440Srrs /* 742171440Srrs * CMT fast recovery code. Need to debug. 743171440Srrs */ 744171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 745217469Stuexen if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) || 746217469Stuexen SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) { 747171440Srrs net->will_exit_fast_recovery = 1; 748171440Srrs } 749171440Srrs } 750171440Srrs#endif 751171440Srrs /* if nothing was acked on this destination skip it */ 752171440Srrs if (net->net_ack == 0) { 753179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 754171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 755171440Srrs } 756171440Srrs continue; 757171440Srrs } 758171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 759171440Srrs /* 760171440Srrs * CMT fast recovery code 761171440Srrs */ 762171440Srrs /* 763216669Stuexen * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery 764216669Stuexen * && net->will_exit_fast_recovery == 0) { @@@ Do something 765216669Stuexen * } else if (sctp_cmt_on_off == 0 && 766171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 767171440Srrs */ 768171440Srrs#endif 769171440Srrs 770211944Stuexen if (asoc->fast_retran_loss_recovery && 771211944Stuexen (will_exit == 0) && 772211944Stuexen (asoc->sctp_cmt_on_off == 0)) { 773171440Srrs /* 774171440Srrs * If we are in loss recovery we skip any cwnd 775171440Srrs * update 776171440Srrs */ 777224641Stuexen return; 778171440Srrs } 779171440Srrs /* 780219120Srrs * Did any measurements go on for this network? 781219120Srrs */ 782219120Srrs if (use_rtcc && (net->cc_mod.rtcc.tls_needs_set > 0)) { 783219120Srrs uint64_t nbw; 784219120Srrs 785219120Srrs /* 786219120Srrs * At this point our bw_bytes has been updated by 787219120Srrs * incoming sack information. 788310218Stuexen * 789219120Srrs * But our bw may not yet be set. 790310218Stuexen * 791219120Srrs */ 792219120Srrs if ((net->cc_mod.rtcc.new_tot_time / 1000) > 0) { 793219120Srrs nbw = net->cc_mod.rtcc.bw_bytes / (net->cc_mod.rtcc.new_tot_time / 1000); 794219120Srrs } else { 795219120Srrs nbw = net->cc_mod.rtcc.bw_bytes; 796219120Srrs } 797219120Srrs if (net->cc_mod.rtcc.lbw) { 798219120Srrs if (cc_bw_limit(stcb, net, nbw)) { 799219120Srrs /* Hold here, no update */ 800224641Stuexen continue; 801219120Srrs } 802219120Srrs } else { 803219120Srrs uint64_t vtag, probepoint; 804219120Srrs 805310773Stuexen probepoint = (((uint64_t)net->cwnd) << 32); 806219120Srrs probepoint |= ((0xa << 16) | 0); 807219120Srrs vtag = (net->rtt << 32) | 808310773Stuexen (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | 809219120Srrs (stcb->rport); 810219120Srrs 811292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 812219120Srrs vtag, 813219120Srrs nbw, 814219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 815219397Srrs net->flight_size, 816219120Srrs probepoint); 817219120Srrs net->cc_mod.rtcc.lbw = nbw; 818219120Srrs net->cc_mod.rtcc.lbw_rtt = net->rtt; 819219397Srrs if (net->cc_mod.rtcc.rtt_set_this_sack) { 820219397Srrs net->cc_mod.rtcc.rtt_set_this_sack = 0; 821219397Srrs net->cc_mod.rtcc.bw_bytes_at_last_rttc = net->cc_mod.rtcc.bw_bytes; 822219397Srrs } 823219120Srrs } 824219120Srrs } 825219120Srrs /* 826171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 827171440Srrs * moved. 828171440Srrs */ 829211944Stuexen if (accum_moved || 830216669Stuexen ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) { 831171440Srrs /* If the cumulative ack moved we can proceed */ 832171440Srrs if (net->cwnd <= net->ssthresh) { 833171440Srrs /* We are in slow start */ 834179157Srrs if (net->flight_size + net->net_ack >= net->cwnd) { 835221460Stuexen uint32_t limit; 836221460Stuexen 837217469Stuexen old_cwnd = net->cwnd; 838221460Stuexen switch (asoc->sctp_cmt_on_off) { 839221460Stuexen case SCTP_CMT_RPV1: 840310773Stuexen limit = (uint32_t)(((uint64_t)net->mtu * 841310773Stuexen (uint64_t)SCTP_BASE_SYSCTL(sctp_L2_abc_variable) * 842310773Stuexen (uint64_t)net->ssthresh) / 843310773Stuexen (uint64_t)t_ssthresh); 844310773Stuexen incr = (uint32_t)(((uint64_t)net->net_ack * 845310773Stuexen (uint64_t)net->ssthresh) / 846310773Stuexen (uint64_t)t_ssthresh); 847217469Stuexen if (incr > limit) { 848217469Stuexen incr = limit; 849171440Srrs } 850217469Stuexen if (incr == 0) { 851217469Stuexen incr = 1; 852217469Stuexen } 853221460Stuexen break; 854221460Stuexen case SCTP_CMT_RPV2: 855310773Stuexen /* 856310773Stuexen * lastsa>>3; we don't need 857310773Stuexen * to divide ... 858310773Stuexen */ 859221460Stuexen srtt = net->lastsa; 860221460Stuexen if (srtt == 0) { 861221460Stuexen srtt = 1; 862221460Stuexen } 863310773Stuexen limit = (uint32_t)(((uint64_t)net->mtu * 864310773Stuexen (uint64_t)SCTP_BASE_SYSCTL(sctp_L2_abc_variable) * 865310773Stuexen (uint64_t)net->cwnd) / 866310773Stuexen ((uint64_t)srtt * t_ucwnd_sbw)); 867221460Stuexen /* INCREASE FACTOR */ 868310773Stuexen incr = (uint32_t)(((uint64_t)net->net_ack * 869310773Stuexen (uint64_t)net->cwnd) / 870310773Stuexen ((uint64_t)srtt * t_ucwnd_sbw)); 871221460Stuexen /* INCREASE FACTOR */ 872221460Stuexen if (incr > limit) { 873221460Stuexen incr = limit; 874221460Stuexen } 875221460Stuexen if (incr == 0) { 876221460Stuexen incr = 1; 877221460Stuexen } 878221460Stuexen break; 879221460Stuexen case SCTP_CMT_MPTCP: 880310773Stuexen limit = (uint32_t)(((uint64_t)net->mtu * 881221460Stuexen mptcp_like_alpha * 882310773Stuexen (uint64_t)SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) >> 883221460Stuexen SHIFT_MPTCP_MULTI); 884310773Stuexen incr = (uint32_t)(((uint64_t)net->net_ack * 885221460Stuexen mptcp_like_alpha) >> 886221460Stuexen SHIFT_MPTCP_MULTI); 887221460Stuexen if (incr > limit) { 888221460Stuexen incr = limit; 889221460Stuexen } 890221460Stuexen if (incr > net->net_ack) { 891221460Stuexen incr = net->net_ack; 892221460Stuexen } 893221460Stuexen if (incr > net->mtu) { 894221460Stuexen incr = net->mtu; 895221460Stuexen } 896221460Stuexen break; 897221460Stuexen default: 898217469Stuexen incr = net->net_ack; 899217469Stuexen if (incr > net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) { 900217469Stuexen incr = net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable); 901171440Srrs } 902221460Stuexen break; 903171440Srrs } 904217469Stuexen net->cwnd += incr; 905279859Stuexen sctp_enforce_cwnd_limit(asoc, net); 906217469Stuexen if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 907217469Stuexen sctp_log_cwnd(stcb, net, incr, 908217469Stuexen SCTP_CWND_LOG_FROM_SS); 909217469Stuexen } 910292384Smarkj SDT_PROBE5(sctp, cwnd, net, ack, 911217469Stuexen stcb->asoc.my_vtag, 912217469Stuexen ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 913217469Stuexen net, 914217469Stuexen old_cwnd, net->cwnd); 915171440Srrs } else { 916179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 917171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 918171440Srrs SCTP_CWND_LOG_NOADV_SS); 919171440Srrs } 920171440Srrs } 921171440Srrs } else { 922171440Srrs /* We are in congestion avoidance */ 923179141Srrs /* 924179141Srrs * Add to pba 925179141Srrs */ 926179157Srrs net->partial_bytes_acked += net->net_ack; 927171440Srrs 928179141Srrs if ((net->flight_size + net->net_ack >= net->cwnd) && 929179141Srrs (net->partial_bytes_acked >= net->cwnd)) { 930179141Srrs net->partial_bytes_acked -= net->cwnd; 931215817Srrs old_cwnd = net->cwnd; 932221460Stuexen switch (asoc->sctp_cmt_on_off) { 933221460Stuexen case SCTP_CMT_RPV1: 934310773Stuexen incr = (uint32_t)(((uint64_t)net->mtu * 935310773Stuexen (uint64_t)net->ssthresh) / 936310773Stuexen (uint64_t)t_ssthresh); 937217469Stuexen if (incr == 0) { 938217469Stuexen incr = 1; 939217469Stuexen } 940221460Stuexen break; 941221460Stuexen case SCTP_CMT_RPV2: 942310773Stuexen /* 943310773Stuexen * lastsa>>3; we don't need 944310773Stuexen * to divide ... 945310773Stuexen */ 946221460Stuexen srtt = net->lastsa; 947221460Stuexen if (srtt == 0) { 948221460Stuexen srtt = 1; 949221460Stuexen } 950310773Stuexen incr = (uint32_t)((uint64_t)net->mtu * 951310773Stuexen (uint64_t)net->cwnd / 952310773Stuexen ((uint64_t)srtt * 953221460Stuexen t_ucwnd_sbw)); 954221460Stuexen /* INCREASE FACTOR */ 955221460Stuexen if (incr == 0) { 956221460Stuexen incr = 1; 957221460Stuexen } 958221460Stuexen break; 959221460Stuexen case SCTP_CMT_MPTCP: 960310773Stuexen incr = (uint32_t)((mptcp_like_alpha * 961310773Stuexen (uint64_t)net->cwnd) >> 962221460Stuexen SHIFT_MPTCP_MULTI); 963221460Stuexen if (incr > net->mtu) { 964221460Stuexen incr = net->mtu; 965221460Stuexen } 966221460Stuexen break; 967221460Stuexen default: 968217469Stuexen incr = net->mtu; 969221460Stuexen break; 970217469Stuexen } 971217469Stuexen net->cwnd += incr; 972279859Stuexen sctp_enforce_cwnd_limit(asoc, net); 973292384Smarkj SDT_PROBE5(sctp, cwnd, net, ack, 974215817Srrs stcb->asoc.my_vtag, 975215817Srrs ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 976215817Srrs net, 977215817Srrs old_cwnd, net->cwnd); 978179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 979179141Srrs sctp_log_cwnd(stcb, net, net->mtu, 980179141Srrs SCTP_CWND_LOG_FROM_CA); 981171440Srrs } 982171440Srrs } else { 983179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 984171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 985171440Srrs SCTP_CWND_LOG_NOADV_CA); 986171440Srrs } 987171440Srrs } 988171440Srrs } 989171440Srrs } else { 990179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 991171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 992171440Srrs SCTP_CWND_LOG_NO_CUMACK); 993171440Srrs } 994171440Srrs } 995171440Srrs } 996171440Srrs} 997171440Srrs 998217611Stuexenstatic void 999224641Stuexensctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb, struct sctp_nets *net) 1000224641Stuexen{ 1001224641Stuexen int old_cwnd; 1002224641Stuexen 1003224641Stuexen old_cwnd = net->cwnd; 1004224641Stuexen net->cwnd = net->mtu; 1005292384Smarkj SDT_PROBE5(sctp, cwnd, net, ack, 1006224641Stuexen stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, 1007224641Stuexen old_cwnd, net->cwnd); 1008224641Stuexen SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", 1009240148Stuexen (void *)net, net->cwnd); 1010224641Stuexen} 1011224641Stuexen 1012224641Stuexen 1013224641Stuexenstatic void 1014179157Srrssctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net) 1015171440Srrs{ 1016171440Srrs int old_cwnd = net->cwnd; 1017217469Stuexen uint32_t t_ssthresh, t_cwnd; 1018221460Stuexen uint64_t t_ucwnd_sbw; 1019171440Srrs 1020217469Stuexen /* MT FIXME: Don't compute this over and over again */ 1021217469Stuexen t_ssthresh = 0; 1022217469Stuexen t_cwnd = 0; 1023221460Stuexen if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) || 1024221460Stuexen (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2)) { 1025217469Stuexen struct sctp_nets *lnet; 1026221460Stuexen uint32_t srtt; 1027217469Stuexen 1028221460Stuexen t_ucwnd_sbw = 0; 1029217469Stuexen TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 1030217469Stuexen t_ssthresh += lnet->ssthresh; 1031217469Stuexen t_cwnd += lnet->cwnd; 1032221460Stuexen srtt = lnet->lastsa; 1033221460Stuexen /* lastsa>>3; we don't need to divide ... */ 1034221460Stuexen if (srtt > 0) { 1035310773Stuexen t_ucwnd_sbw += (uint64_t)lnet->cwnd / (uint64_t)srtt; 1036221460Stuexen } 1037217469Stuexen } 1038228907Stuexen if (t_ssthresh < 1) { 1039228907Stuexen t_ssthresh = 1; 1040228907Stuexen } 1041221460Stuexen if (t_ucwnd_sbw < 1) { 1042221460Stuexen t_ucwnd_sbw = 1; 1043221460Stuexen } 1044221460Stuexen if (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) { 1045310773Stuexen net->ssthresh = (uint32_t)(((uint64_t)4 * 1046310773Stuexen (uint64_t)net->mtu * 1047310773Stuexen (uint64_t)net->ssthresh) / 1048310773Stuexen (uint64_t)t_ssthresh); 1049221460Stuexen } else { 1050221460Stuexen uint64_t cc_delta; 1051221460Stuexen 1052221460Stuexen srtt = net->lastsa; 1053221460Stuexen /* lastsa>>3; we don't need to divide ... */ 1054221460Stuexen if (srtt == 0) { 1055221460Stuexen srtt = 1; 1056221460Stuexen } 1057310773Stuexen cc_delta = t_ucwnd_sbw * (uint64_t)srtt / 2; 1058221460Stuexen if (cc_delta < t_cwnd) { 1059310773Stuexen net->ssthresh = (uint32_t)((uint64_t)t_cwnd - cc_delta); 1060221460Stuexen } else { 1061221460Stuexen net->ssthresh = net->mtu; 1062221460Stuexen } 1063221460Stuexen } 1064217469Stuexen if ((net->cwnd > t_cwnd / 2) && 1065217469Stuexen (net->ssthresh < net->cwnd - t_cwnd / 2)) { 1066217469Stuexen net->ssthresh = net->cwnd - t_cwnd / 2; 1067217469Stuexen } 1068217469Stuexen if (net->ssthresh < net->mtu) { 1069217469Stuexen net->ssthresh = net->mtu; 1070217469Stuexen } 1071217469Stuexen } else { 1072217469Stuexen net->ssthresh = max(net->cwnd / 2, 4 * net->mtu); 1073217469Stuexen } 1074171440Srrs net->cwnd = net->mtu; 1075179157Srrs net->partial_bytes_acked = 0; 1076292384Smarkj SDT_PROBE5(sctp, cwnd, net, to, 1077215817Srrs stcb->asoc.my_vtag, 1078215817Srrs ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 1079215817Srrs net, 1080215817Srrs old_cwnd, net->cwnd); 1081179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1082171440Srrs sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 1083171440Srrs } 1084171440Srrs} 1085171440Srrs 1086217611Stuexenstatic void 1087219120Srrssctp_cwnd_update_after_ecn_echo_common(struct sctp_tcb *stcb, struct sctp_nets *net, 1088219120Srrs int in_window, int num_pkt_lost, int use_rtcc) 1089179157Srrs{ 1090179157Srrs int old_cwnd = net->cwnd; 1091179157Srrs 1092219120Srrs if ((use_rtcc) && (net->lan_type == SCTP_LAN_LOCAL) && (net->cc_mod.rtcc.use_dccc_ecn)) { 1093219120Srrs /* Data center Congestion Control */ 1094219120Srrs if (in_window == 0) { 1095219120Srrs /* 1096219120Srrs * Go to CA with the cwnd at the point we sent the 1097219120Srrs * TSN that was marked with a CE. 1098219120Srrs */ 1099219120Srrs if (net->ecn_prev_cwnd < net->cwnd) { 1100219120Srrs /* Restore to prev cwnd */ 1101219120Srrs net->cwnd = net->ecn_prev_cwnd - (net->mtu * num_pkt_lost); 1102219120Srrs } else { 1103219120Srrs /* Just cut in 1/2 */ 1104219120Srrs net->cwnd /= 2; 1105219120Srrs } 1106219120Srrs /* Drop to CA */ 1107219120Srrs net->ssthresh = net->cwnd - (num_pkt_lost * net->mtu); 1108219120Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1109219120Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 1110219120Srrs } 1111219120Srrs } else { 1112310773Stuexen /* 1113310773Stuexen * Further tuning down required over the drastic 1114310773Stuexen * original cut 1115310773Stuexen */ 1116219120Srrs net->ssthresh -= (net->mtu * num_pkt_lost); 1117219120Srrs net->cwnd -= (net->mtu * num_pkt_lost); 1118219120Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1119219120Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 1120219120Srrs } 1121347154Stuexen 1122219120Srrs } 1123218129Srrs SCTP_STAT_INCR(sctps_ecnereducedcwnd); 1124219120Srrs } else { 1125219120Srrs if (in_window == 0) { 1126219120Srrs SCTP_STAT_INCR(sctps_ecnereducedcwnd); 1127219120Srrs net->ssthresh = net->cwnd / 2; 1128219120Srrs if (net->ssthresh < net->mtu) { 1129219120Srrs net->ssthresh = net->mtu; 1130310773Stuexen /* 1131310773Stuexen * here back off the timer as well, to slow 1132310773Stuexen * us down 1133310773Stuexen */ 1134219120Srrs net->RTO <<= 1; 1135219120Srrs } 1136219120Srrs net->cwnd = net->ssthresh; 1137292384Smarkj SDT_PROBE5(sctp, cwnd, net, ecn, 1138219120Srrs stcb->asoc.my_vtag, 1139219120Srrs ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 1140219120Srrs net, 1141219120Srrs old_cwnd, net->cwnd); 1142219120Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1143219120Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 1144219120Srrs } 1145218129Srrs } 1146179157Srrs } 1147219120Srrs 1148179157Srrs} 1149179157Srrs 1150217611Stuexenstatic void 1151179157Srrssctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb, 1152179157Srrs struct sctp_nets *net, struct sctp_pktdrop_chunk *cp, 1153310773Stuexen uint32_t *bottle_bw, uint32_t *on_queue) 1154179157Srrs{ 1155179157Srrs uint32_t bw_avail; 1156218232Srrs unsigned int incr; 1157179157Srrs int old_cwnd = net->cwnd; 1158179157Srrs 1159179157Srrs /* get bottle neck bw */ 1160179157Srrs *bottle_bw = ntohl(cp->bottle_bw); 1161179157Srrs /* and whats on queue */ 1162179157Srrs *on_queue = ntohl(cp->current_onq); 1163179157Srrs /* 1164179157Srrs * adjust the on-queue if our flight is more it could be that the 1165179157Srrs * router has not yet gotten data "in-flight" to it 1166179157Srrs */ 1167271672Stuexen if (*on_queue < net->flight_size) { 1168179157Srrs *on_queue = net->flight_size; 1169271672Stuexen } 1170271672Stuexen /* rtt is measured in micro seconds, bottle_bw in bytes per second */ 1171310773Stuexen bw_avail = (uint32_t)(((uint64_t)(*bottle_bw) * net->rtt) / (uint64_t)1000000); 1172179157Srrs if (bw_avail > *bottle_bw) { 1173179157Srrs /* 1174179157Srrs * Cap the growth to no more than the bottle neck. This can 1175179157Srrs * happen as RTT slides up due to queues. It also means if 1176179157Srrs * you have more than a 1 second RTT with a empty queue you 1177179157Srrs * will be limited to the bottle_bw per second no matter if 1178179157Srrs * other points have 1/2 the RTT and you could get more 1179179157Srrs * out... 1180179157Srrs */ 1181179157Srrs bw_avail = *bottle_bw; 1182179157Srrs } 1183179157Srrs if (*on_queue > bw_avail) { 1184179157Srrs /* 1185179157Srrs * No room for anything else don't allow anything else to be 1186179157Srrs * "added to the fire". 1187179157Srrs */ 1188179157Srrs int seg_inflight, seg_onqueue, my_portion; 1189179157Srrs 1190179157Srrs net->partial_bytes_acked = 0; 1191179157Srrs /* how much are we over queue size? */ 1192179157Srrs incr = *on_queue - bw_avail; 1193179157Srrs if (stcb->asoc.seen_a_sack_this_pkt) { 1194179157Srrs /* 1195179157Srrs * undo any cwnd adjustment that the sack might have 1196179157Srrs * made 1197179157Srrs */ 1198179157Srrs net->cwnd = net->prev_cwnd; 1199179157Srrs } 1200179157Srrs /* Now how much of that is mine? */ 1201179157Srrs seg_inflight = net->flight_size / net->mtu; 1202179157Srrs seg_onqueue = *on_queue / net->mtu; 1203179157Srrs my_portion = (incr * seg_inflight) / seg_onqueue; 1204179157Srrs 1205179157Srrs /* Have I made an adjustment already */ 1206179157Srrs if (net->cwnd > net->flight_size) { 1207179157Srrs /* 1208179157Srrs * for this flight I made an adjustment we need to 1209179157Srrs * decrease the portion by a share our previous 1210179157Srrs * adjustment. 1211179157Srrs */ 1212179157Srrs int diff_adj; 1213179157Srrs 1214179157Srrs diff_adj = net->cwnd - net->flight_size; 1215179157Srrs if (diff_adj > my_portion) 1216179157Srrs my_portion = 0; 1217179157Srrs else 1218179157Srrs my_portion -= diff_adj; 1219179157Srrs } 1220179157Srrs /* 1221179157Srrs * back down to the previous cwnd (assume we have had a sack 1222179157Srrs * before this packet). minus what ever portion of the 1223179157Srrs * overage is my fault. 1224179157Srrs */ 1225179157Srrs net->cwnd -= my_portion; 1226179157Srrs 1227179157Srrs /* we will NOT back down more than 1 MTU */ 1228179157Srrs if (net->cwnd <= net->mtu) { 1229179157Srrs net->cwnd = net->mtu; 1230179157Srrs } 1231179157Srrs /* force into CA */ 1232179157Srrs net->ssthresh = net->cwnd - 1; 1233179157Srrs } else { 1234179157Srrs /* 1235179157Srrs * Take 1/4 of the space left or max burst up .. whichever 1236179157Srrs * is less. 1237179157Srrs */ 1238217894Stuexen incr = (bw_avail - *on_queue) >> 2; 1239217894Stuexen if ((stcb->asoc.max_burst > 0) && 1240217894Stuexen (stcb->asoc.max_burst * net->mtu < incr)) { 1241217894Stuexen incr = stcb->asoc.max_burst * net->mtu; 1242217894Stuexen } 1243179157Srrs net->cwnd += incr; 1244179157Srrs } 1245179157Srrs if (net->cwnd > bw_avail) { 1246179157Srrs /* We can't exceed the pipe size */ 1247179157Srrs net->cwnd = bw_avail; 1248179157Srrs } 1249179157Srrs if (net->cwnd < net->mtu) { 1250179157Srrs /* We always have 1 MTU */ 1251179157Srrs net->cwnd = net->mtu; 1252179157Srrs } 1253279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 1254179157Srrs if (net->cwnd - old_cwnd != 0) { 1255179157Srrs /* log only changes */ 1256292384Smarkj SDT_PROBE5(sctp, cwnd, net, pd, 1257215817Srrs stcb->asoc.my_vtag, 1258215817Srrs ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 1259215817Srrs net, 1260215817Srrs old_cwnd, net->cwnd); 1261179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1262179157Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 1263179157Srrs SCTP_CWND_LOG_FROM_SAT); 1264179157Srrs } 1265179157Srrs } 1266179157Srrs} 1267179157Srrs 1268217611Stuexenstatic void 1269179157Srrssctp_cwnd_update_after_output(struct sctp_tcb *stcb, 1270179157Srrs struct sctp_nets *net, int burst_limit) 1271179157Srrs{ 1272179157Srrs int old_cwnd = net->cwnd; 1273179157Srrs 1274179157Srrs if (net->ssthresh < net->cwnd) 1275179157Srrs net->ssthresh = net->cwnd; 1276219120Srrs if (burst_limit) { 1277219120Srrs net->cwnd = (net->flight_size + (burst_limit * net->mtu)); 1278279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 1279292384Smarkj SDT_PROBE5(sctp, cwnd, net, bl, 1280219120Srrs stcb->asoc.my_vtag, 1281219120Srrs ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 1282219120Srrs net, 1283219120Srrs old_cwnd, net->cwnd); 1284219120Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1285219120Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST); 1286219120Srrs } 1287179157Srrs } 1288179157Srrs} 1289179157Srrs 1290217611Stuexenstatic void 1291219120Srrssctp_cwnd_update_after_sack(struct sctp_tcb *stcb, 1292219120Srrs struct sctp_association *asoc, 1293219120Srrs int accum_moved, int reneged_all, int will_exit) 1294219120Srrs{ 1295298942Spfg /* Passing a zero argument in last disables the rtcc algorithm */ 1296219120Srrs sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 0); 1297219120Srrs} 1298219120Srrs 1299219120Srrsstatic void 1300219120Srrssctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, 1301219120Srrs int in_window, int num_pkt_lost) 1302219120Srrs{ 1303298942Spfg /* Passing a zero argument in last disables the rtcc algorithm */ 1304219120Srrs sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 0); 1305219120Srrs} 1306219120Srrs 1307219120Srrs/* Here starts the RTCCVAR type CC invented by RRS which 1308219120Srrs * is a slight mod to RFC2581. We reuse a common routine or 1309298942Spfg * two since these algorithms are so close and need to 1310219120Srrs * remain the same. 1311219120Srrs */ 1312219120Srrsstatic void 1313219120Srrssctp_cwnd_update_rtcc_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, 1314219120Srrs int in_window, int num_pkt_lost) 1315219120Srrs{ 1316219120Srrs sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 1); 1317219120Srrs} 1318219120Srrs 1319219120Srrs 1320219120Srrsstatic 1321347154Stuexenvoid 1322219120Srrssctp_cwnd_update_rtcc_tsn_acknowledged(struct sctp_nets *net, 1323219120Srrs struct sctp_tmit_chunk *tp1) 1324219120Srrs{ 1325219120Srrs net->cc_mod.rtcc.bw_bytes += tp1->send_size; 1326219120Srrs} 1327219120Srrs 1328219120Srrsstatic void 1329228653Stuexensctp_cwnd_prepare_rtcc_net_for_sack(struct sctp_tcb *stcb SCTP_UNUSED, 1330219120Srrs struct sctp_nets *net) 1331219120Srrs{ 1332219120Srrs if (net->cc_mod.rtcc.tls_needs_set > 0) { 1333219120Srrs /* We had a bw measurment going on */ 1334219120Srrs struct timeval ltls; 1335219120Srrs 1336219120Srrs SCTP_GETPTIME_TIMEVAL(<ls); 1337219120Srrs timevalsub(<ls, &net->cc_mod.rtcc.tls); 1338219120Srrs net->cc_mod.rtcc.new_tot_time = (ltls.tv_sec * 1000000) + ltls.tv_usec; 1339219120Srrs } 1340219120Srrs} 1341219120Srrs 1342219120Srrsstatic void 1343219120Srrssctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb *stcb, 1344219120Srrs struct sctp_nets *net) 1345219120Srrs{ 1346219120Srrs uint64_t vtag, probepoint; 1347219120Srrs 1348219120Srrs if (net->cc_mod.rtcc.lbw) { 1349219120Srrs /* Clear the old bw.. we went to 0 in-flight */ 1350310773Stuexen vtag = (net->rtt << 32) | (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | 1351219120Srrs (stcb->rport); 1352310773Stuexen probepoint = (((uint64_t)net->cwnd) << 32); 1353219120Srrs /* Probe point 8 */ 1354219120Srrs probepoint |= ((8 << 16) | 0); 1355292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 1356219120Srrs vtag, 1357219120Srrs ((net->cc_mod.rtcc.lbw << 32) | 0), 1358219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 1359219397Srrs net->flight_size, 1360219120Srrs probepoint); 1361219120Srrs net->cc_mod.rtcc.lbw_rtt = 0; 1362219120Srrs net->cc_mod.rtcc.cwnd_at_bw_set = 0; 1363219120Srrs net->cc_mod.rtcc.lbw = 0; 1364219397Srrs net->cc_mod.rtcc.bw_bytes_at_last_rttc = 0; 1365219397Srrs net->cc_mod.rtcc.vol_reduce = 0; 1366219120Srrs net->cc_mod.rtcc.bw_tot_time = 0; 1367219120Srrs net->cc_mod.rtcc.bw_bytes = 0; 1368219120Srrs net->cc_mod.rtcc.tls_needs_set = 0; 1369219397Srrs if (net->cc_mod.rtcc.steady_step) { 1370219397Srrs net->cc_mod.rtcc.vol_reduce = 0; 1371219397Srrs net->cc_mod.rtcc.step_cnt = 0; 1372219397Srrs net->cc_mod.rtcc.last_step_state = 0; 1373219397Srrs } 1374219120Srrs if (net->cc_mod.rtcc.ret_from_eq) { 1375219120Srrs /* less aggressive one - reset cwnd too */ 1376219120Srrs uint32_t cwnd_in_mtu, cwnd; 1377219120Srrs 1378219120Srrs cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd); 1379219120Srrs if (cwnd_in_mtu == 0) { 1380310773Stuexen /* 1381310773Stuexen * Using 0 means that the value of RFC 4960 1382310773Stuexen * is used. 1383310773Stuexen */ 1384219120Srrs cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 1385219120Srrs } else { 1386219120Srrs /* 1387219120Srrs * We take the minimum of the burst limit 1388219120Srrs * and the initial congestion window. 1389219120Srrs */ 1390219120Srrs if ((stcb->asoc.max_burst > 0) && (cwnd_in_mtu > stcb->asoc.max_burst)) 1391219120Srrs cwnd_in_mtu = stcb->asoc.max_burst; 1392219120Srrs cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu; 1393219120Srrs } 1394219120Srrs if (net->cwnd > cwnd) { 1395310773Stuexen /* 1396310773Stuexen * Only set if we are not a timeout (i.e. 1397310773Stuexen * down to 1 mtu) 1398310773Stuexen */ 1399219120Srrs net->cwnd = cwnd; 1400219120Srrs } 1401219120Srrs } 1402219120Srrs } 1403219120Srrs} 1404219120Srrs 1405219120Srrsstatic void 1406219120Srrssctp_set_rtcc_initial_cc_param(struct sctp_tcb *stcb, 1407219120Srrs struct sctp_nets *net) 1408219120Srrs{ 1409219120Srrs uint64_t vtag, probepoint; 1410219120Srrs 1411219120Srrs sctp_set_initial_cc_param(stcb, net); 1412219120Srrs stcb->asoc.use_precise_time = 1; 1413310773Stuexen probepoint = (((uint64_t)net->cwnd) << 32); 1414219120Srrs probepoint |= ((9 << 16) | 0); 1415219120Srrs vtag = (net->rtt << 32) | 1416310773Stuexen (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | 1417219120Srrs (stcb->rport); 1418292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 1419219120Srrs vtag, 1420219120Srrs 0, 1421219120Srrs 0, 1422219120Srrs 0, 1423219120Srrs probepoint); 1424219120Srrs net->cc_mod.rtcc.lbw_rtt = 0; 1425219120Srrs net->cc_mod.rtcc.cwnd_at_bw_set = 0; 1426219397Srrs net->cc_mod.rtcc.vol_reduce = 0; 1427219120Srrs net->cc_mod.rtcc.lbw = 0; 1428219397Srrs net->cc_mod.rtcc.vol_reduce = 0; 1429219397Srrs net->cc_mod.rtcc.bw_bytes_at_last_rttc = 0; 1430219120Srrs net->cc_mod.rtcc.bw_tot_time = 0; 1431219120Srrs net->cc_mod.rtcc.bw_bytes = 0; 1432219120Srrs net->cc_mod.rtcc.tls_needs_set = 0; 1433219120Srrs net->cc_mod.rtcc.ret_from_eq = SCTP_BASE_SYSCTL(sctp_rttvar_eqret); 1434219397Srrs net->cc_mod.rtcc.steady_step = SCTP_BASE_SYSCTL(sctp_steady_step); 1435219397Srrs net->cc_mod.rtcc.use_dccc_ecn = SCTP_BASE_SYSCTL(sctp_use_dccc_ecn); 1436219397Srrs net->cc_mod.rtcc.step_cnt = 0; 1437219397Srrs net->cc_mod.rtcc.last_step_state = 0; 1438219397Srrs 1439219397Srrs 1440219120Srrs} 1441219120Srrs 1442219120Srrsstatic int 1443219120Srrssctp_cwnd_rtcc_socket_option(struct sctp_tcb *stcb, int setorget, 1444219120Srrs struct sctp_cc_option *cc_opt) 1445219120Srrs{ 1446219120Srrs struct sctp_nets *net; 1447219120Srrs 1448219120Srrs if (setorget == 1) { 1449219120Srrs /* a set */ 1450219120Srrs if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) { 1451219120Srrs if ((cc_opt->aid_value.assoc_value != 0) && 1452219120Srrs (cc_opt->aid_value.assoc_value != 1)) { 1453219120Srrs return (EINVAL); 1454219120Srrs } 1455219120Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1456219120Srrs net->cc_mod.rtcc.ret_from_eq = cc_opt->aid_value.assoc_value; 1457219120Srrs } 1458219120Srrs } else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) { 1459219120Srrs if ((cc_opt->aid_value.assoc_value != 0) && 1460219120Srrs (cc_opt->aid_value.assoc_value != 1)) { 1461219120Srrs return (EINVAL); 1462219120Srrs } 1463219120Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1464219120Srrs net->cc_mod.rtcc.use_dccc_ecn = cc_opt->aid_value.assoc_value; 1465219120Srrs } 1466219397Srrs } else if (cc_opt->option == SCTP_CC_OPT_STEADY_STEP) { 1467219397Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1468219397Srrs net->cc_mod.rtcc.steady_step = cc_opt->aid_value.assoc_value; 1469219397Srrs } 1470219120Srrs } else { 1471219120Srrs return (EINVAL); 1472219120Srrs } 1473219120Srrs } else { 1474219120Srrs /* a get */ 1475219120Srrs if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) { 1476219120Srrs net = TAILQ_FIRST(&stcb->asoc.nets); 1477219120Srrs if (net == NULL) { 1478219120Srrs return (EFAULT); 1479219120Srrs } 1480219120Srrs cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.ret_from_eq; 1481219120Srrs } else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) { 1482219120Srrs net = TAILQ_FIRST(&stcb->asoc.nets); 1483219120Srrs if (net == NULL) { 1484219120Srrs return (EFAULT); 1485219120Srrs } 1486219120Srrs cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.use_dccc_ecn; 1487219397Srrs } else if (cc_opt->option == SCTP_CC_OPT_STEADY_STEP) { 1488219397Srrs net = TAILQ_FIRST(&stcb->asoc.nets); 1489219397Srrs if (net == NULL) { 1490219397Srrs return (EFAULT); 1491219397Srrs } 1492219397Srrs cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.steady_step; 1493219120Srrs } else { 1494219120Srrs return (EINVAL); 1495219120Srrs } 1496219120Srrs } 1497219120Srrs return (0); 1498219120Srrs} 1499219120Srrs 1500219120Srrsstatic void 1501228653Stuexensctp_cwnd_update_rtcc_packet_transmitted(struct sctp_tcb *stcb SCTP_UNUSED, 1502219120Srrs struct sctp_nets *net) 1503219120Srrs{ 1504219120Srrs if (net->cc_mod.rtcc.tls_needs_set == 0) { 1505219120Srrs SCTP_GETPTIME_TIMEVAL(&net->cc_mod.rtcc.tls); 1506219120Srrs net->cc_mod.rtcc.tls_needs_set = 2; 1507219120Srrs } 1508219120Srrs} 1509219120Srrs 1510219120Srrsstatic void 1511219120Srrssctp_cwnd_update_rtcc_after_sack(struct sctp_tcb *stcb, 1512219120Srrs struct sctp_association *asoc, 1513219120Srrs int accum_moved, int reneged_all, int will_exit) 1514219120Srrs{ 1515298942Spfg /* Passing a one argument at the last enables the rtcc algorithm */ 1516219120Srrs sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 1); 1517219120Srrs} 1518219120Srrs 1519219397Srrsstatic void 1520228653Stuexensctp_rtt_rtcc_calculated(struct sctp_tcb *stcb SCTP_UNUSED, 1521228653Stuexen struct sctp_nets *net, 1522228653Stuexen struct timeval *now SCTP_UNUSED) 1523219397Srrs{ 1524219397Srrs net->cc_mod.rtcc.rtt_set_this_sack = 1; 1525219397Srrs} 1526219120Srrs 1527219120Srrs/* Here starts Sally Floyds HS-TCP */ 1528219120Srrs 1529171440Srrsstruct sctp_hs_raise_drop { 1530171440Srrs int32_t cwnd; 1531297208Stuexen int8_t increase; 1532297208Stuexen int8_t drop_percent; 1533171440Srrs}; 1534171440Srrs 1535171440Srrs#define SCTP_HS_TABLE_SIZE 73 1536171440Srrs 1537297208Stuexenstatic const struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = { 1538171440Srrs {38, 1, 50}, /* 0 */ 1539171440Srrs {118, 2, 44}, /* 1 */ 1540171440Srrs {221, 3, 41}, /* 2 */ 1541171440Srrs {347, 4, 38}, /* 3 */ 1542171440Srrs {495, 5, 37}, /* 4 */ 1543171440Srrs {663, 6, 35}, /* 5 */ 1544171440Srrs {851, 7, 34}, /* 6 */ 1545171440Srrs {1058, 8, 33}, /* 7 */ 1546171440Srrs {1284, 9, 32}, /* 8 */ 1547171440Srrs {1529, 10, 31}, /* 9 */ 1548171440Srrs {1793, 11, 30}, /* 10 */ 1549171440Srrs {2076, 12, 29}, /* 11 */ 1550171440Srrs {2378, 13, 28}, /* 12 */ 1551171440Srrs {2699, 14, 28}, /* 13 */ 1552171440Srrs {3039, 15, 27}, /* 14 */ 1553171440Srrs {3399, 16, 27}, /* 15 */ 1554171440Srrs {3778, 17, 26}, /* 16 */ 1555171440Srrs {4177, 18, 26}, /* 17 */ 1556171440Srrs {4596, 19, 25}, /* 18 */ 1557171440Srrs {5036, 20, 25}, /* 19 */ 1558171440Srrs {5497, 21, 24}, /* 20 */ 1559171440Srrs {5979, 22, 24}, /* 21 */ 1560171440Srrs {6483, 23, 23}, /* 22 */ 1561171440Srrs {7009, 24, 23}, /* 23 */ 1562171440Srrs {7558, 25, 22}, /* 24 */ 1563171440Srrs {8130, 26, 22}, /* 25 */ 1564171440Srrs {8726, 27, 22}, /* 26 */ 1565171440Srrs {9346, 28, 21}, /* 27 */ 1566171440Srrs {9991, 29, 21}, /* 28 */ 1567171440Srrs {10661, 30, 21}, /* 29 */ 1568171440Srrs {11358, 31, 20}, /* 30 */ 1569171440Srrs {12082, 32, 20}, /* 31 */ 1570171440Srrs {12834, 33, 20}, /* 32 */ 1571171440Srrs {13614, 34, 19}, /* 33 */ 1572171440Srrs {14424, 35, 19}, /* 34 */ 1573171440Srrs {15265, 36, 19}, /* 35 */ 1574171440Srrs {16137, 37, 19}, /* 36 */ 1575171440Srrs {17042, 38, 18}, /* 37 */ 1576171440Srrs {17981, 39, 18}, /* 38 */ 1577171440Srrs {18955, 40, 18}, /* 39 */ 1578171440Srrs {19965, 41, 17}, /* 40 */ 1579171440Srrs {21013, 42, 17}, /* 41 */ 1580171440Srrs {22101, 43, 17}, /* 42 */ 1581171440Srrs {23230, 44, 17}, /* 43 */ 1582171440Srrs {24402, 45, 16}, /* 44 */ 1583171440Srrs {25618, 46, 16}, /* 45 */ 1584171440Srrs {26881, 47, 16}, /* 46 */ 1585171440Srrs {28193, 48, 16}, /* 47 */ 1586171440Srrs {29557, 49, 15}, /* 48 */ 1587171440Srrs {30975, 50, 15}, /* 49 */ 1588171440Srrs {32450, 51, 15}, /* 50 */ 1589171440Srrs {33986, 52, 15}, /* 51 */ 1590171440Srrs {35586, 53, 14}, /* 52 */ 1591171440Srrs {37253, 54, 14}, /* 53 */ 1592171440Srrs {38992, 55, 14}, /* 54 */ 1593171440Srrs {40808, 56, 14}, /* 55 */ 1594171440Srrs {42707, 57, 13}, /* 56 */ 1595171440Srrs {44694, 58, 13}, /* 57 */ 1596171440Srrs {46776, 59, 13}, /* 58 */ 1597171440Srrs {48961, 60, 13}, /* 59 */ 1598171440Srrs {51258, 61, 13}, /* 60 */ 1599171440Srrs {53677, 62, 12}, /* 61 */ 1600171440Srrs {56230, 63, 12}, /* 62 */ 1601171440Srrs {58932, 64, 12}, /* 63 */ 1602171440Srrs {61799, 65, 12}, /* 64 */ 1603171440Srrs {64851, 66, 11}, /* 65 */ 1604171440Srrs {68113, 67, 11}, /* 66 */ 1605171440Srrs {71617, 68, 11}, /* 67 */ 1606171440Srrs {75401, 69, 10}, /* 68 */ 1607171440Srrs {79517, 70, 10}, /* 69 */ 1608171440Srrs {84035, 71, 10}, /* 70 */ 1609171440Srrs {89053, 72, 10}, /* 71 */ 1610171440Srrs {94717, 73, 9} /* 72 */ 1611171440Srrs}; 1612171440Srrs 1613171440Srrsstatic void 1614171440Srrssctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net) 1615171440Srrs{ 1616171440Srrs int cur_val, i, indx, incr; 1617279859Stuexen int old_cwnd = net->cwnd; 1618171440Srrs 1619171440Srrs cur_val = net->cwnd >> 10; 1620171440Srrs indx = SCTP_HS_TABLE_SIZE - 1; 1621234995Stuexen 1622171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 1623171440Srrs /* normal mode */ 1624171440Srrs if (net->net_ack > net->mtu) { 1625171440Srrs net->cwnd += net->mtu; 1626171440Srrs } else { 1627171440Srrs net->cwnd += net->net_ack; 1628171440Srrs } 1629171440Srrs } else { 1630171440Srrs for (i = net->last_hs_used; i < SCTP_HS_TABLE_SIZE; i++) { 1631171440Srrs if (cur_val < sctp_cwnd_adjust[i].cwnd) { 1632171440Srrs indx = i; 1633171440Srrs break; 1634171440Srrs } 1635171440Srrs } 1636171440Srrs net->last_hs_used = indx; 1637310773Stuexen incr = (((int32_t)sctp_cwnd_adjust[indx].increase) << 10); 1638171440Srrs net->cwnd += incr; 1639171440Srrs } 1640279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 1641279859Stuexen if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1642279859Stuexen sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SS); 1643279859Stuexen } 1644171440Srrs} 1645171440Srrs 1646171440Srrsstatic void 1647171440Srrssctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net) 1648171440Srrs{ 1649171440Srrs int cur_val, i, indx; 1650171440Srrs int old_cwnd = net->cwnd; 1651171440Srrs 1652171440Srrs cur_val = net->cwnd >> 10; 1653171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 1654171440Srrs /* normal mode */ 1655171440Srrs net->ssthresh = net->cwnd / 2; 1656171440Srrs if (net->ssthresh < (net->mtu * 2)) { 1657171440Srrs net->ssthresh = 2 * net->mtu; 1658171440Srrs } 1659171440Srrs net->cwnd = net->ssthresh; 1660171440Srrs } else { 1661171440Srrs /* drop by the proper amount */ 1662171440Srrs net->ssthresh = net->cwnd - (int)((net->cwnd / 100) * 1663310773Stuexen (int32_t)sctp_cwnd_adjust[net->last_hs_used].drop_percent); 1664171440Srrs net->cwnd = net->ssthresh; 1665171440Srrs /* now where are we */ 1666171440Srrs indx = net->last_hs_used; 1667171440Srrs cur_val = net->cwnd >> 10; 1668171440Srrs /* reset where we are in the table */ 1669171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 1670171440Srrs /* feel out of hs */ 1671171440Srrs net->last_hs_used = 0; 1672171440Srrs } else { 1673171440Srrs for (i = indx; i >= 1; i--) { 1674171440Srrs if (cur_val > sctp_cwnd_adjust[i - 1].cwnd) { 1675171440Srrs break; 1676171440Srrs } 1677171440Srrs } 1678171440Srrs net->last_hs_used = indx; 1679171440Srrs } 1680171440Srrs } 1681279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 1682179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1683171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_FR); 1684171440Srrs } 1685171440Srrs} 1686171440Srrs 1687217611Stuexenstatic void 1688171440Srrssctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb, 1689171440Srrs struct sctp_association *asoc) 1690171440Srrs{ 1691171440Srrs struct sctp_nets *net; 1692171440Srrs 1693171440Srrs /* 1694216669Stuexen * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) && 1695171440Srrs * (net->fast_retran_loss_recovery == 0))) 1696171440Srrs */ 1697171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 1698211944Stuexen if ((asoc->fast_retran_loss_recovery == 0) || 1699216669Stuexen (asoc->sctp_cmt_on_off > 0)) { 1700171440Srrs /* out of a RFC2582 Fast recovery window? */ 1701171440Srrs if (net->net_ack > 0) { 1702171440Srrs /* 1703171440Srrs * per section 7.2.3, are there any 1704171440Srrs * destinations that had a fast retransmit 1705171440Srrs * to them. If so what we need to do is 1706171440Srrs * adjust ssthresh and cwnd. 1707171440Srrs */ 1708171440Srrs struct sctp_tmit_chunk *lchk; 1709171440Srrs 1710171440Srrs sctp_hs_cwnd_decrease(stcb, net); 1711171440Srrs 1712171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 1713171440Srrs 1714171440Srrs net->partial_bytes_acked = 0; 1715171440Srrs /* Turn on fast recovery window */ 1716171440Srrs asoc->fast_retran_loss_recovery = 1; 1717171440Srrs if (lchk == NULL) { 1718171440Srrs /* Mark end of the window */ 1719171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 1720171440Srrs } else { 1721310219Stuexen asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1; 1722171440Srrs } 1723171440Srrs 1724171440Srrs /* 1725171440Srrs * CMT fast recovery -- per destination 1726171440Srrs * recovery variable. 1727171440Srrs */ 1728171440Srrs net->fast_retran_loss_recovery = 1; 1729171440Srrs 1730171440Srrs if (lchk == NULL) { 1731171440Srrs /* Mark end of the window */ 1732171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 1733171440Srrs } else { 1734310219Stuexen net->fast_recovery_tsn = lchk->rec.data.tsn - 1; 1735171440Srrs } 1736171440Srrs 1737171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 1738283650Stuexen stcb->sctp_ep, stcb, net, 1739283650Stuexen SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_2); 1740171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 1741171440Srrs stcb->sctp_ep, stcb, net); 1742171440Srrs } 1743171440Srrs } else if (net->net_ack > 0) { 1744171440Srrs /* 1745171440Srrs * Mark a peg that we WOULD have done a cwnd 1746171440Srrs * reduction but RFC2582 prevented this action. 1747171440Srrs */ 1748171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 1749171440Srrs } 1750171440Srrs } 1751171440Srrs} 1752171440Srrs 1753217611Stuexenstatic void 1754171440Srrssctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, 1755171440Srrs struct sctp_association *asoc, 1756228653Stuexen int accum_moved, int reneged_all SCTP_UNUSED, int will_exit) 1757171440Srrs{ 1758171440Srrs struct sctp_nets *net; 1759171440Srrs 1760171440Srrs /******************************/ 1761171440Srrs /* update cwnd and Early FR */ 1762171440Srrs /******************************/ 1763171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 1764171440Srrs 1765171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 1766171440Srrs /* 1767171440Srrs * CMT fast recovery code. Need to debug. 1768171440Srrs */ 1769171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 1770217469Stuexen if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) || 1771217469Stuexen SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) { 1772171440Srrs net->will_exit_fast_recovery = 1; 1773171440Srrs } 1774171440Srrs } 1775171440Srrs#endif 1776171440Srrs /* if nothing was acked on this destination skip it */ 1777171440Srrs if (net->net_ack == 0) { 1778179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1779171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 1780171440Srrs } 1781171440Srrs continue; 1782171440Srrs } 1783171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 1784171440Srrs /* 1785171440Srrs * CMT fast recovery code 1786171440Srrs */ 1787171440Srrs /* 1788216669Stuexen * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery 1789216669Stuexen * && net->will_exit_fast_recovery == 0) { @@@ Do something 1790216669Stuexen * } else if (sctp_cmt_on_off == 0 && 1791171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 1792171440Srrs */ 1793171440Srrs#endif 1794171440Srrs 1795211944Stuexen if (asoc->fast_retran_loss_recovery && 1796211944Stuexen (will_exit == 0) && 1797211944Stuexen (asoc->sctp_cmt_on_off == 0)) { 1798171440Srrs /* 1799171440Srrs * If we are in loss recovery we skip any cwnd 1800171440Srrs * update 1801171440Srrs */ 1802224641Stuexen return; 1803171440Srrs } 1804171440Srrs /* 1805171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 1806171440Srrs * moved. 1807171440Srrs */ 1808211944Stuexen if (accum_moved || 1809216669Stuexen ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) { 1810171440Srrs /* If the cumulative ack moved we can proceed */ 1811171440Srrs if (net->cwnd <= net->ssthresh) { 1812171440Srrs /* We are in slow start */ 1813179157Srrs if (net->flight_size + net->net_ack >= net->cwnd) { 1814171440Srrs sctp_hs_cwnd_increase(stcb, net); 1815171440Srrs } else { 1816179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1817171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 1818171440Srrs SCTP_CWND_LOG_NOADV_SS); 1819171440Srrs } 1820171440Srrs } 1821171440Srrs } else { 1822171440Srrs /* We are in congestion avoidance */ 1823179157Srrs net->partial_bytes_acked += net->net_ack; 1824179157Srrs if ((net->flight_size + net->net_ack >= net->cwnd) && 1825179157Srrs (net->partial_bytes_acked >= net->cwnd)) { 1826179157Srrs net->partial_bytes_acked -= net->cwnd; 1827179157Srrs net->cwnd += net->mtu; 1828279859Stuexen sctp_enforce_cwnd_limit(asoc, net); 1829179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1830179157Srrs sctp_log_cwnd(stcb, net, net->mtu, 1831179157Srrs SCTP_CWND_LOG_FROM_CA); 1832171440Srrs } 1833171440Srrs } else { 1834179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1835171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 1836171440Srrs SCTP_CWND_LOG_NOADV_CA); 1837171440Srrs } 1838171440Srrs } 1839171440Srrs } 1840171440Srrs } else { 1841179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1842171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 1843171440Srrs SCTP_CWND_LOG_NO_CUMACK); 1844171440Srrs } 1845171440Srrs } 1846171440Srrs } 1847171440Srrs} 1848171440Srrs 1849171440Srrs 1850171440Srrs/* 1851171440Srrs * H-TCP congestion control. The algorithm is detailed in: 1852171440Srrs * R.N.Shorten, D.J.Leith: 1853171440Srrs * "H-TCP: TCP for high-speed and long-distance networks" 1854171440Srrs * Proc. PFLDnet, Argonne, 2004. 1855171440Srrs * http://www.hamilton.ie/net/htcp3.pdf 1856171440Srrs */ 1857171440Srrs 1858171440Srrs 1859171440Srrsstatic int use_rtt_scaling = 1; 1860171440Srrsstatic int use_bandwidth_switch = 1; 1861171440Srrs 1862171440Srrsstatic inline int 1863171440Srrsbetween(uint32_t seq1, uint32_t seq2, uint32_t seq3) 1864171440Srrs{ 1865228907Stuexen return (seq3 - seq2 >= seq1 - seq2); 1866171440Srrs} 1867171440Srrs 1868171440Srrsstatic inline uint32_t 1869171440Srrshtcp_cong_time(struct htcp *ca) 1870171440Srrs{ 1871228907Stuexen return (sctp_get_tick_count() - ca->last_cong); 1872171440Srrs} 1873171440Srrs 1874171440Srrsstatic inline uint32_t 1875171440Srrshtcp_ccount(struct htcp *ca) 1876171440Srrs{ 1877360758Stuexen return (ca->minRTT == 0 ? htcp_cong_time(ca) : htcp_cong_time(ca) / ca->minRTT); 1878171440Srrs} 1879171440Srrs 1880171440Srrsstatic inline void 1881171440Srrshtcp_reset(struct htcp *ca) 1882171440Srrs{ 1883171440Srrs ca->undo_last_cong = ca->last_cong; 1884171440Srrs ca->undo_maxRTT = ca->maxRTT; 1885171440Srrs ca->undo_old_maxB = ca->old_maxB; 1886171477Srrs ca->last_cong = sctp_get_tick_count(); 1887171440Srrs} 1888171440Srrs 1889171440Srrs#ifdef SCTP_NOT_USED 1890171440Srrs 1891171440Srrsstatic uint32_t 1892171440Srrshtcp_cwnd_undo(struct sctp_tcb *stcb, struct sctp_nets *net) 1893171440Srrs{ 1894219057Srrs net->cc_mod.htcp_ca.last_cong = net->cc_mod.htcp_ca.undo_last_cong; 1895219057Srrs net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.undo_maxRTT; 1896219057Srrs net->cc_mod.htcp_ca.old_maxB = net->cc_mod.htcp_ca.undo_old_maxB; 1897228907Stuexen return (max(net->cwnd, ((net->ssthresh / net->mtu << 7) / net->cc_mod.htcp_ca.beta) * net->mtu)); 1898171440Srrs} 1899171440Srrs 1900171440Srrs#endif 1901171440Srrs 1902171440Srrsstatic inline void 1903228653Stuexenmeasure_rtt(struct sctp_nets *net) 1904171440Srrs{ 1905219014Stuexen uint32_t srtt = net->lastsa >> SCTP_RTT_SHIFT; 1906171440Srrs 1907171440Srrs /* keep track of minimum RTT seen so far, minRTT is zero at first */ 1908219057Srrs if (net->cc_mod.htcp_ca.minRTT > srtt || !net->cc_mod.htcp_ca.minRTT) 1909219057Srrs net->cc_mod.htcp_ca.minRTT = srtt; 1910171440Srrs 1911171440Srrs /* max RTT */ 1912219057Srrs if (net->fast_retran_ip == 0 && net->ssthresh < 0xFFFF && htcp_ccount(&net->cc_mod.htcp_ca) > 3) { 1913219057Srrs if (net->cc_mod.htcp_ca.maxRTT < net->cc_mod.htcp_ca.minRTT) 1914219057Srrs net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.minRTT; 1915219057Srrs if (net->cc_mod.htcp_ca.maxRTT < srtt && srtt <= net->cc_mod.htcp_ca.maxRTT + MSEC_TO_TICKS(20)) 1916219057Srrs net->cc_mod.htcp_ca.maxRTT = srtt; 1917171440Srrs } 1918171440Srrs} 1919171440Srrs 1920171440Srrsstatic void 1921228653Stuexenmeasure_achieved_throughput(struct sctp_nets *net) 1922171440Srrs{ 1923171477Srrs uint32_t now = sctp_get_tick_count(); 1924171440Srrs 1925171440Srrs if (net->fast_retran_ip == 0) 1926219057Srrs net->cc_mod.htcp_ca.bytes_acked = net->net_ack; 1927171440Srrs 1928171440Srrs if (!use_bandwidth_switch) 1929171440Srrs return; 1930171440Srrs 1931171440Srrs /* achieved throughput calculations */ 1932171440Srrs /* JRS - not 100% sure of this statement */ 1933171440Srrs if (net->fast_retran_ip == 1) { 1934219057Srrs net->cc_mod.htcp_ca.bytecount = 0; 1935219057Srrs net->cc_mod.htcp_ca.lasttime = now; 1936171440Srrs return; 1937171440Srrs } 1938347154Stuexen 1939219057Srrs net->cc_mod.htcp_ca.bytecount += net->net_ack; 1940240158Stuexen if ((net->cc_mod.htcp_ca.bytecount >= net->cwnd - (((net->cc_mod.htcp_ca.alpha >> 7) ? (net->cc_mod.htcp_ca.alpha >> 7) : 1) * net->mtu)) && 1941240158Stuexen (now - net->cc_mod.htcp_ca.lasttime >= net->cc_mod.htcp_ca.minRTT) && 1942240158Stuexen (net->cc_mod.htcp_ca.minRTT > 0)) { 1943219057Srrs uint32_t cur_Bi = net->cc_mod.htcp_ca.bytecount / net->mtu * hz / (now - net->cc_mod.htcp_ca.lasttime); 1944171440Srrs 1945219057Srrs if (htcp_ccount(&net->cc_mod.htcp_ca) <= 3) { 1946171440Srrs /* just after backoff */ 1947219057Srrs net->cc_mod.htcp_ca.minB = net->cc_mod.htcp_ca.maxB = net->cc_mod.htcp_ca.Bi = cur_Bi; 1948171440Srrs } else { 1949219057Srrs net->cc_mod.htcp_ca.Bi = (3 * net->cc_mod.htcp_ca.Bi + cur_Bi) / 4; 1950219057Srrs if (net->cc_mod.htcp_ca.Bi > net->cc_mod.htcp_ca.maxB) 1951219057Srrs net->cc_mod.htcp_ca.maxB = net->cc_mod.htcp_ca.Bi; 1952219057Srrs if (net->cc_mod.htcp_ca.minB > net->cc_mod.htcp_ca.maxB) 1953219057Srrs net->cc_mod.htcp_ca.minB = net->cc_mod.htcp_ca.maxB; 1954171440Srrs } 1955219057Srrs net->cc_mod.htcp_ca.bytecount = 0; 1956219057Srrs net->cc_mod.htcp_ca.lasttime = now; 1957171440Srrs } 1958171440Srrs} 1959171440Srrs 1960171440Srrsstatic inline void 1961171440Srrshtcp_beta_update(struct htcp *ca, uint32_t minRTT, uint32_t maxRTT) 1962171440Srrs{ 1963171440Srrs if (use_bandwidth_switch) { 1964171440Srrs uint32_t maxB = ca->maxB; 1965171440Srrs uint32_t old_maxB = ca->old_maxB; 1966171440Srrs 1967171440Srrs ca->old_maxB = ca->maxB; 1968171440Srrs 1969171440Srrs if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) { 1970171440Srrs ca->beta = BETA_MIN; 1971171440Srrs ca->modeswitch = 0; 1972171440Srrs return; 1973171440Srrs } 1974171440Srrs } 1975347154Stuexen 1976310773Stuexen if (ca->modeswitch && minRTT > (uint32_t)MSEC_TO_TICKS(10) && maxRTT) { 1977171440Srrs ca->beta = (minRTT << 7) / maxRTT; 1978171440Srrs if (ca->beta < BETA_MIN) 1979171440Srrs ca->beta = BETA_MIN; 1980171440Srrs else if (ca->beta > BETA_MAX) 1981171440Srrs ca->beta = BETA_MAX; 1982171440Srrs } else { 1983171440Srrs ca->beta = BETA_MIN; 1984171440Srrs ca->modeswitch = 1; 1985171440Srrs } 1986171440Srrs} 1987171440Srrs 1988171440Srrsstatic inline void 1989171440Srrshtcp_alpha_update(struct htcp *ca) 1990171440Srrs{ 1991171440Srrs uint32_t minRTT = ca->minRTT; 1992171440Srrs uint32_t factor = 1; 1993171440Srrs uint32_t diff = htcp_cong_time(ca); 1994171440Srrs 1995310773Stuexen if (diff > (uint32_t)hz) { 1996171440Srrs diff -= hz; 1997171440Srrs factor = 1 + (10 * diff + ((diff / 2) * (diff / 2) / hz)) / hz; 1998171440Srrs } 1999347154Stuexen 2000171440Srrs if (use_rtt_scaling && minRTT) { 2001171440Srrs uint32_t scale = (hz << 3) / (10 * minRTT); 2002171440Srrs 2003171440Srrs scale = min(max(scale, 1U << 2), 10U << 3); /* clamping ratio to 2004171440Srrs * interval [0.5,10]<<3 */ 2005171440Srrs factor = (factor << 3) / scale; 2006171440Srrs if (!factor) 2007171440Srrs factor = 1; 2008171440Srrs } 2009347154Stuexen 2010171440Srrs ca->alpha = 2 * factor * ((1 << 7) - ca->beta); 2011171440Srrs if (!ca->alpha) 2012171440Srrs ca->alpha = ALPHA_BASE; 2013171440Srrs} 2014171440Srrs 2015171440Srrs/* After we have the rtt data to calculate beta, we'd still prefer to wait one 2016171440Srrs * rtt before we adjust our beta to ensure we are working from a consistent 2017171440Srrs * data. 2018171440Srrs * 2019171440Srrs * This function should be called when we hit a congestion event since only at 2020171440Srrs * that point do we really have a real sense of maxRTT (the queues en route 2021171440Srrs * were getting just too full now). 2022171440Srrs */ 2023171440Srrsstatic void 2024228653Stuexenhtcp_param_update(struct sctp_nets *net) 2025171440Srrs{ 2026219057Srrs uint32_t minRTT = net->cc_mod.htcp_ca.minRTT; 2027219057Srrs uint32_t maxRTT = net->cc_mod.htcp_ca.maxRTT; 2028171440Srrs 2029219057Srrs htcp_beta_update(&net->cc_mod.htcp_ca, minRTT, maxRTT); 2030219057Srrs htcp_alpha_update(&net->cc_mod.htcp_ca); 2031171440Srrs 2032310773Stuexen /* 2033310773Stuexen * add slowly fading memory for maxRTT to accommodate routing 2034310773Stuexen * changes etc 2035310773Stuexen */ 2036171440Srrs if (minRTT > 0 && maxRTT > minRTT) 2037219057Srrs net->cc_mod.htcp_ca.maxRTT = minRTT + ((maxRTT - minRTT) * 95) / 100; 2038171440Srrs} 2039171440Srrs 2040171440Srrsstatic uint32_t 2041228653Stuexenhtcp_recalc_ssthresh(struct sctp_nets *net) 2042171440Srrs{ 2043228653Stuexen htcp_param_update(net); 2044228907Stuexen return (max(((net->cwnd / net->mtu * net->cc_mod.htcp_ca.beta) >> 7) * net->mtu, 2U * net->mtu)); 2045171440Srrs} 2046171440Srrs 2047171440Srrsstatic void 2048171440Srrshtcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net) 2049171440Srrs{ 2050171440Srrs /*- 2051171440Srrs * How to handle these functions? 2052171440Srrs * if (!tcp_is_cwnd_limited(sk, in_flight)) RRS - good question. 2053171440Srrs * return; 2054171440Srrs */ 2055171440Srrs if (net->cwnd <= net->ssthresh) { 2056171440Srrs /* We are in slow start */ 2057171440Srrs if (net->flight_size + net->net_ack >= net->cwnd) { 2058179783Srrs if (net->net_ack > (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable))) { 2059179783Srrs net->cwnd += (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)); 2060179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2061171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 2062171440Srrs SCTP_CWND_LOG_FROM_SS); 2063171440Srrs } 2064347154Stuexen 2065171440Srrs } else { 2066171440Srrs net->cwnd += net->net_ack; 2067179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2068171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 2069171440Srrs SCTP_CWND_LOG_FROM_SS); 2070171440Srrs } 2071347154Stuexen 2072171440Srrs } 2073279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 2074171440Srrs } else { 2075179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 2076171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 2077171440Srrs SCTP_CWND_LOG_NOADV_SS); 2078171440Srrs } 2079171440Srrs } 2080171440Srrs } else { 2081228653Stuexen measure_rtt(net); 2082171440Srrs 2083171440Srrs /* 2084171440Srrs * In dangerous area, increase slowly. In theory this is 2085171440Srrs * net->cwnd += alpha / net->cwnd 2086171440Srrs */ 2087171440Srrs /* What is snd_cwnd_cnt?? */ 2088219057Srrs if (((net->partial_bytes_acked / net->mtu * net->cc_mod.htcp_ca.alpha) >> 7) * net->mtu >= net->cwnd) { 2089171440Srrs /*- 2090171440Srrs * Does SCTP have a cwnd clamp? 2091171440Srrs * if (net->snd_cwnd < net->snd_cwnd_clamp) - Nope (RRS). 2092171440Srrs */ 2093171440Srrs net->cwnd += net->mtu; 2094171440Srrs net->partial_bytes_acked = 0; 2095279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 2096219057Srrs htcp_alpha_update(&net->cc_mod.htcp_ca); 2097179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2098171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 2099171440Srrs SCTP_CWND_LOG_FROM_CA); 2100171440Srrs } 2101171440Srrs } else { 2102171440Srrs net->partial_bytes_acked += net->net_ack; 2103179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 2104171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 2105171440Srrs SCTP_CWND_LOG_NOADV_CA); 2106171440Srrs } 2107171440Srrs } 2108171440Srrs 2109219057Srrs net->cc_mod.htcp_ca.bytes_acked = net->mtu; 2110171440Srrs } 2111171440Srrs} 2112171440Srrs 2113171440Srrs#ifdef SCTP_NOT_USED 2114171440Srrs/* Lower bound on congestion window. */ 2115171440Srrsstatic uint32_t 2116171440Srrshtcp_min_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net) 2117171440Srrs{ 2118228907Stuexen return (net->ssthresh); 2119171440Srrs} 2120171440Srrs#endif 2121171440Srrs 2122171440Srrsstatic void 2123228653Stuexenhtcp_init(struct sctp_nets *net) 2124171440Srrs{ 2125219057Srrs memset(&net->cc_mod.htcp_ca, 0, sizeof(struct htcp)); 2126219057Srrs net->cc_mod.htcp_ca.alpha = ALPHA_BASE; 2127219057Srrs net->cc_mod.htcp_ca.beta = BETA_MIN; 2128219057Srrs net->cc_mod.htcp_ca.bytes_acked = net->mtu; 2129219057Srrs net->cc_mod.htcp_ca.last_cong = sctp_get_tick_count(); 2130171440Srrs} 2131171440Srrs 2132217611Stuexenstatic void 2133171440Srrssctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) 2134171440Srrs{ 2135171440Srrs /* 2136171440Srrs * We take the max of the burst limit times a MTU or the 2137171440Srrs * INITIAL_CWND. We then limit this to 4 MTU's of sending. 2138171440Srrs */ 2139171440Srrs net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 2140171440Srrs net->ssthresh = stcb->asoc.peers_rwnd; 2141279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 2142228653Stuexen htcp_init(net); 2143171440Srrs 2144179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { 2145171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); 2146171440Srrs } 2147171440Srrs} 2148171440Srrs 2149217611Stuexenstatic void 2150171440Srrssctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, 2151171440Srrs struct sctp_association *asoc, 2152228653Stuexen int accum_moved, int reneged_all SCTP_UNUSED, int will_exit) 2153171440Srrs{ 2154171440Srrs struct sctp_nets *net; 2155171440Srrs 2156171440Srrs /******************************/ 2157171440Srrs /* update cwnd and Early FR */ 2158171440Srrs /******************************/ 2159171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 2160171440Srrs 2161171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 2162171440Srrs /* 2163171440Srrs * CMT fast recovery code. Need to debug. 2164171440Srrs */ 2165171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 2166217469Stuexen if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) || 2167217469Stuexen SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) { 2168171440Srrs net->will_exit_fast_recovery = 1; 2169171440Srrs } 2170171440Srrs } 2171171440Srrs#endif 2172171440Srrs /* if nothing was acked on this destination skip it */ 2173171440Srrs if (net->net_ack == 0) { 2174179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 2175171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 2176171440Srrs } 2177171440Srrs continue; 2178171440Srrs } 2179171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 2180171440Srrs /* 2181171440Srrs * CMT fast recovery code 2182171440Srrs */ 2183171440Srrs /* 2184216669Stuexen * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery 2185216669Stuexen * && net->will_exit_fast_recovery == 0) { @@@ Do something 2186216669Stuexen * } else if (sctp_cmt_on_off == 0 && 2187171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 2188171440Srrs */ 2189171440Srrs#endif 2190171440Srrs 2191211944Stuexen if (asoc->fast_retran_loss_recovery && 2192211944Stuexen will_exit == 0 && 2193211944Stuexen (asoc->sctp_cmt_on_off == 0)) { 2194171440Srrs /* 2195171440Srrs * If we are in loss recovery we skip any cwnd 2196171440Srrs * update 2197171440Srrs */ 2198224641Stuexen return; 2199171440Srrs } 2200171440Srrs /* 2201171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 2202171440Srrs * moved. 2203171440Srrs */ 2204211944Stuexen if (accum_moved || 2205216669Stuexen ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) { 2206171440Srrs htcp_cong_avoid(stcb, net); 2207228653Stuexen measure_achieved_throughput(net); 2208171440Srrs } else { 2209179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 2210171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 2211171440Srrs SCTP_CWND_LOG_NO_CUMACK); 2212171440Srrs } 2213171440Srrs } 2214171440Srrs } 2215171440Srrs} 2216171440Srrs 2217217611Stuexenstatic void 2218171440Srrssctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb, 2219171440Srrs struct sctp_association *asoc) 2220171440Srrs{ 2221171440Srrs struct sctp_nets *net; 2222171440Srrs 2223171440Srrs /* 2224216669Stuexen * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) && 2225171440Srrs * (net->fast_retran_loss_recovery == 0))) 2226171440Srrs */ 2227171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 2228211944Stuexen if ((asoc->fast_retran_loss_recovery == 0) || 2229216669Stuexen (asoc->sctp_cmt_on_off > 0)) { 2230171440Srrs /* out of a RFC2582 Fast recovery window? */ 2231171440Srrs if (net->net_ack > 0) { 2232171440Srrs /* 2233171440Srrs * per section 7.2.3, are there any 2234171440Srrs * destinations that had a fast retransmit 2235171440Srrs * to them. If so what we need to do is 2236171440Srrs * adjust ssthresh and cwnd. 2237171440Srrs */ 2238171440Srrs struct sctp_tmit_chunk *lchk; 2239171440Srrs int old_cwnd = net->cwnd; 2240171440Srrs 2241171440Srrs /* JRS - reset as if state were changed */ 2242219057Srrs htcp_reset(&net->cc_mod.htcp_ca); 2243228653Stuexen net->ssthresh = htcp_recalc_ssthresh(net); 2244171440Srrs net->cwnd = net->ssthresh; 2245279859Stuexen sctp_enforce_cwnd_limit(asoc, net); 2246179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2247171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 2248171440Srrs SCTP_CWND_LOG_FROM_FR); 2249171440Srrs } 2250171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 2251171440Srrs 2252171440Srrs net->partial_bytes_acked = 0; 2253171440Srrs /* Turn on fast recovery window */ 2254171440Srrs asoc->fast_retran_loss_recovery = 1; 2255171440Srrs if (lchk == NULL) { 2256171440Srrs /* Mark end of the window */ 2257171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 2258171440Srrs } else { 2259310219Stuexen asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1; 2260171440Srrs } 2261171440Srrs 2262171440Srrs /* 2263171440Srrs * CMT fast recovery -- per destination 2264171440Srrs * recovery variable. 2265171440Srrs */ 2266171440Srrs net->fast_retran_loss_recovery = 1; 2267171440Srrs 2268171440Srrs if (lchk == NULL) { 2269171440Srrs /* Mark end of the window */ 2270171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 2271171440Srrs } else { 2272310219Stuexen net->fast_recovery_tsn = lchk->rec.data.tsn - 1; 2273171440Srrs } 2274171440Srrs 2275171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 2276283650Stuexen stcb->sctp_ep, stcb, net, 2277283650Stuexen SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_3); 2278171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 2279171440Srrs stcb->sctp_ep, stcb, net); 2280171440Srrs } 2281171440Srrs } else if (net->net_ack > 0) { 2282171440Srrs /* 2283171440Srrs * Mark a peg that we WOULD have done a cwnd 2284171440Srrs * reduction but RFC2582 prevented this action. 2285171440Srrs */ 2286171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 2287171440Srrs } 2288171440Srrs } 2289171440Srrs} 2290171440Srrs 2291217611Stuexenstatic void 2292171440Srrssctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb, 2293171440Srrs struct sctp_nets *net) 2294171440Srrs{ 2295171440Srrs int old_cwnd = net->cwnd; 2296171440Srrs 2297171440Srrs /* JRS - reset as if the state were being changed to timeout */ 2298219057Srrs htcp_reset(&net->cc_mod.htcp_ca); 2299228653Stuexen net->ssthresh = htcp_recalc_ssthresh(net); 2300171440Srrs net->cwnd = net->mtu; 2301179157Srrs net->partial_bytes_acked = 0; 2302179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2303171440Srrs sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 2304171440Srrs } 2305171440Srrs} 2306171440Srrs 2307217611Stuexenstatic void 2308171440Srrssctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, 2309228653Stuexen struct sctp_nets *net, int in_window, int num_pkt_lost SCTP_UNUSED) 2310171440Srrs{ 2311171440Srrs int old_cwnd; 2312171440Srrs 2313171440Srrs old_cwnd = net->cwnd; 2314171440Srrs 2315171440Srrs /* JRS - reset hctp as if state changed */ 2316218129Srrs if (in_window == 0) { 2317219057Srrs htcp_reset(&net->cc_mod.htcp_ca); 2318218129Srrs SCTP_STAT_INCR(sctps_ecnereducedcwnd); 2319228653Stuexen net->ssthresh = htcp_recalc_ssthresh(net); 2320218129Srrs if (net->ssthresh < net->mtu) { 2321218129Srrs net->ssthresh = net->mtu; 2322218129Srrs /* here back off the timer as well, to slow us down */ 2323218129Srrs net->RTO <<= 1; 2324218129Srrs } 2325218129Srrs net->cwnd = net->ssthresh; 2326279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 2327218129Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2328218129Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 2329218129Srrs } 2330171440Srrs } 2331171440Srrs} 2332217611Stuexen 2333297208Stuexenconst struct sctp_cc_functions sctp_cc_functions[] = { 2334217611Stuexen { 2335217611Stuexen .sctp_set_initial_cc_param = sctp_set_initial_cc_param, 2336217611Stuexen .sctp_cwnd_update_after_sack = sctp_cwnd_update_after_sack, 2337224641Stuexen .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, 2338217611Stuexen .sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr, 2339217611Stuexen .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, 2340217611Stuexen .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo, 2341217611Stuexen .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, 2342217611Stuexen .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, 2343217611Stuexen }, 2344217611Stuexen { 2345217611Stuexen .sctp_set_initial_cc_param = sctp_set_initial_cc_param, 2346217611Stuexen .sctp_cwnd_update_after_sack = sctp_hs_cwnd_update_after_sack, 2347224641Stuexen .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, 2348217611Stuexen .sctp_cwnd_update_after_fr = sctp_hs_cwnd_update_after_fr, 2349217611Stuexen .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, 2350217611Stuexen .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo, 2351217611Stuexen .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, 2352217611Stuexen .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, 2353217611Stuexen }, 2354217611Stuexen { 2355217611Stuexen .sctp_set_initial_cc_param = sctp_htcp_set_initial_cc_param, 2356217611Stuexen .sctp_cwnd_update_after_sack = sctp_htcp_cwnd_update_after_sack, 2357224641Stuexen .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, 2358217611Stuexen .sctp_cwnd_update_after_fr = sctp_htcp_cwnd_update_after_fr, 2359217611Stuexen .sctp_cwnd_update_after_timeout = sctp_htcp_cwnd_update_after_timeout, 2360217611Stuexen .sctp_cwnd_update_after_ecn_echo = sctp_htcp_cwnd_update_after_ecn_echo, 2361217611Stuexen .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, 2362217611Stuexen .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, 2363219120Srrs }, 2364219120Srrs { 2365219120Srrs .sctp_set_initial_cc_param = sctp_set_rtcc_initial_cc_param, 2366219120Srrs .sctp_cwnd_update_after_sack = sctp_cwnd_update_rtcc_after_sack, 2367224641Stuexen .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, 2368219120Srrs .sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr, 2369219120Srrs .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, 2370219120Srrs .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_rtcc_after_ecn_echo, 2371219120Srrs .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, 2372219120Srrs .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, 2373219120Srrs .sctp_cwnd_update_packet_transmitted = sctp_cwnd_update_rtcc_packet_transmitted, 2374219120Srrs .sctp_cwnd_update_tsn_acknowledged = sctp_cwnd_update_rtcc_tsn_acknowledged, 2375219120Srrs .sctp_cwnd_new_transmission_begins = sctp_cwnd_new_rtcc_transmission_begins, 2376219120Srrs .sctp_cwnd_prepare_net_for_sack = sctp_cwnd_prepare_rtcc_net_for_sack, 2377219397Srrs .sctp_cwnd_socket_option = sctp_cwnd_rtcc_socket_option, 2378219397Srrs .sctp_rtt_calculated = sctp_rtt_rtcc_calculated 2379217611Stuexen } 2380217611Stuexen}; 2381