A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
26
27#include "ns3/simulator.h"
28
29#include <functional>
30#include <optional>
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
99{
100 return GetIt(mpdu)->mpdu;
101}
102
105{
106 if (!mpdu->IsQueued())
107 {
108 return nullptr;
109 }
110 if (auto aliasIt = GetIt(mpdu)->inflights.find(linkId);
111 aliasIt != GetIt(mpdu)->inflights.cend())
112 {
113 return aliasIt->second;
114 }
115 return nullptr;
116}
117
118void
120{
121 NS_LOG_FUNCTION(this);
122
123 std::list<Ptr<WifiMpdu>> mpdus;
124 auto [first, last] = GetContainer().ExtractExpiredMpdus(queueId);
125
126 for (auto it = first; it != last; it++)
127 {
128 mpdus.push_back(it->mpdu);
129 }
130 for (const auto& mpdu : mpdus)
131 {
132 // fire the Expired trace
134 }
135 // notify the scheduler
136 if (!mpdus.empty())
137 {
138 m_scheduler->NotifyRemove(m_ac, mpdus);
139 }
140}
141
142void
144{
145 NS_LOG_FUNCTION(this);
146
147 std::list<Ptr<WifiMpdu>> mpdus;
148 auto [first, last] = GetContainer().ExtractAllExpiredMpdus();
149
150 for (auto it = first; it != last; it++)
151 {
152 mpdus.push_back(it->mpdu);
153 }
154 for (const auto& mpdu : mpdus)
155 {
156 // fire the Expired trace
158 }
159 // notify the scheduler
160 if (!mpdus.empty())
161 {
162 m_scheduler->NotifyRemove(m_ac, mpdus);
163 }
164}
165
166void
168{
169 NS_LOG_FUNCTION(this);
170
172
173 auto [first, last] = GetContainer().GetAllExpiredMpdus();
174
175 for (auto it = first; it != last;)
176 {
177 // the scheduler has been notified and the Expired trace has been fired
178 // when the MPDU was extracted from its queue. The only thing left to do
179 // is to update the Queue base class statistics by calling Queue::DoRemove
180 auto curr = it++;
182 }
183}
184
185bool
187{
188 NS_ASSERT(item && item->IsQueued());
189 auto it = GetIt(item);
190 if (now > it->expiryTime)
191 {
192 NS_LOG_DEBUG("Removing packet that stayed in the queue for too long (queuing time="
193 << now - it->expiryTime + m_maxDelay << ")");
195 return true;
196 }
197 return false;
198}
199
200void
202{
203 NS_LOG_FUNCTION(this << scheduler);
204 m_scheduler = scheduler;
205}
206
207void
209{
210 NS_LOG_FUNCTION(this << delay);
211 m_maxDelay = delay;
212}
213
214Time
216{
217 return m_maxDelay;
218}
219
220bool
222{
223 NS_LOG_FUNCTION(this << *item);
224
225 auto queueId = WifiMacQueueContainer::GetQueueId(item);
226 return Insert(GetContainer().GetQueue(queueId).cend(), item);
227}
228
229bool
230WifiMacQueue::Insert(ConstIterator pos, Ptr<WifiMpdu> item)
231{
232 NS_LOG_FUNCTION(this << *item);
234 "WifiMacQueues must be in packet mode");
235
236 // insert the item if the queue is not full
237 if (QueueBase::GetNPackets() < GetMaxSize().GetValue())
238 {
239 return DoEnqueue(pos, item);
240 }
241
242 // the queue is full; try to make some room by removing stale packets
243 auto queueId = WifiMacQueueContainer::GetQueueId(item);
244
245 if (pos != GetContainer().GetQueue(queueId).cend())
246 {
248 "pos must point to an element in the same container queue as item");
249 if (pos->expiryTime <= Simulator::Now())
250 {
251 // the element pointed to by pos is stale and will be removed along with all of
252 // its predecessors; the new item will be enqueued at the front of the queue
253 pos = GetContainer().GetQueue(queueId).cbegin();
254 }
255 }
256
258
259 return DoEnqueue(pos, item);
260}
261
264{
265 // An MPDU is dequeued when either is acknowledged or is dropped, hence a Dequeue
266 // method without an argument makes no sense.
267 NS_ABORT_MSG("Not implemented by WifiMacQueue");
268 return nullptr;
269}
270
271void
273{
274 NS_LOG_FUNCTION(this);
275
276 std::list<ConstIterator> iterators;
277
278 for (const auto& mpdu : mpdus)
279 {
280 if (mpdu->IsQueued())
281 {
282 auto it = GetIt(mpdu);
283 NS_ASSERT(it->ac == m_ac);
284 NS_ASSERT(it->mpdu == mpdu->GetOriginal());
285 iterators.emplace_back(it);
286 }
287 }
288
289 DoDequeue(iterators);
290}
291
294{
295 // Need to specify the link ID
296 NS_ABORT_MSG("Not implemented by WifiMacQueue");
297 return nullptr;
298}
299
301WifiMacQueue::Peek(uint8_t linkId) const
302{
303 NS_LOG_FUNCTION(this);
304
305 auto queueId = m_scheduler->GetNext(m_ac, linkId);
306
307 if (!queueId.has_value())
308 {
309 NS_LOG_DEBUG("The queue is empty");
310 return nullptr;
311 }
312
313 return GetContainer().GetQueue(queueId.value()).cbegin()->mpdu;
314}
315
318{
319 NS_LOG_FUNCTION(this << +tid << dest << item);
320 NS_ABORT_IF(dest.IsGroup());
322 return PeekByQueueId(queueId, item);
323}
324
327{
328 NS_LOG_FUNCTION(this << item);
329 NS_ASSERT(!item || (item->IsQueued() && WifiMacQueueContainer::GetQueueId(item) == queueId));
330
331 // Remove MPDUs with expired lifetime if we are looking for the first MPDU in the queue
332 if (!item)
333 {
334 ExtractExpiredMpdus(queueId);
335 }
336
337 ConstIterator it = (item ? std::next(GetIt(item)) : GetContainer().GetQueue(queueId).cbegin());
338
339 if (it == GetContainer().GetQueue(queueId).cend())
340 {
341 NS_LOG_DEBUG("The queue is empty");
342 return nullptr;
343 }
344
345 return it->mpdu;
346}
347
350{
351 NS_LOG_FUNCTION(this << +linkId << item);
352 NS_ASSERT(!item || item->IsQueued());
353
354 if (item)
355 {
356 // check if there are other MPDUs in the same container queue as item
357 auto mpdu = PeekByQueueId(WifiMacQueueContainer::GetQueueId(item), item);
358
359 if (mpdu)
360 {
361 return mpdu;
362 }
363 }
364
365 std::optional<WifiContainerQueueId> queueId;
366
367 if (item)
368 {
369 queueId = m_scheduler->GetNext(m_ac, linkId, WifiMacQueueContainer::GetQueueId(item));
370 }
371 else
372 {
373 queueId = m_scheduler->GetNext(m_ac, linkId);
374 }
375
376 if (!queueId.has_value())
377 {
378 NS_LOG_DEBUG("The queue is empty");
379 return nullptr;
380 }
381
382 return GetContainer().GetQueue(queueId.value()).cbegin()->mpdu;
383}
384
387{
388 return Remove(Peek(0));
389}
390
393{
394 NS_LOG_FUNCTION(this << mpdu);
395 NS_ASSERT(mpdu && mpdu->IsQueued());
396 auto it = GetIt(mpdu);
397 NS_ASSERT(it->ac == m_ac);
398 NS_ASSERT(it->mpdu == mpdu->GetOriginal());
399
400 return DoRemove(it);
401}
402
403void
405{
406 NS_LOG_FUNCTION(this << *currentItem << *newItem);
407 NS_ASSERT(currentItem->IsQueued());
408 auto currentIt = GetIt(currentItem);
409 NS_ASSERT(currentIt->ac == m_ac);
410 NS_ASSERT(currentIt->mpdu == currentItem->GetOriginal());
411 NS_ASSERT(!newItem->IsQueued());
412
413 Time expiryTime = currentIt->expiryTime;
414 auto pos = std::next(currentIt);
415 DoDequeue({currentIt});
416 bool ret = Insert(pos, newItem);
417 GetIt(newItem)->expiryTime = expiryTime;
418 // The size of a WifiMacQueue is measured as number of packets. We dequeued
419 // one packet, so there is certainly room for inserting one packet
420 NS_ABORT_IF(!ret);
421}
422
425{
426 return GetContainer().GetQueue(queueId).size();
427}
428
431{
432 return GetContainer().GetNBytes(queueId);
433}
434
435bool
437{
438 NS_LOG_FUNCTION(this << *item);
439
440 auto currSize = GetMaxSize();
441 // control frames should not consume room in the MAC queue, so increase queue size
442 // if we are trying to enqueue a control frame
443 if (item->GetHeader().IsCtl())
444 {
445 SetMaxSize(currSize + item);
446 }
447 auto mpdu = m_scheduler->HasToDropBeforeEnqueue(m_ac, item);
448
449 if (mpdu == item)
450 {
451 // the given item must be dropped
452 SetMaxSize(currSize);
453 return false;
454 }
455
456 auto queueId = WifiMacQueueContainer::GetQueueId(item);
457 if (pos != GetContainer().GetQueue(queueId).cend() && mpdu && pos->mpdu == mpdu->GetOriginal())
458 {
459 // the element pointed to by pos must be dropped; update insert position
460 pos = std::next(pos);
461 }
462 if (mpdu)
463 {
464 DoRemove(GetIt(mpdu));
465 }
466
467 Iterator ret;
469 {
470 // set item's information about its position in the queue
471 item->SetQueueIt(ret, {});
472 ret->ac = m_ac;
473 ret->expiryTime = item->GetHeader().IsCtl() ? Time::Max() : Simulator::Now() + m_maxDelay;
474 WmqIteratorTag tag;
475 ret->deleter = [tag](auto mpdu) { mpdu->SetQueueIt(std::nullopt, tag); };
476
477 m_scheduler->NotifyEnqueue(m_ac, item);
478 return true;
479 }
480 SetMaxSize(currSize);
481 return false;
482}
483
484void
485WifiMacQueue::DoDequeue(const std::list<ConstIterator>& iterators)
486{
487 NS_LOG_FUNCTION(this);
488
489 std::list<Ptr<WifiMpdu>> items;
490
491 // First, dequeue all the items
492 for (auto& it : iterators)
493 {
495 {
496 items.push_back(item);
497 if (item->GetHeader().IsCtl())
498 {
499 SetMaxSize(GetMaxSize() - item);
500 }
501 }
502 }
503
504 // Then, notify the scheduler
505 if (!items.empty())
506 {
507 m_scheduler->NotifyDequeue(m_ac, items);
508 }
509}
510
512WifiMacQueue::DoRemove(ConstIterator pos)
513{
514 NS_LOG_FUNCTION(this);
515
517
518 if (item)
519 {
520 if (item->GetHeader().IsCtl())
521 {
522 SetMaxSize(GetMaxSize() - item);
523 }
524 m_scheduler->NotifyRemove(m_ac, {item});
525 }
526
527 return item;
528}
529
530} // 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
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
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:606
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
static Time Max()
Maximum representable Time Not to be confused with Max(Time,Time).
Definition: nstime.h:296
AttributeValue implementation for Time.
Definition: nstime.h:1423
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:936
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 non-inflight MPDUs with expired lifetime in all the container queues to the container queue ...
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 non-inflight MPDUs with expired lifetime in the container queue identified by the given Queu...
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 > GetAlias(Ptr< const WifiMpdu > mpdu, uint8_t linkId)
Ptr< WifiMpdu > DoRemove(ConstIterator pos)
Wrapper for the DoRemove method provided by the base class that additionally resets the iterator fiel...
Ptr< WifiMpdu > GetOriginal(Ptr< WifiMpdu > mpdu)
Unlike the GetOriginal() method of WifiMpdu, this method returns a non-const pointer to the original ...
WifiMacQueue(AcIndex ac=AC_UNDEF)
Constructor.
Ptr< WifiMpdu > PeekFirstAvailable(uint8_t linkId, Ptr< const WifiMpdu > item=nullptr) const
Return first available packet for transmission on the given link.
void DequeueIfQueued(const std::list< Ptr< const WifiMpdu > > &mpdus)
Dequeue the given MPDUs if they are stored in this queue.
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:48
#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 AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1444
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1424
#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:116
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
@ 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:1348
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:72
Definition: first.py:1
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::tuple< WifiContainerQueueType, WifiReceiverAddressType, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.