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 * 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: Stefano Avallone <stavallo@unina.it>
18 *
19 */
20
21#include "ns3/config.h"
22#include "ns3/data-rate.h"
23#include "ns3/double.h"
24#include "ns3/log.h"
25#include "ns3/net-device-queue-interface.h"
26#include "ns3/node-container.h"
27#include "ns3/pointer.h"
28#include "ns3/queue.h"
29#include "ns3/simple-net-device-helper.h"
30#include "ns3/simulator.h"
31#include "ns3/string.h"
32#include "ns3/test.h"
33#include "ns3/traffic-control-helper.h"
34#include "ns3/traffic-control-layer.h"
35#include "ns3/uinteger.h"
36
37#include <algorithm>
38#include <string>
39
40using namespace ns3;
41
48{
49 public:
56 ~QueueDiscTestItem() override;
57
58 // Delete default constructor, copy constructor and assignment operator to avoid misuse
62
63 void AddHeader() override;
64 bool Mark() override;
65};
66
69{
70}
71
73{
74}
75
76void
78{
79}
80
81bool
83{
84 return false;
85}
86
93{
94 public:
102 TcFlowControlTestCase(QueueSizeUnit tt, uint32_t deviceQueueLength, uint32_t totalTxPackets);
103 ~TcFlowControlTestCase() override;
104
105 private:
106 void DoRun() override;
112 void SendPackets(Ptr<Node> n, uint16_t nPackets);
119 void CheckPacketsInDeviceQueue(Ptr<NetDevice> dev, uint16_t nPackets, const std::string msg);
126 void CheckDeviceQueueStopped(Ptr<NetDevice> dev, bool value, const std::string msg);
133 void CheckPacketsInQueueDisc(Ptr<NetDevice> dev, uint16_t nPackets, const std::string msg);
137};
138
140 uint32_t deviceQueueLength,
141 uint32_t totalTxPackets)
142 : TestCase("Test the operation of the flow control mechanism"),
143 m_type(tt),
144 m_deviceQueueLength(deviceQueueLength),
145 m_totalTxPackets(totalTxPackets)
146{
147}
148
150{
151}
152
153void
155{
157 for (uint16_t i = 0; i < nPackets; i++)
158 {
159 tc->Send(n->GetDevice(0), Create<QueueDiscTestItem>(Create<Packet>(1000)));
160 }
161}
162
163void
165 uint16_t nPackets,
166 const std::string msg)
167{
168 PointerValue ptr;
169 dev->GetAttributeFailSafe("TxQueue", ptr);
170 Ptr<Queue<Packet>> queue = ptr.Get<Queue<Packet>>();
171 NS_TEST_EXPECT_MSG_EQ(queue->GetNPackets(), nPackets, msg);
172}
173
174void
176 bool value,
177 const std::string msg)
178{
180 NS_ASSERT_MSG(ndqi, "A device queue interface has not been aggregated to the device");
181 NS_TEST_EXPECT_MSG_EQ(ndqi->GetTxQueue(0)->IsStopped(), value, msg);
182}
183
184void
186 uint16_t nPackets,
187 const std::string msg)
188{
189 Ptr<TrafficControlLayer> tc = dev->GetNode()->GetObject<TrafficControlLayer>();
190 Ptr<QueueDisc> qdisc = tc->GetRootQueueDiscOnDevice(dev);
191 NS_TEST_EXPECT_MSG_EQ(qdisc->GetNPackets(), nPackets, msg);
192}
193
194void
196{
198 n.Create(2);
199
200 n.Get(0)->AggregateObject(CreateObject<TrafficControlLayer>());
201 n.Get(1)->AggregateObject(CreateObject<TrafficControlLayer>());
202
204
205 NetDeviceContainer rxDevC = simple.Install(n.Get(1));
206
207 simple.SetDeviceAttribute("DataRate", DataRateValue(DataRate("1Mb/s")));
208 simple.SetQueue("ns3::DropTailQueue",
209 "MaxSize",
210 StringValue(m_type == QueueSizeUnit::PACKETS
211 ? std::to_string(m_deviceQueueLength) + "p"
212 : std::to_string(m_deviceQueueLength) + "B"));
213
214 Ptr<NetDevice> txDev;
215 txDev =
216 simple.Install(n.Get(0), DynamicCast<SimpleChannel>(rxDevC.Get(0)->GetChannel())).Get(0);
217 txDev->SetMtu(2500);
218
220 tch.Install(txDev);
221
222 // transmit 10 packets at time 0
225 this,
226 n.Get(0),
228
229 if (m_type == QueueSizeUnit::PACKETS)
230 {
231 /*
232 * When the device queue is in packet mode, all the packets enqueued in the
233 * queue disc are correctly transmitted, even if the device queue is stopped
234 * when the last packet is received from the upper layers
235 *
236 * We have the following invariants:
237 * - totalPackets = txPackets + deviceQueuePackets + qdiscPackets
238 * - deviceQueuePackets = MIN(totalPackets - txPackets, deviceQueueLen)
239 * - qdiscPackets = MAX(totalPackets - txPackets - deviceQueuePackets, 0)
240 *
241 * The transmission of each packet takes 1000B/1Mbps = 8ms
242 *
243 * We check the values of deviceQueuePackets and qdiscPackets 1ms after each
244 * packet is transmitted (i.e. at 1ms, 9ms, 17ms, ...), as well as verifying
245 * that the device queue is stopped or not, as appropriate.
246 */
247
248 uint32_t checkTimeMs = 0;
249 uint32_t deviceQueuePackets = 0;
250 uint32_t qdiscPackets = 0;
251
252 uint32_t txPackets = 0;
253 for (txPackets = 1; txPackets <= m_totalTxPackets; txPackets++)
254 {
255 checkTimeMs = 8 * (txPackets - 1) + 1; // Check 1ms after each packet is sent
256 deviceQueuePackets = std::min(m_totalTxPackets - txPackets, m_deviceQueueLength);
257 qdiscPackets = std::max(m_totalTxPackets - txPackets - deviceQueuePackets, (uint32_t)0);
258 if (deviceQueuePackets == m_deviceQueueLength)
259 {
262 this,
263 txDev,
264 true,
265 "The device queue must be stopped after " +
266 std::to_string(checkTimeMs) + "ms");
267 }
268 else
269 {
272 this,
273 txDev,
274 false,
275 "The device queue must not be stopped after " +
276 std::to_string(checkTimeMs) + "ms");
277 }
278
281 this,
282 txDev,
283 deviceQueuePackets,
284 "There must be " + std::to_string(m_deviceQueueLength) +
285 " packets in the device after " + std::to_string(checkTimeMs) +
286 "ms");
287
290 this,
291 txDev,
292 qdiscPackets,
293 "There must be " + std::to_string(qdiscPackets) +
294 " packets in the queue disc after " +
295 std::to_string(checkTimeMs) + "ms");
296 }
297 }
298 else
299 {
300 // TODO: Make this test parametric as well, and add new test cases
301 /*
302 * When the device queue is in byte mode, all the packets enqueued in the
303 * queue disc are correctly transmitted, even if the device queue is stopped
304 * when the last packet is received from the upper layers
305 */
306
307 // The transmission of each packet takes 1000B/1Mbps = 8ms
308 // After 1ms, we have 3 packets in the device queue (stopped) and 6 in the queue disc
311 this,
312 txDev,
313 3,
314 "There must be 3 packets in the device queue after 1ms");
317 this,
318 txDev,
319 true,
320 "The device queue must be stopped after 1ms");
323 this,
324 txDev,
325 6,
326 "There must be 6 packets in the queue disc after 1ms");
327
328 // After 9ms, we have 3 packets in the device queue (stopped) and 5 in the queue disc
331 this,
332 txDev,
333 3,
334 "There must be 3 packets in the device queue after 9ms");
337 this,
338 txDev,
339 true,
340 "The device queue must be stopped after 9ms");
343 this,
344 txDev,
345 5,
346 "There must be 5 packets in the queue disc after 9ms");
347
348 // After 17ms, we have 3 packets in the device queue (stopped) and 4 in the queue disc
351 this,
352 txDev,
353 3,
354 "There must be 3 packets in the device queue after 17ms");
357 this,
358 txDev,
359 true,
360 "The device queue must be stopped after 17ms");
363 this,
364 txDev,
365 4,
366 "There must be 4 packets in the queue disc after 17ms");
367
368 // After 25ms, we have 3 packets in the device queue (stopped) and 3 in the queue disc
371 this,
372 txDev,
373 3,
374 "There must be 3 packets in the device queue after 25ms");
377 this,
378 txDev,
379 true,
380 "The device queue must be stopped after 25ms");
383 this,
384 txDev,
385 3,
386 "There must be 3 packets in the queue disc after 25ms");
387
388 // After 33ms, we have 3 packets in the device queue (stopped) and 2 in the queue disc
391 this,
392 txDev,
393 3,
394 "There must be 3 packets in the device queue after 33ms");
397 this,
398 txDev,
399 true,
400 "The device queue must be stopped after 33ms");
403 this,
404 txDev,
405 2,
406 "There must be 2 packets in the queue disc after 33ms");
407
408 // After 41ms, we have 3 packets in the device queue (stopped) and 1 in the queue disc
411 this,
412 txDev,
413 3,
414 "There must be 3 packets in the device queue after 41ms");
417 this,
418 txDev,
419 true,
420 "The device queue must be stopped after 41ms");
423 this,
424 txDev,
425 1,
426 "There must be 1 packet in the queue disc after 41ms");
427
428 // After 49ms, we have 3 packets in the device queue (stopped) and the queue disc is empty
431 this,
432 txDev,
433 3,
434 "There must be 3 packets in the device queue after 49ms");
437 this,
438 txDev,
439 true,
440 "The device queue must be stopped after 49ms");
443 this,
444 txDev,
445 0,
446 "The queue disc must be empty after 49ms");
447
448 // After 57ms, we have 2 packets in the device queue (not stopped) and the queue disc is
449 // empty
452 this,
453 txDev,
454 2,
455 "There must be 2 packets in the device queue after 57ms");
458 this,
459 txDev,
460 false,
461 "The device queue must not be stopped after 57ms");
464 this,
465 txDev,
466 0,
467 "The queue disc must be empty after 57ms");
468
469 // After 81ms, all packets must have been transmitted (the device queue and the queue disc
470 // are empty)
473 this,
474 txDev,
475 0,
476 "The device queue must be empty after 81ms");
479 this,
480 txDev,
481 false,
482 "The device queue must not be stopped after 81ms");
485 this,
486 txDev,
487 0,
488 "The queue disc must be empty after 81ms");
489 }
490
493}
494
501{
502 public:
504 : TestSuite("tc-flow-control", UNIT)
505 {
506 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 1, 10), TestCase::QUICK);
507 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 5, 10), TestCase::QUICK);
508 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 9, 10), TestCase::QUICK);
509 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 10, 10), TestCase::QUICK);
510 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 11, 10), TestCase::QUICK);
511 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 15, 10), TestCase::QUICK);
512 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 1, 1), TestCase::QUICK);
513 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 2, 1), TestCase::QUICK);
514 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 5, 1), TestCase::QUICK);
515
516 // TODO: Right now, this test only works for 5000B and 10 packets (it's hard coded). Should
517 // also be made parametric.
518 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::BYTES, 5000, 10), TestCase::QUICK);
519 }
Queue Disc Test Item.
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:89
AttributeValue implementation for DataRate.
an EUI-48 address
Definition: mac48-address.h:46
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:259
Hold objects of type Ptr<T>.
Definition: pointer.h:37
Ptr< T > Get() const
Definition: pointer.h:202
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
QueueDiscItem is the abstract base class for items that are stored in a queue disc.
Definition: queue-item.h:133
Template class for packet Queues.
Definition: queue.h:267
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:568
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:140
static void Run()
Run the simulation.
Definition: simulator.cc:176
Hold variables of type string.
Definition: string.h:56
encapsulates test code
Definition: test.h:1060
@ QUICK
Fast test.
Definition: test.h:1065
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
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:86
QueueSizeUnit
Enumeration of the operating modes of queues.
Definition: queue-size.h:44
#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:251
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1348
TcFlowControlTestSuite g_tcFlowControlTestSuite
the test suite
Every class exported by the ns3 library is enclosed in the ns3 namespace.