-
Notifications
You must be signed in to change notification settings - Fork 103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Flow contol and pull-model for message forwarding #1394
Comments
References #488 in HTTP/2 flow control. #498 also discusses HTTP/2 flow control. Also read (from https://h3.edm.uhasselt.be/):
At some point we'll have QUIC and HTTP/3, which share some mechanisms with HTTP/2, so it's good to have #724 in mind during the implementation to probably reuse some code for HTTP/3 |
from #1641 (probably we should use this as a test case) . See https://httpwg.org/specs/rfc9113.html#n-the-flow-control-window FLOW_CONTROL_ERROR appears when client sends multiple requests in one connection. It can be reproduced in Chromium and nghttp2. file.html example:
All images must present. Image Also same error appear if we use large amount of images in one page. For example we can place into file.html 30 images and nghttp will sent File with large amount of images:
Chromium: In this case we can use mixed approach: file.html must contain many(30+) images with first large image. Request to largest image will be failed. |
Test to reproduce: |
This task must also solve #391 point 1 and somewhat #687 in that we must switch to pulling mode. See also slide 18 on https://www.slideshare.net/kazuho/reorganizing-website-architecture-for-http2-and-beyond . All data should be just sent to a TCP socket with When a client's Since at the moment Tempesta FW works in buffering mode only, we'll send response data in chunks and we do need to track where is the current pointer for transmission. With #498 we'll need to deal with partially build HTTP responses, so I think we should keep the transmission pointer in It seems Please, during the development keep in mind (maybe write necessary zero-logic functions and/or TODOs)
We should also not to fetch a full response body from the cache can call the TDB routines for the next data chunk also by an upcall from TCP -> TLS -> HTTP framing. It's TBD and maybe subject for #498 or just a point for another pull request. |
Please enable http2_general.test_flow_control_window tests after fixes. And also h2spec tests. |
Since we decide to move frame making into `xmit` callback, we need to save stream id in skb private area. In `xmit` callback we use this id to find appropriate stream. Part of #1394
Since we decide to move frame making into `xmit` callback, we need to save stream id in skb private area. In `xmit` callback we use this id to find appropriate stream. Part of #1394
Since we decide to move frame making into `xmit` callback, we need to save stream id in skb private area. In `xmit` callback we use this id to find appropriate stream. Part of #1394
Since we decide to move frame making into `xmit` callback, we need to save stream id in skb private area. In `xmit` callback we use this id to find appropriate stream. Part of #1394
Since we decide to move frame making into `xmit` callback, we need to save stream id in skb private area and mark skb as skb, which contains headers or data frame. In `xmit` callback we use this id to find appropriate stream and use information of skb type to add appropriate frame header (HEADERS/DATA). Part of #1394
Adding of frame header can leades to allocation of a new skb, which header should be filled correctly. For this purposes we copy some static inline functions from `tcp_output.c` to our code. Part of #1394
Adding of frame header can leades to allocation of a new skb, which header should be filled correctly. For this purposes we copy some static inline functions from `tcp_output.c` to our code. Part of #1394
Previously, when we forward response, we put appropriate stream into `hclosed_streams` queue and if count of such streams become greater then TFW_MAX_CLOSED_STREAMS we delete streams from this queue. But now we should not delete such streams, because they can used in `xmit` callback, that's why we implement additional queue for such streams. Now when we forward response, we put appropriate stream into `pending_hcl_streams` queue and then when all response data will be sent, we move this stream to `hclosed_streams` queue for further deleting. Part of #1394
Since we know current tcp limit only in `xmit` callback, we move htt2 framing into this function to make frames with optimal size. Part of #1394
Previously, when we forward response, we put appropriate stream into `hclosed_streams` queue and if count of such streams become greater then TFW_MAX_CLOSED_STREAMS we delete streams from this queue. But now we should not delete such streams, because they can used in `xmit` callback, that's why we implement additional queue for streams. Now when we forward response, we put appropriate stream into `hclosed_streams` queue and then when all response data will be sent, we move this stream to `closed_streams` queue for further deleting. Part of #1394
Since we decide to move frame making into `xmit` callback, we need to save stream id in skb private area and mark skb as skb, which contains headers or data frame. In `xmit` callback we use this id to find appropriate stream and use information of skb type to add appropriate frame header (HEADERS/DATA). Part of #1394
Since we know current tcp limit only in `xmit` callback, we move htt2 framing into this function to make frames with optimal size. Part of #1394
Previously, when we forward response, we put appropriate stream into `hclosed_streams` queue and if count of such streams become greater then TFW_MAX_CLOSED_STREAMS we delete streams from this queue. But now we should not delete such streams, because they can used in `xmit` callback, that's why we implement additional queue for streams. Now when we forward response, we put appropriate stream into `hclosed_streams` queue and then when all response data will be sent, we move this stream to `closed_streams` queue for further deleting. Part of #1394
Since we decide to move frame making into `xmit` callback, we need to save stream id in skb private area and mark skb as skb, which contains headers or data frame. In `xmit` callback we use this id to find appropriate stream and use information of skb type to add appropriate frame header (HEADERS/DATA). Part of #1394
Since we know current tcp limit only in `xmit` callback, we move htt2 framing into this function to make frames with optimal size. Part of #1394
Previously, when we forward response, we put appropriate stream into `hclosed_streams` queue and if count of such streams become greater then TFW_MAX_CLOSED_STREAMS we delete streams from this queue. But now we should not delete such streams, because they can used in `xmit` callback, that's why we implement additional queue for streams. Now when we forward response, we put appropriate stream into `hclosed_streams` queue and then when all response data will be sent, we move this stream to `closed_streams` queue for further deleting. Part of #1394
Previously, when we forward response, we put appropriate stream into `hclosed_streams` queue and if count of such streams become greater then TFW_MAX_CLOSED_STREAMS we delete streams from this queue. But now we should not delete such streams, because they can used in `xmit` callback, that's why we implement additional queue for streams. Now when we forward response, we put appropriate stream into `hclosed_streams` queue and then when all response data will be sent, we move this stream to `closed_streams` queue for further deleting. Part of #1394
Since we decide to move frame making into `xmit` callback, we need to save stream id in skb private area and mark skb as skb, which contains headers or data frame. In `xmit` callback we use this id to find appropriate stream and use information of skb type to add appropriate frame header (HEADERS/DATA). Part of #1394
Since we know current tcp limit only in `xmit` callback, we move htt2 framing into this function to make frames with optimal size. Part of #1394
Previously, when we forward response, we put appropriate stream into `hclosed_streams` queue and if count of such streams become greater then TFW_MAX_CLOSED_STREAMS we delete streams from this queue. But now we should not delete such streams, because they can used in `xmit` callback, that's why we implement additional queue for streams. Now when we forward response, we put appropriate stream into `hclosed_streams` queue and then when all response data will be sent, we move this stream to `closed_streams` queue for further deleting. Part of #1394
Since we decide to move frame making into `xmit` callback, we need to save stream id in skb private area and mark skb as skb, which contains headers or data frame. In `xmit` callback we use this id to find appropriate stream and use information of skb type to add appropriate frame header (HEADERS/DATA). Part of #1394
Since we know current tcp limit only in `xmit` callback, we move htt2 framing into this function to make frames with optimal size. Part of #1394
Previously, when we forward response, we put appropriate stream into `hclosed_streams` queue and if count of such streams become greater then TFW_MAX_CLOSED_STREAMS we delete streams from this queue. But now we should not delete such streams, because they can used in `xmit` callback, that's why we implement additional queue for streams. Now when we forward response, we put appropriate stream into `hclosed_streams` queue and then when all response data will be sent, we move this stream to `closed_streams` queue for further deleting. Part of #1394
Since we decide to move frame making into `xmit` callback, we need to save stream id in skb private area and mark skb as skb, which contains headers or data frame. In `xmit` callback we use this id to find appropriate stream and use information of skb type to add appropriate frame header (HEADERS/DATA). Part of #1394
Since we know current tcp limit only in `xmit` callback, we move htt2 framing into this function to make frames with optimal size. Part of #1394
Previously, when we forward response, we put appropriate stream into `hclosed_streams` queue and if count of such streams become greater then TFW_MAX_CLOSED_STREAMS we delete streams from this queue. But now we should not delete such streams, because they can used in `xmit` callback, that's why we implement additional queue for streams. Now when we forward response, we put appropriate stream into `hclosed_streams` queue and then when all response data will be sent, we move this stream to `closed_streams` queue for further deleting. Part of #1394
Since we know current tcp limit only in `xmit` callback, we move htt2 framing into this function to make frames with optimal size. Part of #1394
Previously, when we forward response, we put appropriate stream into `hclosed_streams` queue and if count of such streams become greater then TFW_MAX_CLOSED_STREAMS we delete streams from this queue. But now we should not delete such streams, because they can used in `xmit` callback, that's why we implement additional queue for streams. Now when we forward response, we put appropriate stream into `hclosed_streams` queue and then when all response data will be sent, we move this stream to `closed_streams` queue for further deleting. Part of #1394
Since we know current tcp limit only in `xmit` callback, we move htt2 framing into this function to make frames with optimal size. Part of #1394
Previously, when we forward response, we put appropriate stream into `hclosed_streams` queue and if count of such streams become greater then TFW_MAX_CLOSED_STREAMS we delete streams from this queue. But now we should not delete such streams, because they can used in `xmit` callback, that's why we implement additional queue for streams. Now when we forward response, we put appropriate stream into `hclosed_streams` queue and then when all response data will be sent, we move this stream to `closed_streams` queue for further deleting. Part of #1394
Since we decide to move frame making into `xmit` callback, we need to save stream id in skb private area and mark skb as skb, which contains headers or data frame. In `xmit` callback we use this id to find appropriate stream and use information of skb type to add appropriate frame header (HEADERS/DATA). Part of #1394
Since we know current tcp limit only in `xmit` callback, we move htt2 framing into this function to make frames with optimal size. Part of #1394
Previously, when we forward response, we put appropriate stream into `hclosed_streams` queue and if count of such streams become greater then TFW_MAX_CLOSED_STREAMS we delete streams from this queue. But now we should not delete such streams, because they can used in `xmit` callback, that's why we implement additional queue for streams. Now when we forward response, we put appropriate stream into `hclosed_streams` queue and then when all response data will be sent, we move this stream to `closed_streams` queue for further deleting. Part of #1394
Since we decide to move frame making into `xmit` callback, we need to save stream id in skb private area and mark skb as skb, which contains headers or data frame. In `xmit` callback we use this id to find appropriate stream and use information of skb type to add appropriate frame header (HEADERS/DATA). Part of #1394
Since we know current tcp limit only in `xmit` callback, we move htt2 framing into this function to make frames with optimal size. Part of #1394
Previously, when we forward response, we put appropriate stream into `hclosed_streams` queue and if count of such streams become greater then TFW_MAX_CLOSED_STREAMS we delete streams from this queue. But now we should not delete such streams, because they can used in `xmit` callback, that's why we implement additional queue for streams. Now when we forward response, we put appropriate stream into `hclosed_streams` queue and then when all response data will be sent, we move this stream to `closed_streams` queue for further deleting. Part of #1394
Done in #1845 |
Doesn't block connection and continue to forward Headers frames while flow control limit is exhausted Will be done later in the task of stream prioritization. |
Scope
Need to cover HTTP/2 flow control requirements from RFC 9113 Section 5.2.
When connecting, client sends initial window size and can control receive window size using
WINDOW_UPDATE
frame. This shouldn't be confused for TCP flow control, since HTTP/2 implements it's own one. The flow control in HTTP/2 can be applied at connection and stream level. Only forDATA
frames are subject for flow control.Great discussion about implementation details took place in #1378 issue. But HLD presented there is not a reasonable solution. The proposed solution was to extend current "push" model for sending messages which lead to TCP head-of-line blocking, reverse prioritisation issues and bufferbloats. The streams ready to send will stored inside
TfwConnection
and theirs skb will be pushed into TCP send queue. Currently we aggressively push messages into TCP send queues and can stress connections even harder than userspace applications has, thanks to direct socket access.Instead we should maintain a set of flows which has data ready to send, and chose and frame data from that set according to current congestion window, and http/2 flow control window. So we avoid to use send queue and directly pull data from
TfwConnection
intcp_write_xmit()
. This is called pull-model.During pull we can prioritise streams with
O(1)
complexity, so this task is required for #1196Useful resources: #391 https://www.slideshare.net/kazuho/reorganizing-website-architecture-for-http2-and-beyond
Testing
Check that Tempesta:
Doesn't send more than allowed by per-stream flow controlTest to reproduce or h2spec: http2/6.9.1Headers
frames while flow control limit is exhaustedDATA
ones on reaching close to flow control limit.WINDOW_UPDATE
frames.curl
with CURLPIPE_MULTIPLEX should correctly fetch many resourcesThe text was updated successfully, but these errors were encountered: