9#ifndef WIFI_MAC_QUEUE_SCHEDULER_IMPL_H 
   10#define WIFI_MAC_QUEUE_SCHEDULER_IMPL_H 
   23#include <unordered_map> 
   41template <
class Priority, 
class Compare = std::less<Priority>>
 
   46    friend class ::WifiMacQueueDropOldestTest;
 
   62    std::optional<WifiContainerQueueId> 
GetNext(
AcIndex ac, std::optional<uint8_t> linkId) 
final;
 
   68                                                std::optional<uint8_t> linkId,
 
   73                                  const std::list<WifiQueueBlockedReason>& ignoredReasons) 
final;
 
   77                     const std::list<WifiContainerQueueType>& types,
 
   80                     const std::set<uint8_t>& tids,
 
   81                     const std::set<uint8_t>& linkIds) 
final;
 
   85                       const std::list<WifiContainerQueueType>& types,
 
   88                       const std::set<uint8_t>& tids,
 
   89                       const std::set<uint8_t>& linkIds) 
final;
 
   99                                         uint8_t linkId) 
final;
 
  130    using QueueInfoMap = std::unordered_map<WifiContainerQueueId, QueueInfo>;
 
  144    using SortedQueues = std::multimap<Priority, std::reference_wrapper<QueueInfoPair>, Compare>;
 
  151        std::optional<typename SortedQueues::iterator>
 
 
  214                                                  std::optional<uint8_t> linkId,
 
  215                                                  typename SortedQueues::iterator sortedQueuesIt);
 
  270                       const std::list<WifiContainerQueueType>& types,
 
  273                       const std::set<uint8_t>& tids,
 
  274                       const std::set<uint8_t>& linkIds);
 
  285                          const std::set<uint8_t>& linkIds);
 
  302template <
class Priority, 
class Compare>
 
  308template <
class Priority, 
class Compare>
 
  312    static TypeId tid = 
TypeId(
"ns3::WifiMacQueueSchedulerImpl")
 
  314                            .SetGroupName(
"Wifi");
 
 
  318template <
class Priority, 
class Compare>
 
  326template <
class Priority, 
class Compare>
 
  332        if (
auto queue = mac->GetTxopQueue(ac); queue != 
nullptr)
 
  334            m_perAcInfo.at(ac).wifiMacQueue = queue;
 
  335            queue->SetScheduler(
this);
 
 
  341template <
class Priority, 
class Compare>
 
  346    return m_perAcInfo.at(ac).wifiMacQueue;
 
 
  349template <
class Priority, 
class Compare>
 
  354    return m_perAcInfo.at(ac).sortedQueues;
 
 
  357template <
class Priority, 
class Compare>
 
  358typename WifiMacQueueSchedulerImpl<Priority, Compare>::QueueInfoMap::iterator
 
  365    auto [queueInfoIt, ret] = m_perAcInfo[ac].queueInfoMap.insert({queueId, 
QueueInfo()});
 
  368    if (GetMac() && GetMac()->GetNLinks() > 1 &&
 
  369        mpdu->GetHeader().GetAddr2() == GetMac()->GetAddress())
 
  373        const auto rxAddr = mpdu->GetHeader().GetAddr1();
 
  377        NS_ASSERT_MSG(rxAddr.IsGroup() || GetMac()->GetMldAddress(rxAddr) == rxAddr,
 
  378                      "Address 1 (" << rxAddr << 
") is not an MLD address");
 
  383                      "Cannot forward frame to " << rxAddr
 
  384                                                 << 
"; check that the receiver is associated");
 
  387        for (
const auto linkId : GetMac()->GetLinkIds())
 
  389            if (rxAddr.IsGroup() ||
 
  390                GetMac()->GetWifiRemoteStationManager(linkId)->GetAffiliatedStaAddress(rxAddr))
 
  393                auto [it, inserted] = queueInfoIt->second.linkIds.try_emplace(linkId);
 
  398                    for (
const auto& [reason, linkIds] : m_blockAllInfo)
 
  400                        if (linkIds.contains(linkId))
 
  402                            it->second.set(
static_cast<std::size_t
>(reason), 
true);
 
  410                queueInfoIt->second.linkIds.erase(linkId);
 
  418        auto linkId = GetMac() ? GetMac()->GetLinkIdByAddress(mpdu->GetHeader().GetAddr2())
 
  421        auto& linkIdsMap = queueInfoIt->second.linkIds;
 
  423                      "At most one link can be associated with this container queue");
 
  427        if (linkIdsMap.empty() || linkIdsMap.cbegin()->first != *linkId)
 
  430            for (
const auto& [reason, linkIds] : m_blockAllInfo)
 
  432                if (linkIds.contains(*linkId))
 
  434                    mask.set(
static_cast<std::size_t
>(reason), 
true);
 
  438            linkIdsMap = {{*linkId, mask}};
 
 
  445template <
class Priority, 
class Compare>
 
  449                                                          const Priority& priority)
 
  455                    "Cannot set the priority of an empty queue");
 
  457    auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
 
  458    NS_ASSERT_MSG(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end(),
 
  459                  "No queue info for the given container queue");
 
  460    typename SortedQueues::iterator sortedQueuesIt;
 
  462    if (queueInfoIt->second.priorityIt.has_value())
 
  467        if (queueInfoIt->second.priorityIt.value()->first == priority)
 
  472        auto handle = m_perAcInfo[ac].sortedQueues.extract(queueInfoIt->second.priorityIt.value());
 
  473        handle.key() = priority;
 
  474        sortedQueuesIt = m_perAcInfo[ac].sortedQueues.insert(std::move(handle));
 
  479        sortedQueuesIt = m_perAcInfo[ac].sortedQueues.insert({priority, std::ref(*queueInfoIt)});
 
  482    queueInfoIt->second.priorityIt = sortedQueuesIt;
 
 
  485template <
class Priority, 
class Compare>
 
  490    const std::list<WifiQueueBlockedReason>& ignoredReasons)
 
  492    auto queueInfoIt = InitQueueInfo(ac, mpdu);
 
  493    std::list<uint8_t> linkIds;
 
  496    for (
auto [linkId, mask] : queueInfoIt->second.linkIds)
 
  499        for (
const auto reason : ignoredReasons)
 
  501            mask.reset(
static_cast<std::size_t
>(reason));
 
  506            linkIds.emplace_back(linkId);
 
 
  513template <
class Priority, 
class Compare>
 
  519    const std::list<WifiContainerQueueType>& types,
 
  522    const std::set<uint8_t>& tids,
 
  523    const std::set<uint8_t>& linkIds)
 
  525    std::stringstream ss;
 
  528        std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, 
" "));
 
  530    NS_LOG_FUNCTION(
this << block << reason << ac << rxAddress << txAddress << ss.str());
 
  531    std::list<WifiMacHeader> headers;
 
  533    for (
const auto queueType : types)
 
  545                          "TID must be specified for queues containing QoS data frames");
 
  546            for (
const auto tid : tids)
 
  549                headers.back().SetQosTid(tid);
 
  557    for (
auto& hdr : headers)
 
  559        hdr.SetAddr1(rxAddress);
 
  560        hdr.SetAddr2(txAddress);
 
  563        for (
auto& [linkId, mask] : queueInfoIt->second.linkIds)
 
  565            if (linkIds.empty() || linkIds.contains(linkId))
 
  567                mask.set(
static_cast<std::size_t
>(reason), block);
 
 
  573template <
class Priority, 
class Compare>
 
  578    const std::list<WifiContainerQueueType>& types,
 
  581    const std::set<uint8_t>& tids,
 
  582    const std::set<uint8_t>& linkIds)
 
  584    DoBlockQueues(
true, reason, ac, types, rxAddress, txAddress, tids, linkIds);
 
 
  587template <
class Priority, 
class Compare>
 
  592    const std::list<WifiContainerQueueType>& types,
 
  595    const std::set<uint8_t>& tids,
 
  596    const std::set<uint8_t>& linkIds)
 
  598    DoBlockQueues(
false, reason, ac, types, rxAddress, txAddress, tids, linkIds);
 
 
  601template <
class Priority, 
class Compare>
 
  605                                                               const std::set<uint8_t>& linkIds)
 
  607    for (
auto& perAcInfo : m_perAcInfo)
 
  609        for (
auto& [queueId, queueInfo] : perAcInfo.queueInfoMap)
 
  611            for (
auto& [linkId, mask] : queueInfo.linkIds)
 
  613                if (linkIds.empty() || linkIds.contains(linkId))
 
  615                    mask.set(
static_cast<std::size_t
>(reason), block);
 
 
 
  622template <
class Priority, 
class Compare>
 
  625                                                             const std::set<uint8_t>& linkIds)
 
  627    DoBlockAllQueues(
true, reason, linkIds);
 
  631        m_blockAllInfo[reason] = GetMac()->GetLinkIds(); 
 
  635        m_blockAllInfo[reason].merge(std::set<uint8_t>{linkIds});
 
 
  639template <
class Priority, 
class Compare>
 
  642                                                               const std::set<uint8_t>& linkIds)
 
  644    DoBlockAllQueues(
false, reason, linkIds);
 
  646    auto infoIt = m_blockAllInfo.find(reason);
 
  648    if (infoIt == m_blockAllInfo.end())
 
  652    std::erase_if(infoIt->second,
 
  653                  [&](uint8_t 
id) { return linkIds.empty() || linkIds.contains(id); });
 
  655    if (infoIt->second.empty())
 
  658        m_blockAllInfo.erase(infoIt);
 
 
  662template <
class Priority, 
class Compare>
 
  668    for (
const auto& [r, linkIds] : m_blockAllInfo)
 
  671            linkIds.contains(linkId))
 
 
  679template <
class Priority, 
class Compare>
 
  680std::optional<WifiMacQueueScheduler::Mask>
 
  687    const auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
 
  689    if (queueInfoIt == m_perAcInfo[ac].queueInfoMap.cend())
 
  695    const auto& linkIds = queueInfoIt->second.linkIds;
 
  696    if (
const auto linkIt = linkIds.find(linkId); linkIt != linkIds.cend())
 
  698        return linkIt->second;
 
 
  704template <
class Priority, 
class Compare>
 
  705std::optional<WifiContainerQueueId>
 
  709    return DoGetNext(ac, linkId, m_perAcInfo[ac].sortedQueues.begin());
 
 
  712template <
class Priority, 
class Compare>
 
  713std::optional<WifiContainerQueueId>
 
  715                                                      std::optional<uint8_t> linkId,
 
  720    auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(prevQueueId);
 
  721    NS_ABORT_IF(queueInfoIt == m_perAcInfo[ac].queueInfoMap.end() ||
 
  722                !queueInfoIt->second.priorityIt.has_value());
 
  724    auto sortedQueuesIt = queueInfoIt->second.priorityIt.value();
 
  725    NS_ABORT_IF(sortedQueuesIt == m_perAcInfo[ac].sortedQueues.end());
 
  727    return DoGetNext(ac, linkId, ++sortedQueuesIt);
 
 
  730template <
class Priority, 
class Compare>
 
  731std::optional<WifiContainerQueueId>
 
  734    std::optional<uint8_t> linkId,
 
  735    typename SortedQueues::iterator sortedQueuesIt)
 
  740    while (sortedQueuesIt != m_perAcInfo[ac].sortedQueues.end())
 
  742        const auto& queueInfoPair = sortedQueuesIt->second.get();
 
  743        const auto& linkIds = queueInfoPair.second.linkIds;
 
  744        typename std::decay_t<
decltype(linkIds)>::const_iterator linkIt;
 
  746        if (!linkId.has_value() ||
 
  747            ((linkIt = linkIds.find(*linkId)) != linkIds.cend() && linkIt->second.none()))
 
  754            std::optional<typename SortedQueues::iterator> prevQueueIt;
 
  755            if (sortedQueuesIt != m_perAcInfo[ac].sortedQueues.begin())
 
  757                prevQueueIt = std::prev(sortedQueuesIt);
 
  760            const auto queueId = queueInfoPair.first;
 
  761            GetWifiMacQueue(ac)->ExtractExpiredMpdus(queueId);
 
  763            if (GetWifiMacQueue(ac)->GetNBytes(queueId) == 0)
 
  765                auto nextQueueIt = (prevQueueIt.has_value() ? std::next(prevQueueIt.value())
 
  766                                                            : m_perAcInfo[ac].sortedQueues.begin());
 
  772                if (nextQueueIt != m_perAcInfo[ac].sortedQueues.end() &&
 
  773                    nextQueueIt->second.get().first == queueId)
 
  775                    sortedQueuesIt = std::next(nextQueueIt);
 
  779                    sortedQueuesIt = nextQueueIt;
 
  783            return queueInfoPair.first;
 
 
  791template <
class Priority, 
class Compare>
 
  796    return HasToDropBeforeEnqueuePriv(ac, mpdu);
 
 
  799template <
class Priority, 
class Compare>
 
  807    auto queueInfoIt = InitQueueInfo(ac, mpdu);
 
  809    DoNotifyEnqueue(ac, mpdu);
 
  811    if (!queueInfoIt->second.priorityIt.has_value())
 
  814            "No info for the queue the MPDU was stored into (forgot to call SetPriority()?)");
 
 
  818template <
class Priority, 
class Compare>
 
  826    DoNotifyDequeue(ac, mpdus);
 
  828    std::list<WifiContainerQueueId> queueIds;
 
  830    for (
const auto& mpdu : mpdus)
 
  835    for (
const auto& queueId : queueIds)
 
  837        if (GetWifiMacQueue(ac)->GetNBytes(queueId) == 0)
 
  841            auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
 
  842            NS_ASSERT(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end());
 
  843            if (queueInfoIt->second.priorityIt.has_value())
 
  845                m_perAcInfo[ac].sortedQueues.erase(queueInfoIt->second.priorityIt.value());
 
  846                queueInfoIt->second.priorityIt.reset();
 
 
  852template <
class Priority, 
class Compare>
 
  860    DoNotifyRemove(ac, mpdus);
 
  862    std::list<WifiContainerQueueId> queueIds;
 
  864    for (
const auto& mpdu : mpdus)
 
  869    for (
const auto& queueId : queueIds)
 
  871        if (GetWifiMacQueue(ac)->GetNBytes(queueId) == 0)
 
  875            auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
 
  876            NS_ASSERT(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end());
 
  877            if (queueInfoIt->second.priorityIt.has_value())
 
  879                m_perAcInfo[ac].sortedQueues.erase(queueInfoIt->second.priorityIt.value());
 
  880                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.
void UnblockAllQueues(WifiQueueBlockedReason reason, const std::set< uint8_t > &linkIds) final
Unblock the given set of links for all the container queues for the given reason.
std::unordered_map< WifiContainerQueueId, QueueInfo > QueueInfoMap
Map identifiers (QueueIds) to information associated with container queues.
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.
static TypeId GetTypeId()
Get the type ID.
void DoBlockAllQueues(bool block, WifiQueueBlockedReason reason, const std::set< uint8_t > &linkIds)
Block or unblock the given set of links for all the container queues for the given reason.
std::vector< PerAcInfo > m_perAcInfo
vector of per-AC information
bool GetAllQueuesBlockedOnLink(uint8_t linkId, WifiQueueBlockedReason reason) final
Return whether all the container queues are blocked for the given link for the given reason,...
std::map< WifiQueueBlockedReason, std::set< uint8_t > > m_blockAllInfo
When it is requested to block all the queues, an entry is added to this map to store the reason and t...
std::list< uint8_t > GetLinkIds(AcIndex ac, Ptr< const WifiMpdu > mpdu, const std::list< WifiQueueBlockedReason > &ignoredReasons) final
Get the list of the IDs of the links the given MPDU (belonging to the given Access Category) can be s...
std::optional< WifiContainerQueueId > GetNext(AcIndex ac, std::optional< uint8_t > linkId) final
Get the next queue to serve, which is guaranteed to contain at least an MPDU whose lifetime has not e...
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.
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::optional< WifiContainerQueueId > GetNext(AcIndex ac, std::optional< uint8_t > linkId, const WifiContainerQueueId &prevQueueId) final
Get the next queue to serve after the given one.
std::multimap< Priority, std::reference_wrapper< QueueInfoPair >, Compare > SortedQueues
List of container queues sorted in decreasing order of priority.
void BlockAllQueues(WifiQueueBlockedReason reason, const std::set< uint8_t > &linkIds) final
Block the given set of links for all the container queues for the given reason.
std::optional< WifiContainerQueueId > DoGetNext(AcIndex ac, std::optional< uint8_t > linkId, typename SortedQueues::iterator sortedQueuesIt)
Get the next queue to serve.
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 ",...
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
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...
@ LOG_FUNCTION
Function tracing for non-trivial function calls.
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