Loading...
Searching...
No Matches
satellite-return-link-encapsulator-arq.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
26#include "satellite-llc.h"
27#include "satellite-mac-tag.h"
28#include "satellite-queue.h"
29#include "satellite-time-tag.h"
30
31#include "ns3/log.h"
32#include "ns3/mac48-address.h"
33#include "ns3/simulator.h"
34
35#include <algorithm>
36#include <limits>
37#include <map>
38#include <utility>
39
40NS_LOG_COMPONENT_DEFINE("SatReturnLinkEncapsulatorArq");
41
42namespace ns3
43{
44
45NS_OBJECT_ENSURE_REGISTERED(SatReturnLinkEncapsulatorArq);
46
48 : m_seqNo(),
55 m_retransmissionTimer(Seconds(0.6)),
59{
60 NS_LOG_FUNCTION(this);
61 NS_ASSERT(false);
62
66}
67
69 Mac48Address decapAddress,
70 Mac48Address sourceE2EAddress,
71 Mac48Address destE2EAddress,
72 uint8_t flowId,
73 uint32_t additionalHeaderSize)
74 : SatReturnLinkEncapsulator(encapAddress,
75 decapAddress,
76 sourceE2EAddress,
77 destE2EAddress,
78 flowId,
79 additionalHeaderSize),
80 m_seqNo(),
87 m_retransmissionTimer(Seconds(0.6)),
91{
92 NS_LOG_FUNCTION(this << encapAddress << decapAddress << sourceE2EAddress << destE2EAddress
93 << flowId << additionalHeaderSize);
94}
95
96void
98{
99 NS_LOG_FUNCTION(this);
100
101 SatReturnLinkEncapsulator::NotifyConstructionCompleted();
102
103 m_seqNo = Create<SatArqSequenceNumber>(m_arqWindowSize);
104}
105
110
111TypeId
113{
114 static TypeId tid =
115 TypeId("ns3::SatReturnLinkEncapsulatorArq")
116 .SetParent<SatReturnLinkEncapsulator>()
117 .AddConstructor<SatReturnLinkEncapsulatorArq>()
118 .AddAttribute(
119 "MaxRtnArqSegmentSize",
120 "Maximum return link ARQ segment size in Bytes.",
121 UintegerValue(37),
123 MakeUintegerChecker<uint32_t>())
124 .AddAttribute(
125 "MaxNoOfRetransmissions",
126 "Maximum number of retransmissions for a single RLE PDU.",
127 UintegerValue(2),
129 MakeUintegerChecker<uint32_t>())
130 .AddAttribute(
131 "RetransmissionTimer",
132 "Retransmission time value, i.e. how long to wait for ACK before retransmission.",
133 TimeValue(Seconds(0.6)),
135 MakeTimeChecker())
136 .AddAttribute(
137 "WindowSize",
138 "Window size for ARQ, i.e. how many simultaneous packets are allowed in the air.",
139 UintegerValue(10),
141 MakeUintegerChecker<uint32_t>())
142 .AddAttribute("ArqHeaderSize",
143 "ARQ header size in Bytes.",
144 UintegerValue(1),
146 MakeUintegerChecker<uint32_t>())
147 .AddAttribute("RxWaitingTime",
148 "Time to wait for a packet at the reception (GW) before moving onwards "
149 "with the packet reception.",
150 TimeValue(Seconds(1.8)),
152 MakeTimeChecker());
153 return tid;
154}
155
156void
158{
159 NS_LOG_FUNCTION(this);
160 m_seqNo = 0;
161
162 // Clean-up the Tx'ed buffer
163 std::map<uint8_t, Ptr<SatArqBufferContext>>::iterator it = m_txedBuffer.begin();
164 while (it != m_txedBuffer.end())
165 {
166 it->second->DoDispose();
167 it->second = 0;
168 ++it;
169 }
170 m_txedBuffer.clear();
171
172 // Clean-up the reTx buffer
173 it = m_retxBuffer.begin();
174 while (it != m_retxBuffer.end())
175 {
176 it->second->DoDispose();
177 it->second = 0;
178 ++it;
179 }
180 m_retxBuffer.clear();
181
182 // Clean-up the reordering buffer
183 std::map<uint32_t, Ptr<SatArqBufferContext>>::iterator it2 = m_reorderingBuffer.begin();
184 while (it2 != m_reorderingBuffer.end())
185 {
186 it2->second->DoDispose();
187 it2->second = 0;
188 ++it2;
189 }
190 m_reorderingBuffer.clear();
191
193}
194
195Ptr<Packet>
197 uint32_t& bytesLeft,
198 uint32_t& nextMinTxO)
199{
200 NS_LOG_FUNCTION(this << bytes);
201 NS_LOG_INFO("TxOpportunity for UT: " << m_encapAddress << " flowId: " << (uint32_t)m_flowId
202 << " of " << bytes << " bytes");
203
204 // Payload adapted PDU = NULL
205 Ptr<Packet> packet;
206
212 if (!m_retxBuffer.empty())
213 {
214 // Oldest seqNo sent first
215 Ptr<SatArqBufferContext> context = m_retxBuffer.begin()->second;
216
217 // If the packet fits into the transmission opportunity
218 if (context->m_pdu->GetSize() <= bytes)
219 {
220 // Pop the front
221 m_retxBuffer.erase(m_retxBuffer.begin());
222
223 // Increase the retransmission counter
224 context->m_retransmissionCount = context->m_retransmissionCount + 1;
225
226 m_retxBufferSize -= context->m_pdu->GetSize();
227 m_txedBufferSize += context->m_pdu->GetSize();
228
229 // Store it back to the transmitted packet container.
230 m_txedBuffer.insert(std::make_pair(context->m_seqNo, context));
231
232 // Create the retransmission event and store it to the context. Event is cancelled if a
233 // ACK is received. However, if the event triggers, we shall send the packet again, if
234 // the packet still has retransmissions left.
235 EventId t = Simulator::Schedule(m_retransmissionTimer,
237 this,
238 context->m_seqNo);
239 context->m_waitingTimer = t;
240
241 NS_LOG_INFO("UT: << " << m_encapAddress << " sent a retransmission packet of size: "
242 << context->m_pdu->GetSize()
243 << " with seqNo: " << (uint32_t)(context->m_seqNo)
244 << " flowId: " << (uint32_t)(m_flowId));
245
246 Ptr<Packet> copy = context->m_pdu->Copy();
247 return copy;
248 }
249 else
250 {
251 NS_LOG_INFO("Retransmission PDU: " << context->m_pdu->GetUid()
252 << " size: " << context->m_pdu->GetSize()
253 << " does not fit into TxO: " << bytes);
254 }
255 }
256
257 // Check the transmission buffer. Sequence number needs to be
258 // available for any new transmissions.
259 else if (!m_txQueue->IsEmpty() && m_seqNo->SeqNoAvailable())
260 {
261 // Crate new RLE PDU
263
264 if (packet)
265 {
266 // Add MAC tag to identify the packet in lower layers
267 SatMacTag mTag;
268 if (!packet->PeekPacketTag(mTag))
269 {
272 packet->AddPacketTag(mTag);
273 }
274
275 // Add E2E address tag to identify the packet in lower layers
276 SatAddressE2ETag addressE2ETag;
277 if (!packet->PeekPacketTag(addressE2ETag))
278 {
279 addressE2ETag.SetE2EDestAddress(m_destE2EAddress);
281 packet->AddPacketTag(addressE2ETag);
282 }
283
284 // Add flow id tag
285 SatFlowIdTag flowIdTag;
286 flowIdTag.SetFlowId(m_flowId);
287 packet->AddPacketTag(flowIdTag);
288
289 // Get next available sequence number
290 uint8_t seqNo = m_seqNo->NextSequenceNumber();
291
292 // Add ARQ header
293 SatArqHeader arqHeader;
294 arqHeader.SetSeqNo(seqNo);
295 packet->AddHeader(arqHeader);
296
297 // Create ARQ context and store it to Tx'ed buffer
298 Ptr<SatArqBufferContext> arqContext = CreateObject<SatArqBufferContext>();
299 arqContext->m_retransmissionCount = 0;
300 Ptr<Packet> copy = packet->Copy();
301 arqContext->m_pdu = copy;
302 arqContext->m_seqNo = seqNo;
303
304 // Create the retransmission event and store it to the context. Event is cancelled if a
305 // ACK is received. However, if the event triggers, we shall send the packet again, if
306 // the packet still has retransmissions left.
307 arqContext->m_waitingTimer =
308 Simulator::Schedule(m_retransmissionTimer,
310 this,
311 seqNo);
312
313 // Update the buffer status
314 m_txedBufferSize += packet->GetSize();
315 m_txedBuffer.insert(std::make_pair(seqNo, arqContext));
316
317 if (packet->GetSize() > bytes)
318 {
319 NS_FATAL_ERROR("Created packet of size: " << packet->GetSize()
320 << " is larger than the tx opportunity: "
321 << bytes);
322 }
323
324 NS_LOG_INFO("UT: << " << m_encapAddress << " sent a packet of size: "
325 << packet->GetSize() << " with seqNo: " << (uint32_t)(seqNo)
326 << " flowId: " << (uint32_t)(m_flowId));
327 NS_LOG_INFO("Queue size after TxOpportunity: " << m_txQueue->GetNBytes());
328 }
329 }
330 else if (!m_seqNo->SeqNoAvailable())
331 {
332 bytesLeft = 0;
333 return packet;
334 }
335
336 // Update bytes lefts
337 bytesLeft = GetTxBufferSizeInBytes();
338
339 // Update min TxO
340 nextMinTxO = GetMinTxOpportunityInBytes();
341
342 return packet;
343}
344
345void
347{
348 NS_LOG_FUNCTION(this << (uint32_t)seqNo);
349
350 NS_LOG_INFO("At UT: " << m_encapAddress
351 << " ARQ retransmission timer expired for: " << (uint32_t)(seqNo));
352
353 std::map<uint8_t, Ptr<SatArqBufferContext>>::iterator it = m_txedBuffer.find(seqNo);
354
355 if (it != m_txedBuffer.end())
356 {
357 NS_ASSERT(seqNo == it->second->m_seqNo);
358 NS_ASSERT(it->second->m_pdu);
359
360 // Retransmission still possible
361 if (it->second->m_retransmissionCount < m_maxNoOfRetransmissions)
362 {
363 NS_LOG_INFO("Moving the ARQ context to retransmission buffer");
364
365 Ptr<SatArqBufferContext> context = it->second;
366
367 m_txedBuffer.erase(it);
368 m_retxBufferSize += context->m_pdu->GetSize();
369
370 // Push to the retransmission buffer
371 m_retxBuffer.insert(std::make_pair(seqNo, context));
372 }
373 // Maximum retransmissions reached
374 else
375 {
376 NS_LOG_INFO("For UT: " << m_encapAddress << " max retransmissions reached for "
377 << (uint32_t)(seqNo));
378
379 // Do clean-up
380 CleanUp(seqNo);
381 }
382 }
383 else
384 {
385 NS_LOG_INFO("Element not found anymore in the m_txedBuffer, thus ACK has been received "
386 "already earlier");
387 }
388}
389
390void
392{
393 NS_LOG_FUNCTION(this << (uint32_t)sequenceNumber);
394
395 // Release sequence number
396 m_seqNo->Release(sequenceNumber);
397
398 // Clean-up the Tx'ed buffer
399 std::map<uint8_t, Ptr<SatArqBufferContext>>::iterator it = m_txedBuffer.find(sequenceNumber);
400 if (it != m_txedBuffer.end())
401 {
402 NS_LOG_INFO("Sequence no: " << (uint32_t)sequenceNumber << " clean up from txedBuffer!");
403 m_txedBufferSize -= it->second->m_pdu->GetSize();
404 it->second->DoDispose();
405 it->second = 0;
406 m_txedBuffer.erase(it);
407 }
408
409 // Clean-up the reTx buffer
410 it = m_retxBuffer.find(sequenceNumber);
411 if (it != m_retxBuffer.end())
412 {
413 NS_LOG_INFO("Sequence no: " << (uint32_t)sequenceNumber << " clean up from retxBuffer!");
414 m_retxBufferSize -= it->second->m_pdu->GetSize();
415 it->second->DoDispose();
416 it->second = 0;
417 m_retxBuffer.erase(it);
418 }
419}
420
421void
423{
424 NS_LOG_FUNCTION(this);
425
430
431 NS_LOG_INFO("UT: " << m_encapAddress
432 << " received ACK with SN: " << (uint32_t)(ack->GetSequenceNumber()));
433
434 // Do clean-up
435 CleanUp(ack->GetSequenceNumber());
436}
437
438void
440{
441 NS_LOG_FUNCTION(this << p->GetSize());
442
443 // Remove encap PDU status tag
444 SatEncapPduStatusTag statusTag;
445 p->RemovePacketTag(statusTag);
446
447 // Remove flow id tag
448 SatFlowIdTag flowIdTag;
449 p->RemovePacketTag(flowIdTag);
450
451 // Sanity check
452 SatMacTag mTag;
453 bool mSuccess = p->RemovePacketTag(mTag);
454 if (!mSuccess)
455 {
456 NS_FATAL_ERROR("MAC tag not found in the packet!");
457 }
458 else if (mTag.GetDestAddress() != m_decapAddress)
459 {
460 NS_FATAL_ERROR("Packet was not intended for this receiver!");
461 }
462
463 SatArqHeader arqHeader;
464 p->RemoveHeader(arqHeader);
465 uint8_t seqNo = arqHeader.GetSeqNo();
466
467 NS_LOG_INFO("UT: " << m_encapAddress << " received a packet with SeqNo: " << (uint32_t)(seqNo));
468
469 // Send ACK for the received RLE packet.
470 SendAck(seqNo);
471
472 // Convert the 8-bit sequence number to continuous 32-bit sequence number
473 uint32_t sn = ConvertSeqNo(seqNo);
474
475 NS_LOG_INFO("8bit SN: " << (uint32_t)(seqNo) << " 32bit SN: " << sn);
476
477 // If the received SN is valid. If we receive a SN from the past
478 // nothing is needed to be done.
479 if (sn >= m_nextExpectedSeqNo)
480 {
481 std::map<uint32_t, Ptr<SatArqBufferContext>>::iterator it = m_reorderingBuffer.find(sn);
482
483 // If the context is not found, then we create a new one.
484 if (it == m_reorderingBuffer.end())
485 {
486 NS_LOG_INFO("UT: " << m_encapAddress
487 << " created a new ARQ buffer entry for SeqNo: " << sn);
488 Ptr<SatArqBufferContext> arqContext = CreateObject<SatArqBufferContext>();
489 arqContext->m_pdu = p;
490 arqContext->m_rxStatus = true;
491 arqContext->m_seqNo = sn;
492 arqContext->m_retransmissionCount = 0;
493 m_reorderingBuffer.insert(std::make_pair(sn, arqContext));
494 }
495 // If the context is found, update it.
496 else
497 {
498 NS_LOG_INFO("UT: " << m_encapAddress
499 << " reset an existing ARQ entry for SeqNo: " << sn);
500 it->second->m_waitingTimer.Cancel();
501 it->second->m_pdu = p;
502 it->second->m_rxStatus = true;
503 }
504
505 NS_LOG_INFO("Received a packet with SeqNo: " << sn
506 << ", expecting: " << m_nextExpectedSeqNo);
507
508 // If this is not the SN we expect
509 if (sn != m_nextExpectedSeqNo)
510 {
511 // Add context
512 for (uint32_t i = m_nextExpectedSeqNo; i < sn; ++i)
513 {
514 std::map<uint32_t, Ptr<SatArqBufferContext>>::iterator it2 =
515 m_reorderingBuffer.find(i);
516
517 NS_LOG_INFO("Finding context for " << i);
518
519 // If context not found
520 if (it2 == m_reorderingBuffer.end())
521 {
522 NS_LOG_INFO("Context NOT found for SeqNo: " << i);
523
524 Ptr<SatArqBufferContext> arqContext = CreateObject<SatArqBufferContext>();
525 arqContext->m_pdu = nullptr;
526 arqContext->m_rxStatus = false;
527 arqContext->m_seqNo = i;
528 arqContext->m_retransmissionCount = 0;
529 m_reorderingBuffer.insert(std::make_pair(i, arqContext));
530 EventId id =
531 Simulator::Schedule(m_rxWaitingTimer,
533 this,
534 i);
535 arqContext->m_waitingTimer = id;
536 }
537 }
538 }
539 // An expected sequence number received, reassemble and receive.
540 else
541 {
543 }
544 }
545 else
546 {
547 NS_LOG_INFO("UT: " << m_encapAddress << " received a packet with SeqNo: " << sn
548 << " which is already received!");
549 }
550}
551
552uint32_t
554{
555 NS_LOG_FUNCTION(this << (uint32_t)seqNo);
556
557 uint32_t globalSeqNo(0);
558
559 // Calculate the rounds and current seq no from m_nextExpectedSeqNo
560 uint32_t rounds = (m_nextExpectedSeqNo / std::numeric_limits<uint8_t>::max());
561 uint32_t rawSeqNo = m_nextExpectedSeqNo % std::numeric_limits<uint8_t>::max();
562
563 NS_LOG_INFO("Input: " << (uint32_t)(seqNo) << " rounds: " << rounds << " rawSeqNo: " << rawSeqNo
564 << " windowSize: " << m_arqWindowSize
565 << " next expected: " << m_nextExpectedSeqNo);
566
567 // Received sequence number is higher than the expected one.
568 if (seqNo >= rawSeqNo)
569 {
570 // If seqNo is from previous round
571 if ((seqNo - rawSeqNo) > 2 * m_arqWindowSize)
572 {
573 rounds--;
574 }
575 }
576 // seqNo < rawSeqNo
577 else
578 {
579 if ((rawSeqNo - seqNo) > 2 * m_arqWindowSize)
580 {
581 rounds++;
582 }
583 }
584
585 globalSeqNo = rounds * std::numeric_limits<uint8_t>::max() + seqNo;
586
587 return globalSeqNo;
588}
589
590void
592{
593 NS_LOG_FUNCTION(this);
594
595 // Start from the expected sequence number iterator
596 std::map<uint32_t, Ptr<SatArqBufferContext>>::iterator it = m_reorderingBuffer.begin();
597
598 NS_LOG_INFO("Process SeqNo: " << it->first << ", expected: " << m_nextExpectedSeqNo
599 << ", status: " << it->second->m_rxStatus);
600
605 while (it != m_reorderingBuffer.end() && it->first == m_nextExpectedSeqNo &&
606 it->second->m_rxStatus == true)
607 {
608 NS_LOG_INFO("Process SeqNo: " << it->first << ", expected: " << m_nextExpectedSeqNo
609 << ", status: " << it->second->m_rxStatus);
610
611 // If timer is running, cancel it.
612 if (it->second->m_waitingTimer.IsPending())
613 {
614 it->second->m_waitingTimer.Cancel();
615 }
616
617 // If PDU == NULL, it means that the RxWaitingTimer has expired
618 // without PDU being received
619 if (it->second->m_pdu)
620 {
621 // Process the PDU
622 ProcessPdu(it->second->m_pdu);
623 }
624
625 m_reorderingBuffer.erase(it);
626 it = m_reorderingBuffer.begin();
627
628 // Increase the seq no
630
631 NS_LOG_INFO("Increasing SeqNo to " << m_nextExpectedSeqNo);
632 }
633}
634
635void
637{
638 NS_LOG_FUNCTION(this << seqNo);
639
640 NS_LOG_INFO("For UT: " << m_encapAddress << " max waiting time reached for SeqNo: " << seqNo);
641 NS_LOG_INFO("Mark the PDU received and move forward!");
642
643 // Find waiting timer, erase it and mark the packet received.
644 std::map<uint32_t, Ptr<SatArqBufferContext>>::iterator it = m_reorderingBuffer.find(seqNo);
645 if (it != m_reorderingBuffer.end())
646 {
647 it->second->m_waitingTimer.Cancel();
648 it->second->m_rxStatus = true;
649 }
650 else
651 {
652 NS_FATAL_ERROR("Rx waiting timer is not running anymore even though it expired!");
653 }
654
656}
657
658uint32_t
660{
661 NS_LOG_FUNCTION(this);
662
663 return m_txQueue->GetNBytes() + m_retxBufferSize;
664}
665
666void
668{
669 NS_LOG_FUNCTION(this << (uint32_t)seqNo);
670
671 NS_LOG_INFO("GW: " << m_decapAddress << " send ACK to UT: " << m_encapAddress
672 << " with flowId: " << (uint32_t)(m_flowId)
673 << " with SN: " << (uint32_t)(seqNo));
674
681 if (!m_ctrlCallback.IsNull())
682 {
683 Ptr<SatArqAckMessage> ack = CreateObject<SatArqAckMessage>();
684 ack->SetSequenceNumber(seqNo);
685 ack->SetFlowId(m_flowId);
686
687 // Source address (UT) is used here, since the in RTN the GW is
688 // sending the ACK to the UT.
690 }
691 else
692 {
693 NS_FATAL_ERROR("Unable to send ACK, since the Ctrl callback is NULL!");
694 }
695}
696
697} // 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.
ARQ header implementation contains the sequence number related to the packet in question.
uint8_t GetSeqNo() const
Get sequence number.
void SetSeqNo(uint8_t seqNo)
Set sequence number.
Mac48Address m_encapAddress
Source and destination mac addresses.
Ptr< SatQueue > m_txQueue
Used queue in satellite encapsulator.
SendCtrlCallback m_ctrlCallback
Callback to send control messages.
SatEncapPduStatusTag is used temporarily to tag packets with the fragmentation status in the encapsul...
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.
SatArqSequenceNumber is handling the sequence numbers for the ARQ process.