1b54d3a6cSRandall Stewart /*-
251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni *
4b54d3a6cSRandall Stewart * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
5807aad63SMichael Tuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
6807aad63SMichael Tuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
7b54d3a6cSRandall Stewart *
8b54d3a6cSRandall Stewart * Redistribution and use in source and binary forms, with or without
9b54d3a6cSRandall Stewart * modification, are permitted provided that the following conditions are met:
10b54d3a6cSRandall Stewart *
11b54d3a6cSRandall Stewart * a) Redistributions of source code must retain the above copyright notice,
12b54d3a6cSRandall Stewart * this list of conditions and the following disclaimer.
13b54d3a6cSRandall Stewart *
14b54d3a6cSRandall Stewart * b) Redistributions in binary form must reproduce the above copyright
15b54d3a6cSRandall Stewart * notice, this list of conditions and the following disclaimer in
16b54d3a6cSRandall Stewart * the documentation and/or other materials provided with the distribution.
17b54d3a6cSRandall Stewart *
18b54d3a6cSRandall Stewart * c) Neither the name of Cisco Systems, Inc. nor the names of its
19b54d3a6cSRandall Stewart * contributors may be used to endorse or promote products derived
20b54d3a6cSRandall Stewart * from this software without specific prior written permission.
21b54d3a6cSRandall Stewart *
22b54d3a6cSRandall Stewart * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23b54d3a6cSRandall Stewart * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24b54d3a6cSRandall Stewart * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25b54d3a6cSRandall Stewart * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26b54d3a6cSRandall Stewart * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27b54d3a6cSRandall Stewart * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28b54d3a6cSRandall Stewart * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29b54d3a6cSRandall Stewart * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30b54d3a6cSRandall Stewart * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31b54d3a6cSRandall Stewart * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32b54d3a6cSRandall Stewart * THE POSSIBILITY OF SUCH DAMAGE.
33b54d3a6cSRandall Stewart */
34b54d3a6cSRandall Stewart
35b54d3a6cSRandall Stewart #include <netinet/sctp_os.h>
36b54d3a6cSRandall Stewart #include <netinet/sctp_var.h>
37b54d3a6cSRandall Stewart #include <netinet/sctp_sysctl.h>
38b54d3a6cSRandall Stewart #include <netinet/sctp_pcb.h>
39b54d3a6cSRandall Stewart #include <netinet/sctp_header.h>
40b54d3a6cSRandall Stewart #include <netinet/sctputil.h>
41b54d3a6cSRandall Stewart #include <netinet/sctp_output.h>
42b54d3a6cSRandall Stewart #include <netinet/sctp_input.h>
43b54d3a6cSRandall Stewart #include <netinet/sctp_indata.h>
44b54d3a6cSRandall Stewart #include <netinet/sctp_uio.h>
45b54d3a6cSRandall Stewart #include <netinet/sctp_timer.h>
46b54d3a6cSRandall Stewart #include <netinet/sctp_auth.h>
47b54d3a6cSRandall Stewart #include <netinet/sctp_asconf.h>
48fcfd8ad5SMichael Tuexen #include <netinet/sctp_kdtrace.h>
49dcfc0625SMichael Tuexen
50c3d72c80SMichael Tuexen #define SHIFT_MPTCP_MULTI_N 40
51c3d72c80SMichael Tuexen #define SHIFT_MPTCP_MULTI_Z 16
52c3d72c80SMichael Tuexen #define SHIFT_MPTCP_MULTI 8
53c3d72c80SMichael Tuexen
54*fb259f62SMichael Tuexen #ifdef KDTRACE_HOOKS
55db2ce691SMateusz Guzik #define __dtrace
56db2ce691SMateusz Guzik #else
57db2ce691SMateusz Guzik #define __dtrace __unused
58db2ce691SMateusz Guzik #endif
59db2ce691SMateusz Guzik
600e9a9c10SMichael Tuexen static void
sctp_enforce_cwnd_limit(struct sctp_association * assoc,struct sctp_nets * net)6159b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(struct sctp_association *assoc, struct sctp_nets *net)
6259b6d5beSMichael Tuexen {
6359b6d5beSMichael Tuexen if ((assoc->max_cwnd > 0) &&
6459b6d5beSMichael Tuexen (net->cwnd > assoc->max_cwnd) &&
6559b6d5beSMichael Tuexen (net->cwnd > (net->mtu - sizeof(struct sctphdr)))) {
6659b6d5beSMichael Tuexen net->cwnd = assoc->max_cwnd;
6759b6d5beSMichael Tuexen if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) {
6859b6d5beSMichael Tuexen net->cwnd = net->mtu - sizeof(struct sctphdr);
6959b6d5beSMichael Tuexen }
7059b6d5beSMichael Tuexen }
7159b6d5beSMichael Tuexen }
7259b6d5beSMichael Tuexen
7359b6d5beSMichael Tuexen static void
sctp_set_initial_cc_param(struct sctp_tcb * stcb,struct sctp_nets * net)74b54d3a6cSRandall Stewart sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
75b54d3a6cSRandall Stewart {
76dcfc0625SMichael Tuexen struct sctp_association *assoc;
77dcfc0625SMichael Tuexen uint32_t cwnd_in_mtu;
78b54d3a6cSRandall Stewart
79dcfc0625SMichael Tuexen assoc = &stcb->asoc;
80dcfc0625SMichael Tuexen cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd);
81060bd882SMichael Tuexen if (cwnd_in_mtu == 0) {
82060bd882SMichael Tuexen /* Using 0 means that the value of RFC 4960 is used. */
83060bd882SMichael Tuexen net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
84060bd882SMichael Tuexen } else {
85060bd882SMichael Tuexen /*
86060bd882SMichael Tuexen * We take the minimum of the burst limit and the initial
87060bd882SMichael Tuexen * congestion window.
88060bd882SMichael Tuexen */
89dcfc0625SMichael Tuexen if ((assoc->max_burst > 0) && (cwnd_in_mtu > assoc->max_burst))
90dcfc0625SMichael Tuexen cwnd_in_mtu = assoc->max_burst;
91dcfc0625SMichael Tuexen net->cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu;
92060bd882SMichael Tuexen }
93c3d72c80SMichael Tuexen if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) ||
94c3d72c80SMichael Tuexen (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2)) {
95ea8345d6SMichael Tuexen /* In case of resource pooling initialize appropriately */
96ea8345d6SMichael Tuexen net->cwnd /= assoc->numnets;
97ea8345d6SMichael Tuexen if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) {
98ea8345d6SMichael Tuexen net->cwnd = net->mtu - sizeof(struct sctphdr);
99ea8345d6SMichael Tuexen }
100ea8345d6SMichael Tuexen }
10159b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(assoc, net);
102dcfc0625SMichael Tuexen net->ssthresh = assoc->peers_rwnd;
10336160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, init,
1046324ca61SRandall Stewart stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
1056324ca61SRandall Stewart 0, net->cwnd);
106dcfc0625SMichael Tuexen if (SCTP_BASE_SYSCTL(sctp_logging_level) &
107dcfc0625SMichael Tuexen (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) {
108b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION);
109b54d3a6cSRandall Stewart }
110b54d3a6cSRandall Stewart }
111b54d3a6cSRandall Stewart
1120e9a9c10SMichael Tuexen static void
sctp_cwnd_update_after_fr(struct sctp_tcb * stcb,struct sctp_association * asoc)113b54d3a6cSRandall Stewart sctp_cwnd_update_after_fr(struct sctp_tcb *stcb,
114b54d3a6cSRandall Stewart struct sctp_association *asoc)
115b54d3a6cSRandall Stewart {
116b54d3a6cSRandall Stewart struct sctp_nets *net;
117ea8345d6SMichael Tuexen uint32_t t_ssthresh, t_cwnd;
118c3d72c80SMichael Tuexen uint64_t t_ucwnd_sbw;
119b54d3a6cSRandall Stewart
120ea8345d6SMichael Tuexen /* MT FIXME: Don't compute this over and over again */
121ea8345d6SMichael Tuexen t_ssthresh = 0;
122ea8345d6SMichael Tuexen t_cwnd = 0;
123c3d72c80SMichael Tuexen t_ucwnd_sbw = 0;
124c3d72c80SMichael Tuexen if ((asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) ||
125c3d72c80SMichael Tuexen (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2)) {
126ea8345d6SMichael Tuexen TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
127ea8345d6SMichael Tuexen t_ssthresh += net->ssthresh;
128ea8345d6SMichael Tuexen t_cwnd += net->cwnd;
129c3d72c80SMichael Tuexen if (net->lastsa > 0) {
130c3d72c80SMichael Tuexen t_ucwnd_sbw += (uint64_t)net->cwnd / (uint64_t)net->lastsa;
131c3d72c80SMichael Tuexen }
132c3d72c80SMichael Tuexen }
133c3d72c80SMichael Tuexen if (t_ucwnd_sbw == 0) {
134c3d72c80SMichael Tuexen t_ucwnd_sbw = 1;
135ea8345d6SMichael Tuexen }
136ea8345d6SMichael Tuexen }
1370053ed28SMichael Tuexen
138b54d3a6cSRandall Stewart /*-
1397c99d56fSMichael Tuexen * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) &&
140b54d3a6cSRandall Stewart * (net->fast_retran_loss_recovery == 0)))
141b54d3a6cSRandall Stewart */
142b54d3a6cSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
14320083c2eSMichael Tuexen if ((asoc->fast_retran_loss_recovery == 0) ||
1447c99d56fSMichael Tuexen (asoc->sctp_cmt_on_off > 0)) {
145b54d3a6cSRandall Stewart /* out of a RFC2582 Fast recovery window? */
146b54d3a6cSRandall Stewart if (net->net_ack > 0) {
147b54d3a6cSRandall Stewart /*
148b54d3a6cSRandall Stewart * per section 7.2.3, are there any
149b54d3a6cSRandall Stewart * destinations that had a fast retransmit
150b54d3a6cSRandall Stewart * to them. If so what we need to do is
151b54d3a6cSRandall Stewart * adjust ssthresh and cwnd.
152b54d3a6cSRandall Stewart */
153b54d3a6cSRandall Stewart struct sctp_tmit_chunk *lchk;
154b54d3a6cSRandall Stewart int old_cwnd = net->cwnd;
155b54d3a6cSRandall Stewart
156c3d72c80SMichael Tuexen if ((asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) ||
157c3d72c80SMichael Tuexen (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2)) {
158c3d72c80SMichael Tuexen if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) {
159ea8345d6SMichael Tuexen net->ssthresh = (uint32_t)(((uint64_t)4 *
160ea8345d6SMichael Tuexen (uint64_t)net->mtu *
161ea8345d6SMichael Tuexen (uint64_t)net->ssthresh) /
162ea8345d6SMichael Tuexen (uint64_t)t_ssthresh);
163c3d72c80SMichael Tuexen }
164c3d72c80SMichael Tuexen if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2) {
165c3d72c80SMichael Tuexen uint32_t srtt;
166c3d72c80SMichael Tuexen
167c3d72c80SMichael Tuexen srtt = net->lastsa;
168b7b84c0eSMichael Tuexen /*
169b7b84c0eSMichael Tuexen * lastsa>>3; we don't need
170b7b84c0eSMichael Tuexen * to devide ...
171b7b84c0eSMichael Tuexen */
172c3d72c80SMichael Tuexen if (srtt == 0) {
173c3d72c80SMichael Tuexen srtt = 1;
174c3d72c80SMichael Tuexen }
175b7b84c0eSMichael Tuexen /*
176b7b84c0eSMichael Tuexen * Short Version => Equal to
177b7b84c0eSMichael Tuexen * Contel Version MBe
178b7b84c0eSMichael Tuexen */
179c3d72c80SMichael Tuexen net->ssthresh = (uint32_t)(((uint64_t)4 *
180c3d72c80SMichael Tuexen (uint64_t)net->mtu *
181c3d72c80SMichael Tuexen (uint64_t)net->cwnd) /
182c3d72c80SMichael Tuexen ((uint64_t)srtt *
183c3d72c80SMichael Tuexen t_ucwnd_sbw));
184c3d72c80SMichael Tuexen /* INCREASE FACTOR */ ;
185c3d72c80SMichael Tuexen }
186ea8345d6SMichael Tuexen if ((net->cwnd > t_cwnd / 2) &&
187ea8345d6SMichael Tuexen (net->ssthresh < net->cwnd - t_cwnd / 2)) {
188ea8345d6SMichael Tuexen net->ssthresh = net->cwnd - t_cwnd / 2;
189ea8345d6SMichael Tuexen }
190ea8345d6SMichael Tuexen if (net->ssthresh < net->mtu) {
191ea8345d6SMichael Tuexen net->ssthresh = net->mtu;
192ea8345d6SMichael Tuexen }
193ea8345d6SMichael Tuexen } else {
194b54d3a6cSRandall Stewart net->ssthresh = net->cwnd / 2;
195b54d3a6cSRandall Stewart if (net->ssthresh < (net->mtu * 2)) {
196b54d3a6cSRandall Stewart net->ssthresh = 2 * net->mtu;
197b54d3a6cSRandall Stewart }
198ea8345d6SMichael Tuexen }
199b54d3a6cSRandall Stewart net->cwnd = net->ssthresh;
20059b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(asoc, net);
20136160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, fr,
2026324ca61SRandall Stewart stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
2036324ca61SRandall Stewart old_cwnd, net->cwnd);
204b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
205b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
206b54d3a6cSRandall Stewart SCTP_CWND_LOG_FROM_FR);
207b54d3a6cSRandall Stewart }
208b54d3a6cSRandall Stewart lchk = TAILQ_FIRST(&asoc->send_queue);
209b54d3a6cSRandall Stewart
210b54d3a6cSRandall Stewart net->partial_bytes_acked = 0;
211b54d3a6cSRandall Stewart /* Turn on fast recovery window */
212b54d3a6cSRandall Stewart asoc->fast_retran_loss_recovery = 1;
213b54d3a6cSRandall Stewart if (lchk == NULL) {
214b54d3a6cSRandall Stewart /* Mark end of the window */
215b54d3a6cSRandall Stewart asoc->fast_recovery_tsn = asoc->sending_seq - 1;
216b54d3a6cSRandall Stewart } else {
21749656eefSMichael Tuexen asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1;
218b54d3a6cSRandall Stewart }
219b54d3a6cSRandall Stewart
220b54d3a6cSRandall Stewart /*
221b54d3a6cSRandall Stewart * CMT fast recovery -- per destination
222b54d3a6cSRandall Stewart * recovery variable.
223b54d3a6cSRandall Stewart */
224b54d3a6cSRandall Stewart net->fast_retran_loss_recovery = 1;
225b54d3a6cSRandall Stewart
226b54d3a6cSRandall Stewart if (lchk == NULL) {
227b54d3a6cSRandall Stewart /* Mark end of the window */
228b54d3a6cSRandall Stewart net->fast_recovery_tsn = asoc->sending_seq - 1;
229b54d3a6cSRandall Stewart } else {
23049656eefSMichael Tuexen net->fast_recovery_tsn = lchk->rec.data.tsn - 1;
231b54d3a6cSRandall Stewart }
232b54d3a6cSRandall Stewart
233b54d3a6cSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
234b7d130beSMichael Tuexen stcb->sctp_ep, stcb, net,
235b7d130beSMichael Tuexen SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_1);
236b54d3a6cSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND,
237b54d3a6cSRandall Stewart stcb->sctp_ep, stcb, net);
238b54d3a6cSRandall Stewart }
239b54d3a6cSRandall Stewart } else if (net->net_ack > 0) {
240b54d3a6cSRandall Stewart /*
241b54d3a6cSRandall Stewart * Mark a peg that we WOULD have done a cwnd
242b54d3a6cSRandall Stewart * reduction but RFC2582 prevented this action.
243b54d3a6cSRandall Stewart */
244b54d3a6cSRandall Stewart SCTP_STAT_INCR(sctps_fastretransinrtt);
245b54d3a6cSRandall Stewart }
246b54d3a6cSRandall Stewart }
247b54d3a6cSRandall Stewart }
248b54d3a6cSRandall Stewart
249f79aab18SRandall Stewart /* Defines for instantaneous bw decisions */
250cd0a4ff6SPedro F. Giffuni #define SCTP_INST_LOOSING 1 /* Losing to other flows */
251f79aab18SRandall Stewart #define SCTP_INST_NEUTRAL 2 /* Neutral, no indication */
252f79aab18SRandall Stewart #define SCTP_INST_GAINING 3 /* Gaining, step down possible */
253f79aab18SRandall Stewart
254f79aab18SRandall Stewart 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)255f79aab18SRandall Stewart cc_bw_same(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw,
256f79aab18SRandall Stewart uint64_t rtt_offset, uint64_t vtag, uint8_t inst_ind)
257f79aab18SRandall Stewart {
258db2ce691SMateusz Guzik uint64_t oth __dtrace, probepoint __dtrace;
259f79aab18SRandall Stewart
260f79aab18SRandall Stewart probepoint = (((uint64_t)net->cwnd) << 32);
261f79aab18SRandall Stewart if (net->rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) {
262f79aab18SRandall Stewart /*
263f79aab18SRandall Stewart * rtt increased we don't update bw.. so we don't update the
264f79aab18SRandall Stewart * rtt either.
265f79aab18SRandall Stewart */
266f79aab18SRandall Stewart /* Probe point 5 */
267f79aab18SRandall Stewart probepoint |= ((5 << 16) | 1);
26836160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttvar,
269f79aab18SRandall Stewart vtag,
270f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw << 32) | nbw),
271f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
272f79aab18SRandall Stewart net->flight_size,
273f79aab18SRandall Stewart probepoint);
274f79aab18SRandall Stewart if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) {
275f79aab18SRandall Stewart if (net->cc_mod.rtcc.last_step_state == 5)
276f79aab18SRandall Stewart net->cc_mod.rtcc.step_cnt++;
277f79aab18SRandall Stewart else
278f79aab18SRandall Stewart net->cc_mod.rtcc.step_cnt = 1;
279f79aab18SRandall Stewart net->cc_mod.rtcc.last_step_state = 5;
280f79aab18SRandall Stewart if ((net->cc_mod.rtcc.step_cnt == net->cc_mod.rtcc.steady_step) ||
281f79aab18SRandall Stewart ((net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step) &&
282f79aab18SRandall Stewart ((net->cc_mod.rtcc.step_cnt % net->cc_mod.rtcc.steady_step) == 0))) {
283f79aab18SRandall Stewart /* Try a step down */
284f79aab18SRandall Stewart oth = net->cc_mod.rtcc.vol_reduce;
285f79aab18SRandall Stewart oth <<= 16;
286f79aab18SRandall Stewart oth |= net->cc_mod.rtcc.step_cnt;
287f79aab18SRandall Stewart oth <<= 16;
288f79aab18SRandall Stewart oth |= net->cc_mod.rtcc.last_step_state;
28936160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttstep,
290f79aab18SRandall Stewart vtag,
291f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw << 32) | nbw),
292f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
293f79aab18SRandall Stewart oth,
294f79aab18SRandall Stewart probepoint);
295f79aab18SRandall Stewart if (net->cwnd > (4 * net->mtu)) {
296f79aab18SRandall Stewart net->cwnd -= net->mtu;
297f79aab18SRandall Stewart net->cc_mod.rtcc.vol_reduce++;
298f79aab18SRandall Stewart } else {
299f79aab18SRandall Stewart net->cc_mod.rtcc.step_cnt = 0;
300f79aab18SRandall Stewart }
301f79aab18SRandall Stewart }
302f79aab18SRandall Stewart }
303f79aab18SRandall Stewart return (1);
304f79aab18SRandall Stewart }
305f79aab18SRandall Stewart if (net->rtt < net->cc_mod.rtcc.lbw_rtt - rtt_offset) {
306f79aab18SRandall Stewart /*
307f79aab18SRandall Stewart * rtt decreased, there could be more room. we update both
308f79aab18SRandall Stewart * the bw and the rtt here to lock this in as a good step
309f79aab18SRandall Stewart * down.
310f79aab18SRandall Stewart */
311f79aab18SRandall Stewart /* Probe point 6 */
312f79aab18SRandall Stewart probepoint |= ((6 << 16) | 0);
31336160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttvar,
314f79aab18SRandall Stewart vtag,
315f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw << 32) | nbw),
316f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
317f79aab18SRandall Stewart net->flight_size,
318f79aab18SRandall Stewart probepoint);
319f79aab18SRandall Stewart if (net->cc_mod.rtcc.steady_step) {
320f79aab18SRandall Stewart oth = net->cc_mod.rtcc.vol_reduce;
321f79aab18SRandall Stewart oth <<= 16;
322f79aab18SRandall Stewart oth |= net->cc_mod.rtcc.step_cnt;
323f79aab18SRandall Stewart oth <<= 16;
324f79aab18SRandall Stewart oth |= net->cc_mod.rtcc.last_step_state;
32536160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttstep,
326f79aab18SRandall Stewart vtag,
327f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw << 32) | nbw),
328f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
329f79aab18SRandall Stewart oth,
330f79aab18SRandall Stewart probepoint);
331f79aab18SRandall Stewart if ((net->cc_mod.rtcc.last_step_state == 5) &&
332f79aab18SRandall Stewart (net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step)) {
333f79aab18SRandall Stewart /* Step down worked */
334f79aab18SRandall Stewart net->cc_mod.rtcc.step_cnt = 0;
335f79aab18SRandall Stewart return (1);
336f79aab18SRandall Stewart } else {
337f79aab18SRandall Stewart net->cc_mod.rtcc.last_step_state = 6;
338f79aab18SRandall Stewart net->cc_mod.rtcc.step_cnt = 0;
339f79aab18SRandall Stewart }
340f79aab18SRandall Stewart }
341f79aab18SRandall Stewart net->cc_mod.rtcc.lbw = nbw;
342f79aab18SRandall Stewart net->cc_mod.rtcc.lbw_rtt = net->rtt;
343f79aab18SRandall Stewart net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd;
344f79aab18SRandall Stewart if (inst_ind == SCTP_INST_GAINING)
345f79aab18SRandall Stewart return (1);
346f79aab18SRandall Stewart else if (inst_ind == SCTP_INST_NEUTRAL)
347f79aab18SRandall Stewart return (1);
348f79aab18SRandall Stewart else
349f79aab18SRandall Stewart return (0);
350f79aab18SRandall Stewart }
351f79aab18SRandall Stewart /*
352f79aab18SRandall Stewart * Ok bw and rtt remained the same .. no update to any
353f79aab18SRandall Stewart */
354f79aab18SRandall Stewart /* Probe point 7 */
355f79aab18SRandall Stewart probepoint |= ((7 << 16) | net->cc_mod.rtcc.ret_from_eq);
35636160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttvar,
357f79aab18SRandall Stewart vtag,
358f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw << 32) | nbw),
359f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
360f79aab18SRandall Stewart net->flight_size,
361f79aab18SRandall Stewart probepoint);
362f79aab18SRandall Stewart if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) {
363f79aab18SRandall Stewart if (net->cc_mod.rtcc.last_step_state == 5)
364f79aab18SRandall Stewart net->cc_mod.rtcc.step_cnt++;
365f79aab18SRandall Stewart else
366f79aab18SRandall Stewart net->cc_mod.rtcc.step_cnt = 1;
367f79aab18SRandall Stewart net->cc_mod.rtcc.last_step_state = 5;
368f79aab18SRandall Stewart if ((net->cc_mod.rtcc.step_cnt == net->cc_mod.rtcc.steady_step) ||
369f79aab18SRandall Stewart ((net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step) &&
370f79aab18SRandall Stewart ((net->cc_mod.rtcc.step_cnt % net->cc_mod.rtcc.steady_step) == 0))) {
371f79aab18SRandall Stewart /* Try a step down */
372f79aab18SRandall Stewart if (net->cwnd > (4 * net->mtu)) {
373f79aab18SRandall Stewart net->cwnd -= net->mtu;
374f79aab18SRandall Stewart net->cc_mod.rtcc.vol_reduce++;
375f79aab18SRandall Stewart return (1);
376f79aab18SRandall Stewart } else {
377f79aab18SRandall Stewart net->cc_mod.rtcc.step_cnt = 0;
378f79aab18SRandall Stewart }
379f79aab18SRandall Stewart }
380f79aab18SRandall Stewart }
381f79aab18SRandall Stewart if (inst_ind == SCTP_INST_GAINING)
382f79aab18SRandall Stewart return (1);
383f79aab18SRandall Stewart else if (inst_ind == SCTP_INST_NEUTRAL)
384f79aab18SRandall Stewart return (1);
385f79aab18SRandall Stewart else
386f79aab18SRandall Stewart return ((int)net->cc_mod.rtcc.ret_from_eq);
387f79aab18SRandall Stewart }
388f79aab18SRandall Stewart
389f79aab18SRandall Stewart 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)390f79aab18SRandall Stewart cc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t rtt_offset,
391f79aab18SRandall Stewart uint64_t vtag, uint8_t inst_ind)
392f79aab18SRandall Stewart {
393db2ce691SMateusz Guzik uint64_t oth __dtrace, probepoint __dtrace;
394f79aab18SRandall Stewart
395f79aab18SRandall Stewart /* Bandwidth decreased. */
396f79aab18SRandall Stewart probepoint = (((uint64_t)net->cwnd) << 32);
397f79aab18SRandall Stewart if (net->rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) {
398f79aab18SRandall Stewart /* rtt increased */
399f79aab18SRandall Stewart /* Did we add more */
400f79aab18SRandall Stewart if ((net->cwnd > net->cc_mod.rtcc.cwnd_at_bw_set) &&
401f79aab18SRandall Stewart (inst_ind != SCTP_INST_LOOSING)) {
402f79aab18SRandall Stewart /* We caused it maybe.. back off? */
403f79aab18SRandall Stewart /* PROBE POINT 1 */
404f79aab18SRandall Stewart probepoint |= ((1 << 16) | 1);
40536160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttvar,
406f79aab18SRandall Stewart vtag,
407f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw << 32) | nbw),
408f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
409f79aab18SRandall Stewart net->flight_size,
410f79aab18SRandall Stewart probepoint);
411f79aab18SRandall Stewart if (net->cc_mod.rtcc.ret_from_eq) {
412b7b84c0eSMichael Tuexen /*
413b7b84c0eSMichael Tuexen * Switch over to CA if we are less
414b7b84c0eSMichael Tuexen * aggressive
415b7b84c0eSMichael Tuexen */
416f79aab18SRandall Stewart net->ssthresh = net->cwnd - 1;
417f79aab18SRandall Stewart net->partial_bytes_acked = 0;
418f79aab18SRandall Stewart }
419f79aab18SRandall Stewart return (1);
420f79aab18SRandall Stewart }
421f79aab18SRandall Stewart /* Probe point 2 */
422f79aab18SRandall Stewart probepoint |= ((2 << 16) | 0);
42336160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttvar,
424f79aab18SRandall Stewart vtag,
425f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw << 32) | nbw),
426f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
427f79aab18SRandall Stewart net->flight_size,
428f79aab18SRandall Stewart probepoint);
429f79aab18SRandall Stewart /* Someone else - fight for more? */
430f79aab18SRandall Stewart if (net->cc_mod.rtcc.steady_step) {
431f79aab18SRandall Stewart oth = net->cc_mod.rtcc.vol_reduce;
432f79aab18SRandall Stewart oth <<= 16;
433f79aab18SRandall Stewart oth |= net->cc_mod.rtcc.step_cnt;
434f79aab18SRandall Stewart oth <<= 16;
435f79aab18SRandall Stewart oth |= net->cc_mod.rtcc.last_step_state;
43636160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttstep,
437f79aab18SRandall Stewart vtag,
438f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw << 32) | nbw),
439f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
440f79aab18SRandall Stewart oth,
441f79aab18SRandall Stewart probepoint);
442f79aab18SRandall Stewart /*
443f79aab18SRandall Stewart * Did we voluntarily give up some? if so take one
444f79aab18SRandall Stewart * back please
445f79aab18SRandall Stewart */
446f79aab18SRandall Stewart if ((net->cc_mod.rtcc.vol_reduce) &&
447f79aab18SRandall Stewart (inst_ind != SCTP_INST_GAINING)) {
448f79aab18SRandall Stewart net->cwnd += net->mtu;
44959b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(&stcb->asoc, net);
450f79aab18SRandall Stewart net->cc_mod.rtcc.vol_reduce--;
451f79aab18SRandall Stewart }
452f79aab18SRandall Stewart net->cc_mod.rtcc.last_step_state = 2;
453f79aab18SRandall Stewart net->cc_mod.rtcc.step_cnt = 0;
454f79aab18SRandall Stewart }
455f79aab18SRandall Stewart goto out_decision;
456f79aab18SRandall Stewart } else if (net->rtt < net->cc_mod.rtcc.lbw_rtt - rtt_offset) {
457f79aab18SRandall Stewart /* bw & rtt decreased */
458f79aab18SRandall Stewart /* Probe point 3 */
459f79aab18SRandall Stewart probepoint |= ((3 << 16) | 0);
46036160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttvar,
461f79aab18SRandall Stewart vtag,
462f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw << 32) | nbw),
463f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
464f79aab18SRandall Stewart net->flight_size,
465f79aab18SRandall Stewart probepoint);
466f79aab18SRandall Stewart if (net->cc_mod.rtcc.steady_step) {
467f79aab18SRandall Stewart oth = net->cc_mod.rtcc.vol_reduce;
468f79aab18SRandall Stewart oth <<= 16;
469f79aab18SRandall Stewart oth |= net->cc_mod.rtcc.step_cnt;
470f79aab18SRandall Stewart oth <<= 16;
471f79aab18SRandall Stewart oth |= net->cc_mod.rtcc.last_step_state;
47236160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttstep,
473f79aab18SRandall Stewart vtag,
474f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw << 32) | nbw),
475f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
476f79aab18SRandall Stewart oth,
477f79aab18SRandall Stewart probepoint);
478f79aab18SRandall Stewart if ((net->cc_mod.rtcc.vol_reduce) &&
479f79aab18SRandall Stewart (inst_ind != SCTP_INST_GAINING)) {
480f79aab18SRandall Stewart net->cwnd += net->mtu;
48159b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(&stcb->asoc, net);
482f79aab18SRandall Stewart net->cc_mod.rtcc.vol_reduce--;
483f79aab18SRandall Stewart }
484f79aab18SRandall Stewart net->cc_mod.rtcc.last_step_state = 3;
485f79aab18SRandall Stewart net->cc_mod.rtcc.step_cnt = 0;
486f79aab18SRandall Stewart }
487f79aab18SRandall Stewart goto out_decision;
488f79aab18SRandall Stewart }
489f79aab18SRandall Stewart /* The bw decreased but rtt stayed the same */
490f79aab18SRandall Stewart /* Probe point 4 */
491f79aab18SRandall Stewart probepoint |= ((4 << 16) | 0);
49236160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttvar,
493f79aab18SRandall Stewart vtag,
494f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw << 32) | nbw),
495f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
496f79aab18SRandall Stewart net->flight_size,
497f79aab18SRandall Stewart probepoint);
498f79aab18SRandall Stewart if (net->cc_mod.rtcc.steady_step) {
499f79aab18SRandall Stewart oth = net->cc_mod.rtcc.vol_reduce;
500f79aab18SRandall Stewart oth <<= 16;
501f79aab18SRandall Stewart oth |= net->cc_mod.rtcc.step_cnt;
502f79aab18SRandall Stewart oth <<= 16;
503f79aab18SRandall Stewart oth |= net->cc_mod.rtcc.last_step_state;
50436160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttstep,
505f79aab18SRandall Stewart vtag,
506f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw << 32) | nbw),
507f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
508f79aab18SRandall Stewart oth,
509f79aab18SRandall Stewart probepoint);
510f79aab18SRandall Stewart if ((net->cc_mod.rtcc.vol_reduce) &&
511f79aab18SRandall Stewart (inst_ind != SCTP_INST_GAINING)) {
512f79aab18SRandall Stewart net->cwnd += net->mtu;
51359b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(&stcb->asoc, net);
514f79aab18SRandall Stewart net->cc_mod.rtcc.vol_reduce--;
515f79aab18SRandall Stewart }
516f79aab18SRandall Stewart net->cc_mod.rtcc.last_step_state = 4;
517f79aab18SRandall Stewart net->cc_mod.rtcc.step_cnt = 0;
518f79aab18SRandall Stewart }
519f79aab18SRandall Stewart out_decision:
520f79aab18SRandall Stewart net->cc_mod.rtcc.lbw = nbw;
521f79aab18SRandall Stewart net->cc_mod.rtcc.lbw_rtt = net->rtt;
522f79aab18SRandall Stewart net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd;
523f79aab18SRandall Stewart if (inst_ind == SCTP_INST_GAINING) {
524f79aab18SRandall Stewart return (1);
525f79aab18SRandall Stewart } else {
526f79aab18SRandall Stewart return (0);
527f79aab18SRandall Stewart }
528f79aab18SRandall Stewart }
529f79aab18SRandall Stewart
530f79aab18SRandall Stewart static int
cc_bw_increase(struct sctp_tcb * stcb,struct sctp_nets * net,uint64_t nbw,uint64_t vtag)5317215cc1bSMichael Tuexen cc_bw_increase(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t vtag)
532f79aab18SRandall Stewart {
533db2ce691SMateusz Guzik uint64_t oth __dtrace, probepoint __dtrace;
534f79aab18SRandall Stewart
535f79aab18SRandall Stewart /*
536f79aab18SRandall Stewart * BW increased, so update and return 0, since all actions in our
537f79aab18SRandall Stewart * table say to do the normal CC update. Note that we pay no
538f79aab18SRandall Stewart * attention to the inst_ind since our overall sum is increasing.
539f79aab18SRandall Stewart */
540f79aab18SRandall Stewart /* PROBE POINT 0 */
541f79aab18SRandall Stewart probepoint = (((uint64_t)net->cwnd) << 32);
54236160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttvar,
543f79aab18SRandall Stewart vtag,
544f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw << 32) | nbw),
545f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
546f79aab18SRandall Stewart net->flight_size,
547f79aab18SRandall Stewart probepoint);
548f79aab18SRandall Stewart if (net->cc_mod.rtcc.steady_step) {
549f79aab18SRandall Stewart oth = net->cc_mod.rtcc.vol_reduce;
550f79aab18SRandall Stewart oth <<= 16;
551f79aab18SRandall Stewart oth |= net->cc_mod.rtcc.step_cnt;
552f79aab18SRandall Stewart oth <<= 16;
553f79aab18SRandall Stewart oth |= net->cc_mod.rtcc.last_step_state;
55436160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttstep,
555f79aab18SRandall Stewart vtag,
556f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw << 32) | nbw),
557f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
558f79aab18SRandall Stewart oth,
559f79aab18SRandall Stewart probepoint);
560f79aab18SRandall Stewart net->cc_mod.rtcc.last_step_state = 0;
561f79aab18SRandall Stewart net->cc_mod.rtcc.step_cnt = 0;
562f79aab18SRandall Stewart net->cc_mod.rtcc.vol_reduce = 0;
563f79aab18SRandall Stewart }
564f79aab18SRandall Stewart net->cc_mod.rtcc.lbw = nbw;
565f79aab18SRandall Stewart net->cc_mod.rtcc.lbw_rtt = net->rtt;
566f79aab18SRandall Stewart net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd;
567f79aab18SRandall Stewart return (0);
568f79aab18SRandall Stewart }
56948b6c649SRandall Stewart
570cd0a4ff6SPedro F. Giffuni /* RTCC Algorithm to limit growth of cwnd, return
57148b6c649SRandall Stewart * true if you want to NOT allow cwnd growth
57248b6c649SRandall Stewart */
57348b6c649SRandall Stewart static int
cc_bw_limit(struct sctp_tcb * stcb,struct sctp_nets * net,uint64_t nbw)57448b6c649SRandall Stewart cc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw)
57548b6c649SRandall Stewart {
57660990c0cSMichael Tuexen uint64_t bw_offset, rtt_offset;
577db2ce691SMateusz Guzik uint64_t probepoint __dtrace, rtt, vtag;
578f79aab18SRandall Stewart uint64_t bytes_for_this_rtt, inst_bw;
579f79aab18SRandall Stewart uint64_t div, inst_off;
580f79aab18SRandall Stewart int bw_shift;
581f79aab18SRandall Stewart uint8_t inst_ind;
582f79aab18SRandall Stewart int ret;
58348b6c649SRandall Stewart
58448b6c649SRandall Stewart /*-
58548b6c649SRandall Stewart * Here we need to see if we want
58648b6c649SRandall Stewart * to limit cwnd growth due to increase
58748b6c649SRandall Stewart * in overall rtt but no increase in bw.
58848b6c649SRandall Stewart * We use the following table to figure
58948b6c649SRandall Stewart * out what we should do. When we return
59048b6c649SRandall Stewart * 0, cc update goes on as planned. If we
59148b6c649SRandall Stewart * return 1, then no cc update happens and cwnd
59248b6c649SRandall Stewart * stays where it is at.
59348b6c649SRandall Stewart * ----------------------------------
59448b6c649SRandall Stewart * BW | RTT | Action
59548b6c649SRandall Stewart * *********************************
59648b6c649SRandall Stewart * INC | INC | return 0
59748b6c649SRandall Stewart * ----------------------------------
59848b6c649SRandall Stewart * INC | SAME | return 0
59948b6c649SRandall Stewart * ----------------------------------
60048b6c649SRandall Stewart * INC | DECR | return 0
60148b6c649SRandall Stewart * ----------------------------------
60248b6c649SRandall Stewart * SAME | INC | return 1
60348b6c649SRandall Stewart * ----------------------------------
60448b6c649SRandall Stewart * SAME | SAME | return 1
60548b6c649SRandall Stewart * ----------------------------------
60648b6c649SRandall Stewart * SAME | DECR | return 0
60748b6c649SRandall Stewart * ----------------------------------
60848b6c649SRandall Stewart * DECR | INC | return 0 or 1 based on if we caused.
60948b6c649SRandall Stewart * ----------------------------------
61048b6c649SRandall Stewart * DECR | SAME | return 0
61148b6c649SRandall Stewart * ----------------------------------
61248b6c649SRandall Stewart * DECR | DECR | return 0
61348b6c649SRandall Stewart * ----------------------------------
61448b6c649SRandall Stewart *
61548b6c649SRandall Stewart * We are a bit fuzz on what an increase or
61648b6c649SRandall Stewart * decrease is. For BW it is the same if
61748b6c649SRandall Stewart * it did not change within 1/64th. For
61848b6c649SRandall Stewart * RTT it stayed the same if it did not
61948b6c649SRandall Stewart * change within 1/32nd
62048b6c649SRandall Stewart */
621f79aab18SRandall Stewart bw_shift = SCTP_BASE_SYSCTL(sctp_rttvar_bw);
62248b6c649SRandall Stewart rtt = stcb->asoc.my_vtag;
62348b6c649SRandall Stewart vtag = (rtt << 32) | (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | (stcb->rport);
62448b6c649SRandall Stewart probepoint = (((uint64_t)net->cwnd) << 32);
62548b6c649SRandall Stewart rtt = net->rtt;
626f79aab18SRandall Stewart if (net->cc_mod.rtcc.rtt_set_this_sack) {
627f79aab18SRandall Stewart net->cc_mod.rtcc.rtt_set_this_sack = 0;
628f79aab18SRandall Stewart bytes_for_this_rtt = net->cc_mod.rtcc.bw_bytes - net->cc_mod.rtcc.bw_bytes_at_last_rttc;
629f79aab18SRandall Stewart net->cc_mod.rtcc.bw_bytes_at_last_rttc = net->cc_mod.rtcc.bw_bytes;
630f79aab18SRandall Stewart if (net->rtt) {
631f79aab18SRandall Stewart div = net->rtt / 1000;
632f79aab18SRandall Stewart if (div) {
633f79aab18SRandall Stewart inst_bw = bytes_for_this_rtt / div;
634f79aab18SRandall Stewart inst_off = inst_bw >> bw_shift;
635f79aab18SRandall Stewart if (inst_bw > nbw)
636f79aab18SRandall Stewart inst_ind = SCTP_INST_GAINING;
637f79aab18SRandall Stewart else if ((inst_bw + inst_off) < nbw)
638f79aab18SRandall Stewart inst_ind = SCTP_INST_LOOSING;
639f79aab18SRandall Stewart else
640f79aab18SRandall Stewart inst_ind = SCTP_INST_NEUTRAL;
641f79aab18SRandall Stewart probepoint |= ((0xb << 16) | inst_ind);
642f79aab18SRandall Stewart } else {
64360990c0cSMichael Tuexen inst_ind = net->cc_mod.rtcc.last_inst_ind;
644f79aab18SRandall Stewart inst_bw = bytes_for_this_rtt / (uint64_t)(net->rtt);
645f79aab18SRandall Stewart /* Can't determine do not change */
646f79aab18SRandall Stewart probepoint |= ((0xc << 16) | inst_ind);
647f79aab18SRandall Stewart }
648f79aab18SRandall Stewart } else {
64960990c0cSMichael Tuexen inst_ind = net->cc_mod.rtcc.last_inst_ind;
650f79aab18SRandall Stewart inst_bw = bytes_for_this_rtt;
651f79aab18SRandall Stewart /* Can't determine do not change */
652f79aab18SRandall Stewart probepoint |= ((0xd << 16) | inst_ind);
653f79aab18SRandall Stewart }
65436160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttvar,
65548b6c649SRandall Stewart vtag,
656f79aab18SRandall Stewart ((nbw << 32) | inst_bw),
657f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | rtt),
658f79aab18SRandall Stewart net->flight_size,
65948b6c649SRandall Stewart probepoint);
660f79aab18SRandall Stewart } else {
661f79aab18SRandall Stewart /* No rtt measurement, use last one */
662f79aab18SRandall Stewart inst_ind = net->cc_mod.rtcc.last_inst_ind;
663f79aab18SRandall Stewart }
664f79aab18SRandall Stewart bw_offset = net->cc_mod.rtcc.lbw >> bw_shift;
665f79aab18SRandall Stewart if (nbw > net->cc_mod.rtcc.lbw + bw_offset) {
6667215cc1bSMichael Tuexen ret = cc_bw_increase(stcb, net, nbw, vtag);
667f79aab18SRandall Stewart goto out;
66848b6c649SRandall Stewart }
66948b6c649SRandall Stewart rtt_offset = net->cc_mod.rtcc.lbw_rtt >> SCTP_BASE_SYSCTL(sctp_rttvar_rtt);
67048b6c649SRandall Stewart if (nbw < net->cc_mod.rtcc.lbw - bw_offset) {
671f79aab18SRandall Stewart ret = cc_bw_decrease(stcb, net, nbw, rtt_offset, vtag, inst_ind);
672f79aab18SRandall Stewart goto out;
67348b6c649SRandall Stewart }
67448b6c649SRandall Stewart /*
67548b6c649SRandall Stewart * If we reach here then we are in a situation where the bw stayed
67648b6c649SRandall Stewart * the same.
67748b6c649SRandall Stewart */
678f79aab18SRandall Stewart ret = cc_bw_same(stcb, net, nbw, rtt_offset, vtag, inst_ind);
679f79aab18SRandall Stewart out:
680f79aab18SRandall Stewart net->cc_mod.rtcc.last_inst_ind = inst_ind;
681f79aab18SRandall Stewart return (ret);
68248b6c649SRandall Stewart }
68348b6c649SRandall Stewart
6840e9a9c10SMichael Tuexen 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)68548b6c649SRandall Stewart sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
686b54d3a6cSRandall Stewart struct sctp_association *asoc,
6877215cc1bSMichael Tuexen int accum_moved, int reneged_all SCTP_UNUSED, int will_exit, int use_rtcc)
688b54d3a6cSRandall Stewart {
689b54d3a6cSRandall Stewart struct sctp_nets *net;
690db2ce691SMateusz Guzik int old_cwnd __dtrace;
6913808ab73SMichael Tuexen uint32_t t_ssthresh, incr;
692c3d72c80SMichael Tuexen uint64_t t_ucwnd_sbw;
693c3d72c80SMichael Tuexen uint64_t t_path_mptcp;
694c3d72c80SMichael Tuexen uint64_t mptcp_like_alpha;
695c3d72c80SMichael Tuexen uint32_t srtt;
696c3d72c80SMichael Tuexen uint64_t max_path;
697b54d3a6cSRandall Stewart
698ea8345d6SMichael Tuexen /* MT FIXME: Don't compute this over and over again */
699ea8345d6SMichael Tuexen t_ssthresh = 0;
700c3d72c80SMichael Tuexen t_ucwnd_sbw = 0;
701c3d72c80SMichael Tuexen t_path_mptcp = 0;
702c3d72c80SMichael Tuexen mptcp_like_alpha = 1;
703c3d72c80SMichael Tuexen if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) ||
704c3d72c80SMichael Tuexen (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2) ||
705c3d72c80SMichael Tuexen (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_MPTCP)) {
706c3d72c80SMichael Tuexen max_path = 0;
707ea8345d6SMichael Tuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
708ea8345d6SMichael Tuexen t_ssthresh += net->ssthresh;
709c3d72c80SMichael Tuexen /* lastsa>>3; we don't need to devide ... */
710c3d72c80SMichael Tuexen srtt = net->lastsa;
711c3d72c80SMichael Tuexen if (srtt > 0) {
712c3d72c80SMichael Tuexen uint64_t tmp;
713c3d72c80SMichael Tuexen
714c3d72c80SMichael Tuexen t_ucwnd_sbw += (uint64_t)net->cwnd / (uint64_t)srtt;
715c3d72c80SMichael Tuexen t_path_mptcp += (((uint64_t)net->cwnd) << SHIFT_MPTCP_MULTI_Z) /
716c3d72c80SMichael Tuexen (((uint64_t)net->mtu) * (uint64_t)srtt);
717c3d72c80SMichael Tuexen tmp = (((uint64_t)net->cwnd) << SHIFT_MPTCP_MULTI_N) /
718c3d72c80SMichael Tuexen ((uint64_t)net->mtu * (uint64_t)(srtt * srtt));
719c3d72c80SMichael Tuexen if (tmp > max_path) {
720c3d72c80SMichael Tuexen max_path = tmp;
721c3d72c80SMichael Tuexen }
722c3d72c80SMichael Tuexen }
723c3d72c80SMichael Tuexen }
724c3d72c80SMichael Tuexen if (t_path_mptcp > 0) {
725c3d72c80SMichael Tuexen mptcp_like_alpha = max_path / (t_path_mptcp * t_path_mptcp);
726c3d72c80SMichael Tuexen } else {
727c3d72c80SMichael Tuexen mptcp_like_alpha = 1;
728ea8345d6SMichael Tuexen }
729ea8345d6SMichael Tuexen }
73060990c0cSMichael Tuexen if (t_ssthresh == 0) {
73160990c0cSMichael Tuexen t_ssthresh = 1;
73260990c0cSMichael Tuexen }
73360990c0cSMichael Tuexen if (t_ucwnd_sbw == 0) {
73460990c0cSMichael Tuexen t_ucwnd_sbw = 1;
73560990c0cSMichael Tuexen }
736b54d3a6cSRandall Stewart /******************************/
737b54d3a6cSRandall Stewart /* update cwnd and Early FR */
738b54d3a6cSRandall Stewart /******************************/
739b54d3a6cSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
740b54d3a6cSRandall Stewart #ifdef JANA_CMT_FAST_RECOVERY
741b54d3a6cSRandall Stewart /*
742b54d3a6cSRandall Stewart * CMT fast recovery code. Need to debug.
743b54d3a6cSRandall Stewart */
744b54d3a6cSRandall Stewart if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) {
745ea8345d6SMichael Tuexen if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) ||
746ea8345d6SMichael Tuexen SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) {
747b54d3a6cSRandall Stewart net->will_exit_fast_recovery = 1;
748b54d3a6cSRandall Stewart }
749b54d3a6cSRandall Stewart }
750b54d3a6cSRandall Stewart #endif
751b54d3a6cSRandall Stewart /* if nothing was acked on this destination skip it */
752b54d3a6cSRandall Stewart if (net->net_ack == 0) {
753b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
754b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK);
755b54d3a6cSRandall Stewart }
756b54d3a6cSRandall Stewart continue;
757b54d3a6cSRandall Stewart }
758b54d3a6cSRandall Stewart #ifdef JANA_CMT_FAST_RECOVERY
759b54d3a6cSRandall Stewart /*
760b54d3a6cSRandall Stewart * CMT fast recovery code
761b54d3a6cSRandall Stewart */
762b54d3a6cSRandall Stewart /*
7637c99d56fSMichael Tuexen * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery
7647c99d56fSMichael Tuexen * && net->will_exit_fast_recovery == 0) { @@@ Do something
7657c99d56fSMichael Tuexen * } else if (sctp_cmt_on_off == 0 &&
766b54d3a6cSRandall Stewart * asoc->fast_retran_loss_recovery && will_exit == 0) {
767b54d3a6cSRandall Stewart */
768b54d3a6cSRandall Stewart #endif
769b54d3a6cSRandall Stewart
77020083c2eSMichael Tuexen if (asoc->fast_retran_loss_recovery &&
77120083c2eSMichael Tuexen (will_exit == 0) &&
77220083c2eSMichael Tuexen (asoc->sctp_cmt_on_off == 0)) {
773b54d3a6cSRandall Stewart /*
774b54d3a6cSRandall Stewart * If we are in loss recovery we skip any cwnd
775b54d3a6cSRandall Stewart * update
776b54d3a6cSRandall Stewart */
777ca85e948SMichael Tuexen return;
778b54d3a6cSRandall Stewart }
779b54d3a6cSRandall Stewart /*
78048b6c649SRandall Stewart * Did any measurements go on for this network?
78148b6c649SRandall Stewart */
78248b6c649SRandall Stewart if (use_rtcc && (net->cc_mod.rtcc.tls_needs_set > 0)) {
78348b6c649SRandall Stewart uint64_t nbw;
78448b6c649SRandall Stewart
78548b6c649SRandall Stewart /*
78648b6c649SRandall Stewart * At this point our bw_bytes has been updated by
78748b6c649SRandall Stewart * incoming sack information.
78848b6c649SRandall Stewart *
78948b6c649SRandall Stewart * But our bw may not yet be set.
79048b6c649SRandall Stewart *
79148b6c649SRandall Stewart */
79248b6c649SRandall Stewart if ((net->cc_mod.rtcc.new_tot_time / 1000) > 0) {
79348b6c649SRandall Stewart nbw = net->cc_mod.rtcc.bw_bytes / (net->cc_mod.rtcc.new_tot_time / 1000);
79448b6c649SRandall Stewart } else {
79548b6c649SRandall Stewart nbw = net->cc_mod.rtcc.bw_bytes;
79648b6c649SRandall Stewart }
79748b6c649SRandall Stewart if (net->cc_mod.rtcc.lbw) {
79848b6c649SRandall Stewart if (cc_bw_limit(stcb, net, nbw)) {
79948b6c649SRandall Stewart /* Hold here, no update */
800ca85e948SMichael Tuexen continue;
80148b6c649SRandall Stewart }
80248b6c649SRandall Stewart } else {
803db2ce691SMateusz Guzik uint64_t vtag __dtrace, probepoint __dtrace;
80448b6c649SRandall Stewart
80548b6c649SRandall Stewart probepoint = (((uint64_t)net->cwnd) << 32);
80648b6c649SRandall Stewart probepoint |= ((0xa << 16) | 0);
80748b6c649SRandall Stewart vtag = (net->rtt << 32) |
80848b6c649SRandall Stewart (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) |
80948b6c649SRandall Stewart (stcb->rport);
81048b6c649SRandall Stewart
81136160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttvar,
81248b6c649SRandall Stewart vtag,
81348b6c649SRandall Stewart nbw,
814f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
815f79aab18SRandall Stewart net->flight_size,
81648b6c649SRandall Stewart probepoint);
81748b6c649SRandall Stewart net->cc_mod.rtcc.lbw = nbw;
81848b6c649SRandall Stewart net->cc_mod.rtcc.lbw_rtt = net->rtt;
819f79aab18SRandall Stewart if (net->cc_mod.rtcc.rtt_set_this_sack) {
820f79aab18SRandall Stewart net->cc_mod.rtcc.rtt_set_this_sack = 0;
821f79aab18SRandall Stewart net->cc_mod.rtcc.bw_bytes_at_last_rttc = net->cc_mod.rtcc.bw_bytes;
822f79aab18SRandall Stewart }
82348b6c649SRandall Stewart }
82448b6c649SRandall Stewart }
82548b6c649SRandall Stewart /*
826b54d3a6cSRandall Stewart * CMT: CUC algorithm. Update cwnd if pseudo-cumack has
827b54d3a6cSRandall Stewart * moved.
828b54d3a6cSRandall Stewart */
82920083c2eSMichael Tuexen if (accum_moved ||
8307c99d56fSMichael Tuexen ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) {
831b54d3a6cSRandall Stewart /* If the cumulative ack moved we can proceed */
832b54d3a6cSRandall Stewart if (net->cwnd <= net->ssthresh) {
833b54d3a6cSRandall Stewart /* We are in slow start */
834c54a18d2SRandall Stewart if (net->flight_size + net->net_ack >= net->cwnd) {
835ea8345d6SMichael Tuexen uint32_t limit;
836ea8345d6SMichael Tuexen
837c3d72c80SMichael Tuexen old_cwnd = net->cwnd;
838c3d72c80SMichael Tuexen switch (asoc->sctp_cmt_on_off) {
839c3d72c80SMichael Tuexen case SCTP_CMT_RPV1:
840ea8345d6SMichael Tuexen limit = (uint32_t)(((uint64_t)net->mtu *
841ea8345d6SMichael Tuexen (uint64_t)SCTP_BASE_SYSCTL(sctp_L2_abc_variable) *
842ea8345d6SMichael Tuexen (uint64_t)net->ssthresh) /
843ea8345d6SMichael Tuexen (uint64_t)t_ssthresh);
844ea8345d6SMichael Tuexen incr = (uint32_t)(((uint64_t)net->net_ack *
845ea8345d6SMichael Tuexen (uint64_t)net->ssthresh) /
846ea8345d6SMichael Tuexen (uint64_t)t_ssthresh);
847ea8345d6SMichael Tuexen if (incr > limit) {
848ea8345d6SMichael Tuexen incr = limit;
849ea8345d6SMichael Tuexen }
850ea8345d6SMichael Tuexen if (incr == 0) {
851ea8345d6SMichael Tuexen incr = 1;
852b54d3a6cSRandall Stewart }
853c3d72c80SMichael Tuexen break;
854c3d72c80SMichael Tuexen case SCTP_CMT_RPV2:
855b7b84c0eSMichael Tuexen /*
856b7b84c0eSMichael Tuexen * lastsa>>3; we don't need
857b7b84c0eSMichael Tuexen * to divide ...
858b7b84c0eSMichael Tuexen */
859c3d72c80SMichael Tuexen srtt = net->lastsa;
860c3d72c80SMichael Tuexen if (srtt == 0) {
861c3d72c80SMichael Tuexen srtt = 1;
862c3d72c80SMichael Tuexen }
863c3d72c80SMichael Tuexen limit = (uint32_t)(((uint64_t)net->mtu *
864c3d72c80SMichael Tuexen (uint64_t)SCTP_BASE_SYSCTL(sctp_L2_abc_variable) *
865c3d72c80SMichael Tuexen (uint64_t)net->cwnd) /
866c3d72c80SMichael Tuexen ((uint64_t)srtt * t_ucwnd_sbw));
867c3d72c80SMichael Tuexen /* INCREASE FACTOR */
868c3d72c80SMichael Tuexen incr = (uint32_t)(((uint64_t)net->net_ack *
869c3d72c80SMichael Tuexen (uint64_t)net->cwnd) /
870c3d72c80SMichael Tuexen ((uint64_t)srtt * t_ucwnd_sbw));
871c3d72c80SMichael Tuexen /* INCREASE FACTOR */
872c3d72c80SMichael Tuexen if (incr > limit) {
873c3d72c80SMichael Tuexen incr = limit;
874c3d72c80SMichael Tuexen }
875c3d72c80SMichael Tuexen if (incr == 0) {
876c3d72c80SMichael Tuexen incr = 1;
877c3d72c80SMichael Tuexen }
878c3d72c80SMichael Tuexen break;
879c3d72c80SMichael Tuexen case SCTP_CMT_MPTCP:
880c3d72c80SMichael Tuexen limit = (uint32_t)(((uint64_t)net->mtu *
881c3d72c80SMichael Tuexen mptcp_like_alpha *
882c3d72c80SMichael Tuexen (uint64_t)SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) >>
883c3d72c80SMichael Tuexen SHIFT_MPTCP_MULTI);
884c3d72c80SMichael Tuexen incr = (uint32_t)(((uint64_t)net->net_ack *
885c3d72c80SMichael Tuexen mptcp_like_alpha) >>
886c3d72c80SMichael Tuexen SHIFT_MPTCP_MULTI);
887c3d72c80SMichael Tuexen if (incr > limit) {
888c3d72c80SMichael Tuexen incr = limit;
889c3d72c80SMichael Tuexen }
890c3d72c80SMichael Tuexen if (incr > net->net_ack) {
891c3d72c80SMichael Tuexen incr = net->net_ack;
892c3d72c80SMichael Tuexen }
893c3d72c80SMichael Tuexen if (incr > net->mtu) {
894c3d72c80SMichael Tuexen incr = net->mtu;
895c3d72c80SMichael Tuexen }
896c3d72c80SMichael Tuexen break;
897c3d72c80SMichael Tuexen default:
898ea8345d6SMichael Tuexen incr = net->net_ack;
899ea8345d6SMichael Tuexen if (incr > net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) {
900ea8345d6SMichael Tuexen incr = net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable);
901ea8345d6SMichael Tuexen }
902c3d72c80SMichael Tuexen break;
903ea8345d6SMichael Tuexen }
904ea8345d6SMichael Tuexen net->cwnd += incr;
90559b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(asoc, net);
906ea8345d6SMichael Tuexen if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
907ea8345d6SMichael Tuexen sctp_log_cwnd(stcb, net, incr,
908ea8345d6SMichael Tuexen SCTP_CWND_LOG_FROM_SS);
909ea8345d6SMichael Tuexen }
91036160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, ack,
9116324ca61SRandall Stewart stcb->asoc.my_vtag,
9126324ca61SRandall Stewart ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
9136324ca61SRandall Stewart net,
9146324ca61SRandall Stewart old_cwnd, net->cwnd);
915b54d3a6cSRandall Stewart } else {
916b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
917b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, net->net_ack,
918b54d3a6cSRandall Stewart SCTP_CWND_LOG_NOADV_SS);
919b54d3a6cSRandall Stewart }
920b54d3a6cSRandall Stewart }
921b54d3a6cSRandall Stewart } else {
922b54d3a6cSRandall Stewart /* We are in congestion avoidance */
923b54d3a6cSRandall Stewart /*
924bfefd190SRandall Stewart * Add to pba
925b54d3a6cSRandall Stewart */
926c54a18d2SRandall Stewart net->partial_bytes_acked += net->net_ack;
927b54d3a6cSRandall Stewart
928bfefd190SRandall Stewart if ((net->flight_size + net->net_ack >= net->cwnd) &&
929bfefd190SRandall Stewart (net->partial_bytes_acked >= net->cwnd)) {
930bfefd190SRandall Stewart net->partial_bytes_acked -= net->cwnd;
9316324ca61SRandall Stewart old_cwnd = net->cwnd;
932c3d72c80SMichael Tuexen switch (asoc->sctp_cmt_on_off) {
933c3d72c80SMichael Tuexen case SCTP_CMT_RPV1:
934ea8345d6SMichael Tuexen incr = (uint32_t)(((uint64_t)net->mtu *
935ea8345d6SMichael Tuexen (uint64_t)net->ssthresh) /
936ea8345d6SMichael Tuexen (uint64_t)t_ssthresh);
937ea8345d6SMichael Tuexen if (incr == 0) {
938ea8345d6SMichael Tuexen incr = 1;
939ea8345d6SMichael Tuexen }
940c3d72c80SMichael Tuexen break;
941c3d72c80SMichael Tuexen case SCTP_CMT_RPV2:
942b7b84c0eSMichael Tuexen /*
943b7b84c0eSMichael Tuexen * lastsa>>3; we don't need
944b7b84c0eSMichael Tuexen * to divide ...
945b7b84c0eSMichael Tuexen */
946c3d72c80SMichael Tuexen srtt = net->lastsa;
947c3d72c80SMichael Tuexen if (srtt == 0) {
948c3d72c80SMichael Tuexen srtt = 1;
949c3d72c80SMichael Tuexen }
950c3d72c80SMichael Tuexen incr = (uint32_t)((uint64_t)net->mtu *
951c3d72c80SMichael Tuexen (uint64_t)net->cwnd /
952c3d72c80SMichael Tuexen ((uint64_t)srtt *
953c3d72c80SMichael Tuexen t_ucwnd_sbw));
954c3d72c80SMichael Tuexen /* INCREASE FACTOR */
955c3d72c80SMichael Tuexen if (incr == 0) {
956c3d72c80SMichael Tuexen incr = 1;
957c3d72c80SMichael Tuexen }
958c3d72c80SMichael Tuexen break;
959c3d72c80SMichael Tuexen case SCTP_CMT_MPTCP:
960c3d72c80SMichael Tuexen incr = (uint32_t)((mptcp_like_alpha *
961c3d72c80SMichael Tuexen (uint64_t)net->cwnd) >>
962c3d72c80SMichael Tuexen SHIFT_MPTCP_MULTI);
963c3d72c80SMichael Tuexen if (incr > net->mtu) {
964ea8345d6SMichael Tuexen incr = net->mtu;
965ea8345d6SMichael Tuexen }
966c3d72c80SMichael Tuexen break;
967c3d72c80SMichael Tuexen default:
968c3d72c80SMichael Tuexen incr = net->mtu;
969c3d72c80SMichael Tuexen break;
970c3d72c80SMichael Tuexen }
971ea8345d6SMichael Tuexen net->cwnd += incr;
97259b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(asoc, net);
97336160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, ack,
9746324ca61SRandall Stewart stcb->asoc.my_vtag,
9756324ca61SRandall Stewart ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
9766324ca61SRandall Stewart net,
9776324ca61SRandall Stewart old_cwnd, net->cwnd);
978b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
979b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, net->mtu,
980b54d3a6cSRandall Stewart SCTP_CWND_LOG_FROM_CA);
981b54d3a6cSRandall Stewart }
982b54d3a6cSRandall Stewart } else {
983b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
984b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, net->net_ack,
985b54d3a6cSRandall Stewart SCTP_CWND_LOG_NOADV_CA);
986b54d3a6cSRandall Stewart }
987b54d3a6cSRandall Stewart }
988b54d3a6cSRandall Stewart }
989b54d3a6cSRandall Stewart } else {
990b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
991b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, net->mtu,
992b54d3a6cSRandall Stewart SCTP_CWND_LOG_NO_CUMACK);
993b54d3a6cSRandall Stewart }
994b54d3a6cSRandall Stewart }
995b54d3a6cSRandall Stewart }
996b54d3a6cSRandall Stewart }
997ca85e948SMichael Tuexen
998ca85e948SMichael Tuexen static void
sctp_cwnd_update_exit_pf_common(struct sctp_tcb * stcb,struct sctp_nets * net)999ca85e948SMichael Tuexen sctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb, struct sctp_nets *net)
1000ca85e948SMichael Tuexen {
1001db2ce691SMateusz Guzik int old_cwnd __dtrace;
1002ca85e948SMichael Tuexen
1003ca85e948SMichael Tuexen old_cwnd = net->cwnd;
1004ca85e948SMichael Tuexen net->cwnd = net->mtu;
100536160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, ack,
1006ca85e948SMichael Tuexen stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
1007ca85e948SMichael Tuexen old_cwnd, net->cwnd);
1008ca85e948SMichael Tuexen SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
1009dd294dceSMichael Tuexen (void *)net, net->cwnd);
1010b54d3a6cSRandall Stewart }
1011ca85e948SMichael Tuexen
10120e9a9c10SMichael Tuexen static void
sctp_cwnd_update_after_timeout(struct sctp_tcb * stcb,struct sctp_nets * net)1013c54a18d2SRandall Stewart sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net)
1014b54d3a6cSRandall Stewart {
1015b54d3a6cSRandall Stewart int old_cwnd = net->cwnd;
1016ea8345d6SMichael Tuexen uint32_t t_ssthresh, t_cwnd;
1017c3d72c80SMichael Tuexen uint64_t t_ucwnd_sbw;
1018b54d3a6cSRandall Stewart
1019ea8345d6SMichael Tuexen /* MT FIXME: Don't compute this over and over again */
1020ea8345d6SMichael Tuexen t_ssthresh = 0;
1021ea8345d6SMichael Tuexen t_cwnd = 0;
1022c3d72c80SMichael Tuexen if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) ||
1023c3d72c80SMichael Tuexen (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2)) {
1024ea8345d6SMichael Tuexen struct sctp_nets *lnet;
1025c3d72c80SMichael Tuexen uint32_t srtt;
1026ea8345d6SMichael Tuexen
1027c3d72c80SMichael Tuexen t_ucwnd_sbw = 0;
1028ea8345d6SMichael Tuexen TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
1029ea8345d6SMichael Tuexen t_ssthresh += lnet->ssthresh;
1030ea8345d6SMichael Tuexen t_cwnd += lnet->cwnd;
1031c3d72c80SMichael Tuexen srtt = lnet->lastsa;
1032c3d72c80SMichael Tuexen /* lastsa>>3; we don't need to divide ... */
1033c3d72c80SMichael Tuexen if (srtt > 0) {
1034c3d72c80SMichael Tuexen t_ucwnd_sbw += (uint64_t)lnet->cwnd / (uint64_t)srtt;
1035ea8345d6SMichael Tuexen }
1036c3d72c80SMichael Tuexen }
103760990c0cSMichael Tuexen if (t_ssthresh < 1) {
103860990c0cSMichael Tuexen t_ssthresh = 1;
103960990c0cSMichael Tuexen }
1040c3d72c80SMichael Tuexen if (t_ucwnd_sbw < 1) {
1041c3d72c80SMichael Tuexen t_ucwnd_sbw = 1;
1042c3d72c80SMichael Tuexen }
1043c3d72c80SMichael Tuexen if (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) {
1044ea8345d6SMichael Tuexen net->ssthresh = (uint32_t)(((uint64_t)4 *
1045ea8345d6SMichael Tuexen (uint64_t)net->mtu *
1046ea8345d6SMichael Tuexen (uint64_t)net->ssthresh) /
1047ea8345d6SMichael Tuexen (uint64_t)t_ssthresh);
1048c3d72c80SMichael Tuexen } else {
1049c3d72c80SMichael Tuexen uint64_t cc_delta;
1050c3d72c80SMichael Tuexen
1051c3d72c80SMichael Tuexen srtt = net->lastsa;
1052c3d72c80SMichael Tuexen /* lastsa>>3; we don't need to divide ... */
1053c3d72c80SMichael Tuexen if (srtt == 0) {
1054c3d72c80SMichael Tuexen srtt = 1;
1055c3d72c80SMichael Tuexen }
1056c3d72c80SMichael Tuexen cc_delta = t_ucwnd_sbw * (uint64_t)srtt / 2;
1057c3d72c80SMichael Tuexen if (cc_delta < t_cwnd) {
1058c3d72c80SMichael Tuexen net->ssthresh = (uint32_t)((uint64_t)t_cwnd - cc_delta);
1059c3d72c80SMichael Tuexen } else {
1060c3d72c80SMichael Tuexen net->ssthresh = net->mtu;
1061c3d72c80SMichael Tuexen }
1062c3d72c80SMichael Tuexen }
1063ea8345d6SMichael Tuexen if ((net->cwnd > t_cwnd / 2) &&
1064ea8345d6SMichael Tuexen (net->ssthresh < net->cwnd - t_cwnd / 2)) {
1065ea8345d6SMichael Tuexen net->ssthresh = net->cwnd - t_cwnd / 2;
1066ea8345d6SMichael Tuexen }
1067ea8345d6SMichael Tuexen if (net->ssthresh < net->mtu) {
1068ea8345d6SMichael Tuexen net->ssthresh = net->mtu;
1069ea8345d6SMichael Tuexen }
1070ea8345d6SMichael Tuexen } else {
1071d18f7e0aSMichael Tuexen net->ssthresh = max(net->cwnd / 2, 4 * net->mtu);
1072ea8345d6SMichael Tuexen }
1073b54d3a6cSRandall Stewart net->cwnd = net->mtu;
1074c54a18d2SRandall Stewart net->partial_bytes_acked = 0;
107536160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, to,
10766324ca61SRandall Stewart stcb->asoc.my_vtag,
10776324ca61SRandall Stewart ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
10786324ca61SRandall Stewart net,
10796324ca61SRandall Stewart old_cwnd, net->cwnd);
1080b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1081b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX);
1082b54d3a6cSRandall Stewart }
1083c54a18d2SRandall Stewart }
1084c54a18d2SRandall Stewart
10850e9a9c10SMichael Tuexen 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)108648b6c649SRandall Stewart sctp_cwnd_update_after_ecn_echo_common(struct sctp_tcb *stcb, struct sctp_nets *net,
108748b6c649SRandall Stewart int in_window, int num_pkt_lost, int use_rtcc)
1088c54a18d2SRandall Stewart {
1089c54a18d2SRandall Stewart int old_cwnd = net->cwnd;
1090c54a18d2SRandall Stewart
109148b6c649SRandall Stewart if ((use_rtcc) && (net->lan_type == SCTP_LAN_LOCAL) && (net->cc_mod.rtcc.use_dccc_ecn)) {
109248b6c649SRandall Stewart /* Data center Congestion Control */
109348b6c649SRandall Stewart if (in_window == 0) {
109448b6c649SRandall Stewart /*
109548b6c649SRandall Stewart * Go to CA with the cwnd at the point we sent the
109648b6c649SRandall Stewart * TSN that was marked with a CE.
109748b6c649SRandall Stewart */
109848b6c649SRandall Stewart if (net->ecn_prev_cwnd < net->cwnd) {
109948b6c649SRandall Stewart /* Restore to prev cwnd */
110048b6c649SRandall Stewart net->cwnd = net->ecn_prev_cwnd - (net->mtu * num_pkt_lost);
110148b6c649SRandall Stewart } else {
110248b6c649SRandall Stewart /* Just cut in 1/2 */
110348b6c649SRandall Stewart net->cwnd /= 2;
110448b6c649SRandall Stewart }
110548b6c649SRandall Stewart /* Drop to CA */
110648b6c649SRandall Stewart net->ssthresh = net->cwnd - (num_pkt_lost * net->mtu);
110748b6c649SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
110848b6c649SRandall Stewart sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
110948b6c649SRandall Stewart }
111048b6c649SRandall Stewart } else {
1111b7b84c0eSMichael Tuexen /*
1112b7b84c0eSMichael Tuexen * Further tuning down required over the drastic
1113b7b84c0eSMichael Tuexen * original cut
1114b7b84c0eSMichael Tuexen */
111548b6c649SRandall Stewart net->ssthresh -= (net->mtu * num_pkt_lost);
111648b6c649SRandall Stewart net->cwnd -= (net->mtu * num_pkt_lost);
111748b6c649SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
111848b6c649SRandall Stewart sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
111948b6c649SRandall Stewart }
112048b6c649SRandall Stewart }
112148b6c649SRandall Stewart SCTP_STAT_INCR(sctps_ecnereducedcwnd);
112248b6c649SRandall Stewart } else {
1123493d8e5aSRandall Stewart if (in_window == 0) {
1124c54a18d2SRandall Stewart SCTP_STAT_INCR(sctps_ecnereducedcwnd);
1125c54a18d2SRandall Stewart net->ssthresh = net->cwnd / 2;
1126c54a18d2SRandall Stewart if (net->ssthresh < net->mtu) {
1127c54a18d2SRandall Stewart net->ssthresh = net->mtu;
1128b7b84c0eSMichael Tuexen /*
1129b7b84c0eSMichael Tuexen * here back off the timer as well, to slow
1130b7b84c0eSMichael Tuexen * us down
1131b7b84c0eSMichael Tuexen */
1132c54a18d2SRandall Stewart net->RTO <<= 1;
1133c54a18d2SRandall Stewart }
1134c54a18d2SRandall Stewart net->cwnd = net->ssthresh;
113536160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, ecn,
11366324ca61SRandall Stewart stcb->asoc.my_vtag,
11376324ca61SRandall Stewart ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
11386324ca61SRandall Stewart net,
11396324ca61SRandall Stewart old_cwnd, net->cwnd);
1140b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1141c54a18d2SRandall Stewart sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
1142c54a18d2SRandall Stewart }
1143c54a18d2SRandall Stewart }
1144493d8e5aSRandall Stewart }
1145c54a18d2SRandall Stewart
114648b6c649SRandall Stewart }
114748b6c649SRandall Stewart
11480e9a9c10SMichael Tuexen 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)1149c54a18d2SRandall Stewart sctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb,
1150c54a18d2SRandall Stewart struct sctp_nets *net, struct sctp_pktdrop_chunk *cp,
1151c54a18d2SRandall Stewart uint32_t *bottle_bw, uint32_t *on_queue)
1152c54a18d2SRandall Stewart {
1153c54a18d2SRandall Stewart uint32_t bw_avail;
1154dec0177dSRandall Stewart unsigned int incr;
1155c54a18d2SRandall Stewart int old_cwnd = net->cwnd;
1156c54a18d2SRandall Stewart
1157c54a18d2SRandall Stewart /* get bottle neck bw */
1158c54a18d2SRandall Stewart *bottle_bw = ntohl(cp->bottle_bw);
1159c54a18d2SRandall Stewart /* and whats on queue */
1160c54a18d2SRandall Stewart *on_queue = ntohl(cp->current_onq);
1161c54a18d2SRandall Stewart /*
1162c54a18d2SRandall Stewart * adjust the on-queue if our flight is more it could be that the
1163c54a18d2SRandall Stewart * router has not yet gotten data "in-flight" to it
1164c54a18d2SRandall Stewart */
1165667eb487SMichael Tuexen if (*on_queue < net->flight_size) {
1166c54a18d2SRandall Stewart *on_queue = net->flight_size;
1167667eb487SMichael Tuexen }
1168667eb487SMichael Tuexen /* rtt is measured in micro seconds, bottle_bw in bytes per second */
1169667eb487SMichael Tuexen bw_avail = (uint32_t)(((uint64_t)(*bottle_bw) * net->rtt) / (uint64_t)1000000);
1170c54a18d2SRandall Stewart if (bw_avail > *bottle_bw) {
1171c54a18d2SRandall Stewart /*
1172c54a18d2SRandall Stewart * Cap the growth to no more than the bottle neck. This can
1173c54a18d2SRandall Stewart * happen as RTT slides up due to queues. It also means if
1174c54a18d2SRandall Stewart * you have more than a 1 second RTT with a empty queue you
1175c54a18d2SRandall Stewart * will be limited to the bottle_bw per second no matter if
1176c54a18d2SRandall Stewart * other points have 1/2 the RTT and you could get more
1177c54a18d2SRandall Stewart * out...
1178c54a18d2SRandall Stewart */
1179c54a18d2SRandall Stewart bw_avail = *bottle_bw;
1180c54a18d2SRandall Stewart }
1181c54a18d2SRandall Stewart if (*on_queue > bw_avail) {
1182c54a18d2SRandall Stewart /*
1183c54a18d2SRandall Stewart * No room for anything else don't allow anything else to be
1184c54a18d2SRandall Stewart * "added to the fire".
1185c54a18d2SRandall Stewart */
1186c54a18d2SRandall Stewart int seg_inflight, seg_onqueue, my_portion;
1187c54a18d2SRandall Stewart
1188b54d3a6cSRandall Stewart net->partial_bytes_acked = 0;
1189c54a18d2SRandall Stewart /* how much are we over queue size? */
1190c54a18d2SRandall Stewart incr = *on_queue - bw_avail;
1191c54a18d2SRandall Stewart if (stcb->asoc.seen_a_sack_this_pkt) {
1192c54a18d2SRandall Stewart /*
1193c54a18d2SRandall Stewart * undo any cwnd adjustment that the sack might have
1194c54a18d2SRandall Stewart * made
1195c54a18d2SRandall Stewart */
1196c54a18d2SRandall Stewart net->cwnd = net->prev_cwnd;
1197c54a18d2SRandall Stewart }
1198c54a18d2SRandall Stewart /* Now how much of that is mine? */
1199c54a18d2SRandall Stewart seg_inflight = net->flight_size / net->mtu;
1200c54a18d2SRandall Stewart seg_onqueue = *on_queue / net->mtu;
1201c54a18d2SRandall Stewart my_portion = (incr * seg_inflight) / seg_onqueue;
1202c54a18d2SRandall Stewart
1203c54a18d2SRandall Stewart /* Have I made an adjustment already */
1204c54a18d2SRandall Stewart if (net->cwnd > net->flight_size) {
1205c54a18d2SRandall Stewart /*
1206c54a18d2SRandall Stewart * for this flight I made an adjustment we need to
1207c54a18d2SRandall Stewart * decrease the portion by a share our previous
1208c54a18d2SRandall Stewart * adjustment.
1209c54a18d2SRandall Stewart */
1210c54a18d2SRandall Stewart int diff_adj;
1211c54a18d2SRandall Stewart
1212c54a18d2SRandall Stewart diff_adj = net->cwnd - net->flight_size;
1213c54a18d2SRandall Stewart if (diff_adj > my_portion)
1214c54a18d2SRandall Stewart my_portion = 0;
1215c54a18d2SRandall Stewart else
1216c54a18d2SRandall Stewart my_portion -= diff_adj;
1217c54a18d2SRandall Stewart }
1218c54a18d2SRandall Stewart /*
1219c54a18d2SRandall Stewart * back down to the previous cwnd (assume we have had a sack
1220c54a18d2SRandall Stewart * before this packet). minus what ever portion of the
1221c54a18d2SRandall Stewart * overage is my fault.
1222c54a18d2SRandall Stewart */
1223c54a18d2SRandall Stewart net->cwnd -= my_portion;
1224c54a18d2SRandall Stewart
1225c54a18d2SRandall Stewart /* we will NOT back down more than 1 MTU */
1226c54a18d2SRandall Stewart if (net->cwnd <= net->mtu) {
1227c54a18d2SRandall Stewart net->cwnd = net->mtu;
1228c54a18d2SRandall Stewart }
1229c54a18d2SRandall Stewart /* force into CA */
1230c54a18d2SRandall Stewart net->ssthresh = net->cwnd - 1;
1231c54a18d2SRandall Stewart } else {
1232c54a18d2SRandall Stewart /*
1233c54a18d2SRandall Stewart * Take 1/4 of the space left or max burst up .. whichever
1234c54a18d2SRandall Stewart * is less.
1235c54a18d2SRandall Stewart */
123690fed1d8SMichael Tuexen incr = (bw_avail - *on_queue) >> 2;
123790fed1d8SMichael Tuexen if ((stcb->asoc.max_burst > 0) &&
123890fed1d8SMichael Tuexen (stcb->asoc.max_burst * net->mtu < incr)) {
123990fed1d8SMichael Tuexen incr = stcb->asoc.max_burst * net->mtu;
124090fed1d8SMichael Tuexen }
1241c54a18d2SRandall Stewart net->cwnd += incr;
1242c54a18d2SRandall Stewart }
1243c54a18d2SRandall Stewart if (net->cwnd > bw_avail) {
1244c54a18d2SRandall Stewart /* We can't exceed the pipe size */
1245c54a18d2SRandall Stewart net->cwnd = bw_avail;
1246c54a18d2SRandall Stewart }
1247c54a18d2SRandall Stewart if (net->cwnd < net->mtu) {
1248c54a18d2SRandall Stewart /* We always have 1 MTU */
1249c54a18d2SRandall Stewart net->cwnd = net->mtu;
1250c54a18d2SRandall Stewart }
125159b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(&stcb->asoc, net);
1252c54a18d2SRandall Stewart if (net->cwnd - old_cwnd != 0) {
1253c54a18d2SRandall Stewart /* log only changes */
125436160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, pd,
12556324ca61SRandall Stewart stcb->asoc.my_vtag,
12566324ca61SRandall Stewart ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
12576324ca61SRandall Stewart net,
12586324ca61SRandall Stewart old_cwnd, net->cwnd);
1259b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1260c54a18d2SRandall Stewart sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
1261c54a18d2SRandall Stewart SCTP_CWND_LOG_FROM_SAT);
1262c54a18d2SRandall Stewart }
1263c54a18d2SRandall Stewart }
1264c54a18d2SRandall Stewart }
1265c54a18d2SRandall Stewart
12660e9a9c10SMichael Tuexen static void
sctp_cwnd_update_after_output(struct sctp_tcb * stcb,struct sctp_nets * net,int burst_limit)1267c54a18d2SRandall Stewart sctp_cwnd_update_after_output(struct sctp_tcb *stcb,
1268c54a18d2SRandall Stewart struct sctp_nets *net, int burst_limit)
1269c54a18d2SRandall Stewart {
1270c54a18d2SRandall Stewart int old_cwnd = net->cwnd;
1271c54a18d2SRandall Stewart
1272c54a18d2SRandall Stewart if (net->ssthresh < net->cwnd)
1273c54a18d2SRandall Stewart net->ssthresh = net->cwnd;
127448b6c649SRandall Stewart if (burst_limit) {
1275c54a18d2SRandall Stewart net->cwnd = (net->flight_size + (burst_limit * net->mtu));
127659b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(&stcb->asoc, net);
127736160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, bl,
12786324ca61SRandall Stewart stcb->asoc.my_vtag,
12796324ca61SRandall Stewart ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
12806324ca61SRandall Stewart net,
12816324ca61SRandall Stewart old_cwnd, net->cwnd);
1282b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1283c54a18d2SRandall Stewart sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST);
1284c54a18d2SRandall Stewart }
1285c54a18d2SRandall Stewart }
128648b6c649SRandall Stewart }
1287c54a18d2SRandall Stewart
12880e9a9c10SMichael Tuexen static void
sctp_cwnd_update_after_sack(struct sctp_tcb * stcb,struct sctp_association * asoc,int accum_moved,int reneged_all,int will_exit)128948b6c649SRandall Stewart sctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
129048b6c649SRandall Stewart struct sctp_association *asoc,
129148b6c649SRandall Stewart int accum_moved, int reneged_all, int will_exit)
129248b6c649SRandall Stewart {
1293cd0a4ff6SPedro F. Giffuni /* Passing a zero argument in last disables the rtcc algorithm */
129448b6c649SRandall Stewart sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 0);
129548b6c649SRandall Stewart }
129648b6c649SRandall Stewart
129748b6c649SRandall Stewart static void
sctp_cwnd_update_after_ecn_echo(struct sctp_tcb * stcb,struct sctp_nets * net,int in_window,int num_pkt_lost)129848b6c649SRandall Stewart sctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
129948b6c649SRandall Stewart int in_window, int num_pkt_lost)
130048b6c649SRandall Stewart {
1301cd0a4ff6SPedro F. Giffuni /* Passing a zero argument in last disables the rtcc algorithm */
130248b6c649SRandall Stewart sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 0);
130348b6c649SRandall Stewart }
130448b6c649SRandall Stewart
130548b6c649SRandall Stewart /* Here starts the RTCCVAR type CC invented by RRS which
130648b6c649SRandall Stewart * is a slight mod to RFC2581. We reuse a common routine or
1307cd0a4ff6SPedro F. Giffuni * two since these algorithms are so close and need to
130848b6c649SRandall Stewart * remain the same.
130948b6c649SRandall Stewart */
131048b6c649SRandall Stewart static void
sctp_cwnd_update_rtcc_after_ecn_echo(struct sctp_tcb * stcb,struct sctp_nets * net,int in_window,int num_pkt_lost)131148b6c649SRandall Stewart sctp_cwnd_update_rtcc_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
131248b6c649SRandall Stewart int in_window, int num_pkt_lost)
131348b6c649SRandall Stewart {
131448b6c649SRandall Stewart sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 1);
131548b6c649SRandall Stewart }
131648b6c649SRandall Stewart
1317b6db274dSMichael Tuexen static void
sctp_cwnd_update_rtcc_tsn_acknowledged(struct sctp_nets * net,struct sctp_tmit_chunk * tp1)131848b6c649SRandall Stewart sctp_cwnd_update_rtcc_tsn_acknowledged(struct sctp_nets *net,
131948b6c649SRandall Stewart struct sctp_tmit_chunk *tp1)
132048b6c649SRandall Stewart {
132148b6c649SRandall Stewart net->cc_mod.rtcc.bw_bytes += tp1->send_size;
132248b6c649SRandall Stewart }
132348b6c649SRandall Stewart
132448b6c649SRandall Stewart static void
sctp_cwnd_prepare_rtcc_net_for_sack(struct sctp_tcb * stcb SCTP_UNUSED,struct sctp_nets * net)13257215cc1bSMichael Tuexen sctp_cwnd_prepare_rtcc_net_for_sack(struct sctp_tcb *stcb SCTP_UNUSED,
132648b6c649SRandall Stewart struct sctp_nets *net)
132748b6c649SRandall Stewart {
132848b6c649SRandall Stewart if (net->cc_mod.rtcc.tls_needs_set > 0) {
1329e7e65008SMichael Tuexen /* We had a bw measurement going on */
133048b6c649SRandall Stewart struct timeval ltls;
133148b6c649SRandall Stewart
133248b6c649SRandall Stewart SCTP_GETPTIME_TIMEVAL(<ls);
133348b6c649SRandall Stewart timevalsub(<ls, &net->cc_mod.rtcc.tls);
133448b6c649SRandall Stewart net->cc_mod.rtcc.new_tot_time = (ltls.tv_sec * 1000000) + ltls.tv_usec;
133548b6c649SRandall Stewart }
133648b6c649SRandall Stewart }
133748b6c649SRandall Stewart
133848b6c649SRandall Stewart static void
sctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb * stcb,struct sctp_nets * net)133948b6c649SRandall Stewart sctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb *stcb,
134048b6c649SRandall Stewart struct sctp_nets *net)
134148b6c649SRandall Stewart {
1342db2ce691SMateusz Guzik uint64_t vtag __dtrace, probepoint __dtrace;
134348b6c649SRandall Stewart
134448b6c649SRandall Stewart if (net->cc_mod.rtcc.lbw) {
134548b6c649SRandall Stewart /* Clear the old bw.. we went to 0 in-flight */
134648b6c649SRandall Stewart vtag = (net->rtt << 32) | (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) |
134748b6c649SRandall Stewart (stcb->rport);
134848b6c649SRandall Stewart probepoint = (((uint64_t)net->cwnd) << 32);
134948b6c649SRandall Stewart /* Probe point 8 */
135048b6c649SRandall Stewart probepoint |= ((8 << 16) | 0);
135136160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttvar,
135248b6c649SRandall Stewart vtag,
135348b6c649SRandall Stewart ((net->cc_mod.rtcc.lbw << 32) | 0),
1354f79aab18SRandall Stewart ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
1355f79aab18SRandall Stewart net->flight_size,
135648b6c649SRandall Stewart probepoint);
135748b6c649SRandall Stewart net->cc_mod.rtcc.lbw_rtt = 0;
135848b6c649SRandall Stewart net->cc_mod.rtcc.cwnd_at_bw_set = 0;
135948b6c649SRandall Stewart net->cc_mod.rtcc.lbw = 0;
1360f79aab18SRandall Stewart net->cc_mod.rtcc.bw_bytes_at_last_rttc = 0;
1361f79aab18SRandall Stewart net->cc_mod.rtcc.vol_reduce = 0;
136248b6c649SRandall Stewart net->cc_mod.rtcc.bw_tot_time = 0;
136348b6c649SRandall Stewart net->cc_mod.rtcc.bw_bytes = 0;
136448b6c649SRandall Stewart net->cc_mod.rtcc.tls_needs_set = 0;
1365f79aab18SRandall Stewart if (net->cc_mod.rtcc.steady_step) {
1366f79aab18SRandall Stewart net->cc_mod.rtcc.vol_reduce = 0;
1367f79aab18SRandall Stewart net->cc_mod.rtcc.step_cnt = 0;
1368f79aab18SRandall Stewart net->cc_mod.rtcc.last_step_state = 0;
1369f79aab18SRandall Stewart }
137048b6c649SRandall Stewart if (net->cc_mod.rtcc.ret_from_eq) {
137148b6c649SRandall Stewart /* less aggressive one - reset cwnd too */
137248b6c649SRandall Stewart uint32_t cwnd_in_mtu, cwnd;
137348b6c649SRandall Stewart
137448b6c649SRandall Stewart cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd);
137548b6c649SRandall Stewart if (cwnd_in_mtu == 0) {
1376b7b84c0eSMichael Tuexen /*
1377b7b84c0eSMichael Tuexen * Using 0 means that the value of RFC 4960
1378b7b84c0eSMichael Tuexen * is used.
1379b7b84c0eSMichael Tuexen */
138048b6c649SRandall Stewart cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
138148b6c649SRandall Stewart } else {
138248b6c649SRandall Stewart /*
138348b6c649SRandall Stewart * We take the minimum of the burst limit
138448b6c649SRandall Stewart * and the initial congestion window.
138548b6c649SRandall Stewart */
138648b6c649SRandall Stewart if ((stcb->asoc.max_burst > 0) && (cwnd_in_mtu > stcb->asoc.max_burst))
138748b6c649SRandall Stewart cwnd_in_mtu = stcb->asoc.max_burst;
138848b6c649SRandall Stewart cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu;
138948b6c649SRandall Stewart }
139048b6c649SRandall Stewart if (net->cwnd > cwnd) {
1391b7b84c0eSMichael Tuexen /*
1392b7b84c0eSMichael Tuexen * Only set if we are not a timeout (i.e.
1393b7b84c0eSMichael Tuexen * down to 1 mtu)
1394b7b84c0eSMichael Tuexen */
139548b6c649SRandall Stewart net->cwnd = cwnd;
139648b6c649SRandall Stewart }
139748b6c649SRandall Stewart }
139848b6c649SRandall Stewart }
139948b6c649SRandall Stewart }
140048b6c649SRandall Stewart
140148b6c649SRandall Stewart static void
sctp_set_rtcc_initial_cc_param(struct sctp_tcb * stcb,struct sctp_nets * net)140248b6c649SRandall Stewart sctp_set_rtcc_initial_cc_param(struct sctp_tcb *stcb,
140348b6c649SRandall Stewart struct sctp_nets *net)
140448b6c649SRandall Stewart {
1405*fb259f62SMichael Tuexen uint64_t vtag __dtrace, probepoint __dtrace;
140648b6c649SRandall Stewart
140748b6c649SRandall Stewart sctp_set_initial_cc_param(stcb, net);
140848b6c649SRandall Stewart stcb->asoc.use_precise_time = 1;
140948b6c649SRandall Stewart probepoint = (((uint64_t)net->cwnd) << 32);
141048b6c649SRandall Stewart probepoint |= ((9 << 16) | 0);
141148b6c649SRandall Stewart vtag = (net->rtt << 32) |
141248b6c649SRandall Stewart (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) |
141348b6c649SRandall Stewart (stcb->rport);
141436160958SMark Johnston SDT_PROBE5(sctp, cwnd, net, rttvar,
141548b6c649SRandall Stewart vtag,
141648b6c649SRandall Stewart 0,
141748b6c649SRandall Stewart 0,
141848b6c649SRandall Stewart 0,
141948b6c649SRandall Stewart probepoint);
142048b6c649SRandall Stewart net->cc_mod.rtcc.lbw_rtt = 0;
142148b6c649SRandall Stewart net->cc_mod.rtcc.cwnd_at_bw_set = 0;
1422f79aab18SRandall Stewart net->cc_mod.rtcc.vol_reduce = 0;
142348b6c649SRandall Stewart net->cc_mod.rtcc.lbw = 0;
1424f79aab18SRandall Stewart net->cc_mod.rtcc.vol_reduce = 0;
1425f79aab18SRandall Stewart net->cc_mod.rtcc.bw_bytes_at_last_rttc = 0;
142648b6c649SRandall Stewart net->cc_mod.rtcc.bw_tot_time = 0;
142748b6c649SRandall Stewart net->cc_mod.rtcc.bw_bytes = 0;
142848b6c649SRandall Stewart net->cc_mod.rtcc.tls_needs_set = 0;
142948b6c649SRandall Stewart net->cc_mod.rtcc.ret_from_eq = SCTP_BASE_SYSCTL(sctp_rttvar_eqret);
1430f79aab18SRandall Stewart net->cc_mod.rtcc.steady_step = SCTP_BASE_SYSCTL(sctp_steady_step);
1431f79aab18SRandall Stewart net->cc_mod.rtcc.use_dccc_ecn = SCTP_BASE_SYSCTL(sctp_use_dccc_ecn);
1432f79aab18SRandall Stewart net->cc_mod.rtcc.step_cnt = 0;
1433f79aab18SRandall Stewart net->cc_mod.rtcc.last_step_state = 0;
143448b6c649SRandall Stewart }
143548b6c649SRandall Stewart
143648b6c649SRandall Stewart static int
sctp_cwnd_rtcc_socket_option(struct sctp_tcb * stcb,int setorget,struct sctp_cc_option * cc_opt)143748b6c649SRandall Stewart sctp_cwnd_rtcc_socket_option(struct sctp_tcb *stcb, int setorget,
143848b6c649SRandall Stewart struct sctp_cc_option *cc_opt)
143948b6c649SRandall Stewart {
144048b6c649SRandall Stewart struct sctp_nets *net;
144148b6c649SRandall Stewart
144248b6c649SRandall Stewart if (setorget == 1) {
144348b6c649SRandall Stewart /* a set */
144448b6c649SRandall Stewart if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) {
144548b6c649SRandall Stewart if ((cc_opt->aid_value.assoc_value != 0) &&
144648b6c649SRandall Stewart (cc_opt->aid_value.assoc_value != 1)) {
144748b6c649SRandall Stewart return (EINVAL);
144848b6c649SRandall Stewart }
144948b6c649SRandall Stewart TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
145048b6c649SRandall Stewart net->cc_mod.rtcc.ret_from_eq = cc_opt->aid_value.assoc_value;
145148b6c649SRandall Stewart }
145248b6c649SRandall Stewart } else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) {
145348b6c649SRandall Stewart if ((cc_opt->aid_value.assoc_value != 0) &&
145448b6c649SRandall Stewart (cc_opt->aid_value.assoc_value != 1)) {
145548b6c649SRandall Stewart return (EINVAL);
145648b6c649SRandall Stewart }
145748b6c649SRandall Stewart TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
145848b6c649SRandall Stewart net->cc_mod.rtcc.use_dccc_ecn = cc_opt->aid_value.assoc_value;
145948b6c649SRandall Stewart }
1460f79aab18SRandall Stewart } else if (cc_opt->option == SCTP_CC_OPT_STEADY_STEP) {
1461f79aab18SRandall Stewart TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1462f79aab18SRandall Stewart net->cc_mod.rtcc.steady_step = cc_opt->aid_value.assoc_value;
1463f79aab18SRandall Stewart }
146448b6c649SRandall Stewart } else {
146548b6c649SRandall Stewart return (EINVAL);
146648b6c649SRandall Stewart }
146748b6c649SRandall Stewart } else {
146848b6c649SRandall Stewart /* a get */
146948b6c649SRandall Stewart if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) {
147048b6c649SRandall Stewart net = TAILQ_FIRST(&stcb->asoc.nets);
147148b6c649SRandall Stewart if (net == NULL) {
147248b6c649SRandall Stewart return (EFAULT);
147348b6c649SRandall Stewart }
147448b6c649SRandall Stewart cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.ret_from_eq;
147548b6c649SRandall Stewart } else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) {
147648b6c649SRandall Stewart net = TAILQ_FIRST(&stcb->asoc.nets);
147748b6c649SRandall Stewart if (net == NULL) {
147848b6c649SRandall Stewart return (EFAULT);
147948b6c649SRandall Stewart }
148048b6c649SRandall Stewart cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.use_dccc_ecn;
1481f79aab18SRandall Stewart } else if (cc_opt->option == SCTP_CC_OPT_STEADY_STEP) {
1482f79aab18SRandall Stewart net = TAILQ_FIRST(&stcb->asoc.nets);
1483f79aab18SRandall Stewart if (net == NULL) {
1484f79aab18SRandall Stewart return (EFAULT);
1485f79aab18SRandall Stewart }
1486f79aab18SRandall Stewart cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.steady_step;
148748b6c649SRandall Stewart } else {
148848b6c649SRandall Stewart return (EINVAL);
148948b6c649SRandall Stewart }
149048b6c649SRandall Stewart }
149148b6c649SRandall Stewart return (0);
149248b6c649SRandall Stewart }
149348b6c649SRandall Stewart
149448b6c649SRandall Stewart static void
sctp_cwnd_update_rtcc_packet_transmitted(struct sctp_tcb * stcb SCTP_UNUSED,struct sctp_nets * net)14957215cc1bSMichael Tuexen sctp_cwnd_update_rtcc_packet_transmitted(struct sctp_tcb *stcb SCTP_UNUSED,
149648b6c649SRandall Stewart struct sctp_nets *net)
149748b6c649SRandall Stewart {
149848b6c649SRandall Stewart if (net->cc_mod.rtcc.tls_needs_set == 0) {
149948b6c649SRandall Stewart SCTP_GETPTIME_TIMEVAL(&net->cc_mod.rtcc.tls);
150048b6c649SRandall Stewart net->cc_mod.rtcc.tls_needs_set = 2;
150148b6c649SRandall Stewart }
150248b6c649SRandall Stewart }
150348b6c649SRandall Stewart
150448b6c649SRandall Stewart 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)150548b6c649SRandall Stewart sctp_cwnd_update_rtcc_after_sack(struct sctp_tcb *stcb,
150648b6c649SRandall Stewart struct sctp_association *asoc,
150748b6c649SRandall Stewart int accum_moved, int reneged_all, int will_exit)
150848b6c649SRandall Stewart {
1509cd0a4ff6SPedro F. Giffuni /* Passing a one argument at the last enables the rtcc algorithm */
151048b6c649SRandall Stewart sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 1);
151148b6c649SRandall Stewart }
151248b6c649SRandall Stewart
1513f79aab18SRandall Stewart static void
sctp_rtt_rtcc_calculated(struct sctp_tcb * stcb SCTP_UNUSED,struct sctp_nets * net,struct timeval * now SCTP_UNUSED)15147215cc1bSMichael Tuexen sctp_rtt_rtcc_calculated(struct sctp_tcb *stcb SCTP_UNUSED,
15157215cc1bSMichael Tuexen struct sctp_nets *net,
15167215cc1bSMichael Tuexen struct timeval *now SCTP_UNUSED)
1517f79aab18SRandall Stewart {
1518f79aab18SRandall Stewart net->cc_mod.rtcc.rtt_set_this_sack = 1;
1519f79aab18SRandall Stewart }
152048b6c649SRandall Stewart
152148b6c649SRandall Stewart /* Here starts Sally Floyds HS-TCP */
152248b6c649SRandall Stewart
1523b54d3a6cSRandall Stewart struct sctp_hs_raise_drop {
1524b54d3a6cSRandall Stewart int32_t cwnd;
1525ed654363SMichael Tuexen int8_t increase;
1526ed654363SMichael Tuexen int8_t drop_percent;
1527b54d3a6cSRandall Stewart };
1528b54d3a6cSRandall Stewart
1529b54d3a6cSRandall Stewart #define SCTP_HS_TABLE_SIZE 73
1530b54d3a6cSRandall Stewart
1531ed654363SMichael Tuexen static const struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = {
1532b54d3a6cSRandall Stewart {38, 1, 50}, /* 0 */
1533b54d3a6cSRandall Stewart {118, 2, 44}, /* 1 */
1534b54d3a6cSRandall Stewart {221, 3, 41}, /* 2 */
1535b54d3a6cSRandall Stewart {347, 4, 38}, /* 3 */
1536b54d3a6cSRandall Stewart {495, 5, 37}, /* 4 */
1537b54d3a6cSRandall Stewart {663, 6, 35}, /* 5 */
1538b54d3a6cSRandall Stewart {851, 7, 34}, /* 6 */
1539b54d3a6cSRandall Stewart {1058, 8, 33}, /* 7 */
1540b54d3a6cSRandall Stewart {1284, 9, 32}, /* 8 */
1541b54d3a6cSRandall Stewart {1529, 10, 31}, /* 9 */
1542b54d3a6cSRandall Stewart {1793, 11, 30}, /* 10 */
1543b54d3a6cSRandall Stewart {2076, 12, 29}, /* 11 */
1544b54d3a6cSRandall Stewart {2378, 13, 28}, /* 12 */
1545b54d3a6cSRandall Stewart {2699, 14, 28}, /* 13 */
1546b54d3a6cSRandall Stewart {3039, 15, 27}, /* 14 */
1547b54d3a6cSRandall Stewart {3399, 16, 27}, /* 15 */
1548b54d3a6cSRandall Stewart {3778, 17, 26}, /* 16 */
1549b54d3a6cSRandall Stewart {4177, 18, 26}, /* 17 */
1550b54d3a6cSRandall Stewart {4596, 19, 25}, /* 18 */
1551b54d3a6cSRandall Stewart {5036, 20, 25}, /* 19 */
1552b54d3a6cSRandall Stewart {5497, 21, 24}, /* 20 */
1553b54d3a6cSRandall Stewart {5979, 22, 24}, /* 21 */
1554b54d3a6cSRandall Stewart {6483, 23, 23}, /* 22 */
1555b54d3a6cSRandall Stewart {7009, 24, 23}, /* 23 */
1556b54d3a6cSRandall Stewart {7558, 25, 22}, /* 24 */
1557b54d3a6cSRandall Stewart {8130, 26, 22}, /* 25 */
1558b54d3a6cSRandall Stewart {8726, 27, 22}, /* 26 */
1559b54d3a6cSRandall Stewart {9346, 28, 21}, /* 27 */
1560b54d3a6cSRandall Stewart {9991, 29, 21}, /* 28 */
1561b54d3a6cSRandall Stewart {10661, 30, 21}, /* 29 */
1562b54d3a6cSRandall Stewart {11358, 31, 20}, /* 30 */
1563b54d3a6cSRandall Stewart {12082, 32, 20}, /* 31 */
1564b54d3a6cSRandall Stewart {12834, 33, 20}, /* 32 */
1565b54d3a6cSRandall Stewart {13614, 34, 19}, /* 33 */
1566b54d3a6cSRandall Stewart {14424, 35, 19}, /* 34 */
1567b54d3a6cSRandall Stewart {15265, 36, 19}, /* 35 */
1568b54d3a6cSRandall Stewart {16137, 37, 19}, /* 36 */
1569b54d3a6cSRandall Stewart {17042, 38, 18}, /* 37 */
1570b54d3a6cSRandall Stewart {17981, 39, 18}, /* 38 */
1571b54d3a6cSRandall Stewart {18955, 40, 18}, /* 39 */
1572b54d3a6cSRandall Stewart {19965, 41, 17}, /* 40 */
1573b54d3a6cSRandall Stewart {21013, 42, 17}, /* 41 */
1574b54d3a6cSRandall Stewart {22101, 43, 17}, /* 42 */
1575b54d3a6cSRandall Stewart {23230, 44, 17}, /* 43 */
1576b54d3a6cSRandall Stewart {24402, 45, 16}, /* 44 */
1577b54d3a6cSRandall Stewart {25618, 46, 16}, /* 45 */
1578b54d3a6cSRandall Stewart {26881, 47, 16}, /* 46 */
1579b54d3a6cSRandall Stewart {28193, 48, 16}, /* 47 */
1580b54d3a6cSRandall Stewart {29557, 49, 15}, /* 48 */
1581b54d3a6cSRandall Stewart {30975, 50, 15}, /* 49 */
1582b54d3a6cSRandall Stewart {32450, 51, 15}, /* 50 */
1583b54d3a6cSRandall Stewart {33986, 52, 15}, /* 51 */
1584b54d3a6cSRandall Stewart {35586, 53, 14}, /* 52 */
1585b54d3a6cSRandall Stewart {37253, 54, 14}, /* 53 */
1586b54d3a6cSRandall Stewart {38992, 55, 14}, /* 54 */
1587b54d3a6cSRandall Stewart {40808, 56, 14}, /* 55 */
1588b54d3a6cSRandall Stewart {42707, 57, 13}, /* 56 */
1589b54d3a6cSRandall Stewart {44694, 58, 13}, /* 57 */
1590b54d3a6cSRandall Stewart {46776, 59, 13}, /* 58 */
1591b54d3a6cSRandall Stewart {48961, 60, 13}, /* 59 */
1592b54d3a6cSRandall Stewart {51258, 61, 13}, /* 60 */
1593b54d3a6cSRandall Stewart {53677, 62, 12}, /* 61 */
1594b54d3a6cSRandall Stewart {56230, 63, 12}, /* 62 */
1595b54d3a6cSRandall Stewart {58932, 64, 12}, /* 63 */
1596b54d3a6cSRandall Stewart {61799, 65, 12}, /* 64 */
1597b54d3a6cSRandall Stewart {64851, 66, 11}, /* 65 */
1598b54d3a6cSRandall Stewart {68113, 67, 11}, /* 66 */
1599b54d3a6cSRandall Stewart {71617, 68, 11}, /* 67 */
1600b54d3a6cSRandall Stewart {75401, 69, 10}, /* 68 */
1601b54d3a6cSRandall Stewart {79517, 70, 10}, /* 69 */
1602b54d3a6cSRandall Stewart {84035, 71, 10}, /* 70 */
1603b54d3a6cSRandall Stewart {89053, 72, 10}, /* 71 */
1604b54d3a6cSRandall Stewart {94717, 73, 9} /* 72 */
1605b54d3a6cSRandall Stewart };
1606b54d3a6cSRandall Stewart
1607b54d3a6cSRandall Stewart static void
sctp_hs_cwnd_increase(struct sctp_tcb * stcb,struct sctp_nets * net)1608b54d3a6cSRandall Stewart sctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net)
1609b54d3a6cSRandall Stewart {
1610b54d3a6cSRandall Stewart int cur_val, i, indx, incr;
161159b6d5beSMichael Tuexen int old_cwnd = net->cwnd;
1612b54d3a6cSRandall Stewart
1613b54d3a6cSRandall Stewart cur_val = net->cwnd >> 10;
1614b54d3a6cSRandall Stewart indx = SCTP_HS_TABLE_SIZE - 1;
1615cd3fd531SMichael Tuexen
1616b54d3a6cSRandall Stewart if (cur_val < sctp_cwnd_adjust[0].cwnd) {
1617b54d3a6cSRandall Stewart /* normal mode */
1618b54d3a6cSRandall Stewart if (net->net_ack > net->mtu) {
1619b54d3a6cSRandall Stewart net->cwnd += net->mtu;
1620b54d3a6cSRandall Stewart } else {
1621b54d3a6cSRandall Stewart net->cwnd += net->net_ack;
1622b54d3a6cSRandall Stewart }
1623b54d3a6cSRandall Stewart } else {
1624b54d3a6cSRandall Stewart for (i = net->last_hs_used; i < SCTP_HS_TABLE_SIZE; i++) {
1625b54d3a6cSRandall Stewart if (cur_val < sctp_cwnd_adjust[i].cwnd) {
1626b54d3a6cSRandall Stewart indx = i;
1627b54d3a6cSRandall Stewart break;
1628b54d3a6cSRandall Stewart }
1629b54d3a6cSRandall Stewart }
1630b54d3a6cSRandall Stewart net->last_hs_used = indx;
1631ed654363SMichael Tuexen incr = (((int32_t)sctp_cwnd_adjust[indx].increase) << 10);
1632b54d3a6cSRandall Stewart net->cwnd += incr;
1633b54d3a6cSRandall Stewart }
163459b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(&stcb->asoc, net);
163559b6d5beSMichael Tuexen if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
163659b6d5beSMichael Tuexen sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SS);
1637b54d3a6cSRandall Stewart }
1638b54d3a6cSRandall Stewart }
1639b54d3a6cSRandall Stewart
1640b54d3a6cSRandall Stewart static void
sctp_hs_cwnd_decrease(struct sctp_tcb * stcb,struct sctp_nets * net)1641b54d3a6cSRandall Stewart sctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net)
1642b54d3a6cSRandall Stewart {
1643b54d3a6cSRandall Stewart int cur_val, i, indx;
1644b54d3a6cSRandall Stewart int old_cwnd = net->cwnd;
1645b54d3a6cSRandall Stewart
1646b54d3a6cSRandall Stewart cur_val = net->cwnd >> 10;
1647b54d3a6cSRandall Stewart if (cur_val < sctp_cwnd_adjust[0].cwnd) {
1648b54d3a6cSRandall Stewart /* normal mode */
1649b54d3a6cSRandall Stewart net->ssthresh = net->cwnd / 2;
1650b54d3a6cSRandall Stewart if (net->ssthresh < (net->mtu * 2)) {
1651b54d3a6cSRandall Stewart net->ssthresh = 2 * net->mtu;
1652b54d3a6cSRandall Stewart }
1653b54d3a6cSRandall Stewart net->cwnd = net->ssthresh;
1654b54d3a6cSRandall Stewart } else {
1655b54d3a6cSRandall Stewart /* drop by the proper amount */
1656b54d3a6cSRandall Stewart net->ssthresh = net->cwnd - (int)((net->cwnd / 100) *
1657ed654363SMichael Tuexen (int32_t)sctp_cwnd_adjust[net->last_hs_used].drop_percent);
1658b54d3a6cSRandall Stewart net->cwnd = net->ssthresh;
1659b54d3a6cSRandall Stewart /* now where are we */
1660b54d3a6cSRandall Stewart indx = net->last_hs_used;
1661b54d3a6cSRandall Stewart cur_val = net->cwnd >> 10;
1662b54d3a6cSRandall Stewart /* reset where we are in the table */
1663b54d3a6cSRandall Stewart if (cur_val < sctp_cwnd_adjust[0].cwnd) {
1664b54d3a6cSRandall Stewart /* feel out of hs */
1665b54d3a6cSRandall Stewart net->last_hs_used = 0;
1666b54d3a6cSRandall Stewart } else {
1667b54d3a6cSRandall Stewart for (i = indx; i >= 1; i--) {
1668b54d3a6cSRandall Stewart if (cur_val > sctp_cwnd_adjust[i - 1].cwnd) {
1669b54d3a6cSRandall Stewart break;
1670b54d3a6cSRandall Stewart }
1671b54d3a6cSRandall Stewart }
1672b54d3a6cSRandall Stewart net->last_hs_used = indx;
1673b54d3a6cSRandall Stewart }
1674b54d3a6cSRandall Stewart }
167559b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(&stcb->asoc, net);
1676b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1677b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_FR);
1678b54d3a6cSRandall Stewart }
1679b54d3a6cSRandall Stewart }
1680b54d3a6cSRandall Stewart
16810e9a9c10SMichael Tuexen static void
sctp_hs_cwnd_update_after_fr(struct sctp_tcb * stcb,struct sctp_association * asoc)1682b54d3a6cSRandall Stewart sctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb,
1683b54d3a6cSRandall Stewart struct sctp_association *asoc)
1684b54d3a6cSRandall Stewart {
1685b54d3a6cSRandall Stewart struct sctp_nets *net;
1686b54d3a6cSRandall Stewart
1687b54d3a6cSRandall Stewart /*
16887c99d56fSMichael Tuexen * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) &&
1689b54d3a6cSRandall Stewart * (net->fast_retran_loss_recovery == 0)))
1690b54d3a6cSRandall Stewart */
1691b54d3a6cSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
169220083c2eSMichael Tuexen if ((asoc->fast_retran_loss_recovery == 0) ||
16937c99d56fSMichael Tuexen (asoc->sctp_cmt_on_off > 0)) {
1694b54d3a6cSRandall Stewart /* out of a RFC2582 Fast recovery window? */
1695b54d3a6cSRandall Stewart if (net->net_ack > 0) {
1696b54d3a6cSRandall Stewart /*
1697b54d3a6cSRandall Stewart * per section 7.2.3, are there any
1698b54d3a6cSRandall Stewart * destinations that had a fast retransmit
1699b54d3a6cSRandall Stewart * to them. If so what we need to do is
1700b54d3a6cSRandall Stewart * adjust ssthresh and cwnd.
1701b54d3a6cSRandall Stewart */
1702b54d3a6cSRandall Stewart struct sctp_tmit_chunk *lchk;
1703b54d3a6cSRandall Stewart
1704b54d3a6cSRandall Stewart sctp_hs_cwnd_decrease(stcb, net);
1705b54d3a6cSRandall Stewart
1706b54d3a6cSRandall Stewart lchk = TAILQ_FIRST(&asoc->send_queue);
1707b54d3a6cSRandall Stewart
1708b54d3a6cSRandall Stewart net->partial_bytes_acked = 0;
1709b54d3a6cSRandall Stewart /* Turn on fast recovery window */
1710b54d3a6cSRandall Stewart asoc->fast_retran_loss_recovery = 1;
1711b54d3a6cSRandall Stewart if (lchk == NULL) {
1712b54d3a6cSRandall Stewart /* Mark end of the window */
1713b54d3a6cSRandall Stewart asoc->fast_recovery_tsn = asoc->sending_seq - 1;
1714b54d3a6cSRandall Stewart } else {
171549656eefSMichael Tuexen asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1;
1716b54d3a6cSRandall Stewart }
1717b54d3a6cSRandall Stewart
1718b54d3a6cSRandall Stewart /*
1719b54d3a6cSRandall Stewart * CMT fast recovery -- per destination
1720b54d3a6cSRandall Stewart * recovery variable.
1721b54d3a6cSRandall Stewart */
1722b54d3a6cSRandall Stewart net->fast_retran_loss_recovery = 1;
1723b54d3a6cSRandall Stewart
1724b54d3a6cSRandall Stewart if (lchk == NULL) {
1725b54d3a6cSRandall Stewart /* Mark end of the window */
1726b54d3a6cSRandall Stewart net->fast_recovery_tsn = asoc->sending_seq - 1;
1727b54d3a6cSRandall Stewart } else {
172849656eefSMichael Tuexen net->fast_recovery_tsn = lchk->rec.data.tsn - 1;
1729b54d3a6cSRandall Stewart }
1730b54d3a6cSRandall Stewart
1731b54d3a6cSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
1732b7d130beSMichael Tuexen stcb->sctp_ep, stcb, net,
1733b7d130beSMichael Tuexen SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_2);
1734b54d3a6cSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND,
1735b54d3a6cSRandall Stewart stcb->sctp_ep, stcb, net);
1736b54d3a6cSRandall Stewart }
1737b54d3a6cSRandall Stewart } else if (net->net_ack > 0) {
1738b54d3a6cSRandall Stewart /*
1739b54d3a6cSRandall Stewart * Mark a peg that we WOULD have done a cwnd
1740b54d3a6cSRandall Stewart * reduction but RFC2582 prevented this action.
1741b54d3a6cSRandall Stewart */
1742b54d3a6cSRandall Stewart SCTP_STAT_INCR(sctps_fastretransinrtt);
1743b54d3a6cSRandall Stewart }
1744b54d3a6cSRandall Stewart }
1745b54d3a6cSRandall Stewart }
1746b54d3a6cSRandall Stewart
17470e9a9c10SMichael Tuexen 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)1748b54d3a6cSRandall Stewart sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
1749b54d3a6cSRandall Stewart struct sctp_association *asoc,
17507215cc1bSMichael Tuexen int accum_moved, int reneged_all SCTP_UNUSED, int will_exit)
1751b54d3a6cSRandall Stewart {
1752b54d3a6cSRandall Stewart struct sctp_nets *net;
1753b54d3a6cSRandall Stewart
1754b54d3a6cSRandall Stewart /******************************/
1755b54d3a6cSRandall Stewart /* update cwnd and Early FR */
1756b54d3a6cSRandall Stewart /******************************/
1757b54d3a6cSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
1758b54d3a6cSRandall Stewart #ifdef JANA_CMT_FAST_RECOVERY
1759b54d3a6cSRandall Stewart /*
1760b54d3a6cSRandall Stewart * CMT fast recovery code. Need to debug.
1761b54d3a6cSRandall Stewart */
1762b54d3a6cSRandall Stewart if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) {
1763ea8345d6SMichael Tuexen if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) ||
1764ea8345d6SMichael Tuexen SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) {
1765b54d3a6cSRandall Stewart net->will_exit_fast_recovery = 1;
1766b54d3a6cSRandall Stewart }
1767b54d3a6cSRandall Stewart }
1768b54d3a6cSRandall Stewart #endif
1769b54d3a6cSRandall Stewart /* if nothing was acked on this destination skip it */
1770b54d3a6cSRandall Stewart if (net->net_ack == 0) {
1771b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1772b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK);
1773b54d3a6cSRandall Stewart }
1774b54d3a6cSRandall Stewart continue;
1775b54d3a6cSRandall Stewart }
1776b54d3a6cSRandall Stewart #ifdef JANA_CMT_FAST_RECOVERY
1777b54d3a6cSRandall Stewart /*
1778b54d3a6cSRandall Stewart * CMT fast recovery code
1779b54d3a6cSRandall Stewart */
1780b54d3a6cSRandall Stewart /*
17817c99d56fSMichael Tuexen * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery
17827c99d56fSMichael Tuexen * && net->will_exit_fast_recovery == 0) { @@@ Do something
17837c99d56fSMichael Tuexen * } else if (sctp_cmt_on_off == 0 &&
1784b54d3a6cSRandall Stewart * asoc->fast_retran_loss_recovery && will_exit == 0) {
1785b54d3a6cSRandall Stewart */
1786b54d3a6cSRandall Stewart #endif
1787b54d3a6cSRandall Stewart
178820083c2eSMichael Tuexen if (asoc->fast_retran_loss_recovery &&
178920083c2eSMichael Tuexen (will_exit == 0) &&
179020083c2eSMichael Tuexen (asoc->sctp_cmt_on_off == 0)) {
1791b54d3a6cSRandall Stewart /*
1792b54d3a6cSRandall Stewart * If we are in loss recovery we skip any cwnd
1793b54d3a6cSRandall Stewart * update
1794b54d3a6cSRandall Stewart */
1795ca85e948SMichael Tuexen return;
1796b54d3a6cSRandall Stewart }
1797b54d3a6cSRandall Stewart /*
1798b54d3a6cSRandall Stewart * CMT: CUC algorithm. Update cwnd if pseudo-cumack has
1799b54d3a6cSRandall Stewart * moved.
1800b54d3a6cSRandall Stewart */
180120083c2eSMichael Tuexen if (accum_moved ||
18027c99d56fSMichael Tuexen ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) {
1803b54d3a6cSRandall Stewart /* If the cumulative ack moved we can proceed */
1804b54d3a6cSRandall Stewart if (net->cwnd <= net->ssthresh) {
1805b54d3a6cSRandall Stewart /* We are in slow start */
1806c54a18d2SRandall Stewart if (net->flight_size + net->net_ack >= net->cwnd) {
1807b54d3a6cSRandall Stewart sctp_hs_cwnd_increase(stcb, net);
1808b54d3a6cSRandall Stewart } else {
1809b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1810b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, net->net_ack,
1811b54d3a6cSRandall Stewart SCTP_CWND_LOG_NOADV_SS);
1812b54d3a6cSRandall Stewart }
1813b54d3a6cSRandall Stewart }
1814b54d3a6cSRandall Stewart } else {
1815b54d3a6cSRandall Stewart /* We are in congestion avoidance */
1816c54a18d2SRandall Stewart net->partial_bytes_acked += net->net_ack;
1817c54a18d2SRandall Stewart if ((net->flight_size + net->net_ack >= net->cwnd) &&
1818c54a18d2SRandall Stewart (net->partial_bytes_acked >= net->cwnd)) {
1819c54a18d2SRandall Stewart net->partial_bytes_acked -= net->cwnd;
1820b54d3a6cSRandall Stewart net->cwnd += net->mtu;
182159b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(asoc, net);
1822b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1823b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, net->mtu,
1824b54d3a6cSRandall Stewart SCTP_CWND_LOG_FROM_CA);
1825b54d3a6cSRandall Stewart }
1826b54d3a6cSRandall Stewart } else {
1827b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1828b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, net->net_ack,
1829b54d3a6cSRandall Stewart SCTP_CWND_LOG_NOADV_CA);
1830b54d3a6cSRandall Stewart }
1831b54d3a6cSRandall Stewart }
1832b54d3a6cSRandall Stewart }
1833b54d3a6cSRandall Stewart } else {
1834b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1835b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, net->mtu,
1836b54d3a6cSRandall Stewart SCTP_CWND_LOG_NO_CUMACK);
1837b54d3a6cSRandall Stewart }
1838b54d3a6cSRandall Stewart }
1839b54d3a6cSRandall Stewart }
1840b54d3a6cSRandall Stewart }
1841b54d3a6cSRandall Stewart
1842b54d3a6cSRandall Stewart /*
1843b54d3a6cSRandall Stewart * H-TCP congestion control. The algorithm is detailed in:
1844b54d3a6cSRandall Stewart * R.N.Shorten, D.J.Leith:
1845b54d3a6cSRandall Stewart * "H-TCP: TCP for high-speed and long-distance networks"
1846b54d3a6cSRandall Stewart * Proc. PFLDnet, Argonne, 2004.
1847b54d3a6cSRandall Stewart * http://www.hamilton.ie/net/htcp3.pdf
1848b54d3a6cSRandall Stewart */
1849b54d3a6cSRandall Stewart
1850b54d3a6cSRandall Stewart static int use_rtt_scaling = 1;
1851b54d3a6cSRandall Stewart static int use_bandwidth_switch = 1;
1852b54d3a6cSRandall Stewart
1853b54d3a6cSRandall Stewart static inline int
between(uint32_t seq1,uint32_t seq2,uint32_t seq3)1854b54d3a6cSRandall Stewart between(uint32_t seq1, uint32_t seq2, uint32_t seq3)
1855b54d3a6cSRandall Stewart {
185660990c0cSMichael Tuexen return (seq3 - seq2 >= seq1 - seq2);
1857b54d3a6cSRandall Stewart }
1858b54d3a6cSRandall Stewart
1859b54d3a6cSRandall Stewart static inline uint32_t
htcp_cong_time(struct htcp * ca)1860b0471b4bSMichael Tuexen htcp_cong_time(struct htcp *ca)
1861b0471b4bSMichael Tuexen {
186260990c0cSMichael Tuexen return (sctp_get_tick_count() - ca->last_cong);
1863b54d3a6cSRandall Stewart }
1864b54d3a6cSRandall Stewart
1865b54d3a6cSRandall Stewart static inline uint32_t
htcp_ccount(struct htcp * ca)1866b0471b4bSMichael Tuexen htcp_ccount(struct htcp *ca)
1867b0471b4bSMichael Tuexen {
1868fc0eb763SMichael Tuexen return (ca->minRTT == 0 ? htcp_cong_time(ca) : htcp_cong_time(ca) / ca->minRTT);
1869b54d3a6cSRandall Stewart }
1870b54d3a6cSRandall Stewart
1871b54d3a6cSRandall Stewart static inline void
htcp_reset(struct htcp * ca)1872b54d3a6cSRandall Stewart htcp_reset(struct htcp *ca)
1873b54d3a6cSRandall Stewart {
1874b54d3a6cSRandall Stewart ca->undo_last_cong = ca->last_cong;
1875b54d3a6cSRandall Stewart ca->undo_maxRTT = ca->maxRTT;
1876b54d3a6cSRandall Stewart ca->undo_old_maxB = ca->old_maxB;
187718e198d3SRandall Stewart ca->last_cong = sctp_get_tick_count();
1878b54d3a6cSRandall Stewart }
1879b54d3a6cSRandall Stewart
1880b54d3a6cSRandall Stewart #ifdef SCTP_NOT_USED
1881b54d3a6cSRandall Stewart
1882b54d3a6cSRandall Stewart static uint32_t
htcp_cwnd_undo(struct sctp_tcb * stcb,struct sctp_nets * net)1883b0471b4bSMichael Tuexen htcp_cwnd_undo(struct sctp_tcb *stcb, struct sctp_nets *net)
1884b0471b4bSMichael Tuexen {
1885299108c5SRandall Stewart net->cc_mod.htcp_ca.last_cong = net->cc_mod.htcp_ca.undo_last_cong;
1886299108c5SRandall Stewart net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.undo_maxRTT;
1887299108c5SRandall Stewart net->cc_mod.htcp_ca.old_maxB = net->cc_mod.htcp_ca.undo_old_maxB;
188860990c0cSMichael Tuexen return (max(net->cwnd, ((net->ssthresh / net->mtu << 7) / net->cc_mod.htcp_ca.beta) * net->mtu));
1889b54d3a6cSRandall Stewart }
1890b54d3a6cSRandall Stewart
1891b54d3a6cSRandall Stewart #endif
1892b54d3a6cSRandall Stewart
1893b54d3a6cSRandall Stewart static inline void
measure_rtt(struct sctp_nets * net)18947215cc1bSMichael Tuexen measure_rtt(struct sctp_nets *net)
1895b54d3a6cSRandall Stewart {
18960191fb6dSMichael Tuexen uint32_t srtt = net->lastsa >> SCTP_RTT_SHIFT;
1897b54d3a6cSRandall Stewart
1898b54d3a6cSRandall Stewart /* keep track of minimum RTT seen so far, minRTT is zero at first */
1899299108c5SRandall Stewart if (net->cc_mod.htcp_ca.minRTT > srtt || !net->cc_mod.htcp_ca.minRTT)
1900299108c5SRandall Stewart net->cc_mod.htcp_ca.minRTT = srtt;
1901b54d3a6cSRandall Stewart
1902b54d3a6cSRandall Stewart /* max RTT */
1903299108c5SRandall Stewart if (net->fast_retran_ip == 0 && net->ssthresh < 0xFFFF && htcp_ccount(&net->cc_mod.htcp_ca) > 3) {
1904299108c5SRandall Stewart if (net->cc_mod.htcp_ca.maxRTT < net->cc_mod.htcp_ca.minRTT)
1905299108c5SRandall Stewart net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.minRTT;
190625ec3553SMichael Tuexen if (net->cc_mod.htcp_ca.maxRTT < srtt && srtt <= net->cc_mod.htcp_ca.maxRTT + sctp_msecs_to_ticks(20))
1907299108c5SRandall Stewart net->cc_mod.htcp_ca.maxRTT = srtt;
1908b54d3a6cSRandall Stewart }
1909b54d3a6cSRandall Stewart }
1910b54d3a6cSRandall Stewart
1911b54d3a6cSRandall Stewart static void
measure_achieved_throughput(struct sctp_nets * net)19127215cc1bSMichael Tuexen measure_achieved_throughput(struct sctp_nets *net)
1913b54d3a6cSRandall Stewart {
191418e198d3SRandall Stewart uint32_t now = sctp_get_tick_count();
1915b54d3a6cSRandall Stewart
1916b54d3a6cSRandall Stewart if (net->fast_retran_ip == 0)
1917299108c5SRandall Stewart net->cc_mod.htcp_ca.bytes_acked = net->net_ack;
1918b54d3a6cSRandall Stewart
1919b54d3a6cSRandall Stewart if (!use_bandwidth_switch)
1920b54d3a6cSRandall Stewart return;
1921b54d3a6cSRandall Stewart
1922b54d3a6cSRandall Stewart /* achieved throughput calculations */
1923b54d3a6cSRandall Stewart /* JRS - not 100% sure of this statement */
1924b54d3a6cSRandall Stewart if (net->fast_retran_ip == 1) {
1925299108c5SRandall Stewart net->cc_mod.htcp_ca.bytecount = 0;
1926299108c5SRandall Stewart net->cc_mod.htcp_ca.lasttime = now;
1927b54d3a6cSRandall Stewart return;
1928b54d3a6cSRandall Stewart }
19290053ed28SMichael Tuexen
1930299108c5SRandall Stewart net->cc_mod.htcp_ca.bytecount += net->net_ack;
193112780a59SMichael Tuexen 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)) &&
193212780a59SMichael Tuexen (now - net->cc_mod.htcp_ca.lasttime >= net->cc_mod.htcp_ca.minRTT) &&
193312780a59SMichael Tuexen (net->cc_mod.htcp_ca.minRTT > 0)) {
1934299108c5SRandall Stewart uint32_t cur_Bi = net->cc_mod.htcp_ca.bytecount / net->mtu * hz / (now - net->cc_mod.htcp_ca.lasttime);
1935b54d3a6cSRandall Stewart
1936299108c5SRandall Stewart if (htcp_ccount(&net->cc_mod.htcp_ca) <= 3) {
1937b54d3a6cSRandall Stewart /* just after backoff */
1938299108c5SRandall Stewart net->cc_mod.htcp_ca.minB = net->cc_mod.htcp_ca.maxB = net->cc_mod.htcp_ca.Bi = cur_Bi;
1939b54d3a6cSRandall Stewart } else {
1940299108c5SRandall Stewart net->cc_mod.htcp_ca.Bi = (3 * net->cc_mod.htcp_ca.Bi + cur_Bi) / 4;
1941299108c5SRandall Stewart if (net->cc_mod.htcp_ca.Bi > net->cc_mod.htcp_ca.maxB)
1942299108c5SRandall Stewart net->cc_mod.htcp_ca.maxB = net->cc_mod.htcp_ca.Bi;
1943299108c5SRandall Stewart if (net->cc_mod.htcp_ca.minB > net->cc_mod.htcp_ca.maxB)
1944299108c5SRandall Stewart net->cc_mod.htcp_ca.minB = net->cc_mod.htcp_ca.maxB;
1945b54d3a6cSRandall Stewart }
1946299108c5SRandall Stewart net->cc_mod.htcp_ca.bytecount = 0;
1947299108c5SRandall Stewart net->cc_mod.htcp_ca.lasttime = now;
1948b54d3a6cSRandall Stewart }
1949b54d3a6cSRandall Stewart }
1950b54d3a6cSRandall Stewart
1951b54d3a6cSRandall Stewart static inline void
htcp_beta_update(struct htcp * ca,uint32_t minRTT,uint32_t maxRTT)1952b54d3a6cSRandall Stewart htcp_beta_update(struct htcp *ca, uint32_t minRTT, uint32_t maxRTT)
1953b54d3a6cSRandall Stewart {
1954b54d3a6cSRandall Stewart if (use_bandwidth_switch) {
1955b54d3a6cSRandall Stewart uint32_t maxB = ca->maxB;
1956b54d3a6cSRandall Stewart uint32_t old_maxB = ca->old_maxB;
1957b54d3a6cSRandall Stewart
1958b54d3a6cSRandall Stewart ca->old_maxB = ca->maxB;
1959b54d3a6cSRandall Stewart
1960b54d3a6cSRandall Stewart if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) {
1961b54d3a6cSRandall Stewart ca->beta = BETA_MIN;
1962b54d3a6cSRandall Stewart ca->modeswitch = 0;
1963b54d3a6cSRandall Stewart return;
1964b54d3a6cSRandall Stewart }
1965b54d3a6cSRandall Stewart }
19660053ed28SMichael Tuexen
196725ec3553SMichael Tuexen if (ca->modeswitch && minRTT > sctp_msecs_to_ticks(10) && maxRTT) {
1968b54d3a6cSRandall Stewart ca->beta = (minRTT << 7) / maxRTT;
1969b54d3a6cSRandall Stewart if (ca->beta < BETA_MIN)
1970b54d3a6cSRandall Stewart ca->beta = BETA_MIN;
1971b54d3a6cSRandall Stewart else if (ca->beta > BETA_MAX)
1972b54d3a6cSRandall Stewart ca->beta = BETA_MAX;
1973b54d3a6cSRandall Stewart } else {
1974b54d3a6cSRandall Stewart ca->beta = BETA_MIN;
1975b54d3a6cSRandall Stewart ca->modeswitch = 1;
1976b54d3a6cSRandall Stewart }
1977b54d3a6cSRandall Stewart }
1978b54d3a6cSRandall Stewart
1979b54d3a6cSRandall Stewart static inline void
htcp_alpha_update(struct htcp * ca)1980b54d3a6cSRandall Stewart htcp_alpha_update(struct htcp *ca)
1981b54d3a6cSRandall Stewart {
1982b54d3a6cSRandall Stewart uint32_t minRTT = ca->minRTT;
1983b54d3a6cSRandall Stewart uint32_t factor = 1;
1984b54d3a6cSRandall Stewart uint32_t diff = htcp_cong_time(ca);
1985b54d3a6cSRandall Stewart
1986b54d3a6cSRandall Stewart if (diff > (uint32_t)hz) {
1987b54d3a6cSRandall Stewart diff -= hz;
1988b54d3a6cSRandall Stewart factor = 1 + (10 * diff + ((diff / 2) * (diff / 2) / hz)) / hz;
1989b54d3a6cSRandall Stewart }
19900053ed28SMichael Tuexen
1991b54d3a6cSRandall Stewart if (use_rtt_scaling && minRTT) {
1992b54d3a6cSRandall Stewart uint32_t scale = (hz << 3) / (10 * minRTT);
1993b54d3a6cSRandall Stewart
1994b54d3a6cSRandall Stewart scale = min(max(scale, 1U << 2), 10U << 3); /* clamping ratio to
1995b54d3a6cSRandall Stewart * interval [0.5,10]<<3 */
1996b54d3a6cSRandall Stewart factor = (factor << 3) / scale;
1997e7a39b85SMichael Tuexen if (factor != 0)
1998b54d3a6cSRandall Stewart factor = 1;
1999b54d3a6cSRandall Stewart }
20000053ed28SMichael Tuexen
2001b54d3a6cSRandall Stewart ca->alpha = 2 * factor * ((1 << 7) - ca->beta);
2002e7a39b85SMichael Tuexen if (ca->alpha != 0)
2003b54d3a6cSRandall Stewart ca->alpha = ALPHA_BASE;
2004b54d3a6cSRandall Stewart }
2005b54d3a6cSRandall Stewart
2006b54d3a6cSRandall Stewart /* After we have the rtt data to calculate beta, we'd still prefer to wait one
2007b54d3a6cSRandall Stewart * rtt before we adjust our beta to ensure we are working from a consistent
2008b54d3a6cSRandall Stewart * data.
2009b54d3a6cSRandall Stewart *
2010b54d3a6cSRandall Stewart * This function should be called when we hit a congestion event since only at
2011b54d3a6cSRandall Stewart * that point do we really have a real sense of maxRTT (the queues en route
2012b54d3a6cSRandall Stewart * were getting just too full now).
2013b54d3a6cSRandall Stewart */
2014b54d3a6cSRandall Stewart static void
htcp_param_update(struct sctp_nets * net)20157215cc1bSMichael Tuexen htcp_param_update(struct sctp_nets *net)
2016b54d3a6cSRandall Stewart {
2017299108c5SRandall Stewart uint32_t minRTT = net->cc_mod.htcp_ca.minRTT;
2018299108c5SRandall Stewart uint32_t maxRTT = net->cc_mod.htcp_ca.maxRTT;
2019b54d3a6cSRandall Stewart
2020299108c5SRandall Stewart htcp_beta_update(&net->cc_mod.htcp_ca, minRTT, maxRTT);
2021299108c5SRandall Stewart htcp_alpha_update(&net->cc_mod.htcp_ca);
2022b54d3a6cSRandall Stewart
2023b7b84c0eSMichael Tuexen /*
2024b7b84c0eSMichael Tuexen * add slowly fading memory for maxRTT to accommodate routing
2025b7b84c0eSMichael Tuexen * changes etc
2026b7b84c0eSMichael Tuexen */
2027b54d3a6cSRandall Stewart if (minRTT > 0 && maxRTT > minRTT)
2028299108c5SRandall Stewart net->cc_mod.htcp_ca.maxRTT = minRTT + ((maxRTT - minRTT) * 95) / 100;
2029b54d3a6cSRandall Stewart }
2030b54d3a6cSRandall Stewart
2031b54d3a6cSRandall Stewart static uint32_t
htcp_recalc_ssthresh(struct sctp_nets * net)2032b0471b4bSMichael Tuexen htcp_recalc_ssthresh(struct sctp_nets *net)
2033b0471b4bSMichael Tuexen {
20347215cc1bSMichael Tuexen htcp_param_update(net);
203560990c0cSMichael Tuexen return (max(((net->cwnd / net->mtu * net->cc_mod.htcp_ca.beta) >> 7) * net->mtu, 2U * net->mtu));
2036b54d3a6cSRandall Stewart }
2037b54d3a6cSRandall Stewart
2038b54d3a6cSRandall Stewart static void
htcp_cong_avoid(struct sctp_tcb * stcb,struct sctp_nets * net)2039b54d3a6cSRandall Stewart htcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net)
2040b54d3a6cSRandall Stewart {
2041b54d3a6cSRandall Stewart /*-
2042b54d3a6cSRandall Stewart * How to handle these functions?
2043b54d3a6cSRandall Stewart * if (!tcp_is_cwnd_limited(sk, in_flight)) RRS - good question.
2044b54d3a6cSRandall Stewart * return;
2045b54d3a6cSRandall Stewart */
2046b54d3a6cSRandall Stewart if (net->cwnd <= net->ssthresh) {
2047b54d3a6cSRandall Stewart /* We are in slow start */
2048b54d3a6cSRandall Stewart if (net->flight_size + net->net_ack >= net->cwnd) {
2049b3f1ea41SRandall Stewart if (net->net_ack > (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable))) {
2050b3f1ea41SRandall Stewart net->cwnd += (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable));
2051b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2052b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, net->mtu,
2053b54d3a6cSRandall Stewart SCTP_CWND_LOG_FROM_SS);
2054b54d3a6cSRandall Stewart }
20550053ed28SMichael Tuexen
2056b54d3a6cSRandall Stewart } else {
2057b54d3a6cSRandall Stewart net->cwnd += net->net_ack;
2058b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2059b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, net->net_ack,
2060b54d3a6cSRandall Stewart SCTP_CWND_LOG_FROM_SS);
2061b54d3a6cSRandall Stewart }
2062b54d3a6cSRandall Stewart }
206359b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(&stcb->asoc, net);
2064b54d3a6cSRandall Stewart } else {
2065b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
2066b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, net->net_ack,
2067b54d3a6cSRandall Stewart SCTP_CWND_LOG_NOADV_SS);
2068b54d3a6cSRandall Stewart }
2069b54d3a6cSRandall Stewart }
2070b54d3a6cSRandall Stewart } else {
20717215cc1bSMichael Tuexen measure_rtt(net);
2072b54d3a6cSRandall Stewart
2073b54d3a6cSRandall Stewart /*
2074b54d3a6cSRandall Stewart * In dangerous area, increase slowly. In theory this is
2075b54d3a6cSRandall Stewart * net->cwnd += alpha / net->cwnd
2076b54d3a6cSRandall Stewart */
2077b54d3a6cSRandall Stewart /* What is snd_cwnd_cnt?? */
2078299108c5SRandall Stewart if (((net->partial_bytes_acked / net->mtu * net->cc_mod.htcp_ca.alpha) >> 7) * net->mtu >= net->cwnd) {
2079b54d3a6cSRandall Stewart /*-
2080b54d3a6cSRandall Stewart * Does SCTP have a cwnd clamp?
2081b54d3a6cSRandall Stewart * if (net->snd_cwnd < net->snd_cwnd_clamp) - Nope (RRS).
2082b54d3a6cSRandall Stewart */
2083b54d3a6cSRandall Stewart net->cwnd += net->mtu;
2084b54d3a6cSRandall Stewart net->partial_bytes_acked = 0;
208559b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(&stcb->asoc, net);
2086299108c5SRandall Stewart htcp_alpha_update(&net->cc_mod.htcp_ca);
2087b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2088b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, net->mtu,
2089b54d3a6cSRandall Stewart SCTP_CWND_LOG_FROM_CA);
2090b54d3a6cSRandall Stewart }
2091b54d3a6cSRandall Stewart } else {
2092b54d3a6cSRandall Stewart net->partial_bytes_acked += net->net_ack;
2093b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
2094b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, net->net_ack,
2095b54d3a6cSRandall Stewart SCTP_CWND_LOG_NOADV_CA);
2096b54d3a6cSRandall Stewart }
2097b54d3a6cSRandall Stewart }
2098b54d3a6cSRandall Stewart
2099299108c5SRandall Stewart net->cc_mod.htcp_ca.bytes_acked = net->mtu;
2100b54d3a6cSRandall Stewart }
2101b54d3a6cSRandall Stewart }
2102b54d3a6cSRandall Stewart
2103b54d3a6cSRandall Stewart #ifdef SCTP_NOT_USED
2104b54d3a6cSRandall Stewart /* Lower bound on congestion window. */
2105b54d3a6cSRandall Stewart static uint32_t
htcp_min_cwnd(struct sctp_tcb * stcb,struct sctp_nets * net)2106b0471b4bSMichael Tuexen htcp_min_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net)
2107b0471b4bSMichael Tuexen {
210860990c0cSMichael Tuexen return (net->ssthresh);
2109b54d3a6cSRandall Stewart }
2110b54d3a6cSRandall Stewart #endif
2111b54d3a6cSRandall Stewart
2112b54d3a6cSRandall Stewart static void
htcp_init(struct sctp_nets * net)21137215cc1bSMichael Tuexen htcp_init(struct sctp_nets *net)
2114b54d3a6cSRandall Stewart {
2115299108c5SRandall Stewart memset(&net->cc_mod.htcp_ca, 0, sizeof(struct htcp));
2116299108c5SRandall Stewart net->cc_mod.htcp_ca.alpha = ALPHA_BASE;
2117299108c5SRandall Stewart net->cc_mod.htcp_ca.beta = BETA_MIN;
2118299108c5SRandall Stewart net->cc_mod.htcp_ca.bytes_acked = net->mtu;
2119299108c5SRandall Stewart net->cc_mod.htcp_ca.last_cong = sctp_get_tick_count();
2120b54d3a6cSRandall Stewart }
2121b54d3a6cSRandall Stewart
21220e9a9c10SMichael Tuexen static void
sctp_htcp_set_initial_cc_param(struct sctp_tcb * stcb,struct sctp_nets * net)2123b54d3a6cSRandall Stewart sctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
2124b54d3a6cSRandall Stewart {
2125b54d3a6cSRandall Stewart /*
2126b54d3a6cSRandall Stewart * We take the max of the burst limit times a MTU or the
2127b54d3a6cSRandall Stewart * INITIAL_CWND. We then limit this to 4 MTU's of sending.
2128b54d3a6cSRandall Stewart */
2129b54d3a6cSRandall Stewart net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
2130b54d3a6cSRandall Stewart net->ssthresh = stcb->asoc.peers_rwnd;
213159b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(&stcb->asoc, net);
21327215cc1bSMichael Tuexen htcp_init(net);
2133b54d3a6cSRandall Stewart
2134b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) {
2135b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION);
2136b54d3a6cSRandall Stewart }
2137b54d3a6cSRandall Stewart }
2138b54d3a6cSRandall Stewart
21390e9a9c10SMichael Tuexen 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)2140b54d3a6cSRandall Stewart sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb,
2141b54d3a6cSRandall Stewart struct sctp_association *asoc,
21427215cc1bSMichael Tuexen int accum_moved, int reneged_all SCTP_UNUSED, int will_exit)
2143b54d3a6cSRandall Stewart {
2144b54d3a6cSRandall Stewart struct sctp_nets *net;
2145b54d3a6cSRandall Stewart
2146b54d3a6cSRandall Stewart /******************************/
2147b54d3a6cSRandall Stewart /* update cwnd and Early FR */
2148b54d3a6cSRandall Stewart /******************************/
2149b54d3a6cSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
2150b54d3a6cSRandall Stewart #ifdef JANA_CMT_FAST_RECOVERY
2151b54d3a6cSRandall Stewart /*
2152b54d3a6cSRandall Stewart * CMT fast recovery code. Need to debug.
2153b54d3a6cSRandall Stewart */
2154b54d3a6cSRandall Stewart if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) {
2155ea8345d6SMichael Tuexen if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) ||
2156ea8345d6SMichael Tuexen SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) {
2157b54d3a6cSRandall Stewart net->will_exit_fast_recovery = 1;
2158b54d3a6cSRandall Stewart }
2159b54d3a6cSRandall Stewart }
2160b54d3a6cSRandall Stewart #endif
2161b54d3a6cSRandall Stewart /* if nothing was acked on this destination skip it */
2162b54d3a6cSRandall Stewart if (net->net_ack == 0) {
2163b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
2164b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK);
2165b54d3a6cSRandall Stewart }
2166b54d3a6cSRandall Stewart continue;
2167b54d3a6cSRandall Stewart }
2168b54d3a6cSRandall Stewart #ifdef JANA_CMT_FAST_RECOVERY
2169b54d3a6cSRandall Stewart /*
2170b54d3a6cSRandall Stewart * CMT fast recovery code
2171b54d3a6cSRandall Stewart */
2172b54d3a6cSRandall Stewart /*
21737c99d56fSMichael Tuexen * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery
21747c99d56fSMichael Tuexen * && net->will_exit_fast_recovery == 0) { @@@ Do something
21757c99d56fSMichael Tuexen * } else if (sctp_cmt_on_off == 0 &&
2176b54d3a6cSRandall Stewart * asoc->fast_retran_loss_recovery && will_exit == 0) {
2177b54d3a6cSRandall Stewart */
2178b54d3a6cSRandall Stewart #endif
2179b54d3a6cSRandall Stewart
218020083c2eSMichael Tuexen if (asoc->fast_retran_loss_recovery &&
218120083c2eSMichael Tuexen will_exit == 0 &&
218220083c2eSMichael Tuexen (asoc->sctp_cmt_on_off == 0)) {
2183b54d3a6cSRandall Stewart /*
2184b54d3a6cSRandall Stewart * If we are in loss recovery we skip any cwnd
2185b54d3a6cSRandall Stewart * update
2186b54d3a6cSRandall Stewart */
2187ca85e948SMichael Tuexen return;
2188b54d3a6cSRandall Stewart }
2189b54d3a6cSRandall Stewart /*
2190b54d3a6cSRandall Stewart * CMT: CUC algorithm. Update cwnd if pseudo-cumack has
2191b54d3a6cSRandall Stewart * moved.
2192b54d3a6cSRandall Stewart */
219320083c2eSMichael Tuexen if (accum_moved ||
21947c99d56fSMichael Tuexen ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) {
2195b54d3a6cSRandall Stewart htcp_cong_avoid(stcb, net);
21967215cc1bSMichael Tuexen measure_achieved_throughput(net);
2197b54d3a6cSRandall Stewart } else {
2198b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
2199b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, net->mtu,
2200b54d3a6cSRandall Stewart SCTP_CWND_LOG_NO_CUMACK);
2201b54d3a6cSRandall Stewart }
2202b54d3a6cSRandall Stewart }
2203b54d3a6cSRandall Stewart }
2204b54d3a6cSRandall Stewart }
2205b54d3a6cSRandall Stewart
22060e9a9c10SMichael Tuexen static void
sctp_htcp_cwnd_update_after_fr(struct sctp_tcb * stcb,struct sctp_association * asoc)2207b54d3a6cSRandall Stewart sctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb,
2208b54d3a6cSRandall Stewart struct sctp_association *asoc)
2209b54d3a6cSRandall Stewart {
2210b54d3a6cSRandall Stewart struct sctp_nets *net;
2211b54d3a6cSRandall Stewart
2212b54d3a6cSRandall Stewart /*
22137c99d56fSMichael Tuexen * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) &&
2214b54d3a6cSRandall Stewart * (net->fast_retran_loss_recovery == 0)))
2215b54d3a6cSRandall Stewart */
2216b54d3a6cSRandall Stewart TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
221720083c2eSMichael Tuexen if ((asoc->fast_retran_loss_recovery == 0) ||
22187c99d56fSMichael Tuexen (asoc->sctp_cmt_on_off > 0)) {
2219b54d3a6cSRandall Stewart /* out of a RFC2582 Fast recovery window? */
2220b54d3a6cSRandall Stewart if (net->net_ack > 0) {
2221b54d3a6cSRandall Stewart /*
2222b54d3a6cSRandall Stewart * per section 7.2.3, are there any
2223b54d3a6cSRandall Stewart * destinations that had a fast retransmit
2224b54d3a6cSRandall Stewart * to them. If so what we need to do is
2225b54d3a6cSRandall Stewart * adjust ssthresh and cwnd.
2226b54d3a6cSRandall Stewart */
2227b54d3a6cSRandall Stewart struct sctp_tmit_chunk *lchk;
2228b54d3a6cSRandall Stewart int old_cwnd = net->cwnd;
2229b54d3a6cSRandall Stewart
2230b54d3a6cSRandall Stewart /* JRS - reset as if state were changed */
2231299108c5SRandall Stewart htcp_reset(&net->cc_mod.htcp_ca);
22327215cc1bSMichael Tuexen net->ssthresh = htcp_recalc_ssthresh(net);
2233b54d3a6cSRandall Stewart net->cwnd = net->ssthresh;
223459b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(asoc, net);
2235b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2236b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
2237b54d3a6cSRandall Stewart SCTP_CWND_LOG_FROM_FR);
2238b54d3a6cSRandall Stewart }
2239b54d3a6cSRandall Stewart lchk = TAILQ_FIRST(&asoc->send_queue);
2240b54d3a6cSRandall Stewart
2241b54d3a6cSRandall Stewart net->partial_bytes_acked = 0;
2242b54d3a6cSRandall Stewart /* Turn on fast recovery window */
2243b54d3a6cSRandall Stewart asoc->fast_retran_loss_recovery = 1;
2244b54d3a6cSRandall Stewart if (lchk == NULL) {
2245b54d3a6cSRandall Stewart /* Mark end of the window */
2246b54d3a6cSRandall Stewart asoc->fast_recovery_tsn = asoc->sending_seq - 1;
2247b54d3a6cSRandall Stewart } else {
224849656eefSMichael Tuexen asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1;
2249b54d3a6cSRandall Stewart }
2250b54d3a6cSRandall Stewart
2251b54d3a6cSRandall Stewart /*
2252b54d3a6cSRandall Stewart * CMT fast recovery -- per destination
2253b54d3a6cSRandall Stewart * recovery variable.
2254b54d3a6cSRandall Stewart */
2255b54d3a6cSRandall Stewart net->fast_retran_loss_recovery = 1;
2256b54d3a6cSRandall Stewart
2257b54d3a6cSRandall Stewart if (lchk == NULL) {
2258b54d3a6cSRandall Stewart /* Mark end of the window */
2259b54d3a6cSRandall Stewart net->fast_recovery_tsn = asoc->sending_seq - 1;
2260b54d3a6cSRandall Stewart } else {
226149656eefSMichael Tuexen net->fast_recovery_tsn = lchk->rec.data.tsn - 1;
2262b54d3a6cSRandall Stewart }
2263b54d3a6cSRandall Stewart
2264b54d3a6cSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
2265b7d130beSMichael Tuexen stcb->sctp_ep, stcb, net,
2266b7d130beSMichael Tuexen SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_3);
2267b54d3a6cSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND,
2268b54d3a6cSRandall Stewart stcb->sctp_ep, stcb, net);
2269b54d3a6cSRandall Stewart }
2270b54d3a6cSRandall Stewart } else if (net->net_ack > 0) {
2271b54d3a6cSRandall Stewart /*
2272b54d3a6cSRandall Stewart * Mark a peg that we WOULD have done a cwnd
2273b54d3a6cSRandall Stewart * reduction but RFC2582 prevented this action.
2274b54d3a6cSRandall Stewart */
2275b54d3a6cSRandall Stewart SCTP_STAT_INCR(sctps_fastretransinrtt);
2276b54d3a6cSRandall Stewart }
2277b54d3a6cSRandall Stewart }
2278b54d3a6cSRandall Stewart }
2279b54d3a6cSRandall Stewart
22800e9a9c10SMichael Tuexen static void
sctp_htcp_cwnd_update_after_timeout(struct sctp_tcb * stcb,struct sctp_nets * net)2281b54d3a6cSRandall Stewart sctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb,
2282b54d3a6cSRandall Stewart struct sctp_nets *net)
2283b54d3a6cSRandall Stewart {
2284b54d3a6cSRandall Stewart int old_cwnd = net->cwnd;
2285b54d3a6cSRandall Stewart
2286b54d3a6cSRandall Stewart /* JRS - reset as if the state were being changed to timeout */
2287299108c5SRandall Stewart htcp_reset(&net->cc_mod.htcp_ca);
22887215cc1bSMichael Tuexen net->ssthresh = htcp_recalc_ssthresh(net);
2289b54d3a6cSRandall Stewart net->cwnd = net->mtu;
2290c54a18d2SRandall Stewart net->partial_bytes_acked = 0;
2291b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2292b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX);
2293b54d3a6cSRandall Stewart }
2294b54d3a6cSRandall Stewart }
2295b54d3a6cSRandall Stewart
22960e9a9c10SMichael Tuexen 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)2297b54d3a6cSRandall Stewart sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb,
22987215cc1bSMichael Tuexen struct sctp_nets *net, int in_window, int num_pkt_lost SCTP_UNUSED)
2299b54d3a6cSRandall Stewart {
2300b54d3a6cSRandall Stewart int old_cwnd;
2301b54d3a6cSRandall Stewart
2302b54d3a6cSRandall Stewart old_cwnd = net->cwnd;
2303b54d3a6cSRandall Stewart
2304b54d3a6cSRandall Stewart /* JRS - reset hctp as if state changed */
2305493d8e5aSRandall Stewart if (in_window == 0) {
2306299108c5SRandall Stewart htcp_reset(&net->cc_mod.htcp_ca);
2307b54d3a6cSRandall Stewart SCTP_STAT_INCR(sctps_ecnereducedcwnd);
23087215cc1bSMichael Tuexen net->ssthresh = htcp_recalc_ssthresh(net);
2309b54d3a6cSRandall Stewart if (net->ssthresh < net->mtu) {
2310b54d3a6cSRandall Stewart net->ssthresh = net->mtu;
2311b54d3a6cSRandall Stewart /* here back off the timer as well, to slow us down */
2312b54d3a6cSRandall Stewart net->RTO <<= 1;
2313b54d3a6cSRandall Stewart }
2314b54d3a6cSRandall Stewart net->cwnd = net->ssthresh;
231559b6d5beSMichael Tuexen sctp_enforce_cwnd_limit(&stcb->asoc, net);
2316b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2317b54d3a6cSRandall Stewart sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
2318b54d3a6cSRandall Stewart }
2319b54d3a6cSRandall Stewart }
2320493d8e5aSRandall Stewart }
23210e9a9c10SMichael Tuexen
2322ed654363SMichael Tuexen const struct sctp_cc_functions sctp_cc_functions[] = {
23230e9a9c10SMichael Tuexen {
23240e9a9c10SMichael Tuexen .sctp_set_initial_cc_param = sctp_set_initial_cc_param,
23250e9a9c10SMichael Tuexen .sctp_cwnd_update_after_sack = sctp_cwnd_update_after_sack,
2326ca85e948SMichael Tuexen .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
23270e9a9c10SMichael Tuexen .sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr,
23280e9a9c10SMichael Tuexen .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
23290e9a9c10SMichael Tuexen .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo,
23300e9a9c10SMichael Tuexen .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
23310e9a9c10SMichael Tuexen .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
23320e9a9c10SMichael Tuexen },
23330e9a9c10SMichael Tuexen {
23340e9a9c10SMichael Tuexen .sctp_set_initial_cc_param = sctp_set_initial_cc_param,
23350e9a9c10SMichael Tuexen .sctp_cwnd_update_after_sack = sctp_hs_cwnd_update_after_sack,
2336ca85e948SMichael Tuexen .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
23370e9a9c10SMichael Tuexen .sctp_cwnd_update_after_fr = sctp_hs_cwnd_update_after_fr,
23380e9a9c10SMichael Tuexen .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
23390e9a9c10SMichael Tuexen .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo,
23400e9a9c10SMichael Tuexen .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
23410e9a9c10SMichael Tuexen .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
23420e9a9c10SMichael Tuexen },
23430e9a9c10SMichael Tuexen {
23440e9a9c10SMichael Tuexen .sctp_set_initial_cc_param = sctp_htcp_set_initial_cc_param,
23450e9a9c10SMichael Tuexen .sctp_cwnd_update_after_sack = sctp_htcp_cwnd_update_after_sack,
2346ca85e948SMichael Tuexen .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
23470e9a9c10SMichael Tuexen .sctp_cwnd_update_after_fr = sctp_htcp_cwnd_update_after_fr,
23480e9a9c10SMichael Tuexen .sctp_cwnd_update_after_timeout = sctp_htcp_cwnd_update_after_timeout,
23490e9a9c10SMichael Tuexen .sctp_cwnd_update_after_ecn_echo = sctp_htcp_cwnd_update_after_ecn_echo,
23500e9a9c10SMichael Tuexen .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
23510e9a9c10SMichael Tuexen .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
235248b6c649SRandall Stewart },
235348b6c649SRandall Stewart {
235448b6c649SRandall Stewart .sctp_set_initial_cc_param = sctp_set_rtcc_initial_cc_param,
235548b6c649SRandall Stewart .sctp_cwnd_update_after_sack = sctp_cwnd_update_rtcc_after_sack,
2356ca85e948SMichael Tuexen .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
235748b6c649SRandall Stewart .sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr,
235848b6c649SRandall Stewart .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
235948b6c649SRandall Stewart .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_rtcc_after_ecn_echo,
236048b6c649SRandall Stewart .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
236148b6c649SRandall Stewart .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
236248b6c649SRandall Stewart .sctp_cwnd_update_packet_transmitted = sctp_cwnd_update_rtcc_packet_transmitted,
236348b6c649SRandall Stewart .sctp_cwnd_update_tsn_acknowledged = sctp_cwnd_update_rtcc_tsn_acknowledged,
236448b6c649SRandall Stewart .sctp_cwnd_new_transmission_begins = sctp_cwnd_new_rtcc_transmission_begins,
236548b6c649SRandall Stewart .sctp_cwnd_prepare_net_for_sack = sctp_cwnd_prepare_rtcc_net_for_sack,
2366f79aab18SRandall Stewart .sctp_cwnd_socket_option = sctp_cwnd_rtcc_socket_option,
2367f79aab18SRandall Stewart .sctp_rtt_calculated = sctp_rtt_rtcc_calculated
23680e9a9c10SMichael Tuexen }
23690e9a9c10SMichael Tuexen };
2370