wifi: Improve handling of transmission opportunities

This commit is contained in:
Stefano Avallone
2019-03-07 17:14:56 +01:00
parent e9c69916c9
commit 6fba6dda4e
5 changed files with 167 additions and 173 deletions

View File

@@ -18,6 +18,7 @@
*
* Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
* Mirko Banchi <mk.banchi@gmail.com>
* Stefano Avallone <stavallo@unina.it>
*/
#include "ns3/simulator.h"
@@ -542,8 +543,16 @@ MacLow::StartTransmission (Ptr<WifiMacQueueItem> mpdu,
Ptr<QosTxop> qosTxop = m_edca.find (QosUtilsMapTidToAc (tid))->second;
std::vector<Ptr<WifiMacQueueItem>> mpduList;
// if a TXOP limit exists, compute the remaining TXOP duration
Time txopLimit = Seconds (0);
if (m_currentTxop->GetTxopLimit ().IsStrictlyPositive ())
{
txopLimit = m_currentTxop->GetTxopRemaining () - CalculateOverheadTxTime (mpdu, m_txParams);
NS_ASSERT (txopLimit.IsPositive ());
}
//Perform MPDU aggregation if possible
mpduList = m_mpduAggregator->GetNextAmpdu (mpdu, m_currentTxVector);
mpduList = m_mpduAggregator->GetNextAmpdu (mpdu, m_currentTxVector, txopLimit);
if (mpduList.size () > 1)
{
@@ -788,8 +797,7 @@ MacLow::ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiTxVector txVector, bool
{
m_currentTxop->GotAck ();
}
if (m_txParams.HasNextPacket () && (!m_currentPacket->GetHeader (0).IsQosData () ||
m_currentTxop->GetTxopLimit ().IsZero () || m_currentTxop->HasTxop ()))
if (m_txParams.HasNextPacket ())
{
if (m_stationManager->GetRifsPermitted ())
{
@@ -800,7 +808,8 @@ MacLow::ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiTxVector txVector, bool
m_waitIfsEvent = Simulator::Schedule (GetSifs (), &MacLow::WaitIfsAfterEndTxFragment, this);
}
}
else if (m_currentPacket->GetHeader (0).IsQosData () && m_currentTxop->HasTxop ())
else if (m_currentPacket->GetHeader (0).IsQosData () && m_currentTxop->IsQosTxop () &&
m_currentTxop->GetTxopLimit ().IsStrictlyPositive () && m_currentTxop->GetTxopRemaining () > GetSifs ())
{
if (m_stationManager->GetRifsPermitted ())
{
@@ -811,6 +820,10 @@ MacLow::ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiTxVector txVector, bool
m_waitIfsEvent = Simulator::Schedule (GetSifs (), &MacLow::WaitIfsAfterEndTxPacket, this);
}
}
else if (m_currentTxop->IsQosTxop ())
{
m_currentTxop->TerminateTxop ();
}
}
else if (hdr.IsBlockAck () && hdr.GetAddr1 () == m_self
&& m_txParams.MustWaitBlockAck ()
@@ -824,7 +837,9 @@ MacLow::ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiTxVector txVector, bool
m_blockAckTimeoutEvent.Cancel ();
NotifyAckTimeoutResetNow ();
m_currentTxop->GotBlockAck (&blockAck, hdr.GetAddr2 (), rxSnr, txVector.GetMode (), tag.Get ());
if (m_currentPacket->GetHeader (0).IsQosData () && m_currentTxop->HasTxop ())
// start next packet if TXOP remains, otherwise contend for accessing the channel again
if (m_currentTxop->IsQosTxop () && m_currentTxop->GetTxopLimit ().IsStrictlyPositive ()
&& m_currentTxop->GetTxopRemaining () > GetSifs ())
{
if (m_stationManager->GetRifsPermitted ())
{
@@ -835,6 +850,10 @@ MacLow::ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiTxVector txVector, bool
m_waitIfsEvent = Simulator::Schedule (GetSifs (), &MacLow::WaitIfsAfterEndTxPacket, this);
}
}
else if (m_currentTxop->IsQosTxop ())
{
m_currentTxop->TerminateTxop ();
}
}
else if (hdr.IsBlockAckReq () && hdr.GetAddr1 () == m_self)
{
@@ -1388,6 +1407,14 @@ MacLow::CalculateOverheadTxTime (Ptr<const WifiMacQueueItem> item,
txTime += GetSifs ();
txTime += GetAckDuration (item->GetHeader ().GetAddr1 (), GetDataTxVector (item));
}
else if (params.MustWaitBlockAck ())
{
txTime += GetSifs ();
WifiTxVector blockAckReqTxVector = GetBlockAckTxVector (item->GetHeader ().GetAddr2 (),
GetDataTxVector (item).GetMode ());
txTime += GetBlockAckDuration (blockAckReqTxVector, params.GetBlockAckType ());
}
return txTime;
}
@@ -1758,9 +1785,9 @@ MacLow::StartDataTxTimers (WifiTxVector dataTxVector)
}
m_waitIfsEvent = Simulator::Schedule (delay, &MacLow::WaitIfsAfterEndTxFragment, this);
}
else if (m_currentPacket->GetHeader (0).IsQosData () && m_currentPacket->GetHeader (0).IsQosBlockAck ()
&& m_currentTxop->HasTxop ())
{
else if (m_currentPacket->GetHeader (0).IsQosData () && m_currentTxop->IsQosTxop () &&
m_currentTxop->GetTxopLimit ().IsStrictlyPositive () && m_currentTxop->GetTxopRemaining () > GetSifs ())
{
Time delay = txDuration;
if (m_stationManager->GetRifsPermitted ())
{

View File

@@ -18,6 +18,7 @@
*
* Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
* Mirko Banchi <mk.banchi@gmail.com>
* Stefano Avallone <stavalli@unina.it>
*/
#include "ns3/log.h"
@@ -572,12 +573,24 @@ QosTxop::NotifyAccessGranted (void)
}
m_stationManager->UpdateFragmentationThreshold ();
// dequeue the peeked item. Disable aggregation if fragmentation is needed
Ptr<WifiMacQueueItem> item = DequeuePeekedFrame (peekedItem,
m_low->GetDataTxVector (peekedItem),
!NeedFragmentation ());
Time ppduDurationLimit = Seconds (0);
NS_ASSERT (item != 0);
// compute the limit on the PPDU duration due to the TXOP duration, if any
if (peekedItem->GetHeader ().IsQosData () && GetTxopLimit ().IsStrictlyPositive ())
{
MacLowTransmissionParameters params = GetTransmissionParameters (peekedItem);
ppduDurationLimit = GetTxopRemaining () - m_low->CalculateOverheadTxTime (peekedItem, params);
}
// dequeue the peeked item if it fits within the TXOP duration, if any
Ptr<WifiMacQueueItem> item = DequeuePeekedFrame (peekedItem, m_low->GetDataTxVector (peekedItem),
!NeedFragmentation (), 0, ppduDurationLimit);
if (item == 0)
{
NS_LOG_DEBUG ("Not enough time in the current TXOP");
return;
}
m_currentPacket = item->GetPacket ();
m_currentHdr = item->GetHeader ();
m_currentPacketTimestamp = item->GetTimeStamp ();
@@ -607,6 +620,15 @@ QosTxop::NotifyAccessGranted (void)
{
m_currentParams = GetTransmissionParameters (mpdu);
// check if the current frame meets the QoS TXOP Limit, if any
if (mpdu->GetHeader ().IsQosData () && GetTxopLimit ().IsStrictlyPositive () &&
m_low->CalculateOverallTxTime (mpdu->GetPacket (), &mpdu->GetHeader (),
m_currentParams) > GetTxopRemaining ())
{
NS_LOG_DEBUG ("Not enough time in the current TXOP");
return;
}
//With COMPRESSED_BLOCK_ACK fragmentation must be avoided.
if (((m_currentHdr.IsQosData () && !m_currentHdr.IsQosAmsdu ())
|| (m_currentHdr.IsData () && !m_currentHdr.IsQosData ()))
@@ -852,35 +874,10 @@ QosTxop::GotAck (void)
}
m_currentPacket = 0;
ResetCw ();
if (!HasTxop ())
{
if (m_currentHdr.IsQosData () && GetTxopLimit ().IsStrictlyPositive ())
{
m_txopTrace (m_startTxop, Simulator::Now () - m_startTxop);
}
m_cwTrace = GetCw ();
m_backoff = m_rng->GetInteger (0, GetCw ());
m_backoffTrace (m_backoff);
StartBackoffNow (m_backoff);
RestartAccessIfNeeded ();
}
}
else
{
NS_LOG_DEBUG ("got ack. tx not done, size=" << m_currentPacket->GetSize ());
if (!HasTxop ())
{
if (m_currentHdr.IsQosData () && GetTxopLimit ().IsStrictlyPositive ())
{
m_txopTrace (m_startTxop, Simulator::Now () - m_startTxop);
m_cwTrace = GetCw ();
m_backoff = m_rng->GetInteger (0, GetCw ());
m_backoffTrace (m_backoff);
StartBackoffNow (m_backoff);
m_fragmentNumber++;
RestartAccessIfNeeded ();
}
}
}
}
@@ -1214,78 +1211,99 @@ void
QosTxop::StartNextPacket (void)
{
NS_LOG_FUNCTION (this);
Time txopLimit = GetTxopLimit ();
NS_ASSERT (txopLimit.IsZero () || Simulator::Now () - m_startTxop <= txopLimit);
WifiMacHeader hdr = m_currentHdr;
Ptr<const Packet> peekedPacket;
Ptr<const WifiMacQueueItem> peekedItem = PeekNextFrame ();
if (peekedItem)
{
peekedPacket = peekedItem->GetPacket ();
hdr = peekedItem->GetHeader ();
}
if ((m_currentHdr.IsQosBlockAck () && peekedPacket == 0) || m_baManager->HasBar (m_currentBar))
{
SendBlockAckRequest (m_currentBar);
return;
}
else if (peekedPacket == 0)
{
if (txopLimit.IsStrictlyPositive ())
{
NS_ASSERT (Simulator::Now () - m_startTxop <= txopLimit);
m_txopTrace (m_startTxop, Simulator::Now () - m_startTxop);
}
return;
}
m_currentParams.DisableNextData ();
if (m_currentHdr.IsQosData () && m_currentHdr.IsQosBlockAck ())
{
m_currentParams.DisableAck ();
}
else
{
m_currentParams.EnableAck ();
}
if (m_stationManager->NeedRts (hdr.GetAddr1 (), &hdr, peekedPacket, m_low->GetDataTxVector (peekedItem)))
{
m_currentParams.EnableRts ();
}
else
{
m_currentParams.DisableRts ();
}
if (GetTxopRemaining () >= GetLow ()->CalculateOverallTxTime (peekedPacket, &hdr, m_currentParams))
{
// when dequeuing the peeked packet, A-MSDU aggregation is attempted if the
// packet has been peeked from the EDCA queue. Thus, compute the max available
// time for the transmission of the PPDU
Time maxPpduDuration = GetTxopRemaining () - m_low->CalculateOverheadTxTime (peekedItem, m_currentParams);
NS_ASSERT (GetTxopLimit ().IsStrictlyPositive () && GetTxopRemaining ().IsStrictlyPositive ());
Ptr<WifiMacQueueItem> item = DequeuePeekedFrame (peekedItem, m_low->GetDataTxVector (peekedItem),
true, 0, maxPpduDuration);
if (item == 0)
m_currentPacket = 0;
Ptr<const WifiMacQueueItem> nextFrame;
// peek the next BlockAckReq, if any
if (m_baManager->HasBar (m_currentBar, false))
{
WifiMacHeader hdr;
hdr.SetType (WIFI_MAC_CTL_BACKREQ);
hdr.SetAddr1 (m_currentBar.recipient);
nextFrame = Create<const WifiMacQueueItem> (m_currentBar.bar, hdr);
}
else
{
nextFrame = PeekNextFrame ();
}
if (nextFrame != 0)
{
MacLowTransmissionParameters params = GetTransmissionParameters (nextFrame);
if (GetTxopRemaining () >= m_low->CalculateOverallTxTime (nextFrame->GetPacket (), &nextFrame->GetHeader (), params))
{
m_txopTrace (m_startTxop, Simulator::Now () - m_startTxop);
if (nextFrame->GetHeader ().IsBlockAckReq ())
{
NS_LOG_DEBUG ("start next BlockAckReq within the current TXOP");
m_baManager->HasBar (m_currentBar);
SendBlockAckRequest (m_currentBar);
return;
}
// check if a Block Ack agreement needs to be established
m_currentHdr = nextFrame->GetHeader ();
m_currentPacket = nextFrame->GetPacket ();
if (m_currentHdr.IsQosData () && !m_currentHdr.GetAddr1 ().IsBroadcast ()
&& m_stationManager->GetQosSupported (m_currentHdr.GetAddr1 ())
&& (!m_baManager->ExistsAgreement (m_currentHdr.GetAddr1 (), m_currentHdr.GetQosTid ())
|| m_baManager->ExistsAgreementInState (m_currentHdr.GetAddr1 (), m_currentHdr.GetQosTid (), OriginatorBlockAckAgreement::RESET))
&& SetupBlockAckIfNeeded ())
{
return;
}
// when dequeuing the peeked packet, A-MSDU aggregation is attempted if the
// packet has been peeked from the EDCA queue. Thus, compute the max available
// time for the transmission of the PPDU
Time maxPpduDuration = GetTxopRemaining () - m_low->CalculateOverheadTxTime (nextFrame, params);
NS_ASSERT (maxPpduDuration.IsPositive ());
Ptr<WifiMacQueueItem> item = DequeuePeekedFrame (nextFrame, m_low->GetDataTxVector (nextFrame),
true, 0, maxPpduDuration);
NS_ASSERT (item != 0);
NS_LOG_DEBUG ("start next packet " << *item << " within the current TXOP");
m_currentPacket = item->GetPacket ();
m_currentHdr = item->GetHeader ();
m_currentPacketTimestamp = item->GetTimeStamp ();
NS_ASSERT (m_currentPacket != 0);
m_currentParams = params;
m_stationManager->UpdateFragmentationThreshold ();
m_fragmentNumber = 0;
if (m_currentHdr.IsQosData () && !m_currentHdr.GetAddr1 ().IsBroadcast ())
{
VerifyBlockAck ();
}
GetLow ()->StartTransmission (item, m_currentParams, this);
if (!GetAmpduExist (m_currentHdr.GetAddr1 ()))
{
CompleteTx ();
}
return;
}
NS_LOG_DEBUG ("start next packet");
m_currentPacket = item->GetPacket ();
m_currentHdr = item->GetHeader ();
NS_ASSERT (m_currentPacket != 0);
m_stationManager->UpdateFragmentationThreshold ();
m_fragmentNumber = 0;
VerifyBlockAck ();
GetLow ()->StartTransmission (item, m_currentParams, this);
if (!GetAmpduExist (m_currentHdr.GetAddr1 ()))
{
CompleteTx ();
}
}
else if (txopLimit.IsStrictlyPositive ())
// terminate TXOP because no (suitable) frame was found
TerminateTxop ();
}
void
QosTxop::TerminateTxop (void)
{
NS_LOG_FUNCTION (this);
if (GetTxopLimit ().IsStrictlyPositive ())
{
NS_LOG_DEBUG ("Terminating TXOP. Duration = " << Simulator::Now () - m_startTxop);
m_txopTrace (m_startTxop, Simulator::Now () - m_startTxop);
}
m_cwTrace = GetCw ();
m_backoff = m_rng->GetInteger (0, GetCw ());
m_backoffTrace (m_backoff);
StartBackoffNow (m_backoff);
RestartAccessIfNeeded ();
}
Time
@@ -1301,60 +1319,14 @@ QosTxop::GetTxopRemaining (void) const
return remainingTxop;
}
bool
QosTxop::HasTxop (void) const
{
NS_LOG_FUNCTION (this);
WifiMacHeader hdr;
if (!m_currentHdr.IsQosData () || GetTxopLimit ().IsZero ())
{
return false;
}
Ptr<const WifiMacQueueItem> peekedItem = m_queue->PeekByTidAndAddress (m_currentHdr.GetQosTid (),
m_currentHdr.GetAddr1 ());
if (peekedItem == 0)
{
return false;
}
Ptr<const Packet> peekedPacket = peekedItem->GetPacket ();
hdr = peekedItem->GetHeader ();
MacLowTransmissionParameters params = m_currentParams;
if (m_currentHdr.IsQosData () && m_currentHdr.IsQosBlockAck ())
{
params.DisableAck ();
}
else
{
params.EnableAck ();
}
Time duration = GetLow ()->CalculateOverallTxTime (peekedPacket, &hdr, params);
if (m_currentPacket != 0)
{
//take into account current transmission in duration
duration += GetLow ()->CalculateOverallTxTime (m_currentPacket, &m_currentHdr, params);
}
return (GetTxopRemaining () >= duration);
}
void
QosTxop::EndTxNoAck (void)
{
NS_LOG_FUNCTION (this);
NS_LOG_DEBUG ("a transmission that did not require an ACK just finished");
if (m_currentHdr.IsQosData () && m_currentHdr.IsQosBlockAck () && GetTxopLimit ().IsStrictlyPositive ())
{
m_txopTrace (m_startTxop, Simulator::Now () - m_startTxop);
}
m_currentPacket = 0;
ResetCw ();
m_cwTrace = GetCw ();
m_backoff = m_rng->GetInteger (0, GetCw ());
m_backoffTrace (m_backoff);
StartBackoffNow (m_backoff);
StartAccessIfNeeded ();
TerminateTxop ();
}
bool
@@ -1659,18 +1631,6 @@ QosTxop::GotBlockAck (const CtrlBAckResponseHeader *blockAck, Mac48Address recip
}
m_currentPacket = 0;
ResetCw ();
if (!HasTxop ())
{
if (m_currentHdr.IsQosData () && GetTxopLimit ().IsStrictlyPositive ())
{
m_txopTrace (m_startTxop, Simulator::Now () - m_startTxop);
}
m_cwTrace = GetCw ();
m_backoff = m_rng->GetInteger (0, GetCw ());
m_backoffTrace (m_backoff);
StartBackoffNow (m_backoff);
RestartAccessIfNeeded ();
}
}
void

View File

@@ -561,12 +561,9 @@ private:
*/
Time GetTxopRemaining (void) const;
/**
* Check if the station has TXOP granted for the next MPDU.
*
* \return true if the station has TXOP granted for the next MPDU,
* false otherwise.
* Update backoff and restart access if needed.
*/
bool HasTxop (void) const;
void TerminateTxop (void);
/**
* Calculate the size of the next fragment.

View File

@@ -884,10 +884,17 @@ Txop::MissedBlockAck (uint8_t nMpdus)
NS_LOG_WARN ("MissedBlockAck should not be called for non QoS!");
}
bool
Txop::HasTxop (void) const
Time
Txop::GetTxopRemaining (void) const
{
return false;
NS_LOG_WARN ("GetTxopRemaining should not be called for non QoS!");
return Seconds (0);
}
void
Txop::TerminateTxop (void)
{
NS_LOG_WARN ("TerminateTxop should not be called for non QoS!");
}
} //namespace ns3

View File

@@ -306,12 +306,15 @@ public:
virtual void EndTxNoAck (void);
/**
* Check if the station has TXOP granted for the next MPDU.
* Return the remaining duration in the current TXOP.
*
* \return true if the station has TXOP granted for the next MPDU,
* false otherwise
* \return the remaining duration in the current TXOP.
*/
virtual bool HasTxop (void) const;
virtual Time GetTxopRemaining (void) const;
/**
* Update backoff and restart access if needed.
*/
virtual void TerminateTxop (void);
/**
* Check if the next PCF transmission can fit in the remaining CFP duration.