A Discrete-Event Network Simulator
API
tcp-cubic.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014 Natale Patriciello <natale.patriciello@gmail.com>
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  */
19 
20 #define NS_LOG_APPEND_CONTEXT \
21  { std::clog << Simulator::Now ().GetSeconds () << " "; }
22 
23 #include "tcp-cubic.h"
24 #include "ns3/log.h"
25 
26 NS_LOG_COMPONENT_DEFINE ("TcpCubic");
27 
28 namespace ns3 {
29 
31 
32 TypeId
34 {
35  static TypeId tid = TypeId ("ns3::TcpCubic")
37  .AddConstructor<TcpCubic> ()
38  .SetGroupName ("Internet")
39  .AddAttribute ("FastConvergence", "Enable (true) or disable (false) fast convergence",
40  BooleanValue (true),
43  .AddAttribute ("Beta", "Beta for multiplicative decrease",
44  DoubleValue (0.7),
46  MakeDoubleChecker <double> (0.0))
47  .AddAttribute ("HyStart", "Enable (true) or disable (false) hybrid slow start algorithm",
48  BooleanValue (true),
51  .AddAttribute ("HyStartLowWindow", "Lower bound cWnd for hybrid slow start (segments)",
52  UintegerValue (16),
54  MakeUintegerChecker <uint32_t> ())
55  .AddAttribute ("HyStartDetect", "Hybrid Slow Start detection mechanisms:" \
56  "1: packet train, 2: delay, 3: both",
57  IntegerValue (3),
59  MakeIntegerChecker <int> (1,3))
60  .AddAttribute ("HyStartMinSamples", "Number of delay samples for detecting the increase of delay",
61  UintegerValue (8),
63  MakeUintegerChecker <uint8_t> ())
64  .AddAttribute ("HyStartAckDelta", "Spacing between ack's indicating train",
65  TimeValue (MilliSeconds (2)),
67  MakeTimeChecker ())
68  .AddAttribute ("HyStartDelayMin", "Minimum time for hystart algorithm",
69  TimeValue (MilliSeconds (4)),
71  MakeTimeChecker ())
72  .AddAttribute ("HyStartDelayMax", "Maximum time for hystart algorithm",
73  TimeValue (MilliSeconds (1000)),
75  MakeTimeChecker ())
76  .AddAttribute ("CubicDelta", "Delta Time to wait after fast recovery before adjusting param",
77  TimeValue (MilliSeconds (10)),
79  MakeTimeChecker ())
80  .AddAttribute ("CntClamp", "Counter value when no losses are detected (counter is used" \
81  " when incrementing cWnd in congestion avoidance, to avoid" \
82  " floating point arithmetic). It is the modulo of the (avoided)" \
83  " division",
84  UintegerValue (20),
86  MakeUintegerChecker <uint8_t> ())
87  .AddAttribute ("C", "Cubic Scaling factor",
88  DoubleValue (0.4),
90  MakeDoubleChecker <double> (0.0))
91  ;
92  return tid;
93 }
94 
96  : TcpCongestionOps (),
97  m_cWndCnt (0),
98  m_lastMaxCwnd (0),
99  m_bicOriginPoint (0),
100  m_bicK (0.0),
101  m_delayMin (Time::Min ()),
102  m_epochStart (Time::Min ()),
103  m_found (false),
104  m_roundStart (Time::Min ()),
105  m_endSeq (0),
106  m_lastAck (Time::Min ()),
107  m_cubicDelta (Time::Min ()),
108  m_currRtt (Time::Min ()),
109  m_sampleCnt (0)
110 {
111  NS_LOG_FUNCTION (this);
112 }
113 
115  : TcpCongestionOps (sock),
116  m_fastConvergence (sock.m_fastConvergence),
117  m_beta (sock.m_beta),
118  m_hystart (sock.m_hystart),
119  m_hystartDetect (sock.m_hystartDetect),
120  m_hystartLowWindow (sock.m_hystartLowWindow),
121  m_hystartAckDelta (sock.m_hystartAckDelta),
122  m_hystartDelayMin (sock.m_hystartDelayMin),
123  m_hystartDelayMax (sock.m_hystartDelayMax),
124  m_hystartMinSamples (sock.m_hystartMinSamples),
125  m_initialCwnd (sock.m_initialCwnd),
126  m_cntClamp (sock.m_cntClamp),
127  m_c (sock.m_c),
128  m_cWndCnt (sock.m_cWndCnt),
129  m_lastMaxCwnd (sock.m_lastMaxCwnd),
130  m_bicOriginPoint (sock.m_bicOriginPoint),
131  m_bicK (sock.m_bicK),
132  m_delayMin (sock.m_delayMin),
133  m_epochStart (sock.m_epochStart),
134  m_found (sock.m_found),
135  m_roundStart (sock.m_roundStart),
136  m_endSeq (sock.m_endSeq),
137  m_lastAck (sock.m_lastAck),
138  m_cubicDelta (sock.m_cubicDelta),
139  m_currRtt (sock.m_currRtt),
140  m_sampleCnt (sock.m_sampleCnt)
141 {
142  NS_LOG_FUNCTION (this);
143 }
144 
145 std::string
147 {
148  return "TcpCubic";
149 }
150 
151 void
153 {
154  NS_LOG_FUNCTION (this);
155 
157  m_endSeq = tcb->m_highTxMark;
158  m_currRtt = Time::Min ();
159  m_sampleCnt = 0;
160 }
161 
162 void
163 TcpCubic::IncreaseWindow (Ptr<TcpSocketState> tcb, uint32_t segmentsAcked)
164 {
165  NS_LOG_FUNCTION (this << tcb << segmentsAcked);
166 
167  if (tcb->m_cWnd < tcb->m_ssThresh)
168  {
169 
170  if (m_hystart && tcb->m_lastAckedSeq > m_endSeq)
171  {
172  HystartReset (tcb);
173  }
174 
175  // In Linux, the QUICKACK socket option enables the receiver to send
176  // immediate acks initially (during slow start) and then transition
177  // to delayed acks. ns-3 does not implement QUICKACK, and if ack
178  // counting instead of byte counting is used during slow start window
179  // growth, when TcpSocket::DelAckCount==2, then the slow start will
180  // not reach as large of an initial window as in Linux. Therefore,
181  // we can approximate the effect of QUICKACK by making this slow
182  // start phase perform Appropriate Byte Counting (RFC 3465)
183  tcb->m_cWnd += segmentsAcked * tcb->m_segmentSize;
184  segmentsAcked = 0;
185 
186  NS_LOG_INFO ("In SlowStart, updated to cwnd " << tcb->m_cWnd <<
187  " ssthresh " << tcb->m_ssThresh);
188  }
189 
190  if (tcb->m_cWnd >= tcb->m_ssThresh && segmentsAcked > 0)
191  {
192  m_cWndCnt += segmentsAcked;
193  uint32_t cnt = Update (tcb);
194 
195  /* According to RFC 6356 even once the new cwnd is
196  * calculated you must compare this to the number of ACKs received since
197  * the last cwnd update. If not enough ACKs have been received then cwnd
198  * cannot be updated.
199  */
200  if (m_cWndCnt >= cnt)
201  {
202  tcb->m_cWnd += tcb->m_segmentSize;
203  m_cWndCnt -= cnt;
204  NS_LOG_INFO ("In CongAvoid, updated to cwnd " << tcb->m_cWnd);
205  }
206  else
207  {
208  NS_LOG_INFO ("Not enough segments have been ACKed to increment cwnd."
209  "Until now " << m_cWndCnt << " cnd " << cnt);
210  }
211  }
212 }
213 
214 uint32_t
216 {
217  NS_LOG_FUNCTION (this);
218  Time t;
219  uint32_t delta, bicTarget, cnt = 0;
220  double offs;
221  uint32_t segCwnd = tcb->GetCwndInSegments ();
222 
223  if (m_epochStart == Time::Min ())
224  {
225  m_epochStart = Simulator::Now (); // record the beginning of an epoch
226 
227  if (m_lastMaxCwnd <= segCwnd)
228  {
229  NS_LOG_DEBUG ("lastMaxCwnd <= m_cWnd. K=0 and origin=" << segCwnd);
230  m_bicK = 0.0;
231  m_bicOriginPoint = segCwnd;
232  }
233  else
234  {
235  m_bicK = std::pow ((m_lastMaxCwnd - segCwnd) / m_c, 1 / 3.);
237  NS_LOG_DEBUG ("lastMaxCwnd > m_cWnd. K=" << m_bicK <<
238  " and origin=" << m_lastMaxCwnd);
239  }
240  }
241 
243 
244  if (t.GetSeconds () < m_bicK) /* t - K */
245  {
246  offs = m_bicK - t.GetSeconds ();
247  NS_LOG_DEBUG ("t=" << t.GetSeconds () << " <k: offs=" << offs);
248  }
249  else
250  {
251  offs = t.GetSeconds () - m_bicK;
252  NS_LOG_DEBUG ("t=" << t.GetSeconds () << " >= k: offs=" << offs);
253  }
254 
255 
256  /* Constant value taken from Experimental Evaluation of Cubic Tcp, available at
257  * eprints.nuim.ie/1716/1/Hamiltonpfldnet2007_cubic_final.pdf */
258  delta = m_c * std::pow (offs, 3);
259 
260  NS_LOG_DEBUG ("delta: " << delta);
261 
262  if (t.GetSeconds () < m_bicK)
263  {
264  // below origin
265  bicTarget = m_bicOriginPoint - delta;
266  NS_LOG_DEBUG ("t < k: Bic Target: " << bicTarget);
267  }
268  else
269  {
270  // above origin
271  bicTarget = m_bicOriginPoint + delta;
272  NS_LOG_DEBUG ("t >= k: Bic Target: " << bicTarget);
273  }
274 
275  // Next the window target is converted into a cnt or count value. CUBIC will
276  // wait until enough new ACKs have arrived that a counter meets or exceeds
277  // this cnt value. This is how the CUBIC implementation simulates growing
278  // cwnd by values other than 1 segment size.
279  if (bicTarget > segCwnd)
280  {
281  cnt = segCwnd / (bicTarget - segCwnd);
282  NS_LOG_DEBUG ("target>cwnd. cnt=" << cnt);
283  }
284  else
285  {
286  cnt = 100 * segCwnd;
287  }
288 
289  if (m_lastMaxCwnd == 0 && cnt > m_cntClamp)
290  {
291  cnt = m_cntClamp;
292  }
293 
294  // The maximum rate of cwnd increase CUBIC allows is 1 packet per
295  // 2 packets ACKed, meaning cwnd grows at 1.5x per RTT.
296  return std::max (cnt, 2U);
297 }
298 
299 void
300 TcpCubic::PktsAcked (Ptr<TcpSocketState> tcb, uint32_t segmentsAcked,
301  const Time &rtt)
302 {
303  NS_LOG_FUNCTION (this << tcb << segmentsAcked << rtt);
304 
305  /* Discard delay samples right after fast recovery */
306  if (m_epochStart != Time::Min ()
308  {
309  return;
310  }
311 
312  /* first time call or link delay decreases */
313  if (m_delayMin == Time::Min () || m_delayMin > rtt)
314  {
315  m_delayMin = rtt;
316  }
317 
318  /* hystart triggers when cwnd is larger than some threshold */
319  if (m_hystart
320  && tcb->m_cWnd <= tcb->m_ssThresh
321  && tcb->m_cWnd >= m_hystartLowWindow * tcb->m_segmentSize)
322  {
323  HystartUpdate (tcb, rtt);
324  }
325 }
326 
327 void
329 {
330  NS_LOG_FUNCTION (this << delay);
331 
332  if (!(m_found & m_hystartDetect))
333  {
334  Time now = Simulator::Now ();
335 
336  /* first detection parameter - ack-train detection */
337  if ((now - m_lastAck) <= m_hystartAckDelta)
338  {
339  m_lastAck = now;
340 
341  if ((now - m_roundStart) > m_delayMin)
342  {
344  }
345  }
346 
347  /* obtain the minimum delay of more than sampling packets */
349  {
350  if (m_currRtt == Time::Min () || m_currRtt > delay)
351  {
352  m_currRtt = delay;
353  }
354 
355  ++m_sampleCnt;
356  }
357  else
358  {
359  if (m_currRtt > m_delayMin +
361  {
362  m_found |= DELAY;
363  }
364  }
365  /*
366  * Either one of two conditions are met,
367  * we exit from slow start immediately.
368  */
369  if (m_found & m_hystartDetect)
370  {
371  NS_LOG_DEBUG ("Exit from SS, immediately :-)");
372  tcb->m_ssThresh = tcb->m_cWnd;
373  }
374  }
375 }
376 
377 Time
379 {
380  NS_LOG_FUNCTION (this << t);
381 
382  Time ret = t;
383  if (t > m_hystartDelayMax)
384  {
385  ret = m_hystartDelayMax;
386  }
387  else if (t < m_hystartDelayMin)
388  {
389  ret = m_hystartDelayMin;
390  }
391 
392  return ret;
393 }
394 
395 uint32_t
397 {
398  NS_LOG_FUNCTION (this << tcb << bytesInFlight);
399 
400  // Without inflation and deflation, these two are the same
401  uint32_t segInFlight = bytesInFlight / tcb->m_segmentSize;
402  uint32_t segCwnd = tcb->GetCwndInSegments ();
403  NS_LOG_DEBUG ("Loss at cWnd=" << segCwnd << " in flight=" << segInFlight);
404 
405  /* Wmax and fast convergence */
406  if (segCwnd < m_lastMaxCwnd && m_fastConvergence)
407  {
408  m_lastMaxCwnd = (segCwnd * (1 + m_beta)) / 2; // Section 4.6 in RFC 8312
409  }
410  else
411  {
412  m_lastMaxCwnd = segCwnd;
413  }
414 
415  m_epochStart = Time::Min (); // end of epoch
416 
417  /* Formula taken from the Linux kernel */
418  uint32_t ssThresh = std::max (static_cast<uint32_t> (segInFlight * m_beta ), 2U) * tcb->m_segmentSize;
419 
420  NS_LOG_DEBUG ("SsThresh = " << ssThresh);
421 
422  return ssThresh;
423 }
424 
425 void
427 {
428  NS_LOG_FUNCTION (this << tcb << newState);
429 
430  if (newState == TcpSocketState::CA_LOSS)
431  {
432  CubicReset (tcb);
433  HystartReset (tcb);
434  }
435 }
436 
437 void
439 {
440  NS_LOG_FUNCTION (this << tcb);
441 
442  m_lastMaxCwnd = 0;
443  m_bicOriginPoint = 0;
444  m_bicK = 0;
445  m_delayMin = Time::Min ();
446  m_found = false;
447 }
448 
451 {
452  NS_LOG_FUNCTION (this);
453  return CopyObject<TcpCubic> (this);
454 }
455 
456 }
void CubicReset(Ptr< const TcpSocketState > tcb)
Reset Cubic parameters.
Definition: tcp-cubic.cc:438
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
virtual void CongestionStateSet(Ptr< TcpSocketState > tcb, const TcpSocketState::TcpCongState_t newState)
Trigger events/calculations specific to a congestion state.
Definition: tcp-cubic.cc:426
AttributeValue implementation for Boolean.
Definition: boolean.h:36
Time m_cubicDelta
Time to wait after recovery before update.
Definition: tcp-cubic.h:134
Time HystartDelayThresh(const Time &t) const
Clamp time value in a range.
Definition: tcp-cubic.cc:378
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Time m_epochStart
Beginning of an epoch.
Definition: tcp-cubic.h:129
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
Definition: nstime.h:274
void HystartReset(Ptr< const TcpSocketState > tcb)
Reset HyStart parameters.
Definition: tcp-cubic.cc:152
int m_hystartDetect
Detect way for HyStart algorithm.
Definition: tcp-cubic.h:110
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: boolean.h:85
double GetSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:380
bool m_fastConvergence
Enable or disable fast convergence algorithm.
Definition: tcp-cubic.h:106
SequenceNumber32 m_endSeq
End sequence of the round.
Definition: tcp-cubic.h:132
Hold a signed integer type.
Definition: integer.h:44
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1297
Time m_hystartDelayMin
Minimum time for hystart algorithm.
Definition: tcp-cubic.h:113
uint32_t Update(Ptr< TcpSocketState > tcb)
Cubic window update after a new ack received.
Definition: tcp-cubic.cc:215
uint32_t m_segmentSize
Segment size.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:281
bool m_hystart
Enable or disable HyStart algorithm.
Definition: tcp-cubic.h:109
Time m_hystartAckDelta
Spacing between ack&#39;s indicating train.
Definition: tcp-cubic.h:112
Time m_currRtt
Current Rtt.
Definition: tcp-cubic.h:135
Ptr< const AttributeAccessor > MakeIntegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: integer.h:45
uint32_t m_hystartLowWindow
Lower bound cWnd for hybrid slow start (segments)
Definition: tcp-cubic.h:111
double m_beta
Beta for cubic multiplicative increase.
Definition: tcp-cubic.h:107
virtual uint32_t GetSsThresh(Ptr< const TcpSocketState > tcb, uint32_t bytesInFlight)
Get the slow start threshold after a loss event.
Definition: tcp-cubic.cc:396
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:218
Time m_hystartDelayMax
Maximum time for hystart algorithm.
Definition: tcp-cubic.h:114
#define max(a, b)
Definition: 80211b.c:43
AttributeValue implementation for Time.
Definition: nstime.h:1353
virtual void PktsAcked(Ptr< TcpSocketState > tcb, uint32_t segmentsAcked, const Time &rtt)
Timing information on received ACK.
Definition: tcp-cubic.cc:300
virtual std::string GetName() const
Get the name of the congestion control algorithm.
Definition: tcp-cubic.cc:146
Hold an unsigned integer type.
Definition: uinteger.h:44
Detection by delay value.
Definition: tcp-cubic.h:103
bool m_found
The exit point is found?
Definition: tcp-cubic.h:130
SequenceNumber32 m_lastAckedSeq
Last sequence ACKed.
A base class for implementation of a stream socket using TCP.
TracedValue< uint32_t > m_ssThresh
Slow start threshold.
uint8_t m_cntClamp
Modulo of the (avoided) float division for cWnd.
Definition: tcp-cubic.h:118
TcpCongState_t
Definition of the Congestion state machine.
double m_c
Cubic Scaling factor.
Definition: tcp-cubic.h:120
uint32_t m_lastMaxCwnd
Last maximum cWnd.
Definition: tcp-cubic.h:124
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Congestion control abstract class.
double m_bicK
Time to origin point from the beginning.
Definition: tcp-cubic.h:126
static TypeId GetTypeId(void)
Get the type ID.
Definition: tcp-cubic.cc:33
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: nstime.h:1354
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
TracedValue< uint32_t > m_cWnd
Congestion window.
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: double.h:42
uint32_t m_cWndCnt
cWnd integer-to-float counter
Definition: tcp-cubic.h:123
uint8_t m_hystartMinSamples
Number of delay samples for detecting the increase of delay.
Definition: tcp-cubic.h:115
The Cubic Congestion Control Algorithm.
Definition: tcp-cubic.h:70
Time m_delayMin
Min delay.
Definition: tcp-cubic.h:128
virtual Ptr< TcpCongestionOps > Fork()
Copy the congestion control algorithm across sockets.
Definition: tcp-cubic.cc:450
CWND was reduced due to RTO timeout or SACK reneging.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
Ptr< const AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:533
Time m_lastAck
Last time when the ACK spacing is close.
Definition: tcp-cubic.h:133
uint32_t m_bicOriginPoint
Origin point of bic function.
Definition: tcp-cubic.h:125
Detection by trains of packet.
Definition: tcp-cubic.h:102
void HystartUpdate(Ptr< TcpSocketState > tcb, const Time &delay)
Update HyStart parameters.
Definition: tcp-cubic.cc:328
Time m_roundStart
Beginning of each round.
Definition: tcp-cubic.h:131
virtual void IncreaseWindow(Ptr< TcpSocketState > tcb, uint32_t segmentsAcked)
Congestion avoidance algorithm implementation.
Definition: tcp-cubic.cc:163
This class can be used to hold variables of floating point type such as &#39;double&#39; or &#39;float&#39;...
Definition: double.h:41
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: uinteger.h:45
a unique identifier for an interface.
Definition: type-id.h:58
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923
uint32_t GetCwndInSegments() const
Get cwnd in segments rather than bytes.
uint32_t m_sampleCnt
Count of samples for HyStart.
Definition: tcp-cubic.h:136