From c70d3bafd3ef8cb0b218d942531a2296576a8661 Mon Sep 17 00:00:00 2001 From: Hugo Santos Date: Fri, 20 Apr 2007 09:21:55 +0000 Subject: [PATCH] more TCP fixes, we should now be able to send large amounts of data through congestioned links. - fixed BufferQueue's RemoveUntil. - reset SND.NXT on third duplicate ACK (fast retransmit). - on retransmit reset SND.NXT to SND.UNA (it will be updated back when we get good ACKs). - fixed effective window calculation. - relaxed SWS checking a bit, don't send partial packets on retransmission as the window might have been reduced due to congestion. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20769 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../network/protocols/tcp/BufferQueue.cpp | 17 +++--- .../network/protocols/tcp/TCPEndpoint.cpp | 58 ++++++++++--------- .../network/protocols/tcp/TCPEndpoint.h | 1 - 3 files changed, 40 insertions(+), 36 deletions(-) diff --git a/src/add-ons/kernel/network/protocols/tcp/BufferQueue.cpp b/src/add-ons/kernel/network/protocols/tcp/BufferQueue.cpp index 12d67cd846..2a829c98c4 100644 --- a/src/add-ons/kernel/network/protocols/tcp/BufferQueue.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/BufferQueue.cpp @@ -183,17 +183,12 @@ BufferQueue::RemoveUntil(tcp_sequence sequence) { TRACE(("BufferQueue@%p::RemoveUntil(sequence %lu)\n", this, (uint32)sequence)); - fFirstSequence = sequence; + if (sequence < fFirstSequence) + return B_OK; SegmentList::Iterator iterator = fList.GetIterator(); net_buffer *buffer = NULL; - while ((buffer = iterator.Next()) != NULL) { - if (sequence <= buffer->sequence) { - fFirstSequence = buffer->sequence; - // just in case there is a hole, how unlikely this may ever be - break; - } - + while ((buffer = iterator.Next()) != NULL && buffer->sequence < sequence) { if (sequence >= buffer->sequence + buffer->size) { // remove this buffer completely iterator.Remove(); @@ -209,9 +204,15 @@ BufferQueue::RemoveUntil(tcp_sequence sequence) buffer->sequence += size; fNumBytes -= size; fContiguousBytes -= size; + break; } } + if (fList.IsEmpty()) + fFirstSequence = fLastSequence; + else + fFirstSequence = fList.Head()->sequence; + return B_OK; } diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp index 16835ef3a2..c07592d002 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp @@ -62,12 +62,12 @@ #ifdef PROBE_TCP # define PROBE(buffer, window) \ - dprintf("TCP PROBE %llu %s %s %ld %lu %lu %lu %lu %lu %lu %lu %lu %llu\n", \ + dprintf("TCP PROBE %llu %s %s %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %llu\n", \ system_time(), PrintAddress(&buffer->source), \ PrintAddress(&buffer->destination), buffer->size, (uint32)fSendNext, \ (uint32)fSendUnacknowledged, fCongestionWindow, fSlowStartThreshold, \ window, fSendWindow, (uint32)(fSendMax - fSendUnacknowledged), \ - fSendQueue.Used(), fRetransmitTimeout) + fSendQueue.Available(fSendNext), fSendQueue.Used(), fRetransmitTimeout) #else # define PROBE(buffer, window) do { } while (0) #endif @@ -1016,10 +1016,9 @@ TCPEndpoint::_ShouldSendSegment(tcp_segment_header &segment, uint32 length, // - the buffer is at least larger than half of the maximum send window, or // - we're retransmitting data if (length == segmentMaxSize - || ((flightSize == 0 || (fOptions & TCP_NODELAY) != 0) - && tcp_sequence(fSendNext + length) == fSendQueue.LastSequence()) - || (fSendMaxWindow > 0 && length >= fSendMaxWindow / 2) - || fSendNext < fSendMax) + || (fOptions & TCP_NODELAY) != 0 + || tcp_sequence(fSendNext + length) == fSendQueue.LastSequence() + || (fSendMaxWindow > 0 && length >= fSendMaxWindow / 2)) return true; } @@ -1091,16 +1090,27 @@ TCPEndpoint::_SendQueued(bool force) if (fCongestionWindow > 0) sendWindow = min_c(sendWindow, fCongestionWindow); - // a TCP may not send more data to the network than the - // currently unacknowledged sequence (SND.UNA) plus the - // calculated send window. + // SND.UNA SND.NXT SND.MAX + // | | | + // v v v + // ----------------------------------- + // | effective window | + // ----------------------------------- + + // Flight size represents the window of data which is currently in the + // ether. We should never send data such as the flight size becomes larger + // than the effective window. Note however that the effective window may be + // reduced (by congestion for instance), so at some point in time flight + // size may be larger than the currently calculated window. uint32 flightSize = fSendMax - fSendUnacknowledged; - if (flightSize > sendWindow) { + uint32 consumedWindow = fSendNext - fSendUnacknowledged; + + if (consumedWindow > sendWindow) { sendWindow = 0; // TODO enter persist state? try to get a window update. } else - sendWindow -= flightSize; + sendWindow -= consumedWindow; if (force && sendWindow == 0 && fSendNext <= fSendQueue.LastSequence()) { // send one byte of data to ask for a window update @@ -1155,9 +1165,12 @@ TCPEndpoint::_SendQueued(bool force) buffer, buffer->size, PrintAddress(&buffer->source), PrintAddress(&buffer->destination)); TRACE(" flags 0x%x, seq %lu, ack %lu, rwnd %hu, cwnd %lu" - ", ssthresh %lu", segment.flags, segment.sequence, - segment.acknowledge, segment.advertised_window, - fCongestionWindow, fSlowStartThreshold); + ", ssthresh %lu", segment.flags, segment.sequence, + segment.acknowledge, segment.advertised_window, + fCongestionWindow, fSlowStartThreshold); + TRACE(" len %lu first %lu last %lu", segmentLength, + (uint32)fSendQueue.FirstSequence(), + (uint32)fSendQueue.LastSequence()); PROBE(buffer, sendWindow); sendWindow -= buffer->size; @@ -1219,17 +1232,6 @@ TCPEndpoint::_SendQueued(bool force) } -status_t -TCPEndpoint::_SendQueued(tcp_sequence sendNext) -{ - tcp_sequence previousSendNext = fSendNext; - fSendNext = sendNext; - status_t status = _SendQueued(); - fSendNext = previousSendNext; - return status; -} - - int TCPEndpoint::_GetMSS(const sockaddr *address) const { @@ -1693,7 +1695,8 @@ TCPEndpoint::_Retransmit() { TRACE("Retransmit()"); _ResetSlowStart(); - _SendQueued(fSendUnacknowledged); + fSendNext = fSendUnacknowledged; + _SendQueued(); } @@ -1738,10 +1741,11 @@ TCPEndpoint::_DuplicateAcknowledge(tcp_segment_header &segment) _ResetSlowStart(); fCongestionWindow = fSlowStartThreshold + 3 * fSendMaxSegmentSize; + fSendNext = segment.acknowledge; } else if (fDuplicateAcknowledgeCount > 3) fCongestionWindow += fSendMaxSegmentSize; - _SendQueued(segment.acknowledge); + _SendQueued(); } diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h index 67d88ac07f..07e9ec554e 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h @@ -90,7 +90,6 @@ class TCPEndpoint : public net_protocol { bool _ShouldSendSegment(tcp_segment_header &segment, uint32 length, uint32 segmentMaxSize, uint32 flightSize); status_t _SendQueued(bool force = false); - status_t _SendQueued(tcp_sequence sendNext); int _GetMSS(const struct sockaddr *) const; status_t _ShutdownEgress(bool closing); ssize_t _AvailableData() const;