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