Actions
Bug #13475
openTCP sends fragmented IP when LSO is enabled
Start date:
Due date:
% Done:
0%
Estimated time:
Difficulty:
Medium
Tags:
Gerrit CR:
External Bug:
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
Updated by David Hanisch almost 3 years 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++;
Updated by Marcel Telka over 2 years ago
- Subject changed from TCP sends segmented IP when LSO is enabled to TCP sends fragmented IP when LSO is enabled
- Description updated (diff)
Updated by Marcel Telka over 2 years ago
- Category set to networking
- Status changed from New to In Progress
- Assignee set to Marcel Telka
Actions