traffic-control: CoDel is a queue disc now

This commit is contained in:
Pasquale Imputato
2016-03-08 10:48:18 -08:00
parent 586d3d9e37
commit f2ddfb2948
6 changed files with 305 additions and 124 deletions

View File

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

View File

@@ -7,3 +7,4 @@ Traffic Control Layer
queue-discs
pfifo-fast
red
codel

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

View File

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

View File

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

View File

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