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",
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
133 auto fire = [this, mpdu]() -> void { this->m_traceExpired(mpdu); };
135 }
136 // notify the scheduler
137 if (!mpdus.empty())
138 {
139 m_scheduler->NotifyRemove(m_ac, mpdus);
140 }
141}
142
143void
145{
146 NS_LOG_FUNCTION(this);
147
148 std::list<Ptr<WifiMpdu>> mpdus;
149 auto [first, last] = GetContainer().ExtractAllExpiredMpdus();
150
151 for (auto it = first; it != last; it++)
152 {
153 mpdus.push_back(it->mpdu);
154 }
155 for (const auto& mpdu : mpdus)
156 {
157 // fire the Expired trace
158 auto fire = [this, mpdu]() -> void { this->m_traceExpired(mpdu); };
160 }
161 // notify the scheduler
162 if (!mpdus.empty())
163 {
164 m_scheduler->NotifyRemove(m_ac, mpdus);
165 }
166}
167
168void
170{
171 NS_LOG_FUNCTION(this);
172
174
175 auto [first, last] = GetContainer().GetAllExpiredMpdus();
176
177 for (auto it = first; it != last;)
178 {
179 // the scheduler has been notified and the Expired trace has been fired
180 // when the MPDU was extracted from its queue. The only thing left to do
181 // is to update the Queue base class statistics by calling Queue::DoRemove
182 auto curr = it++;
184 }
185}
186
187bool
189{
190 NS_ASSERT(item && item->IsQueued());
191 auto it = GetIt(item);
192 if (now > it->expiryTime)
193 {
194 NS_LOG_DEBUG("Removing packet that stayed in the queue for too long (queuing time="
195 << now - it->expiryTime + m_maxDelay << ")");
196 // Trace the expired MPDU first and then remove it from the queue (if still in the queue).
197 // Indeed, the Expired traced source is connected to BlockAckManager::NotifyDiscardedMpdu,
198 // which checks if the expired MPDU is in-flight or is a retransmission to determine
199 // whether a BlockAckReq frame must be sent to advance the recipient window. If the
200 // expired MPDU is removed from the queue before tracing the expiration, it is no longer
201 // in-flight and NotifyDiscardedMpdu wrongfully assumes that a BlockAckReq is not needed.
202 m_traceExpired(item);
203 if (item->IsQueued())
204 {
205 DoRemove(it);
206 }
207 return true;
208 }
209 return false;
210}
211
212void
214{
215 NS_LOG_FUNCTION(this << scheduler);
216 m_scheduler = scheduler;
217}
218
219void
221{
222 NS_LOG_FUNCTION(this << delay);
223 m_maxDelay = delay;
224}
225
226Time
228{
229 return m_maxDelay;
230}
231
232bool
234{
235 NS_LOG_FUNCTION(this << *item);
236
237 auto queueId = WifiMacQueueContainer::GetQueueId(item);
238 return Insert(GetContainer().GetQueue(queueId).cend(), item);
239}
240
241bool
242WifiMacQueue::Insert(ConstIterator pos, Ptr<WifiMpdu> item)
243{
244 NS_LOG_FUNCTION(this << *item);
246 "WifiMacQueues must be in packet mode");
247
248 // insert the item if the queue is not full
249 if (QueueBase::GetNPackets() < GetMaxSize().GetValue())
250 {
251 return DoEnqueue(pos, item);
252 }
253
254 // the queue is full; try to make some room by removing stale packets
255 auto queueId = WifiMacQueueContainer::GetQueueId(item);
256
257 if (pos != GetContainer().GetQueue(queueId).cend())
258 {
260 "pos must point to an element in the same container queue as item");
261 if (pos->expiryTime <= Simulator::Now())
262 {
263 // the element pointed to by pos is stale and will be removed along with all of
264 // its predecessors; the new item will be enqueued at the front of the queue
265 pos = GetContainer().GetQueue(queueId).cbegin();
266 }
267 }
268
270
271 return DoEnqueue(pos, item);
272}
273
276{
277 // An MPDU is dequeued when either is acknowledged or is dropped, hence a Dequeue
278 // method without an argument makes no sense.
279 NS_ABORT_MSG("Not implemented by WifiMacQueue");
280 return nullptr;
281}
282
283void
285{
286 NS_LOG_FUNCTION(this);
287
288 std::list<ConstIterator> iterators;
289
290 for (const auto& mpdu : mpdus)
291 {
292 if (mpdu->IsQueued())
293 {
294 auto it = GetIt(mpdu);
295 NS_ASSERT(it->ac == m_ac);
296 NS_ASSERT(it->mpdu == mpdu->GetOriginal());
297 iterators.emplace_back(it);
298 }
299 }
300
301 DoDequeue(iterators);
302}
303
306{
307 return Peek(std::nullopt);
308}
309
311WifiMacQueue::Peek(std::optional<uint8_t> linkId) const
312{
313 NS_LOG_FUNCTION(this);
314
315 auto queueId = m_scheduler->GetNext(m_ac, linkId);
316
317 if (!queueId.has_value())
318 {
319 NS_LOG_DEBUG("The queue is empty");
320 return nullptr;
321 }
322
323 return GetContainer().GetQueue(queueId.value()).cbegin()->mpdu;
324}
325
328{
329 NS_LOG_FUNCTION(this << +tid << dest << item);
330 NS_ABORT_IF(dest.IsGroup());
332 return PeekByQueueId(queueId, item);
333}
334
337{
338 NS_LOG_FUNCTION(this << item);
339 NS_ASSERT(!item || (item->IsQueued() && WifiMacQueueContainer::GetQueueId(item) == queueId));
340
341 // Remove MPDUs with expired lifetime if we are looking for the first MPDU in the queue
342 if (!item)
343 {
344 ExtractExpiredMpdus(queueId);
345 }
346
347 auto it = (item ? std::next(GetIt(item)) : GetContainer().GetQueue(queueId).cbegin());
348
349 if (it == GetContainer().GetQueue(queueId).cend())
350 {
351 NS_LOG_DEBUG("The queue is empty");
352 return nullptr;
353 }
354
355 return it->mpdu;
356}
357
360{
361 NS_LOG_FUNCTION(this << +linkId << item);
362 NS_ASSERT(!item || item->IsQueued());
363
364 if (item)
365 {
366 // check if there are other MPDUs in the same container queue as item
367 auto mpdu = PeekByQueueId(WifiMacQueueContainer::GetQueueId(item), item);
368
369 if (mpdu)
370 {
371 return mpdu;
372 }
373 }
374
375 std::optional<WifiContainerQueueId> queueId;
376
377 if (item)
378 {
379 queueId = m_scheduler->GetNext(m_ac, linkId, WifiMacQueueContainer::GetQueueId(item));
380 }
381 else
382 {
383 queueId = m_scheduler->GetNext(m_ac, linkId);
384 }
385
386 if (!queueId.has_value())
387 {
388 NS_LOG_DEBUG("The queue is empty");
389 return nullptr;
390 }
391
392 return GetContainer().GetQueue(queueId.value()).cbegin()->mpdu;
393}
394
397{
398 return Remove(Peek());
399}
400
403{
404 NS_LOG_FUNCTION(this << mpdu);
405 NS_ASSERT(mpdu && mpdu->IsQueued());
406 auto it = GetIt(mpdu);
407 NS_ASSERT(it->ac == m_ac);
408 NS_ASSERT(it->mpdu == mpdu->GetOriginal());
409
410 return DoRemove(it);
411}
412
413void
415{
416 NS_LOG_FUNCTION(this);
417
418 // there may be some expired MPDUs in the container queue storing MPDUs with expired lifetime,
419 // which will not be flushed by the Flush() method of the base class.
422}
423
424void
426{
427 NS_LOG_FUNCTION(this << *currentItem << *newItem);
428 NS_ASSERT(currentItem->IsQueued());
429 auto currentIt = GetIt(currentItem);
430 NS_ASSERT(currentIt->ac == m_ac);
431 NS_ASSERT(currentIt->mpdu == currentItem->GetOriginal());
432 NS_ASSERT(!newItem->IsQueued());
433
434 Time expiryTime = currentIt->expiryTime;
435 auto pos = std::next(currentIt);
436 DoDequeue({currentIt});
437 bool ret = Insert(pos, newItem);
438 GetIt(newItem)->expiryTime = expiryTime;
439 // The size of a WifiMacQueue is measured as number of packets. We dequeued
440 // one packet, so there is certainly room for inserting one packet
441 NS_ABORT_IF(!ret);
442}
443
446{
447 return GetContainer().GetQueue(queueId).size();
448}
449
452{
453 return GetContainer().GetNBytes(queueId);
454}
455
456bool
458{
459 NS_LOG_FUNCTION(this << *item);
460
461 auto currSize = GetMaxSize();
462 // control frames should not consume room in the MAC queue, so increase queue size
463 // if we are trying to enqueue a control frame
464 if (item->GetHeader().IsCtl())
465 {
466 SetMaxSize(currSize + item);
467 }
468 auto mpdu = m_scheduler->HasToDropBeforeEnqueue(m_ac, item);
469
470 if (mpdu == item)
471 {
472 // the given item must be dropped
473 SetMaxSize(currSize);
474 return false;
475 }
476
477 auto queueId = WifiMacQueueContainer::GetQueueId(item);
478 if (pos != GetContainer().GetQueue(queueId).cend() && mpdu && pos->mpdu == mpdu->GetOriginal())
479 {
480 // the element pointed to by pos must be dropped; update insert position
481 pos = std::next(pos);
482 }
483 if (mpdu)
484 {
485 DoRemove(GetIt(mpdu));
486 }
487
488 Iterator ret;
490 {
491 // set item's information about its position in the queue
492 item->SetQueueIt(ret, {});
493 ret->ac = m_ac;
494 ret->expiryTime = item->GetHeader().IsCtl() ? Time::Max() : Simulator::Now() + m_maxDelay;
495 WmqIteratorTag tag;
496 ret->deleter = [tag](auto mpdu) { mpdu->SetQueueIt(std::nullopt, tag); };
497
498 m_scheduler->NotifyEnqueue(m_ac, item);
499 return true;
500 }
501 SetMaxSize(currSize);
502 return false;
503}
504
505void
506WifiMacQueue::DoDequeue(const std::list<ConstIterator>& iterators)
507{
508 NS_LOG_FUNCTION(this);
509
510 std::list<Ptr<WifiMpdu>> items;
511
512 // First, dequeue all the items
513 for (auto& it : iterators)
514 {
516 {
517 items.push_back(item);
518 if (item->GetHeader().IsCtl())
519 {
520 SetMaxSize(GetMaxSize() - item);
521 }
522 }
523 }
524
525 // Then, notify the scheduler
526 if (!items.empty())
527 {
528 m_scheduler->NotifyDequeue(m_ac, items);
529 }
530}
531
533WifiMacQueue::DoRemove(ConstIterator pos)
534{
535 NS_LOG_FUNCTION(this);
536
538
539 if (item)
540 {
541 if (item->GetHeader().IsCtl())
542 {
543 SetMaxSize(GetMaxSize() - item);
544 }
545 m_scheduler->NotifyRemove(m_ac, {item});
546 }
547
548 return item;
549}
550
551} // 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:77
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:268
Ptr< Item > DoRemove(ConstIterator pos)
Pull the item to drop from the queue.
Definition: queue.h:576
void Flush()
Flush the queue by calling Remove() on each item enqueued.
Definition: queue.h:608
void DoDispose() override
Destructor implementation.
Definition: queue.h:619
const ns3::WifiMacQueueContainer & GetContainer() const
Get a const reference to the container of queue items.
Definition: queue.h:504
Container::iterator Iterator
Iterator.
Definition: queue.h:321
Class for representing queue sizes.
Definition: queue-size.h:96
AttributeValue implementation for QueueSize.
Definition: queue-size.h:221
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:605
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:297
AttributeValue implementation for Time.
Definition: nstime.h:1406
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
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 Flush()
Flush the queue.
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 > MakeQueueSizeChecker()
Definition: queue-size.cc:29
Ptr< const AttributeAccessor > MakeQueueSizeAccessor(T1 a1)
Definition: queue-size.h:221
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1427
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1407
#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:1331
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:73
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.