Loading...
Searching...
No Matches
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
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
35NS_LOG_COMPONENT_DEFINE("SatGenericStreamEncapsulator");
36
37namespace ns3
38{
39
40NS_OBJECT_ENSURE_REGISTERED(SatGenericStreamEncapsulator);
41
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),
73{
74 NS_LOG_FUNCTION(this);
75
76 SatGseHeader gseHeader;
78}
79
84
85TypeId
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),
96 MakeUintegerChecker<uint32_t>());
97 return tid;
98}
99
100void
102{
103 NS_LOG_FUNCTION(this);
104
106}
107
108void
109SatGenericStreamEncapsulator::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
135Ptr<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
194Ptr<Packet>
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
361void
363{
364 NS_LOG_FUNCTION(this);
365
368 {
369 m_txFragmentId = 0;
370 }
371}
372
373void
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
402void
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();
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
485void
487{
488 NS_LOG_FUNCTION(this);
489
494}
495
496uint32_t
498{
499 NS_LOG_FUNCTION(this);
500
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.
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.
SatGenericStreamEncapsulator class is used in the FWD link for GSE encapsulation and fragmentation of...
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.
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.