A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
codel-queue-disc-test-suite.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014 ResiliNets, ITTC, University of Kansas
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Truc Anh N Nguyen <trucanh524@gmail.com>
7 * Modified by: Pasquale Imputato <p.imputato@gmail.com>
8 *
9 */
10
11#include "ns3/codel-queue-disc.h"
12#include "ns3/double.h"
13#include "ns3/log.h"
14#include "ns3/packet.h"
15#include "ns3/simulator.h"
16#include "ns3/string.h"
17#include "ns3/test.h"
18#include "ns3/uinteger.h"
19
20using namespace ns3;
21
22// The following code borrowed from Linux codel.h, for unit testing
23#define REC_INV_SQRT_BITS_ns3 (8 * sizeof(uint16_t))
24/* or sizeof_in_bits(rec_inv_sqrt) */
25/* needed shift to get a Q0.32 number from rec_inv_sqrt */
26#define REC_INV_SQRT_SHIFT_ns3 (32 - REC_INV_SQRT_BITS_ns3)
27
28static uint16_t
30{
32 uint32_t invsqrt2 = ((uint64_t)invsqrt * invsqrt) >> 32;
33 uint64_t val = (3LL << 32) - ((uint64_t)count * invsqrt2);
34
35 val >>= 2; /* avoid overflow in following multiply */
36 val = (val * invsqrt) >> (32 - 2 + 1);
37 return static_cast<uint16_t>(val >> REC_INV_SQRT_SHIFT_ns3);
38}
39
40static uint32_t
42{
43 return (uint32_t)(((uint64_t)val * ep_ro) >> 32);
44}
45
46// End Linux borrow
47
48/**
49 * @ingroup traffic-control-test
50 *
51 * @brief Codel Queue Disc Test Item
52 */
54{
55 public:
56 /**
57 * Constructor
58 *
59 * @param p packet
60 * @param addr address
61 * @param ecnCapable ECN capable
62 */
64 ~CodelQueueDiscTestItem() override;
65
66 // Delete default constructor, copy constructor and assignment operator to avoid misuse
70
71 void AddHeader() override;
72 bool Mark() override;
73
74 private:
75 bool m_ecnCapablePacket; ///< ECN capable packet?
76};
77
79 : QueueDiscItem(p, addr, 0),
80 m_ecnCapablePacket(ecnCapable)
81{
82}
83
87
88void
92
93bool
98
99/**
100 * @ingroup traffic-control-test
101 *
102 * @brief Test 1: simple enqueue/dequeue with no drops
103 */
105{
106 public:
107 /**
108 * Constructor
109 *
110 * @param mode the mode
111 */
113 void DoRun() override;
114
115 private:
117};
118
120 : TestCase("Basic enqueue and dequeue operations, and attribute setting")
121{
122 m_mode = mode;
123}
124
125void
127{
129
130 uint32_t pktSize = 1000;
131 uint32_t modeSize = 0;
132
134
135 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("MinBytes", UintegerValue(pktSize)),
136 true,
137 "Verify that we can actually set the attribute MinBytes");
138 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Interval", StringValue("50ms")),
139 true,
140 "Verify that we can actually set the attribute Interval");
141 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Target", StringValue("4ms")),
142 true,
143 "Verify that we can actually set the attribute Target");
144
145 if (m_mode == QueueSizeUnit::BYTES)
146 {
148 }
149 else if (m_mode == QueueSizeUnit::PACKETS)
150 {
151 modeSize = 1;
152 }
154 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 1500))),
155 true,
156 "Verify that we can actually set the attribute MaxSize");
157 queue->Initialize();
158
171
172 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
173 0 * modeSize,
174 "There should be no packets in queue");
175 queue->Enqueue(Create<CodelQueueDiscTestItem>(p1, dest, false));
176 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
177 1 * modeSize,
178 "There should be one packet in queue");
179 queue->Enqueue(Create<CodelQueueDiscTestItem>(p2, dest, false));
180 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
181 2 * modeSize,
182 "There should be two packets in queue");
183 queue->Enqueue(Create<CodelQueueDiscTestItem>(p3, dest, false));
184 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
185 3 * modeSize,
186 "There should be three packets in queue");
187 queue->Enqueue(Create<CodelQueueDiscTestItem>(p4, dest, false));
188 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
189 4 * modeSize,
190 "There should be four packets in queue");
191 queue->Enqueue(Create<CodelQueueDiscTestItem>(p5, dest, false));
192 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
193 5 * modeSize,
194 "There should be five packets in queue");
195 queue->Enqueue(Create<CodelQueueDiscTestItem>(p6, dest, false));
196 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
197 6 * modeSize,
198 "There should be six packets in queue");
199
200 NS_TEST_ASSERT_MSG_EQ(queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::OVERLIMIT_DROP),
201 0,
202 "There should be no packets being dropped due to full queue");
203
205
206 item = queue->Dequeue();
207 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the first packet");
208 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
209 5 * modeSize,
210 "There should be five packets in queue");
211 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p1->GetUid(), "was this the first packet ?");
212
213 item = queue->Dequeue();
214 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the second packet");
215 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
216 4 * modeSize,
217 "There should be four packets in queue");
218 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(),
219 p2->GetUid(),
220 "Was this the second packet ?");
221
222 item = queue->Dequeue();
223 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the third packet");
224 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
225 3 * modeSize,
226 "There should be three packets in queue");
227 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p3->GetUid(), "Was this the third packet ?");
228
229 item = queue->Dequeue();
230 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the forth packet");
231 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
232 2 * modeSize,
233 "There should be two packets in queue");
234 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(),
235 p4->GetUid(),
236 "Was this the fourth packet ?");
237
238 item = queue->Dequeue();
239 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the fifth packet");
240 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
241 1 * modeSize,
242 "There should be one packet in queue");
243 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p5->GetUid(), "Was this the fifth packet ?");
244
245 item = queue->Dequeue();
246 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the last packet");
247 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
248 0 * modeSize,
249 "There should be zero packet in queue");
250 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p6->GetUid(), "Was this the sixth packet ?");
251
252 item = queue->Dequeue();
253 NS_TEST_ASSERT_MSG_EQ(item, nullptr, "There are really no packets in queue");
254
256 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP),
257 0,
258 "There should be no packet drops according to CoDel algorithm");
259}
260
261/**
262 * @ingroup traffic-control-test
263 *
264 * @brief Test 2: enqueue with drops due to queue overflow
265 */
267{
268 public:
269 /**
270 * Constructor
271 *
272 * @param mode the mode
273 */
275 void DoRun() override;
276
277 private:
278 /**
279 * Enqueue function
280 * @param queue the queue disc
281 * @param size the size
282 * @param nPkt the number of packets
283 */
286};
287
289 : TestCase("Basic overflow behavior")
290{
291 m_mode = mode;
292}
293
294void
296{
298 uint32_t pktSize = 1000;
299 uint32_t modeSize = 0;
300
302
303 if (m_mode == QueueSizeUnit::BYTES)
304 {
306 }
307 else if (m_mode == QueueSizeUnit::PACKETS)
308 {
309 modeSize = 1;
310 }
311
318
320 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
321 true,
322 "Verify that we can actually set the attribute MaxSize");
323 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("MinBytes", UintegerValue(pktSize)),
324 true,
325 "Verify that we can actually set the attribute MinBytes");
326
327 queue->Initialize();
328
329 Enqueue(queue, pktSize, 500);
330 queue->Enqueue(Create<CodelQueueDiscTestItem>(p1, dest, false));
331 queue->Enqueue(Create<CodelQueueDiscTestItem>(p2, dest, false));
332 queue->Enqueue(Create<CodelQueueDiscTestItem>(p3, dest, false));
333
334 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
335 500 * modeSize,
336 "There should be 500 packets in queue");
337 NS_TEST_ASSERT_MSG_EQ(queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::OVERLIMIT_DROP),
338 3,
339 "There should be three packets being dropped due to full queue");
340}
341
342void
344{
346 for (uint32_t i = 0; i < nPkt; i++)
347 {
348 queue->Enqueue(Create<CodelQueueDiscTestItem>(Create<Packet>(size), dest, false));
349 }
350}
351
352/**
353 * @ingroup traffic-control-test
354 *
355 * @brief Test 3: NewtonStep unit test - test against explicit port of Linux implementation
356 */
358{
359 public:
361 void DoRun() override;
362};
363
365 : TestCase("NewtonStep arithmetic unit test")
366{
367}
368
369void
371{
373
374 // Spot check a few points in the expected operational range of
375 // CoDelQueueDisc's m_count and m_recInvSqrt variables
376 uint16_t result;
377 for (uint16_t recInvSqrt = 0xff; recInvSqrt > 0; recInvSqrt /= 2)
378 {
379 for (uint32_t count = 1; count < 0xff; count *= 2)
380 {
381 result = CoDelQueueDisc::NewtonStep(recInvSqrt, count);
382 // Test that ns-3 value is exactly the same as the Linux value
384 result,
385 "ns-3 NewtonStep() fails to match Linux equivalent");
386 }
387 }
388}
389
390/**
391 * @ingroup traffic-control-test
392 *
393 * @brief Test 4: ControlLaw unit test - test against explicit port of Linux implementation
394 */
396{
397 public:
399 void DoRun() override;
400 /**
401 * Codel control law function
402 * @param t
403 * @param interval
404 * @param recInvSqrt
405 * @returns the codel control law
406 */
408};
409
411 : TestCase("ControlLaw arithmetic unit test")
412{
413}
414
415// The following code borrowed from Linux codel.h,
416// except the addition of queue parameter
422
423// End Linux borrow
424
425void
427{
429
430 // Check a few points within the operational range of ControlLaw
431 uint32_t interval = queue->Time2CoDel(MilliSeconds(100));
432
434 for (Time timeVal = Seconds(0); timeVal <= Seconds(20); timeVal += MilliSeconds(100))
435 {
436 for (uint16_t recInvSqrt = 0xff; recInvSqrt > 0; recInvSqrt /= 2)
437 {
438 codelTimeVal = queue->Time2CoDel(timeVal);
443 "Linux result for ControlLaw should equal ns-3 result");
444 }
445 }
446}
447
448/**
449 * @ingroup traffic-control-test
450 *
451 * @brief Test 5: enqueue/dequeue with drops according to CoDel algorithm
452 */
454{
455 public:
456 /**
457 * Constructor
458 *
459 * @param mode the mode
460 */
462 void DoRun() override;
463
464 private:
465 /**
466 * Enqueue function
467 * @param queue the queue disc
468 * @param size the size
469 * @param nPkt the number of packets
470 */
472 /** Dequeue function
473 * @param queue the queue disc
474 * @param modeSize the mode size
475 */
477 /**
478 * Drop next tracer function
479 * @param oldVal the old value
480 * @param newVal the new value
481 */
484 uint32_t m_dropNextCount; ///< count the number of times m_dropNext is recalculated
485};
486
488 : TestCase("Basic drop operations")
489{
490 m_mode = mode;
491 m_dropNextCount = 0;
492}
493
494void
499
500void
502{
504 uint32_t pktSize = 1000;
505 uint32_t modeSize = 0;
506
507 if (m_mode == QueueSizeUnit::BYTES)
508 {
510 }
511 else if (m_mode == QueueSizeUnit::PACKETS)
512 {
513 modeSize = 1;
514 }
515
517 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
518 true,
519 "Verify that we can actually set the attribute MaxSize");
520
521 queue->Initialize();
522
523 Enqueue(queue, pktSize, 20);
524 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
525 20 * modeSize,
526 "There should be 20 packets in queue.");
527
528 // Although the first dequeue occurs with a sojourn time above target
529 // the dequeue should be successful in this interval
530 Time waitUntilFirstDequeue = 2 * queue->GetTarget();
533 this,
534 queue,
535 modeSize);
536
537 // This dequeue should cause a drop
538 Time waitUntilSecondDequeue = waitUntilFirstDequeue + 2 * queue->GetInterval();
541 this,
542 queue,
543 modeSize);
544
545 // Although we are in dropping state, it's not time for next drop
546 // the dequeue should not cause a drop
549 this,
550 queue,
551 modeSize);
552
553 // In dropping time and it's time for next drop
554 // the dequeue should cause additional packet drops
557 this,
558 queue,
559 modeSize);
560
563}
564
565void
567{
569 for (uint32_t i = 0; i < nPkt; i++)
570 {
571 queue->Enqueue(Create<CodelQueueDiscTestItem>(Create<Packet>(size), dest, false));
572 }
573}
574
575void
577{
579 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
580 uint32_t initialQSize = queue->GetCurrentSize().GetValue();
581 uint32_t initialDropNext = queue->GetDropNext();
584
585 if (initialDropCount > 0 && currentTime.GetMicroSeconds() >= initialDropNext)
586 {
587 queue->TraceConnectWithoutContext(
588 "DropNext",
590 }
591
592 if (initialQSize != 0)
593 {
594 Ptr<QueueDiscItem> item = queue->Dequeue();
595 if (initialDropCount == 0 && currentTime > queue->GetTarget())
596 {
597 if (currentTime < queue->GetInterval())
598 {
600 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
602 0,
603 "We are not in dropping state."
604 "Sojourn time has just gone above target from below."
605 "Hence, there should be no packet drops");
606 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
608 "There should be 1 packet dequeued.");
609 }
610 else if (currentTime >= queue->GetInterval())
611 {
613 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
614 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
616 "Sojourn time has been above target for at least interval."
617 "We enter the dropping state, perform initial packet drop, "
618 "and dequeue the next."
619 "So there should be 2 more packets dequeued.");
620 NS_TEST_EXPECT_MSG_EQ(currentDropCount, 1, "There should be 1 packet drop");
621 }
622 }
623 else if (initialDropCount > 0)
624 { // In dropping state
625 if (currentTime.GetMicroSeconds() < initialDropNext)
626 {
628 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
629 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
631 "We are in dropping state."
632 "Sojourn is still above target."
633 "However, it's not time for next drop."
634 "So there should be only 1 more packet dequeued");
635
638 1,
639 "There should still be only 1 packet drop from the last dequeue");
640 }
641 else if (currentTime.GetMicroSeconds() >= initialDropNext)
642 {
644 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
645 NS_TEST_EXPECT_MSG_EQ(queue->GetCurrentSize().GetValue(),
647 "We are in dropping state."
648 "It's time for next drop."
649 "The number of packets dequeued equals to the number of "
650 "times m_dropNext is updated plus initial dequeue");
652 1 + m_dropNextCount,
653 "The number of drops equals to the number of times "
654 "m_dropNext is updated plus 1 from last dequeue");
655 }
656 }
657 }
658}
659
660/**
661 * @ingroup traffic-control-test
662 *
663 * @brief Test 6: enqueue/dequeue with marks according to CoDel algorithm
664 */
666{
667 public:
668 /**
669 * Constructor
670 *
671 * @param mode the mode
672 */
674 void DoRun() override;
675
676 private:
677 /**
678 * Enqueue function
679 * @param queue the queue disc
680 * @param size the size
681 * @param nPkt the number of packets
682 * @param ecnCapable ECN capable traffic
683 */
685 /** Dequeue function
686 * @param queue the queue disc
687 * @param modeSize the mode size
688 * @param testCase the test case number
689 */
691 /**
692 * Drop next tracer function
693 * @param oldVal the old value
694 * @param newVal the new value
695 */
698 uint32_t m_dropNextCount; ///< count the number of times m_dropNext is recalculated
699 uint32_t nPacketsBeforeFirstDrop; ///< Number of packets in the queue before first drop
700 uint32_t nPacketsBeforeFirstMark; ///< Number of packets in the queue before first mark
701};
702
704 : TestCase("Basic mark operations")
705{
706 m_mode = mode;
707 m_dropNextCount = 0;
708}
709
710void
715
716void
718{
719 // Test is divided into 4 sub test cases:
720 // 1) Packets are not ECN capable.
721 // 2) Packets are ECN capable but marking due to exceeding CE threshold disabled
722 // 3) Some packets are ECN capable, with CE threshold set to 2ms.
723 // 4) Packets are ECN capable and CE threshold set to 2ms
724
725 // Test case 1
727 uint32_t pktSize = 1000;
728 uint32_t modeSize = 0;
731
732 if (m_mode == QueueSizeUnit::BYTES)
733 {
735 }
736 else if (m_mode == QueueSizeUnit::PACKETS)
737 {
738 modeSize = 1;
739 }
740
742 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
743 true,
744 "Verify that we can actually set the attribute MaxSize");
745 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
746 true,
747 "Verify that we can actually set the attribute UseEcn");
748
749 queue->Initialize();
750
751 // Not-ECT traffic to induce packet drop
752 Enqueue(queue, pktSize, 20, false);
753 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
754 20 * modeSize,
755 "There should be 20 packets in queue.");
756
757 // Although the first dequeue occurs with a sojourn time above target
758 // there should not be any dropped packets in this interval
759 Time waitUntilFirstDequeue = 2 * queue->GetTarget();
762 this,
763 queue,
764 modeSize,
765 1);
766
767 // This dequeue should cause a packet to be dropped
768 Time waitUntilSecondDequeue = waitUntilFirstDequeue + 2 * queue->GetInterval();
771 this,
772 queue,
773 modeSize,
774 1);
775
778
779 // Test case 2, queue with ECN capable traffic for marking of packets instead of dropping
782 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
783 true,
784 "Verify that we can actually set the attribute MaxSize");
785 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
786 true,
787 "Verify that we can actually set the attribute UseEcn");
788
789 queue->Initialize();
790
791 // ECN capable traffic to induce packets to be marked
792 Enqueue(queue, pktSize, 20, true);
793 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
794 20 * modeSize,
795 "There should be 20 packets in queue.");
796
797 // Although the first dequeue occurs with a sojourn time above target
798 // there should not be any target exceeded marked packets in this interval
801 this,
802 queue,
803 modeSize,
804 2);
805
806 // This dequeue should cause a packet to be marked
809 this,
810 queue,
811 modeSize,
812 2);
813
814 // Although we are in dropping state, it's not time for next packet to be target exceeded marked
815 // the dequeue should not cause a packet to be target exceeded marked
818 this,
819 queue,
820 modeSize,
821 2);
822
823 // In dropping time and it's time for next packet to be target exceeded marked
824 // the dequeue should cause additional packet to be target exceeded marked
827 this,
828 queue,
829 modeSize,
830 2);
831
834
835 // Test case 3, some packets are ECN capable, with CE threshold set to 2ms
838 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
839 true,
840 "Verify that we can actually set the attribute MaxSize");
841 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
842 true,
843 "Verify that we can actually set the attribute UseEcn");
844 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("CeThreshold", TimeValue(MilliSeconds(2))),
845 true,
846 "Verify that we can actually set the attribute CeThreshold");
847
848 queue->Initialize();
849
850 // First 3 packets in the queue are ecnCapable
851 Enqueue(queue, pktSize, 3, true);
852 // Rest of the packet are not ecnCapable
853 Enqueue(queue, pktSize, 17, false);
854 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
855 20 * modeSize,
856 "There should be 20 packets in queue.");
857
858 // Although the first dequeue occurs with a sojourn time above target
859 // there should not be any target exceeded marked packets in this interval
862 this,
863 queue,
864 modeSize,
865 3);
866
867 // This dequeue should cause a packet to be marked
870 this,
871 queue,
872 modeSize,
873 3);
874
875 // Although we are in dropping state, it's not time for next packet to be target exceeded marked
876 // the dequeue should not cause a packet to be target exceeded marked
879 this,
880 queue,
881 modeSize,
882 3);
883
884 // In dropping time and it's time for next packet to be dropped as packets are not ECN capable
885 // the dequeue should cause packet to be dropped
888 this,
889 queue,
890 modeSize,
891 3);
892
895
896 // Test case 4, queue with ECN capable traffic and CeThreshold set for marking of packets
897 // instead of dropping
900 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(m_mode, modeSize * 500))),
901 true,
902 "Verify that we can actually set the attribute MaxSize");
903 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("UseEcn", BooleanValue(true)),
904 true,
905 "Verify that we can actually set the attribute UseEcn");
906 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("CeThreshold", TimeValue(MilliSeconds(2))),
907 true,
908 "Verify that we can actually set the attribute CeThreshold");
909
910 queue->Initialize();
911
912 // ECN capable traffic to induce packets to be marked
913 Enqueue(queue, pktSize, 20, true);
914 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
915 20 * modeSize,
916 "There should be 20 packets in queue.");
917
918 // The first dequeue occurs with a sojourn time below CE threshold
919 // there should not any be CE threshold exceeded marked packets
922 this,
923 queue,
924 modeSize,
925 4);
926
927 // Sojourn time above CE threshold so this dequeue should cause a packet to be CE thershold
928 // exceeded marked
931 this,
932 queue,
933 modeSize,
934 4);
935
936 // the dequeue should cause a packet to be CE threshold exceeded marked
939 this,
940 queue,
941 modeSize,
942 4);
943
944 // In dropping time and it's time for next packet to be dropped but because of using ECN, packet
945 // should be marked
948 this,
949 queue,
950 modeSize,
951 4);
952
955}
956
957void
959 uint32_t size,
961 bool ecnCapable)
962{
964 for (uint32_t i = 0; i < nPkt; i++)
965 {
967 }
968}
969
970void
972{
974 queue->GetStats().GetNMarkedPackets(CoDelQueueDisc::TARGET_EXCEEDED_MARK);
976 queue->GetStats().GetNMarkedPackets(CoDelQueueDisc::CE_THRESHOLD_EXCEEDED_MARK);
977 uint32_t initialQSize = queue->GetCurrentSize().GetValue();
978 uint32_t initialDropNext = queue->GetDropNext();
983
984 if (initialTargetMarkCount > 0 && currentTime.GetMicroSeconds() >= initialDropNext &&
985 testCase == 3)
986 {
987 queue->TraceConnectWithoutContext(
988 "DropNext",
990 }
991
992 if (initialQSize != 0)
993 {
994 Ptr<QueueDiscItem> item = queue->Dequeue();
995 if (testCase == 1)
996 {
998 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
999 if (currentDropCount == 1)
1000 {
1002 }
1003 }
1004 else if (testCase == 2)
1005 {
1006 if (initialTargetMarkCount == 0 && currentTime > queue->GetTarget())
1007 {
1008 if (currentTime < queue->GetInterval())
1009 {
1011 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
1013 queue->GetStats().GetNMarkedPackets(CoDelQueueDisc::TARGET_EXCEEDED_MARK);
1014 currentCeThreshMarkCount = queue->GetStats().GetNMarkedPackets(
1016 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
1018 "There should be 1 packet dequeued.");
1020 0,
1021 "There should not be any packet drops");
1024 0,
1025 "We are not in dropping state."
1026 "Sojourn time has just gone above target from below."
1027 "Hence, there should be no target exceeded marked packets");
1030 0,
1031 "Marking due to CE threshold is disabled"
1032 "Hence, there should not be any CE threshold exceeded marked packet");
1033 }
1034 else if (currentTime >= queue->GetInterval())
1035 {
1037 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
1039 queue->GetStats().GetNMarkedPackets(CoDelQueueDisc::TARGET_EXCEEDED_MARK);
1041 currentCeThreshMarkCount = queue->GetStats().GetNMarkedPackets(
1044 queue->GetCurrentSize().GetValue(),
1046 "Sojourn time has been above target for at least interval."
1047 "We enter the dropping state and perform initial packet marking"
1048 "So there should be only 1 more packet dequeued.");
1050 0,
1051 "There should not be any packet drops");
1053 1,
1054 "There should be 1 target exceeded marked packet");
1057 0,
1058 "There should not be any CE threshold exceeded marked packet");
1059 }
1060 }
1061 else if (initialTargetMarkCount > 0)
1062 { // In dropping state
1063 if (currentTime.GetMicroSeconds() < initialDropNext)
1064 {
1066 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
1068 queue->GetStats().GetNMarkedPackets(CoDelQueueDisc::TARGET_EXCEEDED_MARK);
1069 currentCeThreshMarkCount = queue->GetStats().GetNMarkedPackets(
1071 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
1073 "We are in dropping state."
1074 "Sojourn is still above target."
1075 "However, it's not time for next target exceeded mark."
1076 "So there should be only 1 more packet dequeued");
1078 0,
1079 "There should not be any packet drops");
1081 1,
1082 "There should still be only 1 target exceeded marked "
1083 "packet from the last dequeue");
1086 0,
1087 "There should not be any CE threshold exceeded marked packet");
1088 }
1089 else if (currentTime.GetMicroSeconds() >= initialDropNext)
1090 {
1092 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
1094 queue->GetStats().GetNMarkedPackets(CoDelQueueDisc::TARGET_EXCEEDED_MARK);
1095 currentCeThreshMarkCount = queue->GetStats().GetNMarkedPackets(
1097 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
1099 "We are in dropping state."
1100 "It's time for packet to be marked"
1101 "So there should be only 1 more packet dequeued");
1103 0,
1104 "There should not be any packet drops");
1106 2,
1107 "There should 2 target exceeded marked packet");
1111 "Number of packets in the queue before drop should be equal"
1112 "to number of packets in the queue before first mark as the behavior "
1113 "until packet N should be the same.");
1116 0,
1117 "There should not be any CE threshold exceeded marked packet");
1118 }
1119 }
1120 }
1121 else if (testCase == 3)
1122 {
1123 if (initialTargetMarkCount == 0 && currentTime > queue->GetTarget())
1124 {
1125 if (currentTime < queue->GetInterval())
1126 {
1128 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
1130 queue->GetStats().GetNMarkedPackets(CoDelQueueDisc::TARGET_EXCEEDED_MARK);
1131 currentCeThreshMarkCount = queue->GetStats().GetNMarkedPackets(
1133 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
1135 "There should be 1 packet dequeued.");
1137 0,
1138 "There should not be any packet drops");
1141 0,
1142 "We are not in dropping state."
1143 "Sojourn time has just gone above target from below."
1144 "Hence, there should be no target exceeded marked packets");
1147 1,
1148 "Sojourn time has gone above CE threshold."
1149 "Hence, there should be 1 CE threshold exceeded marked packet");
1150 }
1151 else if (currentTime >= queue->GetInterval())
1152 {
1154 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
1156 queue->GetStats().GetNMarkedPackets(CoDelQueueDisc::TARGET_EXCEEDED_MARK);
1157 currentCeThreshMarkCount = queue->GetStats().GetNMarkedPackets(
1160 queue->GetCurrentSize().GetValue(),
1162 "Sojourn time has been above target for at least interval."
1163 "We enter the dropping state and perform initial packet marking"
1164 "So there should be only 1 more packet dequeued.");
1166 0,
1167 "There should not be any packet drops");
1169 1,
1170 "There should be 1 target exceeded marked packet");
1172 1,
1173 "There should be 1 CE threshold exceeded marked packets");
1174 }
1175 }
1176 else if (initialTargetMarkCount > 0)
1177 { // In dropping state
1178 if (currentTime.GetMicroSeconds() < initialDropNext)
1179 {
1181 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
1183 queue->GetStats().GetNMarkedPackets(CoDelQueueDisc::TARGET_EXCEEDED_MARK);
1184 currentCeThreshMarkCount = queue->GetStats().GetNMarkedPackets(
1186 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
1188 "We are in dropping state."
1189 "Sojourn is still above target."
1190 "However, it's not time for next target exceeded mark."
1191 "So there should be only 1 more packet dequeued");
1193 0,
1194 "There should not be any packet drops");
1196 1,
1197 "There should still be only 1 target exceeded marked "
1198 "packet from the last dequeue");
1200 2,
1201 "There should be 2 CE threshold exceeded marked packets");
1202 }
1203 else if (currentTime.GetMicroSeconds() >= initialDropNext)
1204 {
1206 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
1208 queue->GetStats().GetNMarkedPackets(CoDelQueueDisc::TARGET_EXCEEDED_MARK);
1209 currentCeThreshMarkCount = queue->GetStats().GetNMarkedPackets(
1212 queue->GetCurrentSize().GetValue(),
1214 "We are in dropping state."
1215 "It's time for packet to be dropped as packets are not ecnCapable"
1216 "The number of packets dequeued equals to the number of times m_dropNext "
1217 "is updated plus initial dequeue");
1221 "The number of drops equals to the number of times m_dropNext is updated");
1224 1,
1225 "There should still be only 1 target exceeded marked packet");
1227 2,
1228 "There should still be 2 CE threshold exceeded marked "
1229 "packet as packets are not ecnCapable");
1230 }
1231 }
1232 }
1233 else if (testCase == 4)
1234 {
1235 if (currentTime < queue->GetTarget())
1236 {
1238 {
1240 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
1241 currentCeThreshMarkCount = queue->GetStats().GetNMarkedPackets(
1243 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
1245 "There should be 1 packet dequeued.");
1247 0,
1248 "There should not be any packet drops");
1251 0,
1252 "Sojourn time has not gone above CE threshold."
1253 "Hence, there should not be any CE threshold exceeded marked packet");
1254 }
1255 else
1256 {
1258 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
1259 currentCeThreshMarkCount = queue->GetStats().GetNMarkedPackets(
1261 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
1263 "There should be only 1 more packet dequeued.");
1265 0,
1266 "There should not be any packet drops");
1268 1,
1269 "Sojourn time has gone above CE threshold."
1270 "There should be 1 CE threshold exceeded marked packet");
1271 }
1272 }
1273 else if (initialCeThreshMarkCount > 0 && currentTime < queue->GetInterval())
1274 {
1276 {
1278 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
1279 currentCeThreshMarkCount = queue->GetStats().GetNMarkedPackets(
1281 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
1283 "There should be only 1 more packet dequeued.");
1285 0,
1286 "There should not be any packet drops");
1288 2,
1289 "There should be 2 CE threshold exceeded marked packets");
1290 }
1291 else
1292 { // In dropping state
1294 queue->GetStats().GetNDroppedPackets(CoDelQueueDisc::TARGET_EXCEEDED_DROP);
1295 currentCeThreshMarkCount = queue->GetStats().GetNMarkedPackets(
1297 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
1299 "There should be only 1 more packet dequeued.");
1301 0,
1302 "There should not be any packet drops");
1304 3,
1305 "There should be 3 CE threshold exceeded marked packet");
1306 }
1307 }
1308 }
1309 }
1310}
1311
1312/**
1313 * @ingroup traffic-control-test
1314 *
1315 * @brief CoDel Queue Disc Test Suite
1316 */
1318{
1319 public:
1321 : TestSuite("codel-queue-disc", Type::UNIT)
1322 {
1323 // Test 1: simple enqueue/dequeue with no drops
1324 AddTestCase(new CoDelQueueDiscBasicEnqueueDequeue(QueueSizeUnit::PACKETS),
1325 TestCase::Duration::QUICK);
1326 AddTestCase(new CoDelQueueDiscBasicEnqueueDequeue(QueueSizeUnit::BYTES),
1327 TestCase::Duration::QUICK);
1328 // Test 2: enqueue with drops due to queue overflow
1329 AddTestCase(new CoDelQueueDiscBasicOverflow(QueueSizeUnit::PACKETS),
1330 TestCase::Duration::QUICK);
1331 AddTestCase(new CoDelQueueDiscBasicOverflow(QueueSizeUnit::BYTES),
1332 TestCase::Duration::QUICK);
1333 // Test 3: test NewtonStep() against explicit port of Linux implementation
1334 AddTestCase(new CoDelQueueDiscNewtonStepTest(), TestCase::Duration::QUICK);
1335 // Test 4: test ControlLaw() against explicit port of Linux implementation
1336 AddTestCase(new CoDelQueueDiscControlLawTest(), TestCase::Duration::QUICK);
1337 // Test 5: enqueue/dequeue with drops according to CoDel algorithm
1338 AddTestCase(new CoDelQueueDiscBasicDrop(QueueSizeUnit::PACKETS), TestCase::Duration::QUICK);
1339 AddTestCase(new CoDelQueueDiscBasicDrop(QueueSizeUnit::BYTES), TestCase::Duration::QUICK);
1340 // Test 6: enqueue/dequeue with marks according to CoDel algorithm
1341 AddTestCase(new CoDelQueueDiscBasicMark(QueueSizeUnit::PACKETS), TestCase::Duration::QUICK);
1342 AddTestCase(new CoDelQueueDiscBasicMark(QueueSizeUnit::BYTES), TestCase::Duration::QUICK);
1343 }
1344} g_coDelQueueTestSuite; ///< the test suite
Test 5: enqueue/dequeue with drops according to CoDel algorithm.
uint32_t m_dropNextCount
count the number of times m_dropNext is recalculated
CoDelQueueDiscBasicDrop(QueueSizeUnit mode)
Constructor.
void Dequeue(Ptr< CoDelQueueDisc > queue, uint32_t modeSize)
Dequeue function.
void Enqueue(Ptr< CoDelQueueDisc > queue, uint32_t size, uint32_t nPkt)
Enqueue function.
void DoRun() override
Implementation to actually run this TestCase.
void DropNextTracer(uint32_t oldVal, uint32_t newVal)
Drop next tracer function.
Test 1: simple enqueue/dequeue with no drops.
CoDelQueueDiscBasicEnqueueDequeue(QueueSizeUnit mode)
Constructor.
void DoRun() override
Implementation to actually run this TestCase.
Test 6: enqueue/dequeue with marks according to CoDel algorithm.
uint32_t nPacketsBeforeFirstMark
Number of packets in the queue before first mark.
void Enqueue(Ptr< CoDelQueueDisc > queue, uint32_t size, uint32_t nPkt, bool ecnCapable)
Enqueue function.
uint32_t m_dropNextCount
count the number of times m_dropNext is recalculated
void DropNextTracer(uint32_t oldVal, uint32_t newVal)
Drop next tracer function.
uint32_t nPacketsBeforeFirstDrop
Number of packets in the queue before first drop.
void Dequeue(Ptr< CoDelQueueDisc > queue, uint32_t modeSize, uint32_t testCase)
Dequeue function.
void DoRun() override
Implementation to actually run this TestCase.
CoDelQueueDiscBasicMark(QueueSizeUnit mode)
Constructor.
Test 2: enqueue with drops due to queue overflow.
CoDelQueueDiscBasicOverflow(QueueSizeUnit mode)
Constructor.
void DoRun() override
Implementation to actually run this TestCase.
void Enqueue(Ptr< CoDelQueueDisc > queue, uint32_t size, uint32_t nPkt)
Enqueue function.
Test 4: ControlLaw unit test - test against explicit port of Linux implementation.
void DoRun() override
Implementation to actually run this TestCase.
uint32_t _codel_control_law(uint32_t t, uint32_t interval, uint32_t recInvSqrt)
Codel control law function.
Test 3: NewtonStep unit test - test against explicit port of Linux implementation.
void DoRun() override
Implementation to actually run this TestCase.
CoDel Queue Disc Test Suite.
Codel Queue Disc Test Item.
void AddHeader() override
Add the header to the packet.
bool Mark() override
Marks the packet as a substitute for dropping it, such as for Explicit Congestion Notification.
bool m_ecnCapablePacket
ECN capable packet?
CodelQueueDiscTestItem & operator=(const CodelQueueDiscTestItem &)=delete
CodelQueueDiscTestItem(const CodelQueueDiscTestItem &)=delete
CodelQueueDiscTestItem()=delete
a polymophic address class
Definition address.h:90
AttributeValue implementation for Boolean.
Definition boolean.h:26
static uint16_t NewtonStep(uint16_t recInvSqrt, uint32_t count)
Calculate the reciprocal square root of m_count by using Newton's method http://en....
static constexpr const char * OVERLIMIT_DROP
Overlimit dropped packet.
static uint32_t ControlLaw(uint32_t t, uint32_t interval, uint32_t recInvSqrt)
Determine the time for next drop CoDel control law is t + m_interval/sqrt(m_count).
static constexpr const char * TARGET_EXCEEDED_DROP
Sojourn time above target.
static constexpr const char * CE_THRESHOLD_EXCEEDED_MARK
Sojourn time above CE threshold.
static constexpr const char * TARGET_EXCEEDED_MARK
Sojourn time above target.
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:66
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
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
AttributeValue implementation for Time.
Definition nstime.h:1431
Hold an unsigned integer type.
Definition uinteger.h:34
#define REC_INV_SQRT_SHIFT_ns3
static uint16_t _codel_Newton_step(uint16_t rec_inv_sqrt, uint32_t count)
static uint32_t _reciprocal_scale(uint32_t val, uint32_t ep_ro)
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
#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 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
CoDelQueueDiscTestSuite g_coDelQueueTestSuite
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
uint32_t pktSize
packet size used for the simulation (in bytes)