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