sctp_cc_functions.c revision 310773
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 310773 2016-12-29 11:32:42Z 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 } 132171440Srrs /*- 133216669Stuexen * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) && 134171440Srrs * (net->fast_retran_loss_recovery == 0))) 135171440Srrs */ 136171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 137211944Stuexen if ((asoc->fast_retran_loss_recovery == 0) || 138216669Stuexen (asoc->sctp_cmt_on_off > 0)) { 139171440Srrs /* out of a RFC2582 Fast recovery window? */ 140171440Srrs if (net->net_ack > 0) { 141171440Srrs /* 142171440Srrs * per section 7.2.3, are there any 143171440Srrs * destinations that had a fast retransmit 144171440Srrs * to them. If so what we need to do is 145171440Srrs * adjust ssthresh and cwnd. 146171440Srrs */ 147171440Srrs struct sctp_tmit_chunk *lchk; 148171440Srrs int old_cwnd = net->cwnd; 149171440Srrs 150221460Stuexen if ((asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) || 151221460Stuexen (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2)) { 152221460Stuexen if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) { 153310773Stuexen net->ssthresh = (uint32_t)(((uint64_t)4 * 154310773Stuexen (uint64_t)net->mtu * 155310773Stuexen (uint64_t)net->ssthresh) / 156310773Stuexen (uint64_t)t_ssthresh); 157221460Stuexen 158221460Stuexen } 159221460Stuexen if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2) { 160221460Stuexen uint32_t srtt; 161221460Stuexen 162221460Stuexen srtt = net->lastsa; 163310773Stuexen /* 164310773Stuexen * lastsa>>3; we don't need 165310773Stuexen * to devide ... 166310773Stuexen */ 167221460Stuexen if (srtt == 0) { 168221460Stuexen srtt = 1; 169221460Stuexen } 170310773Stuexen /* 171310773Stuexen * Short Version => Equal to 172310773Stuexen * Contel Version MBe 173310773Stuexen */ 174310773Stuexen net->ssthresh = (uint32_t)(((uint64_t)4 * 175310773Stuexen (uint64_t)net->mtu * 176310773Stuexen (uint64_t)net->cwnd) / 177310773Stuexen ((uint64_t)srtt * 178221460Stuexen t_ucwnd_sbw)); 179221460Stuexen /* INCREASE FACTOR */ ; 180221460Stuexen } 181217469Stuexen if ((net->cwnd > t_cwnd / 2) && 182217469Stuexen (net->ssthresh < net->cwnd - t_cwnd / 2)) { 183217469Stuexen net->ssthresh = net->cwnd - t_cwnd / 2; 184217469Stuexen } 185217469Stuexen if (net->ssthresh < net->mtu) { 186217469Stuexen net->ssthresh = net->mtu; 187217469Stuexen } 188217469Stuexen } else { 189217469Stuexen net->ssthresh = net->cwnd / 2; 190217469Stuexen if (net->ssthresh < (net->mtu * 2)) { 191217469Stuexen net->ssthresh = 2 * net->mtu; 192217469Stuexen } 193171440Srrs } 194171440Srrs net->cwnd = net->ssthresh; 195279859Stuexen sctp_enforce_cwnd_limit(asoc, net); 196292384Smarkj SDT_PROBE5(sctp, cwnd, net, fr, 197215817Srrs stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, 198215817Srrs old_cwnd, net->cwnd); 199179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 200171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 201171440Srrs SCTP_CWND_LOG_FROM_FR); 202171440Srrs } 203171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 204171440Srrs 205171440Srrs net->partial_bytes_acked = 0; 206171440Srrs /* Turn on fast recovery window */ 207171440Srrs asoc->fast_retran_loss_recovery = 1; 208171440Srrs if (lchk == NULL) { 209171440Srrs /* Mark end of the window */ 210171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 211171440Srrs } else { 212310219Stuexen asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1; 213171440Srrs } 214171440Srrs 215171440Srrs /* 216171440Srrs * CMT fast recovery -- per destination 217171440Srrs * recovery variable. 218171440Srrs */ 219171440Srrs net->fast_retran_loss_recovery = 1; 220171440Srrs 221171440Srrs if (lchk == NULL) { 222171440Srrs /* Mark end of the window */ 223171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 224171440Srrs } else { 225310219Stuexen net->fast_recovery_tsn = lchk->rec.data.tsn - 1; 226171440Srrs } 227171440Srrs 228171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 229283650Stuexen stcb->sctp_ep, stcb, net, 230283650Stuexen SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_1); 231171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 232171440Srrs stcb->sctp_ep, stcb, net); 233171440Srrs } 234171440Srrs } else if (net->net_ack > 0) { 235171440Srrs /* 236171440Srrs * Mark a peg that we WOULD have done a cwnd 237171440Srrs * reduction but RFC2582 prevented this action. 238171440Srrs */ 239171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 240171440Srrs } 241171440Srrs } 242171440Srrs} 243171440Srrs 244219397Srrs/* Defines for instantaneous bw decisions */ 245298942Spfg#define SCTP_INST_LOOSING 1 /* Losing to other flows */ 246219397Srrs#define SCTP_INST_NEUTRAL 2 /* Neutral, no indication */ 247219397Srrs#define SCTP_INST_GAINING 3 /* Gaining, step down possible */ 248219120Srrs 249219397Srrs 250219397Srrsstatic int 251219397Srrscc_bw_same(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, 252219397Srrs uint64_t rtt_offset, uint64_t vtag, uint8_t inst_ind) 253219397Srrs{ 254219397Srrs uint64_t oth, probepoint; 255219397Srrs 256310773Stuexen probepoint = (((uint64_t)net->cwnd) << 32); 257219397Srrs if (net->rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) { 258219397Srrs /* 259219397Srrs * rtt increased we don't update bw.. so we don't update the 260219397Srrs * rtt either. 261219397Srrs */ 262219397Srrs /* Probe point 5 */ 263219397Srrs probepoint |= ((5 << 16) | 1); 264292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 265219397Srrs vtag, 266219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 267219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 268219397Srrs net->flight_size, 269219397Srrs probepoint); 270219397Srrs if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) { 271219397Srrs if (net->cc_mod.rtcc.last_step_state == 5) 272219397Srrs net->cc_mod.rtcc.step_cnt++; 273219397Srrs else 274219397Srrs net->cc_mod.rtcc.step_cnt = 1; 275219397Srrs net->cc_mod.rtcc.last_step_state = 5; 276219397Srrs if ((net->cc_mod.rtcc.step_cnt == net->cc_mod.rtcc.steady_step) || 277219397Srrs ((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) == 0))) { 279219397Srrs /* Try a step down */ 280219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 281219397Srrs oth <<= 16; 282219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 283219397Srrs oth <<= 16; 284219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 285292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttstep, 286219397Srrs vtag, 287219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 288219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 289219397Srrs oth, 290219397Srrs probepoint); 291219397Srrs if (net->cwnd > (4 * net->mtu)) { 292219397Srrs net->cwnd -= net->mtu; 293219397Srrs net->cc_mod.rtcc.vol_reduce++; 294219397Srrs } else { 295219397Srrs net->cc_mod.rtcc.step_cnt = 0; 296219397Srrs } 297219397Srrs } 298219397Srrs } 299219397Srrs return (1); 300219397Srrs } 301219397Srrs if (net->rtt < net->cc_mod.rtcc.lbw_rtt - rtt_offset) { 302219397Srrs /* 303219397Srrs * rtt decreased, there could be more room. we update both 304219397Srrs * the bw and the rtt here to lock this in as a good step 305219397Srrs * down. 306219397Srrs */ 307219397Srrs /* Probe point 6 */ 308219397Srrs probepoint |= ((6 << 16) | 0); 309292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 310219397Srrs vtag, 311219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 312219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 313219397Srrs net->flight_size, 314219397Srrs probepoint); 315219397Srrs if (net->cc_mod.rtcc.steady_step) { 316219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 317219397Srrs oth <<= 16; 318219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 319219397Srrs oth <<= 16; 320219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 321292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttstep, 322219397Srrs vtag, 323219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 324219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 325219397Srrs oth, 326219397Srrs probepoint); 327219397Srrs if ((net->cc_mod.rtcc.last_step_state == 5) && 328219397Srrs (net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step)) { 329219397Srrs /* Step down worked */ 330219397Srrs net->cc_mod.rtcc.step_cnt = 0; 331219397Srrs return (1); 332219397Srrs } else { 333219397Srrs net->cc_mod.rtcc.last_step_state = 6; 334219397Srrs net->cc_mod.rtcc.step_cnt = 0; 335219397Srrs } 336219397Srrs } 337219397Srrs net->cc_mod.rtcc.lbw = nbw; 338219397Srrs net->cc_mod.rtcc.lbw_rtt = net->rtt; 339219397Srrs net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd; 340219397Srrs if (inst_ind == SCTP_INST_GAINING) 341219397Srrs return (1); 342219397Srrs else if (inst_ind == SCTP_INST_NEUTRAL) 343219397Srrs return (1); 344219397Srrs else 345219397Srrs return (0); 346219397Srrs } 347219397Srrs /* 348219397Srrs * Ok bw and rtt remained the same .. no update to any 349219397Srrs */ 350219397Srrs /* Probe point 7 */ 351219397Srrs probepoint |= ((7 << 16) | net->cc_mod.rtcc.ret_from_eq); 352292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 353219397Srrs vtag, 354219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 355219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 356219397Srrs net->flight_size, 357219397Srrs probepoint); 358219397Srrs if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) { 359219397Srrs if (net->cc_mod.rtcc.last_step_state == 5) 360219397Srrs net->cc_mod.rtcc.step_cnt++; 361219397Srrs else 362219397Srrs net->cc_mod.rtcc.step_cnt = 1; 363219397Srrs net->cc_mod.rtcc.last_step_state = 5; 364219397Srrs if ((net->cc_mod.rtcc.step_cnt == net->cc_mod.rtcc.steady_step) || 365219397Srrs ((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) == 0))) { 367219397Srrs /* Try a step down */ 368219397Srrs if (net->cwnd > (4 * net->mtu)) { 369219397Srrs net->cwnd -= net->mtu; 370219397Srrs net->cc_mod.rtcc.vol_reduce++; 371219397Srrs return (1); 372219397Srrs } else { 373219397Srrs net->cc_mod.rtcc.step_cnt = 0; 374219397Srrs } 375219397Srrs } 376219397Srrs } 377219397Srrs if (inst_ind == SCTP_INST_GAINING) 378219397Srrs return (1); 379219397Srrs else if (inst_ind == SCTP_INST_NEUTRAL) 380219397Srrs return (1); 381219397Srrs else 382219397Srrs return ((int)net->cc_mod.rtcc.ret_from_eq); 383219397Srrs} 384219397Srrs 385219397Srrsstatic int 386219397Srrscc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t rtt_offset, 387219397Srrs uint64_t vtag, uint8_t inst_ind) 388219397Srrs{ 389219397Srrs uint64_t oth, probepoint; 390219397Srrs 391219397Srrs /* Bandwidth decreased. */ 392310773Stuexen probepoint = (((uint64_t)net->cwnd) << 32); 393219397Srrs if (net->rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) { 394219397Srrs /* rtt increased */ 395219397Srrs /* Did we add more */ 396219397Srrs if ((net->cwnd > net->cc_mod.rtcc.cwnd_at_bw_set) && 397219397Srrs (inst_ind != SCTP_INST_LOOSING)) { 398219397Srrs /* We caused it maybe.. back off? */ 399219397Srrs /* PROBE POINT 1 */ 400219397Srrs probepoint |= ((1 << 16) | 1); 401292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 402219397Srrs vtag, 403219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 404219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 405219397Srrs net->flight_size, 406219397Srrs probepoint); 407219397Srrs if (net->cc_mod.rtcc.ret_from_eq) { 408310773Stuexen /* 409310773Stuexen * Switch over to CA if we are less 410310773Stuexen * aggressive 411310773Stuexen */ 412219397Srrs net->ssthresh = net->cwnd - 1; 413219397Srrs net->partial_bytes_acked = 0; 414219397Srrs } 415219397Srrs return (1); 416219397Srrs } 417219397Srrs /* Probe point 2 */ 418219397Srrs probepoint |= ((2 << 16) | 0); 419292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 420219397Srrs vtag, 421219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 422219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 423219397Srrs net->flight_size, 424219397Srrs probepoint); 425219397Srrs /* Someone else - fight for more? */ 426219397Srrs if (net->cc_mod.rtcc.steady_step) { 427219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 428219397Srrs oth <<= 16; 429219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 430219397Srrs oth <<= 16; 431219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 432292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttstep, 433219397Srrs vtag, 434219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 435219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 436219397Srrs oth, 437219397Srrs probepoint); 438219397Srrs /* 439219397Srrs * Did we voluntarily give up some? if so take one 440219397Srrs * back please 441219397Srrs */ 442219397Srrs if ((net->cc_mod.rtcc.vol_reduce) && 443219397Srrs (inst_ind != SCTP_INST_GAINING)) { 444219397Srrs net->cwnd += net->mtu; 445279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 446219397Srrs net->cc_mod.rtcc.vol_reduce--; 447219397Srrs } 448219397Srrs net->cc_mod.rtcc.last_step_state = 2; 449219397Srrs net->cc_mod.rtcc.step_cnt = 0; 450219397Srrs } 451219397Srrs goto out_decision; 452219397Srrs } else if (net->rtt < net->cc_mod.rtcc.lbw_rtt - rtt_offset) { 453219397Srrs /* bw & rtt decreased */ 454219397Srrs /* Probe point 3 */ 455219397Srrs probepoint |= ((3 << 16) | 0); 456292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 457219397Srrs vtag, 458219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 459219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 460219397Srrs net->flight_size, 461219397Srrs probepoint); 462219397Srrs if (net->cc_mod.rtcc.steady_step) { 463219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 464219397Srrs oth <<= 16; 465219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 466219397Srrs oth <<= 16; 467219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 468292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttstep, 469219397Srrs vtag, 470219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 471219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 472219397Srrs oth, 473219397Srrs probepoint); 474219397Srrs if ((net->cc_mod.rtcc.vol_reduce) && 475219397Srrs (inst_ind != SCTP_INST_GAINING)) { 476219397Srrs net->cwnd += net->mtu; 477279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 478219397Srrs net->cc_mod.rtcc.vol_reduce--; 479219397Srrs } 480219397Srrs net->cc_mod.rtcc.last_step_state = 3; 481219397Srrs net->cc_mod.rtcc.step_cnt = 0; 482219397Srrs } 483219397Srrs goto out_decision; 484219397Srrs } 485219397Srrs /* The bw decreased but rtt stayed the same */ 486219397Srrs /* Probe point 4 */ 487219397Srrs probepoint |= ((4 << 16) | 0); 488292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 489219397Srrs vtag, 490219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 491219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 492219397Srrs net->flight_size, 493219397Srrs probepoint); 494219397Srrs if (net->cc_mod.rtcc.steady_step) { 495219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 496219397Srrs oth <<= 16; 497219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 498219397Srrs oth <<= 16; 499219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 500292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttstep, 501219397Srrs vtag, 502219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 503219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 504219397Srrs oth, 505219397Srrs probepoint); 506219397Srrs if ((net->cc_mod.rtcc.vol_reduce) && 507219397Srrs (inst_ind != SCTP_INST_GAINING)) { 508219397Srrs net->cwnd += net->mtu; 509279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 510219397Srrs net->cc_mod.rtcc.vol_reduce--; 511219397Srrs } 512219397Srrs net->cc_mod.rtcc.last_step_state = 4; 513219397Srrs net->cc_mod.rtcc.step_cnt = 0; 514219397Srrs } 515219397Srrsout_decision: 516219397Srrs net->cc_mod.rtcc.lbw = nbw; 517219397Srrs net->cc_mod.rtcc.lbw_rtt = net->rtt; 518219397Srrs net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd; 519219397Srrs if (inst_ind == SCTP_INST_GAINING) { 520219397Srrs return (1); 521219397Srrs } else { 522219397Srrs return (0); 523219397Srrs } 524219397Srrs} 525219397Srrs 526219397Srrsstatic int 527228653Stuexencc_bw_increase(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t vtag) 528219397Srrs{ 529219397Srrs uint64_t oth, probepoint; 530219397Srrs 531219397Srrs /* 532219397Srrs * BW increased, so update and return 0, since all actions in our 533219397Srrs * table say to do the normal CC update. Note that we pay no 534219397Srrs * attention to the inst_ind since our overall sum is increasing. 535219397Srrs */ 536219397Srrs /* PROBE POINT 0 */ 537310773Stuexen probepoint = (((uint64_t)net->cwnd) << 32); 538292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 539219397Srrs vtag, 540219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 541219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 542219397Srrs net->flight_size, 543219397Srrs probepoint); 544219397Srrs if (net->cc_mod.rtcc.steady_step) { 545219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 546219397Srrs oth <<= 16; 547219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 548219397Srrs oth <<= 16; 549219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 550292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttstep, 551219397Srrs vtag, 552219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 553219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 554219397Srrs oth, 555219397Srrs probepoint); 556219397Srrs net->cc_mod.rtcc.last_step_state = 0; 557219397Srrs net->cc_mod.rtcc.step_cnt = 0; 558219397Srrs net->cc_mod.rtcc.vol_reduce = 0; 559219397Srrs } 560219397Srrs net->cc_mod.rtcc.lbw = nbw; 561219397Srrs net->cc_mod.rtcc.lbw_rtt = net->rtt; 562219397Srrs net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd; 563219397Srrs return (0); 564219397Srrs} 565219397Srrs 566298942Spfg/* RTCC Algorithm to limit growth of cwnd, return 567219120Srrs * true if you want to NOT allow cwnd growth 568219120Srrs */ 569219120Srrsstatic int 570219120Srrscc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw) 571219120Srrs{ 572228907Stuexen uint64_t bw_offset, rtt_offset; 573228907Stuexen uint64_t probepoint, rtt, vtag; 574219397Srrs uint64_t bytes_for_this_rtt, inst_bw; 575219397Srrs uint64_t div, inst_off; 576219397Srrs int bw_shift; 577219397Srrs uint8_t inst_ind; 578219397Srrs int ret; 579219120Srrs 580219120Srrs /*- 581219120Srrs * Here we need to see if we want 582219120Srrs * to limit cwnd growth due to increase 583219120Srrs * in overall rtt but no increase in bw. 584219120Srrs * We use the following table to figure 585219120Srrs * out what we should do. When we return 586219120Srrs * 0, cc update goes on as planned. If we 587219120Srrs * return 1, then no cc update happens and cwnd 588219120Srrs * stays where it is at. 589219120Srrs * ---------------------------------- 590219120Srrs * BW | RTT | Action 591219120Srrs * ********************************* 592219120Srrs * INC | INC | return 0 593219120Srrs * ---------------------------------- 594219120Srrs * INC | SAME | return 0 595219120Srrs * ---------------------------------- 596219120Srrs * INC | DECR | return 0 597219120Srrs * ---------------------------------- 598219120Srrs * SAME | INC | return 1 599219120Srrs * ---------------------------------- 600219120Srrs * SAME | SAME | return 1 601219120Srrs * ---------------------------------- 602219120Srrs * SAME | DECR | return 0 603219120Srrs * ---------------------------------- 604219120Srrs * DECR | INC | return 0 or 1 based on if we caused. 605219120Srrs * ---------------------------------- 606219120Srrs * DECR | SAME | return 0 607219120Srrs * ---------------------------------- 608219120Srrs * DECR | DECR | return 0 609219120Srrs * ---------------------------------- 610219120Srrs * 611219120Srrs * We are a bit fuzz on what an increase or 612219120Srrs * decrease is. For BW it is the same if 613219120Srrs * it did not change within 1/64th. For 614219120Srrs * RTT it stayed the same if it did not 615219120Srrs * change within 1/32nd 616219120Srrs */ 617219397Srrs bw_shift = SCTP_BASE_SYSCTL(sctp_rttvar_bw); 618219120Srrs rtt = stcb->asoc.my_vtag; 619310773Stuexen vtag = (rtt << 32) | (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | (stcb->rport); 620310773Stuexen probepoint = (((uint64_t)net->cwnd) << 32); 621219120Srrs rtt = net->rtt; 622219397Srrs if (net->cc_mod.rtcc.rtt_set_this_sack) { 623219397Srrs net->cc_mod.rtcc.rtt_set_this_sack = 0; 624219397Srrs bytes_for_this_rtt = net->cc_mod.rtcc.bw_bytes - net->cc_mod.rtcc.bw_bytes_at_last_rttc; 625219397Srrs net->cc_mod.rtcc.bw_bytes_at_last_rttc = net->cc_mod.rtcc.bw_bytes; 626219397Srrs if (net->rtt) { 627219397Srrs div = net->rtt / 1000; 628219397Srrs if (div) { 629219397Srrs inst_bw = bytes_for_this_rtt / div; 630219397Srrs inst_off = inst_bw >> bw_shift; 631219397Srrs if (inst_bw > nbw) 632219397Srrs inst_ind = SCTP_INST_GAINING; 633219397Srrs else if ((inst_bw + inst_off) < nbw) 634219397Srrs inst_ind = SCTP_INST_LOOSING; 635219397Srrs else 636219397Srrs inst_ind = SCTP_INST_NEUTRAL; 637219397Srrs probepoint |= ((0xb << 16) | inst_ind); 638219397Srrs } else { 639228907Stuexen inst_ind = net->cc_mod.rtcc.last_inst_ind; 640310773Stuexen inst_bw = bytes_for_this_rtt / (uint64_t)(net->rtt); 641219397Srrs /* Can't determine do not change */ 642219397Srrs probepoint |= ((0xc << 16) | inst_ind); 643219397Srrs } 644219397Srrs } else { 645228907Stuexen inst_ind = net->cc_mod.rtcc.last_inst_ind; 646219397Srrs inst_bw = bytes_for_this_rtt; 647219397Srrs /* Can't determine do not change */ 648219397Srrs probepoint |= ((0xd << 16) | inst_ind); 649219397Srrs } 650292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 651219120Srrs vtag, 652219397Srrs ((nbw << 32) | inst_bw), 653219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | rtt), 654219397Srrs net->flight_size, 655219120Srrs probepoint); 656219397Srrs } else { 657219397Srrs /* No rtt measurement, use last one */ 658219397Srrs inst_ind = net->cc_mod.rtcc.last_inst_ind; 659219120Srrs } 660219397Srrs bw_offset = net->cc_mod.rtcc.lbw >> bw_shift; 661219397Srrs if (nbw > net->cc_mod.rtcc.lbw + bw_offset) { 662228653Stuexen ret = cc_bw_increase(stcb, net, nbw, vtag); 663219397Srrs goto out; 664219397Srrs } 665219120Srrs rtt_offset = net->cc_mod.rtcc.lbw_rtt >> SCTP_BASE_SYSCTL(sctp_rttvar_rtt); 666219120Srrs if (nbw < net->cc_mod.rtcc.lbw - bw_offset) { 667219397Srrs ret = cc_bw_decrease(stcb, net, nbw, rtt_offset, vtag, inst_ind); 668219397Srrs goto out; 669219120Srrs } 670219120Srrs /* 671219120Srrs * If we reach here then we are in a situation where the bw stayed 672219120Srrs * the same. 673219120Srrs */ 674219397Srrs ret = cc_bw_same(stcb, net, nbw, rtt_offset, vtag, inst_ind); 675219397Srrsout: 676219397Srrs net->cc_mod.rtcc.last_inst_ind = inst_ind; 677219397Srrs return (ret); 678219120Srrs} 679219120Srrs 680217611Stuexenstatic void 681219120Srrssctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, 682171440Srrs struct sctp_association *asoc, 683228653Stuexen int accum_moved, int reneged_all SCTP_UNUSED, int will_exit, int use_rtcc) 684171440Srrs{ 685171440Srrs struct sctp_nets *net; 686215817Srrs int old_cwnd; 687217469Stuexen uint32_t t_ssthresh, t_cwnd, incr; 688221460Stuexen uint64_t t_ucwnd_sbw; 689221460Stuexen uint64_t t_path_mptcp; 690221460Stuexen uint64_t mptcp_like_alpha; 691221460Stuexen uint32_t srtt; 692221460Stuexen uint64_t max_path; 693171440Srrs 694217469Stuexen /* MT FIXME: Don't compute this over and over again */ 695217469Stuexen t_ssthresh = 0; 696217469Stuexen t_cwnd = 0; 697221460Stuexen t_ucwnd_sbw = 0; 698221460Stuexen t_path_mptcp = 0; 699221460Stuexen mptcp_like_alpha = 1; 700221460Stuexen if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) || 701221460Stuexen (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2) || 702221460Stuexen (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_MPTCP)) { 703221460Stuexen max_path = 0; 704217469Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 705217469Stuexen t_ssthresh += net->ssthresh; 706217469Stuexen t_cwnd += net->cwnd; 707221460Stuexen /* lastsa>>3; we don't need to devide ... */ 708221460Stuexen srtt = net->lastsa; 709221460Stuexen if (srtt > 0) { 710221460Stuexen uint64_t tmp; 711221460Stuexen 712310773Stuexen t_ucwnd_sbw += (uint64_t)net->cwnd / (uint64_t)srtt; 713310773Stuexen t_path_mptcp += (((uint64_t)net->cwnd) << SHIFT_MPTCP_MULTI_Z) / 714310773Stuexen (((uint64_t)net->mtu) * (uint64_t)srtt); 715310773Stuexen tmp = (((uint64_t)net->cwnd) << SHIFT_MPTCP_MULTI_N) / 716310773Stuexen ((uint64_t)net->mtu * (uint64_t)(srtt * srtt)); 717221460Stuexen if (tmp > max_path) { 718221460Stuexen max_path = tmp; 719221460Stuexen } 720221460Stuexen } 721217469Stuexen } 722221460Stuexen if (t_path_mptcp > 0) { 723221460Stuexen mptcp_like_alpha = max_path / (t_path_mptcp * t_path_mptcp); 724221460Stuexen } else { 725221460Stuexen mptcp_like_alpha = 1; 726221460Stuexen } 727217469Stuexen } 728228907Stuexen if (t_ssthresh == 0) { 729228907Stuexen t_ssthresh = 1; 730228907Stuexen } 731228907Stuexen if (t_ucwnd_sbw == 0) { 732228907Stuexen t_ucwnd_sbw = 1; 733228907Stuexen } 734171440Srrs /******************************/ 735171440Srrs /* update cwnd and Early FR */ 736171440Srrs /******************************/ 737171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 738171440Srrs 739171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 740171440Srrs /* 741171440Srrs * CMT fast recovery code. Need to debug. 742171440Srrs */ 743171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 744217469Stuexen if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) || 745217469Stuexen SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) { 746171440Srrs net->will_exit_fast_recovery = 1; 747171440Srrs } 748171440Srrs } 749171440Srrs#endif 750171440Srrs /* if nothing was acked on this destination skip it */ 751171440Srrs if (net->net_ack == 0) { 752179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 753171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 754171440Srrs } 755171440Srrs continue; 756171440Srrs } 757171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 758171440Srrs /* 759171440Srrs * CMT fast recovery code 760171440Srrs */ 761171440Srrs /* 762216669Stuexen * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery 763216669Stuexen * && net->will_exit_fast_recovery == 0) { @@@ Do something 764216669Stuexen * } else if (sctp_cmt_on_off == 0 && 765171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 766171440Srrs */ 767171440Srrs#endif 768171440Srrs 769211944Stuexen if (asoc->fast_retran_loss_recovery && 770211944Stuexen (will_exit == 0) && 771211944Stuexen (asoc->sctp_cmt_on_off == 0)) { 772171440Srrs /* 773171440Srrs * If we are in loss recovery we skip any cwnd 774171440Srrs * update 775171440Srrs */ 776224641Stuexen return; 777171440Srrs } 778171440Srrs /* 779219120Srrs * Did any measurements go on for this network? 780219120Srrs */ 781219120Srrs if (use_rtcc && (net->cc_mod.rtcc.tls_needs_set > 0)) { 782219120Srrs uint64_t nbw; 783219120Srrs 784219120Srrs /* 785219120Srrs * At this point our bw_bytes has been updated by 786219120Srrs * incoming sack information. 787310218Stuexen * 788219120Srrs * But our bw may not yet be set. 789310218Stuexen * 790219120Srrs */ 791219120Srrs if ((net->cc_mod.rtcc.new_tot_time / 1000) > 0) { 792219120Srrs nbw = net->cc_mod.rtcc.bw_bytes / (net->cc_mod.rtcc.new_tot_time / 1000); 793219120Srrs } else { 794219120Srrs nbw = net->cc_mod.rtcc.bw_bytes; 795219120Srrs } 796219120Srrs if (net->cc_mod.rtcc.lbw) { 797219120Srrs if (cc_bw_limit(stcb, net, nbw)) { 798219120Srrs /* Hold here, no update */ 799224641Stuexen continue; 800219120Srrs } 801219120Srrs } else { 802219120Srrs uint64_t vtag, probepoint; 803219120Srrs 804310773Stuexen probepoint = (((uint64_t)net->cwnd) << 32); 805219120Srrs probepoint |= ((0xa << 16) | 0); 806219120Srrs vtag = (net->rtt << 32) | 807310773Stuexen (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | 808219120Srrs (stcb->rport); 809219120Srrs 810292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 811219120Srrs vtag, 812219120Srrs nbw, 813219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 814219397Srrs net->flight_size, 815219120Srrs probepoint); 816219120Srrs net->cc_mod.rtcc.lbw = nbw; 817219120Srrs net->cc_mod.rtcc.lbw_rtt = net->rtt; 818219397Srrs if (net->cc_mod.rtcc.rtt_set_this_sack) { 819219397Srrs net->cc_mod.rtcc.rtt_set_this_sack = 0; 820219397Srrs net->cc_mod.rtcc.bw_bytes_at_last_rttc = net->cc_mod.rtcc.bw_bytes; 821219397Srrs } 822219120Srrs } 823219120Srrs } 824219120Srrs /* 825171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 826171440Srrs * moved. 827171440Srrs */ 828211944Stuexen if (accum_moved || 829216669Stuexen ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) { 830171440Srrs /* If the cumulative ack moved we can proceed */ 831171440Srrs if (net->cwnd <= net->ssthresh) { 832171440Srrs /* We are in slow start */ 833179157Srrs if (net->flight_size + net->net_ack >= net->cwnd) { 834221460Stuexen uint32_t limit; 835221460Stuexen 836217469Stuexen old_cwnd = net->cwnd; 837221460Stuexen switch (asoc->sctp_cmt_on_off) { 838221460Stuexen case SCTP_CMT_RPV1: 839310773Stuexen limit = (uint32_t)(((uint64_t)net->mtu * 840310773Stuexen (uint64_t)SCTP_BASE_SYSCTL(sctp_L2_abc_variable) * 841310773Stuexen (uint64_t)net->ssthresh) / 842310773Stuexen (uint64_t)t_ssthresh); 843310773Stuexen incr = (uint32_t)(((uint64_t)net->net_ack * 844310773Stuexen (uint64_t)net->ssthresh) / 845310773Stuexen (uint64_t)t_ssthresh); 846217469Stuexen if (incr > limit) { 847217469Stuexen incr = limit; 848171440Srrs } 849217469Stuexen if (incr == 0) { 850217469Stuexen incr = 1; 851217469Stuexen } 852221460Stuexen break; 853221460Stuexen case SCTP_CMT_RPV2: 854310773Stuexen /* 855310773Stuexen * lastsa>>3; we don't need 856310773Stuexen * to divide ... 857310773Stuexen */ 858221460Stuexen srtt = net->lastsa; 859221460Stuexen if (srtt == 0) { 860221460Stuexen srtt = 1; 861221460Stuexen } 862310773Stuexen limit = (uint32_t)(((uint64_t)net->mtu * 863310773Stuexen (uint64_t)SCTP_BASE_SYSCTL(sctp_L2_abc_variable) * 864310773Stuexen (uint64_t)net->cwnd) / 865310773Stuexen ((uint64_t)srtt * t_ucwnd_sbw)); 866221460Stuexen /* INCREASE FACTOR */ 867310773Stuexen incr = (uint32_t)(((uint64_t)net->net_ack * 868310773Stuexen (uint64_t)net->cwnd) / 869310773Stuexen ((uint64_t)srtt * t_ucwnd_sbw)); 870221460Stuexen /* INCREASE FACTOR */ 871221460Stuexen if (incr > limit) { 872221460Stuexen incr = limit; 873221460Stuexen } 874221460Stuexen if (incr == 0) { 875221460Stuexen incr = 1; 876221460Stuexen } 877221460Stuexen break; 878221460Stuexen case SCTP_CMT_MPTCP: 879310773Stuexen limit = (uint32_t)(((uint64_t)net->mtu * 880221460Stuexen mptcp_like_alpha * 881310773Stuexen (uint64_t)SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) >> 882221460Stuexen SHIFT_MPTCP_MULTI); 883310773Stuexen incr = (uint32_t)(((uint64_t)net->net_ack * 884221460Stuexen mptcp_like_alpha) >> 885221460Stuexen SHIFT_MPTCP_MULTI); 886221460Stuexen if (incr > limit) { 887221460Stuexen incr = limit; 888221460Stuexen } 889221460Stuexen if (incr > net->net_ack) { 890221460Stuexen incr = net->net_ack; 891221460Stuexen } 892221460Stuexen if (incr > net->mtu) { 893221460Stuexen incr = net->mtu; 894221460Stuexen } 895221460Stuexen break; 896221460Stuexen default: 897217469Stuexen incr = net->net_ack; 898217469Stuexen if (incr > net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) { 899217469Stuexen incr = net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable); 900171440Srrs } 901221460Stuexen break; 902171440Srrs } 903217469Stuexen net->cwnd += incr; 904279859Stuexen sctp_enforce_cwnd_limit(asoc, net); 905217469Stuexen if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 906217469Stuexen sctp_log_cwnd(stcb, net, incr, 907217469Stuexen SCTP_CWND_LOG_FROM_SS); 908217469Stuexen } 909292384Smarkj SDT_PROBE5(sctp, cwnd, net, ack, 910217469Stuexen stcb->asoc.my_vtag, 911217469Stuexen ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 912217469Stuexen net, 913217469Stuexen old_cwnd, net->cwnd); 914171440Srrs } else { 915179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 916171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 917171440Srrs SCTP_CWND_LOG_NOADV_SS); 918171440Srrs } 919171440Srrs } 920171440Srrs } else { 921171440Srrs /* We are in congestion avoidance */ 922179141Srrs /* 923179141Srrs * Add to pba 924179141Srrs */ 925179157Srrs net->partial_bytes_acked += net->net_ack; 926171440Srrs 927179141Srrs if ((net->flight_size + net->net_ack >= net->cwnd) && 928179141Srrs (net->partial_bytes_acked >= net->cwnd)) { 929179141Srrs net->partial_bytes_acked -= net->cwnd; 930215817Srrs old_cwnd = net->cwnd; 931221460Stuexen switch (asoc->sctp_cmt_on_off) { 932221460Stuexen case SCTP_CMT_RPV1: 933310773Stuexen incr = (uint32_t)(((uint64_t)net->mtu * 934310773Stuexen (uint64_t)net->ssthresh) / 935310773Stuexen (uint64_t)t_ssthresh); 936217469Stuexen if (incr == 0) { 937217469Stuexen incr = 1; 938217469Stuexen } 939221460Stuexen break; 940221460Stuexen case SCTP_CMT_RPV2: 941310773Stuexen /* 942310773Stuexen * lastsa>>3; we don't need 943310773Stuexen * to divide ... 944310773Stuexen */ 945221460Stuexen srtt = net->lastsa; 946221460Stuexen if (srtt == 0) { 947221460Stuexen srtt = 1; 948221460Stuexen } 949310773Stuexen incr = (uint32_t)((uint64_t)net->mtu * 950310773Stuexen (uint64_t)net->cwnd / 951310773Stuexen ((uint64_t)srtt * 952221460Stuexen t_ucwnd_sbw)); 953221460Stuexen /* INCREASE FACTOR */ 954221460Stuexen if (incr == 0) { 955221460Stuexen incr = 1; 956221460Stuexen } 957221460Stuexen break; 958221460Stuexen case SCTP_CMT_MPTCP: 959310773Stuexen incr = (uint32_t)((mptcp_like_alpha * 960310773Stuexen (uint64_t)net->cwnd) >> 961221460Stuexen SHIFT_MPTCP_MULTI); 962221460Stuexen if (incr > net->mtu) { 963221460Stuexen incr = net->mtu; 964221460Stuexen } 965221460Stuexen break; 966221460Stuexen default: 967217469Stuexen incr = net->mtu; 968221460Stuexen break; 969217469Stuexen } 970217469Stuexen net->cwnd += incr; 971279859Stuexen sctp_enforce_cwnd_limit(asoc, net); 972292384Smarkj SDT_PROBE5(sctp, cwnd, net, ack, 973215817Srrs stcb->asoc.my_vtag, 974215817Srrs ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 975215817Srrs net, 976215817Srrs old_cwnd, net->cwnd); 977179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 978179141Srrs sctp_log_cwnd(stcb, net, net->mtu, 979179141Srrs SCTP_CWND_LOG_FROM_CA); 980171440Srrs } 981171440Srrs } else { 982179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 983171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 984171440Srrs SCTP_CWND_LOG_NOADV_CA); 985171440Srrs } 986171440Srrs } 987171440Srrs } 988171440Srrs } else { 989179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 990171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 991171440Srrs SCTP_CWND_LOG_NO_CUMACK); 992171440Srrs } 993171440Srrs } 994171440Srrs } 995171440Srrs} 996171440Srrs 997217611Stuexenstatic void 998224641Stuexensctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb, struct sctp_nets *net) 999224641Stuexen{ 1000224641Stuexen int old_cwnd; 1001224641Stuexen 1002224641Stuexen old_cwnd = net->cwnd; 1003224641Stuexen net->cwnd = net->mtu; 1004292384Smarkj SDT_PROBE5(sctp, cwnd, net, ack, 1005224641Stuexen stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, 1006224641Stuexen old_cwnd, net->cwnd); 1007224641Stuexen SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", 1008240148Stuexen (void *)net, net->cwnd); 1009224641Stuexen} 1010224641Stuexen 1011224641Stuexen 1012224641Stuexenstatic void 1013179157Srrssctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net) 1014171440Srrs{ 1015171440Srrs int old_cwnd = net->cwnd; 1016217469Stuexen uint32_t t_ssthresh, t_cwnd; 1017221460Stuexen uint64_t t_ucwnd_sbw; 1018171440Srrs 1019217469Stuexen /* MT FIXME: Don't compute this over and over again */ 1020217469Stuexen t_ssthresh = 0; 1021217469Stuexen t_cwnd = 0; 1022221460Stuexen if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) || 1023221460Stuexen (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2)) { 1024217469Stuexen struct sctp_nets *lnet; 1025221460Stuexen uint32_t srtt; 1026217469Stuexen 1027221460Stuexen t_ucwnd_sbw = 0; 1028217469Stuexen TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 1029217469Stuexen t_ssthresh += lnet->ssthresh; 1030217469Stuexen t_cwnd += lnet->cwnd; 1031221460Stuexen srtt = lnet->lastsa; 1032221460Stuexen /* lastsa>>3; we don't need to divide ... */ 1033221460Stuexen if (srtt > 0) { 1034310773Stuexen t_ucwnd_sbw += (uint64_t)lnet->cwnd / (uint64_t)srtt; 1035221460Stuexen } 1036217469Stuexen } 1037228907Stuexen if (t_ssthresh < 1) { 1038228907Stuexen t_ssthresh = 1; 1039228907Stuexen } 1040221460Stuexen if (t_ucwnd_sbw < 1) { 1041221460Stuexen t_ucwnd_sbw = 1; 1042221460Stuexen } 1043221460Stuexen if (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) { 1044310773Stuexen net->ssthresh = (uint32_t)(((uint64_t)4 * 1045310773Stuexen (uint64_t)net->mtu * 1046310773Stuexen (uint64_t)net->ssthresh) / 1047310773Stuexen (uint64_t)t_ssthresh); 1048221460Stuexen } else { 1049221460Stuexen uint64_t cc_delta; 1050221460Stuexen 1051221460Stuexen srtt = net->lastsa; 1052221460Stuexen /* lastsa>>3; we don't need to divide ... */ 1053221460Stuexen if (srtt == 0) { 1054221460Stuexen srtt = 1; 1055221460Stuexen } 1056310773Stuexen cc_delta = t_ucwnd_sbw * (uint64_t)srtt / 2; 1057221460Stuexen if (cc_delta < t_cwnd) { 1058310773Stuexen net->ssthresh = (uint32_t)((uint64_t)t_cwnd - cc_delta); 1059221460Stuexen } else { 1060221460Stuexen net->ssthresh = net->mtu; 1061221460Stuexen } 1062221460Stuexen } 1063217469Stuexen if ((net->cwnd > t_cwnd / 2) && 1064217469Stuexen (net->ssthresh < net->cwnd - t_cwnd / 2)) { 1065217469Stuexen net->ssthresh = net->cwnd - t_cwnd / 2; 1066217469Stuexen } 1067217469Stuexen if (net->ssthresh < net->mtu) { 1068217469Stuexen net->ssthresh = net->mtu; 1069217469Stuexen } 1070217469Stuexen } else { 1071217469Stuexen net->ssthresh = max(net->cwnd / 2, 4 * net->mtu); 1072217469Stuexen } 1073171440Srrs net->cwnd = net->mtu; 1074179157Srrs net->partial_bytes_acked = 0; 1075292384Smarkj SDT_PROBE5(sctp, cwnd, net, to, 1076215817Srrs stcb->asoc.my_vtag, 1077215817Srrs ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 1078215817Srrs net, 1079215817Srrs old_cwnd, net->cwnd); 1080179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1081171440Srrs sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 1082171440Srrs } 1083171440Srrs} 1084171440Srrs 1085217611Stuexenstatic void 1086219120Srrssctp_cwnd_update_after_ecn_echo_common(struct sctp_tcb *stcb, struct sctp_nets *net, 1087219120Srrs int in_window, int num_pkt_lost, int use_rtcc) 1088179157Srrs{ 1089179157Srrs int old_cwnd = net->cwnd; 1090179157Srrs 1091219120Srrs if ((use_rtcc) && (net->lan_type == SCTP_LAN_LOCAL) && (net->cc_mod.rtcc.use_dccc_ecn)) { 1092219120Srrs /* Data center Congestion Control */ 1093219120Srrs if (in_window == 0) { 1094219120Srrs /* 1095219120Srrs * Go to CA with the cwnd at the point we sent the 1096219120Srrs * TSN that was marked with a CE. 1097219120Srrs */ 1098219120Srrs if (net->ecn_prev_cwnd < net->cwnd) { 1099219120Srrs /* Restore to prev cwnd */ 1100219120Srrs net->cwnd = net->ecn_prev_cwnd - (net->mtu * num_pkt_lost); 1101219120Srrs } else { 1102219120Srrs /* Just cut in 1/2 */ 1103219120Srrs net->cwnd /= 2; 1104219120Srrs } 1105219120Srrs /* Drop to CA */ 1106219120Srrs net->ssthresh = net->cwnd - (num_pkt_lost * net->mtu); 1107219120Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1108219120Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 1109219120Srrs } 1110219120Srrs } else { 1111310773Stuexen /* 1112310773Stuexen * Further tuning down required over the drastic 1113310773Stuexen * original cut 1114310773Stuexen */ 1115219120Srrs net->ssthresh -= (net->mtu * num_pkt_lost); 1116219120Srrs net->cwnd -= (net->mtu * num_pkt_lost); 1117219120Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1118219120Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 1119219120Srrs } 1120219120Srrs } 1121218129Srrs SCTP_STAT_INCR(sctps_ecnereducedcwnd); 1122219120Srrs } else { 1123219120Srrs if (in_window == 0) { 1124219120Srrs SCTP_STAT_INCR(sctps_ecnereducedcwnd); 1125219120Srrs net->ssthresh = net->cwnd / 2; 1126219120Srrs if (net->ssthresh < net->mtu) { 1127219120Srrs net->ssthresh = net->mtu; 1128310773Stuexen /* 1129310773Stuexen * here back off the timer as well, to slow 1130310773Stuexen * us down 1131310773Stuexen */ 1132219120Srrs net->RTO <<= 1; 1133219120Srrs } 1134219120Srrs net->cwnd = net->ssthresh; 1135292384Smarkj SDT_PROBE5(sctp, cwnd, net, ecn, 1136219120Srrs stcb->asoc.my_vtag, 1137219120Srrs ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 1138219120Srrs net, 1139219120Srrs old_cwnd, net->cwnd); 1140219120Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1141219120Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 1142219120Srrs } 1143218129Srrs } 1144179157Srrs } 1145219120Srrs 1146179157Srrs} 1147179157Srrs 1148217611Stuexenstatic void 1149179157Srrssctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb, 1150179157Srrs struct sctp_nets *net, struct sctp_pktdrop_chunk *cp, 1151310773Stuexen uint32_t *bottle_bw, uint32_t *on_queue) 1152179157Srrs{ 1153179157Srrs uint32_t bw_avail; 1154218232Srrs unsigned int incr; 1155179157Srrs int old_cwnd = net->cwnd; 1156179157Srrs 1157179157Srrs /* get bottle neck bw */ 1158179157Srrs *bottle_bw = ntohl(cp->bottle_bw); 1159179157Srrs /* and whats on queue */ 1160179157Srrs *on_queue = ntohl(cp->current_onq); 1161179157Srrs /* 1162179157Srrs * adjust the on-queue if our flight is more it could be that the 1163179157Srrs * router has not yet gotten data "in-flight" to it 1164179157Srrs */ 1165271672Stuexen if (*on_queue < net->flight_size) { 1166179157Srrs *on_queue = net->flight_size; 1167271672Stuexen } 1168271672Stuexen /* rtt is measured in micro seconds, bottle_bw in bytes per second */ 1169310773Stuexen bw_avail = (uint32_t)(((uint64_t)(*bottle_bw) * net->rtt) / (uint64_t)1000000); 1170179157Srrs if (bw_avail > *bottle_bw) { 1171179157Srrs /* 1172179157Srrs * Cap the growth to no more than the bottle neck. This can 1173179157Srrs * happen as RTT slides up due to queues. It also means if 1174179157Srrs * you have more than a 1 second RTT with a empty queue you 1175179157Srrs * will be limited to the bottle_bw per second no matter if 1176179157Srrs * other points have 1/2 the RTT and you could get more 1177179157Srrs * out... 1178179157Srrs */ 1179179157Srrs bw_avail = *bottle_bw; 1180179157Srrs } 1181179157Srrs if (*on_queue > bw_avail) { 1182179157Srrs /* 1183179157Srrs * No room for anything else don't allow anything else to be 1184179157Srrs * "added to the fire". 1185179157Srrs */ 1186179157Srrs int seg_inflight, seg_onqueue, my_portion; 1187179157Srrs 1188179157Srrs net->partial_bytes_acked = 0; 1189179157Srrs /* how much are we over queue size? */ 1190179157Srrs incr = *on_queue - bw_avail; 1191179157Srrs if (stcb->asoc.seen_a_sack_this_pkt) { 1192179157Srrs /* 1193179157Srrs * undo any cwnd adjustment that the sack might have 1194179157Srrs * made 1195179157Srrs */ 1196179157Srrs net->cwnd = net->prev_cwnd; 1197179157Srrs } 1198179157Srrs /* Now how much of that is mine? */ 1199179157Srrs seg_inflight = net->flight_size / net->mtu; 1200179157Srrs seg_onqueue = *on_queue / net->mtu; 1201179157Srrs my_portion = (incr * seg_inflight) / seg_onqueue; 1202179157Srrs 1203179157Srrs /* Have I made an adjustment already */ 1204179157Srrs if (net->cwnd > net->flight_size) { 1205179157Srrs /* 1206179157Srrs * for this flight I made an adjustment we need to 1207179157Srrs * decrease the portion by a share our previous 1208179157Srrs * adjustment. 1209179157Srrs */ 1210179157Srrs int diff_adj; 1211179157Srrs 1212179157Srrs diff_adj = net->cwnd - net->flight_size; 1213179157Srrs if (diff_adj > my_portion) 1214179157Srrs my_portion = 0; 1215179157Srrs else 1216179157Srrs my_portion -= diff_adj; 1217179157Srrs } 1218179157Srrs /* 1219179157Srrs * back down to the previous cwnd (assume we have had a sack 1220179157Srrs * before this packet). minus what ever portion of the 1221179157Srrs * overage is my fault. 1222179157Srrs */ 1223179157Srrs net->cwnd -= my_portion; 1224179157Srrs 1225179157Srrs /* we will NOT back down more than 1 MTU */ 1226179157Srrs if (net->cwnd <= net->mtu) { 1227179157Srrs net->cwnd = net->mtu; 1228179157Srrs } 1229179157Srrs /* force into CA */ 1230179157Srrs net->ssthresh = net->cwnd - 1; 1231179157Srrs } else { 1232179157Srrs /* 1233179157Srrs * Take 1/4 of the space left or max burst up .. whichever 1234179157Srrs * is less. 1235179157Srrs */ 1236217894Stuexen incr = (bw_avail - *on_queue) >> 2; 1237217894Stuexen if ((stcb->asoc.max_burst > 0) && 1238217894Stuexen (stcb->asoc.max_burst * net->mtu < incr)) { 1239217894Stuexen incr = stcb->asoc.max_burst * net->mtu; 1240217894Stuexen } 1241179157Srrs net->cwnd += incr; 1242179157Srrs } 1243179157Srrs if (net->cwnd > bw_avail) { 1244179157Srrs /* We can't exceed the pipe size */ 1245179157Srrs net->cwnd = bw_avail; 1246179157Srrs } 1247179157Srrs if (net->cwnd < net->mtu) { 1248179157Srrs /* We always have 1 MTU */ 1249179157Srrs net->cwnd = net->mtu; 1250179157Srrs } 1251279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 1252179157Srrs if (net->cwnd - old_cwnd != 0) { 1253179157Srrs /* log only changes */ 1254292384Smarkj SDT_PROBE5(sctp, cwnd, net, pd, 1255215817Srrs stcb->asoc.my_vtag, 1256215817Srrs ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 1257215817Srrs net, 1258215817Srrs old_cwnd, net->cwnd); 1259179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1260179157Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 1261179157Srrs SCTP_CWND_LOG_FROM_SAT); 1262179157Srrs } 1263179157Srrs } 1264179157Srrs} 1265179157Srrs 1266217611Stuexenstatic void 1267179157Srrssctp_cwnd_update_after_output(struct sctp_tcb *stcb, 1268179157Srrs struct sctp_nets *net, int burst_limit) 1269179157Srrs{ 1270179157Srrs int old_cwnd = net->cwnd; 1271179157Srrs 1272179157Srrs if (net->ssthresh < net->cwnd) 1273179157Srrs net->ssthresh = net->cwnd; 1274219120Srrs if (burst_limit) { 1275219120Srrs net->cwnd = (net->flight_size + (burst_limit * net->mtu)); 1276279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 1277292384Smarkj SDT_PROBE5(sctp, cwnd, net, bl, 1278219120Srrs stcb->asoc.my_vtag, 1279219120Srrs ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 1280219120Srrs net, 1281219120Srrs old_cwnd, net->cwnd); 1282219120Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1283219120Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST); 1284219120Srrs } 1285179157Srrs } 1286179157Srrs} 1287179157Srrs 1288217611Stuexenstatic void 1289219120Srrssctp_cwnd_update_after_sack(struct sctp_tcb *stcb, 1290219120Srrs struct sctp_association *asoc, 1291219120Srrs int accum_moved, int reneged_all, int will_exit) 1292219120Srrs{ 1293298942Spfg /* Passing a zero argument in last disables the rtcc algorithm */ 1294219120Srrs sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 0); 1295219120Srrs} 1296219120Srrs 1297219120Srrsstatic void 1298219120Srrssctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, 1299219120Srrs int in_window, int num_pkt_lost) 1300219120Srrs{ 1301298942Spfg /* Passing a zero argument in last disables the rtcc algorithm */ 1302219120Srrs sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 0); 1303219120Srrs} 1304219120Srrs 1305219120Srrs/* Here starts the RTCCVAR type CC invented by RRS which 1306219120Srrs * is a slight mod to RFC2581. We reuse a common routine or 1307298942Spfg * two since these algorithms are so close and need to 1308219120Srrs * remain the same. 1309219120Srrs */ 1310219120Srrsstatic void 1311219120Srrssctp_cwnd_update_rtcc_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, 1312219120Srrs int in_window, int num_pkt_lost) 1313219120Srrs{ 1314219120Srrs sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 1); 1315219120Srrs} 1316219120Srrs 1317219120Srrs 1318219120Srrsstatic 1319219120Srrsvoid 1320219120Srrssctp_cwnd_update_rtcc_tsn_acknowledged(struct sctp_nets *net, 1321219120Srrs struct sctp_tmit_chunk *tp1) 1322219120Srrs{ 1323219120Srrs net->cc_mod.rtcc.bw_bytes += tp1->send_size; 1324219120Srrs} 1325219120Srrs 1326219120Srrsstatic void 1327228653Stuexensctp_cwnd_prepare_rtcc_net_for_sack(struct sctp_tcb *stcb SCTP_UNUSED, 1328219120Srrs struct sctp_nets *net) 1329219120Srrs{ 1330219120Srrs if (net->cc_mod.rtcc.tls_needs_set > 0) { 1331219120Srrs /* We had a bw measurment going on */ 1332219120Srrs struct timeval ltls; 1333219120Srrs 1334219120Srrs SCTP_GETPTIME_TIMEVAL(<ls); 1335219120Srrs timevalsub(<ls, &net->cc_mod.rtcc.tls); 1336219120Srrs net->cc_mod.rtcc.new_tot_time = (ltls.tv_sec * 1000000) + ltls.tv_usec; 1337219120Srrs } 1338219120Srrs} 1339219120Srrs 1340219120Srrsstatic void 1341219120Srrssctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb *stcb, 1342219120Srrs struct sctp_nets *net) 1343219120Srrs{ 1344219120Srrs uint64_t vtag, probepoint; 1345219120Srrs 1346219120Srrs if (net->cc_mod.rtcc.lbw) { 1347219120Srrs /* Clear the old bw.. we went to 0 in-flight */ 1348310773Stuexen vtag = (net->rtt << 32) | (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | 1349219120Srrs (stcb->rport); 1350310773Stuexen probepoint = (((uint64_t)net->cwnd) << 32); 1351219120Srrs /* Probe point 8 */ 1352219120Srrs probepoint |= ((8 << 16) | 0); 1353292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 1354219120Srrs vtag, 1355219120Srrs ((net->cc_mod.rtcc.lbw << 32) | 0), 1356219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 1357219397Srrs net->flight_size, 1358219120Srrs probepoint); 1359219120Srrs net->cc_mod.rtcc.lbw_rtt = 0; 1360219120Srrs net->cc_mod.rtcc.cwnd_at_bw_set = 0; 1361219120Srrs net->cc_mod.rtcc.lbw = 0; 1362219397Srrs net->cc_mod.rtcc.bw_bytes_at_last_rttc = 0; 1363219397Srrs net->cc_mod.rtcc.vol_reduce = 0; 1364219120Srrs net->cc_mod.rtcc.bw_tot_time = 0; 1365219120Srrs net->cc_mod.rtcc.bw_bytes = 0; 1366219120Srrs net->cc_mod.rtcc.tls_needs_set = 0; 1367219397Srrs if (net->cc_mod.rtcc.steady_step) { 1368219397Srrs net->cc_mod.rtcc.vol_reduce = 0; 1369219397Srrs net->cc_mod.rtcc.step_cnt = 0; 1370219397Srrs net->cc_mod.rtcc.last_step_state = 0; 1371219397Srrs } 1372219120Srrs if (net->cc_mod.rtcc.ret_from_eq) { 1373219120Srrs /* less aggressive one - reset cwnd too */ 1374219120Srrs uint32_t cwnd_in_mtu, cwnd; 1375219120Srrs 1376219120Srrs cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd); 1377219120Srrs if (cwnd_in_mtu == 0) { 1378310773Stuexen /* 1379310773Stuexen * Using 0 means that the value of RFC 4960 1380310773Stuexen * is used. 1381310773Stuexen */ 1382219120Srrs cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 1383219120Srrs } else { 1384219120Srrs /* 1385219120Srrs * We take the minimum of the burst limit 1386219120Srrs * and the initial congestion window. 1387219120Srrs */ 1388219120Srrs if ((stcb->asoc.max_burst > 0) && (cwnd_in_mtu > stcb->asoc.max_burst)) 1389219120Srrs cwnd_in_mtu = stcb->asoc.max_burst; 1390219120Srrs cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu; 1391219120Srrs } 1392219120Srrs if (net->cwnd > cwnd) { 1393310773Stuexen /* 1394310773Stuexen * Only set if we are not a timeout (i.e. 1395310773Stuexen * down to 1 mtu) 1396310773Stuexen */ 1397219120Srrs net->cwnd = cwnd; 1398219120Srrs } 1399219120Srrs } 1400219120Srrs } 1401219120Srrs} 1402219120Srrs 1403219120Srrsstatic void 1404219120Srrssctp_set_rtcc_initial_cc_param(struct sctp_tcb *stcb, 1405219120Srrs struct sctp_nets *net) 1406219120Srrs{ 1407219120Srrs uint64_t vtag, probepoint; 1408219120Srrs 1409219120Srrs sctp_set_initial_cc_param(stcb, net); 1410219120Srrs stcb->asoc.use_precise_time = 1; 1411310773Stuexen probepoint = (((uint64_t)net->cwnd) << 32); 1412219120Srrs probepoint |= ((9 << 16) | 0); 1413219120Srrs vtag = (net->rtt << 32) | 1414310773Stuexen (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | 1415219120Srrs (stcb->rport); 1416292384Smarkj SDT_PROBE5(sctp, cwnd, net, rttvar, 1417219120Srrs vtag, 1418219120Srrs 0, 1419219120Srrs 0, 1420219120Srrs 0, 1421219120Srrs probepoint); 1422219120Srrs net->cc_mod.rtcc.lbw_rtt = 0; 1423219120Srrs net->cc_mod.rtcc.cwnd_at_bw_set = 0; 1424219397Srrs net->cc_mod.rtcc.vol_reduce = 0; 1425219120Srrs net->cc_mod.rtcc.lbw = 0; 1426219397Srrs net->cc_mod.rtcc.vol_reduce = 0; 1427219397Srrs net->cc_mod.rtcc.bw_bytes_at_last_rttc = 0; 1428219120Srrs net->cc_mod.rtcc.bw_tot_time = 0; 1429219120Srrs net->cc_mod.rtcc.bw_bytes = 0; 1430219120Srrs net->cc_mod.rtcc.tls_needs_set = 0; 1431219120Srrs net->cc_mod.rtcc.ret_from_eq = SCTP_BASE_SYSCTL(sctp_rttvar_eqret); 1432219397Srrs net->cc_mod.rtcc.steady_step = SCTP_BASE_SYSCTL(sctp_steady_step); 1433219397Srrs net->cc_mod.rtcc.use_dccc_ecn = SCTP_BASE_SYSCTL(sctp_use_dccc_ecn); 1434219397Srrs net->cc_mod.rtcc.step_cnt = 0; 1435219397Srrs net->cc_mod.rtcc.last_step_state = 0; 1436219397Srrs 1437219397Srrs 1438219120Srrs} 1439219120Srrs 1440219120Srrsstatic int 1441219120Srrssctp_cwnd_rtcc_socket_option(struct sctp_tcb *stcb, int setorget, 1442219120Srrs struct sctp_cc_option *cc_opt) 1443219120Srrs{ 1444219120Srrs struct sctp_nets *net; 1445219120Srrs 1446219120Srrs if (setorget == 1) { 1447219120Srrs /* a set */ 1448219120Srrs if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) { 1449219120Srrs if ((cc_opt->aid_value.assoc_value != 0) && 1450219120Srrs (cc_opt->aid_value.assoc_value != 1)) { 1451219120Srrs return (EINVAL); 1452219120Srrs } 1453219120Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1454219120Srrs net->cc_mod.rtcc.ret_from_eq = cc_opt->aid_value.assoc_value; 1455219120Srrs } 1456219120Srrs } else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) { 1457219120Srrs if ((cc_opt->aid_value.assoc_value != 0) && 1458219120Srrs (cc_opt->aid_value.assoc_value != 1)) { 1459219120Srrs return (EINVAL); 1460219120Srrs } 1461219120Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1462219120Srrs net->cc_mod.rtcc.use_dccc_ecn = cc_opt->aid_value.assoc_value; 1463219120Srrs } 1464219397Srrs } else if (cc_opt->option == SCTP_CC_OPT_STEADY_STEP) { 1465219397Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1466219397Srrs net->cc_mod.rtcc.steady_step = cc_opt->aid_value.assoc_value; 1467219397Srrs } 1468219120Srrs } else { 1469219120Srrs return (EINVAL); 1470219120Srrs } 1471219120Srrs } else { 1472219120Srrs /* a get */ 1473219120Srrs if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) { 1474219120Srrs net = TAILQ_FIRST(&stcb->asoc.nets); 1475219120Srrs if (net == NULL) { 1476219120Srrs return (EFAULT); 1477219120Srrs } 1478219120Srrs cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.ret_from_eq; 1479219120Srrs } else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) { 1480219120Srrs net = TAILQ_FIRST(&stcb->asoc.nets); 1481219120Srrs if (net == NULL) { 1482219120Srrs return (EFAULT); 1483219120Srrs } 1484219120Srrs cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.use_dccc_ecn; 1485219397Srrs } else if (cc_opt->option == SCTP_CC_OPT_STEADY_STEP) { 1486219397Srrs net = TAILQ_FIRST(&stcb->asoc.nets); 1487219397Srrs if (net == NULL) { 1488219397Srrs return (EFAULT); 1489219397Srrs } 1490219397Srrs cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.steady_step; 1491219120Srrs } else { 1492219120Srrs return (EINVAL); 1493219120Srrs } 1494219120Srrs } 1495219120Srrs return (0); 1496219120Srrs} 1497219120Srrs 1498219120Srrsstatic void 1499228653Stuexensctp_cwnd_update_rtcc_packet_transmitted(struct sctp_tcb *stcb SCTP_UNUSED, 1500219120Srrs struct sctp_nets *net) 1501219120Srrs{ 1502219120Srrs if (net->cc_mod.rtcc.tls_needs_set == 0) { 1503219120Srrs SCTP_GETPTIME_TIMEVAL(&net->cc_mod.rtcc.tls); 1504219120Srrs net->cc_mod.rtcc.tls_needs_set = 2; 1505219120Srrs } 1506219120Srrs} 1507219120Srrs 1508219120Srrsstatic void 1509219120Srrssctp_cwnd_update_rtcc_after_sack(struct sctp_tcb *stcb, 1510219120Srrs struct sctp_association *asoc, 1511219120Srrs int accum_moved, int reneged_all, int will_exit) 1512219120Srrs{ 1513298942Spfg /* Passing a one argument at the last enables the rtcc algorithm */ 1514219120Srrs sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 1); 1515219120Srrs} 1516219120Srrs 1517219397Srrsstatic void 1518228653Stuexensctp_rtt_rtcc_calculated(struct sctp_tcb *stcb SCTP_UNUSED, 1519228653Stuexen struct sctp_nets *net, 1520228653Stuexen struct timeval *now SCTP_UNUSED) 1521219397Srrs{ 1522219397Srrs net->cc_mod.rtcc.rtt_set_this_sack = 1; 1523219397Srrs} 1524219120Srrs 1525219120Srrs/* Here starts Sally Floyds HS-TCP */ 1526219120Srrs 1527171440Srrsstruct sctp_hs_raise_drop { 1528171440Srrs int32_t cwnd; 1529297208Stuexen int8_t increase; 1530297208Stuexen int8_t drop_percent; 1531171440Srrs}; 1532171440Srrs 1533171440Srrs#define SCTP_HS_TABLE_SIZE 73 1534171440Srrs 1535297208Stuexenstatic const struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = { 1536171440Srrs {38, 1, 50}, /* 0 */ 1537171440Srrs {118, 2, 44}, /* 1 */ 1538171440Srrs {221, 3, 41}, /* 2 */ 1539171440Srrs {347, 4, 38}, /* 3 */ 1540171440Srrs {495, 5, 37}, /* 4 */ 1541171440Srrs {663, 6, 35}, /* 5 */ 1542171440Srrs {851, 7, 34}, /* 6 */ 1543171440Srrs {1058, 8, 33}, /* 7 */ 1544171440Srrs {1284, 9, 32}, /* 8 */ 1545171440Srrs {1529, 10, 31}, /* 9 */ 1546171440Srrs {1793, 11, 30}, /* 10 */ 1547171440Srrs {2076, 12, 29}, /* 11 */ 1548171440Srrs {2378, 13, 28}, /* 12 */ 1549171440Srrs {2699, 14, 28}, /* 13 */ 1550171440Srrs {3039, 15, 27}, /* 14 */ 1551171440Srrs {3399, 16, 27}, /* 15 */ 1552171440Srrs {3778, 17, 26}, /* 16 */ 1553171440Srrs {4177, 18, 26}, /* 17 */ 1554171440Srrs {4596, 19, 25}, /* 18 */ 1555171440Srrs {5036, 20, 25}, /* 19 */ 1556171440Srrs {5497, 21, 24}, /* 20 */ 1557171440Srrs {5979, 22, 24}, /* 21 */ 1558171440Srrs {6483, 23, 23}, /* 22 */ 1559171440Srrs {7009, 24, 23}, /* 23 */ 1560171440Srrs {7558, 25, 22}, /* 24 */ 1561171440Srrs {8130, 26, 22}, /* 25 */ 1562171440Srrs {8726, 27, 22}, /* 26 */ 1563171440Srrs {9346, 28, 21}, /* 27 */ 1564171440Srrs {9991, 29, 21}, /* 28 */ 1565171440Srrs {10661, 30, 21}, /* 29 */ 1566171440Srrs {11358, 31, 20}, /* 30 */ 1567171440Srrs {12082, 32, 20}, /* 31 */ 1568171440Srrs {12834, 33, 20}, /* 32 */ 1569171440Srrs {13614, 34, 19}, /* 33 */ 1570171440Srrs {14424, 35, 19}, /* 34 */ 1571171440Srrs {15265, 36, 19}, /* 35 */ 1572171440Srrs {16137, 37, 19}, /* 36 */ 1573171440Srrs {17042, 38, 18}, /* 37 */ 1574171440Srrs {17981, 39, 18}, /* 38 */ 1575171440Srrs {18955, 40, 18}, /* 39 */ 1576171440Srrs {19965, 41, 17}, /* 40 */ 1577171440Srrs {21013, 42, 17}, /* 41 */ 1578171440Srrs {22101, 43, 17}, /* 42 */ 1579171440Srrs {23230, 44, 17}, /* 43 */ 1580171440Srrs {24402, 45, 16}, /* 44 */ 1581171440Srrs {25618, 46, 16}, /* 45 */ 1582171440Srrs {26881, 47, 16}, /* 46 */ 1583171440Srrs {28193, 48, 16}, /* 47 */ 1584171440Srrs {29557, 49, 15}, /* 48 */ 1585171440Srrs {30975, 50, 15}, /* 49 */ 1586171440Srrs {32450, 51, 15}, /* 50 */ 1587171440Srrs {33986, 52, 15}, /* 51 */ 1588171440Srrs {35586, 53, 14}, /* 52 */ 1589171440Srrs {37253, 54, 14}, /* 53 */ 1590171440Srrs {38992, 55, 14}, /* 54 */ 1591171440Srrs {40808, 56, 14}, /* 55 */ 1592171440Srrs {42707, 57, 13}, /* 56 */ 1593171440Srrs {44694, 58, 13}, /* 57 */ 1594171440Srrs {46776, 59, 13}, /* 58 */ 1595171440Srrs {48961, 60, 13}, /* 59 */ 1596171440Srrs {51258, 61, 13}, /* 60 */ 1597171440Srrs {53677, 62, 12}, /* 61 */ 1598171440Srrs {56230, 63, 12}, /* 62 */ 1599171440Srrs {58932, 64, 12}, /* 63 */ 1600171440Srrs {61799, 65, 12}, /* 64 */ 1601171440Srrs {64851, 66, 11}, /* 65 */ 1602171440Srrs {68113, 67, 11}, /* 66 */ 1603171440Srrs {71617, 68, 11}, /* 67 */ 1604171440Srrs {75401, 69, 10}, /* 68 */ 1605171440Srrs {79517, 70, 10}, /* 69 */ 1606171440Srrs {84035, 71, 10}, /* 70 */ 1607171440Srrs {89053, 72, 10}, /* 71 */ 1608171440Srrs {94717, 73, 9} /* 72 */ 1609171440Srrs}; 1610171440Srrs 1611171440Srrsstatic void 1612171440Srrssctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net) 1613171440Srrs{ 1614171440Srrs int cur_val, i, indx, incr; 1615279859Stuexen int old_cwnd = net->cwnd; 1616171440Srrs 1617171440Srrs cur_val = net->cwnd >> 10; 1618171440Srrs indx = SCTP_HS_TABLE_SIZE - 1; 1619234995Stuexen 1620171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 1621171440Srrs /* normal mode */ 1622171440Srrs if (net->net_ack > net->mtu) { 1623171440Srrs net->cwnd += net->mtu; 1624171440Srrs } else { 1625171440Srrs net->cwnd += net->net_ack; 1626171440Srrs } 1627171440Srrs } else { 1628171440Srrs for (i = net->last_hs_used; i < SCTP_HS_TABLE_SIZE; i++) { 1629171440Srrs if (cur_val < sctp_cwnd_adjust[i].cwnd) { 1630171440Srrs indx = i; 1631171440Srrs break; 1632171440Srrs } 1633171440Srrs } 1634171440Srrs net->last_hs_used = indx; 1635310773Stuexen incr = (((int32_t)sctp_cwnd_adjust[indx].increase) << 10); 1636171440Srrs net->cwnd += incr; 1637171440Srrs } 1638279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 1639279859Stuexen if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1640279859Stuexen sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SS); 1641279859Stuexen } 1642171440Srrs} 1643171440Srrs 1644171440Srrsstatic void 1645171440Srrssctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net) 1646171440Srrs{ 1647171440Srrs int cur_val, i, indx; 1648171440Srrs int old_cwnd = net->cwnd; 1649171440Srrs 1650171440Srrs cur_val = net->cwnd >> 10; 1651171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 1652171440Srrs /* normal mode */ 1653171440Srrs net->ssthresh = net->cwnd / 2; 1654171440Srrs if (net->ssthresh < (net->mtu * 2)) { 1655171440Srrs net->ssthresh = 2 * net->mtu; 1656171440Srrs } 1657171440Srrs net->cwnd = net->ssthresh; 1658171440Srrs } else { 1659171440Srrs /* drop by the proper amount */ 1660171440Srrs net->ssthresh = net->cwnd - (int)((net->cwnd / 100) * 1661310773Stuexen (int32_t)sctp_cwnd_adjust[net->last_hs_used].drop_percent); 1662171440Srrs net->cwnd = net->ssthresh; 1663171440Srrs /* now where are we */ 1664171440Srrs indx = net->last_hs_used; 1665171440Srrs cur_val = net->cwnd >> 10; 1666171440Srrs /* reset where we are in the table */ 1667171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 1668171440Srrs /* feel out of hs */ 1669171440Srrs net->last_hs_used = 0; 1670171440Srrs } else { 1671171440Srrs for (i = indx; i >= 1; i--) { 1672171440Srrs if (cur_val > sctp_cwnd_adjust[i - 1].cwnd) { 1673171440Srrs break; 1674171440Srrs } 1675171440Srrs } 1676171440Srrs net->last_hs_used = indx; 1677171440Srrs } 1678171440Srrs } 1679279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 1680179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1681171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_FR); 1682171440Srrs } 1683171440Srrs} 1684171440Srrs 1685217611Stuexenstatic void 1686171440Srrssctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb, 1687171440Srrs struct sctp_association *asoc) 1688171440Srrs{ 1689171440Srrs struct sctp_nets *net; 1690171440Srrs 1691171440Srrs /* 1692216669Stuexen * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) && 1693171440Srrs * (net->fast_retran_loss_recovery == 0))) 1694171440Srrs */ 1695171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 1696211944Stuexen if ((asoc->fast_retran_loss_recovery == 0) || 1697216669Stuexen (asoc->sctp_cmt_on_off > 0)) { 1698171440Srrs /* out of a RFC2582 Fast recovery window? */ 1699171440Srrs if (net->net_ack > 0) { 1700171440Srrs /* 1701171440Srrs * per section 7.2.3, are there any 1702171440Srrs * destinations that had a fast retransmit 1703171440Srrs * to them. If so what we need to do is 1704171440Srrs * adjust ssthresh and cwnd. 1705171440Srrs */ 1706171440Srrs struct sctp_tmit_chunk *lchk; 1707171440Srrs 1708171440Srrs sctp_hs_cwnd_decrease(stcb, net); 1709171440Srrs 1710171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 1711171440Srrs 1712171440Srrs net->partial_bytes_acked = 0; 1713171440Srrs /* Turn on fast recovery window */ 1714171440Srrs asoc->fast_retran_loss_recovery = 1; 1715171440Srrs if (lchk == NULL) { 1716171440Srrs /* Mark end of the window */ 1717171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 1718171440Srrs } else { 1719310219Stuexen asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1; 1720171440Srrs } 1721171440Srrs 1722171440Srrs /* 1723171440Srrs * CMT fast recovery -- per destination 1724171440Srrs * recovery variable. 1725171440Srrs */ 1726171440Srrs net->fast_retran_loss_recovery = 1; 1727171440Srrs 1728171440Srrs if (lchk == NULL) { 1729171440Srrs /* Mark end of the window */ 1730171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 1731171440Srrs } else { 1732310219Stuexen net->fast_recovery_tsn = lchk->rec.data.tsn - 1; 1733171440Srrs } 1734171440Srrs 1735171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 1736283650Stuexen stcb->sctp_ep, stcb, net, 1737283650Stuexen SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_2); 1738171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 1739171440Srrs stcb->sctp_ep, stcb, net); 1740171440Srrs } 1741171440Srrs } else if (net->net_ack > 0) { 1742171440Srrs /* 1743171440Srrs * Mark a peg that we WOULD have done a cwnd 1744171440Srrs * reduction but RFC2582 prevented this action. 1745171440Srrs */ 1746171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 1747171440Srrs } 1748171440Srrs } 1749171440Srrs} 1750171440Srrs 1751217611Stuexenstatic void 1752171440Srrssctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, 1753171440Srrs struct sctp_association *asoc, 1754228653Stuexen int accum_moved, int reneged_all SCTP_UNUSED, int will_exit) 1755171440Srrs{ 1756171440Srrs struct sctp_nets *net; 1757171440Srrs 1758171440Srrs /******************************/ 1759171440Srrs /* update cwnd and Early FR */ 1760171440Srrs /******************************/ 1761171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 1762171440Srrs 1763171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 1764171440Srrs /* 1765171440Srrs * CMT fast recovery code. Need to debug. 1766171440Srrs */ 1767171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 1768217469Stuexen if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) || 1769217469Stuexen SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) { 1770171440Srrs net->will_exit_fast_recovery = 1; 1771171440Srrs } 1772171440Srrs } 1773171440Srrs#endif 1774171440Srrs /* if nothing was acked on this destination skip it */ 1775171440Srrs if (net->net_ack == 0) { 1776179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1777171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 1778171440Srrs } 1779171440Srrs continue; 1780171440Srrs } 1781171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 1782171440Srrs /* 1783171440Srrs * CMT fast recovery code 1784171440Srrs */ 1785171440Srrs /* 1786216669Stuexen * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery 1787216669Stuexen * && net->will_exit_fast_recovery == 0) { @@@ Do something 1788216669Stuexen * } else if (sctp_cmt_on_off == 0 && 1789171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 1790171440Srrs */ 1791171440Srrs#endif 1792171440Srrs 1793211944Stuexen if (asoc->fast_retran_loss_recovery && 1794211944Stuexen (will_exit == 0) && 1795211944Stuexen (asoc->sctp_cmt_on_off == 0)) { 1796171440Srrs /* 1797171440Srrs * If we are in loss recovery we skip any cwnd 1798171440Srrs * update 1799171440Srrs */ 1800224641Stuexen return; 1801171440Srrs } 1802171440Srrs /* 1803171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 1804171440Srrs * moved. 1805171440Srrs */ 1806211944Stuexen if (accum_moved || 1807216669Stuexen ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) { 1808171440Srrs /* If the cumulative ack moved we can proceed */ 1809171440Srrs if (net->cwnd <= net->ssthresh) { 1810171440Srrs /* We are in slow start */ 1811179157Srrs if (net->flight_size + net->net_ack >= net->cwnd) { 1812171440Srrs sctp_hs_cwnd_increase(stcb, net); 1813171440Srrs } else { 1814179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1815171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 1816171440Srrs SCTP_CWND_LOG_NOADV_SS); 1817171440Srrs } 1818171440Srrs } 1819171440Srrs } else { 1820171440Srrs /* We are in congestion avoidance */ 1821179157Srrs net->partial_bytes_acked += net->net_ack; 1822179157Srrs if ((net->flight_size + net->net_ack >= net->cwnd) && 1823179157Srrs (net->partial_bytes_acked >= net->cwnd)) { 1824179157Srrs net->partial_bytes_acked -= net->cwnd; 1825179157Srrs net->cwnd += net->mtu; 1826279859Stuexen sctp_enforce_cwnd_limit(asoc, net); 1827179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1828179157Srrs sctp_log_cwnd(stcb, net, net->mtu, 1829179157Srrs SCTP_CWND_LOG_FROM_CA); 1830171440Srrs } 1831171440Srrs } else { 1832179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1833171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 1834171440Srrs SCTP_CWND_LOG_NOADV_CA); 1835171440Srrs } 1836171440Srrs } 1837171440Srrs } 1838171440Srrs } else { 1839179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1840171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 1841171440Srrs SCTP_CWND_LOG_NO_CUMACK); 1842171440Srrs } 1843171440Srrs } 1844171440Srrs } 1845171440Srrs} 1846171440Srrs 1847171440Srrs 1848171440Srrs/* 1849171440Srrs * H-TCP congestion control. The algorithm is detailed in: 1850171440Srrs * R.N.Shorten, D.J.Leith: 1851171440Srrs * "H-TCP: TCP for high-speed and long-distance networks" 1852171440Srrs * Proc. PFLDnet, Argonne, 2004. 1853171440Srrs * http://www.hamilton.ie/net/htcp3.pdf 1854171440Srrs */ 1855171440Srrs 1856171440Srrs 1857171440Srrsstatic int use_rtt_scaling = 1; 1858171440Srrsstatic int use_bandwidth_switch = 1; 1859171440Srrs 1860171440Srrsstatic inline int 1861171440Srrsbetween(uint32_t seq1, uint32_t seq2, uint32_t seq3) 1862171440Srrs{ 1863228907Stuexen return (seq3 - seq2 >= seq1 - seq2); 1864171440Srrs} 1865171440Srrs 1866171440Srrsstatic inline uint32_t 1867171440Srrshtcp_cong_time(struct htcp *ca) 1868171440Srrs{ 1869228907Stuexen return (sctp_get_tick_count() - ca->last_cong); 1870171440Srrs} 1871171440Srrs 1872171440Srrsstatic inline uint32_t 1873171440Srrshtcp_ccount(struct htcp *ca) 1874171440Srrs{ 1875228907Stuexen return (htcp_cong_time(ca) / ca->minRTT); 1876171440Srrs} 1877171440Srrs 1878171440Srrsstatic inline void 1879171440Srrshtcp_reset(struct htcp *ca) 1880171440Srrs{ 1881171440Srrs ca->undo_last_cong = ca->last_cong; 1882171440Srrs ca->undo_maxRTT = ca->maxRTT; 1883171440Srrs ca->undo_old_maxB = ca->old_maxB; 1884171477Srrs ca->last_cong = sctp_get_tick_count(); 1885171440Srrs} 1886171440Srrs 1887171440Srrs#ifdef SCTP_NOT_USED 1888171440Srrs 1889171440Srrsstatic uint32_t 1890171440Srrshtcp_cwnd_undo(struct sctp_tcb *stcb, struct sctp_nets *net) 1891171440Srrs{ 1892219057Srrs net->cc_mod.htcp_ca.last_cong = net->cc_mod.htcp_ca.undo_last_cong; 1893219057Srrs net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.undo_maxRTT; 1894219057Srrs net->cc_mod.htcp_ca.old_maxB = net->cc_mod.htcp_ca.undo_old_maxB; 1895228907Stuexen return (max(net->cwnd, ((net->ssthresh / net->mtu << 7) / net->cc_mod.htcp_ca.beta) * net->mtu)); 1896171440Srrs} 1897171440Srrs 1898171440Srrs#endif 1899171440Srrs 1900171440Srrsstatic inline void 1901228653Stuexenmeasure_rtt(struct sctp_nets *net) 1902171440Srrs{ 1903219014Stuexen uint32_t srtt = net->lastsa >> SCTP_RTT_SHIFT; 1904171440Srrs 1905171440Srrs /* keep track of minimum RTT seen so far, minRTT is zero at first */ 1906219057Srrs if (net->cc_mod.htcp_ca.minRTT > srtt || !net->cc_mod.htcp_ca.minRTT) 1907219057Srrs net->cc_mod.htcp_ca.minRTT = srtt; 1908171440Srrs 1909171440Srrs /* max RTT */ 1910219057Srrs if (net->fast_retran_ip == 0 && net->ssthresh < 0xFFFF && htcp_ccount(&net->cc_mod.htcp_ca) > 3) { 1911219057Srrs if (net->cc_mod.htcp_ca.maxRTT < net->cc_mod.htcp_ca.minRTT) 1912219057Srrs net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.minRTT; 1913219057Srrs if (net->cc_mod.htcp_ca.maxRTT < srtt && srtt <= net->cc_mod.htcp_ca.maxRTT + MSEC_TO_TICKS(20)) 1914219057Srrs net->cc_mod.htcp_ca.maxRTT = srtt; 1915171440Srrs } 1916171440Srrs} 1917171440Srrs 1918171440Srrsstatic void 1919228653Stuexenmeasure_achieved_throughput(struct sctp_nets *net) 1920171440Srrs{ 1921171477Srrs uint32_t now = sctp_get_tick_count(); 1922171440Srrs 1923171440Srrs if (net->fast_retran_ip == 0) 1924219057Srrs net->cc_mod.htcp_ca.bytes_acked = net->net_ack; 1925171440Srrs 1926171440Srrs if (!use_bandwidth_switch) 1927171440Srrs return; 1928171440Srrs 1929171440Srrs /* achieved throughput calculations */ 1930171440Srrs /* JRS - not 100% sure of this statement */ 1931171440Srrs if (net->fast_retran_ip == 1) { 1932219057Srrs net->cc_mod.htcp_ca.bytecount = 0; 1933219057Srrs net->cc_mod.htcp_ca.lasttime = now; 1934171440Srrs return; 1935171440Srrs } 1936219057Srrs net->cc_mod.htcp_ca.bytecount += net->net_ack; 1937240158Stuexen 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)) && 1938240158Stuexen (now - net->cc_mod.htcp_ca.lasttime >= net->cc_mod.htcp_ca.minRTT) && 1939240158Stuexen (net->cc_mod.htcp_ca.minRTT > 0)) { 1940219057Srrs uint32_t cur_Bi = net->cc_mod.htcp_ca.bytecount / net->mtu * hz / (now - net->cc_mod.htcp_ca.lasttime); 1941171440Srrs 1942219057Srrs if (htcp_ccount(&net->cc_mod.htcp_ca) <= 3) { 1943171440Srrs /* just after backoff */ 1944219057Srrs net->cc_mod.htcp_ca.minB = net->cc_mod.htcp_ca.maxB = net->cc_mod.htcp_ca.Bi = cur_Bi; 1945171440Srrs } else { 1946219057Srrs net->cc_mod.htcp_ca.Bi = (3 * net->cc_mod.htcp_ca.Bi + cur_Bi) / 4; 1947219057Srrs if (net->cc_mod.htcp_ca.Bi > net->cc_mod.htcp_ca.maxB) 1948219057Srrs net->cc_mod.htcp_ca.maxB = net->cc_mod.htcp_ca.Bi; 1949219057Srrs if (net->cc_mod.htcp_ca.minB > net->cc_mod.htcp_ca.maxB) 1950219057Srrs net->cc_mod.htcp_ca.minB = net->cc_mod.htcp_ca.maxB; 1951171440Srrs } 1952219057Srrs net->cc_mod.htcp_ca.bytecount = 0; 1953219057Srrs net->cc_mod.htcp_ca.lasttime = now; 1954171440Srrs } 1955171440Srrs} 1956171440Srrs 1957171440Srrsstatic inline void 1958171440Srrshtcp_beta_update(struct htcp *ca, uint32_t minRTT, uint32_t maxRTT) 1959171440Srrs{ 1960171440Srrs if (use_bandwidth_switch) { 1961171440Srrs uint32_t maxB = ca->maxB; 1962171440Srrs uint32_t old_maxB = ca->old_maxB; 1963171440Srrs 1964171440Srrs ca->old_maxB = ca->maxB; 1965171440Srrs 1966171440Srrs if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) { 1967171440Srrs ca->beta = BETA_MIN; 1968171440Srrs ca->modeswitch = 0; 1969171440Srrs return; 1970171440Srrs } 1971171440Srrs } 1972310773Stuexen if (ca->modeswitch && minRTT > (uint32_t)MSEC_TO_TICKS(10) && maxRTT) { 1973171440Srrs ca->beta = (minRTT << 7) / maxRTT; 1974171440Srrs if (ca->beta < BETA_MIN) 1975171440Srrs ca->beta = BETA_MIN; 1976171440Srrs else if (ca->beta > BETA_MAX) 1977171440Srrs ca->beta = BETA_MAX; 1978171440Srrs } else { 1979171440Srrs ca->beta = BETA_MIN; 1980171440Srrs ca->modeswitch = 1; 1981171440Srrs } 1982171440Srrs} 1983171440Srrs 1984171440Srrsstatic inline void 1985171440Srrshtcp_alpha_update(struct htcp *ca) 1986171440Srrs{ 1987171440Srrs uint32_t minRTT = ca->minRTT; 1988171440Srrs uint32_t factor = 1; 1989171440Srrs uint32_t diff = htcp_cong_time(ca); 1990171440Srrs 1991310773Stuexen if (diff > (uint32_t)hz) { 1992171440Srrs diff -= hz; 1993171440Srrs factor = 1 + (10 * diff + ((diff / 2) * (diff / 2) / hz)) / hz; 1994171440Srrs } 1995171440Srrs if (use_rtt_scaling && minRTT) { 1996171440Srrs uint32_t scale = (hz << 3) / (10 * minRTT); 1997171440Srrs 1998171440Srrs scale = min(max(scale, 1U << 2), 10U << 3); /* clamping ratio to 1999171440Srrs * interval [0.5,10]<<3 */ 2000171440Srrs factor = (factor << 3) / scale; 2001171440Srrs if (!factor) 2002171440Srrs factor = 1; 2003171440Srrs } 2004171440Srrs ca->alpha = 2 * factor * ((1 << 7) - ca->beta); 2005171440Srrs if (!ca->alpha) 2006171440Srrs ca->alpha = ALPHA_BASE; 2007171440Srrs} 2008171440Srrs 2009171440Srrs/* After we have the rtt data to calculate beta, we'd still prefer to wait one 2010171440Srrs * rtt before we adjust our beta to ensure we are working from a consistent 2011171440Srrs * data. 2012171440Srrs * 2013171440Srrs * This function should be called when we hit a congestion event since only at 2014171440Srrs * that point do we really have a real sense of maxRTT (the queues en route 2015171440Srrs * were getting just too full now). 2016171440Srrs */ 2017171440Srrsstatic void 2018228653Stuexenhtcp_param_update(struct sctp_nets *net) 2019171440Srrs{ 2020219057Srrs uint32_t minRTT = net->cc_mod.htcp_ca.minRTT; 2021219057Srrs uint32_t maxRTT = net->cc_mod.htcp_ca.maxRTT; 2022171440Srrs 2023219057Srrs htcp_beta_update(&net->cc_mod.htcp_ca, minRTT, maxRTT); 2024219057Srrs htcp_alpha_update(&net->cc_mod.htcp_ca); 2025171440Srrs 2026310773Stuexen /* 2027310773Stuexen * add slowly fading memory for maxRTT to accommodate routing 2028310773Stuexen * changes etc 2029310773Stuexen */ 2030171440Srrs if (minRTT > 0 && maxRTT > minRTT) 2031219057Srrs net->cc_mod.htcp_ca.maxRTT = minRTT + ((maxRTT - minRTT) * 95) / 100; 2032171440Srrs} 2033171440Srrs 2034171440Srrsstatic uint32_t 2035228653Stuexenhtcp_recalc_ssthresh(struct sctp_nets *net) 2036171440Srrs{ 2037228653Stuexen htcp_param_update(net); 2038228907Stuexen return (max(((net->cwnd / net->mtu * net->cc_mod.htcp_ca.beta) >> 7) * net->mtu, 2U * net->mtu)); 2039171440Srrs} 2040171440Srrs 2041171440Srrsstatic void 2042171440Srrshtcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net) 2043171440Srrs{ 2044171440Srrs /*- 2045171440Srrs * How to handle these functions? 2046171440Srrs * if (!tcp_is_cwnd_limited(sk, in_flight)) RRS - good question. 2047171440Srrs * return; 2048171440Srrs */ 2049171440Srrs if (net->cwnd <= net->ssthresh) { 2050171440Srrs /* We are in slow start */ 2051171440Srrs if (net->flight_size + net->net_ack >= net->cwnd) { 2052179783Srrs if (net->net_ack > (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable))) { 2053179783Srrs net->cwnd += (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)); 2054179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2055171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 2056171440Srrs SCTP_CWND_LOG_FROM_SS); 2057171440Srrs } 2058171440Srrs } else { 2059171440Srrs net->cwnd += net->net_ack; 2060179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2061171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 2062171440Srrs SCTP_CWND_LOG_FROM_SS); 2063171440Srrs } 2064171440Srrs } 2065279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 2066171440Srrs } else { 2067179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 2068171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 2069171440Srrs SCTP_CWND_LOG_NOADV_SS); 2070171440Srrs } 2071171440Srrs } 2072171440Srrs } else { 2073228653Stuexen measure_rtt(net); 2074171440Srrs 2075171440Srrs /* 2076171440Srrs * In dangerous area, increase slowly. In theory this is 2077171440Srrs * net->cwnd += alpha / net->cwnd 2078171440Srrs */ 2079171440Srrs /* What is snd_cwnd_cnt?? */ 2080219057Srrs if (((net->partial_bytes_acked / net->mtu * net->cc_mod.htcp_ca.alpha) >> 7) * net->mtu >= net->cwnd) { 2081171440Srrs /*- 2082171440Srrs * Does SCTP have a cwnd clamp? 2083171440Srrs * if (net->snd_cwnd < net->snd_cwnd_clamp) - Nope (RRS). 2084171440Srrs */ 2085171440Srrs net->cwnd += net->mtu; 2086171440Srrs net->partial_bytes_acked = 0; 2087279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 2088219057Srrs htcp_alpha_update(&net->cc_mod.htcp_ca); 2089179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2090171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 2091171440Srrs SCTP_CWND_LOG_FROM_CA); 2092171440Srrs } 2093171440Srrs } else { 2094171440Srrs net->partial_bytes_acked += net->net_ack; 2095179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 2096171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 2097171440Srrs SCTP_CWND_LOG_NOADV_CA); 2098171440Srrs } 2099171440Srrs } 2100171440Srrs 2101219057Srrs net->cc_mod.htcp_ca.bytes_acked = net->mtu; 2102171440Srrs } 2103171440Srrs} 2104171440Srrs 2105171440Srrs#ifdef SCTP_NOT_USED 2106171440Srrs/* Lower bound on congestion window. */ 2107171440Srrsstatic uint32_t 2108171440Srrshtcp_min_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net) 2109171440Srrs{ 2110228907Stuexen return (net->ssthresh); 2111171440Srrs} 2112171440Srrs#endif 2113171440Srrs 2114171440Srrsstatic void 2115228653Stuexenhtcp_init(struct sctp_nets *net) 2116171440Srrs{ 2117219057Srrs memset(&net->cc_mod.htcp_ca, 0, sizeof(struct htcp)); 2118219057Srrs net->cc_mod.htcp_ca.alpha = ALPHA_BASE; 2119219057Srrs net->cc_mod.htcp_ca.beta = BETA_MIN; 2120219057Srrs net->cc_mod.htcp_ca.bytes_acked = net->mtu; 2121219057Srrs net->cc_mod.htcp_ca.last_cong = sctp_get_tick_count(); 2122171440Srrs} 2123171440Srrs 2124217611Stuexenstatic void 2125171440Srrssctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) 2126171440Srrs{ 2127171440Srrs /* 2128171440Srrs * We take the max of the burst limit times a MTU or the 2129171440Srrs * INITIAL_CWND. We then limit this to 4 MTU's of sending. 2130171440Srrs */ 2131171440Srrs net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 2132171440Srrs net->ssthresh = stcb->asoc.peers_rwnd; 2133279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 2134228653Stuexen htcp_init(net); 2135171440Srrs 2136179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { 2137171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); 2138171440Srrs } 2139171440Srrs} 2140171440Srrs 2141217611Stuexenstatic void 2142171440Srrssctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, 2143171440Srrs struct sctp_association *asoc, 2144228653Stuexen int accum_moved, int reneged_all SCTP_UNUSED, int will_exit) 2145171440Srrs{ 2146171440Srrs struct sctp_nets *net; 2147171440Srrs 2148171440Srrs /******************************/ 2149171440Srrs /* update cwnd and Early FR */ 2150171440Srrs /******************************/ 2151171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 2152171440Srrs 2153171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 2154171440Srrs /* 2155171440Srrs * CMT fast recovery code. Need to debug. 2156171440Srrs */ 2157171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 2158217469Stuexen if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) || 2159217469Stuexen SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) { 2160171440Srrs net->will_exit_fast_recovery = 1; 2161171440Srrs } 2162171440Srrs } 2163171440Srrs#endif 2164171440Srrs /* if nothing was acked on this destination skip it */ 2165171440Srrs if (net->net_ack == 0) { 2166179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 2167171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 2168171440Srrs } 2169171440Srrs continue; 2170171440Srrs } 2171171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 2172171440Srrs /* 2173171440Srrs * CMT fast recovery code 2174171440Srrs */ 2175171440Srrs /* 2176216669Stuexen * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery 2177216669Stuexen * && net->will_exit_fast_recovery == 0) { @@@ Do something 2178216669Stuexen * } else if (sctp_cmt_on_off == 0 && 2179171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 2180171440Srrs */ 2181171440Srrs#endif 2182171440Srrs 2183211944Stuexen if (asoc->fast_retran_loss_recovery && 2184211944Stuexen will_exit == 0 && 2185211944Stuexen (asoc->sctp_cmt_on_off == 0)) { 2186171440Srrs /* 2187171440Srrs * If we are in loss recovery we skip any cwnd 2188171440Srrs * update 2189171440Srrs */ 2190224641Stuexen return; 2191171440Srrs } 2192171440Srrs /* 2193171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 2194171440Srrs * moved. 2195171440Srrs */ 2196211944Stuexen if (accum_moved || 2197216669Stuexen ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) { 2198171440Srrs htcp_cong_avoid(stcb, net); 2199228653Stuexen measure_achieved_throughput(net); 2200171440Srrs } else { 2201179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 2202171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 2203171440Srrs SCTP_CWND_LOG_NO_CUMACK); 2204171440Srrs } 2205171440Srrs } 2206171440Srrs } 2207171440Srrs} 2208171440Srrs 2209217611Stuexenstatic void 2210171440Srrssctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb, 2211171440Srrs struct sctp_association *asoc) 2212171440Srrs{ 2213171440Srrs struct sctp_nets *net; 2214171440Srrs 2215171440Srrs /* 2216216669Stuexen * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) && 2217171440Srrs * (net->fast_retran_loss_recovery == 0))) 2218171440Srrs */ 2219171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 2220211944Stuexen if ((asoc->fast_retran_loss_recovery == 0) || 2221216669Stuexen (asoc->sctp_cmt_on_off > 0)) { 2222171440Srrs /* out of a RFC2582 Fast recovery window? */ 2223171440Srrs if (net->net_ack > 0) { 2224171440Srrs /* 2225171440Srrs * per section 7.2.3, are there any 2226171440Srrs * destinations that had a fast retransmit 2227171440Srrs * to them. If so what we need to do is 2228171440Srrs * adjust ssthresh and cwnd. 2229171440Srrs */ 2230171440Srrs struct sctp_tmit_chunk *lchk; 2231171440Srrs int old_cwnd = net->cwnd; 2232171440Srrs 2233171440Srrs /* JRS - reset as if state were changed */ 2234219057Srrs htcp_reset(&net->cc_mod.htcp_ca); 2235228653Stuexen net->ssthresh = htcp_recalc_ssthresh(net); 2236171440Srrs net->cwnd = net->ssthresh; 2237279859Stuexen sctp_enforce_cwnd_limit(asoc, net); 2238179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2239171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 2240171440Srrs SCTP_CWND_LOG_FROM_FR); 2241171440Srrs } 2242171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 2243171440Srrs 2244171440Srrs net->partial_bytes_acked = 0; 2245171440Srrs /* Turn on fast recovery window */ 2246171440Srrs asoc->fast_retran_loss_recovery = 1; 2247171440Srrs if (lchk == NULL) { 2248171440Srrs /* Mark end of the window */ 2249171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 2250171440Srrs } else { 2251310219Stuexen asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1; 2252171440Srrs } 2253171440Srrs 2254171440Srrs /* 2255171440Srrs * CMT fast recovery -- per destination 2256171440Srrs * recovery variable. 2257171440Srrs */ 2258171440Srrs net->fast_retran_loss_recovery = 1; 2259171440Srrs 2260171440Srrs if (lchk == NULL) { 2261171440Srrs /* Mark end of the window */ 2262171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 2263171440Srrs } else { 2264310219Stuexen net->fast_recovery_tsn = lchk->rec.data.tsn - 1; 2265171440Srrs } 2266171440Srrs 2267171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 2268283650Stuexen stcb->sctp_ep, stcb, net, 2269283650Stuexen SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_3); 2270171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 2271171440Srrs stcb->sctp_ep, stcb, net); 2272171440Srrs } 2273171440Srrs } else if (net->net_ack > 0) { 2274171440Srrs /* 2275171440Srrs * Mark a peg that we WOULD have done a cwnd 2276171440Srrs * reduction but RFC2582 prevented this action. 2277171440Srrs */ 2278171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 2279171440Srrs } 2280171440Srrs } 2281171440Srrs} 2282171440Srrs 2283217611Stuexenstatic void 2284171440Srrssctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb, 2285171440Srrs struct sctp_nets *net) 2286171440Srrs{ 2287171440Srrs int old_cwnd = net->cwnd; 2288171440Srrs 2289171440Srrs /* JRS - reset as if the state were being changed to timeout */ 2290219057Srrs htcp_reset(&net->cc_mod.htcp_ca); 2291228653Stuexen net->ssthresh = htcp_recalc_ssthresh(net); 2292171440Srrs net->cwnd = net->mtu; 2293179157Srrs net->partial_bytes_acked = 0; 2294179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2295171440Srrs sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 2296171440Srrs } 2297171440Srrs} 2298171440Srrs 2299217611Stuexenstatic void 2300171440Srrssctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, 2301228653Stuexen struct sctp_nets *net, int in_window, int num_pkt_lost SCTP_UNUSED) 2302171440Srrs{ 2303171440Srrs int old_cwnd; 2304171440Srrs 2305171440Srrs old_cwnd = net->cwnd; 2306171440Srrs 2307171440Srrs /* JRS - reset hctp as if state changed */ 2308218129Srrs if (in_window == 0) { 2309219057Srrs htcp_reset(&net->cc_mod.htcp_ca); 2310218129Srrs SCTP_STAT_INCR(sctps_ecnereducedcwnd); 2311228653Stuexen net->ssthresh = htcp_recalc_ssthresh(net); 2312218129Srrs if (net->ssthresh < net->mtu) { 2313218129Srrs net->ssthresh = net->mtu; 2314218129Srrs /* here back off the timer as well, to slow us down */ 2315218129Srrs net->RTO <<= 1; 2316218129Srrs } 2317218129Srrs net->cwnd = net->ssthresh; 2318279859Stuexen sctp_enforce_cwnd_limit(&stcb->asoc, net); 2319218129Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2320218129Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 2321218129Srrs } 2322171440Srrs } 2323171440Srrs} 2324217611Stuexen 2325297208Stuexenconst struct sctp_cc_functions sctp_cc_functions[] = { 2326217611Stuexen { 2327217611Stuexen .sctp_set_initial_cc_param = sctp_set_initial_cc_param, 2328217611Stuexen .sctp_cwnd_update_after_sack = sctp_cwnd_update_after_sack, 2329224641Stuexen .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, 2330217611Stuexen .sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr, 2331217611Stuexen .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, 2332217611Stuexen .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo, 2333217611Stuexen .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, 2334217611Stuexen .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, 2335217611Stuexen }, 2336217611Stuexen { 2337217611Stuexen .sctp_set_initial_cc_param = sctp_set_initial_cc_param, 2338217611Stuexen .sctp_cwnd_update_after_sack = sctp_hs_cwnd_update_after_sack, 2339224641Stuexen .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, 2340217611Stuexen .sctp_cwnd_update_after_fr = sctp_hs_cwnd_update_after_fr, 2341217611Stuexen .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, 2342217611Stuexen .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo, 2343217611Stuexen .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, 2344217611Stuexen .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, 2345217611Stuexen }, 2346217611Stuexen { 2347217611Stuexen .sctp_set_initial_cc_param = sctp_htcp_set_initial_cc_param, 2348217611Stuexen .sctp_cwnd_update_after_sack = sctp_htcp_cwnd_update_after_sack, 2349224641Stuexen .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, 2350217611Stuexen .sctp_cwnd_update_after_fr = sctp_htcp_cwnd_update_after_fr, 2351217611Stuexen .sctp_cwnd_update_after_timeout = sctp_htcp_cwnd_update_after_timeout, 2352217611Stuexen .sctp_cwnd_update_after_ecn_echo = sctp_htcp_cwnd_update_after_ecn_echo, 2353217611Stuexen .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, 2354217611Stuexen .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, 2355219120Srrs }, 2356219120Srrs { 2357219120Srrs .sctp_set_initial_cc_param = sctp_set_rtcc_initial_cc_param, 2358219120Srrs .sctp_cwnd_update_after_sack = sctp_cwnd_update_rtcc_after_sack, 2359224641Stuexen .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, 2360219120Srrs .sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr, 2361219120Srrs .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, 2362219120Srrs .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_rtcc_after_ecn_echo, 2363219120Srrs .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, 2364219120Srrs .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, 2365219120Srrs .sctp_cwnd_update_packet_transmitted = sctp_cwnd_update_rtcc_packet_transmitted, 2366219120Srrs .sctp_cwnd_update_tsn_acknowledged = sctp_cwnd_update_rtcc_tsn_acknowledged, 2367219120Srrs .sctp_cwnd_new_transmission_begins = sctp_cwnd_new_rtcc_transmission_begins, 2368219120Srrs .sctp_cwnd_prepare_net_for_sack = sctp_cwnd_prepare_rtcc_net_for_sack, 2369219397Srrs .sctp_cwnd_socket_option = sctp_cwnd_rtcc_socket_option, 2370219397Srrs .sctp_rtt_calculated = sctp_rtt_rtcc_calculated 2371217611Stuexen } 2372217611Stuexen}; 2373