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 
41 using namespace ns3;
42 
50 public:
57  virtual ~QueueDiscTestItem ();
58  virtual void AddHeader (void);
59  virtual bool Mark(void);
60 
61 private:
73  QueueDiscTestItem &operator = (const QueueDiscTestItem &);
74 };
75 
77  : QueueDiscItem (p, Mac48Address (), 0)
78 {
79 }
80 
82 {
83 }
84 
85 void
87 {
88 }
89 
90 bool
92 {
93  return false;
94 }
95 
103 {
104 public:
112  TcFlowControlTestCase (QueueSizeUnit tt, uint32_t deviceQueueLength, uint32_t totalTxPackets);
113  virtual ~TcFlowControlTestCase ();
114 private:
115  virtual void DoRun (void);
121  void SendPackets (Ptr<Node> n, uint16_t nPackets);
128  void CheckPacketsInDeviceQueue (Ptr<NetDevice> dev, uint16_t nPackets, const std::string msg);
135  void CheckDeviceQueueStopped (Ptr<NetDevice> dev, bool value, const std::string msg);
142  void CheckPacketsInQueueDisc (Ptr<NetDevice> dev, uint16_t nPackets, const std::string msg);
145  uint32_t m_totalTxPackets;
146 };
147 
148 TcFlowControlTestCase::TcFlowControlTestCase (QueueSizeUnit tt, uint32_t deviceQueueLength, uint32_t totalTxPackets)
149  : TestCase ("Test the operation of the flow control mechanism"),
150  m_type (tt), m_deviceQueueLength(deviceQueueLength), m_totalTxPackets(totalTxPackets)
151 {
152 }
153 
155 {
156 }
157 
158 void
160 {
161  Ptr<TrafficControlLayer> tc = n->GetObject<TrafficControlLayer> ();
162  for (uint16_t i = 0; i < nPackets; i++)
163  {
164  tc->Send (n->GetDevice (0), Create<QueueDiscTestItem> (Create<Packet> (1000)));
165  }
166 }
167 
168 void
169 TcFlowControlTestCase::CheckPacketsInDeviceQueue (Ptr<NetDevice> dev, uint16_t nPackets, const std::string msg)
170 {
171  PointerValue ptr;
172  dev->GetAttributeFailSafe ("TxQueue", ptr);
173  Ptr<Queue<Packet> > queue = ptr.Get<Queue<Packet> > ();
174  NS_TEST_EXPECT_MSG_EQ (queue->GetNPackets (), nPackets, msg);
175 }
176 
177 void
178 TcFlowControlTestCase::CheckDeviceQueueStopped (Ptr<NetDevice> dev, bool value, const std::string msg)
179 {
181  NS_ASSERT_MSG (ndqi, "A device queue interface has not been aggregated to the device");
182  NS_TEST_EXPECT_MSG_EQ (ndqi->GetTxQueue (0)->IsStopped (), value, msg);
183 }
184 
185 void
186 TcFlowControlTestCase::CheckPacketsInQueueDisc (Ptr<NetDevice> dev, uint16_t nPackets, const std::string msg)
187 {
189  Ptr<QueueDisc> qdisc = tc->GetRootQueueDiscOnDevice (dev);
190  NS_TEST_EXPECT_MSG_EQ (qdisc->GetNPackets (), nPackets, msg);
191 }
192 
193 
194 void
196 {
198  n.Create (2);
199 
200  n.Get (0)->AggregateObject (CreateObject<TrafficControlLayer> ());
201  n.Get (1)->AggregateObject (CreateObject<TrafficControlLayer> ());
202 
203  SimpleNetDeviceHelper simple;
204 
205  NetDeviceContainer rxDevC = simple.Install (n.Get (1));
206 
207  simple.SetDeviceAttribute ("DataRate", DataRateValue (DataRate ("1Mb/s")));
208  simple.SetQueue ("ns3::DropTailQueue", "MaxSize",
210  ? std::to_string (m_deviceQueueLength) + "p"
211  : std::to_string (m_deviceQueueLength) + "B"));
212 
213  Ptr<NetDevice> txDev;
214  txDev = simple.Install (n.Get (0), DynamicCast<SimpleChannel> (rxDevC.Get (0)->GetChannel ())).Get (0);
215  txDev->SetMtu (2500);
216 
217  TrafficControlHelper tch = TrafficControlHelper::Default ();
218  tch.Install (txDev);
219 
220  // transmit 10 packets at time 0
221  Simulator::Schedule (Time (Seconds (0)), &TcFlowControlTestCase::SendPackets,
222  this, n.Get (0), m_totalTxPackets);
223 
225  {
226  /*
227  * When the device queue is in packet mode, all the packets enqueued in the
228  * queue disc are correctly transmitted, even if the device queue is stopped
229  * when the last packet is received from the upper layers
230  *
231  * We have the following invariants:
232  * - totalPackets = txPackets + deviceQueuePackets + qdiscPackets
233  * - deviceQueuePackets = MIN(totalPackets - txPackets, deviceQueueLen)
234  * - qdiscPackets = MAX(totalPackets - txPackets - deviceQueuePackets, 0)
235  *
236  * The transmission of each packet takes 1000B/1Mbps = 8ms
237  *
238  * We check the values of deviceQueuePackets and qdiscPackets 1ms after each
239  * packet is transmitted (i.e. at 1ms, 9ms, 17ms, ...), as well as verifying
240  * that the device queue is stopped or not, as appropriate.
241  */
242 
243  uint32_t checkTimeMs = 0;
244  uint32_t deviceQueuePackets = 0;
245  uint32_t qdiscPackets = 0;
246 
247  uint32_t txPackets = 0;
248  for (txPackets = 1; txPackets <= m_totalTxPackets; txPackets++)
249  {
250  checkTimeMs = 8 * (txPackets - 1) + 1; // Check 1ms after each packet is sent
251  deviceQueuePackets = std::min (m_totalTxPackets - txPackets, m_deviceQueueLength);
252  qdiscPackets = std::max (m_totalTxPackets - txPackets - deviceQueuePackets, (uint32_t)0);
253  if (deviceQueuePackets == m_deviceQueueLength)
254  {
255  Simulator::Schedule (
256  Time (MilliSeconds (checkTimeMs)),
258  "The device queue must be stopped after " + std::to_string (checkTimeMs) + "ms");
259  }
260  else
261  {
262  Simulator::Schedule (Time (MilliSeconds (checkTimeMs)),
264  false,
265  "The device queue must not be stopped after " +
266  std::to_string (checkTimeMs) + "ms");
267  }
268 
269  Simulator::Schedule (
271  this, txDev, deviceQueuePackets,
272  "There must be " + std::to_string (m_deviceQueueLength) + " packets in the device after " +
273  std::to_string (checkTimeMs) + "ms");
274 
275  Simulator::Schedule (
277  this, txDev, qdiscPackets,
278  "There must be " + std::to_string (qdiscPackets) +
279  " packets in the queue disc after " + std::to_string (checkTimeMs) + "ms");
280  }
281  }
282  else
283  {
284  // TODO: Make this test parametric as well, and add new test cases
285  /*
286  * When the device queue is in byte mode, all the packets enqueued in the
287  * queue disc are correctly transmitted, even if the device queue is stopped
288  * when the last packet is received from the upper layers
289  */
290 
291  // The transmission of each packet takes 1000B/1Mbps = 8ms
292  // After 1ms, we have 3 packets in the device queue (stopped) and 6 in the queue disc
294  this, txDev, 3, "There must be 3 packets in the device queue after 1ms");
296  this, txDev, true, "The device queue must be stopped after 1ms");
298  this, txDev, 6, "There must be 6 packets in the queue disc after 1ms");
299 
300  // After 9ms, we have 3 packets in the device queue (stopped) and 5 in the queue disc
302  this, txDev, 3, "There must be 3 packets in the device queue after 9ms");
304  this, txDev, true, "The device queue must be stopped after 9ms");
306  this, txDev, 5, "There must be 5 packets in the queue disc after 9ms");
307 
308  // After 17ms, we have 3 packets in the device queue (stopped) and 4 in the queue disc
310  this, txDev, 3, "There must be 3 packets in the device queue after 17ms");
312  this, txDev, true, "The device queue must be stopped after 17ms");
314  this, txDev, 4, "There must be 4 packets in the queue disc after 17ms");
315 
316  // After 25ms, we have 3 packets in the device queue (stopped) and 3 in the queue disc
318  this, txDev, 3, "There must be 3 packets in the device queue after 25ms");
320  this, txDev, true, "The device queue must be stopped after 25ms");
322  this, txDev, 3, "There must be 3 packets in the queue disc after 25ms");
323 
324  // After 33ms, we have 3 packets in the device queue (stopped) and 2 in the queue disc
326  this, txDev, 3, "There must be 3 packets in the device queue after 33ms");
328  this, txDev, true, "The device queue must be stopped after 33ms");
330  this, txDev, 2, "There must be 2 packets in the queue disc after 33ms");
331 
332  // After 41ms, we have 3 packets in the device queue (stopped) and 1 in the queue disc
334  this, txDev, 3, "There must be 3 packets in the device queue after 41ms");
336  this, txDev, true, "The device queue must be stopped after 41ms");
338  this, txDev, 1, "There must be 1 packet in the queue disc after 41ms");
339 
340  // After 49ms, we have 3 packets in the device queue (stopped) and the queue disc is empty
342  this, txDev, 3, "There must be 3 packets in the device queue after 49ms");
344  this, txDev, true, "The device queue must be stopped after 49ms");
346  this, txDev, 0, "The queue disc must be empty after 49ms");
347 
348  // After 57ms, we have 2 packets in the device queue (not stopped) and the queue disc is empty
350  this, txDev, 2, "There must be 2 packets in the device queue after 57ms");
352  this, txDev, false, "The device queue must not be stopped after 57ms");
354  this, txDev, 0, "The queue disc must be empty after 57ms");
355 
356  // After 81ms, all packets must have been transmitted (the device queue and the queue disc are empty)
358  this, txDev, 0, "The device queue must be empty after 81ms");
360  this, txDev, false, "The device queue must not be stopped after 81ms");
362  this, txDev, 0, "The queue disc must be empty after 81ms");
363  }
364 
365  Simulator::Run ();
366  Simulator::Destroy ();
367 }
368 
375 static class TcFlowControlTestSuite : public TestSuite
376 {
377 public:
379  : TestSuite ("tc-flow-control", UNIT)
380  {
381  AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 1, 10), TestCase::QUICK);
382  AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 5, 10), TestCase::QUICK);
383  AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 9, 10), TestCase::QUICK);
384  AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 10, 10), TestCase::QUICK);
385  AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 11, 10), TestCase::QUICK);
386  AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 15, 10), TestCase::QUICK);
387  AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 1, 1), TestCase::QUICK);
388  AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 2, 1), TestCase::QUICK);
389  AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::PACKETS, 5, 1), TestCase::QUICK);
390 
391  // TODO: Right now, this test only works for 5000B and 10 packets (it's hard coded). Should
392  // also be made parametric.
393  AddTestCase (new TcFlowControlTestCase (QueueSizeUnit::BYTES, 5000, 10), TestCase::QUICK);
394  }
ns3::NetDeviceContainer
holds a vector of ns3::NetDevice pointers
Definition: net-device-container.h:42
ns3::QueueDiscItem
QueueDiscItem is the abstract base class for items that are stored in a queue disc.
Definition: queue-item.h:148
ns3::DataRateValue
AttributeValue implementation for DataRate.
Definition: data-rate.h:298
ns3::TestCase::AddTestCase
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
ns3::SimpleNetDeviceHelper::SetQueue
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.
Definition: simple-net-device-helper.cc:52
min
#define min(a, b)
Definition: 80211b.c:42
ns3::NetDeviceQueueInterface::GetTxQueue
Ptr< NetDeviceQueue > GetTxQueue(std::size_t i) const
Get the i-th transmission queue of the device.
Definition: net-device-queue-interface.cc:214
ns3
Every class exported by the ns3 library is enclosed in the ns3 namespace.
QueueDiscTestItem::QueueDiscTestItem
QueueDiscTestItem(const QueueDiscTestItem &)
Copy constructor Disable default implementation to avoid misuse.
ns3::Object::GetObject
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:470
ns3::PointerValue
Hold objects of type Ptr<T>.
Definition: pointer.h:37
ns3::Mac48Address
an EUI-48 address
Definition: mac48-address.h:44
ns3::PACKETS
@ PACKETS
Use number of packets for queue size.
Definition: queue-size.h:44
QueueDiscTestItem::Mark
virtual bool Mark(void)
Marks the packet as a substitute for dropping it, such as for Explicit Congestion Notification.
Definition: tc-flow-control-test-suite.cc:91
QueueDiscTestItem::~QueueDiscTestItem
virtual ~QueueDiscTestItem()
Definition: tc-flow-control-test-suite.cc:81
TcFlowControlTestCase::m_deviceQueueLength
uint32_t m_deviceQueueLength
the queue length of the device
Definition: tc-flow-control-test-suite.cc:144
ns3::TestCase
encapsulates test code
Definition: test.h:1154
ns3::ObjectBase::GetAttributeFailSafe
bool GetAttributeFailSafe(std::string name, AttributeValue &value) const
Get the value of an attribute without raising erros.
Definition: object-base.cc:258
ns3::Ptr< Packet >
ns3::DataRate
Class for representing data rates.
Definition: data-rate.h:89
ns3::NetDevice::SetMtu
virtual bool SetMtu(const uint16_t mtu)=0
ns3::SimpleNetDeviceHelper::SetDeviceAttribute
void SetDeviceAttribute(std::string n1, const AttributeValue &v1)
Definition: simple-net-device-helper.cc:82
TcFlowControlTestCase
Traffic Control Flow Control Test Case.
Definition: tc-flow-control-test-suite.cc:103
max
#define max(a, b)
Definition: 80211b.c:43
ns3::TrafficControlHelper::Install
QueueDiscContainer Install(NetDeviceContainer c)
Definition: traffic-control-helper.cc:248
ns3::NetDevice::GetNode
virtual Ptr< Node > GetNode(void) const =0
ns3::MilliSeconds
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1297
ns3::PointerValue::Get
Ptr< T > Get(void) const
Definition: pointer.h:201
ns3::SimpleNetDeviceHelper
build a set of SimpleNetDevice objects
Definition: simple-net-device-helper.h:37
NS_TEST_EXPECT_MSG_EQ
#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:283
ns3::Time
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:104
NS_ASSERT_MSG
#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
ns3::SimpleNetDeviceHelper::Install
NetDeviceContainer Install(Ptr< Node > node) const
This method creates an ns3::SimpleChannel with the attributes configured by SimpleNetDeviceHelper::Se...
Definition: simple-net-device-helper.cc:100
Queue< Packet >
TcFlowControlTestCase::CheckDeviceQueueStopped
void CheckDeviceQueueStopped(Ptr< NetDevice > dev, bool value, const std::string msg)
Check if the device queue is in the expected status (stopped or not)
Definition: tc-flow-control-test-suite.cc:178
ns3::NetDevice::GetChannel
virtual Ptr< Channel > GetChannel(void) const =0
ns3::StringValue
Hold variables of type string.
Definition: string.h:41
ns3::NetDeviceQueueInterface
Network device transmission queue interface.
Definition: net-device-queue-interface.h:231
ns3::TestSuite
A suite of tests to run.
Definition: test.h:1344
TcFlowControlTestCase::CheckPacketsInQueueDisc
void CheckPacketsInQueueDisc(Ptr< NetDevice > dev, uint16_t nPackets, const std::string msg)
Check if the queue disc stores the expected number of packets.
Definition: tc-flow-control-test-suite.cc:186
TcFlowControlTestCase::~TcFlowControlTestCase
virtual ~TcFlowControlTestCase()
Definition: tc-flow-control-test-suite.cc:154
ns3::TrafficControlLayer
Introspection did not find any typical Config paths.
Definition: traffic-control-layer.h:90
ns3::TestSuite::UNIT
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1353
ns3::TrafficControlLayer::Send
virtual void Send(Ptr< NetDevice > device, Ptr< QueueDiscItem > item)
Called from upper layer to queue a packet for the transmission.
Definition: traffic-control-layer.cc:342
QueueDiscTestItem::AddHeader
virtual void AddHeader(void)
Add the header to the packet.
Definition: tc-flow-control-test-suite.cc:86
TcFlowControlTestCase::m_totalTxPackets
uint32_t m_totalTxPackets
the toal number of packets to transmit
Definition: tc-flow-control-test-suite.cc:145
ns3::Seconds
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1289
ns3::TrafficControlHelper
Build a set of QueueDisc objects.
Definition: traffic-control-helper.h:120
TcFlowControlTestCase::DoRun
virtual void DoRun(void)
Implementation to actually run this TestCase.
Definition: tc-flow-control-test-suite.cc:195
ns3::TrafficControlLayer::GetRootQueueDiscOnDevice
virtual Ptr< QueueDisc > GetRootQueueDiscOnDevice(Ptr< NetDevice > device) const
This method can be used to get the root queue disc installed on a device.
Definition: traffic-control-layer.cc:224
ns3::BYTES
@ BYTES
Use number of bytes for queue size.
Definition: queue-size.h:45
TcFlowControlTestCase::SendPackets
void SendPackets(Ptr< Node > n, uint16_t nPackets)
Instruct a node to send a specified number of packets.
Definition: tc-flow-control-test-suite.cc:159
ns3::NodeContainer
keep track of a set of node pointers.
Definition: node-container.h:39
ns3::QueueSizeUnit
QueueSizeUnit
Enumeration of the operating modes of queues.
Definition: queue-size.h:43
QueueDiscTestItem::QueueDiscTestItem
QueueDiscTestItem()
g_tcFlowControlTestSuite
TcFlowControlTestSuite g_tcFlowControlTestSuite
the test suite
TcFlowControlTestSuite
Traffic Control Flow Control Test Suite.
Definition: tc-flow-control-test-suite.cc:376
TcFlowControlTestCase::TcFlowControlTestCase
TcFlowControlTestCase(QueueSizeUnit tt, uint32_t deviceQueueLength, uint32_t totalTxPackets)
Constructor.
Definition: tc-flow-control-test-suite.cc:148
TcFlowControlTestCase::CheckPacketsInDeviceQueue
void CheckPacketsInDeviceQueue(Ptr< NetDevice > dev, uint16_t nPackets, const std::string msg)
Check if the device queue stores the expected number of packets.
Definition: tc-flow-control-test-suite.cc:169
TcFlowControlTestSuite::TcFlowControlTestSuite
TcFlowControlTestSuite()
Definition: tc-flow-control-test-suite.cc:378
QueueDiscTestItem
Queue Disc Test Item.
Definition: tc-flow-control-test-suite.cc:49
ns3::NetDeviceContainer::Get
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr<NetDevice> stored in this container at a given index.
Definition: net-device-container.cc:62
TcFlowControlTestCase::m_type
QueueSizeUnit m_type
the test type
Definition: tc-flow-control-test-suite.cc:143
sample-rng-plot.n
n
Definition: sample-rng-plot.py:37