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