public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: Stefano Brivio <sbrivio@redhat.com>
To: David Gibson <david@gibson.dropbear.id.au>
Cc: Yumei Huang <yuhuang@redhat.com>, passt-dev@passt.top
Subject: Re: [PATCH v7 4/5] tcp: Update data retransmission timeout
Date: Tue, 4 Nov 2025 05:42:25 +0100	[thread overview]
Message-ID: <20251104054225.2b2a5a8c@elisabeth> (raw)
In-Reply-To: <aQh2nmphZVw_XeE9@zatzit>

On Mon, 3 Nov 2025 20:32:14 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:

> On Mon, Nov 03, 2025 at 10:57:27AM +0800, Yumei Huang wrote:
> > On Mon, Nov 3, 2025 at 9:38 AM David Gibson <david@gibson.dropbear.id.au> wrote:  
> > >
> > > On Fri, Oct 31, 2025 at 01:42:41PM +0800, Yumei Huang wrote:  
> > > > Use an exponential backoff timeout for data retransmission according
> > > > to RFC 2988 and RFC 6298. Set the initial RTO to one second as discussed
> > > > in Appendix A of RFC 6298.
> > > >
> > > > Also combine the macros defining the initial RTO for both SYN and ACK.
> > > >
> > > > Signed-off-by: Yumei Huang <yuhuang@redhat.com>
> > > > Reviewed-by: David Gibson <david@gibson.dropbear.id.au>  
> > >
> > > As reported, the carried over R-b was a minor mistake, since the code
> > > has changed, but here's a new one:
> > >
> > > Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> > >
> > > Small comment below, though.
> > >  
> > > > ---
> > > >  tcp.c | 30 ++++++++++++------------------
> > > >  1 file changed, 12 insertions(+), 18 deletions(-)
> > > >
> > > > diff --git a/tcp.c b/tcp.c
> > > > index bada88a..96ee56a 100644
> > > > --- a/tcp.c
> > > > +++ b/tcp.c
> > > > @@ -179,16 +179,13 @@
> > > >   *
> > > >   * Timeouts are implemented by means of timerfd timers, set based on flags:
> > > >   *
> > > > - * - SYN_TIMEOUT_INIT: if no ACK is received from tap/guest during handshake
> > > > - *   (flag ACK_FROM_TAP_DUE without ESTABLISHED event) within this time, resend
> > > > - *   SYN. It's the starting timeout for the first SYN retry. Retry for
> > > > - *   TCP_MAX_RETRIES or (tcp_syn_retries + tcp_syn_linear_timeouts) times,
> > > > - *   reset the connection
> > > > - *
> > > > - * - ACK_TIMEOUT: if no ACK segment was received from tap/guest, after sending
> > > > - *   data (flag ACK_FROM_TAP_DUE with ESTABLISHED event), re-send data from the
> > > > - *   socket and reset sequence to what was acknowledged. If this persists for
> > > > - *   more than TCP_MAX_RETRIES times in a row, reset the connection
> > > > + * - RTO_INIT: if no ACK segment was received from tap/guest, either during
> > > > + *   handshake (flag ACK_FROM_TAP_DUE without ESTABLISHED event) or after
> > > > + *   sending data (flag ACK_FROM_TAP_DUE with ESTABLISHED event), re-send data
> > > > + *   from the socket and reset sequence to what was acknowledged. This is the
> > > > + *   timeout for the first retry, in seconds. Retry for TCP_MAX_RETRIES times
> > > > + *   for established connections, or (tcp_syn_retries +
> > > > + *   tcp_syn_linear_timeouts) times during the handshake, reset the connection
> > > >   *
> > > >   * - FIN_TIMEOUT: if a FIN segment was sent to tap/guest (flag ACK_FROM_TAP_DUE
> > > >   *   with TAP_FIN_SENT event), and no ACK is received within this time, reset
> > > > @@ -342,8 +339,7 @@ enum {
> > > >  #define WINDOW_DEFAULT                       14600           /* RFC 6928 */
> > > >
> > > >  #define ACK_INTERVAL                 10              /* ms */
> > > > -#define SYN_TIMEOUT_INIT             1               /* s, RFC 6928 */
> > > > -#define ACK_TIMEOUT                  2
> > > > +#define RTO_INIT                     1               /* s, RFC 6298 */
> > > >  #define FIN_TIMEOUT                  60
> > > >  #define ACT_TIMEOUT                  7200
> > > >
> > > > @@ -589,12 +585,10 @@ static void tcp_timer_ctl(const struct ctx *c, struct tcp_tap_conn *conn)
> > > >       if (conn->flags & ACK_TO_TAP_DUE) {
> > > >               it.it_value.tv_nsec = (long)ACK_INTERVAL * 1000 * 1000;
> > > >       } else if (conn->flags & ACK_FROM_TAP_DUE) {
> > > > -             if (!(conn->events & ESTABLISHED)) {
> > > > -                     int exp = conn->retries - c->tcp.syn_linear_timeouts;  
> > >
> > > I didn't spot it in the previous patch, but this is (theoretically)
> > > buggy.  conn->retries is unsigned, so the subtraction will be
> > > performed unsigned and only then cast to signed.  I think that will
> > > probably do the right thing in practice, but I don't think that's
> > > guaranteed by the C standard (and might even be UB).  
> > 
> > I'm not sure, but I just googled it. IIUC, the uint8_t (conn->retries
> > and c->tcp.syn_linear_timeouts) will go through integer promotion
> > before subtraction. So the line is like:
> > 
> >     int exp = (int) conn->retries - (int) c->tcp.syn_linear_timeouts;
> > 
> > Please correct me if I'm wrong.  
> 
> Huh, I thought it would only be promoted if one of the operands was an
> int.

I thought and I think so too, yes.

> But C promotion rules are really confusing, so I could well be wrong.

Some references linked at:

  https://archives.passt.top/passt-dev/20240103080834.24fa0a7a@elisabeth/

and here, it's about paragraph 6.3.1.8, "Usual arithmetic conversions"
of C11 (that's what passt uses right now).

No double or float here, so this is the relevant text:

    Otherwise, the integer promotions are performed on both operands.
    Then the following rules are applied to the promoted operands:

        If both operands have the same type, then no further conversion
        is needed

now, are they really the same type? The standard doesn't define uint8_t.
If we see it as an unsigned int, with storage limited to 8 bits, then I
would call them the same type.

If we see c->tcp.syn_linear_timeouts as a character type instead
(6.3.1.1, "Boolean, characters, and integers"), then the integer
conversion rank of unsigned int (conn->retries) is greater than the rank
of char, and the same text applies (promotion of char to unsigned int).

But I'm fairly sure that's not the case. We used uint8_t, not short,
and not char.

All in all I don't think there's any possibility of promotion to a
signed int: for that, you would need one of the operands to be signed.
Or two unsigned chars/shorts (see examples below).

If the operation is performed unsigned, and that's what gcc appears to
do here, promoting both operands to unsigned int (32-bit):

---
$ cat pro_uh_oh_motion.c
#include <stdio.h>
#include <stdint.h>

int main()
{
	uint8_t a = 0;
	struct { unsigned b:3; } x = { 7 };

	printf("%u %i\n", a - x.b, a - x.b);
}
$ gcc -o pro_uh_oh_motion{,.c}
$ ./pro_uh_oh_motion
4294967289 -7
---

...do we really have a problem with that? To me it looks like the
behaviour is defined, and it's what we want.

These pages:

  https://wiki.sei.cmu.edu/confluence/display/c/INT02-C.+Understand+integer+conversion+rules
  https://wiki.sei.cmu.edu/confluence/display/c/EXP14-C.+Beware+of+integer+promotion+when+performing+bitwise+operations+on+integer+types+smaller+than+int

show some problematic examples. This one is close to our case:

  unsigned short x = 45000, y = 50000;
  unsigned int z = x * y;

but there we have implicit promotion of the unsigned shorts to
int, which doesn't happen in our case, because we already have an
unsigned int.

See also the examples with two unsigned shorts from:

  https://cryptoservices.github.io/fde/2018/11/30/undefined-behavior.html

and there the operation would be performed as signed int.

On top of that, you have the fact that the original types can't store
the result of the operation. Here it's not the case.

-- 
Stefano


  reply	other threads:[~2025-11-04  4:42 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-31  5:42 [PATCH v7 0/5] Retry SYNs for inbound connections Yumei Huang
2025-10-31  5:42 ` [PATCH v7 1/5] tcp: Rename "retrans" to "retries" Yumei Huang
2025-10-31  5:42 ` [PATCH v7 2/5] util: Introduce read_file() and read_file_integer() function Yumei Huang
2025-11-03  0:53   ` David Gibson
2025-10-31  5:42 ` [PATCH v7 3/5] tcp: Resend SYN for inbound connections Yumei Huang
2025-11-03  1:09   ` David Gibson
2025-11-03  2:31     ` Yumei Huang
2025-11-03  9:01       ` David Gibson
2025-11-04  4:42         ` Stefano Brivio
2025-11-04  4:42   ` Stefano Brivio
2025-11-05  4:24     ` David Gibson
2025-11-05  7:00       ` Stefano Brivio
2025-11-07  9:56         ` Yumei Huang
2025-11-07 10:05           ` Stefano Brivio
2025-11-10  2:52             ` Yumei Huang
2025-11-10  4:25               ` David Gibson
2025-10-31  5:42 ` [PATCH v7 4/5] tcp: Update data retransmission timeout Yumei Huang
2025-10-31  5:56   ` Yumei Huang
2025-10-31  8:04     ` Stefano Brivio
2025-11-03  1:18   ` David Gibson
2025-11-03  2:57     ` Yumei Huang
2025-11-03  9:32       ` David Gibson
2025-11-04  4:42         ` Stefano Brivio [this message]
2025-11-05  4:19           ` David Gibson
2025-10-31  5:42 ` [PATCH v7 5/5] tcp: Clamp the retry timeout Yumei Huang
2025-10-31  8:38   ` Stefano Brivio
2025-11-03  3:11     ` Yumei Huang
2025-11-03  9:37       ` David Gibson
2025-11-03 10:55       ` Stefano Brivio
2025-11-03  1:37   ` David Gibson
2025-11-03  4:06     ` Yumei Huang
2025-11-03 10:38     ` Stefano Brivio
2025-11-05  4:22       ` David Gibson
2025-11-04  4:42   ` 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=20251104054225.2b2a5a8c@elisabeth \
    --to=sbrivio@redhat.com \
    --cc=david@gibson.dropbear.id.au \
    --cc=passt-dev@passt.top \
    --cc=yuhuang@redhat.com \
    /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).