conn_pool: making TCP upstreams pluggable#13548
conn_pool: making TCP upstreams pluggable#13548alyssawilk merged 14 commits intoenvoyproxy:masterfrom
Conversation
antoniovicente
left a comment
There was a problem hiding this comment.
Nice refactor, thanks for this work to reduce differences between various upstream connection factories.
Please look at CI since there's some doc generation and spellcheck errors.
| hdrs = [ | ||
| "config.h", | ||
| ], | ||
| security_posture = "robust_to_untrusted_downstream", |
There was a problem hiding this comment.
How does this extension interact with upstreams? Worth a comment explaining the interaction (if there's any) or saying that there should be no upstream interaction?
There was a problem hiding this comment.
I think Enovy in general is considered not robust to untrusted upstreams.
@htuch is this documented somewhere?
There was a problem hiding this comment.
Given the work @yanavlasov is doing in #12278, this is about to change shortly. Do you think you think there are untrusted upstream issues in this PR?
There was a problem hiding this comment.
htuch: I think part of the issue is that there's currently no way to indicate that an extension is robust to untrusted downstreams and agnostic to upstream input.
There was a problem hiding this comment.
If it's agnostic then it's robust.
There was a problem hiding this comment.
happy to tag this whatever you folks decide - it's no different from the current TCP proxy code robustness which as I understand today is considered robust to downstream and not to upstream.
There was a problem hiding this comment.
@yanavlasov do you want to make a call on this one based on upstream hardening progress?
| } | ||
|
|
||
| // Test with an explicitly configured upstream. | ||
| TEST_F(TcpProxyTest, DEPRECATED_FEATURE_TEST(ExplicitFactory)) { |
There was a problem hiding this comment.
I'm a bit confused. GenericConnectionPoolProto is the proto that you added in this PR, but it seems that this test is for a feature that is being deprecated.
include/envoy/tcp/upstream.h
Outdated
| * @param cm the cluster manager to get the connection pool from | ||
| * @param hostname the hostname to use if doing connect tunneling, absl::nullopt otherwise. | ||
| * @param context the load balancing context for this connection. | ||
| * @param upstream_callbacks the callbacks to provide to the connection if succesfully created. |
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
source/common/tcp_proxy/tcp_proxy.cc
Outdated
| factory = &Envoy::Config::Utility::getAndCheckFactory<GenericConnPoolFactory>( | ||
| cluster.info()->upstreamConfig().value()); | ||
| } else { | ||
| auto* cluster = cluster_manager_.get(cluster_name); | ||
| if (!cluster) { | ||
| return false; | ||
| } | ||
| // TODO(snowp): Ideally we should prevent this from being configured, but that's tricky to get | ||
| // right since whether a cluster is invalid depends on both the tcp_proxy config + cluster | ||
| // config. | ||
| if ((cluster->info()->features() & Upstream::ClusterInfo::Features::HTTP2) == 0) { | ||
| ENVOY_LOG(error, "Attempted to tunnel over HTTP/1.1, this is not supported. Set " | ||
| "http2_protocol_options on the cluster."); | ||
| return false; | ||
| } | ||
|
|
||
| generic_conn_pool_ = std::make_unique<HttpConnPool>(cluster_name, cluster_manager_, this, | ||
| config_->tunnelingConfig()->hostname(), | ||
| *upstream_callbacks_); | ||
| if (generic_conn_pool_->valid()) { | ||
| generic_conn_pool_->newStream(this); | ||
| return true; | ||
| } else { | ||
| generic_conn_pool_.reset(); | ||
| } | ||
| factory = &Envoy::Config::Utility::getAndCheckFactoryByName<GenericConnPoolFactory>( | ||
| "envoy.filters.connection_pools.tcp.generic"); |
There was a problem hiding this comment.
getAndCheckFactoryByName may throw exception on invalid type_config
Is such "non-exist" factory config validated by XDS already?
There was a problem hiding this comment.
Nice catch. This does look like data plane code with no obvious try/catch blocks in sight. The most concerning one is the getAndCheckFactory on line 447 above which is a function of config.
There was a problem hiding this comment.
I think it's safe to lookup by name providing you can guarantee that the filter will be there; it will throw otherwise. The config thing becomes an issue only when you are actually loading config.
I wonder if we can make this more robust going forward by having the factory functions ASSERT that they are in a control plane context, using some main thread singleton. There's probably static annotations etc. we could use if we wanted to get fancy, but I can see how to build this dynamic check.
Also, Quic has this same pattern.
There was a problem hiding this comment.
Calling the factory lookup functions in a non control plane setting is not legal. I urge we invest in adding the appropriate ASSERTs.
There was a problem hiding this comment.
refactored to make it non-fatal and added a test. PTAL!
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
antoniovicente
left a comment
There was a problem hiding this comment.
Just some remaining nits. Looks good otherwise.
| } | ||
|
|
||
| /** | ||
| * Get a Factory from the registry with a particular name or return nullptr. |
There was a problem hiding this comment.
nit: worth adding a @return statement to the comment?
source/common/tcp_proxy/tcp_proxy.cc
Outdated
| } | ||
|
|
||
| bool Filter::maybeTunnel(Upstream::ThreadLocalCluster& cluster, const std::string& cluster_name) { | ||
| std::cerr << " HERE\n"; |
There was a problem hiding this comment.
nit: Remove debug logging.
| * @param info supplies the stream info object associated with the upstream connection. | ||
| * @param upstream supplies the generic upstream for the stream. | ||
| * @param host supplies the description of the host that will carry the request. | ||
| * @param upstream_local_address supplies the local address of the upstream connection. |
There was a problem hiding this comment.
nit: documentation and argument names disagree: upstream_local_address vs local_address
|
@snowp or @mattklein123 up for second pass? |
snowp
left a comment
There was a problem hiding this comment.
Thanks this looks good for the most part, just a few comments
include/envoy/tcp/upstream.h
Outdated
| * | ||
| * @param callbacks callbacks to communicate stream failure or creation on. | ||
| */ | ||
| virtual void newStream(GenericConnectionPoolCallbacks* callbacks) PURE; |
There was a problem hiding this comment.
Should this take a ref instead of a pointer?
include/envoy/tcp/upstream.h
Outdated
| */ | ||
| virtual GenericConnPoolPtr | ||
| createGenericConnPool(const std::string& cluster_name, Upstream::ClusterManager& cm, | ||
| absl::optional<std::string> hostname, |
source/common/tcp_proxy/tcp_proxy.cc
Outdated
| return false; | ||
| } | ||
|
|
||
| absl::optional<std::string> hostname = |
There was a problem hiding this comment.
This does a string copy, which means two string copies here since hostname is passed by value to createGenericConnPool. Might not matter in this context
A higher level comment: should we do the factory lookup + partially populate the arguments during filter factory creation? That way we avoid factory lookup and string copies etc in the data path
|
@snowp I think I finally got CI sorted, PTAL! |
snowp
left a comment
There was a problem hiding this comment.
Makes sense to me! Just a few small comments
include/envoy/tcp/upstream.h
Outdated
| * | ||
| * @param disable true if the stream should be read disabled, false otherwise. | ||
| * @return returns true if the disable is performed, false otherwise | ||
| (e.g. if the connection is closed) |
include/envoy/tcp/upstream.h
Outdated
| * @param config the tunneling config, if doing connect tunneling. | ||
| * @param context the load balancing context for this connection. | ||
| * @param upstream_callbacks the callbacks to provide to the connection if successfully created. | ||
| * @return may be null |
source/common/config/utility.h
Outdated
|
|
||
| /** | ||
| * Get a Factory from the registry with a particular name or return nullptr. | ||
| * @param name string identifier for the particular implementation. Note: this is a proto string |
There was a problem hiding this comment.
Seems like this is just a regular string?
|
@htuch @mattklein123 @lizan I can has API stamp? |
Risk Level: Medium (some refactory)
Testing: existing tests pass
Docs Changes: n/a
Release Notes: n/a
Fixes #13185