NetSim Source Code Help v14.4
All 13 Components
 
Loading...
Searching...
No Matches
Congestion.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
17//#define _TEST_CONGESTION_
18
19#ifdef _TEST_CONGESTION_
20static FILE* fp;
21#endif
22void cubic_ack_received(PNETSIM_SOCKET s);
23void init_cubic(PNETSIM_SOCKET s);
24
25#define BICTCP_BETA_SCALE 1024 /* Scale factor beta calculation
26 * max_cwnd = snd_cwnd * beta
27 */
28
29#define BICTCP_B 4 /*
30 * In binary search,
31 * go to point (max+min)/N
32 */
33
34typedef struct stru_bic
35{
36 UINT32 low_window;
37 UINT32 max_increment;
38 bool fast_convergence;
39 double beta;
40 UINT32 smooth_part;
41
42 UINT32 cnt; /* increase cwnd by 1 after ACKs */
43 UINT32 last_max_cwnd; /* last maximum snd_cwnd */
44 UINT32 loss_cwnd; /* congestion window at last loss */
45 UINT32 last_cwnd; /* the last snd_cwnd */
46 UINT32 last_time; /* time when updated last_cwnd */
47 UINT32 epoch_start; /* beginning of an epoch */
48#define ACK_RATIO_SHIFT 4
49 UINT32 delayed_ack; /* estimate the ratio of Packets/ACKs << 4 */
50
51 UINT32 cwndcnt;
52}BIC,*PBIC;
54typedef struct stru_congestion_var
56 UINT16 SMSS; ///< To store the size of the largest segment that the sender can transmit.
57 UINT16 RMSS; ///< To store the size of the largest segment that the receiver is willing to accept.
58 UINT16 IW; ///< Size of the sender's congestion window after the three-way handshake is completed.
59 UINT16 LW;
60 UINT16 ssthresh; ///< To store slow start threshold value
61 UINT16 cwnd; ///< To store Congestion window size value.
62 UINT16 rwnd; ///< To store the most recently advertised receiver window size value.
63 double lastWinUpdateTime;
64
65 //Fast Retransmit
66 bool isFastRetransmit;
67 UINT dupAckCount;
68
69 //Fast Recovery
70 bool isFastRecovery;
71
72 //new reno modification for fast recovery
73 UINT recover;
74
75 //SACK
76 bool isLossRecoveryPhase;
77
78 //BIC
79 BIC bic;
80}CONGESTIONVAR,*PCONGESTIONVAR;
81
82static inline bool isReno(PNETSIM_SOCKET s)
83{
84 return s->tcb->variant == TCPVariant_RENO ||
85 s->tcb->variant == TCPVariant_NEWRENO;
86}
87
88static inline bool isBIC(PNETSIM_SOCKET s)
89{
90 return s->tcb->variant == TCPVariant_BIC;
91}
92
93static inline bool isNewReno(PNETSIM_SOCKET s)
94{
95 return s->tcb->variant == TCPVariant_NEWRENO;
96}
97
98static inline bool isFastRetransmit(PNETSIM_SOCKET s)
99{
100 return s->tcb->variant == TCPVariant_TAHOE ||
101 s->tcb->variant == TCPVariant_RENO ||
102 s->tcb->variant == TCPVariant_NEWRENO;
103}
104
105static inline bool isFastRecovery(PNETSIM_SOCKET s)
106{
107 return s->tcb->variant == TCPVariant_RENO ||
108 s->tcb->variant == TCPVariant_NEWRENO ||
109 s->tcb->variant == TCPVariant_BIC;
110}
111
112static inline PCONGESTIONVAR get_congestionvar(PNETSIM_SOCKET s)
113{
114 return (PCONGESTIONVAR)s->tcb->congestionData;
115}
116
117static inline void set_congestionvar(PNETSIM_SOCKET s, PCONGESTIONVAR data)
118{
119 s->tcb->congestionData = data;
120}
121
122static inline UINT16 congestion_get_MSS(PNETSIM_SOCKET s)
123{
124 return get_congestionvar(s)->SMSS;
125}
126
127static inline UINT16 congestion_get_WND(PNETSIM_SOCKET s)
128{
129 return get_congestionvar(s)->cwnd;
130}
131
132static inline UINT32 congestion_get_RCV_WND(PNETSIM_SOCKET s)
133{
134 PCONGESTIONVAR var = get_congestionvar(s);
135 if (s->tcb->isWindowScaling)
136 {
137 UINT32 c = var->rwnd;
138 return c << s->tcb->Rcv.Wind_Shift;
139 }
140 else
141 {
142 return var->rwnd;
143 }
144}
145
146static void set_ssthres(PNETSIM_SOCKET s, UINT32 newssthres)
147{
148 PCONGESTIONVAR var = get_congestionvar(s);
149 if (s->tcb->isWindowScaling)
150 {
151 UINT32 c = (UINT32)newssthres;
152 var->ssthresh = (UINT16)(c >> s->tcb->Snd.Wind_Shift);
153 }
154 else
155 {
156 var->ssthresh = (UINT16)newssthres;
157 }
158}
159
160static UINT32 get_ssthres(PNETSIM_SOCKET s)
161{
162 PCONGESTIONVAR var = get_congestionvar(s);
163 UINT32 c = (UINT32)var->ssthresh;
164 if (s->tcb->isWindowScaling)
165 {
166 return c << s->tcb->Snd.Wind_Shift;
167 }
168 else
169 {
170 return c;
171 }
172}
173
174static void set_cwnd(PNETSIM_SOCKET s, UINT32 newcwnd)
175{
176 PCONGESTIONVAR var = get_congestionvar(s);
177 if (s->tcb->isWindowScaling)
178 {
179 UINT32 c = (UINT32)newcwnd;
180 var->cwnd = (UINT16)(c >> s->tcb->Snd.Wind_Shift);
181 assert(var->cwnd < 65535);
182 if (!var->cwnd)
183 var->cwnd = 1;
184 }
185 else
186 {
187 var->cwnd = (UINT16)newcwnd;
188 }
189}
190
191static UINT32 get_cwnd(PNETSIM_SOCKET s)
192{
193 PCONGESTIONVAR var = get_congestionvar(s);
194 UINT32 c = (UINT32)var->cwnd;
195 if (s->tcb->isWindowScaling)
196 {
197 return c << s->tcb->Snd.Wind_Shift;
198 }
199 else
200 {
201 return c;
202 }
203}
204
205UINT32 get_cwnd_print(PNETSIM_SOCKET s)
206{
207 PCONGESTIONVAR var = get_congestionvar(s);
208 if (s->tcb->isWindowScaling)
209 {
210 UINT32 c = (UINT32)var->cwnd;
211 return (UINT32)(c << s->tcb->Snd.Wind_Shift);
212 }
213 else
214 {
215 return (UINT32)var->cwnd;
216 }
217}
218
219static inline bool tcp_in_slow_start(PNETSIM_SOCKET s)
220{
221 return (get_cwnd(s) <= get_ssthres(s));
222}
223
224static inline void bictcp_reset(PBIC ca)
225{
226 ca->cnt = 0;
227 ca->last_max_cwnd = 0;
228 ca->last_cwnd = 0;
229 ca->last_time = 0;
230 ca->epoch_start = 0;
231 ca->delayed_ack = 2 << ACK_RATIO_SHIFT;
232}
233
234static void bictcp_init(PNETSIM_SOCKET sk, PTCP_DEV_VAR tcp)
235{
236 PBIC bic = &get_congestionvar(sk)->bic;
237
238 bictcp_reset(bic);
239 bic->loss_cwnd = 0;
240
241 bic->low_window = tcp->low_window;
242 bic->max_increment = tcp->max_increment;
243 bic->fast_convergence = true;
244 bic->beta = tcp->beta;
245 bic->smooth_part = tcp->smooth_part;
246}
247
248static void init_congestion(PNETSIM_SOCKET s)
249{
250 PTCP_DEV_VAR tcp = GET_TCP_DEV_VAR(s->localDeviceId);
251 PCONGESTIONVAR var = get_congestionvar(s);
252 if (!var)
253 {
254 var = (PCONGESTIONVAR)calloc(1, sizeof* var);
255 set_congestionvar(s, var);
256 }
257 var->SMSS = tcp->MSS;
258 var->RMSS = tcp->MSS;
259 set_ssthres(s, tcp->initSSThresh);
260 var->cwnd = var->ssthresh;
261 var->rwnd = var->ssthresh;
262
263 var->isFastRetransmit = isFastRetransmit(s);
264
265 if(isNewReno(s))
266 var->recover = s->tcb->ISS;
267
268 if (isBIC(s))
269 bictcp_init(s, tcp);
270
271#ifdef _TEST_CONGESTION_
272 fp = fopen("Congestion.csv","w");
273 fprintf(fp, "Called For,Time,CWND,ssThres,Flight Size,Ackno,UNA,\n");
274 fflush(fp);
275#endif
276}
277
278static void increase_cwnd(PNETSIM_SOCKET s, UINT16 increase)
279{
280 PCONGESTIONVAR var = get_congestionvar(s);
281 if (s->tcb->isWindowScaling)
282 {
283 UINT32 c = window_scale_get_cwnd(s);
284 c += increase;
285 UINT32 cwnd = c >> s->tcb->Snd.Wind_Shift;
286 if (cwnd >= 65535)
287 var->cwnd = 65535; // Don't want to do this. But no option.
288 else
289 var->cwnd = (UINT16)cwnd;
290 assert(var->cwnd <= 65535);
291 }
292 else
293 {
294 UINT32 c = var->cwnd + increase;
295 if (c >= 65535)
296 var->cwnd = 65535; // Don't want to do this. But no option.
297 else
298 var->cwnd = var->cwnd + increase;
299 }
300}
301
302//RFC 3390
303static void congestion_set_IW(PNETSIM_SOCKET s)
304{
305 PCONGESTIONVAR var = get_congestionvar(s);
306 PTCP_DEV_VAR t = GET_TCP_DEV_VAR(s->localDeviceId);
307
308 if (var->SMSS > 2190)
309 var->IW = max(2 * var->SMSS, 2 * t->MSS);
310 else if (var->SMSS > 1095)
311 var->IW = max(3 * var->SMSS, 3 * t->MSS);
312 else if (var->SMSS <= 1095)
313 var->IW = max(4 * var->SMSS, 4 * t->MSS);
314}
315
316static void congestion_set_MSS(PNETSIM_SOCKET s, UINT16 mss)
317{
318 PCONGESTIONVAR var = get_congestionvar(s);
319 var->SMSS = min(var->SMSS, mss);
320 var->RMSS = min(var->RMSS, mss);
321
322 congestion_set_IW(s);
323
324 var->LW = var->SMSS;
325
326 set_cwnd(s, var->IW);
327 var->rwnd = var->IW;
328}
329
330static bool isDupAck(PNETSIM_SOCKET s, PCONGESTIONVAR var)
331{
332 var;
333 return (s->tcb->SEG.ACK <= s->tcb->SND.UNA);
334}
335
336static bool isFullAck(PNETSIM_SOCKET s, PCONGESTIONVAR var)
337{
338 var;
339 return s->tcb->SEG.ACK >= var->recover;
340}
341
342static void slowStart(PNETSIM_SOCKET s, PCONGESTIONVAR var)
343{
344 //Slow start mode
345 UINT16 N; /* N is the number of previously unacknowledged
346 * bytes acknowledged in the incoming ACK.
347 */
348 N = (UINT16)(s->tcb->SEG.ACK - s->tcb->SND.UNA);
349 increase_cwnd(s, min(N, var->SMSS));
350}
351
352static void CongestionAvoidance(PNETSIM_SOCKET s, PCONGESTIONVAR var)
353{
354 //Congestion avoidance mode
355 double RTT = get_RTT(s->tcb, s->tcb->SEG.ACK);
356 if (var->lastWinUpdateTime +
357 RTT < pstruEventDetails->dEventTime)
358 {
359 var->lastWinUpdateTime = pstruEventDetails->dEventTime;
360 UINT16 N = (UINT16)(s->tcb->SEG.ACK - s->tcb->SND.UNA);
361 increase_cwnd(s, min(N, var->SMSS));
362 }
363}
364
365static void FastRetransmit(PNETSIM_SOCKET s, PCONGESTIONVAR var)
366{
367 /* RFC 5681 page 9*/
368 if (var->dupAckCount == TCP_DupThresh)
369 {
370 /*
371 2. When the third duplicate ACK is received, a TCP MUST set ssthresh
372 to no more than the value given in equation (4)
373 ssthresh = max (FlightSize / 2, 2*SMSS) (4)
374 */
375 UINT16 FlightSize = (UINT16)(s->tcb->SND.NXT - s->tcb->SND.UNA);
376 set_ssthres(s, max(FlightSize / 2, 2 * var->SMSS));
377
378 /*
379 3. The lost segment starting at SND.UNA MUST be retransmitted and
380 cwnd set to ssthresh plus 3*SMSS. This artificially "inflates"
381 the congestion window by the number of segments (three) that have
382 left the network and which the receiver has buffered.
383 */
384 set_cwnd(s, get_ssthres(s) + TCP_DupThresh * var->SMSS);
385 resend_segment_without_timeout(s, s->tcb->SEG.ACK);
386
387 var->isFastRecovery = isFastRecovery(s);
388
389 if (s->tcb->isSackOption)
390 {
391 tcp_sack_fastRetransmit(s);
392 var->isLossRecoveryPhase = true;
393 }
394 }
395 else
396 {
397 /*
398 4. For each additional duplicate ACK received(after the third),
399 cwnd MUST be incremented by SMSS.This artificially inflates the
400 congestion window in order to reflect the additional segment that
401 has left the network.
402 */
403 increase_cwnd(s, var->SMSS);
404
405 if (s->tcb->isSackOption &&
406 var->isLossRecoveryPhase)
407 {
408 var->isLossRecoveryPhase = tcp_sack_lossRecoveryPhase(s);
409 }
410 }
411}
412
413static void FastRecovery(PNETSIM_SOCKET s, PCONGESTIONVAR var)
414{
415 var->isFastRecovery = false;
416 var->dupAckCount = 0;
417 set_cwnd(s, get_ssthres(s));
418}
419
420static void newReno_FastRecovery(PNETSIM_SOCKET s, PCONGESTIONVAR var)
421{
422 var->dupAckCount = 0;
423 if (isFullAck(s, var))
424 {
425 //Full Ack
426 UINT16 FlightSize = (UINT16)(s->tcb->SND.NXT - s->tcb->SND.UNA);
427 set_cwnd(s,
428 min((UINT16)get_ssthres(s),
429 max(FlightSize, var->SMSS) + var->SMSS)); //---(1)
430
431 //var->cwnd = var->ssthresh; //----(2)
432 var->isFastRecovery = false;
433 }
434 else
435 {
436 //Partial Ack
437 increase_cwnd (s, (UINT16)(s->tcb->SEG.ACK - var->recover));
438 resend_segment_without_timeout(s, s->tcb->SEG.ACK);
439 }
440}
441
442/*
443* behave like Reno until low_window is reached,
444* then increase congestion window slowly
445*/
446static UINT32 bictcp_recalc_ssthresh(PNETSIM_SOCKET sk)
447{
448 PBIC ca = &get_congestionvar(sk)->bic;
449
450 UINT32 segCwnd = (UINT32)get_cwnd(sk)/sk->tcb->get_MSS(sk);
451
452 ca->epoch_start = 0; /* end of epoch */
453
454 /* Wmax and fast convergence */
455 if (segCwnd < ca->last_max_cwnd && ca->fast_convergence)
456 {
457 ca->last_max_cwnd = (UINT32)(segCwnd * ca->beta);
458 }
459 else
460 {
461 ca->last_max_cwnd = segCwnd;
462 }
463 ca->loss_cwnd = segCwnd;
464 UINT16 FlightSize = (UINT16)(sk->tcb->SND.NXT - sk->tcb->SND.UNA);
465
466 if (segCwnd <= ca->low_window)
467 return max(2 * sk->tcb->get_MSS(sk), FlightSize / 2);
468 else
469 return (UINT32)(max(segCwnd * ca->beta, 2.0) * sk->tcb->get_MSS(sk));
470}
471
472/*
473* Compute congestion window to use.
474*/
475static inline void bictcp_update(PNETSIM_SOCKET sk)
476{
477 PCONGESTIONVAR c = get_congestionvar(sk);
478 PBIC ca = &c->bic;
479 UINT32 cwnd = (UINT32)get_cwnd(sk)/sk->tcb->get_MSS(sk);
480
481 ca->last_cwnd = cwnd;
482 ca->last_time = (UINT32)pstruEventDetails->dEventTime;
483
484 if (ca->epoch_start == 0) /* record the beginning of an epoch */
485 ca->epoch_start = (UINT32)pstruEventDetails->dEventTime;
486
487 /* start off normal */
488 if (cwnd <= ca->low_window)
489 {
490 ca->cnt = cwnd;
491 return;
492 }
493
494 /* binary increase */
495 if (cwnd < ca->last_max_cwnd)
496 {
497 UINT32 dist = (ca->last_max_cwnd - cwnd) / BICTCP_B;
498
499 if (dist > ca->max_increment)
500 {
501 /* linear increase */
502 ca->cnt = cwnd / ca->max_increment;
503 }
504 else if (dist <= 1U)
505 {
506 /* smoothed binary search increase: when our window is really
507 * close to the last maximum, we parameterize in m_smoothPart the number
508 * of RTT needed to reach that window.
509 */
510 ca->cnt = (cwnd * ca->smooth_part) / BICTCP_B;
511 }
512 else
513 {
514 /* binary search increase */
515 ca->cnt = cwnd / dist;
516 }
517 }
518 else
519 {
520 /* slow start AMD linear increase */
521 if (cwnd < ca->last_max_cwnd + BICTCP_B)
522 {
523 /* slow start */
524 ca->cnt = (cwnd * ca->smooth_part) / BICTCP_B;
525 }
526 else if (cwnd < ca->last_max_cwnd + ca->max_increment*(BICTCP_B - 1))
527 {
528 /* slow start */
529 ca->cnt = (cwnd * (BICTCP_B - 1))
530 / (cwnd - ca->last_max_cwnd);
531 }
532 else
533 {
534 /* linear increase */
535 ca->cnt = cwnd / ca->max_increment;
536 }
537 }
538 /* if in slow start or link utilization is very low */
539 if (ca->last_max_cwnd == 0)
540 {
541 if (ca->cnt > 20) /* increase cwnd 5% per RTT */
542 ca->cnt = 20;
543 }
544
545 ca->cnt = (ca->cnt << ACK_RATIO_SHIFT) / ca->delayed_ack;
546 if (ca->cnt == 0) /* cannot be zero */
547 ca->cnt = 1;
548
549}
550
551static void bictcp_cong_avoid(PNETSIM_SOCKET sk, UINT32 segmentAcked)
552{
553 PCONGESTIONVAR var = get_congestionvar(sk);
554
555 if (tcp_in_slow_start(sk))
556 {
557 slowStart(sk, get_congestionvar(sk));
558 segmentAcked--;
559 }
560
561 if(!tcp_in_slow_start(sk) && segmentAcked > 0)
562 {
563 PBIC bic = &var->bic;
564
565 bic->cwndcnt += segmentAcked;
566 bictcp_update(sk);
567 UINT32 cnt = bic->cnt;
568 /* According to the BIC paper and RFC 6356 even once the new cwnd is
569 * calculated you must compare this to the number of ACKs received since
570 * the last cwnd update. If not enough ACKs have been received then cwnd
571 * cannot be updated.
572 */
573 if (bic->cwndcnt > cnt)
574 {
575 increase_cwnd(sk, var->SMSS);
576 bic->cwndcnt = 0;
577 }
578 else
579 {
580 //Not enough segments have been ACKed to increment cwnd
581 }
582 }
583}
584
585static void bictcp_fastretransmit(PNETSIM_SOCKET s)
586{
587 PCONGESTIONVAR var = get_congestionvar(s);
588
589 if (var->dupAckCount == TCP_DupThresh)
590 {
591 UINT32 ssThresh = bictcp_recalc_ssthresh(s);
592 set_ssthres(s, (UINT16)ssThresh);
593
594 /*
595 3. The lost segment starting at SND.UNA MUST be retransmitted and
596 cwnd set to ssthresh plus 3*SMSS. This artificially "inflates"
597 the congestion window by the number of segments (three) that have
598 left the network and which the receiver has buffered.
599 */
600 set_cwnd(s, get_ssthres(s) + TCP_DupThresh * var->SMSS);
601 resend_segment_without_timeout(s, s->tcb->SEG.ACK);
602
603 var->isFastRecovery = isFastRecovery(s);
604
605 if (s->tcb->isSackOption)
606 {
607 tcp_sack_fastRetransmit(s);
608 var->isLossRecoveryPhase = true;
609 }
610 }
611 else
612 {
613 /*
614 4. For each additional duplicate ACK received(after the third),
615 cwnd MUST be incremented by SMSS.This artificially inflates the
616 congestion window in order to reflect the additional segment that
617 has left the network.
618 */
619 increase_cwnd(s, var->SMSS);
620
621 if (s->tcb->isSackOption &&
622 var->isLossRecoveryPhase)
623 {
624 var->isLossRecoveryPhase = tcp_sack_lossRecoveryPhase(s);
625 }
626 }
627}
628
629/* Track delayed acknowledgment ratio using sliding window
630* ratio = (15*ratio + sample) / 16
631*/
632static void bictcp_acked(PNETSIM_SOCKET sk)
633{
634 BIC ca = get_congestionvar(sk)->bic;
635
636 UINT32 pkts_acked = (sk->tcb->SEG.ACK - sk->tcb->SND.UNA) /
637 sk->tcb->get_MSS(sk);
638
639 ca.delayed_ack += pkts_acked -
640 (ca.delayed_ack >> ACK_RATIO_SHIFT);
641}
642
643static void oldtahoe_ack_received(PNETSIM_SOCKET s)
644{
645 PCONGESTIONVAR var = get_congestionvar(s);
646
647 if (get_cwnd(s) <= get_ssthres(s))
648 slowStart(s, var);
649 else
650 CongestionAvoidance(s, var);
651
652#ifdef _TEST_CONGESTION_
653 fprintf(fp, "Ack,%lf,%d,%d,%d,%d,%d\n",
654 pstruEventDetails->dEventTime,
655 get_cwnd_print(s),
656 get_ssthres(s),
657 s->tcb->SND.NXT - s->tcb->SND.UNA,
658 s->tcb->SEG.ACK,s->tcb->SND.UNA);
659 fflush(fp);
660#endif
661}
662
663static void tahoe_ack_received(PNETSIM_SOCKET s)
664{
665 PCONGESTIONVAR var = get_congestionvar(s);
666 bool isdup = isDupAck(s, var);
667 if (isdup)
668 {
669 var->dupAckCount++;
670 if (var->dupAckCount < TCP_DupThresh)
671 {
672 if (s->tcb->isSackOption &&
673 tcp_sack_isLost(s, get_highAck(s) + 1))
674 FastRetransmit(s, var);
675 }
676 else
677 {
678 FastRetransmit(s, var);
679 }
680 }
681 else if (var->dupAckCount)
682 {
683 var->dupAckCount = 0;
684 set_cwnd(s, var->LW);
685 }
686 else
687 {
688 if (get_cwnd(s) <= get_ssthres(s))
689 slowStart(s, var);
690 else
691 CongestionAvoidance(s, var);
692 }
693
694#ifdef _TEST_CONGESTION_
695 fprintf(fp, "Ack,%lf,%d,%d,%d,%d,%d\n",
696 pstruEventDetails->dEventTime,
697 get_cwnd_print(s),
698 get_ssthres(s),
699 s->tcb->SND.NXT - s->tcb->SND.UNA,
700 s->tcb->SEG.ACK,s->tcb->SND.UNA);
701 fflush(fp);
702#endif
703}
704
705static void reno_ack_received(PNETSIM_SOCKET s)
706{
707 PCONGESTIONVAR var = get_congestionvar(s);
708 bool isdup = isDupAck(s, var);
709 if (isdup)
710 {
711 var->dupAckCount++;
712 if (var->dupAckCount < TCP_DupThresh)
713 {
714 if (s->tcb->isSackOption &&
715 tcp_sack_isLost(s, get_highAck(s) + 1))
716 FastRetransmit(s, var);
717 }
718 else
719 {
720 FastRetransmit(s, var);
721 }
722 }
723 else if (var->isFastRecovery)
724 {
725 FastRecovery(s, var);
726 }
727 else
728 {
729 if (get_cwnd(s) <= get_ssthres(s))
730 slowStart(s, var);
731 else
732 CongestionAvoidance(s, var);
733 }
734
735#ifdef _TEST_CONGESTION_
736 fprintf(fp, "Ack,%lf,%d,%d,%d,%d,%d\n",
737 pstruEventDetails->dEventTime,
738 get_cwnd_print(s),
739 get_ssthres(s),
740 s->tcb->SND.NXT - s->tcb->SND.UNA,
741 s->tcb->SEG.ACK, s->tcb->SND.UNA);
742 fflush(fp);
743#endif
744}
745
746static void newreno_ack_received(PNETSIM_SOCKET s)
747{
748 PCONGESTIONVAR var = get_congestionvar(s);
749 bool isdup = isDupAck(s, var);
750 if (isdup)
751 {
752 var->dupAckCount++;
753 if (var->dupAckCount < TCP_DupThresh)
754 {
755 if (s->tcb->isSackOption &&
756 tcp_sack_isLost(s, get_highAck(s) + 1))
757 FastRetransmit(s, var);
758 }
759 else
760 {
761 if (var->recover < s->tcb->SEG.ACK - 1)
762 {
763 var->recover = s->tcb->SND.NXT;
764
765 FastRetransmit(s, var);
766 }
767 }
768 }
769 else if (var->isFastRecovery)
770 {
771 newReno_FastRecovery(s, var);
772 }
773 else
774 {
775 if (get_cwnd(s) <= get_ssthres(s))
776 slowStart(s, var);
777 else
778 CongestionAvoidance(s, var);
779 }
780
781#ifdef _TEST_CONGESTION_
782 fprintf(fp, "Ack,%lf,%d,%d,%d,%d,%d\n",
783 pstruEventDetails->dEventTime,
784 get_cwnd_print(s),
785 get_ssthres(s),
786 s->tcb->SND.NXT - s->tcb->SND.UNA,
787 s->tcb->SEG.ACK, s->tcb->SND.UNA);
788 fflush(fp);
789#endif
790}
791
792static void bic_ack_received(PNETSIM_SOCKET s)
793{
794 PCONGESTIONVAR var = get_congestionvar(s);
795 UINT32 segmentAcked = (s->tcb->SEG.ACK - s->tcb->SND.UNA)/
796 s->tcb->get_MSS(s);
797
798 bool isdup = isDupAck(s, var);
799 if (isdup)
800 {
801 var->dupAckCount++;
802 if (var->dupAckCount < TCP_DupThresh)
803 {
804 if (s->tcb->isSackOption &&
805 tcp_sack_isLost(s, get_highAck(s) + 1))
806 {
807 bictcp_fastretransmit(s);
808 }
809 }
810 else
811 {
812 bictcp_fastretransmit(s);
813 }
814 }
815 else if (var->isFastRecovery)
816 {
817 FastRecovery(s, var);
818 }
819 else
820 {
821 bictcp_acked(s);
822 bictcp_cong_avoid(s,segmentAcked);
823 }
824
825#ifdef _TEST_CONGESTION_
826 fprintf(fp, "Ack,%lf,%d,%d,%d,%d,%d\n",
827 pstruEventDetails->dEventTime,
828 get_cwnd_print(s),
829 get_ssthres(s),
830 s->tcb->SND.NXT - s->tcb->SND.UNA,
831 s->tcb->SEG.ACK, s->tcb->SND.UNA);
832 fflush(fp);
833#endif
834}
835
836static void congestion_rto_timeout(PNETSIM_SOCKET s)
837{
838 PCONGESTIONVAR var = get_congestionvar(s);
839 UINT16 FlightSize = (UINT16)(s->tcb->SND.NXT - s->tcb->SND.UNA);
840 set_ssthres(s, max(FlightSize / 2, 2 * var->SMSS));
841 set_cwnd(s, var->LW);
842
843 if (isNewReno(s))
844 {
845 var->recover = s->tcb->SND.NXT;
846 var->isFastRecovery = false;
847 }
848
849#ifdef _TEST_CONGESTION_
850 fprintf(fp, "RTO,%lf,%d,%d,%d,%d,%d\n",
851 pstruEventDetails->dEventTime,
852 get_cwnd_print(s),
853 get_ssthres(s),
854 s->tcb->SND.NXT - s->tcb->SND.UNA,
855 s->tcb->SEG.ACK, s->tcb->SND.UNA);
856 fflush(fp);
857#endif
858}
859
860UINT congestion_getDupAckCount(PNETSIM_SOCKET s)
861{
862 PCONGESTIONVAR var = get_congestionvar(s);
863 return var->dupAckCount;
864}
865
866void congestion_setcallback(PNETSIM_SOCKET s)
867{
868 s->tcb->init_congestionalgo = init_congestion;
869
870 switch (s->tcb->variant)
871 {
872 case TCPVariant_OLDTAHOE:
873 s->tcb->ack_received = oldtahoe_ack_received;
874 s->tcb->get_dup_ack_count = congestion_getDupAckCount;
875 break;
876 case TCPVariant_TAHOE:
877 s->tcb->ack_received = tahoe_ack_received;
878 s->tcb->get_dup_ack_count = congestion_getDupAckCount;
879 break;
880 case TCPVariant_RENO:
881 s->tcb->ack_received = reno_ack_received;
882 s->tcb->get_dup_ack_count = congestion_getDupAckCount;
883 break;
884 case TCPVariant_NEWRENO:
885 s->tcb->ack_received = newreno_ack_received;
886 s->tcb->get_dup_ack_count = congestion_getDupAckCount;
887 break;
888 case TCPVariant_BIC:
889 s->tcb->ack_received = bic_ack_received;
890 s->tcb->get_dup_ack_count = congestion_getDupAckCount;
891 break;
892 case TCPVariant_CUBIC:
893 s->tcb->init_congestionalgo = init_cubic;
894 s->tcb->ack_received = cubic_ack_received;
895 s->tcb->get_dup_ack_count = congestion_getDupAckCount;
896 //Other function will work as both structure are same initially. :):)
897 //But is it correct to do? Nope.
898 break;
899 default:
900 fnNetSimError("Unknown TCP variant %d in %s\n",
901 s->tcb->variant,
902 __FUNCTION__);
903 break;
904 }
905
906 s->tcb->rto_expired = congestion_rto_timeout;
907 s->tcb->get_MSS = congestion_get_MSS;
908 s->tcb->get_WND = congestion_get_WND;
909 s->tcb->set_MSS = congestion_set_MSS;
910 s->tcb->get_RCVWND = congestion_get_RCV_WND;
911
912 s->tcb->init_congestionalgo(s);
913}
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