sctp_cc_functions.c revision 179141
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 179141 2008-05-20 09:51:36Z 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 */ 307179141Srrs /* 308179141Srrs * Add to pba 309179141Srrs */ 310179141Srrs net->partial_bytes_acked += 311179141Srrs net->net_ack; 312171440Srrs 313179141Srrs if ((net->flight_size + net->net_ack >= net->cwnd) && 314179141Srrs (net->partial_bytes_acked >= net->cwnd)) { 315179141Srrs net->partial_bytes_acked -= net->cwnd; 316179141Srrs net->cwnd += net->mtu; 317179141Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 318179141Srrs sctp_log_cwnd(stcb, net, net->mtu, 319179141Srrs SCTP_CWND_LOG_FROM_CA); 320171440Srrs } 321171440Srrs } else { 322171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 323171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 324171440Srrs SCTP_CWND_LOG_NOADV_CA); 325171440Srrs } 326171440Srrs } 327171440Srrs } 328171440Srrs } else { 329171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 330171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 331171440Srrs SCTP_CWND_LOG_NO_CUMACK); 332171440Srrs } 333171440Srrs } 334171440Srrsskip_cwnd_update: 335171440Srrs /* 336171440Srrs * NOW, according to Karn's rule do we need to restore the 337171440Srrs * RTO timer back? Check our net_ack2. If not set then we 338171440Srrs * have a ambiguity.. i.e. all data ack'd was sent to more 339171440Srrs * than one place. 340171440Srrs */ 341171440Srrs if (net->net_ack2) { 342171440Srrs /* restore any doubled timers */ 343171440Srrs net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1; 344171440Srrs if (net->RTO < stcb->asoc.minrto) { 345171440Srrs net->RTO = stcb->asoc.minrto; 346171440Srrs } 347171440Srrs if (net->RTO > stcb->asoc.maxrto) { 348171440Srrs net->RTO = stcb->asoc.maxrto; 349171440Srrs } 350171440Srrs } 351171440Srrs } 352171440Srrs} 353171440Srrs 354171440Srrsvoid 355171440Srrssctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, 356171440Srrs struct sctp_nets *net) 357171440Srrs{ 358171440Srrs int old_cwnd = net->cwnd; 359171440Srrs 360171440Srrs net->ssthresh = net->cwnd >> 1; 361171440Srrs if (net->ssthresh < (net->mtu << 1)) { 362171440Srrs net->ssthresh = (net->mtu << 1); 363171440Srrs } 364171440Srrs net->cwnd = net->mtu; 365171440Srrs /* floor of 1 mtu */ 366171440Srrs if (net->cwnd < net->mtu) 367171440Srrs net->cwnd = net->mtu; 368171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 369171440Srrs sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 370171440Srrs } 371171440Srrs net->partial_bytes_acked = 0; 372171440Srrs} 373171440Srrs 374171440Srrsstruct sctp_hs_raise_drop { 375171440Srrs int32_t cwnd; 376171440Srrs int32_t increase; 377171440Srrs int32_t drop_percent; 378171440Srrs}; 379171440Srrs 380171440Srrs#define SCTP_HS_TABLE_SIZE 73 381171440Srrs 382171440Srrsstruct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = { 383171440Srrs {38, 1, 50}, /* 0 */ 384171440Srrs {118, 2, 44}, /* 1 */ 385171440Srrs {221, 3, 41}, /* 2 */ 386171440Srrs {347, 4, 38}, /* 3 */ 387171440Srrs {495, 5, 37}, /* 4 */ 388171440Srrs {663, 6, 35}, /* 5 */ 389171440Srrs {851, 7, 34}, /* 6 */ 390171440Srrs {1058, 8, 33}, /* 7 */ 391171440Srrs {1284, 9, 32}, /* 8 */ 392171440Srrs {1529, 10, 31}, /* 9 */ 393171440Srrs {1793, 11, 30}, /* 10 */ 394171440Srrs {2076, 12, 29}, /* 11 */ 395171440Srrs {2378, 13, 28}, /* 12 */ 396171440Srrs {2699, 14, 28}, /* 13 */ 397171440Srrs {3039, 15, 27}, /* 14 */ 398171440Srrs {3399, 16, 27}, /* 15 */ 399171440Srrs {3778, 17, 26}, /* 16 */ 400171440Srrs {4177, 18, 26}, /* 17 */ 401171440Srrs {4596, 19, 25}, /* 18 */ 402171440Srrs {5036, 20, 25}, /* 19 */ 403171440Srrs {5497, 21, 24}, /* 20 */ 404171440Srrs {5979, 22, 24}, /* 21 */ 405171440Srrs {6483, 23, 23}, /* 22 */ 406171440Srrs {7009, 24, 23}, /* 23 */ 407171440Srrs {7558, 25, 22}, /* 24 */ 408171440Srrs {8130, 26, 22}, /* 25 */ 409171440Srrs {8726, 27, 22}, /* 26 */ 410171440Srrs {9346, 28, 21}, /* 27 */ 411171440Srrs {9991, 29, 21}, /* 28 */ 412171440Srrs {10661, 30, 21}, /* 29 */ 413171440Srrs {11358, 31, 20}, /* 30 */ 414171440Srrs {12082, 32, 20}, /* 31 */ 415171440Srrs {12834, 33, 20}, /* 32 */ 416171440Srrs {13614, 34, 19}, /* 33 */ 417171440Srrs {14424, 35, 19}, /* 34 */ 418171440Srrs {15265, 36, 19}, /* 35 */ 419171440Srrs {16137, 37, 19}, /* 36 */ 420171440Srrs {17042, 38, 18}, /* 37 */ 421171440Srrs {17981, 39, 18}, /* 38 */ 422171440Srrs {18955, 40, 18}, /* 39 */ 423171440Srrs {19965, 41, 17}, /* 40 */ 424171440Srrs {21013, 42, 17}, /* 41 */ 425171440Srrs {22101, 43, 17}, /* 42 */ 426171440Srrs {23230, 44, 17}, /* 43 */ 427171440Srrs {24402, 45, 16}, /* 44 */ 428171440Srrs {25618, 46, 16}, /* 45 */ 429171440Srrs {26881, 47, 16}, /* 46 */ 430171440Srrs {28193, 48, 16}, /* 47 */ 431171440Srrs {29557, 49, 15}, /* 48 */ 432171440Srrs {30975, 50, 15}, /* 49 */ 433171440Srrs {32450, 51, 15}, /* 50 */ 434171440Srrs {33986, 52, 15}, /* 51 */ 435171440Srrs {35586, 53, 14}, /* 52 */ 436171440Srrs {37253, 54, 14}, /* 53 */ 437171440Srrs {38992, 55, 14}, /* 54 */ 438171440Srrs {40808, 56, 14}, /* 55 */ 439171440Srrs {42707, 57, 13}, /* 56 */ 440171440Srrs {44694, 58, 13}, /* 57 */ 441171440Srrs {46776, 59, 13}, /* 58 */ 442171440Srrs {48961, 60, 13}, /* 59 */ 443171440Srrs {51258, 61, 13}, /* 60 */ 444171440Srrs {53677, 62, 12}, /* 61 */ 445171440Srrs {56230, 63, 12}, /* 62 */ 446171440Srrs {58932, 64, 12}, /* 63 */ 447171440Srrs {61799, 65, 12}, /* 64 */ 448171440Srrs {64851, 66, 11}, /* 65 */ 449171440Srrs {68113, 67, 11}, /* 66 */ 450171440Srrs {71617, 68, 11}, /* 67 */ 451171440Srrs {75401, 69, 10}, /* 68 */ 452171440Srrs {79517, 70, 10}, /* 69 */ 453171440Srrs {84035, 71, 10}, /* 70 */ 454171440Srrs {89053, 72, 10}, /* 71 */ 455171440Srrs {94717, 73, 9} /* 72 */ 456171440Srrs}; 457171440Srrs 458171440Srrsstatic void 459171440Srrssctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net) 460171440Srrs{ 461171440Srrs int cur_val, i, indx, incr; 462171440Srrs 463171440Srrs cur_val = net->cwnd >> 10; 464171440Srrs indx = SCTP_HS_TABLE_SIZE - 1; 465171440Srrs#ifdef SCTP_DEBUG 466171440Srrs printf("HS CC CAlled.\n"); 467171440Srrs#endif 468171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 469171440Srrs /* normal mode */ 470171440Srrs if (net->net_ack > net->mtu) { 471171440Srrs net->cwnd += net->mtu; 472171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 473171440Srrs sctp_log_cwnd(stcb, net, net->mtu, SCTP_CWND_LOG_FROM_SS); 474171440Srrs } 475171440Srrs } else { 476171440Srrs net->cwnd += net->net_ack; 477171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 478171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, SCTP_CWND_LOG_FROM_SS); 479171440Srrs } 480171440Srrs } 481171440Srrs } else { 482171440Srrs for (i = net->last_hs_used; i < SCTP_HS_TABLE_SIZE; i++) { 483171440Srrs if (cur_val < sctp_cwnd_adjust[i].cwnd) { 484171440Srrs indx = i; 485171440Srrs break; 486171440Srrs } 487171440Srrs } 488171440Srrs net->last_hs_used = indx; 489171440Srrs incr = ((sctp_cwnd_adjust[indx].increase) << 10); 490171440Srrs net->cwnd += incr; 491171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 492171440Srrs sctp_log_cwnd(stcb, net, incr, SCTP_CWND_LOG_FROM_SS); 493171440Srrs } 494171440Srrs } 495171440Srrs} 496171440Srrs 497171440Srrsstatic void 498171440Srrssctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net) 499171440Srrs{ 500171440Srrs int cur_val, i, indx; 501171440Srrs int old_cwnd = net->cwnd; 502171440Srrs 503171440Srrs cur_val = net->cwnd >> 10; 504171440Srrs indx = net->last_hs_used; 505171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 506171440Srrs /* normal mode */ 507171440Srrs net->ssthresh = net->cwnd / 2; 508171440Srrs if (net->ssthresh < (net->mtu * 2)) { 509171440Srrs net->ssthresh = 2 * net->mtu; 510171440Srrs } 511171440Srrs net->cwnd = net->ssthresh; 512171440Srrs } else { 513171440Srrs /* drop by the proper amount */ 514171440Srrs net->ssthresh = net->cwnd - (int)((net->cwnd / 100) * 515171440Srrs sctp_cwnd_adjust[net->last_hs_used].drop_percent); 516171440Srrs net->cwnd = net->ssthresh; 517171440Srrs /* now where are we */ 518171440Srrs indx = net->last_hs_used; 519171440Srrs cur_val = net->cwnd >> 10; 520171440Srrs /* reset where we are in the table */ 521171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 522171440Srrs /* feel out of hs */ 523171440Srrs net->last_hs_used = 0; 524171440Srrs } else { 525171440Srrs for (i = indx; i >= 1; i--) { 526171440Srrs if (cur_val > sctp_cwnd_adjust[i - 1].cwnd) { 527171440Srrs break; 528171440Srrs } 529171440Srrs } 530171440Srrs net->last_hs_used = indx; 531171440Srrs } 532171440Srrs } 533171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 534171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_FR); 535171440Srrs } 536171440Srrs} 537171440Srrs 538171440Srrsvoid 539171440Srrssctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb, 540171440Srrs struct sctp_association *asoc) 541171440Srrs{ 542171440Srrs struct sctp_nets *net; 543171440Srrs 544171440Srrs /* 545171440Srrs * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off == 1) && 546171440Srrs * (net->fast_retran_loss_recovery == 0))) 547171440Srrs */ 548171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 549171440Srrs if ((asoc->fast_retran_loss_recovery == 0) || (sctp_cmt_on_off == 1)) { 550171440Srrs /* out of a RFC2582 Fast recovery window? */ 551171440Srrs if (net->net_ack > 0) { 552171440Srrs /* 553171440Srrs * per section 7.2.3, are there any 554171440Srrs * destinations that had a fast retransmit 555171440Srrs * to them. If so what we need to do is 556171440Srrs * adjust ssthresh and cwnd. 557171440Srrs */ 558171440Srrs struct sctp_tmit_chunk *lchk; 559171440Srrs 560171440Srrs sctp_hs_cwnd_decrease(stcb, net); 561171440Srrs 562171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 563171440Srrs 564171440Srrs net->partial_bytes_acked = 0; 565171440Srrs /* Turn on fast recovery window */ 566171440Srrs asoc->fast_retran_loss_recovery = 1; 567171440Srrs if (lchk == NULL) { 568171440Srrs /* Mark end of the window */ 569171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 570171440Srrs } else { 571171440Srrs asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 572171440Srrs } 573171440Srrs 574171440Srrs /* 575171440Srrs * CMT fast recovery -- per destination 576171440Srrs * recovery variable. 577171440Srrs */ 578171440Srrs net->fast_retran_loss_recovery = 1; 579171440Srrs 580171440Srrs if (lchk == NULL) { 581171440Srrs /* Mark end of the window */ 582171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 583171440Srrs } else { 584171440Srrs net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 585171440Srrs } 586171440Srrs 587171440Srrs /* 588171440Srrs * Disable Nonce Sum Checking and store the 589171440Srrs * resync tsn 590171440Srrs */ 591171440Srrs asoc->nonce_sum_check = 0; 592171440Srrs asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1; 593171440Srrs 594171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 595171440Srrs stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); 596171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 597171440Srrs stcb->sctp_ep, stcb, net); 598171440Srrs } 599171440Srrs } else if (net->net_ack > 0) { 600171440Srrs /* 601171440Srrs * Mark a peg that we WOULD have done a cwnd 602171440Srrs * reduction but RFC2582 prevented this action. 603171440Srrs */ 604171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 605171440Srrs } 606171440Srrs } 607171440Srrs} 608171440Srrs 609171440Srrsvoid 610171440Srrssctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, 611171440Srrs struct sctp_association *asoc, 612171440Srrs int accum_moved, int reneged_all, int will_exit) 613171440Srrs{ 614171440Srrs struct sctp_nets *net; 615171440Srrs 616171440Srrs /******************************/ 617171440Srrs /* update cwnd and Early FR */ 618171440Srrs /******************************/ 619171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 620171440Srrs 621171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 622171440Srrs /* 623171440Srrs * CMT fast recovery code. Need to debug. 624171440Srrs */ 625171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 626171440Srrs if (compare_with_wrap(asoc->last_acked_seq, 627171440Srrs net->fast_recovery_tsn, MAX_TSN) || 628171440Srrs (asoc->last_acked_seq == net->fast_recovery_tsn) || 629171440Srrs compare_with_wrap(net->pseudo_cumack, net->fast_recovery_tsn, MAX_TSN) || 630171440Srrs (net->pseudo_cumack == net->fast_recovery_tsn)) { 631171440Srrs net->will_exit_fast_recovery = 1; 632171440Srrs } 633171440Srrs } 634171440Srrs#endif 635171440Srrs if (sctp_early_fr) { 636171440Srrs /* 637171440Srrs * So, first of all do we need to have a Early FR 638171440Srrs * timer running? 639171440Srrs */ 640171440Srrs if (((TAILQ_FIRST(&asoc->sent_queue)) && 641171440Srrs (net->ref_count > 1) && 642171440Srrs (net->flight_size < net->cwnd)) || 643171440Srrs (reneged_all)) { 644171440Srrs /* 645171440Srrs * yes, so in this case stop it if its 646171440Srrs * running, and then restart it. Reneging 647171440Srrs * all is a special case where we want to 648171440Srrs * run the Early FR timer and then force the 649171440Srrs * last few unacked to be sent, causing us 650171440Srrs * to illicit a sack with gaps to force out 651171440Srrs * the others. 652171440Srrs */ 653171440Srrs if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 654171440Srrs SCTP_STAT_INCR(sctps_earlyfrstpidsck2); 655171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 656171440Srrs SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); 657171440Srrs } 658171440Srrs SCTP_STAT_INCR(sctps_earlyfrstrid); 659171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); 660171440Srrs } else { 661171440Srrs /* No, stop it if its running */ 662171440Srrs if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 663171440Srrs SCTP_STAT_INCR(sctps_earlyfrstpidsck3); 664171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 665171440Srrs SCTP_FROM_SCTP_INDATA + SCTP_LOC_21); 666171440Srrs } 667171440Srrs } 668171440Srrs } 669171440Srrs /* if nothing was acked on this destination skip it */ 670171440Srrs if (net->net_ack == 0) { 671171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 672171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 673171440Srrs } 674171440Srrs continue; 675171440Srrs } 676171440Srrs if (net->net_ack2 > 0) { 677171440Srrs /* 678171440Srrs * Karn's rule applies to clearing error count, this 679171440Srrs * is optional. 680171440Srrs */ 681171440Srrs net->error_count = 0; 682171440Srrs if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == 683171440Srrs SCTP_ADDR_NOT_REACHABLE) { 684171440Srrs /* addr came good */ 685171440Srrs net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; 686171440Srrs net->dest_state |= SCTP_ADDR_REACHABLE; 687171440Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 688172090Srrs SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED); 689171440Srrs /* now was it the primary? if so restore */ 690171440Srrs if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) { 691171440Srrs (void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net); 692171440Srrs } 693171440Srrs } 694171440Srrs /* 695171440Srrs * JRS 5/14/07 - If CMT PF is on and the destination 696171440Srrs * is in PF state, set the destination to active 697171440Srrs * state and set the cwnd to one or two MTU's based 698171440Srrs * on whether PF1 or PF2 is being used. 699171440Srrs * 700171440Srrs * Should we stop any running T3 timer here? 701171440Srrs */ 702171477Srrs if (sctp_cmt_on_off && sctp_cmt_pf && ((net->dest_state & SCTP_ADDR_PF) == 703171440Srrs SCTP_ADDR_PF)) { 704171440Srrs net->dest_state &= ~SCTP_ADDR_PF; 705171440Srrs net->cwnd = net->mtu * sctp_cmt_pf; 706171440Srrs SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", 707171440Srrs net, net->cwnd); 708171440Srrs /* 709171440Srrs * Since the cwnd value is explicitly set, 710171440Srrs * skip the code that updates the cwnd 711171440Srrs * value. 712171440Srrs */ 713171440Srrs goto skip_cwnd_update; 714171440Srrs } 715171440Srrs } 716171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 717171440Srrs /* 718171440Srrs * CMT fast recovery code 719171440Srrs */ 720171440Srrs /* 721171440Srrs * if (sctp_cmt_on_off == 1 && 722171440Srrs * net->fast_retran_loss_recovery && 723171440Srrs * net->will_exit_fast_recovery == 0) { @@@ Do something } 724171440Srrs * else if (sctp_cmt_on_off == 0 && 725171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 726171440Srrs */ 727171440Srrs#endif 728171440Srrs 729171440Srrs if (asoc->fast_retran_loss_recovery && will_exit == 0 && sctp_cmt_on_off == 0) { 730171440Srrs /* 731171440Srrs * If we are in loss recovery we skip any cwnd 732171440Srrs * update 733171440Srrs */ 734171440Srrs goto skip_cwnd_update; 735171440Srrs } 736171440Srrs /* 737171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 738171440Srrs * moved. 739171440Srrs */ 740171440Srrs if (accum_moved || (sctp_cmt_on_off && net->new_pseudo_cumack)) { 741171440Srrs /* If the cumulative ack moved we can proceed */ 742171440Srrs if (net->cwnd <= net->ssthresh) { 743171440Srrs /* We are in slow start */ 744171440Srrs if (net->flight_size + net->net_ack >= 745171440Srrs net->cwnd) { 746171440Srrs 747171440Srrs sctp_hs_cwnd_increase(stcb, net); 748171440Srrs 749171440Srrs } else { 750171440Srrs unsigned int dif; 751171440Srrs 752171440Srrs dif = net->cwnd - (net->flight_size + 753171440Srrs net->net_ack); 754171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 755171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 756171440Srrs SCTP_CWND_LOG_NOADV_SS); 757171440Srrs } 758171440Srrs } 759171440Srrs } else { 760171440Srrs /* We are in congestion avoidance */ 761171440Srrs if (net->flight_size + net->net_ack >= 762171440Srrs net->cwnd) { 763171440Srrs /* 764171440Srrs * add to pba only if we had a 765171440Srrs * cwnd's worth (or so) in flight OR 766171440Srrs * the burst limit was applied. 767171440Srrs */ 768171440Srrs net->partial_bytes_acked += 769171440Srrs net->net_ack; 770171440Srrs 771171440Srrs /* 772171440Srrs * Do we need to increase (if pba is 773171440Srrs * > cwnd)? 774171440Srrs */ 775171440Srrs if (net->partial_bytes_acked >= 776171440Srrs net->cwnd) { 777171440Srrs if (net->cwnd < 778171440Srrs net->partial_bytes_acked) { 779171440Srrs net->partial_bytes_acked -= 780171440Srrs net->cwnd; 781171440Srrs } else { 782171440Srrs net->partial_bytes_acked = 783171440Srrs 0; 784171440Srrs } 785171440Srrs net->cwnd += net->mtu; 786171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 787171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 788171440Srrs SCTP_CWND_LOG_FROM_CA); 789171440Srrs } 790171440Srrs } else { 791171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 792171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 793171440Srrs SCTP_CWND_LOG_NOADV_CA); 794171440Srrs } 795171440Srrs } 796171440Srrs } else { 797171440Srrs unsigned int dif; 798171440Srrs 799171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 800171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 801171440Srrs SCTP_CWND_LOG_NOADV_CA); 802171440Srrs } 803171440Srrs dif = net->cwnd - (net->flight_size + 804171440Srrs net->net_ack); 805171440Srrs } 806171440Srrs } 807171440Srrs } else { 808171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 809171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 810171440Srrs SCTP_CWND_LOG_NO_CUMACK); 811171440Srrs } 812171440Srrs } 813171440Srrsskip_cwnd_update: 814171440Srrs /* 815171440Srrs * NOW, according to Karn's rule do we need to restore the 816171440Srrs * RTO timer back? Check our net_ack2. If not set then we 817171440Srrs * have a ambiguity.. i.e. all data ack'd was sent to more 818171440Srrs * than one place. 819171440Srrs */ 820171440Srrs if (net->net_ack2) { 821171440Srrs /* restore any doubled timers */ 822171440Srrs net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1; 823171440Srrs if (net->RTO < stcb->asoc.minrto) { 824171440Srrs net->RTO = stcb->asoc.minrto; 825171440Srrs } 826171440Srrs if (net->RTO > stcb->asoc.maxrto) { 827171440Srrs net->RTO = stcb->asoc.maxrto; 828171440Srrs } 829171440Srrs } 830171440Srrs } 831171440Srrs} 832171440Srrs 833171440Srrsvoid 834171440Srrssctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, 835171440Srrs struct sctp_nets *net) 836171440Srrs{ 837171440Srrs int old_cwnd; 838171440Srrs 839171440Srrs old_cwnd = net->cwnd; 840171440Srrs 841171440Srrs SCTP_STAT_INCR(sctps_ecnereducedcwnd); 842171440Srrs net->ssthresh = net->cwnd / 2; 843171440Srrs if (net->ssthresh < net->mtu) { 844171440Srrs net->ssthresh = net->mtu; 845171440Srrs /* here back off the timer as well, to slow us down */ 846171440Srrs net->RTO <<= 1; 847171440Srrs } 848171440Srrs net->cwnd = net->ssthresh; 849171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 850171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 851171440Srrs } 852171440Srrs} 853171440Srrs 854171440Srrsvoid 855171440Srrssctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb, 856171440Srrs struct sctp_nets *net, struct sctp_pktdrop_chunk *cp, 857171440Srrs uint32_t * bottle_bw, uint32_t * on_queue) 858171440Srrs{ 859171440Srrs uint32_t bw_avail; 860171440Srrs int rtt, incr; 861171440Srrs int old_cwnd = net->cwnd; 862171440Srrs 863171440Srrs /* need real RTT for this calc */ 864171440Srrs rtt = ((net->lastsa >> 2) + net->lastsv) >> 1; 865171440Srrs /* get bottle neck bw */ 866171440Srrs *bottle_bw = ntohl(cp->bottle_bw); 867171440Srrs /* and whats on queue */ 868171440Srrs *on_queue = ntohl(cp->current_onq); 869171440Srrs /* 870171440Srrs * adjust the on-queue if our flight is more it could be that the 871171440Srrs * router has not yet gotten data "in-flight" to it 872171440Srrs */ 873171440Srrs if (*on_queue < net->flight_size) 874171440Srrs *on_queue = net->flight_size; 875171440Srrs /* calculate the available space */ 876171440Srrs bw_avail = (*bottle_bw * rtt) / 1000; 877171440Srrs if (bw_avail > *bottle_bw) { 878171440Srrs /* 879171440Srrs * Cap the growth to no more than the bottle neck. This can 880171440Srrs * happen as RTT slides up due to queues. It also means if 881171440Srrs * you have more than a 1 second RTT with a empty queue you 882171440Srrs * will be limited to the bottle_bw per second no matter if 883171440Srrs * other points have 1/2 the RTT and you could get more 884171440Srrs * out... 885171440Srrs */ 886171440Srrs bw_avail = *bottle_bw; 887171440Srrs } 888171440Srrs if (*on_queue > bw_avail) { 889171440Srrs /* 890171440Srrs * No room for anything else don't allow anything else to be 891171440Srrs * "added to the fire". 892171440Srrs */ 893171440Srrs int seg_inflight, seg_onqueue, my_portion; 894171440Srrs 895171440Srrs net->partial_bytes_acked = 0; 896171440Srrs 897171440Srrs /* how much are we over queue size? */ 898171440Srrs incr = *on_queue - bw_avail; 899171440Srrs if (stcb->asoc.seen_a_sack_this_pkt) { 900171440Srrs /* 901171440Srrs * undo any cwnd adjustment that the sack might have 902171440Srrs * made 903171440Srrs */ 904171440Srrs net->cwnd = net->prev_cwnd; 905171440Srrs } 906171440Srrs /* Now how much of that is mine? */ 907171440Srrs seg_inflight = net->flight_size / net->mtu; 908171440Srrs seg_onqueue = *on_queue / net->mtu; 909171440Srrs my_portion = (incr * seg_inflight) / seg_onqueue; 910171440Srrs 911171440Srrs /* Have I made an adjustment already */ 912171440Srrs if (net->cwnd > net->flight_size) { 913171440Srrs /* 914171440Srrs * for this flight I made an adjustment we need to 915171440Srrs * decrease the portion by a share our previous 916171440Srrs * adjustment. 917171440Srrs */ 918171440Srrs int diff_adj; 919171440Srrs 920171440Srrs diff_adj = net->cwnd - net->flight_size; 921171440Srrs if (diff_adj > my_portion) 922171440Srrs my_portion = 0; 923171440Srrs else 924171440Srrs my_portion -= diff_adj; 925171440Srrs } 926171440Srrs /* 927171440Srrs * back down to the previous cwnd (assume we have had a sack 928171440Srrs * before this packet). minus what ever portion of the 929171440Srrs * overage is my fault. 930171440Srrs */ 931171440Srrs net->cwnd -= my_portion; 932171440Srrs 933171440Srrs /* we will NOT back down more than 1 MTU */ 934171440Srrs if (net->cwnd <= net->mtu) { 935171440Srrs net->cwnd = net->mtu; 936171440Srrs } 937171440Srrs /* force into CA */ 938171440Srrs net->ssthresh = net->cwnd - 1; 939171440Srrs } else { 940171440Srrs /* 941171440Srrs * Take 1/4 of the space left or max burst up .. whichever 942171440Srrs * is less. 943171440Srrs */ 944171440Srrs incr = min((bw_avail - *on_queue) >> 2, 945171440Srrs stcb->asoc.max_burst * net->mtu); 946171440Srrs net->cwnd += incr; 947171440Srrs } 948171440Srrs if (net->cwnd > bw_avail) { 949171440Srrs /* We can't exceed the pipe size */ 950171440Srrs net->cwnd = bw_avail; 951171440Srrs } 952171440Srrs if (net->cwnd < net->mtu) { 953171440Srrs /* We always have 1 MTU */ 954171440Srrs net->cwnd = net->mtu; 955171440Srrs } 956171440Srrs if (net->cwnd - old_cwnd != 0) { 957171440Srrs /* log only changes */ 958171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 959171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 960171440Srrs SCTP_CWND_LOG_FROM_SAT); 961171440Srrs } 962171440Srrs } 963171440Srrs} 964171440Srrs 965171440Srrsvoid 966171440Srrssctp_cwnd_update_after_output(struct sctp_tcb *stcb, 967171440Srrs struct sctp_nets *net, int burst_limit) 968171440Srrs{ 969171440Srrs int old_cwnd; 970171440Srrs 971171440Srrs if (net->ssthresh < net->cwnd) 972171440Srrs net->ssthresh = net->cwnd; 973171440Srrs old_cwnd = net->cwnd; 974171440Srrs net->cwnd = (net->flight_size + (burst_limit * net->mtu)); 975171440Srrs 976171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 977171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST); 978171440Srrs } 979171440Srrs} 980171440Srrs 981171440Srrsvoid 982171440Srrssctp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp, 983171440Srrs struct sctp_tcb *stcb, struct sctp_nets *net) 984171440Srrs{ 985171440Srrs int old_cwnd; 986171440Srrs 987171440Srrs old_cwnd = net->cwnd; 988171440Srrs 989172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED); 990171440Srrs /* 991171440Srrs * make a small adjustment to cwnd and force to CA. 992171440Srrs */ 993171440Srrs if (net->cwnd > net->mtu) 994171440Srrs /* drop down one MTU after sending */ 995171440Srrs net->cwnd -= net->mtu; 996171440Srrs if (net->cwnd < net->ssthresh) 997171440Srrs /* still in SS move to CA */ 998171440Srrs net->ssthresh = net->cwnd - 1; 999171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1000171440Srrs sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR); 1001171440Srrs } 1002171440Srrs} 1003171440Srrs 1004171440Srrs/* 1005171440Srrs * H-TCP congestion control. The algorithm is detailed in: 1006171440Srrs * R.N.Shorten, D.J.Leith: 1007171440Srrs * "H-TCP: TCP for high-speed and long-distance networks" 1008171440Srrs * Proc. PFLDnet, Argonne, 2004. 1009171440Srrs * http://www.hamilton.ie/net/htcp3.pdf 1010171440Srrs */ 1011171440Srrs 1012171440Srrs 1013171440Srrsstatic int use_rtt_scaling = 1; 1014171440Srrsstatic int use_bandwidth_switch = 1; 1015171440Srrs 1016171440Srrsstatic inline int 1017171440Srrsbetween(uint32_t seq1, uint32_t seq2, uint32_t seq3) 1018171440Srrs{ 1019171440Srrs return seq3 - seq2 >= seq1 - seq2; 1020171440Srrs} 1021171440Srrs 1022171440Srrsstatic inline uint32_t 1023171440Srrshtcp_cong_time(struct htcp *ca) 1024171440Srrs{ 1025171477Srrs return sctp_get_tick_count() - ca->last_cong; 1026171440Srrs} 1027171440Srrs 1028171440Srrsstatic inline uint32_t 1029171440Srrshtcp_ccount(struct htcp *ca) 1030171440Srrs{ 1031171440Srrs return htcp_cong_time(ca) / ca->minRTT; 1032171440Srrs} 1033171440Srrs 1034171440Srrsstatic inline void 1035171440Srrshtcp_reset(struct htcp *ca) 1036171440Srrs{ 1037171440Srrs ca->undo_last_cong = ca->last_cong; 1038171440Srrs ca->undo_maxRTT = ca->maxRTT; 1039171440Srrs ca->undo_old_maxB = ca->old_maxB; 1040171477Srrs ca->last_cong = sctp_get_tick_count(); 1041171440Srrs} 1042171440Srrs 1043171440Srrs#ifdef SCTP_NOT_USED 1044171440Srrs 1045171440Srrsstatic uint32_t 1046171440Srrshtcp_cwnd_undo(struct sctp_tcb *stcb, struct sctp_nets *net) 1047171440Srrs{ 1048171440Srrs net->htcp_ca.last_cong = net->htcp_ca.undo_last_cong; 1049171440Srrs net->htcp_ca.maxRTT = net->htcp_ca.undo_maxRTT; 1050171440Srrs net->htcp_ca.old_maxB = net->htcp_ca.undo_old_maxB; 1051171440Srrs return max(net->cwnd, ((net->ssthresh / net->mtu << 7) / net->htcp_ca.beta) * net->mtu); 1052171440Srrs} 1053171440Srrs 1054171440Srrs#endif 1055171440Srrs 1056171440Srrsstatic inline void 1057171440Srrsmeasure_rtt(struct sctp_tcb *stcb, struct sctp_nets *net) 1058171440Srrs{ 1059171440Srrs uint32_t srtt = net->lastsa >> 3; 1060171440Srrs 1061171440Srrs /* keep track of minimum RTT seen so far, minRTT is zero at first */ 1062171440Srrs if (net->htcp_ca.minRTT > srtt || !net->htcp_ca.minRTT) 1063171440Srrs net->htcp_ca.minRTT = srtt; 1064171440Srrs 1065171440Srrs /* max RTT */ 1066171440Srrs if (net->fast_retran_ip == 0 && net->ssthresh < 0xFFFF && htcp_ccount(&net->htcp_ca) > 3) { 1067171440Srrs if (net->htcp_ca.maxRTT < net->htcp_ca.minRTT) 1068171440Srrs net->htcp_ca.maxRTT = net->htcp_ca.minRTT; 1069171440Srrs if (net->htcp_ca.maxRTT < srtt && srtt <= net->htcp_ca.maxRTT + MSEC_TO_TICKS(20)) 1070171440Srrs net->htcp_ca.maxRTT = srtt; 1071171440Srrs } 1072171440Srrs} 1073171440Srrs 1074171440Srrsstatic void 1075171440Srrsmeasure_achieved_throughput(struct sctp_tcb *stcb, struct sctp_nets *net) 1076171440Srrs{ 1077171477Srrs uint32_t now = sctp_get_tick_count(); 1078171440Srrs 1079171440Srrs if (net->fast_retran_ip == 0) 1080171440Srrs net->htcp_ca.bytes_acked = net->net_ack; 1081171440Srrs 1082171440Srrs if (!use_bandwidth_switch) 1083171440Srrs return; 1084171440Srrs 1085171440Srrs /* achieved throughput calculations */ 1086171440Srrs /* JRS - not 100% sure of this statement */ 1087171440Srrs if (net->fast_retran_ip == 1) { 1088171440Srrs net->htcp_ca.bytecount = 0; 1089171440Srrs net->htcp_ca.lasttime = now; 1090171440Srrs return; 1091171440Srrs } 1092171440Srrs net->htcp_ca.bytecount += net->net_ack; 1093171440Srrs 1094171440Srrs if (net->htcp_ca.bytecount >= net->cwnd - ((net->htcp_ca.alpha >> 7 ? : 1) * net->mtu) 1095171440Srrs && now - net->htcp_ca.lasttime >= net->htcp_ca.minRTT 1096171440Srrs && net->htcp_ca.minRTT > 0) { 1097171440Srrs uint32_t cur_Bi = net->htcp_ca.bytecount / net->mtu * hz / (now - net->htcp_ca.lasttime); 1098171440Srrs 1099171440Srrs if (htcp_ccount(&net->htcp_ca) <= 3) { 1100171440Srrs /* just after backoff */ 1101171440Srrs net->htcp_ca.minB = net->htcp_ca.maxB = net->htcp_ca.Bi = cur_Bi; 1102171440Srrs } else { 1103171440Srrs net->htcp_ca.Bi = (3 * net->htcp_ca.Bi + cur_Bi) / 4; 1104171440Srrs if (net->htcp_ca.Bi > net->htcp_ca.maxB) 1105171440Srrs net->htcp_ca.maxB = net->htcp_ca.Bi; 1106171440Srrs if (net->htcp_ca.minB > net->htcp_ca.maxB) 1107171440Srrs net->htcp_ca.minB = net->htcp_ca.maxB; 1108171440Srrs } 1109171440Srrs net->htcp_ca.bytecount = 0; 1110171440Srrs net->htcp_ca.lasttime = now; 1111171440Srrs } 1112171440Srrs} 1113171440Srrs 1114171440Srrsstatic inline void 1115171440Srrshtcp_beta_update(struct htcp *ca, uint32_t minRTT, uint32_t maxRTT) 1116171440Srrs{ 1117171440Srrs if (use_bandwidth_switch) { 1118171440Srrs uint32_t maxB = ca->maxB; 1119171440Srrs uint32_t old_maxB = ca->old_maxB; 1120171440Srrs 1121171440Srrs ca->old_maxB = ca->maxB; 1122171440Srrs 1123171440Srrs if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) { 1124171440Srrs ca->beta = BETA_MIN; 1125171440Srrs ca->modeswitch = 0; 1126171440Srrs return; 1127171440Srrs } 1128171440Srrs } 1129171440Srrs if (ca->modeswitch && minRTT > (uint32_t) MSEC_TO_TICKS(10) && maxRTT) { 1130171440Srrs ca->beta = (minRTT << 7) / maxRTT; 1131171440Srrs if (ca->beta < BETA_MIN) 1132171440Srrs ca->beta = BETA_MIN; 1133171440Srrs else if (ca->beta > BETA_MAX) 1134171440Srrs ca->beta = BETA_MAX; 1135171440Srrs } else { 1136171440Srrs ca->beta = BETA_MIN; 1137171440Srrs ca->modeswitch = 1; 1138171440Srrs } 1139171440Srrs} 1140171440Srrs 1141171440Srrsstatic inline void 1142171440Srrshtcp_alpha_update(struct htcp *ca) 1143171440Srrs{ 1144171440Srrs uint32_t minRTT = ca->minRTT; 1145171440Srrs uint32_t factor = 1; 1146171440Srrs uint32_t diff = htcp_cong_time(ca); 1147171440Srrs 1148171440Srrs if (diff > (uint32_t) hz) { 1149171440Srrs diff -= hz; 1150171440Srrs factor = 1 + (10 * diff + ((diff / 2) * (diff / 2) / hz)) / hz; 1151171440Srrs } 1152171440Srrs if (use_rtt_scaling && minRTT) { 1153171440Srrs uint32_t scale = (hz << 3) / (10 * minRTT); 1154171440Srrs 1155171440Srrs scale = min(max(scale, 1U << 2), 10U << 3); /* clamping ratio to 1156171440Srrs * interval [0.5,10]<<3 */ 1157171440Srrs factor = (factor << 3) / scale; 1158171440Srrs if (!factor) 1159171440Srrs factor = 1; 1160171440Srrs } 1161171440Srrs ca->alpha = 2 * factor * ((1 << 7) - ca->beta); 1162171440Srrs if (!ca->alpha) 1163171440Srrs ca->alpha = ALPHA_BASE; 1164171440Srrs} 1165171440Srrs 1166171440Srrs/* After we have the rtt data to calculate beta, we'd still prefer to wait one 1167171440Srrs * rtt before we adjust our beta to ensure we are working from a consistent 1168171440Srrs * data. 1169171440Srrs * 1170171440Srrs * This function should be called when we hit a congestion event since only at 1171171440Srrs * that point do we really have a real sense of maxRTT (the queues en route 1172171440Srrs * were getting just too full now). 1173171440Srrs */ 1174171440Srrsstatic void 1175171440Srrshtcp_param_update(struct sctp_tcb *stcb, struct sctp_nets *net) 1176171440Srrs{ 1177171440Srrs uint32_t minRTT = net->htcp_ca.minRTT; 1178171440Srrs uint32_t maxRTT = net->htcp_ca.maxRTT; 1179171440Srrs 1180171440Srrs htcp_beta_update(&net->htcp_ca, minRTT, maxRTT); 1181171440Srrs htcp_alpha_update(&net->htcp_ca); 1182171440Srrs 1183171440Srrs /* 1184171440Srrs * add slowly fading memory for maxRTT to accommodate routing 1185171440Srrs * changes etc 1186171440Srrs */ 1187171440Srrs if (minRTT > 0 && maxRTT > minRTT) 1188171440Srrs net->htcp_ca.maxRTT = minRTT + ((maxRTT - minRTT) * 95) / 100; 1189171440Srrs} 1190171440Srrs 1191171440Srrsstatic uint32_t 1192171440Srrshtcp_recalc_ssthresh(struct sctp_tcb *stcb, struct sctp_nets *net) 1193171440Srrs{ 1194171440Srrs htcp_param_update(stcb, net); 1195171440Srrs return max(((net->cwnd / net->mtu * net->htcp_ca.beta) >> 7) * net->mtu, 2U * net->mtu); 1196171440Srrs} 1197171440Srrs 1198171440Srrsstatic void 1199171440Srrshtcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net) 1200171440Srrs{ 1201171440Srrs /*- 1202171440Srrs * How to handle these functions? 1203171440Srrs * if (!tcp_is_cwnd_limited(sk, in_flight)) RRS - good question. 1204171440Srrs * return; 1205171440Srrs */ 1206171440Srrs if (net->cwnd <= net->ssthresh) { 1207171440Srrs /* We are in slow start */ 1208171440Srrs if (net->flight_size + net->net_ack >= net->cwnd) { 1209171440Srrs if (net->net_ack > (net->mtu * sctp_L2_abc_variable)) { 1210171440Srrs net->cwnd += (net->mtu * sctp_L2_abc_variable); 1211171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1212171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 1213171440Srrs SCTP_CWND_LOG_FROM_SS); 1214171440Srrs } 1215171440Srrs } else { 1216171440Srrs net->cwnd += net->net_ack; 1217171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1218171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 1219171440Srrs SCTP_CWND_LOG_FROM_SS); 1220171440Srrs } 1221171440Srrs } 1222171440Srrs } else { 1223171440Srrs unsigned int dif; 1224171440Srrs 1225171440Srrs dif = net->cwnd - (net->flight_size + 1226171440Srrs net->net_ack); 1227171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 1228171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 1229171440Srrs SCTP_CWND_LOG_NOADV_SS); 1230171440Srrs } 1231171440Srrs } 1232171440Srrs } else { 1233171440Srrs measure_rtt(stcb, net); 1234171440Srrs 1235171440Srrs /* 1236171440Srrs * In dangerous area, increase slowly. In theory this is 1237171440Srrs * net->cwnd += alpha / net->cwnd 1238171440Srrs */ 1239171440Srrs /* What is snd_cwnd_cnt?? */ 1240171440Srrs if (((net->partial_bytes_acked / net->mtu * net->htcp_ca.alpha) >> 7) * net->mtu >= net->cwnd) { 1241171440Srrs /*- 1242171440Srrs * Does SCTP have a cwnd clamp? 1243171440Srrs * if (net->snd_cwnd < net->snd_cwnd_clamp) - Nope (RRS). 1244171440Srrs */ 1245171440Srrs net->cwnd += net->mtu; 1246171440Srrs net->partial_bytes_acked = 0; 1247171440Srrs htcp_alpha_update(&net->htcp_ca); 1248171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1249171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 1250171440Srrs SCTP_CWND_LOG_FROM_CA); 1251171440Srrs } 1252171440Srrs } else { 1253171440Srrs net->partial_bytes_acked += net->net_ack; 1254171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 1255171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 1256171440Srrs SCTP_CWND_LOG_NOADV_CA); 1257171440Srrs } 1258171440Srrs } 1259171440Srrs 1260171440Srrs net->htcp_ca.bytes_acked = net->mtu; 1261171440Srrs } 1262171440Srrs} 1263171440Srrs 1264171440Srrs#ifdef SCTP_NOT_USED 1265171440Srrs/* Lower bound on congestion window. */ 1266171440Srrsstatic uint32_t 1267171440Srrshtcp_min_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net) 1268171440Srrs{ 1269171440Srrs return net->ssthresh; 1270171440Srrs} 1271171440Srrs 1272171440Srrs#endif 1273171440Srrs 1274171440Srrsstatic void 1275171440Srrshtcp_init(struct sctp_tcb *stcb, struct sctp_nets *net) 1276171440Srrs{ 1277171440Srrs memset(&net->htcp_ca, 0, sizeof(struct htcp)); 1278171440Srrs net->htcp_ca.alpha = ALPHA_BASE; 1279171440Srrs net->htcp_ca.beta = BETA_MIN; 1280171440Srrs net->htcp_ca.bytes_acked = net->mtu; 1281171477Srrs net->htcp_ca.last_cong = sctp_get_tick_count(); 1282171440Srrs} 1283171440Srrs 1284171440Srrsvoid 1285171440Srrssctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) 1286171440Srrs{ 1287171440Srrs /* 1288171440Srrs * We take the max of the burst limit times a MTU or the 1289171440Srrs * INITIAL_CWND. We then limit this to 4 MTU's of sending. 1290171440Srrs */ 1291171440Srrs net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 1292171440Srrs /* we always get at LEAST 2 MTU's */ 1293171440Srrs if (net->cwnd < (2 * net->mtu)) { 1294171440Srrs net->cwnd = 2 * net->mtu; 1295171440Srrs } 1296171440Srrs net->ssthresh = stcb->asoc.peers_rwnd; 1297171440Srrs htcp_init(stcb, net); 1298171440Srrs 1299171440Srrs if (sctp_logging_level & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { 1300171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); 1301171440Srrs } 1302171440Srrs} 1303171440Srrs 1304171440Srrsvoid 1305171440Srrssctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, 1306171440Srrs struct sctp_association *asoc, 1307171440Srrs int accum_moved, int reneged_all, int will_exit) 1308171440Srrs{ 1309171440Srrs struct sctp_nets *net; 1310171440Srrs 1311171440Srrs /******************************/ 1312171440Srrs /* update cwnd and Early FR */ 1313171440Srrs /******************************/ 1314171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 1315171440Srrs 1316171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 1317171440Srrs /* 1318171440Srrs * CMT fast recovery code. Need to debug. 1319171440Srrs */ 1320171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 1321171440Srrs if (compare_with_wrap(asoc->last_acked_seq, 1322171440Srrs net->fast_recovery_tsn, MAX_TSN) || 1323171440Srrs (asoc->last_acked_seq == net->fast_recovery_tsn) || 1324171440Srrs compare_with_wrap(net->pseudo_cumack, net->fast_recovery_tsn, MAX_TSN) || 1325171440Srrs (net->pseudo_cumack == net->fast_recovery_tsn)) { 1326171440Srrs net->will_exit_fast_recovery = 1; 1327171440Srrs } 1328171440Srrs } 1329171440Srrs#endif 1330171440Srrs if (sctp_early_fr) { 1331171440Srrs /* 1332171440Srrs * So, first of all do we need to have a Early FR 1333171440Srrs * timer running? 1334171440Srrs */ 1335171440Srrs if (((TAILQ_FIRST(&asoc->sent_queue)) && 1336171440Srrs (net->ref_count > 1) && 1337171440Srrs (net->flight_size < net->cwnd)) || 1338171440Srrs (reneged_all)) { 1339171440Srrs /* 1340171440Srrs * yes, so in this case stop it if its 1341171440Srrs * running, and then restart it. Reneging 1342171440Srrs * all is a special case where we want to 1343171440Srrs * run the Early FR timer and then force the 1344171440Srrs * last few unacked to be sent, causing us 1345171440Srrs * to illicit a sack with gaps to force out 1346171440Srrs * the others. 1347171440Srrs */ 1348171440Srrs if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 1349171440Srrs SCTP_STAT_INCR(sctps_earlyfrstpidsck2); 1350171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 1351171440Srrs SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); 1352171440Srrs } 1353171440Srrs SCTP_STAT_INCR(sctps_earlyfrstrid); 1354171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); 1355171440Srrs } else { 1356171440Srrs /* No, stop it if its running */ 1357171440Srrs if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 1358171440Srrs SCTP_STAT_INCR(sctps_earlyfrstpidsck3); 1359171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 1360171440Srrs SCTP_FROM_SCTP_INDATA + SCTP_LOC_21); 1361171440Srrs } 1362171440Srrs } 1363171440Srrs } 1364171440Srrs /* if nothing was acked on this destination skip it */ 1365171440Srrs if (net->net_ack == 0) { 1366171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 1367171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 1368171440Srrs } 1369171440Srrs continue; 1370171440Srrs } 1371171440Srrs if (net->net_ack2 > 0) { 1372171440Srrs /* 1373171440Srrs * Karn's rule applies to clearing error count, this 1374171440Srrs * is optional. 1375171440Srrs */ 1376171440Srrs net->error_count = 0; 1377171440Srrs if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == 1378171440Srrs SCTP_ADDR_NOT_REACHABLE) { 1379171440Srrs /* addr came good */ 1380171440Srrs net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; 1381171440Srrs net->dest_state |= SCTP_ADDR_REACHABLE; 1382171440Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 1383172090Srrs SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED); 1384171440Srrs /* now was it the primary? if so restore */ 1385171440Srrs if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) { 1386171440Srrs (void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net); 1387171440Srrs } 1388171440Srrs } 1389171440Srrs /* 1390171440Srrs * JRS 5/14/07 - If CMT PF is on and the destination 1391171440Srrs * is in PF state, set the destination to active 1392171440Srrs * state and set the cwnd to one or two MTU's based 1393171440Srrs * on whether PF1 or PF2 is being used. 1394171440Srrs * 1395171440Srrs * Should we stop any running T3 timer here? 1396171440Srrs */ 1397171477Srrs if (sctp_cmt_on_off && sctp_cmt_pf && ((net->dest_state & SCTP_ADDR_PF) == 1398171440Srrs SCTP_ADDR_PF)) { 1399171440Srrs net->dest_state &= ~SCTP_ADDR_PF; 1400171440Srrs net->cwnd = net->mtu * sctp_cmt_pf; 1401171440Srrs SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", 1402171440Srrs net, net->cwnd); 1403171440Srrs /* 1404171440Srrs * Since the cwnd value is explicitly set, 1405171440Srrs * skip the code that updates the cwnd 1406171440Srrs * value. 1407171440Srrs */ 1408171440Srrs goto skip_cwnd_update; 1409171440Srrs } 1410171440Srrs } 1411171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 1412171440Srrs /* 1413171440Srrs * CMT fast recovery code 1414171440Srrs */ 1415171440Srrs /* 1416171440Srrs * if (sctp_cmt_on_off == 1 && 1417171440Srrs * net->fast_retran_loss_recovery && 1418171440Srrs * net->will_exit_fast_recovery == 0) { @@@ Do something } 1419171440Srrs * else if (sctp_cmt_on_off == 0 && 1420171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 1421171440Srrs */ 1422171440Srrs#endif 1423171440Srrs 1424171440Srrs if (asoc->fast_retran_loss_recovery && will_exit == 0 && sctp_cmt_on_off == 0) { 1425171440Srrs /* 1426171440Srrs * If we are in loss recovery we skip any cwnd 1427171440Srrs * update 1428171440Srrs */ 1429171440Srrs goto skip_cwnd_update; 1430171440Srrs } 1431171440Srrs /* 1432171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 1433171440Srrs * moved. 1434171440Srrs */ 1435171440Srrs if (accum_moved || (sctp_cmt_on_off && net->new_pseudo_cumack)) { 1436171440Srrs htcp_cong_avoid(stcb, net); 1437171440Srrs measure_achieved_throughput(stcb, net); 1438171440Srrs } else { 1439171440Srrs if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 1440171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 1441171440Srrs SCTP_CWND_LOG_NO_CUMACK); 1442171440Srrs } 1443171440Srrs } 1444171440Srrsskip_cwnd_update: 1445171440Srrs /* 1446171440Srrs * NOW, according to Karn's rule do we need to restore the 1447171440Srrs * RTO timer back? Check our net_ack2. If not set then we 1448171440Srrs * have a ambiguity.. i.e. all data ack'd was sent to more 1449171440Srrs * than one place. 1450171440Srrs */ 1451171440Srrs if (net->net_ack2) { 1452171440Srrs /* restore any doubled timers */ 1453171440Srrs net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1; 1454171440Srrs if (net->RTO < stcb->asoc.minrto) { 1455171440Srrs net->RTO = stcb->asoc.minrto; 1456171440Srrs } 1457171440Srrs if (net->RTO > stcb->asoc.maxrto) { 1458171440Srrs net->RTO = stcb->asoc.maxrto; 1459171440Srrs } 1460171440Srrs } 1461171440Srrs } 1462171440Srrs} 1463171440Srrs 1464171440Srrsvoid 1465171440Srrssctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb, 1466171440Srrs struct sctp_association *asoc) 1467171440Srrs{ 1468171440Srrs struct sctp_nets *net; 1469171440Srrs 1470171440Srrs /* 1471171440Srrs * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off == 1) && 1472171440Srrs * (net->fast_retran_loss_recovery == 0))) 1473171440Srrs */ 1474171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 1475171440Srrs if ((asoc->fast_retran_loss_recovery == 0) || (sctp_cmt_on_off == 1)) { 1476171440Srrs /* out of a RFC2582 Fast recovery window? */ 1477171440Srrs if (net->net_ack > 0) { 1478171440Srrs /* 1479171440Srrs * per section 7.2.3, are there any 1480171440Srrs * destinations that had a fast retransmit 1481171440Srrs * to them. If so what we need to do is 1482171440Srrs * adjust ssthresh and cwnd. 1483171440Srrs */ 1484171440Srrs struct sctp_tmit_chunk *lchk; 1485171440Srrs int old_cwnd = net->cwnd; 1486171440Srrs 1487171440Srrs /* JRS - reset as if state were changed */ 1488171440Srrs htcp_reset(&net->htcp_ca); 1489171440Srrs net->ssthresh = htcp_recalc_ssthresh(stcb, net); 1490171440Srrs net->cwnd = net->ssthresh; 1491171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1492171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 1493171440Srrs SCTP_CWND_LOG_FROM_FR); 1494171440Srrs } 1495171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 1496171440Srrs 1497171440Srrs net->partial_bytes_acked = 0; 1498171440Srrs /* Turn on fast recovery window */ 1499171440Srrs asoc->fast_retran_loss_recovery = 1; 1500171440Srrs if (lchk == NULL) { 1501171440Srrs /* Mark end of the window */ 1502171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 1503171440Srrs } else { 1504171440Srrs asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 1505171440Srrs } 1506171440Srrs 1507171440Srrs /* 1508171440Srrs * CMT fast recovery -- per destination 1509171440Srrs * recovery variable. 1510171440Srrs */ 1511171440Srrs net->fast_retran_loss_recovery = 1; 1512171440Srrs 1513171440Srrs if (lchk == NULL) { 1514171440Srrs /* Mark end of the window */ 1515171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 1516171440Srrs } else { 1517171440Srrs net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 1518171440Srrs } 1519171440Srrs 1520171440Srrs /* 1521171440Srrs * Disable Nonce Sum Checking and store the 1522171440Srrs * resync tsn 1523171440Srrs */ 1524171440Srrs asoc->nonce_sum_check = 0; 1525171440Srrs asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1; 1526171440Srrs 1527171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 1528171440Srrs stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); 1529171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 1530171440Srrs stcb->sctp_ep, stcb, net); 1531171440Srrs } 1532171440Srrs } else if (net->net_ack > 0) { 1533171440Srrs /* 1534171440Srrs * Mark a peg that we WOULD have done a cwnd 1535171440Srrs * reduction but RFC2582 prevented this action. 1536171440Srrs */ 1537171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 1538171440Srrs } 1539171440Srrs } 1540171440Srrs} 1541171440Srrs 1542171440Srrsvoid 1543171440Srrssctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb, 1544171440Srrs struct sctp_nets *net) 1545171440Srrs{ 1546171440Srrs int old_cwnd = net->cwnd; 1547171440Srrs 1548171440Srrs /* JRS - reset as if the state were being changed to timeout */ 1549171440Srrs htcp_reset(&net->htcp_ca); 1550171440Srrs net->ssthresh = htcp_recalc_ssthresh(stcb, net); 1551171440Srrs net->cwnd = net->mtu; 1552171440Srrs /* floor of 1 mtu */ 1553171440Srrs if (net->cwnd < net->mtu) 1554171440Srrs net->cwnd = net->mtu; 1555171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1556171440Srrs sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 1557171440Srrs } 1558171440Srrs net->partial_bytes_acked = 0; 1559171440Srrs} 1560171440Srrs 1561171440Srrsvoid 1562171440Srrssctp_htcp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp, 1563171440Srrs struct sctp_tcb *stcb, struct sctp_nets *net) 1564171440Srrs{ 1565171440Srrs int old_cwnd; 1566171440Srrs 1567171440Srrs old_cwnd = net->cwnd; 1568171440Srrs 1569172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED); 1570171477Srrs net->htcp_ca.last_cong = sctp_get_tick_count(); 1571171440Srrs /* 1572171440Srrs * make a small adjustment to cwnd and force to CA. 1573171440Srrs */ 1574171440Srrs if (net->cwnd > net->mtu) 1575171440Srrs /* drop down one MTU after sending */ 1576171440Srrs net->cwnd -= net->mtu; 1577171440Srrs if (net->cwnd < net->ssthresh) 1578171440Srrs /* still in SS move to CA */ 1579171440Srrs net->ssthresh = net->cwnd - 1; 1580171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1581171440Srrs sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR); 1582171440Srrs } 1583171440Srrs} 1584171440Srrs 1585171440Srrsvoid 1586171440Srrssctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, 1587171440Srrs struct sctp_nets *net) 1588171440Srrs{ 1589171440Srrs int old_cwnd; 1590171440Srrs 1591171440Srrs old_cwnd = net->cwnd; 1592171440Srrs 1593171440Srrs /* JRS - reset hctp as if state changed */ 1594171440Srrs htcp_reset(&net->htcp_ca); 1595171440Srrs SCTP_STAT_INCR(sctps_ecnereducedcwnd); 1596171440Srrs net->ssthresh = htcp_recalc_ssthresh(stcb, net); 1597171440Srrs if (net->ssthresh < net->mtu) { 1598171440Srrs net->ssthresh = net->mtu; 1599171440Srrs /* here back off the timer as well, to slow us down */ 1600171440Srrs net->RTO <<= 1; 1601171440Srrs } 1602171440Srrs net->cwnd = net->ssthresh; 1603171440Srrs if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1604171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 1605171440Srrs } 1606171440Srrs} 1607