wifi: Do not freeze backoff while using another EMLSR link
This commit is contained in:
committed by
Stefano Avallone
parent
c512f3e872
commit
cb7f3b68b6
@@ -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)
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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})
|
||||
{
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user