From a1f26ca3078a51f289727d7ad1ffc23fe33f5b49 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 29 Oct 2025 17:38:07 +0100 Subject: [PATCH] BUG/MINOR: mux-h2: send the preface along with the first request if needed Tests involving 0-RTT and H2 on the backend show that 0-RTT is being partially used but does not work. The analysis shows that only the preface and settings are sent using early-data and the request is sent separately. As explained in the previous patch, this is caused by the fact that a wakeup of the iocb is needed just to send the preface, then a new call to process_stream is needed to try sending again. Here with this patch, we're making h2_snd_buf() able to send the preface if it was not yet sent. Thanks to this, the preface, settings and first request can now leave as a single TCP segment. In case of TLS with 0-RTT, it now allows all the block to leave in early data. Even in clear-text H2, we're now seeing a 15% lower context-switch count, and the number of calls to process_stream() per connection dropped from 3 to 2. The connection rate increased by an extra 9.5%. Compared to without the last 3 patches, this is a 22% reduction of context-switches, 33% reduction of process_stream() calls, and 15.7% increase in connection rate. And more importantly, 0-RTT now really works with H2 on the backend, saving one full RTT on the first request. This fix is only for a missed optimization and a non-functional 0-RTT on the backend. It's worth backporting it, but it doesn't cause enough harm to hurry a backport. Better wait for it to live a little bit in 3.3 (till at least a week or two after the final release) before backporting it. It's not sure that it's worth going beyond 3.2 in any case. It depends on the these two previous commits: MEDIUM: mux-h2: do not needlessly refrain from sending data early MINOR: mux-h2: extract the code to send preface+settings into its own function --- src/mux_h2.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/mux_h2.c b/src/mux_h2.c index 03937dc33..a5232d0ca 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -7867,6 +7867,16 @@ static size_t h2_snd_buf(struct stconn *sc, struct buffer *buf, size_t count, in } h2s->flags &= ~H2_SF_NOTIFIED; + if (unlikely(h2s->h2c->st0 < H2_CS_SETTINGS1 && (h2s->h2c->flags & H2_CF_IS_BACK))) { + /* The preface and settings were not sent yet. Let's just push + * them now instead of doing a wakeup dance. This function will + * possibly do nothing, or update the state to H2_CS_SETTINGS1 + * on success, or H2_CS_ERROR* on error. Let's merge this path + * with the common checks below. + */ + h2c_bck_send_preface_and_settings(h2s->h2c); + } + if (h2s->h2c->st0 < ((h2s->h2c->flags & H2_CF_SETTINGS_NEEDED) ? H2_CS_FRAME_H : H2_CS_SETTINGS1)) { TRACE_DEVEL("connection not ready, leaving", H2_EV_H2S_SEND|H2_EV_H2S_BLK, h2s->h2c->conn, h2s); return 0; -- 2.47.3