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}
103
104/**
105 * @ingroup internet-test
106 *
107 * @brief Test to validate cWnd increment/decrement in LEDBAT Congestion Avoidance Phase
108 */
110{
111 public:
112 /**
113 * @brief Type of expected CWND behavior in LEDBAT congestion avoidance
114 */
116 {
117 /**
118 * To enable check for CWND increases because the measured queue delay is
119 * below the target delay (positive offset).
120 */
122
123 /**
124 * To enable check that CWND increase is limited by the maximum allowed CWND,
125 * computed from flight size before ack (bytesInFlight + segmentsAcked * segmentSize).
126 */
128
129 /**
130 * To enable check for CWND decreases because the measured queue delay is
131 * above the target delay (negative offset).
132 */
134
135 /**
136 * To enable check that CWND decrease is limited by the minimum CWND constraint
137 * (MinCwnd × segmentSize).
138 */
140 };
141
142 /**
143 * @brief Constructor
144 *
145 * @param cWnd congestion window
146 * @param segmentSize segment size
147 * @param ssThresh slow start threshold
148 * @param segmentsAcked segments acked
149 * @param bytesInFlight bytes in flight
150 * @param rtt RTT
151 * @param rcvTimestampValue Receive timestamp for delay estimation
152 * @param currentRcvTimestampEchoReply Echo reply timestamp for current delay
153 * @param testType Expected test behavior
154 * @param name Name of the test
155 */
156
159 uint32_t ssThresh,
160 uint32_t segmentsAcked,
161 uint32_t bytesInFlight,
162 Time rtt,
163 uint32_t rcvTimestampValue,
164 uint32_t currentRcvTimestampEchoReply,
165 TestType testType,
166 const std::string& name);
167
168 private:
169 void DoRun() override;
170
171 uint32_t m_cWnd; //!< cWnd
172 uint32_t m_segmentSize; //!< segment size
173 uint32_t m_segmentsAcked; //!< segments acked
174 uint32_t m_ssThresh; //!< ss thresh
175 Time m_rtt; //!< rtt
176 uint32_t m_bytesInFlight; //!< bytes in flight (after ACK)
177 uint32_t m_rcvTimestampValue; //!< received timestamp value
178 uint32_t m_currentRcvTimestampEchoReply; //!< current echoed timestamp value
179 TestType m_testType; //!< test type
181};
182
184 uint32_t cWnd,
186 uint32_t ssThresh,
187 uint32_t segmentsAcked,
188 uint32_t bytesInFlight,
189 Time rtt,
190 uint32_t rcvTimestampValue,
191 uint32_t currentRcvTimestampEchoReply,
192 TestType testType,
193 const std::string& name)
194 : TestCase(name),
195 m_cWnd(cWnd),
197 m_segmentsAcked(segmentsAcked),
198 m_ssThresh(ssThresh),
199 m_rtt(rtt),
200 m_bytesInFlight(bytesInFlight),
201 m_rcvTimestampValue(rcvTimestampValue),
202 m_currentRcvTimestampEchoReply(currentRcvTimestampEchoReply),
203 m_testType(testType)
204{
205}
206
207void
209{
211 m_state->m_cWnd = m_cWnd;
212 m_state->m_ssThresh = m_ssThresh;
213 m_state->m_segmentSize = m_segmentSize;
214 m_state->m_bytesInFlight = m_bytesInFlight;
215
217 cong->SetAttribute("Gain", DoubleValue(1.0)); // Default LEDBAT GAIN value as per RFC 6817
218 cong->SetAttribute("AllowedIncrease",
219 DoubleValue(1.0)); // Default LEDBAT Allowed Increase value as per RFC 6817
220 cong->SetAttribute("SSParam", StringValue("no"));
221 cong->SetAttribute("NoiseFilterLen", UintegerValue(1));
222 cong->SetAttribute("MinCwnd", UintegerValue(2));
223
224 // Establish base delay measurement (Base Delay = 40 - 20 = 20ms)
225 m_state->m_rcvTimestampValue = 40;
226 m_state->m_rcvTimestampEchoReply = 20;
227 cong->PktsAcked(m_state, m_segmentsAcked, m_rtt);
228
229 // Set current measured delay based on test parameters
230 m_state->m_rcvTimestampValue = m_rcvTimestampValue;
231 m_state->m_rcvTimestampEchoReply = m_currentRcvTimestampEchoReply;
232 cong->PktsAcked(m_state, m_segmentsAcked, m_rtt);
233
234 uint32_t oldCwnd = m_state->m_cWnd.Get();
235
236 // LEDBAT adjusts cwnd based on queuing delay relative to target:
237 // - When queuing delay < target: cwnd increases (positive offset)
238 // - When queuing delay > target: cwnd decreases (negative offset)
239 // - cwnd is bounded by max (flightSizeBeforeAck + ALLOWED_INCREASE * MSS)
240 // and min (minCwnd * MSS)
241
242 switch (m_testType)
243 {
244 case INCREMENT_TEST:
245 // Timestamps: rcvTimestamp=80, echoReply=20
246 // currentDelay = 80 - 20 = 60ms
247 // baseDelay = 20ms (established earlier: 40 - 20)
248 // queueDelay = currentDelay - baseDelay = 60 - 20 = 40ms
249 // offset = target - queueDelay = 100 - 40 = 60ms
250 // offset *= gain: offset = 60 * 1.0 = 60
251 // oldCwnd = 8676 bytes
252 // m_sndCwndCnt = offset * segmentsAcked * segmentSize
253 // = 60 * 2 * 1446 = 173520
254 // inc = m_sndCwndCnt / (target * oldCwnd)
255 // = 173520 / (100 * 8676) = 0.2
256 // newCwnd = oldCwnd + (inc * segmentSize)
257 // = 8676 + (0.2 * 1446) = 8676 + 289.2 = 8965.2 ≈ 8965
258 // flightSizeBeforeAck = bytesInFlight + segmentsAcked * segmentSize
259 // = 5784 + 2 * 1446 = 8676
260 // maxCwnd = flightSizeBeforeAck + allowedIncrease * segmentSize
261 // = 8676 + 1.0 * 1446 = 10122
262 // newCwnd = min(8965, 10122) = 8965
263 // newCwnd = max(8965, 2892) = 8965
264 // Final newCwnd = 8965 bytes
265 // increment = inc * segmentSize = 0.2 * 1446 = 289
266 cong->IncreaseWindow(m_state, m_segmentsAcked);
267 NS_TEST_ASSERT_MSG_EQ(m_state->m_cWnd.Get(),
268 oldCwnd + 289,
269 "cWnd of 8676 should increase by 289");
270 break;
271
272 case MAX_CWND_TEST:
273 // Timestamps: rcvTimestamp=80, echoReply=20
274 // currentDelay = 80 - 20 = 60ms
275 // baseDelay = 20ms (established earlier: 40 - 20)
276 // queueDelay = currentDelay - baseDelay = 60 - 20 = 40ms
277 // offset = target - queueDelay = 100 - 40 = 60ms
278 // offset *= gain: offset = 60 * 1.0 = 60
279 // oldCwnd = 8676 bytes, bytesInFlight = 4338 bytes
280 // m_sndCwndCnt = offset * segmentsAcked * segmentSize
281 // = 60 * 2 * 1446 = 173520
282 // inc = m_sndCwndCnt / (target * oldCwnd)
283 // = 173520 / (100 * 8676) = 0.2
284 // newCwnd = oldCwnd + (inc * segmentSize)
285 // = 8676 + (0.2 * 1446) = 8676 + 289.2 = 8965.2 ≈ 8965
286 // flightSizeBeforeAck = bytesInFlight + segmentsAcked * segmentSize
287 // = 4338 + 2 * 1446 = 7230
288 // maxCwnd = flightSizeBeforeAck + allowedIncrease * segmentSize
289 // = 7230 + 1.0 * 1446 = 8676
290 // Final newCwnd = min(8965, 8676) = 8676 bytes (clamped by maxCwnd)
291 cong->IncreaseWindow(m_state, m_segmentsAcked);
292 NS_TEST_ASSERT_MSG_EQ(m_state->m_cWnd.Get(), 8676, "cWnd should be limited by maxCwnd");
293 break;
294
295 case DECREMENT_TEST:
296 // Timestamps: rcvTimestamp=160, echoReply=20
297 // currentDelay = 160 - 20 = 140ms
298 // baseDelay = 20ms (established earlier: 40 - 20)
299 // queueDelay = currentDelay - baseDelay = 140 - 20 = 120ms
300 // offset = target - queueDelay = 100 - 120 = -20ms
301 // offset *= gain: offset = -20 * 1.0 = -20
302 // oldCwnd = 8676 bytes
303 // m_sndCwndCnt = offset * segmentsAcked * segmentSize
304 // = -20 * 2 * 1446 = -57840
305 // inc = m_sndCwndCnt / (target * oldCwnd)
306 // = -57840 / (100 * 8676) = -0.06667
307 // newCwnd = oldCwnd + (inc * segmentSize)
308 // = 8676 + (-0.06667 * 1446) = 8676 - 96.4 = 8579.6 ≈ 8579
309 // flightSizeBeforeAck = bytesInFlight + segmentsAcked * segmentSize
310 // = 5784 + 2 * 1446 = 8676
311 // maxCwnd = flightSizeBeforeAck + allowedIncrease * segmentSize
312 // = 8676 + 1.0 * 1446 = 10122
313 // newCwnd = min(8579, 10122) = 8579
314 // newCwnd = max(8579, 2892) = 8579
315 // Final newCwnd = 8579 bytes
316 // decrement = inc * segmentSize = -0.06667 * 1446 = -97
317 cong->IncreaseWindow(m_state, m_segmentsAcked);
318 NS_TEST_ASSERT_MSG_EQ(m_state->m_cWnd.Get(),
319 oldCwnd - 97,
320 "cWnd of 8676 should decrease by 97");
321 break;
322
323 case MIN_CWND_TEST:
324 // Timestamps: rcvTimestamp=160, echoReply=20
325 // currentDelay = 160 - 20 = 140ms
326 // baseDelay = 20ms (established earlier: 40 - 20)
327 // queueDelay = currentDelay - baseDelay = 140 - 20 = 120ms
328 // offset = target - queueDelay = 100 - 120 = -20ms
329 // offset *= gain: offset = -20 * 1.0 = -20
330 // oldCwnd = 2892 bytes, minCwnd = 2 segments = 2892 bytes
331 // m_sndCwndCnt = offset * segmentsAcked * segmentSize
332 // = -20 * 2 * 1446 = -57840
333 // inc = m_sndCwndCnt / (target * oldCwnd)
334 // = -57840 / (100 * 2892) = -0.2
335 // newCwnd = oldCwnd + (inc * segmentSize)
336 // = 2892 + (-0.2 * 1446) = 2892 - 289.2 = 2602.8 ≈ 2602
337 // flightSizeBeforeAck = bytesInFlight + segmentsAcked * segmentSize
338 // = 5784 + 2 * 1446 = 8676
339 // maxCwnd = flightSizeBeforeAck + allowedIncrease * segmentSize
340 // = 8676 + 1.0 * 1446 = 10122
341 // newCwnd = min(2602, 10122) = 2602
342 // Final newCwnd = max(2602, 2892) = 2892 bytes (clamped by minCwnd)
343 cong->IncreaseWindow(m_state, m_segmentsAcked);
344 NS_TEST_ASSERT_MSG_EQ(m_state->m_cWnd.Get(),
345 2 * 1446,
346 "cWnd should be clamped to minCwnd (2892)");
347 break;
348
349 default:
350 NS_FATAL_ERROR("Unknown Test Type");
351 break;
352 }
353}
354
355/**
356 * @ingroup internet-test
357 *
358 * @brief TCP Ledbat TestSuite
359 */
361{
362 public:
364 : TestSuite("tcp-ledbat-test", Type::UNIT)
365 {
366 AddTestCase(new TcpLedbatToNewReno(2 * 1446,
367 1446,
368 4 * 1446,
369 2,
370 1446,
371 MilliSeconds(100),
372 "LEDBAT falls to New Reno for slowstart"),
374 AddTestCase(new TcpLedbatToNewReno(4 * 1446,
375 1446,
376 2 * 1446,
377 2,
378 1446,
379 MilliSeconds(100),
380 "LEDBAT falls to New Reno if timestamps are not found"),
384 1446,
385 4 * 1446,
386 2,
387 4 * 1446,
388 MilliSeconds(100),
389 80,
390 20,
392 "LEDBAT Congestion Avoidance Increment"),
395 6 * 1446,
396 1446,
397 4 * 1446,
398 2,
399 3 * 1446,
400 MilliSeconds(100),
401 80,
402 20,
404 "LEDBAT Congestion Avoidance Increment (Limited by max_cwnd)"),
408 1446,
409 4 * 1446,
410 2,
411 4 * 1446,
412 MilliSeconds(100),
413 160,
414 20,
416 "LEDBAT Congestion Avoidance Decrement"),
419 2 * 1446,
420 1446,
421 4 * 1446,
422 2,
423 4 * 1446,
424 MilliSeconds(100),
425 160,
426 20,
428 "LEDBAT Congestion Avoidance Decrement (Limited by min_cwnd)"),
430 }
431};
432
433static 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
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