NetSim Source Code Help v14.4
All 13 Components
 
Loading...
Searching...
No Matches
CUBIC.c
1/************************************************************************************
2* Copyright (C) 2023 *
3* TETCOS, Bangalore. India *
4* *
5* Tetcos owns the intellectual property rights in the Product and its content. *
6* The copying, redistribution, reselling or publication of any or all of the *
7* Product or its content without express prior written consent of Tetcos is *
8* prohibited. Ownership and / or any other right relating to the software and all *
9* intellectual property rights therein shall remain at all times with Tetcos. *
10* *
11* Author: Shashi Kant Suman *
12* *
13* ---------------------------------------------------------------------------------*/
14#include "main.h"
15#include "TCP.h"
16#include <intrin.h>
17
18//#define _TEST_CONGESTION_
19
20#ifdef _TEST_CONGESTION_
21static FILE* fp;
22#endif
23
24#define clamp(val, lo, hi) min(max(val, lo), hi)
25
26#define tcp_time_stamp ((UINT32)(pstruEventDetails->dEventTime/1000))
27#define CUBIC_HZ 1024
28
29#define BICTCP_BETA_SCALE 1024 /* Scale factor beta calculation
30* max_cwnd = snd_cwnd * beta
31*/
32#define BICTCP_HZ 10 /* BIC HZ 2^10 = 1024 */
33
34/* Two methods of hybrid slow start */
35#define HYSTART_ACK_TRAIN 0x1
36#define HYSTART_DELAY 0x2
37
38/* Number of delay samples for detecting the increase of delay */
39#define HYSTART_MIN_SAMPLES 8
40#define HYSTART_DELAY_MIN (4U<<3)
41#define HYSTART_DELAY_MAX (16U<<3)
42#define HYSTART_DELAY_THRESH(x) clamp(x, HYSTART_DELAY_MIN, HYSTART_DELAY_MAX)
43
44static int fast_convergence = 1;
45static int tcp_friendliness = 1;
46
47static int hystart = 1;
48static int hystart_detect = HYSTART_ACK_TRAIN | HYSTART_DELAY;
49
50
51static UINT32 cube_rtt_scale;
52static UINT32 beta_scale;
53static UINT32 cube_factor;
54
55typedef struct stru_cubic
56{
57 UINT32 hystart_low_window;
58 int hystart_ack_delta;
59 int bic_scale;
60 int beta; /* = 717/1024 (BICTCP_BETA_SCALE) */
61 UINT32 initial_ssthresh;
62
63 UINT32 cnt; /* increase cwnd by 1 after ACKs */
64 UINT32 last_max_cwnd; /* last maximum snd_cwnd */
65 UINT32 loss_cwnd; /* congestion window at last loss */
66 UINT32 last_cwnd; /* the last snd_cwnd */
67 UINT32 last_time; /* time when updated last_cwnd */
68 UINT32 bic_origin_point;/* origin point of bic function */
69 UINT32 bic_K; /* time to origin point
70 from the beginning of the current epoch */
71 UINT32 delay_min; /* min delay (msec << 3) */
72 UINT32 epoch_start; /* beginning of an epoch */
73 UINT32 ack_cnt; /* number of acks */
74 UINT32 tcp_cwnd; /* estimated tcp cwnd */
75 UINT32 unused;
76 UINT8 sample_cnt; /* number of samples to decide curr_rtt */
77 UINT8 found; /* the exit point is found? */
78 UINT32 round_start; /* beginning of each round */
79 UINT32 end_seq; /* end_seq of the round */
80 UINT32 last_ack; /* last time when the ACK spacing is close */
81 UINT32 curr_rtt; /* the minimum rtt of current round */
82 UINT32 cwndcnt;
83}CUBIC, *PCUBIC;
84
85typedef struct stru_congestion_var
86{
87 UINT16 SMSS; ///< To store the size of the largest segment that the sender can transmit.
88 UINT16 RMSS; ///< To store the size of the largest segment that the receiver is willing to accept.
89 UINT16 IW; ///< Size of the sender's congestion window after the three-way handshake is completed.
90 UINT16 LW;
91 UINT16 ssthresh; ///< To store slow start threshold value
92 UINT16 cwnd; ///< To store Congestion window size value.
93 UINT16 rwnd; ///< To store the most recently advertised receiver window size value.
94 double lastWinUpdateTime;
95
96 //Fast Retransmit
97 bool isFastRetransmit;
98 UINT dupAckCount;
99
100 //Fast Recovery
101 bool isFastRecovery;
102
103 //SACK
104 bool isLossRecoveryPhase;
105
106 //CUBIC
107 CUBIC cubic;
108}CONGESTIONVAR, *PCONGESTIONVAR;
109
110static inline PCONGESTIONVAR get_congestionvar(PNETSIM_SOCKET s)
111{
112 return (PCONGESTIONVAR)s->tcb->congestionData;
113}
114
115static inline void set_congestionvar(PNETSIM_SOCKET s, PCONGESTIONVAR data)
116{
117 s->tcb->congestionData = data;
118}
119
120static void set_cwnd(PNETSIM_SOCKET s, UINT32 newcwnd)
121{
122 PCONGESTIONVAR var = get_congestionvar(s);
123 if (s->tcb->isWindowScaling)
124 {
125 UINT32 c = (UINT32)newcwnd;
126 var->cwnd = (UINT16)(c >> s->tcb->Snd.Wind_Shift);
127 assert(var->cwnd < 65535);
128 }
129 else
130 {
131 var->cwnd = (UINT16)newcwnd;
132 }
133}
134
135static UINT32 get_cwnd(PNETSIM_SOCKET s)
136{
137 PCONGESTIONVAR var = get_congestionvar(s);
138 UINT32 c = (UINT32)var->cwnd;
139 if (s->tcb->isWindowScaling)
140 {
141 return c << s->tcb->Snd.Wind_Shift;
142 }
143 else
144 {
145 return c;
146 }
147}
148
149static void set_ssthres(PNETSIM_SOCKET s, UINT32 newssthres)
150{
151 PCONGESTIONVAR var = get_congestionvar(s);
152 if (s->tcb->isWindowScaling)
153 {
154 UINT32 c = (UINT32)newssthres;
155 var->ssthresh = (UINT16)(c >> s->tcb->Snd.Wind_Shift);
156 }
157 else
158 {
159 var->ssthresh = (UINT16)newssthres;
160 }
161}
162
163static UINT32 get_ssthres(PNETSIM_SOCKET s)
164{
165 PCONGESTIONVAR var = get_congestionvar(s);
166 UINT32 c = (UINT32)var->ssthresh;
167 if (s->tcb->isWindowScaling)
168 {
169 return c << s->tcb->Snd.Wind_Shift;
170 }
171 else
172 {
173 return c;
174 }
175}
176
177static void increase_cwnd(PNETSIM_SOCKET s, UINT16 increase)
178{
179 PCONGESTIONVAR var = get_congestionvar(s);
180 if (s->tcb->isWindowScaling)
181 {
182 UINT32 c = window_scale_get_cwnd(s);
183 c += increase;
184 var->cwnd = (UINT16)(c >> s->tcb->Snd.Wind_Shift);
185 assert(var->cwnd < 65535);
186 }
187 else
188 {
189 UINT32 c = var->cwnd + increase;
190 if (c >= 65535)
191 var->cwnd = 65535; // Don't want to do this. But no option.
192 else
193 var->cwnd = var->cwnd + increase;
194 }
195}
196
197static inline bool tcp_in_slow_start(PNETSIM_SOCKET s)
198{
199 return (get_cwnd(s) <= get_ssthres(s));
200}
201
202static bool isDupAck(PNETSIM_SOCKET s, PCONGESTIONVAR var)
203{
204 var;
205 return (s->tcb->SEG.ACK <= s->tcb->SND.UNA);
206}
207
208/**
209* div64_u64 - unsigned 64bit divide with 64bit divisor
210*/
211static inline UINT64 div64_u64(UINT64 dividend, UINT64 divisor)
212{
213 return dividend / divisor;
214}
215
216#define do_div(x,y) (x=x/y)
217
218static inline bool before(UINT32 seq1, UINT32 seq2)
219{
220 return (int)(seq1 - seq2) < 0;
221}
222#define after(seq2, seq1) before(seq1, seq2)
223
224static UINT count_bit(UINT64 n)
225{
226 char a[100];
227 _i64toa(n, a, 2);
228 int i;
229 int len = (int)strlen(a);
230 for (i = 0; i < len; i++)
231 if (a[i] == '1')
232 return i;
233 return 0;
234}
235
236static void slowStart(PNETSIM_SOCKET s, PCONGESTIONVAR var)
237{
238 //Slow start mode
239 UINT16 N; /* N is the number of previously unacknowledged
240 * bytes acknowledged in the incoming ACK.
241 */
242 N = (UINT16)(s->tcb->SEG.ACK - s->tcb->SND.UNA);
243 increase_cwnd(s, min(N, var->SMSS));
244}
245
246static inline void cubictcp_reset(PCUBIC ca)
247{
248 ca->cnt = 0;
249 ca->last_max_cwnd = 0;
250 ca->last_cwnd = 0;
251 ca->last_time = 0;
252 ca->bic_origin_point = 0;
253 ca->bic_K = 0;
254 ca->delay_min = 0;
255 ca->epoch_start = 0;
256 ca->ack_cnt = 0;
257 ca->tcp_cwnd = 0;
258 ca->found = 0;
259}
260
261static inline UINT32 cubictcp_clock(void)
262{
263 return (UINT32)(pstruEventDetails->dEventTime / 1000);
264}
265
266static inline void cubictcp_hystart_reset(PNETSIM_SOCKET sk)
267{
268 PCUBIC ca = &get_congestionvar(sk)->cubic;
269
270 ca->round_start = ca->last_ack = cubictcp_clock();
271 ca->end_seq = sk->tcb->SND.NXT;
272 ca->curr_rtt = 0;
273 ca->sample_cnt = 0;
274}
275
276static void cubictcp_init(PNETSIM_SOCKET sk, PTCP_DEV_VAR tcp)
277{
278 PCUBIC ca = &get_congestionvar(sk)->cubic;
279
280 cubictcp_reset(ca);
281 ca->loss_cwnd = 0;
282
283 ca->hystart_ack_delta = tcp->hystart_ack_delta;
284 ca->hystart_low_window = tcp->hystart_low_window;
285 ca->beta = (int)tcp->beta;
286 ca->bic_scale = tcp->bic_scale;
287 ca->initial_ssthresh = tcp->initSSThresh;
288
289 if (hystart)
290 cubictcp_hystart_reset(sk);
291}
292
293void init_cubic(PNETSIM_SOCKET s)
294{
295 PTCP_DEV_VAR tcp = GET_TCP_DEV_VAR(s->localDeviceId);
296 PCONGESTIONVAR var = get_congestionvar(s);
297 if (!var)
298 {
299 var = (PCONGESTIONVAR)calloc(1, sizeof* var);
300 set_congestionvar(s, var);
301 }
302 var->SMSS = tcp->MSS;
303 var->RMSS = tcp->MSS;
304 set_ssthres(s, tcp->initSSThresh);
305 var->cwnd = var->ssthresh;
306 var->rwnd = var->ssthresh;
307
308 var->isFastRetransmit = true;
309
310 cubictcp_init(s,tcp);
311 PCUBIC cubic = &var->cubic;
312
313 beta_scale = 8 * (BICTCP_BETA_SCALE + cubic->beta) / 3
314 / (BICTCP_BETA_SCALE - cubic->beta);
315
316 cube_rtt_scale = (cubic->bic_scale * 10); /* 1024*c/rtt */
317
318 /* calculate the "K" for (wmax-cwnd) = c/rtt * K^3
319 * so K = cubic_root( (wmax-cwnd)*rtt/c )
320 * the unit of K is bictcp_HZ=2^10, not HZ
321 *
322 * c = bic_scale >> 10
323 * rtt = 100ms
324 *
325 * the following code has been designed and tested for
326 * cwnd < 1 million packets
327 * RTT < 100 seconds
328 * HZ < 1,000,00 (corresponding to 10 nano-second)
329 */
330
331 /* 1/c * 2^2*bictcp_HZ * srtt */
332
333#pragma warning(disable:4310)
334 cube_factor = (UINT32)(1ull << (10 + 3 * BICTCP_HZ)); /* 2^40 */
335#pragma warning(default:4310)
336
337 /* divide by bic_scale and by constant Srtt (100ms) */
338 do_div(cube_factor, cubic->bic_scale * 10);
339
340
341#ifdef _TEST_CONGESTION_
342 fp = fopen("Congestion.csv", "w");
343 fprintf(fp, "Called For,Time,CWND,ssThres,Flight Size,Ackno,UNA,\n");
344 fflush(fp);
345#endif
346}
347
348/* calculate the cubic root of x using a table lookup followed by one
349* Newton-Raphson iteration.
350* Avg err ~= 0.195%
351*/
352static UINT32 cubic_root(UINT64 a)
353{
354 UINT32 x, b, shift;
355 /*
356 * cbrt(x) MSB values for x MSB values in [0..63].
357 * Precomputed then refined by hand - Willy Tarreau
358 *
359 * For x in [0..63],
360 * v = cbrt(x << 18) - 1
361 * cbrt(x) = (v[x] + 10) >> 6
362 */
363 static const UINT8 v[] = {
364 /* 0x00 */ 0, 54, 54, 54, 118, 118, 118, 118,
365 /* 0x08 */ 123, 129, 134, 138, 143, 147, 151, 156,
366 /* 0x10 */ 157, 161, 164, 168, 170, 173, 176, 179,
367 /* 0x18 */ 181, 185, 187, 190, 192, 194, 197, 199,
368 /* 0x20 */ 200, 202, 204, 206, 209, 211, 213, 215,
369 /* 0x28 */ 217, 219, 221, 222, 224, 225, 227, 229,
370 /* 0x30 */ 231, 232, 234, 236, 237, 239, 240, 242,
371 /* 0x38 */ 244, 245, 246, 248, 250, 251, 252, 254,
372 };
373
374 b = count_bit(a);
375 if (b < 7) {
376 /* a in [0..63] */
377 return ((UINT32)v[(UINT32)a] + 35) >> 6;
378 }
379
380 b = ((b * 84) >> 8) - 1;
381 shift = (UINT32)(a >> (b * 3));
382
383 x = ((UINT32)(((UINT32)v[shift] + 10) << b)) >> 6;
384
385 /*
386 * Newton-Raphson iteration
387 * 2
388 * x = ( 2 * x + a / x ) / 3
389 * k+1 k k
390 */
391 x = (2 * x + (UINT32)div64_u64(a, (UINT64)x * (UINT64)(x - 1)));
392 x = ((x * 341) >> 10);
393 return x;
394}
395
396static UINT32 cubictcp_recalc_ssthresh(PNETSIM_SOCKET sk)
397{
398 PCUBIC ca = &get_congestionvar(sk)->cubic;
399
400 UINT32 segCwnd = (UINT32)get_cwnd(sk) / sk->tcb->get_MSS(sk);
401
402 ca->epoch_start = 0; /* end of epoch */
403
404 /* Wmax and fast convergence */
405 if (segCwnd < ca->last_max_cwnd && fast_convergence)
406 ca->last_max_cwnd = (segCwnd * (BICTCP_BETA_SCALE + ca->beta))
407 / (2 * BICTCP_BETA_SCALE);
408 else
409 ca->last_max_cwnd = segCwnd;
410
411 ca->loss_cwnd = segCwnd;
412
413 return max((segCwnd * ca->beta) / BICTCP_BETA_SCALE, 2U);
414}
415
416/*
417* Compute congestion window to use.
418*/
419static inline void cubictcp_update(PNETSIM_SOCKET sk, UINT32 acked)
420{
421 PCONGESTIONVAR c = get_congestionvar(sk);
422 PCUBIC ca = &c->cubic;
423 UINT32 cwnd = (UINT32)get_cwnd(sk) / sk->tcb->get_MSS(sk);
424
425 UINT32 delta, bic_target, max_cnt;
426 UINT64 offs, t;
427
428 ca->ack_cnt += acked; /* count the number of ACKed packets */
429
430 if (ca->last_cwnd == cwnd &&
431 (int)(tcp_time_stamp - ca->last_time) <= CUBIC_HZ / 32)
432 return;
433
434 /* The CUBIC function can update ca->cnt at most once per jiffy.
435 * On all cwnd reduction events, ca->epoch_start is set to 0,
436 * which will force a recalculation of ca->cnt.
437 */
438 if (ca->epoch_start && tcp_time_stamp == ca->last_time)
439 goto tcp_friendliness;
440
441 ca->last_cwnd = cwnd;
442 ca->last_time = tcp_time_stamp;
443
444 if (ca->epoch_start == 0)
445 {
446 ca->epoch_start = tcp_time_stamp; /* record beginning */
447 ca->ack_cnt = acked; /* start counting */
448 ca->tcp_cwnd = cwnd; /* syn with cubic */
449
450 if (ca->last_max_cwnd <= cwnd)
451 {
452 ca->bic_K = 0;
453 ca->bic_origin_point = cwnd;
454 }
455 else
456 {
457 /* Compute new K based on
458 * (wmax-cwnd) * (srtt>>3 / HZ) / c * 2^(3*bictcp_HZ)
459 */
460 ca->bic_K = cubic_root((UINT64)cube_factor
461 * (ca->last_max_cwnd - cwnd));
462 ca->bic_origin_point = ca->last_max_cwnd;
463 }
464 }
465
466 /* cubic function - calc*/
467 /* calculate c * time^3 / rtt,
468 * while considering overflow in calculation of time^3
469 * (so time^3 is done by using 64 bit)
470 * and without the support of division of 64bit numbers
471 * (so all divisions are done by using 32 bit)
472 * also NOTE the unit of those veriables
473 * time = (t - K) / 2^bictcp_HZ
474 * c = bic_scale >> 10
475 * rtt = (srtt >> 3) / HZ
476 * !!! The following code does not have overflow problems,
477 * if the cwnd < 1 million packets !!!
478 */
479
480 t = (UINT64)(tcp_time_stamp - ca->epoch_start);
481 t += (ca->delay_min >> 3);
482 /* change the unit from HZ to bictcp_HZ */
483 t <<= BICTCP_HZ;
484 do_div(t, CUBIC_HZ);
485
486 if (t < ca->bic_K) /* t - K */
487 offs = ca->bic_K - t;
488 else
489 offs = t - ca->bic_K;
490
491 /* c/rtt * (t-K)^3 */
492 delta = (cube_rtt_scale * offs * offs * offs) >> (10 + 3 * BICTCP_HZ);
493 if (t < ca->bic_K) /* below origin*/
494 bic_target = ca->bic_origin_point - delta;
495 else /* above origin*/
496 bic_target = ca->bic_origin_point + delta;
497
498 /* cubic function - calc bictcp_cnt*/
499 if (bic_target > cwnd)
500 {
501 ca->cnt = cwnd / (bic_target - cwnd);
502 }
503 else
504 {
505 ca->cnt = 100 * cwnd; /* very small increment*/
506 }
507
508 /*
509 * The initial growth of cubic function may be too conservative
510 * when the available bandwidth is still unknown.
511 */
512 if (ca->last_max_cwnd == 0 && ca->cnt > 20)
513 ca->cnt = 20; /* increase cwnd 5% per RTT */
514
515tcp_friendliness:
516 /* TCP Friendly */
517 if (tcp_friendliness)
518 {
519 UINT32 scale = beta_scale;
520
521 delta = (cwnd * scale) >> 3;
522 while (delta && ca->ack_cnt > delta)
523 { /* update tcp cwnd */
524 ca->ack_cnt -= delta;
525 ca->tcp_cwnd++;
526 }
527
528 if (ca->tcp_cwnd > cwnd)
529 { /* if bic is slower than tcp */
530 delta = ca->tcp_cwnd - cwnd;
531 max_cnt = cwnd / delta;
532 if (ca->cnt > max_cnt)
533 ca->cnt = max_cnt;
534 }
535 }
536
537 /* The maximum rate of cwnd increase CUBIC allows is 1 packet per
538 * 2 packets ACKed, meaning cwnd grows at 1.5x per RTT.
539 */
540 ca->cnt = max(ca->cnt, 2U);
541
542}
543
544static void cubictcp_cong_avoid(PNETSIM_SOCKET sk, UINT32 segmentAcked)
545{
546 PCONGESTIONVAR var = get_congestionvar(sk);
547 PCUBIC ca = &var->cubic;
548 UINT32 ack = sk->tcb->SEG.ACK;
549
550 if (tcp_in_slow_start(sk))
551 {
552 if (hystart && after(ack, ca->end_seq))
553 cubictcp_hystart_reset(sk);
554 slowStart(sk, get_congestionvar(sk));
555 segmentAcked--;
556 }
557
558 if (!tcp_in_slow_start(sk) && segmentAcked > 0)
559 {
560
561 ca->cwndcnt += segmentAcked;
562 cubictcp_update(sk,segmentAcked);
563 UINT32 cnt = ca->cnt;
564 /* According to the BIC paper and RFC 6356 even once the new cwnd is
565 * calculated you must compare this to the number of ACKs received since
566 * the last cwnd update. If not enough ACKs have been received then cwnd
567 * cannot be updated.
568 */
569 if (ca->cwndcnt > cnt)
570 {
571 increase_cwnd(sk, var->SMSS);
572 ca->cwndcnt = 0;
573 }
574 else
575 {
576 //Not enough segments have been ACKed to increment cwnd
577 }
578 }
579}
580
581static void hystart_update(PNETSIM_SOCKET sk, UINT32 delay)
582{
583 PCONGESTIONVAR var = get_congestionvar(sk);
584 PCUBIC ca = &var->cubic;
585
586 if (ca->found & hystart_detect)
587 return;
588
589 if (hystart_detect & HYSTART_ACK_TRAIN) {
590 UINT32 now = cubictcp_clock();
591
592 /* first detection parameter - ack-train detection */
593 if ((int)(now - ca->last_ack) <= ca->hystart_ack_delta)
594 {
595 ca->last_ack = now;
596 if ((int)(now - ca->round_start) > ca->delay_min >> 4)
597 {
598 ca->found |= HYSTART_ACK_TRAIN;
599 if(get_ssthres(sk) != ca->initial_ssthresh)
600 set_cwnd(sk, get_ssthres(sk));
601 }
602 }
603 }
604
605 if (hystart_detect & HYSTART_DELAY)
606 {
607 /* obtain the minimum delay of more than sampling packets */
608 if (ca->sample_cnt < HYSTART_MIN_SAMPLES)
609 {
610 if (ca->curr_rtt == 0 || ca->curr_rtt > delay)
611 ca->curr_rtt = delay;
612
613 ca->sample_cnt++;
614 }
615 else
616 {
617 if (ca->curr_rtt > ca->delay_min +
618 HYSTART_DELAY_THRESH(ca->delay_min >> 3))
619 {
620 ca->found |= HYSTART_DELAY;
621 set_ssthres(sk, get_cwnd(sk));
622 }
623 }
624 }
625}
626
627/* Track delayed acknowledgment ratio using sliding window
628* ratio = (15*ratio + sample) / 16
629*/
630static void cubictcp_acked(PNETSIM_SOCKET sk)
631{
632 PCUBIC ca = &get_congestionvar(sk)->cubic;
633 UINT32 delay;
634 UINT32 cwnd = (UINT32)get_cwnd(sk) / sk->tcb->get_MSS(sk);
635 delay = (UINT32)((((UINT32)get_RTT(sk->tcb, sk->tcb->SEG.ACK)) << 3) / MILLISECOND);
636 if (!delay)
637 delay = 1;
638
639 /* hystart triggers when cwnd is larger than some threshold */
640 if (hystart && tcp_in_slow_start(sk) &&
641 cwnd >= ca->hystart_low_window)
642 hystart_update(sk, delay);
643}
644
645static void cubictcp_fastretransmit(PNETSIM_SOCKET s)
646{
647 PCONGESTIONVAR var = get_congestionvar(s);
648
649 if (var->dupAckCount == TCP_DupThresh)
650 {
651 UINT32 ssThresh = cubictcp_recalc_ssthresh(s);
652 set_ssthres(s, ssThresh*s->tcb->get_MSS(s));
653
654 /*
655 3. The lost segment starting at SND.UNA MUST be retransmitted and
656 cwnd set to ssthresh plus 3*SMSS. This artificially "inflates"
657 the congestion window by the number of segments (three) that have
658 left the network and which the receiver has buffered.
659 */
660 set_cwnd(s, get_ssthres(s) + TCP_DupThresh * var->SMSS);
661 resend_segment_without_timeout(s, s->tcb->SEG.ACK);
662
663 var->isFastRecovery = true;
664
665 if (s->tcb->isSackOption)
666 {
667 tcp_sack_fastRetransmit(s);
668 var->isLossRecoveryPhase = true;
669 }
670 }
671 else
672 {
673 /*
674 4. For each additional duplicate ACK received(after the third),
675 cwnd MUST be incremented by SMSS.This artificially inflates the
676 congestion window in order to reflect the additional segment that
677 has left the network.
678 */
679 increase_cwnd(s, var->SMSS);
680
681 if (s->tcb->isSackOption &&
682 var->isLossRecoveryPhase)
683 {
684 var->isLossRecoveryPhase = tcp_sack_lossRecoveryPhase(s);
685 }
686 }
687}
688
689static void FastRecovery(PNETSIM_SOCKET s, PCONGESTIONVAR var)
690{
691 var->isFastRecovery = false;
692 var->dupAckCount = 0;
693 set_cwnd(s, get_ssthres(s));
694}
695
696void cubic_ack_received(PNETSIM_SOCKET s)
697 {
698 PCONGESTIONVAR var = get_congestionvar(s);
699 UINT32 segmentAcked = (s->tcb->SEG.ACK - s->tcb->SND.UNA) /
700 s->tcb->get_MSS(s);
701
702 bool isdup = isDupAck(s, var);
703 if (isdup)
704 {
705 var->dupAckCount++;
706 if (var->dupAckCount < TCP_DupThresh)
707 {
708 if (s->tcb->isSackOption &&
709 tcp_sack_isLost(s, get_highAck(s) + 1))
710 {
711 cubictcp_fastretransmit(s);
712 }
713 }
714 else
715 {
716 cubictcp_fastretransmit(s);
717 }
718 }
719 else if (var->isFastRecovery)
720 {
721 FastRecovery(s, var);
722 }
723 else
724 {
725 cubictcp_acked(s);
726 cubictcp_cong_avoid(s, segmentAcked);
727 }
728
729#ifdef _TEST_CONGESTION_
730 fprintf(fp, "Ack,%lf,%d,%d,%d,%d,%d\n",
731 pstruEventDetails->dEventTime,
732 get_cwnd_print(s),
733 get_ssthres(s),
734 s->tcb->SND.NXT - s->tcb->SND.UNA,
735 s->tcb->SEG.ACK, s->tcb->SND.UNA);
736 fflush(fp);
737#endif
738}
UINT16 IW
Size of the sender's congestion window after the three-way handshake is completed.
Definition Congestion.c:53
UINT16 RMSS
To store the size of the largest segment that the receiver is willing to accept.
Definition Congestion.c:52
UINT16 ssthresh
To store slow start threshold value.
Definition Congestion.c:55
UINT16 rwnd
To store the most recently advertised receiver window size value.
Definition Congestion.c:57
UINT16 SMSS
To store the size of the largest segment that the sender can transmit.
Definition Congestion.c:51
UINT16 cwnd
To store Congestion window size value.
Definition Congestion.c:56