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-ns3-constants.h"
32#include "ns3/wifi-ppdu.h"
33#include "ns3/wifi-psdu.h"
34#include "ns3/wifi-tx-stats-helper.h"
35
36#include <vector>
37
38using namespace ns3;
39
40NS_LOG_COMPONENT_DEFINE("WifiTxStatsHelperTest");
41
42/**
43 * @ingroup wifi-test
44 * @brief Implements a test case to evaluate the transmission process of multiple Wi-Fi
45 * MAC Layer MPDUs. The testcase has two options.
46 * 1) SINGLE_LINK_NON_QOS: test the handling of regular ACKs.
47 * 2) MULTI_LINK_QOS: test the handling of MPDU aggregation, Block ACKs, and Multi-Link Operation.
48 *
49 * To observe the operation of WifiTxStatsHelper, the test can be run from the command line as
50 * follows:
51 * @code
52 * NS_LOG="WifiTxStatsHelper=level_info|prefix_all" ./ns3 run 'test-runner
53 * --suite=wifi-tx-stats-helper'
54 * @endcode
55 */
57{
58 public:
59 /**
60 * Option for the test
61 */
67
68 /**
69 * Constructor
70 * @param testName Test name
71 * @param option Test option
72 */
73 WifiTxStatsHelperTest(const std::string& testName, TestOption option);
74
75 /**
76 * Callback invoked when PHY starts transmission of a PSDU, used to record TX start
77 * time and TX duration.
78 *
79 * @param context the context
80 * @param psduMap the PSDU map
81 * @param txVector the TX vector
82 * @param txPower the tx power in Watts
83 */
84 void Transmit(std::string context,
85 WifiConstPsduMap psduMap,
86 WifiTxVector txVector,
87 Watt_u txPower);
88
89 private:
90 TestOption m_option; //!< Test option
91 NodeContainer m_wifiApNode; //!< NodeContainer for AP
92 NodeContainer m_wifiStaNodes; //!< NodeContainer for STAs
93 int64_t m_streamNumber; //!< Random variable stream number
94 Time m_sifs; //!< SIFS time
95 Time m_slot; //!< slot time
96
97 Time m_difs; //!< DIFS time (for SINGLE_LINK_NON_QOS case only)
98 std::map<uint8_t, std::vector<Time>> m_txStartTimes; //!< Map of independently obtain vector of
99 //!< PhyTxBegin trace, indexed per link
100 std::map<uint8_t, std::vector<Time>>
101 m_durations; //!< Map of vector of MPDU durations, indexed per link
102 std::map<uint8_t, uint32_t> m_cwMins; //!< Map of CW Mins, indexed per link
103 std::map<uint8_t, uint32_t>
104 m_aifsns; //!< Map of AIFSNs, indexed per link (for MULTI_LINK_QOS case only)
105 std::map<uint8_t, Time>
106 m_aifss; //!< Map of AIFSs, indexed per link (for MULTI_LINK_QOS case only)
107
108 void DoSetup() override;
109 void DoRun() override;
110 /**
111 * Check correctness of test
112 * @param wifiTxStats Reference to the helper
113 */
114 void CheckResults(const WifiTxStatsHelper& wifiTxStats);
115};
116
118 : TestCase(testName),
119 m_option(option),
120 m_streamNumber(100)
121{
122}
123
124void
126 WifiConstPsduMap psduMap,
127 WifiTxVector txVector,
128 Watt_u txPower)
129{
130 const auto linkId = atoi(context.c_str());
131 if (linkId == 0)
132 {
133 m_txStartTimes[0].push_back(Simulator::Now());
134 m_durations[0].push_back(
136 }
137 else if (linkId == 1)
138 {
139 m_txStartTimes[1].push_back(Simulator::Now());
140 m_durations[1].push_back(
142 }
143 NS_LOG_INFO("LINKID=" << +linkId << " " << *psduMap.cbegin()->second << "\n");
144}
145
146void
148{
151
152 m_wifiApNode.Create(1);
153 m_wifiStaNodes.Create(1);
154
155 MobilityHelper mobility;
156 auto positionAlloc = CreateObject<ListPositionAllocator>();
157 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
158 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
159 mobility.SetPositionAllocator(positionAlloc);
160 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
161 mobility.Install(m_wifiApNode);
162 mobility.Install(m_wifiStaNodes);
163
164 PacketSocketHelper packetSocket;
165 packetSocket.Install(m_wifiApNode);
166 packetSocket.Install(m_wifiStaNodes);
167}
168
169void
171{
172 Config::SetDefault("ns3::WifiRemoteStationManager::IncrementRetryCountUnderBa",
173 BooleanValue(true));
174 std::string dataMode;
175 std::string ackMode;
177 {
178 dataMode = "OfdmRate12Mbps";
179 ackMode = "OfdmRate6Mbps";
180 }
181 else
182 {
183 dataMode = "EhtMcs6";
184 ackMode = "OfdmRate54Mbps";
185 }
186
187 WifiHelper wifi;
188 NetDeviceContainer staDevices;
189 NetDeviceContainer apDevices;
191 {
192 wifi.SetStandard(WIFI_STANDARD_80211a);
193 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
194 "DataMode",
195 StringValue(dataMode),
196 "ControlMode",
197 StringValue(ackMode));
198 auto spectrumChannel = CreateObject<SingleModelSpectrumChannel>();
200 spectrumChannel->AddPropagationLossModel(lossModel);
202 spectrumChannel->SetPropagationDelayModel(delayModel);
203
205 phy.SetChannel(spectrumChannel);
206
207 WifiMacHelper mac;
208 mac.SetType("ns3::StaWifiMac",
209 "QosSupported",
210 BooleanValue(false),
211 "Ssid",
212 SsidValue(Ssid("test-ssid")));
213 staDevices = wifi.Install(phy, mac, m_wifiStaNodes);
214
215 mac.SetType("ns3::ApWifiMac",
216 "QosSupported",
217 BooleanValue(false),
218 "Ssid",
219 SsidValue(Ssid("test-ssid")),
220 "BeaconInterval",
222 "EnableBeaconJitter",
223 BooleanValue(false));
224 apDevices = wifi.Install(phy, mac, m_wifiApNode);
225 }
226 else
227 {
228 wifi.SetStandard(WIFI_STANDARD_80211be);
229 // Get channel string for MLD STA
230 std::array<std::string, 2> mldChannelStr;
231 uint32_t frequency = 5;
232 uint32_t frequency2 = 6;
233 for (auto freq : {frequency, frequency2})
234 {
235 NS_TEST_ASSERT_MSG_EQ((freq == 5 || freq == 6), true, "Unsupported frequency for BSS");
236 if (freq == 6)
237 {
238 mldChannelStr[1] = "{0, 20, BAND_6GHZ, 0}";
239 uint8_t linkId = 1;
240 wifi.SetRemoteStationManager(linkId,
241 "ns3::ConstantRateWifiManager",
242 "DataMode",
243 StringValue(dataMode),
244 "ControlMode",
245 StringValue(ackMode));
246 }
247 else
248 {
249 mldChannelStr[0] = "{0, 20, BAND_5GHZ, 0}";
250 // linkId is passed as a variable here because MSVC
251 // interprets uint8_t as a char, and the 0 value as a
252 // c-string null terminator \0. This results into a
253 // compilation error due to SetRemoteStationManager(uint8_t,...)
254 // and SetRemoteStationManager(std::string, ...) signatures.
255 uint8_t linkId = 0;
256 wifi.SetRemoteStationManager(linkId,
257 "ns3::ConstantRateWifiManager",
258 "DataMode",
259 StringValue(dataMode),
260 "ControlMode",
261 StringValue(ackMode));
262 }
263 }
264
266
268 auto spectrumChannel1 = CreateObject<MultiModelSpectrumChannel>();
269 spectrumChannel1->AddPropagationLossModel(lossModel);
270 auto spectrumChannel2 = CreateObject<MultiModelSpectrumChannel>();
271 spectrumChannel2->AddPropagationLossModel(lossModel);
272
273 phy.AddChannel(spectrumChannel1, WIFI_SPECTRUM_5_GHZ);
274 phy.AddChannel(spectrumChannel2, WIFI_SPECTRUM_6_GHZ);
275
276 for (uint8_t linkId = 0; linkId < 2; ++linkId)
277 {
278 phy.Set(linkId, "ChannelSettings", StringValue(mldChannelStr[linkId]));
279 }
280
281 WifiMacHelper mac;
282 mac.SetType("ns3::StaWifiMac",
283 "QosSupported",
284 BooleanValue(true),
285 "Ssid",
286 SsidValue(Ssid("test-ssid")));
287 staDevices = wifi.Install(phy, mac, m_wifiStaNodes);
288
289 mac.SetType("ns3::ApWifiMac",
290 "QosSupported",
291 BooleanValue(true),
292 "Ssid",
293 SsidValue(Ssid("test-ssid")),
294 "BeaconInterval",
296 "EnableBeaconJitter",
297 BooleanValue(false));
298 apDevices = wifi.Install(phy, mac, m_wifiApNode);
299 }
300
301 m_sifs = DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetPhy()->GetSifs();
302 m_slot = DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetPhy()->GetSlot();
304 {
305 m_difs = m_sifs + 2 * m_slot;
307 DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetMac()->GetTxop()->GetMinCw();
308 }
309 else
310 {
311 // Use TID-to-link Mapping to tx TID=3 pkts (BE) only on link 0,
312 // TID=4 pkts (VI) only on link 1
313 m_cwMins[0] = 15;
314 m_cwMins[1] = 7;
315 m_aifsns[0] = 3;
316 m_aifsns[1] = 2;
317 m_aifss[0] = m_aifsns[0] * m_slot + m_sifs;
318 m_aifss[1] = m_aifsns[1] * m_slot + m_sifs;
319 std::string mldMappingStr = "3 0; 4 1";
320 DynamicCast<WifiNetDevice>(staDevices.Get(0))
321 ->GetMac()
322 ->GetEhtConfiguration()
323 ->SetAttribute("TidToLinkMappingUl", StringValue(mldMappingStr));
324 }
325
326 auto streamsUsed = WifiHelper::AssignStreams(apDevices, m_streamNumber);
327 NS_ASSERT_MSG(streamsUsed < 100, "Need to increment by larger quantity");
328 WifiHelper::AssignStreams(staDevices, m_streamNumber + 100);
329
330 // UL traffic (TX statistics will be installed at STA side)
331 PacketSocketAddress socket;
332 socket.SetSingleDevice(staDevices.Get(0)->GetIfIndex());
333 socket.SetPhysicalAddress(apDevices.Get(0)->GetAddress());
334 auto server = CreateObject<PacketSocketServer>();
335 server->SetLocal(socket);
336 m_wifiApNode.Get(0)->AddApplication(server);
337 server->SetStartTime(Seconds(0.0));
338 server->SetStopTime(Seconds(1.0));
340 {
341 auto client = CreateObject<PacketSocketClient>();
342 client->SetAttribute("PacketSize", UintegerValue(1500));
343 client->SetAttribute("MaxPackets", UintegerValue(3));
344 client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
345 client->SetRemote(socket);
346 m_wifiStaNodes.Get(0)->AddApplication(client);
347 client->SetStartTime(MicroSeconds(210000));
348 client->SetStopTime(Seconds(1.0));
349 }
350 else
351 {
352 auto clientBe = CreateObject<PacketSocketClient>();
353 clientBe->SetAttribute("Priority", UintegerValue(3));
354 clientBe->SetAttribute("PacketSize", UintegerValue(1500));
355 clientBe->SetAttribute("MaxPackets", UintegerValue(3));
356 clientBe->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
357 clientBe->SetRemote(socket);
358 m_wifiStaNodes.Get(0)->AddApplication(clientBe);
359 clientBe->SetStartTime(MicroSeconds(200000));
360 clientBe->SetStopTime(Seconds(1.0));
361
362 auto clientVi = CreateObject<PacketSocketClient>();
363 clientVi->SetAttribute("Priority", UintegerValue(4));
364 clientVi->SetAttribute("PacketSize", UintegerValue(1500));
365 clientVi->SetAttribute("MaxPackets", UintegerValue(3));
366 clientVi->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
367 clientVi->SetRemote(socket);
368 m_wifiStaNodes.Get(0)->AddApplication(clientVi);
369 clientVi->SetStartTime(MicroSeconds(300000));
370 clientVi->SetStopTime(Seconds(1.0));
371 }
372
373 // Add AP side receiver corruption
375 {
376 // We corrupt AP side reception so that:
377 // 1) the 2nd data frame is retransmitted and succeeds (1 failure, 1 success)
378 // 2) the 3rd data frame is transmitted 7 times (=FrameRetryLimit) and finally fails (7
379 // failures, 0 success)
380 //
381 // No. of pkt | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
382 // No. recvd by AP | | | 0 | | | 1 | | 2 | | AP's
383 // pkts | Bea | Bea | | Ack | AsRes | | Bea | | Ack1 |
384 // STA's pkts | | | AsReq | | | Ack | | Data1 | |
385 //
386 // No. of pkt | 9 | 10 | 11 | 12 | 13 | ... | 18 | 19 | ...
387 // No. recvd by AP | 3 (x) | 4 | | 5 (x) | 6 (x) | ... |11 (x) | | ...
388 // AP's pkts | | | Ack2 | | | ... | | Bea | ...
389 // STA's pkts | Data2 | Data2 | | Data3 | Data3 | ... | Data3 | | ...
390 //
391 // Legend:
392 // Bea = Beacon, AsReq = Association Request, AsRes = Association Response
393 // AP side corruption is indicated with (x)
394
396 apPem->SetList({3, 5, 6, 7, 8, 9, 10, 11});
397 DynamicCast<WifiNetDevice>(apDevices.Get(0))
398 ->GetMac()
399 ->GetWifiPhy()
400 ->SetPostReceptionErrorModel(apPem);
401 }
402 else
403 {
404 // We corrupt AP side reception so that:
405 // On Link 0 (contains uplink data with TID = 3):
406 // 1) the 2nd data frame is retransmitted once and succeeds (retransmission = 1)
407 // 2) the 3rd data frame is transmitted 2 times within A-MPDU and 7 times alone
408 // (WifiMac::FrameRetryLimit) and finally fails (retransmission = 8)
409 //
410 // No. of PSDU | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
411 // No. recvd by AP | | | 0 | | | 1 | 2 | |
412 // AP's pkts | Bea | Bea | | Ack | AsRes | | | Ack |
413 // STA's pkts | | | AsReq | | | Ack | ABReq | |
414 //
415 // No. of PSDU | 8 | 9 | 10 | 10 | 10 | 11 | 12 | 12 |
416 // No. recvd by AP | | 3 | 4 | 5(x) | 6(x) | | 7 | 8(x) |
417 // AP's pkts | ABRes | | | | | BAck | | |
418 // STA's pkts | | Ack | Data1 | Data2 | Data3 | | Data2 | Data3 |
419 //
420 // No. of PSDU | 13 | 14 | ... | | ... | 21 | 22 | 23 | ...
421 // No. recvd by AP | | 9(x) | ... | | ... | 15(x) | 16 | | ...
422 // AP's pkts | BAck | | ... | Bea | ... | | | BAck | ...
423 // STA's pkts | | Data3 | ... | | ... | Data3 | Bar | | ...
424 //
425 // On Link 1 (contains uplink data with TID = 4):
426 // 1) the 2nd data frame is transmitted 2 times within A-MPDU and 7 times alone
427 // (=WifiMac::FrameRetryLimit) and finally fails (retransmission = 8)
428 // 2) the 3rd data frame is
429 // retransmitted once and succeeds (retransmission = 1)
430 //
431 // No. of PSDU | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
432 // No. recvd by AP | | | 0 | | | 1 | | 2 | |
433 // AP's pkts | Bea | Bea | | Ack | Bea | | Ack | | ABRes |
434 // STA's pkts | | | Null | | | ABReq | | CfEnd | |
435 //
436 // No. of PSDU | 9 | 10 | 11 | 11 | 11 | 12 | 13 | 13 | 14 |
437 // No. recvd by AP | 3 | | 4 | 5(x) | 6(x) | | 7(x) | 8 | |
438 // AP's pkts | | CfEnd | | | | BAck | | | BAck |
439 // STA's pkts | Ack | | Data1 | Data2 | Data3 | | Data2 | Data3 | |
440 //
441 // No. of PSDU | 15 | ... | 21 | 22 | 23 | 24 | ...
442 // No. recvd by AP | 9(x) | ... | 15(x) | 16 | | 17 | ...
443 // AP's pkts | | ... | | | BAck | | ...
444 // STA's pkts | Data2 | ... | Data2 | Bar | | CfEnd | ...
445 //
446 // Legend:
447 // Bea = Beacon, AsReq = Association Request, AsRes = Association Response
448 // ABReq = Add Block ACK Request, ABRes = Add Block ACK Response
449 // Bar = Block ACK Request (used to notify the discarded MPDU)
450 // CfEnd = CF-End, BAck = Block ACK (Response), Null = Null function
451 // AP side corruption is indicated with (x)
452
453 // Force drops on link 0 at AP
455 apPem0->SetList({5, 6, 8, 9, 10, 11, 12, 13, 14, 15});
456 DynamicCast<WifiNetDevice>(apDevices.Get(0))
457 ->GetMac()
458 ->GetWifiPhy(0)
459 ->SetPostReceptionErrorModel(apPem0);
460
461 // Force drops on link 1 at AP
463 apPem1->SetList({5, 6, 7, 9, 10, 11, 12, 13, 14, 15});
464 DynamicCast<WifiNetDevice>(apDevices.Get(0))
465 ->GetMac()
466 ->GetWifiPhy(1)
467 ->SetPostReceptionErrorModel(apPem1);
468 }
469
470 NetDeviceContainer allNetDev;
471 allNetDev.Add(apDevices);
472 allNetDev.Add(staDevices);
473 WifiTxStatsHelper wifiTxStats;
474 wifiTxStats.Enable(allNetDev);
475 wifiTxStats.Start(Seconds(0));
476 wifiTxStats.Stop(Seconds(1));
477
478 // Trace PSDU TX at both AP and STA to get start times and durations, including acks
480 {
481 for (auto it = allNetDev.Begin(); it != allNetDev.End(); ++it)
482 {
483 auto dev = DynamicCast<WifiNetDevice>(*it);
484 dev->GetPhy()->TraceConnect("PhyTxPsduBegin",
485 std::to_string(SINGLE_LINK_OP_ID),
486 // "0"
488 }
489 }
490 else
491 {
492 for (auto it = allNetDev.Begin(); it != allNetDev.End(); ++it)
493 {
494 auto dev = DynamicCast<WifiNetDevice>(*it);
495 dev->GetPhy(0)->TraceConnect("PhyTxPsduBegin",
496 "0",
498 dev->GetPhy(1)->TraceConnect("PhyTxPsduBegin",
499 "1",
501 }
502 }
503
506 CheckResults(wifiTxStats);
508}
509
510void
512{
513 const auto tolerance = NanoSeconds(50); // due to propagation delay
514 // Check both variants of GetSuccesses...()
515 const auto successMap = wifiTxStats.GetSuccessesByNodeDevice();
516 const auto successMapPerNodeDeviceLink = wifiTxStats.GetSuccessesByNodeDeviceLink();
517 const auto failureMap = wifiTxStats.GetFailuresByNodeDevice();
518 const auto retransmissionMap = wifiTxStats.GetRetransmissionsByNodeDevice();
519 const auto totalSuccesses = wifiTxStats.GetSuccesses();
520 const auto totalFailures = wifiTxStats.GetFailures();
521 const auto totalRetransmissions = wifiTxStats.GetRetransmissions();
522 const auto& successRecords = wifiTxStats.GetSuccessRecords();
523 const auto& failureRecords = wifiTxStats.GetFailureRecords();
524
525 uint32_t nodeId = 1;
526 uint32_t deviceId = 0;
527 auto nodeDeviceTuple = std::make_tuple(nodeId, deviceId);
528 auto nodeDeviceLink0Tuple = std::make_tuple(nodeId, deviceId, 0);
529 auto nodeDeviceLink1Tuple = std::make_tuple(nodeId, deviceId, 1);
530
532 {
533 const auto totalFailuresDrop =
535 const auto totalFailuresDropMap = wifiTxStats.GetFailuresByNodeDevice(
537
538 NS_TEST_ASSERT_MSG_EQ(successMapPerNodeDeviceLink.at(nodeDeviceLink0Tuple),
539 2,
540 "Number of success packets should be 2");
541 NS_TEST_ASSERT_MSG_EQ(successMap.at(nodeDeviceTuple),
542 2,
543 "Number of success packets should be 2");
544 NS_TEST_ASSERT_MSG_EQ(totalSuccesses, 2, "Number of success packets should be 2");
545
546 NS_TEST_ASSERT_MSG_EQ(retransmissionMap.at(nodeDeviceTuple),
547 1,
548 "Number of retransmitted successful packets should be 1");
549 NS_TEST_ASSERT_MSG_EQ(totalRetransmissions,
550 1,
551 "Number of retransmitted successful packets should be 1");
552
553 NS_TEST_ASSERT_MSG_EQ(failureMap.at(nodeDeviceTuple),
554 1,
555 "Number of failed packets should be 1");
556 NS_TEST_ASSERT_MSG_EQ(totalFailures, 1, "Number of failed packets (aggregate) should be 1");
558 totalFailuresDrop,
559 1,
560 "Number of dropped packets (aggregate) due to retry limit reached should be 1");
562 totalFailuresDropMap.at(nodeDeviceTuple),
563 1,
564 "Number of dropped packets (aggregate) due to retry limit reached should be 1");
565
566 auto successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
567 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_nodeId,
568 1,
569 "Source node ID of the 1st successful data packet should be 1");
570 std::advance(successRecordIt, 1);
571 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_nodeId,
572 1,
573 "Source node ID of the 2nd successful data packet should be 1");
574 auto failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
575 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_nodeId,
576 1,
577 "Source node ID of the failed data packet should be 1");
578
579 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
581 successRecordIt->m_retransmissions,
582 0,
583 "The retransmission count of the 1st successful data packet should be 0");
584 std::advance(successRecordIt, 1);
586 successRecordIt->m_retransmissions,
587 1,
588 "The retransmission count of the 2nd successful data packet should be 1");
589 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_retransmissions,
590 6,
591 "The retransmission count of the failed data packet should be 6");
592
593 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
594 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime.IsStrictlyPositive(),
595 true,
596 "The 1st successful data packet should have been TXed");
597 std::advance(successRecordIt, 1);
598 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime.IsStrictlyPositive(),
599 true,
600 "The 2nd successful data packet should have been TXed");
601 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime.IsStrictlyPositive(),
602 true,
603 "The failed data packet should have been TXed");
604
605 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
606 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
607 true,
608 "The 1st successful data packet should have been acked");
609 std::advance(successRecordIt, 1);
610 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
611 true,
612 "The 2nd successful data packet should have been acked");
613 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_ackTime.IsStrictlyPositive(),
614 false,
615 "The failed data packet should not have been acked");
616
617 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
618 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
619 true,
620 "The 1st successful data packet should have been dequeued");
621 std::advance(successRecordIt, 1);
622 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
623 true,
624 "The 2nd successful data packet should have been dequeued");
625 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
626 failureRecordIt->m_dropTime.value().IsStrictlyPositive(),
627 true,
628 "The failed data packet should have been dequeued");
629
630 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
631 auto successRecordItNext = successRecordIt;
632 std::advance(successRecordItNext, 1);
633 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_enqueueTime,
634 successRecordItNext->m_enqueueTime,
635 "Three packets should be enqueued at the same time");
636 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_enqueueTime,
637 failureRecordIt->m_enqueueTime,
638 "Three packets should be enqueued at the same time");
639
640 successRecordIt = successRecords.at(nodeDeviceLink0Tuple).begin();
641 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordIt->m_txStartTime,
642 successRecordIt->m_enqueueTime,
643 "Packets should be TXed after enqueued");
644 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordIt->m_txStartTime,
645 successRecordIt->m_enqueueTime + tolerance +
647 "Packet backoff slots should not exceed cwMin");
648 // Packet start time 7 corresponds to first data packet (prior to this, beacons and assoc)
649 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime,
651 "Wrong TX start time");
652 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordIt->m_ackTime,
656 "Wrong Ack reception time");
657 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordIt->m_ackTime,
660 m_durations[SINGLE_LINK_OP_ID][8] + 2 * tolerance,
661 "Wrong Ack reception time");
662 std::advance(successRecordIt, 1);
663 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordIt->m_txStartTime,
666 "Packets should be TXed after enqueued");
667 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordIt->m_txStartTime,
669 m_durations[SINGLE_LINK_OP_ID][8] + m_difs + tolerance +
671 "Packet backoff slots should not exceed cwMin");
672 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime,
674 "Wrong TX start time");
675 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordIt->m_ackTime,
679 "Wrong Ack reception time");
681 successRecordIt->m_ackTime,
684 ((m_cwMins[SINGLE_LINK_OP_ID] + 1) * 2 - 1) * m_slot + 2 * tolerance,
685 "Wrong Ack reception time");
686
687 NS_TEST_ASSERT_MSG_GT_OR_EQ(failureRecordIt->m_txStartTime,
690 "Packets should be TXed after enqueued");
691 NS_TEST_ASSERT_MSG_LT_OR_EQ(failureRecordIt->m_txStartTime,
693 m_durations[SINGLE_LINK_OP_ID][11] + m_difs + tolerance +
695 "Packet backoff slots should not exceed cwMin");
696 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime,
698 "Wrong TX start time");
699 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
700 failureRecordIt->m_dropReason.has_value(),
701 true,
702 "Missing drop time or reason");
703 NS_TEST_ASSERT_MSG_GT_OR_EQ(failureRecordIt->m_dropTime.value(),
706 "Wrong Dequeue time for failed packet");
707 NS_TEST_ASSERT_MSG_LT_OR_EQ(failureRecordIt->m_dropTime.value(),
711 "Wrong Dequeue time for failed packet");
712 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropReason.value(),
714 "Wrong drop reason");
715 }
716 else
717 {
718 const auto totalFailuresQos =
720 const auto totalFailuresQosMap =
722
723 for (std::vector<Time>::size_type i = 0; i < m_txStartTimes[0].size(); ++i)
724 {
725 NS_LOG_INFO("link 0 pkt " << i << " start tx at " << m_txStartTimes[0][i].As(Time::US));
726 }
727 for (std::vector<Time>::size_type i = 0; i < m_txStartTimes[1].size(); ++i)
728 {
729 NS_LOG_INFO("link 1 pkt " << i << " start tx at " << m_txStartTimes[1][i].As(Time::US));
730 }
731
732 NS_TEST_ASSERT_MSG_EQ(successMapPerNodeDeviceLink.at(nodeDeviceLink0Tuple),
733 2,
734 "Number of success packets on link 0 should be 2");
735 NS_TEST_ASSERT_MSG_EQ(successMapPerNodeDeviceLink.at(nodeDeviceLink1Tuple),
736 2,
737 "Number of success packets on link 1 should be 2");
738 NS_TEST_ASSERT_MSG_EQ(successMap.at(nodeDeviceTuple),
739 4,
740 "Number of success packets should be 4");
741 NS_TEST_ASSERT_MSG_EQ(totalSuccesses, 4, "Number of success packets should be 4");
742
743 NS_TEST_ASSERT_MSG_EQ(retransmissionMap.at(nodeDeviceTuple),
744 2,
745 "Number of retransmitted successful packets should be 2");
746 NS_TEST_ASSERT_MSG_EQ(totalRetransmissions,
747 2,
748 "Number of retransmitted successful packets (aggregate) should be 2");
749 NS_TEST_ASSERT_MSG_EQ(failureMap.at(nodeDeviceTuple),
750 2,
751 "Number of failed packets should be 2");
752 NS_TEST_ASSERT_MSG_EQ(totalFailures, 2, "Number of failed packets (aggregate) should be 2");
753 NS_TEST_ASSERT_MSG_EQ(totalFailuresQos,
754 2,
755 "Number of dropped packets (aggregate) by QosTxop should be 2");
756 NS_TEST_ASSERT_MSG_EQ(totalFailuresQosMap.at(nodeDeviceTuple),
757 2,
758 "Number of dropped packets (aggregate) by QosTxop should be 2");
759
760 auto successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
762 successRecordLink0It->m_nodeId,
763 1,
764 "Source node ID of the 1st successful data packet on link 0 should be 1");
765 std::advance(successRecordLink0It, 1);
767 successRecordLink0It->m_nodeId,
768 1,
769 "Source node ID of the 2nd successful data packet on link 0 should be 1");
770 auto successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
772 successRecordLink1It->m_nodeId,
773 1,
774 "Source node ID of the 1st successful data packet on link 0 should be 1");
775 std::advance(successRecordLink1It, 1);
777 successRecordLink1It->m_nodeId,
778 1,
779 "Source node ID of the 2nd successful data packet on link 0 should be 1");
780 auto failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
781 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_nodeId,
782 1,
783 "Source node ID of the failed data packet on link 0 should be 1");
784 std::advance(failureRecordIt, 1);
785 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_nodeId,
786 1,
787 "Source node ID of the failed data packet on link 1 should be 1");
788
789 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
790 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_deviceId,
791 0,
792 "Device ID of the 1st successful data packet on link 0 should be 0");
793 std::advance(successRecordLink0It, 1);
794 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_deviceId,
795 0,
796 "Device ID of the 2nd successful data packet on link 0 should be 0");
797 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
798 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_deviceId,
799 0,
800 "Device ID of the 1st successful data packet on link 0 should be 0");
801 std::advance(successRecordLink1It, 1);
802 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_deviceId,
803 0,
804 "Device ID of the 2nd successful data packet on link 1 should be 0");
805 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
806 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_deviceId,
807 0,
808 "Device ID of the failed data packet on link 1 should be 0");
809 std::advance(failureRecordIt, 1);
810 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_deviceId,
811 0,
812 "Device ID of the failed data packet on link 1 should be 0");
813
814 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
816 *successRecordLink0It->m_successLinkIdSet.begin(),
817 0,
818 "Successful link ID of the 1st successful data packet on link 0 should be 0");
819 std::advance(successRecordLink0It, 1);
821 *successRecordLink0It->m_successLinkIdSet.begin(),
822 0,
823 "Successful link ID of the 2nd successful data packet on link 0 should be 0");
824 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
826 *successRecordLink1It->m_successLinkIdSet.begin(),
827 1,
828 "Successful link ID of the 1st successful data packet on link 1 should be 1");
829 std::advance(successRecordLink1It, 1);
831 *successRecordLink1It->m_successLinkIdSet.begin(),
832 1,
833 "Successful link ID of the 2nd successful data packet on link 1 should be 1");
834 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
836 failureRecordIt->m_successLinkIdSet.empty(),
837 true,
838 "Successful link ID set of the failed data packet on link 0 should be empty");
839 std::advance(failureRecordIt, 1);
841 failureRecordIt->m_successLinkIdSet.empty(),
842 true,
843 "Successful link ID set of the failed data packet on link 1 should be empty");
844
845 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
847 successRecordLink0It->m_retransmissions,
848 0,
849 "The 1st successful data packet on link 0 should have no retransmissions");
850 std::advance(successRecordLink0It, 1);
852 successRecordLink0It->m_retransmissions,
853 1,
854 "The 2nd successful data packet on link 0 should have 1 retransmission");
855 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
857 successRecordLink1It->m_retransmissions,
858 0,
859 "The 1st successful data packet on link 1 should have no retransmissions");
860 std::advance(successRecordLink1It, 1);
862 successRecordLink1It->m_retransmissions,
863 1,
864 "The 2nd successful data packet on link 1 should have 1 retransmission");
865 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
866 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_retransmissions,
867 8,
868 "The failed data packet on link 0 should have 8 retransmissions");
869 std::advance(failureRecordIt, 1);
870 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_retransmissions,
871 8,
872 "The failed data packet on link 1 should have 8 retransmissions");
873
874 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
875 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_tid,
876 3,
877 "The 1st successful data packet on link 0 should have a TID of 3");
878 std::advance(successRecordLink0It, 1);
879 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_tid,
880 3,
881 "The 2nd successful data packet on link 0 should have a TID of 3");
882 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
883 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_tid,
884 4,
885 "The 1st successful data packet on link 1 should have a TID of 4");
886 std::advance(successRecordLink1It, 1);
887 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_tid,
888 4,
889 "The 2nd successful data packet on link 1 should have a TID of 4");
890 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
891 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_tid,
892 3,
893 "The failed data packet on link 0 should have a TID of 3");
894 std::advance(failureRecordIt, 1);
895 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_tid,
896 4,
897 "The failed data packet on link 1 should have a TID of 4");
898
899 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
901 successRecordLink0It->m_mpduSeqNum,
902 0,
903 "The 1st successful data packet on link 0 should have a Seq Num of 0");
904 std::advance(successRecordLink0It, 1);
906 successRecordLink0It->m_mpduSeqNum,
907 1,
908 "The 2nd successful data packet on link 0 should have a Seq Num of 1");
909 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
911 successRecordLink1It->m_mpduSeqNum,
912 0,
913 "The 1st successful data packet on link 1 should have a Seq Num of 0");
914 std::advance(successRecordLink1It, 1);
916 successRecordLink1It->m_mpduSeqNum,
917 2,
918 "The 2nd successful data packet on link 1 should have a Seq Num of 2");
919 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
920 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_mpduSeqNum,
921 2,
922 "The failed data packet on link 0 should have a Seq Num of 2");
923 std::advance(failureRecordIt, 1);
924 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_mpduSeqNum,
925 1,
926 "The failed data packet on link 1 should have a Seq Num of 1");
927
928 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
929 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime.IsStrictlyPositive(),
930 true,
931 "The 1st successful data packet on link 0 should have been TXed");
932 std::advance(successRecordLink0It, 1);
933 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime.IsStrictlyPositive(),
934 true,
935 "The 2nd successful data packet on link 0 should have been TXed");
936 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
937 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime.IsStrictlyPositive(),
938 true,
939 "The 1st successful data packet on link 1 should have been TXed");
940 std::advance(successRecordLink1It, 1);
941 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime.IsStrictlyPositive(),
942 true,
943 "The 2nd successful data packet on link 1 should have been TXed");
944 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
945 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime.IsStrictlyPositive(),
946 true,
947 "The failed data packet on link 0 should have been TXed");
948 std::advance(failureRecordIt, 1);
949 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime.IsStrictlyPositive(),
950 true,
951 "The failed data packet on link 1 should have been TXed");
952
953 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
954 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
955 true,
956 "The 1st successful data packet on link 0 should have been acked");
957 std::advance(successRecordLink0It, 1);
958 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
959 true,
960 "The 2nd successful data packet on link 0 should have been acked");
961 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
962 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
963 true,
964 "The 1st successful data packet on link 1 should have been acked");
965 std::advance(successRecordLink1It, 1);
966 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
967 true,
968 "The 2nd successful data packet on link 1 should have been acked");
969 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
970 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_ackTime.IsStrictlyPositive(),
971 false,
972 "The failed data packet on link 0 should not have been acked");
973 std::advance(failureRecordIt, 1);
974 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_ackTime.IsStrictlyPositive(),
975 false,
976 "The failed data packet on link 1 should not have been acked");
977
978 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
979 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
980 true,
981 "The 1st successful data packet on link 0 should have been dequeued");
982 std::advance(successRecordLink0It, 1);
983 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
984 true,
985 "The 2nd successful data packet on link 0 should have been dequeued");
986 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
987 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
988 true,
989 "The 1st successful data packet on link 1 should have been dequeued");
990 std::advance(successRecordLink1It, 1);
991 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
992 true,
993 "The 2nd successful data packet on link 1 should have been dequeued");
994 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
995 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
996 failureRecordIt->m_dropReason.has_value(),
997 true,
998 "Missing drop time or reason");
999 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.value().IsStrictlyPositive(),
1000 true,
1001 "The failed data packet on link 0 should have been dequeued");
1002 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropReason.value(),
1004 "Wrong drop reason");
1005 std::advance(failureRecordIt, 1);
1006 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
1007 failureRecordIt->m_dropReason.has_value(),
1008 true,
1009 "Missing drop time or reason");
1010 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.value().IsStrictlyPositive(),
1011 true,
1012 "The failed data packet on link 1 should have been dequeued");
1013 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropReason.value(),
1015 "Wrong drop reason");
1016
1017 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1018 auto successRecordLink0ItNext = successRecordLink0It;
1019 std::advance(successRecordLink0ItNext, 1);
1020 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
1021 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_enqueueTime,
1022 successRecordLink0ItNext->m_enqueueTime,
1023 "Packets on link 0 should be enqueued at the same time");
1024 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_enqueueTime,
1025 failureRecordIt->m_enqueueTime,
1026 "Packets on link 0 should be enqueued at the same time");
1027 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1028 auto successRecordLink1ItNext = successRecordLink1It;
1029 std::advance(successRecordLink1ItNext, 1);
1030 std::advance(failureRecordIt, 1);
1031 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_enqueueTime,
1032 successRecordLink1ItNext->m_enqueueTime,
1033 "Packets on link 1 should be enqueued at the same time");
1034 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_enqueueTime,
1035 failureRecordIt->m_enqueueTime,
1036 "Packets on link 1 should be enqueued at the same time");
1037
1038 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1039 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_txStartTime,
1040 successRecordLink0It->m_enqueueTime,
1041 "The 1st data packet on link 0 should be TXed after enqueued");
1042 std::advance(successRecordLink0It, 1);
1043 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_txStartTime,
1044 successRecordLink0It->m_enqueueTime,
1045 "The 2nd data packet on link 0 should be TXed after enqueued");
1046 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1047 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_txStartTime,
1048 successRecordLink1It->m_enqueueTime,
1049 "The 1st data packet on link 1 should be TXed after enqueued");
1050 std::advance(successRecordLink1It, 1);
1051 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_txStartTime,
1052 successRecordLink1It->m_enqueueTime,
1053 "The 2nd data packet on link 1 should be TXed after enqueued");
1054 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
1055 NS_TEST_ASSERT_MSG_GT_OR_EQ(failureRecordIt->m_txStartTime,
1056 failureRecordIt->m_enqueueTime,
1057 "The 3rd data packet on link 0 should be TXed after enqueued");
1058 std::advance(failureRecordIt, 1);
1059 NS_TEST_ASSERT_MSG_GT_OR_EQ(failureRecordIt->m_txStartTime,
1060 failureRecordIt->m_enqueueTime,
1061 "The 3rd data packet on link 1 should be TXed after enqueued");
1062
1063 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1064 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_txStartTime,
1065 m_txStartTimes[0][9] + m_durations[0][9] + m_aifss[0],
1066 "link 0 pkt first tx should be after the 9th packet on link");
1067 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink0It->m_txStartTime,
1068 m_txStartTimes[0][9] + m_durations[0][9] + m_aifss[0] +
1069 tolerance + m_cwMins[0] * m_slot,
1070 "link 0 pkt first backoff should not exceed cwMin");
1071 successRecordLink0ItNext = successRecordLink0It;
1072 std::advance(successRecordLink0ItNext, 1);
1073 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
1074 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime,
1075 successRecordLink0ItNext->m_txStartTime,
1076 "3 pkts of link 0 should tx at the same time");
1077 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime,
1078 failureRecordIt->m_txStartTime,
1079 "3 pkts of link 0 should tx at the same time");
1080
1081 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1082 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_txStartTime,
1083 m_txStartTimes[1][10] + m_durations[1][10] + m_aifss[1],
1084 "link 1 pkt first tx should be after the 10th packet on link");
1085 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink1It->m_txStartTime,
1086 m_txStartTimes[1][10] + m_durations[1][10] + m_aifss[1] +
1087 tolerance + m_cwMins[1] * m_slot,
1088 "link 1 pkt first backoff should not exceed cwMin");
1089 successRecordLink1ItNext = successRecordLink1It;
1090 std::advance(successRecordLink1ItNext, 1);
1091 failureRecordIt = failureRecords.at(nodeDeviceTuple).begin();
1092 std::advance(failureRecordIt, 1);
1093 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime,
1094 successRecordLink1ItNext->m_txStartTime,
1095 "3 pkts of link 1 should tx at the same time");
1096 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime,
1097 failureRecordIt->m_txStartTime,
1098 "3 pkts of link 1 should tx at the same time");
1099
1100 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1101 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_ackTime,
1102 m_txStartTimes[0][10] + m_durations[0][10] + m_sifs +
1103 m_durations[0][11],
1104 "Wrong first Block Ack reception time on link 0");
1105 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink0It->m_ackTime,
1106 m_txStartTimes[0][10] + m_durations[0][10] + m_sifs +
1107 m_durations[0][11] + 2 * tolerance,
1108 "Wrong first Block Ack reception time on link 0");
1109 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1110 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_ackTime,
1111 m_txStartTimes[1][11] + m_durations[1][11] + m_sifs +
1112 m_durations[1][12],
1113 "Wrong first Block Ack reception time on link 1");
1114 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink1It->m_ackTime,
1115 m_txStartTimes[1][11] + m_durations[1][11] + m_sifs +
1116 m_durations[1][12] + 2 * tolerance,
1117 "Wrong first Block Ack reception time on link 1");
1118
1119 successRecordLink0It = successRecords.at(nodeDeviceLink0Tuple).begin();
1120 std::advance(successRecordLink0It, 1);
1121 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink0It->m_ackTime,
1122 m_txStartTimes[0][12] + m_durations[0][12] + m_sifs +
1123 m_durations[0][13],
1124 "Wrong second Block Ack reception time on link 0");
1125 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink0It->m_ackTime,
1126 m_txStartTimes[0][12] + m_durations[0][12] + m_sifs +
1127 m_durations[0][13] + 2 * tolerance,
1128 "Wrong second Block Ack reception time on link 0");
1129 successRecordLink1It = successRecords.at(nodeDeviceLink1Tuple).begin();
1130 std::advance(successRecordLink1It, 1);
1131 NS_TEST_ASSERT_MSG_GT_OR_EQ(successRecordLink1It->m_ackTime,
1132 m_txStartTimes[1][13] + m_durations[1][13] + m_sifs +
1133 m_durations[1][14],
1134 "Wrong second Block Ack reception time on link 1");
1135 NS_TEST_ASSERT_MSG_LT_OR_EQ(successRecordLink1It->m_ackTime,
1136 m_txStartTimes[1][13] + m_durations[1][13] + m_sifs +
1137 m_durations[1][14] + 2 * tolerance,
1138 "Wrong second Block Ack reception time on link 1");
1139 }
1140}
1141
1142/**
1143 * @ingroup wifi-test
1144 * @ingroup tests
1145 *
1146 * @brief WifiTxStatsHelper Test Suite
1147 */
1149{
1150 public:
1152};
1153
1155 : TestSuite("wifi-tx-stats-helper", Type::UNIT)
1156{
1157 // A test case to evaluate the transmission process of multiple Wi-Fi MAC Layer MPDUs in
1158 // a single link device. This testcase uses .11a to test the handling of regular ACKs.
1159 //
1160 // This class tests the WifiTxStatsHelper output by creating three transmission cases:
1161 // 1) packet is sent successfully on the first try
1162 // 2) packet is lost on the first try but successfully transmitted on the second try
1163 // 3) packet is lost on all seven tries and a failure is logged
1164 // The MPDU losses are forced by the use of WifiPhy post-reception error model.
1165 //
1166 // This test also connects to the PHY trace PhyTxPsduBegin and records the sequence of
1167 // transmission times and packet durations observed at the PHY layer, to cross-check against
1168 // the times recorded in the WifiTxStatsHelper record (traced at the MAC layer).
1169 // The testcase also checks the various fields in this helper's output records for correctness.
1170 // AddTestCase(new WifiTxStatsHelperTest("Check single link non-QoS configuration",
1171 // WifiTxStatsHelperTest::SINGLE_LINK_NON_QOS),
1172 // TestCase::Duration::QUICK);
1173
1174 // A test case to evaluate the transmission process of multiple Wi-Fi MAC Layer MPDUs in
1175 // a multi link device. This testcase, unlike the previous, uses .11be to test the
1176 // handling of MPDU aggregation, Block ACKs, and Multi-Link Operation.
1177 //
1178 // This class tests the WifiTxStatsHelper output by creating three transmission cases:
1179 // 1) packet is sent successfully on the first try
1180 // 2) packet is lost on the first try (in an A-MPDU) but successfully transmitted on the
1181 // second try (also in an A-MPDU)
1182 // 3) packet is lost on all 9 tries (first 2 in A-MPDU, other 7 alone) and a failure is logged
1183 // The MPDU losses are forced by the use of WifiPhy post-reception error model.
1184 //
1185 // This test also connects to the PHY trace PhyTxPsduBegin and records the sequence of
1186 // transmission times and packet durations observed at the PHY layer, to cross-check against
1187 // the times recorded in the WifiTxStatsHelper record (traced at the MAC layer).
1188 // The testcase also checks the various fields in this helper's output records for correctness.
1189 AddTestCase(new WifiTxStatsHelperTest("Check multi-link QoS configuration",
1192}
1193
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.
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:125
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
static void Run()
Run the simulation.
Definition simulator.cc:161
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:169
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
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:296
@ QUICK
Fast test.
Definition test.h:1057
TestCase(const TestCase &)=delete
Caller graph was not generated because of its size.
Type
Type of test.
Definition test.h:1271
TestSuite(std::string name, Type type=Type::UNIT)
Construct a new test suite.
Definition test.cc:494
Simulation virtual time values and global simulation resolution.
Definition nstime.h:95
@ US
microsecond
Definition nstime.h:108
AttributeValue implementation for Time.
Definition nstime.h:1375
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:1574
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
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:690
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:194
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:267
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:627
#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:133
#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:739
#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:904
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1307
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1324
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1273
@ WIFI_STANDARD_80211a
@ WIFI_STANDARD_80211be
@ WIFI_MAC_DROP_QOS_OLD_PACKET
Definition wifi-mac.h:75
@ WIFI_MAC_DROP_REACHED_RETRY_LIMIT
Definition wifi-mac.h:74
@ 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.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:605
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:295
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
double Watt_u
Watt weak type.
Definition wifi-units.h:25
const Time DEFAULT_BEACON_INTERVAL
Default Beacon interval.
static WifiTxStatsHelperTestSuite g_wifiTxStatsHelperTestSuite
the test suite