From eb0351dccb52229f7d2a7b1304b271fe4dadae74 Mon Sep 17 00:00:00 2001
From: Stefano Avallone
Date: Thu, 14 Sep 2017 18:12:34 +0200
Subject: [PATCH] traffic-control: Record reasons for dropping and marking
packets
---
CHANGES.html | 32 +-
.../traffic-control/red-vs-fengadaptive.cc | 10 +-
examples/traffic-control/red-vs-nlred.cc | 10 +-
examples/traffic-control/traffic-control.cc | 2 +-
src/traffic-control/doc/queue-discs.rst | 6 +
.../examples/adaptive-red-tests.cc | 12 +-
src/traffic-control/examples/pie-example.cc | 10 +-
src/traffic-control/examples/red-tests.cc | 16 +-
src/traffic-control/examples/red-vs-ared.cc | 10 +-
src/traffic-control/model/codel-queue-disc.cc | 33 +-
src/traffic-control/model/codel-queue-disc.h | 21 +-
.../model/fq-codel-queue-disc.cc | 10 +-
.../model/fq-codel-queue-disc.h | 6 +-
.../model/pfifo-fast-queue-disc.cc | 2 +-
.../model/pfifo-fast-queue-disc.h | 3 +
src/traffic-control/model/pie-queue-disc.cc | 15 +-
src/traffic-control/model/pie-queue-disc.h | 22 +-
src/traffic-control/model/queue-disc.cc | 295 +++++++++++++++++-
src/traffic-control/model/queue-disc.h | 99 +++++-
src/traffic-control/model/red-queue-disc.cc | 29 +-
src/traffic-control/model/red-queue-disc.h | 28 +-
.../adaptive-red-queue-disc-test-suite.cc | 49 +--
.../test/codel-queue-disc-test-suite.cc | 19 +-
.../test/pie-queue-disc-test-suite.cc | 24 +-
.../test/red-queue-disc-test-suite.cc | 77 +++--
25 files changed, 568 insertions(+), 272 deletions(-)
diff --git a/CHANGES.html b/CHANGES.html
index 799e31dfa..681478fb0 100644
--- a/CHANGES.html
+++ b/CHANGES.html
@@ -95,13 +95,33 @@ us a note on ns-developers mailing list.
MqQueueDisc, a multi-queue aware queue disc modelled after the mq qdisc in Linux, has been introduced.
-Added QueueDisc::GetStats() which returns detailed statistics about the operations of a queue disc.
- Consequently, a number of methods of the QueueDisc class have been removed: GetTotalReceivedPackets(),
- GetTotalReceivedBytes(), GetTotalDroppedPackets(), GetTotalDroppedBytes(),
- GetTotalRequeuedPackets(), GetTotalRequeuedBytes().
-
Two new methods, QueueDisc::DropBeforeEnqueue() and QueueDisc::DropAfterDequeue() have
- been introduced to replace QueueDisc::Drop(). Correspondingly, two new trace sources have been added to the QueueDisc class: DropBeforeEnqueue and DropAfterDequeue.
+ been introduced to replace QueueDisc::Drop(). These new methods require the caller to specify the
+ reason why a packet was dropped. Correspondingly, two new trace sources ("DropBeforeEnqueue" and
+ "DropAfterDequeue") have been added to the QueueDisc class, providing both the items that were dropped
+ and the reason why they were dropped.
+
+Added QueueDisc::GetStats() which returns detailed statistics about the operations of
+ a queue disc. Statistics can be accessed through the member variables of the returned object and
+ by calling the GetNDroppedPackets(), GetNDroppedBytes(), GetNMarkedPackets() and GetNMarkedBytes() methods on the returned object. Such methods return the number of packets/bytes
+ dropped/marked for the specified reason (passed as argument). Consequently:
+
+ - A number of methods of the QueueDisc class have been removed: GetTotalReceivedPackets(),
+ GetTotalReceivedBytes(), GetTotalDroppedPackets(), GetTotalDroppedBytes(),
+ GetTotalRequeuedPackets(), GetTotalRequeuedBytes().
+ - The Stats struct and the GetStats() method of RedQueueDisc and PieQueueDisc have been removed and replaced by those of the QueueDisc base class.
+ - The GetDropOverLimit and GetDropCount methods of CoDelQueueDisc have been removed.
+ The values they returned can be obtained by calling, respectively,
+ GetStats ().GetNDroppedPackets (CoDelQueueDisc::OVERLIMIT_DROP) and
+ GetStats ().GetNDroppedPackets (CoDelQueueDisc::TARGET_EXCEEDED_DROP). The "DropCount" trace of
+ CoDelQueueDisc has been removed as well. Packets dropped because the target is exceeded can
+ be obtained through the new "DropAfterDequeue" trace of the QueueDisc class.
+
+
+ The new QueueDisc::Mark() method has been introduced to allow subclasses to request to mark a packet.
+ The caller must specify the reason why the packet must be marked. Correspondingly, a new trace source ("Mark")
+ has been added to the QueueDisc class, providing both the items that were marked and the reason why they
+ were marked.
A new trace source, SojournTime, is exported by the QueueDisc base class to provide the
sojourn time of every packet dequeued from a queue disc. This has been made possible by adding a
diff --git a/examples/traffic-control/red-vs-fengadaptive.cc b/examples/traffic-control/red-vs-fengadaptive.cc
index 818266315..e78e2fa1a 100644
--- a/examples/traffic-control/red-vs-fengadaptive.cc
+++ b/examples/traffic-control/red-vs-fengadaptive.cc
@@ -165,24 +165,22 @@ int main (int argc, char *argv[])
std::cout << "Running the simulation" << std::endl;
Simulator::Run ();
- RedQueueDisc::Stats st = StaticCast (queueDiscs.Get (0))->GetStats ();
+ QueueDisc::Stats st = queueDiscs.Get (0)->GetStats ();
- if (st.unforcedDrop == 0)
+ if (st.GetNDroppedPackets (RedQueueDisc::UNFORCED_DROP) == 0)
{
std::cout << "There should be some unforced drops" << std::endl;
exit (1);
}
- if (st.qLimDrop != 0)
+ if (st.GetNDroppedPackets (QueueDisc::INTERNAL_QUEUE_DROP) != 0)
{
std::cout << "There should be zero drops due to queue full" << std::endl;
exit (1);
}
std::cout << "*** Stats from the bottleneck queue disc ***" << std::endl;
- std::cout << "\t " << st.unforcedDrop << " drops due to prob mark" << std::endl;
- std::cout << "\t " << st.forcedDrop << " drops due to hard mark" << std::endl;
- std::cout << "\t " << st.qLimDrop << " drops due to queue full" << std::endl;
+ std::cout << st << std::endl;
std::cout << "Destroying the simulation" << std::endl;
Simulator::Destroy ();
diff --git a/examples/traffic-control/red-vs-nlred.cc b/examples/traffic-control/red-vs-nlred.cc
index 6cf3c122b..c04c393de 100644
--- a/examples/traffic-control/red-vs-nlred.cc
+++ b/examples/traffic-control/red-vs-nlred.cc
@@ -167,24 +167,22 @@ int main (int argc, char *argv[])
std::cout << "Running the simulation" << std::endl;
Simulator::Run ();
- RedQueueDisc::Stats st = StaticCast (queueDiscs.Get (0))->GetStats ();
+ QueueDisc::Stats st = queueDiscs.Get (0)->GetStats ();
- if (st.unforcedDrop == 0)
+ if (st.GetNDroppedPackets (RedQueueDisc::UNFORCED_DROP) == 0)
{
std::cout << "There should be some unforced drops" << std::endl;
exit (1);
}
- if (st.qLimDrop != 0)
+ if (st.GetNDroppedPackets (QueueDisc::INTERNAL_QUEUE_DROP) != 0)
{
std::cout << "There should be zero drops due to queue full" << std::endl;
exit (1);
}
std::cout << "*** Stats from the bottleneck queue disc ***" << std::endl;
- std::cout << "\t " << st.unforcedDrop << " drops due to prob mark" << std::endl;
- std::cout << "\t " << st.forcedDrop << " drops due to hard mark" << std::endl;
- std::cout << "\t " << st.qLimDrop << " drops due to queue full" << std::endl;
+ std::cout << st << std::endl;
std::cout << "Destroying the simulation" << std::endl;
Simulator::Destroy ();
diff --git a/examples/traffic-control/traffic-control.cc b/examples/traffic-control/traffic-control.cc
index 5042b977e..94fca9286 100644
--- a/examples/traffic-control/traffic-control.cc
+++ b/examples/traffic-control/traffic-control.cc
@@ -81,7 +81,7 @@ DevicePacketsInQueueTrace (uint32_t oldValue, uint32_t newValue)
void
SojournTimeTrace (Time oldValue, Time newValue)
{
- std::cout << "Sojourn time " << newValue << std::endl;
+ std::cout << "Sojourn time " << newValue.ToDouble (Time::MS) << "ms" << std::endl;
}
int
diff --git a/src/traffic-control/doc/queue-discs.rst b/src/traffic-control/doc/queue-discs.rst
index fe9e72086..77f9705a7 100644
--- a/src/traffic-control/doc/queue-discs.rst
+++ b/src/traffic-control/doc/queue-discs.rst
@@ -70,6 +70,12 @@ of the queue disc. The following identities hold:
* queued = enqueued - dequeued
* sent = dequeued - dropped after dequeue (- 1 if there is a requeued packet)
+Separate counters are also kept for each possible reason to drop a packet.
+When a packet is dropped by an internal queue, e.g., because the queue is full,
+the reason is "Dropped by internal queue". When a packet is dropped by a child
+queue disc, the reason is "(Dropped by child queue disc) " followed by the
+reason why the child queue disc dropped the packet.
+
The QueueDisc base class provides the SojournTime trace source, which provides
the sojourn time of every packet dequeued from a queue disc, including packets
that are dropped or requeued after being dequeued. The sojourn time is taken
diff --git a/src/traffic-control/examples/adaptive-red-tests.cc b/src/traffic-control/examples/adaptive-red-tests.cc
index d3dc2f15c..3ca033f76 100644
--- a/src/traffic-control/examples/adaptive-red-tests.cc
+++ b/src/traffic-control/examples/adaptive-red-tests.cc
@@ -479,9 +479,9 @@ main (int argc, char *argv[])
Simulator::Stop (Seconds (sink_stop_time));
Simulator::Run ();
- RedQueueDisc::Stats st = StaticCast (queueDiscs.Get (0))->GetStats ();
+ QueueDisc::Stats st = queueDiscs.Get (0)->GetStats ();
- if (st.unforcedDrop == 0)
+ if (st.GetNDroppedPackets (RedQueueDisc::UNFORCED_DROP) == 0)
{
std::cout << "There should be some unforced drops" << std::endl;
exit (1);
@@ -489,7 +489,7 @@ main (int argc, char *argv[])
if (aredTest == 1 || aredTest == 2 || aredTest == 13)
{
- if (st.qLimDrop == 0)
+ if (st.GetNDroppedPackets (QueueDisc::INTERNAL_QUEUE_DROP) == 0)
{
std::cout << "There should be some drops due to queue full" << std::endl;
exit (1);
@@ -497,7 +497,7 @@ main (int argc, char *argv[])
}
else
{
- if (st.qLimDrop != 0)
+ if (st.GetNDroppedPackets (QueueDisc::INTERNAL_QUEUE_DROP) != 0)
{
std::cout << "There should be zero drops due to queue full" << std::endl;
exit (1);
@@ -515,9 +515,7 @@ main (int argc, char *argv[])
if (printAredStats)
{
std::cout << "*** ARED stats from Node 2 queue ***" << std::endl;
- std::cout << "\t " << st.unforcedDrop << " drops due to prob mark" << std::endl;
- std::cout << "\t " << st.forcedDrop << " drops due to hard mark" << std::endl;
- std::cout << "\t " << st.qLimDrop << " drops due to queue full" << std::endl;
+ std::cout << st << std::endl;
}
Simulator::Destroy ();
diff --git a/src/traffic-control/examples/pie-example.cc b/src/traffic-control/examples/pie-example.cc
index 6f3645967..0c26833f2 100644
--- a/src/traffic-control/examples/pie-example.cc
+++ b/src/traffic-control/examples/pie-example.cc
@@ -304,9 +304,9 @@ main (int argc, char *argv[])
Simulator::Stop (Seconds (sink_stop_time));
Simulator::Run ();
- PieQueueDisc::Stats st = StaticCast (queueDiscs.Get (0))->GetStats ();
+ QueueDisc::Stats st = queueDiscs.Get (0)->GetStats ();
- if (st.forcedDrop != 0)
+ if (st.GetNDroppedPackets (PieQueueDisc::FORCED_DROP) != 0)
{
std::cout << "There should be no drops due to queue full." << std::endl;
exit (1);
@@ -323,8 +323,10 @@ main (int argc, char *argv[])
if (printPieStats)
{
std::cout << "*** PIE stats from Node 2 queue ***" << std::endl;
- std::cout << "\t " << st.unforcedDrop << " drops due to prob mark" << std::endl;
- std::cout << "\t " << st.forcedDrop << " drops due to queue limits" << std::endl;
+ std::cout << "\t " << st.GetNDroppedPackets (PieQueueDisc::UNFORCED_DROP)
+ << " drops due to prob mark" << std::endl;
+ std::cout << "\t " << st.GetNDroppedPackets (PieQueueDisc::FORCED_DROP)
+ << " drops due to queue limits" << std::endl;
}
Simulator::Destroy ();
diff --git a/src/traffic-control/examples/red-tests.cc b/src/traffic-control/examples/red-tests.cc
index d96ab0f3f..456814f24 100644
--- a/src/traffic-control/examples/red-tests.cc
+++ b/src/traffic-control/examples/red-tests.cc
@@ -458,17 +458,13 @@ main (int argc, char *argv[])
if (printRedStats)
{
- RedQueueDisc::Stats st = StaticCast (queueDiscs.Get (0))->GetStats ();
- std::cout << "*** RED stats from Node 2 queue ***" << std::endl;
- std::cout << "\t " << st.unforcedDrop << " drops due prob mark" << std::endl;
- std::cout << "\t " << st.forcedDrop << " drops due hard mark" << std::endl;
- std::cout << "\t " << st.qLimDrop << " drops due queue full" << std::endl;
+ QueueDisc::Stats st = queueDiscs.Get (0)->GetStats ();
+ std::cout << "*** RED stats from Node 2 queue disc ***" << std::endl;
+ std::cout << st << std::endl;
- st = StaticCast (queueDiscs.Get (1))->GetStats ();
- std::cout << "*** RED stats from Node 3 queue ***" << std::endl;
- std::cout << "\t " << st.unforcedDrop << " drops due prob mark" << std::endl;
- std::cout << "\t " << st.forcedDrop << " drops due hard mark" << std::endl;
- std::cout << "\t " << st.qLimDrop << " drops due queue full" << std::endl;
+ st = queueDiscs.Get (1)->GetStats ();
+ std::cout << "*** RED stats from Node 3 queue disc ***" << std::endl;
+ std::cout << st << std::endl;
}
Simulator::Destroy ();
diff --git a/src/traffic-control/examples/red-vs-ared.cc b/src/traffic-control/examples/red-vs-ared.cc
index 9ff14cdf7..e6213cb7d 100644
--- a/src/traffic-control/examples/red-vs-ared.cc
+++ b/src/traffic-control/examples/red-vs-ared.cc
@@ -166,24 +166,22 @@ int main (int argc, char *argv[])
std::cout << "Running the simulation" << std::endl;
Simulator::Run ();
- RedQueueDisc::Stats st = StaticCast (queueDiscs.Get (0))->GetStats ();
+ QueueDisc::Stats st = queueDiscs.Get (0)->GetStats ();
- if (st.unforcedDrop == 0)
+ if (st.GetNDroppedPackets (RedQueueDisc::UNFORCED_DROP) == 0)
{
std::cout << "There should be some unforced drops" << std::endl;
exit (1);
}
- if (st.qLimDrop != 0)
+ if (st.GetNDroppedPackets (QueueDisc::INTERNAL_QUEUE_DROP) != 0)
{
std::cout << "There should be zero drops due to queue full" << std::endl;
exit (1);
}
std::cout << "*** Stats from the bottleneck queue disc ***" << std::endl;
- std::cout << "\t " << st.unforcedDrop << " drops due to prob mark" << std::endl;
- std::cout << "\t " << st.forcedDrop << " drops due to hard mark" << std::endl;
- std::cout << "\t " << st.qLimDrop << " drops due to queue full" << std::endl;
+ std::cout << st << std::endl;
std::cout << "Destroying the simulation" << std::endl;
Simulator::Destroy ();
diff --git a/src/traffic-control/model/codel-queue-disc.cc b/src/traffic-control/model/codel-queue-disc.cc
index f151c9f8d..09322cf2c 100644
--- a/src/traffic-control/model/codel-queue-disc.cc
+++ b/src/traffic-control/model/codel-queue-disc.cc
@@ -109,10 +109,6 @@ TypeId CoDelQueueDisc::GetTypeId (void)
"CoDel count",
MakeTraceSourceAccessor (&CoDelQueueDisc::m_count),
"ns3::TracedValueCallback::Uint32")
- .AddTraceSource ("DropCount",
- "CoDel drop count",
- MakeTraceSourceAccessor (&CoDelQueueDisc::m_dropCount),
- "ns3::TracedValueCallback::Uint32")
.AddTraceSource ("LastCount",
"CoDel lastcount",
MakeTraceSourceAccessor (&CoDelQueueDisc::m_lastCount),
@@ -134,7 +130,6 @@ CoDelQueueDisc::CoDelQueueDisc ()
: QueueDisc (),
m_maxBytes (),
m_count (0),
- m_dropCount (0),
m_lastCount (0),
m_dropping (false),
m_recInvSqrt (~0U >> REC_INV_SQRT_SHIFT),
@@ -143,8 +138,7 @@ CoDelQueueDisc::CoDelQueueDisc ()
m_state1 (0),
m_state2 (0),
m_state3 (0),
- m_states (0),
- m_dropOverLimit (0)
+ m_states (0)
{
NS_LOG_FUNCTION (this);
}
@@ -192,21 +186,18 @@ bool
CoDelQueueDisc::DoEnqueue (Ptr item)
{
NS_LOG_FUNCTION (this << item);
- Ptr p = item->GetPacket ();
if (m_mode == QUEUE_DISC_MODE_PACKETS && (GetInternalQueue (0)->GetNPackets () + 1 > m_maxPackets))
{
NS_LOG_LOGIC ("Queue full (at max packets) -- dropping pkt");
- DropBeforeEnqueue (item);
- ++m_dropOverLimit;
+ DropBeforeEnqueue (item, OVERLIMIT_DROP);
return false;
}
if (m_mode == QUEUE_DISC_MODE_BYTES && (GetInternalQueue (0)->GetNBytes () + item->GetSize () > m_maxBytes))
{
NS_LOG_LOGIC ("Queue full (packet would exceed max bytes) -- dropping pkt");
- DropBeforeEnqueue (item);
- ++m_dropOverLimit;
+ DropBeforeEnqueue (item, OVERLIMIT_DROP);
return false;
}
@@ -307,9 +298,8 @@ CoDelQueueDisc::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 " << item);
- DropAfterDequeue (item);
+ DropAfterDequeue (item, TARGET_EXCEEDED_DROP);
- ++m_dropCount;
++m_count;
NewtonStep ();
item = GetInternalQueue (0)->Dequeue ();
@@ -346,8 +336,7 @@ CoDelQueueDisc::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 " << item << " and entering the dropping state");
- ++m_dropCount;
- DropAfterDequeue (item);
+ DropAfterDequeue (item, TARGET_EXCEEDED_DROP);
item = GetInternalQueue (0)->Dequeue ();
@@ -405,18 +394,6 @@ CoDelQueueDisc::GetQueueSize (void)
}
}
-uint32_t
-CoDelQueueDisc::GetDropOverLimit (void)
-{
- return m_dropOverLimit;
-}
-
-uint32_t
-CoDelQueueDisc::GetDropCount (void)
-{
- return m_dropCount;
-}
-
Time
CoDelQueueDisc::GetTarget (void)
{
diff --git a/src/traffic-control/model/codel-queue-disc.h b/src/traffic-control/model/codel-queue-disc.h
index 1f71fb281..5436dea5c 100644
--- a/src/traffic-control/model/codel-queue-disc.h
+++ b/src/traffic-control/model/codel-queue-disc.h
@@ -108,21 +108,6 @@ public:
*/
uint32_t GetQueueSize (void);
- /**
- * \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);
-
- /**
- * \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
*
@@ -144,6 +129,10 @@ public:
*/
uint32_t GetDropNext (void);
+ // 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
+
private:
friend class::CoDelQueueDiscNewtonStepTest; // Test code
friend class::CoDelQueueDiscControlLawTest; // Test code
@@ -242,7 +231,6 @@ private:
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; //!< Last number of packets dropped since entering drop state
TracedValue m_dropping; //!< True if in dropping state
uint16_t m_recInvSqrt; //!< Reciprocal inverse square root
@@ -252,7 +240,6 @@ private:
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
QueueDiscMode m_mode; //!< The operating mode (Bytes or packets)
};
diff --git a/src/traffic-control/model/fq-codel-queue-disc.cc b/src/traffic-control/model/fq-codel-queue-disc.cc
index 674eef47f..d9545c65d 100644
--- a/src/traffic-control/model/fq-codel-queue-disc.cc
+++ b/src/traffic-control/model/fq-codel-queue-disc.cc
@@ -128,8 +128,7 @@ TypeId FqCoDelQueueDisc::GetTypeId (void)
}
FqCoDelQueueDisc::FqCoDelQueueDisc ()
- : m_quantum (0),
- m_overlimitDroppedPackets (0)
+ : m_quantum (0)
{
NS_LOG_FUNCTION (this);
}
@@ -162,7 +161,7 @@ FqCoDelQueueDisc::DoEnqueue (Ptr item)
if (ret == PacketFilter::PF_NO_MATCH)
{
NS_LOG_ERROR ("No filter has been able to classify this packet, drop it.");
- DropBeforeEnqueue (item);
+ DropBeforeEnqueue (item, UNCLASSIFIED_DROP);
return false;
}
@@ -387,12 +386,11 @@ FqCoDelQueueDisc::FqCoDelDrop (void)
do
{
- item = qd->GetInternalQueue (0)->Remove ();
+ item = qd->GetInternalQueue (0)->Dequeue ();
+ DropAfterDequeue (item, OVERLIMIT_DROP);
len += item->GetSize ();
} while (++count < m_dropBatchSize && len < threshold);
- m_overlimitDroppedPackets += count;
-
return index;
}
diff --git a/src/traffic-control/model/fq-codel-queue-disc.h b/src/traffic-control/model/fq-codel-queue-disc.h
index 079f25235..4938326cb 100644
--- a/src/traffic-control/model/fq-codel-queue-disc.h
+++ b/src/traffic-control/model/fq-codel-queue-disc.h
@@ -126,6 +126,10 @@ public:
*/
uint32_t GetQuantum (void) const;
+ // Reasons for dropping packets
+ static constexpr const char* UNCLASSIFIED_DROP = "Unclassified drop"; //!< No packet filter able to classify packet
+ static constexpr const char* OVERLIMIT_DROP = "Overlimit drop"; //!< Overlimit dropped packets
+
private:
virtual bool DoEnqueue (Ptr item);
virtual Ptr DoDequeue (void);
@@ -146,8 +150,6 @@ private:
uint32_t m_flows; //!< Number of flow queues
uint32_t m_dropBatchSize; //!< Max number of packets dropped from the fat flow
- uint32_t m_overlimitDroppedPackets; //!< Number of overlimit dropped packets
-
std::list > m_newFlows; //!< The list of new flows
std::list > m_oldFlows; //!< The list of old flows
diff --git a/src/traffic-control/model/pfifo-fast-queue-disc.cc b/src/traffic-control/model/pfifo-fast-queue-disc.cc
index 3348a4f06..6926f796b 100644
--- a/src/traffic-control/model/pfifo-fast-queue-disc.cc
+++ b/src/traffic-control/model/pfifo-fast-queue-disc.cc
@@ -68,7 +68,7 @@ PfifoFastQueueDisc::DoEnqueue (Ptr item)
if (GetNPackets () >= m_limit)
{
NS_LOG_LOGIC ("Queue disc limit exceeded -- dropping packet");
- DropBeforeEnqueue (item);
+ DropBeforeEnqueue (item, LIMIT_EXCEEDED_DROP);
return false;
}
diff --git a/src/traffic-control/model/pfifo-fast-queue-disc.h b/src/traffic-control/model/pfifo-fast-queue-disc.h
index 49e163ec9..cf9c3170a 100644
--- a/src/traffic-control/model/pfifo-fast-queue-disc.h
+++ b/src/traffic-control/model/pfifo-fast-queue-disc.h
@@ -62,6 +62,9 @@ public:
virtual ~PfifoFastQueueDisc();
+ // Reasons for dropping packets
+ static constexpr const char* LIMIT_EXCEEDED_DROP = "Queue disc limit exceeded"; //!< Packet dropped due to queue disc limit exceeded
+
private:
/**
* Priority to band map. Values are taken from the prio2band array used by
diff --git a/src/traffic-control/model/pie-queue-disc.cc b/src/traffic-control/model/pie-queue-disc.cc
index dc4a067fe..d341e443b 100644
--- a/src/traffic-control/model/pie-queue-disc.cc
+++ b/src/traffic-control/model/pie-queue-disc.cc
@@ -164,13 +164,6 @@ PieQueueDisc::GetQueueSize (void)
}
}
-PieQueueDisc::Stats
-PieQueueDisc::GetStats ()
-{
- NS_LOG_FUNCTION (this);
- return m_stats;
-}
-
Time
PieQueueDisc::GetQueueDelay (void)
{
@@ -197,15 +190,13 @@ PieQueueDisc::DoEnqueue (Ptr item)
|| (GetMode () == QUEUE_DISC_MODE_BYTES && nQueued + item->GetSize () > m_queueLimit))
{
// Drops due to queue limit: reactive
- DropBeforeEnqueue (item);
- m_stats.forcedDrop++;
+ DropBeforeEnqueue (item, FORCED_DROP);
return false;
}
else if (DropEarly (item, nQueued))
{
// Early probability drop: proactive
- DropBeforeEnqueue (item);
- m_stats.unforcedDrop++;
+ DropBeforeEnqueue (item, UNFORCED_DROP);
return false;
}
@@ -232,8 +223,6 @@ PieQueueDisc::InitializeParams (void)
m_dqStart = 0;
m_burstState = NO_BURST;
m_qDelayOld = Time (Seconds (0));
- m_stats.forcedDrop = 0;
- m_stats.unforcedDrop = 0;
}
bool PieQueueDisc::DropEarly (Ptr item, uint32_t qSize)
diff --git a/src/traffic-control/model/pie-queue-disc.h b/src/traffic-control/model/pie-queue-disc.h
index 637115455..5ed9256ab 100644
--- a/src/traffic-control/model/pie-queue-disc.h
+++ b/src/traffic-control/model/pie-queue-disc.h
@@ -67,15 +67,6 @@ public:
*/
virtual ~PieQueueDisc ();
- /**
- * \brief Stats
- */
- typedef struct
- {
- uint32_t unforcedDrop; //!< Early probability drops: proactive
- uint32_t forcedDrop; //!< Drops due to queue limit: reactive
- } Stats;
-
/**
* \brief Burst types
*/
@@ -131,13 +122,6 @@ public:
*/
Time GetQueueDelay (void);
- /**
- * \brief Get PIE statistics after running.
- *
- * \returns The drop statistics.
- */
- Stats GetStats ();
-
/**
* Assign a fixed random variable stream number to the random variables
* used by this model. Return the number of streams (possibly zero) that
@@ -148,6 +132,10 @@ public:
*/
int64_t AssignStreams (int64_t stream);
+ // Reasons for dropping packets
+ static constexpr const char* UNFORCED_DROP = "Unforced drop"; //!< Early probability drops: proactive
+ static constexpr const char* FORCED_DROP = "Forced drop"; //!< Drops due to queue limit: reactive
+
protected:
/**
* \brief Dispose of the object
@@ -180,8 +168,6 @@ private:
*/
void CalculateP ();
- Stats m_stats; //!< PIE statistics
-
// ** Variables supplied by user
QueueDiscMode m_mode; //!< Mode (bytes or packets)
uint32_t m_queueLimit; //!< Queue limit in bytes / packets
diff --git a/src/traffic-control/model/queue-disc.cc b/src/traffic-control/model/queue-disc.cc
index 95f14b516..f025d8e14 100644
--- a/src/traffic-control/model/queue-disc.cc
+++ b/src/traffic-control/model/queue-disc.cc
@@ -103,13 +103,86 @@ QueueDisc::Stats::Stats ()
nTotalDroppedBytesBeforeEnqueue (0),
nTotalDroppedBytesAfterDequeue (0),
nTotalRequeuedPackets (0),
- nTotalRequeuedBytes (0)
+ nTotalRequeuedBytes (0),
+ nTotalMarkedPackets (0),
+ nTotalMarkedBytes (0)
{
}
+uint32_t
+QueueDisc::Stats::GetNDroppedPackets (std::string reason) const
+{
+ uint32_t count = 0;
+ auto it = nDroppedPacketsBeforeEnqueue.find (reason);
+
+ if (it != nDroppedPacketsBeforeEnqueue.end ())
+ {
+ count += it->second;
+ }
+
+ it = nDroppedPacketsAfterDequeue.find (reason);
+
+ if (it != nDroppedPacketsAfterDequeue.end ())
+ {
+ count += it->second;
+ }
+
+ return count;
+}
+
+uint64_t
+QueueDisc::Stats::GetNDroppedBytes (std::string reason) const
+{
+ uint64_t count = 0;
+ auto it = nDroppedBytesBeforeEnqueue.find (reason);
+
+ if (it != nDroppedBytesBeforeEnqueue.end ())
+ {
+ count += it->second;
+ }
+
+ it = nDroppedBytesAfterDequeue.find (reason);
+
+ if (it != nDroppedBytesAfterDequeue.end ())
+ {
+ count += it->second;
+ }
+
+ return count;
+}
+
+uint32_t
+QueueDisc::Stats::GetNMarkedPackets (std::string reason) const
+{
+ auto it = nMarkedPackets.find (reason);
+
+ if (it != nMarkedPackets.end ())
+ {
+ return it->second;
+ }
+
+ return 0;
+}
+
+uint64_t
+QueueDisc::Stats::GetNMarkedBytes (std::string reason) const
+{
+ auto it = nMarkedBytes.find (reason);
+
+ if (it != nMarkedBytes.end ())
+ {
+ return it->second;
+ }
+
+ return 0;
+}
+
void
QueueDisc::Stats::Print (std::ostream &os) const
{
+ std::map::const_iterator itp;
+ std::map::const_iterator itb;
+
os << std::endl << "Packets/Bytes received: "
<< nTotalReceivedPackets << " / "
<< nTotalReceivedBytes
@@ -127,14 +200,59 @@ QueueDisc::Stats::Print (std::ostream &os) const
<< nTotalDroppedBytes
<< std::endl << "Packets/Bytes dropped before enqueue: "
<< nTotalDroppedPacketsBeforeEnqueue << " / "
- << nTotalDroppedBytesBeforeEnqueue
- << std::endl << "Packets/Bytes dropped after dequeue: "
+ << nTotalDroppedBytesBeforeEnqueue;
+
+ itp = nDroppedPacketsBeforeEnqueue.begin ();
+ itb = nDroppedBytesBeforeEnqueue.begin ();
+
+ while (itp != nDroppedPacketsBeforeEnqueue.end () &&
+ itb != nDroppedBytesBeforeEnqueue.end ())
+ {
+ NS_ASSERT (itp->first.compare (itb->first) == 0);
+ os << std::endl << " " << itp->first << ": "
+ << itp->second << " / " << itb->second;
+ itp++;
+ itb++;
+ }
+
+ os << std::endl << "Packets/Bytes dropped after dequeue: "
<< nTotalDroppedPacketsAfterDequeue << " / "
- << nTotalDroppedBytesAfterDequeue
- << std::endl << "Packets/Bytes sent: "
+ << nTotalDroppedBytesAfterDequeue;
+
+ itp = nDroppedPacketsAfterDequeue.begin ();
+ itb = nDroppedBytesAfterDequeue.begin ();
+
+ while (itp != nDroppedPacketsAfterDequeue.end () &&
+ itb != nDroppedBytesAfterDequeue.end ())
+ {
+ NS_ASSERT (itp->first.compare (itb->first) == 0);
+ os << std::endl << " " << itp->first << ": "
+ << itp->second << " / " << itb->second;
+ itp++;
+ itb++;
+ }
+
+ os << std::endl << "Packets/Bytes sent: "
<< nTotalSentPackets << " / "
<< nTotalSentBytes
- << std::endl;
+ << std::endl << "Packets/Bytes marked: "
+ << nTotalMarkedPackets << " / "
+ << nTotalMarkedBytes;
+
+ itp = nMarkedPackets.begin ();
+ itb = nMarkedBytes.begin ();
+
+ while (itp != nMarkedPackets.end () &&
+ itb != nMarkedBytes.end ())
+ {
+ NS_ASSERT (itp->first.compare (itb->first) == 0);
+ os << std::endl << " " << itp->first << ": "
+ << itp->second << " / " << itb->second;
+ itp++;
+ itb++;
+ }
+
+ os << std::endl;
}
std::ostream & operator << (std::ostream &os, const QueueDisc::Stats &stats)
@@ -185,6 +303,9 @@ TypeId QueueDisc::GetTypeId (void)
.AddTraceSource ("DropAfterDequeue", "Drop a packet after dequeue",
MakeTraceSourceAccessor (&QueueDisc::m_traceDropAfterDequeue),
"ns3::QueueDiscItem::TracedCallback")
+ .AddTraceSource ("Mark", "Mark a packet stored in the queue disc",
+ MakeTraceSourceAccessor (&QueueDisc::m_traceMark),
+ "ns3::QueueDiscItem::TracedCallback")
.AddTraceSource ("PacketsInQueue",
"Number of packets currently stored in the queue disc",
MakeTraceSourceAccessor (&QueueDisc::m_nPackets),
@@ -208,6 +329,51 @@ QueueDisc::QueueDisc ()
m_running (false)
{
NS_LOG_FUNCTION (this);
+
+ using namespace std::placeholders;
+
+ // Remove ambiguity for overloaded member functions
+ typedef std::basic_string& (std::basic_string::*Function) (const char*);
+
+ Function append = &std::basic_string::append,
+ assign = &std::basic_string::assign;
+
+ // The operator() of these function objects calls the QueueDisc::DropBeforeEnqueue
+ // and QueueDisc::DropAfterDequeue methods of this QueueDisc object (these function
+ // objects are bound to this QueueDisc object), which require two arguments: a
+ // Ptr and a const char*. Given that a callback to the operator()
+ // is connected to the DropBeforeEnqueue and DropAfterDequeue traces of the Queue
+ // class, the first argument is provided by such traces, while the second argument
+ // (the reason why the packet was dropped) is bound to the INTERNAL_QUEUE_DROP constant.
+ m_internalQueueDbeFunctor = std::bind (&QueueDisc::DropBeforeEnqueue, this,
+ _1, (const char*)INTERNAL_QUEUE_DROP);
+ m_internalQueueDadFunctor = std::bind (&QueueDisc::DropAfterDequeue, this,
+ _1, (const char*)INTERNAL_QUEUE_DROP);
+
+ // The operator() of these function objects calls the QueueDisc::DropBeforeEnqueue
+ // and QueueDisc::DropAfterDequeue methods of this QueueDisc object (these function
+ // objects are bound to this QueueDisc object), which require two arguments: a
+ // Ptr and a const char*. Given that a callback to the operator()
+ // is connected to the DropBeforeEnqueue and DropAfterDequeue traces of the QueueDisc
+ // class, both arguments are provided by such traces. The first argument is provided
+ // as is, while the second argument (the reason why the packet was dropped) is obtained
+ // by calling m_childQueueDiscDropMsg.assign (CHILD_QUEUE_DISC_DROP).append (_2).data ()
+ // i.e., the second argument is the concatenation of the CHILD_QUEUE_DISC_DROP constant
+ // and the second argument provided by the traces of the QueueDisc class.
+ m_childQueueDiscDbeFunctor = std::bind (&QueueDisc::DropBeforeEnqueue, this, _1,
+ std::bind (&std::basic_string::data,
+ std::bind (append,
+ std::bind (assign,
+ &m_childQueueDiscDropMsg,
+ (const char*)CHILD_QUEUE_DISC_DROP),
+ _2)));
+ m_childQueueDiscDadFunctor = std::bind (&QueueDisc::DropAfterDequeue, this, _1,
+ std::bind (&std::basic_string::data,
+ std::bind (append,
+ std::bind (assign,
+ &m_childQueueDiscDropMsg,
+ (const char*)CHILD_QUEUE_DISC_DROP),
+ _2)));
}
QueueDisc::~QueueDisc ()
@@ -320,6 +486,7 @@ void
QueueDisc::AddInternalQueue (Ptr queue)
{
NS_LOG_FUNCTION (this);
+
// set various callbacks on the internal queue, so that the queue disc is
// notified of packets enqueued, dequeued or dropped by the internal queue
queue->TraceConnectWithoutContext ("Enqueue",
@@ -327,9 +494,11 @@ QueueDisc::AddInternalQueue (Ptr queue)
queue->TraceConnectWithoutContext ("Dequeue",
MakeCallback (&QueueDisc::PacketDequeued, this));
queue->TraceConnectWithoutContext ("DropBeforeEnqueue",
- MakeCallback (&QueueDisc::DropBeforeEnqueue, this));
+ MakeCallback (&InternalQueueDropFunctor::operator(),
+ &m_internalQueueDbeFunctor));
queue->TraceConnectWithoutContext ("DropAfterDequeue",
- MakeCallback (&QueueDisc::DropAfterDequeue, this));
+ MakeCallback (&InternalQueueDropFunctor::operator(),
+ &m_internalQueueDadFunctor));
m_queues.push_back (queue);
}
@@ -375,6 +544,7 @@ QueueDisc::AddQueueDiscClass (Ptr qdClass)
// such queue discs do not implement the enqueue/dequeue methods
NS_ABORT_MSG_IF (qdClass->GetQueueDisc ()->GetWakeMode () == WAKE_CHILD,
"A queue disc with WAKE_CHILD as wake mode can only be a root queue disc");
+
// set the parent callbacks on the child queue disc, so that it can notify
// the parent queue disc of packets enqueued, dequeued or dropped
qdClass->GetQueueDisc ()->TraceConnectWithoutContext ("Enqueue",
@@ -382,9 +552,11 @@ QueueDisc::AddQueueDiscClass (Ptr qdClass)
qdClass->GetQueueDisc ()->TraceConnectWithoutContext ("Dequeue",
MakeCallback (&QueueDisc::PacketDequeued, this));
qdClass->GetQueueDisc ()->TraceConnectWithoutContext ("DropBeforeEnqueue",
- MakeCallback (&QueueDisc::DropBeforeEnqueue, this));
+ MakeCallback (&ChildQueueDiscDropFunctor::operator(),
+ &m_childQueueDiscDbeFunctor));
qdClass->GetQueueDisc ()->TraceConnectWithoutContext ("DropAfterDequeue",
- MakeCallback (&QueueDisc::DropAfterDequeue, this));
+ MakeCallback (&ChildQueueDiscDropFunctor::operator(),
+ &m_childQueueDiscDadFunctor));
m_classes.push_back (qdClass);
}
@@ -448,33 +620,124 @@ QueueDisc::PacketDequeued (Ptr item)
}
void
-QueueDisc::DropBeforeEnqueue (Ptr item)
+QueueDisc::DropBeforeEnqueue (Ptr item, const char* reason)
{
- NS_LOG_FUNCTION (this << item);
+ NS_LOG_FUNCTION (this << item << reason);
m_stats.nTotalDroppedPackets++;
m_stats.nTotalDroppedBytes += item->GetSize ();
m_stats.nTotalDroppedPacketsBeforeEnqueue++;
m_stats.nTotalDroppedBytesBeforeEnqueue += item->GetSize ();
+ // update the number of packets dropped for the given reason
+ std::map::iterator itp = m_stats.nDroppedPacketsBeforeEnqueue.find (reason);
+ if (itp != m_stats.nDroppedPacketsBeforeEnqueue.end ())
+ {
+ itp->second++;
+ }
+ else
+ {
+ m_stats.nDroppedPacketsBeforeEnqueue[reason] = 1;
+ }
+ // update the amount of bytes dropped for the given reason
+ std::map::iterator itb = m_stats.nDroppedBytesBeforeEnqueue.find (reason);
+ if (itb != m_stats.nDroppedBytesBeforeEnqueue.end ())
+ {
+ itb->second += item->GetSize ();
+ }
+ else
+ {
+ m_stats.nDroppedBytesBeforeEnqueue[reason] = item->GetSize ();
+ }
+
+ NS_LOG_DEBUG ("Total packets/bytes dropped before enqueue: "
+ << m_stats.nTotalDroppedPacketsBeforeEnqueue << " / "
+ << m_stats.nTotalDroppedBytesBeforeEnqueue);
NS_LOG_LOGIC ("m_traceDropBeforeEnqueue (p)");
m_traceDrop (item);
- m_traceDropBeforeEnqueue (item);
+ m_traceDropBeforeEnqueue (item, reason);
}
void
-QueueDisc::DropAfterDequeue (Ptr item)
+QueueDisc::DropAfterDequeue (Ptr item, const char* reason)
{
- NS_LOG_FUNCTION (this << item);
+ NS_LOG_FUNCTION (this << item << reason);
m_stats.nTotalDroppedPackets++;
m_stats.nTotalDroppedBytes += item->GetSize ();
m_stats.nTotalDroppedPacketsAfterDequeue++;
m_stats.nTotalDroppedBytesAfterDequeue += item->GetSize ();
+ // update the number of packets dropped for the given reason
+ std::map::iterator itp = m_stats.nDroppedPacketsAfterDequeue.find (reason);
+ if (itp != m_stats.nDroppedPacketsAfterDequeue.end ())
+ {
+ itp->second++;
+ }
+ else
+ {
+ m_stats.nDroppedPacketsAfterDequeue[reason] = 1;
+ }
+ // update the amount of bytes dropped for the given reason
+ std::map::iterator itb = m_stats.nDroppedBytesAfterDequeue.find (reason);
+ if (itb != m_stats.nDroppedBytesAfterDequeue.end ())
+ {
+ itb->second += item->GetSize ();
+ }
+ else
+ {
+ m_stats.nDroppedBytesAfterDequeue[reason] = item->GetSize ();
+ }
+
+ NS_LOG_DEBUG ("Total packets/bytes dropped after dequeue: "
+ << m_stats.nTotalDroppedPacketsAfterDequeue << " / "
+ << m_stats.nTotalDroppedBytesAfterDequeue);
NS_LOG_LOGIC ("m_traceDropAfterDequeue (p)");
m_traceDrop (item);
- m_traceDropAfterDequeue (item);
+ m_traceDropAfterDequeue (item, reason);
+}
+
+bool
+QueueDisc::Mark (Ptr item, const char* reason)
+{
+ NS_LOG_FUNCTION (this << item << reason);
+
+ bool retval = item->Mark ();
+
+ if (!retval)
+ {
+ return false;
+ }
+
+ m_stats.nTotalMarkedPackets++;
+ m_stats.nTotalMarkedBytes += item->GetSize ();
+
+ // update the number of packets marked for the given reason
+ std::map::iterator itp = m_stats.nMarkedPackets.find (reason);
+ if (itp != m_stats.nMarkedPackets.end ())
+ {
+ itp->second++;
+ }
+ else
+ {
+ m_stats.nMarkedPackets[reason] = 1;
+ }
+ // update the amount of bytes marked for the given reason
+ std::map::iterator itb = m_stats.nMarkedBytes.find (reason);
+ if (itb != m_stats.nMarkedBytes.end ())
+ {
+ itb->second += item->GetSize ();
+ }
+ else
+ {
+ m_stats.nMarkedBytes[reason] = item->GetSize ();
+ }
+
+ NS_LOG_DEBUG ("Total packets/bytes marked: "
+ << m_stats.nTotalMarkedPackets << " / "
+ << m_stats.nTotalMarkedBytes);
+ m_traceMark (item, reason);
+ return true;
}
bool
diff --git a/src/traffic-control/model/queue-disc.h b/src/traffic-control/model/queue-disc.h
index 7763f891a..4aad70b30 100644
--- a/src/traffic-control/model/queue-disc.h
+++ b/src/traffic-control/model/queue-disc.h
@@ -25,6 +25,9 @@
#include "ns3/net-device.h"
#include "ns3/queue-item.h"
#include
+#include