19#ifdef _TEST_CONGESTION_
22void cubic_ack_received(PNETSIM_SOCKET s);
23void init_cubic(PNETSIM_SOCKET s);
25#define BICTCP_BETA_SCALE 1024
38 bool fast_convergence;
48#define ACK_RATIO_SHIFT 4
63 double lastWinUpdateTime;
66 bool isFastRetransmit;
76 bool isLossRecoveryPhase;
80}CONGESTIONVAR,*PCONGESTIONVAR;
82static inline bool isReno(PNETSIM_SOCKET s)
84 return s->tcb->variant == TCPVariant_RENO ||
85 s->tcb->variant == TCPVariant_NEWRENO;
88static inline bool isBIC(PNETSIM_SOCKET s)
90 return s->tcb->variant == TCPVariant_BIC;
93static inline bool isNewReno(PNETSIM_SOCKET s)
95 return s->tcb->variant == TCPVariant_NEWRENO;
98static inline bool isFastRetransmit(PNETSIM_SOCKET s)
100 return s->tcb->variant == TCPVariant_TAHOE ||
101 s->tcb->variant == TCPVariant_RENO ||
102 s->tcb->variant == TCPVariant_NEWRENO;
105static inline bool isFastRecovery(PNETSIM_SOCKET s)
107 return s->tcb->variant == TCPVariant_RENO ||
108 s->tcb->variant == TCPVariant_NEWRENO ||
109 s->tcb->variant == TCPVariant_BIC;
112static inline PCONGESTIONVAR get_congestionvar(PNETSIM_SOCKET s)
114 return (PCONGESTIONVAR)s->tcb->congestionData;
117static inline void set_congestionvar(PNETSIM_SOCKET s, PCONGESTIONVAR data)
119 s->tcb->congestionData = data;
122static inline UINT16 congestion_get_MSS(PNETSIM_SOCKET s)
124 return get_congestionvar(s)->SMSS;
127static inline UINT16 congestion_get_WND(PNETSIM_SOCKET s)
129 return get_congestionvar(s)->cwnd;
132static inline UINT32 congestion_get_RCV_WND(PNETSIM_SOCKET s)
134 PCONGESTIONVAR var = get_congestionvar(s);
135 if (s->tcb->isWindowScaling)
137 UINT32 c = var->
rwnd;
138 return c << s->tcb->Rcv.Wind_Shift;
146static void set_ssthres(PNETSIM_SOCKET s, UINT32 newssthres)
148 PCONGESTIONVAR var = get_congestionvar(s);
149 if (s->tcb->isWindowScaling)
151 UINT32 c = (UINT32)newssthres;
152 var->
ssthresh = (UINT16)(c >> s->tcb->Snd.Wind_Shift);
160static UINT32 get_ssthres(PNETSIM_SOCKET s)
162 PCONGESTIONVAR var = get_congestionvar(s);
164 if (s->tcb->isWindowScaling)
166 return c << s->tcb->Snd.Wind_Shift;
174static void set_cwnd(PNETSIM_SOCKET s, UINT32 newcwnd)
176 PCONGESTIONVAR var = get_congestionvar(s);
177 if (s->tcb->isWindowScaling)
179 UINT32 c = (UINT32)newcwnd;
180 var->
cwnd = (UINT16)(c >> s->tcb->Snd.Wind_Shift);
181 assert(var->
cwnd < 65535);
187 var->
cwnd = (UINT16)newcwnd;
191static UINT32 get_cwnd(PNETSIM_SOCKET s)
193 PCONGESTIONVAR var = get_congestionvar(s);
194 UINT32 c = (UINT32)var->
cwnd;
195 if (s->tcb->isWindowScaling)
197 return c << s->tcb->Snd.Wind_Shift;
205UINT32 get_cwnd_print(PNETSIM_SOCKET s)
207 PCONGESTIONVAR var = get_congestionvar(s);
208 if (s->tcb->isWindowScaling)
210 UINT32 c = (UINT32)var->
cwnd;
211 return (UINT32)(c << s->tcb->Snd.Wind_Shift);
215 return (UINT32)var->
cwnd;
219static inline bool tcp_in_slow_start(PNETSIM_SOCKET s)
221 return (get_cwnd(s) <= get_ssthres(s));
224static inline void bictcp_reset(PBIC ca)
227 ca->last_max_cwnd = 0;
231 ca->delayed_ack = 2 << ACK_RATIO_SHIFT;
234static void bictcp_init(PNETSIM_SOCKET sk, PTCP_DEV_VAR tcp)
236 PBIC bic = &get_congestionvar(sk)->bic;
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;
248static void init_congestion(PNETSIM_SOCKET s)
250 PTCP_DEV_VAR tcp = GET_TCP_DEV_VAR(s->localDeviceId);
251 PCONGESTIONVAR var = get_congestionvar(s);
254 var = (PCONGESTIONVAR)calloc(1,
sizeof* var);
255 set_congestionvar(s, var);
257 var->
SMSS = tcp->MSS;
258 var->
RMSS = tcp->MSS;
259 set_ssthres(s, tcp->initSSThresh);
263 var->isFastRetransmit = isFastRetransmit(s);
266 var->recover = s->tcb->ISS;
271#ifdef _TEST_CONGESTION_
272 fp = fopen(
"Congestion.csv",
"w");
273 fprintf(fp,
"Called For,Time,CWND,ssThres,Flight Size,Ackno,UNA,\n");
278static void increase_cwnd(PNETSIM_SOCKET s, UINT16 increase)
280 PCONGESTIONVAR var = get_congestionvar(s);
281 if (s->tcb->isWindowScaling)
283 UINT32 c = window_scale_get_cwnd(s);
285 UINT32 cwnd = c >> s->tcb->Snd.Wind_Shift;
289 var->
cwnd = (UINT16)cwnd;
290 assert(var->
cwnd <= 65535);
294 UINT32 c = var->
cwnd + increase;
303static void congestion_set_IW(PNETSIM_SOCKET s)
305 PCONGESTIONVAR var = get_congestionvar(s);
306 PTCP_DEV_VAR t = GET_TCP_DEV_VAR(s->localDeviceId);
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);
316static void congestion_set_MSS(PNETSIM_SOCKET s, UINT16 mss)
318 PCONGESTIONVAR var = get_congestionvar(s);
322 congestion_set_IW(s);
326 set_cwnd(s, var->
IW);
330static bool isDupAck(PNETSIM_SOCKET s, PCONGESTIONVAR var)
333 return (s->tcb->SEG.ACK <= s->tcb->SND.UNA);
336static bool isFullAck(PNETSIM_SOCKET s, PCONGESTIONVAR var)
339 return s->tcb->SEG.ACK >= var->recover;
342static void slowStart(PNETSIM_SOCKET s, PCONGESTIONVAR var)
348 N = (UINT16)(s->tcb->SEG.ACK - s->tcb->SND.UNA);
349 increase_cwnd(s, min(N, var->
SMSS));
352static void CongestionAvoidance(PNETSIM_SOCKET s, PCONGESTIONVAR var)
355 double RTT = get_RTT(s->tcb, s->tcb->SEG.ACK);
356 if (var->lastWinUpdateTime +
357 RTT < pstruEventDetails->dEventTime)
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));
365static void FastRetransmit(PNETSIM_SOCKET s, PCONGESTIONVAR var)
368 if (var->dupAckCount == TCP_DupThresh)
375 UINT16 FlightSize = (UINT16)(s->tcb->SND.NXT - s->tcb->SND.UNA);
376 set_ssthres(s, max(FlightSize / 2, 2 * var->
SMSS));
384 set_cwnd(s, get_ssthres(s) + TCP_DupThresh * var->
SMSS);
385 resend_segment_without_timeout(s, s->tcb->SEG.ACK);
387 var->isFastRecovery = isFastRecovery(s);
389 if (s->tcb->isSackOption)
391 tcp_sack_fastRetransmit(s);
392 var->isLossRecoveryPhase =
true;
403 increase_cwnd(s, var->
SMSS);
405 if (s->tcb->isSackOption &&
406 var->isLossRecoveryPhase)
408 var->isLossRecoveryPhase = tcp_sack_lossRecoveryPhase(s);
413static void FastRecovery(PNETSIM_SOCKET s, PCONGESTIONVAR var)
415 var->isFastRecovery =
false;
416 var->dupAckCount = 0;
417 set_cwnd(s, get_ssthres(s));
420static void newReno_FastRecovery(PNETSIM_SOCKET s, PCONGESTIONVAR var)
422 var->dupAckCount = 0;
423 if (isFullAck(s, var))
426 UINT16 FlightSize = (UINT16)(s->tcb->SND.NXT - s->tcb->SND.UNA);
428 min((UINT16)get_ssthres(s),
429 max(FlightSize, var->
SMSS) + var->
SMSS));
432 var->isFastRecovery =
false;
437 increase_cwnd (s, (UINT16)(s->tcb->SEG.ACK - var->recover));
438 resend_segment_without_timeout(s, s->tcb->SEG.ACK);
446static UINT32 bictcp_recalc_ssthresh(PNETSIM_SOCKET sk)
448 PBIC ca = &get_congestionvar(sk)->bic;
450 UINT32 segCwnd = (UINT32)get_cwnd(sk)/sk->tcb->get_MSS(sk);
455 if (segCwnd < ca->last_max_cwnd && ca->fast_convergence)
457 ca->last_max_cwnd = (UINT32)(segCwnd * ca->beta);
461 ca->last_max_cwnd = segCwnd;
463 ca->loss_cwnd = segCwnd;
464 UINT16 FlightSize = (UINT16)(sk->tcb->SND.NXT - sk->tcb->SND.UNA);
466 if (segCwnd <= ca->low_window)
467 return max(2 * sk->tcb->get_MSS(sk), FlightSize / 2);
469 return (UINT32)(max(segCwnd * ca->beta, 2.0) * sk->tcb->get_MSS(sk));
475static inline void bictcp_update(PNETSIM_SOCKET sk)
477 PCONGESTIONVAR c = get_congestionvar(sk);
479 UINT32 cwnd = (UINT32)get_cwnd(sk)/sk->tcb->get_MSS(sk);
481 ca->last_cwnd = cwnd;
482 ca->last_time = (UINT32)pstruEventDetails->dEventTime;
484 if (ca->epoch_start == 0)
485 ca->epoch_start = (UINT32)pstruEventDetails->dEventTime;
488 if (cwnd <= ca->low_window)
495 if (cwnd < ca->last_max_cwnd)
497 UINT32 dist = (ca->last_max_cwnd - cwnd) / BICTCP_B;
499 if (dist > ca->max_increment)
502 ca->cnt = cwnd / ca->max_increment;
510 ca->cnt = (cwnd * ca->smooth_part) / BICTCP_B;
515 ca->cnt = cwnd / dist;
521 if (cwnd < ca->last_max_cwnd + BICTCP_B)
524 ca->cnt = (cwnd * ca->smooth_part) / BICTCP_B;
526 else if (cwnd < ca->last_max_cwnd + ca->max_increment*(BICTCP_B - 1))
529 ca->cnt = (cwnd * (BICTCP_B - 1))
530 / (cwnd - ca->last_max_cwnd);
535 ca->cnt = cwnd / ca->max_increment;
539 if (ca->last_max_cwnd == 0)
545 ca->cnt = (ca->cnt << ACK_RATIO_SHIFT) / ca->delayed_ack;
551static void bictcp_cong_avoid(PNETSIM_SOCKET sk, UINT32 segmentAcked)
553 PCONGESTIONVAR var = get_congestionvar(sk);
555 if (tcp_in_slow_start(sk))
557 slowStart(sk, get_congestionvar(sk));
561 if(!tcp_in_slow_start(sk) && segmentAcked > 0)
563 PBIC bic = &var->bic;
565 bic->cwndcnt += segmentAcked;
567 UINT32 cnt = bic->cnt;
573 if (bic->cwndcnt > cnt)
575 increase_cwnd(sk, var->
SMSS);
585static void bictcp_fastretransmit(PNETSIM_SOCKET s)
587 PCONGESTIONVAR var = get_congestionvar(s);
589 if (var->dupAckCount == TCP_DupThresh)
591 UINT32 ssThresh = bictcp_recalc_ssthresh(s);
592 set_ssthres(s, (UINT16)ssThresh);
600 set_cwnd(s, get_ssthres(s) + TCP_DupThresh * var->
SMSS);
601 resend_segment_without_timeout(s, s->tcb->SEG.ACK);
603 var->isFastRecovery = isFastRecovery(s);
605 if (s->tcb->isSackOption)
607 tcp_sack_fastRetransmit(s);
608 var->isLossRecoveryPhase =
true;
619 increase_cwnd(s, var->
SMSS);
621 if (s->tcb->isSackOption &&
622 var->isLossRecoveryPhase)
624 var->isLossRecoveryPhase = tcp_sack_lossRecoveryPhase(s);
632static void bictcp_acked(PNETSIM_SOCKET sk)
634 BIC ca = get_congestionvar(sk)->bic;
636 UINT32 pkts_acked = (sk->tcb->SEG.ACK - sk->tcb->SND.UNA) /
637 sk->tcb->get_MSS(sk);
639 ca.delayed_ack += pkts_acked -
640 (ca.delayed_ack >> ACK_RATIO_SHIFT);
643static void oldtahoe_ack_received(PNETSIM_SOCKET s)
645 PCONGESTIONVAR var = get_congestionvar(s);
647 if (get_cwnd(s) <= get_ssthres(s))
650 CongestionAvoidance(s, var);
652#ifdef _TEST_CONGESTION_
653 fprintf(fp,
"Ack,%lf,%d,%d,%d,%d,%d\n",
654 pstruEventDetails->dEventTime,
657 s->tcb->SND.NXT - s->tcb->SND.UNA,
658 s->tcb->SEG.ACK,s->tcb->SND.UNA);
663static void tahoe_ack_received(PNETSIM_SOCKET s)
665 PCONGESTIONVAR var = get_congestionvar(s);
666 bool isdup = isDupAck(s, var);
670 if (var->dupAckCount < TCP_DupThresh)
672 if (s->tcb->isSackOption &&
673 tcp_sack_isLost(s, get_highAck(s) + 1))
674 FastRetransmit(s, var);
678 FastRetransmit(s, var);
681 else if (var->dupAckCount)
683 var->dupAckCount = 0;
684 set_cwnd(s, var->LW);
688 if (get_cwnd(s) <= get_ssthres(s))
691 CongestionAvoidance(s, var);
694#ifdef _TEST_CONGESTION_
695 fprintf(fp,
"Ack,%lf,%d,%d,%d,%d,%d\n",
696 pstruEventDetails->dEventTime,
699 s->tcb->SND.NXT - s->tcb->SND.UNA,
700 s->tcb->SEG.ACK,s->tcb->SND.UNA);
705static void reno_ack_received(PNETSIM_SOCKET s)
707 PCONGESTIONVAR var = get_congestionvar(s);
708 bool isdup = isDupAck(s, var);
712 if (var->dupAckCount < TCP_DupThresh)
714 if (s->tcb->isSackOption &&
715 tcp_sack_isLost(s, get_highAck(s) + 1))
716 FastRetransmit(s, var);
720 FastRetransmit(s, var);
723 else if (var->isFastRecovery)
725 FastRecovery(s, var);
729 if (get_cwnd(s) <= get_ssthres(s))
732 CongestionAvoidance(s, var);
735#ifdef _TEST_CONGESTION_
736 fprintf(fp,
"Ack,%lf,%d,%d,%d,%d,%d\n",
737 pstruEventDetails->dEventTime,
740 s->tcb->SND.NXT - s->tcb->SND.UNA,
741 s->tcb->SEG.ACK, s->tcb->SND.UNA);
746static void newreno_ack_received(PNETSIM_SOCKET s)
748 PCONGESTIONVAR var = get_congestionvar(s);
749 bool isdup = isDupAck(s, var);
753 if (var->dupAckCount < TCP_DupThresh)
755 if (s->tcb->isSackOption &&
756 tcp_sack_isLost(s, get_highAck(s) + 1))
757 FastRetransmit(s, var);
761 if (var->recover < s->tcb->SEG.ACK - 1)
763 var->recover = s->tcb->SND.NXT;
765 FastRetransmit(s, var);
769 else if (var->isFastRecovery)
771 newReno_FastRecovery(s, var);
775 if (get_cwnd(s) <= get_ssthres(s))
778 CongestionAvoidance(s, var);
781#ifdef _TEST_CONGESTION_
782 fprintf(fp,
"Ack,%lf,%d,%d,%d,%d,%d\n",
783 pstruEventDetails->dEventTime,
786 s->tcb->SND.NXT - s->tcb->SND.UNA,
787 s->tcb->SEG.ACK, s->tcb->SND.UNA);
792static void bic_ack_received(PNETSIM_SOCKET s)
794 PCONGESTIONVAR var = get_congestionvar(s);
795 UINT32 segmentAcked = (s->tcb->SEG.ACK - s->tcb->SND.UNA)/
798 bool isdup = isDupAck(s, var);
802 if (var->dupAckCount < TCP_DupThresh)
804 if (s->tcb->isSackOption &&
805 tcp_sack_isLost(s, get_highAck(s) + 1))
807 bictcp_fastretransmit(s);
812 bictcp_fastretransmit(s);
815 else if (var->isFastRecovery)
817 FastRecovery(s, var);
822 bictcp_cong_avoid(s,segmentAcked);
825#ifdef _TEST_CONGESTION_
826 fprintf(fp,
"Ack,%lf,%d,%d,%d,%d,%d\n",
827 pstruEventDetails->dEventTime,
830 s->tcb->SND.NXT - s->tcb->SND.UNA,
831 s->tcb->SEG.ACK, s->tcb->SND.UNA);
836static void congestion_rto_timeout(PNETSIM_SOCKET s)
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);
845 var->recover = s->tcb->SND.NXT;
846 var->isFastRecovery =
false;
849#ifdef _TEST_CONGESTION_
850 fprintf(fp,
"RTO,%lf,%d,%d,%d,%d,%d\n",
851 pstruEventDetails->dEventTime,
854 s->tcb->SND.NXT - s->tcb->SND.UNA,
855 s->tcb->SEG.ACK, s->tcb->SND.UNA);
860UINT congestion_getDupAckCount(PNETSIM_SOCKET s)
862 PCONGESTIONVAR var = get_congestionvar(s);
863 return var->dupAckCount;
866void congestion_setcallback(PNETSIM_SOCKET s)
868 s->tcb->init_congestionalgo = init_congestion;
870 switch (s->tcb->variant)
872 case TCPVariant_OLDTAHOE:
873 s->tcb->ack_received = oldtahoe_ack_received;
874 s->tcb->get_dup_ack_count = congestion_getDupAckCount;
876 case TCPVariant_TAHOE:
877 s->tcb->ack_received = tahoe_ack_received;
878 s->tcb->get_dup_ack_count = congestion_getDupAckCount;
880 case TCPVariant_RENO:
881 s->tcb->ack_received = reno_ack_received;
882 s->tcb->get_dup_ack_count = congestion_getDupAckCount;
884 case TCPVariant_NEWRENO:
885 s->tcb->ack_received = newreno_ack_received;
886 s->tcb->get_dup_ack_count = congestion_getDupAckCount;
889 s->tcb->ack_received = bic_ack_received;
890 s->tcb->get_dup_ack_count = congestion_getDupAckCount;
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;
900 fnNetSimError(
"Unknown TCP variant %d in %s\n",
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;
912 s->tcb->init_congestionalgo(s);
UINT16 IW
Size of the sender's congestion window after the three-way handshake is completed.
UINT16 RMSS
To store the size of the largest segment that the receiver is willing to accept.
UINT16 ssthresh
To store slow start threshold value.
UINT16 rwnd
To store the most recently advertised receiver window size value.
UINT16 SMSS
To store the size of the largest segment that the sender can transmit.
UINT16 cwnd
To store Congestion window size value.