Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
ef08270
merge
Aug 7, 2020
c3d39db
add test and test migration to v3
Aug 10, 2020
7f93c95
add test and test migration to v3
Aug 10, 2020
88704aa
add unit test
Aug 10, 2020
71d9526
add unit test for dangling reference
Aug 11, 2020
1fb167f
add unit test for dangling reference
Aug 11, 2020
3cb0a1c
clean up
Aug 11, 2020
399ad9b
Merge branch 'master' of https://github.com/envoyproxy/envoy into laz…
Aug 11, 2020
2e5eccc
clean up
Aug 11, 2020
477dc6b
clean up
Aug 11, 2020
abd354b
test migration
Aug 12, 2020
25f487d
...
Aug 12, 2020
ab60437
finish
Aug 13, 2020
ae188bf
Merge branch 'master' of https://github.com/envoyproxy/envoy into tes…
Aug 13, 2020
7353474
clean up
Aug 13, 2020
3ce3677
make control flag bool
Aug 13, 2020
d54fc36
fix spelling
Aug 14, 2020
6588bf2
fix spelling
Aug 14, 2020
6cca147
clean up
Aug 14, 2020
f05c622
clean up
Aug 14, 2020
9626719
clean up
Aug 14, 2020
3f23c10
Merge branch 'master' of https://github.com/envoyproxy/envoy into laz…
Aug 15, 2020
b2e3e1f
change scope interface
Aug 15, 2020
2564425
...
Aug 15, 2020
7c4d74d
unit test for srds stats
Aug 17, 2020
8a641f2
refactor
Aug 17, 2020
c65f4b7
add comment
Aug 20, 2020
1aeb72b
sync
Aug 20, 2020
f941ea4
fix format
Aug 20, 2020
74f8c29
add comments
Aug 22, 2020
346ff81
fix spelling
Aug 22, 2020
a4153af
fix test
Aug 25, 2020
16aa77e
release note
Aug 25, 2020
44d5c29
release note
Aug 25, 2020
3dcfa02
release note
Aug 25, 2020
041bc98
release note
Aug 25, 2020
874e4d3
Merge branch 'master' of https://github.com/envoyproxy/envoy into laz…
Aug 25, 2020
67734d8
fix format
Aug 25, 2020
eddcd6d
add comment
Aug 26, 2020
8f40eb2
fix nullconfig comparasion
Aug 27, 2020
45e633c
clean up
Aug 27, 2020
d56f1bc
refactor
Aug 27, 2020
e08c201
Merge branch 'master' of https://github.com/envoyproxy/envoy into laz…
Aug 27, 2020
b9dc81f
pass scope key
Aug 27, 2020
71b7a1b
format
Aug 27, 2020
e4e7a51
add test
Aug 28, 2020
d9affce
clean up
Aug 31, 2020
896f52a
add test
Sep 1, 2020
826ef9d
test
Sep 2, 2020
e1e1e74
Merge branch 'master' of https://github.com/envoyproxy/envoy into laz…
Sep 2, 2020
44cb868
clean up
Sep 2, 2020
d8c3552
resolve conflict
Sep 2, 2020
62cb93f
less verbose
Sep 7, 2020
6d3f7f0
less verbose
Sep 7, 2020
d26f173
clean up
Sep 7, 2020
6a46ebb
clean up
Sep 7, 2020
d78d733
Merge branch 'master' of https://github.com/envoyproxy/envoy into laz…
Sep 7, 2020
70ec602
clean up
Sep 7, 2020
d60da44
clean up
Sep 7, 2020
ae7f157
fix missing test coverage
Sep 8, 2020
1da611e
add comment
Sep 8, 2020
f867e53
add comment
Sep 8, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions api/envoy/config/route/v3/scoped_route.proto
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ message ScopedRouteConfiguration {
repeated Fragment fragments = 1 [(validate.rules).repeated = {min_items: 1}];
}

// Whether the RouteConfiguration should be loaded on demand.
bool on_demand = 4;

// The name assigned to the routing scope.
string name = 1 [(validate.rules).string = {min_bytes: 1}];

Expand Down
3 changes: 3 additions & 0 deletions api/envoy/config/route/v4alpha/scoped_route.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
.. _config_http_filters_on_demand:

On-demand VHDS Updates
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

======================
On-demand VHDS and S/RDS Updates
================================

The on-demand VHDS filter is used to request a :ref:`virtual host <envoy_v3_api_msg_config.route.v3.VirtualHost>`
The on demand filter can be used to support either on demand VHDS or S/RDS update if configured in the filter chain.

The on-demand update filter can be used to request a :ref:`virtual host <envoy_v3_api_msg_config.route.v3.VirtualHost>`
data if it's not already present in the :ref:`Route Configuration <envoy_v3_api_msg_config.route.v3.RouteConfiguration>`. The
contents of the *Host* or *:authority* header is used to create the on-demand request. For an on-demand
request to be created, :ref:`VHDS <envoy_v3_api_field_config.route.v3.RouteConfiguration.vhds>` must be enabled and either *Host*
or *:authority* header be present.

On-demand VHDS cannot be used with SRDS at this point.
The on-demand update filter can also be used to request a *Route Configuration* data if RouteConfiguration is specified to be
loaded on demand in the :ref:`Scoped RouteConfiguration <envoy_v3_api_msg_config.route.v3.ScopedRouteConfiguration>`.
The contents of the HTTP header is used to find the scope and create the on-demand request.

On-demand VHDS and on-demand S/RDS can not be used at the same time at this point.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a tracking issue yet for converging the two?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess not.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend adding one.


Configuration
-------------
Expand Down
3 changes: 2 additions & 1 deletion docs/root/intro/arch_overview/http/http_routing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,11 @@ Route Scope
Scoped routing enables Envoy to put constraints on search space of domains and route rules.
A :ref:`Route Scope<envoy_api_msg_ScopedRouteConfiguration>` associates a key with a :ref:`route table <arch_overview_http_routing_route_table>`.
For each request, a scope key is computed dynamically by the HTTP connection manager to pick the :ref:`route table<envoy_api_msg_RouteConfiguration>`.
RouteConfiguration associated with scope can be loaded on demand with :ref:`v3 API reference <envoy_v3_api_msg_extensions.filters.http.on_demand.v3.OnDemand>` configured and on demand filed in protobuf set to true.

The Scoped RDS (SRDS) API contains a set of :ref:`Scopes <envoy_v3_api_msg_config.route.v3.ScopedRouteConfiguration>` resources, each defining independent routing configuration,
along with a :ref:`ScopeKeyBuilder <envoy_v3_api_msg_extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder>`
defining the key construction algorithm used by Envoy to look up the scope corresponding to each request.
defining the key construction algorithm used by Envoy to look up the scope corresponding to each request.

For example, for the following scoped route configuration, Envoy will look into the "addr" header value, split the header value by ";" first, and use the first value for key 'x-foo-key' as the scope key.
If the "addr" header value is "foo=1;x-foo-key=127.0.0.1;x-bar-key=1.1.1.1", then "127.0.0.1" will be computed as the scope key to look up for corresponding route configuration.
Expand Down
3 changes: 3 additions & 0 deletions generated_api_shadow/envoy/config/route/v3/scoped_route.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 0 additions & 9 deletions include/envoy/http/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -523,15 +523,6 @@ class StreamDecoderFilterCallbacks : public virtual StreamFilterCallbacks {
*/
virtual void
requestRouteConfigUpdate(RouteConfigUpdatedCallbackSharedPtr route_config_updated_cb) PURE;

/**
*
* @return absl::optional<Router::ConfigConstSharedPtr>. Contains a value if a non-scoped RDS
* route config provider is used. Scoped RDS provides are not supported at the moment, as
* retrieval of a route configuration in their case requires passing of http request headers
* as a parameter.
*/
virtual absl::optional<Router::ConfigConstSharedPtr> routeConfig() PURE;
};

/**
Expand Down
78 changes: 78 additions & 0 deletions include/envoy/router/scopes.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,77 @@
namespace Envoy {
namespace Router {

/**
* Scope key fragment base class.
*/
class ScopeKeyFragmentBase {
public:
bool operator!=(const ScopeKeyFragmentBase& other) const { return !(*this == other); }

bool operator==(const ScopeKeyFragmentBase& other) const {
if (typeid(*this) == typeid(other)) {
return hash() == other.hash();
}
return false;
}
virtual ~ScopeKeyFragmentBase() = default;

// Hash of the fragment.
virtual uint64_t hash() const PURE;
};

/**
* Scope Key is composed of non-null fragments.
**/
class ScopeKey {
public:
ScopeKey() = default;
ScopeKey(ScopeKey&& other) = default;

// Scopekey is not copy-assignable and copy-constructible as it contains unique_ptr inside itself.
ScopeKey(const ScopeKey&) = delete;
ScopeKey operator=(const ScopeKey&) = delete;

// Caller should guarantee the fragment is not nullptr.
void addFragment(std::unique_ptr<ScopeKeyFragmentBase>&& fragment) {
ASSERT(fragment != nullptr, "null fragment not allowed in ScopeKey.");
updateHash(*fragment);
fragments_.emplace_back(std::move(fragment));
}

uint64_t hash() const { return hash_; }
bool operator!=(const ScopeKey& other) const;
bool operator==(const ScopeKey& other) const;

private:
// Update the key's hash with the new fragment hash.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why we have these diffs?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nvm, I see the move later now.
on the other hand, maybe not move stringkeyfragment here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arguably we should split this into interface/implementation, since there is a lot of low-level implementation logic here. We have precedence for doing it this way in some cases, e.g. header map, but strongly prefer to not put a ton of implementation logic (e.g. the hash function below) inside include/.

void updateHash(const ScopeKeyFragmentBase& fragment) {
std::stringbuf buffer;
buffer.sputn(reinterpret_cast<const char*>(&hash_), sizeof(hash_));
const auto& fragment_hash = fragment.hash();
buffer.sputn(reinterpret_cast<const char*>(&fragment_hash), sizeof(fragment_hash));
hash_ = HashUtil::xxHash64(buffer.str());
}

uint64_t hash_{0};
std::vector<std::unique_ptr<ScopeKeyFragmentBase>> fragments_;
};

using ScopeKeyPtr = std::unique_ptr<ScopeKey>;

// String fragment.
class StringKeyFragment : public ScopeKeyFragmentBase {
public:
explicit StringKeyFragment(absl::string_view value)
: value_(value), hash_(HashUtil::xxHash64(value_)) {}

uint64_t hash() const override { return hash_; }

private:
const std::string value_;
const uint64_t hash_;
};

/**
* The scoped routing configuration.
*/
Expand All @@ -22,6 +93,13 @@ class ScopedConfig : public Envoy::Config::ConfigProvider::Config {
* @return ConfigConstSharedPtr the router's Config matching the request headers.
*/
virtual ConfigConstSharedPtr getRouteConfig(const Http::HeaderMap& headers) const PURE;

/**
* Based on the incoming HTTP request headers, returns the hash value of its scope key.
* @param headers the request headers to match the scoped routing configuration against.
* @return unique_ptr of the scope key computed from header.
*/
virtual ScopeKeyPtr computeScopeKey(const Http::HeaderMap&) const { return {}; }
};

using ScopedConfigConstSharedPtr = std::shared_ptr<const ScopedConfig>;
Expand Down
1 change: 1 addition & 0 deletions source/common/http/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ envoy_cc_library(
"//source/common/http/http3:well_known_names",
"//source/common/network:utility_lib",
"//source/common/router:config_lib",
"//source/common/router:scoped_rds_lib",
"//source/common/stats:timespan_lib",
"//source/common/stream_info:stream_info_lib",
"//source/common/tracing:http_tracer_lib",
Expand Down
1 change: 0 additions & 1 deletion source/common/http/async_client_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ class AsyncStreamImpl : public AsyncClient::Stream,
void requestRouteConfigUpdate(Http::RouteConfigUpdatedCallbackSharedPtr) override {
NOT_IMPLEMENTED_GCOVR_EXCL_LINE;
}
absl::optional<Router::ConfigConstSharedPtr> routeConfig() override { return {}; }

// Http::AsyncClient::Stream
void sendHeaders(RequestHeaderMap& headers, bool end_stream) override;
Expand Down
73 changes: 60 additions & 13 deletions source/common/http/conn_manager_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -480,13 +480,61 @@ void ConnectionManagerImpl::chargeTracingStats(const Tracing::Reason& tracing_re
}
}

// TODO(chaoqin-li1123): Make on demand vhds and on demand srds works at the same time.
void ConnectionManagerImpl::RdsRouteConfigUpdateRequester::requestRouteConfigUpdate(
const std::string host_header, Event::Dispatcher& thread_local_dispatcher,
Http::RouteConfigUpdatedCallbackSharedPtr route_config_updated_cb) {
absl::optional<Router::ConfigConstSharedPtr> route_config = parent_.routeConfig();
Event::Dispatcher& thread_local_dispatcher =
parent_.connection_manager_.read_callbacks_->connection().dispatcher();
if (route_config.has_value() && route_config.value()->usesVhds()) {
ASSERT(!parent_.request_headers_->Host()->value().empty());
const auto& host_header = absl::AsciiStrToLower(parent_.request_headers_->getHostValue());
requestVhdsUpdate(host_header, thread_local_dispatcher, std::move(route_config_updated_cb));
return;
} else if (parent_.snapped_scoped_routes_config_ != nullptr) {
Router::ScopeKeyPtr scope_key =
parent_.snapped_scoped_routes_config_->computeScopeKey(*parent_.request_headers_);
// If scope_key is not null, the scope exists but RouteConfiguration is not initialized.
if (scope_key != nullptr) {
requestSrdsUpdate(std::move(scope_key), thread_local_dispatcher,
std::move(route_config_updated_cb));
return;
}
}
// Continue the filter chain if no on demand update is requested.
(*route_config_updated_cb)(false);
}

void ConnectionManagerImpl::RdsRouteConfigUpdateRequester::requestVhdsUpdate(
const std::string& host_header, Event::Dispatcher& thread_local_dispatcher,
Http::RouteConfigUpdatedCallbackSharedPtr route_config_updated_cb) {
route_config_provider_->requestVirtualHostsUpdate(host_header, thread_local_dispatcher,
std::move(route_config_updated_cb));
}

void ConnectionManagerImpl::RdsRouteConfigUpdateRequester::requestSrdsUpdate(
Router::ScopeKeyPtr scope_key, Event::Dispatcher& thread_local_dispatcher,
Http::RouteConfigUpdatedCallbackSharedPtr route_config_updated_cb) {
// Since inline scope_route_config_provider is not fully implemented and never used,
// dynamic cast in constructor always succeed and the pointer should not be null here.
ASSERT(scoped_route_config_provider_ != nullptr);
Http::RouteConfigUpdatedCallback scoped_route_config_updated_cb =
Http::RouteConfigUpdatedCallback(
[this, weak_route_config_updated_cb = std::weak_ptr<Http::RouteConfigUpdatedCallback>(
route_config_updated_cb)](bool scope_exist) {
// If the callback can be locked, this ActiveStream is still alive.
if (auto cb = weak_route_config_updated_cb.lock()) {
// Refresh the route before continue the filter chain.
if (scope_exist) {
parent_.refreshCachedRoute();
}
(*cb)(scope_exist && parent_.hasCachedRoute());
}
});
scoped_route_config_provider_->onDemandRdsUpdate(std::move(scope_key), thread_local_dispatcher,
std::move(scoped_route_config_updated_cb));
}

ConnectionManagerImpl::ActiveStream::ActiveStream(ConnectionManagerImpl& connection_manager,
uint32_t buffer_limit)
: connection_manager_(connection_manager),
Expand Down Expand Up @@ -520,11 +568,12 @@ ConnectionManagerImpl::ActiveStream::ActiveStream(ConnectionManagerImpl& connect
connection_manager.config_.routeConfigProvider() != nullptr) {
route_config_update_requester_ =
std::make_unique<ConnectionManagerImpl::RdsRouteConfigUpdateRequester>(
connection_manager.config_.routeConfigProvider());
connection_manager.config_.routeConfigProvider(), *this);
} else if (connection_manager_.config_.isRoutable() &&
connection_manager.config_.scopedRouteConfigProvider() != nullptr) {
route_config_update_requester_ =
std::make_unique<ConnectionManagerImpl::NullRouteConfigUpdateRequester>();
std::make_unique<ConnectionManagerImpl::RdsRouteConfigUpdateRequester>(
connection_manager.config_.scopedRouteConfigProvider(), *this);
}
ScopeTrackerScopeState scope(this,
connection_manager_.read_callbacks_->connection().dispatcher());
Expand Down Expand Up @@ -1138,21 +1187,18 @@ void ConnectionManagerImpl::ActiveStream::refreshCachedTracingCustomTags() {
}
}

// TODO(chaoqin-li1123): Make on demand vhds and on demand srds works at the same time.
void ConnectionManagerImpl::ActiveStream::requestRouteConfigUpdate(
Event::Dispatcher& thread_local_dispatcher,
Http::RouteConfigUpdatedCallbackSharedPtr route_config_updated_cb) {
ASSERT(!request_headers_->Host()->value().empty());
const auto& host_header = absl::AsciiStrToLower(request_headers_->getHostValue());
route_config_update_requester_->requestRouteConfigUpdate(host_header, thread_local_dispatcher,
std::move(route_config_updated_cb));
route_config_update_requester_->requestRouteConfigUpdate(route_config_updated_cb);
}

absl::optional<Router::ConfigConstSharedPtr> ConnectionManagerImpl::ActiveStream::routeConfig() {
if (connection_manager_.config_.routeConfigProvider() == nullptr) {
return {};
if (connection_manager_.config_.routeConfigProvider() != nullptr) {
return absl::optional<Router::ConfigConstSharedPtr>(
connection_manager_.config_.routeConfigProvider()->config());
}
return absl::optional<Router::ConfigConstSharedPtr>(
connection_manager_.config_.routeConfigProvider()->config());
return {};
}

void ConnectionManagerImpl::ActiveStream::onLocalReply(Code code) {
Expand Down Expand Up @@ -1196,7 +1242,8 @@ void ConnectionManagerImpl::ActiveStream::encodeHeaders(ResponseHeaderMap& heade
connection_manager_.config_.dateProvider().setDateHeader(headers);
}

// Following setReference() is safe because serverName() is constant for the life of the listener.
// Following setReference() is safe because serverName() is constant for the life of the
// listener.
const auto transformation = connection_manager_.config_.serverHeaderTransformation();
if (transformation == ConnectionManagerConfig::HttpConnectionManagerProto::OVERWRITE ||
(transformation == ConnectionManagerConfig::HttpConnectionManagerProto::APPEND_IF_ABSENT &&
Expand Down
Loading