wifi: Do not freeze backoff while using another EMLSR link

This commit is contained in:
Stefano Avallone
2023-09-23 19:04:08 +02:00
committed by Stefano Avallone
parent c512f3e872
commit cb7f3b68b6
5 changed files with 107 additions and 78 deletions

View File

@@ -199,7 +199,6 @@ ChannelAccessManager::ChannelAccessManager()
m_lastTxEnd(0),
m_lastSwitchingEnd(0),
m_usingOtherEmlsrLink(false),
m_lastUsingOtherEmlsrLinkEnd(0),
m_sleeping(false),
m_off(false),
m_linkId(0)
@@ -419,8 +418,8 @@ ChannelAccessManager::NeedBackoffUponAccess(Ptr<Txop> txop,
{
NS_LOG_FUNCTION(this << txop << hadFramesToTransmit << checkMediumBusy);
// No backoff needed if in sleep mode, off or when using another EMLSR link
if (m_sleeping || m_off || m_usingOtherEmlsrLink)
// No backoff needed if in sleep mode or off
if (m_sleeping || m_off)
{
return false;
}
@@ -479,11 +478,6 @@ ChannelAccessManager::RequestAccess(Ptr<Txop> txop)
{
m_phy->NotifyChannelAccessRequested();
}
if (m_usingOtherEmlsrLink)
{
NS_LOG_DEBUG("Channel access cannot be requested while using another EMLSR link");
return;
}
// Deny access if in sleep mode or off
if (m_sleeping || m_off)
{
@@ -620,8 +614,6 @@ ChannelAccessManager::GetAccessGrantStart(bool ignoreNav) const
Time ackTimeoutAccessStart = m_lastAckTimeoutEnd + sifs;
Time ctsTimeoutAccessStart = m_lastCtsTimeoutEnd + sifs;
Time switchingAccessStart = m_lastSwitchingEnd + sifs;
Time usingOtherEmlsrLinkAccessStart =
(m_usingOtherEmlsrLink ? Simulator::Now() : m_lastUsingOtherEmlsrLinkEnd) + sifs;
Time accessGrantedStart;
if (ignoreNav)
{
@@ -630,7 +622,6 @@ ChannelAccessManager::GetAccessGrantStart(bool ignoreNav) const
txAccessStart,
ackTimeoutAccessStart,
ctsTimeoutAccessStart,
usingOtherEmlsrLinkAccessStart,
switchingAccessStart});
}
else
@@ -641,14 +632,9 @@ ChannelAccessManager::GetAccessGrantStart(bool ignoreNav) const
navAccessStart,
ackTimeoutAccessStart,
ctsTimeoutAccessStart,
usingOtherEmlsrLinkAccessStart,
switchingAccessStart});
}
std::stringstream ss;
if (m_usingOtherEmlsrLink)
{
ss << ", using other EMLSR link access start=" << usingOtherEmlsrLinkAccessStart;
}
NS_LOG_INFO("access grant start=" << accessGrantedStart << ", rx access start=" << rxAccessStart
<< ", busy access start=" << busyAccessStart
<< ", tx access start=" << txAccessStart
@@ -1132,18 +1118,7 @@ void
ChannelAccessManager::NotifyStartUsingOtherEmlsrLink()
{
NS_LOG_FUNCTION(this);
// update backoff if a PHY is operating on this link
if (m_phy)
{
UpdateBackoff();
}
// Cancel timeout
if (m_accessTimeout.IsRunning())
{
m_accessTimeout.Cancel();
}
m_usingOtherEmlsrLink = true;
UpdateLastIdlePeriod();
}
void
@@ -1151,16 +1126,13 @@ ChannelAccessManager::NotifyStopUsingOtherEmlsrLink()
{
NS_LOG_FUNCTION(this);
m_usingOtherEmlsrLink = false;
m_lastUsingOtherEmlsrLinkEnd = Simulator::Now();
DoRestartAccessTimeoutIfNeeded();
}
void
ChannelAccessManager::UpdateLastIdlePeriod()
{
NS_LOG_FUNCTION(this);
Time idleStart =
std::max({m_lastTxEnd, m_lastRx.end, m_lastSwitchingEnd, m_lastUsingOtherEmlsrLinkEnd});
Time idleStart = std::max({m_lastTxEnd, m_lastRx.end, m_lastSwitchingEnd});
Time now = Simulator::Now();
if (idleStart >= now)

View File

@@ -33,6 +33,8 @@
#include <unordered_map>
#include <vector>
class EmlsrUlTxopTest;
namespace ns3
{
@@ -58,6 +60,9 @@ class FrameExchangeManager;
*/
class ChannelAccessManager : public Object
{
/// Allow test cases to access private members
friend class ::EmlsrUlTxopTest;
public:
ChannelAccessManager();
~ChannelAccessManager() override;
@@ -444,15 +449,13 @@ class ChannelAccessManager : public Object
std::vector<Time> m_lastPer20MHzBusyEnd; /**< the last busy end time per 20 MHz channel
(HE stations and channel width > 20 MHz only) */
std::map<WifiChannelListType, Timespan>
m_lastIdle; //!< the last idle start and end time for each channel type
Time m_lastSwitchingEnd; //!< the last switching end time
bool m_usingOtherEmlsrLink; //!< whether another EMLSR link is being used
Time m_lastUsingOtherEmlsrLinkEnd; //!< the last time we were blocked because using another
//!< EMLSR link
bool m_sleeping; //!< flag whether it is in sleeping state
bool m_off; //!< flag whether it is in off state
Time m_eifsNoDifs; //!< EIFS no DIFS time
EventId m_accessTimeout; //!< the access timeout ID
m_lastIdle; //!< the last idle start and end time for each channel type
Time m_lastSwitchingEnd; //!< the last switching end time
bool m_usingOtherEmlsrLink; //!< whether another EMLSR link is being used
bool m_sleeping; //!< flag whether it is in sleeping state
bool m_off; //!< flag whether it is in off state
Time m_eifsNoDifs; //!< EIFS no DIFS time
EventId m_accessTimeout; //!< the access timeout ID
bool m_generateBackoffOnNoTx; //!< whether the backoff should be invoked when the AC gains the
//!< right to start a TXOP but it does not transmit any frame
//!< (e.g., due to constraints associated with EMLSR operations),

View File

@@ -179,8 +179,12 @@ EhtFrameExchangeManager::StartTransmission(Ptr<Txop> edca, uint16_t allowedWidth
if (m_staMac && m_staMac->IsEmlsrLink(m_linkId))
{
// Cannot start a transmission on a link blocked because another EMLSR link is being used
NS_ASSERT_MSG(!UsingOtherEmlsrLink(),
"StartTransmission called while another EMLSR link is being used");
if (UsingOtherEmlsrLink())
{
NS_LOG_DEBUG("StartTransmission called while another EMLSR link is being used");
NotifyChannelReleased(edca);
return false;
}
auto emlsrManager = m_staMac->GetEmlsrManager();

View File

@@ -2262,10 +2262,11 @@ EmlsrUlTxopTest::EmlsrUlTxopTest(const Params& params)
m_emlsrEnabledTime(0),
m_firstUlPktsGenTime(0),
m_unblockMainPhyLinkDelay(MilliSeconds(20)),
m_checkBackoffStarted(false),
m_countQoSframes(0),
m_countBlockAck(0),
m_countRtsframes(0),
m_backoffSlots(0)
m_genBackoffIfTxopWithoutTx(params.genBackoffIfTxopWithoutTx)
{
m_nEmlsrStations = 1;
m_nNonEmlsrStations = 0;
@@ -2301,6 +2302,8 @@ EmlsrUlTxopTest::DoSetup()
Config::SetDefault("ns3::EhtConfiguration::MediumSyncDuration",
TimeValue(m_mediumSyncDuration));
Config::SetDefault("ns3::EhtConfiguration::MsdMaxNTxops", UintegerValue(m_msdMaxNTxops));
Config::SetDefault("ns3::ChannelAccessManager::GenerateBackoffIfTxopWithoutTx",
BooleanValue(m_genBackoffIfTxopWithoutTx));
EmlsrOperationsTestBase::DoSetup();
@@ -2341,6 +2344,40 @@ EmlsrUlTxopTest::BackoffGenerated(uint32_t backoff, uint8_t linkId)
{
NS_LOG_INFO("Backoff value " << backoff << " generated by EMLSR client on link " << +linkId
<< "\n");
if (linkId != m_mainPhyId)
{
return; // we are only interested in backoff on main PHY link
}
if (m_backoffEndTime)
{
if (m_checkBackoffStarted)
{
// another backoff value while checkBackoffStarted is true is generated only if
// GenerateBackoffIfTxopWithoutTx is true
NS_TEST_EXPECT_MSG_EQ(
m_genBackoffIfTxopWithoutTx,
true,
"Another backoff value should not be generated while the main PHY link is blocked");
NS_TEST_EXPECT_MSG_EQ(m_backoffEndTime.value(),
Simulator::Now(),
"Backoff generated at unexpected time");
}
else
{
// we are done checking the backoff
m_backoffEndTime.reset();
}
}
if (m_checkBackoffStarted)
{
m_backoffEndTime = Simulator::Now() +
m_staMacs[0]->GetChannelAccessManager(linkId)->GetSifs() +
(m_staMacs[0]->GetQosTxop(AC_BE)->GetAifsn(linkId) + backoff) *
m_staMacs[0]->GetChannelAccessManager(linkId)->GetSlot();
}
}
void
@@ -2590,6 +2627,7 @@ EmlsrUlTxopTest::CheckBlockAck(const WifiConstPsduMap& psduMap,
// this BlockAck has been sent on the non-EMLSR link, ignore it
break;
}
m_checkBackoffStarted = true;
if (!m_nonEmlsrLink)
{
m_countBlockAck++; // if all EMLSR links, next case is already executed now
@@ -2610,6 +2648,7 @@ EmlsrUlTxopTest::CheckBlockAck(const WifiConstPsduMap& psduMap,
// this BlockAck has been sent on the non-EMLSR link, ignore it
break;
}
m_checkBackoffStarted = true;
// check MediumSyncDelay timer on the EMLSR client after receiving BlockAck
Simulator::Schedule(txDuration + NanoSeconds(1), checkMediumSyncDelayTimerActive);
break;
@@ -2628,10 +2667,17 @@ EmlsrUlTxopTest::CheckBlockAck(const WifiConstPsduMap& psduMap,
m_lastMsdExpiryTime = Simulator::Now() +
m_staMacs[0]->GetEmlsrManager()->GetMediumSyncDuration() -
*elapsed;
NS_TEST_EXPECT_MSG_EQ(m_backoffSlots,
m_staMacs[0]->GetQosTxop(AC_BE)->GetBackoffSlots(1),
"Unexpected backoff slots after terminating the second frame "
"exchange on EMLSR links");
});
Simulator::Schedule(txDuration, [=, this]() {
m_checkBackoffStarted = false;
NS_TEST_ASSERT_MSG_EQ(m_backoffEndTime.has_value(),
true,
"Backoff end time should have been calculated");
// when this BlockAck is received, the TXOP ends and the main PHY link is unblocked,
// which causes a new backoff timer to be generated if the backoff timer is not
// already running
*m_backoffEndTime = Max(*m_backoffEndTime, Simulator::Now());
});
// make aux PHYs not capable of transmitting frames
@@ -2650,15 +2696,6 @@ EmlsrUlTxopTest::CheckRtsFrames(Ptr<const WifiMpdu> mpdu,
const WifiTxVector& txVector,
uint8_t linkId)
{
if (linkId != m_mainPhyId && !m_firstUlPktsGenTime.IsZero())
{
// this is the RTS sent by the aux PHY to start an UL TXOP
Simulator::ScheduleNow([=, this]() {
// save the number of backoff slots on link 1
m_backoffSlots = m_staMacs[0]->GetQosTxop(AC_BE)->GetBackoffSlots(1);
});
}
if (linkId != m_mainPhyId || m_firstUlPktsGenTime.IsZero())
{
// this function only considers RTS frames sent by the main PHY while the MediumSyncDelay
@@ -2735,9 +2772,10 @@ EmlsrUlTxopTest::CheckResults()
* ────────────────────────┬───┬┴───┴┬───┬───┬┴──┴─────────────────────────────────────────
* │RTS│ │QoS│QoS│
* └───┘ │ 6 │ 7 │
* └───┴───┘ MediumSyncDelay
* ┌──┐ timer expired ┌──┐
* [link 1] │BA│ backoff frozen │ │ │BA│
* └───┴───┘
* gen backoff gen backoff if MediumSyncDelay
* ┌──┐ (also many times) not running timer expired ┌──┐
* [link 1] │BA│ │ if allowed │ │ │BA│
* ─────────┬───┬───┬┴──┴───────────────────────────┬───┬─────┬───┬────┬───┬───┬┴──┴───────
* │QoS│QoS│ │RTS│ ... │RTS│ │QoS│QoS│
* │ 4 │ 5 │ └───┘ └───┘ │ 8 │ 9 │
@@ -2763,9 +2801,9 @@ EmlsrUlTxopTest::CheckResults()
* ────────────────────────┬───┬┴───┴┬───┬───┬┴──┴─────────────────────────────────────────
* │RTS│ │QoS│QoS│
* └───┘ │ 8 │ 9 │
* └───┴───┘ MediumSyncDelay
* ┌──┐ timer expired ┌──┐
* [link 1] │BA│ │ backoff frozen │ │ │BA│
* gen backoff gen backoff if MediumSyncDelay
* ┌──┐ (also many times) not running timer expired ┌──┐
* [link 1] │BA│ │ if allowed │ │ │BA│
* ─────────┬───┬───┬┴──┴───────────────────────────┬───┬─────┬───┬────┬───┬───┬┴──┴───────
* │QoS│QoS│ │RTS│ ... │RTS│ │QoS│QoS│
* │ 4 │ 5 │ └───┘ └───┘ │ 10│ 11│
@@ -3299,8 +3337,15 @@ WifiEmlsrTestSuite::WifiEmlsrTestSuite()
TestCase::QUICK);
}
AddTestCase(new EmlsrUlTxopTest({{0, 1, 2}, 40, 20, MicroSeconds(5504), 3}), TestCase::QUICK);
AddTestCase(new EmlsrUlTxopTest({{0, 1}, 40, 20, MicroSeconds(5504), 1}), TestCase::QUICK);
for (auto genBackoffIfTxopWithoutTx : {true, false})
{
AddTestCase(new EmlsrUlTxopTest(
{{0, 1, 2}, 40, 20, MicroSeconds(5504), 3, genBackoffIfTxopWithoutTx}),
TestCase::QUICK);
AddTestCase(
new EmlsrUlTxopTest({{0, 1}, 40, 20, MicroSeconds(5504), 1, genBackoffIfTxopWithoutTx}),
TestCase::QUICK);
}
for (bool switchAuxPhy : {true, false})
{

View File

@@ -488,10 +488,10 @@ class EmlsrDlTxopTest : public EmlsrOperationsTestBase
* of transmitting, we block transmissions on the link where the main PHY is operating and
* generate new UL packets, which will then be transmitted on a link where an aux PHY is
* operating. Thus, the aux PHY transmits an RTS frame and the main PHY will take over and
* transmit the second UL data frame. We check that the number of backoff slots on the link
* where the main PHY was operating (which is blocked because another EMLSR link is being used)
* at the end of the frame exchange on the other EMLSR link is the same as the one at the
* beginning of that frame exchange.
* transmit the second UL data frame. We check that, while the link on which the main PHY was
* operating is blocked because another EMLSR link is being used, new backoff values for that
* link are generated if and only if the QosTxop::GenerateBackoffIfTxopWithoutTx attribute is
* true; otherwise, a new backoff value is generated when the link is unblocked.
* - When the exchange of the second UL data frame terminates, we make the aux PHY unable to
* transmit, block transmissions on the non-EMLSR link (if any) and generate some more UL
* packets, which will then be transmitted by the main PHY. However, a MediumSyncDelay timer
@@ -511,13 +511,16 @@ class EmlsrUlTxopTest : public EmlsrOperationsTestBase
struct Params
{
std::set<uint8_t>
linksToEnableEmlsrOn; //!< IDs of links on which EMLSR mode should be enabled
uint16_t channelWidth; //!< width (MHz) of the channels used by MLDs
uint16_t auxPhyChannelWidth; //!< max width (MHz) supported by aux PHYs
Time mediumSyncDuration; //!< duration of the MediumSyncDelay timer
uint8_t msdMaxNTxops; //!< Max number of TXOPs that an EMLSR client is allowed
//!< to attempt to initiate while the MediumSyncDelay
//!< timer is running (zero indicates no limit)
linksToEnableEmlsrOn; //!< IDs of links on which EMLSR mode should be enabled
uint16_t channelWidth; //!< width (MHz) of the channels used by MLDs
uint16_t auxPhyChannelWidth; //!< max width (MHz) supported by aux PHYs
Time mediumSyncDuration; //!< duration of the MediumSyncDelay timer
uint8_t msdMaxNTxops; //!< Max number of TXOPs that an EMLSR client is allowed
//!< to attempt to initiate while the MediumSyncDelay
//!< timer is running (zero indicates no limit)
bool genBackoffIfTxopWithoutTx; //!< whether the backoff should be invoked when the AC
//!< gains the right to start a TXOP but it does not
//!< transmit any frame
};
/**
@@ -601,13 +604,15 @@ class EmlsrUlTxopTest : public EmlsrOperationsTestBase
//!< generated and the time transmissions are unblocked
//!< on the link where the main PHY is operating on
Time m_lastMsdExpiryTime; //!< expiry time of the last MediumSyncDelay timer
bool m_checkBackoffStarted; //!< whether we are checking the generated backoff values
std::optional<Time> m_backoffEndTime; //!< expected backoff end time on main PHY link
Ptr<ListErrorModel> m_errorModel; ///< error rate model to corrupt packets
std::size_t m_countQoSframes; //!< counter for QoS frames
std::size_t m_countBlockAck; //!< counter for BlockAck frames
std::size_t m_countRtsframes; //!< counter for RTS frames
uint32_t m_backoffSlots; //!< backoff slots on the link where the main PHY is
//!< operating when an RTS is sent by the aux PHY to
//!< start an UL TXOP
bool m_genBackoffIfTxopWithoutTx; //!< whether the backoff should be invoked when the AC
//!< gains the right to start a TXOP but it does not
//!< transmit any frame
};
/**