A Discrete-Event Network Simulator
API
wifi-mac-queue.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2005, 2009 INRIA
3 * Copyright (c) 2009 MIRKO BANCHI
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 * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19 * Mirko Banchi <mk.banchi@gmail.com>
20 * Stefano Avallone <stavallo@unina.it>
21 */
22
23#include "wifi-mac-queue.h"
24
27
28#include "ns3/simulator.h"
29
30#include <functional>
31
32namespace ns3
33{
34
35NS_LOG_COMPONENT_DEFINE("WifiMacQueue");
36
37NS_OBJECT_ENSURE_REGISTERED(WifiMacQueue);
38NS_OBJECT_TEMPLATE_CLASS_TWO_DEFINE(Queue, WifiMpdu, WifiMacQueueContainer);
39
40TypeId
42{
43 static TypeId tid =
44 TypeId("ns3::WifiMacQueue")
46 .SetGroupName("Wifi")
47 .AddConstructor<WifiMacQueue>()
48 .AddAttribute("MaxSize",
49 "The max queue size",
51 MakeQueueSizeAccessor(&QueueBase::SetMaxSize, &QueueBase::GetMaxSize),
52 MakeQueueSizeChecker())
53 .AddAttribute("MaxDelay",
54 "If a packet stays longer than this delay in the queue, it is dropped.",
58 .AddTraceSource("Expired",
59 "MPDU dropped because its lifetime expired.",
61 "ns3::WifiMpdu::TracedCallback");
62 return tid;
63}
64
66 : m_ac(ac),
67 NS_LOG_TEMPLATE_DEFINE("WifiMacQueue")
68{
69}
70
72{
74}
75
76void
78{
79 NS_LOG_FUNCTION(this);
80 m_scheduler = nullptr;
82}
83
86{
87 return m_ac;
88}
89
92{
93 NS_ASSERT(mpdu->IsQueued());
94 return mpdu->GetQueueIt(WmqIteratorTag());
95}
96
97void
99{
100 NS_LOG_FUNCTION(this);
101
102 std::list<Ptr<WifiMpdu>> mpdus;
103 auto [first, last] = GetContainer().ExtractExpiredMpdus(queueId);
104
105 for (auto it = first; it != last; it++)
106 {
107 mpdus.push_back(it->mpdu);
108 // fire the Expired trace
109 m_traceExpired(it->mpdu);
110 }
111 // notify the scheduler
112 m_scheduler->NotifyRemove(m_ac, mpdus);
113}
114
115void
117{
118 NS_LOG_FUNCTION(this);
119
120 std::list<Ptr<WifiMpdu>> mpdus;
121 auto [first, last] = GetContainer().ExtractAllExpiredMpdus();
122
123 for (auto it = first; it != last; it++)
124 {
125 mpdus.push_back(it->mpdu);
126 // fire the Expired trace
127 m_traceExpired(it->mpdu);
128 }
129 // notify the scheduler
130 m_scheduler->NotifyRemove(m_ac, mpdus);
131}
132
133void
135{
136 NS_LOG_FUNCTION(this);
137
139
140 auto [first, last] = GetContainer().GetAllExpiredMpdus();
141
142 for (auto it = first; it != last;)
143 {
144 // the scheduler has been notified and the Expired trace has been fired
145 // when the MPDU was extracted from its queue. The only thing left to do
146 // is to update the Queue base class statistics by calling Queue::DoRemove
147 auto curr = it++;
149 }
150}
151
152bool
154{
155 NS_ASSERT(item && item->IsQueued());
156 auto it = GetIt(item);
157 if (now > it->expiryTime)
158 {
159 NS_LOG_DEBUG("Removing packet that stayed in the queue for too long (queuing time="
160 << now - it->expiryTime + m_maxDelay << ")");
162 return true;
163 }
164 return false;
165}
166
167void
169{
170 NS_LOG_FUNCTION(this << scheduler);
171 m_scheduler = scheduler;
172}
173
174void
176{
177 NS_LOG_FUNCTION(this << delay);
178 m_maxDelay = delay;
179}
180
181Time
183{
184 return m_maxDelay;
185}
186
187bool
189{
190 NS_LOG_FUNCTION(this << *item);
191
192 auto queueId = WifiMacQueueContainer::GetQueueId(item);
193 return Insert(GetContainer().GetQueue(queueId).cend(), item);
194}
195
196bool
197WifiMacQueue::Insert(ConstIterator pos, Ptr<WifiMpdu> item)
198{
199 NS_LOG_FUNCTION(this << *item);
201 "WifiMacQueues must be in packet mode");
202
203 // insert the item if the queue is not full
204 if (QueueBase::GetNPackets() < GetMaxSize().GetValue())
205 {
206 return DoEnqueue(pos, item);
207 }
208
209 // the queue is full; try to make some room by removing stale packets
210 auto queueId = WifiMacQueueContainer::GetQueueId(item);
211
212 if (pos != GetContainer().GetQueue(queueId).cend())
213 {
215 "pos must point to an element in the same container queue as item");
216 if (pos->expiryTime <= Simulator::Now())
217 {
218 // the element pointed to by pos is stale and will be removed along with all of
219 // its predecessors; the new item will be enqueued at the front of the queue
220 pos = GetContainer().GetQueue(queueId).cbegin();
221 }
222 }
223
225
226 return DoEnqueue(pos, item);
227}
228
231{
232 // An MPDU is dequeued when either is acknowledged or is dropped, hence a Dequeue
233 // method without an argument makes no sense.
234 NS_ABORT_MSG("Not implemented by WifiMacQueue");
235 return nullptr;
236}
237
238void
240{
241 NS_LOG_FUNCTION(this);
242
243 std::list<ConstIterator> iterators;
244
245 for (const auto& mpdu : mpdus)
246 {
247 if (mpdu->IsQueued())
248 {
249 auto it = GetIt(mpdu);
250 NS_ASSERT(it->ac == m_ac);
251 NS_ASSERT(it->mpdu == mpdu);
252 iterators.emplace_back(it);
253 }
254 }
255
256 DoDequeue(iterators);
257}
258
261{
262 // Need to specify the link ID
263 NS_ABORT_MSG("Not implemented by WifiMacQueue");
264 return nullptr;
265}
266
268WifiMacQueue::Peek(uint8_t linkId) const
269{
270 NS_LOG_FUNCTION(this);
271
272 auto queueId = m_scheduler->GetNext(m_ac, linkId);
273
274 if (!queueId.has_value())
275 {
276 NS_LOG_DEBUG("The queue is empty");
277 return nullptr;
278 }
279
280 return GetContainer().GetQueue(queueId.value()).cbegin()->mpdu;
281}
282
285{
286 NS_LOG_FUNCTION(this << +tid << dest << item);
287 NS_ABORT_IF(dest.IsGroup());
289 return PeekByQueueId(queueId, item);
290}
291
294{
295 NS_LOG_FUNCTION(this << item);
296 NS_ASSERT(!item || (item->IsQueued() && WifiMacQueueContainer::GetQueueId(item) == queueId));
297
298 // Remove MPDUs with expired lifetime if we are looking for the first MPDU in the queue
299 if (!item)
300 {
301 ExtractExpiredMpdus(queueId);
302 }
303
304 ConstIterator it = (item ? std::next(GetIt(item)) : GetContainer().GetQueue(queueId).cbegin());
305
306 if (it == GetContainer().GetQueue(queueId).cend())
307 {
308 NS_LOG_DEBUG("The queue is empty");
309 return nullptr;
310 }
311
312 return it->mpdu;
313}
314
317 const Ptr<QosBlockedDestinations> blockedPackets,
318 Ptr<const WifiMpdu> item) const
319{
320 NS_LOG_FUNCTION(this << +linkId << item);
321 NS_ASSERT(!item || item->IsQueued());
322
323 if (item)
324 {
325 NS_ASSERT(!item->GetHeader().IsQosData() || !blockedPackets ||
326 !blockedPackets->IsBlocked(item->GetHeader().GetAddr1(),
327 item->GetHeader().GetQosTid()));
328 // check if there are other MPDUs in the same container queue as item
329 auto mpdu = PeekByQueueId(WifiMacQueueContainer::GetQueueId(item), item);
330
331 if (mpdu)
332 {
333 return mpdu;
334 }
335 }
336
337 std::optional<WifiContainerQueueId> queueId;
338
339 if (item)
340 {
341 queueId = m_scheduler->GetNext(m_ac, linkId, WifiMacQueueContainer::GetQueueId(item));
342 }
343 else
344 {
345 queueId = m_scheduler->GetNext(m_ac, linkId);
346 }
347
348 while (queueId.has_value() && blockedPackets &&
349 std::get<0>(queueId.value()) == WIFI_QOSDATA_UNICAST_QUEUE &&
350 blockedPackets->IsBlocked(std::get<1>(queueId.value()), std::get<2>(queueId.value())))
351 {
352 queueId = m_scheduler->GetNext(m_ac, linkId, queueId.value());
353 }
354
355 if (!queueId.has_value())
356 {
357 NS_LOG_DEBUG("The queue is empty");
358 return nullptr;
359 }
360
361 return GetContainer().GetQueue(queueId.value()).cbegin()->mpdu;
362}
363
366{
367 return Remove(Peek(0));
368}
369
372{
373 NS_LOG_FUNCTION(this << mpdu);
374 NS_ASSERT(mpdu && mpdu->IsQueued());
375 auto it = GetIt(mpdu);
376 NS_ASSERT(it->ac == m_ac);
377 NS_ASSERT(it->mpdu == mpdu);
378
379 return DoRemove(it);
380}
381
382void
384{
385 NS_LOG_FUNCTION(this << *currentItem << *newItem);
386 NS_ASSERT(currentItem->IsQueued());
387 auto currentIt = GetIt(currentItem);
388 NS_ASSERT(currentIt->ac == m_ac);
389 NS_ASSERT(currentIt->mpdu == currentItem);
390 NS_ASSERT(!newItem->IsQueued());
391
392 Time expiryTime = currentIt->expiryTime;
393 auto pos = std::next(currentIt);
394 DoDequeue({currentIt});
395 bool ret = Insert(pos, newItem);
396 GetIt(newItem)->expiryTime = expiryTime;
397 // The size of a WifiMacQueue is measured as number of packets. We dequeued
398 // one packet, so there is certainly room for inserting one packet
399 NS_ABORT_IF(!ret);
400}
401
404{
405 return GetContainer().GetQueue(queueId).size();
406}
407
410{
411 return GetContainer().GetNBytes(queueId);
412}
413
414bool
416{
417 NS_LOG_FUNCTION(this << *item);
418
419 auto mpdu = m_scheduler->HasToDropBeforeEnqueue(m_ac, item);
420
421 if (mpdu == item)
422 {
423 // the given item must be dropped
424 return false;
425 }
426
427 auto queueId = WifiMacQueueContainer::GetQueueId(item);
428 if (pos != GetContainer().GetQueue(queueId).cend() && pos->mpdu == mpdu)
429 {
430 // the element pointed to by pos must be dropped; update insert position
431 pos = std::next(pos);
432 }
433 if (mpdu != nullptr)
434 {
435 DoRemove(GetIt(mpdu));
436 }
437
438 Iterator ret;
440 {
441 // set item's information about its position in the queue
442 item->SetQueueIt(ret, {});
443 ret->ac = m_ac;
444 ret->expiryTime = Simulator::Now() + m_maxDelay;
445 WmqIteratorTag tag;
446 ret->deleter = [tag](auto mpdu) { mpdu->SetQueueIt(std::nullopt, tag); };
447
448 m_scheduler->NotifyEnqueue(m_ac, item);
449 return true;
450 }
451 return false;
452}
453
454void
455WifiMacQueue::DoDequeue(const std::list<ConstIterator>& iterators)
456{
457 NS_LOG_FUNCTION(this);
458
459 std::list<Ptr<WifiMpdu>> items;
460
461 // First, dequeue all the items
462 for (auto& it : iterators)
463 {
465 {
466 items.push_back(item);
467 }
468 }
469
470 // Then, notify the scheduler
471 if (!items.empty())
472 {
473 m_scheduler->NotifyDequeue(m_ac, items);
474 }
475}
476
478WifiMacQueue::DoRemove(ConstIterator pos)
479{
480 NS_LOG_FUNCTION(this);
481
483
484 if (item)
485 {
486 m_scheduler->NotifyRemove(m_ac, {item});
487 }
488
489 return item;
490}
491
492} // namespace ns3
an EUI-48 address
Definition: mac48-address.h:46
bool IsGroup() const
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
Introspection did not find any typical Config paths.
QueueSize GetMaxSize() const
Definition: queue.cc:217
uint32_t GetNBytes() const
Definition: queue.cc:98
uint32_t GetNPackets() const
Definition: queue.cc:90
void SetMaxSize(QueueSize size)
Set the maximum size of this queue.
Definition: queue.cc:200
Template class for packet Queues.
Definition: queue.h:267
Ptr< Item > DoRemove(ConstIterator pos)
Pull the item to drop from the queue.
Definition: queue.h:575
void DoDispose() override
Destructor implementation.
Definition: queue.h:618
const ns3::WifiMacQueueContainer & GetContainer() const
Get a const reference to the container of queue items.
Definition: queue.h:503
Container::iterator Iterator
Iterator.
Definition: queue.h:320
Container::const_iterator ConstIterator
Const iterator.
Definition: queue.h:318
Class for representing queue sizes.
Definition: queue-size.h:96
AttributeValue implementation for QueueSize.
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
AttributeValue implementation for Time.
Definition: nstime.h:1425
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
const ContainerQueue & GetQueue(const WifiContainerQueueId &queueId) const
Get a const reference to the container queue identified by the given QueueId.
static WifiContainerQueueId GetQueueId(Ptr< const WifiMpdu > mpdu)
Return the QueueId identifying the container queue in which the given MPDU is (or is to be) enqueued.
uint32_t GetNBytes(const WifiContainerQueueId &queueId) const
Get the total size of the MPDUs stored in the queue identified by the given QueueId.
std::pair< iterator, iterator > ExtractAllExpiredMpdus() const
Transfer MPDUs with expired lifetime in all the container queues to the container queue storing MPDUs...
std::pair< iterator, iterator > GetAllExpiredMpdus() const
Get the range [first, last) of iterators pointing to all the MPDUs queued in the container queue stor...
std::pair< iterator, iterator > ExtractExpiredMpdus(const WifiContainerQueueId &queueId) const
Transfer MPDUs with expired lifetime in the container queue identified by the given QueueId to the co...
This queue implements the timeout procedure described in (Section 9.19.2.6 "Retransmit procedures" pa...
Time m_maxDelay
Time to live for packets in the queue.
void Replace(Ptr< const WifiMpdu > currentItem, Ptr< WifiMpdu > newItem)
Replace the given current item with the given new item.
Ptr< WifiMpdu > PeekByQueueId(const WifiContainerQueueId &queueId, Ptr< const WifiMpdu > item=nullptr) const
Search and return the first packet present in the container queue identified by the given queue ID.
Ptr< WifiMpdu > Remove() override
Remove the packet in the front of the queue.
Ptr< WifiMacQueueScheduler > m_scheduler
the MAC queue scheduler
AcIndex GetAc() const
Get the Access Category of the packets stored in this queue.
bool Insert(ConstIterator pos, Ptr< WifiMpdu > item)
Enqueue the given Wifi MAC queue item before the given position.
void ExtractExpiredMpdus(const WifiContainerQueueId &queueId) const
Move MPDUs with expired lifetime from the container queue identified by the given queue ID to the con...
bool Enqueue(Ptr< WifiMpdu > item) override
Enqueue the given Wifi MAC queue item at the end of the queue.
Ptr< const WifiMpdu > Peek() const override
Peek the packet in the front of the queue.
Iterator GetIt(Ptr< const WifiMpdu > mpdu) const
bool TtlExceeded(Ptr< const WifiMpdu > item, const Time &now)
Remove the given item if it has been in the queue for too long.
void WipeAllExpiredMpdus()
Remove all MPDUs with expired lifetime from this WifiMacQueue object.
Ptr< WifiMpdu > Dequeue() override
Dequeue the packet in the front of the queue.
void SetScheduler(Ptr< WifiMacQueueScheduler > scheduler)
Set the wifi MAC queue scheduler.
void SetMaxDelay(Time delay)
Set the maximum delay before the packet is discarded.
void DoDispose() override
Destructor implementation.
~WifiMacQueue() override
Ptr< WifiMpdu > DoRemove(ConstIterator pos)
Wrapper for the DoRemove method provided by the base class that additionally resets the iterator fiel...
WifiMacQueue(AcIndex ac=AC_UNDEF)
Constructor.
void DequeueIfQueued(const std::list< Ptr< const WifiMpdu > > &mpdus)
Dequeue the given MPDUs if they are stored in this queue.
Ptr< WifiMpdu > PeekFirstAvailable(uint8_t linkId, const Ptr< QosBlockedDestinations > blockedPackets=nullptr, Ptr< const WifiMpdu > item=nullptr) const
Return first available packet for transmission on the given link.
TracedCallback< Ptr< const WifiMpdu > > m_traceExpired
Traced callback: fired when a packet is dropped due to lifetime expiration.
bool DoEnqueue(ConstIterator pos, Ptr< WifiMpdu > item)
Wrapper for the DoEnqueue method provided by the base class that additionally sets the iterator field...
AcIndex m_ac
the access category
Ptr< WifiMpdu > PeekByTidAndAddress(uint8_t tid, Mac48Address dest, Ptr< const WifiMpdu > item=nullptr) const
Search and return, if present in the queue, the first packet having the receiver address equal to des...
void DoDequeue(const std::list< ConstIterator > &iterators)
Wrapper for the DoDequeue method provided by the base class that additionally resets the iterator fie...
void ExtractAllExpiredMpdus() const
Move MPDUs with expired lifetime from all the container queues to the container queue storing MPDUs w...
static TypeId GetTypeId()
Get the type ID.
Time GetMaxDelay() const
Return the maximum delay before the packet is discarded.
Tag used to allow (only) WifiMacQueue to access the queue iterator stored by a WifiMpdu.
Definition: wifi-mpdu.h:45
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1426
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition: abort.h:76
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_TEMPLATE_DEFINE(name)
Initialize a reference to a Log component.
Definition: log.h:236
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_TEMPLATE_CLASS_TWO_DEFINE(type, param1, param2)
Explicitly instantiate a template class with two template parameters and register the resulting insta...
Definition: object-base.h:113
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
@ PACKETS
Use number of packets for queue size.
Definition: queue-size.h:45
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition: qos-utils.h:74
Definition: first.py:1
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::tuple< WifiContainerQueueType, Mac48Address, uint8_t > WifiContainerQueueId
Tuple (queue type, Address, TID) identifying a container queue.
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:535
@ WIFI_QOSDATA_UNICAST_QUEUE
#define list