A Discrete-Event Network Simulator
API
tbf-queue-disc-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 Kungliga Tekniska Högskolan
4  * 2017 Universita' degli Studi di Napoli Federico II
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation;
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Authors: Surya Seetharaman <suryaseetharaman.9@gmail.com>
20  * Stefano Avallone <stavallo@unina.it>
21  */
22 
23 #include "ns3/test.h"
24 #include "ns3/tbf-queue-disc.h"
25 #include "ns3/packet.h"
26 #include "ns3/uinteger.h"
27 #include "ns3/string.h"
28 #include "ns3/double.h"
29 #include "ns3/log.h"
30 #include "ns3/simulator.h"
31 #include "ns3/node-container.h"
32 #include "ns3/simple-net-device.h"
33 #include "ns3/simple-channel.h"
34 #include "ns3/traffic-control-layer.h"
35 #include "ns3/config.h"
36 
37 using namespace ns3;
38 
46 public:
53  TbfQueueDiscTestItem (Ptr<Packet> p, const Address & addr);
54  virtual ~TbfQueueDiscTestItem ();
55 
56  // Delete copy constructor and assignment operator to avoid misuse
58  TbfQueueDiscTestItem & operator = (const TbfQueueDiscTestItem &) = delete;
59 
60  virtual void AddHeader (void);
61  virtual bool Mark (void);
62 
63 private:
65 };
66 
68  : QueueDiscItem (p, addr, 0)
69 {
70 }
71 
73 {
74 }
75 
76 void
78 {
79 }
80 
81 bool
83 {
84  return false;
85 }
86 
94 {
95 public:
97  virtual void DoRun (void);
98 private:
105  void Enqueue (Ptr<TbfQueueDisc> queue, Address dest, uint32_t size);
112  void DequeueAndCheck (Ptr<TbfQueueDisc> queue, bool flag, std::string printStatement);
117  void RunTbfTest (QueueSizeUnit mode);
118 };
119 
121  : TestCase ("Sanity check on the TBF queue implementation")
122 {
123 }
124 
125 void
127 {
128  uint32_t pktSize = 1500;
129  // 1 for packets; pktSize for bytes
130  uint32_t modeSize = 1;
131  uint32_t qSize = 4;
132  uint32_t burst = 6000;
133  uint32_t mtu = 0;
134  DataRate rate = DataRate ("6KB/s");
135  DataRate peakRate = DataRate ("0KB/s");
136 
137  Ptr<TbfQueueDisc> queue = CreateObject<TbfQueueDisc> ();
138 
139  // test 1: Simple Enqueue/Dequeue with verification of attribute setting
140  /* 1. There is no second bucket since "peakRate" is set to 0.
141  2. A simple enqueue of five packets, each containing 1500B is followed by
142  the dequeue those five packets.
143  3. The subtraction of tokens from the first bucket to send out each of the
144  five packets is monitored and verified.
145  Note : The number of tokens in the first bucket is full at the beginning.
146  With the dequeuing of each packet, the number of tokens keeps decreasing.
147  So packets are dequeued as long as there are enough tokens in the bucket. */
148 
149  if (mode == QueueSizeUnit::BYTES)
150  {
151  modeSize = pktSize;
152  qSize = qSize * modeSize;
153  }
154 
155  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (mode, qSize))),
156  true, "Verify that we can actually set the attribute MaxSize");
157  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Burst", UintegerValue (burst)), true,
158  "Verify that we can actually set the attribute Burst");
159  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Mtu", UintegerValue (mtu)), true,
160  "Verify that we can actually set the attribute Mtu");
161  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Rate", DataRateValue (rate)), true,
162  "Verify that we can actually set the attribute Rate");
163  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("PeakRate", DataRateValue (peakRate)), true,
164  "Verify that we can actually set the attribute PeakRate");
165 
166  Address dest;
167 
168  Ptr<Packet> p1, p2, p3, p4, p5;
169  p1 = Create<Packet> (pktSize);
170  p2 = Create<Packet> (pktSize);
171  p3 = Create<Packet> (pktSize);
172  p4 = Create<Packet> (pktSize);
173  p5 = Create<Packet> (pktSize);
174 
175  queue->Initialize ();
176  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 0 * modeSize, "There should be no packets in there");
177  queue->Enqueue (Create<TbfQueueDiscTestItem> (p1, dest));
178  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 1 * modeSize, "There should be one packet in there");
179  queue->Enqueue (Create<TbfQueueDiscTestItem> (p2, dest));
180  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 2 * modeSize, "There should be two packets in there");
181  queue->Enqueue (Create<TbfQueueDiscTestItem> (p3, dest));
182  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 3 * modeSize, "There should be three packets in there");
183  queue->Enqueue (Create<TbfQueueDiscTestItem> (p4, dest));
184  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 4 * modeSize, "There should be four packets in there");
185  queue->Enqueue (Create<TbfQueueDiscTestItem> (p5, dest));
186  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 4 * modeSize,
187  "There should still be four packets in there as this enqueue cannot happen since QueueLimit will be exceeded");
188 
189  Ptr<QueueDiscItem> item;
190  NS_TEST_ASSERT_MSG_EQ (queue->GetFirstBucketTokens (), burst, "The first token bucket should be full");
191  item = queue->Dequeue ();
192  NS_TEST_ASSERT_MSG_EQ ((item != 0), true, "I want to remove the first packet");
193  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 3 * modeSize, "There should be three packets in there");
194  NS_TEST_ASSERT_MSG_EQ (item->GetPacket ()->GetUid (), p1->GetUid (), "was this the first packet ?");
195  NS_TEST_ASSERT_MSG_EQ (queue->GetFirstBucketTokens (), burst - (1 * pktSize),
196  "The number of tokens in the first bucket should be one pktSize lesser");
197 
198  item = queue->Dequeue ();
199  NS_TEST_ASSERT_MSG_EQ ((item != 0), true, "I want to remove the second packet");
200  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 2 * modeSize, "There should be two packets in there");
201  NS_TEST_ASSERT_MSG_EQ (item->GetPacket ()->GetUid (), p2->GetUid (), "Was this the second packet ?");
202  NS_TEST_ASSERT_MSG_EQ (queue->GetFirstBucketTokens (), burst - (2 * pktSize),
203  "The number of tokens in the first bucket should be two pktSizes lesser");
204 
205  item = queue->Dequeue ();
206  NS_TEST_ASSERT_MSG_EQ ((item != 0), true, "I want to remove the third packet");
207  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 1 * modeSize, "There should be one packet in there");
208  NS_TEST_ASSERT_MSG_EQ (item->GetPacket ()->GetUid (), p3->GetUid (), "Was this the third packet ?");
209  NS_TEST_ASSERT_MSG_EQ (queue->GetFirstBucketTokens (), burst - (3 * pktSize),
210  "The number of tokens in the first bucket should be three pktSizes lesser");
211 
212  item = queue->Dequeue ();
213  NS_TEST_ASSERT_MSG_EQ ((item != 0), true, "I want to remove the fourth packet");
214  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 0 * modeSize, "There should be zero packet in there");
215  NS_TEST_ASSERT_MSG_EQ (item->GetPacket ()->GetUid (), p4->GetUid (), "Was this the fourth packet ?");
216  NS_TEST_ASSERT_MSG_EQ (queue->GetFirstBucketTokens (), burst - (4 * pktSize),
217  "The number of tokens in the first bucket should be four pktSizes lesser");
218 
219  // test 2 : When DataRate == FirstBucketTokenRate; packets should pass smoothly.
220  queue = CreateObject<TbfQueueDisc> ();
221  qSize = 10;
222  pktSize = 1000;
223  burst = 10000;
224  mtu = 1000;
225  rate = DataRate ("10KB/s");
226  peakRate = DataRate ("100KB/s");
227  uint32_t nPkt = qSize;
228 
229  if (mode == QueueSizeUnit::BYTES)
230  {
231  modeSize = pktSize;
232  qSize = qSize * modeSize;
233  }
234 
235  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (mode, qSize))),
236  true, "Verify that we can actually set the attribute MaxSize");
237  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Burst", UintegerValue (burst)), true,
238  "Verify that we can actually set the attribute Burst");
239  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Mtu", UintegerValue (mtu)), true,
240  "Verify that we can actually set the attribute Mtu");
241  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Rate", DataRateValue (rate)), true,
242  "Verify that we can actually set the attribute Rate");
243  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("PeakRate", DataRateValue (peakRate)), true,
244  "Verify that we can actually set the attribute PeakRate");
245 
246  queue->Initialize ();
247  double delay = 0.09;
248  for (uint32_t i = 1; i <= nPkt; i++)
249  {
250  Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::Enqueue, this, queue, dest, pktSize);
251  }
252  delay = 0.1;
253  for (uint32_t i = 1; i <= nPkt; i++)
254  {
255  Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::DequeueAndCheck, this,
256  queue, true, "No packet should be blocked");
257  }
258  Simulator::Stop (Seconds (1));
259  Simulator::Run ();
260 
261  // test 3 : When DataRate >>> FirstBucketTokenRate; some packets should get blocked and waking of queue should get scheduled.
262  /* 10 packets are enqueued and then dequeued. Since the token rate is less than the data rate, the last packet i.e the 10th
263  packet gets blocked and waking of queue is scheduled after a time when enough tokens will be available. At that time the
264  10th packet passes through. */
265  queue = CreateObject<TbfQueueDisc> ();
266 
267  Config::SetDefault ("ns3::QueueDisc::Quota", UintegerValue (1));
268  NodeContainer nodesA;
269  nodesA.Create (2);
270  Ptr<SimpleNetDevice> txDevA = CreateObject<SimpleNetDevice> ();
271  nodesA.Get (0)->AddDevice (txDevA);
272  Ptr<SimpleNetDevice> rxDevA = CreateObject<SimpleNetDevice> ();
273  nodesA.Get (1)->AddDevice (rxDevA);
274  Ptr<SimpleChannel> channelA = CreateObject<SimpleChannel> ();
275  txDevA->SetChannel (channelA);
276  rxDevA->SetChannel (channelA);
277  txDevA->SetNode (nodesA.Get (0));
278  rxDevA->SetNode (nodesA.Get (1));
279 
280  dest = txDevA->GetAddress ();
281 
282  Ptr<TrafficControlLayer> tcA = CreateObject<TrafficControlLayer> ();
283  nodesA.Get (0)->AggregateObject (tcA);
284  tcA->SetRootQueueDiscOnDevice (txDevA, queue);
285  tcA->Initialize ();
286 
287  burst = 5000;
288  mtu = 1000;
289  rate = DataRate ("5KB/s");
290  peakRate = DataRate ("100KB/s");
291 
292  if (mode == QueueSizeUnit::BYTES)
293  {
294  modeSize = pktSize;
295  qSize = qSize * modeSize;
296  }
297 
298  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (mode, qSize))),
299  true, "Verify that we can actually set the attribute MaxSize");
300  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Burst", UintegerValue (burst)), true,
301  "Verify that we can actually set the attribute Burst");
302  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Mtu", UintegerValue (mtu)), true,
303  "Verify that we can actually set the attribute Mtu");
304  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Rate", DataRateValue (rate)), true,
305  "Verify that we can actually set the attribute Rate");
306  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("PeakRate", DataRateValue (peakRate)), true,
307  "Verify that we can actually set the attribute PeakRate");
308 
309  delay = 0.09;
310  for (uint32_t i = 1; i <= nPkt; i++)
311  {
312  Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::Enqueue, this, queue, dest, pktSize);
313  }
314  delay = 0.1;
315  for (uint32_t i = 1; i <= nPkt; i++)
316  {
317  if (i == 10)
318  {
319  Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::DequeueAndCheck, this,
320  queue, false, "10th packet should be blocked");
321  }
322  else
323  {
324  Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::DequeueAndCheck, this,
325  queue, true, "This packet should not be blocked");
326  }
327  }
328  Simulator::Stop (Seconds (1.3));
329  Simulator::Run ();
330 
331  // test 4 : This test checks the peakRate control of packet dequeue, when DataRate < FirstBucketTokenRate.
332  /* 10 packets each of size 1000 bytes are enqueued followed by
333  their dequeue. The data rate (25 KB/s) is not sufficiently higher than the btokens rate (15 KB/s), so that in
334  the startup phase the first bucket is not empty. Hence when adequate tokens are present in the second (peak) bucket,
335  the packets get transmitted, otherwise they are blocked. So basically the transmission of packets falls under the
336  regulation of the second bucket since first bucket will always have excess tokens. TBF does not let all
337  the packets go smoothly without any control just because there are excess tokens in the first bucket. */
338  queue = CreateObject<TbfQueueDisc> ();
339 
340  Config::SetDefault ("ns3::QueueDisc::Quota", UintegerValue (1));
341  NodeContainer nodesB;
342  nodesB.Create (2);
343  Ptr<SimpleNetDevice> txDevB = CreateObject<SimpleNetDevice> ();
344  nodesB.Get (0)->AddDevice (txDevB);
345  Ptr<SimpleNetDevice> rxDevB = CreateObject<SimpleNetDevice> ();
346  nodesB.Get (1)->AddDevice (rxDevB);
347  Ptr<SimpleChannel> channelB = CreateObject<SimpleChannel> ();
348  txDevB->SetChannel (channelB);
349  rxDevB->SetChannel (channelB);
350  txDevB->SetNode (nodesB.Get (0));
351  rxDevB->SetNode (nodesB.Get (1));
352 
353  dest = txDevB->GetAddress ();
354 
355  Ptr<TrafficControlLayer> tcB = CreateObject<TrafficControlLayer> ();
356  nodesB.Get (0)->AggregateObject (tcB);
357  tcB->SetRootQueueDiscOnDevice (txDevB, queue);
358  tcB->Initialize ();
359 
360  burst = 15000;
361  mtu = 1000;
362  pktSize = 1000;
363  rate = DataRate ("15KB/s");
364  peakRate = DataRate ("20KB/s");
365 
366  if (mode == QueueSizeUnit::BYTES)
367  {
368  modeSize = pktSize;
369  qSize = qSize * modeSize;
370  }
371 
372  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (mode, qSize))),
373  true, "Verify that we can actually set the attribute MaxSize");
374  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Burst", UintegerValue (burst)), true,
375  "Verify that we can actually set the attribute Burst");
376  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Mtu", UintegerValue (mtu)), true,
377  "Verify that we can actually set the attribute Mtu");
378  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Rate", DataRateValue (rate)), true,
379  "Verify that we can actually set the attribute Rate");
380  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("PeakRate", DataRateValue (peakRate)), true,
381  "Verify that we can actually set the attribute PeakRate");
382 
383  queue->Initialize ();
384  delay = 0.04;
385  for (uint32_t i = 1; i <= nPkt; i++)
386  {
387  Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::Enqueue, this, queue, dest, pktSize);
388  }
389 
390  // The pattern being checked is a pattern of dequeue followed by blocked. The delay between enqueues is not sufficient
391  // to allow ptokens to refill befor the next dequeue. The first enqueue is at 1.08s in the future, and the attempted
392  // dequeue is at 1.10s in the future. The first dequeue will always succeed. The second enqueue is 1.12s and attempted
393  // dequeue is at 1.14s in the future, but the last dequeue was 0.04s prior; only 800 tokens can be refilled in 0.04s
394  // at a peak rate of 20Kbps. The actual dequeue occurs at 0.01s further into the future when ptokens refills to 1000.
395  // To repeat the pattern, odd-numbered dequeue events should be spaced at intervals of at least 100ms, and the
396  // even-numbered dequeue events (that block) should be 0.04s (delay) following the last odd-numbered dequeue event.
397  double nextDelay = (2 * delay) + 0.02; // 20ms after first enqueue to attempt the first dequeue;
398  for (uint32_t i = 1; i <= nPkt; i++)
399  {
400  if (i % 2 == 1)
401  {
402  Simulator::Schedule (Seconds (nextDelay), &TbfQueueDiscTestCase::DequeueAndCheck, this,
403  queue, true, "1st packet should not be blocked");
404  nextDelay += 0.04;
405  }
406  else
407  {
408  Simulator::Schedule (Seconds (nextDelay), &TbfQueueDiscTestCase::DequeueAndCheck, this,
409  queue, false, "This packet should be blocked");
410  nextDelay += 0.06; // Need 0.04 + 0.06 seconds to allow the next packet to be dequeued without block
411  }
412  }
413  Simulator::Stop (Seconds (0.55));
414  Simulator::Run ();
415 
416 }
417 
418 void
420 {
421  queue->Enqueue (Create<TbfQueueDiscTestItem> (Create<Packet> (size), dest));
422 }
423 
424 void
425 TbfQueueDiscTestCase::DequeueAndCheck (Ptr<TbfQueueDisc> queue, bool flag, std::string printStatement)
426 {
427  Ptr<QueueDiscItem> item = queue->Dequeue ();
428  NS_TEST_EXPECT_MSG_EQ ((item != 0), flag, printStatement);
429 }
430 
431 void
433 {
436  Simulator::Destroy ();
437 
438 }
439 
446 static class TbfQueueDiscTestSuite : public TestSuite
447 {
448 public:
450  : TestSuite ("tbf-queue-disc", UNIT)
451  {
452  AddTestCase (new TbfQueueDiscTestCase (), TestCase::QUICK);
453  }
Tbf Queue Disc Test Case.
void RunTbfTest(QueueSizeUnit mode)
Run TBF test function.
virtual void DoRun(void)
Implementation to actually run this TestCase.
void Enqueue(Ptr< TbfQueueDisc > queue, Address dest, uint32_t size)
Enqueue function.
void DequeueAndCheck(Ptr< TbfQueueDisc > queue, bool flag, std::string printStatement)
DequeueAndCheck function to check if a packet is blocked or not after dequeuing and verify against ex...
Tbf Queue Disc Test Item.
virtual bool Mark(void)
Marks the packet as a substitute for dropping it, such as for Explicit Congestion Notification.
TbfQueueDiscTestItem(const TbfQueueDiscTestItem &)=delete
virtual void AddHeader(void)
Add the header to the packet.
Tbf Queue Disc Test Suite.
a polymophic address class
Definition: address.h:91
Class for representing data rates.
Definition: data-rate.h:89
AttributeValue implementation for DataRate.
Definition: data-rate.h:298
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.
uint32_t AddDevice(Ptr< NetDevice > device)
Associate a NetDevice to this node.
Definition: node.cc:130
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition: object.cc:252
uint64_t GetUid(void) const
Returns the packet's Uid.
Definition: packet.cc:390
QueueDiscItem is the abstract base class for items that are stored in a queue disc.
Definition: queue-item.h:133
Class for representing queue sizes.
Definition: queue-size.h:95
AttributeValue implementation for QueueSize.
Definition: queue-size.h:221
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
Hold an unsigned integer type.
Definition: uinteger.h:44
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:849
void(* DataRate)(DataRate oldValue, DataRate newValue)
TracedValue callback signature for DataRate.
Definition: data-rate.h:329
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_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:141
#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
TbfQueueDiscTestSuite g_tbfQueueTestSuite
the test suite
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
Every class exported by the ns3 library is enclosed in the ns3 namespace.
uint32_t pktSize
packet size used for the simulation (in bytes)
Definition: wifi-bianchi.cc:89