[PATCH v9 0/2] Add support for SO_PEEK_OFF
We add support for the SO_PEEK_OFF option, plus work around a kernel bug discovered along the way. Jon Maloy (2): tcp: leverage support of SO_PEEK_OFF socket option when available tcp: handle shrunk window advertisemenst from guest tcp.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- tcp.h | 3 +++ tcp_buf.c | 25 ++++++++++++++++------ 3 files changed, 81 insertions(+), 9 deletions(-) -- 2.45.2
From linux-6.9.0 the kernel will contain
commit 05ea491641d3 ("tcp: add support for SO_PEEK_OFF socket option").
This new feature makes is possible to call recv_msg(MSG_PEEK) and make
it start reading data from a given offset set by the SO_PEEK_OFF socket
option. This way, we can avoid repeated reading of already read bytes of
a received message, hence saving read cycles when forwarding TCP
messages in the host->name space direction.
In this commit, we add functionality to leverage this feature when
available, while we fall back to the previous behavior when not.
Measurements with iperf3 shows that throughput increases with 15-20
percent in the host->namespace direction when this feature is used.
Reviewed-by: David Gibson
A bug in kernel TCP may lead to a deadlock where a zero window is sent
from the guest peer, while it is unable to send out window updates even
after socket reads have freed up enough buffer space to permit a larger
window. In this situation, new window advertisements from the peer can
only be triggered by data packets arriving from this side.
However, currently such packets are never sent, because the zero-window
condition prevents this side from sending out any packets whatsoever
to the peer.
We notice that the above bug is triggered *only* after the peer has
dropped one or more arriving packets because of severe memory squeeze,
and that we hence always enter a retransmission situation when this
occurs. This also means that the implementation goes against the
RFC-9293 recommendation that a previously advertised window never
should shrink.
RFC-9293 seems to permit that we can continue sending up to the right
edge of the last advertised non-zero window in such situations, so that
is what we do to resolve this situation.
It turns out that this solution is extremely simple to implememt in the
code: We just omit to save the advertised zero-window when we see that
it has shrunk, i.e., if the acknowledged sequence number in the
advertisement message is lower than that of the last data byte sent
from our side.
When that is the case, the following happens:
- The 'retr' flag in tcp_data_from_tap() will be 'false', so no
retransmission will occur at this occasion.
- The data stream will soon reach the right edge of the previously
advertised window. In fact, in all observed cases we have seen that
it is already there when the zero-advertisement arrives.
- At that moment, the flags STALLED and ACK_FROM_TAP_DUE will be set,
unless they already have been, meaning that only the next timer
expiration will open for data retransmission or transmission.
- When that happens, the memory squeeze at the guest will normally have
abated, and the data flow can resume.
It should be noted that although this solves the problem we have at
hand, it is a work-around, and not a genuine solution to the described
kernel bug.
Suggested-by: Stefano Brivio
On Fri, Jul 12, 2024 at 03:04:50PM -0400, Jon Maloy wrote:
A bug in kernel TCP may lead to a deadlock where a zero window is sent from the guest peer, while it is unable to send out window updates even after socket reads have freed up enough buffer space to permit a larger window. In this situation, new window advertisements from the peer can only be triggered by data packets arriving from this side.
However, currently such packets are never sent, because the zero-window condition prevents this side from sending out any packets whatsoever to the peer.
We notice that the above bug is triggered *only* after the peer has dropped one or more arriving packets because of severe memory squeeze, and that we hence always enter a retransmission situation when this occurs. This also means that the implementation goes against the RFC-9293 recommendation that a previously advertised window never should shrink.
RFC-9293 seems to permit that we can continue sending up to the right edge of the last advertised non-zero window in such situations, so that is what we do to resolve this situation.
It turns out that this solution is extremely simple to implememt in the code: We just omit to save the advertised zero-window when we see that it has shrunk, i.e., if the acknowledged sequence number in the advertisement message is lower than that of the last data byte sent from our side.
When that is the case, the following happens: - The 'retr' flag in tcp_data_from_tap() will be 'false', so no retransmission will occur at this occasion. - The data stream will soon reach the right edge of the previously advertised window. In fact, in all observed cases we have seen that it is already there when the zero-advertisement arrives. - At that moment, the flags STALLED and ACK_FROM_TAP_DUE will be set, unless they already have been, meaning that only the next timer expiration will open for data retransmission or transmission. - When that happens, the memory squeeze at the guest will normally have abated, and the data flow can resume.
It should be noted that although this solves the problem we have at hand, it is a work-around, and not a genuine solution to the described kernel bug.
Suggested-by: Stefano Brivio
Signed-off-by: Jon Maloy
I only half-understand the problem here, but the fix LGTM.
Reviewed-by: David Gibson
On Mon, 15 Jul 2024 10:34:23 +1000
David Gibson
On Fri, Jul 12, 2024 at 03:04:50PM -0400, Jon Maloy wrote:
A bug in kernel TCP may lead to a deadlock where a zero window is sent from the guest peer, while it is unable to send out window updates even after socket reads have freed up enough buffer space to permit a larger window. In this situation, new window advertisements from the peer can only be triggered by data packets arriving from this side.
However, currently such packets are never sent, because the zero-window condition prevents this side from sending out any packets whatsoever to the peer.
We notice that the above bug is triggered *only* after the peer has dropped one or more arriving packets because of severe memory squeeze, and that we hence always enter a retransmission situation when this occurs. This also means that the implementation goes against the RFC-9293 recommendation that a previously advertised window never should shrink.
RFC-9293 seems to permit that we can continue sending up to the right edge of the last advertised non-zero window in such situations, so that is what we do to resolve this situation.
It turns out that this solution is extremely simple to implememt in the code: We just omit to save the advertised zero-window when we see that it has shrunk, i.e., if the acknowledged sequence number in the advertisement message is lower than that of the last data byte sent from our side.
When that is the case, the following happens: - The 'retr' flag in tcp_data_from_tap() will be 'false', so no retransmission will occur at this occasion. - The data stream will soon reach the right edge of the previously advertised window. In fact, in all observed cases we have seen that it is already there when the zero-advertisement arrives. - At that moment, the flags STALLED and ACK_FROM_TAP_DUE will be set, unless they already have been, meaning that only the next timer expiration will open for data retransmission or transmission. - When that happens, the memory squeeze at the guest will normally have abated, and the data flow can resume.
It should be noted that although this solves the problem we have at hand, it is a work-around, and not a genuine solution to the described kernel bug.
Suggested-by: Stefano Brivio
Signed-off-by: Jon Maloy I only half-understand the problem here
Long story short(er): we fill up the socket receive buffer in a Linux guest, completely, complying with the window. At that point, since kernel commit e2142825c120, on memory pressure, we get an ACK segment from the Linux guest *not* acknowledging all the data we sent (a bit less), but reporting zero as window (as if we sent "too much" data, which is not the case). After that, we don't get any further segment at all (second issue introduced by e2142825c120), and whatever pending transfer times out. -- Stefano
On Fri, 12 Jul 2024 15:04:48 -0400
Jon Maloy
We add support for the SO_PEEK_OFF option, plus work around a kernel bug discovered along the way.
Jon Maloy (2): tcp: leverage support of SO_PEEK_OFF socket option when available tcp: handle shrunk window advertisemenst from guest
tcp.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- tcp.h | 3 +++ tcp_buf.c | 25 ++++++++++++++++------ 3 files changed, 81 insertions(+), 9 deletions(-)
Thanks, it looks good to me now! I'll wait for David's review before applying it. -- Stefano
On Fri, 12 Jul 2024 15:04:48 -0400
Jon Maloy
We add support for the SO_PEEK_OFF option, plus work around a kernel bug discovered along the way.
Jon Maloy (2): tcp: leverage support of SO_PEEK_OFF socket option when available tcp: handle shrunk window advertisemenst from guest
tcp.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- tcp.h | 3 +++ tcp_buf.c | 25 ++++++++++++++++------ 3 files changed, 81 insertions(+), 9 deletions(-)
Applied! I just s/advertisemenst/advertisements/ in 2/2, and fixed up the SHA of the buggy kernel commit... I guess d4317abf7160 is from your local tree? Upstream has e2142825c120. -- Stefano
On 2024-07-15 12:58, Stefano Brivio wrote:
On Fri, 12 Jul 2024 15:04:48 -0400 Jon Maloy
wrote: We add support for the SO_PEEK_OFF option, plus work around a kernel bug discovered along the way.
Jon Maloy (2): tcp: leverage support of SO_PEEK_OFF socket option when available tcp: handle shrunk window advertisemenst from guest
tcp.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- tcp.h | 3 +++ tcp_buf.c | 25 ++++++++++++++++------ 3 files changed, 81 insertions(+), 9 deletions(-) Applied! Great! Finally. Thanks!
I just s/advertisemenst/advertisements/ in 2/2, and fixed up the SHA of the buggy kernel commit... I guess d4317abf7160 is from your local tree? I use net-next by old habit, and don't update it often. Maybe I should change that. Upstream has e2142825c120.
///jon
participants (3)
-
David Gibson
-
Jon Maloy
-
Stefano Brivio