From 1a131df02fd038ab88e77399379dedae0e63e2d2 Mon Sep 17 00:00:00 2001 From: Matus Fabian Date: Mon, 21 Jul 2025 08:10:36 -0400 Subject: [PATCH] http: h2 flow control improvement resereve half of the app fifo size for headers to avoid full fifo when first data frame is received Type: improvement Change-Id: I366b9a5495b3b6303125260b340b600fd212be58 Signed-off-by: Matus Fabian --- extras/hs-test/h2spec_extras/h2spec_extras.go | 3 ++- src/plugins/http/http2/http2.c | 10 ++++++++-- src/plugins/http/http_private.h | 7 +++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/extras/hs-test/h2spec_extras/h2spec_extras.go b/extras/hs-test/h2spec_extras/h2spec_extras.go index a48cdac137a..b2c5c85fb63 100644 --- a/extras/hs-test/h2spec_extras/h2spec_extras.go +++ b/extras/hs-test/h2spec_extras/h2spec_extras.go @@ -186,8 +186,9 @@ func FlowControl() *spec.TestGroup { } conn.WriteHeaders(hp) // we send window update on stream when app read data from rx fifo, so send DATA frame and wait for WINDOW_UPDATE frame + // first increment is bigger because half of the fifo size was reserved for headers conn.WriteData(streamID, false, []byte("AAAA")) - err = VerifyWindowUpdate(conn, streamID, 4) + err = VerifyWindowUpdate(conn, streamID, 4+conn.Settings[http2.SettingMaxHeaderListSize]) if err != nil { return err } diff --git a/src/plugins/http/http2/http2.c b/src/plugins/http/http2/http2.c index 77a9c661a24..52147b8a1e9 100644 --- a/src/plugins/http/http2/http2.c +++ b/src/plugins/http/http2/http2.c @@ -159,8 +159,11 @@ http2_conn_ctx_alloc_w_thread (http_conn_t *hc) h2c->our_window = HTTP2_CONNECTION_WINDOW_SIZE; h2c->settings = h2m->settings; /* adjust settings according to app rx_fifo size */ + h2c->settings.max_header_list_size = + clib_min (h2c->settings.max_header_list_size, (hc->app_rx_fifo_size >> 1)); h2c->settings.initial_window_size = - clib_min (h2c->settings.initial_window_size, hc->app_rx_fifo_size); + clib_min (h2c->settings.initial_window_size, + (hc->app_rx_fifo_size - h2c->settings.max_header_list_size)); h2c->req_by_stream_id = hash_create (0, sizeof (uword)); h2c->new_tx_streams = clib_llist_make_head (wrk->req_pool, sched_list); h2c->old_tx_streams = clib_llist_make_head (wrk->req_pool, sched_list); @@ -478,7 +481,10 @@ http2_stream_error (http_conn_t *hc, http2_req_t *req, http2_error_t error, if (req->flags & HTTP2_REQ_F_APP_CLOSED) session_transport_closed_notify (&req->base.connection); else - session_transport_closing_notify (&req->base.connection); + { + http_io_as_drain_unread (&req->base); + session_transport_closing_notify (&req->base.connection); + } h2c = http2_conn_ctx_get_w_thread (hc); session_transport_delete_notify (&req->base.connection); diff --git a/src/plugins/http/http_private.h b/src/plugins/http/http_private.h index 51fdfd65d32..b6a63b9711f 100644 --- a/src/plugins/http/http_private.h +++ b/src/plugins/http/http_private.h @@ -651,6 +651,13 @@ http_io_as_drain_all (http_req_t *req) req->as_fifo_offset = 0; } +always_inline void +http_io_as_drain_unread (http_req_t *req) +{ + session_t *as = session_get_from_handle (req->hr_pa_session_handle); + svm_fifo_dequeue_drop_all (as->rx_fifo); +} + /* Abstraction of transport session fifo operations */ always_inline u32 -- 2.16.6