Loading...
Searching...
No Matches
satellite-return-link-encapsulator.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: Jani Puttonen <jani.puttonen@magister.fi>
19 */
20
22
24#include "satellite-llc.h"
25#include "satellite-mac-tag.h"
26#include "satellite-queue.h"
29
30#include "ns3/log.h"
31#include "ns3/mac48-address.h"
32#include "ns3/simulator.h"
33
34#include <algorithm>
35
36NS_LOG_COMPONENT_DEFINE("SatReturnLinkEncapsulator");
37
38namespace ns3
39{
40
41NS_OBJECT_ENSURE_REGISTERED(SatReturnLinkEncapsulator);
42
60
62 Mac48Address decapAddress,
63 Mac48Address sourceE2EAddress,
64 Mac48Address destE2EAddress,
65 uint8_t flowId,
66 uint32_t additionalHeaderSize)
67 : SatBaseEncapsulator(encapAddress,
68 decapAddress,
69 sourceE2EAddress,
70 destE2EAddress,
71 flowId,
72 additionalHeaderSize),
81{
82 NS_LOG_FUNCTION(this);
83
84 SatPPduHeader ppduHeader;
86}
87
92
93TypeId
95{
96 static TypeId tid = TypeId("ns3::SatReturnLinkEncapsulator")
97 .SetParent<SatBaseEncapsulator>()
98 .AddConstructor<SatReturnLinkEncapsulator>();
99 return tid;
100}
101
102void
104{
105 NS_LOG_FUNCTION(this);
106
108}
109
110void
111SatReturnLinkEncapsulator::EnquePdu(Ptr<Packet> p, Mac48Address /*dest*/)
112{
113 NS_LOG_FUNCTION(this << p->GetSize());
114
115 // If the packet is smaller than the maximum size
116 if (p->GetSize() > MAX_HL_PDU_PACKET_SIZE)
117 {
118 NS_FATAL_ERROR("SatReturnLinkEncapsulator received too large HL PDU!");
119 }
120
121 // Mark the PDU with FULL_PDU tag
124 p->AddPacketTag(tag);
125
126 // Add MAC tag to identify the packet in lower layers
127 SatMacTag mTag;
130 p->AddPacketTag(mTag);
131
136
137 NS_LOG_INFO("Tx Buffer: New packet added of size: " << p->GetSize());
138
139 if (!m_txQueue->Enqueue(p))
140 {
141 NS_LOG_INFO("Packet is dropped!");
142 }
143
144 NS_LOG_INFO("NumPackets = " << m_txQueue->GetNPackets());
145 NS_LOG_INFO("NumBytes = " << m_txQueue->GetNBytes());
146}
147
148Ptr<Packet>
150 uint32_t& bytesLeft,
151 uint32_t& nextMinTxO)
152{
153 NS_LOG_FUNCTION(this << bytes);
154 NS_LOG_INFO("TxOpportunity for UT: " << m_encapAddress << " flowId: " << (uint32_t)m_flowId
155 << " of " << bytes << " bytes");
156
157 // Payload adapted PDU = NULL
158 Ptr<Packet> packet;
159
160 NS_LOG_INFO("Queue size before TxOpportunity: " << m_txQueue->GetNBytes());
161
162 // No packets in buffer
163 if (m_txQueue->GetNPackets() == 0)
164 {
165 NS_LOG_INFO("No data pending, return NULL packet");
166 return packet;
167 }
168
170
171 if (packet)
172 {
173 // Add MAC tag to identify the packet in lower layers if not already added
174 SatMacTag mTag;
175 if (!packet->PeekPacketTag(mTag))
176 {
179 packet->AddPacketTag(mTag);
180 }
181
182 // Add E2E address tag to identify the packet in lower layers
183 SatAddressE2ETag addressE2ETag;
184 if (!packet->PeekPacketTag(addressE2ETag))
185 {
186 addressE2ETag.SetE2EDestAddress(m_destE2EAddress);
188 packet->AddPacketTag(addressE2ETag);
189 }
190
191 // Add flow id tag
192 SatFlowIdTag flowIdTag;
193 flowIdTag.SetFlowId(m_flowId);
194 packet->AddPacketTag(flowIdTag);
195
196 if (packet->GetSize() > bytes)
197 {
198 NS_FATAL_ERROR("Created packet of size: "
199 << packet->GetSize() << " is larger than the tx opportunity: " << bytes);
200 }
201 NS_LOG_INFO("Created packet size: " << packet->GetSize());
202 }
203
204 NS_LOG_INFO("Queue size after TxOpportunity: " << m_txQueue->GetNBytes());
205
206 // Update bytes lefts
207 bytesLeft = GetTxBufferSizeInBytes();
208
209 // Update min TxO
210 nextMinTxO = GetMinTxOpportunityInBytes();
211
212 return packet;
213}
214
215Ptr<Packet>
216SatReturnLinkEncapsulator::GetNewRlePdu(uint32_t txOpportunityBytes,
217 uint32_t maxRlePduSize,
218 uint32_t additionalHeaderSize)
219{
220 NS_LOG_FUNCTION(this << txOpportunityBytes << maxRlePduSize << additionalHeaderSize);
221
222 // Payload adapted PDU = NULL
223 Ptr<Packet> packet;
224
225 // RLE (PPDU) header
226 SatPPduHeader ppduHeader;
227
228 // Peek the first PDU from the buffer.
229 Ptr<const Packet> peekSegment = m_txQueue->Peek();
230
232 bool found = peekSegment->PeekPacketTag(tag);
233 if (!found)
234 {
235 NS_FATAL_ERROR("EncapPduStatus tag not found from packet!");
236 }
237
238 // Tx opportunity bytes is not enough
239 uint32_t headerSize = ppduHeader.GetHeaderSizeInBytes(tag.GetStatus()) + additionalHeaderSize;
240 if (txOpportunityBytes <= headerSize)
241 {
242 NS_LOG_INFO("TX opportunity too small = " << txOpportunityBytes);
243 return packet;
244 }
245
246 NS_LOG_INFO("Size of the first packet in buffer: " << peekSegment->GetSize());
247 NS_LOG_INFO("Encapsulation status of the first packet in buffer: " << tag.GetStatus());
248
249 // Build Data field
250 uint32_t maxSegmentSize = std::min(txOpportunityBytes, maxRlePduSize) - headerSize;
251
252 NS_LOG_INFO("Maximum supported segment size: " << maxSegmentSize);
253
254 // Fragmentation if the HL PDU does not fit into the burst or
255 // the HL packet is too large.
256 if (peekSegment->GetSize() > maxSegmentSize)
257 {
258 NS_LOG_INFO("Buffered packet is larger than the maximum segment size!");
259
261 {
262 // Calculate again that the packet fits into the Tx opportunity
264 additionalHeaderSize;
265 if (txOpportunityBytes <= headerSize)
266 {
267 NS_LOG_INFO("Start PDU does not fit into the TxOpportunity anymore!");
268 return packet;
269 }
270
271 maxSegmentSize = std::min(txOpportunityBytes, maxRlePduSize) - headerSize;
272 NS_LOG_INFO("Recalculated maximum supported segment size: " << maxSegmentSize);
273
274 // In case we have to fragment a FULL PDU, we need to increase
275 // the fragment id.
277 }
278 // END_PDU
279 else
280 {
281 // Calculate again that the packet fits into the Tx opportunity
283 additionalHeaderSize;
284 if (txOpportunityBytes <= headerSize)
285 {
286 NS_LOG_INFO("Continuation PDU does not fit into the TxOpportunity anymore!");
287 return packet;
288 }
289
290 maxSegmentSize = std::min(txOpportunityBytes, maxRlePduSize) - headerSize;
291 NS_LOG_INFO("Recalculated maximum supported segment size: " << maxSegmentSize);
292 }
293
294 // Now we can take the packe away from the queue
295 Ptr<Packet> firstSegment = m_txQueue->Dequeue();
296
297 // Create a new fragment
298 Ptr<Packet> newSegment = firstSegment->CreateFragment(0, maxSegmentSize);
299
300 // Status tag of the new and remaining segments
301 // Note: This is the only place where a PDU is segmented and
302 // therefore its status can change
303 SatEncapPduStatusTag oldTag, newTag;
304 firstSegment->RemovePacketTag(oldTag);
305 newSegment->RemovePacketTag(newTag);
306
307 // Create new PPDU header
308 ppduHeader.SetPPduLength(newSegment->GetSize());
309 ppduHeader.SetFragmentId(m_txFragmentId);
310
312 {
313 ppduHeader.SetStartIndicator();
314 ppduHeader.SetTotalLength(firstSegment->GetSize());
315
318 }
319 else if (oldTag.GetStatus() == SatEncapPduStatusTag::END_PDU)
320 {
321 // oldTag still is left with the END_PPDU tag
323 }
324
325 // Give back the remaining segment to the transmission buffer
326 firstSegment->RemoveAtStart(maxSegmentSize);
327
328 // If bytes left after fragmentation
329 if (firstSegment->GetSize() > 0)
330 {
331 NS_LOG_INFO("Returning the remaining " << firstSegment->GetSize()
332 << " bytes to buffer");
333 firstSegment->AddPacketTag(oldTag);
334 m_txQueue->PushFront(firstSegment);
335 }
336 else
337 {
338 NS_FATAL_ERROR("The full segment was taken even though we are in the fragmentation "
339 "part of the code!");
340 }
341
342 // Put status tag once it has been adjusted
343 newSegment->AddPacketTag(newTag);
344
345 // Add PPDU header
346 newSegment->AddHeader(ppduHeader);
347
348 // PPDU
349 packet = newSegment;
350
351 NS_LOG_INFO("Created a fragment of size: " << packet->GetSize());
352 }
353 // Packing functionality, for either a FULL_PPDU or END_PPDU
354 else
355 {
356 NS_LOG_INFO("Packing functionality TxO: " << txOpportunityBytes
357 << " packet size: " << peekSegment->GetSize());
358
360 {
361 ppduHeader.SetStartIndicator();
362 }
363 else
364 {
365 ppduHeader.SetFragmentId(m_txFragmentId);
366 }
367
368 // Take the packe away from the queue
369 Ptr<Packet> firstSegment = m_txQueue->Dequeue();
370
371 ppduHeader.SetEndIndicator();
372 ppduHeader.SetPPduLength(firstSegment->GetSize());
373
374 // Add PPDU header
375 firstSegment->AddHeader(ppduHeader);
376
377 // PPDU
378 packet = firstSegment;
379
380 NS_LOG_INFO("Packed a packet of size: " << packet->GetSize());
381 }
382
383 return packet;
384}
385
386void
388{
389 NS_LOG_FUNCTION(this << p->GetSize());
390
391 // Remove encap PDU status tag
392 SatEncapPduStatusTag statusTag;
393 p->RemovePacketTag(statusTag);
394
395 // Remove flow id tag
396 SatFlowIdTag flowIdTag;
397 p->RemovePacketTag(flowIdTag);
398
399 // Sanity check
400 SatMacTag mTag;
401 bool mSuccess = p->RemovePacketTag(mTag);
402 if (!mSuccess)
403 {
404 NS_FATAL_ERROR("MAC tag not found in the packet!");
405 }
406 else if (mTag.GetDestAddress() != m_decapAddress)
407 {
408 NS_FATAL_ERROR("Packet was not intended for this receiver!");
409 }
410
411 // Do decapsulation and defragmentation
412 ProcessPdu(p);
413}
414
415void
417{
418 NS_LOG_FUNCTION(this << p->GetSize());
419
420 // Remove PPDU header
421 SatPPduHeader ppduHeader;
422 p->RemoveHeader(ppduHeader);
423
424 // FULL_PPDU
425 if (ppduHeader.GetStartIndicator() == true && ppduHeader.GetEndIndicator() == true)
426 {
427 NS_LOG_INFO("FULL PPDU received");
428
429 Reset();
430
432 }
433
434 // START_PPDU
435 else if (ppduHeader.GetStartIndicator() == true && ppduHeader.GetEndIndicator() == false)
436 {
437 NS_LOG_INFO("START PPDU received");
438
439 Reset();
440
441 m_currRxFragmentId = ppduHeader.GetFragmentId();
442 m_currRxPacketSize = ppduHeader.GetTotalLength();
445 }
446
447 // CONTINUATION_PPDU
448 else if (ppduHeader.GetStartIndicator() == false && ppduHeader.GetEndIndicator() == false)
449 {
450 NS_LOG_INFO("CONTINUATION PPDU received");
451
452 // Previous fragment found
454 {
456 m_currRxPacketFragment->AddAtEnd(p);
457 }
458 else
459 {
460 Reset();
461 NS_LOG_INFO(
462 "CONTINUATION PPDU received while the START of the PPDU may have been lost");
463 }
464 }
465
466 // END_PPDU
467 else if (ppduHeader.GetStartIndicator() == false && ppduHeader.GetEndIndicator() == true)
468 {
469 NS_LOG_INFO("END PPDU received");
470
471 // Previous fragment found
473 {
475
476 // The packet size is wrong!
478 {
479 NS_LOG_INFO("END PDU received, but the packet size of the HL PDU is wrong. Drop "
480 "the HL packet!");
481 }
482 // Receive the HL packet here
483 else
484 {
485 m_currRxPacketFragment->AddAtEnd(p);
487 }
488 }
489 else
490 {
491 NS_LOG_INFO("END PPDU received while the START of the PPDU may have been lost");
492 }
493
494 // Reset anyway
495 Reset();
496 }
497}
498
499void
501{
502 NS_LOG_FUNCTION(this);
503 NS_ASSERT(false);
504
509}
510
511void
513{
514 NS_LOG_FUNCTION(this);
515
518 {
519 m_txFragmentId = 0;
520 }
521}
522
523void
525{
526 NS_LOG_FUNCTION(this);
527
532}
533
534uint32_t
536{
537 NS_LOG_FUNCTION(this);
538
539 return m_minTxOpportunity;
540}
541
542} // 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.
SatBaseEncapsulator()
Default constructor not used.
virtual uint32_t GetTxBufferSizeInBytes() const
Get the buffered packets for this encapsulator.
ReceiveCallback m_rxCallback
Receive callback.
virtual void DoDispose()
Dispose of this class instance.
Mac48Address m_encapAddress
Source and destination mac addresses.
Ptr< SatQueue > m_txQueue
Used queue in satellite encapsulator.
uint32_t m_additionalHeaderSize
Additional value in to take into account when pulling packets to represent E2E tags.
SatEncapPduStatusTag is used temporarily to tag packets with the fragmentation status in the encapsul...
void SetStatus(uint8_t status)
Set PDU status.
uint8_t GetStatus(void) const
Get PDU status.
SatFlowIdTag implements a tag which carries the flow identifier of a packet.
void SetFlowId(uint8_t flowId)
Set flow id.
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.
Mac48Address GetDestAddress(void) const
Get destination MAC address.
void SetSourceAddress(Mac48Address source)
Set source MAC address.
SatPPduHeader implementation.
uint32_t GetMaxHeaderSizeInBytes() const
Get maximum RLE header size.
void SetPPduLength(uint16_t bytes)
Set PPDU fragment length to PPDU header.
uint16_t GetPPduLength() const
Get PPDU fragment length in bytes.
void SetEndIndicator()
Set end indicator to PPDU header.
void SetTotalLength(uint16_t bytes)
Set total length of higher layer PDU.
uint32_t GetHeaderSizeInBytes(uint8_t type) const
Get the maximum RLE header size.
uint8_t GetEndIndicator() const
Get end indicator of PPDU header.
void SetStartIndicator()
Set start indicator to PPDU header.
uint8_t GetFragmentId() const
Get PPDU fragment id.
void SetFragmentId(uint8_t id)
Set fragment id to PPDU header.
uint16_t GetTotalLength() const
Get total length of higher layer PDU.
uint8_t GetStartIndicator() const
Get start indicator of PPDU header.
SatArqSequenceNumber is handling the sequence numbers for the ARQ process.