sctp_cc_functions.c revision 212702
1/*- 2 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * a) Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * 10 * b) Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the distribution. 13 * 14 * c) Neither the name of Cisco Systems, Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include <netinet/sctp_os.h> 32#include <netinet/sctp_var.h> 33#include <netinet/sctp_sysctl.h> 34#include <netinet/sctp_pcb.h> 35#include <netinet/sctp_header.h> 36#include <netinet/sctputil.h> 37#include <netinet/sctp_output.h> 38#include <netinet/sctp_input.h> 39#include <netinet/sctp_indata.h> 40#include <netinet/sctp_uio.h> 41#include <netinet/sctp_timer.h> 42#include <netinet/sctp_auth.h> 43#include <netinet/sctp_asconf.h> 44#include <netinet/sctp_cc_functions.h> 45#include <sys/cdefs.h> 46__FBSDID("$FreeBSD: head/sys/netinet/sctp_cc_functions.c 212702 2010-09-15 20:53:20Z tuexen $"); 47void 48sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) 49{ 50 /* 51 * We take the max of the burst limit times a MTU or the 52 * INITIAL_CWND. We then limit this to 4 MTU's of sending. cwnd must 53 * be at least 2 MTU. 54 */ 55 net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 56 net->ssthresh = stcb->asoc.peers_rwnd; 57 58 if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { 59 sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); 60 } 61} 62 63void 64sctp_cwnd_update_after_fr(struct sctp_tcb *stcb, 65 struct sctp_association *asoc) 66{ 67 struct sctp_nets *net; 68 69 /*- 70 * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off == 1) && 71 * (net->fast_retran_loss_recovery == 0))) 72 */ 73 TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 74 if ((asoc->fast_retran_loss_recovery == 0) || 75 (asoc->sctp_cmt_on_off == 1)) { 76 /* out of a RFC2582 Fast recovery window? */ 77 if (net->net_ack > 0) { 78 /* 79 * per section 7.2.3, are there any 80 * destinations that had a fast retransmit 81 * to them. If so what we need to do is 82 * adjust ssthresh and cwnd. 83 */ 84 struct sctp_tmit_chunk *lchk; 85 int old_cwnd = net->cwnd; 86 87 net->ssthresh = net->cwnd / 2; 88 if (net->ssthresh < (net->mtu * 2)) { 89 net->ssthresh = 2 * net->mtu; 90 } 91 net->cwnd = net->ssthresh; 92 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 93 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 94 SCTP_CWND_LOG_FROM_FR); 95 } 96 lchk = TAILQ_FIRST(&asoc->send_queue); 97 98 net->partial_bytes_acked = 0; 99 /* Turn on fast recovery window */ 100 asoc->fast_retran_loss_recovery = 1; 101 if (lchk == NULL) { 102 /* Mark end of the window */ 103 asoc->fast_recovery_tsn = asoc->sending_seq - 1; 104 } else { 105 asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 106 } 107 108 /* 109 * CMT fast recovery -- per destination 110 * recovery variable. 111 */ 112 net->fast_retran_loss_recovery = 1; 113 114 if (lchk == NULL) { 115 /* Mark end of the window */ 116 net->fast_recovery_tsn = asoc->sending_seq - 1; 117 } else { 118 net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 119 } 120 121 /* 122 * Disable Nonce Sum Checking and store the 123 * resync tsn 124 */ 125 asoc->nonce_sum_check = 0; 126 asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1; 127 128 sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 129 stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); 130 sctp_timer_start(SCTP_TIMER_TYPE_SEND, 131 stcb->sctp_ep, stcb, net); 132 } 133 } else if (net->net_ack > 0) { 134 /* 135 * Mark a peg that we WOULD have done a cwnd 136 * reduction but RFC2582 prevented this action. 137 */ 138 SCTP_STAT_INCR(sctps_fastretransinrtt); 139 } 140 } 141} 142 143void 144sctp_cwnd_update_after_sack(struct sctp_tcb *stcb, 145 struct sctp_association *asoc, 146 int accum_moved, int reneged_all, int will_exit) 147{ 148 struct sctp_nets *net; 149 150 /******************************/ 151 /* update cwnd and Early FR */ 152 /******************************/ 153 TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 154 155#ifdef JANA_CMT_FAST_RECOVERY 156 /* 157 * CMT fast recovery code. Need to debug. 158 */ 159 if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 160 if (compare_with_wrap(asoc->last_acked_seq, 161 net->fast_recovery_tsn, MAX_TSN) || 162 (asoc->last_acked_seq == net->fast_recovery_tsn) || 163 compare_with_wrap(net->pseudo_cumack, net->fast_recovery_tsn, MAX_TSN) || 164 (net->pseudo_cumack == net->fast_recovery_tsn)) { 165 net->will_exit_fast_recovery = 1; 166 } 167 } 168#endif 169 if (SCTP_BASE_SYSCTL(sctp_early_fr)) { 170 /* 171 * So, first of all do we need to have a Early FR 172 * timer running? 173 */ 174 if ((!TAILQ_EMPTY(&asoc->sent_queue) && 175 (net->ref_count > 1) && 176 (net->flight_size < net->cwnd)) || 177 (reneged_all)) { 178 /* 179 * yes, so in this case stop it if its 180 * running, and then restart it. Reneging 181 * all is a special case where we want to 182 * run the Early FR timer and then force the 183 * last few unacked to be sent, causing us 184 * to illicit a sack with gaps to force out 185 * the others. 186 */ 187 if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 188 SCTP_STAT_INCR(sctps_earlyfrstpidsck2); 189 sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 190 SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); 191 } 192 SCTP_STAT_INCR(sctps_earlyfrstrid); 193 sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); 194 } else { 195 /* No, stop it if its running */ 196 if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 197 SCTP_STAT_INCR(sctps_earlyfrstpidsck3); 198 sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 199 SCTP_FROM_SCTP_INDATA + SCTP_LOC_21); 200 } 201 } 202 } 203 /* if nothing was acked on this destination skip it */ 204 if (net->net_ack == 0) { 205 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 206 sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 207 } 208 continue; 209 } 210 if (net->net_ack2 > 0) { 211 /* 212 * Karn's rule applies to clearing error count, this 213 * is optional. 214 */ 215 net->error_count = 0; 216 if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == 217 SCTP_ADDR_NOT_REACHABLE) { 218 /* addr came good */ 219 net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; 220 net->dest_state |= SCTP_ADDR_REACHABLE; 221 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 222 SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED); 223 /* now was it the primary? if so restore */ 224 if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) { 225 (void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net); 226 } 227 } 228 /* 229 * JRS 5/14/07 - If CMT PF is on and the destination 230 * is in PF state, set the destination to active 231 * state and set the cwnd to one or two MTU's based 232 * on whether PF1 or PF2 is being used. 233 * 234 * Should we stop any running T3 timer here? 235 */ 236 if ((asoc->sctp_cmt_on_off == 1) && 237 (asoc->sctp_cmt_pf > 0) && 238 ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { 239 net->dest_state &= ~SCTP_ADDR_PF; 240 net->cwnd = net->mtu * asoc->sctp_cmt_pf; 241 SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", 242 net, net->cwnd); 243 /* 244 * Since the cwnd value is explicitly set, 245 * skip the code that updates the cwnd 246 * value. 247 */ 248 goto skip_cwnd_update; 249 } 250 } 251#ifdef JANA_CMT_FAST_RECOVERY 252 /* 253 * CMT fast recovery code 254 */ 255 /* 256 * if (sctp_cmt_on_off == 1 && 257 * net->fast_retran_loss_recovery && 258 * net->will_exit_fast_recovery == 0) { @@@ Do something } 259 * else if (sctp_cmt_on_off == 0 && 260 * asoc->fast_retran_loss_recovery && will_exit == 0) { 261 */ 262#endif 263 264 if (asoc->fast_retran_loss_recovery && 265 (will_exit == 0) && 266 (asoc->sctp_cmt_on_off == 0)) { 267 /* 268 * If we are in loss recovery we skip any cwnd 269 * update 270 */ 271 goto skip_cwnd_update; 272 } 273 /* 274 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 275 * moved. 276 */ 277 if (accum_moved || 278 ((asoc->sctp_cmt_on_off == 1) && net->new_pseudo_cumack)) { 279 /* If the cumulative ack moved we can proceed */ 280 if (net->cwnd <= net->ssthresh) { 281 /* We are in slow start */ 282 if (net->flight_size + net->net_ack >= net->cwnd) { 283 if (net->net_ack > (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable))) { 284 net->cwnd += (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)); 285 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 286 sctp_log_cwnd(stcb, net, net->mtu, 287 SCTP_CWND_LOG_FROM_SS); 288 } 289 } else { 290 net->cwnd += net->net_ack; 291 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 292 sctp_log_cwnd(stcb, net, net->net_ack, 293 SCTP_CWND_LOG_FROM_SS); 294 } 295 } 296 } else { 297 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 298 sctp_log_cwnd(stcb, net, net->net_ack, 299 SCTP_CWND_LOG_NOADV_SS); 300 } 301 } 302 } else { 303 /* We are in congestion avoidance */ 304 /* 305 * Add to pba 306 */ 307 net->partial_bytes_acked += net->net_ack; 308 309 if ((net->flight_size + net->net_ack >= net->cwnd) && 310 (net->partial_bytes_acked >= net->cwnd)) { 311 net->partial_bytes_acked -= net->cwnd; 312 net->cwnd += net->mtu; 313 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 314 sctp_log_cwnd(stcb, net, net->mtu, 315 SCTP_CWND_LOG_FROM_CA); 316 } 317 } else { 318 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 319 sctp_log_cwnd(stcb, net, net->net_ack, 320 SCTP_CWND_LOG_NOADV_CA); 321 } 322 } 323 } 324 } else { 325 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 326 sctp_log_cwnd(stcb, net, net->mtu, 327 SCTP_CWND_LOG_NO_CUMACK); 328 } 329 } 330skip_cwnd_update: 331 /* 332 * NOW, according to Karn's rule do we need to restore the 333 * RTO timer back? Check our net_ack2. If not set then we 334 * have a ambiguity.. i.e. all data ack'd was sent to more 335 * than one place. 336 */ 337 if (net->net_ack2) { 338 /* restore any doubled timers */ 339 net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1; 340 if (net->RTO < stcb->asoc.minrto) { 341 net->RTO = stcb->asoc.minrto; 342 } 343 if (net->RTO > stcb->asoc.maxrto) { 344 net->RTO = stcb->asoc.maxrto; 345 } 346 } 347 } 348} 349 350void 351sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net) 352{ 353 int old_cwnd = net->cwnd; 354 355 net->ssthresh = max(net->cwnd / 2, 4 * net->mtu); 356 net->cwnd = net->mtu; 357 net->partial_bytes_acked = 0; 358 359 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 360 sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 361 } 362} 363 364void 365sctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net) 366{ 367 int old_cwnd = net->cwnd; 368 369 SCTP_STAT_INCR(sctps_ecnereducedcwnd); 370 net->ssthresh = net->cwnd / 2; 371 if (net->ssthresh < net->mtu) { 372 net->ssthresh = net->mtu; 373 /* here back off the timer as well, to slow us down */ 374 net->RTO <<= 1; 375 } 376 net->cwnd = net->ssthresh; 377 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 378 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 379 } 380} 381 382void 383sctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb, 384 struct sctp_nets *net, struct sctp_pktdrop_chunk *cp, 385 uint32_t * bottle_bw, uint32_t * on_queue) 386{ 387 uint32_t bw_avail; 388 int rtt, incr; 389 int old_cwnd = net->cwnd; 390 391 /* need real RTT for this calc */ 392 rtt = ((net->lastsa >> 2) + net->lastsv) >> 1; 393 /* get bottle neck bw */ 394 *bottle_bw = ntohl(cp->bottle_bw); 395 /* and whats on queue */ 396 *on_queue = ntohl(cp->current_onq); 397 /* 398 * adjust the on-queue if our flight is more it could be that the 399 * router has not yet gotten data "in-flight" to it 400 */ 401 if (*on_queue < net->flight_size) 402 *on_queue = net->flight_size; 403 /* calculate the available space */ 404 bw_avail = (*bottle_bw * rtt) / 1000; 405 if (bw_avail > *bottle_bw) { 406 /* 407 * Cap the growth to no more than the bottle neck. This can 408 * happen as RTT slides up due to queues. It also means if 409 * you have more than a 1 second RTT with a empty queue you 410 * will be limited to the bottle_bw per second no matter if 411 * other points have 1/2 the RTT and you could get more 412 * out... 413 */ 414 bw_avail = *bottle_bw; 415 } 416 if (*on_queue > bw_avail) { 417 /* 418 * No room for anything else don't allow anything else to be 419 * "added to the fire". 420 */ 421 int seg_inflight, seg_onqueue, my_portion; 422 423 net->partial_bytes_acked = 0; 424 425 /* how much are we over queue size? */ 426 incr = *on_queue - bw_avail; 427 if (stcb->asoc.seen_a_sack_this_pkt) { 428 /* 429 * undo any cwnd adjustment that the sack might have 430 * made 431 */ 432 net->cwnd = net->prev_cwnd; 433 } 434 /* Now how much of that is mine? */ 435 seg_inflight = net->flight_size / net->mtu; 436 seg_onqueue = *on_queue / net->mtu; 437 my_portion = (incr * seg_inflight) / seg_onqueue; 438 439 /* Have I made an adjustment already */ 440 if (net->cwnd > net->flight_size) { 441 /* 442 * for this flight I made an adjustment we need to 443 * decrease the portion by a share our previous 444 * adjustment. 445 */ 446 int diff_adj; 447 448 diff_adj = net->cwnd - net->flight_size; 449 if (diff_adj > my_portion) 450 my_portion = 0; 451 else 452 my_portion -= diff_adj; 453 } 454 /* 455 * back down to the previous cwnd (assume we have had a sack 456 * before this packet). minus what ever portion of the 457 * overage is my fault. 458 */ 459 net->cwnd -= my_portion; 460 461 /* we will NOT back down more than 1 MTU */ 462 if (net->cwnd <= net->mtu) { 463 net->cwnd = net->mtu; 464 } 465 /* force into CA */ 466 net->ssthresh = net->cwnd - 1; 467 } else { 468 /* 469 * Take 1/4 of the space left or max burst up .. whichever 470 * is less. 471 */ 472 incr = min((bw_avail - *on_queue) >> 2, 473 stcb->asoc.max_burst * net->mtu); 474 net->cwnd += incr; 475 } 476 if (net->cwnd > bw_avail) { 477 /* We can't exceed the pipe size */ 478 net->cwnd = bw_avail; 479 } 480 if (net->cwnd < net->mtu) { 481 /* We always have 1 MTU */ 482 net->cwnd = net->mtu; 483 } 484 if (net->cwnd - old_cwnd != 0) { 485 /* log only changes */ 486 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 487 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 488 SCTP_CWND_LOG_FROM_SAT); 489 } 490 } 491} 492 493void 494sctp_cwnd_update_after_output(struct sctp_tcb *stcb, 495 struct sctp_nets *net, int burst_limit) 496{ 497 int old_cwnd = net->cwnd; 498 499 if (net->ssthresh < net->cwnd) 500 net->ssthresh = net->cwnd; 501 net->cwnd = (net->flight_size + (burst_limit * net->mtu)); 502 503 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 504 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST); 505 } 506} 507 508void 509sctp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp, 510 struct sctp_tcb *stcb, struct sctp_nets *net) 511{ 512 int old_cwnd = net->cwnd; 513 514 sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED); 515 /* 516 * make a small adjustment to cwnd and force to CA. 517 */ 518 if (net->cwnd > net->mtu) 519 /* drop down one MTU after sending */ 520 net->cwnd -= net->mtu; 521 if (net->cwnd < net->ssthresh) 522 /* still in SS move to CA */ 523 net->ssthresh = net->cwnd - 1; 524 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 525 sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR); 526 } 527} 528 529struct sctp_hs_raise_drop { 530 int32_t cwnd; 531 int32_t increase; 532 int32_t drop_percent; 533}; 534 535#define SCTP_HS_TABLE_SIZE 73 536 537struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = { 538 {38, 1, 50}, /* 0 */ 539 {118, 2, 44}, /* 1 */ 540 {221, 3, 41}, /* 2 */ 541 {347, 4, 38}, /* 3 */ 542 {495, 5, 37}, /* 4 */ 543 {663, 6, 35}, /* 5 */ 544 {851, 7, 34}, /* 6 */ 545 {1058, 8, 33}, /* 7 */ 546 {1284, 9, 32}, /* 8 */ 547 {1529, 10, 31}, /* 9 */ 548 {1793, 11, 30}, /* 10 */ 549 {2076, 12, 29}, /* 11 */ 550 {2378, 13, 28}, /* 12 */ 551 {2699, 14, 28}, /* 13 */ 552 {3039, 15, 27}, /* 14 */ 553 {3399, 16, 27}, /* 15 */ 554 {3778, 17, 26}, /* 16 */ 555 {4177, 18, 26}, /* 17 */ 556 {4596, 19, 25}, /* 18 */ 557 {5036, 20, 25}, /* 19 */ 558 {5497, 21, 24}, /* 20 */ 559 {5979, 22, 24}, /* 21 */ 560 {6483, 23, 23}, /* 22 */ 561 {7009, 24, 23}, /* 23 */ 562 {7558, 25, 22}, /* 24 */ 563 {8130, 26, 22}, /* 25 */ 564 {8726, 27, 22}, /* 26 */ 565 {9346, 28, 21}, /* 27 */ 566 {9991, 29, 21}, /* 28 */ 567 {10661, 30, 21}, /* 29 */ 568 {11358, 31, 20}, /* 30 */ 569 {12082, 32, 20}, /* 31 */ 570 {12834, 33, 20}, /* 32 */ 571 {13614, 34, 19}, /* 33 */ 572 {14424, 35, 19}, /* 34 */ 573 {15265, 36, 19}, /* 35 */ 574 {16137, 37, 19}, /* 36 */ 575 {17042, 38, 18}, /* 37 */ 576 {17981, 39, 18}, /* 38 */ 577 {18955, 40, 18}, /* 39 */ 578 {19965, 41, 17}, /* 40 */ 579 {21013, 42, 17}, /* 41 */ 580 {22101, 43, 17}, /* 42 */ 581 {23230, 44, 17}, /* 43 */ 582 {24402, 45, 16}, /* 44 */ 583 {25618, 46, 16}, /* 45 */ 584 {26881, 47, 16}, /* 46 */ 585 {28193, 48, 16}, /* 47 */ 586 {29557, 49, 15}, /* 48 */ 587 {30975, 50, 15}, /* 49 */ 588 {32450, 51, 15}, /* 50 */ 589 {33986, 52, 15}, /* 51 */ 590 {35586, 53, 14}, /* 52 */ 591 {37253, 54, 14}, /* 53 */ 592 {38992, 55, 14}, /* 54 */ 593 {40808, 56, 14}, /* 55 */ 594 {42707, 57, 13}, /* 56 */ 595 {44694, 58, 13}, /* 57 */ 596 {46776, 59, 13}, /* 58 */ 597 {48961, 60, 13}, /* 59 */ 598 {51258, 61, 13}, /* 60 */ 599 {53677, 62, 12}, /* 61 */ 600 {56230, 63, 12}, /* 62 */ 601 {58932, 64, 12}, /* 63 */ 602 {61799, 65, 12}, /* 64 */ 603 {64851, 66, 11}, /* 65 */ 604 {68113, 67, 11}, /* 66 */ 605 {71617, 68, 11}, /* 67 */ 606 {75401, 69, 10}, /* 68 */ 607 {79517, 70, 10}, /* 69 */ 608 {84035, 71, 10}, /* 70 */ 609 {89053, 72, 10}, /* 71 */ 610 {94717, 73, 9} /* 72 */ 611}; 612 613static void 614sctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net) 615{ 616 int cur_val, i, indx, incr; 617 618 cur_val = net->cwnd >> 10; 619 indx = SCTP_HS_TABLE_SIZE - 1; 620#ifdef SCTP_DEBUG 621 printf("HS CC CAlled.\n"); 622#endif 623 if (cur_val < sctp_cwnd_adjust[0].cwnd) { 624 /* normal mode */ 625 if (net->net_ack > net->mtu) { 626 net->cwnd += net->mtu; 627 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 628 sctp_log_cwnd(stcb, net, net->mtu, SCTP_CWND_LOG_FROM_SS); 629 } 630 } else { 631 net->cwnd += net->net_ack; 632 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 633 sctp_log_cwnd(stcb, net, net->net_ack, SCTP_CWND_LOG_FROM_SS); 634 } 635 } 636 } else { 637 for (i = net->last_hs_used; i < SCTP_HS_TABLE_SIZE; i++) { 638 if (cur_val < sctp_cwnd_adjust[i].cwnd) { 639 indx = i; 640 break; 641 } 642 } 643 net->last_hs_used = indx; 644 incr = ((sctp_cwnd_adjust[indx].increase) << 10); 645 net->cwnd += incr; 646 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 647 sctp_log_cwnd(stcb, net, incr, SCTP_CWND_LOG_FROM_SS); 648 } 649 } 650} 651 652static void 653sctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net) 654{ 655 int cur_val, i, indx; 656 int old_cwnd = net->cwnd; 657 658 cur_val = net->cwnd >> 10; 659 if (cur_val < sctp_cwnd_adjust[0].cwnd) { 660 /* normal mode */ 661 net->ssthresh = net->cwnd / 2; 662 if (net->ssthresh < (net->mtu * 2)) { 663 net->ssthresh = 2 * net->mtu; 664 } 665 net->cwnd = net->ssthresh; 666 } else { 667 /* drop by the proper amount */ 668 net->ssthresh = net->cwnd - (int)((net->cwnd / 100) * 669 sctp_cwnd_adjust[net->last_hs_used].drop_percent); 670 net->cwnd = net->ssthresh; 671 /* now where are we */ 672 indx = net->last_hs_used; 673 cur_val = net->cwnd >> 10; 674 /* reset where we are in the table */ 675 if (cur_val < sctp_cwnd_adjust[0].cwnd) { 676 /* feel out of hs */ 677 net->last_hs_used = 0; 678 } else { 679 for (i = indx; i >= 1; i--) { 680 if (cur_val > sctp_cwnd_adjust[i - 1].cwnd) { 681 break; 682 } 683 } 684 net->last_hs_used = indx; 685 } 686 } 687 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 688 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_FR); 689 } 690} 691 692void 693sctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb, 694 struct sctp_association *asoc) 695{ 696 struct sctp_nets *net; 697 698 /* 699 * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off == 1) && 700 * (net->fast_retran_loss_recovery == 0))) 701 */ 702 TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 703 if ((asoc->fast_retran_loss_recovery == 0) || 704 (asoc->sctp_cmt_on_off == 1)) { 705 /* out of a RFC2582 Fast recovery window? */ 706 if (net->net_ack > 0) { 707 /* 708 * per section 7.2.3, are there any 709 * destinations that had a fast retransmit 710 * to them. If so what we need to do is 711 * adjust ssthresh and cwnd. 712 */ 713 struct sctp_tmit_chunk *lchk; 714 715 sctp_hs_cwnd_decrease(stcb, net); 716 717 lchk = TAILQ_FIRST(&asoc->send_queue); 718 719 net->partial_bytes_acked = 0; 720 /* Turn on fast recovery window */ 721 asoc->fast_retran_loss_recovery = 1; 722 if (lchk == NULL) { 723 /* Mark end of the window */ 724 asoc->fast_recovery_tsn = asoc->sending_seq - 1; 725 } else { 726 asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 727 } 728 729 /* 730 * CMT fast recovery -- per destination 731 * recovery variable. 732 */ 733 net->fast_retran_loss_recovery = 1; 734 735 if (lchk == NULL) { 736 /* Mark end of the window */ 737 net->fast_recovery_tsn = asoc->sending_seq - 1; 738 } else { 739 net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 740 } 741 742 /* 743 * Disable Nonce Sum Checking and store the 744 * resync tsn 745 */ 746 asoc->nonce_sum_check = 0; 747 asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1; 748 749 sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 750 stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); 751 sctp_timer_start(SCTP_TIMER_TYPE_SEND, 752 stcb->sctp_ep, stcb, net); 753 } 754 } else if (net->net_ack > 0) { 755 /* 756 * Mark a peg that we WOULD have done a cwnd 757 * reduction but RFC2582 prevented this action. 758 */ 759 SCTP_STAT_INCR(sctps_fastretransinrtt); 760 } 761 } 762} 763 764void 765sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, 766 struct sctp_association *asoc, 767 int accum_moved, int reneged_all, int will_exit) 768{ 769 struct sctp_nets *net; 770 771 /******************************/ 772 /* update cwnd and Early FR */ 773 /******************************/ 774 TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 775 776#ifdef JANA_CMT_FAST_RECOVERY 777 /* 778 * CMT fast recovery code. Need to debug. 779 */ 780 if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 781 if (compare_with_wrap(asoc->last_acked_seq, 782 net->fast_recovery_tsn, MAX_TSN) || 783 (asoc->last_acked_seq == net->fast_recovery_tsn) || 784 compare_with_wrap(net->pseudo_cumack, net->fast_recovery_tsn, MAX_TSN) || 785 (net->pseudo_cumack == net->fast_recovery_tsn)) { 786 net->will_exit_fast_recovery = 1; 787 } 788 } 789#endif 790 if (SCTP_BASE_SYSCTL(sctp_early_fr)) { 791 /* 792 * So, first of all do we need to have a Early FR 793 * timer running? 794 */ 795 if ((!TAILQ_EMPTY(&asoc->sent_queue) && 796 (net->ref_count > 1) && 797 (net->flight_size < net->cwnd)) || 798 (reneged_all)) { 799 /* 800 * yes, so in this case stop it if its 801 * running, and then restart it. Reneging 802 * all is a special case where we want to 803 * run the Early FR timer and then force the 804 * last few unacked to be sent, causing us 805 * to illicit a sack with gaps to force out 806 * the others. 807 */ 808 if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 809 SCTP_STAT_INCR(sctps_earlyfrstpidsck2); 810 sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 811 SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); 812 } 813 SCTP_STAT_INCR(sctps_earlyfrstrid); 814 sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); 815 } else { 816 /* No, stop it if its running */ 817 if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 818 SCTP_STAT_INCR(sctps_earlyfrstpidsck3); 819 sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 820 SCTP_FROM_SCTP_INDATA + SCTP_LOC_21); 821 } 822 } 823 } 824 /* if nothing was acked on this destination skip it */ 825 if (net->net_ack == 0) { 826 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 827 sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 828 } 829 continue; 830 } 831 if (net->net_ack2 > 0) { 832 /* 833 * Karn's rule applies to clearing error count, this 834 * is optional. 835 */ 836 net->error_count = 0; 837 if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == 838 SCTP_ADDR_NOT_REACHABLE) { 839 /* addr came good */ 840 net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; 841 net->dest_state |= SCTP_ADDR_REACHABLE; 842 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 843 SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED); 844 /* now was it the primary? if so restore */ 845 if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) { 846 (void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net); 847 } 848 } 849 /* 850 * JRS 5/14/07 - If CMT PF is on and the destination 851 * is in PF state, set the destination to active 852 * state and set the cwnd to one or two MTU's based 853 * on whether PF1 or PF2 is being used. 854 * 855 * Should we stop any running T3 timer here? 856 */ 857 if ((asoc->sctp_cmt_on_off == 1) && 858 (asoc->sctp_cmt_pf > 0) && 859 ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { 860 net->dest_state &= ~SCTP_ADDR_PF; 861 net->cwnd = net->mtu * asoc->sctp_cmt_pf; 862 SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", 863 net, net->cwnd); 864 /* 865 * Since the cwnd value is explicitly set, 866 * skip the code that updates the cwnd 867 * value. 868 */ 869 goto skip_cwnd_update; 870 } 871 } 872#ifdef JANA_CMT_FAST_RECOVERY 873 /* 874 * CMT fast recovery code 875 */ 876 /* 877 * if (sctp_cmt_on_off == 1 && 878 * net->fast_retran_loss_recovery && 879 * net->will_exit_fast_recovery == 0) { @@@ Do something } 880 * else if (sctp_cmt_on_off == 0 && 881 * asoc->fast_retran_loss_recovery && will_exit == 0) { 882 */ 883#endif 884 885 if (asoc->fast_retran_loss_recovery && 886 (will_exit == 0) && 887 (asoc->sctp_cmt_on_off == 0)) { 888 /* 889 * If we are in loss recovery we skip any cwnd 890 * update 891 */ 892 goto skip_cwnd_update; 893 } 894 /* 895 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 896 * moved. 897 */ 898 if (accum_moved || 899 ((asoc->sctp_cmt_on_off == 1) && net->new_pseudo_cumack)) { 900 /* If the cumulative ack moved we can proceed */ 901 if (net->cwnd <= net->ssthresh) { 902 /* We are in slow start */ 903 if (net->flight_size + net->net_ack >= net->cwnd) { 904 905 sctp_hs_cwnd_increase(stcb, net); 906 907 } else { 908 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 909 sctp_log_cwnd(stcb, net, net->net_ack, 910 SCTP_CWND_LOG_NOADV_SS); 911 } 912 } 913 } else { 914 /* We are in congestion avoidance */ 915 net->partial_bytes_acked += net->net_ack; 916 if ((net->flight_size + net->net_ack >= net->cwnd) && 917 (net->partial_bytes_acked >= net->cwnd)) { 918 net->partial_bytes_acked -= net->cwnd; 919 net->cwnd += net->mtu; 920 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 921 sctp_log_cwnd(stcb, net, net->mtu, 922 SCTP_CWND_LOG_FROM_CA); 923 } 924 } else { 925 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 926 sctp_log_cwnd(stcb, net, net->net_ack, 927 SCTP_CWND_LOG_NOADV_CA); 928 } 929 } 930 } 931 } else { 932 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 933 sctp_log_cwnd(stcb, net, net->mtu, 934 SCTP_CWND_LOG_NO_CUMACK); 935 } 936 } 937skip_cwnd_update: 938 /* 939 * NOW, according to Karn's rule do we need to restore the 940 * RTO timer back? Check our net_ack2. If not set then we 941 * have a ambiguity.. i.e. all data ack'd was sent to more 942 * than one place. 943 */ 944 if (net->net_ack2) { 945 /* restore any doubled timers */ 946 net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1; 947 if (net->RTO < stcb->asoc.minrto) { 948 net->RTO = stcb->asoc.minrto; 949 } 950 if (net->RTO > stcb->asoc.maxrto) { 951 net->RTO = stcb->asoc.maxrto; 952 } 953 } 954 } 955} 956 957 958/* 959 * H-TCP congestion control. The algorithm is detailed in: 960 * R.N.Shorten, D.J.Leith: 961 * "H-TCP: TCP for high-speed and long-distance networks" 962 * Proc. PFLDnet, Argonne, 2004. 963 * http://www.hamilton.ie/net/htcp3.pdf 964 */ 965 966 967static int use_rtt_scaling = 1; 968static int use_bandwidth_switch = 1; 969 970static inline int 971between(uint32_t seq1, uint32_t seq2, uint32_t seq3) 972{ 973 return seq3 - seq2 >= seq1 - seq2; 974} 975 976static inline uint32_t 977htcp_cong_time(struct htcp *ca) 978{ 979 return sctp_get_tick_count() - ca->last_cong; 980} 981 982static inline uint32_t 983htcp_ccount(struct htcp *ca) 984{ 985 return htcp_cong_time(ca) / ca->minRTT; 986} 987 988static inline void 989htcp_reset(struct htcp *ca) 990{ 991 ca->undo_last_cong = ca->last_cong; 992 ca->undo_maxRTT = ca->maxRTT; 993 ca->undo_old_maxB = ca->old_maxB; 994 ca->last_cong = sctp_get_tick_count(); 995} 996 997#ifdef SCTP_NOT_USED 998 999static uint32_t 1000htcp_cwnd_undo(struct sctp_tcb *stcb, struct sctp_nets *net) 1001{ 1002 net->htcp_ca.last_cong = net->htcp_ca.undo_last_cong; 1003 net->htcp_ca.maxRTT = net->htcp_ca.undo_maxRTT; 1004 net->htcp_ca.old_maxB = net->htcp_ca.undo_old_maxB; 1005 return max(net->cwnd, ((net->ssthresh / net->mtu << 7) / net->htcp_ca.beta) * net->mtu); 1006} 1007 1008#endif 1009 1010static inline void 1011measure_rtt(struct sctp_tcb *stcb, struct sctp_nets *net) 1012{ 1013 uint32_t srtt = net->lastsa >> 3; 1014 1015 /* keep track of minimum RTT seen so far, minRTT is zero at first */ 1016 if (net->htcp_ca.minRTT > srtt || !net->htcp_ca.minRTT) 1017 net->htcp_ca.minRTT = srtt; 1018 1019 /* max RTT */ 1020 if (net->fast_retran_ip == 0 && net->ssthresh < 0xFFFF && htcp_ccount(&net->htcp_ca) > 3) { 1021 if (net->htcp_ca.maxRTT < net->htcp_ca.minRTT) 1022 net->htcp_ca.maxRTT = net->htcp_ca.minRTT; 1023 if (net->htcp_ca.maxRTT < srtt && srtt <= net->htcp_ca.maxRTT + MSEC_TO_TICKS(20)) 1024 net->htcp_ca.maxRTT = srtt; 1025 } 1026} 1027 1028static void 1029measure_achieved_throughput(struct sctp_tcb *stcb, struct sctp_nets *net) 1030{ 1031 uint32_t now = sctp_get_tick_count(); 1032 1033 if (net->fast_retran_ip == 0) 1034 net->htcp_ca.bytes_acked = net->net_ack; 1035 1036 if (!use_bandwidth_switch) 1037 return; 1038 1039 /* achieved throughput calculations */ 1040 /* JRS - not 100% sure of this statement */ 1041 if (net->fast_retran_ip == 1) { 1042 net->htcp_ca.bytecount = 0; 1043 net->htcp_ca.lasttime = now; 1044 return; 1045 } 1046 net->htcp_ca.bytecount += net->net_ack; 1047 1048 if (net->htcp_ca.bytecount >= net->cwnd - ((net->htcp_ca.alpha >> 7 ? : 1) * net->mtu) 1049 && now - net->htcp_ca.lasttime >= net->htcp_ca.minRTT 1050 && net->htcp_ca.minRTT > 0) { 1051 uint32_t cur_Bi = net->htcp_ca.bytecount / net->mtu * hz / (now - net->htcp_ca.lasttime); 1052 1053 if (htcp_ccount(&net->htcp_ca) <= 3) { 1054 /* just after backoff */ 1055 net->htcp_ca.minB = net->htcp_ca.maxB = net->htcp_ca.Bi = cur_Bi; 1056 } else { 1057 net->htcp_ca.Bi = (3 * net->htcp_ca.Bi + cur_Bi) / 4; 1058 if (net->htcp_ca.Bi > net->htcp_ca.maxB) 1059 net->htcp_ca.maxB = net->htcp_ca.Bi; 1060 if (net->htcp_ca.minB > net->htcp_ca.maxB) 1061 net->htcp_ca.minB = net->htcp_ca.maxB; 1062 } 1063 net->htcp_ca.bytecount = 0; 1064 net->htcp_ca.lasttime = now; 1065 } 1066} 1067 1068static inline void 1069htcp_beta_update(struct htcp *ca, uint32_t minRTT, uint32_t maxRTT) 1070{ 1071 if (use_bandwidth_switch) { 1072 uint32_t maxB = ca->maxB; 1073 uint32_t old_maxB = ca->old_maxB; 1074 1075 ca->old_maxB = ca->maxB; 1076 1077 if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) { 1078 ca->beta = BETA_MIN; 1079 ca->modeswitch = 0; 1080 return; 1081 } 1082 } 1083 if (ca->modeswitch && minRTT > (uint32_t) MSEC_TO_TICKS(10) && maxRTT) { 1084 ca->beta = (minRTT << 7) / maxRTT; 1085 if (ca->beta < BETA_MIN) 1086 ca->beta = BETA_MIN; 1087 else if (ca->beta > BETA_MAX) 1088 ca->beta = BETA_MAX; 1089 } else { 1090 ca->beta = BETA_MIN; 1091 ca->modeswitch = 1; 1092 } 1093} 1094 1095static inline void 1096htcp_alpha_update(struct htcp *ca) 1097{ 1098 uint32_t minRTT = ca->minRTT; 1099 uint32_t factor = 1; 1100 uint32_t diff = htcp_cong_time(ca); 1101 1102 if (diff > (uint32_t) hz) { 1103 diff -= hz; 1104 factor = 1 + (10 * diff + ((diff / 2) * (diff / 2) / hz)) / hz; 1105 } 1106 if (use_rtt_scaling && minRTT) { 1107 uint32_t scale = (hz << 3) / (10 * minRTT); 1108 1109 scale = min(max(scale, 1U << 2), 10U << 3); /* clamping ratio to 1110 * interval [0.5,10]<<3 */ 1111 factor = (factor << 3) / scale; 1112 if (!factor) 1113 factor = 1; 1114 } 1115 ca->alpha = 2 * factor * ((1 << 7) - ca->beta); 1116 if (!ca->alpha) 1117 ca->alpha = ALPHA_BASE; 1118} 1119 1120/* After we have the rtt data to calculate beta, we'd still prefer to wait one 1121 * rtt before we adjust our beta to ensure we are working from a consistent 1122 * data. 1123 * 1124 * This function should be called when we hit a congestion event since only at 1125 * that point do we really have a real sense of maxRTT (the queues en route 1126 * were getting just too full now). 1127 */ 1128static void 1129htcp_param_update(struct sctp_tcb *stcb, struct sctp_nets *net) 1130{ 1131 uint32_t minRTT = net->htcp_ca.minRTT; 1132 uint32_t maxRTT = net->htcp_ca.maxRTT; 1133 1134 htcp_beta_update(&net->htcp_ca, minRTT, maxRTT); 1135 htcp_alpha_update(&net->htcp_ca); 1136 1137 /* 1138 * add slowly fading memory for maxRTT to accommodate routing 1139 * changes etc 1140 */ 1141 if (minRTT > 0 && maxRTT > minRTT) 1142 net->htcp_ca.maxRTT = minRTT + ((maxRTT - minRTT) * 95) / 100; 1143} 1144 1145static uint32_t 1146htcp_recalc_ssthresh(struct sctp_tcb *stcb, struct sctp_nets *net) 1147{ 1148 htcp_param_update(stcb, net); 1149 return max(((net->cwnd / net->mtu * net->htcp_ca.beta) >> 7) * net->mtu, 2U * net->mtu); 1150} 1151 1152static void 1153htcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net) 1154{ 1155 /*- 1156 * How to handle these functions? 1157 * if (!tcp_is_cwnd_limited(sk, in_flight)) RRS - good question. 1158 * return; 1159 */ 1160 if (net->cwnd <= net->ssthresh) { 1161 /* We are in slow start */ 1162 if (net->flight_size + net->net_ack >= net->cwnd) { 1163 if (net->net_ack > (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable))) { 1164 net->cwnd += (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)); 1165 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1166 sctp_log_cwnd(stcb, net, net->mtu, 1167 SCTP_CWND_LOG_FROM_SS); 1168 } 1169 } else { 1170 net->cwnd += net->net_ack; 1171 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1172 sctp_log_cwnd(stcb, net, net->net_ack, 1173 SCTP_CWND_LOG_FROM_SS); 1174 } 1175 } 1176 } else { 1177 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1178 sctp_log_cwnd(stcb, net, net->net_ack, 1179 SCTP_CWND_LOG_NOADV_SS); 1180 } 1181 } 1182 } else { 1183 measure_rtt(stcb, net); 1184 1185 /* 1186 * In dangerous area, increase slowly. In theory this is 1187 * net->cwnd += alpha / net->cwnd 1188 */ 1189 /* What is snd_cwnd_cnt?? */ 1190 if (((net->partial_bytes_acked / net->mtu * net->htcp_ca.alpha) >> 7) * net->mtu >= net->cwnd) { 1191 /*- 1192 * Does SCTP have a cwnd clamp? 1193 * if (net->snd_cwnd < net->snd_cwnd_clamp) - Nope (RRS). 1194 */ 1195 net->cwnd += net->mtu; 1196 net->partial_bytes_acked = 0; 1197 htcp_alpha_update(&net->htcp_ca); 1198 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1199 sctp_log_cwnd(stcb, net, net->mtu, 1200 SCTP_CWND_LOG_FROM_CA); 1201 } 1202 } else { 1203 net->partial_bytes_acked += net->net_ack; 1204 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1205 sctp_log_cwnd(stcb, net, net->net_ack, 1206 SCTP_CWND_LOG_NOADV_CA); 1207 } 1208 } 1209 1210 net->htcp_ca.bytes_acked = net->mtu; 1211 } 1212} 1213 1214#ifdef SCTP_NOT_USED 1215/* Lower bound on congestion window. */ 1216static uint32_t 1217htcp_min_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net) 1218{ 1219 return net->ssthresh; 1220} 1221 1222#endif 1223 1224static void 1225htcp_init(struct sctp_tcb *stcb, struct sctp_nets *net) 1226{ 1227 memset(&net->htcp_ca, 0, sizeof(struct htcp)); 1228 net->htcp_ca.alpha = ALPHA_BASE; 1229 net->htcp_ca.beta = BETA_MIN; 1230 net->htcp_ca.bytes_acked = net->mtu; 1231 net->htcp_ca.last_cong = sctp_get_tick_count(); 1232} 1233 1234void 1235sctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) 1236{ 1237 /* 1238 * We take the max of the burst limit times a MTU or the 1239 * INITIAL_CWND. We then limit this to 4 MTU's of sending. 1240 */ 1241 net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 1242 net->ssthresh = stcb->asoc.peers_rwnd; 1243 htcp_init(stcb, net); 1244 1245 if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { 1246 sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); 1247 } 1248} 1249 1250void 1251sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, 1252 struct sctp_association *asoc, 1253 int accum_moved, int reneged_all, int will_exit) 1254{ 1255 struct sctp_nets *net; 1256 1257 /******************************/ 1258 /* update cwnd and Early FR */ 1259 /******************************/ 1260 TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 1261 1262#ifdef JANA_CMT_FAST_RECOVERY 1263 /* 1264 * CMT fast recovery code. Need to debug. 1265 */ 1266 if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 1267 if (compare_with_wrap(asoc->last_acked_seq, 1268 net->fast_recovery_tsn, MAX_TSN) || 1269 (asoc->last_acked_seq == net->fast_recovery_tsn) || 1270 compare_with_wrap(net->pseudo_cumack, net->fast_recovery_tsn, MAX_TSN) || 1271 (net->pseudo_cumack == net->fast_recovery_tsn)) { 1272 net->will_exit_fast_recovery = 1; 1273 } 1274 } 1275#endif 1276 if (SCTP_BASE_SYSCTL(sctp_early_fr)) { 1277 /* 1278 * So, first of all do we need to have a Early FR 1279 * timer running? 1280 */ 1281 if ((!TAILQ_EMPTY(&asoc->sent_queue) && 1282 (net->ref_count > 1) && 1283 (net->flight_size < net->cwnd)) || 1284 (reneged_all)) { 1285 /* 1286 * yes, so in this case stop it if its 1287 * running, and then restart it. Reneging 1288 * all is a special case where we want to 1289 * run the Early FR timer and then force the 1290 * last few unacked to be sent, causing us 1291 * to illicit a sack with gaps to force out 1292 * the others. 1293 */ 1294 if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 1295 SCTP_STAT_INCR(sctps_earlyfrstpidsck2); 1296 sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 1297 SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); 1298 } 1299 SCTP_STAT_INCR(sctps_earlyfrstrid); 1300 sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); 1301 } else { 1302 /* No, stop it if its running */ 1303 if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { 1304 SCTP_STAT_INCR(sctps_earlyfrstpidsck3); 1305 sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, 1306 SCTP_FROM_SCTP_INDATA + SCTP_LOC_21); 1307 } 1308 } 1309 } 1310 /* if nothing was acked on this destination skip it */ 1311 if (net->net_ack == 0) { 1312 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1313 sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 1314 } 1315 continue; 1316 } 1317 if (net->net_ack2 > 0) { 1318 /* 1319 * Karn's rule applies to clearing error count, this 1320 * is optional. 1321 */ 1322 net->error_count = 0; 1323 if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == 1324 SCTP_ADDR_NOT_REACHABLE) { 1325 /* addr came good */ 1326 net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; 1327 net->dest_state |= SCTP_ADDR_REACHABLE; 1328 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 1329 SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED); 1330 /* now was it the primary? if so restore */ 1331 if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) { 1332 (void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net); 1333 } 1334 } 1335 /* 1336 * JRS 5/14/07 - If CMT PF is on and the destination 1337 * is in PF state, set the destination to active 1338 * state and set the cwnd to one or two MTU's based 1339 * on whether PF1 or PF2 is being used. 1340 * 1341 * Should we stop any running T3 timer here? 1342 */ 1343 if ((asoc->sctp_cmt_on_off == 1) && 1344 (asoc->sctp_cmt_pf > 0) && 1345 ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { 1346 net->dest_state &= ~SCTP_ADDR_PF; 1347 net->cwnd = net->mtu * asoc->sctp_cmt_pf; 1348 SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", 1349 net, net->cwnd); 1350 /* 1351 * Since the cwnd value is explicitly set, 1352 * skip the code that updates the cwnd 1353 * value. 1354 */ 1355 goto skip_cwnd_update; 1356 } 1357 } 1358#ifdef JANA_CMT_FAST_RECOVERY 1359 /* 1360 * CMT fast recovery code 1361 */ 1362 /* 1363 * if (sctp_cmt_on_off == 1 && 1364 * net->fast_retran_loss_recovery && 1365 * net->will_exit_fast_recovery == 0) { @@@ Do something } 1366 * else if (sctp_cmt_on_off == 0 && 1367 * asoc->fast_retran_loss_recovery && will_exit == 0) { 1368 */ 1369#endif 1370 1371 if (asoc->fast_retran_loss_recovery && 1372 will_exit == 0 && 1373 (asoc->sctp_cmt_on_off == 0)) { 1374 /* 1375 * If we are in loss recovery we skip any cwnd 1376 * update 1377 */ 1378 goto skip_cwnd_update; 1379 } 1380 /* 1381 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 1382 * moved. 1383 */ 1384 if (accum_moved || 1385 ((asoc->sctp_cmt_on_off == 1) && net->new_pseudo_cumack)) { 1386 htcp_cong_avoid(stcb, net); 1387 measure_achieved_throughput(stcb, net); 1388 } else { 1389 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1390 sctp_log_cwnd(stcb, net, net->mtu, 1391 SCTP_CWND_LOG_NO_CUMACK); 1392 } 1393 } 1394skip_cwnd_update: 1395 /* 1396 * NOW, according to Karn's rule do we need to restore the 1397 * RTO timer back? Check our net_ack2. If not set then we 1398 * have a ambiguity.. i.e. all data ack'd was sent to more 1399 * than one place. 1400 */ 1401 if (net->net_ack2) { 1402 /* restore any doubled timers */ 1403 net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1; 1404 if (net->RTO < stcb->asoc.minrto) { 1405 net->RTO = stcb->asoc.minrto; 1406 } 1407 if (net->RTO > stcb->asoc.maxrto) { 1408 net->RTO = stcb->asoc.maxrto; 1409 } 1410 } 1411 } 1412} 1413 1414void 1415sctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb, 1416 struct sctp_association *asoc) 1417{ 1418 struct sctp_nets *net; 1419 1420 /* 1421 * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off == 1) && 1422 * (net->fast_retran_loss_recovery == 0))) 1423 */ 1424 TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 1425 if ((asoc->fast_retran_loss_recovery == 0) || 1426 (asoc->sctp_cmt_on_off == 1)) { 1427 /* out of a RFC2582 Fast recovery window? */ 1428 if (net->net_ack > 0) { 1429 /* 1430 * per section 7.2.3, are there any 1431 * destinations that had a fast retransmit 1432 * to them. If so what we need to do is 1433 * adjust ssthresh and cwnd. 1434 */ 1435 struct sctp_tmit_chunk *lchk; 1436 int old_cwnd = net->cwnd; 1437 1438 /* JRS - reset as if state were changed */ 1439 htcp_reset(&net->htcp_ca); 1440 net->ssthresh = htcp_recalc_ssthresh(stcb, net); 1441 net->cwnd = net->ssthresh; 1442 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1443 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 1444 SCTP_CWND_LOG_FROM_FR); 1445 } 1446 lchk = TAILQ_FIRST(&asoc->send_queue); 1447 1448 net->partial_bytes_acked = 0; 1449 /* Turn on fast recovery window */ 1450 asoc->fast_retran_loss_recovery = 1; 1451 if (lchk == NULL) { 1452 /* Mark end of the window */ 1453 asoc->fast_recovery_tsn = asoc->sending_seq - 1; 1454 } else { 1455 asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 1456 } 1457 1458 /* 1459 * CMT fast recovery -- per destination 1460 * recovery variable. 1461 */ 1462 net->fast_retran_loss_recovery = 1; 1463 1464 if (lchk == NULL) { 1465 /* Mark end of the window */ 1466 net->fast_recovery_tsn = asoc->sending_seq - 1; 1467 } else { 1468 net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 1469 } 1470 1471 /* 1472 * Disable Nonce Sum Checking and store the 1473 * resync tsn 1474 */ 1475 asoc->nonce_sum_check = 0; 1476 asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1; 1477 1478 sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 1479 stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); 1480 sctp_timer_start(SCTP_TIMER_TYPE_SEND, 1481 stcb->sctp_ep, stcb, net); 1482 } 1483 } else if (net->net_ack > 0) { 1484 /* 1485 * Mark a peg that we WOULD have done a cwnd 1486 * reduction but RFC2582 prevented this action. 1487 */ 1488 SCTP_STAT_INCR(sctps_fastretransinrtt); 1489 } 1490 } 1491} 1492 1493void 1494sctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb, 1495 struct sctp_nets *net) 1496{ 1497 int old_cwnd = net->cwnd; 1498 1499 /* JRS - reset as if the state were being changed to timeout */ 1500 htcp_reset(&net->htcp_ca); 1501 net->ssthresh = htcp_recalc_ssthresh(stcb, net); 1502 net->cwnd = net->mtu; 1503 net->partial_bytes_acked = 0; 1504 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1505 sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 1506 } 1507} 1508 1509void 1510sctp_htcp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp, 1511 struct sctp_tcb *stcb, struct sctp_nets *net) 1512{ 1513 int old_cwnd; 1514 1515 old_cwnd = net->cwnd; 1516 1517 sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED); 1518 net->htcp_ca.last_cong = sctp_get_tick_count(); 1519 /* 1520 * make a small adjustment to cwnd and force to CA. 1521 */ 1522 if (net->cwnd > net->mtu) 1523 /* drop down one MTU after sending */ 1524 net->cwnd -= net->mtu; 1525 if (net->cwnd < net->ssthresh) 1526 /* still in SS move to CA */ 1527 net->ssthresh = net->cwnd - 1; 1528 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1529 sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR); 1530 } 1531} 1532 1533void 1534sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, 1535 struct sctp_nets *net) 1536{ 1537 int old_cwnd; 1538 1539 old_cwnd = net->cwnd; 1540 1541 /* JRS - reset hctp as if state changed */ 1542 htcp_reset(&net->htcp_ca); 1543 SCTP_STAT_INCR(sctps_ecnereducedcwnd); 1544 net->ssthresh = htcp_recalc_ssthresh(stcb, net); 1545 if (net->ssthresh < net->mtu) { 1546 net->ssthresh = net->mtu; 1547 /* here back off the timer as well, to slow us down */ 1548 net->RTO <<= 1; 1549 } 1550 net->cwnd = net->ssthresh; 1551 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1552 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 1553 } 1554} 1555