1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2018 NITK Surathkal
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * Authors: Vivek Jain <jain.vivek.anand@gmail.com>
19  *          Viyom Mittal <viyommittal@gmail.com>
20  *          Mohit P. Tahiliani <tahiliani@nitk.edu.in>
21  */
22 
23 #include "tcp-bbr.h"
24 
25 #include "ns3/log.h"
26 #include "ns3/simulator.h"
27 
28 namespace ns3 {
29 
30 NS_LOG_COMPONENT_DEFINE ("TcpBbr");
31 NS_OBJECT_ENSURE_REGISTERED (TcpBbr);
32 
33 const double TcpBbr::PACING_GAIN_CYCLE [] = {5.0 / 4, 3.0 / 4, 1, 1, 1, 1, 1, 1};
34 
35 TypeId
GetTypeId(void)36 TcpBbr::GetTypeId (void)
37 {
38   static TypeId tid = TypeId ("ns3::TcpBbr")
39     .SetParent<TcpCongestionOps> ()
40     .AddConstructor<TcpBbr> ()
41     .SetGroupName ("Internet")
42     .AddAttribute ("Stream",
43                    "Random number stream (default is set to 4 to align with Linux results)",
44                    UintegerValue (4),
45                    MakeUintegerAccessor (&TcpBbr::SetStream),
46                    MakeUintegerChecker<uint32_t> ())
47     .AddAttribute ("HighGain",
48                    "Value of high gain",
49                    DoubleValue (2.89),
50                    MakeDoubleAccessor (&TcpBbr::m_highGain),
51                    MakeDoubleChecker<double> ())
52     .AddAttribute ("BwWindowLength",
53                    "Length of bandwidth windowed filter",
54                    UintegerValue (10),
55                    MakeUintegerAccessor (&TcpBbr::m_bandwidthWindowLength),
56                    MakeUintegerChecker<uint32_t> ())
57     .AddAttribute ("RttWindowLength",
58                    "Length of RTT windowed filter",
59                    TimeValue (Seconds (10)),
60                    MakeTimeAccessor (&TcpBbr::m_rtPropFilterLen),
61                    MakeTimeChecker ())
62     .AddAttribute ("ProbeRttDuration",
63                    "Time to be spent in PROBE_RTT phase",
64                    TimeValue (MilliSeconds (200)),
65                    MakeTimeAccessor (&TcpBbr::m_probeRttDuration),
66                    MakeTimeChecker ())
67     .AddAttribute ("ExtraAckedRttWindowLength",
68                    "Window length of extra acked window",
69                    UintegerValue (5),
70                    MakeUintegerAccessor (&TcpBbr::m_extraAckedWinRttLength),
71                    MakeUintegerChecker<uint32_t> ())
72     .AddAttribute ("AckEpochAckedResetThresh",
73                    "Max allowed val for m_ackEpochAcked, after which sampling epoch is reset",
74                    UintegerValue (1 << 12),
75                    MakeUintegerAccessor (&TcpBbr::m_ackEpochAckedResetThresh),
76                    MakeUintegerChecker<uint32_t> ())
77   ;
78   return tid;
79 }
80 
TcpBbr()81 TcpBbr::TcpBbr ()
82   : TcpCongestionOps ()
83 {
84   NS_LOG_FUNCTION (this);
85   m_uv = CreateObject<UniformRandomVariable> ();
86 }
87 
TcpBbr(const TcpBbr & sock)88 TcpBbr::TcpBbr (const TcpBbr &sock)
89   : TcpCongestionOps (sock),
90     m_bandwidthWindowLength (sock.m_bandwidthWindowLength),
91     m_pacingGain (sock.m_pacingGain),
92     m_cWndGain (sock.m_cWndGain),
93     m_highGain (sock.m_highGain),
94     m_isPipeFilled (sock.m_isPipeFilled),
95     m_minPipeCwnd (sock.m_minPipeCwnd),
96     m_roundCount (sock.m_roundCount),
97     m_roundStart (sock.m_roundStart),
98     m_nextRoundDelivered (sock.m_nextRoundDelivered),
99     m_probeRttDuration (sock.m_probeRttDuration),
100     m_probeRtPropStamp (sock.m_probeRtPropStamp),
101     m_probeRttDoneStamp (sock.m_probeRttDoneStamp),
102     m_probeRttRoundDone (sock.m_probeRttRoundDone),
103     m_packetConservation (sock.m_packetConservation),
104     m_priorCwnd (sock.m_priorCwnd),
105     m_idleRestart (sock.m_idleRestart),
106     m_targetCWnd (sock.m_targetCWnd),
107     m_fullBandwidth (sock.m_fullBandwidth),
108     m_fullBandwidthCount (sock.m_fullBandwidthCount),
109     m_rtProp (Time::Max ()),
110     m_sendQuantum (sock.m_sendQuantum),
111     m_cycleStamp (sock.m_cycleStamp),
112     m_cycleIndex (sock.m_cycleIndex),
113     m_rtPropExpired (sock.m_rtPropExpired),
114     m_rtPropFilterLen (sock.m_rtPropFilterLen),
115     m_rtPropStamp (sock.m_rtPropStamp),
116     m_isInitialized (sock.m_isInitialized),
117     m_uv (sock.m_uv),
118     m_delivered (sock.m_delivered),
119     m_appLimited (sock.m_appLimited),
120     m_txItemDelivered (sock.m_txItemDelivered),
121     m_extraAckedGain (sock.m_extraAckedGain),
122     m_extraAckedWinRtt (sock.m_extraAckedWinRtt),
123     m_extraAckedWinRttLength (sock.m_extraAckedWinRttLength),
124     m_ackEpochAckedResetThresh (sock.m_ackEpochAckedResetThresh),
125     m_extraAckedIdx (sock.m_extraAckedIdx),
126     m_ackEpochTime (sock.m_ackEpochTime),
127     m_ackEpochAcked (sock.m_ackEpochAcked),
128     m_hasSeenRtt (sock.m_hasSeenRtt)
129 {
130   NS_LOG_FUNCTION (this);
131 }
132 
133 const char* const
134 TcpBbr::BbrModeName[BBR_PROBE_RTT + 1] =
135 {
136   "BBR_STARTUP", "BBR_DRAIN", "BBR_PROBE_BW", "BBR_PROBE_RTT"
137 };
138 
139 void
SetStream(uint32_t stream)140 TcpBbr::SetStream (uint32_t stream)
141 {
142   NS_LOG_FUNCTION (this << stream);
143   m_uv->SetStream (stream);
144 }
145 
146 void
InitRoundCounting()147 TcpBbr::InitRoundCounting ()
148 {
149   NS_LOG_FUNCTION (this);
150   m_nextRoundDelivered = 0;
151   m_roundStart = false;
152   m_roundCount = 0;
153 }
154 
155 void
InitFullPipe()156 TcpBbr::InitFullPipe ()
157 {
158   NS_LOG_FUNCTION (this);
159   m_isPipeFilled = false;
160   m_fullBandwidth = 0;
161   m_fullBandwidthCount = 0;
162 }
163 
164 void
InitPacingRate(Ptr<TcpSocketState> tcb)165 TcpBbr::InitPacingRate (Ptr<TcpSocketState> tcb)
166 {
167   NS_LOG_FUNCTION (this << tcb);
168 
169   if (!tcb->m_pacing)
170     {
171       NS_LOG_WARN ("BBR must use pacing");
172       tcb->m_pacing = true;
173     }
174 
175   Time rtt;
176   if (tcb->m_minRtt != Time::Max ())
177     {
178       rtt = MilliSeconds (std::max<long int> (tcb->m_minRtt.GetMilliSeconds (), 1));
179       m_hasSeenRtt = true;
180     }
181   else
182     {
183       rtt = MilliSeconds (1);
184     }
185 
186   DataRate nominalBandwidth (tcb->m_cWnd * 8 / rtt.GetSeconds ());
187   tcb->m_pacingRate = DataRate (m_pacingGain * nominalBandwidth.GetBitRate ());
188   m_maxBwFilter = MaxBandwidthFilter_t (m_bandwidthWindowLength,
189                                         DataRate (tcb->m_cWnd * 8 / rtt.GetSeconds ()),
190                                         0);
191 }
192 
193 void
EnterStartup()194 TcpBbr::EnterStartup ()
195 {
196   NS_LOG_FUNCTION (this);
197   SetBbrState (BbrMode_t::BBR_STARTUP);
198   m_pacingGain = m_highGain;
199   m_cWndGain = m_highGain;
200 }
201 
202 void
HandleRestartFromIdle(Ptr<TcpSocketState> tcb,const TcpRateOps::TcpRateSample & rs)203 TcpBbr::HandleRestartFromIdle (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
204 {
205   NS_LOG_FUNCTION (this << tcb << rs);
206   if (tcb->m_bytesInFlight.Get () == 0U && rs.m_isAppLimited)
207     {
208       m_idleRestart = true;
209       if (m_state == BbrMode_t::BBR_PROBE_BW)
210         {
211           SetPacingRate (tcb, 1);
212         }
213     }
214 }
215 
216 void
SetPacingRate(Ptr<TcpSocketState> tcb,double gain)217 TcpBbr::SetPacingRate (Ptr<TcpSocketState> tcb, double gain)
218 {
219   NS_LOG_FUNCTION (this << tcb << gain);
220   DataRate rate (gain * m_maxBwFilter.GetBest ().GetBitRate ());
221   rate = std::min (rate, tcb->m_maxPacingRate);
222 
223   if (!m_hasSeenRtt && tcb->m_minRtt != Time::Max ())
224     {
225       InitPacingRate (tcb);
226     }
227 
228   if (m_isPipeFilled || rate > tcb->m_pacingRate)
229     {
230       tcb->m_pacingRate = rate;
231     }
232 }
233 
234 uint32_t
InFlight(Ptr<TcpSocketState> tcb,double gain)235 TcpBbr::InFlight (Ptr<TcpSocketState> tcb, double gain)
236 {
237   NS_LOG_FUNCTION (this << tcb << gain);
238   if (m_rtProp == Time::Max ())
239     {
240       return tcb->m_initialCWnd * tcb->m_segmentSize;
241     }
242   double quanta = 3 * m_sendQuantum;
243   double estimatedBdp = m_maxBwFilter.GetBest () * m_rtProp / 8.0;
244 
245   if (m_state == BbrMode_t::BBR_PROBE_BW && m_cycleIndex == 0)
246     {
247       return (gain * estimatedBdp) + quanta + (2 * tcb->m_segmentSize);
248     }
249   return (gain * estimatedBdp) + quanta;
250 }
251 
252 void
AdvanceCyclePhase()253 TcpBbr::AdvanceCyclePhase ()
254 {
255   NS_LOG_FUNCTION (this);
256   m_cycleStamp = Simulator::Now ();
257   m_cycleIndex = (m_cycleIndex + 1) % GAIN_CYCLE_LENGTH;
258   m_pacingGain = PACING_GAIN_CYCLE [m_cycleIndex];
259 }
260 
261 bool
IsNextCyclePhase(Ptr<TcpSocketState> tcb,const TcpRateOps::TcpRateSample & rs)262 TcpBbr::IsNextCyclePhase (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
263 {
264   NS_LOG_FUNCTION (this << tcb << rs);
265   bool isFullLength = (Simulator::Now () - m_cycleStamp) > m_rtProp;
266   if (m_pacingGain == 1)
267     {
268       return isFullLength;
269     }
270   else if (m_pacingGain > 1)
271     {
272       return isFullLength && (rs.m_bytesLoss > 0 || rs.m_priorInFlight >= InFlight (tcb, m_pacingGain));
273     }
274   else
275     {
276       return isFullLength || rs.m_priorInFlight <= InFlight (tcb, 1);
277     }
278 }
279 
280 void
CheckCyclePhase(Ptr<TcpSocketState> tcb,const TcpRateOps::TcpRateSample & rs)281 TcpBbr::CheckCyclePhase (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
282 {
283   NS_LOG_FUNCTION (this << tcb << rs);
284   if (m_state == BbrMode_t::BBR_PROBE_BW && IsNextCyclePhase (tcb, rs))
285     {
286       AdvanceCyclePhase ();
287     }
288 }
289 
290 void
CheckFullPipe(const TcpRateOps::TcpRateSample & rs)291 TcpBbr::CheckFullPipe (const TcpRateOps::TcpRateSample &rs)
292 {
293   NS_LOG_FUNCTION (this << rs);
294   if (m_isPipeFilled || !m_roundStart || rs.m_isAppLimited)
295     {
296       return;
297     }
298 
299   /* Check if Bottleneck bandwidth is still growing*/
300   if (m_maxBwFilter.GetBest ().GetBitRate () >= m_fullBandwidth.GetBitRate () * 1.25)
301     {
302       m_fullBandwidth = m_maxBwFilter.GetBest ();
303       m_fullBandwidthCount = 0;
304       return;
305     }
306 
307   m_fullBandwidthCount++;
308   if (m_fullBandwidthCount >= 3)
309     {
310       NS_LOG_DEBUG ("Pipe filled");
311       m_isPipeFilled = true;
312     }
313 }
314 
315 void
EnterDrain()316 TcpBbr::EnterDrain ()
317 {
318   NS_LOG_FUNCTION (this);
319   SetBbrState (BbrMode_t::BBR_DRAIN);
320   m_pacingGain = 1.0 / m_highGain;
321   m_cWndGain = m_highGain;
322 }
323 
324 void
EnterProbeBW()325 TcpBbr::EnterProbeBW ()
326 {
327   NS_LOG_FUNCTION (this);
328   SetBbrState (BbrMode_t::BBR_PROBE_BW);
329   m_pacingGain = 1;
330   m_cWndGain = 2;
331   m_cycleIndex = GAIN_CYCLE_LENGTH - 1 - (int) m_uv->GetValue (0, 6);
332   AdvanceCyclePhase ();
333 }
334 
335 void
CheckDrain(Ptr<TcpSocketState> tcb)336 TcpBbr::CheckDrain (Ptr<TcpSocketState> tcb)
337 {
338   NS_LOG_FUNCTION (this << tcb);
339   if (m_state == BbrMode_t::BBR_STARTUP && m_isPipeFilled)
340     {
341       EnterDrain ();
342       tcb->m_ssThresh = InFlight (tcb, 1);
343     }
344 
345   if (m_state == BbrMode_t::BBR_DRAIN && tcb->m_bytesInFlight <= InFlight (tcb, 1))
346     {
347       EnterProbeBW ();
348     }
349 }
350 
351 void
UpdateRTprop(Ptr<TcpSocketState> tcb)352 TcpBbr::UpdateRTprop (Ptr<TcpSocketState> tcb)
353 {
354   NS_LOG_FUNCTION (this << tcb);
355   m_rtPropExpired = Simulator::Now () > (m_rtPropStamp + m_rtPropFilterLen);
356   if (tcb->m_lastRtt >= Seconds (0) && (tcb->m_lastRtt <= m_rtProp || m_rtPropExpired))
357     {
358       m_rtProp = tcb->m_lastRtt;
359       m_rtPropStamp = Simulator::Now ();
360     }
361 }
362 
363 void
EnterProbeRTT()364 TcpBbr::EnterProbeRTT ()
365 {
366   NS_LOG_FUNCTION (this);
367   SetBbrState (BbrMode_t::BBR_PROBE_RTT);
368   m_pacingGain = 1;
369   m_cWndGain = 1;
370 }
371 
372 void
SaveCwnd(Ptr<const TcpSocketState> tcb)373 TcpBbr::SaveCwnd (Ptr<const TcpSocketState> tcb)
374 {
375   NS_LOG_FUNCTION (this << tcb);
376   if (tcb->m_congState != TcpSocketState::CA_RECOVERY && m_state != BbrMode_t::BBR_PROBE_RTT)
377     {
378       m_priorCwnd = tcb->m_cWnd;
379     }
380   else
381     {
382       m_priorCwnd = std::max (m_priorCwnd, tcb->m_cWnd.Get ());
383     }
384 }
385 
386 void
RestoreCwnd(Ptr<TcpSocketState> tcb)387 TcpBbr::RestoreCwnd (Ptr<TcpSocketState> tcb)
388 {
389   NS_LOG_FUNCTION (this << tcb);
390   tcb->m_cWnd = std::max (m_priorCwnd, tcb->m_cWnd.Get ());
391 }
392 
393 void
ExitProbeRTT()394 TcpBbr::ExitProbeRTT ()
395 {
396   NS_LOG_FUNCTION (this);
397   if (m_isPipeFilled)
398     {
399       EnterProbeBW ();
400     }
401   else
402     {
403       EnterStartup ();
404     }
405 }
406 
407 void
HandleProbeRTT(Ptr<TcpSocketState> tcb)408 TcpBbr::HandleProbeRTT (Ptr<TcpSocketState> tcb)
409 {
410   NS_LOG_FUNCTION (this << tcb);
411   m_appLimited = (m_delivered + tcb->m_bytesInFlight.Get ()) ? : 1;
412 
413   if (m_probeRttDoneStamp == Seconds (0) && tcb->m_bytesInFlight <= m_minPipeCwnd)
414     {
415       m_probeRttDoneStamp = Simulator::Now () + m_probeRttDuration;
416       m_probeRttRoundDone = false;
417       m_nextRoundDelivered = m_delivered;
418     }
419   else if (m_probeRttDoneStamp != Seconds (0))
420     {
421       if (m_roundStart)
422         {
423           m_probeRttRoundDone = true;
424         }
425       if (m_probeRttRoundDone && Simulator::Now () > m_probeRttDoneStamp)
426         {
427           m_rtPropStamp = Simulator::Now ();
428           RestoreCwnd (tcb);
429           ExitProbeRTT ();
430         }
431     }
432 }
433 
434 void
CheckProbeRTT(Ptr<TcpSocketState> tcb,const TcpRateOps::TcpRateSample & rs)435 TcpBbr::CheckProbeRTT (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
436 {
437   NS_LOG_FUNCTION (this << tcb);
438   if (m_state != BbrMode_t::BBR_PROBE_RTT && m_rtPropExpired && !m_idleRestart)
439     {
440       EnterProbeRTT ();
441       SaveCwnd (tcb);
442       m_probeRttDoneStamp = Seconds (0);
443     }
444 
445   if (m_state == BbrMode_t::BBR_PROBE_RTT)
446     {
447       HandleProbeRTT (tcb);
448     }
449 
450   if (rs.m_delivered)
451     {
452       m_idleRestart = false;
453     }
454 }
455 
456 void
SetSendQuantum(Ptr<TcpSocketState> tcb)457 TcpBbr::SetSendQuantum (Ptr<TcpSocketState> tcb)
458 {
459   NS_LOG_FUNCTION (this << tcb);
460   m_sendQuantum = 1 * tcb->m_segmentSize;
461 }
462 
463 void
UpdateTargetCwnd(Ptr<TcpSocketState> tcb)464 TcpBbr::UpdateTargetCwnd (Ptr<TcpSocketState> tcb)
465 {
466   NS_LOG_FUNCTION (this << tcb);
467   m_targetCWnd = InFlight (tcb, m_cWndGain) + AckAggregationCwnd ();
468 }
469 
470 uint32_t
AckAggregationCwnd()471 TcpBbr::AckAggregationCwnd ()
472 {
473   uint32_t maxAggrBytes; // MaxBW * 0.1 secs
474   uint32_t aggrCwndBytes = 0;
475 
476   if (m_extraAckedGain && m_isPipeFilled)
477     {
478       maxAggrBytes = m_maxBwFilter.GetBest ().GetBitRate () / (10 * 8);
479       aggrCwndBytes = m_extraAckedGain * std::max (m_extraAcked[0], m_extraAcked[1]);
480       aggrCwndBytes = std::min (aggrCwndBytes, maxAggrBytes);
481     }
482   return aggrCwndBytes;
483 }
484 
485 void
UpdateAckAggregation(Ptr<TcpSocketState> tcb,const TcpRateOps::TcpRateSample & rs)486 TcpBbr::UpdateAckAggregation (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
487 {
488   uint32_t expectedAcked, extraAck;
489   uint32_t epochProp;
490 
491   if (!m_extraAckedGain || rs.m_ackedSacked <= 0 || rs.m_delivered < 0)
492     {
493       return;
494     }
495 
496   if (m_roundStart)
497     {
498       m_extraAckedWinRtt = std::min<uint32_t> (31, m_extraAckedWinRtt + 1);
499       if (m_extraAckedWinRtt >= m_extraAckedWinRttLength)
500         {
501           m_extraAckedWinRtt = 0;
502           m_extraAckedIdx = m_extraAckedIdx ? 0 : 1;
503           m_extraAcked[m_extraAckedIdx] = 0;
504         }
505     }
506 
507   epochProp = Simulator::Now ().GetSeconds () - m_ackEpochTime.GetSeconds ();
508   expectedAcked = m_maxBwFilter.GetBest ().GetBitRate () * epochProp / 8;
509 
510   if (m_ackEpochAcked <= expectedAcked ||
511       (m_ackEpochAcked + rs.m_ackedSacked >= m_ackEpochAckedResetThresh))
512     {
513       m_ackEpochAcked = 0;
514       m_ackEpochTime = Simulator::Now ();
515       expectedAcked = 0;
516     }
517 
518   m_ackEpochAcked = m_ackEpochAcked + rs.m_ackedSacked;
519   extraAck = m_ackEpochAcked - expectedAcked;
520   extraAck = std::min (extraAck, tcb->m_cWnd.Get ());
521 
522   if (extraAck > m_extraAcked[m_extraAckedIdx])
523     {
524       m_extraAcked[m_extraAckedIdx] = extraAck;
525     }
526 }
527 
528 bool
ModulateCwndForRecovery(Ptr<TcpSocketState> tcb,const TcpRateOps::TcpRateSample & rs)529 TcpBbr::ModulateCwndForRecovery (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
530 {
531   NS_LOG_FUNCTION (this << tcb << rs);
532   if (rs.m_bytesLoss > 0)
533     {
534       tcb->m_cWnd = std::max ((int) tcb->m_cWnd.Get () - (int) rs.m_bytesLoss, (int) tcb->m_segmentSize);
535     }
536 
537   if (m_packetConservation)
538     {
539       tcb->m_cWnd = std::max (tcb->m_cWnd.Get (), tcb->m_bytesInFlight.Get () + rs.m_ackedSacked);
540       return true;
541     }
542   return false;
543 }
544 
545 void
ModulateCwndForProbeRTT(Ptr<TcpSocketState> tcb)546 TcpBbr::ModulateCwndForProbeRTT (Ptr<TcpSocketState> tcb)
547 {
548   NS_LOG_FUNCTION (this << tcb);
549   if (m_state == BbrMode_t::BBR_PROBE_RTT)
550     {
551       tcb->m_cWnd = std::min (tcb->m_cWnd.Get (), m_minPipeCwnd);
552     }
553 }
554 
555 void
SetCwnd(Ptr<TcpSocketState> tcb,const TcpRateOps::TcpRateSample & rs)556 TcpBbr::SetCwnd (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
557 {
558   NS_LOG_FUNCTION (this << tcb << rs);
559 
560   if (!rs.m_ackedSacked)
561     {
562       goto done;
563     }
564 
565   if (tcb->m_congState == TcpSocketState::CA_RECOVERY)
566     {
567       if (ModulateCwndForRecovery (tcb, rs))
568         {
569           goto done;
570         }
571     }
572 
573     UpdateTargetCwnd (tcb);
574 
575   if (m_isPipeFilled)
576     {
577       tcb->m_cWnd = std::min (tcb->m_cWnd.Get () + (uint32_t) rs.m_ackedSacked, m_targetCWnd);
578     }
579   else if (tcb->m_cWnd < m_targetCWnd || m_delivered < tcb->m_initialCWnd * tcb->m_segmentSize)
580     {
581       tcb->m_cWnd = tcb->m_cWnd.Get () + rs.m_ackedSacked;
582     }
583   tcb->m_cWnd = std::max (tcb->m_cWnd.Get (), m_minPipeCwnd);
584 
585 done:
586   ModulateCwndForProbeRTT (tcb);
587 }
588 
589 void
UpdateRound(Ptr<TcpSocketState> tcb,const TcpRateOps::TcpRateSample & rs)590 TcpBbr::UpdateRound (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
591 {
592   NS_LOG_FUNCTION (this << tcb << rs);
593   if (rs.m_priorDelivered >= m_nextRoundDelivered)
594     {
595       m_nextRoundDelivered = m_delivered;
596       m_roundCount++;
597       m_roundStart = true;
598       m_packetConservation = false;
599     }
600   else
601     {
602       m_roundStart = false;
603     }
604 }
605 
606 void
UpdateBtlBw(Ptr<TcpSocketState> tcb,const TcpRateOps::TcpRateSample & rs)607 TcpBbr::UpdateBtlBw (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
608 {
609   NS_LOG_FUNCTION (this << tcb << rs);
610 
611   if (rs.m_deliveryRate == 0)
612     {
613       return;
614     }
615 
616   UpdateRound (tcb, rs);
617 
618   if (rs.m_deliveryRate >= m_maxBwFilter.GetBest () || !rs.m_isAppLimited)
619     {
620       m_maxBwFilter.Update (rs.m_deliveryRate, m_roundCount);
621     }
622 }
623 
624 void
UpdateModelAndState(Ptr<TcpSocketState> tcb,const TcpRateOps::TcpRateSample & rs)625 TcpBbr::UpdateModelAndState (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
626 {
627   NS_LOG_FUNCTION (this << tcb << rs);
628   UpdateBtlBw (tcb, rs);
629   UpdateAckAggregation (tcb, rs);
630   CheckCyclePhase (tcb, rs);
631   CheckFullPipe (rs);
632   CheckDrain (tcb);
633   UpdateRTprop (tcb);
634   CheckProbeRTT (tcb, rs);
635 }
636 
637 void
UpdateControlParameters(Ptr<TcpSocketState> tcb,const TcpRateOps::TcpRateSample & rs)638 TcpBbr::UpdateControlParameters (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
639 {
640   NS_LOG_FUNCTION (this << tcb << rs);
641   SetPacingRate (tcb, m_pacingGain);
642   SetSendQuantum (tcb);
643   SetCwnd (tcb, rs);
644 }
645 
646 void
SetBbrState(BbrMode_t mode)647 TcpBbr::SetBbrState (BbrMode_t mode)
648 {
649   NS_LOG_FUNCTION (this << mode);
650   NS_LOG_DEBUG (Simulator::Now () << " Changing from " << BbrModeName[m_state] << " to " << BbrModeName[mode]);
651   m_state = mode;
652 }
653 
654 uint32_t
GetBbrState()655 TcpBbr::GetBbrState ()
656 {
657   NS_LOG_FUNCTION (this);
658   return m_state;
659 }
660 
661 double
GetCwndGain()662 TcpBbr::GetCwndGain ()
663 {
664   NS_LOG_FUNCTION (this);
665   return m_cWndGain;
666 }
667 
668 double
GetPacingGain()669 TcpBbr::GetPacingGain ()
670 {
671   NS_LOG_FUNCTION (this);
672   return m_pacingGain;
673 }
674 
675 std::string
GetName() const676 TcpBbr::GetName () const
677 {
678   return "TcpBbr";
679 }
680 
681 bool
HasCongControl() const682 TcpBbr::HasCongControl () const
683 {
684   NS_LOG_FUNCTION (this);
685   return true;
686 }
687 
688 void
CongControl(Ptr<TcpSocketState> tcb,const TcpRateOps::TcpRateConnection & rc,const TcpRateOps::TcpRateSample & rs)689 TcpBbr::CongControl (Ptr<TcpSocketState> tcb,
690                      const TcpRateOps::TcpRateConnection &rc,
691                      const TcpRateOps::TcpRateSample &rs)
692 {
693   NS_LOG_FUNCTION (this << tcb << rs);
694   m_delivered = rc.m_delivered;
695   m_txItemDelivered = rc.m_txItemDelivered;
696   UpdateModelAndState (tcb, rs);
697   UpdateControlParameters (tcb, rs);
698 }
699 
700 void
CongestionStateSet(Ptr<TcpSocketState> tcb,const TcpSocketState::TcpCongState_t newState)701 TcpBbr::CongestionStateSet (Ptr<TcpSocketState> tcb,
702                             const TcpSocketState::TcpCongState_t newState)
703 {
704   NS_LOG_FUNCTION (this << tcb << newState);
705   if (newState == TcpSocketState::CA_OPEN && !m_isInitialized)
706     {
707       NS_LOG_DEBUG ("CongestionStateSet triggered to CA_OPEN :: " << newState);
708       m_rtProp = tcb->m_lastRtt.Get () != Time::Max () ? tcb->m_lastRtt.Get () : Time::Max ();
709       m_rtPropStamp = Simulator::Now ();
710       m_priorCwnd = tcb->m_cWnd;
711       tcb->m_ssThresh = tcb->m_initialSsThresh;
712       m_targetCWnd = tcb->m_cWnd;
713       m_minPipeCwnd = 4 * tcb->m_segmentSize;
714       m_sendQuantum = 1 * tcb->m_segmentSize;
715 
716       InitRoundCounting ();
717       InitFullPipe ();
718       EnterStartup ();
719       InitPacingRate (tcb);
720       m_ackEpochTime = Simulator::Now();
721       m_extraAckedWinRtt = 0;
722       m_extraAckedIdx = 0;
723       m_ackEpochAcked = 0;
724       m_extraAcked[0] = 0;
725       m_extraAcked[1] = 0;
726       m_isInitialized = true;
727     }
728   else if (newState == TcpSocketState::CA_LOSS)
729     {
730       NS_LOG_DEBUG ("CongestionStateSet triggered to CA_LOSS :: " << newState);
731       SaveCwnd (tcb);
732       m_roundStart = true;
733     }
734   else if (newState == TcpSocketState::CA_RECOVERY)
735     {
736       NS_LOG_DEBUG ("CongestionStateSet triggered to CA_RECOVERY :: " << newState);
737       SaveCwnd (tcb);
738       tcb->m_cWnd = tcb->m_bytesInFlight.Get () + std::max (tcb->m_lastAckedSackedBytes, tcb->m_segmentSize);
739       m_packetConservation = true;
740     }
741 }
742 
743 void
CwndEvent(Ptr<TcpSocketState> tcb,const TcpSocketState::TcpCAEvent_t event)744 TcpBbr::CwndEvent (Ptr<TcpSocketState> tcb,
745                    const TcpSocketState::TcpCAEvent_t event)
746 {
747   NS_LOG_FUNCTION (this << tcb << event);
748   if (event == TcpSocketState::CA_EVENT_COMPLETE_CWR)
749     {
750       NS_LOG_DEBUG ("CwndEvent triggered to CA_EVENT_COMPLETE_CWR :: " << event);
751       m_packetConservation = false;
752       RestoreCwnd (tcb);
753     }
754   else if (event == TcpSocketState::CA_EVENT_TX_START && m_appLimited )
755     {
756       NS_LOG_DEBUG ("CwndEvent triggered to CA_EVENT_TX_START :: " << event);
757       m_idleRestart = true;
758       m_ackEpochTime = Simulator::Now ();
759       m_ackEpochAcked = 0;
760       if (m_state == BbrMode_t::BBR_PROBE_BW)
761         {
762           SetPacingRate (tcb, 1);
763         }
764       else if (m_state == BbrMode_t::BBR_PROBE_RTT)
765         {
766           if (m_probeRttRoundDone && Simulator::Now () > m_probeRttDoneStamp)
767             {
768               m_rtPropStamp = Simulator::Now ();
769               RestoreCwnd (tcb);
770               ExitProbeRTT ();
771             }
772         }
773     }
774 }
775 
776 uint32_t
GetSsThresh(Ptr<const TcpSocketState> tcb,uint32_t bytesInFlight)777 TcpBbr::GetSsThresh (Ptr<const TcpSocketState> tcb, uint32_t bytesInFlight)
778 {
779   NS_LOG_FUNCTION (this << tcb << bytesInFlight);
780   SaveCwnd (tcb);
781   return tcb->m_ssThresh;
782 }
783 
784 Ptr<TcpCongestionOps>
Fork(void)785 TcpBbr::Fork (void)
786 {
787   return CopyObject<TcpBbr> (this);
788 }
789 
790 } // namespace ns3
791