bug 2058: TCP window update can shrink the Left Edge of the window which is a bug (patch based on earlier contribution from Evgeny Evstropov)

This commit is contained in:
Tom Henderson
2015-05-04 22:39:00 -07:00
parent db17672017
commit 2e4b36c82e
2 changed files with 96 additions and 17 deletions

View File

@@ -142,6 +142,14 @@ TcpSocketBase::GetTypeId (void)
"Remote side's flow control window",
MakeTraceSourceAccessor (&TcpSocketBase::m_rWnd),
"ns3::TracedValue::Uint32Callback")
.AddTraceSource ("HighestRxSequence",
"Highest sequence number received from peer",
MakeTraceSourceAccessor (&TcpSocketBase::m_highRxMark),
"ns3::SequenceNumber32TracedValueCallback")
.AddTraceSource ("HighestRxAck",
"Highest ack received from peer",
MakeTraceSourceAccessor (&TcpSocketBase::m_highRxAckMark),
"ns3::SequenceNumber32TracedValueCallback")
;
return tid;
}
@@ -169,6 +177,8 @@ TcpSocketBase::TcpSocketBase (void)
m_segmentSize (0),
// For attribute initialization consistency (quiet valgrind)
m_rWnd (0),
m_highRxMark (0),
m_highRxAckMark (0),
m_sndScaleFactor (0),
m_rcvScaleFactor (0),
m_timestampEnabled (true),
@@ -209,6 +219,8 @@ TcpSocketBase::TcpSocketBase (const TcpSocketBase& sock)
m_segmentSize (sock.m_segmentSize),
m_maxWinSize (sock.m_maxWinSize),
m_rWnd (sock.m_rWnd),
m_highRxMark (sock.m_highRxMark),
m_highRxAckMark (sock.m_highRxAckMark),
m_winScalingEnabled (sock.m_winScalingEnabled),
m_sndScaleFactor (sock.m_sndScaleFactor),
m_rcvScaleFactor (sock.m_rcvScaleFactor),
@@ -945,14 +957,6 @@ TcpSocketBase::DoForwardUp (Ptr<Packet> packet, Ipv4Header header, uint16_t port
EstimateRtt (tcpHeader);
}
// Update Rx window size, i.e. the flow control window
if (m_rWnd.Get () == 0 && tcpHeader.GetWindowSize () != 0)
{ // persist probes end
NS_LOG_LOGIC (this << " Leaving zerowindow persist state");
m_persistEvent.Cancel ();
}
m_rWnd = (uint32_t(tcpHeader.GetWindowSize ()) << m_rcvScaleFactor);
// Discard fully out of range data packets
if (packet->GetSize ()
&& OutOfRange (tcpHeader.GetSequenceNumber (), tcpHeader.GetSequenceNumber () + packet->GetSize ()))
@@ -970,6 +974,17 @@ TcpSocketBase::DoForwardUp (Ptr<Packet> packet, Ipv4Header header, uint16_t port
return;
}
// Update Rx window size, i.e. the flow control window
if (m_rWnd.Get () == 0 && tcpHeader.GetWindowSize () != 0 && m_persistEvent.IsRunning ())
{ // persist probes end
NS_LOG_LOGIC (this << " Leaving zerowindow persist state");
m_persistEvent.Cancel ();
}
if (tcpHeader.GetFlags () & TcpHeader::ACK)
{
UpdateWindowSize (tcpHeader);
}
// TCP state machine code in different process functions
// C.f.: tcp_rcv_state_process() in tcp_input.c in Linux kernel
switch (m_state)
@@ -1048,14 +1063,6 @@ TcpSocketBase::DoForwardUp (Ptr<Packet> packet, Ipv6Header header, uint16_t port
EstimateRtt (tcpHeader);
}
// Update Rx window size, i.e. the flow control window
if (m_rWnd.Get () == 0 && tcpHeader.GetWindowSize () != 0)
{ // persist probes end
NS_LOG_LOGIC (this << " Leaving zerowindow persist state");
m_persistEvent.Cancel ();
}
m_rWnd = (uint32_t(tcpHeader.GetWindowSize ()) << m_rcvScaleFactor);
// Discard fully out of range packets
if (packet->GetSize ()
&& OutOfRange (tcpHeader.GetSequenceNumber (), tcpHeader.GetSequenceNumber () + packet->GetSize ()))
@@ -1073,6 +1080,18 @@ TcpSocketBase::DoForwardUp (Ptr<Packet> packet, Ipv6Header header, uint16_t port
return;
}
// Update Rx window size, i.e. the flow control window
if (m_rWnd.Get () == 0 && tcpHeader.GetWindowSize () != 0 && m_persistEvent.IsRunning ())
{ // persist probes end
NS_LOG_LOGIC (this << " Leaving zerowindow persist state");
m_persistEvent.Cancel ();
}
if (tcpHeader.GetFlags () & TcpHeader::ACK)
{
UpdateWindowSize (tcpHeader);
}
// TCP state machine code in different process functions
// C.f.: tcp_rcv_state_process() in tcp_input.c in Linux kernel
switch (m_state)
@@ -2726,6 +2745,50 @@ TcpSocketBase::AddOptionTimestamp (TcpHeader& header)
option->GetTimestamp () << " echo=" << m_timestampToEcho);
}
void TcpSocketBase::UpdateWindowSize (const TcpHeader &header)
{
NS_LOG_FUNCTION (this << header);
// If the connection is not established, the window size is always
// updated
uint32_t receivedWindow = header.GetWindowSize ();
receivedWindow <<= m_rcvScaleFactor;
NS_LOG_DEBUG ("Received (scaled) window is " << receivedWindow << " bytes");
if (m_state < ESTABLISHED)
{
m_rWnd = receivedWindow;
NS_LOG_DEBUG ("State less than ESTABLISHED; updating rWnd to " << m_rWnd);
return;
}
// Test for conditions that allow updating of the window
// 1) segment contains new data (advancing the right edge of the receive
// buffer),
// 2) segment does not contain new data but the segment acks new data
// (highest sequence number acked advances), or
// 3) the advertised window is larger than the current send window
bool update = false;
if (header.GetAckNumber () == m_highRxAckMark && receivedWindow > m_rWnd)
{
// right edge of the send window is increased (window update)
update = true;
}
if (header.GetAckNumber () > m_highRxAckMark)
{
m_highRxAckMark = header.GetAckNumber ();
update = true;
}
if (header.GetSequenceNumber () > m_highRxMark)
{
m_highRxMark = header.GetSequenceNumber ();
update = true;
}
if (update == true)
{
m_rWnd = receivedWindow;
NS_LOG_DEBUG ("updating rWnd to " << m_rWnd);
}
}
void
TcpSocketBase::SetMinRto (Time minRto)
{

View File

@@ -532,6 +532,20 @@ protected:
*/
virtual uint16_t AdvertisedWindowSize (void);
/**
* \brief Update the receiver window (RWND) based on the value of the
* window field in the header.
*
* This method suppresses updates unless one of the following three
* conditions holds: 1) segment contains new data (advancing the right
* edge of the receive buffer), 2) segment does not contain new data
* but the segment acks new data (highest sequence number acked advances),
* or 3) the advertised window is larger than the current send window
*
* \param header TcpHeader from which to extract the new window value
*/
void UpdateWindowSize (const TcpHeader& header);
// Manage data tx/rx
@@ -736,7 +750,9 @@ protected:
// Window management
uint32_t m_segmentSize; //!< Segment size
uint16_t m_maxWinSize; //!< Maximum window size to advertise
TracedValue<uint32_t> m_rWnd; //!< Flow control window at remote side
TracedValue<uint32_t> m_rWnd; //!< Receiver window (RCV.WND in RFC793)
TracedValue<SequenceNumber32> m_highRxMark; //!< Highest seqno received
TracedValue<SequenceNumber32> m_highRxAckMark; //!< Highest ack received
// Options
bool m_winScalingEnabled; //!< Window Scale option enabled