sctp_cc_functions.c revision 211944
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 211944 2010-08-28 17:59:51Z tuexen $"); 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 52179157Srrs * INITIAL_CWND. We then limit this to 4 MTU's of sending. cwnd must 53179157Srrs * be at least 2 MTU. 54171440Srrs */ 55171440Srrs net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 56171440Srrs net->ssthresh = stcb->asoc.peers_rwnd; 57171440Srrs 58179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { 59171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); 60171440Srrs } 61171440Srrs} 62171440Srrs 63171440Srrsvoid 64171440Srrssctp_cwnd_update_after_fr(struct sctp_tcb *stcb, 65171440Srrs struct sctp_association *asoc) 66171440Srrs{ 67171440Srrs struct sctp_nets *net; 68171440Srrs 69171440Srrs /*- 70171440Srrs * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off == 1) && 71171440Srrs * (net->fast_retran_loss_recovery == 0))) 72171440Srrs */ 73171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 74211944Stuexen if ((asoc->fast_retran_loss_recovery == 0) || 75211944Stuexen (asoc->sctp_cmt_on_off == 1)) { 76171440Srrs /* out of a RFC2582 Fast recovery window? */ 77171440Srrs if (net->net_ack > 0) { 78171440Srrs /* 79171440Srrs * per section 7.2.3, are there any 80171440Srrs * destinations that had a fast retransmit 81171440Srrs * to them. If so what we need to do is 82171440Srrs * adjust ssthresh and cwnd. 83171440Srrs */ 84171440Srrs struct sctp_tmit_chunk *lchk; 85171440Srrs int old_cwnd = net->cwnd; 86171440Srrs 87171440Srrs net->ssthresh = net->cwnd / 2; 88171440Srrs if (net->ssthresh < (net->mtu * 2)) { 89171440Srrs net->ssthresh = 2 * net->mtu; 90171440Srrs } 91171440Srrs net->cwnd = net->ssthresh; 92179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 93171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 94171440Srrs SCTP_CWND_LOG_FROM_FR); 95171440Srrs } 96171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 97171440Srrs 98171440Srrs net->partial_bytes_acked = 0; 99171440Srrs /* Turn on fast recovery window */ 100171440Srrs asoc->fast_retran_loss_recovery = 1; 101171440Srrs if (lchk == NULL) { 102171440Srrs /* Mark end of the window */ 103171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 104171440Srrs } else { 105171440Srrs asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 106171440Srrs } 107171440Srrs 108171440Srrs /* 109171440Srrs * CMT fast recovery -- per destination 110171440Srrs * recovery variable. 111171440Srrs */ 112171440Srrs net->fast_retran_loss_recovery = 1; 113171440Srrs 114171440Srrs if (lchk == NULL) { 115171440Srrs /* Mark end of the window */ 116171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 117171440Srrs } else { 118171440Srrs net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 119171440Srrs } 120171440Srrs 121171440Srrs /* 122171440Srrs * Disable Nonce Sum Checking and store the 123171440Srrs * resync tsn 124171440Srrs */ 125171440Srrs asoc->nonce_sum_check = 0; 126171440Srrs asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1; 127171440Srrs 128171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 129171440Srrs stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); 130171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 131171440Srrs stcb->sctp_ep, stcb, net); 132171440Srrs } 133171440Srrs } else if (net->net_ack > 0) { 134171440Srrs /* 135171440Srrs * Mark a peg that we WOULD have done a cwnd 136171440Srrs * reduction but RFC2582 prevented this action. 137171440Srrs */ 138171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 139171440Srrs } 140171440Srrs } 141171440Srrs} 142171440Srrs 143171440Srrsvoid 144171440Srrssctp_cwnd_update_after_sack(struct sctp_tcb *stcb, 145171440Srrs struct sctp_association *asoc, 146171440Srrs int accum_moved, int reneged_all, int will_exit) 147171440Srrs{ 148171440Srrs struct sctp_nets *net; 149171440Srrs 150171440Srrs /******************************/ 151171440Srrs /* update cwnd and Early FR */ 152171440Srrs /******************************/ 153171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 154171440Srrs 155171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 156171440Srrs /* 157171440Srrs * CMT fast recovery code. Need to debug. 158171440Srrs */ 159171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 160171440Srrs if (compare_with_wrap(asoc->last_acked_seq, 161171440Srrs net->fast_recovery_tsn, MAX_TSN) || 162171440Srrs (asoc->last_acked_seq == net->fast_recovery_tsn) || 163171440Srrs compare_with_wrap(net->pseudo_cumack, net->fast_recovery_tsn, MAX_TSN) || 164171440Srrs (net->pseudo_cumack == net->fast_recovery_tsn)) { 165171440Srrs net->will_exit_fast_recovery = 1; 166171440Srrs } 167171440Srrs } 168171440Srrs#endif 169179783Srrs if (SCTP_BASE_SYSCTL(sctp_early_fr)) { 170171440Srrs /* 171171440Srrs * So, first of all do we need to have a Early FR 172171440Srrs * timer running? 173171440Srrs */ 174171440Srrs if (((TAILQ_FIRST(&asoc->sent_queue)) && 175171440Srrs (net->ref_count > 1) && 176171440Srrs (net->flight_size < net->cwnd)) || 177171440Srrs (reneged_all)) { 178171440Srrs /* 179171440Srrs * yes, so in this case stop it if its 180171440Srrs * running, and then restart it. Reneging 181171440Srrs * all is a special case where we want to 182171440Srrs * run the Early FR timer and then force the 183171440Srrs * last few unacked to be sent, causing us 184171440Srrs * to illicit a sack with gaps to force out 185171440Srrs * the others. 186171440Srrs */ 187171440Srrs if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 188171440Srrs SCTP_STAT_INCR(sctps_earlyfrstpidsck2); 189171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 190171440Srrs SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); 191171440Srrs } 192171440Srrs SCTP_STAT_INCR(sctps_earlyfrstrid); 193171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); 194171440Srrs } else { 195171440Srrs /* No, stop it if its running */ 196171440Srrs if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 197171440Srrs SCTP_STAT_INCR(sctps_earlyfrstpidsck3); 198171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 199171440Srrs SCTP_FROM_SCTP_INDATA + SCTP_LOC_21); 200171440Srrs } 201171440Srrs } 202171440Srrs } 203171440Srrs /* if nothing was acked on this destination skip it */ 204171440Srrs if (net->net_ack == 0) { 205179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 206171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 207171440Srrs } 208171440Srrs continue; 209171440Srrs } 210171440Srrs if (net->net_ack2 > 0) { 211171440Srrs /* 212171440Srrs * Karn's rule applies to clearing error count, this 213171440Srrs * is optional. 214171440Srrs */ 215171440Srrs net->error_count = 0; 216171440Srrs if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == 217171440Srrs SCTP_ADDR_NOT_REACHABLE) { 218171440Srrs /* addr came good */ 219171440Srrs net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; 220171440Srrs net->dest_state |= SCTP_ADDR_REACHABLE; 221171440Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 222172090Srrs SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED); 223171440Srrs /* now was it the primary? if so restore */ 224171440Srrs if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) { 225171440Srrs (void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net); 226171440Srrs } 227171440Srrs } 228171440Srrs /* 229171440Srrs * JRS 5/14/07 - If CMT PF is on and the destination 230171440Srrs * is in PF state, set the destination to active 231171440Srrs * state and set the cwnd to one or two MTU's based 232171440Srrs * on whether PF1 or PF2 is being used. 233171440Srrs * 234171440Srrs * Should we stop any running T3 timer here? 235171440Srrs */ 236211944Stuexen if ((asoc->sctp_cmt_on_off == 1) && 237211944Stuexen (asoc->sctp_cmt_pf > 0) && 238179783Srrs ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { 239171440Srrs net->dest_state &= ~SCTP_ADDR_PF; 240211944Stuexen net->cwnd = net->mtu * asoc->sctp_cmt_pf; 241171440Srrs SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", 242171440Srrs net, net->cwnd); 243171440Srrs /* 244171440Srrs * Since the cwnd value is explicitly set, 245171440Srrs * skip the code that updates the cwnd 246171440Srrs * value. 247171440Srrs */ 248171440Srrs goto skip_cwnd_update; 249171440Srrs } 250171440Srrs } 251171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 252171440Srrs /* 253171440Srrs * CMT fast recovery code 254171440Srrs */ 255171440Srrs /* 256171440Srrs * if (sctp_cmt_on_off == 1 && 257171440Srrs * net->fast_retran_loss_recovery && 258171440Srrs * net->will_exit_fast_recovery == 0) { @@@ Do something } 259171440Srrs * else if (sctp_cmt_on_off == 0 && 260171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 261171440Srrs */ 262171440Srrs#endif 263171440Srrs 264211944Stuexen if (asoc->fast_retran_loss_recovery && 265211944Stuexen (will_exit == 0) && 266211944Stuexen (asoc->sctp_cmt_on_off == 0)) { 267171440Srrs /* 268171440Srrs * If we are in loss recovery we skip any cwnd 269171440Srrs * update 270171440Srrs */ 271171440Srrs goto skip_cwnd_update; 272171440Srrs } 273171440Srrs /* 274171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 275171440Srrs * moved. 276171440Srrs */ 277211944Stuexen if (accum_moved || 278211944Stuexen ((asoc->sctp_cmt_on_off == 1) && net->new_pseudo_cumack)) { 279171440Srrs /* If the cumulative ack moved we can proceed */ 280171440Srrs if (net->cwnd <= net->ssthresh) { 281171440Srrs /* We are in slow start */ 282179157Srrs if (net->flight_size + net->net_ack >= net->cwnd) { 283179783Srrs if (net->net_ack > (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable))) { 284179783Srrs net->cwnd += (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)); 285179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 286171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 287171440Srrs SCTP_CWND_LOG_FROM_SS); 288171440Srrs } 289171440Srrs } else { 290171440Srrs net->cwnd += net->net_ack; 291179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 292171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 293171440Srrs SCTP_CWND_LOG_FROM_SS); 294171440Srrs } 295171440Srrs } 296171440Srrs } else { 297179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 298171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 299171440Srrs SCTP_CWND_LOG_NOADV_SS); 300171440Srrs } 301171440Srrs } 302171440Srrs } else { 303171440Srrs /* We are in congestion avoidance */ 304179141Srrs /* 305179141Srrs * Add to pba 306179141Srrs */ 307179157Srrs net->partial_bytes_acked += net->net_ack; 308171440Srrs 309179141Srrs if ((net->flight_size + net->net_ack >= net->cwnd) && 310179141Srrs (net->partial_bytes_acked >= net->cwnd)) { 311179141Srrs net->partial_bytes_acked -= net->cwnd; 312179141Srrs net->cwnd += net->mtu; 313179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 314179141Srrs sctp_log_cwnd(stcb, net, net->mtu, 315179141Srrs SCTP_CWND_LOG_FROM_CA); 316171440Srrs } 317171440Srrs } else { 318179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 319171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 320171440Srrs SCTP_CWND_LOG_NOADV_CA); 321171440Srrs } 322171440Srrs } 323171440Srrs } 324171440Srrs } else { 325179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 326171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 327171440Srrs SCTP_CWND_LOG_NO_CUMACK); 328171440Srrs } 329171440Srrs } 330171440Srrsskip_cwnd_update: 331171440Srrs /* 332171440Srrs * NOW, according to Karn's rule do we need to restore the 333171440Srrs * RTO timer back? Check our net_ack2. If not set then we 334171440Srrs * have a ambiguity.. i.e. all data ack'd was sent to more 335171440Srrs * than one place. 336171440Srrs */ 337171440Srrs if (net->net_ack2) { 338171440Srrs /* restore any doubled timers */ 339171440Srrs net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1; 340171440Srrs if (net->RTO < stcb->asoc.minrto) { 341171440Srrs net->RTO = stcb->asoc.minrto; 342171440Srrs } 343171440Srrs if (net->RTO > stcb->asoc.maxrto) { 344171440Srrs net->RTO = stcb->asoc.maxrto; 345171440Srrs } 346171440Srrs } 347171440Srrs } 348171440Srrs} 349171440Srrs 350171440Srrsvoid 351179157Srrssctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net) 352171440Srrs{ 353171440Srrs int old_cwnd = net->cwnd; 354171440Srrs 355198522Stuexen net->ssthresh = max(net->cwnd / 2, 4 * net->mtu); 356171440Srrs net->cwnd = net->mtu; 357179157Srrs net->partial_bytes_acked = 0; 358179157Srrs 359179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 360171440Srrs sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 361171440Srrs } 362171440Srrs} 363171440Srrs 364179157Srrsvoid 365179157Srrssctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net) 366179157Srrs{ 367179157Srrs int old_cwnd = net->cwnd; 368179157Srrs 369179157Srrs SCTP_STAT_INCR(sctps_ecnereducedcwnd); 370179157Srrs net->ssthresh = net->cwnd / 2; 371179157Srrs if (net->ssthresh < net->mtu) { 372179157Srrs net->ssthresh = net->mtu; 373179157Srrs /* here back off the timer as well, to slow us down */ 374179157Srrs net->RTO <<= 1; 375179157Srrs } 376179157Srrs net->cwnd = net->ssthresh; 377179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 378179157Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 379179157Srrs } 380179157Srrs} 381179157Srrs 382179157Srrsvoid 383179157Srrssctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb, 384179157Srrs struct sctp_nets *net, struct sctp_pktdrop_chunk *cp, 385179157Srrs uint32_t * bottle_bw, uint32_t * on_queue) 386179157Srrs{ 387179157Srrs uint32_t bw_avail; 388179157Srrs int rtt, incr; 389179157Srrs int old_cwnd = net->cwnd; 390179157Srrs 391179157Srrs /* need real RTT for this calc */ 392179157Srrs rtt = ((net->lastsa >> 2) + net->lastsv) >> 1; 393179157Srrs /* get bottle neck bw */ 394179157Srrs *bottle_bw = ntohl(cp->bottle_bw); 395179157Srrs /* and whats on queue */ 396179157Srrs *on_queue = ntohl(cp->current_onq); 397179157Srrs /* 398179157Srrs * adjust the on-queue if our flight is more it could be that the 399179157Srrs * router has not yet gotten data "in-flight" to it 400179157Srrs */ 401179157Srrs if (*on_queue < net->flight_size) 402179157Srrs *on_queue = net->flight_size; 403179157Srrs /* calculate the available space */ 404179157Srrs bw_avail = (*bottle_bw * rtt) / 1000; 405179157Srrs if (bw_avail > *bottle_bw) { 406179157Srrs /* 407179157Srrs * Cap the growth to no more than the bottle neck. This can 408179157Srrs * happen as RTT slides up due to queues. It also means if 409179157Srrs * you have more than a 1 second RTT with a empty queue you 410179157Srrs * will be limited to the bottle_bw per second no matter if 411179157Srrs * other points have 1/2 the RTT and you could get more 412179157Srrs * out... 413179157Srrs */ 414179157Srrs bw_avail = *bottle_bw; 415179157Srrs } 416179157Srrs if (*on_queue > bw_avail) { 417179157Srrs /* 418179157Srrs * No room for anything else don't allow anything else to be 419179157Srrs * "added to the fire". 420179157Srrs */ 421179157Srrs int seg_inflight, seg_onqueue, my_portion; 422179157Srrs 423179157Srrs net->partial_bytes_acked = 0; 424179157Srrs 425179157Srrs /* how much are we over queue size? */ 426179157Srrs incr = *on_queue - bw_avail; 427179157Srrs if (stcb->asoc.seen_a_sack_this_pkt) { 428179157Srrs /* 429179157Srrs * undo any cwnd adjustment that the sack might have 430179157Srrs * made 431179157Srrs */ 432179157Srrs net->cwnd = net->prev_cwnd; 433179157Srrs } 434179157Srrs /* Now how much of that is mine? */ 435179157Srrs seg_inflight = net->flight_size / net->mtu; 436179157Srrs seg_onqueue = *on_queue / net->mtu; 437179157Srrs my_portion = (incr * seg_inflight) / seg_onqueue; 438179157Srrs 439179157Srrs /* Have I made an adjustment already */ 440179157Srrs if (net->cwnd > net->flight_size) { 441179157Srrs /* 442179157Srrs * for this flight I made an adjustment we need to 443179157Srrs * decrease the portion by a share our previous 444179157Srrs * adjustment. 445179157Srrs */ 446179157Srrs int diff_adj; 447179157Srrs 448179157Srrs diff_adj = net->cwnd - net->flight_size; 449179157Srrs if (diff_adj > my_portion) 450179157Srrs my_portion = 0; 451179157Srrs else 452179157Srrs my_portion -= diff_adj; 453179157Srrs } 454179157Srrs /* 455179157Srrs * back down to the previous cwnd (assume we have had a sack 456179157Srrs * before this packet). minus what ever portion of the 457179157Srrs * overage is my fault. 458179157Srrs */ 459179157Srrs net->cwnd -= my_portion; 460179157Srrs 461179157Srrs /* we will NOT back down more than 1 MTU */ 462179157Srrs if (net->cwnd <= net->mtu) { 463179157Srrs net->cwnd = net->mtu; 464179157Srrs } 465179157Srrs /* force into CA */ 466179157Srrs net->ssthresh = net->cwnd - 1; 467179157Srrs } else { 468179157Srrs /* 469179157Srrs * Take 1/4 of the space left or max burst up .. whichever 470179157Srrs * is less. 471179157Srrs */ 472179157Srrs incr = min((bw_avail - *on_queue) >> 2, 473179157Srrs stcb->asoc.max_burst * net->mtu); 474179157Srrs net->cwnd += incr; 475179157Srrs } 476179157Srrs if (net->cwnd > bw_avail) { 477179157Srrs /* We can't exceed the pipe size */ 478179157Srrs net->cwnd = bw_avail; 479179157Srrs } 480179157Srrs if (net->cwnd < net->mtu) { 481179157Srrs /* We always have 1 MTU */ 482179157Srrs net->cwnd = net->mtu; 483179157Srrs } 484179157Srrs if (net->cwnd - old_cwnd != 0) { 485179157Srrs /* log only changes */ 486179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 487179157Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 488179157Srrs SCTP_CWND_LOG_FROM_SAT); 489179157Srrs } 490179157Srrs } 491179157Srrs} 492179157Srrs 493179157Srrsvoid 494179157Srrssctp_cwnd_update_after_output(struct sctp_tcb *stcb, 495179157Srrs struct sctp_nets *net, int burst_limit) 496179157Srrs{ 497179157Srrs int old_cwnd = net->cwnd; 498179157Srrs 499179157Srrs if (net->ssthresh < net->cwnd) 500179157Srrs net->ssthresh = net->cwnd; 501179157Srrs net->cwnd = (net->flight_size + (burst_limit * net->mtu)); 502179157Srrs 503179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 504179157Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST); 505179157Srrs } 506179157Srrs} 507179157Srrs 508179157Srrsvoid 509179157Srrssctp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp, 510179157Srrs struct sctp_tcb *stcb, struct sctp_nets *net) 511179157Srrs{ 512179157Srrs int old_cwnd = net->cwnd; 513179157Srrs 514179157Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED); 515179157Srrs /* 516179157Srrs * make a small adjustment to cwnd and force to CA. 517179157Srrs */ 518179157Srrs if (net->cwnd > net->mtu) 519179157Srrs /* drop down one MTU after sending */ 520179157Srrs net->cwnd -= net->mtu; 521179157Srrs if (net->cwnd < net->ssthresh) 522179157Srrs /* still in SS move to CA */ 523179157Srrs net->ssthresh = net->cwnd - 1; 524179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 525179157Srrs sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR); 526179157Srrs } 527179157Srrs} 528179157Srrs 529171440Srrsstruct sctp_hs_raise_drop { 530171440Srrs int32_t cwnd; 531171440Srrs int32_t increase; 532171440Srrs int32_t drop_percent; 533171440Srrs}; 534171440Srrs 535171440Srrs#define SCTP_HS_TABLE_SIZE 73 536171440Srrs 537171440Srrsstruct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = { 538171440Srrs {38, 1, 50}, /* 0 */ 539171440Srrs {118, 2, 44}, /* 1 */ 540171440Srrs {221, 3, 41}, /* 2 */ 541171440Srrs {347, 4, 38}, /* 3 */ 542171440Srrs {495, 5, 37}, /* 4 */ 543171440Srrs {663, 6, 35}, /* 5 */ 544171440Srrs {851, 7, 34}, /* 6 */ 545171440Srrs {1058, 8, 33}, /* 7 */ 546171440Srrs {1284, 9, 32}, /* 8 */ 547171440Srrs {1529, 10, 31}, /* 9 */ 548171440Srrs {1793, 11, 30}, /* 10 */ 549171440Srrs {2076, 12, 29}, /* 11 */ 550171440Srrs {2378, 13, 28}, /* 12 */ 551171440Srrs {2699, 14, 28}, /* 13 */ 552171440Srrs {3039, 15, 27}, /* 14 */ 553171440Srrs {3399, 16, 27}, /* 15 */ 554171440Srrs {3778, 17, 26}, /* 16 */ 555171440Srrs {4177, 18, 26}, /* 17 */ 556171440Srrs {4596, 19, 25}, /* 18 */ 557171440Srrs {5036, 20, 25}, /* 19 */ 558171440Srrs {5497, 21, 24}, /* 20 */ 559171440Srrs {5979, 22, 24}, /* 21 */ 560171440Srrs {6483, 23, 23}, /* 22 */ 561171440Srrs {7009, 24, 23}, /* 23 */ 562171440Srrs {7558, 25, 22}, /* 24 */ 563171440Srrs {8130, 26, 22}, /* 25 */ 564171440Srrs {8726, 27, 22}, /* 26 */ 565171440Srrs {9346, 28, 21}, /* 27 */ 566171440Srrs {9991, 29, 21}, /* 28 */ 567171440Srrs {10661, 30, 21}, /* 29 */ 568171440Srrs {11358, 31, 20}, /* 30 */ 569171440Srrs {12082, 32, 20}, /* 31 */ 570171440Srrs {12834, 33, 20}, /* 32 */ 571171440Srrs {13614, 34, 19}, /* 33 */ 572171440Srrs {14424, 35, 19}, /* 34 */ 573171440Srrs {15265, 36, 19}, /* 35 */ 574171440Srrs {16137, 37, 19}, /* 36 */ 575171440Srrs {17042, 38, 18}, /* 37 */ 576171440Srrs {17981, 39, 18}, /* 38 */ 577171440Srrs {18955, 40, 18}, /* 39 */ 578171440Srrs {19965, 41, 17}, /* 40 */ 579171440Srrs {21013, 42, 17}, /* 41 */ 580171440Srrs {22101, 43, 17}, /* 42 */ 581171440Srrs {23230, 44, 17}, /* 43 */ 582171440Srrs {24402, 45, 16}, /* 44 */ 583171440Srrs {25618, 46, 16}, /* 45 */ 584171440Srrs {26881, 47, 16}, /* 46 */ 585171440Srrs {28193, 48, 16}, /* 47 */ 586171440Srrs {29557, 49, 15}, /* 48 */ 587171440Srrs {30975, 50, 15}, /* 49 */ 588171440Srrs {32450, 51, 15}, /* 50 */ 589171440Srrs {33986, 52, 15}, /* 51 */ 590171440Srrs {35586, 53, 14}, /* 52 */ 591171440Srrs {37253, 54, 14}, /* 53 */ 592171440Srrs {38992, 55, 14}, /* 54 */ 593171440Srrs {40808, 56, 14}, /* 55 */ 594171440Srrs {42707, 57, 13}, /* 56 */ 595171440Srrs {44694, 58, 13}, /* 57 */ 596171440Srrs {46776, 59, 13}, /* 58 */ 597171440Srrs {48961, 60, 13}, /* 59 */ 598171440Srrs {51258, 61, 13}, /* 60 */ 599171440Srrs {53677, 62, 12}, /* 61 */ 600171440Srrs {56230, 63, 12}, /* 62 */ 601171440Srrs {58932, 64, 12}, /* 63 */ 602171440Srrs {61799, 65, 12}, /* 64 */ 603171440Srrs {64851, 66, 11}, /* 65 */ 604171440Srrs {68113, 67, 11}, /* 66 */ 605171440Srrs {71617, 68, 11}, /* 67 */ 606171440Srrs {75401, 69, 10}, /* 68 */ 607171440Srrs {79517, 70, 10}, /* 69 */ 608171440Srrs {84035, 71, 10}, /* 70 */ 609171440Srrs {89053, 72, 10}, /* 71 */ 610171440Srrs {94717, 73, 9} /* 72 */ 611171440Srrs}; 612171440Srrs 613171440Srrsstatic void 614171440Srrssctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net) 615171440Srrs{ 616171440Srrs int cur_val, i, indx, incr; 617171440Srrs 618171440Srrs cur_val = net->cwnd >> 10; 619171440Srrs indx = SCTP_HS_TABLE_SIZE - 1; 620171440Srrs#ifdef SCTP_DEBUG 621171440Srrs printf("HS CC CAlled.\n"); 622171440Srrs#endif 623171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 624171440Srrs /* normal mode */ 625171440Srrs if (net->net_ack > net->mtu) { 626171440Srrs net->cwnd += net->mtu; 627179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 628171440Srrs sctp_log_cwnd(stcb, net, net->mtu, SCTP_CWND_LOG_FROM_SS); 629171440Srrs } 630171440Srrs } else { 631171440Srrs net->cwnd += net->net_ack; 632179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 633171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, SCTP_CWND_LOG_FROM_SS); 634171440Srrs } 635171440Srrs } 636171440Srrs } else { 637171440Srrs for (i = net->last_hs_used; i < SCTP_HS_TABLE_SIZE; i++) { 638171440Srrs if (cur_val < sctp_cwnd_adjust[i].cwnd) { 639171440Srrs indx = i; 640171440Srrs break; 641171440Srrs } 642171440Srrs } 643171440Srrs net->last_hs_used = indx; 644171440Srrs incr = ((sctp_cwnd_adjust[indx].increase) << 10); 645171440Srrs net->cwnd += incr; 646179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 647171440Srrs sctp_log_cwnd(stcb, net, incr, SCTP_CWND_LOG_FROM_SS); 648171440Srrs } 649171440Srrs } 650171440Srrs} 651171440Srrs 652171440Srrsstatic void 653171440Srrssctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net) 654171440Srrs{ 655171440Srrs int cur_val, i, indx; 656171440Srrs int old_cwnd = net->cwnd; 657171440Srrs 658171440Srrs cur_val = net->cwnd >> 10; 659171440Srrs indx = net->last_hs_used; 660171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 661171440Srrs /* normal mode */ 662171440Srrs net->ssthresh = net->cwnd / 2; 663171440Srrs if (net->ssthresh < (net->mtu * 2)) { 664171440Srrs net->ssthresh = 2 * net->mtu; 665171440Srrs } 666171440Srrs net->cwnd = net->ssthresh; 667171440Srrs } else { 668171440Srrs /* drop by the proper amount */ 669171440Srrs net->ssthresh = net->cwnd - (int)((net->cwnd / 100) * 670171440Srrs sctp_cwnd_adjust[net->last_hs_used].drop_percent); 671171440Srrs net->cwnd = net->ssthresh; 672171440Srrs /* now where are we */ 673171440Srrs indx = net->last_hs_used; 674171440Srrs cur_val = net->cwnd >> 10; 675171440Srrs /* reset where we are in the table */ 676171440Srrs if (cur_val < sctp_cwnd_adjust[0].cwnd) { 677171440Srrs /* feel out of hs */ 678171440Srrs net->last_hs_used = 0; 679171440Srrs } else { 680171440Srrs for (i = indx; i >= 1; i--) { 681171440Srrs if (cur_val > sctp_cwnd_adjust[i - 1].cwnd) { 682171440Srrs break; 683171440Srrs } 684171440Srrs } 685171440Srrs net->last_hs_used = indx; 686171440Srrs } 687171440Srrs } 688179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 689171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_FR); 690171440Srrs } 691171440Srrs} 692171440Srrs 693171440Srrsvoid 694171440Srrssctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb, 695171440Srrs struct sctp_association *asoc) 696171440Srrs{ 697171440Srrs struct sctp_nets *net; 698171440Srrs 699171440Srrs /* 700171440Srrs * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off == 1) && 701171440Srrs * (net->fast_retran_loss_recovery == 0))) 702171440Srrs */ 703171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 704211944Stuexen if ((asoc->fast_retran_loss_recovery == 0) || 705211944Stuexen (asoc->sctp_cmt_on_off == 1)) { 706171440Srrs /* out of a RFC2582 Fast recovery window? */ 707171440Srrs if (net->net_ack > 0) { 708171440Srrs /* 709171440Srrs * per section 7.2.3, are there any 710171440Srrs * destinations that had a fast retransmit 711171440Srrs * to them. If so what we need to do is 712171440Srrs * adjust ssthresh and cwnd. 713171440Srrs */ 714171440Srrs struct sctp_tmit_chunk *lchk; 715171440Srrs 716171440Srrs sctp_hs_cwnd_decrease(stcb, net); 717171440Srrs 718171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 719171440Srrs 720171440Srrs net->partial_bytes_acked = 0; 721171440Srrs /* Turn on fast recovery window */ 722171440Srrs asoc->fast_retran_loss_recovery = 1; 723171440Srrs if (lchk == NULL) { 724171440Srrs /* Mark end of the window */ 725171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 726171440Srrs } else { 727171440Srrs asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 728171440Srrs } 729171440Srrs 730171440Srrs /* 731171440Srrs * CMT fast recovery -- per destination 732171440Srrs * recovery variable. 733171440Srrs */ 734171440Srrs net->fast_retran_loss_recovery = 1; 735171440Srrs 736171440Srrs if (lchk == NULL) { 737171440Srrs /* Mark end of the window */ 738171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 739171440Srrs } else { 740171440Srrs net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 741171440Srrs } 742171440Srrs 743171440Srrs /* 744171440Srrs * Disable Nonce Sum Checking and store the 745171440Srrs * resync tsn 746171440Srrs */ 747171440Srrs asoc->nonce_sum_check = 0; 748171440Srrs asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1; 749171440Srrs 750171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 751171440Srrs stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); 752171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 753171440Srrs stcb->sctp_ep, stcb, net); 754171440Srrs } 755171440Srrs } else if (net->net_ack > 0) { 756171440Srrs /* 757171440Srrs * Mark a peg that we WOULD have done a cwnd 758171440Srrs * reduction but RFC2582 prevented this action. 759171440Srrs */ 760171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 761171440Srrs } 762171440Srrs } 763171440Srrs} 764171440Srrs 765171440Srrsvoid 766171440Srrssctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, 767171440Srrs struct sctp_association *asoc, 768171440Srrs int accum_moved, int reneged_all, int will_exit) 769171440Srrs{ 770171440Srrs struct sctp_nets *net; 771171440Srrs 772171440Srrs /******************************/ 773171440Srrs /* update cwnd and Early FR */ 774171440Srrs /******************************/ 775171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 776171440Srrs 777171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 778171440Srrs /* 779171440Srrs * CMT fast recovery code. Need to debug. 780171440Srrs */ 781171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 782171440Srrs if (compare_with_wrap(asoc->last_acked_seq, 783171440Srrs net->fast_recovery_tsn, MAX_TSN) || 784171440Srrs (asoc->last_acked_seq == net->fast_recovery_tsn) || 785171440Srrs compare_with_wrap(net->pseudo_cumack, net->fast_recovery_tsn, MAX_TSN) || 786171440Srrs (net->pseudo_cumack == net->fast_recovery_tsn)) { 787171440Srrs net->will_exit_fast_recovery = 1; 788171440Srrs } 789171440Srrs } 790171440Srrs#endif 791179783Srrs if (SCTP_BASE_SYSCTL(sctp_early_fr)) { 792171440Srrs /* 793171440Srrs * So, first of all do we need to have a Early FR 794171440Srrs * timer running? 795171440Srrs */ 796171440Srrs if (((TAILQ_FIRST(&asoc->sent_queue)) && 797171440Srrs (net->ref_count > 1) && 798171440Srrs (net->flight_size < net->cwnd)) || 799171440Srrs (reneged_all)) { 800171440Srrs /* 801171440Srrs * yes, so in this case stop it if its 802171440Srrs * running, and then restart it. Reneging 803171440Srrs * all is a special case where we want to 804171440Srrs * run the Early FR timer and then force the 805171440Srrs * last few unacked to be sent, causing us 806171440Srrs * to illicit a sack with gaps to force out 807171440Srrs * the others. 808171440Srrs */ 809171440Srrs if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 810171440Srrs SCTP_STAT_INCR(sctps_earlyfrstpidsck2); 811171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 812171440Srrs SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); 813171440Srrs } 814171440Srrs SCTP_STAT_INCR(sctps_earlyfrstrid); 815171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); 816171440Srrs } else { 817171440Srrs /* No, stop it if its running */ 818171440Srrs if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 819171440Srrs SCTP_STAT_INCR(sctps_earlyfrstpidsck3); 820171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 821171440Srrs SCTP_FROM_SCTP_INDATA + SCTP_LOC_21); 822171440Srrs } 823171440Srrs } 824171440Srrs } 825171440Srrs /* if nothing was acked on this destination skip it */ 826171440Srrs if (net->net_ack == 0) { 827179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 828171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 829171440Srrs } 830171440Srrs continue; 831171440Srrs } 832171440Srrs if (net->net_ack2 > 0) { 833171440Srrs /* 834171440Srrs * Karn's rule applies to clearing error count, this 835171440Srrs * is optional. 836171440Srrs */ 837171440Srrs net->error_count = 0; 838171440Srrs if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == 839171440Srrs SCTP_ADDR_NOT_REACHABLE) { 840171440Srrs /* addr came good */ 841171440Srrs net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; 842171440Srrs net->dest_state |= SCTP_ADDR_REACHABLE; 843171440Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 844172090Srrs SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED); 845171440Srrs /* now was it the primary? if so restore */ 846171440Srrs if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) { 847171440Srrs (void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net); 848171440Srrs } 849171440Srrs } 850171440Srrs /* 851171440Srrs * JRS 5/14/07 - If CMT PF is on and the destination 852171440Srrs * is in PF state, set the destination to active 853171440Srrs * state and set the cwnd to one or two MTU's based 854171440Srrs * on whether PF1 or PF2 is being used. 855171440Srrs * 856171440Srrs * Should we stop any running T3 timer here? 857171440Srrs */ 858211944Stuexen if ((asoc->sctp_cmt_on_off == 1) && 859211944Stuexen (asoc->sctp_cmt_pf > 0) && 860179783Srrs ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { 861171440Srrs net->dest_state &= ~SCTP_ADDR_PF; 862211944Stuexen net->cwnd = net->mtu * asoc->sctp_cmt_pf; 863171440Srrs SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", 864171440Srrs net, net->cwnd); 865171440Srrs /* 866171440Srrs * Since the cwnd value is explicitly set, 867171440Srrs * skip the code that updates the cwnd 868171440Srrs * value. 869171440Srrs */ 870171440Srrs goto skip_cwnd_update; 871171440Srrs } 872171440Srrs } 873171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 874171440Srrs /* 875171440Srrs * CMT fast recovery code 876171440Srrs */ 877171440Srrs /* 878171440Srrs * if (sctp_cmt_on_off == 1 && 879171440Srrs * net->fast_retran_loss_recovery && 880171440Srrs * net->will_exit_fast_recovery == 0) { @@@ Do something } 881171440Srrs * else if (sctp_cmt_on_off == 0 && 882171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 883171440Srrs */ 884171440Srrs#endif 885171440Srrs 886211944Stuexen if (asoc->fast_retran_loss_recovery && 887211944Stuexen (will_exit == 0) && 888211944Stuexen (asoc->sctp_cmt_on_off == 0)) { 889171440Srrs /* 890171440Srrs * If we are in loss recovery we skip any cwnd 891171440Srrs * update 892171440Srrs */ 893171440Srrs goto skip_cwnd_update; 894171440Srrs } 895171440Srrs /* 896171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 897171440Srrs * moved. 898171440Srrs */ 899211944Stuexen if (accum_moved || 900211944Stuexen ((asoc->sctp_cmt_on_off == 1) && net->new_pseudo_cumack)) { 901171440Srrs /* If the cumulative ack moved we can proceed */ 902171440Srrs if (net->cwnd <= net->ssthresh) { 903171440Srrs /* We are in slow start */ 904179157Srrs if (net->flight_size + net->net_ack >= net->cwnd) { 905171440Srrs 906171440Srrs sctp_hs_cwnd_increase(stcb, net); 907171440Srrs 908171440Srrs } else { 909179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 910171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 911171440Srrs SCTP_CWND_LOG_NOADV_SS); 912171440Srrs } 913171440Srrs } 914171440Srrs } else { 915171440Srrs /* We are in congestion avoidance */ 916179157Srrs net->partial_bytes_acked += net->net_ack; 917179157Srrs if ((net->flight_size + net->net_ack >= net->cwnd) && 918179157Srrs (net->partial_bytes_acked >= net->cwnd)) { 919179157Srrs net->partial_bytes_acked -= net->cwnd; 920179157Srrs net->cwnd += net->mtu; 921179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 922179157Srrs sctp_log_cwnd(stcb, net, net->mtu, 923179157Srrs SCTP_CWND_LOG_FROM_CA); 924171440Srrs } 925171440Srrs } else { 926179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 927171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 928171440Srrs SCTP_CWND_LOG_NOADV_CA); 929171440Srrs } 930171440Srrs } 931171440Srrs } 932171440Srrs } else { 933179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 934171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 935171440Srrs SCTP_CWND_LOG_NO_CUMACK); 936171440Srrs } 937171440Srrs } 938171440Srrsskip_cwnd_update: 939171440Srrs /* 940171440Srrs * NOW, according to Karn's rule do we need to restore the 941171440Srrs * RTO timer back? Check our net_ack2. If not set then we 942171440Srrs * have a ambiguity.. i.e. all data ack'd was sent to more 943171440Srrs * than one place. 944171440Srrs */ 945171440Srrs if (net->net_ack2) { 946171440Srrs /* restore any doubled timers */ 947171440Srrs net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1; 948171440Srrs if (net->RTO < stcb->asoc.minrto) { 949171440Srrs net->RTO = stcb->asoc.minrto; 950171440Srrs } 951171440Srrs if (net->RTO > stcb->asoc.maxrto) { 952171440Srrs net->RTO = stcb->asoc.maxrto; 953171440Srrs } 954171440Srrs } 955171440Srrs } 956171440Srrs} 957171440Srrs 958171440Srrs 959171440Srrs/* 960171440Srrs * H-TCP congestion control. The algorithm is detailed in: 961171440Srrs * R.N.Shorten, D.J.Leith: 962171440Srrs * "H-TCP: TCP for high-speed and long-distance networks" 963171440Srrs * Proc. PFLDnet, Argonne, 2004. 964171440Srrs * http://www.hamilton.ie/net/htcp3.pdf 965171440Srrs */ 966171440Srrs 967171440Srrs 968171440Srrsstatic int use_rtt_scaling = 1; 969171440Srrsstatic int use_bandwidth_switch = 1; 970171440Srrs 971171440Srrsstatic inline int 972171440Srrsbetween(uint32_t seq1, uint32_t seq2, uint32_t seq3) 973171440Srrs{ 974171440Srrs return seq3 - seq2 >= seq1 - seq2; 975171440Srrs} 976171440Srrs 977171440Srrsstatic inline uint32_t 978171440Srrshtcp_cong_time(struct htcp *ca) 979171440Srrs{ 980171477Srrs return sctp_get_tick_count() - ca->last_cong; 981171440Srrs} 982171440Srrs 983171440Srrsstatic inline uint32_t 984171440Srrshtcp_ccount(struct htcp *ca) 985171440Srrs{ 986171440Srrs return htcp_cong_time(ca) / ca->minRTT; 987171440Srrs} 988171440Srrs 989171440Srrsstatic inline void 990171440Srrshtcp_reset(struct htcp *ca) 991171440Srrs{ 992171440Srrs ca->undo_last_cong = ca->last_cong; 993171440Srrs ca->undo_maxRTT = ca->maxRTT; 994171440Srrs ca->undo_old_maxB = ca->old_maxB; 995171477Srrs ca->last_cong = sctp_get_tick_count(); 996171440Srrs} 997171440Srrs 998171440Srrs#ifdef SCTP_NOT_USED 999171440Srrs 1000171440Srrsstatic uint32_t 1001171440Srrshtcp_cwnd_undo(struct sctp_tcb *stcb, struct sctp_nets *net) 1002171440Srrs{ 1003171440Srrs net->htcp_ca.last_cong = net->htcp_ca.undo_last_cong; 1004171440Srrs net->htcp_ca.maxRTT = net->htcp_ca.undo_maxRTT; 1005171440Srrs net->htcp_ca.old_maxB = net->htcp_ca.undo_old_maxB; 1006171440Srrs return max(net->cwnd, ((net->ssthresh / net->mtu << 7) / net->htcp_ca.beta) * net->mtu); 1007171440Srrs} 1008171440Srrs 1009171440Srrs#endif 1010171440Srrs 1011171440Srrsstatic inline void 1012171440Srrsmeasure_rtt(struct sctp_tcb *stcb, struct sctp_nets *net) 1013171440Srrs{ 1014171440Srrs uint32_t srtt = net->lastsa >> 3; 1015171440Srrs 1016171440Srrs /* keep track of minimum RTT seen so far, minRTT is zero at first */ 1017171440Srrs if (net->htcp_ca.minRTT > srtt || !net->htcp_ca.minRTT) 1018171440Srrs net->htcp_ca.minRTT = srtt; 1019171440Srrs 1020171440Srrs /* max RTT */ 1021171440Srrs if (net->fast_retran_ip == 0 && net->ssthresh < 0xFFFF && htcp_ccount(&net->htcp_ca) > 3) { 1022171440Srrs if (net->htcp_ca.maxRTT < net->htcp_ca.minRTT) 1023171440Srrs net->htcp_ca.maxRTT = net->htcp_ca.minRTT; 1024171440Srrs if (net->htcp_ca.maxRTT < srtt && srtt <= net->htcp_ca.maxRTT + MSEC_TO_TICKS(20)) 1025171440Srrs net->htcp_ca.maxRTT = srtt; 1026171440Srrs } 1027171440Srrs} 1028171440Srrs 1029171440Srrsstatic void 1030171440Srrsmeasure_achieved_throughput(struct sctp_tcb *stcb, struct sctp_nets *net) 1031171440Srrs{ 1032171477Srrs uint32_t now = sctp_get_tick_count(); 1033171440Srrs 1034171440Srrs if (net->fast_retran_ip == 0) 1035171440Srrs net->htcp_ca.bytes_acked = net->net_ack; 1036171440Srrs 1037171440Srrs if (!use_bandwidth_switch) 1038171440Srrs return; 1039171440Srrs 1040171440Srrs /* achieved throughput calculations */ 1041171440Srrs /* JRS - not 100% sure of this statement */ 1042171440Srrs if (net->fast_retran_ip == 1) { 1043171440Srrs net->htcp_ca.bytecount = 0; 1044171440Srrs net->htcp_ca.lasttime = now; 1045171440Srrs return; 1046171440Srrs } 1047171440Srrs net->htcp_ca.bytecount += net->net_ack; 1048171440Srrs 1049171440Srrs if (net->htcp_ca.bytecount >= net->cwnd - ((net->htcp_ca.alpha >> 7 ? : 1) * net->mtu) 1050171440Srrs && now - net->htcp_ca.lasttime >= net->htcp_ca.minRTT 1051171440Srrs && net->htcp_ca.minRTT > 0) { 1052171440Srrs uint32_t cur_Bi = net->htcp_ca.bytecount / net->mtu * hz / (now - net->htcp_ca.lasttime); 1053171440Srrs 1054171440Srrs if (htcp_ccount(&net->htcp_ca) <= 3) { 1055171440Srrs /* just after backoff */ 1056171440Srrs net->htcp_ca.minB = net->htcp_ca.maxB = net->htcp_ca.Bi = cur_Bi; 1057171440Srrs } else { 1058171440Srrs net->htcp_ca.Bi = (3 * net->htcp_ca.Bi + cur_Bi) / 4; 1059171440Srrs if (net->htcp_ca.Bi > net->htcp_ca.maxB) 1060171440Srrs net->htcp_ca.maxB = net->htcp_ca.Bi; 1061171440Srrs if (net->htcp_ca.minB > net->htcp_ca.maxB) 1062171440Srrs net->htcp_ca.minB = net->htcp_ca.maxB; 1063171440Srrs } 1064171440Srrs net->htcp_ca.bytecount = 0; 1065171440Srrs net->htcp_ca.lasttime = now; 1066171440Srrs } 1067171440Srrs} 1068171440Srrs 1069171440Srrsstatic inline void 1070171440Srrshtcp_beta_update(struct htcp *ca, uint32_t minRTT, uint32_t maxRTT) 1071171440Srrs{ 1072171440Srrs if (use_bandwidth_switch) { 1073171440Srrs uint32_t maxB = ca->maxB; 1074171440Srrs uint32_t old_maxB = ca->old_maxB; 1075171440Srrs 1076171440Srrs ca->old_maxB = ca->maxB; 1077171440Srrs 1078171440Srrs if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) { 1079171440Srrs ca->beta = BETA_MIN; 1080171440Srrs ca->modeswitch = 0; 1081171440Srrs return; 1082171440Srrs } 1083171440Srrs } 1084171440Srrs if (ca->modeswitch && minRTT > (uint32_t) MSEC_TO_TICKS(10) && maxRTT) { 1085171440Srrs ca->beta = (minRTT << 7) / maxRTT; 1086171440Srrs if (ca->beta < BETA_MIN) 1087171440Srrs ca->beta = BETA_MIN; 1088171440Srrs else if (ca->beta > BETA_MAX) 1089171440Srrs ca->beta = BETA_MAX; 1090171440Srrs } else { 1091171440Srrs ca->beta = BETA_MIN; 1092171440Srrs ca->modeswitch = 1; 1093171440Srrs } 1094171440Srrs} 1095171440Srrs 1096171440Srrsstatic inline void 1097171440Srrshtcp_alpha_update(struct htcp *ca) 1098171440Srrs{ 1099171440Srrs uint32_t minRTT = ca->minRTT; 1100171440Srrs uint32_t factor = 1; 1101171440Srrs uint32_t diff = htcp_cong_time(ca); 1102171440Srrs 1103171440Srrs if (diff > (uint32_t) hz) { 1104171440Srrs diff -= hz; 1105171440Srrs factor = 1 + (10 * diff + ((diff / 2) * (diff / 2) / hz)) / hz; 1106171440Srrs } 1107171440Srrs if (use_rtt_scaling && minRTT) { 1108171440Srrs uint32_t scale = (hz << 3) / (10 * minRTT); 1109171440Srrs 1110171440Srrs scale = min(max(scale, 1U << 2), 10U << 3); /* clamping ratio to 1111171440Srrs * interval [0.5,10]<<3 */ 1112171440Srrs factor = (factor << 3) / scale; 1113171440Srrs if (!factor) 1114171440Srrs factor = 1; 1115171440Srrs } 1116171440Srrs ca->alpha = 2 * factor * ((1 << 7) - ca->beta); 1117171440Srrs if (!ca->alpha) 1118171440Srrs ca->alpha = ALPHA_BASE; 1119171440Srrs} 1120171440Srrs 1121171440Srrs/* After we have the rtt data to calculate beta, we'd still prefer to wait one 1122171440Srrs * rtt before we adjust our beta to ensure we are working from a consistent 1123171440Srrs * data. 1124171440Srrs * 1125171440Srrs * This function should be called when we hit a congestion event since only at 1126171440Srrs * that point do we really have a real sense of maxRTT (the queues en route 1127171440Srrs * were getting just too full now). 1128171440Srrs */ 1129171440Srrsstatic void 1130171440Srrshtcp_param_update(struct sctp_tcb *stcb, struct sctp_nets *net) 1131171440Srrs{ 1132171440Srrs uint32_t minRTT = net->htcp_ca.minRTT; 1133171440Srrs uint32_t maxRTT = net->htcp_ca.maxRTT; 1134171440Srrs 1135171440Srrs htcp_beta_update(&net->htcp_ca, minRTT, maxRTT); 1136171440Srrs htcp_alpha_update(&net->htcp_ca); 1137171440Srrs 1138171440Srrs /* 1139171440Srrs * add slowly fading memory for maxRTT to accommodate routing 1140171440Srrs * changes etc 1141171440Srrs */ 1142171440Srrs if (minRTT > 0 && maxRTT > minRTT) 1143171440Srrs net->htcp_ca.maxRTT = minRTT + ((maxRTT - minRTT) * 95) / 100; 1144171440Srrs} 1145171440Srrs 1146171440Srrsstatic uint32_t 1147171440Srrshtcp_recalc_ssthresh(struct sctp_tcb *stcb, struct sctp_nets *net) 1148171440Srrs{ 1149171440Srrs htcp_param_update(stcb, net); 1150171440Srrs return max(((net->cwnd / net->mtu * net->htcp_ca.beta) >> 7) * net->mtu, 2U * net->mtu); 1151171440Srrs} 1152171440Srrs 1153171440Srrsstatic void 1154171440Srrshtcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net) 1155171440Srrs{ 1156171440Srrs /*- 1157171440Srrs * How to handle these functions? 1158171440Srrs * if (!tcp_is_cwnd_limited(sk, in_flight)) RRS - good question. 1159171440Srrs * return; 1160171440Srrs */ 1161171440Srrs if (net->cwnd <= net->ssthresh) { 1162171440Srrs /* We are in slow start */ 1163171440Srrs if (net->flight_size + net->net_ack >= net->cwnd) { 1164179783Srrs if (net->net_ack > (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable))) { 1165179783Srrs net->cwnd += (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)); 1166179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1167171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 1168171440Srrs SCTP_CWND_LOG_FROM_SS); 1169171440Srrs } 1170171440Srrs } else { 1171171440Srrs net->cwnd += net->net_ack; 1172179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1173171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 1174171440Srrs SCTP_CWND_LOG_FROM_SS); 1175171440Srrs } 1176171440Srrs } 1177171440Srrs } else { 1178179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1179171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 1180171440Srrs SCTP_CWND_LOG_NOADV_SS); 1181171440Srrs } 1182171440Srrs } 1183171440Srrs } else { 1184171440Srrs measure_rtt(stcb, net); 1185171440Srrs 1186171440Srrs /* 1187171440Srrs * In dangerous area, increase slowly. In theory this is 1188171440Srrs * net->cwnd += alpha / net->cwnd 1189171440Srrs */ 1190171440Srrs /* What is snd_cwnd_cnt?? */ 1191171440Srrs if (((net->partial_bytes_acked / net->mtu * net->htcp_ca.alpha) >> 7) * net->mtu >= net->cwnd) { 1192171440Srrs /*- 1193171440Srrs * Does SCTP have a cwnd clamp? 1194171440Srrs * if (net->snd_cwnd < net->snd_cwnd_clamp) - Nope (RRS). 1195171440Srrs */ 1196171440Srrs net->cwnd += net->mtu; 1197171440Srrs net->partial_bytes_acked = 0; 1198171440Srrs htcp_alpha_update(&net->htcp_ca); 1199179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1200171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 1201171440Srrs SCTP_CWND_LOG_FROM_CA); 1202171440Srrs } 1203171440Srrs } else { 1204171440Srrs net->partial_bytes_acked += net->net_ack; 1205179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1206171440Srrs sctp_log_cwnd(stcb, net, net->net_ack, 1207171440Srrs SCTP_CWND_LOG_NOADV_CA); 1208171440Srrs } 1209171440Srrs } 1210171440Srrs 1211171440Srrs net->htcp_ca.bytes_acked = net->mtu; 1212171440Srrs } 1213171440Srrs} 1214171440Srrs 1215171440Srrs#ifdef SCTP_NOT_USED 1216171440Srrs/* Lower bound on congestion window. */ 1217171440Srrsstatic uint32_t 1218171440Srrshtcp_min_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net) 1219171440Srrs{ 1220171440Srrs return net->ssthresh; 1221171440Srrs} 1222171440Srrs 1223171440Srrs#endif 1224171440Srrs 1225171440Srrsstatic void 1226171440Srrshtcp_init(struct sctp_tcb *stcb, struct sctp_nets *net) 1227171440Srrs{ 1228171440Srrs memset(&net->htcp_ca, 0, sizeof(struct htcp)); 1229171440Srrs net->htcp_ca.alpha = ALPHA_BASE; 1230171440Srrs net->htcp_ca.beta = BETA_MIN; 1231171440Srrs net->htcp_ca.bytes_acked = net->mtu; 1232171477Srrs net->htcp_ca.last_cong = sctp_get_tick_count(); 1233171440Srrs} 1234171440Srrs 1235171440Srrsvoid 1236171440Srrssctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) 1237171440Srrs{ 1238171440Srrs /* 1239171440Srrs * We take the max of the burst limit times a MTU or the 1240171440Srrs * INITIAL_CWND. We then limit this to 4 MTU's of sending. 1241171440Srrs */ 1242171440Srrs net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 1243171440Srrs net->ssthresh = stcb->asoc.peers_rwnd; 1244171440Srrs htcp_init(stcb, net); 1245171440Srrs 1246179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { 1247171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); 1248171440Srrs } 1249171440Srrs} 1250171440Srrs 1251171440Srrsvoid 1252171440Srrssctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, 1253171440Srrs struct sctp_association *asoc, 1254171440Srrs int accum_moved, int reneged_all, int will_exit) 1255171440Srrs{ 1256171440Srrs struct sctp_nets *net; 1257171440Srrs 1258171440Srrs /******************************/ 1259171440Srrs /* update cwnd and Early FR */ 1260171440Srrs /******************************/ 1261171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 1262171440Srrs 1263171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 1264171440Srrs /* 1265171440Srrs * CMT fast recovery code. Need to debug. 1266171440Srrs */ 1267171440Srrs if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 1268171440Srrs if (compare_with_wrap(asoc->last_acked_seq, 1269171440Srrs net->fast_recovery_tsn, MAX_TSN) || 1270171440Srrs (asoc->last_acked_seq == net->fast_recovery_tsn) || 1271171440Srrs compare_with_wrap(net->pseudo_cumack, net->fast_recovery_tsn, MAX_TSN) || 1272171440Srrs (net->pseudo_cumack == net->fast_recovery_tsn)) { 1273171440Srrs net->will_exit_fast_recovery = 1; 1274171440Srrs } 1275171440Srrs } 1276171440Srrs#endif 1277179783Srrs if (SCTP_BASE_SYSCTL(sctp_early_fr)) { 1278171440Srrs /* 1279171440Srrs * So, first of all do we need to have a Early FR 1280171440Srrs * timer running? 1281171440Srrs */ 1282171440Srrs if (((TAILQ_FIRST(&asoc->sent_queue)) && 1283171440Srrs (net->ref_count > 1) && 1284171440Srrs (net->flight_size < net->cwnd)) || 1285171440Srrs (reneged_all)) { 1286171440Srrs /* 1287171440Srrs * yes, so in this case stop it if its 1288171440Srrs * running, and then restart it. Reneging 1289171440Srrs * all is a special case where we want to 1290171440Srrs * run the Early FR timer and then force the 1291171440Srrs * last few unacked to be sent, causing us 1292171440Srrs * to illicit a sack with gaps to force out 1293171440Srrs * the others. 1294171440Srrs */ 1295171440Srrs if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 1296171440Srrs SCTP_STAT_INCR(sctps_earlyfrstpidsck2); 1297171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 1298171440Srrs SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); 1299171440Srrs } 1300171440Srrs SCTP_STAT_INCR(sctps_earlyfrstrid); 1301171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); 1302171440Srrs } else { 1303171440Srrs /* No, stop it if its running */ 1304171440Srrs if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 1305171440Srrs SCTP_STAT_INCR(sctps_earlyfrstpidsck3); 1306171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 1307171440Srrs SCTP_FROM_SCTP_INDATA + SCTP_LOC_21); 1308171440Srrs } 1309171440Srrs } 1310171440Srrs } 1311171440Srrs /* if nothing was acked on this destination skip it */ 1312171440Srrs if (net->net_ack == 0) { 1313179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1314171440Srrs sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 1315171440Srrs } 1316171440Srrs continue; 1317171440Srrs } 1318171440Srrs if (net->net_ack2 > 0) { 1319171440Srrs /* 1320171440Srrs * Karn's rule applies to clearing error count, this 1321171440Srrs * is optional. 1322171440Srrs */ 1323171440Srrs net->error_count = 0; 1324171440Srrs if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == 1325171440Srrs SCTP_ADDR_NOT_REACHABLE) { 1326171440Srrs /* addr came good */ 1327171440Srrs net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; 1328171440Srrs net->dest_state |= SCTP_ADDR_REACHABLE; 1329171440Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 1330172090Srrs SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED); 1331171440Srrs /* now was it the primary? if so restore */ 1332171440Srrs if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) { 1333171440Srrs (void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net); 1334171440Srrs } 1335171440Srrs } 1336171440Srrs /* 1337171440Srrs * JRS 5/14/07 - If CMT PF is on and the destination 1338171440Srrs * is in PF state, set the destination to active 1339171440Srrs * state and set the cwnd to one or two MTU's based 1340171440Srrs * on whether PF1 or PF2 is being used. 1341171440Srrs * 1342171440Srrs * Should we stop any running T3 timer here? 1343171440Srrs */ 1344211944Stuexen if ((asoc->sctp_cmt_on_off == 1) && 1345211944Stuexen (asoc->sctp_cmt_pf > 0) && 1346179783Srrs ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { 1347171440Srrs net->dest_state &= ~SCTP_ADDR_PF; 1348211944Stuexen net->cwnd = net->mtu * asoc->sctp_cmt_pf; 1349171440Srrs SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", 1350171440Srrs net, net->cwnd); 1351171440Srrs /* 1352171440Srrs * Since the cwnd value is explicitly set, 1353171440Srrs * skip the code that updates the cwnd 1354171440Srrs * value. 1355171440Srrs */ 1356171440Srrs goto skip_cwnd_update; 1357171440Srrs } 1358171440Srrs } 1359171440Srrs#ifdef JANA_CMT_FAST_RECOVERY 1360171440Srrs /* 1361171440Srrs * CMT fast recovery code 1362171440Srrs */ 1363171440Srrs /* 1364171440Srrs * if (sctp_cmt_on_off == 1 && 1365171440Srrs * net->fast_retran_loss_recovery && 1366171440Srrs * net->will_exit_fast_recovery == 0) { @@@ Do something } 1367171440Srrs * else if (sctp_cmt_on_off == 0 && 1368171440Srrs * asoc->fast_retran_loss_recovery && will_exit == 0) { 1369171440Srrs */ 1370171440Srrs#endif 1371171440Srrs 1372211944Stuexen if (asoc->fast_retran_loss_recovery && 1373211944Stuexen will_exit == 0 && 1374211944Stuexen (asoc->sctp_cmt_on_off == 0)) { 1375171440Srrs /* 1376171440Srrs * If we are in loss recovery we skip any cwnd 1377171440Srrs * update 1378171440Srrs */ 1379171440Srrs goto skip_cwnd_update; 1380171440Srrs } 1381171440Srrs /* 1382171440Srrs * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 1383171440Srrs * moved. 1384171440Srrs */ 1385211944Stuexen if (accum_moved || 1386211944Stuexen ((asoc->sctp_cmt_on_off == 1) && net->new_pseudo_cumack)) { 1387171440Srrs htcp_cong_avoid(stcb, net); 1388171440Srrs measure_achieved_throughput(stcb, net); 1389171440Srrs } else { 1390179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1391171440Srrs sctp_log_cwnd(stcb, net, net->mtu, 1392171440Srrs SCTP_CWND_LOG_NO_CUMACK); 1393171440Srrs } 1394171440Srrs } 1395171440Srrsskip_cwnd_update: 1396171440Srrs /* 1397171440Srrs * NOW, according to Karn's rule do we need to restore the 1398171440Srrs * RTO timer back? Check our net_ack2. If not set then we 1399171440Srrs * have a ambiguity.. i.e. all data ack'd was sent to more 1400171440Srrs * than one place. 1401171440Srrs */ 1402171440Srrs if (net->net_ack2) { 1403171440Srrs /* restore any doubled timers */ 1404171440Srrs net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1; 1405171440Srrs if (net->RTO < stcb->asoc.minrto) { 1406171440Srrs net->RTO = stcb->asoc.minrto; 1407171440Srrs } 1408171440Srrs if (net->RTO > stcb->asoc.maxrto) { 1409171440Srrs net->RTO = stcb->asoc.maxrto; 1410171440Srrs } 1411171440Srrs } 1412171440Srrs } 1413171440Srrs} 1414171440Srrs 1415171440Srrsvoid 1416171440Srrssctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb, 1417171440Srrs struct sctp_association *asoc) 1418171440Srrs{ 1419171440Srrs struct sctp_nets *net; 1420171440Srrs 1421171440Srrs /* 1422171440Srrs * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off == 1) && 1423171440Srrs * (net->fast_retran_loss_recovery == 0))) 1424171440Srrs */ 1425171440Srrs TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 1426211944Stuexen if ((asoc->fast_retran_loss_recovery == 0) || 1427211944Stuexen (asoc->sctp_cmt_on_off == 1)) { 1428171440Srrs /* out of a RFC2582 Fast recovery window? */ 1429171440Srrs if (net->net_ack > 0) { 1430171440Srrs /* 1431171440Srrs * per section 7.2.3, are there any 1432171440Srrs * destinations that had a fast retransmit 1433171440Srrs * to them. If so what we need to do is 1434171440Srrs * adjust ssthresh and cwnd. 1435171440Srrs */ 1436171440Srrs struct sctp_tmit_chunk *lchk; 1437171440Srrs int old_cwnd = net->cwnd; 1438171440Srrs 1439171440Srrs /* JRS - reset as if state were changed */ 1440171440Srrs htcp_reset(&net->htcp_ca); 1441171440Srrs net->ssthresh = htcp_recalc_ssthresh(stcb, net); 1442171440Srrs net->cwnd = net->ssthresh; 1443179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1444171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 1445171440Srrs SCTP_CWND_LOG_FROM_FR); 1446171440Srrs } 1447171440Srrs lchk = TAILQ_FIRST(&asoc->send_queue); 1448171440Srrs 1449171440Srrs net->partial_bytes_acked = 0; 1450171440Srrs /* Turn on fast recovery window */ 1451171440Srrs asoc->fast_retran_loss_recovery = 1; 1452171440Srrs if (lchk == NULL) { 1453171440Srrs /* Mark end of the window */ 1454171440Srrs asoc->fast_recovery_tsn = asoc->sending_seq - 1; 1455171440Srrs } else { 1456171440Srrs asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 1457171440Srrs } 1458171440Srrs 1459171440Srrs /* 1460171440Srrs * CMT fast recovery -- per destination 1461171440Srrs * recovery variable. 1462171440Srrs */ 1463171440Srrs net->fast_retran_loss_recovery = 1; 1464171440Srrs 1465171440Srrs if (lchk == NULL) { 1466171440Srrs /* Mark end of the window */ 1467171440Srrs net->fast_recovery_tsn = asoc->sending_seq - 1; 1468171440Srrs } else { 1469171440Srrs net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 1470171440Srrs } 1471171440Srrs 1472171440Srrs /* 1473171440Srrs * Disable Nonce Sum Checking and store the 1474171440Srrs * resync tsn 1475171440Srrs */ 1476171440Srrs asoc->nonce_sum_check = 0; 1477171440Srrs asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1; 1478171440Srrs 1479171440Srrs sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 1480171440Srrs stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); 1481171440Srrs sctp_timer_start(SCTP_TIMER_TYPE_SEND, 1482171440Srrs stcb->sctp_ep, stcb, net); 1483171440Srrs } 1484171440Srrs } else if (net->net_ack > 0) { 1485171440Srrs /* 1486171440Srrs * Mark a peg that we WOULD have done a cwnd 1487171440Srrs * reduction but RFC2582 prevented this action. 1488171440Srrs */ 1489171440Srrs SCTP_STAT_INCR(sctps_fastretransinrtt); 1490171440Srrs } 1491171440Srrs } 1492171440Srrs} 1493171440Srrs 1494171440Srrsvoid 1495171440Srrssctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb, 1496171440Srrs struct sctp_nets *net) 1497171440Srrs{ 1498171440Srrs int old_cwnd = net->cwnd; 1499171440Srrs 1500171440Srrs /* JRS - reset as if the state were being changed to timeout */ 1501171440Srrs htcp_reset(&net->htcp_ca); 1502171440Srrs net->ssthresh = htcp_recalc_ssthresh(stcb, net); 1503171440Srrs net->cwnd = net->mtu; 1504179157Srrs net->partial_bytes_acked = 0; 1505179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1506171440Srrs sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 1507171440Srrs } 1508171440Srrs} 1509171440Srrs 1510171440Srrsvoid 1511171440Srrssctp_htcp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp, 1512171440Srrs struct sctp_tcb *stcb, struct sctp_nets *net) 1513171440Srrs{ 1514171440Srrs int old_cwnd; 1515171440Srrs 1516171440Srrs old_cwnd = net->cwnd; 1517171440Srrs 1518172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED); 1519171477Srrs net->htcp_ca.last_cong = sctp_get_tick_count(); 1520171440Srrs /* 1521171440Srrs * make a small adjustment to cwnd and force to CA. 1522171440Srrs */ 1523171440Srrs if (net->cwnd > net->mtu) 1524171440Srrs /* drop down one MTU after sending */ 1525171440Srrs net->cwnd -= net->mtu; 1526171440Srrs if (net->cwnd < net->ssthresh) 1527171440Srrs /* still in SS move to CA */ 1528171440Srrs net->ssthresh = net->cwnd - 1; 1529179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1530171440Srrs sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR); 1531171440Srrs } 1532171440Srrs} 1533171440Srrs 1534171440Srrsvoid 1535171440Srrssctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, 1536171440Srrs struct sctp_nets *net) 1537171440Srrs{ 1538171440Srrs int old_cwnd; 1539171440Srrs 1540171440Srrs old_cwnd = net->cwnd; 1541171440Srrs 1542171440Srrs /* JRS - reset hctp as if state changed */ 1543171440Srrs htcp_reset(&net->htcp_ca); 1544171440Srrs SCTP_STAT_INCR(sctps_ecnereducedcwnd); 1545171440Srrs net->ssthresh = htcp_recalc_ssthresh(stcb, net); 1546171440Srrs if (net->ssthresh < net->mtu) { 1547171440Srrs net->ssthresh = net->mtu; 1548171440Srrs /* here back off the timer as well, to slow us down */ 1549171440Srrs net->RTO <<= 1; 1550171440Srrs } 1551171440Srrs net->cwnd = net->ssthresh; 1552179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1553171440Srrs sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 1554171440Srrs } 1555171440Srrs} 1556