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$"); 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 56171440Srrssctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) 57171440Srrs{ 58212800Stuexen struct sctp_association *assoc; 59212800Stuexen uint32_t cwnd_in_mtu; 60212800Stuexen 61212800Stuexen assoc = &stcb->asoc; 62212800Stuexen cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd); 63216672Stuexen if (cwnd_in_mtu == 0) { 64216672Stuexen /* Using 0 means that the value of RFC 4960 is used. */ 65216672Stuexen net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 66216672Stuexen } else { 67216672Stuexen /* 68216672Stuexen * We take the minimum of the burst limit and the initial 69216672Stuexen * congestion window. 70216672Stuexen */ 71216672Stuexen if ((assoc->max_burst > 0) && (cwnd_in_mtu > assoc->max_burst)) 72216672Stuexen cwnd_in_mtu = assoc->max_burst; 73216672Stuexen net->cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu; 74216672Stuexen } 75221460Stuexen if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) || 76221460Stuexen (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2)) { 77217469Stuexen /* In case of resource pooling initialize appropriately */ 78217469Stuexen net->cwnd /= assoc->numnets; 79217469Stuexen if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) { 80217469Stuexen net->cwnd = net->mtu - sizeof(struct sctphdr); 81217469Stuexen } 82217469Stuexen } 83212800Stuexen net->ssthresh = assoc->peers_rwnd; 84215817Srrs SDT_PROBE(sctp, cwnd, net, init, 85215817Srrs stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, 86215817Srrs 0, net->cwnd); 87212800Stuexen if (SCTP_BASE_SYSCTL(sctp_logging_level) & 88212800Stuexen (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { 89171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); 90171440Srrs } 91171440Srrs} 92171440Srrs 93217611Stuexenstatic void 94171440Srrssctp_cwnd_update_after_fr(struct sctp_tcb *stcb, 95171440Srrs struct sctp_association *asoc) 96171440Srrs{ 97171440Srrs struct sctp_nets *net; 98217469Stuexen uint32_t t_ssthresh, t_cwnd; 99221460Stuexen uint64_t t_ucwnd_sbw; 100171440Srrs 101217469Stuexen /* MT FIXME: Don't compute this over and over again */ 102217469Stuexen t_ssthresh = 0; 103217469Stuexen t_cwnd = 0; 104221460Stuexen t_ucwnd_sbw = 0; 105221460Stuexen if ((asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) || 106221460Stuexen (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2)) { 107217469Stuexen TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 108217469Stuexen t_ssthresh += net->ssthresh; 109217469Stuexen t_cwnd += net->cwnd; 110221460Stuexen if (net->lastsa > 0) { 111221460Stuexen t_ucwnd_sbw += (uint64_t) net->cwnd / (uint64_t) net->lastsa; 112221460Stuexen } 113217469Stuexen } 114221460Stuexen if (t_ucwnd_sbw == 0) { 115221460Stuexen t_ucwnd_sbw = 1; 116221460Stuexen } 117217469Stuexen } 118171440Srrs /*- 119216669Stuexen * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) && 120171440Srrs * (net->fast_retran_loss_recovery == 0))) 121171440Srrs */ 122171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 123211944Stuexen if ((asoc->fast_retran_loss_recovery == 0) || 124216669Stuexen (asoc->sctp_cmt_on_off > 0)) { 125171440Srrs /* out of a RFC2582 Fast recovery window? */ 126171440Srrs if (net->net_ack > 0) { 127171440Srrs /* 128171440Srrs * per section 7.2.3, are there any 129171440Srrs * destinations that had a fast retransmit 130171440Srrs * to them. If so what we need to do is 131171440Srrs * adjust ssthresh and cwnd. 132171440Srrs */ 133171440Srrs struct sctp_tmit_chunk *lchk; 134171440Srrs int old_cwnd = net->cwnd; 135171440Srrs 136221460Stuexen if ((asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) || 137221460Stuexen (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2)) { 138221460Stuexen if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) { 139221460Stuexen net->ssthresh = (uint32_t) (((uint64_t) 4 * 140221460Stuexen (uint64_t) net->mtu * 141221460Stuexen (uint64_t) net->ssthresh) / 142221460Stuexen (uint64_t) t_ssthresh); 143221460Stuexen 144221460Stuexen } 145221460Stuexen if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2) { 146221460Stuexen uint32_t srtt; 147221460Stuexen 148221460Stuexen srtt = net->lastsa; 149221460Stuexen /* 150221460Stuexen * lastsa>>3; we don't need 151221460Stuexen * to devide ... 152221460Stuexen */ 153221460Stuexen if (srtt == 0) { 154221460Stuexen srtt = 1; 155221460Stuexen } 156221460Stuexen /* 157221460Stuexen * Short Version => Equal to 158221460Stuexen * Contel Version MBe 159221460Stuexen */ 160221460Stuexen net->ssthresh = (uint32_t) (((uint64_t) 4 * 161221460Stuexen (uint64_t) net->mtu * 162221460Stuexen (uint64_t) net->cwnd) / 163221460Stuexen ((uint64_t) srtt * 164221460Stuexen t_ucwnd_sbw)); 165221460Stuexen /* INCREASE FACTOR */ ; 166221460Stuexen } 167217469Stuexen if ((net->cwnd > t_cwnd / 2) && 168217469Stuexen (net->ssthresh < net->cwnd - t_cwnd / 2)) { 169217469Stuexen net->ssthresh = net->cwnd - t_cwnd / 2; 170217469Stuexen } 171217469Stuexen if (net->ssthresh < net->mtu) { 172217469Stuexen net->ssthresh = net->mtu; 173217469Stuexen } 174217469Stuexen } else { 175217469Stuexen net->ssthresh = net->cwnd / 2; 176217469Stuexen if (net->ssthresh < (net->mtu * 2)) { 177217469Stuexen net->ssthresh = 2 * net->mtu; 178217469Stuexen } 179171440Srrs } 180171440Srrs net->cwnd = net->ssthresh; 181215817Srrs SDT_PROBE(sctp, cwnd, net, fr, 182215817Srrs stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, 183215817Srrs old_cwnd, net->cwnd); 184179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 185171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 186171440Srrs SCTP_CWND_LOG_FROM_FR); 187171440Srrs } 188171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 189171440Srrs 190171440Srrs net->partial_bytes_acked = 0; 191171440Srrs /* Turn on fast recovery window */ 192171440Srrs asoc->fast_retran_loss_recovery = 1; 193171440Srrs if (lchk == NULL) { 194171440Srrs /* Mark end of the window */ 195171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 196171440Srrs } else { 197171440Srrs asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 198171440Srrs } 199171440Srrs 200171440Srrs /* 201171440Srrs * CMT fast recovery -- per destination 202171440Srrs * recovery variable. 203171440Srrs */ 204171440Srrs net->fast_retran_loss_recovery = 1; 205171440Srrs 206171440Srrs if (lchk == NULL) { 207171440Srrs /* Mark end of the window */ 208171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 209171440Srrs } else { 210171440Srrs net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 211171440Srrs } 212171440Srrs 213171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 214171440Srrs stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); 215171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 216171440Srrs stcb->sctp_ep, stcb, net); 217171440Srrs } 218171440Srrs } else if (net->net_ack > 0) { 219171440Srrs /* 220171440Srrs * Mark a peg that we WOULD have done a cwnd 221171440Srrs * reduction but RFC2582 prevented this action. 222171440Srrs */ 223171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 224171440Srrs } 225171440Srrs } 226171440Srrs} 227171440Srrs 228219397Srrs/* Defines for instantaneous bw decisions */ 229219397Srrs#define SCTP_INST_LOOSING 1 /* Loosing to other flows */ 230219397Srrs#define SCTP_INST_NEUTRAL 2 /* Neutral, no indication */ 231219397Srrs#define SCTP_INST_GAINING 3 /* Gaining, step down possible */ 232219120Srrs 233219397Srrs 234219397Srrsstatic int 235219397Srrscc_bw_same(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, 236219397Srrs uint64_t rtt_offset, uint64_t vtag, uint8_t inst_ind) 237219397Srrs{ 238219397Srrs uint64_t oth, probepoint; 239219397Srrs 240219397Srrs probepoint = (((uint64_t) net->cwnd) << 32); 241219397Srrs if (net->rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) { 242219397Srrs /* 243219397Srrs * rtt increased we don't update bw.. so we don't update the 244219397Srrs * rtt either. 245219397Srrs */ 246219397Srrs /* Probe point 5 */ 247219397Srrs probepoint |= ((5 << 16) | 1); 248219397Srrs SDT_PROBE(sctp, cwnd, net, rttvar, 249219397Srrs vtag, 250219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 251219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 252219397Srrs net->flight_size, 253219397Srrs probepoint); 254219397Srrs if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) { 255219397Srrs if (net->cc_mod.rtcc.last_step_state == 5) 256219397Srrs net->cc_mod.rtcc.step_cnt++; 257219397Srrs else 258219397Srrs net->cc_mod.rtcc.step_cnt = 1; 259219397Srrs net->cc_mod.rtcc.last_step_state = 5; 260219397Srrs if ((net->cc_mod.rtcc.step_cnt == net->cc_mod.rtcc.steady_step) || 261219397Srrs ((net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step) && 262219397Srrs ((net->cc_mod.rtcc.step_cnt % net->cc_mod.rtcc.steady_step) == 0))) { 263219397Srrs /* Try a step down */ 264219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 265219397Srrs oth <<= 16; 266219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 267219397Srrs oth <<= 16; 268219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 269219397Srrs SDT_PROBE(sctp, cwnd, net, rttstep, 270219397Srrs vtag, 271219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 272219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 273219397Srrs oth, 274219397Srrs probepoint); 275219397Srrs if (net->cwnd > (4 * net->mtu)) { 276219397Srrs net->cwnd -= net->mtu; 277219397Srrs net->cc_mod.rtcc.vol_reduce++; 278219397Srrs } else { 279219397Srrs net->cc_mod.rtcc.step_cnt = 0; 280219397Srrs } 281219397Srrs } 282219397Srrs } 283219397Srrs return (1); 284219397Srrs } 285219397Srrs if (net->rtt < net->cc_mod.rtcc.lbw_rtt - rtt_offset) { 286219397Srrs /* 287219397Srrs * rtt decreased, there could be more room. we update both 288219397Srrs * the bw and the rtt here to lock this in as a good step 289219397Srrs * down. 290219397Srrs */ 291219397Srrs /* Probe point 6 */ 292219397Srrs probepoint |= ((6 << 16) | 0); 293219397Srrs SDT_PROBE(sctp, cwnd, net, rttvar, 294219397Srrs vtag, 295219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 296219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 297219397Srrs net->flight_size, 298219397Srrs probepoint); 299219397Srrs if (net->cc_mod.rtcc.steady_step) { 300219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 301219397Srrs oth <<= 16; 302219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 303219397Srrs oth <<= 16; 304219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 305219397Srrs SDT_PROBE(sctp, cwnd, net, rttstep, 306219397Srrs vtag, 307219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 308219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 309219397Srrs oth, 310219397Srrs probepoint); 311219397Srrs if ((net->cc_mod.rtcc.last_step_state == 5) && 312219397Srrs (net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step)) { 313219397Srrs /* Step down worked */ 314219397Srrs net->cc_mod.rtcc.step_cnt = 0; 315219397Srrs return (1); 316219397Srrs } else { 317219397Srrs net->cc_mod.rtcc.last_step_state = 6; 318219397Srrs net->cc_mod.rtcc.step_cnt = 0; 319219397Srrs } 320219397Srrs } 321219397Srrs net->cc_mod.rtcc.lbw = nbw; 322219397Srrs net->cc_mod.rtcc.lbw_rtt = net->rtt; 323219397Srrs net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd; 324219397Srrs if (inst_ind == SCTP_INST_GAINING) 325219397Srrs return (1); 326219397Srrs else if (inst_ind == SCTP_INST_NEUTRAL) 327219397Srrs return (1); 328219397Srrs else 329219397Srrs return (0); 330219397Srrs } 331219397Srrs /* 332219397Srrs * Ok bw and rtt remained the same .. no update to any 333219397Srrs */ 334219397Srrs /* Probe point 7 */ 335219397Srrs probepoint |= ((7 << 16) | net->cc_mod.rtcc.ret_from_eq); 336219397Srrs SDT_PROBE(sctp, cwnd, net, rttvar, 337219397Srrs vtag, 338219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 339219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 340219397Srrs net->flight_size, 341219397Srrs probepoint); 342219397Srrs if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) { 343219397Srrs if (net->cc_mod.rtcc.last_step_state == 5) 344219397Srrs net->cc_mod.rtcc.step_cnt++; 345219397Srrs else 346219397Srrs net->cc_mod.rtcc.step_cnt = 1; 347219397Srrs net->cc_mod.rtcc.last_step_state = 5; 348219397Srrs if ((net->cc_mod.rtcc.step_cnt == net->cc_mod.rtcc.steady_step) || 349219397Srrs ((net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step) && 350219397Srrs ((net->cc_mod.rtcc.step_cnt % net->cc_mod.rtcc.steady_step) == 0))) { 351219397Srrs /* Try a step down */ 352219397Srrs if (net->cwnd > (4 * net->mtu)) { 353219397Srrs net->cwnd -= net->mtu; 354219397Srrs net->cc_mod.rtcc.vol_reduce++; 355219397Srrs return (1); 356219397Srrs } else { 357219397Srrs net->cc_mod.rtcc.step_cnt = 0; 358219397Srrs } 359219397Srrs } 360219397Srrs } 361219397Srrs if (inst_ind == SCTP_INST_GAINING) 362219397Srrs return (1); 363219397Srrs else if (inst_ind == SCTP_INST_NEUTRAL) 364219397Srrs return (1); 365219397Srrs else 366219397Srrs return ((int)net->cc_mod.rtcc.ret_from_eq); 367219397Srrs} 368219397Srrs 369219397Srrsstatic int 370219397Srrscc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t rtt_offset, 371219397Srrs uint64_t vtag, uint8_t inst_ind) 372219397Srrs{ 373219397Srrs uint64_t oth, probepoint; 374219397Srrs 375219397Srrs /* Bandwidth decreased. */ 376219397Srrs probepoint = (((uint64_t) net->cwnd) << 32); 377219397Srrs if (net->rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) { 378219397Srrs /* rtt increased */ 379219397Srrs /* Did we add more */ 380219397Srrs if ((net->cwnd > net->cc_mod.rtcc.cwnd_at_bw_set) && 381219397Srrs (inst_ind != SCTP_INST_LOOSING)) { 382219397Srrs /* We caused it maybe.. back off? */ 383219397Srrs /* PROBE POINT 1 */ 384219397Srrs probepoint |= ((1 << 16) | 1); 385219397Srrs SDT_PROBE(sctp, cwnd, net, rttvar, 386219397Srrs vtag, 387219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 388219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 389219397Srrs net->flight_size, 390219397Srrs probepoint); 391219397Srrs if (net->cc_mod.rtcc.ret_from_eq) { 392219397Srrs /* 393219397Srrs * Switch over to CA if we are less 394219397Srrs * aggressive 395219397Srrs */ 396219397Srrs net->ssthresh = net->cwnd - 1; 397219397Srrs net->partial_bytes_acked = 0; 398219397Srrs } 399219397Srrs return (1); 400219397Srrs } 401219397Srrs /* Probe point 2 */ 402219397Srrs probepoint |= ((2 << 16) | 0); 403219397Srrs SDT_PROBE(sctp, cwnd, net, rttvar, 404219397Srrs vtag, 405219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 406219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 407219397Srrs net->flight_size, 408219397Srrs probepoint); 409219397Srrs /* Someone else - fight for more? */ 410219397Srrs if (net->cc_mod.rtcc.steady_step) { 411219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 412219397Srrs oth <<= 16; 413219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 414219397Srrs oth <<= 16; 415219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 416219397Srrs SDT_PROBE(sctp, cwnd, net, rttstep, 417219397Srrs vtag, 418219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 419219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 420219397Srrs oth, 421219397Srrs probepoint); 422219397Srrs /* 423219397Srrs * Did we voluntarily give up some? if so take one 424219397Srrs * back please 425219397Srrs */ 426219397Srrs if ((net->cc_mod.rtcc.vol_reduce) && 427219397Srrs (inst_ind != SCTP_INST_GAINING)) { 428219397Srrs net->cwnd += net->mtu; 429219397Srrs net->cc_mod.rtcc.vol_reduce--; 430219397Srrs } 431219397Srrs net->cc_mod.rtcc.last_step_state = 2; 432219397Srrs net->cc_mod.rtcc.step_cnt = 0; 433219397Srrs } 434219397Srrs goto out_decision; 435219397Srrs } else if (net->rtt < net->cc_mod.rtcc.lbw_rtt - rtt_offset) { 436219397Srrs /* bw & rtt decreased */ 437219397Srrs /* Probe point 3 */ 438219397Srrs probepoint |= ((3 << 16) | 0); 439219397Srrs SDT_PROBE(sctp, cwnd, net, rttvar, 440219397Srrs vtag, 441219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 442219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 443219397Srrs net->flight_size, 444219397Srrs probepoint); 445219397Srrs if (net->cc_mod.rtcc.steady_step) { 446219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 447219397Srrs oth <<= 16; 448219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 449219397Srrs oth <<= 16; 450219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 451219397Srrs SDT_PROBE(sctp, cwnd, net, rttstep, 452219397Srrs vtag, 453219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 454219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 455219397Srrs oth, 456219397Srrs probepoint); 457219397Srrs if ((net->cc_mod.rtcc.vol_reduce) && 458219397Srrs (inst_ind != SCTP_INST_GAINING)) { 459219397Srrs net->cwnd += net->mtu; 460219397Srrs net->cc_mod.rtcc.vol_reduce--; 461219397Srrs } 462219397Srrs net->cc_mod.rtcc.last_step_state = 3; 463219397Srrs net->cc_mod.rtcc.step_cnt = 0; 464219397Srrs } 465219397Srrs goto out_decision; 466219397Srrs } 467219397Srrs /* The bw decreased but rtt stayed the same */ 468219397Srrs /* Probe point 4 */ 469219397Srrs probepoint |= ((4 << 16) | 0); 470219397Srrs SDT_PROBE(sctp, cwnd, net, rttvar, 471219397Srrs vtag, 472219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 473219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 474219397Srrs net->flight_size, 475219397Srrs probepoint); 476219397Srrs if (net->cc_mod.rtcc.steady_step) { 477219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 478219397Srrs oth <<= 16; 479219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 480219397Srrs oth <<= 16; 481219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 482219397Srrs SDT_PROBE(sctp, cwnd, net, rttstep, 483219397Srrs vtag, 484219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 485219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 486219397Srrs oth, 487219397Srrs probepoint); 488219397Srrs if ((net->cc_mod.rtcc.vol_reduce) && 489219397Srrs (inst_ind != SCTP_INST_GAINING)) { 490219397Srrs net->cwnd += net->mtu; 491219397Srrs net->cc_mod.rtcc.vol_reduce--; 492219397Srrs } 493219397Srrs net->cc_mod.rtcc.last_step_state = 4; 494219397Srrs net->cc_mod.rtcc.step_cnt = 0; 495219397Srrs } 496219397Srrsout_decision: 497219397Srrs net->cc_mod.rtcc.lbw = nbw; 498219397Srrs net->cc_mod.rtcc.lbw_rtt = net->rtt; 499219397Srrs net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd; 500219397Srrs if (inst_ind == SCTP_INST_GAINING) { 501219397Srrs return (1); 502219397Srrs } else { 503219397Srrs return (0); 504219397Srrs } 505219397Srrs} 506219397Srrs 507219397Srrsstatic int 508228653Stuexencc_bw_increase(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t vtag) 509219397Srrs{ 510219397Srrs uint64_t oth, probepoint; 511219397Srrs 512219397Srrs /* 513219397Srrs * BW increased, so update and return 0, since all actions in our 514219397Srrs * table say to do the normal CC update. Note that we pay no 515219397Srrs * attention to the inst_ind since our overall sum is increasing. 516219397Srrs */ 517219397Srrs /* PROBE POINT 0 */ 518219397Srrs probepoint = (((uint64_t) net->cwnd) << 32); 519219397Srrs SDT_PROBE(sctp, cwnd, net, rttvar, 520219397Srrs vtag, 521219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 522219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 523219397Srrs net->flight_size, 524219397Srrs probepoint); 525219397Srrs if (net->cc_mod.rtcc.steady_step) { 526219397Srrs oth = net->cc_mod.rtcc.vol_reduce; 527219397Srrs oth <<= 16; 528219397Srrs oth |= net->cc_mod.rtcc.step_cnt; 529219397Srrs oth <<= 16; 530219397Srrs oth |= net->cc_mod.rtcc.last_step_state; 531219397Srrs SDT_PROBE(sctp, cwnd, net, rttstep, 532219397Srrs vtag, 533219397Srrs ((net->cc_mod.rtcc.lbw << 32) | nbw), 534219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 535219397Srrs oth, 536219397Srrs probepoint); 537219397Srrs net->cc_mod.rtcc.last_step_state = 0; 538219397Srrs net->cc_mod.rtcc.step_cnt = 0; 539219397Srrs net->cc_mod.rtcc.vol_reduce = 0; 540219397Srrs } 541219397Srrs net->cc_mod.rtcc.lbw = nbw; 542219397Srrs net->cc_mod.rtcc.lbw_rtt = net->rtt; 543219397Srrs net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd; 544219397Srrs return (0); 545219397Srrs} 546219397Srrs 547219120Srrs/* RTCC Algoritm to limit growth of cwnd, return 548219120Srrs * true if you want to NOT allow cwnd growth 549219120Srrs */ 550219120Srrsstatic int 551219120Srrscc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw) 552219120Srrs{ 553228907Stuexen uint64_t bw_offset, rtt_offset; 554228907Stuexen uint64_t probepoint, rtt, vtag; 555219397Srrs uint64_t bytes_for_this_rtt, inst_bw; 556219397Srrs uint64_t div, inst_off; 557219397Srrs int bw_shift; 558219397Srrs uint8_t inst_ind; 559219397Srrs int ret; 560219120Srrs 561219120Srrs /*- 562219120Srrs * Here we need to see if we want 563219120Srrs * to limit cwnd growth due to increase 564219120Srrs * in overall rtt but no increase in bw. 565219120Srrs * We use the following table to figure 566219120Srrs * out what we should do. When we return 567219120Srrs * 0, cc update goes on as planned. If we 568219120Srrs * return 1, then no cc update happens and cwnd 569219120Srrs * stays where it is at. 570219120Srrs * ---------------------------------- 571219120Srrs * BW | RTT | Action 572219120Srrs * ********************************* 573219120Srrs * INC | INC | return 0 574219120Srrs * ---------------------------------- 575219120Srrs * INC | SAME | return 0 576219120Srrs * ---------------------------------- 577219120Srrs * INC | DECR | return 0 578219120Srrs * ---------------------------------- 579219120Srrs * SAME | INC | return 1 580219120Srrs * ---------------------------------- 581219120Srrs * SAME | SAME | return 1 582219120Srrs * ---------------------------------- 583219120Srrs * SAME | DECR | return 0 584219120Srrs * ---------------------------------- 585219120Srrs * DECR | INC | return 0 or 1 based on if we caused. 586219120Srrs * ---------------------------------- 587219120Srrs * DECR | SAME | return 0 588219120Srrs * ---------------------------------- 589219120Srrs * DECR | DECR | return 0 590219120Srrs * ---------------------------------- 591219120Srrs * 592219120Srrs * We are a bit fuzz on what an increase or 593219120Srrs * decrease is. For BW it is the same if 594219120Srrs * it did not change within 1/64th. For 595219120Srrs * RTT it stayed the same if it did not 596219120Srrs * change within 1/32nd 597219120Srrs */ 598219397Srrs bw_shift = SCTP_BASE_SYSCTL(sctp_rttvar_bw); 599219120Srrs rtt = stcb->asoc.my_vtag; 600219120Srrs vtag = (rtt << 32) | (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) | (stcb->rport); 601219120Srrs probepoint = (((uint64_t) net->cwnd) << 32); 602219120Srrs rtt = net->rtt; 603219397Srrs if (net->cc_mod.rtcc.rtt_set_this_sack) { 604219397Srrs net->cc_mod.rtcc.rtt_set_this_sack = 0; 605219397Srrs bytes_for_this_rtt = net->cc_mod.rtcc.bw_bytes - net->cc_mod.rtcc.bw_bytes_at_last_rttc; 606219397Srrs net->cc_mod.rtcc.bw_bytes_at_last_rttc = net->cc_mod.rtcc.bw_bytes; 607219397Srrs if (net->rtt) { 608219397Srrs div = net->rtt / 1000; 609219397Srrs if (div) { 610219397Srrs inst_bw = bytes_for_this_rtt / div; 611219397Srrs inst_off = inst_bw >> bw_shift; 612219397Srrs if (inst_bw > nbw) 613219397Srrs inst_ind = SCTP_INST_GAINING; 614219397Srrs else if ((inst_bw + inst_off) < nbw) 615219397Srrs inst_ind = SCTP_INST_LOOSING; 616219397Srrs else 617219397Srrs inst_ind = SCTP_INST_NEUTRAL; 618219397Srrs probepoint |= ((0xb << 16) | inst_ind); 619219397Srrs } else { 620228907Stuexen inst_ind = net->cc_mod.rtcc.last_inst_ind; 621219397Srrs inst_bw = bytes_for_this_rtt / (uint64_t) (net->rtt); 622219397Srrs /* Can't determine do not change */ 623219397Srrs probepoint |= ((0xc << 16) | inst_ind); 624219397Srrs } 625219397Srrs } else { 626228907Stuexen inst_ind = net->cc_mod.rtcc.last_inst_ind; 627219397Srrs inst_bw = bytes_for_this_rtt; 628219397Srrs /* Can't determine do not change */ 629219397Srrs probepoint |= ((0xd << 16) | inst_ind); 630219397Srrs } 631219120Srrs SDT_PROBE(sctp, cwnd, net, rttvar, 632219120Srrs vtag, 633219397Srrs ((nbw << 32) | inst_bw), 634219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | rtt), 635219397Srrs net->flight_size, 636219120Srrs probepoint); 637219397Srrs } else { 638219397Srrs /* No rtt measurement, use last one */ 639219397Srrs inst_ind = net->cc_mod.rtcc.last_inst_ind; 640219120Srrs } 641219397Srrs bw_offset = net->cc_mod.rtcc.lbw >> bw_shift; 642219397Srrs if (nbw > net->cc_mod.rtcc.lbw + bw_offset) { 643228653Stuexen ret = cc_bw_increase(stcb, net, nbw, vtag); 644219397Srrs goto out; 645219397Srrs } 646219120Srrs rtt_offset = net->cc_mod.rtcc.lbw_rtt >> SCTP_BASE_SYSCTL(sctp_rttvar_rtt); 647219120Srrs if (nbw < net->cc_mod.rtcc.lbw - bw_offset) { 648219397Srrs ret = cc_bw_decrease(stcb, net, nbw, rtt_offset, vtag, inst_ind); 649219397Srrs goto out; 650219120Srrs } 651219120Srrs /* 652219120Srrs * If we reach here then we are in a situation where the bw stayed 653219120Srrs * the same. 654219120Srrs */ 655219397Srrs ret = cc_bw_same(stcb, net, nbw, rtt_offset, vtag, inst_ind); 656219397Srrsout: 657219397Srrs net->cc_mod.rtcc.last_inst_ind = inst_ind; 658219397Srrs return (ret); 659219120Srrs} 660219120Srrs 661217611Stuexenstatic void 662219120Srrssctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, 663171440Srrs struct sctp_association *asoc, 664228653Stuexen int accum_moved, int reneged_all SCTP_UNUSED, int will_exit, int use_rtcc) 665171440Srrs{ 666171440Srrs struct sctp_nets *net; 667215817Srrs int old_cwnd; 668217469Stuexen uint32_t t_ssthresh, t_cwnd, incr; 669221460Stuexen uint64_t t_ucwnd_sbw; 670221460Stuexen uint64_t t_path_mptcp; 671221460Stuexen uint64_t mptcp_like_alpha; 672221460Stuexen uint32_t srtt; 673221460Stuexen uint64_t max_path; 674171440Srrs 675217469Stuexen /* MT FIXME: Don't compute this over and over again */ 676217469Stuexen t_ssthresh = 0; 677217469Stuexen t_cwnd = 0; 678221460Stuexen t_ucwnd_sbw = 0; 679221460Stuexen t_path_mptcp = 0; 680221460Stuexen mptcp_like_alpha = 1; 681221460Stuexen if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) || 682221460Stuexen (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2) || 683221460Stuexen (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_MPTCP)) { 684221460Stuexen max_path = 0; 685217469Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 686217469Stuexen t_ssthresh += net->ssthresh; 687217469Stuexen t_cwnd += net->cwnd; 688221460Stuexen /* lastsa>>3; we don't need to devide ... */ 689221460Stuexen srtt = net->lastsa; 690221460Stuexen if (srtt > 0) { 691221460Stuexen uint64_t tmp; 692221460Stuexen 693221460Stuexen t_ucwnd_sbw += (uint64_t) net->cwnd / (uint64_t) srtt; 694221460Stuexen t_path_mptcp += (((uint64_t) net->cwnd) << SHIFT_MPTCP_MULTI_Z) / 695221460Stuexen (((uint64_t) net->mtu) * (uint64_t) srtt); 696221460Stuexen tmp = (((uint64_t) net->cwnd) << SHIFT_MPTCP_MULTI_N) / 697221460Stuexen ((uint64_t) net->mtu * (uint64_t) (srtt * srtt)); 698221460Stuexen if (tmp > max_path) { 699221460Stuexen max_path = tmp; 700221460Stuexen } 701221460Stuexen } 702217469Stuexen } 703221460Stuexen if (t_path_mptcp > 0) { 704221460Stuexen mptcp_like_alpha = max_path / (t_path_mptcp * t_path_mptcp); 705221460Stuexen } else { 706221460Stuexen mptcp_like_alpha = 1; 707221460Stuexen } 708217469Stuexen } 709228907Stuexen if (t_ssthresh == 0) { 710228907Stuexen t_ssthresh = 1; 711228907Stuexen } 712228907Stuexen if (t_ucwnd_sbw == 0) { 713228907Stuexen t_ucwnd_sbw = 1; 714228907Stuexen } 715171440Srrs /******************************/ 716171440Srrs /* update cwnd and Early FR */ 717171440Srrs /******************************/ 718171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 719171440Srrs 720171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 721171440Srrs /* 722171440Srrs * CMT fast recovery code. Need to debug. 723171440Srrs */ 724171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 725217469Stuexen if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) || 726217469Stuexen SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) { 727171440Srrs net->will_exit_fast_recovery = 1; 728171440Srrs } 729171440Srrs } 730171440Srrs#endif 731171440Srrs /* if nothing was acked on this destination skip it */ 732171440Srrs if (net->net_ack == 0) { 733179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 734171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 735171440Srrs } 736171440Srrs continue; 737171440Srrs } 738171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 739171440Srrs /* 740171440Srrs * CMT fast recovery code 741171440Srrs */ 742171440Srrs /* 743216669Stuexen * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery 744216669Stuexen * && net->will_exit_fast_recovery == 0) { @@@ Do something 745216669Stuexen * } else if (sctp_cmt_on_off == 0 && 746171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 747171440Srrs */ 748171440Srrs#endif 749171440Srrs 750211944Stuexen if (asoc->fast_retran_loss_recovery && 751211944Stuexen (will_exit == 0) && 752211944Stuexen (asoc->sctp_cmt_on_off == 0)) { 753171440Srrs /* 754171440Srrs * If we are in loss recovery we skip any cwnd 755171440Srrs * update 756171440Srrs */ 757224641Stuexen return; 758171440Srrs } 759171440Srrs /* 760219120Srrs * Did any measurements go on for this network? 761219120Srrs */ 762219120Srrs if (use_rtcc && (net->cc_mod.rtcc.tls_needs_set > 0)) { 763219120Srrs uint64_t nbw; 764219120Srrs 765219120Srrs /* 766219120Srrs * At this point our bw_bytes has been updated by 767219120Srrs * incoming sack information. 768219120Srrs * 769219120Srrs * But our bw may not yet be set. 770219120Srrs * 771219120Srrs */ 772219120Srrs if ((net->cc_mod.rtcc.new_tot_time / 1000) > 0) { 773219120Srrs nbw = net->cc_mod.rtcc.bw_bytes / (net->cc_mod.rtcc.new_tot_time / 1000); 774219120Srrs } else { 775219120Srrs nbw = net->cc_mod.rtcc.bw_bytes; 776219120Srrs } 777219120Srrs if (net->cc_mod.rtcc.lbw) { 778219120Srrs if (cc_bw_limit(stcb, net, nbw)) { 779219120Srrs /* Hold here, no update */ 780224641Stuexen continue; 781219120Srrs } 782219120Srrs } else { 783219120Srrs uint64_t vtag, probepoint; 784219120Srrs 785219120Srrs probepoint = (((uint64_t) net->cwnd) << 32); 786219120Srrs probepoint |= ((0xa << 16) | 0); 787219120Srrs vtag = (net->rtt << 32) | 788219120Srrs (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) | 789219120Srrs (stcb->rport); 790219120Srrs 791219120Srrs SDT_PROBE(sctp, cwnd, net, rttvar, 792219120Srrs vtag, 793219120Srrs nbw, 794219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 795219397Srrs net->flight_size, 796219120Srrs probepoint); 797219120Srrs net->cc_mod.rtcc.lbw = nbw; 798219120Srrs net->cc_mod.rtcc.lbw_rtt = net->rtt; 799219397Srrs if (net->cc_mod.rtcc.rtt_set_this_sack) { 800219397Srrs net->cc_mod.rtcc.rtt_set_this_sack = 0; 801219397Srrs net->cc_mod.rtcc.bw_bytes_at_last_rttc = net->cc_mod.rtcc.bw_bytes; 802219397Srrs } 803219120Srrs } 804219120Srrs } 805219120Srrs /* 806171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 807171440Srrs * moved. 808171440Srrs */ 809211944Stuexen if (accum_moved || 810216669Stuexen ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) { 811171440Srrs /* If the cumulative ack moved we can proceed */ 812171440Srrs if (net->cwnd <= net->ssthresh) { 813171440Srrs /* We are in slow start */ 814179157Srrs if (net->flight_size + net->net_ack >= net->cwnd) { 815221460Stuexen uint32_t limit; 816221460Stuexen 817217469Stuexen old_cwnd = net->cwnd; 818221460Stuexen switch (asoc->sctp_cmt_on_off) { 819221460Stuexen case SCTP_CMT_RPV1: 820217469Stuexen limit = (uint32_t) (((uint64_t) net->mtu * 821217469Stuexen (uint64_t) SCTP_BASE_SYSCTL(sctp_L2_abc_variable) * 822217469Stuexen (uint64_t) net->ssthresh) / 823217469Stuexen (uint64_t) t_ssthresh); 824217469Stuexen incr = (uint32_t) (((uint64_t) net->net_ack * 825217469Stuexen (uint64_t) net->ssthresh) / 826217469Stuexen (uint64_t) t_ssthresh); 827217469Stuexen if (incr > limit) { 828217469Stuexen incr = limit; 829171440Srrs } 830217469Stuexen if (incr == 0) { 831217469Stuexen incr = 1; 832217469Stuexen } 833221460Stuexen break; 834221460Stuexen case SCTP_CMT_RPV2: 835221460Stuexen /* 836221460Stuexen * lastsa>>3; we don't need 837221460Stuexen * to divide ... 838221460Stuexen */ 839221460Stuexen srtt = net->lastsa; 840221460Stuexen if (srtt == 0) { 841221460Stuexen srtt = 1; 842221460Stuexen } 843221460Stuexen limit = (uint32_t) (((uint64_t) net->mtu * 844221460Stuexen (uint64_t) SCTP_BASE_SYSCTL(sctp_L2_abc_variable) * 845221460Stuexen (uint64_t) net->cwnd) / 846221460Stuexen ((uint64_t) srtt * t_ucwnd_sbw)); 847221460Stuexen /* INCREASE FACTOR */ 848221460Stuexen incr = (uint32_t) (((uint64_t) net->net_ack * 849221460Stuexen (uint64_t) net->cwnd) / 850221460Stuexen ((uint64_t) srtt * t_ucwnd_sbw)); 851221460Stuexen /* INCREASE FACTOR */ 852221460Stuexen if (incr > limit) { 853221460Stuexen incr = limit; 854221460Stuexen } 855221460Stuexen if (incr == 0) { 856221460Stuexen incr = 1; 857221460Stuexen } 858221460Stuexen break; 859221460Stuexen case SCTP_CMT_MPTCP: 860221460Stuexen limit = (uint32_t) (((uint64_t) net->mtu * 861221460Stuexen mptcp_like_alpha * 862221460Stuexen (uint64_t) SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) >> 863221460Stuexen SHIFT_MPTCP_MULTI); 864221460Stuexen incr = (uint32_t) (((uint64_t) net->net_ack * 865221460Stuexen mptcp_like_alpha) >> 866221460Stuexen SHIFT_MPTCP_MULTI); 867221460Stuexen if (incr > limit) { 868221460Stuexen incr = limit; 869221460Stuexen } 870221460Stuexen if (incr > net->net_ack) { 871221460Stuexen incr = net->net_ack; 872221460Stuexen } 873221460Stuexen if (incr > net->mtu) { 874221460Stuexen incr = net->mtu; 875221460Stuexen } 876221460Stuexen break; 877221460Stuexen default: 878217469Stuexen incr = net->net_ack; 879217469Stuexen if (incr > net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) { 880217469Stuexen incr = net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable); 881171440Srrs } 882221460Stuexen break; 883171440Srrs } 884217469Stuexen net->cwnd += incr; 885217469Stuexen if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 886217469Stuexen sctp_log_cwnd(stcb, net, incr, 887217469Stuexen SCTP_CWND_LOG_FROM_SS); 888217469Stuexen } 889217469Stuexen SDT_PROBE(sctp, cwnd, net, ack, 890217469Stuexen stcb->asoc.my_vtag, 891217469Stuexen ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 892217469Stuexen net, 893217469Stuexen old_cwnd, net->cwnd); 894171440Srrs } else { 895179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 896171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 897171440Srrs SCTP_CWND_LOG_NOADV_SS); 898171440Srrs } 899171440Srrs } 900171440Srrs } else { 901171440Srrs /* We are in congestion avoidance */ 902179141Srrs /* 903179141Srrs * Add to pba 904179141Srrs */ 905179157Srrs net->partial_bytes_acked += net->net_ack; 906171440Srrs 907179141Srrs if ((net->flight_size + net->net_ack >= net->cwnd) && 908179141Srrs (net->partial_bytes_acked >= net->cwnd)) { 909179141Srrs net->partial_bytes_acked -= net->cwnd; 910215817Srrs old_cwnd = net->cwnd; 911221460Stuexen switch (asoc->sctp_cmt_on_off) { 912221460Stuexen case SCTP_CMT_RPV1: 913217469Stuexen incr = (uint32_t) (((uint64_t) net->mtu * 914217469Stuexen (uint64_t) net->ssthresh) / 915217469Stuexen (uint64_t) t_ssthresh); 916217469Stuexen if (incr == 0) { 917217469Stuexen incr = 1; 918217469Stuexen } 919221460Stuexen break; 920221460Stuexen case SCTP_CMT_RPV2: 921221460Stuexen /* 922221460Stuexen * lastsa>>3; we don't need 923221460Stuexen * to divide ... 924221460Stuexen */ 925221460Stuexen srtt = net->lastsa; 926221460Stuexen if (srtt == 0) { 927221460Stuexen srtt = 1; 928221460Stuexen } 929221460Stuexen incr = (uint32_t) ((uint64_t) net->mtu * 930221460Stuexen (uint64_t) net->cwnd / 931221460Stuexen ((uint64_t) srtt * 932221460Stuexen t_ucwnd_sbw)); 933221460Stuexen /* INCREASE FACTOR */ 934221460Stuexen if (incr == 0) { 935221460Stuexen incr = 1; 936221460Stuexen } 937221460Stuexen break; 938221460Stuexen case SCTP_CMT_MPTCP: 939221460Stuexen incr = (uint32_t) ((mptcp_like_alpha * 940221460Stuexen (uint64_t) net->cwnd) >> 941221460Stuexen SHIFT_MPTCP_MULTI); 942221460Stuexen if (incr > net->mtu) { 943221460Stuexen incr = net->mtu; 944221460Stuexen } 945221460Stuexen break; 946221460Stuexen default: 947217469Stuexen incr = net->mtu; 948221460Stuexen break; 949217469Stuexen } 950217469Stuexen net->cwnd += incr; 951215817Srrs SDT_PROBE(sctp, cwnd, net, ack, 952215817Srrs stcb->asoc.my_vtag, 953215817Srrs ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 954215817Srrs net, 955215817Srrs old_cwnd, net->cwnd); 956179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 957179141Srrs sctp_log_cwnd(stcb, net, net->mtu, 958179141Srrs SCTP_CWND_LOG_FROM_CA); 959171440Srrs } 960171440Srrs } else { 961179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 962171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 963171440Srrs SCTP_CWND_LOG_NOADV_CA); 964171440Srrs } 965171440Srrs } 966171440Srrs } 967171440Srrs } else { 968179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 969171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 970171440Srrs SCTP_CWND_LOG_NO_CUMACK); 971171440Srrs } 972171440Srrs } 973171440Srrs } 974171440Srrs} 975171440Srrs 976217611Stuexenstatic void 977224641Stuexensctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb, struct sctp_nets *net) 978224641Stuexen{ 979224641Stuexen int old_cwnd; 980224641Stuexen 981224641Stuexen old_cwnd = net->cwnd; 982224641Stuexen net->cwnd = net->mtu; 983224641Stuexen SDT_PROBE(sctp, cwnd, net, ack, 984224641Stuexen stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, 985224641Stuexen old_cwnd, net->cwnd); 986224641Stuexen SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", 987240148Stuexen (void *)net, net->cwnd); 988224641Stuexen} 989224641Stuexen 990224641Stuexen 991224641Stuexenstatic void 992179157Srrssctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net) 993171440Srrs{ 994171440Srrs int old_cwnd = net->cwnd; 995217469Stuexen uint32_t t_ssthresh, t_cwnd; 996221460Stuexen uint64_t t_ucwnd_sbw; 997171440Srrs 998217469Stuexen /* MT FIXME: Don't compute this over and over again */ 999217469Stuexen t_ssthresh = 0; 1000217469Stuexen t_cwnd = 0; 1001221460Stuexen if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) || 1002221460Stuexen (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2)) { 1003217469Stuexen struct sctp_nets *lnet; 1004221460Stuexen uint32_t srtt; 1005217469Stuexen 1006221460Stuexen t_ucwnd_sbw = 0; 1007217469Stuexen TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 1008217469Stuexen t_ssthresh += lnet->ssthresh; 1009217469Stuexen t_cwnd += lnet->cwnd; 1010221460Stuexen srtt = lnet->lastsa; 1011221460Stuexen /* lastsa>>3; we don't need to divide ... */ 1012221460Stuexen if (srtt > 0) { 1013221460Stuexen t_ucwnd_sbw += (uint64_t) lnet->cwnd / (uint64_t) srtt; 1014221460Stuexen } 1015217469Stuexen } 1016228907Stuexen if (t_ssthresh < 1) { 1017228907Stuexen t_ssthresh = 1; 1018228907Stuexen } 1019221460Stuexen if (t_ucwnd_sbw < 1) { 1020221460Stuexen t_ucwnd_sbw = 1; 1021221460Stuexen } 1022221460Stuexen if (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) { 1023221460Stuexen net->ssthresh = (uint32_t) (((uint64_t) 4 * 1024221460Stuexen (uint64_t) net->mtu * 1025221460Stuexen (uint64_t) net->ssthresh) / 1026221460Stuexen (uint64_t) t_ssthresh); 1027221460Stuexen } else { 1028221460Stuexen uint64_t cc_delta; 1029221460Stuexen 1030221460Stuexen srtt = net->lastsa; 1031221460Stuexen /* lastsa>>3; we don't need to divide ... */ 1032221460Stuexen if (srtt == 0) { 1033221460Stuexen srtt = 1; 1034221460Stuexen } 1035221460Stuexen cc_delta = t_ucwnd_sbw * (uint64_t) srtt / 2; 1036221460Stuexen if (cc_delta < t_cwnd) { 1037221460Stuexen net->ssthresh = (uint32_t) ((uint64_t) t_cwnd - cc_delta); 1038221460Stuexen } else { 1039221460Stuexen net->ssthresh = net->mtu; 1040221460Stuexen } 1041221460Stuexen } 1042217469Stuexen if ((net->cwnd > t_cwnd / 2) && 1043217469Stuexen (net->ssthresh < net->cwnd - t_cwnd / 2)) { 1044217469Stuexen net->ssthresh = net->cwnd - t_cwnd / 2; 1045217469Stuexen } 1046217469Stuexen if (net->ssthresh < net->mtu) { 1047217469Stuexen net->ssthresh = net->mtu; 1048217469Stuexen } 1049217469Stuexen } else { 1050217469Stuexen net->ssthresh = max(net->cwnd / 2, 4 * net->mtu); 1051217469Stuexen } 1052171440Srrs net->cwnd = net->mtu; 1053179157Srrs net->partial_bytes_acked = 0; 1054215817Srrs SDT_PROBE(sctp, cwnd, net, to, 1055215817Srrs stcb->asoc.my_vtag, 1056215817Srrs ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 1057215817Srrs net, 1058215817Srrs old_cwnd, net->cwnd); 1059179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1060171440Srrs sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 1061171440Srrs } 1062171440Srrs} 1063171440Srrs 1064217611Stuexenstatic void 1065219120Srrssctp_cwnd_update_after_ecn_echo_common(struct sctp_tcb *stcb, struct sctp_nets *net, 1066219120Srrs int in_window, int num_pkt_lost, int use_rtcc) 1067179157Srrs{ 1068179157Srrs int old_cwnd = net->cwnd; 1069179157Srrs 1070219120Srrs if ((use_rtcc) && (net->lan_type == SCTP_LAN_LOCAL) && (net->cc_mod.rtcc.use_dccc_ecn)) { 1071219120Srrs /* Data center Congestion Control */ 1072219120Srrs if (in_window == 0) { 1073219120Srrs /* 1074219120Srrs * Go to CA with the cwnd at the point we sent the 1075219120Srrs * TSN that was marked with a CE. 1076219120Srrs */ 1077219120Srrs if (net->ecn_prev_cwnd < net->cwnd) { 1078219120Srrs /* Restore to prev cwnd */ 1079219120Srrs net->cwnd = net->ecn_prev_cwnd - (net->mtu * num_pkt_lost); 1080219120Srrs } else { 1081219120Srrs /* Just cut in 1/2 */ 1082219120Srrs net->cwnd /= 2; 1083219120Srrs } 1084219120Srrs /* Drop to CA */ 1085219120Srrs net->ssthresh = net->cwnd - (num_pkt_lost * net->mtu); 1086219120Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1087219120Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 1088219120Srrs } 1089219120Srrs } else { 1090219120Srrs /* 1091219120Srrs * Further tuning down required over the drastic 1092219120Srrs * orginal cut 1093219120Srrs */ 1094219120Srrs net->ssthresh -= (net->mtu * num_pkt_lost); 1095219120Srrs net->cwnd -= (net->mtu * num_pkt_lost); 1096219120Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1097219120Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 1098219120Srrs } 1099219120Srrs } 1100218129Srrs SCTP_STAT_INCR(sctps_ecnereducedcwnd); 1101219120Srrs } else { 1102219120Srrs if (in_window == 0) { 1103219120Srrs SCTP_STAT_INCR(sctps_ecnereducedcwnd); 1104219120Srrs net->ssthresh = net->cwnd / 2; 1105219120Srrs if (net->ssthresh < net->mtu) { 1106219120Srrs net->ssthresh = net->mtu; 1107219120Srrs /* 1108219120Srrs * here back off the timer as well, to slow 1109219120Srrs * us down 1110219120Srrs */ 1111219120Srrs net->RTO <<= 1; 1112219120Srrs } 1113219120Srrs net->cwnd = net->ssthresh; 1114219120Srrs SDT_PROBE(sctp, cwnd, net, ecn, 1115219120Srrs stcb->asoc.my_vtag, 1116219120Srrs ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 1117219120Srrs net, 1118219120Srrs old_cwnd, net->cwnd); 1119219120Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1120219120Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 1121219120Srrs } 1122218129Srrs } 1123179157Srrs } 1124219120Srrs 1125179157Srrs} 1126179157Srrs 1127217611Stuexenstatic void 1128179157Srrssctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb, 1129179157Srrs struct sctp_nets *net, struct sctp_pktdrop_chunk *cp, 1130179157Srrs uint32_t * bottle_bw, uint32_t * on_queue) 1131179157Srrs{ 1132179157Srrs uint32_t bw_avail; 1133218232Srrs unsigned int incr; 1134179157Srrs int old_cwnd = net->cwnd; 1135179157Srrs 1136179157Srrs /* get bottle neck bw */ 1137179157Srrs *bottle_bw = ntohl(cp->bottle_bw); 1138179157Srrs /* and whats on queue */ 1139179157Srrs *on_queue = ntohl(cp->current_onq); 1140179157Srrs /* 1141179157Srrs * adjust the on-queue if our flight is more it could be that the 1142179157Srrs * router has not yet gotten data "in-flight" to it 1143179157Srrs */ 1144271750Stuexen if (*on_queue < net->flight_size) { 1145179157Srrs *on_queue = net->flight_size; 1146271750Stuexen } 1147271750Stuexen /* rtt is measured in micro seconds, bottle_bw in bytes per second */ 1148271750Stuexen bw_avail = (uint32_t) (((uint64_t) (*bottle_bw) * net->rtt) / (uint64_t) 1000000); 1149179157Srrs if (bw_avail > *bottle_bw) { 1150179157Srrs /* 1151179157Srrs * Cap the growth to no more than the bottle neck. This can 1152179157Srrs * happen as RTT slides up due to queues. It also means if 1153179157Srrs * you have more than a 1 second RTT with a empty queue you 1154179157Srrs * will be limited to the bottle_bw per second no matter if 1155179157Srrs * other points have 1/2 the RTT and you could get more 1156179157Srrs * out... 1157179157Srrs */ 1158179157Srrs bw_avail = *bottle_bw; 1159179157Srrs } 1160179157Srrs if (*on_queue > bw_avail) { 1161179157Srrs /* 1162179157Srrs * No room for anything else don't allow anything else to be 1163179157Srrs * "added to the fire". 1164179157Srrs */ 1165179157Srrs int seg_inflight, seg_onqueue, my_portion; 1166179157Srrs 1167179157Srrs net->partial_bytes_acked = 0; 1168179157Srrs /* how much are we over queue size? */ 1169179157Srrs incr = *on_queue - bw_avail; 1170179157Srrs if (stcb->asoc.seen_a_sack_this_pkt) { 1171179157Srrs /* 1172179157Srrs * undo any cwnd adjustment that the sack might have 1173179157Srrs * made 1174179157Srrs */ 1175179157Srrs net->cwnd = net->prev_cwnd; 1176179157Srrs } 1177179157Srrs /* Now how much of that is mine? */ 1178179157Srrs seg_inflight = net->flight_size / net->mtu; 1179179157Srrs seg_onqueue = *on_queue / net->mtu; 1180179157Srrs my_portion = (incr * seg_inflight) / seg_onqueue; 1181179157Srrs 1182179157Srrs /* Have I made an adjustment already */ 1183179157Srrs if (net->cwnd > net->flight_size) { 1184179157Srrs /* 1185179157Srrs * for this flight I made an adjustment we need to 1186179157Srrs * decrease the portion by a share our previous 1187179157Srrs * adjustment. 1188179157Srrs */ 1189179157Srrs int diff_adj; 1190179157Srrs 1191179157Srrs diff_adj = net->cwnd - net->flight_size; 1192179157Srrs if (diff_adj > my_portion) 1193179157Srrs my_portion = 0; 1194179157Srrs else 1195179157Srrs my_portion -= diff_adj; 1196179157Srrs } 1197179157Srrs /* 1198179157Srrs * back down to the previous cwnd (assume we have had a sack 1199179157Srrs * before this packet). minus what ever portion of the 1200179157Srrs * overage is my fault. 1201179157Srrs */ 1202179157Srrs net->cwnd -= my_portion; 1203179157Srrs 1204179157Srrs /* we will NOT back down more than 1 MTU */ 1205179157Srrs if (net->cwnd <= net->mtu) { 1206179157Srrs net->cwnd = net->mtu; 1207179157Srrs } 1208179157Srrs /* force into CA */ 1209179157Srrs net->ssthresh = net->cwnd - 1; 1210179157Srrs } else { 1211179157Srrs /* 1212179157Srrs * Take 1/4 of the space left or max burst up .. whichever 1213179157Srrs * is less. 1214179157Srrs */ 1215217894Stuexen incr = (bw_avail - *on_queue) >> 2; 1216217894Stuexen if ((stcb->asoc.max_burst > 0) && 1217217894Stuexen (stcb->asoc.max_burst * net->mtu < incr)) { 1218217894Stuexen incr = stcb->asoc.max_burst * net->mtu; 1219217894Stuexen } 1220179157Srrs net->cwnd += incr; 1221179157Srrs } 1222179157Srrs if (net->cwnd > bw_avail) { 1223179157Srrs /* We can't exceed the pipe size */ 1224179157Srrs net->cwnd = bw_avail; 1225179157Srrs } 1226179157Srrs if (net->cwnd < net->mtu) { 1227179157Srrs /* We always have 1 MTU */ 1228179157Srrs net->cwnd = net->mtu; 1229179157Srrs } 1230179157Srrs if (net->cwnd - old_cwnd != 0) { 1231179157Srrs /* log only changes */ 1232215817Srrs SDT_PROBE(sctp, cwnd, net, pd, 1233215817Srrs stcb->asoc.my_vtag, 1234215817Srrs ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 1235215817Srrs net, 1236215817Srrs old_cwnd, net->cwnd); 1237179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1238179157Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 1239179157Srrs SCTP_CWND_LOG_FROM_SAT); 1240179157Srrs } 1241179157Srrs } 1242179157Srrs} 1243179157Srrs 1244217611Stuexenstatic void 1245179157Srrssctp_cwnd_update_after_output(struct sctp_tcb *stcb, 1246179157Srrs struct sctp_nets *net, int burst_limit) 1247179157Srrs{ 1248179157Srrs int old_cwnd = net->cwnd; 1249179157Srrs 1250179157Srrs if (net->ssthresh < net->cwnd) 1251179157Srrs net->ssthresh = net->cwnd; 1252219120Srrs if (burst_limit) { 1253219120Srrs net->cwnd = (net->flight_size + (burst_limit * net->mtu)); 1254219120Srrs SDT_PROBE(sctp, cwnd, net, bl, 1255219120Srrs stcb->asoc.my_vtag, 1256219120Srrs ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 1257219120Srrs net, 1258219120Srrs old_cwnd, net->cwnd); 1259219120Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1260219120Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST); 1261219120Srrs } 1262179157Srrs } 1263179157Srrs} 1264179157Srrs 1265217611Stuexenstatic void 1266219120Srrssctp_cwnd_update_after_sack(struct sctp_tcb *stcb, 1267219120Srrs struct sctp_association *asoc, 1268219120Srrs int accum_moved, int reneged_all, int will_exit) 1269219120Srrs{ 1270219120Srrs /* Passing a zero argument in last disables the rtcc algoritm */ 1271219120Srrs sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 0); 1272219120Srrs} 1273219120Srrs 1274219120Srrsstatic void 1275219120Srrssctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, 1276219120Srrs int in_window, int num_pkt_lost) 1277219120Srrs{ 1278219120Srrs /* Passing a zero argument in last disables the rtcc algoritm */ 1279219120Srrs sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 0); 1280219120Srrs} 1281219120Srrs 1282219120Srrs/* Here starts the RTCCVAR type CC invented by RRS which 1283219120Srrs * is a slight mod to RFC2581. We reuse a common routine or 1284219120Srrs * two since these algoritms are so close and need to 1285219120Srrs * remain the same. 1286219120Srrs */ 1287219120Srrsstatic void 1288219120Srrssctp_cwnd_update_rtcc_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, 1289219120Srrs int in_window, int num_pkt_lost) 1290219120Srrs{ 1291219120Srrs sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 1); 1292219120Srrs} 1293219120Srrs 1294219120Srrs 1295219120Srrsstatic 1296219120Srrsvoid 1297219120Srrssctp_cwnd_update_rtcc_tsn_acknowledged(struct sctp_nets *net, 1298219120Srrs struct sctp_tmit_chunk *tp1) 1299219120Srrs{ 1300219120Srrs net->cc_mod.rtcc.bw_bytes += tp1->send_size; 1301219120Srrs} 1302219120Srrs 1303219120Srrsstatic void 1304228653Stuexensctp_cwnd_prepare_rtcc_net_for_sack(struct sctp_tcb *stcb SCTP_UNUSED, 1305219120Srrs struct sctp_nets *net) 1306219120Srrs{ 1307219120Srrs if (net->cc_mod.rtcc.tls_needs_set > 0) { 1308219120Srrs /* We had a bw measurment going on */ 1309219120Srrs struct timeval ltls; 1310219120Srrs 1311219120Srrs SCTP_GETPTIME_TIMEVAL(<ls); 1312219120Srrs timevalsub(<ls, &net->cc_mod.rtcc.tls); 1313219120Srrs net->cc_mod.rtcc.new_tot_time = (ltls.tv_sec * 1000000) + ltls.tv_usec; 1314219120Srrs } 1315219120Srrs} 1316219120Srrs 1317219120Srrsstatic void 1318219120Srrssctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb *stcb, 1319219120Srrs struct sctp_nets *net) 1320219120Srrs{ 1321219120Srrs uint64_t vtag, probepoint; 1322219120Srrs 1323219120Srrs if (net->cc_mod.rtcc.lbw) { 1324219120Srrs /* Clear the old bw.. we went to 0 in-flight */ 1325219120Srrs vtag = (net->rtt << 32) | (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) | 1326219120Srrs (stcb->rport); 1327219120Srrs probepoint = (((uint64_t) net->cwnd) << 32); 1328219120Srrs /* Probe point 8 */ 1329219120Srrs probepoint |= ((8 << 16) | 0); 1330219120Srrs SDT_PROBE(sctp, cwnd, net, rttvar, 1331219120Srrs vtag, 1332219120Srrs ((net->cc_mod.rtcc.lbw << 32) | 0), 1333219397Srrs ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 1334219397Srrs net->flight_size, 1335219120Srrs probepoint); 1336219120Srrs net->cc_mod.rtcc.lbw_rtt = 0; 1337219120Srrs net->cc_mod.rtcc.cwnd_at_bw_set = 0; 1338219120Srrs net->cc_mod.rtcc.lbw = 0; 1339219397Srrs net->cc_mod.rtcc.bw_bytes_at_last_rttc = 0; 1340219397Srrs net->cc_mod.rtcc.vol_reduce = 0; 1341219120Srrs net->cc_mod.rtcc.bw_tot_time = 0; 1342219120Srrs net->cc_mod.rtcc.bw_bytes = 0; 1343219120Srrs net->cc_mod.rtcc.tls_needs_set = 0; 1344219397Srrs if (net->cc_mod.rtcc.steady_step) { 1345219397Srrs net->cc_mod.rtcc.vol_reduce = 0; 1346219397Srrs net->cc_mod.rtcc.step_cnt = 0; 1347219397Srrs net->cc_mod.rtcc.last_step_state = 0; 1348219397Srrs } 1349219120Srrs if (net->cc_mod.rtcc.ret_from_eq) { 1350219120Srrs /* less aggressive one - reset cwnd too */ 1351219120Srrs uint32_t cwnd_in_mtu, cwnd; 1352219120Srrs 1353219120Srrs cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd); 1354219120Srrs if (cwnd_in_mtu == 0) { 1355219120Srrs /* 1356219120Srrs * Using 0 means that the value of RFC 4960 1357219120Srrs * is used. 1358219120Srrs */ 1359219120Srrs cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 1360219120Srrs } else { 1361219120Srrs /* 1362219120Srrs * We take the minimum of the burst limit 1363219120Srrs * and the initial congestion window. 1364219120Srrs */ 1365219120Srrs if ((stcb->asoc.max_burst > 0) && (cwnd_in_mtu > stcb->asoc.max_burst)) 1366219120Srrs cwnd_in_mtu = stcb->asoc.max_burst; 1367219120Srrs cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu; 1368219120Srrs } 1369219120Srrs if (net->cwnd > cwnd) { 1370219120Srrs /* 1371219120Srrs * Only set if we are not a timeout (i.e. 1372219120Srrs * down to 1 mtu) 1373219120Srrs */ 1374219120Srrs net->cwnd = cwnd; 1375219120Srrs } 1376219120Srrs } 1377219120Srrs } 1378219120Srrs} 1379219120Srrs 1380219120Srrsstatic void 1381219120Srrssctp_set_rtcc_initial_cc_param(struct sctp_tcb *stcb, 1382219120Srrs struct sctp_nets *net) 1383219120Srrs{ 1384219120Srrs uint64_t vtag, probepoint; 1385219120Srrs 1386219120Srrs sctp_set_initial_cc_param(stcb, net); 1387219120Srrs stcb->asoc.use_precise_time = 1; 1388219120Srrs probepoint = (((uint64_t) net->cwnd) << 32); 1389219120Srrs probepoint |= ((9 << 16) | 0); 1390219120Srrs vtag = (net->rtt << 32) | 1391219120Srrs (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) | 1392219120Srrs (stcb->rport); 1393219120Srrs SDT_PROBE(sctp, cwnd, net, rttvar, 1394219120Srrs vtag, 1395219120Srrs 0, 1396219120Srrs 0, 1397219120Srrs 0, 1398219120Srrs probepoint); 1399219120Srrs net->cc_mod.rtcc.lbw_rtt = 0; 1400219120Srrs net->cc_mod.rtcc.cwnd_at_bw_set = 0; 1401219397Srrs net->cc_mod.rtcc.vol_reduce = 0; 1402219120Srrs net->cc_mod.rtcc.lbw = 0; 1403219397Srrs net->cc_mod.rtcc.vol_reduce = 0; 1404219397Srrs net->cc_mod.rtcc.bw_bytes_at_last_rttc = 0; 1405219120Srrs net->cc_mod.rtcc.bw_tot_time = 0; 1406219120Srrs net->cc_mod.rtcc.bw_bytes = 0; 1407219120Srrs net->cc_mod.rtcc.tls_needs_set = 0; 1408219120Srrs net->cc_mod.rtcc.ret_from_eq = SCTP_BASE_SYSCTL(sctp_rttvar_eqret); 1409219397Srrs net->cc_mod.rtcc.steady_step = SCTP_BASE_SYSCTL(sctp_steady_step); 1410219397Srrs net->cc_mod.rtcc.use_dccc_ecn = SCTP_BASE_SYSCTL(sctp_use_dccc_ecn); 1411219397Srrs net->cc_mod.rtcc.step_cnt = 0; 1412219397Srrs net->cc_mod.rtcc.last_step_state = 0; 1413219397Srrs 1414219397Srrs 1415219120Srrs} 1416219120Srrs 1417219120Srrsstatic int 1418219120Srrssctp_cwnd_rtcc_socket_option(struct sctp_tcb *stcb, int setorget, 1419219120Srrs struct sctp_cc_option *cc_opt) 1420219120Srrs{ 1421219120Srrs struct sctp_nets *net; 1422219120Srrs 1423219120Srrs if (setorget == 1) { 1424219120Srrs /* a set */ 1425219120Srrs if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) { 1426219120Srrs if ((cc_opt->aid_value.assoc_value != 0) && 1427219120Srrs (cc_opt->aid_value.assoc_value != 1)) { 1428219120Srrs return (EINVAL); 1429219120Srrs } 1430219120Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1431219120Srrs net->cc_mod.rtcc.ret_from_eq = cc_opt->aid_value.assoc_value; 1432219120Srrs } 1433219120Srrs } else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) { 1434219120Srrs if ((cc_opt->aid_value.assoc_value != 0) && 1435219120Srrs (cc_opt->aid_value.assoc_value != 1)) { 1436219120Srrs return (EINVAL); 1437219120Srrs } 1438219120Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1439219120Srrs net->cc_mod.rtcc.use_dccc_ecn = cc_opt->aid_value.assoc_value; 1440219120Srrs } 1441219397Srrs } else if (cc_opt->option == SCTP_CC_OPT_STEADY_STEP) { 1442219397Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1443219397Srrs net->cc_mod.rtcc.steady_step = cc_opt->aid_value.assoc_value; 1444219397Srrs } 1445219120Srrs } else { 1446219120Srrs return (EINVAL); 1447219120Srrs } 1448219120Srrs } else { 1449219120Srrs /* a get */ 1450219120Srrs if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) { 1451219120Srrs net = TAILQ_FIRST(&stcb->asoc.nets); 1452219120Srrs if (net == NULL) { 1453219120Srrs return (EFAULT); 1454219120Srrs } 1455219120Srrs cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.ret_from_eq; 1456219120Srrs } else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) { 1457219120Srrs net = TAILQ_FIRST(&stcb->asoc.nets); 1458219120Srrs if (net == NULL) { 1459219120Srrs return (EFAULT); 1460219120Srrs } 1461219120Srrs cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.use_dccc_ecn; 1462219397Srrs } else if (cc_opt->option == SCTP_CC_OPT_STEADY_STEP) { 1463219397Srrs net = TAILQ_FIRST(&stcb->asoc.nets); 1464219397Srrs if (net == NULL) { 1465219397Srrs return (EFAULT); 1466219397Srrs } 1467219397Srrs cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.steady_step; 1468219120Srrs } else { 1469219120Srrs return (EINVAL); 1470219120Srrs } 1471219120Srrs } 1472219120Srrs return (0); 1473219120Srrs} 1474219120Srrs 1475219120Srrsstatic void 1476228653Stuexensctp_cwnd_update_rtcc_packet_transmitted(struct sctp_tcb *stcb SCTP_UNUSED, 1477219120Srrs struct sctp_nets *net) 1478219120Srrs{ 1479219120Srrs if (net->cc_mod.rtcc.tls_needs_set == 0) { 1480219120Srrs SCTP_GETPTIME_TIMEVAL(&net->cc_mod.rtcc.tls); 1481219120Srrs net->cc_mod.rtcc.tls_needs_set = 2; 1482219120Srrs } 1483219120Srrs} 1484219120Srrs 1485219120Srrsstatic void 1486219120Srrssctp_cwnd_update_rtcc_after_sack(struct sctp_tcb *stcb, 1487219120Srrs struct sctp_association *asoc, 1488219120Srrs int accum_moved, int reneged_all, int will_exit) 1489219120Srrs{ 1490219120Srrs /* Passing a one argument at the last enables the rtcc algoritm */ 1491219120Srrs sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 1); 1492219120Srrs} 1493219120Srrs 1494219397Srrsstatic void 1495228653Stuexensctp_rtt_rtcc_calculated(struct sctp_tcb *stcb SCTP_UNUSED, 1496228653Stuexen struct sctp_nets *net, 1497228653Stuexen struct timeval *now SCTP_UNUSED) 1498219397Srrs{ 1499219397Srrs net->cc_mod.rtcc.rtt_set_this_sack = 1; 1500219397Srrs} 1501219120Srrs 1502219120Srrs/* Here starts Sally Floyds HS-TCP */ 1503219120Srrs 1504171440Srrsstruct sctp_hs_raise_drop { 1505171440Srrs int32_t cwnd; 1506171440Srrs int32_t increase; 1507171440Srrs int32_t drop_percent; 1508171440Srrs}; 1509171440Srrs 1510171440Srrs#define SCTP_HS_TABLE_SIZE 73 1511171440Srrs 1512171440Srrsstruct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = { 1513171440Srrs {38, 1, 50}, /* 0 */ 1514171440Srrs {118, 2, 44}, /* 1 */ 1515171440Srrs {221, 3, 41}, /* 2 */ 1516171440Srrs {347, 4, 38}, /* 3 */ 1517171440Srrs {495, 5, 37}, /* 4 */ 1518171440Srrs {663, 6, 35}, /* 5 */ 1519171440Srrs {851, 7, 34}, /* 6 */ 1520171440Srrs {1058, 8, 33}, /* 7 */ 1521171440Srrs {1284, 9, 32}, /* 8 */ 1522171440Srrs {1529, 10, 31}, /* 9 */ 1523171440Srrs {1793, 11, 30}, /* 10 */ 1524171440Srrs {2076, 12, 29}, /* 11 */ 1525171440Srrs {2378, 13, 28}, /* 12 */ 1526171440Srrs {2699, 14, 28}, /* 13 */ 1527171440Srrs {3039, 15, 27}, /* 14 */ 1528171440Srrs {3399, 16, 27}, /* 15 */ 1529171440Srrs {3778, 17, 26}, /* 16 */ 1530171440Srrs {4177, 18, 26}, /* 17 */ 1531171440Srrs {4596, 19, 25}, /* 18 */ 1532171440Srrs {5036, 20, 25}, /* 19 */ 1533171440Srrs {5497, 21, 24}, /* 20 */ 1534171440Srrs {5979, 22, 24}, /* 21 */ 1535171440Srrs {6483, 23, 23}, /* 22 */ 1536171440Srrs {7009, 24, 23}, /* 23 */ 1537171440Srrs {7558, 25, 22}, /* 24 */ 1538171440Srrs {8130, 26, 22}, /* 25 */ 1539171440Srrs {8726, 27, 22}, /* 26 */ 1540171440Srrs {9346, 28, 21}, /* 27 */ 1541171440Srrs {9991, 29, 21}, /* 28 */ 1542171440Srrs {10661, 30, 21}, /* 29 */ 1543171440Srrs {11358, 31, 20}, /* 30 */ 1544171440Srrs {12082, 32, 20}, /* 31 */ 1545171440Srrs {12834, 33, 20}, /* 32 */ 1546171440Srrs {13614, 34, 19}, /* 33 */ 1547171440Srrs {14424, 35, 19}, /* 34 */ 1548171440Srrs {15265, 36, 19}, /* 35 */ 1549171440Srrs {16137, 37, 19}, /* 36 */ 1550171440Srrs {17042, 38, 18}, /* 37 */ 1551171440Srrs {17981, 39, 18}, /* 38 */ 1552171440Srrs {18955, 40, 18}, /* 39 */ 1553171440Srrs {19965, 41, 17}, /* 40 */ 1554171440Srrs {21013, 42, 17}, /* 41 */ 1555171440Srrs {22101, 43, 17}, /* 42 */ 1556171440Srrs {23230, 44, 17}, /* 43 */ 1557171440Srrs {24402, 45, 16}, /* 44 */ 1558171440Srrs {25618, 46, 16}, /* 45 */ 1559171440Srrs {26881, 47, 16}, /* 46 */ 1560171440Srrs {28193, 48, 16}, /* 47 */ 1561171440Srrs {29557, 49, 15}, /* 48 */ 1562171440Srrs {30975, 50, 15}, /* 49 */ 1563171440Srrs {32450, 51, 15}, /* 50 */ 1564171440Srrs {33986, 52, 15}, /* 51 */ 1565171440Srrs {35586, 53, 14}, /* 52 */ 1566171440Srrs {37253, 54, 14}, /* 53 */ 1567171440Srrs {38992, 55, 14}, /* 54 */ 1568171440Srrs {40808, 56, 14}, /* 55 */ 1569171440Srrs {42707, 57, 13}, /* 56 */ 1570171440Srrs {44694, 58, 13}, /* 57 */ 1571171440Srrs {46776, 59, 13}, /* 58 */ 1572171440Srrs {48961, 60, 13}, /* 59 */ 1573171440Srrs {51258, 61, 13}, /* 60 */ 1574171440Srrs {53677, 62, 12}, /* 61 */ 1575171440Srrs {56230, 63, 12}, /* 62 */ 1576171440Srrs {58932, 64, 12}, /* 63 */ 1577171440Srrs {61799, 65, 12}, /* 64 */ 1578171440Srrs {64851, 66, 11}, /* 65 */ 1579171440Srrs {68113, 67, 11}, /* 66 */ 1580171440Srrs {71617, 68, 11}, /* 67 */ 1581171440Srrs {75401, 69, 10}, /* 68 */ 1582171440Srrs {79517, 70, 10}, /* 69 */ 1583171440Srrs {84035, 71, 10}, /* 70 */ 1584171440Srrs {89053, 72, 10}, /* 71 */ 1585171440Srrs {94717, 73, 9} /* 72 */ 1586171440Srrs}; 1587171440Srrs 1588171440Srrsstatic void 1589171440Srrssctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net) 1590171440Srrs{ 1591171440Srrs int cur_val, i, indx, incr; 1592171440Srrs 1593171440Srrs cur_val = net->cwnd >> 10; 1594171440Srrs indx = SCTP_HS_TABLE_SIZE - 1; 1595234995Stuexen 1596171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 1597171440Srrs /* normal mode */ 1598171440Srrs if (net->net_ack > net->mtu) { 1599171440Srrs net->cwnd += net->mtu; 1600179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1601171440Srrs sctp_log_cwnd(stcb, net, net->mtu, SCTP_CWND_LOG_FROM_SS); 1602171440Srrs } 1603171440Srrs } else { 1604171440Srrs net->cwnd += net->net_ack; 1605179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1606171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, SCTP_CWND_LOG_FROM_SS); 1607171440Srrs } 1608171440Srrs } 1609171440Srrs } else { 1610171440Srrs for (i = net->last_hs_used; i < SCTP_HS_TABLE_SIZE; i++) { 1611171440Srrs if (cur_val < sctp_cwnd_adjust[i].cwnd) { 1612171440Srrs indx = i; 1613171440Srrs break; 1614171440Srrs } 1615171440Srrs } 1616171440Srrs net->last_hs_used = indx; 1617171440Srrs incr = ((sctp_cwnd_adjust[indx].increase) << 10); 1618171440Srrs net->cwnd += incr; 1619179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1620171440Srrs sctp_log_cwnd(stcb, net, incr, SCTP_CWND_LOG_FROM_SS); 1621171440Srrs } 1622171440Srrs } 1623171440Srrs} 1624171440Srrs 1625171440Srrsstatic void 1626171440Srrssctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net) 1627171440Srrs{ 1628171440Srrs int cur_val, i, indx; 1629171440Srrs int old_cwnd = net->cwnd; 1630171440Srrs 1631171440Srrs cur_val = net->cwnd >> 10; 1632171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 1633171440Srrs /* normal mode */ 1634171440Srrs net->ssthresh = net->cwnd / 2; 1635171440Srrs if (net->ssthresh < (net->mtu * 2)) { 1636171440Srrs net->ssthresh = 2 * net->mtu; 1637171440Srrs } 1638171440Srrs net->cwnd = net->ssthresh; 1639171440Srrs } else { 1640171440Srrs /* drop by the proper amount */ 1641171440Srrs net->ssthresh = net->cwnd - (int)((net->cwnd / 100) * 1642171440Srrs sctp_cwnd_adjust[net->last_hs_used].drop_percent); 1643171440Srrs net->cwnd = net->ssthresh; 1644171440Srrs /* now where are we */ 1645171440Srrs indx = net->last_hs_used; 1646171440Srrs cur_val = net->cwnd >> 10; 1647171440Srrs /* reset where we are in the table */ 1648171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 1649171440Srrs /* feel out of hs */ 1650171440Srrs net->last_hs_used = 0; 1651171440Srrs } else { 1652171440Srrs for (i = indx; i >= 1; i--) { 1653171440Srrs if (cur_val > sctp_cwnd_adjust[i - 1].cwnd) { 1654171440Srrs break; 1655171440Srrs } 1656171440Srrs } 1657171440Srrs net->last_hs_used = indx; 1658171440Srrs } 1659171440Srrs } 1660179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1661171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_FR); 1662171440Srrs } 1663171440Srrs} 1664171440Srrs 1665217611Stuexenstatic void 1666171440Srrssctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb, 1667171440Srrs struct sctp_association *asoc) 1668171440Srrs{ 1669171440Srrs struct sctp_nets *net; 1670171440Srrs 1671171440Srrs /* 1672216669Stuexen * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) && 1673171440Srrs * (net->fast_retran_loss_recovery == 0))) 1674171440Srrs */ 1675171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 1676211944Stuexen if ((asoc->fast_retran_loss_recovery == 0) || 1677216669Stuexen (asoc->sctp_cmt_on_off > 0)) { 1678171440Srrs /* out of a RFC2582 Fast recovery window? */ 1679171440Srrs if (net->net_ack > 0) { 1680171440Srrs /* 1681171440Srrs * per section 7.2.3, are there any 1682171440Srrs * destinations that had a fast retransmit 1683171440Srrs * to them. If so what we need to do is 1684171440Srrs * adjust ssthresh and cwnd. 1685171440Srrs */ 1686171440Srrs struct sctp_tmit_chunk *lchk; 1687171440Srrs 1688171440Srrs sctp_hs_cwnd_decrease(stcb, net); 1689171440Srrs 1690171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 1691171440Srrs 1692171440Srrs net->partial_bytes_acked = 0; 1693171440Srrs /* Turn on fast recovery window */ 1694171440Srrs asoc->fast_retran_loss_recovery = 1; 1695171440Srrs if (lchk == NULL) { 1696171440Srrs /* Mark end of the window */ 1697171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 1698171440Srrs } else { 1699171440Srrs asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 1700171440Srrs } 1701171440Srrs 1702171440Srrs /* 1703171440Srrs * CMT fast recovery -- per destination 1704171440Srrs * recovery variable. 1705171440Srrs */ 1706171440Srrs net->fast_retran_loss_recovery = 1; 1707171440Srrs 1708171440Srrs if (lchk == NULL) { 1709171440Srrs /* Mark end of the window */ 1710171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 1711171440Srrs } else { 1712171440Srrs net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 1713171440Srrs } 1714171440Srrs 1715171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 1716171440Srrs stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); 1717171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 1718171440Srrs stcb->sctp_ep, stcb, net); 1719171440Srrs } 1720171440Srrs } else if (net->net_ack > 0) { 1721171440Srrs /* 1722171440Srrs * Mark a peg that we WOULD have done a cwnd 1723171440Srrs * reduction but RFC2582 prevented this action. 1724171440Srrs */ 1725171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 1726171440Srrs } 1727171440Srrs } 1728171440Srrs} 1729171440Srrs 1730217611Stuexenstatic void 1731171440Srrssctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, 1732171440Srrs struct sctp_association *asoc, 1733228653Stuexen int accum_moved, int reneged_all SCTP_UNUSED, int will_exit) 1734171440Srrs{ 1735171440Srrs struct sctp_nets *net; 1736171440Srrs 1737171440Srrs /******************************/ 1738171440Srrs /* update cwnd and Early FR */ 1739171440Srrs /******************************/ 1740171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 1741171440Srrs 1742171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 1743171440Srrs /* 1744171440Srrs * CMT fast recovery code. Need to debug. 1745171440Srrs */ 1746171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 1747217469Stuexen if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) || 1748217469Stuexen SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) { 1749171440Srrs net->will_exit_fast_recovery = 1; 1750171440Srrs } 1751171440Srrs } 1752171440Srrs#endif 1753171440Srrs /* if nothing was acked on this destination skip it */ 1754171440Srrs if (net->net_ack == 0) { 1755179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1756171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 1757171440Srrs } 1758171440Srrs continue; 1759171440Srrs } 1760171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 1761171440Srrs /* 1762171440Srrs * CMT fast recovery code 1763171440Srrs */ 1764171440Srrs /* 1765216669Stuexen * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery 1766216669Stuexen * && net->will_exit_fast_recovery == 0) { @@@ Do something 1767216669Stuexen * } else if (sctp_cmt_on_off == 0 && 1768171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 1769171440Srrs */ 1770171440Srrs#endif 1771171440Srrs 1772211944Stuexen if (asoc->fast_retran_loss_recovery && 1773211944Stuexen (will_exit == 0) && 1774211944Stuexen (asoc->sctp_cmt_on_off == 0)) { 1775171440Srrs /* 1776171440Srrs * If we are in loss recovery we skip any cwnd 1777171440Srrs * update 1778171440Srrs */ 1779224641Stuexen return; 1780171440Srrs } 1781171440Srrs /* 1782171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 1783171440Srrs * moved. 1784171440Srrs */ 1785211944Stuexen if (accum_moved || 1786216669Stuexen ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) { 1787171440Srrs /* If the cumulative ack moved we can proceed */ 1788171440Srrs if (net->cwnd <= net->ssthresh) { 1789171440Srrs /* We are in slow start */ 1790179157Srrs if (net->flight_size + net->net_ack >= net->cwnd) { 1791171440Srrs 1792171440Srrs sctp_hs_cwnd_increase(stcb, net); 1793171440Srrs 1794171440Srrs } else { 1795179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1796171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 1797171440Srrs SCTP_CWND_LOG_NOADV_SS); 1798171440Srrs } 1799171440Srrs } 1800171440Srrs } else { 1801171440Srrs /* We are in congestion avoidance */ 1802179157Srrs net->partial_bytes_acked += net->net_ack; 1803179157Srrs if ((net->flight_size + net->net_ack >= net->cwnd) && 1804179157Srrs (net->partial_bytes_acked >= net->cwnd)) { 1805179157Srrs net->partial_bytes_acked -= net->cwnd; 1806179157Srrs net->cwnd += net->mtu; 1807179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1808179157Srrs sctp_log_cwnd(stcb, net, net->mtu, 1809179157Srrs SCTP_CWND_LOG_FROM_CA); 1810171440Srrs } 1811171440Srrs } else { 1812179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1813171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 1814171440Srrs SCTP_CWND_LOG_NOADV_CA); 1815171440Srrs } 1816171440Srrs } 1817171440Srrs } 1818171440Srrs } else { 1819179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1820171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 1821171440Srrs SCTP_CWND_LOG_NO_CUMACK); 1822171440Srrs } 1823171440Srrs } 1824171440Srrs } 1825171440Srrs} 1826171440Srrs 1827171440Srrs 1828171440Srrs/* 1829171440Srrs * H-TCP congestion control. The algorithm is detailed in: 1830171440Srrs * R.N.Shorten, D.J.Leith: 1831171440Srrs * "H-TCP: TCP for high-speed and long-distance networks" 1832171440Srrs * Proc. PFLDnet, Argonne, 2004. 1833171440Srrs * http://www.hamilton.ie/net/htcp3.pdf 1834171440Srrs */ 1835171440Srrs 1836171440Srrs 1837171440Srrsstatic int use_rtt_scaling = 1; 1838171440Srrsstatic int use_bandwidth_switch = 1; 1839171440Srrs 1840171440Srrsstatic inline int 1841171440Srrsbetween(uint32_t seq1, uint32_t seq2, uint32_t seq3) 1842171440Srrs{ 1843228907Stuexen return (seq3 - seq2 >= seq1 - seq2); 1844171440Srrs} 1845171440Srrs 1846171440Srrsstatic inline uint32_t 1847171440Srrshtcp_cong_time(struct htcp *ca) 1848171440Srrs{ 1849228907Stuexen return (sctp_get_tick_count() - ca->last_cong); 1850171440Srrs} 1851171440Srrs 1852171440Srrsstatic inline uint32_t 1853171440Srrshtcp_ccount(struct htcp *ca) 1854171440Srrs{ 1855228907Stuexen return (htcp_cong_time(ca) / ca->minRTT); 1856171440Srrs} 1857171440Srrs 1858171440Srrsstatic inline void 1859171440Srrshtcp_reset(struct htcp *ca) 1860171440Srrs{ 1861171440Srrs ca->undo_last_cong = ca->last_cong; 1862171440Srrs ca->undo_maxRTT = ca->maxRTT; 1863171440Srrs ca->undo_old_maxB = ca->old_maxB; 1864171477Srrs ca->last_cong = sctp_get_tick_count(); 1865171440Srrs} 1866171440Srrs 1867171440Srrs#ifdef SCTP_NOT_USED 1868171440Srrs 1869171440Srrsstatic uint32_t 1870171440Srrshtcp_cwnd_undo(struct sctp_tcb *stcb, struct sctp_nets *net) 1871171440Srrs{ 1872219057Srrs net->cc_mod.htcp_ca.last_cong = net->cc_mod.htcp_ca.undo_last_cong; 1873219057Srrs net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.undo_maxRTT; 1874219057Srrs net->cc_mod.htcp_ca.old_maxB = net->cc_mod.htcp_ca.undo_old_maxB; 1875228907Stuexen return (max(net->cwnd, ((net->ssthresh / net->mtu << 7) / net->cc_mod.htcp_ca.beta) * net->mtu)); 1876171440Srrs} 1877171440Srrs 1878171440Srrs#endif 1879171440Srrs 1880171440Srrsstatic inline void 1881228653Stuexenmeasure_rtt(struct sctp_nets *net) 1882171440Srrs{ 1883219014Stuexen uint32_t srtt = net->lastsa >> SCTP_RTT_SHIFT; 1884171440Srrs 1885171440Srrs /* keep track of minimum RTT seen so far, minRTT is zero at first */ 1886219057Srrs if (net->cc_mod.htcp_ca.minRTT > srtt || !net->cc_mod.htcp_ca.minRTT) 1887219057Srrs net->cc_mod.htcp_ca.minRTT = srtt; 1888171440Srrs 1889171440Srrs /* max RTT */ 1890219057Srrs if (net->fast_retran_ip == 0 && net->ssthresh < 0xFFFF && htcp_ccount(&net->cc_mod.htcp_ca) > 3) { 1891219057Srrs if (net->cc_mod.htcp_ca.maxRTT < net->cc_mod.htcp_ca.minRTT) 1892219057Srrs net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.minRTT; 1893219057Srrs if (net->cc_mod.htcp_ca.maxRTT < srtt && srtt <= net->cc_mod.htcp_ca.maxRTT + MSEC_TO_TICKS(20)) 1894219057Srrs net->cc_mod.htcp_ca.maxRTT = srtt; 1895171440Srrs } 1896171440Srrs} 1897171440Srrs 1898171440Srrsstatic void 1899228653Stuexenmeasure_achieved_throughput(struct sctp_nets *net) 1900171440Srrs{ 1901171477Srrs uint32_t now = sctp_get_tick_count(); 1902171440Srrs 1903171440Srrs if (net->fast_retran_ip == 0) 1904219057Srrs net->cc_mod.htcp_ca.bytes_acked = net->net_ack; 1905171440Srrs 1906171440Srrs if (!use_bandwidth_switch) 1907171440Srrs return; 1908171440Srrs 1909171440Srrs /* achieved throughput calculations */ 1910171440Srrs /* JRS - not 100% sure of this statement */ 1911171440Srrs if (net->fast_retran_ip == 1) { 1912219057Srrs net->cc_mod.htcp_ca.bytecount = 0; 1913219057Srrs net->cc_mod.htcp_ca.lasttime = now; 1914171440Srrs return; 1915171440Srrs } 1916219057Srrs net->cc_mod.htcp_ca.bytecount += net->net_ack; 1917240158Stuexen 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)) && 1918240158Stuexen (now - net->cc_mod.htcp_ca.lasttime >= net->cc_mod.htcp_ca.minRTT) && 1919240158Stuexen (net->cc_mod.htcp_ca.minRTT > 0)) { 1920219057Srrs uint32_t cur_Bi = net->cc_mod.htcp_ca.bytecount / net->mtu * hz / (now - net->cc_mod.htcp_ca.lasttime); 1921171440Srrs 1922219057Srrs if (htcp_ccount(&net->cc_mod.htcp_ca) <= 3) { 1923171440Srrs /* just after backoff */ 1924219057Srrs net->cc_mod.htcp_ca.minB = net->cc_mod.htcp_ca.maxB = net->cc_mod.htcp_ca.Bi = cur_Bi; 1925171440Srrs } else { 1926219057Srrs net->cc_mod.htcp_ca.Bi = (3 * net->cc_mod.htcp_ca.Bi + cur_Bi) / 4; 1927219057Srrs if (net->cc_mod.htcp_ca.Bi > net->cc_mod.htcp_ca.maxB) 1928219057Srrs net->cc_mod.htcp_ca.maxB = net->cc_mod.htcp_ca.Bi; 1929219057Srrs if (net->cc_mod.htcp_ca.minB > net->cc_mod.htcp_ca.maxB) 1930219057Srrs net->cc_mod.htcp_ca.minB = net->cc_mod.htcp_ca.maxB; 1931171440Srrs } 1932219057Srrs net->cc_mod.htcp_ca.bytecount = 0; 1933219057Srrs net->cc_mod.htcp_ca.lasttime = now; 1934171440Srrs } 1935171440Srrs} 1936171440Srrs 1937171440Srrsstatic inline void 1938171440Srrshtcp_beta_update(struct htcp *ca, uint32_t minRTT, uint32_t maxRTT) 1939171440Srrs{ 1940171440Srrs if (use_bandwidth_switch) { 1941171440Srrs uint32_t maxB = ca->maxB; 1942171440Srrs uint32_t old_maxB = ca->old_maxB; 1943171440Srrs 1944171440Srrs ca->old_maxB = ca->maxB; 1945171440Srrs 1946171440Srrs if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) { 1947171440Srrs ca->beta = BETA_MIN; 1948171440Srrs ca->modeswitch = 0; 1949171440Srrs return; 1950171440Srrs } 1951171440Srrs } 1952171440Srrs if (ca->modeswitch && minRTT > (uint32_t) MSEC_TO_TICKS(10) && maxRTT) { 1953171440Srrs ca->beta = (minRTT << 7) / maxRTT; 1954171440Srrs if (ca->beta < BETA_MIN) 1955171440Srrs ca->beta = BETA_MIN; 1956171440Srrs else if (ca->beta > BETA_MAX) 1957171440Srrs ca->beta = BETA_MAX; 1958171440Srrs } else { 1959171440Srrs ca->beta = BETA_MIN; 1960171440Srrs ca->modeswitch = 1; 1961171440Srrs } 1962171440Srrs} 1963171440Srrs 1964171440Srrsstatic inline void 1965171440Srrshtcp_alpha_update(struct htcp *ca) 1966171440Srrs{ 1967171440Srrs uint32_t minRTT = ca->minRTT; 1968171440Srrs uint32_t factor = 1; 1969171440Srrs uint32_t diff = htcp_cong_time(ca); 1970171440Srrs 1971171440Srrs if (diff > (uint32_t) hz) { 1972171440Srrs diff -= hz; 1973171440Srrs factor = 1 + (10 * diff + ((diff / 2) * (diff / 2) / hz)) / hz; 1974171440Srrs } 1975171440Srrs if (use_rtt_scaling && minRTT) { 1976171440Srrs uint32_t scale = (hz << 3) / (10 * minRTT); 1977171440Srrs 1978171440Srrs scale = min(max(scale, 1U << 2), 10U << 3); /* clamping ratio to 1979171440Srrs * interval [0.5,10]<<3 */ 1980171440Srrs factor = (factor << 3) / scale; 1981171440Srrs if (!factor) 1982171440Srrs factor = 1; 1983171440Srrs } 1984171440Srrs ca->alpha = 2 * factor * ((1 << 7) - ca->beta); 1985171440Srrs if (!ca->alpha) 1986171440Srrs ca->alpha = ALPHA_BASE; 1987171440Srrs} 1988171440Srrs 1989171440Srrs/* After we have the rtt data to calculate beta, we'd still prefer to wait one 1990171440Srrs * rtt before we adjust our beta to ensure we are working from a consistent 1991171440Srrs * data. 1992171440Srrs * 1993171440Srrs * This function should be called when we hit a congestion event since only at 1994171440Srrs * that point do we really have a real sense of maxRTT (the queues en route 1995171440Srrs * were getting just too full now). 1996171440Srrs */ 1997171440Srrsstatic void 1998228653Stuexenhtcp_param_update(struct sctp_nets *net) 1999171440Srrs{ 2000219057Srrs uint32_t minRTT = net->cc_mod.htcp_ca.minRTT; 2001219057Srrs uint32_t maxRTT = net->cc_mod.htcp_ca.maxRTT; 2002171440Srrs 2003219057Srrs htcp_beta_update(&net->cc_mod.htcp_ca, minRTT, maxRTT); 2004219057Srrs htcp_alpha_update(&net->cc_mod.htcp_ca); 2005171440Srrs 2006171440Srrs /* 2007171440Srrs * add slowly fading memory for maxRTT to accommodate routing 2008171440Srrs * changes etc 2009171440Srrs */ 2010171440Srrs if (minRTT > 0 && maxRTT > minRTT) 2011219057Srrs net->cc_mod.htcp_ca.maxRTT = minRTT + ((maxRTT - minRTT) * 95) / 100; 2012171440Srrs} 2013171440Srrs 2014171440Srrsstatic uint32_t 2015228653Stuexenhtcp_recalc_ssthresh(struct sctp_nets *net) 2016171440Srrs{ 2017228653Stuexen htcp_param_update(net); 2018228907Stuexen return (max(((net->cwnd / net->mtu * net->cc_mod.htcp_ca.beta) >> 7) * net->mtu, 2U * net->mtu)); 2019171440Srrs} 2020171440Srrs 2021171440Srrsstatic void 2022171440Srrshtcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net) 2023171440Srrs{ 2024171440Srrs /*- 2025171440Srrs * How to handle these functions? 2026171440Srrs * if (!tcp_is_cwnd_limited(sk, in_flight)) RRS - good question. 2027171440Srrs * return; 2028171440Srrs */ 2029171440Srrs if (net->cwnd <= net->ssthresh) { 2030171440Srrs /* We are in slow start */ 2031171440Srrs if (net->flight_size + net->net_ack >= net->cwnd) { 2032179783Srrs if (net->net_ack > (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable))) { 2033179783Srrs net->cwnd += (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)); 2034179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2035171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 2036171440Srrs SCTP_CWND_LOG_FROM_SS); 2037171440Srrs } 2038171440Srrs } else { 2039171440Srrs net->cwnd += net->net_ack; 2040179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2041171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 2042171440Srrs SCTP_CWND_LOG_FROM_SS); 2043171440Srrs } 2044171440Srrs } 2045171440Srrs } else { 2046179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 2047171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 2048171440Srrs SCTP_CWND_LOG_NOADV_SS); 2049171440Srrs } 2050171440Srrs } 2051171440Srrs } else { 2052228653Stuexen measure_rtt(net); 2053171440Srrs 2054171440Srrs /* 2055171440Srrs * In dangerous area, increase slowly. In theory this is 2056171440Srrs * net->cwnd += alpha / net->cwnd 2057171440Srrs */ 2058171440Srrs /* What is snd_cwnd_cnt?? */ 2059219057Srrs if (((net->partial_bytes_acked / net->mtu * net->cc_mod.htcp_ca.alpha) >> 7) * net->mtu >= net->cwnd) { 2060171440Srrs /*- 2061171440Srrs * Does SCTP have a cwnd clamp? 2062171440Srrs * if (net->snd_cwnd < net->snd_cwnd_clamp) - Nope (RRS). 2063171440Srrs */ 2064171440Srrs net->cwnd += net->mtu; 2065171440Srrs net->partial_bytes_acked = 0; 2066219057Srrs htcp_alpha_update(&net->cc_mod.htcp_ca); 2067179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2068171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 2069171440Srrs SCTP_CWND_LOG_FROM_CA); 2070171440Srrs } 2071171440Srrs } else { 2072171440Srrs net->partial_bytes_acked += net->net_ack; 2073179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 2074171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 2075171440Srrs SCTP_CWND_LOG_NOADV_CA); 2076171440Srrs } 2077171440Srrs } 2078171440Srrs 2079219057Srrs net->cc_mod.htcp_ca.bytes_acked = net->mtu; 2080171440Srrs } 2081171440Srrs} 2082171440Srrs 2083171440Srrs#ifdef SCTP_NOT_USED 2084171440Srrs/* Lower bound on congestion window. */ 2085171440Srrsstatic uint32_t 2086171440Srrshtcp_min_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net) 2087171440Srrs{ 2088228907Stuexen return (net->ssthresh); 2089171440Srrs} 2090171440Srrs 2091171440Srrs#endif 2092171440Srrs 2093171440Srrsstatic void 2094228653Stuexenhtcp_init(struct sctp_nets *net) 2095171440Srrs{ 2096219057Srrs memset(&net->cc_mod.htcp_ca, 0, sizeof(struct htcp)); 2097219057Srrs net->cc_mod.htcp_ca.alpha = ALPHA_BASE; 2098219057Srrs net->cc_mod.htcp_ca.beta = BETA_MIN; 2099219057Srrs net->cc_mod.htcp_ca.bytes_acked = net->mtu; 2100219057Srrs net->cc_mod.htcp_ca.last_cong = sctp_get_tick_count(); 2101171440Srrs} 2102171440Srrs 2103217611Stuexenstatic void 2104171440Srrssctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) 2105171440Srrs{ 2106171440Srrs /* 2107171440Srrs * We take the max of the burst limit times a MTU or the 2108171440Srrs * INITIAL_CWND. We then limit this to 4 MTU's of sending. 2109171440Srrs */ 2110171440Srrs net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 2111171440Srrs net->ssthresh = stcb->asoc.peers_rwnd; 2112228653Stuexen htcp_init(net); 2113171440Srrs 2114179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { 2115171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); 2116171440Srrs } 2117171440Srrs} 2118171440Srrs 2119217611Stuexenstatic void 2120171440Srrssctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, 2121171440Srrs struct sctp_association *asoc, 2122228653Stuexen int accum_moved, int reneged_all SCTP_UNUSED, int will_exit) 2123171440Srrs{ 2124171440Srrs struct sctp_nets *net; 2125171440Srrs 2126171440Srrs /******************************/ 2127171440Srrs /* update cwnd and Early FR */ 2128171440Srrs /******************************/ 2129171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 2130171440Srrs 2131171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 2132171440Srrs /* 2133171440Srrs * CMT fast recovery code. Need to debug. 2134171440Srrs */ 2135171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 2136217469Stuexen if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) || 2137217469Stuexen SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) { 2138171440Srrs net->will_exit_fast_recovery = 1; 2139171440Srrs } 2140171440Srrs } 2141171440Srrs#endif 2142171440Srrs /* if nothing was acked on this destination skip it */ 2143171440Srrs if (net->net_ack == 0) { 2144179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 2145171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 2146171440Srrs } 2147171440Srrs continue; 2148171440Srrs } 2149171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 2150171440Srrs /* 2151171440Srrs * CMT fast recovery code 2152171440Srrs */ 2153171440Srrs /* 2154216669Stuexen * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery 2155216669Stuexen * && net->will_exit_fast_recovery == 0) { @@@ Do something 2156216669Stuexen * } else if (sctp_cmt_on_off == 0 && 2157171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 2158171440Srrs */ 2159171440Srrs#endif 2160171440Srrs 2161211944Stuexen if (asoc->fast_retran_loss_recovery && 2162211944Stuexen will_exit == 0 && 2163211944Stuexen (asoc->sctp_cmt_on_off == 0)) { 2164171440Srrs /* 2165171440Srrs * If we are in loss recovery we skip any cwnd 2166171440Srrs * update 2167171440Srrs */ 2168224641Stuexen return; 2169171440Srrs } 2170171440Srrs /* 2171171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 2172171440Srrs * moved. 2173171440Srrs */ 2174211944Stuexen if (accum_moved || 2175216669Stuexen ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) { 2176171440Srrs htcp_cong_avoid(stcb, net); 2177228653Stuexen measure_achieved_throughput(net); 2178171440Srrs } else { 2179179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 2180171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 2181171440Srrs SCTP_CWND_LOG_NO_CUMACK); 2182171440Srrs } 2183171440Srrs } 2184171440Srrs } 2185171440Srrs} 2186171440Srrs 2187217611Stuexenstatic void 2188171440Srrssctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb, 2189171440Srrs struct sctp_association *asoc) 2190171440Srrs{ 2191171440Srrs struct sctp_nets *net; 2192171440Srrs 2193171440Srrs /* 2194216669Stuexen * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) && 2195171440Srrs * (net->fast_retran_loss_recovery == 0))) 2196171440Srrs */ 2197171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 2198211944Stuexen if ((asoc->fast_retran_loss_recovery == 0) || 2199216669Stuexen (asoc->sctp_cmt_on_off > 0)) { 2200171440Srrs /* out of a RFC2582 Fast recovery window? */ 2201171440Srrs if (net->net_ack > 0) { 2202171440Srrs /* 2203171440Srrs * per section 7.2.3, are there any 2204171440Srrs * destinations that had a fast retransmit 2205171440Srrs * to them. If so what we need to do is 2206171440Srrs * adjust ssthresh and cwnd. 2207171440Srrs */ 2208171440Srrs struct sctp_tmit_chunk *lchk; 2209171440Srrs int old_cwnd = net->cwnd; 2210171440Srrs 2211171440Srrs /* JRS - reset as if state were changed */ 2212219057Srrs htcp_reset(&net->cc_mod.htcp_ca); 2213228653Stuexen net->ssthresh = htcp_recalc_ssthresh(net); 2214171440Srrs net->cwnd = net->ssthresh; 2215179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2216171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 2217171440Srrs SCTP_CWND_LOG_FROM_FR); 2218171440Srrs } 2219171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 2220171440Srrs 2221171440Srrs net->partial_bytes_acked = 0; 2222171440Srrs /* Turn on fast recovery window */ 2223171440Srrs asoc->fast_retran_loss_recovery = 1; 2224171440Srrs if (lchk == NULL) { 2225171440Srrs /* Mark end of the window */ 2226171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 2227171440Srrs } else { 2228171440Srrs asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 2229171440Srrs } 2230171440Srrs 2231171440Srrs /* 2232171440Srrs * CMT fast recovery -- per destination 2233171440Srrs * recovery variable. 2234171440Srrs */ 2235171440Srrs net->fast_retran_loss_recovery = 1; 2236171440Srrs 2237171440Srrs if (lchk == NULL) { 2238171440Srrs /* Mark end of the window */ 2239171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 2240171440Srrs } else { 2241171440Srrs net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 2242171440Srrs } 2243171440Srrs 2244171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 2245171440Srrs stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); 2246171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 2247171440Srrs stcb->sctp_ep, stcb, net); 2248171440Srrs } 2249171440Srrs } else if (net->net_ack > 0) { 2250171440Srrs /* 2251171440Srrs * Mark a peg that we WOULD have done a cwnd 2252171440Srrs * reduction but RFC2582 prevented this action. 2253171440Srrs */ 2254171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 2255171440Srrs } 2256171440Srrs } 2257171440Srrs} 2258171440Srrs 2259217611Stuexenstatic void 2260171440Srrssctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb, 2261171440Srrs struct sctp_nets *net) 2262171440Srrs{ 2263171440Srrs int old_cwnd = net->cwnd; 2264171440Srrs 2265171440Srrs /* JRS - reset as if the state were being changed to timeout */ 2266219057Srrs htcp_reset(&net->cc_mod.htcp_ca); 2267228653Stuexen net->ssthresh = htcp_recalc_ssthresh(net); 2268171440Srrs net->cwnd = net->mtu; 2269179157Srrs net->partial_bytes_acked = 0; 2270179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2271171440Srrs sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 2272171440Srrs } 2273171440Srrs} 2274171440Srrs 2275217611Stuexenstatic void 2276171440Srrssctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, 2277228653Stuexen struct sctp_nets *net, int in_window, int num_pkt_lost SCTP_UNUSED) 2278171440Srrs{ 2279171440Srrs int old_cwnd; 2280171440Srrs 2281171440Srrs old_cwnd = net->cwnd; 2282171440Srrs 2283171440Srrs /* JRS - reset hctp as if state changed */ 2284218129Srrs if (in_window == 0) { 2285219057Srrs htcp_reset(&net->cc_mod.htcp_ca); 2286218129Srrs SCTP_STAT_INCR(sctps_ecnereducedcwnd); 2287228653Stuexen net->ssthresh = htcp_recalc_ssthresh(net); 2288218129Srrs if (net->ssthresh < net->mtu) { 2289218129Srrs net->ssthresh = net->mtu; 2290218129Srrs /* here back off the timer as well, to slow us down */ 2291218129Srrs net->RTO <<= 1; 2292218129Srrs } 2293218129Srrs net->cwnd = net->ssthresh; 2294218129Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2295218129Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 2296218129Srrs } 2297171440Srrs } 2298171440Srrs} 2299217611Stuexen 2300217611Stuexenstruct sctp_cc_functions sctp_cc_functions[] = { 2301217611Stuexen { 2302217611Stuexen .sctp_set_initial_cc_param = sctp_set_initial_cc_param, 2303217611Stuexen .sctp_cwnd_update_after_sack = sctp_cwnd_update_after_sack, 2304224641Stuexen .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, 2305217611Stuexen .sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr, 2306217611Stuexen .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, 2307217611Stuexen .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo, 2308217611Stuexen .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, 2309217611Stuexen .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, 2310217611Stuexen }, 2311217611Stuexen { 2312217611Stuexen .sctp_set_initial_cc_param = sctp_set_initial_cc_param, 2313217611Stuexen .sctp_cwnd_update_after_sack = sctp_hs_cwnd_update_after_sack, 2314224641Stuexen .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, 2315217611Stuexen .sctp_cwnd_update_after_fr = sctp_hs_cwnd_update_after_fr, 2316217611Stuexen .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, 2317217611Stuexen .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo, 2318217611Stuexen .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, 2319217611Stuexen .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, 2320217611Stuexen }, 2321217611Stuexen { 2322217611Stuexen .sctp_set_initial_cc_param = sctp_htcp_set_initial_cc_param, 2323217611Stuexen .sctp_cwnd_update_after_sack = sctp_htcp_cwnd_update_after_sack, 2324224641Stuexen .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, 2325217611Stuexen .sctp_cwnd_update_after_fr = sctp_htcp_cwnd_update_after_fr, 2326217611Stuexen .sctp_cwnd_update_after_timeout = sctp_htcp_cwnd_update_after_timeout, 2327217611Stuexen .sctp_cwnd_update_after_ecn_echo = sctp_htcp_cwnd_update_after_ecn_echo, 2328217611Stuexen .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, 2329217611Stuexen .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, 2330219120Srrs }, 2331219120Srrs { 2332219120Srrs .sctp_set_initial_cc_param = sctp_set_rtcc_initial_cc_param, 2333219120Srrs .sctp_cwnd_update_after_sack = sctp_cwnd_update_rtcc_after_sack, 2334224641Stuexen .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, 2335219120Srrs .sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr, 2336219120Srrs .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, 2337219120Srrs .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_rtcc_after_ecn_echo, 2338219120Srrs .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, 2339219120Srrs .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, 2340219120Srrs .sctp_cwnd_update_packet_transmitted = sctp_cwnd_update_rtcc_packet_transmitted, 2341219120Srrs .sctp_cwnd_update_tsn_acknowledged = sctp_cwnd_update_rtcc_tsn_acknowledged, 2342219120Srrs .sctp_cwnd_new_transmission_begins = sctp_cwnd_new_rtcc_transmission_begins, 2343219120Srrs .sctp_cwnd_prepare_net_for_sack = sctp_cwnd_prepare_rtcc_net_for_sack, 2344219397Srrs .sctp_cwnd_socket_option = sctp_cwnd_rtcc_socket_option, 2345219397Srrs .sctp_rtt_calculated = sctp_rtt_rtcc_calculated 2346217611Stuexen } 2347217611Stuexen}; 2348