diff options
author | Stefano Brivio <sbrivio@redhat.com> | 2023-03-23 16:07:57 +0100 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2023-03-29 13:47:17 +0200 |
commit | 33d88f79d920699be5162e1f5d6901da0c02b005 (patch) | |
tree | 7ffffbab76b25ae4a563a30a5db9ab039b8934ad /tcp.c | |
parent | 4e73e9bd655c8ebb3e253284f51d4349eea1cc5c (diff) | |
download | passt-33d88f79d920699be5162e1f5d6901da0c02b005.tar passt-33d88f79d920699be5162e1f5d6901da0c02b005.tar.gz passt-33d88f79d920699be5162e1f5d6901da0c02b005.tar.bz2 passt-33d88f79d920699be5162e1f5d6901da0c02b005.tar.lz passt-33d88f79d920699be5162e1f5d6901da0c02b005.tar.xz passt-33d88f79d920699be5162e1f5d6901da0c02b005.tar.zst passt-33d88f79d920699be5162e1f5d6901da0c02b005.zip |
tcp: Clear ACK_FROM_TAP_DUE also on unchanged ACK sequence from peer
Since commit cc6d8286d104 ("tcp: Reset ACK_FROM_TAP_DUE flag only as
needed, update timer"), we don't clear ACK_FROM_TAP_DUE whenever we
process an ACK segment, but, more correctly, only if we're really not
waiting for a further ACK segment, that is, only if the acknowledged
sequence matches what we sent.
In the new function implementing this, tcp_update_seqack_from_tap(),
we also reset the retransmission counter and store the updated ACK
sequence. Both should be done iff forward progress is acknowledged,
implied by the fact that the new ACK sequence is greater than the
one we previously stored.
At that point, it looked natural to also include the statements that
clear and set the ACK_FROM_TAP_DUE flag inside the same conditional
block: if we're not making forward progress, the need for an ACK, or
lack thereof, should remain unchanged.
There might be cases where this isn't true, though: without the
previous commit 4e73e9bd655c ("tcp: Don't special case the handling
of the ack of a syn"), this would happen if a tap-side client
initiated a connection, and the server didn't send any data.
At that point we would never, in the established state of the
connection, call tcp_update_seqack_from_tap() with reported forward
progress.
That issue itself is fixed by the previous commit, now, but clearing
ACK_FROM_TAP_DUE only on ACK sequence progress doesn't really follow
any logic.
Clear the ACK_FROM_TAP_DUE flag regardless of reported forward
progress. If we clear it when it's already unset, conn_flag() will do
nothing with it.
This doesn't fix any known functional issue, rather a conceptual one.
Fixes: cc6d8286d104 ("tcp: Reset ACK_FROM_TAP_DUE flag only as needed, update timer")
Reported-by: David Gibson <david@gibson.dropbear.id.au>
Analysed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Diffstat (limited to 'tcp.c')
-rw-r--r-- | tcp.c | 8 |
1 files changed, 5 insertions, 3 deletions
@@ -1610,10 +1610,12 @@ out: static void tcp_update_seqack_from_tap(const struct ctx *c, struct tcp_tap_conn *conn, uint32_t seq) { + if (seq == conn->seq_to_tap) + conn_flag(c, conn, ~ACK_FROM_TAP_DUE); + if (SEQ_GT(seq, conn->seq_ack_from_tap)) { - if (seq == conn->seq_to_tap) - conn_flag(c, conn, ~ACK_FROM_TAP_DUE); - else + /* Forward progress, but more data to acknowledge: reschedule */ + if (SEQ_LT(seq, conn->seq_to_tap)) conn_flag(c, conn, ACK_FROM_TAP_DUE); conn->retrans = 0; |