Ticket #13681: 0008-tcp-rfc-2018-implemented-SACK-option.patch

File 0008-tcp-rfc-2018-implemented-SACK-option.patch, 7.6 KB (added by a-star, 7 years ago)
  • src/add-ons/kernel/network/protocols/tcp/BufferQueue.cpp

    From 3388f7c151f1f8faf3906ae3753cf0872e099e33 Mon Sep 17 00:00:00 2001
    From: A-star-ayush <myselfthebest@yahoo.com>
    Date: Fri, 25 Aug 2017 14:14:35 +0530
    Subject: [PATCH] tcp: rfc 2018: implemented SACK option
    
    ---
     .../kernel/network/protocols/tcp/BufferQueue.cpp   | 35 ++++++++++++++++++++++
     .../kernel/network/protocols/tcp/BufferQueue.h     |  1 +
     .../kernel/network/protocols/tcp/TCPEndpoint.cpp   | 22 ++++++++++++--
     src/add-ons/kernel/network/protocols/tcp/tcp.cpp   | 23 ++++++++++----
     src/add-ons/kernel/network/protocols/tcp/tcp.h     |  5 ++--
     5 files changed, 77 insertions(+), 9 deletions(-)
    
    diff --git a/src/add-ons/kernel/network/protocols/tcp/BufferQueue.cpp b/src/add-ons/kernel/network/protocols/tcp/BufferQueue.cpp
    index de83ba3..4cf95c5 100644
    a b BufferQueue::SetPushPointer()  
    436436        fPushPointer = fList.Tail()->sequence + fList.Tail()->size;
    437437}
    438438
     439
     440int
     441BufferQueue::PopulateSackInfo(tcp_sequence sequence, int maxSackCount, tcp_sack* sacks)
     442{
     443    SegmentList::ReverseIterator iterator = fList.GetReverseIterator();
     444    net_buffer* buffer = iterator.Next();
     445
     446    int sackCount = 0;
     447    while (buffer != NULL && buffer->sequence > sequence) {
     448        if (buffer->sequence + buffer->size < sacks[sackCount].left_edge) {
     449            if (sackCount + 1 == maxSackCount)
     450                break;
     451            ++sackCount;
     452            sacks[sackCount].left_edge = buffer->sequence;
     453            sacks[sackCount].right_edge = buffer->sequence + buffer->size;
     454        } else {
     455            sacks[sackCount].left_edge = buffer->sequence;
     456            if (sacks[sackCount].right_edge == 0)
     457                sacks[sackCount].right_edge = buffer->sequence + buffer->size;
     458        }
     459
     460        buffer = iterator.Next();
     461    }
     462
     463    if (sacks[0].left_edge != 0) {
     464        for (int i = 0; i <= sackCount; ++i) {
     465            sacks[i].left_edge = htonl(sacks[i].left_edge);
     466            sacks[i].right_edge = htonl(sacks[i].right_edge);
     467        }
     468        ++sackCount;
     469    }
     470
     471    return sackCount;
     472}
     473
    439474#if DEBUG_BUFFER_QUEUE
    440475
    441476/*! Perform a sanity check of the whole queue.
  • src/add-ons/kernel/network/protocols/tcp/BufferQueue.h

    diff --git a/src/add-ons/kernel/network/protocols/tcp/BufferQueue.h b/src/add-ons/kernel/network/protocols/tcp/BufferQueue.h
    index 73986a8..4c4567e 100644
    a b public:  
    4242
    4343    inline  size_t              PushedData() const;
    4444            void                SetPushPointer();
     45            int             PopulateSackInfo(tcp_sequence sequence, int maxSackCount, tcp_sack* sacks);
    4546
    4647            size_t              Used() const { return fNumBytes; }
    4748    inline  size_t              Free() const;
  • src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp

    diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp
    index 1d02161..0e2282e 100644
    a b enum {  
    319319    FLAG_CLOSED                 = 0x08,
    320320    FLAG_DELETE_ON_CLOSE        = 0x10,
    321321    FLAG_LOCAL                  = 0x20,
    322     FLAG_RECOVERY               = 0x40
     322    FLAG_RECOVERY               = 0x40,
     323    FLAG_OPTION_SACK_PERMITTED  = 0x80,
    323324};
    324325
    325326
    TCPEndpoint::TCPEndpoint(net_socket* socket)  
    450451    fCongestionWindow(0),
    451452    fSlowStartThreshold(0),
    452453    fState(CLOSED),
    453     fFlags(FLAG_OPTION_WINDOW_SCALE | FLAG_OPTION_TIMESTAMP)
     454    fFlags(FLAG_OPTION_WINDOW_SCALE | FLAG_OPTION_TIMESTAMP | FLAG_OPTION_SACK_PERMITTED)
    454455{
    455456    // TODO: to be replaced with a real read/write locking strategy!
    456457    mutex_init(&fLock, "tcp lock");
    TCPEndpoint::_PrepareReceivePath(tcp_segment_header& segment)  
    14261427            fReceivedTimestamp = segment.timestamp_value;
    14271428        } else
    14281429            fFlags &= ~FLAG_OPTION_TIMESTAMP;
     1430
     1431        if ((segment.options & TCP_SACK_PERMITTED) == 0)
     1432            fFlags &= ~FLAG_OPTION_SACK_PERMITTED;
    14291433    }
    14301434
    14311435    if (fSendMaxSegmentSize > 2190)
    TCPEndpoint::_SendQueued(bool force, uint32 sendWindow)  
    20272031            segment.timestamp_value = tcp_now();
    20282032        }
    20292033
     2034        // SACK information is embedded with duplicate acknowledgements
     2035        if (!fReceiveQueue.IsContiguous() && fLastAcknowledgeSent == fReceiveNext
     2036            && (fFlags & FLAG_OPTION_SACK_PERMITTED) != 0) {
     2037            segment.options |= TCP_HAS_SACK;
     2038            int maxSackCount = 4 - ((fFlags & FLAG_OPTION_TIMESTAMP) != 0);
     2039            segment.sacks = (tcp_sack*)calloc(maxSackCount, sizeof(tcp_sack));
     2040            if (segment.sacks != NULL)
     2041                segment.sackCount = fReceiveQueue.PopulateSackInfo(fReceiveNext, maxSackCount, segment.sacks);
     2042            else
     2043                segment.sackCount = 0;
     2044        }
     2045
    20302046        if ((segment.flags & TCP_FLAG_SYNCHRONIZE) != 0
    20312047            && fSendNext == fInitialSendSequence) {
    20322048            // add connection establishment options
    TCPEndpoint::_SendQueued(bool force, uint32 sendWindow)  
    20352051                segment.options |= TCP_HAS_WINDOW_SCALE;
    20362052                segment.window_shift = fReceiveWindowShift;
    20372053            }
     2054            if ((fFlags & FLAG_OPTION_SACK_PERMITTED) != 0)
     2055                segment.options |= TCP_SACK_PERMITTED;
    20382056        }
    20392057    }
    20402058
  • src/add-ons/kernel/network/protocols/tcp/tcp.cpp

    diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp
    index b14f662..61c4ca5 100644
    a b add_options(tcp_segment_header &segment, uint8 *buffer, size_t bufferSize)  
    140140        bump_option(option, length);
    141141    }
    142142
    143     if (segment.sack_count > 0) {
     143    if (segment.sackCount > 0) {
    144144        int sackCount = ((int)(bufferSize - length) - 4) / sizeof(tcp_sack);
    145         if (sackCount > segment.sack_count)
    146             sackCount = segment.sack_count;
     145        if (sackCount > segment.sackCount)
     146            sackCount = segment.sackCount;
    147147
    148148        if (sackCount > 0) {
    149149            option->kind = TCP_OPTION_NOP;
    add_options(tcp_segment_header &segment, uint8 *buffer, size_t bufferSize)  
    154154            option->length = 2 + sackCount * sizeof(tcp_sack);
    155155            memcpy(option->sack, segment.sacks, sackCount * sizeof(tcp_sack));
    156156            bump_option(option, length);
     157            free(segment.sacks);
    157158        }
    158159    }
    159160
    process_options(tcp_segment_header &segment, net_buffer *buffer, size_t size)  
    218219                if (option->length == 2 && size >= 2)
    219220                    segment.options |= TCP_SACK_PERMITTED;
    220221                break;
     222            case TCP_OPTION_SACK:
     223                if (size >= option->length) {
     224                    segment.options |= TCP_HAS_SACK;
     225                    segment.sackCount = (option->length - 2) / sizeof(tcp_sack);
     226                    segment.sacks = option->sack;
     227
     228                    for(int i = 0; i < segment.sackCount; ++i) {
     229                        segment.sacks[i].left_edge = ntohl(segment.sacks[i].left_edge);
     230                        segment.sacks[i].right_edge = ntohl(segment.sacks[i].right_edge);
     231                    }
     232                }
     233                break;
    221234        }
    222235
    223236        if (length < 0) {
    tcp_options_length(tcp_segment_header& segment)  
    432445    if (segment.options & TCP_SACK_PERMITTED)
    433446        length += 2;
    434447
    435     if (segment.sack_count > 0) {
     448    if (segment.sackCount > 0) {
    436449        int sackCount = min_c((int)((kMaxOptionSize - length - 4)
    437             / sizeof(tcp_sack)), segment.sack_count);
     450            / sizeof(tcp_sack)), segment.sackCount);
    438451        if (sackCount > 0)
    439452            length += 4 + sackCount * sizeof(tcp_sack);
    440453    }
  • src/add-ons/kernel/network/protocols/tcp/tcp.h

    diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.h b/src/add-ons/kernel/network/protocols/tcp/tcp.h
    index 24890a3..3b2100b 100644
    a b enum {  
    231231    TCP_HAS_WINDOW_SCALE    = 1 << 0,
    232232    TCP_HAS_TIMESTAMPS      = 1 << 1,
    233233    TCP_SACK_PERMITTED      = 1 << 2,
     234    TCP_HAS_SACK            = 1 << 3,
    234235};
    235236
    236237struct tcp_segment_header {
    struct tcp_segment_header {  
    239240        flags(_flags),
    240241        window_shift(0),
    241242        max_segment_size(0),
    242         sack_count(0),
     243        sackCount(0),
    243244        options(0)
    244245    {}
    245246
    struct tcp_segment_header {  
    255256    uint32  timestamp_reply;
    256257
    257258    tcp_sack    *sacks;
    258     int         sack_count;
     259    int         sackCount;
    259260
    260261    uint32  options;
    261262