--- 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);