wifi: Check if main PHY switch must be postponed when the switch back timer expires

This commit is contained in:
Stefano Avallone
2024-09-26 15:56:39 +02:00
parent 37b61c25e7
commit a07cb9a05e
4 changed files with 136 additions and 12 deletions

View File

@@ -266,6 +266,20 @@ AdvancedEmlsrManager::ReceivedMacHdr(Ptr<WifiPhy> phy,
// Hence, schedule the call to NotifyTxopEnd to execute it outside such for loop.
Simulator::ScheduleNow(&AdvancedEmlsrManager::NotifyTxopEnd, this, *linkId, false, false);
}
// if the MAC header has been received on the link on which the main PHY is operating, the
// switch main PHY back timer is running and channel access is not expected to be gained by
// the main PHY before the switch main PHY back timer expires (plus a channel switch delay),
// try to switch the main PHY back to the preferred link
if (m_switchMainPhyBackEvent.IsPending() &&
phy == GetStaMac()->GetDevice()->GetPhy(GetMainPhyId()) &&
!GetExpectedAccessWithinDelay(*linkId,
Simulator::GetDelayLeft(m_switchMainPhyBackEvent) +
phy->GetChannelSwitchDelay()))
{
m_switchMainPhyBackEvent.Cancel();
SwitchMainPhyBackDelayExpired(*linkId);
}
}
void
@@ -401,6 +415,19 @@ AdvancedEmlsrManager::CheckNavAndCcaLastPifs(Ptr<WifiPhy> phy, uint8_t linkId, P
}
else
{
// medium busy, check when access may be granted
if (!GetExpectedAccessWithinDelay(linkId,
m_switchMainPhyBackDelay + phy->GetChannelSwitchDelay()))
{
NS_LOG_DEBUG("No AC is expected to get backoff soon, switch main PHY back");
if (auto mainPhy = GetStaMac()->GetDevice()->GetPhy(GetMainPhyId());
!mainPhy->IsStateSwitching())
{
SwitchMainPhyBackDelayExpired(linkId);
}
return;
}
// medium busy, restart channel access
NS_LOG_DEBUG("Medium busy in the last PIFS interval");
edca->NotifyChannelReleased(linkId); // to set access to NOT_REQUESTED
@@ -412,15 +439,93 @@ AdvancedEmlsrManager::CheckNavAndCcaLastPifs(Ptr<WifiPhy> phy, uint8_t linkId, P
// The timer is stopped if a DL or UL TXOP is started. When the timer expires, the main PHY
// switches back to the preferred link if SwitchAuxPhy is false
m_switchMainPhyBackEvent.Cancel();
m_switchMainPhyBackEvent = Simulator::Schedule(m_switchMainPhyBackDelay, [this, linkId]() {
if (!m_switchAuxPhy)
{
SwitchMainPhyBackToPreferredLink(linkId, EmlsrSwitchMainPhyBackTrace(false));
}
});
m_switchMainPhyBackEvent =
Simulator::Schedule(m_switchMainPhyBackDelay,
&AdvancedEmlsrManager::SwitchMainPhyBackDelayExpired,
this,
linkId);
}
}
void
AdvancedEmlsrManager::SwitchMainPhyBackDelayExpired(uint8_t linkId)
{
NS_LOG_FUNCTION(this << linkId);
if (m_switchAuxPhy)
{
return; // nothing to do
}
Time delay{0};
// check if the timer must be restarted because a frame is being received on any link
for (const auto id : GetStaMac()->GetLinkIds())
{
auto phy = GetStaMac()->GetWifiPhy(id);
if (!phy || !GetStaMac()->IsEmlsrLink(id))
{
continue;
}
if (!GetEhtFem(id)->VirtualCsMediumIdle() &&
GetEhtFem(id)->GetTxopHolder() != GetEhtFem(id)->GetBssid())
{
NS_LOG_DEBUG("NAV is set and TXOP holder is not the associated AP MLD on link " << +id);
continue;
}
if (auto macHdr = GetEhtFem(id)->GetReceivedMacHdr(); macHdr && m_useNotifiedMacHdr)
{
// the MAC header has been received; if this is a Trigger Frame, we shall restart the
// timer, so that we do not yet switch the main PHY back to the preferred link
if (const auto& hdr = macHdr->get();
hdr.IsTrigger() &&
(hdr.GetAddr1().IsBroadcast() || hdr.GetAddr1() == GetEhtFem(id)->GetAddress()))
{
delay = Max(delay, phy->GetDelayUntilIdle());
}
}
else if (phy->IsStateRx())
{
if (auto ongoingRxInfo = GetEhtFem(id)->GetOngoingRxInfo();
ongoingRxInfo &&
ongoingRxInfo->get().txVector.GetModulationClass() < WIFI_MOD_CLASS_HT)
{
// the MAC header of a non-HT PPDU, which may be an ICF, has not been received yet
// (or we cannot use its info); restart the timer, we will be called back when the
// MAC header is received
delay = Max(delay, phy->GetDelayUntilIdle());
}
}
else if (id == linkId && phy->IsStateIdle())
{
// this is the link on which the main PHY is operating. If an AC with traffic is
// expected to get channel access soon (within a channel switch delay), restart
// the timer to have the main PHY stay a bit longer on this link
if (GetExpectedAccessWithinDelay(linkId, phy->GetChannelSwitchDelay()))
{
delay = Max(delay, phy->GetChannelSwitchDelay());
}
}
}
if (delay.IsStrictlyPositive())
{
NS_LOG_DEBUG("Restarting the timer, check again in " << delay.As(Time::US));
m_switchMainPhyBackEvent =
Simulator::Schedule(delay,
&AdvancedEmlsrManager::SwitchMainPhyBackDelayExpired,
this,
linkId);
return;
}
// no need to wait further, switch the main PHY back to the preferred link
SwitchMainPhyBackToPreferredLink(linkId, EmlsrSwitchMainPhyBackTrace(false));
}
void
AdvancedEmlsrManager::DoNotifyIcfReceived(uint8_t linkId)
{
@@ -717,12 +822,10 @@ AdvancedEmlsrManager::SwitchMainPhyIfTxopToBeGainedByAuxPhy(uint8_t linkId,
mainPhy->GetChannelSwitchDelay() + GetStaMac()->GetWifiPhy(linkId)->GetPifs());
m_switchMainPhyBackEvent.Cancel();
m_switchMainPhyBackEvent =
Simulator::Schedule(minDelay + m_switchMainPhyBackDelay, [this, linkId]() {
if (!m_switchAuxPhy)
{
SwitchMainPhyBackToPreferredLink(linkId, EmlsrSwitchMainPhyBackTrace(false));
}
});
Simulator::Schedule(minDelay + m_switchMainPhyBackDelay,
&AdvancedEmlsrManager::SwitchMainPhyBackDelayExpired,
this,
linkId);
}
} // namespace ns3

View File

@@ -90,6 +90,16 @@ class AdvancedEmlsrManager : public DefaultEmlsrManager
*/
void SwitchMainPhyIfTxopToBeGainedByAuxPhy(uint8_t linkId, AcIndex aci, const Time& delay);
/**
* This method is called when the switch main PHY back delay timer (which is started when the
* main PHY switches to the link of an aux PHY that does not switch and is not TX capable)
* expires and decides whether to delay the request to switch the main PHY back to the preferred
* link or to execute it immediately.
*
* @param linkId the ID of the link that the main PHY is leaving
*/
void SwitchMainPhyBackDelayExpired(uint8_t linkId);
private:
void DoNotifyTxopEnd(uint8_t linkId) override;
void DoNotifyIcfReceived(uint8_t linkId) override;

View File

@@ -727,6 +727,12 @@ QosFrameExchangeManager::SetTxopHolder(Ptr<const WifiPsdu> psdu, const WifiTxVec
}
}
std::optional<Mac48Address>
QosFrameExchangeManager::GetTxopHolder() const
{
return m_txopHolder;
}
std::optional<Mac48Address>
QosFrameExchangeManager::FindTxopHolder(const WifiMacHeader& hdr, const WifiTxVector& txVector)
{

View File

@@ -93,6 +93,11 @@ class QosFrameExchangeManager : public FrameExchangeManager
*/
virtual Ptr<WifiMpdu> CreateAliasIfNeeded(Ptr<WifiMpdu> mpdu) const;
/**
* @return the TXOP holder (if any)
*/
std::optional<Mac48Address> GetTxopHolder() const;
protected:
void DoDispose() override;