--- a/CHANGES.html Wed Sep 13 23:11:38 2017 +0200
+++ b/CHANGES.html Thu Sep 14 18:12:19 2017 +0200
@@ -95,6 +95,14 @@
</li>
<li>MqQueueDisc, a multi-queue aware queue disc modelled after the mq qdisc in Linux, has been introduced.
</li>
+<li>Added <b>QueueDisc::GetStats()</b> which returns detailed statistics about the operations of a queue disc.
+ Consequently, a number of methods of the QueueDisc class have been removed: <b>GetTotalReceivedPackets()</b>,
+ <b>GetTotalReceivedBytes()</b>, <b>GetTotalDroppedPackets()</b>, <b>GetTotalDroppedBytes()</b>,
+ <b>GetTotalRequeuedPackets()</b>, <b>GetTotalRequeuedBytes()</b>.
+</li>
+<li>Two new methods, <b>QueueDisc::DropBeforeEnqueue()</b> and <b>QueueDisc::DropAfterDequeue()</b> have
+ been introduced to replace <b>QueueDisc::Drop()</b>. Correspondingly, two new trace sources have been added to the QueueDisc class: DropBeforeEnqueue and DropAfterDequeue.
+</li>
</ul>
<h2>Changes to existing API:</h2>
<ul>
--- a/RELEASE_NOTES Wed Sep 13 23:11:38 2017 +0200
+++ b/RELEASE_NOTES Thu Sep 14 18:12:19 2017 +0200
@@ -107,6 +107,7 @@
- Bug 2733 - Ideal wifi manager cannot handle NSS higher than 1
- Bug 2741 - IPv4 fragmentation fails when last fragment have to be re-fragmented.
- Bug 2744 - 802.11n/ac with RTS/CTS is crashing for a large number of nodes
+- Bug 2751 - QueueDisc::Enqueue() order of operations
- Bug 2757 - 802.11n/ac/ax maximum TXOP is not properly enforced
- Bug 2758 - IPv4 sockets bound to unicast receive also subnet-directed broadcasts
- Bug 2759 - Packets sent to broadcast address are converted to subnet-directed broadcast
--- a/examples/traffic-control/traffic-control.cc Wed Sep 13 23:11:38 2017 +0200
+++ b/examples/traffic-control/traffic-control.cc Thu Sep 14 18:12:19 2017 +0200
@@ -170,11 +170,11 @@
Ptr<Ipv4FlowClassifier> classifier = DynamicCast<Ipv4FlowClassifier> (flowmon.GetClassifier ());
std::map<FlowId, FlowMonitor::FlowStats> stats = monitor->GetFlowStats ();
std::cout << std::endl << "*** Flow monitor statistics ***" << std::endl;
- std::cout << " Tx Packets: " << stats[1].txPackets << std::endl;
- std::cout << " Tx Bytes: " << stats[1].txBytes << std::endl;
+ std::cout << " Tx Packets/Bytes: " << stats[1].txPackets
+ << " / " << stats[1].txBytes << std::endl;
std::cout << " Offered Load: " << stats[1].txBytes * 8.0 / (stats[1].timeLastTxPacket.GetSeconds () - stats[1].timeFirstTxPacket.GetSeconds ()) / 1000000 << " Mbps" << std::endl;
- std::cout << " Rx Packets: " << stats[1].rxPackets << std::endl;
- std::cout << " Rx Bytes: " << stats[1].rxBytes << std::endl;
+ std::cout << " Rx Packets/Bytes: " << stats[1].rxPackets
+ << " / " << stats[1].rxBytes << std::endl;
uint32_t packetsDroppedByQueueDisc = 0;
uint64_t bytesDroppedByQueueDisc = 0;
if (stats[1].packetsDropped.size () > Ipv4FlowProbe::DROP_QUEUE_DISC)
@@ -182,8 +182,8 @@
packetsDroppedByQueueDisc = stats[1].packetsDropped[Ipv4FlowProbe::DROP_QUEUE_DISC];
bytesDroppedByQueueDisc = stats[1].bytesDropped[Ipv4FlowProbe::DROP_QUEUE_DISC];
}
- std::cout << " Packets Dropped by Queue Disc: " << packetsDroppedByQueueDisc << std::endl;
- std::cout << " Bytes Dropped by Queue Disc: " << bytesDroppedByQueueDisc << std::endl;
+ std::cout << " Packets/Bytes Dropped by Queue Disc: " << packetsDroppedByQueueDisc
+ << " / " << bytesDroppedByQueueDisc << std::endl;
uint32_t packetsDroppedByNetDevice = 0;
uint64_t bytesDroppedByNetDevice = 0;
if (stats[1].packetsDropped.size () > Ipv4FlowProbe::DROP_QUEUE)
@@ -191,8 +191,8 @@
packetsDroppedByNetDevice = stats[1].packetsDropped[Ipv4FlowProbe::DROP_QUEUE];
bytesDroppedByNetDevice = stats[1].bytesDropped[Ipv4FlowProbe::DROP_QUEUE];
}
- std::cout << " Packets Dropped by NetDevice: " << packetsDroppedByNetDevice << std::endl;
- std::cout << " Bytes Dropped by NetDevice: " << bytesDroppedByNetDevice << std::endl;
+ std::cout << " Packets/Bytes Dropped by NetDevice: " << packetsDroppedByNetDevice
+ << " / " << bytesDroppedByNetDevice << std::endl;
std::cout << " Throughput: " << stats[1].rxBytes * 8.0 / (stats[1].timeLastRxPacket.GetSeconds () - stats[1].timeFirstRxPacket.GetSeconds ()) / 1000000 << " Mbps" << std::endl;
std::cout << " Mean delay: " << stats[1].delaySum.GetSeconds () / stats[1].rxPackets << std::endl;
std::cout << " Mean jitter: " << stats[1].jitterSum.GetSeconds () / (stats[1].rxPackets - 1) << std::endl;
@@ -212,10 +212,6 @@
std::cout << " Rx Bytes: " << totalPacketsThr << std::endl;
std::cout << " Average Goodput: " << thr << " Mbit/s" << std::endl;
std::cout << std::endl << "*** TC Layer statistics ***" << std::endl;
- std::cout << " Packets dropped by the TC layer: " << q->GetTotalDroppedPackets () << std::endl;
- std::cout << " Bytes dropped by the TC layer: " << q->GetTotalDroppedBytes () << std::endl;
- std::cout << " Packets dropped by the netdevice: " << queue->GetTotalDroppedPackets () << std::endl;
- std::cout << " Packets requeued by the TC layer: " << q->GetTotalRequeuedPackets () << std::endl;
-
+ std::cout << q->GetStats () << std::endl;
return 0;
}
--- a/src/network/utils/queue.h Wed Sep 13 23:11:38 2017 +0200
+++ b/src/network/utils/queue.h Thu Sep 14 18:12:19 2017 +0200
@@ -552,6 +552,10 @@
m_nBytes -= item->GetSize ();
m_nPackets--;
+ // packets are first dequeued and then dropped
+ NS_LOG_LOGIC ("m_traceDequeue (p)");
+ m_traceDequeue (item);
+
DropAfterDequeue (item);
}
return item;
--- a/src/traffic-control/doc/queue-discs.rst Wed Sep 13 23:11:38 2017 +0200
+++ b/src/traffic-control/doc/queue-discs.rst Thu Sep 14 18:12:19 2017 +0200
@@ -50,10 +50,26 @@
The traffic control layer interacts with a queue disc in a simple manner: after requesting
to enqueue a packet, the traffic control layer requests the qdisc to "run", i.e., to
dequeue a set of packets, until a predefined number ("quota") of packets is dequeued
-or the netdevice stops the queue disc. A netdevice may stop the queue disc when its
-transmission queue(s) is/are (almost) full. Also, a netdevice may wake the
-queue disc when its transmission queue(s) is/are (almost) empty. Waking a queue disc
-is equivalent to make it run.
+or the netdevice stops the queue disc. A netdevice shall
+stop the queue disc when its transmission queue does not have room for another
+packet. Also, a netdevice shall wake the queue disc when it detects that there
+is room for another packet in its transmission queue, but the transmission queue
+is stopped. Waking a queue disc is equivalent to make it run.
+
+Every queue disc collects statistics about the total number of packets/bytes
+received from the upper layers (in case of root queue disc) or from the parent
+queue disc (in case of child queue disc), enqueued, dequeued, requeued, dropped,
+dropped before enqueue, dropped after dequeue, stored in the queue disc and
+sent to the netdevice or to the parent queue disc. Note that packets that are
+dequeued may be requeued, i.e., retained by the traffic control infrastructure,
+if the netdevice is not ready to receive them. Requeued packets are not part
+of the queue disc. The following identities hold:
+
+* dropped = dropped before enqueue + dropped after dequeue
+* received = dropped before enqueue + enqueued
+* queued = enqueued - dequeued
+* sent = dequeued - dropped after dequeue (- 1 if there is a requeued packet)
+
Design
==========
--- a/src/traffic-control/model/codel-queue-disc.cc Wed Sep 13 23:11:38 2017 +0200
+++ b/src/traffic-control/model/codel-queue-disc.cc Thu Sep 14 18:12:19 2017 +0200
@@ -281,7 +281,7 @@
if (m_mode == QUEUE_DISC_MODE_PACKETS && (GetInternalQueue (0)->GetNPackets () + 1 > m_maxPackets))
{
NS_LOG_LOGIC ("Queue full (at max packets) -- droppping pkt");
- Drop (item);
+ DropBeforeEnqueue (item);
++m_dropOverLimit;
return false;
}
@@ -289,7 +289,7 @@
if (m_mode == QUEUE_DISC_MODE_BYTES && (GetInternalQueue (0)->GetNBytes () + item->GetSize () > m_maxBytes))
{
NS_LOG_LOGIC ("Queue full (packet would exceed max bytes) -- droppping pkt");
- Drop (item);
+ DropBeforeEnqueue (item);
++m_dropOverLimit;
return false;
}
@@ -300,8 +300,8 @@
bool retval = GetInternalQueue (0)->Enqueue (item);
- // If Queue::Enqueue fails, QueueDisc::Drop is called by the internal queue
- // because QueueDisc::AddInternalQueue sets the drop callback
+ // If Queue::Enqueue fails, QueueDisc::DropBeforeEnqueue is called by the
+ // internal queue because QueueDisc::AddInternalQueue sets the trace callback
NS_LOG_LOGIC ("Number packets " << GetInternalQueue (0)->GetNPackets ());
NS_LOG_LOGIC ("Number bytes " << GetInternalQueue (0)->GetNBytes ());
@@ -400,7 +400,7 @@
// 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);
- Drop (item);
+ DropAfterDequeue (item);
++m_dropCount;
++m_count;
@@ -440,7 +440,7 @@
// 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;
- Drop (item);
+ DropAfterDequeue (item);
item = GetInternalQueue (0)->Dequeue ();
--- a/src/traffic-control/model/fq-codel-queue-disc.cc Wed Sep 13 23:11:38 2017 +0200
+++ b/src/traffic-control/model/fq-codel-queue-disc.cc Thu Sep 14 18:12:19 2017 +0200
@@ -162,7 +162,7 @@
if (ret == PacketFilter::PF_NO_MATCH)
{
NS_LOG_ERROR ("No filter has been able to classify this packet, drop it.");
- Drop (item);
+ DropBeforeEnqueue (item);
return false;
}
--- a/src/traffic-control/model/pfifo-fast-queue-disc.cc Wed Sep 13 23:11:38 2017 +0200
+++ b/src/traffic-control/model/pfifo-fast-queue-disc.cc Thu Sep 14 18:12:19 2017 +0200
@@ -65,10 +65,10 @@
{
NS_LOG_FUNCTION (this << item);
- if (GetNPackets () > m_limit)
+ if (GetNPackets () >= m_limit)
{
NS_LOG_LOGIC ("Queue disc limit exceeded -- dropping packet");
- Drop (item);
+ DropBeforeEnqueue (item);
return false;
}
@@ -83,8 +83,8 @@
bool retval = GetInternalQueue (band)->Enqueue (item);
- // If Queue::Enqueue fails, QueueDisc::Drop is called by the internal queue
- // because QueueDisc::AddInternalQueue sets the drop callback
+ // If Queue::Enqueue fails, QueueDisc::DropBeforeEnqueue is called by the
+ // internal queue because QueueDisc::AddInternalQueue sets the trace callback
NS_LOG_LOGIC ("Number packets band " << band << ": " << GetInternalQueue (band)->GetNPackets ());
--- a/src/traffic-control/model/pie-queue-disc.cc Wed Sep 13 23:11:38 2017 +0200
+++ b/src/traffic-control/model/pie-queue-disc.cc Thu Sep 14 18:12:19 2017 +0200
@@ -197,14 +197,14 @@
|| (GetMode () == QUEUE_DISC_MODE_BYTES && nQueued + item->GetSize () > m_queueLimit))
{
// Drops due to queue limit: reactive
- Drop (item);
+ DropBeforeEnqueue (item);
m_stats.forcedDrop++;
return false;
}
else if (DropEarly (item, nQueued))
{
// Early probability drop: proactive
- Drop (item);
+ DropBeforeEnqueue (item);
m_stats.unforcedDrop++;
return false;
}
@@ -212,8 +212,8 @@
// No drop
bool retval = GetInternalQueue (0)->Enqueue (item);
- // If Queue::Enqueue fails, QueueDisc::Drop is called by the internal queue
- // because QueueDisc::AddInternalQueue sets the drop callback
+ // If Queue::Enqueue fails, QueueDisc::DropBeforeEnqueue is called by the
+ // internal queue because QueueDisc::AddInternalQueue sets the trace callback
NS_LOG_LOGIC ("\t bytesInQueue " << GetInternalQueue (0)->GetNBytes ());
NS_LOG_LOGIC ("\t packetsInQueue " << GetInternalQueue (0)->GetNPackets ());
--- a/src/traffic-control/model/queue-disc.cc Wed Sep 13 23:11:38 2017 +0200
+++ b/src/traffic-control/model/queue-disc.cc Thu Sep 14 18:12:19 2017 +0200
@@ -86,6 +86,61 @@
m_queueDisc = qd;
}
+QueueDisc::Stats::Stats ()
+ : nTotalReceivedPackets (0),
+ nTotalReceivedBytes (0),
+ nTotalSentPackets (0),
+ nTotalSentBytes (0),
+ nTotalEnqueuedPackets (0),
+ nTotalEnqueuedBytes (0),
+ nTotalDequeuedPackets (0),
+ nTotalDequeuedBytes (0),
+ nTotalDroppedPackets (0),
+ nTotalDroppedPacketsBeforeEnqueue (0),
+ nTotalDroppedPacketsAfterDequeue (0),
+ nTotalDroppedBytes (0),
+ nTotalDroppedBytesBeforeEnqueue (0),
+ nTotalDroppedBytesAfterDequeue (0),
+ nTotalRequeuedPackets (0),
+ nTotalRequeuedBytes (0)
+{
+}
+
+void
+QueueDisc::Stats::Print (std::ostream &os) const
+{
+ os << std::endl << "Packets/Bytes received: "
+ << nTotalReceivedPackets << " / "
+ << nTotalReceivedBytes
+ << std::endl << "Packets/Bytes enqueued: "
+ << nTotalEnqueuedPackets << " / "
+ << nTotalEnqueuedBytes
+ << std::endl << "Packets/Bytes dequeued: "
+ << nTotalDequeuedPackets << " / "
+ << nTotalDequeuedBytes
+ << std::endl << "Packets/Bytes requeued: "
+ << nTotalRequeuedPackets << " / "
+ << nTotalRequeuedBytes
+ << std::endl << "Packets/Bytes dropped: "
+ << nTotalDroppedPackets << " / "
+ << nTotalDroppedBytes
+ << std::endl << "Packets/Bytes dropped before enqueue: "
+ << nTotalDroppedPacketsBeforeEnqueue << " / "
+ << nTotalDroppedBytesBeforeEnqueue
+ << std::endl << "Packets/Bytes dropped after dequeue: "
+ << nTotalDroppedPacketsAfterDequeue << " / "
+ << nTotalDroppedBytesAfterDequeue
+ << std::endl << "Packets/Bytes sent: "
+ << nTotalSentPackets << " / "
+ << nTotalSentBytes
+ << std::endl;
+}
+
+std::ostream & operator << (std::ostream &os, const QueueDisc::Stats &stats)
+{
+ stats.Print (os);
+ return os;
+}
NS_OBJECT_ENSURE_REGISTERED (QueueDisc);
@@ -123,6 +178,12 @@
.AddTraceSource ("Drop", "Drop a packet stored in the queue disc",
MakeTraceSourceAccessor (&QueueDisc::m_traceDrop),
"ns3::QueueDiscItem::TracedCallback")
+ .AddTraceSource ("DropBeforeEnqueue", "Drop a packet before enqueue",
+ MakeTraceSourceAccessor (&QueueDisc::m_traceDropBeforeEnqueue),
+ "ns3::QueueDiscItem::TracedCallback")
+ .AddTraceSource ("DropAfterDequeue", "Drop a packet after dequeue",
+ MakeTraceSourceAccessor (&QueueDisc::m_traceDropAfterDequeue),
+ "ns3::QueueDiscItem::TracedCallback")
.AddTraceSource ("PacketsInQueue",
"Number of packets currently stored in the queue disc",
MakeTraceSourceAccessor (&QueueDisc::m_nPackets),
@@ -138,12 +199,6 @@
QueueDisc::QueueDisc ()
: m_nPackets (0),
m_nBytes (0),
- m_nTotalReceivedPackets (0),
- m_nTotalReceivedBytes (0),
- m_nTotalDroppedPackets (0),
- m_nTotalDroppedBytes (0),
- m_nTotalRequeuedPackets (0),
- m_nTotalRequeuedBytes (0),
m_running (false)
{
NS_LOG_FUNCTION (this);
@@ -194,6 +249,25 @@
Object::DoInitialize ();
}
+const QueueDisc::Stats&
+QueueDisc::GetStats (void)
+{
+ NS_ASSERT (m_stats.nTotalDroppedPackets == m_stats.nTotalDroppedPacketsBeforeEnqueue
+ + m_stats.nTotalDroppedPacketsAfterDequeue);
+ NS_ASSERT (m_stats.nTotalDroppedBytes == m_stats.nTotalDroppedBytesBeforeEnqueue
+ + m_stats.nTotalDroppedBytesAfterDequeue);
+
+ // the total number of sent packets is only updated here to avoid to increase it
+ // after a dequeue and then having to decrease it if the packet is dropped after
+ // dequeue or requeued
+ m_stats.nTotalSentPackets = m_stats.nTotalDequeuedPackets - (m_requeued ? 1 : 0)
+ - m_stats.nTotalDroppedPacketsAfterDequeue;
+ m_stats.nTotalSentBytes = m_stats.nTotalDequeuedBytes - (m_requeued ? m_requeued->GetSize () : 0)
+ - m_stats.nTotalDroppedBytesAfterDequeue;
+
+ return m_stats;
+}
+
uint32_t
QueueDisc::GetNPackets () const
{
@@ -208,48 +282,6 @@
return m_nBytes;
}
-uint32_t
-QueueDisc::GetTotalReceivedPackets (void) const
-{
- NS_LOG_FUNCTION (this);
- return m_nTotalReceivedPackets;
-}
-
-uint32_t
-QueueDisc::GetTotalReceivedBytes (void) const
-{
- NS_LOG_FUNCTION (this);
- return m_nTotalReceivedBytes;
-}
-
-uint32_t
-QueueDisc::GetTotalDroppedPackets (void) const
-{
- NS_LOG_FUNCTION (this);
- return m_nTotalDroppedPackets;
-}
-
-uint32_t
-QueueDisc:: GetTotalDroppedBytes (void) const
-{
- NS_LOG_FUNCTION (this);
- return m_nTotalDroppedBytes;
-}
-
-uint32_t
-QueueDisc::GetTotalRequeuedPackets (void) const
-{
- NS_LOG_FUNCTION (this);
- return m_nTotalRequeuedPackets;
-}
-
-uint32_t
-QueueDisc:: GetTotalRequeuedBytes (void) const
-{
- NS_LOG_FUNCTION (this);
- return m_nTotalRequeuedBytes;
-}
-
void
QueueDisc::SetNetDevice (Ptr<NetDevice> device)
{
@@ -282,9 +314,16 @@
QueueDisc::AddInternalQueue (Ptr<InternalQueue> queue)
{
NS_LOG_FUNCTION (this);
- // set the drop callback on the internal queue, so that the queue disc is
- // notified of packets dropped by the internal queue
- queue->TraceConnectWithoutContext ("Drop", MakeCallback (&QueueDisc::Drop, 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",
+ MakeCallback (&QueueDisc::PacketEnqueued, this));
+ queue->TraceConnectWithoutContext ("Dequeue",
+ MakeCallback (&QueueDisc::PacketDequeued, this));
+ queue->TraceConnectWithoutContext ("DropBeforeEnqueue",
+ MakeCallback (&QueueDisc::DropBeforeEnqueue, this));
+ queue->TraceConnectWithoutContext ("DropAfterDequeue",
+ MakeCallback (&QueueDisc::DropAfterDequeue, this));
m_queues.push_back (queue);
}
@@ -330,9 +369,16 @@
// 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 drop callback on the child queue disc, so that it can notify
- // packet drops to the parent queue disc
- qdClass->GetQueueDisc ()->SetParentDropCallback (MakeCallback (&QueueDisc::Drop, this));
+ // 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",
+ MakeCallback (&QueueDisc::PacketEnqueued, this));
+ qdClass->GetQueueDisc ()->TraceConnectWithoutContext ("Dequeue",
+ MakeCallback (&QueueDisc::PacketDequeued, this));
+ qdClass->GetQueueDisc ()->TraceConnectWithoutContext ("DropBeforeEnqueue",
+ MakeCallback (&QueueDisc::DropBeforeEnqueue, this));
+ qdClass->GetQueueDisc ()->TraceConnectWithoutContext ("DropAfterDequeue",
+ MakeCallback (&QueueDisc::DropAfterDequeue, this));
m_classes.push_back (qdClass);
}
@@ -370,49 +416,57 @@
}
void
-QueueDisc::SetParentDropCallback (ParentDropCallback cb)
+QueueDisc::PacketEnqueued (Ptr<const QueueDiscItem> item)
{
- m_parentDropCallback = cb;
+ m_nPackets++;
+ m_nBytes += item->GetSize ();
+ m_stats.nTotalEnqueuedPackets++;
+ m_stats.nTotalEnqueuedBytes += item->GetSize ();
+
+ NS_LOG_LOGIC ("m_traceEnqueue (p)");
+ m_traceEnqueue (item);
}
void
-QueueDisc::Drop (Ptr<const QueueDiscItem> item)
+QueueDisc::PacketDequeued (Ptr<const QueueDiscItem> item)
+{
+ m_nPackets--;
+ m_nBytes -= item->GetSize ();
+ m_stats.nTotalDequeuedPackets++;
+ m_stats.nTotalDequeuedBytes += item->GetSize ();
+
+ NS_LOG_LOGIC ("m_traceDequeue (p)");
+ m_traceDequeue (item);
+}
+
+void
+QueueDisc::DropBeforeEnqueue (Ptr<const QueueDiscItem> item)
{
NS_LOG_FUNCTION (this << item);
- // if the wake mode of this queue disc is WAKE_CHILD, packets are directly
- // enqueued/dequeued from the child queue discs, thus this queue disc does not
- // keep valid packets/bytes counters and no actions need to be performed.
- if (this->GetWakeMode () == WAKE_CHILD)
- {
- return;
- }
+ m_stats.nTotalDroppedPackets++;
+ m_stats.nTotalDroppedBytes += item->GetSize ();
+ m_stats.nTotalDroppedPacketsBeforeEnqueue++;
+ m_stats.nTotalDroppedBytesBeforeEnqueue += item->GetSize ();
- NS_ASSERT_MSG (m_nPackets >= 1u, "No packet in the queue disc, cannot drop");
- NS_ASSERT_MSG (m_nBytes >= item->GetSize (), "The size of the packet that"
- << " is reported to be dropped is greater than the amount of bytes"
- << "stored in the queue disc");
-
- m_nPackets--;
- m_nBytes -= item->GetSize ();
- m_nTotalDroppedPackets++;
- m_nTotalDroppedBytes += item->GetSize ();
-
- NS_LOG_LOGIC ("m_traceDrop (p)");
+ NS_LOG_LOGIC ("m_traceDropBeforeEnqueue (p)");
m_traceDrop (item);
-
- NotifyParentDrop (item);
+ m_traceDropBeforeEnqueue (item);
}
void
-QueueDisc::NotifyParentDrop (Ptr<const QueueDiscItem> item)
+QueueDisc::DropAfterDequeue (Ptr<const QueueDiscItem> item)
{
NS_LOG_FUNCTION (this << item);
- // the parent drop callback is clearly null on root queue discs
- if (!m_parentDropCallback.IsNull ())
- {
- m_parentDropCallback (item);
- }
+
+ m_stats.nTotalDroppedPackets++;
+ m_stats.nTotalDroppedBytes += item->GetSize ();
+ m_stats.nTotalDroppedPacketsAfterDequeue++;
+ m_stats.nTotalDroppedBytesAfterDequeue += item->GetSize ();
+
+ NS_LOG_LOGIC ("m_traceDropAfterDequeue (p)");
+ m_traceDrop (item);
+ m_traceDropAfterDequeue (item);
}
bool
@@ -420,15 +474,29 @@
{
NS_LOG_FUNCTION (this << item);
- m_nPackets++;
- m_nBytes += item->GetSize ();
- m_nTotalReceivedPackets++;
- m_nTotalReceivedBytes += item->GetSize ();
+ m_stats.nTotalReceivedPackets++;
+ m_stats.nTotalReceivedBytes += item->GetSize ();
+
+ bool retval = DoEnqueue (item);
- NS_LOG_LOGIC ("m_traceEnqueue (p)");
- m_traceEnqueue (item);
+ // DoEnqueue may return false because:
+ // 1) the internal queue is full
+ // -> the DropBeforeEnqueue method of this queue disc is automatically called
+ // because QueueDisc::AddInternalQueue sets the trace callback
+ // 2) the child queue disc dropped the packet
+ // -> the DropBeforeEnqueue method of this queue disc is automatically called
+ // because QueueDisc::AddQueueDiscClass sets the trace callback
+ // 3) it dropped the packet
+ // -> DoEnqueue has to explicitly call DropBeforeEnqueue
+ // Thus, we do not have to call DropBeforeEnqueue here.
- return DoEnqueue (item);
+ // check that the received packet was either enqueued or dropped
+ NS_ASSERT (m_stats.nTotalReceivedPackets == m_stats.nTotalDroppedPacketsBeforeEnqueue +
+ m_stats.nTotalEnqueuedPackets);
+ NS_ASSERT (m_stats.nTotalReceivedBytes == m_stats.nTotalDroppedBytesBeforeEnqueue +
+ m_stats.nTotalEnqueuedBytes);
+
+ return retval;
}
Ptr<QueueDiscItem>
@@ -436,17 +504,10 @@
{
NS_LOG_FUNCTION (this);
- Ptr<QueueDiscItem> item;
- item = DoDequeue ();
+ Ptr<QueueDiscItem> item = DoDequeue ();
- if (item != 0)
- {
- m_nPackets--;
- m_nBytes -= item->GetSize ();
-
- NS_LOG_LOGIC ("m_traceDequeue (p)");
- m_traceDequeue (item);
- }
+ NS_ASSERT (m_nPackets == m_stats.nTotalEnqueuedPackets - m_stats.nTotalDequeuedPackets);
+ NS_ASSERT (m_nBytes == m_stats.nTotalEnqueuedBytes - m_stats.nTotalDequeuedBytes);
return item;
}
@@ -530,12 +591,6 @@
{
item = m_requeued;
m_requeued = 0;
-
- m_nPackets--;
- m_nBytes -= item->GetSize ();
-
- NS_LOG_LOGIC ("m_traceDequeue (p)");
- m_traceDequeue (item);
}
}
else
@@ -566,10 +621,8 @@
m_requeued = item;
/// \todo netif_schedule (q);
- m_nPackets++; // it's still part of the queue
- m_nBytes += item->GetSize ();
- m_nTotalRequeuedPackets++;
- m_nTotalRequeuedBytes += item->GetSize ();
+ m_stats.nTotalRequeuedPackets++;
+ m_stats.nTotalRequeuedBytes += item->GetSize ();
NS_LOG_LOGIC ("m_traceRequeue (p)");
m_traceRequeue (item);
--- a/src/traffic-control/model/queue-disc.h Wed Sep 13 23:11:38 2017 +0200
+++ b/src/traffic-control/model/queue-disc.h Thu Sep 14 18:12:19 2017 +0200
@@ -107,19 +107,80 @@
* An attempt is made, also, to enqueue each packet in the "same" queue both within the
* queue disc and within the device.
*
- * The traffic control layer interacts with a queue disc in a simple manner: after requesting
- * to enqueue a packet, the traffic control layer requests the qdisc to "run", i.e., to
- * dequeue a set of packets, until a predefined number ("quota") of packets is dequeued
- * or the netdevice stops the queue disc. A netdevice may stop the queue disc when its
- * transmission queue(s) is/are (almost) full. Also, a netdevice may wake the
- * queue disc when its transmission queue(s) is/are (almost) empty. Waking a queue disc
- * is equivalent to make it run.
+ * The traffic control layer interacts with a queue disc in a simple manner: after
+ * requesting to enqueue a packet, the traffic control layer requests the qdisc to
+ * "run", i.e., to dequeue a set of packets, until a predefined number ("quota")
+ * of packets is dequeued or the netdevice stops the queue disc. A netdevice shall
+ * stop the queue disc when its transmission queue does not have room for another
+ * packet. Also, a netdevice shall wake the queue disc when it detects that there
+ * is room for another packet in its transmission queue, but the transmission queue
+ * is stopped. Waking a queue disc is equivalent to make it run.
+ *
+ * Every queue disc collects statistics about the total number of packets/bytes
+ * received from the upper layers (in case of root queue disc) or from the parent
+ * queue disc (in case of child queue disc), enqueued, dequeued, requeued, dropped,
+ * dropped before enqueue, dropped after dequeue, queued in the queue disc and
+ * sent to the netdevice or to the parent queue disc. Note that packets that are
+ * dequeued may be requeued, i.e., retained by the traffic control infrastructure,
+ * if the netdevice is not ready to receive them. Requeued packets are not part
+ * of the queue disc. The following identities hold:
+ * - dropped = dropped before enqueue + dropped after dequeue
+ * - received = dropped before enqueue + enqueued
+ * - queued = enqueued - dequeued
+ * - sent = dequeued - dropped after dequeue (- 1 if there is a requeued packet)
*
* The design and implementation of this class is heavily inspired by Linux.
* For more details, see the traffic-control model page.
*/
class QueueDisc : public Object {
public:
+
+ /// \brief Structure that keeps the queue disc statistics
+ struct Stats
+ {
+ /// Total received packets
+ uint32_t nTotalReceivedPackets;
+ /// Total received bytes
+ uint64_t nTotalReceivedBytes;
+ /// Total sent packets -- this value is not kept up to date, call GetStats first
+ uint32_t nTotalSentPackets;
+ /// Total sent bytes -- this value is not kept up to date, call GetStats first
+ uint64_t nTotalSentBytes;
+ /// Total enqueued packets
+ uint32_t nTotalEnqueuedPackets;
+ /// Total enqueued bytes
+ uint64_t nTotalEnqueuedBytes;
+ /// Total dequeued packets
+ uint32_t nTotalDequeuedPackets;
+ /// Total dequeued bytes
+ uint64_t nTotalDequeuedBytes;
+ /// Total dropped packets
+ uint32_t nTotalDroppedPackets;
+ /// Total packets dropped before enqueue
+ uint32_t nTotalDroppedPacketsBeforeEnqueue;
+ /// Total packets dropped after dequeue
+ uint32_t nTotalDroppedPacketsAfterDequeue;
+ /// Total dropped bytes
+ uint64_t nTotalDroppedBytes;
+ /// Total bytes dropped before enqueue
+ uint64_t nTotalDroppedBytesBeforeEnqueue;
+ /// Total bytes dropped after dequeue
+ uint64_t nTotalDroppedBytesAfterDequeue;
+ /// Total requeued packets
+ uint32_t nTotalRequeuedPackets;
+ /// Total requeued bytes
+ uint64_t nTotalRequeuedBytes;
+
+ /// constructor
+ Stats ();
+
+ /**
+ * \brief Print the statistics.
+ * \param os output stream in which the data should be printed.
+ */
+ void Print (std::ostream &os) const;
+ };
+
/**
* \brief Get the type ID.
* \return the object TypeId
@@ -133,12 +194,7 @@
* \brief Get the number of packets stored by the queue disc
* \return the number of packets stored by the queue disc.
*
- * Note that the number of packets stored by the queue disc is updated as soon
- * as a packet is received by the queue disc and before actually enqueuing the
- * packet (i.e., before calling DoEnqueue). Thus, while implementing the DoEnqueue
- * method of a subclass, keep in mind that GetNPackets returns the number of
- * packets stored in the queue disc, including the packet that we are trying
- * to enqueue.
+ * The requeued packet, if any, is counted.
*/
uint32_t GetNPackets (void) const;
@@ -146,50 +202,15 @@
* \brief Get the amount of bytes stored by the queue disc
* \return the amount of bytes stored by the queue disc.
*
- * Note that the amount of bytes stored by the queue disc is updated as soon
- * as a packet is received by the queue disc and before actually enqueuing the
- * packet (i.e., before calling DoEnqueue). Thus, while implementing the DoEnqueue
- * method of a subclass, keep in mind that GetNBytes returns the amount of
- * bytes stored in the queue disc, including the size of the packet that we are
- * trying to enqueue.
+ * The requeued packet, if any, is counted.
*/
uint32_t GetNBytes (void) const;
/**
- * \brief Get the total number of received packets
- * \return the total number of received packets.
- */
- uint32_t GetTotalReceivedPackets (void) const;
-
- /**
- * \brief Get the total amount of received bytes
- * \return the total amount of received bytes.
- */
- uint32_t GetTotalReceivedBytes (void) const;
-
- /**
- * \brief Get the total number of dropped packets
- * \return the total number of dropped packets.
+ * \brief Retrieve all the collected statistics.
+ * \return the collected statistics.
*/
- uint32_t GetTotalDroppedPackets (void) const;
-
- /**
- * \brief Get the total amount of dropped bytes
- * \return the total amount of dropped bytes.
- */
- uint32_t GetTotalDroppedBytes (void) const;
-
- /**
- * \brief Get the total number of requeued packets
- * \return the total number of requeued packets.
- */
- uint32_t GetTotalRequeuedPackets (void) const;
-
- /**
- * \brief Get the total amount of requeued bytes
- * \return the total amount of requeued bytes.
- */
- uint32_t GetTotalRequeuedBytes (void) const;
+ const Stats& GetStats (void);
/**
* \brief Set the NetDevice on which this queue discipline is installed.
@@ -341,18 +362,6 @@
*/
virtual WakeMode GetWakeMode (void) const;
- /// Callback invoked by a child queue disc to notify the parent of a packet drop
- typedef Callback<void, Ptr<const QueueDiscItem> > ParentDropCallback;
-
- /**
- * \brief Set the parent drop callback
- * \param cb the callback to set
- *
- * Called when a queue disc class is added to a queue disc in order to set a
- * callback to the Drop method of the parent queue disc.
- */
- virtual void SetParentDropCallback (ParentDropCallback cb);
-
protected:
/**
* \brief Dispose of the object
@@ -369,11 +378,22 @@
void DoInitialize (void);
/**
- * \brief Drop a packet
+ * \brief Perform the actions required when the queue disc is notified of
+ * a packet dropped before enqueue
* \param item item that was dropped
- * This method is called by subclasses to notify parent (this class) of packet drops.
+ * This method must be called by subclasses to notify parent (this class) of a packet
+ * dropped before enqueue
*/
- void Drop (Ptr<const QueueDiscItem> item);
+ void DropBeforeEnqueue (Ptr<const QueueDiscItem> item);
+
+ /**
+ * \brief Perform the actions required when the queue disc is notified of
+ * a packet dropped after dequeue
+ * \param item item that was dropped
+ * This method must be called by subclasses to notify parent (this class) of a packet
+ * dropped after dequeue
+ */
+ void DropAfterDequeue (Ptr<const QueueDiscItem> item);
private:
/**
@@ -394,12 +414,6 @@
QueueDisc &operator = (const QueueDisc &o);
/**
- * \brief Notify the parent queue disc of a packet drop
- * \param item item that was dropped
- */
- void NotifyParentDrop (Ptr<const QueueDiscItem> item);
-
- /**
* This function actually enqueues a packet into the queue disc.
* \param item item to enqueue
* \return True if the operation was successful; false otherwise
@@ -472,6 +486,20 @@
*/
bool Transmit (Ptr<QueueDiscItem> item);
+ /**
+ * \brief Perform the actions required when the queue disc is notified of
+ * a packet enqueue
+ * \param item item that was enqueued
+ */
+ void PacketEnqueued (Ptr<const QueueDiscItem> item);
+
+ /**
+ * \brief Perform the actions required when the queue disc is notified of
+ * a packet dequeue
+ * \param item item that was dequeued
+ */
+ void PacketDequeued (Ptr<const QueueDiscItem> item);
+
static const uint32_t DEFAULT_QUOTA = 64; //!< Default quota (as in /proc/sys/net/core/dev_weight)
std::vector<Ptr<InternalQueue> > m_queues; //!< Internal queues
@@ -481,29 +509,36 @@
TracedValue<uint32_t> m_nPackets; //!< Number of packets in the queue
TracedValue<uint32_t> m_nBytes; //!< Number of bytes in the queue
- uint32_t m_nTotalReceivedPackets; //!< Total received packets
- uint32_t m_nTotalReceivedBytes; //!< Total received bytes
- uint32_t m_nTotalDroppedPackets; //!< Total dropped packets
- uint32_t m_nTotalDroppedBytes; //!< Total dropped bytes
- uint32_t m_nTotalRequeuedPackets; //!< Total requeued packets
- uint32_t m_nTotalRequeuedBytes; //!< Total requeued bytes
+ Stats m_stats; //!< The collected statistics
uint32_t m_quota; //!< Maximum number of packets dequeued in a qdisc run
Ptr<NetDevice> m_device; //!< The NetDevice on which this queue discipline is installed
Ptr<NetDeviceQueueInterface> m_devQueueIface; //!< NetDevice queue interface
bool m_running; //!< The queue disc is performing multiple dequeue operations
Ptr<QueueDiscItem> m_requeued; //!< The last packet that failed to be transmitted
- ParentDropCallback m_parentDropCallback; //!< Parent drop callback
/// Traced callback: fired when a packet is enqueued
TracedCallback<Ptr<const QueueDiscItem> > m_traceEnqueue;
/// Traced callback: fired when a packet is dequeued
TracedCallback<Ptr<const QueueDiscItem> > m_traceDequeue;
- /// Traced callback: fired when a packet is requeued
+ /// Traced callback: fired when a packet is requeued
TracedCallback<Ptr<const QueueDiscItem> > m_traceRequeue;
/// Traced callback: fired when a packet is dropped
TracedCallback<Ptr<const QueueDiscItem> > m_traceDrop;
+ /// Traced callback: fired when a packet is dropped before enqueue
+ TracedCallback<Ptr<const QueueDiscItem> > m_traceDropBeforeEnqueue;
+ /// Traced callback: fired when a packet is dropped after dequeue
+ TracedCallback<Ptr<const QueueDiscItem> > m_traceDropAfterDequeue;
};
+/**
+ * \brief Stream insertion operator.
+ *
+ * \param os the stream
+ * \param stats the queue disc statistics
+ * \returns a reference to the stream
+ */
+std::ostream& operator<< (std::ostream& os, const QueueDisc::Stats &stats);
+
} // namespace ns3
#endif /* QueueDisc */
--- a/src/traffic-control/model/red-queue-disc.cc Wed Sep 13 23:11:38 2017 +0200
+++ b/src/traffic-control/model/red-queue-disc.cc Thu Sep 14 18:12:19 2017 +0200
@@ -457,7 +457,7 @@
{
NS_LOG_DEBUG ("\t Dropping due to Prob Mark " << m_qAvg);
m_stats.unforcedDrop++;
- Drop (item);
+ DropBeforeEnqueue (item);
return false;
}
NS_LOG_DEBUG ("\t Marking due to Prob Mark " << m_qAvg);
@@ -469,7 +469,7 @@
{
NS_LOG_DEBUG ("\t Dropping due to Hard Mark " << m_qAvg);
m_stats.forcedDrop++;
- Drop (item);
+ DropBeforeEnqueue (item);
if (m_isNs1Compat)
{
m_count = 0;
@@ -488,8 +488,8 @@
m_stats.qLimDrop++;
}
- // If Queue::Enqueue fails, QueueDisc::Drop is called by the internal queue
- // because QueueDisc::AddInternalQueue sets the drop callback
+ // If Queue::Enqueue fails, QueueDisc::DropBeforeEnqueue is called by the
+ // internal queue because QueueDisc::AddInternalQueue sets the trace callback
NS_LOG_LOGIC ("Number packets " << GetInternalQueue (0)->GetNPackets ());
NS_LOG_LOGIC ("Number bytes " << GetInternalQueue (0)->GetNBytes ());