filter state: add a mark for sharing with the upstream#21700
filter state: add a mark for sharing with the upstream#21700kyessenov merged 17 commits intoenvoyproxy:mainfrom
Conversation
Signed-off-by: Kuat Yessenov <kuat@google.com>
Signed-off-by: Kuat Yessenov <kuat@google.com>
ggreenway
left a comment
There was a problem hiding this comment.
This approach seems good to me.
/wait
envoy/stream_info/filter_state.h
Outdated
| class FilterState { | ||
| public: | ||
| enum class StateType { ReadOnly, Mutable }; | ||
| enum StateType { |
There was a problem hiding this comment.
I think it's simpler to just leave this as the previous enum, and add another bool for SharedWithUpstreamConnection.
There was a problem hiding this comment.
When the upstream L7 filters get done, we'll also need to share with the upstream request I think. I could add another enum for sharing configuration I suppose?
|
CC @envoyproxy/api-shepherds: Your approval is needed for changes made to |
|
@ggreenway This should be ready now. I could simplify the recently merged extension, too, which was the only client in-tree for filter state within transport socket options. |
lizan
left a comment
There was a problem hiding this comment.
/lgtm api
breaking API changes approved per exception:
Changes made within 14 days of the introduction of a new API field or message, provided the new field or message has not been included in an Envoy release.
envoy/event/dispatcher.h
Outdated
| Network::Address::InstanceConstSharedPtr source_address, | ||
| Network::TransportSocketPtr&& transport_socket, | ||
| const Network::ConnectionSocket::OptionsSharedPtr& options, | ||
| const Network::TransportSocketOptionsConstSharedPtr& transport_options = nullptr) PURE; |
There was a problem hiding this comment.
no default argument for virtual methods per style guide.
Signed-off-by: Kuat Yessenov <kuat@google.com>
envoy/network/transport_socket.h
Outdated
| * that are marked as shared with the upstream connection. | ||
| */ | ||
| virtual const StreamInfo::FilterStateSharedPtr& filterState() const PURE; | ||
| virtual const StreamInfo::FilterState::Objects& filterStateObjects() const PURE; |
There was a problem hiding this comment.
I think this function name should be more descriptive, maybe something like downstreamSharedFilterStateObjects().
envoy/stream_info/filter_state.h
Outdated
| // state. | ||
| // | ||
| // As a special case, objects that are marked as shared with the upstream | ||
| // become bound to the upstream connection life span, regardless of the |
There was a problem hiding this comment.
clarify: the object will live as long as either the downstream or upstream connection is open. The current wording implies that the lifetime is strictly tied to the upstream connection.
There was a problem hiding this comment.
Clarified, LMK if it can be improved further.
envoy/stream_info/filter_state.h
Outdated
| std::shared_ptr<Object> data_; | ||
| StateType state_type_; | ||
| StreamSharing stream_sharing_{StreamSharing::None}; | ||
| std::string name_{""}; |
There was a problem hiding this comment.
The initialization can just be {} instead of {""}, but empty is the default so it can be omitted entirely.
| if (!filter_state) { | ||
| return nullptr; | ||
| for (const auto& object : options->filterStateObjects()) { | ||
| if (auto hashable = dynamic_cast<const Hashable*>(object.data_.get()); hashable != nullptr) { |
There was a problem hiding this comment.
What happens if an object isn't Hashable? Can we end up with bugs due to matching transport socket options hash even though it contains different filter state? Should FilterState::Object always inherit from Hashable? Or maybe make it required when the object opts in to sharing, via an accessor like getHashable()? We mostly try to avoid dynamic_cast in envoy for this type of feature detection.
There was a problem hiding this comment.
Hashable is only needed for L7->L4 stream transition. For tcp_proxy, it's already 1-1 so hashing is not necessary. I followed https://www.envoyproxy.io/docs/envoy/latest/api-v3/type/v3/hash_policy.proto#envoy-v3-api-msg-type-v3-hashpolicy-filterstate which does the same dynamic cast test.
| filter_state.setData(object.name_, object.data_, object.state_type_, | ||
| StreamInfo::FilterState::LifeSpan::Connection, object.stream_sharing_); | ||
| } catch (const EnvoyException& e) { | ||
| ENVOY_LOG(trace, "Failed to set data for '{}': {}", object.name_, e.what()); |
There was a problem hiding this comment.
Ignoring this error seems unsafe; something important may have been discarded. Are there cases where this is expected to happen? Should this have an ENVOY_BUG()?
There was a problem hiding this comment.
I think this never throws because the stream info is new and objects have distinct names. Removed try/catch.
envoy/stream_info/filter_state.h
Outdated
|
|
||
| struct FilterObject { | ||
| std::shared_ptr<Object> data_; | ||
| StateType state_type_; |
There was a problem hiding this comment.
| StateType state_type_; | |
| StateType state_type_{}; |
default initialize this?
Signed-off-by: Kuat Yessenov <kuat@google.com>
|
/retest |
|
Retrying Azure Pipelines: |
lizan
left a comment
There was a problem hiding this comment.
LGTM, can you resolve conflicts?
|
/retest |
|
Retrying Azure Pipelines: |
Commit Message: Adds a new flag for filter state objects that indicates the intent to share with the upstream.
Additional Description: Follow-up to #19809. There have been multiple reports of unexpected lifecycle changes for the filter state objects because they are stored in the transport socket options. This PR addresses this issue by introducing a new mark for filter state that explicitly changes the usage of filter state objects:
Risk Level: medium, revert to the original behavior prior to #19809
Testing: yes
Docs Changes: yes
Release Notes: yes