diff --git a/src/wifi/model/channel-access-manager.cc b/src/wifi/model/channel-access-manager.cc index 7a8bae0e2..3336cbc89 100644 --- a/src/wifi/model/channel-access-manager.cc +++ b/src/wifi/model/channel-access-manager.cc @@ -513,13 +513,14 @@ ChannelAccessManager::DoGrantDcfAccess() { NS_LOG_FUNCTION(this); uint32_t k = 0; - Time now = Simulator::Now(); + const auto now = Simulator::Now(); + const auto accessGrantStart = GetAccessGrantStart(); for (auto i = m_txops.begin(); i != m_txops.end(); k++) { Ptr txop = *i; if (txop->GetAccessStatus(m_linkId) == Txop::REQUESTED && (!txop->IsQosTxop() || !StaticCast(txop)->EdcaDisabled(m_linkId)) && - GetBackoffEndFor(txop) <= now) + GetBackoffEndFor(txop, accessGrantStart) <= now) { /** * This is the first Txop we find with an expired backoff and which @@ -534,7 +535,7 @@ ChannelAccessManager::DoGrantDcfAccess() { Ptr otherTxop = *j; if (otherTxop->GetAccessStatus(m_linkId) == Txop::REQUESTED && - GetBackoffEndFor(otherTxop) <= now) + GetBackoffEndFor(otherTxop, accessGrantStart) <= now) { NS_LOG_DEBUG( "dcf " << k << " needs access. backoff expired. internal collision. slots=" @@ -602,58 +603,47 @@ ChannelAccessManager::AccessTimeout() Time ChannelAccessManager::GetAccessGrantStart(bool ignoreNav) const { - NS_LOG_FUNCTION(this); - const Time& sifs = GetSifs(); - Time rxAccessStart = m_lastRx.end + sifs; + NS_LOG_FUNCTION(this << ignoreNav); + auto rxAccessStart = m_lastRx.end; if ((m_lastRx.end <= Simulator::Now()) && !m_lastRxReceivedOk) { rxAccessStart += GetEifsNoDifs(); } // an EDCA TXOP is obtained based solely on activity of the primary channel // (Sec. 10.23.2.5 of IEEE 802.11-2020) - Time busyAccessStart = m_lastBusyEnd.at(WIFI_CHANLIST_PRIMARY) + sifs; - Time txAccessStart = m_lastTxEnd + sifs; - Time navAccessStart = m_lastNavEnd + sifs; - Time ackTimeoutAccessStart = m_lastAckTimeoutEnd + sifs; - Time ctsTimeoutAccessStart = m_lastCtsTimeoutEnd + sifs; - Time switchingAccessStart = m_lastSwitchingEnd + sifs; - Time accessGrantedStart; - if (ignoreNav) - { - accessGrantedStart = std::max({rxAccessStart, - busyAccessStart, - txAccessStart, - ackTimeoutAccessStart, - ctsTimeoutAccessStart, - switchingAccessStart}); - } - else - { - accessGrantedStart = std::max({rxAccessStart, - busyAccessStart, - txAccessStart, - navAccessStart, - ackTimeoutAccessStart, - ctsTimeoutAccessStart, - switchingAccessStart}); - } - NS_LOG_INFO("access grant start=" << accessGrantedStart.As(Time::US) - << ", rx access start=" << rxAccessStart.As(Time::US) - << ", busy access start=" << busyAccessStart.As(Time::US) - << ", tx access start=" << txAccessStart.As(Time::US) - << ", nav access start=" << navAccessStart.As(Time::US) - << ", switching access start=" - << switchingAccessStart.As(Time::US)); - return accessGrantedStart; + const auto busyAccessStart = m_lastBusyEnd.at(WIFI_CHANLIST_PRIMARY); + const auto navAccessStart = ignoreNav ? Time{0} : m_lastNavEnd; + + const auto accessGrantedStart = std::max({rxAccessStart, + busyAccessStart, + m_lastTxEnd, + navAccessStart, + m_lastAckTimeoutEnd, + m_lastCtsTimeoutEnd, + m_lastSwitchingEnd}); + + NS_LOG_INFO("access grant start=" + << accessGrantedStart.As(Time::US) + << ", rx access start=" << rxAccessStart.As(Time::US) << ", busy access start=" + << busyAccessStart.As(Time::US) << ", tx access start=" << m_lastTxEnd.As(Time::US) + << ", nav access start=" << navAccessStart.As(Time::US) + << ", switching access start=" << m_lastSwitchingEnd.As(Time::US)); + return accessGrantedStart + GetSifs(); } Time ChannelAccessManager::GetBackoffStartFor(Ptr txop) { - NS_LOG_FUNCTION(this << txop); - Time mostRecentEvent = + return GetBackoffStartFor(txop, GetAccessGrantStart()); +} + +Time +ChannelAccessManager::GetBackoffStartFor(Ptr txop, Time accessGrantStart) const +{ + NS_LOG_FUNCTION(this << txop << accessGrantStart.As(Time::S)); + const auto mostRecentEvent = std::max({txop->GetBackoffStart(m_linkId), - GetAccessGrantStart() + (txop->GetAifsn(m_linkId) * GetSlot())}); + accessGrantStart + (txop->GetAifsn(m_linkId) * GetSlot())}); NS_LOG_DEBUG("Backoff start for " << txop->GetWifiMacQueue()->GetAc() << ": " << mostRecentEvent.As(Time::US)); @@ -662,9 +652,16 @@ ChannelAccessManager::GetBackoffStartFor(Ptr txop) Time ChannelAccessManager::GetBackoffEndFor(Ptr txop) +{ + return GetBackoffEndFor(txop, GetAccessGrantStart()); +} + +Time +ChannelAccessManager::GetBackoffEndFor(Ptr txop, Time accessGrantStart) const { NS_LOG_FUNCTION(this << txop); - Time backoffEnd = GetBackoffStartFor(txop) + (txop->GetBackoffSlots(m_linkId) * GetSlot()); + Time backoffEnd = + GetBackoffStartFor(txop, accessGrantStart) + (txop->GetBackoffSlots(m_linkId) * GetSlot()); NS_LOG_DEBUG("Backoff end for " << txop->GetWifiMacQueue()->GetAc() << ": " << backoffEnd.As(Time::US)); @@ -676,9 +673,10 @@ ChannelAccessManager::UpdateBackoff() { NS_LOG_FUNCTION(this); uint32_t k = 0; + const auto accessGrantStart = GetAccessGrantStart(); for (auto txop : m_txops) { - Time backoffStart = GetBackoffStartFor(txop); + Time backoffStart = GetBackoffStartFor(txop, accessGrantStart); if (backoffStart <= Simulator::Now()) { uint32_t nIntSlots = ((Simulator::Now() - backoffStart) / GetSlot()).GetHigh(); @@ -715,12 +713,13 @@ ChannelAccessManager::DoRestartAccessTimeoutIfNeeded() * if there is one, how many slots for AIFS+backoff does it require ? */ bool accessTimeoutNeeded = false; - Time expectedBackoffEnd = Simulator::GetMaximumSimulationTime(); + auto expectedBackoffEnd = Simulator::GetMaximumSimulationTime(); + const auto accessGrantStart = GetAccessGrantStart(); for (auto txop : m_txops) { if (txop->GetAccessStatus(m_linkId) == Txop::REQUESTED) { - Time tmp = GetBackoffEndFor(txop); + Time tmp = GetBackoffEndFor(txop, accessGrantStart); if (tmp > Simulator::Now()) { accessTimeoutNeeded = true; diff --git a/src/wifi/model/channel-access-manager.h b/src/wifi/model/channel-access-manager.h index 6250a688f..eee2f488a 100644 --- a/src/wifi/model/channel-access-manager.h +++ b/src/wifi/model/channel-access-manager.h @@ -359,15 +359,40 @@ class ChannelAccessManager : public Object * \return the current registered listener for PHY events on the given PHY */ std::shared_ptr GetPhyListener(Ptr phy) const; + /** * Initialize the structures holding busy end times per channel type (primary, * secondary, etc.) and per 20 MHz channel. */ void InitLastBusyStructs(); + /** * Update backoff slots for all Txops. */ void UpdateBackoff(); + + /** + * This overload is provided to enable caching the value returned by GetAccessGrantStart(), + * which is independent of the given Txop object. + * + * \param txop the Txop + * \param accessGrantStart the value returned by GetAccessGrantStart() + * + * \return the time when the backoff procedure started + */ + Time GetBackoffStartFor(Ptr txop, Time accessGrantStart) const; + + /** + * This overload is provided to enable caching the value returned by GetAccessGrantStart(), + * which is independent of the given Txop object. + * + * \param txop the Txop + * \param accessGrantStart the value returned by GetAccessGrantStart() + * + * \return the time when the backoff procedure ended (or will ended) + */ + Time GetBackoffEndFor(Ptr txop, Time accessGrantStart) const; + /** * Return the time when the backoff procedure * started for the given Txop. @@ -404,6 +429,7 @@ class ChannelAccessManager : public Object * (e.g. backoff procedure expired). */ void AccessTimeout(); + /** * Grant access to Txop using DCF/EDCF contention rules */ @@ -415,12 +441,14 @@ class ChannelAccessManager : public Object * \return the SIFS duration */ virtual Time GetSifs() const; + /** * Return the slot duration for this PHY. * * \return the slot duration */ virtual Time GetSlot() const; + /** * Return the EIFS duration minus a DIFS. *