traffic-control: (merges !362) Add FqCobalt queue disc
FqCobalt includes COBALT enhancements to CoDel (Blue enhancement) and set-associative hash, as used in the Linux cake queue disc. An L4S mode is also included.
This commit is contained in:
committed by
Tom Henderson
parent
fe26cf8b46
commit
3d7a42d42e
@@ -54,7 +54,7 @@ us a note on ns-developers mailing list.</p>
|
||||
<h1>Changes from ns-3.33 to ns-3.34</h1>
|
||||
<h2>New API:</h2>
|
||||
<ul>
|
||||
<li></li>
|
||||
<li>Added <b>FqCobalt</b> queue disc with L4S features and set associative hash.</li>
|
||||
</ul>
|
||||
<h2>Changes to existing API:</h2>
|
||||
<ul>
|
||||
|
||||
@@ -31,6 +31,7 @@ New user-visible features
|
||||
- (wifi) Holland PHY configuration has been removed from the model
|
||||
- (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.
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
1123
src/test/ns3tc/fq-cobalt-queue-disc-test-suite.cc
Normal file
1123
src/test/ns3tc/fq-cobalt-queue-disc-test-suite.cc
Normal file
File diff suppressed because it is too large
Load Diff
@@ -31,6 +31,7 @@ def build(bld):
|
||||
test_test.source = [
|
||||
'csma-system-test-suite.cc',
|
||||
'ns3tc/fq-codel-queue-disc-test-suite.cc',
|
||||
'ns3tc/fq-cobalt-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',
|
||||
|
||||
@@ -37,10 +37,14 @@ Linux model of COBALT is provided in ([Cobalt19]_).
|
||||
`m_stats.qLimDrop`.
|
||||
* ``CobaltQueueDisc::ShouldDrop ()``: This routine is
|
||||
``CobaltQueueDisc::DoDequeue()``'s helper routine that determines whether a
|
||||
packet should be dropped or not based on its sojourn time. If the sojourn
|
||||
time goes above `m_target` and remains above continuously for at least
|
||||
`m_interval`, the routine returns ``true`` indicating that it is OK
|
||||
to drop the packet. ``Otherwise, it returns ``false``. This routine
|
||||
packet should be dropped or not based on its sojourn time. If L4S mode is
|
||||
enabled then if the packet is ECT1 is checked and if delay is greater than
|
||||
CE threshold then the packet is marked and returns ``false``.
|
||||
If the sojourn time goes above `m_target` and remains above continuously
|
||||
for at least `m_interval`, the routine returns ``true`` indicating that it
|
||||
is OK to drop the packet. ``Otherwise, it returns ``false``. If L4S mode
|
||||
is turned off and CE threshold marking is enabled, then if the delay is
|
||||
greater than CE threshold, packet is marked. This routine
|
||||
decides if a packet should be dropped based on the dropping state of
|
||||
CoDel and drop probability of BLUE. The idea is to have both algorithms
|
||||
running in parallel and their effectiveness is decided by their respective
|
||||
@@ -53,10 +57,6 @@ Linux model of COBALT is provided in ([Cobalt19]_).
|
||||
Otherwise Cobalt will take the next packet from the queue and calculate
|
||||
its drop state by running CoDel and BLUE in parallel till there are none
|
||||
left to drop.
|
||||
* class :cpp:class:`CobaltTimestampTag`: This class implements the timestamp
|
||||
tagging for a packet. This tag is used to compute the packet's sojourn time
|
||||
(the difference between the time the packet is dequeued and the time it is
|
||||
pushed into the queue).
|
||||
|
||||
|
||||
|
||||
@@ -94,6 +94,8 @@ The key attributes that the CobaltQueue Disc class holds include the following:
|
||||
* ``Pdrop:`` Value of drop probability.
|
||||
* ``Increment:`` Increment value of drop probability. Default value is 1./256 .
|
||||
* ``Decrement:`` Decrement value of drop probability. Default value is 1./4096 .
|
||||
* ``CeThreshold:`` The CoDel CE threshold for marking packets.
|
||||
* ``UseL4s:`` True to use L4S (only ECT1 packets are marked at CE threshold).
|
||||
* ``Count:`` Cobalt count.
|
||||
* ``DropState:`` Dropping state of Cobalt. Default value is false.
|
||||
* ``Sojourn:`` Per packet time spent in the queue.
|
||||
@@ -120,7 +122,8 @@ The suite includes 2 test cases:
|
||||
* Test 1: Simple enqueue/dequeue with no drops.
|
||||
* Test 2: Change of BLUE's drop probability upon queue full
|
||||
(Activation of Blue).
|
||||
* Test 3: Test for ECN marking of packets
|
||||
* Test 3: This test verfies ECN marking.
|
||||
* Test 4: CE threshold marking test.
|
||||
|
||||
The test suite can be run using the following commands:
|
||||
|
||||
|
||||
76
src/traffic-control/doc/fq-cobalt.rst
Normal file
76
src/traffic-control/doc/fq-cobalt.rst
Normal file
@@ -0,0 +1,76 @@
|
||||
.. include:: replace.txt
|
||||
.. highlight:: cpp
|
||||
.. highlight:: bash
|
||||
|
||||
FqCobalt queue disc
|
||||
------------------
|
||||
|
||||
This chapter describes the FqCobalt ([Hoe16]_) queue disc implementation in |ns3|.
|
||||
|
||||
The FlowQueue-Cobalt (FQ-Cobalt) algorithm is similar to FlowQueue-CoDel (FQ-CoDel) algorithm available in ns-3-dev/src/traffic-control/doc/fq-codel.rst.
|
||||
The documentation for Cobalt is available in ns-3-dev/src/traffic-control/doc/cobalt.rst.
|
||||
|
||||
FqCobalt is one of the crucial piece needed to complete to CAKE module `<https://ieeexplore.ieee.org/document/8475045>`
|
||||
|
||||
Model Description
|
||||
*****************
|
||||
|
||||
The source code for the FqCobalt queue disc is located in the directory
|
||||
``src/traffic-control/model`` and consists of 2 files `fq-cobalt-queue-disc.h`
|
||||
and `fq-cobalt-queue-disc.cc` defining a FqCobaltQueueDisc class and a helper
|
||||
FqCobaltFlow class. The code was ported to |ns3| based on Linux kernel code
|
||||
implemented by Jonathan Morton.
|
||||
|
||||
The Model Description is similar to the FqCoDel documentation mentioned above.
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [CAK16] https://github.com/torvalds/linux/blob/master/net/sched/sch_cake.c , Implementation of CAKE in Linux
|
||||
|
||||
Attributes
|
||||
==========
|
||||
|
||||
The key attributes that the FqCobaltQueue class holds include the following:
|
||||
|
||||
Most of the key attributes are similar to the FqCoDel implementation mentioned above.
|
||||
Some differences are:
|
||||
Absence of ``MinBytes`` parameter.
|
||||
Some extra parameters are
|
||||
* ``Pdrop:`` Value of drop probability.
|
||||
* ``Increment:`` Increment value of drop probability. Default value is 1./256 .
|
||||
* ``Decrement:`` Decrement value of drop probability. Default value is 1./4096 .
|
||||
* ``BlueThreshold:`` The Threshold after which Blue is enabled. Default value is 400ms.
|
||||
|
||||
Note that if the user wants to disable Blue Enhancement then the user can set
|
||||
it to a large value for example Time::Max().
|
||||
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, FqCobalt
|
||||
can be configured as follows:
|
||||
|
||||
.. sourcecode:: cpp
|
||||
|
||||
TrafficControlHelper tch;
|
||||
tch.SetRootQueueDisc ("ns3::FqCobaltQueueDisc", "DropBatchSize", UintegerValue (1)
|
||||
"Perturbation", UintegerValue (256));
|
||||
QueueDiscContainer qdiscs = tch.Install (devices);
|
||||
|
||||
Validation
|
||||
**********
|
||||
|
||||
The FqCobalt model is tested using :cpp:class:`FqCobaltQueueDiscTestSuite` class defined in `src/test/ns3tc/codel-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-cobalt-queue-disc
|
||||
|
||||
or::
|
||||
|
||||
$ NS_LOG="FqCobaltQueueDisc" ./waf --run "test-runner --suite=fq-cobalt-queue-disc"
|
||||
@@ -84,6 +84,21 @@ TypeId CobaltQueueDisc::GetTypeId (void)
|
||||
DoubleValue (1. / 4096),
|
||||
MakeDoubleAccessor (&CobaltQueueDisc::m_decrement),
|
||||
MakeDoubleChecker<double> ())
|
||||
.AddAttribute ("CeThreshold",
|
||||
"The CoDel CE threshold for marking packets",
|
||||
TimeValue (Time::Max ()),
|
||||
MakeTimeAccessor (&CobaltQueueDisc::m_ceThreshold),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("UseL4s",
|
||||
"True to use L4S (only ECT1 packets are marked at CE threshold)",
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&CobaltQueueDisc::m_useL4s),
|
||||
MakeBooleanChecker ())
|
||||
.AddAttribute ("BlueThreshold",
|
||||
"The Threshold after which Blue is enabled",
|
||||
TimeValue (MilliSeconds (400)),
|
||||
MakeTimeAccessor (&CobaltQueueDisc::m_blueThreshold),
|
||||
MakeTimeChecker ())
|
||||
.AddTraceSource ("Count",
|
||||
"Cobalt count",
|
||||
MakeTraceSourceAccessor (&CobaltQueueDisc::m_count),
|
||||
@@ -436,6 +451,31 @@ bool CobaltQueueDisc::CobaltShouldDrop (Ptr<QueueDiscItem> item, int64_t now)
|
||||
int64_t schedule = now - m_dropNext;
|
||||
bool over_target = CoDelTimeAfter (sojournTime, Time2CoDel (m_target));
|
||||
bool next_due = m_count && schedule >= 0;
|
||||
bool isMarked = false;
|
||||
|
||||
// If L4S mode is enabled then check if the packet is ECT1 or CE and
|
||||
// if sojourn time is greater than CE threshold then the packet is marked.
|
||||
// If packet is marked succesfully then the CoDel steps can be skipped.
|
||||
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 (CoDelTimeAfter (sojournTime, Time2CoDel (m_ceThreshold)) && Mark (item, CE_THRESHOLD_EXCEEDED_MARK))
|
||||
{
|
||||
NS_LOG_LOGIC ("Marking due to CeThreshold " << m_ceThreshold.GetSeconds ());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (over_target)
|
||||
{
|
||||
@@ -458,7 +498,8 @@ bool CobaltQueueDisc::CobaltShouldDrop (Ptr<QueueDiscItem> item, int64_t now)
|
||||
{
|
||||
/* Check for marking possibility only if BLUE decides NOT to drop. */
|
||||
/* Check if router and packet, both have ECN enabled. Only if this is true, mark the packet. */
|
||||
drop = !(m_useEcn && Mark (item, FORCED_MARK));
|
||||
isMarked = (m_useEcn && Mark (item, FORCED_MARK));
|
||||
drop = !isMarked;
|
||||
|
||||
m_count = max (m_count, m_count + 1);
|
||||
|
||||
@@ -477,6 +518,22 @@ bool CobaltQueueDisc::CobaltShouldDrop (Ptr<QueueDiscItem> item, int64_t now)
|
||||
next_due = m_count && schedule >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If CE threshold is enabled then isMarked flag is used to determine whether
|
||||
// packet is marked and if the packet is marked then a second attempt at marking should be suppressed.
|
||||
// If UseL4S attribute is enabled then ECT0 packets should not be marked.
|
||||
if (!isMarked && !m_useL4s && m_useEcn && CoDelTimeAfter (sojournTime, Time2CoDel (m_ceThreshold)) && Mark (item, CE_THRESHOLD_EXCEEDED_MARK))
|
||||
{
|
||||
NS_LOG_LOGIC ("Marking due to CeThreshold " << m_ceThreshold.GetSeconds ());
|
||||
}
|
||||
|
||||
// Enable Blue Enhancement if sojourn time is greater than blueThreshold and its been m_target time until the last time blue was updated
|
||||
if (CoDelTimeAfter (sojournTime, Time2CoDel (m_blueThreshold)) && CoDelTimeAfter ((now - m_lastUpdateTimeBlue), Time2CoDel (m_target)))
|
||||
{
|
||||
m_Pdrop = min (m_Pdrop + m_increment, (double)1.0);
|
||||
m_lastUpdateTimeBlue = now;
|
||||
}
|
||||
|
||||
/* Simple BLUE implementation. Lack of ECN is deliberate. */
|
||||
if (m_Pdrop)
|
||||
{
|
||||
|
||||
@@ -103,6 +103,7 @@ public:
|
||||
static constexpr const char* TARGET_EXCEEDED_DROP = "Target exceeded drop"; //!< Sojourn time above target
|
||||
static constexpr const char* OVERLIMIT_DROP = "Overlimit drop"; //!< Overlimit dropped packet
|
||||
static constexpr const char* FORCED_MARK = "forcedMark"; //!< forced marks by Codel on ECN-enabled
|
||||
static constexpr const char* CE_THRESHOLD_EXCEEDED_MARK = "CE threshold exceeded mark"; //!< Sojourn time above CE threshold
|
||||
|
||||
/**
|
||||
* \brief Get the drop probability of Blue
|
||||
@@ -227,6 +228,9 @@ private:
|
||||
Time m_interval; //!< 100 ms sliding minimum time window width
|
||||
Time m_target; //!< 5 ms target queue delay
|
||||
bool m_useEcn; //!< True if ECN is used (packets are marked instead of being dropped)
|
||||
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_blueThreshold; //!< Threshold to enable blue enhancement
|
||||
|
||||
// Blue parameters
|
||||
// Maintained by Cobalt
|
||||
|
||||
523
src/traffic-control/model/fq-cobalt-queue-disc.cc
Normal file
523
src/traffic-control/model/fq-cobalt-queue-disc.cc
Normal file
@@ -0,0 +1,523 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2016 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: Pasquale Imputato <p.imputato@gmail.com>
|
||||
* Stefano Avallone <stefano.avallone@unina.it>
|
||||
*/
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/string.h"
|
||||
#include "ns3/queue.h"
|
||||
#include "fq-cobalt-queue-disc.h"
|
||||
#include "cobalt-queue-disc.h"
|
||||
#include "ns3/net-device-queue-interface.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("FqCobaltQueueDisc");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (FqCobaltFlow);
|
||||
|
||||
TypeId FqCobaltFlow::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::FqCobaltFlow")
|
||||
.SetParent<QueueDiscClass> ()
|
||||
.SetGroupName ("TrafficControl")
|
||||
.AddConstructor<FqCobaltFlow> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
FqCobaltFlow::FqCobaltFlow ()
|
||||
: m_deficit (0),
|
||||
m_status (INACTIVE),
|
||||
m_index (0)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
FqCobaltFlow::~FqCobaltFlow ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
void
|
||||
FqCobaltFlow::SetDeficit (uint32_t deficit)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << deficit);
|
||||
m_deficit = deficit;
|
||||
}
|
||||
|
||||
int32_t
|
||||
FqCobaltFlow::GetDeficit (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_deficit;
|
||||
}
|
||||
|
||||
void
|
||||
FqCobaltFlow::IncreaseDeficit (int32_t deficit)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << deficit);
|
||||
m_deficit += deficit;
|
||||
}
|
||||
|
||||
void
|
||||
FqCobaltFlow::SetStatus (FlowStatus status)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_status = status;
|
||||
}
|
||||
|
||||
FqCobaltFlow::FlowStatus
|
||||
FqCobaltFlow::GetStatus (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_status;
|
||||
}
|
||||
|
||||
void
|
||||
FqCobaltFlow::SetIndex (uint32_t index)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_index = index;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
FqCobaltFlow::GetIndex (void) const
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (FqCobaltQueueDisc);
|
||||
|
||||
TypeId FqCobaltQueueDisc::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::FqCobaltQueueDisc")
|
||||
.SetParent<QueueDisc> ()
|
||||
.SetGroupName ("TrafficControl")
|
||||
.AddConstructor<FqCobaltQueueDisc> ()
|
||||
.AddAttribute ("UseEcn",
|
||||
"True to use ECN (packets are marked instead of being dropped)",
|
||||
BooleanValue (true),
|
||||
MakeBooleanAccessor (&FqCobaltQueueDisc::m_useEcn),
|
||||
MakeBooleanChecker ())
|
||||
.AddAttribute ("Interval",
|
||||
"The CoDel algorithm interval for each FqCobalt queue",
|
||||
StringValue ("100ms"),
|
||||
MakeStringAccessor (&FqCobaltQueueDisc::m_interval),
|
||||
MakeStringChecker ())
|
||||
.AddAttribute ("Target",
|
||||
"The CoDel algorithm target queue delay for each FqCobalt queue",
|
||||
StringValue ("5ms"),
|
||||
MakeStringAccessor (&FqCobaltQueueDisc::m_target),
|
||||
MakeStringChecker ())
|
||||
.AddAttribute ("MaxSize",
|
||||
"The maximum number of packets accepted by this queue disc",
|
||||
QueueSizeValue (QueueSize ("10240p")),
|
||||
MakeQueueSizeAccessor (&QueueDisc::SetMaxSize,
|
||||
&QueueDisc::GetMaxSize),
|
||||
MakeQueueSizeChecker ())
|
||||
.AddAttribute ("Flows",
|
||||
"The number of queues into which the incoming packets are classified",
|
||||
UintegerValue (1024),
|
||||
MakeUintegerAccessor (&FqCobaltQueueDisc::m_flows),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("DropBatchSize",
|
||||
"The maximum number of packets dropped from the fat flow",
|
||||
UintegerValue (64),
|
||||
MakeUintegerAccessor (&FqCobaltQueueDisc::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 (&FqCobaltQueueDisc::m_perturbation),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("CeThreshold",
|
||||
"The FqCobalt CE threshold for marking packets",
|
||||
TimeValue (Time::Max ()),
|
||||
MakeTimeAccessor (&FqCobaltQueueDisc::m_ceThreshold),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("EnableSetAssociativeHash",
|
||||
"Enable/Disable Set Associative Hash",
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&FqCobaltQueueDisc::m_enableSetAssociativeHash),
|
||||
MakeBooleanChecker ())
|
||||
.AddAttribute ("SetWays",
|
||||
"The size of a set of queues (used by set associative hash)",
|
||||
UintegerValue (8),
|
||||
MakeUintegerAccessor (&FqCobaltQueueDisc::m_setWays),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("UseL4s",
|
||||
"True to use L4S (only ECT1 packets are marked at CE threshold)",
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&FqCobaltQueueDisc::m_useL4s),
|
||||
MakeBooleanChecker ())
|
||||
.AddAttribute ("Pdrop",
|
||||
"Marking Probability",
|
||||
DoubleValue (0),
|
||||
MakeDoubleAccessor (&FqCobaltQueueDisc::m_Pdrop),
|
||||
MakeDoubleChecker<double> ())
|
||||
.AddAttribute ("Increment",
|
||||
"Pdrop increment value",
|
||||
DoubleValue (1. / 256),
|
||||
MakeDoubleAccessor (&FqCobaltQueueDisc::m_increment),
|
||||
MakeDoubleChecker<double> ())
|
||||
.AddAttribute ("Decrement",
|
||||
"Pdrop decrement Value",
|
||||
DoubleValue (1. / 4096),
|
||||
MakeDoubleAccessor (&FqCobaltQueueDisc::m_decrement),
|
||||
MakeDoubleChecker<double> ())
|
||||
.AddAttribute ("BlueThreshold",
|
||||
"The Threshold after which Blue is enabled",
|
||||
TimeValue (MilliSeconds (400)),
|
||||
MakeTimeAccessor (&FqCobaltQueueDisc::m_blueThreshold),
|
||||
MakeTimeChecker ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
FqCobaltQueueDisc::FqCobaltQueueDisc ()
|
||||
: QueueDisc (QueueDiscSizePolicy::MULTIPLE_QUEUES, QueueSizeUnit::PACKETS),
|
||||
m_quantum (0)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
FqCobaltQueueDisc::~FqCobaltQueueDisc ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
void
|
||||
FqCobaltQueueDisc::SetQuantum (uint32_t quantum)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << quantum);
|
||||
m_quantum = quantum;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
FqCobaltQueueDisc::GetQuantum (void) const
|
||||
{
|
||||
return m_quantum;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
FqCobaltQueueDisc::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<FqCobaltFlow> (GetQueueDiscClass (it->second))->GetStatus () == FqCobaltFlow::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
|
||||
FqCobaltQueueDisc::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<FqCobaltFlow> flow;
|
||||
if (m_flowsIndices.find (h) == m_flowsIndices.end ())
|
||||
{
|
||||
NS_LOG_DEBUG ("Creating a new flow queue with index " << h);
|
||||
flow = m_flowFactory.Create<FqCobaltFlow> ();
|
||||
Ptr<QueueDisc> qd = m_queueDiscFactory.Create<QueueDisc> ();
|
||||
// If Cobalt, Set values of CobaltQueueDisc to match this QueueDisc
|
||||
Ptr<CobaltQueueDisc> cobalt = qd->GetObject<CobaltQueueDisc> ();
|
||||
if (cobalt)
|
||||
{
|
||||
cobalt->SetAttribute ("UseEcn", BooleanValue (m_useEcn));
|
||||
cobalt->SetAttribute ("CeThreshold", TimeValue (m_ceThreshold));
|
||||
cobalt->SetAttribute ("UseL4s", BooleanValue (m_useL4s));
|
||||
cobalt->SetAttribute ("BlueThreshold", TimeValue (m_blueThreshold));
|
||||
}
|
||||
qd->Initialize ();
|
||||
flow->SetQueueDisc (qd);
|
||||
flow->SetIndex (h);
|
||||
AddQueueDiscClass (flow);
|
||||
|
||||
m_flowsIndices[h] = GetNQueueDiscClasses () - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
flow = StaticCast<FqCobaltFlow> (GetQueueDiscClass (m_flowsIndices[h]));
|
||||
}
|
||||
|
||||
if (flow->GetStatus () == FqCobaltFlow::INACTIVE)
|
||||
{
|
||||
flow->SetStatus (FqCobaltFlow::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 FqCobaltDrop ()");
|
||||
FqCobaltDrop ();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Ptr<QueueDiscItem>
|
||||
FqCobaltQueueDisc::DoDequeue (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
Ptr<FqCobaltFlow> 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 (FqCobaltFlow::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 (FqCobaltFlow::OLD_FLOW);
|
||||
m_oldFlows.push_back (flow);
|
||||
m_newFlows.pop_front ();
|
||||
}
|
||||
else
|
||||
{
|
||||
flow->SetStatus (FqCobaltFlow::INACTIVE);
|
||||
m_oldFlows.pop_front ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_DEBUG ("Dequeued packet " << item->GetPacket ());
|
||||
}
|
||||
} while (item == 0);
|
||||
|
||||
flow->IncreaseDeficit (item->GetSize () * -1);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
bool
|
||||
FqCobaltQueueDisc::CheckConfig (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
if (GetNQueueDiscClasses () > 0)
|
||||
{
|
||||
NS_LOG_ERROR ("FqCobaltQueueDisc cannot have classes");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetNInternalQueues () > 0)
|
||||
{
|
||||
NS_LOG_ERROR ("FqCobaltQueueDisc 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
|
||||
FqCobaltQueueDisc::InitializeParams (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
m_flowFactory.SetTypeId ("ns3::FqCobaltFlow");
|
||||
|
||||
m_queueDiscFactory.SetTypeId ("ns3::CobaltQueueDisc");
|
||||
m_queueDiscFactory.Set ("MaxSize", QueueSizeValue (GetMaxSize ()));
|
||||
m_queueDiscFactory.Set ("Interval", StringValue (m_interval));
|
||||
m_queueDiscFactory.Set ("Target", StringValue (m_target));
|
||||
m_queueDiscFactory.Set ("Pdrop", DoubleValue (m_Pdrop));
|
||||
m_queueDiscFactory.Set ("Increment", DoubleValue (m_increment));
|
||||
m_queueDiscFactory.Set ("Decrement", DoubleValue (m_decrement));
|
||||
}
|
||||
|
||||
uint32_t
|
||||
FqCobaltQueueDisc::FqCobaltDrop (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
|
||||
|
||||
197
src/traffic-control/model/fq-cobalt-queue-disc.h
Normal file
197
src/traffic-control/model/fq-cobalt-queue-disc.h
Normal file
@@ -0,0 +1,197 @@
|
||||
/* -*- 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>
|
||||
*/
|
||||
|
||||
#ifndef FQ_COBALT_QUEUE_DISC
|
||||
#define FQ_COBALT_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 FqCobalt queue disc
|
||||
*/
|
||||
|
||||
class FqCobaltFlow : public QueueDiscClass {
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
/**
|
||||
* \brief FqCobaltFlow constructor
|
||||
*/
|
||||
FqCobaltFlow ();
|
||||
|
||||
virtual ~FqCobaltFlow ();
|
||||
|
||||
/**
|
||||
* \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 FqCobalt packet queue disc
|
||||
*/
|
||||
|
||||
class FqCobaltQueueDisc : public QueueDisc {
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
/**
|
||||
* \brief FqCobaltQueueDisc constructor
|
||||
*/
|
||||
FqCobaltQueueDisc ();
|
||||
|
||||
virtual ~FqCobaltQueueDisc ();
|
||||
|
||||
/**
|
||||
* \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 FqCobaltDrop (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);
|
||||
|
||||
std::string m_interval; //!< CoDel interval attribute
|
||||
std::string m_target; //!< CoDel target attribute
|
||||
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_useEcn; //!< True if ECN is used (packets are marked instead of being dropped)
|
||||
Time m_ceThreshold; //!< Threshold above which to CE mark
|
||||
bool m_enableSetAssociativeHash; //!< whether to enable set associative hash
|
||||
bool m_useL4s; //!< True if L4S is used (ECT1 packets are marked at CE threshold)
|
||||
double m_increment; //!< increment value for marking probability
|
||||
double m_decrement; //!< decrement value for marking probability
|
||||
double m_Pdrop; //!< Drop Probability
|
||||
Time m_blueThreshold; //!< Threshold to enable blue enhancement
|
||||
|
||||
std::list<Ptr<FqCobaltFlow> > m_newFlows; //!< The list of new flows
|
||||
std::list<Ptr<FqCobaltFlow> > 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_COBALT_QUEUE_DISC */
|
||||
|
||||
@@ -144,6 +144,8 @@ CobaltQueueDiscBasicEnqueueDequeue::DoRun (void)
|
||||
"Verify that we can actually set the attribute Interval");
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Target", StringValue ("4ms")), true,
|
||||
"Verify that we can actually set the attribute Target");
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("BlueThreshold", TimeValue (Time::Max ())), true,
|
||||
"Disable Blue enhancement");
|
||||
|
||||
if (m_mode == QueueSizeUnit::BYTES)
|
||||
{
|
||||
@@ -272,7 +274,8 @@ CobaltQueueDiscDropTest::RunDropTest (QueueSizeUnit mode)
|
||||
queue = CreateObject<CobaltQueueDisc> ();
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (mode, modeSize * 100))),
|
||||
true, "Verify that we can actually set the attribute MaxSize");
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("BlueThreshold", TimeValue (Time::Max ())), true,
|
||||
"Disable Blue enhancement");
|
||||
queue->Initialize ();
|
||||
|
||||
if (mode == QueueSizeUnit::BYTES)
|
||||
@@ -411,7 +414,8 @@ CobaltQueueDiscMarkTest::DoRun (void)
|
||||
true, "Verify that we can actually set the attribute MaxSize");
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("UseEcn", BooleanValue (false)),
|
||||
true, "Verify that we can actually set the attribute UseEcn");
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("BlueThreshold", TimeValue (Time::Max ())), true,
|
||||
"Disable Blue enhancement");
|
||||
queue->Initialize ();
|
||||
|
||||
// Not-ECT traffic to induce packet drop
|
||||
@@ -436,7 +440,8 @@ CobaltQueueDiscMarkTest::DoRun (void)
|
||||
true, "Verify that we can actually set the attribute MaxSize");
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("UseEcn", BooleanValue (true)),
|
||||
true, "Verify that we can actually set the attribute UseEcn");
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("BlueThreshold", TimeValue (Time::Max ())), true,
|
||||
"Disable Blue enhancement");
|
||||
queue->Initialize ();
|
||||
|
||||
// ECN capable traffic
|
||||
@@ -466,7 +471,8 @@ CobaltQueueDiscMarkTest::DoRun (void)
|
||||
true, "Verify that we can actually set the attribute MaxSize");
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("UseEcn", BooleanValue (true)),
|
||||
true, "Verify that we can actually set the attribute UseEcn");
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("BlueThreshold", TimeValue (Time::Max ())), true,
|
||||
"Disable Blue enhancement");
|
||||
queue->Initialize ();
|
||||
|
||||
// First 3 packets in the queue are ecnCapable
|
||||
@@ -529,7 +535,7 @@ CobaltQueueDiscMarkTest::Dequeue (Ptr<CobaltQueueDisc> queue, uint32_t modeSize,
|
||||
nPacketsBeforeFirstDrop = initialQSize;
|
||||
}
|
||||
}
|
||||
if (testCase == 2)
|
||||
if (testCase == 2)
|
||||
{
|
||||
if (initialMarkCount == 0 && currentTime > queue->GetTarget ())
|
||||
{
|
||||
@@ -540,8 +546,8 @@ CobaltQueueDiscMarkTest::Dequeue (Ptr<CobaltQueueDisc> queue, uint32_t modeSize,
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize, "There should be 1 packet dequeued.");
|
||||
NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
|
||||
NS_TEST_ASSERT_MSG_EQ (currentMarkCount, 0, "We are not in dropping state."
|
||||
"Sojourn time has just gone above target from below."
|
||||
"Hence, there should be no marked packets");
|
||||
"Sojourn time has just gone above target from below."
|
||||
"Hence, there should be no marked packets");
|
||||
}
|
||||
else if (currentTime >= queue->GetInterval ())
|
||||
{
|
||||
@@ -549,9 +555,9 @@ CobaltQueueDiscMarkTest::Dequeue (Ptr<CobaltQueueDisc> queue, uint32_t modeSize,
|
||||
currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
|
||||
currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize,
|
||||
"Sojourn time has been above target for at least interval."
|
||||
"We enter the dropping state and perform initial packet marking"
|
||||
"So there should be only 1 more packet dequeued.");
|
||||
"Sojourn time has been above target for at least interval."
|
||||
"We enter the dropping state and perform initial packet marking"
|
||||
"So there should be only 1 more packet dequeued.");
|
||||
NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
|
||||
NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 1, "There should be 1 marked packet");
|
||||
}
|
||||
@@ -563,23 +569,23 @@ CobaltQueueDiscMarkTest::Dequeue (Ptr<CobaltQueueDisc> queue, uint32_t modeSize,
|
||||
currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
|
||||
currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize, "We are in dropping state."
|
||||
"Sojourn is still above target."
|
||||
"There should be only 1 more packet dequeued");
|
||||
"Sojourn is still above target."
|
||||
"There should be only 1 more packet dequeued");
|
||||
NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
|
||||
NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 2, "There should be 2 marked packet as."
|
||||
"current dropnext is equal to current time.");
|
||||
"current dropnext is equal to current time.");
|
||||
}
|
||||
else if (currentTime.GetNanoSeconds () > initialDropNext)
|
||||
{
|
||||
currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
|
||||
currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize, "We are in dropping state."
|
||||
"It's time for packet to be marked"
|
||||
"So there should be only 1 more packet dequeued");
|
||||
"It's time for packet to be marked"
|
||||
"So there should be only 1 more packet dequeued");
|
||||
NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
|
||||
NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 3, "There should be 3 marked packet");
|
||||
NS_TEST_EXPECT_MSG_EQ (nPacketsBeforeFirstDrop, nPacketsBeforeFirstMark, "Number of packets in the queue before drop should be equal"
|
||||
"to number of packets in the queue before first mark as the behavior until packet N should be the same.");
|
||||
"to number of packets in the queue before first mark as the behavior until packet N should be the same.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -594,17 +600,17 @@ CobaltQueueDiscMarkTest::Dequeue (Ptr<CobaltQueueDisc> queue, uint32_t modeSize,
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize, "There should be 1 packet dequeued.");
|
||||
NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
|
||||
NS_TEST_ASSERT_MSG_EQ (currentMarkCount, 0, "We are not in dropping state."
|
||||
"Sojourn time has just gone above target from below."
|
||||
"Hence, there should be no marked packets");
|
||||
"Sojourn time has just gone above target from below."
|
||||
"Hence, there should be no marked packets");
|
||||
}
|
||||
else if (currentTime >= queue->GetInterval ())
|
||||
{
|
||||
currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
|
||||
currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize,
|
||||
"Sojourn time has been above target for at least interval."
|
||||
"We enter the dropping state and perform initial packet marking"
|
||||
"So there should be only 1 more packet dequeued.");
|
||||
"Sojourn time has been above target for at least interval."
|
||||
"We enter the dropping state and perform initial packet marking"
|
||||
"So there should be only 1 more packet dequeued.");
|
||||
NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
|
||||
NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 1, "There should be 1 marked packet");
|
||||
}
|
||||
@@ -616,19 +622,19 @@ CobaltQueueDiscMarkTest::Dequeue (Ptr<CobaltQueueDisc> queue, uint32_t modeSize,
|
||||
currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
|
||||
currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - modeSize, "We are in dropping state."
|
||||
"Sojourn is still above target."
|
||||
"So there should be only 1 more packet dequeued");
|
||||
"Sojourn is still above target."
|
||||
"So there should be only 1 more packet dequeued");
|
||||
NS_TEST_EXPECT_MSG_EQ (currentDropCount, 0, "There should not be any packet drops");
|
||||
NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 2, "There should be 2 marked packet"
|
||||
"as dropnext is equal to current time");
|
||||
"as dropnext is equal to current time");
|
||||
}
|
||||
else if (currentTime.GetNanoSeconds () > initialDropNext)
|
||||
{
|
||||
currentDropCount = queue->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP);
|
||||
currentMarkCount = queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK);
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), initialQSize - (m_dropNextCount + 1) * modeSize, "We are in dropping state."
|
||||
"It's time for packet to be dropped as packets are not ecnCapable"
|
||||
"The number of packets dequeued equals to the number of times m_dropNext is updated plus initial dequeue");
|
||||
"It's time for packet to be dropped as packets are not ecnCapable"
|
||||
"The number of packets dequeued equals to the number of times m_dropNext is updated plus initial dequeue");
|
||||
NS_TEST_EXPECT_MSG_EQ (currentDropCount, m_dropNextCount, "The number of drops equals to the number of times m_dropNext is updated");
|
||||
NS_TEST_EXPECT_MSG_EQ (currentMarkCount, 2, "There should still be only 2 marked packet");
|
||||
}
|
||||
@@ -637,6 +643,296 @@ CobaltQueueDiscMarkTest::Dequeue (Ptr<CobaltQueueDisc> queue, uint32_t modeSize,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup traffic-control-test
|
||||
* \ingroup tests
|
||||
*
|
||||
* \brief Test 4: Cobalt Queue Disc CE Threshold marking Test Item
|
||||
*/
|
||||
class CobaltQueueDiscCeThresholdTest : public TestCase
|
||||
{
|
||||
public:
|
||||
CobaltQueueDiscCeThresholdTest (QueueSizeUnit mode);
|
||||
virtual ~CobaltQueueDiscCeThresholdTest ();
|
||||
|
||||
private:
|
||||
virtual void DoRun (void);
|
||||
/**
|
||||
* \brief Enqueue function
|
||||
* \param queue the queue disc
|
||||
* \param size the size
|
||||
* \param nPkt the number of packets
|
||||
*/
|
||||
void Enqueue (Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
|
||||
/**
|
||||
* \brief Enqueue with delay function
|
||||
* \param queue the queue disc
|
||||
* \param size the size
|
||||
* \param nPkt the number of packets
|
||||
* \param delay the delay between the enqueueing of the packets
|
||||
*/
|
||||
void EnqueueWithDelay (Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, Time delay);
|
||||
/**
|
||||
* \brief Dequeue function
|
||||
* \param queue the queue disc
|
||||
* \param modeSize the mode size
|
||||
*/
|
||||
void Dequeue (Ptr<CobaltQueueDisc> queue, uint32_t modeSize);
|
||||
/**
|
||||
* \brief Dequeue with delay function
|
||||
* \param queue the queue disc
|
||||
* \param modeSize the mode size
|
||||
* \param nPkt the number of packets
|
||||
* \param delay the delay between the enqueueing of the packets
|
||||
*/
|
||||
void DequeueWithDelay (Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t nPkt, Time delay);
|
||||
QueueSizeUnit m_mode; ///< mode
|
||||
};
|
||||
|
||||
CobaltQueueDiscCeThresholdTest::CobaltQueueDiscCeThresholdTest (QueueSizeUnit mode)
|
||||
: TestCase ("Test CE Threshold marking")
|
||||
{
|
||||
m_mode = mode;
|
||||
}
|
||||
|
||||
CobaltQueueDiscCeThresholdTest::~CobaltQueueDiscCeThresholdTest ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CobaltQueueDiscCeThresholdTest::Enqueue (Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt)
|
||||
{
|
||||
Address dest;
|
||||
for (uint32_t i = 0; i < nPkt; i++)
|
||||
{
|
||||
queue->Enqueue (Create<CobaltQueueDiscTestItem> (Create<Packet> (size), dest, 0, true));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CobaltQueueDiscCeThresholdTest::EnqueueWithDelay (Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt, Time delay)
|
||||
{
|
||||
for (uint32_t i = 0; i < nPkt; i++)
|
||||
{
|
||||
Simulator::Schedule (Time (Seconds ((i + 1) * delay.GetSeconds ())), &CobaltQueueDiscCeThresholdTest::Enqueue, this, queue, size, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CobaltQueueDiscCeThresholdTest::Dequeue (Ptr<CobaltQueueDisc> queue, uint32_t modeSize)
|
||||
{
|
||||
Ptr<QueueDiscItem> item = queue->Dequeue ();
|
||||
|
||||
if (Simulator::Now () > MilliSeconds (11) && Simulator::Now () < MilliSeconds (28))
|
||||
{
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 1, "There should be only 1 packet"
|
||||
"mark, the delay between the enqueueing of the packets decreased after the"
|
||||
"1st mark (packet enqueued at 11ms) and increased for the packet enqueued after 20.6ms."
|
||||
"Queue delay remains below or equal to 1ms for the packet enqueued before 28ms");
|
||||
}
|
||||
if (Simulator::Now () > MilliSeconds (31) )
|
||||
{
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 3, "There should be 3 packet"
|
||||
"marks, the delay between the enqueueing of the packets decreased after 1st mark"
|
||||
"(packet enqueued at 11ms) and increased for the packet enqueued after 20.6ms."
|
||||
"Queue delay remains below 1ms for the packets enqueued before 28ms and increases"
|
||||
"for the packets enqueued after 28ms.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CobaltQueueDiscCeThresholdTest::DequeueWithDelay (Ptr<CobaltQueueDisc> queue, uint32_t modeSize, uint32_t nPkt, Time delay)
|
||||
{
|
||||
for (uint32_t i = 0; i < nPkt; i++)
|
||||
{
|
||||
Simulator::Schedule (Time (Seconds ((i + 1) * delay.GetSeconds ())), &CobaltQueueDiscCeThresholdTest::Dequeue, this, queue, modeSize);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CobaltQueueDiscCeThresholdTest::DoRun (void)
|
||||
{
|
||||
Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc> ();
|
||||
uint32_t pktSize = 1000;
|
||||
uint32_t modeSize = 0;
|
||||
|
||||
if (m_mode == QueueSizeUnit::BYTES)
|
||||
{
|
||||
modeSize = pktSize;
|
||||
}
|
||||
else if (m_mode == QueueSizeUnit::PACKETS)
|
||||
{
|
||||
modeSize = 1;
|
||||
}
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("UseEcn", BooleanValue (true)),
|
||||
true, "Verify that we can actually set the attribute UseEcn");
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("CeThreshold", TimeValue (MilliSeconds (1))),
|
||||
true, "Verify that we can actually set the attribute UseEcn");
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("BlueThreshold", TimeValue (Time::Max ())), true,
|
||||
"Disable Blue enhancement");
|
||||
queue->Initialize ();
|
||||
|
||||
// Enqueue 11 packets every 1ms
|
||||
EnqueueWithDelay (queue, pktSize, 11, MilliSeconds (1));
|
||||
|
||||
// With every dequeue, queue delay increases by 0.1ms as packet enqueues every 1ms while dequeues at 1.1ms
|
||||
// so at 11th dequeue, the dequeued packet should be marked.
|
||||
Time dequeueInterval = MicroSeconds (1100);
|
||||
DequeueWithDelay (queue, modeSize, 11, dequeueInterval);
|
||||
|
||||
// First mark occured for the packet enqueued at 11ms, ideally TCP would decrease sending rate
|
||||
// which can be simulated by increasing interval between subsequent enqueues, so packets are now enqueued with a delay 1.2ms.
|
||||
Time waitUntilFirstMark = MilliSeconds(11);
|
||||
Simulator::Schedule (waitUntilFirstMark, &CobaltQueueDiscCeThresholdTest::EnqueueWithDelay, this, queue, pktSize, 9, MicroSeconds (1200));
|
||||
|
||||
// Keep dequeueing with the same delay
|
||||
Simulator::Schedule (waitUntilFirstMark, &CobaltQueueDiscCeThresholdTest::DequeueWithDelay, this, queue, modeSize, 9, dequeueInterval);
|
||||
|
||||
// Queue delay becomes 0.2ms for the packet enqueued at 20.6ms, time to decrease interval between subsequent enqueues,
|
||||
// as ideally TCP would again start increasing sending rate
|
||||
Time waitUntilDecreasingEnqueueDelay = waitUntilFirstMark + MilliSeconds(9);
|
||||
Simulator::Schedule (waitUntilDecreasingEnqueueDelay, &CobaltQueueDiscCeThresholdTest::EnqueueWithDelay, this, queue, pktSize, 10, MilliSeconds (1));
|
||||
|
||||
// Keep dequeueing with the same delay
|
||||
Simulator::Schedule (waitUntilFirstMark, &CobaltQueueDiscCeThresholdTest::DequeueWithDelay, this, queue, modeSize, 10, dequeueInterval);
|
||||
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup traffic-control-test
|
||||
* \ingroup tests
|
||||
*
|
||||
* \brief Test 5: Cobalt Queue Disc Enhanced Blue Test Item
|
||||
* This test checks that the Blue Enhancement is working correctly. This test checks that Pdrop should increase as expected with
|
||||
* a certain number of dropped packets which is fixed by assigning a stream to the uniform random variable.
|
||||
* This test case is divided into 2 sub test cases
|
||||
* 1) With Blue Enhancement enabled, the test checks that Pdrop should increase as expected with
|
||||
* a certain number of dropped packets which is fixed by assigning a stream to the uniform random variable.
|
||||
* 2) Without Blue Enhancement, Pdrop should remain zero and there should not be any dropped packets as ECN is enabled.
|
||||
*/
|
||||
class CobaltQueueDiscEnhancedBlueTest : public TestCase
|
||||
{
|
||||
public:
|
||||
CobaltQueueDiscEnhancedBlueTest (QueueSizeUnit mode);
|
||||
virtual ~CobaltQueueDiscEnhancedBlueTest ();
|
||||
|
||||
private:
|
||||
virtual void DoRun (void);
|
||||
/**
|
||||
* Enqueue function
|
||||
* \param queue the queue disc
|
||||
* \param size the size
|
||||
* \param nPkt the number of packets
|
||||
*/
|
||||
void Enqueue (Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt);
|
||||
/**
|
||||
* \brief Dequeue function
|
||||
* \param queue the queue disc
|
||||
*/
|
||||
void Dequeue (Ptr<CobaltQueueDisc> queue);
|
||||
/**
|
||||
* \brief Dequeue with delay function
|
||||
* \param queue the queue disc
|
||||
* \param nPkt the number of packets
|
||||
* \param delay the delay between the enqueueing of the packets
|
||||
*/
|
||||
void DequeueWithDelay (Ptr<CobaltQueueDisc> queue, uint32_t nPkt, Time delay);
|
||||
QueueSizeUnit m_mode; ///< mode
|
||||
};
|
||||
|
||||
CobaltQueueDiscEnhancedBlueTest::CobaltQueueDiscEnhancedBlueTest (QueueSizeUnit mode)
|
||||
: TestCase ("Enhanced Blue tests verification for both packets and bytes mode")
|
||||
{
|
||||
m_mode = mode;
|
||||
}
|
||||
|
||||
CobaltQueueDiscEnhancedBlueTest::~CobaltQueueDiscEnhancedBlueTest ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CobaltQueueDiscEnhancedBlueTest::DoRun (void)
|
||||
|
||||
{
|
||||
uint32_t pktSize = 1500;
|
||||
uint32_t modeSize = 0;
|
||||
Ptr<CobaltQueueDisc> queue = CreateObject<CobaltQueueDisc> ();
|
||||
|
||||
if (m_mode == QueueSizeUnit::BYTES)
|
||||
{
|
||||
modeSize = pktSize;
|
||||
}
|
||||
else if (m_mode == QueueSizeUnit::PACKETS)
|
||||
{
|
||||
modeSize = 1;
|
||||
}
|
||||
queue->Initialize ();
|
||||
queue->AssignStreams (1);
|
||||
Enqueue (queue, modeSize, 200);
|
||||
DequeueWithDelay (queue, 100, MilliSeconds (10));
|
||||
|
||||
Simulator::Stop (Seconds (8.0));
|
||||
Simulator::Run ();
|
||||
|
||||
QueueDisc::Stats st = queue->GetStats ();
|
||||
|
||||
// The Pdrop value should increase, from it's default value of zero
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->GetPdrop (), 0.234375, "Pdrop should be increased by 1/256 for every packet whose sojourn time is above 400ms."
|
||||
" From the 41st dequeue until the last one, sojourn time is above 400ms, so 60 packets have sojourn time above 400ms"
|
||||
"hence Pdrop should be increased 60*(1/256) which is 0.234375");
|
||||
NS_TEST_EXPECT_MSG_EQ (st.GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 49, "There should a fixed number of drops (49 here)");
|
||||
Simulator::Destroy ();
|
||||
|
||||
|
||||
queue = CreateObject<CobaltQueueDisc> ();
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("UseEcn", BooleanValue (true)),
|
||||
true, "Verify that we can actually set the attribute UseEcn");
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("BlueThreshold", TimeValue (Time::Max ())), true,
|
||||
"Disable Blue enhancement");
|
||||
queue->Initialize ();
|
||||
Enqueue (queue, modeSize, 200);
|
||||
DequeueWithDelay (queue, 100, MilliSeconds (10));
|
||||
|
||||
Simulator::Stop (Seconds (8.0));
|
||||
Simulator::Run ();
|
||||
|
||||
st = queue->GetStats ();
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ (queue->GetPdrop (), 0, "Pdrop should be zero");
|
||||
NS_TEST_EXPECT_MSG_EQ (st.GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not any dropped packets");
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
void
|
||||
CobaltQueueDiscEnhancedBlueTest::Enqueue (Ptr<CobaltQueueDisc> queue, uint32_t size, uint32_t nPkt)
|
||||
{
|
||||
Address dest;
|
||||
for (uint32_t i = 0; i < nPkt; i++)
|
||||
{
|
||||
queue->Enqueue (Create<CobaltQueueDiscTestItem> (Create<Packet> (size), dest, 0, true));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CobaltQueueDiscEnhancedBlueTest::Dequeue (Ptr<CobaltQueueDisc> queue)
|
||||
{
|
||||
Ptr<QueueDiscItem> item = queue->Dequeue ();
|
||||
}
|
||||
|
||||
void
|
||||
CobaltQueueDiscEnhancedBlueTest::DequeueWithDelay (Ptr<CobaltQueueDisc> queue, uint32_t nPkt, Time delay)
|
||||
{
|
||||
for (uint32_t i = 0; i < nPkt; i++)
|
||||
{
|
||||
Simulator::Schedule (Time (Seconds ((i + 1) * delay.GetSeconds ())), &CobaltQueueDiscEnhancedBlueTest::Dequeue, this, queue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class CobaltQueueDiscTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
@@ -651,5 +947,11 @@ public:
|
||||
// Test 3: Mark test
|
||||
AddTestCase (new CobaltQueueDiscMarkTest (PACKETS), TestCase::QUICK);
|
||||
AddTestCase (new CobaltQueueDiscMarkTest (BYTES), TestCase::QUICK);
|
||||
// Test 4: CE threshold marking test
|
||||
AddTestCase (new CobaltQueueDiscCeThresholdTest (PACKETS), TestCase::QUICK);
|
||||
AddTestCase (new CobaltQueueDiscCeThresholdTest (BYTES), TestCase::QUICK);
|
||||
// Test 4: Blue enhancement test
|
||||
AddTestCase (new CobaltQueueDiscEnhancedBlueTest (PACKETS), TestCase::QUICK);
|
||||
AddTestCase (new CobaltQueueDiscEnhancedBlueTest (BYTES), TestCase::QUICK);
|
||||
}
|
||||
} g_cobaltQueueTestSuite; ///< the test suite
|
||||
|
||||
@@ -22,6 +22,7 @@ def build(bld):
|
||||
'model/mq-queue-disc.cc',
|
||||
'model/tbf-queue-disc.cc',
|
||||
'model/cobalt-queue-disc.cc',
|
||||
'model/fq-cobalt-queue-disc.cc',
|
||||
'helper/traffic-control-helper.cc',
|
||||
'helper/queue-disc-container.cc'
|
||||
]
|
||||
@@ -62,6 +63,7 @@ def build(bld):
|
||||
'model/mq-queue-disc.h',
|
||||
'model/tbf-queue-disc.h',
|
||||
'model/cobalt-queue-disc.h',
|
||||
'model/fq-cobalt-queue-disc.h',
|
||||
'helper/traffic-control-helper.h',
|
||||
'helper/queue-disc-container.h'
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user