From 4516f1347e54e1183b10285d60a988afba1e281d Mon Sep 17 00:00:00 2001 From: Stefano Avallone Date: Mon, 30 Sep 2024 10:26:41 +0200 Subject: [PATCH] wifi: Connecting PHY to a new link is postponed if an ICF is being received --- examples/wireless/examples-to-run.py | 2 +- src/wifi/model/eht/default-emlsr-manager.cc | 72 ++++++++++++++------- src/wifi/model/eht/default-emlsr-manager.h | 26 +++++--- src/wifi/model/eht/emlsr-manager.cc | 56 +++++++++++++--- src/wifi/model/eht/emlsr-manager.h | 9 +++ src/wifi/model/sta-wifi-mac.cc | 42 +++++++++--- src/wifi/model/sta-wifi-mac.h | 7 ++ 7 files changed, 162 insertions(+), 52 deletions(-) diff --git a/examples/wireless/examples-to-run.py b/examples/wireless/examples-to-run.py index 091452f06..b86cd1523 100755 --- a/examples/wireless/examples-to-run.py +++ b/examples/wireless/examples-to-run.py @@ -215,7 +215,7 @@ cpp_examples = [ "True", ), ( - "wifi-eht-network --simulationTime=0.3s --frequency=2.4 --frequency2=5 --frequency3=6 --guardInterval=1600 --udp=0 --downlink=1 --useRts=0 --mpduBufferSize=512 --emlsrLinks=0,1,2 --emlsrPaddingDelay=32 --emlsrTransitionDelay=32 --channelSwitchDelay=32us --emlsrAuxSwitch=True --emlsrAuxTxCapable=True --nStations=4 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=0 --mcs=0,3,5,9,10 --minExpectedThroughput=8 --maxExpectedThroughput=300 --RngRun=2", + "wifi-eht-network --simulationTime=0.3s --frequency=2.4 --frequency2=5 --frequency3=6 --guardInterval=1600 --udp=0 --downlink=1 --useRts=0 --mpduBufferSize=512 --emlsrLinks=0,1,2 --emlsrPaddingDelay=32 --emlsrTransitionDelay=32 --channelSwitchDelay=32us --emlsrAuxSwitch=True --emlsrAuxTxCapable=True --nStations=4 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=0 --mcs=0,3,5,9,10 --minExpectedThroughput=8 --maxExpectedThroughput=300 --RngRun=6", "True", "True", ), diff --git a/src/wifi/model/eht/default-emlsr-manager.cc b/src/wifi/model/eht/default-emlsr-manager.cc index 0e5a70998..4adcbec80 100644 --- a/src/wifi/model/eht/default-emlsr-manager.cc +++ b/src/wifi/model/eht/default-emlsr-manager.cc @@ -46,7 +46,6 @@ DefaultEmlsrManager::GetTypeId() } DefaultEmlsrManager::DefaultEmlsrManager() - : m_mainPhySwitchInfo{} { NS_LOG_FUNCTION(this); } @@ -95,15 +94,6 @@ DefaultEmlsrManager::NotifyMainPhySwitch(std::optional currLinkId, NS_LOG_FUNCTION(this << (currLinkId ? std::to_string(*currLinkId) : "") << nextLinkId << auxPhy << duration.As(Time::US)); - // if currLinkId has no value (i.e., the main PHY is not operating on any link), it means that - // the main PHY is switching - const auto now = Simulator::Now(); - NS_ASSERT_MSG(currLinkId || m_mainPhySwitchInfo.end >= now, - "No current link ID provided nor valid main PHY switch information stored"); - m_mainPhySwitchInfo.from = currLinkId.value_or(m_mainPhySwitchInfo.from); - m_mainPhySwitchInfo.to = nextLinkId; - m_mainPhySwitchInfo.end = now + duration; - if (m_switchAuxPhy) { // cancel any previously requested aux PHY switch @@ -119,21 +109,9 @@ DefaultEmlsrManager::NotifyMainPhySwitch(std::optional currLinkId, // schedule Aux PHY switch so that it operates on the link on which the main PHY was // operating NS_LOG_DEBUG("Aux PHY (" << auxPhy << ") operating on link " << +nextLinkId - << " will switch to link " << +currLinkId.value() << " in " + << " will switch to link " << +m_mainPhySwitchInfo.from << " in " << duration.As(Time::US)); - - if (duration.IsStrictlyPositive()) - { - m_auxPhySwitchEvent = - Simulator::Schedule(duration, [=, this, prevLinkId = m_mainPhySwitchInfo.from]() { - SwitchAuxPhy(auxPhy, nextLinkId, prevLinkId); - }); - } - else - { - SwitchAuxPhy(auxPhy, nextLinkId, m_mainPhySwitchInfo.from); - } - + SwitchAuxPhyAfterMainPhy(auxPhy, nextLinkId, m_mainPhySwitchInfo.from, duration); return; } @@ -161,6 +139,52 @@ DefaultEmlsrManager::NotifyMainPhySwitch(std::optional currLinkId, } } +void +DefaultEmlsrManager::SwitchAuxPhyAfterMainPhy(Ptr auxPhy, + uint8_t currLinkId, + uint8_t nextLinkId, + Time duration) +{ + NS_LOG_FUNCTION(this << auxPhy << currLinkId << nextLinkId << duration.As(Time::US)); + + if (duration.IsStrictlyPositive()) + { + auto lambda = [=, this]() { + if (GetStaMac()->GetWifiPhy(currLinkId) == auxPhy) + { + // the aux PHY is still operating on the link, likely because it is receiving a + // PPDU and connecting the main PHY to the link has been postponed + const auto [maybeIcf, extension] = CheckPossiblyReceivingIcf(currLinkId); + if (maybeIcf && extension.IsStrictlyPositive()) + { + NS_LOG_DEBUG("Switching aux PHY to link " << +nextLinkId << " is postponed by " + << extension.As(Time::US)); + SwitchAuxPhyAfterMainPhy(auxPhy, currLinkId, nextLinkId, extension); + return; + } + } + const auto isSleeping = auxPhy->IsStateSleep(); + if (isSleeping) + { + // if the aux PHY is sleeping, it cannot switch channel + auxPhy->ResumeFromSleep(); + } + SwitchAuxPhy(auxPhy, currLinkId, nextLinkId); + if (isSleeping) + { + // sleep mode will be postponed until the end of channel switch + auxPhy->SetSleepMode(true); + } + }; + + m_auxPhySwitchEvent = Simulator::Schedule(duration, lambda); + } + else + { + SwitchAuxPhy(auxPhy, currLinkId, nextLinkId); + } +} + std::pair DefaultEmlsrManager::DoGetDelayUntilAccessRequest(uint8_t linkId) { diff --git a/src/wifi/model/eht/default-emlsr-manager.h b/src/wifi/model/eht/default-emlsr-manager.h index 69fee37c0..b41b27db8 100644 --- a/src/wifi/model/eht/default-emlsr-manager.h +++ b/src/wifi/model/eht/default-emlsr-manager.h @@ -75,26 +75,34 @@ class DefaultEmlsrManager : public EmlsrManager */ void SwitchMainPhyBackToPreferredLink(uint8_t linkId, EmlsrMainPhySwitchTrace&& traceInfo); - /// Store information about a main PHY switch. - struct MainPhySwitchInfo - { - Time end; //!< end of channel switching - uint8_t from; //!< ID of the link which the main PHY is/has been leaving - uint8_t to; //!< ID of the link which the main PHY is moving to - }; - bool m_switchAuxPhy; /**< whether Aux PHY should switch channel to operate on the link on which the Main PHY was operating before moving to the link of the Aux PHY */ Ptr m_auxPhyToReconnect; //!< Aux PHY the ChannelAccessManager of the link on which //!< the main PHY is operating has to connect a listener to //!< when the main PHY is back operating on its previous link EventId m_auxPhySwitchEvent; //!< event scheduled for an aux PHY to switch link - MainPhySwitchInfo m_mainPhySwitchInfo; //!< main PHY switch info std::map m_switchMainPhyOnRtsTx; //!< link ID-indexed map of the time when an RTS //!< that requires the main PHY to switch link //!< is expected to be transmitted on the link private: + /** + * This function shall be called when the main PHY starts switching to a link on which an aux + * PHY that is capable of switching link is operating. This function schedules the aux PHY + * switch to occur when the main PHY completes the switch and, in case the connection of the + * main PHY to the aux PHY link is postponed because the aux PHY is receiving a PPDU, the + * aux PHY switch is postponed accordingly. + * + * @param auxPhy the aux PHY that has to switch link + * @param currLinkId the link on which the aux PHY is operating + * @param nextLinkId the link to which the aux PHY will switch + * @param duration the remaining time until the aux PHY switch starts + */ + void SwitchAuxPhyAfterMainPhy(Ptr auxPhy, + uint8_t currLinkId, + uint8_t nextLinkId, + Time duration); + void DoNotifyMgtFrameReceived(Ptr mpdu, uint8_t linkId) override; void NotifyMainPhySwitch(std::optional currLinkId, uint8_t nextLinkId, diff --git a/src/wifi/model/eht/emlsr-manager.cc b/src/wifi/model/eht/emlsr-manager.cc index d404ea7c9..6de004e7f 100644 --- a/src/wifi/model/eht/emlsr-manager.cc +++ b/src/wifi/model/eht/emlsr-manager.cc @@ -143,9 +143,10 @@ EmlsrManager::GetTypeId() } EmlsrManager::EmlsrManager() - // The STA initializes dot11MSDTimerDuration to aPPDUMaxTime defined in Table 36-70 - // (Sec. 35.3.16.8.1 of 802.11be D3.1) - : m_mediumSyncDuration(MicroSeconds(DEFAULT_MSD_DURATION_USEC)), + : m_mainPhySwitchInfo{}, + // The STA initializes dot11MSDTimerDuration to aPPDUMaxTime defined in Table 36-70 + // (Sec. 35.3.16.8.1 of 802.11be D3.1) + m_mediumSyncDuration(MicroSeconds(DEFAULT_MSD_DURATION_USEC)), // The default value of dot11MSDOFDMEDthreshold is –72 dBm and the default value of // dot11MSDTXOPMax is 1, respectively (Sec. 35.3.16.8.1 of 802.11be D3.1) m_msdOfdmEdThreshold(DEFAULT_MSD_OFDM_ED_THRESH), @@ -449,19 +450,53 @@ EmlsrManager::NotifyIcfReceived(uint8_t linkId) } auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId); - auto auxPhy = m_staMac->GetWifiPhy(linkId); + auto rxPhy = m_staMac->GetWifiPhy(linkId); - if (m_staMac->GetWifiPhy(linkId) != mainPhy) + const auto receivedByAuxPhy = (rxPhy != mainPhy); + const auto mainPhyOnALink = (m_staMac->GetLinkForPhy(mainPhy).has_value()); + const auto mainPhyIsSwitching = + (mainPhy->GetState()->GetLastTime({WifiPhyState::SWITCHING}) == Simulator::Now()); + // if the main PHY is not operating on a link and it is not switching, then we have postponed + // the reconnection of the main PHY to a link because a PPDU reception was ongoing on that link + const auto mainPhyToConnect = (!mainPhyOnALink && !mainPhyIsSwitching); + + const auto mainPhyToConnectToOtherLink = mainPhyToConnect && (m_mainPhySwitchInfo.to != linkId); + + if (mainPhyToConnect) + { + // If ICF was received on a link other than the one the main PHY is waiting to be connected + // to, we need to cancel the pending reconnection and request a new main PHY switch. + // If ICF was received on the link the main PHY is waiting to be connected to, we cancel + // the pending reconnection and explicitly request the reconnection below + GetStaMac()->CancelEmlsrPhyConnectEvent(mainPhy->GetPhyId()); + } + + // We need to request a main PHY switch if: + // - the ICF was received by an aux PHY, AND + // - the main PHY is not waiting to be connected to a link OR it is waiting to be connected + // to a link other than the link on which the ICF is received. + if (receivedByAuxPhy && (!mainPhyToConnect || mainPhyToConnectToOtherLink)) { - // an aux PHY received the ICF SwitchMainPhy(linkId, true, // channel switch should occur instantaneously RESET_BACKOFF, DONT_REQUEST_ACCESS, EmlsrDlTxopIcfReceivedByAuxPhyTrace{}); + } + else if (mainPhyToConnect && !mainPhyToConnectToOtherLink) + { + // If the main PHY is waiting to be connected to the link on which the ICF was received, we + // have to explicitly perform the connection because the pending event was cancelled above. + // We do this way in order to reconnect the main PHY before putting aux PHYs to sleep: if + // the aux PHY is put to sleep while still operating on the link on which it received the + // ICF, all the MAC events (including scheduled CTS transmission) will be cancelled. + m_staMac->NotifySwitchingEmlsrLink(mainPhy, linkId, Time{0}); + } + if (receivedByAuxPhy) + { // aux PHY received the ICF but main PHY will send the response - auto uid = auxPhy->GetPreviouslyRxPpduUid(); + auto uid = rxPhy->GetPreviouslyRxPpduUid(); mainPhy->SetPreviouslyRxPpduUid(uid); } @@ -784,9 +819,6 @@ EmlsrManager::SwitchMainPhy(uint8_t linkId, traceInfo.toLinkId = linkId; m_mainPhySwitchTrace(traceInfo); - NS_ASSERT_MSG(currMainPhyLinkId.has_value() || mainPhy->IsStateSwitching(), - "If the main PHY is not operating on a link, it must be switching"); - const auto newMainPhyChannel = GetChannelForMainPhy(linkId); NS_LOG_DEBUG("Main PHY (" << mainPhy << ") is about to switch to " << newMainPhyChannel @@ -861,6 +893,10 @@ EmlsrManager::SwitchMainPhy(uint8_t linkId, }); } + m_mainPhySwitchInfo.from = currMainPhyLinkId.value_or(m_mainPhySwitchInfo.from); + m_mainPhySwitchInfo.to = linkId; + m_mainPhySwitchInfo.end = Simulator::Now() + timeToSwitchEnd; + SetCcaEdThresholdOnLinkSwitch(mainPhy, linkId); NotifyMainPhySwitch(currMainPhyLinkId, linkId, auxPhy, timeToSwitchEnd); } diff --git a/src/wifi/model/eht/emlsr-manager.h b/src/wifi/model/eht/emlsr-manager.h index 70108c129..77eacd001 100644 --- a/src/wifi/model/eht/emlsr-manager.h +++ b/src/wifi/model/eht/emlsr-manager.h @@ -509,6 +509,14 @@ class EmlsrManager : public Object */ bool GetExpectedAccessWithinDelay(uint8_t linkId, const Time& delay) const; + /// Store information about a main PHY switch. + struct MainPhySwitchInfo + { + Time end; //!< end of channel switching + uint8_t from{}; //!< ID of the link which the main PHY is/has been leaving + uint8_t to{}; //!< ID of the link which the main PHY is moving to + }; + Time m_emlsrPaddingDelay; //!< EMLSR Padding delay Time m_emlsrTransitionDelay; //!< EMLSR Transition delay uint8_t m_mainPhyId; //!< ID of main PHY (position in the vector of PHYs held by WifiNetDevice) @@ -525,6 +533,7 @@ class EmlsrManager : public Object std::map m_ulMainPhySwitch; //!< link ID-indexed map of timers started when //!< an aux PHY gains an UL TXOP and schedules //!< a channel switch for the main PHY + MainPhySwitchInfo m_mainPhySwitchInfo; //!< main PHY switch info private: /** diff --git a/src/wifi/model/sta-wifi-mac.cc b/src/wifi/model/sta-wifi-mac.cc index c83ec3c3c..eccc454ef 100644 --- a/src/wifi/model/sta-wifi-mac.cc +++ b/src/wifi/model/sta-wifi-mac.cc @@ -2105,17 +2105,32 @@ StaWifiMac::NotifySwitchingEmlsrLink(Ptr phy, uint8_t linkId, Time dela }; // cancel any pending event for the given PHY to switch link - if (auto eventIt = m_emlsrLinkSwitch.find(phy->GetPhyId()); eventIt != m_emlsrLinkSwitch.end()) - { - eventIt->second.Cancel(); - m_emlsrLinkSwitch.erase(eventIt); - } + CancelEmlsrPhyConnectEvent(phy->GetPhyId()); - // connect the PHY to the new link when the channel switch is completed, so that the PHY - // operating on the new link can possibly continue receiving frames in the meantime. + // connect the PHY to the new link when the channel switch is completed, unless there is a PHY + // operating on the new link that is possibly receiving an ICF, in which case the PHY is + // connected when the frame reception is completed if (delay.IsStrictlyPositive()) { - m_emlsrLinkSwitch.emplace(phy->GetPhyId(), Simulator::Schedule(delay, connectPhy)); + auto lambda = [=, this]() mutable { + const auto [maybeIcf, extension] = m_emlsrManager->CheckPossiblyReceivingIcf(linkId); + if (maybeIcf && extension.IsStrictlyPositive()) + { + NS_ASSERT_MSG(phy->GetPhyId() == m_emlsrManager->GetMainPhyId(), + "Only the main PHY is expected to move to a link on which another " + "PHY is operating. PHY ID=" + << +phy->GetPhyId()); + NS_LOG_DEBUG("Connecting main PHY to link " << +linkId << " is postponed by " + << extension.As(Time::US)); + NotifySwitchingEmlsrLink(phy, linkId, extension); + } + else + { + connectPhy(); + } + }; + + m_emlsrLinkSwitch.emplace(phy->GetPhyId(), Simulator::Schedule(delay, lambda)); } else { @@ -2123,6 +2138,17 @@ StaWifiMac::NotifySwitchingEmlsrLink(Ptr phy, uint8_t linkId, Time dela } } +void +StaWifiMac::CancelEmlsrPhyConnectEvent(uint8_t phyId) +{ + NS_LOG_FUNCTION(this << phyId); + if (auto eventIt = m_emlsrLinkSwitch.find(phyId); eventIt != m_emlsrLinkSwitch.end()) + { + eventIt->second.Cancel(); + m_emlsrLinkSwitch.erase(eventIt); + } +} + void StaWifiMac::NotifyChannelSwitching(uint8_t linkId) { diff --git a/src/wifi/model/sta-wifi-mac.h b/src/wifi/model/sta-wifi-mac.h index 4767b04ed..d131c9d86 100644 --- a/src/wifi/model/sta-wifi-mac.h +++ b/src/wifi/model/sta-wifi-mac.h @@ -321,6 +321,13 @@ class StaWifiMac : public WifiMac */ void NotifySwitchingEmlsrLink(Ptr phy, uint8_t linkId, Time delay); + /** + * Cancel any scheduled event for connecting the given PHY to an EMLSR link. + * + * @param phyId the ID of the given PHY + */ + void CancelEmlsrPhyConnectEvent(uint8_t phyId); + /** * Block transmissions on the given link for the given reason. *