satellite-generic-stream-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-gse-header.h"
25 #include "satellite-llc.h"
26 #include "satellite-mac-tag.h"
27 #include "satellite-time-tag.h"
28 
29 #include <ns3/log.h>
30 #include <ns3/mac48-address.h>
31 #include <ns3/simulator.h>
32 
33 #include <algorithm>
34 
35 NS_LOG_COMPONENT_DEFINE("SatGenericStreamEncapsulator");
36 
37 namespace ns3
38 {
39 
40 NS_OBJECT_ENSURE_REGISTERED(SatGenericStreamEncapsulator);
41 
44  m_maxGsePduSize(4095),
45  m_txFragmentId(0),
46  m_currRxFragmentId(0),
47  m_currRxPacketSize(0),
48  m_currRxPacketFragmentBytes(0),
49  m_minGseTxOpportunity(0)
50 {
51  NS_LOG_FUNCTION(this);
52  NS_ASSERT(true);
53 }
54 
56  Mac48Address decapAddress,
57  Mac48Address sourceE2EAddress,
58  Mac48Address destE2EAddress,
59  uint8_t flowId,
60  uint32_t additionalHeaderSize)
61  : SatBaseEncapsulator(encapAddress,
62  decapAddress,
63  sourceE2EAddress,
64  destE2EAddress,
65  flowId,
66  additionalHeaderSize),
67  m_maxGsePduSize(4095),
68  m_txFragmentId(0),
69  m_currRxFragmentId(0),
70  m_currRxPacketSize(0),
71  m_currRxPacketFragmentBytes(0),
72  m_minGseTxOpportunity(0)
73 {
74  NS_LOG_FUNCTION(this);
75 
76  SatGseHeader gseHeader;
78 }
79 
81 {
82  NS_LOG_FUNCTION(this);
83 }
84 
85 TypeId
87 {
88  static TypeId tid =
89  TypeId("ns3::SatGenericStreamEncapsulator")
90  .SetParent<SatBaseEncapsulator>()
91  .AddConstructor<SatGenericStreamEncapsulator>()
92  .AddAttribute("MaxGsePduSize",
93  "Maximum size of the GSE PDU (in Bytes)",
94  UintegerValue(4096),
95  MakeUintegerAccessor(&SatGenericStreamEncapsulator::m_maxGsePduSize),
96  MakeUintegerChecker<uint32_t>());
97  return tid;
98 }
99 
100 void
102 {
103  NS_LOG_FUNCTION(this);
104 
106 }
107 
108 void
109 SatGenericStreamEncapsulator::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_PACKET_SIZE)
115  {
116  NS_FATAL_ERROR("SatGenericStreamEncapsulator received too large HL PDU!");
117  }
118 
119  // Mark the PDU with FULL_PDU tag
122  p->AddPacketTag(tag);
123 
124  NS_LOG_INFO("Tx Buffer: New packet added of size: " << p->GetSize());
125 
126  if (!m_txQueue->Enqueue(p))
127  {
128  NS_LOG_INFO("Packet is dropped!");
129  }
130 
131  NS_LOG_INFO("NumPackets = " << m_txQueue->GetNPackets());
132  NS_LOG_INFO("NumBytes = " << m_txQueue->GetNBytes());
133 }
134 
135 Ptr<Packet>
137  uint32_t& bytesLeft,
138  uint32_t& nextMinTxO)
139 {
140  NS_LOG_FUNCTION(this << bytesLeft);
141  NS_LOG_INFO("TxOpportunity for UT: " << m_decapAddress << " flowId: " << (uint32_t)m_flowId
142  << " of " << bytes << " bytes");
143 
144  // GSE PDU
145  Ptr<Packet> packet;
146 
147  // No packets in buffer
148  if (m_txQueue->GetNPackets() == 0)
149  {
150  NS_LOG_INFO("No data pending, return NULL packet");
151  return packet;
152  }
153 
155 
156  if (packet)
157  {
158  // Add MAC tag to identify the packet in lower layers
159  SatMacTag mTag;
162  packet->AddPacketTag(mTag);
163 
164  // Add E2E address tag to identify the packet in lower layers
165  SatAddressE2ETag addressE2ETag;
166  if (!packet->PeekPacketTag(addressE2ETag))
167  {
168  addressE2ETag.SetE2EDestAddress(m_destE2EAddress);
170  packet->AddPacketTag(addressE2ETag);
171  }
172 
173  // Add flow id tag
174  SatFlowIdTag flowIdTag;
175  flowIdTag.SetFlowId(m_flowId);
176  packet->AddPacketTag(flowIdTag);
177 
178  if (packet->GetSize() > bytes)
179  {
180  NS_FATAL_ERROR("Created packet of size: "
181  << packet->GetSize() << " is larger than the tx opportunity: " << bytes);
182  }
183  }
184 
185  // Update bytes lefts
186  bytesLeft = GetTxBufferSizeInBytes();
187 
188  // Update min TxO
189  nextMinTxO = GetMinTxOpportunityInBytes();
190 
191  return packet;
192 }
193 
194 Ptr<Packet>
195 SatGenericStreamEncapsulator::GetNewGsePdu(uint32_t txOpportunityBytes,
196  uint32_t maxGsePduSize,
197  uint32_t additionalHeaderSize)
198 {
199  NS_LOG_FUNCTION(this << txOpportunityBytes << maxGsePduSize << additionalHeaderSize);
200 
201  // GSE packet = NULL
202  Ptr<Packet> packet;
203 
204  // GSE header
205  SatGseHeader gseHeader;
206 
207  // Peek the first PDU from the buffer.
208  Ptr<const Packet> peekPacket = m_txQueue->Peek();
209 
210  SatEncapPduStatusTag peekTag;
211  peekPacket->PeekPacketTag(peekTag);
212 
213  // Too small TxOpportunity!
214  uint32_t headerSize =
215  gseHeader.GetGseHeaderSizeInBytes(peekTag.GetStatus()) + additionalHeaderSize;
216  if (txOpportunityBytes <= headerSize)
217  {
218  NS_LOG_INFO("TX opportunity too small = " << txOpportunityBytes);
219  return packet;
220  }
221 
222  // Build Data field
223  uint32_t maxGsePayload = std::min(txOpportunityBytes, maxGsePduSize) - headerSize;
224 
225  NS_LOG_INFO("GSE header size: " << gseHeader.GetGseHeaderSizeInBytes(peekTag.GetStatus()));
226 
227  // Fragmentation
228  if (peekPacket->GetSize() > maxGsePayload)
229  {
230  NS_LOG_INFO("In fragmentation - packet size: " << peekPacket->GetSize()
231  << " max GSE payload: " << maxGsePayload);
232 
233  // Now we can take the packe away from the queue
234  Ptr<Packet> firstPacket = m_txQueue->Dequeue();
235 
236  // Status tag of the old and new segment
237  // Note: This is the only place where a PDU is segmented and
238  // therefore its status can change
239  SatEncapPduStatusTag oldTag, newTag;
240  firstPacket->RemovePacketTag(oldTag);
241 
242  // Create new GSE header
243  SatGseHeader gseHeader;
244 
246  {
248  gseHeader.SetStartIndicator();
249  gseHeader.SetTotalLength(firstPacket->GetSize());
252 
253  uint32_t newMaxGsePayload =
254  std::min(txOpportunityBytes, maxGsePduSize) -
256  additionalHeaderSize;
257 
258  NS_LOG_INFO("Packet size: " << firstPacket->GetSize()
259  << " max GSE payload: " << maxGsePayload);
260 
261  if (maxGsePayload > newMaxGsePayload)
262  {
263  NS_FATAL_ERROR("Packet will fit into the time slot after all, since we changed to "
264  "utilize START PDU GSE header");
265  }
266  }
267  else if (oldTag.GetStatus() == SatEncapPduStatusTag::END_PDU)
268  {
269  // oldTag still is left with the END_PDU tag
271 
272  uint32_t newMaxGsePayload =
273  std::min(txOpportunityBytes, maxGsePduSize) -
275  additionalHeaderSize;
276 
277  NS_LOG_INFO("Packet size: " << firstPacket->GetSize()
278  << " max GSE payload: " << maxGsePayload);
279 
280  if (maxGsePayload > newMaxGsePayload)
281  {
282  NS_FATAL_ERROR("Packet will fit into the time slot after all, since we changed to "
283  "utilize CONTINUATION PDU GSE header");
284  }
285  }
286 
287  gseHeader.SetFragmentId(m_txFragmentId);
288 
289  // Create a fragment of correct size
290  Ptr<Packet> fragment = firstPacket->CreateFragment(0, maxGsePayload);
291 
292  NS_LOG_INFO("Create fragment of size: " << fragment->GetSize());
293 
294  // Add proper payload length of the GSE packet
295  gseHeader.SetGsePduLength(fragment->GetSize());
296 
297  // Give back the remaining segment to the transmission buffer
298  firstPacket->RemoveAtStart(maxGsePayload);
299 
300  // Add old tag back to the old packet
301  firstPacket->AddPacketTag(oldTag);
302 
303  // Push remainder packet to the queue
304  m_txQueue->PushFront(firstPacket);
305 
306  // Put status tag once it has been adjusted
307  fragment->AddPacketTag(newTag);
308 
309  // Add PDU header
310  fragment->AddHeader(gseHeader);
311 
312  // GSE PDU
313  packet = fragment;
314  }
315  // Just encapsulation
316  else
317  {
318  NS_LOG_INFO("In fragmentation - packet size: " << peekPacket->GetSize()
319  << " max GSE payload: " << maxGsePayload);
320 
321  // Take the packe away from the queue
322  Ptr<Packet> firstPacket = m_txQueue->Dequeue();
323 
324  // Create new GSE header
325  SatGseHeader gseHeader;
326 
328  firstPacket->PeekPacketTag(tag);
329 
331  {
332  gseHeader.SetTotalLength(firstPacket->GetSize());
333  gseHeader.SetStartIndicator();
334  }
335  // Fragment id is added to all fragmented packets
336  else
337  {
338  gseHeader.SetFragmentId(m_txFragmentId);
339  }
340 
341  gseHeader.SetGsePduLength(firstPacket->GetSize());
342  gseHeader.SetEndIndicator();
343 
344  // Add PDU header
345  firstPacket->AddHeader(gseHeader);
346 
347  // GSE PDU
348  packet = firstPacket;
349  }
350 
351  if (packet->GetSize() > txOpportunityBytes)
352  {
353  NS_FATAL_ERROR("Created GSE PDU of size: " << packet->GetSize()
354  << " is larger than the Tx opportunity: "
355  << txOpportunityBytes);
356  }
357 
358  return packet;
359 }
360 
361 void
363 {
364  NS_LOG_FUNCTION(this);
365 
366  ++m_txFragmentId;
368  {
369  m_txFragmentId = 0;
370  }
371 }
372 
373 void
375 {
376  NS_LOG_FUNCTION(this << p->GetSize());
377 
378  // Remove encap PDU status tag
379  SatEncapPduStatusTag statusTag;
380  p->RemovePacketTag(statusTag);
381 
382  // Remove flow id tag
383  SatFlowIdTag flowIdTag;
384  p->RemovePacketTag(flowIdTag);
385 
386  // Sanity check
387  SatMacTag mTag;
388  bool success = p->RemovePacketTag(mTag);
389  if (!success)
390  {
391  NS_FATAL_ERROR("MAC tag not found in the packet!");
392  }
393  else if (mTag.GetDestAddress() != m_decapAddress)
394  {
395  NS_FATAL_ERROR("Packet was not intended for this receiver!");
396  }
397 
398  // Decapsuling and defragmentation
399  ProcessPdu(p);
400 }
401 
402 void
404 {
405  NS_LOG_FUNCTION(this << packet->GetSize());
406 
407  // Remove PDU header
408  SatGseHeader gseHeader;
409  packet->RemoveHeader(gseHeader);
410 
411  // FULL_PDU
412  if (gseHeader.GetStartIndicator() == true && gseHeader.GetEndIndicator() == true)
413  {
414  NS_LOG_INFO("FULL PDU received");
415 
416  Reset();
417 
419  }
420 
421  // START_PDU
422  else if (gseHeader.GetStartIndicator() == true && gseHeader.GetEndIndicator() == false)
423  {
424  NS_LOG_INFO("START PDU received");
425 
426  Reset();
427 
428  m_currRxFragmentId = gseHeader.GetFragmentId();
429  m_currRxPacketSize = gseHeader.GetTotalLength();
431  m_currRxPacketFragment = packet;
432  }
433 
434  // CONTINUATION_PDU
435  else if (gseHeader.GetStartIndicator() == false && gseHeader.GetEndIndicator() == false)
436  {
437  NS_LOG_INFO("CONTINUATION PDU received");
438 
439  // Previous fragment found
441  {
443  m_currRxPacketFragment->AddAtEnd(packet);
444  }
445  else
446  {
447  Reset();
448  NS_LOG_INFO("CONTINUATION PDU received while the START of the PDU may have been lost");
449  }
450  }
451 
452  // END_PDU
453  else if (gseHeader.GetStartIndicator() == false && gseHeader.GetEndIndicator() == true)
454  {
455  NS_LOG_INFO("END PDU received");
456 
457  // Previous fragment found
459  {
461 
462  // The packet size is wrong!
464  {
465  NS_LOG_INFO("END PDU received, but the packet size of the HL PDU is wrong. Drop "
466  "the HL packet!");
467  }
468  // Receive the HL packet here
469  else
470  {
471  m_currRxPacketFragment->AddAtEnd(packet);
473  }
474  }
475  else
476  {
477  NS_LOG_INFO("END PDU received while the START of the PDU may have been lost");
478  }
479 
480  // Reset anyway
481  Reset();
482  }
483 }
484 
485 void
487 {
488  NS_LOG_FUNCTION(this);
489 
490  m_currRxFragmentId = 0;
491  m_currRxPacketSize = 0;
494 }
495 
496 uint32_t
498 {
499  NS_LOG_FUNCTION(this);
500 
501  return m_minGseTxOpportunity;
502 }
503 
504 } // 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.
uint32_t m_txFragmentId
Fragment id used in the packet transmissions.
static const uint32_t MAX_FRAGMENT_ID
The fragment is described with 8 bits, thus the maximum fragment id is 256.
uint32_t m_currRxPacketFragmentBytes
Currently received bytes of the fragmented packet.
virtual void DoDispose()
Dispose of this class instance.
virtual void EnquePdu(Ptr< Packet > p, Mac48Address dest)
Enqueue a Higher Layer packet to txBuffer.
void Reset()
Reset defragmentation variables.
SatGenericStreamEncapsulator()
Default constructor, not used.
static const uint32_t MAX_HL_PACKET_SIZE
The maximum packet size is described with 16 bits, thus, the maximum HL packet size is 65536 bytes.
uint32_t m_currRxFragmentId
Current fragment id in the reassembly process.
Ptr< Packet > GetNewGsePdu(uint32_t txOpportunityBytes, uint32_t maxGsePduSize, uint32_t additionalHeaderSize=0)
Get new packet performs the GSE fragmentation and encapsulation for a one single packet.
uint32_t m_currRxPacketSize
The total size of the ALPDU size reassembly process.
virtual ~SatGenericStreamEncapsulator()
Destructor for SatGenericStreamEncapsulator.
virtual Ptr< Packet > NotifyTxOpportunity(uint32_t bytes, uint32_t &bytesLeft, uint32_t &nextMinTxO)
Notify a Tx opportunity to this encapsulator.
virtual void ReceivePdu(Ptr< Packet > p)
Receive a packet, thus decapsulate and defragment/deconcatenate if needed.
virtual void ProcessPdu(Ptr< Packet > p)
Process the reception of individual GSE PDUs.
Ptr< Packet > m_currRxPacketFragment
Current packet in the reassembly process.
void IncreaseFragmentId()
Method increases the fragment id by one.
uint32_t m_minGseTxOpportunity
If the GSE opportunity is smaller than this, a NULL packet is returned.
virtual uint32_t GetMinTxOpportunityInBytes() const
Get minimum Tx opportunity in bytes, which takes the assumed header sizes into account.
SatGseHeader implementation.
uint8_t GetEndIndicator() const
Get end indicator of GSE header.
uint32_t GetGsePduLength() const
Get GSE fragment length in bytes.
uint32_t GetTotalLength() const
Get total length of higher layer PDU.
uint32_t GetGseHeaderSizeInBytes(uint8_t type) const
Get the maximum GSE header size.
void SetStartIndicator()
Set start indicator to GSE header.
uint8_t GetStartIndicator() const
Get start indicator of GSE header.
uint32_t GetMaxGseHeaderSizeInBytes() const
Get the maximum GSE header size.
uint32_t GetFragmentId() const
Get GSE fragment id.
void SetTotalLength(uint32_t bytes)
Set total length of higher layer PDU.
void SetGsePduLength(uint32_t bytes)
Set GSE fragment length to PPDU header.
void SetEndIndicator()
Set end indicator to GSE header.
void SetFragmentId(uint32_t id)
Set fragment id to GSE header.
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.
SatArqSequenceNumber is handling the sequence numbers for the ARQ process.