changes suggested in original code review, and aditional improvements made during 2014 GSoC project

This commit is contained in:
Anh Nguyen
2014-09-04 12:24:07 -07:00
parent 16e4f9b004
commit 153479dac9
2 changed files with 406 additions and 236 deletions

View File

@@ -14,7 +14,7 @@
* 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
*
*
* Codel, the COntrolled DELay Queueing discipline
* Based on ns2 simulation code presented by Kathie Nichols
*
@@ -35,25 +35,15 @@ NS_LOG_COMPONENT_DEFINE ("CoDelQueue");
namespace ns3 {
#define BITS_PER_LONG (8 * sizeof (unsigned long))
/* borrowed from the linux kernel */
#define do_div(n,base) \
({ \
int __res; \
__res = ((unsigned long)n) % (unsigned int)base; \
n = ((unsigned long)n) / (unsigned int)base; \
__res; \
})
static inline uint32_t reciprocal_divide(uint32_t A, uint32_t R)
static inline uint32_t ReciprocalDivide (uint32_t A, uint32_t R)
{
return (uint32_t)(((uint64_t)A * R) >> 32);
return (uint32_t)(((uint64_t)A * R) >> 32);
}
/* end kernel borrowings */
static codel_time_t codel_get_time(void)
static uint32_t CoDelGetTime (void)
{
Time time = Simulator::Now ();
uint64_t ns = time.GetNanoSeconds ();
@@ -61,21 +51,6 @@ static codel_time_t codel_get_time(void)
return ns >> CODEL_SHIFT;
}
#define codel_time_after(a, b) ((int)(a) - (int)(b) > 0)
#define codel_time_after_eq(a, b) ((int)(a) - (int)(b) >= 0)
#define codel_time_before(a, b) ((int)(a) - (int)(b) < 0)
#define codel_time_before_eq(a, b) ((int)(a) - (int)(b) <= 0)
#define NSEC_PER_MSEC 1000000
#define NSEC_PER_USEC 1000
#define MS2TIME(a) ((a * NSEC_PER_MSEC) >> CODEL_SHIFT)
#define US2TIME(a) ((a * NSEC_PER_USEC) >> CODEL_SHIFT)
#define NS2TIME(a) ((a) >> CODEL_SHIFT)
#define TIME2CODEL(a) NS2TIME(a.GetNanoSeconds())
#define DEFAULT_CODEL_LIMIT 1000
class CoDelTimestampTag : public Tag
{
public:
@@ -101,7 +76,7 @@ CoDelTimestampTag::CoDelTimestampTag ()
TypeId
CoDelTimestampTag::GetTypeId (void)
{
static TypeId tid = TypeId ("anon::CoDelTimestampTag")
static TypeId tid = TypeId ("ns3::CoDelTimestampTag")
.SetParent<Tag> ()
.AddConstructor<CoDelTimestampTag> ()
.AddAttribute ("CreationTime",
@@ -112,6 +87,7 @@ CoDelTimestampTag::GetTypeId (void)
;
return tid;
}
TypeId
CoDelTimestampTag::GetInstanceTypeId (void) const
{
@@ -146,141 +122,154 @@ CoDelTimestampTag::GetTxTime (void) const
NS_OBJECT_ENSURE_REGISTERED (CoDelQueue);
TypeId CoDelQueue::GetTypeId (void)
TypeId CoDelQueue::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::CoDelQueue")
.SetParent<Queue> ()
.AddConstructor<CoDelQueue> ()
.AddAttribute ("Mode",
.AddAttribute ("Mode",
"Whether to use Bytes (see MaxBytes) or Packets (see MaxPackets) as the maximum queue size metric.",
EnumValue (BYTES),
EnumValue (QUEUE_MODE_BYTES),
MakeEnumAccessor (&CoDelQueue::SetMode),
MakeEnumChecker (BYTES, "Bytes",
PACKETS, "Packets"))
.AddAttribute ("MaxPackets",
MakeEnumChecker (QUEUE_MODE_BYTES, "QUEUE_MODE_BYTES",
QUEUE_MODE_PACKETS, "QUEUE_MODE_PACKETS"))
.AddAttribute ("MaxPackets",
"The maximum number of packets accepted by this CoDelQueue.",
UintegerValue (DEFAULT_CODEL_LIMIT),
MakeUintegerAccessor (&CoDelQueue::m_maxPackets),
MakeUintegerChecker<uint32_t> ())
.AddAttribute ("MaxBytes",
.AddAttribute ("MaxBytes",
"The maximum number of bytes accepted by this CoDelQueue.",
UintegerValue (1500*DEFAULT_CODEL_LIMIT),
UintegerValue (1500 * DEFAULT_CODEL_LIMIT),
MakeUintegerAccessor (&CoDelQueue::m_maxBytes),
MakeUintegerChecker<uint32_t> ())
.AddAttribute ("MinBytes",
.AddAttribute ("MinBytes",
"The CoDel algorithm minbytes parameter.",
UintegerValue (1500),
MakeUintegerAccessor (&CoDelQueue::m_minbytes),
MakeUintegerAccessor (&CoDelQueue::m_minBytes),
MakeUintegerChecker<uint32_t> ())
.AddAttribute ("Interval",
"The CoDel algorithm interval",
StringValue ("100ms"),
MakeTimeAccessor (&CoDelQueue::m_Interval),
MakeTimeAccessor (&CoDelQueue::m_interval),
MakeTimeChecker ())
.AddAttribute ("Target",
"The CoDel algorithm target queue delay",
StringValue ("5ms"),
MakeTimeAccessor (&CoDelQueue::m_Target),
MakeTimeAccessor (&CoDelQueue::m_target),
MakeTimeChecker ())
.AddTraceSource("count",
"CoDel count",
MakeTraceSourceAccessor(&CoDelQueue::m_count))
.AddTraceSource("drop_count",
"CoDel drop count",
MakeTraceSourceAccessor(&CoDelQueue::m_drop_count))
.AddTraceSource("last_count",
"CoDel lastcount",
MakeTraceSourceAccessor(&CoDelQueue::m_lastcount))
// .AddTraceSource("bytesInQueue",
// "Number of bytes in the queue",
// MakeTraceSourceAccessor(&CoDelQueue::m_bytesInQueue))
.AddTraceSource ("Count",
"CoDel count",
MakeTraceSourceAccessor (&CoDelQueue::m_count))
.AddTraceSource ("DropCount",
"CoDel drop count",
MakeTraceSourceAccessor (&CoDelQueue::m_dropCount))
.AddTraceSource ("LastCount",
"CoDel lastcount",
MakeTraceSourceAccessor (&CoDelQueue::m_lastCount))
.AddTraceSource ("DropState",
"Dropping state",
MakeTraceSourceAccessor (&CoDelQueue::m_dropping))
.AddTraceSource ("BytesInQueue",
"Number of bytes in the queue",
MakeTraceSourceAccessor (&CoDelQueue::m_bytesInQueue))
.AddTraceSource ("Sojourn",
"Time in the queue",
MakeTraceSourceAccessor (&CoDelQueue::m_sojourn))
.AddTraceSource ("DropNext",
"Time until next packet drop",
MakeTraceSourceAccessor (&CoDelQueue::m_dropNext))
;
return tid;
}
CoDelQueue::CoDelQueue () :
Queue (),
m_packets (),
m_maxBytes(),
m_bytesInQueue(0),
backlog(&m_bytesInQueue),
m_count(0),
m_drop_count(0),
m_lastcount(0),
m_dropping(false),
m_rec_inv_sqrt(~0U >> REC_INV_SQRT_SHIFT),
m_first_above_time(0),
m_drop_next(0),
m_state1(0),
m_state2(0),
m_state3(0),
m_states(0),
m_drop_overlimit(0)
CoDelQueue::CoDelQueue ()
: Queue (),
m_packets (),
m_maxBytes (),
m_bytesInQueue (0),
m_count (0),
m_dropCount (0),
m_lastCount (0),
m_dropping (false),
m_recInvSqrt (~0U >> REC_INV_SQRT_SHIFT),
m_firstAboveTime (0),
m_dropNext (0),
m_state1 (0),
m_state2 (0),
m_state3 (0),
m_states (0),
m_dropOverLimit (0),
m_sojourn (0)
{
NS_LOG_FUNCTION_NOARGS ();
NS_LOG_FUNCTION (this);
}
CoDelQueue::~CoDelQueue ()
{
NS_LOG_FUNCTION_NOARGS ();
NS_LOG_FUNCTION (this);
}
void
CoDelQueue::NewtonStep(void)
CoDelQueue::NewtonStep (void)
{
uint32_t invsqrt = ((uint32_t) m_rec_inv_sqrt) << REC_INV_SQRT_SHIFT;
uint32_t invsqrt2 = ((uint64_t) invsqrt*invsqrt) >> 32;
uint64_t val = (3ll<<32) - ((uint64_t) m_count * invsqrt2);
NS_LOG_FUNCTION (this);
uint32_t invsqrt = ((uint32_t) m_recInvSqrt) << REC_INV_SQRT_SHIFT;
uint32_t invsqrt2 = ((uint64_t) invsqrt * invsqrt) >> 32;
uint64_t val = (3ll << 32) - ((uint64_t) m_count * invsqrt2);
val >>= 2; /* avoid overflow */
val = (val * invsqrt) >> (32-2+1);
m_rec_inv_sqrt = val >> REC_INV_SQRT_SHIFT;
val = (val * invsqrt) >> (32 - 2 + 1);
m_recInvSqrt = val >> REC_INV_SQRT_SHIFT;
}
codel_time_t
CoDelQueue::ControlLaw(codel_time_t t)
uint32_t
CoDelQueue::ControlLaw (uint32_t t)
{
return t + reciprocal_divide(TIME2CODEL(m_Interval), m_rec_inv_sqrt << REC_INV_SQRT_SHIFT);
NS_LOG_FUNCTION (this);
return t + ReciprocalDivide (Time2CoDel (m_interval), m_recInvSqrt << REC_INV_SQRT_SHIFT);
}
void
CoDelQueue::SetMode (enum Mode mode)
CoDelQueue::SetMode (CoDelQueue::QueueMode mode)
{
NS_LOG_FUNCTION (mode);
m_mode = mode;
}
CoDelQueue::Mode
CoDelQueue::QueueMode
CoDelQueue::GetMode (void)
{
NS_LOG_FUNCTION_NOARGS ();
NS_LOG_FUNCTION (this);
return m_mode;
}
bool
bool
CoDelQueue::DoEnqueue (Ptr<Packet> p)
{
NS_LOG_FUNCTION (this << p);
if (m_mode == PACKETS && (m_packets.size () >= m_maxPackets))
if (m_mode == QUEUE_MODE_PACKETS && (m_packets.size () + 1 > m_maxPackets))
{
NS_LOG_LOGIC ("Queue full (at max packets) -- droppping pkt");
Drop (p);
++m_drop_overlimit;
++m_dropOverLimit;
return false;
}
if (m_mode == BYTES && (m_bytesInQueue + p->GetSize () >= m_maxBytes))
if (m_mode == QUEUE_MODE_BYTES && (m_bytesInQueue + p->GetSize () > m_maxBytes))
{
NS_LOG_LOGIC ("Queue full (packet would exceed max bytes) -- droppping pkt");
Drop (p);
++m_drop_overlimit;
++m_dropOverLimit;
return false;
}
// Tag packet with current time for DoDequeue() to compute sojourn time
CoDelTimestampTag tag;
p->AddByteTag (tag);
p->AddPacketTag (tag);
m_bytesInQueue += p->GetSize ();
m_packets.push (p);
@@ -291,39 +280,45 @@ CoDelQueue::DoEnqueue (Ptr<Packet> p)
}
bool
CoDelQueue::ShouldDrop(Ptr<Packet> p, codel_time_t now)
CoDelQueue::OkToDrop (Ptr<Packet> p, uint32_t now)
{
NS_LOG_FUNCTION (this);
CoDelTimestampTag tag;
bool drop;
bool okToDrop;
p->FindFirstMatchingByteTag (tag);
bool found = p->RemovePacketTag (tag);
NS_ASSERT_MSG (found, "found a packet without an input timestamp tag");
NS_UNUSED (found); //silence compiler warning
Time delta = Simulator::Now () - tag.GetTxTime ();
NS_LOG_INFO ("Sojourn time "<<delta.GetSeconds ());
codel_time_t sojourn_time = TIME2CODEL(delta);
if (codel_time_before(sojourn_time, TIME2CODEL(m_Target)) ||
*backlog < m_minbytes)
NS_LOG_INFO ("Sojourn time " << delta.GetSeconds ());
m_sojourn = delta;
uint32_t sojournTime = Time2CoDel (delta);
if (CoDelTimeBefore (sojournTime, Time2CoDel (m_target))
|| m_bytesInQueue < m_minBytes)
{
/* went below so we'll stay below for at least q->interval */
m_first_above_time = 0;
// 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");
m_firstAboveTime = 0;
return false;
}
drop = false;
if (m_first_above_time == 0)
okToDrop = false;
if (m_firstAboveTime == 0)
{
/* just went above from below. If we stay above
* for at least q->interval we'll say it's ok to drop
*/
m_first_above_time = now + TIME2CODEL(m_Interval);
}
else
if (codel_time_after(now, m_first_above_time))
{
drop = true;
++m_state1;
}
if (!drop)
Drop (p);
return drop;
NS_LOG_LOGIC ("Sojourn time has just gone above target from below, need to stay above for at least q->interval before packet can be dropped. ");
m_firstAboveTime = now + Time2CoDel (m_interval);
}
else
if (CoDelTimeAfter (now, m_firstAboveTime))
{
NS_LOG_LOGIC ("Sojourn time has been above target for at least q->interval; it's OK to (possibly) drop packet.");
okToDrop = true;
++m_state1;
}
return okToDrop;
}
Ptr<Packet>
@@ -333,46 +328,51 @@ CoDelQueue::DoDequeue (void)
if (m_packets.empty ())
{
// Leave dropping state when queue is empty
m_dropping = false;
m_first_above_time = 0;
m_firstAboveTime = 0;
NS_LOG_LOGIC ("Queue empty");
return 0;
}
codel_time_t now = codel_get_time();
uint32_t now = CoDelGetTime ();
Ptr<Packet> p = m_packets.front ();
m_packets.pop ();
m_bytesInQueue -= p->GetSize ();
NS_LOG_LOGIC ("Popped " << p);
NS_LOG_LOGIC ("Number packets " << m_packets.size ());
NS_LOG_LOGIC ("Number bytes " << m_bytesInQueue);
NS_LOG_LOGIC ("Number packets remaining " << m_packets.size ());
NS_LOG_LOGIC ("Number bytes remaining " << m_bytesInQueue);
// Determine if p should be dropped
bool okToDrop = OkToDrop (p, now);
bool drop = ShouldDrop(p, now);
if (m_dropping)
{
if (!drop)
{ // In the dropping state (sojourn time has gone above target and hasn't come down yet)
// Check if we can leave the dropping state or next drop should occur
NS_LOG_LOGIC ("In dropping state, check if it's OK to leave or next drop should occur");
if (!okToDrop)
{
/* sojourn time below target - leave dropping state */
/* sojourn time fell below target - leave dropping state */
NS_LOG_LOGIC ("Sojourn time goes below target, it's OK to leave dropping state.");
m_dropping = false;
}
else
if (codel_time_after_eq(now, m_drop_next))
{
m_state2++;
/* It's time for the next drop. Drop the current
* packet and dequeue the next. The dequeue might
* take us out of dropping state.
* If not, schedule the next drop.
* A large backlog might result in drop rates so high
* that the next drop should happen now,
* hence the while loop.
*/
while (m_dropping &&
codel_time_after_eq(now, m_drop_next)) {
Drop(p);
++m_drop_count;
if (CoDelTimeAfterEq (now, m_dropNext))
{
m_state2++;
while (m_dropping && CoDelTimeAfterEq (now, m_dropNext))
{
// It's time for the next drop. Drop the current packet and
// dequeue the next. The dequeue might take us out of dropping
// state. If not, schedule the next drop.
// A large amount of packets in queue might result in drop
// 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);
++m_dropCount;
++m_count;
NewtonStep();
NewtonStep ();
if (m_packets.empty ())
{
m_dropping = false;
@@ -385,58 +385,79 @@ CoDelQueue::DoDequeue (void)
m_bytesInQueue -= p->GetSize ();
NS_LOG_LOGIC ("Popped " << p);
NS_LOG_LOGIC ("Number packets " << m_packets.size ());
NS_LOG_LOGIC ("Number bytes " << m_bytesInQueue);
NS_LOG_LOGIC ("Number packets remaining " << m_packets.size ());
NS_LOG_LOGIC ("Number bytes remaining " << m_bytesInQueue);
if (!ShouldDrop(p, now))
if (!OkToDrop (p, now))
{
/* leave dropping state */
NS_LOG_LOGIC ("Leaving dropping state");
m_dropping = false;
}
else
else
{
/* and schedule the next drop */
m_drop_next = ControlLaw(m_drop_next);
/* schedule the next drop */
NS_LOG_LOGIC ("Running ControlLaw for input m_dropNext: " << (double)m_dropNext / 1000000);
m_dropNext = ControlLaw (m_dropNext);
NS_LOG_LOGIC ("Scheduled next drop at " << (double)m_dropNext / 1000000);
}
}
}
}
}
else
if (drop &&
(codel_time_before(now - m_drop_next,
TIME2CODEL(m_Interval)) ||
codel_time_after_eq(now - m_first_above_time,
TIME2CODEL(m_Interval))))
{
++m_drop_count;
else
{
// Not in the dropping state
// Decide if we have to enter the dropping state and drop the first packet
NS_LOG_LOGIC ("Not in dropping state; decide if we have to enter the state and drop the first packet");
if (okToDrop)
{
// 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);
if (m_packets.empty ())
{
m_dropping = false;
okToDrop = false;
NS_LOG_LOGIC ("Queue empty");
++m_states;
}
else
{
p = m_packets.front ();
m_packets.pop ();
m_bytesInQueue -= p->GetSize ();
NS_LOG_LOGIC ("Popped " << p);
NS_LOG_LOGIC ("Number packets " << m_packets.size ());
NS_LOG_LOGIC ("Number bytes " << m_bytesInQueue);
NS_LOG_LOGIC ("Popped " << p);
NS_LOG_LOGIC ("Number packets remaining " << m_packets.size ());
NS_LOG_LOGIC ("Number bytes remaining " << m_bytesInQueue);
drop = ShouldDrop(p, now);
m_dropping = true;
++m_state3;
/*
* if min went above target close to when we last went below it
* assume that the drop rate that controlled the queue on the
* last cycle is a good starting point to control it now.
*/
int delta = m_count - m_lastcount;
if (delta > 1 && codel_time_after(now - m_drop_next, TIME2CODEL(m_Interval)))
{
m_count = delta;
NewtonStep();
}
else
{
m_count = 1;
m_rec_inv_sqrt = ~0U >> REC_INV_SQRT_SHIFT;
}
m_lastcount = m_count;
m_drop_next = ControlLaw(now);
p = NULL;
}
okToDrop = OkToDrop (p, now);
m_dropping = true;
}
++m_state3;
/*
* if min went above target close to when we last went below it
* assume that the drop rate that controlled the queue on the
* last cycle is a good starting point to control it now.
*/
int delta = m_count - m_lastCount;
if (delta > 1 && CoDelTimeBefore (now - m_dropNext, 16 * Time2CoDel (m_interval)))
{
m_count = delta;
NewtonStep ();
}
else
{
m_count = 1;
m_recInvSqrt = ~0U >> REC_INV_SQRT_SHIFT;
}
m_lastCount = m_count;
NS_LOG_LOGIC ("Running ControlLaw for input now: " << (double)now);
m_dropNext = ControlLaw (now);
NS_LOG_LOGIC ("Scheduled next drop at " << (double)m_dropNext / 1000000 << " now " << (double)now / 1000000);
}
}
++m_states;
return p;
}
@@ -444,12 +465,12 @@ CoDelQueue::DoDequeue (void)
uint32_t
CoDelQueue::GetQueueSize (void)
{
NS_LOG_FUNCTION_NOARGS ();
if (GetMode () == BYTES)
NS_LOG_FUNCTION (this);
if (GetMode () == QUEUE_MODE_BYTES)
{
return m_bytesInQueue;
}
else if (GetMode () == PACKETS)
else if (GetMode () == QUEUE_MODE_PACKETS)
{
return m_packets.size ();
}
@@ -459,6 +480,36 @@ CoDelQueue::GetQueueSize (void)
}
}
uint32_t
CoDelQueue::GetDropOverLimit (void)
{
return m_dropOverLimit;
}
uint32_t
CoDelQueue::GetDropCount (void)
{
return m_dropCount;
}
Time
CoDelQueue::GetTarget (void)
{
return m_target;
}
Time
CoDelQueue::GetInterval (void)
{
return m_interval;
}
uint32_t
CoDelQueue::GetDropNext (void)
{
return m_dropNext;
}
Ptr<const Packet>
CoDelQueue::DoPeek (void) const
{
@@ -478,5 +529,36 @@ CoDelQueue::DoPeek (void) const
return p;
}
bool
CoDelQueue::CoDelTimeAfter (uint32_t a, uint32_t b)
{
return ((int)(a) - (int)(b) > 0);
}
bool
CoDelQueue::CoDelTimeAfterEq (uint32_t a, uint32_t b)
{
return ((int)(a) - (int)(b) >= 0);
}
bool
CoDelQueue::CoDelTimeBefore (uint32_t a, uint32_t b)
{
return ((int)(a) - (int)(b) < 0);
}
bool
CoDelQueue::CoDelTimeBeforeEq (uint32_t a, uint32_t b)
{
return ((int)(a) - (int)(b) <= 0);
}
uint32_t
CoDelQueue::Time2CoDel (Time t)
{
return (t.GetNanoSeconds () >> CODEL_SHIFT);
}
} // namespace ns3

View File

@@ -14,7 +14,7 @@
* 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
*
*
* Codel, the COntrolled DELay Queueing discipline
* Based on ns2 simulation code presented by Kathie Nichols
*
@@ -37,13 +37,15 @@
#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
namespace ns3 {
typedef uint32_t codel_time_t;
typedef uint16_t rec_inv_sqrt_t;
static const int CODEL_SHIFT = 10;
static const int DEFAULT_CODEL_LIMIT = 1000;
#define CODEL_SHIFT 10
#define REC_INV_SQRT_BITS (8*sizeof(rec_inv_sqrt_t))
#define REC_INV_SQRT_BITS (8 * sizeof(uint16_t))
#define REC_INV_SQRT_SHIFT (32 - REC_INV_SQRT_BITS)
class TraceContainer;
@@ -51,78 +53,164 @@ class TraceContainer;
/**
* \ingroup queue
*
* \brief A FIFO packet queue that drops tail-end packets on overflow
* \brief A CoDel packet queue
*/
class CoDelQueue : public Queue {
public:
friend class Fq_CoDelQueue;
class CoDelQueue : public Queue
{
public:
static TypeId GetTypeId (void);
/**
* \brief CoDelQueue Constructor
*
* Creates a codel queue with a maximum size of 100 packets by default
* Creates a CoDel queue
*/
CoDelQueue ();
virtual ~CoDelQueue();
virtual ~CoDelQueue ();
/**
* Enumeration of the modes supported in the class.
*
*/
enum Mode {
ILLEGAL, /**< Mode not set */
PACKETS, /**< Use number of packets for maximum queue size */
BYTES, /**< Use number of bytes for maximum queue size */
};
/**
* Set the operating mode of this device.
* \brief Set the operating mode of this device.
*
* \param mode The operating mode of this device.
*
*/
void SetMode (CoDelQueue::Mode mode);
void SetMode (CoDelQueue::QueueMode mode);
/**
* Get the encapsulation mode of this device.
* \brief Get the encapsulation mode of this device.
*
* \returns The encapsulation mode of this device.
*/
CoDelQueue::Mode GetMode (void);
CoDelQueue::QueueMode GetMode (void);
/**
* \brief Get the current value of the queue in bytes or packets.
*
* \returns The queue size in bytes or packets.
*/
uint32_t GetQueueSize (void);
private:
virtual bool DoEnqueue (Ptr<Packet> p);
virtual Ptr<Packet> DoDequeue (void);
virtual Ptr<const Packet> DoPeek (void) const;
void NewtonStep(void);
codel_time_t ControlLaw(codel_time_t t);
bool ShouldDrop(Ptr<Packet> p, codel_time_t now);
/**
* \brief Get the number of packets dropped when packets
* arrive at a full queue and cannot be enqueued.
*
* \returns The number of dropped packets
*/
uint32_t GetDropOverLimit (void);
std::queue<Ptr<Packet> > m_packets;
uint32_t m_maxPackets;
uint32_t m_maxBytes;
uint32_t m_bytesInQueue;
uint32_t *backlog;
uint32_t m_minbytes;
Time m_Interval;
Time m_Target;
TracedValue<uint32_t> m_count;
TracedValue<uint32_t> m_drop_count;
TracedValue<uint32_t> m_lastcount;
bool m_dropping;
uint16_t m_rec_inv_sqrt;
codel_time_t m_first_above_time;
codel_time_t m_drop_next;
uint32_t m_state1;
uint32_t m_state2;
uint32_t m_state3;
uint32_t m_states;
uint32_t m_drop_overlimit;
Mode m_mode;
/**
* \brief Get the number of packets dropped according to CoDel algorithm
*
* \returns The number of dropped packets
*/
uint32_t GetDropCount (void);
/**
* \brief Get the target queue delay
*
* \returns The target queue delay
*/
Time GetTarget (void);
/**
* \brief Get the interval
*
* \returns The interval
*/
Time GetInterval (void);
/**
* \brief Get the time for next packet drop while in the dropping state
*
* \returns The time for next packet drop
*/
uint32_t GetDropNext (void);
private:
friend class::CoDelQueueNewtonStepTest; // Test code
friend class::CoDelQueueControlLawTest; // Test code
/**
* \brief Add a packet to the queue
*
* \param p The packet 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<Packet> p);
/**
* \brief Remove a packet from queue based on the current state
* If we are in dropping state, check if we could leave the dropping state
* or if we should perform next drop
* If we are not currently in dropping state, check if we need to enter the state
* and drop the first packet
*
* \returns The packet that is examined
*/
virtual Ptr<Packet> DoDequeue (void);
virtual Ptr<const Packet> DoPeek (void) const;
/**
* \brief Calculate the reciprocal square root of m_count by using Newton's method
* http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Iterative_methods_for_reciprocal_square_roots
* m_recInvSqrt (new) = (m_recInvSqrt (old) / 2) * (3 - m_count * m_recInvSqrt^2)
*/
void NewtonStep (void);
/**
* \brief Determine the time for next drop
* CoDel control law is t + m_interval/sqrt(m_count).
* Here, we use m_recInvSqrt calculated by Newton's method in NewtonStep() to avoid
* both sqrt() and divide operations
*
* \param t Current next drop time
* \returns The new next drop time:
*/
uint32_t ControlLaw (uint32_t t);
/**
* \brief Determine whether a packet is OK to be dropped. The packet
* may not be actually dropped (depending on the drop state)
*
* \param p The packet that is considered
* \param now The current time represented as 32-bit unsigned integer (us)
* \returns True if it is OK to drop the packet (sojourn time above target for at least interval)
*/
bool OkToDrop (Ptr<Packet> p, uint32_t now);
bool CoDelTimeAfter (uint32_t a, uint32_t b);
bool CoDelTimeAfterEq (uint32_t a, uint32_t b);
bool CoDelTimeBefore (uint32_t a, uint32_t b);
bool CoDelTimeBeforeEq (uint32_t a, uint32_t b);
/**
* returned unsigned 32-bit integer representation of the input Time object
* units are microseconds
*/
uint32_t Time2CoDel (Time t);
std::queue<Ptr<Packet> > m_packets; //!< The packet queue
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
TracedValue<uint32_t> m_count; //!< Number of packets dropped since entering drop state
TracedValue<uint32_t> m_dropCount; //!< Number of dropped packets according CoDel algorithm
TracedValue<uint32_t> m_lastCount; //<! Last number of packets dropped since entering drop state
TracedValue<bool> m_dropping; //!< True if in dropping state
uint16_t m_recInvSqrt; //!< Reciprocal inverse square root
uint32_t m_firstAboveTime; //!< Time to declare sojourn time above target
TracedValue<uint32_t> m_dropNext; //!< Time to drop next packet
uint32_t m_state1; //!< Number of times packet sojourn goes above target for interval
uint32_t m_state2; //!< Number of times we perform next drop while in dropping state
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)
TracedValue<Time> m_sojourn; //!< Time in queue
};
} // namespace ns3