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