A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-tx-stats-helper-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2024 Huazhong University of Science and Technology
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Muyuan Shen <muyuan@uw.edu>
7 */
8
9#include "ns3/ap-wifi-mac.h"
10#include "ns3/boolean.h"
11#include "ns3/config.h"
12#include "ns3/eht-configuration.h"
13#include "ns3/log.h"
14#include "ns3/mobility-helper.h"
15#include "ns3/multi-model-spectrum-channel.h"
16#include "ns3/packet-socket-client.h"
17#include "ns3/packet-socket-helper.h"
18#include "ns3/packet-socket-server.h"
19#include "ns3/packet.h"
20#include "ns3/pointer.h"
21#include "ns3/qos-txop.h"
22#include "ns3/qos-utils.h"
23#include "ns3/rng-seed-manager.h"
24#include "ns3/single-model-spectrum-channel.h"
25#include "ns3/spectrum-wifi-helper.h"
26#include "ns3/string.h"
27#include "ns3/test.h"
28#include "ns3/wifi-mac-header.h"
29#include "ns3/wifi-mac.h"
30#include "ns3/wifi-net-device.h"
31#include "ns3/wifi-ppdu.h"
32#include "ns3/wifi-psdu.h"
33#include "ns3/wifi-tx-stats-helper.h"
34
35#include <vector>
36
37using namespace ns3;
38
39NS_LOG_COMPONENT_DEFINE("WifiTxStatsHelperTest");
40
41/**
42 * @ingroup wifi-test
43 * @brief Implements a test case to evaluate the transmission process of multiple Wi-Fi
44 * MAC Layer MPDUs. The testcase has two options.
45 * 1) SINGLE_LINK_NON_QOS: test the handling of regular ACKs.
46 * 2) MULTI_LINK_QOS: test the handling of MPDU aggregation, Block ACKs, and Multi-Link Operation.
47 *
48 * To observe the operation of WifiTxStatsHelper, the test can be run from the command line as
49 * follows:
50 * @code
51 * NS_LOG="WifiTxStatsHelper=level_info|prefix_all" ./ns3 run 'test-runner
52 * --suite=wifi-tx-stats-helper'
53 * @endcode
54 */
56{
57 public:
58 /**
59 * Option for the test
60 */
66
67 /**
68 * Constructor
69 * @param testName Test name
70 * @param option Test option
71 */
72 WifiTxStatsHelperTest(const std::string& testName, TestOption option);
73
74 /**
75 * Callback invoked when PHY starts transmission of a PSDU, used to record TX start
76 * time and TX duration.
77 *
78 * @param context the context
79 * @param psduMap the PSDU map
80 * @param txVector the TX vector
81 * @param txPower the tx power in Watts
82 */
83 void Transmit(std::string context,
84 WifiConstPsduMap psduMap,
85 WifiTxVector txVector,
86 Watt_u txPower);
87
88 private:
89 TestOption m_option; //!< Test option
90 NodeContainer m_wifiApNode; //!< NodeContainer for AP
91 NodeContainer m_wifiStaNodes; //!< NodeContainer for STAs
92 int64_t m_streamNumber; //!< Random variable stream number
93 Time m_sifs; //!< SIFS time
94 Time m_slot; //!< slot time
95
96 Time m_difs; //!< DIFS time (for SINGLE_LINK_NON_QOS case only)
97 std::map<uint8_t, std::vector<Time>> m_txStartTimes; //!< Map of independently obtain vector of
98 //!< PhyTxBegin trace, indexed per link
99 std::map<uint8_t, std::vector<Time>>
100 m_durations; //!< Map of vector of MPDU durations, indexed per link
101 std::map<uint8_t, uint32_t> m_cwMins; //!< Map of CW Mins, indexed per link
102 std::map<uint8_t, uint32_t>
103 m_aifsns; //!< Map of AIFSNs, indexed per link (for MULTI_LINK_QOS case only)
104 std::map<uint8_t, Time>
105 m_aifss; //!< Map of AIFSs, indexed per link (for MULTI_LINK_QOS case only)
106
107 void DoSetup() override;
108 void DoRun() override;
109 /**
110 * Check correctness of test
111 * @param wifiTxStats Reference to the helper
112 */
113 void CheckResults(const WifiTxStatsHelper& wifiTxStats);
114};
115
117 : TestCase(testName),
118 m_option(option),
119 m_streamNumber(100)
120{
121}
122
123void
125 WifiConstPsduMap psduMap,
126 WifiTxVector txVector,
127 Watt_u txPower)
128{
129 const auto linkId = atoi(context.c_str());
130 if (linkId == 0)
131 {
132 m_txStartTimes[0].push_back(Simulator::Now());
133 m_durations[0].push_back(
135 }
136 else if (linkId == 1)
137 {
138 m_txStartTimes[1].push_back(Simulator::Now());
139 m_durations[1].push_back(
141 }
142 NS_LOG_INFO("LINKID=" << +linkId << " " << *psduMap.cbegin()->second << "\n");
143}
144
145void
147{
150
153
154 MobilityHelper mobility;
155 auto positionAlloc = CreateObject<ListPositionAllocator>();
156 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
157 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
158 mobility.SetPositionAllocator(positionAlloc);
159 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
160 mobility.Install(m_wifiApNode);
161 mobility.Install(m_wifiStaNodes);
162
163 PacketSocketHelper packetSocket;
164 packetSocket.Install(m_wifiApNode);
165 packetSocket.Install(m_wifiStaNodes);
166}
167
168void
170{
171 std::string dataMode;
172 std::string ackMode;
174 {
175 dataMode = "OfdmRate12Mbps";
176 ackMode = "OfdmRate6Mbps";
177 }
178 else
179 {
180 dataMode = "EhtMcs6";
181 ackMode = "OfdmRate54Mbps";
182 }
183
184 WifiHelper wifi;
185 NetDeviceContainer staDevices;
186 NetDeviceContainer apDevices;
188 {
189 wifi.SetStandard(WIFI_STANDARD_80211a);
190 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
191 "DataMode",
192 StringValue(dataMode),
193 "ControlMode",
194 StringValue(ackMode));
195 auto spectrumChannel = CreateObject<SingleModelSpectrumChannel>();
197 spectrumChannel->AddPropagationLossModel(lossModel);
199 spectrumChannel->SetPropagationDelayModel(delayModel);
200
202 phy.SetChannel(spectrumChannel);
203
204 WifiMacHelper mac;
205 mac.SetType("ns3::StaWifiMac",
206 "QosSupported",
207 BooleanValue(false),
208 "Ssid",
209 SsidValue(Ssid("test-ssid")));
210 staDevices = wifi.Install(phy, mac, m_wifiStaNodes);
211
212 mac.SetType("ns3::ApWifiMac",
213 "QosSupported",
214 BooleanValue(false),
215 "Ssid",
216 SsidValue(Ssid("test-ssid")),
217 "BeaconInterval",
218 TimeValue(MicroSeconds(102400)),
219 "EnableBeaconJitter",
220 BooleanValue(false));
221 apDevices = wifi.Install(phy, mac, m_wifiApNode);
222 }
223 else
224 {
225 wifi.SetStandard(WIFI_STANDARD_80211be);
226 // Get channel string for MLD STA
227 std::array<std::string, 2> mldChannelStr;
228 uint32_t frequency = 5;
229 uint32_t frequency2 = 6;
230 for (auto freq : {frequency, frequency2})
231 {
232 NS_TEST_ASSERT_MSG_EQ((freq == 5 || freq == 6), true, "Unsupported frequency for BSS");
233 if (freq == 6)
234 {
235 mldChannelStr[1] = "{0, 20, BAND_6GHZ, 0}";
236 wifi.SetRemoteStationManager(static_cast<uint8_t>(1),
237 "ns3::ConstantRateWifiManager",
238 "DataMode",
239 StringValue(dataMode),
240 "ControlMode",
241 StringValue(ackMode));
242 }
243 else
244 {
245 mldChannelStr[0] = "{0, 20, BAND_5GHZ, 0}";
246 wifi.SetRemoteStationManager(static_cast<uint8_t>(0),
247 "ns3::ConstantRateWifiManager",
248 "DataMode",
249 StringValue(dataMode),
250 "ControlMode",
251 StringValue(ackMode));
252 }
253 }
254
256
258 auto spectrumChannel1 = CreateObject<MultiModelSpectrumChannel>();
259 spectrumChannel1->AddPropagationLossModel(lossModel);
260 auto spectrumChannel2 = CreateObject<MultiModelSpectrumChannel>();
261 spectrumChannel2->AddPropagationLossModel(lossModel);
262
263 phy.AddChannel(spectrumChannel1, WIFI_SPECTRUM_5_GHZ);
264 phy.AddChannel(spectrumChannel2, WIFI_SPECTRUM_6_GHZ);
265
266 for (uint8_t linkId = 0; linkId < 2; ++linkId)
267 {
268 phy.Set(linkId, "ChannelSettings", StringValue(mldChannelStr[linkId]));
269 }
270
271 WifiMacHelper mac;
272 mac.SetType("ns3::StaWifiMac",
273 "QosSupported",
274 BooleanValue(true),
275 "Ssid",
276 SsidValue(Ssid("test-ssid")));
277 staDevices = wifi.Install(phy, mac, m_wifiStaNodes);
278
279 mac.SetType("ns3::ApWifiMac",
280 "QosSupported",
281 BooleanValue(true),
282 "Ssid",
283 SsidValue(Ssid("test-ssid")),
284 "BeaconInterval",
285 TimeValue(MicroSeconds(102400)),
286 "EnableBeaconJitter",
287 BooleanValue(false));
288 apDevices = wifi.Install(phy, mac, m_wifiApNode);
289 }
290
291 m_sifs = DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetPhy()->GetSifs();
292 m_slot = DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetPhy()->GetSlot();
294 {
295 m_difs = m_sifs + 2 * m_slot;
297 DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetMac()->GetTxop()->GetMinCw();
298 }
299 else
300 {
301 // Use TID-to-link Mapping to tx TID=3 pkts (BE) only on link 0,
302 // TID=4 pkts (VI) only on link 1
303 m_cwMins[0] = 15;
304 m_cwMins[1] = 7;
305 m_aifsns[0] = 3;
306 m_aifsns[1] = 2;
307 m_aifss[0] = m_aifsns[0] * m_slot + m_sifs;
308 m_aifss[1] = m_aifsns[1] * m_slot + m_sifs;
309 std::string mldMappingStr = "3 0; 4 1";
310 DynamicCast<WifiNetDevice>(staDevices.Get(0))
311 ->GetMac()
312 ->GetEhtConfiguration()
313 ->SetAttribute("TidToLinkMappingUl", StringValue(mldMappingStr));
314 }
315
316 auto streamsUsed = WifiHelper::AssignStreams(apDevices, m_streamNumber);
317 NS_ASSERT_MSG(streamsUsed < 100, "Need to increment by larger quantity");
318 WifiHelper::AssignStreams(staDevices, m_streamNumber + 100);
319
320 // UL traffic (TX statistics will be installed at STA side)
321 PacketSocketAddress socket;
322 socket.SetSingleDevice(staDevices.Get(0)->GetIfIndex());
323 socket.SetPhysicalAddress(apDevices.Get(0)->GetAddress());
324 auto server = CreateObject<PacketSocketServer>();
325 server->SetLocal(socket);
326 m_wifiApNode.Get(0)->AddApplication(server);
327 server->SetStartTime(Seconds(0.0));
328 server->SetStopTime(Seconds(1.0));
330 {
331 auto client = CreateObject<PacketSocketClient>();
332 client->SetAttribute("PacketSize", UintegerValue(1500));
333 client->SetAttribute("MaxPackets", UintegerValue(3));
334 client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
335 client->SetRemote(socket);
337 client->SetStartTime(MicroSeconds(210000));
338 client->SetStopTime(Seconds(1.0));
339 }
340 else
341 {
342 auto clientBe = CreateObject<PacketSocketClient>();
343 clientBe->SetAttribute("Priority", UintegerValue(3));
344 clientBe->SetAttribute("PacketSize", UintegerValue(1500));
345 clientBe->SetAttribute("MaxPackets", UintegerValue(3));
346 clientBe->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
347 clientBe->SetRemote(socket);
348 m_wifiStaNodes.Get(0)->AddApplication(clientBe);
349 clientBe->SetStartTime(MicroSeconds(200000));
350 clientBe->SetStopTime(Seconds(1.0));
351
352 auto clientVi = CreateObject<PacketSocketClient>();
353 clientVi->SetAttribute("Priority", UintegerValue(4));
354 clientVi->SetAttribute("PacketSize", UintegerValue(1500));
355 clientVi->SetAttribute("MaxPackets", UintegerValue(3));
356 clientVi->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
357 clientVi->SetRemote(socket);
358 m_wifiStaNodes.Get(0)->AddApplication(clientVi);
359 clientVi->SetStartTime(MicroSeconds(300000));
360 clientVi->SetStopTime(Seconds(1.0));
361 }
362
363 // Add AP side receiver corruption
365 {
366 // We corrupt AP side reception so that:
367 // 1) the 2nd data frame is retransmitted and succeeds (1 failure, 1 success)
368 // 2) the 3rd data frame is transmitted 7 times (=FrameRetryLimit) and finally fails (7
369 // failures, 0 success)
370 //
371 // No. of pkt | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
372 // No. recvd by AP | | | 0 | | | 1 | | 2 | | AP's
373 // pkts | Bea | Bea | | Ack | AsRes | | Bea | | Ack1 |
374 // STA's pkts | | | AsReq | | | Ack | | Data1 | |
375 //
376 // No. of pkt | 9 | 10 | 11 | 12 | 13 | ... | 18 | 19 | ...
377 // No. recvd by AP | 3 (x) | 4 | | 5 (x) | 6 (x) | ... |11 (x) | | ...
378 // AP's pkts | | | Ack2 | | | ... | | Bea | ...
379 // STA's pkts | Data2 | Data2 | | Data3 | Data3 | ... | Data3 | | ...
380 //
381 // Legend:
382 // Bea = Beacon, AsReq = Association Request, AsRes = Association Response
383 // AP side corruption is indicated with (x)
384
386 apPem->SetList({3, 5, 6, 7, 8, 9, 10, 11});
387 DynamicCast<WifiNetDevice>(apDevices.Get(0))
388 ->GetMac()
389 ->GetWifiPhy()
390 ->SetPostReceptionErrorModel(apPem);
391 }
392 else
393 {
394 // We corrupt AP side reception so that:
395 // On Link 0 (contains uplink data with TID = 3):
396 // 1) the 2nd data frame is retransmitted once and succeeds (retransmission = 1)
397 // 2) the 3rd data frame is transmitted 2 times within A-MPDU and 7 times alone
398 // (WifiMac::FrameRetryLimit) and finally fails (retransmission = 8)
399 //
400 // No. of PSDU | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
401 // No. recvd by AP | | | 0 | | 1 | | 2 | | 3 |
402 // AP's pkts | Bea | Bea | | Ack | | AsRes | | CfEnd | |
403 // STA's pkts | | | AsReq | | CfEnd | | Ack | | ABReq
404 // |
405 //
406 // No. of PSDU | 9 | 10 | 11 | 12 | 12 | 12 | 13 | 14 | 14 |
407 // No. recvd by AP | | | 4 | 5 | 6(x) | 7(x) | | 8 | 9(x) |
408 // AP's pkts | Ack | ABRes | | | | | BAck | | |
409 // STA's pkts | | | Ack | Data1 | Data2 | Data3 | | Data2 | Data3
410 // |
411 //
412 // No. of PSDU | 15 | 16 | ... | | ... | 23 | 24 | 25 | ...
413 // No. recvd by AP | | 10(x) | ... | | ... | 16(x) | 17 | | ...
414 // AP's pkts | BAck | | ... | Bea | ... | | | BAck | ...
415 // STA's pkts | | Data3 | ... | | ... | Data3 | Bar | | ...
416 //
417 // On Link 1 (contains uplink data with TID = 4):
418 // 1) the 2nd data frame is transmitted 2 times within A-MPDU and 7 times alone
419 // (=WifiMac::FrameRetryLimit) and finally fails (retransmission = 8)
420 // 2) the 3rd data frame is
421 // retransmitted once and succeeds (retransmission = 1)
422 //
423 // No. of PSDU | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
424 // No. recvd by AP | | | 0 | | | 1 | | 2 | | AP's
425 // pkts | Bea | Bea | | Ack | Bea | | Ack | | ABRes |
426 // STA's pkts | | | Null | | | ABReq | | CfEnd | |
427 //
428 // No. of PSDU | 9 | 10 | 11 | 11 | 11 | 12 | 13 | 13 | 14 |
429 // No. recvd by AP | 3 | | 4 | 5(x) | 6(x) | | 7(x) | 8 | | AP's
430 // pkts | | CfEnd | | | | BAck | | | BAck |
431 // STA's pkts | Ack | | Data1 | Data2 | Data3 | | Data2 | Data3 | |
432 //
433 // No. of PSDU | 15 | ... | 21 | 22 | 23 | 24 | ...
434 // No. recvd by AP | 9(x) | ... | 15(x) | 16 | | 17 | ...
435 // AP's pkts | | ... | | | BAck | | ...
436 // STA's pkts | Data2 | ... | Data2 | Bar | | CfEnd | ...
437 //
438 // Legend:
439 // Bea = Beacon, AsReq = Association Request, AsRes = Association Response
440 // ABReq = Add Block ACK Request, ABRes = Add Block ACK Response
441 // Bar = Block ACK Request (used to notify the discarded MPDU)
442 // CfEnd = CF-End, BAck = Block ACK (Response), Null = Null function
443 // AP side corruption is indicated with (x)
444
445 // Force drops on link 0 at AP
447 apPem0->SetList({6, 7, 9, 10, 11, 12, 13, 14, 15, 16});
448 DynamicCast<WifiNetDevice>(apDevices.Get(0))
449 ->GetMac()
450 ->GetWifiPhy(0)
451 ->SetPostReceptionErrorModel(apPem0);
452
453 // Force drops on link 1 at AP
455 apPem1->SetList({5, 6, 7, 9, 10, 11, 12, 13, 14, 15});
456 DynamicCast<WifiNetDevice>(apDevices.Get(0))
457 ->GetMac()
458 ->GetWifiPhy(1)
459 ->SetPostReceptionErrorModel(apPem1);
460 }
461
462 NetDeviceContainer allNetDev;
463 allNetDev.Add(apDevices);
464 allNetDev.Add(staDevices);
465 WifiTxStatsHelper wifiTxStats;
466 wifiTxStats.Enable(allNetDev);
467 wifiTxStats.Start(Seconds(0));
468 wifiTxStats.Stop(Seconds(1));
469
470 // Trace PSDU TX at both AP and STA to get start times and durations, including acks
472 {
473 for (auto it = allNetDev.Begin(); it != allNetDev.End(); ++it)
474 {
475 auto dev = DynamicCast<WifiNetDevice>(*it);
476 dev->GetPhy()->TraceConnect("PhyTxPsduBegin",
477 std::to_string(SINGLE_LINK_OP_ID),
478 // "0"
480 }
481 }
482 else
483 {
484 for (auto it = allNetDev.Begin(); it != allNetDev.End(); ++it)
485 {
486 auto dev = DynamicCast<WifiNetDevice>(*it);
487 dev->GetPhy(0)->TraceConnect("PhyTxPsduBegin",
488 "0",
490 dev->GetPhy(1)->TraceConnect("PhyTxPsduBegin",
491 "1",
493 }
494 }
495
498 CheckResults(wifiTxStats);
500}
501
502void
504{
505 const auto tolerance = NanoSeconds(50); // due to propagation delay
506 // Check both variants of GetSuccesses...()
507 const auto successMap = wifiTxStats.GetSuccessesByNodeDevice();
508 const auto successMapPerNodeDeviceLink = wifiTxStats.GetSuccessesByNodeDeviceLink();
509 const auto failureMap = wifiTxStats.GetFailuresByNodeDevice();
510 const auto retransmissionMap = wifiTxStats.GetRetransmissionsByNodeDevice();
511 const auto totalSuccesses = wifiTxStats.GetSuccesses();
512 const auto totalFailures = wifiTxStats.GetFailures();
513 const auto totalRetransmissions = wifiTxStats.GetRetransmissions();
514 const auto& successRecords = wifiTxStats.GetSuccessRecords();
515 const auto& failureRecords = wifiTxStats.GetFailureRecords();
516
517 uint32_t nodeId = 1;
518 uint32_t deviceId = 0;
519 auto nodeDeviceTuple = std::make_tuple(nodeId, deviceId);
520 auto nodeDeviceLink0Tuple = std::make_tuple(nodeId, deviceId, 0);
521 auto nodeDeviceLink1Tuple = std::make_tuple(nodeId, deviceId, 1);
522
524 {
525 const auto totalFailuresDrop =
526 wifiTxStats.GetFailures(WifiMacDropReason::WIFI_MAC_DROP_REACHED_RETRY_LIMIT);
527 const auto totalFailuresDropMap = wifiTxStats.GetFailuresByNodeDevice(
528 WifiMacDropReason::WIFI_MAC_DROP_REACHED_RETRY_LIMIT);
529
530 NS_TEST_ASSERT_MSG_EQ(successMapPerNodeDeviceLink.at(nodeDeviceLink0Tuple),
531 2,
532 "Number of success packets should be 2");
533 NS_TEST_ASSERT_MSG_EQ(successMap.at(nodeDeviceTuple),
534 2,
535 "Number of success packets should be 2");
536 NS_TEST_ASSERT_MSG_EQ(totalSuccesses, 2, "Number of success packets should be 2");
537
538 NS_TEST_ASSERT_MSG_EQ(retransmissionMap.at(nodeDeviceTuple),
539 1,
540 "Number of retransmitted successful packets should be 1");
541 NS_TEST_ASSERT_MSG_EQ(totalRetransmissions,
542 1,
543 "Number of retransmitted successful packets should be 1");
544
545 NS_TEST_ASSERT_MSG_EQ(failureMap.at(nodeDeviceTuple),
546 1,
547 "Number of failed packets should be 1");
548 NS_TEST_ASSERT_MSG_EQ(totalFailures, 1, "Number of failed packets (aggregate) should be 1");
550 totalFailuresDrop,
551 1,
552 "Number of dropped packets (aggregate) due to retry limit reached should be 1");
554 totalFailuresDropMap.at(nodeDeviceTuple),
555 1,
556 "Number of dropped packets (aggregate) due to retry limit reached should be 1");
557
558 auto successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
559 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_nodeId,
560 1,
561 "Source node ID of the 1st successful data packet should be 1");
562 std::advance(successRecordIt, 1);
563 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_nodeId,
564 1,
565 "Source node ID of the 2nd successful data packet should be 1");
566 auto failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
567 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_nodeId,
568 1,
569 "Source node ID of the failed data packet should be 1");
570
571 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
573 successRecordIt->m_retransmissions,
574 0,
575 "The retransmission count of the 1st successful data packet should be 0");
576 std::advance(successRecordIt, 1);
578 successRecordIt->m_retransmissions,
579 1,
580 "The retransmission count of the 2nd successful data packet should be 1");
581 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_retransmissions,
582 6,
583 "The retransmission count of the failed data packet should be 6");
584
585 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
586 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime.IsStrictlyPositive(),
587 true,
588 "The 1st successful data packet should have been TXed");
589 std::advance(successRecordIt, 1);
590 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime.IsStrictlyPositive(),
591 true,
592 "The 2nd successful data packet should have been TXed");
593 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime.IsStrictlyPositive(),
594 true,
595 "The failed data packet should have been TXed");
596
597 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
598 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
599 true,
600 "The 1st successful data packet should have been acked");
601 std::advance(successRecordIt, 1);
602 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
603 true,
604 "The 2nd successful data packet should have been acked");
605 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_ackTime.IsStrictlyPositive(),
606 false,
607 "The failed data packet should not have been acked");
608
609 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
610 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
611 true,
612 "The 1st successful data packet should have been dequeued");
613 std::advance(successRecordIt, 1);
614 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
615 true,
616 "The 2nd successful data packet should have been dequeued");
617 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
618 failureRecordIt->m_dropTime.value().IsStrictlyPositive(),
619 true,
620 "The failed data packet should have been dequeued");
621
622 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
623 auto successRecordItNext = successRecordIt;
624 std::advance(successRecordItNext, 1);
625 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_enqueueTime,
626 successRecordItNext->m_enqueueTime,
627 "Three packets should be enqueued at the same time");
628 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_enqueueTime,
629 failureRecordIt->m_enqueueTime,
630 "Three packets should be enqueued at the same time");
631
632 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
633 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordIt->m_txStartTime,
634 successRecordIt->m_enqueueTime,
635 "Packets should be TXed after enqueued");
636 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordIt->m_txStartTime,
637 successRecordIt->m_enqueueTime + tolerance +
639 "Packet backoff slots should not exceed cwMin");
640 // Packet start time 7 corresponds to first data packet (prior to this, beacons and assoc)
641 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime,
643 "Wrong TX start time");
644 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordIt->m_ackTime,
648 "Wrong Ack reception time");
649 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordIt->m_ackTime,
652 m_durations[SINGLE_LINK_OP_ID][8] + 2 * tolerance,
653 "Wrong Ack reception time");
654 std::advance(successRecordIt, 1);
655 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordIt->m_txStartTime,
658 "Packets should be TXed after enqueued");
659 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordIt->m_txStartTime,
661 m_durations[SINGLE_LINK_OP_ID][8] + m_difs + tolerance +
663 "Packet backoff slots should not exceed cwMin");
664 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime,
666 "Wrong TX start time");
667 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordIt->m_ackTime,
671 "Wrong Ack reception time");
673 successRecordIt->m_ackTime,
676 ((m_cwMins[SINGLE_LINK_OP_ID] + 1) * 2 - 1) * m_slot + 2 * tolerance,
677 "Wrong Ack reception time");
678
679 NS_TEST_ASSERT_MSG_GT_OR_EQ(failureRecordIt->m_txStartTime,
682 "Packets should be TXed after enqueued");
683 NS_TEST_ASSERT_MSG_LT_OR_EQ(failureRecordIt->m_txStartTime,
685 m_durations[SINGLE_LINK_OP_ID][11] + m_difs + tolerance +
687 "Packet backoff slots should not exceed cwMin");
688 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime,
690 "Wrong TX start time");
691 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
692 failureRecordIt->m_dropReason.has_value(),
693 true,
694 "Missing drop time or reason");
695 NS_TEST_ASSERT_MSG_GT_OR_EQ(failureRecordIt->m_dropTime.value(),
698 "Wrong Dequeue time for failed packet");
699 NS_TEST_ASSERT_MSG_LT_OR_EQ(failureRecordIt->m_dropTime.value(),
703 "Wrong Dequeue time for failed packet");
704 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropReason.value(),
705 WifiMacDropReason::WIFI_MAC_DROP_REACHED_RETRY_LIMIT,
706 "Wrong drop reason");
707 }
708 else
709 {
710 const auto totalFailuresQos =
711 wifiTxStats.GetFailures(WifiMacDropReason::WIFI_MAC_DROP_QOS_OLD_PACKET);
712 const auto totalFailuresQosMap =
713 wifiTxStats.GetFailuresByNodeDevice(WifiMacDropReason::WIFI_MAC_DROP_QOS_OLD_PACKET);
714
715 for (std::vector<Time>::size_type i = 0; i < m_txStartTimes[0].size(); ++i)
716 {
717 NS_LOG_INFO("link 0 pkt " << i << " start tx at " << m_txStartTimes[0][i].As(Time::US));
718 }
719 for (std::vector<Time>::size_type i = 0; i < m_txStartTimes[1].size(); ++i)
720 {
721 NS_LOG_INFO("link 1 pkt " << i << " start tx at " << m_txStartTimes[1][i].As(Time::US));
722 }
723
724 NS_TEST_ASSERT_MSG_EQ(successMapPerNodeDeviceLink.at(nodeDeviceLink0Tuple),
725 2,
726 "Number of success packets on link 0 should be 2");
727 NS_TEST_ASSERT_MSG_EQ(successMapPerNodeDeviceLink.at(nodeDeviceLink1Tuple),
728 2,
729 "Number of success packets on link 1 should be 2");
730 NS_TEST_ASSERT_MSG_EQ(successMap.at(nodeDeviceTuple),
731 4,
732 "Number of success packets should be 4");
733 NS_TEST_ASSERT_MSG_EQ(totalSuccesses, 4, "Number of success packets should be 4");
734
735 NS_TEST_ASSERT_MSG_EQ(retransmissionMap.at(nodeDeviceTuple),
736 2,
737 "Number of retransmitted successful packets should be 2");
738 NS_TEST_ASSERT_MSG_EQ(totalRetransmissions,
739 2,
740 "Number of retransmitted successful packets (aggregate) should be 2");
741 NS_TEST_ASSERT_MSG_EQ(failureMap.at(nodeDeviceTuple),
742 2,
743 "Number of failed packets should be 2");
744 NS_TEST_ASSERT_MSG_EQ(totalFailures, 2, "Number of failed packets (aggregate) should be 2");
745 NS_TEST_ASSERT_MSG_EQ(totalFailuresQos,
746 2,
747 "Number of dropped packets (aggregate) by QosTxop should be 2");
748 NS_TEST_ASSERT_MSG_EQ(totalFailuresQosMap.at(nodeDeviceTuple),
749 2,
750 "Number of dropped packets (aggregate) by QosTxop should be 2");
751
752 auto successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
754 successRecordLink0It->m_nodeId,
755 1,
756 "Source node ID of the 1st successful data packet on link 0 should be 1");
757 std::advance(successRecordLink0It, 1);
759 successRecordLink0It->m_nodeId,
760 1,
761 "Source node ID of the 2nd successful data packet on link 0 should be 1");
762 auto successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
764 successRecordLink1It->m_nodeId,
765 1,
766 "Source node ID of the 1st successful data packet on link 0 should be 1");
767 std::advance(successRecordLink1It, 1);
769 successRecordLink1It->m_nodeId,
770 1,
771 "Source node ID of the 2nd successful data packet on link 0 should be 1");
772 auto failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
773 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_nodeId,
774 1,
775 "Source node ID of the failed data packet on link 0 should be 1");
776 std::advance(failureRecordIt, 1);
777 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_nodeId,
778 1,
779 "Source node ID of the failed data packet on link 1 should be 1");
780
781 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
782 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_deviceId,
783 0,
784 "Device ID of the 1st successful data packet on link 0 should be 0");
785 std::advance(successRecordLink0It, 1);
786 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_deviceId,
787 0,
788 "Device ID of the 2nd successful data packet on link 0 should be 0");
789 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
790 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_deviceId,
791 0,
792 "Device ID of the 1st successful data packet on link 0 should be 0");
793 std::advance(successRecordLink1It, 1);
794 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_deviceId,
795 0,
796 "Device ID of the 2nd successful data packet on link 1 should be 0");
797 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
798 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_deviceId,
799 0,
800 "Device ID of the failed data packet on link 1 should be 0");
801 std::advance(failureRecordIt, 1);
802 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_deviceId,
803 0,
804 "Device ID of the failed data packet on link 1 should be 0");
805
806 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
808 *successRecordLink0It->m_successLinkIdSet.begin(),
809 0,
810 "Successful link ID of the 1st successful data packet on link 0 should be 0");
811 std::advance(successRecordLink0It, 1);
813 *successRecordLink0It->m_successLinkIdSet.begin(),
814 0,
815 "Successful link ID of the 2nd successful data packet on link 0 should be 0");
816 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
818 *successRecordLink1It->m_successLinkIdSet.begin(),
819 1,
820 "Successful link ID of the 1st successful data packet on link 1 should be 1");
821 std::advance(successRecordLink1It, 1);
823 *successRecordLink1It->m_successLinkIdSet.begin(),
824 1,
825 "Successful link ID of the 2nd successful data packet on link 1 should be 1");
826 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
828 failureRecordIt->m_successLinkIdSet.empty(),
829 true,
830 "Successful link ID set of the failed data packet on link 0 should be empty");
831 std::advance(failureRecordIt, 1);
833 failureRecordIt->m_successLinkIdSet.empty(),
834 true,
835 "Successful link ID set of the failed data packet on link 1 should be empty");
836
837 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
839 successRecordLink0It->m_retransmissions,
840 0,
841 "The 1st successful data packet on link 0 should have no retransmissions");
842 std::advance(successRecordLink0It, 1);
844 successRecordLink0It->m_retransmissions,
845 1,
846 "The 2nd successful data packet on link 0 should have 1 retransmission");
847 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
849 successRecordLink1It->m_retransmissions,
850 0,
851 "The 1st successful data packet on link 1 should have no retransmissions");
852 std::advance(successRecordLink1It, 1);
854 successRecordLink1It->m_retransmissions,
855 1,
856 "The 2nd successful data packet on link 1 should have 1 retransmission");
857 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
858 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_retransmissions,
859 8,
860 "The failed data packet on link 0 should have 8 retransmissions");
861 std::advance(failureRecordIt, 1);
862 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_retransmissions,
863 8,
864 "The failed data packet on link 1 should have 8 retransmissions");
865
866 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
867 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_tid,
868 3,
869 "The 1st successful data packet on link 0 should have a TID of 3");
870 std::advance(successRecordLink0It, 1);
871 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_tid,
872 3,
873 "The 2nd successful data packet on link 0 should have a TID of 3");
874 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
875 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_tid,
876 4,
877 "The 1st successful data packet on link 1 should have a TID of 4");
878 std::advance(successRecordLink1It, 1);
879 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_tid,
880 4,
881 "The 2nd successful data packet on link 1 should have a TID of 4");
882 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
883 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_tid,
884 3,
885 "The failed data packet on link 0 should have a TID of 3");
886 std::advance(failureRecordIt, 1);
887 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_tid,
888 4,
889 "The failed data packet on link 1 should have a TID of 4");
890
891 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
893 successRecordLink0It->m_mpduSeqNum,
894 0,
895 "The 1st successful data packet on link 0 should have a Seq Num of 0");
896 std::advance(successRecordLink0It, 1);
898 successRecordLink0It->m_mpduSeqNum,
899 1,
900 "The 2nd successful data packet on link 0 should have a Seq Num of 1");
901 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
903 successRecordLink1It->m_mpduSeqNum,
904 0,
905 "The 1st successful data packet on link 1 should have a Seq Num of 0");
906 std::advance(successRecordLink1It, 1);
908 successRecordLink1It->m_mpduSeqNum,
909 2,
910 "The 2nd successful data packet on link 1 should have a Seq Num of 2");
911 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
912 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_mpduSeqNum,
913 2,
914 "The failed data packet on link 0 should have a Seq Num of 2");
915 std::advance(failureRecordIt, 1);
916 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_mpduSeqNum,
917 1,
918 "The failed data packet on link 1 should have a Seq Num of 1");
919
920 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
921 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime.IsStrictlyPositive(),
922 true,
923 "The 1st successful data packet on link 0 should have been TXed");
924 std::advance(successRecordLink0It, 1);
925 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime.IsStrictlyPositive(),
926 true,
927 "The 2nd successful data packet on link 0 should have been TXed");
928 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
929 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime.IsStrictlyPositive(),
930 true,
931 "The 1st successful data packet on link 1 should have been TXed");
932 std::advance(successRecordLink1It, 1);
933 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime.IsStrictlyPositive(),
934 true,
935 "The 2nd successful data packet on link 1 should have been TXed");
936 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
937 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime.IsStrictlyPositive(),
938 true,
939 "The failed data packet on link 0 should have been TXed");
940 std::advance(failureRecordIt, 1);
941 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime.IsStrictlyPositive(),
942 true,
943 "The failed data packet on link 1 should have been TXed");
944
945 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
946 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
947 true,
948 "The 1st successful data packet on link 0 should have been acked");
949 std::advance(successRecordLink0It, 1);
950 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
951 true,
952 "The 2nd successful data packet on link 0 should have been acked");
953 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
954 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
955 true,
956 "The 1st successful data packet on link 1 should have been acked");
957 std::advance(successRecordLink1It, 1);
958 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
959 true,
960 "The 2nd successful data packet on link 1 should have been acked");
961 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
962 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_ackTime.IsStrictlyPositive(),
963 false,
964 "The failed data packet on link 0 should not have been acked");
965 std::advance(failureRecordIt, 1);
966 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_ackTime.IsStrictlyPositive(),
967 false,
968 "The failed data packet on link 1 should not have been acked");
969
970 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
971 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
972 true,
973 "The 1st successful data packet on link 0 should have been dequeued");
974 std::advance(successRecordLink0It, 1);
975 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
976 true,
977 "The 2nd successful data packet on link 0 should have been dequeued");
978 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
979 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
980 true,
981 "The 1st successful data packet on link 1 should have been dequeued");
982 std::advance(successRecordLink1It, 1);
983 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
984 true,
985 "The 2nd successful data packet on link 1 should have been dequeued");
986 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
987 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
988 failureRecordIt->m_dropReason.has_value(),
989 true,
990 "Missing drop time or reason");
991 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.value().IsStrictlyPositive(),
992 true,
993 "The failed data packet on link 0 should have been dequeued");
994 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropReason.value(),
995 WifiMacDropReason::WIFI_MAC_DROP_QOS_OLD_PACKET,
996 "Wrong drop reason");
997 std::advance(failureRecordIt, 1);
998 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
999 failureRecordIt->m_dropReason.has_value(),
1000 true,
1001 "Missing drop time or reason");
1002 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.value().IsStrictlyPositive(),
1003 true,
1004 "The failed data packet on link 1 should have been dequeued");
1005 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropReason.value(),
1006 WifiMacDropReason::WIFI_MAC_DROP_QOS_OLD_PACKET,
1007 "Wrong drop reason");
1008
1009 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1010 auto successRecordLink0ItNext = successRecordLink0It;
1011 std::advance(successRecordLink0ItNext, 1);
1012 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
1013 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_enqueueTime,
1014 successRecordLink0ItNext->m_enqueueTime,
1015 "Packets on link 0 should be enqueued at the same time");
1016 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_enqueueTime,
1017 failureRecordIt->m_enqueueTime,
1018 "Packets on link 0 should be enqueued at the same time");
1019 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1020 auto successRecordLink1ItNext = successRecordLink1It;
1021 std::advance(successRecordLink1ItNext, 1);
1022 std::advance(failureRecordIt, 1);
1023 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_enqueueTime,
1024 successRecordLink1ItNext->m_enqueueTime,
1025 "Packets on link 1 should be enqueued at the same time");
1026 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_enqueueTime,
1027 failureRecordIt->m_enqueueTime,
1028 "Packets on link 1 should be enqueued at the same time");
1029
1030 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1031 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_txStartTime,
1032 successRecordLink0It->m_enqueueTime,
1033 "The 1st data packet on link 0 should be TXed after enqueued");
1034 std::advance(successRecordLink0It, 1);
1035 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_txStartTime,
1036 successRecordLink0It->m_enqueueTime,
1037 "The 2nd data packet on link 0 should be TXed after enqueued");
1038 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1039 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_txStartTime,
1040 successRecordLink1It->m_enqueueTime,
1041 "The 1st data packet on link 1 should be TXed after enqueued");
1042 std::advance(successRecordLink1It, 1);
1043 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_txStartTime,
1044 successRecordLink1It->m_enqueueTime,
1045 "The 2nd data packet on link 1 should be TXed after enqueued");
1046 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
1047 NS_TEST_ASSERT_MSG_GT_OR_EQ(failureRecordIt->m_txStartTime,
1048 failureRecordIt->m_enqueueTime,
1049 "The 3rd data packet on link 0 should be TXed after enqueued");
1050 std::advance(failureRecordIt, 1);
1051 NS_TEST_ASSERT_MSG_GT_OR_EQ(failureRecordIt->m_txStartTime,
1052 failureRecordIt->m_enqueueTime,
1053 "The 3rd data packet on link 1 should be TXed after enqueued");
1054
1055 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1056 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_txStartTime,
1057 m_txStartTimes[0][11] + m_durations[0][11] + m_aifss[0],
1058 "link 0 pkt first tx should be after the 11th packet on link");
1059 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink0It->m_txStartTime,
1060 m_txStartTimes[0][11] + m_durations[0][11] + m_aifss[0] +
1061 tolerance + m_cwMins[0] * m_slot,
1062 "link 0 pkt first backoff should not exceed cwMin");
1063 successRecordLink0ItNext = successRecordLink0It;
1064 std::advance(successRecordLink0ItNext, 1);
1065 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
1066 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime,
1067 successRecordLink0ItNext->m_txStartTime,
1068 "3 pkts of link 0 should tx at the same time");
1069 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime,
1070 failureRecordIt->m_txStartTime,
1071 "3 pkts of link 0 should tx at the same time");
1072
1073 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1074 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_txStartTime,
1075 m_txStartTimes[1][10] + m_durations[1][10] + m_aifss[1],
1076 "link 1 pkt first tx should be after the 10th packet on link");
1077 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink1It->m_txStartTime,
1078 m_txStartTimes[1][10] + m_durations[1][10] + m_aifss[1] +
1079 tolerance + m_cwMins[1] * m_slot,
1080 "link 1 pkt first backoff should not exceed cwMin");
1081 successRecordLink1ItNext = successRecordLink1It;
1082 std::advance(successRecordLink1ItNext, 1);
1083 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
1084 std::advance(failureRecordIt, 1);
1085 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime,
1086 successRecordLink1ItNext->m_txStartTime,
1087 "3 pkts of link 1 should tx at the same time");
1088 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime,
1089 failureRecordIt->m_txStartTime,
1090 "3 pkts of link 1 should tx at the same time");
1091
1092 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1093 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_ackTime,
1094 m_txStartTimes[0][12] + m_durations[0][12] + m_sifs +
1095 m_durations[0][13],
1096 "Wrong first Block Ack reception time on link 0");
1097 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink0It->m_ackTime,
1098 m_txStartTimes[0][12] + m_durations[0][12] + m_sifs +
1099 m_durations[0][13] + 2 * tolerance,
1100 "Wrong first Block Ack reception time on link 0");
1101 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1102 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_ackTime,
1103 m_txStartTimes[1][11] + m_durations[1][11] + m_sifs +
1104 m_durations[1][12],
1105 "Wrong first Block Ack reception time on link 1");
1106 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink1It->m_ackTime,
1107 m_txStartTimes[1][11] + m_durations[1][11] + m_sifs +
1108 m_durations[1][12] + 2 * tolerance,
1109 "Wrong first Block Ack reception time on link 1");
1110
1111 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1112 std::advance(successRecordLink0It, 1);
1113 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_ackTime,
1114 m_txStartTimes[0][14] + m_durations[0][14] + m_sifs +
1115 m_durations[0][15],
1116 "Wrong second Block Ack reception time on link 0");
1117 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink0It->m_ackTime,
1118 m_txStartTimes[0][14] + m_durations[0][14] + m_sifs +
1119 m_durations[0][15] + 2 * tolerance,
1120 "Wrong second Block Ack reception time on link 0");
1121 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1122 std::advance(successRecordLink1It, 1);
1123 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_ackTime,
1124 m_txStartTimes[1][13] + m_durations[1][13] + m_sifs +
1125 m_durations[1][14],
1126 "Wrong second Block Ack reception time on link 1");
1127 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink1It->m_ackTime,
1128 m_txStartTimes[1][13] + m_durations[1][13] + m_sifs +
1129 m_durations[1][14] + 2 * tolerance,
1130 "Wrong second Block Ack reception time on link 1");
1131 }
1132}
1133
1134/**
1135 * @ingroup wifi-test
1136 * @ingroup tests
1137 *
1138 * @brief WifiTxStatsHelper Test Suite
1139 */
1141{
1142 public:
1144};
1145
1147 : TestSuite("wifi-tx-stats-helper", Type::UNIT)
1148{
1149 // A test case to evaluate the transmission process of multiple Wi-Fi MAC Layer MPDUs in
1150 // a single link device. This testcase uses .11a to test the handling of regular ACKs.
1151 //
1152 // This class tests the WifiTxStatsHelper output by creating three transmission cases:
1153 // 1) packet is sent successfully on the first try
1154 // 2) packet is lost on the first try but successfully transmitted on the second try
1155 // 3) packet is lost on all seven tries and a failure is logged
1156 // The MPDU losses are forced by the use of WifiPhy post-reception error model.
1157 //
1158 // This test also connects to the PHY trace PhyTxPsduBegin and records the sequence of
1159 // transmission times and packet durations observed at the PHY layer, to cross-check against
1160 // the times recorded in the WifiTxStatsHelper record (traced at the MAC layer).
1161 // The testcase also checks the various fields in this helper's output records for correctness.
1162 // AddTestCase(new WifiTxStatsHelperTest("Check single link non-QoS configuration",
1163 // WifiTxStatsHelperTest::SINGLE_LINK_NON_QOS),
1164 // TestCase::Duration::QUICK);
1165
1166 // A test case to evaluate the transmission process of multiple Wi-Fi MAC Layer MPDUs in
1167 // a multi link device. This testcase, unlike the previous, uses .11be to test the
1168 // handling of MPDU aggregation, Block ACKs, and Multi-Link Operation.
1169 //
1170 // This class tests the WifiTxStatsHelper output by creating three transmission cases:
1171 // 1) packet is sent successfully on the first try
1172 // 2) packet is lost on the first try (in an A-MPDU) but successfully transmitted on the
1173 // second try (also in an A-MPDU)
1174 // 3) packet is lost on all 9 tries (first 2 in A-MPDU, other 7 alone) and a failure is logged
1175 // The MPDU losses are forced by the use of WifiPhy post-reception error model.
1176 //
1177 // This test also connects to the PHY trace PhyTxPsduBegin and records the sequence of
1178 // transmission times and packet durations observed at the PHY layer, to cross-check against
1179 // the times recorded in the WifiTxStatsHelper record (traced at the MAC layer).
1180 // The testcase also checks the various fields in this helper's output records for correctness.
1181 AddTestCase(new WifiTxStatsHelperTest("Check multi-link QoS configuration",
1183 TestCase::Duration::QUICK);
1184}
1185
Implements a test case to evaluate the transmission process of multiple Wi-Fi MAC Layer MPDUs.
void DoRun() override
Implementation to actually run this TestCase.
void CheckResults(const WifiTxStatsHelper &wifiTxStats)
Check correctness of test.
int64_t m_streamNumber
Random variable stream number.
NodeContainer m_wifiStaNodes
NodeContainer for STAs.
std::map< uint8_t, Time > m_aifss
Map of AIFSs, indexed per link (for MULTI_LINK_QOS case only)
std::map< uint8_t, std::vector< Time > > m_durations
Map of vector of MPDU durations, indexed per link.
std::map< uint8_t, std::vector< Time > > m_txStartTimes
Map of independently obtain vector of PhyTxBegin trace, indexed per link.
WifiTxStatsHelperTest(const std::string &testName, TestOption option)
Constructor.
std::map< uint8_t, uint32_t > m_cwMins
Map of CW Mins, indexed per link.
std::map< uint8_t, uint32_t > m_aifsns
Map of AIFSNs, indexed per link (for MULTI_LINK_QOS case only)
NodeContainer m_wifiApNode
NodeContainer for AP.
Time m_difs
DIFS time (for SINGLE_LINK_NON_QOS case only)
void Transmit(std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, Watt_u txPower)
Callback invoked when PHY starts transmission of a PSDU, used to record TX start time and TX duration...
TestOption m_option
Test option.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
WifiTxStatsHelper Test Suite.
AttributeValue implementation for Boolean.
Definition boolean.h:26
Helper class used to assign positions and mobility models to nodes.
holds a vector of ns3::NetDevice pointers
Iterator Begin() const
Get an iterator which refers to the first NetDevice in the container.
void Add(NetDeviceContainer other)
Append the contents of another NetDeviceContainer to the end of this container.
Iterator End() const
Get an iterator which indicates past-the-last NetDevice in the container.
keep track of a set of node pointers.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
uint32_t AddApplication(Ptr< Application > application)
Associate an Application to this Node.
Definition node.cc:153
an address for a packet socket
void SetPhysicalAddress(const Address address)
Set the destination address.
void SetSingleDevice(uint32_t device)
Set the address to match only a specified NetDevice.
Give ns3::PacketSocket powers to ns3::Node.
void Install(Ptr< Node > node) const
Aggregate an instance of a ns3::PacketSocketFactory onto the provided node.
static void SetRun(uint64_t run)
Set the run number of simulation.
static void SetSeed(uint32_t seed)
Set the seed.
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static void Run()
Run the simulation.
Definition simulator.cc:167
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
Make it easy to create and manage PHY objects for the spectrum model.
The IEEE 802.11 SSID Information Element.
Definition ssid.h:25
AttributeValue implementation for Ssid.
Definition ssid.h:85
Hold variables of type string.
Definition string.h:45
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
@ US
microsecond
Definition nstime.h:107
AttributeValue implementation for Time.
Definition nstime.h:1432
Hold an unsigned integer type.
Definition uinteger.h:34
helps to create WifiNetDevice objects
static int64_t AssignStreams(NetDeviceContainer c, int64_t stream)
Assign a fixed random variable stream number to the random variables used by the PHY and MAC aspects ...
create MAC layers for a ns3::WifiNetDevice.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1588
Statistics helper for tracking outcomes of data MPDU transmissions.
CountPerNodeDeviceLink_t GetSuccessesByNodeDeviceLink(WifiTxStatsHelper::MultiLinkSuccessType type=FIRST_LINK_IN_SET) const
Return the counts of successful MPDU transmissions in a hash map.
void Stop(Time stopTime)
Set the stop time for statistics collection.
uint64_t GetFailures() const
Return the count of failed MPDU transmissions across all enabled devices.
CountPerNodeDevice_t GetFailuresByNodeDevice() const
Return the counts of failed MPDU transmissions in a hash map.
const MpduRecordsPerNodeDeviceLink_t GetSuccessRecords(WifiTxStatsHelper::MultiLinkSuccessType type=FIRST_LINK_IN_SET) const
Return a hash map of successful MPDU records.
const MpduRecordsPerNodeDevice_t & GetFailureRecords() const
Return a hash map of MPDU records for failed transmissions.
CountPerNodeDevice_t GetSuccessesByNodeDevice() const
Return the counts of successful MPDU transmissions in a hash map.
uint64_t GetSuccesses() const
Return the count of successful MPDU transmissions across all enabled devices.
void Enable(const NodeContainer &nodes)
Enables trace collection for all nodes and WifiNetDevices in the specified NodeContainer.
CountPerNodeDevice_t GetRetransmissionsByNodeDevice() const
Return the counts of MPDU retransmissions in a hash map.
uint64_t GetRetransmissions() const
Return the count of MPDU retransmissions across all enabled devices.
void Start(Time startTime)
Set the start time for statistics collection.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition test.h:134
#define NS_TEST_ASSERT_MSG_LT_OR_EQ(actual, limit, msg)
Test that an actual value is less than or equal to a limit and report and abort if not.
Definition test.h:740
#define NS_TEST_ASSERT_MSG_GT_OR_EQ(actual, limit, msg)
Test that an actual value is greater than or equal to a limit and report and abort if not.
Definition test.h:905
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1369
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
@ WIFI_STANDARD_80211a
@ WIFI_STANDARD_80211be
@ WIFI_PHY_BAND_6GHZ
The 6 GHz band.
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
constexpr FrequencyRange WIFI_SPECTRUM_6_GHZ
Identifier for the frequency range covering the wifi spectrum in the 6 GHz band.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
static constexpr uint8_t SINGLE_LINK_OP_ID
Link ID for single link operations (helps tracking places where correct link ID is to be used to supp...
Definition wifi-utils.h:272
constexpr FrequencyRange WIFI_SPECTRUM_5_GHZ
Identifier for the frequency range covering the wifi spectrum in the 5 GHz band.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
static WifiTxStatsHelperTestSuite g_wifiTxStatsHelperTestSuite
the test suite