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"
27 #include "satellite-rle-header.h"
29 
30 #include <ns3/log.h>
31 #include <ns3/mac48-address.h>
32 #include <ns3/simulator.h>
33 
34 #include <algorithm>
35 
36 NS_LOG_COMPONENT_DEFINE("SatReturnLinkEncapsulator");
37 
38 namespace ns3
39 {
40 
41 NS_OBJECT_ENSURE_REGISTERED(SatReturnLinkEncapsulator);
42 
44  : m_txFragmentId(0),
45  m_currRxFragmentId(0),
46  m_currRxPacketSize(0),
47  m_currRxPacketFragmentBytes(0),
48  m_minTxOpportunity(0),
49  MAX_FRAGMENT_ID(8),
50  MAX_PPDU_PACKET_SIZE(2048),
51  MAX_HL_PDU_PACKET_SIZE(4096)
52 {
53  NS_LOG_FUNCTION(this);
54  NS_ASSERT(false);
55 
59 }
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),
73  m_txFragmentId(0),
74  m_currRxFragmentId(0),
75  m_currRxPacketSize(0),
76  m_currRxPacketFragmentBytes(0),
77  m_minTxOpportunity(0),
78  MAX_FRAGMENT_ID(8),
79  MAX_PPDU_PACKET_SIZE(2048),
80  MAX_HL_PDU_PACKET_SIZE(4096)
81 {
82  NS_LOG_FUNCTION(this);
83 
84  SatPPduHeader ppduHeader;
86 }
87 
89 {
90  NS_LOG_FUNCTION(this);
91 }
92 
93 TypeId
95 {
96  static TypeId tid = TypeId("ns3::SatReturnLinkEncapsulator")
97  .SetParent<SatBaseEncapsulator>()
98  .AddConstructor<SatReturnLinkEncapsulator>();
99  return tid;
100 }
101 
102 void
104 {
105  NS_LOG_FUNCTION(this);
106 
108 }
109 
110 void
111 SatReturnLinkEncapsulator::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 
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 
148 Ptr<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 
215 Ptr<Packet>
216 SatReturnLinkEncapsulator::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
263  headerSize = ppduHeader.GetHeaderSizeInBytes(SatEncapPduStatusTag::START_PDU) +
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 
386 void
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 
415 void
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 
499 void
500 SatReturnLinkEncapsulator::ReceiveAck(Ptr<SatArqAckMessage> ack)
501 {
502  NS_LOG_FUNCTION(this);
503  NS_ASSERT(false);
504 
509 }
510 
511 void
513 {
514  NS_LOG_FUNCTION(this);
515 
516  ++m_txFragmentId;
518  {
519  m_txFragmentId = 0;
520  }
521 }
522 
523 void
525 {
526  NS_LOG_FUNCTION(this);
527 
528  m_currRxFragmentId = 0;
529  m_currRxPacketSize = 0;
532 }
533 
534 uint32_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.
A base encapsulator implementation which does not support encapsulation, fragmentation or packing.
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.