Coverage Report

Created: 2025-07-12 06:07

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