satellite-fwd-link-scheduler-time-slicing.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013 Magister Solutions Ltd
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: Bastien Tauran <bastien.tauran@viveris.fr>
19  */
20 
22 
23 #include "satellite-utils.h"
24 
25 #include <map>
26 #include <string>
27 #include <utility>
28 #include <vector>
29 
30 NS_LOG_COMPONENT_DEFINE("SatFwdLinkSchedulerTimeSlicing");
31 
32 namespace ns3
33 {
34 
35 NS_OBJECT_ENSURE_REGISTERED(SatFwdLinkSchedulerTimeSlicing);
36 
37 TypeId
39 {
40  static TypeId tid =
41  TypeId("ns3::SatFwdLinkSchedulerTimeSlicing")
42  .SetParent<SatFwdLinkScheduler>()
43  .AddConstructor<SatFwdLinkSchedulerTimeSlicing>()
44  .AddAttribute("NumberOfSlices",
45  "Number of slices used.",
46  UintegerValue(1),
48  MakeUintegerChecker<uint8_t>(1, 255));
49  return tid;
50 }
51 
52 TypeId
54 {
55  return GetTypeId();
56 }
57 
60 {
61  NS_LOG_FUNCTION(this);
62  NS_FATAL_ERROR("Default constructor for SatFwdLinkSchedulerTimeSlicing not supported");
63 }
64 
66  Mac48Address address,
67  double carrierBandwidthInHz)
68  : SatFwdLinkScheduler(conf, address, carrierBandwidthInHz),
69  m_lastSliceAssigned(1),
70  m_lastSliceDequeued(1)
71 {
72  NS_LOG_FUNCTION(this);
73 
74  ObjectBase::ConstructSelf(AttributeConstructionList());
75 
76  std::vector<SatEnums::SatModcod_t> modCods = conf->GetModCodsUsed();
77 
78  // Create control and broadcast container
79  m_bbFrameContainers.insert(std::pair<uint8_t, Ptr<SatBbFrameContainer>>(
80  0,
81  CreateObject<SatBbFrameContainer>(modCods, m_bbFrameConf)));
82  m_bbFrameContainers.at(0)->SetMaxSymbolRate(m_carrierBandwidthInHz);
83 
84  // Initialize containers
85  for (uint8_t i = 0; i < m_numberOfSlices; i++)
86  {
87  Ptr<SatBbFrameContainer> container =
88  CreateObject<SatBbFrameContainer>(modCods, m_bbFrameConf);
89  container->SetMaxSymbolRate(m_carrierBandwidthInHz / m_numberOfSlices);
90  m_bbFrameContainers.insert(std::pair<uint8_t, Ptr<SatBbFrameContainer>>(i + 1, container));
91  }
92 
93  // Initialize number of symbols sent per slice
94  for (uint8_t i = 0; i <= m_numberOfSlices; i++)
95  {
96  m_symbolsSent.insert(std::pair<uint8_t, uint32_t>(i, 0));
97  }
98 
99  // Check if all symbol rates are high enough
100  for (std::map<uint8_t, Ptr<SatBbFrameContainer>>::iterator it = m_bbFrameContainers.begin();
101  it != m_bbFrameContainers.end();
102  it++)
103  {
104  uint32_t maxSymbolPerCycle =
105  it->second->GetMaxSymbolRate() * m_periodicInterval.GetSeconds();
106  uint32_t symbolsMostRobustModcod;
107  if (m_bbFrameConf->GetMostRobustModcod(SatEnums::NORMAL_FRAME) !=
109  {
110  symbolsMostRobustModcod = it->second->GetFrameSymbols(
111  m_bbFrameConf->GetMostRobustModcod(SatEnums::NORMAL_FRAME));
112  }
113  else
114  {
115  // We are using only short Frames, as new ModCod exists for normal Frames.
116  symbolsMostRobustModcod = it->second->GetFrameSymbols(
117  m_bbFrameConf->GetMostRobustModcod(SatEnums::SHORT_FRAME));
118  }
119  if (symbolsMostRobustModcod > maxSymbolPerCycle)
120  {
121  NS_FATAL_ERROR("Symbol rate of slice " + std::to_string(it->first) + " (" +
122  std::to_string(it->second->GetMaxSymbolRate()) +
123  " Baud) is too low to allow at least one BBFrame of the most robust "
124  "ModCod. Must be at least " +
125  std::to_string((uint32_t)(symbolsMostRobustModcod /
126  m_periodicInterval.GetSeconds())) +
127  " Baud");
128  }
129  }
130 
131  Simulator::Schedule(m_periodicInterval,
133  this);
134 }
135 
137 {
138  NS_LOG_FUNCTION(this);
139 }
140 
141 void
143 {
144  NS_LOG_FUNCTION(this);
146  m_bbFrameContainers.clear();
147 }
148 
149 std::pair<Ptr<SatBbFrame>, const Time>
151 {
152  NS_LOG_FUNCTION(this);
153 
154  Ptr<SatBbFrame> frame;
155  Time frameDuration;
156 
157  // Send slice control messages first if there is any.
158  if (!m_bbFrameContainers.at(0)->IsEmpty(0, m_bbFrameConf->GetDefaultModCod()))
159  {
160  frame = m_bbFrameContainers.at(0)->GetNextFrame();
161  if (frame != nullptr)
162  {
163  frame->SetSliceId(0);
164  frameDuration = frame->GetDuration();
165  m_symbolsSent.at(0) += ceil(frame->GetDuration().GetSeconds() * m_carrierBandwidthInHz);
166  }
167  else
168  {
169  frameDuration = m_bbFrameConf->GetDummyBbFrameDuration();
170  }
171  }
172  else
173  {
174  uint8_t firstDeque = m_lastSliceDequeued;
175  do
176  {
177  uint32_t symbols = m_symbolsSent.at(m_lastSliceDequeued) + m_symbolsSent.at(0);
178  double maxSymbolRate = m_bbFrameContainers.at(m_lastSliceDequeued)->GetMaxSymbolRate();
179 
180  frame = m_bbFrameContainers.at(m_lastSliceDequeued)->GetNextFrame();
181  if (frame != nullptr)
182  {
184  ceil(frame->GetDuration().GetSeconds() * m_carrierBandwidthInHz);
185  symbols += ceil(frame->GetDuration().GetSeconds() * m_carrierBandwidthInHz);
186  frame->SetSliceId(m_lastSliceDequeued);
187  frameDuration = frame->GetDuration();
188 
189  if (symbols / m_periodicInterval.GetSeconds() > maxSymbolRate)
190  {
191  NS_LOG_WARN("Symbol rate not respected for slice " +
192  std::to_string(m_lastSliceDequeued) + ". Got " +
193  std::to_string(symbols / m_periodicInterval.GetSeconds()) + "Baud" +
194  " while max is " + std::to_string(maxSymbolRate) + " Baud");
195  }
196  }
198  {
199  m_lastSliceDequeued = -1;
200  }
202  } while (frame == nullptr && m_lastSliceDequeued != firstDeque);
203  }
204 
205  // create dummy frame
206  if (m_dummyFrameSendingEnabled && frame == nullptr)
207  {
208  frame = Create<SatBbFrame>(m_bbFrameConf->GetDefaultModCod(),
210  m_bbFrameConf);
211 
212  // create dummy packet
213  Ptr<Packet> dummyPacket = Create<Packet>(1);
214 
215  // Add MAC tag
216  SatMacTag mTag;
217  mTag.SetDestAddress(Mac48Address::GetBroadcast());
219  dummyPacket->AddPacketTag(mTag);
220 
221  // Add E2E address tag
222  SatAddressE2ETag addressE2ETag;
223  addressE2ETag.SetE2EDestAddress(Mac48Address::GetBroadcast());
224  addressE2ETag.SetE2ESourceAddress(m_macAddress);
225  dummyPacket->AddPacketTag(addressE2ETag);
226 
227  // Add dummy packet to dummy frame
228  frame->AddPayload(dummyPacket);
229  frame->SetSliceId(0);
230  frameDuration = frame->GetDuration();
231  }
232  // If no bb frame available and dummy frames disabled
233  else if (frame == nullptr)
234  {
235  frameDuration = m_bbFrameConf->GetDummyBbFrameDuration();
236  }
237 
238  return std::make_pair(frame, frameDuration);
239 }
240 
241 void
243 {
244  NS_LOG_FUNCTION(this);
245 
246  std::map<uint8_t, Ptr<SatBbFrameContainer>>::iterator it;
247  for (it = m_bbFrameContainers.begin(); it != m_bbFrameContainers.end(); it++)
248  {
249  it->second->ClearAllFrames();
250  }
251 }
252 
253 void
255 {
256  NS_LOG_FUNCTION(this);
257 
260 
261  Simulator::Schedule(m_periodicInterval,
263  this);
264 }
265 
266 void
268 {
269  NS_LOG_FUNCTION(this);
270 
271  for (std::map<uint8_t, uint32_t>::iterator it = m_symbolsSent.begin();
272  it != m_symbolsSent.end();
273  it++)
274  {
275  m_schedulingSymbolRateTrace(it->first, it->second / Seconds(1).GetSeconds());
276  }
277 
278  m_symbolsSent.clear();
279 
280  for (uint8_t i = 0; i <= m_numberOfSlices; i++)
281  {
282  m_symbolsSent.insert(std::pair<uint8_t, uint32_t>(i, 0));
283  }
284 }
285 
286 void
288 {
289  NS_LOG_FUNCTION(this);
290 
291  // Get scheduling objects from LLC
292  std::vector<Ptr<SatSchedulingObject>> so;
294 
295  for (std::vector<Ptr<SatSchedulingObject>>::const_iterator it = so.begin();
296  (it != so.end()) && (GetTotalDuration() < m_periodicInterval);
297  it++)
298  {
299  uint32_t currentObBytes = (*it)->GetBufferedBytes();
300  uint32_t currentObMinReqBytes = (*it)->GetMinTxOpportunityInBytes();
301  uint8_t flowId = (*it)->GetFlowId();
302  Mac48Address address = (*it)->GetMacAddress();
303 
304  if ((m_slicesMapping.find(address) == m_slicesMapping.end()) &&
305  (address != Mac48Address::GetBroadcast()))
306  {
307  m_slicesMapping.insert(std::pair<Mac48Address, uint8_t>(address, m_lastSliceAssigned));
309  {
311  }
313 
314  SendTimeSliceSubscription(address, std::vector<uint8_t>{m_slicesMapping.at(address)});
315 
316  // Begin again scheduling to insert slice subscription control packet.
317  Simulator::Schedule(Seconds(0),
319  this);
320  return;
321  }
322  uint8_t slice = (address == Mac48Address::GetBroadcast()) ? 0 : m_slicesMapping.at(address);
323  SatEnums::SatModcod_t modcod =
324  m_bbFrameContainers.at(slice)->GetModcod(flowId, GetSchedulingObjectCno(*it));
325 
326  uint32_t frameBytes =
327  m_bbFrameContainers.at(slice)->GetBytesLeftInTailFrame(flowId, modcod);
328 
329  if ((m_bbFrameContainers.at(slice)->IsEmpty(flowId, modcod)) && (currentObBytes > 0) &&
330  !CanOpenBbFrame(address, flowId, modcod))
331  {
332  continue;
333  }
334 
335  while ((GetTotalDuration() < m_periodicInterval) && (currentObBytes > 0))
336  {
337  if (frameBytes < currentObMinReqBytes)
338  {
339  frameBytes =
340  m_bbFrameContainers.at(slice)->GetMaxFramePayloadInBytes(flowId, modcod) -
341  m_bbFrameConf->GetBbFrameHeaderSizeInBytes();
342 
343  if (!CanOpenBbFrame(address, flowId, modcod))
344  {
345  break;
346  }
347 
348  // if frame bytes still too small, we must have too long control message, so let's
349  // crash
350  if (frameBytes < currentObMinReqBytes)
351  {
352  NS_FATAL_ERROR("Control package probably too long!!!");
353  }
354  }
355 
356  Ptr<Packet> p = m_txOpportunityCallback(frameBytes,
357  address,
358  flowId,
359  currentObBytes,
360  currentObMinReqBytes);
361 
362  if (p)
363  {
364  if ((flowId == 0) || (address == Mac48Address::GetBroadcast()))
365  {
366  m_bbFrameContainers.at(0)->AddData(flowId, modcod, p);
367  }
368  else
369  {
370  m_bbFrameContainers.at(slice)->AddData(flowId, modcod, p);
371  frameBytes =
372  m_bbFrameContainers.at(slice)->GetBytesLeftInTailFrame(flowId, modcod);
373  }
374  }
375  else if (m_bbFrameContainers.at(slice)->GetMaxFramePayloadInBytes(flowId, modcod) !=
376  m_bbFrameContainers.at(slice)->GetBytesLeftInTailFrame(flowId, modcod))
377  {
378  frameBytes =
379  m_bbFrameContainers.at(slice)->GetMaxFramePayloadInBytes(flowId, modcod);
380 
381  if (!CanOpenBbFrame(address, flowId, modcod))
382  {
383  break;
384  }
385  }
386  else
387  {
388  NS_FATAL_ERROR("Packet does not fit in empty BB Frame. Control package too long or "
389  "fragmentation problem in user package!!!");
390  }
391  }
392 
393  m_bbFrameContainers.at(slice)->MergeBbFrames(m_carrierBandwidthInHz);
394  }
395 }
396 
397 void
398 SatFwdLinkSchedulerTimeSlicing::GetSchedulingObjects(std::vector<Ptr<SatSchedulingObject>>& output)
399 {
400  NS_LOG_FUNCTION(this);
401 
403  {
404  // Get scheduling objects from LLC
405  m_schedContextCallback(output);
406 
407  SortSchedulingObjects(output);
408  }
409 }
410 
411 Time
413 {
414  NS_LOG_FUNCTION(this);
415 
416  Time duration = Time(0);
417  for (std::map<uint8_t, Ptr<SatBbFrameContainer>>::iterator it = m_bbFrameContainers.begin();
418  it != m_bbFrameContainers.end();
419  it++)
420  {
421  duration += it->second->GetTotalDuration();
422  }
423 
424  return duration;
425 }
426 
427 void
429  std::vector<uint8_t> slices)
430 {
431  NS_LOG_FUNCTION(this);
432 
433  for (std::vector<uint8_t>::iterator it = slices.begin(); it != slices.end(); ++it)
434  {
435  Ptr<SatSliceSubscriptionMessage> sliceSubscription =
436  CreateObject<SatSliceSubscriptionMessage>();
437  sliceSubscription->SetSliceId(*it);
438  sliceSubscription->SetAddress(address);
439 
440  m_sendControlMsgCallback(sliceSubscription, Mac48Address::GetBroadcast());
441  }
442 }
443 
444 bool
446  uint32_t priorityClass,
447  SatEnums::SatModcod_t modcod)
448 {
449  NS_LOG_FUNCTION(this);
450 
451  if (priorityClass == 0)
452  {
453  // Always allow control messages to be send
454  // TODO add a margin to take this into account ?
455  return true;
456  }
457 
458  uint8_t sliceId = (address == Mac48Address::GetBroadcast()) ? 0 : m_slicesMapping.at(address);
459  double maxSymbolRate = m_bbFrameContainers.at(sliceId)->GetMaxSymbolRate();
460 
461  if (sliceId == 0)
462  {
463  // This is broadcast -> need to test all slices >= 1
464  uint32_t symbols = GetSymbols(0, modcod);
465  for (std::map<uint8_t, Ptr<SatBbFrameContainer>>::iterator it = m_bbFrameContainers.begin();
466  it != m_bbFrameContainers.end();
467  it++)
468  {
469  if (it->first == 0)
470  {
471  continue;
472  }
473  double symbolRate = (symbols + GetSymbols(it->first, SatEnums::SAT_NONVALID_MODCOD)) /
474  m_periodicInterval.GetSeconds();
475  if (symbolRate > maxSymbolRate)
476  {
477  // One slice will not respect constraints
478  return false;
479  }
480  }
481  // Constraints are respected for all slices
482  return true;
483  }
484  else
485  {
486  uint32_t symbols =
487  GetSymbols(sliceId, modcod) + GetSymbols(0, SatEnums::SAT_NONVALID_MODCOD);
488  double symbolRate = symbols / m_periodicInterval.GetSeconds();
489  return symbolRate < maxSymbolRate;
490  }
491 }
492 
493 uint32_t
495 {
496  NS_LOG_FUNCTION(this);
497 
498  uint32_t symbols =
499  m_bbFrameContainers.at(sliceId)->GetTotalDuration().GetSeconds() * m_carrierBandwidthInHz;
500 
501  if (modcod != SatEnums::SAT_NONVALID_MODCOD)
502  {
503  symbols += m_bbFrameContainers.at(sliceId)->GetFrameSymbols(modcod);
504  }
505 
506  return symbols;
507 }
508 
509 } // namespace ns3
This class implements a tag that carries the satellite MAC of GW and UT.
void SetE2ESourceAddress(Mac48Address e2eSourceAddress)
Set E2E source MAC address.
void SetE2EDestAddress(Mac48Address e2eDestAddress)
Set E2E destination MAC address.
SatModcod_t
Modulation scheme and coding rate for DVB-S2.
This class implements a tag that carries the satellite MAC specific information, such as source and d...
void SetDestAddress(Mac48Address dest)
Set destination MAC address.
void SetSourceAddress(Mac48Address source)
Set source MAC address.
SatArqSequenceNumber is handling the sequence numbers for the ARQ process.