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 <compare>
19#include <functional>
20#include <iterator>
21#include <list>
22#include <map>
23#include <numeric>
24#include <sstream>
25#include <unordered_map>
26#include <vector>
27
30
31namespace ns3
32{
33
34class WifiMpdu;
35class WifiMacQueue;
36
37/**
38 * @ingroup wifi
39 *
40 * Definition of priority for container queues that can be specialized by subclasses by providing
41 * the type of the priority field. This definition gives precedence to control frames over frames
42 * of the other types, and to management frames over data frames. In case multiple container queues
43 * have precedence over others, the one with the highest priority is served.
44 *
45 * @tparam Prio \explicit Priority type (must provide the spaceship operator)
46 */
47template <class Prio>
49{
50 Prio priority; ///< priority
51 WifiContainerQueueType type; ///< type of container queue
52
53 /**
54 * Spaceship comparison operator.
55 *
56 * @param other WifiSchedPrecedence object to compare to this one
57 * @return the result of the comparison
58 */
59 std::weak_ordering operator<=>(const WifiSchedPrecedence<Prio>& other) const;
60
61 /**
62 * Equality operator, needed because equality testing never invokes the spaceship operator
63 * and the spaceship operator is non-defaulted.
64 *
65 * @return whether this object is equal to the given one
66 */
67 bool operator==(const WifiSchedPrecedence<Prio>&) const = default;
68};
69
70/**
71 * @ingroup wifi
72 *
73 * WifiMacQueueSchedulerImpl is a template class enabling the definition of
74 * different types of priority values for the container queues. The function to
75 * compare priority values can be customized as well.
76 */
77template <class Priority, class Compare = std::less<Priority>>
79{
80 public:
81 /// allow test classes access
82 friend class ::WifiMacQueueDropOldestTest;
83 friend class ::WifiMacQueueFlushTest;
84
85 /**
86 * @brief Get the type ID.
87 * @return the object TypeId
88 */
89 static TypeId GetTypeId();
90
91 /**
92 * Constructor
93 */
95
96 /// drop policy
102
103 /** @copydoc ns3::WifiMacQueueScheduler::SetWifiMac */
104 void SetWifiMac(Ptr<WifiMac> mac) override;
105 /** @copydoc ns3::WifiMacQueueScheduler::SetWifiMacQueue */
106 void SetWifiMacQueue(AcIndex ac, Ptr<WifiMacQueue> queue) override;
107 /** @copydoc ns3::WifiMacQueueScheduler::GetNext(AcIndex,std::optional<uint8_t>,bool) */
108 std::optional<WifiContainerQueueId> GetNext(AcIndex ac,
109 std::optional<uint8_t> linkId,
110 bool skipBlockedQueues = true) final;
111 /**
112 * @copydoc ns3::WifiMacQueueScheduler::GetNext(AcIndex,std::optional<uint8_t>,
113 * const WifiContainerQueueId&,bool)
114 */
116 std::optional<uint8_t> linkId,
117 const WifiContainerQueueId& prevQueueId,
118 bool skipBlockedQueues = true) final;
119 /** @copydoc ns3::WifiMacQueueScheduler::GetLinkIds */
121 Ptr<const WifiMpdu> mpdu,
122 const std::list<WifiQueueBlockedReason>& ignoredReasons) final;
123 /** @copydoc ns3::WifiMacQueueScheduler::BlockQueues */
125 AcIndex ac,
126 const std::list<WifiContainerQueueType>& types,
127 const Mac48Address& rxAddress,
128 const Mac48Address& txAddress,
129 const std::set<uint8_t>& tids,
130 const std::set<uint8_t>& linkIds) final;
131 /** @copydoc ns3::WifiMacQueueScheduler::UnblockQueues */
133 AcIndex ac,
134 const std::list<WifiContainerQueueType>& types,
135 const Mac48Address& rxAddress,
136 const Mac48Address& txAddress,
137 const std::set<uint8_t>& tids,
138 const std::set<uint8_t>& linkIds) final;
139 /** @copydoc ns3::WifiMacQueueScheduler::BlockAllQueues */
141 const std::set<uint8_t>& linkIds,
142 const std::set<WifiRcvAddr>& addrTypes) final;
143 /** @copydoc ns3::WifiMacQueueScheduler::UnblockAllQueues */
145 const std::set<uint8_t>& linkIds,
146 const std::set<WifiRcvAddr>& addrTypes) final;
147 /** @copydoc ns3::WifiMacQueueScheduler::GetAllQueuesBlockedOnLink */
148 bool GetAllQueuesBlockedOnLink(uint8_t linkId,
149 WifiRcvAddr addrType,
150 WifiQueueBlockedReason reason) final;
151 /** @copydoc ns3::WifiMacQueueScheduler::GetQueueLinkMask */
153 const WifiContainerQueueId& queueId,
154 uint8_t linkId) final;
155 /** @copydoc ns3::WifiMacQueueScheduler::HasToDropBeforeEnqueue */
157 /** @copydoc ns3::WifiMacQueueScheduler::NotifyEnqueue */
158 void NotifyEnqueue(AcIndex ac, Ptr<WifiMpdu> mpdu) final;
159 /** @copydoc ns3::WifiMacQueueScheduler::NotifyDequeue */
160 void NotifyDequeue(AcIndex ac, const std::list<Ptr<WifiMpdu>>& mpdus) final;
161 /** @copydoc ns3::WifiMacQueueScheduler::NotifyRemove */
162 void NotifyRemove(AcIndex ac, const std::list<Ptr<WifiMpdu>>& mpdus) final;
163
164 protected:
165 /** @copydoc ns3::Object::DoDispose */
166 void DoDispose() override;
167
168 /**
169 * Set the priority for the given container queue belonging to the given Access Category.
170 *
171 * @param ac the Access Category of the container queue
172 * @param queueId the ID of the given container queue
173 * @param priority the priority value
174 */
175 void SetPriority(AcIndex ac, const WifiContainerQueueId& queueId, const Priority& priority);
176
177 struct QueueInfo;
178
179 /**
180 * Map identifiers (QueueIds) to information associated with container queues.
181 *
182 * Empty queues shall be kept in this data structure because queue information
183 * (such as the set of link IDs) may be configured just once.
184 */
186
187 /// typedef for a QueueInfoMap element
189
190 /**
191 * List of container queues sorted in decreasing order of priority.
192 *
193 * Empty queues shall not be kept in this data structure.
194 *
195 * @note We cannot store iterators to QueueInfoMap because if rehashing occurs due
196 * to an insertion, all iterators are invalidated. References are not invalidated
197 * instead. Therefore, we store reference wrappers (which can be reassigned).
198 */
199 using SortedQueues = std::multimap<Priority, std::reference_wrapper<QueueInfoPair>, Compare>;
200
201 /**
202 * Information associated with a container queue.
203 */
205 {
206 std::optional<typename SortedQueues::iterator>
207 priorityIt; /**< iterator pointing to the entry
208 for this queue in the sorted list */
209 std::map<uint8_t, Mask> linkIds; /**< Maps ID of each link on which packets contained
210 in this queue can be sent to a bitset indicating
211 whether the link is blocked (at least one bit is
212 non-zero) and for which reason */
213 };
214
215 /**
216 * Information specific to a wifi MAC queue
217 */
219 {
220 SortedQueues sortedQueues; //!< sorted list of container queues
221 QueueInfoMap queueInfoMap; //!< information associated with container queues
222 Ptr<WifiMacQueue> wifiMacQueue; //!< pointer to the WifiMacQueue object
223 };
224
225 /**
226 * Get a const reference to the sorted list of container queues for the given
227 * Access Category.
228 *
229 * @param ac the given Access Category
230 * @return a const reference to the sorted list of container queues for the given Access
231 * Category
232 */
234
235 /**
236 * Get the wifi MAC queue associated with the given Access Category.
237 *
238 * @param ac the given Access Category
239 * @return the wifi MAC queue associated with the given Access Category
240 */
242
243 private:
244 /**
245 * If no information for the container queue used to store the given MPDU of the given
246 * Access Category is present in the queue info map, add the information for such a
247 * container queue and initialize the list of the IDs of the links over which packets
248 * contained in that container queue can be sent.
249 *
250 * @param ac the given Access Category
251 * @param mpdu the given MPDU
252 * @return an iterator to the information associated with the container queue used to
253 * store the given MPDU of the given Access Category
254 */
255 typename QueueInfoMap::iterator InitQueueInfo(AcIndex ac, Ptr<const WifiMpdu> mpdu);
256
257 /**
258 * Get the next queue to serve. The search starts from the given one. The returned queue is
259 * guaranteed to contain at least an MPDU whose lifetime has not expired. Queues containing
260 * MPDUs that cannot be sent over the given link, if any, or on any link, otherwise, are ignored
261 * if and only if <i>skipBlockedQueues</i> is true.
262 *
263 * @param ac the Access Category that we want to serve
264 * @param linkId the ID of the link on which MPDUs contained in the returned queue must be
265 * allowed to be sent
266 * @param sortedQueuesIt iterator pointing to the queue we start the search from
267 * @param skipBlockedQueues whether queues containing MPDUs that cannot be sent over the given
268 * link, if any, or on any link, otherwise, must be ignored
269 * @return the ID of the selected container queue (if any)
270 */
271 std::optional<WifiContainerQueueId> DoGetNext(AcIndex ac,
272 std::optional<uint8_t> linkId,
273 typename SortedQueues::iterator sortedQueuesIt,
274 bool skipBlockedQueues);
275
276 /**
277 * Notify the scheduler that the given MPDU has been enqueued by the given Access
278 * Category. The container queue in which the MPDU has been enqueued must be
279 * assigned a priority value.
280 *
281 * @param ac the Access Category of the enqueued MPDU
282 * @param mpdu the enqueued MPDU
283 */
284 virtual void DoNotifyEnqueue(AcIndex ac, Ptr<WifiMpdu> mpdu) = 0;
285 /**
286 * Notify the scheduler that the given list of MPDUs have been dequeued by the
287 * given Access Category. The container queues which became empty after dequeuing
288 * the MPDUs are removed from the sorted list of queues.
289 *
290 * @param ac the Access Category of the dequeued MPDUs
291 * @param mpdus the list of dequeued MPDUs
292 */
293 virtual void DoNotifyDequeue(AcIndex ac, const std::list<Ptr<WifiMpdu>>& mpdus) = 0;
294 /**
295 * Notify the scheduler that the given list of MPDUs have been removed by the
296 * given Access Category. The container queues which became empty after removing
297 * the MPDUs are removed from the sorted list of queues.
298 *
299 * @param ac the Access Category of the removed MPDUs
300 * @param mpdus the list of removed MPDUs
301 */
302 virtual void DoNotifyRemove(AcIndex ac, const std::list<Ptr<WifiMpdu>>& mpdus) = 0;
303
304 /**
305 * Block or unblock the given set of links for the container queues of the given types and
306 * Access Category that hold frames having the given Receiver Address (RA),
307 * Transmitter Address (TA) and TID (if needed) for the given reason.
308 *
309 * @param block true to block the queues, false to unblock
310 * @param reason the reason for blocking the queues
311 * @param ac the given Access Category
312 * @param types the types of the queues to block
313 * @param rxAddress the Receiver Address (RA) of the frames
314 * @param txAddress the Transmitter Address (TA) of the frames
315 * @param tids the TIDs optionally identifying the queues to block
316 * @param linkIds set of links to block (empty to block all setup links)
317 */
318 void DoBlockQueues(bool block,
320 AcIndex ac,
321 const std::list<WifiContainerQueueType>& types,
322 const Mac48Address& rxAddress,
323 const Mac48Address& txAddress,
324 const std::set<uint8_t>& tids,
325 const std::set<uint8_t>& linkIds);
326
327 /**
328 * Block or unblock the given set of links for all the container queues of the given receiver
329 * address types for the given reason.
330 *
331 * @param block true to block the queues, false to unblock
332 * @param reason the reason for blocking the queues
333 * @param addrTypes set of receiver address types (empty to block all types)
334 * @param linkIds set of links to block (empty to block all setup links)
335 */
336 void DoBlockAllQueues(bool block,
338 const std::set<WifiRcvAddr>& addrTypes,
339 const std::set<uint8_t>& linkIds);
340
341 /// Map a given reason to the set of links to be (un)blocked for that reason
342 using ReasonLinksMap = std::map<WifiQueueBlockedReason, std::set<uint8_t>>;
343
344 /**
345 * When it is requested to block all the queues of given receiver address types, the reason and
346 * the IDs of the links to block are stored in the elements of the array corresponding to the
347 * receiver address types. This information is used to block queues that will be created
348 * afterwards.
349 */
350 std::array<ReasonLinksMap, static_cast<std::size_t>(WifiRcvAddr::COUNT)> m_blockAllInfo;
351
352 std::vector<PerAcInfo> m_perAcInfo{AC_UNDEF}; //!< vector of per-AC information
353 DropPolicy m_dropPolicy; //!< Drop behavior of queue
354 NS_LOG_TEMPLATE_DECLARE; //!< the log component
355};
356
357/**
358 * Implementation of the templates declared above.
359 */
360
361template <class Prio>
362std::weak_ordering
364{
365 // Control queues have the highest precedence
366 if (type == WIFI_CTL_QUEUE && other.type != WIFI_CTL_QUEUE)
367 {
368 return std::weak_ordering::less;
369 }
370 if (type != WIFI_CTL_QUEUE && other.type == WIFI_CTL_QUEUE)
371 {
372 return std::weak_ordering::greater;
373 }
374 // Management queues have the second highest precedence
375 if (type == WIFI_MGT_QUEUE && other.type != WIFI_MGT_QUEUE)
376 {
377 return std::weak_ordering::less;
378 }
379 if (type != WIFI_MGT_QUEUE && other.type == WIFI_MGT_QUEUE)
380 {
381 return std::weak_ordering::greater;
382 }
383 // we get here if both priority values refer to container queues of the same type,
384 // hence we can compare the time values.
385 return priority <=> other.priority;
386}
387
388template <class Priority, class Compare>
393
394template <class Priority, class Compare>
395TypeId
397{
398 static TypeId tid =
401 .SetGroupName("Wifi")
402 .AddAttribute("DropPolicy",
403 "Upon enqueue with full queue, drop oldest (DropOldest) "
404 "or newest (DropNewest) packet",
408 MakeEnumChecker(DROP_OLDEST, "DropOldest", DROP_NEWEST, "DropNewest"));
409 return tid;
410}
411
412template <class Priority, class Compare>
413void
419
420template <class Priority, class Compare>
421void
423{
424 for (auto ac : {AC_BE, AC_BK, AC_VI, AC_VO, AC_BE_NQOS, AC_BEACON})
425 {
426 if (auto queue = mac->GetTxopQueue(ac); queue != nullptr)
427 {
428 SetWifiMacQueue(ac, queue);
429 }
430 }
432}
433
434template <class Priority, class Compare>
435void
437{
438 NS_LOG_FUNCTION(this << ac << queue);
439 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
440 m_perAcInfo.at(ac).wifiMacQueue = queue;
442}
443
444template <class Priority, class Compare>
447{
448 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
449 return m_perAcInfo.at(ac).wifiMacQueue;
450}
451
452template <class Priority, class Compare>
455{
456 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
457 return m_perAcInfo.at(ac).sortedQueues;
458}
459
460template <class Priority, class Compare>
461typename WifiMacQueueSchedulerImpl<Priority, Compare>::QueueInfoMap::iterator
463{
464 NS_LOG_FUNCTION(this << ac << *mpdu);
465
466 auto queueId = WifiMacQueueContainer::GetQueueId(mpdu);
467 // insert queueId in the queue info map if not present yet
468 auto [queueInfoIt, ret] = m_perAcInfo[ac].queueInfoMap.insert({queueId, QueueInfo()});
469
470 // Initialize/update the set of link IDs depending on the container queue type
471 if (GetMac() && GetMac()->GetNLinks() > 1 &&
472 mpdu->GetHeader().GetAddr2() == GetMac()->GetAddress())
473 {
474 // this is an MLD and the TA field of the frame contains the MLD address,
475 // which means that the frame can be sent on multiple links
476 const auto rxAddr = mpdu->GetHeader().GetAddr1();
477
478 // this assert checks that the RA field also contain an MLD address, unless
479 // it contains the broadcast address
480 NS_ASSERT_MSG(rxAddr.IsGroup() || GetMac()->GetMldAddress(rxAddr) == rxAddr,
481 "Address 1 (" << rxAddr << ") is not an MLD address");
482
483 // this assert checks that association (ML setup) has been established
484 // between sender and receiver (unless the receiver is the broadcast address)
485 NS_ASSERT_MSG(GetMac()->CanForwardPacketsTo(rxAddr),
486 "Cannot forward frame to " << rxAddr
487 << "; check that the receiver is associated");
488 // we have to include all the links in case of broadcast frame (we are an AP)
489 // and the links that have been setup with the receiver in case of unicast frame
490 for (const auto linkId : GetMac()->GetLinkIds())
491 {
492 if (rxAddr.IsGroup() ||
493 GetMac()->GetWifiRemoteStationManager(linkId)->GetAffiliatedStaAddress(rxAddr))
494 {
495 // the mask is not modified if linkId is already in the map
496 auto [it, inserted] = queueInfoIt->second.linkIds.try_emplace(linkId);
497
498 if (inserted)
499 {
500 // linkId was not in the map, set the mask if all queues are blocked
501 for (const auto& [reason, linkIds] :
502 m_blockAllInfo[static_cast<std::size_t>(queueId.addrType)])
503 {
504 if (linkIds.contains(linkId))
505 {
506 it->second.set(static_cast<std::size_t>(reason), true);
507 }
508 }
509 }
510 }
511 else
512 {
513 // this link is no (longer) setup
514 queueInfoIt->second.linkIds.erase(linkId);
515 }
516 }
517 }
518 else
519 {
520 // the TA field of the frame contains a link address, which means that the
521 // frame can only be sent on the corresponding link
522 auto linkId = GetMac() ? GetMac()->GetLinkIdByAddress(mpdu->GetHeader().GetAddr2())
523 : SINGLE_LINK_OP_ID; // make unit test happy
524 NS_ASSERT(linkId.has_value());
525 auto& linkIdsMap = queueInfoIt->second.linkIds;
526 NS_ASSERT_MSG(linkIdsMap.size() <= 1,
527 "At most one link can be associated with this container queue");
528 // set the link map to contain one entry corresponding to the computed link ID;
529 // unless the link map already contained such an entry (in which case the mask
530 // is preserved)
531 if (linkIdsMap.empty() || linkIdsMap.cbegin()->first != *linkId)
532 {
533 Mask mask;
534 for (const auto& [reason, linkIds] :
535 m_blockAllInfo[static_cast<std::size_t>(queueId.addrType)])
536 {
537 if (linkIds.contains(*linkId))
538 {
539 mask.set(static_cast<std::size_t>(reason), true);
540 }
541 }
542
543 linkIdsMap = {{*linkId, mask}};
544 }
545 }
546
547 return queueInfoIt;
548}
549
550template <class Priority, class Compare>
551void
553 const WifiContainerQueueId& queueId,
554 const Priority& priority)
555{
556 NS_LOG_FUNCTION(this << ac);
557 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
558
559 NS_ABORT_MSG_IF(GetWifiMacQueue(ac)->GetNBytes(queueId) == 0,
560 "Cannot set the priority of an empty queue");
561
562 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
563 NS_ASSERT_MSG(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end(),
564 "No queue info for the given container queue");
565 typename SortedQueues::iterator sortedQueuesIt;
566
567 if (queueInfoIt->second.priorityIt.has_value())
568 {
569 // an element for queueId is present in the set of sorted queues. If the priority
570 // has not changed, do nothing. Otherwise, unlink the node containing such element,
571 // change the priority and insert it back
572 if (queueInfoIt->second.priorityIt.value()->first == priority)
573 {
574 return;
575 }
576
577 auto handle = m_perAcInfo[ac].sortedQueues.extract(queueInfoIt->second.priorityIt.value());
578 handle.key() = priority;
579 sortedQueuesIt = m_perAcInfo[ac].sortedQueues.insert(std::move(handle));
580 }
581 else
582 {
583 // an element for queueId is not present in the set of sorted queues
584 sortedQueuesIt = m_perAcInfo[ac].sortedQueues.insert({priority, std::ref(*queueInfoIt)});
585 }
586 // update the stored iterator
587 queueInfoIt->second.priorityIt = sortedQueuesIt;
588}
589
590template <class Priority, class Compare>
591std::list<uint8_t>
593 AcIndex ac,
595 const std::list<WifiQueueBlockedReason>& ignoredReasons)
596{
597 auto queueInfoIt = InitQueueInfo(ac, mpdu);
598 std::list<uint8_t> linkIds;
599
600 // include only links that are not blocked in the returned list
601 for (auto [linkId, mask] : queueInfoIt->second.linkIds)
602 {
603 // reset the bits of the mask corresponding to the reasons to ignore
604 for (const auto reason : ignoredReasons)
605 {
606 mask.reset(static_cast<std::size_t>(reason));
607 }
608
609 if (mask.none())
610 {
611 linkIds.emplace_back(linkId);
612 }
613 }
614
615 return linkIds;
616}
617
618template <class Priority, class Compare>
619void
621 bool block,
623 AcIndex ac,
624 const std::list<WifiContainerQueueType>& types,
625 const Mac48Address& rxAddress,
626 const Mac48Address& txAddress,
627 const std::set<uint8_t>& tids,
628 const std::set<uint8_t>& linkIds)
629{
630 std::stringstream ss;
631 if (g_log.IsEnabled(ns3::LOG_FUNCTION))
632 {
633 std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
634 }
635 NS_LOG_FUNCTION(this << block << reason << ac << rxAddress << txAddress << ss.str());
636 std::list<WifiMacHeader> headers;
637
638 for (const auto queueType : types)
639 {
640 switch (queueType)
641 {
642 case WIFI_CTL_QUEUE:
643 headers.emplace_back(WIFI_MAC_CTL_BACKREQ);
644 break;
645 case WIFI_MGT_QUEUE:
646 headers.emplace_back(WIFI_MAC_MGT_ACTION);
647 break;
649 NS_ASSERT_MSG(!tids.empty(),
650 "TID must be specified for queues containing QoS data frames");
651 for (const auto tid : tids)
652 {
653 headers.emplace_back(WIFI_MAC_QOSDATA);
654 headers.back().SetQosTid(tid);
655 }
656 break;
657 case WIFI_DATA_QUEUE:
658 headers.emplace_back(WIFI_MAC_DATA);
659 break;
660 }
661 }
662 for (auto& hdr : headers)
663 {
664 hdr.SetAddr1(rxAddress);
665 hdr.SetAddr2(txAddress);
666
667 auto queueInfoIt = InitQueueInfo(ac, Create<WifiMpdu>(Create<Packet>(), hdr));
668 for (auto& [linkId, mask] : queueInfoIt->second.linkIds)
669 {
670 if (linkIds.empty() || linkIds.contains(linkId))
671 {
672 mask.set(static_cast<std::size_t>(reason), block);
673 }
674 }
675 }
676}
677
678template <class Priority, class Compare>
679void
682 AcIndex ac,
683 const std::list<WifiContainerQueueType>& types,
684 const Mac48Address& rxAddress,
685 const Mac48Address& txAddress,
686 const std::set<uint8_t>& tids,
687 const std::set<uint8_t>& linkIds)
688{
689 DoBlockQueues(true, reason, ac, types, rxAddress, txAddress, tids, linkIds);
690}
691
692template <class Priority, class Compare>
693void
696 AcIndex ac,
697 const std::list<WifiContainerQueueType>& types,
698 const Mac48Address& rxAddress,
699 const Mac48Address& txAddress,
700 const std::set<uint8_t>& tids,
701 const std::set<uint8_t>& linkIds)
702{
703 DoBlockQueues(false, reason, ac, types, rxAddress, txAddress, tids, linkIds);
704}
705
706template <class Priority, class Compare>
707void
709 bool block,
711 const std::set<WifiRcvAddr>& addrTypes,
712 const std::set<uint8_t>& linkIds)
713{
714 const auto acList =
715 GetMac()->GetQosSupported() ? edcaAcIndices : std::list<AcIndex>{AC_BE_NQOS};
716 for (const auto ac : acList)
717 {
718 for (auto& [queueId, queueInfo] : m_perAcInfo[ac].queueInfoMap)
719 {
720 if (addrTypes.empty() || addrTypes.contains(queueId.addrType))
721 {
722 for (auto& [linkId, mask] : queueInfo.linkIds)
723 {
724 if (linkIds.empty() || linkIds.contains(linkId))
725 {
726 mask.set(static_cast<std::size_t>(reason), block);
727 }
728 }
729 }
730 }
731 }
732}
733
734template <class Priority, class Compare>
735void
737 const std::set<uint8_t>& linkIds,
738 const std::set<WifiRcvAddr>& addrTypes)
739{
740 DoBlockAllQueues(true, reason, addrTypes, linkIds);
741
742 const auto rcvAddrTypes =
743 (addrTypes.empty()
745 : addrTypes);
746
747 for (const auto addrType : rcvAddrTypes)
748 {
749 const auto index = static_cast<std::size_t>(addrType);
750 if (linkIds.empty())
751 {
752 m_blockAllInfo[index][reason] = GetMac()->GetLinkIds(); // all links blocked
753 }
754 else
755 {
756 m_blockAllInfo[index][reason].merge(std::set{linkIds});
757 }
758 }
759}
760
761template <class Priority, class Compare>
762void
765 const std::set<uint8_t>& linkIds,
766 const std::set<WifiRcvAddr>& addrTypes)
767{
768 DoBlockAllQueues(false, reason, addrTypes, linkIds);
769
770 const auto rcvAddrTypes =
771 (addrTypes.empty()
773 : addrTypes);
774
775 for (const auto addrType : rcvAddrTypes)
776 {
777 auto& blockAllInfo = m_blockAllInfo[static_cast<std::size_t>(addrType)];
778 auto infoIt = blockAllInfo.find(reason);
779
780 if (infoIt == blockAllInfo.end())
781 {
782 continue; // all queues were not blocked for the given reason
783 }
784 std::erase_if(infoIt->second,
785 [&](uint8_t id) { return linkIds.empty() || linkIds.contains(id); });
786
787 if (infoIt->second.empty())
788 {
789 // no more links blocked for the given reason
790 blockAllInfo.erase(infoIt);
791 }
792 }
793}
794
795template <class Priority, class Compare>
796bool
798 uint8_t linkId,
799 WifiRcvAddr addrType,
801{
802 const auto rcvAddrTypes =
803 (addrType == WifiRcvAddr::COUNT
805 : std::set{addrType});
806
807 return std::all_of(
808 rcvAddrTypes.cbegin(),
809 rcvAddrTypes.cend(),
810 // lambda returning whether all the container queues of the given receiver address type are
811 // blocked for the given reason (or for any reason)
812 [=, this](const auto rcvAddrType) {
813 for (const auto& [r, linkIds] : m_blockAllInfo[static_cast<std::size_t>(rcvAddrType)])
814 {
815 if ((reason == WifiQueueBlockedReason::REASONS_COUNT || reason == r) &&
816 linkIds.contains(linkId))
817 {
818 return true;
819 }
820 }
821 return false;
822 });
823}
824
825template <class Priority, class Compare>
826std::optional<WifiMacQueueScheduler::Mask>
828 const WifiContainerQueueId& queueId,
829 uint8_t linkId)
830{
831 NS_LOG_FUNCTION(this << ac << linkId);
832
833 const auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
834
835 if (queueInfoIt == m_perAcInfo[ac].queueInfoMap.cend())
836 {
837 // the given container queue does not exist
838 return std::nullopt;
839 }
840
841 const auto& linkIds = queueInfoIt->second.linkIds;
842 if (const auto linkIt = linkIds.find(linkId); linkIt != linkIds.cend())
843 {
844 return linkIt->second;
845 }
846
847 return std::nullopt;
848}
849
850template <class Priority, class Compare>
851std::optional<WifiContainerQueueId>
853 std::optional<uint8_t> linkId,
854 bool skipBlockedQueues)
855{
856 NS_LOG_FUNCTION(this << ac << linkId.has_value() << skipBlockedQueues);
857 return DoGetNext(ac, linkId, m_perAcInfo[ac].sortedQueues.begin(), skipBlockedQueues);
858}
859
860template <class Priority, class Compare>
861std::optional<WifiContainerQueueId>
863 std::optional<uint8_t> linkId,
864 const WifiContainerQueueId& prevQueueId,
865 bool skipBlockedQueues)
866{
867 NS_LOG_FUNCTION(this << ac << linkId.has_value() << skipBlockedQueues);
868
869 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(prevQueueId);
870 NS_ABORT_IF(queueInfoIt == m_perAcInfo[ac].queueInfoMap.end() ||
871 !queueInfoIt->second.priorityIt.has_value());
872
873 auto sortedQueuesIt = queueInfoIt->second.priorityIt.value();
874 NS_ABORT_IF(sortedQueuesIt == m_perAcInfo[ac].sortedQueues.end());
875
876 return DoGetNext(ac, linkId, ++sortedQueuesIt, skipBlockedQueues);
877}
878
879template <class Priority, class Compare>
880std::optional<WifiContainerQueueId>
882 AcIndex ac,
883 std::optional<uint8_t> linkId,
884 typename SortedQueues::iterator sortedQueuesIt,
885 bool skipBlockedQueues)
886{
887 NS_LOG_FUNCTION(this << ac << linkId.has_value() << skipBlockedQueues);
888 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
889
890 while (sortedQueuesIt != m_perAcInfo[ac].sortedQueues.end())
891 {
892 const auto& queueInfoPair = sortedQueuesIt->second.get();
893 const auto& linkIds = queueInfoPair.second.linkIds;
894 typename std::decay_t<decltype(linkIds)>::const_iterator linkIt;
895
896 if (!skipBlockedQueues ||
897 std::any_of(linkIds.cbegin(), linkIds.cend(), [&linkId](const auto& linkIdMask) {
898 return (!linkId.has_value() || linkId == linkIdMask.first) &&
899 linkIdMask.second.none();
900 }))
901 {
902 // Remove packets with expired lifetime from this queue.
903 // In case the queue becomes empty, the queue is removed from the sorted
904 // list and sortedQueuesIt is invalidated; thus, store an iterator to the
905 // previous queue in the sorted list (if any) to resume the search afterwards.
906 std::optional<typename SortedQueues::iterator> prevQueueIt;
907 if (sortedQueuesIt != m_perAcInfo[ac].sortedQueues.begin())
908 {
909 prevQueueIt = std::prev(sortedQueuesIt);
910 }
911
912 const auto queueId = queueInfoPair.first;
913 GetWifiMacQueue(ac)->ExtractExpiredMpdus(queueId);
914
915 if (GetWifiMacQueue(ac)->GetNBytes(queueId) == 0)
916 {
917 auto nextQueueIt = (prevQueueIt.has_value() ? std::next(prevQueueIt.value())
918 : m_perAcInfo[ac].sortedQueues.begin());
919 // the container queue may be empty but it may not have been removed yet from the
920 // sorted list. This may happen because the scheduler is notified after that packets
921 // are dequeued and there may be a callback connected to the Dequeue trace source
922 // that calls this function. In such a case, nextQueueIt actually points to the same
923 // queue as sortedQueuesIt. The iterator is advanced to avoid an infinite loop.
924 if (nextQueueIt != m_perAcInfo[ac].sortedQueues.end() &&
925 nextQueueIt->second.get().first == queueId)
926 {
927 sortedQueuesIt = std::next(nextQueueIt);
928 }
929 else
930 {
931 sortedQueuesIt = nextQueueIt;
932 }
933 continue;
934 }
935 return queueInfoPair.first;
936 }
937
938 sortedQueuesIt++;
939 }
940 return {};
941}
942
943template <class Priority, class Compare>
946{
947 NS_LOG_FUNCTION(this << ac << *mpdu);
948 auto queue = GetWifiMacQueue(ac);
949 if (queue->QueueBase::GetNPackets() < queue->GetMaxSize().GetValue())
950 {
951 // the queue is not full, do not drop anything
952 return nullptr;
953 }
954
955 // Control and management frames should be prioritized
956 if (m_dropPolicy == DROP_OLDEST || mpdu->GetHeader().IsCtl() || mpdu->GetHeader().IsMgt())
957 {
958 for (const auto& [priority, queueInfo] : GetSortedQueues(ac))
959 {
960 if (queueInfo.get().first.type == WIFI_MGT_QUEUE ||
961 queueInfo.get().first.type == WIFI_CTL_QUEUE)
962 {
963 // do not drop control or management frames
964 continue;
965 }
966
967 // do not drop frames that are inflight or to be retransmitted
968 Ptr<WifiMpdu> item;
969 while ((item = queue->PeekByQueueId(queueInfo.get().first, item)))
970 {
971 if (!item->IsInFlight() && !item->GetHeader().IsRetry())
972 {
973 NS_LOG_DEBUG("Dropping " << *item);
974 return item;
975 }
976 }
977 }
978 }
979 NS_LOG_DEBUG("Dropping received MPDU: " << *mpdu);
980 return mpdu;
981}
982
983template <class Priority, class Compare>
984void
986{
987 NS_LOG_FUNCTION(this << ac << *mpdu);
988 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
989
990 // add information for the queue storing the MPDU to the queue info map, if not present yet
991 auto queueInfoIt = InitQueueInfo(ac, mpdu);
992
993 DoNotifyEnqueue(ac, mpdu);
994
995 if (!queueInfoIt->second.priorityIt.has_value())
996 {
998 "No info for the queue the MPDU was stored into (forgot to call SetPriority()?)");
999 }
1000}
1001
1002template <class Priority, class Compare>
1003void
1005 const std::list<Ptr<WifiMpdu>>& mpdus)
1006{
1007 NS_LOG_FUNCTION(this << ac);
1008 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
1009
1010 DoNotifyDequeue(ac, mpdus);
1011
1012 std::list<WifiContainerQueueId> queueIds;
1013
1014 for (const auto& mpdu : mpdus)
1015 {
1016 queueIds.push_back(WifiMacQueueContainer::GetQueueId(mpdu));
1017 }
1018
1019 for (const auto& queueId : queueIds)
1020 {
1021 if (GetWifiMacQueue(ac)->GetNBytes(queueId) == 0)
1022 {
1023 // The queue has now become empty and needs to be removed from the sorted
1024 // list kept by the scheduler
1025 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
1026 NS_ASSERT(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end());
1027 if (queueInfoIt->second.priorityIt.has_value())
1028 {
1029 m_perAcInfo[ac].sortedQueues.erase(queueInfoIt->second.priorityIt.value());
1030 queueInfoIt->second.priorityIt.reset();
1031 }
1032 }
1033 }
1034}
1035
1036template <class Priority, class Compare>
1037void
1039 const std::list<Ptr<WifiMpdu>>& mpdus)
1040{
1041 NS_LOG_FUNCTION(this << ac);
1042 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
1043
1044 DoNotifyRemove(ac, mpdus);
1045
1046 std::list<WifiContainerQueueId> queueIds;
1047
1048 for (const auto& mpdu : mpdus)
1049 {
1050 queueIds.push_back(WifiMacQueueContainer::GetQueueId(mpdu));
1051 }
1052
1053 for (const auto& queueId : queueIds)
1054 {
1055 if (GetWifiMacQueue(ac)->GetNBytes(queueId) == 0)
1056 {
1057 // The queue has now become empty and needs to be removed from the sorted
1058 // list kept by the scheduler
1059 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
1060 NS_ASSERT(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end());
1061 if (queueInfoIt->second.priorityIt.has_value())
1062 {
1063 m_perAcInfo[ac].sortedQueues.erase(queueInfoIt->second.priorityIt.value());
1064 queueInfoIt->second.priorityIt.reset();
1065 }
1066 }
1067 }
1068}
1069
1070} // namespace ns3
1071
1072#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.
Hold variables of type enum.
Definition enum.h:52
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.
virtual void SetWifiMacQueue(AcIndex ac, Ptr< WifiMacQueue > queue)
Set the Wifi MAC queue associated with the given Access Category.
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.
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
DropPolicy m_dropPolicy
Drop behavior of queue.
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...
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 ...
Ptr< WifiMpdu > HasToDropBeforeEnqueue(AcIndex ac, Ptr< WifiMpdu > mpdu) override
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.
void NotifyRemove(AcIndex ac, const std::list< Ptr< WifiMpdu > > &mpdus) final
void SetWifiMac(Ptr< WifiMac > mac) override
Set the wifi MAC.
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...
void SetWifiMacQueue(AcIndex ac, Ptr< WifiMacQueue > queue) override
Set the Wifi MAC queue associated with the given Access Category.
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 WifiSchedPrecedence< Time > &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_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#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:492
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.
std::string GetTemplateClassName()
Helper function to get the name (as a string) of the type of a template class.
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition enum.h:181
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
@ LOG_FUNCTION
Function tracing for non-trivial function calls.
Definition log.h:98
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Definition enum.h:223
STL namespace.
#define list
Structure identifying a container queue.
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
Definition of priority for container queues that can be specialized by subclasses by providing the ty...
std::weak_ordering operator<=>(const WifiSchedPrecedence< Prio > &other) const
Spaceship comparison operator.
bool operator==(const WifiSchedPrecedence< Prio > &) const =default
Equality operator, needed because equality testing never invokes the spaceship operator and the space...