tentative RLC AM NACK implementation https://groups.google.com/d/msg/ns-3-users/CEfmMX3IRBw/tX1X1yY_tgoJ
authorBrett
Fri, 11 Oct 2013 11:35:18 +0200
changeset 11296 942b41aa9151
parent 10394 6b889edbe9e5
child 11297 cc080dcdc11e
tentative RLC AM NACK implementation https://groups.google.com/d/msg/ns-3-users/CEfmMX3IRBw/tX1X1yY_tgoJ
src/lte/model/lte-rlc-am-header.cc
src/lte/model/lte-rlc-am-header.h
src/lte/model/lte-rlc-am.cc
--- a/src/lte/model/lte-rlc-am-header.cc	Thu Oct 10 14:39:23 2013 +0200
+++ b/src/lte/model/lte-rlc-am-header.cc	Fri Oct 11 11:35:18 2013 +0200
@@ -26,6 +26,7 @@
 
 namespace ns3 {
 
+
 NS_OBJECT_ENSURE_REGISTERED (LteRlcAmHeader);
 
 LteRlcAmHeader::LteRlcAmHeader ()
@@ -214,6 +215,38 @@
   m_ackSn = ackSn;
 }
 
+void
+LteRlcAmHeader::PushNack (int nack)
+{
+  m_my_nackSNs.push_back (nack);
+
+  if (m_my_nackSNs.size () % 2 == 0)
+    {
+      m_headerLength++;
+    }
+  else
+    {
+      m_headerLength+=2;
+    }
+}
+
+
+int
+LteRlcAmHeader::PopNack (void)
+{
+  if ( m_my_nackSNs.empty () )
+    {
+      return -1;
+    }
+
+  int nack = m_my_nackSNs.front ();
+  m_my_nackSNs.pop_front ();
+
+  return nack;
+}
+
+
+
 SequenceNumber10
 LteRlcAmHeader::GetAckSn (void) const
 {
@@ -242,6 +275,7 @@
 {
   std::list <uint8_t>::const_iterator it1 = m_extensionBits.begin ();
   std::list <uint16_t>::const_iterator it2 = m_lengthIndicators.begin ();
+  std::list <int>::const_iterator it3 = m_my_nackSNs.begin ();
 
   os << "Len=" << m_headerLength;
   os << " D/C=" << (uint16_t)m_dataControlBit;
@@ -280,7 +314,14 @@
   else // if ( m_dataControlBit == CONTROL_PDU )
     {
       os << " ACK_SN=" << m_ackSn;
-      os << " NACK_SN=" << m_nackSn;
+
+       while ( it3 != m_my_nackSNs.end () )
+        {
+          os << " NACK_SN=" << (int)(*it3);
+          it3++;
+        }
+
+ 
     }
 }
 
@@ -295,6 +336,7 @@
 
   std::list <uint8_t>::const_iterator it1 = m_extensionBits.begin ();
   std::list <uint16_t>::const_iterator it2 = m_lengthIndicators.begin ();
+  std::list <int>::const_iterator it3 = m_my_nackSNs.begin ();
 
   if ( m_dataControlBit == DATA_PDU )
     {
@@ -347,7 +389,76 @@
       i.WriteU8 ( ((CONTROL_PDU << 7) & 0x80) |
                   ((m_controlPduType << 4) & 0x70) |
                   ((m_ackSn.GetValue () >> 6) & 0x0F) );
-      i.WriteU8 ( ((m_ackSn.GetValue () << 2) & 0xFC) );
+//      i.WriteU8 ( ((m_ackSn.GetValue () << 2) & 0xFC) );
+
+      // Brett - Add code to serialize the NACKs
+      if ( it3 == m_my_nackSNs.end () ) 
+        {
+           // If there are no NACKs then this line adds the rest of the ACK
+           // along with 0x00, indicating an E1 value of 0 or no NACKs follow.
+           i.WriteU8 ( ((m_ackSn.GetValue () << 2) & 0xFC) );
+        }
+      else
+        {
+          int oddNack = *it3;
+          int evenNack = -1;
+          // Else write out a series of E1 = 1 and NACK values. Note since we
+          // are not supporting SO start/end the value of E2 will always be 0.
+
+
+          // First write out the ACK along with the very first NACK
+          // And the remaining NACK with 0x02 or 10 in binary to set
+          // E1 to 1, then Or in the first bit of the NACK
+          i.WriteU8 ( ((m_ackSn.GetValue () << 2) & 0xFC)
+            | (0x02)
+            | ((*it3 >> 9) & 0x01));
+
+          while ( it3 != m_my_nackSNs.end () )
+            {
+              // The variable oddNack has the current NACK value to write, also
+              // either the setup to enter this loop or the previous loop would
+              // have written the highest order bit to the previouse octet.
+              // Write the next set of bits (2 - 9) into the next octet
+              i.WriteU8( ((oddNack >> 1) & 0xFF) );
+
+              // Next check to see if there is going to be another NACK after
+              // this
+              it3++;
+              if ( it3 != m_my_nackSNs.end () )
+                {
+                  // Yes there will be another NACK after this, so E1 will be 1
+                  evenNack = *it3;
+                  i.WriteU8( ((oddNack << 7) & 0x80)
+                   | (0x40)  // E1 = 1 E2 = 0, more NACKs
+                   | ( (evenNack >> 5) & 0x1F) );
+
+                  // The final octet of this loop will have the rest of the
+                  // NACK and another E1, E2. Check to see if there will be
+                  // one more NACK after this.
+                  it3++;
+                  if ( it3 != m_my_nackSNs.end () )
+                    {
+                      // Yes there is at least one more NACK. Finish writing
+                      // this octet and the next iteration will do the rest.
+                      oddNack = *it3;
+                      i.WriteU8 ( ((evenNack << 3) & 0xF8)
+                        | (0x04)
+                        | ((oddNack >> 9) & 0x01));
+                    }
+                  else
+                    {
+                      // No, there are no more NACKs
+                      i.WriteU8 ( ((evenNack << 3) & 0xF8) );
+                    }
+                }
+              else
+                {
+                  // No, this is the last NACK so E1 will be 0
+                  i.WriteU8 ( ((oddNack << 7) & 0x80) );
+                }
+            }
+        }
+
     }
 }
 
@@ -431,7 +542,65 @@
       m_controlPduType = (byte_1 & 0x70) >> 4;
       m_ackSn = ((byte_1 & 0x0F) << 6 ) | ((byte_2 & 0xFC) >> 2);
 
-      m_headerLength++;
+      int moreNacks = (byte_2 & 0x02) >> 1;
+      // Get the first NACK outside the loop as it is not preceded by an E2
+      // field but all following NACKs will.
+      if ( moreNacks == 1 )
+        {
+          byte_3 = i.ReadU8 ();
+          byte_4 = i.ReadU8 ();
+          m_headerLength = 4;
+
+          m_my_nackSNs.push_back (
+            ((byte_2 & 0x01) << 9)
+            | (byte_3 << 1)
+            | ((byte_4 & 0x80) >> 7)
+          );
+
+         // Loop until all NACKs are found
+         moreNacks = ((byte_4 & 0x40) >> 6);
+         uint8_t byte = byte_4;
+         uint8_t nextByte;
+         uint8_t finalByte;
+         while (moreNacks == 1)
+           {
+             // Ignore E2, read next NACK
+             nextByte = i.ReadU8 ();
+             m_my_nackSNs.push_back (
+              ((byte & 0x1F) << 5)
+              | ((nextByte & 0xF8) >> 3)
+            );
+
+            // Check for another NACK, after this any following NACKs will
+            // be aligned properly for the next iteration of this loop.
+            moreNacks = (nextByte & 0x04) >> 2;
+            byte = nextByte;
+            if (moreNacks == 1)
+              {
+                nextByte = i.ReadU8 ();
+                finalByte = i.ReadU8 ();
+
+                 m_my_nackSNs.push_back (
+                   ((byte & 0x01) << 9)
+                   | (nextByte << 1)
+                   | ((finalByte & 0x80) >> 7)
+                 );
+
+                moreNacks = ((finalByte & 0x40) >> 6);
+                byte = finalByte;
+                m_headerLength+=3;
+              }
+            else
+              {
+                m_headerLength++;
+              }
+
+           }
+        }
+      else
+        {
+          m_headerLength++;
+        }
     }
 
   return GetSerializedSize ();
--- a/src/lte/model/lte-rlc-am-header.h	Thu Oct 10 14:39:23 2013 +0200
+++ b/src/lte/model/lte-rlc-am-header.h	Fri Oct 11 11:35:18 2013 +0200
@@ -136,6 +136,10 @@
   virtual void Serialize (Buffer::Iterator start) const;
   virtual uint32_t Deserialize (Buffer::Iterator start);
 
+  // Brett - Methods to handle NACKs
+  void PushNack (int nack);
+  int PopNack (void);
+
 private:
   uint16_t m_headerLength;
   uint8_t  m_dataControlBit;
@@ -158,6 +162,7 @@
   // Status PDU fields
   SequenceNumber10 m_ackSn;
   SequenceNumber10 m_nackSn;
+  std::list <int> m_my_nackSNs;
 
   std::list <uint8_t> m_extensionBits1; // Includes E1 after ACK_SN
   std::list <uint8_t> m_extensionBits2;
--- a/src/lte/model/lte-rlc-am.cc	Thu Oct 10 14:39:23 2013 +0200
+++ b/src/lte/model/lte-rlc-am.cc	Fri Oct 11 11:35:18 2013 +0200
@@ -25,6 +25,7 @@
 #include "ns3/lte-rlc-am.h"
 #include "ns3/lte-rlc-sdu-status-tag.h"
 #include "ns3/lte-rlc-tag.h"
+#include "ns3/random-variable.h"
 
 NS_LOG_COMPONENT_DEFINE ("LteRlcAm");
 
@@ -32,6 +33,12 @@
 
 NS_OBJECT_ENSURE_REGISTERED (LteRlcAm);
 
+// Brett
+// Used to keep track of when the RLC AM sliding window wraps back around. This
+// is required for knowning when a small ACK SN also ACKs a larger SN from the
+// before the window wrapped around.
+bool m_windowWrap = false;
+
 LteRlcAm::LteRlcAm ()
 {
   NS_LOG_FUNCTION (this);
@@ -192,9 +199,45 @@
       NS_LOG_LOGIC ("Sending STATUS PDU");
 
       Ptr<Packet> packet = Create<Packet> ();
+      NS_LOG_LOGIC ( "Brett -- About to make AM header for STATUS PDU" );
       LteRlcAmHeader rlcAmHeader;
       rlcAmHeader.SetControlPdu (LteRlcAmHeader::STATUS_PDU);
-      rlcAmHeader.SetAckSn (m_vrR);
+//      rlcAmHeader.SetAckSn (m_vrR); // Brett, need to change this
+      rlcAmHeader.SetAckSn (m_vrH); // Brett, is this right?
+
+      //=======================================================================
+      // Brett
+      // Check the reception buffer and find which Sequence Numbers are missing
+      // based on what is being ACKed. All SNs missing from the reception
+      // buffer that come before the SN number that is being ACKed are going to
+      // be NACKed packets.
+       
+      NS_LOG_LOGIC ("Brett - Receiver Side - Check for SNs to NACK");
+      NS_LOG_LOGIC ("Brett - Receiver Side - Check SNs from " << m_vrR.GetValue() << " to " << m_vrH.GetValue());
+      for ( int i = m_vrR.GetValue(); i < m_vrH.GetValue(); i++ ) {
+        // NS_LOG_LOGIC ("Brett - Receiver Side - Checking SN " << i );
+        // Need a different check but similar idea
+      /* struct PduBuffer
+        {
+          SequenceNumber10  m_seqNumber;
+          std::list < Ptr<Packet> >  m_byteSegments;
+
+          bool      m_pduComplete;
+          uint16_t  m_totalSize;
+          uint16_t  m_currSize;
+        };*/
+
+        int test =  m_rxonBuffer[ i ].m_pduComplete;
+        //NS_LOG_LOGIC("Brett - Is PDU complete: " <<  m_rxonBuffer[ i ].m_pduComplete);
+        if ( test == 0 ) {
+//          NS_LOG_LOGIC("Brett - NACK " << i );
+//          rlcAmHeader.EnqueueNAckSn( SequenceNumber10( i ) );
+          rlcAmHeader.PushNack( SequenceNumber10( i ).GetValue() );
+        }
+      }
+      //=======================================================================
+
+
 
       NS_LOG_LOGIC ("RLC header: " << rlcAmHeader);
       packet->AddHeader (rlcAmHeader);
@@ -219,8 +262,7 @@
 
       Ptr<Packet> packet = m_retxBuffer.at (m_vtA.GetValue ()).m_pdu->Copy ();
 
-      if (( packet->GetSize () <= bytes )
-          || m_txOpportunityForRetxAlwaysBigEnough)
+      if ( packet->GetSize () <= bytes )
         {
           LteRlcAmHeader rlcAmHeader;
           packet->PeekHeader (rlcAmHeader);
@@ -257,7 +299,7 @@
 
       NS_LOG_LOGIC ("Sending data from Transmission Buffer");
     }
-  else if ( m_txedBufferSize > 0 )
+ /* else if ( m_txedBufferSize > 0 )
     {
       NS_LOG_LOGIC ("Sending data from Transmitted Buffer");
 
@@ -267,9 +309,9 @@
       uint16_t vta = m_vtA.GetValue ();
       Ptr<Packet> packet = m_txedBuffer.at (vta)->Copy ();
 
-      if (( packet->GetSize () <= bytes )
-          || m_txOpportunityForRetxAlwaysBigEnough)
+      if ( packet->GetSize () <= bytes )
         {
+         // Brett - Move to retransmission buffer
           NS_LOG_INFO ("Move SN = " << vta << " to retxBuffer");
           m_retxBuffer.at (vta).m_pdu = m_txedBuffer.at (vta)->Copy ();
           m_retxBuffer.at (vta).m_retxCount = 1;
@@ -300,7 +342,7 @@
           return;
         }
     }
-  else
+*/  else
     {
       NS_LOG_LOGIC ("No data pending");
       return;
@@ -430,7 +472,7 @@
 
           // nextSegmentSize MUST be zero (only if segment is smaller or equal to 2047)
 
-          // (NO more segments) → exit
+          // (NO more segments) ? exit
           // break;
         }
       else if ( (nextSegmentSize - firstSegment->GetSize () <= 2) || (m_txonBuffer.size () == 0) )
@@ -461,7 +503,7 @@
 
           // nextSegmentSize <= 2 (only if txBuffer is not empty)
 
-          // (NO more segments) → exit
+          // (NO more segments) ? exit
           // break;
         }
       else // (firstSegment->GetSize () < m_nextSegmentSize) && (m_txBuffer.size () > 0)
@@ -624,6 +666,7 @@
   NS_LOG_FUNCTION (this);
 }
 
+
 void
 LteRlcAm::DoReceivePdu (Ptr<Packet> p)
 {
@@ -973,73 +1016,130 @@
       NS_LOG_INFO ("VT(A)     = " << m_vtA);
       NS_LOG_INFO ("VT(S)     = " << m_vtS);
 
-      m_vtA.SetModulusBase (m_vtA);
-      m_vtS.SetModulusBase (m_vtA);
-      ackSn.SetModulusBase (m_vtA);
-      while (m_vtA < ackSn && m_vtA < m_vtS)
+
+
+      // Check for the first NACK
+      uint16_t nackSN = rlcAmHeader.PopNack ();
+      // Flag to indicate if any NACKs exist in the header. This is used to
+      // determine when VT(A) should stop incrementing as it is the lower
+      // bound of the transmission window and should equal the highest ACKed
+      // SN in sequence (no NACKs previous).
+      bool foundNack = false;
+      // Used to iterate over the transmission window to apply the ACKs and
+      // NACKs from the control PDU.
+      uint16_t loopCount = m_vtA.GetValue ();
+
+      // Brett - Check to see if the transmission window needs to wrap around.
+      // This window needs to wrap if the current VT(A) (last ACKed PDU) plus
+      // the window size is larger than 1023 and the SN just received is for
+      // a PDU that somwhere in the range of 0 to the top of the window. If
+      // this is the case then set the window wrap flag.
+      if ((m_vtA.GetValue() + m_windowSize > 1023) 
+          && 0 <= ackSn.GetValue() && ackSn.GetValue() < m_vtA.GetValue() + m_windowSize - 1023)
         {
+          m_windowWrap = true;
+        } 
+
+      // Brett - There is a problem with the transmitting window wrapping back
+      // to the beginning. An ACK is for the next sequence number expected, but
+      // the largest sequence number that can be sent is 1023. We cannot send
+      // 1024 or anything higher than this to ACK an SN of 1023. To resolve I
+      // am adding the OR condition to this while loop. In the situation that
+      // the check above finds that it is time for the window to wrap then the
+      // window wrap flag allows this loop to execute. The loop will ACK all
+      // SNs from VT(A) to SN 1023 before resetting the window wrap flag to
+      // false and resetting the last ACKed SN to 0.
+      NS_LOG_INFO("Brett - Check - Look at transmit window from " << loopCount << " to " << m_vtS.GetValue ());
+      while (( loopCount < ackSn.GetValue() && loopCount < m_vtS.GetValue ())
+              || m_windowWrap)
+       {
+           NS_LOG_INFO("Brett - Current NACK is " << nackSN);
 //           NS_LOG_INFO ("seqNumber = " << seqNumber);
 //           NS_LOG_INFO ("m_txedBuffer( VT(A) ).size = " << m_txedBuffer.size ());
 
-          uint16_t seqNumberValue = m_vtA.GetValue ();
-          if (m_pollRetransmitTimer.IsRunning () 
-              && (seqNumberValue == m_pollSn.GetValue ()))
-            {
-              m_pollRetransmitTimer.Cancel ();
-            }
+          //uint16_t seqNumberValue = m_vtA.GetValue ();
+          uint16_t seqNumberValue = loopCount;
+          if ( nackSN != seqNumberValue )
+          {
 
-          if (m_txedBuffer.at (seqNumberValue))
-            {
-              NS_LOG_INFO ("ACKed SN = " << seqNumberValue << " from txedBuffer");
-//               NS_LOG_INFO ("m_txedBuffer( " << m_vtA << " )->GetSize = " << m_txedBuffer.at (m_vtA.GetValue ())->GetSize ());
-              m_txedBufferSize -= m_txedBuffer.at (seqNumberValue)->GetSize ();
-              m_txedBuffer.at (seqNumberValue) = 0;
-            }
+            if (m_txedBuffer.at (seqNumberValue))
+              {
+                NS_LOG_INFO ("ACKed SN = " << seqNumberValue << " from txedBuffer");
+//                 NS_LOG_INFO ("m_txedBuffer( " << m_vtA << " )->GetSize = " << m_txedBuffer.at (m_vtA.GetValue ())->GetSize ());
+                m_txedBufferSize -= m_txedBuffer.at (seqNumberValue)->GetSize ();
+                m_txedBuffer.at (seqNumberValue) = 0;
+              }
 
-          if (m_retxBuffer.at (seqNumberValue).m_pdu)
-            {
-              NS_LOG_INFO ("ACKed SN = " << seqNumberValue << " from retxBuffer");
-              m_retxBufferSize -= m_retxBuffer.at (seqNumberValue).m_pdu->GetSize ();
-              m_retxBuffer.at (seqNumberValue).m_pdu = 0;
-              m_retxBuffer.at (seqNumberValue).m_retxCount = 0;
-            }
+            if (m_retxBuffer.at (seqNumberValue).m_pdu)
+              {
+                NS_LOG_INFO ("ACKed SN = " << seqNumberValue << " from retxBuffer");
+                m_retxBufferSize -= m_retxBuffer.at (seqNumberValue).m_pdu->GetSize ();
+                m_retxBuffer.at (seqNumberValue).m_pdu = 0;
+                m_retxBuffer.at (seqNumberValue).m_retxCount = 0;
+              }
 
           m_vtA++;
           m_vtA.SetModulusBase (m_vtA);
           m_vtS.SetModulusBase (m_vtA);
           ackSn.SetModulusBase (m_vtA);
+            }
+          else
+            {
+              foundNack = true;
+              if (m_txedBuffer.at (nackSN))
+               {
+                 NS_LOG_INFO ("NACKed SN = " << seqNumberValue << " from txedBuffer");
+                 // Brett - Move to Retransmission Buffer
+                  NS_LOG_INFO ("Move SN = " << nackSN << " to retxBuffer");
+                  m_retxBuffer.at (nackSN).m_pdu = m_txedBuffer.at (nackSN)->Copy ();
+                  m_retxBuffer.at (nackSN).m_retxCount = 0;
+                  m_retxBufferSize += m_retxBuffer.at (nackSN).m_pdu->GetSize ();
+
+                  m_txedBufferSize -= m_txedBuffer.at (nackSN)->GetSize ();
+                  m_txedBuffer.at (nackSN) = 0;
+               }
+              else if (m_retxBuffer.at (nackSN).m_pdu)
+               {
+                 NS_LOG_INFO ("NACKed SN = " << seqNumberValue << " from retxBuffer");
+                 m_retxBuffer.at (nackSN).m_retxCount++;
+                 NS_LOG_INFO ("Incr RETX_COUNT for SN = " << nackSN);
+                 if (m_retxBuffer.at (nackSN).m_retxCount >= m_maxRetxThreshold)
+                   {
+                     NS_LOG_INFO ("Max RETX_COUNT for SN = " << nackSN);
+                   }
+               }
+
+            }
+            // Check to see if it is time to find the next NACK
+            if ( seqNumberValue == nackSN )
+              {
+                nackSN = rlcAmHeader.PopNack ();
+              }
+
+
+            // If m_vtA has an SN of 1023 and the window wrap flag is true then
+            // it is time to reset m_vtA to 0 an reset the window wrap flag.
+            if ( m_vtA.GetValue() == 1023 && m_windowWrap )
+              {
+                loopCount = 0;
+                m_vtA = 0;
+                m_windowWrap = false;
+             
+                // Wrap around with the transmission window.
+                //nackSN = rlcAmHeader.PopNack ();
+                //NS_LOG_INFO( "Brett - Tx window wrap, new NACK is " << nackSN );
+              }
+            else
+              {
+                loopCount++;
+                if (!foundNack)
+                  {
+                    m_vtA++;
+                  }
+              }
         }
 
       NS_LOG_INFO ("New VT(A) = " << m_vtA);
-
-      SequenceNumber10 seqNumber = m_vtA;
-      uint16_t seqNumberValue;
-      while (seqNumber < m_vtS)
-        {
-          seqNumberValue = seqNumber.GetValue ();
-          if (m_txedBuffer.at (seqNumberValue))
-            {
-              NS_LOG_INFO ("Move SN = " << seqNumberValue << " to retxBuffer");
-              m_retxBuffer.at (seqNumberValue).m_pdu = m_txedBuffer.at (seqNumberValue)->Copy ();
-              m_retxBuffer.at (seqNumberValue).m_retxCount = 0;
-              m_retxBufferSize += m_retxBuffer.at (seqNumberValue).m_pdu->GetSize ();
-
-              m_txedBufferSize -= m_txedBuffer.at (seqNumberValue)->GetSize ();
-              m_txedBuffer.at (seqNumberValue) = 0;
-            }
-          else if (m_retxBuffer.at (seqNumberValue).m_pdu)
-            {
-              m_retxBuffer.at (seqNumberValue).m_retxCount++;
-              NS_LOG_INFO ("Incr RETX_COUNT for SN = " << seqNumberValue);
-              if (m_retxBuffer.at (seqNumberValue).m_retxCount >= m_maxRetxThreshold)
-                {
-                  NS_LOG_INFO ("Max RETX_COUNT for SN = " << seqNumberValue);
-                }
-            }
-
-          seqNumber++;
-        }
-
       return;
     }
   else