tcp_proxy: Add filter state envoy.tcp_proxy.receive_before_connect#25804
tcp_proxy: Add filter state envoy.tcp_proxy.receive_before_connect#25804jrajahalme wants to merge 5 commits intoenvoyproxy:mainfrom
Conversation
|
CC @envoyproxy/api-shepherds: Your approval is needed for changes made to |
7b5077b to
3d4a268
Compare
|
Force-pushed to fix format. |
3d4a268 to
aa1e991
Compare
|
Force pushed to fix spelling |
botengyao
left a comment
There was a problem hiding this comment.
Thanks! Overall reasonable for me, but we need @ggreenway's input as well I think.
There was a problem hiding this comment.
This is not the early data buffer you create in Tcp proxy, right? It is a little bit confusing for the comment, like we stop the filter chain iteration at InjectDynamicMetadata::onData() when just receives pri. Tcp proxy cannot get the onData call before the InjectDynamicMetadata continues the filter chain.
And writing a new set of integration tests maybe more clear here to make sure the original behavior is also tested. We should also add some situations that trigger early_data_buffer_ when connection is not created, but seems not easy to test.
There was a problem hiding this comment.
Actually we can read-enable here, seems this PR will only buy some time back between the initialization and onNewConnection?
There was a problem hiding this comment.
This PR does two things:
-
asks the (TCP) proxy to not read-disable in the first place, so that other filters do not need to know the exact spots where to read-enable and disable again. This enables filters receiving data before and while the upstream connection setup takes place.
-
adds early data buffering to the tcp_proxy filter, so that filters can write (early) data after tcp_proxy has started connect() system call, but the connection has not yet been established. As of now tcp_proxy will assert-fail if it receives data before the connection has been established. This allows filters that read data enabled by point (1) to pass it on without buffering and waiting for connection setup to complete.
|
/assign @ggreenway |
ggreenway
left a comment
There was a problem hiding this comment.
This is basically a compatibility problem between different filters. In my opinion, it would be nicer to do this mechanism via some communication between the filters (maybe a FilterState), not via a config knob. The user shouldn't have to keep track of whether their other network filter requires this tcp_proxy setting. And accidentally setting this when the other network filters aren't handling the data will result in buggy behavior.
/wait
aa1e991 to
b5d1460
Compare
Changed to introduce a new filter state instead as suggested here. Since reverting API changes in a new commit could have been confusing, I force pushed the code with the new approach, hope this is OK. |
b5d1460 to
9d3d455
Compare
|
@ggreenway Care to take another look? |
There was a problem hiding this comment.
I don't think we need a new class for this; you can use StreamInfo::BoolAccessor. Also, the definition of the key belongs in source/common/tcp_proxy/tcp_proxy.h.
Related example that was recently added: constexpr absl::string_view DisableTunnelingFilterStateKey = "envoy.tcp_proxy.disable_tunneling";.
There was a problem hiding this comment.
Thanks for the pointers, changed!
source/common/tcp_proxy/tcp_proxy.cc
Outdated
There was a problem hiding this comment.
Should there be a limit on how much data can be buffered here? Or do you depend on the earlier network filter to readDisable() if there's too much data?
There was a problem hiding this comment.
Did not consider this, so maybe the latter? Of should I change the boolean metadata to be an integral maximum buffer size instead?
There was a problem hiding this comment.
You could probably use one of the existing connection buffer size settings for the value. But if you want the other filter to specify how much data to buffer, that's fine too.
source/common/tcp_proxy/tcp_proxy.cc
Outdated
There was a problem hiding this comment.
Can you add a test that causes a high watermark on the upstream here, to make sure that any callbacks that re-renter this class have the correct state?
There was a problem hiding this comment.
Could you point to a test that is close enough to use for inspiration to what you mean here?
|
Side-note - could we use this to solve #9023, assuming we have some way to detect the end of the downstream TLS handshake. |
|
@ggreenway Sorry for the delay, addressed your comment on use of |
|
Friendly ping @ggreenway |
|
Added docs. |
c9b3227 to
5ac3dd3
Compare
|
Rebased to resolve conflict on changelogs. |
|
fixed doc format |
Add filter state object bool proxy_receive_before_connect that tcp_proxy filter checks for and when set to 'true' will not set readDisable on the downstream connection before upstream connection is established. This change allows advanced cases where a network read filter needs to receive (and possibly send) downstream data that may change the destination of the upstream TCP connection, e.g. via metadata set based on the received data. If this is the case, then the read filter preceding the tcp_proxy filter must return StopIteration from its onNewConnection() call, causing tcp_proxy filter to postpone its upstream connection establishment until onData() returns Continue. Any data reaching the tcp_proxy filter before the upstream connection is established is buffered so that the downstream filters do not see the same data again which would be the case if it would remaining in the buffer and more data is received. This also allows downstream filters inject data before the upstream connection is established; such injected data would be lost if tcp_proxy would not buffer it while connection establishment is still ongoing. An existing dynamic metadata integration test is modified to use proxy_receive_before_connect=true. This makes the use case less reliant on the tcp_proxy internal detail, such as balancing and timing of the readDisable() calls on the downstream connection. Signed-off-by: Jarno Rajahalme <jarno@isovalent.com>
Signed-off-by: Jarno Rajahalme <jarno@isovalent.com>
8ebec98 to
fff172e
Compare
|
Rebased to fix conflict on |
|
@ggreenway Do I need to be rebasing this to resolve the conflict on |
| } | ||
| return Network::FilterStatus::StopIteration; | ||
| // Allow OnData() to receive data before connect if so configured | ||
| return receive_before_connect_ ? Network::FilterStatus::Continue |
There was a problem hiding this comment.
In the case of receive_before_connect_, now that earlier filters have seen whatever data they need and allowed the filter chain to continue, should tcp_proxy readDisable(true) to prevent additional data from getting buffered while the upstream connection is established?
If not, then I think there needs to be some limit to the data enforced. One option is to leave it in the Connection buffer so that flow control can be triggered.
There's a merge conflict, so merge main into your PR branch and resolve conflict there. |
…n-to-read-before-connect
|
@ggreenway merged main, conflicts resolved. |
|
@ggreenway Can you re-trigger presubmit checks? The fail seems to be in |
…n-to-read-before-connect
|
Pushed another main merge to rerun tests. |
ggreenway
left a comment
There was a problem hiding this comment.
This still needs some buffer-limit/flow-control added to it.
Also, need to address https://github.com/envoyproxy/envoy/pull/25804/files#r1125129552.
/wait
source/common/tcp_proxy/tcp_proxy.cc
Outdated
There was a problem hiding this comment.
You could probably use one of the existing connection buffer size settings for the value. But if you want the other filter to specify how much data to buffer, that's fine too.
|
This pull request has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
|
This pull request has been automatically closed because it has not had activity in the last 37 days. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
|
Hi @jrajahalme would you be able to re-work this PR ? Our team also has a use case where we have RBAC before TCP_Proxy and TCP_Proxy is opening connection to upstream before RBAC is performed which is not ideal for us. So having this filter state will be very useful for our case as well. |
Commit Message:
Add filter state object
envoy.tcp_proxy.receive_before_connectthatTcpProxyfilter checks for and when set to 'true' will not set
readDisable=trueon thedownstream connection before upstream connection is established.
proxy_receive_before_connectneeds to be set a read filter'sinitializeReadFilterCallbacks()astcp_proxychecks for this in itsinitializeReadFilterCallbacks()that is called when the filter chain is created,but after all the other filters as
tcp_proxyis the last filter in the chain.This change allows advanced cases where a network read filter needs to
receive (and possibly send) downstream data that may change the
destination of the upstream TCP connection, e.g. via metadata set based
on the received data. If this is the case, then the read filter preceding
the tcp_proxy filter must return
StopIterationfrom itsonNewConnection()call, causing
tcp_proxyfilter to postpone its upstream connectionestablishment until
onData()returnsContinue.Any data reaching the
tcp_proxyfilter before the upstream connection isestablished is buffered so that the downstream filters do not see the
same data again which would be the case if it would remaining in the buffer
and more data is received. This also allows downstream filters inject
data before the upstream connection is established; such injected data
would be lost if
tcp_proxywould not buffer it while connectionestablishment is still ongoing.
An existing dynamic metadata integration test is modified to use
proxy_receive_before_connect=true. This makes the use case lessreliant on the
tcp_proxyinternal detail, such as balancing and timing ofthe
readDisable()calls on the downstream connection.Additional Description:
Risk Level: Low
Testing: Existing test is enhanced to cover the new code
Docs Changes:
Release Notes: Tcp proxy filter can now be configured to receive data from downstream connection before the upstream connection is established with the new receive_before_connect configuration option.
Platform Specific Features: