A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
tc-flow-control-test-suite.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2017 Universita' degli Studi di Napoli Federico II
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Stefano Avallone <stavallo@unina.it>
7 *
8 */
9
10#include "ns3/config.h"
11#include "ns3/data-rate.h"
12#include "ns3/double.h"
13#include "ns3/log.h"
14#include "ns3/net-device-queue-interface.h"
15#include "ns3/node-container.h"
16#include "ns3/pointer.h"
17#include "ns3/queue.h"
18#include "ns3/simple-net-device-helper.h"
19#include "ns3/simulator.h"
20#include "ns3/string.h"
21#include "ns3/test.h"
22#include "ns3/traffic-control-helper.h"
23#include "ns3/traffic-control-layer.h"
24#include "ns3/uinteger.h"
25
26#include <algorithm>
27#include <string>
28
29using namespace ns3;
30
31/**
32 * @ingroup traffic-control-test
33 *
34 * @brief Queue Disc Test Item
35 */
37{
38 public:
39 /**
40 * Constructor
41 *
42 * @param p the packet stored in this item
43 */
45 ~QueueDiscTestItem() override;
46
47 // Delete default constructor, copy constructor and assignment operator to avoid misuse
51
52 void AddHeader() override;
53 bool Mark() override;
54};
55
60
64
65void
69
70bool
72{
73 return false;
74}
75
76/**
77 * @ingroup traffic-control-test
78 *
79 * @brief Traffic Control Flow Control Test Case
80 */
82{
83 public:
84 /**
85 * Constructor
86 *
87 * @param tt the test type
88 * @param deviceQueueLength the queue length of the device
89 * @param totalTxPackets the total number of packets to transmit
90 */
91 TcFlowControlTestCase(QueueSizeUnit tt, uint32_t deviceQueueLength, uint32_t totalTxPackets);
92 ~TcFlowControlTestCase() override;
93
94 private:
95 void DoRun() override;
96 /**
97 * Instruct a node to send a specified number of packets
98 * @param n the node
99 * @param nPackets the number of packets to send
100 */
101 void SendPackets(Ptr<Node> n, uint16_t nPackets);
102 /**
103 * Check if the device queue stores the expected number of packets
104 * @param dev the device
105 * @param nPackets the expected number of packets stored in the device queue
106 * @param msg the message to print if a different number of packets are stored
107 */
108 void CheckPacketsInDeviceQueue(Ptr<NetDevice> dev, uint16_t nPackets, const std::string msg);
109 /**
110 * Check if the device queue is in the expected status (stopped or not)
111 * @param dev the device
112 * @param value the expected status of the queue (true means stopped)
113 * @param msg the message to print if the status of the device queue is different
114 */
115 void CheckDeviceQueueStopped(Ptr<NetDevice> dev, bool value, const std::string msg);
116 /**
117 * Check if the queue disc stores the expected number of packets
118 * @param dev the device the queue disc is installed on
119 * @param nPackets the expected number of packets stored in the queue disc
120 * @param msg the message to print if a different number of packets are stored
121 */
122 void CheckPacketsInQueueDisc(Ptr<NetDevice> dev, uint16_t nPackets, const std::string msg);
123 QueueSizeUnit m_type; //!< the test type
124 uint32_t m_deviceQueueLength; //!< the queue length of the device
125 uint32_t m_totalTxPackets; //!< the toal number of packets to transmit
126};
127
129 uint32_t deviceQueueLength,
130 uint32_t totalTxPackets)
131 : TestCase("Test the operation of the flow control mechanism"),
132 m_type(tt),
133 m_deviceQueueLength(deviceQueueLength),
134 m_totalTxPackets(totalTxPackets)
135{
136}
137
141
142void
144{
146 for (uint16_t i = 0; i < nPackets; i++)
147 {
148 tc->Send(n->GetDevice(0), Create<QueueDiscTestItem>(Create<Packet>(1000)));
149 }
150}
151
152void
154 uint16_t nPackets,
155 const std::string msg)
156{
157 PointerValue ptr;
158 dev->GetAttributeFailSafe("TxQueue", ptr);
159 Ptr<Queue<Packet>> queue = ptr.Get<Queue<Packet>>();
160 NS_TEST_EXPECT_MSG_EQ(queue->GetNPackets(), nPackets, msg);
161}
162
163void
165 bool value,
166 const std::string msg)
167{
169 NS_ASSERT_MSG(ndqi, "A device queue interface has not been aggregated to the device");
170 NS_TEST_EXPECT_MSG_EQ(ndqi->GetTxQueue(0)->IsStopped(), value, msg);
171}
172
173void
175 uint16_t nPackets,
176 const std::string msg)
177{
178 Ptr<TrafficControlLayer> tc = dev->GetNode()->GetObject<TrafficControlLayer>();
179 Ptr<QueueDisc> qdisc = tc->GetRootQueueDiscOnDevice(dev);
180 NS_TEST_EXPECT_MSG_EQ(qdisc->GetNPackets(), nPackets, msg);
181}
182
183void
185{
187 n.Create(2);
188
191
193
194 NetDeviceContainer rxDevC = simple.Install(n.Get(1));
195
196 simple.SetDeviceAttribute("DataRate", DataRateValue(DataRate("1Mb/s")));
197 simple.SetQueue("ns3::DropTailQueue",
198 "MaxSize",
199 StringValue(m_type == QueueSizeUnit::PACKETS
200 ? std::to_string(m_deviceQueueLength) + "p"
201 : std::to_string(m_deviceQueueLength) + "B"));
202
203 Ptr<NetDevice> txDev;
204 txDev =
205 simple.Install(n.Get(0), DynamicCast<SimpleChannel>(rxDevC.Get(0)->GetChannel())).Get(0);
206 txDev->SetMtu(2500);
207
209 tch.Install(txDev);
210
211 // transmit 10 packets at time 0
214 this,
215 n.Get(0),
217
218 if (m_type == QueueSizeUnit::PACKETS)
219 {
220 /*
221 * When the device queue is in packet mode, all the packets enqueued in the
222 * queue disc are correctly transmitted, even if the device queue is stopped
223 * when the last packet is received from the upper layers
224 *
225 * We have the following invariants:
226 * - totalPackets = txPackets + deviceQueuePackets + qdiscPackets
227 * - deviceQueuePackets = MIN(totalPackets - txPackets, deviceQueueLen)
228 * - qdiscPackets = MAX(totalPackets - txPackets - deviceQueuePackets, 0)
229 *
230 * The transmission of each packet takes 1000B/1Mbps = 8ms
231 *
232 * We check the values of deviceQueuePackets and qdiscPackets 1ms after each
233 * packet is transmitted (i.e. at 1ms, 9ms, 17ms, ...), as well as verifying
234 * that the device queue is stopped or not, as appropriate.
235 */
236
237 uint32_t checkTimeMs = 0;
238 uint32_t deviceQueuePackets = 0;
239 uint32_t qdiscPackets = 0;
240
241 uint32_t txPackets = 0;
242 for (txPackets = 1; txPackets <= m_totalTxPackets; txPackets++)
243 {
244 checkTimeMs = 8 * (txPackets - 1) + 1; // Check 1ms after each packet is sent
245 deviceQueuePackets = std::min(m_totalTxPackets - txPackets, m_deviceQueueLength);
246 qdiscPackets = std::max(m_totalTxPackets - txPackets - deviceQueuePackets, (uint32_t)0);
247 if (deviceQueuePackets == m_deviceQueueLength)
248 {
251 this,
252 txDev,
253 true,
254 "The device queue must be stopped after " +
255 std::to_string(checkTimeMs) + "ms");
256 }
257 else
258 {
261 this,
262 txDev,
263 false,
264 "The device queue must not be stopped after " +
265 std::to_string(checkTimeMs) + "ms");
266 }
267
270 this,
271 txDev,
272 deviceQueuePackets,
273 "There must be " + std::to_string(m_deviceQueueLength) +
274 " packets in the device after " + std::to_string(checkTimeMs) +
275 "ms");
276
279 this,
280 txDev,
281 qdiscPackets,
282 "There must be " + std::to_string(qdiscPackets) +
283 " packets in the queue disc after " +
284 std::to_string(checkTimeMs) + "ms");
285 }
286 }
287 else
288 {
289 // TODO: Make this test parametric as well, and add new test cases
290 /*
291 * When the device queue is in byte mode, all the packets enqueued in the
292 * queue disc are correctly transmitted, even if the device queue is stopped
293 * when the last packet is received from the upper layers
294 */
295
296 // The transmission of each packet takes 1000B/1Mbps = 8ms
297 // After 1ms, we have 3 packets in the device queue (stopped) and 6 in the queue disc
300 this,
301 txDev,
302 3,
303 "There must be 3 packets in the device queue after 1ms");
306 this,
307 txDev,
308 true,
309 "The device queue must be stopped after 1ms");
312 this,
313 txDev,
314 6,
315 "There must be 6 packets in the queue disc after 1ms");
316
317 // After 9ms, we have 3 packets in the device queue (stopped) and 5 in the queue disc
320 this,
321 txDev,
322 3,
323 "There must be 3 packets in the device queue after 9ms");
326 this,
327 txDev,
328 true,
329 "The device queue must be stopped after 9ms");
332 this,
333 txDev,
334 5,
335 "There must be 5 packets in the queue disc after 9ms");
336
337 // After 17ms, we have 3 packets in the device queue (stopped) and 4 in the queue disc
340 this,
341 txDev,
342 3,
343 "There must be 3 packets in the device queue after 17ms");
346 this,
347 txDev,
348 true,
349 "The device queue must be stopped after 17ms");
352 this,
353 txDev,
354 4,
355 "There must be 4 packets in the queue disc after 17ms");
356
357 // After 25ms, we have 3 packets in the device queue (stopped) and 3 in the queue disc
360 this,
361 txDev,
362 3,
363 "There must be 3 packets in the device queue after 25ms");
366 this,
367 txDev,
368 true,
369 "The device queue must be stopped after 25ms");
372 this,
373 txDev,
374 3,
375 "There must be 3 packets in the queue disc after 25ms");
376
377 // After 33ms, we have 3 packets in the device queue (stopped) and 2 in the queue disc
380 this,
381 txDev,
382 3,
383 "There must be 3 packets in the device queue after 33ms");
386 this,
387 txDev,
388 true,
389 "The device queue must be stopped after 33ms");
392 this,
393 txDev,
394 2,
395 "There must be 2 packets in the queue disc after 33ms");
396
397 // After 41ms, we have 3 packets in the device queue (stopped) and 1 in the queue disc
400 this,
401 txDev,
402 3,
403 "There must be 3 packets in the device queue after 41ms");
406 this,
407 txDev,
408 true,
409 "The device queue must be stopped after 41ms");
412 this,
413 txDev,
414 1,
415 "There must be 1 packet in the queue disc after 41ms");
416
417 // After 49ms, we have 3 packets in the device queue (stopped) and the queue disc is empty
420 this,
421 txDev,
422 3,
423 "There must be 3 packets in the device queue after 49ms");
426 this,
427 txDev,
428 true,
429 "The device queue must be stopped after 49ms");
432 this,
433 txDev,
434 0,
435 "The queue disc must be empty after 49ms");
436
437 // After 57ms, we have 2 packets in the device queue (not stopped) and the queue disc is
438 // empty
441 this,
442 txDev,
443 2,
444 "There must be 2 packets in the device queue after 57ms");
447 this,
448 txDev,
449 false,
450 "The device queue must not be stopped after 57ms");
453 this,
454 txDev,
455 0,
456 "The queue disc must be empty after 57ms");
457
458 // After 81ms, all packets must have been transmitted (the device queue and the queue disc
459 // are empty)
462 this,
463 txDev,
464 0,
465 "The device queue must be empty after 81ms");
468 this,
469 txDev,
470 false,
471 "The device queue must not be stopped after 81ms");
474 this,
475 txDev,
476 0,
477 "The queue disc must be empty after 81ms");
478 }
479
482}
483
484/**
485 * @ingroup traffic-control-test
486 *
487 * @brief Traffic Control Flow Control Test Suite
488 */
490{
491 public:
493 : TestSuite("tc-flow-control", Type::UNIT)
494 {
495 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 1, 10),
496 TestCase::Duration::QUICK);
497 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 5, 10),
498 TestCase::Duration::QUICK);
499 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 9, 10),
500 TestCase::Duration::QUICK);
501 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 10, 10),
502 TestCase::Duration::QUICK);
503 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 11, 10),
504 TestCase::Duration::QUICK);
505 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 15, 10),
506 TestCase::Duration::QUICK);
507 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 1, 1),
508 TestCase::Duration::QUICK);
509 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 2, 1),
510 TestCase::Duration::QUICK);
511 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 5, 1),
512 TestCase::Duration::QUICK);
513
514 // TODO: Right now, this test only works for 5000B and 10 packets (it's hard coded). Should
515 // also be made parametric.
516 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::BYTES, 5000, 10),
517 TestCase::Duration::QUICK);
518 }
519} g_tcFlowControlTestSuite; ///< the test suite
bool Mark() override
Marks the packet as a substitute for dropping it, such as for Explicit Congestion Notification.
QueueDiscTestItem(const QueueDiscTestItem &)=delete
QueueDiscTestItem()=delete
QueueDiscTestItem & operator=(const QueueDiscTestItem &)=delete
void AddHeader() override
Add the header to the packet.
Traffic Control Flow Control Test Case.
uint32_t m_deviceQueueLength
the queue length of the device
void CheckPacketsInQueueDisc(Ptr< NetDevice > dev, uint16_t nPackets, const std::string msg)
Check if the queue disc stores the expected number of packets.
void DoRun() override
Implementation to actually run this TestCase.
void SendPackets(Ptr< Node > n, uint16_t nPackets)
Instruct a node to send a specified number of packets.
TcFlowControlTestCase(QueueSizeUnit tt, uint32_t deviceQueueLength, uint32_t totalTxPackets)
Constructor.
void CheckDeviceQueueStopped(Ptr< NetDevice > dev, bool value, const std::string msg)
Check if the device queue is in the expected status (stopped or not)
QueueSizeUnit m_type
the test type
void CheckPacketsInDeviceQueue(Ptr< NetDevice > dev, uint16_t nPackets, const std::string msg)
Check if the device queue stores the expected number of packets.
uint32_t m_totalTxPackets
the toal number of packets to transmit
Traffic Control Flow Control Test Suite.
Class for representing data rates.
Definition data-rate.h:78
AttributeValue implementation for DataRate.
Definition data-rate.h:285
an EUI-48 address
holds a vector of ns3::NetDevice pointers
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr<NetDevice> stored in this container at a given index.
Network device transmission queue interface.
keep track of a set of node pointers.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition object.cc:298
AttributeValue implementation for Pointer.
Ptr< T > Get() const
Definition pointer.h:223
Smart pointer class similar to boost::intrusive_ptr.
QueueDiscItem is the abstract base class for items that are stored in a queue disc.
Definition queue-item.h:122
Template class for packet Queues.
Definition queue.h:257
build a set of SimpleNetDevice objects
void SetQueue(std::string type, Ts &&... args)
Each net device must have a queue to pass packets through.
void SetDeviceAttribute(std::string n1, const AttributeValue &v1)
NetDeviceContainer Install(Ptr< Node > node) const
This method creates an ns3::SimpleChannel with the attributes configured by SimpleNetDeviceHelper::Se...
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static void Run()
Run the simulation.
Definition simulator.cc:167
Hold variables of type string.
Definition string.h:45
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
static constexpr auto UNIT
Definition test.h:1291
Build a set of QueueDisc objects.
QueueDiscContainer Install(NetDeviceContainer c)
static TrafficControlHelper Default(std::size_t nTxQueues=1)
The Traffic Control layer aims at introducing an equivalent of the Linux Traffic Control infrastructu...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
QueueSizeUnit
Enumeration of the operating modes of queues.
Definition queue-size.h:33
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition test.h:241
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1356
TcFlowControlTestSuite g_tcFlowControlTestSuite
the test suite
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580