http: h2 flow control improvement 64/43464/3
authorMatus Fabian <[email protected]>
Mon, 21 Jul 2025 12:10:36 +0000 (08:10 -0400)
committerFlorin Coras <[email protected]>
Sat, 26 Jul 2025 03:13:59 +0000 (03:13 +0000)
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 <[email protected]>
extras/hs-test/h2spec_extras/h2spec_extras.go
src/plugins/http/http2/http2.c
src/plugins/http/http_private.h

index a48cdac..b2c5c85 100644 (file)
@@ -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
                        }
index 77a9c66..52147b8 100644 (file)
@@ -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);
index 51fdfd6..b6a63b9 100644 (file)
@@ -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