A Discrete-Event Network Simulator
API
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
49{
50 public:
57 ~QueueDiscTestItem() override;
58
59 // Delete default constructor, copy constructor and assignment operator to avoid misuse
63
64 void AddHeader() override;
65 bool Mark() override;
66};
67
70{
71}
72
74{
75}
76
77void
79{
80}
81
82bool
84{
85 return false;
86}
87
95{
96 public:
104 TcFlowControlTestCase(QueueSizeUnit tt, uint32_t deviceQueueLength, uint32_t totalTxPackets);
105 ~TcFlowControlTestCase() override;
106
107 private:
108 void DoRun() override;
114 void SendPackets(Ptr<Node> n, uint16_t nPackets);
121 void CheckPacketsInDeviceQueue(Ptr<NetDevice> dev, uint16_t nPackets, const std::string msg);
128 void CheckDeviceQueueStopped(Ptr<NetDevice> dev, bool value, const std::string msg);
135 void CheckPacketsInQueueDisc(Ptr<NetDevice> dev, uint16_t nPackets, const std::string msg);
139};
140
142 uint32_t deviceQueueLength,
143 uint32_t totalTxPackets)
144 : TestCase("Test the operation of the flow control mechanism"),
145 m_type(tt),
146 m_deviceQueueLength(deviceQueueLength),
147 m_totalTxPackets(totalTxPackets)
148{
149}
150
152{
153}
154
155void
157{
159 for (uint16_t i = 0; i < nPackets; i++)
160 {
161 tc->Send(n->GetDevice(0), Create<QueueDiscTestItem>(Create<Packet>(1000)));
162 }
163}
164
165void
167 uint16_t nPackets,
168 const std::string msg)
169{
170 PointerValue ptr;
171 dev->GetAttributeFailSafe("TxQueue", ptr);
172 Ptr<Queue<Packet>> queue = ptr.Get<Queue<Packet>>();
173 NS_TEST_EXPECT_MSG_EQ(queue->GetNPackets(), nPackets, msg);
174}
175
176void
178 bool value,
179 const std::string msg)
180{
182 NS_ASSERT_MSG(ndqi, "A device queue interface has not been aggregated to the device");
183 NS_TEST_EXPECT_MSG_EQ(ndqi->GetTxQueue(0)->IsStopped(), value, msg);
184}
185
186void
188 uint16_t nPackets,
189 const std::string msg)
190{
191 Ptr<TrafficControlLayer> tc = dev->GetNode()->GetObject<TrafficControlLayer>();
192 Ptr<QueueDisc> qdisc = tc->GetRootQueueDiscOnDevice(dev);
193 NS_TEST_EXPECT_MSG_EQ(qdisc->GetNPackets(), nPackets, msg);
194}
195
196void
198{
200 n.Create(2);
201
202 n.Get(0)->AggregateObject(CreateObject<TrafficControlLayer>());
203 n.Get(1)->AggregateObject(CreateObject<TrafficControlLayer>());
204
206
207 NetDeviceContainer rxDevC = simple.Install(n.Get(1));
208
209 simple.SetDeviceAttribute("DataRate", DataRateValue(DataRate("1Mb/s")));
210 simple.SetQueue("ns3::DropTailQueue",
211 "MaxSize",
213 ? std::to_string(m_deviceQueueLength) + "p"
214 : std::to_string(m_deviceQueueLength) + "B"));
215
216 Ptr<NetDevice> txDev;
217 txDev =
218 simple.Install(n.Get(0), DynamicCast<SimpleChannel>(rxDevC.Get(0)->GetChannel())).Get(0);
219 txDev->SetMtu(2500);
220
221 TrafficControlHelper tch = TrafficControlHelper::Default();
222 tch.Install(txDev);
223
224 // transmit 10 packets at time 0
225 Simulator::Schedule(Time(Seconds(0)),
227 this,
228 n.Get(0),
230
232 {
233 /*
234 * When the device queue is in packet mode, all the packets enqueued in the
235 * queue disc are correctly transmitted, even if the device queue is stopped
236 * when the last packet is received from the upper layers
237 *
238 * We have the following invariants:
239 * - totalPackets = txPackets + deviceQueuePackets + qdiscPackets
240 * - deviceQueuePackets = MIN(totalPackets - txPackets, deviceQueueLen)
241 * - qdiscPackets = MAX(totalPackets - txPackets - deviceQueuePackets, 0)
242 *
243 * The transmission of each packet takes 1000B/1Mbps = 8ms
244 *
245 * We check the values of deviceQueuePackets and qdiscPackets 1ms after each
246 * packet is transmitted (i.e. at 1ms, 9ms, 17ms, ...), as well as verifying
247 * that the device queue is stopped or not, as appropriate.
248 */
249
250 uint32_t checkTimeMs = 0;
251 uint32_t deviceQueuePackets = 0;
252 uint32_t qdiscPackets = 0;
253
254 uint32_t txPackets = 0;
255 for (txPackets = 1; txPackets <= m_totalTxPackets; txPackets++)
256 {
257 checkTimeMs = 8 * (txPackets - 1) + 1; // Check 1ms after each packet is sent
258 deviceQueuePackets = std::min(m_totalTxPackets - txPackets, m_deviceQueueLength);
259 qdiscPackets = std::max(m_totalTxPackets - txPackets - deviceQueuePackets, (uint32_t)0);
260 if (deviceQueuePackets == m_deviceQueueLength)
261 {
262 Simulator::Schedule(Time(MilliSeconds(checkTimeMs)),
264 this,
265 txDev,
266 true,
267 "The device queue must be stopped after " +
268 std::to_string(checkTimeMs) + "ms");
269 }
270 else
271 {
272 Simulator::Schedule(Time(MilliSeconds(checkTimeMs)),
274 this,
275 txDev,
276 false,
277 "The device queue must not be stopped after " +
278 std::to_string(checkTimeMs) + "ms");
279 }
280
281 Simulator::Schedule(Time(MilliSeconds(checkTimeMs)),
283 this,
284 txDev,
285 deviceQueuePackets,
286 "There must be " + std::to_string(m_deviceQueueLength) +
287 " packets in the device after " + std::to_string(checkTimeMs) +
288 "ms");
289
290 Simulator::Schedule(Time(MilliSeconds(checkTimeMs)),
292 this,
293 txDev,
294 qdiscPackets,
295 "There must be " + std::to_string(qdiscPackets) +
296 " packets in the queue disc after " +
297 std::to_string(checkTimeMs) + "ms");
298 }
299 }
300 else
301 {
302 // TODO: Make this test parametric as well, and add new test cases
303 /*
304 * When the device queue is in byte mode, all the packets enqueued in the
305 * queue disc are correctly transmitted, even if the device queue is stopped
306 * when the last packet is received from the upper layers
307 */
308
309 // The transmission of each packet takes 1000B/1Mbps = 8ms
310 // After 1ms, we have 3 packets in the device queue (stopped) and 6 in the queue disc
311 Simulator::Schedule(Time(MilliSeconds(1)),
313 this,
314 txDev,
315 3,
316 "There must be 3 packets in the device queue after 1ms");
317 Simulator::Schedule(Time(MilliSeconds(1)),
319 this,
320 txDev,
321 true,
322 "The device queue must be stopped after 1ms");
323 Simulator::Schedule(Time(MilliSeconds(1)),
325 this,
326 txDev,
327 6,
328 "There must be 6 packets in the queue disc after 1ms");
329
330 // After 9ms, we have 3 packets in the device queue (stopped) and 5 in the queue disc
331 Simulator::Schedule(Time(MilliSeconds(9)),
333 this,
334 txDev,
335 3,
336 "There must be 3 packets in the device queue after 9ms");
337 Simulator::Schedule(Time(MilliSeconds(9)),
339 this,
340 txDev,
341 true,
342 "The device queue must be stopped after 9ms");
343 Simulator::Schedule(Time(MilliSeconds(9)),
345 this,
346 txDev,
347 5,
348 "There must be 5 packets in the queue disc after 9ms");
349
350 // After 17ms, we have 3 packets in the device queue (stopped) and 4 in the queue disc
351 Simulator::Schedule(Time(MilliSeconds(17)),
353 this,
354 txDev,
355 3,
356 "There must be 3 packets in the device queue after 17ms");
357 Simulator::Schedule(Time(MilliSeconds(17)),
359 this,
360 txDev,
361 true,
362 "The device queue must be stopped after 17ms");
363 Simulator::Schedule(Time(MilliSeconds(17)),
365 this,
366 txDev,
367 4,
368 "There must be 4 packets in the queue disc after 17ms");
369
370 // After 25ms, we have 3 packets in the device queue (stopped) and 3 in the queue disc
371 Simulator::Schedule(Time(MilliSeconds(25)),
373 this,
374 txDev,
375 3,
376 "There must be 3 packets in the device queue after 25ms");
377 Simulator::Schedule(Time(MilliSeconds(25)),
379 this,
380 txDev,
381 true,
382 "The device queue must be stopped after 25ms");
383 Simulator::Schedule(Time(MilliSeconds(25)),
385 this,
386 txDev,
387 3,
388 "There must be 3 packets in the queue disc after 25ms");
389
390 // After 33ms, we have 3 packets in the device queue (stopped) and 2 in the queue disc
391 Simulator::Schedule(Time(MilliSeconds(33)),
393 this,
394 txDev,
395 3,
396 "There must be 3 packets in the device queue after 33ms");
397 Simulator::Schedule(Time(MilliSeconds(33)),
399 this,
400 txDev,
401 true,
402 "The device queue must be stopped after 33ms");
403 Simulator::Schedule(Time(MilliSeconds(33)),
405 this,
406 txDev,
407 2,
408 "There must be 2 packets in the queue disc after 33ms");
409
410 // After 41ms, we have 3 packets in the device queue (stopped) and 1 in the queue disc
411 Simulator::Schedule(Time(MilliSeconds(41)),
413 this,
414 txDev,
415 3,
416 "There must be 3 packets in the device queue after 41ms");
417 Simulator::Schedule(Time(MilliSeconds(41)),
419 this,
420 txDev,
421 true,
422 "The device queue must be stopped after 41ms");
423 Simulator::Schedule(Time(MilliSeconds(41)),
425 this,
426 txDev,
427 1,
428 "There must be 1 packet in the queue disc after 41ms");
429
430 // After 49ms, we have 3 packets in the device queue (stopped) and the queue disc is empty
431 Simulator::Schedule(Time(MilliSeconds(49)),
433 this,
434 txDev,
435 3,
436 "There must be 3 packets in the device queue after 49ms");
437 Simulator::Schedule(Time(MilliSeconds(49)),
439 this,
440 txDev,
441 true,
442 "The device queue must be stopped after 49ms");
443 Simulator::Schedule(Time(MilliSeconds(49)),
445 this,
446 txDev,
447 0,
448 "The queue disc must be empty after 49ms");
449
450 // After 57ms, we have 2 packets in the device queue (not stopped) and the queue disc is
451 // empty
452 Simulator::Schedule(Time(MilliSeconds(57)),
454 this,
455 txDev,
456 2,
457 "There must be 2 packets in the device queue after 57ms");
458 Simulator::Schedule(Time(MilliSeconds(57)),
460 this,
461 txDev,
462 false,
463 "The device queue must not be stopped after 57ms");
464 Simulator::Schedule(Time(MilliSeconds(57)),
466 this,
467 txDev,
468 0,
469 "The queue disc must be empty after 57ms");
470
471 // After 81ms, all packets must have been transmitted (the device queue and the queue disc
472 // are empty)
473 Simulator::Schedule(Time(MilliSeconds(81)),
475 this,
476 txDev,
477 0,
478 "The device queue must be empty after 81ms");
479 Simulator::Schedule(Time(MilliSeconds(81)),
481 this,
482 txDev,
483 false,
484 "The device queue must not be stopped after 81ms");
485 Simulator::Schedule(Time(MilliSeconds(81)),
487 this,
488 txDev,
489 0,
490 "The queue disc must be empty after 81ms");
491 }
492
493 Simulator::Run();
494 Simulator::Destroy();
495}
496
504{
505 public:
507 : TestSuite("tc-flow-control", UNIT)
508 {
509 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 1, 10), TestCase::QUICK);
510 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 5, 10), TestCase::QUICK);
511 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 9, 10), TestCase::QUICK);
512 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 10, 10), TestCase::QUICK);
513 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 11, 10), TestCase::QUICK);
514 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 15, 10), TestCase::QUICK);
515 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 1, 1), TestCase::QUICK);
516 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 2, 1), TestCase::QUICK);
517 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 5, 1), TestCase::QUICK);
518
519 // TODO: Right now, this test only works for 5000B and 10 packets (it's hard coded). Should
520 // also be made parametric.
521 AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::BYTES, 5000, 10), TestCase::QUICK);
522 }
#define min(a, b)
Definition: 80211b.c:42
#define max(a, b)
Definition: 80211b.c:43
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.
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.
Ptr< NetDevice > GetDevice(uint32_t index) const
Retrieve the index-th NetDevice associated to this node.
Definition: node.cc:152
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition: object.h:471
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:205
QueueDiscItem is the abstract base class for items that are stored in a queue disc.
Definition: queue-item.h:133
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...
Hold variables of type string.
Definition: string.h:42
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:305
A suite of tests to run.
Definition: test.h:1256
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1265
Build a set of QueueDisc objects.
QueueDiscContainer Install(NetDeviceContainer c)
Introspection did not find any typical Config paths.
#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
void(* DataRate)(DataRate oldValue, DataRate newValue)
TracedValue callback signature for DataRate.
Definition: data-rate.h:328
QueueSizeUnit
Enumeration of the operating modes of queues.
Definition: queue-size.h:44
@ BYTES
Use number of bytes for queue size.
Definition: queue-size.h:46
@ PACKETS
Use number of packets for queue size.
Definition: queue-size.h:45
#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
TcFlowControlTestSuite g_tcFlowControlTestSuite
the test suite
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:850
Every class exported by the ns3 library is enclosed in the ns3 namespace.
value
Definition: second.py:41