A Discrete-Event Network Simulator
API
tc-flow-control-test-suite.cc
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2017 Universita' degli Studi di Napoli Federico II
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Stefano Avallone <stavallo@unina.it>
19 *
20 */
21
22#include <algorithm>
23#include <string>
24
25#include "ns3/test.h"
26#include "ns3/uinteger.h"
27#include "ns3/pointer.h"
28#include "ns3/string.h"
29#include "ns3/double.h"
30#include "ns3/log.h"
31#include "ns3/simulator.h"
32#include "ns3/node-container.h"
33#include "ns3/traffic-control-layer.h"
34#include "ns3/traffic-control-helper.h"
35#include "ns3/simple-net-device-helper.h"
36#include "ns3/data-rate.h"
37#include "ns3/net-device-queue-interface.h"
38#include "ns3/queue.h"
39#include "ns3/config.h"
40
41using namespace ns3;
42
50public:
57 virtual ~QueueDiscTestItem ();
58
59 // Delete copy constructor and assignment operator to avoid misuse
62
63 virtual void AddHeader (void);
64 virtual bool Mark(void);
65
66private:
68};
69
71 : QueueDiscItem (p, Mac48Address (), 0)
72{
73}
74
76{
77}
78
79void
81{
82}
83
84bool
86{
87 return false;
88}
89
97{
98public:
106 TcFlowControlTestCase (QueueSizeUnit tt, uint32_t deviceQueueLength, uint32_t totalTxPackets);
107 virtual ~TcFlowControlTestCase ();
108private:
109 virtual void DoRun (void);
115 void SendPackets (Ptr<Node> n, uint16_t nPackets);
122 void CheckPacketsInDeviceQueue (Ptr<NetDevice> dev, uint16_t nPackets, const std::string msg);
129 void CheckDeviceQueueStopped (Ptr<NetDevice> dev, bool value, const std::string msg);
136 void CheckPacketsInQueueDisc (Ptr<NetDevice> dev, uint16_t nPackets, const std::string msg);
140};
141
143 : TestCase ("Test the operation of the flow control mechanism"),
144 m_type (tt), m_deviceQueueLength(deviceQueueLength), m_totalTxPackets(totalTxPackets)
145{
146}
147
149{
150}
151
152void
154{
156 for (uint16_t i = 0; i < nPackets; i++)
157 {
158 tc->Send (n->GetDevice (0), Create<QueueDiscTestItem> (Create<Packet> (1000)));
159 }
160}
161
162void
163TcFlowControlTestCase::CheckPacketsInDeviceQueue (Ptr<NetDevice> dev, uint16_t nPackets, const std::string msg)
164{
165 PointerValue ptr;
166 dev->GetAttributeFailSafe ("TxQueue", ptr);
167 Ptr<Queue<Packet> > queue = ptr.Get<Queue<Packet> > ();
168 NS_TEST_EXPECT_MSG_EQ (queue->GetNPackets (), nPackets, msg);
169}
170
171void
173{
175 NS_ASSERT_MSG (ndqi, "A device queue interface has not been aggregated to the device");
176 NS_TEST_EXPECT_MSG_EQ (ndqi->GetTxQueue (0)->IsStopped (), value, msg);
177}
178
179void
180TcFlowControlTestCase::CheckPacketsInQueueDisc (Ptr<NetDevice> dev, uint16_t nPackets, const std::string msg)
181{
183 Ptr<QueueDisc> qdisc = tc->GetRootQueueDiscOnDevice (dev);
184 NS_TEST_EXPECT_MSG_EQ (qdisc->GetNPackets (), nPackets, msg);
185}
186
187
188void
190{
192 n.Create (2);
193
194 n.Get (0)->AggregateObject (CreateObject<TrafficControlLayer> ());
195 n.Get (1)->AggregateObject (CreateObject<TrafficControlLayer> ());
196
198
199 NetDeviceContainer rxDevC = simple.Install (n.Get (1));
200
201 simple.SetDeviceAttribute ("DataRate", DataRateValue (DataRate ("1Mb/s")));
202 simple.SetQueue ("ns3::DropTailQueue", "MaxSize",
204 ? std::to_string (m_deviceQueueLength) + "p"
205 : std::to_string (m_deviceQueueLength) + "B"));
206
207 Ptr<NetDevice> txDev;
208 txDev = simple.Install (n.Get (0), DynamicCast<SimpleChannel> (rxDevC.Get (0)->GetChannel ())).Get (0);
209 txDev->SetMtu (2500);
210
211 TrafficControlHelper tch = TrafficControlHelper::Default ();
212 tch.Install (txDev);
213
214 // transmit 10 packets at time 0
215 Simulator::Schedule (Time (Seconds (0)), &TcFlowControlTestCase::SendPackets,
216 this, n.Get (0), m_totalTxPackets);
217
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 {
249 Simulator::Schedule (
250 Time (MilliSeconds (checkTimeMs)),
252 "The device queue must be stopped after " + std::to_string (checkTimeMs) + "ms");
253 }
254 else
255 {
256 Simulator::Schedule (Time (MilliSeconds (checkTimeMs)),
258 false,
259 "The device queue must not be stopped after " +
260 std::to_string (checkTimeMs) + "ms");
261 }
262
263 Simulator::Schedule (
265 this, txDev, deviceQueuePackets,
266 "There must be " + std::to_string (m_deviceQueueLength) + " packets in the device after " +
267 std::to_string (checkTimeMs) + "ms");
268
269 Simulator::Schedule (
271 this, txDev, qdiscPackets,
272 "There must be " + std::to_string (qdiscPackets) +
273 " packets in the queue disc after " + std::to_string (checkTimeMs) + "ms");
274 }
275 }
276 else
277 {
278 // TODO: Make this test parametric as well, and add new test cases
279 /*
280 * When the device queue is in byte mode, all the packets enqueued in the
281 * queue disc are correctly transmitted, even if the device queue is stopped
282 * when the last packet is received from the upper layers
283 */
284
285 // The transmission of each packet takes 1000B/1Mbps = 8ms
286 // After 1ms, we have 3 packets in the device queue (stopped) and 6 in the queue disc
288 this, txDev, 3, "There must be 3 packets in the device queue after 1ms");
290 this, txDev, true, "The device queue must be stopped after 1ms");
292 this, txDev, 6, "There must be 6 packets in the queue disc after 1ms");
293
294 // After 9ms, we have 3 packets in the device queue (stopped) and 5 in the queue disc
296 this, txDev, 3, "There must be 3 packets in the device queue after 9ms");
298 this, txDev, true, "The device queue must be stopped after 9ms");
300 this, txDev, 5, "There must be 5 packets in the queue disc after 9ms");
301
302 // After 17ms, we have 3 packets in the device queue (stopped) and 4 in the queue disc
304 this, txDev, 3, "There must be 3 packets in the device queue after 17ms");
306 this, txDev, true, "The device queue must be stopped after 17ms");
308 this, txDev, 4, "There must be 4 packets in the queue disc after 17ms");
309
310 // After 25ms, we have 3 packets in the device queue (stopped) and 3 in the queue disc
312 this, txDev, 3, "There must be 3 packets in the device queue after 25ms");
314 this, txDev, true, "The device queue must be stopped after 25ms");
316 this, txDev, 3, "There must be 3 packets in the queue disc after 25ms");
317
318 // After 33ms, we have 3 packets in the device queue (stopped) and 2 in the queue disc
320 this, txDev, 3, "There must be 3 packets in the device queue after 33ms");
322 this, txDev, true, "The device queue must be stopped after 33ms");
324 this, txDev, 2, "There must be 2 packets in the queue disc after 33ms");
325
326 // After 41ms, we have 3 packets in the device queue (stopped) and 1 in the queue disc
328 this, txDev, 3, "There must be 3 packets in the device queue after 41ms");
330 this, txDev, true, "The device queue must be stopped after 41ms");
332 this, txDev, 1, "There must be 1 packet in the queue disc after 41ms");
333
334 // After 49ms, we have 3 packets in the device queue (stopped) and the queue disc is empty
336 this, txDev, 3, "There must be 3 packets in the device queue after 49ms");
338 this, txDev, true, "The device queue must be stopped after 49ms");
340 this, txDev, 0, "The queue disc must be empty after 49ms");
341
342 // After 57ms, we have 2 packets in the device queue (not stopped) and the queue disc is empty
344 this, txDev, 2, "There must be 2 packets in the device queue after 57ms");
346 this, txDev, false, "The device queue must not be stopped after 57ms");
348 this, txDev, 0, "The queue disc must be empty after 57ms");
349
350 // After 81ms, all packets must have been transmitted (the device queue and the queue disc are empty)
352 this, txDev, 0, "The device queue must be empty after 81ms");
354 this, txDev, false, "The device queue must not be stopped after 81ms");
356 this, txDev, 0, "The queue disc must be empty after 81ms");
357 }
358
359 Simulator::Run ();
360 Simulator::Destroy ();
361}
362
370{
371public:
373 : TestSuite ("tc-flow-control", UNIT)
374 {
375 AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 1, 10), TestCase::QUICK);
376 AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 5, 10), TestCase::QUICK);
377 AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 9, 10), TestCase::QUICK);
378 AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 10, 10), TestCase::QUICK);
379 AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 11, 10), TestCase::QUICK);
380 AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 15, 10), TestCase::QUICK);
381 AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 1, 1), TestCase::QUICK);
382 AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 2, 1), TestCase::QUICK);
383 AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 5, 1), TestCase::QUICK);
384
385 // TODO: Right now, this test only works for 5000B and 10 packets (it's hard coded). Should
386 // also be made parametric.
387 AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::BYTES, 5000, 10), TestCase::QUICK);
388 }
#define min(a, b)
Definition: 80211b.c:42
#define max(a, b)
Definition: 80211b.c:43
Queue Disc Test Item.
virtual bool Mark(void)
Marks the packet as a substitute for dropping it, such as for Explicit Congestion Notification.
QueueDiscTestItem(const QueueDiscTestItem &)=delete
QueueDiscTestItem & operator=(const QueueDiscTestItem &)=delete
virtual void AddHeader(void)
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.
virtual void DoRun(void)
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:44
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.
virtual bool SetMtu(const uint16_t mtu)=0
virtual Ptr< Node > GetNode(void) const =0
virtual Ptr< Channel > GetChannel(void) const =0
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:144
bool GetAttributeFailSafe(std::string name, AttributeValue &value) const
Get the value of an attribute without raising erros.
Definition: object-base.cc:329
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:470
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition: object.cc:252
Hold objects of type Ptr<T>.
Definition: pointer.h:37
Ptr< T > Get(void) const
Definition: pointer.h:201
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 SetDeviceAttribute(std::string n1, const AttributeValue &v1)
void SetQueue(std::string type, std::string n1="", const AttributeValue &v1=EmptyAttributeValue(), std::string n2="", const AttributeValue &v2=EmptyAttributeValue(), std::string n3="", const AttributeValue &v3=EmptyAttributeValue(), std::string n4="", const AttributeValue &v4=EmptyAttributeValue())
Each net device must have a queue to pass packets through.
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:41
encapsulates test code
Definition: test.h:994
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
A suite of tests to run.
Definition: test.h:1188
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1197
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
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:88
QueueSizeUnit
Enumeration of the operating modes of queues.
Definition: queue-size.h:43
@ BYTES
Use number of bytes for queue size.
Definition: queue-size.h:45
@ PACKETS
Use number of packets for queue size.
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:240
TcFlowControlTestSuite g_tcFlowControlTestSuite
the test suite
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1252
Every class exported by the ns3 library is enclosed in the ns3 namespace.