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
This commit is contained in:
Hugo Santos
2007-04-20 09:21:55 +00:00
parent 91a808dc40
commit c70d3bafd3
3 changed files with 40 additions and 36 deletions
@@ -183,17 +183,12 @@ BufferQueue::RemoveUntil(tcp_sequence sequence)
{ {
TRACE(("BufferQueue@%p::RemoveUntil(sequence %lu)\n", this, (uint32)sequence)); TRACE(("BufferQueue@%p::RemoveUntil(sequence %lu)\n", this, (uint32)sequence));
fFirstSequence = sequence; if (sequence < fFirstSequence)
return B_OK;
SegmentList::Iterator iterator = fList.GetIterator(); SegmentList::Iterator iterator = fList.GetIterator();
net_buffer *buffer = NULL; net_buffer *buffer = NULL;
while ((buffer = iterator.Next()) != NULL) { while ((buffer = iterator.Next()) != NULL && buffer->sequence < sequence) {
if (sequence <= buffer->sequence) {
fFirstSequence = buffer->sequence;
// just in case there is a hole, how unlikely this may ever be
break;
}
if (sequence >= buffer->sequence + buffer->size) { if (sequence >= buffer->sequence + buffer->size) {
// remove this buffer completely // remove this buffer completely
iterator.Remove(); iterator.Remove();
@@ -209,9 +204,15 @@ BufferQueue::RemoveUntil(tcp_sequence sequence)
buffer->sequence += size; buffer->sequence += size;
fNumBytes -= size; fNumBytes -= size;
fContiguousBytes -= size; fContiguousBytes -= size;
break;
} }
} }
if (fList.IsEmpty())
fFirstSequence = fLastSequence;
else
fFirstSequence = fList.Head()->sequence;
return B_OK; return B_OK;
} }
@@ -62,12 +62,12 @@
#ifdef PROBE_TCP #ifdef PROBE_TCP
# define PROBE(buffer, window) \ # 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), \ system_time(), PrintAddress(&buffer->source), \
PrintAddress(&buffer->destination), buffer->size, (uint32)fSendNext, \ PrintAddress(&buffer->destination), buffer->size, (uint32)fSendNext, \
(uint32)fSendUnacknowledged, fCongestionWindow, fSlowStartThreshold, \ (uint32)fSendUnacknowledged, fCongestionWindow, fSlowStartThreshold, \
window, fSendWindow, (uint32)(fSendMax - fSendUnacknowledged), \ window, fSendWindow, (uint32)(fSendMax - fSendUnacknowledged), \
fSendQueue.Used(), fRetransmitTimeout) fSendQueue.Available(fSendNext), fSendQueue.Used(), fRetransmitTimeout)
#else #else
# define PROBE(buffer, window) do { } while (0) # define PROBE(buffer, window) do { } while (0)
#endif #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 // - the buffer is at least larger than half of the maximum send window, or
// - we're retransmitting data // - we're retransmitting data
if (length == segmentMaxSize if (length == segmentMaxSize
|| ((flightSize == 0 || (fOptions & TCP_NODELAY) != 0) || (fOptions & TCP_NODELAY) != 0
&& tcp_sequence(fSendNext + length) == fSendQueue.LastSequence()) || tcp_sequence(fSendNext + length) == fSendQueue.LastSequence()
|| (fSendMaxWindow > 0 && length >= fSendMaxWindow / 2) || (fSendMaxWindow > 0 && length >= fSendMaxWindow / 2))
|| fSendNext < fSendMax)
return true; return true;
} }
@@ -1091,16 +1090,27 @@ TCPEndpoint::_SendQueued(bool force)
if (fCongestionWindow > 0) if (fCongestionWindow > 0)
sendWindow = min_c(sendWindow, fCongestionWindow); sendWindow = min_c(sendWindow, fCongestionWindow);
// a TCP may not send more data to the network than the // SND.UNA SND.NXT SND.MAX
// currently unacknowledged sequence (SND.UNA) plus the // | | |
// calculated send window. // 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; uint32 flightSize = fSendMax - fSendUnacknowledged;
if (flightSize > sendWindow) { uint32 consumedWindow = fSendNext - fSendUnacknowledged;
if (consumedWindow > sendWindow) {
sendWindow = 0; sendWindow = 0;
// TODO enter persist state? try to get a window update. // TODO enter persist state? try to get a window update.
} else } else
sendWindow -= flightSize; sendWindow -= consumedWindow;
if (force && sendWindow == 0 && fSendNext <= fSendQueue.LastSequence()) { if (force && sendWindow == 0 && fSendNext <= fSendQueue.LastSequence()) {
// send one byte of data to ask for a window update // send one byte of data to ask for a window update
@@ -1158,6 +1168,9 @@ TCPEndpoint::_SendQueued(bool force)
", ssthresh %lu", segment.flags, segment.sequence, ", ssthresh %lu", segment.flags, segment.sequence,
segment.acknowledge, segment.advertised_window, segment.acknowledge, segment.advertised_window,
fCongestionWindow, fSlowStartThreshold); fCongestionWindow, fSlowStartThreshold);
TRACE(" len %lu first %lu last %lu", segmentLength,
(uint32)fSendQueue.FirstSequence(),
(uint32)fSendQueue.LastSequence());
PROBE(buffer, sendWindow); PROBE(buffer, sendWindow);
sendWindow -= buffer->size; 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 int
TCPEndpoint::_GetMSS(const sockaddr *address) const TCPEndpoint::_GetMSS(const sockaddr *address) const
{ {
@@ -1693,7 +1695,8 @@ TCPEndpoint::_Retransmit()
{ {
TRACE("Retransmit()"); TRACE("Retransmit()");
_ResetSlowStart(); _ResetSlowStart();
_SendQueued(fSendUnacknowledged); fSendNext = fSendUnacknowledged;
_SendQueued();
} }
@@ -1738,10 +1741,11 @@ TCPEndpoint::_DuplicateAcknowledge(tcp_segment_header &segment)
_ResetSlowStart(); _ResetSlowStart();
fCongestionWindow = fSlowStartThreshold + 3 fCongestionWindow = fSlowStartThreshold + 3
* fSendMaxSegmentSize; * fSendMaxSegmentSize;
fSendNext = segment.acknowledge;
} else if (fDuplicateAcknowledgeCount > 3) } else if (fDuplicateAcknowledgeCount > 3)
fCongestionWindow += fSendMaxSegmentSize; fCongestionWindow += fSendMaxSegmentSize;
_SendQueued(segment.acknowledge); _SendQueued();
} }
@@ -90,7 +90,6 @@ class TCPEndpoint : public net_protocol {
bool _ShouldSendSegment(tcp_segment_header &segment, uint32 length, bool _ShouldSendSegment(tcp_segment_header &segment, uint32 length,
uint32 segmentMaxSize, uint32 flightSize); uint32 segmentMaxSize, uint32 flightSize);
status_t _SendQueued(bool force = false); status_t _SendQueued(bool force = false);
status_t _SendQueued(tcp_sequence sendNext);
int _GetMSS(const struct sockaddr *) const; int _GetMSS(const struct sockaddr *) const;
status_t _ShutdownEgress(bool closing); status_t _ShutdownEgress(bool closing);
ssize_t _AvailableData() const; ssize_t _AvailableData() const;