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