A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
33using 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
77void
79{
80}
81
82bool
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
122void
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
142 if (m_mode == QueueSizeUnit::BYTES)
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
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);
289};
290
292 : TestCase("Drop tests verification for both packets and bytes mode")
293{
294}
295
296void
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
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");
340 0,
341 "Drops due to queue overflow should be non-zero");
342}
343
344void
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
360void
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
370void
372{
373 RunDropTest(QueueSizeUnit::PACKETS);
374 RunDropTest(QueueSizeUnit::BYTES);
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);
420};
421
423 : TestCase("Basic mark operations")
424{
425 m_mode = mode;
426 m_dropNextCount = 0;
427}
428
429void
430CobaltQueueDiscMarkTest::DropNextTracer(int64_t /* oldVal */, int64_t /* newVal */)
431{
433}
434
435void
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
450 if (m_mode == QueueSizeUnit::BYTES)
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
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
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
614}
615
616void
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
629void
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
891void
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
901void
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
918void
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
946void
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
962void
964{
965 Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
966 uint32_t pktSize = 1000;
967 uint32_t modeSize = 0;
968
969 if (m_mode == QueueSizeUnit::BYTES)
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
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
1099void
1101
1102{
1103 uint32_t pktSize = 1500;
1104 uint32_t modeSize = 0;
1105 Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
1106
1107 if (m_mode == QueueSizeUnit::BYTES)
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
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");
1134 49,
1135 "There should a fixed number of drops (49 here)");
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
1151
1152 st = queue->GetStats();
1153
1154 NS_TEST_ASSERT_MSG_EQ(queue->GetPdrop(), 0, "Pdrop should be zero");
1156 0,
1157 "There should not any dropped packets");
1159}
1160
1161void
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
1171void
1173{
1174 Ptr<QueueDiscItem> item = queue->Dequeue();
1175}
1176
1177void
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", Type::UNIT)
1200 {
1201 // Test 1: simple enqueue/dequeue with no drops
1202 AddTestCase(new CobaltQueueDiscBasicEnqueueDequeue(PACKETS), TestCase::Duration::QUICK);
1203 AddTestCase(new CobaltQueueDiscBasicEnqueueDequeue(BYTES), TestCase::Duration::QUICK);
1204 // Test 2: Drop test
1205 AddTestCase(new CobaltQueueDiscDropTest(), TestCase::Duration::QUICK);
1206 // Test 3: Mark test
1207 AddTestCase(new CobaltQueueDiscMarkTest(PACKETS), TestCase::Duration::QUICK);
1208 AddTestCase(new CobaltQueueDiscMarkTest(BYTES), TestCase::Duration::QUICK);
1209 // Test 4: CE threshold marking test
1210 AddTestCase(new CobaltQueueDiscCeThresholdTest(PACKETS), TestCase::Duration::QUICK);
1211 AddTestCase(new CobaltQueueDiscCeThresholdTest(BYTES), TestCase::Duration::QUICK);
1212 // Test 4: Blue enhancement test
1213 AddTestCase(new CobaltQueueDiscEnhancedBlueTest(PACKETS), TestCase::Duration::QUICK);
1214 AddTestCase(new CobaltQueueDiscEnhancedBlueTest(BYTES), TestCase::Duration::QUICK);
1215 }
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
CobaltQueueDiscTestItem & operator=(const CobaltQueueDiscTestItem &)=delete
void AddHeader() override
Add the header to the packet.
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
AttributeValue implementation for Boolean.
Definition: boolean.h:37
static constexpr const char * CE_THRESHOLD_EXCEEDED_MARK
Sojourn time above CE threshold.
static constexpr const char * TARGET_EXCEEDED_DROP
Sojourn time above target.
static constexpr const char * FORCED_MARK
forced marks by Codel on ECN-enabled
static constexpr const char * OVERLIMIT_DROP
Overlimit dropped packet.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
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.
Definition: queue-size.h:221
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static void Run()
Run the simulation.
Definition: simulator.cc:178
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:186
Hold variables of type string.
Definition: string.h:56
encapsulates test code
Definition: test.h:1061
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1268
Type
Type of test.
Definition: test.h:1275
static constexpr auto UNIT
Definition: test.h:1286
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
static Time Max()
Maximum representable Time Not to be confused with Max(Time,Time).
Definition: nstime.h:297
AttributeValue implementation for Time.
Definition: nstime.h:1413
QueueSizeUnit
Enumeration of the operating modes of queues.
Definition: queue-size.h:44
@ BYTES
Use number of bytes for queue size.
Definition: queue-size.h:46
@ PACKETS
Use number of packets for queue size.
Definition: queue-size.h:45
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:145
#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:252
#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:565
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
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
STL namespace.
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)