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