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 NS_LOG_COMPONENT_DEFINE("SatReturnLinkEncapsulator");
35 
36 namespace ns3
37 {
38 
39 NS_OBJECT_ENSURE_REGISTERED(SatReturnLinkEncapsulator);
40 
42  : m_txFragmentId(0),
43  m_currRxFragmentId(0),
44  m_currRxPacketSize(0),
45  m_currRxPacketFragmentBytes(0),
46  m_minTxOpportunity(0),
47  MAX_FRAGMENT_ID(8),
48  MAX_PPDU_PACKET_SIZE(2048),
49  MAX_HL_PDU_PACKET_SIZE(4096)
50 {
51  NS_LOG_FUNCTION(this);
52  NS_ASSERT(false);
53 
57 }
58 
60  Mac48Address decapAddress,
61  Mac48Address sourceE2EAddress,
62  Mac48Address destE2EAddress,
63  uint8_t flowId,
64  uint32_t additionalHeaderSize)
65  : SatBaseEncapsulator(encapAddress,
66  decapAddress,
67  sourceE2EAddress,
68  destE2EAddress,
69  flowId,
70  additionalHeaderSize),
71  m_txFragmentId(0),
72  m_currRxFragmentId(0),
73  m_currRxPacketSize(0),
74  m_currRxPacketFragmentBytes(0),
75  m_minTxOpportunity(0),
76  MAX_FRAGMENT_ID(8),
77  MAX_PPDU_PACKET_SIZE(2048),
78  MAX_HL_PDU_PACKET_SIZE(4096)
79 {
80  NS_LOG_FUNCTION(this);
81 
82  SatPPduHeader ppduHeader;
84 }
85 
87 {
88  NS_LOG_FUNCTION(this);
89 }
90 
91 TypeId
93 {
94  static TypeId tid = TypeId("ns3::SatReturnLinkEncapsulator")
95  .SetParent<SatBaseEncapsulator>()
96  .AddConstructor<SatReturnLinkEncapsulator>();
97  return tid;
98 }
99 
100 void
102 {
103  NS_LOG_FUNCTION(this);
104 
106 }
107 
108 void
109 SatReturnLinkEncapsulator::EnquePdu(Ptr<Packet> p, Mac48Address /*dest*/)
110 {
111  NS_LOG_FUNCTION(this << p->GetSize());
112 
113  // If the packet is smaller than the maximum size
114  if (p->GetSize() > MAX_HL_PDU_PACKET_SIZE)
115  {
116  NS_FATAL_ERROR("SatReturnLinkEncapsulator received too large HL PDU!");
117  }
118 
119  // Mark the PDU with FULL_PDU tag
122  p->AddPacketTag(tag);
123 
124  // Add MAC tag to identify the packet in lower layers
125  SatMacTag mTag;
128  p->AddPacketTag(mTag);
129 
135  NS_LOG_INFO("Tx Buffer: New packet added of size: " << p->GetSize());
136 
137  if (!m_txQueue->Enqueue(p))
138  {
139  NS_LOG_INFO("Packet is dropped!");
140  }
141 
142  NS_LOG_INFO("NumPackets = " << m_txQueue->GetNPackets());
143  NS_LOG_INFO("NumBytes = " << m_txQueue->GetNBytes());
144 }
145 
146 Ptr<Packet>
148  uint32_t& bytesLeft,
149  uint32_t& nextMinTxO)
150 {
151  NS_LOG_FUNCTION(this << bytes);
152  NS_LOG_INFO("TxOpportunity for UT: " << m_encapAddress << " flowId: " << (uint32_t)m_flowId
153  << " of " << bytes << " bytes");
154 
155  // Payload adapted PDU = NULL
156  Ptr<Packet> packet;
157 
158  NS_LOG_INFO("Queue size before TxOpportunity: " << m_txQueue->GetNBytes());
159 
160  // No packets in buffer
161  if (m_txQueue->GetNPackets() == 0)
162  {
163  NS_LOG_INFO("No data pending, return NULL packet");
164  return packet;
165  }
166 
168 
169  if (packet)
170  {
171  // Add MAC tag to identify the packet in lower layers if not already added
172  SatMacTag mTag;
173  if (!packet->PeekPacketTag(mTag))
174  {
177  packet->AddPacketTag(mTag);
178  }
179 
180  // Add E2E address tag to identify the packet in lower layers
181  SatAddressE2ETag addressE2ETag;
182  if (!packet->PeekPacketTag(addressE2ETag))
183  {
184  addressE2ETag.SetE2EDestAddress(m_destE2EAddress);
186  packet->AddPacketTag(addressE2ETag);
187  }
188 
189  // Add flow id tag
190  SatFlowIdTag flowIdTag;
191  flowIdTag.SetFlowId(m_flowId);
192  packet->AddPacketTag(flowIdTag);
193 
194  if (packet->GetSize() > bytes)
195  {
196  NS_FATAL_ERROR("Created packet of size: "
197  << packet->GetSize() << " is larger than the tx opportunity: " << bytes);
198  }
199  NS_LOG_INFO("Created packet size: " << packet->GetSize());
200  }
201 
202  NS_LOG_INFO("Queue size after TxOpportunity: " << m_txQueue->GetNBytes());
203 
204  // Update bytes lefts
205  bytesLeft = GetTxBufferSizeInBytes();
206 
207  // Update min TxO
208  nextMinTxO = GetMinTxOpportunityInBytes();
209 
210  return packet;
211 }
212 
213 Ptr<Packet>
214 SatReturnLinkEncapsulator::GetNewRlePdu(uint32_t txOpportunityBytes,
215  uint32_t maxRlePduSize,
216  uint32_t additionalHeaderSize)
217 {
218  NS_LOG_FUNCTION(this << txOpportunityBytes << maxRlePduSize << additionalHeaderSize);
219 
220  // Payload adapted PDU = NULL
221  Ptr<Packet> packet;
222 
223  // RLE (PPDU) header
224  SatPPduHeader ppduHeader;
225 
226  // Peek the first PDU from the buffer.
227  Ptr<const Packet> peekSegment = m_txQueue->Peek();
228 
230  bool found = peekSegment->PeekPacketTag(tag);
231  if (!found)
232  {
233  NS_FATAL_ERROR("EncapPduStatus tag not found from packet!");
234  }
235 
236  // Tx opportunity bytes is not enough
237  uint32_t headerSize = ppduHeader.GetHeaderSizeInBytes(tag.GetStatus()) + additionalHeaderSize;
238  if (txOpportunityBytes <= headerSize)
239  {
240  NS_LOG_INFO("TX opportunity too small = " << txOpportunityBytes);
241  return packet;
242  }
243 
244  NS_LOG_INFO("Size of the first packet in buffer: " << peekSegment->GetSize());
245  NS_LOG_INFO("Encapsulation status of the first packet in buffer: " << tag.GetStatus());
246 
247  // Build Data field
248  uint32_t maxSegmentSize = std::min(txOpportunityBytes, maxRlePduSize) - headerSize;
249 
250  NS_LOG_INFO("Maximum supported segment size: " << maxSegmentSize);
251 
252  // Fragmentation if the HL PDU does not fit into the burst or
253  // the HL packet is too large.
254  if (peekSegment->GetSize() > maxSegmentSize)
255  {
256  NS_LOG_INFO("Buffered packet is larger than the maximum segment size!");
257 
259  {
260  // Calculate again that the packet fits into the Tx opportunity
261  headerSize = ppduHeader.GetHeaderSizeInBytes(SatEncapPduStatusTag::START_PDU) +
262  additionalHeaderSize;
263  if (txOpportunityBytes <= headerSize)
264  {
265  NS_LOG_INFO("Start PDU does not fit into the TxOpportunity anymore!");
266  return packet;
267  }
268 
269  maxSegmentSize = std::min(txOpportunityBytes, maxRlePduSize) - headerSize;
270  NS_LOG_INFO("Recalculated maximum supported segment size: " << maxSegmentSize);
271 
272  // In case we have to fragment a FULL PDU, we need to increase
273  // the fragment id.
275  }
276  // END_PDU
277  else
278  {
279  // Calculate again that the packet fits into the Tx opportunity
281  additionalHeaderSize;
282  if (txOpportunityBytes <= headerSize)
283  {
284  NS_LOG_INFO("Continuation PDU does not fit into the TxOpportunity anymore!");
285  return packet;
286  }
287 
288  maxSegmentSize = std::min(txOpportunityBytes, maxRlePduSize) - headerSize;
289  NS_LOG_INFO("Recalculated maximum supported segment size: " << maxSegmentSize);
290  }
291 
292  // Now we can take the packe away from the queue
293  Ptr<Packet> firstSegment = m_txQueue->Dequeue();
294 
295  // Create a new fragment
296  Ptr<Packet> newSegment = firstSegment->CreateFragment(0, maxSegmentSize);
297 
298  // Status tag of the new and remaining segments
299  // Note: This is the only place where a PDU is segmented and
300  // therefore its status can change
301  SatEncapPduStatusTag oldTag, newTag;
302  firstSegment->RemovePacketTag(oldTag);
303  newSegment->RemovePacketTag(newTag);
304 
305  // Create new PPDU header
306  ppduHeader.SetPPduLength(newSegment->GetSize());
307  ppduHeader.SetFragmentId(m_txFragmentId);
308 
310  {
311  ppduHeader.SetStartIndicator();
312  ppduHeader.SetTotalLength(firstSegment->GetSize());
313 
316  }
317  else if (oldTag.GetStatus() == SatEncapPduStatusTag::END_PDU)
318  {
319  // oldTag still is left with the END_PPDU tag
321  }
322 
323  // Give back the remaining segment to the transmission buffer
324  firstSegment->RemoveAtStart(maxSegmentSize);
325 
326  // If bytes left after fragmentation
327  if (firstSegment->GetSize() > 0)
328  {
329  NS_LOG_INFO("Returning the remaining " << firstSegment->GetSize()
330  << " bytes to buffer");
331  firstSegment->AddPacketTag(oldTag);
332  m_txQueue->PushFront(firstSegment);
333  }
334  else
335  {
336  NS_FATAL_ERROR("The full segment was taken even though we are in the fragmentation "
337  "part of the code!");
338  }
339 
340  // Put status tag once it has been adjusted
341  newSegment->AddPacketTag(newTag);
342 
343  // Add PPDU header
344  newSegment->AddHeader(ppduHeader);
345 
346  // PPDU
347  packet = newSegment;
348 
349  NS_LOG_INFO("Created a fragment of size: " << packet->GetSize());
350  }
351  // Packing functionality, for either a FULL_PPDU or END_PPDU
352  else
353  {
354  NS_LOG_INFO("Packing functionality TxO: " << txOpportunityBytes
355  << " packet size: " << peekSegment->GetSize());
356 
358  {
359  ppduHeader.SetStartIndicator();
360  }
361  else
362  {
363  ppduHeader.SetFragmentId(m_txFragmentId);
364  }
365 
366  // Take the packe away from the queue
367  Ptr<Packet> firstSegment = m_txQueue->Dequeue();
368 
369  ppduHeader.SetEndIndicator();
370  ppduHeader.SetPPduLength(firstSegment->GetSize());
371 
372  // Add PPDU header
373  firstSegment->AddHeader(ppduHeader);
374 
375  // PPDU
376  packet = firstSegment;
377 
378  NS_LOG_INFO("Packed a packet of size: " << packet->GetSize());
379  }
380 
381  return packet;
382 }
383 
384 void
386 {
387  NS_LOG_FUNCTION(this << p->GetSize());
388 
389  // Remove encap PDU status tag
390  SatEncapPduStatusTag statusTag;
391  p->RemovePacketTag(statusTag);
392 
393  // Remove flow id tag
394  SatFlowIdTag flowIdTag;
395  p->RemovePacketTag(flowIdTag);
396 
397  // Sanity check
398  SatMacTag mTag;
399  bool mSuccess = p->RemovePacketTag(mTag);
400  if (!mSuccess)
401  {
402  NS_FATAL_ERROR("MAC tag not found in the packet!");
403  }
404  else if (mTag.GetDestAddress() != m_decapAddress)
405  {
406  NS_FATAL_ERROR("Packet was not intended for this receiver!");
407  }
408 
409  // Do decapsulation and defragmentation
410  ProcessPdu(p);
411 }
412 
413 void
415 {
416  NS_LOG_FUNCTION(this << p->GetSize());
417 
418  // Remove PPDU header
419  SatPPduHeader ppduHeader;
420  p->RemoveHeader(ppduHeader);
421 
422  // FULL_PPDU
423  if (ppduHeader.GetStartIndicator() == true && ppduHeader.GetEndIndicator() == true)
424  {
425  NS_LOG_INFO("FULL PPDU received");
426 
427  Reset();
428 
430  }
431 
432  // START_PPDU
433  else if (ppduHeader.GetStartIndicator() == true && ppduHeader.GetEndIndicator() == false)
434  {
435  NS_LOG_INFO("START PPDU received");
436 
437  Reset();
438 
439  m_currRxFragmentId = ppduHeader.GetFragmentId();
440  m_currRxPacketSize = ppduHeader.GetTotalLength();
443  }
444 
445  // CONTINUATION_PPDU
446  else if (ppduHeader.GetStartIndicator() == false && ppduHeader.GetEndIndicator() == false)
447  {
448  NS_LOG_INFO("CONTINUATION PPDU received");
449 
450  // Previous fragment found
452  {
454  m_currRxPacketFragment->AddAtEnd(p);
455  }
456  else
457  {
458  Reset();
459  NS_LOG_INFO(
460  "CONTINUATION PPDU received while the START of the PPDU may have been lost");
461  }
462  }
463 
464  // END_PPDU
465  else if (ppduHeader.GetStartIndicator() == false && ppduHeader.GetEndIndicator() == true)
466  {
467  NS_LOG_INFO("END PPDU received");
468 
469  // Previous fragment found
471  {
473 
474  // The packet size is wrong!
476  {
477  NS_LOG_INFO("END PDU received, but the packet size of the HL PDU is wrong. Drop "
478  "the HL packet!");
479  }
480  // Receive the HL packet here
481  else
482  {
483  m_currRxPacketFragment->AddAtEnd(p);
485  }
486  }
487  else
488  {
489  NS_LOG_INFO("END PPDU received while the START of the PPDU may have been lost");
490  }
491 
492  // Reset anyway
493  Reset();
494  }
495 }
496 
497 void
498 SatReturnLinkEncapsulator::ReceiveAck(Ptr<SatArqAckMessage> ack)
499 {
500  NS_LOG_FUNCTION(this);
501  NS_ASSERT(false);
502 
507 }
508 
509 void
511 {
512  NS_LOG_FUNCTION(this);
513 
514  ++m_txFragmentId;
516  {
517  m_txFragmentId = 0;
518  }
519 }
520 
521 void
523 {
524  NS_LOG_FUNCTION(this);
525 
526  m_currRxFragmentId = 0;
527  m_currRxPacketSize = 0;
530 }
531 
532 uint32_t
534 {
535  NS_LOG_FUNCTION(this);
536 
537  return m_minTxOpportunity;
538 }
539 
540 } // 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.