From 9e79ad7d4540d588bfb0798185074d15babe1cf2 Mon Sep 17 00:00:00 2001 From: Stefano Avallone Date: Tue, 8 Mar 2016 10:45:07 -0800 Subject: [PATCH] point-to-point: Add preliminary support for flow control The (unique) transmission queue is stopped when enqueuing a packet fails, so that upper layers do not send other packets down. When a packet transmission is completed, if the queue is empty then wake the upper layers. If the queue was stopped, there is now room for another packet and hence wake the upper layers as well. --- .../model/point-to-point-net-device.cc | 36 ++++++++++++++++--- .../model/point-to-point-net-device.h | 3 ++ .../test/point-to-point-test.cc | 5 +++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/point-to-point/model/point-to-point-net-device.cc b/src/point-to-point/model/point-to-point-net-device.cc index bfa31fff6..df7b747ad 100644 --- a/src/point-to-point/model/point-to-point-net-device.cc +++ b/src/point-to-point/model/point-to-point-net-device.cc @@ -206,6 +206,16 @@ PointToPointNetDevice::ProcessHeader (Ptr p, uint16_t& param) return true; } +void +PointToPointNetDevice::DoInitialize (void) +{ + NS_LOG_FUNCTION (this); + // A NetDeviceQueueInterface object must have been aggregated to this device + // by the traffic control layer + m_queueInterface = GetObject (); + NetDevice::DoInitialize (); +} + void PointToPointNetDevice::DoDispose () { @@ -280,18 +290,27 @@ PointToPointNetDevice::TransmitComplete (void) m_phyTxEndTrace (m_currentPkt); m_currentPkt = 0; + NS_ASSERT (m_queueInterface); + Ptr txq = m_queueInterface->GetTxQueue (0); + Ptr item = m_queue->Dequeue (); if (item == 0) { - // - // No packet was on the queue, so we just exit. - // + NS_LOG_LOGIC ("No pending packets in device queue after tx complete"); + txq->Wake (); return; } // - // Got another packet off of the queue, so start the transmit process agin. + // Got another packet off of the queue, so start the transmit process again. + // If the queue was stopped, start it again. Note that we cannot wake the upper + // layers because otherwise a packet is sent to the device while the machine + // state is busy, thus causing the assert in TransmitStart to fail. // + if (txq->IsStopped ()) + { + txq->Start (); + } Ptr p = item->GetPacket (); m_snifferTrace (p); m_promiscSnifferTrace (p); @@ -511,6 +530,11 @@ PointToPointNetDevice::Send ( const Address &dest, uint16_t protocolNumber) { + NS_ASSERT (m_queueInterface); + Ptr txq = m_queueInterface->GetTxQueue (0); + + NS_ASSERT_MSG (!txq->IsStopped (), "Send should not be called when the device is stopped"); + NS_LOG_FUNCTION (this << packet << dest << protocolNumber); NS_LOG_LOGIC ("p=" << packet << ", dest=" << &dest); NS_LOG_LOGIC ("UID is " << packet->GetUid ()); @@ -551,8 +575,10 @@ PointToPointNetDevice::Send ( return true; } - // Enqueue may fail (overflow) + // Enqueue may fail (overflow). Stop the tx queue, so that the upper layers + // do not send packets until there is room in the queue again. m_macTxDropTrace (packet); + txq->Stop (); return false; } diff --git a/src/point-to-point/model/point-to-point-net-device.h b/src/point-to-point/model/point-to-point-net-device.h index b43cb2f68..2ec402ce6 100644 --- a/src/point-to-point/model/point-to-point-net-device.h +++ b/src/point-to-point/model/point-to-point-net-device.h @@ -198,6 +198,8 @@ protected: */ void DoMpiReceive (Ptr p); + virtual void DoInitialize (void); + private: /** @@ -435,6 +437,7 @@ private: TracedCallback > m_promiscSnifferTrace; Ptr m_node; //!< Node owning this NetDevice + Ptr m_queueInterface; //!< NetDevice queue interface Mac48Address m_address; //!< Mac48Address of this NetDevice NetDevice::ReceiveCallback m_rxCallback; //!< Receive callback NetDevice::PromiscReceiveCallback m_promiscCallback; //!< Receive callback diff --git a/src/point-to-point/test/point-to-point-test.cc b/src/point-to-point/test/point-to-point-test.cc index 211e6584f..302549b4e 100644 --- a/src/point-to-point/test/point-to-point-test.cc +++ b/src/point-to-point/test/point-to-point-test.cc @@ -86,6 +86,11 @@ PointToPointTest::DoRun (void) a->AddDevice (devA); b->AddDevice (devB); + Ptr ifaceA = CreateObject (); + devA->AggregateObject (ifaceA); + Ptr ifaceB = CreateObject (); + devB->AggregateObject (ifaceB); + Simulator::Schedule (Seconds (1.0), &PointToPointTest::SendOnePacket, this, devA); Simulator::Run ();