From: Stefano Brivio <sbrivio@redhat.com>
To: David Gibson <david@gibson.dropbear.id.au>
Cc: passt-dev@passt.top
Subject: Re: [PATCH 4/5] tcp: Avoid SEQ_*() comparisons against 0
Date: Wed, 17 Jun 2026 01:08:38 +0200 (CEST) [thread overview]
Message-ID: <20260617010837.41032877@elisabeth> (raw)
In-Reply-To: <20260615081833.1061725-5-david@gibson.dropbear.id.au>
On Mon, 15 Jun 2026 18:18:32 +1000
David Gibson <david@gibson.dropbear.id.au> wrote:
> Usually we use the SEQ_{LT,LE,GT,GE}() comparison macros on raw sequence
> numbers, to see how they related handling possible wraparounds. However,
> in two cases we take a difference of sequence numbers then compare that
> difference to 0.
>
> As long as the difference is done using wrapping unsigned arithmetic,
> that's not incorrect. It's essentially doing comparisons in a "shifted"
> space of sequence numbers, and I find working in both the raw and shifted
> spaces makes it harder to reason about. Specifically I sometimes find I
> have to go through an additional layer of logic to convince myself that the
> wraparound handling is correct.
>
> In addition to confusing me, it also tends to confuse cppcheck, at least in
> cppcheck 2.21.0 it often seems to trip false positives via cppcheck bug
> 14848.
>
> It turns out that in each of the cases we use comparisons of sequence
> differences against 0, it's pretty much just as clear - maybe clearer to
> perform the comparisons against raw sequence numbers. We still need the
> difference afterwards, but it's much more obvious that it means what we
> need it do, if we've already eliminated cases where the sequence numbers
> aren't in the expected order.
>
> In the case in tcp_data_from_tap() this also lets us simplify the diagram
> explanation of the different cases a bit. While there we correct the
> diagram in the second discard case: seq was shown as partway into the
> packet, which is not true by definition. Instead seq_from_tap should be
> some distance after the end of the packet.
I have to admit I missed this paragraph and spent a disproportionate
amount of time trying to figure out why you would change that. Oops.
Good catch.
> Link: https://trac.cppcheck.net/ticket/14848
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> tcp.c | 28 ++++++++++++----------------
> 1 file changed, 12 insertions(+), 16 deletions(-)
>
> diff --git a/tcp.c b/tcp.c
> index dcadc765..edcabe27 100644
> --- a/tcp.c
> +++ b/tcp.c
> @@ -1840,21 +1840,20 @@ static int tcp_data_from_sock(const struct ctx *c, struct tcp_tap_conn *conn)
> uint32_t wnd_scaled = conn->wnd_from_tap << conn->ws_from_tap;
> uint32_t already_sent;
>
> - /* How much have we read/sent since last received ack ? */
> - already_sent = conn->seq_to_tap - conn->seq_ack_from_tap;
> -
> - if (SEQ_LT(already_sent, 0)) {
> + if (SEQ_LT(conn->seq_to_tap, conn->seq_ack_from_tap)) {
> /* RFC 761, section 2.1. */
> flow_trace(conn, "ACK sequence gap: ACK for %u, sent: %u",
> conn->seq_ack_from_tap, conn->seq_to_tap);
> conn->seq_to_tap = conn->seq_ack_from_tap;
> - already_sent = 0;
> if (tcp_set_peek_offset(conn, 0)) {
> tcp_rst(c, conn);
> return -1;
> }
> }
>
> + /* How much have we read/sent since last received ack ? */
> + already_sent = conn->seq_to_tap - conn->seq_ack_from_tap;
> +
> if (!wnd_scaled || already_sent >= wnd_scaled) {
> conn_flag(c, conn, ACK_FROM_TAP_BLOCKS);
> conn_flag(c, conn, STALLED);
> @@ -1997,37 +1996,34 @@ static int tcp_data_from_tap(const struct ctx *c, struct tcp_tap_conn *conn,
> if (!len)
> continue;
>
> - seq_offset = seq_from_tap - seq;
> /* Use data from this buffer only in these two cases:
> *
> * , seq_from_tap , seq_from_tap
> * |--------| <-- len |--------| <-- len
> - * '----' <-- offset ' <-- offset
> * ^ seq ^ seq
> - * (offset >= 0, seq + len > seq_from_tap)
> + * (seq_from_tap >= seq, seq + len > seq_from_tap)
> *
> * discard in these two cases:
> - * , seq_from_tap , seq_from_tap
> + * , seq_from_tap , seq_from_tap
> * |--------| <-- len |--------| <-- len
> - * '--------' <-- offset '-----| <- offset
> - * ^ seq ^ seq
> - * (offset >= 0, seq + len <= seq_from_tap)
> + * ^ seq ^ seq
> + * (seq_from_tap >= seq, seq + len <= seq_from_tap)
> *
> * keep, look for another buffer, then go back, in this case:
> * , seq_from_tap
> * |--------| <-- len
> - * '===' <-- offset
> * ^ seq
> - * (offset < 0)
> + * (seq_from_tap < seq)
> */
> - if (SEQ_GE(seq_offset, 0) && SEQ_LE(seq + len, seq_from_tap))
> + if (SEQ_GE(seq_from_tap, seq) && SEQ_LE(seq + len, seq_from_tap))
> continue;
>
> - if (SEQ_LT(seq_offset, 0)) {
> + if (SEQ_LT(seq_from_tap, seq)) {
> if (keep == -1)
> keep = i;
> continue;
> }
> + seq_offset = seq_from_tap - seq;
>
> iov_drop_header(&data, seq_offset);
> size = len - seq_offset;
--
Stefano
next prev parent reply other threads:[~2026-06-16 23:08 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-15 8:18 [PATCH 0/5] Fix cppcheck-2.21.0 warnings David Gibson
2026-06-15 8:18 ` [PATCH 1/5] cppcheck: Remove unused CPPCHECK_6936 David Gibson
2026-06-15 8:18 ` [PATCH 2/5] cppcheck: Add workaround for cppcheck bug 14847 David Gibson
2026-06-15 8:18 ` [PATCH 3/5] tcp: Merge common sequence logic from tcp_{buf,vu}_data_from_sock() David Gibson
2026-06-15 8:50 ` Laurent Vivier
2026-06-15 8:18 ` [PATCH 4/5] tcp: Avoid SEQ_*() comparisons against 0 David Gibson
2026-06-16 23:08 ` Stefano Brivio [this message]
2026-06-15 8:18 ` [PATCH 5/5] tcp: MAX_WINDOW should be unsigned David Gibson
2026-06-16 23:11 ` [PATCH 0/5] Fix cppcheck-2.21.0 warnings Stefano Brivio
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260617010837.41032877@elisabeth \
--to=sbrivio@redhat.com \
--cc=david@gibson.dropbear.id.au \
--cc=passt-dev@passt.top \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://passt.top/passt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).