A Discrete-Event Network Simulator
API
cobalt-queue-disc-test-suite.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019 NITK Surathkal
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  * Ported to ns-3 by: Vignesh Kannan <vignesh2496@gmail.com>
18  * Harsh Lara <harshapplefan@gmail.com>
19  * Jendaipou Palmei <jendaipoupalmei@gmail.com>
20  * Shefali Gupta <shefaligups11@gmail.com>
21  * Mohit P. Tahiliani <tahiliani@nitk.edu.in>
22  */
23 
24 #include "ns3/cobalt-queue-disc.h"
25 #include "ns3/double.h"
26 #include "ns3/log.h"
27 #include "ns3/packet.h"
28 #include "ns3/simulator.h"
29 #include "ns3/string.h"
30 #include "ns3/test.h"
31 #include "ns3/uinteger.h"
32 
33 using namespace ns3;
34 
41 {
42  public:
50  CobaltQueueDiscTestItem(Ptr<Packet> p, const Address& addr, bool ecnCapable);
51  ~CobaltQueueDiscTestItem() override;
52 
53  // Delete default constructor, copy constructor and assignment operator to avoid misuse
57 
58  void AddHeader() override;
59  bool Mark() override;
60 
61  private:
63 };
64 
66  const Address& addr,
67  bool ecnCapable)
68  : QueueDiscItem(p, addr, 0),
69  m_ecnCapablePacket(ecnCapable)
70 {
71 }
72 
74 {
75 }
76 
77 void
79 {
80 }
81 
82 bool
84 {
86  {
87  return true;
88  }
89  return false;
90 }
91 
98 {
99  public:
106  void DoRun() override;
107 
116  private:
118 };
119 
121  : TestCase("Basic enqueue and dequeue operations, and attribute setting" + std::to_string(mode))
122 {
123  m_mode = mode;
124 }
125 
126 void
128 {
129  Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
130 
131  uint32_t pktSize = 1000;
132  uint32_t modeSize = 0;
133 
134  Address dest;
135 
136  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Interval", StringValue("50ms")),
137  true,
138  "Verify that we can actually set the attribute Interval");
139  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Target", StringValue("4ms")),
140  true,
141  "Verify that we can actually set the attribute Target");
142  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
143  true,
144  "Disable Blue enhancement");
145 
147  {
148  modeSize = pktSize;
149  }
150  else if (m_mode == QueueSizeUnit::PACKETS)
151  {
152  modeSize = 1;
153  }
155  queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 1500))),
156  true,
157  "Verify that we can actually set the attribute MaxSize");
158  queue->Initialize();
159 
160  Ptr<Packet> p1;
161  Ptr<Packet> p2;
162  Ptr<Packet> p3;
163  Ptr<Packet> p4;
164  Ptr<Packet> p5;
165  Ptr<Packet> p6;
166  p1 = Create<Packet>(pktSize);
167  p2 = Create<Packet>(pktSize);
168  p3 = Create<Packet>(pktSize);
169  p4 = Create<Packet>(pktSize);
170  p5 = Create<Packet>(pktSize);
171  p6 = Create<Packet>(pktSize);
172 
173  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
174  0 * modeSize,
175  "There should be no packets in queue");
176  queue->Enqueue(Create<CobaltQueueDiscTestItem>(p1, dest, false));
177  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
178  1 * modeSize,
179  "There should be one packet in queue");
180  queue->Enqueue(Create<CobaltQueueDiscTestItem>(p2, dest, false));
181  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
182  2 * modeSize,
183  "There should be two packets in queue");
184  queue->Enqueue(Create<CobaltQueueDiscTestItem>(p3, dest, false));
185  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
186  3 * modeSize,
187  "There should be three packets in queue");
188  queue->Enqueue(Create<CobaltQueueDiscTestItem>(p4, dest, false));
189  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
190  4 * modeSize,
191  "There should be four packets in queue");
192  queue->Enqueue(Create<CobaltQueueDiscTestItem>(p5, dest, false));
193  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
194  5 * modeSize,
195  "There should be five packets in queue");
196  queue->Enqueue(Create<CobaltQueueDiscTestItem>(p6, dest, false));
197  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
198  6 * modeSize,
199  "There should be six packets in queue");
200 
201  NS_TEST_ASSERT_MSG_EQ(queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::OVERLIMIT_DROP),
202  0,
203  "There should be no packets being dropped due to full queue");
204 
205  Ptr<QueueDiscItem> item;
206 
207  item = queue->Dequeue();
208  NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the first packet");
209  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
210  5 * modeSize,
211  "There should be five packets in queue");
212  NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p1->GetUid(), "was this the first packet ?");
213 
214  item = queue->Dequeue();
215  NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the second packet");
216  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
217  4 * modeSize,
218  "There should be four packets in queue");
219  NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(),
220  p2->GetUid(),
221  "Was this the second packet ?");
222 
223  item = queue->Dequeue();
224  NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the third packet");
225  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
226  3 * modeSize,
227  "There should be three packets in queue");
228  NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p3->GetUid(), "Was this the third packet ?");
229 
230  item = queue->Dequeue();
231  NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the forth packet");
232  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
233  2 * modeSize,
234  "There should be two packets in queue");
235  NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(),
236  p4->GetUid(),
237  "Was this the fourth packet ?");
238 
239  item = queue->Dequeue();
240  NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the fifth packet");
241  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
242  1 * modeSize,
243  "There should be one packet in queue");
244  NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p5->GetUid(), "Was this the fifth packet ?");
245 
246  item = queue->Dequeue();
247  NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the last packet");
248  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
249  0 * modeSize,
250  "There should be zero packet in queue");
251  NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p6->GetUid(), "Was this the sixth packet ?");
252 
253  item = queue->Dequeue();
254  NS_TEST_ASSERT_MSG_EQ(item, nullptr, "There are really no packets in queue");
255 
257  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
258  0,
259  "There should be no packet drops according to Cobalt algorithm");
260 }
261 
268 {
269  public:
271  void DoRun() override;
278  void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
283  void RunDropTest(QueueSizeUnit mode);
292  void EnqueueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
293 };
294 
296  : TestCase("Drop tests verification for both packets and bytes mode")
297 {
298 }
299 
300 void
302 
303 {
304  uint32_t pktSize = 1500;
305  uint32_t modeSize = 0;
306  Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
307 
308  if (mode == QueueSizeUnit::BYTES)
309  {
310  modeSize = pktSize;
311  }
312  else if (mode == QueueSizeUnit::PACKETS)
313  {
314  modeSize = 1;
315  }
316 
317  queue = CreateObject<CobaltQueueDisc>();
319  queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(mode, modeSize * 100))),
320  true,
321  "Verify that we can actually set the attribute MaxSize");
322  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
323  true,
324  "Disable Blue enhancement");
325  queue->Initialize();
326 
327  if (mode == QueueSizeUnit::BYTES)
328  {
329  EnqueueWithDelay(queue, pktSize, 200);
330  }
331  else
332  {
333  EnqueueWithDelay(queue, 1, 200);
334  }
335 
336  Simulator::Stop(Seconds(8.0));
337  Simulator::Run();
338 
339  QueueDisc::Stats st = queue->GetStats();
340 
341  // The Pdrop value should increase, from it's default value of zero
342  NS_TEST_ASSERT_MSG_NE(queue->GetPdrop(), 0, "Pdrop should be non-zero");
343  NS_TEST_ASSERT_MSG_NE(st.GetNDroppedPackets(CobaltQueueDisc::OVERLIMIT_DROP),
344  0,
345  "Drops due to queue overflow should be non-zero");
346 }
347 
348 void
350 {
351  Address dest;
352  double delay = 0.01; // enqueue packets with delay
353  for (uint32_t i = 0; i < nPkt; i++)
354  {
355  Simulator::Schedule(Time(Seconds((i + 1) * delay)),
357  this,
358  queue,
359  size,
360  1);
361  }
362 }
363 
364 void
365 CobaltQueueDiscDropTest::Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt)
366 {
367  Address dest;
368  for (uint32_t i = 0; i < nPkt; i++)
369  {
370  queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, true));
371  }
372 }
373 
374 void
376 {
379  Simulator::Destroy();
380 }
381 
388 {
389  public:
396  void DoRun() override;
397 
398  private:
406  void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, bool ecnCapable);
413  void Dequeue(Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t testCase);
419  void DropNextTracer(int64_t oldVal, int64_t newVal);
421  uint32_t m_dropNextCount;
424 };
425 
427  : TestCase("Basic mark operations")
428 {
429  m_mode = mode;
430  m_dropNextCount = 0;
431 }
432 
433 void
434 CobaltQueueDiscMarkTest::DropNextTracer(int64_t /* oldVal */, int64_t /* newVal */)
435 {
436  m_dropNextCount++;
437 }
438 
439 void
441 {
442  // Test is divided into 3 sub test cases:
443  // 1) Packets are not ECN capable.
444  // 2) Packets are ECN capable.
445  // 3) Some packets are ECN capable.
446 
447  // Test case 1
448  Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
449  uint32_t pktSize = 1000;
450  uint32_t modeSize = 0;
453 
455  {
456  modeSize = pktSize;
457  }
458  else if (m_mode == QueueSizeUnit::PACKETS)
459  {
460  modeSize = 1;
461  }
462 
464  queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
465  true,
466  "Verify that we can actually set the attribute MaxSize");
467  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(false)),
468  true,
469  "Verify that we can actually set the attribute UseEcn");
470  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
471  true,
472  "Disable Blue enhancement");
473  queue->Initialize();
474 
475  // Not-ECT traffic to induce packet drop
476  Enqueue(queue, pktSize, 20, false);
477  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
478  20 * modeSize,
479  "There should be 20 packets in queue.");
480 
481  // Although the first dequeue occurs with a sojourn time above target
482  // there should not be any dropped packets in this interval
483  Time waitUntilFirstDequeue = 2 * queue->GetTarget();
484  Simulator::Schedule(waitUntilFirstDequeue,
486  this,
487  queue,
488  modeSize,
489  1);
490 
491  // This dequeue should cause a packet to be dropped
492  Time waitUntilSecondDequeue = waitUntilFirstDequeue + 2 * queue->GetInterval();
493  Simulator::Schedule(waitUntilSecondDequeue,
495  this,
496  queue,
497  modeSize,
498  1);
499 
500  Simulator::Run();
501  Simulator::Destroy();
502 
503  // Test case 2, queue with ECN capable traffic for marking of packets instead of dropping
504  queue = CreateObject<CobaltQueueDisc>();
506  queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
507  true,
508  "Verify that we can actually set the attribute MaxSize");
509  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
510  true,
511  "Verify that we can actually set the attribute UseEcn");
512  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
513  true,
514  "Disable Blue enhancement");
515  queue->Initialize();
516 
517  // ECN capable traffic
518  Enqueue(queue, pktSize, 20, true);
519  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
520  20 * modeSize,
521  "There should be 20 packets in queue.");
522 
523  // Although the first dequeue occurs with a sojourn time above target
524  // there should not be any marked packets in this interval
525  Simulator::Schedule(waitUntilFirstDequeue,
527  this,
528  queue,
529  modeSize,
530  2);
531 
532  // This dequeue should cause a packet to be marked
533  Simulator::Schedule(waitUntilSecondDequeue,
535  this,
536  queue,
537  modeSize,
538  2);
539 
540  // This dequeue should cause a packet to be marked as dropnext is equal to current time
541  Simulator::Schedule(waitUntilSecondDequeue,
543  this,
544  queue,
545  modeSize,
546  2);
547 
548  // In dropping phase and it's time for next packet to be marked
549  // the dequeue should cause additional packet to be marked
550  Simulator::Schedule(waitUntilSecondDequeue * 2,
552  this,
553  queue,
554  modeSize,
555  2);
556 
557  Simulator::Run();
558  Simulator::Destroy();
559 
560  // Test case 3, some packets are ECN capable
561  queue = CreateObject<CobaltQueueDisc>();
563  queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
564  true,
565  "Verify that we can actually set the attribute MaxSize");
566  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
567  true,
568  "Verify that we can actually set the attribute UseEcn");
569  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
570  true,
571  "Disable Blue enhancement");
572  queue->Initialize();
573 
574  // First 3 packets in the queue are ecnCapable
575  Enqueue(queue, pktSize, 3, true);
576  // Rest of the packet are not ecnCapable
577  Enqueue(queue, pktSize, 17, false);
578  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
579  20 * modeSize,
580  "There should be 20 packets in queue.");
581 
582  // Although the first dequeue occurs with a sojourn time above target
583  // there should not be any marked packets in this interval
584  Simulator::Schedule(waitUntilFirstDequeue,
586  this,
587  queue,
588  modeSize,
589  3);
590 
591  // This dequeue should cause a packet to be marked
592  Simulator::Schedule(waitUntilSecondDequeue,
594  this,
595  queue,
596  modeSize,
597  3);
598 
599  // This dequeue should cause a packet to be marked as dropnext is equal to current time
600  Simulator::Schedule(waitUntilSecondDequeue,
602  this,
603  queue,
604  modeSize,
605  3);
606 
607  // In dropping phase and it's time for next packet to be dropped as packets are not ECN capable
608  // the dequeue should cause packet to be dropped
609  Simulator::Schedule(waitUntilSecondDequeue * 2,
611  this,
612  queue,
613  modeSize,
614  3);
615 
616  Simulator::Run();
617  Simulator::Destroy();
618 }
619 
620 void
622  uint32_t size,
623  uint32_t nPkt,
624  bool ecnCapable)
625 {
626  Address dest;
627  for (uint32_t i = 0; i < nPkt; i++)
628  {
629  queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, ecnCapable));
630  }
631 }
632 
633 void
634 CobaltQueueDiscMarkTest::Dequeue(Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t testCase)
635 {
636  uint32_t initialMarkCount = queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
637  uint32_t initialQSize = queue->GetCurrentSize().GetValue();
638  uint32_t initialDropNext = queue->GetDropNext();
639  Time currentTime = Simulator::Now();
640  uint32_t currentDropCount = 0;
641  uint32_t currentMarkCount = 0;
642 
643  if (initialMarkCount > 0 && currentTime.GetNanoSeconds() > initialDropNext && testCase == 3)
644  {
645  queue->TraceConnectWithoutContext(
646  "DropNext",
648  }
649 
650  if (initialQSize != 0)
651  {
652  Ptr<QueueDiscItem> item = queue->Dequeue();
653  if (testCase == 1)
654  {
655  currentDropCount =
656  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
657  if (currentDropCount != 0)
658  {
659  nPacketsBeforeFirstDrop = initialQSize;
660  }
661  }
662  if (testCase == 2)
663  {
664  if (initialMarkCount == 0 && currentTime > queue->GetTarget())
665  {
666  if (currentTime < queue->GetInterval())
667  {
668  currentDropCount =
669  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
670  currentMarkCount =
671  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
672  NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
673  initialQSize - modeSize,
674  "There should be 1 packet dequeued.");
675  NS_TEST_EXPECT_MSG_EQ(currentDropCount,
676  0,
677  "There should not be any packet drops");
678  NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
679  0,
680  "We are not in dropping state."
681  "Sojourn time has just gone above target from below."
682  "Hence, there should be no marked packets");
683  }
684  else if (currentTime >= queue->GetInterval())
685  {
686  nPacketsBeforeFirstMark = initialQSize;
687  currentDropCount =
688  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
689  currentMarkCount =
690  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
692  queue->GetCurrentSize().GetValue(),
693  initialQSize - modeSize,
694  "Sojourn time has been above target for at least interval."
695  "We enter the dropping state and perform initial packet marking"
696  "So there should be only 1 more packet dequeued.");
697  NS_TEST_EXPECT_MSG_EQ(currentDropCount,
698  0,
699  "There should not be any packet drops");
700  NS_TEST_EXPECT_MSG_EQ(currentMarkCount, 1, "There should be 1 marked packet");
701  }
702  }
703  else if (initialMarkCount > 0)
704  {
705  if (currentTime.GetNanoSeconds() <= initialDropNext)
706  {
707  currentDropCount =
708  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
709  currentMarkCount =
710  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
711  NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
712  initialQSize - modeSize,
713  "We are in dropping state."
714  "Sojourn is still above target."
715  "There should be only 1 more packet dequeued");
716  NS_TEST_EXPECT_MSG_EQ(currentDropCount,
717  0,
718  "There should not be any packet drops");
719  NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
720  2,
721  "There should be 2 marked packet as."
722  "current dropnext is equal to current time.");
723  }
724  else if (currentTime.GetNanoSeconds() > initialDropNext)
725  {
726  currentDropCount =
727  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
728  currentMarkCount =
729  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
730  NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
731  initialQSize - modeSize,
732  "We are in dropping state."
733  "It's time for packet to be marked"
734  "So there should be only 1 more packet dequeued");
735  NS_TEST_EXPECT_MSG_EQ(currentDropCount,
736  0,
737  "There should not be any packet drops");
738  NS_TEST_EXPECT_MSG_EQ(currentMarkCount, 3, "There should be 3 marked packet");
742  "Number of packets in the queue before drop should be equal"
743  "to number of packets in the queue before first mark as the behavior until "
744  "packet N should be the same.");
745  }
746  }
747  }
748  else if (testCase == 3)
749  {
750  if (initialMarkCount == 0 && currentTime > queue->GetTarget())
751  {
752  if (currentTime < queue->GetInterval())
753  {
754  currentDropCount =
755  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
756  currentMarkCount =
757  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
758  NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
759  initialQSize - modeSize,
760  "There should be 1 packet dequeued.");
761  NS_TEST_EXPECT_MSG_EQ(currentDropCount,
762  0,
763  "There should not be any packet drops");
764  NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
765  0,
766  "We are not in dropping state."
767  "Sojourn time has just gone above target from below."
768  "Hence, there should be no marked packets");
769  }
770  else if (currentTime >= queue->GetInterval())
771  {
772  currentDropCount =
773  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
774  currentMarkCount =
775  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
777  queue->GetCurrentSize().GetValue(),
778  initialQSize - modeSize,
779  "Sojourn time has been above target for at least interval."
780  "We enter the dropping state and perform initial packet marking"
781  "So there should be only 1 more packet dequeued.");
782  NS_TEST_EXPECT_MSG_EQ(currentDropCount,
783  0,
784  "There should not be any packet drops");
785  NS_TEST_EXPECT_MSG_EQ(currentMarkCount, 1, "There should be 1 marked packet");
786  }
787  }
788  else if (initialMarkCount > 0)
789  {
790  if (currentTime.GetNanoSeconds() <= initialDropNext)
791  {
792  currentDropCount =
793  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
794  currentMarkCount =
795  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
796  NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
797  initialQSize - modeSize,
798  "We are in dropping state."
799  "Sojourn is still above target."
800  "So there should be only 1 more packet dequeued");
801  NS_TEST_EXPECT_MSG_EQ(currentDropCount,
802  0,
803  "There should not be any packet drops");
804  NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
805  2,
806  "There should be 2 marked packet"
807  "as dropnext is equal to current time");
808  }
809  else if (currentTime.GetNanoSeconds() > initialDropNext)
810  {
811  currentDropCount =
812  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
813  currentMarkCount =
814  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
816  queue->GetCurrentSize().GetValue(),
817  initialQSize - (m_dropNextCount + 1) * modeSize,
818  "We are in dropping state."
819  "It's time for packet to be dropped as packets are not ecnCapable"
820  "The number of packets dequeued equals to the number of times m_dropNext "
821  "is updated plus initial dequeue");
823  currentDropCount,
825  "The number of drops equals to the number of times m_dropNext is updated");
826  NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
827  2,
828  "There should still be only 2 marked packet");
829  }
830  }
831  }
832  }
833 }
834 
841 {
842  public:
850 
851  private:
852  void DoRun() override;
859  void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
867  void EnqueueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, Time delay);
873  void Dequeue(Ptr<CobaltQueueDisc> queue, uint32_t modeSize);
881  void DequeueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t nPkt, Time delay);
883 };
884 
886  : TestCase("Test CE Threshold marking")
887 {
888  m_mode = mode;
889 }
890 
892 {
893 }
894 
895 void
897 {
898  Address dest;
899  for (uint32_t i = 0; i < nPkt; i++)
900  {
901  queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, true));
902  }
903 }
904 
905 void
907  uint32_t size,
908  uint32_t nPkt,
909  Time delay)
910 {
911  for (uint32_t i = 0; i < nPkt; i++)
912  {
913  Simulator::Schedule(Time(Seconds((i + 1) * delay.GetSeconds())),
915  this,
916  queue,
917  size,
918  1);
919  }
920 }
921 
922 void
924 {
925  Ptr<QueueDiscItem> item = queue->Dequeue();
926 
928  {
930  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
931  1,
932  "There should be only 1 packet"
933  "mark, the delay between the enqueueing of the packets decreased after the"
934  "1st mark (packet enqueued at 11ms) and increased for the packet enqueued after 20.6ms."
935  "Queue delay remains below or equal to 1ms for the packet enqueued before 28ms");
936  }
937  if (Simulator::Now() > MilliSeconds(31))
938  {
940  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
941  3,
942  "There should be 3 packet"
943  "marks, the delay between the enqueueing of the packets decreased after 1st mark"
944  "(packet enqueued at 11ms) and increased for the packet enqueued after 20.6ms."
945  "Queue delay remains below 1ms for the packets enqueued before 28ms and increases"
946  "for the packets enqueued after 28ms.");
947  }
948 }
949 
950 void
952  uint32_t modeSize,
953  uint32_t nPkt,
954  Time delay)
955 {
956  for (uint32_t i = 0; i < nPkt; i++)
957  {
958  Simulator::Schedule(Time(Seconds((i + 1) * delay.GetSeconds())),
960  this,
961  queue,
962  modeSize);
963  }
964 }
965 
966 void
968 {
969  Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
970  uint32_t pktSize = 1000;
971  uint32_t modeSize = 0;
972 
974  {
975  modeSize = pktSize;
976  }
977  else if (m_mode == QueueSizeUnit::PACKETS)
978  {
979  modeSize = 1;
980  }
981 
982  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
983  true,
984  "Verify that we can actually set the attribute UseEcn");
985  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("CeThreshold", TimeValue(MilliSeconds(1))),
986  true,
987  "Verify that we can actually set the attribute UseEcn");
988  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
989  true,
990  "Disable Blue enhancement");
991  queue->Initialize();
992 
993  // Enqueue 11 packets every 1ms
994  EnqueueWithDelay(queue, pktSize, 11, MilliSeconds(1));
995 
996  // With every dequeue, queue delay increases by 0.1ms as packet enqueues every 1ms while
997  // dequeues at 1.1ms so at 11th dequeue, the dequeued packet should be marked.
998  Time dequeueInterval = MicroSeconds(1100);
999  DequeueWithDelay(queue, modeSize, 11, dequeueInterval);
1000 
1001  // First mark occurred for the packet enqueued at 11ms, ideally TCP would decrease sending rate
1002  // which can be simulated by increasing interval between subsequent enqueues, so packets are now
1003  // enqueued with a delay 1.2ms.
1004  Time waitUntilFirstMark = MilliSeconds(11);
1005  Simulator::Schedule(waitUntilFirstMark,
1007  this,
1008  queue,
1009  pktSize,
1010  9,
1011  MicroSeconds(1200));
1012 
1013  // Keep dequeueing with the same delay
1014  Simulator::Schedule(waitUntilFirstMark,
1016  this,
1017  queue,
1018  modeSize,
1019  9,
1020  dequeueInterval);
1021 
1022  // Queue delay becomes 0.2ms for the packet enqueued at 20.6ms, time to decrease interval
1023  // between subsequent enqueues, as ideally TCP would again start increasing sending rate
1024  Time waitUntilDecreasingEnqueueDelay = waitUntilFirstMark + MilliSeconds(9);
1025  Simulator::Schedule(waitUntilDecreasingEnqueueDelay,
1027  this,
1028  queue,
1029  pktSize,
1030  10,
1031  MilliSeconds(1));
1032 
1033  // Keep dequeueing with the same delay
1034  Simulator::Schedule(waitUntilFirstMark,
1036  this,
1037  queue,
1038  modeSize,
1039  10,
1040  dequeueInterval);
1041 
1042  Simulator::Run();
1043  Simulator::Destroy();
1044 }
1045 
1059 {
1060  public:
1068 
1069  private:
1070  void DoRun() override;
1077  void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
1082  void Dequeue(Ptr<CobaltQueueDisc> queue);
1089  void DequeueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t nPkt, Time delay);
1091 };
1092 
1094  : TestCase("Enhanced Blue tests verification for both packets and bytes mode")
1095 {
1096  m_mode = mode;
1097 }
1098 
1100 {
1101 }
1102 
1103 void
1105 
1106 {
1107  uint32_t pktSize = 1500;
1108  uint32_t modeSize = 0;
1109  Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
1110 
1112  {
1113  modeSize = pktSize;
1114  }
1115  else if (m_mode == QueueSizeUnit::PACKETS)
1116  {
1117  modeSize = 1;
1118  }
1119  queue->Initialize();
1120  queue->AssignStreams(1);
1121  Enqueue(queue, modeSize, 200);
1122  DequeueWithDelay(queue, 100, MilliSeconds(10));
1123 
1124  Simulator::Stop(Seconds(8.0));
1125  Simulator::Run();
1126 
1127  QueueDisc::Stats st = queue->GetStats();
1128 
1129  // The Pdrop value should increase, from it's default value of zero
1131  queue->GetPdrop(),
1132  0.234375,
1133  "Pdrop should be increased by 1/256 for every packet whose sojourn time is above 400ms."
1134  " From the 41st dequeue until the last one, sojourn time is above 400ms, so 60 packets "
1135  "have sojourn time above 400ms"
1136  "hence Pdrop should be increased 60*(1/256) which is 0.234375");
1137  NS_TEST_ASSERT_MSG_EQ(st.GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1138  49,
1139  "There should a fixed number of drops (49 here)");
1140  Simulator::Destroy();
1141 
1142  queue = CreateObject<CobaltQueueDisc>();
1143  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
1144  true,
1145  "Verify that we can actually set the attribute UseEcn");
1146  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
1147  true,
1148  "Disable Blue enhancement");
1149  queue->Initialize();
1150  Enqueue(queue, modeSize, 200);
1151  DequeueWithDelay(queue, 100, MilliSeconds(10));
1152 
1153  Simulator::Stop(Seconds(8.0));
1154  Simulator::Run();
1155 
1156  st = queue->GetStats();
1157 
1158  NS_TEST_ASSERT_MSG_EQ(queue->GetPdrop(), 0, "Pdrop should be zero");
1159  NS_TEST_ASSERT_MSG_EQ(st.GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1160  0,
1161  "There should not any dropped packets");
1162  Simulator::Destroy();
1163 }
1164 
1165 void
1167 {
1168  Address dest;
1169  for (uint32_t i = 0; i < nPkt; i++)
1170  {
1171  queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, true));
1172  }
1173 }
1174 
1175 void
1177 {
1178  Ptr<QueueDiscItem> item = queue->Dequeue();
1179 }
1180 
1181 void
1183  uint32_t nPkt,
1184  Time delay)
1185 {
1186  for (uint32_t i = 0; i < nPkt; i++)
1187  {
1188  Simulator::Schedule(Time(Seconds((i + 1) * delay.GetSeconds())),
1190  this,
1191  queue);
1192  }
1193 }
1194 
1200 {
1201  public:
1203  : TestSuite("cobalt-queue-disc", UNIT)
1204  {
1205  // Test 1: simple enqueue/dequeue with no drops
1207  AddTestCase(new CobaltQueueDiscBasicEnqueueDequeue(BYTES), TestCase::QUICK);
1208  // Test 2: Drop test
1209  AddTestCase(new CobaltQueueDiscDropTest(), TestCase::QUICK);
1210  // Test 3: Mark test
1211  AddTestCase(new CobaltQueueDiscMarkTest(PACKETS), TestCase::QUICK);
1212  AddTestCase(new CobaltQueueDiscMarkTest(BYTES), TestCase::QUICK);
1213  // Test 4: CE threshold marking test
1214  AddTestCase(new CobaltQueueDiscCeThresholdTest(PACKETS), TestCase::QUICK);
1215  AddTestCase(new CobaltQueueDiscCeThresholdTest(BYTES), TestCase::QUICK);
1216  // Test 4: Blue enhancement test
1217  AddTestCase(new CobaltQueueDiscEnhancedBlueTest(PACKETS), TestCase::QUICK);
1218  AddTestCase(new CobaltQueueDiscEnhancedBlueTest(BYTES), TestCase::QUICK);
1219  }
#define Max(a, b)
Test 1: simple enqueue/dequeue with no drops.
QueueSizeUnit m_mode
Queue test size function.
void DoRun() override
Implementation to actually run this TestCase.
CobaltQueueDiscBasicEnqueueDequeue(QueueSizeUnit mode)
Constructor.
Test 4: Cobalt Queue Disc CE Threshold marking Test Item.
CobaltQueueDiscCeThresholdTest(QueueSizeUnit mode)
Constructor.
void DoRun() override
Implementation to actually run this TestCase.
void DequeueWithDelay(Ptr< CobaltQueueDisc > queue, uint32_t modeSize, uint32_t nPkt, Time delay)
Dequeue with delay function.
void Enqueue(Ptr< CobaltQueueDisc > queue, uint32_t size, uint32_t nPkt)
Enqueue function.
void EnqueueWithDelay(Ptr< CobaltQueueDisc > queue, uint32_t size, uint32_t nPkt, Time delay)
Enqueue with delay function.
void Dequeue(Ptr< CobaltQueueDisc > queue, uint32_t modeSize)
Dequeue function.
Test 2: Cobalt Queue Disc Drop Test Item.
void DoRun() override
Implementation to actually run this TestCase.
void RunDropTest(QueueSizeUnit mode)
Run Cobalt test function.
void Enqueue(Ptr< CobaltQueueDisc > queue, uint32_t size, uint32_t nPkt)
Enqueue function.
void EnqueueWithDelay(Ptr< CobaltQueueDisc > queue, uint32_t size, uint32_t nPkt)
Enqueue the given number of packets, each of the given size, at different times.
Test 5: Cobalt Queue Disc Enhanced Blue Test Item This test checks that the Blue Enhancement is worki...
CobaltQueueDiscEnhancedBlueTest(QueueSizeUnit mode)
Constructor.
void Dequeue(Ptr< CobaltQueueDisc > queue)
Dequeue function.
void DoRun() override
Implementation to actually run this TestCase.
void Enqueue(Ptr< CobaltQueueDisc > queue, uint32_t size, uint32_t nPkt)
Enqueue function.
void DequeueWithDelay(Ptr< CobaltQueueDisc > queue, uint32_t nPkt, Time delay)
Dequeue with delay function.
Test 3: Cobalt Queue Disc ECN marking Test Item.
CobaltQueueDiscMarkTest(QueueSizeUnit mode)
Constructor.
uint32_t nPacketsBeforeFirstMark
Number of packets in the queue before first mark.
void Enqueue(Ptr< CobaltQueueDisc > queue, uint32_t size, uint32_t nPkt, bool ecnCapable)
Enqueue function.
void DropNextTracer(int64_t oldVal, int64_t newVal)
Drop next tracer function.
uint32_t nPacketsBeforeFirstDrop
Number of packets in the queue before first drop.
void DoRun() override
Implementation to actually run this TestCase.
void Dequeue(Ptr< CobaltQueueDisc > queue, uint32_t modeSize, uint32_t testCase)
Dequeue function.
uint32_t m_dropNextCount
count the number of times m_dropNext is recalculated
Cobalt Queue Disc Test Item.
bool m_ecnCapablePacket
ECN capable packet?
CobaltQueueDiscTestItem()=delete
void AddHeader() override
Add the header to the packet.
CobaltQueueDiscTestItem & operator=(const CobaltQueueDiscTestItem &)=delete
CobaltQueueDiscTestItem(const CobaltQueueDiscTestItem &)=delete
bool Mark() override
Marks the packet as a substitute for dropping it, such as for Explicit Congestion Notification.
The COBALT queue disc test suite.
a polymophic address class
Definition: address.h:100
AttributeValue implementation for Boolean.
Definition: boolean.h:37
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
AttributeValue implementation for QueueSize.
Hold variables of type string.
Definition: string.h:56
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:305
A suite of tests to run.
Definition: test.h:1256
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1265
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:417
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:402
AttributeValue implementation for Time.
Definition: nstime.h:1423
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
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:296
#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 MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1360
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1348
CobaltQueueDiscTestSuite g_cobaltQueueTestSuite
the test suite
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:848
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:707
Structure that keeps the queue disc statistics.
Definition: queue-disc.h:188
uint32_t GetNDroppedPackets(std::string reason) const
Get the number of packets dropped for the given reason.
Definition: queue-disc.cc:111
uint32_t pktSize
packet size used for the simulation (in bytes)