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