1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2017 Universita' degli Studi di Napoli Federico II
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * Author: Stefano Avallone <stefano.avallone@.unina.it>
19  */
20 
21 #include "ns3/abort.h"
22 #include "ns3/queue-limits.h"
23 #include "ns3/net-device-queue-interface.h"
24 #include "ns3/simulator.h"
25 #include "ns3/uinteger.h"
26 #include "ns3/queue-item.h"
27 
28 namespace ns3 {
29 
30 NS_LOG_COMPONENT_DEFINE ("NetDeviceQueueInterface");
31 
32 TypeId
GetTypeId(void)33 NetDeviceQueue::GetTypeId (void)
34 {
35   static TypeId tid = TypeId ("ns3::NetDeviceQueue")
36     .SetParent<Object> ()
37     .SetGroupName("Network")
38     .AddConstructor<NetDeviceQueue> ()
39   ;
40   return tid;
41 }
42 
NetDeviceQueue()43 NetDeviceQueue::NetDeviceQueue ()
44   : m_stoppedByDevice (false),
45     m_stoppedByQueueLimits (false),
46     NS_LOG_TEMPLATE_DEFINE ("NetDeviceQueueInterface")
47 {
48   NS_LOG_FUNCTION (this);
49 }
50 
~NetDeviceQueue()51 NetDeviceQueue::~NetDeviceQueue ()
52 {
53   NS_LOG_FUNCTION (this);
54 
55   m_queueLimits = 0;
56   m_wakeCallback.Nullify ();
57   m_device = 0;
58 }
59 
60 bool
IsStopped(void) const61 NetDeviceQueue::IsStopped (void) const
62 {
63   NS_LOG_FUNCTION (this);
64   return m_stoppedByDevice || m_stoppedByQueueLimits;
65 }
66 
67 void
Start(void)68 NetDeviceQueue::Start (void)
69 {
70   NS_LOG_FUNCTION (this);
71   m_stoppedByDevice = false;
72 }
73 
74 void
Stop(void)75 NetDeviceQueue::Stop (void)
76 {
77   NS_LOG_FUNCTION (this);
78   m_stoppedByDevice = true;
79 }
80 
81 void
Wake(void)82 NetDeviceQueue::Wake (void)
83 {
84   NS_LOG_FUNCTION (this);
85 
86   bool wasStoppedByDevice = m_stoppedByDevice;
87   m_stoppedByDevice = false;
88 
89   // Request the queue disc to dequeue a packet
90   if (wasStoppedByDevice && !m_wakeCallback.IsNull ())
91     {
92       Simulator::ScheduleNow (&NetDeviceQueue::m_wakeCallback, this);
93     }
94 }
95 
96 void
NotifyAggregatedObject(Ptr<NetDeviceQueueInterface> ndqi)97 NetDeviceQueue::NotifyAggregatedObject (Ptr<NetDeviceQueueInterface> ndqi)
98 {
99   NS_LOG_FUNCTION (this << ndqi);
100 
101   m_device = ndqi->GetObject<NetDevice> ();
102   NS_ABORT_MSG_IF (!m_device, "No NetDevice object was aggregated to the NetDeviceQueueInterface");
103 }
104 
105 void
SetWakeCallback(WakeCallback cb)106 NetDeviceQueue::SetWakeCallback (WakeCallback cb)
107 {
108   m_wakeCallback = cb;
109 }
110 
111 void
NotifyQueuedBytes(uint32_t bytes)112 NetDeviceQueue::NotifyQueuedBytes (uint32_t bytes)
113 {
114   NS_LOG_FUNCTION (this << bytes);
115   if (!m_queueLimits)
116     {
117       return;
118     }
119   m_queueLimits->Queued (bytes);
120   if (m_queueLimits->Available () >= 0)
121     {
122       return;
123     }
124   m_stoppedByQueueLimits = true;
125 }
126 
127 void
NotifyTransmittedBytes(uint32_t bytes)128 NetDeviceQueue::NotifyTransmittedBytes (uint32_t bytes)
129 {
130   NS_LOG_FUNCTION (this << bytes);
131   if ((!m_queueLimits) || (!bytes))
132     {
133       return;
134     }
135   m_queueLimits->Completed (bytes);
136   if (m_queueLimits->Available () < 0)
137     {
138       return;
139     }
140   bool wasStoppedByQueueLimits = m_stoppedByQueueLimits;
141   m_stoppedByQueueLimits = false;
142   // Request the queue disc to dequeue a packet
143   if (wasStoppedByQueueLimits && !m_wakeCallback.IsNull ())
144     {
145       Simulator::ScheduleNow (&NetDeviceQueue::m_wakeCallback, this);
146     }
147 }
148 
149 void
ResetQueueLimits()150 NetDeviceQueue::ResetQueueLimits ()
151 {
152   NS_LOG_FUNCTION (this);
153   if (!m_queueLimits)
154     {
155       return;
156     }
157   m_queueLimits->Reset ();
158 }
159 
160 void
SetQueueLimits(Ptr<QueueLimits> ql)161 NetDeviceQueue::SetQueueLimits (Ptr<QueueLimits> ql)
162 {
163   NS_LOG_FUNCTION (this << ql);
164   m_queueLimits = ql;
165 }
166 
167 Ptr<QueueLimits>
GetQueueLimits()168 NetDeviceQueue::GetQueueLimits ()
169 {
170   NS_LOG_FUNCTION (this);
171   return m_queueLimits;
172 }
173 
174 
175 NS_OBJECT_ENSURE_REGISTERED (NetDeviceQueueInterface);
176 
177 TypeId
GetTypeId(void)178 NetDeviceQueueInterface::GetTypeId (void)
179 {
180   static TypeId tid = TypeId ("ns3::NetDeviceQueueInterface")
181     .SetParent<Object> ()
182     .SetGroupName("Network")
183     .AddConstructor<NetDeviceQueueInterface> ()
184     .AddAttribute ("TxQueuesType",
185                    "The type of transmission queues to be used",
186                    TypeId::ATTR_CONSTRUCT,
187                    TypeIdValue (NetDeviceQueue::GetTypeId ()),
188                    MakeTypeIdAccessor (&NetDeviceQueueInterface::SetTxQueuesType),
189                    MakeTypeIdChecker ())
190     .AddAttribute ("NTxQueues", "The number of device transmission queues",
191                    TypeId::ATTR_GET | TypeId::ATTR_CONSTRUCT,
192                    UintegerValue (1),
193                    MakeUintegerAccessor (&NetDeviceQueueInterface::SetNTxQueues,
194                                          &NetDeviceQueueInterface::GetNTxQueues),
195                    MakeUintegerChecker<uint16_t> (1, 65535))
196   ;
197   return tid;
198 }
199 
NetDeviceQueueInterface()200 NetDeviceQueueInterface::NetDeviceQueueInterface ()
201 {
202   NS_LOG_FUNCTION (this);
203 
204   // the default select queue callback returns 0
205   m_selectQueueCallback = [] (Ptr<QueueItem> item) { return 0; };
206 }
207 
~NetDeviceQueueInterface()208 NetDeviceQueueInterface::~NetDeviceQueueInterface ()
209 {
210   NS_LOG_FUNCTION (this);
211 }
212 
213 Ptr<NetDeviceQueue>
GetTxQueue(std::size_t i) const214 NetDeviceQueueInterface::GetTxQueue (std::size_t i) const
215 {
216   NS_ASSERT (i < m_txQueuesVector.size ());
217   return m_txQueuesVector[i];
218 }
219 
220 std::size_t
GetNTxQueues(void) const221 NetDeviceQueueInterface::GetNTxQueues (void) const
222 {
223   return m_txQueuesVector.size ();
224 }
225 
226 void
DoDispose(void)227 NetDeviceQueueInterface::DoDispose (void)
228 {
229   NS_LOG_FUNCTION (this);
230 
231   m_txQueuesVector.clear ();
232   Object::DoDispose ();
233 }
234 
235 void
NotifyNewAggregate(void)236 NetDeviceQueueInterface::NotifyNewAggregate (void)
237 {
238   NS_LOG_FUNCTION (this);
239 
240   // Notify the NetDeviceQueue objects that an object was aggregated
241   for (auto& tx : m_txQueuesVector)
242     {
243       tx->NotifyAggregatedObject (this);
244     }
245   Object::NotifyNewAggregate ();
246 }
247 
248 void
SetTxQueuesType(TypeId type)249 NetDeviceQueueInterface::SetTxQueuesType (TypeId type)
250 {
251   NS_LOG_FUNCTION (this << type);
252 
253   NS_ABORT_MSG_IF (!m_txQueuesVector.empty (), "Cannot call SetTxQueuesType after creating device queues");
254 
255   m_txQueues = ObjectFactory ();
256   m_txQueues.SetTypeId (type);
257 }
258 
259 void
SetNTxQueues(std::size_t numTxQueues)260 NetDeviceQueueInterface::SetNTxQueues (std::size_t numTxQueues)
261 {
262   NS_LOG_FUNCTION (this << numTxQueues);
263   NS_ASSERT (numTxQueues > 0);
264 
265   NS_ABORT_MSG_IF (!m_txQueuesVector.empty (), "Cannot call SetNTxQueues after creating device queues");
266 
267   // create the netdevice queues
268   for (std::size_t i = 0; i < numTxQueues; i++)
269     {
270       m_txQueuesVector.push_back (m_txQueues.Create ()->GetObject<NetDeviceQueue> ());
271     }
272 }
273 
274 void
SetSelectQueueCallback(SelectQueueCallback cb)275 NetDeviceQueueInterface::SetSelectQueueCallback (SelectQueueCallback cb)
276 {
277   m_selectQueueCallback = cb;
278 }
279 
280 NetDeviceQueueInterface::SelectQueueCallback
GetSelectQueueCallback(void) const281 NetDeviceQueueInterface::GetSelectQueueCallback (void) const
282 {
283   return m_selectQueueCallback;
284 }
285 
286 } // namespace ns3
287