traffic-control: CoDel is a queue disc now
This commit is contained in:
@@ -79,6 +79,7 @@ SOURCES = \
|
||||
$(SRC)/traffic-control/doc/queue-discs.rst \
|
||||
$(SRC)/traffic-control/doc/pfifo-fast.rst \
|
||||
$(SRC)/traffic-control/doc/red.rst \
|
||||
$(SRC)/traffic-control/doc/codel.rst \
|
||||
$(SRC)/spectrum/doc/spectrum.rst \
|
||||
$(SRC)/stats/doc/adaptor.rst \
|
||||
$(SRC)/stats/doc/aggregator.rst \
|
||||
|
||||
@@ -7,3 +7,4 @@ Traffic Control Layer
|
||||
queue-discs
|
||||
pfifo-fast
|
||||
red
|
||||
codel
|
||||
|
||||
140
src/traffic-control/doc/codel.rst
Normal file
140
src/traffic-control/doc/codel.rst
Normal file
@@ -0,0 +1,140 @@
|
||||
.. include:: replace.txt
|
||||
.. highlight:: cpp
|
||||
|
||||
CoDel queue disc
|
||||
----------------
|
||||
|
||||
This chapter describes the CoDel ([Nic12]_, [Nic14]_) queue disc implementation
|
||||
in |ns3|.
|
||||
|
||||
Developed by Kathleen Nichols and Van Jacobson as a solution to the
|
||||
bufferbloat [Buf14]_ problem, CoDel (Controlled Delay Management) is a queuing
|
||||
discipline that uses a packet's sojourn time (time in queue) to make
|
||||
decisions on packet drops.
|
||||
|
||||
Note that, starting from ns-3.25, CoDel is no longer a queue variant and
|
||||
cannot be installed as a NetDevice queue. Instead, CoDel is a queue disc
|
||||
and must be installed in the context of the traffic control (see the
|
||||
examples mentioned below).
|
||||
|
||||
|
||||
Model Description
|
||||
*****************
|
||||
|
||||
The source code for the CoDel model is located in the directory ``src/traffic-control/model``
|
||||
and consists of 2 files `codel-queue-disc.h` and `codel-queue-disc.cc` defining a CoDelQueueDisc
|
||||
class and a helper CoDelTimestampTag class. The code was ported to |ns3| by
|
||||
Andrew McGregor based on Linux kernel code implemented by Dave Täht and Eric Dumazet.
|
||||
|
||||
* class :cpp:class:`CoDelQueueDisc`: This class implements the main CoDel algorithm:
|
||||
|
||||
* ``CoDelQueueDisc::DoEnqueue ()``: This routine tags a packet with the current time before pushing it into the queue. The timestamp tag is used by ``CoDelQueue::DoDequeue()`` to compute the packet's sojourn time. If the queue is full upon the packet arrival, this routine will drop the packet and record the number of drops due to queue overflow, which is stored in `m_dropOverLimit`.
|
||||
|
||||
* ``CoDelQueueDisc::ShouldDrop ()``: This routine is ``CoDelQueueDisc::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``.
|
||||
|
||||
* ``CoDelQueueDisc::DoDequeue ()``: This routine performs the actual packet drop based on ``CoDelQueueDisc::ShouldDrop ()``'s return value and schedules the next drop.
|
||||
* class :cpp:class:`CoDelTimestampTag`: 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).
|
||||
|
||||
There are 2 branches to ``CoDelQueueDisc::DoDequeue ()``:
|
||||
|
||||
1. If the queue is currently in the dropping state, which means the sojourn time has remained above `m_target` for more than `m_interval`, the routine determines if it's OK to leave the dropping state or it's time for the next drop. When ``CoDelQueueDisc::ShouldDrop ()`` returns ``false``, the queue can move out of the dropping state (set `m_dropping` to ``false``). Otherwise, the queue continuously drops packets and updates the time for next drop (`m_dropNext`) until one of the following conditions is met:
|
||||
|
||||
1. The queue is empty, upon which the queue leaves the dropping state and exits ``CoDelQueueDisc::ShouldDrop ()`` routine;
|
||||
2. ``CoDelQueueDisc::ShouldDrop ()`` returns ``false`` (meaning the sojourn time goes below `m_target`) upon which the queue leaves the dropping state;
|
||||
3. It is not yet time for next drop (`m_dropNext` is less than current time) upon which the queue waits for the next packet dequeue to check the condition again.
|
||||
|
||||
2. If the queue is not in the dropping state, the routine enters the dropping state and drop the first packet if ``CoDelQueueDisc::ShouldDrop ()`` returns ``true`` (meaning the sojourn time has gone above `m_target` for at least `m_interval` for the first time or it has gone above again after the queue leaves the dropping state).
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [Nic12] K. Nichols and V. Jacobson, Controlling Queue Delay, ACM Queue, Vol. 10 No. 5, May 2012. Available online at `<http://queue.acm.org/detail.cfm?id=2209336>`_.
|
||||
|
||||
.. [Nic14] K. Nichols and V. Jacobson, Internet-Draft: Controlled Delay Active Queue Management, March 2014. Available online at `<http://tools.ietf.org/html/draft-nichols-tsvwg-codel-02>`_.
|
||||
|
||||
.. [Buf14] Bufferbloat.net. Available online at `<http://www.bufferbloat.net/>`_.
|
||||
|
||||
Attributes
|
||||
==========
|
||||
|
||||
The key attributes that the CoDelQueue class holds include the following:
|
||||
|
||||
* ``Mode:`` CoDel operating mode (BYTES, PACKETS, or ILLEGAL). The default mode is BYTES.
|
||||
* ``MaxPackets:`` The maximum number of packets the queue can hold. The default value is DEFAULT_CODEL_LIMIT, which is 1000 packets.
|
||||
* ``MaxBytes:`` The maximum number of bytes the queue can hold. The default value is 1500 * DEFAULT_CODEL_LIMIT, which is 1500 * 1000 bytes.
|
||||
* ``MinBytes:`` The CoDel algorithm minbytes parameter. The default value is 1500 bytes.
|
||||
* ``Interval:`` The sliding-minimum window. The default value is 100 ms.
|
||||
* ``Target:`` The CoDel algorithm target queue delay. The default value is 5 ms.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
The first example is `codel-vs-pfifo-basic-test.cc` located in ``src/traffic-control/examples``. To run the file (the first invocation below shows the available
|
||||
command-line options):
|
||||
|
||||
::
|
||||
|
||||
$ ./waf --run "codel-vs-pfifo-basic-test --PrintHelp"
|
||||
$ ./waf --run "codel-vs-pfifo-basic-test --queueType=CoDel --pcapFileName=codel.pcap --cwndTrFileName=cwndCodel.tr"
|
||||
|
||||
The expected output from the previous commands are two files: `codel.pcap` file and `cwndCoDel.tr` (ASCII trace) file The .pcap file can be analyzed using
|
||||
wireshark or tcptrace:
|
||||
|
||||
::
|
||||
|
||||
$ tcptrace -l -r -n -W codel.pcap
|
||||
|
||||
The second example is `codel-vs-pfifo-asymmetric.cc` located in ``src/traffic-control/examples``. This example is intended to model a typical cable modem
|
||||
deployment scenario. To run the file:
|
||||
|
||||
::
|
||||
|
||||
$ ./waf --run "codel-vs-pfifo-asymmetric --PrintHelp"
|
||||
$ ./waf --run codel-vs-pfifo-asymmetric
|
||||
|
||||
The expected output from the previous commands is six pcap files:
|
||||
|
||||
* codel-vs-pfifo-asymmetric-CoDel-server-lan.pcap
|
||||
* codel-vs-pfifo-asymmetric-CoDel-router-wan.pcap
|
||||
* codel-vs-pfifo-asymmetric-CoDel-router-lan.pcap
|
||||
* codel-vs-pfifo-asymmetric-CoDel-cmts-wan.pcap
|
||||
* codel-vs-pfifo-asymmetric-CoDel-cmts-lan.pcap
|
||||
* codel-vs-pfifo-asymmetric-CoDel-host-lan.pcap
|
||||
|
||||
One attribute file:
|
||||
|
||||
* codel-vs-pfifo-asymmetric-CoDel.attr
|
||||
|
||||
Five ASCII trace files:
|
||||
|
||||
* codel-vs-pfifo-asymmetric-CoDel-drop.tr
|
||||
* codel-vs-pfifo-asymmetric-CoDel-drop-state.tr
|
||||
* codel-vs-pfifo-asymmetric-CoDel-sojourn.tr
|
||||
* codel-vs-pfifo-asymmetric-CoDel-length.tr
|
||||
* codel-vs-pfifo-asymmetric-CoDel-cwnd.tr
|
||||
|
||||
Validation
|
||||
**********
|
||||
|
||||
The CoDel model is tested using :cpp:class:`CoDelQueueDiscTestSuite` class defined in `src/traffic-control/test/codel-queue-test-suite.cc`. The suite includes 5 test cases:
|
||||
|
||||
* Test 1: The first test checks the enqueue/dequeue with no drops and makes sure that CoDel attributes can be set correctly.
|
||||
* Test 2: The second test checks the enqueue with drops due to queue overflow.
|
||||
* Test 3: The third test checks the NewtonStep() arithmetic against explicit port of Linux implementation
|
||||
* Test 4: The fourth test checks the ControlLaw() against explicit port of Linux implementation
|
||||
* Test 5: The fifth test checks the enqueue/dequeue with drops according to CoDel algorithm
|
||||
|
||||
The test suite can be run using the following commands:
|
||||
|
||||
::
|
||||
|
||||
$ ./waf configure --enable-examples --enable-tests
|
||||
$ ./waf build
|
||||
$ ./test.py -s codel-queue-disc
|
||||
|
||||
or
|
||||
|
||||
::
|
||||
|
||||
$ NS_LOG="CoDelQueueDisc" ./waf --run "test-runner --suite=codel-queue-disc"
|
||||
|
||||
@@ -29,11 +29,13 @@
|
||||
#include "ns3/enum.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include "ns3/abort.h"
|
||||
#include "codel-queue.h"
|
||||
#include "codel-queue-disc.h"
|
||||
#include "ns3/object-factory.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("CoDelQueue");
|
||||
NS_LOG_COMPONENT_DEFINE ("CoDelQueueDisc");
|
||||
|
||||
/**
|
||||
* Performs a reciprocal divide, similar to the
|
||||
@@ -142,83 +144,77 @@ CoDelTimestampTag::GetTxTime (void) const
|
||||
return TimeStep (m_creationTime);
|
||||
}
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (CoDelQueue);
|
||||
NS_OBJECT_ENSURE_REGISTERED (CoDelQueueDisc);
|
||||
|
||||
TypeId CoDelQueue::GetTypeId (void)
|
||||
TypeId CoDelQueueDisc::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::CoDelQueue")
|
||||
.SetParent<Queue> ()
|
||||
.SetGroupName ("Internet")
|
||||
.AddConstructor<CoDelQueue> ()
|
||||
static TypeId tid = TypeId ("ns3::CoDelQueueDisc")
|
||||
.SetParent<QueueDisc> ()
|
||||
.SetGroupName ("TrafficControl")
|
||||
.AddConstructor<CoDelQueueDisc> ()
|
||||
.AddAttribute ("Mode",
|
||||
"Whether to use Bytes (see MaxBytes) or Packets (see MaxPackets) as the maximum queue size metric.",
|
||||
EnumValue (QUEUE_MODE_BYTES),
|
||||
MakeEnumAccessor (&CoDelQueue::SetMode),
|
||||
MakeEnumChecker (QUEUE_MODE_BYTES, "QUEUE_MODE_BYTES",
|
||||
QUEUE_MODE_PACKETS, "QUEUE_MODE_PACKETS"))
|
||||
EnumValue (Queue::QUEUE_MODE_BYTES),
|
||||
MakeEnumAccessor (&CoDelQueueDisc::SetMode),
|
||||
MakeEnumChecker (Queue::QUEUE_MODE_BYTES, "QUEUE_MODE_BYTES",
|
||||
Queue::QUEUE_MODE_PACKETS, "QUEUE_MODE_PACKETS"))
|
||||
.AddAttribute ("MaxPackets",
|
||||
"The maximum number of packets accepted by this CoDelQueue.",
|
||||
"The maximum number of packets accepted by this CoDelQueueDisc.",
|
||||
UintegerValue (DEFAULT_CODEL_LIMIT),
|
||||
MakeUintegerAccessor (&CoDelQueue::m_maxPackets),
|
||||
MakeUintegerAccessor (&CoDelQueueDisc::m_maxPackets),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("MaxBytes",
|
||||
"The maximum number of bytes accepted by this CoDelQueue.",
|
||||
"The maximum number of bytes accepted by this CoDelQueueDisc.",
|
||||
UintegerValue (1500 * DEFAULT_CODEL_LIMIT),
|
||||
MakeUintegerAccessor (&CoDelQueue::m_maxBytes),
|
||||
MakeUintegerAccessor (&CoDelQueueDisc::m_maxBytes),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("MinBytes",
|
||||
"The CoDel algorithm minbytes parameter.",
|
||||
UintegerValue (1500),
|
||||
MakeUintegerAccessor (&CoDelQueue::m_minBytes),
|
||||
MakeUintegerAccessor (&CoDelQueueDisc::m_minBytes),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("Interval",
|
||||
"The CoDel algorithm interval",
|
||||
StringValue ("100ms"),
|
||||
MakeTimeAccessor (&CoDelQueue::m_interval),
|
||||
MakeTimeAccessor (&CoDelQueueDisc::m_interval),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("Target",
|
||||
"The CoDel algorithm target queue delay",
|
||||
StringValue ("5ms"),
|
||||
MakeTimeAccessor (&CoDelQueue::m_target),
|
||||
MakeTimeAccessor (&CoDelQueueDisc::m_target),
|
||||
MakeTimeChecker ())
|
||||
.AddTraceSource ("Count",
|
||||
"CoDel count",
|
||||
MakeTraceSourceAccessor (&CoDelQueue::m_count),
|
||||
MakeTraceSourceAccessor (&CoDelQueueDisc::m_count),
|
||||
"ns3::TracedValueCallback::Uint32")
|
||||
.AddTraceSource ("DropCount",
|
||||
"CoDel drop count",
|
||||
MakeTraceSourceAccessor (&CoDelQueue::m_dropCount),
|
||||
MakeTraceSourceAccessor (&CoDelQueueDisc::m_dropCount),
|
||||
"ns3::TracedValueCallback::Uint32")
|
||||
.AddTraceSource ("LastCount",
|
||||
"CoDel lastcount",
|
||||
MakeTraceSourceAccessor (&CoDelQueue::m_lastCount),
|
||||
MakeTraceSourceAccessor (&CoDelQueueDisc::m_lastCount),
|
||||
"ns3::TracedValueCallback::Uint32")
|
||||
.AddTraceSource ("DropState",
|
||||
"Dropping state",
|
||||
MakeTraceSourceAccessor (&CoDelQueue::m_dropping),
|
||||
MakeTraceSourceAccessor (&CoDelQueueDisc::m_dropping),
|
||||
"ns3::TracedValueCallback::Bool")
|
||||
.AddTraceSource ("BytesInQueue",
|
||||
"Number of bytes in the queue",
|
||||
MakeTraceSourceAccessor (&CoDelQueue::m_bytesInQueue),
|
||||
"ns3::TracedValueCallback::Uint32")
|
||||
.AddTraceSource ("Sojourn",
|
||||
"Time in the queue",
|
||||
MakeTraceSourceAccessor (&CoDelQueue::m_sojourn),
|
||||
MakeTraceSourceAccessor (&CoDelQueueDisc::m_sojourn),
|
||||
"ns3::Time::TracedValueCallback")
|
||||
.AddTraceSource ("DropNext",
|
||||
"Time until next packet drop",
|
||||
MakeTraceSourceAccessor (&CoDelQueue::m_dropNext),
|
||||
MakeTraceSourceAccessor (&CoDelQueueDisc::m_dropNext),
|
||||
"ns3::TracedValueCallback::Uint32")
|
||||
;
|
||||
|
||||
return tid;
|
||||
}
|
||||
|
||||
CoDelQueue::CoDelQueue ()
|
||||
: Queue (),
|
||||
m_packets (),
|
||||
CoDelQueueDisc::CoDelQueueDisc ()
|
||||
: QueueDisc (),
|
||||
m_maxBytes (),
|
||||
m_bytesInQueue (0),
|
||||
m_count (0),
|
||||
m_dropCount (0),
|
||||
m_lastCount (0),
|
||||
@@ -236,13 +232,13 @@ CoDelQueue::CoDelQueue ()
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
CoDelQueue::~CoDelQueue ()
|
||||
CoDelQueueDisc::~CoDelQueueDisc ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
void
|
||||
CoDelQueue::NewtonStep (void)
|
||||
CoDelQueueDisc::NewtonStep (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
uint32_t invsqrt = ((uint32_t) m_recInvSqrt) << REC_INV_SQRT_SHIFT;
|
||||
@@ -255,44 +251,44 @@ CoDelQueue::NewtonStep (void)
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CoDelQueue::ControlLaw (uint32_t t)
|
||||
CoDelQueueDisc::ControlLaw (uint32_t t)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return t + ReciprocalDivide (Time2CoDel (m_interval), m_recInvSqrt << REC_INV_SQRT_SHIFT);
|
||||
}
|
||||
|
||||
void
|
||||
CoDelQueue::SetMode (CoDelQueue::QueueMode mode)
|
||||
CoDelQueueDisc::SetMode (Queue::QueueMode mode)
|
||||
{
|
||||
NS_LOG_FUNCTION (mode);
|
||||
m_mode = mode;
|
||||
}
|
||||
|
||||
CoDelQueue::QueueMode
|
||||
CoDelQueue::GetMode (void)
|
||||
Queue::QueueMode
|
||||
CoDelQueueDisc::GetMode (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_mode;
|
||||
}
|
||||
|
||||
bool
|
||||
CoDelQueue::DoEnqueue (Ptr<QueueItem> item)
|
||||
CoDelQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << item);
|
||||
Ptr<Packet> p = item->GetPacket ();
|
||||
|
||||
if (m_mode == QUEUE_MODE_PACKETS && (m_packets.size () + 1 > m_maxPackets))
|
||||
if (m_mode == Queue::QUEUE_MODE_PACKETS && (GetInternalQueue (0)->GetNPackets () + 1 > m_maxPackets))
|
||||
{
|
||||
NS_LOG_LOGIC ("Queue full (at max packets) -- droppping pkt");
|
||||
Drop (p);
|
||||
Drop (item);
|
||||
++m_dropOverLimit;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_mode == QUEUE_MODE_BYTES && (m_bytesInQueue + item->GetPacketSize () > m_maxBytes))
|
||||
if (m_mode == Queue::QUEUE_MODE_BYTES && (GetInternalQueue (0)->GetNBytes () + item->GetPacketSize () > m_maxBytes))
|
||||
{
|
||||
NS_LOG_LOGIC ("Queue full (packet would exceed max bytes) -- droppping pkt");
|
||||
Drop (p);
|
||||
Drop (item);
|
||||
++m_dropOverLimit;
|
||||
return false;
|
||||
}
|
||||
@@ -300,18 +296,17 @@ CoDelQueue::DoEnqueue (Ptr<QueueItem> item)
|
||||
// Tag packet with current time for DoDequeue() to compute sojourn time
|
||||
CoDelTimestampTag tag;
|
||||
p->AddPacketTag (tag);
|
||||
|
||||
GetInternalQueue (0)->Enqueue (item);
|
||||
|
||||
m_bytesInQueue += item->GetPacketSize ();
|
||||
m_packets.push (item);
|
||||
|
||||
NS_LOG_LOGIC ("Number packets " << m_packets.size ());
|
||||
NS_LOG_LOGIC ("Number bytes " << m_bytesInQueue);
|
||||
NS_LOG_LOGIC ("Number packets " << GetInternalQueue (0)->GetNPackets ());
|
||||
NS_LOG_LOGIC ("Number bytes " << GetInternalQueue (0)->GetNBytes ());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CoDelQueue::OkToDrop (Ptr<Packet> p, uint32_t now)
|
||||
CoDelQueueDisc::OkToDrop (Ptr<Packet> p, uint32_t now)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
CoDelTimestampTag tag;
|
||||
@@ -326,7 +321,7 @@ CoDelQueue::OkToDrop (Ptr<Packet> p, uint32_t now)
|
||||
uint32_t sojournTime = Time2CoDel (delta);
|
||||
|
||||
if (CoDelTimeBefore (sojournTime, Time2CoDel (m_target))
|
||||
|| m_bytesInQueue < m_minBytes)
|
||||
|| GetInternalQueue (0)->GetNBytes () < m_minBytes)
|
||||
{
|
||||
// went below so we'll stay below for at least q->interval
|
||||
NS_LOG_LOGIC ("Sojourn time is below target or number of bytes in queue is less than minBytes; packet should not be dropped");
|
||||
@@ -352,12 +347,12 @@ CoDelQueue::OkToDrop (Ptr<Packet> p, uint32_t now)
|
||||
return okToDrop;
|
||||
}
|
||||
|
||||
Ptr<QueueItem>
|
||||
CoDelQueue::DoDequeue (void)
|
||||
Ptr<QueueDiscItem>
|
||||
CoDelQueueDisc::DoDequeue (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
if (m_packets.empty ())
|
||||
if (GetInternalQueue (0)->IsEmpty ())
|
||||
{
|
||||
// Leave dropping state when queue is empty
|
||||
m_dropping = false;
|
||||
@@ -366,14 +361,12 @@ CoDelQueue::DoDequeue (void)
|
||||
return 0;
|
||||
}
|
||||
uint32_t now = CoDelGetTime ();
|
||||
Ptr<QueueItem> item = m_packets.front ();
|
||||
m_packets.pop ();
|
||||
Ptr<QueueDiscItem> item = StaticCast<QueueDiscItem> (GetInternalQueue (0)->Dequeue ());
|
||||
Ptr<Packet> p = item->GetPacket ();
|
||||
m_bytesInQueue -= item->GetPacketSize ();
|
||||
|
||||
NS_LOG_LOGIC ("Popped " << item);
|
||||
NS_LOG_LOGIC ("Number packets remaining " << m_packets.size ());
|
||||
NS_LOG_LOGIC ("Number bytes remaining " << m_bytesInQueue);
|
||||
NS_LOG_LOGIC ("Number packets remaining " << GetInternalQueue (0)->GetNPackets ());
|
||||
NS_LOG_LOGIC ("Number bytes remaining " << GetInternalQueue (0)->GetNBytes ());
|
||||
|
||||
// Determine if p should be dropped
|
||||
bool okToDrop = OkToDrop (p, now);
|
||||
@@ -401,31 +394,24 @@ CoDelQueue::DoDequeue (void)
|
||||
// rates so high that the next drop should happen now,
|
||||
// hence the while loop.
|
||||
NS_LOG_LOGIC ("Sojourn time is still above target and it's time for next drop; dropping " << p);
|
||||
Drop (p);
|
||||
|
||||
// p was in queue, trace dequeue and update stats manually
|
||||
m_traceDequeue (p);
|
||||
m_nBytes -= item->GetPacketSize ();
|
||||
m_nPackets--;
|
||||
Drop (item);
|
||||
|
||||
++m_dropCount;
|
||||
++m_count;
|
||||
NewtonStep ();
|
||||
if (m_packets.empty ())
|
||||
if (GetInternalQueue (0)->IsEmpty ())
|
||||
{
|
||||
m_dropping = false;
|
||||
NS_LOG_LOGIC ("Queue empty");
|
||||
++m_states;
|
||||
return 0;
|
||||
}
|
||||
item = m_packets.front ();
|
||||
m_packets.pop ();
|
||||
item = StaticCast<QueueDiscItem> (GetInternalQueue (0)->Dequeue ());
|
||||
p = item ->GetPacket ();
|
||||
m_bytesInQueue -= item->GetPacketSize ();
|
||||
|
||||
NS_LOG_LOGIC ("Popped " << item);
|
||||
NS_LOG_LOGIC ("Number packets remaining " << m_packets.size ());
|
||||
NS_LOG_LOGIC ("Number bytes remaining " << m_bytesInQueue);
|
||||
NS_LOG_LOGIC ("Number packets remaining " << GetInternalQueue (0)->GetNPackets ());
|
||||
NS_LOG_LOGIC ("Number bytes remaining " << GetInternalQueue (0)->GetNBytes ());
|
||||
|
||||
if (!OkToDrop (p, now))
|
||||
{
|
||||
@@ -453,14 +439,9 @@ CoDelQueue::DoDequeue (void)
|
||||
// Drop the first packet and enter dropping state unless the queue is empty
|
||||
NS_LOG_LOGIC ("Sojourn time goes above target, dropping the first packet " << p << " and entering the dropping state");
|
||||
++m_dropCount;
|
||||
Drop (p);
|
||||
Drop (item);
|
||||
|
||||
// p was in queue, trace the dequeue and update stats manually
|
||||
m_traceDequeue (p);
|
||||
m_nBytes -= item->GetPacketSize ();
|
||||
m_nPackets--;
|
||||
|
||||
if (m_packets.empty ())
|
||||
if (GetInternalQueue (0)->IsEmpty ())
|
||||
{
|
||||
m_dropping = false;
|
||||
okToDrop = false;
|
||||
@@ -469,14 +450,12 @@ CoDelQueue::DoDequeue (void)
|
||||
}
|
||||
else
|
||||
{
|
||||
item = m_packets.front ();
|
||||
m_packets.pop ();
|
||||
item = StaticCast<QueueDiscItem> (GetInternalQueue (0)->Dequeue ());
|
||||
p = item->GetPacket ();
|
||||
m_bytesInQueue -= item->GetPacketSize ();
|
||||
|
||||
NS_LOG_LOGIC ("Popped " << item);
|
||||
NS_LOG_LOGIC ("Number packets remaining " << m_packets.size ());
|
||||
NS_LOG_LOGIC ("Number bytes remaining " << m_bytesInQueue);
|
||||
NS_LOG_LOGIC ("Number packets remaining " << GetInternalQueue (0)->GetNPackets ());
|
||||
NS_LOG_LOGIC ("Number bytes remaining " << GetInternalQueue (0)->GetNBytes ());
|
||||
|
||||
okToDrop = OkToDrop (p, now);
|
||||
m_dropping = true;
|
||||
@@ -509,16 +488,16 @@ CoDelQueue::DoDequeue (void)
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CoDelQueue::GetQueueSize (void)
|
||||
CoDelQueueDisc::GetQueueSize (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
if (GetMode () == QUEUE_MODE_BYTES)
|
||||
if (GetMode () == Queue::QUEUE_MODE_BYTES)
|
||||
{
|
||||
return m_bytesInQueue;
|
||||
return GetInternalQueue (0)->GetNBytes ();
|
||||
}
|
||||
else if (GetMode () == QUEUE_MODE_PACKETS)
|
||||
else if (GetMode () == Queue::QUEUE_MODE_PACKETS)
|
||||
{
|
||||
return m_packets.size ();
|
||||
return GetInternalQueue (0)->GetNPackets ();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -527,84 +506,142 @@ CoDelQueue::GetQueueSize (void)
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CoDelQueue::GetDropOverLimit (void)
|
||||
CoDelQueueDisc::GetDropOverLimit (void)
|
||||
{
|
||||
return m_dropOverLimit;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CoDelQueue::GetDropCount (void)
|
||||
CoDelQueueDisc::GetDropCount (void)
|
||||
{
|
||||
return m_dropCount;
|
||||
}
|
||||
|
||||
Time
|
||||
CoDelQueue::GetTarget (void)
|
||||
CoDelQueueDisc::GetTarget (void)
|
||||
{
|
||||
return m_target;
|
||||
}
|
||||
|
||||
Time
|
||||
CoDelQueue::GetInterval (void)
|
||||
CoDelQueueDisc::GetInterval (void)
|
||||
{
|
||||
return m_interval;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CoDelQueue::GetDropNext (void)
|
||||
CoDelQueueDisc::GetDropNext (void)
|
||||
{
|
||||
return m_dropNext;
|
||||
}
|
||||
|
||||
Ptr<const QueueItem>
|
||||
CoDelQueue::DoPeek (void) const
|
||||
Ptr<const QueueDiscItem>
|
||||
CoDelQueueDisc::DoPeek (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
if (m_packets.empty ())
|
||||
if (GetInternalQueue (0)->IsEmpty ())
|
||||
{
|
||||
NS_LOG_LOGIC ("Queue empty");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Ptr<QueueItem> item = m_packets.front ();
|
||||
Ptr<const QueueDiscItem> item = StaticCast<const QueueDiscItem> (GetInternalQueue (0)->Peek ());
|
||||
|
||||
NS_LOG_LOGIC ("Number packets " << m_packets.size ());
|
||||
NS_LOG_LOGIC ("Number bytes " << m_bytesInQueue);
|
||||
NS_LOG_LOGIC ("Number packets " << GetInternalQueue (0)->GetNPackets ());
|
||||
NS_LOG_LOGIC ("Number bytes " << GetInternalQueue (0)->GetNBytes ());
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
bool
|
||||
CoDelQueue::CoDelTimeAfter (uint32_t a, uint32_t b)
|
||||
CoDelQueueDisc::CoDelTimeAfter (uint32_t a, uint32_t b)
|
||||
{
|
||||
return ((int)(a) - (int)(b) > 0);
|
||||
}
|
||||
|
||||
bool
|
||||
CoDelQueue::CoDelTimeAfterEq (uint32_t a, uint32_t b)
|
||||
CoDelQueueDisc::CoDelTimeAfterEq (uint32_t a, uint32_t b)
|
||||
{
|
||||
return ((int)(a) - (int)(b) >= 0);
|
||||
}
|
||||
|
||||
bool
|
||||
CoDelQueue::CoDelTimeBefore (uint32_t a, uint32_t b)
|
||||
CoDelQueueDisc::CoDelTimeBefore (uint32_t a, uint32_t b)
|
||||
{
|
||||
return ((int)(a) - (int)(b) < 0);
|
||||
}
|
||||
|
||||
bool
|
||||
CoDelQueue::CoDelTimeBeforeEq (uint32_t a, uint32_t b)
|
||||
CoDelQueueDisc::CoDelTimeBeforeEq (uint32_t a, uint32_t b)
|
||||
{
|
||||
return ((int)(a) - (int)(b) <= 0);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CoDelQueue::Time2CoDel (Time t)
|
||||
CoDelQueueDisc::Time2CoDel (Time t)
|
||||
{
|
||||
return (t.GetNanoSeconds () >> CODEL_SHIFT);
|
||||
}
|
||||
|
||||
bool
|
||||
CoDelQueueDisc::CheckConfig (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
if (GetNQueueDiscClasses () > 0)
|
||||
{
|
||||
NS_LOG_ERROR ("CoDelQueueDisc cannot have classes");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetNPacketFilters () > 0)
|
||||
{
|
||||
NS_LOG_ERROR ("CoDelQueueDisc cannot have packet filters");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetNInternalQueues () == 0)
|
||||
{
|
||||
// create a DropTail queue
|
||||
Ptr<Queue> queue = CreateObjectWithAttributes<DropTailQueue> ("Mode", EnumValue (m_mode));
|
||||
if (m_mode == Queue::QUEUE_MODE_PACKETS)
|
||||
{
|
||||
queue->SetMaxPackets (m_maxPackets);
|
||||
}
|
||||
else
|
||||
{
|
||||
queue->SetMaxBytes (m_maxBytes);
|
||||
}
|
||||
AddInternalQueue (queue);
|
||||
}
|
||||
|
||||
if (GetNInternalQueues () != 1)
|
||||
{
|
||||
NS_LOG_ERROR ("CoDelQueueDisc needs 1 internal queue");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetInternalQueue (0)->GetMode () != m_mode)
|
||||
{
|
||||
NS_LOG_ERROR ("The mode of the provided queue does not match the mode set on the CoDelQueueDisc");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((m_mode == Queue::QUEUE_MODE_PACKETS && GetInternalQueue (0)->GetMaxPackets () < m_maxPackets) ||
|
||||
(m_mode == Queue::QUEUE_MODE_BYTES && GetInternalQueue (0)->GetMaxBytes () < m_maxBytes))
|
||||
{
|
||||
NS_LOG_ERROR ("The size of the internal queue is less than the queue disc limit");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CoDelQueueDisc::InitializeParams (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
|
||||
@@ -28,17 +28,16 @@
|
||||
#ifndef CODEL_H
|
||||
#define CODEL_H
|
||||
|
||||
#include <queue>
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/queue.h"
|
||||
#include "ns3/queue-disc.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/string.h"
|
||||
#include "ns3/traced-value.h"
|
||||
#include "ns3/trace-source-accessor.h"
|
||||
|
||||
class CoDelQueueNewtonStepTest; // Forward declaration for unit test
|
||||
class CoDelQueueControlLawTest; // Forward declaration for unit test
|
||||
class CoDelQueueDiscNewtonStepTest; // Forward declaration for unit test
|
||||
class CoDelQueueDiscControlLawTest; // Forward declaration for unit test
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -55,12 +54,12 @@ static const int CODEL_SHIFT = 10;
|
||||
class TraceContainer;
|
||||
|
||||
/**
|
||||
* \ingroup queue
|
||||
* \ingroup traffic-control
|
||||
*
|
||||
* \brief A CoDel packet queue
|
||||
* \brief A CoDel packet queue disc
|
||||
*/
|
||||
|
||||
class CoDelQueue : public Queue
|
||||
class CoDelQueueDisc : public QueueDisc
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -71,27 +70,27 @@ public:
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
/**
|
||||
* \brief CoDelQueue Constructor
|
||||
* \brief CoDelQueueDisc Constructor
|
||||
*
|
||||
* Creates a CoDel queue
|
||||
*/
|
||||
CoDelQueue ();
|
||||
CoDelQueueDisc ();
|
||||
|
||||
virtual ~CoDelQueue ();
|
||||
virtual ~CoDelQueueDisc ();
|
||||
|
||||
/**
|
||||
* \brief Set the operating mode of this device.
|
||||
*
|
||||
* \param mode The operating mode of this device.
|
||||
*/
|
||||
void SetMode (CoDelQueue::QueueMode mode);
|
||||
void SetMode (Queue::QueueMode mode);
|
||||
|
||||
/**
|
||||
* \brief Get the encapsulation mode of this device.
|
||||
*
|
||||
* \returns The encapsulation mode of this device.
|
||||
*/
|
||||
CoDelQueue::QueueMode GetMode (void);
|
||||
Queue::QueueMode GetMode (void);
|
||||
|
||||
/**
|
||||
* \brief Get the current value of the queue in bytes or packets.
|
||||
@@ -137,15 +136,15 @@ public:
|
||||
uint32_t GetDropNext (void);
|
||||
|
||||
private:
|
||||
friend class::CoDelQueueNewtonStepTest; // Test code
|
||||
friend class::CoDelQueueControlLawTest; // Test code
|
||||
friend class::CoDelQueueDiscNewtonStepTest; // Test code
|
||||
friend class::CoDelQueueDiscControlLawTest; // Test code
|
||||
/**
|
||||
* \brief Add a packet to the queue
|
||||
*
|
||||
* \param item The item to be added
|
||||
* \returns True if the packet can be added, False if the packet is dropped due to full queue
|
||||
*/
|
||||
virtual bool DoEnqueue (Ptr<QueueItem> item);
|
||||
virtual bool DoEnqueue (Ptr<QueueDiscItem> item);
|
||||
|
||||
/**
|
||||
* \brief Remove a packet from queue based on the current state
|
||||
@@ -156,9 +155,10 @@ private:
|
||||
*
|
||||
* \returns The packet that is examined
|
||||
*/
|
||||
virtual Ptr<QueueItem> DoDequeue (void);
|
||||
virtual Ptr<QueueDiscItem> DoDequeue (void);
|
||||
|
||||
virtual Ptr<const QueueItem> DoPeek (void) const;
|
||||
virtual Ptr<const QueueDiscItem> DoPeek (void) const;
|
||||
virtual bool CheckConfig (void);
|
||||
|
||||
/**
|
||||
* \brief Calculate the reciprocal square root of m_count by using Newton's method
|
||||
@@ -223,10 +223,10 @@ private:
|
||||
*/
|
||||
uint32_t Time2CoDel (Time t);
|
||||
|
||||
std::queue<Ptr<QueueItem> > m_packets; //!< The packet queue
|
||||
virtual void InitializeParams (void);
|
||||
|
||||
uint32_t m_maxPackets; //!< Max # of packets accepted by the queue
|
||||
uint32_t m_maxBytes; //!< Max # of bytes accepted by the queue
|
||||
TracedValue<uint32_t> m_bytesInQueue; //!< The total number of bytes in queue
|
||||
uint32_t m_minBytes; //!< Minimum bytes in queue to allow a packet drop
|
||||
Time m_interval; //!< 100 ms sliding minimum time window width
|
||||
Time m_target; //!< 5 ms target queue delay
|
||||
@@ -242,7 +242,7 @@ private:
|
||||
uint32_t m_state3; //!< Number of times we enter drop state and drop the fist packet
|
||||
uint32_t m_states; //!< Total number of times we are in state 1, state 2, or state 3
|
||||
uint32_t m_dropOverLimit; //!< The number of packets dropped due to full queue
|
||||
QueueMode m_mode; //!< The operating mode (Bytes or packets)
|
||||
Queue::QueueMode m_mode; //!< The operating mode (Bytes or packets)
|
||||
TracedValue<Time> m_sojourn; //!< Time in queue
|
||||
};
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ def build(bld):
|
||||
'model/queue-disc.cc',
|
||||
'model/pfifo-fast-queue-disc.cc',
|
||||
'model/red-queue-disc.cc',
|
||||
'model/codel-queue-disc.cc',
|
||||
'helper/traffic-control-helper.cc',
|
||||
'helper/queue-disc-container.cc'
|
||||
]
|
||||
@@ -32,6 +33,7 @@ def build(bld):
|
||||
'model/queue-disc.h',
|
||||
'model/pfifo-fast-queue-disc.h',
|
||||
'model/red-queue-disc.h',
|
||||
'model/codel-queue-disc.h',
|
||||
'helper/traffic-control-helper.h',
|
||||
'helper/queue-disc-container.h'
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user