From 6e574036e8495a1c454b7a7de1a07fce104f2d8d Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Wed, 12 Nov 2025 00:33:20 -0800 Subject: [PATCH 01/30] Abstract, background, impl, env var protection, proto validation --- A106-xds-unified-matcher-and-cel.md | 275 ++++++++++++++-------------- 1 file changed, 139 insertions(+), 136 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 42ccbedfe..65d6d3328 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -1,24 +1,20 @@ A106: xDS Unified Matcher and CEL Integration ====== -* Author(s): Sergii Tkachenko (@sergiitk) -* Approver: Mark Roth (@markdroth) -* Status: In Review -* Last updated: 2025-11-03 -* Discussion at: - - [ ] TODO(sergiitk): insert google group thread +* Author(s): Sergii Tkachenko (@sergiitk) +* Approver: Mark Roth (@markdroth) +* Status: In Review +* Last updated: 2025-11-03 +* Discussion at: + - [ ] TODO(sergiitk): insert google group thread ## Abstract We will add support for the xDS [Unified Matcher API] and -[Common Expression Language](cel.dev) (CEL) within gRPC. This integration will -enable advanced, flexible matching capabilities for various xDS-managed -features, such as server-side rate limiting (RLQS, [A77]), external -authorization (ExtAuthz, [A92]), and external processing (ExtProc, [A93]). - -> [!WARNING] TODO(sergiitk): q: is this really needed for ExtAuthz, ExtProc? -> a: no, needed for composite filter, https://github.com/grpc/proposal/pull/511 - +[Common Expression Language] (CEL) within gRPC. This integration will enable +advanced, flexible matching capabilities for various xDS-managed features, such +as server-side rate limiting (RLQS, [A77]), Role Based Access Control (RBAC, +[A41]), and Composite Filter ([A103]). ## Background @@ -28,19 +24,32 @@ its custom mechanisms for performing assertion against response/request metadata. The Unified Matcher API was introduced to standardize and unify these matching capabilities across various xDS components. -> [!WARNING] TODO(sergiitk): finish +[Common Expression Language](CEL) is an open-source, non-Turing complete +expression language designed for evaluating expressions quickly and safely. It +is commonly used in authorization, policy enforcement, and data validation +scenarios. CEL expressions are evaluated against a set of input variables and +can perform operations such as comparisons, logical operations, string +manipulations, and map/list indexing. + +CEL is particularly well-suited for xDS because it allows the control plane to +push user-defined matching logic to gRPC clients, while CEL's non-Turing +complete nature ensures safe and predictable execution. + +The Unified Matcher API is designed to be extensible, allowing for different +types of inputs and matching logic to be plugged in. CEL integration is achieved +through this extension mechanism, where CEL expressions can be used as a +powerful, flexible and safe custom matcher. This allows for complex, dynamic +request matching based on a wide range of request attributes. ### Related Proposals -* [gRFC A41: xDS RBAC Support][A41] -* [gRFC A77: xDS Server-Side Rate Limiting][A77] (WIP) -* [gRFC A92: xDS ExtAuthz Support][A92] (WIP) -* [gRFC A93: xDS ExtProc Support][A93] (WIP) +* [gRFC A41: xDS RBAC Support][A41] +* [gRFC A77: xDS Server-Side Rate Limiting][A77] (WIP) +* [gRFC A103: xDS Composite Filter][A103] (WIP) [A41]: A41-xds-rbac.md [A77]: https://github.com/grpc/proposal/pull/414 -[A92]: https://github.com/grpc/proposal/pull/481 -[A93]: https://github.com/grpc/proposal/pull/484 +[A103]: https://github.com/grpc/proposal/pull/511 [Unified Matcher API]: https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/advanced/matching/matching_api.html [Unified Matcher API Support]: #unified-matcher-api-support @@ -56,22 +65,25 @@ matching capabilities across various xDS components. [Unified Matcher: `StringMatcher`]: #unified-matcher-stringmatcher [Unified Matcher: `CelMatcher`]: #unified-matcher-celmatcher +[Common Expression Language]: https://cel.dev [`cel.expr.CheckedExpr`]: https://github.com/google/cel-spec/blob/master/proto/cel/expr/checked.proto [CEL Integration]: #cel-integration [CEL Runtime Restrictions]: #cel-runtime-restrictions [Supported CEL Variables]: #supported-cel-variables +[`TypedExtensionConfig`]: https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/core/v3/extension.proto#L14 + ## Proposal ### Unified Matcher API Support -> [!WARNING] TODO(sergiitk): good idea to executing parse matching tree, add a few examples. here's how matching should work in these cases. +> [!WARNING] TODO(sergiitk): good idea to executing parse matching tree, add a +> few examples. here's how matching should work in these cases. > > implementation and test suite: > https://github.com/grpc/grpc/blob/master/test/core/xds/xds_matcher_test.cc > https://github.com/grpc/grpc/blob/master/test/core/xds/xds_matcher_parse_test.cc - Envoy provides two syntactically equivalent Unified Matcher definitions: [`envoy.config.common.matcher.v3.Matcher`](https://github.com/envoyproxy/envoy/blob/e3da7ebb16ad01c2ac7662758a75dba5cdc024ce/api/envoy/config/common/matcher/v3/matcher.proto) and @@ -90,7 +102,7 @@ In this iteration the following Unified Mather extensions will be supported: 1. [Unified Matcher: `HttpRequestHeaderMatchInput`] 2. [Unified Matcher: `HttpAttributesCelMatchInput`] 2. Matchers: - 1. [Unified Matcher: `StringMatcher`] (standard matcher) + 1. [Unified Matcher: `StringMatcher`](standard matcher) 2. [Unified Matcher: `CelMatcher`] #### Unified Matcher: Filter Integration @@ -100,29 +112,29 @@ When implementing Unified Matcher API, a filter must define the following: - Supported protocol-specific actions (see [Unified Matcher: `OnMatch`]). - Supported [Unified Matcher: Input Extensions]. - Supported [Unified Matcher: Matching Extensions], including any additional - limitations on their inputs. - > [!WARNING] TODO(sergiitk): remove, clarify this is based on return type of the input + limitations on their inputs. > [!WARNING] TODO(sergiitk): remove, clarify + this is based on return type of > the input - Filter-specific default no-match behavior (f.e. xDS resource NACK). #### Unified Matcher: `Matcher` While the Unified Matcher API allows for matcher trees of arbitrary depth, gRPC -will reject any matcher definition with a tree depth greater than `16`, NACKing +will reject any matcher definition with a tree depth g the xDS resource. We will support the following fields in the [`xds.type.matcher.v3.Matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L22) message: -- `matcher_type`: One of the following must be present and valid: - - [`matcher_list`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L126): - A valid [Unified Matcher: `MatcherList`] message. - - [`matcher_tree`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L129): - A valid [Unified Matcher: `MatcherTree`] message. +- `matcher_type`: One of the following must be present: + - [`matcher_list`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L126) + ([Unified Matcher: `MatcherList`]). + - [`matcher_tree`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L129) + ([Unified Matcher: `MatcherTree`]). - [`on_no_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L135): - Specifies the action executed if no match is found in the `matcher_list` or - `matcher_tree`. If set, must be a valid [Unified Matcher: `OnMatch`]. - If not set, refer to filter's default no-match behavior. + ([Unified Matcher: `OnMatch`]): Specifies the action executed if no match is + found in the `matcher_list` or `matcher_tree`. If not set, refer to filter's + [default no-match behavior][Unified Matcher: Filter Integration]. #### Unified Matcher: `OnMatch` @@ -130,13 +142,14 @@ We will support the following fields in the [`xds.type.matcher.v3.Matcher.OnMatch`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L24) message: -- `on_match`: One of the following must be present and valid: - - [`matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L33): - A nested [Unified Matcher: `Matcher`] for more complex, tree-like - matching logic. - - [`action`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L36): - A [`TypedExtensionConfig`] containing a protocol-specific action to - take. +- `on_match`: One of the following must be present: + - [`matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L33) + ([Unified Matcher: `Matcher`]): A nested matcher that allows for + building more complex, tree-like matching logic. + - [`action`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L36) + ([`TypedExtensionConfig`]): If set, must contain one of the + protocol-specific actions + [supported by the filter][Unified Matcher: Filter Integration]. The following fields will be ignored by gRPC: @@ -147,62 +160,55 @@ The following fields will be ignored by gRPC: #### Unified Matcher: `MatcherList` -> [!WARNING] TODO(sergiitk): format: no need to specify "valid" message when it's already implied +[`Matcher.MatcherList.Predicate`]: https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L45 +[`Matcher.MatcherList.Predicate.PredicateList`]: https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L65 We will support the following fields in the [`xds.type.matcher.v3.Matcher.MatcherList`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L43) message: -- [`matchers`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L96): - A list of - [`Matcher.MatcherList.FieldMatcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L87) - messages. Must contain at least 1 item. - - [`predicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L89): - Must be set and contain a valid - [`Matcher.MatcherList.Predicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L45) - message. - - `match_type`: One of the following must be present and valid: - - [`single_predicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L73): - A - [`Matcher.MatcherList.Predicate.SinglePredicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L47) - message. The return type of the input must match the input type - of the matcher. - - [`input`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L50): - A valid [`TypedExtensionConfig`]. Must be present and - contain one of the input extensions +- [`matchers`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L96) + (repeated + [`Matcher.MatcherList.FieldMatcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L87)): + Must contain at least 1 item. + - [`predicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L89) + ([`Matcher.MatcherList.Predicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L45)): + Must be present. + - `match_type`: One of the following must be present: + - [`single_predicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L73) + ([`Matcher.MatcherList.Predicate.SinglePredicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L47)): + If set, the return type of the `input` must match the input type + of the `matcher`. + - [`input`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L50) + ([`TypedExtensionConfig`]): Must be present and contain one + of the input extensions [supported by the filter][Unified Matcher: Filter Integration]. Must have return type compatible with the `matcher`. - - `matcher`: One of the following must be present and valid: - - [`value_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L56): - A valid [Unified Matcher: `StringMatcher`]. Only - compatible with `input` that returns a string. - - [`custom_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L60): - A valid [`TypedExtensionConfig`] containing one of the + - `matcher`: One of the following must be present: + - [`value_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L56) + ([Unified Matcher: `StringMatcher`]): Only compatible + with `input` that returns a string. + - [`custom_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L60) + ([`TypedExtensionConfig`]): Must contain one of the matching extensions [supported by the filter][Unified Matcher: Filter Integration]. Must have input type compatible with the `input`. Must return a boolean indicating the status of the match. - - [`or_matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L76): - A - [`Matcher.MatcherList.Predicate.PredicateList`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L65) - message. - - [`predicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L66): - A list of `Matcher.MatcherList.Predicate` messages. Must - contain at least 2 items. Returns true if any of them are - true. - - [`and_matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L79): - A - [`Matcher.MatcherList.Predicate.PredicateList`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L65) - message. - - [`predicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L66): - A list of `Matcher.MatcherList.Predicate` messages. Must - contain at least 2 items. Returns true if all of them are - true. - - [`not_matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L82): - A nested `Matcher.MatcherList.Predicate` message. Returns the - inverted result of predicate evaluation. - - [`on_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L92): - Must be set and contain a valid [Unified Matcher: `OnMatch`] message. + - [`or_matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L76) + ([`Matcher.MatcherList.Predicate.PredicateList`]): + - [`predicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L66) + (repeated [`Matcher.MatcherList.Predicate`]): Must contain + at least 2 items. Returns true if any of them are true. + - [`and_matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L79) + ([`Matcher.MatcherList.Predicate.PredicateList`]): + - [`predicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L66) + (repeated [`Matcher.MatcherList.Predicate`]): Must contain + at least 2 items. Returns true if all of them are true. + - [`not_matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L82) + ([`Matcher.MatcherList.Predicate`]): Returns the inverted result + of predicate evaluation. + - [`on_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L92) + ([Unified Matcher: `OnMatch`]): Must be present. #### Unified Matcher: `MatcherTree` @@ -210,29 +216,26 @@ We will support the following fields in the [`xds.type.matcher.v3.Matcher.MatcherTree`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L99) message: -- [`input`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L106): - A valid [`TypedExtensionConfig`]. Must be present and contain one of the - input extensions +- [`input`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L106) + ([`TypedExtensionConfig`]): Must be present and contain one of the input + extensions [supported by the filter][Unified Matcher: Filter Integration]. Must have return type compatible with the `matcher`. -- `tree_type`: One of the following must be present and valid: - - [`exact_match_map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L114): - A - [`Matcher.MatcherTree.MatchMap`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L101) - message. Only compatible with `input` that returns a string. - - [`map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L102): - A map from a string to a valid [Unified Matcher: `OnMatch`] message. - Must contain at least 1 pair. - - [`prefix_match_map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L117): - A - [`Matcher.MatcherTree.MatchMap`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L101) - message. Only compatible with `input` that returns a string. - - [`map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L102): - A map from a string to a valid [Unified Matcher: `OnMatch`] message. - Must contain at least 1 pair. - - [`custom_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L120): - A valid [`TypedExtensionConfig`] containing one of the matching - extensions +- `tree_type`: One of the following must be present: + - [`exact_match_map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L114) + ([`Matcher.MatcherTree.MatchMap`]): Only compatible with `input` that + returns a string. + - [`map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L102) + (map): Must contain at least 1 + pair. + - [`prefix_match_map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L117) + ([`Matcher.MatcherTree.MatchMap`]): Only compatible with `input` that + returns a string. + - [`map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L102) + (map): Must contain at least 1 + pair. + - [`custom_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L120) + ([`TypedExtensionConfig`]): Must contain one of the matching extensions [supported by the filter][Unified Matcher: Filter Integration]. Must have input type compatible with the `input`. Must return a boolean indicating the status of the match. @@ -273,7 +276,7 @@ We will support the following fields in the [`xds.type.matcher.v3.StringMatcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/string.proto#L19) message: -- `match_pattern`: One of the following must be present and valid: +- `match_pattern`: One of the following must be present: - [`exact`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/string.proto#L28): The input string must match exactly. An empty string is a valid value. - [`prefix`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/string.proto#L36): @@ -295,20 +298,18 @@ result in xDS resource NACK: Compatible with [Unified Matcher: `HttpAttributesCelMatchInput`]. -Performs a match by evaluating a Common Expression Language (CEL) expression. +Performs a match by evaluating a [Common Expression Language] (CEL) expression. See [CEL Integration] for details. We will support the following fields in the [`xds.type.matcher.v3.CelMatcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/cel.proto#L30) message: -- [`expr_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/cel.proto#L32): - Must be present and contain a valid - [`xds.type.v3.CelExpression`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L26) - message. - - [`cel_expr_checked`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L49): - Must be present and contain a valid [`cel.expr.CheckedExpr`] message. - This message will be converted into a native CEL Abstract Syntax Tree +- [`expr_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/cel.proto#L32) + ([`xds.type.v3.CelExpression`]): Must be present. + - [`cel_expr_checked`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L49) + ([`cel.expr.CheckedExpr`]): Must be present. This message will be + converted into a native CEL Abstract Syntax Tree (AST) using the language-specific CEL library. The AST's output (return) type must be boolean. The resulting CEL program must also be validated to conform to [CEL Runtime Restrictions]. If any of these conversion or @@ -336,8 +337,8 @@ and CEL interpreter configuration. #### CEL Runtime Restrictions Certain CEL features can lead to superlinear time complexity or memory -exhaustion. To ensure consistent behavior with Envoy and maintain security, -gRPC will configure the CEL runtime +exhaustion. To ensure consistent behavior with Envoy and maintain security, gRPC +will configure the CEL runtime [similar to Envoy](https://github.com/envoyproxy/envoy/blob/c57801c2afbe26dd6fad7f5ce764f267d07fbd04/source/extensions/filters/common/expr/evaluator.cc#L17-L23): ```c @@ -359,8 +360,8 @@ options.enable_list_concat = false; #### Supported CEL Functions -Similar to Envoy, we will -support [standard CEL functions](https://github.com/google/cel-spec/blob/c629b2be086ed6b4c44ef4975e56945f66560677/doc/langdef.md#standard-definitions) +Similar to Envoy, we will support +[standard CEL functions](https://github.com/google/cel-spec/blob/c629b2be086ed6b4c44ef4975e56945f66560677/doc/langdef.md#standard-definitions) except comprehension-style macros. | CEL Method | Description | @@ -403,31 +404,33 @@ for gRPC. ##### Footnotes -**1 `request.method`**\ +**1 `request.method`** \ Hard-coded to `"POST"` if unavailable and a code audit confirms the server denies requests for all other method types. -**2 `request.headers`**\ +**2 `request.headers`** \ As defined in [A41], "header" field. -> [!WARNING] TODO(sergiitk): comment: Response attributes are needed for ext_proc +> [!WARNING] TODO(sergiitk): comment: Response attributes are needed for +> ext_proc ##### CEL Variable Implementation Details For performance reasons, CEL variables should be resolved on demand. CEL Runtime provides the different variable resolving approaches based on the language: -* CPP: [`BaseActivation::FindValue()`](https://github.com/google/cel-cpp/blob/9310c4910e598362695930f0e11b7f278f714755/eval/public/base_activation.h#L35) -* Go: [`Activation.ResolveName(string)`](https://github.com/google/cel-go/blob/3f12ecad39e2eb662bcd82b6391cfd0cb4cb1c5e/interpreter/activation.go#L30) -* Java: [`CelVariableResolver`](https://javadoc.io/doc/dev.cel/runtime/0.6.0/dev/cel/runtime/CelVariableResolver.html) +- CPP: + [`BaseActivation::FindValue()`](https://github.com/google/cel-cpp/blob/9310c4910e598362695930f0e11b7f278f714755/eval/public/base_activation.h#L35) +- Go: + [`Activation.ResolveName(string)`](https://github.com/google/cel-go/blob/3f12ecad39e2eb662bcd82b6391cfd0cb4cb1c5e/interpreter/activation.go#L30) +- Java: + [`CelVariableResolver`](https://javadoc.io/doc/dev.cel/runtime/0.6.0/dev/cel/runtime/CelVariableResolver.html) ### Temporary Environment Variable Protection -> [!WARNING] TODO(sergiitk): update env var - -During initial development, this feature will be enabled via -the `GRPC_EXPERIMENTAL_XDS_ENABLE_RLQS` environment variable. This environment -variable protection will be removed once the feature has proven stable. +The Unified Matcher API feature will not be guarded by a dedicated environment +variable. The environment variable protection will be handled by the features +that depend on it (e.g., `GRPC_EXPERIMENTAL_XDS_ENABLE_RLQS` for RLQS). ## Rationale @@ -435,8 +438,8 @@ variable protection will be removed once the feature has proven stable. ## Implementation -> [!WARNING] TODO(sergiitk): update impl notes - Will be implemented in C-core, Java, Go, and Node as part of either RLQS -([A77]), ExtAuthz ([A92]), or ExtProc ([A93]), whichever happens to be -implemented first in any given language. +([A77]) or Composite Filter ([A103]), whichever happens to be implemented first +in any given language. Role Based Access Control (RBAC, [A41]) currently does +not support the Unified Matcher API in gRPC, though it is supported by Envoy. +This may be extended in the future. From 347a61dd2cba6770f7c28a0703d788435fd40985 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Fri, 14 Nov 2025 12:59:49 -0800 Subject: [PATCH 02/30] MatcherTree --- A106-xds-unified-matcher-and-cel.md | 30 +++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 65d6d3328..f19e05ea7 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -192,8 +192,7 @@ message: ([`TypedExtensionConfig`]): Must contain one of the matching extensions [supported by the filter][Unified Matcher: Filter Integration]. - Must have input type compatible with the `input`. Must - return a boolean indicating the status of the match. + Must be compatible with the return type of the `input`. - [`or_matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L76) ([`Matcher.MatcherList.Predicate.PredicateList`]): - [`predicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L66) @@ -212,6 +211,8 @@ message: #### Unified Matcher: `MatcherTree` +[`Matcher.MatcherTree.MatchMap`]: https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L101 + We will support the following fields in the [`xds.type.matcher.v3.Matcher.MatcherTree`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L99) message: @@ -220,25 +221,27 @@ message: ([`TypedExtensionConfig`]): Must be present and contain one of the input extensions [supported by the filter][Unified Matcher: Filter Integration]. Must have - return type compatible with the `matcher`. + return type compatible with each matcher specified in the tree. - `tree_type`: One of the following must be present: - [`exact_match_map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L114) ([`Matcher.MatcherTree.MatchMap`]): Only compatible with `input` that - returns a string. + returns a `string`. - [`map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L102) - (map): Must contain at least 1 - pair. + A map from a `string` to [Unified Matcher: `OnMatch`]. Must contain + at least 1 pair. - [`prefix_match_map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L117) ([`Matcher.MatcherTree.MatchMap`]): Only compatible with `input` that - returns a string. + returns a `string`. - [`map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L102) - (map): Must contain at least 1 - pair. + A map from a `string` to [Unified Matcher: `OnMatch`]. Must contain + at least 1 pair. - [`custom_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L120) ([`TypedExtensionConfig`]): Must contain one of the matching extensions - [supported by the filter][Unified Matcher: Filter Integration]. Must - have input type compatible with the `input`. Must return a boolean - indicating the status of the match. + [supported by the filter][Unified Matcher: Filter Integration]. Must be + compatible with the return type of the `input`. + +> [!WARNING] TODO(sergiitk): MatcherTree.custom_match +> check what actually goes into `custom_match` for `MatcherTree` #### Unified Matcher: Input Extensions @@ -268,6 +271,9 @@ message: #### Unified Matcher: Matching Extensions +Matching extensions must return a boolean that indicates the status of the +match. + ##### Unified Matcher: `StringMatcher` Compatible with [Unified Matcher: Input Extensions] that return a `string`. From f3dd1d97abe593c1d7b60684025e6f38c61a5227 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Fri, 14 Nov 2025 17:05:12 -0800 Subject: [PATCH 03/30] CelExpression --- A106-xds-unified-matcher-and-cel.md | 52 +++++++++++++++++++---------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index f19e05ea7..01a6a8d42 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -67,7 +67,10 @@ request matching based on a wide range of request attributes. [Common Expression Language]: https://cel.dev [`cel.expr.CheckedExpr`]: https://github.com/google/cel-spec/blob/master/proto/cel/expr/checked.proto + + [CEL Integration]: #cel-integration +[`CelExpression` message]: #celexpression-message [CEL Runtime Restrictions]: #cel-runtime-restrictions [Supported CEL Variables]: #supported-cel-variables @@ -312,34 +315,49 @@ We will support the following fields in the message: - [`expr_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/cel.proto#L32) - ([`xds.type.v3.CelExpression`]): Must be present. - - [`cel_expr_checked`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L49) - ([`cel.expr.CheckedExpr`]): Must be present. This message will be - converted into a native CEL Abstract Syntax Tree - (AST) using the language-specific CEL library. The AST's output (return) - type must be boolean. The resulting CEL program must also be validated - to conform to [CEL Runtime Restrictions]. If any of these conversion or - validation steps fail, gRPC will NACK the xDS resource. + ([`xds.type.v3.CelExpression`][`CelExpression` message]): Must be present. - [`description`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/cel.proto#L36): An optional string. May be ignored or used for testing/debugging. -The following fields will be ignored by gRPC: - -- `CelExpression.parsed_expr` - deprecated, only Canonical CEL is supported. -- `CelExpression.checked_expr` - deprecated, only Canonical CEL is supported. -- `CelExpression.cel_expr_parsed` - only Checked CEL expressions are - supported. - ### CEL Integration -We will support request metadata matching via CEL expressions. Only Canonical -CEL and only checked expressions will be supported [`cel.expr.CheckedExpr`]. +We will support request metadata matching via CEL expressions. CEL evaluation environment is a set of available variables and extension functions in a CEL program. We will match [Envoy CEL environment](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/advanced/attributes) and CEL interpreter configuration. +#### `CelExpression` message + +[`xds.type.v3.CelExpression`]: https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L26 + +CEL expressions will be provided by the xDS Control Plane in the +[`xds.type.v3.CelExpression`] message, which allows to specify CEL Abstract +Syntax Tree (AST) in different forms (e.g., `googleapis` or canonical, and each +may be either parsed or checked). We will only support one form: type-checked +Canonical CEL, specifically the [`cel.expr.CheckedExpr`] message. + +We will support the following fields in the +[`xds.type.v3.CelExpression`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/cel.proto#L30) +message: + +- ([`xds.type.v3.CelExpression`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L26)): + Must be present. + - [`cel_expr_checked`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L49) + ([`cel.expr.CheckedExpr`]): Must be present. This message will be + converted into a native CEL Abstract Syntax Tree (AST) using the + language-specific CEL library. The AST's output (return) type must be + boolean. The resulting CEL program must also be validated to conform to + [CEL Runtime Restrictions]. If the conversion or the validation step + fail, gRPC will NACK the xDS resource. + +The following fields will be ignored by gRPC: + +- `parsed_expr` - deprecated, only Canonical CEL is supported. +- `checked_expr` - deprecated, only Canonical CEL is supported. +- `cel_expr_parsed` - only Checked CEL expressions are supported. + #### CEL Runtime Restrictions Certain CEL features can lead to superlinear time complexity or memory From b76a1806b5dd0d814c6fc12e48e26957bf506824 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Sat, 15 Nov 2025 00:19:49 -0800 Subject: [PATCH 04/30] CelExtractString --- A106-xds-unified-matcher-and-cel.md | 47 +++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 01a6a8d42..b55e21b18 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -4,9 +4,8 @@ A106: xDS Unified Matcher and CEL Integration * Author(s): Sergii Tkachenko (@sergiitk) * Approver: Mark Roth (@markdroth) * Status: In Review -* Last updated: 2025-11-03 -* Discussion at: - - [ ] TODO(sergiitk): insert google group thread +* Last updated: 2025-11-15 +* Discussion at: TODO(sergiitk): insert google group thread ## Abstract @@ -52,7 +51,6 @@ request matching based on a wide range of request attributes. [A103]: https://github.com/grpc/proposal/pull/511 [Unified Matcher API]: https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/advanced/matching/matching_api.html -[Unified Matcher API Support]: #unified-matcher-api-support [Unified Matcher: Filter Integration]: #unified-matcher-filter-integration [Unified Matcher: Input Extensions]: #unified-matcher-input-extensions [Unified Matcher: Matching Extensions]: #unified-matcher-matching-extensions @@ -68,12 +66,13 @@ request matching based on a wide range of request attributes. [Common Expression Language]: https://cel.dev [`cel.expr.CheckedExpr`]: https://github.com/google/cel-spec/blob/master/proto/cel/expr/checked.proto - [CEL Integration]: #cel-integration [`CelExpression` message]: #celexpression-message [CEL Runtime Restrictions]: #cel-runtime-restrictions +[Supported CEL Functions]: #supported-cel-functions [Supported CEL Variables]: #supported-cel-variables +[`StringValue`]: https://protobuf.dev/reference/protobuf/google.protobuf/#string-value [`TypedExtensionConfig`]: https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/core/v3/extension.proto#L14 ## Proposal @@ -316,6 +315,11 @@ message: - [`expr_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/cel.proto#L32) ([`xds.type.v3.CelExpression`][`CelExpression` message]): Must be present. + This message will be converted into a native CEL Abstract Syntax Tree (AST) + using the language-specific CEL library. The AST's output (return) type must + be boolean. The resulting CEL program must also be validated to conform to + [CEL Runtime Restrictions] and only contain [Supported CEL Variables]. If + the conversion or the validation step fail, gRPC will NACK the xDS resource. - [`description`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/cel.proto#L36): An optional string. May be ignored or used for testing/debugging. @@ -345,12 +349,7 @@ message: - ([`xds.type.v3.CelExpression`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L26)): Must be present. - [`cel_expr_checked`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L49) - ([`cel.expr.CheckedExpr`]): Must be present. This message will be - converted into a native CEL Abstract Syntax Tree (AST) using the - language-specific CEL library. The AST's output (return) type must be - boolean. The resulting CEL program must also be validated to conform to - [CEL Runtime Restrictions]. If the conversion or the validation step - fail, gRPC will NACK the xDS resource. + ([`cel.expr.CheckedExpr`]): Must be present. The following fields will be ignored by gRPC: @@ -358,6 +357,28 @@ The following fields will be ignored by gRPC: - `checked_expr` - deprecated, only Canonical CEL is supported. - `cel_expr_parsed` - only Checked CEL expressions are supported. +#### `CelExtractString` message + +`CelExtractString` is a small tool that allows to extract a string from +[Supported CEL Variables] using a CEL expression. The expression must evaluate +to a `string`. + +We will support the following fields in the +[`xds.type.matcher.v3.CelExtractString`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L62) +message: + +- [`expr_extract`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#65) + ([`xds.type.v3.CelExpression`][`CelExpression` message]): Must be present. + This message will be converted into a native CEL Abstract Syntax Tree (AST) + using the language-specific CEL library. The AST's output (return) type must + be a `string`. It may only contain [Supported CEL Functions] and + [Supported CEL Variables]. The resulting CEL program must also be validated + to conform to [CEL Runtime Restrictions]. If the conversion or the + validation step fail, gRPC will NACK the xDS resource. +- [`default_value`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L69): + ([`StringValue`]) Optional. If set, and the CEL expression evaluates to an + error or a non-string type, this default value will be returned instead. + #### CEL Runtime Restrictions Certain CEL features can lead to superlinear time complexity or memory @@ -465,5 +486,5 @@ that depend on it (e.g., `GRPC_EXPERIMENTAL_XDS_ENABLE_RLQS` for RLQS). Will be implemented in C-core, Java, Go, and Node as part of either RLQS ([A77]) or Composite Filter ([A103]), whichever happens to be implemented first in any given language. Role Based Access Control (RBAC, [A41]) currently does -not support the Unified Matcher API in gRPC, though it is supported by Envoy. -This may be extended in the future. +not support the Unified Matcher API in gRPC, though it is supported by Envoy, +but it may be added in the future. From 59e91a7e32474d8dde6ca0e79f0b1c852866399f Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Sat, 15 Nov 2025 00:25:36 -0800 Subject: [PATCH 05/30] minor change to Unified Matcher definitions note --- A106-xds-unified-matcher-and-cel.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index b55e21b18..3fec6cdd7 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -90,15 +90,10 @@ Envoy provides two syntactically equivalent Unified Matcher definitions: [`envoy.config.common.matcher.v3.Matcher`](https://github.com/envoyproxy/envoy/blob/e3da7ebb16ad01c2ac7662758a75dba5cdc024ce/api/envoy/config/common/matcher/v3/matcher.proto) and [`xds.type.matcher.v3.Matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto), -which is the preferred version for all new APIs using Unified Matcher. +which is the preferred version for all new APIs using Unified Matcher. We will +produce the same form for either one. -Will produce the same form for either one. - - - -In this iteration the following Unified Mather extensions will be supported: +In this iteration, the following Unified Mather extensions will be supported: 1. Inputs: 1. [Unified Matcher: `HttpRequestHeaderMatchInput`] From 9d02d64334f7f6f3feca91cae5ecb232812f5db1 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Mon, 17 Nov 2025 22:27:33 -0800 Subject: [PATCH 06/30] Improve Unified Matcher: Filter Integration --- A106-xds-unified-matcher-and-cel.md | 42 ++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 3fec6cdd7..32713e523 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -104,19 +104,43 @@ In this iteration, the following Unified Mather extensions will be supported: #### Unified Matcher: Filter Integration -When implementing Unified Matcher API, a filter must define the following: +When implementing Unified Matcher API, a filter must define the following for +each [Unified Matcher: `Matcher`] field in its config: -- Supported protocol-specific actions (see [Unified Matcher: `OnMatch`]). -- Supported [Unified Matcher: Input Extensions]. -- Supported [Unified Matcher: Matching Extensions], including any additional - limitations on their inputs. > [!WARNING] TODO(sergiitk): remove, clarify - this is based on return type of > the input -- Filter-specific default no-match behavior (f.e. xDS resource NACK). +1. Supported protocol-specific actions. +2. Supported [Unified Matcher: Input Extensions]. +3. Filter-specific behavior for unsuccessful matches. + +Note that the selection of input extensions defines the +[Unified Matcher: Matching Extensions] that can be used with the filter. + +##### Protocol-Specific Actions + +Protocol-specific actions are used in +[`OnMatch.action`][Unified Matcher: `OnMatch`] and may be any protocol-specific +message packed into [`TypedExtensionConfig`]. + +The filter implementing the Unified Matcher API must define the set of +protocol-specific actions it supports. If an action is not supported, gRPC will +NACK the xDS resource. + +The filter must define the supported fields and proto validation rules for each +protocol-specific action. + +##### Behavior for Unsuccessful Matches + +The match is considered unsuccessful: + +1. If no match found after evaluating the [Unified Matcher: `Matcher`] AND +2. `on_no_match` field is unset OR its evaluation is unsuccessful. + +The filter may define any behavior for an unsuccessful match, f.e. NACK the xDS +resource, failing open/closed, etc. #### Unified Matcher: `Matcher` While the Unified Matcher API allows for matcher trees of arbitrary depth, gRPC -will reject any matcher definition with a tree depth g +will reject any matcher definition with a tree depth greater than `16`, NACKing the xDS resource. We will support the following fields in the @@ -131,7 +155,7 @@ message: - [`on_no_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L135): ([Unified Matcher: `OnMatch`]): Specifies the action executed if no match is found in the `matcher_list` or `matcher_tree`. If not set, refer to filter's - [default no-match behavior][Unified Matcher: Filter Integration]. + [unsuccessful match behavior][Unified Matcher: Filter Integration]. #### Unified Matcher: `OnMatch` From fab0a4b22b0d6a98a7ce7538629e30de00a79a3a Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Mon, 17 Nov 2025 23:50:23 -0800 Subject: [PATCH 07/30] MatcherTree.custom_match not supported --- A106-xds-unified-matcher-and-cel.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 32713e523..09227e7be 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -124,8 +124,8 @@ The filter implementing the Unified Matcher API must define the set of protocol-specific actions it supports. If an action is not supported, gRPC will NACK the xDS resource. -The filter must define the supported fields and proto validation rules for each -protocol-specific action. +Upon a successful match, the matched action will be returned as the result of +the matcher tree evaluation. ##### Behavior for Unsuccessful Matches @@ -256,13 +256,11 @@ message: - [`map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L102) A map from a `string` to [Unified Matcher: `OnMatch`]. Must contain at least 1 pair. - - [`custom_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L120) - ([`TypedExtensionConfig`]): Must contain one of the matching extensions - [supported by the filter][Unified Matcher: Filter Integration]. Must be - compatible with the return type of the `input`. -> [!WARNING] TODO(sergiitk): MatcherTree.custom_match -> check what actually goes into `custom_match` for `MatcherTree` +The following are not supported by gRPC in the initial implementation and will +result in xDS resource NACK: + +- `custom_match` #### Unified Matcher: Input Extensions From 58c61af53f8fe46a05f4c3f4c37ec47470544452 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Tue, 18 Nov 2025 01:11:49 -0800 Subject: [PATCH 08/30] fix envoy references and some missing line numbers --- A106-xds-unified-matcher-and-cel.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 09227e7be..047b6ef34 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -87,7 +87,7 @@ request matching based on a wide range of request attributes. > https://github.com/grpc/grpc/blob/master/test/core/xds/xds_matcher_parse_test.cc Envoy provides two syntactically equivalent Unified Matcher definitions: -[`envoy.config.common.matcher.v3.Matcher`](https://github.com/envoyproxy/envoy/blob/e3da7ebb16ad01c2ac7662758a75dba5cdc024ce/api/envoy/config/common/matcher/v3/matcher.proto) +[`envoy.config.common.matcher.v3.Matcher`](https://github.com/envoyproxy/envoy/blob/426cd861187368163b42fce910ab5828f7f0b392/api/envoy/config/common/matcher/v3/matcher.proto) and [`xds.type.matcher.v3.Matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto), which is the preferred version for all new APIs using Unified Matcher. We will @@ -270,7 +270,7 @@ Returns a `string` containing the value of the header with name specified in `header_name`. We will support the following fields in the -[`envoy.type.matcher.v3.HttpRequestHeaderMatchInput`](https://github.com/envoyproxy/envoy/blob/7ebdf6da0a49240778fd6fed42670157fde371db/api/envoy/type/matcher/v3/http_inputs.proto#L22) +[`envoy.type.matcher.v3.HttpRequestHeaderMatchInput`](https://github.com/envoyproxy/envoy/blob/426cd861187368163b42fce910ab5828f7f0b392/api/envoy/type/matcher/v3/http_inputs.proto#L22) message: - [`header_name`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L106): @@ -384,7 +384,7 @@ We will support the following fields in the [`xds.type.matcher.v3.CelExtractString`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L62) message: -- [`expr_extract`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#65) +- [`expr_extract`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L65) ([`xds.type.v3.CelExpression`][`CelExpression` message]): Must be present. This message will be converted into a native CEL Abstract Syntax Tree (AST) using the language-specific CEL library. The AST's output (return) type must From 5b4ae8113a9fc1a37cafd631cc90438c2dc7c996 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Tue, 18 Nov 2025 01:58:59 -0800 Subject: [PATCH 09/30] update cncf/xds to 2ac532fd44436293585084f8d94c6bdb17835af0 --- A106-xds-unified-matcher-and-cel.md | 104 ++++++++++++++-------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 047b6ef34..08c79444c 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -73,7 +73,7 @@ request matching based on a wide range of request attributes. [Supported CEL Variables]: #supported-cel-variables [`StringValue`]: https://protobuf.dev/reference/protobuf/google.protobuf/#string-value -[`TypedExtensionConfig`]: https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/core/v3/extension.proto#L14 +[`TypedExtensionConfig`]: https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/core/v3/extension.proto#L14 ## Proposal @@ -89,7 +89,7 @@ request matching based on a wide range of request attributes. Envoy provides two syntactically equivalent Unified Matcher definitions: [`envoy.config.common.matcher.v3.Matcher`](https://github.com/envoyproxy/envoy/blob/426cd861187368163b42fce910ab5828f7f0b392/api/envoy/config/common/matcher/v3/matcher.proto) and -[`xds.type.matcher.v3.Matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto), +[`xds.type.matcher.v3.Matcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto), which is the preferred version for all new APIs using Unified Matcher. We will produce the same form for either one. @@ -144,15 +144,15 @@ will reject any matcher definition with a tree depth greater than `16`, NACKing the xDS resource. We will support the following fields in the -[`xds.type.matcher.v3.Matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L22) +[`xds.type.matcher.v3.Matcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L22) message: - `matcher_type`: One of the following must be present: - - [`matcher_list`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L126) + - [`matcher_list`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L126) ([Unified Matcher: `MatcherList`]). - - [`matcher_tree`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L129) + - [`matcher_tree`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L129) ([Unified Matcher: `MatcherTree`]). -- [`on_no_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L135): +- [`on_no_match`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L135): ([Unified Matcher: `OnMatch`]): Specifies the action executed if no match is found in the `matcher_list` or `matcher_tree`. If not set, refer to filter's [unsuccessful match behavior][Unified Matcher: Filter Integration]. @@ -160,14 +160,14 @@ message: #### Unified Matcher: `OnMatch` We will support the following fields in the -[`xds.type.matcher.v3.Matcher.OnMatch`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L24) +[`xds.type.matcher.v3.Matcher.OnMatch`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L24) message: - `on_match`: One of the following must be present: - - [`matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L33) + - [`matcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L33) ([Unified Matcher: `Matcher`]): A nested matcher that allows for building more complex, tree-like matching logic. - - [`action`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L36) + - [`action`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L36) ([`TypedExtensionConfig`]): If set, must contain one of the protocol-specific actions [supported by the filter][Unified Matcher: Filter Integration]. @@ -181,79 +181,79 @@ The following fields will be ignored by gRPC: #### Unified Matcher: `MatcherList` -[`Matcher.MatcherList.Predicate`]: https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L45 -[`Matcher.MatcherList.Predicate.PredicateList`]: https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L65 +[`Matcher.MatcherList.Predicate`]: https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L45 +[`Matcher.MatcherList.Predicate.PredicateList`]: https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L65 We will support the following fields in the -[`xds.type.matcher.v3.Matcher.MatcherList`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L43) +[`xds.type.matcher.v3.Matcher.MatcherList`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L43) message: -- [`matchers`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L96) +- [`matchers`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L96) (repeated - [`Matcher.MatcherList.FieldMatcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L87)): + [`Matcher.MatcherList.FieldMatcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L87)): Must contain at least 1 item. - - [`predicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L89) - ([`Matcher.MatcherList.Predicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L45)): + - [`predicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L89) + ([`Matcher.MatcherList.Predicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L45)): Must be present. - `match_type`: One of the following must be present: - - [`single_predicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L73) - ([`Matcher.MatcherList.Predicate.SinglePredicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L47)): + - [`single_predicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L73) + ([`Matcher.MatcherList.Predicate.SinglePredicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L47)): If set, the return type of the `input` must match the input type of the `matcher`. - - [`input`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L50) + - [`input`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L50) ([`TypedExtensionConfig`]): Must be present and contain one of the input extensions [supported by the filter][Unified Matcher: Filter Integration]. Must have return type compatible with the `matcher`. - `matcher`: One of the following must be present: - - [`value_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L56) + - [`value_match`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L56) ([Unified Matcher: `StringMatcher`]): Only compatible with `input` that returns a string. - - [`custom_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L60) + - [`custom_match`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L60) ([`TypedExtensionConfig`]): Must contain one of the matching extensions [supported by the filter][Unified Matcher: Filter Integration]. Must be compatible with the return type of the `input`. - - [`or_matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L76) + - [`or_matcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L76) ([`Matcher.MatcherList.Predicate.PredicateList`]): - - [`predicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L66) + - [`predicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L66) (repeated [`Matcher.MatcherList.Predicate`]): Must contain at least 2 items. Returns true if any of them are true. - - [`and_matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L79) + - [`and_matcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L79) ([`Matcher.MatcherList.Predicate.PredicateList`]): - - [`predicate`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L66) + - [`predicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L66) (repeated [`Matcher.MatcherList.Predicate`]): Must contain at least 2 items. Returns true if all of them are true. - - [`not_matcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L82) + - [`not_matcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L82) ([`Matcher.MatcherList.Predicate`]): Returns the inverted result of predicate evaluation. - - [`on_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L92) + - [`on_match`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L92) ([Unified Matcher: `OnMatch`]): Must be present. #### Unified Matcher: `MatcherTree` -[`Matcher.MatcherTree.MatchMap`]: https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L101 +[`Matcher.MatcherTree.MatchMap`]: https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L101 We will support the following fields in the -[`xds.type.matcher.v3.Matcher.MatcherTree`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L99) +[`xds.type.matcher.v3.Matcher.MatcherTree`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L99) message: -- [`input`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L106) +- [`input`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L106) ([`TypedExtensionConfig`]): Must be present and contain one of the input extensions [supported by the filter][Unified Matcher: Filter Integration]. Must have return type compatible with each matcher specified in the tree. - `tree_type`: One of the following must be present: - - [`exact_match_map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L114) + - [`exact_match_map`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L114) ([`Matcher.MatcherTree.MatchMap`]): Only compatible with `input` that returns a `string`. - - [`map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L102) + - [`map`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L102) A map from a `string` to [Unified Matcher: `OnMatch`]. Must contain at least 1 pair. - - [`prefix_match_map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L117) + - [`prefix_match_map`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L117) ([`Matcher.MatcherTree.MatchMap`]): Only compatible with `input` that returns a `string`. - - [`map`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L102) + - [`map`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L102) A map from a `string` to [Unified Matcher: `OnMatch`]. Must contain at least 1 pair. @@ -273,7 +273,7 @@ We will support the following fields in the [`envoy.type.matcher.v3.HttpRequestHeaderMatchInput`](https://github.com/envoyproxy/envoy/blob/426cd861187368163b42fce910ab5828f7f0b392/api/envoy/type/matcher/v3/http_inputs.proto#L22) message: -- [`header_name`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/matcher.proto#L106): +- [`header_name`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L106): Must be present. Value length must be in the range `[1, 16384)`. Must be a valid HTTP/2 header name. @@ -283,7 +283,7 @@ Returns a language-specific interface that allows to access request RPC metadata as defined in [Supported CEL Variables]. We will support the following fields in the -[`xds.type.matcher.v3.HttpAttributesCelMatchInput`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/http_inputs.proto#L22) +[`xds.type.matcher.v3.HttpAttributesCelMatchInput`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/http_inputs.proto#L22) message: - no fields. @@ -298,19 +298,19 @@ match. Compatible with [Unified Matcher: Input Extensions] that return a `string`. We will support the following fields in the -[`xds.type.matcher.v3.StringMatcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/string.proto#L19) +[`xds.type.matcher.v3.StringMatcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/string.proto#L19) message: - `match_pattern`: One of the following must be present: - - [`exact`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/string.proto#L28): + - [`exact`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/string.proto#L28): The input string must match exactly. An empty string is a valid value. - - [`prefix`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/string.proto#L36): + - [`prefix`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/string.proto#L36): The input string must have this prefix. Must be non-empty. - - [`suffix`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/string.proto#L44): + - [`suffix`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/string.proto#L44): The input string must have this suffix. Must be non-empty. - - [`contains`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/string.proto#L55): + - [`contains`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/string.proto#L55): The input string must contain this substring. Must be non-empty. -- [`ignore_case`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/string.proto#L65): +- [`ignore_case`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/string.proto#L65): If `true`, the matching is case-insensitive. The following are not supported by gRPC in the initial implementation and will @@ -327,17 +327,17 @@ Performs a match by evaluating a [Common Expression Language] (CEL) expression. See [CEL Integration] for details. We will support the following fields in the -[`xds.type.matcher.v3.CelMatcher`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/cel.proto#L30) +[`xds.type.matcher.v3.CelMatcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/cel.proto#L30) message: -- [`expr_match`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/cel.proto#L32) +- [`expr_match`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/cel.proto#L32) ([`xds.type.v3.CelExpression`][`CelExpression` message]): Must be present. This message will be converted into a native CEL Abstract Syntax Tree (AST) using the language-specific CEL library. The AST's output (return) type must be boolean. The resulting CEL program must also be validated to conform to [CEL Runtime Restrictions] and only contain [Supported CEL Variables]. If the conversion or the validation step fail, gRPC will NACK the xDS resource. -- [`description`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/cel.proto#L36): +- [`description`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/cel.proto#L36): An optional string. May be ignored or used for testing/debugging. ### CEL Integration @@ -351,7 +351,7 @@ and CEL interpreter configuration. #### `CelExpression` message -[`xds.type.v3.CelExpression`]: https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L26 +[`xds.type.v3.CelExpression`]: https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L26 CEL expressions will be provided by the xDS Control Plane in the [`xds.type.v3.CelExpression`] message, which allows to specify CEL Abstract @@ -360,12 +360,12 @@ may be either parsed or checked). We will only support one form: type-checked Canonical CEL, specifically the [`cel.expr.CheckedExpr`] message. We will support the following fields in the -[`xds.type.v3.CelExpression`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/matcher/v3/cel.proto#L30) +[`xds.type.v3.CelExpression`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/cel.proto#L30) message: -- ([`xds.type.v3.CelExpression`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L26)): +- ([`xds.type.v3.CelExpression`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L26)): Must be present. - - [`cel_expr_checked`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L49) + - [`cel_expr_checked`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L49) ([`cel.expr.CheckedExpr`]): Must be present. The following fields will be ignored by gRPC: @@ -381,10 +381,10 @@ The following fields will be ignored by gRPC: to a `string`. We will support the following fields in the -[`xds.type.matcher.v3.CelExtractString`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L62) +[`xds.type.matcher.v3.CelExtractString`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L62) message: -- [`expr_extract`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L65) +- [`expr_extract`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L65) ([`xds.type.v3.CelExpression`][`CelExpression` message]): Must be present. This message will be converted into a native CEL Abstract Syntax Tree (AST) using the language-specific CEL library. The AST's output (return) type must @@ -392,7 +392,7 @@ message: [Supported CEL Variables]. The resulting CEL program must also be validated to conform to [CEL Runtime Restrictions]. If the conversion or the validation step fail, gRPC will NACK the xDS resource. -- [`default_value`](https://github.com/cncf/xds/blob/b4127c9b8d78b77423fd25169f05b7476b6ea932/xds/type/v3/cel.proto#L69): +- [`default_value`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L69): ([`StringValue`]) Optional. If set, and the CEL expression evaluates to an error or a non-string type, this default value will be returned instead. From d4f293d1cd5c32320f7fb35b4119e0a0209f74b3 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Tue, 18 Nov 2025 03:38:46 -0800 Subject: [PATCH 10/30] fix xds/type/matcher/v3/matcher.proto line numbers --- A106-xds-unified-matcher-and-cel.md | 60 ++++++++++++++--------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 08c79444c..68d6e799e 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -81,7 +81,7 @@ request matching based on a wide range of request attributes. > [!WARNING] TODO(sergiitk): good idea to executing parse matching tree, add a > few examples. here's how matching should work in these cases. -> +> > implementation and test suite: > https://github.com/grpc/grpc/blob/master/test/core/xds/xds_matcher_test.cc > https://github.com/grpc/grpc/blob/master/test/core/xds/xds_matcher_parse_test.cc @@ -148,11 +148,11 @@ We will support the following fields in the message: - `matcher_type`: One of the following must be present: - - [`matcher_list`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L126) + - [`matcher_list`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L134) ([Unified Matcher: `MatcherList`]). - - [`matcher_tree`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L129) + - [`matcher_tree`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L137) ([Unified Matcher: `MatcherTree`]). -- [`on_no_match`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L135): +- [`on_no_match`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L143): ([Unified Matcher: `OnMatch`]): Specifies the action executed if no match is found in the `matcher_list` or `matcher_tree`. If not set, refer to filter's [unsuccessful match behavior][Unified Matcher: Filter Integration]. @@ -181,79 +181,79 @@ The following fields will be ignored by gRPC: #### Unified Matcher: `MatcherList` -[`Matcher.MatcherList.Predicate`]: https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L45 -[`Matcher.MatcherList.Predicate.PredicateList`]: https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L65 +[`Matcher.MatcherList.Predicate`]: https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L53 +[`Matcher.MatcherList.Predicate.PredicateList`]: https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L73 We will support the following fields in the -[`xds.type.matcher.v3.Matcher.MatcherList`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L43) +[`xds.type.matcher.v3.Matcher.MatcherList`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L51) message: -- [`matchers`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L96) +- [`matchers`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L104) (repeated - [`Matcher.MatcherList.FieldMatcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L87)): + [`Matcher.MatcherList.FieldMatcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L95)): Must contain at least 1 item. - - [`predicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L89) - ([`Matcher.MatcherList.Predicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L45)): + - [`predicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L97) + ([`Matcher.MatcherList.Predicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L53)): Must be present. - `match_type`: One of the following must be present: - - [`single_predicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L73) - ([`Matcher.MatcherList.Predicate.SinglePredicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L47)): + - [`single_predicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L81) + ([`Matcher.MatcherList.Predicate.SinglePredicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L55)): If set, the return type of the `input` must match the input type of the `matcher`. - - [`input`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L50) + - [`input`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L58) ([`TypedExtensionConfig`]): Must be present and contain one of the input extensions [supported by the filter][Unified Matcher: Filter Integration]. Must have return type compatible with the `matcher`. - `matcher`: One of the following must be present: - - [`value_match`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L56) + - [`value_match`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L64) ([Unified Matcher: `StringMatcher`]): Only compatible with `input` that returns a string. - - [`custom_match`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L60) + - [`custom_match`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L68) ([`TypedExtensionConfig`]): Must contain one of the matching extensions [supported by the filter][Unified Matcher: Filter Integration]. Must be compatible with the return type of the `input`. - - [`or_matcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L76) + - [`or_matcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L84) ([`Matcher.MatcherList.Predicate.PredicateList`]): - - [`predicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L66) + - [`predicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L74) (repeated [`Matcher.MatcherList.Predicate`]): Must contain at least 2 items. Returns true if any of them are true. - - [`and_matcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L79) + - [`and_matcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L87) ([`Matcher.MatcherList.Predicate.PredicateList`]): - - [`predicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L66) + - [`predicate`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L74) (repeated [`Matcher.MatcherList.Predicate`]): Must contain at least 2 items. Returns true if all of them are true. - - [`not_matcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L82) + - [`not_matcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L90) ([`Matcher.MatcherList.Predicate`]): Returns the inverted result of predicate evaluation. - - [`on_match`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L92) + - [`on_match`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L100) ([Unified Matcher: `OnMatch`]): Must be present. #### Unified Matcher: `MatcherTree` -[`Matcher.MatcherTree.MatchMap`]: https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L101 +[`Matcher.MatcherTree.MatchMap`]: https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L109 We will support the following fields in the -[`xds.type.matcher.v3.Matcher.MatcherTree`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L99) +[`xds.type.matcher.v3.Matcher.MatcherTree`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L107) message: -- [`input`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L106) +- [`input`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L114) ([`TypedExtensionConfig`]): Must be present and contain one of the input extensions [supported by the filter][Unified Matcher: Filter Integration]. Must have return type compatible with each matcher specified in the tree. - `tree_type`: One of the following must be present: - - [`exact_match_map`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L114) + - [`exact_match_map`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L122) ([`Matcher.MatcherTree.MatchMap`]): Only compatible with `input` that returns a `string`. - - [`map`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L102) + - [`map`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L110) A map from a `string` to [Unified Matcher: `OnMatch`]. Must contain at least 1 pair. - - [`prefix_match_map`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L117) + - [`prefix_match_map`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L125) ([`Matcher.MatcherTree.MatchMap`]): Only compatible with `input` that returns a `string`. - - [`map`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L102) + - [`map`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L110) A map from a `string` to [Unified Matcher: `OnMatch`]. Must contain at least 1 pair. @@ -273,7 +273,7 @@ We will support the following fields in the [`envoy.type.matcher.v3.HttpRequestHeaderMatchInput`](https://github.com/envoyproxy/envoy/blob/426cd861187368163b42fce910ab5828f7f0b392/api/envoy/type/matcher/v3/http_inputs.proto#L22) message: -- [`header_name`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L106): +- [`header_name`](https://github.com/envoyproxy/envoy/blob/426cd861187368163b42fce910ab5828f7f0b392/api/envoy/type/matcher/v3/http_inputs.proto#L24): Must be present. Value length must be in the range `[1, 16384)`. Must be a valid HTTP/2 header name. From ec435bef290cbf449d6fa88e69c3c5a54a5e3b93 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Tue, 18 Nov 2025 03:49:50 -0800 Subject: [PATCH 11/30] xds/type/v3/cel.proto --- A106-xds-unified-matcher-and-cel.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 68d6e799e..81dcb564c 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -359,14 +359,11 @@ Syntax Tree (AST) in different forms (e.g., `googleapis` or canonical, and each may be either parsed or checked). We will only support one form: type-checked Canonical CEL, specifically the [`cel.expr.CheckedExpr`] message. -We will support the following fields in the -[`xds.type.v3.CelExpression`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/cel.proto#L30) +We will support the following fields in the [`xds.type.v3.CelExpression`] message: -- ([`xds.type.v3.CelExpression`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L26)): - Must be present. - - [`cel_expr_checked`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L49) - ([`cel.expr.CheckedExpr`]): Must be present. +- [`cel_expr_checked`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L49) + ([`cel.expr.CheckedExpr`]): Must be present. The following fields will be ignored by gRPC: @@ -374,6 +371,11 @@ The following fields will be ignored by gRPC: - `checked_expr` - deprecated, only Canonical CEL is supported. - `cel_expr_parsed` - only Checked CEL expressions are supported. +The following are not supported by gRPC in the initial implementation and will +result in xDS resource NACK: + +- `cel_expr_string` + #### `CelExtractString` message `CelExtractString` is a small tool that allows to extract a string from From a10b3e66f9855ed05b11407e3221af4f0f9586a6 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Tue, 18 Nov 2025 03:55:55 -0800 Subject: [PATCH 12/30] CelExtractString --- A106-xds-unified-matcher-and-cel.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 81dcb564c..e5df3c4b8 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -383,10 +383,10 @@ result in xDS resource NACK: to a `string`. We will support the following fields in the -[`xds.type.matcher.v3.CelExtractString`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L62) +[`xds.type.v3.CelExtractString`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L69) message: -- [`expr_extract`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L65) +- [`expr_extract`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L72) ([`xds.type.v3.CelExpression`][`CelExpression` message]): Must be present. This message will be converted into a native CEL Abstract Syntax Tree (AST) using the language-specific CEL library. The AST's output (return) type must @@ -394,7 +394,7 @@ message: [Supported CEL Variables]. The resulting CEL program must also be validated to conform to [CEL Runtime Restrictions]. If the conversion or the validation step fail, gRPC will NACK the xDS resource. -- [`default_value`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L69): +- [`default_value`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L76): ([`StringValue`]) Optional. If set, and the CEL expression evaluates to an error or a non-string type, this default value will be returned instead. From 4607f082262e8011c0ad4856a7e649fc466e46ee Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Tue, 18 Nov 2025 04:23:35 -0800 Subject: [PATCH 13/30] keep_matching --- A106-xds-unified-matcher-and-cel.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index e5df3c4b8..5b8be8be4 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -171,13 +171,9 @@ message: ([`TypedExtensionConfig`]): If set, must contain one of the protocol-specific actions [supported by the filter][Unified Matcher: Filter Integration]. - -The following fields will be ignored by gRPC: - -- `keep_matching`: Not supported in the initial implementation, may be added - later. - -> [!WARNING] TODO(sergiitk): consider +- [`keep_matching`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L45) + (bool): If this field is set in a context in which it's not supported, the + xDS resource will be NACKed. #### Unified Matcher: `MatcherList` From 6d9cfae3f07eaf6e112a7e3a1e993c75073b6fa0 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Tue, 18 Nov 2025 14:27:16 -0800 Subject: [PATCH 14/30] Core Concepts --- A106-xds-unified-matcher-and-cel.md | 69 ++++++++++++++++------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 5b8be8be4..ee889ebcc 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -77,30 +77,27 @@ request matching based on a wide range of request attributes. ## Proposal -### Unified Matcher API Support - -> [!WARNING] TODO(sergiitk): good idea to executing parse matching tree, add a -> few examples. here's how matching should work in these cases. -> -> implementation and test suite: -> https://github.com/grpc/grpc/blob/master/test/core/xds/xds_matcher_test.cc -> https://github.com/grpc/grpc/blob/master/test/core/xds/xds_matcher_parse_test.cc - -Envoy provides two syntactically equivalent Unified Matcher definitions: -[`envoy.config.common.matcher.v3.Matcher`](https://github.com/envoyproxy/envoy/blob/426cd861187368163b42fce910ab5828f7f0b392/api/envoy/config/common/matcher/v3/matcher.proto) -and -[`xds.type.matcher.v3.Matcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto), -which is the preferred version for all new APIs using Unified Matcher. We will -produce the same form for either one. - -In this iteration, the following Unified Mather extensions will be supported: - -1. Inputs: - 1. [Unified Matcher: `HttpRequestHeaderMatchInput`] - 2. [Unified Matcher: `HttpAttributesCelMatchInput`] -2. Matchers: - 1. [Unified Matcher: `StringMatcher`](standard matcher) - 2. [Unified Matcher: `CelMatcher`] +### Unified Matcher + +#### Unified Matcher: Core Concepts + +The Unified Matcher API revolves around a few key concepts: + +1. **Matcher**: A matcher is a rule that evaluates to true or false based on + some properties of the input data. Matchers can be simple (e.g., checking if + a header has a specific value) or complex (e.g., a boolean combination of + other matchers, nested matchers, etc). +2. **Matcher Action**: If a matcher evaluates to true, an associated action is + taken. This action could be anything from selecting a route to applying a + filter. +3. **Matcher Input**: This extracts the data from the Matcher Context and + provides it to the matchers evaluate. For example, it may get a specific + header from the request provided in the matcher context. +4. **Matcher Context**: This holds the input data and any other contextual + information needed during the matching process. It may include information + about the request being processed, the response, connection info, a + combination of thereof, additional parameters to mathers that support it, + etc. #### Unified Matcher: Filter Integration @@ -143,9 +140,14 @@ While the Unified Matcher API allows for matcher trees of arbitrary depth, gRPC will reject any matcher definition with a tree depth greater than `16`, NACKing the xDS resource. -We will support the following fields in the -[`xds.type.matcher.v3.Matcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L22) -message: +Envoy provides two syntactically equivalent Unified Matcher definitions: +[`envoy.config.common.matcher.v3.Matcher`](https://github.com/envoyproxy/envoy/blob/426cd861187368163b42fce910ab5828f7f0b392/api/envoy/config/common/matcher/v3/matcher.proto) +and +[`xds.type.matcher.v3.Matcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto), +which is the preferred version for all new APIs using Unified Matcher. We will +produce the same form for either one. + +We will support the following `Matcher` fields: - `matcher_type`: One of the following must be present: - [`matcher_list`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/matcher.proto#L134) @@ -260,6 +262,11 @@ result in xDS resource NACK: #### Unified Matcher: Input Extensions +In this iteration, the following Unified Mather extensions will be supported: + +1. [Unified Matcher: `HttpRequestHeaderMatchInput`] +2. [Unified Matcher: `HttpAttributesCelMatchInput`] + ##### Unified Matcher: `HttpRequestHeaderMatchInput` Returns a `string` containing the value of the header with name specified in @@ -286,8 +293,10 @@ message: #### Unified Matcher: Matching Extensions -Matching extensions must return a boolean that indicates the status of the -match. +In this iteration, the following Unified Mather extensions will be supported: + +1. [Unified Matcher: `StringMatcher`](standard matcher) +2. [Unified Matcher: `CelMatcher`] ##### Unified Matcher: `StringMatcher` @@ -401,7 +410,7 @@ exhaustion. To ensure consistent behavior with Envoy and maintain security, gRPC will configure the CEL runtime [similar to Envoy](https://github.com/envoyproxy/envoy/blob/c57801c2afbe26dd6fad7f5ce764f267d07fbd04/source/extensions/filters/common/expr/evaluator.cc#L17-L23): -```c +```cpp // Disables comprehension expressions, e.g. exists(), all(). options.enable_comprehension = false; From a3ebd79180fd68e549b3f47e68735c45cac0b4c3 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Tue, 18 Nov 2025 17:00:30 -0800 Subject: [PATCH 15/30] Unified Matcher: Evaluation Flow --- A106-xds-unified-matcher-and-cel.md | 140 ++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index ee889ebcc..8de7ca3a6 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -345,6 +345,146 @@ message: - [`description`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/cel.proto#L36): An optional string. May be ignored or used for testing/debugging. +#### Unified Matcher: Evaluation Flow + +**The Goal:** To produce a list of matching `Action`s.\ +**Matcher Context:** The input to the Matcher evaluation tree. Provided at +runtime by the filter, contains the input data. May contain any other contextual +information relevant to the filter.\ +**The Matching Process:** Starting with a top-level `Matcher`, there will be one +of the following matchers types: + +* **[List Matcher][Unified Matcher: `MatcherList`]:** This is like a series of + "if-elif-elif-else" statements. It goes through a list of rules: + * Each rule has a **Condition** (`Predicate`) and a **Result** (`OnMatch`). + * **Condition Checking:** To check a typical condition: + 1. Using the `input` extension, extract a specific piece of data from + the **Matcher Context** (e.g., the value of requests's `:host` + header). + 2. Using the `matcher` extension, compare the extracted data against + the matcher's criteria (e.g., "is it equal to `'example.com'`?", + "does it start with `'api.'`?"). + * Conditions can be combined using AND, OR, NOT, or nested via `OnMatch`. + * **First Match Wins:** The *first* rule whose **Condition** is true has its + **Result** executed. + +* **[Exact Map Matcher][Unified Matcher: `MatcherTree`]:** This is like a switch + statement or dictionary lookup. + * Using the `input` extension, it extracts a specific string value from + the **Matcher Context**. + * It looks this the key for this exact string the a predefined map. + * If found, it executes the corresponding **Result**. + +* **[Prefix Map Matcher][Unified Matcher: `MatcherTree`]:** Similar to the Map + Matcher, but uses prefix matching (a Trie data structure). + * Using the `input` extension, it extracts a specific string value from the + **Matcher Context**. + * It finds all entries in the map whose keys are prefixes of the input + string. + * The **Result** is chosen based the the key with the *longest* matching + prefix. + * Undefined behavior: If there are multiple prefixes of the same greatest + length, their **Result**s are all processed in order of Trie traversal. + There's no other tie-breaking rule like alphabetical order among the + tied keys. + +**[The Result][Unified Matcher: `OnMatch`]:** When a match occurs, the `OnMatch` +dictates the outcome: + +* It can contain an `Action` to be added to the results. +* It can contain a nested `Matcher`, triggering a further round of matching. + * The tree is validated to not contain matchers with the tree depth + greater than `16`. If this three depth is reached at runtime, + the tree evaluation is terminated, and considered an + [unsuccessful match][Unified Matcher: Filter Integration]. +* `keep_matching` determines whether a successful match within an `OnMatch` + should be considered "terminal" for the current `Matcher` being evaluated. + It essentially answers the question: "After processing this `OnMatch`, + should the current matcher stop looking for more matches, or continue?" + * If `keep_matching` is `false` (the usual case), finding this `OnMatch` is + terminal. The `Action` is added (or the nested `Matcher` is evaluated), + and the current matcher stops searching. + * If `keep_matching` is `true`, the `Action` is added (or nested + `XdsMatcher` evaluated), but the current matcher *continues* to look for + more matches. The overall process is not considered complete until an + `OnMatch` with `keep_matching` set to `false` is encountered. + +**Default/No Match:** Any `Matcher` can have a default `OnMatch` to use if none +of its primary conditions or map lookups succeed. See details in +[Unified Matcher: `Matcher`] and [Unified Matcher: Filter Integration].\ +**The Output:** A list of `Action` accumulated from all triggered `OnMatch` +results. Generally, only a single `Action` will be returned, unless +`keep_matching` is enabled, and multiple matches found. + +#### Unified Matcher: Evaluation Examples + +For simplicity, `TypedExtensionConfig`s are represented in a comment, and the +`onMatch` action is be represented by a string like `"onMatch": { "action": +"route_to_cluster_A" }`. + +##### Example 1: Simple Linear Match + +This example shows a basic matcher list. It routes requests based on the value +of a single header, the first matching predicate wins. + +**Configuration:** + +```json5 +{ + "matcher_list": { + "matchers": [ + { + "predicate": { + "single_predicate": { + "input": { "header_name": "x-user-segment" }, + "value_match": { "exact": "premium" } + } + }, + "onMatch": { "action": "route_to_premium_cluster" } + }, + { + "predicate": { + "single_predicate": { + "input": { "header_name": "x-user-segment" }, + "value_match": { "prefix": "standard" } + } + }, + "onMatch": { "action": "route_to_standard_cluster" } + } + ] + }, + "on_no_match": { "action": "route_to_default_cluster" } +} +``` + +**Request Input 1:** + +* Headers: `{ "x-user-segment": "premium" }` + +**Evaluation:** + +1. The `matcher_list` evaluates its matchers in order. +2. The first matcher checks if the `x-user-segment` header has the exact value "premium". +3. The input header `x-user-segment: premium` is an exact match. +4. The predicate is **true**. The `matcher_list` stops processing further matchers. + +**Result 1:** The action `route_to_premium_cluster` is chosen. + +**Request Input 2:** + +* Headers: `{ "x-user-segment": "guest" }` + +**Evaluation:** + +1. The `matcher_list` evaluates its matchers in order. +2. The first matcher for "premium" is **false**. +3. The second matcher for "standard" is **false**. +4. No matchers in the list evaluated to true. + +**Result 2:** The `onNoMatch` action `route_to_default_cluster` is chosen. + +--- + ### CEL Integration We will support request metadata matching via CEL expressions. From 8199211ab5df031947588cefe816d30d84239e5f Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Wed, 19 Nov 2025 10:49:02 -0800 Subject: [PATCH 16/30] Evaluation proofread --- A106-xds-unified-matcher-and-cel.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 8de7ca3a6..726372372 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -347,11 +347,13 @@ message: #### Unified Matcher: Evaluation Flow -**The Goal:** To produce a list of matching `Action`s.\ +**Goal:** To produce a list of matching `Action`s.\ **Matcher Context:** The input to the Matcher evaluation tree. Provided at runtime by the filter, contains the input data. May contain any other contextual -information relevant to the filter.\ -**The Matching Process:** Starting with a top-level `Matcher`, there will be one +information relevant to the filter. Implementation note: when setting an input, +consider memory footprint. For example, instead of resolving all headers in +advance, provide them in a lazy-loading wrapper. +**Matching Process:** Starting with a top-level `Matcher`, there will be one of the following matchers types: * **[List Matcher][Unified Matcher: `MatcherList`]:** This is like a series of @@ -375,7 +377,7 @@ of the following matchers types: * It looks this the key for this exact string the a predefined map. * If found, it executes the corresponding **Result**. -* **[Prefix Map Matcher][Unified Matcher: `MatcherTree`]:** Similar to the Map +* **[Prefix Map Matcher][Unified Matcher: `MatcherTree`]:** Similar to the Map Matcher, but uses prefix matching (a Trie data structure). * Using the `input` extension, it extracts a specific string value from the **Matcher Context**. @@ -388,7 +390,7 @@ of the following matchers types: There's no other tie-breaking rule like alphabetical order among the tied keys. -**[The Result][Unified Matcher: `OnMatch`]:** When a match occurs, the `OnMatch` +**[Result][Unified Matcher: `OnMatch`]:** When a match occurs, the `OnMatch` dictates the outcome: * It can contain an `Action` to be added to the results. @@ -412,9 +414,9 @@ dictates the outcome: **Default/No Match:** Any `Matcher` can have a default `OnMatch` to use if none of its primary conditions or map lookups succeed. See details in [Unified Matcher: `Matcher`] and [Unified Matcher: Filter Integration].\ -**The Output:** A list of `Action` accumulated from all triggered `OnMatch` +**The Output:** A list of `Action`s accumulated from all triggered `OnMatch` results. Generally, only a single `Action` will be returned, unless -`keep_matching` is enabled, and multiple matches found. +`keep_matching` is enabled and multiple matches found. #### Unified Matcher: Evaluation Examples @@ -436,6 +438,7 @@ of a single header, the first matching predicate wins. { "predicate": { "single_predicate": { + // envoy.type.matcher.v3.HttpRequestHeaderMatchInput "input": { "header_name": "x-user-segment" }, "value_match": { "exact": "premium" } } From befb75890b30f1e56a8cf67c3055bc6b25923749 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 20 Nov 2025 01:25:59 -0800 Subject: [PATCH 17/30] "Example 1: Simple Linear Match" done --- A106-xds-unified-matcher-and-cel.md | 50 ++++++++++++++++++----------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 726372372..a6350811e 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -377,7 +377,7 @@ of the following matchers types: * It looks this the key for this exact string the a predefined map. * If found, it executes the corresponding **Result**. -* **[Prefix Map Matcher][Unified Matcher: `MatcherTree`]:** Similar to the Map +* **[Prefix Map Matcher][Unified Matcher: `MatcherTree`]:** Similar to the Map Matcher, but uses prefix matching (a Trie data structure). * Using the `input` extension, it extracts a specific string value from the **Matcher Context**. @@ -396,7 +396,7 @@ dictates the outcome: * It can contain an `Action` to be added to the results. * It can contain a nested `Matcher`, triggering a further round of matching. * The tree is validated to not contain matchers with the tree depth - greater than `16`. If this three depth is reached at runtime, + greater than `16`. If this three depth is reached at runtime, the tree evaluation is terminated, and considered an [unsuccessful match][Unified Matcher: Filter Integration]. * `keep_matching` determines whether a successful match within an `OnMatch` @@ -407,7 +407,7 @@ dictates the outcome: terminal. The `Action` is added (or the nested `Matcher` is evaluated), and the current matcher stops searching. * If `keep_matching` is `true`, the `Action` is added (or nested - `XdsMatcher` evaluated), but the current matcher *continues* to look for + `Matcher` evaluated), but the current matcher *continues* to look for more matches. The overall process is not considered complete until an `OnMatch` with `keep_matching` set to `false` is encountered. @@ -420,9 +420,12 @@ results. Generally, only a single `Action` will be returned, unless #### Unified Matcher: Evaluation Examples -For simplicity, `TypedExtensionConfig`s are represented in a comment, and the -`onMatch` action is be represented by a string like `"onMatch": { "action": -"route_to_cluster_A" }`. +For simplicity: + +* `TypedExtensionConfig` fields: The type is captured in a comment, and the + value directly contains the unpacked message content. +* `on_match` action: Represented by a string, for example, + `"on_match": { "action": "route_to_cluster_A" }`. ##### Example 1: Simple Linear Match @@ -443,16 +446,17 @@ of a single header, the first matching predicate wins. "value_match": { "exact": "premium" } } }, - "onMatch": { "action": "route_to_premium_cluster" } + "on_match": { "action": "route_to_premium_cluster" } }, { "predicate": { "single_predicate": { + // envoy.type.matcher.v3.HttpRequestHeaderMatchInput "input": { "header_name": "x-user-segment" }, - "value_match": { "prefix": "standard" } + "value_match": { "prefix": "standard-" } } }, - "onMatch": { "action": "route_to_standard_cluster" } + "on_match": { "action": "route_to_standard_cluster" } } ] }, @@ -462,16 +466,22 @@ of a single header, the first matching predicate wins. **Request Input 1:** -* Headers: `{ "x-user-segment": "premium" }` +* Headers: `{ "x-user-segment": "standard-user-1" }` **Evaluation:** 1. The `matcher_list` evaluates its matchers in order. -2. The first matcher checks if the `x-user-segment` header has the exact value "premium". -3. The input header `x-user-segment: premium` is an exact match. -4. The predicate is **true**. The `matcher_list` stops processing further matchers. - -**Result 1:** The action `route_to_premium_cluster` is chosen. +2. The first matcher checks if the `x-user-segment` header has the exact value + `premium`. + * The predicate is `false`, matching continues. +3. The second matcher checks if the `x-user-segment` header has the prefix + `standard-`. + * The predicate is `true`, its `on_match` is evaluated. + * The action `route_to_standard_cluster` is chosen. + * The `matcher_list` stops processing further matchers because + `keep_matching` is not set. + +**Result 1:** `["route_to_standard_cluster"]`. **Request Input 2:** @@ -480,11 +490,13 @@ of a single header, the first matching predicate wins. **Evaluation:** 1. The `matcher_list` evaluates its matchers in order. -2. The first matcher for "premium" is **false**. -3. The second matcher for "standard" is **false**. -4. No matchers in the list evaluated to true. +2. The first matcher for "premium" is `false`. +3. The second matcher for "standard" is `false`. +4. No matchers in the list evaluated to `true`. +5. `on_no_match` is evaluated. + * The action `route_to_default_cluster` is chosen. -**Result 2:** The `onNoMatch` action `route_to_default_cluster` is chosen. +**Result 2:** ["route_to_default_cluster"] --- From 4d071454a7142c813018d0076074045f4b1a1cfa Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 20 Nov 2025 02:40:32 -0800 Subject: [PATCH 18/30] Example 2: Keep Matching --- A106-xds-unified-matcher-and-cel.md | 96 +++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 13 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index a6350811e..42b52f8b1 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -426,6 +426,9 @@ For simplicity: value directly contains the unpacked message content. * `on_match` action: Represented by a string, for example, `"on_match": { "action": "route_to_cluster_A" }`. +* The first example will include `input` to demonstrate the data flow. +* Other examples will skip the input and simply indicates the result of + evaluation in `custom_match` field, for example, `{ "custom_match": true }`. ##### Example 1: Simple Linear Match @@ -468,18 +471,36 @@ of a single header, the first matching predicate wins. * Headers: `{ "x-user-segment": "standard-user-1" }` -**Evaluation:** +**Evaluation (detailed):** 1. The `matcher_list` evaluates its matchers in order. -2. The first matcher checks if the `x-user-segment` header has the exact value - `premium`. +2. The first matcher is evaluated. + * The `input` executes `HttpRequestHeaderMatchInput` extension: + * The extension logic extracts the value of the `x-user-segment` + header from the Matcher Context. + * The `input` returns `standard-user-1`. + * The `StringMatcher` is evaluated (standard matcher): + * The input is a string `standard-user-1`, which is the correct input + type for this matcher. + * The `StringMatcher` checks if the value `standard-user-1` has + the exact value `premium`. + * The result of matcher evaluation is `false` * The predicate is `false`, matching continues. -3. The second matcher checks if the `x-user-segment` header has the prefix - `standard-`. +3. The second matcher is evaluated: + * The `input` executes `HttpRequestHeaderMatchInput` extension: + * The extension logic extracts the value of the `x-user-segment` + header from the Matcher Context. + * The `input` returns `standard-user-1`. + * The `StringMatcher` is evaluated (standard matcher): + * The input is a string `standard-user-1`, which is the correct input + type for this matcher. + * The `StringMatcher` checks if the value `standard-user-1` has the + prefix `standard-`. + * The result of matcher evaluation is `true` * The predicate is `true`, its `on_match` is evaluated. - * The action `route_to_standard_cluster` is chosen. - * The `matcher_list` stops processing further matchers because - `keep_matching` is not set. + * The action `route_to_standard_cluster` is chosen. + * The `matcher_list` stops processing further matchers because + `keep_matching` is not set. **Result 1:** `["route_to_standard_cluster"]`. @@ -487,17 +508,66 @@ of a single header, the first matching predicate wins. * Headers: `{ "x-user-segment": "guest" }` -**Evaluation:** +**Evaluation (simplified):** 1. The `matcher_list` evaluates its matchers in order. -2. The first matcher for "premium" is `false`. -3. The second matcher for "standard" is `false`. -4. No matchers in the list evaluated to `true`. -5. `on_no_match` is evaluated. +2. The first matcher for `premium` is `false`. +3. The second matcher for `standard-` prefix is `false`. +4. No matchers in the list evaluated to `true`, therefore the `on_no_match` is + evaluated: * The action `route_to_default_cluster` is chosen. **Result 2:** ["route_to_default_cluster"] +##### Example 2: Keep Matching + +This example demonstrates the effect of `keep_matching: true`. Actions are +accumulated until a matcher with `keep_matching: false` (the default) is found. + +**Configuration:** + +```json5 +{ + "matcher_list": { + "matchers": [ + // Matcher 1 + { + "predicate": { "single_predicate": { "custom_match": true } }, + "on_match": { "action": "Action1", "keep_matching": true } + }, + // Matcher 2 + { + "predicate": { "single_predicate": { "custom_match": false } }, + "on_match": { "action": "Action2" } + }, + // Matcher 3 + { + "predicate": { "single_predicate": { "custom_match": true } }, + "on_match": { "action": "Action3" } + }, + // Matcher 4 + { + "predicate": { "single_predicate": { "custom_match": false } }, + "on_match": { "action": "Action4" } + } + ] + } +} +``` + +**Evaluation:** + +1. Matcher 1 evaluates to `true`. + * `Action1` is added to the result list. + * Matching continues because `keep_matching: true`. +2. Matcher 2 evaluates to `false`. +3. Matcher 3 evaluates to `true`. + * `Action3` is added to the result list. + * Matching stops because `keep_matching` is false by default. +4. Matcher 4 is not evaluated. + +**Result:** `["Action1", "Action3"]` + --- ### CEL Integration From 20bc41198c082032cf723978635cfb8cabe432a6 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 20 Nov 2025 02:53:23 -0800 Subject: [PATCH 19/30] Example 3: Nested Matcher --- A106-xds-unified-matcher-and-cel.md | 50 +++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 42b52f8b1..e80ef1cef 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -568,6 +568,56 @@ accumulated until a matcher with `keep_matching: false` (the default) is found. **Result:** `["Action1", "Action3"]` +##### Example 3: Nested Matcher + +This example shows a matcher whose action is another matcher. + +**Configuration:** + +```json5 +{ + "matcher_list": { + "matchers": [ + { + "predicate": { "single_predicate": { "custom_match": true } }, + "on_match": { + // Nested matcher with matcher_list. + "matcher": { + "matcher_list": { + "matchers": [ + { + "predicate": { "single_predicate": { "custom_match": false } }, + "on_match": { "action": "inner_matcher_1" } + }, + { + "predicate": { "single_predicate": { "custom_match": true } }, + "on_match": { "action": "inner_matcher_2" } + } + ] + } + } + // Nested matcher end. + } + } + ] + } +} +``` + +**Evaluation:** + +1. The outer `matcher_list` evaluates its first (and only) matcher: + * The predicate of the outer matcher evaluates to `true`. + * The `on_match` of the outer matcher contains a nested matcher. + * The three depth is not greater than 16, the nested matcher is evaluated: + 1. The inner `matcher_list` evaluates first matcher to `false`. + 2. The inner `matcher_list` evaluates its second matcher to `true`: + * The predicate is `true`, its `on_match` is evaluated. + * The action `inner_match_2` is added to the result list. + * Evaluation stops because `keep_matching` is not set. + +**Result 1:** `["inner_matcher_2"]` + --- ### CEL Integration From cd1b22f41b60dcd7e816ac08e405c18cfd2f2954 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 20 Nov 2025 02:55:35 -0800 Subject: [PATCH 20/30] minor example results --- A106-xds-unified-matcher-and-cel.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index e80ef1cef..ce013f39e 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -533,22 +533,22 @@ accumulated until a matcher with `keep_matching: false` (the default) is found. // Matcher 1 { "predicate": { "single_predicate": { "custom_match": true } }, - "on_match": { "action": "Action1", "keep_matching": true } + "on_match": { "action": "action_1", "keep_matching": true } }, // Matcher 2 { "predicate": { "single_predicate": { "custom_match": false } }, - "on_match": { "action": "Action2" } + "on_match": { "action": "action_2" } }, // Matcher 3 { "predicate": { "single_predicate": { "custom_match": true } }, - "on_match": { "action": "Action3" } + "on_match": { "action": "action_3" } }, // Matcher 4 { "predicate": { "single_predicate": { "custom_match": false } }, - "on_match": { "action": "Action4" } + "on_match": { "action": "action_4" } } ] } @@ -558,15 +558,15 @@ accumulated until a matcher with `keep_matching: false` (the default) is found. **Evaluation:** 1. Matcher 1 evaluates to `true`. - * `Action1` is added to the result list. + * `action_1` is added to the result list. * Matching continues because `keep_matching: true`. 2. Matcher 2 evaluates to `false`. 3. Matcher 3 evaluates to `true`. - * `Action3` is added to the result list. + * `action_3` is added to the result list. * Matching stops because `keep_matching` is false by default. 4. Matcher 4 is not evaluated. -**Result:** `["Action1", "Action3"]` +**Result:** `["action_1", "action_3"]` ##### Example 3: Nested Matcher From a545828a3df086fdaad64335065c7f966e9b9522 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 20 Nov 2025 03:05:22 -0800 Subject: [PATCH 21/30] Example 4: Prefix Map Matcher --- A106-xds-unified-matcher-and-cel.md | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index ce013f39e..b40ebad72 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -618,6 +618,39 @@ This example shows a matcher whose action is another matcher. **Result 1:** `["inner_matcher_2"]` +##### Example 4: Prefix Map Matcher + +This shows a prefix map, where the longest prefix match wins. + +**Configuration:** + +```json5 +{ + "matcher_prefix_map": { + // envoy.type.matcher.v3.HttpRequestHeaderMatchInput + "input": { "header_name": "x-user-segment" }, + "map": { + "grpc": { "action": "shorter_prefix" }, + "grpc.channelz": { "action": "longer_prefix" } + } + } +} +``` + +**Request Input:** + +* Path: `grpc.channelz.v1.Channelz/GetTopChannels` + +**Evaluation:** + +1. The input path `grpc.channelz.v1.Channelz/GetTopChannels` is checked against + the map keys. +2. It matches both `grpc` and `grpc.channelz`. +3. The longest matching prefix is `grpc.channelz`. + * The action `longer_prefix` is chosen. + +**Result 1:** `["longer_prefix"]` + --- ### CEL Integration From 13d06072a1745bb6abe6fa17d7b094abb3a03a2d Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 20 Nov 2025 03:14:35 -0800 Subject: [PATCH 22/30] envoy docs examples --- A106-xds-unified-matcher-and-cel.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index b40ebad72..c26c0d884 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -430,6 +430,10 @@ For simplicity: * Other examples will skip the input and simply indicates the result of evaluation in `custom_match` field, for example, `{ "custom_match": true }`. +For even more examples, refer to +[Envoy's Unified Matcher API Documentation][Unified Matcher API] (note that +these examples might be Envoy-specific). + ##### Example 1: Simple Linear Match This example shows a basic matcher list. It routes requests based on the value From 303847f481b0277ef73fee0477535cd93b3d40f4 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 20 Nov 2025 03:21:39 -0800 Subject: [PATCH 23/30] rename CEL headers --- A106-xds-unified-matcher-and-cel.md | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index c26c0d884..eefa7592a 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -67,10 +67,10 @@ request matching based on a wide range of request attributes. [`cel.expr.CheckedExpr`]: https://github.com/google/cel-spec/blob/master/proto/cel/expr/checked.proto [CEL Integration]: #cel-integration -[`CelExpression` message]: #celexpression-message -[CEL Runtime Restrictions]: #cel-runtime-restrictions -[Supported CEL Functions]: #supported-cel-functions -[Supported CEL Variables]: #supported-cel-variables +[CEL: `CelExpression`]: #cel-celexpression +[CEL: Runtime Restrictions]: #cel-runtime-restrictions +[CEL: Supported Functions]: #cel-supported-functions +[CEL: Supported Variables]: #cel-supported-variables [`StringValue`]: https://protobuf.dev/reference/protobuf/google.protobuf/#string-value [`TypedExtensionConfig`]: https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/core/v3/extension.proto#L14 @@ -283,7 +283,7 @@ message: ##### Unified Matcher: `HttpAttributesCelMatchInput` Returns a language-specific interface that allows to access request RPC metadata -as defined in [Supported CEL Variables]. +as defined in [CEL: Supported Variables]. We will support the following fields in the [`xds.type.matcher.v3.HttpAttributesCelMatchInput`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/http_inputs.proto#L22) @@ -336,11 +336,11 @@ We will support the following fields in the message: - [`expr_match`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/cel.proto#L32) - ([`xds.type.v3.CelExpression`][`CelExpression` message]): Must be present. + ([`xds.type.v3.CelExpression`][CEL: `CelExpression`]): Must be present. This message will be converted into a native CEL Abstract Syntax Tree (AST) using the language-specific CEL library. The AST's output (return) type must be boolean. The resulting CEL program must also be validated to conform to - [CEL Runtime Restrictions] and only contain [Supported CEL Variables]. If + [CEL: Runtime Restrictions] and only contain [CEL: Supported Variables]. If the conversion or the validation step fail, gRPC will NACK the xDS resource. - [`description`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/cel.proto#L36): An optional string. May be ignored or used for testing/debugging. @@ -666,7 +666,7 @@ functions in a CEL program. We will match [Envoy CEL environment](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/advanced/attributes) and CEL interpreter configuration. -#### `CelExpression` message +#### CEL: `CelExpression` [`xds.type.v3.CelExpression`]: https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L26 @@ -693,10 +693,10 @@ result in xDS resource NACK: - `cel_expr_string` -#### `CelExtractString` message +#### CEL: `CelExtractString` `CelExtractString` is a small tool that allows to extract a string from -[Supported CEL Variables] using a CEL expression. The expression must evaluate +[CEL: Supported Variables] using a CEL expression. The expression must evaluate to a `string`. We will support the following fields in the @@ -704,18 +704,18 @@ We will support the following fields in the message: - [`expr_extract`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L72) - ([`xds.type.v3.CelExpression`][`CelExpression` message]): Must be present. + ([`xds.type.v3.CelExpression`][CEL: `CelExpression`]): Must be present. This message will be converted into a native CEL Abstract Syntax Tree (AST) using the language-specific CEL library. The AST's output (return) type must - be a `string`. It may only contain [Supported CEL Functions] and - [Supported CEL Variables]. The resulting CEL program must also be validated - to conform to [CEL Runtime Restrictions]. If the conversion or the + be a `string`. It may only contain [CEL: Supported Functions] and + [CEL: Supported Variables]. The resulting CEL program must also be validated + to conform to [CEL: Runtime Restrictions]. If the conversion or the validation step fail, gRPC will NACK the xDS resource. - [`default_value`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/v3/cel.proto#L76): ([`StringValue`]) Optional. If set, and the CEL expression evaluates to an error or a non-string type, this default value will be returned instead. -#### CEL Runtime Restrictions +#### CEL: Runtime Restrictions Certain CEL features can lead to superlinear time complexity or memory exhaustion. To ensure consistent behavior with Envoy and maintain security, gRPC @@ -739,7 +739,7 @@ options.enable_string_concat = false; options.enable_list_concat = false; ``` -#### Supported CEL Functions +#### CEL: Supported Functions Similar to Envoy, we will support [standard CEL functions](https://github.com/google/cel-spec/blob/c629b2be086ed6b4c44ef4975e56945f66560677/doc/langdef.md#standard-definitions) @@ -761,7 +761,7 @@ except comprehension-style macros. [RE2_wiki]: https://en.wikipedia.org/wiki/RE2_(software) -#### Supported CEL Variables +#### CEL: Supported Variables In the initial implementation only the `request` variable is supported in CEL expressions. We will adapt @@ -795,7 +795,7 @@ As defined in [A41], "header" field. > [!WARNING] TODO(sergiitk): comment: Response attributes are needed for > ext_proc -##### CEL Variable Implementation Details +##### CEL: Variable Implementation Details For performance reasons, CEL variables should be resolved on demand. CEL Runtime provides the different variable resolving approaches based on the language: From c0c198b09b7128f518282fc5ae9df5ab2301aed0 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 20 Nov 2025 03:44:07 -0800 Subject: [PATCH 24/30] CEL: Unified Matcher Example --- A106-xds-unified-matcher-and-cel.md | 37 ++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index eefa7592a..247f58dd3 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -792,9 +792,6 @@ denies requests for all other method types. **2 `request.headers`** \ As defined in [A41], "header" field. -> [!WARNING] TODO(sergiitk): comment: Response attributes are needed for -> ext_proc - ##### CEL: Variable Implementation Details For performance reasons, CEL variables should be resolved on demand. CEL Runtime @@ -807,6 +804,40 @@ provides the different variable resolving approaches based on the language: - Java: [`CelVariableResolver`](https://javadoc.io/doc/dev.cel/runtime/0.6.0/dev/cel/runtime/CelVariableResolver.html) +#### CEL: Unified Matcher Example + +CEL will be integrated into the Unified Matcher API like so: + +```textproto +matcher_list { + matchers { + predicate { + single_predicate { + input { + typed_config: { + [type.googleapis.com/xds.type.matcher.v3.HttpAttributesCelMatchInput] {} + } + } + custom_match: { + typed_config: { + [type.googleapis.com/xds.type.matcher.v3.CelMatcher] { + expr_match: { + cel_expr_checked: { + # Checked CEL AST here. + } + } + } + } + } + } + } + on_match: { + # Action on successful match. + } + } +} +``` + ### Temporary Environment Variable Protection The Unified Matcher API feature will not be guarded by a dedicated environment From f3ca24ad3413af4e5d9d18164997c0af6e804bd7 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 20 Nov 2025 04:29:25 -0800 Subject: [PATCH 25/30] Rationale and safe_regex --- A106-xds-unified-matcher-and-cel.md | 61 +++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 247f58dd3..6af4d3998 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -74,6 +74,7 @@ request matching based on a wide range of request attributes. [`StringValue`]: https://protobuf.dev/reference/protobuf/google.protobuf/#string-value [`TypedExtensionConfig`]: https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/core/v3/extension.proto#L14 +[RE2_wiki]: https://github.com/google/re2/wiki/Syntax ## Proposal @@ -313,17 +314,28 @@ message: The input string must have this prefix. Must be non-empty. - [`suffix`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/string.proto#L44): The input string must have this suffix. Must be non-empty. + - [`safe_regex`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/string.proto#L47): + ([`RegexMatcher`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/regex.proto#L15)) + The input string must match the regular expression. + - [`google_re2`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/regex.proto#L40): + Effectively ignored, [Google's RE2][RE2_wiki] is the only supported + implementation. + - [`regex`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/regex.proto#L45) + Must be non-empty. - [`contains`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/string.proto#L55): The input string must contain this substring. Must be non-empty. - [`ignore_case`](https://github.com/cncf/xds/blob/2ac532fd44436293585084f8d94c6bdb17835af0/xds/type/matcher/v3/string.proto#L65): - If `true`, the matching is case-insensitive. + If `true`, the matching is case-insensitive. Does not apply to the + `safe_regex` match type. -The following are not supported by gRPC in the initial implementation and will -result in xDS resource NACK: +The following are not supported by gRPC and will result in xDS resource NACK: -- `safe_regex` - `custom` +The following fields are ignored: + +- `RegexMatcher.google_re2` + ##### Unified Matcher: `CelMatcher` Compatible with [Unified Matcher: `HttpAttributesCelMatchInput`]. @@ -759,8 +771,6 @@ except comprehension-style macros. | `==`, `!=`, `>`, `<`, `<=`, `>=` | Comparisons. | | `or`, `&&`, `+`, `-`, `/`, `*`, `%`, `!` | Basic functions. | -[RE2_wiki]: https://en.wikipedia.org/wiki/RE2_(software) - #### CEL: Supported Variables In the initial implementation only the `request` variable is supported in CEL @@ -846,7 +856,44 @@ that depend on it (e.g., `GRPC_EXPERIMENTAL_XDS_ENABLE_RLQS` for RLQS). ## Rationale -> [!WARNING] TODO(sergiitk): rationale +The chosen approach, integrating the xDS Unified Matcher API with CEL, was +selected over several alternatives due to its advantages in consistency, +maintainability, safety, and alignment with the broader xDS ecosystem. + +### Considered Alternatives + +The main alternative is for each xDS feature (e.g., RLQS, RBAC) to define its +own custom matching logic. This is how older xDS features were designed, but it +leads to significant drawbacks: + +* Duplication and Inconsistency: It forces repeated implementation of + common matching primitives (header, path, etc.) across different filters and + gRPC language implementations, leading to code bloat and subtle behavioral + differences. +* High Maintenance Cost: Bug fixes and new features must be implemented in + multiple places. + +The Unified Matcher API provides a single, consistent, and reusable framework +that is implemented once and shared by all features. This improves +maintainability, provides a uniform configuration experience for users, and +aligns gRPC with Envoy, creating a more cohesive xDS ecosystem. + +### Disadvantages and Trade-offs + +* **Increased Complexity**: The system is powerful but also complex. The + matcher API involves nested structures, different evaluation flows + (`MatcherList` vs. `MatcherTree`), and nuanced behaviors like + `keep_matching`. Configuring and debugging this can be more challenging than + simpler matching schemes. +* **Restricted CEL Functionality**: To ensure safety and performance, the + implementation explicitly disables certain CEL features, such as + comprehensions (`exists()`, `all()`). This is a direct trade-off of power + for safety, meaning not all standard CEL capabilities are available. +* **Performance Overhead**: Evaluating CEL expressions for every request + introduces computational overhead. While designed to be fast, it will be + slower than simple, hard-coded logic or basic string comparisons. The + proposal acknowledges this by recommending performance-conscious + implementation details like on-demand variable resolution. ## Implementation From f99b0d3db879e6bde9340d56afcab5d37045d43c Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 20 Nov 2025 04:41:05 -0800 Subject: [PATCH 26/30] replace * lists with - --- A106-xds-unified-matcher-and-cel.md | 134 ++++++++++++++-------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 6af4d3998..aa83d4bba 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -368,36 +368,36 @@ advance, provide them in a lazy-loading wrapper. **Matching Process:** Starting with a top-level `Matcher`, there will be one of the following matchers types: -* **[List Matcher][Unified Matcher: `MatcherList`]:** This is like a series of +- **[List Matcher][Unified Matcher: `MatcherList`]:** This is like a series of "if-elif-elif-else" statements. It goes through a list of rules: - * Each rule has a **Condition** (`Predicate`) and a **Result** (`OnMatch`). - * **Condition Checking:** To check a typical condition: + - Each rule has a **Condition** (`Predicate`) and a **Result** (`OnMatch`). + - **Condition Checking:** To check a typical condition: 1. Using the `input` extension, extract a specific piece of data from the **Matcher Context** (e.g., the value of requests's `:host` header). 2. Using the `matcher` extension, compare the extracted data against the matcher's criteria (e.g., "is it equal to `'example.com'`?", "does it start with `'api.'`?"). - * Conditions can be combined using AND, OR, NOT, or nested via `OnMatch`. - * **First Match Wins:** The *first* rule whose **Condition** is true has its - **Result** executed. + - Conditions can be combined using AND, OR, NOT, or nested via `OnMatch`. + - **First Match Wins:** The *first* rule whose **Condition** is true has + its **Result** executed. -* **[Exact Map Matcher][Unified Matcher: `MatcherTree`]:** This is like a switch - statement or dictionary lookup. - * Using the `input` extension, it extracts a specific string value from +- **[Exact Map Matcher][Unified Matcher: `MatcherTree`]:** This is like a + switch statement or dictionary lookup. + - Using the `input` extension, it extracts a specific string value from the **Matcher Context**. - * It looks this the key for this exact string the a predefined map. - * If found, it executes the corresponding **Result**. + - It looks this the key for this exact string the a predefined map. + - If found, it executes the corresponding **Result**. -* **[Prefix Map Matcher][Unified Matcher: `MatcherTree`]:** Similar to the Map +- **[Prefix Map Matcher][Unified Matcher: `MatcherTree`]:** Similar to the Map Matcher, but uses prefix matching (a Trie data structure). - * Using the `input` extension, it extracts a specific string value from the - **Matcher Context**. - * It finds all entries in the map whose keys are prefixes of the input + - Using the `input` extension, it extracts a specific string value from + the **Matcher Context**. + - It finds all entries in the map whose keys are prefixes of the input string. - * The **Result** is chosen based the the key with the *longest* matching + - The **Result** is chosen based the the key with the *longest* matching prefix. - * Undefined behavior: If there are multiple prefixes of the same greatest + - Undefined behavior: If there are multiple prefixes of the same greatest length, their **Result**s are all processed in order of Trie traversal. There's no other tie-breaking rule like alphabetical order among the tied keys. @@ -405,20 +405,20 @@ of the following matchers types: **[Result][Unified Matcher: `OnMatch`]:** When a match occurs, the `OnMatch` dictates the outcome: -* It can contain an `Action` to be added to the results. -* It can contain a nested `Matcher`, triggering a further round of matching. - * The tree is validated to not contain matchers with the tree depth +- It can contain an `Action` to be added to the results. +- It can contain a nested `Matcher`, triggering a further round of matching. + - The tree is validated to not contain matchers with the tree depth greater than `16`. If this three depth is reached at runtime, the tree evaluation is terminated, and considered an [unsuccessful match][Unified Matcher: Filter Integration]. -* `keep_matching` determines whether a successful match within an `OnMatch` +- `keep_matching` determines whether a successful match within an `OnMatch` should be considered "terminal" for the current `Matcher` being evaluated. It essentially answers the question: "After processing this `OnMatch`, should the current matcher stop looking for more matches, or continue?" - * If `keep_matching` is `false` (the usual case), finding this `OnMatch` is - terminal. The `Action` is added (or the nested `Matcher` is evaluated), - and the current matcher stops searching. - * If `keep_matching` is `true`, the `Action` is added (or nested + - If `keep_matching` is `false` (the usual case), finding this `OnMatch` + is terminal. The `Action` is added (or the nested `Matcher` is + evaluated), and the current matcher stops searching. + - If `keep_matching` is `true`, the `Action` is added (or nested `Matcher` evaluated), but the current matcher *continues* to look for more matches. The overall process is not considered complete until an `OnMatch` with `keep_matching` set to `false` is encountered. @@ -434,12 +434,12 @@ results. Generally, only a single `Action` will be returned, unless For simplicity: -* `TypedExtensionConfig` fields: The type is captured in a comment, and the +- `TypedExtensionConfig` fields: The type is captured in a comment, and the value directly contains the unpacked message content. -* `on_match` action: Represented by a string, for example, +- `on_match` action: Represented by a string, for example, `"on_match": { "action": "route_to_cluster_A" }`. -* The first example will include `input` to demonstrate the data flow. -* Other examples will skip the input and simply indicates the result of +- The first example will include `input` to demonstrate the data flow. +- Other examples will skip the input and simply indicates the result of evaluation in `custom_match` field, for example, `{ "custom_match": true }`. For even more examples, refer to @@ -485,44 +485,44 @@ of a single header, the first matching predicate wins. **Request Input 1:** -* Headers: `{ "x-user-segment": "standard-user-1" }` +- Headers: `{ "x-user-segment": "standard-user-1" }` **Evaluation (detailed):** 1. The `matcher_list` evaluates its matchers in order. 2. The first matcher is evaluated. - * The `input` executes `HttpRequestHeaderMatchInput` extension: - * The extension logic extracts the value of the `x-user-segment` + - The `input` executes `HttpRequestHeaderMatchInput` extension: + - The extension logic extracts the value of the `x-user-segment` header from the Matcher Context. - * The `input` returns `standard-user-1`. - * The `StringMatcher` is evaluated (standard matcher): - * The input is a string `standard-user-1`, which is the correct input + - The `input` returns `standard-user-1`. + - The `StringMatcher` is evaluated (standard matcher): + - The input is a string `standard-user-1`, which is the correct input type for this matcher. - * The `StringMatcher` checks if the value `standard-user-1` has + - The `StringMatcher` checks if the value `standard-user-1` has the exact value `premium`. - * The result of matcher evaluation is `false` - * The predicate is `false`, matching continues. + - The result of matcher evaluation is `false` + - The predicate is `false`, matching continues. 3. The second matcher is evaluated: - * The `input` executes `HttpRequestHeaderMatchInput` extension: - * The extension logic extracts the value of the `x-user-segment` + - The `input` executes `HttpRequestHeaderMatchInput` extension: + - The extension logic extracts the value of the `x-user-segment` header from the Matcher Context. - * The `input` returns `standard-user-1`. - * The `StringMatcher` is evaluated (standard matcher): - * The input is a string `standard-user-1`, which is the correct input + - The `input` returns `standard-user-1`. + - The `StringMatcher` is evaluated (standard matcher): + - The input is a string `standard-user-1`, which is the correct input type for this matcher. - * The `StringMatcher` checks if the value `standard-user-1` has the + - The `StringMatcher` checks if the value `standard-user-1` has the prefix `standard-`. - * The result of matcher evaluation is `true` - * The predicate is `true`, its `on_match` is evaluated. - * The action `route_to_standard_cluster` is chosen. - * The `matcher_list` stops processing further matchers because + - The result of matcher evaluation is `true` + - The predicate is `true`, its `on_match` is evaluated. + - The action `route_to_standard_cluster` is chosen. + - The `matcher_list` stops processing further matchers because `keep_matching` is not set. **Result 1:** `["route_to_standard_cluster"]`. **Request Input 2:** -* Headers: `{ "x-user-segment": "guest" }` +- Headers: `{ "x-user-segment": "guest" }` **Evaluation (simplified):** @@ -531,7 +531,7 @@ of a single header, the first matching predicate wins. 3. The second matcher for `standard-` prefix is `false`. 4. No matchers in the list evaluated to `true`, therefore the `on_no_match` is evaluated: - * The action `route_to_default_cluster` is chosen. + - The action `route_to_default_cluster` is chosen. **Result 2:** ["route_to_default_cluster"] @@ -574,12 +574,12 @@ accumulated until a matcher with `keep_matching: false` (the default) is found. **Evaluation:** 1. Matcher 1 evaluates to `true`. - * `action_1` is added to the result list. - * Matching continues because `keep_matching: true`. + - `action_1` is added to the result list. + - Matching continues because `keep_matching: true`. 2. Matcher 2 evaluates to `false`. 3. Matcher 3 evaluates to `true`. - * `action_3` is added to the result list. - * Matching stops because `keep_matching` is false by default. + - `action_3` is added to the result list. + - Matching stops because `keep_matching` is false by default. 4. Matcher 4 is not evaluated. **Result:** `["action_1", "action_3"]` @@ -623,14 +623,14 @@ This example shows a matcher whose action is another matcher. **Evaluation:** 1. The outer `matcher_list` evaluates its first (and only) matcher: - * The predicate of the outer matcher evaluates to `true`. - * The `on_match` of the outer matcher contains a nested matcher. - * The three depth is not greater than 16, the nested matcher is evaluated: + - The predicate of the outer matcher evaluates to `true`. + - The `on_match` of the outer matcher contains a nested matcher. + - The three depth is not greater than 16, the nested matcher is evaluated: 1. The inner `matcher_list` evaluates first matcher to `false`. 2. The inner `matcher_list` evaluates its second matcher to `true`: - * The predicate is `true`, its `on_match` is evaluated. - * The action `inner_match_2` is added to the result list. - * Evaluation stops because `keep_matching` is not set. + - The predicate is `true`, its `on_match` is evaluated. + - The action `inner_match_2` is added to the result list. + - Evaluation stops because `keep_matching` is not set. **Result 1:** `["inner_matcher_2"]` @@ -655,7 +655,7 @@ This shows a prefix map, where the longest prefix match wins. **Request Input:** -* Path: `grpc.channelz.v1.Channelz/GetTopChannels` +- Path: `grpc.channelz.v1.Channelz/GetTopChannels` **Evaluation:** @@ -663,7 +663,7 @@ This shows a prefix map, where the longest prefix match wins. the map keys. 2. It matches both `grpc` and `grpc.channelz`. 3. The longest matching prefix is `grpc.channelz`. - * The action `longer_prefix` is chosen. + - The action `longer_prefix` is chosen. **Result 1:** `["longer_prefix"]` @@ -866,11 +866,11 @@ The main alternative is for each xDS feature (e.g., RLQS, RBAC) to define its own custom matching logic. This is how older xDS features were designed, but it leads to significant drawbacks: -* Duplication and Inconsistency: It forces repeated implementation of +- Duplication and Inconsistency: It forces repeated implementation of common matching primitives (header, path, etc.) across different filters and gRPC language implementations, leading to code bloat and subtle behavioral differences. -* High Maintenance Cost: Bug fixes and new features must be implemented in +- High Maintenance Cost: Bug fixes and new features must be implemented in multiple places. The Unified Matcher API provides a single, consistent, and reusable framework @@ -880,16 +880,16 @@ aligns gRPC with Envoy, creating a more cohesive xDS ecosystem. ### Disadvantages and Trade-offs -* **Increased Complexity**: The system is powerful but also complex. The +- **Increased Complexity**: The system is powerful but also complex. The matcher API involves nested structures, different evaluation flows (`MatcherList` vs. `MatcherTree`), and nuanced behaviors like `keep_matching`. Configuring and debugging this can be more challenging than simpler matching schemes. -* **Restricted CEL Functionality**: To ensure safety and performance, the +- **Restricted CEL Functionality**: To ensure safety and performance, the implementation explicitly disables certain CEL features, such as comprehensions (`exists()`, `all()`). This is a direct trade-off of power for safety, meaning not all standard CEL capabilities are available. -* **Performance Overhead**: Evaluating CEL expressions for every request +- **Performance Overhead**: Evaluating CEL expressions for every request introduces computational overhead. While designed to be fast, it will be slower than simple, hard-coded logic or basic string comparisons. The proposal acknowledges this by recommending performance-conscious From 2cfa55264528cae81405b368c5c3ed077ee1ba45 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 20 Nov 2025 04:44:24 -0800 Subject: [PATCH 27/30] remove rationale fluff --- A106-xds-unified-matcher-and-cel.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index aa83d4bba..22de6081d 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -883,17 +883,15 @@ aligns gRPC with Envoy, creating a more cohesive xDS ecosystem. - **Increased Complexity**: The system is powerful but also complex. The matcher API involves nested structures, different evaluation flows (`MatcherList` vs. `MatcherTree`), and nuanced behaviors like - `keep_matching`. Configuring and debugging this can be more challenging than - simpler matching schemes. + `keep_matching`. Debugging this can be more challenging than simpler + matching schemes. - **Restricted CEL Functionality**: To ensure safety and performance, the implementation explicitly disables certain CEL features, such as comprehensions (`exists()`, `all()`). This is a direct trade-off of power for safety, meaning not all standard CEL capabilities are available. - **Performance Overhead**: Evaluating CEL expressions for every request introduces computational overhead. While designed to be fast, it will be - slower than simple, hard-coded logic or basic string comparisons. The - proposal acknowledges this by recommending performance-conscious - implementation details like on-demand variable resolution. + slower than simple, hard-coded logic or basic string comparisons. ## Implementation From d4ea2fd5f094724c7af9acce6f670089cbc27421 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 20 Nov 2025 08:53:39 -0800 Subject: [PATCH 28/30] date --- A106-xds-unified-matcher-and-cel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 22de6081d..5507acebd 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -4,7 +4,7 @@ A106: xDS Unified Matcher and CEL Integration * Author(s): Sergii Tkachenko (@sergiitk) * Approver: Mark Roth (@markdroth) * Status: In Review -* Last updated: 2025-11-15 +* Last updated: 2025-11-20 * Discussion at: TODO(sergiitk): insert google group thread ## Abstract From 7667e2ee2c626cbf40e10afc9b67dfbdcac47135 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 20 Nov 2025 09:00:46 -0800 Subject: [PATCH 29/30] unto header list indent --- A106-xds-unified-matcher-and-cel.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/A106-xds-unified-matcher-and-cel.md b/A106-xds-unified-matcher-and-cel.md index 5507acebd..3158f5b5e 100644 --- a/A106-xds-unified-matcher-and-cel.md +++ b/A106-xds-unified-matcher-and-cel.md @@ -1,11 +1,11 @@ A106: xDS Unified Matcher and CEL Integration ====== -* Author(s): Sergii Tkachenko (@sergiitk) -* Approver: Mark Roth (@markdroth) -* Status: In Review -* Last updated: 2025-11-20 -* Discussion at: TODO(sergiitk): insert google group thread +* Author(s): Sergii Tkachenko (@sergiitk) +* Approver: Mark Roth (@markdroth) +* Status: In Review +* Last updated: 2025-11-20 +* Discussion at: TODO(sergiitk): insert google group thread ## Abstract From 6270751243a0ba422208fece6723bc5d72079a79 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 20 Nov 2025 09:39:14 -0800 Subject: [PATCH 30/30] --- synced with origin/a106-xds-unified-matcher-and-cel ---