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
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;
151 p1 = Create<Packet>(pktSize);
152 p2 = Create<Packet>(pktSize);
153 p3 = Create<Packet>(pktSize);
154 p4 = Create<Packet>(pktSize);
155 p5 = Create<Packet>(pktSize);
156 p6 = Create<Packet>(pktSize);
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 double delay = 0.01; // enqueue packets with delay
337 for (uint32_t i = 0; i < nPkt; i++)
338 {
339 Simulator::Schedule(Seconds((i + 1) * delay),
341 this,
342 queue,
343 size,
344 1);
345 }
346}
347
348void
350{
351 Address dest;
352 for (uint32_t i = 0; i < nPkt; i++)
353 {
354 queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, true));
355 }
356}
357
358void
365
366/**
367 * @ingroup traffic-control-test
368 *
369 * @brief Test 3: Cobalt Queue Disc ECN marking Test Item
370 */
372{
373 public:
374 /**
375 * Constructor
376 *
377 * @param mode the mode
378 */
380 void DoRun() override;
381
382 private:
383 /**
384 * @brief Enqueue function
385 * @param queue the queue disc
386 * @param size the size
387 * @param nPkt the number of packets
388 * @param ecnCapable ECN capable traffic
389 */
390 void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, bool ecnCapable);
391 /**
392 * @brief Dequeue function
393 * @param queue the queue disc
394 * @param modeSize the mode size
395 * @param testCase the test case number
396 */
397 void Dequeue(Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t testCase);
398 /**
399 * @brief Drop next tracer function
400 * @param oldVal the old value of m_dropNext
401 * @param newVal the new value of m_dropNext
402 */
403 void DropNextTracer(int64_t oldVal, int64_t newVal);
405 uint32_t m_dropNextCount; ///< count the number of times m_dropNext is recalculated
406 uint32_t nPacketsBeforeFirstDrop; ///< Number of packets in the queue before first drop
407 uint32_t nPacketsBeforeFirstMark; ///< Number of packets in the queue before first mark
408};
409
411 : TestCase("Basic mark operations")
412{
413 m_mode = mode;
414 m_dropNextCount = 0;
415}
416
417void
418CobaltQueueDiscMarkTest::DropNextTracer(int64_t /* oldVal */, int64_t /* newVal */)
419{
421}
422
423void
425{
426 // Test is divided into 3 sub test cases:
427 // 1) Packets are not ECN capable.
428 // 2) Packets are ECN capable.
429 // 3) Some packets are ECN capable.
430
431 // Test case 1
433 uint32_t pktSize = 1000;
434 uint32_t modeSize = 0;
437
439 {
440 modeSize = pktSize;
441 }
442 else if (m_mode == QueueSizeUnit::PACKETS)
443 {
444 modeSize = 1;
445 }
446
448 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
449 true,
450 "Verify that we can actually set the attribute MaxSize");
451 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(false)),
452 true,
453 "Verify that we can actually set the attribute UseEcn");
454 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
455 true,
456 "Disable Blue enhancement");
457 queue->Initialize();
458
459 // Not-ECT traffic to induce packet drop
460 Enqueue(queue, pktSize, 20, false);
461 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
462 20 * modeSize,
463 "There should be 20 packets in queue.");
464
465 // Although the first dequeue occurs with a sojourn time above target
466 // there should not be any dropped packets in this interval
467 Time waitUntilFirstDequeue = 2 * queue->GetTarget();
468 Simulator::Schedule(waitUntilFirstDequeue,
470 this,
471 queue,
472 modeSize,
473 1);
474
475 // This dequeue should cause a packet to be dropped
476 Time waitUntilSecondDequeue = waitUntilFirstDequeue + 2 * queue->GetInterval();
477 Simulator::Schedule(waitUntilSecondDequeue,
479 this,
480 queue,
481 modeSize,
482 1);
483
486
487 // Test case 2, queue with ECN capable traffic for marking of packets instead of dropping
490 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
491 true,
492 "Verify that we can actually set the attribute MaxSize");
493 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
494 true,
495 "Verify that we can actually set the attribute UseEcn");
496 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
497 true,
498 "Disable Blue enhancement");
499 queue->Initialize();
500
501 // ECN capable traffic
502 Enqueue(queue, pktSize, 20, true);
503 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
504 20 * modeSize,
505 "There should be 20 packets in queue.");
506
507 // Although the first dequeue occurs with a sojourn time above target
508 // there should not be any marked packets in this interval
509 Simulator::Schedule(waitUntilFirstDequeue,
511 this,
512 queue,
513 modeSize,
514 2);
515
516 // This dequeue should cause a packet to be marked
517 Simulator::Schedule(waitUntilSecondDequeue,
519 this,
520 queue,
521 modeSize,
522 2);
523
524 // This dequeue should cause a packet to be marked as dropnext is equal to current time
525 Simulator::Schedule(waitUntilSecondDequeue,
527 this,
528 queue,
529 modeSize,
530 2);
531
532 // In dropping phase and it's time for next packet to be marked
533 // the dequeue should cause additional packet to be marked
534 Simulator::Schedule(waitUntilSecondDequeue * 2,
536 this,
537 queue,
538 modeSize,
539 2);
540
543
544 // Test case 3, some packets are ECN capable
547 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
548 true,
549 "Verify that we can actually set the attribute MaxSize");
550 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
551 true,
552 "Verify that we can actually set the attribute UseEcn");
553 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
554 true,
555 "Disable Blue enhancement");
556 queue->Initialize();
557
558 // First 3 packets in the queue are ecnCapable
559 Enqueue(queue, pktSize, 3, true);
560 // Rest of the packet are not ecnCapable
561 Enqueue(queue, pktSize, 17, false);
562 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
563 20 * modeSize,
564 "There should be 20 packets in queue.");
565
566 // Although the first dequeue occurs with a sojourn time above target
567 // there should not be any marked packets in this interval
568 Simulator::Schedule(waitUntilFirstDequeue,
570 this,
571 queue,
572 modeSize,
573 3);
574
575 // This dequeue should cause a packet to be marked
576 Simulator::Schedule(waitUntilSecondDequeue,
578 this,
579 queue,
580 modeSize,
581 3);
582
583 // This dequeue should cause a packet to be marked as dropnext is equal to current time
584 Simulator::Schedule(waitUntilSecondDequeue,
586 this,
587 queue,
588 modeSize,
589 3);
590
591 // In dropping phase and it's time for next packet to be dropped as packets are not ECN capable
592 // the dequeue should cause packet to be dropped
593 Simulator::Schedule(waitUntilSecondDequeue * 2,
595 this,
596 queue,
597 modeSize,
598 3);
599
602}
603
604void
606 uint32_t size,
607 uint32_t nPkt,
608 bool ecnCapable)
609{
610 Address dest;
611 for (uint32_t i = 0; i < nPkt; i++)
612 {
613 queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, ecnCapable));
614 }
615}
616
617void
619{
620 uint32_t initialMarkCount = queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
621 uint32_t initialQSize = queue->GetCurrentSize().GetValue();
622 uint32_t initialDropNext = queue->GetDropNext();
623 Time currentTime = Simulator::Now();
624 uint32_t currentDropCount = 0;
625 uint32_t currentMarkCount = 0;
626
627 if (initialMarkCount > 0 && currentTime.GetNanoSeconds() > initialDropNext && testCase == 3)
628 {
629 queue->TraceConnectWithoutContext(
630 "DropNext",
632 }
633
634 if (initialQSize != 0)
635 {
636 Ptr<QueueDiscItem> item = queue->Dequeue();
637 if (testCase == 1)
638 {
639 currentDropCount =
640 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
641 if (currentDropCount != 0)
642 {
643 nPacketsBeforeFirstDrop = initialQSize;
644 }
645 }
646 if (testCase == 2)
647 {
648 if (initialMarkCount == 0 && currentTime > queue->GetTarget())
649 {
650 if (currentTime < queue->GetInterval())
651 {
652 currentDropCount =
653 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
654 currentMarkCount =
655 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
656 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
657 initialQSize - modeSize,
658 "There should be 1 packet dequeued.");
659 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
660 0,
661 "There should not be any packet drops");
662 NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
663 0,
664 "We are not in dropping state."
665 "Sojourn time has just gone above target from below."
666 "Hence, there should be no marked packets");
667 }
668 else if (currentTime >= queue->GetInterval())
669 {
670 nPacketsBeforeFirstMark = initialQSize;
671 currentDropCount =
672 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
673 currentMarkCount =
674 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
676 queue->GetCurrentSize().GetValue(),
677 initialQSize - modeSize,
678 "Sojourn time has been above target for at least interval."
679 "We enter the dropping state and perform initial packet marking"
680 "So there should be only 1 more 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, 1, "There should be 1 marked packet");
685 }
686 }
687 else if (initialMarkCount > 0)
688 {
689 if (currentTime.GetNanoSeconds() <= initialDropNext)
690 {
691 currentDropCount =
692 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
693 currentMarkCount =
694 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
695 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
696 initialQSize - modeSize,
697 "We are in dropping state."
698 "Sojourn is still above target."
699 "There should be only 1 more packet dequeued");
700 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
701 0,
702 "There should not be any packet drops");
703 NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
704 2,
705 "There should be 2 marked packet as."
706 "current dropnext is equal to current time.");
707 }
708 else if (currentTime.GetNanoSeconds() > initialDropNext)
709 {
710 currentDropCount =
711 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
712 currentMarkCount =
713 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
714 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
715 initialQSize - modeSize,
716 "We are in dropping state."
717 "It's time for packet to be marked"
718 "So there should be only 1 more packet dequeued");
719 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
720 0,
721 "There should not be any packet drops");
722 NS_TEST_EXPECT_MSG_EQ(currentMarkCount, 3, "There should be 3 marked packet");
726 "Number of packets in the queue before drop should be equal"
727 "to number of packets in the queue before first mark as the behavior until "
728 "packet N should be the same.");
729 }
730 }
731 }
732 else if (testCase == 3)
733 {
734 if (initialMarkCount == 0 && currentTime > queue->GetTarget())
735 {
736 if (currentTime < queue->GetInterval())
737 {
738 currentDropCount =
739 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
740 currentMarkCount =
741 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
742 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
743 initialQSize - modeSize,
744 "There should be 1 packet dequeued.");
745 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
746 0,
747 "There should not be any packet drops");
748 NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
749 0,
750 "We are not in dropping state."
751 "Sojourn time has just gone above target from below."
752 "Hence, there should be no marked packets");
753 }
754 else if (currentTime >= queue->GetInterval())
755 {
756 currentDropCount =
757 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
758 currentMarkCount =
759 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
761 queue->GetCurrentSize().GetValue(),
762 initialQSize - modeSize,
763 "Sojourn time has been above target for at least interval."
764 "We enter the dropping state and perform initial packet marking"
765 "So there should be only 1 more packet dequeued.");
766 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
767 0,
768 "There should not be any packet drops");
769 NS_TEST_EXPECT_MSG_EQ(currentMarkCount, 1, "There should be 1 marked packet");
770 }
771 }
772 else if (initialMarkCount > 0)
773 {
774 if (currentTime.GetNanoSeconds() <= initialDropNext)
775 {
776 currentDropCount =
777 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
778 currentMarkCount =
779 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
780 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
781 initialQSize - modeSize,
782 "We are in dropping state."
783 "Sojourn is still above target."
784 "So there should be only 1 more packet dequeued");
785 NS_TEST_EXPECT_MSG_EQ(currentDropCount,
786 0,
787 "There should not be any packet drops");
788 NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
789 2,
790 "There should be 2 marked packet"
791 "as dropnext is equal to current time");
792 }
793 else if (currentTime.GetNanoSeconds() > initialDropNext)
794 {
795 currentDropCount =
796 queue->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP);
797 currentMarkCount =
798 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK);
800 queue->GetCurrentSize().GetValue(),
801 initialQSize - (m_dropNextCount + 1) * modeSize,
802 "We are in dropping state."
803 "It's time for packet to be dropped as packets are not ecnCapable"
804 "The number of packets dequeued equals to the number of times m_dropNext "
805 "is updated plus initial dequeue");
807 currentDropCount,
809 "The number of drops equals to the number of times m_dropNext is updated");
810 NS_TEST_EXPECT_MSG_EQ(currentMarkCount,
811 2,
812 "There should still be only 2 marked packet");
813 }
814 }
815 }
816 }
817}
818
819/**
820 * @ingroup traffic-control-test
821 *
822 * @brief Test 4: Cobalt Queue Disc CE Threshold marking Test Item
823 */
825{
826 public:
827 /**
828 * Constructor
829 *
830 * @param mode the queue size unit mode
831 */
834
835 private:
836 void DoRun() override;
837 /**
838 * @brief Enqueue function
839 * @param queue the queue disc
840 * @param size the size
841 * @param nPkt the number of packets
842 */
843 void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
844 /**
845 * @brief Enqueue with delay function
846 * @param queue the queue disc
847 * @param size the size
848 * @param nPkt the number of packets
849 * @param delay the delay between the enqueueing of the packets
850 */
851 void EnqueueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, Time delay);
852 /**
853 * @brief Dequeue function
854 * @param queue the queue disc
855 * @param modeSize the mode size
856 */
857 void Dequeue(Ptr<CobaltQueueDisc> queue, uint32_t modeSize);
858 /**
859 * @brief Dequeue with delay function
860 * @param queue the queue disc
861 * @param modeSize the mode size
862 * @param nPkt the number of packets
863 * @param delay the delay between the enqueueing of the packets
864 */
865 void DequeueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t nPkt, Time delay);
867};
868
870 : TestCase("Test CE Threshold marking")
871{
872 m_mode = mode;
873}
874
878
879void
881{
882 Address dest;
883 for (uint32_t i = 0; i < nPkt; i++)
884 {
885 queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, true));
886 }
887}
888
889void
891 uint32_t size,
892 uint32_t nPkt,
893 Time delay)
894{
895 for (uint32_t i = 0; i < nPkt; i++)
896 {
897 Simulator::Schedule(Seconds((i + 1) * delay.GetSeconds()),
899 this,
900 queue,
901 size,
902 1);
903 }
904}
905
906void
908{
909 Ptr<QueueDiscItem> item = queue->Dequeue();
910
912 {
914 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
915 1,
916 "There should be only 1 packet"
917 "mark, the delay between the enqueueing of the packets decreased after the"
918 "1st mark (packet enqueued at 11ms) and increased for the packet enqueued after 20.6ms."
919 "Queue delay remains below or equal to 1ms for the packet enqueued before 28ms");
920 }
921 if (Simulator::Now() > MilliSeconds(31))
922 {
924 queue->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
925 3,
926 "There should be 3 packet"
927 "marks, the delay between the enqueueing of the packets decreased after 1st mark"
928 "(packet enqueued at 11ms) and increased for the packet enqueued after 20.6ms."
929 "Queue delay remains below 1ms for the packets enqueued before 28ms and increases"
930 "for the packets enqueued after 28ms.");
931 }
932}
933
934void
936 uint32_t modeSize,
937 uint32_t nPkt,
938 Time delay)
939{
940 for (uint32_t i = 0; i < nPkt; i++)
941 {
942 Simulator::Schedule(Seconds((i + 1) * delay.GetSeconds()),
944 this,
945 queue,
946 modeSize);
947 }
948}
949
950void
952{
954 uint32_t pktSize = 1000;
955 uint32_t modeSize = 0;
956
958 {
959 modeSize = pktSize;
960 }
961 else if (m_mode == QueueSizeUnit::PACKETS)
962 {
963 modeSize = 1;
964 }
965
966 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
967 true,
968 "Verify that we can actually set the attribute UseEcn");
969 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("CeThreshold", TimeValue(MilliSeconds(1))),
970 true,
971 "Verify that we can actually set the attribute UseEcn");
972 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
973 true,
974 "Disable Blue enhancement");
975 queue->Initialize();
976
977 // Enqueue 11 packets every 1ms
978 EnqueueWithDelay(queue, pktSize, 11, MilliSeconds(1));
979
980 // With every dequeue, queue delay increases by 0.1ms as packet enqueues every 1ms while
981 // dequeues at 1.1ms so at 11th dequeue, the dequeued packet should be marked.
982 Time dequeueInterval = MicroSeconds(1100);
983 DequeueWithDelay(queue, modeSize, 11, dequeueInterval);
984
985 // First mark occurred for the packet enqueued at 11ms, ideally TCP would decrease sending rate
986 // which can be simulated by increasing interval between subsequent enqueues, so packets are now
987 // enqueued with a delay 1.2ms.
988 Time waitUntilFirstMark = MilliSeconds(11);
989 Simulator::Schedule(waitUntilFirstMark,
991 this,
992 queue,
993 pktSize,
994 9,
995 MicroSeconds(1200));
996
997 // Keep dequeueing with the same delay
998 Simulator::Schedule(waitUntilFirstMark,
1000 this,
1001 queue,
1002 modeSize,
1003 9,
1004 dequeueInterval);
1005
1006 // Queue delay becomes 0.2ms for the packet enqueued at 20.6ms, time to decrease interval
1007 // between subsequent enqueues, as ideally TCP would again start increasing sending rate
1008 Time waitUntilDecreasingEnqueueDelay = waitUntilFirstMark + MilliSeconds(9);
1009 Simulator::Schedule(waitUntilDecreasingEnqueueDelay,
1011 this,
1012 queue,
1013 pktSize,
1014 10,
1015 MilliSeconds(1));
1016
1017 // Keep dequeueing with the same delay
1018 Simulator::Schedule(waitUntilFirstMark,
1020 this,
1021 queue,
1022 modeSize,
1023 10,
1024 dequeueInterval);
1025
1028}
1029
1030/**
1031 * @ingroup traffic-control-test
1032 *
1033 * @brief Test 5: Cobalt Queue Disc Enhanced Blue Test Item
1034 * This test checks that the Blue Enhancement is working correctly. This test checks that Pdrop
1035 * should increase as expected with a certain number of dropped packets which is fixed by assigning
1036 * a stream to the uniform random variable. This test case is divided into 2 sub test cases 1) With
1037 * Blue Enhancement enabled, the test checks that Pdrop should increase as expected with a certain
1038 * number of dropped packets which is fixed by assigning a stream to the uniform random variable. 2)
1039 * Without Blue Enhancement, Pdrop should remain zero and there should not be any dropped packets as
1040 * ECN is enabled.
1041 */
1043{
1044 public:
1045 /**
1046 * Constructor
1047 *
1048 * @param mode the queue size unit mode
1049 */
1052
1053 private:
1054 void DoRun() override;
1055 /**
1056 * Enqueue function
1057 * @param queue the queue disc
1058 * @param size the size
1059 * @param nPkt the number of packets
1060 */
1061 void Enqueue(Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
1062 /**
1063 * @brief Dequeue function
1064 * @param queue the queue disc
1065 */
1066 void Dequeue(Ptr<CobaltQueueDisc> queue);
1067 /**
1068 * @brief Dequeue with delay function
1069 * @param queue the queue disc
1070 * @param nPkt the number of packets
1071 * @param delay the delay between the enqueueing of the packets
1072 */
1073 void DequeueWithDelay(Ptr<CobaltQueueDisc> queue, uint32_t nPkt, Time delay);
1075};
1076
1078 : TestCase("Enhanced Blue tests verification for both packets and bytes mode")
1079{
1080 m_mode = mode;
1081}
1082
1086
1087void
1089
1090{
1091 uint32_t pktSize = 1500;
1092 uint32_t modeSize = 0;
1094
1096 {
1097 modeSize = pktSize;
1098 }
1099 else if (m_mode == QueueSizeUnit::PACKETS)
1100 {
1101 modeSize = 1;
1102 }
1103 queue->Initialize();
1104 queue->AssignStreams(1);
1105 Enqueue(queue, modeSize, 200);
1106 DequeueWithDelay(queue, 100, MilliSeconds(10));
1107
1110
1111 QueueDisc::Stats st = queue->GetStats();
1112
1113 // The Pdrop value should increase, from it's default value of zero
1115 queue->GetPdrop(),
1116 0.234375,
1117 "Pdrop should be increased by 1/256 for every packet whose sojourn time is above 400ms."
1118 " From the 41st dequeue until the last one, sojourn time is above 400ms, so 60 packets "
1119 "have sojourn time above 400ms"
1120 "hence Pdrop should be increased 60*(1/256) which is 0.234375");
1122 49,
1123 "There should a fixed number of drops (49 here)");
1125
1127 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
1128 true,
1129 "Verify that we can actually set the attribute UseEcn");
1130 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("BlueThreshold", TimeValue(Time::Max())),
1131 true,
1132 "Disable Blue enhancement");
1133 queue->Initialize();
1134 Enqueue(queue, modeSize, 200);
1135 DequeueWithDelay(queue, 100, MilliSeconds(10));
1136
1139
1140 st = queue->GetStats();
1141
1142 NS_TEST_ASSERT_MSG_EQ(queue->GetPdrop(), 0, "Pdrop should be zero");
1144 0,
1145 "There should not any dropped packets");
1147}
1148
1149void
1151{
1152 Address dest;
1153 for (uint32_t i = 0; i < nPkt; i++)
1154 {
1155 queue->Enqueue(Create<CobaltQueueDiscTestItem>(Create<Packet>(size), dest, true));
1156 }
1157}
1158
1159void
1164
1165void
1167 uint32_t nPkt,
1168 Time delay)
1169{
1170 for (uint32_t i = 0; i < nPkt; i++)
1171 {
1172 Simulator::Schedule(Seconds((i + 1) * delay.GetSeconds()),
1174 this,
1175 queue);
1176 }
1177}
1178
1179/**
1180 * @ingroup traffic-control-test
1181 * The COBALT queue disc test suite.
1182 */
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
bool m_ecnCapablePacket
ECN capable packet?
CobaltQueueDiscTestItem()=delete
CobaltQueueDiscTestItem & operator=(const CobaltQueueDiscTestItem &)=delete
void AddHeader() override
Add the header to the packet.
CobaltQueueDiscTestItem(Ptr< Packet > p, const Address &addr, bool ecnCapable)
Constructor.
CobaltQueueDiscTestItem(const CobaltQueueDiscTestItem &)=delete
bool Mark() override
Marks the packet as a substitute for dropping it, such as for Explicit Congestion Notification.
a polymophic address class
Definition address.h:114
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.
Definition ptr.h:70
QueueDiscItem(Ptr< Packet > p, const Address &addr, uint16_t protocol)
Create a queue disc item.
Definition queue-item.cc:66
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:580
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:125
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
static void Run()
Run the simulation.
Definition simulator.cc:161
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:169
Hold variables of type string.
Definition string.h:45
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:296
@ QUICK
Fast test.
Definition test.h:1057
TestCase(const TestCase &)=delete
Caller graph was not generated because of its size.
Type
Type of test.
Definition test.h:1271
@ UNIT
This test suite implements a Unit Test.
Definition test.h:1273
TestSuite(std::string name, Type type=Type::UNIT)
Construct a new test suite.
Definition test.cc:494
Simulation virtual time values and global simulation resolution.
Definition nstime.h:96
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:414
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:399
static Time Max()
Maximum representable Time Not to be confused with Max(Time,Time).
Definition nstime.h:288
AttributeValue implementation for Time.
Definition nstime.h:1483
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:690
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:627
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:454
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:133
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition test.h:240
#define NS_TEST_ASSERT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report and abort if not.
Definition test.h:553
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1415
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1398
CobaltQueueDiscTestSuite g_cobaltQueueTestSuite
the test suite
Every class exported by the ns3 library is enclosed in the ns3 namespace.
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.