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