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 <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
#include <Select.h>
|
#include <Select.h>
|
||||||
@@ -427,6 +428,7 @@ TCPEndpoint::TCPEndpoint(net_socket* socket)
|
|||||||
fSendWindow(0),
|
fSendWindow(0),
|
||||||
fSendMaxWindow(0),
|
fSendMaxWindow(0),
|
||||||
fSendMaxSegmentSize(TCP_DEFAULT_MAX_SEGMENT_SIZE),
|
fSendMaxSegmentSize(TCP_DEFAULT_MAX_SEGMENT_SIZE),
|
||||||
|
fSendMaxSegments(0),
|
||||||
fSendQueue(socket->send.buffer_size),
|
fSendQueue(socket->send.buffer_size),
|
||||||
fInitialSendSequence(0),
|
fInitialSendSequence(0),
|
||||||
fDuplicateAcknowledgeCount(0),
|
fDuplicateAcknowledgeCount(0),
|
||||||
@@ -1392,7 +1394,14 @@ TCPEndpoint::_PrepareReceivePath(tcp_segment_header& segment)
|
|||||||
fFlags &= ~FLAG_OPTION_TIMESTAMP;
|
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;
|
fSlowStartThreshold = (uint32)segment.advertised_window << fSendWindowShift;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1897,6 +1906,9 @@ inline bool
|
|||||||
TCPEndpoint::_ShouldSendSegment(tcp_segment_header& segment, uint32 length,
|
TCPEndpoint::_ShouldSendSegment(tcp_segment_header& segment, uint32 length,
|
||||||
uint32 segmentMaxSize, uint32 flightSize)
|
uint32 segmentMaxSize, uint32 flightSize)
|
||||||
{
|
{
|
||||||
|
if (fState == ESTABLISHED && fSendMaxSegments == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
// Avoid the silly window syndrome - we only send a segment in case:
|
// Avoid the silly window syndrome - we only send a segment in case:
|
||||||
// - we have a full segment to send, or
|
// - we have a full segment to send, or
|
||||||
@@ -2114,6 +2126,9 @@ TCPEndpoint::_SendQueued(bool force, uint32 sendWindow)
|
|||||||
fReceiveMaxAdvertised = fReceiveNext
|
fReceiveMaxAdvertised = fReceiveNext
|
||||||
+ ((uint32)segment.advertised_window << fReceiveWindowShift);
|
+ ((uint32)segment.advertised_window << fReceiveWindowShift);
|
||||||
|
|
||||||
|
if (segmentLength != 0 && fState == ESTABLISHED)
|
||||||
|
--fSendMaxSegments;
|
||||||
|
|
||||||
status = next->module->send_routed_data(next, fRoute, buffer);
|
status = next->module->send_routed_data(next, fRoute, buffer);
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
gBufferModule->free(buffer);
|
gBufferModule->free(buffer);
|
||||||
@@ -2207,6 +2222,26 @@ TCPEndpoint::_Acknowledged(tcp_segment_header& segment)
|
|||||||
|
|
||||||
if (fSendUnacknowledged < segment.acknowledge) {
|
if (fSendUnacknowledged < segment.acknowledge) {
|
||||||
fSendQueue.RemoveUntil(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;
|
fSendUnacknowledged = segment.acknowledge;
|
||||||
if (fSendNext < fSendUnacknowledged)
|
if (fSendNext < fSendUnacknowledged)
|
||||||
fSendNext = fSendUnacknowledged;
|
fSendNext = fSendUnacknowledged;
|
||||||
@@ -2236,20 +2271,6 @@ TCPEndpoint::_Acknowledged(tcp_segment_header& segment)
|
|||||||
fSendCondition.NotifyAll();
|
fSendCondition.NotifyAll();
|
||||||
gSocketModule->notify(socket, B_SELECT_WRITE, fSendQueue.Free());
|
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
|
// if there is data left to be sent, send it now
|
||||||
@@ -2261,16 +2282,21 @@ TCPEndpoint::_Acknowledged(tcp_segment_header& segment)
|
|||||||
void
|
void
|
||||||
TCPEndpoint::_Retransmit()
|
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()");
|
TRACE("Retransmit()");
|
||||||
|
|
||||||
_ResetSlowStart();
|
|
||||||
fSendNext = fSendUnacknowledged;
|
fSendNext = fSendUnacknowledged;
|
||||||
|
|
||||||
// Do exponential back off of the retransmit timeout
|
|
||||||
fRetransmitTimeout *= 2;
|
|
||||||
if (fRetransmitTimeout > TCP_MAX_RETRANSMIT_TIMEOUT)
|
|
||||||
fRetransmitTimeout = TCP_MAX_RETRANSMIT_TIMEOUT;
|
|
||||||
|
|
||||||
_SendQueued();
|
_SendQueued();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ private:
|
|||||||
uint32 fSendWindow;
|
uint32 fSendWindow;
|
||||||
uint32 fSendMaxWindow;
|
uint32 fSendMaxWindow;
|
||||||
uint32 fSendMaxSegmentSize;
|
uint32 fSendMaxSegmentSize;
|
||||||
|
uint32 fSendMaxSegments;
|
||||||
BufferQueue fSendQueue;
|
BufferQueue fSendQueue;
|
||||||
tcp_sequence fLastAcknowledgeSent;
|
tcp_sequence fLastAcknowledgeSent;
|
||||||
tcp_sequence fInitialSendSequence;
|
tcp_sequence fInitialSendSequence;
|
||||||
|
|||||||
@@ -193,6 +193,8 @@ operator==(tcp_sequence a, tcp_sequence b)
|
|||||||
#define TCP_MIN_RETRANSMIT_TIMEOUT 200000 // 200 msecs
|
#define TCP_MIN_RETRANSMIT_TIMEOUT 200000 // 200 msecs
|
||||||
// Maximum retransmit timeout (per RFC6298)
|
// Maximum retransmit timeout (per RFC6298)
|
||||||
#define TCP_MAX_RETRANSMIT_TIMEOUT 60000000 // 60 secs
|
#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 {
|
struct tcp_sack {
|
||||||
uint32 left_edge;
|
uint32 left_edge;
|
||||||
|
|||||||
Reference in New Issue
Block a user