A Discrete-Event Network Simulator
API
bs-uplink-scheduler-mbqos.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License version 2 as
4  * published by the Free Software Foundation;
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public License
12  * along with this program; if not, write to the Free Software
13  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14  *
15  */
16 
18 
19 #include "bandwidth-manager.h"
20 #include "bs-link-manager.h"
21 #include "bs-net-device.h"
22 #include "burst-profile-manager.h"
23 #include "cid.h"
24 #include "connection-manager.h"
25 #include "service-flow-record.h"
26 #include "service-flow.h"
27 #include "ss-manager.h"
28 
29 #include "ns3/log.h"
30 #include "ns3/simulator.h"
31 #include "ns3/uinteger.h"
32 
33 namespace ns3
34 {
35 
36 NS_LOG_COMPONENT_DEFINE("UplinkSchedulerMBQoS");
37 
38 NS_OBJECT_ENSURE_REGISTERED(UplinkSchedulerMBQoS);
39 
41 {
42 }
43 
45  : m_windowInterval(time)
46 {
47 }
48 
50 {
51  SetBs(nullptr);
52  m_uplinkAllocations.clear();
53 }
54 
55 TypeId
57 {
58  static TypeId tid = TypeId("ns3::UplinkSchedulerMBQoS")
59 
61 
62  .SetGroupName("Wimax")
63 
64  .AddAttribute("WindowInterval",
65  "The time to wait to reset window",
66  TimeValue(Seconds(1.0)),
68  MakeTimeChecker());
69  return tid;
70 }
71 
72 void
74 {
76 }
77 
78 std::list<OfdmUlMapIe>
80 {
81  return m_uplinkAllocations;
82 }
83 
84 void
86  bool& updateUcd,
87  bool& sendDcd,
88  bool& sendUcd)
89 {
90  /* DCD and UCD shall actually be updated when channel or burst profile definitions
91  change. burst profiles are updated based on number of SSs, network conditions and etc.
92  for now temporarily assuming DCD/UCD shall be updated every time */
93 
94  uint32_t randNr = rand();
95  if (randNr % 5 == 0 || GetBs()->GetNrDcdSent() == 0)
96  {
97  sendDcd = true;
98  }
99 
100  randNr = rand();
101  if (randNr % 5 == 0 || GetBs()->GetNrUcdSent() == 0)
102  {
103  sendUcd = true;
104  }
105 
106  // -------------------------------------
107  // additional, just to send more frequently
108  if (!sendDcd)
109  {
110  randNr = rand();
111  if (randNr % 4 == 0)
112  {
113  sendDcd = true;
114  }
115  }
116 
117  if (!sendUcd)
118  {
119  randNr = rand();
120  if (randNr % 4 == 0)
121  {
122  sendUcd = true;
123  }
124  }
125  // -------------------------------------
126 
127  Time timeSinceLastDcd = Simulator::Now() - GetDcdTimeStamp();
128  Time timeSinceLastUcd = Simulator::Now() - GetUcdTimeStamp();
129 
130  if (timeSinceLastDcd > GetBs()->GetDcdInterval())
131  {
132  sendDcd = true;
134  }
135 
136  if (timeSinceLastUcd > GetBs()->GetUcdInterval())
137  {
138  sendUcd = true;
140  }
141 }
142 
143 uint32_t
145 {
146  return GetBs()->GetNrDlSymbols() * GetBs()->GetPhy()->GetPsPerSymbol() + GetBs()->GetTtg();
147 }
148 
149 void
151  const uint32_t& allocationSize,
152  uint32_t& symbolsToAllocation,
153  uint32_t& availableSymbols)
154 {
155  ulMapIe.SetDuration(allocationSize);
156  ulMapIe.SetStartTime(symbolsToAllocation);
157  m_uplinkAllocations.push_back(ulMapIe);
158  symbolsToAllocation += allocationSize;
159  availableSymbols -= allocationSize;
160 }
161 
162 void
164 {
165  NS_LOG(LOG_DEBUG, "Window Reset at " << (Simulator::Now()).As(Time::S));
166 
167  uint32_t min_bw = 0;
168 
169  if (!GetBs()->GetSSManager())
170  {
172  return;
173  }
174 
175  std::vector<SSRecord*>* ssRecords = GetBs()->GetSSManager()->GetSSRecords();
176 
177  // For each SS
178  for (auto iter = ssRecords->begin(); iter != ssRecords->end(); ++iter)
179  {
180  SSRecord* ssRecord = *iter;
181  std::vector<ServiceFlow*> serviceFlows =
183 
184  // For each flow
185  for (auto iter2 = serviceFlows.begin(); iter2 != serviceFlows.end(); ++iter2)
186  {
187  ServiceFlow* serviceFlow = *iter2;
188  if ((serviceFlow->GetSchedulingType() == ServiceFlow::SF_TYPE_RTPS) ||
189  (serviceFlow->GetSchedulingType() == ServiceFlow::SF_TYPE_NRTPS))
190  {
191  min_bw = (int)ceil(serviceFlow->GetMinReservedTrafficRate());
192 
193  // This way we can compensate flows which did not get min_bw in the previous window
194  if ((serviceFlow->GetRecord()->GetBacklogged() > 0) &&
195  (serviceFlow->GetRecord()->GetBwSinceLastExpiry() < min_bw))
196  {
197  serviceFlow->GetRecord()->UpdateBwSinceLastExpiry(-min_bw);
198 
199  // if backlogged < granted_bw then we don't need to provide granted_bw + min_bw
200  // in next window, but backlogged + min_bw
201  if (serviceFlow->GetRecord()->GetBacklogged() <
202  (serviceFlow->GetRecord()->GetBwSinceLastExpiry()))
203  {
204  serviceFlow->GetRecord()->SetBwSinceLastExpiry(
205  -serviceFlow->GetRecord()->GetBacklogged());
206  }
207  }
208  else
209  {
210  serviceFlow->GetRecord()->SetBwSinceLastExpiry(0);
211  }
212  }
213  }
214  }
215 
216  // Periodically reset window
218 }
219 
220 void
222 {
223  m_uplinkAllocations.clear();
224  SetIsIrIntrvlAllocated(false);
226  bool allocationForDsa = false;
227 
228  uint32_t symbolsToAllocation = 0;
229  uint32_t allocationSize = 0; // size in symbols
230  uint32_t availableSymbols = GetBs()->GetNrUlSymbols();
231 
232  AllocateInitialRangingInterval(symbolsToAllocation, availableSymbols);
233 
234  std::vector<SSRecord*>* ssRecords = GetBs()->GetSSManager()->GetSSRecords();
235  for (auto iter = ssRecords->begin(); iter != ssRecords->end(); ++iter)
236  {
237  SSRecord* ssRecord = *iter;
238 
239  if (ssRecord->GetIsBroadcastSS())
240  {
241  continue;
242  }
243  Cid cid = ssRecord->GetBasicCid();
244  OfdmUlMapIe ulMapIe;
245  ulMapIe.SetCid(cid);
246 
247  if (ssRecord->GetPollForRanging() &&
249  {
250  // SS's ranging is not yet complete
251  // allocating invited initial ranging interval
253  allocationSize = GetBs()->GetRangReqOppSize();
255 
256  if (availableSymbols >= allocationSize)
257  {
258  AddUplinkAllocation(ulMapIe, allocationSize, symbolsToAllocation, availableSymbols);
259  }
260  else
261  {
262  break;
263  }
264  }
265  else
266  {
267  WimaxPhy::ModulationType modulationType = ssRecord->GetModulationType();
268 
269  // need to update because modulation/FEC to UIUC mapping may vary over time
270  ulMapIe.SetUiuc(GetBs()->GetBurstProfileManager()->GetBurstProfile(
271  modulationType,
273 
274  // establish service flows for SS
276  !ssRecord->GetAreServiceFlowsAllocated())
277  {
278  // allocating grant (with arbitrary size) to allow SS to send DSA messages DSA-REQ
279  // and DSA-ACK only one DSA allocation per frame
280  if (!allocationForDsa)
281  {
282  allocationSize =
283  GetBs()->GetPhy()->GetNrSymbols(sizeof(DsaReq), modulationType);
284 
285  if (availableSymbols >= allocationSize)
286  {
287  AddUplinkAllocation(ulMapIe,
288  allocationSize,
289  symbolsToAllocation,
290  availableSymbols);
291  allocationForDsa = true;
292  }
293  else
294  {
295  break;
296  }
297  }
298  }
299  else
300  {
301  // all service flows associated to SS are established now
302 
303  /* Implementation of uplink scheduler
304  * [1] Freitag, J.; da Fonseca, N.L.S., "Uplink Scheduling with Quality of Service
305  * in IEEE 802.16 Networks," Global Telecommunications Conference, 2007. GLOBECOM
306  * '07. IEEE , vol., no., pp.2503-2508, 26-30 Nov. 2007 URL:
307  * http://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=4411386&isnumber=4410910 */
308 
309  // Step 1
310  if (availableSymbols)
311  {
312  /*allocating grants for data transmission for UGS flows (Data Grant Burst Type
313  IEs, 6.3.7.4.3.3) (grant has been referred by different names e.g. transmission
314  opportunity, slot, uplink allocation, etc)*/
315  if (ssRecord->GetHasServiceFlowUgs())
316  {
317  NS_LOG_DEBUG("At " << Simulator::Now().As(Time::S)
318  << " offering be unicast polling");
319  // Recover period interval information for UGS flow
320  Time frame_duration = GetBs()->GetPhy()->GetFrameDuration();
321  Time timestamp =
322  (*(ssRecord->GetServiceFlows(ServiceFlow::SF_TYPE_UGS).begin()))
323  ->GetRecord()
324  ->GetLastGrantTime() +
325  MilliSeconds(
326  (*(ssRecord->GetServiceFlows(ServiceFlow::SF_TYPE_UGS).begin()))
327  ->GetUnsolicitedGrantInterval());
328 
329  int64_t frame = ((timestamp - Simulator::Now()) / frame_duration).GetHigh();
330 
331  if (frame <= 1)
332  {
333  // UGS Grants
334  // It is not necessary to enqueue UGS grants once it is periodically
335  // served
336  ServiceUnsolicitedGrants(ssRecord,
338  ulMapIe,
339  modulationType,
340  symbolsToAllocation,
341  availableSymbols);
342  }
343  }
344 
345  // enqueue allocate unicast polls for rtPS flows if bandwidth is available
346  if (ssRecord->GetHasServiceFlowRtps())
347  {
348  NS_LOG_DEBUG("At " << Simulator::Now().As(Time::S)
349  << " offering rtps unicast polling");
350  Ptr<UlJob> jobRTPSPoll =
352  EnqueueJob(UlJob::HIGH, jobRTPSPoll);
353  }
354 
355  if (ssRecord->GetHasServiceFlowNrtps())
356  {
357  NS_LOG_DEBUG("At " << Simulator::Now().As(Time::S)
358  << " offering nrtps unicast polling");
359  // allocate unicast polls for nrtPS flows if bandwidth is available
360  Ptr<UlJob> jobNRTPSPoll =
362  EnqueueJob(UlJob::HIGH, jobNRTPSPoll);
363  }
364 
365  if (ssRecord->GetHasServiceFlowBe())
366  {
367  NS_LOG_DEBUG("At " << Simulator::Now().As(Time::S)
368  << " offering be unicast polling");
369  // finally allocate unicast polls for BE flows if bandwidth is available
370  Ptr<UlJob> jobBEPoll =
372  EnqueueJob(UlJob::HIGH, jobBEPoll);
373  }
374  }
375  }
376  }
377  }
378  NS_LOG_DEBUG("At " << Simulator::Now().As(Time::S) << " high queue has "
379  << m_uplinkJobs_high.size() << " jobs - after sched");
380 
381  uint32_t availableSymbolsAux = availableSymbols;
382  uint32_t symbolsUsed = 0;
383 
384  symbolsUsed += CountSymbolsQueue(m_uplinkJobs_high);
385  availableSymbolsAux -= symbolsUsed;
386 
387  // Step 2 - Check Deadline - Migrate requests with deadline expiring
388  CheckDeadline(availableSymbolsAux);
389 
390  // Step 3 - Check Minimum Bandwidth
391  CheckMinimumBandwidth(availableSymbolsAux);
392 
393  // Scheduling high priority queue
394  NS_LOG_DEBUG("At " << Simulator::Now().As(Time::S) << " high queue has "
395  << m_uplinkJobs_high.size() << " jobs");
396  while ((availableSymbols) && (!m_uplinkJobs_high.empty()))
397  {
398  Ptr<UlJob> job = m_uplinkJobs_high.front();
399  OfdmUlMapIe ulMapIe;
400  SSRecord* ssRecord = job->GetSsRecord();
401  ServiceFlow::SchedulingType schedulingType = job->GetSchedulingType();
402 
403  Cid cid = ssRecord->GetBasicCid();
404  ulMapIe.SetCid(cid);
405  WimaxPhy::ModulationType modulationType = ssRecord->GetModulationType();
406  // need to update because modulation/FEC to UIUC mapping may vary over time
407  ulMapIe.SetUiuc(
408  GetBs()->GetBurstProfileManager()->GetBurstProfile(modulationType,
410 
411  ReqType reqType = job->GetType();
412 
413  if (reqType == UNICAST_POLLING)
414  {
415  ServiceUnsolicitedGrants(ssRecord,
416  schedulingType,
417  ulMapIe,
418  modulationType,
419  symbolsToAllocation,
420  availableSymbols);
421  }
422  else if (reqType == DATA)
423  {
424  ServiceFlow* serviceFlow = job->GetServiceFlow();
425  uint32_t allocSizeBytes = job->GetSize();
426  ServiceBandwidthRequestsBytes(serviceFlow,
427  schedulingType,
428  ulMapIe,
429  modulationType,
430  symbolsToAllocation,
431  availableSymbols,
432  allocSizeBytes);
433  }
434  m_uplinkJobs_high.pop_front();
435  }
436 
437  NS_LOG_DEBUG("At " << Simulator::Now().As(Time::S) << " interqueue has "
438  << m_uplinkJobs_inter.size() << " jobs");
439  /* Scheduling intermediate priority queue */
440  while ((availableSymbols) && (!m_uplinkJobs_inter.empty()))
441  {
442  NS_LOG_DEBUG("At " << Simulator::Now().As(Time::S) << " Scheduling interqueue");
443  Ptr<UlJob> job = m_uplinkJobs_inter.front();
444  OfdmUlMapIe ulMapIe;
445  SSRecord* ssRecord = job->GetSsRecord();
446  ServiceFlow::SchedulingType schedulingType = job->GetSchedulingType();
447 
448  Cid cid = ssRecord->GetBasicCid();
449  ulMapIe.SetCid(cid);
450  WimaxPhy::ModulationType modulationType = ssRecord->GetModulationType();
451  // need to update because modulation/FEC to UIUC mapping may vary over time
452  ulMapIe.SetUiuc(
453  GetBs()->GetBurstProfileManager()->GetBurstProfile(modulationType,
455 
456  ReqType reqType = job->GetType();
457 
458  if (reqType == DATA)
459  {
460  ServiceBandwidthRequests(ssRecord,
461  schedulingType,
462  ulMapIe,
463  modulationType,
464  symbolsToAllocation,
465  availableSymbols);
466  }
467  else
468  {
469  NS_FATAL_ERROR("Intermediate priority queue only should enqueue data packets.");
470  }
471  m_uplinkJobs_inter.pop_front();
472  }
473 
474  /* Scheduling low priority queue */
475  while ((availableSymbols) && (!m_uplinkJobs_low.empty()))
476  {
477  Ptr<UlJob> job = m_uplinkJobs_low.front();
478  OfdmUlMapIe ulMapIe;
479  SSRecord* ssRecord = job->GetSsRecord();
480  ServiceFlow::SchedulingType schedulingType = job->GetSchedulingType();
481 
482  Cid cid = ssRecord->GetBasicCid();
483  ulMapIe.SetCid(cid);
484  WimaxPhy::ModulationType modulationType = ssRecord->GetModulationType();
485  // need to update because modulation/FEC to UIUC mapping may vary over time
486  ulMapIe.SetUiuc(
487  GetBs()->GetBurstProfileManager()->GetBurstProfile(modulationType,
489 
490  ReqType reqType = job->GetType();
491 
492  if (reqType == DATA)
493  {
494  ServiceBandwidthRequests(ssRecord,
495  schedulingType,
496  ulMapIe,
497  modulationType,
498  symbolsToAllocation,
499  availableSymbols);
500  }
501  else
502  {
503  NS_FATAL_ERROR("Low priority queue only should enqueue data packets.");
504  }
505  m_uplinkJobs_low.pop_front();
506  }
507 
508  OfdmUlMapIe ulMapIeEnd;
509  ulMapIeEnd.SetCid(Cid(0));
510  ulMapIeEnd.SetStartTime(symbolsToAllocation);
512  ulMapIeEnd.SetDuration(0);
513  m_uplinkAllocations.push_back(ulMapIeEnd);
514 
515  // setting DL/UL subframe allocation for the next frame
516  GetBs()->GetBandwidthManager()->SetSubframeRatio();
517 }
518 
519 bool
521  ServiceFlow::SchedulingType schedulingType,
522  OfdmUlMapIe& ulMapIe,
523  const WimaxPhy::ModulationType modulationType,
524  uint32_t& symbolsToAllocation,
525  uint32_t& availableSymbols,
526  uint32_t allocationSizeBytes)
527 {
528  uint32_t allocSizeBytes = allocationSizeBytes;
529  uint32_t allocSizeSymbols = 0;
530 
531  ServiceFlowRecord* record = serviceFlow->GetRecord();
532 
533  uint32_t requiredBandwidth = record->GetRequestedBandwidth();
534 
535  if (requiredBandwidth > 0)
536  {
537  allocSizeSymbols = GetBs()->GetPhy()->GetNrSymbols(allocSizeBytes, modulationType);
538 
539  if (availableSymbols < allocSizeSymbols)
540  {
541  allocSizeSymbols = availableSymbols;
542  }
543 
544  if (availableSymbols >= allocSizeSymbols)
545  {
546  NS_LOG_DEBUG("At " << Simulator::Now().As(Time::S) << " BS uplink scheduler, "
547  << serviceFlow->GetSchedulingTypeStr()
548  << " allocation, size: " << allocSizeSymbols << " symbols"
549  << ", CID: " << serviceFlow->GetConnection()->GetCid()
550  << ", SFID: " << serviceFlow->GetSfid()
551  << ", bw requested: " << record->GetRequestedBandwidth()
552  << ", bw granted: " << allocSizeBytes << std::endl);
553 
554  record->UpdateGrantedBandwidthTemp(allocSizeBytes);
555  record->UpdateGrantedBandwidth(allocSizeBytes);
556  record->UpdateRequestedBandwidth(-allocSizeBytes);
557 
558  record->UpdateBwSinceLastExpiry(allocSizeBytes);
559 
560  AddUplinkAllocation(ulMapIe, allocSizeSymbols, symbolsToAllocation, availableSymbols);
561  }
562  else
563  {
564  return false;
565  }
566  }
567  return true;
568 }
569 
570 uint32_t
572 {
573  uint32_t symbols = 0;
574  for (auto iter = jobs.begin(); iter != jobs.end(); ++iter)
575  {
576  Ptr<UlJob> job = *iter;
577 
578  // count symbols
579  symbols += CountSymbolsJobs(job);
580  }
581  return symbols;
582 }
583 
586  ServiceFlow::SchedulingType schedType,
587  ReqType reqType)
588 {
589  Ptr<UlJob> job = CreateObject<UlJob>();
590  job->SetSsRecord(ssRecord);
591  job->SetSchedulingType(schedType);
592  job->SetServiceFlow(*(ssRecord->GetServiceFlows(schedType).begin()));
593  job->SetType(reqType);
594  return job;
595 }
596 
597 uint32_t
599 {
600  SSRecord* ssRecord = job->GetSsRecord();
601  ServiceFlow* serviceFlow = job->GetServiceFlow();
602  uint32_t allocationSize = 0;
603 
604  if (job->GetType() == UNICAST_POLLING)
605  {
606  // if polling
607  Time currentTime = Simulator::Now();
608  allocationSize = 0;
609  if ((currentTime - serviceFlow->GetRecord()->GetGrantTimeStamp()).GetMilliSeconds() >=
610  serviceFlow->GetUnsolicitedPollingInterval())
611  {
612  allocationSize = GetBs()->GetBwReqOppSize();
613  }
614  }
615  else
616  {
617  // if data
618  uint16_t sduSize = serviceFlow->GetSduSize();
619  ServiceFlowRecord* record = serviceFlow->GetRecord();
620  uint32_t requiredBandwidth =
621  record->GetRequestedBandwidth() - record->GetGrantedBandwidth();
622  if (requiredBandwidth > 0)
623  {
624  WimaxPhy::ModulationType modulationType = ssRecord->GetModulationType();
625  if (sduSize > 0)
626  {
627  // if SDU size is mentioned, allocate grant of that size
628  allocationSize = GetBs()->GetPhy()->GetNrSymbols(sduSize, modulationType);
629  }
630  else
631  {
632  allocationSize = GetBs()->GetPhy()->GetNrSymbols(requiredBandwidth, modulationType);
633  }
634  }
635  }
636  return allocationSize;
637 }
638 
639 void
641 {
642  switch (priority)
643  {
644  case UlJob::HIGH:
645  m_uplinkJobs_high.push_back(job);
646  break;
647  case UlJob::INTERMEDIATE:
648  m_uplinkJobs_inter.push_back(job);
649  break;
650  case UlJob::LOW:
651  m_uplinkJobs_low.push_back(job);
652  }
653 }
654 
657 {
658  Ptr<UlJob> job_front;
659  switch (priority)
660  {
661  case UlJob::HIGH:
662  job_front = m_uplinkJobs_high.front();
663  m_uplinkJobs_high.pop_front();
664  break;
665  case UlJob::INTERMEDIATE:
666  job_front = m_uplinkJobs_inter.front();
667  m_uplinkJobs_inter.pop_front();
668  break;
669  case UlJob::LOW:
670  job_front = m_uplinkJobs_low.front();
671  m_uplinkJobs_low.pop_front();
672  }
673  return job_front;
674 }
675 
676 void
677 UplinkSchedulerMBQoS::CheckDeadline(uint32_t& availableSymbols)
678 {
679  // for each request in the intermediate queue
680  if (!m_uplinkJobs_inter.empty())
681  {
682  auto iter = m_uplinkJobs_inter.begin();
683 
684  while (iter != m_uplinkJobs_inter.end() && availableSymbols)
685  {
686  Ptr<UlJob> job = *iter;
687 
688  // guarantee delay bound for rtps connections
689  if (job->GetSchedulingType() == ServiceFlow::SF_TYPE_RTPS)
690  {
691  Time deadline = job->GetDeadline();
692  Time frame_duration = GetBs()->GetPhy()->GetFrameDuration();
693 
694  int64_t frame = ((deadline - Simulator::Now()) / frame_duration).GetHigh();
695 
696  NS_LOG_DEBUG("At " << Simulator::Now().As(Time::S) << " reserved traffic rate: "
697  << job->GetServiceFlow()->GetMinReservedTrafficRate()
698  << " deadline: " << job->GetDeadline().As(Time::S)
699  << " frame start: " << GetBs()->m_frameStartTime.As(Time::S)
700  << " frame duration: " << frame_duration);
701 
702  // should be schedule in this frame to max latency
703  if (frame >= 3)
704  {
705  if (availableSymbols)
706  {
707  uint32_t availableBytes =
708  GetBs()->GetPhy()->GetNrBytes(availableSymbols,
709  job->GetSsRecord()->GetModulationType());
710  uint32_t allocationSize = job->GetSize();
711  if (allocationSize > availableBytes)
712  {
713  allocationSize = availableBytes;
714  }
715 
716  if (allocationSize == 0)
717  {
718  continue;
719  }
720 
721  uint32_t symbolsToAllocate = GetBs()->GetPhy()->GetNrSymbols(
722  allocationSize,
723  job->GetSsRecord()->GetModulationType());
724  if (symbolsToAllocate > availableSymbols)
725  {
726  symbolsToAllocate = availableSymbols;
727  allocationSize = GetBs()->GetPhy()->GetNrBytes(
728  symbolsToAllocate,
729  job->GetSsRecord()->GetModulationType());
730  }
731 
732  job->SetSize(job->GetSize() - allocationSize);
733 
734  Ptr<UlJob> newJob = CreateObject<UlJob>();
735  // Record data in job
736  newJob->SetSsRecord(job->GetSsRecord());
737  newJob->SetServiceFlow(job->GetServiceFlow());
738  newJob->SetSize(allocationSize);
739  newJob->SetDeadline(job->GetDeadline());
740  newJob->SetReleaseTime(job->GetReleaseTime());
741  newJob->SetSchedulingType(job->GetSchedulingType());
742  newJob->SetPeriod(job->GetPeriod());
743  newJob->SetType(job->GetType());
744 
745  EnqueueJob(UlJob::HIGH, newJob);
746 
747  // migrate request
748  iter++;
749  if ((job->GetSize() - allocationSize) == 0)
750  {
751  m_uplinkJobs_inter.remove(job);
752  }
753  }
754  }
755  else
756  {
757  iter++;
758  }
759  }
760  else
761  {
762  iter++;
763  }
764  }
765  }
766 }
767 
768 void
770 {
771  std::list<Ptr<PriorityUlJob>> priorityUlJobs;
772 
773  // For each connection of type rtPS or nrtPS
774  std::vector<SSRecord*>* ssRecords = GetBs()->GetSSManager()->GetSSRecords();
775  for (auto iter = ssRecords->begin(); iter != ssRecords->end(); ++iter)
776  {
777  SSRecord* ssRecord = *iter;
778  std::vector<ServiceFlow*> serviceFlows =
780  for (auto iter2 = serviceFlows.begin(); iter2 != serviceFlows.end(); ++iter2)
781  {
782  ServiceFlow* serviceFlow = *iter2;
783  if (serviceFlow->GetSchedulingType() == ServiceFlow::SF_TYPE_RTPS ||
785  {
786  serviceFlow->GetRecord()->SetBackloggedTemp(
787  serviceFlow->GetRecord()->GetBacklogged());
788  serviceFlow->GetRecord()->SetGrantedBandwidthTemp(
789  serviceFlow->GetRecord()->GetBwSinceLastExpiry());
790  }
791  }
792  }
793 
794  // for each request in the imermediate queue
795  for (auto iter = m_uplinkJobs_inter.begin(); iter != m_uplinkJobs_inter.end(); ++iter)
796  {
797  Ptr<UlJob> job = *iter;
798  // SSRecord ssRecord = job->GetSsRecord();
799  ServiceFlow* serviceFlow = job->GetServiceFlow();
800  if ((job->GetSchedulingType() == ServiceFlow::SF_TYPE_RTPS ||
801  job->GetSchedulingType() == ServiceFlow::SF_TYPE_NRTPS) &&
802  (serviceFlow->GetRecord()->GetBacklogged() > 0))
803  {
804  uint32_t minReservedTrafficRate = serviceFlow->GetMinReservedTrafficRate();
805  uint32_t grantedBandwidth = serviceFlow->GetRecord()->GetBwSinceLastExpiry();
806 
807  Ptr<PriorityUlJob> priorityUlJob = CreateObject<PriorityUlJob>();
808  priorityUlJob->SetUlJob(job);
809  // pri_array
810  if (minReservedTrafficRate <= grantedBandwidth)
811  {
812  priorityUlJob->SetPriority(-10000);
813  }
814  else
815  {
816  uint32_t allocationSize = serviceFlow->GetRecord()->GetRequestedBandwidth() -
817  serviceFlow->GetRecord()->GetGrantedBandwidth();
818  uint32_t sduSize = serviceFlow->GetSduSize();
819 
820  if (allocationSize > 0)
821  {
822  if (sduSize > 0)
823  {
824  // if SDU size is mentioned, grant of that size
825  allocationSize = sduSize;
826  }
827  }
828  int priority =
829  serviceFlow->GetRecord()->GetBackloggedTemp() -
830  (serviceFlow->GetRecord()->GetGrantedBandwidthTemp() - minReservedTrafficRate);
831  priorityUlJob->SetPriority(priority);
832  serviceFlow->GetRecord()->SetGrantedBandwidthTemp(
833  serviceFlow->GetRecord()->GetGrantedBandwidthTemp() + allocationSize);
834  serviceFlow->GetRecord()->SetBackloggedTemp(
835  serviceFlow->GetRecord()->GetBackloggedTemp() - allocationSize);
836  }
837 
838  priorityUlJobs.push_back(priorityUlJob);
839  }
840  }
841 
842  priorityUlJobs.sort(SortProcessPtr());
843 
844  for (auto iter = priorityUlJobs.begin(); iter != priorityUlJobs.end(); ++iter)
845  {
846  Ptr<PriorityUlJob> priorityUlJob = *iter;
847  Ptr<UlJob> job_priority = priorityUlJob->GetUlJob();
848  Ptr<UlJob> job = job_priority;
849  if (availableSymbols)
850  {
851  availableSymbols -= CountSymbolsJobs(job);
852  // migrate request
853  m_uplinkJobs_inter.remove(job);
854  EnqueueJob(UlJob::HIGH, job);
855  }
856  }
857 }
858 
859 void
861  ServiceFlow::SchedulingType schedulingType,
862  OfdmUlMapIe& ulMapIe,
863  const WimaxPhy::ModulationType modulationType,
864  uint32_t& symbolsToAllocation,
865  uint32_t& availableSymbols)
866 {
867  uint32_t allocationSize = 0; // size in symbols
868  uint8_t uiuc = ulMapIe.GetUiuc(); // SS's burst profile
869  std::vector<ServiceFlow*> serviceFlows = ssRecord->GetServiceFlows(schedulingType);
870 
871  for (auto iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
872  {
873  ServiceFlow* serviceFlow = *iter;
874 
875  /* in case of rtPS, nrtPS and BE, allocating unicast polls for bandwidth requests (Request
876  IEs, 6.3.7.4.3.1). in case of UGS, allocating grants for data transmission (Data Grant
877  Burst Type IEs, 6.3.7.4.3.3) (grant has been referred in this code by different names e.g.
878  transmission opportunity, slot, allocation, etc) */
879 
880  allocationSize =
881  GetBs()->GetBandwidthManager()->CalculateAllocationSize(ssRecord, serviceFlow);
882 
883  if (availableSymbols < allocationSize)
884  {
885  break;
886  }
887 
888  if (allocationSize > 0)
889  {
890  ulMapIe.SetStartTime(symbolsToAllocation);
891  if (serviceFlow->GetSchedulingType() != ServiceFlow::SF_TYPE_UGS)
892  {
893  // special burst profile with most robust modulation type is used for unicast polls
894  // (Request IEs)
896  }
897  }
898  else
899  {
900  continue;
901  }
902 
903  if (serviceFlow->GetSchedulingType() == ServiceFlow::SF_TYPE_UGS)
904  {
905  NS_LOG_DEBUG("BS uplink scheduler, UGS allocation, size: " << allocationSize
906  << " symbols");
907  }
908  else
909  {
910  NS_LOG_DEBUG("BS uplink scheduler, " << serviceFlow->GetSchedulingTypeStr()
911  << " unicast poll, size: " << allocationSize
912  << " symbols"
913  << ", modulation: BPSK 1/2");
914  }
915 
916  NS_LOG_DEBUG(", CID: " << serviceFlow->GetConnection()->GetCid()
917  << ", SFID: " << serviceFlow->GetSfid());
918 
919  serviceFlow->GetRecord()->SetLastGrantTime(Simulator::Now());
920  AddUplinkAllocation(ulMapIe, allocationSize, symbolsToAllocation, availableSymbols);
921  ulMapIe.SetUiuc(uiuc);
922  }
923 }
924 
925 void
927  ServiceFlow::SchedulingType schedulingType,
928  OfdmUlMapIe& ulMapIe,
929  const WimaxPhy::ModulationType modulationType,
930  uint32_t& symbolsToAllocation,
931  uint32_t& availableSymbols)
932 {
933  std::vector<ServiceFlow*> serviceFlows = ssRecord->GetServiceFlows(schedulingType);
934 
935  for (auto iter = serviceFlows.begin(); iter != serviceFlows.end(); ++iter)
936  {
937  if (!ServiceBandwidthRequests(*iter,
938  schedulingType,
939  ulMapIe,
940  modulationType,
941  symbolsToAllocation,
942  availableSymbols))
943  {
944  break;
945  }
946  }
947 }
948 
949 bool
951  ServiceFlow::SchedulingType schedulingType,
952  OfdmUlMapIe& ulMapIe,
953  const WimaxPhy::ModulationType modulationType,
954  uint32_t& symbolsToAllocation,
955  uint32_t& availableSymbols)
956 {
957  uint32_t allocSizeBytes = 0;
958  uint32_t allocSizeSymbols = 0;
959  uint16_t sduSize = 0;
960 
961  ServiceFlowRecord* record = serviceFlow->GetRecord();
962  sduSize = serviceFlow->GetSduSize();
963 
964  uint32_t requiredBandwidth = record->GetRequestedBandwidth() - record->GetGrantedBandwidth();
965  if (requiredBandwidth > 0)
966  {
967  if (sduSize > 0)
968  {
969  // if SDU size is mentioned, allocate grant of that size
970  allocSizeBytes = sduSize;
971  allocSizeSymbols = GetBs()->GetPhy()->GetNrSymbols(sduSize, modulationType);
972  }
973  else
974  {
975  allocSizeBytes = requiredBandwidth;
976  allocSizeSymbols = GetBs()->GetPhy()->GetNrSymbols(requiredBandwidth, modulationType);
977  }
978 
979  if (availableSymbols >= allocSizeSymbols)
980  {
981  NS_LOG_DEBUG("BS uplink scheduler, "
982  << serviceFlow->GetSchedulingTypeStr()
983  << " allocation, size: " << allocSizeSymbols << " symbols"
984  << ", CID: " << serviceFlow->GetConnection()->GetCid()
985  << ", SFID: " << serviceFlow->GetSfid()
986  << ", bw requested: " << record->GetRequestedBandwidth()
987  << ", bw granted: " << record->GetGrantedBandwidth());
988 
989  record->UpdateGrantedBandwidth(allocSizeBytes);
990 
991  record->SetBwSinceLastExpiry(allocSizeBytes);
992 
993  if (serviceFlow->GetRecord()->GetBacklogged() < allocSizeBytes)
994  {
995  serviceFlow->GetRecord()->SetBacklogged(0);
996  }
997  else
998  {
999  serviceFlow->GetRecord()->IncreaseBacklogged(-allocSizeBytes);
1000  }
1001  serviceFlow->GetRecord()->SetLastGrantTime(Simulator::Now());
1002 
1003  AddUplinkAllocation(ulMapIe, allocSizeSymbols, symbolsToAllocation, availableSymbols);
1004  }
1005  else
1006  {
1007  return false;
1008  }
1009  }
1010  return true;
1011 }
1012 
1013 void
1015  uint32_t& availableSymbols)
1016 {
1017  Time ssUlStartTime =
1018  Seconds(CalculateAllocationStartTime() * GetBs()->GetPsDuration().GetSeconds());
1019  SetNrIrOppsAllocated(GetBs()->GetLinkManager()->CalculateRangingOppsToAllocate());
1020  uint32_t allocationSize = GetNrIrOppsAllocated() * GetBs()->GetRangReqOppSize();
1021  Time timeSinceLastIrInterval = Simulator::Now() - GetTimeStampIrInterval();
1022 
1023  // adding one frame because may be the time has not elapsed now but will elapse before the next
1024  // frame is sent
1025  if (timeSinceLastIrInterval + GetBs()->GetPhy()->GetFrameDuration() >
1026  GetBs()->GetInitialRangingInterval() &&
1027  availableSymbols >= allocationSize)
1028  {
1029  SetIsIrIntrvlAllocated(true);
1030  OfdmUlMapIe ulMapIeIr;
1031  ulMapIeIr.SetCid((GetBs()->GetBroadcastConnection())->GetCid());
1032  ulMapIeIr.SetStartTime(symbolsToAllocation);
1034 
1035  NS_LOG_DEBUG("BS uplink scheduler, initial ranging allocation, size: "
1036  << allocationSize << " symbols"
1037  << ", modulation: BPSK 1/2");
1038 
1039  // marking start and end of each TO, only for debugging
1040  for (uint8_t i = 0; i < GetNrIrOppsAllocated(); i++)
1041  {
1042  GetBs()->MarkRangingOppStart(
1043  ssUlStartTime +
1044  Seconds(symbolsToAllocation * GetBs()->GetSymbolDuration().GetSeconds()) +
1045  Seconds(i * GetBs()->GetRangReqOppSize() *
1046  GetBs()->GetSymbolDuration().GetSeconds()));
1047  }
1048 
1049  AddUplinkAllocation(ulMapIeIr, allocationSize, symbolsToAllocation, availableSymbols);
1051  }
1052 }
1053 
1054 void
1056 {
1057  uint8_t delayNrFrames = 1;
1058  uint32_t bitsPerSecond = serviceFlow->GetMinReservedTrafficRate();
1059  WimaxPhy::ModulationType modulation;
1060  uint32_t bytesPerFrame =
1061  (uint32_t((double)(bitsPerSecond)*GetBs()->GetPhy()->GetFrameDuration().GetSeconds())) / 8;
1062  uint32_t frameDurationMSec = GetBs()->GetPhy()->GetFrameDuration().GetMilliSeconds();
1063 
1064  switch (serviceFlow->GetSchedulingType())
1065  {
1066  case ServiceFlow::SF_TYPE_UGS: {
1067  if (serviceFlow->GetIsMulticast())
1068  {
1069  modulation = serviceFlow->GetModulation();
1070  }
1071  else
1072  {
1073  modulation = ssRecord->GetModulationType();
1074  }
1075  uint32_t grantSize = GetBs()->GetPhy()->GetNrSymbols(bytesPerFrame, modulation);
1076  serviceFlow->GetRecord()->SetGrantSize(grantSize);
1077 
1078  uint32_t toleratedJitter = serviceFlow->GetToleratedJitter();
1079 
1080  if (toleratedJitter > frameDurationMSec)
1081  {
1082  delayNrFrames = (uint8_t)(toleratedJitter / frameDurationMSec);
1083  }
1084 
1085  uint16_t interval = delayNrFrames * frameDurationMSec;
1086  serviceFlow->SetUnsolicitedGrantInterval(interval);
1087  }
1088  break;
1090  serviceFlow->SetUnsolicitedPollingInterval(20);
1091  }
1092  break;
1094  // no real-time guarantees are given to NRTPS, serviced based on available bandwidth
1095  uint16_t interval = 1000;
1096  serviceFlow->SetUnsolicitedPollingInterval(interval);
1097  }
1098  break;
1099  case ServiceFlow::SF_TYPE_BE: {
1100  // no real-time guarantees are given to BE, serviced based on available bandwidth
1101  }
1102  break;
1103  default:
1104  NS_FATAL_ERROR("Invalid scheduling type");
1105  }
1106 }
1107 
1108 uint32_t
1110 {
1111  uint32_t size = 0;
1112  std::list<Ptr<PriorityUlJob>> priorityUlJobs;
1113 
1114  // for each request in the imermediate queue
1115  for (auto iter = m_uplinkJobs_inter.begin(); iter != m_uplinkJobs_inter.end(); ++iter)
1116  {
1117  Ptr<UlJob> job = *iter;
1118 
1119  ServiceFlow* serviceFlowJob = job->GetServiceFlow();
1120 
1121  if (serviceFlowJob == serviceFlow)
1122  {
1123  size += job->GetSize();
1124  }
1125  }
1126  return size;
1127 }
1128 
1129 void
1131 {
1132  // Enqueue requests for uplink scheduler.
1133  Ptr<UlJob> job = CreateObject<UlJob>();
1134  Ptr<WimaxConnection> connection =
1135  GetBs()->GetConnectionManager()->GetConnection(bwRequestHdr.GetCid());
1136  SSRecord* ssRecord = GetBs()->GetSSManager()->GetSSRecord(connection->GetCid());
1137  ServiceFlow* serviceFlow = connection->GetServiceFlow();
1138 
1139  uint32_t size = bwRequestHdr.GetBr();
1140  uint32_t pendingSize = GetPendingSize(serviceFlow);
1141 
1142  if (size > pendingSize)
1143  {
1144  size -= pendingSize;
1145  }
1146  else
1147  {
1148  size = 0;
1149  }
1150 
1151  if (size == 0)
1152  {
1153  return;
1154  }
1155 
1156  Time deadline = DetermineDeadline(serviceFlow);
1157  Time currentTime = Simulator::Now();
1158  const Time& period = deadline; // So that deadline is properly updated..
1159 
1160  NS_LOG_DEBUG("At " << Simulator::Now().As(Time::S)
1161  << " at BS uplink scheduler, processing bandwidth request from."
1162  << ssRecord->GetMacAddress() << " and sf "
1163  << serviceFlow->GetSchedulingType() << " with deadline in "
1164  << deadline.As(Time::S) << " and size " << size << " aggreg size "
1165  << bwRequestHdr.GetBr());
1166 
1167  // Record data in job
1168  job->SetSsRecord(ssRecord);
1169  job->SetServiceFlow(serviceFlow);
1170  job->SetSize(size);
1171  job->SetDeadline(deadline);
1172  job->SetReleaseTime(currentTime);
1173  job->SetSchedulingType(serviceFlow->GetSchedulingType());
1174  job->SetPeriod(period);
1175  job->SetType(DATA);
1176 
1177  // Enqueue job in Uplink Scheduler
1178  switch (serviceFlow->GetSchedulingType())
1179  {
1182  break;
1185  break;
1187  EnqueueJob(UlJob::LOW, job);
1188  break;
1189  default:
1190  EnqueueJob(UlJob::LOW, job);
1191  break;
1192  }
1193 }
1194 
1195 /*
1196  * Calculate Deadline of requests according to QoS parameter
1197  * */
1198 Time
1200 {
1201  uint32_t latency = serviceFlow->GetMaximumLatency();
1202  Time lastGrantTime = serviceFlow->GetRecord()->GetLastGrantTime();
1203  Time deadline = MilliSeconds(latency) + lastGrantTime;
1204  return deadline;
1205 }
1206 
1207 void
1209 {
1210  // virtual function on UplinkScheduler
1211  // this is not necessary on this implementation
1212 }
1213 
1214 } // namespace ns3
This class implements the bandwidth-request mac Header as described by IEEE Standard for Local and me...
uint32_t GetBr() const
Get BR field.
Cid GetCid() const
Get CID field.
Cid class.
Definition: cid.h:37
This class implements the DSA-REQ message described by "IEEE Standard for Local and metropolitan area...
Definition: mac-messages.h:386
This class implements the UL-MAP_IE message as described by "IEEE Standard for Local and metropolitan...
void SetStartTime(uint16_t startTime)
Set start time.
uint8_t GetUiuc() const
Get UIUC.
void SetDuration(uint16_t duration)
Set duration.
void SetCid(const Cid &cid)
Set CID.
void SetUiuc(uint8_t uiuc)
Set UIUC.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
This class is used by the base station to store some information related to subscriber station in the...
Definition: ss-record.h:46
bool GetHasServiceFlowUgs() const
Check if at least one flow has scheduling type SF_TYPE_UGS.
Definition: ss-record.cc:260
Cid GetBasicCid() const
Get basic CID.
Definition: ss-record.cc:95
WimaxNetDevice::RangingStatus GetRangingStatus() const
Get ranging status.
Definition: ss-record.cc:179
bool GetPollForRanging() const
Get poll for ranging.
Definition: ss-record.cc:197
bool GetHasServiceFlowRtps() const
Check if at least one flow has scheduling type SF_TYPE_RTPS.
Definition: ss-record.cc:273
std::vector< ServiceFlow * > GetServiceFlows(ServiceFlow::SchedulingType schedulingType) const
Get service flows.
Definition: ss-record.cc:233
bool GetAreServiceFlowsAllocated() const
Check if service flows are allocated.
Definition: ss-record.cc:209
Mac48Address GetMacAddress() const
Get MAC address.
Definition: ss-record.cc:119
bool GetIsBroadcastSS() const
Get is broadcast SS.
Definition: ss-record.cc:254
WimaxPhy::ModulationType GetModulationType() const
Get modulation type.
Definition: ss-record.cc:167
bool GetHasServiceFlowNrtps() const
Check if at least one flow has scheduling type SF_TYPE_NRTPS.
Definition: ss-record.cc:286
bool GetHasServiceFlowBe() const
Check if at least one flow has scheduling type SF_TYPE_BE.
Definition: ss-record.cc:299
This class implements service flows as described by the IEEE-802.16 standard.
Definition: service-flow.h:43
uint32_t GetSfid() const
Get SFID.
uint32_t GetMaximumLatency() const
Get maximum latency.
ServiceFlow::SchedulingType GetSchedulingType() const
Get scheduling type.
uint16_t GetUnsolicitedPollingInterval() const
Get unsolicited polling interval.
SchedulingType
section 11.13.11 Service flow scheduling type, page 701
Definition: service-flow.h:62
char * GetSchedulingTypeStr() const
Get scheduling type string.
uint32_t GetMinReservedTrafficRate() const
Get minimum reserved traffic rate.
uint8_t GetSduSize() const
Get SDU size.
WimaxPhy::ModulationType GetModulation() const
Get modulation.
void SetUnsolicitedGrantInterval(uint16_t unsolicitedGrantInterval)
Set unsolicited grant interval.
ServiceFlowRecord * GetRecord() const
Get service flow record.
void SetUnsolicitedPollingInterval(uint16_t unsolicitedPollingInterval)
Set unsolicited polling interval.
bool GetIsMulticast() const
Get is multicast.
uint32_t GetToleratedJitter() const
Get tolerated jitter.
Ptr< WimaxConnection > GetConnection() const
Can return a null connection is this service flow has not been associated yet to a connection.
this class implements a structure to manage some parameters and statistics related to a service flow
uint32_t GetBacklogged() const
void UpdateRequestedBandwidth(uint32_t requestedBandwidth)
update the requested bandwidth
void UpdateGrantedBandwidthTemp(uint32_t grantedBandwidthTemp)
update the temporary granted bandwidth
uint32_t GetRequestedBandwidth() const
void IncreaseBacklogged(uint32_t backlogged)
increase backlogged
uint32_t GetBackloggedTemp() const
void SetBackloggedTemp(uint32_t backloggedTemp)
set temporary back logged
uint32_t GetGrantedBandwidthTemp() const
void SetGrantSize(uint32_t grantSize)
Set the grant size (only for UGS service flows)
uint32_t GetGrantedBandwidth() const
void SetGrantedBandwidthTemp(uint32_t grantedBandwidthTemp)
set the temporary granted bandwidth
void SetBwSinceLastExpiry(uint32_t bwSinceLastExpiry)
set BW since last expiry
void UpdateGrantedBandwidth(uint32_t grantedBandwidth)
update the granted bandwidth
void UpdateBwSinceLastExpiry(uint32_t bwSinceLastExpiry)
update BW since last expiry
void SetBacklogged(uint32_t backlogged)
set backlogged
uint32_t GetBwSinceLastExpiry() const
void SetLastGrantTime(Time grantTime)
set last grant time
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:415
@ S
second
Definition: nstime.h:116
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
JobPriority
Job priority enumeration.
Definition: ul-job.h:54
@ INTERMEDIATE
Definition: ul-job.h:56
@ HIGH
Definition: ul-job.h:57
ModulationType
ModulationType enumeration.
Definition: wimax-phy.h:54
const char * NS_LOG
Control which logging components are enabled.
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1414
ReqType
Request type enumeration.
Definition: ul-job.h:40
@ UNICAST_POLLING
Definition: ul-job.h:42
@ DATA
Definition: ul-job.h:41
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:533
@ LOG_DEBUG
Full voluminous logging to support debugging.
Definition: log.h:112
#define list
SortProcessPtr structure.
Definition: ul-job.h:234