A Discrete-Event Network Simulator
API
queue-disc-traces-test-suite.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 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  * Authors: Stefano Avallone <stavallo@unina.it>
18  *
19  */
20 
21 #include "ns3/drop-tail-queue.h"
22 #include "ns3/packet.h"
23 #include "ns3/queue-disc.h"
24 #include "ns3/simulator.h"
25 #include "ns3/test.h"
26 
27 #include <map>
28 
29 using namespace ns3;
30 
36 class QdTestItem : public QueueDiscItem
37 {
38  public:
45  QdTestItem(Ptr<Packet> p, const Address& addr);
46  ~QdTestItem() override;
47  void AddHeader() override;
48  bool Mark() override;
49 };
50 
52  : QueueDiscItem(p, addr, 0)
53 {
54 }
55 
57 {
58 }
59 
60 void
62 {
63 }
64 
65 bool
67 {
68  return false;
69 }
70 
77 {
78  public:
83  ~TestChildQueueDisc() override;
84  bool DoEnqueue(Ptr<QueueDiscItem> item) override;
85  Ptr<QueueDiscItem> DoDequeue() override;
86  bool CheckConfig() override;
87  void InitializeParams() override;
88 
89  // Reasons for dropping packets
90  static constexpr const char* BEFORE_ENQUEUE = "Before enqueue";
91  static constexpr const char* AFTER_DEQUEUE = "After dequeue";
92 };
93 
96 {
97 }
98 
100 {
101 }
102 
103 bool
105 {
106  // Drop the packet if there are already 4 packets queued
107  if (GetNPackets() >= 4)
108  {
110  return false;
111  }
112  return GetInternalQueue(0)->Enqueue(item);
113 }
114 
117 {
118  Ptr<QueueDiscItem> item = GetInternalQueue(0)->Dequeue();
119 
120  // Drop the packet if at least 2 packets remain in the queue
121  while (GetNPackets() >= 2)
122  {
124  item = GetInternalQueue(0)->Dequeue();
125  }
126  return item;
127 }
128 
129 bool
131 {
133  return true;
134 }
135 
136 void
138 {
139 }
140 
147 {
148  public:
153  ~TestParentQueueDisc() override;
154  bool DoEnqueue(Ptr<QueueDiscItem> item) override;
155  Ptr<QueueDiscItem> DoDequeue() override;
156  bool CheckConfig() override;
157  void InitializeParams() override;
158 };
159 
162 {
163 }
164 
166 {
167 }
168 
169 bool
171 {
172  return GetQueueDiscClass(0)->GetQueueDisc()->Enqueue(item);
173 }
174 
177 {
178  return GetQueueDiscClass(0)->GetQueueDisc()->Dequeue();
179 }
180 
181 bool
183 {
184  Ptr<QueueDiscClass> c = CreateObject<QueueDiscClass>();
185  c->SetQueueDisc(CreateObject<TestChildQueueDisc>());
187  return true;
188 }
189 
190 void
192 {
193 }
194 
201 {
202  public:
206  TestCounter();
207  virtual ~TestCounter();
208 
213  void ConnectTraces(Ptr<QueueDisc> qd);
214 
215  private:
231  void PacketDbe(Ptr<const QueueDiscItem> item, const char* reason);
237  void PacketDad(Ptr<const QueueDiscItem> item, const char* reason);
238 
239  uint32_t m_nPackets;
240  uint32_t m_nBytes;
241  uint32_t m_nDbePackets;
242  uint32_t m_nDbeBytes;
243  uint32_t m_nDadPackets;
244  uint32_t m_nDadBytes;
245 
246  friend class QueueDiscTracesTestCase;
247 };
248 
250  : m_nPackets(0),
251  m_nBytes(0),
252  m_nDbePackets(0),
253  m_nDbeBytes(0),
254  m_nDadPackets(0),
255  m_nDadBytes(0)
256 {
257 }
258 
260 {
261 }
262 
263 void
265 {
266  m_nPackets++;
267  m_nBytes += item->GetSize();
268 }
269 
270 void
272 {
273  m_nPackets--;
274  m_nBytes -= item->GetSize();
275 }
276 
277 void
279 {
280  m_nDbePackets++;
281  m_nDbeBytes += item->GetSize();
282 }
283 
284 void
286 {
287  m_nDadPackets++;
288  m_nDadBytes += item->GetSize();
289 }
290 
291 void
293 {
296  qd->TraceConnectWithoutContext("DropBeforeEnqueue",
298  qd->TraceConnectWithoutContext("DropAfterDequeue", MakeCallback(&TestCounter::PacketDad, this));
299 }
300 
317 {
318  public:
320  void DoRun() override;
321 
328  void CheckQueued(Ptr<QueueDisc> qd, uint32_t nPackets, uint32_t nBytes);
335  void CheckDroppedBeforeEnqueue(Ptr<QueueDisc> qd, uint32_t nDbePackets, uint32_t nDbeBytes);
342  void CheckDroppedAfterDequeue(Ptr<QueueDisc> qd, uint32_t nDadPackets, uint32_t nDadBytes);
343 
344  private:
345  std::map<Ptr<QueueDisc>, TestCounter> m_counter;
346 };
347 
349  : TestCase("Sanity check on the queue disc traces and statistics")
350 {
351 }
352 
353 void
354 QueueDiscTracesTestCase::CheckQueued(Ptr<QueueDisc> qd, uint32_t nPackets, uint32_t nBytes)
355 {
357  nPackets,
358  "Verify that the number of queued packets is computed correctly");
359  NS_TEST_ASSERT_MSG_EQ(m_counter[qd].m_nPackets,
360  nPackets,
361  "Verify that the number of queued packets is computed correctly");
362 
364  nBytes,
365  "Verify that the number of queued bytes is computed correctly");
366  NS_TEST_ASSERT_MSG_EQ(m_counter[qd].m_nBytes,
367  nBytes,
368  "Verify that the number of queued bytes is computed correctly");
369 }
370 
371 void
373  uint32_t nDbePackets,
374  uint32_t nDbeBytes)
375 {
376  QueueDisc::Stats stats = qd->GetStats();
377 
380  nDbePackets,
381  "Verify that the number of packets dropped before enqueue is computed correctly");
383  m_counter[qd].m_nDbePackets,
384  nDbePackets,
385  "Verify that the number of packets dropped before enqueue is computed correctly");
386 
389  nDbeBytes,
390  "Verify that the number of bytes dropped before enqueue is computed correctly");
392  m_counter[qd].m_nDbeBytes,
393  nDbeBytes,
394  "Verify that the number of bytes dropped before enqueue is computed correctly");
395 }
396 
397 void
399  uint32_t nDadPackets,
400  uint32_t nDadBytes)
401 {
402  QueueDisc::Stats stats = qd->GetStats();
403 
406  nDadPackets,
407  "Verify that the number of packets dropped after dequeue is computed correctly");
409  m_counter[qd].m_nDadPackets,
410  nDadPackets,
411  "Verify that the number of packets dropped after dequeue is computed correctly");
412 
415  nDadBytes,
416  "Verify that the number of bytes dropped after dequeue is computed correctly");
418  m_counter[qd].m_nDadBytes,
419  nDadBytes,
420  "Verify that the number of bytes dropped after dequeue is computed correctly");
421 }
422 
423 void
425 {
426  Address dest;
427  uint32_t pktSizeUnit = 100;
429 
430  // Create queue discs
431  Ptr<QueueDisc> root = CreateObject<TestParentQueueDisc>();
432  root->Initialize();
433 
434  Ptr<QueueDisc> child = root->GetQueueDiscClass(0)->GetQueueDisc();
435 
436  NS_TEST_ASSERT_MSG_NE(child, nullptr, "The child queue disc has not been created");
437 
438  // Create counters and connect traces to the counters
439  m_counter.emplace(root, TestCounter());
440  m_counter.emplace(child, TestCounter());
441 
442  m_counter[root].ConnectTraces(root);
443  m_counter[child].ConnectTraces(child);
444 
445  // Enqueue 4 packets. They must all be enqueued
446  for (uint16_t i = 1; i <= 4; i++)
447  {
448  root->Enqueue(Create<QdTestItem>(Create<Packet>(pktSizeUnit * i), dest));
449 
450  CheckQueued(root, i, pktSizeUnit * i * (i + 1) / 2);
451  CheckDroppedBeforeEnqueue(root, 0, 0);
452  CheckDroppedAfterDequeue(root, 0, 0);
453 
454  CheckQueued(child, i, pktSizeUnit * i * (i + 1) / 2);
455  CheckDroppedBeforeEnqueue(child, 0, 0);
456  CheckDroppedAfterDequeue(child, 0, 0);
457  }
458 
459  // The fifth packet is dropped before enqueue by the child queue disc.
460  // The packet drop is notified to the root queue disc.
461  root->Enqueue(Create<QdTestItem>(Create<Packet>(pktSizeUnit * 5), dest));
462 
463  CheckQueued(root, 4, pktSizeUnit * 10);
464  CheckDroppedBeforeEnqueue(root, 1, pktSizeUnit * 5);
465  CheckDroppedAfterDequeue(root, 0, 0);
466 
467  CheckQueued(child, 4, pktSizeUnit * 10);
468  CheckDroppedBeforeEnqueue(child, 1, pktSizeUnit * 5);
469  CheckDroppedAfterDequeue(child, 0, 0);
470 
471  // Peek one packet. The default DoPeek method asks the root queue disc to dequeue
472  // a packet, even though the statistics are not updated and the dequeue trace is
473  // not fired. The root queue disc asks the child queue disc to dequeue a packet.
474  // In this case, two packets (those having size of 100 and 200 bytes) are dequeued
475  // and dropped by the child queue disc. Therefore, the dequeue trace of the root
476  // queue disc is fired twice and the packet drops are notified to the root queue
477  // disc to reflect the fact that two packets are no longer in the queue disc.
478  // The peeked packet is still part of the root queue disc, but no longer part
479  // of the child queue disc.
480  item = root->Peek();
481 
482  NS_TEST_ASSERT_MSG_NE(item, nullptr, "A packet must have been returned");
483  NS_TEST_ASSERT_MSG_EQ(item->GetSize(),
484  pktSizeUnit * 3,
485  "The peeked packet has not the expected size");
486 
487  CheckQueued(root, 2, pktSizeUnit * 7);
488  CheckDroppedBeforeEnqueue(root, 1, pktSizeUnit * 5);
489  CheckDroppedAfterDequeue(root, 2, pktSizeUnit * 3);
490 
491  CheckQueued(child, 1, pktSizeUnit * 4);
492  CheckDroppedBeforeEnqueue(child, 1, pktSizeUnit * 5);
493  CheckDroppedAfterDequeue(child, 2, pktSizeUnit * 3);
494 
495  // Peek again. Nothing changes.
496  item = root->Peek();
497 
498  NS_TEST_ASSERT_MSG_NE(item, nullptr, "A packet must have been returned");
499  NS_TEST_ASSERT_MSG_EQ(item->GetSize(),
500  pktSizeUnit * 3,
501  "The peeked packet has not the expected size");
502 
503  CheckQueued(root, 2, pktSizeUnit * 7);
504  CheckDroppedBeforeEnqueue(root, 1, pktSizeUnit * 5);
505  CheckDroppedAfterDequeue(root, 2, pktSizeUnit * 3);
506 
507  CheckQueued(child, 1, pktSizeUnit * 4);
508  CheckDroppedBeforeEnqueue(child, 1, pktSizeUnit * 5);
509  CheckDroppedAfterDequeue(child, 2, pktSizeUnit * 3);
510 
511  // Dequeue one packet. The root queue disc returns the previously peeked packet.
512  item = root->Dequeue();
513 
514  NS_TEST_ASSERT_MSG_NE(item, nullptr, "A packet must have been returned");
515  NS_TEST_ASSERT_MSG_EQ(item->GetSize(),
516  pktSizeUnit * 3,
517  "The dequeued packet has not the expected size");
518 
519  CheckQueued(root, 1, pktSizeUnit * 4);
520  CheckDroppedBeforeEnqueue(root, 1, pktSizeUnit * 5);
521  CheckDroppedAfterDequeue(root, 2, pktSizeUnit * 3);
522 
523  CheckQueued(child, 1, pktSizeUnit * 4);
524  CheckDroppedBeforeEnqueue(child, 1, pktSizeUnit * 5);
525  CheckDroppedAfterDequeue(child, 2, pktSizeUnit * 3);
526 
527  // Dequeue the last packet.
528  item = root->Dequeue();
529 
530  NS_TEST_ASSERT_MSG_NE(item, nullptr, "A packet must have been returned");
531  NS_TEST_ASSERT_MSG_EQ(item->GetSize(),
532  pktSizeUnit * 4,
533  "The dequeued packet has not the expected size");
534 
535  CheckQueued(root, 0, 0);
536  CheckDroppedBeforeEnqueue(root, 1, pktSizeUnit * 5);
537  CheckDroppedAfterDequeue(root, 2, pktSizeUnit * 3);
538 
539  CheckQueued(child, 0, 0);
540  CheckDroppedBeforeEnqueue(child, 1, pktSizeUnit * 5);
541  CheckDroppedAfterDequeue(child, 2, pktSizeUnit * 3);
542 
543  // Peek a packet. No packet is left.
544  item = root->Peek();
545 
546  NS_TEST_ASSERT_MSG_EQ(item, nullptr, "No packet must have been returned");
547 
548  CheckQueued(root, 0, 0);
549  CheckDroppedBeforeEnqueue(root, 1, pktSizeUnit * 5);
550  CheckDroppedAfterDequeue(root, 2, pktSizeUnit * 3);
551 
552  CheckQueued(child, 0, 0);
553  CheckDroppedBeforeEnqueue(child, 1, pktSizeUnit * 5);
554  CheckDroppedAfterDequeue(child, 2, pktSizeUnit * 3);
555 
556  // Enqueue one packet.
557  root->Enqueue(Create<QdTestItem>(Create<Packet>(pktSizeUnit), dest));
558 
559  CheckQueued(root, 1, pktSizeUnit);
560  CheckDroppedBeforeEnqueue(root, 1, pktSizeUnit * 5);
561  CheckDroppedAfterDequeue(root, 2, pktSizeUnit * 3);
562 
563  CheckQueued(child, 1, pktSizeUnit);
564  CheckDroppedBeforeEnqueue(child, 1, pktSizeUnit * 5);
565  CheckDroppedAfterDequeue(child, 2, pktSizeUnit * 3);
566 
567  // Dequeue one packet.
568  item = root->Dequeue();
569 
570  NS_TEST_ASSERT_MSG_NE(item, nullptr, "A packet must have been returned");
571  NS_TEST_ASSERT_MSG_EQ(item->GetSize(),
572  pktSizeUnit,
573  "The dequeued packet has not the expected size");
574 
575  CheckQueued(root, 0, 0);
576  CheckDroppedBeforeEnqueue(root, 1, pktSizeUnit * 5);
577  CheckDroppedAfterDequeue(root, 2, pktSizeUnit * 3);
578 
579  CheckQueued(child, 0, 0);
580  CheckDroppedBeforeEnqueue(child, 1, pktSizeUnit * 5);
581  CheckDroppedAfterDequeue(child, 2, pktSizeUnit * 3);
582 
583  Simulator::Destroy();
584 }
585 
591 static class QueueDiscTracesTestSuite : public TestSuite
592 {
593  public:
595  : TestSuite("queue-disc-traces", UNIT)
596  {
597  AddTestCase(new QueueDiscTracesTestCase(), TestCase::QUICK);
598  }
Queue Disc Test Item.
void AddHeader() override
Add the header to the packet.
bool Mark() override
Marks the packet as a substitute for dropping it, such as for Explicit Congestion Notification.
QdTestItem(Ptr< Packet > p, const Address &addr)
Constructor.
Queue Disc Traces Test Case.
void DoRun() override
Implementation to actually run this TestCase.
std::map< Ptr< QueueDisc >, TestCounter > m_counter
counters for the queue discs
void CheckDroppedAfterDequeue(Ptr< QueueDisc > qd, uint32_t nDadPackets, uint32_t nDadBytes)
Check that packets/bytes dropped after dequeue are consistent with what is expected.
void CheckDroppedBeforeEnqueue(Ptr< QueueDisc > qd, uint32_t nDbePackets, uint32_t nDbeBytes)
Check that packets/bytes dropped before enqueue are consistent with what is expected.
void CheckQueued(Ptr< QueueDisc > qd, uint32_t nPackets, uint32_t nBytes)
Check that queued packets/bytes are consistent with what is expected.
Queue Disc Traces Test Suite.
Test Child Queue Disc that may drop packets before enqueue or after dequeue.
static constexpr const char * AFTER_DEQUEUE
Drop after dequeue.
bool DoEnqueue(Ptr< QueueDiscItem > item) override
This function actually enqueues a packet into the queue disc.
Ptr< QueueDiscItem > DoDequeue() override
This function actually extracts a packet from the queue disc.
void InitializeParams() override
Initialize parameters (if any) before the first packet is enqueued.
static constexpr const char * BEFORE_ENQUEUE
Drop before enqueue.
bool CheckConfig() override
Check whether the current configuration is correct.
Keep statistics based on traces.
void PacketDequeued(Ptr< const QueueDiscItem > item)
Update statistics after a packet has been dequeued.
void PacketDad(Ptr< const QueueDiscItem > item, const char *reason)
Update statistics after a packet has been dropped after dequeue.
void PacketDbe(Ptr< const QueueDiscItem > item, const char *reason)
Update statistics after a packet has been dropped before enqueue.
uint32_t m_nDbeBytes
Number of packets dropped before enqueue.
void PacketEnqueued(Ptr< const QueueDiscItem > item)
Update statistics after a packet has been enqueued.
uint32_t m_nPackets
Number of queued packets.
uint32_t m_nBytes
Number of queued bytes.
uint32_t m_nDbePackets
Number of packets dropped before enqueue.
uint32_t m_nDadBytes
Number of packets dropped after dequeue.
uint32_t m_nDadPackets
Number of packets dropped after dequeue.
void ConnectTraces(Ptr< QueueDisc > qd)
Connect private methods to the queue disc traces.
Test Parent Queue Disc having a child of type TestChildQueueDisc.
Ptr< QueueDiscItem > DoDequeue() override
This function actually extracts a packet from the queue disc.
bool CheckConfig() override
Check whether the current configuration is correct.
void InitializeParams() override
Initialize parameters (if any) before the first packet is enqueued.
bool DoEnqueue(Ptr< QueueDiscItem > item) override
This function actually enqueues a packet into the queue disc.
a polymophic address class
Definition: address.h:101
A FIFO packet queue that drops tail-end packets on overflow.
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
Definition: object-base.cc:315
void Initialize()
Invoke DoInitialize on all Objects aggregated to this one.
Definition: object.cc:186
QueueDisc is an abstract base class providing the interface and implementing the operations common to...
Definition: queue-disc.h:184
void AddInternalQueue(Ptr< InternalQueue > queue)
Add an internal queue to the tail of the list of queues.
Definition: queue-disc.cc:573
void AddQueueDiscClass(Ptr< QueueDiscClass > qdClass)
Add a queue disc class to the tail of the list of classes.
Definition: queue-disc.cc:624
uint32_t GetNPackets() const
Get the number of packets stored by the queue disc.
Definition: queue-disc.cc:432
uint32_t GetNBytes() const
Get the amount of bytes stored by the queue disc.
Definition: queue-disc.cc:439
Ptr< InternalQueue > GetInternalQueue(std::size_t i) const
Get the i-th internal queue.
Definition: queue-disc.cc:591
void DropAfterDequeue(Ptr< const QueueDiscItem > item, const char *reason)
Perform the actions required when the queue disc is notified of a packet dropped after dequeue.
Definition: queue-disc.cc:759
const Stats & GetStats()
Retrieve all the collected statistics.
Definition: queue-disc.cc:412
Ptr< QueueDiscClass > GetQueueDiscClass(std::size_t i) const
Get the i-th queue disc class.
Definition: queue-disc.cc:654
Ptr< QueueDiscItem > Dequeue()
Extract from the queue disc the packet that has been dequeued by calling Peek, if any,...
Definition: queue-disc.cc:886
Ptr< const QueueDiscItem > Peek()
Get a copy of the next packet the queue discipline will extract.
Definition: queue-disc.cc:920
void DropBeforeEnqueue(Ptr< const QueueDiscItem > item, const char *reason)
Perform the actions required when the queue disc is notified of a packet dropped before enqueue.
Definition: queue-disc.cc:720
bool Enqueue(Ptr< QueueDiscItem > item)
Pass a packet to store to the queue discipline.
Definition: queue-disc.cc:851
QueueDiscItem is the abstract base class for items that are stored in a queue disc.
Definition: queue-item.h:133
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
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition: object.h:579
#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_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
QueueDiscTracesTestSuite g_queueDiscTracesTestSuite
the test suite
QueueDiscSizePolicy
Enumeration of the available policies to handle the queue disc size.
Definition: queue-disc.h:107
@ SINGLE_INTERNAL_QUEUE
Used by queue discs with single internal queue.
Definition: queue-disc.h:108
@ SINGLE_CHILD_QUEUE_DISC
Used by queue discs with single child queue disc.
Definition: queue-disc.h:109
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:704
Structure that keeps the queue disc statistics.
Definition: queue-disc.h:188
uint64_t nTotalDroppedBytesBeforeEnqueue
Total bytes dropped before enqueue.
Definition: queue-disc.h:218
uint64_t nTotalDroppedBytesAfterDequeue
Total bytes dropped after dequeue.
Definition: queue-disc.h:222
uint32_t nTotalDroppedPacketsBeforeEnqueue
Total packets dropped before enqueue.
Definition: queue-disc.h:208
uint32_t nTotalDroppedPacketsAfterDequeue
Total packets dropped after dequeue.
Definition: queue-disc.h:212