traffic-control: (fixes #2751) Ensure queue discs keep correct statistics

This commit is contained in:
Stefano Avallone
2017-09-14 18:12:19 +02:00
parent 923ef42e42
commit 59cd4d5f55
12 changed files with 341 additions and 228 deletions

View File

@@ -95,6 +95,14 @@ us a note on ns-developers mailing list.</p>
</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>

View File

@@ -107,6 +107,7 @@ Bugs fixed
- 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

View File

@@ -170,11 +170,11 @@ main (int argc, char *argv[])
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 @@ main (int argc, char *argv[])
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 @@ main (int argc, char *argv[])
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 @@ main (int argc, char *argv[])
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;
}

View File

@@ -552,6 +552,10 @@ Queue<Item>::DoRemove (ConstIterator pos)
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;

View File

@@ -50,10 +50,26 @@ 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.
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
==========

View File

@@ -281,7 +281,7 @@ CoDelQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
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 @@ CoDelQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
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 @@ CoDelQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
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 @@ 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);
Drop (item);
DropAfterDequeue (item);
++m_dropCount;
++m_count;
@@ -440,7 +440,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;
Drop (item);
DropAfterDequeue (item);
item = GetInternalQueue (0)->Dequeue ();

View File

@@ -162,7 +162,7 @@ FqCoDelQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
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;
}

View File

@@ -65,10 +65,10 @@ PfifoFastQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
{
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 @@ PfifoFastQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
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 ());

View File

@@ -197,14 +197,14 @@ PieQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
|| (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 @@ PieQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
// 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 ());

View File

@@ -86,6 +86,61 @@ QueueDiscClass::SetQueueDisc (Ptr<QueueDisc> qd)
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 @@ TypeId QueueDisc::GetTypeId (void)
.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 @@ TypeId QueueDisc::GetTypeId (void)
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 @@ QueueDisc::DoInitialize (void)
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 @@ QueueDisc::GetNBytes (void) const
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 @@ void
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 @@ QueueDisc::AddQueueDiscClass (Ptr<QueueDiscClass> 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 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 @@ QueueDisc::GetWakeMode (void) const
}
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)
{
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;
}
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 ();
m_stats.nTotalDequeuedPackets++;
m_stats.nTotalDequeuedBytes += item->GetSize ();
NS_LOG_LOGIC ("m_traceDrop (p)");
m_traceDrop (item);
NotifyParentDrop (item);
NS_LOG_LOGIC ("m_traceDequeue (p)");
m_traceDequeue (item);
}
void
QueueDisc::NotifyParentDrop (Ptr<const QueueDiscItem> item)
QueueDisc::DropBeforeEnqueue (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.nTotalDroppedPacketsBeforeEnqueue++;
m_stats.nTotalDroppedBytesBeforeEnqueue += item->GetSize ();
NS_LOG_LOGIC ("m_traceDropBeforeEnqueue (p)");
m_traceDrop (item);
m_traceDropBeforeEnqueue (item);
}
void
QueueDisc::DropAfterDequeue (Ptr<const QueueDiscItem> item)
{
NS_LOG_FUNCTION (this << 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 @@ QueueDisc::Enqueue (Ptr<QueueDiscItem> item)
{
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 ();
NS_LOG_LOGIC ("m_traceEnqueue (p)");
m_traceEnqueue (item);
bool retval = DoEnqueue (item);
return DoEnqueue (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.
// 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 @@ QueueDisc::Dequeue (void)
{
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 @@ QueueDisc::DequeuePacket ()
{
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 @@ QueueDisc::Requeue (Ptr<QueueDiscItem> item)
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);

View File

@@ -107,19 +107,80 @@ private:
* 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 @@ public:
* \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 @@ public:
* \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.
* \brief Retrieve all the collected statistics.
* \return the collected statistics.
*/
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.
*/
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 @@ public:
*/
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 @@ protected:
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:
/**
@@ -393,12 +413,6 @@ private:
*/
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
@@ -472,6 +486,20 @@ private:
*/
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 @@ private:
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 */

View File

@@ -457,7 +457,7 @@ RedQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
{
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 @@ RedQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
{
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 @@ RedQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
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 ());