Skip to content

Commit

Permalink
router: integrate matching API (#17633)
Browse files Browse the repository at this point in the history
Adds support for using the matching API in the route table. This wires up using the generic match as part of a virtual host, making it possible to define a match tree that results in Route actions that reuses the same routing actions currently in use by the router.

Signed-off-by: Snow Pettersen <snowp@lyft.com>
  • Loading branch information
snowp authored Oct 13, 2021
1 parent 12c96a8 commit 94d0013
Show file tree
Hide file tree
Showing 11 changed files with 493 additions and 68 deletions.
2 changes: 2 additions & 0 deletions api/envoy/config/route/v3/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ api_proto_package(
"//envoy/type/tracing/v3:pkg",
"//envoy/type/v3:pkg",
"@com_github_cncf_udpa//udpa/annotations:pkg",
"@com_github_cncf_udpa//xds/annotations/v3:pkg",
"@com_github_cncf_udpa//xds/type/matcher/v3:pkg",
],
)
12 changes: 11 additions & 1 deletion api/envoy/config/route/v3/route_components.proto
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import "google/protobuf/any.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/wrappers.proto";

import "xds/annotations/v3/status.proto";
import "xds/type/matcher/v3/matcher.proto";

import "envoy/annotations/deprecation.proto";
import "udpa/annotations/migrate.proto";
import "udpa/annotations/status.proto";
Expand All @@ -37,7 +40,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// host header. This allows a single listener to service multiple top level domain path trees. Once
// a virtual host is selected based on the domain, the routes are processed in order to see which
// upstream cluster to route to or whether to perform a redirect.
// [#next-free-field: 21]
// [#next-free-field: 22]
message VirtualHost {
option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.route.VirtualHost";

Expand Down Expand Up @@ -87,8 +90,15 @@ message VirtualHost {

// The list of routes that will be matched, in order, for incoming requests.
// The first route that matches will be used.
// Only one of this and `matcher` can be specified.
repeated Route routes = 3;

// [#next-major-version: This should be included in a oneof with routes wrapped in a message.]
// The match tree to use when resolving route actions for incoming requests. Only one of this and `routes`
// can be specified.
xds.type.matcher.v3.Matcher matcher = 21
[(xds.annotations.v3.field_status).work_in_progress = true];

// Specifies the type of TLS enforcement the virtual host expects. If this option is not
// specified, there is no TLS requirement for the virtual host.
TlsRequirementType require_tls = 4 [(validate.rules).enum = {defined_only: true}];
Expand Down
18 changes: 14 additions & 4 deletions docs/root/intro/arch_overview/advanced/matching/matching_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ better performance than the linear list matching as seen in Envoy's HTTP routing
use of extension points to make it easy to extend to different inputs based on protocol or
environment data as well as custom sublinear matchers and direct matchers.

Filter Integration
##################

Within supported environments (currently only HTTP filters), a wrapper proto can be used to
instantiate a matching filter associated with the wrapped structure:

Expand All @@ -28,7 +31,7 @@ The above example wraps a HTTP filter (the
allowing us to define a match tree to be evaluated in conjunction with evaluation of the wrapped
filter. Prior to data being made available to the filter, it will be provided to the match tree,
which will then attempt to evaluate the matching rules with the provided data, triggering an
action if match evaluation completes in an action.
action if match evaluation results in an action.

In the above example, we are specifying that we want to match on the incoming request header
``some-header`` by setting the ``input`` to
Expand All @@ -54,7 +57,7 @@ the filter if ``some-header: skip_filter`` is present and ``second-header`` is s
.. _arch_overview_matching_api_iteration_impact:

HTTP Filter Iteration Impact
============================
****************************

The above example only demonstrates matching on request headers, which ends up being the simplest
case due to it happening before the associated filter receives any data. Matching on other HTTP
Expand All @@ -80,8 +83,15 @@ client will receive an invalid response back from Envoy. If the skip action was
trailers, the same gRPC-Web filter would consume all the data but never write it back out (as this
happens when it sees the trailers), resulting in a gRPC-Web response with an empty body.

HTTP Routing Integration
########################

The matching API can be used with HTTP routing, by specifying a match tree as part of the virtual host
and specifying a Route as the resulting action. See examples in the above sections for how the match
tree can be configured.

Match Tree Validation
=====================
#####################

As the match tree structure is very flexible, some filters might need to impose additional restrictions
on what kind of match trees can be used. This system is somewhat inflexible at the moment, only supporting
Expand All @@ -91,7 +101,7 @@ will fail during configuration load, reporting back which data input was invalid

This is done for example to limit the issues talked about in
:ref:`the above section <arch_overview_matching_api_iteration_impact>` or to help users understand in what
context a match tree can be used for a specific filter. Due to the limitations of the validations framework
context a match tree can be used for a specific filter. Due to the limitations of the validation framework
at the current time, it is not used for all filters.

For HTTP filters, the restrictions are specified by the filter implementation, so consult the individual
Expand Down
60 changes: 60 additions & 0 deletions docs/root/intro/arch_overview/http/http_routing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,63 @@ upon configuration load and cache the contents.

If **response_headers_to_add** has been set for the Route or the enclosing Virtual Host,
Envoy will include the specified headers in the direct HTTP response.

Routing Via Generic Matching
----------------------------

Envoy recently added support for utilzing a :ref:`generic match tree <arch_overview_matching_api>` to
specify the route table. This is a more expressive matching engine than the original one, allowing
for sublinear matching on arbitrary headers (unlike the original matching engine which could only
do this for :authority in some cases).

To use the generic matching tree, specify a matcher on a virtual host with a RouteAction action:

.. code-block:: yaml
matcher:
"@type": type.googleapis.com/xds.type.matcher.v3.Matcher
matcher_tree:
input:
name: request-headers
typed_config:
"@type": type.googleapis.com/envoy.type.matcher.v3.HttpRequestHeaderMatchInput
header_name: :path
exact_match_map:
map:
"/new_endpoint/foo":
action:
name: route
typed_config:
"@type": type.googleapis.com/envoy.config.route.v3.Route
match:
prefix: /
route:
cluster: cluster_foo
request_headers_to_add:
- header:
key: x-route-header
value: new-value
"/new_endpoint/bar":
action:
name: route
typed_config:
"@type": type.googleapis.com/envoy.config.route.v3.Route
match:
prefix: /
route:
cluster: cluster_bar
request_headers_to_add:
- header:
key: x-route-header
value: new-value
This allows resolving the same Route proto message used for the `routes`-based routing using the additional
matching flexibility provided by the generic matching framework.

Note that the resulting Route also specifies a match criteria. This must be satisfied in addition to resolving
the route in order to achieve a route match. When path rewrites are used, the matched path will only depend on
the match criteria of the resolved Route. Path matching done during the match tree traversal does not contribute
to path rewrites.

The only inputs supported are request headers (via `envoy.type.matcher.v3.HttpRequestHeaderMatchInput`). See
the docs for the :ref:`matching API <arch_overview_matching_api>` for more information about the API as a whole.
13 changes: 7 additions & 6 deletions source/common/matcher/matcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@ namespace Matcher {

template <class ProtoType> class ActionBase : public Action {
public:
ActionBase() : type_name_(ProtoType().GetTypeName()) {}
absl::string_view typeUrl() const override { return staticTypeUrl(); }

absl::string_view typeUrl() const override { return type_name_; }
static absl::string_view staticTypeUrl() {
const static std::string typeUrl = ProtoType().GetTypeName();

private:
const std::string type_name_;
return typeUrl;
}
};

struct MaybeMatchResult {
Expand Down Expand Up @@ -72,9 +73,9 @@ template <class DataType> using DataInputFactoryCb = std::function<DataInputPtr<
template <class DataType, class ActionFactoryContext> class MatchTreeFactory {
public:
MatchTreeFactory(ActionFactoryContext& context,
Server::Configuration::ServerFactoryContext& server_factory_context,
Server::Configuration::ServerFactoryContext& factory_context,
MatchTreeValidationVisitor<DataType>& validation_visitor)
: action_factory_context_(context), server_factory_context_(server_factory_context),
: action_factory_context_(context), server_factory_context_(factory_context),
validation_visitor_(validation_visitor) {}

// TODO(snowp): Remove this type parameter once we only have one Matcher proto.
Expand Down
3 changes: 3 additions & 0 deletions source/common/router/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,13 @@ envoy_cc_library(
"//source/common/http:headers_lib",
"//source/common/http:path_utility_lib",
"//source/common/http:utility_lib",
"//source/common/http/matching:data_impl_lib",
"//source/common/matcher:matcher_lib",
"//source/common/protobuf:utility_lib",
"//source/common/tracing:http_tracer_lib",
"//source/common/upstream:retry_factory_lib",
"//source/extensions/filters/http/common:utility_lib",
"@envoy_api//envoy/config/common/matcher/v3:pkg_cc_proto",
"@envoy_api//envoy/config/core/v3:pkg_cc_proto",
"@envoy_api//envoy/config/route/v3:pkg_cc_proto",
"@envoy_api//envoy/type/matcher/v3:pkg_cc_proto",
Expand Down
Loading

0 comments on commit 94d0013

Please sign in to comment.