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