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