sctp_cc_functions.c revision 172090
1171440Srrs/*- 2171440Srrs * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 3171440Srrs * 4171440Srrs * Redistribution and use in source and binary forms, with or without 5171440Srrs * modification, are permitted provided that the following conditions are met: 6171440Srrs * 7171440Srrs * a) Redistributions of source code must retain the above copyright notice, 8171440Srrs * this list of conditions and the following disclaimer. 9171440Srrs * 10171440Srrs * b) Redistributions in binary form must reproduce the above copyright 11171440Srrs * notice, this list of conditions and the following disclaimer in 12171440Srrs * the documentation and/or other materials provided with the distribution. 13171440Srrs * 14171440Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its 15171440Srrs * contributors may be used to endorse or promote products derived 16171440Srrs * from this software without specific prior written permission. 17171440Srrs * 18171440Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19171440Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20171440Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21171440Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22171440Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23171440Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24171440Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25171440Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26171440Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27171440Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28171440Srrs * THE POSSIBILITY OF SUCH DAMAGE. 29171440Srrs */ 30171440Srrs 31171440Srrs#include <netinet/sctp_os.h> 32171440Srrs#include <netinet/sctp_var.h> 33171440Srrs#include <netinet/sctp_sysctl.h> 34171440Srrs#include <netinet/sctp_pcb.h> 35171440Srrs#include <netinet/sctp_header.h> 36171440Srrs#include <netinet/sctputil.h> 37171440Srrs#include <netinet/sctp_output.h> 38171440Srrs#include <netinet/sctp_input.h> 39171440Srrs#include <netinet/sctp_indata.h> 40171440Srrs#include <netinet/sctp_uio.h> 41171440Srrs#include <netinet/sctp_timer.h> 42171440Srrs#include <netinet/sctp_auth.h> 43171440Srrs#include <netinet/sctp_asconf.h> 44171440Srrs#include <netinet/sctp_cc_functions.h> 45171440Srrs#include <sys/cdefs.h> 46171440Srrs__FBSDID("$FreeBSD: head/sys/netinet/sctp_cc_functions.c 172090 2007-09-08 11:35:11Z rrs $"); 47171440Srrsvoid 48171440Srrssctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) 49171440Srrs{ 50171440Srrs /* 51171440Srrs * We take the max of the burst limit times a MTU or the 52171440Srrs * INITIAL_CWND. We then limit this to 4 MTU's of sending. 53171440Srrs */ 54171440Srrs net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 55171440Srrs /* we always get at LEAST 2 MTU's */ 56171440Srrs if (net->cwnd < (2 * net->mtu)) { 57171440Srrs net->cwnd = 2 * net->mtu; 58171440Srrs } 59171440Srrs net->ssthresh = stcb->asoc.peers_rwnd; 60171440Srrs 61171440Srrs if (sctp_logging_level & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { 62171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); 63171440Srrs } 64171440Srrs} 65171440Srrs 66171440Srrsvoid 67171440Srrssctp_cwnd_update_after_fr(struct sctp_tcb *stcb, 68171440Srrs struct sctp_association *asoc) 69171440Srrs{ 70171440Srrs struct sctp_nets *net; 71171440Srrs 72171440Srrs /*- 73171440Srrs * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off == 1) && 74171440Srrs * (net->fast_retran_loss_recovery == 0))) 75171440Srrs */ 76171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 77171440Srrs if ((asoc->fast_retran_loss_recovery == 0) || (sctp_cmt_on_off == 1)) { 78171440Srrs /* out of a RFC2582 Fast recovery window? */ 79171440Srrs if (net->net_ack > 0) { 80171440Srrs /* 81171440Srrs * per section 7.2.3, are there any 82171440Srrs * destinations that had a fast retransmit 83171440Srrs * to them. If so what we need to do is 84171440Srrs * adjust ssthresh and cwnd. 85171440Srrs */ 86171440Srrs struct sctp_tmit_chunk *lchk; 87171440Srrs int old_cwnd = net->cwnd; 88171440Srrs 89171440Srrs net->ssthresh = net->cwnd / 2; 90171440Srrs if (net->ssthresh < (net->mtu * 2)) { 91171440Srrs net->ssthresh = 2 * net->mtu; 92171440Srrs } 93171440Srrs net->cwnd = net->ssthresh; 94171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 95171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 96171440Srrs SCTP_CWND_LOG_FROM_FR); 97171440Srrs } 98171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 99171440Srrs 100171440Srrs net->partial_bytes_acked = 0; 101171440Srrs /* Turn on fast recovery window */ 102171440Srrs asoc->fast_retran_loss_recovery = 1; 103171440Srrs if (lchk == NULL) { 104171440Srrs /* Mark end of the window */ 105171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 106171440Srrs } else { 107171440Srrs asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 108171440Srrs } 109171440Srrs 110171440Srrs /* 111171440Srrs * CMT fast recovery -- per destination 112171440Srrs * recovery variable. 113171440Srrs */ 114171440Srrs net->fast_retran_loss_recovery = 1; 115171440Srrs 116171440Srrs if (lchk == NULL) { 117171440Srrs /* Mark end of the window */ 118171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 119171440Srrs } else { 120171440Srrs net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 121171440Srrs } 122171440Srrs 123171440Srrs /* 124171440Srrs * Disable Nonce Sum Checking and store the 125171440Srrs * resync tsn 126171440Srrs */ 127171440Srrs asoc->nonce_sum_check = 0; 128171440Srrs asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1; 129171440Srrs 130171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 131171440Srrs stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); 132171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 133171440Srrs stcb->sctp_ep, stcb, net); 134171440Srrs } 135171440Srrs } else if (net->net_ack > 0) { 136171440Srrs /* 137171440Srrs * Mark a peg that we WOULD have done a cwnd 138171440Srrs * reduction but RFC2582 prevented this action. 139171440Srrs */ 140171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 141171440Srrs } 142171440Srrs } 143171440Srrs} 144171440Srrs 145171440Srrsvoid 146171440Srrssctp_cwnd_update_after_sack(struct sctp_tcb *stcb, 147171440Srrs struct sctp_association *asoc, 148171440Srrs int accum_moved, int reneged_all, int will_exit) 149171440Srrs{ 150171440Srrs struct sctp_nets *net; 151171440Srrs 152171440Srrs /******************************/ 153171440Srrs /* update cwnd and Early FR */ 154171440Srrs /******************************/ 155171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 156171440Srrs 157171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 158171440Srrs /* 159171440Srrs * CMT fast recovery code. Need to debug. 160171440Srrs */ 161171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 162171440Srrs if (compare_with_wrap(asoc->last_acked_seq, 163171440Srrs net->fast_recovery_tsn, MAX_TSN) || 164171440Srrs (asoc->last_acked_seq == net->fast_recovery_tsn) || 165171440Srrs compare_with_wrap(net->pseudo_cumack, net->fast_recovery_tsn, MAX_TSN) || 166171440Srrs (net->pseudo_cumack == net->fast_recovery_tsn)) { 167171440Srrs net->will_exit_fast_recovery = 1; 168171440Srrs } 169171440Srrs } 170171440Srrs#endif 171171440Srrs if (sctp_early_fr) { 172171440Srrs /* 173171440Srrs * So, first of all do we need to have a Early FR 174171440Srrs * timer running? 175171440Srrs */ 176171440Srrs if (((TAILQ_FIRST(&asoc->sent_queue)) && 177171440Srrs (net->ref_count > 1) && 178171440Srrs (net->flight_size < net->cwnd)) || 179171440Srrs (reneged_all)) { 180171440Srrs /* 181171440Srrs * yes, so in this case stop it if its 182171440Srrs * running, and then restart it. Reneging 183171440Srrs * all is a special case where we want to 184171440Srrs * run the Early FR timer and then force the 185171440Srrs * last few unacked to be sent, causing us 186171440Srrs * to illicit a sack with gaps to force out 187171440Srrs * the others. 188171440Srrs */ 189171440Srrs if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 190171440Srrs SCTP_STAT_INCR(sctps_earlyfrstpidsck2); 191171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 192171440Srrs SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); 193171440Srrs } 194171440Srrs SCTP_STAT_INCR(sctps_earlyfrstrid); 195171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); 196171440Srrs } else { 197171440Srrs /* No, stop it if its running */ 198171440Srrs if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 199171440Srrs SCTP_STAT_INCR(sctps_earlyfrstpidsck3); 200171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 201171440Srrs SCTP_FROM_SCTP_INDATA + SCTP_LOC_21); 202171440Srrs } 203171440Srrs } 204171440Srrs } 205171440Srrs /* if nothing was acked on this destination skip it */ 206171440Srrs if (net->net_ack == 0) { 207171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 208171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 209171440Srrs } 210171440Srrs continue; 211171440Srrs } 212171440Srrs if (net->net_ack2 > 0) { 213171440Srrs /* 214171440Srrs * Karn's rule applies to clearing error count, this 215171440Srrs * is optional. 216171440Srrs */ 217171440Srrs net->error_count = 0; 218171440Srrs if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == 219171440Srrs SCTP_ADDR_NOT_REACHABLE) { 220171440Srrs /* addr came good */ 221171440Srrs net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; 222171440Srrs net->dest_state |= SCTP_ADDR_REACHABLE; 223171440Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 224172090Srrs SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED); 225171440Srrs /* now was it the primary? if so restore */ 226171440Srrs if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) { 227171440Srrs (void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net); 228171440Srrs } 229171440Srrs } 230171440Srrs /* 231171440Srrs * JRS 5/14/07 - If CMT PF is on and the destination 232171440Srrs * is in PF state, set the destination to active 233171440Srrs * state and set the cwnd to one or two MTU's based 234171440Srrs * on whether PF1 or PF2 is being used. 235171440Srrs * 236171440Srrs * Should we stop any running T3 timer here? 237171440Srrs */ 238171477Srrs if (sctp_cmt_on_off && sctp_cmt_pf && ((net->dest_state & SCTP_ADDR_PF) == 239171440Srrs SCTP_ADDR_PF)) { 240171440Srrs net->dest_state &= ~SCTP_ADDR_PF; 241171440Srrs net->cwnd = net->mtu * sctp_cmt_pf; 242171440Srrs SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", 243171440Srrs net, net->cwnd); 244171440Srrs /* 245171440Srrs * Since the cwnd value is explicitly set, 246171440Srrs * skip the code that updates the cwnd 247171440Srrs * value. 248171440Srrs */ 249171440Srrs goto skip_cwnd_update; 250171440Srrs } 251171440Srrs } 252171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 253171440Srrs /* 254171440Srrs * CMT fast recovery code 255171440Srrs */ 256171440Srrs /* 257171440Srrs * if (sctp_cmt_on_off == 1 && 258171440Srrs * net->fast_retran_loss_recovery && 259171440Srrs * net->will_exit_fast_recovery == 0) { @@@ Do something } 260171440Srrs * else if (sctp_cmt_on_off == 0 && 261171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 262171440Srrs */ 263171440Srrs#endif 264171440Srrs 265171440Srrs if (asoc->fast_retran_loss_recovery && will_exit == 0 && sctp_cmt_on_off == 0) { 266171440Srrs /* 267171440Srrs * If we are in loss recovery we skip any cwnd 268171440Srrs * update 269171440Srrs */ 270171440Srrs goto skip_cwnd_update; 271171440Srrs } 272171440Srrs /* 273171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 274171440Srrs * moved. 275171440Srrs */ 276171440Srrs if (accum_moved || (sctp_cmt_on_off && net->new_pseudo_cumack)) { 277171440Srrs /* If the cumulative ack moved we can proceed */ 278171440Srrs if (net->cwnd <= net->ssthresh) { 279171440Srrs /* We are in slow start */ 280171440Srrs if (net->flight_size + net->net_ack >= 281171440Srrs net->cwnd) { 282171440Srrs if (net->net_ack > (net->mtu * sctp_L2_abc_variable)) { 283171440Srrs net->cwnd += (net->mtu * sctp_L2_abc_variable); 284171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 285171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 286171440Srrs SCTP_CWND_LOG_FROM_SS); 287171440Srrs } 288171440Srrs } else { 289171440Srrs net->cwnd += net->net_ack; 290171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 291171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 292171440Srrs SCTP_CWND_LOG_FROM_SS); 293171440Srrs } 294171440Srrs } 295171440Srrs } else { 296171440Srrs unsigned int dif; 297171440Srrs 298171440Srrs dif = net->cwnd - (net->flight_size + 299171440Srrs net->net_ack); 300171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 301171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 302171440Srrs SCTP_CWND_LOG_NOADV_SS); 303171440Srrs } 304171440Srrs } 305171440Srrs } else { 306171440Srrs /* We are in congestion avoidance */ 307171440Srrs if (net->flight_size + net->net_ack >= 308171440Srrs net->cwnd) { 309171440Srrs /* 310171440Srrs * add to pba only if we had a 311171440Srrs * cwnd's worth (or so) in flight OR 312171440Srrs * the burst limit was applied. 313171440Srrs */ 314171440Srrs net->partial_bytes_acked += 315171440Srrs net->net_ack; 316171440Srrs 317171440Srrs /* 318171440Srrs * Do we need to increase (if pba is 319171440Srrs * > cwnd)? 320171440Srrs */ 321171440Srrs if (net->partial_bytes_acked >= 322171440Srrs net->cwnd) { 323171440Srrs if (net->cwnd < 324171440Srrs net->partial_bytes_acked) { 325171440Srrs net->partial_bytes_acked -= 326171440Srrs net->cwnd; 327171440Srrs } else { 328171440Srrs net->partial_bytes_acked = 329171440Srrs 0; 330171440Srrs } 331171440Srrs net->cwnd += net->mtu; 332171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 333171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 334171440Srrs SCTP_CWND_LOG_FROM_CA); 335171440Srrs } 336171440Srrs } else { 337171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 338171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 339171440Srrs SCTP_CWND_LOG_NOADV_CA); 340171440Srrs } 341171440Srrs } 342171440Srrs } else { 343171440Srrs unsigned int dif; 344171440Srrs 345171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 346171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 347171440Srrs SCTP_CWND_LOG_NOADV_CA); 348171440Srrs } 349171440Srrs dif = net->cwnd - (net->flight_size + 350171440Srrs net->net_ack); 351171440Srrs } 352171440Srrs } 353171440Srrs } else { 354171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 355171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 356171440Srrs SCTP_CWND_LOG_NO_CUMACK); 357171440Srrs } 358171440Srrs } 359171440Srrsskip_cwnd_update: 360171440Srrs /* 361171440Srrs * NOW, according to Karn's rule do we need to restore the 362171440Srrs * RTO timer back? Check our net_ack2. If not set then we 363171440Srrs * have a ambiguity.. i.e. all data ack'd was sent to more 364171440Srrs * than one place. 365171440Srrs */ 366171440Srrs if (net->net_ack2) { 367171440Srrs /* restore any doubled timers */ 368171440Srrs net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1; 369171440Srrs if (net->RTO < stcb->asoc.minrto) { 370171440Srrs net->RTO = stcb->asoc.minrto; 371171440Srrs } 372171440Srrs if (net->RTO > stcb->asoc.maxrto) { 373171440Srrs net->RTO = stcb->asoc.maxrto; 374171440Srrs } 375171440Srrs } 376171440Srrs } 377171440Srrs} 378171440Srrs 379171440Srrsvoid 380171440Srrssctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, 381171440Srrs struct sctp_nets *net) 382171440Srrs{ 383171440Srrs int old_cwnd = net->cwnd; 384171440Srrs 385171440Srrs net->ssthresh = net->cwnd >> 1; 386171440Srrs if (net->ssthresh < (net->mtu << 1)) { 387171440Srrs net->ssthresh = (net->mtu << 1); 388171440Srrs } 389171440Srrs net->cwnd = net->mtu; 390171440Srrs /* floor of 1 mtu */ 391171440Srrs if (net->cwnd < net->mtu) 392171440Srrs net->cwnd = net->mtu; 393171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 394171440Srrs sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 395171440Srrs } 396171440Srrs net->partial_bytes_acked = 0; 397171440Srrs} 398171440Srrs 399171440Srrsstruct sctp_hs_raise_drop { 400171440Srrs int32_t cwnd; 401171440Srrs int32_t increase; 402171440Srrs int32_t drop_percent; 403171440Srrs}; 404171440Srrs 405171440Srrs#define SCTP_HS_TABLE_SIZE 73 406171440Srrs 407171440Srrsstruct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = { 408171440Srrs {38, 1, 50}, /* 0 */ 409171440Srrs {118, 2, 44}, /* 1 */ 410171440Srrs {221, 3, 41}, /* 2 */ 411171440Srrs {347, 4, 38}, /* 3 */ 412171440Srrs {495, 5, 37}, /* 4 */ 413171440Srrs {663, 6, 35}, /* 5 */ 414171440Srrs {851, 7, 34}, /* 6 */ 415171440Srrs {1058, 8, 33}, /* 7 */ 416171440Srrs {1284, 9, 32}, /* 8 */ 417171440Srrs {1529, 10, 31}, /* 9 */ 418171440Srrs {1793, 11, 30}, /* 10 */ 419171440Srrs {2076, 12, 29}, /* 11 */ 420171440Srrs {2378, 13, 28}, /* 12 */ 421171440Srrs {2699, 14, 28}, /* 13 */ 422171440Srrs {3039, 15, 27}, /* 14 */ 423171440Srrs {3399, 16, 27}, /* 15 */ 424171440Srrs {3778, 17, 26}, /* 16 */ 425171440Srrs {4177, 18, 26}, /* 17 */ 426171440Srrs {4596, 19, 25}, /* 18 */ 427171440Srrs {5036, 20, 25}, /* 19 */ 428171440Srrs {5497, 21, 24}, /* 20 */ 429171440Srrs {5979, 22, 24}, /* 21 */ 430171440Srrs {6483, 23, 23}, /* 22 */ 431171440Srrs {7009, 24, 23}, /* 23 */ 432171440Srrs {7558, 25, 22}, /* 24 */ 433171440Srrs {8130, 26, 22}, /* 25 */ 434171440Srrs {8726, 27, 22}, /* 26 */ 435171440Srrs {9346, 28, 21}, /* 27 */ 436171440Srrs {9991, 29, 21}, /* 28 */ 437171440Srrs {10661, 30, 21}, /* 29 */ 438171440Srrs {11358, 31, 20}, /* 30 */ 439171440Srrs {12082, 32, 20}, /* 31 */ 440171440Srrs {12834, 33, 20}, /* 32 */ 441171440Srrs {13614, 34, 19}, /* 33 */ 442171440Srrs {14424, 35, 19}, /* 34 */ 443171440Srrs {15265, 36, 19}, /* 35 */ 444171440Srrs {16137, 37, 19}, /* 36 */ 445171440Srrs {17042, 38, 18}, /* 37 */ 446171440Srrs {17981, 39, 18}, /* 38 */ 447171440Srrs {18955, 40, 18}, /* 39 */ 448171440Srrs {19965, 41, 17}, /* 40 */ 449171440Srrs {21013, 42, 17}, /* 41 */ 450171440Srrs {22101, 43, 17}, /* 42 */ 451171440Srrs {23230, 44, 17}, /* 43 */ 452171440Srrs {24402, 45, 16}, /* 44 */ 453171440Srrs {25618, 46, 16}, /* 45 */ 454171440Srrs {26881, 47, 16}, /* 46 */ 455171440Srrs {28193, 48, 16}, /* 47 */ 456171440Srrs {29557, 49, 15}, /* 48 */ 457171440Srrs {30975, 50, 15}, /* 49 */ 458171440Srrs {32450, 51, 15}, /* 50 */ 459171440Srrs {33986, 52, 15}, /* 51 */ 460171440Srrs {35586, 53, 14}, /* 52 */ 461171440Srrs {37253, 54, 14}, /* 53 */ 462171440Srrs {38992, 55, 14}, /* 54 */ 463171440Srrs {40808, 56, 14}, /* 55 */ 464171440Srrs {42707, 57, 13}, /* 56 */ 465171440Srrs {44694, 58, 13}, /* 57 */ 466171440Srrs {46776, 59, 13}, /* 58 */ 467171440Srrs {48961, 60, 13}, /* 59 */ 468171440Srrs {51258, 61, 13}, /* 60 */ 469171440Srrs {53677, 62, 12}, /* 61 */ 470171440Srrs {56230, 63, 12}, /* 62 */ 471171440Srrs {58932, 64, 12}, /* 63 */ 472171440Srrs {61799, 65, 12}, /* 64 */ 473171440Srrs {64851, 66, 11}, /* 65 */ 474171440Srrs {68113, 67, 11}, /* 66 */ 475171440Srrs {71617, 68, 11}, /* 67 */ 476171440Srrs {75401, 69, 10}, /* 68 */ 477171440Srrs {79517, 70, 10}, /* 69 */ 478171440Srrs {84035, 71, 10}, /* 70 */ 479171440Srrs {89053, 72, 10}, /* 71 */ 480171440Srrs {94717, 73, 9} /* 72 */ 481171440Srrs}; 482171440Srrs 483171440Srrsstatic void 484171440Srrssctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net) 485171440Srrs{ 486171440Srrs int cur_val, i, indx, incr; 487171440Srrs 488171440Srrs cur_val = net->cwnd >> 10; 489171440Srrs indx = SCTP_HS_TABLE_SIZE - 1; 490171440Srrs#ifdef SCTP_DEBUG 491171440Srrs printf("HS CC CAlled.\n"); 492171440Srrs#endif 493171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 494171440Srrs /* normal mode */ 495171440Srrs if (net->net_ack > net->mtu) { 496171440Srrs net->cwnd += net->mtu; 497171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 498171440Srrs sctp_log_cwnd(stcb, net, net->mtu, SCTP_CWND_LOG_FROM_SS); 499171440Srrs } 500171440Srrs } else { 501171440Srrs net->cwnd += net->net_ack; 502171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 503171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, SCTP_CWND_LOG_FROM_SS); 504171440Srrs } 505171440Srrs } 506171440Srrs } else { 507171440Srrs for (i = net->last_hs_used; i < SCTP_HS_TABLE_SIZE; i++) { 508171440Srrs if (cur_val < sctp_cwnd_adjust[i].cwnd) { 509171440Srrs indx = i; 510171440Srrs break; 511171440Srrs } 512171440Srrs } 513171440Srrs net->last_hs_used = indx; 514171440Srrs incr = ((sctp_cwnd_adjust[indx].increase) << 10); 515171440Srrs net->cwnd += incr; 516171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 517171440Srrs sctp_log_cwnd(stcb, net, incr, SCTP_CWND_LOG_FROM_SS); 518171440Srrs } 519171440Srrs } 520171440Srrs} 521171440Srrs 522171440Srrsstatic void 523171440Srrssctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net) 524171440Srrs{ 525171440Srrs int cur_val, i, indx; 526171440Srrs int old_cwnd = net->cwnd; 527171440Srrs 528171440Srrs cur_val = net->cwnd >> 10; 529171440Srrs indx = net->last_hs_used; 530171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 531171440Srrs /* normal mode */ 532171440Srrs net->ssthresh = net->cwnd / 2; 533171440Srrs if (net->ssthresh < (net->mtu * 2)) { 534171440Srrs net->ssthresh = 2 * net->mtu; 535171440Srrs } 536171440Srrs net->cwnd = net->ssthresh; 537171440Srrs } else { 538171440Srrs /* drop by the proper amount */ 539171440Srrs net->ssthresh = net->cwnd - (int)((net->cwnd / 100) * 540171440Srrs sctp_cwnd_adjust[net->last_hs_used].drop_percent); 541171440Srrs net->cwnd = net->ssthresh; 542171440Srrs /* now where are we */ 543171440Srrs indx = net->last_hs_used; 544171440Srrs cur_val = net->cwnd >> 10; 545171440Srrs /* reset where we are in the table */ 546171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 547171440Srrs /* feel out of hs */ 548171440Srrs net->last_hs_used = 0; 549171440Srrs } else { 550171440Srrs for (i = indx; i >= 1; i--) { 551171440Srrs if (cur_val > sctp_cwnd_adjust[i - 1].cwnd) { 552171440Srrs break; 553171440Srrs } 554171440Srrs } 555171440Srrs net->last_hs_used = indx; 556171440Srrs } 557171440Srrs } 558171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 559171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_FR); 560171440Srrs } 561171440Srrs} 562171440Srrs 563171440Srrsvoid 564171440Srrssctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb, 565171440Srrs struct sctp_association *asoc) 566171440Srrs{ 567171440Srrs struct sctp_nets *net; 568171440Srrs 569171440Srrs /* 570171440Srrs * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off == 1) && 571171440Srrs * (net->fast_retran_loss_recovery == 0))) 572171440Srrs */ 573171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 574171440Srrs if ((asoc->fast_retran_loss_recovery == 0) || (sctp_cmt_on_off == 1)) { 575171440Srrs /* out of a RFC2582 Fast recovery window? */ 576171440Srrs if (net->net_ack > 0) { 577171440Srrs /* 578171440Srrs * per section 7.2.3, are there any 579171440Srrs * destinations that had a fast retransmit 580171440Srrs * to them. If so what we need to do is 581171440Srrs * adjust ssthresh and cwnd. 582171440Srrs */ 583171440Srrs struct sctp_tmit_chunk *lchk; 584171440Srrs 585171440Srrs sctp_hs_cwnd_decrease(stcb, net); 586171440Srrs 587171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 588171440Srrs 589171440Srrs net->partial_bytes_acked = 0; 590171440Srrs /* Turn on fast recovery window */ 591171440Srrs asoc->fast_retran_loss_recovery = 1; 592171440Srrs if (lchk == NULL) { 593171440Srrs /* Mark end of the window */ 594171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 595171440Srrs } else { 596171440Srrs asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 597171440Srrs } 598171440Srrs 599171440Srrs /* 600171440Srrs * CMT fast recovery -- per destination 601171440Srrs * recovery variable. 602171440Srrs */ 603171440Srrs net->fast_retran_loss_recovery = 1; 604171440Srrs 605171440Srrs if (lchk == NULL) { 606171440Srrs /* Mark end of the window */ 607171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 608171440Srrs } else { 609171440Srrs net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 610171440Srrs } 611171440Srrs 612171440Srrs /* 613171440Srrs * Disable Nonce Sum Checking and store the 614171440Srrs * resync tsn 615171440Srrs */ 616171440Srrs asoc->nonce_sum_check = 0; 617171440Srrs asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1; 618171440Srrs 619171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 620171440Srrs stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); 621171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 622171440Srrs stcb->sctp_ep, stcb, net); 623171440Srrs } 624171440Srrs } else if (net->net_ack > 0) { 625171440Srrs /* 626171440Srrs * Mark a peg that we WOULD have done a cwnd 627171440Srrs * reduction but RFC2582 prevented this action. 628171440Srrs */ 629171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 630171440Srrs } 631171440Srrs } 632171440Srrs} 633171440Srrs 634171440Srrsvoid 635171440Srrssctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, 636171440Srrs struct sctp_association *asoc, 637171440Srrs int accum_moved, int reneged_all, int will_exit) 638171440Srrs{ 639171440Srrs struct sctp_nets *net; 640171440Srrs 641171440Srrs /******************************/ 642171440Srrs /* update cwnd and Early FR */ 643171440Srrs /******************************/ 644171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 645171440Srrs 646171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 647171440Srrs /* 648171440Srrs * CMT fast recovery code. Need to debug. 649171440Srrs */ 650171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 651171440Srrs if (compare_with_wrap(asoc->last_acked_seq, 652171440Srrs net->fast_recovery_tsn, MAX_TSN) || 653171440Srrs (asoc->last_acked_seq == net->fast_recovery_tsn) || 654171440Srrs compare_with_wrap(net->pseudo_cumack, net->fast_recovery_tsn, MAX_TSN) || 655171440Srrs (net->pseudo_cumack == net->fast_recovery_tsn)) { 656171440Srrs net->will_exit_fast_recovery = 1; 657171440Srrs } 658171440Srrs } 659171440Srrs#endif 660171440Srrs if (sctp_early_fr) { 661171440Srrs /* 662171440Srrs * So, first of all do we need to have a Early FR 663171440Srrs * timer running? 664171440Srrs */ 665171440Srrs if (((TAILQ_FIRST(&asoc->sent_queue)) && 666171440Srrs (net->ref_count > 1) && 667171440Srrs (net->flight_size < net->cwnd)) || 668171440Srrs (reneged_all)) { 669171440Srrs /* 670171440Srrs * yes, so in this case stop it if its 671171440Srrs * running, and then restart it. Reneging 672171440Srrs * all is a special case where we want to 673171440Srrs * run the Early FR timer and then force the 674171440Srrs * last few unacked to be sent, causing us 675171440Srrs * to illicit a sack with gaps to force out 676171440Srrs * the others. 677171440Srrs */ 678171440Srrs if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 679171440Srrs SCTP_STAT_INCR(sctps_earlyfrstpidsck2); 680171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 681171440Srrs SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); 682171440Srrs } 683171440Srrs SCTP_STAT_INCR(sctps_earlyfrstrid); 684171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); 685171440Srrs } else { 686171440Srrs /* No, stop it if its running */ 687171440Srrs if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 688171440Srrs SCTP_STAT_INCR(sctps_earlyfrstpidsck3); 689171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 690171440Srrs SCTP_FROM_SCTP_INDATA + SCTP_LOC_21); 691171440Srrs } 692171440Srrs } 693171440Srrs } 694171440Srrs /* if nothing was acked on this destination skip it */ 695171440Srrs if (net->net_ack == 0) { 696171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 697171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 698171440Srrs } 699171440Srrs continue; 700171440Srrs } 701171440Srrs if (net->net_ack2 > 0) { 702171440Srrs /* 703171440Srrs * Karn's rule applies to clearing error count, this 704171440Srrs * is optional. 705171440Srrs */ 706171440Srrs net->error_count = 0; 707171440Srrs if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == 708171440Srrs SCTP_ADDR_NOT_REACHABLE) { 709171440Srrs /* addr came good */ 710171440Srrs net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; 711171440Srrs net->dest_state |= SCTP_ADDR_REACHABLE; 712171440Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 713172090Srrs SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED); 714171440Srrs /* now was it the primary? if so restore */ 715171440Srrs if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) { 716171440Srrs (void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net); 717171440Srrs } 718171440Srrs } 719171440Srrs /* 720171440Srrs * JRS 5/14/07 - If CMT PF is on and the destination 721171440Srrs * is in PF state, set the destination to active 722171440Srrs * state and set the cwnd to one or two MTU's based 723171440Srrs * on whether PF1 or PF2 is being used. 724171440Srrs * 725171440Srrs * Should we stop any running T3 timer here? 726171440Srrs */ 727171477Srrs if (sctp_cmt_on_off && sctp_cmt_pf && ((net->dest_state & SCTP_ADDR_PF) == 728171440Srrs SCTP_ADDR_PF)) { 729171440Srrs net->dest_state &= ~SCTP_ADDR_PF; 730171440Srrs net->cwnd = net->mtu * sctp_cmt_pf; 731171440Srrs SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", 732171440Srrs net, net->cwnd); 733171440Srrs /* 734171440Srrs * Since the cwnd value is explicitly set, 735171440Srrs * skip the code that updates the cwnd 736171440Srrs * value. 737171440Srrs */ 738171440Srrs goto skip_cwnd_update; 739171440Srrs } 740171440Srrs } 741171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 742171440Srrs /* 743171440Srrs * CMT fast recovery code 744171440Srrs */ 745171440Srrs /* 746171440Srrs * if (sctp_cmt_on_off == 1 && 747171440Srrs * net->fast_retran_loss_recovery && 748171440Srrs * net->will_exit_fast_recovery == 0) { @@@ Do something } 749171440Srrs * else if (sctp_cmt_on_off == 0 && 750171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 751171440Srrs */ 752171440Srrs#endif 753171440Srrs 754171440Srrs if (asoc->fast_retran_loss_recovery && will_exit == 0 && sctp_cmt_on_off == 0) { 755171440Srrs /* 756171440Srrs * If we are in loss recovery we skip any cwnd 757171440Srrs * update 758171440Srrs */ 759171440Srrs goto skip_cwnd_update; 760171440Srrs } 761171440Srrs /* 762171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 763171440Srrs * moved. 764171440Srrs */ 765171440Srrs if (accum_moved || (sctp_cmt_on_off && net->new_pseudo_cumack)) { 766171440Srrs /* If the cumulative ack moved we can proceed */ 767171440Srrs if (net->cwnd <= net->ssthresh) { 768171440Srrs /* We are in slow start */ 769171440Srrs if (net->flight_size + net->net_ack >= 770171440Srrs net->cwnd) { 771171440Srrs 772171440Srrs sctp_hs_cwnd_increase(stcb, net); 773171440Srrs 774171440Srrs } else { 775171440Srrs unsigned int dif; 776171440Srrs 777171440Srrs dif = net->cwnd - (net->flight_size + 778171440Srrs net->net_ack); 779171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 780171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 781171440Srrs SCTP_CWND_LOG_NOADV_SS); 782171440Srrs } 783171440Srrs } 784171440Srrs } else { 785171440Srrs /* We are in congestion avoidance */ 786171440Srrs if (net->flight_size + net->net_ack >= 787171440Srrs net->cwnd) { 788171440Srrs /* 789171440Srrs * add to pba only if we had a 790171440Srrs * cwnd's worth (or so) in flight OR 791171440Srrs * the burst limit was applied. 792171440Srrs */ 793171440Srrs net->partial_bytes_acked += 794171440Srrs net->net_ack; 795171440Srrs 796171440Srrs /* 797171440Srrs * Do we need to increase (if pba is 798171440Srrs * > cwnd)? 799171440Srrs */ 800171440Srrs if (net->partial_bytes_acked >= 801171440Srrs net->cwnd) { 802171440Srrs if (net->cwnd < 803171440Srrs net->partial_bytes_acked) { 804171440Srrs net->partial_bytes_acked -= 805171440Srrs net->cwnd; 806171440Srrs } else { 807171440Srrs net->partial_bytes_acked = 808171440Srrs 0; 809171440Srrs } 810171440Srrs net->cwnd += net->mtu; 811171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 812171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 813171440Srrs SCTP_CWND_LOG_FROM_CA); 814171440Srrs } 815171440Srrs } else { 816171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 817171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 818171440Srrs SCTP_CWND_LOG_NOADV_CA); 819171440Srrs } 820171440Srrs } 821171440Srrs } else { 822171440Srrs unsigned int dif; 823171440Srrs 824171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 825171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 826171440Srrs SCTP_CWND_LOG_NOADV_CA); 827171440Srrs } 828171440Srrs dif = net->cwnd - (net->flight_size + 829171440Srrs net->net_ack); 830171440Srrs } 831171440Srrs } 832171440Srrs } else { 833171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 834171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 835171440Srrs SCTP_CWND_LOG_NO_CUMACK); 836171440Srrs } 837171440Srrs } 838171440Srrsskip_cwnd_update: 839171440Srrs /* 840171440Srrs * NOW, according to Karn's rule do we need to restore the 841171440Srrs * RTO timer back? Check our net_ack2. If not set then we 842171440Srrs * have a ambiguity.. i.e. all data ack'd was sent to more 843171440Srrs * than one place. 844171440Srrs */ 845171440Srrs if (net->net_ack2) { 846171440Srrs /* restore any doubled timers */ 847171440Srrs net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1; 848171440Srrs if (net->RTO < stcb->asoc.minrto) { 849171440Srrs net->RTO = stcb->asoc.minrto; 850171440Srrs } 851171440Srrs if (net->RTO > stcb->asoc.maxrto) { 852171440Srrs net->RTO = stcb->asoc.maxrto; 853171440Srrs } 854171440Srrs } 855171440Srrs } 856171440Srrs} 857171440Srrs 858171440Srrsvoid 859171440Srrssctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, 860171440Srrs struct sctp_nets *net) 861171440Srrs{ 862171440Srrs int old_cwnd; 863171440Srrs 864171440Srrs old_cwnd = net->cwnd; 865171440Srrs 866171440Srrs SCTP_STAT_INCR(sctps_ecnereducedcwnd); 867171440Srrs net->ssthresh = net->cwnd / 2; 868171440Srrs if (net->ssthresh < net->mtu) { 869171440Srrs net->ssthresh = net->mtu; 870171440Srrs /* here back off the timer as well, to slow us down */ 871171440Srrs net->RTO <<= 1; 872171440Srrs } 873171440Srrs net->cwnd = net->ssthresh; 874171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 875171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 876171440Srrs } 877171440Srrs} 878171440Srrs 879171440Srrsvoid 880171440Srrssctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb, 881171440Srrs struct sctp_nets *net, struct sctp_pktdrop_chunk *cp, 882171440Srrs uint32_t * bottle_bw, uint32_t * on_queue) 883171440Srrs{ 884171440Srrs uint32_t bw_avail; 885171440Srrs int rtt, incr; 886171440Srrs int old_cwnd = net->cwnd; 887171440Srrs 888171440Srrs /* need real RTT for this calc */ 889171440Srrs rtt = ((net->lastsa >> 2) + net->lastsv) >> 1; 890171440Srrs /* get bottle neck bw */ 891171440Srrs *bottle_bw = ntohl(cp->bottle_bw); 892171440Srrs /* and whats on queue */ 893171440Srrs *on_queue = ntohl(cp->current_onq); 894171440Srrs /* 895171440Srrs * adjust the on-queue if our flight is more it could be that the 896171440Srrs * router has not yet gotten data "in-flight" to it 897171440Srrs */ 898171440Srrs if (*on_queue < net->flight_size) 899171440Srrs *on_queue = net->flight_size; 900171440Srrs /* calculate the available space */ 901171440Srrs bw_avail = (*bottle_bw * rtt) / 1000; 902171440Srrs if (bw_avail > *bottle_bw) { 903171440Srrs /* 904171440Srrs * Cap the growth to no more than the bottle neck. This can 905171440Srrs * happen as RTT slides up due to queues. It also means if 906171440Srrs * you have more than a 1 second RTT with a empty queue you 907171440Srrs * will be limited to the bottle_bw per second no matter if 908171440Srrs * other points have 1/2 the RTT and you could get more 909171440Srrs * out... 910171440Srrs */ 911171440Srrs bw_avail = *bottle_bw; 912171440Srrs } 913171440Srrs if (*on_queue > bw_avail) { 914171440Srrs /* 915171440Srrs * No room for anything else don't allow anything else to be 916171440Srrs * "added to the fire". 917171440Srrs */ 918171440Srrs int seg_inflight, seg_onqueue, my_portion; 919171440Srrs 920171440Srrs net->partial_bytes_acked = 0; 921171440Srrs 922171440Srrs /* how much are we over queue size? */ 923171440Srrs incr = *on_queue - bw_avail; 924171440Srrs if (stcb->asoc.seen_a_sack_this_pkt) { 925171440Srrs /* 926171440Srrs * undo any cwnd adjustment that the sack might have 927171440Srrs * made 928171440Srrs */ 929171440Srrs net->cwnd = net->prev_cwnd; 930171440Srrs } 931171440Srrs /* Now how much of that is mine? */ 932171440Srrs seg_inflight = net->flight_size / net->mtu; 933171440Srrs seg_onqueue = *on_queue / net->mtu; 934171440Srrs my_portion = (incr * seg_inflight) / seg_onqueue; 935171440Srrs 936171440Srrs /* Have I made an adjustment already */ 937171440Srrs if (net->cwnd > net->flight_size) { 938171440Srrs /* 939171440Srrs * for this flight I made an adjustment we need to 940171440Srrs * decrease the portion by a share our previous 941171440Srrs * adjustment. 942171440Srrs */ 943171440Srrs int diff_adj; 944171440Srrs 945171440Srrs diff_adj = net->cwnd - net->flight_size; 946171440Srrs if (diff_adj > my_portion) 947171440Srrs my_portion = 0; 948171440Srrs else 949171440Srrs my_portion -= diff_adj; 950171440Srrs } 951171440Srrs /* 952171440Srrs * back down to the previous cwnd (assume we have had a sack 953171440Srrs * before this packet). minus what ever portion of the 954171440Srrs * overage is my fault. 955171440Srrs */ 956171440Srrs net->cwnd -= my_portion; 957171440Srrs 958171440Srrs /* we will NOT back down more than 1 MTU */ 959171440Srrs if (net->cwnd <= net->mtu) { 960171440Srrs net->cwnd = net->mtu; 961171440Srrs } 962171440Srrs /* force into CA */ 963171440Srrs net->ssthresh = net->cwnd - 1; 964171440Srrs } else { 965171440Srrs /* 966171440Srrs * Take 1/4 of the space left or max burst up .. whichever 967171440Srrs * is less. 968171440Srrs */ 969171440Srrs incr = min((bw_avail - *on_queue) >> 2, 970171440Srrs stcb->asoc.max_burst * net->mtu); 971171440Srrs net->cwnd += incr; 972171440Srrs } 973171440Srrs if (net->cwnd > bw_avail) { 974171440Srrs /* We can't exceed the pipe size */ 975171440Srrs net->cwnd = bw_avail; 976171440Srrs } 977171440Srrs if (net->cwnd < net->mtu) { 978171440Srrs /* We always have 1 MTU */ 979171440Srrs net->cwnd = net->mtu; 980171440Srrs } 981171440Srrs if (net->cwnd - old_cwnd != 0) { 982171440Srrs /* log only changes */ 983171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 984171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 985171440Srrs SCTP_CWND_LOG_FROM_SAT); 986171440Srrs } 987171440Srrs } 988171440Srrs} 989171440Srrs 990171440Srrsvoid 991171440Srrssctp_cwnd_update_after_output(struct sctp_tcb *stcb, 992171440Srrs struct sctp_nets *net, int burst_limit) 993171440Srrs{ 994171440Srrs int old_cwnd; 995171440Srrs 996171440Srrs if (net->ssthresh < net->cwnd) 997171440Srrs net->ssthresh = net->cwnd; 998171440Srrs old_cwnd = net->cwnd; 999171440Srrs net->cwnd = (net->flight_size + (burst_limit * net->mtu)); 1000171440Srrs 1001171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1002171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST); 1003171440Srrs } 1004171440Srrs} 1005171440Srrs 1006171440Srrsvoid 1007171440Srrssctp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp, 1008171440Srrs struct sctp_tcb *stcb, struct sctp_nets *net) 1009171440Srrs{ 1010171440Srrs int old_cwnd; 1011171440Srrs 1012171440Srrs old_cwnd = net->cwnd; 1013171440Srrs 1014172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED); 1015171440Srrs /* 1016171440Srrs * make a small adjustment to cwnd and force to CA. 1017171440Srrs */ 1018171440Srrs if (net->cwnd > net->mtu) 1019171440Srrs /* drop down one MTU after sending */ 1020171440Srrs net->cwnd -= net->mtu; 1021171440Srrs if (net->cwnd < net->ssthresh) 1022171440Srrs /* still in SS move to CA */ 1023171440Srrs net->ssthresh = net->cwnd - 1; 1024171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1025171440Srrs sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR); 1026171440Srrs } 1027171440Srrs} 1028171440Srrs 1029171440Srrs/* 1030171440Srrs * H-TCP congestion control. The algorithm is detailed in: 1031171440Srrs * R.N.Shorten, D.J.Leith: 1032171440Srrs * "H-TCP: TCP for high-speed and long-distance networks" 1033171440Srrs * Proc. PFLDnet, Argonne, 2004. 1034171440Srrs * http://www.hamilton.ie/net/htcp3.pdf 1035171440Srrs */ 1036171440Srrs 1037171440Srrs 1038171440Srrsstatic int use_rtt_scaling = 1; 1039171440Srrsstatic int use_bandwidth_switch = 1; 1040171440Srrs 1041171440Srrsstatic inline int 1042171440Srrsbetween(uint32_t seq1, uint32_t seq2, uint32_t seq3) 1043171440Srrs{ 1044171440Srrs return seq3 - seq2 >= seq1 - seq2; 1045171440Srrs} 1046171440Srrs 1047171440Srrsstatic inline uint32_t 1048171440Srrshtcp_cong_time(struct htcp *ca) 1049171440Srrs{ 1050171477Srrs return sctp_get_tick_count() - ca->last_cong; 1051171440Srrs} 1052171440Srrs 1053171440Srrsstatic inline uint32_t 1054171440Srrshtcp_ccount(struct htcp *ca) 1055171440Srrs{ 1056171440Srrs return htcp_cong_time(ca) / ca->minRTT; 1057171440Srrs} 1058171440Srrs 1059171440Srrsstatic inline void 1060171440Srrshtcp_reset(struct htcp *ca) 1061171440Srrs{ 1062171440Srrs ca->undo_last_cong = ca->last_cong; 1063171440Srrs ca->undo_maxRTT = ca->maxRTT; 1064171440Srrs ca->undo_old_maxB = ca->old_maxB; 1065171477Srrs ca->last_cong = sctp_get_tick_count(); 1066171440Srrs} 1067171440Srrs 1068171440Srrs#ifdef SCTP_NOT_USED 1069171440Srrs 1070171440Srrsstatic uint32_t 1071171440Srrshtcp_cwnd_undo(struct sctp_tcb *stcb, struct sctp_nets *net) 1072171440Srrs{ 1073171440Srrs net->htcp_ca.last_cong = net->htcp_ca.undo_last_cong; 1074171440Srrs net->htcp_ca.maxRTT = net->htcp_ca.undo_maxRTT; 1075171440Srrs net->htcp_ca.old_maxB = net->htcp_ca.undo_old_maxB; 1076171440Srrs return max(net->cwnd, ((net->ssthresh / net->mtu << 7) / net->htcp_ca.beta) * net->mtu); 1077171440Srrs} 1078171440Srrs 1079171440Srrs#endif 1080171440Srrs 1081171440Srrsstatic inline void 1082171440Srrsmeasure_rtt(struct sctp_tcb *stcb, struct sctp_nets *net) 1083171440Srrs{ 1084171440Srrs uint32_t srtt = net->lastsa >> 3; 1085171440Srrs 1086171440Srrs /* keep track of minimum RTT seen so far, minRTT is zero at first */ 1087171440Srrs if (net->htcp_ca.minRTT > srtt || !net->htcp_ca.minRTT) 1088171440Srrs net->htcp_ca.minRTT = srtt; 1089171440Srrs 1090171440Srrs /* max RTT */ 1091171440Srrs if (net->fast_retran_ip == 0 && net->ssthresh < 0xFFFF && htcp_ccount(&net->htcp_ca) > 3) { 1092171440Srrs if (net->htcp_ca.maxRTT < net->htcp_ca.minRTT) 1093171440Srrs net->htcp_ca.maxRTT = net->htcp_ca.minRTT; 1094171440Srrs if (net->htcp_ca.maxRTT < srtt && srtt <= net->htcp_ca.maxRTT + MSEC_TO_TICKS(20)) 1095171440Srrs net->htcp_ca.maxRTT = srtt; 1096171440Srrs } 1097171440Srrs} 1098171440Srrs 1099171440Srrsstatic void 1100171440Srrsmeasure_achieved_throughput(struct sctp_tcb *stcb, struct sctp_nets *net) 1101171440Srrs{ 1102171477Srrs uint32_t now = sctp_get_tick_count(); 1103171440Srrs 1104171440Srrs if (net->fast_retran_ip == 0) 1105171440Srrs net->htcp_ca.bytes_acked = net->net_ack; 1106171440Srrs 1107171440Srrs if (!use_bandwidth_switch) 1108171440Srrs return; 1109171440Srrs 1110171440Srrs /* achieved throughput calculations */ 1111171440Srrs /* JRS - not 100% sure of this statement */ 1112171440Srrs if (net->fast_retran_ip == 1) { 1113171440Srrs net->htcp_ca.bytecount = 0; 1114171440Srrs net->htcp_ca.lasttime = now; 1115171440Srrs return; 1116171440Srrs } 1117171440Srrs net->htcp_ca.bytecount += net->net_ack; 1118171440Srrs 1119171440Srrs if (net->htcp_ca.bytecount >= net->cwnd - ((net->htcp_ca.alpha >> 7 ? : 1) * net->mtu) 1120171440Srrs && now - net->htcp_ca.lasttime >= net->htcp_ca.minRTT 1121171440Srrs && net->htcp_ca.minRTT > 0) { 1122171440Srrs uint32_t cur_Bi = net->htcp_ca.bytecount / net->mtu * hz / (now - net->htcp_ca.lasttime); 1123171440Srrs 1124171440Srrs if (htcp_ccount(&net->htcp_ca) <= 3) { 1125171440Srrs /* just after backoff */ 1126171440Srrs net->htcp_ca.minB = net->htcp_ca.maxB = net->htcp_ca.Bi = cur_Bi; 1127171440Srrs } else { 1128171440Srrs net->htcp_ca.Bi = (3 * net->htcp_ca.Bi + cur_Bi) / 4; 1129171440Srrs if (net->htcp_ca.Bi > net->htcp_ca.maxB) 1130171440Srrs net->htcp_ca.maxB = net->htcp_ca.Bi; 1131171440Srrs if (net->htcp_ca.minB > net->htcp_ca.maxB) 1132171440Srrs net->htcp_ca.minB = net->htcp_ca.maxB; 1133171440Srrs } 1134171440Srrs net->htcp_ca.bytecount = 0; 1135171440Srrs net->htcp_ca.lasttime = now; 1136171440Srrs } 1137171440Srrs} 1138171440Srrs 1139171440Srrsstatic inline void 1140171440Srrshtcp_beta_update(struct htcp *ca, uint32_t minRTT, uint32_t maxRTT) 1141171440Srrs{ 1142171440Srrs if (use_bandwidth_switch) { 1143171440Srrs uint32_t maxB = ca->maxB; 1144171440Srrs uint32_t old_maxB = ca->old_maxB; 1145171440Srrs 1146171440Srrs ca->old_maxB = ca->maxB; 1147171440Srrs 1148171440Srrs if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) { 1149171440Srrs ca->beta = BETA_MIN; 1150171440Srrs ca->modeswitch = 0; 1151171440Srrs return; 1152171440Srrs } 1153171440Srrs } 1154171440Srrs if (ca->modeswitch && minRTT > (uint32_t) MSEC_TO_TICKS(10) && maxRTT) { 1155171440Srrs ca->beta = (minRTT << 7) / maxRTT; 1156171440Srrs if (ca->beta < BETA_MIN) 1157171440Srrs ca->beta = BETA_MIN; 1158171440Srrs else if (ca->beta > BETA_MAX) 1159171440Srrs ca->beta = BETA_MAX; 1160171440Srrs } else { 1161171440Srrs ca->beta = BETA_MIN; 1162171440Srrs ca->modeswitch = 1; 1163171440Srrs } 1164171440Srrs} 1165171440Srrs 1166171440Srrsstatic inline void 1167171440Srrshtcp_alpha_update(struct htcp *ca) 1168171440Srrs{ 1169171440Srrs uint32_t minRTT = ca->minRTT; 1170171440Srrs uint32_t factor = 1; 1171171440Srrs uint32_t diff = htcp_cong_time(ca); 1172171440Srrs 1173171440Srrs if (diff > (uint32_t) hz) { 1174171440Srrs diff -= hz; 1175171440Srrs factor = 1 + (10 * diff + ((diff / 2) * (diff / 2) / hz)) / hz; 1176171440Srrs } 1177171440Srrs if (use_rtt_scaling && minRTT) { 1178171440Srrs uint32_t scale = (hz << 3) / (10 * minRTT); 1179171440Srrs 1180171440Srrs scale = min(max(scale, 1U << 2), 10U << 3); /* clamping ratio to 1181171440Srrs * interval [0.5,10]<<3 */ 1182171440Srrs factor = (factor << 3) / scale; 1183171440Srrs if (!factor) 1184171440Srrs factor = 1; 1185171440Srrs } 1186171440Srrs ca->alpha = 2 * factor * ((1 << 7) - ca->beta); 1187171440Srrs if (!ca->alpha) 1188171440Srrs ca->alpha = ALPHA_BASE; 1189171440Srrs} 1190171440Srrs 1191171440Srrs/* After we have the rtt data to calculate beta, we'd still prefer to wait one 1192171440Srrs * rtt before we adjust our beta to ensure we are working from a consistent 1193171440Srrs * data. 1194171440Srrs * 1195171440Srrs * This function should be called when we hit a congestion event since only at 1196171440Srrs * that point do we really have a real sense of maxRTT (the queues en route 1197171440Srrs * were getting just too full now). 1198171440Srrs */ 1199171440Srrsstatic void 1200171440Srrshtcp_param_update(struct sctp_tcb *stcb, struct sctp_nets *net) 1201171440Srrs{ 1202171440Srrs uint32_t minRTT = net->htcp_ca.minRTT; 1203171440Srrs uint32_t maxRTT = net->htcp_ca.maxRTT; 1204171440Srrs 1205171440Srrs htcp_beta_update(&net->htcp_ca, minRTT, maxRTT); 1206171440Srrs htcp_alpha_update(&net->htcp_ca); 1207171440Srrs 1208171440Srrs /* 1209171440Srrs * add slowly fading memory for maxRTT to accommodate routing 1210171440Srrs * changes etc 1211171440Srrs */ 1212171440Srrs if (minRTT > 0 && maxRTT > minRTT) 1213171440Srrs net->htcp_ca.maxRTT = minRTT + ((maxRTT - minRTT) * 95) / 100; 1214171440Srrs} 1215171440Srrs 1216171440Srrsstatic uint32_t 1217171440Srrshtcp_recalc_ssthresh(struct sctp_tcb *stcb, struct sctp_nets *net) 1218171440Srrs{ 1219171440Srrs htcp_param_update(stcb, net); 1220171440Srrs return max(((net->cwnd / net->mtu * net->htcp_ca.beta) >> 7) * net->mtu, 2U * net->mtu); 1221171440Srrs} 1222171440Srrs 1223171440Srrsstatic void 1224171440Srrshtcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net) 1225171440Srrs{ 1226171440Srrs /*- 1227171440Srrs * How to handle these functions? 1228171440Srrs * if (!tcp_is_cwnd_limited(sk, in_flight)) RRS - good question. 1229171440Srrs * return; 1230171440Srrs */ 1231171440Srrs if (net->cwnd <= net->ssthresh) { 1232171440Srrs /* We are in slow start */ 1233171440Srrs if (net->flight_size + net->net_ack >= net->cwnd) { 1234171440Srrs if (net->net_ack > (net->mtu * sctp_L2_abc_variable)) { 1235171440Srrs net->cwnd += (net->mtu * sctp_L2_abc_variable); 1236171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1237171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 1238171440Srrs SCTP_CWND_LOG_FROM_SS); 1239171440Srrs } 1240171440Srrs } else { 1241171440Srrs net->cwnd += net->net_ack; 1242171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1243171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 1244171440Srrs SCTP_CWND_LOG_FROM_SS); 1245171440Srrs } 1246171440Srrs } 1247171440Srrs } else { 1248171440Srrs unsigned int dif; 1249171440Srrs 1250171440Srrs dif = net->cwnd - (net->flight_size + 1251171440Srrs net->net_ack); 1252171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 1253171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 1254171440Srrs SCTP_CWND_LOG_NOADV_SS); 1255171440Srrs } 1256171440Srrs } 1257171440Srrs } else { 1258171440Srrs measure_rtt(stcb, net); 1259171440Srrs 1260171440Srrs /* 1261171440Srrs * In dangerous area, increase slowly. In theory this is 1262171440Srrs * net->cwnd += alpha / net->cwnd 1263171440Srrs */ 1264171440Srrs /* What is snd_cwnd_cnt?? */ 1265171440Srrs if (((net->partial_bytes_acked / net->mtu * net->htcp_ca.alpha) >> 7) * net->mtu >= net->cwnd) { 1266171440Srrs /*- 1267171440Srrs * Does SCTP have a cwnd clamp? 1268171440Srrs * if (net->snd_cwnd < net->snd_cwnd_clamp) - Nope (RRS). 1269171440Srrs */ 1270171440Srrs net->cwnd += net->mtu; 1271171440Srrs net->partial_bytes_acked = 0; 1272171440Srrs htcp_alpha_update(&net->htcp_ca); 1273171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1274171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 1275171440Srrs SCTP_CWND_LOG_FROM_CA); 1276171440Srrs } 1277171440Srrs } else { 1278171440Srrs net->partial_bytes_acked += net->net_ack; 1279171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 1280171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 1281171440Srrs SCTP_CWND_LOG_NOADV_CA); 1282171440Srrs } 1283171440Srrs } 1284171440Srrs 1285171440Srrs net->htcp_ca.bytes_acked = net->mtu; 1286171440Srrs } 1287171440Srrs} 1288171440Srrs 1289171440Srrs#ifdef SCTP_NOT_USED 1290171440Srrs/* Lower bound on congestion window. */ 1291171440Srrsstatic uint32_t 1292171440Srrshtcp_min_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net) 1293171440Srrs{ 1294171440Srrs return net->ssthresh; 1295171440Srrs} 1296171440Srrs 1297171440Srrs#endif 1298171440Srrs 1299171440Srrsstatic void 1300171440Srrshtcp_init(struct sctp_tcb *stcb, struct sctp_nets *net) 1301171440Srrs{ 1302171440Srrs memset(&net->htcp_ca, 0, sizeof(struct htcp)); 1303171440Srrs net->htcp_ca.alpha = ALPHA_BASE; 1304171440Srrs net->htcp_ca.beta = BETA_MIN; 1305171440Srrs net->htcp_ca.bytes_acked = net->mtu; 1306171477Srrs net->htcp_ca.last_cong = sctp_get_tick_count(); 1307171440Srrs} 1308171440Srrs 1309171440Srrsvoid 1310171440Srrssctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) 1311171440Srrs{ 1312171440Srrs /* 1313171440Srrs * We take the max of the burst limit times a MTU or the 1314171440Srrs * INITIAL_CWND. We then limit this to 4 MTU's of sending. 1315171440Srrs */ 1316171440Srrs net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 1317171440Srrs /* we always get at LEAST 2 MTU's */ 1318171440Srrs if (net->cwnd < (2 * net->mtu)) { 1319171440Srrs net->cwnd = 2 * net->mtu; 1320171440Srrs } 1321171440Srrs net->ssthresh = stcb->asoc.peers_rwnd; 1322171440Srrs htcp_init(stcb, net); 1323171440Srrs 1324171440Srrs if (sctp_logging_level & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { 1325171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); 1326171440Srrs } 1327171440Srrs} 1328171440Srrs 1329171440Srrsvoid 1330171440Srrssctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, 1331171440Srrs struct sctp_association *asoc, 1332171440Srrs int accum_moved, int reneged_all, int will_exit) 1333171440Srrs{ 1334171440Srrs struct sctp_nets *net; 1335171440Srrs 1336171440Srrs /******************************/ 1337171440Srrs /* update cwnd and Early FR */ 1338171440Srrs /******************************/ 1339171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 1340171440Srrs 1341171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 1342171440Srrs /* 1343171440Srrs * CMT fast recovery code. Need to debug. 1344171440Srrs */ 1345171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 1346171440Srrs if (compare_with_wrap(asoc->last_acked_seq, 1347171440Srrs net->fast_recovery_tsn, MAX_TSN) || 1348171440Srrs (asoc->last_acked_seq == net->fast_recovery_tsn) || 1349171440Srrs compare_with_wrap(net->pseudo_cumack, net->fast_recovery_tsn, MAX_TSN) || 1350171440Srrs (net->pseudo_cumack == net->fast_recovery_tsn)) { 1351171440Srrs net->will_exit_fast_recovery = 1; 1352171440Srrs } 1353171440Srrs } 1354171440Srrs#endif 1355171440Srrs if (sctp_early_fr) { 1356171440Srrs /* 1357171440Srrs * So, first of all do we need to have a Early FR 1358171440Srrs * timer running? 1359171440Srrs */ 1360171440Srrs if (((TAILQ_FIRST(&asoc->sent_queue)) && 1361171440Srrs (net->ref_count > 1) && 1362171440Srrs (net->flight_size < net->cwnd)) || 1363171440Srrs (reneged_all)) { 1364171440Srrs /* 1365171440Srrs * yes, so in this case stop it if its 1366171440Srrs * running, and then restart it. Reneging 1367171440Srrs * all is a special case where we want to 1368171440Srrs * run the Early FR timer and then force the 1369171440Srrs * last few unacked to be sent, causing us 1370171440Srrs * to illicit a sack with gaps to force out 1371171440Srrs * the others. 1372171440Srrs */ 1373171440Srrs if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 1374171440Srrs SCTP_STAT_INCR(sctps_earlyfrstpidsck2); 1375171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 1376171440Srrs SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); 1377171440Srrs } 1378171440Srrs SCTP_STAT_INCR(sctps_earlyfrstrid); 1379171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); 1380171440Srrs } else { 1381171440Srrs /* No, stop it if its running */ 1382171440Srrs if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 1383171440Srrs SCTP_STAT_INCR(sctps_earlyfrstpidsck3); 1384171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 1385171440Srrs SCTP_FROM_SCTP_INDATA + SCTP_LOC_21); 1386171440Srrs } 1387171440Srrs } 1388171440Srrs } 1389171440Srrs /* if nothing was acked on this destination skip it */ 1390171440Srrs if (net->net_ack == 0) { 1391171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 1392171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 1393171440Srrs } 1394171440Srrs continue; 1395171440Srrs } 1396171440Srrs if (net->net_ack2 > 0) { 1397171440Srrs /* 1398171440Srrs * Karn's rule applies to clearing error count, this 1399171440Srrs * is optional. 1400171440Srrs */ 1401171440Srrs net->error_count = 0; 1402171440Srrs if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == 1403171440Srrs SCTP_ADDR_NOT_REACHABLE) { 1404171440Srrs /* addr came good */ 1405171440Srrs net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; 1406171440Srrs net->dest_state |= SCTP_ADDR_REACHABLE; 1407171440Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 1408172090Srrs SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED); 1409171440Srrs /* now was it the primary? if so restore */ 1410171440Srrs if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) { 1411171440Srrs (void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net); 1412171440Srrs } 1413171440Srrs } 1414171440Srrs /* 1415171440Srrs * JRS 5/14/07 - If CMT PF is on and the destination 1416171440Srrs * is in PF state, set the destination to active 1417171440Srrs * state and set the cwnd to one or two MTU's based 1418171440Srrs * on whether PF1 or PF2 is being used. 1419171440Srrs * 1420171440Srrs * Should we stop any running T3 timer here? 1421171440Srrs */ 1422171477Srrs if (sctp_cmt_on_off && sctp_cmt_pf && ((net->dest_state & SCTP_ADDR_PF) == 1423171440Srrs SCTP_ADDR_PF)) { 1424171440Srrs net->dest_state &= ~SCTP_ADDR_PF; 1425171440Srrs net->cwnd = net->mtu * sctp_cmt_pf; 1426171440Srrs SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", 1427171440Srrs net, net->cwnd); 1428171440Srrs /* 1429171440Srrs * Since the cwnd value is explicitly set, 1430171440Srrs * skip the code that updates the cwnd 1431171440Srrs * value. 1432171440Srrs */ 1433171440Srrs goto skip_cwnd_update; 1434171440Srrs } 1435171440Srrs } 1436171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 1437171440Srrs /* 1438171440Srrs * CMT fast recovery code 1439171440Srrs */ 1440171440Srrs /* 1441171440Srrs * if (sctp_cmt_on_off == 1 && 1442171440Srrs * net->fast_retran_loss_recovery && 1443171440Srrs * net->will_exit_fast_recovery == 0) { @@@ Do something } 1444171440Srrs * else if (sctp_cmt_on_off == 0 && 1445171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 1446171440Srrs */ 1447171440Srrs#endif 1448171440Srrs 1449171440Srrs if (asoc->fast_retran_loss_recovery && will_exit == 0 && sctp_cmt_on_off == 0) { 1450171440Srrs /* 1451171440Srrs * If we are in loss recovery we skip any cwnd 1452171440Srrs * update 1453171440Srrs */ 1454171440Srrs goto skip_cwnd_update; 1455171440Srrs } 1456171440Srrs /* 1457171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 1458171440Srrs * moved. 1459171440Srrs */ 1460171440Srrs if (accum_moved || (sctp_cmt_on_off && net->new_pseudo_cumack)) { 1461171440Srrs htcp_cong_avoid(stcb, net); 1462171440Srrs measure_achieved_throughput(stcb, net); 1463171440Srrs } else { 1464171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 1465171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 1466171440Srrs SCTP_CWND_LOG_NO_CUMACK); 1467171440Srrs } 1468171440Srrs } 1469171440Srrsskip_cwnd_update: 1470171440Srrs /* 1471171440Srrs * NOW, according to Karn's rule do we need to restore the 1472171440Srrs * RTO timer back? Check our net_ack2. If not set then we 1473171440Srrs * have a ambiguity.. i.e. all data ack'd was sent to more 1474171440Srrs * than one place. 1475171440Srrs */ 1476171440Srrs if (net->net_ack2) { 1477171440Srrs /* restore any doubled timers */ 1478171440Srrs net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1; 1479171440Srrs if (net->RTO < stcb->asoc.minrto) { 1480171440Srrs net->RTO = stcb->asoc.minrto; 1481171440Srrs } 1482171440Srrs if (net->RTO > stcb->asoc.maxrto) { 1483171440Srrs net->RTO = stcb->asoc.maxrto; 1484171440Srrs } 1485171440Srrs } 1486171440Srrs } 1487171440Srrs} 1488171440Srrs 1489171440Srrsvoid 1490171440Srrssctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb, 1491171440Srrs struct sctp_association *asoc) 1492171440Srrs{ 1493171440Srrs struct sctp_nets *net; 1494171440Srrs 1495171440Srrs /* 1496171440Srrs * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off == 1) && 1497171440Srrs * (net->fast_retran_loss_recovery == 0))) 1498171440Srrs */ 1499171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 1500171440Srrs if ((asoc->fast_retran_loss_recovery == 0) || (sctp_cmt_on_off == 1)) { 1501171440Srrs /* out of a RFC2582 Fast recovery window? */ 1502171440Srrs if (net->net_ack > 0) { 1503171440Srrs /* 1504171440Srrs * per section 7.2.3, are there any 1505171440Srrs * destinations that had a fast retransmit 1506171440Srrs * to them. If so what we need to do is 1507171440Srrs * adjust ssthresh and cwnd. 1508171440Srrs */ 1509171440Srrs struct sctp_tmit_chunk *lchk; 1510171440Srrs int old_cwnd = net->cwnd; 1511171440Srrs 1512171440Srrs /* JRS - reset as if state were changed */ 1513171440Srrs htcp_reset(&net->htcp_ca); 1514171440Srrs net->ssthresh = htcp_recalc_ssthresh(stcb, net); 1515171440Srrs net->cwnd = net->ssthresh; 1516171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1517171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 1518171440Srrs SCTP_CWND_LOG_FROM_FR); 1519171440Srrs } 1520171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 1521171440Srrs 1522171440Srrs net->partial_bytes_acked = 0; 1523171440Srrs /* Turn on fast recovery window */ 1524171440Srrs asoc->fast_retran_loss_recovery = 1; 1525171440Srrs if (lchk == NULL) { 1526171440Srrs /* Mark end of the window */ 1527171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 1528171440Srrs } else { 1529171440Srrs asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 1530171440Srrs } 1531171440Srrs 1532171440Srrs /* 1533171440Srrs * CMT fast recovery -- per destination 1534171440Srrs * recovery variable. 1535171440Srrs */ 1536171440Srrs net->fast_retran_loss_recovery = 1; 1537171440Srrs 1538171440Srrs if (lchk == NULL) { 1539171440Srrs /* Mark end of the window */ 1540171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 1541171440Srrs } else { 1542171440Srrs net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 1543171440Srrs } 1544171440Srrs 1545171440Srrs /* 1546171440Srrs * Disable Nonce Sum Checking and store the 1547171440Srrs * resync tsn 1548171440Srrs */ 1549171440Srrs asoc->nonce_sum_check = 0; 1550171440Srrs asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1; 1551171440Srrs 1552171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 1553171440Srrs stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); 1554171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 1555171440Srrs stcb->sctp_ep, stcb, net); 1556171440Srrs } 1557171440Srrs } else if (net->net_ack > 0) { 1558171440Srrs /* 1559171440Srrs * Mark a peg that we WOULD have done a cwnd 1560171440Srrs * reduction but RFC2582 prevented this action. 1561171440Srrs */ 1562171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 1563171440Srrs } 1564171440Srrs } 1565171440Srrs} 1566171440Srrs 1567171440Srrsvoid 1568171440Srrssctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb, 1569171440Srrs struct sctp_nets *net) 1570171440Srrs{ 1571171440Srrs int old_cwnd = net->cwnd; 1572171440Srrs 1573171440Srrs /* JRS - reset as if the state were being changed to timeout */ 1574171440Srrs htcp_reset(&net->htcp_ca); 1575171440Srrs net->ssthresh = htcp_recalc_ssthresh(stcb, net); 1576171440Srrs net->cwnd = net->mtu; 1577171440Srrs /* floor of 1 mtu */ 1578171440Srrs if (net->cwnd < net->mtu) 1579171440Srrs net->cwnd = net->mtu; 1580171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1581171440Srrs sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 1582171440Srrs } 1583171440Srrs net->partial_bytes_acked = 0; 1584171440Srrs} 1585171440Srrs 1586171440Srrsvoid 1587171440Srrssctp_htcp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp, 1588171440Srrs struct sctp_tcb *stcb, struct sctp_nets *net) 1589171440Srrs{ 1590171440Srrs int old_cwnd; 1591171440Srrs 1592171440Srrs old_cwnd = net->cwnd; 1593171440Srrs 1594172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED); 1595171477Srrs net->htcp_ca.last_cong = sctp_get_tick_count(); 1596171440Srrs /* 1597171440Srrs * make a small adjustment to cwnd and force to CA. 1598171440Srrs */ 1599171440Srrs if (net->cwnd > net->mtu) 1600171440Srrs /* drop down one MTU after sending */ 1601171440Srrs net->cwnd -= net->mtu; 1602171440Srrs if (net->cwnd < net->ssthresh) 1603171440Srrs /* still in SS move to CA */ 1604171440Srrs net->ssthresh = net->cwnd - 1; 1605171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1606171440Srrs sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR); 1607171440Srrs } 1608171440Srrs} 1609171440Srrs 1610171440Srrsvoid 1611171440Srrssctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, 1612171440Srrs struct sctp_nets *net) 1613171440Srrs{ 1614171440Srrs int old_cwnd; 1615171440Srrs 1616171440Srrs old_cwnd = net->cwnd; 1617171440Srrs 1618171440Srrs /* JRS - reset hctp as if state changed */ 1619171440Srrs htcp_reset(&net->htcp_ca); 1620171440Srrs SCTP_STAT_INCR(sctps_ecnereducedcwnd); 1621171440Srrs net->ssthresh = htcp_recalc_ssthresh(stcb, net); 1622171440Srrs if (net->ssthresh < net->mtu) { 1623171440Srrs net->ssthresh = net->mtu; 1624171440Srrs /* here back off the timer as well, to slow us down */ 1625171440Srrs net->RTO <<= 1; 1626171440Srrs } 1627171440Srrs net->cwnd = net->ssthresh; 1628171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1629171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 1630171440Srrs } 1631171440Srrs} 1632