wifi: Rework wifi MAC queues
Also, add a First Come First Serve wifi MAC queue scheduler
This commit is contained in:
committed by
Stefano Avallone
parent
b47a59135d
commit
4e70063f8c
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
157
src/wifi/model/fcfs-wifi-queue-scheduler.cc
Normal file
157
src/wifi/model/fcfs-wifi-queue-scheduler.cc
Normal 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
|
||||
66
src/wifi/model/fcfs-wifi-queue-scheduler.h
Normal file
66
src/wifi/model/fcfs-wifi-queue-scheduler.h
Normal 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 */
|
||||
@@ -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});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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> ();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user