traffic-control: Add Prio queue disc
This commit is contained in:
@@ -61,6 +61,7 @@ us a note on ns-developers mailing list.</p>
|
||||
nodes to be placed outside of buildings defined in the scenario.</li>
|
||||
<li> The Hash() method has been added to the QueueDiscItem class to compute the
|
||||
hash of various fields of the packet header (depending on the packet type).</li>
|
||||
<li> Added a priority queue disc (PrioQueueDisc).</li>
|
||||
</ul>
|
||||
<h2>Changes to existing API:</h2>
|
||||
<ul>
|
||||
|
||||
@@ -82,6 +82,7 @@ SOURCES = \
|
||||
$(SRC)/traffic-control/doc/queue-discs.rst \
|
||||
$(SRC)/traffic-control/doc/pfifo-fast.rst \
|
||||
$(SRC)/traffic-control/doc/fifo.rst \
|
||||
$(SRC)/traffic-control/doc/prio.rst \
|
||||
$(SRC)/traffic-control/doc/tbf.rst \
|
||||
$(SRC)/traffic-control/doc/red.rst \
|
||||
$(SRC)/traffic-control/doc/codel.rst \
|
||||
|
||||
@@ -7,6 +7,7 @@ Traffic Control Layer
|
||||
queue-discs
|
||||
fifo
|
||||
pfifo-fast
|
||||
prio
|
||||
tbf
|
||||
red
|
||||
codel
|
||||
|
||||
@@ -99,7 +99,7 @@ int main (int argc, char *argv[])
|
||||
std::string delay = "5ms";
|
||||
std::string queueDiscType = "PfifoFast";
|
||||
uint32_t queueDiscSize = 1000;
|
||||
uint32_t netdevicesQueueSize = 100;
|
||||
uint32_t netdevicesQueueSize = 50;
|
||||
bool bql = false;
|
||||
|
||||
std::string flowsDatarate = "20Mbps";
|
||||
@@ -112,7 +112,7 @@ int main (int argc, char *argv[])
|
||||
CommandLine cmd;
|
||||
cmd.AddValue ("bandwidth", "Bottleneck bandwidth", bandwidth);
|
||||
cmd.AddValue ("delay", "Bottleneck delay", delay);
|
||||
cmd.AddValue ("queueDiscType", "Bottleneck queue disc type in {PfifoFast, ARED, CoDel, FqCoDel, PIE}", queueDiscType);
|
||||
cmd.AddValue ("queueDiscType", "Bottleneck queue disc type in {PfifoFast, ARED, CoDel, FqCoDel, PIE, prio}", queueDiscType);
|
||||
cmd.AddValue ("queueDiscSize", "Bottleneck queue disc size in packets", queueDiscSize);
|
||||
cmd.AddValue ("netdevicesQueueSize", "Bottleneck netdevices queue size in packets", netdevicesQueueSize);
|
||||
cmd.AddValue ("bql", "Enable byte queue limits on bottleneck netdevices", bql);
|
||||
@@ -180,6 +180,14 @@ int main (int argc, char *argv[])
|
||||
Config::SetDefault ("ns3::PieQueueDisc::MaxSize",
|
||||
QueueSizeValue (QueueSize (QueueSizeUnit::PACKETS, queueDiscSize)));
|
||||
}
|
||||
else if (queueDiscType.compare ("prio") == 0)
|
||||
{
|
||||
uint16_t handle = tchBottleneck.SetRootQueueDisc ("ns3::PrioQueueDisc", "Priomap",
|
||||
StringValue ("0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1"));
|
||||
TrafficControlHelper::ClassIdList cid = tchBottleneck.AddQueueDiscClasses (handle, 2, "ns3::QueueDiscClass");
|
||||
tchBottleneck.AddChildQueueDisc (handle, cid[0], "ns3::FifoQueueDisc");
|
||||
tchBottleneck.AddChildQueueDisc (handle, cid[1], "ns3::RedQueueDisc");
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ABORT_MSG ("--queueDiscType not valid");
|
||||
|
||||
76
src/traffic-control/doc/prio.rst
Normal file
76
src/traffic-control/doc/prio.rst
Normal file
@@ -0,0 +1,76 @@
|
||||
.. include:: replace.txt
|
||||
.. highlight:: cpp
|
||||
|
||||
Prio queue disc
|
||||
---------------------
|
||||
|
||||
Model Description
|
||||
*****************
|
||||
|
||||
PrioQueueDisc implements a strict priority policy, where packets are dequeued from
|
||||
a band only if higher priority bands are all empty. PrioQueueDisc is a classful
|
||||
queue disc and can have an arbitrary number of bands, each of which is handled by a
|
||||
queue disc of any kind. The capacity of PrioQueueDisc is not limited; packets can
|
||||
only be dropped by child queue discs (which may have a limited capacity).
|
||||
If no packet filter is installed or able to classify a packet, then the
|
||||
packet is enqueued into a priority band based on its priority (modulo 16), which
|
||||
is used as an index into an array called priomap. Users can read :ref:`Socket-options`
|
||||
for details on how to set the packet priority. If a packet is classified
|
||||
by an installed packet filter and the returned value ``i`` is non-negative and less than the
|
||||
number of priority bands, then the packet is enqueued into the ``i``-th priority band.
|
||||
Otherwise, the packet is enqueued into the priority band specified by the first element
|
||||
of the priomap array.
|
||||
|
||||
If no queue disc class is added by the user before the queue disc is initialized,
|
||||
three child queue discs of type FifoQueueDisc are automatically added. It has to
|
||||
be noted that PrioQueueDisc needs at least two child queue discs.
|
||||
|
||||
|
||||
Attributes
|
||||
==========
|
||||
|
||||
The PrioQueueDisc class holds the following attribute:
|
||||
|
||||
* ``Priomap:`` The priority to band mapping. The default value is the same mapping as the (fixed) one used by PfifoFastQueueDisc.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
An example of how to configure PrioQueueDisc with custom child queue discs and priomap
|
||||
is provided by `queue-discs-benchmark.cc` located in ``examples/traffic-control``:
|
||||
|
||||
.. sourcecode:: cpp
|
||||
|
||||
TrafficControlHelper tch;
|
||||
uint16_t handle = tch.SetRootQueueDisc ("ns3::PrioQueueDisc", "Priomap", StringValue ("0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1"));
|
||||
TrafficControlHelper::ClassIdList cid = tch.AddQueueDiscClasses (handle, 2, "ns3::QueueDiscClass");
|
||||
tch.AddChildQueueDisc (handle, cid[0], "ns3::FifoQueueDisc");
|
||||
tch.AddChildQueueDisc (handle, cid[1], "ns3::RedQueueDisc");
|
||||
|
||||
The code above adds two classes (bands) to a PrioQueueDisc. The highest priority one
|
||||
is a FifoQueueDisc, the other one is a RedQueueDisc. The attribute Priomap is set to
|
||||
an array containing only 0 and 1 (since PrioQueueDisc only has two bands).
|
||||
|
||||
|
||||
Validation
|
||||
**********
|
||||
|
||||
PrioQueueDisc is tested using :cpp:class:`PrioQueueDiscTestSuite` class defined
|
||||
in ``src/traffic-control/test/prio-queue-disc-test-suite.cc``. The test aims to
|
||||
check that: i) packets are enqueued in the correct band based on their priority and
|
||||
the priomap or according to the value returned by the installed packet filter;
|
||||
ii) packets are dequeued in the correct order.
|
||||
|
||||
The test suite can be run using the following commands:
|
||||
|
||||
::
|
||||
|
||||
$ ./waf configure --enable-examples --enable-tests
|
||||
$ ./waf build
|
||||
$ ./test.py -s prio-queue-disc
|
||||
|
||||
or
|
||||
|
||||
::
|
||||
|
||||
$ NS_LOG="PrioQueueDisc" ./waf --run "test-runner --suite=prio-queue-disc"
|
||||
224
src/traffic-control/model/prio-queue-disc.cc
Normal file
224
src/traffic-control/model/prio-queue-disc.cc
Normal file
@@ -0,0 +1,224 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2017 Universita' degli Studi di Napoli Federico II
|
||||
*
|
||||
* 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: Stefano Avallone <stavallo@unina.it>
|
||||
*/
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/pointer.h"
|
||||
#include "ns3/object-factory.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "prio-queue-disc.h"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("PrioQueueDisc");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (PrioQueueDisc);
|
||||
|
||||
ATTRIBUTE_HELPER_CPP (Priomap);
|
||||
|
||||
std::ostream &
|
||||
operator << (std::ostream &os, const Priomap &priomap)
|
||||
{
|
||||
std::copy (priomap.begin (), priomap.end ()-1, std::ostream_iterator<uint16_t>(os, " "));
|
||||
os << priomap.back ();
|
||||
return os;
|
||||
}
|
||||
|
||||
std::istream &operator >> (std::istream &is, Priomap &priomap)
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (!(is >> priomap[i]))
|
||||
{
|
||||
NS_FATAL_ERROR ("Incomplete priomap specification (" << i << " values provided, 16 required)");
|
||||
}
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
TypeId PrioQueueDisc::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::PrioQueueDisc")
|
||||
.SetParent<QueueDisc> ()
|
||||
.SetGroupName ("TrafficControl")
|
||||
.AddConstructor<PrioQueueDisc> ()
|
||||
.AddAttribute ("Priomap", "The priority to band mapping.",
|
||||
PriomapValue (Priomap{{1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}}),
|
||||
MakePriomapAccessor (&PrioQueueDisc::m_prio2band),
|
||||
MakePriomapChecker ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
PrioQueueDisc::PrioQueueDisc ()
|
||||
: QueueDisc (QueueDiscSizePolicy::NO_LIMITS)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
PrioQueueDisc::~PrioQueueDisc ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
void
|
||||
PrioQueueDisc::SetBandForPriority (uint8_t prio, uint16_t band)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << prio << band);
|
||||
|
||||
NS_ASSERT_MSG (prio < 16, "Priority must be a value between 0 and 15");
|
||||
|
||||
m_prio2band[prio] = band;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
PrioQueueDisc::GetBandForPriority (uint8_t prio) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this << prio);
|
||||
|
||||
NS_ASSERT_MSG (prio < 16, "Priority must be a value between 0 and 15");
|
||||
|
||||
return m_prio2band[prio];
|
||||
}
|
||||
|
||||
bool
|
||||
PrioQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << item);
|
||||
|
||||
uint32_t band = m_prio2band[0];
|
||||
|
||||
int32_t ret = Classify (item);
|
||||
|
||||
if (ret == PacketFilter::PF_NO_MATCH)
|
||||
{
|
||||
NS_LOG_DEBUG ("No filter has been able to classify this packet, using priomap.");
|
||||
|
||||
SocketPriorityTag priorityTag;
|
||||
if (item->GetPacket ()->PeekPacketTag (priorityTag))
|
||||
{
|
||||
band = m_prio2band[priorityTag.GetPriority () & 0x0f];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_DEBUG ("Packet filters returned " << ret);
|
||||
|
||||
if (ret >= 0 && static_cast<uint32_t>(ret) < GetNQueueDiscClasses ())
|
||||
{
|
||||
band = ret;
|
||||
}
|
||||
}
|
||||
|
||||
NS_ASSERT_MSG (band < GetNQueueDiscClasses (), "Selected band out of range");
|
||||
bool retval = GetQueueDiscClass (band)->GetQueueDisc ()->Enqueue (item);
|
||||
|
||||
// If Queue::Enqueue fails, QueueDisc::Drop is called by the child queue disc
|
||||
// because QueueDisc::AddQueueDiscClass sets the drop callback
|
||||
|
||||
NS_LOG_LOGIC ("Number packets band " << band << ": " << GetQueueDiscClass (band)->GetQueueDisc ()->GetNPackets ());
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
Ptr<QueueDiscItem>
|
||||
PrioQueueDisc::DoDequeue (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
Ptr<QueueDiscItem> item;
|
||||
|
||||
for (uint32_t i = 0; i < GetNQueueDiscClasses (); i++)
|
||||
{
|
||||
if ((item = GetQueueDiscClass (i)->GetQueueDisc ()->Dequeue ()) != 0)
|
||||
{
|
||||
NS_LOG_LOGIC ("Popped from band " << i << ": " << item);
|
||||
NS_LOG_LOGIC ("Number packets band " << i << ": " << GetQueueDiscClass (i)->GetQueueDisc ()->GetNPackets ());
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
NS_LOG_LOGIC ("Queue empty");
|
||||
return item;
|
||||
}
|
||||
|
||||
Ptr<const QueueDiscItem>
|
||||
PrioQueueDisc::DoPeek (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
Ptr<const QueueDiscItem> item;
|
||||
|
||||
for (uint32_t i = 0; i < GetNQueueDiscClasses (); i++)
|
||||
{
|
||||
if ((item = GetQueueDiscClass (i)->GetQueueDisc ()->Peek ()) != 0)
|
||||
{
|
||||
NS_LOG_LOGIC ("Peeked from band " << i << ": " << item);
|
||||
NS_LOG_LOGIC ("Number packets band " << i << ": " << GetQueueDiscClass (i)->GetQueueDisc ()->GetNPackets ());
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
NS_LOG_LOGIC ("Queue empty");
|
||||
return item;
|
||||
}
|
||||
|
||||
bool
|
||||
PrioQueueDisc::CheckConfig (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
if (GetNInternalQueues () > 0)
|
||||
{
|
||||
NS_LOG_ERROR ("PrioQueueDisc cannot have internal queues");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetNQueueDiscClasses () == 0)
|
||||
{
|
||||
// create 3 fifo queue discs
|
||||
ObjectFactory factory;
|
||||
factory.SetTypeId ("ns3::FifoQueueDisc");
|
||||
for (uint8_t i = 0; i < 2; i++)
|
||||
{
|
||||
Ptr<QueueDisc> qd = factory.Create<QueueDisc> ();
|
||||
qd->Initialize ();
|
||||
Ptr<QueueDiscClass> c = CreateObject<QueueDiscClass> ();
|
||||
c->SetQueueDisc (qd);
|
||||
AddQueueDiscClass (c);
|
||||
}
|
||||
}
|
||||
|
||||
if (GetNQueueDiscClasses () < 2)
|
||||
{
|
||||
NS_LOG_ERROR ("PrioQueueDisc needs at least 2 classes");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
PrioQueueDisc::InitializeParams (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
113
src/traffic-control/model/prio-queue-disc.h
Normal file
113
src/traffic-control/model/prio-queue-disc.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2017 Universita' degli Studi di Napoli Federico II
|
||||
*
|
||||
* 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: Stefano Avallone <stavallo@unina.it>
|
||||
*/
|
||||
|
||||
#ifndef PRIO_QUEUE_DISC_H
|
||||
#define PRIO_QUEUE_DISC_H
|
||||
|
||||
#include "ns3/queue-disc.h"
|
||||
#include <array>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
typedef std::array<uint16_t, 16> Priomap;
|
||||
|
||||
/**
|
||||
* \ingroup traffic-control
|
||||
*
|
||||
* The Prio qdisc is a simple classful queueing discipline that contains an
|
||||
* arbitrary number of classes of differing priority. The classes are dequeued
|
||||
* in numerical descending order of priority. By default, three Fifo queue
|
||||
* discs are created, unless the user provides (at least two) child queue
|
||||
* discs.
|
||||
*
|
||||
* If no packet filter is installed or able to classify a packet, then the
|
||||
* packet is assigned a priority band based on its priority (modulo 16), which
|
||||
* is used as an index into an array called priomap. If a packet is classified
|
||||
* by a packet filter and the returned value is non-negative and less than the
|
||||
* number of priority bands, then the packet is assigned the priority band
|
||||
* corresponding to the value returned by the packet filter. Otherwise, the
|
||||
* packet is assigned the priority band specified by the first element of the
|
||||
* priomap array.
|
||||
*/
|
||||
class PrioQueueDisc : public QueueDisc {
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
/**
|
||||
* \brief PrioQueueDisc constructor
|
||||
*/
|
||||
PrioQueueDisc ();
|
||||
|
||||
virtual ~PrioQueueDisc();
|
||||
|
||||
/**
|
||||
* Set the band (class) assigned to packets with specified priority.
|
||||
*
|
||||
* \param prio the priority of packets (a value between 0 and 15).
|
||||
* \param band the band assigned to packets.
|
||||
*/
|
||||
void SetBandForPriority (uint8_t prio, uint16_t band);
|
||||
|
||||
/**
|
||||
* Get the band (class) assigned to packets with specified priority.
|
||||
*
|
||||
* \param prio the priority of packets (a value between 0 and 15).
|
||||
* \returns the band assigned to packets.
|
||||
*/
|
||||
uint16_t GetBandForPriority (uint8_t prio) const;
|
||||
|
||||
private:
|
||||
virtual bool DoEnqueue (Ptr<QueueDiscItem> item);
|
||||
virtual Ptr<QueueDiscItem> DoDequeue (void);
|
||||
virtual Ptr<const QueueDiscItem> DoPeek (void);
|
||||
virtual bool CheckConfig (void);
|
||||
virtual void InitializeParams (void);
|
||||
|
||||
Priomap m_prio2band; //!< Priority to band mapping
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize the priomap to the given ostream
|
||||
*
|
||||
* \param os
|
||||
* \param priomap
|
||||
*
|
||||
* \return std::ostream
|
||||
*/
|
||||
std::ostream &operator << (std::ostream &os, const Priomap &priomap);
|
||||
|
||||
/**
|
||||
* Serialize from the given istream to this priomap.
|
||||
*
|
||||
* \param is
|
||||
* \param priomap
|
||||
*
|
||||
* \return std::istream
|
||||
*/
|
||||
std::istream &operator >> (std::istream &is, Priomap &priomap);
|
||||
|
||||
ATTRIBUTE_HELPER_HEADER (Priomap);
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* PRIO_QUEUE_DISC_H */
|
||||
324
src/traffic-control/test/prio-queue-disc-test-suite.cc
Normal file
324
src/traffic-control/test/prio-queue-disc-test-suite.cc
Normal file
@@ -0,0 +1,324 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2017 Universita' degli Studi di Napoli Federico II
|
||||
*
|
||||
* 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: Stefano Avallone <stavallo@unina.it>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ns3/test.h"
|
||||
#include "ns3/prio-queue-disc.h"
|
||||
#include "ns3/fifo-queue-disc.h"
|
||||
#include "ns3/packet-filter.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/string.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include <array>
|
||||
#include <queue>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
/**
|
||||
* \ingroup traffic-control-test
|
||||
* \ingroup tests
|
||||
*
|
||||
* \brief Prio Queue Disc Test Item
|
||||
*/
|
||||
class PrioQueueDiscTestItem : public QueueDiscItem
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param p the packet
|
||||
* \param addr the address
|
||||
* \param priority the packet priority
|
||||
*/
|
||||
PrioQueueDiscTestItem (Ptr<Packet> p, const Address & addr, uint8_t priority);
|
||||
virtual ~PrioQueueDiscTestItem ();
|
||||
virtual void AddHeader (void);
|
||||
virtual bool Mark (void);
|
||||
};
|
||||
|
||||
PrioQueueDiscTestItem::PrioQueueDiscTestItem (Ptr<Packet> p, const Address & addr, uint8_t priority)
|
||||
: QueueDiscItem (p, addr, 0)
|
||||
{
|
||||
SocketPriorityTag priorityTag;
|
||||
priorityTag.SetPriority (priority);
|
||||
p->ReplacePacketTag (priorityTag);
|
||||
}
|
||||
|
||||
PrioQueueDiscTestItem::~PrioQueueDiscTestItem ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
PrioQueueDiscTestItem::AddHeader (void)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
PrioQueueDiscTestItem::Mark (void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup traffic-control-test
|
||||
* \ingroup tests
|
||||
*
|
||||
* \brief Prio Queue Disc Test Packet Filter
|
||||
*/
|
||||
class PrioQueueDiscTestFilter : public PacketFilter
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param cls whether this filter is able to classify a PrioQueueDiscTestItem
|
||||
*/
|
||||
PrioQueueDiscTestFilter (bool cls);
|
||||
virtual ~PrioQueueDiscTestFilter ();
|
||||
/**
|
||||
* \brief Set the value returned by DoClassify
|
||||
*
|
||||
* \param ret the value that DoClassify returns
|
||||
*/
|
||||
void SetReturnValue (int32_t ret);
|
||||
|
||||
private:
|
||||
virtual bool CheckProtocol (Ptr<QueueDiscItem> item) const;
|
||||
virtual int32_t DoClassify (Ptr<QueueDiscItem> item) const;
|
||||
|
||||
bool m_cls; //!< whether this filter is able to classify a PrioQueueDiscTestItem
|
||||
int32_t m_ret; //!< the value that DoClassify returns if m_cls is true
|
||||
};
|
||||
|
||||
PrioQueueDiscTestFilter::PrioQueueDiscTestFilter (bool cls)
|
||||
: m_cls (cls),
|
||||
m_ret (0)
|
||||
{
|
||||
}
|
||||
|
||||
PrioQueueDiscTestFilter::~PrioQueueDiscTestFilter ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
PrioQueueDiscTestFilter::SetReturnValue (int32_t ret)
|
||||
{
|
||||
m_ret = ret;
|
||||
}
|
||||
|
||||
bool
|
||||
PrioQueueDiscTestFilter::CheckProtocol (Ptr<QueueDiscItem> item) const
|
||||
{
|
||||
return m_cls;
|
||||
}
|
||||
|
||||
int32_t
|
||||
PrioQueueDiscTestFilter::DoClassify (Ptr<QueueDiscItem> item) const
|
||||
{
|
||||
return m_ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup traffic-control-test
|
||||
* \ingroup tests
|
||||
*
|
||||
* \brief Prio Queue Disc Test Case
|
||||
*/
|
||||
class PrioQueueDiscTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
PrioQueueDiscTestCase ();
|
||||
virtual void DoRun (void);
|
||||
};
|
||||
|
||||
PrioQueueDiscTestCase::PrioQueueDiscTestCase ()
|
||||
: TestCase ("Sanity check on the prio queue disc implementation")
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
PrioQueueDiscTestCase::DoRun (void)
|
||||
{
|
||||
Ptr<PrioQueueDisc> qdisc;
|
||||
Ptr<QueueDiscItem> item;
|
||||
std::string priomap ("0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3");
|
||||
Address dest;
|
||||
std::array<std::queue<uint64_t>,4> uids;
|
||||
|
||||
/*
|
||||
* Test 1: set priomap
|
||||
*/
|
||||
qdisc = CreateObject<PrioQueueDisc> ();
|
||||
|
||||
// add 4 child fifo queue discs
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
{
|
||||
Ptr<FifoQueueDisc> child = CreateObject<FifoQueueDisc> ();
|
||||
child->Initialize ();
|
||||
Ptr<QueueDiscClass> c = CreateObject<QueueDiscClass> ();
|
||||
c->SetQueueDisc (child);
|
||||
qdisc->AddQueueDiscClass (c);
|
||||
}
|
||||
qdisc->Initialize ();
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ (qdisc->GetNQueueDiscClasses (), 4, "Verify that the queue disc has 4 child queue discs");
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ (qdisc->SetAttributeFailSafe ("Priomap", StringValue (priomap)),
|
||||
true, "Verify that we can actually set the attribute Priomap");
|
||||
|
||||
StringValue sv;
|
||||
NS_TEST_EXPECT_MSG_EQ (qdisc->GetAttributeFailSafe ("Priomap", sv),
|
||||
true, "Verify that we can actually get the attribute Priomap");
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ (sv.Get (), priomap, "Verify that the priomap has been correctly set");
|
||||
|
||||
/*
|
||||
* Test 2: classify packets based on priomap because no packet filter is installed
|
||||
*/
|
||||
|
||||
// create packets with priorities from 0 to 3
|
||||
for (uint16_t i = 0; i < 4; i++)
|
||||
{
|
||||
NS_TEST_EXPECT_MSG_EQ (qdisc->GetQueueDiscClass (i)->GetQueueDisc ()->GetNPackets (),
|
||||
0, "There should be no packets in the child queue disc " << i);
|
||||
|
||||
item = Create<PrioQueueDiscTestItem> (Create<Packet> (100), dest, i);
|
||||
qdisc->Enqueue (item);
|
||||
// packet is assigned band i
|
||||
uids[i].push (item->GetPacket ()->GetUid ());
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ (qdisc->GetQueueDiscClass (i)->GetQueueDisc ()->GetNPackets (),
|
||||
1, "There should be one packet in the child queue disc " << i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test 3: classify packets based on priomap because no packet filter able
|
||||
* to classify packets is installed
|
||||
*/
|
||||
|
||||
Ptr<PrioQueueDiscTestFilter> pf1 = CreateObject<PrioQueueDiscTestFilter> (false);
|
||||
qdisc->AddPacketFilter (pf1);
|
||||
|
||||
// create packets with priorities from 4 to 7
|
||||
for (uint16_t i = 0; i < 4; i++)
|
||||
{
|
||||
NS_TEST_EXPECT_MSG_EQ (qdisc->GetQueueDiscClass (i)->GetQueueDisc ()->GetNPackets (),
|
||||
1, "There should be one packet in the child queue disc " << i);
|
||||
|
||||
item = Create<PrioQueueDiscTestItem> (Create<Packet> (100), dest, i+4);
|
||||
qdisc->Enqueue (item);
|
||||
// packet is assigned band i
|
||||
uids[i].push (item->GetPacket ()->GetUid ());
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ (qdisc->GetQueueDiscClass (i)->GetQueueDisc ()->GetNPackets (),
|
||||
2, "There should be two packets in the child queue disc " << i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test 4: classify packets based on the value returned by the installed packet filter
|
||||
*/
|
||||
|
||||
Ptr<PrioQueueDiscTestFilter> pf2 = CreateObject<PrioQueueDiscTestFilter> (true);
|
||||
qdisc->AddPacketFilter (pf2);
|
||||
|
||||
// create packets with priority 0 (which is neglected by the prio queue disc)
|
||||
for (uint16_t i = 0; i < 4; i++)
|
||||
{
|
||||
pf2->SetReturnValue (i);
|
||||
NS_TEST_EXPECT_MSG_EQ (qdisc->GetQueueDiscClass (i)->GetQueueDisc ()->GetNPackets (),
|
||||
2, "There should be two packets in the child queue disc " << i);
|
||||
|
||||
item = Create<PrioQueueDiscTestItem> (Create<Packet> (100), dest, 0);
|
||||
qdisc->Enqueue (item);
|
||||
// packet is assigned band i
|
||||
uids[i].push (item->GetPacket ()->GetUid ());
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ (qdisc->GetQueueDiscClass (i)->GetQueueDisc ()->GetNPackets (),
|
||||
3, "There should be three packets in the child queue disc " << i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test 5: classify packets into the band specified by the first element of the
|
||||
* priomap array because the value returned by the installed packet filter is
|
||||
* not less than the number of bands
|
||||
*/
|
||||
|
||||
// create packets with priority 1 (which is neglected by the prio queue disc)
|
||||
for (uint16_t i = 0; i < 4; i++)
|
||||
{
|
||||
pf2->SetReturnValue (4+i);
|
||||
NS_TEST_EXPECT_MSG_EQ (qdisc->GetBandForPriority (0), 0, "The band for priority 0 must be band 0");
|
||||
NS_TEST_EXPECT_MSG_EQ (qdisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), i+3u,
|
||||
"There should be " << i+3 << " packets in the child queue disc "
|
||||
<< qdisc->GetBandForPriority (0));
|
||||
|
||||
item = Create<PrioQueueDiscTestItem> (Create<Packet> (100), dest, 1);
|
||||
qdisc->Enqueue (item);
|
||||
// packet is assigned band 0
|
||||
uids[0].push (item->GetPacket ()->GetUid ());
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ (qdisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), i+4u,
|
||||
"There should be " << i+4 << " packets in the child queue disc "
|
||||
<< qdisc->GetBandForPriority (0));
|
||||
}
|
||||
|
||||
/*
|
||||
* Test 6: dequeue packets starting from the highest priority band (band 0)
|
||||
*/
|
||||
|
||||
while ((item = qdisc->Dequeue ()))
|
||||
{
|
||||
for (uint16_t i = 0; i < 4; i++)
|
||||
{
|
||||
if (uids[i].empty ())
|
||||
{
|
||||
NS_TEST_EXPECT_MSG_EQ (qdisc->GetQueueDiscClass (i)->GetQueueDisc ()->GetNPackets (),
|
||||
0, "Band " << i << " should be empty");
|
||||
continue;
|
||||
}
|
||||
NS_TEST_EXPECT_MSG_EQ (uids[i].front (), item->GetPacket ()->GetUid (),
|
||||
"The dequeued packet is not the one we expected");
|
||||
uids[i].pop ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup traffic-control-test
|
||||
* \ingroup tests
|
||||
*
|
||||
* \brief Prio Queue Disc Test Suite
|
||||
*/
|
||||
static class PrioQueueDiscTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
PrioQueueDiscTestSuite ()
|
||||
: TestSuite ("prio-queue-disc", UNIT)
|
||||
{
|
||||
AddTestCase (new PrioQueueDiscTestCase (), TestCase::QUICK);
|
||||
}
|
||||
} g_prioQueueTestSuite; ///< the test suite
|
||||
@@ -18,6 +18,7 @@ def build(bld):
|
||||
'model/codel-queue-disc.cc',
|
||||
'model/fq-codel-queue-disc.cc',
|
||||
'model/pie-queue-disc.cc',
|
||||
'model/prio-queue-disc.cc',
|
||||
'model/mq-queue-disc.cc',
|
||||
'model/tbf-queue-disc.cc',
|
||||
'helper/traffic-control-helper.cc',
|
||||
@@ -31,6 +32,7 @@ def build(bld):
|
||||
'test/adaptive-red-queue-disc-test-suite.cc',
|
||||
'test/pie-queue-disc-test-suite.cc',
|
||||
'test/fifo-queue-disc-test-suite.cc',
|
||||
'test/prio-queue-disc-test-suite.cc',
|
||||
'test/tbf-queue-disc-test-suite.cc',
|
||||
'test/tc-flow-control-test-suite.cc'
|
||||
]
|
||||
@@ -47,6 +49,7 @@ def build(bld):
|
||||
'model/codel-queue-disc.h',
|
||||
'model/fq-codel-queue-disc.h',
|
||||
'model/pie-queue-disc.h',
|
||||
'model/prio-queue-disc.h',
|
||||
'model/mq-queue-disc.h',
|
||||
'model/tbf-queue-disc.h',
|
||||
'helper/traffic-control-helper.h',
|
||||
|
||||
Reference in New Issue
Block a user