diff --git a/src/internet/model/codel-queue.cc b/src/internet/model/codel-queue.cc index 789f52e81..218362018 100644 --- a/src/internet/model/codel-queue.cc +++ b/src/internet/model/codel-queue.cc @@ -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 () .AddConstructor () .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 () .AddConstructor () - .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 ()) - .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 ()) - .AddAttribute ("MinBytes", + .AddAttribute ("MinBytes", "The CoDel algorithm minbytes parameter.", UintegerValue (1500), - MakeUintegerAccessor (&CoDelQueue::m_minbytes), + MakeUintegerAccessor (&CoDelQueue::m_minBytes), MakeUintegerChecker ()) .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 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 p) } bool -CoDelQueue::ShouldDrop(Ptr p, codel_time_t now) +CoDelQueue::OkToDrop (Ptr 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 "<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 @@ -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 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 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 diff --git a/src/internet/model/codel-queue.h b/src/internet/model/codel-queue.h index 83885c4ac..4c8c9fea1 100644 --- a/src/internet/model/codel-queue.h +++ b/src/internet/model/codel-queue.h @@ -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 p); - virtual Ptr DoDequeue (void); - virtual Ptr DoPeek (void) const; - void NewtonStep(void); - codel_time_t ControlLaw(codel_time_t t); - bool ShouldDrop(Ptr 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 > 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 m_count; - TracedValue m_drop_count; - TracedValue 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 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 DoDequeue (void); + + virtual Ptr 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 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 > 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 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 m_count; //!< Number of packets dropped since entering drop state + TracedValue m_dropCount; //!< Number of dropped packets according CoDel algorithm + TracedValue m_lastCount; // 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 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