Project

General

Profile

Actions

Bug #13475

open

TCP sends fragmented IP when LSO is enabled

Added by David Hanisch 10 months ago. Updated 4 months ago.

Status:
In Progress
Priority:
Normal
Assignee:
Category:
networking
Start date:
Due date:
% Done:

0%

Estimated time:
Difficulty:
Medium
Tags:
Gerrit CR:

Description

Situation:
  • tcp connection was closed
  • there is more than one mss unsent
  • LSO is enabled

In tcp_send() the calculation of bytes to send is done under the assumption that LSO will be used. A value higher than mss is set for lso_usable. Later this 'if' is taken, because we are at the end of the data stream:

        if (tcp->tcp_valid_bits != 0 &&
            (tcp->tcp_valid_bits != TCP_FSS_VALID ||
            ((*snxt + len) == tcp->tcp_fss))) {

This causes data with len > mss being sent without LSO setup and due to this with IP fragmentation. Beside the general wish to avoid IP fragmentation this conflicted with IP filter: The additional fragments were dropped and retransmission occurred.

I can imagine two fixes:

  • the easy one: don't do LSO if any of the VALID bits is set
  • more complicated: with TCP_FSS_VALID don't send the complete unsent data with LSO but leave data <=mss for the next loop, which will then automaticaly be without LSO
Actions #1

Updated by Marcel Telka 10 months ago

  • Description updated (diff)
Actions #2

Updated by Marcel Telka 10 months ago

  • Description updated (diff)
Actions #3

Updated by David Hanisch 10 months ago

This how a fix could look like.

The easy one:

diff --git a/usr/src/uts/common/inet/tcp/tcp_output.c b/usr/src/uts/common/inet/tcp/tcp_output.c
index 115842e5e1e0..3fb1eb53fd1f 100644
--- a/usr/src/uts/common/inet/tcp/tcp_output.c
+++ b/usr/src/uts/common/inet/tcp/tcp_output.c
@@ -1783,7 +1783,7 @@ tcp_send(tcp_t *tcp, const int mss, const int total_hdr_len,
         * enough available data to initiate LSO transmission in the for(){}
         * loops.
         */
-       if (tcp->tcp_lso && (tcp->tcp_valid_bits & ~TCP_FSS_VALID) == 0)
+       if (tcp->tcp_lso && tcp->tcp_valid_bits == 0)
                do_lso_send = B_TRUE;

        for (;;) {

A bit more complicated:

diff --git a/usr/src/uts/common/inet/tcp/tcp_output.c b/usr/src/uts/common/inet/tcp/tcp_output.c
index 115842e5e1e0..998fd76aee87 100644
--- a/usr/src/uts/common/inet/tcp/tcp_output.c
+++ b/usr/src/uts/common/inet/tcp/tcp_output.c
@@ -1803,8 +1803,17 @@ tcp_send(tcp_t *tcp, const int mss, const int total_hdr_len,
                         * Determine whether or not it's possible to do LSO,
                         * and if so, how much data we can send.
                         */
-                       if ((*usable - 1) / mss >= 1) {
-                               lso_usable = MIN(tcp->tcp_lso_max, *usable);
+                       lso_usable = MIN(tcp->tcp_lso_max, *usable);
+                       if ((tcp->tcp_valid_bits & TCP_FSS_VALID) &&
+                           (*snxt + lso_usable) == tcp->tcp_fss) {
+                               /*
+                                * we must leave some data to be sent not LSO
+                                * through the tcp_xmit_mp() (see below)
+                                */
+                               int remain = lso_usable % mss;
+                               lso_usable -= remain ? remain : mss;
+                       }
+                       if ((lso_usable - 1) / mss >= 1) {
                                num_lso_seg = lso_usable / mss;
                                if (lso_usable % mss) {
                                        num_lso_seg++;
Actions #4

Updated by Marcel Telka 6 months ago

  • Subject changed from TCP sends segmented IP when LSO is enabled to TCP sends fragmented IP when LSO is enabled
  • Description updated (diff)
Actions #5

Updated by Marcel Telka 4 months ago

  • Category set to networking
  • Status changed from New to In Progress
  • Assignee set to Marcel Telka
Actions

Also available in: Atom PDF