A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
tcp-ledbat-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016 NITK Surathkal
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Ankit Deepak <adadeepak8@gmail.com>
7 * Modified by: S B L Prateek <sblprateek@gmail.com>
8 *
9 */
10
11#include "ns3/log.h"
12#include "ns3/string.h"
13#include "ns3/tcp-congestion-ops.h"
14#include "ns3/tcp-ledbat.h"
15#include "ns3/tcp-socket-base.h"
16#include "ns3/test.h"
17
18using namespace ns3;
19
20NS_LOG_COMPONENT_DEFINE("TcpLedbatTestSuite");
21
22/**
23 * @ingroup internet-test
24 *
25 * @brief LEDBAT should be same as NewReno during slow start, and when timestamps are disabled
26 */
28{
29 public:
30 /**
31 * @brief Constructor
32 *
33 * @param cWnd congestion window
34 * @param segmentSize segment size
35 * @param ssThresh slow start threshold
36 * @param segmentsAcked segments acked
37 * @param bytesInFlight bytes in flight
38 * @param rtt RTT
39 * @param name Name of the test
40 */
43 uint32_t ssThresh,
44 uint32_t segmentsAcked,
45 uint32_t bytesInFlight,
46 Time rtt,
47 const std::string& name);
48
49 private:
50 void DoRun() override;
51
52 uint32_t m_cWnd; //!< cWnd
53 uint32_t m_segmentSize; //!< segment size
54 uint32_t m_segmentsAcked; //!< segments acked
55 uint32_t m_ssThresh; //!< ss thresh
56 Time m_rtt; //!< rtt
57 uint32_t m_bytesInFlight; //!< bytes in flight
59};
60
63 uint32_t ssThresh,
64 uint32_t segmentsAcked,
65 uint32_t bytesInFlight,
66 Time rtt,
67 const std::string& name)
68 : TestCase(name),
69 m_cWnd(cWnd),
71 m_segmentsAcked(segmentsAcked),
72 m_ssThresh(ssThresh),
73 m_rtt(rtt),
74 m_bytesInFlight(bytesInFlight)
75{
76}
77
78void
80{
82 m_state->m_cWnd = m_cWnd;
83 m_state->m_ssThresh = m_ssThresh;
84 m_state->m_segmentSize = m_segmentSize;
85 m_state->m_bytesInFlight = m_bytesInFlight;
86
88 state->m_cWnd = m_cWnd;
89 state->m_ssThresh = m_ssThresh;
90 state->m_segmentSize = m_segmentSize;
91 state->m_bytesInFlight = m_bytesInFlight;
92
94 cong->IncreaseWindow(m_state, m_segmentsAcked);
95
97 NewRenoCong->IncreaseWindow(state, m_segmentsAcked);
98
99 NS_TEST_ASSERT_MSG_EQ(m_state->m_cWnd.Get(),
100 state->m_cWnd.Get(),
101 "cWnd has not updated correctly");
102
104}
105
106/**
107 * @ingroup internet-test
108 *
109 * @brief Test to validate cWnd increment/decrement in LEDBAT Congestion Avoidance Phase
110 */
112{
113 public:
114 /**
115 * @brief Type of expected CWND behavior in LEDBAT congestion avoidance
116 */
118 {
119 /**
120 * To enable check for CWND increases because the measured queue delay is
121 * below the target delay (positive offset).
122 */
124
125 /**
126 * To enable check that CWND increase is limited by the maximum allowed CWND,
127 * computed from flight size before ack (bytesInFlight + segmentsAcked * segmentSize).
128 */
130
131 /**
132 * To enable check for CWND decreases because the measured queue delay is
133 * above the target delay (negative offset).
134 */
136
137 /**
138 * To enable check that CWND decrease is limited by the minimum CWND constraint
139 * (MinCwnd × segmentSize).
140 */
142 };
143
144 /**
145 * @brief Constructor
146 *
147 * @param cWnd congestion window
148 * @param segmentSize segment size
149 * @param ssThresh slow start threshold
150 * @param segmentsAcked segments acked
151 * @param bytesInFlight bytes in flight
152 * @param rtt RTT
153 * @param rcvTimestampValue Receive timestamp for delay estimation
154 * @param currentRcvTimestampEchoReply Echo reply timestamp for current delay
155 * @param testType Expected test behavior
156 * @param name Name of the test
157 */
158
161 uint32_t ssThresh,
162 uint32_t segmentsAcked,
163 uint32_t bytesInFlight,
164 Time rtt,
165 uint32_t rcvTimestampValue,
166 uint32_t currentRcvTimestampEchoReply,
167 TestType testType,
168 const std::string& name);
169
170 private:
171 void DoRun() override;
172
173 uint32_t m_cWnd; //!< cWnd
174 uint32_t m_segmentSize; //!< segment size
175 uint32_t m_segmentsAcked; //!< segments acked
176 uint32_t m_ssThresh; //!< ss thresh
177 Time m_rtt; //!< rtt
178 uint32_t m_bytesInFlight; //!< bytes in flight (after ACK)
179 uint32_t m_rcvTimestampValue; //!< received timestamp value
180 uint32_t m_currentRcvTimestampEchoReply; //!< current echoed timestamp value
181 TestType m_testType; //!< test type
183};
184
186 uint32_t cWnd,
188 uint32_t ssThresh,
189 uint32_t segmentsAcked,
190 uint32_t bytesInFlight,
191 Time rtt,
192 uint32_t rcvTimestampValue,
193 uint32_t currentRcvTimestampEchoReply,
194 TestType testType,
195 const std::string& name)
196 : TestCase(name),
197 m_cWnd(cWnd),
199 m_segmentsAcked(segmentsAcked),
200 m_ssThresh(ssThresh),
201 m_rtt(rtt),
202 m_bytesInFlight(bytesInFlight),
203 m_rcvTimestampValue(rcvTimestampValue),
204 m_currentRcvTimestampEchoReply(currentRcvTimestampEchoReply),
205 m_testType(testType)
206{
207}
208
209void
211{
213 m_state->m_cWnd = m_cWnd;
214 m_state->m_ssThresh = m_ssThresh;
215 m_state->m_segmentSize = m_segmentSize;
216 m_state->m_bytesInFlight = m_bytesInFlight;
217
219 cong->SetAttribute("Gain", DoubleValue(1.0)); // Default LEDBAT GAIN value as per RFC 6817
220 cong->SetAttribute("AllowedIncrease",
221 DoubleValue(1.0)); // Default LEDBAT Allowed Increase value as per RFC 6817
222 cong->SetAttribute("SSParam", StringValue("no"));
223 cong->SetAttribute("NoiseFilterLen", UintegerValue(1));
224 cong->SetAttribute("MinCwnd", UintegerValue(2));
225
226 // Establish base delay measurement (Base Delay = 40 - 20 = 20ms)
227 m_state->m_rcvTimestampValue = 40;
228 m_state->m_rcvTimestampEchoReply = 20;
229 cong->PktsAcked(m_state, m_segmentsAcked, m_rtt);
230
231 // Set current measured delay based on test parameters
232 m_state->m_rcvTimestampValue = m_rcvTimestampValue;
233 m_state->m_rcvTimestampEchoReply = m_currentRcvTimestampEchoReply;
234 cong->PktsAcked(m_state, m_segmentsAcked, m_rtt);
235
236 uint32_t oldCwnd = m_state->m_cWnd.Get();
237
238 // LEDBAT adjusts cwnd based on queuing delay relative to target:
239 // - When queuing delay < target: cwnd increases (positive offset)
240 // - When queuing delay > target: cwnd decreases (negative offset)
241 // - cwnd is bounded by max (flightSizeBeforeAck + ALLOWED_INCREASE * MSS)
242 // and min (minCwnd * MSS)
243
244 switch (m_testType)
245 {
246 case INCREMENT_TEST:
247 // Timestamps: rcvTimestamp=80, echoReply=20
248 // currentDelay = 80 - 20 = 60ms
249 // baseDelay = 20ms (established earlier: 40 - 20)
250 // queueDelay = currentDelay - baseDelay = 60 - 20 = 40ms
251 // offset = target - queueDelay = 100 - 40 = 60ms
252 // offset *= gain: offset = 60 * 1.0 = 60
253 // oldCwnd = 8676 bytes
254 // m_sndCwndCnt = offset * segmentsAcked * segmentSize
255 // = 60 * 2 * 1446 = 173520
256 // inc = m_sndCwndCnt / (target * oldCwnd)
257 // = 173520 / (100 * 8676) = 0.2
258 // newCwnd = oldCwnd + (inc * segmentSize)
259 // = 8676 + (0.2 * 1446) = 8676 + 289.2 = 8965.2 ≈ 8965
260 // flightSizeBeforeAck = bytesInFlight + segmentsAcked * segmentSize
261 // = 5784 + 2 * 1446 = 8676
262 // maxCwnd = flightSizeBeforeAck + allowedIncrease * segmentSize
263 // = 8676 + 1.0 * 1446 = 10122
264 // newCwnd = min(8965, 10122) = 8965
265 // newCwnd = max(8965, 2892) = 8965
266 // Final newCwnd = 8965 bytes
267 // increment = inc * segmentSize = 0.2 * 1446 = 289
268 cong->IncreaseWindow(m_state, m_segmentsAcked);
269 NS_TEST_ASSERT_MSG_EQ(m_state->m_cWnd.Get(),
270 oldCwnd + 289,
271 "cWnd of 8676 should increase by 289");
272 break;
273
274 case MAX_CWND_TEST:
275 // Timestamps: rcvTimestamp=80, echoReply=20
276 // currentDelay = 80 - 20 = 60ms
277 // baseDelay = 20ms (established earlier: 40 - 20)
278 // queueDelay = currentDelay - baseDelay = 60 - 20 = 40ms
279 // offset = target - queueDelay = 100 - 40 = 60ms
280 // offset *= gain: offset = 60 * 1.0 = 60
281 // oldCwnd = 8676 bytes, bytesInFlight = 4338 bytes
282 // m_sndCwndCnt = offset * segmentsAcked * segmentSize
283 // = 60 * 2 * 1446 = 173520
284 // inc = m_sndCwndCnt / (target * oldCwnd)
285 // = 173520 / (100 * 8676) = 0.2
286 // newCwnd = oldCwnd + (inc * segmentSize)
287 // = 8676 + (0.2 * 1446) = 8676 + 289.2 = 8965.2 ≈ 8965
288 // flightSizeBeforeAck = bytesInFlight + segmentsAcked * segmentSize
289 // = 4338 + 2 * 1446 = 7230
290 // maxCwnd = flightSizeBeforeAck + allowedIncrease * segmentSize
291 // = 7230 + 1.0 * 1446 = 8676
292 // Final newCwnd = min(8965, 8676) = 8676 bytes (clamped by maxCwnd)
293 cong->IncreaseWindow(m_state, m_segmentsAcked);
294 NS_TEST_ASSERT_MSG_EQ(m_state->m_cWnd.Get(), 8676, "cWnd should be limited by maxCwnd");
295 break;
296
297 case DECREMENT_TEST:
298 // Timestamps: rcvTimestamp=160, echoReply=20
299 // currentDelay = 160 - 20 = 140ms
300 // baseDelay = 20ms (established earlier: 40 - 20)
301 // queueDelay = currentDelay - baseDelay = 140 - 20 = 120ms
302 // offset = target - queueDelay = 100 - 120 = -20ms
303 // offset *= gain: offset = -20 * 1.0 = -20
304 // oldCwnd = 8676 bytes
305 // m_sndCwndCnt = offset * segmentsAcked * segmentSize
306 // = -20 * 2 * 1446 = -57840
307 // inc = m_sndCwndCnt / (target * oldCwnd)
308 // = -57840 / (100 * 8676) = -0.06667
309 // newCwnd = oldCwnd + (inc * segmentSize)
310 // = 8676 + (-0.06667 * 1446) = 8676 - 96.4 = 8579.6 ≈ 8579
311 // flightSizeBeforeAck = bytesInFlight + segmentsAcked * segmentSize
312 // = 5784 + 2 * 1446 = 8676
313 // maxCwnd = flightSizeBeforeAck + allowedIncrease * segmentSize
314 // = 8676 + 1.0 * 1446 = 10122
315 // newCwnd = min(8579, 10122) = 8579
316 // newCwnd = max(8579, 2892) = 8579
317 // Final newCwnd = 8579 bytes
318 // decrement = inc * segmentSize = -0.06667 * 1446 = -97
319 cong->IncreaseWindow(m_state, m_segmentsAcked);
320 NS_TEST_ASSERT_MSG_EQ(m_state->m_cWnd.Get(),
321 oldCwnd - 97,
322 "cWnd of 8676 should decrease by 97");
323 break;
324
325 case MIN_CWND_TEST:
326 // Timestamps: rcvTimestamp=160, echoReply=20
327 // currentDelay = 160 - 20 = 140ms
328 // baseDelay = 20ms (established earlier: 40 - 20)
329 // queueDelay = currentDelay - baseDelay = 140 - 20 = 120ms
330 // offset = target - queueDelay = 100 - 120 = -20ms
331 // offset *= gain: offset = -20 * 1.0 = -20
332 // oldCwnd = 2892 bytes, minCwnd = 2 segments = 2892 bytes
333 // m_sndCwndCnt = offset * segmentsAcked * segmentSize
334 // = -20 * 2 * 1446 = -57840
335 // inc = m_sndCwndCnt / (target * oldCwnd)
336 // = -57840 / (100 * 2892) = -0.2
337 // newCwnd = oldCwnd + (inc * segmentSize)
338 // = 2892 + (-0.2 * 1446) = 2892 - 289.2 = 2602.8 ≈ 2602
339 // flightSizeBeforeAck = bytesInFlight + segmentsAcked * segmentSize
340 // = 5784 + 2 * 1446 = 8676
341 // maxCwnd = flightSizeBeforeAck + allowedIncrease * segmentSize
342 // = 8676 + 1.0 * 1446 = 10122
343 // newCwnd = min(2602, 10122) = 2602
344 // Final newCwnd = max(2602, 2892) = 2892 bytes (clamped by minCwnd)
345 cong->IncreaseWindow(m_state, m_segmentsAcked);
346 NS_TEST_ASSERT_MSG_EQ(m_state->m_cWnd.Get(),
347 2 * 1446,
348 "cWnd should be clamped to minCwnd (2892)");
349 break;
350
351 default:
352 NS_FATAL_ERROR("Unknown Test Type");
353 break;
354 }
355
357}
358
359/**
360 * @ingroup internet-test
361 *
362 * @brief TCP Ledbat TestSuite
363 */
365{
366 public:
368 : TestSuite("tcp-ledbat-test", Type::UNIT)
369 {
370 AddTestCase(new TcpLedbatToNewReno(2 * 1446,
371 1446,
372 4 * 1446,
373 2,
374 1446,
375 MilliSeconds(100),
376 "LEDBAT falls to New Reno for slowstart"),
378 AddTestCase(new TcpLedbatToNewReno(4 * 1446,
379 1446,
380 2 * 1446,
381 2,
382 1446,
383 MilliSeconds(100),
384 "LEDBAT falls to New Reno if timestamps are not found"),
388 1446,
389 4 * 1446,
390 2,
391 4 * 1446,
392 MilliSeconds(100),
393 80,
394 20,
396 "LEDBAT Congestion Avoidance Increment"),
399 6 * 1446,
400 1446,
401 4 * 1446,
402 2,
403 3 * 1446,
404 MilliSeconds(100),
405 80,
406 20,
408 "LEDBAT Congestion Avoidance Increment (Limited by max_cwnd)"),
412 1446,
413 4 * 1446,
414 2,
415 4 * 1446,
416 MilliSeconds(100),
417 160,
418 20,
420 "LEDBAT Congestion Avoidance Decrement"),
423 2 * 1446,
424 1446,
425 4 * 1446,
426 2,
427 4 * 1446,
428 MilliSeconds(100),
429 160,
430 20,
432 "LEDBAT Congestion Avoidance Decrement (Limited by min_cwnd)"),
434 }
435};
436
437static TcpLedbatTestSuite g_tcpledbatTest; //!< static var for test initialization
Test to validate cWnd increment/decrement in LEDBAT Congestion Avoidance Phase.
Ptr< TcpSocketState > m_state
state
uint32_t m_currentRcvTimestampEchoReply
current echoed timestamp value
void DoRun() override
Implementation to actually run this TestCase.
uint32_t m_rcvTimestampValue
received timestamp value
uint32_t m_segmentsAcked
segments acked
TcpLedbatCongestionAvoidanceTest(uint32_t cWnd, uint32_t segmentSize, uint32_t ssThresh, uint32_t segmentsAcked, uint32_t bytesInFlight, Time rtt, uint32_t rcvTimestampValue, uint32_t currentRcvTimestampEchoReply, TestType testType, const std::string &name)
Constructor.
uint32_t m_bytesInFlight
bytes in flight (after ACK)
TestType
Type of expected CWND behavior in LEDBAT congestion avoidance.
@ DECREMENT_TEST
To enable check for CWND decreases because the measured queue delay is above the target delay (negati...
@ MIN_CWND_TEST
To enable check that CWND decrease is limited by the minimum CWND constraint (MinCwnd × segmentSize).
@ INCREMENT_TEST
To enable check for CWND increases because the measured queue delay is below the target delay (positi...
@ MAX_CWND_TEST
To enable check that CWND increase is limited by the maximum allowed CWND, computed from flight size ...
TCP Ledbat TestSuite.
LEDBAT should be same as NewReno during slow start, and when timestamps are disabled.
uint32_t m_segmentsAcked
segments acked
TcpLedbatToNewReno(uint32_t cWnd, uint32_t segmentSize, uint32_t ssThresh, uint32_t segmentsAcked, uint32_t bytesInFlight, Time rtt, const std::string &name)
Constructor.
Ptr< TcpSocketState > m_state
state
uint32_t m_bytesInFlight
bytes in flight
void DoRun() override
Implementation to actually run this TestCase.
uint32_t m_segmentSize
segment size
uint32_t m_ssThresh
ss thresh
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:125
Hold variables of type string.
Definition string.h:45
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:296
@ QUICK
Fast test.
Definition test.h:1057
TestCase(const TestCase &)=delete
Caller graph was not generated because of its size.
Type
Type of test.
Definition test.h:1271
@ UNIT
This test suite implements a Unit Test.
Definition test.h:1273
TestSuite(std::string name, Type type=Type::UNIT)
Construct a new test suite.
Definition test.cc:494
Simulation virtual time values and global simulation resolution.
Definition nstime.h:95
Hold an unsigned integer type.
Definition uinteger.h:34
uint32_t segmentSize
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:627
#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:133
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1290
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static TcpLedbatTestSuite g_tcpledbatTest
static var for test initialization