wifi: Add unit test for data transmission between MLDs (no BA)

This commit is contained in:
Stefano Avallone
2022-09-14 17:44:09 +02:00
committed by Stefano Avallone
parent e312d69ab3
commit cfdbf4c2cf
2 changed files with 575 additions and 101 deletions

View File

@@ -31,6 +31,7 @@
class TwoLevelAggregationTest;
class AmpduAggregationTest;
class HeAggregationTest;
class MultiLinkOperationsTestBase;
namespace ns3
{
@@ -128,6 +129,8 @@ class StaWifiMac : public WifiMac
friend class ::AmpduAggregationTest;
/// Allow test cases to access private members
friend class ::HeAggregationTest;
/// Allow test cases to access private members
friend class ::MultiLinkOperationsTestBase;
/// type of the management frames used to get info about APs
using MgtFrameType =

View File

@@ -27,6 +27,7 @@
#include "ns3/mobility-helper.h"
#include "ns3/multi-link-element.h"
#include "ns3/multi-model-spectrum-channel.h"
#include "ns3/node-list.h"
#include "ns3/packet-socket-client.h"
#include "ns3/packet-socket-helper.h"
#include "ns3/packet-socket-server.h"
@@ -35,6 +36,7 @@
#include "ns3/qos-utils.h"
#include "ns3/rng-seed-manager.h"
#include "ns3/spectrum-wifi-helper.h"
#include "ns3/spectrum-wifi-phy.h"
#include "ns3/sta-wifi-mac.h"
#include "ns3/string.h"
#include "ns3/test.h"
@@ -45,6 +47,8 @@
#include "ns3/wifi-protection.h"
#include "ns3/wifi-psdu.h"
#include <algorithm>
#include <array>
#include <iomanip>
#include <sstream>
#include <vector>
@@ -206,9 +210,9 @@ class MultiLinkOperationsTestBase : public TestCase
*/
MultiLinkOperationsTestBase(const std::string& name,
uint8_t nStations,
std::initializer_list<std::string> staChannels,
std::initializer_list<std::string> apChannels,
std::initializer_list<uint8_t> fixedPhyBands = {});
std::vector<std::string> staChannels,
std::vector<std::string> apChannels,
std::vector<uint8_t> fixedPhyBands = {});
~MultiLinkOperationsTestBase() override = default;
protected:
@@ -235,6 +239,26 @@ class MultiLinkOperationsTestBase : public TestCase
void DoSetup() override;
/// PHY band-indexed map of spectrum channels
using ChannelMap = std::map<WifiPhyBand, Ptr<MultiModelSpectrumChannel>>;
/**
* Notify a PHY state change for the given link of the given station.
*
* \param staId the ID of the given station
* \param linkId the ID of the given link
* \param channelMap the PHY-band indexed map of spectrum channels
* \param now the time of the transition to the given PHY state
* \param duration the time spent in the given PHY state
* \param state the PHY state
*/
void NotifyPhyStateChange(uint8_t staId,
uint8_t linkId,
const ChannelMap& channelMap,
Time now,
Time duration,
WifiPhyState state);
/**
* Check that the Address 1 and Address 2 fields of the given PSDU contain device MAC addresses.
*
@@ -259,6 +283,7 @@ class MultiLinkOperationsTestBase : public TestCase
Ptr<ApWifiMac> m_apMac; ///< AP wifi MAC
std::vector<Ptr<StaWifiMac>> m_staMacs; ///< STA wifi MACs
uint8_t m_nStations; ///< number of stations to create
uint16_t m_lastAid; ///< AID of last associated station
private:
/**
@@ -272,21 +297,37 @@ class MultiLinkOperationsTestBase : public TestCase
*/
void SetChannels(SpectrumWifiPhyHelper& helper,
const std::vector<std::string>& channels,
const std::map<WifiPhyBand, Ptr<MultiModelSpectrumChannel>>& channelMap);
const ChannelMap& channelMap);
/**
* Set the SSID on the next station that needs to start the association procedure.
* This method is connected to the ApWifiMac's AssociatedSta trace source.
* Start generating traffic (if needed) when all stations are associated.
*
* \param aid the AID assigned to the previous associated STA
*/
void SetSsid(uint16_t aid, Mac48Address /* addr */);
/**
* Start the generation of traffic (needs to be overridden)
*/
virtual void StartTraffic()
{
}
};
MultiLinkOperationsTestBase::MultiLinkOperationsTestBase(
const std::string& name,
uint8_t nStations,
std::initializer_list<std::string> staChannels,
std::initializer_list<std::string> apChannels,
std::initializer_list<uint8_t> fixedPhyBands)
MultiLinkOperationsTestBase::MultiLinkOperationsTestBase(const std::string& name,
uint8_t nStations,
std::vector<std::string> staChannels,
std::vector<std::string> apChannels,
std::vector<uint8_t> fixedPhyBands)
: TestCase(name),
m_staChannels(staChannels),
m_apChannels(apChannels),
m_fixedPhyBands(fixedPhyBands),
m_staMacs(nStations),
m_nStations(nStations)
m_nStations(nStations),
m_lastAid(0)
{
}
@@ -343,6 +384,10 @@ MultiLinkOperationsTestBase::CheckAddresses(Ptr<const WifiPsdu> psdu, bool downl
break;
}
}
if (found)
{
break;
}
}
NS_TEST_EXPECT_MSG_EQ(found,
true,
@@ -366,7 +411,8 @@ MultiLinkOperationsTestBase::Transmit(uint8_t linkId,
<< psduMap.begin()->second->GetNMpdus() << " duration/ID "
<< psduMap.begin()->second->GetHeader(0).GetDuration()
<< " RA = " << psduMap.begin()->second->GetAddr1()
<< " TA = " << psduMap.begin()->second->GetAddr2();
<< " TA = " << psduMap.begin()->second->GetAddr2()
<< " ADDR3 = " << psduMap.begin()->second->GetHeader(0).GetAddr3();
if (psduMap.begin()->second->GetHeader(0).IsQosData())
{
ss << " seqNo = {";
@@ -381,10 +427,9 @@ MultiLinkOperationsTestBase::Transmit(uint8_t linkId,
}
void
MultiLinkOperationsTestBase::SetChannels(
SpectrumWifiPhyHelper& helper,
const std::vector<std::string>& channels,
const std::map<WifiPhyBand, Ptr<MultiModelSpectrumChannel>>& channelMap)
MultiLinkOperationsTestBase::SetChannels(SpectrumWifiPhyHelper& helper,
const std::vector<std::string>& channels,
const ChannelMap& channelMap)
{
helper = SpectrumWifiPhyHelper(channels.size());
helper.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
@@ -393,7 +438,9 @@ MultiLinkOperationsTestBase::SetChannels(
for (const auto& str : channels)
{
helper.Set(linkId, "ChannelSettings", StringValue(str));
helper.SetChannel(linkId, channelMap.at(GetPhyBandFromChannelStr(str)));
// helper.SetChannel (linkId, channelMap.at (GetPhyBandFromChannelStr (str)));
// TODO replace this line with the one above to use per-band spectrum channels
helper.SetChannel(linkId, channelMap.begin()->second);
linkId++;
}
@@ -438,10 +485,9 @@ MultiLinkOperationsTestBase::DoSetup()
"DataMode",
StringValue("EhtMcs0"));
std::map<WifiPhyBand, Ptr<MultiModelSpectrumChannel>> channelMap = {
{WIFI_PHY_BAND_2_4GHZ, CreateObject<MultiModelSpectrumChannel>()},
{WIFI_PHY_BAND_5GHZ, CreateObject<MultiModelSpectrumChannel>()},
{WIFI_PHY_BAND_6GHZ, CreateObject<MultiModelSpectrumChannel>()}};
ChannelMap channelMap{{WIFI_PHY_BAND_2_4GHZ, CreateObject<MultiModelSpectrumChannel>()},
{WIFI_PHY_BAND_5GHZ, CreateObject<MultiModelSpectrumChannel>()},
{WIFI_PHY_BAND_6GHZ, CreateObject<MultiModelSpectrumChannel>()}};
SpectrumWifiPhyHelper staPhyHelper;
SpectrumWifiPhyHelper apPhyHelper;
@@ -454,12 +500,17 @@ MultiLinkOperationsTestBase::DoSetup()
}
WifiMacHelper mac;
Ssid ssid = Ssid("ns-3-ssid");
mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssid), "ActiveProbing", BooleanValue(false));
mac.SetType("ns3::StaWifiMac", // default SSID
"ActiveProbing",
BooleanValue(false));
NetDeviceContainer staDevices = wifi.Install(staPhyHelper, mac, wifiStaNodes);
mac.SetType("ns3::ApWifiMac", "Ssid", SsidValue(ssid), "BeaconGeneration", BooleanValue(true));
mac.SetType("ns3::ApWifiMac",
"Ssid",
SsidValue(Ssid("ns-3-ssid")),
"BeaconGeneration",
BooleanValue(true));
NetDeviceContainer apDevices = wifi.Install(apPhyHelper, mac, wifiApNode);
@@ -508,13 +559,91 @@ MultiLinkOperationsTestBase::DoSetup()
MakeCallback(&MultiLinkOperationsTestBase::Transmit, this).Bind(linkId));
}
}
// notify PHY state changes on the stations
for (uint8_t i = 0; i < m_nStations; i++)
{
auto dev = StaticCast<WifiNetDevice>(staDevices.Get(i));
for (uint8_t linkId = 0; linkId < dev->GetNPhys(); linkId++)
{
dev->GetPhy(linkId)->GetState()->TraceConnectWithoutContext(
"State",
MakeCallback(&MultiLinkOperationsTestBase::NotifyPhyStateChange, this)
.Bind(i, linkId, channelMap));
}
}
// schedule ML setup for one station at a time
m_apMac->TraceConnectWithoutContext("AssociatedSta",
MakeCallback(&MultiLinkOperationsTestBase::SetSsid, this));
Simulator::Schedule(Seconds(0), [&]() { m_staMacs[0]->SetSsid(Ssid("ns-3-ssid")); });
}
void
MultiLinkOperationsTestBase::NotifyPhyStateChange(uint8_t staId,
uint8_t linkId,
const ChannelMap& channelMap,
Time now,
Time duration,
WifiPhyState state)
{
if (state != WifiPhyState::SWITCHING)
{
return;
}
// this PHY is switching channel. Connect it to the proper spectrum channel
auto staPhy = DynamicCast<SpectrumWifiPhy>(m_staMacs[staId]->GetWifiPhy(linkId));
NS_ASSERT(staPhy);
// TODO causes an assert failure
// staPhy->SetChannel (channelMap.at (staPhy->GetPhyBand ()));
}
void
MultiLinkOperationsTestBase::SetSsid(uint16_t aid, Mac48Address /* addr */)
{
// connect each PHY of the STA that completed ML setup to the correct spectrum channel
// auto currId = aid - 1;
// for (uint8_t linkId = 0; linkId < m_staMacs[currId]->GetNLinks (); linkId++)
// {
// if (const auto& apLinkId = m_staMacs[currId]->GetLink (linkId).apLinkId)
// {
// auto staPhy = DynamicCast<SpectrumWifiPhy> (m_staMacs[currId]->GetWifiPhy (linkId));
// NS_ASSERT (staPhy);
// auto apChannel = DynamicCast<SpectrumChannel> (m_apMac->GetWifiPhy
// (*apLinkId)->GetChannel ()); NS_ASSERT (apChannel); staPhy->SetChannel (apChannel);
// }
// }
if (m_lastAid == aid)
{
// another STA of this non-AP MLD has already fired this callback
return;
}
m_lastAid = aid;
// make the next STA to start ML discovery & setup
if (aid < m_nStations)
{
m_staMacs[aid]->SetSsid(Ssid("ns-3-ssid"));
return;
}
// wait some time (5ms) to allow the completion of association before generating traffic
Simulator::Schedule(MilliSeconds(5), &MultiLinkOperationsTestBase::StartTraffic, this);
}
/**
* \ingroup wifi-test
* \ingroup tests
*
* Multi-Link Discovery & Setup test.
* \brief Multi-Link Discovery & Setup test.
*
* This test sets up an AP MLD and a non-AP MLD having a variable number of links.
* The RF channels to set each link to are provided as input parameters through the test
* case constructor, along with the identifiers (starting at 0) of the links that cannot
* switch PHY band (if any). The links that are expected to be setup are also provided as input
* parameters. This test verifies that the management frames exchanged during ML discovery
* and ML setup contain the expected values and that the two MLDs setup the expected links.
*/
class MultiLinkSetupTest : public MultiLinkOperationsTestBase
{
@@ -527,10 +656,10 @@ class MultiLinkSetupTest : public MultiLinkOperationsTestBase
* \param setupLinks a list of links (STA link ID, AP link ID) that are expected to be setup
* \param fixedPhyBands list of IDs of STA links that cannot switch PHY band
*/
MultiLinkSetupTest(std::initializer_list<std::string> staChannels,
std::initializer_list<std::string> apChannels,
std::initializer_list<std::pair<uint8_t, uint8_t>> setupLinks,
std::initializer_list<uint8_t> fixedPhyBands = {});
MultiLinkSetupTest(std::vector<std::string> staChannels,
std::vector<std::string> apChannels,
std::vector<std::pair<uint8_t, uint8_t>> setupLinks,
std::vector<uint8_t> fixedPhyBands = {});
~MultiLinkSetupTest() override = default;
protected:
@@ -575,11 +704,10 @@ class MultiLinkSetupTest : public MultiLinkOperationsTestBase
const std::vector<std::pair<uint8_t, uint8_t>> m_setupLinks;
};
MultiLinkSetupTest::MultiLinkSetupTest(
std::initializer_list<std::string> staChannels,
std::initializer_list<std::string> apChannels,
std::initializer_list<std::pair<uint8_t, uint8_t>> setupLinks,
std::initializer_list<uint8_t> fixedPhyBands)
MultiLinkSetupTest::MultiLinkSetupTest(std::vector<std::string> staChannels,
std::vector<std::string> apChannels,
std::vector<std::pair<uint8_t, uint8_t>> setupLinks,
std::vector<uint8_t> fixedPhyBands)
: MultiLinkOperationsTestBase("Check correctness of Multi-Link Setup",
1,
staChannels,
@@ -907,14 +1035,15 @@ MultiLinkSetupTest::CheckDisabledLinks()
if (GetPhyBandFromChannelStr(m_staChannels.at(it->first)) !=
GetPhyBandFromChannelStr(m_apChannels.at(it->second)))
{
// TODO Uncomment this check if distinct spectrum channels are used (one per PHY band)
// and spectrum channels are not reassigned based on the final operating PHY band
// STA had to switch PHY band to match AP's operating band. Given that we
// are using three distinct spectrum channels (one per band), a STA will
// not receive Beacon frames after switching PHY band. After a number of
// missed Beacon frames, the link is disabled
NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->GetWifiPhy(linkId)->GetState()->IsStateOff(),
true,
"Expecting link " << +linkId
<< " to be disabled due to switching PHY band");
// NS_TEST_EXPECT_MSG_EQ (m_staMacs[0]->GetWifiPhy (linkId)->GetState ()->IsStateOff (),
// true, "Expecting link " << +linkId << " to be disabled due to switching PHY band");
continue;
}
@@ -925,6 +1054,329 @@ MultiLinkSetupTest::CheckDisabledLinks()
}
}
/**
* Tested traffic patterns.
*/
enum class TrafficPattern : uint8_t
{
STA_TO_STA = 0,
STA_TO_AP,
AP_TO_STA,
AP_TO_BCAST,
STA_TO_BCAST
};
/**
* \ingroup wifi-test
* \ingroup tests
*
* \brief Test data transmission between two MLDs when Block Ack agreement is not established.
*
* This test sets up an AP MLD and two non-AP MLDs having a variable number of links.
* The RF channels to set each link to are provided as input parameters through the test
* case constructor, along with the identifiers (starting at 0) of the links that cannot
* switch PHY band (if any). This test aims at veryfing the successful transmission of both
* unicast QoS data frames (from one station to another, from one station to the AP, from
* the AP to the station) and broadcast QoS data frames (from the AP or from one station).
* Two QoS data frames are generated for this purpose. The second one is also corrupted once
* (by using a post reception error model) to test its successful re-transmission.
* Establishment of a BA agreement is prevented by corrupting all ADDBA_REQUEST frames
* with a post reception error model.
*/
class MultiLinkTxNoBaTest : public MultiLinkOperationsTestBase
{
public:
/**
* Constructor
*
* \param trafficPattern the pattern of traffic to generate
* \param staChannels the strings specifying the operating channels for the STA
* \param apChannels the strings specifying the operating channels for the AP
* \param fixedPhyBands list of IDs of STA links that cannot switch PHY band
*/
MultiLinkTxNoBaTest(TrafficPattern trafficPattern,
std::vector<std::string> staChannels,
std::vector<std::string> apChannels,
std::vector<uint8_t> fixedPhyBands = {});
~MultiLinkTxNoBaTest() override = default;
protected:
/**
* Function to trace packets received by the server application
* \param nodeId the ID of the node that received the packet
* \param p the packet
* \param addr the address
*/
void L7Receive(uint8_t nodeId, Ptr<const Packet> p, const Address& addr);
void Transmit(uint8_t linkId,
std::string context,
WifiConstPsduMap psduMap,
WifiTxVector txVector,
double txPowerW) override;
void DoSetup() override;
void DoRun() override;
private:
void StartTraffic() override;
Ptr<ListErrorModel> m_errorModel; ///< error rate model to corrupt packets
std::list<uint64_t> m_uidList; ///< list of UIDs of packets to corrupt
bool m_dataCorrupted{false}; ///< whether second data frame has been already corrupted
TrafficPattern m_trafficPattern; ///< the pattern of traffic to generate
std::array<std::size_t, 3> m_rxPkts{}; ///< number of packets received at application layer
///< by each node (AP, STA 0, STA 1)
};
MultiLinkTxNoBaTest::MultiLinkTxNoBaTest(TrafficPattern trafficPattern,
std::vector<std::string> staChannels,
std::vector<std::string> apChannels,
std::vector<uint8_t> fixedPhyBands)
: MultiLinkOperationsTestBase("Check data transmission between MLDs without BA agreement",
2,
staChannels,
apChannels,
fixedPhyBands),
m_errorModel(CreateObject<ListErrorModel>()),
m_trafficPattern(trafficPattern)
{
}
void
MultiLinkTxNoBaTest::Transmit(uint8_t linkId,
std::string context,
WifiConstPsduMap psduMap,
WifiTxVector txVector,
double txPowerW)
{
auto psdu = psduMap.begin()->second;
auto uid = psdu->GetPacket()->GetUid();
switch (psdu->GetHeader(0).GetType())
{
case WIFI_MAC_MGT_ACTION:
// CheckAddresses (psdu, true); TODO uncomment when ADDBA_REQUEST contains proper addresses
// corrupt all management action frames (ADDBA Request frames) to prevent
// the establishment of a BA agreement
m_uidList.push_front(uid);
m_errorModel->SetList(m_uidList);
NS_LOG_INFO("CORRUPTED");
break;
case WIFI_MAC_QOSDATA: {
Address dlAddr3; // Source Address (SA)
switch (m_trafficPattern)
{
case TrafficPattern::STA_TO_STA:
case TrafficPattern::STA_TO_BCAST:
dlAddr3 = m_staMacs[0]->GetDevice()->GetAddress();
break;
case TrafficPattern::STA_TO_AP:
dlAddr3 = Mac48Address("00:00:00:00:00:00"); // invalid address, no DL frames
break;
case TrafficPattern::AP_TO_STA:
case TrafficPattern::AP_TO_BCAST:
dlAddr3 = m_apMac->GetAddress();
break;
}
// a QoS data frame is a DL frame if Addr3 is the SA
CheckAddresses(psdu, psdu->GetHeader(0).GetAddr3() == dlAddr3);
}
// corrupt the second QoS data frame (only once)
if (psdu->GetHeader(0).GetSequenceNumber() != 1 ||
m_trafficPattern == TrafficPattern::AP_TO_BCAST ||
m_trafficPattern == TrafficPattern::STA_TO_BCAST)
{
break;
}
if (!m_dataCorrupted)
{
m_uidList.push_front(uid);
m_dataCorrupted = true;
NS_LOG_INFO("CORRUPTED");
m_errorModel->SetList(m_uidList);
break;
}
// do not corrupt the second data frame anymore
if (auto it = std::find(m_uidList.cbegin(), m_uidList.cend(), uid); it != m_uidList.cend())
{
m_uidList.erase(it);
}
m_errorModel->SetList(m_uidList);
break;
default:;
}
MultiLinkOperationsTestBase::Transmit(linkId, context, psduMap, txVector, txPowerW);
}
void
MultiLinkTxNoBaTest::L7Receive(uint8_t nodeId, Ptr<const Packet> p, const Address& addr)
{
NS_LOG_INFO("Packet received by NODE " << +nodeId << "\n");
m_rxPkts[nodeId]++;
}
void
MultiLinkTxNoBaTest::DoSetup()
{
MultiLinkOperationsTestBase::DoSetup();
// install post reception error model on receivers
switch (m_trafficPattern)
{
case TrafficPattern::STA_TO_STA:
for (std::size_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
{
m_apMac->GetWifiPhy(linkId)->SetPostReceptionErrorModel(m_errorModel);
}
for (std::size_t linkId = 0; linkId < m_staMacs[1]->GetNLinks(); linkId++)
{
m_staMacs[1]->GetWifiPhy(linkId)->SetPostReceptionErrorModel(m_errorModel);
}
break;
case TrafficPattern::STA_TO_AP:
for (std::size_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
{
m_apMac->GetWifiPhy(linkId)->SetPostReceptionErrorModel(m_errorModel);
}
break;
case TrafficPattern::AP_TO_STA:
for (std::size_t linkId = 0; linkId < m_staMacs[1]->GetNLinks(); linkId++)
{
m_staMacs[1]->GetWifiPhy(linkId)->SetPostReceptionErrorModel(m_errorModel);
}
break;
case TrafficPattern::AP_TO_BCAST:
// No frame to corrupt (broadcast frames do not trigger establishment of BA agreement)
break;
case TrafficPattern::STA_TO_BCAST:
// uplink frames are not broadcast
for (std::size_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
{
m_apMac->GetWifiPhy(linkId)->SetPostReceptionErrorModel(m_errorModel);
}
break;
}
}
void
MultiLinkTxNoBaTest::StartTraffic()
{
const Time duration = Seconds(1);
Ptr<WifiMac> sender;
Address destAddr;
switch (m_trafficPattern)
{
case TrafficPattern::STA_TO_STA:
sender = m_staMacs[0];
destAddr = m_staMacs[1]->GetDevice()->GetAddress();
break;
case TrafficPattern::STA_TO_AP:
sender = m_staMacs[0];
destAddr = m_apMac->GetDevice()->GetAddress();
break;
case TrafficPattern::AP_TO_STA:
sender = m_apMac;
destAddr = m_staMacs[1]->GetDevice()->GetAddress();
break;
case TrafficPattern::AP_TO_BCAST:
sender = m_apMac;
destAddr = Mac48Address::GetBroadcast();
break;
case TrafficPattern::STA_TO_BCAST:
sender = m_staMacs[0];
destAddr = Mac48Address::GetBroadcast();
break;
}
PacketSocketHelper packetSocket;
packetSocket.Install(m_apMac->GetDevice()->GetNode());
packetSocket.Install(m_staMacs[0]->GetDevice()->GetNode());
packetSocket.Install(m_staMacs[1]->GetDevice()->GetNode());
PacketSocketAddress socket;
socket.SetSingleDevice(sender->GetDevice()->GetIfIndex());
socket.SetPhysicalAddress(destAddr);
socket.SetProtocol(1);
// install client application
Ptr<PacketSocketClient> client = CreateObject<PacketSocketClient>();
client->SetAttribute("PacketSize", UintegerValue(1400));
client->SetAttribute("MaxPackets", UintegerValue(2));
client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
client->SetRemote(socket);
sender->GetDevice()->GetNode()->AddApplication(client);
client->SetStartTime(Seconds(0)); // now
client->SetStopTime(duration);
// install a server on all nodes
for (auto nodeIt = NodeList::Begin(); nodeIt != NodeList::End(); nodeIt++)
{
Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer>();
server->SetLocal(socket);
(*nodeIt)->AddApplication(server);
server->SetStartTime(Seconds(0)); // now
server->SetStopTime(duration);
}
for (std::size_t nodeId = 0; nodeId < NodeList::GetNNodes(); nodeId++)
{
Config::ConnectWithoutContext(
"/NodeList/" + std::to_string(nodeId) +
"/ApplicationList/*/$ns3::PacketSocketServer/Rx",
MakeCallback(&MultiLinkTxNoBaTest::L7Receive, this).Bind(nodeId));
}
Simulator::Stop(duration);
}
void
MultiLinkTxNoBaTest::DoRun()
{
Simulator::Run();
// Expected number of packets received by each node (AP, STA 0, STA 1) at application layer
std::array<std::size_t, 3> expectedRxPkts{};
switch (m_trafficPattern)
{
case TrafficPattern::STA_TO_STA:
case TrafficPattern::AP_TO_STA:
// only STA 1 receives the 2 packets that have been transmitted
expectedRxPkts[2] = 2;
break;
case TrafficPattern::STA_TO_AP:
// only the AP receives the 2 packets that have been transmitted
expectedRxPkts[0] = 2;
break;
case TrafficPattern::AP_TO_BCAST:
// the AP replicates the broadcast frames on all the links, hence each station
// receives the 2 packets N times, where N is the number of setup link
expectedRxPkts[1] = 2 * m_staMacs[0]->GetSetupLinkIds().size();
expectedRxPkts[2] = 2 * m_staMacs[1]->GetSetupLinkIds().size();
break;
case TrafficPattern::STA_TO_BCAST:
// the AP receives the two packets and then replicates them on all the links,
// hence STA 1 receives 2 packets N times, where N is the number of setup link
expectedRxPkts[0] = 2;
expectedRxPkts[2] = 2 * m_staMacs[1]->GetSetupLinkIds().size();
break;
}
NS_TEST_EXPECT_MSG_EQ(+m_rxPkts[0],
+expectedRxPkts[0],
"Unexpected number of packets received by the AP");
NS_TEST_EXPECT_MSG_EQ(+m_rxPkts[1],
+expectedRxPkts[1],
"Unexpected number of packets received by STA 0");
NS_TEST_EXPECT_MSG_EQ(+m_rxPkts[2],
+expectedRxPkts[2],
"Unexpected number of packets received by STA 1");
Simulator::Destroy();
}
/**
* \ingroup wifi-test
* \ingroup tests
@@ -940,71 +1392,90 @@ class WifiMultiLinkOperationsTestSuite : public TestSuite
WifiMultiLinkOperationsTestSuite::WifiMultiLinkOperationsTestSuite()
: TestSuite("wifi-mlo", UNIT)
{
using ParamsTuple = std::tuple<std::vector<std::string>,
std::vector<std::string>,
std::vector<std::pair<uint8_t, uint8_t>>,
std::vector<uint8_t>>;
AddTestCase(new GetRnrLinkInfoTest(), TestCase::QUICK);
// matching channels: setup all links
AddTestCase(new MultiLinkSetupTest(
{"{36, 0, BAND_5GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
{{0, 0}, {1, 1}, {2, 2}}),
TestCase::QUICK);
// non-matching channels, matching PHY bands: setup all links
AddTestCase(new MultiLinkSetupTest(
{"{108, 0, BAND_5GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{120, 0, BAND_5GHZ, 0}", "{5, 0, BAND_6GHZ, 0}"},
{{1, 0}, {0, 1}, {2, 2}}),
TestCase::QUICK);
// non-AP MLD switches band on some links to setup 3 links
AddTestCase(new MultiLinkSetupTest(
{"{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{36, 0, BAND_5GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{9, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
{{2, 0}, {0, 1}, {1, 2}}),
TestCase::QUICK);
// the first link of the non-AP MLD cannot change PHY band and no AP is operating on
// that band, hence only 2 links are setup
AddTestCase(new MultiLinkSetupTest(
{"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{8, 20, BAND_2_4GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
{{1, 0}, {2, 1}},
{0}),
TestCase::QUICK);
// the first link of the non-AP MLD cannot change PHY band and no AP is operating on
// that band; the second link of the non-AP MLD cannot change PHY band and there is
// an AP operating on the same channel; hence 2 links are setup
AddTestCase(new MultiLinkSetupTest(
{"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{8, 20, BAND_2_4GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
{{1, 0}, {2, 1}},
{0, 1}),
TestCase::QUICK);
// the first link of the non-AP MLD cannot change PHY band and no AP is operating on
// that band; the second link of the non-AP MLD cannot change PHY band and there is
// an AP operating on the same channel; the third link of the non-AP MLD cannot
// change PHY band and there is an AP operating on the same band (different channel);
// hence 2 links are setup by switching channel (not band) on the third link
AddTestCase(new MultiLinkSetupTest(
{"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{60, 0, BAND_5GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
{{1, 0}, {2, 2}},
{0, 1, 2}),
TestCase::QUICK);
// non-AP MLD has only two STAs and setups two links
AddTestCase(new MultiLinkSetupTest(
{"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
{{0, 1}, {1, 0}}),
TestCase::QUICK);
// single link non-AP STA associates with an AP affiliated with an AP MLD
AddTestCase(new MultiLinkSetupTest(
{"{120, 0, BAND_5GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
{{0, 2}}),
TestCase::QUICK);
// a STA affiliated with a non-AP MLD associates with a single link AP
AddTestCase(new MultiLinkSetupTest(
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
{"{120, 0, BAND_5GHZ, 0}"},
{{2, 0}}),
for (const auto& [staChannels, apChannels, setupLinks, fixedPhyBands] :
{// matching channels: setup all links
ParamsTuple({"{36, 0, BAND_5GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
{{0, 0}, {1, 1}, {2, 2}},
{}),
// non-matching channels, matching PHY bands: setup all links
ParamsTuple({"{108, 0, BAND_5GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{120, 0, BAND_5GHZ, 0}", "{5, 0, BAND_6GHZ, 0}"},
{{1, 0}, {0, 1}, {2, 2}},
{}),
// non-AP MLD switches band on some links to setup 3 links
ParamsTuple({"{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{36, 0, BAND_5GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{9, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
{{2, 0}, {0, 1}, {1, 2}},
{}),
// the first link of the non-AP MLD cannot change PHY band and no AP is operating on
// that band, hence only 2 links are setup
ParamsTuple(
{"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{8, 20, BAND_2_4GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
{{1, 0}, {2, 1}},
{0}),
// the first link of the non-AP MLD cannot change PHY band and no AP is operating on
// that band; the second link of the non-AP MLD cannot change PHY band and there is
// an AP operating on the same channel; hence 2 links are setup
ParamsTuple(
{"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{8, 20, BAND_2_4GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
{{1, 0}, {2, 1}},
{0, 1}),
// the first link of the non-AP MLD cannot change PHY band and no AP is operating on
// that band; the second link of the non-AP MLD cannot change PHY band and there is
// an AP operating on the same channel; the third link of the non-AP MLD cannot
// change PHY band and there is an AP operating on the same band (different channel);
// hence 2 links are setup by switching channel (not band) on the third link
ParamsTuple({"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{60, 0, BAND_5GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
{{1, 0}, {2, 2}},
{0, 1, 2}),
// the first link of the non-AP MLD cannot change PHY band and no AP is operating on
// that band; the second link of the non-AP MLD cannot change PHY band and there is
// an AP operating on the same channel; hence one link only is setup
ParamsTuple({"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
{{1, 0}},
{0, 1}),
// non-AP MLD has only two STAs and setups two links
ParamsTuple({"{2, 0, BAND_2_4GHZ, 0}", "{36, 0, BAND_5GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
{{0, 1}, {1, 0}},
{}),
// single link non-AP STA associates with an AP affiliated with an AP MLD
ParamsTuple({"{120, 0, BAND_5GHZ, 0}"},
{"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
{{0, 2}},
{}),
// a STA affiliated with a non-AP MLD associates with a single link AP
ParamsTuple({"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
{"{120, 0, BAND_5GHZ, 0}"},
{{2, 0}},
{})})
{
AddTestCase(new MultiLinkSetupTest(staChannels, apChannels, setupLinks, fixedPhyBands),
TestCase::QUICK);
for (const auto& trafficPattern : {TrafficPattern::STA_TO_STA,
TrafficPattern::STA_TO_AP,
TrafficPattern::AP_TO_STA,
TrafficPattern::AP_TO_BCAST,
TrafficPattern::STA_TO_BCAST})
{
AddTestCase(
new MultiLinkTxNoBaTest(trafficPattern, staChannels, apChannels, fixedPhyBands),
TestCase::QUICK);
}
}
}
static WifiMultiLinkOperationsTestSuite g_wifiMultiLinkOperationsTestSuite; ///< the test suite