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