A Discrete-Event Network Simulator
API
rr-multi-user-scheduler.cc
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Stefano Avallone <stavallo@unina.it>
19 */
20
21#include "ns3/log.h"
23#include "ns3/wifi-protection.h"
24#include "ns3/wifi-acknowledgment.h"
25#include "ns3/wifi-psdu.h"
27#include "he-configuration.h"
28#include "he-phy.h"
29#include <algorithm>
30
31namespace ns3 {
32
33NS_LOG_COMPONENT_DEFINE ("RrMultiUserScheduler");
34
35NS_OBJECT_ENSURE_REGISTERED (RrMultiUserScheduler);
36
37TypeId
39{
40 static TypeId tid = TypeId ("ns3::RrMultiUserScheduler")
42 .SetGroupName ("Wifi")
43 .AddConstructor<RrMultiUserScheduler> ()
44 .AddAttribute ("NStations",
45 "The maximum number of stations that can be granted an RU in a DL MU OFDMA transmission",
46 UintegerValue (4),
48 MakeUintegerChecker<uint8_t> (1, 74))
49 .AddAttribute ("EnableTxopSharing",
50 "If enabled, allow A-MPDUs of different TIDs in a DL MU PPDU.",
51 BooleanValue (true),
54 .AddAttribute ("ForceDlOfdma",
55 "If enabled, return DL_MU_TX even if no DL MU PPDU could be built.",
56 BooleanValue (false),
59 .AddAttribute ("EnableUlOfdma",
60 "If enabled, return UL_MU_TX if DL_MU_TX was returned the previous time.",
61 BooleanValue (true),
64 .AddAttribute ("EnableBsrp",
65 "If enabled, send a BSRP Trigger Frame before an UL MU transmission.",
66 BooleanValue (true),
69 .AddAttribute ("UlPsduSize",
70 "The default size in bytes of the solicited PSDU (to be sent in a TB PPDU)",
71 UintegerValue (500),
73 MakeUintegerChecker<uint32_t> ())
74 .AddAttribute ("UseCentral26TonesRus",
75 "If enabled, central 26-tone RUs are allocated, too, when the "
76 "selected RU type is at least 52 tones.",
77 BooleanValue (false),
80 .AddAttribute ("MaxCredits",
81 "Maximum amount of credits a station can have. When transmitting a DL MU PPDU, "
82 "the amount of credits received by each station equals the TX duration (in "
83 "microseconds) divided by the total number of stations. Stations that are the "
84 "recipient of the DL MU PPDU have to pay a number of credits equal to the TX "
85 "duration (in microseconds) times the allocated bandwidth share",
86 TimeValue (Seconds (1)),
89 ;
90 return tid;
91}
92
94{
95 NS_LOG_FUNCTION (this);
96}
97
99{
101}
102
103void
105{
106 NS_LOG_FUNCTION (this);
107 NS_ASSERT (m_apMac != nullptr);
108 m_apMac->TraceConnectWithoutContext ("AssociatedSta",
110 m_apMac->TraceConnectWithoutContext ("DeAssociatedSta",
112 for (const auto& ac : wifiAcList)
113 {
114 m_staList.insert ({ac.first, {}});
115 }
117}
118
119void
121{
122 NS_LOG_FUNCTION (this);
123 m_staList.clear ();
124 m_candidates.clear ();
125 m_txParams.Clear ();
126 m_apMac->TraceDisconnectWithoutContext ("AssociatedSta",
128 m_apMac->TraceDisconnectWithoutContext ("DeAssociatedSta",
131}
132
135{
136 NS_LOG_FUNCTION (this);
137
139
140 if (mpdu != 0 && !GetWifiRemoteStationManager ()->GetHeSupported (mpdu->GetHeader ().GetAddr1 ()))
141 {
142 return SU_TX;
143 }
144
146 {
147 return TrySendingBsrpTf ();
148 }
149
152 {
153 TxFormat txFormat = TrySendingBasicTf ();
154
155 if (txFormat != DL_MU_TX)
156 {
157 return txFormat;
158 }
159 }
160
161 return TrySendingDlMuPpdu ();
162}
163
166{
167 NS_LOG_FUNCTION (this);
168
170
173
174 Ptr<Packet> packet = Create<Packet> ();
175 packet->AddHeader (m_trigger);
176
178 if (m_trigger.GetNUserInfoFields () == 1)
179 {
180 NS_ASSERT (m_apMac->GetStaList ().find (m_trigger.begin ()->GetAid12 ()) != m_apMac->GetStaList ().end ());
181 receiver = m_apMac->GetStaList ().at (m_trigger.begin ()->GetAid12 ());
182 }
183
185 m_triggerMacHdr.SetAddr1 (receiver);
186 m_triggerMacHdr.SetAddr2 (m_apMac->GetAddress ());
189
190 Ptr<WifiMacQueueItem> item = Create<WifiMacQueueItem> (packet, m_triggerMacHdr);
191
192 m_txParams.Clear ();
193 // set the TXVECTOR used to send the Trigger Frame
194 m_txParams.m_txVector = m_apMac->GetWifiRemoteStationManager ()->GetRtsTxVector (receiver);
195
196 if (!m_heFem->TryAddMpdu (item, m_txParams, m_availableTime))
197 {
198 // sending the BSRP Trigger Frame is not possible, hence return NO_TX. In
199 // this way, no transmission will occur now and the next time we will
200 // try again sending a BSRP Trigger Frame.
201 NS_LOG_DEBUG ("Remaining TXOP duration is not enough for BSRP TF exchange");
202 return NO_TX;
203 }
204
205 // Compute the time taken by each station to transmit 8 QoS Null frames
206 Time qosNullTxDuration = Seconds (0);
207 for (const auto& userInfo : m_trigger)
208 {
210 m_apMac->GetWifiPhy ()->GetPhyBand (),
211 userInfo.GetAid12 ());
212 qosNullTxDuration = Max (qosNullTxDuration, duration);
213 }
214
215 if (m_availableTime != Time::Min ())
216 {
217 // TryAddMpdu only considers the time to transmit the Trigger Frame
219 NS_ASSERT (m_txParams.m_acknowledgment && m_txParams.m_acknowledgment->acknowledgmentTime.IsZero ());
221
222 if (m_txParams.m_protection->protectionTime
223 + m_txParams.m_txDuration // BSRP TF tx time
224 + m_apMac->GetWifiPhy ()->GetSifs ()
225 + qosNullTxDuration
227 {
228 NS_LOG_DEBUG ("Remaining TXOP duration is not enough for BSRP TF exchange");
229 return NO_TX;
230 }
231 }
232
233 uint16_t ulLength;
234 std::tie (ulLength, qosNullTxDuration) = HePhy::ConvertHeTbPpduDurationToLSigLength (qosNullTxDuration,
235 m_trigger.GetHeTbTxVector (m_trigger.begin ()->GetAid12 ()),
236 m_apMac->GetWifiPhy ()->GetPhyBand ());
237 NS_LOG_DEBUG ("Duration of QoS Null frames: " << qosNullTxDuration.As (Time::MS));
238 m_trigger.SetUlLength (ulLength);
239
240 return UL_MU_TX;
241}
242
245{
246 NS_LOG_FUNCTION (this);
247
248 // check if an UL OFDMA transmission is possible after a DL OFDMA transmission
249 NS_ABORT_MSG_IF (m_ulPsduSize == 0, "The UlPsduSize attribute must be set to a non-null value");
250
251 // determine which of the stations served in DL have UL traffic
252 uint32_t maxBufferSize = 0;
253 // candidates sorted in decreasing order of queue size
254 std::multimap<uint8_t, CandidateInfo, std::greater<uint8_t>> ulCandidates;
255
256 for (const auto& candidate : m_candidates)
257 {
258 uint8_t queueSize = m_apMac->GetMaxBufferStatus (candidate.first->address);
259 if (queueSize == 255)
260 {
261 NS_LOG_DEBUG ("Buffer status of station " << candidate.first->address << " is unknown");
262 maxBufferSize = std::max (maxBufferSize, m_ulPsduSize);
263 }
264 else if (queueSize == 254)
265 {
266 NS_LOG_DEBUG ("Buffer status of station " << candidate.first->address << " is not limited");
267 maxBufferSize = 0xffffffff;
268 }
269 else
270 {
271 NS_LOG_DEBUG ("Buffer status of station " << candidate.first->address << " is " << +queueSize);
272 maxBufferSize = std::max (maxBufferSize, static_cast<uint32_t> (queueSize * 256));
273 }
274 // serve the station if its queue size is not null
275 if (queueSize > 0)
276 {
277 ulCandidates.emplace (queueSize, candidate);
278 }
279 }
280
281 // if the maximum buffer size is 0, skip UL OFDMA and proceed with trying DL OFDMA
282 if (maxBufferSize > 0)
283 {
284 NS_ASSERT (!ulCandidates.empty ());
285 std::size_t count = ulCandidates.size ();
286 std::size_t nCentral26TonesRus;
287 HeRu::RuType ruType = HeRu::GetEqualSizedRusForStations (m_apMac->GetWifiPhy ()->GetChannelWidth (),
288 count, nCentral26TonesRus);
289 if (!m_useCentral26TonesRus || ulCandidates.size () == count)
290 {
291 nCentral26TonesRus = 0;
292 }
293 else
294 {
295 nCentral26TonesRus = std::min (ulCandidates.size () - count, nCentral26TonesRus);
296 }
297
298 WifiTxVector txVector;
300 auto candidateIt = ulCandidates.begin ();
301
302 if (GetLastTxFormat () == DL_MU_TX)
303 {
304 txVector.SetChannelWidth (GetDlMuInfo ().txParams.m_txVector.GetChannelWidth ());
305 txVector.SetGuardInterval (CtrlTriggerHeader ().GetGuardInterval ());
306
307 for (std::size_t i = 0; i < count + nCentral26TonesRus; i++)
308 {
309 NS_ASSERT (candidateIt != ulCandidates.end ());
310 uint16_t staId = candidateIt->second.first->aid;
311 // AssignRuIndices will be called below to set RuSpec
312 txVector.SetHeMuUserInfo (staId,
313 {{(i < count ? ruType : HeRu::RU_26_TONE), 1, false},
316
317 candidateIt++;
318 }
319 }
320 else
321 {
324
325 for (std::size_t i = 0; i < count + nCentral26TonesRus; i++)
326 {
327 NS_ASSERT (candidateIt != ulCandidates.end ());
328 uint16_t staId = candidateIt->second.first->aid;
329 auto userInfoIt = GetUlMuInfo ().trigger.FindUserInfoWithAid (staId);
330 NS_ASSERT (userInfoIt != GetUlMuInfo ().trigger.end ());
331 // AssignRuIndices will be called below to set RuSpec
332 txVector.SetHeMuUserInfo (staId,
333 {{(i < count ? ruType : HeRu::RU_26_TONE), 1, false},
334 HePhy::GetHeMcs (userInfoIt->GetUlMcs ()),
335 userInfoIt->GetNss ()});
336
337 candidateIt++;
338 }
339 }
340
341 // remove candidates that will not be served
342 ulCandidates.erase (candidateIt, ulCandidates.end ());
343 AssignRuIndices (txVector);
344
346 Ptr<Packet> packet = Create<Packet> ();
347 packet->AddHeader (m_trigger);
348
350 if (ulCandidates.size () == 1)
351 {
352 receiver = ulCandidates.begin ()->second.first->address;
353 }
354
356 m_triggerMacHdr.SetAddr1 (receiver);
357 m_triggerMacHdr.SetAddr2 (m_apMac->GetAddress ());
360
361 Ptr<WifiMacQueueItem> item = Create<WifiMacQueueItem> (packet, m_triggerMacHdr);
362
363 // compute the maximum amount of time that can be granted to stations.
364 // This value is limited by the max PPDU duration
365 Time maxDuration = GetPpduMaxTime (txVector.GetPreambleType ());
366
367 m_txParams.Clear ();
368 // set the TXVECTOR used to send the Trigger Frame
369 m_txParams.m_txVector = m_apMac->GetWifiRemoteStationManager ()->GetRtsTxVector (receiver);
370
371 if (!m_heFem->TryAddMpdu (item, m_txParams, m_availableTime))
372 {
373 // an UL OFDMA transmission is not possible, hence return NO_TX. In
374 // this way, no transmission will occur now and the next time we will
375 // try again performing an UL OFDMA transmission.
376 NS_LOG_DEBUG ("Remaining TXOP duration is not enough for UL MU exchange");
377 return NO_TX;
378 }
379
380 if (m_availableTime != Time::Min ())
381 {
382 // TryAddMpdu only considers the time to transmit the Trigger Frame
386
387 maxDuration = Min (maxDuration, m_availableTime
388 - m_txParams.m_protection->protectionTime
390 - m_apMac->GetWifiPhy ()->GetSifs ()
391 - m_txParams.m_acknowledgment->acknowledgmentTime);
392 if (maxDuration.IsNegative ())
393 {
394 NS_LOG_DEBUG ("Remaining TXOP duration is not enough for UL MU exchange");
395 return NO_TX;
396 }
397 }
398
399 // Compute the time taken by each station to transmit a frame of maxBufferSize size
400 Time bufferTxTime = Seconds (0);
401 for (const auto& userInfo : m_trigger)
402 {
403 Time duration = WifiPhy::CalculateTxDuration (maxBufferSize, txVector,
404 m_apMac->GetWifiPhy ()->GetPhyBand (),
405 userInfo.GetAid12 ());
406 bufferTxTime = Max (bufferTxTime, duration);
407 }
408
409 if (bufferTxTime < maxDuration)
410 {
411 // the maximum buffer size can be transmitted within the allowed time
412 maxDuration = bufferTxTime;
413 }
414 else
415 {
416 // maxDuration may be a too short time. If it does not allow any station to
417 // transmit at least m_ulPsduSize bytes, give up the UL MU transmission for now
418 Time minDuration = Seconds (0);
419 for (const auto& userInfo : m_trigger)
420 {
421 Time duration = WifiPhy::CalculateTxDuration (m_ulPsduSize, txVector,
422 m_apMac->GetWifiPhy ()->GetPhyBand (),
423 userInfo.GetAid12 ());
424 minDuration = (minDuration.IsZero () ? duration : Min (minDuration, duration));
425 }
426
427 if (maxDuration < minDuration)
428 {
429 // maxDuration is a too short time, hence return NO_TX. In this way,
430 // no transmission will occur now and the next time we will try again
431 // performing an UL OFDMA transmission.
432 NS_LOG_DEBUG ("Available time " << maxDuration.As (Time::MS) << " is too short");
433 return NO_TX;
434 }
435 }
436
437 // maxDuration is the time to grant to the stations. Finalize the Trigger Frame
438 uint16_t ulLength;
439 std::tie (ulLength, maxDuration) = HePhy::ConvertHeTbPpduDurationToLSigLength (maxDuration,
440 txVector,
441 m_apMac->GetWifiPhy ()->GetPhyBand ());
442 NS_LOG_DEBUG ("TB PPDU duration: " << maxDuration.As (Time::MS));
443 m_trigger.SetUlLength (ulLength);
444 // set Preferred AC to the AC that gained channel access
445 for (auto& userInfo : m_trigger)
446 {
447 userInfo.SetBasicTriggerDepUserInfo (0, 0, m_edca->GetAccessCategory ());
448 }
449
450 return UL_MU_TX;
451 }
452 return DL_MU_TX;
453}
454
455void
457{
458 NS_LOG_FUNCTION (this << aid << address);
459
460 if (GetWifiRemoteStationManager ()->GetHeSupported (address))
461 {
462 for (auto& staList : m_staList)
463 {
464 staList.second.push_back (MasterInfo {aid, address, 0.0});
465 }
466 }
467}
468
469void
471{
472 NS_LOG_FUNCTION (this << aid << address);
473
474 if (GetWifiRemoteStationManager ()->GetHeSupported (address))
475 {
476 for (auto& staList : m_staList)
477 {
478 staList.second.remove_if ([&aid, &address] (const MasterInfo& info)
479 { return info.aid == aid && info.address == address; });
480 }
481 }
482}
483
486{
487 NS_LOG_FUNCTION (this);
488
489 AcIndex primaryAc = m_edca->GetAccessCategory ();
490
491 if (m_staList[primaryAc].empty ())
492 {
493 NS_LOG_DEBUG ("No HE stations associated: return SU_TX");
494 return TxFormat::SU_TX;
495 }
496
497 std::size_t count = std::min (static_cast<std::size_t> (m_nStations), m_staList[primaryAc].size ());
498 std::size_t nCentral26TonesRus;
499 HeRu::RuType ruType = HeRu::GetEqualSizedRusForStations (m_apMac->GetWifiPhy ()->GetChannelWidth (), count,
500 nCentral26TonesRus);
501 NS_ASSERT (count >= 1);
502
504 {
505 nCentral26TonesRus = 0;
506 }
507
508 uint8_t currTid = wifiAcList.at (primaryAc).GetHighTid ();
509
511
512 if (mpdu != nullptr && mpdu->GetHeader ().IsQosData ())
513 {
514 currTid = mpdu->GetHeader ().GetQosTid ();
515 }
516
517 // determine the list of TIDs to check
518 std::vector<uint8_t> tids;
519
521 {
522 for (auto acIt = wifiAcList.find (primaryAc); acIt != wifiAcList.end (); acIt++)
523 {
524 uint8_t firstTid = (acIt->first == primaryAc ? currTid : acIt->second.GetHighTid ());
525 tids.push_back (firstTid);
526 tids.push_back (acIt->second.GetOtherTid (firstTid));
527 }
528 }
529 else
530 {
531 tids.push_back (currTid);
532 }
533
534 Ptr<HeConfiguration> heConfiguration = m_apMac->GetHeConfiguration ();
535 NS_ASSERT (heConfiguration != 0);
536
537 m_txParams.Clear ();
539 m_txParams.m_txVector.SetChannelWidth (m_apMac->GetWifiPhy ()->GetChannelWidth ());
540 m_txParams.m_txVector.SetGuardInterval (heConfiguration->GetGuardInterval ().GetNanoSeconds ());
541 m_txParams.m_txVector.SetBssColor (heConfiguration->GetBssColor ());
542
543 // The TXOP limit can be exceeded by the TXOP holder if it does not transmit more
544 // than one Data or Management frame in the TXOP and the frame is not in an A-MPDU
545 // consisting of more than one MPDU (Sec. 10.22.2.8 of 802.11-2016).
546 // For the moment, we are considering just one MPDU per receiver.
547 Time actualAvailableTime = (m_initialFrame ? Time::Min () : m_availableTime);
548
549 // iterate over the associated stations until an enough number of stations is identified
550 auto staIt = m_staList[primaryAc].begin ();
551 m_candidates.clear ();
552
553 while (staIt != m_staList[primaryAc].end ()
554 && m_candidates.size () < std::min (static_cast<std::size_t> (m_nStations), count + nCentral26TonesRus))
555 {
556 NS_LOG_DEBUG ("Next candidate STA (MAC=" << staIt->address << ", AID=" << staIt->aid << ")");
557
558 HeRu::RuType currRuType = (m_candidates.size () < count ? ruType : HeRu::RU_26_TONE);
559
560 // check if the AP has at least one frame to be sent to the current station
561 for (uint8_t tid : tids)
562 {
563 AcIndex ac = QosUtilsMapTidToAc (tid);
564 NS_ASSERT (ac >= primaryAc);
565 // check that a BA agreement is established with the receiver for the
566 // considered TID, since ack sequences for DL MU PPDUs require block ack
567 if (m_apMac->GetQosTxop (ac)->GetBaAgreementEstablished (staIt->address, tid))
568 {
569 mpdu = m_apMac->GetQosTxop (ac)->PeekNextMpdu (tid, staIt->address);
570
571 // we only check if the first frame of the current TID meets the size
572 // and duration constraints. We do not explore the queues further.
573 if (mpdu != 0)
574 {
575 // Use a temporary TX vector including only the STA-ID of the
576 // candidate station to check if the MPDU meets the size and time limits.
577 // An RU of the computed size is tentatively assigned to the candidate
578 // station, so that the TX duration can be correctly computed.
579 WifiTxVector suTxVector = GetWifiRemoteStationManager ()->GetDataTxVector (mpdu->GetHeader ()),
580 txVectorCopy = m_txParams.m_txVector;
581
583 {{currRuType, 1, false},
584 suTxVector.GetMode (),
585 suTxVector.GetNss ()});
586
587 if (!m_heFem->TryAddMpdu (mpdu, m_txParams, actualAvailableTime))
588 {
589 NS_LOG_DEBUG ("Adding the peeked frame violates the time constraints");
590 m_txParams.m_txVector = txVectorCopy;
591 }
592 else
593 {
594 // the frame meets the constraints
595 NS_LOG_DEBUG ("Adding candidate STA (MAC=" << staIt->address << ", AID="
596 << staIt->aid << ") TID=" << +tid);
597 m_candidates.push_back ({staIt, mpdu});
598 break; // terminate the for loop
599 }
600 }
601 else
602 {
603 NS_LOG_DEBUG ("No frames to send to " << staIt->address << " with TID=" << +tid);
604 }
605 }
606 }
607
608 // move to the next station in the list
609 staIt++;
610 }
611
612 if (m_candidates.empty ())
613 {
614 if (m_forceDlOfdma)
615 {
616 NS_LOG_DEBUG ("The AP does not have suitable frames to transmit: return NO_TX");
617 return NO_TX;
618 }
619 NS_LOG_DEBUG ("The AP does not have suitable frames to transmit: return SU_TX");
620 return SU_TX;
621 }
622
623 return TxFormat::DL_MU_TX;
624}
625
626MultiUserScheduler::DlMuInfo
627RrMultiUserScheduler::ComputeDlMuInfo (void)
628{
629 NS_LOG_FUNCTION (this);
630
631 if (m_candidates.empty ())
632 {
633 return DlMuInfo ();
634 }
635
636 uint16_t bw = m_apMac->GetWifiPhy ()->GetChannelWidth ();
637
638 // compute how many stations can be granted an RU and the RU size
639 std::size_t nRusAssigned = m_txParams.GetPsduInfoMap ().size ();
640 std::size_t nCentral26TonesRus;
641 HeRu::RuType ruType = HeRu::GetEqualSizedRusForStations (bw, nRusAssigned, nCentral26TonesRus);
642
643 NS_LOG_DEBUG (nRusAssigned << " stations are being assigned a " << ruType << " RU");
644
645 if (!m_useCentral26TonesRus || m_candidates.size () == nRusAssigned)
646 {
647 nCentral26TonesRus = 0;
648 }
649 else
650 {
651 nCentral26TonesRus = std::min (m_candidates.size () - nRusAssigned, nCentral26TonesRus);
652 NS_LOG_DEBUG (nCentral26TonesRus << " stations are being assigned a 26-tones RU");
653 }
654
655 DlMuInfo dlMuInfo;
656
657 // We have to update the TXVECTOR
658 dlMuInfo.txParams.m_txVector.SetPreambleType (m_txParams.m_txVector.GetPreambleType ());
659 dlMuInfo.txParams.m_txVector.SetChannelWidth (m_txParams.m_txVector.GetChannelWidth ());
660 dlMuInfo.txParams.m_txVector.SetGuardInterval (m_txParams.m_txVector.GetGuardInterval ());
661 dlMuInfo.txParams.m_txVector.SetBssColor (m_txParams.m_txVector.GetBssColor ());
662
663 auto candidateIt = m_candidates.begin (); // iterator over the list of candidate receivers
664
665 for (std::size_t i = 0; i < nRusAssigned + nCentral26TonesRus; i++)
666 {
667 NS_ASSERT (candidateIt != m_candidates.end ());
668
669 uint16_t staId = candidateIt->first->aid;
670 // AssignRuIndices will be called below to set RuSpec
671 dlMuInfo.txParams.m_txVector.SetHeMuUserInfo (staId,
672 {{(i < nRusAssigned ? ruType : HeRu::RU_26_TONE), 1, false},
673 m_txParams.m_txVector.GetMode (staId),
674 m_txParams.m_txVector.GetNss (staId)});
675 candidateIt++;
676 }
677
678 // remove candidates that will not be served
679 m_candidates.erase (candidateIt, m_candidates.end ());
680
681 AssignRuIndices (dlMuInfo.txParams.m_txVector);
682 m_txParams.Clear ();
683
685
686 // Compute the TX params (again) by using the stored MPDUs and the final TXVECTOR
687 Time actualAvailableTime = (m_initialFrame ? Time::Min () : m_availableTime);
688
689 for (const auto& candidate : m_candidates)
690 {
691 mpdu = candidate.second;
692 NS_ASSERT (mpdu != nullptr);
693
694 [[maybe_unused]] bool ret = m_heFem->TryAddMpdu (mpdu, dlMuInfo.txParams, actualAvailableTime);
695 NS_ASSERT_MSG (ret, "Weird that an MPDU does not meet constraints when "
696 "transmitted over a larger RU");
697 }
698
699 // We have to complete the PSDUs to send
700 Ptr<WifiMacQueue> queue;
701 Mac48Address receiver;
702
703 for (const auto& candidate : m_candidates)
704 {
705 // Let us try first A-MSDU aggregation if possible
706 mpdu = candidate.second;
707 NS_ASSERT (mpdu != nullptr);
708 uint8_t tid = mpdu->GetHeader ().GetQosTid ();
709 receiver = mpdu->GetHeader ().GetAddr1 ();
710 NS_ASSERT (receiver == candidate.first->address);
711
712 NS_ASSERT (mpdu->IsQueued ());
713 Ptr<WifiMacQueueItem> item = mpdu->GetItem ();
714
715 if (!mpdu->GetHeader ().IsRetry ())
716 {
717 // this MPDU must have been dequeued from the AC queue and we can try
718 // A-MSDU aggregation
719 item = m_heFem->GetMsduAggregator ()->GetNextAmsdu (mpdu, dlMuInfo.txParams, m_availableTime);
720
721 if (item == nullptr)
722 {
723 // A-MSDU aggregation failed or disabled
724 item = mpdu->GetItem ();
725 }
726 m_apMac->GetQosTxop (QosUtilsMapTidToAc (tid))->AssignSequenceNumber (item);
727 }
728
729 // Now, let's try A-MPDU aggregation if possible
730 std::vector<Ptr<WifiMacQueueItem>> mpduList = m_heFem->GetMpduAggregator ()->GetNextAmpdu (item, dlMuInfo.txParams, m_availableTime);
731
732 if (mpduList.size () > 1)
733 {
734 // A-MPDU aggregation succeeded, update psduMap
735 dlMuInfo.psduMap[candidate.first->aid] = Create<WifiPsdu> (std::move (mpduList));
736 }
737 else
738 {
739 dlMuInfo.psduMap[candidate.first->aid] = Create<WifiPsdu> (item, true);
740 }
741 }
742
743 AcIndex primaryAc = m_edca->GetAccessCategory ();
744
745 // The amount of credits received by each station equals the TX duration (in
746 // microseconds) divided by the number of stations.
747 double creditsPerSta = dlMuInfo.txParams.m_txDuration.ToDouble (Time::US)
748 / m_staList[primaryAc].size ();
749 // Transmitting stations have to pay a number of credits equal to the TX duration
750 // (in microseconds) times the allocated bandwidth share.
751 double debitsPerMhz = dlMuInfo.txParams.m_txDuration.ToDouble (Time::US)
752 / (nRusAssigned * HeRu::GetBandwidth (ruType)
753 + nCentral26TonesRus * HeRu::GetBandwidth (HeRu::RU_26_TONE));
754
755 // assign credits to all stations
756 for (auto& sta : m_staList[primaryAc])
757 {
758 sta.credits += creditsPerSta;
759 sta.credits = std::min (sta.credits, m_maxCredits.ToDouble (Time::US));
760 }
761
762 // subtract debits to the selected stations
763 candidateIt = m_candidates.begin ();
764
765 for (std::size_t i = 0; i < nRusAssigned + nCentral26TonesRus; i++)
766 {
767 NS_ASSERT (candidateIt != m_candidates.end ());
768
769 candidateIt->first->credits -= debitsPerMhz * HeRu::GetBandwidth (i < nRusAssigned ? ruType : HeRu::RU_26_TONE);
770
771 candidateIt++;
772 }
773
774 // sort the list in decreasing order of credits
775 m_staList[primaryAc].sort ([] (const MasterInfo& a, const MasterInfo& b)
776 { return a.credits > b.credits; });
777
778 NS_LOG_DEBUG ("Next station to serve has AID=" << m_staList[primaryAc].front ().aid);
779
780 return dlMuInfo;
781}
782
783void
784RrMultiUserScheduler::AssignRuIndices (WifiTxVector& txVector)
785{
786 NS_LOG_FUNCTION (this << txVector);
787
788 uint8_t bw = txVector.GetChannelWidth ();
789
790 // find the RU types allocated in the TXVECTOR
791 std::set<HeRu::RuType> ruTypeSet;
792 for (const auto& userInfo : txVector.GetHeMuUserInfoMap ())
793 {
794 ruTypeSet.insert (userInfo.second.ru.GetRuType ());
795 }
796
797 std::vector<HeRu::RuSpec> ruSet, central26TonesRus;
798
799 // This scheduler allocates equal sized RUs and optionally the remaining 26-tone RUs
800 if (ruTypeSet.size () == 2)
801 {
802 // central 26-tone RUs have been allocated
803 NS_ASSERT (ruTypeSet.find (HeRu::RU_26_TONE) != ruTypeSet.end ());
804 ruTypeSet.erase (HeRu::RU_26_TONE);
805 NS_ASSERT (ruTypeSet.size () == 1);
806 central26TonesRus = HeRu::GetCentral26TonesRus (bw, *ruTypeSet.begin ());
807 }
808
809 NS_ASSERT (ruTypeSet.size () == 1);
810 ruSet = HeRu::GetRusOfType (bw, *ruTypeSet.begin ());
811
812 auto ruSetIt = ruSet.begin ();
813 auto central26TonesRusIt = central26TonesRus.begin ();
814
815 for (const auto& userInfo : txVector.GetHeMuUserInfoMap ())
816 {
817 if (userInfo.second.ru.GetRuType () == *ruTypeSet.begin ())
818 {
819 NS_ASSERT (ruSetIt != ruSet.end ());
820 txVector.SetRu (*ruSetIt, userInfo.first);
821 ruSetIt++;
822 }
823 else
824 {
825 NS_ASSERT (central26TonesRusIt != central26TonesRus.end ());
826 txVector.SetRu (*central26TonesRusIt, userInfo.first);
827 central26TonesRusIt++;
828 }
829 }
830}
831
833RrMultiUserScheduler::ComputeUlMuInfo (void)
834{
835 return UlMuInfo {m_trigger, m_triggerMacHdr, std::move (m_txParams)};
836}
837
838} //namespace ns3
#define min(a, b)
Definition: 80211b.c:42
#define max(a, b)
Definition: 80211b.c:43
#define Min(a, b)
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Headers for Trigger frames.
Definition: ctrl-headers.h:886
ConstIterator begin(void) const
Get a const iterator pointing to the first User Info field in the list.
WifiTxVector GetHeTbTxVector(uint16_t staId) const
Get the TX vector that the station with the given STA-ID will use to send the HE TB PPDU solicited by...
uint16_t GetUlBandwidth(void) const
Get the bandwidth of the solicited HE TB PPDU.
std::size_t GetNUserInfoFields(void) const
Get the number of User Info fields in this Trigger Frame.
ConstIterator FindUserInfoWithAid(ConstIterator start, uint16_t aid12) const
Get a const iterator pointing to the first User Info field found (starting from the one pointed to by...
TriggerFrameType GetType(void) const
Get the Trigger Frame type.
void SetUlLength(uint16_t len)
Set the UL Length subfield of the Common Info field.
uint16_t GetGuardInterval(void) const
Get the guard interval duration (in nanoseconds) of the solicited HE TB PPDU.
static WifiMode GetHeMcs(uint8_t index)
Return the HE MCS corresponding to the provided index.
Definition: he-phy.cc:1031
static std::pair< uint16_t, Time > ConvertHeTbPpduDurationToLSigLength(Time ppduDuration, const WifiTxVector &txVector, WifiPhyBand band)
Compute the L-SIG length value corresponding to the given HE TB PPDU duration.
Definition: he-phy.cc:274
RuType
The different HE Resource Unit (RU) types.
Definition: he-ru.h:42
@ RU_26_TONE
Definition: he-ru.h:43
static RuType GetEqualSizedRusForStations(uint16_t bandwidth, std::size_t &nStations, std::size_t &nCentral26TonesRus)
Given the channel bandwidth and the number of stations candidate for being assigned an RU,...
Definition: he-ru.cc:537
an EUI-48 address
Definition: mac48-address.h:44
static Mac48Address GetBroadcast(void)
MultiUserScheduler is an abstract base class defining the API that APs supporting at least VHT can us...
bool m_initialFrame
true if a TXOP is being started
void DoInitialize(void) override
Initialize() implementation.
Ptr< ApWifiMac > m_apMac
the AP wifi MAC
Time m_availableTime
the time available for frame exchange
void DoDispose(void) override
Destructor implementation.
TxFormat GetLastTxFormat(void) const
Get the format of the last transmission, as determined by the last call to NotifyAccessGranted that d...
Ptr< HeFrameExchangeManager > m_heFem
HE Frame Exchange Manager.
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(void) const
Get the station manager attached to the AP.
Ptr< QosTxop > m_edca
the AC that gained channel access
uint32_t m_sizeOf8QosNull
size in bytes of 8 QoS Null frames
UlMuInfo & GetUlMuInfo(void)
Get the information required to solicit an UL MU transmission.
DlMuInfo & GetDlMuInfo(void)
Get the information required to perform a DL MU transmission.
TxFormat
Enumeration of the possible transmission formats.
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
AcIndex GetAccessCategory(void) const
Get the access category of this object.
Definition: qos-txop.cc:745
Ptr< const WifiMacQueueItem > PeekNextMpdu(uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast(), Ptr< const WifiMacQueueItem > item=nullptr)
Peek the next frame to transmit to the given receiver and of the given TID from the EDCA queue.
Definition: qos-txop.cc:357
RrMultiUserScheduler is a simple OFDMA scheduler that indicates to perform a DL OFDMA transmission if...
virtual TxFormat TrySendingBsrpTf(void)
Check if it is possible to send a BSRP Trigger Frame given the current time limits.
void DoDispose(void) override
Destructor implementation.
bool m_enableBsrp
send a BSRP before an UL MU transmission
void NotifyStationAssociated(uint16_t aid, Mac48Address address)
Notify the scheduler that a station associated with the AP.
uint32_t m_ulPsduSize
the size in byte of the solicited PSDU
std::list< CandidateInfo > m_candidates
Candidate stations for MU TX.
bool m_useCentral26TonesRus
whether to allocate central 26-tone RUs
bool m_forceDlOfdma
return DL_OFDMA even if no DL MU PPDU was built
bool m_enableUlOfdma
enable the scheduler to also return UL_OFDMA
virtual TxFormat TrySendingDlMuPpdu(void)
Check if it is possible to send a DL MU PPDU given the current time limits.
WifiMacHeader m_triggerMacHdr
MAC header for Trigger Frame.
TxFormat SelectTxFormat(void) override
Select the format of the next transmission.
uint8_t m_nStations
Number of stations/slots to fill.
WifiTxParameters m_txParams
TX parameters.
virtual TxFormat TrySendingBasicTf(void)
Check if it is possible to send a Basic Trigger Frame given the current time limits.
void AssignRuIndices(WifiTxVector &txVector)
Assign an RU index to all the RUs allocated by the given TXVECTOR.
void NotifyStationDeassociated(uint16_t aid, Mac48Address address)
Notify the scheduler that a station deassociated with the AP.
Time m_maxCredits
Max amount of credits a station can have.
std::map< AcIndex, std::list< MasterInfo > > m_staList
Per-AC list of stations (next to serve first)
bool m_enableTxopSharing
allow A-MPDUs of different TIDs in a DL MU PPDU
CtrlTriggerHeader m_trigger
Trigger Frame to send.
void DoInitialize(void) override
Initialize() implementation.
static TypeId GetTypeId(void)
Get the type ID.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
double ToDouble(enum Unit unit) const
Get the Time value expressed in a particular unit.
Definition: nstime.h:529
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
Definition: nstime.h:273
@ MS
millisecond
Definition: nstime.h:115
bool IsZero(void) const
Exactly equivalent to t == 0.
Definition: nstime.h:300
TimeWithUnit As(const enum Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:418
bool IsNegative(void) const
Exactly equivalent to t <= 0.
Definition: nstime.h:308
AttributeValue implementation for Time.
Definition: nstime.h:1308
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
Hold an unsigned integer type.
Definition: uinteger.h:44
Implements the IEEE 802.11 MAC header.
void SetDsNotFrom(void)
Un-set the From DS bit in the Frame Control field.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
void SetDsNotTo(void)
Un-set the To DS bit in the Frame Control field.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition: wifi-phy.cc:1335
WifiTxVector GetDataTxVector(const WifiMacHeader &header)
void Clear(void)
Reset the TX parameters.
std::unique_ptr< WifiProtection > m_protection
protection method
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
Time m_txDuration
TX duration of the frame.
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
WifiPreamble GetPreambleType(void) const
void SetRu(HeRu::RuSpec ru, uint16_t staId)
Set the RU specification for the STA-ID.
uint8_t GetNss(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the number of spatial streams.
const HeMuUserInfoMap & GetHeMuUserInfoMap(void) const
Get a const reference to the map HE MU user-specific transmission information indexed by STA-ID.
void SetBssColor(uint8_t color)
Set the BSS color.
uint16_t GetChannelWidth(void) const
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
make Callback use a separate empty type
Definition: empty.h:34
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:67
#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:88
Ptr< const AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:85
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1309
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:45
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
int64x64_t Max(const int64x64_t &a, const int64x64_t &b)
Maximum.
Definition: int64x64.h:230
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:218
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
AcIndex QosUtilsMapTidToAc(uint8_t tid)
Maps TID (Traffic ID) to Access classes.
Definition: qos-utils.cc:126
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition: qos-utils.h:71
@ WIFI_PREAMBLE_HE_TB
@ WIFI_PREAMBLE_HE_MU
@ BASIC_TRIGGER
Definition: ctrl-headers.h:562
@ BSRP_TRIGGER
Definition: ctrl-headers.h:566
Declaration of ns3::HePhy class and ns3::HeSigAParameters struct.
address
Definition: first.py:44
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Time GetPpduMaxTime(WifiPreamble preamble)
Get the maximum PPDU duration (see Section 10.14 of 802.11-2016) for the PHY layers defining the aPPD...
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:522
const std::map< AcIndex, WifiAc > wifiAcList
Map containing the four ACs in increasing order of priority (according to Table 10-1 "UP-to-AC Mappin...
Definition: qos-utils.cc:120
@ WIFI_MAC_CTL_TRIGGER
Callback< R, Ts... > MakeCallback(R(T::*memPtr)(Ts...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:1648
Information to be provided in case of DL MU transmission.
WifiTxParameters txParams
the transmission parameters
WifiPsduMap psduMap
the DL MU PPDU to transmit
Information to be provided in case of UL MU transmission.
CtrlTriggerHeader trigger
the Trigger Frame used to solicit TB PPDUs
Information used to sort stations.
Mac48Address address
station's MAC Address
double credits
credits accumulated by the station