A Discrete-Event Network Simulator
API
tbf-queue-disc-test-suite.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Kungliga Tekniska Högskolan
3  * 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  * Authors: Surya Seetharaman <suryaseetharaman.9@gmail.com>
19  * Stefano Avallone <stavallo@unina.it>
20  */
21 
22 #include "ns3/config.h"
23 #include "ns3/double.h"
24 #include "ns3/log.h"
25 #include "ns3/node-container.h"
26 #include "ns3/packet.h"
27 #include "ns3/simple-channel.h"
28 #include "ns3/simple-net-device.h"
29 #include "ns3/simulator.h"
30 #include "ns3/string.h"
31 #include "ns3/tbf-queue-disc.h"
32 #include "ns3/test.h"
33 #include "ns3/traffic-control-layer.h"
34 #include "ns3/uinteger.h"
35 
36 using namespace ns3;
37 
44 {
45  public:
53  ~TbfQueueDiscTestItem() override;
54 
55  // Delete default constructor, copy constructor and assignment operator to avoid misuse
59 
60  void AddHeader() override;
61  bool Mark() override;
62 };
63 
65  : QueueDiscItem(p, addr, 0)
66 {
67 }
68 
70 {
71 }
72 
73 void
75 {
76 }
77 
78 bool
80 {
81  return false;
82 }
83 
90 {
91  public:
93  void DoRun() override;
94 
95  private:
102  void Enqueue(Ptr<TbfQueueDisc> queue, Address dest, uint32_t size);
111  void DequeueAndCheck(Ptr<TbfQueueDisc> queue, bool flag, std::string printStatement);
116  void RunTbfTest(QueueSizeUnit mode);
117 };
118 
120  : TestCase("Sanity check on the TBF queue implementation")
121 {
122 }
123 
124 void
126 {
127  uint32_t pktSize = 1500;
128  // 1 for packets; pktSize for bytes
129  uint32_t modeSize = 1;
130  uint32_t qSize = 4;
131  uint32_t burst = 6000;
132  uint32_t mtu = 0;
133  DataRate rate = DataRate("6KB/s");
134  DataRate peakRate = DataRate("0KB/s");
135 
136  Ptr<TbfQueueDisc> queue = CreateObject<TbfQueueDisc>();
137 
138  // test 1: Simple Enqueue/Dequeue with verification of attribute setting
139  /* 1. There is no second bucket since "peakRate" is set to 0.
140  2. A simple enqueue of five packets, each containing 1500B is followed by
141  the dequeue those five packets.
142  3. The subtraction of tokens from the first bucket to send out each of the
143  five packets is monitored and verified.
144  Note : The number of tokens in the first bucket is full at the beginning.
145  With the dequeuing of each packet, the number of tokens keeps decreasing.
146  So packets are dequeued as long as there are enough tokens in the bucket. */
147 
148  if (mode == QueueSizeUnit::BYTES)
149  {
150  modeSize = pktSize;
151  qSize = qSize * modeSize;
152  }
153 
155  queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(mode, qSize))),
156  true,
157  "Verify that we can actually set the attribute MaxSize");
158  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Burst", UintegerValue(burst)),
159  true,
160  "Verify that we can actually set the attribute Burst");
161  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Mtu", UintegerValue(mtu)),
162  true,
163  "Verify that we can actually set the attribute Mtu");
164  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Rate", DataRateValue(rate)),
165  true,
166  "Verify that we can actually set the attribute Rate");
167  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("PeakRate", DataRateValue(peakRate)),
168  true,
169  "Verify that we can actually set the attribute PeakRate");
170 
171  Address dest;
172 
173  Ptr<Packet> p1;
174  Ptr<Packet> p2;
175  Ptr<Packet> p3;
176  Ptr<Packet> p4;
177  Ptr<Packet> p5;
178  p1 = Create<Packet>(pktSize);
179  p2 = Create<Packet>(pktSize);
180  p3 = Create<Packet>(pktSize);
181  p4 = Create<Packet>(pktSize);
182  p5 = Create<Packet>(pktSize);
183 
184  queue->Initialize();
185  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
186  0 * modeSize,
187  "There should be no packets in there");
188  queue->Enqueue(Create<TbfQueueDiscTestItem>(p1, dest));
189  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
190  1 * modeSize,
191  "There should be one packet in there");
192  queue->Enqueue(Create<TbfQueueDiscTestItem>(p2, dest));
193  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
194  2 * modeSize,
195  "There should be two packets in there");
196  queue->Enqueue(Create<TbfQueueDiscTestItem>(p3, dest));
197  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
198  3 * modeSize,
199  "There should be three packets in there");
200  queue->Enqueue(Create<TbfQueueDiscTestItem>(p4, dest));
201  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
202  4 * modeSize,
203  "There should be four packets in there");
204  queue->Enqueue(Create<TbfQueueDiscTestItem>(p5, dest));
205  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
206  4 * modeSize,
207  "There should still be four packets in there as this enqueue cannot "
208  "happen since QueueLimit will be exceeded");
209 
210  Ptr<QueueDiscItem> item;
211  NS_TEST_ASSERT_MSG_EQ(queue->GetFirstBucketTokens(),
212  burst,
213  "The first token bucket should be full");
214  item = queue->Dequeue();
215  NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the first packet");
216  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
217  3 * modeSize,
218  "There should be three packets in there");
219  NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p1->GetUid(), "was this the first packet ?");
220  NS_TEST_ASSERT_MSG_EQ(queue->GetFirstBucketTokens(),
221  burst - (1 * pktSize),
222  "The number of tokens in the first bucket should be one pktSize lesser");
223 
224  item = queue->Dequeue();
225  NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the second packet");
226  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
227  2 * modeSize,
228  "There should be two packets in there");
229  NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(),
230  p2->GetUid(),
231  "Was this the second packet ?");
232  NS_TEST_ASSERT_MSG_EQ(queue->GetFirstBucketTokens(),
233  burst - (2 * pktSize),
234  "The number of tokens in the first bucket should be two pktSizes lesser");
235 
236  item = queue->Dequeue();
237  NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the third packet");
238  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
239  1 * modeSize,
240  "There should be one packet in there");
241  NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p3->GetUid(), "Was this the third packet ?");
243  queue->GetFirstBucketTokens(),
244  burst - (3 * pktSize),
245  "The number of tokens in the first bucket should be three pktSizes lesser");
246 
247  item = queue->Dequeue();
248  NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the fourth packet");
249  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
250  0 * modeSize,
251  "There should be zero packet in there");
252  NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(),
253  p4->GetUid(),
254  "Was this the fourth packet ?");
256  queue->GetFirstBucketTokens(),
257  burst - (4 * pktSize),
258  "The number of tokens in the first bucket should be four pktSizes lesser");
259 
260  // test 2 : When DataRate == FirstBucketTokenRate; packets should pass smoothly.
261  queue = CreateObject<TbfQueueDisc>();
262  qSize = 10;
263  pktSize = 1000;
264  burst = 10000;
265  mtu = 1000;
266  rate = DataRate("10KB/s");
267  peakRate = DataRate("100KB/s");
268  uint32_t nPkt = qSize;
269 
270  if (mode == QueueSizeUnit::BYTES)
271  {
272  modeSize = pktSize;
273  qSize = qSize * modeSize;
274  }
275 
277  queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(mode, qSize))),
278  true,
279  "Verify that we can actually set the attribute MaxSize");
280  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Burst", UintegerValue(burst)),
281  true,
282  "Verify that we can actually set the attribute Burst");
283  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Mtu", UintegerValue(mtu)),
284  true,
285  "Verify that we can actually set the attribute Mtu");
286  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Rate", DataRateValue(rate)),
287  true,
288  "Verify that we can actually set the attribute Rate");
289  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("PeakRate", DataRateValue(peakRate)),
290  true,
291  "Verify that we can actually set the attribute PeakRate");
292 
293  queue->Initialize();
294  double delay = 0.09;
295  for (uint32_t i = 1; i <= nPkt; i++)
296  {
297  Simulator::Schedule(Time(Seconds((i + 1) * delay)),
299  this,
300  queue,
301  dest,
302  pktSize);
303  }
304  delay = 0.1;
305  for (uint32_t i = 1; i <= nPkt; i++)
306  {
307  Simulator::Schedule(Time(Seconds((i + 1) * delay)),
309  this,
310  queue,
311  true,
312  "No packet should be blocked");
313  }
314  Simulator::Stop(Seconds(1));
315  Simulator::Run();
316 
317  // test 3 : When DataRate >>> FirstBucketTokenRate; some packets should get blocked and waking
318  // of queue should get scheduled.
319  /* 10 packets are enqueued and then dequeued. Since the token rate is less than the data rate,
320  the last packet i.e the 10th packet gets blocked and waking of queue is scheduled after a
321  time when enough tokens will be available. At that time the 10th packet passes through. */
322  queue = CreateObject<TbfQueueDisc>();
323 
324  Config::SetDefault("ns3::QueueDisc::Quota", UintegerValue(1));
325  NodeContainer nodesA;
326  nodesA.Create(2);
327  Ptr<SimpleNetDevice> txDevA = CreateObject<SimpleNetDevice>();
328  nodesA.Get(0)->AddDevice(txDevA);
329  Ptr<SimpleNetDevice> rxDevA = CreateObject<SimpleNetDevice>();
330  nodesA.Get(1)->AddDevice(rxDevA);
331  Ptr<SimpleChannel> channelA = CreateObject<SimpleChannel>();
332  txDevA->SetChannel(channelA);
333  rxDevA->SetChannel(channelA);
334  txDevA->SetNode(nodesA.Get(0));
335  rxDevA->SetNode(nodesA.Get(1));
336 
337  dest = txDevA->GetAddress();
338 
339  Ptr<TrafficControlLayer> tcA = CreateObject<TrafficControlLayer>();
340  nodesA.Get(0)->AggregateObject(tcA);
341  tcA->SetRootQueueDiscOnDevice(txDevA, queue);
342  tcA->Initialize();
343 
344  burst = 5000;
345  mtu = 1000;
346  rate = DataRate("5KB/s");
347  peakRate = DataRate("100KB/s");
348 
349  if (mode == QueueSizeUnit::BYTES)
350  {
351  modeSize = pktSize;
352  qSize = qSize * modeSize;
353  }
354 
356  queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(mode, qSize))),
357  true,
358  "Verify that we can actually set the attribute MaxSize");
359  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Burst", UintegerValue(burst)),
360  true,
361  "Verify that we can actually set the attribute Burst");
362  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Mtu", UintegerValue(mtu)),
363  true,
364  "Verify that we can actually set the attribute Mtu");
365  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Rate", DataRateValue(rate)),
366  true,
367  "Verify that we can actually set the attribute Rate");
368  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("PeakRate", DataRateValue(peakRate)),
369  true,
370  "Verify that we can actually set the attribute PeakRate");
371 
372  delay = 0.09;
373  for (uint32_t i = 1; i <= nPkt; i++)
374  {
375  Simulator::Schedule(Time(Seconds((i + 1) * delay)),
377  this,
378  queue,
379  dest,
380  pktSize);
381  }
382  delay = 0.1;
383  for (uint32_t i = 1; i <= nPkt; i++)
384  {
385  if (i == 10)
386  {
387  Simulator::Schedule(Time(Seconds((i + 1) * delay)),
389  this,
390  queue,
391  false,
392  "10th packet should be blocked");
393  }
394  else
395  {
396  Simulator::Schedule(Time(Seconds((i + 1) * delay)),
398  this,
399  queue,
400  true,
401  "This packet should not be blocked");
402  }
403  }
404  Simulator::Stop(Seconds(1.3));
405  Simulator::Run();
406 
407  // test 4 : This test checks the peakRate control of packet dequeue, when DataRate <
408  // FirstBucketTokenRate.
409  /* 10 packets each of size 1000 bytes are enqueued followed by
410  their dequeue. The data rate (25 KB/s) is not sufficiently higher than the btokens rate (15
411  KB/s), so that in the startup phase the first bucket is not empty. Hence when adequate tokens
412  are present in the second (peak) bucket, the packets get transmitted, otherwise they are
413  blocked. So basically the transmission of packets falls under the regulation of the second
414  bucket since first bucket will always have excess tokens. TBF does not let all the packets go
415  smoothly without any control just because there are excess tokens in the first bucket. */
416  queue = CreateObject<TbfQueueDisc>();
417 
418  Config::SetDefault("ns3::QueueDisc::Quota", UintegerValue(1));
419  NodeContainer nodesB;
420  nodesB.Create(2);
421  Ptr<SimpleNetDevice> txDevB = CreateObject<SimpleNetDevice>();
422  nodesB.Get(0)->AddDevice(txDevB);
423  Ptr<SimpleNetDevice> rxDevB = CreateObject<SimpleNetDevice>();
424  nodesB.Get(1)->AddDevice(rxDevB);
425  Ptr<SimpleChannel> channelB = CreateObject<SimpleChannel>();
426  txDevB->SetChannel(channelB);
427  rxDevB->SetChannel(channelB);
428  txDevB->SetNode(nodesB.Get(0));
429  rxDevB->SetNode(nodesB.Get(1));
430 
431  dest = txDevB->GetAddress();
432 
433  Ptr<TrafficControlLayer> tcB = CreateObject<TrafficControlLayer>();
434  nodesB.Get(0)->AggregateObject(tcB);
435  tcB->SetRootQueueDiscOnDevice(txDevB, queue);
436  tcB->Initialize();
437 
438  burst = 15000;
439  mtu = 1000;
440  pktSize = 1000;
441  rate = DataRate("15KB/s");
442  peakRate = DataRate("20KB/s");
443 
444  if (mode == QueueSizeUnit::BYTES)
445  {
446  modeSize = pktSize;
447  qSize = qSize * modeSize;
448  }
449 
451  queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(mode, qSize))),
452  true,
453  "Verify that we can actually set the attribute MaxSize");
454  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Burst", UintegerValue(burst)),
455  true,
456  "Verify that we can actually set the attribute Burst");
457  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Mtu", UintegerValue(mtu)),
458  true,
459  "Verify that we can actually set the attribute Mtu");
460  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Rate", DataRateValue(rate)),
461  true,
462  "Verify that we can actually set the attribute Rate");
463  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("PeakRate", DataRateValue(peakRate)),
464  true,
465  "Verify that we can actually set the attribute PeakRate");
466 
467  queue->Initialize();
468  delay = 0.04;
469  for (uint32_t i = 1; i <= nPkt; i++)
470  {
471  Simulator::Schedule(Time(Seconds((i + 1) * delay)),
473  this,
474  queue,
475  dest,
476  pktSize);
477  }
478 
479  // The pattern being checked is a pattern of dequeue followed by blocked. The delay between
480  // enqueues is not sufficient to allow ptokens to refill before the next dequeue. The first
481  // enqueue is at 1.08s in the future, and the attempted dequeue is at 1.10s in the future. The
482  // first dequeue will always succeed. The second enqueue is 1.12s and attempted dequeue is
483  // at 1.14s in the future, but the last dequeue was 0.04s prior; only 800 tokens can be refilled
484  // in 0.04s at a peak rate of 20Kbps. The actual dequeue occurs at 0.01s further into the
485  // future when ptokens refills to 1000. To repeat the pattern, odd-numbered dequeue events
486  // should be spaced at intervals of at least 100ms, and the even-numbered dequeue events (that
487  // block) should be 0.04s (delay) following the last odd-numbered dequeue event.
488  double nextDelay = (2 * delay) + 0.02; // 20ms after first enqueue to attempt the first dequeue;
489  for (uint32_t i = 1; i <= nPkt; i++)
490  {
491  if (i % 2 == 1)
492  {
493  Simulator::Schedule(Seconds(nextDelay),
495  this,
496  queue,
497  true,
498  "1st packet should not be blocked");
499  nextDelay += 0.04;
500  }
501  else
502  {
503  Simulator::Schedule(Seconds(nextDelay),
505  this,
506  queue,
507  false,
508  "This packet should be blocked");
509  nextDelay += 0.06; // Need 0.04 + 0.06 seconds to allow the next packet to be dequeued
510  // without block
511  }
512  }
513  Simulator::Stop(Seconds(0.55));
514  Simulator::Run();
515 }
516 
517 void
519 {
520  queue->Enqueue(Create<TbfQueueDiscTestItem>(Create<Packet>(size), dest));
521 }
522 
523 void
525  bool flag,
526  std::string printStatement)
527 {
528  Ptr<QueueDiscItem> item = queue->Dequeue();
529  NS_TEST_EXPECT_MSG_EQ((item != nullptr), flag, printStatement);
530 }
531 
532 void
534 {
537  Simulator::Destroy();
538 }
539 
545 static class TbfQueueDiscTestSuite : public TestSuite
546 {
547  public:
549  : TestSuite("tbf-queue-disc", UNIT)
550  {
551  AddTestCase(new TbfQueueDiscTestCase(), TestCase::QUICK);
552  }
Tbf Queue Disc Test Case.
void RunTbfTest(QueueSizeUnit mode)
Run TBF test function.
void DoRun() override
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.
TbfQueueDiscTestItem()=delete
bool Mark() override
Marks the packet as a substitute for dropping it, such as for Explicit Congestion Notification.
TbfQueueDiscTestItem(const TbfQueueDiscTestItem &)=delete
TbfQueueDiscTestItem & operator=(const TbfQueueDiscTestItem &)=delete
void AddHeader() override
Add the header to the packet.
Tbf Queue Disc Test Suite.
a polymophic address class
Definition: address.h:101
Class for representing data rates.
Definition: data-rate.h:89
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:138
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition: object.cc:259
uint64_t GetUid() const
Returns the packet's Uid.
Definition: packet.cc:412
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:96
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:301
A suite of tests to run.
Definition: test.h:1256
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1265
Hold an unsigned integer type.
Definition: uinteger.h:45
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:890
void(* DataRate)(DataRate oldValue, DataRate newValue)
TracedValue callback signature for DataRate.
Definition: data-rate.h:327
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_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:144
#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
#define NS_TEST_ASSERT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report and abort if not.
Definition: test.h:564
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
TbfQueueDiscTestSuite g_tbfQueueTestSuite
the test suite
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:839
Every class exported by the ns3 library is enclosed in the ns3 namespace.
uint32_t pktSize
packet size used for the simulation (in bytes)