diff --git a/src/traffic-control/helper/traffic-control-helper.cc b/src/traffic-control/helper/traffic-control-helper.cc index b1500f5ff..c09120f32 100644 --- a/src/traffic-control/helper/traffic-control-helper.cc +++ b/src/traffic-control/helper/traffic-control-helper.cc @@ -369,9 +369,7 @@ TrafficControlHelper::Install (Ptr d) // Create queue discs (from leaves to root) for (auto i = m_queueDiscFactory.size (); i-- > 0; ) { - Ptr q = m_queueDiscFactory[i].CreateQueueDisc (m_queueDiscs); - q->SetNetDevice (d); - m_queueDiscs[i] = q; + m_queueDiscs[i] = m_queueDiscFactory[i].CreateQueueDisc (m_queueDiscs); } // Set the root queue disc (if any has been created) on the device diff --git a/src/traffic-control/model/fq-codel-queue-disc.cc b/src/traffic-control/model/fq-codel-queue-disc.cc index 053caf1b9..3ea41b050 100644 --- a/src/traffic-control/model/fq-codel-queue-disc.cc +++ b/src/traffic-control/model/fq-codel-queue-disc.cc @@ -318,6 +318,27 @@ FqCoDelQueueDisc::CheckConfig (void) return false; } + // we are at initialization time. If the user has not set a quantum value, + // set the quantum to the MTU of the device (if any) + if (!m_quantum) + { + Ptr ndqi = GetNetDeviceQueueInterface (); + Ptr dev; + // if the NetDeviceQueueInterface object is aggregated to a + // NetDevice, get the MTU of such NetDevice + if (ndqi && (dev = ndqi->GetObject ())) + { + m_quantum = dev->GetMtu (); + NS_LOG_DEBUG ("Setting the quantum to the MTU of the device: " << m_quantum); + } + + if (!m_quantum) + { + NS_LOG_ERROR ("The quantum parameter cannot be null"); + return false; + } + } + return true; } @@ -326,16 +347,6 @@ FqCoDelQueueDisc::InitializeParams (void) { NS_LOG_FUNCTION (this); - // we are at initialization time. If the user has not set a quantum value, - // set the quantum to the MTU of the device - if (!m_quantum) - { - Ptr device = GetNetDevice (); - NS_ASSERT_MSG (device, "Device not set for the queue disc"); - m_quantum = device->GetMtu (); - NS_LOG_DEBUG ("Setting the quantum to the MTU of the device: " << m_quantum); - } - m_flowFactory.SetTypeId ("ns3::FqCoDelFlow"); m_queueDiscFactory.SetTypeId ("ns3::CoDelQueueDisc"); diff --git a/src/traffic-control/model/queue-disc.cc b/src/traffic-control/model/queue-disc.cc index 94ec1e1e3..6137e4d14 100644 --- a/src/traffic-control/model/queue-disc.cc +++ b/src/traffic-control/model/queue-disc.cc @@ -384,9 +384,13 @@ QueueDisc::DoDispose (void) m_queues.clear (); m_filters.clear (); m_classes.clear (); - m_device = 0; m_devQueueIface = 0; + m_send = nullptr; m_requeued = 0; + m_internalQueueDbeFunctor = nullptr; + m_internalQueueDadFunctor = nullptr; + m_childQueueDiscDbeFunctor = nullptr; + m_childQueueDiscDadFunctor = nullptr; Object::DoDispose (); } @@ -394,12 +398,6 @@ void QueueDisc::DoInitialize (void) { NS_LOG_FUNCTION (this); - // When adding a new interface, the traffic control aggregates - // a NetDeviceQueueInterface object to the netdevice - if (m_device) - { - m_devQueueIface = m_device->GetObject (); - } // Check the configuration and initialize the parameters of this queue disc bool ok = CheckConfig (); @@ -536,17 +534,31 @@ QueueDisc::GetCurrentSize (void) } void -QueueDisc::SetNetDevice (Ptr device) +QueueDisc::SetNetDeviceQueueInterface (Ptr ndqi) { - NS_LOG_FUNCTION (this << device); - m_device = device; + NS_LOG_FUNCTION (this << ndqi); + m_devQueueIface = ndqi; } -Ptr -QueueDisc::GetNetDevice (void) const +Ptr +QueueDisc::GetNetDeviceQueueInterface (void) const { NS_LOG_FUNCTION (this); - return m_device; + return m_devQueueIface; +} + +void +QueueDisc::SetSendCallback (SendCallback func) +{ + NS_LOG_FUNCTION (this); + m_send = func; +} + +QueueDisc::SendCallback +QueueDisc::GetSendCallback (void) const +{ + NS_LOG_FUNCTION (this); + return m_send; } void @@ -1073,7 +1085,8 @@ QueueDisc::Transmit (Ptr item) SocketPriorityTag priorityTag; item->GetPacket ()->RemovePacketTag (priorityTag); } - m_device->Send (item->GetPacket (), item->GetAddress (), item->GetProtocol ()); + NS_ASSERT_MSG (m_send, "Send callback not set"); + m_send (item); // the behavior here slightly diverges from Linux. In Linux, it is advised that // the function called when a packet needs to be transmitted (ndo_start_xmit) diff --git a/src/traffic-control/model/queue-disc.h b/src/traffic-control/model/queue-disc.h index 493803dbb..02e429559 100644 --- a/src/traffic-control/model/queue-disc.h +++ b/src/traffic-control/model/queue-disc.h @@ -339,16 +339,39 @@ public: const Stats& GetStats (void); /** - * \brief Set the NetDevice on which this queue discipline is installed. - * \param device the NetDevice on which this queue discipline is installed. + * \param ndqi the NetDeviceQueueInterface aggregated to the receiving object. + * + * Set the pointer to the NetDeviceQueueInterface object aggregated to the + * object receiving the packets dequeued from this queue disc. */ - void SetNetDevice (Ptr device); + void SetNetDeviceQueueInterface (Ptr ndqi); /** - * \brief Get the NetDevice on which this queue discipline is installed - * \return the NetDevice on which this queue discipline is installed. + * \return the NetDeviceQueueInterface aggregated to the receiving object. + * + * Get the pointer to the NetDeviceQueueInterface object aggregated to the + * object receiving the packets dequeued from this queue disc. */ - Ptr GetNetDevice (void) const; + Ptr GetNetDeviceQueueInterface (void) const; + + /// Callback invoked to send a packet to the receiving object when Run is called + typedef std::function)> SendCallback; + + /** + * \param func the callback to send a packet to the receiving object. + * + * Set the callback used by the Transmit method (called eventually by the Run + * method) to send a packet to the receiving object. + */ + void SetSendCallback (SendCallback func); + + /** + * \return the callback to send a packet to the receiving object. + * + * Get the callback used by the Transmit method (called eventually by the Run + * method) to send a packet to the receiving object. + */ + SendCallback GetSendCallback (void) const; /** * \brief Set the maximum number of dequeue operations following a packet enqueue @@ -671,8 +694,8 @@ private: Stats m_stats; //!< The collected statistics uint32_t m_quota; //!< Maximum number of packets dequeued in a qdisc run - Ptr m_device; //!< The NetDevice on which this queue discipline is installed Ptr m_devQueueIface; //!< NetDevice queue interface + SendCallback m_send; //!< Callback used to send a packet to the receiving object bool m_running; //!< The queue disc is performing multiple dequeue operations Ptr m_requeued; //!< The last packet that failed to be transmitted bool m_peeked; //!< A packet was dequeued because Peek was called diff --git a/src/traffic-control/model/tbf-queue-disc.cc b/src/traffic-control/model/tbf-queue-disc.cc index 00b397595..5ca156bf7 100644 --- a/src/traffic-control/model/tbf-queue-disc.cc +++ b/src/traffic-control/model/tbf-queue-disc.cc @@ -62,7 +62,7 @@ TypeId TbfQueueDisc::GetTypeId (void) MakeUintegerChecker ()) .AddAttribute ("Mtu", "Size of the second bucket in bytes. If null, it is initialized" - " to the MTU of the attached NetDevice (if any)", + " to the MTU of the receiving NetDevice (if any)", UintegerValue (0), MakeUintegerAccessor (&TbfQueueDisc::SetMtu), MakeUintegerChecker ()) @@ -310,9 +310,16 @@ TbfQueueDisc::CheckConfig (void) return false; } - if (m_mtu == 0 && GetNetDevice ()) + if (m_mtu == 0) { - m_mtu = GetNetDevice ()->GetMtu (); + Ptr ndqi = GetNetDeviceQueueInterface (); + Ptr dev; + // if the NetDeviceQueueInterface object is aggregated to a + // NetDevice, get the MTU of such NetDevice + if (ndqi && (dev = ndqi->GetObject ())) + { + m_mtu = dev->GetMtu (); + } } if (m_mtu == 0 && m_peakRate > DataRate ("0bps")) diff --git a/src/traffic-control/model/traffic-control-layer.cc b/src/traffic-control/model/traffic-control-layer.cc index 44fc3d9c0..e2f84271e 100644 --- a/src/traffic-control/model/traffic-control-layer.cc +++ b/src/traffic-control/model/traffic-control-layer.cc @@ -178,6 +178,15 @@ TrafficControlLayer::ScanDevices (void) { ndi->second.m_queueDiscsToWake.push_back (ndi->second.m_rootQueueDisc); } + + // set the NetDeviceQueueInterface object and the SendCallback on the queue discs + // into which packets are enqueued and dequeued by calling Run + for (auto& q : ndi->second.m_queueDiscsToWake) + { + q->SetNetDeviceQueueInterface (ndqi); + q->SetSendCallback ([dev] (Ptr item) + { dev->Send (item->GetPacket (), item->GetAddress (), item->GetProtocol ()); }); + } } } } @@ -237,6 +246,11 @@ TrafficControlLayer::DeleteRootQueueDiscOnDevice (Ptr device) // remove the root queue disc ndi->second.m_rootQueueDisc = 0; + for (auto& q : ndi->second.m_queueDiscsToWake) + { + q->SetNetDeviceQueueInterface (nullptr); + q->SetSendCallback (nullptr); + } ndi->second.m_queueDiscsToWake.clear (); Ptr ndqi = ndi->second.m_ndqi; diff --git a/src/traffic-control/test/tbf-queue-disc-test-suite.cc b/src/traffic-control/test/tbf-queue-disc-test-suite.cc index 64ac31ca7..03afcc834 100644 --- a/src/traffic-control/test/tbf-queue-disc-test-suite.cc +++ b/src/traffic-control/test/tbf-queue-disc-test-suite.cc @@ -287,7 +287,6 @@ TbfQueueDiscTestCase::RunTbfTest (QueueSizeUnit mode) Ptr tcA = CreateObject (); nodesA.Get (0)->AggregateObject (tcA); - queue->SetNetDevice (txDevA); tcA->SetRootQueueDiscOnDevice (txDevA, queue); tcA->Initialize (); @@ -361,7 +360,6 @@ TbfQueueDiscTestCase::RunTbfTest (QueueSizeUnit mode) Ptr tcB = CreateObject (); nodesB.Get (0)->AggregateObject (tcB); - queue->SetNetDevice (txDevB); tcB->SetRootQueueDiscOnDevice (txDevB, queue); tcB->Initialize ();