traffic-control: (merges !377) Add FqPIE and an L4S mode for PIE queue disc
This commit is contained in:
committed by
Tom Henderson
parent
31ad20931a
commit
85e3a7a917
@@ -55,6 +55,7 @@ us a note on ns-developers mailing list.</p>
|
||||
<h2>New API:</h2>
|
||||
<ul>
|
||||
<li>Added <b>FqCobalt</b> queue disc with L4S features and set associative hash.</li>
|
||||
<li>Added <b>FqPIE</b> queue disc with <b>L4S</b> mode</li>
|
||||
</ul>
|
||||
<h2>Changes to existing API:</h2>
|
||||
<ul>
|
||||
@@ -127,9 +128,9 @@ in order to support multi-users (MU) transmissions.
|
||||
<li>Added <b>Active/Inactive feature</b> to PIE queue disc</li>
|
||||
<li>Added <b>netmap</b> and <b>DPDK</b> emulation device variants</li>
|
||||
<li>Added capability to configure <b>STL pair and containers as attributes</b></li>
|
||||
<li> Added <b>CartesianToGeographic</b> coordinate conversion capability
|
||||
<li> Added <b>LollipopCounter</b>, a sequence number counter type
|
||||
<li> Added <b>6 GHz band</b> support for Wi-Fi 802.11ax
|
||||
<li> Added <b>CartesianToGeographic</b> coordinate conversion capability</li>
|
||||
<li> Added <b>LollipopCounter</b>, a sequence number counter type</li>
|
||||
<li> Added <b>6 GHz band</b> support for Wi-Fi 802.11ax</li>
|
||||
</ul>
|
||||
<h2>Changes to existing API:</h2>
|
||||
<ul>
|
||||
|
||||
@@ -32,6 +32,7 @@ New user-visible features
|
||||
- (wifi) HT Greenfield (HT_GF) preamble support has been removed from the model
|
||||
- (wifi) Some wifi/src/model files were moved to the relevant subfolders (non-ht, ht, vht, he, and rate-control)
|
||||
- (traffic-control) Added FqCobalt queue disc with L4S features and set associative hash.
|
||||
- (traffic-control) Added FqPIE queue disc with L4S mode.
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
834
src/test/ns3tc/fq-pie-queue-disc-test-suite.cc
Normal file
834
src/test/ns3tc/fq-pie-queue-disc-test-suite.cc
Normal file
@@ -0,0 +1,834 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2020 NITK Surathkal
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Authors: Bhaskar Kataria <bhaskar.k7920@gmail.com>
|
||||
* Tom Henderson <tomhend@u.washington.edu>
|
||||
* Mohit P. Tahiliani <tahiliani@nitk.edu.in>
|
||||
* Vivek Jain <jain.vivek.anand@gmail.com>
|
||||
* Ankit Deepak <adadeepak8@gmail.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ns3/test.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/fq-pie-queue-disc.h"
|
||||
#include "ns3/pie-queue-disc.h"
|
||||
#include "ns3/ipv4-header.h"
|
||||
#include "ns3/ipv4-packet-filter.h"
|
||||
#include "ns3/ipv4-queue-disc-item.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/ipv6-header.h"
|
||||
#include "ns3/ipv6-packet-filter.h"
|
||||
#include "ns3/ipv6-queue-disc-item.h"
|
||||
#include "ns3/tcp-header.h"
|
||||
#include "ns3/udp-header.h"
|
||||
#include "ns3/string.h"
|
||||
#include "ns3/pointer.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
// Variable to assign g_hash to a new packet's flow
|
||||
int32_t g_hash;
|
||||
|
||||
/**
|
||||
* Simple test packet filter able to classify IPv4 packets
|
||||
*
|
||||
*/
|
||||
class Ipv4FqPieTestPacketFilter : public Ipv4PacketFilter {
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
Ipv4FqPieTestPacketFilter ();
|
||||
virtual ~Ipv4FqPieTestPacketFilter ();
|
||||
|
||||
private:
|
||||
virtual int32_t DoClassify (Ptr<QueueDiscItem> item) const;
|
||||
virtual bool CheckProtocol (Ptr<QueueDiscItem> item) const;
|
||||
};
|
||||
|
||||
TypeId
|
||||
Ipv4FqPieTestPacketFilter::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::Ipv4FqPieTestPacketFilter")
|
||||
.SetParent<Ipv4PacketFilter> ()
|
||||
.SetGroupName ("Internet")
|
||||
.AddConstructor<Ipv4FqPieTestPacketFilter> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
Ipv4FqPieTestPacketFilter::Ipv4FqPieTestPacketFilter ()
|
||||
{
|
||||
}
|
||||
|
||||
Ipv4FqPieTestPacketFilter::~Ipv4FqPieTestPacketFilter ()
|
||||
{
|
||||
}
|
||||
|
||||
int32_t
|
||||
Ipv4FqPieTestPacketFilter::DoClassify (Ptr<QueueDiscItem> item) const
|
||||
{
|
||||
return g_hash;
|
||||
}
|
||||
|
||||
bool
|
||||
Ipv4FqPieTestPacketFilter::CheckProtocol (Ptr<QueueDiscItem> item) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class tests packets for which there is no suitable filter
|
||||
*/
|
||||
class FqPieQueueDiscNoSuitableFilter : public TestCase
|
||||
{
|
||||
public:
|
||||
FqPieQueueDiscNoSuitableFilter ();
|
||||
virtual ~FqPieQueueDiscNoSuitableFilter ();
|
||||
|
||||
private:
|
||||
virtual void DoRun (void);
|
||||
};
|
||||
|
||||
FqPieQueueDiscNoSuitableFilter::FqPieQueueDiscNoSuitableFilter ()
|
||||
: TestCase ("Test packets that are not classified by any filter")
|
||||
{
|
||||
}
|
||||
|
||||
FqPieQueueDiscNoSuitableFilter::~FqPieQueueDiscNoSuitableFilter ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDiscNoSuitableFilter::DoRun (void)
|
||||
{
|
||||
// Packets that cannot be classified by the available filters should be dropped
|
||||
Ptr<FqPieQueueDisc> queueDisc = CreateObjectWithAttributes<FqPieQueueDisc> ("MaxSize", StringValue ("4p"));
|
||||
Ptr<Ipv4FqPieTestPacketFilter> filter = CreateObject<Ipv4FqPieTestPacketFilter> ();
|
||||
queueDisc->AddPacketFilter (filter);
|
||||
|
||||
g_hash = -1;
|
||||
queueDisc->SetQuantum (1500);
|
||||
queueDisc->Initialize ();
|
||||
|
||||
Ptr<Packet> p;
|
||||
p = Create<Packet> ();
|
||||
Ptr<Ipv6QueueDiscItem> item;
|
||||
Ipv6Header ipv6Header;
|
||||
Address dest;
|
||||
item = Create<Ipv6QueueDiscItem> (p, dest, 0, ipv6Header);
|
||||
queueDisc->Enqueue (item);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetNQueueDiscClasses (), 0, "no flow queue should have been created");
|
||||
|
||||
p = Create<Packet> (reinterpret_cast<const uint8_t*> ("hello, world"), 12);
|
||||
item = Create<Ipv6QueueDiscItem> (p, dest, 0, ipv6Header);
|
||||
queueDisc->Enqueue (item);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetNQueueDiscClasses (), 0, "no flow queue should have been created");
|
||||
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
/**
|
||||
* This class tests the IP flows separation and the packet limit
|
||||
*/
|
||||
class FqPieQueueDiscIPFlowsSeparationAndPacketLimit : public TestCase
|
||||
{
|
||||
public:
|
||||
FqPieQueueDiscIPFlowsSeparationAndPacketLimit ();
|
||||
virtual ~FqPieQueueDiscIPFlowsSeparationAndPacketLimit ();
|
||||
|
||||
private:
|
||||
virtual void DoRun (void);
|
||||
void AddPacket (Ptr<FqPieQueueDisc> queue, Ipv4Header hdr);
|
||||
};
|
||||
|
||||
FqPieQueueDiscIPFlowsSeparationAndPacketLimit::FqPieQueueDiscIPFlowsSeparationAndPacketLimit ()
|
||||
: TestCase ("Test IP flows separation and packet limit")
|
||||
{
|
||||
}
|
||||
|
||||
FqPieQueueDiscIPFlowsSeparationAndPacketLimit::~FqPieQueueDiscIPFlowsSeparationAndPacketLimit ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDiscIPFlowsSeparationAndPacketLimit::AddPacket (Ptr<FqPieQueueDisc> queue, Ipv4Header hdr)
|
||||
{
|
||||
Ptr<Packet> p = Create<Packet> (100);
|
||||
Address dest;
|
||||
Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, hdr);
|
||||
queue->Enqueue (item);
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDiscIPFlowsSeparationAndPacketLimit::DoRun (void)
|
||||
{
|
||||
Ptr<FqPieQueueDisc> queueDisc = CreateObjectWithAttributes<FqPieQueueDisc> ("MaxSize", StringValue ("4p"));
|
||||
|
||||
queueDisc->SetQuantum (1500);
|
||||
queueDisc->Initialize ();
|
||||
|
||||
Ipv4Header hdr;
|
||||
hdr.SetPayloadSize (100);
|
||||
hdr.SetSource (Ipv4Address ("10.10.1.1"));
|
||||
hdr.SetDestination (Ipv4Address ("10.10.1.2"));
|
||||
hdr.SetProtocol (7);
|
||||
|
||||
// Add three packets from the first flow
|
||||
AddPacket (queueDisc, hdr);
|
||||
AddPacket (queueDisc, hdr);
|
||||
AddPacket (queueDisc, hdr);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 3, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the flow queue");
|
||||
|
||||
// Add two packets from the second flow
|
||||
hdr.SetDestination (Ipv4Address ("10.10.1.7"));
|
||||
// Add the first packet
|
||||
AddPacket (queueDisc, hdr);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 4, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the flow queue");
|
||||
// Add the second packet that causes two packets to be dropped from the fat flow (max backlog = 300, threshold = 150)
|
||||
AddPacket (queueDisc, hdr);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 3, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the flow queue");
|
||||
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
/**
|
||||
* This class tests the deficit per flow
|
||||
*/
|
||||
class FqPieQueueDiscDeficit : public TestCase
|
||||
{
|
||||
public:
|
||||
FqPieQueueDiscDeficit ();
|
||||
virtual ~FqPieQueueDiscDeficit ();
|
||||
|
||||
private:
|
||||
virtual void DoRun (void);
|
||||
void AddPacket (Ptr<FqPieQueueDisc> queue, Ipv4Header hdr);
|
||||
};
|
||||
|
||||
FqPieQueueDiscDeficit::FqPieQueueDiscDeficit ()
|
||||
: TestCase ("Test credits and flows status")
|
||||
{
|
||||
}
|
||||
|
||||
FqPieQueueDiscDeficit::~FqPieQueueDiscDeficit ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDiscDeficit::AddPacket (Ptr<FqPieQueueDisc> queue, Ipv4Header hdr)
|
||||
{
|
||||
Ptr<Packet> p = Create<Packet> (100);
|
||||
Address dest;
|
||||
Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, hdr);
|
||||
queue->Enqueue (item);
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDiscDeficit::DoRun (void)
|
||||
{
|
||||
Ptr<FqPieQueueDisc> queueDisc = CreateObjectWithAttributes<FqPieQueueDisc> ();
|
||||
|
||||
queueDisc->SetQuantum (90);
|
||||
queueDisc->Initialize ();
|
||||
|
||||
Ipv4Header hdr;
|
||||
hdr.SetPayloadSize (100);
|
||||
hdr.SetSource (Ipv4Address ("10.10.1.1"));
|
||||
hdr.SetDestination (Ipv4Address ("10.10.1.2"));
|
||||
hdr.SetProtocol (7);
|
||||
|
||||
// Add a packet from the first flow
|
||||
AddPacket (queueDisc, hdr);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 1, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the first flow queue");
|
||||
Ptr<FqPieFlow> flow1 = StaticCast<FqPieFlow> (queueDisc->GetQueueDiscClass (0));
|
||||
NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), static_cast<int32_t> (queueDisc->GetQuantum ()), "the deficit of the first flow must equal the quantum");
|
||||
NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqPieFlow::NEW_FLOW, "the first flow must be in the list of new queues");
|
||||
// Dequeue a packet
|
||||
queueDisc->Dequeue ();
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 0, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 0, "unexpected number of packets in the first flow queue");
|
||||
// the deficit for the first flow becomes 90 - (100+20) = -30
|
||||
NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), -30, "unexpected deficit for the first flow");
|
||||
|
||||
// Add two packets from the first flow
|
||||
AddPacket (queueDisc, hdr);
|
||||
AddPacket (queueDisc, hdr);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 2, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the first flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqPieFlow::NEW_FLOW, "the first flow must still be in the list of new queues");
|
||||
|
||||
// Add two packets from the second flow
|
||||
hdr.SetDestination (Ipv4Address ("10.10.1.10"));
|
||||
AddPacket (queueDisc, hdr);
|
||||
AddPacket (queueDisc, hdr);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 4, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the first flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the second flow queue");
|
||||
Ptr<FqPieFlow> flow2 = StaticCast<FqPieFlow> (queueDisc->GetQueueDiscClass (1));
|
||||
NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), static_cast<int32_t> (queueDisc->GetQuantum ()), "the deficit of the second flow must equal the quantum");
|
||||
NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqPieFlow::NEW_FLOW, "the second flow must be in the list of new queues");
|
||||
|
||||
// Dequeue a packet (from the second flow, as the first flow has a negative deficit)
|
||||
queueDisc->Dequeue ();
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 3, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the first flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
|
||||
// the first flow got a quantum of deficit (-30+90=60) and has been moved to the end of the list of old queues
|
||||
NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), 60, "unexpected deficit for the first flow");
|
||||
NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqPieFlow::OLD_FLOW, "the first flow must be in the list of old queues");
|
||||
// the second flow has a negative deficit (-30) and is still in the list of new queues
|
||||
NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), -30, "unexpected deficit for the second flow");
|
||||
NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqPieFlow::NEW_FLOW, "the second flow must be in the list of new queues");
|
||||
|
||||
// Dequeue a packet (from the first flow, as the second flow has a negative deficit)
|
||||
queueDisc->Dequeue ();
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 2, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the first flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
|
||||
// the first flow has a negative deficit (60-(100+20)= -60) and stays in the list of old queues
|
||||
NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), -60, "unexpected deficit for the first flow");
|
||||
NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqPieFlow::OLD_FLOW, "the first flow must be in the list of old queues");
|
||||
// the second flow got a quantum of deficit (-30+90=60) and has been moved to the end of the list of old queues
|
||||
NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), 60, "unexpected deficit for the second flow");
|
||||
NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqPieFlow::OLD_FLOW, "the second flow must be in the list of new queues");
|
||||
|
||||
// Dequeue a packet (from the second flow, as the first flow has a negative deficit)
|
||||
queueDisc->Dequeue ();
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 1, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the first flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 0, "unexpected number of packets in the second flow queue");
|
||||
// the first flow got a quantum of deficit (-60+90=30) and has been moved to the end of the list of old queues
|
||||
NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), 30, "unexpected deficit for the first flow");
|
||||
NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqPieFlow::OLD_FLOW, "the first flow must be in the list of old queues");
|
||||
// the second flow has a negative deficit (60-(100+20)= -60)
|
||||
NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), -60, "unexpected deficit for the second flow");
|
||||
NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqPieFlow::OLD_FLOW, "the second flow must be in the list of new queues");
|
||||
|
||||
// Dequeue a packet (from the first flow, as the second flow has a negative deficit)
|
||||
queueDisc->Dequeue ();
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 0, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 0, "unexpected number of packets in the first flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 0, "unexpected number of packets in the second flow queue");
|
||||
// the first flow has a negative deficit (30-(100+20)= -90)
|
||||
NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), -90, "unexpected deficit for the first flow");
|
||||
NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqPieFlow::OLD_FLOW, "the first flow must be in the list of old queues");
|
||||
// the second flow got a quantum of deficit (-60+90=30) and has been moved to the end of the list of old queues
|
||||
NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), 30, "unexpected deficit for the second flow");
|
||||
NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqPieFlow::OLD_FLOW, "the second flow must be in the list of new queues");
|
||||
|
||||
// Dequeue a packet
|
||||
queueDisc->Dequeue ();
|
||||
// the first flow is at the head of the list of old queues but has a negative deficit, thus it gets a quantun
|
||||
// of deficit (-90+90=0) and is moved to the end of the list of old queues. Then, the second flow (which has a
|
||||
// positive deficit) is selected, but the second flow is empty and thus it is set to inactive. The first flow is
|
||||
// reconsidered, but it has a null deficit, hence it gets another quantum of deficit (0+90=90). Then, the first
|
||||
// flow is reconsidered again, now it has a positive deficit and hence it is selected. But, it is empty and
|
||||
// therefore is set to inactive, too.
|
||||
NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), 90, "unexpected deficit for the first flow");
|
||||
NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqPieFlow::INACTIVE, "the first flow must be inactive");
|
||||
NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), 30, "unexpected deficit for the second flow");
|
||||
NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqPieFlow::INACTIVE, "the second flow must be inactive");
|
||||
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
/**
|
||||
* This class tests the TCP flows separation
|
||||
*/
|
||||
class FqPieQueueDiscTCPFlowsSeparation : public TestCase
|
||||
{
|
||||
public:
|
||||
FqPieQueueDiscTCPFlowsSeparation ();
|
||||
virtual ~FqPieQueueDiscTCPFlowsSeparation ();
|
||||
|
||||
private:
|
||||
virtual void DoRun (void);
|
||||
void AddPacket (Ptr<FqPieQueueDisc> queue, Ipv4Header ipHdr, TcpHeader tcpHdr);
|
||||
};
|
||||
|
||||
FqPieQueueDiscTCPFlowsSeparation::FqPieQueueDiscTCPFlowsSeparation ()
|
||||
: TestCase ("Test TCP flows separation")
|
||||
{
|
||||
}
|
||||
|
||||
FqPieQueueDiscTCPFlowsSeparation::~FqPieQueueDiscTCPFlowsSeparation ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDiscTCPFlowsSeparation::AddPacket (Ptr<FqPieQueueDisc> queue, Ipv4Header ipHdr, TcpHeader tcpHdr)
|
||||
{
|
||||
Ptr<Packet> p = Create<Packet> (100);
|
||||
p->AddHeader (tcpHdr);
|
||||
Address dest;
|
||||
Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, ipHdr);
|
||||
queue->Enqueue (item);
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDiscTCPFlowsSeparation::DoRun (void)
|
||||
{
|
||||
Ptr<FqPieQueueDisc> queueDisc = CreateObjectWithAttributes<FqPieQueueDisc> ("MaxSize", StringValue ("10p"));
|
||||
|
||||
queueDisc->SetQuantum (1500);
|
||||
queueDisc->Initialize ();
|
||||
|
||||
Ipv4Header hdr;
|
||||
hdr.SetPayloadSize (100);
|
||||
hdr.SetSource (Ipv4Address ("10.10.1.1"));
|
||||
hdr.SetDestination (Ipv4Address ("10.10.1.2"));
|
||||
hdr.SetProtocol (6);
|
||||
|
||||
TcpHeader tcpHdr;
|
||||
tcpHdr.SetSourcePort (7);
|
||||
tcpHdr.SetDestinationPort (27);
|
||||
|
||||
// Add three packets from the first flow
|
||||
AddPacket (queueDisc, hdr, tcpHdr);
|
||||
AddPacket (queueDisc, hdr, tcpHdr);
|
||||
AddPacket (queueDisc, hdr, tcpHdr);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 3, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
|
||||
|
||||
// Add a packet from the second flow
|
||||
tcpHdr.SetSourcePort (8);
|
||||
AddPacket (queueDisc, hdr, tcpHdr);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 4, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
|
||||
|
||||
// Add a packet from the third flow
|
||||
tcpHdr.SetDestinationPort (28);
|
||||
AddPacket (queueDisc, hdr, tcpHdr);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 5, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the third flow queue");
|
||||
|
||||
// Add two packets from the fourth flow
|
||||
tcpHdr.SetSourcePort (7);
|
||||
AddPacket (queueDisc, hdr, tcpHdr);
|
||||
AddPacket (queueDisc, hdr, tcpHdr);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 7, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the third flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (3)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the third flow queue");
|
||||
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
/**
|
||||
* This class tests the UDP flows separation
|
||||
*/
|
||||
class FqPieQueueDiscUDPFlowsSeparation : public TestCase
|
||||
{
|
||||
public:
|
||||
FqPieQueueDiscUDPFlowsSeparation ();
|
||||
virtual ~FqPieQueueDiscUDPFlowsSeparation ();
|
||||
|
||||
private:
|
||||
virtual void DoRun (void);
|
||||
void AddPacket (Ptr<FqPieQueueDisc> queue, Ipv4Header ipHdr, UdpHeader udpHdr);
|
||||
};
|
||||
|
||||
FqPieQueueDiscUDPFlowsSeparation::FqPieQueueDiscUDPFlowsSeparation ()
|
||||
: TestCase ("Test UDP flows separation")
|
||||
{
|
||||
}
|
||||
|
||||
FqPieQueueDiscUDPFlowsSeparation::~FqPieQueueDiscUDPFlowsSeparation ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDiscUDPFlowsSeparation::AddPacket (Ptr<FqPieQueueDisc> queue, Ipv4Header ipHdr, UdpHeader udpHdr)
|
||||
{
|
||||
Ptr<Packet> p = Create<Packet> (100);
|
||||
p->AddHeader (udpHdr);
|
||||
Address dest;
|
||||
Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, ipHdr);
|
||||
queue->Enqueue (item);
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDiscUDPFlowsSeparation::DoRun (void)
|
||||
{
|
||||
Ptr<FqPieQueueDisc> queueDisc = CreateObjectWithAttributes<FqPieQueueDisc> ("MaxSize", StringValue ("10p"));
|
||||
|
||||
queueDisc->SetQuantum (1500);
|
||||
queueDisc->Initialize ();
|
||||
|
||||
Ipv4Header hdr;
|
||||
hdr.SetPayloadSize (100);
|
||||
hdr.SetSource (Ipv4Address ("10.10.1.1"));
|
||||
hdr.SetDestination (Ipv4Address ("10.10.1.2"));
|
||||
hdr.SetProtocol (17);
|
||||
|
||||
UdpHeader udpHdr;
|
||||
udpHdr.SetSourcePort (7);
|
||||
udpHdr.SetDestinationPort (27);
|
||||
|
||||
// Add three packets from the first flow
|
||||
AddPacket (queueDisc, hdr, udpHdr);
|
||||
AddPacket (queueDisc, hdr, udpHdr);
|
||||
AddPacket (queueDisc, hdr, udpHdr);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 3, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
|
||||
|
||||
// Add a packet from the second flow
|
||||
udpHdr.SetSourcePort (8);
|
||||
AddPacket (queueDisc, hdr, udpHdr);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 4, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
|
||||
|
||||
// Add a packet from the third flow
|
||||
udpHdr.SetDestinationPort (28);
|
||||
AddPacket (queueDisc, hdr, udpHdr);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 5, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the third flow queue");
|
||||
|
||||
// Add two packets from the fourth flow
|
||||
udpHdr.SetSourcePort (7);
|
||||
AddPacket (queueDisc, hdr, udpHdr);
|
||||
AddPacket (queueDisc, hdr, udpHdr);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 7, "unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the third flow queue");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (3)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the third flow queue");
|
||||
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This class tests linear probing, collision response, and set
|
||||
* creation capability of set associative hashing in FqPIE.
|
||||
* We modified DoClassify () and CheckProtocol () so that we could control
|
||||
* the hash returned for each packet. In the beginning, we use flow hashes
|
||||
* ranging from 0 to 7. These must go into different queues in the same set.
|
||||
* The set number for these is obtained using outerhash, which is 0.
|
||||
* When a new packet arrives with flow hash 1024, outerhash = 0 is obtained
|
||||
* and the first set is iteratively searched.
|
||||
* The packet is eventually added to queue 0 since the tags of queues
|
||||
* in the set do not match with the hash of the flow. The tag of queue 0 is
|
||||
* updated as 1024. When a packet with hash 1025 arrives, outerhash = 0
|
||||
* is obtained and the first set is iteratively searched.
|
||||
* Since there is no match, it is added to queue 0 and the tag of queue 0 is
|
||||
* updated to 1025.
|
||||
*
|
||||
* The variable outerhash stores the nearest multiple of 8 that is lesser than
|
||||
* the hash. When a flow hash of 20 arrives, the value of outerhash
|
||||
* is 16. Since m_flowIndices[16] wasn’t previously allotted, a new flow
|
||||
* is created, and the tag corresponding to this queue is set to 20.
|
||||
*/
|
||||
|
||||
class FqPieQueueDiscSetLinearProbing : public TestCase
|
||||
{
|
||||
public:
|
||||
FqPieQueueDiscSetLinearProbing ();
|
||||
virtual ~FqPieQueueDiscSetLinearProbing ();
|
||||
private:
|
||||
virtual void DoRun (void);
|
||||
void AddPacket (Ptr<FqPieQueueDisc> queue, Ipv4Header hdr);
|
||||
};
|
||||
|
||||
FqPieQueueDiscSetLinearProbing::FqPieQueueDiscSetLinearProbing ()
|
||||
: TestCase ("Test credits and flows status")
|
||||
{
|
||||
}
|
||||
|
||||
FqPieQueueDiscSetLinearProbing::~FqPieQueueDiscSetLinearProbing ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDiscSetLinearProbing::AddPacket (Ptr<FqPieQueueDisc> queue, Ipv4Header hdr)
|
||||
{
|
||||
Ptr<Packet> p = Create<Packet> (100);
|
||||
Address dest;
|
||||
Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, hdr);
|
||||
queue->Enqueue (item);
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDiscSetLinearProbing::DoRun (void)
|
||||
{
|
||||
Ptr<FqPieQueueDisc> queueDisc = CreateObjectWithAttributes<FqPieQueueDisc> ("EnableSetAssociativeHash", BooleanValue (true));
|
||||
queueDisc->SetQuantum (90);
|
||||
queueDisc->Initialize ();
|
||||
|
||||
Ptr<Ipv4FqPieTestPacketFilter> filter = CreateObject<Ipv4FqPieTestPacketFilter> ();
|
||||
queueDisc->AddPacketFilter (filter);
|
||||
|
||||
Ipv4Header hdr;
|
||||
hdr.SetPayloadSize (100);
|
||||
hdr.SetSource (Ipv4Address ("10.10.1.1"));
|
||||
hdr.SetDestination (Ipv4Address ("10.10.1.2"));
|
||||
hdr.SetProtocol (7);
|
||||
|
||||
g_hash = 0;
|
||||
AddPacket (queueDisc, hdr);
|
||||
g_hash = 1;
|
||||
AddPacket (queueDisc, hdr);
|
||||
AddPacket (queueDisc, hdr);
|
||||
g_hash = 2;
|
||||
AddPacket (queueDisc, hdr);
|
||||
g_hash = 3;
|
||||
AddPacket (queueDisc, hdr);
|
||||
g_hash = 4;
|
||||
AddPacket (queueDisc, hdr);
|
||||
AddPacket (queueDisc, hdr);
|
||||
g_hash = 5;
|
||||
AddPacket (queueDisc, hdr);
|
||||
g_hash = 6;
|
||||
AddPacket (queueDisc, hdr);
|
||||
g_hash = 7;
|
||||
AddPacket (queueDisc, hdr);
|
||||
g_hash = 1024;
|
||||
AddPacket (queueDisc, hdr);
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 11,
|
||||
"unexpected number of packets in the queue disc");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 2,
|
||||
"unexpected number of packets in the first flow queue of set one");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 2,
|
||||
"unexpected number of packets in the second flow queue of set one");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetNPackets (), 1,
|
||||
"unexpected number of packets in the third flow queue of set one");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (3)->GetQueueDisc ()->GetNPackets (), 1,
|
||||
"unexpected number of packets in the fourth flow queue of set one");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (4)->GetQueueDisc ()->GetNPackets (), 2,
|
||||
"unexpected number of packets in the fifth flow queue of set one");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (5)->GetQueueDisc ()->GetNPackets (), 1,
|
||||
"unexpected number of packets in the sixth flow queue of set one");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (6)->GetQueueDisc ()->GetNPackets (), 1,
|
||||
"unexpected number of packets in the seventh flow queue of set one");
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (7)->GetQueueDisc ()->GetNPackets (), 1,
|
||||
"unexpected number of packets in the eighth flow queue of set one");
|
||||
g_hash = 1025;
|
||||
AddPacket (queueDisc, hdr);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3,
|
||||
"unexpected number of packets in the first flow of set one");
|
||||
g_hash = 10;
|
||||
AddPacket (queueDisc, hdr);
|
||||
NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (8)->GetQueueDisc ()->GetNPackets (), 1,
|
||||
"unexpected number of packets in the first flow of set two");
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This class tests L4S mode. This test is divided to sub test one without hash collisions and so ECT0 and ECT1 flows are
|
||||
* classified into different flows.
|
||||
* Sub Test 1
|
||||
* 70 packets are enqueued into both the flows with the delay of 0.5ms between two enqueues, and dequeued with the delay of
|
||||
* 1ms between two dequeues.
|
||||
* Sub Test 2
|
||||
* 140(70 ECT0 + 70 ECT1) packets are enqueued such that ECT1 packets are enqueued at 0.5ms, 1.5ms, 2.5ms and so on, and ECT0 packets are
|
||||
* enqueued are enqueued at 1ms, 2ms, 3ms and so on
|
||||
* Any future classifier options (e.g. SetAssociativehash) should be disabled to prevent a hash collision on this test case.
|
||||
*/
|
||||
class FqPieQueueDiscL4sMode : public TestCase
|
||||
{
|
||||
public:
|
||||
FqPieQueueDiscL4sMode ();
|
||||
virtual ~FqPieQueueDiscL4sMode ();
|
||||
|
||||
private:
|
||||
virtual void DoRun (void);
|
||||
void AddPacket (Ptr<FqPieQueueDisc> queue, Ipv4Header hdr, u_int32_t nPkt);
|
||||
void AddPacketWithDelay (Ptr<FqPieQueueDisc> queue,Ipv4Header hdr, double delay, uint32_t nPkt);
|
||||
void Dequeue (Ptr<FqPieQueueDisc> queue, uint32_t nPkt);
|
||||
void DequeueWithDelay (Ptr<FqPieQueueDisc> queue, double delay, uint32_t nPkt);
|
||||
};
|
||||
|
||||
FqPieQueueDiscL4sMode::FqPieQueueDiscL4sMode ()
|
||||
: TestCase ("Test L4S mode")
|
||||
{
|
||||
}
|
||||
|
||||
FqPieQueueDiscL4sMode::~FqPieQueueDiscL4sMode ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDiscL4sMode::AddPacket (Ptr<FqPieQueueDisc> queue, Ipv4Header hdr, uint32_t nPkt)
|
||||
{
|
||||
Address dest;
|
||||
Ptr<Packet> p = Create<Packet> (100);
|
||||
for (uint32_t i = 0; i < nPkt; i++)
|
||||
{
|
||||
Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, hdr);
|
||||
queue->Enqueue (item);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDiscL4sMode::AddPacketWithDelay (Ptr<FqPieQueueDisc> queue,Ipv4Header hdr, double delay, uint32_t nPkt)
|
||||
{
|
||||
for (uint32_t i = 0; i < nPkt; i++)
|
||||
{
|
||||
Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &FqPieQueueDiscL4sMode::AddPacket, this, queue, hdr, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDiscL4sMode::Dequeue (Ptr<FqPieQueueDisc> queue, uint32_t nPkt)
|
||||
{
|
||||
for (uint32_t i = 0; i < nPkt; i++)
|
||||
{
|
||||
Ptr<QueueDiscItem> item = queue->Dequeue ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDiscL4sMode::DequeueWithDelay (Ptr<FqPieQueueDisc> queue, double delay, uint32_t nPkt)
|
||||
{
|
||||
for (uint32_t i = 0; i < nPkt; i++)
|
||||
{
|
||||
Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &FqPieQueueDiscL4sMode::Dequeue, this, queue, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDiscL4sMode::DoRun (void)
|
||||
{
|
||||
// Test is divided into 2 sub test cases:
|
||||
// 1) Without hash collisions
|
||||
// 2) With hash collisions
|
||||
|
||||
// Test case 1, Without hash collisions
|
||||
Ptr<FqPieQueueDisc> queueDisc = CreateObjectWithAttributes<FqPieQueueDisc> ("MaxSize", StringValue ("10240p"), "UseEcn", BooleanValue (true),
|
||||
"Perturbation", UintegerValue (0), "UseL4s", BooleanValue (true),
|
||||
"CeThreshold", TimeValue (MilliSeconds (2)));
|
||||
|
||||
queueDisc->SetQuantum (1514);
|
||||
queueDisc->Initialize ();
|
||||
Ipv4Header hdr;
|
||||
hdr.SetPayloadSize (100);
|
||||
hdr.SetSource (Ipv4Address ("10.10.1.1"));
|
||||
hdr.SetDestination (Ipv4Address ("10.10.1.2"));
|
||||
hdr.SetProtocol (7);
|
||||
hdr.SetEcn (Ipv4Header::ECN_ECT1);
|
||||
|
||||
// Add 70 ECT1 (ECN capable) packets from the first flow
|
||||
// Set delay = 0.5ms
|
||||
double delay = 0.0005;
|
||||
Simulator::Schedule (Time (Seconds (0)), &FqPieQueueDiscL4sMode::AddPacketWithDelay, this, queueDisc, hdr, delay, 70);
|
||||
|
||||
// Add 70 ECT0 (ECN capable) packets from second flow
|
||||
hdr.SetEcn (Ipv4Header::ECN_ECT0);
|
||||
hdr.SetDestination (Ipv4Address ("10.10.1.10"));
|
||||
Simulator::Schedule (Time (Seconds (0)), &FqPieQueueDiscL4sMode::AddPacketWithDelay, this, queueDisc, hdr, delay, 70);
|
||||
|
||||
//Dequeue 140 packets with delay 1ms
|
||||
delay = 0.001;
|
||||
DequeueWithDelay (queueDisc, delay, 140);
|
||||
Simulator::Stop (Seconds (10.0));
|
||||
Simulator::Run ();
|
||||
|
||||
Ptr<PieQueueDisc> q0 = queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetObject <PieQueueDisc> ();
|
||||
Ptr<PieQueueDisc> q1 = queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetObject <PieQueueDisc> ();
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (PieQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 66, "There should be 66 marked packets"
|
||||
"4th packet is enqueued at 2ms and dequeued at 4ms hence the delay of 2ms which not greater than CE threshold"
|
||||
"5th packet is enqueued at 2.5ms and dequeued at 5ms hence the delay of 2.5ms and subsequent packet also do have delay"
|
||||
"greater than CE threshold so all the packets after 4th packet are marked");
|
||||
NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNDroppedPackets (PieQueueDisc::UNFORCED_DROP), 0, "Queue delay is less than max burst allowance so"
|
||||
"There should not be any dropped packets");
|
||||
NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (PieQueueDisc::UNFORCED_MARK), 0, "There should not be any marked packets");
|
||||
NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNMarkedPackets (PieQueueDisc::UNFORCED_MARK), 0, "There should not be marked packets.");
|
||||
NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNDroppedPackets (PieQueueDisc::UNFORCED_DROP), 0, "There should not be any dropped packets");
|
||||
|
||||
Simulator::Destroy ();
|
||||
|
||||
// Test case 2, With hash collisions
|
||||
queueDisc = CreateObjectWithAttributes<FqPieQueueDisc> ("MaxSize", StringValue ("10240p"), "UseEcn", BooleanValue (true),
|
||||
"Perturbation", UintegerValue (0), "UseL4s", BooleanValue (true),
|
||||
"CeThreshold", TimeValue (MilliSeconds (2)));
|
||||
|
||||
queueDisc->SetQuantum (1514);
|
||||
queueDisc->Initialize ();
|
||||
hdr.SetPayloadSize (100);
|
||||
hdr.SetSource (Ipv4Address ("10.10.1.1"));
|
||||
hdr.SetDestination (Ipv4Address ("10.10.1.2"));
|
||||
hdr.SetProtocol (7);
|
||||
hdr.SetEcn (Ipv4Header::ECN_ECT1);
|
||||
|
||||
// Add 70 ECT1 (ECN capable) packets from the first flow
|
||||
// Set delay = 1ms
|
||||
delay = 0.001;
|
||||
Simulator::Schedule (Time (Seconds (0.0005)), &FqPieQueueDiscL4sMode::AddPacket, this, queueDisc, hdr, 1);
|
||||
Simulator::Schedule (Time (Seconds (0.0005)), &FqPieQueueDiscL4sMode::AddPacketWithDelay, this, queueDisc, hdr, delay, 69);
|
||||
|
||||
// Add 70 ECT0 (ECN capable) packets from first flow
|
||||
hdr.SetEcn (Ipv4Header::ECN_ECT0);
|
||||
Simulator::Schedule (Time (Seconds (0)), &FqPieQueueDiscL4sMode::AddPacketWithDelay, this, queueDisc, hdr, delay, 70);
|
||||
|
||||
//Dequeue 140 packets with delay 1ms
|
||||
DequeueWithDelay (queueDisc, delay, 140);
|
||||
Simulator::Stop (Seconds (1.0));
|
||||
Simulator::Run ();
|
||||
q0 = queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetObject <PieQueueDisc> ();
|
||||
q0 = queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetObject <PieQueueDisc> ();
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (PieQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 68, "There should be 68 marked packets"
|
||||
"2nd ECT1 packet is enqueued at 1.5ms and dequeued at 3ms hence the delay of 1.5ms which not greater than CE threshold"
|
||||
"3rd packet is enqueued at 2.5ms and dequeued at 5ms hence the delay of 2.5ms and subsequent packet also do have delay"
|
||||
"greater than CE threshold so all the packets after 2nd packet are marked");
|
||||
NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNDroppedPackets (PieQueueDisc::UNFORCED_DROP), 0, "Queue delay is less than max burst allowance so"
|
||||
"There should not be any dropped packets");
|
||||
NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (PieQueueDisc::UNFORCED_MARK), 0, "There should not be any marked packets");
|
||||
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
class FqPieQueueDiscTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
FqPieQueueDiscTestSuite ();
|
||||
};
|
||||
|
||||
FqPieQueueDiscTestSuite::FqPieQueueDiscTestSuite ()
|
||||
: TestSuite ("fq-pie-queue-disc", UNIT)
|
||||
{
|
||||
AddTestCase (new FqPieQueueDiscNoSuitableFilter, TestCase::QUICK);
|
||||
AddTestCase (new FqPieQueueDiscIPFlowsSeparationAndPacketLimit, TestCase::QUICK);
|
||||
AddTestCase (new FqPieQueueDiscDeficit, TestCase::QUICK);
|
||||
AddTestCase (new FqPieQueueDiscTCPFlowsSeparation, TestCase::QUICK);
|
||||
AddTestCase (new FqPieQueueDiscUDPFlowsSeparation, TestCase::QUICK);
|
||||
AddTestCase (new FqPieQueueDiscSetLinearProbing, TestCase::QUICK);
|
||||
AddTestCase (new FqPieQueueDiscL4sMode, TestCase::QUICK);
|
||||
}
|
||||
|
||||
static FqPieQueueDiscTestSuite FqPieQueueDiscTestSuite;
|
||||
@@ -32,6 +32,7 @@ def build(bld):
|
||||
'csma-system-test-suite.cc',
|
||||
'ns3tc/fq-codel-queue-disc-test-suite.cc',
|
||||
'ns3tc/fq-cobalt-queue-disc-test-suite.cc',
|
||||
'ns3tc/fq-pie-queue-disc-test-suite.cc',
|
||||
'ns3tc/pfifo-fast-queue-disc-test-suite.cc',
|
||||
'ns3tcp/ns3tcp-cwnd-test-suite.cc',
|
||||
'ns3tcp/ns3tcp-interop-test-suite.cc',
|
||||
|
||||
83
src/traffic-control/doc/fq-pie.rst
Normal file
83
src/traffic-control/doc/fq-pie.rst
Normal file
@@ -0,0 +1,83 @@
|
||||
.. include:: replace.txt
|
||||
.. highlight:: cpp
|
||||
.. highlight:: bash
|
||||
|
||||
FqPIE queue disc
|
||||
------------------
|
||||
|
||||
This chapter describes the FqPIE ([Hoe16]_) queue disc implementation in |ns3|.
|
||||
|
||||
The FlowQueue-PIE (FQ-PIE) algorithm is similar to the FlowQueue part of FlowQueue-CoDel (FQ-CoDel) algorithm available in ns-3-dev/src/traffic-control/doc/fq-codel.rst.
|
||||
The documentation for PIE is available in ns-3-dev/src/traffic-control/doc/pie.rst.
|
||||
|
||||
|
||||
Model Description
|
||||
*****************
|
||||
|
||||
The source code for the FqPIE queue disc is located in the directory
|
||||
``src/traffic-control/model`` and consists of 2 files `fq-pie-queue-disc.h`
|
||||
and `fq-pie-queue-disc.cc` defining a FqPieQueueDisc class and a helper
|
||||
FqPieFlow class. The code was ported to |ns3| based on Linux kernel code
|
||||
implemented by Mohit P. Tahiliani.
|
||||
|
||||
The Model Description is similar to the FqCoDel documentation mentioned above.
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [CAK16] https://github.com/torvalds/linux/blob/master/net/sched/sch_fq_pie.c , Implementation of FqPIE in Linux
|
||||
.. [PIE] https://ieeexplore.ieee.org/document/9000684
|
||||
|
||||
Attributes
|
||||
==========
|
||||
|
||||
The key attributes that the FqPieQueue class holds include the following:
|
||||
|
||||
Most of the key attributes are similar to the FqCoDel implementation mentioned above.
|
||||
Some differences are:
|
||||
Absence of ``MinBytes``, ``Interval`` and ``Target`` parameter.
|
||||
Some extra parameters are
|
||||
* ``MarkEcnThreshold:`` ECN marking threshold (RFC 8033 suggests 0.1 (i.e., 10%) default).
|
||||
* ``MeanPktSize:`` Average of packet size.
|
||||
* ``A:`` Decrement value of drop probability. Default value is 1./4096 .
|
||||
* ``B:`` The Threshold after which Blue is enabled. Default value is 400ms.
|
||||
* ``Tupdate:`` Time period to calculate drop probability
|
||||
* ``Supdate:`` Start time of the update timer
|
||||
* ``DequeueThreshold:`` Minimum queue size in bytes before dequeue rate is measured
|
||||
* ``QueueDelayReference:`` Desired queue delay
|
||||
* ``MaxBurstAllowance:`` Current max burst allowance before random drop
|
||||
* ``UseDequeueRateEstimator:`` Enable/Disable usage of Dequeue Rate Estimator
|
||||
* ``UseCapDropAdjustment:`` Enable/Disable Cap Drop Adjustment feature mentioned in RFC 8033
|
||||
* ``UseDerandomization:`` Enable/Disable Derandomization feature mentioned in RFC 8033
|
||||
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
A typical usage pattern is to create a traffic control helper and to configure type
|
||||
and attributes of queue disc and filters from the helper. For example, FqPIE
|
||||
can be configured as follows:
|
||||
|
||||
.. sourcecode:: cpp
|
||||
|
||||
TrafficControlHelper tch;
|
||||
tch.SetRootQueueDisc ("ns3::FqPieQueueDisc", "DropBatchSize", UintegerValue (1)
|
||||
"Perturbation", UintegerValue (256));
|
||||
QueueDiscContainer qdiscs = tch.Install (devices);
|
||||
|
||||
Validation
|
||||
**********
|
||||
|
||||
The FqPie model is tested using :cpp:class:`FqPieQueueDiscTestSuite` class defined in `src/test/ns3tc/fq-pie-queue-test-suite.cc`.
|
||||
|
||||
The tests are similar to the ones for FqCoDel queue disc mentioned in first section of this document.
|
||||
The test suite can be run using the following commands::
|
||||
|
||||
$ ./waf configure --enable-examples --enable-tests
|
||||
$ ./waf build
|
||||
$ ./test.py -s fq-pie-queue-disc
|
||||
|
||||
or::
|
||||
|
||||
$ NS_LOG="FqPieQueueDisc" ./waf --run "test-runner --suite=fq-pie-queue-disc"
|
||||
561
src/traffic-control/model/fq-pie-queue-disc.cc
Executable file
561
src/traffic-control/model/fq-pie-queue-disc.cc
Executable file
@@ -0,0 +1,561 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2018 NITK Surathkal
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Authors: Sumukha PK <sumukhapk46@gmail.com>
|
||||
* Prajval M <26prajval98@gmail.com>
|
||||
* Ishaan R D <ishaanrd6@gmail.com>
|
||||
* Mohit P. Tahiliani <tahiliani@nitk.edu.in>
|
||||
*/
|
||||
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/string.h"
|
||||
#include "ns3/queue.h"
|
||||
#include "fq-pie-queue-disc.h"
|
||||
#include "pie-queue-disc.h"
|
||||
#include "ns3/net-device-queue-interface.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("FqPieQueueDisc");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (FqPieFlow);
|
||||
|
||||
TypeId FqPieFlow::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::FqPieFlow")
|
||||
.SetParent<QueueDiscClass> ()
|
||||
.SetGroupName ("TrafficControl")
|
||||
.AddConstructor<FqPieFlow> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
FqPieFlow::FqPieFlow ()
|
||||
: m_deficit (0),
|
||||
m_status (INACTIVE),
|
||||
m_index (0)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
FqPieFlow::~FqPieFlow ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
void
|
||||
FqPieFlow::SetDeficit (uint32_t deficit)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << deficit);
|
||||
m_deficit = deficit;
|
||||
}
|
||||
|
||||
int32_t
|
||||
FqPieFlow::GetDeficit (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_deficit;
|
||||
}
|
||||
|
||||
void
|
||||
FqPieFlow::IncreaseDeficit (int32_t deficit)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << deficit);
|
||||
m_deficit += deficit;
|
||||
}
|
||||
|
||||
void
|
||||
FqPieFlow::SetStatus (FlowStatus status)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_status = status;
|
||||
}
|
||||
|
||||
FqPieFlow::FlowStatus
|
||||
FqPieFlow::GetStatus (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_status;
|
||||
}
|
||||
|
||||
void
|
||||
FqPieFlow::SetIndex (uint32_t index)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_index = index;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
FqPieFlow::GetIndex (void) const
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (FqPieQueueDisc);
|
||||
|
||||
TypeId FqPieQueueDisc::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::FqPieQueueDisc")
|
||||
.SetParent<QueueDisc> ()
|
||||
.SetGroupName ("TrafficControl")
|
||||
.AddConstructor<FqPieQueueDisc> ()
|
||||
.AddAttribute ("UseEcn",
|
||||
"True to use ECN (packets are marked instead of being dropped)",
|
||||
BooleanValue (true),
|
||||
MakeBooleanAccessor (&FqPieQueueDisc::m_useEcn),
|
||||
MakeBooleanChecker ())
|
||||
.AddAttribute ("MarkEcnThreshold",
|
||||
"ECN marking threshold (RFC 8033 suggests 0.1 (i.e., 10%) default)",
|
||||
DoubleValue (0.1),
|
||||
MakeDoubleAccessor (&FqPieQueueDisc::m_markEcnTh),
|
||||
MakeDoubleChecker<double> (0, 1))
|
||||
.AddAttribute ("CeThreshold",
|
||||
"The FqPie CE threshold for marking packets",
|
||||
TimeValue (Time::Max ()),
|
||||
MakeTimeAccessor (&FqPieQueueDisc::m_ceThreshold),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("UseL4s",
|
||||
"True to use L4S (only ECT1 packets are marked at CE threshold)",
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&FqPieQueueDisc::m_useL4s),
|
||||
MakeBooleanChecker ())
|
||||
.AddAttribute ("MeanPktSize",
|
||||
"Average of packet size",
|
||||
UintegerValue (1000),
|
||||
MakeUintegerAccessor (&FqPieQueueDisc::m_meanPktSize),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("A",
|
||||
"Value of alpha",
|
||||
DoubleValue (0.125),
|
||||
MakeDoubleAccessor (&FqPieQueueDisc::m_a),
|
||||
MakeDoubleChecker<double> ())
|
||||
.AddAttribute ("B",
|
||||
"Value of beta",
|
||||
DoubleValue (1.25),
|
||||
MakeDoubleAccessor (&FqPieQueueDisc::m_b),
|
||||
MakeDoubleChecker<double> ())
|
||||
.AddAttribute ("Tupdate",
|
||||
"Time period to calculate drop probability",
|
||||
TimeValue (Seconds (0.015)),
|
||||
MakeTimeAccessor (&FqPieQueueDisc::m_tUpdate),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("Supdate",
|
||||
"Start time of the update timer",
|
||||
TimeValue (Seconds (0)),
|
||||
MakeTimeAccessor (&FqPieQueueDisc::m_sUpdate),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("MaxSize",
|
||||
"The maximum number of packets accepted by this queue disc",
|
||||
QueueSizeValue (QueueSize ("10240p")),
|
||||
MakeQueueSizeAccessor (&QueueDisc::SetMaxSize,
|
||||
&QueueDisc::GetMaxSize),
|
||||
MakeQueueSizeChecker ())
|
||||
.AddAttribute ("DequeueThreshold",
|
||||
"Minimum queue size in bytes before dequeue rate is measured",
|
||||
UintegerValue (16384),
|
||||
MakeUintegerAccessor (&FqPieQueueDisc::m_dqThreshold),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("QueueDelayReference",
|
||||
"Desired queue delay",
|
||||
TimeValue (Seconds (0.015)),
|
||||
MakeTimeAccessor (&FqPieQueueDisc::m_qDelayRef),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("MaxBurstAllowance",
|
||||
"Current max burst allowance before random drop",
|
||||
TimeValue (Seconds (0.15)),
|
||||
MakeTimeAccessor (&FqPieQueueDisc::m_maxBurst),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("UseDequeueRateEstimator",
|
||||
"Enable/Disable usage of Dequeue Rate Estimator",
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&FqPieQueueDisc::m_useDqRateEstimator),
|
||||
MakeBooleanChecker ())
|
||||
.AddAttribute ("UseCapDropAdjustment",
|
||||
"Enable/Disable Cap Drop Adjustment feature mentioned in RFC 8033",
|
||||
BooleanValue (true),
|
||||
MakeBooleanAccessor (&FqPieQueueDisc::m_isCapDropAdjustment),
|
||||
MakeBooleanChecker ())
|
||||
.AddAttribute ("UseDerandomization",
|
||||
"Enable/Disable Derandomization feature mentioned in RFC 8033",
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&FqPieQueueDisc::m_useDerandomization),
|
||||
MakeBooleanChecker ())
|
||||
.AddAttribute ("Flows",
|
||||
"The number of queues into which the incoming packets are classified",
|
||||
UintegerValue (1024),
|
||||
MakeUintegerAccessor (&FqPieQueueDisc::m_flows),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("DropBatchSize",
|
||||
"The maximum number of packets dropped from the fat flow",
|
||||
UintegerValue (64),
|
||||
MakeUintegerAccessor (&FqPieQueueDisc::m_dropBatchSize),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("Perturbation",
|
||||
"The salt used as an additional input to the hash function used to classify packets",
|
||||
UintegerValue (0),
|
||||
MakeUintegerAccessor (&FqPieQueueDisc::m_perturbation),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("EnableSetAssociativeHash",
|
||||
"Enable/Disable Set Associative Hash",
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&FqPieQueueDisc::m_enableSetAssociativeHash),
|
||||
MakeBooleanChecker ())
|
||||
.AddAttribute ("SetWays",
|
||||
"The size of a set of queues (used by set associative hash)",
|
||||
UintegerValue (8),
|
||||
MakeUintegerAccessor (&FqPieQueueDisc::m_setWays),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
FqPieQueueDisc::FqPieQueueDisc ()
|
||||
: QueueDisc (QueueDiscSizePolicy::MULTIPLE_QUEUES, QueueSizeUnit::PACKETS),
|
||||
m_quantum (0)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
FqPieQueueDisc::~FqPieQueueDisc ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDisc::SetQuantum (uint32_t quantum)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << quantum);
|
||||
m_quantum = quantum;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
FqPieQueueDisc::GetQuantum (void) const
|
||||
{
|
||||
return m_quantum;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
FqPieQueueDisc::SetAssociativeHash (uint32_t flowHash)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << flowHash);
|
||||
|
||||
uint32_t h = (flowHash % m_flows);
|
||||
uint32_t innerHash = h % m_setWays;
|
||||
uint32_t outerHash = h - innerHash;
|
||||
|
||||
for (uint32_t i = outerHash; i < outerHash + m_setWays; i++)
|
||||
{
|
||||
auto it = m_flowsIndices.find (i);
|
||||
|
||||
if (it == m_flowsIndices.end ()
|
||||
|| (m_tags.find (i) != m_tags.end () && m_tags[i] == flowHash)
|
||||
|| StaticCast<FqPieFlow> (GetQueueDiscClass (it->second))->GetStatus () == FqPieFlow::INACTIVE)
|
||||
{
|
||||
// this queue has not been created yet or is associated with this flow
|
||||
// or is inactive, hence we can use it
|
||||
m_tags[i] = flowHash;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// all the queues of the set are used. Use the first queue of the set
|
||||
m_tags[outerHash] = flowHash;
|
||||
return outerHash;
|
||||
}
|
||||
|
||||
bool
|
||||
FqPieQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << item);
|
||||
|
||||
uint32_t flowHash, h;
|
||||
|
||||
if (GetNPacketFilters () == 0)
|
||||
{
|
||||
flowHash = item->Hash (m_perturbation);
|
||||
}
|
||||
else
|
||||
{
|
||||
int32_t ret = Classify (item);
|
||||
|
||||
if (ret != PacketFilter::PF_NO_MATCH)
|
||||
{
|
||||
flowHash = static_cast<uint32_t> (ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_ERROR ("No filter has been able to classify this packet, drop it.");
|
||||
DropBeforeEnqueue (item, UNCLASSIFIED_DROP);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_enableSetAssociativeHash)
|
||||
{
|
||||
h = SetAssociativeHash (flowHash);
|
||||
}
|
||||
else
|
||||
{
|
||||
h = flowHash % m_flows;
|
||||
}
|
||||
|
||||
Ptr<FqPieFlow> flow;
|
||||
if (m_flowsIndices.find (h) == m_flowsIndices.end ())
|
||||
{
|
||||
NS_LOG_DEBUG ("Creating a new flow queue with index " << h);
|
||||
flow = m_flowFactory.Create<FqPieFlow> ();
|
||||
Ptr<QueueDisc> qd = m_queueDiscFactory.Create<QueueDisc> ();
|
||||
// If Pie, Set values of PieQueueDisc to match this QueueDisc
|
||||
Ptr<PieQueueDisc> pie = qd->GetObject<PieQueueDisc> ();
|
||||
if (pie)
|
||||
{
|
||||
pie->SetAttribute ("UseEcn", BooleanValue (m_useEcn));
|
||||
pie->SetAttribute ("CeThreshold", TimeValue (m_ceThreshold));
|
||||
pie->SetAttribute ("UseL4s", BooleanValue (m_useL4s));
|
||||
}
|
||||
qd->Initialize ();
|
||||
flow->SetQueueDisc (qd);
|
||||
flow->SetIndex (h);
|
||||
AddQueueDiscClass (flow);
|
||||
|
||||
m_flowsIndices[h] = GetNQueueDiscClasses () - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
flow = StaticCast<FqPieFlow> (GetQueueDiscClass (m_flowsIndices[h]));
|
||||
}
|
||||
|
||||
if (flow->GetStatus () == FqPieFlow::INACTIVE)
|
||||
{
|
||||
flow->SetStatus (FqPieFlow::NEW_FLOW);
|
||||
flow->SetDeficit (m_quantum);
|
||||
m_newFlows.push_back (flow);
|
||||
}
|
||||
|
||||
flow->GetQueueDisc ()->Enqueue (item);
|
||||
|
||||
NS_LOG_DEBUG ("Packet enqueued into flow " << h << "; flow index " << m_flowsIndices[h]);
|
||||
|
||||
if (GetCurrentSize () > GetMaxSize ())
|
||||
{
|
||||
NS_LOG_DEBUG ("Overload; enter FqPieDrop ()");
|
||||
FqPieDrop ();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Ptr<QueueDiscItem>
|
||||
FqPieQueueDisc::DoDequeue (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
Ptr<FqPieFlow> flow;
|
||||
Ptr<QueueDiscItem> item;
|
||||
|
||||
do
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
while (!found && !m_newFlows.empty ())
|
||||
{
|
||||
flow = m_newFlows.front ();
|
||||
|
||||
if (flow->GetDeficit () <= 0)
|
||||
{
|
||||
NS_LOG_DEBUG ("Increase deficit for new flow index " << flow->GetIndex ());
|
||||
flow->IncreaseDeficit (m_quantum);
|
||||
flow->SetStatus (FqPieFlow::OLD_FLOW);
|
||||
m_oldFlows.push_back (flow);
|
||||
m_newFlows.pop_front ();
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_DEBUG ("Found a new flow " << flow->GetIndex () << " with positive deficit");
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
while (!found && !m_oldFlows.empty ())
|
||||
{
|
||||
flow = m_oldFlows.front ();
|
||||
|
||||
if (flow->GetDeficit () <= 0)
|
||||
{
|
||||
NS_LOG_DEBUG ("Increase deficit for old flow index " << flow->GetIndex ());
|
||||
flow->IncreaseDeficit (m_quantum);
|
||||
m_oldFlows.push_back (flow);
|
||||
m_oldFlows.pop_front ();
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_DEBUG ("Found an old flow " << flow->GetIndex () << " with positive deficit");
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
NS_LOG_DEBUG ("No flow found to dequeue a packet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
item = flow->GetQueueDisc ()->Dequeue ();
|
||||
|
||||
if (!item)
|
||||
{
|
||||
NS_LOG_DEBUG ("Could not get a packet from the selected flow queue");
|
||||
if (!m_newFlows.empty ())
|
||||
{
|
||||
flow->SetStatus (FqPieFlow::OLD_FLOW);
|
||||
m_oldFlows.push_back (flow);
|
||||
m_newFlows.pop_front ();
|
||||
}
|
||||
else
|
||||
{
|
||||
flow->SetStatus (FqPieFlow::INACTIVE);
|
||||
m_oldFlows.pop_front ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_DEBUG ("Dequeued packet " << item->GetPacket ());
|
||||
}
|
||||
} while (item == 0);
|
||||
|
||||
flow->IncreaseDeficit (item->GetSize () * -1);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
bool
|
||||
FqPieQueueDisc::CheckConfig (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
if (GetNQueueDiscClasses () > 0)
|
||||
{
|
||||
NS_LOG_ERROR ("FqPieQueueDisc cannot have classes");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetNInternalQueues () > 0)
|
||||
{
|
||||
NS_LOG_ERROR ("FqPieQueueDisc cannot have internal queues");
|
||||
return false;
|
||||
}
|
||||
// we are at initialization time. If the user has not set a quantum value,
|
||||
// set the quantum to the MTU of the device (if any)
|
||||
if (!m_quantum)
|
||||
{
|
||||
Ptr<NetDeviceQueueInterface> ndqi = GetNetDeviceQueueInterface ();
|
||||
Ptr<NetDevice> dev;
|
||||
// if the NetDeviceQueueInterface object is aggregated to a
|
||||
// NetDevice, get the MTU of such NetDevice
|
||||
if (ndqi && (dev = ndqi->GetObject<NetDevice> ()))
|
||||
{
|
||||
m_quantum = dev->GetMtu ();
|
||||
NS_LOG_DEBUG ("Setting the quantum to the MTU of the device: " << m_quantum);
|
||||
}
|
||||
|
||||
if (!m_quantum)
|
||||
{
|
||||
NS_LOG_ERROR ("The quantum parameter cannot be null");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_enableSetAssociativeHash && (m_flows % m_setWays != 0))
|
||||
{
|
||||
NS_LOG_ERROR ("The number of queues must be an integer multiple of the size "
|
||||
"of the set of queues used by set associative hash");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If UseL4S attribute is enabled then CE threshold must be set.
|
||||
if (m_useL4s)
|
||||
{
|
||||
NS_ABORT_MSG_IF (m_ceThreshold == Time::Max(), "CE threshold not set");
|
||||
if (m_useEcn == false)
|
||||
{
|
||||
NS_LOG_WARN ("Enabling ECN as L4S mode is enabled");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
FqPieQueueDisc::InitializeParams (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
m_flowFactory.SetTypeId ("ns3::FqPieFlow");
|
||||
|
||||
m_queueDiscFactory.SetTypeId ("ns3::PieQueueDisc");
|
||||
m_queueDiscFactory.Set ("MaxSize", QueueSizeValue (GetMaxSize ()));
|
||||
m_queueDiscFactory.Set ("MeanPktSize", UintegerValue (1000));
|
||||
m_queueDiscFactory.Set ("A", DoubleValue (0.125));
|
||||
m_queueDiscFactory.Set ("B", DoubleValue (1.25));
|
||||
m_queueDiscFactory.Set ("Tupdate", TimeValue (Seconds (0.015)));
|
||||
m_queueDiscFactory.Set ("Supdate", TimeValue (Seconds (0)));
|
||||
m_queueDiscFactory.Set ("DequeueThreshold", UintegerValue (16384));
|
||||
m_queueDiscFactory.Set ("QueueDelayReference", TimeValue (Seconds (0.015)));
|
||||
m_queueDiscFactory.Set ("MaxBurstAllowance", TimeValue (Seconds (0.15)));
|
||||
m_queueDiscFactory.Set ("UseDequeueRateEstimator", BooleanValue (false));
|
||||
m_queueDiscFactory.Set ("UseCapDropAdjustment", BooleanValue (true));
|
||||
m_queueDiscFactory.Set ("UseDerandomization", BooleanValue (false));
|
||||
}
|
||||
|
||||
uint32_t
|
||||
FqPieQueueDisc::FqPieDrop (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
uint32_t maxBacklog = 0, index = 0;
|
||||
Ptr<QueueDisc> qd;
|
||||
|
||||
/* Queue is full! Find the fat flow and drop packet(s) from it */
|
||||
for (uint32_t i = 0; i < GetNQueueDiscClasses (); i++)
|
||||
{
|
||||
qd = GetQueueDiscClass (i)->GetQueueDisc ();
|
||||
uint32_t bytes = qd->GetNBytes ();
|
||||
if (bytes > maxBacklog)
|
||||
{
|
||||
maxBacklog = bytes;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Our goal is to drop half of this fat flow backlog */
|
||||
uint32_t len = 0, count = 0, threshold = maxBacklog >> 1;
|
||||
qd = GetQueueDiscClass (index)->GetQueueDisc ();
|
||||
Ptr<QueueDiscItem> item;
|
||||
|
||||
do
|
||||
{
|
||||
NS_LOG_DEBUG ("Drop packet (overflow); count: " << count << " len: " << len << " threshold: " << threshold);
|
||||
item = qd->GetInternalQueue (0)->Dequeue ();
|
||||
DropAfterDequeue (item, OVERLIMIT_DROP);
|
||||
len += item->GetSize ();
|
||||
} while (++count < m_dropBatchSize && len < threshold);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
204
src/traffic-control/model/fq-pie-queue-disc.h
Executable file
204
src/traffic-control/model/fq-pie-queue-disc.h
Executable file
@@ -0,0 +1,204 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2018 NITK Surathkal
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Authors: Sumukha PK <sumukhapk46@gmail.com>
|
||||
* Prajval M <26prajval98@gmail.com>
|
||||
* Ishaan R D <ishaanrd6@gmail.com>
|
||||
* Mohit P. Tahiliani <tahiliani@nitk.edu.in>
|
||||
*/
|
||||
|
||||
#ifndef FQ_PIE_QUEUE_DISC
|
||||
#define FQ_PIE_QUEUE_DISC
|
||||
|
||||
#include "ns3/queue-disc.h"
|
||||
#include "ns3/object-factory.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \ingroup traffic-control
|
||||
*
|
||||
* \brief A flow queue used by the FqPie queue disc
|
||||
*/
|
||||
|
||||
class FqPieFlow : public QueueDiscClass {
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
/**
|
||||
* \brief FqPieFlow constructor
|
||||
*/
|
||||
FqPieFlow ();
|
||||
|
||||
virtual ~FqPieFlow ();
|
||||
|
||||
/**
|
||||
* \enum FlowStatus
|
||||
* \brief Used to determine the status of this flow queue
|
||||
*/
|
||||
enum FlowStatus
|
||||
{
|
||||
INACTIVE,
|
||||
NEW_FLOW,
|
||||
OLD_FLOW
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Set the deficit for this flow
|
||||
* \param deficit the deficit for this flow
|
||||
*/
|
||||
void SetDeficit (uint32_t deficit);
|
||||
/**
|
||||
* \brief Get the deficit for this flow
|
||||
* \return the deficit for this flow
|
||||
*/
|
||||
int32_t GetDeficit (void) const;
|
||||
/**
|
||||
* \brief Increase the deficit for this flow
|
||||
* \param deficit the amount by which the deficit is to be increased
|
||||
*/
|
||||
void IncreaseDeficit (int32_t deficit);
|
||||
/**
|
||||
* \brief Set the status for this flow
|
||||
* \param status the status for this flow
|
||||
*/
|
||||
void SetStatus (FlowStatus status);
|
||||
/**
|
||||
* \brief Get the status of this flow
|
||||
* \return the status of this flow
|
||||
*/
|
||||
FlowStatus GetStatus (void) const;
|
||||
/**
|
||||
* \brief Set the index for this flow
|
||||
* \param index the index for this flow
|
||||
*/
|
||||
void SetIndex (uint32_t index);
|
||||
/**
|
||||
* \brief Get the index of this flow
|
||||
* \return the index of this flow
|
||||
*/
|
||||
uint32_t GetIndex (void) const;
|
||||
|
||||
private:
|
||||
int32_t m_deficit; //!< the deficit for this flow
|
||||
FlowStatus m_status; //!< the status of this flow
|
||||
uint32_t m_index; //!< the index for this flow
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup traffic-control
|
||||
*
|
||||
* \brief A FqPie packet queue disc
|
||||
*/
|
||||
|
||||
class FqPieQueueDisc : public QueueDisc {
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
/**
|
||||
* \brief FqPieQueueDisc constructor
|
||||
*/
|
||||
FqPieQueueDisc ();
|
||||
|
||||
virtual ~FqPieQueueDisc ();
|
||||
|
||||
/**
|
||||
* \brief Set the quantum value.
|
||||
*
|
||||
* \param quantum The number of bytes each queue gets to dequeue on each round of the scheduling algorithm
|
||||
*/
|
||||
void SetQuantum (uint32_t quantum);
|
||||
|
||||
/**
|
||||
* \brief Get the quantum value.
|
||||
*
|
||||
* \returns The number of bytes each queue gets to dequeue on each round of the scheduling algorithm
|
||||
*/
|
||||
uint32_t GetQuantum (void) const;
|
||||
|
||||
// Reasons for dropping packets
|
||||
static constexpr const char* UNCLASSIFIED_DROP = "Unclassified drop"; //!< No packet filter able to classify packet
|
||||
static constexpr const char* OVERLIMIT_DROP = "Overlimit drop"; //!< Overlimit dropped packets
|
||||
|
||||
private:
|
||||
virtual bool DoEnqueue (Ptr<QueueDiscItem> item);
|
||||
virtual Ptr<QueueDiscItem> DoDequeue (void);
|
||||
virtual bool CheckConfig (void);
|
||||
virtual void InitializeParams (void);
|
||||
|
||||
/**
|
||||
* \brief Drop a packet from the head of the queue with the largest current byte count
|
||||
* \return the index of the queue with the largest current byte count
|
||||
*/
|
||||
uint32_t FqPieDrop (void);
|
||||
|
||||
/**
|
||||
* Compute the index of the queue for the flow having the given flowHash,
|
||||
* according to the set associative hash approach.
|
||||
*
|
||||
* \param flowHash the hash of the flow 5-tuple
|
||||
* \return the index of the queue for the given flow
|
||||
*/
|
||||
uint32_t SetAssociativeHash (uint32_t flowHash);
|
||||
|
||||
// PIE queue disc parameter
|
||||
bool m_useEcn; //!< True if ECN is used (packets are marked instead of being dropped)
|
||||
double m_markEcnTh; //!< ECN marking threshold (default 10% as suggested in RFC 8033)
|
||||
Time m_ceThreshold; //!< Threshold above which to CE mark
|
||||
bool m_useL4s; //!< True if L4S is used (ECT1 packets are marked at CE threshold)
|
||||
Time m_sUpdate; //!< Start time of the update timer
|
||||
Time m_tUpdate; //!< Time period after which CalculateP () is called
|
||||
Time m_qDelayRef; //!< Desired queue delay
|
||||
uint32_t m_meanPktSize; //!< Average packet size in bytes
|
||||
Time m_maxBurst; //!< Maximum burst allowed before random early dropping kicks in
|
||||
double m_a; //!< Parameter to pie controller
|
||||
double m_b; //!< Parameter to pie controller
|
||||
uint32_t m_dqThreshold; //!< Minimum queue size in bytes before dequeue rate is measured
|
||||
bool m_useDqRateEstimator; //!< Enable/Disable usage of dequeue rate estimator for queue delay calculation
|
||||
bool m_isCapDropAdjustment;//!< Enable/Disable Cap Drop Adjustment feature mentioned in RFC 8033
|
||||
bool m_useDerandomization; //!< Enable Derandomization feature mentioned in RFC 8033
|
||||
|
||||
// Fq parameters
|
||||
uint32_t m_quantum; //!< Deficit assigned to flows at each round
|
||||
uint32_t m_flows; //!< Number of flow queues
|
||||
uint32_t m_setWays; //!< size of a set of queues (used by set associative hash)
|
||||
uint32_t m_dropBatchSize; //!< Max number of packets dropped from the fat flow
|
||||
uint32_t m_perturbation; //!< hash perturbation value
|
||||
bool m_enableSetAssociativeHash; //!< whether to enable set associative hash
|
||||
|
||||
std::list<Ptr<FqPieFlow> > m_newFlows; //!< The list of new flows
|
||||
std::list<Ptr<FqPieFlow> > m_oldFlows; //!< The list of old flows
|
||||
|
||||
std::map<uint32_t, uint32_t> m_flowsIndices; //!< Map with the index of class for each flow
|
||||
std::map<uint32_t, uint32_t> m_tags; //!< Tags used by set associative hash
|
||||
|
||||
ObjectFactory m_flowFactory; //!< Factory to create a new flow
|
||||
ObjectFactory m_queueDiscFactory; //!< Factory to create a new queue
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* FQ_PIE_QUEUE_DISC */
|
||||
@@ -50,7 +50,7 @@ TypeId PieQueueDisc::GetTypeId (void)
|
||||
"Average of packet size",
|
||||
UintegerValue (1000),
|
||||
MakeUintegerAccessor (&PieQueueDisc::m_meanPktSize),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("A",
|
||||
"Value of alpha",
|
||||
DoubleValue (0.125),
|
||||
@@ -122,6 +122,16 @@ TypeId PieQueueDisc::GetTypeId (void)
|
||||
TimeValue (Time::Max ()),
|
||||
MakeTimeAccessor (&PieQueueDisc::m_activeThreshold),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("CeThreshold",
|
||||
"The FqPie CE threshold for marking packets",
|
||||
TimeValue (Time::Max ()),
|
||||
MakeTimeAccessor (&PieQueueDisc::m_ceThreshold),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("UseL4s",
|
||||
"True to use L4S (only ECT1 packets are marked at CE threshold)",
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&PieQueueDisc::m_useL4s),
|
||||
MakeBooleanChecker ())
|
||||
;
|
||||
|
||||
return tid;
|
||||
@@ -169,6 +179,24 @@ PieQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
|
||||
NS_LOG_FUNCTION (this << item);
|
||||
|
||||
QueueSize nQueued = GetCurrentSize ();
|
||||
// If L4S is enabled, then check if the packet is ECT1, and if it is then set isEct true
|
||||
bool isEct1 = false;
|
||||
if (item && m_useL4s)
|
||||
{
|
||||
uint8_t tosByte = 0;
|
||||
if (item->GetUint8Value (QueueItem::IP_DSFIELD, tosByte) && (((tosByte & 0x3) == 1) || (tosByte & 0x3) == 3))
|
||||
{
|
||||
if ((tosByte & 0x3) == 1)
|
||||
{
|
||||
NS_LOG_DEBUG ("Enqueueing ECT1 packet " << static_cast<uint16_t> (tosByte & 0x3));
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_DEBUG ("Enqueueing CE packet " << static_cast<uint16_t> (tosByte & 0x3));
|
||||
}
|
||||
isEct1 = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (nQueued + item > GetMaxSize ())
|
||||
{
|
||||
@@ -177,7 +205,9 @@ PieQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
|
||||
m_accuProb = 0;
|
||||
return false;
|
||||
}
|
||||
else if ((m_activeThreshold == Time::Max () || m_active) && DropEarly (item, nQueued.GetValue ()))
|
||||
// isEct1 will be true only if L4S enabled as well as the packet is ECT1.
|
||||
// If L4S is enabled and packet is ECT1 then directly enqueue the packet.
|
||||
else if ((m_activeThreshold == Time::Max () || m_active) && !isEct1 && DropEarly (item, nQueued.GetValue ()))
|
||||
{
|
||||
if (!m_useEcn || m_dropProb >= m_markEcnTh || !Mark (item, UNFORCED_MARK))
|
||||
{
|
||||
@@ -452,6 +482,29 @@ PieQueueDisc::DoDequeue ()
|
||||
double now = Simulator::Now ().GetSeconds ();
|
||||
uint32_t pktSize = item->GetSize ();
|
||||
|
||||
// If L4S is enabled and packet is ECT1, then check if delay is greater than CE threshold and if it is then mark the packet,
|
||||
// and skip PIE steps, and return the item.
|
||||
if (item && m_useL4s)
|
||||
{
|
||||
uint8_t tosByte = 0;
|
||||
if (item->GetUint8Value (QueueItem::IP_DSFIELD, tosByte) && (((tosByte & 0x3) == 1) || (tosByte & 0x3) == 3))
|
||||
{
|
||||
if ((tosByte & 0x3) == 1)
|
||||
{
|
||||
NS_LOG_DEBUG ("ECT1 packet " << static_cast<uint16_t> (tosByte & 0x3));
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_DEBUG ("CE packet " << static_cast<uint16_t> (tosByte & 0x3));
|
||||
}
|
||||
if (Time (Seconds (now - item->GetTimeStamp ().GetSeconds ())) > m_ceThreshold && Mark (item, CE_THRESHOLD_EXCEEDED_MARK))
|
||||
{
|
||||
NS_LOG_LOGIC ("Marking due to CeThreshold " << m_ceThreshold.GetSeconds ());
|
||||
}
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
// if not in a measurement cycle and the queue has built up to dq_threshold,
|
||||
// start the measurement cycle
|
||||
if (m_useDqRateEstimator)
|
||||
|
||||
@@ -98,6 +98,7 @@ public:
|
||||
static constexpr const char* UNFORCED_DROP = "Unforced drop"; //!< Early probability drops: proactive
|
||||
static constexpr const char* FORCED_DROP = "Forced drop"; //!< Drops due to queue limit: reactive
|
||||
static constexpr const char* UNFORCED_MARK = "Unforced mark"; //!< Early probability marks: proactive
|
||||
static constexpr const char* CE_THRESHOLD_EXCEEDED_MARK = "CE threshold exceeded mark"; //!< Early probability marks: proactive
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -131,6 +132,7 @@ private:
|
||||
*/
|
||||
void CalculateP ();
|
||||
|
||||
|
||||
static const uint64_t DQCOUNT_INVALID = std::numeric_limits<uint64_t>::max(); //!< Invalid dqCount value
|
||||
|
||||
// ** Variables supplied by user
|
||||
@@ -148,6 +150,8 @@ private:
|
||||
bool m_useDerandomization; //!< Enable Derandomization feature mentioned in RFC 8033
|
||||
double m_markEcnTh; //!< ECN marking threshold (default 10% as suggested in RFC 8033)
|
||||
Time m_activeThreshold; //!< Threshold for activating PIE (disabled by default)
|
||||
Time m_ceThreshold; //!< Threshold above which to CE mark
|
||||
bool m_useL4s; //!< True if L4S is used (ECT1 packets are marked at CE threshold)
|
||||
|
||||
// ** Variables maintained by PIE
|
||||
double m_dropProb; //!< Variable used in calculation of drop probability
|
||||
|
||||
@@ -18,6 +18,7 @@ def build(bld):
|
||||
'model/codel-queue-disc.cc',
|
||||
'model/fq-codel-queue-disc.cc',
|
||||
'model/pie-queue-disc.cc',
|
||||
'model/fq-pie-queue-disc.cc',
|
||||
'model/prio-queue-disc.cc',
|
||||
'model/mq-queue-disc.cc',
|
||||
'model/tbf-queue-disc.cc',
|
||||
@@ -59,6 +60,7 @@ def build(bld):
|
||||
'model/codel-queue-disc.h',
|
||||
'model/fq-codel-queue-disc.h',
|
||||
'model/pie-queue-disc.h',
|
||||
'model/fq-pie-queue-disc.h',
|
||||
'model/prio-queue-disc.h',
|
||||
'model/mq-queue-disc.h',
|
||||
'model/tbf-queue-disc.h',
|
||||
|
||||
Reference in New Issue
Block a user