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