wifi: Extend EMLSR unit test to check single link EMLSR clients
This commit is contained in:
@@ -327,13 +327,12 @@ EmlsrOperationsTestBase::DoSetup()
|
||||
SpectrumWifiPhyHelper phyHelper(3);
|
||||
phyHelper.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
|
||||
phyHelper.SetPcapCaptureType(WifiPhyHelper::PcapCaptureType::PCAP_PER_LINK);
|
||||
phyHelper.Set(0, "ChannelSettings", StringValue("{2, 0, BAND_2_4GHZ, 0}"));
|
||||
phyHelper.Set(1, "ChannelSettings", StringValue("{36, 0, BAND_5GHZ, 0}"));
|
||||
phyHelper.Set(2, "ChannelSettings", StringValue("{1, 0, BAND_6GHZ, 0}"));
|
||||
// Add three spectrum channels to use multi-RF interface
|
||||
phyHelper.AddChannel(CreateObject<MultiModelSpectrumChannel>(), WIFI_SPECTRUM_2_4_GHZ);
|
||||
phyHelper.AddChannel(CreateObject<MultiModelSpectrumChannel>(), WIFI_SPECTRUM_5_GHZ);
|
||||
phyHelper.AddChannel(CreateObject<MultiModelSpectrumChannel>(), WIFI_SPECTRUM_6_GHZ);
|
||||
|
||||
for (std::size_t id = 0; id < m_channelsStr.size(); ++id)
|
||||
{
|
||||
phyHelper.Set(id, "ChannelSettings", StringValue(m_channelsStr[id]));
|
||||
phyHelper.AddChannel(CreateObject<MultiModelSpectrumChannel>(), m_freqRanges[id]);
|
||||
}
|
||||
|
||||
WifiMacHelper mac;
|
||||
mac.SetType("ns3::ApWifiMac",
|
||||
@@ -346,6 +345,7 @@ EmlsrOperationsTestBase::DoSetup()
|
||||
BooleanValue(true));
|
||||
|
||||
NetDeviceContainer apDevice = wifi.Install(phyHelper, mac, wifiApNode);
|
||||
m_apMac = DynamicCast<ApWifiMac>(DynamicCast<WifiNetDevice>(apDevice.Get(0))->GetMac());
|
||||
|
||||
mac.SetType("ns3::StaWifiMac",
|
||||
"Ssid",
|
||||
@@ -360,9 +360,25 @@ EmlsrOperationsTestBase::DoSetup()
|
||||
"MainPhyId",
|
||||
UintegerValue(m_mainPhyId));
|
||||
|
||||
NetDeviceContainer staDevices = wifi.Install(phyHelper, mac, wifiStaNodes);
|
||||
if (m_nPhysPerEmlsrDevice < 3)
|
||||
{
|
||||
phyHelper = SpectrumWifiPhyHelper(m_nPhysPerEmlsrDevice);
|
||||
phyHelper.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
|
||||
phyHelper.SetPcapCaptureType(WifiPhyHelper::PcapCaptureType::PCAP_PER_LINK);
|
||||
|
||||
m_apMac = DynamicCast<ApWifiMac>(DynamicCast<WifiNetDevice>(apDevice.Get(0))->GetMac());
|
||||
for (std::size_t id = 0; id < m_nPhysPerEmlsrDevice; ++id)
|
||||
{
|
||||
phyHelper.Set(id, "ChannelSettings", StringValue(m_channelsStr[id]));
|
||||
auto channel =
|
||||
DynamicCast<MultiModelSpectrumChannel>(m_apMac->GetWifiPhy(id)->GetChannel());
|
||||
NS_TEST_ASSERT_MSG_NE(channel,
|
||||
nullptr,
|
||||
"Channel " << +id << " is not a spectrum channel");
|
||||
phyHelper.AddChannel(channel, m_freqRanges[id]);
|
||||
}
|
||||
}
|
||||
|
||||
NetDeviceContainer staDevices = wifi.Install(phyHelper, mac, wifiStaNodes);
|
||||
|
||||
for (uint32_t i = 0; i < staDevices.GetN(); i++)
|
||||
{
|
||||
@@ -4956,6 +4972,202 @@ EmlsrCcaBusyTest::CheckPoint3()
|
||||
"until end of transmission");
|
||||
}
|
||||
|
||||
SingleLinkEmlsrTest::SingleLinkEmlsrTest(bool switchAuxPhy, bool auxPhyTxCapable)
|
||||
: EmlsrOperationsTestBase(
|
||||
"Check EMLSR single link operation (switchAuxPhy=" + std::to_string(switchAuxPhy) +
|
||||
", auxPhyTxCapable=" + std::to_string(auxPhyTxCapable) + ")"),
|
||||
m_switchAuxPhy(switchAuxPhy),
|
||||
m_auxPhyTxCapable(auxPhyTxCapable)
|
||||
{
|
||||
m_mainPhyId = 0;
|
||||
m_linksToEnableEmlsrOn = {m_mainPhyId};
|
||||
m_nPhysPerEmlsrDevice = 1;
|
||||
m_nEmlsrStations = 1;
|
||||
m_nNonEmlsrStations = 0;
|
||||
|
||||
// channel switch delay will be also set to 64 us
|
||||
m_paddingDelay = {MicroSeconds(64)};
|
||||
m_transitionDelay = {MicroSeconds(64)};
|
||||
m_establishBaDl = true;
|
||||
m_establishBaUl = true;
|
||||
m_duration = Seconds(0.5);
|
||||
}
|
||||
|
||||
void
|
||||
SingleLinkEmlsrTest::DoSetup()
|
||||
{
|
||||
Config::SetDefault("ns3::WifiPhy::ChannelSwitchDelay", TimeValue(MicroSeconds(64)));
|
||||
Config::SetDefault("ns3::DefaultEmlsrManager::SwitchAuxPhy", BooleanValue(m_switchAuxPhy));
|
||||
Config::SetDefault("ns3::EmlsrManager::AuxPhyTxCapable", BooleanValue(m_auxPhyTxCapable));
|
||||
|
||||
EmlsrOperationsTestBase::DoSetup();
|
||||
}
|
||||
|
||||
void
|
||||
SingleLinkEmlsrTest::Transmit(Ptr<WifiMac> mac,
|
||||
uint8_t phyId,
|
||||
WifiConstPsduMap psduMap,
|
||||
WifiTxVector txVector,
|
||||
double txPowerW)
|
||||
{
|
||||
EmlsrOperationsTestBase::Transmit(mac, phyId, psduMap, txVector, txPowerW);
|
||||
|
||||
const auto psdu = psduMap.cbegin()->second;
|
||||
const auto& hdr = psdu->GetHeader(0);
|
||||
|
||||
// nothing to do in case of Beacon and CF-End frames
|
||||
if (hdr.IsBeacon() || hdr.IsCfEnd())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto linkId = mac->GetLinkForPhy(phyId);
|
||||
NS_TEST_ASSERT_MSG_EQ(linkId.has_value(),
|
||||
true,
|
||||
"PHY " << +phyId << " is not operating on any link");
|
||||
NS_TEST_EXPECT_MSG_EQ(+linkId.value(), 0, "TX occurred on unexpected link " << +linkId.value());
|
||||
|
||||
if (m_eventIt != m_events.cend())
|
||||
{
|
||||
// check that the expected frame is being transmitted
|
||||
NS_TEST_EXPECT_MSG_EQ(m_eventIt->hdrType,
|
||||
hdr.GetType(),
|
||||
"Unexpected MAC header type for frame #"
|
||||
<< std::distance(m_events.cbegin(), m_eventIt));
|
||||
// perform actions/checks, if any
|
||||
if (m_eventIt->func)
|
||||
{
|
||||
m_eventIt->func(psdu, txVector);
|
||||
}
|
||||
|
||||
++m_eventIt;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SingleLinkEmlsrTest::DoRun()
|
||||
{
|
||||
// lambda to check that AP MLD started the transition delay timer after the TX/RX of given frame
|
||||
auto checkTransDelay = [this](Ptr<const WifiPsdu> psdu,
|
||||
const WifiTxVector& txVector,
|
||||
bool testUnblockedForOtherReasons,
|
||||
const std::string& frameStr) {
|
||||
const auto txDuration = WifiPhy::CalculateTxDuration(psdu->GetSize(),
|
||||
txVector,
|
||||
m_apMac->GetWifiPhy(0)->GetPhyBand());
|
||||
Simulator::Schedule(txDuration + MicroSeconds(1), /* to account for propagation delay */
|
||||
&SingleLinkEmlsrTest::CheckBlockedLink,
|
||||
this,
|
||||
m_apMac,
|
||||
m_staMacs[0]->GetAddress(),
|
||||
0,
|
||||
WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
|
||||
true,
|
||||
"Checking that AP MLD blocked transmissions to single link EMLSR "
|
||||
"client after " +
|
||||
frameStr,
|
||||
testUnblockedForOtherReasons);
|
||||
};
|
||||
|
||||
// expected sequence of transmitted frames
|
||||
m_events.emplace_back(WIFI_MAC_MGT_ASSOCIATION_REQUEST);
|
||||
m_events.emplace_back(WIFI_MAC_CTL_ACK);
|
||||
m_events.emplace_back(WIFI_MAC_MGT_ASSOCIATION_RESPONSE);
|
||||
m_events.emplace_back(WIFI_MAC_CTL_ACK);
|
||||
|
||||
// EML OMN sent by EMLSR client
|
||||
m_events.emplace_back(WIFI_MAC_MGT_ACTION,
|
||||
[=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
|
||||
// check that the address of the EMLSR client is seen as an MLD
|
||||
// address
|
||||
NS_TEST_EXPECT_MSG_EQ(
|
||||
m_apMac->GetWifiRemoteStationManager(0)
|
||||
->GetMldAddress(m_staMacs[0]->GetAddress())
|
||||
.has_value(),
|
||||
true,
|
||||
"Expected the EMLSR client address to be seen as an MLD address");
|
||||
});
|
||||
m_events.emplace_back(WIFI_MAC_CTL_ACK);
|
||||
// EML OMN sent by AP MLD, protected by ICF
|
||||
m_events.emplace_back(WIFI_MAC_CTL_TRIGGER);
|
||||
m_events.emplace_back(WIFI_MAC_CTL_CTS);
|
||||
m_events.emplace_back(WIFI_MAC_MGT_ACTION);
|
||||
m_events.emplace_back(WIFI_MAC_CTL_ACK,
|
||||
[=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
|
||||
// check that EMLSR mode has been enabled on link 0 of EMLSR client
|
||||
NS_TEST_EXPECT_MSG_EQ(
|
||||
m_staMacs[0]->IsEmlsrLink(0),
|
||||
true,
|
||||
"Expected EMLSR mode to be enabled on link 0 of EMLSR client");
|
||||
});
|
||||
|
||||
// Establishment of BA agreement for downlink direction
|
||||
|
||||
// ADDBA REQUEST sent by AP MLD (protected by ICF)
|
||||
m_events.emplace_back(WIFI_MAC_CTL_TRIGGER);
|
||||
m_events.emplace_back(WIFI_MAC_CTL_CTS);
|
||||
m_events.emplace_back(WIFI_MAC_MGT_ACTION);
|
||||
m_events.emplace_back(WIFI_MAC_CTL_ACK,
|
||||
[=](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
|
||||
// check that transition delay is started after reception of Ack
|
||||
checkTransDelay(psdu, txVector, false, "DL ADDBA REQUEST");
|
||||
});
|
||||
|
||||
// ADDBA RESPONSE sent by EMLSR client (no RTS because it is sent by main PHY)
|
||||
m_events.emplace_back(WIFI_MAC_MGT_ACTION);
|
||||
m_events.emplace_back(WIFI_MAC_CTL_ACK,
|
||||
[=](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
|
||||
// check that transition delay is started after reception of Ack
|
||||
checkTransDelay(psdu, txVector, true, "DL ADDBA RESPONSE");
|
||||
});
|
||||
|
||||
// Downlink QoS data frame that triggered BA agreement establishment
|
||||
m_events.emplace_back(WIFI_MAC_CTL_TRIGGER);
|
||||
m_events.emplace_back(WIFI_MAC_CTL_CTS);
|
||||
m_events.emplace_back(WIFI_MAC_QOSDATA);
|
||||
m_events.emplace_back(WIFI_MAC_CTL_BACKRESP,
|
||||
[=](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
|
||||
// check that transition delay is started after reception of BlockAck
|
||||
checkTransDelay(psdu, txVector, true, "DL QoS Data");
|
||||
});
|
||||
|
||||
// Establishment of BA agreement for uplink direction
|
||||
|
||||
// ADDBA REQUEST sent by EMLSR client (no RTS because it is sent by main PHY)
|
||||
m_events.emplace_back(WIFI_MAC_MGT_ACTION);
|
||||
m_events.emplace_back(WIFI_MAC_CTL_ACK,
|
||||
[=](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
|
||||
// check that transition delay is started after reception of Ack
|
||||
checkTransDelay(psdu, txVector, false, "UL ADDBA REQUEST");
|
||||
});
|
||||
// ADDBA RESPONSE sent by AP MLD (protected by ICF)
|
||||
m_events.emplace_back(WIFI_MAC_CTL_TRIGGER);
|
||||
m_events.emplace_back(WIFI_MAC_CTL_CTS);
|
||||
m_events.emplace_back(WIFI_MAC_MGT_ACTION);
|
||||
m_events.emplace_back(WIFI_MAC_CTL_ACK,
|
||||
[=](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
|
||||
// check that transition delay is started after reception of Ack
|
||||
checkTransDelay(psdu, txVector, true, "UL ADDBA RESPONSE");
|
||||
});
|
||||
|
||||
// Uplink QoS data frame that triggered BA agreement establishment
|
||||
m_events.emplace_back(WIFI_MAC_QOSDATA);
|
||||
m_events.emplace_back(WIFI_MAC_CTL_BACKRESP,
|
||||
[=](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) {
|
||||
// check that transition delay is started after reception of BlockAck
|
||||
checkTransDelay(psdu, txVector, true, "UL QoS Data");
|
||||
});
|
||||
|
||||
m_eventIt = m_events.cbegin();
|
||||
|
||||
Simulator::Stop(m_duration);
|
||||
Simulator::Run();
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ((m_eventIt == m_events.cend()), true, "Not all events took place");
|
||||
|
||||
Simulator::Destroy();
|
||||
}
|
||||
|
||||
WifiEmlsrTestSuite::WifiEmlsrTestSuite()
|
||||
: TestSuite("wifi-emlsr", Type::UNIT)
|
||||
{
|
||||
@@ -5039,6 +5251,15 @@ WifiEmlsrTestSuite::WifiEmlsrTestSuite()
|
||||
|
||||
AddTestCase(new EmlsrCcaBusyTest(MHz_u{20}), TestCase::Duration::QUICK);
|
||||
AddTestCase(new EmlsrCcaBusyTest(MHz_u{80}), TestCase::Duration::QUICK);
|
||||
|
||||
for (const auto switchAuxPhy : {true, false})
|
||||
{
|
||||
for (const auto auxPhyTxCapable : {true, false})
|
||||
{
|
||||
AddTestCase(new SingleLinkEmlsrTest(switchAuxPhy, auxPhyTxCapable),
|
||||
TestCase::Duration::QUICK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static WifiEmlsrTestSuite g_wifiEmlsrTestSuite; ///< the test suite
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "ns3/wifi-ppdu.h"
|
||||
#include "ns3/wifi-psdu.h"
|
||||
|
||||
#include <array>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -29,6 +30,7 @@
|
||||
#include <vector>
|
||||
|
||||
using namespace ns3;
|
||||
using namespace std::string_literals;
|
||||
|
||||
// forward declaration
|
||||
namespace ns3
|
||||
@@ -196,9 +198,20 @@ class EmlsrOperationsTestBase : public TestCase
|
||||
uint8_t phyId; ///< ID of the transmitting PHY
|
||||
};
|
||||
|
||||
/// array of strings defining the channels for the MLD links
|
||||
const std::array<std::string, 3> m_channelsStr{"{2, 0, BAND_2_4GHZ, 0}"s,
|
||||
"{36, 0, BAND_5GHZ, 0}"s,
|
||||
"{1, 0, BAND_6GHZ, 0}"s};
|
||||
|
||||
/// array of frequency ranges for MLD links
|
||||
const std::array<FrequencyRange, 3> m_freqRanges{WIFI_SPECTRUM_2_4_GHZ,
|
||||
WIFI_SPECTRUM_5_GHZ,
|
||||
WIFI_SPECTRUM_6_GHZ};
|
||||
|
||||
uint8_t m_mainPhyId{0}; //!< ID of the main PHY
|
||||
std::set<uint8_t> m_linksToEnableEmlsrOn; /**< IDs of the links on which EMLSR mode has to
|
||||
be enabled */
|
||||
std::size_t m_nPhysPerEmlsrDevice{3}; //!< number of PHYs per EMLSR client
|
||||
std::size_t m_nEmlsrStations{1}; ///< number of stations to create that activate EMLSR
|
||||
std::size_t m_nNonEmlsrStations{0}; /**< number of stations to create that do not
|
||||
activate EMLSR */
|
||||
@@ -973,4 +986,70 @@ class EmlsrCcaBusyTest : public EmlsrOperationsTestBase
|
||||
uint8_t m_nextMainPhyLinkId; //!< the ID of the link the main PHY switches to
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup wifi-test
|
||||
* @ingroup tests
|
||||
*
|
||||
* @brief Test ML setup and data exchange between an AP MLD and a single link EMLSR client.
|
||||
*
|
||||
* A single link EMLSR client performs ML setup with an AP MLD having three links and then enables
|
||||
* EMLSR mode on the unique link. A Block Ack agreement is established (for both the downlink and
|
||||
* uplink directions) and QoS data frames (aggregated in an A-MPDU) are transmitted by both the
|
||||
* AP MLD and the EMLSR client.
|
||||
*
|
||||
* It is checked that:
|
||||
* - the expected sequence of frames is transmitted, including ICFs before downlink transmissions
|
||||
* - EMLSR mode is enabled on the single EMLSR link
|
||||
* - the address of the EMLSR client is seen as an MLD address
|
||||
* - the AP MLD starts the transition delay timer at the end of each TXOP
|
||||
*/
|
||||
class SingleLinkEmlsrTest : public EmlsrOperationsTestBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param switchAuxPhy whether aux PHYs switch link
|
||||
* @param auxPhyTxCapable whether aux PHYs are TX capable
|
||||
*/
|
||||
SingleLinkEmlsrTest(bool switchAuxPhy, bool auxPhyTxCapable);
|
||||
|
||||
protected:
|
||||
void DoSetup() override;
|
||||
void DoRun() override;
|
||||
|
||||
void Transmit(Ptr<WifiMac> mac,
|
||||
uint8_t phyId,
|
||||
WifiConstPsduMap psduMap,
|
||||
WifiTxVector txVector,
|
||||
double txPowerW) override;
|
||||
|
||||
/// Actions and checks to perform upon the transmission of each frame
|
||||
struct Events
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param type the frame MAC header type
|
||||
* @param f function to perform actions and checks
|
||||
*/
|
||||
Events(WifiMacType type,
|
||||
std::function<void(Ptr<const WifiPsdu>, const WifiTxVector&)>&& f = {})
|
||||
: hdrType(type),
|
||||
func(f)
|
||||
{
|
||||
}
|
||||
|
||||
WifiMacType hdrType; ///< MAC header type of frame being transmitted
|
||||
std::function<void(Ptr<const WifiPsdu>, const WifiTxVector&)>
|
||||
func; ///< function to perform actions and checks
|
||||
};
|
||||
|
||||
private:
|
||||
bool m_switchAuxPhy; //!< whether aux PHYs switch link
|
||||
bool m_auxPhyTxCapable; //!< whether aux PHYs are TX capable
|
||||
std::list<Events> m_events; //!< list of events for a test run
|
||||
std::list<Events>::const_iterator m_eventIt; //!< iterator over the list of events
|
||||
};
|
||||
|
||||
#endif /* WIFI_EMLSR_TEST_H */
|
||||
|
||||
Reference in New Issue
Block a user