decouple TcpTxBuffer::HeadSequence from TcpSocketBase SND.UNA draft
authorMatt <mattator@gmail.com>
Fri, 01 May 2015 07:21:48 -0700
changeset 11345 003802413c8e
parent 11344 4f866f756e68
child 11346 783869cd9dff
decouple TcpTxBuffer::HeadSequence from TcpSocketBase SND.UNA
src/internet/model/tcp-newreno.cc
src/internet/model/tcp-socket-base.cc
src/internet/model/tcp-socket-base.h
src/internet/model/tcp-socket.h
--- a/src/internet/model/tcp-newreno.cc	Fri May 01 07:20:50 2015 -0700
+++ b/src/internet/model/tcp-newreno.cc	Fri May 01 07:21:48 2015 -0700
@@ -130,16 +130,16 @@
 
   // Check for exit condition of fast recovery
   if (m_inFastRec && seq < m_recover)
-    { // Partial ACK, partial window deflation (RFC2582 sec.3 bullet #5 paragraph 3)
-      m_cWnd += m_segmentSize - (seq - m_txBuffer->HeadSequence ());
+    { // Partial ACK, partial window deflation (RFC6582 sec.3.2 bullet #4)
+      m_cWnd += m_segmentSize - (seq - FirstUnackedSeq());
       NS_LOG_INFO ("Partial ACK for seq " << seq << " in fast recovery: cwnd set to " << m_cWnd);
-      m_txBuffer->DiscardUpTo(seq);  //Bug 1850:  retransmit before newack
+      m_firstTxUnack = seq; //Bug 1850:  retransmit before newack
       DoRetransmit (); // Assume the next seq is lost. Retransmit lost packet
       TcpSocketBase::NewAck (seq); // update m_nextTxSequence and send new data if allowed by window
       return;
     }
   else if (m_inFastRec && seq >= m_recover)
-    { // Full ACK (RFC2582 sec.3 bullet #5 paragraph 2, option 1)
+    { // Full ACK (RFC6582 sec.3.2 bullet #4)
       m_cWnd = std::min (m_ssThresh.Get (), BytesInFlight () + m_segmentSize);
       m_inFastRec = false;
       NS_LOG_INFO ("Received full ACK for seq " << seq <<". Leaving fast recovery with cwnd set to " << m_cWnd);
@@ -250,7 +250,7 @@
   return m_initialCWnd;
 }
 
-void 
+void
 TcpNewReno::InitializeCwnd (void)
 {
   /*
--- a/src/internet/model/tcp-socket-base.cc	Fri May 01 07:20:50 2015 -0700
+++ b/src/internet/model/tcp-socket-base.cc	Fri May 01 07:21:48 2015 -0700
@@ -126,6 +126,10 @@
                      "Last RTT sample",
                      MakeTraceSourceAccessor (&TcpSocketBase::m_lastRtt),
                      "ns3::Time::TracedValueCallback")
+    .AddTraceSource("UnackSequence",
+                    "First unacknowledged sequence number (SND.UNA)",
+                    MakeTraceSourceAccessor(&TcpSocketBase::m_firstTxUnack),
+                    "ns3::SequenceNumber32TracedValueCallback")
     .AddTraceSource ("NextTxSequence",
                      "Next sequence number to send (SND.NXT)",
                      MakeTraceSourceAccessor (&TcpSocketBase::m_nextTxSequence),
@@ -154,6 +158,7 @@
     m_node (0),
     m_tcp (0),
     m_rtt (0),
+    m_firstTxUnack(0),
     m_nextTxSequence (0),
     // Change this for non-zero initial sequence number
     m_highTxMark (0),
@@ -196,6 +201,7 @@
     m_node (sock.m_node),
     m_tcp (sock.m_tcp),
     m_rtt (0),
+    m_firstTxUnack(sock.m_firstTxUnack),
     m_nextTxSequence (sock.m_nextTxSequence),
     m_highTxMark (sock.m_highTxMark),
     m_state (sock.m_state),
@@ -521,7 +527,7 @@
       SendRST ();
       return 0;
     }
- 
+
   if (m_txBuffer->SizeFromSequence (m_nextTxSequence) > 0)
     { // App close with pending data must wait until all data transmitted
       if (m_closeOnEmpty == false)
@@ -539,7 +545,7 @@
 TcpSocketBase::ShutdownSend (void)
 {
   NS_LOG_FUNCTION (this);
-  
+
   //this prevents data from being added to the buffer
   m_shutdownSend = true;
   m_closeOnEmpty = true;
@@ -550,7 +556,7 @@
       if (m_state == ESTABLISHED || m_state == CLOSE_WAIT)
         {
           NS_LOG_INFO("Emtpy tx buffer, send fin");
-          SendEmptyPacket (TcpHeader::FIN);  
+          SendEmptyPacket (TcpHeader::FIN);
 
           if (m_state == ESTABLISHED)
             { // On active close: I am the first one to send FIN
@@ -561,10 +567,10 @@
             { // On passive close: Peer sent me FIN already
               NS_LOG_INFO ("CLOSE_WAIT -> LAST_ACK");
               m_state = LAST_ACK;
-            }  
+            }
         }
     }
- 
+
   return 0;
 }
 
@@ -846,7 +852,7 @@
 
   NS_LOG_INFO (TcpStateName[m_state] << " -> CLOSED");
   m_state = CLOSED;
-  DeallocateEndPoint ();  
+  DeallocateEndPoint ();
 }
 
 
@@ -869,6 +875,23 @@
   return (tail < m_rxBuffer->NextRxSequence () || m_rxBuffer->MaxRxSequence () <= head);
 }
 
+
+/* Set sequence number of the first packet to send */
+void
+TcpSocketBase::SetTxHead(const SequenceNumber32& seq)
+{
+  NS_LOG_LOGIC("Setting Tx Head to " << seq);
+  m_txBuffer->SetHeadSequence(seq);
+  m_firstTxUnack = seq;
+  m_highTxMark = seq;
+}
+
+SequenceNumber32
+TcpSocketBase::FirstUnackedSeq() const
+{
+  return m_firstTxUnack.Get();
+}
+
 /* Function called by the L3 protocol when it received a packet to pass on to
     the TCP. This function is registered as the "RxCallback" function in
     SetupCallback(), which invoked by Bind(), and CompleteFork() */
@@ -1178,11 +1201,11 @@
   if (0 == (tcpHeader.GetFlags () & TcpHeader::ACK))
     { // Ignore if no ACK flag
     }
-  else if (tcpHeader.GetAckNumber () < m_txBuffer->HeadSequence ())
+  else if (tcpHeader.GetAckNumber () < FirstUnackedSeq())
     { // Case 1: Old ACK, ignored.
       NS_LOG_LOGIC ("Ignored ack of " << tcpHeader.GetAckNumber ());
     }
-  else if (tcpHeader.GetAckNumber () == m_txBuffer->HeadSequence ())
+  else if (tcpHeader.GetAckNumber () == FirstUnackedSeq())
     { // Case 2: Potentially a duplicated ACK
       if (tcpHeader.GetAckNumber () < m_nextTxSequence && packet->GetSize() == 0)
         {
@@ -1192,7 +1215,7 @@
       // otherwise, the ACK is precisely equal to the nextTxSequence
       NS_ASSERT (tcpHeader.GetAckNumber () <= m_nextTxSequence);
     }
-  else if (tcpHeader.GetAckNumber () > m_txBuffer->HeadSequence ())
+  else if (tcpHeader.GetAckNumber () > FirstUnackedSeq())
     { // Case 3: New ACK, reset m_dupAckCount and update m_txBuffer
       NS_LOG_LOGIC ("New ack of " << tcpHeader.GetAckNumber ());
       NewAck (tcpHeader.GetAckNumber ());
@@ -1273,8 +1296,7 @@
       m_connected = true;
       m_retxEvent.Cancel ();
       m_rxBuffer->SetNextRxSequence (tcpHeader.GetSequenceNumber () + SequenceNumber32 (1));
-      m_highTxMark = ++m_nextTxSequence;
-      m_txBuffer->SetHeadSequence (m_nextTxSequence);
+      SetTxHead(++m_nextTxSequence);
       SendEmptyPacket (TcpHeader::ACK);
       SendPendingData (m_connected);
       Simulator::ScheduleNow (&TcpSocketBase::ConnectionSucceeded, this);
@@ -1313,8 +1335,7 @@
       m_state = ESTABLISHED;
       m_connected = true;
       m_retxEvent.Cancel ();
-      m_highTxMark = ++m_nextTxSequence;
-      m_txBuffer->SetHeadSequence (m_nextTxSequence);
+      SetTxHead(++m_nextTxSequence);
       if (m_endPoint)
         {
           m_endPoint->SetPeer (InetSocketAddress::ConvertFrom (fromAddress).GetIpv4 (),
@@ -1347,8 +1368,8 @@
         { // In-sequence FIN before connection complete. Set up connection and close.
           m_connected = true;
           m_retxEvent.Cancel ();
-          m_highTxMark = ++m_nextTxSequence;
-          m_txBuffer->SetHeadSequence (m_nextTxSequence);
+
+          SetTxHead(++m_nextTxSequence);
           if (m_endPoint)
             {
               m_endPoint->SetPeer (InetSocketAddress::ConvertFrom (fromAddress).GetIpv4 (),
@@ -1920,7 +1941,7 @@
   NS_LOG_FUNCTION (this << seq << maxSize << withAck);
 
   bool isRetransmission = false;
-  if ( seq == m_txBuffer->HeadSequence () )
+  if ( seq == FirstUnackedSeq() )
     {
       isRetransmission = true;
     }
@@ -2080,7 +2101,7 @@
                     " rxwin " << m_rWnd <<
                     " segsize " << m_segmentSize <<
                     " nextTxSeq " << m_nextTxSequence <<
-                    " highestRxAck " << m_txBuffer->HeadSequence () <<
+                    " highestRxAck " << FirstUnackedSeq() <<
                     " pd->Size " << m_txBuffer->Size () <<
                     " pd->SFS " << m_txBuffer->SizeFromSequence (m_nextTxSequence));
       // Stop sending if we need to wait for a larger Tx window (prevent silly window syndrome)
@@ -2109,14 +2130,14 @@
 TcpSocketBase::UnAckDataCount ()
 {
   NS_LOG_FUNCTION (this);
-  return m_nextTxSequence.Get () - m_txBuffer->HeadSequence ();
+  return m_nextTxSequence.Get () - FirstUnackedSeq();
 }
 
 uint32_t
 TcpSocketBase::BytesInFlight ()
 {
   NS_LOG_FUNCTION (this);
-  return m_highTxMark.Get () - m_txBuffer->HeadSequence ();
+  return m_highTxMark.Get () - FirstUnackedSeq();
 }
 
 uint32_t
@@ -2297,8 +2318,11 @@
     }
   // Note the highest ACK and tell app to send more
   NS_LOG_LOGIC ("TCP " << this << " NewAck " << ack <<
-                " numberAck " << (ack - m_txBuffer->HeadSequence ())); // Number bytes ack'ed
+                " numberAck " << (ack - FirstUnackedSeq())); // Number bytes ack'ed
+
+  m_firstTxUnack = ack;
   m_txBuffer->DiscardUpTo (ack);
+
   if (GetTxAvailable () > 0)
     {
       NotifySend (GetTxAvailable ());
@@ -2329,7 +2353,7 @@
       return;
     }
   // If all data are received (non-closing socket and nothing to send), just return
-  if (m_state <= ESTABLISHED && m_txBuffer->HeadSequence () >= m_highTxMark)
+  if (m_state <= ESTABLISHED && FirstUnackedSeq() >= m_highTxMark)
     {
       return;
     }
@@ -2404,7 +2428,7 @@
 void
 TcpSocketBase::Retransmit ()
 {
-  m_nextTxSequence = m_txBuffer->HeadSequence (); // Start from highest Ack
+  m_nextTxSequence = FirstUnackedSeq(); // Start from highest Ack
   m_dupAckCount = 0;
   DoRetransmit (); // Retransmit the packet
 }
@@ -2436,10 +2460,10 @@
       return;
     }
   // Retransmit a data packet: Call SendDataPacket
-  NS_LOG_LOGIC ("TcpSocketBase " << this << " retxing seq " << m_txBuffer->HeadSequence ());
-  uint32_t sz = SendDataPacket (m_txBuffer->HeadSequence (), m_segmentSize, true);
+  NS_LOG_LOGIC ("TcpSocketBase " << this << " retxing seq " << FirstUnackedSeq());
+  uint32_t sz = SendDataPacket (FirstUnackedSeq(), m_segmentSize, true);
   // In case of RTO, advance m_nextTxSequence
-  m_nextTxSequence = std::max (m_nextTxSequence.Get (), m_txBuffer->HeadSequence () + sz);
+  m_nextTxSequence = std::max (m_nextTxSequence.Get (), FirstUnackedSeq() + sz);
 
 }
 
--- a/src/internet/model/tcp-socket-base.h	Fri May 01 07:20:50 2015 -0700
+++ b/src/internet/model/tcp-socket-base.h	Fri May 01 07:21:48 2015 -0700
@@ -217,8 +217,6 @@
   virtual bool     SetAllowBroadcast (bool allowBroadcast);
   virtual bool     GetAllowBroadcast (void) const;
 
-
-
   // Helper functions: Connection set up
 
   /**
@@ -376,6 +374,17 @@
   bool OutOfRange (SequenceNumber32 head, SequenceNumber32 tail) const;
 
 
+  /**
+   *Should be called only to set the very first byte Tx seq
+   */
+  virtual void SetTxHead(const SequenceNumber32& seq);
+
+  /**
+   * \return First unacknowledged sequence number
+   */
+  virtual SequenceNumber32 FirstUnackedSeq() const;
+
+
   // Helper functions: Connection close
 
   /**
@@ -606,7 +615,7 @@
 
   /**
    * \brief Read TCP options from incoming packets
-   *  
+   *
    * This method sequentially checks each kind of option, and if it
    * is present in the header, starts its processing.
    *
@@ -709,6 +718,7 @@
   Ptr<RttEstimator> m_rtt; //!< Round trip time estimator
 
   // Rx and Tx buffer management
+  TracedValue<SequenceNumber32> m_firstTxUnack;   //!< First unacknowledged seq nb  (SND.UNA)
   TracedValue<SequenceNumber32> m_nextTxSequence; //!< Next seqnum to be sent (SND.NXT), ReTx pushes it back
   TracedValue<SequenceNumber32> m_highTxMark;     //!< Highest seqno ever sent, regardless of ReTx
   Ptr<TcpRxBuffer>              m_rxBuffer;       //!< Rx buffer (reordering buffer)
--- a/src/internet/model/tcp-socket.h	Fri May 01 07:20:50 2015 -0700
+++ b/src/internet/model/tcp-socket.h	Fri May 01 07:21:48 2015 -0700
@@ -83,7 +83,7 @@
    * \return the object TypeId
    */
   static TypeId GetTypeId (void);
- 
+
   TcpSocket (void);
   virtual ~TcpSocket (void);