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