traffic-control: Add Prio queue disc

This commit is contained in:
Stefano Avallone
2018-06-07 23:55:24 +02:00
parent 8a81339dc3
commit ca5fbe9555
9 changed files with 753 additions and 2 deletions

View File

@@ -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>

View File

@@ -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 \

View File

@@ -7,6 +7,7 @@ Traffic Control Layer
queue-discs
fifo
pfifo-fast
prio
tbf
red
codel

View File

@@ -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");

View 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"

View 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

View 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 */

View 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

View File

@@ -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',