20#ifndef WIFI_MAC_QUEUE_SCHEDULER_IMPL_H
21#define WIFI_MAC_QUEUE_SCHEDULER_IMPL_H
31#include <unordered_map>
49template <
class Priority,
class Compare = std::less<Priority>>
54 friend class ::WifiMacQueueDropOldestTest;
70 std::optional<WifiContainerQueueId>
GetNext(
AcIndex ac, uint8_t linkId)
final;
80 const std::list<WifiContainerQueueType>& types,
83 const std::set<uint8_t>& tids,
84 const std::set<uint8_t>& linkIds)
final;
88 const std::list<WifiContainerQueueType>& types,
91 const std::set<uint8_t>& tids,
92 const std::set<uint8_t>& linkIds)
final;
96 uint8_t linkId)
final;
127 using QueueInfoMap = std::unordered_map<WifiContainerQueueId, QueueInfo>;
141 using SortedQueues = std::multimap<Priority, std::reference_wrapper<QueueInfoPair>, Compare>;
148 std::optional<typename SortedQueues::iterator>
211 typename SortedQueues::iterator sortedQueuesIt);
266 const std::list<WifiContainerQueueType>& types,
269 const std::set<uint8_t>& tids,
270 const std::set<uint8_t>& linkIds);
280template <
class Priority,
class Compare>
286template <
class Priority,
class Compare>
290 static TypeId tid =
TypeId(
"ns3::WifiMacQueueSchedulerImpl")
292 .SetGroupName(
"Wifi");
296template <
class Priority,
class Compare>
304template <
class Priority,
class Compare>
310 if (
auto queue = mac->GetTxopQueue(ac); queue !=
nullptr)
312 m_perAcInfo.at(ac).wifiMacQueue = queue;
313 queue->SetScheduler(
this);
319template <
class Priority,
class Compare>
324 return m_perAcInfo.at(ac).wifiMacQueue;
327template <
class Priority,
class Compare>
332 return m_perAcInfo.at(ac).sortedQueues;
335template <
class Priority,
class Compare>
343 auto [queueInfoIt, ret] = m_perAcInfo[ac].queueInfoMap.insert({queueId,
QueueInfo()});
346 if (GetMac() && GetMac()->GetNLinks() > 1 &&
347 mpdu->GetHeader().GetAddr2() == GetMac()->GetAddress())
351 const auto rxAddr = mpdu->GetHeader().GetAddr1();
355 NS_ASSERT_MSG(rxAddr.IsGroup() || GetMac()->GetMldAddress(rxAddr),
356 "Address 1 (" << rxAddr <<
") is not an MLD address");
360 NS_ASSERT_MSG(GetMac()->CanForwardPacketsTo(rxAddr),
"Cannot forward frame to " << rxAddr);
364 for (uint8_t linkId = 0; linkId < GetMac()->GetNLinks(); linkId++)
366 if (rxAddr.IsGroup() ||
367 GetMac()->GetWifiRemoteStationManager(linkId)->GetAffiliatedStaAddress(rxAddr))
370 queueInfoIt->second.linkIds.emplace(linkId,
Mask{});
375 queueInfoIt->second.linkIds.erase(linkId);
383 auto linkId = GetMac() ? GetMac()->GetLinkIdByAddress(mpdu->GetHeader().GetAddr2())
386 auto& linkIdsMap = queueInfoIt->second.linkIds;
388 "At most one link can be associated with this container queue");
392 if (linkIdsMap.empty() || linkIdsMap.cbegin()->first != *linkId)
394 linkIdsMap = {{*linkId,
Mask{}}};
401template <
class Priority,
class Compare>
405 const Priority& priority)
411 "Cannot set the priority of an empty queue");
413 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
414 NS_ASSERT_MSG(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end(),
415 "No queue info for the given container queue");
416 typename SortedQueues::iterator sortedQueuesIt;
418 if (queueInfoIt->second.priorityIt.has_value())
423 if (queueInfoIt->second.priorityIt.value()->first == priority)
428 auto handle = m_perAcInfo[ac].sortedQueues.extract(queueInfoIt->second.priorityIt.value());
429 handle.key() = priority;
430 sortedQueuesIt = m_perAcInfo[ac].sortedQueues.insert(std::move(handle));
435 sortedQueuesIt = m_perAcInfo[ac].sortedQueues.insert({priority, std::ref(*queueInfoIt)});
438 queueInfoIt->second.priorityIt = sortedQueuesIt;
441template <
class Priority,
class Compare>
445 auto queueInfoIt = InitQueueInfo(ac, mpdu);
446 std::list<uint8_t> linkIds;
449 for (
const auto [linkId, mask] : queueInfoIt->second.linkIds)
453 linkIds.emplace_back(linkId);
460template <
class Priority,
class Compare>
466 const std::list<WifiContainerQueueType>& types,
469 const std::set<uint8_t>& tids,
470 const std::set<uint8_t>& linkIds)
472 NS_LOG_FUNCTION(
this << block << reason << ac << rxAddress << txAddress);
473 std::list<WifiMacHeader> headers;
475 for (
const auto queueType : types)
487 "TID must be specified for queues containing QoS data frames");
488 for (
const auto tid : tids)
491 headers.back().SetQosTid(tid);
499 for (
auto& hdr : headers)
501 hdr.SetAddr1(rxAddress);
502 hdr.SetAddr2(txAddress);
504 auto queueInfoIt = InitQueueInfo(ac, Create<WifiMpdu>(Create<Packet>(), hdr));
505 for (
auto& [linkId, mask] : queueInfoIt->second.linkIds)
507 if (linkIds.empty() || linkIds.count(linkId) > 0)
509 mask.set(
static_cast<std::size_t
>(reason), block);
515template <
class Priority,
class Compare>
520 const std::list<WifiContainerQueueType>& types,
523 const std::set<uint8_t>& tids,
524 const std::set<uint8_t>& linkIds)
526 DoBlockQueues(
true, reason, ac, types, rxAddress, txAddress, tids, linkIds);
529template <
class Priority,
class Compare>
534 const std::list<WifiContainerQueueType>& types,
537 const std::set<uint8_t>& tids,
538 const std::set<uint8_t>& linkIds)
540 DoBlockQueues(
false, reason, ac, types, rxAddress, txAddress, tids, linkIds);
543template <
class Priority,
class Compare>
544std::optional<WifiMacQueueScheduler::Mask>
551 const auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
553 if (queueInfoIt == m_perAcInfo[ac].queueInfoMap.cend())
559 const auto& linkIds = queueInfoIt->second.linkIds;
560 if (
const auto linkIt = linkIds.find(linkId); linkIt != linkIds.cend())
562 return linkIt->second;
568template <
class Priority,
class Compare>
569std::optional<WifiContainerQueueId>
573 return DoGetNext(ac, linkId, m_perAcInfo[ac].sortedQueues.begin());
576template <
class Priority,
class Compare>
577std::optional<WifiContainerQueueId>
584 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(prevQueueId);
585 NS_ABORT_IF(queueInfoIt == m_perAcInfo[ac].queueInfoMap.end() ||
586 !queueInfoIt->second.priorityIt.has_value());
588 auto sortedQueuesIt = queueInfoIt->second.priorityIt.value();
589 NS_ABORT_IF(sortedQueuesIt == m_perAcInfo[ac].sortedQueues.end());
591 return DoGetNext(ac, linkId, ++sortedQueuesIt);
594template <
class Priority,
class Compare>
595std::optional<WifiContainerQueueId>
599 typename SortedQueues::iterator sortedQueuesIt)
604 while (sortedQueuesIt != m_perAcInfo[ac].sortedQueues.end())
606 const auto& queueInfoPair = sortedQueuesIt->second.get();
607 const auto& linkIds = queueInfoPair.second.linkIds;
609 if (
const auto linkIt = linkIds.find(linkId);
610 linkIt != linkIds.cend() && linkIt->second.none())
617 std::optional<typename SortedQueues::iterator> prevQueueIt;
618 if (sortedQueuesIt != m_perAcInfo[ac].sortedQueues.begin())
620 prevQueueIt = std::prev(sortedQueuesIt);
623 GetWifiMacQueue(ac)->ExtractExpiredMpdus(queueInfoPair.first);
625 if (GetWifiMacQueue(ac)->GetNBytes(queueInfoPair.first) == 0)
627 sortedQueuesIt = (prevQueueIt.has_value() ? std::next(prevQueueIt.value())
628 : m_perAcInfo[ac].sortedQueues.begin());
637 std::optional<WifiContainerQueueId> queueId;
639 if (sortedQueuesIt != m_perAcInfo[ac].sortedQueues.end())
641 queueId = sortedQueuesIt->second.get().first;
646template <
class Priority,
class Compare>
651 return HasToDropBeforeEnqueuePriv(ac, mpdu);
654template <
class Priority,
class Compare>
662 auto queueInfoIt = InitQueueInfo(ac, mpdu);
664 DoNotifyEnqueue(ac, mpdu);
666 if (!queueInfoIt->second.priorityIt.has_value())
669 "No info for the queue the MPDU was stored into (forgot to call SetPriority()?)");
673template <
class Priority,
class Compare>
681 DoNotifyDequeue(ac, mpdus);
683 std::list<WifiContainerQueueId> queueIds;
685 for (
const auto& mpdu : mpdus)
690 for (
const auto& queueId : queueIds)
692 if (GetWifiMacQueue(ac)->GetNBytes(queueId) == 0)
696 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
697 NS_ASSERT(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end());
698 if (queueInfoIt->second.priorityIt.has_value())
700 m_perAcInfo[ac].sortedQueues.erase(queueInfoIt->second.priorityIt.value());
701 queueInfoIt->second.priorityIt.reset();
707template <
class Priority,
class Compare>
715 DoNotifyRemove(ac, mpdus);
717 std::list<WifiContainerQueueId> queueIds;
719 for (
const auto& mpdu : mpdus)
724 for (
const auto& queueId : queueIds)
726 if (GetWifiMacQueue(ac)->GetNBytes(queueId) == 0)
730 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
731 NS_ASSERT(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end());
732 if (queueInfoIt->second.priorityIt.has_value())
734 m_perAcInfo[ac].sortedQueues.erase(queueInfoIt->second.priorityIt.value());
735 queueInfoIt->second.priorityIt.reset();
Test DROP_OLDEST setting.
Smart pointer class similar to boost::intrusive_ptr.
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
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.
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.
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.
WifiMacQueueSchedulerImpl is a template class enabling the definition of different types of priority ...
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 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
Unblock the given set of links for the container queues of the given types and Access Category that h...
std::pair< const WifiContainerQueueId, QueueInfo > QueueInfoPair
typedef for a QueueInfoMap element
NS_LOG_TEMPLATE_DECLARE
the log component
std::optional< Mask > GetQueueLinkMask(AcIndex ac, const WifiContainerQueueId &queueId, uint8_t linkId) final
Get the mask associated with the given container queue indicating whether the given link is blocked a...
void SetWifiMac(Ptr< WifiMac > mac) final
Set the wifi MAC.
void DoDispose() override
Destructor implementation.
void NotifyDequeue(AcIndex ac, const std::list< Ptr< WifiMpdu > > &mpdus) final
Notify the scheduler that the given list of MPDUs have been dequeued by the given Access Category.
std::unordered_map< WifiContainerQueueId, QueueInfo > QueueInfoMap
Map identifiers (QueueIds) to information associated with container queues.
std::optional< WifiContainerQueueId > GetNext(AcIndex ac, uint8_t linkId, const WifiContainerQueueId &prevQueueId) final
Get the next queue to serve after the given one.
void NotifyEnqueue(AcIndex ac, Ptr< WifiMpdu > mpdu) final
Notify the scheduler that the given MPDU has been enqueued by the given Access Category.
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
Block the given set of links for the container queues of the given types and Access Category that hol...
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::list< uint8_t > GetLinkIds(AcIndex ac, Ptr< const WifiMpdu > mpdu) final
Get the list of the IDs of the links the given MPDU (belonging to the given Access Category) can be s...
static TypeId GetTypeId()
Get the type ID.
std::optional< WifiContainerQueueId > DoGetNext(AcIndex ac, uint8_t linkId, typename SortedQueues::iterator sortedQueuesIt)
Get the next queue to serve.
std::vector< PerAcInfo > m_perAcInfo
vector of per-AC information
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
Check whether an MPDU has to be dropped before enqueuing the given MPDU.
void NotifyRemove(AcIndex ac, const std::list< Ptr< WifiMpdu > > &mpdus) final
Notify the scheduler that the given list of MPDUs have been removed by the given Access Category.
virtual Ptr< WifiMpdu > HasToDropBeforeEnqueuePriv(AcIndex ac, Ptr< WifiMpdu > mpdu)=0
Check whether an MPDU has to be dropped before enqueuing the given MPDU.
WifiMacQueueSchedulerImpl()
Constructor.
std::optional< WifiContainerQueueId > GetNext(AcIndex ac, uint8_t linkId) final
Get the next queue to serve, which is guaranteed to contain at least an MPDU whose lifetime has not e...
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 Priority &priority)
Set the priority for the given container queue belonging to the given Access Category.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
#define NS_LOG_TEMPLATE_DEFINE(name)
Initialize a reference to a Log component.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
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 ...
@ AC_UNDEF
Total number of ACs.
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.
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...
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