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
33using namespace ns3;
34
42{
43 public:
52 CobaltQueueDiscTestItem(Ptr<Packet> p, const Address& addr, uint16_t protocol, bool ecnCapable);
53 ~CobaltQueueDiscTestItem() override;
54
55 // Delete default constructor, copy constructor and assignment operator to avoid misuse
59
60 void AddHeader() override;
61 bool Mark() override;
62
63 private:
65};
66
68 const Address& addr,
69 uint16_t protocol,
70 bool ecnCapable)
71 : QueueDiscItem(p, addr, ecnCapable),
72 m_ecnCapablePacket(ecnCapable)
73{
74}
75
77{
78}
79
80void
82{
83}
84
85bool
87{
89 {
90 return true;
91 }
92 return false;
93}
94
102{
103 public:
110 void DoRun() override;
111
120 private:
122};
123
125 : TestCase("Basic enqueue and dequeue operations, and attribute setting" + std::to_string(mode))
126{
127 m_mode = mode;
128}
129
130void
132{
133 Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
134
135 uint32_t pktSize = 1000;
136 uint32_t modeSize = 0;
137
138 Address dest;
139
140 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Interval", StringValue("50ms")),
141 true,
142 "Verify that we can actually set the attribute Interval");
143 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Target", StringValue("4ms")),
144 true,
145 "Verify that we can actually set the attribute Target");
146 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
147 true,
148 "Disable Blue enhancement");
149
151 {
152 modeSize = pktSize;
153 }
154 else if (m_mode == QueueSizeUnit::PACKETS)
155 {
156 modeSize = 1;
157 }
159 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 1500))),
160 true,
161 "Verify that we can actually set the attribute MaxSize");
162 queue->Initialize();
163
164 Ptr<Packet> p1;
165 Ptr<Packet> p2;
166 Ptr<Packet> p3;
167 Ptr<Packet> p4;
168 Ptr<Packet> p5;
169 Ptr<Packet> p6;
170 p1 = Create<Packet>(pktSize);
171 p2 = Create<Packet>(pktSize);
172 p3 = Create<Packet>(pktSize);
173 p4 = Create<Packet>(pktSize);
174 p5 = Create<Packet>(pktSize);
175 p6 = Create<Packet>(pktSize);
176
177 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
178 0 * modeSize,
179 "There should be no packets in queue");
180 queue->Enqueue(Create<CobaltQueueDiscTestItem>(p1, dest, 0, false));
181 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
182 1 * modeSize,
183 "There should be one packet in queue");
184 queue->Enqueue(Create<CobaltQueueDiscTestItem>(p2, dest, 0, false));
185 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
186 2 * modeSize,
187 "There should be two packets in queue");
188 queue->Enqueue(Create<CobaltQueueDiscTestItem>(p3, dest, 0, false));
189 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
190 3 * modeSize,
191 "There should be three packets in queue");
192 queue->Enqueue(Create<CobaltQueueDiscTestItem>(p4, dest, 0, false));
193 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
194 4 * modeSize,
195 "There should be four packets in queue");
196 queue->Enqueue(Create<CobaltQueueDiscTestItem>(p5, dest, 0, false));
197 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
198 5 * modeSize,
199 "There should be five packets in queue");
200 queue->Enqueue(Create<CobaltQueueDiscTestItem>(p6, dest, 0, false));
201 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
202 6 * modeSize,
203 "There should be six packets in queue");
204
205 NS_TEST_ASSERT_MSG_EQ(queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::OVERLIMIT_DROP),
206 0,
207 "There should be no packets being dropped due to full queue");
208
210
211 item = queue->Dequeue();
212 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the first packet");
213 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
214 5 * modeSize,
215 "There should be five packets in queue");
216 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p1->GetUid(), "was this the first packet ?");
217
218 item = queue->Dequeue();
219 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the second packet");
220 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
221 4 * modeSize,
222 "There should be four packets in queue");
223 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(),
224 p2->GetUid(),
225 "Was this the second packet ?");
226
227 item = queue->Dequeue();
228 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the third packet");
229 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
230 3 * modeSize,
231 "There should be three packets in queue");
232 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p3->GetUid(), "Was this the third packet ?");
233
234 item = queue->Dequeue();
235 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the forth packet");
236 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
237 2 * modeSize,
238 "There should be two packets in queue");
239 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(),
240 p4->GetUid(),
241 "Was this the fourth packet ?");
242
243 item = queue->Dequeue();
244 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the fifth packet");
245 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
246 1 * modeSize,
247 "There should be one packet in queue");
248 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p5->GetUid(), "Was this the fifth packet ?");
249
250 item = queue->Dequeue();
251 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the last packet");
252 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
253 0 * modeSize,
254 "There should be zero packet in queue");
255 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p6->GetUid(), "Was this the sixth packet ?");
256
257 item = queue->Dequeue();
258 NS_TEST_ASSERT_MSG_EQ(item, nullptr, "There are really no packets in queue");
259
261 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
262 0,
263 "There should be no packet drops according to Cobalt algorithm");
264}
265
273{
274 public:
276 void DoRun() override;
283 void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
288 void RunDropTest(QueueSizeUnit mode);
298};
299
301 : TestCase("Drop tests verification for both packets and bytes mode")
302{
303}
304
305void
307
308{
309 uint32_t pktSize = 1500;
310 uint32_t modeSize = 0;
311 Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
312
313 if (mode == QueueSizeUnit::BYTES)
314 {
315 modeSize = pktSize;
316 }
317 else if (mode == QueueSizeUnit::PACKETS)
318 {
319 modeSize = 1;
320 }
321
322 queue = CreateObject<CobaltQueueDisc>();
324 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(mode, modeSize * 100))),
325 true,
326 "Verify that we can actually set the attribute MaxSize");
327 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
328 true,
329 "Disable Blue enhancement");
330 queue->Initialize();
331
332 if (mode == QueueSizeUnit::BYTES)
333 {
334 EnqueueWithDelay(queue, pktSize, 200);
335 }
336 else
337 {
338 EnqueueWithDelay(queue, 1, 200);
339 }
340
341 Simulator::Stop(Seconds(8.0));
342 Simulator::Run();
343
344 QueueDisc::Stats st = queue->GetStats();
345
346 // The Pdrop value should increase, from it's default value of zero
347 NS_TEST_ASSERT_MSG_NE(queue->GetPdrop(), 0, "Pdrop should be non-zero");
348 NS_TEST_ASSERT_MSG_NE(st.GetNDroppedPackets(CobaltQueueDisc::OVERLIMIT_DROP),
349 0,
350 "Drops due to queue overflow should be non-zero");
351}
352
353void
355{
356 Address dest;
357 double delay = 0.01; // enqueue packets with delay
358 for (uint32_t i = 0; i < nPkt; i++)
359 {
360 Simulator::Schedule(Time(Seconds((i + 1) * delay)),
362 this,
363 queue,
364 size,
365 1);
366 }
367}
368
369void
371{
372 Address dest;
373 for (uint32_t i = 0; i < nPkt; i++)
374 {
375 queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, 0, true));
376 }
377}
378
379void
381{
384 Simulator::Destroy();
385}
386
394{
395 public:
402 void DoRun() override;
403
404 private:
412 void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, bool ecnCapable);
419 void Dequeue(Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t testCase);
425 void DropNextTracer(int64_t oldVal, int64_t newVal);
430};
431
433 : TestCase("Basic mark operations")
434{
435 m_mode = mode;
436 m_dropNextCount = 0;
437}
438
439void
440CobaltQueueDiscMarkTest::DropNextTracer(int64_t /* oldVal */, int64_t /* newVal */)
441{
443}
444
445void
447{
448 // Test is divided into 3 sub test cases:
449 // 1) Packets are not ECN capable.
450 // 2) Packets are ECN capable.
451 // 3) Some packets are ECN capable.
452
453 // Test case 1
454 Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
455 uint32_t pktSize = 1000;
456 uint32_t modeSize = 0;
459
461 {
462 modeSize = pktSize;
463 }
464 else if (m_mode == QueueSizeUnit::PACKETS)
465 {
466 modeSize = 1;
467 }
468
470 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
471 true,
472 "Verify that we can actually set the attribute MaxSize");
473 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(false)),
474 true,
475 "Verify that we can actually set the attribute UseEcn");
476 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
477 true,
478 "Disable Blue enhancement");
479 queue->Initialize();
480
481 // Not-ECT traffic to induce packet drop
482 Enqueue(queue, pktSize, 20, false);
483 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
484 20 * modeSize,
485 "There should be 20 packets in queue.");
486
487 // Although the first dequeue occurs with a sojourn time above target
488 // there should not be any dropped packets in this interval
489 Time waitUntilFirstDequeue = 2 * queue->GetTarget();
490 Simulator::Schedule(waitUntilFirstDequeue,
492 this,
493 queue,
494 modeSize,
495 1);
496
497 // This dequeue should cause a packet to be dropped
498 Time waitUntilSecondDequeue = waitUntilFirstDequeue + 2 * queue->GetInterval();
499 Simulator::Schedule(waitUntilSecondDequeue,
501 this,
502 queue,
503 modeSize,
504 1);
505
506 Simulator::Run();
507 Simulator::Destroy();
508
509 // Test case 2, queue with ECN capable traffic for marking of packets instead of dropping
510 queue = CreateObject<CobaltQueueDisc>();
512 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
513 true,
514 "Verify that we can actually set the attribute MaxSize");
515 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
516 true,
517 "Verify that we can actually set the attribute UseEcn");
518 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
519 true,
520 "Disable Blue enhancement");
521 queue->Initialize();
522
523 // ECN capable traffic
524 Enqueue(queue, pktSize, 20, true);
525 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
526 20 * modeSize,
527 "There should be 20 packets in queue.");
528
529 // Although the first dequeue occurs with a sojourn time above target
530 // there should not be any marked packets in this interval
531 Simulator::Schedule(waitUntilFirstDequeue,
533 this,
534 queue,
535 modeSize,
536 2);
537
538 // This dequeue should cause a packet to be marked
539 Simulator::Schedule(waitUntilSecondDequeue,
541 this,
542 queue,
543 modeSize,
544 2);
545
546 // This dequeue should cause a packet to be marked as dropnext is equal to current time
547 Simulator::Schedule(waitUntilSecondDequeue,
549 this,
550 queue,
551 modeSize,
552 2);
553
554 // In dropping phase and it's time for next packet to be marked
555 // the dequeue should cause additional packet to be marked
556 Simulator::Schedule(waitUntilSecondDequeue * 2,
558 this,
559 queue,
560 modeSize,
561 2);
562
563 Simulator::Run();
564 Simulator::Destroy();
565
566 // Test case 3, some packets are ECN capable
567 queue = CreateObject<CobaltQueueDisc>();
569 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
570 true,
571 "Verify that we can actually set the attribute MaxSize");
572 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
573 true,
574 "Verify that we can actually set the attribute UseEcn");
575 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
576 true,
577 "Disable Blue enhancement");
578 queue->Initialize();
579
580 // First 3 packets in the queue are ecnCapable
581 Enqueue(queue, pktSize, 3, true);
582 // Rest of the packet are not ecnCapable
583 Enqueue(queue, pktSize, 17, false);
584 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
585 20 * modeSize,
586 "There should be 20 packets in queue.");
587
588 // Although the first dequeue occurs with a sojourn time above target
589 // there should not be any marked packets in this interval
590 Simulator::Schedule(waitUntilFirstDequeue,
592 this,
593 queue,
594 modeSize,
595 3);
596
597 // This dequeue should cause a packet to be marked
598 Simulator::Schedule(waitUntilSecondDequeue,
600 this,
601 queue,
602 modeSize,
603 3);
604
605 // This dequeue should cause a packet to be marked as dropnext is equal to current time
606 Simulator::Schedule(waitUntilSecondDequeue,
608 this,
609 queue,
610 modeSize,
611 3);
612
613 // In dropping phase and it's time for next packet to be dropped as packets are not ECN capable
614 // the dequeue should cause packet to be dropped
615 Simulator::Schedule(waitUntilSecondDequeue * 2,
617 this,
618 queue,
619 modeSize,
620 3);
621
622 Simulator::Run();
623 Simulator::Destroy();
624}
625
626void
628 uint32_t size,
629 uint32_t nPkt,
630 bool ecnCapable)
631{
632 Address dest;
633 for (uint32_t i = 0; i < nPkt; i++)
634 {
635 queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, 0, ecnCapable));
636 }
637}
638
639void
641{
642 uint32_t initialMarkCount = queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
643 uint32_t initialQSize = queue->GetCurrentSize().GetValue();
644 uint32_t initialDropNext = queue->GetDropNext();
645 Time currentTime = Simulator::Now();
646 uint32_t currentDropCount = 0;
647 uint32_t currentMarkCount = 0;
648
649 if (initialMarkCount > 0 && currentTime.GetNanoSeconds() > initialDropNext && testCase == 3)
650 {
651 queue->TraceConnectWithoutContext(
652 "DropNext",
654 }
655
656 if (initialQSize != 0)
657 {
658 Ptr<QueueDiscItem> item = queue->Dequeue();
659 if (testCase == 1)
660 {
661 currentDropCount =
662 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
663 if (currentDropCount != 0)
664 {
665 nPacketsBeforeFirstDrop = initialQSize;
666 }
667 }
668 if (testCase == 2)
669 {
670 if (initialMarkCount == 0 && currentTime > queue->GetTarget())
671 {
672 if (currentTime < queue->GetInterval())
673 {
674 currentDropCount =
675 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
676 currentMarkCount =
677 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
678 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
679 initialQSize - modeSize,
680 "There should be 1 packet dequeued.");
681 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
682 0,
683 "There should not be any packet drops");
684 NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
685 0,
686 "We are not in dropping state."
687 "Sojourn time has just gone above target from below."
688 "Hence, there should be no marked packets");
689 }
690 else if (currentTime >= queue->GetInterval())
691 {
692 nPacketsBeforeFirstMark = initialQSize;
693 currentDropCount =
694 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
695 currentMarkCount =
696 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
698 queue->GetCurrentSize().GetValue(),
699 initialQSize - modeSize,
700 "Sojourn time has been above target for at least interval."
701 "We enter the dropping state and perform initial packet marking"
702 "So there should be only 1 more packet dequeued.");
703 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
704 0,
705 "There should not be any packet drops");
706 NS_TEST_EXPECT_MSG_EQ(currentMarkCount, 1, "There should be 1 marked packet");
707 }
708 }
709 else if (initialMarkCount > 0)
710 {
711 if (currentTime.GetNanoSeconds() <= initialDropNext)
712 {
713 currentDropCount =
714 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
715 currentMarkCount =
716 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
717 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
718 initialQSize - modeSize,
719 "We are in dropping state."
720 "Sojourn is still above target."
721 "There should be only 1 more packet dequeued");
722 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
723 0,
724 "There should not be any packet drops");
725 NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
726 2,
727 "There should be 2 marked packet as."
728 "current dropnext is equal to current time.");
729 }
730 else if (currentTime.GetNanoSeconds() > initialDropNext)
731 {
732 currentDropCount =
733 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
734 currentMarkCount =
735 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
736 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
737 initialQSize - modeSize,
738 "We are in dropping state."
739 "It's time for packet to be marked"
740 "So there should be only 1 more packet dequeued");
741 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
742 0,
743 "There should not be any packet drops");
744 NS_TEST_EXPECT_MSG_EQ(currentMarkCount, 3, "There should be 3 marked packet");
748 "Number of packets in the queue before drop should be equal"
749 "to number of packets in the queue before first mark as the behavior until "
750 "packet N should be the same.");
751 }
752 }
753 }
754 else if (testCase == 3)
755 {
756 if (initialMarkCount == 0 && currentTime > queue->GetTarget())
757 {
758 if (currentTime < queue->GetInterval())
759 {
760 currentDropCount =
761 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
762 currentMarkCount =
763 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
764 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
765 initialQSize - modeSize,
766 "There should be 1 packet dequeued.");
767 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
768 0,
769 "There should not be any packet drops");
770 NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
771 0,
772 "We are not in dropping state."
773 "Sojourn time has just gone above target from below."
774 "Hence, there should be no marked packets");
775 }
776 else if (currentTime >= queue->GetInterval())
777 {
778 currentDropCount =
779 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
780 currentMarkCount =
781 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
783 queue->GetCurrentSize().GetValue(),
784 initialQSize - modeSize,
785 "Sojourn time has been above target for at least interval."
786 "We enter the dropping state and perform initial packet marking"
787 "So there should be only 1 more packet dequeued.");
788 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
789 0,
790 "There should not be any packet drops");
791 NS_TEST_EXPECT_MSG_EQ(currentMarkCount, 1, "There should be 1 marked packet");
792 }
793 }
794 else if (initialMarkCount > 0)
795 {
796 if (currentTime.GetNanoSeconds() <= initialDropNext)
797 {
798 currentDropCount =
799 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
800 currentMarkCount =
801 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
802 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
803 initialQSize - modeSize,
804 "We are in dropping state."
805 "Sojourn is still above target."
806 "So there should be only 1 more packet dequeued");
807 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
808 0,
809 "There should not be any packet drops");
810 NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
811 2,
812 "There should be 2 marked packet"
813 "as dropnext is equal to current time");
814 }
815 else if (currentTime.GetNanoSeconds() > initialDropNext)
816 {
817 currentDropCount =
818 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
819 currentMarkCount =
820 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
822 queue->GetCurrentSize().GetValue(),
823 initialQSize - (m_dropNextCount + 1) * modeSize,
824 "We are in dropping state."
825 "It's time for packet to be dropped as packets are not ecnCapable"
826 "The number of packets dequeued equals to the number of times m_dropNext "
827 "is updated plus initial dequeue");
829 currentDropCount,
831 "The number of drops equals to the number of times m_dropNext is updated");
832 NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
833 2,
834 "There should still be only 2 marked packet");
835 }
836 }
837 }
838 }
839}
840
848{
849 public:
857
858 private:
859 void DoRun() override;
866 void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
874 void EnqueueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, Time delay);
880 void Dequeue(Ptr<CobaltQueueDisc> queue, uint32_t modeSize);
888 void DequeueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t nPkt, Time delay);
890};
891
893 : TestCase("Test CE Threshold marking")
894{
895 m_mode = mode;
896}
897
899{
900}
901
902void
904{
905 Address dest;
906 for (uint32_t i = 0; i < nPkt; i++)
907 {
908 queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, 0, true));
909 }
910}
911
912void
914 uint32_t size,
915 uint32_t nPkt,
916 Time delay)
917{
918 for (uint32_t i = 0; i < nPkt; i++)
919 {
920 Simulator::Schedule(Time(Seconds((i + 1) * delay.GetSeconds())),
922 this,
923 queue,
924 size,
925 1);
926 }
927}
928
929void
931{
932 Ptr<QueueDiscItem> item = queue->Dequeue();
933
935 {
937 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
938 1,
939 "There should be only 1 packet"
940 "mark, the delay between the enqueueing of the packets decreased after the"
941 "1st mark (packet enqueued at 11ms) and increased for the packet enqueued after 20.6ms."
942 "Queue delay remains below or equal to 1ms for the packet enqueued before 28ms");
943 }
944 if (Simulator::Now() > MilliSeconds(31))
945 {
947 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
948 3,
949 "There should be 3 packet"
950 "marks, the delay between the enqueueing of the packets decreased after 1st mark"
951 "(packet enqueued at 11ms) and increased for the packet enqueued after 20.6ms."
952 "Queue delay remains below 1ms for the packets enqueued before 28ms and increases"
953 "for the packets enqueued after 28ms.");
954 }
955}
956
957void
959 uint32_t modeSize,
960 uint32_t nPkt,
961 Time delay)
962{
963 for (uint32_t i = 0; i < nPkt; i++)
964 {
965 Simulator::Schedule(Time(Seconds((i + 1) * delay.GetSeconds())),
967 this,
968 queue,
969 modeSize);
970 }
971}
972
973void
975{
976 Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
977 uint32_t pktSize = 1000;
978 uint32_t modeSize = 0;
979
981 {
982 modeSize = pktSize;
983 }
984 else if (m_mode == QueueSizeUnit::PACKETS)
985 {
986 modeSize = 1;
987 }
988
989 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
990 true,
991 "Verify that we can actually set the attribute UseEcn");
992 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("CeThreshold", TimeValue(MilliSeconds(1))),
993 true,
994 "Verify that we can actually set the attribute UseEcn");
995 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
996 true,
997 "Disable Blue enhancement");
998 queue->Initialize();
999
1000 // Enqueue 11 packets every 1ms
1001 EnqueueWithDelay(queue, pktSize, 11, MilliSeconds(1));
1002
1003 // With every dequeue, queue delay increases by 0.1ms as packet enqueues every 1ms while
1004 // dequeues at 1.1ms so at 11th dequeue, the dequeued packet should be marked.
1005 Time dequeueInterval = MicroSeconds(1100);
1006 DequeueWithDelay(queue, modeSize, 11, dequeueInterval);
1007
1008 // First mark occured for the packet enqueued at 11ms, ideally TCP would decrease sending rate
1009 // which can be simulated by increasing interval between subsequent enqueues, so packets are now
1010 // enqueued with a delay 1.2ms.
1011 Time waitUntilFirstMark = MilliSeconds(11);
1012 Simulator::Schedule(waitUntilFirstMark,
1014 this,
1015 queue,
1016 pktSize,
1017 9,
1018 MicroSeconds(1200));
1019
1020 // Keep dequeueing with the same delay
1021 Simulator::Schedule(waitUntilFirstMark,
1023 this,
1024 queue,
1025 modeSize,
1026 9,
1027 dequeueInterval);
1028
1029 // Queue delay becomes 0.2ms for the packet enqueued at 20.6ms, time to decrease interval
1030 // between subsequent enqueues, as ideally TCP would again start increasing sending rate
1031 Time waitUntilDecreasingEnqueueDelay = waitUntilFirstMark + MilliSeconds(9);
1032 Simulator::Schedule(waitUntilDecreasingEnqueueDelay,
1034 this,
1035 queue,
1036 pktSize,
1037 10,
1038 MilliSeconds(1));
1039
1040 // Keep dequeueing with the same delay
1041 Simulator::Schedule(waitUntilFirstMark,
1043 this,
1044 queue,
1045 modeSize,
1046 10,
1047 dequeueInterval);
1048
1049 Simulator::Run();
1050 Simulator::Destroy();
1051}
1052
1067{
1068 public:
1076
1077 private:
1078 void DoRun() override;
1085 void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
1090 void Dequeue(Ptr<CobaltQueueDisc> queue);
1097 void DequeueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t nPkt, Time delay);
1099};
1100
1102 : TestCase("Enhanced Blue tests verification for both packets and bytes mode")
1103{
1104 m_mode = mode;
1105}
1106
1108{
1109}
1110
1111void
1113
1114{
1115 uint32_t pktSize = 1500;
1116 uint32_t modeSize = 0;
1117 Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc>();
1118
1120 {
1121 modeSize = pktSize;
1122 }
1123 else if (m_mode == QueueSizeUnit::PACKETS)
1124 {
1125 modeSize = 1;
1126 }
1127 queue->Initialize();
1128 queue->AssignStreams(1);
1129 Enqueue(queue, modeSize, 200);
1130 DequeueWithDelay(queue, 100, MilliSeconds(10));
1131
1132 Simulator::Stop(Seconds(8.0));
1133 Simulator::Run();
1134
1135 QueueDisc::Stats st = queue->GetStats();
1136
1137 // The Pdrop value should increase, from it's default value of zero
1139 queue->GetPdrop(),
1140 0.234375,
1141 "Pdrop should be increased by 1/256 for every packet whose sojourn time is above 400ms."
1142 " From the 41st dequeue until the last one, sojourn time is above 400ms, so 60 packets "
1143 "have sojourn time above 400ms"
1144 "hence Pdrop should be increased 60*(1/256) which is 0.234375");
1145 NS_TEST_ASSERT_MSG_EQ(st.GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1146 49,
1147 "There should a fixed number of drops (49 here)");
1148 Simulator::Destroy();
1149
1150 queue = CreateObject<CobaltQueueDisc>();
1151 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
1152 true,
1153 "Verify that we can actually set the attribute UseEcn");
1154 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
1155 true,
1156 "Disable Blue enhancement");
1157 queue->Initialize();
1158 Enqueue(queue, modeSize, 200);
1159 DequeueWithDelay(queue, 100, MilliSeconds(10));
1160
1161 Simulator::Stop(Seconds(8.0));
1162 Simulator::Run();
1163
1164 st = queue->GetStats();
1165
1166 NS_TEST_ASSERT_MSG_EQ(queue->GetPdrop(), 0, "Pdrop should be zero");
1167 NS_TEST_ASSERT_MSG_EQ(st.GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1168 0,
1169 "There should not any dropped packets");
1170 Simulator::Destroy();
1171}
1172
1173void
1175{
1176 Address dest;
1177 for (uint32_t i = 0; i < nPkt; i++)
1178 {
1179 queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, 0, true));
1180 }
1181}
1182
1183void
1185{
1186 Ptr<QueueDiscItem> item = queue->Dequeue();
1187}
1188
1189void
1191 uint32_t nPkt,
1192 Time delay)
1193{
1194 for (uint32_t i = 0; i < nPkt; i++)
1195 {
1196 Simulator::Schedule(Time(Seconds((i + 1) * delay.GetSeconds())),
1198 this,
1199 queue);
1200 }
1201}
1202
1207{
1208 public:
1210 : TestSuite("cobalt-queue-disc", UNIT)
1211 {
1212 // Test 1: simple enqueue/dequeue with no drops
1215 // Test 2: Drop test
1216 AddTestCase(new CobaltQueueDiscDropTest(), TestCase::QUICK);
1217 // Test 3: Mark test
1218 AddTestCase(new CobaltQueueDiscMarkTest(PACKETS), TestCase::QUICK);
1219 AddTestCase(new CobaltQueueDiscMarkTest(BYTES), TestCase::QUICK);
1220 // Test 4: CE threshold marking test
1221 AddTestCase(new CobaltQueueDiscCeThresholdTest(PACKETS), TestCase::QUICK);
1222 AddTestCase(new CobaltQueueDiscCeThresholdTest(BYTES), TestCase::QUICK);
1223 // Test 4: Blue enhancement test
1225 AddTestCase(new CobaltQueueDiscEnhancedBlueTest(BYTES), TestCase::QUICK);
1226 }
#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
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:92
AttributeValue implementation for Boolean.
Definition: boolean.h:37
uint64_t GetUid() const
Returns the packet's Uid.
Definition: packet.cc:412
QueueDiscItem is the abstract base class for items that are stored in a queue disc.
Definition: queue-item.h:133
Class for representing queue sizes.
Definition: queue-size.h:96
AttributeValue implementation for QueueSize.
Hold variables of type string.
Definition: string.h:42
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:305
A suite of tests to run.
Definition: test.h:1256
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1265
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:417
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:402
AttributeValue implementation for Time.
Definition: nstime.h:1425
CobaltQueueDiscTestSuite g_cobaltQueueTestSuite
the test suite
QueueSizeUnit
Enumeration of the operating modes of queues.
Definition: queue-size.h:44
@ BYTES
Use number of bytes for queue size.
Definition: queue-size.h:46
@ PACKETS
Use number of packets for queue size.
Definition: queue-size.h:45
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:296
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:144
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition: test.h:251
#define NS_TEST_ASSERT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report and abort if not.
Definition: test.h:564
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1362
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:850
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:691
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)