tcp: slow start@rfc5681 : updated rules for congestion window
Signed-off-by: Jessica Hamilton <[email protected]>
This commit is contained in:
committed by
Jessica Hamilton
parent
e9300454b6
commit
05743f6a13
@@ -18,6 +18,7 @@
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <Select.h>
|
||||
@@ -427,6 +428,7 @@ TCPEndpoint::TCPEndpoint(net_socket* socket)
|
||||
fSendWindow(0),
|
||||
fSendMaxWindow(0),
|
||||
fSendMaxSegmentSize(TCP_DEFAULT_MAX_SEGMENT_SIZE),
|
||||
fSendMaxSegments(0),
|
||||
fSendQueue(socket->send.buffer_size),
|
||||
fInitialSendSequence(0),
|
||||
fDuplicateAcknowledgeCount(0),
|
||||
@@ -1392,7 +1394,14 @@ TCPEndpoint::_PrepareReceivePath(tcp_segment_header& segment)
|
||||
fFlags &= ~FLAG_OPTION_TIMESTAMP;
|
||||
}
|
||||
|
||||
fCongestionWindow = 2 * fSendMaxSegmentSize;
|
||||
if (fSendMaxSegmentSize > 2190)
|
||||
fCongestionWindow = 2 * fSendMaxSegmentSize;
|
||||
else if (fSendMaxSegmentSize > 1095)
|
||||
fCongestionWindow = 3 * fSendMaxSegmentSize;
|
||||
else
|
||||
fCongestionWindow = 4 * fSendMaxSegmentSize;
|
||||
|
||||
fSendMaxSegments = fCongestionWindow / fSendMaxSegmentSize;
|
||||
fSlowStartThreshold = (uint32)segment.advertised_window << fSendWindowShift;
|
||||
}
|
||||
|
||||
@@ -1897,6 +1906,9 @@ inline bool
|
||||
TCPEndpoint::_ShouldSendSegment(tcp_segment_header& segment, uint32 length,
|
||||
uint32 segmentMaxSize, uint32 flightSize)
|
||||
{
|
||||
if (fState == ESTABLISHED && fSendMaxSegments == 0)
|
||||
return false;
|
||||
|
||||
if (length > 0) {
|
||||
// Avoid the silly window syndrome - we only send a segment in case:
|
||||
// - we have a full segment to send, or
|
||||
@@ -2114,6 +2126,9 @@ TCPEndpoint::_SendQueued(bool force, uint32 sendWindow)
|
||||
fReceiveMaxAdvertised = fReceiveNext
|
||||
+ ((uint32)segment.advertised_window << fReceiveWindowShift);
|
||||
|
||||
if (segmentLength != 0 && fState == ESTABLISHED)
|
||||
--fSendMaxSegments;
|
||||
|
||||
status = next->module->send_routed_data(next, fRoute, buffer);
|
||||
if (status < B_OK) {
|
||||
gBufferModule->free(buffer);
|
||||
@@ -2207,6 +2222,26 @@ TCPEndpoint::_Acknowledged(tcp_segment_header& segment)
|
||||
|
||||
if (fSendUnacknowledged < segment.acknowledge) {
|
||||
fSendQueue.RemoveUntil(segment.acknowledge);
|
||||
|
||||
// the acknowledgment of the SYN/ACK MUST NOT increase the size of the congestion window
|
||||
if (fSendUnacknowledged != fInitialSendSequence) {
|
||||
if (fCongestionWindow < fSlowStartThreshold)
|
||||
fCongestionWindow += min_c(segment.acknowledge - fSendUnacknowledged.Number(),
|
||||
fSendMaxSegmentSize);
|
||||
else {
|
||||
uint32 increment = fSendMaxSegmentSize * fSendMaxSegmentSize;
|
||||
|
||||
if (increment < fCongestionWindow)
|
||||
increment = 1;
|
||||
else
|
||||
increment /= fCongestionWindow;
|
||||
|
||||
fCongestionWindow += increment;
|
||||
}
|
||||
|
||||
fSendMaxSegments = UINT32_MAX;
|
||||
}
|
||||
|
||||
fSendUnacknowledged = segment.acknowledge;
|
||||
if (fSendNext < fSendUnacknowledged)
|
||||
fSendNext = fSendUnacknowledged;
|
||||
@@ -2236,20 +2271,6 @@ TCPEndpoint::_Acknowledged(tcp_segment_header& segment)
|
||||
fSendCondition.NotifyAll();
|
||||
gSocketModule->notify(socket, B_SELECT_WRITE, fSendQueue.Free());
|
||||
}
|
||||
|
||||
if (fCongestionWindow < fSlowStartThreshold)
|
||||
fCongestionWindow += fSendMaxSegmentSize;
|
||||
}
|
||||
|
||||
if (fCongestionWindow >= fSlowStartThreshold) {
|
||||
uint32 increment = fSendMaxSegmentSize * fSendMaxSegmentSize;
|
||||
|
||||
if (increment < fCongestionWindow)
|
||||
increment = 1;
|
||||
else
|
||||
increment /= fCongestionWindow;
|
||||
|
||||
fCongestionWindow += increment;
|
||||
}
|
||||
|
||||
// if there is data left to be sent, send it now
|
||||
@@ -2261,16 +2282,21 @@ TCPEndpoint::_Acknowledged(tcp_segment_header& segment)
|
||||
void
|
||||
TCPEndpoint::_Retransmit()
|
||||
{
|
||||
if (fState < ESTABLISHED) {
|
||||
fRetransmitTimeout = TCP_SYN_RETRANSMIT_TIMEOUT;
|
||||
fCongestionWindow = fSendMaxSegmentSize;
|
||||
} else {
|
||||
_ResetSlowStart();
|
||||
|
||||
// Do exponential back off of the retransmit timeout
|
||||
fRetransmitTimeout *= 2;
|
||||
if (fRetransmitTimeout > TCP_MAX_RETRANSMIT_TIMEOUT)
|
||||
fRetransmitTimeout = TCP_MAX_RETRANSMIT_TIMEOUT;
|
||||
}
|
||||
|
||||
TRACE("Retransmit()");
|
||||
|
||||
_ResetSlowStart();
|
||||
fSendNext = fSendUnacknowledged;
|
||||
|
||||
// Do exponential back off of the retransmit timeout
|
||||
fRetransmitTimeout *= 2;
|
||||
if (fRetransmitTimeout > TCP_MAX_RETRANSMIT_TIMEOUT)
|
||||
fRetransmitTimeout = TCP_MAX_RETRANSMIT_TIMEOUT;
|
||||
|
||||
_SendQueued();
|
||||
}
|
||||
|
||||
|
||||
@@ -145,6 +145,7 @@ private:
|
||||
uint32 fSendWindow;
|
||||
uint32 fSendMaxWindow;
|
||||
uint32 fSendMaxSegmentSize;
|
||||
uint32 fSendMaxSegments;
|
||||
BufferQueue fSendQueue;
|
||||
tcp_sequence fLastAcknowledgeSent;
|
||||
tcp_sequence fInitialSendSequence;
|
||||
|
||||
@@ -193,6 +193,8 @@ operator==(tcp_sequence a, tcp_sequence b)
|
||||
#define TCP_MIN_RETRANSMIT_TIMEOUT 200000 // 200 msecs
|
||||
// Maximum retransmit timeout (per RFC6298)
|
||||
#define TCP_MAX_RETRANSMIT_TIMEOUT 60000000 // 60 secs
|
||||
// New value for timeout in case of lost SYN (RFC 6298)
|
||||
#define TCP_SYN_RETRANSMIT_TIMEOUT 3000000 // 3 secs
|
||||
|
||||
struct tcp_sack {
|
||||
uint32 left_edge;
|
||||
|
||||
Reference in New Issue
Block a user