traffic-control: Add ECN tests for COBALT queue disc

This commit is contained in:
Bhaskar Kataria
2020-05-29 21:48:23 +05:30
committed by Tom Henderson
parent 32e95f8228
commit 830edb7623
2 changed files with 318 additions and 0 deletions

View File

@@ -120,6 +120,7 @@ The suite includes 2 test cases:
* Test 1: Simple enqueue/dequeue with no drops.
* Test 2: Change of BLUE's drop probability upon queue full
(Activation of Blue).
* Test 3: Test for ECN marking of packets
The test suite can be run using the following commands:

View File

@@ -323,6 +323,320 @@ CobaltQueueDiscDropTest::DoRun (void)
Simulator::Destroy ();
}
/**
* \ingroup traffic-control-test
* \ingroup tests
*
* \brief Test 3: Cobalt Queue Disc ECN marking Test Item
*/
class CobaltQueueDiscMarkTest : public TestCase
{
public:
/**
* Constructor
*
* \param mode the mode
*/
CobaltQueueDiscMarkTest (QueueSizeUnit mode);
virtual void DoRun (void);
private:
/**
* \brief Enqueue function
* \param queue the queue disc
* \param size the size
* \param nPkt the number of packets
* \param ecnCapable ECN capable traffic
*/
void Enqueue (Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, bool ecnCapable);
/**
* \brief Dequeue function
* \param queue the queue disc
* \param modeSize the mode size
* \param testCase the test case number
*/
void Dequeue (Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t testCase);
/**
* \brief Drop next tracer function
* \param oldVal the old value of m_dropNext
* \param newVal the new value of m_dropNext
*/
void DropNextTracer (int64_t oldVal, int64_t newVal);
QueueSizeUnit m_mode; ///< mode
uint32_t m_dropNextCount; ///< count the number of times m_dropNext is recalculated
uint32_t nPacketsBeforeFirstDrop; ///< Number of packets in the queue before first drop
uint32_t nPacketsBeforeFirstMark; ///< Number of packets in the queue before first mark
};
CobaltQueueDiscMarkTest::CobaltQueueDiscMarkTest (QueueSizeUnit mode)
: TestCase ("Basic mark operations")
{
m_mode = mode;
m_dropNextCount = 0;
}
void
CobaltQueueDiscMarkTest::DropNextTracer (int64_t oldVal, int64_t newVal)
{
NS_UNUSED (oldVal);
NS_UNUSED (newVal);
m_dropNextCount++;
}
void
CobaltQueueDiscMarkTest::DoRun (void)
{
// Test is divided into 3 sub test cases:
// 1) Packets are not ECN capable.
// 2) Packets are ECN capable.
// 3) Some packets are ECN capable.
// Test case 1
Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc> ();
uint32_t pktSize = 1000;
uint32_t modeSize = 0;
nPacketsBeforeFirstDrop = 0;
nPacketsBeforeFirstMark = 0;
if (m_mode == QueueSizeUnit::BYTES)
{
modeSize = pktSize;
}
else if (m_mode == QueueSizeUnit::PACKETS)
{
modeSize = 1;
}
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (m_mode, modeSize * 500))),
true, "Verify that we can actually set the attribute MaxSize");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("UseEcn", BooleanValue (false)),
true, "Verify that we can actually set the attribute UseEcn");
queue->Initialize ();
// Not-ECT traffic to induce packet drop
Enqueue (queue, pktSize, 20, false);
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 20 * modeSize, "There should be 20 packets in queue.");
// Although the first dequeue occurs with a sojourn time above target
// there should not be any dropped packets in this interval
Time waitUntilFirstDequeue = 2 * queue->GetTarget ();
Simulator::Schedule (waitUntilFirstDequeue, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 1);
// This dequeue should cause a packet to be dropped
Time waitUntilSecondDequeue = waitUntilFirstDequeue + 2 * queue->GetInterval ();
Simulator::Schedule (waitUntilSecondDequeue, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 1);
Simulator::Run ();
Simulator::Destroy ();
// Test case 2, queue with ECN capable traffic for marking of packets instead of dropping
queue = CreateObject<CobaltQueueDisc> ();
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (m_mode, modeSize * 500))),
true, "Verify that we can actually set the attribute MaxSize");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("UseEcn", BooleanValue (true)),
true, "Verify that we can actually set the attribute UseEcn");
queue->Initialize ();
// ECN capable traffic
Enqueue (queue, pktSize, 20, true);
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 20 * modeSize, "There should be 20 packets in queue.");
// Although the first dequeue occurs with a sojourn time above target
// there should not be any marked packets in this interval
Simulator::Schedule (waitUntilFirstDequeue, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 2);
// This dequeue should cause a packet to be marked
Simulator::Schedule (waitUntilSecondDequeue, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 2);
// This dequeue should cause a packet to be marked as dropnext is equal to current time
Simulator::Schedule (waitUntilSecondDequeue, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 2);
// In dropping phase and it's time for next packet to be marked
// the dequeue should cause additional packet to be marked
Simulator::Schedule (waitUntilSecondDequeue * 2, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 2);
Simulator::Run ();
Simulator::Destroy ();
// Test case 3, some packets are ECN capable
queue = CreateObject<CobaltQueueDisc> ();
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (m_mode, modeSize * 500))),
true, "Verify that we can actually set the attribute MaxSize");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("UseEcn", BooleanValue (true)),
true, "Verify that we can actually set the attribute UseEcn");
queue->Initialize ();
// First 3 packets in the queue are ecnCapable
Enqueue (queue, pktSize, 3, true);
// Rest of the packet are not ecnCapable
Enqueue (queue, pktSize, 17, false);
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 20 * modeSize, "There should be 20 packets in queue.");
// Although the first dequeue occurs with a sojourn time above target
// there should not be any marked packets in this interval
Simulator::Schedule (waitUntilFirstDequeue, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 3);
// This dequeue should cause a packet to be marked
Simulator::Schedule (waitUntilSecondDequeue, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 3);
// This dequeue should cause a packet to be marked as dropnext is equal to current time
Simulator::Schedule (waitUntilSecondDequeue, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 3);
// In dropping phase and it's time for next packet to be dropped as packets are not ECN capable
// the dequeue should cause packet to be dropped
Simulator::Schedule (waitUntilSecondDequeue * 2, &CobaltQueueDiscMarkTest::Dequeue, this, queue, modeSize, 3);
Simulator::Run ();
Simulator::Destroy ();
}
void
CobaltQueueDiscMarkTest::Enqueue (Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, bool ecnCapable)
{
Address dest;
for (uint32_t i = 0; i < nPkt; i++)
{
queue->Enqueue (Create<CobaltQueueDiscTestItem> (Create<Packet> (size), dest, 0, ecnCapable));
}
}
void
CobaltQueueDiscMarkTest::Dequeue (Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t testCase)
{
uint32_t initialMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
uint32_t initialQSize = queue->GetCurrentSize ().GetValue ();
uint32_t initialDropNext = queue->GetDropNext ();
Time currentTime = Simulator::Now ();
uint32_t currentDropCount = 0;
uint32_t currentMarkCount = 0;
if (initialMarkCount > 0 && currentTime.GetNanoSeconds () > initialDropNext && testCase == 3)
{
queue->TraceConnectWithoutContext ("DropNext", MakeCallback (&CobaltQueueDiscMarkTest::DropNextTracer, this));
}
if (initialQSize != 0)
{
Ptr<QueueDiscItem> item = queue->Dequeue ();
if (testCase == 1)
{
currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
if (currentDropCount != 0)
{
nPacketsBeforeFirstDrop = initialQSize;
}
}
if (testCase == 2)
{
if (initialMarkCount == 0 && currentTime > queue->GetTarget ())
{
if (currentTime < queue->GetInterval ())
{
currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize, "There should be 1 packet dequeued.");
NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
NS_TEST_ASSERT_MSG_EQ (currentMarkCount, 0, "We are not in dropping state."
"Sojourn time has just gone above target from below."
"Hence, there should be no marked packets");
}
else if (currentTime >= queue->GetInterval ())
{
nPacketsBeforeFirstMark = initialQSize;
currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize,
"Sojourn time has been above target for at least interval."
"We enter the dropping state and perform initial packet marking"
"So there should be only 1 more packet dequeued.");
NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 1, "There should be 1 marked packet");
}
}
else if (initialMarkCount > 0)
{
if (currentTime.GetNanoSeconds () <= initialDropNext)
{
currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize, "We are in dropping state."
"Sojourn is still above target."
"There should be only 1 more packet dequeued");
NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 2, "There should be 2 marked packet as."
"current dropnext is equal to current time.");
}
else if (currentTime.GetNanoSeconds () > initialDropNext)
{
currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize, "We are in dropping state."
"It's time for packet to be marked"
"So there should be only 1 more packet dequeued");
NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 3, "There should be 3 marked packet");
NS_TEST_EXPECT_MSG_EQ (nPacketsBeforeFirstDrop, nPacketsBeforeFirstMark, "Number of packets in the queue before drop should be equal"
"to number of packets in the queue before first mark as the behavior until packet N should be the same.");
}
}
}
else if (testCase == 3)
{
if (initialMarkCount == 0 && currentTime > queue->GetTarget ())
{
if (currentTime < queue->GetInterval ())
{
currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize, "There should be 1 packet dequeued.");
NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
NS_TEST_ASSERT_MSG_EQ (currentMarkCount, 0, "We are not in dropping state."
"Sojourn time has just gone above target from below."
"Hence, there should be no marked packets");
}
else if (currentTime >= queue->GetInterval ())
{
currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize,
"Sojourn time has been above target for at least interval."
"We enter the dropping state and perform initial packet marking"
"So there should be only 1 more packet dequeued.");
NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 1, "There should be 1 marked packet");
}
}
else if (initialMarkCount > 0)
{
if (currentTime.GetNanoSeconds () <= initialDropNext)
{
currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize, "We are in dropping state."
"Sojourn is still above target."
"So there should be only 1 more packet dequeued");
NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 2, "There should be 2 marked packet"
"as dropnext is equal to current time");
}
else if (currentTime.GetNanoSeconds () > initialDropNext)
{
currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - (m_dropNextCount + 1) * modeSize, "We are in dropping state."
"It's time for packet to be dropped as packets are not ecnCapable"
"The number of packets dequeued equals to the number of times m_dropNext is updated plus initial dequeue");
NS_TEST_EXPECT_MSG_EQ (currentDropCount, m_dropNextCount, "The number of drops equals to the number of times m_dropNext is updated");
NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 2, "There should still be only 2 marked packet");
}
}
}
}
}
static class CobaltQueueDiscTestSuite : public TestSuite
{
public:
@@ -334,5 +648,8 @@ public:
AddTestCase (new CobaltQueueDiscBasicEnqueueDequeue (BYTES), TestCase::QUICK);
// Test 2: Drop test
AddTestCase (new CobaltQueueDiscDropTest (), TestCase::QUICK);
// Test 3: Mark test
AddTestCase (new CobaltQueueDiscMarkTest (PACKETS), TestCase::QUICK);
AddTestCase (new CobaltQueueDiscMarkTest (BYTES), TestCase::QUICK);
}
} g_cobaltQueueTestSuite; ///< the test suite