A Discrete-Event Network Simulator
API
cobalt-queue-disc-test-suite.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2019 NITK Surathkal
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Ported to ns-3 by: Vignesh Kannan <vignesh2496@gmail.com>
19  * Harsh Lara <harshapplefan@gmail.com>
20  * Jendaipou Palmei <jendaipoupalmei@gmail.com>
21  * Shefali Gupta <shefaligups11@gmail.com>
22  * Mohit P. Tahiliani <tahiliani@nitk.edu.in>
23  */
24 
25 #include "ns3/test.h"
26 #include "ns3/cobalt-queue-disc.h"
27 #include "ns3/packet.h"
28 #include "ns3/uinteger.h"
29 #include "ns3/string.h"
30 #include "ns3/double.h"
31 #include "ns3/log.h"
32 #include "ns3/simulator.h"
33 
34 using namespace ns3;
42 {
43 public:
52  CobaltQueueDiscTestItem (Ptr<Packet> p, const Address & addr,uint16_t protocol, bool ecnCapable);
53  virtual ~CobaltQueueDiscTestItem ();
54 
55  // Delete copy constructor and assignment operator to avoid misuse
57  CobaltQueueDiscTestItem & operator = (const CobaltQueueDiscTestItem &) = delete;
58 
59  virtual void AddHeader (void);
60  virtual bool Mark (void);
61 
62 private:
64 
66 };
67 
68 CobaltQueueDiscTestItem::CobaltQueueDiscTestItem (Ptr<Packet> p, const Address & addr,uint16_t protocol, bool ecnCapable)
69  : QueueDiscItem (p, addr, ecnCapable),
70  m_ecnCapablePacket (ecnCapable)
71 {
72 }
73 
75 {
76 }
77 
78 void
80 {
81 }
82 
83 bool
85 {
87  {
88  return true;
89  }
90  return false;
91 }
92 
100 {
101 public:
108  virtual void DoRun (void);
109 
118 private:
120 };
121 
123  : TestCase ("Basic enqueue and dequeue operations, and attribute setting" + std::to_string (mode))
124 {
125  m_mode = mode;
126 }
127 
128 void
130 {
131  Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc> ();
132 
133  uint32_t pktSize = 1000;
134  uint32_t modeSize = 0;
135 
136  Address dest;
137 
138  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Interval", StringValue ("50ms")), true,
139  "Verify that we can actually set the attribute Interval");
140  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Target", StringValue ("4ms")), true,
141  "Verify that we can actually set the attribute Target");
142  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("BlueThreshold", TimeValue (Time::Max ())), true,
143  "Disable Blue enhancement");
144 
146  {
147  modeSize = pktSize;
148  }
149  else if (m_mode == QueueSizeUnit::PACKETS)
150  {
151  modeSize = 1;
152  }
153  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (m_mode, modeSize * 1500))),
154  true, "Verify that we can actually set the attribute MaxSize");
155  queue->Initialize ();
156 
157  Ptr<Packet> p1, p2, p3, p4, p5, p6;
158  p1 = Create<Packet> (pktSize);
159  p2 = Create<Packet> (pktSize);
160  p3 = Create<Packet> (pktSize);
161  p4 = Create<Packet> (pktSize);
162  p5 = Create<Packet> (pktSize);
163  p6 = Create<Packet> (pktSize);
164 
165  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 0 * modeSize, "There should be no packets in queue");
166  queue->Enqueue (Create<CobaltQueueDiscTestItem> (p1, dest,0, false));
167  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 1 * modeSize, "There should be one packet in queue");
168  queue->Enqueue (Create<CobaltQueueDiscTestItem> (p2, dest,0, false));
169  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 2 * modeSize, "There should be two packets in queue");
170  queue->Enqueue (Create<CobaltQueueDiscTestItem> (p3, dest,0, false));
171  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 3 * modeSize, "There should be three packets in queue");
172  queue->Enqueue (Create<CobaltQueueDiscTestItem> (p4, dest,0, false));
173  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 4 * modeSize, "There should be four packets in queue");
174  queue->Enqueue (Create<CobaltQueueDiscTestItem> (p5, dest,0, false));
175  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 5 * modeSize, "There should be five packets in queue");
176  queue->Enqueue (Create<CobaltQueueDiscTestItem> (p6, dest,0, false));
177  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 6 * modeSize, "There should be six packets in queue");
178 
179  NS_TEST_ASSERT_MSG_EQ (queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::OVERLIMIT_DROP), 0, "There should be no packets being dropped due to full queue");
180 
181  Ptr<QueueDiscItem> item;
182 
183  item = queue->Dequeue ();
184  NS_TEST_ASSERT_MSG_EQ ((item != 0), true, "I want to remove the first packet");
185  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 5 * modeSize, "There should be five packets in queue");
186  NS_TEST_ASSERT_MSG_EQ (item->GetPacket ()->GetUid (), p1->GetUid (), "was this the first packet ?");
187 
188  item = queue->Dequeue ();
189  NS_TEST_ASSERT_MSG_EQ ((item != 0), true, "I want to remove the second packet");
190  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 4 * modeSize, "There should be four packets in queue");
191  NS_TEST_ASSERT_MSG_EQ (item->GetPacket ()->GetUid (), p2->GetUid (), "Was this the second packet ?");
192 
193  item = queue->Dequeue ();
194  NS_TEST_ASSERT_MSG_EQ ((item != 0), true, "I want to remove the third packet");
195  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 3 * modeSize, "There should be three packets in queue");
196  NS_TEST_ASSERT_MSG_EQ (item->GetPacket ()->GetUid (), p3->GetUid (), "Was this the third packet ?");
197 
198  item = queue->Dequeue ();
199  NS_TEST_ASSERT_MSG_EQ ((item != 0), true, "I want to remove the forth packet");
200  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 2 * modeSize, "There should be two packets in queue");
201  NS_TEST_ASSERT_MSG_EQ (item->GetPacket ()->GetUid (), p4->GetUid (), "Was this the fourth packet ?");
202 
203  item = queue->Dequeue ();
204  NS_TEST_ASSERT_MSG_EQ ((item != 0), true, "I want to remove the fifth packet");
205  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 1 * modeSize, "There should be one packet in queue");
206  NS_TEST_ASSERT_MSG_EQ (item->GetPacket ()->GetUid (), p5->GetUid (), "Was this the fifth packet ?");
207 
208  item = queue->Dequeue ();
209  NS_TEST_ASSERT_MSG_EQ ((item != 0), true, "I want to remove the last packet");
210  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 0 * modeSize, "There should be zero packet in queue");
211  NS_TEST_ASSERT_MSG_EQ (item->GetPacket ()->GetUid (), p6->GetUid (), "Was this the sixth packet ?");
212 
213  item = queue->Dequeue ();
214  NS_TEST_ASSERT_MSG_EQ ((item == 0), true, "There are really no packets in queue");
215 
216  NS_TEST_ASSERT_MSG_EQ (queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should be no packet drops according to Cobalt algorithm");
217 }
218 
226 {
227 public:
229  virtual void DoRun (void);
236  void Enqueue (Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
241  void RunDropTest (QueueSizeUnit mode);
250  void EnqueueWithDelay (Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
251 
252 };
253 
255  : TestCase ("Drop tests verification for both packets and bytes mode")
256 {
257 }
258 
259 void
261 
262 {
263  uint32_t pktSize = 1500;
264  uint32_t modeSize = 0;
265  Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc> ();
266 
267  if (mode == QueueSizeUnit::BYTES)
268  {
269  modeSize = pktSize;
270  }
271  else if (mode == QueueSizeUnit::PACKETS)
272  {
273  modeSize = 1;
274  }
275 
276  queue = CreateObject<CobaltQueueDisc> ();
277  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (mode, modeSize * 100))),
278  true, "Verify that we can actually set the attribute MaxSize");
279  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("BlueThreshold", TimeValue (Time::Max ())), true,
280  "Disable Blue enhancement");
281  queue->Initialize ();
282 
283  if (mode == QueueSizeUnit::BYTES)
284  {
285  EnqueueWithDelay (queue, pktSize, 200);
286  }
287  else
288  {
289  EnqueueWithDelay (queue, 1, 200);
290  }
291 
292  Simulator::Stop (Seconds (8.0));
293  Simulator::Run ();
294 
295  QueueDisc::Stats st = queue->GetStats ();
296 
297 // The Pdrop value should increase, from it's default value of zero
298  NS_TEST_ASSERT_MSG_NE (queue->GetPdrop (), 0, "Pdrop should be non-zero");
299  NS_TEST_ASSERT_MSG_NE (st.GetNDroppedPackets (CobaltQueueDisc::OVERLIMIT_DROP), 0, "Drops due to queue overflow should be non-zero");
300 }
301 
302 void
304 {
305  Address dest;
306  double delay = 0.01; // enqueue packets with delay
307  for (uint32_t i = 0; i < nPkt; i++)
308  {
309  Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &CobaltQueueDiscDropTest::Enqueue, this, queue, size, 1);
310  }
311 }
312 
313 void
314 CobaltQueueDiscDropTest::Enqueue (Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt)
315 {
316  Address dest;
317  for (uint32_t i = 0; i < nPkt; i++)
318  {
319  queue->Enqueue (Create<CobaltQueueDiscTestItem> (Create<Packet> (size), dest, 0, true));
320  }
321 }
322 
323 void
325 {
328  Simulator::Destroy ();
329 }
330 
338 {
339 public:
346  virtual void DoRun (void);
347 
348 private:
356  void Enqueue (Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, bool ecnCapable);
363  void Dequeue (Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t testCase);
369  void DropNextTracer (int64_t oldVal, int64_t newVal);
371  uint32_t m_dropNextCount;
374 };
375 
377  : TestCase ("Basic mark operations")
378 {
379  m_mode = mode;
380  m_dropNextCount = 0;
381 }
382 
383 void
384 CobaltQueueDiscMarkTest::DropNextTracer ([[maybe_unused]] int64_t oldVal, [[maybe_unused]] int64_t newVal)
385 {
386  m_dropNextCount++;
387 }
388 
389 void
391 {
392  // Test is divided into 3 sub test cases:
393  // 1) Packets are not ECN capable.
394  // 2) Packets are ECN capable.
395  // 3) Some packets are ECN capable.
396 
397  // Test case 1
398  Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc> ();
399  uint32_t pktSize = 1000;
400  uint32_t modeSize = 0;
403 
405  {
406  modeSize = pktSize;
407  }
408  else if (m_mode == QueueSizeUnit::PACKETS)
409  {
410  modeSize = 1;
411  }
412 
413  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (m_mode, modeSize * 500))),
414  true, "Verify that we can actually set the attribute MaxSize");
415  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("UseEcn", BooleanValue (false)),
416  true, "Verify that we can actually set the attribute UseEcn");
417  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("BlueThreshold", TimeValue (Time::Max ())), true,
418  "Disable Blue enhancement");
419  queue->Initialize ();
420 
421  // Not-ECT traffic to induce packet drop
422  Enqueue (queue, pktSize, 20, false);
423  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 20 * modeSize, "There should be 20 packets in queue.");
424 
425  // Although the first dequeue occurs with a sojourn time above target
426  // there should not be any dropped packets in this interval
427  Time waitUntilFirstDequeue = 2 * queue->GetTarget ();
428  Simulator::Schedule (waitUntilFirstDequeue, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 1);
429 
430  // This dequeue should cause a packet to be dropped
431  Time waitUntilSecondDequeue = waitUntilFirstDequeue + 2 * queue->GetInterval ();
432  Simulator::Schedule (waitUntilSecondDequeue, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 1);
433 
434  Simulator::Run ();
435  Simulator::Destroy ();
436 
437  // Test case 2, queue with ECN capable traffic for marking of packets instead of dropping
438  queue = CreateObject<CobaltQueueDisc> ();
439  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (m_mode, modeSize * 500))),
440  true, "Verify that we can actually set the attribute MaxSize");
441  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("UseEcn", BooleanValue (true)),
442  true, "Verify that we can actually set the attribute UseEcn");
443  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("BlueThreshold", TimeValue (Time::Max ())), true,
444  "Disable Blue enhancement");
445  queue->Initialize ();
446 
447  // ECN capable traffic
448  Enqueue (queue, pktSize, 20, true);
449  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 20 * modeSize, "There should be 20 packets in queue.");
450 
451  // Although the first dequeue occurs with a sojourn time above target
452  // there should not be any marked packets in this interval
453  Simulator::Schedule (waitUntilFirstDequeue, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 2);
454 
455  // This dequeue should cause a packet to be marked
456  Simulator::Schedule (waitUntilSecondDequeue, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 2);
457 
458  // This dequeue should cause a packet to be marked as dropnext is equal to current time
459  Simulator::Schedule (waitUntilSecondDequeue, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 2);
460 
461  // In dropping phase and it's time for next packet to be marked
462  // the dequeue should cause additional packet to be marked
463  Simulator::Schedule (waitUntilSecondDequeue * 2, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 2);
464 
465  Simulator::Run ();
466  Simulator::Destroy ();
467 
468  // Test case 3, some packets are ECN capable
469  queue = CreateObject<CobaltQueueDisc> ();
470  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (m_mode, modeSize * 500))),
471  true, "Verify that we can actually set the attribute MaxSize");
472  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("UseEcn", BooleanValue (true)),
473  true, "Verify that we can actually set the attribute UseEcn");
474  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("BlueThreshold", TimeValue (Time::Max ())), true,
475  "Disable Blue enhancement");
476  queue->Initialize ();
477 
478  // First 3 packets in the queue are ecnCapable
479  Enqueue (queue, pktSize, 3, true);
480  // Rest of the packet are not ecnCapable
481  Enqueue (queue, pktSize, 17, false);
482  NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 20 * modeSize, "There should be 20 packets in queue.");
483 
484  // Although the first dequeue occurs with a sojourn time above target
485  // there should not be any marked packets in this interval
486  Simulator::Schedule (waitUntilFirstDequeue, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 3);
487 
488  // This dequeue should cause a packet to be marked
489  Simulator::Schedule (waitUntilSecondDequeue, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 3);
490 
491  // This dequeue should cause a packet to be marked as dropnext is equal to current time
492  Simulator::Schedule (waitUntilSecondDequeue, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 3);
493 
494  // In dropping phase and it's time for next packet to be dropped as packets are not ECN capable
495  // the dequeue should cause packet to be dropped
496  Simulator::Schedule (waitUntilSecondDequeue * 2, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 3);
497 
498  Simulator::Run ();
499  Simulator::Destroy ();
500 }
501 
502 void
503 CobaltQueueDiscMarkTest::Enqueue (Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, bool ecnCapable)
504 {
505  Address dest;
506  for (uint32_t i = 0; i < nPkt; i++)
507  {
508  queue->Enqueue (Create<CobaltQueueDiscTestItem> (Create<Packet> (size), dest, 0, ecnCapable));
509  }
510 }
511 
512 void
513 CobaltQueueDiscMarkTest::Dequeue (Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t testCase)
514 {
515  uint32_t initialMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
516  uint32_t initialQSize = queue->GetCurrentSize ().GetValue ();
517  uint32_t initialDropNext = queue->GetDropNext ();
518  Time currentTime = Simulator::Now ();
519  uint32_t currentDropCount = 0;
520  uint32_t currentMarkCount = 0;
521 
522  if (initialMarkCount > 0 && currentTime.GetNanoSeconds () > initialDropNext && testCase == 3)
523  {
524  queue->TraceConnectWithoutContext ("DropNext", MakeCallback (&CobaltQueueDiscMarkTest::DropNextTracer, this));
525  }
526 
527  if (initialQSize != 0)
528  {
529  Ptr<QueueDiscItem> item = queue->Dequeue ();
530  if (testCase == 1)
531  {
532  currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
533  if (currentDropCount != 0)
534  {
535  nPacketsBeforeFirstDrop = initialQSize;
536  }
537  }
538  if (testCase == 2)
539  {
540  if (initialMarkCount == 0 && currentTime > queue->GetTarget ())
541  {
542  if (currentTime < queue->GetInterval ())
543  {
544  currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
545  currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
546  NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize, "There should be 1 packet dequeued.");
547  NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
548  NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 0, "We are not in dropping state."
549  "Sojourn time has just gone above target from below."
550  "Hence, there should be no marked packets");
551  }
552  else if (currentTime >= queue->GetInterval ())
553  {
554  nPacketsBeforeFirstMark = initialQSize;
555  currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
556  currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
557  NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize,
558  "Sojourn time has been above target for at least interval."
559  "We enter the dropping state and perform initial packet marking"
560  "So there should be only 1 more packet dequeued.");
561  NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
562  NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 1, "There should be 1 marked packet");
563  }
564  }
565  else if (initialMarkCount > 0)
566  {
567  if (currentTime.GetNanoSeconds () <= initialDropNext)
568  {
569  currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
570  currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
571  NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize, "We are in dropping state."
572  "Sojourn is still above target."
573  "There should be only 1 more packet dequeued");
574  NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
575  NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 2, "There should be 2 marked packet as."
576  "current dropnext is equal to current time.");
577  }
578  else if (currentTime.GetNanoSeconds () > initialDropNext)
579  {
580  currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
581  currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
582  NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize, "We are in dropping state."
583  "It's time for packet to be marked"
584  "So there should be only 1 more packet dequeued");
585  NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
586  NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 3, "There should be 3 marked packet");
587  NS_TEST_EXPECT_MSG_EQ (nPacketsBeforeFirstDrop, nPacketsBeforeFirstMark, "Number of packets in the queue before drop should be equal"
588  "to number of packets in the queue before first mark as the behavior until packet N should be the same.");
589  }
590  }
591  }
592  else if (testCase == 3)
593  {
594  if (initialMarkCount == 0 && currentTime > queue->GetTarget ())
595  {
596  if (currentTime < queue->GetInterval ())
597  {
598  currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
599  currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
600  NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize, "There should be 1 packet dequeued.");
601  NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
602  NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 0, "We are not in dropping state."
603  "Sojourn time has just gone above target from below."
604  "Hence, there should be no marked packets");
605  }
606  else if (currentTime >= queue->GetInterval ())
607  {
608  currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
609  currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
610  NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize,
611  "Sojourn time has been above target for at least interval."
612  "We enter the dropping state and perform initial packet marking"
613  "So there should be only 1 more packet dequeued.");
614  NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
615  NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 1, "There should be 1 marked packet");
616  }
617  }
618  else if (initialMarkCount > 0)
619  {
620  if (currentTime.GetNanoSeconds () <= initialDropNext)
621  {
622  currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
623  currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
624  NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize, "We are in dropping state."
625  "Sojourn is still above target."
626  "So there should be only 1 more packet dequeued");
627  NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
628  NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 2, "There should be 2 marked packet"
629  "as dropnext is equal to current time");
630  }
631  else if (currentTime.GetNanoSeconds () > initialDropNext)
632  {
633  currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
634  currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
635  NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - (m_dropNextCount + 1) * modeSize, "We are in dropping state."
636  "It's time for packet to be dropped as packets are not ecnCapable"
637  "The number of packets dequeued equals to the number of times m_dropNext is updated plus initial dequeue");
638  NS_TEST_EXPECT_MSG_EQ (currentDropCount, m_dropNextCount, "The number of drops equals to the number of times m_dropNext is updated");
639  NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 2, "There should still be only 2 marked packet");
640  }
641  }
642  }
643  }
644 }
645 
653 {
654 public:
662 
663 private:
664  virtual void DoRun (void);
671  void Enqueue (Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
679  void EnqueueWithDelay (Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, Time delay);
685  void Dequeue (Ptr<CobaltQueueDisc> queue, uint32_t modeSize);
693  void DequeueWithDelay (Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t nPkt, Time delay);
695 };
696 
698  : TestCase ("Test CE Threshold marking")
699 {
700  m_mode = mode;
701 }
702 
704 {
705 }
706 
707 void
709 {
710  Address dest;
711  for (uint32_t i = 0; i < nPkt; i++)
712  {
713  queue->Enqueue (Create<CobaltQueueDiscTestItem> (Create<Packet> (size), dest, 0, true));
714  }
715 }
716 
717 void
719 {
720  for (uint32_t i = 0; i < nPkt; i++)
721  {
722  Simulator::Schedule (Time (Seconds ((i + 1) * delay.GetSeconds ())), &CobaltQueueDiscCeThresholdTest::Enqueue, this, queue, size, 1);
723  }
724 }
725 
726 void
728 {
729  Ptr<QueueDiscItem> item = queue->Dequeue ();
730 
731  if (Simulator::Now () > MilliSeconds (11) && Simulator::Now () < MilliSeconds (28))
732  {
733  NS_TEST_EXPECT_MSG_EQ (queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 1, "There should be only 1 packet"
734  "mark, the delay between the enqueueing of the packets decreased after the"
735  "1st mark (packet enqueued at 11ms) and increased for the packet enqueued after 20.6ms."
736  "Queue delay remains below or equal to 1ms for the packet enqueued before 28ms");
737  }
738  if (Simulator::Now () > MilliSeconds (31) )
739  {
740  NS_TEST_EXPECT_MSG_EQ (queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 3, "There should be 3 packet"
741  "marks, the delay between the enqueueing of the packets decreased after 1st mark"
742  "(packet enqueued at 11ms) and increased for the packet enqueued after 20.6ms."
743  "Queue delay remains below 1ms for the packets enqueued before 28ms and increases"
744  "for the packets enqueued after 28ms.");
745  }
746 }
747 
748 void
749 CobaltQueueDiscCeThresholdTest::DequeueWithDelay (Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t nPkt, Time delay)
750 {
751  for (uint32_t i = 0; i < nPkt; i++)
752  {
753  Simulator::Schedule (Time (Seconds ((i + 1) * delay.GetSeconds ())), &CobaltQueueDiscCeThresholdTest::Dequeue, this, queue, modeSize);
754  }
755 }
756 
757 void
759 {
760  Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc> ();
761  uint32_t pktSize = 1000;
762  uint32_t modeSize = 0;
763 
765  {
766  modeSize = pktSize;
767  }
768  else if (m_mode == QueueSizeUnit::PACKETS)
769  {
770  modeSize = 1;
771  }
772 
773  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("UseEcn", BooleanValue (true)),
774  true, "Verify that we can actually set the attribute UseEcn");
775  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("CeThreshold", TimeValue (MilliSeconds (1))),
776  true, "Verify that we can actually set the attribute UseEcn");
777  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("BlueThreshold", TimeValue (Time::Max ())), true,
778  "Disable Blue enhancement");
779  queue->Initialize ();
780 
781  // Enqueue 11 packets every 1ms
782  EnqueueWithDelay (queue, pktSize, 11, MilliSeconds (1));
783 
784  // With every dequeue, queue delay increases by 0.1ms as packet enqueues every 1ms while dequeues at 1.1ms
785  // so at 11th dequeue, the dequeued packet should be marked.
786  Time dequeueInterval = MicroSeconds (1100);
787  DequeueWithDelay (queue, modeSize, 11, dequeueInterval);
788 
789  // First mark occured for the packet enqueued at 11ms, ideally TCP would decrease sending rate
790  // which can be simulated by increasing interval between subsequent enqueues, so packets are now enqueued with a delay 1.2ms.
791  Time waitUntilFirstMark = MilliSeconds(11);
792  Simulator::Schedule (waitUntilFirstMark, &CobaltQueueDiscCeThresholdTest::EnqueueWithDelay, this, queue, pktSize, 9, MicroSeconds (1200));
793 
794  // Keep dequeueing with the same delay
795  Simulator::Schedule (waitUntilFirstMark, &CobaltQueueDiscCeThresholdTest::DequeueWithDelay, this, queue, modeSize, 9, dequeueInterval);
796 
797  // Queue delay becomes 0.2ms for the packet enqueued at 20.6ms, time to decrease interval between subsequent enqueues,
798  // as ideally TCP would again start increasing sending rate
799  Time waitUntilDecreasingEnqueueDelay = waitUntilFirstMark + MilliSeconds(9);
800  Simulator::Schedule (waitUntilDecreasingEnqueueDelay, &CobaltQueueDiscCeThresholdTest::EnqueueWithDelay, this, queue, pktSize, 10, MilliSeconds (1));
801 
802  // Keep dequeueing with the same delay
803  Simulator::Schedule (waitUntilFirstMark, &CobaltQueueDiscCeThresholdTest::DequeueWithDelay, this, queue, modeSize, 10, dequeueInterval);
804 
805  Simulator::Run ();
806  Simulator::Destroy ();
807 }
808 
809 
823 {
824 public:
832 
833 private:
834  virtual void DoRun (void);
841  void Enqueue (Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
846  void Dequeue (Ptr<CobaltQueueDisc> queue);
853  void DequeueWithDelay (Ptr<CobaltQueueDisc> queue, uint32_t nPkt, Time delay);
855 };
856 
858  : TestCase ("Enhanced Blue tests verification for both packets and bytes mode")
859 {
860  m_mode = mode;
861 }
862 
864 {
865 }
866 
867 void
869 
870 {
871  uint32_t pktSize = 1500;
872  uint32_t modeSize = 0;
873  Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc> ();
874 
876  {
877  modeSize = pktSize;
878  }
879  else if (m_mode == QueueSizeUnit::PACKETS)
880  {
881  modeSize = 1;
882  }
883  queue->Initialize ();
884  queue->AssignStreams (1);
885  Enqueue (queue, modeSize, 200);
886  DequeueWithDelay (queue, 100, MilliSeconds (10));
887 
888  Simulator::Stop (Seconds (8.0));
889  Simulator::Run ();
890 
891  QueueDisc::Stats st = queue->GetStats ();
892 
893  // The Pdrop value should increase, from it's default value of zero
894  NS_TEST_ASSERT_MSG_EQ (queue->GetPdrop (), 0.234375, "Pdrop should be increased by 1/256 for every packet whose sojourn time is above 400ms."
895  " From the 41st dequeue until the last one, sojourn time is above 400ms, so 60 packets have sojourn time above 400ms"
896  "hence Pdrop should be increased 60*(1/256) which is 0.234375");
897  NS_TEST_ASSERT_MSG_EQ (st.GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 49, "There should a fixed number of drops (49 here)");
898  Simulator::Destroy ();
899 
900 
901  queue = CreateObject<CobaltQueueDisc> ();
902  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("UseEcn", BooleanValue (true)),
903  true, "Verify that we can actually set the attribute UseEcn");
904  NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("BlueThreshold", TimeValue (Time::Max ())), true,
905  "Disable Blue enhancement");
906  queue->Initialize ();
907  Enqueue (queue, modeSize, 200);
908  DequeueWithDelay (queue, 100, MilliSeconds (10));
909 
910  Simulator::Stop (Seconds (8.0));
911  Simulator::Run ();
912 
913  st = queue->GetStats ();
914 
915  NS_TEST_ASSERT_MSG_EQ (queue->GetPdrop (), 0, "Pdrop should be zero");
916  NS_TEST_ASSERT_MSG_EQ (st.GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not any dropped packets");
917  Simulator::Destroy ();
918 }
919 
920 void
922 {
923  Address dest;
924  for (uint32_t i = 0; i < nPkt; i++)
925  {
926  queue->Enqueue (Create<CobaltQueueDiscTestItem> (Create<Packet> (size), dest, 0, true));
927  }
928 }
929 
930 void
932 {
933  Ptr<QueueDiscItem> item = queue->Dequeue ();
934 }
935 
936 void
938 {
939  for (uint32_t i = 0; i < nPkt; i++)
940  {
941  Simulator::Schedule (Time (Seconds ((i + 1) * delay.GetSeconds ())), &CobaltQueueDiscEnhancedBlueTest::Dequeue, this, queue);
942  }
943 }
944 
945 
949 static class CobaltQueueDiscTestSuite : public TestSuite
950 {
951 public:
953  : TestSuite ("cobalt-queue-disc", UNIT)
954  {
955  // Test 1: simple enqueue/dequeue with no drops
956  AddTestCase (new CobaltQueueDiscBasicEnqueueDequeue (PACKETS), TestCase::QUICK);
957  AddTestCase (new CobaltQueueDiscBasicEnqueueDequeue (BYTES), TestCase::QUICK);
958  // Test 2: Drop test
959  AddTestCase (new CobaltQueueDiscDropTest (), TestCase::QUICK);
960  // Test 3: Mark test
961  AddTestCase (new CobaltQueueDiscMarkTest (PACKETS), TestCase::QUICK);
962  AddTestCase (new CobaltQueueDiscMarkTest (BYTES), TestCase::QUICK);
963  // Test 4: CE threshold marking test
964  AddTestCase (new CobaltQueueDiscCeThresholdTest (PACKETS), TestCase::QUICK);
965  AddTestCase (new CobaltQueueDiscCeThresholdTest (BYTES), TestCase::QUICK);
966  // Test 4: Blue enhancement test
967  AddTestCase (new CobaltQueueDiscEnhancedBlueTest (PACKETS), TestCase::QUICK);
968  AddTestCase (new CobaltQueueDiscEnhancedBlueTest (BYTES), TestCase::QUICK);
969  }
#define Max(a, b)
Test 1: simple enqueue/dequeue with no drops.
QueueSizeUnit m_mode
Queue test size function.
CobaltQueueDiscBasicEnqueueDequeue(QueueSizeUnit mode)
Constructor.
virtual void DoRun(void)
Implementation to actually run this TestCase.
Test 4: Cobalt Queue Disc CE Threshold marking Test Item.
CobaltQueueDiscCeThresholdTest(QueueSizeUnit mode)
Constructor.
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.
virtual void DoRun(void)
Implementation to actually run this TestCase.
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 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.
virtual void DoRun(void)
Implementation to actually run this TestCase.
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 Enqueue(Ptr< CobaltQueueDisc > queue, uint32_t size, uint32_t nPkt)
Enqueue function.
virtual void DoRun(void)
Implementation to actually run this TestCase.
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.
virtual void DoRun(void)
Implementation to actually run this TestCase.
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 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?
virtual void AddHeader(void)
Add the header to the packet.
virtual bool Mark(void)
Marks the packet as a substitute for dropping it, such as for Explicit Congestion Notification.
CobaltQueueDiscTestItem(const CobaltQueueDiscTestItem &)=delete
The COBALT queue disc test suite.
a polymophic address class
Definition: address.h:91
AttributeValue implementation for Boolean.
Definition: boolean.h:37
uint64_t GetUid(void) const
Returns the packet's Uid.
Definition: packet.cc:390
QueueDiscItem is the abstract base class for items that are stored in a queue disc.
Definition: queue-item.h:133
Class for representing queue sizes.
Definition: queue-size.h:95
AttributeValue implementation for QueueSize.
Definition: queue-size.h:221
Hold variables of type string.
Definition: string.h:41
encapsulates test code
Definition: test.h:994
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
A suite of tests to run.
Definition: test.h:1188
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1197
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
double GetSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:379
int64_t GetNanoSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:391
AttributeValue implementation for Time.
Definition: nstime.h:1308
CobaltQueueDiscTestSuite g_cobaltQueueTestSuite
the test suite
QueueSizeUnit
Enumeration of the operating modes of queues.
Definition: queue-size.h:43
@ BYTES
Use number of bytes for queue size.
Definition: queue-size.h:45
@ PACKETS
Use number of packets for queue size.
Definition: queue-size.h:44
Time Now(void)
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:287
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:141
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition: test.h:240
#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:542
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1260
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1252
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
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Ts... > MakeCallback(R(T::*memPtr)(Ts...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:1648
Structure that keeps the queue disc statistics.
Definition: queue-disc.h:186
uint32_t GetNDroppedPackets(std::string reason) const
Get the number of packets dropped for the given reason.
Definition: queue-disc.cc:109
uint32_t pktSize
packet size used for the simulation (in bytes)
Definition: wifi-bianchi.cc:89