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 {
85  return m_ecnCapablePacket;
86 }
87 
94 {
95  public:
102  void DoRun() override;
103 
112  private:
114 };
115 
117  : TestCase("Basic enqueue and dequeue operations, and attribute setting" + std::to_string(mode))
118 {
119  m_mode = mode;
120 }
121 
122 void
124 {
125  Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
126 
127  uint32_t pktSize = 1000;
128  uint32_t modeSize = 0;
129 
130  Address dest;
131 
132  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Interval", StringValue("50ms")),
133  true,
134  "Verify that we can actually set the attribute Interval");
135  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Target", StringValue("4ms")),
136  true,
137  "Verify that we can actually set the attribute Target");
138  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
139  true,
140  "Disable Blue enhancement");
141 
143  {
144  modeSize = pktSize;
145  }
146  else if (m_mode == QueueSizeUnit::PACKETS)
147  {
148  modeSize = 1;
149  }
151  queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 1500))),
152  true,
153  "Verify that we can actually set the attribute MaxSize");
154  queue->Initialize();
155 
156  Ptr<Packet> p1;
157  Ptr<Packet> p2;
158  Ptr<Packet> p3;
159  Ptr<Packet> p4;
160  Ptr<Packet> p5;
161  Ptr<Packet> p6;
162  p1 = Create<Packet>(pktSize);
163  p2 = Create<Packet>(pktSize);
164  p3 = Create<Packet>(pktSize);
165  p4 = Create<Packet>(pktSize);
166  p5 = Create<Packet>(pktSize);
167  p6 = Create<Packet>(pktSize);
168 
169  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
170  0 * modeSize,
171  "There should be no packets in queue");
172  queue->Enqueue(Create<CobaltQueueDiscTestItem>(p1, dest, false));
173  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
174  1 * modeSize,
175  "There should be one packet in queue");
176  queue->Enqueue(Create<CobaltQueueDiscTestItem>(p2, dest, false));
177  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
178  2 * modeSize,
179  "There should be two packets in queue");
180  queue->Enqueue(Create<CobaltQueueDiscTestItem>(p3, dest, false));
181  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
182  3 * modeSize,
183  "There should be three packets in queue");
184  queue->Enqueue(Create<CobaltQueueDiscTestItem>(p4, dest, false));
185  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
186  4 * modeSize,
187  "There should be four packets in queue");
188  queue->Enqueue(Create<CobaltQueueDiscTestItem>(p5, dest, false));
189  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
190  5 * modeSize,
191  "There should be five packets in queue");
192  queue->Enqueue(Create<CobaltQueueDiscTestItem>(p6, dest, false));
193  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
194  6 * modeSize,
195  "There should be six packets in queue");
196 
197  NS_TEST_ASSERT_MSG_EQ(queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::OVERLIMIT_DROP),
198  0,
199  "There should be no packets being dropped due to full queue");
200 
201  Ptr<QueueDiscItem> item;
202 
203  item = queue->Dequeue();
204  NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the first packet");
205  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
206  5 * modeSize,
207  "There should be five packets in queue");
208  NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p1->GetUid(), "was this the first packet ?");
209 
210  item = queue->Dequeue();
211  NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the second packet");
212  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
213  4 * modeSize,
214  "There should be four packets in queue");
215  NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(),
216  p2->GetUid(),
217  "Was this the second packet ?");
218 
219  item = queue->Dequeue();
220  NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the third packet");
221  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
222  3 * modeSize,
223  "There should be three packets in queue");
224  NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p3->GetUid(), "Was this the third packet ?");
225 
226  item = queue->Dequeue();
227  NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the forth packet");
228  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
229  2 * modeSize,
230  "There should be two packets in queue");
231  NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(),
232  p4->GetUid(),
233  "Was this the fourth packet ?");
234 
235  item = queue->Dequeue();
236  NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the fifth packet");
237  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
238  1 * modeSize,
239  "There should be one packet in queue");
240  NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p5->GetUid(), "Was this the fifth packet ?");
241 
242  item = queue->Dequeue();
243  NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the last packet");
244  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
245  0 * modeSize,
246  "There should be zero packet in queue");
247  NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p6->GetUid(), "Was this the sixth packet ?");
248 
249  item = queue->Dequeue();
250  NS_TEST_ASSERT_MSG_EQ(item, nullptr, "There are really no packets in queue");
251 
253  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
254  0,
255  "There should be no packet drops according to Cobalt algorithm");
256 }
257 
264 {
265  public:
267  void DoRun() override;
274  void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
279  void RunDropTest(QueueSizeUnit mode);
288  void EnqueueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
289 };
290 
292  : TestCase("Drop tests verification for both packets and bytes mode")
293 {
294 }
295 
296 void
298 
299 {
300  uint32_t pktSize = 1500;
301  uint32_t modeSize = 0;
302  Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
303 
304  if (mode == QueueSizeUnit::BYTES)
305  {
306  modeSize = pktSize;
307  }
308  else if (mode == QueueSizeUnit::PACKETS)
309  {
310  modeSize = 1;
311  }
312 
313  queue = CreateObject<CobaltQueueDisc>();
315  queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(mode, modeSize * 100))),
316  true,
317  "Verify that we can actually set the attribute MaxSize");
318  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
319  true,
320  "Disable Blue enhancement");
321  queue->Initialize();
322 
323  if (mode == QueueSizeUnit::BYTES)
324  {
325  EnqueueWithDelay(queue, pktSize, 200);
326  }
327  else
328  {
329  EnqueueWithDelay(queue, 1, 200);
330  }
331 
332  Simulator::Stop(Seconds(8.0));
333  Simulator::Run();
334 
335  QueueDisc::Stats st = queue->GetStats();
336 
337  // The Pdrop value should increase, from it's default value of zero
338  NS_TEST_ASSERT_MSG_NE(queue->GetPdrop(), 0, "Pdrop should be non-zero");
339  NS_TEST_ASSERT_MSG_NE(st.GetNDroppedPackets(CobaltQueueDisc::OVERLIMIT_DROP),
340  0,
341  "Drops due to queue overflow should be non-zero");
342 }
343 
344 void
346 {
347  Address dest;
348  double delay = 0.01; // enqueue packets with delay
349  for (uint32_t i = 0; i < nPkt; i++)
350  {
351  Simulator::Schedule(Time(Seconds((i + 1) * delay)),
353  this,
354  queue,
355  size,
356  1);
357  }
358 }
359 
360 void
361 CobaltQueueDiscDropTest::Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt)
362 {
363  Address dest;
364  for (uint32_t i = 0; i < nPkt; i++)
365  {
366  queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, true));
367  }
368 }
369 
370 void
372 {
375  Simulator::Destroy();
376 }
377 
384 {
385  public:
392  void DoRun() override;
393 
394  private:
402  void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, bool ecnCapable);
409  void Dequeue(Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t testCase);
415  void DropNextTracer(int64_t oldVal, int64_t newVal);
417  uint32_t m_dropNextCount;
420 };
421 
423  : TestCase("Basic mark operations")
424 {
425  m_mode = mode;
426  m_dropNextCount = 0;
427 }
428 
429 void
430 CobaltQueueDiscMarkTest::DropNextTracer(int64_t /* oldVal */, int64_t /* newVal */)
431 {
432  m_dropNextCount++;
433 }
434 
435 void
437 {
438  // Test is divided into 3 sub test cases:
439  // 1) Packets are not ECN capable.
440  // 2) Packets are ECN capable.
441  // 3) Some packets are ECN capable.
442 
443  // Test case 1
444  Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
445  uint32_t pktSize = 1000;
446  uint32_t modeSize = 0;
449 
451  {
452  modeSize = pktSize;
453  }
454  else if (m_mode == QueueSizeUnit::PACKETS)
455  {
456  modeSize = 1;
457  }
458 
460  queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
461  true,
462  "Verify that we can actually set the attribute MaxSize");
463  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(false)),
464  true,
465  "Verify that we can actually set the attribute UseEcn");
466  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
467  true,
468  "Disable Blue enhancement");
469  queue->Initialize();
470 
471  // Not-ECT traffic to induce packet drop
472  Enqueue(queue, pktSize, 20, false);
473  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
474  20 * modeSize,
475  "There should be 20 packets in queue.");
476 
477  // Although the first dequeue occurs with a sojourn time above target
478  // there should not be any dropped packets in this interval
479  Time waitUntilFirstDequeue = 2 * queue->GetTarget();
480  Simulator::Schedule(waitUntilFirstDequeue,
482  this,
483  queue,
484  modeSize,
485  1);
486 
487  // This dequeue should cause a packet to be dropped
488  Time waitUntilSecondDequeue = waitUntilFirstDequeue + 2 * queue->GetInterval();
489  Simulator::Schedule(waitUntilSecondDequeue,
491  this,
492  queue,
493  modeSize,
494  1);
495 
496  Simulator::Run();
497  Simulator::Destroy();
498 
499  // Test case 2, queue with ECN capable traffic for marking of packets instead of dropping
500  queue = CreateObject<CobaltQueueDisc>();
502  queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
503  true,
504  "Verify that we can actually set the attribute MaxSize");
505  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
506  true,
507  "Verify that we can actually set the attribute UseEcn");
508  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
509  true,
510  "Disable Blue enhancement");
511  queue->Initialize();
512 
513  // ECN capable traffic
514  Enqueue(queue, pktSize, 20, true);
515  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
516  20 * modeSize,
517  "There should be 20 packets in queue.");
518 
519  // Although the first dequeue occurs with a sojourn time above target
520  // there should not be any marked packets in this interval
521  Simulator::Schedule(waitUntilFirstDequeue,
523  this,
524  queue,
525  modeSize,
526  2);
527 
528  // This dequeue should cause a packet to be marked
529  Simulator::Schedule(waitUntilSecondDequeue,
531  this,
532  queue,
533  modeSize,
534  2);
535 
536  // This dequeue should cause a packet to be marked as dropnext is equal to current time
537  Simulator::Schedule(waitUntilSecondDequeue,
539  this,
540  queue,
541  modeSize,
542  2);
543 
544  // In dropping phase and it's time for next packet to be marked
545  // the dequeue should cause additional packet to be marked
546  Simulator::Schedule(waitUntilSecondDequeue * 2,
548  this,
549  queue,
550  modeSize,
551  2);
552 
553  Simulator::Run();
554  Simulator::Destroy();
555 
556  // Test case 3, some packets are ECN capable
557  queue = CreateObject<CobaltQueueDisc>();
559  queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
560  true,
561  "Verify that we can actually set the attribute MaxSize");
562  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
563  true,
564  "Verify that we can actually set the attribute UseEcn");
565  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
566  true,
567  "Disable Blue enhancement");
568  queue->Initialize();
569 
570  // First 3 packets in the queue are ecnCapable
571  Enqueue(queue, pktSize, 3, true);
572  // Rest of the packet are not ecnCapable
573  Enqueue(queue, pktSize, 17, false);
574  NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
575  20 * modeSize,
576  "There should be 20 packets in queue.");
577 
578  // Although the first dequeue occurs with a sojourn time above target
579  // there should not be any marked packets in this interval
580  Simulator::Schedule(waitUntilFirstDequeue,
582  this,
583  queue,
584  modeSize,
585  3);
586 
587  // This dequeue should cause a packet to be marked
588  Simulator::Schedule(waitUntilSecondDequeue,
590  this,
591  queue,
592  modeSize,
593  3);
594 
595  // This dequeue should cause a packet to be marked as dropnext is equal to current time
596  Simulator::Schedule(waitUntilSecondDequeue,
598  this,
599  queue,
600  modeSize,
601  3);
602 
603  // In dropping phase and it's time for next packet to be dropped as packets are not ECN capable
604  // the dequeue should cause packet to be dropped
605  Simulator::Schedule(waitUntilSecondDequeue * 2,
607  this,
608  queue,
609  modeSize,
610  3);
611 
612  Simulator::Run();
613  Simulator::Destroy();
614 }
615 
616 void
618  uint32_t size,
619  uint32_t nPkt,
620  bool ecnCapable)
621 {
622  Address dest;
623  for (uint32_t i = 0; i < nPkt; i++)
624  {
625  queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, ecnCapable));
626  }
627 }
628 
629 void
630 CobaltQueueDiscMarkTest::Dequeue(Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t testCase)
631 {
632  uint32_t initialMarkCount = queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
633  uint32_t initialQSize = queue->GetCurrentSize().GetValue();
634  uint32_t initialDropNext = queue->GetDropNext();
635  Time currentTime = Simulator::Now();
636  uint32_t currentDropCount = 0;
637  uint32_t currentMarkCount = 0;
638 
639  if (initialMarkCount > 0 && currentTime.GetNanoSeconds() > initialDropNext && testCase == 3)
640  {
641  queue->TraceConnectWithoutContext(
642  "DropNext",
644  }
645 
646  if (initialQSize != 0)
647  {
648  Ptr<QueueDiscItem> item = queue->Dequeue();
649  if (testCase == 1)
650  {
651  currentDropCount =
652  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
653  if (currentDropCount != 0)
654  {
655  nPacketsBeforeFirstDrop = initialQSize;
656  }
657  }
658  if (testCase == 2)
659  {
660  if (initialMarkCount == 0 && currentTime > queue->GetTarget())
661  {
662  if (currentTime < queue->GetInterval())
663  {
664  currentDropCount =
665  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
666  currentMarkCount =
667  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
668  NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
669  initialQSize - modeSize,
670  "There should be 1 packet dequeued.");
671  NS_TEST_EXPECT_MSG_EQ(currentDropCount,
672  0,
673  "There should not be any packet drops");
674  NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
675  0,
676  "We are not in dropping state."
677  "Sojourn time has just gone above target from below."
678  "Hence, there should be no marked packets");
679  }
680  else if (currentTime >= queue->GetInterval())
681  {
682  nPacketsBeforeFirstMark = initialQSize;
683  currentDropCount =
684  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
685  currentMarkCount =
686  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
688  queue->GetCurrentSize().GetValue(),
689  initialQSize - modeSize,
690  "Sojourn time has been above target for at least interval."
691  "We enter the dropping state and perform initial packet marking"
692  "So there should be only 1 more packet dequeued.");
693  NS_TEST_EXPECT_MSG_EQ(currentDropCount,
694  0,
695  "There should not be any packet drops");
696  NS_TEST_EXPECT_MSG_EQ(currentMarkCount, 1, "There should be 1 marked packet");
697  }
698  }
699  else if (initialMarkCount > 0)
700  {
701  if (currentTime.GetNanoSeconds() <= initialDropNext)
702  {
703  currentDropCount =
704  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
705  currentMarkCount =
706  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
707  NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
708  initialQSize - modeSize,
709  "We are in dropping state."
710  "Sojourn is still above target."
711  "There should be only 1 more packet dequeued");
712  NS_TEST_EXPECT_MSG_EQ(currentDropCount,
713  0,
714  "There should not be any packet drops");
715  NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
716  2,
717  "There should be 2 marked packet as."
718  "current dropnext is equal to current time.");
719  }
720  else if (currentTime.GetNanoSeconds() > initialDropNext)
721  {
722  currentDropCount =
723  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
724  currentMarkCount =
725  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
726  NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
727  initialQSize - modeSize,
728  "We are in dropping state."
729  "It's time for packet to be marked"
730  "So there should be only 1 more packet dequeued");
731  NS_TEST_EXPECT_MSG_EQ(currentDropCount,
732  0,
733  "There should not be any packet drops");
734  NS_TEST_EXPECT_MSG_EQ(currentMarkCount, 3, "There should be 3 marked packet");
738  "Number of packets in the queue before drop should be equal"
739  "to number of packets in the queue before first mark as the behavior until "
740  "packet N should be the same.");
741  }
742  }
743  }
744  else if (testCase == 3)
745  {
746  if (initialMarkCount == 0 && currentTime > queue->GetTarget())
747  {
748  if (currentTime < queue->GetInterval())
749  {
750  currentDropCount =
751  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
752  currentMarkCount =
753  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
754  NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
755  initialQSize - modeSize,
756  "There should be 1 packet dequeued.");
757  NS_TEST_EXPECT_MSG_EQ(currentDropCount,
758  0,
759  "There should not be any packet drops");
760  NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
761  0,
762  "We are not in dropping state."
763  "Sojourn time has just gone above target from below."
764  "Hence, there should be no marked packets");
765  }
766  else if (currentTime >= queue->GetInterval())
767  {
768  currentDropCount =
769  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
770  currentMarkCount =
771  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
773  queue->GetCurrentSize().GetValue(),
774  initialQSize - modeSize,
775  "Sojourn time has been above target for at least interval."
776  "We enter the dropping state and perform initial packet marking"
777  "So there should be only 1 more packet dequeued.");
778  NS_TEST_EXPECT_MSG_EQ(currentDropCount,
779  0,
780  "There should not be any packet drops");
781  NS_TEST_EXPECT_MSG_EQ(currentMarkCount, 1, "There should be 1 marked packet");
782  }
783  }
784  else if (initialMarkCount > 0)
785  {
786  if (currentTime.GetNanoSeconds() <= initialDropNext)
787  {
788  currentDropCount =
789  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
790  currentMarkCount =
791  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
792  NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
793  initialQSize - modeSize,
794  "We are in dropping state."
795  "Sojourn is still above target."
796  "So there should be only 1 more packet dequeued");
797  NS_TEST_EXPECT_MSG_EQ(currentDropCount,
798  0,
799  "There should not be any packet drops");
800  NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
801  2,
802  "There should be 2 marked packet"
803  "as dropnext is equal to current time");
804  }
805  else if (currentTime.GetNanoSeconds() > initialDropNext)
806  {
807  currentDropCount =
808  queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
809  currentMarkCount =
810  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
812  queue->GetCurrentSize().GetValue(),
813  initialQSize - (m_dropNextCount + 1) * modeSize,
814  "We are in dropping state."
815  "It's time for packet to be dropped as packets are not ecnCapable"
816  "The number of packets dequeued equals to the number of times m_dropNext "
817  "is updated plus initial dequeue");
819  currentDropCount,
821  "The number of drops equals to the number of times m_dropNext is updated");
822  NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
823  2,
824  "There should still be only 2 marked packet");
825  }
826  }
827  }
828  }
829 }
830 
837 {
838  public:
846 
847  private:
848  void DoRun() override;
855  void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
863  void EnqueueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, Time delay);
869  void Dequeue(Ptr<CobaltQueueDisc> queue, uint32_t modeSize);
877  void DequeueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t nPkt, Time delay);
879 };
880 
882  : TestCase("Test CE Threshold marking")
883 {
884  m_mode = mode;
885 }
886 
888 {
889 }
890 
891 void
893 {
894  Address dest;
895  for (uint32_t i = 0; i < nPkt; i++)
896  {
897  queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, true));
898  }
899 }
900 
901 void
903  uint32_t size,
904  uint32_t nPkt,
905  Time delay)
906 {
907  for (uint32_t i = 0; i < nPkt; i++)
908  {
909  Simulator::Schedule(Time(Seconds((i + 1) * delay.GetSeconds())),
911  this,
912  queue,
913  size,
914  1);
915  }
916 }
917 
918 void
920 {
921  Ptr<QueueDiscItem> item = queue->Dequeue();
922 
924  {
926  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
927  1,
928  "There should be only 1 packet"
929  "mark, the delay between the enqueueing of the packets decreased after the"
930  "1st mark (packet enqueued at 11ms) and increased for the packet enqueued after 20.6ms."
931  "Queue delay remains below or equal to 1ms for the packet enqueued before 28ms");
932  }
933  if (Simulator::Now() > MilliSeconds(31))
934  {
936  queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
937  3,
938  "There should be 3 packet"
939  "marks, the delay between the enqueueing of the packets decreased after 1st mark"
940  "(packet enqueued at 11ms) and increased for the packet enqueued after 20.6ms."
941  "Queue delay remains below 1ms for the packets enqueued before 28ms and increases"
942  "for the packets enqueued after 28ms.");
943  }
944 }
945 
946 void
948  uint32_t modeSize,
949  uint32_t nPkt,
950  Time delay)
951 {
952  for (uint32_t i = 0; i < nPkt; i++)
953  {
954  Simulator::Schedule(Time(Seconds((i + 1) * delay.GetSeconds())),
956  this,
957  queue,
958  modeSize);
959  }
960 }
961 
962 void
964 {
965  Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
966  uint32_t pktSize = 1000;
967  uint32_t modeSize = 0;
968 
970  {
971  modeSize = pktSize;
972  }
973  else if (m_mode == QueueSizeUnit::PACKETS)
974  {
975  modeSize = 1;
976  }
977 
978  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
979  true,
980  "Verify that we can actually set the attribute UseEcn");
981  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("CeThreshold", TimeValue(MilliSeconds(1))),
982  true,
983  "Verify that we can actually set the attribute UseEcn");
984  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
985  true,
986  "Disable Blue enhancement");
987  queue->Initialize();
988 
989  // Enqueue 11 packets every 1ms
990  EnqueueWithDelay(queue, pktSize, 11, MilliSeconds(1));
991 
992  // With every dequeue, queue delay increases by 0.1ms as packet enqueues every 1ms while
993  // dequeues at 1.1ms so at 11th dequeue, the dequeued packet should be marked.
994  Time dequeueInterval = MicroSeconds(1100);
995  DequeueWithDelay(queue, modeSize, 11, dequeueInterval);
996 
997  // First mark occurred for the packet enqueued at 11ms, ideally TCP would decrease sending rate
998  // which can be simulated by increasing interval between subsequent enqueues, so packets are now
999  // enqueued with a delay 1.2ms.
1000  Time waitUntilFirstMark = MilliSeconds(11);
1001  Simulator::Schedule(waitUntilFirstMark,
1003  this,
1004  queue,
1005  pktSize,
1006  9,
1007  MicroSeconds(1200));
1008 
1009  // Keep dequeueing with the same delay
1010  Simulator::Schedule(waitUntilFirstMark,
1012  this,
1013  queue,
1014  modeSize,
1015  9,
1016  dequeueInterval);
1017 
1018  // Queue delay becomes 0.2ms for the packet enqueued at 20.6ms, time to decrease interval
1019  // between subsequent enqueues, as ideally TCP would again start increasing sending rate
1020  Time waitUntilDecreasingEnqueueDelay = waitUntilFirstMark + MilliSeconds(9);
1021  Simulator::Schedule(waitUntilDecreasingEnqueueDelay,
1023  this,
1024  queue,
1025  pktSize,
1026  10,
1027  MilliSeconds(1));
1028 
1029  // Keep dequeueing with the same delay
1030  Simulator::Schedule(waitUntilFirstMark,
1032  this,
1033  queue,
1034  modeSize,
1035  10,
1036  dequeueInterval);
1037 
1038  Simulator::Run();
1039  Simulator::Destroy();
1040 }
1041 
1055 {
1056  public:
1064 
1065  private:
1066  void DoRun() override;
1073  void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
1078  void Dequeue(Ptr<CobaltQueueDisc> queue);
1085  void DequeueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t nPkt, Time delay);
1087 };
1088 
1090  : TestCase("Enhanced Blue tests verification for both packets and bytes mode")
1091 {
1092  m_mode = mode;
1093 }
1094 
1096 {
1097 }
1098 
1099 void
1101 
1102 {
1103  uint32_t pktSize = 1500;
1104  uint32_t modeSize = 0;
1105  Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
1106 
1108  {
1109  modeSize = pktSize;
1110  }
1111  else if (m_mode == QueueSizeUnit::PACKETS)
1112  {
1113  modeSize = 1;
1114  }
1115  queue->Initialize();
1116  queue->AssignStreams(1);
1117  Enqueue(queue, modeSize, 200);
1118  DequeueWithDelay(queue, 100, MilliSeconds(10));
1119 
1120  Simulator::Stop(Seconds(8.0));
1121  Simulator::Run();
1122 
1123  QueueDisc::Stats st = queue->GetStats();
1124 
1125  // The Pdrop value should increase, from it's default value of zero
1127  queue->GetPdrop(),
1128  0.234375,
1129  "Pdrop should be increased by 1/256 for every packet whose sojourn time is above 400ms."
1130  " From the 41st dequeue until the last one, sojourn time is above 400ms, so 60 packets "
1131  "have sojourn time above 400ms"
1132  "hence Pdrop should be increased 60*(1/256) which is 0.234375");
1133  NS_TEST_ASSERT_MSG_EQ(st.GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1134  49,
1135  "There should a fixed number of drops (49 here)");
1136  Simulator::Destroy();
1137 
1138  queue = CreateObject<CobaltQueueDisc>();
1139  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
1140  true,
1141  "Verify that we can actually set the attribute UseEcn");
1142  NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
1143  true,
1144  "Disable Blue enhancement");
1145  queue->Initialize();
1146  Enqueue(queue, modeSize, 200);
1147  DequeueWithDelay(queue, 100, MilliSeconds(10));
1148 
1149  Simulator::Stop(Seconds(8.0));
1150  Simulator::Run();
1151 
1152  st = queue->GetStats();
1153 
1154  NS_TEST_ASSERT_MSG_EQ(queue->GetPdrop(), 0, "Pdrop should be zero");
1155  NS_TEST_ASSERT_MSG_EQ(st.GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1156  0,
1157  "There should not any dropped packets");
1158  Simulator::Destroy();
1159 }
1160 
1161 void
1163 {
1164  Address dest;
1165  for (uint32_t i = 0; i < nPkt; i++)
1166  {
1167  queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, true));
1168  }
1169 }
1170 
1171 void
1173 {
1174  Ptr<QueueDiscItem> item = queue->Dequeue();
1175 }
1176 
1177 void
1179  uint32_t nPkt,
1180  Time delay)
1181 {
1182  for (uint32_t i = 0; i < nPkt; i++)
1183  {
1184  Simulator::Schedule(Time(Seconds((i + 1) * delay.GetSeconds())),
1186  this,
1187  queue);
1188  }
1189 }
1190 
1196 {
1197  public:
1199  : TestSuite("cobalt-queue-disc", UNIT)
1200  {
1201  // Test 1: simple enqueue/dequeue with no drops
1203  AddTestCase(new CobaltQueueDiscBasicEnqueueDequeue(BYTES), TestCase::QUICK);
1204  // Test 2: Drop test
1205  AddTestCase(new CobaltQueueDiscDropTest(), TestCase::QUICK);
1206  // Test 3: Mark test
1207  AddTestCase(new CobaltQueueDiscMarkTest(PACKETS), TestCase::QUICK);
1208  AddTestCase(new CobaltQueueDiscMarkTest(BYTES), TestCase::QUICK);
1209  // Test 4: CE threshold marking test
1210  AddTestCase(new CobaltQueueDiscCeThresholdTest(PACKETS), TestCase::QUICK);
1211  AddTestCase(new CobaltQueueDiscCeThresholdTest(BYTES), TestCase::QUICK);
1212  // Test 4: Blue enhancement test
1213  AddTestCase(new CobaltQueueDiscEnhancedBlueTest(PACKETS), TestCase::QUICK);
1214  AddTestCase(new CobaltQueueDiscEnhancedBlueTest(BYTES), TestCase::QUICK);
1215  }
#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:101
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
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:301
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:418
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:403
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:305
#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:1350
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
CobaltQueueDiscTestSuite g_cobaltQueueTestSuite
the test suite
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
Definition: json.h:25255
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.
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
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)