Files
unison/src/wifi/model/wifi-mac-queue.cc
Stefano Avallone 62542e5fb9 wifi: WifiMacQueueItem does not keep a pointer to the queue it is stored into
Instead, it keeps the AC index associated with the queue it is stored into
2021-09-26 17:06:27 +00:00

585 lines
15 KiB
C++

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2005, 2009 INRIA
* Copyright (c) 2009 MIRKO BANCHI
*
* 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
*
* Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
* Mirko Banchi <mk.banchi@gmail.com>
* Stefano Avallone <stavallo@unina.it>
*/
#include "ns3/simulator.h"
#include "wifi-mac-queue.h"
#include "qos-blocked-destinations.h"
#include <functional>
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("WifiMacQueue");
NS_OBJECT_ENSURE_REGISTERED (WifiMacQueue);
NS_OBJECT_TEMPLATE_CLASS_DEFINE (Queue, WifiMacQueueItem);
TypeId
WifiMacQueue::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::WifiMacQueue")
.SetParent<Queue<WifiMacQueueItem> > ()
.SetGroupName ("Wifi")
.AddConstructor<WifiMacQueue> ()
.AddAttribute ("MaxSize",
"The max queue size",
QueueSizeValue (QueueSize ("500p")),
MakeQueueSizeAccessor (&QueueBase::SetMaxSize,
&QueueBase::GetMaxSize),
MakeQueueSizeChecker ())
.AddAttribute ("MaxDelay", "If a packet stays longer than this delay in the queue, it is dropped.",
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")
;
return tid;
}
WifiMacQueue::WifiMacQueue (AcIndex ac)
: m_ac (ac),
NS_LOG_TEMPLATE_DEFINE ("WifiMacQueue")
{
}
WifiMacQueue::~WifiMacQueue ()
{
NS_LOG_FUNCTION_NOARGS ();
m_nQueuedPackets.clear ();
m_nQueuedBytes.clear ();
}
static std::list<Ptr<WifiMacQueueItem>> g_emptyWifiMacQueue; //!< empty Wi-Fi MAC queue
const WifiMacQueue::ConstIterator WifiMacQueue::EMPTY = g_emptyWifiMacQueue.end ();
void
WifiMacQueue::SetMaxDelay (Time delay)
{
NS_LOG_FUNCTION (this << delay);
m_maxDelay = delay;
}
Time
WifiMacQueue::GetMaxDelay (void) const
{
return m_maxDelay;
}
bool
WifiMacQueue::Enqueue (Ptr<WifiMacQueueItem> item)
{
NS_LOG_FUNCTION (this << *item);
return Insert (end (), item);
}
bool
WifiMacQueue::PushFront (Ptr<WifiMacQueueItem> item)
{
NS_LOG_FUNCTION (this << *item);
return Insert (begin (), item);
}
bool
WifiMacQueue::Insert (ConstIterator pos, Ptr<WifiMacQueueItem> item)
{
NS_LOG_FUNCTION (this << *item);
NS_ASSERT_MSG (GetMaxSize ().GetUnit () == QueueSizeUnit::PACKETS,
"WifiMacQueues must be in packet mode");
// insert the item if the queue is not full
if (QueueBase::GetNPackets () < GetMaxSize ().GetValue ())
{
return DoEnqueue (pos, item);
}
// the queue is full; scan the list in the attempt to remove stale packets
ConstIterator it = begin ();
const Time now = Simulator::Now ();
while (it != end ())
{
if (it == pos && TtlExceeded (it, now))
{
return DoEnqueue (it, item);
}
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 == begin ())
{
// Avoid invalidating pos
DoRemove (begin ());
pos = begin ();
}
else
{
DoRemove (begin ());
}
}
return DoEnqueue (pos, item);
}
Ptr<WifiMacQueueItem>
WifiMacQueue::Dequeue (void)
{
NS_LOG_FUNCTION (this);
const Time now = Simulator::Now ();
for (ConstIterator it = begin (); it != end (); )
{
if (!TtlExceeded (it, now))
{
return DoDequeue (it);
}
}
NS_LOG_DEBUG ("The queue is empty");
return 0;
}
void
WifiMacQueue::DequeueIfQueued (Ptr<const WifiMacQueueItem> mpdu)
{
NS_LOG_FUNCTION (this << *mpdu);
if (mpdu->IsQueued ())
{
NS_ASSERT (mpdu->m_queueAc == m_ac);
NS_ASSERT (*mpdu->m_queueIt == mpdu);
DoDequeue (mpdu->m_queueIt);
}
}
Ptr<const WifiMacQueueItem>
WifiMacQueue::Peek (void) const
{
NS_LOG_FUNCTION (this);
const Time now = Simulator::Now ();
for (auto it = begin (); it != end (); it++)
{
// 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 0;
}
WifiMacQueue::ConstIterator
WifiMacQueue::PeekByAddress (Mac48Address dest, ConstIterator pos) const
{
NS_LOG_FUNCTION (this << dest);
ConstIterator it = (pos != EMPTY ? pos : begin ());
const Time now = Simulator::Now ();
while (it != end ())
{
// 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 end ();
}
WifiMacQueue::ConstIterator
WifiMacQueue::PeekByTid (uint8_t tid, ConstIterator pos) const
{
NS_LOG_FUNCTION (this << +tid);
ConstIterator it = (pos != EMPTY ? pos : begin ());
const Time now = Simulator::Now ();
while (it != end ())
{
// 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 end ();
}
WifiMacQueue::ConstIterator
WifiMacQueue::PeekByTidAndAddress (uint8_t tid, Mac48Address dest, ConstIterator pos) const
{
NS_LOG_FUNCTION (this << +tid << dest);
ConstIterator it = (pos != EMPTY ? pos : begin ());
const Time now = Simulator::Now ();
while (it != end ())
{
// 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++;
}
NS_LOG_DEBUG ("The queue is empty");
return end ();
}
WifiMacQueue::ConstIterator
WifiMacQueue::PeekFirstAvailable (const Ptr<QosBlockedDestinations> blockedPackets, ConstIterator pos) const
{
NS_LOG_FUNCTION (this);
ConstIterator it = (pos != EMPTY ? pos : begin ());
const Time now = Simulator::Now ();
while (it != end ())
{
// 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 () || !blockedPackets
|| !blockedPackets->IsBlocked ((*it)->GetHeader ().GetAddr1 (), (*it)->GetHeader ().GetQosTid ()))
{
return it;
}
}
it++;
}
NS_LOG_DEBUG ("The queue is empty");
return end ();
}
Ptr<WifiMacQueueItem>
WifiMacQueue::Remove (void)
{
NS_LOG_FUNCTION (this);
const Time now = Simulator::Now ();
for (ConstIterator it = begin (); it != end (); )
{
if (!TtlExceeded (it, now))
{
return DoRemove (it);
}
}
NS_LOG_DEBUG ("The queue is empty");
return 0;
}
bool
WifiMacQueue::Remove (Ptr<const Packet> packet)
{
NS_LOG_FUNCTION (this << packet);
const Time now = Simulator::Now ();
for (ConstIterator it = begin (); it != end (); )
{
if (!TtlExceeded (it, now))
{
if ((*it)->GetPacket () == packet)
{
DoRemove (it);
return true;
}
it++;
}
}
NS_LOG_DEBUG ("Packet " << packet << " not found in the queue");
return false;
}
WifiMacQueue::ConstIterator
WifiMacQueue::Remove (ConstIterator pos, bool removeExpired)
{
NS_LOG_FUNCTION (this);
if (!removeExpired)
{
ConstIterator curr = pos++;
DoRemove (curr);
return pos;
}
const Time now = Simulator::Now ();
// remove stale items queued before the given position
ConstIterator it = begin ();
while (it != end ())
{
if (it == pos)
{
ConstIterator curr = pos++;
DoRemove (curr);
return pos;
}
else if (!TtlExceeded (it, now))
{
it++;
}
}
NS_LOG_DEBUG ("Invalid iterator");
return end ();
}
uint32_t
WifiMacQueue::GetNPacketsByAddress (Mac48Address dest)
{
NS_LOG_FUNCTION (this << dest);
uint32_t nPackets = 0;
const Time now = Simulator::Now ();
for (ConstIterator it = begin (); it != end (); )
{
if (!TtlExceeded (it, now))
{
if ((*it)->GetHeader ().IsData () && (*it)->GetDestinationAddress () == dest)
{
nPackets++;
}
it++;
}
}
NS_LOG_DEBUG ("returns " << nPackets);
return nPackets;
}
uint32_t
WifiMacQueue::GetNPacketsByTidAndAddress (uint8_t tid, Mac48Address dest)
{
NS_LOG_FUNCTION (this << dest);
uint32_t nPackets = 0;
const Time now = Simulator::Now ();
for (ConstIterator it = begin (); it != end (); )
{
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 = begin (); it != end (); )
{
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 = begin (); it != end (); )
{
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 = begin (); it != end (); )
{
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);
}
bool
WifiMacQueue::DoEnqueue (ConstIterator pos, Ptr<WifiMacQueueItem> item)
{
Iterator ret;
if (Queue<WifiMacQueueItem>::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;
return true;
}
return false;
}
Ptr<WifiMacQueueItem>
WifiMacQueue::DoDequeue (ConstIterator pos)
{
NS_LOG_FUNCTION (this);
if (TtlExceeded (pos, Simulator::Now ()))
{
NS_LOG_DEBUG ("Packet lifetime expired");
return nullptr;
}
Ptr<WifiMacQueueItem> item = Queue<WifiMacQueueItem>::DoDequeue (pos);
if (item != 0 && 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 ();
}
if (item != 0)
{
NS_ASSERT (item->IsQueued ());
item->m_queueAc = AC_UNDEF;
}
return item;
}
Ptr<WifiMacQueueItem>
WifiMacQueue::DoRemove (ConstIterator pos)
{
Ptr<WifiMacQueueItem> item = Queue<WifiMacQueueItem>::DoRemove (pos);
if (item != 0 && 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 ();
}
if (item != 0)
{
NS_ASSERT (item->IsQueued ());
item->m_queueAc = AC_UNDEF;
}
return item;
}
} //namespace ns3