wifi: Rework wifi MAC queues

Also, add a First Come First Serve wifi MAC queue scheduler
This commit is contained in:
Stefano Avallone
2022-02-15 23:32:03 +01:00
committed by Stefano Avallone
parent b47a59135d
commit 4e70063f8c
27 changed files with 805 additions and 688 deletions

View File

@@ -20,16 +20,17 @@
*/
#include "mesh-helper.h"
#include "ns3/simulator.h"
#include "ns3/pointer.h"
#include "ns3/mesh-point-device.h"
#include "ns3/wifi-net-device.h"
#include "ns3/minstrel-wifi-manager.h"
#include "ns3/mesh-wifi-interface-mac.h"
#include "ns3/wifi-helper.h"
#include "ns3/fcfs-wifi-queue-scheduler.h"
#include "ns3/frame-exchange-manager.h"
#include "ns3/wifi-default-protection-manager.h"
#include "ns3/mesh-point-device.h"
#include "ns3/mesh-wifi-interface-mac.h"
#include "ns3/minstrel-wifi-manager.h"
#include "ns3/pointer.h"
#include "ns3/simulator.h"
#include "ns3/wifi-default-ack-manager.h"
#include "ns3/wifi-default-protection-manager.h"
#include "ns3/wifi-helper.h"
#include "ns3/wifi-net-device.h"
namespace ns3
{
@@ -127,6 +128,7 @@ MeshHelper::CreateInterface (const WifiPhyHelper &phyHelper, Ptr<Node> node, uin
device->SetRemoteStationManager (manager);
mac->SetAddress (Mac48Address::Allocate ());
device->SetMac (mac);
mac->SetMacQueueScheduler (CreateObject<FcfsWifiQueueScheduler> ());
mac->ConfigureStandard (m_standard);
Ptr<FrameExchangeManager> fem = mac->GetFrameExchangeManager ();
if (fem)

View File

@@ -35,6 +35,8 @@
#include "ns3/channel-access-manager.h"
#include "ns3/mac-tx-middle.h"
#include "ns3/qos-txop.h"
#include "ns3/wifi-mac-queue-scheduler.h"
#include "ns3/wifi-mac-queue.h"
namespace ns3 {
@@ -566,6 +568,7 @@ MeshWifiInterfaceMac::ConfigureContentionWindow (uint32_t cwMin, uint32_t cwMax)
m_txop->SetMinCw (0);
m_txop->SetMaxCw (0);
m_txop->SetAifsn (1);
m_scheduler->SetWifiMac (this);
}
} // namespace ns3

View File

@@ -32,6 +32,7 @@ set(source_files
model/eht/multi-link-element.cc
model/error-rate-model.cc
model/extended-capabilities.cc
model/fcfs-wifi-queue-scheduler.cc
model/frame-capture-model.cc
model/frame-exchange-manager.cc
model/he/constant-obss-pd-algorithm.cc
@@ -177,6 +178,7 @@ set(header_files
model/eht/multi-link-element.h
model/error-rate-model.h
model/extended-capabilities.h
model/fcfs-wifi-queue-scheduler.h
model/frame-capture-model.h
model/frame-exchange-manager.h
model/he/constant-obss-pd-algorithm.h

View File

@@ -20,6 +20,7 @@
#include "ns3/wifi-net-device.h"
#include "wifi-mac-helper.h"
#include "ns3/wifi-mac-queue-scheduler.h"
#include "ns3/frame-exchange-manager.h"
#include "ns3/wifi-protection-manager.h"
#include "ns3/wifi-ack-manager.h"
@@ -35,6 +36,7 @@ WifiMacHelper::WifiMacHelper ()
SetType ("ns3::AdhocWifiMac");
m_assocManager.SetTypeId ("ns3::WifiDefaultAssocManager");
m_queueScheduler.SetTypeId ("ns3::FcfsWifiQueueScheduler");
m_protectionManager.SetTypeId ("ns3::WifiDefaultProtectionManager");
m_ackManager.SetTypeId ("ns3::WifiDefaultAckManager");
}
@@ -61,6 +63,9 @@ WifiMacHelper::Create (Ptr<WifiNetDevice> device, WifiStandard standard) const
device->SetMac (mac);
mac->ConfigureStandard (standard);
Ptr<WifiMacQueueScheduler> queueScheduler = m_queueScheduler.Create<WifiMacQueueScheduler> ();
mac->SetMacQueueScheduler (queueScheduler);
// WaveNetDevice stores PHY entities in a different member than WifiNetDevice, hence
// GetNPhys() would return 0. We have to attach a protection manager and an ack manager
// to the unique instance of frame exchange manager anyway

View File

@@ -78,6 +78,16 @@ public:
template <typename... Args>
void SetAssocManager (std::string type, Args&&... args);
/**
* Helper function used to set the MAC queue scheduler.
*
* \tparam Args \deduced Template type parameter pack for the sequence of name-value pairs.
* \param type the type of MAC queue scheduler
* \param args A sequence of name-value pairs of the attributes to set.
*/
template <typename... Args>
void SetMacQueueScheduler (std::string type, Args&&... args);
/**
* Helper function used to set the Protection Manager.
*
@@ -122,6 +132,7 @@ public:
protected:
ObjectFactory m_mac; ///< MAC object factory
ObjectFactory m_assocManager; ///< Association Manager
ObjectFactory m_queueScheduler; ///< MAC queue scheduler
ObjectFactory m_protectionManager; ///< Factory to create a protection manager
ObjectFactory m_ackManager; ///< Factory to create an acknowledgment manager
ObjectFactory m_muScheduler; ///< Multi-user Scheduler object factory
@@ -152,6 +163,14 @@ WifiMacHelper::SetAssocManager (std::string type, Args&&... args)
m_assocManager.Set (args...);
}
template <typename... Args>
void
WifiMacHelper::SetMacQueueScheduler (std::string type, Args&&... args)
{
m_queueScheduler.SetTypeId (type);
m_queueScheduler.Set (args...);
}
template <typename... Args>
void
WifiMacHelper::SetProtectionManager (std::string type, Args&&... args)

View File

@@ -266,9 +266,9 @@ BlockAckManager::GetBar (bool remove, uint8_t tid, Mac48Address address)
{
Time now = Simulator::Now ();
Ptr<const WifiMacQueueItem> bar;
// remove all expired MPDUs from the head of the MAC queue, so that
// remove all expired MPDUs from the MAC queue, so that
// BlockAckRequest frames (if needed) are scheduled
m_queue->IsEmpty ();
m_queue->WipeAllExpiredMpdus ();
auto nextBar = m_bars.begin ();
@@ -300,33 +300,6 @@ BlockAckManager::GetBar (bool remove, uint8_t tid, Mac48Address address)
nextBar++;
continue;
}
// remove expired outstanding MPDUs and update the starting sequence number
for (auto mpduIt = it->second.second.begin (); mpduIt != it->second.second.end (); )
{
if (!(*mpduIt)->IsQueued ())
{
// the MPDU is no longer in the EDCA queue
mpduIt = it->second.second.erase (mpduIt);
continue;
}
if ((*mpduIt)->GetTimeStamp () + m_queue->GetMaxDelay () <= now)
{
// MPDU expired
it->second.first.NotifyDiscardedMpdu (*mpduIt);
// Remove from the EDCA queue and fire the Expired trace source, but the
// consequent call to NotifyDiscardedMpdu does nothing (in particular,
// does not schedule a BAR) because we have advanced the transmit window
// and hence this MPDU became an old packet
m_queue->TtlExceeded (*mpduIt, now);
mpduIt = it->second.second.erase (mpduIt);
}
else
{
// MPDUs are typically in increasing order of remaining lifetime
break;
}
}
// update BAR if the starting sequence number changed
CtrlBAckRequestHeader reqHdr;
nextBar->bar->GetPacket ()->PeekHeader (reqHdr);
@@ -385,7 +358,6 @@ BlockAckManager::HandleInFlightMpdu (PacketQueueI mpduIt, MpduStatus status,
if (status == ACKNOWLEDGED)
{
// the MPDU has to be dequeued from the EDCA queue
m_queue->DequeueIfQueued (*mpduIt);
return it->second.second.erase (mpduIt);
}
@@ -401,7 +373,7 @@ BlockAckManager::HandleInFlightMpdu (PacketQueueI mpduIt, MpduStatus status,
{
m_droppedOldMpduCallback (*mpduIt);
}
m_queue->Remove (*mpduIt, false);
m_queue->Remove (*mpduIt);
return it->second.second.erase (mpduIt);
}
@@ -453,6 +425,7 @@ BlockAckManager::NotifyGotAck (Ptr<const WifiMacQueueItem> mpdu)
{
if ((*queueIt)->GetHeader ().GetSequenceNumber () == mpdu->GetHeader ().GetSequenceNumber ())
{
m_queue->DequeueIfQueued ({*queueIt});
HandleInFlightMpdu (queueIt, ACKNOWLEDGED, it, Simulator::Now ());
break;
}
@@ -522,10 +495,12 @@ BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader& blockAck, Mac4
NS_ASSERT (blockAck.IsCompressed () || blockAck.IsExtendedCompressed () || blockAck.IsMultiSta ());
Time now = Simulator::Now ();
std::list<Ptr<const WifiMacQueueItem>> acked;
for (auto queueIt = it->second.second.begin (); queueIt != it->second.second.end (); )
{
uint16_t currentSeq = (*queueIt)->GetHeader ().GetSequenceNumber ();
NS_LOG_DEBUG ("Current seq=" << currentSeq);
if (blockAck.IsPacketReceived (currentSeq, index))
{
it->second.first.NotifyAckedMpdu (*queueIt);
@@ -534,18 +509,28 @@ BlockAckManager::NotifyGotBlockAck (const CtrlBAckResponseHeader& blockAck, Mac4
{
m_txOkCallback (*queueIt);
}
acked.push_back (*queueIt);
queueIt = HandleInFlightMpdu (queueIt, ACKNOWLEDGED, it, now);
}
else
{
nFailedMpdus++;
if (!m_txFailedCallback.IsNull ())
{
m_txFailedCallback (*queueIt);
}
queueIt = HandleInFlightMpdu (queueIt, TO_RETRANSMIT, it, now);
++queueIt;
}
}
// Dequeue all acknowledged MPDUs at once
m_queue->DequeueIfQueued (acked);
// Remaining outstanding MPDUs have not been acknowledged
for (auto queueIt = it->second.second.begin (); queueIt != it->second.second.end (); )
{
nFailedMpdus++;
if (!m_txFailedCallback.IsNull ())
{
m_txFailedCallback (*queueIt);
}
queueIt = HandleInFlightMpdu (queueIt, TO_RETRANSMIT, it, now);
}
}
return {nSuccessfulMpdus, nFailedMpdus};
}
@@ -611,7 +596,7 @@ BlockAckManager::NotifyDiscardedMpdu (Ptr<const WifiMacQueueItem> mpdu)
if (it->second.first.GetDistance ((*mpduIt)->GetHeader ().GetSequenceNumber ()) >= SEQNO_SPACE_HALF_SIZE)
{
NS_LOG_DEBUG ("Dropping old MPDU: " << **mpduIt);
m_queue->DequeueIfQueued (*mpduIt);
m_queue->DequeueIfQueued ({*mpduIt});
if (!m_droppedOldMpduCallback.IsNull ())
{
m_droppedOldMpduCallback (*mpduIt);
@@ -780,8 +765,9 @@ BlockAckManager::SwitchToBlockAckIfNeeded (Mac48Address recipient, uint8_t tid,
NS_ASSERT (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::PENDING));
if (!ExistsAgreementInState (recipient, tid, OriginatorBlockAckAgreement::REJECTED) && ExistsAgreement (recipient, tid))
{
uint32_t packets = m_queue->GetNPacketsByTidAndAddress (tid, recipient) +
GetNBufferedPackets (recipient, tid);
WifiContainerQueueId queueId {WIFI_QOSDATA_UNICAST_QUEUE, recipient, tid};
uint32_t packets = m_queue->GetNPackets (queueId)
+ GetNBufferedPackets (recipient, tid);
if (packets >= m_blockAckThreshold)
{
NotifyAgreementEstablished (recipient, tid, startingSeq);

View File

@@ -0,0 +1,157 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2022 Universita' degli Studi di Napoli Federico II
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Stefano Avallone <stavallo@unina.it>
*/
#include "ns3/log.h"
#include "ns3/enum.h"
#include "fcfs-wifi-queue-scheduler.h"
#include "wifi-mac-queue.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("FcfsWifiQueueScheduler");
NS_OBJECT_ENSURE_REGISTERED (FcfsWifiQueueScheduler);
TypeId
FcfsWifiQueueScheduler::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::FcfsWifiQueueScheduler")
.SetParent<WifiMacQueueSchedulerImpl<Time>> ()
.SetGroupName ("Wifi")
.AddConstructor<FcfsWifiQueueScheduler> ()
.AddAttribute ("DropPolicy",
"Upon enqueue with full queue, drop oldest (DropOldest) or newest (DropNewest) packet",
EnumValue (DROP_NEWEST),
MakeEnumAccessor (&FcfsWifiQueueScheduler::m_dropPolicy),
MakeEnumChecker (FcfsWifiQueueScheduler::DROP_OLDEST, "DropOldest",
FcfsWifiQueueScheduler::DROP_NEWEST, "DropNewest"))
;
return tid;
}
FcfsWifiQueueScheduler::FcfsWifiQueueScheduler ()
: NS_LOG_TEMPLATE_DEFINE ("FcfsWifiQueueScheduler")
{
}
Ptr<WifiMacQueueItem>
FcfsWifiQueueScheduler::HasToDropBeforeEnqueuePriv (AcIndex ac, Ptr<WifiMacQueueItem> mpdu)
{
auto queue = GetWifiMacQueue (ac);
if (queue->QueueBase::GetNPackets () < queue->GetMaxSize ().GetValue ())
{
// the queue is not full, do not drop anything
return nullptr;
}
// Management frames should be prioritized
if (m_dropPolicy == DROP_OLDEST || mpdu->GetHeader ().IsMgt ())
{
auto sortedQueuesIt = GetSortedQueues (ac).begin ();
while (sortedQueuesIt != GetSortedQueues (ac).end ()
&& std::get<WifiContainerQueueType> (sortedQueuesIt->second.get ().first) == WIFI_MGT_QUEUE)
{
sortedQueuesIt++;
}
if (sortedQueuesIt != GetSortedQueues (ac).end ())
{
return queue->PeekByQueueId (sortedQueuesIt->second.get ().first);
}
}
return mpdu;
}
void
FcfsWifiQueueScheduler::DoNotifyEnqueue (AcIndex ac, Ptr<WifiMacQueueItem> mpdu)
{
NS_LOG_FUNCTION (this << +ac << *mpdu);
auto queueId = WifiMacQueueContainer::GetQueueId (mpdu);
if (GetWifiMacQueue (ac)->GetNPackets (queueId) > 1)
{
// Enqueue takes place at the tail, while the priority is determined by the
// head of the queue. Therefore, if the queue was not empty before inserting
// this MPDU, priority does not change
return;
}
auto priority = (mpdu->GetHeader ().IsMgt () ? Seconds(0) // Highest priority for management frames
: mpdu->GetExpiryTime ());
SetPriority (ac, queueId, priority);
}
void
FcfsWifiQueueScheduler::DoNotifyDequeue (AcIndex ac, const std::list<Ptr<WifiMacQueueItem>>& mpdus)
{
NS_LOG_FUNCTION (this << +ac);
std::set<WifiContainerQueueId> queueIds;
for (const auto& mpdu : mpdus)
{
queueIds.insert (WifiMacQueueContainer::GetQueueId (mpdu));
}
for (const auto& queueId : queueIds)
{
if (std::get<WifiContainerQueueType> (queueId) == WIFI_MGT_QUEUE)
{
// the priority of management queues does not change
continue;
}
if (auto item = GetWifiMacQueue (ac)->PeekByQueueId (queueId); item != nullptr)
{
SetPriority (ac, queueId, item->GetExpiryTime ());
}
}
}
void
FcfsWifiQueueScheduler::DoNotifyRemove (AcIndex ac, const std::list<Ptr<WifiMacQueueItem>>& mpdus)
{
NS_LOG_FUNCTION (this << +ac);
std::set<WifiContainerQueueId> queueIds;
for (const auto& mpdu : mpdus)
{
queueIds.insert (WifiMacQueueContainer::GetQueueId (mpdu));
}
for (const auto& queueId : queueIds)
{
if (std::get<0> (queueId) == WIFI_MGT_QUEUE)
{
// the priority of management queues does not change
continue;
}
if (auto item = GetWifiMacQueue (ac)->PeekByQueueId (queueId); item != nullptr)
{
SetPriority (ac, queueId, item->GetExpiryTime ());
}
}
}
} //namespace ns3

View File

@@ -0,0 +1,66 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2022 Universita' degli Studi di Napoli Federico II
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Stefano Avallone <stavallo@unina.it>
*/
#ifndef FCFS_WIFI_QUEUE_SCHEDULER_H
#define FCFS_WIFI_QUEUE_SCHEDULER_H
#include "ns3/nstime.h"
#include "wifi-mac-queue-scheduler-impl.h"
namespace ns3 {
class WifiMacQueueItem;
/**
* \ingroup wifi
*
* WifiMacQueueScheduler ...
*/
class FcfsWifiQueueScheduler : public WifiMacQueueSchedulerImpl<Time>
{
public:
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
FcfsWifiQueueScheduler ();
/// drop policy
enum DropPolicy
{
DROP_NEWEST,
DROP_OLDEST
};
private:
Ptr<WifiMacQueueItem> HasToDropBeforeEnqueuePriv (AcIndex ac, Ptr<WifiMacQueueItem> mpdu) override;
void DoNotifyEnqueue (AcIndex ac, Ptr<WifiMacQueueItem> mpdu) override;
void DoNotifyDequeue (AcIndex ac, const std::list<Ptr<WifiMacQueueItem>>& mpdus) override;
void DoNotifyRemove (AcIndex ac, const std::list<Ptr<WifiMacQueueItem>>& mpdus) override;
DropPolicy m_dropPolicy; //!< Drop behavior of queue
NS_LOG_TEMPLATE_DECLARE; //!< redefinition of the log component
};
} //namespace ns3
#endif /* FCFS_WIFI_QUEUE_SCHEDULER_H */

View File

@@ -302,6 +302,8 @@ FrameExchangeManager::StartTransmission (Ptr<Txop> dcf, uint16_t allowedWidth)
// Even though channel access is requested when the queue is not empty, at
// the time channel access is granted the lifetime of the packet might be
// expired and the queue might be empty.
queue->WipeAllExpiredMpdus ();
if (queue->IsEmpty ())
{
NS_LOG_DEBUG ("Queue empty");
@@ -482,7 +484,7 @@ FrameExchangeManager::DequeueMpdu (Ptr<const WifiMacQueueItem> mpdu)
if (mpdu->IsQueued ())
{
m_mac->GetTxopQueue (mpdu->GetQueueAc ())->DequeueIfQueued (mpdu);
m_mac->GetTxopQueue (mpdu->GetQueueAc ())->DequeueIfQueued ({mpdu});
}
}

View File

@@ -119,7 +119,8 @@ HtFrameExchangeManager::NeedSetupBlockAck (Mac48Address recipient, uint8_t tid)
}
else
{
uint32_t packets = qosTxop->GetWifiMacQueue ()->GetNPacketsByTidAndAddress (tid, recipient);
WifiContainerQueueId queueId {WIFI_QOSDATA_UNICAST_QUEUE, recipient, tid};
uint32_t packets = qosTxop->GetWifiMacQueue ()->GetNPackets (queueId);
establish = ((qosTxop->GetBlockAckThreshold () > 0 && packets >= qosTxop->GetBlockAckThreshold ())
|| (m_mpduAggregator->GetMaxAmpduSize (recipient, tid, WIFI_MOD_CLASS_HT) > 0 && packets > 1)
|| m_mac->GetWifiRemoteStationManager ()->GetVhtSupported ());
@@ -186,13 +187,8 @@ HtFrameExchangeManager::SendAddBaRequest (Mac48Address dest, uint8_t tid, uint16
txParams.m_protection = std::unique_ptr<WifiProtection> (new WifiNoProtection);
txParams.m_acknowledgment = GetAckManager ()->TryAddMpdu (mpdu, txParams);
// Push the MPDU to the front of the queue and transmit it
auto queue = m_mac->GetQosTxop (tid)->GetWifiMacQueue ();
if (!queue->PushFront (mpdu))
{
NS_LOG_DEBUG ("Queue is full, replace the oldest frame with the ADDBA Request frame");
queue->Replace (queue->Peek (), mpdu);
}
// Wifi MAC queue scheduler is expected to prioritize management frames
m_mac->GetQosTxop (tid)->GetWifiMacQueue ()->Enqueue (mpdu);
SendMpduWithProtection (mpdu, txParams);
}
@@ -270,7 +266,8 @@ HtFrameExchangeManager::SendAddBaResponse (const MgtAddBaRequestHeader *reqHdr,
//It is unclear which queue this frame should go into. For now we
//bung it into the queue corresponding to the TID for which we are
//establishing an agreement, and push it to the head.
m_mac->GetQosTxop (reqHdr->GetTid ())->PushFront (mpdu);
// Wifi MAC queue scheduler is expected to prioritize management frames
m_mac->GetQosTxop (reqHdr->GetTid ())->Queue (mpdu);
}
uint16_t
@@ -313,7 +310,7 @@ HtFrameExchangeManager::SendDelbaFrame (Mac48Address addr, uint8_t tid, bool byO
packet->AddHeader (delbaHdr);
packet->AddHeader (actionHdr);
m_mac->GetQosTxop (tid)->GetWifiMacQueue ()->PushFront (Create<WifiMacQueueItem> (packet, hdr));
m_mac->GetQosTxop (tid)->GetWifiMacQueue ()->Enqueue (Create<WifiMacQueueItem> (packet, hdr));
}
void

View File

@@ -127,13 +127,10 @@ MsduAggregator::GetNextAmsdu (Ptr<WifiMacQueueItem> peekedItem, WifiTxParameters
// find the next MPDU before dequeuing the current one
Ptr<const WifiMacQueueItem> msdu = peekedItem;
peekedItem = queue->PeekByTidAndAddress (tid, recipient, peekedItem);
queue->DequeueIfQueued (msdu);
queue->DequeueIfQueued ({amsdu});
// perform A-MSDU aggregation
queue->Transform (amsdu, [&msdu](Ptr<WifiMacQueueItem> amsdu)
{
amsdu->Aggregate (msdu);
});
amsdu->Aggregate (msdu);
queue->Replace (msdu, amsdu);
nMsdu++;
}

View File

@@ -136,7 +136,8 @@ QosTxop::GetLink (uint8_t linkId) const
uint8_t
QosTxop::GetQosQueueSize (uint8_t tid, Mac48Address receiver) const
{
uint32_t bufferSize = m_queue->GetNBytes (tid, receiver);
WifiContainerQueueId queueId {WIFI_QOSDATA_UNICAST_QUEUE, receiver, tid};
uint32_t bufferSize = m_queue->GetNBytes (queueId);
// A queue size value of 254 is used for all sizes greater than 64 768 octets.
uint8_t queueSize = static_cast<uint8_t> (std::ceil (std::min (bufferSize, 64769u) / 256.0));
NS_LOG_DEBUG ("Buffer size=" << bufferSize << " Queue Size=" << +queueSize);
@@ -304,10 +305,8 @@ QosTxop::HasFramesToTransmit (void)
// the starting sequence number of the transmit (and receiver) window
bool baManagerHasPackets {m_baManager->GetBar (false)};
// remove MSDUs with expired lifetime starting from the head of the queue
// TODO Add a WifiMacQueue method that serves this purpose; IsEmpty () can
// then reuse such method.
m_queue->IsEmpty ();
bool queueIsNotEmpty {m_queue->PeekFirstAvailable (m_qosBlockedDestinations)};
m_queue->WipeAllExpiredMpdus ();
bool queueIsNotEmpty = (bool)(m_queue->PeekFirstAvailable (m_qosBlockedDestinations));
bool ret = (baManagerHasPackets || queueIsNotEmpty);
NS_LOG_FUNCTION (this << baManagerHasPackets << queueIsNotEmpty);
@@ -578,22 +577,6 @@ QosTxop::GetRemainingTxop (uint8_t linkId) const
return remainingTxop;
}
void
QosTxop::PushFront (Ptr<WifiMacQueueItem> mpdu)
{
NS_LOG_FUNCTION (this << *mpdu);
if (!m_queue->PushFront (mpdu))
{
NS_LOG_DEBUG ("Queue is full, replace the oldest frame with the ADDBA Request frame");
m_queue->Replace (m_queue->Peek (), mpdu);
}
if (HasFramesToTransmit () && GetLink (0).access == NOT_REQUESTED) // TODO use appropriate linkId
{
m_mac->GetChannelAccessManager (SINGLE_LINK_OP_ID)->RequestAccess (this);
}
}
void
QosTxop::GotAddBaResponse (const MgtAddBaResponseHeader *respHdr, Mac48Address recipient)
{

View File

@@ -211,14 +211,6 @@ public:
*/
void ResetBa (Mac48Address recipient, uint8_t tid);
/**
* \param mpdu the given MPDU
*
* Store the given MPDU in the front of the internal queue until it
* can be sent safely.
*/
void PushFront (Ptr<WifiMacQueueItem> mpdu);
/**
* Set threshold for block ack mechanism. If number of packets in the
* queue reaches the threshold, block ack mechanism is used.

View File

@@ -476,6 +476,7 @@ Txop::GetTxopLimit (uint8_t linkId) const
bool
Txop::HasFramesToTransmit (void)
{
m_queue->WipeAllExpiredMpdus ();
bool ret = (!m_queue->IsEmpty ());
NS_LOG_FUNCTION (this << ret);
return ret;

View File

@@ -151,7 +151,7 @@ WifiDefaultAckManager::IsResponseNeeded (Ptr<const WifiMacQueueItem> mpdu,
// protected by RTS/CTS (see Annex G.3 of IEEE 802.11-2016)
if (m_baThreshold > 0
&& GetMaxDistFromStartingSeq (mpdu, txParams) < m_baThreshold * edca->GetBaBufferSize (receiver, tid)
&& (edca->GetWifiMacQueue ()->GetNPackets (tid, receiver)
&& (edca->GetWifiMacQueue ()->GetNPackets ({WIFI_QOSDATA_UNICAST_QUEUE, receiver, tid})
- edca->GetBaManager ()->GetNBufferedPackets (receiver, tid) > 1)
&& !(edca->GetTxopLimit (m_linkId).IsStrictlyPositive ()
&& edca->GetRemainingTxop (m_linkId) == edca->GetTxopLimit (m_linkId)

View File

@@ -41,8 +41,7 @@ WifiMacQueueItem::WifiMacQueueItem (Ptr<const Packet> p, const WifiMacHeader & h
WifiMacQueueItem::WifiMacQueueItem (Ptr<const Packet> p, const WifiMacHeader & header, Time tstamp)
: m_packet (p),
m_header (header),
m_tstamp (tstamp),
m_queueAc (AC_UNDEF)
m_tstamp (tstamp)
{
if (header.IsQosData () && header.IsQosAmsdu ())
{
@@ -204,26 +203,34 @@ WifiMacQueueItem::DoAggregate (Ptr<const WifiMacQueueItem> msdu)
bool
WifiMacQueueItem::IsQueued (void) const
{
return m_queueAc != AC_UNDEF;
return m_queueIt.has_value ();
}
void
WifiMacQueueItem::SetQueueIt (std::optional<Iterator> queueIt, WmqIteratorTag tag)
{
// empty for now
m_queueIt = queueIt;
}
WifiMacQueueItem::Iterator
WifiMacQueueItem::GetQueueIt (WmqIteratorTag tag) const
{
return m_queueIt;
NS_ASSERT (IsQueued ());
return m_queueIt.value ();
}
AcIndex
WifiMacQueueItem::GetQueueAc (void) const
{
NS_ASSERT (IsQueued ());
return m_queueAc;
return (*m_queueIt)->ac;
}
Time
WifiMacQueueItem::GetExpiryTime (void) const
{
NS_ASSERT (IsQueued ());
return (*m_queueIt)->expiryTime;
}
void

View File

@@ -24,11 +24,10 @@
#ifndef WIFI_MAC_QUEUE_ITEM_H
#define WIFI_MAC_QUEUE_ITEM_H
#include "ns3/nstime.h"
#include "ns3/packet.h"
#include "wifi-mac-header.h"
#include "amsdu-subframe-header.h"
#include "qos-utils.h"
#include "wifi-mac-header.h"
#include "wifi-mac-queue-elem.h"
#include <list>
#include <optional>
@@ -154,7 +153,7 @@ public:
DeaggregatedMsdusCI end (void);
/// Const iterator typedef
typedef std::list<Ptr<WifiMacQueueItem>>::iterator Iterator;
typedef std::list<WifiMacQueueElem>::iterator Iterator;
/**
* Set the queue iterator stored by this object.
@@ -182,6 +181,10 @@ public:
* \return the AC of the queue this item is stored into
*/
AcIndex GetQueueAc (void) const;
/**
* \return the expiry time of this MPDU
*/
Time GetExpiryTime (void) const;
/**
* \brief Get the MAC protocol data unit (MPDU) corresponding to this item
@@ -221,14 +224,11 @@ private:
*/
void DoAggregate (Ptr<const WifiMacQueueItem> msdu);
friend class WifiMacQueue; // to set queue AC and iterator information
Ptr<const Packet> m_packet; //!< The packet (MSDU or A-MSDU) contained in this queue item
WifiMacHeader m_header; //!< Wifi MAC header associated with the packet
Time m_tstamp; //!< timestamp when the packet arrived at the queue
DeaggregatedMsdus m_msduList; //!< The list of aggregated MSDUs included in this MPDU
Iterator m_queueIt; //!< Queue iterator pointing to this MPDU, if queued
AcIndex m_queueAc; //!< AC associated with the queue this MPDU is stored into
std::optional<Iterator> m_queueIt; //!< Queue iterator pointing to this MPDU, if queued
bool m_inFlight; //!< whether the MPDU is in flight
};

View File

@@ -63,6 +63,8 @@ public:
*/
WifiMacQueueSchedulerImpl ();
/** \copydoc ns3::WifiMacQueueScheduler::SetWifiMac */
void SetWifiMac (Ptr<WifiMac> mac) final;
/** \copydoc ns3::WifiMacQueueScheduler::GetNext(AcIndex,uint8_t) */
std::optional<WifiContainerQueueId> GetNext (AcIndex ac, uint8_t linkId) final;
/** \copydoc ns3::WifiMacQueueScheduler::GetNext(AcIndex,uint8_t,const WifiContainerQueueId&) */
@@ -254,6 +256,21 @@ WifiMacQueueSchedulerImpl<Priority, Compare>::DoDispose (void)
WifiMacQueueScheduler::DoDispose ();
}
template <class Priority, class Compare>
void
WifiMacQueueSchedulerImpl<Priority, Compare>::SetWifiMac (Ptr<WifiMac> mac)
{
for (auto ac : {AC_BE, AC_BK, AC_VI, AC_VO, AC_BE_NQOS, AC_BEACON})
{
if (auto queue = mac->GetTxopQueue (ac); queue != nullptr)
{
m_perAcInfo.at (ac).wifiMacQueue = queue;
queue->SetScheduler (this);
}
}
WifiMacQueueScheduler::SetWifiMac (mac);
}
template <class Priority, class Compare>
Ptr<WifiMacQueue>
WifiMacQueueSchedulerImpl<Priority, Compare>::GetWifiMacQueue (AcIndex ac) const

View File

@@ -23,6 +23,7 @@
#include "ns3/simulator.h"
#include "wifi-mac-queue.h"
#include "wifi-mac-queue-scheduler.h"
#include "qos-blocked-destinations.h"
#include <functional>
@@ -31,13 +32,13 @@ namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("WifiMacQueue");
NS_OBJECT_ENSURE_REGISTERED (WifiMacQueue);
NS_OBJECT_TEMPLATE_CLASS_DEFINE (Queue, WifiMacQueueItem);
NS_OBJECT_TEMPLATE_CLASS_TWO_DEFINE (Queue, WifiMacQueueItem, WifiMacQueueContainer);
TypeId
WifiMacQueue::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::WifiMacQueue")
.SetParent<Queue<WifiMacQueueItem> > ()
.SetParent<Queue<WifiMacQueueItem, WifiMacQueueContainer> > ()
.SetGroupName ("Wifi")
.AddConstructor<WifiMacQueue> ()
.AddAttribute ("MaxSize",
@@ -50,11 +51,6 @@ WifiMacQueue::GetTypeId (void)
TimeValue (MilliSeconds (500)),
MakeTimeAccessor (&WifiMacQueue::SetMaxDelay),
MakeTimeChecker ())
.AddAttribute ("DropPolicy", "Upon enqueue with full queue, drop oldest (DropOldest) or newest (DropNewest) packet",
EnumValue (DROP_NEWEST),
MakeEnumAccessor (&WifiMacQueue::m_dropPolicy),
MakeEnumChecker (WifiMacQueue::DROP_OLDEST, "DropOldest",
WifiMacQueue::DROP_NEWEST, "DropNewest"))
.AddTraceSource ("Expired", "MPDU dropped because its lifetime expired.",
MakeTraceSourceAccessor (&WifiMacQueue::m_traceExpired),
"ns3::WifiMacQueueItem::TracedCallback")
@@ -71,30 +67,104 @@ WifiMacQueue::WifiMacQueue (AcIndex ac)
WifiMacQueue::~WifiMacQueue ()
{
NS_LOG_FUNCTION_NOARGS ();
m_nQueuedPackets.clear ();
m_nQueuedBytes.clear ();
}
bool
WifiMacQueue::TtlExceeded (ConstIterator &it, const Time& now)
void
WifiMacQueue::DoDispose (void)
{
if (now > (*it)->GetTimeStamp () + m_maxDelay)
NS_LOG_FUNCTION (this);
m_scheduler = nullptr;
Queue<WifiMacQueueItem, WifiMacQueueContainer>::DoDispose ();
}
AcIndex
WifiMacQueue::GetAc (void) const
{
return m_ac;
}
WifiMacQueue::Iterator
WifiMacQueue::GetIt (Ptr<const WifiMacQueueItem> mpdu) const
{
NS_ASSERT (mpdu->IsQueued ());
return mpdu->GetQueueIt (WmqIteratorTag ());
}
void
WifiMacQueue::ExtractExpiredMpdus (const WifiContainerQueueId& queueId) const
{
NS_LOG_FUNCTION (this);
std::list<Ptr<WifiMacQueueItem>> mpdus;
auto [first, last] = GetContainer ().ExtractExpiredMpdus (queueId);
for (auto it = first; it != last; it++)
{
NS_LOG_DEBUG ("Removing packet that stayed in the queue for too long (" <<
now - (*it)->GetTimeStamp () << ")");
auto curr = it++;
m_traceExpired (DoRemove (curr));
return true;
mpdus.push_back (it->mpdu);
// fire the Expired trace
m_traceExpired (it->mpdu);
}
// notify the scheduler
m_scheduler->NotifyRemove (m_ac, mpdus);
}
void
WifiMacQueue::ExtractAllExpiredMpdus (void) const
{
NS_LOG_FUNCTION (this);
std::list<Ptr<WifiMacQueueItem>> mpdus;
auto [first, last] = GetContainer ().ExtractAllExpiredMpdus ();
for (auto it = first; it != last; it++)
{
mpdus.push_back (it->mpdu);
// fire the Expired trace
m_traceExpired (it->mpdu);
}
// notify the scheduler
m_scheduler->NotifyRemove (m_ac, mpdus);
}
void
WifiMacQueue::WipeAllExpiredMpdus (void)
{
NS_LOG_FUNCTION (this);
ExtractAllExpiredMpdus ();
auto [first, last] = GetContainer ().GetAllExpiredMpdus ();
for (auto it = first; it != last; )
{
// the scheduler has been notified and the Expired trace has been fired
// when the MPDU was extracted from its queue. The only thing left to do
// is to update the Queue base class statistics by calling Queue::DoRemove
auto curr = it++;
Queue<WifiMacQueueItem, WifiMacQueueContainer>::DoRemove (curr);
}
return false;
}
bool
WifiMacQueue::TtlExceeded (Ptr<const WifiMacQueueItem> item, const Time& now)
{
NS_ASSERT (item && item->IsQueued ());
ConstIterator it = item->m_queueIt;
return TtlExceeded (it, now);
auto it = GetIt (item);
if (now > it->expiryTime)
{
NS_LOG_DEBUG ("Removing packet that stayed in the queue for too long (queuing time=" <<
now - it->expiryTime + m_maxDelay << ")");
m_traceExpired (DoRemove (it));
return true;
}
return false;
}
void
WifiMacQueue::SetScheduler (Ptr<WifiMacQueueScheduler> scheduler)
{
NS_LOG_FUNCTION (this << scheduler);
m_scheduler = scheduler;
}
void
@@ -115,15 +185,8 @@ WifiMacQueue::Enqueue (Ptr<WifiMacQueueItem> item)
{
NS_LOG_FUNCTION (this << *item);
return Insert (GetContainer ().cend (), item);
}
bool
WifiMacQueue::PushFront (Ptr<WifiMacQueueItem> item)
{
NS_LOG_FUNCTION (this << *item);
return Insert (GetContainer ().cbegin (), item);
auto queueId = WifiMacQueueContainer::GetQueueId (item);
return Insert (GetContainer ().GetQueue (queueId).cend (), item);
}
bool
@@ -139,37 +202,22 @@ WifiMacQueue::Insert (ConstIterator pos, Ptr<WifiMacQueueItem> item)
return DoEnqueue (pos, item);
}
// the queue is full; scan the list in the attempt to remove stale packets
ConstIterator it = GetContainer ().cbegin ();
const Time now = Simulator::Now ();
while (it != GetContainer ().cend ())
// the queue is full; try to make some room by removing stale packets
auto queueId = WifiMacQueueContainer::GetQueueId (item);
if (pos != GetContainer ().GetQueue (queueId).cend ())
{
if (it == pos && TtlExceeded (it, now))
NS_ABORT_MSG_IF (WifiMacQueueContainer::GetQueueId (pos->mpdu) != queueId,
"pos must point to an element in the same container queue as item");
if (pos->expiryTime <= Simulator::Now ())
{
return DoEnqueue (it, item);
// the element pointed to by pos is stale and will be removed along with all of
// its predecessors; the new item will be enqueued at the front of the queue
pos = GetContainer ().GetQueue (queueId).cbegin ();
}
if (TtlExceeded (it, now))
{
return DoEnqueue (pos, item);
}
it++;
}
// the queue is still full, remove the oldest item if the policy is drop oldest
if (m_dropPolicy == DROP_OLDEST)
{
NS_LOG_DEBUG ("Remove the oldest item in the queue");
if (pos == GetContainer ().cbegin ())
{
// Avoid invalidating pos
DoRemove (GetContainer ().cbegin ());
pos = GetContainer ().cbegin ();
}
else
{
DoRemove (GetContainer ().cbegin ());
}
}
WipeAllExpiredMpdus ();
return DoEnqueue (pos, item);
}
@@ -177,126 +225,89 @@ WifiMacQueue::Insert (ConstIterator pos, Ptr<WifiMacQueueItem> item)
Ptr<WifiMacQueueItem>
WifiMacQueue::Dequeue (void)
{
NS_LOG_FUNCTION (this);
const Time now = Simulator::Now ();
for (ConstIterator it = GetContainer ().cbegin (); it != GetContainer ().cend (); )
{
if (!TtlExceeded (it, now))
{
return DoDequeue (it);
}
}
NS_LOG_DEBUG ("The queue is empty");
return 0;
// An MPDU is dequeued when either is acknowledged or is dropped, hence a Dequeue
// method without an argument makes no sense.
NS_ABORT_MSG ("Not implemented by WifiMacQueue");
return nullptr;
}
void
WifiMacQueue::DequeueIfQueued (Ptr<const WifiMacQueueItem> mpdu)
WifiMacQueue::DequeueIfQueued (const std::list<Ptr<const WifiMacQueueItem>>& mpdus)
{
NS_LOG_FUNCTION (this << *mpdu);
NS_LOG_FUNCTION (this);
if (mpdu->IsQueued ())
std::list<ConstIterator> iterators;
for (const auto& mpdu : mpdus)
{
NS_ASSERT (mpdu->m_queueAc == m_ac);
NS_ASSERT (*mpdu->m_queueIt == mpdu);
DoDequeue (mpdu->m_queueIt);
if (mpdu->IsQueued ())
{
auto it = GetIt (mpdu);
NS_ASSERT (it->ac == m_ac);
NS_ASSERT (it->mpdu == mpdu);
iterators.push_back (it);
}
}
DoDequeue (iterators);
}
Ptr<const WifiMacQueueItem>
WifiMacQueue::Peek (void) const
{
return Peek (0);
}
Ptr<WifiMacQueueItem>
WifiMacQueue::Peek (uint8_t linkId) const
{
NS_LOG_FUNCTION (this);
const Time now = Simulator::Now ();
for (auto it = GetContainer ().cbegin (); it != GetContainer ().cend (); it++)
auto queueId = m_scheduler->GetNext (m_ac, linkId);
if (!queueId.has_value ())
{
// skip packets that stayed in the queue for too long. They will be
// actually removed from the queue by the next call to a non-const method
if (now <= (*it)->GetTimeStamp () + m_maxDelay)
{
return DoPeek (it);
}
NS_LOG_DEBUG ("The queue is empty");
return nullptr;
}
NS_LOG_DEBUG ("The queue is empty");
return 0;
}
Ptr<WifiMacQueueItem>
WifiMacQueue::PeekByAddress (Mac48Address dest, Ptr<const WifiMacQueueItem> item) const
{
NS_LOG_FUNCTION (this << dest << item);
NS_ASSERT ( !item || item->IsQueued ());
ConstIterator it = (item ? std::next (item->m_queueIt) : GetContainer ().cbegin ());
const Time now = Simulator::Now ();
while (it != GetContainer ().cend ())
{
// skip packets that stayed in the queue for too long. They will be
// actually removed from the queue by the next call to a non-const method
if (now <= (*it)->GetTimeStamp () + m_maxDelay)
{
if (((*it)->GetHeader ().IsData () || (*it)->GetHeader ().IsQosData ())
&& (*it)->GetDestinationAddress () == dest)
{
return *it;
}
}
it++;
}
NS_LOG_DEBUG ("The queue is empty");
return nullptr;
}
Ptr<WifiMacQueueItem>
WifiMacQueue::PeekByTid (uint8_t tid, Ptr<const WifiMacQueueItem> item) const
{
NS_LOG_FUNCTION (this << +tid << item);
NS_ASSERT ( !item || item->IsQueued ());
ConstIterator it = (item ? std::next (item->m_queueIt) : GetContainer ().cbegin ());
const Time now = Simulator::Now ();
while (it != GetContainer ().cend ())
{
// skip packets that stayed in the queue for too long. They will be
// actually removed from the queue by the next call to a non-const method
if (now <= (*it)->GetTimeStamp () + m_maxDelay)
{
if ((*it)->GetHeader ().IsQosData () && (*it)->GetHeader ().GetQosTid () == tid)
{
return *it;
}
}
it++;
}
NS_LOG_DEBUG ("The queue is empty");
return nullptr;
return GetContainer ().GetQueue (queueId.value ()).cbegin ()->mpdu;
}
Ptr<WifiMacQueueItem>
WifiMacQueue::PeekByTidAndAddress (uint8_t tid, Mac48Address dest, Ptr<const WifiMacQueueItem> item) const
{
NS_LOG_FUNCTION (this << +tid << dest << item);
NS_ASSERT ( !item || item->IsQueued ());
NS_ABORT_IF (dest.IsGroup ());
WifiContainerQueueId queueId (WIFI_QOSDATA_UNICAST_QUEUE, dest, tid);
return PeekByQueueId (queueId, item);
}
ConstIterator it = (item ? std::next (item->m_queueIt) : GetContainer ().cbegin ());
const Time now = Simulator::Now ();
while (it != GetContainer ().cend ())
Ptr<WifiMacQueueItem>
WifiMacQueue::PeekByQueueId (const WifiContainerQueueId& queueId,
Ptr<const WifiMacQueueItem> item) const
{
NS_LOG_FUNCTION (this << item);
NS_ASSERT (!item
|| (item->IsQueued () && WifiMacQueueContainer::GetQueueId (item) == queueId));
// Remove MPDUs with expired lifetime if we are looking for the first MPDU in the queue
if (!item)
{
// skip packets that stayed in the queue for too long. They will be
// actually removed from the queue by the next call to a non-const method
if (now <= (*it)->GetTimeStamp () + m_maxDelay)
{
if ((*it)->GetHeader ().IsQosData () && (*it)->GetDestinationAddress () == dest
&& (*it)->GetHeader ().GetQosTid () == tid)
{
return *it;
}
}
it++;
ExtractExpiredMpdus (queueId);
}
NS_LOG_DEBUG ("The queue is empty");
return nullptr;
ConstIterator it = (item ? std::next (GetIt (item))
: GetContainer ().GetQueue (queueId).cbegin ());
if (it == GetContainer ().GetQueue (queueId).cend ())
{
NS_LOG_DEBUG ("The queue is empty");
return nullptr;
}
return it->mpdu;
}
Ptr<WifiMacQueueItem>
@@ -304,77 +315,68 @@ WifiMacQueue::PeekFirstAvailable (const Ptr<QosBlockedDestinations> blockedPacke
Ptr<const WifiMacQueueItem> item) const
{
NS_LOG_FUNCTION (this << item);
NS_ASSERT ( !item || item->IsQueued ());
NS_ASSERT (!item || item->IsQueued ());
ConstIterator it = (item ? std::next (item->m_queueIt) : GetContainer ().cbegin ());
const Time now = Simulator::Now ();
while (it != GetContainer ().cend ())
if (item)
{
// skip packets that stayed in the queue for too long. They will be
// actually removed from the queue by the next call to a non-const method
if (now <= (*it)->GetTimeStamp () + m_maxDelay)
NS_ASSERT (!item->GetHeader ().IsQosData ()
|| !blockedPackets
|| !blockedPackets->IsBlocked (item->GetHeader ().GetAddr1 (),
item->GetHeader ().GetQosTid ()));
// check if there are other MPDUs in the same container queue as item
auto mpdu = PeekByQueueId (WifiMacQueueContainer::GetQueueId (item), item);
if (mpdu)
{
if (!(*it)->GetHeader ().IsQosData () || !blockedPackets
|| !blockedPackets->IsBlocked ((*it)->GetHeader ().GetAddr1 (), (*it)->GetHeader ().GetQosTid ()))
{
return *it;
}
return mpdu;
}
it++;
}
NS_LOG_DEBUG ("The queue is empty");
return nullptr;
std::optional<WifiContainerQueueId> queueId;
if (item)
{
queueId = m_scheduler->GetNext (m_ac, 0, WifiMacQueueContainer::GetQueueId (item));
}
else
{
queueId = m_scheduler->GetNext (m_ac, 0);
}
while (queueId.has_value ()
&& blockedPackets
&& std::get<0> (queueId.value ()) == WIFI_QOSDATA_UNICAST_QUEUE
&& blockedPackets->IsBlocked (std::get<1> (queueId.value ()),
std::get<2> (queueId.value ())))
{
queueId = m_scheduler->GetNext (m_ac, 0, queueId.value ());
}
if (!queueId.has_value ())
{
NS_LOG_DEBUG ("The queue is empty");
return nullptr;
}
return GetContainer ().GetQueue (queueId.value ()).cbegin ()->mpdu;
}
Ptr<WifiMacQueueItem>
WifiMacQueue::Remove (void)
{
NS_LOG_FUNCTION (this);
const Time now = Simulator::Now ();
for (ConstIterator it = GetContainer ().cbegin (); it != GetContainer ().cend (); )
{
if (!TtlExceeded (it, now))
{
return DoRemove (it);
}
}
NS_LOG_DEBUG ("The queue is empty");
return 0;
return Remove (Peek ());
}
Ptr<const WifiMacQueueItem>
WifiMacQueue::Remove (Ptr<const WifiMacQueueItem> item, bool removeExpired)
Ptr<WifiMacQueueItem>
WifiMacQueue::Remove (Ptr<const WifiMacQueueItem> mpdu)
{
NS_LOG_FUNCTION (this << item << removeExpired);
NS_ASSERT (item && item->IsQueued ());
NS_LOG_FUNCTION (this << mpdu);
NS_ASSERT (mpdu && mpdu->IsQueued ());
auto it = GetIt (mpdu);
NS_ASSERT (it->ac == m_ac);
NS_ASSERT (it->mpdu == mpdu);
if (!removeExpired)
{
ConstIterator next = std::next (item->m_queueIt);
DoRemove (item->m_queueIt);
return (next == GetContainer ().cend () ? nullptr : *next);
}
const Time now = Simulator::Now ();
// remove stale items queued before the given position
ConstIterator it = GetContainer ().cbegin ();
while (it != GetContainer ().cend ())
{
if (*it == item)
{
ConstIterator next = std::next (item->m_queueIt);
DoRemove (item->m_queueIt);
return (next == GetContainer ().cend () ? nullptr : *next);
}
else if (!TtlExceeded (it, now))
{
it++;
}
}
NS_LOG_DEBUG ("Invalid iterator");
return nullptr;
return DoRemove (it);
}
void
@@ -382,216 +384,106 @@ WifiMacQueue::Replace (Ptr<const WifiMacQueueItem> currentItem, Ptr<WifiMacQueue
{
NS_LOG_FUNCTION (this << *currentItem << *newItem);
NS_ASSERT (currentItem->IsQueued ());
NS_ASSERT (currentItem->m_queueAc == m_ac);
NS_ASSERT (*currentItem->m_queueIt == currentItem);
auto currentIt = GetIt (currentItem);
NS_ASSERT (currentIt->ac == m_ac);
NS_ASSERT (currentIt->mpdu == currentItem);
NS_ASSERT (!newItem->IsQueued ());
auto pos = std::next (currentItem->m_queueIt);
DoDequeue (currentItem->m_queueIt);
Time expiryTime = currentIt->expiryTime;
auto pos = std::next (currentIt);
DoDequeue ({currentIt});
bool ret = Insert (pos, newItem);
GetIt (newItem)->expiryTime = expiryTime;
// The size of a WifiMacQueue is measured as number of packets. We dequeued
// one packet, so there is certainly room for inserting one packet
NS_ABORT_IF (!ret);
}
uint32_t
WifiMacQueue::GetNPacketsByAddress (Mac48Address dest)
WifiMacQueue::GetNPackets (const WifiContainerQueueId& queueId) const
{
NS_LOG_FUNCTION (this << dest);
uint32_t nPackets = 0;
const Time now = Simulator::Now ();
for (ConstIterator it = GetContainer ().cbegin (); it != GetContainer ().cend (); )
{
if (!TtlExceeded (it, now))
{
if ((*it)->GetHeader ().IsData () && (*it)->GetDestinationAddress () == dest)
{
nPackets++;
}
it++;
}
}
NS_LOG_DEBUG ("returns " << nPackets);
return nPackets;
return GetContainer ().GetQueue (queueId).size ();
}
uint32_t
WifiMacQueue::GetNPacketsByTidAndAddress (uint8_t tid, Mac48Address dest)
WifiMacQueue::GetNBytes (const WifiContainerQueueId& queueId) const
{
NS_LOG_FUNCTION (this << dest);
uint32_t nPackets = 0;
const Time now = Simulator::Now ();
for (ConstIterator it = GetContainer ().cbegin (); it != GetContainer ().cend (); )
{
if (!TtlExceeded (it, now))
{
if ((*it)->GetHeader ().IsQosData () && (*it)->GetDestinationAddress () == dest
&& (*it)->GetHeader ().GetQosTid () == tid)
{
nPackets++;
}
it++;
}
}
NS_LOG_DEBUG ("returns " << nPackets);
return nPackets;
}
bool
WifiMacQueue::IsEmpty (void)
{
NS_LOG_FUNCTION (this);
const Time now = Simulator::Now ();
for (ConstIterator it = GetContainer ().cbegin (); it != GetContainer ().cend (); )
{
if (!TtlExceeded (it, now))
{
NS_LOG_DEBUG ("returns false");
return false;
}
}
NS_LOG_DEBUG ("returns true");
return true;
}
uint32_t
WifiMacQueue::GetNPackets (void)
{
NS_LOG_FUNCTION (this);
const Time now = Simulator::Now ();
// remove packets that stayed in the queue for too long
for (ConstIterator it = GetContainer ().cbegin (); it != GetContainer ().cend (); )
{
if (!TtlExceeded (it, now))
{
it++;
}
}
return QueueBase::GetNPackets ();
}
uint32_t
WifiMacQueue::GetNBytes (void)
{
NS_LOG_FUNCTION (this);
const Time now = Simulator::Now ();
// remove packets that stayed in the queue for too long
for (ConstIterator it = GetContainer ().cbegin (); it != GetContainer ().cend (); )
{
if (!TtlExceeded (it, now))
{
it++;
}
}
return QueueBase::GetNBytes ();
}
uint32_t
WifiMacQueue::GetNPackets (uint8_t tid, Mac48Address dest) const
{
WifiAddressTidPair addressTidPair (dest, tid);
auto it = m_nQueuedPackets.find (addressTidPair);
if (it == m_nQueuedPackets.end ())
{
return 0;
}
return m_nQueuedPackets.at (addressTidPair);
}
uint32_t
WifiMacQueue::GetNBytes (uint8_t tid, Mac48Address dest) const
{
WifiAddressTidPair addressTidPair (dest, tid);
auto it = m_nQueuedBytes.find (addressTidPair);
if (it == m_nQueuedBytes.end ())
{
return 0;
}
return m_nQueuedBytes.at (addressTidPair);
return GetContainer ().GetNBytes (queueId);
}
bool
WifiMacQueue::DoEnqueue (ConstIterator pos, Ptr<WifiMacQueueItem> item)
{
Iterator ret;
if (Queue<WifiMacQueueItem>::DoEnqueue (pos, item, ret))
NS_LOG_FUNCTION (this << *item);
auto mpdu = m_scheduler->HasToDropBeforeEnqueue (m_ac, item);
if (mpdu == item)
{
// the given item must be dropped
return false;
}
auto queueId = WifiMacQueueContainer::GetQueueId (item);
if (pos != GetContainer ().GetQueue (queueId).cend () && pos->mpdu == mpdu)
{
// the element pointed to by pos must be dropped; update insert position
pos = std::next (pos);
}
if (mpdu != nullptr)
{
DoRemove (GetIt (mpdu));
}
Iterator ret;
if (Queue<WifiMacQueueItem, WifiMacQueueContainer>::DoEnqueue (pos, item, ret))
{
// update statistics about queued packets
if (item->GetHeader ().IsQosData ())
{
WifiAddressTidPair addressTidPair (item->GetHeader ().GetAddr1 (), item->GetHeader ().GetQosTid ());
auto it = m_nQueuedPackets.find (addressTidPair);
if (it == m_nQueuedPackets.end ())
{
m_nQueuedPackets[addressTidPair] = 0;
m_nQueuedBytes[addressTidPair] = 0;
}
m_nQueuedPackets[addressTidPair]++;
m_nQueuedBytes[addressTidPair] += item->GetSize ();
}
// set item's information about its position in the queue
item->m_queueAc = m_ac;
item->m_queueIt = ret;
item->SetQueueIt (ret, {});
ret->ac = m_ac;
ret->expiryTime = Simulator::Now () + m_maxDelay;
WmqIteratorTag tag;
ret->deleter = [tag](auto mpdu){ mpdu->SetQueueIt (std::nullopt, tag); };
m_scheduler->NotifyEnqueue (m_ac, item);
return true;
}
return false;
}
Ptr<WifiMacQueueItem>
WifiMacQueue::DoDequeue (ConstIterator pos)
void
WifiMacQueue::DoDequeue (const std::list<ConstIterator>& iterators)
{
NS_LOG_FUNCTION (this);
Ptr<WifiMacQueueItem> item = Queue<WifiMacQueueItem>::DoDequeue (pos);
std::list<Ptr<WifiMacQueueItem>> items;
if (item && item->GetHeader ().IsQosData ())
// First, dequeue all the items
for (auto& it : iterators)
{
WifiAddressTidPair addressTidPair (item->GetHeader ().GetAddr1 (), item->GetHeader ().GetQosTid ());
NS_ASSERT (m_nQueuedPackets.find (addressTidPair) != m_nQueuedPackets.end ());
NS_ASSERT (m_nQueuedPackets[addressTidPair] >= 1);
NS_ASSERT (m_nQueuedBytes[addressTidPair] >= item->GetSize ());
m_nQueuedPackets[addressTidPair]--;
m_nQueuedBytes[addressTidPair] -= item->GetSize ();
if (auto item = Queue<WifiMacQueueItem, WifiMacQueueContainer>::DoDequeue (it); item)
{
items.push_back (item);
}
}
if (item)
// Then, notify the scheduler
if (!items.empty ())
{
NS_ASSERT (item->IsQueued ());
item->m_queueAc = AC_UNDEF;
m_scheduler->NotifyDequeue (m_ac, items);
}
return item;
}
Ptr<WifiMacQueueItem>
WifiMacQueue::DoRemove (ConstIterator pos)
{
Ptr<WifiMacQueueItem> item = Queue<WifiMacQueueItem>::DoRemove (pos);
NS_LOG_FUNCTION (this);
if (item && item->GetHeader ().IsQosData ())
{
WifiAddressTidPair addressTidPair (item->GetHeader ().GetAddr1 (), item->GetHeader ().GetQosTid ());
NS_ASSERT (m_nQueuedPackets.find (addressTidPair) != m_nQueuedPackets.end ());
NS_ASSERT (m_nQueuedPackets[addressTidPair] >= 1);
NS_ASSERT (m_nQueuedBytes[addressTidPair] >= item->GetSize ());
m_nQueuedPackets[addressTidPair]--;
m_nQueuedBytes[addressTidPair] -= item->GetSize ();
}
auto item = Queue<WifiMacQueueItem, WifiMacQueueContainer>::DoRemove (pos);
if (item)
{
NS_ASSERT (item->IsQueued ());
item->m_queueAc = AC_UNDEF;
m_scheduler->NotifyRemove (m_ac, {item});
}
return item;

View File

@@ -25,6 +25,7 @@
#define WIFI_MAC_QUEUE_H
#include "wifi-mac-queue-item.h"
#include "wifi-mac-queue-container.h"
#include "ns3/queue.h"
#include <unordered_map>
#include "qos-utils.h"
@@ -33,13 +34,14 @@
namespace ns3 {
class QosBlockedDestinations;
class WifiMacQueueScheduler;
// The following explicit template instantiation declaration prevents modules
// including this header file from implicitly instantiating Queue<WifiMacQueueItem>.
// This would cause python examples using wifi to crash at runtime with the
// following error message: "Trying to allocate twice the same UID:
// ns3::Queue<WifiMacQueueItem>"
extern template class Queue<WifiMacQueueItem>;
extern template class Queue<WifiMacQueueItem, ns3::WifiMacQueueContainer>;
/**
@@ -56,8 +58,11 @@ extern template class Queue<WifiMacQueueItem>;
* to verify whether or not it should be dropped. If
* dot11EDCATableMSDULifetime has elapsed, it is dropped.
* Otherwise, it is returned to the caller.
*
* Compiling python bindings fails if the namespace (ns3) is not
* specified for WifiMacQueueContainerT.
*/
class WifiMacQueue : public Queue<WifiMacQueueItem>
class WifiMacQueue : public Queue<WifiMacQueueItem, ns3::WifiMacQueueContainer>
{
public:
/**
@@ -75,17 +80,26 @@ public:
~WifiMacQueue ();
/// drop policy
enum DropPolicy
{
DROP_NEWEST,
DROP_OLDEST
};
/// allow the usage of iterators and const iterators
using Queue<WifiMacQueueItem>::ConstIterator;
using Queue<WifiMacQueueItem>::Iterator;
using Queue<WifiMacQueueItem>::GetContainer;
using Queue<WifiMacQueueItem, WifiMacQueueContainer>::ConstIterator;
using Queue<WifiMacQueueItem, WifiMacQueueContainer>::Iterator;
using Queue<WifiMacQueueItem, WifiMacQueueContainer>::IsEmpty;
using Queue<WifiMacQueueItem, WifiMacQueueContainer>::GetNPackets;
using Queue<WifiMacQueueItem, WifiMacQueueContainer>::GetNBytes;
/**
* Get the Access Category of the packets stored in this queue
*
* \return the Access Category of the packets stored in this queue
*/
AcIndex GetAc (void) const;
/**
* Set the wifi MAC queue scheduler
*
* \param scheduler the wifi MAC queue scheduler
*/
void SetScheduler (Ptr<WifiMacQueueScheduler> scheduler);
/**
* Set the maximum delay before the packet is discarded.
@@ -107,13 +121,6 @@ public:
* \return true if success, false if the packet has been dropped
*/
bool Enqueue (Ptr<WifiMacQueueItem> item) override;
/**
* Enqueue the given Wifi MAC queue item at the <i>front</i> of the queue.
*
* \param item the Wifi MAC queue item to be enqueued at the front
* \return true if success, false if the packet has been dropped
*/
bool PushFront (Ptr<WifiMacQueueItem> item);
/**
* Dequeue the packet in the front of the queue.
*
@@ -121,11 +128,11 @@ public:
*/
Ptr<WifiMacQueueItem> Dequeue (void) override;
/**
* Dequeue the given MPDU if it is stored in this queue.
* Dequeue the given MPDUs if they are stored in this queue.
*
* \param mpdu the given MPDU
* \param mpdus the given MPDUs
*/
void DequeueIfQueued (Ptr<const WifiMacQueueItem> mpdu);
void DequeueIfQueued (const std::list<Ptr<const WifiMacQueueItem>>& mpdus);
/**
* Peek the packet in the front of the queue. The packet is not removed.
*
@@ -133,33 +140,13 @@ public:
*/
Ptr<const WifiMacQueueItem> Peek (void) const override;
/**
* Search and return, if present in the queue, the first packet (either Data
* frame or QoS Data frame) having the receiver address equal to <i>addr</i>.
* If <i>item</i> is not a null pointer, the search starts from the packet following
* <i>item</i> in the queue; otherwise, the search starts from the head of the queue.
* This method does not remove the packet from the queue.
* Peek the packet in the front of the queue for transmission on the given
* link. The packet is not removed.
*
* \param dest the given destination
* \param item the item after which the search starts from
*
* \return the peeked packet or nullptr if no packet was found
* \param linkId the ID of the link onto which we can transmit a packet
* \return the packet
*/
Ptr<WifiMacQueueItem> PeekByAddress (Mac48Address dest,
Ptr<const WifiMacQueueItem> item = nullptr) const;
/**
* Search and return, if present in the queue, the first packet having the
* TID equal to <i>tid</i>. If <i>item</i> is not a null pointer, the search
* starts from the packet following <i>item</i> in the queue; otherwise, the
* search starts from the head of the queue.
* This method does not remove the packet from the queue.
*
* \param tid the given TID
* \param item the item after which the search starts from
*
* \return the peeked packet or nullptr if no packet was found
*/
Ptr<WifiMacQueueItem> PeekByTid (uint8_t tid,
Ptr<const WifiMacQueueItem> item = nullptr) const;
Ptr<WifiMacQueueItem> Peek (uint8_t linkId) const;
/**
* Search and return, if present in the queue, the first packet having the
* receiver address equal to <i>dest</i>, and TID equal to <i>tid</i>.
@@ -177,6 +164,23 @@ public:
*/
Ptr<WifiMacQueueItem> PeekByTidAndAddress (uint8_t tid, Mac48Address dest,
Ptr<const WifiMacQueueItem> item = nullptr) const;
/**
* Search and return the first packet present in the container queue identified
* by the given queue ID. If <i>item</i> is a null pointer, the search starts from
* the head of the container queue; MPDUs with expired lifetime at the head of the
* container queue are ignored (and moved to the container queue storing MPDUs with
* expired lifetime). If <i>item</i> is not a null pointer, the search starts from
* the packet following <i>item</i> in the container queue (and we do not check for
* expired lifetime because we assume that a previous call was made with a null
* pointer as argument, which removed the MPDUs with expired lifetime).
*
* \param queueId the given queue ID
* \param item the item after which the search starts from
* \return the peeked packet or nullptr if no packet was found
*/
Ptr<WifiMacQueueItem> PeekByQueueId (const WifiContainerQueueId& queueId,
Ptr<const WifiMacQueueItem> item = nullptr) const;
/**
* Return first available packet for transmission. If <i>item</i> is not a null
* pointer, the search starts from the packet following <i>item</i> in the queue;
@@ -203,10 +207,9 @@ public:
* removed if their lifetime expired.
*
* \param item the item to be removed
* \param removeExpired true to remove expired items
* \return the item following the removed one, if any, or a null pointer, otherwise
* \return the removed item
*/
Ptr<const WifiMacQueueItem> Remove (Ptr<const WifiMacQueueItem> item, bool removeExpired = false);
Ptr<WifiMacQueueItem> Remove (Ptr<const WifiMacQueueItem> item);
/**
* Replace the given current item with the given new item. Actually, the current
@@ -217,99 +220,24 @@ public:
* \param newItem the given new item
*/
void Replace (Ptr<const WifiMacQueueItem> currentItem, Ptr<WifiMacQueueItem> newItem);
/**
* Transform the given item by invoking the given function with the given item
* as parameter. The given function must be an object of a callable type
* and must have an argument of type pointer to WifiMacQueueItem.
* Actually, the given item is dequeued and the transformed item is enqueued in
* its place. In this way, statistics about queue size (in terms of bytes) are
* correctly updated.
*
* \internal
* If this method needs to be overloaded, we can use SFINAE to help in overload
* resolution:
*
* \code
* template <class CALLABLE,
* std::invoke_result_t<CALLABLE, Ptr<WifiMacQueueItem>>* = nullptr>
* void Transform (Ptr<const WifiMacQueueItem> item, CALLABLE func);
* \endcode
*
* Unfortunately, this will break python bindings scanning.
*
* \tparam CALLABLE \deduced The type of the given function object
* \param item the given item
* \param func the given function object
*/
template <class CALLABLE>
void Transform (Ptr<const WifiMacQueueItem> item, CALLABLE func);
/**
* Return the number of packets having destination address specified by
* <i>dest</i>. The complexity is linear in the size of the queue.
* Get the number of MPDUs currently stored in the container queue identified
* by the given queue ID.
*
* \param dest the given destination
*
* \return the number of packets
* \param queueId the given queue ID
* \return the number of MPDUs currently stored in the container queue
*/
uint32_t GetNPacketsByAddress (Mac48Address dest);
/**
* Return the number of QoS packets having TID equal to <i>tid</i> and
* destination address equal to <i>dest</i>. The complexity is linear in
* the size of the queue.
*
* \param tid the given TID
* \param dest the given destination
*
* \return the number of QoS packets
*/
uint32_t GetNPacketsByTidAndAddress (uint8_t tid, Mac48Address dest);
uint32_t GetNPackets (const WifiContainerQueueId& queueId) const;
/**
* Return the number of QoS packets in the queue having tid equal to <i>tid</i>
* and destination address equal to <i>dest</i>. The complexity in the average
* case is constant. However, packets expired since the last non-const
* operation on the queue are included in the returned count.
* Get the amount of bytes currently stored in the container queue identified
* by the given queue ID.
*
* \param tid the given TID
* \param dest the given destination
*
* \return the number of QoS packets in the queue
* \param queueId the given queue ID
* \return the amount of bytes currently stored in the container queue
*/
uint32_t GetNPackets (uint8_t tid, Mac48Address dest) const;
/**
* Return the number of bytes in the queue having tid equal to <i>tid</i> and
* destination address equal to <i>dest</i>. The complexity in the average
* case is constant. However, packets expired since the last non-const
* operation on the queue are included in the returned count.
*
* \param tid the given TID
* \param dest the given destination
*
* \return the number of bytes in the queue
*/
uint32_t GetNBytes (uint8_t tid, Mac48Address dest) const;
/**
* \return true if the queue is empty; false otherwise
*
* Overrides the IsEmpty method provided by QueueBase
*/
bool IsEmpty (void);
/**
* \return The number of packets currently stored in the Queue
*
* Overrides the GetNPackets method provided by QueueBase
*/
uint32_t GetNPackets (void);
/**
* \return The number of bytes currently occupied by the packets in the Queue
*
* Overrides the GetNBytes method provided by QueueBase
*/
uint32_t GetNBytes (void);
uint32_t GetNBytes (const WifiContainerQueueId& queueId) const;
/**
* Remove the given item if it has been in the queue for too long. Return true
@@ -321,17 +249,44 @@ public:
*/
bool TtlExceeded (Ptr<const WifiMacQueueItem> item, const Time& now);
/**
* Move MPDUs with expired lifetime from the container queue identified by the
* given queue ID to the container queue storing MPDUs with expired lifetime.
* Each MPDU that is found to have an expired lifetime feeds the "Expired"
* trace source and is notified to the scheduler.
* \note that such MPDUs are not removed from the WifiMacQueue (and hence are
* still accounted for in the overall statistics kept by the Queue base class)
* in order to make this method const.
*
* \param queueId the given queue ID
*/
void ExtractExpiredMpdus (const WifiContainerQueueId& queueId) const;
/**
* Move MPDUs with expired lifetime from all the container queues to the
* container queue storing MPDUs with expired lifetime. Each MPDU that is found
* to have an expired lifetime feeds the "Expired" trace source and is notified
* to the scheduler.
* \note that such MPDUs are not removed from the WifiMacQueue (and hence are
* still accounted for in the overall statistics kept by the Queue base class)
* in order to make this method const.
*/
void ExtractAllExpiredMpdus (void) const;
/**
* Remove all MPDUs with expired lifetime from this WifiMacQueue object.
*/
void WipeAllExpiredMpdus (void);
protected:
using Queue<WifiMacQueueItem, WifiMacQueueContainer>::GetContainer;
void DoDispose (void) override;
private:
/**
* Remove the item pointed to by the iterator <i>it</i> if it has been in the
* queue for too long. If the item is removed, the iterator is updated to
* point to the item that followed the erased one.
*
* \param it an iterator pointing to the item
* \param now a copy of Simulator::Now()
* \return true if the item is removed, false otherwise
* \param mpdu the given MPDU
* \return the queue iterator stored by the given MPDU
*/
inline bool TtlExceeded (ConstIterator &it, const Time& now);
Iterator GetIt (Ptr<const WifiMacQueueItem> mpdu) const;
/**
* Enqueue the given Wifi MAC queue item before the given position.
@@ -353,31 +308,25 @@ private:
bool DoEnqueue (ConstIterator pos, Ptr<WifiMacQueueItem> item);
/**
* Wrapper for the DoDequeue method provided by the base class that additionally
* resets the iterator field of the item and updates internal statistics, if
* an item was dequeued.
* resets the iterator field of the dequeued items and notifies the scheduler, if
* any item was dequeued.
*
* \param pos the position of the item to dequeue
* \return the item.
* \param iterators the list of iterators pointing to the items to dequeue
*/
Ptr<WifiMacQueueItem> DoDequeue (ConstIterator pos);
void DoDequeue (const std::list<ConstIterator>& iterators);
/**
* Wrapper for the DoRemove method provided by the base class that additionally
* resets the iterator field of the item and updates internal statistics, if
* an item was dropped.
* resets the iterator field of the item and notifies the scheduleer, if an
* item was dropped.
*
* \param pos the position of the item to drop
* \return the item.
* \return the dropped item.
*/
Ptr<WifiMacQueueItem> DoRemove (ConstIterator pos);
Time m_maxDelay; //!< Time to live for packets in the queue
DropPolicy m_dropPolicy; //!< Drop behavior of queue
AcIndex m_ac; //!< the access category
/// Per (MAC address, TID) pair queued packets
std::unordered_map<WifiAddressTidPair, uint32_t, WifiAddressTidHash> m_nQueuedPackets;
/// Per (MAC address, TID) pair queued bytes
std::unordered_map<WifiAddressTidPair, uint32_t, WifiAddressTidHash> m_nQueuedBytes;
Ptr<WifiMacQueueScheduler> m_scheduler; //!< the MAC queue scheduler
/// Traced callback: fired when a packet is dropped due to lifetime expiration
TracedCallback<Ptr<const WifiMacQueueItem> > m_traceExpired;
@@ -387,31 +336,4 @@ private:
} // namespace ns3
/***************************************************************
* Implementation of the templates declared above.
***************************************************************/
namespace ns3 {
template <class CALLABLE>
void
WifiMacQueue::Transform (Ptr<const WifiMacQueueItem> item, CALLABLE func)
{
NS_ASSERT (item->IsQueued ());
NS_ASSERT (item->m_queueAc == m_ac);
NS_ASSERT (*item->m_queueIt == item);
auto pos = std::next (item->m_queueIt);
Ptr<WifiMacQueueItem> mpdu = DoDequeue (item->m_queueIt);
NS_ASSERT (mpdu);
func (mpdu); // python bindings scanning does not like std::invoke (func, mpdu);
bool ret = Insert (pos, mpdu);
// The size of a WifiMacQueue is measured as number of packets. We dequeued
// one packet, so there is certainly room for inserting one packet
NS_ABORT_IF (!ret);
}
} //namespace ns3
#endif /* WIFI_MAC_QUEUE_H */

View File

@@ -36,6 +36,7 @@
#include "ns3/eht-configuration.h"
#include "ns3/he-frame-exchange-manager.h"
#include "extended-capabilities.h"
#include "wifi-mac-queue-scheduler.h"
namespace ns3 {
@@ -355,6 +356,11 @@ WifiMac::DoDispose ()
}
m_device = 0;
if (m_scheduler != nullptr)
{
m_scheduler->Dispose ();
}
m_scheduler = nullptr;
}
WifiMac::LinkEntity::~LinkEntity ()
@@ -501,6 +507,19 @@ WifiMac::GetTxopQueue (AcIndex ac) const
return (txop ? txop->GetWifiMacQueue () : nullptr);
}
void
WifiMac::SetMacQueueScheduler (Ptr<WifiMacQueueScheduler> scheduler)
{
m_scheduler = scheduler;
m_scheduler->SetWifiMac (this);
}
Ptr<WifiMacQueueScheduler>
WifiMac::GetMacQueueScheduler (void) const
{
return m_scheduler;
}
void
WifiMac::NotifyChannelSwitching (void)
{

View File

@@ -49,6 +49,7 @@ class EhtConfiguration;
class FrameExchangeManager;
class ChannelAccessManager;
class ExtendedCapabilities;
class WifiMacQueueScheduler;
/**
* Enumeration for type of station
@@ -175,6 +176,19 @@ public:
*/
virtual Ptr<WifiMacQueue> GetTxopQueue (AcIndex ac) const;
/**
* Set the wifi MAC queue scheduler
*
* \param scheduler the wifi MAC queue scheduler
*/
virtual void SetMacQueueScheduler (Ptr<WifiMacQueueScheduler> scheduler);
/**
* Get the wifi MAC queue scheduler
*
* \return the wifi MAC queue scheduler
*/
Ptr<WifiMacQueueScheduler> GetMacQueueScheduler (void) const;
/**
* This method is invoked by a subclass to specify what type of
* station it is implementing. This is something that the channel
@@ -617,6 +631,7 @@ protected:
Ptr<MacRxMiddle> m_rxMiddle; //!< RX middle (defragmentation etc.)
Ptr<MacTxMiddle> m_txMiddle; //!< TX middle (aggregation etc.)
Ptr<Txop> m_txop; //!< TXOP used for transmission of frames to non-QoS peers.
Ptr<WifiMacQueueScheduler> m_scheduler; //!< wifi MAC queue scheduler
Callback<void> m_linkUp; //!< Callback when a link is up
Callback<void> m_linkDown; //!< Callback when a link is down

View File

@@ -30,6 +30,7 @@
#include "ns3/interference-helper.h"
#include "ns3/wifi-default-protection-manager.h"
#include "ns3/wifi-default-ack-manager.h"
#include "ns3/fcfs-wifi-queue-scheduler.h"
using namespace ns3;
@@ -119,6 +120,7 @@ PowerRateAdaptationTest::ConfigureNode ()
mac->SetAddress (Mac48Address::Allocate ());
dev->SetMac (mac);
mac->ConfigureStandard (WIFI_STANDARD_80211a);
mac->SetMacQueueScheduler (CreateObject<FcfsWifiQueueScheduler> ());
Ptr<FrameExchangeManager> fem = mac->GetFrameExchangeManager ();
Ptr<WifiProtectionManager> protectionManager = CreateObject<WifiDefaultProtectionManager> ();

View File

@@ -44,6 +44,7 @@
#include "ns3/packet-socket-helper.h"
#include "ns3/wifi-default-protection-manager.h"
#include "ns3/wifi-default-ack-manager.h"
#include "ns3/fcfs-wifi-queue-scheduler.h"
#include <iterator>
#include <algorithm>
@@ -138,6 +139,7 @@ AmpduAggregationTest::DoRun (void)
fem->SetAckManager (ackManager);
m_device->SetMac (m_mac);
m_mac->SetState (StaWifiMac::ASSOCIATED);
m_mac->SetMacQueueScheduler (CreateObject<FcfsWifiQueueScheduler> ());
/*
* Configure MPDU aggregation.
@@ -389,6 +391,7 @@ TwoLevelAggregationTest::DoRun (void)
fem->SetAckManager (ackManager);
m_device->SetMac (m_mac);
m_mac->SetState (StaWifiMac::ASSOCIATED);
m_mac->SetMacQueueScheduler (CreateObject<FcfsWifiQueueScheduler> ());
/*
* Configure aggregation.
@@ -627,6 +630,7 @@ HeAggregationTest::DoRunSubTest (uint16_t bufferSize)
fem->SetAckManager (ackManager);
m_device->SetMac (m_mac);
m_mac->SetState (StaWifiMac::ASSOCIATED);
m_mac->SetMacQueueScheduler (CreateObject<FcfsWifiQueueScheduler> ());
/*
* Configure aggregation.

View File

@@ -483,13 +483,24 @@ OfdmaAckSequenceTest::Transmit (std::string context, WifiConstPsduMap psduMap, W
auto dev = DynamicCast<WifiNetDevice> (m_apDevice);
Ptr<WifiMacQueue> queue = dev->GetMac ()->GetQosTxop (AC_BE)->GetWifiMacQueue ();
m_flushed = 0;
for (auto it = queue->GetContainer ().begin (); it != queue->GetContainer ().end (); )
for (uint32_t i = 0; i < m_staDevices.GetN (); i++)
{
auto tmp = it++;
if (!(*tmp)->IsInFlight ())
auto staDev = DynamicCast<WifiNetDevice> (m_staDevices.Get (i));
Ptr<const WifiMacQueueItem> lastInFlight = nullptr;
Ptr<const WifiMacQueueItem> mpdu;
while ((mpdu = queue->PeekByTidAndAddress (0, staDev->GetMac ()->GetAddress (),
lastInFlight)) != nullptr)
{
queue->Remove (*tmp, false);
m_flushed++;
if (mpdu->IsInFlight ())
{
lastInFlight = mpdu;
}
else
{
queue->Remove (mpdu);
m_flushed++;
}
}
}
}

View File

@@ -20,6 +20,7 @@
#include "ns3/test.h"
#include "ns3/wifi-mac-queue.h"
#include "ns3/fcfs-wifi-queue-scheduler.h"
#include "ns3/simulator.h"
using namespace ns3;
@@ -55,55 +56,64 @@ WifiMacQueueDropOldestTest::DoRun ()
{
auto wifiMacQueue = CreateObject<WifiMacQueue> (AC_BE);
wifiMacQueue->SetMaxSize (QueueSize ("5p"));
wifiMacQueue->SetAttribute ("DropPolicy", EnumValue (WifiMacQueue::DROP_OLDEST));
auto wifiMacScheduler = CreateObject<FcfsWifiQueueScheduler> ();
wifiMacScheduler->SetAttribute ("DropPolicy", EnumValue (FcfsWifiQueueScheduler::DROP_OLDEST));
wifiMacScheduler->m_perAcInfo[AC_BE].wifiMacQueue = wifiMacQueue;
wifiMacQueue->SetScheduler (wifiMacScheduler);
Mac48Address addr1 = Mac48Address::Allocate ();
// Initialize the queue with 5 packets.
std::vector<uint64_t> packetUids;
std::list<uint64_t> packetUids;
for (uint32_t i = 0; i < 5; i++)
{
WifiMacHeader header;
header.SetType (WIFI_MAC_QOSDATA);
header.SetAddr1 (addr1);
header.SetQosTid (0);
auto packet = Create<Packet> ();
auto item = Create<WifiMacQueueItem> (packet, header);
wifiMacQueue->PushFront (item);
wifiMacQueue->Enqueue (item);
packetUids.push_back (packet->GetUid ());
}
// Check that all elements are inserted successfully.
auto it = wifiMacQueue->GetContainer ().begin ();
auto mpdu = wifiMacQueue->PeekByTidAndAddress (0, addr1);
NS_TEST_EXPECT_MSG_EQ (wifiMacQueue->GetNPackets (), 5, "Queue has unexpected number of elements");
for (uint32_t i = 5; i > 0; i--)
for (auto packetUid : packetUids)
{
NS_TEST_EXPECT_MSG_EQ ((*it)->GetPacket ()->GetUid (),
packetUids.at (i - 1),
NS_TEST_EXPECT_MSG_EQ (mpdu->GetPacket ()->GetUid (),
packetUid,
"Stored packet is not the expected one");
it++;
mpdu = wifiMacQueue->PeekByTidAndAddress (0, addr1, mpdu);
}
// Push another element in front of the queue.
// Push another element into the queue.
WifiMacHeader header;
header.SetType (WIFI_MAC_QOSDATA);
header.SetAddr1 (addr1);
header.SetQosTid (0);
auto packet = Create<Packet> ();
auto item = Create<WifiMacQueueItem> (packet, header);
wifiMacQueue->PushFront (item);
wifiMacQueue->Enqueue (item);
// Update the vector of expected packet UIDs.
packetUids.at (4) = packet->GetUid ();
// Update the list of expected packet UIDs.
packetUids.pop_front ();
packetUids.push_back (packet->GetUid ());
// Check that front packet was replaced correctly.
it = wifiMacQueue->GetContainer ().begin ();
mpdu = wifiMacQueue->PeekByTidAndAddress (0, addr1);
NS_TEST_EXPECT_MSG_EQ (wifiMacQueue->GetNPackets (), 5, "Queue has unexpected number of elements");
for (uint32_t i = 5; i > 0; i--)
for (auto packetUid : packetUids)
{
NS_TEST_EXPECT_MSG_EQ ((*it)->GetPacket ()->GetUid (),
packetUids.at (i - 1),
NS_TEST_EXPECT_MSG_EQ (mpdu->GetPacket ()->GetUid (),
packetUid,
"Stored packet is not the expected one");
it++;
mpdu = wifiMacQueue->PeekByTidAndAddress (0, addr1, mpdu);
}
wifiMacScheduler->Dispose ();
Simulator::Destroy ();
}

View File

@@ -54,6 +54,7 @@
#include "ns3/wifi-default-protection-manager.h"
#include "ns3/wifi-default-ack-manager.h"
#include "ns3/wifi-default-assoc-manager.h"
#include "ns3/fcfs-wifi-queue-scheduler.h"
using namespace ns3;
@@ -165,6 +166,7 @@ WifiTest::CreateOne (Vector pos, Ptr<YansWifiChannel> channel)
{
StaticCast<StaWifiMac> (mac)->SetAssocManager (CreateObject<WifiDefaultAssocManager> ());
}
mac->SetMacQueueScheduler (CreateObject<FcfsWifiQueueScheduler> ());
Ptr<FrameExchangeManager> fem = mac->GetFrameExchangeManager ();
Ptr<WifiProtectionManager> protectionManager = CreateObject<WifiDefaultProtectionManager> ();
protectionManager->SetWifiMac (mac);
@@ -344,6 +346,7 @@ InterferenceHelperSequenceTest::CreateOne (Vector pos, Ptr<YansWifiChannel> chan
mac->SetAddress (Mac48Address::Allocate ());
dev->SetMac (mac);
mac->ConfigureStandard (WIFI_STANDARD_80211a);
mac->SetMacQueueScheduler (CreateObject<FcfsWifiQueueScheduler> ());
Ptr<FrameExchangeManager> fem = mac->GetFrameExchangeManager ();
Ptr<WifiProtectionManager> protectionManager = CreateObject<WifiDefaultProtectionManager> ();
protectionManager->SetWifiMac (mac);
@@ -553,6 +556,7 @@ DcfImmediateAccessBroadcastTestCase::DoRun (void)
txMac->SetAddress (Mac48Address::Allocate ());
txDev->SetMac (txMac);
txMac->ConfigureStandard (WIFI_STANDARD_80211a);
txMac->SetMacQueueScheduler (CreateObject<FcfsWifiQueueScheduler> ());
auto fem = txMac->GetFrameExchangeManager ();
auto protectionManager = CreateObject<WifiDefaultProtectionManager> ();
protectionManager->SetWifiMac (txMac);
@@ -1769,6 +1773,7 @@ Bug2831TestCase::DoRun (void)
apMac->SetAddress (Mac48Address::Allocate ());
apDev->SetMac (apMac);
apMac->ConfigureStandard (WIFI_STANDARD_80211ax);
apMac->SetMacQueueScheduler (CreateObject<FcfsWifiQueueScheduler> ());
Ptr<FrameExchangeManager> fem = apMac->GetFrameExchangeManager ();
Ptr<WifiProtectionManager> protectionManager = CreateObject<WifiDefaultProtectionManager> ();
protectionManager->SetWifiMac (apMac);
@@ -1807,6 +1812,7 @@ Bug2831TestCase::DoRun (void)
staMac->SetAddress (Mac48Address::Allocate ());
staMac->ConfigureStandard (WIFI_STANDARD_80211ax);
StaticCast<StaWifiMac> (staMac)->SetAssocManager (CreateObject<WifiDefaultAssocManager> ());
staMac->SetMacQueueScheduler (CreateObject<FcfsWifiQueueScheduler> ());
fem = staMac->GetFrameExchangeManager ();
protectionManager = CreateObject<WifiDefaultProtectionManager> ();
protectionManager->SetWifiMac (staMac);