A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-mac-queue-scheduler-impl.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022 Universita' degli Studi di Napoli Federico II
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Stefano Avallone <stavallo@unina.it>
7 */
8
9#ifndef WIFI_MAC_QUEUE_SCHEDULER_IMPL_H
10#define WIFI_MAC_QUEUE_SCHEDULER_IMPL_H
11
13#include "wifi-mac-queue.h"
14#include "wifi-mac.h"
15
16#include <algorithm>
17#include <array>
18#include <functional>
19#include <iterator>
20#include <list>
21#include <map>
22#include <numeric>
23#include <sstream>
24#include <unordered_map>
25#include <vector>
26
29
30namespace ns3
31{
32
33class WifiMpdu;
34class WifiMacQueue;
35
36/**
37 * @ingroup wifi
38 *
39 * WifiMacQueueSchedulerImpl is a template class enabling the definition of
40 * different types of priority values for the container queues. The function to
41 * compare priority values can be customized as well.
42 */
43template <class Priority, class Compare = std::less<Priority>>
45{
46 public:
47 /// allow test classes access
48 friend class ::WifiMacQueueDropOldestTest;
49 friend class ::WifiMacQueueFlushTest;
50
51 /**
52 * @brief Get the type ID.
53 * @return the object TypeId
54 */
55 static TypeId GetTypeId();
56
57 /**
58 * Constructor
59 */
61
62 /** @copydoc ns3::WifiMacQueueScheduler::SetWifiMac */
63 void SetWifiMac(Ptr<WifiMac> mac) final;
64 /** @copydoc ns3::WifiMacQueueScheduler::GetNext(AcIndex,std::optional<uint8_t>,bool) */
65 std::optional<WifiContainerQueueId> GetNext(AcIndex ac,
66 std::optional<uint8_t> linkId,
67 bool skipBlockedQueues = true) final;
68 /**
69 * @copydoc ns3::WifiMacQueueScheduler::GetNext(AcIndex,std::optional<uint8_t>,
70 * const WifiContainerQueueId&,bool)
71 */
73 std::optional<uint8_t> linkId,
74 const WifiContainerQueueId& prevQueueId,
75 bool skipBlockedQueues = true) final;
76 /** @copydoc ns3::WifiMacQueueScheduler::GetLinkIds */
77 std::list<uint8_t> GetLinkIds(AcIndex ac,
78 Ptr<const WifiMpdu> mpdu,
79 const std::list<WifiQueueBlockedReason>& ignoredReasons) final;
80 /** @copydoc ns3::WifiMacQueueScheduler::BlockQueues */
82 AcIndex ac,
83 const std::list<WifiContainerQueueType>& types,
84 const Mac48Address& rxAddress,
85 const Mac48Address& txAddress,
86 const std::set<uint8_t>& tids,
87 const std::set<uint8_t>& linkIds) final;
88 /** @copydoc ns3::WifiMacQueueScheduler::UnblockQueues */
90 AcIndex ac,
91 const std::list<WifiContainerQueueType>& types,
92 const Mac48Address& rxAddress,
93 const Mac48Address& txAddress,
94 const std::set<uint8_t>& tids,
95 const std::set<uint8_t>& linkIds) final;
96 /** @copydoc ns3::WifiMacQueueScheduler::BlockAllQueues */
98 const std::set<uint8_t>& linkIds,
99 const std::set<WifiRcvAddr>& addrTypes) final;
100 /** @copydoc ns3::WifiMacQueueScheduler::UnblockAllQueues */
102 const std::set<uint8_t>& linkIds,
103 const std::set<WifiRcvAddr>& addrTypes) final;
104 /** @copydoc ns3::WifiMacQueueScheduler::GetAllQueuesBlockedOnLink */
105 bool GetAllQueuesBlockedOnLink(uint8_t linkId,
106 WifiRcvAddr addrType,
107 WifiQueueBlockedReason reason) final;
108 /** @copydoc ns3::WifiMacQueueScheduler::GetQueueLinkMask */
110 const WifiContainerQueueId& queueId,
111 uint8_t linkId) final;
112 /** @copydoc ns3::WifiMacQueueScheduler::HasToDropBeforeEnqueue */
114 /** @copydoc ns3::WifiMacQueueScheduler::NotifyEnqueue */
115 void NotifyEnqueue(AcIndex ac, Ptr<WifiMpdu> mpdu) final;
116 /** @copydoc ns3::WifiMacQueueScheduler::NotifyDequeue */
117 void NotifyDequeue(AcIndex ac, const std::list<Ptr<WifiMpdu>>& mpdus) final;
118 /** @copydoc ns3::WifiMacQueueScheduler::NotifyRemove */
119 void NotifyRemove(AcIndex ac, const std::list<Ptr<WifiMpdu>>& mpdus) final;
120
121 protected:
122 /** @copydoc ns3::Object::DoDispose */
123 void DoDispose() override;
124
125 /**
126 * Set the priority for the given container queue belonging to the given Access Category.
127 *
128 * @param ac the Access Category of the container queue
129 * @param queueId the ID of the given container queue
130 * @param priority the priority value
131 */
132 void SetPriority(AcIndex ac, const WifiContainerQueueId& queueId, const Priority& priority);
133
134 struct QueueInfo;
135
136 /**
137 * Map identifiers (QueueIds) to information associated with container queues.
138 *
139 * Empty queues shall be kept in this data structure because queue information
140 * (such as the set of link IDs) may be configured just once.
141 */
143
144 /// typedef for a QueueInfoMap element
146
147 /**
148 * List of container queues sorted in decreasing order of priority.
149 *
150 * Empty queues shall not be kept in this data structure.
151 *
152 * @note We cannot store iterators to QueueInfoMap because if rehashing occurs due
153 * to an insertion, all iterators are invalidated. References are not invalidated
154 * instead. Therefore, we store reference wrappers (which can be reassigned).
155 */
156 using SortedQueues = std::multimap<Priority, std::reference_wrapper<QueueInfoPair>, Compare>;
157
158 /**
159 * Information associated with a container queue.
160 */
162 {
163 std::optional<typename SortedQueues::iterator>
164 priorityIt; /**< iterator pointing to the entry
165 for this queue in the sorted list */
166 std::map<uint8_t, Mask> linkIds; /**< Maps ID of each link on which packets contained
167 in this queue can be sent to a bitset indicating
168 whether the link is blocked (at least one bit is
169 non-zero) and for which reason */
170 };
171
172 /**
173 * Information specific to a wifi MAC queue
174 */
176 {
177 SortedQueues sortedQueues; //!< sorted list of container queues
178 QueueInfoMap queueInfoMap; //!< information associated with container queues
179 Ptr<WifiMacQueue> wifiMacQueue; //!< pointer to the WifiMacQueue object
180 };
181
182 /**
183 * Get a const reference to the sorted list of container queues for the given
184 * Access Category.
185 *
186 * @param ac the given Access Category
187 * @return a const reference to the sorted list of container queues for the given Access
188 * Category
189 */
191
192 /**
193 * Get the wifi MAC queue associated with the given Access Category.
194 *
195 * @param ac the given Access Category
196 * @return the wifi MAC queue associated with the given Access Category
197 */
199
200 private:
201 /**
202 * If no information for the container queue used to store the given MPDU of the given
203 * Access Category is present in the queue info map, add the information for such a
204 * container queue and initialize the list of the IDs of the links over which packets
205 * contained in that container queue can be sent.
206 *
207 * @param ac the given Access Category
208 * @param mpdu the given MPDU
209 * @return an iterator to the information associated with the container queue used to
210 * store the given MPDU of the given Access Category
211 */
212 typename QueueInfoMap::iterator InitQueueInfo(AcIndex ac, Ptr<const WifiMpdu> mpdu);
213
214 /**
215 * Get the next queue to serve. The search starts from the given one. The returned queue is
216 * guaranteed to contain at least an MPDU whose lifetime has not expired. Queues containing
217 * MPDUs that cannot be sent over the given link, if any, or on any link, otherwise, are ignored
218 * if and only if <i>skipBlockedQueues</i> is true.
219 *
220 * @param ac the Access Category that we want to serve
221 * @param linkId the ID of the link on which MPDUs contained in the returned queue must be
222 * allowed to be sent
223 * @param sortedQueuesIt iterator pointing to the queue we start the search from
224 * @param skipBlockedQueues whether queues containing MPDUs that cannot be sent over the given
225 * link, if any, or on any link, otherwise, must be ignored
226 * @return the ID of the selected container queue (if any)
227 */
228 std::optional<WifiContainerQueueId> DoGetNext(AcIndex ac,
229 std::optional<uint8_t> linkId,
230 typename SortedQueues::iterator sortedQueuesIt,
231 bool skipBlockedQueues);
232
233 /**
234 * Check whether an MPDU has to be dropped before enqueuing the given MPDU.
235 *
236 * @param ac the Access Category of the MPDU being enqueued
237 * @param mpdu the MPDU to enqueue
238 * @return a pointer to the MPDU to drop, if any, or a null pointer, otherwise
239 */
241 /**
242 * Notify the scheduler that the given MPDU has been enqueued by the given Access
243 * Category. The container queue in which the MPDU has been enqueued must be
244 * assigned a priority value.
245 *
246 * @param ac the Access Category of the enqueued MPDU
247 * @param mpdu the enqueued MPDU
248 */
249 virtual void DoNotifyEnqueue(AcIndex ac, Ptr<WifiMpdu> mpdu) = 0;
250 /**
251 * Notify the scheduler that the given list of MPDUs have been dequeued by the
252 * given Access Category. The container queues which became empty after dequeuing
253 * the MPDUs are removed from the sorted list of queues.
254 *
255 * @param ac the Access Category of the dequeued MPDUs
256 * @param mpdus the list of dequeued MPDUs
257 */
258 virtual void DoNotifyDequeue(AcIndex ac, const std::list<Ptr<WifiMpdu>>& mpdus) = 0;
259 /**
260 * Notify the scheduler that the given list of MPDUs have been removed by the
261 * given Access Category. The container queues which became empty after removing
262 * the MPDUs are removed from the sorted list of queues.
263 *
264 * @param ac the Access Category of the removed MPDUs
265 * @param mpdus the list of removed MPDUs
266 */
267 virtual void DoNotifyRemove(AcIndex ac, const std::list<Ptr<WifiMpdu>>& mpdus) = 0;
268
269 /**
270 * Block or unblock the given set of links for the container queues of the given types and
271 * Access Category that hold frames having the given Receiver Address (RA),
272 * Transmitter Address (TA) and TID (if needed) for the given reason.
273 *
274 * @param block true to block the queues, false to unblock
275 * @param reason the reason for blocking the queues
276 * @param ac the given Access Category
277 * @param types the types of the queues to block
278 * @param rxAddress the Receiver Address (RA) of the frames
279 * @param txAddress the Transmitter Address (TA) of the frames
280 * @param tids the TIDs optionally identifying the queues to block
281 * @param linkIds set of links to block (empty to block all setup links)
282 */
283 void DoBlockQueues(bool block,
285 AcIndex ac,
286 const std::list<WifiContainerQueueType>& types,
287 const Mac48Address& rxAddress,
288 const Mac48Address& txAddress,
289 const std::set<uint8_t>& tids,
290 const std::set<uint8_t>& linkIds);
291
292 /**
293 * Block or unblock the given set of links for all the container queues of the given receiver
294 * address types for the given reason.
295 *
296 * @param block true to block the queues, false to unblock
297 * @param reason the reason for blocking the queues
298 * @param addrTypes set of receiver address types (empty to block all types)
299 * @param linkIds set of links to block (empty to block all setup links)
300 */
301 void DoBlockAllQueues(bool block,
303 const std::set<WifiRcvAddr>& addrTypes,
304 const std::set<uint8_t>& linkIds);
305
306 /// Map a given reason to the set of links to be (un)blocked for that reason
307 using ReasonLinksMap = std::map<WifiQueueBlockedReason, std::set<uint8_t>>;
308
309 /**
310 * When it is requested to block all the queues of given receiver address types, the reason and
311 * the IDs of the links to block are stored in the elements of the array corresponding to the
312 * receiver address types. This information is used to block queues that will be created
313 * afterwards.
314 */
315 std::array<ReasonLinksMap, static_cast<std::size_t>(WifiRcvAddr::COUNT)> m_blockAllInfo;
316
317 std::vector<PerAcInfo> m_perAcInfo{AC_UNDEF}; //!< vector of per-AC information
318 NS_LOG_TEMPLATE_DECLARE; //!< the log component
319};
320
321/**
322 * Implementation of the templates declared above.
323 */
324
325template <class Priority, class Compare>
330
331template <class Priority, class Compare>
332TypeId
334{
335 static TypeId tid = TypeId("ns3::WifiMacQueueSchedulerImpl")
337 .SetGroupName("Wifi");
338 return tid;
339}
340
341template <class Priority, class Compare>
342void
348
349template <class Priority, class Compare>
350void
352{
353 for (auto ac : {AC_BE, AC_BK, AC_VI, AC_VO, AC_BE_NQOS, AC_BEACON})
354 {
355 if (auto queue = mac->GetTxopQueue(ac); queue != nullptr)
356 {
357 m_perAcInfo.at(ac).wifiMacQueue = queue;
358 queue->SetScheduler(this);
359 }
360 }
362}
363
364template <class Priority, class Compare>
367{
368 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
369 return m_perAcInfo.at(ac).wifiMacQueue;
370}
371
372template <class Priority, class Compare>
375{
376 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
377 return m_perAcInfo.at(ac).sortedQueues;
378}
379
380template <class Priority, class Compare>
381typename WifiMacQueueSchedulerImpl<Priority, Compare>::QueueInfoMap::iterator
383{
384 NS_LOG_FUNCTION(this << ac << *mpdu);
385
386 auto queueId = WifiMacQueueContainer::GetQueueId(mpdu);
387 // insert queueId in the queue info map if not present yet
388 auto [queueInfoIt, ret] = m_perAcInfo[ac].queueInfoMap.insert({queueId, QueueInfo()});
389
390 // Initialize/update the set of link IDs depending on the container queue type
391 if (GetMac() && GetMac()->GetNLinks() > 1 &&
392 mpdu->GetHeader().GetAddr2() == GetMac()->GetAddress())
393 {
394 // this is an MLD and the TA field of the frame contains the MLD address,
395 // which means that the frame can be sent on multiple links
396 const auto rxAddr = mpdu->GetHeader().GetAddr1();
397
398 // this assert checks that the RA field also contain an MLD address, unless
399 // it contains the broadcast address
400 NS_ASSERT_MSG(rxAddr.IsGroup() || GetMac()->GetMldAddress(rxAddr) == rxAddr,
401 "Address 1 (" << rxAddr << ") is not an MLD address");
402
403 // this assert checks that association (ML setup) has been established
404 // between sender and receiver (unless the receiver is the broadcast address)
405 NS_ASSERT_MSG(GetMac()->CanForwardPacketsTo(rxAddr),
406 "Cannot forward frame to " << rxAddr
407 << "; check that the receiver is associated");
408 // we have to include all the links in case of broadcast frame (we are an AP)
409 // and the links that have been setup with the receiver in case of unicast frame
410 for (const auto linkId : GetMac()->GetLinkIds())
411 {
412 if (rxAddr.IsGroup() ||
413 GetMac()->GetWifiRemoteStationManager(linkId)->GetAffiliatedStaAddress(rxAddr))
414 {
415 // the mask is not modified if linkId is already in the map
416 auto [it, inserted] = queueInfoIt->second.linkIds.try_emplace(linkId);
417
418 if (inserted)
419 {
420 // linkId was not in the map, set the mask if all queues are blocked
421 for (const auto& [reason, linkIds] :
422 m_blockAllInfo[static_cast<std::size_t>(std::get<WifiRcvAddr>(queueId))])
423 {
424 if (linkIds.contains(linkId))
425 {
426 it->second.set(static_cast<std::size_t>(reason), true);
427 }
428 }
429 }
430 }
431 else
432 {
433 // this link is no (longer) setup
434 queueInfoIt->second.linkIds.erase(linkId);
435 }
436 }
437 }
438 else
439 {
440 // the TA field of the frame contains a link address, which means that the
441 // frame can only be sent on the corresponding link
442 auto linkId = GetMac() ? GetMac()->GetLinkIdByAddress(mpdu->GetHeader().GetAddr2())
443 : SINGLE_LINK_OP_ID; // make unit test happy
444 NS_ASSERT(linkId.has_value());
445 auto& linkIdsMap = queueInfoIt->second.linkIds;
446 NS_ASSERT_MSG(linkIdsMap.size() <= 1,
447 "At most one link can be associated with this container queue");
448 // set the link map to contain one entry corresponding to the computed link ID;
449 // unless the link map already contained such an entry (in which case the mask
450 // is preserved)
451 if (linkIdsMap.empty() || linkIdsMap.cbegin()->first != *linkId)
452 {
453 Mask mask;
454 for (const auto& [reason, linkIds] :
455 m_blockAllInfo[static_cast<std::size_t>(std::get<WifiRcvAddr>(queueId))])
456 {
457 if (linkIds.contains(*linkId))
458 {
459 mask.set(static_cast<std::size_t>(reason), true);
460 }
461 }
462
463 linkIdsMap = {{*linkId, mask}};
464 }
465 }
466
467 return queueInfoIt;
468}
469
470template <class Priority, class Compare>
471void
473 const WifiContainerQueueId& queueId,
474 const Priority& priority)
475{
476 NS_LOG_FUNCTION(this << +ac);
477 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
478
479 NS_ABORT_MSG_IF(GetWifiMacQueue(ac)->GetNBytes(queueId) == 0,
480 "Cannot set the priority of an empty queue");
481
482 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
483 NS_ASSERT_MSG(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end(),
484 "No queue info for the given container queue");
485 typename SortedQueues::iterator sortedQueuesIt;
486
487 if (queueInfoIt->second.priorityIt.has_value())
488 {
489 // an element for queueId is present in the set of sorted queues. If the priority
490 // has not changed, do nothing. Otherwise, unlink the node containing such element,
491 // change the priority and insert it back
492 if (queueInfoIt->second.priorityIt.value()->first == priority)
493 {
494 return;
495 }
496
497 auto handle = m_perAcInfo[ac].sortedQueues.extract(queueInfoIt->second.priorityIt.value());
498 handle.key() = priority;
499 sortedQueuesIt = m_perAcInfo[ac].sortedQueues.insert(std::move(handle));
500 }
501 else
502 {
503 // an element for queueId is not present in the set of sorted queues
504 sortedQueuesIt = m_perAcInfo[ac].sortedQueues.insert({priority, std::ref(*queueInfoIt)});
505 }
506 // update the stored iterator
507 queueInfoIt->second.priorityIt = sortedQueuesIt;
508}
509
510template <class Priority, class Compare>
511std::list<uint8_t>
513 AcIndex ac,
515 const std::list<WifiQueueBlockedReason>& ignoredReasons)
516{
517 auto queueInfoIt = InitQueueInfo(ac, mpdu);
518 std::list<uint8_t> linkIds;
519
520 // include only links that are not blocked in the returned list
521 for (auto [linkId, mask] : queueInfoIt->second.linkIds)
522 {
523 // reset the bits of the mask corresponding to the reasons to ignore
524 for (const auto reason : ignoredReasons)
525 {
526 mask.reset(static_cast<std::size_t>(reason));
527 }
528
529 if (mask.none())
530 {
531 linkIds.emplace_back(linkId);
532 }
533 }
534
535 return linkIds;
536}
537
538template <class Priority, class Compare>
539void
541 bool block,
543 AcIndex ac,
544 const std::list<WifiContainerQueueType>& types,
545 const Mac48Address& rxAddress,
546 const Mac48Address& txAddress,
547 const std::set<uint8_t>& tids,
548 const std::set<uint8_t>& linkIds)
549{
550 std::stringstream ss;
551 if (g_log.IsEnabled(ns3::LOG_FUNCTION))
552 {
553 std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
554 }
555 NS_LOG_FUNCTION(this << block << reason << ac << rxAddress << txAddress << ss.str());
556 std::list<WifiMacHeader> headers;
557
558 for (const auto queueType : types)
559 {
560 switch (queueType)
561 {
562 case WIFI_CTL_QUEUE:
563 headers.emplace_back(WIFI_MAC_CTL_BACKREQ);
564 break;
565 case WIFI_MGT_QUEUE:
566 headers.emplace_back(WIFI_MAC_MGT_ACTION);
567 break;
569 NS_ASSERT_MSG(!tids.empty(),
570 "TID must be specified for queues containing QoS data frames");
571 for (const auto tid : tids)
572 {
573 headers.emplace_back(WIFI_MAC_QOSDATA);
574 headers.back().SetQosTid(tid);
575 }
576 break;
577 case WIFI_DATA_QUEUE:
578 headers.emplace_back(WIFI_MAC_DATA);
579 break;
580 }
581 }
582 for (auto& hdr : headers)
583 {
584 hdr.SetAddr1(rxAddress);
585 hdr.SetAddr2(txAddress);
586
587 auto queueInfoIt = InitQueueInfo(ac, Create<WifiMpdu>(Create<Packet>(), hdr));
588 for (auto& [linkId, mask] : queueInfoIt->second.linkIds)
589 {
590 if (linkIds.empty() || linkIds.contains(linkId))
591 {
592 mask.set(static_cast<std::size_t>(reason), block);
593 }
594 }
595 }
596}
597
598template <class Priority, class Compare>
599void
602 AcIndex ac,
603 const std::list<WifiContainerQueueType>& types,
604 const Mac48Address& rxAddress,
605 const Mac48Address& txAddress,
606 const std::set<uint8_t>& tids,
607 const std::set<uint8_t>& linkIds)
608{
609 DoBlockQueues(true, reason, ac, types, rxAddress, txAddress, tids, linkIds);
610}
611
612template <class Priority, class Compare>
613void
616 AcIndex ac,
617 const std::list<WifiContainerQueueType>& types,
618 const Mac48Address& rxAddress,
619 const Mac48Address& txAddress,
620 const std::set<uint8_t>& tids,
621 const std::set<uint8_t>& linkIds)
622{
623 DoBlockQueues(false, reason, ac, types, rxAddress, txAddress, tids, linkIds);
624}
625
626template <class Priority, class Compare>
627void
629 bool block,
631 const std::set<WifiRcvAddr>& addrTypes,
632 const std::set<uint8_t>& linkIds)
633{
634 const auto acList =
635 GetMac()->GetQosSupported() ? edcaAcIndices : std::list<AcIndex>{AC_BE_NQOS};
636 for (const auto ac : acList)
637 {
638 for (auto& [queueId, queueInfo] : m_perAcInfo[ac].queueInfoMap)
639 {
640 if (addrTypes.empty() || addrTypes.contains(std::get<WifiRcvAddr>(queueId)))
641 {
642 for (auto& [linkId, mask] : queueInfo.linkIds)
643 {
644 if (linkIds.empty() || linkIds.contains(linkId))
645 {
646 mask.set(static_cast<std::size_t>(reason), block);
647 }
648 }
649 }
650 }
651 }
652}
653
654template <class Priority, class Compare>
655void
657 const std::set<uint8_t>& linkIds,
658 const std::set<WifiRcvAddr>& addrTypes)
659{
660 DoBlockAllQueues(true, reason, addrTypes, linkIds);
661
662 const auto rcvAddrTypes =
663 (addrTypes.empty()
665 : addrTypes);
666
667 for (const auto addrType : rcvAddrTypes)
668 {
669 const auto index = static_cast<std::size_t>(addrType);
670 if (linkIds.empty())
671 {
672 m_blockAllInfo[index][reason] = GetMac()->GetLinkIds(); // all links blocked
673 }
674 else
675 {
676 m_blockAllInfo[index][reason].merge(std::set{linkIds});
677 }
678 }
679}
680
681template <class Priority, class Compare>
682void
685 const std::set<uint8_t>& linkIds,
686 const std::set<WifiRcvAddr>& addrTypes)
687{
688 DoBlockAllQueues(false, reason, addrTypes, linkIds);
689
690 const auto rcvAddrTypes =
691 (addrTypes.empty()
693 : addrTypes);
694
695 for (const auto addrType : rcvAddrTypes)
696 {
697 auto& blockAllInfo = m_blockAllInfo[static_cast<std::size_t>(addrType)];
698 auto infoIt = blockAllInfo.find(reason);
699
700 if (infoIt == blockAllInfo.end())
701 {
702 continue; // all queues were not blocked for the given reason
703 }
704 std::erase_if(infoIt->second,
705 [&](uint8_t id) { return linkIds.empty() || linkIds.contains(id); });
706
707 if (infoIt->second.empty())
708 {
709 // no more links blocked for the given reason
710 blockAllInfo.erase(infoIt);
711 }
712 }
713}
714
715template <class Priority, class Compare>
716bool
718 uint8_t linkId,
719 WifiRcvAddr addrType,
721{
722 const auto rcvAddrTypes =
723 (addrType == WifiRcvAddr::COUNT
725 : std::set{addrType});
726
727 return std::all_of(
728 rcvAddrTypes.cbegin(),
729 rcvAddrTypes.cend(),
730 // lambda returning whether all the container queues of the given receiver address type are
731 // blocked for the given reason (or for any reason)
732 [=, this](const auto rcvAddrType) {
733 for (const auto& [r, linkIds] : m_blockAllInfo[static_cast<std::size_t>(rcvAddrType)])
734 {
735 if ((reason == WifiQueueBlockedReason::REASONS_COUNT || reason == r) &&
736 linkIds.contains(linkId))
737 {
738 return true;
739 }
740 }
741 return false;
742 });
743}
744
745template <class Priority, class Compare>
746std::optional<WifiMacQueueScheduler::Mask>
748 const WifiContainerQueueId& queueId,
749 uint8_t linkId)
750{
751 NS_LOG_FUNCTION(this << +ac << +linkId);
752
753 const auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
754
755 if (queueInfoIt == m_perAcInfo[ac].queueInfoMap.cend())
756 {
757 // the given container queue does not exist
758 return std::nullopt;
759 }
760
761 const auto& linkIds = queueInfoIt->second.linkIds;
762 if (const auto linkIt = linkIds.find(linkId); linkIt != linkIds.cend())
763 {
764 return linkIt->second;
765 }
766
767 return std::nullopt;
768}
769
770template <class Priority, class Compare>
771std::optional<WifiContainerQueueId>
773 std::optional<uint8_t> linkId,
774 bool skipBlockedQueues)
775{
776 NS_LOG_FUNCTION(this << +ac << linkId.has_value() << skipBlockedQueues);
777 return DoGetNext(ac, linkId, m_perAcInfo[ac].sortedQueues.begin(), skipBlockedQueues);
778}
779
780template <class Priority, class Compare>
781std::optional<WifiContainerQueueId>
783 std::optional<uint8_t> linkId,
784 const WifiContainerQueueId& prevQueueId,
785 bool skipBlockedQueues)
786{
787 NS_LOG_FUNCTION(this << +ac << linkId.has_value() << skipBlockedQueues);
788
789 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(prevQueueId);
790 NS_ABORT_IF(queueInfoIt == m_perAcInfo[ac].queueInfoMap.end() ||
791 !queueInfoIt->second.priorityIt.has_value());
792
793 auto sortedQueuesIt = queueInfoIt->second.priorityIt.value();
794 NS_ABORT_IF(sortedQueuesIt == m_perAcInfo[ac].sortedQueues.end());
795
796 return DoGetNext(ac, linkId, ++sortedQueuesIt, skipBlockedQueues);
797}
798
799template <class Priority, class Compare>
800std::optional<WifiContainerQueueId>
802 AcIndex ac,
803 std::optional<uint8_t> linkId,
804 typename SortedQueues::iterator sortedQueuesIt,
805 bool skipBlockedQueues)
806{
807 NS_LOG_FUNCTION(this << +ac << linkId.has_value() << skipBlockedQueues);
808 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
809
810 while (sortedQueuesIt != m_perAcInfo[ac].sortedQueues.end())
811 {
812 const auto& queueInfoPair = sortedQueuesIt->second.get();
813 const auto& linkIds = queueInfoPair.second.linkIds;
814 typename std::decay_t<decltype(linkIds)>::const_iterator linkIt;
815
816 if (!skipBlockedQueues ||
817 std::any_of(linkIds.cbegin(), linkIds.cend(), [&linkId](const auto& linkIdMask) {
818 return (!linkId.has_value() || linkId == linkIdMask.first) &&
819 linkIdMask.second.none();
820 }))
821 {
822 // Remove packets with expired lifetime from this queue.
823 // In case the queue becomes empty, the queue is removed from the sorted
824 // list and sortedQueuesIt is invalidated; thus, store an iterator to the
825 // previous queue in the sorted list (if any) to resume the search afterwards.
826 std::optional<typename SortedQueues::iterator> prevQueueIt;
827 if (sortedQueuesIt != m_perAcInfo[ac].sortedQueues.begin())
828 {
829 prevQueueIt = std::prev(sortedQueuesIt);
830 }
831
832 const auto queueId = queueInfoPair.first;
833 GetWifiMacQueue(ac)->ExtractExpiredMpdus(queueId);
834
835 if (GetWifiMacQueue(ac)->GetNBytes(queueId) == 0)
836 {
837 auto nextQueueIt = (prevQueueIt.has_value() ? std::next(prevQueueIt.value())
838 : m_perAcInfo[ac].sortedQueues.begin());
839 // the container queue may be empty but it may not have been removed yet from the
840 // sorted list. This may happen because the scheduler is notified after that packets
841 // are dequeued and there may be a callback connected to the Dequeue trace source
842 // that calls this function. In such a case, nextQueueIt actually points to the same
843 // queue as sortedQueuesIt. The iterator is advanced to avoid an infinite loop.
844 if (nextQueueIt != m_perAcInfo[ac].sortedQueues.end() &&
845 nextQueueIt->second.get().first == queueId)
846 {
847 sortedQueuesIt = std::next(nextQueueIt);
848 }
849 else
850 {
851 sortedQueuesIt = nextQueueIt;
852 }
853 continue;
854 }
855 return queueInfoPair.first;
856 }
857
858 sortedQueuesIt++;
859 }
860 return {};
861}
862
863template <class Priority, class Compare>
870
871template <class Priority, class Compare>
872void
874{
875 NS_LOG_FUNCTION(this << +ac << *mpdu);
876 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
877
878 // add information for the queue storing the MPDU to the queue info map, if not present yet
879 auto queueInfoIt = InitQueueInfo(ac, mpdu);
880
881 DoNotifyEnqueue(ac, mpdu);
882
883 if (!queueInfoIt->second.priorityIt.has_value())
884 {
886 "No info for the queue the MPDU was stored into (forgot to call SetPriority()?)");
887 }
888}
889
890template <class Priority, class Compare>
891void
893 const std::list<Ptr<WifiMpdu>>& mpdus)
894{
895 NS_LOG_FUNCTION(this << +ac);
896 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
897
898 DoNotifyDequeue(ac, mpdus);
899
900 std::list<WifiContainerQueueId> queueIds;
901
902 for (const auto& mpdu : mpdus)
903 {
904 queueIds.push_back(WifiMacQueueContainer::GetQueueId(mpdu));
905 }
906
907 for (const auto& queueId : queueIds)
908 {
909 if (GetWifiMacQueue(ac)->GetNBytes(queueId) == 0)
910 {
911 // The queue has now become empty and needs to be removed from the sorted
912 // list kept by the scheduler
913 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
914 NS_ASSERT(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end());
915 if (queueInfoIt->second.priorityIt.has_value())
916 {
917 m_perAcInfo[ac].sortedQueues.erase(queueInfoIt->second.priorityIt.value());
918 queueInfoIt->second.priorityIt.reset();
919 }
920 }
921 }
922}
923
924template <class Priority, class Compare>
925void
927 const std::list<Ptr<WifiMpdu>>& mpdus)
928{
929 NS_LOG_FUNCTION(this << +ac);
930 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
931
932 DoNotifyRemove(ac, mpdus);
933
934 std::list<WifiContainerQueueId> queueIds;
935
936 for (const auto& mpdu : mpdus)
937 {
938 queueIds.push_back(WifiMacQueueContainer::GetQueueId(mpdu));
939 }
940
941 for (const auto& queueId : queueIds)
942 {
943 if (GetWifiMacQueue(ac)->GetNBytes(queueId) == 0)
944 {
945 // The queue has now become empty and needs to be removed from the sorted
946 // list kept by the scheduler
947 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
948 NS_ASSERT(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end());
949 if (queueInfoIt->second.priorityIt.has_value())
950 {
951 m_perAcInfo[ac].sortedQueues.erase(queueInfoIt->second.priorityIt.value());
952 queueInfoIt->second.priorityIt.reset();
953 }
954 }
955 }
956}
957
958} // namespace ns3
959
960#endif /* WIFI_MAC_QUEUE_SCHEDULER_IMPL_H */
Test DROP_OLDEST setting.
Test that a wifi MAC queue is correctly flushed even if (at least) a container queue is blocked.
an EUI-48 address
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
a unique identifier for an interface.
Definition type-id.h:50
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
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.
This queue implements the timeout procedure described in (Section 9.19.2.6 "Retransmit procedures" pa...
WifiMacQueueScheduler is an abstract base class defining the public interface for a wifi MAC queue sc...
virtual void SetWifiMac(Ptr< WifiMac > mac)
Set the wifi MAC.
Ptr< WifiMac > GetMac() const
Get the wifi MAC.
std::bitset< static_cast< std::size_t >(WifiQueueBlockedReason::REASONS_COUNT)> Mask
Bitset identifying the reasons to block individual links for a container queue.
void DoDispose() override
Destructor implementation.
void DoBlockQueues(bool block, WifiQueueBlockedReason reason, AcIndex ac, const std::list< WifiContainerQueueType > &types, const Mac48Address &rxAddress, const Mac48Address &txAddress, const std::set< uint8_t > &tids, const std::set< uint8_t > &linkIds)
Block or unblock the given set of links for the container queues of the given types and Access Catego...
void DoBlockAllQueues(bool block, WifiQueueBlockedReason reason, const std::set< WifiRcvAddr > &addrTypes, const std::set< uint8_t > &linkIds)
Block or unblock the given set of links for all the container queues of the given receiver address ty...
void UnblockQueues(WifiQueueBlockedReason reason, AcIndex ac, const std::list< WifiContainerQueueType > &types, const Mac48Address &rxAddress, const Mac48Address &txAddress, const std::set< uint8_t > &tids, const std::set< uint8_t > &linkIds) final
std::optional< WifiContainerQueueId > DoGetNext(AcIndex ac, std::optional< uint8_t > linkId, typename SortedQueues::iterator sortedQueuesIt, bool skipBlockedQueues)
Get the next queue to serve.
std::pair< const WifiContainerQueueId, QueueInfo > QueueInfoPair
typedef for a QueueInfoMap element
std::optional< Mask > GetQueueLinkMask(AcIndex ac, const WifiContainerQueueId &queueId, uint8_t linkId) final
std::map< WifiQueueBlockedReason, std::set< uint8_t > > ReasonLinksMap
Map a given reason to the set of links to be (un)blocked for that reason.
void SetWifiMac(Ptr< WifiMac > mac) final
Set the wifi MAC.
bool GetAllQueuesBlockedOnLink(uint8_t linkId, WifiRcvAddr addrType, WifiQueueBlockedReason reason) final
void BlockAllQueues(WifiQueueBlockedReason reason, const std::set< uint8_t > &linkIds, const std::set< WifiRcvAddr > &addrTypes) final
void NotifyDequeue(AcIndex ac, const std::list< Ptr< WifiMpdu > > &mpdus) final
std::unordered_map< WifiContainerQueueId, QueueInfo > QueueInfoMap
Map identifiers (QueueIds) to information associated with container queues.
std::optional< WifiContainerQueueId > GetNext(AcIndex ac, std::optional< uint8_t > linkId, bool skipBlockedQueues=true) final
Get the next queue to serve, which is guaranteed to contain at least an MPDU whose lifetime has not e...
void NotifyEnqueue(AcIndex ac, Ptr< WifiMpdu > mpdu) final
virtual void DoNotifyDequeue(AcIndex ac, const std::list< Ptr< WifiMpdu > > &mpdus)=0
Notify the scheduler that the given list of MPDUs have been dequeued by the given Access Category.
void BlockQueues(WifiQueueBlockedReason reason, AcIndex ac, const std::list< WifiContainerQueueType > &types, const Mac48Address &rxAddress, const Mac48Address &txAddress, const std::set< uint8_t > &tids, const std::set< uint8_t > &linkIds) final
virtual void DoNotifyEnqueue(AcIndex ac, Ptr< WifiMpdu > mpdu)=0
Notify the scheduler that the given MPDU has been enqueued by the given Access Category.
Ptr< WifiMacQueue > GetWifiMacQueue(AcIndex ac) const
Get the wifi MAC queue associated with the given Access Category.
std::array< ReasonLinksMap, static_cast< std::size_t >(WifiRcvAddr::COUNT)> m_blockAllInfo
When it is requested to block all the queues of given receiver address types, the reason and the IDs ...
static TypeId GetTypeId()
Get the type ID.
void UnblockAllQueues(WifiQueueBlockedReason reason, const std::set< uint8_t > &linkIds, const std::set< WifiRcvAddr > &addrTypes) final
std::vector< PerAcInfo > m_perAcInfo
vector of per-AC information
std::list< uint8_t > GetLinkIds(AcIndex ac, Ptr< const WifiMpdu > mpdu, const std::list< WifiQueueBlockedReason > &ignoredReasons) final
const SortedQueues & GetSortedQueues(AcIndex ac) const
Get a const reference to the sorted list of container queues for the given Access Category.
Ptr< WifiMpdu > HasToDropBeforeEnqueue(AcIndex ac, Ptr< WifiMpdu > mpdu) final
void NotifyRemove(AcIndex ac, const std::list< Ptr< WifiMpdu > > &mpdus) final
virtual Ptr< WifiMpdu > HasToDropBeforeEnqueuePriv(AcIndex ac, Ptr< WifiMpdu > mpdu)=0
Check whether an MPDU has to be dropped before enqueuing the given MPDU.
QueueInfoMap::iterator InitQueueInfo(AcIndex ac, Ptr< const WifiMpdu > mpdu)
If no information for the container queue used to store the given MPDU of the given Access Category i...
std::multimap< Priority, std::reference_wrapper< QueueInfoPair >, Compare > SortedQueues
List of container queues sorted in decreasing order of priority.
virtual void DoNotifyRemove(AcIndex ac, const std::list< Ptr< WifiMpdu > > &mpdus)=0
Notify the scheduler that the given list of MPDUs have been removed by the given Access Category.
void SetPriority(AcIndex ac, const WifiContainerQueueId &queueId, const FcfsPrio &priority)
WifiMpdu stores a (const) packet along with a MAC header.
Definition wifi-mpdu.h:51
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#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:75
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition abort.h:65
#define NS_LOG_TEMPLATE_DEFINE(name)
Initialize a reference to a Log component.
Definition log.h:228
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:454
WifiQueueBlockedReason
Enumeration of the reasons to block container queues.
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition qos-utils.h:64
@ AC_BE_NQOS
Non-QoS.
Definition qos-utils.h:74
@ AC_BE
Best Effort.
Definition qos-utils.h:66
@ AC_VO
Voice.
Definition qos-utils.h:72
@ AC_VI
Video.
Definition qos-utils.h:70
@ AC_BK
Background.
Definition qos-utils.h:68
@ AC_UNDEF
Total number of ACs.
Definition qos-utils.h:78
@ AC_BEACON
Beacon queue.
Definition qos-utils.h:76
Every class exported by the ns3 library is enclosed in the ns3 namespace.
const std::list< AcIndex > edcaAcIndices
List of the Access Categories corresponding to the four EDCA functions.
Definition qos-utils.h:203
static constexpr uint8_t SINGLE_LINK_OP_ID
Link ID for single link operations (helps tracking places where correct link ID is to be used to supp...
Definition wifi-utils.h:295
WifiRcvAddr
enumeration of frame types based on receiver address
@ WIFI_MAC_CTL_BACKREQ
@ WIFI_MAC_MGT_ACTION
@ WIFI_MAC_DATA
@ WIFI_MAC_QOSDATA
WifiContainerQueueType
enumeration of container queue types
std::tuple< WifiContainerQueueType, WifiRcvAddr, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
@ LOG_FUNCTION
Function tracing for non-trivial function calls.
Definition log.h:98
STL namespace.
#define list
Information specific to a wifi MAC queue.
SortedQueues sortedQueues
sorted list of container queues
Ptr< WifiMacQueue > wifiMacQueue
pointer to the WifiMacQueue object
QueueInfoMap queueInfoMap
information associated with container queues
Information associated with a container queue.
std::map< uint8_t, Mask > linkIds
Maps ID of each link on which packets contained in this queue can be sent to a bitset indicating whet...
std::optional< typename SortedQueues::iterator > priorityIt
iterator pointing to the entry for this queue in the sorted list