diff --git a/src/internet/model/tcp-socket-base.cc b/src/internet/model/tcp-socket-base.cc index cb9b39eb6..14900a1c6 100644 --- a/src/internet/model/tcp-socket-base.cc +++ b/src/internet/model/tcp-socket-base.cc @@ -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, 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, 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, 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, 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) { diff --git a/src/internet/model/tcp-socket-base.h b/src/internet/model/tcp-socket-base.h index 2802fc6a4..2b4b6bb4b 100644 --- a/src/internet/model/tcp-socket-base.h +++ b/src/internet/model/tcp-socket-base.h @@ -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 m_rWnd; //!< Flow control window at remote side + TracedValue m_rWnd; //!< Receiver window (RCV.WND in RFC793) + TracedValue m_highRxMark; //!< Highest seqno received + TracedValue m_highRxAckMark; //!< Highest ack received // Options bool m_winScalingEnabled; //!< Window Scale option enabled