wifi: Split MLO test into header and module

This commit is contained in:
Stefano Avallone
2024-06-18 11:17:19 +02:00
parent 805deb16f1
commit d32a8a576f
3 changed files with 773 additions and 741 deletions

View File

@@ -337,6 +337,7 @@ set(header_files
model/yans-wifi-channel.h
model/yans-wifi-phy.h
model/wifi-spectrum-value-helper.h
test/wifi-mlo-test.h
)
build_lib(

View File

@@ -6,7 +6,8 @@
* Author: Stefano Avallone <stavallo@unina.it>
*/
#include "ns3/ap-wifi-mac.h"
#include "wifi-mlo-test.h"
#include "ns3/config.h"
#include "ns3/eht-configuration.h"
#include "ns3/ht-frame-exchange-manager.h"
@@ -15,21 +16,14 @@
#include "ns3/mgt-headers.h"
#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"
#include "ns3/packet.h"
#include "ns3/pointer.h"
#include "ns3/qos-utils.h"
#include "ns3/rng-seed-manager.h"
#include "ns3/rr-multi-user-scheduler.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"
#include "ns3/vht-configuration.h"
#include "ns3/wifi-acknowledgment.h"
#include "ns3/wifi-assoc-manager.h"
@@ -37,41 +31,17 @@
#include "ns3/wifi-mac-queue.h"
#include "ns3/wifi-net-device.h"
#include "ns3/wifi-protection.h"
#include "ns3/wifi-psdu.h"
#include <algorithm>
#include <array>
#include <iomanip>
#include <optional>
#include <sstream>
#include <tuple>
#include <vector>
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("WifiMloTest");
/**
* \ingroup wifi-test
* \ingroup tests
*
* \brief Test the implementation of WifiAssocManager::GetNextAffiliatedAp(), which
* searches a given RNR element for APs affiliated to the same AP MLD as the
* reporting AP that sent the frame containing the element.
*/
class GetRnrLinkInfoTest : public TestCase
{
public:
/**
* Constructor
*/
GetRnrLinkInfoTest();
~GetRnrLinkInfoTest() override = default;
private:
void DoRun() override;
};
GetRnrLinkInfoTest::GetRnrLinkInfoTest()
: TestCase("Check the implementation of WifiAssocManager::GetNextAffiliatedAp()")
{
@@ -180,64 +150,6 @@ GetRnrLinkInfoTest::DoRun()
"Unexpected tbtt ID of the second reported AP");
}
/**
* \ingroup wifi-test
* \ingroup tests
*
* Test the WifiMac::SwapLinks() method.
*/
class MldSwapLinksTest : public TestCase
{
/**
* Test WifiMac subclass used to access the SwapLinks method.
*/
class TestWifiMac : public WifiMac
{
public:
~TestWifiMac() override = default;
using WifiMac::GetLinks;
using WifiMac::SwapLinks;
bool CanForwardPacketsTo(Mac48Address to) const override
{
return true;
}
private:
void DoCompleteConfig() override
{
}
void Enqueue(Ptr<WifiMpdu> mpdu, Mac48Address to, Mac48Address from) override
{
}
};
public:
MldSwapLinksTest();
~MldSwapLinksTest() override = default;
protected:
void DoRun() override;
private:
/**
* Run a single test case.
*
* \param text string identifying the test case
* \param nLinks the number of links of the MLD
* \param links a set of pairs (from, to) each mapping a current link ID to the
* link ID it has to become (i.e., link 'from' becomes link 'to')
* \param expected maps each link ID to the id of the PHY that is expected
* to operate on that link after the swap
*/
void RunOne(std::string text,
std::size_t nLinks,
const std::map<uint8_t, uint8_t>& links,
const std::map<uint8_t, uint8_t>& expected);
};
MldSwapLinksTest::MldSwapLinksTest()
: TestCase("Test the WifiMac::SwapLinks() method")
{
@@ -300,40 +212,6 @@ MldSwapLinksTest::DoRun()
RunOne("Move all links to a new set of IDs", 2, {{0, 2}, {1, 3}}, {{2, 0}, {3, 1}});
}
/**
* \ingroup wifi-test
* \ingroup tests
*
* Test that the AIDs that an AP MLD assigns to SLDs and MLDs are all unique.
*/
class AidAssignmentTest : public TestCase
{
public:
/**
* Constructor.
*
* \param linkIds A vector specifying the set of link IDs each STA will setup
*/
AidAssignmentTest(const std::vector<std::set<uint8_t>>& linkIds);
private:
void DoSetup() override;
void DoRun() override;
/**
* Set the SSID on the next station that needs to start the association procedure.
* This method is triggered every time a STA completes its association.
*
* \param staMac the MAC of the STA that completed association
*/
void SetSsid(Ptr<StaWifiMac> staMac, Mac48Address /* apAddr */);
const std::vector<std::string> m_linkChannels; //!< channels for all AP links
const std::vector<std::set<uint8_t>> m_linkIds; //!< link IDs for all non-AP STAs/MLDs
NetDeviceContainer m_staDevices; //!< non-AP STAs/MLDs devices
uint16_t m_expectedAid; //!< expected AID for current non-AP STA/MLD
};
AidAssignmentTest::AidAssignmentTest(const std::vector<std::set<uint8_t>>& linkIds)
: TestCase("Test the assignment of AIDs"),
m_linkChannels({"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}"}),
@@ -484,170 +362,6 @@ AidAssignmentTest::DoRun()
Simulator::Destroy();
}
/**
* \ingroup wifi-test
* \ingroup tests
*
* \brief Base class for Multi-Link Operations tests
*
* Three spectrum channels are created, one for each band (2.4 GHz, 5 GHz and 6 GHz).
* Each PHY object is attached to the spectrum channel corresponding to the PHY band
* in which it is operating.
*/
class MultiLinkOperationsTestBase : public TestCase
{
public:
/**
* Configuration parameters common to all subclasses
*/
struct BaseParams
{
std::vector<std::string>
staChannels; //!< the strings specifying the operating channels for the non-AP MLD
std::vector<std::string>
apChannels; //!< the strings specifying the operating channels for the AP MLD
std::vector<uint8_t>
fixedPhyBands; //!< list of IDs of non-AP MLD PHYs that cannot switch band
};
/**
* Constructor
*
* \param name The name of the new TestCase created
* \param nStations the number of stations to create
* \param baseParams common configuration parameters
*/
MultiLinkOperationsTestBase(const std::string& name,
uint8_t nStations,
const BaseParams& baseParams);
~MultiLinkOperationsTestBase() override = default;
protected:
/**
* Callback invoked when a FEM passes PSDUs to the PHY.
*
* \param mac the MAC transmitting the PSDUs
* \param phyId the ID of the PHY transmitting the PSDUs
* \param psduMap the PSDU map
* \param txVector the TX vector
* \param txPowerW the tx power in Watts
*/
virtual void Transmit(Ptr<WifiMac> mac,
uint8_t phyId,
WifiConstPsduMap psduMap,
WifiTxVector txVector,
double txPowerW);
/**
* Check that the expected Capabilities information elements are present in the given
* management frame based on the band in which the given link is operating.
*
* \param mpdu the given management frame
* \param mac the MAC transmitting the management frame
* \param phyId the ID of the PHY transmitting the management frame
*/
void CheckCapabilities(Ptr<WifiMpdu> mpdu, Ptr<WifiMac> mac, uint8_t phyId);
/**
* 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
*/
virtual void L7Receive(uint8_t nodeId, Ptr<const Packet> p, const Address& addr);
/**
* \param sockAddr the packet socket address identifying local outgoing interface
* and remote address
* \param count the number of packets to generate
* \param pktSize the size of the packets to generate
* \param delay the delay with which traffic generation starts
* \param priority user priority for generated packets
* \return an application generating the given number packets of the given size destined
* to the given packet socket address
*/
Ptr<PacketSocketClient> GetApplication(const PacketSocketAddress& sockAddr,
std::size_t count,
std::size_t pktSize,
Time delay = Seconds(0),
uint8_t priority = 0) const;
void DoSetup() override;
/// PHY band-indexed map of spectrum channels
using ChannelMap = std::map<FrequencyRange, Ptr<MultiModelSpectrumChannel>>;
/**
* Uplink or Downlink direction
*/
enum Direction
{
DL = 0,
UL
};
/**
* Check that the Address 1 and Address 2 fields of the given PSDU contain device MAC addresses.
*
* \param psdu the given PSDU
* \param direction indicates direction for management frames (DL or UL)
*/
void CheckAddresses(Ptr<const WifiPsdu> psdu,
std::optional<Direction> direction = std::nullopt);
/// Information about transmitted frames
struct FrameInfo
{
Time startTx; ///< TX start time
WifiConstPsduMap psduMap; ///< transmitted PSDU map
WifiTxVector txVector; ///< TXVECTOR
uint8_t linkId; ///< link ID
uint8_t phyId; ///< ID of the transmitting PHY
};
std::vector<FrameInfo> m_txPsdus; ///< transmitted PSDUs
const std::vector<std::string> m_staChannels; ///< strings specifying channels for STA
const std::vector<std::string> m_apChannels; ///< strings specifying channels for AP
const std::vector<uint8_t> m_fixedPhyBands; ///< links on non-AP MLD with fixed PHY band
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
Time m_duration{Seconds(1)}; ///< simulation duration
std::vector<std::size_t> m_rxPkts; ///< number of packets received at application layer
///< by each node (index is node ID)
private:
/**
* Reset the given PHY helper, use the given strings to set the ChannelSettings
* attribute of the PHY objects to create, and attach them to the given spectrum
* channels appropriately.
*
* \param helper the given PHY helper
* \param channels the strings specifying the operating channels to configure
* \param channelMap the created spectrum channels
*/
void SetChannels(SpectrumWifiPhyHelper& helper,
const std::vector<std::string>& channels,
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,
const BaseParams& baseParams)
@@ -1041,147 +755,6 @@ MultiLinkOperationsTestBase::SetSsid(uint16_t aid, Mac48Address /* addr */)
Simulator::Schedule(MilliSeconds(5), &MultiLinkOperationsTestBase::StartTraffic, this);
}
/**
* \ingroup wifi-test
* \ingroup tests
*
* \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.
*
* The negotiated TID-to-link mapping is tested by verifying that generated QoS data frames of
* a given TID are transmitted on links which the TID is mapped to. Specifically, the following
* operations are performed separately for each direction (downlink and uplink). A first TID
* is searched such that it is not mapped on all the setup links. If no such TID is found, only
* QoS frames of TID 0 are generated. Otherwise, we also search for a second TID that is mapped
* to a link set that is disjoint with the link set to which the first TID is mapped. If such a
* TID is found, QoS frames of both the first TID and the second TID are generated; otherwise,
* only QoS frames of the first TID are generated. For each TID, a number of QoS frames equal
* to the number of setup links is generated. For each TID, we check that the first N QoS frames,
* where N is the size of the link set to which the TID is mapped, are transmitted concurrently,
* while the following QoS frames are sent after the first QoS frame sent on the same link. We
* also check that all the QoS frames are sent on a link belonging to the link set to which the
* TID is mapped. If QoS frames of two TIDs are generated, we also check that the first N QoS
* frames of a TID, where N is the size of the link set to which that TID is mapped, are sent
* concurrently with the first M QoS frames of the other TID, where M is the size of the link
* set to which the other TID is mapped.
*/
class MultiLinkSetupTest : public MultiLinkOperationsTestBase
{
public:
/**
* Constructor
*
* \param baseParams common configuration parameters
* \param scanType the scan type (active or passive)
* \param setupLinks a list of links that are expected to be setup. In case one of the two
* devices has a single link, the ID of the link on the MLD is indicated
* \param apNegSupport TID-to-Link Mapping negotiation supported by the AP MLD (0, 1, or 3)
* \param dlTidToLinkMapping DL TID-to-Link Mapping for EHT configuration of non-AP MLD
* \param ulTidToLinkMapping UL TID-to-Link Mapping for EHT configuration of non-AP MLD
* \param support160MHzOp whether non-AP MLDs support 160 MHz operations
*/
MultiLinkSetupTest(const BaseParams& baseParams,
WifiScanType scanType,
const std::vector<uint8_t>& setupLinks,
WifiTidToLinkMappingNegSupport apNegSupport,
const std::string& dlTidToLinkMapping,
const std::string& ulTidToLinkMapping,
bool support160MHzOp = true);
~MultiLinkSetupTest() override = default;
protected:
void DoSetup() override;
void DoRun() override;
private:
void StartTraffic() override;
/**
* Check correctness of Multi-Link Setup procedure.
*/
void CheckMlSetup();
/**
* Check that links that are not setup on the non-AP MLD are disabled. Also, on the AP side,
* check that the queue storing QoS data frames destined to the non-AP MLD has a mask for a
* link if and only if the link has been setup by the non-AO MLD.
*/
void CheckDisabledLinks();
/**
* Check correctness of the given Beacon frame.
*
* \param mpdu the given Beacon frame
* \param linkId the ID of the link on which the Beacon frame was transmitted
*/
void CheckBeacon(Ptr<WifiMpdu> mpdu, uint8_t linkId);
/**
* Check correctness of the given Probe Response frame.
*
* \param mpdu the given Probe Response frame
* \param linkId the ID of the link on which the Probe Response frame was transmitted
*/
void CheckProbeResponse(Ptr<WifiMpdu> mpdu, uint8_t linkId);
/**
* Check correctness of the given Association Request frame.
*
* \param mpdu the given Association Request frame
* \param linkId the ID of the link on which the Association Request frame was transmitted
*/
void CheckAssocRequest(Ptr<WifiMpdu> mpdu, uint8_t linkId);
/**
* Check correctness of the given Association Response frame.
*
* \param mpdu the given Association Response frame
* \param linkId the ID of the link on which the Association Response frame was transmitted
*/
void CheckAssocResponse(Ptr<WifiMpdu> mpdu, uint8_t linkId);
/**
* Check that QoS data frames are sent on links their TID is mapped to and with the
* correct TX width.
*
* \param mpdu the given QoS data frame
* \param txvector the TXVECTOR used to send the QoS data frame
* \param linkId the ID of the link on which the QoS data frame was transmitted
* \param index index of the QoS data frame in the vector of transmitted PSDUs
*/
void CheckQosData(Ptr<WifiMpdu> mpdu,
const WifiTxVector& txvector,
uint8_t linkId,
std::size_t index);
const std::vector<uint8_t> m_setupLinks; //!< IDs of the expected links to setup
WifiScanType m_scanType; //!< the scan type (active or passive)
std::size_t m_nProbeResp; //!< number of Probe Responses received by the non-AP MLD
WifiTidToLinkMappingNegSupport
m_apNegSupport; //!< TID-to-Link Mapping negotiation supported by the AP MLD
std::string m_dlTidLinkMappingStr; //!< DL TID-to-Link Mapping for non-AP MLD EHT configuration
std::string m_ulTidLinkMappingStr; //!< UL TID-to-Link Mapping for non-AP MLD EHT configuration
WifiTidLinkMapping m_dlTidLinkMapping; //!< expected DL TID-to-Link Mapping requested by non-AP
//!< MLD and accepted by AP MLD
WifiTidLinkMapping m_ulTidLinkMapping; //!< expected UL TID-to-Link Mapping requested by non-AP
//!< MLD and accepted by AP MLD
uint8_t m_dlTid1; //!< the TID of the first set of DL QoS data frames
uint8_t m_ulTid1; //!< the TID of the first set of UL QoS data frames
std::optional<uint8_t> m_dlTid2; //!< the TID of the optional set of DL QoS data frames
std::optional<uint8_t> m_ulTid2; //!< the TID of the optional set of UL QoS data frames
std::vector<std::size_t>
m_qosFrames1; //!< indices of QoS frames of the first set in the vector of TX PSDUs
std::vector<std::size_t>
m_qosFrames2; //!< indices of QoS frames of the optional set in the vector of TX PSDUs
bool m_support160MHzOp; //!< whether non-AP MLDs support 160 MHz operations
};
MultiLinkSetupTest::MultiLinkSetupTest(const BaseParams& baseParams,
WifiScanType scanType,
const std::vector<uint8_t>& setupLinks,
@@ -2097,124 +1670,6 @@ MultiLinkSetupTest::CheckQosData(Ptr<WifiMpdu> mpdu,
}
}
/**
* Tested traffic patterns.
*/
enum class WifiTrafficPattern : uint8_t
{
STA_TO_STA = 0,
STA_TO_AP,
AP_TO_STA,
AP_TO_BCAST,
STA_TO_BCAST
};
/**
* Block Ack agreement enabled/disabled
*/
enum class WifiBaEnabled : uint8_t
{
NO = 0,
YES
};
/**
* Whether to send a BlockAckReq after a missed BlockAck
*/
enum class WifiUseBarAfterMissedBa : uint8_t
{
NO = 0,
YES
};
/**
* \ingroup wifi-test
* \ingroup tests
*
* \brief Test data transmission between two MLDs.
*
* 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).
* In the scenarios in which the AP forwards frames (i.e., from one station to another and
* from one station to broadcast) the client application generates only 4 packets, in order
* to limit the probability of collisions. In the other scenarios, 8 packets are generated.
* When BlockAck agreements are enabled, the maximum A-MSDU size is set such that two
* packets can be aggregated in an A-MSDU. The MPDU with sequence number equal to 1 is
* corrupted (once, by using a post reception error model) to test its successful
* re-transmission, unless the traffic scenario is from the AP to broadcast (broadcast frames
* are not retransmitted) or is a scenario where the AP forwards frame (to limit the
* probability of collisions).
*
* When BlockAck agreements are enabled, we also corrupt a BlockAck frame, so as to simulate
* the case of BlockAck timeout. Both the case where a BlockAckReq is sent and the case where
* data frame are retransmitted are tested. Finally, when BlockAck agreements are enabled, we
* also enable the concurrent transmission of data frames over two links and check that at
* least one MPDU is concurrently transmitted over two links.
*/
class MultiLinkTxTest : public MultiLinkOperationsTestBase
{
public:
/**
* Constructor
*
* \param baseParams common configuration parameters
* \param trafficPattern the pattern of traffic to generate
* \param baEnabled whether BA agreement is enabled or disabled
* \param useBarAfterMissedBa whether a BAR or Data frames are sent after missed BlockAck
* \param nMaxInflight the max number of links on which an MPDU can be simultaneously inflight
* (unused if Block Ack agreements are not established)
*/
MultiLinkTxTest(const BaseParams& baseParams,
WifiTrafficPattern trafficPattern,
WifiBaEnabled baEnabled,
WifiUseBarAfterMissedBa useBarAfterMissedBa,
uint8_t nMaxInflight);
~MultiLinkTxTest() override = default;
protected:
/**
* Check the content of a received BlockAck frame when the max number of links on which
* an MPDU can be inflight is one.
*
* \param psdu the PSDU containing the BlockAck
* \param txVector the TXVECTOR used to transmit the BlockAck
* \param linkId the ID of the link on which the BlockAck was transmitted
*/
void CheckBlockAck(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, uint8_t linkId);
void Transmit(Ptr<WifiMac> mac,
uint8_t phyId,
WifiConstPsduMap psduMap,
WifiTxVector txVector,
double txPowerW) override;
void DoSetup() override;
void DoRun() override;
private:
void StartTraffic() override;
/// Receiver address-indexed map of list error models
using RxErrorModelMap = std::unordered_map<Mac48Address, Ptr<ListErrorModel>, WifiAddressHash>;
RxErrorModelMap m_errorModels; ///< error rate models 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
WifiTrafficPattern m_trafficPattern; ///< the pattern of traffic to generate
bool m_baEnabled; ///< whether BA agreement is enabled or disabled
bool m_useBarAfterMissedBa; ///< whether to send BAR after missed BlockAck
std::size_t m_nMaxInflight; ///< max number of links on which an MPDU can be inflight
std::size_t m_nPackets; ///< number of application packets to generate
std::size_t m_blockAckCount{0}; ///< transmitted BlockAck counter
std::size_t m_blockAckReqCount{0}; ///< transmitted BlockAckReq counter
std::map<uint16_t, std::size_t> m_inflightCount; ///< seqNo-indexed max number of simultaneous
///< transmissions of a data frame
Ptr<WifiMac> m_sourceMac; ///< MAC of the node sending application packets
};
MultiLinkTxTest::MultiLinkTxTest(const BaseParams& baseParams,
WifiTrafficPattern trafficPattern,
WifiBaEnabled baEnabled,
@@ -2682,105 +2137,6 @@ MultiLinkTxTest::DoRun()
Simulator::Destroy();
}
/**
* Tested MU traffic patterns.
*/
enum class WifiMuTrafficPattern : uint8_t
{
DL_MU_BAR_BA_SEQUENCE = 0,
DL_MU_MU_BAR,
DL_MU_AGGR_MU_BAR,
UL_MU
};
/**
* \ingroup wifi-test
* \ingroup tests
*
* \brief Test data transmission between MLDs using OFDMA MU transmissions
*
* 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
* DL MU and UL MU frames. In the DL MU scenarios, the client applications installed on the
* AP generate 8 packets addressed to each of the stations (plus 3 packets to trigger the
* establishment of BlockAck agreements). In the UL MU scenario, client applications
* installed on the stations generate 4 packets each (plus 3 packets to trigger the
* establishment of BlockAck agreements).
*
* The maximum A-MSDU size is set such that two packets can be aggregated in an A-MSDU.
* The MPDU with sequence number equal to 3 is corrupted (by using a post reception error
* model) once and for a single station, to test its successful re-transmission.
*
* Also, we enable the concurrent transmission of data frames over two links and check that at
* least one MPDU is concurrently transmitted over two links.
*/
class MultiLinkMuTxTest : public MultiLinkOperationsTestBase
{
public:
/**
* Constructor
*
* \param baseParams common configuration parameters
* \param muTrafficPattern the pattern of traffic to generate
* \param useBarAfterMissedBa whether a BAR or Data frames are sent after missed BlockAck
* \param nMaxInflight the max number of links on which an MPDU can be simultaneously inflight
* (unused if Block Ack agreements are not established)
*/
MultiLinkMuTxTest(const BaseParams& baseParams,
WifiMuTrafficPattern muTrafficPattern,
WifiUseBarAfterMissedBa useBarAfterMissedBa,
uint8_t nMaxInflight);
~MultiLinkMuTxTest() override = default;
protected:
/**
* Check the content of a received BlockAck frame when the max number of links on which
* an MPDU can be inflight is one.
*
* \param psdu the PSDU containing the BlockAck
* \param txVector the TXVECTOR used to transmit the BlockAck
* \param linkId the ID of the link on which the BlockAck was transmitted
*/
void CheckBlockAck(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, uint8_t linkId);
void Transmit(Ptr<WifiMac> mac,
uint8_t phyId,
WifiConstPsduMap psduMap,
WifiTxVector txVector,
double txPowerW) override;
void DoSetup() override;
void DoRun() override;
private:
void StartTraffic() override;
/// Receiver address-indexed map of list error models
using RxErrorModelMap = std::unordered_map<Mac48Address, Ptr<ListErrorModel>, WifiAddressHash>;
/// A pair of a MAC address (the address of the receiver for DL frames and the address of
/// the sender for UL frames) and a sequence number identifying a transmitted QoS data frame
using AddrSeqNoPair = std::pair<Mac48Address, uint16_t>;
RxErrorModelMap m_errorModels; ///< error rate models to corrupt packets
std::list<uint64_t> m_uidList; ///< list of UIDs of packets to corrupt
std::optional<Mac48Address> m_dataCorruptedSta; ///< MAC address of the station that received
///< MPDU with SeqNo=2 corrupted
bool m_waitFirstTf{true}; ///< whether we are waiting for the first Basic Trigger Frame
WifiMuTrafficPattern m_muTrafficPattern; ///< the pattern of traffic to generate
bool m_useBarAfterMissedBa; ///< whether to send BAR after missed BlockAck
std::size_t m_nMaxInflight; ///< max number of links on which an MPDU can be inflight
std::vector<PacketSocketAddress> m_sockets; ///< packet socket addresses for STAs
std::size_t m_nPackets; ///< number of application packets to generate
std::size_t m_blockAckCount{0}; ///< transmitted BlockAck counter
std::size_t m_tfCount{0}; ///< transmitted Trigger Frame counter
// std::size_t m_blockAckReqCount{0}; ///< transmitted BlockAckReq counter
std::map<AddrSeqNoPair, std::size_t> m_inflightCount; ///< max number of simultaneous
///< transmissions of each data frame
Ptr<WifiMac> m_sourceMac; ///< MAC of the node sending application packets
};
MultiLinkMuTxTest::MultiLinkMuTxTest(const BaseParams& baseParams,
WifiMuTrafficPattern muTrafficPattern,
WifiUseBarAfterMissedBa useBarAfterMissedBa,
@@ -3292,48 +2648,6 @@ MultiLinkMuTxTest::DoRun()
Simulator::Destroy();
}
/**
* \ingroup wifi-test
* \ingroup tests
*
* \brief Test release of sequence numbers upon CTS timeout in multi-link operations
*
* In this test, an AP MLD and a non-AP MLD setup 3 links. Usage of RTS/CTS protection is
* enabled for frames whose length is at least 1000 bytes. The AP MLD receives a first set
* of 4 packets from the upper layer and sends an RTS frame, which is corrupted at the
* receiver, on a first link. When the RTS frame is transmitted, the AP MLD receives another
* set of 4 packets, which are transmitted after a successful RTS/CTS exchange on a second
* link. In the meantime, a new RTS/CTS exchange is successfully carried out (on the first
* link or on the third link) to transmit the first set of 4 packets. When the transmission
* of the first set of 4 packets starts, the AP MLD receives the third set of 4 packets from
* the upper layer, which are transmitted after a successful RTS/CTS exchange.
*
* This test checks that sequence numbers are correctly assigned to all the MPDUs carrying data.
*/
class ReleaseSeqNoAfterCtsTimeoutTest : public MultiLinkOperationsTestBase
{
public:
ReleaseSeqNoAfterCtsTimeoutTest();
~ReleaseSeqNoAfterCtsTimeoutTest() override = default;
protected:
void DoSetup() override;
void DoRun() override;
void Transmit(Ptr<WifiMac> mac,
uint8_t phyId,
WifiConstPsduMap psduMap,
WifiTxVector txVector,
double txPowerW) override;
private:
void StartTraffic() override;
PacketSocketAddress m_sockAddr; //!< packet socket address
std::size_t m_nQosDataFrames; //!< counter for transmitted QoS data frames
Ptr<ListErrorModel> m_errorModel; //!< error rate model to corrupt first RTS frame
bool m_rtsCorrupted; //!< whether the first RTS frame has been corrupted
};
ReleaseSeqNoAfterCtsTimeoutTest::ReleaseSeqNoAfterCtsTimeoutTest()
: MultiLinkOperationsTestBase(
"Check sequence numbers after CTS timeout",
@@ -3451,47 +2765,6 @@ ReleaseSeqNoAfterCtsTimeoutTest::DoRun()
Simulator::Destroy();
}
/**
* \ingroup wifi-test
* \ingroup tests
*
* \brief Test update of BA starting sequence number after ADDBA Response timeout in
* multi-link operations
*
* In this test, an AP MLD and a non-AP MLD setup 2 links. The AP MLD has a QoS data frame to
* transmit to the non-AP MLD, which triggers the establishment of a BA agreement. When the ADDBA
* Request frame is received by the non-AP MLD, transmissions of the non-AP MLD are blocked to put
* the transmission of the ADDBA Response on hold. The goal is to mimic a delay in getting channel
* access due to, e.g., other devices grabbing the medium. When the ADDBA Response timer at the AP
* MLD expires, transmissions of the non-AP MLD are unblocked, so that the AP MLD sends the QoS data
* frame (protected by RTS, but the test works without RTS as well, and using Normal acknowledgment)
* on one link and the non-AP MLD sends the ADDBA Response on the other link. The transmission of
* the QoS data frame is then corrupted. We verify that:
*
* - when the AP MLD receives the ADDBA Response, the BA starting sequence number is set to the
* sequence number of the QoS data frame which is inflight
* - the QoS data frame is retransmitted and received by the non-AP MLD
*/
class StartSeqNoUpdateAfterAddBaTimeoutTest : public MultiLinkOperationsTestBase
{
public:
StartSeqNoUpdateAfterAddBaTimeoutTest();
private:
void DoSetup() override;
void DoRun() override;
void Transmit(Ptr<WifiMac> mac,
uint8_t phyId,
WifiConstPsduMap psduMap,
WifiTxVector txVector,
double txPowerW) override;
void StartTraffic() override;
PacketSocketAddress m_sockAddr; //!< packet socket address
std::size_t m_nQosDataCount; //!< counter for transmitted QoS data frames
Ptr<ListErrorModel> m_staErrorModel; //!< error rate model to corrupt frames at the non-AP MLD
};
StartSeqNoUpdateAfterAddBaTimeoutTest::StartSeqNoUpdateAfterAddBaTimeoutTest()
: MultiLinkOperationsTestBase(
"Check starting sequence number update after ADDBA Response timeout",
@@ -3647,18 +2920,6 @@ StartSeqNoUpdateAfterAddBaTimeoutTest::DoRun()
Simulator::Destroy();
}
/**
* \ingroup wifi-test
* \ingroup tests
*
* \brief wifi 11be MLD Test Suite
*/
class WifiMultiLinkOperationsTestSuite : public TestSuite
{
public:
WifiMultiLinkOperationsTestSuite();
};
WifiMultiLinkOperationsTestSuite::WifiMultiLinkOperationsTestSuite()
: TestSuite("wifi-mlo", Type::UNIT)
{

View File

@@ -0,0 +1,770 @@
/*
* Copyright (c) 2022 Universita' degli Studi di Napoli Federico II
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Stefano Avallone <stavallo@unina.it>
*/
#ifndef WIFI_MLO_TEST_H
#define WIFI_MLO_TEST_H
#include "ns3/ap-wifi-mac.h"
#include "ns3/mgt-action-headers.h"
#include "ns3/mgt-headers.h"
#include "ns3/multi-model-spectrum-channel.h"
#include "ns3/packet-socket-client.h"
#include "ns3/packet-socket-server.h"
#include "ns3/qos-utils.h"
#include "ns3/spectrum-wifi-helper.h"
#include "ns3/sta-wifi-mac.h"
#include "ns3/test.h"
#include "ns3/wifi-psdu.h"
#include <optional>
#include <vector>
using namespace ns3;
/**
* \ingroup wifi-test
* \ingroup tests
*
* \brief Test the implementation of WifiAssocManager::GetNextAffiliatedAp(), which
* searches a given RNR element for APs affiliated to the same AP MLD as the
* reporting AP that sent the frame containing the element.
*/
class GetRnrLinkInfoTest : public TestCase
{
public:
/**
* Constructor
*/
GetRnrLinkInfoTest();
~GetRnrLinkInfoTest() override = default;
private:
void DoRun() override;
};
/**
* \ingroup wifi-test
* \ingroup tests
*
* Test the WifiMac::SwapLinks() method.
*/
class MldSwapLinksTest : public TestCase
{
/**
* Test WifiMac subclass used to access the SwapLinks method.
*/
class TestWifiMac : public WifiMac
{
public:
~TestWifiMac() override = default;
using WifiMac::GetLinks;
using WifiMac::SwapLinks;
bool CanForwardPacketsTo(Mac48Address to) const override
{
return true;
}
private:
void DoCompleteConfig() override
{
}
void Enqueue(Ptr<WifiMpdu> mpdu, Mac48Address to, Mac48Address from) override
{
}
};
public:
MldSwapLinksTest();
~MldSwapLinksTest() override = default;
protected:
void DoRun() override;
private:
/**
* Run a single test case.
*
* \param text string identifying the test case
* \param nLinks the number of links of the MLD
* \param links a set of pairs (from, to) each mapping a current link ID to the
* link ID it has to become (i.e., link 'from' becomes link 'to')
* \param expected maps each link ID to the id of the PHY that is expected
* to operate on that link after the swap
*/
void RunOne(std::string text,
std::size_t nLinks,
const std::map<uint8_t, uint8_t>& links,
const std::map<uint8_t, uint8_t>& expected);
};
/**
* \ingroup wifi-test
* \ingroup tests
*
* Test that the AIDs that an AP MLD assigns to SLDs and MLDs are all unique.
*/
class AidAssignmentTest : public TestCase
{
public:
/**
* Constructor.
*
* \param linkIds A vector specifying the set of link IDs each STA will setup
*/
AidAssignmentTest(const std::vector<std::set<uint8_t>>& linkIds);
private:
void DoSetup() override;
void DoRun() override;
/**
* Set the SSID on the next station that needs to start the association procedure.
* This method is triggered every time a STA completes its association.
*
* \param staMac the MAC of the STA that completed association
*/
void SetSsid(Ptr<StaWifiMac> staMac, Mac48Address /* apAddr */);
const std::vector<std::string> m_linkChannels; //!< channels for all AP links
const std::vector<std::set<uint8_t>> m_linkIds; //!< link IDs for all non-AP STAs/MLDs
NetDeviceContainer m_staDevices; //!< non-AP STAs/MLDs devices
uint16_t m_expectedAid; //!< expected AID for current non-AP STA/MLD
};
/**
* \ingroup wifi-test
* \ingroup tests
*
* \brief Base class for Multi-Link Operations tests
*
* Three spectrum channels are created, one for each band (2.4 GHz, 5 GHz and 6 GHz).
* Each PHY object is attached to the spectrum channel corresponding to the PHY band
* in which it is operating.
*/
class MultiLinkOperationsTestBase : public TestCase
{
public:
/**
* Configuration parameters common to all subclasses
*/
struct BaseParams
{
std::vector<std::string>
staChannels; //!< the strings specifying the operating channels for the non-AP MLD
std::vector<std::string>
apChannels; //!< the strings specifying the operating channels for the AP MLD
std::vector<uint8_t>
fixedPhyBands; //!< list of IDs of non-AP MLD PHYs that cannot switch band
};
/**
* Constructor
*
* \param name The name of the new TestCase created
* \param nStations the number of stations to create
* \param baseParams common configuration parameters
*/
MultiLinkOperationsTestBase(const std::string& name,
uint8_t nStations,
const BaseParams& baseParams);
~MultiLinkOperationsTestBase() override = default;
protected:
/**
* Callback invoked when a FEM passes PSDUs to the PHY.
*
* \param mac the MAC transmitting the PSDUs
* \param phyId the ID of the PHY transmitting the PSDUs
* \param psduMap the PSDU map
* \param txVector the TX vector
* \param txPowerW the tx power in Watts
*/
virtual void Transmit(Ptr<WifiMac> mac,
uint8_t phyId,
WifiConstPsduMap psduMap,
WifiTxVector txVector,
double txPowerW);
/**
* Check that the expected Capabilities information elements are present in the given
* management frame based on the band in which the given link is operating.
*
* \param mpdu the given management frame
* \param mac the MAC transmitting the management frame
* \param phyId the ID of the PHY transmitting the management frame
*/
void CheckCapabilities(Ptr<WifiMpdu> mpdu, Ptr<WifiMac> mac, uint8_t phyId);
/**
* 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
*/
virtual void L7Receive(uint8_t nodeId, Ptr<const Packet> p, const Address& addr);
/**
* \param sockAddr the packet socket address identifying local outgoing interface
* and remote address
* \param count the number of packets to generate
* \param pktSize the size of the packets to generate
* \param delay the delay with which traffic generation starts
* \param priority user priority for generated packets
* \return an application generating the given number packets of the given size destined
* to the given packet socket address
*/
Ptr<PacketSocketClient> GetApplication(const PacketSocketAddress& sockAddr,
std::size_t count,
std::size_t pktSize,
Time delay = Seconds(0),
uint8_t priority = 0) const;
void DoSetup() override;
/// PHY band-indexed map of spectrum channels
using ChannelMap = std::map<FrequencyRange, Ptr<MultiModelSpectrumChannel>>;
/**
* Uplink or Downlink direction
*/
enum Direction
{
DL = 0,
UL
};
/**
* Check that the Address 1 and Address 2 fields of the given PSDU contain device MAC addresses.
*
* \param psdu the given PSDU
* \param direction indicates direction for management frames (DL or UL)
*/
void CheckAddresses(Ptr<const WifiPsdu> psdu,
std::optional<Direction> direction = std::nullopt);
/// Information about transmitted frames
struct FrameInfo
{
Time startTx; ///< TX start time
WifiConstPsduMap psduMap; ///< transmitted PSDU map
WifiTxVector txVector; ///< TXVECTOR
uint8_t linkId; ///< link ID
uint8_t phyId; ///< ID of the transmitting PHY
};
std::vector<FrameInfo> m_txPsdus; ///< transmitted PSDUs
const std::vector<std::string> m_staChannels; ///< strings specifying channels for STA
const std::vector<std::string> m_apChannels; ///< strings specifying channels for AP
const std::vector<uint8_t> m_fixedPhyBands; ///< links on non-AP MLD with fixed PHY band
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
Time m_duration{Seconds(1)}; ///< simulation duration
std::vector<std::size_t> m_rxPkts; ///< number of packets received at application layer
///< by each node (index is node ID)
/**
* Reset the given PHY helper, use the given strings to set the ChannelSettings
* attribute of the PHY objects to create, and attach them to the given spectrum
* channels appropriately.
*
* \param helper the given PHY helper
* \param channels the strings specifying the operating channels to configure
* \param channelMap the created spectrum channels
*/
void SetChannels(SpectrumWifiPhyHelper& helper,
const std::vector<std::string>& channels,
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 */);
private:
/**
* Start the generation of traffic (needs to be overridden)
*/
virtual void StartTraffic()
{
}
};
/**
* \ingroup wifi-test
* \ingroup tests
*
* \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.
*
* The negotiated TID-to-link mapping is tested by verifying that generated QoS data frames of
* a given TID are transmitted on links which the TID is mapped to. Specifically, the following
* operations are performed separately for each direction (downlink and uplink). A first TID
* is searched such that it is not mapped on all the setup links. If no such TID is found, only
* QoS frames of TID 0 are generated. Otherwise, we also search for a second TID that is mapped
* to a link set that is disjoint with the link set to which the first TID is mapped. If such a
* TID is found, QoS frames of both the first TID and the second TID are generated; otherwise,
* only QoS frames of the first TID are generated. For each TID, a number of QoS frames equal
* to the number of setup links is generated. For each TID, we check that the first N QoS frames,
* where N is the size of the link set to which the TID is mapped, are transmitted concurrently,
* while the following QoS frames are sent after the first QoS frame sent on the same link. We
* also check that all the QoS frames are sent on a link belonging to the link set to which the
* TID is mapped. If QoS frames of two TIDs are generated, we also check that the first N QoS
* frames of a TID, where N is the size of the link set to which that TID is mapped, are sent
* concurrently with the first M QoS frames of the other TID, where M is the size of the link
* set to which the other TID is mapped.
*/
class MultiLinkSetupTest : public MultiLinkOperationsTestBase
{
public:
/**
* Constructor
*
* \param baseParams common configuration parameters
* \param scanType the scan type (active or passive)
* \param setupLinks a list of links that are expected to be setup. In case one of the two
* devices has a single link, the ID of the link on the MLD is indicated
* \param apNegSupport TID-to-Link Mapping negotiation supported by the AP MLD (0, 1, or 3)
* \param dlTidToLinkMapping DL TID-to-Link Mapping for EHT configuration of non-AP MLD
* \param ulTidToLinkMapping UL TID-to-Link Mapping for EHT configuration of non-AP MLD
* \param support160MHzOp whether non-AP MLDs support 160 MHz operations
*/
MultiLinkSetupTest(const BaseParams& baseParams,
WifiScanType scanType,
const std::vector<uint8_t>& setupLinks,
WifiTidToLinkMappingNegSupport apNegSupport,
const std::string& dlTidToLinkMapping,
const std::string& ulTidToLinkMapping,
bool support160MHzOp = true);
~MultiLinkSetupTest() override = default;
protected:
void DoSetup() override;
void DoRun() override;
private:
void StartTraffic() override;
/**
* Check correctness of Multi-Link Setup procedure.
*/
void CheckMlSetup();
/**
* Check that links that are not setup on the non-AP MLD are disabled. Also, on the AP side,
* check that the queue storing QoS data frames destined to the non-AP MLD has a mask for a
* link if and only if the link has been setup by the non-AO MLD.
*/
void CheckDisabledLinks();
/**
* Check correctness of the given Beacon frame.
*
* \param mpdu the given Beacon frame
* \param linkId the ID of the link on which the Beacon frame was transmitted
*/
void CheckBeacon(Ptr<WifiMpdu> mpdu, uint8_t linkId);
/**
* Check correctness of the given Probe Response frame.
*
* \param mpdu the given Probe Response frame
* \param linkId the ID of the link on which the Probe Response frame was transmitted
*/
void CheckProbeResponse(Ptr<WifiMpdu> mpdu, uint8_t linkId);
/**
* Check correctness of the given Association Request frame.
*
* \param mpdu the given Association Request frame
* \param linkId the ID of the link on which the Association Request frame was transmitted
*/
void CheckAssocRequest(Ptr<WifiMpdu> mpdu, uint8_t linkId);
/**
* Check correctness of the given Association Response frame.
*
* \param mpdu the given Association Response frame
* \param linkId the ID of the link on which the Association Response frame was transmitted
*/
void CheckAssocResponse(Ptr<WifiMpdu> mpdu, uint8_t linkId);
/**
* Check that QoS data frames are sent on links their TID is mapped to and with the
* correct TX width.
*
* \param mpdu the given QoS data frame
* \param txvector the TXVECTOR used to send the QoS data frame
* \param linkId the ID of the link on which the QoS data frame was transmitted
* \param index index of the QoS data frame in the vector of transmitted PSDUs
*/
void CheckQosData(Ptr<WifiMpdu> mpdu,
const WifiTxVector& txvector,
uint8_t linkId,
std::size_t index);
const std::vector<uint8_t> m_setupLinks; //!< IDs of the expected links to setup
WifiScanType m_scanType; //!< the scan type (active or passive)
std::size_t m_nProbeResp; //!< number of Probe Responses received by the non-AP MLD
WifiTidToLinkMappingNegSupport
m_apNegSupport; //!< TID-to-Link Mapping negotiation supported by the AP MLD
std::string m_dlTidLinkMappingStr; //!< DL TID-to-Link Mapping for non-AP MLD EHT configuration
std::string m_ulTidLinkMappingStr; //!< UL TID-to-Link Mapping for non-AP MLD EHT configuration
WifiTidLinkMapping m_dlTidLinkMapping; //!< expected DL TID-to-Link Mapping requested by non-AP
//!< MLD and accepted by AP MLD
WifiTidLinkMapping m_ulTidLinkMapping; //!< expected UL TID-to-Link Mapping requested by non-AP
//!< MLD and accepted by AP MLD
uint8_t m_dlTid1; //!< the TID of the first set of DL QoS data frames
uint8_t m_ulTid1; //!< the TID of the first set of UL QoS data frames
std::optional<uint8_t> m_dlTid2; //!< the TID of the optional set of DL QoS data frames
std::optional<uint8_t> m_ulTid2; //!< the TID of the optional set of UL QoS data frames
std::vector<std::size_t>
m_qosFrames1; //!< indices of QoS frames of the first set in the vector of TX PSDUs
std::vector<std::size_t>
m_qosFrames2; //!< indices of QoS frames of the optional set in the vector of TX PSDUs
bool m_support160MHzOp; //!< whether non-AP MLDs support 160 MHz operations
};
/**
* Tested traffic patterns.
*/
enum class WifiTrafficPattern : uint8_t
{
STA_TO_STA = 0,
STA_TO_AP,
AP_TO_STA,
AP_TO_BCAST,
STA_TO_BCAST
};
/**
* Block Ack agreement enabled/disabled
*/
enum class WifiBaEnabled : uint8_t
{
NO = 0,
YES
};
/**
* Whether to send a BlockAckReq after a missed BlockAck
*/
enum class WifiUseBarAfterMissedBa : uint8_t
{
NO = 0,
YES
};
/**
* \ingroup wifi-test
* \ingroup tests
*
* \brief Test data transmission between two MLDs.
*
* 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).
* In the scenarios in which the AP forwards frames (i.e., from one station to another and
* from one station to broadcast) the client application generates only 4 packets, in order
* to limit the probability of collisions. In the other scenarios, 8 packets are generated.
* When BlockAck agreements are enabled, the maximum A-MSDU size is set such that two
* packets can be aggregated in an A-MSDU. The MPDU with sequence number equal to 1 is
* corrupted (once, by using a post reception error model) to test its successful
* re-transmission, unless the traffic scenario is from the AP to broadcast (broadcast frames
* are not retransmitted) or is a scenario where the AP forwards frame (to limit the
* probability of collisions).
*
* When BlockAck agreements are enabled, we also corrupt a BlockAck frame, so as to simulate
* the case of BlockAck timeout. Both the case where a BlockAckReq is sent and the case where
* data frame are retransmitted are tested. Finally, when BlockAck agreements are enabled, we
* also enable the concurrent transmission of data frames over two links and check that at
* least one MPDU is concurrently transmitted over two links.
*/
class MultiLinkTxTest : public MultiLinkOperationsTestBase
{
public:
/**
* Constructor
*
* \param baseParams common configuration parameters
* \param trafficPattern the pattern of traffic to generate
* \param baEnabled whether BA agreement is enabled or disabled
* \param useBarAfterMissedBa whether a BAR or Data frames are sent after missed BlockAck
* \param nMaxInflight the max number of links on which an MPDU can be simultaneously inflight
* (unused if Block Ack agreements are not established)
*/
MultiLinkTxTest(const BaseParams& baseParams,
WifiTrafficPattern trafficPattern,
WifiBaEnabled baEnabled,
WifiUseBarAfterMissedBa useBarAfterMissedBa,
uint8_t nMaxInflight);
~MultiLinkTxTest() override = default;
protected:
/**
* Check the content of a received BlockAck frame when the max number of links on which
* an MPDU can be inflight is one.
*
* \param psdu the PSDU containing the BlockAck
* \param txVector the TXVECTOR used to transmit the BlockAck
* \param linkId the ID of the link on which the BlockAck was transmitted
*/
void CheckBlockAck(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, uint8_t linkId);
void Transmit(Ptr<WifiMac> mac,
uint8_t phyId,
WifiConstPsduMap psduMap,
WifiTxVector txVector,
double txPowerW) override;
void DoSetup() override;
void DoRun() override;
private:
void StartTraffic() override;
/// Receiver address-indexed map of list error models
using RxErrorModelMap = std::unordered_map<Mac48Address, Ptr<ListErrorModel>, WifiAddressHash>;
RxErrorModelMap m_errorModels; ///< error rate models 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
WifiTrafficPattern m_trafficPattern; ///< the pattern of traffic to generate
bool m_baEnabled; ///< whether BA agreement is enabled or disabled
bool m_useBarAfterMissedBa; ///< whether to send BAR after missed BlockAck
std::size_t m_nMaxInflight; ///< max number of links on which an MPDU can be inflight
std::size_t m_nPackets; ///< number of application packets to generate
std::size_t m_blockAckCount{0}; ///< transmitted BlockAck counter
std::size_t m_blockAckReqCount{0}; ///< transmitted BlockAckReq counter
std::map<uint16_t, std::size_t> m_inflightCount; ///< seqNo-indexed max number of simultaneous
///< transmissions of a data frame
Ptr<WifiMac> m_sourceMac; ///< MAC of the node sending application packets
};
/**
* Tested MU traffic patterns.
*/
enum class WifiMuTrafficPattern : uint8_t
{
DL_MU_BAR_BA_SEQUENCE = 0,
DL_MU_MU_BAR,
DL_MU_AGGR_MU_BAR,
UL_MU
};
/**
* \ingroup wifi-test
* \ingroup tests
*
* \brief Test data transmission between MLDs using OFDMA MU transmissions
*
* 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
* DL MU and UL MU frames. In the DL MU scenarios, the client applications installed on the
* AP generate 8 packets addressed to each of the stations (plus 3 packets to trigger the
* establishment of BlockAck agreements). In the UL MU scenario, client applications
* installed on the stations generate 4 packets each (plus 3 packets to trigger the
* establishment of BlockAck agreements).
*
* The maximum A-MSDU size is set such that two packets can be aggregated in an A-MSDU.
* The MPDU with sequence number equal to 3 is corrupted (by using a post reception error
* model) once and for a single station, to test its successful re-transmission.
*
* Also, we enable the concurrent transmission of data frames over two links and check that at
* least one MPDU is concurrently transmitted over two links.
*/
class MultiLinkMuTxTest : public MultiLinkOperationsTestBase
{
public:
/**
* Constructor
*
* \param baseParams common configuration parameters
* \param muTrafficPattern the pattern of traffic to generate
* \param useBarAfterMissedBa whether a BAR or Data frames are sent after missed BlockAck
* \param nMaxInflight the max number of links on which an MPDU can be simultaneously inflight
* (unused if Block Ack agreements are not established)
*/
MultiLinkMuTxTest(const BaseParams& baseParams,
WifiMuTrafficPattern muTrafficPattern,
WifiUseBarAfterMissedBa useBarAfterMissedBa,
uint8_t nMaxInflight);
~MultiLinkMuTxTest() override = default;
protected:
/**
* Check the content of a received BlockAck frame when the max number of links on which
* an MPDU can be inflight is one.
*
* \param psdu the PSDU containing the BlockAck
* \param txVector the TXVECTOR used to transmit the BlockAck
* \param linkId the ID of the link on which the BlockAck was transmitted
*/
void CheckBlockAck(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, uint8_t linkId);
void Transmit(Ptr<WifiMac> mac,
uint8_t phyId,
WifiConstPsduMap psduMap,
WifiTxVector txVector,
double txPowerW) override;
void DoSetup() override;
void DoRun() override;
private:
void StartTraffic() override;
/// Receiver address-indexed map of list error models
using RxErrorModelMap = std::unordered_map<Mac48Address, Ptr<ListErrorModel>, WifiAddressHash>;
/// A pair of a MAC address (the address of the receiver for DL frames and the address of
/// the sender for UL frames) and a sequence number identifying a transmitted QoS data frame
using AddrSeqNoPair = std::pair<Mac48Address, uint16_t>;
RxErrorModelMap m_errorModels; ///< error rate models to corrupt packets
std::list<uint64_t> m_uidList; ///< list of UIDs of packets to corrupt
std::optional<Mac48Address> m_dataCorruptedSta; ///< MAC address of the station that received
///< MPDU with SeqNo=2 corrupted
bool m_waitFirstTf{true}; ///< whether we are waiting for the first Basic Trigger Frame
WifiMuTrafficPattern m_muTrafficPattern; ///< the pattern of traffic to generate
bool m_useBarAfterMissedBa; ///< whether to send BAR after missed BlockAck
std::size_t m_nMaxInflight; ///< max number of links on which an MPDU can be inflight
std::vector<PacketSocketAddress> m_sockets; ///< packet socket addresses for STAs
std::size_t m_nPackets; ///< number of application packets to generate
std::size_t m_blockAckCount{0}; ///< transmitted BlockAck counter
std::size_t m_tfCount{0}; ///< transmitted Trigger Frame counter
// std::size_t m_blockAckReqCount{0}; ///< transmitted BlockAckReq counter
std::map<AddrSeqNoPair, std::size_t> m_inflightCount; ///< max number of simultaneous
///< transmissions of each data frame
Ptr<WifiMac> m_sourceMac; ///< MAC of the node sending application packets
};
/**
* \ingroup wifi-test
* \ingroup tests
*
* \brief Test release of sequence numbers upon CTS timeout in multi-link operations
*
* In this test, an AP MLD and a non-AP MLD setup 3 links. Usage of RTS/CTS protection is
* enabled for frames whose length is at least 1000 bytes. The AP MLD receives a first set
* of 4 packets from the upper layer and sends an RTS frame, which is corrupted at the
* receiver, on a first link. When the RTS frame is transmitted, the AP MLD receives another
* set of 4 packets, which are transmitted after a successful RTS/CTS exchange on a second
* link. In the meantime, a new RTS/CTS exchange is successfully carried out (on the first
* link or on the third link) to transmit the first set of 4 packets. When the transmission
* of the first set of 4 packets starts, the AP MLD receives the third set of 4 packets from
* the upper layer, which are transmitted after a successful RTS/CTS exchange.
*
* This test checks that sequence numbers are correctly assigned to all the MPDUs carrying data.
*/
class ReleaseSeqNoAfterCtsTimeoutTest : public MultiLinkOperationsTestBase
{
public:
ReleaseSeqNoAfterCtsTimeoutTest();
~ReleaseSeqNoAfterCtsTimeoutTest() override = default;
protected:
void DoSetup() override;
void DoRun() override;
void Transmit(Ptr<WifiMac> mac,
uint8_t phyId,
WifiConstPsduMap psduMap,
WifiTxVector txVector,
double txPowerW) override;
private:
void StartTraffic() override;
PacketSocketAddress m_sockAddr; //!< packet socket address
std::size_t m_nQosDataFrames; //!< counter for transmitted QoS data frames
Ptr<ListErrorModel> m_errorModel; //!< error rate model to corrupt first RTS frame
bool m_rtsCorrupted; //!< whether the first RTS frame has been corrupted
};
/**
* \ingroup wifi-test
* \ingroup tests
*
* \brief Test update of BA starting sequence number after ADDBA Response timeout in
* multi-link operations
*
* In this test, an AP MLD and a non-AP MLD setup 2 links. The AP MLD has a QoS data frame to
* transmit to the non-AP MLD, which triggers the establishment of a BA agreement. When the ADDBA
* Request frame is received by the non-AP MLD, transmissions of the non-AP MLD are blocked to put
* the transmission of the ADDBA Response on hold. The goal is to mimic a delay in getting channel
* access due to, e.g., other devices grabbing the medium. When the ADDBA Response timer at the AP
* MLD expires, transmissions of the non-AP MLD are unblocked, so that the AP MLD sends the QoS data
* frame (protected by RTS, but the test works without RTS as well, and using Normal acknowledgment)
* on one link and the non-AP MLD sends the ADDBA Response on the other link. The transmission of
* the QoS data frame is then corrupted. We verify that:
*
* - when the AP MLD receives the ADDBA Response, the BA starting sequence number is set to the
* sequence number of the QoS data frame which is inflight
* - the QoS data frame is retransmitted and received by the non-AP MLD
*/
class StartSeqNoUpdateAfterAddBaTimeoutTest : public MultiLinkOperationsTestBase
{
public:
StartSeqNoUpdateAfterAddBaTimeoutTest();
private:
void DoSetup() override;
void DoRun() override;
void Transmit(Ptr<WifiMac> mac,
uint8_t phyId,
WifiConstPsduMap psduMap,
WifiTxVector txVector,
double txPowerW) override;
void StartTraffic() override;
PacketSocketAddress m_sockAddr; //!< packet socket address
std::size_t m_nQosDataCount; //!< counter for transmitted QoS data frames
Ptr<ListErrorModel> m_staErrorModel; //!< error rate model to corrupt frames at the non-AP MLD
};
/**
* \ingroup wifi-test
* \ingroup tests
*
* \brief wifi 11be MLD Test Suite
*/
class WifiMultiLinkOperationsTestSuite : public TestSuite
{
public:
WifiMultiLinkOperationsTestSuite();
};
#endif /* WIFI_MLO_TEST_H */