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 NS_LOG_COMPONENT_DEFINE("SatGenericStreamEncapsulator");
34 
35 namespace ns3
36 {
37 
38 NS_OBJECT_ENSURE_REGISTERED(SatGenericStreamEncapsulator);
39 
42  m_maxGsePduSize(4095),
43  m_txFragmentId(0),
44  m_currRxFragmentId(0),
45  m_currRxPacketSize(0),
46  m_currRxPacketFragmentBytes(0),
47  m_minGseTxOpportunity(0)
48 {
49  NS_LOG_FUNCTION(this);
50  NS_ASSERT(true);
51 }
52 
54  Mac48Address decapAddress,
55  Mac48Address sourceE2EAddress,
56  Mac48Address destE2EAddress,
57  uint8_t flowId,
58  uint32_t additionalHeaderSize)
59  : SatBaseEncapsulator(encapAddress,
60  decapAddress,
61  sourceE2EAddress,
62  destE2EAddress,
63  flowId,
64  additionalHeaderSize),
65  m_maxGsePduSize(4095),
66  m_txFragmentId(0),
67  m_currRxFragmentId(0),
68  m_currRxPacketSize(0),
69  m_currRxPacketFragmentBytes(0),
70  m_minGseTxOpportunity(0)
71 {
72  NS_LOG_FUNCTION(this);
73 
74  SatGseHeader gseHeader;
76 }
77 
79 {
80  NS_LOG_FUNCTION(this);
81 }
82 
83 TypeId
85 {
86  static TypeId tid =
87  TypeId("ns3::SatGenericStreamEncapsulator")
88  .SetParent<SatBaseEncapsulator>()
89  .AddConstructor<SatGenericStreamEncapsulator>()
90  .AddAttribute("MaxGsePduSize",
91  "Maximum size of the GSE PDU (in Bytes)",
92  UintegerValue(4096),
93  MakeUintegerAccessor(&SatGenericStreamEncapsulator::m_maxGsePduSize),
94  MakeUintegerChecker<uint32_t>());
95  return tid;
96 }
97 
98 void
100 {
101  NS_LOG_FUNCTION(this);
102 
104 }
105 
106 void
107 SatGenericStreamEncapsulator::EnquePdu(Ptr<Packet> p, Mac48Address /*dest*/)
108 {
109  NS_LOG_FUNCTION(this << p->GetSize());
110 
111  // If the packet is smaller than the maximum size
112  if (p->GetSize() > MAX_HL_PACKET_SIZE)
113  {
114  NS_FATAL_ERROR("SatGenericStreamEncapsulator received too large HL PDU!");
115  }
116 
117  // Mark the PDU with FULL_PDU tag
120  p->AddPacketTag(tag);
121 
122  NS_LOG_INFO("Tx Buffer: New packet added of size: " << p->GetSize());
123 
124  if (!m_txQueue->Enqueue(p))
125  {
126  NS_LOG_INFO("Packet is dropped!");
127  }
128 
129  NS_LOG_INFO("NumPackets = " << m_txQueue->GetNPackets());
130  NS_LOG_INFO("NumBytes = " << m_txQueue->GetNBytes());
131 }
132 
133 Ptr<Packet>
135  uint32_t& bytesLeft,
136  uint32_t& nextMinTxO)
137 {
138  NS_LOG_FUNCTION(this << bytesLeft);
139  NS_LOG_INFO("TxOpportunity for UT: " << m_decapAddress << " flowId: " << (uint32_t)m_flowId
140  << " of " << bytes << " bytes");
141 
142  // GSE PDU
143  Ptr<Packet> packet;
144 
145  // No packets in buffer
146  if (m_txQueue->GetNPackets() == 0)
147  {
148  NS_LOG_INFO("No data pending, return NULL packet");
149  return packet;
150  }
151 
153 
154  if (packet)
155  {
156  // Add MAC tag to identify the packet in lower layers
157  SatMacTag mTag;
160  packet->AddPacketTag(mTag);
161 
162  // Add E2E address tag to identify the packet in lower layers
163  SatAddressE2ETag addressE2ETag;
164  if (!packet->PeekPacketTag(addressE2ETag))
165  {
166  addressE2ETag.SetE2EDestAddress(m_destE2EAddress);
168  packet->AddPacketTag(addressE2ETag);
169  }
170 
171  // Add flow id tag
172  SatFlowIdTag flowIdTag;
173  flowIdTag.SetFlowId(m_flowId);
174  packet->AddPacketTag(flowIdTag);
175 
176  if (packet->GetSize() > bytes)
177  {
178  NS_FATAL_ERROR("Created packet of size: "
179  << packet->GetSize() << " is larger than the tx opportunity: " << bytes);
180  }
181  }
182 
183  // Update bytes lefts
184  bytesLeft = GetTxBufferSizeInBytes();
185 
186  // Update min TxO
187  nextMinTxO = GetMinTxOpportunityInBytes();
188 
189  return packet;
190 }
191 
192 Ptr<Packet>
193 SatGenericStreamEncapsulator::GetNewGsePdu(uint32_t txOpportunityBytes,
194  uint32_t maxGsePduSize,
195  uint32_t additionalHeaderSize)
196 {
197  NS_LOG_FUNCTION(this << txOpportunityBytes << maxGsePduSize << additionalHeaderSize);
198 
199  // GSE packet = NULL
200  Ptr<Packet> packet;
201 
202  // GSE header
203  SatGseHeader gseHeader;
204 
205  // Peek the first PDU from the buffer.
206  Ptr<const Packet> peekPacket = m_txQueue->Peek();
207 
208  SatEncapPduStatusTag peekTag;
209  peekPacket->PeekPacketTag(peekTag);
210 
211  // Too small TxOpportunity!
212  uint32_t headerSize =
213  gseHeader.GetGseHeaderSizeInBytes(peekTag.GetStatus()) + additionalHeaderSize;
214  if (txOpportunityBytes <= headerSize)
215  {
216  NS_LOG_INFO("TX opportunity too small = " << txOpportunityBytes);
217  return packet;
218  }
219 
220  // Build Data field
221  uint32_t maxGsePayload = std::min(txOpportunityBytes, maxGsePduSize) - headerSize;
222 
223  NS_LOG_INFO("GSE header size: " << gseHeader.GetGseHeaderSizeInBytes(peekTag.GetStatus()));
224 
225  // Fragmentation
226  if (peekPacket->GetSize() > maxGsePayload)
227  {
228  NS_LOG_INFO("In fragmentation - packet size: " << peekPacket->GetSize()
229  << " max GSE payload: " << maxGsePayload);
230 
231  // Now we can take the packe away from the queue
232  Ptr<Packet> firstPacket = m_txQueue->Dequeue();
233 
234  // Status tag of the old and new segment
235  // Note: This is the only place where a PDU is segmented and
236  // therefore its status can change
237  SatEncapPduStatusTag oldTag, newTag;
238  firstPacket->RemovePacketTag(oldTag);
239 
240  // Create new GSE header
241  SatGseHeader gseHeader;
242 
244  {
246  gseHeader.SetStartIndicator();
247  gseHeader.SetTotalLength(firstPacket->GetSize());
250 
251  uint32_t newMaxGsePayload =
252  std::min(txOpportunityBytes, maxGsePduSize) -
254  additionalHeaderSize;
255 
256  NS_LOG_INFO("Packet size: " << firstPacket->GetSize()
257  << " max GSE payload: " << maxGsePayload);
258 
259  if (maxGsePayload > newMaxGsePayload)
260  {
261  NS_FATAL_ERROR("Packet will fit into the time slot after all, since we changed to "
262  "utilize START PDU GSE header");
263  }
264  }
265  else if (oldTag.GetStatus() == SatEncapPduStatusTag::END_PDU)
266  {
267  // oldTag still is left with the END_PDU tag
269 
270  uint32_t newMaxGsePayload =
271  std::min(txOpportunityBytes, maxGsePduSize) -
273  additionalHeaderSize;
274 
275  NS_LOG_INFO("Packet size: " << firstPacket->GetSize()
276  << " max GSE payload: " << maxGsePayload);
277 
278  if (maxGsePayload > newMaxGsePayload)
279  {
280  NS_FATAL_ERROR("Packet will fit into the time slot after all, since we changed to "
281  "utilize CONTINUATION PDU GSE header");
282  }
283  }
284 
285  gseHeader.SetFragmentId(m_txFragmentId);
286 
287  // Create a fragment of correct size
288  Ptr<Packet> fragment = firstPacket->CreateFragment(0, maxGsePayload);
289 
290  NS_LOG_INFO("Create fragment of size: " << fragment->GetSize());
291 
292  // Add proper payload length of the GSE packet
293  gseHeader.SetGsePduLength(fragment->GetSize());
294 
295  // Give back the remaining segment to the transmission buffer
296  firstPacket->RemoveAtStart(maxGsePayload);
297 
298  // Add old tag back to the old packet
299  firstPacket->AddPacketTag(oldTag);
300 
301  // Push remainder packet to the queue
302  m_txQueue->PushFront(firstPacket);
303 
304  // Put status tag once it has been adjusted
305  fragment->AddPacketTag(newTag);
306 
307  // Add PDU header
308  fragment->AddHeader(gseHeader);
309 
310  // GSE PDU
311  packet = fragment;
312  }
313  // Just encapsulation
314  else
315  {
316  NS_LOG_INFO("In fragmentation - packet size: " << peekPacket->GetSize()
317  << " max GSE payload: " << maxGsePayload);
318 
319  // Take the packe away from the queue
320  Ptr<Packet> firstPacket = m_txQueue->Dequeue();
321 
322  // Create new GSE header
323  SatGseHeader gseHeader;
324 
326  firstPacket->PeekPacketTag(tag);
327 
329  {
330  gseHeader.SetTotalLength(firstPacket->GetSize());
331  gseHeader.SetStartIndicator();
332  }
333  // Fragment id is added to all fragmented packets
334  else
335  {
336  gseHeader.SetFragmentId(m_txFragmentId);
337  }
338 
339  gseHeader.SetGsePduLength(firstPacket->GetSize());
340  gseHeader.SetEndIndicator();
341 
342  // Add PDU header
343  firstPacket->AddHeader(gseHeader);
344 
345  // GSE PDU
346  packet = firstPacket;
347  }
348 
349  if (packet->GetSize() > txOpportunityBytes)
350  {
351  NS_FATAL_ERROR("Created GSE PDU of size: " << packet->GetSize()
352  << " is larger than the Tx opportunity: "
353  << txOpportunityBytes);
354  }
355 
356  return packet;
357 }
358 
359 void
361 {
362  NS_LOG_FUNCTION(this);
363 
364  ++m_txFragmentId;
366  {
367  m_txFragmentId = 0;
368  }
369 }
370 
371 void
373 {
374  NS_LOG_FUNCTION(this << p->GetSize());
375 
376  // Remove encap PDU status tag
377  SatEncapPduStatusTag statusTag;
378  p->RemovePacketTag(statusTag);
379 
380  // Remove flow id tag
381  SatFlowIdTag flowIdTag;
382  p->RemovePacketTag(flowIdTag);
383 
384  // Sanity check
385  SatMacTag mTag;
386  bool success = p->RemovePacketTag(mTag);
387  if (!success)
388  {
389  NS_FATAL_ERROR("MAC tag not found in the packet!");
390  }
391  else if (mTag.GetDestAddress() != m_decapAddress)
392  {
393  NS_FATAL_ERROR("Packet was not intended for this receiver!");
394  }
395 
396  // Decapsuling and defragmentation
397  ProcessPdu(p);
398 }
399 
400 void
402 {
403  NS_LOG_FUNCTION(this << packet->GetSize());
404 
405  // Remove PDU header
406  SatGseHeader gseHeader;
407  packet->RemoveHeader(gseHeader);
408 
409  // FULL_PDU
410  if (gseHeader.GetStartIndicator() == true && gseHeader.GetEndIndicator() == true)
411  {
412  NS_LOG_INFO("FULL PDU received");
413 
414  Reset();
415 
417  }
418 
419  // START_PDU
420  else if (gseHeader.GetStartIndicator() == true && gseHeader.GetEndIndicator() == false)
421  {
422  NS_LOG_INFO("START PDU received");
423 
424  Reset();
425 
426  m_currRxFragmentId = gseHeader.GetFragmentId();
427  m_currRxPacketSize = gseHeader.GetTotalLength();
429  m_currRxPacketFragment = packet;
430  }
431 
432  // CONTINUATION_PDU
433  else if (gseHeader.GetStartIndicator() == false && gseHeader.GetEndIndicator() == false)
434  {
435  NS_LOG_INFO("CONTINUATION PDU received");
436 
437  // Previous fragment found
439  {
441  m_currRxPacketFragment->AddAtEnd(packet);
442  }
443  else
444  {
445  Reset();
446  NS_LOG_INFO("CONTINUATION PDU received while the START of the PDU may have been lost");
447  }
448  }
449 
450  // END_PDU
451  else if (gseHeader.GetStartIndicator() == false && gseHeader.GetEndIndicator() == true)
452  {
453  NS_LOG_INFO("END PDU received");
454 
455  // Previous fragment found
457  {
459 
460  // The packet size is wrong!
462  {
463  NS_LOG_INFO("END PDU received, but the packet size of the HL PDU is wrong. Drop "
464  "the HL packet!");
465  }
466  // Receive the HL packet here
467  else
468  {
469  m_currRxPacketFragment->AddAtEnd(packet);
471  }
472  }
473  else
474  {
475  NS_LOG_INFO("END PDU received while the START of the PDU may have been lost");
476  }
477 
478  // Reset anyway
479  Reset();
480  }
481 }
482 
483 void
485 {
486  NS_LOG_FUNCTION(this);
487 
488  m_currRxFragmentId = 0;
489  m_currRxPacketSize = 0;
492 }
493 
494 uint32_t
496 {
497  NS_LOG_FUNCTION(this);
498 
499  return m_minGseTxOpportunity;
500 }
501 
502 } // 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.