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}
143
144void
146{
149
152
153 MobilityHelper mobility;
154 auto positionAlloc = CreateObject<ListPositionAllocator>();
155 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
156 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
157 mobility.SetPositionAllocator(positionAlloc);
158 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
159 mobility.Install(m_wifiApNode);
160 mobility.Install(m_wifiStaNodes);
161
162 PacketSocketHelper packetSocket;
163 packetSocket.Install(m_wifiApNode);
164 packetSocket.Install(m_wifiStaNodes);
165}
166
167void
169{
170 std::string dataMode;
171 std::string ackMode;
173 {
174 dataMode = "OfdmRate12Mbps";
175 ackMode = "OfdmRate6Mbps";
176 }
177 else
178 {
179 dataMode = "EhtMcs6";
180 ackMode = "OfdmRate54Mbps";
181 }
182
183 WifiHelper wifi;
184 NetDeviceContainer staDevices;
185 NetDeviceContainer apDevices;
187 {
188 wifi.SetStandard(WIFI_STANDARD_80211a);
189 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
190 "DataMode",
191 StringValue(dataMode),
192 "ControlMode",
193 StringValue(ackMode));
194 auto spectrumChannel = CreateObject<SingleModelSpectrumChannel>();
196 spectrumChannel->AddPropagationLossModel(lossModel);
198 spectrumChannel->SetPropagationDelayModel(delayModel);
199
201 phy.SetChannel(spectrumChannel);
202
203 WifiMacHelper mac;
204 mac.SetType("ns3::StaWifiMac",
205 "QosSupported",
206 BooleanValue(false),
207 "Ssid",
208 SsidValue(Ssid("test-ssid")));
209 staDevices = wifi.Install(phy, mac, m_wifiStaNodes);
210
211 mac.SetType("ns3::ApWifiMac",
212 "QosSupported",
213 BooleanValue(false),
214 "Ssid",
215 SsidValue(Ssid("test-ssid")),
216 "BeaconInterval",
217 TimeValue(MicroSeconds(102400)),
218 "EnableBeaconJitter",
219 BooleanValue(false));
220 apDevices = wifi.Install(phy, mac, m_wifiApNode);
221 }
222 else
223 {
224 wifi.SetStandard(WIFI_STANDARD_80211be);
225 // Get channel string for MLD STA
226 std::array<std::string, 2> mldChannelStr;
227 uint32_t frequency = 5;
228 uint32_t frequency2 = 6;
229 for (auto freq : {frequency, frequency2})
230 {
231 NS_TEST_ASSERT_MSG_EQ((freq == 5 || freq == 6), true, "Unsupported frequency for BSS");
232 if (freq == 6)
233 {
234 mldChannelStr[1] = "{0, 20, BAND_6GHZ, 0}";
235 wifi.SetRemoteStationManager(static_cast<uint8_t>(1),
236 "ns3::ConstantRateWifiManager",
237 "DataMode",
238 StringValue(dataMode),
239 "ControlMode",
240 StringValue(ackMode));
241 }
242 else
243 {
244 mldChannelStr[0] = "{0, 20, BAND_5GHZ, 0}";
245 wifi.SetRemoteStationManager(static_cast<uint8_t>(0),
246 "ns3::ConstantRateWifiManager",
247 "DataMode",
248 StringValue(dataMode),
249 "ControlMode",
250 StringValue(ackMode));
251 }
252 }
253
255
257 auto spectrumChannel1 = CreateObject<MultiModelSpectrumChannel>();
258 spectrumChannel1->AddPropagationLossModel(lossModel);
259 auto spectrumChannel2 = CreateObject<MultiModelSpectrumChannel>();
260 spectrumChannel2->AddPropagationLossModel(lossModel);
261
262 phy.AddChannel(spectrumChannel1, WIFI_SPECTRUM_5_GHZ);
263 phy.AddChannel(spectrumChannel2, WIFI_SPECTRUM_6_GHZ);
264
265 for (uint8_t linkId = 0; linkId < 2; ++linkId)
266 {
267 phy.Set(linkId, "ChannelSettings", StringValue(mldChannelStr[linkId]));
268 }
269
270 WifiMacHelper mac;
271 mac.SetType("ns3::StaWifiMac",
272 "QosSupported",
273 BooleanValue(true),
274 "Ssid",
275 SsidValue(Ssid("test-ssid")));
276 staDevices = wifi.Install(phy, mac, m_wifiStaNodes);
277
278 mac.SetType("ns3::ApWifiMac",
279 "QosSupported",
280 BooleanValue(true),
281 "Ssid",
282 SsidValue(Ssid("test-ssid")),
283 "BeaconInterval",
284 TimeValue(MicroSeconds(102400)),
285 "EnableBeaconJitter",
286 BooleanValue(false));
287 apDevices = wifi.Install(phy, mac, m_wifiApNode);
288 }
289
290 m_sifs = DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetPhy()->GetSifs();
291 m_slot = DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetPhy()->GetSlot();
293 {
294 m_difs = m_sifs + 2 * m_slot;
296 DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetMac()->GetTxop()->GetMinCw();
297 }
298 else
299 {
300 // Use TID-to-link Mapping to tx TID=3 pkts (BE) only on link 0,
301 // TID=4 pkts (VI) only on link 1
302 m_cwMins[0] = 15;
303 m_cwMins[1] = 7;
304 m_aifsns[0] = 3;
305 m_aifsns[1] = 2;
306 m_aifss[0] = m_aifsns[0] * m_slot + m_sifs;
307 m_aifss[1] = m_aifsns[1] * m_slot + m_sifs;
308 std::string mldMappingStr = "3 0; 4 1";
309 DynamicCast<WifiNetDevice>(staDevices.Get(0))
310 ->GetMac()
311 ->GetEhtConfiguration()
312 ->SetAttribute("TidToLinkMappingUl", StringValue(mldMappingStr));
313 }
314
315 auto streamsUsed = WifiHelper::AssignStreams(apDevices, m_streamNumber);
316 NS_ASSERT_MSG(streamsUsed < 100, "Need to increment by larger quantity");
317 WifiHelper::AssignStreams(staDevices, m_streamNumber + 100);
318
319 // UL traffic (TX statistics will be installed at STA side)
320 PacketSocketAddress socket;
321 socket.SetSingleDevice(staDevices.Get(0)->GetIfIndex());
322 socket.SetPhysicalAddress(apDevices.Get(0)->GetAddress());
323 auto server = CreateObject<PacketSocketServer>();
324 server->SetLocal(socket);
325 m_wifiApNode.Get(0)->AddApplication(server);
326 server->SetStartTime(Seconds(0.0));
327 server->SetStopTime(Seconds(1.0));
329 {
330 auto client = CreateObject<PacketSocketClient>();
331 client->SetAttribute("PacketSize", UintegerValue(1500));
332 client->SetAttribute("MaxPackets", UintegerValue(3));
333 client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
334 client->SetRemote(socket);
336 client->SetStartTime(MicroSeconds(210000));
337 client->SetStopTime(Seconds(1.0));
338 }
339 else
340 {
341 auto clientBe = CreateObject<PacketSocketClient>();
342 clientBe->SetAttribute("Priority", UintegerValue(3));
343 clientBe->SetAttribute("PacketSize", UintegerValue(1500));
344 clientBe->SetAttribute("MaxPackets", UintegerValue(3));
345 clientBe->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
346 clientBe->SetRemote(socket);
347 m_wifiStaNodes.Get(0)->AddApplication(clientBe);
348 clientBe->SetStartTime(MicroSeconds(200000));
349 clientBe->SetStopTime(Seconds(1.0));
350
351 auto clientVi = CreateObject<PacketSocketClient>();
352 clientVi->SetAttribute("Priority", UintegerValue(4));
353 clientVi->SetAttribute("PacketSize", UintegerValue(1500));
354 clientVi->SetAttribute("MaxPackets", UintegerValue(3));
355 clientVi->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
356 clientVi->SetRemote(socket);
357 m_wifiStaNodes.Get(0)->AddApplication(clientVi);
358 clientVi->SetStartTime(MicroSeconds(300000));
359 clientVi->SetStopTime(Seconds(1.0));
360 }
361
362 // Add AP side receiver corruption
364 {
365 // We corrupt AP side reception so that:
366 // 1) the 2nd data frame is retransmitted and succeeds (1 failure, 1 success)
367 // 2) the 3rd data frame is transmitted 7 times (=FrameRetryLimit) and finally fails (7
368 // failures, 0 success)
369 //
370 // No. of pkt | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
371 // No. recvd by AP | | | 0 | | | 1 | | 2 | | AP's
372 // pkts | Bea | Bea | | Ack | AsRes | | Bea | | Ack1 |
373 // STA's pkts | | | AsReq | | | Ack | | Data1 | |
374 //
375 // No. of pkt | 9 | 10 | 11 | 12 | 13 | ... | 18 | 19 | ...
376 // No. recvd by AP | 3 (x) | 4 | | 5 (x) | 6 (x) | ... |11 (x) | | ...
377 // AP's pkts | | | Ack2 | | | ... | | Bea | ...
378 // STA's pkts | Data2 | Data2 | | Data3 | Data3 | ... | Data3 | | ...
379 //
380 // Legend:
381 // Bea = Beacon, AsReq = Association Request, AsRes = Association Response
382 // AP side corruption is indicated with (x)
383
385 apPem->SetList({3, 5, 6, 7, 8, 9, 10, 11});
386 DynamicCast<WifiNetDevice>(apDevices.Get(0))
387 ->GetMac()
388 ->GetWifiPhy()
389 ->SetPostReceptionErrorModel(apPem);
390 }
391 else
392 {
393 // We corrupt AP side reception so that:
394 // On Link 0 (contains uplink data with TID = 3):
395 // 1) the 2nd data frame is retransmitted once and succeeds (retransmission = 1)
396 // 2) the 3rd data frame is transmitted 2 times within A-MPDU and 7 times alone
397 // (WifiMac::FrameRetryLimit) and finally fails (retransmission = 8)
398 //
399 // No. of PSDU | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
400 // No. recvd by AP | | | 0 | | 1 | | 2 | | 3 |
401 // AP's pkts | Bea | Bea | | Ack | | AsRes | | CfEnd | |
402 // STA's pkts | | | AsReq | | CfEnd | | Ack | | ABReq
403 // |
404 //
405 // No. of PSDU | 9 | 10 | 11 | 12 | 12 | 12 | 13 | 14 | 14 |
406 // No. recvd by AP | | | 4 | 5 | 6(x) | 7(x) | | 8 | 9(x) |
407 // AP's pkts | Ack | ABRes | | | | | BAck | | |
408 // STA's pkts | | | Ack | Data1 | Data2 | Data3 | | Data2 | Data3
409 // |
410 //
411 // No. of PSDU | 15 | 16 | ... | | ... | 23 | 24 | 25 | ...
412 // No. recvd by AP | | 10(x) | ... | | ... | 16(x) | 17 | | ...
413 // AP's pkts | BAck | | ... | Bea | ... | | | BAck | ...
414 // STA's pkts | | Data3 | ... | | ... | Data3 | Bar | | ...
415 //
416 // On Link 1 (contains uplink data with TID = 4):
417 // 1) the 2nd data frame is transmitted 2 times within A-MPDU and 7 times alone
418 // (=WifiMac::FrameRetryLimit) and finally fails (retransmission = 8)
419 // 2) the 3rd data frame is
420 // retransmitted once and succeeds (retransmission = 1)
421 //
422 // No. of PSDU | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
423 // No. recvd by AP | | | 0 | | | 1 | | 2 | | AP's
424 // pkts | Bea | Bea | | Ack | Bea | | Ack | | ABRes |
425 // STA's pkts | | | Null | | | ABReq | | CfEnd | |
426 //
427 // No. of PSDU | 9 | 10 | 11 | 11 | 11 | 12 | 13 | 13 | 14 |
428 // No. recvd by AP | 3 | | 4 | 5(x) | 6(x) | | 7(x) | 8 | | AP's
429 // pkts | | CfEnd | | | | BAck | | | BAck |
430 // STA's pkts | Ack | | Data1 | Data2 | Data3 | | Data2 | Data3 | |
431 //
432 // No. of PSDU | 15 | ... | 21 | 22 | 23 | 24 | ...
433 // No. recvd by AP | 9(x) | ... | 15(x) | 16 | | 17 | ...
434 // AP's pkts | | ... | | | BAck | | ...
435 // STA's pkts | Data2 | ... | Data2 | Bar | | CfEnd | ...
436 //
437 // Legend:
438 // Bea = Beacon, AsReq = Association Request, AsRes = Association Response
439 // ABReq = Add Block ACK Request, ABRes = Add Block ACK Response
440 // Bar = Block ACK Request (used to notify the discarded MPDU)
441 // CfEnd = CF-End, BAck = Block ACK (Response), Null = Null function
442 // AP side corruption is indicated with (x)
443
444 // Force drops on link 0 at AP
446 apPem0->SetList({6, 7, 9, 10, 11, 12, 13, 14, 15, 16});
447 DynamicCast<WifiNetDevice>(apDevices.Get(0))
448 ->GetMac()
449 ->GetWifiPhy(0)
450 ->SetPostReceptionErrorModel(apPem0);
451
452 // Force drops on link 1 at AP
454 apPem1->SetList({5, 6, 7, 9, 10, 11, 12, 13, 14, 15});
455 DynamicCast<WifiNetDevice>(apDevices.Get(0))
456 ->GetMac()
457 ->GetWifiPhy(1)
458 ->SetPostReceptionErrorModel(apPem1);
459 }
460
461 NetDeviceContainer allNetDev;
462 allNetDev.Add(apDevices);
463 allNetDev.Add(staDevices);
464 WifiTxStatsHelper wifiTxStats;
465 wifiTxStats.Enable(allNetDev);
466 wifiTxStats.Start(Seconds(0));
467 wifiTxStats.Stop(Seconds(1));
468
469 // Trace PSDU TX at both AP and STA to get start times and durations, including acks
471 {
472 for (auto it = allNetDev.Begin(); it != allNetDev.End(); ++it)
473 {
474 auto dev = DynamicCast<WifiNetDevice>(*it);
475 dev->GetPhy()->TraceConnect("PhyTxPsduBegin",
476 std::to_string(SINGLE_LINK_OP_ID),
477 // "0"
479 }
480 }
481 else
482 {
483 for (auto it = allNetDev.Begin(); it != allNetDev.End(); ++it)
484 {
485 auto dev = DynamicCast<WifiNetDevice>(*it);
486 dev->GetPhy(0)->TraceConnect("PhyTxPsduBegin",
487 "0",
489 dev->GetPhy(1)->TraceConnect("PhyTxPsduBegin",
490 "1",
492 }
493 }
494
497 CheckResults(wifiTxStats);
499}
500
501void
503{
504 const auto tolerance = NanoSeconds(50); // due to propagation delay
505 // Check both variants of GetSuccesses...()
506 const auto successMap = wifiTxStats.GetSuccessesByNodeDevice();
507 const auto successMapPerNodeDeviceLink = wifiTxStats.GetSuccessesByNodeDeviceLink();
508 const auto failureMap = wifiTxStats.GetFailuresByNodeDevice();
509 const auto retransmissionMap = wifiTxStats.GetRetransmissionsByNodeDevice();
510 const auto totalSuccesses = wifiTxStats.GetSuccesses();
511 const auto totalFailures = wifiTxStats.GetFailures();
512 const auto totalRetransmissions = wifiTxStats.GetRetransmissions();
513 const auto& successRecords = wifiTxStats.GetSuccessRecords();
514 const auto& failureRecords = wifiTxStats.GetFailureRecords();
515
516 uint32_t nodeId = 1;
517 uint32_t deviceId = 0;
518 auto nodeDeviceTuple = std::make_tuple(nodeId, deviceId);
519 auto nodeDeviceLink0Tuple = std::make_tuple(nodeId, deviceId, 0);
520 auto nodeDeviceLink1Tuple = std::make_tuple(nodeId, deviceId, 1);
521
523 {
524 const auto totalFailuresDrop =
525 wifiTxStats.GetFailures(WifiMacDropReason::WIFI_MAC_DROP_REACHED_RETRY_LIMIT);
526 const auto totalFailuresDropMap = wifiTxStats.GetFailuresByNodeDevice(
527 WifiMacDropReason::WIFI_MAC_DROP_REACHED_RETRY_LIMIT);
528
529 NS_TEST_ASSERT_MSG_EQ(successMapPerNodeDeviceLink.at(nodeDeviceLink0Tuple),
530 2,
531 "Number of success packets should be 2");
532 NS_TEST_ASSERT_MSG_EQ(successMap.at(nodeDeviceTuple),
533 2,
534 "Number of success packets should be 2");
535 NS_TEST_ASSERT_MSG_EQ(totalSuccesses, 2, "Number of success packets should be 2");
536
537 NS_TEST_ASSERT_MSG_EQ(retransmissionMap.at(nodeDeviceTuple),
538 1,
539 "Number of retransmitted successful packets should be 1");
540 NS_TEST_ASSERT_MSG_EQ(totalRetransmissions,
541 1,
542 "Number of retransmitted successful packets should be 1");
543
544 NS_TEST_ASSERT_MSG_EQ(failureMap.at(nodeDeviceTuple),
545 1,
546 "Number of failed packets should be 1");
547 NS_TEST_ASSERT_MSG_EQ(totalFailures, 1, "Number of failed packets (aggregate) should be 1");
549 totalFailuresDrop,
550 1,
551 "Number of dropped packets (aggregate) due to retry limit reached should be 1");
553 totalFailuresDropMap.at(nodeDeviceTuple),
554 1,
555 "Number of dropped packets (aggregate) due to retry limit reached should be 1");
556
557 auto successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
558 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_nodeId,
559 1,
560 "Source node ID of the 1st successful data packet should be 1");
561 std::advance(successRecordIt, 1);
562 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_nodeId,
563 1,
564 "Source node ID of the 2nd successful data packet should be 1");
565 auto failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
566 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_nodeId,
567 1,
568 "Source node ID of the failed data packet should be 1");
569
570 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
572 successRecordIt->m_retransmissions,
573 0,
574 "The retransmission count of the 1st successful data packet should be 0");
575 std::advance(successRecordIt, 1);
577 successRecordIt->m_retransmissions,
578 1,
579 "The retransmission count of the 2nd successful data packet should be 1");
580 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_retransmissions,
581 6,
582 "The retransmission count of the failed data packet should be 6");
583
584 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
585 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime.IsStrictlyPositive(),
586 true,
587 "The 1st successful data packet should have been TXed");
588 std::advance(successRecordIt, 1);
589 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime.IsStrictlyPositive(),
590 true,
591 "The 2nd successful data packet should have been TXed");
592 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime.IsStrictlyPositive(),
593 true,
594 "The failed data packet should have been TXed");
595
596 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
597 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
598 true,
599 "The 1st successful data packet should have been acked");
600 std::advance(successRecordIt, 1);
601 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
602 true,
603 "The 2nd successful data packet should have been acked");
604 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_ackTime.IsStrictlyPositive(),
605 false,
606 "The failed data packet should not have been acked");
607
608 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
609 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
610 true,
611 "The 1st successful data packet should have been dequeued");
612 std::advance(successRecordIt, 1);
613 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
614 true,
615 "The 2nd successful data packet should have been dequeued");
616 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
617 failureRecordIt->m_dropTime.value().IsStrictlyPositive(),
618 true,
619 "The failed data packet should have been dequeued");
620
621 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
622 auto successRecordItNext = successRecordIt;
623 std::advance(successRecordItNext, 1);
624 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_enqueueTime,
625 successRecordItNext->m_enqueueTime,
626 "Three packets should be enqueued at the same time");
627 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_enqueueTime,
628 failureRecordIt->m_enqueueTime,
629 "Three packets should be enqueued at the same time");
630
631 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
632 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordIt->m_txStartTime,
633 successRecordIt->m_enqueueTime,
634 "Packets should be TXed after enqueued");
635 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordIt->m_txStartTime,
636 successRecordIt->m_enqueueTime + tolerance +
638 "Packet backoff slots should not exceed cwMin");
639 // Packet start time 7 corresponds to first data packet (prior to this, beacons and assoc)
640 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime,
642 "Wrong TX start time");
643 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordIt->m_ackTime,
647 "Wrong Ack reception time");
648 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordIt->m_ackTime,
651 m_durations[SINGLE_LINK_OP_ID][8] + 2 * tolerance,
652 "Wrong Ack reception time");
653 std::advance(successRecordIt, 1);
654 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordIt->m_txStartTime,
657 "Packets should be TXed after enqueued");
658 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordIt->m_txStartTime,
660 m_durations[SINGLE_LINK_OP_ID][8] + m_difs + tolerance +
662 "Packet backoff slots should not exceed cwMin");
663 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime,
665 "Wrong TX start time");
666 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordIt->m_ackTime,
670 "Wrong Ack reception time");
672 successRecordIt->m_ackTime,
675 ((m_cwMins[SINGLE_LINK_OP_ID] + 1) * 2 - 1) * m_slot + 2 * tolerance,
676 "Wrong Ack reception time");
677
678 NS_TEST_ASSERT_MSG_GT_OR_EQ(failureRecordIt->m_txStartTime,
681 "Packets should be TXed after enqueued");
682 NS_TEST_ASSERT_MSG_LT_OR_EQ(failureRecordIt->m_txStartTime,
684 m_durations[SINGLE_LINK_OP_ID][11] + m_difs + tolerance +
686 "Packet backoff slots should not exceed cwMin");
687 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime,
689 "Wrong TX start time");
690 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
691 failureRecordIt->m_dropReason.has_value(),
692 true,
693 "Missing drop time or reason");
694 NS_TEST_ASSERT_MSG_GT_OR_EQ(failureRecordIt->m_dropTime.value(),
697 "Wrong Dequeue time for failed packet");
698 NS_TEST_ASSERT_MSG_LT_OR_EQ(failureRecordIt->m_dropTime.value(),
702 "Wrong Dequeue time for failed packet");
703 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropReason.value(),
704 WifiMacDropReason::WIFI_MAC_DROP_REACHED_RETRY_LIMIT,
705 "Wrong drop reason");
706 }
707 else
708 {
709 const auto totalFailuresQos =
710 wifiTxStats.GetFailures(WifiMacDropReason::WIFI_MAC_DROP_QOS_OLD_PACKET);
711 const auto totalFailuresQosMap =
712 wifiTxStats.GetFailuresByNodeDevice(WifiMacDropReason::WIFI_MAC_DROP_QOS_OLD_PACKET);
713
714 for (std::vector<Time>::size_type i = 0; i < m_txStartTimes[0].size(); ++i)
715 {
716 NS_LOG_INFO("link 0 pkt " << i << " start tx at " << m_txStartTimes[0][i].As(Time::US));
717 }
718 for (std::vector<Time>::size_type i = 0; i < m_txStartTimes[1].size(); ++i)
719 {
720 NS_LOG_INFO("link 1 pkt " << i << " start tx at " << m_txStartTimes[1][i].As(Time::US));
721 }
722
723 NS_TEST_ASSERT_MSG_EQ(successMapPerNodeDeviceLink.at(nodeDeviceLink0Tuple),
724 2,
725 "Number of success packets on link 0 should be 2");
726 NS_TEST_ASSERT_MSG_EQ(successMapPerNodeDeviceLink.at(nodeDeviceLink1Tuple),
727 2,
728 "Number of success packets on link 1 should be 2");
729 NS_TEST_ASSERT_MSG_EQ(successMap.at(nodeDeviceTuple),
730 4,
731 "Number of success packets should be 4");
732 NS_TEST_ASSERT_MSG_EQ(totalSuccesses, 4, "Number of success packets should be 4");
733
734 NS_TEST_ASSERT_MSG_EQ(retransmissionMap.at(nodeDeviceTuple),
735 2,
736 "Number of retransmitted successful packets should be 2");
737 NS_TEST_ASSERT_MSG_EQ(totalRetransmissions,
738 2,
739 "Number of retransmitted successful packets (aggregate) should be 2");
740 NS_TEST_ASSERT_MSG_EQ(failureMap.at(nodeDeviceTuple),
741 2,
742 "Number of failed packets should be 2");
743 NS_TEST_ASSERT_MSG_EQ(totalFailures, 2, "Number of failed packets (aggregate) should be 2");
744 NS_TEST_ASSERT_MSG_EQ(totalFailuresQos,
745 2,
746 "Number of dropped packets (aggregate) by QosTxop should be 2");
747 NS_TEST_ASSERT_MSG_EQ(totalFailuresQosMap.at(nodeDeviceTuple),
748 2,
749 "Number of dropped packets (aggregate) by QosTxop should be 2");
750
751 auto successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
753 successRecordLink0It->m_nodeId,
754 1,
755 "Source node ID of the 1st successful data packet on link 0 should be 1");
756 std::advance(successRecordLink0It, 1);
758 successRecordLink0It->m_nodeId,
759 1,
760 "Source node ID of the 2nd successful data packet on link 0 should be 1");
761 auto successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
763 successRecordLink1It->m_nodeId,
764 1,
765 "Source node ID of the 1st successful data packet on link 0 should be 1");
766 std::advance(successRecordLink1It, 1);
768 successRecordLink1It->m_nodeId,
769 1,
770 "Source node ID of the 2nd successful data packet on link 0 should be 1");
771 auto failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
772 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_nodeId,
773 1,
774 "Source node ID of the failed data packet on link 0 should be 1");
775 std::advance(failureRecordIt, 1);
776 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_nodeId,
777 1,
778 "Source node ID of the failed data packet on link 1 should be 1");
779
780 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
781 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_deviceId,
782 0,
783 "Device ID of the 1st successful data packet on link 0 should be 0");
784 std::advance(successRecordLink0It, 1);
785 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_deviceId,
786 0,
787 "Device ID of the 2nd successful data packet on link 0 should be 0");
788 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
789 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_deviceId,
790 0,
791 "Device ID of the 1st successful data packet on link 0 should be 0");
792 std::advance(successRecordLink1It, 1);
793 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_deviceId,
794 0,
795 "Device ID of the 2nd successful data packet on link 1 should be 0");
796 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
797 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_deviceId,
798 0,
799 "Device ID of the failed data packet on link 1 should be 0");
800 std::advance(failureRecordIt, 1);
801 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_deviceId,
802 0,
803 "Device ID of the failed data packet on link 1 should be 0");
804
805 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
807 *successRecordLink0It->m_successLinkIdSet.begin(),
808 0,
809 "Successful link ID of the 1st successful data packet on link 0 should be 0");
810 std::advance(successRecordLink0It, 1);
812 *successRecordLink0It->m_successLinkIdSet.begin(),
813 0,
814 "Successful link ID of the 2nd successful data packet on link 0 should be 0");
815 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
817 *successRecordLink1It->m_successLinkIdSet.begin(),
818 1,
819 "Successful link ID of the 1st successful data packet on link 1 should be 1");
820 std::advance(successRecordLink1It, 1);
822 *successRecordLink1It->m_successLinkIdSet.begin(),
823 1,
824 "Successful link ID of the 2nd successful data packet on link 1 should be 1");
825 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
827 failureRecordIt->m_successLinkIdSet.empty(),
828 true,
829 "Successful link ID set of the failed data packet on link 0 should be empty");
830 std::advance(failureRecordIt, 1);
832 failureRecordIt->m_successLinkIdSet.empty(),
833 true,
834 "Successful link ID set of the failed data packet on link 1 should be empty");
835
836 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
838 successRecordLink0It->m_retransmissions,
839 0,
840 "The 1st successful data packet on link 0 should have no retransmissions");
841 std::advance(successRecordLink0It, 1);
843 successRecordLink0It->m_retransmissions,
844 1,
845 "The 2nd successful data packet on link 0 should have 1 retransmission");
846 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
848 successRecordLink1It->m_retransmissions,
849 0,
850 "The 1st successful data packet on link 1 should have no retransmissions");
851 std::advance(successRecordLink1It, 1);
853 successRecordLink1It->m_retransmissions,
854 1,
855 "The 2nd successful data packet on link 1 should have 1 retransmission");
856 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
857 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_retransmissions,
858 8,
859 "The failed data packet on link 0 should have 8 retransmissions");
860 std::advance(failureRecordIt, 1);
861 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_retransmissions,
862 8,
863 "The failed data packet on link 1 should have 8 retransmissions");
864
865 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
866 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_tid,
867 3,
868 "The 1st successful data packet on link 0 should have a TID of 3");
869 std::advance(successRecordLink0It, 1);
870 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_tid,
871 3,
872 "The 2nd successful data packet on link 0 should have a TID of 3");
873 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
874 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_tid,
875 4,
876 "The 1st successful data packet on link 1 should have a TID of 4");
877 std::advance(successRecordLink1It, 1);
878 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_tid,
879 4,
880 "The 2nd successful data packet on link 1 should have a TID of 4");
881 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
882 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_tid,
883 3,
884 "The failed data packet on link 0 should have a TID of 3");
885 std::advance(failureRecordIt, 1);
886 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_tid,
887 4,
888 "The failed data packet on link 1 should have a TID of 4");
889
890 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
892 successRecordLink0It->m_mpduSeqNum,
893 0,
894 "The 1st successful data packet on link 0 should have a Seq Num of 0");
895 std::advance(successRecordLink0It, 1);
897 successRecordLink0It->m_mpduSeqNum,
898 1,
899 "The 2nd successful data packet on link 0 should have a Seq Num of 1");
900 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
902 successRecordLink1It->m_mpduSeqNum,
903 0,
904 "The 1st successful data packet on link 1 should have a Seq Num of 0");
905 std::advance(successRecordLink1It, 1);
907 successRecordLink1It->m_mpduSeqNum,
908 2,
909 "The 2nd successful data packet on link 1 should have a Seq Num of 2");
910 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
911 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_mpduSeqNum,
912 2,
913 "The failed data packet on link 0 should have a Seq Num of 2");
914 std::advance(failureRecordIt, 1);
915 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_mpduSeqNum,
916 1,
917 "The failed data packet on link 1 should have a Seq Num of 1");
918
919 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
920 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime.IsStrictlyPositive(),
921 true,
922 "The 1st successful data packet on link 0 should have been TXed");
923 std::advance(successRecordLink0It, 1);
924 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime.IsStrictlyPositive(),
925 true,
926 "The 2nd successful data packet on link 0 should have been TXed");
927 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
928 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime.IsStrictlyPositive(),
929 true,
930 "The 1st successful data packet on link 1 should have been TXed");
931 std::advance(successRecordLink1It, 1);
932 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime.IsStrictlyPositive(),
933 true,
934 "The 2nd successful data packet on link 1 should have been TXed");
935 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
936 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime.IsStrictlyPositive(),
937 true,
938 "The failed data packet on link 0 should have been TXed");
939 std::advance(failureRecordIt, 1);
940 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime.IsStrictlyPositive(),
941 true,
942 "The failed data packet on link 1 should have been TXed");
943
944 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
945 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
946 true,
947 "The 1st successful data packet on link 0 should have been acked");
948 std::advance(successRecordLink0It, 1);
949 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
950 true,
951 "The 2nd successful data packet on link 0 should have been acked");
952 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
953 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
954 true,
955 "The 1st successful data packet on link 1 should have been acked");
956 std::advance(successRecordLink1It, 1);
957 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
958 true,
959 "The 2nd successful data packet on link 1 should have been acked");
960 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
961 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_ackTime.IsStrictlyPositive(),
962 false,
963 "The failed data packet on link 0 should not have been acked");
964 std::advance(failureRecordIt, 1);
965 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_ackTime.IsStrictlyPositive(),
966 false,
967 "The failed data packet on link 1 should not have been acked");
968
969 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
970 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
971 true,
972 "The 1st successful data packet on link 0 should have been dequeued");
973 std::advance(successRecordLink0It, 1);
974 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
975 true,
976 "The 2nd successful data packet on link 0 should have been dequeued");
977 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
978 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
979 true,
980 "The 1st successful data packet on link 1 should have been dequeued");
981 std::advance(successRecordLink1It, 1);
982 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
983 true,
984 "The 2nd successful data packet on link 1 should have been dequeued");
985 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
986 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
987 failureRecordIt->m_dropReason.has_value(),
988 true,
989 "Missing drop time or reason");
990 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.value().IsStrictlyPositive(),
991 true,
992 "The failed data packet on link 0 should have been dequeued");
993 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropReason.value(),
994 WifiMacDropReason::WIFI_MAC_DROP_QOS_OLD_PACKET,
995 "Wrong drop reason");
996 std::advance(failureRecordIt, 1);
997 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
998 failureRecordIt->m_dropReason.has_value(),
999 true,
1000 "Missing drop time or reason");
1001 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.value().IsStrictlyPositive(),
1002 true,
1003 "The failed data packet on link 1 should have been dequeued");
1004 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropReason.value(),
1005 WifiMacDropReason::WIFI_MAC_DROP_QOS_OLD_PACKET,
1006 "Wrong drop reason");
1007
1008 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1009 auto successRecordLink0ItNext = successRecordLink0It;
1010 std::advance(successRecordLink0ItNext, 1);
1011 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
1012 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_enqueueTime,
1013 successRecordLink0ItNext->m_enqueueTime,
1014 "Packets on link 0 should be enqueued at the same time");
1015 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_enqueueTime,
1016 failureRecordIt->m_enqueueTime,
1017 "Packets on link 0 should be enqueued at the same time");
1018 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1019 auto successRecordLink1ItNext = successRecordLink1It;
1020 std::advance(successRecordLink1ItNext, 1);
1021 std::advance(failureRecordIt, 1);
1022 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_enqueueTime,
1023 successRecordLink1ItNext->m_enqueueTime,
1024 "Packets on link 1 should be enqueued at the same time");
1025 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_enqueueTime,
1026 failureRecordIt->m_enqueueTime,
1027 "Packets on link 1 should be enqueued at the same time");
1028
1029 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1030 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_txStartTime,
1031 successRecordLink0It->m_enqueueTime,
1032 "The 1st data packet on link 0 should be TXed after enqueued");
1033 std::advance(successRecordLink0It, 1);
1034 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_txStartTime,
1035 successRecordLink0It->m_enqueueTime,
1036 "The 2nd data packet on link 0 should be TXed after enqueued");
1037 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1038 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_txStartTime,
1039 successRecordLink1It->m_enqueueTime,
1040 "The 1st data packet on link 1 should be TXed after enqueued");
1041 std::advance(successRecordLink1It, 1);
1042 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_txStartTime,
1043 successRecordLink1It->m_enqueueTime,
1044 "The 2nd data packet on link 1 should be TXed after enqueued");
1045 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
1046 NS_TEST_ASSERT_MSG_GT_OR_EQ(failureRecordIt->m_txStartTime,
1047 failureRecordIt->m_enqueueTime,
1048 "The 3rd data packet on link 0 should be TXed after enqueued");
1049 std::advance(failureRecordIt, 1);
1050 NS_TEST_ASSERT_MSG_GT_OR_EQ(failureRecordIt->m_txStartTime,
1051 failureRecordIt->m_enqueueTime,
1052 "The 3rd data packet on link 1 should be TXed after enqueued");
1053
1054 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1055 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_txStartTime,
1056 m_txStartTimes[0][11] + m_durations[0][11] + m_aifss[0],
1057 "link 0 pkt first tx should be after the 11th packet on link");
1058 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink0It->m_txStartTime,
1059 m_txStartTimes[0][11] + m_durations[0][11] + m_aifss[0] +
1060 tolerance + m_cwMins[0] * m_slot,
1061 "link 0 pkt first backoff should not exceed cwMin");
1062 successRecordLink0ItNext = successRecordLink0It;
1063 std::advance(successRecordLink0ItNext, 1);
1064 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
1065 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime,
1066 successRecordLink0ItNext->m_txStartTime,
1067 "3 pkts of link 0 should tx at the same time");
1068 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime,
1069 failureRecordIt->m_txStartTime,
1070 "3 pkts of link 0 should tx at the same time");
1071
1072 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1073 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_txStartTime,
1074 m_txStartTimes[1][10] + m_durations[1][10] + m_aifss[1],
1075 "link 1 pkt first tx should be after the 10th packet on link");
1076 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink1It->m_txStartTime,
1077 m_txStartTimes[1][10] + m_durations[1][10] + m_aifss[1] +
1078 tolerance + m_cwMins[1] * m_slot,
1079 "link 1 pkt first backoff should not exceed cwMin");
1080 successRecordLink1ItNext = successRecordLink1It;
1081 std::advance(successRecordLink1ItNext, 1);
1082 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
1083 std::advance(failureRecordIt, 1);
1084 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime,
1085 successRecordLink1ItNext->m_txStartTime,
1086 "3 pkts of link 1 should tx at the same time");
1087 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime,
1088 failureRecordIt->m_txStartTime,
1089 "3 pkts of link 1 should tx at the same time");
1090
1091 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1092 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_ackTime,
1093 m_txStartTimes[0][12] + m_durations[0][12] + m_sifs +
1094 m_durations[0][13],
1095 "Wrong first Block Ack reception time on link 0");
1096 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink0It->m_ackTime,
1097 m_txStartTimes[0][12] + m_durations[0][12] + m_sifs +
1098 m_durations[0][13] + 2 * tolerance,
1099 "Wrong first Block Ack reception time on link 0");
1100 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1101 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_ackTime,
1102 m_txStartTimes[1][11] + m_durations[1][11] + m_sifs +
1103 m_durations[1][12],
1104 "Wrong first Block Ack reception time on link 1");
1105 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink1It->m_ackTime,
1106 m_txStartTimes[1][11] + m_durations[1][11] + m_sifs +
1107 m_durations[1][12] + 2 * tolerance,
1108 "Wrong first Block Ack reception time on link 1");
1109
1110 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1111 std::advance(successRecordLink0It, 1);
1112 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_ackTime,
1113 m_txStartTimes[0][14] + m_durations[0][14] + m_sifs +
1114 m_durations[0][15],
1115 "Wrong second Block Ack reception time on link 0");
1116 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink0It->m_ackTime,
1117 m_txStartTimes[0][14] + m_durations[0][14] + m_sifs +
1118 m_durations[0][15] + 2 * tolerance,
1119 "Wrong second Block Ack reception time on link 0");
1120 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1121 std::advance(successRecordLink1It, 1);
1122 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_ackTime,
1123 m_txStartTimes[1][13] + m_durations[1][13] + m_sifs +
1124 m_durations[1][14],
1125 "Wrong second Block Ack reception time on link 1");
1126 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink1It->m_ackTime,
1127 m_txStartTimes[1][13] + m_durations[1][13] + m_sifs +
1128 m_durations[1][14] + 2 * tolerance,
1129 "Wrong second Block Ack reception time on link 1");
1130 }
1131}
1132
1133/**
1134 * @ingroup wifi-test
1135 * @ingroup tests
1136 *
1137 * @brief WifiTxStatsHelper Test Suite
1138 */
1140{
1141 public:
1143};
1144
1146 : TestSuite("wifi-tx-stats-helper", Type::UNIT)
1147{
1148 // A test case to evaluate the transmission process of multiple Wi-Fi MAC Layer MPDUs in
1149 // a single link device. This testcase uses .11a to test the handling of regular ACKs.
1150 //
1151 // This class tests the WifiTxStatsHelper output by creating three transmission cases:
1152 // 1) packet is sent successfully on the first try
1153 // 2) packet is lost on the first try but successfully transmitted on the second try
1154 // 3) packet is lost on all seven tries and a failure is logged
1155 // The MPDU losses are forced by the use of WifiPhy post-reception error model.
1156 //
1157 // This test also connects to the PHY trace PhyTxPsduBegin and records the sequence of
1158 // transmission times and packet durations observed at the PHY layer, to cross-check against
1159 // the times recorded in the WifiTxStatsHelper record (traced at the MAC layer).
1160 // The testcase also checks the various fields in this helper's output records for correctness.
1161 AddTestCase(new WifiTxStatsHelperTest("Check single link non-QoS configuration",
1163 TestCase::Duration::QUICK);
1164
1165 // A test case to evaluate the transmission process of multiple Wi-Fi MAC Layer MPDUs in
1166 // a multi link device. This testcase, unlike the previous, uses .11be to test the
1167 // handling of MPDU aggregation, Block ACKs, and Multi-Link Operation.
1168 //
1169 // This class tests the WifiTxStatsHelper output by creating three transmission cases:
1170 // 1) packet is sent successfully on the first try
1171 // 2) packet is lost on the first try (in an A-MPDU) but successfully transmitted on the
1172 // second try (also in an A-MPDU)
1173 // 3) packet is lost on all 9 tries (first 2 in A-MPDU, other 7 alone) and a failure is logged
1174 // The MPDU losses are forced by the use of WifiPhy post-reception error model.
1175 //
1176 // This test also connects to the PHY trace PhyTxPsduBegin and records the sequence of
1177 // transmission times and packet durations observed at the PHY layer, to cross-check against
1178 // the times recorded in the WifiTxStatsHelper record (traced at the MAC layer).
1179 // The testcase also checks the various fields in this helper's output records for correctness.
1180 AddTestCase(new WifiTxStatsHelperTest("Check multi-link QoS configuration",
1182 TestCase::Duration::QUICK);
1183}
1184
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.
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
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
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:1587
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:1368
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1380
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
@ 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