Loading...
Searching...
No Matches
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
30NS_LOG_COMPONENT_DEFINE("SatFwdLinkSchedulerTimeSlicing");
31
32namespace ns3
33{
34
35NS_OBJECT_ENSURE_REGISTERED(SatFwdLinkSchedulerTimeSlicing);
36
37TypeId
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
54{
55 NS_LOG_FUNCTION(this);
56 NS_FATAL_ERROR("Default constructor for SatFwdLinkSchedulerTimeSlicing not supported");
57}
58
60 Mac48Address address,
61 double carrierBandwidthInHz)
62 : SatFwdLinkScheduler(conf, address, carrierBandwidthInHz),
65{
66 NS_LOG_FUNCTION(this << conf << address << carrierBandwidthInHz);
67}
68
69void
71{
72 NS_LOG_FUNCTION(this);
73
75
76 std::vector<SatEnums::SatModcod_t> modCods = m_bbFrameConf->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
136
137void
144
145std::pair<Ptr<SatBbFrame>, const Time>
147{
148 NS_LOG_FUNCTION(this);
149
150 Ptr<SatBbFrame> frame;
151 Time frameDuration;
152
153 // Send slice control messages first if there is any.
154 if (!m_bbFrameContainers.at(0)->IsEmpty(0, m_bbFrameConf->GetDefaultModCod()))
155 {
156 frame = m_bbFrameContainers.at(0)->GetNextFrame();
157 if (frame != nullptr)
158 {
159 frame->SetSliceId(0);
160 frameDuration = frame->GetDuration();
161 m_symbolsSent.at(0) += ceil(frame->GetDuration().GetSeconds() * m_carrierBandwidthInHz);
162 }
163 else
164 {
165 frameDuration = m_bbFrameConf->GetDummyBbFrameDuration();
166 }
167 }
168 else
169 {
170 uint8_t firstDeque = m_lastSliceDequeued;
171 do
172 {
173 uint32_t symbols = m_symbolsSent.at(m_lastSliceDequeued) + m_symbolsSent.at(0);
174 double maxSymbolRate = m_bbFrameContainers.at(m_lastSliceDequeued)->GetMaxSymbolRate();
175
176 frame = m_bbFrameContainers.at(m_lastSliceDequeued)->GetNextFrame();
177 if (frame != nullptr)
178 {
180 ceil(frame->GetDuration().GetSeconds() * m_carrierBandwidthInHz);
181 symbols += ceil(frame->GetDuration().GetSeconds() * m_carrierBandwidthInHz);
182 frame->SetSliceId(m_lastSliceDequeued);
183 frameDuration = frame->GetDuration();
184
185 if (symbols / m_periodicInterval.GetSeconds() > maxSymbolRate)
186 {
187 NS_LOG_WARN("Symbol rate not respected for slice " +
188 std::to_string(m_lastSliceDequeued) + ". Got " +
189 std::to_string(symbols / m_periodicInterval.GetSeconds()) + "Baud" +
190 " while max is " + std::to_string(maxSymbolRate) + " Baud");
191 }
192 }
194 {
196 }
198 } while (frame == nullptr && m_lastSliceDequeued != firstDeque);
199 }
200
201 // create dummy frame
202 if (m_dummyFrameSendingEnabled && frame == nullptr)
203 {
204 frame = Create<SatBbFrame>(m_bbFrameConf->GetDefaultModCod(),
207
208 // create dummy packet
209 Ptr<Packet> dummyPacket = Create<Packet>(1);
210
211 // Add MAC tag
212 SatMacTag mTag;
213 mTag.SetDestAddress(Mac48Address::GetBroadcast());
215 dummyPacket->AddPacketTag(mTag);
216
217 // Add E2E address tag
218 SatAddressE2ETag addressE2ETag;
219 addressE2ETag.SetE2EDestAddress(Mac48Address::GetBroadcast());
220 addressE2ETag.SetE2ESourceAddress(m_macAddress);
221 dummyPacket->AddPacketTag(addressE2ETag);
222
223 // Add dummy packet to dummy frame
224 frame->AddPayload(dummyPacket);
225 frame->SetSliceId(0);
226 frameDuration = frame->GetDuration();
227 }
228 // If no bb frame available and dummy frames disabled
229 else if (frame == nullptr)
230 {
231 frameDuration = m_bbFrameConf->GetDummyBbFrameDuration();
232 }
233
234 return std::make_pair(frame, frameDuration);
235}
236
237void
239{
240 NS_LOG_FUNCTION(this);
241
242 std::map<uint8_t, Ptr<SatBbFrameContainer>>::iterator it;
243 for (it = m_bbFrameContainers.begin(); it != m_bbFrameContainers.end(); it++)
244 {
245 it->second->ClearAllFrames();
246 }
247}
248
249void
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
269void
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
380void
381SatFwdLinkSchedulerTimeSlicing::GetSchedulingObjects(std::vector<Ptr<SatSchedulingObject>>& output)
382{
383 NS_LOG_FUNCTION(this);
384
386 {
387 // Get scheduling objects from LLC
389
390 SortSchedulingObjects(output);
391 }
392}
393
394Time
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
410void
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
427bool
429 uint32_t priorityClass,
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 =
471 double symbolRate = symbols / m_periodicInterval.GetSeconds();
472 return symbolRate < maxSymbolRate;
473 }
474}
475
476uint32_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.