A Discrete-Event Network Simulator
API
tcp-yeah-test.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 ResiliNets, ITTC, University of Kansas
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  * Author: Truc Anh N. Nguyen <annguyen@ittc.ku.edu>
18  *
19  * James P.G. Sterbenz <jpgs@ittc.ku.edu>, director
20  * ResiliNets Research Group https://resilinets.org/
21  * Information and Telecommunication Technology Center (ITTC)
22  * and Department of Electrical Engineering and Computer Science
23  * The University of Kansas Lawrence, KS USA.
24  */
25 
26 #include "ns3/log.h"
27 #include "ns3/tcp-congestion-ops.h"
28 #include "ns3/tcp-socket-base.h"
29 #include "ns3/tcp-yeah.h"
30 #include "ns3/test.h"
31 
32 using namespace ns3;
33 
34 NS_LOG_COMPONENT_DEFINE("TcpYeahTestSuite");
35 
42 {
43  public:
55  TcpYeahIncrementTest(uint32_t cWnd,
56  uint32_t ssThresh,
57  uint32_t segmentSize,
58  SequenceNumber32 nextTxSeq,
59  SequenceNumber32 lastAckedSeq,
60  uint32_t segmentsAcked,
61  Time minRtt,
62  const std::string& name);
63 
64  private:
65  void DoRun() override;
70  void IncreaseWindow(Ptr<TcpYeah> cong);
71 
72  uint32_t m_cWnd;
73  uint32_t m_ssThresh;
74  uint32_t m_segmentSize;
77  uint32_t m_segmentsAcked;
80  uint32_t m_doingRenoNow;
81  uint32_t m_cntRtt;
82  uint32_t m_renoCount;
83 };
84 
86  uint32_t ssThresh,
87  uint32_t segmentSize,
88  SequenceNumber32 nextTxSeq,
89  SequenceNumber32 lastAckedSeq,
90  uint32_t segmentsAcked,
91  Time minRtt,
92  const std::string& name)
93  : TestCase(name),
94  m_cWnd(cWnd),
95  m_ssThresh(ssThresh),
96  m_segmentSize(segmentSize),
97  m_nextTxSeq(nextTxSeq),
98  m_lastAckedSeq(lastAckedSeq),
99  m_segmentsAcked(segmentsAcked),
100  m_baseRtt(MilliSeconds(100)),
101  m_minRtt(minRtt),
102  m_doingRenoNow(0),
103  m_cntRtt(4),
104  m_renoCount(2)
105 {
106 }
107 
108 void
110 {
111  Ptr<TcpSocketState> state = CreateObject<TcpSocketState>();
112  state->m_cWnd = m_cWnd;
113  state->m_ssThresh = m_ssThresh;
114  state->m_segmentSize = m_segmentSize;
115  state->m_nextTxSequence = m_nextTxSeq;
117  state->m_minRtt = m_minRtt;
118 
119  Ptr<TcpYeah> cong = CreateObject<TcpYeah>();
120 
121  // Set baseRtt to 100 ms
122  cong->PktsAcked(state, m_segmentsAcked, m_baseRtt);
123 
124  // Reset YeAH to assign a new value of minRtt
125  cong->CongestionStateSet(state, TcpSocketState::CA_OPEN);
126  cong->PktsAcked(state, m_segmentsAcked, m_minRtt);
127 
128  // 2 more calls to PktsAcked to increment cntRtt beyond 2
129  cong->PktsAcked(state, m_segmentsAcked, m_minRtt);
130  cong->PktsAcked(state, m_segmentsAcked, m_minRtt);
131 
132  cong->IncreaseWindow(state, m_segmentsAcked);
133  IncreaseWindow(cong);
134 
135  NS_TEST_ASSERT_MSG_EQ(state->m_cWnd.Get(), m_cWnd, "CWnd has not updated correctly");
136 }
137 
138 void
140 {
141  uint32_t segCwnd = m_cWnd / m_segmentSize;
142 
143  if (m_cWnd < m_ssThresh)
144  { // NewReno slow start
145  if (m_segmentsAcked >= 1)
146  {
148  m_segmentsAcked -= 1;
149  NS_LOG_INFO("In SlowStart, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
150  }
151  }
152  else if (!m_doingRenoNow)
153  { // Fast mode, follow STCP increment rule
154  UintegerValue aiFactor;
155  cong->GetAttribute("StcpAiFactor", aiFactor);
156  uint32_t w = std::min(segCwnd, (uint32_t)aiFactor.Get());
157  uint32_t delta = m_segmentsAcked / w;
159  NS_LOG_INFO("In Fast mode, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
160  }
161  else
162  { // NewReno congestion avoidance
163  if (m_segmentsAcked > 0)
164  {
165  double adder = static_cast<double>(m_segmentSize * m_segmentSize) / m_cWnd;
166  adder = std::max(1.0, adder);
167  m_cWnd += static_cast<uint32_t>(adder);
168  NS_LOG_INFO("In CongAvoid, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
169  }
170  }
172  {
173  if (m_cntRtt > 2)
174  {
175  /*
176  * Calculate the extra number of packets in queue
177  */
178  Time rttQueue = m_minRtt - m_baseRtt;
179  double bw = segCwnd / m_minRtt.GetSeconds();
180  uint32_t queue = bw * rttQueue.GetSeconds();
181 
182  // Calculate network congestion level
183  double L = rttQueue.GetSeconds() / m_baseRtt.GetSeconds();
184 
185  UintegerValue alpha;
186  cong->GetAttribute("Alpha", alpha);
188  cong->GetAttribute("Phy", phy);
189  UintegerValue gamma;
190  cong->GetAttribute("Gamma", gamma);
192  cong->GetAttribute("Epsilon", epsilon);
193  UintegerValue zeta;
194  cong->GetAttribute("Zeta", zeta);
195 
196  if (queue > alpha.Get() || L > (1 / phy.Get()))
197  { // Slow mode
198  NS_LOG_INFO("Enter Slow mode");
199  if (queue > alpha.Get() && segCwnd > m_renoCount)
200  { // Precautionary decongestion
201  uint32_t reduction =
202  std::min(queue / (uint32_t)gamma.Get(), segCwnd >> (uint32_t)epsilon.Get());
203  segCwnd -= reduction;
204  segCwnd = std::max(segCwnd, m_renoCount);
205  m_cWnd = segCwnd * m_segmentSize;
206  m_ssThresh = m_cWnd;
207  NS_LOG_INFO("In Slow mode, after precautionary decongestion, "
208  "updated to cwnd "
209  << m_cWnd << " ssthresh " << m_ssThresh);
210  }
211  }
212  }
213  }
214 }
215 
222 {
223  public:
235  TcpYeahDecrementTest(uint32_t cWnd,
236  uint32_t ssThresh,
237  uint32_t segmentSize,
238  SequenceNumber32 nextTxSeq,
239  SequenceNumber32 lastAckedSeq,
240  Time minRtt,
241  UintegerValue rho,
242  const std::string& name);
243 
244  private:
245  void DoRun() override;
251  uint32_t CalculateSsThresh(Ptr<TcpYeah> cong);
252 
253  uint32_t m_cWnd;
254  uint32_t m_ssThresh;
255  uint32_t m_segmentSize;
256  uint32_t m_doingRenoNow;
261  uint32_t m_segmentsAcked;
263 };
264 
266  uint32_t ssThresh,
267  uint32_t segmentSize,
268  SequenceNumber32 nextTxSeq,
269  SequenceNumber32 lastAckedSeq,
270  Time minRtt,
271  UintegerValue rho,
272  const std::string& name)
273  : TestCase(name),
274  m_cWnd(cWnd),
275  m_ssThresh(ssThresh),
276  m_segmentSize(segmentSize),
277  m_doingRenoNow(0),
278  m_nextTxSeq(nextTxSeq),
279  m_lastAckedSeq(lastAckedSeq),
280  m_minRtt(minRtt),
281  m_baseRtt(MilliSeconds(100)),
282  m_segmentsAcked(2),
283  m_rho(rho)
284 {
285 }
286 
287 void
289 {
290  Ptr<TcpSocketState> state = CreateObject<TcpSocketState>();
291  state->m_cWnd = m_cWnd;
292  state->m_nextTxSequence = m_nextTxSeq;
294  state->m_segmentSize = m_segmentSize;
295  state->m_ssThresh = m_ssThresh;
296 
297  Ptr<TcpYeah> cong = CreateObject<TcpYeah>();
298 
299  // Re-set rho to 1 for this unit test
300  cong->SetAttribute("Rho", UintegerValue(m_rho));
301 
302  // Set baseRtt to 100 ms
303  cong->PktsAcked(state, m_segmentsAcked, m_baseRtt);
304 
305  // Set minRtt to a different value
306  cong->CongestionStateSet(state, TcpSocketState::CA_OPEN);
307  cong->PktsAcked(state, m_segmentsAcked, m_minRtt);
308 
309  // 2 more calls to PktsAcked to increment cntRtt beyond 2
310  cong->PktsAcked(state, m_segmentsAcked, m_minRtt);
311  cong->PktsAcked(state, m_segmentsAcked, m_minRtt);
312 
313  // Calculate queue backlog
314  cong->IncreaseWindow(state, m_segmentsAcked);
315 
316  // Now get the value of ssThresh
317  uint32_t ssThresh = cong->GetSsThresh(state, m_cWnd);
318 
319  // Our calculation of ssThresh
320  uint32_t ssThreshVal = CalculateSsThresh(cong);
321 
322  NS_TEST_ASSERT_MSG_EQ(ssThresh, ssThreshVal, "SsThresh has not updated correctly");
323 }
324 
325 uint32_t
327 {
328  // Calculate queue backlog
329  uint32_t segCwnd = m_cWnd / m_segmentSize;
330  uint32_t reduction;
331 
333  cong->GetAttribute("Delta", delta);
334 
335  Time rttQueue = m_minRtt - m_baseRtt;
336 
337  // queue = rttQueue * bw = rttQueue * (cwnd/RTTmin)
338  double bw = segCwnd / m_minRtt.GetSeconds();
339  uint32_t queue = bw * rttQueue.GetSeconds();
340 
341  NS_LOG_LOGIC("queue backlog" << queue);
342 
343  if (m_doingRenoNow < m_rho.Get())
344  {
345  reduction = std::max(queue, segCwnd >> delta.Get());
346  reduction = std::min(reduction, std::max(segCwnd >> 1, (uint32_t)2));
347  NS_LOG_INFO("Reduction amount for yeah upon loss = " << reduction);
348  }
349  else
350  {
351  reduction = std::max(segCwnd >> 1, (uint32_t)2);
352  NS_LOG_INFO("Reduction amount for reno upon loss = " << reduction);
353  }
354 
355  return (m_cWnd - (reduction * m_segmentSize));
356 }
357 
364 {
365  public:
367  : TestSuite("tcp-yeah-test", UNIT)
368  {
369  AddTestCase(new TcpYeahIncrementTest(20 * 1446,
370  25 * 1446,
371  1446,
372  SequenceNumber32(2893),
373  SequenceNumber32(1447),
374  1,
375  MilliSeconds(105),
376  "YeAH test on cWnd when in slow start"),
377  TestCase::QUICK);
378  AddTestCase(new TcpYeahIncrementTest(30 * 1446,
379  25 * 1446,
380  1446,
381  SequenceNumber32(2893),
382  SequenceNumber32(1447),
383  30,
384  MilliSeconds(105),
385  "YeAH test on cWnd when in Fast mode"),
386  TestCase::QUICK);
388  40 * 356,
389  30 * 356,
390  356,
391  SequenceNumber32(20761),
392  SequenceNumber32(21117),
393  1,
394  MilliSeconds(120),
395  "YeAH test on cWnd when in slow mode without precautionary decongestion"),
396  TestCase::QUICK);
398  100 * 356,
399  70 * 356,
400  356,
401  SequenceNumber32(20761),
402  SequenceNumber32(21117),
403  1,
404  MilliSeconds(600),
405  "YeAH test on cWnd when in slow mode with precautionary decongestion"),
406  TestCase::QUICK);
408  40 * 1446,
409  30 * 1446,
410  1446,
411  SequenceNumber32(2893),
412  SequenceNumber32(7230),
413  MilliSeconds(120),
414  UintegerValue(0),
415  "YeAH test on ssThresh upon loss while competing with Reno flows"),
416  TestCase::QUICK);
418  57 * 1446,
419  42 * 1446,
420  1446,
421  SequenceNumber32(2893),
422  SequenceNumber32(7230),
423  MilliSeconds(200),
424  UintegerValue(2),
425  "YeAH test on ssThresh upon loss while not competing with Reno flows"),
426  TestCase::QUICK);
427  }
428 };
429 
#define min(a, b)
Definition: 80211b.c:41
#define max(a, b)
Definition: 80211b.c:42
Testing TcpYeah multiplicative decrease algorithm.
Time m_baseRtt
Base RTT.
uint32_t m_cWnd
Congestion window.
void DoRun() override
Implementation to actually run this TestCase.
uint32_t m_segmentsAcked
Number of segments ACKed.
uint32_t m_ssThresh
Slow Start Threshold.
SequenceNumber32 m_nextTxSeq
Next Tx sequence number.
uint32_t m_segmentSize
Segment size.
uint32_t m_doingRenoNow
TCP Reno fallback.
uint32_t CalculateSsThresh(Ptr< TcpYeah > cong)
Calculate the Slow Start threshold.
UintegerValue m_rho
TCP Yeah rho param.
TcpYeahDecrementTest(uint32_t cWnd, uint32_t ssThresh, uint32_t segmentSize, SequenceNumber32 nextTxSeq, SequenceNumber32 lastAckedSeq, Time minRtt, UintegerValue rho, const std::string &name)
Constructor.
SequenceNumber32 m_lastAckedSeq
Last ACKed sequence number.
Testing TcpYeah additive increase algorithm.
void IncreaseWindow(Ptr< TcpYeah > cong)
Increases the TCP window.
uint32_t m_segmentsAcked
Number of segments ACKed.
uint32_t m_cWnd
Congestion window.
void DoRun() override
Implementation to actually run this TestCase.
Time m_baseRtt
Base RTT.
uint32_t m_segmentSize
Segment size.
TcpYeahIncrementTest(uint32_t cWnd, uint32_t ssThresh, uint32_t segmentSize, SequenceNumber32 nextTxSeq, SequenceNumber32 lastAckedSeq, uint32_t segmentsAcked, Time minRtt, const std::string &name)
Constructor.
uint32_t m_doingRenoNow
TCP Reno fallback.
SequenceNumber32 m_lastAckedSeq
Last ACKed sequence number.
SequenceNumber32 m_nextTxSeq
Next Tx sequence number.
uint32_t m_ssThresh
Slow Start Threshold.
uint32_t m_renoCount
Reno counter.
Time m_minRtt
Min RTT.
uint32_t m_cntRtt
RTT counter.
TCP Yeah TestSuite.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
uint32_t m_segmentSize
Segment size.
Time m_minRtt
Minimum RTT observed throughout the connection.
SequenceNumber32 m_lastAckedSeq
Last sequence ACKed.
TracedValue< uint32_t > m_cWnd
Congestion window.
TracedValue< SequenceNumber32 > m_nextTxSequence
Next seqnum to be sent (SND.NXT), ReTx pushes it back.
TracedValue< uint32_t > m_ssThresh
Slow start threshold.
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1256
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1265
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:403
T Get() const
Get the underlying value.
Definition: traced-value.h:249
Hold an unsigned integer type.
Definition: uinteger.h:45
uint64_t Get() const
Definition: uinteger.cc:37
uint32_t segmentSize
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
SequenceNumber< uint32_t, int32_t > SequenceNumber32
32 bit Sequence number.
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:144
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
Every class exported by the ns3 library is enclosed in the ns3 namespace.
phy
Definition: third.py:89
static TcpYeahTestSuite g_tcpYeahTest
Static variable for test initialization.