From 4aade6e7ef5d9eb294ab7580a8e51f80e7d5d0d7 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Wed, 13 May 2020 14:05:06 +0530 Subject: [PATCH] traffic-control: Add ECN marking to CoDel queue disc --- src/traffic-control/model/codel-queue-disc.cc | 64 +++++++++++++------ src/traffic-control/model/codel-queue-disc.h | 5 ++ 2 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/traffic-control/model/codel-queue-disc.cc b/src/traffic-control/model/codel-queue-disc.cc index 089cfa4bb..95d39243b 100644 --- a/src/traffic-control/model/codel-queue-disc.cc +++ b/src/traffic-control/model/codel-queue-disc.cc @@ -73,6 +73,11 @@ TypeId CoDelQueueDisc::GetTypeId (void) .SetParent () .SetGroupName ("TrafficControl") .AddConstructor () + .AddAttribute ("UseEcn", + "True to use ECN (packets are marked instead of being dropped)", + BooleanValue (false), + MakeBooleanAccessor (&CoDelQueueDisc::m_useEcn), + MakeBooleanChecker ()) .AddAttribute ("MaxSize", "The maximum number of packets/bytes accepted by this queue disc.", QueueSizeValue (QueueSize (QueueSizeUnit::BYTES, 1500 * DEFAULT_CODEL_LIMIT)), @@ -94,6 +99,11 @@ TypeId CoDelQueueDisc::GetTypeId (void) StringValue ("5ms"), MakeTimeAccessor (&CoDelQueueDisc::m_target), MakeTimeChecker ()) + .AddAttribute ("CeThreshold", + "The CoDel CE threshold for marking packets", + TimeValue (Time::Max ()), + MakeTimeAccessor (&CoDelQueueDisc::m_ceThreshold), + MakeTimeChecker ()) .AddTraceSource ("Count", "CoDel count", MakeTraceSourceAccessor (&CoDelQueueDisc::m_count), @@ -258,17 +268,25 @@ CoDelQueueDisc::DoDequeue (void) m_state2++; while (m_dropping && CoDelTimeAfterEq (now, m_dropNext)) { + ++m_count; + m_recInvSqrt = NewtonStep (m_recInvSqrt, m_count); // 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. + if (m_useEcn && Mark (item, TARGET_EXCEEDED_MARK)) + { + NS_LOG_LOGIC ("Sojourn time is still above target and it's time for next drop or mark; marking " << item); + NS_LOG_LOGIC ("Running ControlLaw for input m_dropNext: " << (double)m_dropNext / 1000000); + m_dropNext = ControlLaw (now, Time2CoDel (m_interval), m_recInvSqrt); + NS_LOG_LOGIC ("Scheduled next drop at " << (double) m_dropNext / 1000000); + goto end; + } NS_LOG_LOGIC ("Sojourn time is still above target and it's time for next drop; dropping " << item); DropAfterDequeue (item, TARGET_EXCEEDED_DROP); - ++m_count; - m_recInvSqrt = NewtonStep (m_recInvSqrt, m_count); item = GetInternalQueue (0)->Dequeue (); if (item) @@ -301,20 +319,24 @@ CoDelQueueDisc::DoDequeue (void) 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 " << item << " and entering the dropping state"); - DropAfterDequeue (item, TARGET_EXCEEDED_DROP); - - item = GetInternalQueue (0)->Dequeue (); - - if (item) + if (m_useEcn && Mark (item, TARGET_EXCEEDED_MARK)) { - NS_LOG_LOGIC ("Popped " << item); - NS_LOG_LOGIC ("Number packets remaining " << GetInternalQueue (0)->GetNPackets ()); - NS_LOG_LOGIC ("Number bytes remaining " << GetInternalQueue (0)->GetNBytes ()); + NS_LOG_LOGIC ("Sojourn time goes above target, marking the first packet " << item << " and entering the dropping state"); + } + else + { + // 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 " << item << " and entering the dropping state"); + DropAfterDequeue (item, TARGET_EXCEEDED_DROP); + item = GetInternalQueue (0)->Dequeue (); + if (item) + { + NS_LOG_LOGIC ("Popped " << item); + NS_LOG_LOGIC ("Number packets remaining " << GetInternalQueue (0)->GetNPackets ()); + NS_LOG_LOGIC ("Number bytes remaining " << GetInternalQueue (0)->GetNBytes ()); + } + OkToDrop (item, now); } - - OkToDrop (item, now); m_dropping = true; ++m_state3; /* @@ -339,6 +361,12 @@ CoDelQueueDisc::DoDequeue (void) NS_LOG_LOGIC ("Scheduled next drop at " << (double)m_dropNext / 1000000 << " now " << (double)now / 1000000); } } + end: + uint32_t ldelay = Time2CoDel (Simulator::Now () - item->GetTimeStamp ()); + if (item && m_useEcn && CoDelTimeAfter (ldelay, Time2CoDel (m_ceThreshold)) && Mark (item, CE_THRESHOLD_EXCEEDED_MARK)) + { + NS_LOG_LOGIC ("Marking due to CeThreshold " << m_ceThreshold.GetSeconds ()); + } ++m_states; return item; } @@ -364,25 +392,25 @@ CoDelQueueDisc::GetDropNext (void) bool CoDelQueueDisc::CoDelTimeAfter (uint32_t a, uint32_t b) { - return ((int)(a) - (int)(b) > 0); + return ((int64_t)(a) - (int64_t)(b) > 0); } bool CoDelQueueDisc::CoDelTimeAfterEq (uint32_t a, uint32_t b) { - return ((int)(a) - (int)(b) >= 0); + return ((int64_t)(a) - (int64_t)(b) >= 0); } bool CoDelQueueDisc::CoDelTimeBefore (uint32_t a, uint32_t b) { - return ((int)(a) - (int)(b) < 0); + return ((int64_t)(a) - (int64_t)(b) < 0); } bool CoDelQueueDisc::CoDelTimeBeforeEq (uint32_t a, uint32_t b) { - return ((int)(a) - (int)(b) <= 0); + return ((int64_t)(a) - (int64_t)(b) <= 0); } uint32_t diff --git a/src/traffic-control/model/codel-queue-disc.h b/src/traffic-control/model/codel-queue-disc.h index c6d24eecf..1f1edc509 100644 --- a/src/traffic-control/model/codel-queue-disc.h +++ b/src/traffic-control/model/codel-queue-disc.h @@ -101,6 +101,9 @@ public: // Reasons for dropping packets static constexpr const char* TARGET_EXCEEDED_DROP = "Target exceeded drop"; //!< Sojourn time above target static constexpr const char* OVERLIMIT_DROP = "Overlimit drop"; //!< Overlimit dropped packet + // Reasons for marking packets + static constexpr const char* TARGET_EXCEEDED_MARK = "Target exceeded mark"; //!< Sojourn time above target + static constexpr const char* CE_THRESHOLD_EXCEEDED_MARK = "CE threshold exceeded mark"; //!< Sojourn time above CE threshold private: friend class::CoDelQueueDiscNewtonStepTest; // Test code @@ -198,9 +201,11 @@ private: virtual void InitializeParams (void); + bool m_useEcn; //!< True if ECN is used (packets are marked instead of being dropped) 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 + Time m_ceThreshold; //!< Threshold above which to CE mark TracedValue m_count; //!< Number of packets dropped since entering drop state TracedValue m_lastCount; //!< Last number of packets dropped since entering drop state TracedValue m_dropping; //!< True if in dropping state