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 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Ported to ns-3 by: Vignesh Kannan <vignesh2496@gmail.com>
7 * Harsh Lara <harshapplefan@gmail.com>
8 * Jendaipou Palmei <jendaipoupalmei@gmail.com>
9 * Shefali Gupta <shefaligups11@gmail.com>
10 * Mohit P. Tahiliani <tahiliani@nitk.edu.in>
11 */
12
13#include "ns3/cobalt-queue-disc.h"
14#include "ns3/double.h"
15#include "ns3/log.h"
16#include "ns3/packet.h"
17#include "ns3/simulator.h"
18#include "ns3/string.h"
19#include "ns3/test.h"
20#include "ns3/uinteger.h"
21
22using namespace ns3;
23
24/**
25 * @ingroup traffic-control-test
26 *
27 * @brief Cobalt Queue Disc Test Item
28 */
30{
31 public:
32 /**
33 * Constructor
34 *
35 * @param p packet
36 * @param addr address
37 * @param ecnCapable ECN capable
38 */
39 CobaltQueueDiscTestItem(Ptr<Packet> p, const Address& addr, bool ecnCapable);
40 ~CobaltQueueDiscTestItem() override;
41
42 // Delete default constructor, copy constructor and assignment operator to avoid misuse
46
47 void AddHeader() override;
48 bool Mark() override;
49
50 private:
51 bool m_ecnCapablePacket; ///< ECN capable packet?
52};
53
55 const Address& addr,
56 bool ecnCapable)
57 : QueueDiscItem(p, addr, 0),
58 m_ecnCapablePacket(ecnCapable)
59{
60}
61
65
66void
70
71bool
76
77/**
78 * @ingroup traffic-control-test
79 *
80 * @brief Test 1: simple enqueue/dequeue with no drops
81 */
83{
84 public:
85 /**
86 * Constructor
87 *
88 * @param mode the mode
89 */
91 void DoRun() override;
92
93 /**
94 * Queue test size function
95 * @param queue the queue disc
96 * @param size the size
97 * @param error the error string
98 *
99 */
100
101 private:
103};
104
106 : TestCase("Basic enqueue and dequeue operations, and attribute setting" + std::to_string(mode))
107{
108 m_mode = mode;
109}
110
111void
113{
115
116 uint32_t pktSize = 1000;
117 uint32_t modeSize = 0;
118
119 Address dest;
120
121 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Interval", StringValue("50ms")),
122 true,
123 "Verify that we can actually set the attribute Interval");
124 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Target", StringValue("4ms")),
125 true,
126 "Verify that we can actually set the attribute Target");
127 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
128 true,
129 "Disable Blue enhancement");
130
131 if (m_mode == QueueSizeUnit::BYTES)
132 {
133 modeSize = pktSize;
134 }
135 else if (m_mode == QueueSizeUnit::PACKETS)
136 {
137 modeSize = 1;
138 }
140 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 1500))),
141 true,
142 "Verify that we can actually set the attribute MaxSize");
143 queue->Initialize();
144
145 Ptr<Packet> p1;
146 Ptr<Packet> p2;
147 Ptr<Packet> p3;
148 Ptr<Packet> p4;
149 Ptr<Packet> p5;
150 Ptr<Packet> p6;
157
158 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
159 0 * modeSize,
160 "There should be no packets in queue");
161 queue->Enqueue(Create<CobaltQueueDiscTestItem>(p1, dest, false));
162 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
163 1 * modeSize,
164 "There should be one packet in queue");
165 queue->Enqueue(Create<CobaltQueueDiscTestItem>(p2, dest, false));
166 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
167 2 * modeSize,
168 "There should be two packets in queue");
169 queue->Enqueue(Create<CobaltQueueDiscTestItem>(p3, dest, false));
170 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
171 3 * modeSize,
172 "There should be three packets in queue");
173 queue->Enqueue(Create<CobaltQueueDiscTestItem>(p4, dest, false));
174 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
175 4 * modeSize,
176 "There should be four packets in queue");
177 queue->Enqueue(Create<CobaltQueueDiscTestItem>(p5, dest, false));
178 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
179 5 * modeSize,
180 "There should be five packets in queue");
181 queue->Enqueue(Create<CobaltQueueDiscTestItem>(p6, dest, false));
182 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
183 6 * modeSize,
184 "There should be six packets in queue");
185
186 NS_TEST_ASSERT_MSG_EQ(queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::OVERLIMIT_DROP),
187 0,
188 "There should be no packets being dropped due to full queue");
189
191
192 item = queue->Dequeue();
193 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the first packet");
194 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
195 5 * modeSize,
196 "There should be five packets in queue");
197 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p1->GetUid(), "was this the first packet ?");
198
199 item = queue->Dequeue();
200 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the second packet");
201 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
202 4 * modeSize,
203 "There should be four packets in queue");
204 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(),
205 p2->GetUid(),
206 "Was this the second packet ?");
207
208 item = queue->Dequeue();
209 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the third packet");
210 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
211 3 * modeSize,
212 "There should be three packets in queue");
213 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p3->GetUid(), "Was this the third packet ?");
214
215 item = queue->Dequeue();
216 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the forth packet");
217 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
218 2 * modeSize,
219 "There should be two packets in queue");
220 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(),
221 p4->GetUid(),
222 "Was this the fourth packet ?");
223
224 item = queue->Dequeue();
225 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the fifth packet");
226 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
227 1 * modeSize,
228 "There should be one packet in queue");
229 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p5->GetUid(), "Was this the fifth packet ?");
230
231 item = queue->Dequeue();
232 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the last packet");
233 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
234 0 * modeSize,
235 "There should be zero packet in queue");
236 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p6->GetUid(), "Was this the sixth packet ?");
237
238 item = queue->Dequeue();
239 NS_TEST_ASSERT_MSG_EQ(item, nullptr, "There are really no packets in queue");
240
242 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
243 0,
244 "There should be no packet drops according to Cobalt algorithm");
245}
246
247/**
248 * @ingroup traffic-control-test
249 *
250 * @brief Test 2: Cobalt Queue Disc Drop Test Item
251 */
253{
254 public:
256 void DoRun() override;
257 /**
258 * Enqueue function
259 * @param queue the queue disc
260 * @param size the size
261 * @param nPkt the number of packets
262 */
263 void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
264 /**
265 * Run Cobalt test function
266 * @param mode the mode
267 */
268 void RunDropTest(QueueSizeUnit mode);
269 /**
270 * Enqueue the given number of packets, each of the given size,
271 * at different times.
272 *
273 * @param queue the queue disc
274 * @param size the packet size in bytes
275 * @param nPkt the number of packets
276 */
278};
279
281 : TestCase("Drop tests verification for both packets and bytes mode")
282{
283}
284
285void
287
288{
289 uint32_t pktSize = 1500;
290 uint32_t modeSize = 0;
292
293 if (mode == QueueSizeUnit::BYTES)
294 {
295 modeSize = pktSize;
296 }
297 else if (mode == QueueSizeUnit::PACKETS)
298 {
299 modeSize = 1;
300 }
301
304 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(mode, modeSize * 100))),
305 true,
306 "Verify that we can actually set the attribute MaxSize");
307 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
308 true,
309 "Disable Blue enhancement");
310 queue->Initialize();
311
312 if (mode == QueueSizeUnit::BYTES)
313 {
314 EnqueueWithDelay(queue, pktSize, 200);
315 }
316 else
317 {
318 EnqueueWithDelay(queue, 1, 200);
319 }
320
323
324 QueueDisc::Stats st = queue->GetStats();
325
326 // The Pdrop value should increase, from it's default value of zero
327 NS_TEST_ASSERT_MSG_NE(queue->GetPdrop(), 0, "Pdrop should be non-zero");
329 0,
330 "Drops due to queue overflow should be non-zero");
331}
332
333void
335{
336 Address dest;
337 double delay = 0.01; // enqueue packets with delay
338 for (uint32_t i = 0; i < nPkt; i++)
339 {
340 Simulator::Schedule(Seconds((i + 1) * delay),
342 this,
343 queue,
344 size,
345 1);
346 }
347}
348
349void
351{
352 Address dest;
353 for (uint32_t i = 0; i < nPkt; i++)
354 {
355 queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, true));
356 }
357}
358
359void
361{
362 RunDropTest(QueueSizeUnit::PACKETS);
363 RunDropTest(QueueSizeUnit::BYTES);
365}
366
367/**
368 * @ingroup traffic-control-test
369 *
370 * @brief Test 3: Cobalt Queue Disc ECN marking Test Item
371 */
373{
374 public:
375 /**
376 * Constructor
377 *
378 * @param mode the mode
379 */
381 void DoRun() override;
382
383 private:
384 /**
385 * @brief Enqueue function
386 * @param queue the queue disc
387 * @param size the size
388 * @param nPkt the number of packets
389 * @param ecnCapable ECN capable traffic
390 */
391 void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, bool ecnCapable);
392 /**
393 * @brief Dequeue function
394 * @param queue the queue disc
395 * @param modeSize the mode size
396 * @param testCase the test case number
397 */
398 void Dequeue(Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t testCase);
399 /**
400 * @brief Drop next tracer function
401 * @param oldVal the old value of m_dropNext
402 * @param newVal the new value of m_dropNext
403 */
404 void DropNextTracer(int64_t oldVal, int64_t newVal);
406 uint32_t m_dropNextCount; ///< count the number of times m_dropNext is recalculated
407 uint32_t nPacketsBeforeFirstDrop; ///< Number of packets in the queue before first drop
408 uint32_t nPacketsBeforeFirstMark; ///< Number of packets in the queue before first mark
409};
410
412 : TestCase("Basic mark operations")
413{
414 m_mode = mode;
415 m_dropNextCount = 0;
416}
417
418void
419CobaltQueueDiscMarkTest::DropNextTracer(int64_t /* oldVal */, int64_t /* newVal */)
420{
422}
423
424void
426{
427 // Test is divided into 3 sub test cases:
428 // 1) Packets are not ECN capable.
429 // 2) Packets are ECN capable.
430 // 3) Some packets are ECN capable.
431
432 // Test case 1
434 uint32_t pktSize = 1000;
435 uint32_t modeSize = 0;
438
439 if (m_mode == QueueSizeUnit::BYTES)
440 {
441 modeSize = pktSize;
442 }
443 else if (m_mode == QueueSizeUnit::PACKETS)
444 {
445 modeSize = 1;
446 }
447
449 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
450 true,
451 "Verify that we can actually set the attribute MaxSize");
452 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(false)),
453 true,
454 "Verify that we can actually set the attribute UseEcn");
455 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
456 true,
457 "Disable Blue enhancement");
458 queue->Initialize();
459
460 // Not-ECT traffic to induce packet drop
461 Enqueue(queue, pktSize, 20, false);
462 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
463 20 * modeSize,
464 "There should be 20 packets in queue.");
465
466 // Although the first dequeue occurs with a sojourn time above target
467 // there should not be any dropped packets in this interval
468 Time waitUntilFirstDequeue = 2 * queue->GetTarget();
469 Simulator::Schedule(waitUntilFirstDequeue,
471 this,
472 queue,
473 modeSize,
474 1);
475
476 // This dequeue should cause a packet to be dropped
477 Time waitUntilSecondDequeue = waitUntilFirstDequeue + 2 * queue->GetInterval();
478 Simulator::Schedule(waitUntilSecondDequeue,
480 this,
481 queue,
482 modeSize,
483 1);
484
487
488 // Test case 2, queue with ECN capable traffic for marking of packets instead of dropping
491 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
492 true,
493 "Verify that we can actually set the attribute MaxSize");
494 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
495 true,
496 "Verify that we can actually set the attribute UseEcn");
497 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
498 true,
499 "Disable Blue enhancement");
500 queue->Initialize();
501
502 // ECN capable traffic
503 Enqueue(queue, pktSize, 20, true);
504 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
505 20 * modeSize,
506 "There should be 20 packets in queue.");
507
508 // Although the first dequeue occurs with a sojourn time above target
509 // there should not be any marked packets in this interval
510 Simulator::Schedule(waitUntilFirstDequeue,
512 this,
513 queue,
514 modeSize,
515 2);
516
517 // This dequeue should cause a packet to be marked
518 Simulator::Schedule(waitUntilSecondDequeue,
520 this,
521 queue,
522 modeSize,
523 2);
524
525 // This dequeue should cause a packet to be marked as dropnext is equal to current time
526 Simulator::Schedule(waitUntilSecondDequeue,
528 this,
529 queue,
530 modeSize,
531 2);
532
533 // In dropping phase and it's time for next packet to be marked
534 // the dequeue should cause additional packet to be marked
535 Simulator::Schedule(waitUntilSecondDequeue * 2,
537 this,
538 queue,
539 modeSize,
540 2);
541
544
545 // Test case 3, some packets are ECN capable
548 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
549 true,
550 "Verify that we can actually set the attribute MaxSize");
551 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
552 true,
553 "Verify that we can actually set the attribute UseEcn");
554 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
555 true,
556 "Disable Blue enhancement");
557 queue->Initialize();
558
559 // First 3 packets in the queue are ecnCapable
560 Enqueue(queue, pktSize, 3, true);
561 // Rest of the packet are not ecnCapable
562 Enqueue(queue, pktSize, 17, false);
563 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
564 20 * modeSize,
565 "There should be 20 packets in queue.");
566
567 // Although the first dequeue occurs with a sojourn time above target
568 // there should not be any marked packets in this interval
569 Simulator::Schedule(waitUntilFirstDequeue,
571 this,
572 queue,
573 modeSize,
574 3);
575
576 // This dequeue should cause a packet to be marked
577 Simulator::Schedule(waitUntilSecondDequeue,
579 this,
580 queue,
581 modeSize,
582 3);
583
584 // This dequeue should cause a packet to be marked as dropnext is equal to current time
585 Simulator::Schedule(waitUntilSecondDequeue,
587 this,
588 queue,
589 modeSize,
590 3);
591
592 // In dropping phase and it's time for next packet to be dropped as packets are not ECN capable
593 // the dequeue should cause packet to be dropped
594 Simulator::Schedule(waitUntilSecondDequeue * 2,
596 this,
597 queue,
598 modeSize,
599 3);
600
603}
604
605void
607 uint32_t size,
608 uint32_t nPkt,
609 bool ecnCapable)
610{
611 Address dest;
612 for (uint32_t i = 0; i < nPkt; i++)
613 {
614 queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, ecnCapable));
615 }
616}
617
618void
620{
621 uint32_t initialMarkCount = queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
622 uint32_t initialQSize = queue->GetCurrentSize().GetValue();
623 uint32_t initialDropNext = queue->GetDropNext();
624 Time currentTime = Simulator::Now();
625 uint32_t currentDropCount = 0;
626 uint32_t currentMarkCount = 0;
627
628 if (initialMarkCount > 0 && currentTime.GetNanoSeconds() > initialDropNext && testCase == 3)
629 {
630 queue->TraceConnectWithoutContext(
631 "DropNext",
633 }
634
635 if (initialQSize != 0)
636 {
637 Ptr<QueueDiscItem> item = queue->Dequeue();
638 if (testCase == 1)
639 {
640 currentDropCount =
641 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
642 if (currentDropCount != 0)
643 {
644 nPacketsBeforeFirstDrop = initialQSize;
645 }
646 }
647 if (testCase == 2)
648 {
649 if (initialMarkCount == 0 && currentTime > queue->GetTarget())
650 {
651 if (currentTime < queue->GetInterval())
652 {
653 currentDropCount =
654 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
655 currentMarkCount =
656 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
657 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
658 initialQSize - modeSize,
659 "There should be 1 packet dequeued.");
660 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
661 0,
662 "There should not be any packet drops");
663 NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
664 0,
665 "We are not in dropping state."
666 "Sojourn time has just gone above target from below."
667 "Hence, there should be no marked packets");
668 }
669 else if (currentTime >= queue->GetInterval())
670 {
671 nPacketsBeforeFirstMark = initialQSize;
672 currentDropCount =
673 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
674 currentMarkCount =
675 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
677 queue->GetCurrentSize().GetValue(),
678 initialQSize - modeSize,
679 "Sojourn time has been above target for at least interval."
680 "We enter the dropping state and perform initial packet marking"
681 "So there should be only 1 more packet dequeued.");
682 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
683 0,
684 "There should not be any packet drops");
685 NS_TEST_EXPECT_MSG_EQ(currentMarkCount, 1, "There should be 1 marked packet");
686 }
687 }
688 else if (initialMarkCount > 0)
689 {
690 if (currentTime.GetNanoSeconds() <= initialDropNext)
691 {
692 currentDropCount =
693 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
694 currentMarkCount =
695 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
696 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
697 initialQSize - modeSize,
698 "We are in dropping state."
699 "Sojourn is still above target."
700 "There should be only 1 more packet dequeued");
701 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
702 0,
703 "There should not be any packet drops");
704 NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
705 2,
706 "There should be 2 marked packet as."
707 "current dropnext is equal to current time.");
708 }
709 else if (currentTime.GetNanoSeconds() > initialDropNext)
710 {
711 currentDropCount =
712 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
713 currentMarkCount =
714 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
715 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
716 initialQSize - modeSize,
717 "We are in dropping state."
718 "It's time for packet to be marked"
719 "So there should be only 1 more packet dequeued");
720 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
721 0,
722 "There should not be any packet drops");
723 NS_TEST_EXPECT_MSG_EQ(currentMarkCount, 3, "There should be 3 marked packet");
727 "Number of packets in the queue before drop should be equal"
728 "to number of packets in the queue before first mark as the behavior until "
729 "packet N should be the same.");
730 }
731 }
732 }
733 else if (testCase == 3)
734 {
735 if (initialMarkCount == 0 && currentTime > queue->GetTarget())
736 {
737 if (currentTime < queue->GetInterval())
738 {
739 currentDropCount =
740 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
741 currentMarkCount =
742 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
743 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
744 initialQSize - modeSize,
745 "There should be 1 packet dequeued.");
746 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
747 0,
748 "There should not be any packet drops");
749 NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
750 0,
751 "We are not in dropping state."
752 "Sojourn time has just gone above target from below."
753 "Hence, there should be no marked packets");
754 }
755 else if (currentTime >= queue->GetInterval())
756 {
757 currentDropCount =
758 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
759 currentMarkCount =
760 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
762 queue->GetCurrentSize().GetValue(),
763 initialQSize - modeSize,
764 "Sojourn time has been above target for at least interval."
765 "We enter the dropping state and perform initial packet marking"
766 "So there should be only 1 more 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, 1, "There should be 1 marked packet");
771 }
772 }
773 else if (initialMarkCount > 0)
774 {
775 if (currentTime.GetNanoSeconds() <= initialDropNext)
776 {
777 currentDropCount =
778 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
779 currentMarkCount =
780 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
781 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
782 initialQSize - modeSize,
783 "We are in dropping state."
784 "Sojourn is still above target."
785 "So there should be only 1 more packet dequeued");
786 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
787 0,
788 "There should not be any packet drops");
789 NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
790 2,
791 "There should be 2 marked packet"
792 "as dropnext is equal to current time");
793 }
794 else if (currentTime.GetNanoSeconds() > initialDropNext)
795 {
796 currentDropCount =
797 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
798 currentMarkCount =
799 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
801 queue->GetCurrentSize().GetValue(),
802 initialQSize - (m_dropNextCount + 1) * modeSize,
803 "We are in dropping state."
804 "It's time for packet to be dropped as packets are not ecnCapable"
805 "The number of packets dequeued equals to the number of times m_dropNext "
806 "is updated plus initial dequeue");
808 currentDropCount,
810 "The number of drops equals to the number of times m_dropNext is updated");
811 NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
812 2,
813 "There should still be only 2 marked packet");
814 }
815 }
816 }
817 }
818}
819
820/**
821 * @ingroup traffic-control-test
822 *
823 * @brief Test 4: Cobalt Queue Disc CE Threshold marking Test Item
824 */
826{
827 public:
828 /**
829 * Constructor
830 *
831 * @param mode the queue size unit mode
832 */
835
836 private:
837 void DoRun() override;
838 /**
839 * @brief Enqueue function
840 * @param queue the queue disc
841 * @param size the size
842 * @param nPkt the number of packets
843 */
844 void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
845 /**
846 * @brief Enqueue with delay function
847 * @param queue the queue disc
848 * @param size the size
849 * @param nPkt the number of packets
850 * @param delay the delay between the enqueueing of the packets
851 */
852 void EnqueueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, Time delay);
853 /**
854 * @brief Dequeue function
855 * @param queue the queue disc
856 * @param modeSize the mode size
857 */
858 void Dequeue(Ptr<CobaltQueueDisc> queue, uint32_t modeSize);
859 /**
860 * @brief Dequeue with delay function
861 * @param queue the queue disc
862 * @param modeSize the mode size
863 * @param nPkt the number of packets
864 * @param delay the delay between the enqueueing of the packets
865 */
866 void DequeueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t nPkt, Time delay);
868};
869
871 : TestCase("Test CE Threshold marking")
872{
873 m_mode = mode;
874}
875
879
880void
882{
883 Address dest;
884 for (uint32_t i = 0; i < nPkt; i++)
885 {
886 queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, true));
887 }
888}
889
890void
892 uint32_t size,
893 uint32_t nPkt,
894 Time delay)
895{
896 for (uint32_t i = 0; i < nPkt; i++)
897 {
898 Simulator::Schedule(Seconds((i + 1) * delay.GetSeconds()),
900 this,
901 queue,
902 size,
903 1);
904 }
905}
906
907void
909{
910 Ptr<QueueDiscItem> item = queue->Dequeue();
911
913 {
915 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
916 1,
917 "There should be only 1 packet"
918 "mark, the delay between the enqueueing of the packets decreased after the"
919 "1st mark (packet enqueued at 11ms) and increased for the packet enqueued after 20.6ms."
920 "Queue delay remains below or equal to 1ms for the packet enqueued before 28ms");
921 }
922 if (Simulator::Now() > MilliSeconds(31))
923 {
925 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
926 3,
927 "There should be 3 packet"
928 "marks, the delay between the enqueueing of the packets decreased after 1st mark"
929 "(packet enqueued at 11ms) and increased for the packet enqueued after 20.6ms."
930 "Queue delay remains below 1ms for the packets enqueued before 28ms and increases"
931 "for the packets enqueued after 28ms.");
932 }
933}
934
935void
937 uint32_t modeSize,
938 uint32_t nPkt,
939 Time delay)
940{
941 for (uint32_t i = 0; i < nPkt; i++)
942 {
943 Simulator::Schedule(Seconds((i + 1) * delay.GetSeconds()),
945 this,
946 queue,
947 modeSize);
948 }
949}
950
951void
953{
955 uint32_t pktSize = 1000;
956 uint32_t modeSize = 0;
957
958 if (m_mode == QueueSizeUnit::BYTES)
959 {
960 modeSize = pktSize;
961 }
962 else if (m_mode == QueueSizeUnit::PACKETS)
963 {
964 modeSize = 1;
965 }
966
967 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
968 true,
969 "Verify that we can actually set the attribute UseEcn");
970 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("CeThreshold", TimeValue(MilliSeconds(1))),
971 true,
972 "Verify that we can actually set the attribute UseEcn");
973 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
974 true,
975 "Disable Blue enhancement");
976 queue->Initialize();
977
978 // Enqueue 11 packets every 1ms
979 EnqueueWithDelay(queue, pktSize, 11, MilliSeconds(1));
980
981 // With every dequeue, queue delay increases by 0.1ms as packet enqueues every 1ms while
982 // dequeues at 1.1ms so at 11th dequeue, the dequeued packet should be marked.
983 Time dequeueInterval = MicroSeconds(1100);
984 DequeueWithDelay(queue, modeSize, 11, dequeueInterval);
985
986 // First mark occurred for the packet enqueued at 11ms, ideally TCP would decrease sending rate
987 // which can be simulated by increasing interval between subsequent enqueues, so packets are now
988 // enqueued with a delay 1.2ms.
989 Time waitUntilFirstMark = MilliSeconds(11);
990 Simulator::Schedule(waitUntilFirstMark,
992 this,
993 queue,
994 pktSize,
995 9,
996 MicroSeconds(1200));
997
998 // Keep dequeueing with the same delay
999 Simulator::Schedule(waitUntilFirstMark,
1001 this,
1002 queue,
1003 modeSize,
1004 9,
1005 dequeueInterval);
1006
1007 // Queue delay becomes 0.2ms for the packet enqueued at 20.6ms, time to decrease interval
1008 // between subsequent enqueues, as ideally TCP would again start increasing sending rate
1009 Time waitUntilDecreasingEnqueueDelay = waitUntilFirstMark + MilliSeconds(9);
1010 Simulator::Schedule(waitUntilDecreasingEnqueueDelay,
1012 this,
1013 queue,
1014 pktSize,
1015 10,
1016 MilliSeconds(1));
1017
1018 // Keep dequeueing with the same delay
1019 Simulator::Schedule(waitUntilFirstMark,
1021 this,
1022 queue,
1023 modeSize,
1024 10,
1025 dequeueInterval);
1026
1029}
1030
1031/**
1032 * @ingroup traffic-control-test
1033 *
1034 * @brief Test 5: Cobalt Queue Disc Enhanced Blue Test Item
1035 * This test checks that the Blue Enhancement is working correctly. This test checks that Pdrop
1036 * should increase as expected with a certain number of dropped packets which is fixed by assigning
1037 * a stream to the uniform random variable. This test case is divided into 2 sub test cases 1) With
1038 * Blue Enhancement enabled, the test checks that Pdrop should increase as expected with a certain
1039 * number of dropped packets which is fixed by assigning a stream to the uniform random variable. 2)
1040 * Without Blue Enhancement, Pdrop should remain zero and there should not be any dropped packets as
1041 * ECN is enabled.
1042 */
1044{
1045 public:
1046 /**
1047 * Constructor
1048 *
1049 * @param mode the queue size unit mode
1050 */
1053
1054 private:
1055 void DoRun() override;
1056 /**
1057 * Enqueue function
1058 * @param queue the queue disc
1059 * @param size the size
1060 * @param nPkt the number of packets
1061 */
1062 void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
1063 /**
1064 * @brief Dequeue function
1065 * @param queue the queue disc
1066 */
1067 void Dequeue(Ptr<CobaltQueueDisc> queue);
1068 /**
1069 * @brief Dequeue with delay function
1070 * @param queue the queue disc
1071 * @param nPkt the number of packets
1072 * @param delay the delay between the enqueueing of the packets
1073 */
1074 void DequeueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t nPkt, Time delay);
1076};
1077
1079 : TestCase("Enhanced Blue tests verification for both packets and bytes mode")
1080{
1081 m_mode = mode;
1082}
1083
1087
1088void
1090
1091{
1092 uint32_t pktSize = 1500;
1093 uint32_t modeSize = 0;
1095
1096 if (m_mode == QueueSizeUnit::BYTES)
1097 {
1098 modeSize = pktSize;
1099 }
1100 else if (m_mode == QueueSizeUnit::PACKETS)
1101 {
1102 modeSize = 1;
1103 }
1104 queue->Initialize();
1105 queue->AssignStreams(1);
1106 Enqueue(queue, modeSize, 200);
1107 DequeueWithDelay(queue, 100, MilliSeconds(10));
1108
1111
1112 QueueDisc::Stats st = queue->GetStats();
1113
1114 // The Pdrop value should increase, from it's default value of zero
1116 queue->GetPdrop(),
1117 0.234375,
1118 "Pdrop should be increased by 1/256 for every packet whose sojourn time is above 400ms."
1119 " From the 41st dequeue until the last one, sojourn time is above 400ms, so 60 packets "
1120 "have sojourn time above 400ms"
1121 "hence Pdrop should be increased 60*(1/256) which is 0.234375");
1123 49,
1124 "There should a fixed number of drops (49 here)");
1126
1128 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
1129 true,
1130 "Verify that we can actually set the attribute UseEcn");
1131 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
1132 true,
1133 "Disable Blue enhancement");
1134 queue->Initialize();
1135 Enqueue(queue, modeSize, 200);
1136 DequeueWithDelay(queue, 100, MilliSeconds(10));
1137
1140
1141 st = queue->GetStats();
1142
1143 NS_TEST_ASSERT_MSG_EQ(queue->GetPdrop(), 0, "Pdrop should be zero");
1145 0,
1146 "There should not any dropped packets");
1148}
1149
1150void
1152{
1153 Address dest;
1154 for (uint32_t i = 0; i < nPkt; i++)
1155 {
1156 queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, true));
1157 }
1158}
1159
1160void
1165
1166void
1168 uint32_t nPkt,
1169 Time delay)
1170{
1171 for (uint32_t i = 0; i < nPkt; i++)
1172 {
1173 Simulator::Schedule(Seconds((i + 1) * delay.GetSeconds()),
1175 this,
1176 queue);
1177 }
1178}
1179
1180/**
1181 * @ingroup traffic-control-test
1182 * The COBALT queue disc test suite.
1183 */
1185{
1186 public:
1188 : TestSuite("cobalt-queue-disc", Type::UNIT)
1189 {
1190 // Test 1: simple enqueue/dequeue with no drops
1191 AddTestCase(new CobaltQueueDiscBasicEnqueueDequeue(PACKETS), TestCase::Duration::QUICK);
1192 AddTestCase(new CobaltQueueDiscBasicEnqueueDequeue(BYTES), TestCase::Duration::QUICK);
1193 // Test 2: Drop test
1194 AddTestCase(new CobaltQueueDiscDropTest(), TestCase::Duration::QUICK);
1195 // Test 3: Mark test
1196 AddTestCase(new CobaltQueueDiscMarkTest(PACKETS), TestCase::Duration::QUICK);
1197 AddTestCase(new CobaltQueueDiscMarkTest(BYTES), TestCase::Duration::QUICK);
1198 // Test 4: CE threshold marking test
1199 AddTestCase(new CobaltQueueDiscCeThresholdTest(PACKETS), TestCase::Duration::QUICK);
1200 AddTestCase(new CobaltQueueDiscCeThresholdTest(BYTES), TestCase::Duration::QUICK);
1201 // Test 4: Blue enhancement test
1202 AddTestCase(new CobaltQueueDiscEnhancedBlueTest(PACKETS), TestCase::Duration::QUICK);
1203 AddTestCase(new CobaltQueueDiscEnhancedBlueTest(BYTES), TestCase::Duration::QUICK);
1204 }
1205} g_cobaltQueueTestSuite; ///< the test suite
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:90
AttributeValue implementation for Boolean.
Definition boolean.h:26
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.
QueueDiscItem is the abstract base class for items that are stored in a queue disc.
Definition queue-item.h:122
Class for representing queue sizes.
Definition queue-size.h:85
AttributeValue implementation for QueueSize.
Definition queue-size.h:210
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static void Run()
Run the simulation.
Definition simulator.cc:167
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
Hold variables of type string.
Definition string.h:45
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
static constexpr auto UNIT
Definition test.h:1291
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:407
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:392
static Time Max()
Maximum representable Time Not to be confused with Max(Time,Time).
Definition nstime.h:286
AttributeValue implementation for Time.
Definition nstime.h:1431
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
QueueSizeUnit
Enumeration of the operating modes of queues.
Definition queue-size.h:33
@ BYTES
Use number of bytes for queue size.
Definition queue-size.h:35
@ PACKETS
Use number of packets for queue size.
Definition queue-size.h:34
#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:134
#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:241
#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:554
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1368
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1356
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:684
STL namespace.
Structure that keeps the queue disc statistics.
Definition queue-disc.h:177
uint32_t GetNDroppedPackets(std::string reason) const
Get the number of packets dropped for the given reason.
uint32_t pktSize
packet size used for the simulation (in bytes)