wifi: Extend EMLSR test to check UL TXOP with aux PHY switch true
This commit is contained in:
@@ -3487,6 +3487,8 @@ EmlsrLinkSwitchTest::EmlsrLinkSwitchTest(const Params& params)
|
||||
m_resetCamState(params.resetCamState),
|
||||
m_auxPhyMaxChWidth(params.auxPhyMaxChWidth),
|
||||
m_countQoSframes(0),
|
||||
m_countIcfFrames(0),
|
||||
m_countRtsFrames(0),
|
||||
m_txPsdusPos(0)
|
||||
{
|
||||
m_nEmlsrStations = 1;
|
||||
@@ -3497,7 +3499,7 @@ EmlsrLinkSwitchTest::EmlsrLinkSwitchTest(const Params& params)
|
||||
m_duration = Seconds(1.0);
|
||||
// when aux PHYs do not switch link, the main PHY switches back to its previous link after
|
||||
// a TXOP, hence the transition delay must exceed the channel switch delay (default: 250us)
|
||||
m_transitionDelay = {MicroSeconds(256)};
|
||||
m_transitionDelay = {MicroSeconds(128)};
|
||||
}
|
||||
|
||||
void
|
||||
@@ -3547,12 +3549,6 @@ EmlsrLinkSwitchTest::Transmit(Ptr<WifiMac> mac,
|
||||
{0},
|
||||
linksToBlock);
|
||||
}
|
||||
else if (category == WifiActionHeader::BLOCK_ACK &&
|
||||
action.blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_RESPONSE)
|
||||
{
|
||||
// store the current number of transmitted frame
|
||||
m_txPsdusPos = m_txPsdus.size() - 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -3564,6 +3560,27 @@ EmlsrLinkSwitchTest::Transmit(Ptr<WifiMac> mac,
|
||||
CheckQosFrames(psduMap, txVector, linkId);
|
||||
break;
|
||||
|
||||
case WIFI_MAC_CTL_RTS:
|
||||
// corrupt the first RTS frame (sent by the EMLSR client)
|
||||
if (++m_countRtsFrames == 1)
|
||||
{
|
||||
m_errorModel->SetList({psdu->GetPacket()->GetUid()});
|
||||
}
|
||||
// block transmissions on all other links at non-AP MLD side
|
||||
{
|
||||
std::set<uint8_t> links{0, 1, 2};
|
||||
links.erase(linkId);
|
||||
m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(
|
||||
WifiQueueBlockedReason::TID_NOT_MAPPED,
|
||||
AC_BE,
|
||||
{WIFI_QOSDATA_QUEUE},
|
||||
m_apMac->GetAddress(),
|
||||
m_staMacs[0]->GetAddress(),
|
||||
{0},
|
||||
links);
|
||||
}
|
||||
break;
|
||||
|
||||
default:;
|
||||
}
|
||||
}
|
||||
@@ -3575,9 +3592,16 @@ EmlsrLinkSwitchTest::DoSetup()
|
||||
Config::SetDefault("ns3::EmlsrManager::ResetCamState", BooleanValue(m_resetCamState));
|
||||
Config::SetDefault("ns3::EmlsrManager::AuxPhyChannelWidth", UintegerValue(m_auxPhyMaxChWidth));
|
||||
Config::SetDefault("ns3::WifiPhy::ChannelSwitchDelay", TimeValue(MicroSeconds(75)));
|
||||
Config::SetDefault("ns3::EhtConfiguration::MediumSyncDuration", TimeValue(Time{0}));
|
||||
|
||||
EmlsrOperationsTestBase::DoSetup();
|
||||
|
||||
m_errorModel = CreateObject<ListErrorModel>();
|
||||
for (std::size_t linkId = 0; linkId < m_apMac->GetNLinks(); ++linkId)
|
||||
{
|
||||
m_apMac->GetWifiPhy(linkId)->SetPostReceptionErrorModel(m_errorModel);
|
||||
}
|
||||
|
||||
// use channels of different widths
|
||||
for (auto mac : std::initializer_list<Ptr<WifiMac>>{m_apMac, m_staMacs[0]})
|
||||
{
|
||||
@@ -3665,18 +3689,59 @@ EmlsrLinkSwitchTest::CheckQosFrames(const WifiConstPsduMap& psduMap,
|
||||
// hence triggering yet another link switching on the EMLSR client
|
||||
m_apMac->GetDevice()->GetNode()->AddApplication(GetApplication(DOWNLINK, 0, 2, 1000));
|
||||
break;
|
||||
case 4:
|
||||
// block transmissions on all links at non-AP MLD side
|
||||
m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
|
||||
AC_BE,
|
||||
{WIFI_QOSDATA_QUEUE},
|
||||
m_apMac->GetAddress(),
|
||||
m_staMacs[0]->GetAddress(),
|
||||
{0},
|
||||
{0, 1, 2});
|
||||
// unblock transmissions on the link used for ML setup (non-AP MLD side)
|
||||
m_staMacs[0]->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
|
||||
AC_BE,
|
||||
{WIFI_QOSDATA_QUEUE},
|
||||
m_apMac->GetAddress(),
|
||||
m_staMacs[0]->GetAddress(),
|
||||
{0},
|
||||
{m_mainPhyId});
|
||||
// trigger establishment of BA agreement with AP as recipient
|
||||
m_staMacs[0]->GetDevice()->GetNode()->AddApplication(GetApplication(UPLINK, 0, 4, 1000));
|
||||
break;
|
||||
case 5:
|
||||
// unblock transmissions on all links at non-AP MLD side
|
||||
m_staMacs[0]->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
|
||||
AC_BE,
|
||||
{WIFI_QOSDATA_QUEUE},
|
||||
m_apMac->GetAddress(),
|
||||
m_staMacs[0]->GetAddress(),
|
||||
{0},
|
||||
{0, 1, 2});
|
||||
// block transmissions on the link used for ML setup (non-AP MLD side)
|
||||
m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
|
||||
AC_BE,
|
||||
{WIFI_QOSDATA_QUEUE},
|
||||
m_apMac->GetAddress(),
|
||||
m_staMacs[0]->GetAddress(),
|
||||
{0},
|
||||
{m_mainPhyId});
|
||||
// generate a new data packet, which will be sent on a link other than the one
|
||||
// used for ML setup, hence triggering a link switching on the EMLSR client
|
||||
m_staMacs[0]->GetDevice()->GetNode()->AddApplication(GetApplication(UPLINK, 0, 2, 1000));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AUX PHY switching enabled
|
||||
* AUX PHY switching enabled (X = channel switch delay)
|
||||
*
|
||||
* |--------- aux PHY A ---------|------ main PHY ------|-------------- aux PHY B -------------
|
||||
* ┌───┐ ┌───┐
|
||||
* │ICF│ │QoS│
|
||||
* ──────────────────────────┴───┴┬───┬┴───┴┬──┬────────────────────────────────────────────────
|
||||
* [link 0] │CTS│ │BA│
|
||||
* └───┘ └──┘
|
||||
* [link 0] │CTS│ │BA│
|
||||
* └───┘ └──┘
|
||||
*
|
||||
*
|
||||
* |--------- main PHY ----------|------------------ aux PHY A ----------------|--- main PHY ---
|
||||
@@ -3694,8 +3759,28 @@ EmlsrLinkSwitchTest::CheckQosFrames(const WifiConstPsduMap& psduMap,
|
||||
* [link 2] │CTS│ │BA│
|
||||
* └───┘ └──┘
|
||||
*
|
||||
* ... continued ...
|
||||
*
|
||||
* AUX PHY switching disabled (X = main PHY channel switch delay)
|
||||
* |----------------------------------------- aux PHY B ---------------------------------------
|
||||
* ─────────────────────────────────────────────────────────────────────────────────────────────
|
||||
* [link 0]
|
||||
*
|
||||
* |--------- main PHY ----------|X|X|------------------------ aux PHY A ----------------------
|
||||
* ┌───┐
|
||||
* │ACK│
|
||||
* ──────────┬───┬┴───┴────────────────────────────────────────────────────────────────────────
|
||||
* [link 1] │QoS│
|
||||
* └───┘
|
||||
*
|
||||
* |-------- aux PHY A ----------|X|---------------------- main PHY ---------------------------
|
||||
* ┌──┐
|
||||
* │BA│
|
||||
* ────────────────────────┬───X──────┬───┬┴──┴────────────────────────────────────────────────
|
||||
* [link 2] │RTS│ │QoS│
|
||||
* └───┘ └───┘
|
||||
************************************************************************************************
|
||||
*
|
||||
* AUX PHY switching disabled (X = channel switch delay)
|
||||
*
|
||||
* |------------------------------------------ aux PHY A ---------------------------------------
|
||||
* |-- main PHY --|X|
|
||||
@@ -3721,6 +3806,28 @@ EmlsrLinkSwitchTest::CheckQosFrames(const WifiConstPsduMap& psduMap,
|
||||
* ─────────────────────────────────────────────────┴───┴┬───┬┴───┴┬──┬─────────────────────────
|
||||
* [link 2] │CTS│ │BA│
|
||||
* └───┘ └──┘
|
||||
*
|
||||
* ... continued ...
|
||||
*
|
||||
* |----------------------------------------- aux PHY A ---------------------------------------
|
||||
* ─────────────────────────────────────────────────────────────────────────────────────────────
|
||||
* [link 0]
|
||||
*
|
||||
* |-------- main PHY --------| |--- main PHY ---|
|
||||
* ┌───┐
|
||||
* │ACK│
|
||||
* ──────────┬───┬┴───┴────────────────────────────────────────────────────────────────────────
|
||||
* [link 1] │QoS│
|
||||
* └───┘
|
||||
*
|
||||
* |------------------------------------------ aux PHY B --------------------------------------
|
||||
* |X||X| |X|-------------- main PHY --------------
|
||||
* ┌───┐ ┌──┐
|
||||
* │CTS│ │BA│
|
||||
* ────────────────────────┬───X───────────────┬───┬┴───┴┬───┬┴──┴─────────────────────────────
|
||||
* [link 2] │RTS│ │RTS│ │QoS│
|
||||
* └───┘ └───┘ └───┘
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
@@ -3728,14 +3835,16 @@ EmlsrLinkSwitchTest::CheckInitialControlFrame(const WifiConstPsduMap& psduMap,
|
||||
const WifiTxVector& txVector,
|
||||
uint8_t linkId)
|
||||
{
|
||||
if (m_txPsdusPos == 0)
|
||||
if (++m_countIcfFrames == 1)
|
||||
{
|
||||
// the iterator has not been set yet, thus we are not done with the establishment of
|
||||
// the BA agreement
|
||||
return;
|
||||
m_txPsdusPos = m_txPsdus.size() - 1;
|
||||
}
|
||||
|
||||
NS_TEST_EXPECT_MSG_LT(m_countQoSframes, 4, "Unexpected number of ICFs");
|
||||
// the first ICF is sent to protect ADDBA_REQ for DL BA agreement, then one ICF is sent before
|
||||
// each of the 4 DL QoS Data frames; finally, another ICF is sent before the ADDBA_RESP for UL
|
||||
// BA agreement. Hence, at any time the number of ICF sent is always greater than or equal to
|
||||
// the number of QoS data frames sent.
|
||||
NS_TEST_EXPECT_MSG_GT_OR_EQ(m_countIcfFrames, m_countQoSframes, "Unexpected number of ICFs");
|
||||
|
||||
auto mainPhy = m_staMacs[0]->GetDevice()->GetPhy(m_mainPhyId);
|
||||
auto phyRecvIcf = m_staMacs[0]->GetWifiPhy(linkId); // PHY receiving the ICF
|
||||
@@ -3757,10 +3866,12 @@ EmlsrLinkSwitchTest::CheckInitialControlFrame(const WifiConstPsduMap& psduMap,
|
||||
<< m_countQoSframes << " is operating on a channel whose width exceeds the limit");
|
||||
}
|
||||
|
||||
// if aux PHYs switch links, only the first ICF is received by the main PHY; otherwise,
|
||||
// the first ICF and the last ICF are received by the main PHY
|
||||
// the first two ICFs (before ADDBA_REQ and before first DL QoS Data) and the ICF before the
|
||||
// ADDBA_RESP are received by the main PHY. If aux PHYs do not switch links, the ICF before
|
||||
// the last DL QoS Data is also received by the main PHY
|
||||
NS_TEST_EXPECT_MSG_EQ((phyRecvIcf == mainPhy),
|
||||
(m_countQoSframes == 0 || (!m_switchAuxPhy && m_countQoSframes == 3)),
|
||||
(m_countIcfFrames == 1 || m_countIcfFrames == 2 ||
|
||||
(!m_switchAuxPhy && m_countIcfFrames == 5) || m_countIcfFrames == 6),
|
||||
"Expecting that the ICF was received by the main PHY");
|
||||
|
||||
// if aux PHYs do not switch links, the main PHY is operating on its original link when
|
||||
@@ -3815,36 +3926,86 @@ EmlsrLinkSwitchTest::CheckResults()
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_NE(m_txPsdusPos, 0, "BA agreement establishment not completed");
|
||||
|
||||
const std::size_t nRxOk = 4; // successfully received ICFs
|
||||
// Expected frame exchanges after ML setup and EML OMN exchange:
|
||||
// 1. (DL) ICF + CTS + ADDBA_REQ + ACK
|
||||
// 2. (UL) ADDBA_RESP + ACK
|
||||
// 3. (DL) ICF + CTS + DATA + BA
|
||||
// 4. (DL) ICF + CTS + DATA + BA
|
||||
// 5. (DL) ICF + CTS + DATA + BA
|
||||
// 6. (DL) ICF + CTS + DATA + BA
|
||||
// 7. (UL) ADDBA_REQ + ACK
|
||||
// 8. (DL) ICF + CTS + ADDBA_RESP + ACK
|
||||
// 9. (UL) DATA + BA
|
||||
// 10. (UL) RTS - CTS timeout
|
||||
// 11. (UL) (RTS + CTS if SwitchAuxPhy is false + ) DATA + BA
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(m_countIcfFrames, 6, "Unexpected number of ICFs sent");
|
||||
|
||||
// frame exchanges without RTS because the EMLSR client sent the initial frame through main PHY
|
||||
const std::size_t nFrameExchNoRts = m_switchAuxPhy ? 4 : 3;
|
||||
|
||||
const std::size_t nFrameExchWithRts = m_switchAuxPhy ? 0 : 1;
|
||||
|
||||
NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(),
|
||||
m_txPsdusPos + 2 + nRxOk * 4,
|
||||
m_txPsdusPos +
|
||||
m_countIcfFrames * 4 + /* frames in frame exchange with ICF */
|
||||
nFrameExchNoRts * 2 + /* frames in frame exchange without RTS */
|
||||
nFrameExchWithRts * 4 + /* frames in frame exchange with RTS */
|
||||
1, /* corrupted RTS */
|
||||
"Insufficient number of TX PSDUs");
|
||||
|
||||
// m_txPsdusPos points to ADDBA_RESPONSE, then ACK and then ICF
|
||||
auto psduIt = std::next(m_txPsdus.cbegin(), m_txPsdusPos + 2);
|
||||
// m_txPsdusPos points to the first ICF
|
||||
auto psduIt = std::next(m_txPsdus.cbegin(), m_txPsdusPos);
|
||||
|
||||
for (std::size_t i = 0; i < nRxOk; i++)
|
||||
const std::size_t nFrameExchanges =
|
||||
m_countIcfFrames + nFrameExchNoRts + nFrameExchWithRts + 1 /* corrupted RTS */;
|
||||
|
||||
for (std::size_t i = 1; i <= nFrameExchanges; ++i)
|
||||
{
|
||||
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
|
||||
psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsTrigger()),
|
||||
true,
|
||||
"Expected a Trigger Frame (ICF)");
|
||||
psduIt++;
|
||||
NS_TEST_EXPECT_MSG_EQ(
|
||||
(psduIt->psduMap.size() == 1 && psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsCts()),
|
||||
true,
|
||||
"Expected a CTS");
|
||||
psduIt++;
|
||||
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
|
||||
psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsQosData()),
|
||||
true,
|
||||
"Expected a QoS Data frame");
|
||||
psduIt++;
|
||||
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
|
||||
psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsBlockAck()),
|
||||
true,
|
||||
"Expected a BlockAck");
|
||||
if (i == 1 || (i >= 3 && i <= 6) || i == 8 || i == 10 || (i == 11 && !m_switchAuxPhy))
|
||||
{
|
||||
// frame exchanges with protection
|
||||
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
|
||||
(i < 9 ? psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsTrigger()
|
||||
: psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsRts())),
|
||||
true,
|
||||
"Expected a Trigger Frame (ICF)");
|
||||
psduIt++;
|
||||
if (i == 10)
|
||||
{
|
||||
continue; // corrupted RTS
|
||||
}
|
||||
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
|
||||
psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsCts()),
|
||||
true,
|
||||
"Expected a CTS");
|
||||
psduIt++;
|
||||
}
|
||||
|
||||
if (i == 1 || i == 2 || i == 7 || i == 8) // frame exchanges with ADDBA REQ/RESP frames
|
||||
{
|
||||
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
|
||||
psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsMgt()),
|
||||
true,
|
||||
"Expected a management frame");
|
||||
psduIt++;
|
||||
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
|
||||
psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsAck()),
|
||||
true,
|
||||
"Expected a Normal Ack");
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
|
||||
psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsQosData()),
|
||||
true,
|
||||
"Expected a QoS Data frame");
|
||||
psduIt++;
|
||||
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
|
||||
psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsBlockAck()),
|
||||
true,
|
||||
"Expected a BlockAck");
|
||||
}
|
||||
psduIt++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,9 +669,10 @@ class EmlsrUlTxopTest : public EmlsrOperationsTestBase
|
||||
* - the first one on the link used for ML setup, hence no PHY switch occurs
|
||||
* - the second one on another link, thus causing the main PHY to switch link
|
||||
* - the third one on the remaining link, thus causing the main PHY to switch link again
|
||||
* - the fourth one on the link used for ML setup; if the aux PHYs switches link, there is
|
||||
* one aux PHY listening on such a link and the main PHY switches to this link, otherwise
|
||||
* no PHY is listening on such a link and there is no response to the ICF sent by the AP MLD
|
||||
* - the fourth one on the link used for ML setup
|
||||
*
|
||||
* Afterwards, the EMLSR client transmits 2 QoS data frames; the first one on the link used for
|
||||
* ML setup (hence, no RTS is sent), the second one on another link.
|
||||
*/
|
||||
class EmlsrLinkSwitchTest : public EmlsrOperationsTestBase
|
||||
{
|
||||
@@ -741,9 +742,12 @@ class EmlsrLinkSwitchTest : public EmlsrOperationsTestBase
|
||||
the Main PHY was operating before moving to the link of Aux PHY */
|
||||
bool m_resetCamState; /**< whether to reset the state of the ChannelAccessManager associated
|
||||
with the link on which the main PHY has just switched to */
|
||||
MHz_u m_auxPhyMaxChWidth; //!< max channel width supported by aux PHYs
|
||||
std::size_t m_countQoSframes; //!< counter for QoS data frames
|
||||
std::size_t m_txPsdusPos; //!< a position in the vector of TX PSDUs
|
||||
MHz_u m_auxPhyMaxChWidth; //!< max channel width supported by aux PHYs
|
||||
std::size_t m_countQoSframes; //!< counter for QoS data frames
|
||||
std::size_t m_countIcfFrames; //!< counter for ICF frames
|
||||
std::size_t m_countRtsFrames; //!< counter for RTS frames
|
||||
std::size_t m_txPsdusPos; //!< position in the vector of TX PSDUs of the first ICF
|
||||
Ptr<ListErrorModel> m_errorModel; ///< error rate model to corrupt packets at AP MLD
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user