traffic-control: Add ECN marking to CoDel queue disc

This commit is contained in:
Tom Henderson
2020-05-13 14:05:06 +05:30
committed by Stefano Avallone
parent d7a144bcf8
commit 4aade6e7ef
2 changed files with 51 additions and 18 deletions

View File

@@ -73,6 +73,11 @@ TypeId CoDelQueueDisc::GetTypeId (void)
.SetParent<QueueDisc> ()
.SetGroupName ("TrafficControl")
.AddConstructor<CoDelQueueDisc> ()
.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

View File

@@ -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<uint32_t> m_count; //!< Number of packets dropped since entering drop state
TracedValue<uint32_t> m_lastCount; //!< Last number of packets dropped since entering drop state
TracedValue<bool> m_dropping; //!< True if in dropping state