tcp: slow start@rfc5681 : updated rules for congestion window

Signed-off-by: Jessica Hamilton <[email protected]>
This commit is contained in:
A-star-ayush
2017-08-28 08:52:19 +00:00
committed by Jessica Hamilton
parent e9300454b6
commit 05743f6a13
3 changed files with 51 additions and 22 deletions
@@ -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;