netwerk/sctp/src/netinet/sctp_cc_functions.c

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rwxr-xr-x

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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  */
    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
    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
    55 #define SHIFT_MPTCP_MULTI_N 40
    56 #define SHIFT_MPTCP_MULTI_Z 16
    57 #define SHIFT_MPTCP_MULTI 8
    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;
    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 }
    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;
   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 	}
   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;
   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);
   151 					}
   152 					if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2) {
   153 						uint32_t srtt;
   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);
   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 				}
   203 				/*
   204 				 * CMT fast recovery -- per destination
   205 				 * recovery variable.
   206 				 */
   207 				net->fast_retran_loss_recovery = 1;
   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 				}
   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 }
   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 */
   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
   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 }
   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
   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 }
   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;
   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 }
   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 }
   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;
   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;
   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) {
   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
   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;
   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);
   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;
   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;
   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;
  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;
  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;
  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;
  1025 						break;
  1026 					default:
  1027 						incr = net->mtu;
  1028 						break;
  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);
  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);
  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);
  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
  1066 #if defined(__FreeBSD__) && __FreeBSD_version >= 803000
  1067 	int old_cwnd;
  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);
  1082 static void
  1083 sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net)
  1085 	int old_cwnd = net->cwnd;
  1086 	uint32_t t_ssthresh, t_cwnd;
  1087 	uint64_t t_ucwnd_sbw;
  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;
  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;
  1107 		if (t_ssthresh < 1) {
  1108 			t_ssthresh = 1;
  1110 		if (t_ucwnd_sbw < 1) {
  1111 			t_ucwnd_sbw = 1;
  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;
  1121 			srtt = net->lastsa;
  1122 			/* lastsa>>3;  we don't need to divide ... */
  1123 			if (srtt == 0) {
  1124 				srtt = 1;
  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;
  1133 		if ((net->cwnd > t_cwnd / 2) &&
  1134 		    (net->ssthresh < net->cwnd - t_cwnd / 2)) {
  1135 			net->ssthresh = net->cwnd - t_cwnd / 2;
  1137 		if (net->ssthresh < net->mtu) {
  1138 			net->ssthresh = net->mtu;
  1140 	} else {
  1141 		net->ssthresh = max(net->cwnd / 2, 4 * net->mtu);
  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);
  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)
  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;
  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);
  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);
  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;
  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);
  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)
  1220 	uint32_t bw_avail;
  1221 	int rtt;
  1222 	unsigned int incr;
  1223 	int old_cwnd = net->cwnd;
  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;
  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;
  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;
  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;
  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;
  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;
  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;
  1294 		/* we will NOT back down more than 1 MTU */
  1295 		if (net->cwnd <= net->mtu) {
  1296 			net->cwnd = net->mtu;
  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;
  1310 		net->cwnd += incr;
  1312 	if (net->cwnd > bw_avail) {
  1313 		/* We can't exceed the pipe size */
  1314 		net->cwnd = bw_avail;
  1316 	if (net->cwnd < net->mtu) {
  1317 		/* We always have 1 MTU */
  1318 		net->cwnd = net->mtu;
  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);
  1337 static void
  1338 sctp_cwnd_update_after_output(struct sctp_tcb *stcb,
  1339 			      struct sctp_nets *net, int burst_limit)
  1341 	int old_cwnd = net->cwnd;
  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);
  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)
  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);
  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)
  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);
  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)
  1386 	sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 1);
  1390 static
  1391 void sctp_cwnd_update_rtcc_tsn_acknowledged(struct sctp_nets *net,
  1392 					    struct sctp_tmit_chunk *tp1)
  1394 	net->cc_mod.rtcc.bw_bytes += tp1->send_size;
  1397 static void
  1398 sctp_cwnd_prepare_rtcc_net_for_sack(struct sctp_tcb *stcb SCTP_UNUSED,
  1399 				    struct sctp_nets *net)
  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(&ltls);
  1405 		timevalsub(&ltls, &net->cc_mod.rtcc.tls);
  1406 		net->cc_mod.rtcc.new_tot_time = (ltls.tv_sec * 1000000) + ltls.tv_usec;
  1410 static void
  1411 sctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb *stcb,
  1412 				       struct sctp_nets *net)
  1414 #if defined(__FreeBSD__) && __FreeBSD_version >= 803000
  1415 	uint64_t vtag, probepoint;
  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;
  1446 		if (net->cc_mod.rtcc.ret_from_eq) {
  1447 			/* less aggressive one - reset cwnd too */
  1448 			uint32_t cwnd_in_mtu, cwnd;
  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;
  1463 			if (net->cwnd > cwnd) {
  1464 				/* Only set if we are not a timeout (i.e. down to 1 mtu) */
  1465 				net->cwnd = cwnd;
  1471 static void
  1472 sctp_set_rtcc_initial_cc_param(struct sctp_tcb *stcb,
  1473 			       struct sctp_nets *net)
  1475 #if defined(__FreeBSD__) && __FreeBSD_version >= 803000
  1476 	uint64_t vtag, probepoint;
  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;
  1512 static int
  1513 sctp_cwnd_rtcc_socket_option(struct sctp_tcb *stcb, int setorget,
  1514 			     struct sctp_cc_option *cc_opt)
  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);
  1524 			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1525 				net->cc_mod.rtcc.ret_from_eq = cc_opt->aid_value.assoc_value;
  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);
  1532 			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1533 				net->cc_mod.rtcc.use_dccc_ecn = cc_opt->aid_value.assoc_value;
  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;
  1539 		} else {
  1540 			return (EINVAL);
  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);
  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);
  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);
  1561 			cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.steady_step;
  1562 		} else {
  1563 			return (EINVAL);
  1566 	return (0);
  1569 static void
  1570 sctp_cwnd_update_rtcc_packet_transmitted(struct sctp_tcb *stcb SCTP_UNUSED,
  1571                                          struct sctp_nets *net)
  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;
  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)
  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);
  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)
  1593 	net->cc_mod.rtcc.rtt_set_this_sack = 1;
  1596 /* Here starts Sally Floyds HS-TCP */
  1598 struct sctp_hs_raise_drop {
  1599 	int32_t cwnd;
  1600 	int32_t increase;
  1601 	int32_t drop_percent;
  1602 };
  1604 #define SCTP_HS_TABLE_SIZE 73
  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 };
  1682 static void
  1683 sctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net)
  1685 	int cur_val, i, indx, incr;
  1687 	cur_val = net->cwnd >> 10;
  1688 	indx = SCTP_HS_TABLE_SIZE - 1;
  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);
  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);
  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;
  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);
  1719 static void
  1720 sctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net)
  1722 	int cur_val, i, indx;
  1723 	int old_cwnd = net->cwnd;
  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;
  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;
  1751 			net->last_hs_used = indx;
  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);
  1759 static void
  1760 sctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb,
  1761                              struct sctp_association *asoc)
  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;
  1781 				sctp_hs_cwnd_decrease(stcb, net);
  1783 				lchk = TAILQ_FIRST(&asoc->send_queue);
  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;
  1795 				/*
  1796 				 * CMT fast recovery -- per destination
  1797 				 * recovery variable.
  1798 				 */
  1799 				net->fast_retran_loss_recovery = 1;
  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;
  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);
  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);
  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)
  1828 	struct sctp_nets *net;
  1829 	/******************************/
  1830 	/* update cwnd and Early FR   */
  1831 	/******************************/
  1832 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
  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;
  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);
  1850 			continue;
  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
  1859 		 else if (sctp_cmt_on_off == 0 && asoc->fast_retran_loss_recovery && will_exit == 0) {
  1860 		*/
  1861 #endif
  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;
  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) {
  1883 					sctp_hs_cwnd_increase(stcb, net);
  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);
  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);
  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);
  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);
  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  */
  1928 static int use_rtt_scaling = 1;
  1929 static int use_bandwidth_switch = 1;
  1931 static inline int
  1932 between(uint32_t seq1, uint32_t seq2, uint32_t seq3)
  1934 	return (seq3 - seq2 >= seq1 - seq2);
  1937 static inline uint32_t
  1938 htcp_cong_time(struct htcp *ca)
  1940 	return (sctp_get_tick_count() - ca->last_cong);
  1943 static inline uint32_t
  1944 htcp_ccount(struct htcp *ca)
  1946 	return (htcp_cong_time(ca)/ca->minRTT);
  1949 static inline void
  1950 htcp_reset(struct htcp *ca)
  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();
  1958 #ifdef SCTP_NOT_USED
  1960 static uint32_t
  1961 htcp_cwnd_undo(struct sctp_tcb *stcb, struct sctp_nets *net)
  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));
  1969 #endif
  1971 static inline void
  1972 measure_rtt(struct sctp_nets *net)
  1974 	uint32_t srtt = net->lastsa>>SCTP_RTT_SHIFT;
  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;
  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;
  1989 static void
  1990 measure_achieved_throughput(struct sctp_nets *net)
  1992 	uint32_t now = sctp_get_tick_count();
  1994 	if (net->fast_retran_ip == 0)
  1995 		net->cc_mod.htcp_ca.bytes_acked = net->net_ack;
  1997 	if (!use_bandwidth_switch)
  1998 		return;
  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;
  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);
  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;
  2024 		net->cc_mod.htcp_ca.bytecount = 0;
  2025 		net->cc_mod.htcp_ca.lasttime = now;
  2029 static inline void
  2030 htcp_beta_update(struct htcp *ca, uint32_t minRTT, uint32_t maxRTT)
  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;
  2037 		if (!between(5*maxB, 4*old_maxB, 6*old_maxB)) {
  2038 			ca->beta = BETA_MIN;
  2039 			ca->modeswitch = 0;
  2040 			return;
  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;
  2056 static inline void
  2057 htcp_alpha_update(struct htcp *ca)
  2059 	uint32_t minRTT = ca->minRTT;
  2060 	uint32_t factor = 1;
  2061 	uint32_t diff = htcp_cong_time(ca);
  2063 	if (diff > (uint32_t)hz) {
  2064 		diff -= hz;
  2065 		factor = 1+ ( 10*diff + ((diff/2)*(diff/2)/hz))/hz;
  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;
  2076 	ca->alpha = 2*factor*((1<<7)-ca->beta);
  2077 	if (!ca->alpha)
  2078 		ca->alpha = ALPHA_BASE;
  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.
  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)
  2092 	uint32_t minRTT = net->cc_mod.htcp_ca.minRTT;
  2093 	uint32_t maxRTT = net->cc_mod.htcp_ca.maxRTT;
  2095 	htcp_beta_update(&net->cc_mod.htcp_ca, minRTT, maxRTT);
  2096 	htcp_alpha_update(&net->cc_mod.htcp_ca);
  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;
  2103 static uint32_t
  2104 htcp_recalc_ssthresh(struct sctp_nets *net)
  2106 	htcp_param_update(net);
  2107 	return (max(((net->cwnd/net->mtu * net->cc_mod.htcp_ca.beta) >> 7)*net->mtu, 2U*net->mtu));
  2110 static void
  2111 htcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net)
  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);
  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);
  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);
  2142 	} else {
  2143 		measure_rtt(net);
  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);
  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);
  2169 		net->cc_mod.htcp_ca.bytes_acked = net->mtu;
  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)
  2178 	return (net->ssthresh);
  2180 #endif
  2182 static void
  2183 htcp_init(struct sctp_nets *net)
  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();
  2192 static void
  2193 sctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
  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);
  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);
  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)
  2213 	struct sctp_nets *net;
  2215 	/******************************/
  2216 	/* update cwnd and Early FR   */
  2217 	/******************************/
  2218 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
  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;
  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);
  2236 			continue;
  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
  2245 		 else if (sctp_cmt_on_off == 0 && asoc->fast_retran_loss_recovery && will_exit == 0) {
  2246 		*/
  2247 #endif
  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;
  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);
  2275 static void
  2276 sctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb,
  2277 		struct sctp_association *asoc)
  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;
  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);
  2306 				lchk = TAILQ_FIRST(&asoc->send_queue);
  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;
  2318 				/*
  2319 				 * CMT fast recovery -- per destination
  2320 				 * recovery variable.
  2321 				 */
  2322 				net->fast_retran_loss_recovery = 1;
  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;
  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);
  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);
  2346 static void
  2347 sctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb,
  2348 	struct sctp_nets *net)
  2350 		int old_cwnd = net->cwnd;
  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);
  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)
  2366 	int old_cwnd;
  2367 	old_cwnd = net->cwnd;
  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;
  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);
  2386 struct sctp_cc_functions sctp_cc_functions[] = {
  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 },
  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 },
  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 },
  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
  2483 };

mercurial