1 /*- 2 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 3 * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. 4 * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * a) Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * b) Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the distribution. 15 * 16 * c) Neither the name of Cisco Systems, Inc. nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 * THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <netinet/sctp_os.h> 37 #include <netinet/sctp_var.h> 38 #include <netinet/sctp_sysctl.h> 39 #include <netinet/sctp_pcb.h> 40 #include <netinet/sctp_header.h> 41 #include <netinet/sctputil.h> 42 #include <netinet/sctp_output.h> 43 #include <netinet/sctp_input.h> 44 #include <netinet/sctp_indata.h> 45 #include <netinet/sctp_uio.h> 46 #include <netinet/sctp_timer.h> 47 #include <netinet/sctp_auth.h> 48 #include <netinet/sctp_asconf.h> 49 #include <netinet/sctp_dtrace_declare.h> 50 51 #define SHIFT_MPTCP_MULTI_N 40 52 #define SHIFT_MPTCP_MULTI_Z 16 53 #define SHIFT_MPTCP_MULTI 8 54 55 static void 56 sctp_enforce_cwnd_limit(struct sctp_association *assoc, struct sctp_nets *net) 57 { 58 if ((assoc->max_cwnd > 0) && 59 (net->cwnd > assoc->max_cwnd) && 60 (net->cwnd > (net->mtu - sizeof(struct sctphdr)))) { 61 net->cwnd = assoc->max_cwnd; 62 if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) { 63 net->cwnd = net->mtu - sizeof(struct sctphdr); 64 } 65 } 66 } 67 68 static void 69 sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) 70 { 71 struct sctp_association *assoc; 72 uint32_t cwnd_in_mtu; 73 74 assoc = &stcb->asoc; 75 cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd); 76 if (cwnd_in_mtu == 0) { 77 /* Using 0 means that the value of RFC 4960 is used. */ 78 net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 79 } else { 80 /* 81 * We take the minimum of the burst limit and the initial 82 * congestion window. 83 */ 84 if ((assoc->max_burst > 0) && (cwnd_in_mtu > assoc->max_burst)) 85 cwnd_in_mtu = assoc->max_burst; 86 net->cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu; 87 } 88 if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) || 89 (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2)) { 90 /* In case of resource pooling initialize appropriately */ 91 net->cwnd /= assoc->numnets; 92 if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) { 93 net->cwnd = net->mtu - sizeof(struct sctphdr); 94 } 95 } 96 sctp_enforce_cwnd_limit(assoc, net); 97 net->ssthresh = assoc->peers_rwnd; 98 SDT_PROBE5(sctp, cwnd, net, init, 99 stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, 100 0, net->cwnd); 101 if (SCTP_BASE_SYSCTL(sctp_logging_level) & 102 (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { 103 sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); 104 } 105 } 106 107 static void 108 sctp_cwnd_update_after_fr(struct sctp_tcb *stcb, 109 struct sctp_association *asoc) 110 { 111 struct sctp_nets *net; 112 uint32_t t_ssthresh, t_cwnd; 113 uint64_t t_ucwnd_sbw; 114 115 /* MT FIXME: Don't compute this over and over again */ 116 t_ssthresh = 0; 117 t_cwnd = 0; 118 t_ucwnd_sbw = 0; 119 if ((asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) || 120 (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2)) { 121 TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 122 t_ssthresh += net->ssthresh; 123 t_cwnd += net->cwnd; 124 if (net->lastsa > 0) { 125 t_ucwnd_sbw += (uint64_t) net->cwnd / (uint64_t) net->lastsa; 126 } 127 } 128 if (t_ucwnd_sbw == 0) { 129 t_ucwnd_sbw = 1; 130 } 131 } 132 /*- 133 * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) && 134 * (net->fast_retran_loss_recovery == 0))) 135 */ 136 TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 137 if ((asoc->fast_retran_loss_recovery == 0) || 138 (asoc->sctp_cmt_on_off > 0)) { 139 /* out of a RFC2582 Fast recovery window? */ 140 if (net->net_ack > 0) { 141 /* 142 * per section 7.2.3, are there any 143 * destinations that had a fast retransmit 144 * to them. If so what we need to do is 145 * adjust ssthresh and cwnd. 146 */ 147 struct sctp_tmit_chunk *lchk; 148 int old_cwnd = net->cwnd; 149 150 if ((asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) || 151 (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2)) { 152 if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) { 153 net->ssthresh = (uint32_t) (((uint64_t) 4 * 154 (uint64_t) net->mtu * 155 (uint64_t) net->ssthresh) / 156 (uint64_t) t_ssthresh); 157 158 } 159 if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2) { 160 uint32_t srtt; 161 162 srtt = net->lastsa; 163 /* 164 * lastsa>>3; we don't need 165 * to devide ... 166 */ 167 if (srtt == 0) { 168 srtt = 1; 169 } 170 /* 171 * Short Version => Equal to 172 * Contel Version MBe 173 */ 174 net->ssthresh = (uint32_t) (((uint64_t) 4 * 175 (uint64_t) net->mtu * 176 (uint64_t) net->cwnd) / 177 ((uint64_t) srtt * 178 t_ucwnd_sbw)); 179 /* INCREASE FACTOR */ ; 180 } 181 if ((net->cwnd > t_cwnd / 2) && 182 (net->ssthresh < net->cwnd - t_cwnd / 2)) { 183 net->ssthresh = net->cwnd - t_cwnd / 2; 184 } 185 if (net->ssthresh < net->mtu) { 186 net->ssthresh = net->mtu; 187 } 188 } else { 189 net->ssthresh = net->cwnd / 2; 190 if (net->ssthresh < (net->mtu * 2)) { 191 net->ssthresh = 2 * net->mtu; 192 } 193 } 194 net->cwnd = net->ssthresh; 195 sctp_enforce_cwnd_limit(asoc, net); 196 SDT_PROBE5(sctp, cwnd, net, fr, 197 stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, 198 old_cwnd, net->cwnd); 199 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 200 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 201 SCTP_CWND_LOG_FROM_FR); 202 } 203 lchk = TAILQ_FIRST(&asoc->send_queue); 204 205 net->partial_bytes_acked = 0; 206 /* Turn on fast recovery window */ 207 asoc->fast_retran_loss_recovery = 1; 208 if (lchk == NULL) { 209 /* Mark end of the window */ 210 asoc->fast_recovery_tsn = asoc->sending_seq - 1; 211 } else { 212 asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 213 } 214 215 /* 216 * CMT fast recovery -- per destination 217 * recovery variable. 218 */ 219 net->fast_retran_loss_recovery = 1; 220 221 if (lchk == NULL) { 222 /* Mark end of the window */ 223 net->fast_recovery_tsn = asoc->sending_seq - 1; 224 } else { 225 net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 226 } 227 228 sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 229 stcb->sctp_ep, stcb, net, 230 SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_1); 231 sctp_timer_start(SCTP_TIMER_TYPE_SEND, 232 stcb->sctp_ep, stcb, net); 233 } 234 } else if (net->net_ack > 0) { 235 /* 236 * Mark a peg that we WOULD have done a cwnd 237 * reduction but RFC2582 prevented this action. 238 */ 239 SCTP_STAT_INCR(sctps_fastretransinrtt); 240 } 241 } 242 } 243 244 /* Defines for instantaneous bw decisions */ 245 #define SCTP_INST_LOOSING 1 /* Losing to other flows */ 246 #define SCTP_INST_NEUTRAL 2 /* Neutral, no indication */ 247 #define SCTP_INST_GAINING 3 /* Gaining, step down possible */ 248 249 250 static int 251 cc_bw_same(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, 252 uint64_t rtt_offset, uint64_t vtag, uint8_t inst_ind) 253 { 254 uint64_t oth, probepoint; 255 256 probepoint = (((uint64_t) net->cwnd) << 32); 257 if (net->rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) { 258 /* 259 * rtt increased we don't update bw.. so we don't update the 260 * rtt either. 261 */ 262 /* Probe point 5 */ 263 probepoint |= ((5 << 16) | 1); 264 SDT_PROBE5(sctp, cwnd, net, rttvar, 265 vtag, 266 ((net->cc_mod.rtcc.lbw << 32) | nbw), 267 ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 268 net->flight_size, 269 probepoint); 270 if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) { 271 if (net->cc_mod.rtcc.last_step_state == 5) 272 net->cc_mod.rtcc.step_cnt++; 273 else 274 net->cc_mod.rtcc.step_cnt = 1; 275 net->cc_mod.rtcc.last_step_state = 5; 276 if ((net->cc_mod.rtcc.step_cnt == net->cc_mod.rtcc.steady_step) || 277 ((net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step) && 278 ((net->cc_mod.rtcc.step_cnt % net->cc_mod.rtcc.steady_step) == 0))) { 279 /* Try a step down */ 280 oth = net->cc_mod.rtcc.vol_reduce; 281 oth <<= 16; 282 oth |= net->cc_mod.rtcc.step_cnt; 283 oth <<= 16; 284 oth |= net->cc_mod.rtcc.last_step_state; 285 SDT_PROBE5(sctp, cwnd, net, rttstep, 286 vtag, 287 ((net->cc_mod.rtcc.lbw << 32) | nbw), 288 ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 289 oth, 290 probepoint); 291 if (net->cwnd > (4 * net->mtu)) { 292 net->cwnd -= net->mtu; 293 net->cc_mod.rtcc.vol_reduce++; 294 } else { 295 net->cc_mod.rtcc.step_cnt = 0; 296 } 297 } 298 } 299 return (1); 300 } 301 if (net->rtt < net->cc_mod.rtcc.lbw_rtt - rtt_offset) { 302 /* 303 * rtt decreased, there could be more room. we update both 304 * the bw and the rtt here to lock this in as a good step 305 * down. 306 */ 307 /* Probe point 6 */ 308 probepoint |= ((6 << 16) | 0); 309 SDT_PROBE5(sctp, cwnd, net, rttvar, 310 vtag, 311 ((net->cc_mod.rtcc.lbw << 32) | nbw), 312 ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 313 net->flight_size, 314 probepoint); 315 if (net->cc_mod.rtcc.steady_step) { 316 oth = net->cc_mod.rtcc.vol_reduce; 317 oth <<= 16; 318 oth |= net->cc_mod.rtcc.step_cnt; 319 oth <<= 16; 320 oth |= net->cc_mod.rtcc.last_step_state; 321 SDT_PROBE5(sctp, cwnd, net, rttstep, 322 vtag, 323 ((net->cc_mod.rtcc.lbw << 32) | nbw), 324 ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 325 oth, 326 probepoint); 327 if ((net->cc_mod.rtcc.last_step_state == 5) && 328 (net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step)) { 329 /* Step down worked */ 330 net->cc_mod.rtcc.step_cnt = 0; 331 return (1); 332 } else { 333 net->cc_mod.rtcc.last_step_state = 6; 334 net->cc_mod.rtcc.step_cnt = 0; 335 } 336 } 337 net->cc_mod.rtcc.lbw = nbw; 338 net->cc_mod.rtcc.lbw_rtt = net->rtt; 339 net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd; 340 if (inst_ind == SCTP_INST_GAINING) 341 return (1); 342 else if (inst_ind == SCTP_INST_NEUTRAL) 343 return (1); 344 else 345 return (0); 346 } 347 /* 348 * Ok bw and rtt remained the same .. no update to any 349 */ 350 /* Probe point 7 */ 351 probepoint |= ((7 << 16) | net->cc_mod.rtcc.ret_from_eq); 352 SDT_PROBE5(sctp, cwnd, net, rttvar, 353 vtag, 354 ((net->cc_mod.rtcc.lbw << 32) | nbw), 355 ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 356 net->flight_size, 357 probepoint); 358 if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) { 359 if (net->cc_mod.rtcc.last_step_state == 5) 360 net->cc_mod.rtcc.step_cnt++; 361 else 362 net->cc_mod.rtcc.step_cnt = 1; 363 net->cc_mod.rtcc.last_step_state = 5; 364 if ((net->cc_mod.rtcc.step_cnt == net->cc_mod.rtcc.steady_step) || 365 ((net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step) && 366 ((net->cc_mod.rtcc.step_cnt % net->cc_mod.rtcc.steady_step) == 0))) { 367 /* Try a step down */ 368 if (net->cwnd > (4 * net->mtu)) { 369 net->cwnd -= net->mtu; 370 net->cc_mod.rtcc.vol_reduce++; 371 return (1); 372 } else { 373 net->cc_mod.rtcc.step_cnt = 0; 374 } 375 } 376 } 377 if (inst_ind == SCTP_INST_GAINING) 378 return (1); 379 else if (inst_ind == SCTP_INST_NEUTRAL) 380 return (1); 381 else 382 return ((int)net->cc_mod.rtcc.ret_from_eq); 383 } 384 385 static int 386 cc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t rtt_offset, 387 uint64_t vtag, uint8_t inst_ind) 388 { 389 uint64_t oth, probepoint; 390 391 /* Bandwidth decreased. */ 392 probepoint = (((uint64_t) net->cwnd) << 32); 393 if (net->rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) { 394 /* rtt increased */ 395 /* Did we add more */ 396 if ((net->cwnd > net->cc_mod.rtcc.cwnd_at_bw_set) && 397 (inst_ind != SCTP_INST_LOOSING)) { 398 /* We caused it maybe.. back off? */ 399 /* PROBE POINT 1 */ 400 probepoint |= ((1 << 16) | 1); 401 SDT_PROBE5(sctp, cwnd, net, rttvar, 402 vtag, 403 ((net->cc_mod.rtcc.lbw << 32) | nbw), 404 ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 405 net->flight_size, 406 probepoint); 407 if (net->cc_mod.rtcc.ret_from_eq) { 408 /* 409 * Switch over to CA if we are less 410 * aggressive 411 */ 412 net->ssthresh = net->cwnd - 1; 413 net->partial_bytes_acked = 0; 414 } 415 return (1); 416 } 417 /* Probe point 2 */ 418 probepoint |= ((2 << 16) | 0); 419 SDT_PROBE5(sctp, cwnd, net, rttvar, 420 vtag, 421 ((net->cc_mod.rtcc.lbw << 32) | nbw), 422 ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 423 net->flight_size, 424 probepoint); 425 /* Someone else - fight for more? */ 426 if (net->cc_mod.rtcc.steady_step) { 427 oth = net->cc_mod.rtcc.vol_reduce; 428 oth <<= 16; 429 oth |= net->cc_mod.rtcc.step_cnt; 430 oth <<= 16; 431 oth |= net->cc_mod.rtcc.last_step_state; 432 SDT_PROBE5(sctp, cwnd, net, rttstep, 433 vtag, 434 ((net->cc_mod.rtcc.lbw << 32) | nbw), 435 ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 436 oth, 437 probepoint); 438 /* 439 * Did we voluntarily give up some? if so take one 440 * back please 441 */ 442 if ((net->cc_mod.rtcc.vol_reduce) && 443 (inst_ind != SCTP_INST_GAINING)) { 444 net->cwnd += net->mtu; 445 sctp_enforce_cwnd_limit(&stcb->asoc, net); 446 net->cc_mod.rtcc.vol_reduce--; 447 } 448 net->cc_mod.rtcc.last_step_state = 2; 449 net->cc_mod.rtcc.step_cnt = 0; 450 } 451 goto out_decision; 452 } else if (net->rtt < net->cc_mod.rtcc.lbw_rtt - rtt_offset) { 453 /* bw & rtt decreased */ 454 /* Probe point 3 */ 455 probepoint |= ((3 << 16) | 0); 456 SDT_PROBE5(sctp, cwnd, net, rttvar, 457 vtag, 458 ((net->cc_mod.rtcc.lbw << 32) | nbw), 459 ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 460 net->flight_size, 461 probepoint); 462 if (net->cc_mod.rtcc.steady_step) { 463 oth = net->cc_mod.rtcc.vol_reduce; 464 oth <<= 16; 465 oth |= net->cc_mod.rtcc.step_cnt; 466 oth <<= 16; 467 oth |= net->cc_mod.rtcc.last_step_state; 468 SDT_PROBE5(sctp, cwnd, net, rttstep, 469 vtag, 470 ((net->cc_mod.rtcc.lbw << 32) | nbw), 471 ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 472 oth, 473 probepoint); 474 if ((net->cc_mod.rtcc.vol_reduce) && 475 (inst_ind != SCTP_INST_GAINING)) { 476 net->cwnd += net->mtu; 477 sctp_enforce_cwnd_limit(&stcb->asoc, net); 478 net->cc_mod.rtcc.vol_reduce--; 479 } 480 net->cc_mod.rtcc.last_step_state = 3; 481 net->cc_mod.rtcc.step_cnt = 0; 482 } 483 goto out_decision; 484 } 485 /* The bw decreased but rtt stayed the same */ 486 /* Probe point 4 */ 487 probepoint |= ((4 << 16) | 0); 488 SDT_PROBE5(sctp, cwnd, net, rttvar, 489 vtag, 490 ((net->cc_mod.rtcc.lbw << 32) | nbw), 491 ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 492 net->flight_size, 493 probepoint); 494 if (net->cc_mod.rtcc.steady_step) { 495 oth = net->cc_mod.rtcc.vol_reduce; 496 oth <<= 16; 497 oth |= net->cc_mod.rtcc.step_cnt; 498 oth <<= 16; 499 oth |= net->cc_mod.rtcc.last_step_state; 500 SDT_PROBE5(sctp, cwnd, net, rttstep, 501 vtag, 502 ((net->cc_mod.rtcc.lbw << 32) | nbw), 503 ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 504 oth, 505 probepoint); 506 if ((net->cc_mod.rtcc.vol_reduce) && 507 (inst_ind != SCTP_INST_GAINING)) { 508 net->cwnd += net->mtu; 509 sctp_enforce_cwnd_limit(&stcb->asoc, net); 510 net->cc_mod.rtcc.vol_reduce--; 511 } 512 net->cc_mod.rtcc.last_step_state = 4; 513 net->cc_mod.rtcc.step_cnt = 0; 514 } 515 out_decision: 516 net->cc_mod.rtcc.lbw = nbw; 517 net->cc_mod.rtcc.lbw_rtt = net->rtt; 518 net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd; 519 if (inst_ind == SCTP_INST_GAINING) { 520 return (1); 521 } else { 522 return (0); 523 } 524 } 525 526 static int 527 cc_bw_increase(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t vtag) 528 { 529 uint64_t oth, probepoint; 530 531 /* 532 * BW increased, so update and return 0, since all actions in our 533 * table say to do the normal CC update. Note that we pay no 534 * attention to the inst_ind since our overall sum is increasing. 535 */ 536 /* PROBE POINT 0 */ 537 probepoint = (((uint64_t) net->cwnd) << 32); 538 SDT_PROBE5(sctp, cwnd, net, rttvar, 539 vtag, 540 ((net->cc_mod.rtcc.lbw << 32) | nbw), 541 ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 542 net->flight_size, 543 probepoint); 544 if (net->cc_mod.rtcc.steady_step) { 545 oth = net->cc_mod.rtcc.vol_reduce; 546 oth <<= 16; 547 oth |= net->cc_mod.rtcc.step_cnt; 548 oth <<= 16; 549 oth |= net->cc_mod.rtcc.last_step_state; 550 SDT_PROBE5(sctp, cwnd, net, rttstep, 551 vtag, 552 ((net->cc_mod.rtcc.lbw << 32) | nbw), 553 ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 554 oth, 555 probepoint); 556 net->cc_mod.rtcc.last_step_state = 0; 557 net->cc_mod.rtcc.step_cnt = 0; 558 net->cc_mod.rtcc.vol_reduce = 0; 559 } 560 net->cc_mod.rtcc.lbw = nbw; 561 net->cc_mod.rtcc.lbw_rtt = net->rtt; 562 net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd; 563 return (0); 564 } 565 566 /* RTCC Algorithm to limit growth of cwnd, return 567 * true if you want to NOT allow cwnd growth 568 */ 569 static int 570 cc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw) 571 { 572 uint64_t bw_offset, rtt_offset; 573 uint64_t probepoint, rtt, vtag; 574 uint64_t bytes_for_this_rtt, inst_bw; 575 uint64_t div, inst_off; 576 int bw_shift; 577 uint8_t inst_ind; 578 int ret; 579 580 /*- 581 * Here we need to see if we want 582 * to limit cwnd growth due to increase 583 * in overall rtt but no increase in bw. 584 * We use the following table to figure 585 * out what we should do. When we return 586 * 0, cc update goes on as planned. If we 587 * return 1, then no cc update happens and cwnd 588 * stays where it is at. 589 * ---------------------------------- 590 * BW | RTT | Action 591 * ********************************* 592 * INC | INC | return 0 593 * ---------------------------------- 594 * INC | SAME | return 0 595 * ---------------------------------- 596 * INC | DECR | return 0 597 * ---------------------------------- 598 * SAME | INC | return 1 599 * ---------------------------------- 600 * SAME | SAME | return 1 601 * ---------------------------------- 602 * SAME | DECR | return 0 603 * ---------------------------------- 604 * DECR | INC | return 0 or 1 based on if we caused. 605 * ---------------------------------- 606 * DECR | SAME | return 0 607 * ---------------------------------- 608 * DECR | DECR | return 0 609 * ---------------------------------- 610 * 611 * We are a bit fuzz on what an increase or 612 * decrease is. For BW it is the same if 613 * it did not change within 1/64th. For 614 * RTT it stayed the same if it did not 615 * change within 1/32nd 616 */ 617 bw_shift = SCTP_BASE_SYSCTL(sctp_rttvar_bw); 618 rtt = stcb->asoc.my_vtag; 619 vtag = (rtt << 32) | (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) | (stcb->rport); 620 probepoint = (((uint64_t) net->cwnd) << 32); 621 rtt = net->rtt; 622 if (net->cc_mod.rtcc.rtt_set_this_sack) { 623 net->cc_mod.rtcc.rtt_set_this_sack = 0; 624 bytes_for_this_rtt = net->cc_mod.rtcc.bw_bytes - net->cc_mod.rtcc.bw_bytes_at_last_rttc; 625 net->cc_mod.rtcc.bw_bytes_at_last_rttc = net->cc_mod.rtcc.bw_bytes; 626 if (net->rtt) { 627 div = net->rtt / 1000; 628 if (div) { 629 inst_bw = bytes_for_this_rtt / div; 630 inst_off = inst_bw >> bw_shift; 631 if (inst_bw > nbw) 632 inst_ind = SCTP_INST_GAINING; 633 else if ((inst_bw + inst_off) < nbw) 634 inst_ind = SCTP_INST_LOOSING; 635 else 636 inst_ind = SCTP_INST_NEUTRAL; 637 probepoint |= ((0xb << 16) | inst_ind); 638 } else { 639 inst_ind = net->cc_mod.rtcc.last_inst_ind; 640 inst_bw = bytes_for_this_rtt / (uint64_t) (net->rtt); 641 /* Can't determine do not change */ 642 probepoint |= ((0xc << 16) | inst_ind); 643 } 644 } else { 645 inst_ind = net->cc_mod.rtcc.last_inst_ind; 646 inst_bw = bytes_for_this_rtt; 647 /* Can't determine do not change */ 648 probepoint |= ((0xd << 16) | inst_ind); 649 } 650 SDT_PROBE5(sctp, cwnd, net, rttvar, 651 vtag, 652 ((nbw << 32) | inst_bw), 653 ((net->cc_mod.rtcc.lbw_rtt << 32) | rtt), 654 net->flight_size, 655 probepoint); 656 } else { 657 /* No rtt measurement, use last one */ 658 inst_ind = net->cc_mod.rtcc.last_inst_ind; 659 } 660 bw_offset = net->cc_mod.rtcc.lbw >> bw_shift; 661 if (nbw > net->cc_mod.rtcc.lbw + bw_offset) { 662 ret = cc_bw_increase(stcb, net, nbw, vtag); 663 goto out; 664 } 665 rtt_offset = net->cc_mod.rtcc.lbw_rtt >> SCTP_BASE_SYSCTL(sctp_rttvar_rtt); 666 if (nbw < net->cc_mod.rtcc.lbw - bw_offset) { 667 ret = cc_bw_decrease(stcb, net, nbw, rtt_offset, vtag, inst_ind); 668 goto out; 669 } 670 /* 671 * If we reach here then we are in a situation where the bw stayed 672 * the same. 673 */ 674 ret = cc_bw_same(stcb, net, nbw, rtt_offset, vtag, inst_ind); 675 out: 676 net->cc_mod.rtcc.last_inst_ind = inst_ind; 677 return (ret); 678 } 679 680 static void 681 sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, 682 struct sctp_association *asoc, 683 int accum_moved, int reneged_all SCTP_UNUSED, int will_exit, int use_rtcc) 684 { 685 struct sctp_nets *net; 686 int old_cwnd; 687 uint32_t t_ssthresh, t_cwnd, incr; 688 uint64_t t_ucwnd_sbw; 689 uint64_t t_path_mptcp; 690 uint64_t mptcp_like_alpha; 691 uint32_t srtt; 692 uint64_t max_path; 693 694 /* MT FIXME: Don't compute this over and over again */ 695 t_ssthresh = 0; 696 t_cwnd = 0; 697 t_ucwnd_sbw = 0; 698 t_path_mptcp = 0; 699 mptcp_like_alpha = 1; 700 if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) || 701 (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2) || 702 (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_MPTCP)) { 703 max_path = 0; 704 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 705 t_ssthresh += net->ssthresh; 706 t_cwnd += net->cwnd; 707 /* lastsa>>3; we don't need to devide ... */ 708 srtt = net->lastsa; 709 if (srtt > 0) { 710 uint64_t tmp; 711 712 t_ucwnd_sbw += (uint64_t) net->cwnd / (uint64_t) srtt; 713 t_path_mptcp += (((uint64_t) net->cwnd) << SHIFT_MPTCP_MULTI_Z) / 714 (((uint64_t) net->mtu) * (uint64_t) srtt); 715 tmp = (((uint64_t) net->cwnd) << SHIFT_MPTCP_MULTI_N) / 716 ((uint64_t) net->mtu * (uint64_t) (srtt * srtt)); 717 if (tmp > max_path) { 718 max_path = tmp; 719 } 720 } 721 } 722 if (t_path_mptcp > 0) { 723 mptcp_like_alpha = max_path / (t_path_mptcp * t_path_mptcp); 724 } else { 725 mptcp_like_alpha = 1; 726 } 727 } 728 if (t_ssthresh == 0) { 729 t_ssthresh = 1; 730 } 731 if (t_ucwnd_sbw == 0) { 732 t_ucwnd_sbw = 1; 733 } 734 /******************************/ 735 /* update cwnd and Early FR */ 736 /******************************/ 737 TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 738 739 #ifdef JANA_CMT_FAST_RECOVERY 740 /* 741 * CMT fast recovery code. Need to debug. 742 */ 743 if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 744 if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) || 745 SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) { 746 net->will_exit_fast_recovery = 1; 747 } 748 } 749 #endif 750 /* if nothing was acked on this destination skip it */ 751 if (net->net_ack == 0) { 752 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 753 sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 754 } 755 continue; 756 } 757 #ifdef JANA_CMT_FAST_RECOVERY 758 /* 759 * CMT fast recovery code 760 */ 761 /* 762 * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery 763 * && net->will_exit_fast_recovery == 0) { @@@ Do something 764 * } else if (sctp_cmt_on_off == 0 && 765 * asoc->fast_retran_loss_recovery && will_exit == 0) { 766 */ 767 #endif 768 769 if (asoc->fast_retran_loss_recovery && 770 (will_exit == 0) && 771 (asoc->sctp_cmt_on_off == 0)) { 772 /* 773 * If we are in loss recovery we skip any cwnd 774 * update 775 */ 776 return; 777 } 778 /* 779 * Did any measurements go on for this network? 780 */ 781 if (use_rtcc && (net->cc_mod.rtcc.tls_needs_set > 0)) { 782 uint64_t nbw; 783 784 /* 785 * At this point our bw_bytes has been updated by 786 * incoming sack information. 787 * 788 * But our bw may not yet be set. 789 * 790 */ 791 if ((net->cc_mod.rtcc.new_tot_time / 1000) > 0) { 792 nbw = net->cc_mod.rtcc.bw_bytes / (net->cc_mod.rtcc.new_tot_time / 1000); 793 } else { 794 nbw = net->cc_mod.rtcc.bw_bytes; 795 } 796 if (net->cc_mod.rtcc.lbw) { 797 if (cc_bw_limit(stcb, net, nbw)) { 798 /* Hold here, no update */ 799 continue; 800 } 801 } else { 802 uint64_t vtag, probepoint; 803 804 probepoint = (((uint64_t) net->cwnd) << 32); 805 probepoint |= ((0xa << 16) | 0); 806 vtag = (net->rtt << 32) | 807 (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) | 808 (stcb->rport); 809 810 SDT_PROBE5(sctp, cwnd, net, rttvar, 811 vtag, 812 nbw, 813 ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 814 net->flight_size, 815 probepoint); 816 net->cc_mod.rtcc.lbw = nbw; 817 net->cc_mod.rtcc.lbw_rtt = net->rtt; 818 if (net->cc_mod.rtcc.rtt_set_this_sack) { 819 net->cc_mod.rtcc.rtt_set_this_sack = 0; 820 net->cc_mod.rtcc.bw_bytes_at_last_rttc = net->cc_mod.rtcc.bw_bytes; 821 } 822 } 823 } 824 /* 825 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 826 * moved. 827 */ 828 if (accum_moved || 829 ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) { 830 /* If the cumulative ack moved we can proceed */ 831 if (net->cwnd <= net->ssthresh) { 832 /* We are in slow start */ 833 if (net->flight_size + net->net_ack >= net->cwnd) { 834 uint32_t limit; 835 836 old_cwnd = net->cwnd; 837 switch (asoc->sctp_cmt_on_off) { 838 case SCTP_CMT_RPV1: 839 limit = (uint32_t) (((uint64_t) net->mtu * 840 (uint64_t) SCTP_BASE_SYSCTL(sctp_L2_abc_variable) * 841 (uint64_t) net->ssthresh) / 842 (uint64_t) t_ssthresh); 843 incr = (uint32_t) (((uint64_t) net->net_ack * 844 (uint64_t) net->ssthresh) / 845 (uint64_t) t_ssthresh); 846 if (incr > limit) { 847 incr = limit; 848 } 849 if (incr == 0) { 850 incr = 1; 851 } 852 break; 853 case SCTP_CMT_RPV2: 854 /* 855 * lastsa>>3; we don't need 856 * to divide ... 857 */ 858 srtt = net->lastsa; 859 if (srtt == 0) { 860 srtt = 1; 861 } 862 limit = (uint32_t) (((uint64_t) net->mtu * 863 (uint64_t) SCTP_BASE_SYSCTL(sctp_L2_abc_variable) * 864 (uint64_t) net->cwnd) / 865 ((uint64_t) srtt * t_ucwnd_sbw)); 866 /* INCREASE FACTOR */ 867 incr = (uint32_t) (((uint64_t) net->net_ack * 868 (uint64_t) net->cwnd) / 869 ((uint64_t) srtt * t_ucwnd_sbw)); 870 /* INCREASE FACTOR */ 871 if (incr > limit) { 872 incr = limit; 873 } 874 if (incr == 0) { 875 incr = 1; 876 } 877 break; 878 case SCTP_CMT_MPTCP: 879 limit = (uint32_t) (((uint64_t) net->mtu * 880 mptcp_like_alpha * 881 (uint64_t) SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) >> 882 SHIFT_MPTCP_MULTI); 883 incr = (uint32_t) (((uint64_t) net->net_ack * 884 mptcp_like_alpha) >> 885 SHIFT_MPTCP_MULTI); 886 if (incr > limit) { 887 incr = limit; 888 } 889 if (incr > net->net_ack) { 890 incr = net->net_ack; 891 } 892 if (incr > net->mtu) { 893 incr = net->mtu; 894 } 895 break; 896 default: 897 incr = net->net_ack; 898 if (incr > net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) { 899 incr = net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable); 900 } 901 break; 902 } 903 net->cwnd += incr; 904 sctp_enforce_cwnd_limit(asoc, net); 905 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 906 sctp_log_cwnd(stcb, net, incr, 907 SCTP_CWND_LOG_FROM_SS); 908 } 909 SDT_PROBE5(sctp, cwnd, net, ack, 910 stcb->asoc.my_vtag, 911 ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 912 net, 913 old_cwnd, net->cwnd); 914 } else { 915 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 916 sctp_log_cwnd(stcb, net, net->net_ack, 917 SCTP_CWND_LOG_NOADV_SS); 918 } 919 } 920 } else { 921 /* We are in congestion avoidance */ 922 /* 923 * Add to pba 924 */ 925 net->partial_bytes_acked += net->net_ack; 926 927 if ((net->flight_size + net->net_ack >= net->cwnd) && 928 (net->partial_bytes_acked >= net->cwnd)) { 929 net->partial_bytes_acked -= net->cwnd; 930 old_cwnd = net->cwnd; 931 switch (asoc->sctp_cmt_on_off) { 932 case SCTP_CMT_RPV1: 933 incr = (uint32_t) (((uint64_t) net->mtu * 934 (uint64_t) net->ssthresh) / 935 (uint64_t) t_ssthresh); 936 if (incr == 0) { 937 incr = 1; 938 } 939 break; 940 case SCTP_CMT_RPV2: 941 /* 942 * lastsa>>3; we don't need 943 * to divide ... 944 */ 945 srtt = net->lastsa; 946 if (srtt == 0) { 947 srtt = 1; 948 } 949 incr = (uint32_t) ((uint64_t) net->mtu * 950 (uint64_t) net->cwnd / 951 ((uint64_t) srtt * 952 t_ucwnd_sbw)); 953 /* INCREASE FACTOR */ 954 if (incr == 0) { 955 incr = 1; 956 } 957 break; 958 case SCTP_CMT_MPTCP: 959 incr = (uint32_t) ((mptcp_like_alpha * 960 (uint64_t) net->cwnd) >> 961 SHIFT_MPTCP_MULTI); 962 if (incr > net->mtu) { 963 incr = net->mtu; 964 } 965 break; 966 default: 967 incr = net->mtu; 968 break; 969 } 970 net->cwnd += incr; 971 sctp_enforce_cwnd_limit(asoc, net); 972 SDT_PROBE5(sctp, cwnd, net, ack, 973 stcb->asoc.my_vtag, 974 ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 975 net, 976 old_cwnd, net->cwnd); 977 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 978 sctp_log_cwnd(stcb, net, net->mtu, 979 SCTP_CWND_LOG_FROM_CA); 980 } 981 } else { 982 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 983 sctp_log_cwnd(stcb, net, net->net_ack, 984 SCTP_CWND_LOG_NOADV_CA); 985 } 986 } 987 } 988 } else { 989 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 990 sctp_log_cwnd(stcb, net, net->mtu, 991 SCTP_CWND_LOG_NO_CUMACK); 992 } 993 } 994 } 995 } 996 997 static void 998 sctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb, struct sctp_nets *net) 999 { 1000 int old_cwnd; 1001 1002 old_cwnd = net->cwnd; 1003 net->cwnd = net->mtu; 1004 SDT_PROBE5(sctp, cwnd, net, ack, 1005 stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, 1006 old_cwnd, net->cwnd); 1007 SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", 1008 (void *)net, net->cwnd); 1009 } 1010 1011 1012 static void 1013 sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net) 1014 { 1015 int old_cwnd = net->cwnd; 1016 uint32_t t_ssthresh, t_cwnd; 1017 uint64_t t_ucwnd_sbw; 1018 1019 /* MT FIXME: Don't compute this over and over again */ 1020 t_ssthresh = 0; 1021 t_cwnd = 0; 1022 if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) || 1023 (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2)) { 1024 struct sctp_nets *lnet; 1025 uint32_t srtt; 1026 1027 t_ucwnd_sbw = 0; 1028 TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 1029 t_ssthresh += lnet->ssthresh; 1030 t_cwnd += lnet->cwnd; 1031 srtt = lnet->lastsa; 1032 /* lastsa>>3; we don't need to divide ... */ 1033 if (srtt > 0) { 1034 t_ucwnd_sbw += (uint64_t) lnet->cwnd / (uint64_t) srtt; 1035 } 1036 } 1037 if (t_ssthresh < 1) { 1038 t_ssthresh = 1; 1039 } 1040 if (t_ucwnd_sbw < 1) { 1041 t_ucwnd_sbw = 1; 1042 } 1043 if (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) { 1044 net->ssthresh = (uint32_t) (((uint64_t) 4 * 1045 (uint64_t) net->mtu * 1046 (uint64_t) net->ssthresh) / 1047 (uint64_t) t_ssthresh); 1048 } else { 1049 uint64_t cc_delta; 1050 1051 srtt = net->lastsa; 1052 /* lastsa>>3; we don't need to divide ... */ 1053 if (srtt == 0) { 1054 srtt = 1; 1055 } 1056 cc_delta = t_ucwnd_sbw * (uint64_t) srtt / 2; 1057 if (cc_delta < t_cwnd) { 1058 net->ssthresh = (uint32_t) ((uint64_t) t_cwnd - cc_delta); 1059 } else { 1060 net->ssthresh = net->mtu; 1061 } 1062 } 1063 if ((net->cwnd > t_cwnd / 2) && 1064 (net->ssthresh < net->cwnd - t_cwnd / 2)) { 1065 net->ssthresh = net->cwnd - t_cwnd / 2; 1066 } 1067 if (net->ssthresh < net->mtu) { 1068 net->ssthresh = net->mtu; 1069 } 1070 } else { 1071 net->ssthresh = max(net->cwnd / 2, 4 * net->mtu); 1072 } 1073 net->cwnd = net->mtu; 1074 net->partial_bytes_acked = 0; 1075 SDT_PROBE5(sctp, cwnd, net, to, 1076 stcb->asoc.my_vtag, 1077 ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 1078 net, 1079 old_cwnd, net->cwnd); 1080 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1081 sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 1082 } 1083 } 1084 1085 static void 1086 sctp_cwnd_update_after_ecn_echo_common(struct sctp_tcb *stcb, struct sctp_nets *net, 1087 int in_window, int num_pkt_lost, int use_rtcc) 1088 { 1089 int old_cwnd = net->cwnd; 1090 1091 if ((use_rtcc) && (net->lan_type == SCTP_LAN_LOCAL) && (net->cc_mod.rtcc.use_dccc_ecn)) { 1092 /* Data center Congestion Control */ 1093 if (in_window == 0) { 1094 /* 1095 * Go to CA with the cwnd at the point we sent the 1096 * TSN that was marked with a CE. 1097 */ 1098 if (net->ecn_prev_cwnd < net->cwnd) { 1099 /* Restore to prev cwnd */ 1100 net->cwnd = net->ecn_prev_cwnd - (net->mtu * num_pkt_lost); 1101 } else { 1102 /* Just cut in 1/2 */ 1103 net->cwnd /= 2; 1104 } 1105 /* Drop to CA */ 1106 net->ssthresh = net->cwnd - (num_pkt_lost * net->mtu); 1107 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1108 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 1109 } 1110 } else { 1111 /* 1112 * Further tuning down required over the drastic 1113 * original cut 1114 */ 1115 net->ssthresh -= (net->mtu * num_pkt_lost); 1116 net->cwnd -= (net->mtu * num_pkt_lost); 1117 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1118 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 1119 } 1120 } 1121 SCTP_STAT_INCR(sctps_ecnereducedcwnd); 1122 } else { 1123 if (in_window == 0) { 1124 SCTP_STAT_INCR(sctps_ecnereducedcwnd); 1125 net->ssthresh = net->cwnd / 2; 1126 if (net->ssthresh < net->mtu) { 1127 net->ssthresh = net->mtu; 1128 /* 1129 * here back off the timer as well, to slow 1130 * us down 1131 */ 1132 net->RTO <<= 1; 1133 } 1134 net->cwnd = net->ssthresh; 1135 SDT_PROBE5(sctp, cwnd, net, ecn, 1136 stcb->asoc.my_vtag, 1137 ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 1138 net, 1139 old_cwnd, net->cwnd); 1140 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1141 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 1142 } 1143 } 1144 } 1145 1146 } 1147 1148 static void 1149 sctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb, 1150 struct sctp_nets *net, struct sctp_pktdrop_chunk *cp, 1151 uint32_t * bottle_bw, uint32_t * on_queue) 1152 { 1153 uint32_t bw_avail; 1154 unsigned int incr; 1155 int old_cwnd = net->cwnd; 1156 1157 /* get bottle neck bw */ 1158 *bottle_bw = ntohl(cp->bottle_bw); 1159 /* and whats on queue */ 1160 *on_queue = ntohl(cp->current_onq); 1161 /* 1162 * adjust the on-queue if our flight is more it could be that the 1163 * router has not yet gotten data "in-flight" to it 1164 */ 1165 if (*on_queue < net->flight_size) { 1166 *on_queue = net->flight_size; 1167 } 1168 /* rtt is measured in micro seconds, bottle_bw in bytes per second */ 1169 bw_avail = (uint32_t) (((uint64_t) (*bottle_bw) * net->rtt) / (uint64_t) 1000000); 1170 if (bw_avail > *bottle_bw) { 1171 /* 1172 * Cap the growth to no more than the bottle neck. This can 1173 * happen as RTT slides up due to queues. It also means if 1174 * you have more than a 1 second RTT with a empty queue you 1175 * will be limited to the bottle_bw per second no matter if 1176 * other points have 1/2 the RTT and you could get more 1177 * out... 1178 */ 1179 bw_avail = *bottle_bw; 1180 } 1181 if (*on_queue > bw_avail) { 1182 /* 1183 * No room for anything else don't allow anything else to be 1184 * "added to the fire". 1185 */ 1186 int seg_inflight, seg_onqueue, my_portion; 1187 1188 net->partial_bytes_acked = 0; 1189 /* how much are we over queue size? */ 1190 incr = *on_queue - bw_avail; 1191 if (stcb->asoc.seen_a_sack_this_pkt) { 1192 /* 1193 * undo any cwnd adjustment that the sack might have 1194 * made 1195 */ 1196 net->cwnd = net->prev_cwnd; 1197 } 1198 /* Now how much of that is mine? */ 1199 seg_inflight = net->flight_size / net->mtu; 1200 seg_onqueue = *on_queue / net->mtu; 1201 my_portion = (incr * seg_inflight) / seg_onqueue; 1202 1203 /* Have I made an adjustment already */ 1204 if (net->cwnd > net->flight_size) { 1205 /* 1206 * for this flight I made an adjustment we need to 1207 * decrease the portion by a share our previous 1208 * adjustment. 1209 */ 1210 int diff_adj; 1211 1212 diff_adj = net->cwnd - net->flight_size; 1213 if (diff_adj > my_portion) 1214 my_portion = 0; 1215 else 1216 my_portion -= diff_adj; 1217 } 1218 /* 1219 * back down to the previous cwnd (assume we have had a sack 1220 * before this packet). minus what ever portion of the 1221 * overage is my fault. 1222 */ 1223 net->cwnd -= my_portion; 1224 1225 /* we will NOT back down more than 1 MTU */ 1226 if (net->cwnd <= net->mtu) { 1227 net->cwnd = net->mtu; 1228 } 1229 /* force into CA */ 1230 net->ssthresh = net->cwnd - 1; 1231 } else { 1232 /* 1233 * Take 1/4 of the space left or max burst up .. whichever 1234 * is less. 1235 */ 1236 incr = (bw_avail - *on_queue) >> 2; 1237 if ((stcb->asoc.max_burst > 0) && 1238 (stcb->asoc.max_burst * net->mtu < incr)) { 1239 incr = stcb->asoc.max_burst * net->mtu; 1240 } 1241 net->cwnd += incr; 1242 } 1243 if (net->cwnd > bw_avail) { 1244 /* We can't exceed the pipe size */ 1245 net->cwnd = bw_avail; 1246 } 1247 if (net->cwnd < net->mtu) { 1248 /* We always have 1 MTU */ 1249 net->cwnd = net->mtu; 1250 } 1251 sctp_enforce_cwnd_limit(&stcb->asoc, net); 1252 if (net->cwnd - old_cwnd != 0) { 1253 /* log only changes */ 1254 SDT_PROBE5(sctp, cwnd, net, pd, 1255 stcb->asoc.my_vtag, 1256 ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 1257 net, 1258 old_cwnd, net->cwnd); 1259 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1260 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 1261 SCTP_CWND_LOG_FROM_SAT); 1262 } 1263 } 1264 } 1265 1266 static void 1267 sctp_cwnd_update_after_output(struct sctp_tcb *stcb, 1268 struct sctp_nets *net, int burst_limit) 1269 { 1270 int old_cwnd = net->cwnd; 1271 1272 if (net->ssthresh < net->cwnd) 1273 net->ssthresh = net->cwnd; 1274 if (burst_limit) { 1275 net->cwnd = (net->flight_size + (burst_limit * net->mtu)); 1276 sctp_enforce_cwnd_limit(&stcb->asoc, net); 1277 SDT_PROBE5(sctp, cwnd, net, bl, 1278 stcb->asoc.my_vtag, 1279 ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), 1280 net, 1281 old_cwnd, net->cwnd); 1282 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1283 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST); 1284 } 1285 } 1286 } 1287 1288 static void 1289 sctp_cwnd_update_after_sack(struct sctp_tcb *stcb, 1290 struct sctp_association *asoc, 1291 int accum_moved, int reneged_all, int will_exit) 1292 { 1293 /* Passing a zero argument in last disables the rtcc algorithm */ 1294 sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 0); 1295 } 1296 1297 static void 1298 sctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, 1299 int in_window, int num_pkt_lost) 1300 { 1301 /* Passing a zero argument in last disables the rtcc algorithm */ 1302 sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 0); 1303 } 1304 1305 /* Here starts the RTCCVAR type CC invented by RRS which 1306 * is a slight mod to RFC2581. We reuse a common routine or 1307 * two since these algorithms are so close and need to 1308 * remain the same. 1309 */ 1310 static void 1311 sctp_cwnd_update_rtcc_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, 1312 int in_window, int num_pkt_lost) 1313 { 1314 sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 1); 1315 } 1316 1317 1318 static 1319 void 1320 sctp_cwnd_update_rtcc_tsn_acknowledged(struct sctp_nets *net, 1321 struct sctp_tmit_chunk *tp1) 1322 { 1323 net->cc_mod.rtcc.bw_bytes += tp1->send_size; 1324 } 1325 1326 static void 1327 sctp_cwnd_prepare_rtcc_net_for_sack(struct sctp_tcb *stcb SCTP_UNUSED, 1328 struct sctp_nets *net) 1329 { 1330 if (net->cc_mod.rtcc.tls_needs_set > 0) { 1331 /* We had a bw measurment going on */ 1332 struct timeval ltls; 1333 1334 SCTP_GETPTIME_TIMEVAL(<ls); 1335 timevalsub(<ls, &net->cc_mod.rtcc.tls); 1336 net->cc_mod.rtcc.new_tot_time = (ltls.tv_sec * 1000000) + ltls.tv_usec; 1337 } 1338 } 1339 1340 static void 1341 sctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb *stcb, 1342 struct sctp_nets *net) 1343 { 1344 uint64_t vtag, probepoint; 1345 1346 if (net->cc_mod.rtcc.lbw) { 1347 /* Clear the old bw.. we went to 0 in-flight */ 1348 vtag = (net->rtt << 32) | (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) | 1349 (stcb->rport); 1350 probepoint = (((uint64_t) net->cwnd) << 32); 1351 /* Probe point 8 */ 1352 probepoint |= ((8 << 16) | 0); 1353 SDT_PROBE5(sctp, cwnd, net, rttvar, 1354 vtag, 1355 ((net->cc_mod.rtcc.lbw << 32) | 0), 1356 ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), 1357 net->flight_size, 1358 probepoint); 1359 net->cc_mod.rtcc.lbw_rtt = 0; 1360 net->cc_mod.rtcc.cwnd_at_bw_set = 0; 1361 net->cc_mod.rtcc.lbw = 0; 1362 net->cc_mod.rtcc.bw_bytes_at_last_rttc = 0; 1363 net->cc_mod.rtcc.vol_reduce = 0; 1364 net->cc_mod.rtcc.bw_tot_time = 0; 1365 net->cc_mod.rtcc.bw_bytes = 0; 1366 net->cc_mod.rtcc.tls_needs_set = 0; 1367 if (net->cc_mod.rtcc.steady_step) { 1368 net->cc_mod.rtcc.vol_reduce = 0; 1369 net->cc_mod.rtcc.step_cnt = 0; 1370 net->cc_mod.rtcc.last_step_state = 0; 1371 } 1372 if (net->cc_mod.rtcc.ret_from_eq) { 1373 /* less aggressive one - reset cwnd too */ 1374 uint32_t cwnd_in_mtu, cwnd; 1375 1376 cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd); 1377 if (cwnd_in_mtu == 0) { 1378 /* 1379 * Using 0 means that the value of RFC 4960 1380 * is used. 1381 */ 1382 cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 1383 } else { 1384 /* 1385 * We take the minimum of the burst limit 1386 * and the initial congestion window. 1387 */ 1388 if ((stcb->asoc.max_burst > 0) && (cwnd_in_mtu > stcb->asoc.max_burst)) 1389 cwnd_in_mtu = stcb->asoc.max_burst; 1390 cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu; 1391 } 1392 if (net->cwnd > cwnd) { 1393 /* 1394 * Only set if we are not a timeout (i.e. 1395 * down to 1 mtu) 1396 */ 1397 net->cwnd = cwnd; 1398 } 1399 } 1400 } 1401 } 1402 1403 static void 1404 sctp_set_rtcc_initial_cc_param(struct sctp_tcb *stcb, 1405 struct sctp_nets *net) 1406 { 1407 uint64_t vtag, probepoint; 1408 1409 sctp_set_initial_cc_param(stcb, net); 1410 stcb->asoc.use_precise_time = 1; 1411 probepoint = (((uint64_t) net->cwnd) << 32); 1412 probepoint |= ((9 << 16) | 0); 1413 vtag = (net->rtt << 32) | 1414 (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) | 1415 (stcb->rport); 1416 SDT_PROBE5(sctp, cwnd, net, rttvar, 1417 vtag, 1418 0, 1419 0, 1420 0, 1421 probepoint); 1422 net->cc_mod.rtcc.lbw_rtt = 0; 1423 net->cc_mod.rtcc.cwnd_at_bw_set = 0; 1424 net->cc_mod.rtcc.vol_reduce = 0; 1425 net->cc_mod.rtcc.lbw = 0; 1426 net->cc_mod.rtcc.vol_reduce = 0; 1427 net->cc_mod.rtcc.bw_bytes_at_last_rttc = 0; 1428 net->cc_mod.rtcc.bw_tot_time = 0; 1429 net->cc_mod.rtcc.bw_bytes = 0; 1430 net->cc_mod.rtcc.tls_needs_set = 0; 1431 net->cc_mod.rtcc.ret_from_eq = SCTP_BASE_SYSCTL(sctp_rttvar_eqret); 1432 net->cc_mod.rtcc.steady_step = SCTP_BASE_SYSCTL(sctp_steady_step); 1433 net->cc_mod.rtcc.use_dccc_ecn = SCTP_BASE_SYSCTL(sctp_use_dccc_ecn); 1434 net->cc_mod.rtcc.step_cnt = 0; 1435 net->cc_mod.rtcc.last_step_state = 0; 1436 1437 1438 } 1439 1440 static int 1441 sctp_cwnd_rtcc_socket_option(struct sctp_tcb *stcb, int setorget, 1442 struct sctp_cc_option *cc_opt) 1443 { 1444 struct sctp_nets *net; 1445 1446 if (setorget == 1) { 1447 /* a set */ 1448 if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) { 1449 if ((cc_opt->aid_value.assoc_value != 0) && 1450 (cc_opt->aid_value.assoc_value != 1)) { 1451 return (EINVAL); 1452 } 1453 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1454 net->cc_mod.rtcc.ret_from_eq = cc_opt->aid_value.assoc_value; 1455 } 1456 } else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) { 1457 if ((cc_opt->aid_value.assoc_value != 0) && 1458 (cc_opt->aid_value.assoc_value != 1)) { 1459 return (EINVAL); 1460 } 1461 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1462 net->cc_mod.rtcc.use_dccc_ecn = cc_opt->aid_value.assoc_value; 1463 } 1464 } else if (cc_opt->option == SCTP_CC_OPT_STEADY_STEP) { 1465 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1466 net->cc_mod.rtcc.steady_step = cc_opt->aid_value.assoc_value; 1467 } 1468 } else { 1469 return (EINVAL); 1470 } 1471 } else { 1472 /* a get */ 1473 if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) { 1474 net = TAILQ_FIRST(&stcb->asoc.nets); 1475 if (net == NULL) { 1476 return (EFAULT); 1477 } 1478 cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.ret_from_eq; 1479 } else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) { 1480 net = TAILQ_FIRST(&stcb->asoc.nets); 1481 if (net == NULL) { 1482 return (EFAULT); 1483 } 1484 cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.use_dccc_ecn; 1485 } else if (cc_opt->option == SCTP_CC_OPT_STEADY_STEP) { 1486 net = TAILQ_FIRST(&stcb->asoc.nets); 1487 if (net == NULL) { 1488 return (EFAULT); 1489 } 1490 cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.steady_step; 1491 } else { 1492 return (EINVAL); 1493 } 1494 } 1495 return (0); 1496 } 1497 1498 static void 1499 sctp_cwnd_update_rtcc_packet_transmitted(struct sctp_tcb *stcb SCTP_UNUSED, 1500 struct sctp_nets *net) 1501 { 1502 if (net->cc_mod.rtcc.tls_needs_set == 0) { 1503 SCTP_GETPTIME_TIMEVAL(&net->cc_mod.rtcc.tls); 1504 net->cc_mod.rtcc.tls_needs_set = 2; 1505 } 1506 } 1507 1508 static void 1509 sctp_cwnd_update_rtcc_after_sack(struct sctp_tcb *stcb, 1510 struct sctp_association *asoc, 1511 int accum_moved, int reneged_all, int will_exit) 1512 { 1513 /* Passing a one argument at the last enables the rtcc algorithm */ 1514 sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 1); 1515 } 1516 1517 static void 1518 sctp_rtt_rtcc_calculated(struct sctp_tcb *stcb SCTP_UNUSED, 1519 struct sctp_nets *net, 1520 struct timeval *now SCTP_UNUSED) 1521 { 1522 net->cc_mod.rtcc.rtt_set_this_sack = 1; 1523 } 1524 1525 /* Here starts Sally Floyds HS-TCP */ 1526 1527 struct sctp_hs_raise_drop { 1528 int32_t cwnd; 1529 int8_t increase; 1530 int8_t drop_percent; 1531 }; 1532 1533 #define SCTP_HS_TABLE_SIZE 73 1534 1535 static const struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = { 1536 {38, 1, 50}, /* 0 */ 1537 {118, 2, 44}, /* 1 */ 1538 {221, 3, 41}, /* 2 */ 1539 {347, 4, 38}, /* 3 */ 1540 {495, 5, 37}, /* 4 */ 1541 {663, 6, 35}, /* 5 */ 1542 {851, 7, 34}, /* 6 */ 1543 {1058, 8, 33}, /* 7 */ 1544 {1284, 9, 32}, /* 8 */ 1545 {1529, 10, 31}, /* 9 */ 1546 {1793, 11, 30}, /* 10 */ 1547 {2076, 12, 29}, /* 11 */ 1548 {2378, 13, 28}, /* 12 */ 1549 {2699, 14, 28}, /* 13 */ 1550 {3039, 15, 27}, /* 14 */ 1551 {3399, 16, 27}, /* 15 */ 1552 {3778, 17, 26}, /* 16 */ 1553 {4177, 18, 26}, /* 17 */ 1554 {4596, 19, 25}, /* 18 */ 1555 {5036, 20, 25}, /* 19 */ 1556 {5497, 21, 24}, /* 20 */ 1557 {5979, 22, 24}, /* 21 */ 1558 {6483, 23, 23}, /* 22 */ 1559 {7009, 24, 23}, /* 23 */ 1560 {7558, 25, 22}, /* 24 */ 1561 {8130, 26, 22}, /* 25 */ 1562 {8726, 27, 22}, /* 26 */ 1563 {9346, 28, 21}, /* 27 */ 1564 {9991, 29, 21}, /* 28 */ 1565 {10661, 30, 21}, /* 29 */ 1566 {11358, 31, 20}, /* 30 */ 1567 {12082, 32, 20}, /* 31 */ 1568 {12834, 33, 20}, /* 32 */ 1569 {13614, 34, 19}, /* 33 */ 1570 {14424, 35, 19}, /* 34 */ 1571 {15265, 36, 19}, /* 35 */ 1572 {16137, 37, 19}, /* 36 */ 1573 {17042, 38, 18}, /* 37 */ 1574 {17981, 39, 18}, /* 38 */ 1575 {18955, 40, 18}, /* 39 */ 1576 {19965, 41, 17}, /* 40 */ 1577 {21013, 42, 17}, /* 41 */ 1578 {22101, 43, 17}, /* 42 */ 1579 {23230, 44, 17}, /* 43 */ 1580 {24402, 45, 16}, /* 44 */ 1581 {25618, 46, 16}, /* 45 */ 1582 {26881, 47, 16}, /* 46 */ 1583 {28193, 48, 16}, /* 47 */ 1584 {29557, 49, 15}, /* 48 */ 1585 {30975, 50, 15}, /* 49 */ 1586 {32450, 51, 15}, /* 50 */ 1587 {33986, 52, 15}, /* 51 */ 1588 {35586, 53, 14}, /* 52 */ 1589 {37253, 54, 14}, /* 53 */ 1590 {38992, 55, 14}, /* 54 */ 1591 {40808, 56, 14}, /* 55 */ 1592 {42707, 57, 13}, /* 56 */ 1593 {44694, 58, 13}, /* 57 */ 1594 {46776, 59, 13}, /* 58 */ 1595 {48961, 60, 13}, /* 59 */ 1596 {51258, 61, 13}, /* 60 */ 1597 {53677, 62, 12}, /* 61 */ 1598 {56230, 63, 12}, /* 62 */ 1599 {58932, 64, 12}, /* 63 */ 1600 {61799, 65, 12}, /* 64 */ 1601 {64851, 66, 11}, /* 65 */ 1602 {68113, 67, 11}, /* 66 */ 1603 {71617, 68, 11}, /* 67 */ 1604 {75401, 69, 10}, /* 68 */ 1605 {79517, 70, 10}, /* 69 */ 1606 {84035, 71, 10}, /* 70 */ 1607 {89053, 72, 10}, /* 71 */ 1608 {94717, 73, 9} /* 72 */ 1609 }; 1610 1611 static void 1612 sctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net) 1613 { 1614 int cur_val, i, indx, incr; 1615 int old_cwnd = net->cwnd; 1616 1617 cur_val = net->cwnd >> 10; 1618 indx = SCTP_HS_TABLE_SIZE - 1; 1619 1620 if (cur_val < sctp_cwnd_adjust[0].cwnd) { 1621 /* normal mode */ 1622 if (net->net_ack > net->mtu) { 1623 net->cwnd += net->mtu; 1624 } else { 1625 net->cwnd += net->net_ack; 1626 } 1627 } else { 1628 for (i = net->last_hs_used; i < SCTP_HS_TABLE_SIZE; i++) { 1629 if (cur_val < sctp_cwnd_adjust[i].cwnd) { 1630 indx = i; 1631 break; 1632 } 1633 } 1634 net->last_hs_used = indx; 1635 incr = (((int32_t) sctp_cwnd_adjust[indx].increase) << 10); 1636 net->cwnd += incr; 1637 } 1638 sctp_enforce_cwnd_limit(&stcb->asoc, net); 1639 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1640 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SS); 1641 } 1642 } 1643 1644 static void 1645 sctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net) 1646 { 1647 int cur_val, i, indx; 1648 int old_cwnd = net->cwnd; 1649 1650 cur_val = net->cwnd >> 10; 1651 if (cur_val < sctp_cwnd_adjust[0].cwnd) { 1652 /* normal mode */ 1653 net->ssthresh = net->cwnd / 2; 1654 if (net->ssthresh < (net->mtu * 2)) { 1655 net->ssthresh = 2 * net->mtu; 1656 } 1657 net->cwnd = net->ssthresh; 1658 } else { 1659 /* drop by the proper amount */ 1660 net->ssthresh = net->cwnd - (int)((net->cwnd / 100) * 1661 (int32_t) sctp_cwnd_adjust[net->last_hs_used].drop_percent); 1662 net->cwnd = net->ssthresh; 1663 /* now where are we */ 1664 indx = net->last_hs_used; 1665 cur_val = net->cwnd >> 10; 1666 /* reset where we are in the table */ 1667 if (cur_val < sctp_cwnd_adjust[0].cwnd) { 1668 /* feel out of hs */ 1669 net->last_hs_used = 0; 1670 } else { 1671 for (i = indx; i >= 1; i--) { 1672 if (cur_val > sctp_cwnd_adjust[i - 1].cwnd) { 1673 break; 1674 } 1675 } 1676 net->last_hs_used = indx; 1677 } 1678 } 1679 sctp_enforce_cwnd_limit(&stcb->asoc, net); 1680 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1681 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_FR); 1682 } 1683 } 1684 1685 static void 1686 sctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb, 1687 struct sctp_association *asoc) 1688 { 1689 struct sctp_nets *net; 1690 1691 /* 1692 * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) && 1693 * (net->fast_retran_loss_recovery == 0))) 1694 */ 1695 TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 1696 if ((asoc->fast_retran_loss_recovery == 0) || 1697 (asoc->sctp_cmt_on_off > 0)) { 1698 /* out of a RFC2582 Fast recovery window? */ 1699 if (net->net_ack > 0) { 1700 /* 1701 * per section 7.2.3, are there any 1702 * destinations that had a fast retransmit 1703 * to them. If so what we need to do is 1704 * adjust ssthresh and cwnd. 1705 */ 1706 struct sctp_tmit_chunk *lchk; 1707 1708 sctp_hs_cwnd_decrease(stcb, net); 1709 1710 lchk = TAILQ_FIRST(&asoc->send_queue); 1711 1712 net->partial_bytes_acked = 0; 1713 /* Turn on fast recovery window */ 1714 asoc->fast_retran_loss_recovery = 1; 1715 if (lchk == NULL) { 1716 /* Mark end of the window */ 1717 asoc->fast_recovery_tsn = asoc->sending_seq - 1; 1718 } else { 1719 asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 1720 } 1721 1722 /* 1723 * CMT fast recovery -- per destination 1724 * recovery variable. 1725 */ 1726 net->fast_retran_loss_recovery = 1; 1727 1728 if (lchk == NULL) { 1729 /* Mark end of the window */ 1730 net->fast_recovery_tsn = asoc->sending_seq - 1; 1731 } else { 1732 net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 1733 } 1734 1735 sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 1736 stcb->sctp_ep, stcb, net, 1737 SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_2); 1738 sctp_timer_start(SCTP_TIMER_TYPE_SEND, 1739 stcb->sctp_ep, stcb, net); 1740 } 1741 } else if (net->net_ack > 0) { 1742 /* 1743 * Mark a peg that we WOULD have done a cwnd 1744 * reduction but RFC2582 prevented this action. 1745 */ 1746 SCTP_STAT_INCR(sctps_fastretransinrtt); 1747 } 1748 } 1749 } 1750 1751 static void 1752 sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, 1753 struct sctp_association *asoc, 1754 int accum_moved, int reneged_all SCTP_UNUSED, int will_exit) 1755 { 1756 struct sctp_nets *net; 1757 1758 /******************************/ 1759 /* update cwnd and Early FR */ 1760 /******************************/ 1761 TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 1762 1763 #ifdef JANA_CMT_FAST_RECOVERY 1764 /* 1765 * CMT fast recovery code. Need to debug. 1766 */ 1767 if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 1768 if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) || 1769 SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) { 1770 net->will_exit_fast_recovery = 1; 1771 } 1772 } 1773 #endif 1774 /* if nothing was acked on this destination skip it */ 1775 if (net->net_ack == 0) { 1776 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1777 sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 1778 } 1779 continue; 1780 } 1781 #ifdef JANA_CMT_FAST_RECOVERY 1782 /* 1783 * CMT fast recovery code 1784 */ 1785 /* 1786 * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery 1787 * && net->will_exit_fast_recovery == 0) { @@@ Do something 1788 * } else if (sctp_cmt_on_off == 0 && 1789 * asoc->fast_retran_loss_recovery && will_exit == 0) { 1790 */ 1791 #endif 1792 1793 if (asoc->fast_retran_loss_recovery && 1794 (will_exit == 0) && 1795 (asoc->sctp_cmt_on_off == 0)) { 1796 /* 1797 * If we are in loss recovery we skip any cwnd 1798 * update 1799 */ 1800 return; 1801 } 1802 /* 1803 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 1804 * moved. 1805 */ 1806 if (accum_moved || 1807 ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) { 1808 /* If the cumulative ack moved we can proceed */ 1809 if (net->cwnd <= net->ssthresh) { 1810 /* We are in slow start */ 1811 if (net->flight_size + net->net_ack >= net->cwnd) { 1812 sctp_hs_cwnd_increase(stcb, net); 1813 } else { 1814 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1815 sctp_log_cwnd(stcb, net, net->net_ack, 1816 SCTP_CWND_LOG_NOADV_SS); 1817 } 1818 } 1819 } else { 1820 /* We are in congestion avoidance */ 1821 net->partial_bytes_acked += net->net_ack; 1822 if ((net->flight_size + net->net_ack >= net->cwnd) && 1823 (net->partial_bytes_acked >= net->cwnd)) { 1824 net->partial_bytes_acked -= net->cwnd; 1825 net->cwnd += net->mtu; 1826 sctp_enforce_cwnd_limit(asoc, net); 1827 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1828 sctp_log_cwnd(stcb, net, net->mtu, 1829 SCTP_CWND_LOG_FROM_CA); 1830 } 1831 } else { 1832 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1833 sctp_log_cwnd(stcb, net, net->net_ack, 1834 SCTP_CWND_LOG_NOADV_CA); 1835 } 1836 } 1837 } 1838 } else { 1839 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1840 sctp_log_cwnd(stcb, net, net->mtu, 1841 SCTP_CWND_LOG_NO_CUMACK); 1842 } 1843 } 1844 } 1845 } 1846 1847 1848 /* 1849 * H-TCP congestion control. The algorithm is detailed in: 1850 * R.N.Shorten, D.J.Leith: 1851 * "H-TCP: TCP for high-speed and long-distance networks" 1852 * Proc. PFLDnet, Argonne, 2004. 1853 * http://www.hamilton.ie/net/htcp3.pdf 1854 */ 1855 1856 1857 static int use_rtt_scaling = 1; 1858 static int use_bandwidth_switch = 1; 1859 1860 static inline int 1861 between(uint32_t seq1, uint32_t seq2, uint32_t seq3) 1862 { 1863 return (seq3 - seq2 >= seq1 - seq2); 1864 } 1865 1866 static inline uint32_t 1867 htcp_cong_time(struct htcp *ca) 1868 { 1869 return (sctp_get_tick_count() - ca->last_cong); 1870 } 1871 1872 static inline uint32_t 1873 htcp_ccount(struct htcp *ca) 1874 { 1875 return (htcp_cong_time(ca) / ca->minRTT); 1876 } 1877 1878 static inline void 1879 htcp_reset(struct htcp *ca) 1880 { 1881 ca->undo_last_cong = ca->last_cong; 1882 ca->undo_maxRTT = ca->maxRTT; 1883 ca->undo_old_maxB = ca->old_maxB; 1884 ca->last_cong = sctp_get_tick_count(); 1885 } 1886 1887 #ifdef SCTP_NOT_USED 1888 1889 static uint32_t 1890 htcp_cwnd_undo(struct sctp_tcb *stcb, struct sctp_nets *net) 1891 { 1892 net->cc_mod.htcp_ca.last_cong = net->cc_mod.htcp_ca.undo_last_cong; 1893 net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.undo_maxRTT; 1894 net->cc_mod.htcp_ca.old_maxB = net->cc_mod.htcp_ca.undo_old_maxB; 1895 return (max(net->cwnd, ((net->ssthresh / net->mtu << 7) / net->cc_mod.htcp_ca.beta) * net->mtu)); 1896 } 1897 1898 #endif 1899 1900 static inline void 1901 measure_rtt(struct sctp_nets *net) 1902 { 1903 uint32_t srtt = net->lastsa >> SCTP_RTT_SHIFT; 1904 1905 /* keep track of minimum RTT seen so far, minRTT is zero at first */ 1906 if (net->cc_mod.htcp_ca.minRTT > srtt || !net->cc_mod.htcp_ca.minRTT) 1907 net->cc_mod.htcp_ca.minRTT = srtt; 1908 1909 /* max RTT */ 1910 if (net->fast_retran_ip == 0 && net->ssthresh < 0xFFFF && htcp_ccount(&net->cc_mod.htcp_ca) > 3) { 1911 if (net->cc_mod.htcp_ca.maxRTT < net->cc_mod.htcp_ca.minRTT) 1912 net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.minRTT; 1913 if (net->cc_mod.htcp_ca.maxRTT < srtt && srtt <= net->cc_mod.htcp_ca.maxRTT + MSEC_TO_TICKS(20)) 1914 net->cc_mod.htcp_ca.maxRTT = srtt; 1915 } 1916 } 1917 1918 static void 1919 measure_achieved_throughput(struct sctp_nets *net) 1920 { 1921 uint32_t now = sctp_get_tick_count(); 1922 1923 if (net->fast_retran_ip == 0) 1924 net->cc_mod.htcp_ca.bytes_acked = net->net_ack; 1925 1926 if (!use_bandwidth_switch) 1927 return; 1928 1929 /* achieved throughput calculations */ 1930 /* JRS - not 100% sure of this statement */ 1931 if (net->fast_retran_ip == 1) { 1932 net->cc_mod.htcp_ca.bytecount = 0; 1933 net->cc_mod.htcp_ca.lasttime = now; 1934 return; 1935 } 1936 net->cc_mod.htcp_ca.bytecount += net->net_ack; 1937 if ((net->cc_mod.htcp_ca.bytecount >= net->cwnd - (((net->cc_mod.htcp_ca.alpha >> 7) ? (net->cc_mod.htcp_ca.alpha >> 7) : 1) * net->mtu)) && 1938 (now - net->cc_mod.htcp_ca.lasttime >= net->cc_mod.htcp_ca.minRTT) && 1939 (net->cc_mod.htcp_ca.minRTT > 0)) { 1940 uint32_t cur_Bi = net->cc_mod.htcp_ca.bytecount / net->mtu * hz / (now - net->cc_mod.htcp_ca.lasttime); 1941 1942 if (htcp_ccount(&net->cc_mod.htcp_ca) <= 3) { 1943 /* just after backoff */ 1944 net->cc_mod.htcp_ca.minB = net->cc_mod.htcp_ca.maxB = net->cc_mod.htcp_ca.Bi = cur_Bi; 1945 } else { 1946 net->cc_mod.htcp_ca.Bi = (3 * net->cc_mod.htcp_ca.Bi + cur_Bi) / 4; 1947 if (net->cc_mod.htcp_ca.Bi > net->cc_mod.htcp_ca.maxB) 1948 net->cc_mod.htcp_ca.maxB = net->cc_mod.htcp_ca.Bi; 1949 if (net->cc_mod.htcp_ca.minB > net->cc_mod.htcp_ca.maxB) 1950 net->cc_mod.htcp_ca.minB = net->cc_mod.htcp_ca.maxB; 1951 } 1952 net->cc_mod.htcp_ca.bytecount = 0; 1953 net->cc_mod.htcp_ca.lasttime = now; 1954 } 1955 } 1956 1957 static inline void 1958 htcp_beta_update(struct htcp *ca, uint32_t minRTT, uint32_t maxRTT) 1959 { 1960 if (use_bandwidth_switch) { 1961 uint32_t maxB = ca->maxB; 1962 uint32_t old_maxB = ca->old_maxB; 1963 1964 ca->old_maxB = ca->maxB; 1965 1966 if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) { 1967 ca->beta = BETA_MIN; 1968 ca->modeswitch = 0; 1969 return; 1970 } 1971 } 1972 if (ca->modeswitch && minRTT > (uint32_t) MSEC_TO_TICKS(10) && maxRTT) { 1973 ca->beta = (minRTT << 7) / maxRTT; 1974 if (ca->beta < BETA_MIN) 1975 ca->beta = BETA_MIN; 1976 else if (ca->beta > BETA_MAX) 1977 ca->beta = BETA_MAX; 1978 } else { 1979 ca->beta = BETA_MIN; 1980 ca->modeswitch = 1; 1981 } 1982 } 1983 1984 static inline void 1985 htcp_alpha_update(struct htcp *ca) 1986 { 1987 uint32_t minRTT = ca->minRTT; 1988 uint32_t factor = 1; 1989 uint32_t diff = htcp_cong_time(ca); 1990 1991 if (diff > (uint32_t) hz) { 1992 diff -= hz; 1993 factor = 1 + (10 * diff + ((diff / 2) * (diff / 2) / hz)) / hz; 1994 } 1995 if (use_rtt_scaling && minRTT) { 1996 uint32_t scale = (hz << 3) / (10 * minRTT); 1997 1998 scale = min(max(scale, 1U << 2), 10U << 3); /* clamping ratio to 1999 * interval [0.5,10]<<3 */ 2000 factor = (factor << 3) / scale; 2001 if (!factor) 2002 factor = 1; 2003 } 2004 ca->alpha = 2 * factor * ((1 << 7) - ca->beta); 2005 if (!ca->alpha) 2006 ca->alpha = ALPHA_BASE; 2007 } 2008 2009 /* After we have the rtt data to calculate beta, we'd still prefer to wait one 2010 * rtt before we adjust our beta to ensure we are working from a consistent 2011 * data. 2012 * 2013 * This function should be called when we hit a congestion event since only at 2014 * that point do we really have a real sense of maxRTT (the queues en route 2015 * were getting just too full now). 2016 */ 2017 static void 2018 htcp_param_update(struct sctp_nets *net) 2019 { 2020 uint32_t minRTT = net->cc_mod.htcp_ca.minRTT; 2021 uint32_t maxRTT = net->cc_mod.htcp_ca.maxRTT; 2022 2023 htcp_beta_update(&net->cc_mod.htcp_ca, minRTT, maxRTT); 2024 htcp_alpha_update(&net->cc_mod.htcp_ca); 2025 2026 /* 2027 * add slowly fading memory for maxRTT to accommodate routing 2028 * changes etc 2029 */ 2030 if (minRTT > 0 && maxRTT > minRTT) 2031 net->cc_mod.htcp_ca.maxRTT = minRTT + ((maxRTT - minRTT) * 95) / 100; 2032 } 2033 2034 static uint32_t 2035 htcp_recalc_ssthresh(struct sctp_nets *net) 2036 { 2037 htcp_param_update(net); 2038 return (max(((net->cwnd / net->mtu * net->cc_mod.htcp_ca.beta) >> 7) * net->mtu, 2U * net->mtu)); 2039 } 2040 2041 static void 2042 htcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net) 2043 { 2044 /*- 2045 * How to handle these functions? 2046 * if (!tcp_is_cwnd_limited(sk, in_flight)) RRS - good question. 2047 * return; 2048 */ 2049 if (net->cwnd <= net->ssthresh) { 2050 /* We are in slow start */ 2051 if (net->flight_size + net->net_ack >= net->cwnd) { 2052 if (net->net_ack > (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable))) { 2053 net->cwnd += (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)); 2054 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2055 sctp_log_cwnd(stcb, net, net->mtu, 2056 SCTP_CWND_LOG_FROM_SS); 2057 } 2058 } else { 2059 net->cwnd += net->net_ack; 2060 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2061 sctp_log_cwnd(stcb, net, net->net_ack, 2062 SCTP_CWND_LOG_FROM_SS); 2063 } 2064 } 2065 sctp_enforce_cwnd_limit(&stcb->asoc, net); 2066 } else { 2067 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 2068 sctp_log_cwnd(stcb, net, net->net_ack, 2069 SCTP_CWND_LOG_NOADV_SS); 2070 } 2071 } 2072 } else { 2073 measure_rtt(net); 2074 2075 /* 2076 * In dangerous area, increase slowly. In theory this is 2077 * net->cwnd += alpha / net->cwnd 2078 */ 2079 /* What is snd_cwnd_cnt?? */ 2080 if (((net->partial_bytes_acked / net->mtu * net->cc_mod.htcp_ca.alpha) >> 7) * net->mtu >= net->cwnd) { 2081 /*- 2082 * Does SCTP have a cwnd clamp? 2083 * if (net->snd_cwnd < net->snd_cwnd_clamp) - Nope (RRS). 2084 */ 2085 net->cwnd += net->mtu; 2086 net->partial_bytes_acked = 0; 2087 sctp_enforce_cwnd_limit(&stcb->asoc, net); 2088 htcp_alpha_update(&net->cc_mod.htcp_ca); 2089 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2090 sctp_log_cwnd(stcb, net, net->mtu, 2091 SCTP_CWND_LOG_FROM_CA); 2092 } 2093 } else { 2094 net->partial_bytes_acked += net->net_ack; 2095 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 2096 sctp_log_cwnd(stcb, net, net->net_ack, 2097 SCTP_CWND_LOG_NOADV_CA); 2098 } 2099 } 2100 2101 net->cc_mod.htcp_ca.bytes_acked = net->mtu; 2102 } 2103 } 2104 2105 #ifdef SCTP_NOT_USED 2106 /* Lower bound on congestion window. */ 2107 static uint32_t 2108 htcp_min_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net) 2109 { 2110 return (net->ssthresh); 2111 } 2112 2113 #endif 2114 2115 static void 2116 htcp_init(struct sctp_nets *net) 2117 { 2118 memset(&net->cc_mod.htcp_ca, 0, sizeof(struct htcp)); 2119 net->cc_mod.htcp_ca.alpha = ALPHA_BASE; 2120 net->cc_mod.htcp_ca.beta = BETA_MIN; 2121 net->cc_mod.htcp_ca.bytes_acked = net->mtu; 2122 net->cc_mod.htcp_ca.last_cong = sctp_get_tick_count(); 2123 } 2124 2125 static void 2126 sctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) 2127 { 2128 /* 2129 * We take the max of the burst limit times a MTU or the 2130 * INITIAL_CWND. We then limit this to 4 MTU's of sending. 2131 */ 2132 net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); 2133 net->ssthresh = stcb->asoc.peers_rwnd; 2134 sctp_enforce_cwnd_limit(&stcb->asoc, net); 2135 htcp_init(net); 2136 2137 if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { 2138 sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); 2139 } 2140 } 2141 2142 static void 2143 sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, 2144 struct sctp_association *asoc, 2145 int accum_moved, int reneged_all SCTP_UNUSED, int will_exit) 2146 { 2147 struct sctp_nets *net; 2148 2149 /******************************/ 2150 /* update cwnd and Early FR */ 2151 /******************************/ 2152 TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 2153 2154 #ifdef JANA_CMT_FAST_RECOVERY 2155 /* 2156 * CMT fast recovery code. Need to debug. 2157 */ 2158 if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) { 2159 if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) || 2160 SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) { 2161 net->will_exit_fast_recovery = 1; 2162 } 2163 } 2164 #endif 2165 /* if nothing was acked on this destination skip it */ 2166 if (net->net_ack == 0) { 2167 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 2168 sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK); 2169 } 2170 continue; 2171 } 2172 #ifdef JANA_CMT_FAST_RECOVERY 2173 /* 2174 * CMT fast recovery code 2175 */ 2176 /* 2177 * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery 2178 * && net->will_exit_fast_recovery == 0) { @@@ Do something 2179 * } else if (sctp_cmt_on_off == 0 && 2180 * asoc->fast_retran_loss_recovery && will_exit == 0) { 2181 */ 2182 #endif 2183 2184 if (asoc->fast_retran_loss_recovery && 2185 will_exit == 0 && 2186 (asoc->sctp_cmt_on_off == 0)) { 2187 /* 2188 * If we are in loss recovery we skip any cwnd 2189 * update 2190 */ 2191 return; 2192 } 2193 /* 2194 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has 2195 * moved. 2196 */ 2197 if (accum_moved || 2198 ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) { 2199 htcp_cong_avoid(stcb, net); 2200 measure_achieved_throughput(net); 2201 } else { 2202 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 2203 sctp_log_cwnd(stcb, net, net->mtu, 2204 SCTP_CWND_LOG_NO_CUMACK); 2205 } 2206 } 2207 } 2208 } 2209 2210 static void 2211 sctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb, 2212 struct sctp_association *asoc) 2213 { 2214 struct sctp_nets *net; 2215 2216 /* 2217 * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) && 2218 * (net->fast_retran_loss_recovery == 0))) 2219 */ 2220 TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 2221 if ((asoc->fast_retran_loss_recovery == 0) || 2222 (asoc->sctp_cmt_on_off > 0)) { 2223 /* out of a RFC2582 Fast recovery window? */ 2224 if (net->net_ack > 0) { 2225 /* 2226 * per section 7.2.3, are there any 2227 * destinations that had a fast retransmit 2228 * to them. If so what we need to do is 2229 * adjust ssthresh and cwnd. 2230 */ 2231 struct sctp_tmit_chunk *lchk; 2232 int old_cwnd = net->cwnd; 2233 2234 /* JRS - reset as if state were changed */ 2235 htcp_reset(&net->cc_mod.htcp_ca); 2236 net->ssthresh = htcp_recalc_ssthresh(net); 2237 net->cwnd = net->ssthresh; 2238 sctp_enforce_cwnd_limit(asoc, net); 2239 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2240 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), 2241 SCTP_CWND_LOG_FROM_FR); 2242 } 2243 lchk = TAILQ_FIRST(&asoc->send_queue); 2244 2245 net->partial_bytes_acked = 0; 2246 /* Turn on fast recovery window */ 2247 asoc->fast_retran_loss_recovery = 1; 2248 if (lchk == NULL) { 2249 /* Mark end of the window */ 2250 asoc->fast_recovery_tsn = asoc->sending_seq - 1; 2251 } else { 2252 asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 2253 } 2254 2255 /* 2256 * CMT fast recovery -- per destination 2257 * recovery variable. 2258 */ 2259 net->fast_retran_loss_recovery = 1; 2260 2261 if (lchk == NULL) { 2262 /* Mark end of the window */ 2263 net->fast_recovery_tsn = asoc->sending_seq - 1; 2264 } else { 2265 net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1; 2266 } 2267 2268 sctp_timer_stop(SCTP_TIMER_TYPE_SEND, 2269 stcb->sctp_ep, stcb, net, 2270 SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_3); 2271 sctp_timer_start(SCTP_TIMER_TYPE_SEND, 2272 stcb->sctp_ep, stcb, net); 2273 } 2274 } else if (net->net_ack > 0) { 2275 /* 2276 * Mark a peg that we WOULD have done a cwnd 2277 * reduction but RFC2582 prevented this action. 2278 */ 2279 SCTP_STAT_INCR(sctps_fastretransinrtt); 2280 } 2281 } 2282 } 2283 2284 static void 2285 sctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb, 2286 struct sctp_nets *net) 2287 { 2288 int old_cwnd = net->cwnd; 2289 2290 /* JRS - reset as if the state were being changed to timeout */ 2291 htcp_reset(&net->cc_mod.htcp_ca); 2292 net->ssthresh = htcp_recalc_ssthresh(net); 2293 net->cwnd = net->mtu; 2294 net->partial_bytes_acked = 0; 2295 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2296 sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 2297 } 2298 } 2299 2300 static void 2301 sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, 2302 struct sctp_nets *net, int in_window, int num_pkt_lost SCTP_UNUSED) 2303 { 2304 int old_cwnd; 2305 2306 old_cwnd = net->cwnd; 2307 2308 /* JRS - reset hctp as if state changed */ 2309 if (in_window == 0) { 2310 htcp_reset(&net->cc_mod.htcp_ca); 2311 SCTP_STAT_INCR(sctps_ecnereducedcwnd); 2312 net->ssthresh = htcp_recalc_ssthresh(net); 2313 if (net->ssthresh < net->mtu) { 2314 net->ssthresh = net->mtu; 2315 /* here back off the timer as well, to slow us down */ 2316 net->RTO <<= 1; 2317 } 2318 net->cwnd = net->ssthresh; 2319 sctp_enforce_cwnd_limit(&stcb->asoc, net); 2320 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 2321 sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); 2322 } 2323 } 2324 } 2325 2326 const struct sctp_cc_functions sctp_cc_functions[] = { 2327 { 2328 .sctp_set_initial_cc_param = sctp_set_initial_cc_param, 2329 .sctp_cwnd_update_after_sack = sctp_cwnd_update_after_sack, 2330 .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, 2331 .sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr, 2332 .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, 2333 .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo, 2334 .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, 2335 .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, 2336 }, 2337 { 2338 .sctp_set_initial_cc_param = sctp_set_initial_cc_param, 2339 .sctp_cwnd_update_after_sack = sctp_hs_cwnd_update_after_sack, 2340 .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, 2341 .sctp_cwnd_update_after_fr = sctp_hs_cwnd_update_after_fr, 2342 .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, 2343 .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo, 2344 .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, 2345 .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, 2346 }, 2347 { 2348 .sctp_set_initial_cc_param = sctp_htcp_set_initial_cc_param, 2349 .sctp_cwnd_update_after_sack = sctp_htcp_cwnd_update_after_sack, 2350 .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, 2351 .sctp_cwnd_update_after_fr = sctp_htcp_cwnd_update_after_fr, 2352 .sctp_cwnd_update_after_timeout = sctp_htcp_cwnd_update_after_timeout, 2353 .sctp_cwnd_update_after_ecn_echo = sctp_htcp_cwnd_update_after_ecn_echo, 2354 .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, 2355 .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, 2356 }, 2357 { 2358 .sctp_set_initial_cc_param = sctp_set_rtcc_initial_cc_param, 2359 .sctp_cwnd_update_after_sack = sctp_cwnd_update_rtcc_after_sack, 2360 .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, 2361 .sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr, 2362 .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, 2363 .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_rtcc_after_ecn_echo, 2364 .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, 2365 .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, 2366 .sctp_cwnd_update_packet_transmitted = sctp_cwnd_update_rtcc_packet_transmitted, 2367 .sctp_cwnd_update_tsn_acknowledged = sctp_cwnd_update_rtcc_tsn_acknowledged, 2368 .sctp_cwnd_new_transmission_begins = sctp_cwnd_new_rtcc_transmission_begins, 2369 .sctp_cwnd_prepare_net_for_sack = sctp_cwnd_prepare_rtcc_net_for_sack, 2370 .sctp_cwnd_socket_option = sctp_cwnd_rtcc_socket_option, 2371 .sctp_rtt_calculated = sctp_rtt_rtcc_calculated 2372 } 2373 }; 2374