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