From 6a372234f4d67cac20b1d2efabbfebc838e5d78f Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Tue, 2 Nov 2021 12:08:47 -0700 Subject: [PATCH 01/39] [wip] Add filter chain match predicate order Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener.proto | 36 +++++- .../listener/v3/listener_components.proto | 114 +++++++++++++++++- 2 files changed, 148 insertions(+), 2 deletions(-) diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index f065ff67160b3..d194151a8732e 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -35,7 +35,7 @@ message ListenerCollection { repeated xds.core.v3.CollectionEntry entries = 1; } -// [#next-free-field: 31] +// [#next-free-field: 32] message Listener { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.Listener"; @@ -119,6 +119,40 @@ message Listener { // :ref:`FAQ entry `. repeated FilterChain filter_chains = 3; + // A list of filter chain matching predicate extension type URLs specifying + // the order of selection for the most specific filter chain. At each step, + // the predicate is evaluated for each filter chain. If the predicate returns + // false, the filter chain is eliminated from subsequent consideration. If + // the predicate returns true, but there is a more specific match, it is also + // eliminated. + // + // For example, for SNI ``www.example.com`` the filter chain with the + // predicate ```*.example.com``` remains and the filter chain with the + // predicate ```*.com``` is eliminated, assuming there is no filter chain + // with the exact SNI match. In general, the order of specificity is domain + // specific as defined by the predicate extension. + // + // In case, there is more than one filter chain candidates remaining after + // the process completes, the first of the filter chains in the order of + // their declaration is selected. + // + // If left unspecified, the following default matching order is applied: + // 1. :ref:`DestinationPort `. + // 2. :ref:`DestinationIP `. + // 3. :ref:`SNI `. + // 4. :ref:`TransportProtocol `. + // 5. :ref:`ApplicationProtocol `. + // 6. :ref:`DirectSourceIP `. + // 7. :ref:`SourceType `. + // 8. :ref:`SourceIP `. + // 9. :ref:`SourcePort `. + // + // Filter chain match conditions that are not in the matching order list are + // ignored. Filter chains without a match condition for the specificed + // predicate type URL are assumed to match all. + // [#not-implemented-hide:] + repeated string matching_order = 31; + // If a connection is redirected using *iptables*, the port on which the proxy // receives it might be different from the original destination address. When this flag is set to // true, the listener hands off redirected connections to the listener associated with the diff --git a/api/envoy/config/listener/v3/listener_components.proto b/api/envoy/config/listener/v3/listener_components.proto index e737b14b17456..52b8c90f075d2 100644 --- a/api/envoy/config/listener/v3/listener_components.proto +++ b/api/envoy/config/listener/v3/listener_components.proto @@ -93,7 +93,7 @@ message Filter { // listed at the end, because that's how we want to list them in the docs. // // [#comment:TODO(PiotrSikora): Add support for configurable precedence of the rules] -// [#next-free-field: 14] +// [#next-free-field: 15] message FilterChainMatch { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.listener.FilterChainMatch"; @@ -109,6 +109,113 @@ message FilterChainMatch { EXTERNAL = 2; } + // Matches filter chains by the destination port. + message DestinationPort { + // Optional destination port to consider when use_original_dst is set on the + // listener in determining a filter chain match. + google.protobuf.UInt32Value destination_port = 1 + [(validate.rules).uint32 = {lte: 65535 gte: 1}]; + } + + // Matches filter chains by the destination IP address. + message DestinationIP { + // If non-empty, an IP address and prefix length to match addresses when the + // listener is bound to 0.0.0.0/:: or when use_original_dst is specified. + repeated core.v3.CidrRange prefix_ranges = 1; + } + + // Matches filter chains by the directly connected source IP address (this + // will only be different from the source IP address when using a listener + // filter that overrides the source address, such as the :ref:`Proxy Protocol + // listener filter `). + message DirectSourceIP { + // The criteria is satisfied if the directly connected source IP address of the downstream + // connection is contained in at least one of the specified subnets. If the parameter is not + // specified or the list is empty, the directly connected source IP address is ignored. + repeated core.v3.CidrRange direct_source_prefix_ranges = 1; + } + + // Matches filter chains by the connection source IP type. + message SourceType { + // Specifies the connection source IP match type. Can be any, local or external network. + ConnectionSourceType source_type = 1 [(validate.rules).enum = {defined_only: true}]; + } + + // Matches filter chains by the source IP address. + message SourceIP { + // The criteria is satisfied if the source IP address of the downstream + // connection is contained in at least one of the specified subnets. If the + // parameter is not specified or the list is empty, the source IP address is + // ignored. + repeated core.v3.CidrRange source_prefix_ranges = 1; + } + + // Matches filter chains by the source port. + message SourcePort { + // The criteria is satisfied if the source port of the downstream connection + // is contained in at least one of the specified ports. If the parameter is + // not specified, the source port is ignored. + repeated uint32 source_ports = 1 + [(validate.rules).repeated = {items {uint32 {lte: 65535 gte: 1}}}]; + } + + // Matches filter chains by the server name indication. + message SNI { + // If non-empty, a list of server names (e.g. SNI for TLS protocol) to consider when determining + // a filter chain match. Those values will be compared against the server names of a new + // connection, when detected by one of the listener filters. + // + // The server name will be matched against all wildcard domains, i.e. ``www.example.com`` + // will be first matched against ``www.example.com``, then ``*.example.com``, then ``*.com``. + // + // Note that partial wildcards are not supported, and values like ``*w.example.com`` are invalid. + // + // .. attention:: + // + // See the :ref:`FAQ entry ` on how to configure SNI for more + // information. + repeated string server_names = 1; + } + + // Matches filter chains by the transport protocol. + message TransportProtocol { + // If non-empty, a transport protocol to consider when determining a filter chain match. + // This value will be compared against the transport protocol of a new connection, when + // it's detected by one of the listener filters. + // + // Suggested values include: + // + // * ``raw_buffer`` - default, used when no transport protocol is detected, + // * ``tls`` - set by :ref:`envoy.filters.listener.tls_inspector ` + // when TLS protocol is detected. + string transport_protocol = 1; + } + + // Matches filter chains by the application protocol (e.g. ALPN for TLS protocol). + // [#next-free-field: 11] + message ApplicationProtocol { + // If non-empty, a list of application protocols (e.g. ALPN for TLS protocol) to consider when + // determining a filter chain match. Those values will be compared against the application + // protocols of a new connection, when detected by one of the listener filters. + // + // Suggested values include: + // + // * ``http/1.1`` - set by :ref:`envoy.filters.listener.tls_inspector + // `, + // * ``h2`` - set by :ref:`envoy.filters.listener.tls_inspector ` + // + // .. attention:: + // + // Currently, only :ref:`TLS Inspector ` provides + // application protocol detection based on the requested + // `ALPN `_ values. + // + // However, the use of ALPN is pretty much limited to the HTTP/2 traffic on the Internet, + // and matching on values other than ``h2`` is going to lead to a lot of false negatives, + // unless all connecting clients are known to use ALPN. + repeated string application_protocols = 10; + } + reserved 1; // Optional destination port to consider when use_original_dst is set on the @@ -193,6 +300,11 @@ message FilterChainMatch { // and matching on values other than ``h2`` is going to lead to a lot of false negatives, // unless all connecting clients are known to use ALPN. repeated string application_protocols = 10; + + // Specifies the filter chain matching predicates to be used in the matching order. + // Each predicate extension must be specified at most once. + // [#not-implemented-hide:] + repeated core.v3.TypedExtensionConfig predicates = 14; } // A filter chain wraps a set of match criteria, an option TLS context, a set of filters, and From 8aa165f444d6253888189d2107480a619cec9230 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Tue, 2 Nov 2021 14:26:40 -0700 Subject: [PATCH 02/39] spelling Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener.proto | 2 +- api/envoy/config/listener/v3/listener_components.proto | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index d194151a8732e..52559b2b9e6cb 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -148,7 +148,7 @@ message Listener { // 9. :ref:`SourcePort `. // // Filter chain match conditions that are not in the matching order list are - // ignored. Filter chains without a match condition for the specificed + // ignored. Filter chains without a match condition for the specified // predicate type URL are assumed to match all. // [#not-implemented-hide:] repeated string matching_order = 31; diff --git a/api/envoy/config/listener/v3/listener_components.proto b/api/envoy/config/listener/v3/listener_components.proto index 52b8c90f075d2..893697a87f723 100644 --- a/api/envoy/config/listener/v3/listener_components.proto +++ b/api/envoy/config/listener/v3/listener_components.proto @@ -301,8 +301,11 @@ message FilterChainMatch { // unless all connecting clients are known to use ALPN. repeated string application_protocols = 10; - // Specifies the filter chain matching predicates to be used in the matching order. - // Each predicate extension must be specified at most once. + // Specifies the filter chain matching predicates to be used in the matching + // order. Each predicate extension must be specified at most once. For + // backwards compatibility, the existing fields in the filter chain match, if + // specified, are converted to their corresponding filter chain matching + // predicates in this list. // [#not-implemented-hide:] repeated core.v3.TypedExtensionConfig predicates = 14; } From cfdb93af146ccc9ebf2d18b5cd283b1bbe20ece1 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Fri, 5 Nov 2021 10:45:54 -0700 Subject: [PATCH 03/39] review Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener.proto | 36 +---------- .../listener/v3/listener_components.proto | 59 +++++++++++++++++-- 2 files changed, 54 insertions(+), 41 deletions(-) diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index 52559b2b9e6cb..f065ff67160b3 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -35,7 +35,7 @@ message ListenerCollection { repeated xds.core.v3.CollectionEntry entries = 1; } -// [#next-free-field: 32] +// [#next-free-field: 31] message Listener { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.Listener"; @@ -119,40 +119,6 @@ message Listener { // :ref:`FAQ entry `. repeated FilterChain filter_chains = 3; - // A list of filter chain matching predicate extension type URLs specifying - // the order of selection for the most specific filter chain. At each step, - // the predicate is evaluated for each filter chain. If the predicate returns - // false, the filter chain is eliminated from subsequent consideration. If - // the predicate returns true, but there is a more specific match, it is also - // eliminated. - // - // For example, for SNI ``www.example.com`` the filter chain with the - // predicate ```*.example.com``` remains and the filter chain with the - // predicate ```*.com``` is eliminated, assuming there is no filter chain - // with the exact SNI match. In general, the order of specificity is domain - // specific as defined by the predicate extension. - // - // In case, there is more than one filter chain candidates remaining after - // the process completes, the first of the filter chains in the order of - // their declaration is selected. - // - // If left unspecified, the following default matching order is applied: - // 1. :ref:`DestinationPort `. - // 2. :ref:`DestinationIP `. - // 3. :ref:`SNI `. - // 4. :ref:`TransportProtocol `. - // 5. :ref:`ApplicationProtocol `. - // 6. :ref:`DirectSourceIP `. - // 7. :ref:`SourceType `. - // 8. :ref:`SourceIP `. - // 9. :ref:`SourcePort `. - // - // Filter chain match conditions that are not in the matching order list are - // ignored. Filter chains without a match condition for the specified - // predicate type URL are assumed to match all. - // [#not-implemented-hide:] - repeated string matching_order = 31; - // If a connection is redirected using *iptables*, the port on which the proxy // receives it might be different from the original destination address. When this flag is set to // true, the listener hands off redirected connections to the listener associated with the diff --git a/api/envoy/config/listener/v3/listener_components.proto b/api/envoy/config/listener/v3/listener_components.proto index 893697a87f723..090808bf314f5 100644 --- a/api/envoy/config/listener/v3/listener_components.proto +++ b/api/envoy/config/listener/v3/listener_components.proto @@ -216,6 +216,21 @@ message FilterChainMatch { repeated string application_protocols = 10; } + // Individual filter chain match predicate. + message FilterChainMatchPredicate { + // The typed config for the match predicate extension. The type URL will be + // used to identify the extension. In the case that the type URL is + // *xds.type.v3.TypedStruct* (or, for historical reasons, + // *udpa.type.v1.TypedStruct*), the inner type URL of *TypedStruct* will be + // utilized. See the :ref:`extension configuration overview + // ` for further details. + google.protobuf.Any typed_config = 1 [(validate.rules).any = {required: true}]; + + // Flag to continue matching if this match is a wildcard match and there is a + // more specific match. + bool fallthrough = 2; + } + reserved 1; // Optional destination port to consider when use_original_dst is set on the @@ -301,13 +316,45 @@ message FilterChainMatch { // unless all connecting clients are known to use ALPN. repeated string application_protocols = 10; - // Specifies the filter chain matching predicates to be used in the matching - // order. Each predicate extension must be specified at most once. For - // backwards compatibility, the existing fields in the filter chain match, if - // specified, are converted to their corresponding filter chain matching - // predicates in this list. + // A list of filter chain matching predicate extensions specifying the order + // of selection for the most specific filter chain. The filter chains in a + // single listener must have the identical order of predicate extension type + // URLs. For backwards compatibility, if the existing fields in the filter + // chain match are specified, the fields are converted to their corresponding + // filter chain matching predicates in the following default matching order: + // 1. :ref:`DestinationPort `. + // 2. :ref:`DestinationIP `. + // 3. :ref:`SNI `. + // 4. :ref:`TransportProtocol `. + // 5. :ref:`ApplicationProtocol `. + // 6. :ref:`DirectSourceIP `. + // 7. :ref:`SourceType `. + // 8. :ref:`SourceIP `. + // 9. :ref:`SourcePort `. + // + // At each step, the predicate is evaluated for each filter chain. If the + // predicate returns false, the filter chain is eliminated from subsequent + // consideration. If the predicate returns true, then the decision is based + // on the ``fallthrough`` flag. If there is another more specific match for + // the same predicate and the flag is not set, then the less specific match + // is eliminated. If the flag is set, then it remains as a candidate for the + // next step. + // + // For example, consider SNI ``www.example.com``and two filter chains with + // the predicates ```*.example.com``` and ```*.com```. If ``fallthrough`` + // flag is not set then only the filter chain ```*.example.com``` matches. If + // ``fallthrough`` flag is set on ```*.com```, then both filter chains match. + // In general, the order of specificity is domain specific as defined by the + // predicate extension. The flag should be set when matching on multiple + // properties in order for a default chain to apply without explicit specific + // matching of the first properties in the list. + // + // In case, there is more than one filter chain candidates remaining after + // the process completes, the first of the filter chains in the order of + // their declaration is selected. + // // [#not-implemented-hide:] - repeated core.v3.TypedExtensionConfig predicates = 14; + repeated FilterChainMatchPredicate predicates = 14; } // A filter chain wraps a set of match criteria, an option TLS context, a set of filters, and From a13ed92033aabe824af36ea484085c04884466df Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Fri, 5 Nov 2021 10:52:33 -0700 Subject: [PATCH 04/39] review Signed-off-by: Kuat Yessenov --- .../config/listener/v3/listener_components.proto | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/api/envoy/config/listener/v3/listener_components.proto b/api/envoy/config/listener/v3/listener_components.proto index 090808bf314f5..680600b9f6c90 100644 --- a/api/envoy/config/listener/v3/listener_components.proto +++ b/api/envoy/config/listener/v3/listener_components.proto @@ -110,17 +110,22 @@ message FilterChainMatch { } // Matches filter chains by the destination port. + // [#next-free-field: 6] message DestinationPort { // Optional destination port to consider when use_original_dst is set on the // listener in determining a filter chain match. google.protobuf.UInt32Value destination_port = 1 [(validate.rules).uint32 = {lte: 65535 gte: 1}]; + + // Match destination port by range. + type.v3.Int32Range destination_port_range = 5; } // Matches filter chains by the destination IP address. message DestinationIP { // If non-empty, an IP address and prefix length to match addresses when the // listener is bound to 0.0.0.0/:: or when use_original_dst is specified. + // Empty list matches all. repeated core.v3.CidrRange prefix_ranges = 1; } @@ -130,8 +135,8 @@ message FilterChainMatch { // listener filter `). message DirectSourceIP { // The criteria is satisfied if the directly connected source IP address of the downstream - // connection is contained in at least one of the specified subnets. If the parameter is not - // specified or the list is empty, the directly connected source IP address is ignored. + // connection is contained in at least one of the specified subnets. If the list is empty, + // the directly connected source IP address is ignored. repeated core.v3.CidrRange direct_source_prefix_ranges = 1; } @@ -144,8 +149,7 @@ message FilterChainMatch { // Matches filter chains by the source IP address. message SourceIP { // The criteria is satisfied if the source IP address of the downstream - // connection is contained in at least one of the specified subnets. If the - // parameter is not specified or the list is empty, the source IP address is + // connection is contained in at least one of the specified subnets. If the list is empty, the source IP address is // ignored. repeated core.v3.CidrRange source_prefix_ranges = 1; } @@ -192,7 +196,6 @@ message FilterChainMatch { } // Matches filter chains by the application protocol (e.g. ALPN for TLS protocol). - // [#next-free-field: 11] message ApplicationProtocol { // If non-empty, a list of application protocols (e.g. ALPN for TLS protocol) to consider when // determining a filter chain match. Those values will be compared against the application @@ -213,7 +216,7 @@ message FilterChainMatch { // However, the use of ALPN is pretty much limited to the HTTP/2 traffic on the Internet, // and matching on values other than ``h2`` is going to lead to a lot of false negatives, // unless all connecting clients are known to use ALPN. - repeated string application_protocols = 10; + repeated string application_protocols = 1; } // Individual filter chain match predicate. From 2228fef36e9f6a766868f0c1163047b65c334709 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Mon, 8 Nov 2021 14:19:05 -0800 Subject: [PATCH 05/39] review Signed-off-by: Kuat Yessenov --- .../listener/v3/listener_components.proto | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/api/envoy/config/listener/v3/listener_components.proto b/api/envoy/config/listener/v3/listener_components.proto index 680600b9f6c90..3df69a8bfbbc3 100644 --- a/api/envoy/config/listener/v3/listener_components.proto +++ b/api/envoy/config/listener/v3/listener_components.proto @@ -110,15 +110,14 @@ message FilterChainMatch { } // Matches filter chains by the destination port. - // [#next-free-field: 6] message DestinationPort { // Optional destination port to consider when use_original_dst is set on the // listener in determining a filter chain match. google.protobuf.UInt32Value destination_port = 1 [(validate.rules).uint32 = {lte: 65535 gte: 1}]; - // Match destination port by range. - type.v3.Int32Range destination_port_range = 5; + // Match destination port by ranges. + repeated type.v3.Int32Range destination_port_ranges = 2; } // Matches filter chains by the destination IP address. @@ -157,10 +156,9 @@ message FilterChainMatch { // Matches filter chains by the source port. message SourcePort { // The criteria is satisfied if the source port of the downstream connection - // is contained in at least one of the specified ports. If the parameter is + // is contained in at least one of the specified port ranges. If the parameter is // not specified, the source port is ignored. - repeated uint32 source_ports = 1 - [(validate.rules).repeated = {items {uint32 {lte: 65535 gte: 1}}}]; + repeated type.v3.Int32Range source_port_ranges = 1; } // Matches filter chains by the server name indication. @@ -341,17 +339,25 @@ message FilterChainMatch { // on the ``fallthrough`` flag. If there is another more specific match for // the same predicate and the flag is not set, then the less specific match // is eliminated. If the flag is set, then it remains as a candidate for the - // next step. - // - // For example, consider SNI ``www.example.com``and two filter chains with - // the predicates ```*.example.com``` and ```*.com```. If ``fallthrough`` - // flag is not set then only the filter chain ```*.example.com``` matches. If - // ``fallthrough`` flag is set on ```*.com```, then both filter chains match. - // In general, the order of specificity is domain specific as defined by the + // next step. In general, the order of specificity is domain specific to the // predicate extension. The flag should be set when matching on multiple // properties in order for a default chain to apply without explicit specific // matching of the first properties in the list. // + // As an example, consider a filter chain ``FC1`` matching plaintext HTTP + // traffic on destination port 80, and another pass-through filter chain + // ``FC2`` for the rest of the traffic. The first chain match condition can + // be expressed with the transport protocol match on ``raw_buffer``, the + // application protocol match on ``http/1.1`` and ``h2``, and the destination + // port match on 80, in this order. If the second filter chain match does not + // specify ``fallthrough`` for any of its empty predicates, then for the + // plaintext non-HTTP traffic, ``FC2`` is not selected because it is + // eliminated at the first step as being less specific than ``FC1`` on the + // transport protocol match ``raw_buffer``. Therefore, ``FC2`` should specify + // ``fallthrough`` flag for both the transport protocol and the application + // protocol match predicates, in order to match plaintext non-HTTP traffic as + // well as plaintext HTTP traffic on ports other than 80. + // // In case, there is more than one filter chain candidates remaining after // the process completes, the first of the filter chains in the order of // their declaration is selected. From f45bc06742890f598b3d1efd760c8e3d978baaef Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Mon, 15 Nov 2021 14:12:25 -0800 Subject: [PATCH 06/39] review Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/BUILD | 1 + api/envoy/config/listener/v3/listener.proto | 40 ++- .../listener/v3/listener_components.proto | 277 +++++++++--------- 3 files changed, 172 insertions(+), 146 deletions(-) diff --git a/api/envoy/config/listener/v3/BUILD b/api/envoy/config/listener/v3/BUILD index c2d6c133a73ae..fc2ebb5ae174d 100644 --- a/api/envoy/config/listener/v3/BUILD +++ b/api/envoy/config/listener/v3/BUILD @@ -8,6 +8,7 @@ api_proto_package( deps = [ "//envoy/annotations:pkg", "//envoy/config/accesslog/v3:pkg", + "//envoy/config/common/matcher/v3:pkg", "//envoy/config/core/v3:pkg", "//envoy/type/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index f065ff67160b3..fb0490130eba3 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -3,8 +3,10 @@ syntax = "proto3"; package envoy.config.listener.v3; import "envoy/config/accesslog/v3/accesslog.proto"; +import "envoy/config/common/matcher/v3/matcher.proto"; import "envoy/config/core/v3/address.proto"; import "envoy/config/core/v3/base.proto"; +import "envoy/config/core/v3/extension.proto"; import "envoy/config/core/v3/socket_option.proto"; import "envoy/config/listener/v3/api_listener.proto"; import "envoy/config/listener/v3/listener_components.proto"; @@ -35,7 +37,7 @@ message ListenerCollection { repeated xds.core.v3.CollectionEntry entries = 1; } -// [#next-free-field: 31] +// [#next-free-field: 33] message Listener { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.Listener"; @@ -93,6 +95,23 @@ message Listener { message InternalListenerConfig { } + // Filter chain with a name. + message NamedFilterChain { + // Filter chain name. + string name = 1 [(validate.rules).string = {min_len: 1}]; + + oneof config_type { + // Filter chain configuration. + FilterChain filter_chain = 2; + + // Configuration source specifier for an extension configuration discovery + // service. In case of a failure and without the default configuration, the + // connection is rejected. + // [#not-implemented-hide:] + core.v3.ExtensionConfigSource config_discovery = 3; + } + } + reserved 14, 23; // The unique name by which this listener is known. If no name is provided, @@ -119,6 +138,25 @@ message Listener { // :ref:`FAQ entry `. repeated FilterChain filter_chains = 3; + // A filter chain matcher resolving the filter chain name based on the connection properties. + // The following inputs are supported by the matcher: + // + // 1. :ref:`DestinationPort `. + // 2. :ref:`DestinationIP `. + // 3. :ref:`SNI `. + // 4. :ref:`TransportProtocol `. + // 5. :ref:`ApplicationProtocol `. + // 6. :ref:`DirectSourceIP `. + // 7. :ref:`SourceType `. + // 8. :ref:`SourceIP `. + // 9. :ref:`SourcePort `. + // [#not-implemented-hide:] + repeated common.matcher.v3.Matcher filter_chain_matcher = 31; + + // Filter chains. + // [#not-implemented-hide:] + repeated NamedFilterChain named_filter_chains = 32; + // If a connection is redirected using *iptables*, the port on which the proxy // receives it might be different from the original destination address. When this flag is set to // true, the listener hands off redirected connections to the listener associated with the diff --git a/api/envoy/config/listener/v3/listener_components.proto b/api/envoy/config/listener/v3/listener_components.proto index 3df69a8bfbbc3..881810cc08d6f 100644 --- a/api/envoy/config/listener/v3/listener_components.proto +++ b/api/envoy/config/listener/v3/listener_components.proto @@ -2,6 +2,7 @@ syntax = "proto3"; package envoy.config.listener.v3; +import "envoy/config/common/matcher/v3/matcher.proto"; import "envoy/config/core/v3/address.proto"; import "envoy/config/core/v3/base.proto"; import "envoy/config/core/v3/extension.proto"; @@ -93,7 +94,7 @@ message Filter { // listed at the end, because that's how we want to list them in the docs. // // [#comment:TODO(PiotrSikora): Add support for configurable precedence of the rules] -// [#next-free-field: 15] +// [#next-free-field: 14] message FilterChainMatch { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.listener.FilterChainMatch"; @@ -110,126 +111,160 @@ message FilterChainMatch { } // Matches filter chains by the destination port. - message DestinationPort { - // Optional destination port to consider when use_original_dst is set on the - // listener in determining a filter chain match. - google.protobuf.UInt32Value destination_port = 1 - [(validate.rules).uint32 = {lte: 65535 gte: 1}]; - - // Match destination port by ranges. - repeated type.v3.Int32Range destination_port_ranges = 2; + message DestinationPortInput { } // Matches filter chains by the destination IP address. - message DestinationIP { - // If non-empty, an IP address and prefix length to match addresses when the - // listener is bound to 0.0.0.0/:: or when use_original_dst is specified. - // Empty list matches all. - repeated core.v3.CidrRange prefix_ranges = 1; + message DestinationIPInput { + } + + // Matches filter chains by the source IP address. + message SourceIPInput { } // Matches filter chains by the directly connected source IP address (this // will only be different from the source IP address when using a listener // filter that overrides the source address, such as the :ref:`Proxy Protocol // listener filter `). - message DirectSourceIP { - // The criteria is satisfied if the directly connected source IP address of the downstream - // connection is contained in at least one of the specified subnets. If the list is empty, - // the directly connected source IP address is ignored. - repeated core.v3.CidrRange direct_source_prefix_ranges = 1; + message DirectSourceIPInput { + } + + // Matches filter chains by the source port. + message SourcePortInput { } // Matches filter chains by the connection source IP type. - message SourceType { - // Specifies the connection source IP match type. Can be any, local or external network. - ConnectionSourceType source_type = 1 [(validate.rules).enum = {defined_only: true}]; + // Specifies the connection source IP match type. The values include: + // + // * ``any`` - any connection source, + // * ``local`` - matches a connection originating from the same host, + // * ``external`` - matches a connection originating from a different host + message SourceTypeInput { } - // Matches filter chains by the source IP address. - message SourceIP { - // The criteria is satisfied if the source IP address of the downstream - // connection is contained in at least one of the specified subnets. If the list is empty, the source IP address is - // ignored. - repeated core.v3.CidrRange source_prefix_ranges = 1; + // Matches filter chains by the server names of a new connection, when detected by one of the listener filters. + message SNIInput { } - // Matches filter chains by the source port. - message SourcePort { - // The criteria is satisfied if the source port of the downstream connection - // is contained in at least one of the specified port ranges. If the parameter is - // not specified, the source port is ignored. - repeated type.v3.Int32Range source_port_ranges = 1; + // Matches filter chains by the transport protocol. + // This value will be compared against the transport protocol of a new connection, when + // it's detected by one of the listener filters. + // + // Suggested values include: + // + // * ``raw_buffer`` - default, used when no transport protocol is detected, + // * ``tls`` - set by :ref:`envoy.filters.listener.tls_inspector ` + // when TLS protocol is detected. + message TransportProtocolInput { } - // Matches filter chains by the server name indication. - message SNI { - // If non-empty, a list of server names (e.g. SNI for TLS protocol) to consider when determining - // a filter chain match. Those values will be compared against the server names of a new - // connection, when detected by one of the listener filters. - // - // The server name will be matched against all wildcard domains, i.e. ``www.example.com`` - // will be first matched against ``www.example.com``, then ``*.example.com``, then ``*.com``. - // - // Note that partial wildcards are not supported, and values like ``*w.example.com`` are invalid. - // - // .. attention:: - // - // See the :ref:`FAQ entry ` on how to configure SNI for more - // information. - repeated string server_names = 1; + // Matches filter chains by the application protocol (e.g. ALPN for TLS protocol). + // This values will be compared against the application + // protocols of a new connection, when detected by one of the listener filters. + // + // Suggested values include: + // + // * ``http/1.1`` - set by :ref:`envoy.filters.listener.tls_inspector + // `, + // * ``h2`` - set by :ref:`envoy.filters.listener.tls_inspector ` + // + // .. attention:: + // + // Currently, only :ref:`TLS Inspector ` provides + // application protocol detection based on the requested + // `ALPN `_ values. + // + // However, the use of ALPN is pretty much limited to the HTTP/2 traffic on the Internet, + // and matching on values other than ``h2`` is going to lead to a lot of false negatives, + // unless all connecting clients are known to use ALPN. + message ApplicationProtocolInput { } - // Matches filter chains by the transport protocol. - message TransportProtocol { - // If non-empty, a transport protocol to consider when determining a filter chain match. - // This value will be compared against the transport protocol of a new connection, when - // it's detected by one of the listener filters. - // - // Suggested values include: - // - // * ``raw_buffer`` - default, used when no transport protocol is detected, - // * ``tls`` - set by :ref:`envoy.filters.listener.tls_inspector ` - // when TLS protocol is detected. - string transport_protocol = 1; + // Matches a specific port against a set of possibly overlapping port ranges. + message PortMatcher { + // Specifies an optional list of port ranges and a match action. + message PortRangeMatcher { + // Optional set of port ranges. An empty set matches any port. + repeated type.v3.Int32Range ranges = 1; + + // Match action to apply when the port is within one of the port ranges. + common.matcher.v3.Matcher.OnMatch on_match = 2; + + // Indicates whether this match option should be considered if there is a + // matcher for the specific port value. For example, consider a matcher + // for the port range [1, 1000] applied to a specific port 80. If there + // is another matcher for the specific port 80 that fully matches, then + // the specific port matcher is selected. However, if the specific port + // matcher does not fully match, then the behavior depends on whether the + // range matcher [1, 1000] is exclusive. Exclusive port matchers do not + // apply when there is a more specific port match. Non-exclusive port + // matchers may apply when the nested match conditions are satisfied for + // the range matcher but not for the specific port value nested matcher. + // + // The order of range matchers is important since it dictates the order + // of matching in case of overlapping port ranges. + bool exclusive = 3; + } + + // Match port by value. Takes precedence over matching by the port ranges. + map port_map = 1; + + // Match port by port ranges. + repeated PortRangeMatcher range_matchers = 2; } - // Matches filter chains by the application protocol (e.g. ALPN for TLS protocol). - message ApplicationProtocol { - // If non-empty, a list of application protocols (e.g. ALPN for TLS protocol) to consider when - // determining a filter chain match. Those values will be compared against the application - // protocols of a new connection, when detected by one of the listener filters. - // - // Suggested values include: - // - // * ``http/1.1`` - set by :ref:`envoy.filters.listener.tls_inspector - // `, - // * ``h2`` - set by :ref:`envoy.filters.listener.tls_inspector ` - // - // .. attention:: - // - // Currently, only :ref:`TLS Inspector ` provides - // application protocol detection based on the requested - // `ALPN `_ values. - // - // However, the use of ALPN is pretty much limited to the HTTP/2 traffic on the Internet, - // and matching on values other than ``h2`` is going to lead to a lot of false negatives, - // unless all connecting clients are known to use ALPN. - repeated string application_protocols = 1; + // Matches a specific IP address against a set of possibly overlapping subnets. + message IPMatcher { + // Specifies an optional list of IP address ranges and a match action. + message IPRangeMatcher { + // Optional set of CIDR ranges. An empty set matches any IP address. + repeated core.v3.CidrRange ranges = 1; + + // Match action to apply when the IP address is within one of the CIDR ranges. + common.matcher.v3.Matcher.OnMatch on_match = 2; + + // Indicates whether this match option should be considered if there is a + // more specific matcher. Exclusive matchers are not selected whenever a + // more specific matcher exists (e.g. matcher with a longer prefix) even + // when the more specific matcher fails its nested match condition. + // Non-exclusive matchers are considered if the more specific matcher + // exists but its nested match condition does not entirely match. + // Non-exclusive matchers are selected in the order of their specificity + // first (longest prefix first), then the order of declaration next. + bool exclusive = 3; + } + + // Match IP address by CIDR ranges. + repeated IPRangeMatcher range_matchers = 1; } - // Individual filter chain match predicate. - message FilterChainMatchPredicate { - // The typed config for the match predicate extension. The type URL will be - // used to identify the extension. In the case that the type URL is - // *xds.type.v3.TypedStruct* (or, for historical reasons, - // *udpa.type.v1.TypedStruct*), the inner type URL of *TypedStruct* will be - // utilized. See the :ref:`extension configuration overview - // ` for further details. - google.protobuf.Any typed_config = 1 [(validate.rules).any = {required: true}]; - - // Flag to continue matching if this match is a wildcard match and there is a - // more specific match. - bool fallthrough = 2; + // Matches a specific server name against of a set of possibly overlapping wildcard domains. + message ServerNameMatcher { + // Specifies an optional list of wildcard domains and a match action. + // The server name will be matched against all wildcard domains, i.e. ``www.example.com`` + // will be first matched against ``www.example.com``, then ``*.example.com``, then ``*.com``. + // + // Note that partial wildcards are not supported, and values like ``*w.example.com`` are invalid. + message DomainMatcher { + // Optional set of wildcard domains. An empty set matches any server name. + repeated string server_names = 1; + + // Match action to apply when the server name matches. + common.matcher.v3.Matcher.OnMatch on_match = 2; + + // Indicates whether this match option should be considered if there is a + // more specific matcher. Exclusive matches are not selected whenever a + // more specific matcher exists even when the more specific matcher fails + // to match its nested match condition. For example, an exclusive matcher + // for ```*.com``` does not match ``www.example.com``` if there is a + // matcher for ```*.example.com```. Matchers are selected in the order of + // their specificity first (longest suffix first), then + // the order of declaration next. + bool exclusive = 3; + } + + // Match server name by wildcard domains. + repeated DomainMatcher domain_matchers = 1; } reserved 1; @@ -316,54 +351,6 @@ message FilterChainMatch { // and matching on values other than ``h2`` is going to lead to a lot of false negatives, // unless all connecting clients are known to use ALPN. repeated string application_protocols = 10; - - // A list of filter chain matching predicate extensions specifying the order - // of selection for the most specific filter chain. The filter chains in a - // single listener must have the identical order of predicate extension type - // URLs. For backwards compatibility, if the existing fields in the filter - // chain match are specified, the fields are converted to their corresponding - // filter chain matching predicates in the following default matching order: - // 1. :ref:`DestinationPort `. - // 2. :ref:`DestinationIP `. - // 3. :ref:`SNI `. - // 4. :ref:`TransportProtocol `. - // 5. :ref:`ApplicationProtocol `. - // 6. :ref:`DirectSourceIP `. - // 7. :ref:`SourceType `. - // 8. :ref:`SourceIP `. - // 9. :ref:`SourcePort `. - // - // At each step, the predicate is evaluated for each filter chain. If the - // predicate returns false, the filter chain is eliminated from subsequent - // consideration. If the predicate returns true, then the decision is based - // on the ``fallthrough`` flag. If there is another more specific match for - // the same predicate and the flag is not set, then the less specific match - // is eliminated. If the flag is set, then it remains as a candidate for the - // next step. In general, the order of specificity is domain specific to the - // predicate extension. The flag should be set when matching on multiple - // properties in order for a default chain to apply without explicit specific - // matching of the first properties in the list. - // - // As an example, consider a filter chain ``FC1`` matching plaintext HTTP - // traffic on destination port 80, and another pass-through filter chain - // ``FC2`` for the rest of the traffic. The first chain match condition can - // be expressed with the transport protocol match on ``raw_buffer``, the - // application protocol match on ``http/1.1`` and ``h2``, and the destination - // port match on 80, in this order. If the second filter chain match does not - // specify ``fallthrough`` for any of its empty predicates, then for the - // plaintext non-HTTP traffic, ``FC2`` is not selected because it is - // eliminated at the first step as being less specific than ``FC1`` on the - // transport protocol match ``raw_buffer``. Therefore, ``FC2`` should specify - // ``fallthrough`` flag for both the transport protocol and the application - // protocol match predicates, in order to match plaintext non-HTTP traffic as - // well as plaintext HTTP traffic on ports other than 80. - // - // In case, there is more than one filter chain candidates remaining after - // the process completes, the first of the filter chains in the order of - // their declaration is selected. - // - // [#not-implemented-hide:] - repeated FilterChainMatchPredicate predicates = 14; } // A filter chain wraps a set of match criteria, an option TLS context, a set of filters, and From 937f7a86f00282da49ff7090a21177d6c9e454f1 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Wed, 17 Nov 2021 13:39:24 -0800 Subject: [PATCH 07/39] review Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/BUILD | 2 +- api/envoy/config/listener/v3/listener.proto | 47 +-- .../listener/v3/listener_components.proto | 317 +++++++++--------- 3 files changed, 177 insertions(+), 189 deletions(-) diff --git a/api/envoy/config/listener/v3/BUILD b/api/envoy/config/listener/v3/BUILD index fc2ebb5ae174d..75f6e10c7e4f9 100644 --- a/api/envoy/config/listener/v3/BUILD +++ b/api/envoy/config/listener/v3/BUILD @@ -8,10 +8,10 @@ api_proto_package( deps = [ "//envoy/annotations:pkg", "//envoy/config/accesslog/v3:pkg", - "//envoy/config/common/matcher/v3:pkg", "//envoy/config/core/v3:pkg", "//envoy/type/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", "@com_github_cncf_udpa//xds/core/v3:pkg", + "@com_github_cncf_udpa//xds/type/matcher/v3:pkg", ], ) diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index fb0490130eba3..fc4b16e1814b2 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -3,7 +3,6 @@ syntax = "proto3"; package envoy.config.listener.v3; import "envoy/config/accesslog/v3/accesslog.proto"; -import "envoy/config/common/matcher/v3/matcher.proto"; import "envoy/config/core/v3/address.proto"; import "envoy/config/core/v3/base.proto"; import "envoy/config/core/v3/extension.proto"; @@ -16,6 +15,7 @@ import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; import "xds/core/v3/collection_entry.proto"; +import "xds/type/matcher/v3/matcher.proto"; import "envoy/annotations/deprecation.proto"; import "udpa/annotations/security.proto"; @@ -95,23 +95,6 @@ message Listener { message InternalListenerConfig { } - // Filter chain with a name. - message NamedFilterChain { - // Filter chain name. - string name = 1 [(validate.rules).string = {min_len: 1}]; - - oneof config_type { - // Filter chain configuration. - FilterChain filter_chain = 2; - - // Configuration source specifier for an extension configuration discovery - // service. In case of a failure and without the default configuration, the - // connection is rejected. - // [#not-implemented-hide:] - core.v3.ExtensionConfigSource config_discovery = 3; - } - } - reserved 14, 23; // The unique name by which this listener is known. If no name is provided, @@ -141,21 +124,25 @@ message Listener { // A filter chain matcher resolving the filter chain name based on the connection properties. // The following inputs are supported by the matcher: // - // 1. :ref:`DestinationPort `. - // 2. :ref:`DestinationIP `. - // 3. :ref:`SNI `. - // 4. :ref:`TransportProtocol `. - // 5. :ref:`ApplicationProtocol `. - // 6. :ref:`DirectSourceIP `. - // 7. :ref:`SourceType `. - // 8. :ref:`SourceIP `. - // 9. :ref:`SourcePort `. + // 1. :ref:`DestinationPort `. + // 2. :ref:`DestinationIP `. + // 3. :ref:`SNI `. + // 4. :ref:`TransportProtocol `. + // 5. :ref:`ApplicationProtocol `. + // 6. :ref:`DirectSourceIP `. + // 7. :ref:`SourceType `. + // 8. :ref:`SourceIP `. + // 9. :ref:`SourcePort `. + // + // If specified, all :ref:`filter_chains ` must + // have a non-empty :ref:`name ` and empty :ref:`filter_chain_match `. // [#not-implemented-hide:] - repeated common.matcher.v3.Matcher filter_chain_matcher = 31; + repeated xds.type.matcher.v3.Matcher filter_chain_matcher = 31; - // Filter chains. + // Defines the discovery service configuration for filter chains indexed by the filter chain name. + // The set of filter chain names must be disjoint from the filter chain names in the field :ref:`filter_chains `. // [#not-implemented-hide:] - repeated NamedFilterChain named_filter_chains = 32; + map filter_chain_discovery = 32; // If a connection is redirected using *iptables*, the port on which the proxy // receives it might be different from the original destination address. When this flag is set to diff --git a/api/envoy/config/listener/v3/listener_components.proto b/api/envoy/config/listener/v3/listener_components.proto index 881810cc08d6f..ad8024036998f 100644 --- a/api/envoy/config/listener/v3/listener_components.proto +++ b/api/envoy/config/listener/v3/listener_components.proto @@ -2,7 +2,6 @@ syntax = "proto3"; package envoy.config.listener.v3; -import "envoy/config/common/matcher/v3/matcher.proto"; import "envoy/config/core/v3/address.proto"; import "envoy/config/core/v3/base.proto"; import "envoy/config/core/v3/extension.proto"; @@ -12,6 +11,8 @@ import "google/protobuf/any.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; +import "xds/type/matcher/v3/matcher.proto"; + import "envoy/annotations/deprecation.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; @@ -110,163 +111,6 @@ message FilterChainMatch { EXTERNAL = 2; } - // Matches filter chains by the destination port. - message DestinationPortInput { - } - - // Matches filter chains by the destination IP address. - message DestinationIPInput { - } - - // Matches filter chains by the source IP address. - message SourceIPInput { - } - - // Matches filter chains by the directly connected source IP address (this - // will only be different from the source IP address when using a listener - // filter that overrides the source address, such as the :ref:`Proxy Protocol - // listener filter `). - message DirectSourceIPInput { - } - - // Matches filter chains by the source port. - message SourcePortInput { - } - - // Matches filter chains by the connection source IP type. - // Specifies the connection source IP match type. The values include: - // - // * ``any`` - any connection source, - // * ``local`` - matches a connection originating from the same host, - // * ``external`` - matches a connection originating from a different host - message SourceTypeInput { - } - - // Matches filter chains by the server names of a new connection, when detected by one of the listener filters. - message SNIInput { - } - - // Matches filter chains by the transport protocol. - // This value will be compared against the transport protocol of a new connection, when - // it's detected by one of the listener filters. - // - // Suggested values include: - // - // * ``raw_buffer`` - default, used when no transport protocol is detected, - // * ``tls`` - set by :ref:`envoy.filters.listener.tls_inspector ` - // when TLS protocol is detected. - message TransportProtocolInput { - } - - // Matches filter chains by the application protocol (e.g. ALPN for TLS protocol). - // This values will be compared against the application - // protocols of a new connection, when detected by one of the listener filters. - // - // Suggested values include: - // - // * ``http/1.1`` - set by :ref:`envoy.filters.listener.tls_inspector - // `, - // * ``h2`` - set by :ref:`envoy.filters.listener.tls_inspector ` - // - // .. attention:: - // - // Currently, only :ref:`TLS Inspector ` provides - // application protocol detection based on the requested - // `ALPN `_ values. - // - // However, the use of ALPN is pretty much limited to the HTTP/2 traffic on the Internet, - // and matching on values other than ``h2`` is going to lead to a lot of false negatives, - // unless all connecting clients are known to use ALPN. - message ApplicationProtocolInput { - } - - // Matches a specific port against a set of possibly overlapping port ranges. - message PortMatcher { - // Specifies an optional list of port ranges and a match action. - message PortRangeMatcher { - // Optional set of port ranges. An empty set matches any port. - repeated type.v3.Int32Range ranges = 1; - - // Match action to apply when the port is within one of the port ranges. - common.matcher.v3.Matcher.OnMatch on_match = 2; - - // Indicates whether this match option should be considered if there is a - // matcher for the specific port value. For example, consider a matcher - // for the port range [1, 1000] applied to a specific port 80. If there - // is another matcher for the specific port 80 that fully matches, then - // the specific port matcher is selected. However, if the specific port - // matcher does not fully match, then the behavior depends on whether the - // range matcher [1, 1000] is exclusive. Exclusive port matchers do not - // apply when there is a more specific port match. Non-exclusive port - // matchers may apply when the nested match conditions are satisfied for - // the range matcher but not for the specific port value nested matcher. - // - // The order of range matchers is important since it dictates the order - // of matching in case of overlapping port ranges. - bool exclusive = 3; - } - - // Match port by value. Takes precedence over matching by the port ranges. - map port_map = 1; - - // Match port by port ranges. - repeated PortRangeMatcher range_matchers = 2; - } - - // Matches a specific IP address against a set of possibly overlapping subnets. - message IPMatcher { - // Specifies an optional list of IP address ranges and a match action. - message IPRangeMatcher { - // Optional set of CIDR ranges. An empty set matches any IP address. - repeated core.v3.CidrRange ranges = 1; - - // Match action to apply when the IP address is within one of the CIDR ranges. - common.matcher.v3.Matcher.OnMatch on_match = 2; - - // Indicates whether this match option should be considered if there is a - // more specific matcher. Exclusive matchers are not selected whenever a - // more specific matcher exists (e.g. matcher with a longer prefix) even - // when the more specific matcher fails its nested match condition. - // Non-exclusive matchers are considered if the more specific matcher - // exists but its nested match condition does not entirely match. - // Non-exclusive matchers are selected in the order of their specificity - // first (longest prefix first), then the order of declaration next. - bool exclusive = 3; - } - - // Match IP address by CIDR ranges. - repeated IPRangeMatcher range_matchers = 1; - } - - // Matches a specific server name against of a set of possibly overlapping wildcard domains. - message ServerNameMatcher { - // Specifies an optional list of wildcard domains and a match action. - // The server name will be matched against all wildcard domains, i.e. ``www.example.com`` - // will be first matched against ``www.example.com``, then ``*.example.com``, then ``*.com``. - // - // Note that partial wildcards are not supported, and values like ``*w.example.com`` are invalid. - message DomainMatcher { - // Optional set of wildcard domains. An empty set matches any server name. - repeated string server_names = 1; - - // Match action to apply when the server name matches. - common.matcher.v3.Matcher.OnMatch on_match = 2; - - // Indicates whether this match option should be considered if there is a - // more specific matcher. Exclusive matches are not selected whenever a - // more specific matcher exists even when the more specific matcher fails - // to match its nested match condition. For example, an exclusive matcher - // for ```*.com``` does not match ``www.example.com``` if there is a - // matcher for ```*.example.com```. Matchers are selected in the order of - // their specificity first (longest suffix first), then - // the order of declaration next. - bool exclusive = 3; - } - - // Match server name by wildcard domains. - repeated DomainMatcher domain_matchers = 1; - } - reserved 1; // Optional destination port to consider when use_original_dst is set on the @@ -515,3 +359,160 @@ message ListenerFilter { // for further examples. ListenerFilterChainMatchPredicate filter_disabled = 4; } + +// Matcher input that allows matching connections by by the destination port. +message DestinationPortInput { +} + +// Matcher input that allows matching connections by by the destination IP address. +message DestinationIPInput { +} + +// Matcher input that allows matching connections by by the source IP address. +message SourceIPInput { +} + +// Matcher input that allows matching connections by by the directly connected source IP address (this +// will only be different from the source IP address when using a listener +// filter that overrides the source address, such as the :ref:`Proxy Protocol +// listener filter `). +message DirectSourceIPInput { +} + +// Matcher input that allows matching connections by by the source port. +message SourcePortInput { +} + +// Matcher input that allows matching connections by by the connection source IP type. +// Specifies the connection source IP match type. The values include: +// +// * ``any`` - any connection source, +// * ``local`` - matches a connection originating from the same host, +// * ``external`` - matches a connection originating from a different host +message SourceTypeInput { +} + +// Matcher input that allows matching connections by by the server names of a new connection, when detected by one of the listener filters. +message SNIInput { +} + +// Matcher input that allows matching connections by by the transport protocol. +// This value will be compared against the transport protocol of a new connection, when +// it's detected by one of the listener filters. +// +// Suggested values include: +// +// * ``raw_buffer`` - default, used when no transport protocol is detected, +// * ``tls`` - set by :ref:`envoy.filters.listener.tls_inspector ` +// when TLS protocol is detected. +message TransportProtocolInput { +} + +// Matcher input that allows matching connections by by the application protocol (e.g. ALPN for TLS protocol). +// This values will be compared against the application +// protocols of a new connection, when detected by one of the listener filters. +// +// Suggested values include: +// +// * ``http/1.1`` - set by :ref:`envoy.filters.listener.tls_inspector +// `, +// * ``h2`` - set by :ref:`envoy.filters.listener.tls_inspector ` +// +// .. attention:: +// +// Currently, only :ref:`TLS Inspector ` provides +// application protocol detection based on the requested +// `ALPN `_ values. +// +// However, the use of ALPN is pretty much limited to the HTTP/2 traffic on the Internet, +// and matching on values other than ``h2`` is going to lead to a lot of false negatives, +// unless all connecting clients are known to use ALPN. +message ApplicationProtocolInput { +} + +// Matches a specific port against a set of possibly overlapping port ranges. +message PortMatcher { + // Specifies an optional list of port ranges and a match action. + message PortRangeMatcher { + // Optional set of port ranges. An empty set matches any port. + repeated type.v3.Int32Range ranges = 1; + + // Match action to apply when the port is within one of the port ranges. + xds.type.matcher.v3.Matcher.OnMatch on_match = 2; + + // Indicates whether this match option should be considered if there is a + // matcher for the specific port value. For example, consider a matcher + // for the port range [1, 1000] applied to a specific port 80. If there + // is another matcher for the specific port 80 that fully matches, then + // the specific port matcher is selected. However, if the specific port + // matcher does not fully match, then the behavior depends on whether the + // range matcher [1, 1000] is exclusive. Exclusive port matchers do not + // apply when there is a more specific port match. Non-exclusive port + // matchers may apply when the nested match conditions are satisfied for + // the range matcher but not for the specific port value nested matcher. + // + // The order of range matchers is important since it dictates the order + // of matching in case of overlapping port ranges. + bool exclusive = 3; + } + + // Match port by value. Takes precedence over matching by the port ranges. + map port_map = 1; + + // Match port by port ranges. + repeated PortRangeMatcher range_matchers = 2; +} + +// Matches a specific IP address against a set of possibly overlapping subnets. +message IPMatcher { + // Specifies an optional list of IP address ranges and a match action. + message IPRangeMatcher { + // Optional set of CIDR ranges. An empty set matches any IP address. + repeated core.v3.CidrRange ranges = 1; + + // Match action to apply when the IP address is within one of the CIDR ranges. + xds.type.matcher.v3.Matcher.OnMatch on_match = 2; + + // Indicates whether this match option should be considered if there is a + // more specific matcher. Exclusive matchers are not selected whenever a + // more specific matcher exists (e.g. matcher with a longer prefix) even + // when the more specific matcher fails its nested match condition. + // Non-exclusive matchers are considered if the more specific matcher + // exists but its nested match condition does not entirely match. + // Non-exclusive matchers are selected in the order of their specificity + // first (longest prefix first), then the order of declaration next. + bool exclusive = 3; + } + + // Match IP address by CIDR ranges. + repeated IPRangeMatcher range_matchers = 1; +} + +// Matches a specific server name against of a set of possibly overlapping wildcard domains. +message ServerNameMatcher { + // Specifies an optional list of wildcard domains and a match action. + // The server name will be matched against all wildcard domains, i.e. ``www.example.com`` + // will be first matched against ``www.example.com``, then ``*.example.com``, then ``*.com``. + // + // Note that partial wildcards are not supported, and values like ``*w.example.com`` are invalid. + message DomainMatcher { + // Optional set of wildcard domains. An empty set matches any server name. + repeated string server_names = 1; + + // Match action to apply when the server name matches. + xds.type.matcher.v3.Matcher.OnMatch on_match = 2; + + // Indicates whether this match option should be considered if there is a + // more specific matcher. Exclusive matches are not selected whenever a + // more specific matcher exists even when the more specific matcher fails + // to match its nested match condition. For example, an exclusive matcher + // for ```*.com``` does not match ``www.example.com``` if there is a + // matcher for ```*.example.com```. Matchers are selected in the order of + // their specificity first (longest suffix first), then + // the order of declaration next. + bool exclusive = 3; + } + + // Match server name by wildcard domains. + repeated DomainMatcher domain_matchers = 1; +} From 9fd0f34ffdbdedd59bbc93a9335b8114378b952b Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Wed, 17 Nov 2021 13:44:39 -0800 Subject: [PATCH 08/39] review Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener_components.proto | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/api/envoy/config/listener/v3/listener_components.proto b/api/envoy/config/listener/v3/listener_components.proto index ad8024036998f..cc03f3a9737dd 100644 --- a/api/envoy/config/listener/v3/listener_components.proto +++ b/api/envoy/config/listener/v3/listener_components.proto @@ -415,12 +415,13 @@ message TransportProtocolInput { // Suggested values include: // // * ``http/1.1`` - set by :ref:`envoy.filters.listener.tls_inspector -// `, -// * ``h2`` - set by :ref:`envoy.filters.listener.tls_inspector ` +// ` and :ref:`envoy.filters.listener.http_inspector +// `, +// * ``h2`` - set by :ref:`envoy.filters.listener.tls_inspector ` and :ref:`envoy.filters.listener.http_inspector ` // // .. attention:: // -// Currently, only :ref:`TLS Inspector ` provides +// Currently, :ref:`TLS Inspector ` provides // application protocol detection based on the requested // `ALPN `_ values. // From 595eb183ba3b2590f9ce8f20188b2f8343a79f3c Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Mon, 22 Nov 2021 08:00:38 -0800 Subject: [PATCH 09/39] add move note Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener_components.proto | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/envoy/config/listener/v3/listener_components.proto b/api/envoy/config/listener/v3/listener_components.proto index cc03f3a9737dd..48e29ec68507c 100644 --- a/api/envoy/config/listener/v3/listener_components.proto +++ b/api/envoy/config/listener/v3/listener_components.proto @@ -432,6 +432,7 @@ message ApplicationProtocolInput { } // Matches a specific port against a set of possibly overlapping port ranges. +// TODO(kuat) Move to cncf/xds. message PortMatcher { // Specifies an optional list of port ranges and a match action. message PortRangeMatcher { @@ -465,6 +466,7 @@ message PortMatcher { } // Matches a specific IP address against a set of possibly overlapping subnets. +// TODO(kuat) Move to cncf/xds. message IPMatcher { // Specifies an optional list of IP address ranges and a match action. message IPRangeMatcher { @@ -490,6 +492,7 @@ message IPMatcher { } // Matches a specific server name against of a set of possibly overlapping wildcard domains. +// TODO(kuat) Move to cncf/xds. message ServerNameMatcher { // Specifies an optional list of wildcard domains and a match action. // The server name will be matched against all wildcard domains, i.e. ``www.example.com`` From 262d0842a936e84a790edf754ffc19c638391f77 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Mon, 29 Nov 2021 14:12:19 -0800 Subject: [PATCH 10/39] merge Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index 03f1a122123b6..8f0f5fd099de3 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -37,7 +37,7 @@ message ListenerCollection { repeated xds.core.v3.CollectionEntry entries = 1; } -// [#next-free-field: 33] +// [#next-free-field: 34] message Listener { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.Listener"; From 76e5040af6e743e6f20186e47f101742af5ae361 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Wed, 1 Dec 2021 13:46:11 -0800 Subject: [PATCH 11/39] more review Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener.proto | 44 ++++++++++++++++--- .../listener/v3/listener_components.proto | 24 +++------- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index 8f0f5fd099de3..4d41bc6b998c2 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -5,7 +5,6 @@ package envoy.config.listener.v3; import "envoy/config/accesslog/v3/accesslog.proto"; import "envoy/config/core/v3/address.proto"; import "envoy/config/core/v3/base.proto"; -import "envoy/config/core/v3/extension.proto"; import "envoy/config/core/v3/socket_option.proto"; import "envoy/config/listener/v3/api_listener.proto"; import "envoy/config/listener/v3/listener_components.proto"; @@ -37,7 +36,7 @@ message ListenerCollection { repeated xds.core.v3.CollectionEntry entries = 1; } -// [#next-free-field: 34] +// [#next-free-field: 33] message Listener { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.Listener"; @@ -136,13 +135,44 @@ message Listener { // // If specified, all :ref:`filter_chains ` must // have a non-empty :ref:`name ` and empty :ref:`filter_chain_match `. - // [#not-implemented-hide:] - repeated xds.type.matcher.v3.Matcher filter_chain_matcher = 32; + // + // Example 1: Match port 80 for chain "http", port 443 and SNI "*.server.com" for chain "server" or SNI "*.com" for chain "https". - // Defines the discovery service configuration for filter chains indexed by the filter chain name. - // The set of filter chain names must be disjoint from the filter chain names in the field :ref:`filter_chains `. + // .. code-block:: yaml + // + // filter_chain_matcher: + // matcher_tree: + // input: + // typed_config: + // "@type": type.googleapis.com/envoy.config.listener.v3.DestinationPortInput + // exact_match_map: + // map: + // "80": + // action: + // name: http + // "443": + // matcher: + // matcher_tree: + // input: + // typed_config: + // "@type": type.googleapis.com/envoy.config.listener.v3.SNIInput + // custom_match: + // typed_config: + // "@type": type.googleapis.com/envoy.config.listener.v3.ServerNameMatcher + // domain_matchers: + // - server_names: ["*.server.com"] + // on_match: + // action: + // name: server + // - server_names: ["*.com"] + // on_match: + // action: + // name: https + // + // The example above requires that filter chains named "http", "server", and "https" are present in :ref:`filter_chains ` field. + // // [#not-implemented-hide:] - map filter_chain_discovery = 33; + repeated xds.type.matcher.v3.Matcher filter_chain_matcher = 32; // If a connection is redirected using *iptables*, the port on which the proxy // receives it might be different from the original destination address. When this flag is set to diff --git a/api/envoy/config/listener/v3/listener_components.proto b/api/envoy/config/listener/v3/listener_components.proto index 48e29ec68507c..53d3d829015f5 100644 --- a/api/envoy/config/listener/v3/listener_components.proto +++ b/api/envoy/config/listener/v3/listener_components.proto @@ -223,6 +223,9 @@ message FilterChain { reserved "tls_context"; // The criteria to use when matching a connection to this filter chain. + // Note: :ref:`filter_chain_matcher + // ` + // supersedes this field. FilterChainMatch filter_chain_match = 1; // A list of individual network filters that make up the filter chain for @@ -260,6 +263,9 @@ message FilterChain { // establishment, the connection is summarily closed. google.protobuf.Duration transport_socket_connect_timeout = 9; + // Note: :ref:`filter_chain_matcher + // ` + // requires that filter chains are uniquely named. // [#not-implemented-hide:] The unique name (or empty) by which this filter chain is known. If no // name is provided, Envoy will allocate an internal UUID for the filter chain. If the filter // chain is to be dynamically updated or removed via FCDS a unique name must be provided. @@ -441,26 +447,8 @@ message PortMatcher { // Match action to apply when the port is within one of the port ranges. xds.type.matcher.v3.Matcher.OnMatch on_match = 2; - - // Indicates whether this match option should be considered if there is a - // matcher for the specific port value. For example, consider a matcher - // for the port range [1, 1000] applied to a specific port 80. If there - // is another matcher for the specific port 80 that fully matches, then - // the specific port matcher is selected. However, if the specific port - // matcher does not fully match, then the behavior depends on whether the - // range matcher [1, 1000] is exclusive. Exclusive port matchers do not - // apply when there is a more specific port match. Non-exclusive port - // matchers may apply when the nested match conditions are satisfied for - // the range matcher but not for the specific port value nested matcher. - // - // The order of range matchers is important since it dictates the order - // of matching in case of overlapping port ranges. - bool exclusive = 3; } - // Match port by value. Takes precedence over matching by the port ranges. - map port_map = 1; - // Match port by port ranges. repeated PortRangeMatcher range_matchers = 2; } From 3b92ec5dad0ee87cb9b2607b705867256c8f085f Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Wed, 1 Dec 2021 13:47:14 -0800 Subject: [PATCH 12/39] typo Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener_components.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/envoy/config/listener/v3/listener_components.proto b/api/envoy/config/listener/v3/listener_components.proto index 53d3d829015f5..b9ac10c382dc5 100644 --- a/api/envoy/config/listener/v3/listener_components.proto +++ b/api/envoy/config/listener/v3/listener_components.proto @@ -415,7 +415,7 @@ message TransportProtocolInput { } // Matcher input that allows matching connections by by the application protocol (e.g. ALPN for TLS protocol). -// This values will be compared against the application +// This value will be compared against the application // protocols of a new connection, when detected by one of the listener filters. // // Suggested values include: From ddeeaf9e6006354d957cc27674ea2e9b38f25d0d Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Wed, 15 Dec 2021 10:46:24 -0800 Subject: [PATCH 13/39] update Signed-off-by: Kuat Yessenov --- .../listener/v3/listener_components.proto | 35 ++----------------- tools/spelling/spelling_dictionary.txt | 1 + 2 files changed, 4 insertions(+), 32 deletions(-) diff --git a/api/envoy/config/listener/v3/listener_components.proto b/api/envoy/config/listener/v3/listener_components.proto index dc9b961615594..be099ff2f9f43 100644 --- a/api/envoy/config/listener/v3/listener_components.proto +++ b/api/envoy/config/listener/v3/listener_components.proto @@ -224,9 +224,6 @@ message FilterChain { reserved "tls_context"; // The criteria to use when matching a connection to this filter chain. - // Note: :ref:`filter_chain_matcher - // ` - // supersedes this field. FilterChainMatch filter_chain_match = 1; // A list of individual network filters that make up the filter chain for @@ -264,12 +261,12 @@ message FilterChain { // establishment, the connection is summarily closed. google.protobuf.Duration transport_socket_connect_timeout = 9; - // Note: :ref:`filter_chain_matcher - // ` - // requires that filter chains are uniquely named. // [#not-implemented-hide:] The unique name (or empty) by which this filter chain is known. If no // name is provided, Envoy will allocate an internal UUID for the filter chain. If the filter // chain is to be dynamically updated or removed via FCDS a unique name must be provided. + // Note: :ref:`filter_chain_matcher + // ` + // requires that filter chains are uniquely named. string name = 7; // [#not-implemented-hide:] The configuration to specify whether the filter chain will be built on-demand. @@ -454,32 +451,6 @@ message PortMatcher { repeated PortRangeMatcher range_matchers = 2; } -// Matches a specific IP address against a set of possibly overlapping subnets. -// TODO(kuat) Move to cncf/xds. -message IPMatcher { - // Specifies an optional list of IP address ranges and a match action. - message IPRangeMatcher { - // Optional set of CIDR ranges. An empty set matches any IP address. - repeated core.v3.CidrRange ranges = 1; - - // Match action to apply when the IP address is within one of the CIDR ranges. - xds.type.matcher.v3.Matcher.OnMatch on_match = 2; - - // Indicates whether this match option should be considered if there is a - // more specific matcher. Exclusive matchers are not selected whenever a - // more specific matcher exists (e.g. matcher with a longer prefix) even - // when the more specific matcher fails its nested match condition. - // Non-exclusive matchers are considered if the more specific matcher - // exists but its nested match condition does not entirely match. - // Non-exclusive matchers are selected in the order of their specificity - // first (longest prefix first), then the order of declaration next. - bool exclusive = 3; - } - - // Match IP address by CIDR ranges. - repeated IPRangeMatcher range_matchers = 1; -} - // Matches a specific server name against of a set of possibly overlapping wildcard domains. // TODO(kuat) Move to cncf/xds. message ServerNameMatcher { diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index aa402263a170a..5d3ff83923747 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -521,6 +521,7 @@ cloneable cloneability cmd cmsghdr +cncf codebase codec codecs From e981df6f7331643def807ae1536c5cfe9ffa609e Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Tue, 1 Feb 2022 15:48:05 -0800 Subject: [PATCH 14/39] review Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener.proto | 52 ++++---- .../listener/v3/listener_components.proto | 119 ------------------ tools/spelling/spelling_dictionary.txt | 1 - 3 files changed, 29 insertions(+), 143 deletions(-) diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index de6bdc177c0c2..f2049b32faea2 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -121,31 +121,27 @@ message Listener { // :ref:`FAQ entry `. repeated FilterChain filter_chains = 3; - // A filter chain matcher resolving the filter chain name based on the connection properties. - // The following inputs are supported by the matcher: + // Unified matcher resolving the filter chain name from the network properties. This matcher is used as a replacement + // for the per-filter chain match condition + // `filter_chain_match `. + // If specified, all :ref:`filter_chains ` must + // have non-empty and unique :ref:`name ` fields and omit + // `filter_chain_match ` field. // - // 1. :ref:`DestinationPort `. - // 2. :ref:`DestinationIP `. - // 3. :ref:`SNI `. - // 4. :ref:`TransportProtocol `. - // 5. :ref:`ApplicationProtocol `. - // 6. :ref:`DirectSourceIP `. - // 7. :ref:`SourceType `. - // 8. :ref:`SourceIP `. - // 9. :ref:`SourcePort `. + // Example 1: The following matcher selects three filter chains as follows: // - // If specified, all :ref:`filter_chains ` must - // have a non-empty :ref:`name ` and empty :ref:`filter_chain_match `. + // * if the destination port is 80, then the filter chain "http" is selected; + // * if the destination port is 443 and the source IP is in the range 192.0.0.0/2, then the filter chain "internal" is selected; + // * otherwise, if the destination port is 443, then the filter chain "https" is selected; + // * otherwise, the default filter chain is selected (or the connection is rejected without the default filter chain). // - // Example 1: Match port 80 for chain "http", port 443 and SNI "*.server.com" for chain "server" or SNI "*.com" for chain "https". - // .. code-block:: yaml // // filter_chain_matcher: // matcher_tree: // input: // typed_config: - // "@type": type.googleapis.com/envoy.config.listener.v3.DestinationPortInput + // "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput // exact_match_map: // map: // "80": @@ -156,21 +152,31 @@ message Listener { // matcher_tree: // input: // typed_config: - // "@type": type.googleapis.com/envoy.config.listener.v3.SNIInput + // "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.SourceIPInput // custom_match: // typed_config: - // "@type": type.googleapis.com/envoy.config.listener.v3.ServerNameMatcher - // domain_matchers: - // - server_names: ["*.server.com"] + // "@type": type.googleapis.com/xds.type.matcher.v3.IPMatcher + // range_matchers: + // - ranges: + // - address_prefix: 192.0.0.0 + // prefix_len: 2 // on_match: // action: - // name: server - // - server_names: ["*.com"] + // name: internal + // - ranges: + // - address_prefix: 0.0.0.0 // on_match: // action: // name: https // - // The example above requires that filter chains named "http", "server", and "https" are present in :ref:`filter_chains ` field. + // + // .. note:: + // + // Once matched, each connection is permanently bound to its filter chain. + // If the matcher changes but the filter chain remains the same, the + // connections bound to the filter chain are not drained. If, however, the + // filter chain is removed or structurally modified, then the drain for its + // connections is initiated. // // [#not-implemented-hide:] repeated xds.type.matcher.v3.Matcher filter_chain_matcher = 32; diff --git a/api/envoy/config/listener/v3/listener_components.proto b/api/envoy/config/listener/v3/listener_components.proto index be099ff2f9f43..535d181405462 100644 --- a/api/envoy/config/listener/v3/listener_components.proto +++ b/api/envoy/config/listener/v3/listener_components.proto @@ -11,8 +11,6 @@ import "google/protobuf/any.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; -import "xds/type/matcher/v3/matcher.proto"; - import "envoy/annotations/deprecation.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; @@ -363,120 +361,3 @@ message ListenerFilter { // for further examples. ListenerFilterChainMatchPredicate filter_disabled = 4; } - -// Matcher input that allows matching connections by by the destination port. -message DestinationPortInput { -} - -// Matcher input that allows matching connections by by the destination IP address. -message DestinationIPInput { -} - -// Matcher input that allows matching connections by by the source IP address. -message SourceIPInput { -} - -// Matcher input that allows matching connections by by the directly connected source IP address (this -// will only be different from the source IP address when using a listener -// filter that overrides the source address, such as the :ref:`Proxy Protocol -// listener filter `). -message DirectSourceIPInput { -} - -// Matcher input that allows matching connections by by the source port. -message SourcePortInput { -} - -// Matcher input that allows matching connections by by the connection source IP type. -// Specifies the connection source IP match type. The values include: -// -// * ``any`` - any connection source, -// * ``local`` - matches a connection originating from the same host, -// * ``external`` - matches a connection originating from a different host -message SourceTypeInput { -} - -// Matcher input that allows matching connections by by the server names of a new connection, when detected by one of the listener filters. -message SNIInput { -} - -// Matcher input that allows matching connections by by the transport protocol. -// This value will be compared against the transport protocol of a new connection, when -// it's detected by one of the listener filters. -// -// Suggested values include: -// -// * ``raw_buffer`` - default, used when no transport protocol is detected, -// * ``tls`` - set by :ref:`envoy.filters.listener.tls_inspector ` -// when TLS protocol is detected. -message TransportProtocolInput { -} - -// Matcher input that allows matching connections by by the application protocol (e.g. ALPN for TLS protocol). -// This value will be compared against the application -// protocols of a new connection, when detected by one of the listener filters. -// -// Suggested values include: -// -// * ``http/1.1`` - set by :ref:`envoy.filters.listener.tls_inspector -// ` and :ref:`envoy.filters.listener.http_inspector -// `, -// * ``h2`` - set by :ref:`envoy.filters.listener.tls_inspector ` and :ref:`envoy.filters.listener.http_inspector ` -// -// .. attention:: -// -// Currently, :ref:`TLS Inspector ` provides -// application protocol detection based on the requested -// `ALPN `_ values. -// -// However, the use of ALPN is pretty much limited to the HTTP/2 traffic on the Internet, -// and matching on values other than ``h2`` is going to lead to a lot of false negatives, -// unless all connecting clients are known to use ALPN. -message ApplicationProtocolInput { -} - -// Matches a specific port against a set of possibly overlapping port ranges. -// TODO(kuat) Move to cncf/xds. -message PortMatcher { - // Specifies an optional list of port ranges and a match action. - message PortRangeMatcher { - // Optional set of port ranges. An empty set matches any port. - repeated type.v3.Int32Range ranges = 1; - - // Match action to apply when the port is within one of the port ranges. - xds.type.matcher.v3.Matcher.OnMatch on_match = 2; - } - - // Match port by port ranges. - repeated PortRangeMatcher range_matchers = 2; -} - -// Matches a specific server name against of a set of possibly overlapping wildcard domains. -// TODO(kuat) Move to cncf/xds. -message ServerNameMatcher { - // Specifies an optional list of wildcard domains and a match action. - // The server name will be matched against all wildcard domains, i.e. ``www.example.com`` - // will be first matched against ``www.example.com``, then ``*.example.com``, then ``*.com``. - // - // Note that partial wildcards are not supported, and values like ``*w.example.com`` are invalid. - message DomainMatcher { - // Optional set of wildcard domains. An empty set matches any server name. - repeated string server_names = 1; - - // Match action to apply when the server name matches. - xds.type.matcher.v3.Matcher.OnMatch on_match = 2; - - // Indicates whether this match option should be considered if there is a - // more specific matcher. Exclusive matches are not selected whenever a - // more specific matcher exists even when the more specific matcher fails - // to match its nested match condition. For example, an exclusive matcher - // for ```*.com``` does not match ``www.example.com``` if there is a - // matcher for ```*.example.com```. Matchers are selected in the order of - // their specificity first (longest suffix first), then - // the order of declaration next. - bool exclusive = 3; - } - - // Match server name by wildcard domains. - repeated DomainMatcher domain_matchers = 1; -} diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index 38787c687e37e..80223b742b948 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -522,7 +522,6 @@ cloneable cloneability cmd cmsghdr -cncf codebase codec codecs From 0185225dd2f2aa3c04ace3fe9a88873594ba80c6 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Thu, 17 Feb 2022 16:05:48 -0800 Subject: [PATCH 15/39] try validation Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener.proto | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index f2049b32faea2..790fa625bb768 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -135,7 +135,8 @@ message Listener { // * otherwise, if the destination port is 443, then the filter chain "https" is selected; // * otherwise, the default filter chain is selected (or the connection is rejected without the default filter chain). // - // .. code-block:: yaml + // .. validated-code-block:: yaml + // :type-name: envoy.config.listener.v3.Listener // // filter_chain_matcher: // matcher_tree: @@ -179,7 +180,7 @@ message Listener { // connections is initiated. // // [#not-implemented-hide:] - repeated xds.type.matcher.v3.Matcher filter_chain_matcher = 32; + xds.type.matcher.v3.Matcher filter_chain_matcher = 32; // If a connection is redirected using *iptables*, the port on which the proxy // receives it might be different from the original destination address. When this flag is set to From d1c8f753da17fcff7a6e8567680d65d547ec6d2e Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Wed, 23 Feb 2022 14:07:37 -0500 Subject: [PATCH 16/39] verify example Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener.proto | 75 +++++++++++---------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index 790fa625bb768..e1da21b518d44 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -121,6 +121,7 @@ message Listener { // :ref:`FAQ entry `. repeated FilterChain filter_chains = 3; + // [#not-implemented-hide:] // Unified matcher resolving the filter chain name from the network properties. This matcher is used as a replacement // for the per-filter chain match condition // `filter_chain_match `. @@ -138,38 +139,46 @@ message Listener { // .. validated-code-block:: yaml // :type-name: envoy.config.listener.v3.Listener // - // filter_chain_matcher: - // matcher_tree: - // input: - // typed_config: - // "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput - // exact_match_map: - // map: - // "80": - // action: - // name: http - // "443": - // matcher: - // matcher_tree: - // input: - // typed_config: - // "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.SourceIPInput - // custom_match: - // typed_config: - // "@type": type.googleapis.com/xds.type.matcher.v3.IPMatcher - // range_matchers: - // - ranges: - // - address_prefix: 192.0.0.0 - // prefix_len: 2 - // on_match: - // action: - // name: internal - // - ranges: - // - address_prefix: 0.0.0.0 - // on_match: - // action: - // name: https - // + // filter_chain_matcher: + // matcher_tree: + // input: + // typed_config: + // "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput + // exact_match_map: + // map: + // "80": + // action: + // name: http + // typed_config: + // "@type": type.googleapis.com/google.protobuf.StringValue + // value: http + // "443": + // matcher: + // matcher_tree: + // input: + // typed_config: + // "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.SourceIPInput + // custom_match: + // typed_config: + // "@type": type.googleapis.com/xds.type.matcher.v3.IPMatcher + // range_matchers: + // - ranges: + // - address_prefix: 192.0.0.0 + // prefix_len: 2 + // on_match: + // action: + // name: internal + // typed_config: + // "@type": type.googleapis.com/google.protobuf.StringValue + // value: internal + // - ranges: + // - address_prefix: 0.0.0.0 + // on_match: + // action: + // name: https + // typed_config: + // "@type": type.googleapis.com/google.protobuf.StringValue + // value: https // // .. note:: // @@ -178,8 +187,6 @@ message Listener { // connections bound to the filter chain are not drained. If, however, the // filter chain is removed or structurally modified, then the drain for its // connections is initiated. - // - // [#not-implemented-hide:] xds.type.matcher.v3.Matcher filter_chain_matcher = 32; // If a connection is redirected using *iptables*, the port on which the proxy From a4dcf212457d3d2de4ec05d47c755e9ec973cca2 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Wed, 23 Feb 2022 15:24:46 -0800 Subject: [PATCH 17/39] initial implementation Signed-off-by: Kuat Yessenov --- source/server/BUILD | 5 + source/server/filter_chain_manager_impl.cc | 163 +++++++++++++----- source/server/filter_chain_manager_impl.h | 13 +- source/server/listener_impl.cc | 1 + test/server/filter_chain_benchmark_test.cc | 4 +- test/server/filter_chain_manager_impl_test.cc | 51 ++++-- 6 files changed, 181 insertions(+), 56 deletions(-) diff --git a/source/server/BUILD b/source/server/BUILD index 85cb1facb30cf..3e0fec926263c 100644 --- a/source/server/BUILD +++ b/source/server/BUILD @@ -537,14 +537,19 @@ envoy_cc_library( deps = [ ":filter_chain_factory_context_callback", "//envoy/config:typed_metadata_interface", + "//envoy/matcher:matcher_interface", + "//envoy/network:filter_interface", "//envoy/server:instance_interface", "//envoy/server:listener_manager_interface", "//envoy/server:transport_socket_config_interface", "//source/common/common:empty_string", "//source/common/config:utility_lib", "//source/common/init:manager_lib", + "//source/common/matcher:matcher_lib", "//source/common/network:cidr_range_lib", "//source/common/network:lc_trie_lib", + "//source/common/network/matching:data_impl_lib", + "//source/common/network/matching:inputs_lib", "//source/server:configuration_lib", "@envoy_api//envoy/config/listener/v3:pkg_cc_proto", ], diff --git a/source/server/filter_chain_manager_impl.cc b/source/server/filter_chain_manager_impl.cc index 224315b7e245b..d32223b22ab78 100644 --- a/source/server/filter_chain_manager_impl.cc +++ b/source/server/filter_chain_manager_impl.cc @@ -6,6 +6,9 @@ #include "source/common/common/empty_string.h" #include "source/common/common/fmt.h" #include "source/common/config/utility.h" +#include "source/common/matcher/matcher.h" +#include "source/common/network/matching/data_impl.h" +#include "source/common/network/matching/inputs.h" #include "source/common/network/socket_interface.h" #include "source/common/protobuf/utility.h" #include "source/server/configuration_impl.h" @@ -27,6 +30,37 @@ Network::Address::InstanceConstSharedPtr fakeAddress() { Network::Utility::parseInternetAddress("255.255.255.255")); } +struct FilterChainNameAction : public Matcher::ActionBase { + explicit FilterChainNameAction(const std::string& name) : name_(name) {} + const std::string name_; +}; + +class FilterChainNameActionFactory : public Matcher::ActionFactory { +public: + std::string name() const override { return "filter-chain-name"; } + Matcher::ActionFactoryCb createActionFactoryCb(const Protobuf::Message& config, + Configuration::FactoryContext&, + ProtobufMessage::ValidationVisitor&) override { + const auto& name = dynamic_cast(config); + return [name]() { return std::make_unique(name.value()); }; + } + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } +}; + +REGISTER_FACTORY(FilterChainNameActionFactory, + Matcher::ActionFactory); + +class FilterChainNameActionValidationVisitor + : public Matcher::MatchTreeValidationVisitor { +public: + absl::Status performDataInputValidation(const Matcher::DataInputFactory&, + absl::string_view) override { + return absl::OkStatus(); + } +}; + } // namespace PerFilterChainFactoryContextImpl::PerFilterChainFactoryContextImpl( @@ -160,6 +194,7 @@ bool FilterChainManagerImpl::isWildcardServerName(const std::string& name) { } void FilterChainManagerImpl::addFilterChains( + const xds::type::matcher::v3::Matcher* filter_chain_matcher, absl::Span filter_chain_span, const envoy::config::listener::v3::FilterChain* default_filter_chain, FilterChainFactoryBuilder& filter_chain_factory_builder, @@ -169,6 +204,15 @@ void FilterChainManagerImpl::addFilterChains( MessageUtil> filter_chains; uint32_t new_filter_chain_size = 0; + + // Construct matcher if it is present in the listener configuration. + if (filter_chain_matcher) { + FilterChainNameActionValidationVisitor validation_visitor; + Matcher::MatchTreeFactory factory( + parent_context_, parent_context_.getServerFactoryContext(), validation_visitor); + matcher_ = factory.create(*filter_chain_matcher)(); + } + for (const auto& filter_chain : filter_chain_span) { const auto& filter_chain_match = filter_chain->filter_chain_match(); if (!filter_chain_match.address_suffix().empty() || filter_chain_match.has_suffix_len()) { @@ -176,43 +220,15 @@ void FilterChainManagerImpl::addFilterChains( "unimplemented fields", address_->asString(), filter_chain->name())); } - const auto& matching_iter = filter_chains.find(filter_chain_match); - if (matching_iter != filter_chains.end()) { - throw EnvoyException(fmt::format("error adding listener '{}': filter chain '{}' has " - "the same matching rules defined as '{}'", - address_->asString(), filter_chain->name(), - matching_iter->second)); - } - filter_chains.insert({filter_chain_match, filter_chain->name()}); - - auto createAddressVector = [](const auto& prefix_ranges) -> std::vector { - std::vector ips; - ips.reserve(prefix_ranges.size()); - for (const auto& ip : prefix_ranges) { - const auto& cidr_range = Network::Address::CidrRange::create(ip); - ips.push_back(cidr_range.asString()); - } - return ips; - }; - - // Validate IP addresses. - std::vector destination_ips = - createAddressVector(filter_chain_match.prefix_ranges()); - std::vector source_ips = - createAddressVector(filter_chain_match.source_prefix_ranges()); - std::vector direct_source_ips = - createAddressVector(filter_chain_match.direct_source_prefix_ranges()); - - std::vector server_names; - // Reject partial wildcards, we don't match on them. - for (const auto& server_name : filter_chain_match.server_names()) { - if (server_name.find('*') != std::string::npos && !isWildcardServerName(server_name)) { - throw EnvoyException( - fmt::format("error adding listener '{}': partial wildcards are not supported in " - "\"server_names\"", - address_->asString())); + if (!matcher_) { + const auto& matching_iter = filter_chains.find(filter_chain_match); + if (matching_iter != filter_chains.end()) { + throw EnvoyException(fmt::format("error adding listener '{}': filter chain '{}' has " + "the same matching rules defined as '{}'", + address_->asString(), filter_chain->name(), + matching_iter->second)); } - server_names.push_back(absl::AsciiStrToLower(server_name)); + filter_chains.insert({filter_chain_match, filter_chain->name()}); } // Reuse created filter chain if possible. @@ -225,13 +241,53 @@ void FilterChainManagerImpl::addFilterChains( ++new_filter_chain_size; } - addFilterChainForDestinationPorts( - destination_ports_map_, - PROTOBUF_GET_WRAPPED_OR_DEFAULT(filter_chain_match, destination_port, 0), destination_ips, - server_names, filter_chain_match.transport_protocol(), - filter_chain_match.application_protocols(), direct_source_ips, - filter_chain_match.source_type(), source_ips, filter_chain_match.source_ports(), - filter_chain_impl); + // If using the matcher, require usage of "name" field and skip building the index. + if (matcher_) { + if (filter_chain->name().empty()) { + throw EnvoyException(fmt::format( + "error adding listener '{}': \"name\" field is required when using a listener matcher", + address_->asString())); + } + filter_chains_by_name_.try_emplace(filter_chain->name(), filter_chain_impl); + } else { + auto createAddressVector = [](const auto& prefix_ranges) -> std::vector { + std::vector ips; + ips.reserve(prefix_ranges.size()); + for (const auto& ip : prefix_ranges) { + const auto& cidr_range = Network::Address::CidrRange::create(ip); + ips.push_back(cidr_range.asString()); + } + return ips; + }; + + // Validate IP addresses. + std::vector destination_ips = + createAddressVector(filter_chain_match.prefix_ranges()); + std::vector source_ips = + createAddressVector(filter_chain_match.source_prefix_ranges()); + std::vector direct_source_ips = + createAddressVector(filter_chain_match.direct_source_prefix_ranges()); + + std::vector server_names; + // Reject partial wildcards, we don't match on them. + for (const auto& server_name : filter_chain_match.server_names()) { + if (server_name.find('*') != std::string::npos && !isWildcardServerName(server_name)) { + throw EnvoyException( + fmt::format("error adding listener '{}': partial wildcards are not supported in " + "\"server_names\"", + address_->asString())); + } + server_names.push_back(absl::AsciiStrToLower(server_name)); + } + + addFilterChainForDestinationPorts( + destination_ports_map_, + PROTOBUF_GET_WRAPPED_OR_DEFAULT(filter_chain_match, destination_port, 0), destination_ips, + server_names, filter_chain_match.transport_protocol(), + filter_chain_match.application_protocols(), direct_source_ips, + filter_chain_match.source_type(), source_ips, filter_chain_match.source_ports(), + filter_chain_impl); + } fc_contexts_[*filter_chain] = filter_chain_impl; } @@ -468,6 +524,10 @@ std::pair> makeCidrListEntry(const s const Network::FilterChain* FilterChainManagerImpl::findFilterChain(const Network::ConnectionSocket& socket) const { + if (matcher_) { + return findFilterChainUsingMatcher(socket); + } + const auto& address = socket.connectionInfoProvider().localAddress(); const Network::FilterChain* best_match_filter_chain = nullptr; @@ -496,6 +556,23 @@ FilterChainManagerImpl::findFilterChain(const Network::ConnectionSocket& socket) : default_filter_chain_.get(); } +const Network::FilterChain* +FilterChainManagerImpl::findFilterChainUsingMatcher(const Network::ConnectionSocket& socket) const { + Network::Matching::MatchingDataImpl data(socket); + const auto match_result = Matcher::evaluateMatch(*matcher_, data); + ASSERT(match_result.match_state_ == Matcher::MatchState::MatchComplete, + "Matching must complete for network streams."); + if (match_result.result_) { + const auto result = match_result.result_(); + const auto chain_match = + filter_chains_by_name_.find(result->getTyped().name_); + if (chain_match != filter_chains_by_name_.end()) { + return chain_match->second.get(); + } + } + return default_filter_chain_.get(); +} + const Network::FilterChain* FilterChainManagerImpl::findFilterChainForDestinationIP( const DestinationIPsTrie& destination_ips_trie, const Network::ConnectionSocket& socket) const { auto address = socket.connectionInfoProvider().localAddress(); diff --git a/source/server/filter_chain_manager_impl.h b/source/server/filter_chain_manager_impl.h index 6fc0509f663b3..0756aaaefc5d6 100644 --- a/source/server/filter_chain_manager_impl.h +++ b/source/server/filter_chain_manager_impl.h @@ -6,7 +6,9 @@ #include "envoy/config/listener/v3/listener_components.pb.h" #include "envoy/config/typed_metadata.h" +#include "envoy/matcher/matcher.h" #include "envoy/network/drain_decision.h" +#include "envoy/network/filter.h" #include "envoy/server/filter_config.h" #include "envoy/server/instance.h" #include "envoy/server/options.h" @@ -217,6 +219,7 @@ class FilterChainManagerImpl : public Network::FilterChainManager, // Add all filter chains into this manager. During the lifetime of FilterChainManagerImpl this // should be called at most once. void addFilterChains( + const xds::type::matcher::v3::Matcher* filter_chain_matcher, absl::Span filter_chain_span, const envoy::config::listener::v3::FilterChain* default_filter_chain, FilterChainFactoryBuilder& filter_chain_factory_builder, @@ -237,6 +240,8 @@ class FilterChainManagerImpl : public Network::FilterChainManager, private: void convertIPsToTries(); + const Network::FilterChain* + findFilterChainUsingMatcher(const Network::ConnectionSocket& socket) const; // Build default filter chain from filter chain message. Skip the build but copy from original // filter chain manager if the default filter chain message duplicates the message in origin @@ -365,6 +370,9 @@ class FilterChainManagerImpl : public Network::FilterChainManager, // detect the filter chains in the intersection of existing listener and new listener. FcContextMap fc_contexts_; + // Mapping from filter chain name to filter chain. + absl::flat_hash_map filter_chains_by_name_; + absl::optional default_filter_chain_message_; // The optional fallback filter chain if destination_ports_map_ does not find a matched filter // chain. @@ -385,8 +393,11 @@ class FilterChainManagerImpl : public Network::FilterChainManager, // For FilterChainFactoryContextCreator // init manager owned by the corresponding listener. The reference is valid when building the - // filter chain. + // filter chain.,, Init::Manager& init_manager_; + + // Matcher selecting the filter chain name. + Matcher::MatchTreeSharedPtr matcher_; }; } // namespace Server } // namespace Envoy diff --git a/source/server/listener_impl.cc b/source/server/listener_impl.cc index cbe41f4c11c53..b31e551160aaf 100644 --- a/source/server/listener_impl.cc +++ b/source/server/listener_impl.cc @@ -629,6 +629,7 @@ void ListenerImpl::buildFilterChains() { transport_factory_context_->setInitManager(*dynamic_init_manager_); ListenerFilterChainFactoryBuilder builder(*this, *transport_factory_context_); filter_chain_manager_.addFilterChains( + config_.has_filter_chain_matcher() ? &config_.filter_chain_matcher() : nullptr, config_.filter_chains(), config_.has_default_filter_chain() ? &config_.default_filter_chain() : nullptr, builder, filter_chain_manager_); diff --git a/test/server/filter_chain_benchmark_test.cc b/test/server/filter_chain_benchmark_test.cc index e2d4a9b891e1d..4c64cc71997fa 100644 --- a/test/server/filter_chain_benchmark_test.cc +++ b/test/server/filter_chain_benchmark_test.cc @@ -230,7 +230,7 @@ BENCHMARK_DEFINE_F(FilterChainBenchmarkFixture, FilterChainManagerBuildTest) FilterChainManagerImpl filter_chain_manager{ std::make_shared("127.0.0.1", 1234), factory_context, init_manager_}; - filter_chain_manager.addFilterChains(filter_chains_, nullptr, dummy_builder_, + filter_chain_manager.addFilterChains(nullptr, filter_chains_, nullptr, dummy_builder_, filter_chain_manager); } } @@ -254,7 +254,7 @@ BENCHMARK_DEFINE_F(FilterChainBenchmarkFixture, FilterChainFindTest) std::make_shared("127.0.0.1", 1234), factory_context, init_manager_}; - filter_chain_manager.addFilterChains(filter_chains_, nullptr, dummy_builder_, + filter_chain_manager.addFilterChains(nullptr, filter_chains_, nullptr, dummy_builder_, filter_chain_manager); for (auto _ : state) { UNREFERENCED_PARAMETER(_); diff --git a/test/server/filter_chain_manager_impl_test.cc b/test/server/filter_chain_manager_impl_test.cc index e62d8c399da0f..dc7c5a7be27bd 100644 --- a/test/server/filter_chain_manager_impl_test.cc +++ b/test/server/filter_chain_manager_impl_test.cc @@ -55,7 +55,7 @@ class MockFilterChainFactoryBuilder : public FilterChainFactoryBuilder { (const)); }; -class FilterChainManagerImplTest : public testing::Test { +class FilterChainManagerImplTest : public testing::TestWithParam { public: void SetUp() override { local_address_ = std::make_shared("127.0.0.1", 1234); @@ -63,6 +63,7 @@ class FilterChainManagerImplTest : public testing::Test { TestUtility::loadFromYaml( TestEnvironment::substitute(filter_chain_yaml, Network::Address::IpVersion::v4), filter_chain_template_); + TestUtility::loadFromYaml(filter_chain_matcher, matcher_); } const Network::FilterChain* @@ -101,6 +102,7 @@ class FilterChainManagerImplTest : public testing::Test { const envoy::config::listener::v3::FilterChain& filter_chain, const envoy::config::listener::v3::FilterChain* fallback_filter_chain = nullptr) { filter_chain_manager_.addFilterChains( + GetParam() ? &matcher_ : nullptr, std::vector{&filter_chain}, fallback_filter_chain, filter_chain_factory_builder_, filter_chain_manager_); } @@ -112,6 +114,7 @@ class FilterChainManagerImplTest : public testing::Test { // Reusable template. const std::string filter_chain_yaml = R"EOF( + name: foo filter_chain_match: destination_port: 10000 transport_socket: @@ -126,8 +129,23 @@ class FilterChainManagerImplTest : public testing::Test { keys: - filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/ticket_key_a" )EOF"; + const std::string filter_chain_matcher = R"EOF( + matcher_tree: + input: + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput + exact_match_map: + map: + "10000": + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; Init::ManagerImpl init_manager_{"for_filter_chain_manager_test"}; envoy::config::listener::v3::FilterChain filter_chain_template_; + xds::type::matcher::v3::Matcher matcher_; std::shared_ptr build_out_filter_chain_{ std::make_shared()}; envoy::config::listener::v3::FilterChain fallback_filter_chain_; @@ -142,15 +160,16 @@ class FilterChainManagerImplTest : public testing::Test { init_manager_}; }; -TEST_F(FilterChainManagerImplTest, FilterChainMatchNothing) { +TEST_P(FilterChainManagerImplTest, FilterChainMatchNothing) { auto filter_chain = findFilterChainHelper(10000, "127.0.0.1", "", "tls", {}, "8.8.8.8", 111); EXPECT_EQ(filter_chain, nullptr); } -TEST_F(FilterChainManagerImplTest, FilterChainMatchCaseInSensitive) { +TEST_P(FilterChainManagerImplTest, FilterChainMatchCaseInSensitive) { envoy::config::listener::v3::FilterChain new_filter_chain = filter_chain_template_; new_filter_chain.mutable_filter_chain_match()->add_server_names("foo.EXAMPLE.com"); filter_chain_manager_.addFilterChains( + GetParam() ? &matcher_ : nullptr, std::vector{&new_filter_chain}, nullptr, filter_chain_factory_builder_, filter_chain_manager_); auto filter_chain = @@ -158,13 +177,19 @@ TEST_F(FilterChainManagerImplTest, FilterChainMatchCaseInSensitive) { EXPECT_NE(filter_chain, nullptr); } -TEST_F(FilterChainManagerImplTest, AddSingleFilterChain) { +TEST_P(FilterChainManagerImplTest, AddSingleFilterChain) { addSingleFilterChainHelper(filter_chain_template_); - auto* filter_chain = findFilterChainHelper(10000, "127.0.0.1", "", "tls", {}, "8.8.8.8", 111); - EXPECT_NE(filter_chain, nullptr); + { + auto* filter_chain = findFilterChainHelper(10000, "127.0.0.1", "", "tls", {}, "8.8.8.8", 111); + EXPECT_NE(filter_chain, nullptr); + } + { + auto* filter_chain = findFilterChainHelper(15000, "127.0.0.1", "", "tls", {}, "8.8.8.8", 111); + EXPECT_EQ(filter_chain, nullptr); + } } -TEST_F(FilterChainManagerImplTest, FilterChainUseFallbackIfNoFilterChainMatches) { +TEST_P(FilterChainManagerImplTest, FilterChainUseFallbackIfNoFilterChainMatches) { // The build helper will build matchable filter chain and then build the default filter chain. EXPECT_CALL(filter_chain_factory_builder_, buildFilterChain(_, _)) .WillOnce(Return(build_out_fallback_filter_chain_)); @@ -180,7 +205,7 @@ TEST_F(FilterChainManagerImplTest, FilterChainUseFallbackIfNoFilterChainMatches) EXPECT_EQ(fallback_filter_chain, build_out_fallback_filter_chain_.get()); } -TEST_F(FilterChainManagerImplTest, LookupFilterChainContextByFilterChainMessage) { +TEST_P(FilterChainManagerImplTest, LookupFilterChainContextByFilterChainMessage) { std::vector filter_chain_messages; for (int i = 0; i < 2; i++) { @@ -192,12 +217,13 @@ TEST_F(FilterChainManagerImplTest, LookupFilterChainContextByFilterChainMessage) } EXPECT_CALL(filter_chain_factory_builder_, buildFilterChain(_, _)).Times(2); filter_chain_manager_.addFilterChains( + GetParam() ? &matcher_ : nullptr, std::vector{&filter_chain_messages[0], &filter_chain_messages[1]}, nullptr, filter_chain_factory_builder_, filter_chain_manager_); } -TEST_F(FilterChainManagerImplTest, DuplicateContextsAreNotBuilt) { +TEST_P(FilterChainManagerImplTest, DuplicateContextsAreNotBuilt) { std::vector filter_chain_messages; for (int i = 0; i < 3; i++) { @@ -210,6 +236,7 @@ TEST_F(FilterChainManagerImplTest, DuplicateContextsAreNotBuilt) { EXPECT_CALL(filter_chain_factory_builder_, buildFilterChain(_, _)); filter_chain_manager_.addFilterChains( + GetParam() ? &matcher_ : nullptr, std::vector{&filter_chain_messages[0]}, nullptr, filter_chain_factory_builder_, filter_chain_manager_); @@ -220,12 +247,13 @@ TEST_F(FilterChainManagerImplTest, DuplicateContextsAreNotBuilt) { // built because it reuse the filter chain context in the previous filter chain manager EXPECT_CALL(filter_chain_factory_builder_, buildFilterChain(_, _)).Times(2); new_filter_chain_manager.addFilterChains( + GetParam() ? &matcher_ : nullptr, std::vector{ &filter_chain_messages[0], &filter_chain_messages[1], &filter_chain_messages[2]}, nullptr, filter_chain_factory_builder_, new_filter_chain_manager); } -TEST_F(FilterChainManagerImplTest, CreatedFilterChainFactoryContextHasIndependentDrainClose) { +TEST_P(FilterChainManagerImplTest, CreatedFilterChainFactoryContextHasIndependentDrainClose) { std::vector filter_chain_messages; for (int i = 0; i < 3; i++) { envoy::config::listener::v3::FilterChain new_filter_chain = filter_chain_template_; @@ -255,5 +283,8 @@ TEST_F(FilterChainManagerImplTest, CreatedFilterChainFactoryContextHasIndependen EXPECT_TRUE(context0->drainDecision().drainClose()); EXPECT_FALSE(context1->drainDecision().drainClose()); } + +INSTANTIATE_TEST_SUITE_P(Matcher, FilterChainManagerImplTest, ::testing::Values(true, false)); + } // namespace Server } // namespace Envoy From 2cd49310ccca9931392e1f6eb713e23e7f946097 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Thu, 24 Feb 2022 11:41:59 -0800 Subject: [PATCH 18/39] changes Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener.proto | 1 - .../listener/v3/listener_components.proto | 5 +- source/server/filter_chain_manager_impl.cc | 8 +- source/server/listener_impl.cc | 2 + test/integration/xds_integration_test.cc | 136 ++++++++++++++++-- test/server/filter_chain_manager_impl_test.cc | 1 + test/server/listener_manager_impl_test.cc | 86 +++++++++++ 7 files changed, 220 insertions(+), 19 deletions(-) diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index e1da21b518d44..52af634a3f7df 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -121,7 +121,6 @@ message Listener { // :ref:`FAQ entry `. repeated FilterChain filter_chains = 3; - // [#not-implemented-hide:] // Unified matcher resolving the filter chain name from the network properties. This matcher is used as a replacement // for the per-filter chain match condition // `filter_chain_match `. diff --git a/api/envoy/config/listener/v3/listener_components.proto b/api/envoy/config/listener/v3/listener_components.proto index 535d181405462..8ca54b3cb2624 100644 --- a/api/envoy/config/listener/v3/listener_components.proto +++ b/api/envoy/config/listener/v3/listener_components.proto @@ -259,9 +259,8 @@ message FilterChain { // establishment, the connection is summarily closed. google.protobuf.Duration transport_socket_connect_timeout = 9; - // [#not-implemented-hide:] The unique name (or empty) by which this filter chain is known. If no - // name is provided, Envoy will allocate an internal UUID for the filter chain. If the filter - // chain is to be dynamically updated or removed via FCDS a unique name must be provided. + // The unique name (or empty) by which this filter chain is known. If no + // name is provided, Envoy will allocate an internal UUID for the filter chain. // Note: :ref:`filter_chain_matcher // ` // requires that filter chains are uniquely named. diff --git a/source/server/filter_chain_manager_impl.cc b/source/server/filter_chain_manager_impl.cc index d32223b22ab78..2f79e22b68e16 100644 --- a/source/server/filter_chain_manager_impl.cc +++ b/source/server/filter_chain_manager_impl.cc @@ -248,7 +248,13 @@ void FilterChainManagerImpl::addFilterChains( "error adding listener '{}': \"name\" field is required when using a listener matcher", address_->asString())); } - filter_chains_by_name_.try_emplace(filter_chain->name(), filter_chain_impl); + auto [_, inserted] = + filter_chains_by_name_.try_emplace(filter_chain->name(), filter_chain_impl); + if (!inserted) { + throw EnvoyException( + fmt::format("error adding listener '{}': \"name\" field is duplicated with value '{}'", + address_->asString(), filter_chain->name())); + } } else { auto createAddressVector = [](const auto& prefix_ranges) -> std::vector { std::vector ips; diff --git a/source/server/listener_impl.cc b/source/server/listener_impl.cc index b31e551160aaf..a4d601923d3ee 100644 --- a/source/server/listener_impl.cc +++ b/source/server/listener_impl.cc @@ -949,6 +949,8 @@ bool ListenerMessageUtil::filterChainOnlyChange(const envoy::config::listener::v envoy::config::listener::v3::Listener::GetDescriptor()->FindFieldByName("filter_chains")); differencer.IgnoreField(envoy::config::listener::v3::Listener::GetDescriptor()->FindFieldByName( "default_filter_chain")); + differencer.IgnoreField(envoy::config::listener::v3::Listener::GetDescriptor()->FindFieldByName( + "filter_chain_matcher")); return differencer.Compare(lhs, rhs); } diff --git a/test/integration/xds_integration_test.cc b/test/integration/xds_integration_test.cc index 8e866132782b7..a1d6885ddd205 100644 --- a/test/integration/xds_integration_test.cc +++ b/test/integration/xds_integration_test.cc @@ -102,14 +102,39 @@ TEST_P(UdpaXdsIntegrationTestListCollection, RouterRequestAndResponseWithBodyNoB } class LdsInplaceUpdateTcpProxyIntegrationTest - : public testing::TestWithParam, + : public testing::TestWithParam>, public BaseIntegrationTest { public: LdsInplaceUpdateTcpProxyIntegrationTest() - : BaseIntegrationTest(GetParam(), ConfigHelper::baseConfig() + R"EOF( + : BaseIntegrationTest(std::get<0>(GetParam()), ConfigHelper::baseConfig() + + (std::get<1>(GetParam()) ? R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: alpn + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.ApplicationProtocolInput + exact_match_map: + map: + "'alpn0'": + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + "'alpn1'": + action: + name: bar + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: bar +)EOF" + : "") + + R"EOF( filter_chains: - filter_chain_match: application_protocols: ["alpn0"] + name: foo filters: - name: envoy.filters.network.tcp_proxy typed_config: @@ -118,6 +143,7 @@ class LdsInplaceUpdateTcpProxyIntegrationTest cluster: cluster_0 - filter_chain_match: application_protocols: ["alpn1"] + name: bar filters: - name: envoy.filters.network.tcp_proxy typed_config: @@ -136,7 +162,8 @@ class LdsInplaceUpdateTcpProxyIntegrationTest "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy stat_prefix: tcp_stats cluster: cluster_0 -)EOF") {} +)EOF"), + matcher_(std::get<1>(GetParam())) {} void initialize() override { config_helper_.renameListener("tcp"); @@ -181,6 +208,7 @@ class LdsInplaceUpdateTcpProxyIntegrationTest std::unique_ptr context_manager_; Network::TransportSocketFactoryPtr context_; testing::NiceMock secret_manager_; + bool matcher_; }; // Verify that tcp connection 1 is closed while client 0 survives when deleting filter chain 1. @@ -205,6 +233,24 @@ TEST_P(LdsInplaceUpdateTcpProxyIntegrationTest, ReloadConfigDeletingFilterChain) [&](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { auto* listener = bootstrap.mutable_static_resources()->mutable_listeners(0); listener->mutable_filter_chains()->RemoveLast(); + if (matcher_) { + TestUtility::loadFromYaml(R"EOF( + matcher_tree: + input: + name: alpn + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.ApplicationProtocolInput + exact_match_map: + map: + "'alpn0'": + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF", + *listener->mutable_filter_chain_matcher()); + } }); new_config_helper.setLds("1"); test_server_->waitForCounterGe("listener_manager.listener_in_place_updated", 1); @@ -250,6 +296,25 @@ TEST_P(LdsInplaceUpdateTcpProxyIntegrationTest, ReloadConfigAddingFilterChain) { *listener->mutable_filter_chains(2) ->mutable_filter_chain_match() ->mutable_application_protocols(0) = "alpn2"; + listener->mutable_filter_chains(2)->set_name("baz"); + if (matcher_) { + TestUtility::loadFromYaml(R"EOF( + matcher_tree: + input: + name: alpn + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.ApplicationProtocolInput + exact_match_map: + map: + "'alpn2'": + action: + name: baz + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: baz + )EOF", + *listener->mutable_filter_chain_matcher()); + } }); new_config_helper.setLds("1"); test_server_->waitForCounterGe("listener_manager.listener_in_place_updated", 1); @@ -288,10 +353,12 @@ TEST_P(LdsInplaceUpdateTcpProxyIntegrationTest, ReloadConfigAddingFilterChain) { } class LdsInplaceUpdateHttpIntegrationTest - : public testing::TestWithParam, + : public testing::TestWithParam>, public HttpIntegrationTest { public: - LdsInplaceUpdateHttpIntegrationTest() : HttpIntegrationTest(Http::CodecType::HTTP1, GetParam()) {} + LdsInplaceUpdateHttpIntegrationTest() + : HttpIntegrationTest(Http::CodecType::HTTP1, std::get<0>(GetParam())), + matcher_(std::get<1>(GetParam())) {} void inplaceInitialize(bool add_default_filter_chain = false) { autonomous_upstream_ = true; @@ -316,6 +383,7 @@ class LdsInplaceUpdateHttpIntegrationTest bootstrap.mutable_static_resources()->mutable_listeners(0)->mutable_filter_chains(0); *filter_chain_0->mutable_filter_chain_match()->mutable_application_protocols()->Add() = "alpn0"; + filter_chain_0->set_name("alpn0"); auto* filter_chain_1 = bootstrap.mutable_static_resources() ->mutable_listeners(0) ->mutable_filter_chains() @@ -325,6 +393,7 @@ class LdsInplaceUpdateHttpIntegrationTest // filter chain 1 // alpn1, route to cluster_1 *filter_chain_1->mutable_filter_chain_match()->mutable_application_protocols(0) = "alpn1"; + filter_chain_1->set_name("alpn1"); auto* config_blob = filter_chain_1->mutable_filters(0)->mutable_typed_config(); @@ -349,6 +418,39 @@ class LdsInplaceUpdateHttpIntegrationTest ->mutable_listeners(0) ->mutable_default_filter_chain(); default_filter_chain->MergeFrom(*filter_chain_0); + default_filter_chain->set_name("default"); + } + if (matcher_) { + TestUtility::loadFromYaml(R"EOF( + matcher_tree: + input: + name: alpn + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.ApplicationProtocolInput + exact_match_map: + map: + "'alpn0'": + action: + name: alpn0 + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: alpn0 + "'alpn1'": + action: + name: alpn1 + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: alpn1 + "'alpn2'": + action: + name: alpn2 + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: alpn2 + )EOF", + *bootstrap.mutable_static_resources() + ->mutable_listeners(0) + ->mutable_filter_chain_matcher()); } }); @@ -396,6 +498,7 @@ class LdsInplaceUpdateHttpIntegrationTest testing::NiceMock secret_manager_; Network::Address::InstanceConstSharedPtr address_; bool use_default_balancer_{false}; + bool matcher_; }; // Verify that http response on filter chain 1 and default filter chain have "Connection: close" @@ -456,10 +559,12 @@ TEST_P(LdsInplaceUpdateHttpIntegrationTest, ReloadConfigAddingFilterChain) { *listener->mutable_filter_chains(2) ->mutable_filter_chain_match() ->mutable_application_protocols(0) = "alpn2"; + listener->mutable_filter_chains(2)->set_name("alpn2"); auto default_filter_chain = bootstrap.mutable_static_resources()->mutable_listeners(0)->mutable_default_filter_chain(); default_filter_chain->MergeFrom(*listener->mutable_filter_chains(1)); + default_filter_chain->set_name("default"); }); new_config_helper.setLds("1"); test_server_->waitForCounterGe("listener_manager.listener_in_place_updated", 1); @@ -533,13 +638,15 @@ TEST_P(LdsInplaceUpdateHttpIntegrationTest, OverlappingFilterChainServesNewConne // Verify default filter chain update is filter chain only update. TEST_P(LdsInplaceUpdateHttpIntegrationTest, DefaultFilterChainUpdate) {} -INSTANTIATE_TEST_SUITE_P(IpVersions, LdsInplaceUpdateHttpIntegrationTest, - testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), - TestUtility::ipTestParamsToString); +INSTANTIATE_TEST_SUITE_P( + IpVersionsAndMatcher, LdsInplaceUpdateHttpIntegrationTest, + testing::Combine(testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), + testing::Values(false, true))); -INSTANTIATE_TEST_SUITE_P(IpVersions, LdsInplaceUpdateTcpProxyIntegrationTest, - testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), - TestUtility::ipTestParamsToString); +INSTANTIATE_TEST_SUITE_P( + IpVersionsAndMatcher, LdsInplaceUpdateTcpProxyIntegrationTest, + testing::Combine(testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), + testing::Values(false, true))); using LdsIntegrationTest = HttpProtocolIntegrationTest; @@ -625,9 +732,10 @@ TEST_P(LdsIntegrationTest, FailConfigLoad) { class LdsStsIntegrationTest : public Event::SimulatedTimeSystem, public LdsInplaceUpdateTcpProxyIntegrationTest {}; -INSTANTIATE_TEST_SUITE_P(IpVersions, LdsStsIntegrationTest, - testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), - TestUtility::ipTestParamsToString); +INSTANTIATE_TEST_SUITE_P( + IpVersionsAndMatcher, LdsStsIntegrationTest, + testing::Combine(testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), + testing::Values(false, true))); // Verify that the listener in place update will accomplish anyway if the listener is removed. TEST_P(LdsStsIntegrationTest, TcpListenerRemoveFilterChainCalledAfterListenerIsRemoved) { diff --git a/test/server/filter_chain_manager_impl_test.cc b/test/server/filter_chain_manager_impl_test.cc index dc7c5a7be27bd..11d09c45258e6 100644 --- a/test/server/filter_chain_manager_impl_test.cc +++ b/test/server/filter_chain_manager_impl_test.cc @@ -132,6 +132,7 @@ class FilterChainManagerImplTest : public testing::TestWithParam { const std::string filter_chain_matcher = R"EOF( matcher_tree: input: + name: port typed_config: "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput exact_match_map: diff --git a/test/server/listener_manager_impl_test.cc b/test/server/listener_manager_impl_test.cc index 2f9c18052998a..96bd303f64079 100644 --- a/test/server/listener_manager_impl_test.cc +++ b/test/server/listener_manager_impl_test.cc @@ -3733,6 +3733,71 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithOverlappi "overlapping matching rules are defined"); } +TEST_F(ListenerManagerImplWithRealFiltersTest, MatcherFilterChainWithoutName) { + const std::string yaml = TestEnvironment::substitute(R"EOF( + address: + socket_address: { address: 127.0.0.1, port_value: 1234 } + listener_filters: + - name: "envoy.filters.listener.tls_inspector" + filter_chain_matcher: + matcher_tree: + input: + name: port + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput + exact_match_map: + map: + "10000": + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + filter_chains: + - filters: [] + )EOF", + Network::Address::IpVersion::v4); + + EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), + EnvoyException, + "error adding listener '127.0.0.1:1234': \"name\" field is required " + "when using a listener matcher"); +} + +TEST_F(ListenerManagerImplWithRealFiltersTest, MatcherFilterChainWithDuplicateName) { + const std::string yaml = TestEnvironment::substitute(R"EOF( + address: + socket_address: { address: 127.0.0.1, port_value: 1234 } + listener_filters: + - name: "envoy.filters.listener.tls_inspector" + filter_chain_matcher: + matcher_tree: + input: + name: port + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput + exact_match_map: + map: + "10000": + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + filter_chains: + - name: foo + filters: [] + - name: foo + filters: [] + )EOF", + Network::Address::IpVersion::v4); + + EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), + EnvoyException, + "error adding listener '127.0.0.1:1234': \"name\" field is duplicated " + "with value 'foo'"); +} + TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInline) { const std::string cert = TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns3_chain.pem")); @@ -5663,6 +5728,27 @@ TEST(ListenerMessageUtilTest, ListenerDefaultFilterChainChangeIsAlwaysFilterChai *listener2.mutable_default_filter_chain() = default_filter_chain_2; EXPECT_TRUE(Server::ListenerMessageUtil::filterChainOnlyChange(listener1, listener2)); } + { + listener1.clear_default_filter_chain(); + listener2.clear_default_filter_chain(); + const std::string filter_chain_matcher = R"EOF( + matcher_tree: + input: + name: port + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput + exact_match_map: + map: + "10000": + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + TestUtility::loadFromYaml(filter_chain_matcher, *listener2.mutable_filter_chain_matcher()); + EXPECT_TRUE(Server::ListenerMessageUtil::filterChainOnlyChange(listener1, listener2)); + } } TEST(ListenerMessageUtilTest, ListenerMessageHaveDifferentFilterChainsAreEquivalent) { From e8961864b5f496f121662ae45f0fc9534d15ad8f Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Thu, 24 Feb 2022 12:00:06 -0800 Subject: [PATCH 19/39] fix doc Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener.proto | 1 + 1 file changed, 1 insertion(+) diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index 52af634a3f7df..a6ae24f516b92 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -141,6 +141,7 @@ message Listener { // filter_chain_matcher: // matcher_tree: // input: + // name: port // typed_config: // "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput // exact_match_map: From d5feb5f5f9261e5fea4dead64fb7a3e6d1dcee01 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Thu, 24 Feb 2022 22:57:47 -0800 Subject: [PATCH 20/39] increase coverage Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener.proto | 2 + source/extensions/common/matcher/BUILD | 2 + source/server/filter_chain_manager_impl.h | 2 +- test/server/BUILD | 1 + test/server/listener_manager_impl_test.cc | 1470 +++++++++++++------ test/server/listener_manager_impl_test.h | 40 +- 6 files changed, 1035 insertions(+), 482 deletions(-) diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index a6ae24f516b92..de579bf02e5be 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -156,9 +156,11 @@ message Listener { // matcher: // matcher_tree: // input: + // name: ip // typed_config: // "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.SourceIPInput // custom_match: + // name: ip-matcher // typed_config: // "@type": type.googleapis.com/xds.type.matcher.v3.IPMatcher // range_matchers: diff --git a/source/extensions/common/matcher/BUILD b/source/extensions/common/matcher/BUILD index c783a68487384..b04a3b04905c1 100644 --- a/source/extensions/common/matcher/BUILD +++ b/source/extensions/common/matcher/BUILD @@ -24,6 +24,8 @@ envoy_cc_library( name = "trie_matcher_lib", srcs = ["trie_matcher.cc"], hdrs = ["trie_matcher.h"], + # IP matching is core functionality. + visibility = ["//visibility:public"], deps = [ "//envoy/matcher:matcher_interface", "//envoy/network:filter_interface", diff --git a/source/server/filter_chain_manager_impl.h b/source/server/filter_chain_manager_impl.h index 0756aaaefc5d6..239451405f410 100644 --- a/source/server/filter_chain_manager_impl.h +++ b/source/server/filter_chain_manager_impl.h @@ -393,7 +393,7 @@ class FilterChainManagerImpl : public Network::FilterChainManager, // For FilterChainFactoryContextCreator // init manager owned by the corresponding listener. The reference is valid when building the - // filter chain.,, + // filter chain. Init::Manager& init_manager_; // Matcher selecting the filter chain name. diff --git a/test/server/BUILD b/test/server/BUILD index e62d1f586941a..63e3877356f8f 100644 --- a/test/server/BUILD +++ b/test/server/BUILD @@ -284,6 +284,7 @@ envoy_cc_test_library( data = ["//test/extensions/transport_sockets/tls/test_data:certs"], deps = [ "//source/common/init:manager_lib", + "//source/extensions/common/matcher:trie_matcher_lib", "//source/server:listener_manager_lib", "//test/mocks/init:init_mocks", "//test/mocks/matcher:matcher_mocks", diff --git a/test/server/listener_manager_impl_test.cc b/test/server/listener_manager_impl_test.cc index 96bd303f64079..eebfe0f8b1396 100644 --- a/test/server/listener_manager_impl_test.cc +++ b/test/server/listener_manager_impl_test.cc @@ -23,6 +23,7 @@ #include "source/common/network/socket_interface_impl.h" #include "source/common/network/utility.h" #include "source/common/protobuf/protobuf.h" +#include "source/extensions/common/matcher/trie_matcher.h" #include "source/extensions/filters/listener/original_dst/original_dst.h" #include "source/extensions/transport_sockets/tls/ssl_socket.h" @@ -63,7 +64,8 @@ class ListenerManagerImplWithRealFiltersTest : public ListenerManagerImplTest { address: socket_address: { address: 127.0.0.1, port_value: 1111 } filter_chains: - - filters: + - filters: [] + name: foo )EOF"); listener.set_name(name); return listener; @@ -84,10 +86,10 @@ class ListenerManagerImplWithRealFiltersTest : public ListenerManagerImplTest { expectCreateListenSocket(expected_state, expected_num_options, bind_type); expectSetsockopt(expected_option.level(), expected_option.option(), expected_value, expected_num_options); - manager_->addOrUpdateListener(listener, "", true); + addOrUpdateListener(listener); EXPECT_EQ(1U, manager_->listeners().size()); } else { - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(listener, "", true), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(listener), EnvoyException, "MockListenerComponentFactory: Setting socket options failed"); EXPECT_EQ(0U, manager_->listeners().size()); } @@ -117,7 +119,7 @@ class ListenerManagerImplForInPlaceFilterChainUpdateTest : public Event::Simulat ListenerHandle*) { EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(*worker_, addListener(_, _, _, _)); - manager_->addOrUpdateListener(listener_proto, "", true); + addOrUpdateListener(listener_proto); worker_->callAddCompletion(); EXPECT_EQ(1UL, manager_->listeners().size()); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); @@ -141,7 +143,7 @@ class ListenerManagerImplForInPlaceFilterChainUpdateTest : public Event::Simulat EXPECT_CALL(*worker_, stopListener(_, _)); EXPECT_CALL(*old_listener_handle->drain_manager_, startDrainSequence(_)); - EXPECT_TRUE(manager_->addOrUpdateListener(new_listener_proto, "", true)); + EXPECT_TRUE(addOrUpdateListener(new_listener_proto)); EXPECT_CALL(*worker_, removeListener(_, _)); old_listener_handle->drain_manager_->drain_sequence_completion_(); @@ -172,7 +174,7 @@ class MockLdsApi : public LdsApi { MOCK_METHOD(std::string, versionInfo, (), (const)); }; -TEST_F(ListenerManagerImplWithRealFiltersTest, EmptyFilter) { +TEST_P(ListenerManagerImplWithRealFiltersTest, EmptyFilter) { const std::string yaml = R"EOF( address: socket_address: @@ -180,18 +182,19 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, EmptyFilter) { port_value: 1234 filter_chains: - filters: [] + name: foo )EOF"; EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(&manager_->httpContext(), &server_.httpContext()); EXPECT_EQ(1U, manager_->listeners().size()); EXPECT_EQ(std::chrono::milliseconds(15000), manager_->listeners().front().get().listenerFiltersTimeout()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, DefaultListenerPerConnectionBufferLimit) { +TEST_P(ListenerManagerImplWithRealFiltersTest, DefaultListenerPerConnectionBufferLimit) { const std::string yaml = R"EOF( address: socket_address: @@ -199,14 +202,15 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, DefaultListenerPerConnectionBuffe port_value: 1234 filter_chains: - filters: [] + name: foo )EOF"; EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1024 * 1024U, manager_->listeners().back().get().perConnectionBufferLimitBytes()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, DuplicatePortNotAllowed) { +TEST_P(ListenerManagerImplWithRealFiltersTest, DuplicatePortNotAllowed) { const std::string yaml1 = R"EOF( name: foo address: @@ -215,6 +219,7 @@ name: foo port_value: 1234 filter_chains: - filters: [] + name: foo )EOF"; const std::string yaml2 = R"EOF( @@ -225,16 +230,17 @@ name: bar port_value: 1234 filter_chains: - filters: [] + name: foo )EOF"; EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml1), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml1)); EXPECT_THROW_WITH_MESSAGE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml2), "", true), EnvoyException, + addOrUpdateListener(parseListenerFromV3Yaml(yaml2)), EnvoyException, "error adding listener: 'bar' has duplicate address '127.0.0.1:1234' as existing listener"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, SetListenerPerConnectionBufferLimit) { +TEST_P(ListenerManagerImplWithRealFiltersTest, SetListenerPerConnectionBufferLimit) { const std::string yaml = R"EOF( address: socket_address: @@ -242,15 +248,16 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SetListenerPerConnectionBufferLim port_value: 1234 filter_chains: - filters: [] + name: foo per_connection_buffer_limit_bytes: 8192 )EOF"; EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(8192U, manager_->listeners().back().get().perConnectionBufferLimitBytes()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, TlsTransportSocket) { +TEST_P(ListenerManagerImplWithRealFiltersTest, TlsTransportSocket) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: @@ -258,6 +265,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TlsTransportSocket) { port_value: 1234 filter_chains: - filters: [] + name: foo transport_socket: name: tls typed_config: @@ -278,7 +286,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TlsTransportSocket) { Network::Address::IpVersion::v4); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); auto filter_chain = findFilterChain(1234, "127.0.0.1", "", "tls", {}, "8.8.8.8", 111); @@ -286,7 +294,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TlsTransportSocket) { EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, TransportSocketConnectTimeout) { +TEST_P(ListenerManagerImplWithRealFiltersTest, TransportSocketConnectTimeout) { const std::string yaml = R"EOF( address: socket_address: @@ -294,17 +302,18 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TransportSocketConnectTimeout) { port_value: 1234 filter_chains: - filters: [] + name: foo transport_socket_connect_timeout: 3s )EOF"; EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); auto filter_chain = findFilterChain(1234, "127.0.0.1", "", "", {}, "8.8.8.8", 111); ASSERT_NE(filter_chain, nullptr); EXPECT_EQ(filter_chain->transportSocketConnectTimeout(), std::chrono::seconds(3)); } -TEST_F(ListenerManagerImplWithRealFiltersTest, UdpAddress) { +TEST_P(ListenerManagerImplWithRealFiltersTest, UdpAddress) { EXPECT_CALL(*worker_, start(_, _)); EXPECT_FALSE(manager_->isWorkerStarted()); manager_->startWorkers(guard_dog_, callback_.AsStdFunction()); @@ -341,11 +350,11 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, UdpAddress) { uint32_t) -> Network::SocketSharedPtr { return listener_factory_.socket_; })); EXPECT_CALL(*listener_factory_.socket_, setSocketOption(_, _, _, _)).Times(testing::AtLeast(1)); EXPECT_CALL(os_sys_calls_, close(_)).WillRepeatedly(Return(Api::SysCallIntResult{0, errno})); - manager_->addOrUpdateListener(listener_proto, "", true); + addOrUpdateListener(listener_proto); EXPECT_EQ(1u, manager_->listeners().size()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, AllowOnlyDefaultFilterChain) { +TEST_P(ListenerManagerImplWithRealFiltersTest, AllowOnlyDefaultFilterChain) { const std::string yaml = R"EOF( address: socket_address: @@ -355,11 +364,11 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, AllowOnlyDefaultFilterChain) { filters: [] )EOF"; - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1, manager_->listeners().size()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, BadListenerConfig) { +TEST_P(ListenerManagerImplWithRealFiltersTest, BadListenerConfig) { const std::string yaml = R"EOF( address: socket_address: @@ -370,11 +379,11 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, BadListenerConfig) { test: a )EOF"; - EXPECT_THROW_WITH_REGEX(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, "test: Cannot find field"); + EXPECT_THROW_WITH_REGEX(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, + "test: Cannot find field"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, BadListenerConfigNoFilterChains) { +TEST_P(ListenerManagerImplWithRealFiltersTest, BadListenerConfigNoFilterChains) { const std::string yaml = R"EOF( address: socket_address: @@ -382,11 +391,11 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, BadListenerConfigNoFilterChains) port_value: 1234 )EOF"; - EXPECT_THROW_WITH_REGEX(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, "no filter chains specified"); + EXPECT_THROW_WITH_REGEX(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, + "no filter chains specified"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, BadFilterConfig) { +TEST_P(ListenerManagerImplWithRealFiltersTest, BadFilterConfig) { const std::string yaml = R"EOF( address: socket_address: @@ -396,24 +405,26 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, BadFilterConfig) { - filters: - foo: type name: name + name: foo )EOF"; - EXPECT_THROW_WITH_REGEX(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, "foo: Cannot find field"); + EXPECT_THROW_WITH_REGEX(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, + "foo: Cannot find field"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, BadConnectionLessUdpConfigWithFilterChain) { +TEST_P(ListenerManagerImplWithRealFiltersTest, BadConnectionLessUdpConfigWithFilterChain) { const std::string yaml = R"EOF( address: socket_address: protocol: UDP address: 127.0.0.1 port_value: 1234 -filter_chains: {} +filter_chains: +- filters: [] + name: foo )EOF"; - EXPECT_THROW_WITH_REGEX(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, + EXPECT_THROW_WITH_REGEX(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "1 filter chain\\(s\\) specified for connection-less UDP listener"); } @@ -435,7 +446,7 @@ class NonTerminalFilterFactory : public Configuration::NamedNetworkFilterConfigF std::string name() const override { return "non_terminal"; } }; -TEST_F(ListenerManagerImplWithRealFiltersTest, TerminalNotLast) { +TEST_P(ListenerManagerImplWithRealFiltersTest, TerminalNotLast) { NonTerminalFilterFactory filter; Registry::InjectFactory registered(filter); @@ -447,15 +458,16 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TerminalNotLast) { filter_chains: - filters: - name: non_terminal + name: foo )EOF"; EXPECT_THROW_WITH_REGEX( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), EnvoyException, + addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "Error: non-terminal filter named non_terminal of type non_terminal is the last " "filter in a network filter chain."); } -TEST_F(ListenerManagerImplWithRealFiltersTest, NotTerminalLast) { +TEST_P(ListenerManagerImplWithRealFiltersTest, NotTerminalLast) { const std::string yaml = R"EOF( address: socket_address: @@ -469,15 +481,16 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, NotTerminalLast) { stat_prefix: tcp cluster: cluster - name: unknown_but_will_not_be_processed + name: foo )EOF"; EXPECT_THROW_WITH_REGEX( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), EnvoyException, + addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "Error: terminal filter named envoy.filters.network.tcp_proxy of type " "envoy.filters.network.tcp_proxy must be the last filter in a network filter chain."); } -TEST_F(ListenerManagerImplWithRealFiltersTest, BadFilterName) { +TEST_P(ListenerManagerImplWithRealFiltersTest, BadFilterName) { const std::string yaml = R"EOF( address: socket_address: @@ -486,10 +499,10 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, BadFilterName) { filter_chains: - filters: - name: invalid + name: foo )EOF"; - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "Didn't find a registered implementation for name: 'invalid'"); } @@ -522,7 +535,7 @@ class TestStatsConfigFactory : public Configuration::NamedNetworkFilterConfigFac } }; -TEST_F(ListenerManagerImplWithRealFiltersTest, StatsScopeTest) { +TEST_P(ListenerManagerImplWithRealFiltersTest, StatsScopeTest) { TestStatsConfigFactory filter; Registry::InjectFactory registered(filter); @@ -535,18 +548,19 @@ bind_to_port: false filter_chains: - filters: - name: stats_test + name: foo )EOF"; EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, ListenerComponentFactory::BindType::NoBind, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); manager_->listeners().front().get().listenerScope().counterFromString("foo").inc(); EXPECT_EQ(1UL, server_.stats_store_.counterFromString("bar").value()); EXPECT_EQ(1UL, server_.stats_store_.counterFromString("listener.127.0.0.1_1234.foo").value()); } -TEST_F(ListenerManagerImplTest, UnsupportedInternalListener) { +TEST_P(ListenerManagerImplTest, UnsupportedInternalListener) { auto scoped_runtime_guard = std::make_unique(); // Workaround of triggering death at windows platform. Runtime::LoaderSingleton::getExisting()->mergeValues( @@ -561,10 +575,10 @@ TEST_F(ListenerManagerImplTest, UnsupportedInternalListener) { - filters: [] )EOF"; - EXPECT_DEATH(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), ".*"); + EXPECT_DEATH(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), ".*"); } -TEST_F(ListenerManagerImplTest, RejectListenerWithSocketAddressWithInternalListenerConfig) { +TEST_P(ListenerManagerImplTest, RejectListenerWithSocketAddressWithInternalListenerConfig) { auto scoped_runtime_guard = std::make_unique(); Runtime::LoaderSingleton::getExisting()->mergeValues( {{"envoy.reloadable_features.internal_address", "true"}}); @@ -580,13 +594,12 @@ TEST_F(ListenerManagerImplTest, RejectListenerWithSocketAddressWithInternalListe - filters: [] )EOF"; - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "error adding listener '127.0.0.1:1234': address is not an internal " "address but an internal listener config is provided"); } -TEST_F(ListenerManagerImplTest, RejectTcpOptionsWithInternalListenerConfig) { +TEST_P(ListenerManagerImplTest, RejectTcpOptionsWithInternalListenerConfig) { auto scoped_runtime_guard = std::make_unique(); Runtime::LoaderSingleton::getExisting()->mergeValues( {{"envoy.reloadable_features.internal_address", "true"}}); @@ -624,19 +637,19 @@ TEST_F(ListenerManagerImplTest, RejectTcpOptionsWithInternalListenerConfig) { { auto new_listener = listener; new_listener.mutable_socket_options()->Add(); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(new_listener, "", true), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(new_listener), EnvoyException, "error adding listener 'envoy://test_internal_listener_name': does " "not support socket option") } { auto new_listener = listener; new_listener.set_enable_mptcp(true); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(new_listener, "", true), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(new_listener), EnvoyException, "listener foo: enable_mptcp can only be used with IP addresses") } } -TEST_F(ListenerManagerImplTest, NotDefaultListenerFiltersTimeout) { +TEST_P(ListenerManagerImplTest, NotDefaultListenerFiltersTimeout) { const std::string yaml = R"EOF( name: "foo" address: @@ -647,12 +660,12 @@ TEST_F(ListenerManagerImplTest, NotDefaultListenerFiltersTimeout) { )EOF"; EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(yaml))); EXPECT_EQ(std::chrono::milliseconds(), manager_->listeners().front().get().listenerFiltersTimeout()); } -TEST_F(ListenerManagerImplTest, ModifyOnlyDrainType) { +TEST_P(ListenerManagerImplTest, ModifyOnlyDrainType) { InSequence s; // Add foo listener. @@ -668,13 +681,13 @@ TEST_F(ListenerManagerImplTest, ModifyOnlyDrainType) { ListenerHandle* listener_foo = expectListenerCreate(false, true, envoy::config::listener::v3::Listener::MODIFY_ONLY); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); EXPECT_CALL(*listener_foo, onDestroy()); } -TEST_F(ListenerManagerImplTest, AddListenerAddressNotMatching) { +TEST_P(ListenerManagerImplTest, AddListenerAddressNotMatching) { time_system_.setSystemTime(std::chrono::milliseconds(1001001001001)); InSequence s; @@ -696,8 +709,7 @@ filter_chains: {} ListenerHandle* listener_foo = expectListenerCreate(false, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "version1", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "version1")); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); EXPECT_CALL(*lds_api, versionInfo()).WillOnce(Return("version1")); checkConfigDump(R"EOF( @@ -736,8 +748,8 @@ filter_chains: {} // Another socket should be created. EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(*listener_foo, onDestroy()); - EXPECT_TRUE(manager_->addOrUpdateListener( - parseListenerFromV3Yaml(listener_foo_different_address_yaml), "version2", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_different_address_yaml), + "version2")); checkStats(__LINE__, 1, 1, 0, 0, 1, 0, 0); EXPECT_CALL(*lds_api, versionInfo()).WillOnce(Return("version2")); checkConfigDump(R"EOF( @@ -780,8 +792,7 @@ filter_chains: {} ListenerHandle* listener_baz = expectListenerCreate(true, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(listener_baz->target_, initialize()); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_baz_yaml), "version3", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_baz_yaml), "version3")); EXPECT_CALL(*lds_api, versionInfo()).WillOnce(Return("version3")); checkConfigDump(R"EOF( version_info: version3 @@ -836,8 +847,8 @@ filter_chains: {} listener_baz->target_.ready(); })); EXPECT_CALL(listener_baz_different_address->target_, initialize()); - EXPECT_TRUE(manager_->addOrUpdateListener( - parseListenerFromV3Yaml(listener_baz_different_address_yaml), "version4", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_baz_different_address_yaml), + "version4")); EXPECT_CALL(*lds_api, versionInfo()).WillOnce(Return("version4")); checkConfigDump(R"EOF( version_info: version4 @@ -884,7 +895,7 @@ version_info: version4 // Make sure that a listener creation does not fail on IPv4 only setups when FilterChainMatch is not // specified and we try to create default CidrRange. See makeCidrListEntry function for // more details. -TEST_F(ListenerManagerImplTest, AddListenerOnIpv4OnlySetups) { +TEST_P(ListenerManagerImplTest, AddListenerOnIpv4OnlySetups) { InSequence s; const std::string listener_foo_yaml = R"EOF( @@ -908,7 +919,7 @@ drain_type: default EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); EXPECT_CALL(*listener_foo, onDestroy()); } @@ -916,7 +927,7 @@ drain_type: default // Make sure that a listener creation does not fail on IPv6 only setups when FilterChainMatch is not // specified and we try to create default CidrRange. See makeCidrListEntry function for // more details. -TEST_F(ListenerManagerImplTest, AddListenerOnIpv6OnlySetups) { +TEST_P(ListenerManagerImplTest, AddListenerOnIpv6OnlySetups) { InSequence s; const std::string listener_foo_yaml = R"EOF( @@ -940,13 +951,13 @@ drain_type: default EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); EXPECT_CALL(*listener_foo, onDestroy()); } // Make sure that a listener that is not added_via_api cannot be updated or removed. -TEST_F(ListenerManagerImplTest, UpdateRemoveNotModifiableListener) { +TEST_P(ListenerManagerImplTest, UpdateRemoveNotModifiableListener) { time_system_.setSystemTime(std::chrono::milliseconds(1001001001001)); InSequence s; @@ -964,7 +975,7 @@ name: foo ListenerHandle* listener_foo = expectListenerCreate(false, false); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", false)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", false)); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); checkConfigDump(R"EOF( static_listeners: @@ -993,8 +1004,7 @@ name: foo - name: fake )EOF"; - EXPECT_FALSE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), "", false)); + EXPECT_FALSE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), "", false)); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); // Remove foo listener. Should be blocked. @@ -1005,7 +1015,7 @@ name: foo } // Tests that when listener tears down, server's initManager is notified. -TEST_F(ListenerManagerImplTest, ListenerTeardownNotifiesServerInitManager) { +TEST_P(ListenerManagerImplTest, ListenerTeardownNotifiesServerInitManager) { time_system_.setSystemTime(std::chrono::milliseconds(1001001001001)); InSequence s; @@ -1044,8 +1054,7 @@ filter_chains: {} ListenerHandle* listener_foo = expectListenerCreate(true, true); EXPECT_CALL(server_, initManager()).WillOnce(ReturnRef(server_init_mgr)); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), - "version1", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "version1")); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); EXPECT_CALL(*lds_api, versionInfo()).WillOnce(Return("version1")); @@ -1097,8 +1106,7 @@ version_info: version1 EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); // Version 2 listener will be initialized by listener manager directly. EXPECT_CALL(listener_foo2->target_, initialize()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), - "version2", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "version2")); // Version2 is in warming list as listener_foo2->target_ is not ready yet. checkStats(__LINE__, /*added=*/2, 0, /*removed=*/1, /*warming=*/1, 0, 0, 0); EXPECT_CALL(*lds_api, versionInfo()).WillOnce(Return("version2")); @@ -1128,7 +1136,7 @@ version_info: version1 } } -TEST_F(ListenerManagerImplTest, OverrideListener) { +TEST_P(ListenerManagerImplTest, OverrideListener) { InSequence s; time_system_.setSystemTime(std::chrono::milliseconds(1001001001001)); @@ -1149,8 +1157,7 @@ filter_chains: {} ListenerHandle* listener_foo = expectListenerCreate(false, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "version1", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "version1", true)); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); // Start workers and capture ListenerImpl. @@ -1184,8 +1191,7 @@ name: foo EXPECT_CALL(*worker_, addListener(_, _, _, _)); auto* timer = new Event::MockTimer(dynamic_cast(&server_.dispatcher())); EXPECT_CALL(*timer, enableTimer(_, _)); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml))); EXPECT_EQ(1UL, manager_->listeners().size()); worker_->callAddCompletion(); @@ -1201,7 +1207,7 @@ name: foo EXPECT_EQ(1, server_.stats_store_.counter("listener_manager.listener_create_success").value()); } -TEST_F(ListenerManagerImplTest, AddOrUpdateListener) { +TEST_P(ListenerManagerImplTest, AddOrUpdateListener) { time_system_.setSystemTime(std::chrono::milliseconds(1001001001001)); NiceMock mock_matcher; ON_CALL(mock_matcher, match(_)).WillByDefault(Return(false)); @@ -1229,8 +1235,7 @@ filter_chains: {} ListenerHandle* listener_foo = expectListenerCreate(false, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "version1", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "version1", true)); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); EXPECT_CALL(*lds_api, versionInfo()).WillOnce(Return("version1")); checkConfigDump(R"EOF( @@ -1261,7 +1266,7 @@ version_info: version1 mock_matcher); // Update duplicate should be a NOP. - EXPECT_FALSE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_FALSE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); // Update foo listener. @@ -1282,8 +1287,8 @@ per_connection_buffer_limit_bytes: 10 EXPECT_CALL(*listener_factory_.socket_, duplicate()) .WillOnce(Return(ByMove(std::unique_ptr(duplicated_socket)))); EXPECT_CALL(*listener_foo, onDestroy()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), - "version2", true)); + EXPECT_TRUE( + addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), "version2", true)); checkStats(__LINE__, 1, 1, 0, 0, 1, 0, 0); EXPECT_CALL(*lds_api, versionInfo()).WillOnce(Return("version2")); checkConfigDump(R"EOF( @@ -1337,8 +1342,7 @@ version_info: version2 .value()); // Update duplicate should be a NOP. - EXPECT_FALSE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), "", true)); + EXPECT_FALSE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml))); checkStats(__LINE__, 1, 1, 0, 0, 1, 0, 0); time_system_.setSystemTime(std::chrono::milliseconds(3003003003003)); @@ -1350,8 +1354,7 @@ version_info: version2 EXPECT_CALL(*worker_, addListener(_, _, _, _)); EXPECT_CALL(*worker_, stopListener(_, _)); EXPECT_CALL(*listener_foo_update1->drain_manager_, startDrainSequence(_)); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "version3", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "version3", true)); worker_->callAddCompletion(); checkStats(__LINE__, 1, 2, 0, 0, 1, 1, 0); EXPECT_CALL(*lds_api, versionInfo()).WillOnce(Return("version3")); @@ -1419,8 +1422,7 @@ filter_chains: {} ListenerHandle* listener_bar = expectListenerCreate(false, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(*worker_, addListener(_, _, _, _)); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_bar_yaml), "version4", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_bar_yaml), "version4", true)); EXPECT_EQ(2UL, manager_->listeners().size()); worker_->callAddCompletion(); checkStats(__LINE__, 2, 2, 0, 0, 2, 0, 0); @@ -1440,8 +1442,7 @@ filter_chains: {} ListenerHandle* listener_baz = expectListenerCreate(true, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(listener_baz->target_, initialize()); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_baz_yaml), "version5", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_baz_yaml), "version5", true)); EXPECT_EQ(2UL, manager_->listeners().size()); checkStats(__LINE__, 3, 2, 0, 1, 2, 0, 0); EXPECT_CALL(*lds_api, versionInfo()).WillOnce(Return("version5")); @@ -1501,7 +1502,7 @@ version_info: version5 mock_matcher); // Update a duplicate baz that is currently warming. - EXPECT_FALSE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_baz_yaml), "", true)); + EXPECT_FALSE(addOrUpdateListener(parseListenerFromV3Yaml(listener_baz_yaml))); checkStats(__LINE__, 3, 2, 0, 1, 2, 0, 0); // Update baz while it is warming. @@ -1523,8 +1524,7 @@ name: baz listener_baz->target_.ready(); })); EXPECT_CALL(listener_baz_update1->target_, initialize()); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_baz_update1_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_baz_update1_yaml))); EXPECT_EQ(2UL, manager_->listeners().size()); checkStats(__LINE__, 3, 3, 0, 1, 2, 0, 0); @@ -1540,7 +1540,7 @@ name: baz EXPECT_CALL(*listener_baz_update1, onDestroy()); } -TEST_F(ListenerManagerImplTest, UpdateActiveToWarmAndBack) { +TEST_P(ListenerManagerImplTest, UpdateActiveToWarmAndBack) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -1560,7 +1560,7 @@ name: foo ListenerHandle* listener_foo = expectListenerCreate(true, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(listener_foo->target_, initialize()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); checkStats(__LINE__, 1, 0, 0, 1, 0, 0, 0); EXPECT_CALL(*worker_, addListener(_, _, _, _)); listener_foo->target_.ready(); @@ -1583,8 +1583,7 @@ per_connection_buffer_limit_bytes: 999 ListenerHandle* listener_foo_update1 = expectListenerCreate(true, true); EXPECT_CALL(*listener_factory_.socket_, duplicate()); EXPECT_CALL(listener_foo_update1->target_, initialize()); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml))); // Should be both active and warming now. EXPECT_EQ(1UL, manager_->listeners(ListenerManager::WARMING).size()); @@ -1593,7 +1592,7 @@ per_connection_buffer_limit_bytes: 999 // Update foo back to original active, should cause the warming listener to be removed. EXPECT_CALL(*listener_foo_update1, onDestroy()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); checkStats(__LINE__, 1, 2, 0, 0, 1, 0, 0); EXPECT_EQ(0UL, manager_->listeners(ListenerManager::WARMING).size()); @@ -1602,7 +1601,7 @@ per_connection_buffer_limit_bytes: 999 EXPECT_CALL(*listener_foo, onDestroy()); } -TEST_F(ListenerManagerImplTest, AddReusableDrainingListener) { +TEST_P(ListenerManagerImplTest, AddReusableDrainingListener) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -1626,7 +1625,7 @@ name: foo ListenerHandle* listener_foo = expectListenerCreate(false, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(*worker_, addListener(_, _, _, _)); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); worker_->callAddCompletion(); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); @@ -1649,7 +1648,7 @@ name: foo ListenerHandle* listener_foo2 = expectListenerCreate(false, true); EXPECT_CALL(*listener_factory_.socket_, duplicate()); EXPECT_CALL(*worker_, addListener(_, _, _, _)); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); worker_->callAddCompletion(); checkStats(__LINE__, 2, 0, 1, 0, 1, 1, 0); @@ -1662,7 +1661,7 @@ name: foo EXPECT_CALL(*listener_foo2, onDestroy()); } -TEST_F(ListenerManagerImplTest, AddClosedDrainingListener) { +TEST_P(ListenerManagerImplTest, AddClosedDrainingListener) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -1686,7 +1685,7 @@ name: foo ListenerHandle* listener_foo = expectListenerCreate(false, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(*worker_, addListener(_, _, _, _)); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); worker_->callAddCompletion(); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); @@ -1704,7 +1703,7 @@ name: foo ListenerHandle* listener_foo2 = expectListenerCreate(false, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(*worker_, addListener(_, _, _, _)); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); worker_->callAddCompletion(); checkStats(__LINE__, 2, 0, 1, 0, 1, 1, 0); @@ -1715,7 +1714,7 @@ name: foo EXPECT_CALL(*listener_foo2, onDestroy()); } -TEST_F(ListenerManagerImplTest, BindToPortEqualToFalse) { +TEST_P(ListenerManagerImplTest, BindToPortEqualToFalse) { InSequence s; auto mock_interface = std::make_unique( std::vector{Network::Address::IpVersion::v4}); @@ -1752,10 +1751,10 @@ bind_to_port: false })); EXPECT_CALL(listener_foo->target_, initialize()); EXPECT_CALL(*listener_foo, onDestroy()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); } -TEST_F(ListenerManagerImplTest, UpdateBindToPortEqualToFalse) { +TEST_P(ListenerManagerImplTest, UpdateBindToPortEqualToFalse) { InSequence s; auto mock_interface = std::make_unique( std::vector{Network::Address::IpVersion::v4}); @@ -1791,7 +1790,7 @@ bind_to_port: false address, socket_type, options, bind_type, creation_options, worker_index); })); EXPECT_CALL(*worker_, addListener(_, _, _, _)); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); worker_->callAddCompletion(); @@ -1811,7 +1810,7 @@ bind_to_port: false worker_->callRemovalCompletion(); } -TEST_F(ListenerManagerImplTest, DEPRECATED_FEATURE_TEST(DeprecatedBindToPortEqualToFalse)) { +TEST_P(ListenerManagerImplTest, DEPRECATED_FEATURE_TEST(DeprecatedBindToPortEqualToFalse)) { InSequence s; ProdListenerComponentFactory real_listener_factory(server_); EXPECT_CALL(*worker_, start(_, _)); @@ -1850,10 +1849,10 @@ name: foo })); EXPECT_CALL(listener_foo->target_, initialize()); EXPECT_CALL(*listener_foo, onDestroy()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); } -TEST_F(ListenerManagerImplTest, ReusePortEqualToTrue) { +TEST_P(ListenerManagerImplTest, ReusePortEqualToTrue) { InSequence s; ProdListenerComponentFactory real_listener_factory(server_); EXPECT_CALL(*worker_, start(_, _)); @@ -1896,10 +1895,10 @@ name: foo })); EXPECT_CALL(listener_foo->target_, initialize()); EXPECT_CALL(*listener_foo, onDestroy()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); } -TEST_F(ListenerManagerImplTest, NotSupportedDatagramUds) { +TEST_P(ListenerManagerImplTest, NotSupportedDatagramUds) { ProdListenerComponentFactory real_listener_factory(server_); EXPECT_THROW_WITH_MESSAGE(real_listener_factory.createListenSocket( std::make_shared("/foo"), @@ -1908,7 +1907,7 @@ TEST_F(ListenerManagerImplTest, NotSupportedDatagramUds) { "socket type SocketType::Datagram not supported for pipes"); } -TEST_F(ListenerManagerImplTest, CantListen) { +TEST_P(ListenerManagerImplTest, CantListen) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -1927,7 +1926,7 @@ name: foo ListenerHandle* listener_foo = expectListenerCreate(true, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(listener_foo->target_, initialize()); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml)); EXPECT_CALL(*listener_factory_.socket_->io_handle_, listen(_)) .WillOnce(Return(Api::SysCallIntResult{-1, 100})); @@ -1939,7 +1938,7 @@ name: foo server_.stats_store_.counterFromString("listener_manager.listener_create_failure").value()); } -TEST_F(ListenerManagerImplTest, CantBindSocket) { +TEST_P(ListenerManagerImplTest, CantBindSocket) { time_system_.setSystemTime(std::chrono::milliseconds(1001001001001)); InSequence s; @@ -1962,8 +1961,7 @@ enable_reuse_port: false createListenSocket(_, _, _, ListenerComponentFactory::BindType::NoReusePort, _, 0)) .WillOnce(Throw(EnvoyException("can't bind"))); EXPECT_CALL(*listener_foo, onDestroy()); - EXPECT_THROW(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true), - EnvoyException); + EXPECT_THROW(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml)), EnvoyException); EXPECT_EQ( 1UL, server_.stats_store_.counterFromString("listener_manager.listener_create_failure").value()); @@ -1998,7 +1996,7 @@ enable_reuse_port: false } // Verify that errors tracked on endListenerUpdate show up in the config dump/ -TEST_F(ListenerManagerImplTest, ConfigDumpWithExternalError) { +TEST_P(ListenerManagerImplTest, ConfigDumpWithExternalError) { time_system_.setSystemTime(std::chrono::milliseconds(1001001001001)); InSequence s; @@ -2035,7 +2033,7 @@ TEST_F(ListenerManagerImplTest, ConfigDumpWithExternalError) { )EOF"); } -TEST_F(ListenerManagerImplTest, ListenerDraining) { +TEST_P(ListenerManagerImplTest, ListenerDraining) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -2054,7 +2052,7 @@ name: foo ListenerHandle* listener_foo = expectListenerCreate(false, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(*worker_, addListener(_, _, _, _)); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); worker_->callAddCompletion(); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); @@ -2085,7 +2083,7 @@ name: foo checkStats(__LINE__, 1, 0, 1, 0, 0, 0, 0); } -TEST_F(ListenerManagerImplTest, RemoveListener) { +TEST_P(ListenerManagerImplTest, RemoveListener) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -2108,7 +2106,7 @@ name: foo ListenerHandle* listener_foo = expectListenerCreate(true, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(listener_foo->target_, initialize()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); EXPECT_EQ(0UL, manager_->listeners().size()); checkStats(__LINE__, 1, 0, 0, 1, 0, 0, 0); @@ -2122,7 +2120,7 @@ name: foo listener_foo = expectListenerCreate(true, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(listener_foo->target_, initialize()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); checkStats(__LINE__, 2, 0, 1, 1, 0, 0, 0); EXPECT_CALL(*worker_, addListener(_, _, _, _)); listener_foo->target_.ready(); @@ -2145,8 +2143,7 @@ per_connection_buffer_limit_bytes: 999 ListenerHandle* listener_foo_update1 = expectListenerCreate(true, true); EXPECT_CALL(*listener_factory_.socket_, duplicate()); EXPECT_CALL(listener_foo_update1->target_, initialize()); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml))); EXPECT_EQ(1UL, manager_->listeners().size()); checkStats(__LINE__, 2, 1, 1, 1, 1, 0, 0); @@ -2168,7 +2165,7 @@ per_connection_buffer_limit_bytes: 999 // Validates that StopListener functionality works correctly when only inbound listeners are // stopped. -TEST_F(ListenerManagerImplTest, StopListeners) { +TEST_P(ListenerManagerImplTest, StopListeners) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -2190,7 +2187,7 @@ traffic_direction: INBOUND EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(listener_foo->target_, initialize()); auto foo_inbound_proto = parseListenerFromV3Yaml(listener_foo_yaml); - EXPECT_TRUE(manager_->addOrUpdateListener(foo_inbound_proto, "", true)); + EXPECT_TRUE(addOrUpdateListener(foo_inbound_proto)); checkStats(__LINE__, 1, 0, 0, 1, 0, 0, 0); EXPECT_CALL(*worker_, addListener(_, _, _, _)); listener_foo->target_.ready(); @@ -2213,8 +2210,7 @@ traffic_direction: OUTBOUND ListenerHandle* listener_foo_outbound = expectListenerCreate(true, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(listener_foo_outbound->target_, initialize()); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_outbound_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_outbound_yaml))); EXPECT_CALL(*worker_, addListener(_, _, _, _)); listener_foo_outbound->target_.ready(); worker_->callAddCompletion(); @@ -2241,8 +2237,7 @@ traffic_direction: OUTBOUND ListenerHandle* listener_bar_outbound = expectListenerCreate(false, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(*worker_, addListener(_, _, _, _)); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_bar_outbound_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_bar_outbound_yaml))); EXPECT_EQ(3UL, manager_->listeners().size()); worker_->callAddCompletion(); @@ -2257,7 +2252,7 @@ traffic_direction: INBOUND filter_chains: - filters: [] )EOF"; - EXPECT_FALSE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_bar_yaml), "", true)); + EXPECT_FALSE(addOrUpdateListener(parseListenerFromV3Yaml(listener_bar_yaml))); // Explicitly validate that in place filter chain update is not allowed. auto in_place_foo_inbound_proto = foo_inbound_proto; @@ -2266,14 +2261,14 @@ traffic_direction: INBOUND ->mutable_destination_port() ->set_value(9999); - EXPECT_FALSE(manager_->addOrUpdateListener(in_place_foo_inbound_proto, "", true)); + EXPECT_FALSE(addOrUpdateListener(in_place_foo_inbound_proto)); EXPECT_CALL(*listener_foo, onDestroy()); EXPECT_CALL(*listener_foo_outbound, onDestroy()); EXPECT_CALL(*listener_bar_outbound, onDestroy()); } // Validates that StopListener functionality works correctly when all listeners are stopped. -TEST_F(ListenerManagerImplTest, StopAllListeners) { +TEST_P(ListenerManagerImplTest, StopAllListeners) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -2293,7 +2288,7 @@ name: foo ListenerHandle* listener_foo = expectListenerCreate(true, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(listener_foo->target_, initialize()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); checkStats(__LINE__, 1, 0, 0, 1, 0, 0, 0); EXPECT_CALL(*worker_, addListener(_, _, _, _)); listener_foo->target_.ready(); @@ -2317,11 +2312,11 @@ name: bar filter_chains: - filters: [] )EOF"; - EXPECT_FALSE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_bar_yaml), "", true)); + EXPECT_FALSE(addOrUpdateListener(parseListenerFromV3Yaml(listener_bar_yaml))); } // Validate that stopping a warming listener, removes directly from warming listener list. -TEST_F(ListenerManagerImplTest, StopWarmingListener) { +TEST_P(ListenerManagerImplTest, StopWarmingListener) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -2342,7 +2337,7 @@ traffic_direction: INBOUND ListenerHandle* listener_foo = expectListenerCreate(true, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(listener_foo->target_, initialize()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); checkStats(__LINE__, 1, 0, 0, 1, 0, 0, 0); EXPECT_CALL(*worker_, addListener(_, _, _, _)); listener_foo->target_.ready(); @@ -2366,8 +2361,7 @@ per_connection_buffer_limit_bytes: 999 ListenerHandle* listener_foo_update1 = expectListenerCreate(true, true); EXPECT_CALL(*listener_factory_.socket_, duplicate()); EXPECT_CALL(listener_foo_update1->target_, initialize()); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml))); EXPECT_EQ(1UL, manager_->listeners().size()); // Stop foo which should remove warming listener. @@ -2379,7 +2373,7 @@ per_connection_buffer_limit_bytes: 999 EXPECT_EQ(1, server_.stats_store_.counterFromString("listener_manager.listener_stopped").value()); } -TEST_F(ListenerManagerImplTest, StatsNameValidCharacterTest) { +TEST_P(ListenerManagerImplTest, StatsNameValidCharacterTest) { const std::string yaml = R"EOF( address: socket_address: @@ -2389,13 +2383,13 @@ TEST_F(ListenerManagerImplTest, StatsNameValidCharacterTest) { - filters: [] )EOF"; - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); manager_->listeners().front().get().listenerScope().counterFromString("foo").inc(); EXPECT_EQ(1UL, server_.stats_store_.counterFromString("listener.[__1]_10000.foo").value()); } -TEST_F(ListenerManagerImplTest, ListenerStatPrefix) { +TEST_P(ListenerManagerImplTest, ListenerStatPrefix) { const std::string yaml = R"EOF( stat_prefix: test_prefix address: @@ -2406,13 +2400,13 @@ stat_prefix: test_prefix - filters: [] )EOF"; - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); manager_->listeners().front().get().listenerScope().counterFromString("foo").inc(); EXPECT_EQ(1UL, server_.stats_store_.counterFromString("listener.test_prefix.foo").value()); } -TEST_F(ListenerManagerImplTest, DuplicateAddressDontBind) { +TEST_P(ListenerManagerImplTest, DuplicateAddressDontBind) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -2434,7 +2428,7 @@ bind_to_port: false EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, ListenerComponentFactory::BindType::NoBind, _, 0)); EXPECT_CALL(listener_foo->target_, initialize()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); // Add bar with same non-binding address. Should fail. const std::string listener_bar_yaml = R"EOF( @@ -2451,8 +2445,7 @@ bind_to_port: false ListenerHandle* listener_bar = expectListenerCreate(true, true); EXPECT_CALL(*listener_bar, onDestroy()); EXPECT_THROW_WITH_MESSAGE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_bar_yaml), "", true), - EnvoyException, + addOrUpdateListener(parseListenerFromV3Yaml(listener_bar_yaml)), EnvoyException, "error adding listener: 'bar' has duplicate address '0.0.0.0:1234' as existing listener"); // Move foo to active and then try to add again. This should still fail. @@ -2463,14 +2456,13 @@ bind_to_port: false listener_bar = expectListenerCreate(true, true); EXPECT_CALL(*listener_bar, onDestroy()); EXPECT_THROW_WITH_MESSAGE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_bar_yaml), "", true), - EnvoyException, + addOrUpdateListener(parseListenerFromV3Yaml(listener_bar_yaml)), EnvoyException, "error adding listener: 'bar' has duplicate address '0.0.0.0:1234' as existing listener"); EXPECT_CALL(*listener_foo, onDestroy()); } -TEST_F(ListenerManagerImplTest, EarlyShutdown) { +TEST_P(ListenerManagerImplTest, EarlyShutdown) { // If stopWorkers is called before the workers are started, it should be a no-op: they should be // neither started nor stopped. EXPECT_CALL(*worker_, start(_, _)).Times(0); @@ -2478,8 +2470,8 @@ TEST_F(ListenerManagerImplTest, EarlyShutdown) { manager_->stopWorkers(); } -TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDestinationPortMatch) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDestinationPortMatch) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: @@ -2487,6 +2479,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDestinationP filter_chains: - filter_chain_match: destination_port: 8080 + name: foo transport_socket: name: tls typed_config: @@ -2496,11 +2489,29 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDestinationP - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_cert.pem" } private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (matcher_) { + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: port + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput + exact_match_map: + map: + "8080": + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); // IPv4 client connects to unknown port - no match. @@ -2523,8 +2534,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDestinationP EXPECT_EQ(filter_chain, nullptr); } -TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDirectSourceIPMatch) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDirectSourceIPMatch) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: @@ -2533,6 +2544,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDirectSource filter_chains: - filter_chain_match: direct_source_prefix_ranges: { address_prefix: 127.0.0.0, prefix_len: 8 } + name: foo transport_socket: name: tls typed_config: @@ -2542,11 +2554,35 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDirectSource - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_cert.pem" } private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (matcher_) { + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: ip + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DirectSourceIPInput + custom_match: + name: ip-matcher + typed_config: + "@type": type.googleapis.com/xds.type.matcher.v3.IPMatcher + range_matchers: + - ranges: + - address_prefix: 127.0.0.0 + prefix_len: 8 + on_match: + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); // IPv4 client connects to unknown IP - no match. @@ -2569,8 +2605,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDirectSource EXPECT_EQ(filter_chain, nullptr); } -TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDestinationIPMatch) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDestinationIPMatch) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: @@ -2578,6 +2614,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDestinationI filter_chains: - filter_chain_match: prefix_ranges: { address_prefix: 127.0.0.0, prefix_len: 8 } + name: foo transport_socket: name: tls typed_config: @@ -2587,11 +2624,35 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDestinationI - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_cert.pem" } private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (matcher_) { + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: ip + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationIPInput + custom_match: + name: ip-matcher + typed_config: + "@type": type.googleapis.com/xds.type.matcher.v3.IPMatcher + range_matchers: + - ranges: + - address_prefix: 127.0.0.0 + prefix_len: 8 + on_match: + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); // IPv4 client connects to unknown IP - no match. @@ -2614,8 +2675,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDestinationI EXPECT_EQ(filter_chain, nullptr); } -TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithServerNamesMatch) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithServerNamesMatch) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: @@ -2623,6 +2684,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithServerNamesM filter_chains: - filter_chain_match: server_names: "server1.example.com" + name: foo transport_socket: name: tls typed_config: @@ -2632,11 +2694,29 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithServerNamesM - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_cert.pem" } private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (matcher_) { + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: ip + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.ServerNameInput + exact_match_map: + map: + "server1.example.com": + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); // TLS client without SNI - no match. @@ -2660,8 +2740,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithServerNamesM EXPECT_EQ(server_names.front(), "server1.example.com"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithTransportProtocolMatch) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithTransportProtocolMatch) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: @@ -2669,6 +2749,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithTransportPro filter_chains: - filter_chain_match: transport_protocol: "tls" + name: foo transport_socket: name: tls typed_config: @@ -2678,11 +2759,29 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithTransportPro - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_cert.pem" } private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (matcher_) { + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: transport + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.TransportProtocolInput + exact_match_map: + map: + "tls": + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); // TCP client - no match. @@ -2701,8 +2800,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithTransportPro EXPECT_EQ(server_names.front(), "server1.example.com"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithApplicationProtocolMatch) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithApplicationProtocolMatch) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: @@ -2711,6 +2810,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithApplicationP - filter_chain_match: application_protocols: "http/1.1" source_type: ANY + name: foo transport_socket: name: tls typed_config: @@ -2720,11 +2820,30 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithApplicationP - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_cert.pem" } private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (matcher_) { + // TODO(kyessenov) Switch to using prefix/suffix/containment matching for ALPN. + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: application + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.ApplicationProtocolInput + exact_match_map: + map: + "'h2','http/1.1'": + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); // TLS client without ALPN - no match. @@ -2747,8 +2866,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithApplicationP } // Define a source_type filter chain match and test against it. -TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceTypeMatch) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceTypeMatch) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: @@ -2756,6 +2875,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceTypeMa filter_chains: - filter_chain_match: source_type: SAME_IP_OR_LOOPBACK + name: foo transport_socket: name: tls typed_config: @@ -2765,11 +2885,29 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceTypeMa - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_cert.pem" } private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (matcher_) { + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: source-type + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.SourceTypeInput + exact_match_map: + map: + local: + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); // EXTERNAL IPv4 client without "http/1.1" ALPN - no match. @@ -2805,8 +2943,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceTypeMa } // Verify source IP matches. -TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceIpMatch) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceIpMatch) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: @@ -2816,6 +2954,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceIpMatc source_prefix_ranges: - address_prefix: 10.0.0.1 prefix_len: 24 + name: foo transport_socket: name: tls typed_config: @@ -2825,11 +2964,35 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceIpMatc - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_cert.pem" } private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (matcher_) { + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: ip + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.SourceIPInput + custom_match: + name: ip-matcher + typed_config: + "@type": type.googleapis.com/xds.type.matcher.v3.IPMatcher + range_matchers: + - ranges: + - address_prefix: 10.0.0.1 + prefix_len: 24 + on_match: + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); // IPv4 client with source 10.0.1.1. No match. @@ -2864,8 +3027,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceIpMatc } // Verify source IPv6 matches. -TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceIpv6Match) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceIpv6Match) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: @@ -2875,6 +3038,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceIpv6Ma source_prefix_ranges: - address_prefix: 2001:0db8:85a3:0000:0000:0000:0000:0000 prefix_len: 64 + name: foo transport_socket: name: tls typed_config: @@ -2884,11 +3048,35 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceIpv6Ma - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_cert.pem" } private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (matcher_) { + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: ip + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.SourceIPInput + custom_match: + name: ip-matcher + typed_config: + "@type": type.googleapis.com/xds.type.matcher.v3.IPMatcher + range_matchers: + - ranges: + - address_prefix: 2001:0db8:85a3:0000:0000:0000:0000:0000 + prefix_len: 64 + on_match: + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); // IPv6 client with matching subnet. Match. @@ -2903,8 +3091,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceIpv6Ma } // Verify source port matches. -TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourcePortMatch) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourcePortMatch) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: @@ -2913,6 +3101,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourcePortMa - filter_chain_match: source_ports: - 100 + name: foo transport_socket: name: tls typed_config: @@ -2922,11 +3111,29 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourcePortMa - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_cert.pem" } private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (matcher_) { + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: port + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.SourcePortInput + exact_match_map: + map: + "100": + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); // Client with source port 100. Match. @@ -2949,8 +3156,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourcePortMa } // Define multiple source_type filter chain matches and test against them. -TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainWithSourceTypeMatch) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithSourceTypeMatch) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: @@ -2958,6 +3165,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainWithSourceType filter_chains: - filter_chain_match: source_type: SAME_IP_OR_LOOPBACK + name: foo transport_socket: name: tls typed_config: @@ -2969,6 +3177,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainWithSourceType - filter_chain_match: application_protocols: "http/1.1" source_type: EXTERNAL + name: bar transport_socket: name: tls typed_config: @@ -2979,6 +3188,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainWithSourceType private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_uri_key.pem" } - filter_chain_match: source_type: ANY + name: baz transport_socket: name: tls typed_config: @@ -2988,11 +3198,66 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainWithSourceType - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_multiple_dns_cert.pem" } private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_multiple_dns_key.pem" } )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (matcher_) { + // TODO(kyessenov) Switch to using prefix/suffix/containment matching for ALPN. + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: source-type + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.SourceTypeInput + exact_match_map: + map: + local: + matcher: + matcher_tree: + input: + name: application + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.ApplicationProtocolInput + exact_match_map: + map: + "'h2','http/1.1'": + action: + name: none + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: none + on_no_match: + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + on_no_match: + matcher: + matcher_tree: + input: + name: application + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.ApplicationProtocolInput + exact_match_map: + map: + "'h2','http/1.1'": + action: + name: bar + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: bar + on_no_match: + action: + name: baz + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: baz + )EOF"; + } EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); // LOCAL TLS client with "http/1.1" ALPN - no match. @@ -3036,8 +3301,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainWithSourceType EXPECT_EQ(server_names.front(), "*.example.com"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinationPortMatch) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinationPortMatch) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: @@ -3045,6 +3310,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati filter_chains: - filter_chain_match: # empty + name: foo transport_socket: name: tls typed_config: @@ -3055,6 +3321,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_uri_key.pem" } - filter_chain_match: destination_port: 8080 + name: bar transport_socket: name: tls typed_config: @@ -3065,6 +3332,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } - filter_chain_match: destination_port: 8081 + name: baz transport_socket: name: tls typed_config: @@ -3074,11 +3342,41 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_multiple_dns_cert.pem" } private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_multiple_dns_key.pem" } )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (matcher_) { + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: port + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput + exact_match_map: + map: + "8080": + action: + name: bar + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: bar + "8081": + action: + name: baz + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: baz + on_no_match: + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); // IPv4 client connects to default port - using 1st filter chain. @@ -3121,8 +3419,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinationIPMatch) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinationIPMatch) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: @@ -3130,6 +3428,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati filter_chains: - filter_chain_match: # empty + name: foo transport_socket: name: tls typed_config: @@ -3140,6 +3439,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_uri_key.pem" } - filter_chain_match: prefix_ranges: { address_prefix: 192.168.0.1, prefix_len: 32 } + name: bar transport_socket: name: tls typed_config: @@ -3150,6 +3450,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } - filter_chain_match: prefix_ranges: { address_prefix: 192.168.0.0, prefix_len: 16 } + name: baz transport_socket: name: tls typed_config: @@ -3159,42 +3460,86 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_multiple_dns_cert.pem" } private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_multiple_dns_key.pem" } )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (matcher_) { + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: ip + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationIPInput + custom_match: + name: ip-matcher + typed_config: + "@type": type.googleapis.com/xds.type.matcher.v3.IPMatcher + range_matchers: + - ranges: + - address_prefix: 192.168.0.1 + prefix_len: 32 + on_match: + action: + name: bar + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: bar + - ranges: + - address_prefix: 192.168.0.0 + prefix_len: 16 + on_match: + action: + name: baz + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: baz + on_no_match: + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); - // UDS client connects - using 1st filter chain with no IP match - auto filter_chain = findFilterChain(1234, "127.0.0.1", "", "tls", {}, "127.0.0.1", 111); + // IPv4 client connects to exact IP match - using 2nd filter chain. + auto filter_chain = findFilterChain(1234, "192.168.0.1", "", "tls", {}, "127.0.0.1", 111); ASSERT_NE(filter_chain, nullptr); EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); auto transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); auto ssl_socket = dynamic_cast(transport_socket.get()); - auto uri = ssl_socket->ssl()->uriSanLocalCertificate(); - EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); - - // IPv4 client connects to default IP - using 1st filter chain. - filter_chain = findFilterChain(1234, "127.0.0.1", "", "tls", {}, "127.0.0.1", 111); - ASSERT_NE(filter_chain, nullptr); - EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); - transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); - ssl_socket = dynamic_cast(transport_socket.get()); - uri = ssl_socket->ssl()->uriSanLocalCertificate(); - EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); - - // IPv4 client connects to exact IP match - using 2nd filter chain. - filter_chain = findFilterChain(1234, "192.168.0.1", "", "tls", {}, "127.0.0.1", 111); - ASSERT_NE(filter_chain, nullptr); - EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); - transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); - ssl_socket = dynamic_cast(transport_socket.get()); auto server_names = ssl_socket->ssl()->dnsSansLocalCertificate(); EXPECT_EQ(server_names.size(), 1); EXPECT_EQ(server_names.front(), "server1.example.com"); + // UDS client connects - using 1st filter chain with no IP match + // TODO(kyessenov): Implement on_no_match for custom matchers. + if (!matcher_) { + filter_chain = findFilterChain(1234, "127.0.0.1", "", "tls", {}, "127.0.0.1", 111); + ASSERT_NE(filter_chain, nullptr); + EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); + transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); + ssl_socket = + dynamic_cast(transport_socket.get()); + auto uri = ssl_socket->ssl()->uriSanLocalCertificate(); + EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); + + // IPv4 client connects to default IP - using 1st filter chain. + filter_chain = findFilterChain(1234, "127.0.0.1", "", "tls", {}, "127.0.0.1", 111); + ASSERT_NE(filter_chain, nullptr); + EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); + transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); + ssl_socket = + dynamic_cast(transport_socket.get()); + uri = ssl_socket->ssl()->uriSanLocalCertificate(); + EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); + } + // IPv4 client connects to wildcard IP match - using 3rd filter chain. filter_chain = findFilterChain(1234, "192.168.1.1", "", "tls", {}, "192.168.1.1", 111); ASSERT_NE(filter_chain, nullptr); @@ -3206,17 +3551,21 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati EXPECT_EQ(server_names.front(), "*.example.com"); // UDS client - using 1st filter chain. - filter_chain = findFilterChain(0, "/tmp/test.sock", "", "tls", {}, "/tmp/test.sock", 111); - ASSERT_NE(filter_chain, nullptr); - EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); - transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); - ssl_socket = dynamic_cast(transport_socket.get()); - uri = ssl_socket->ssl()->uriSanLocalCertificate(); - EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); + // TODO(kyessenov): Implement on_no_match for custom matchers. + if (!matcher_) { + filter_chain = findFilterChain(0, "/tmp/test.sock", "", "tls", {}, "/tmp/test.sock", 111); + ASSERT_NE(filter_chain, nullptr); + EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); + transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); + ssl_socket = + dynamic_cast(transport_socket.get()); + auto uri = ssl_socket->ssl()->uriSanLocalCertificate(); + EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); + } } -TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDirectSourceIPMatch) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDirectSourceIPMatch) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: @@ -3225,6 +3574,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDirectSou filter_chains: - filter_chain_match: # empty + name: foo transport_socket: name: tls typed_config: @@ -3235,6 +3585,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDirectSou private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_uri_key.pem" } - filter_chain_match: direct_source_prefix_ranges: { address_prefix: 192.168.0.1, prefix_len: 32 } + name: bar transport_socket: name: tls typed_config: @@ -3245,6 +3596,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDirectSou private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } - filter_chain_match: direct_source_prefix_ranges: { address_prefix: 192.168.0.0, prefix_len: 16 } + name: baz transport_socket: name: tls typed_config: @@ -3254,38 +3606,60 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDirectSou - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_multiple_dns_cert.pem" } private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_multiple_dns_key.pem" } )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (matcher_) { + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: ip + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DirectSourceIPInput + custom_match: + name: ip-matcher + typed_config: + "@type": type.googleapis.com/xds.type.matcher.v3.IPMatcher + range_matchers: + - ranges: + - address_prefix: 192.168.0.1 + prefix_len: 32 + on_match: + action: + name: bar + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: bar + - ranges: + - address_prefix: 192.168.0.0 + prefix_len: 16 + on_match: + action: + name: baz + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: baz + on_no_match: + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); - // UDS client connects - using 1st filter chain with no IP match - auto filter_chain = findFilterChain(1234, "/uds_1", "", "tls", {}, "/uds_2", 111, "/uds_3"); + // IPv4 client connects to exact IP match - using 2nd filter chain. + auto filter_chain = + findFilterChain(1234, "127.0.0.1", "", "tls", {}, "127.0.0.1", 111, "192.168.0.1"); ASSERT_NE(filter_chain, nullptr); EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); auto transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); auto ssl_socket = dynamic_cast(transport_socket.get()); - auto uri = ssl_socket->ssl()->uriSanLocalCertificate(); - EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); - - // IPv4 client connects to default IP - using 1st filter chain. - filter_chain = findFilterChain(1234, "127.0.0.1", "", "tls", {}, "127.0.0.1", 111, "127.0.0.1"); - ASSERT_NE(filter_chain, nullptr); - EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); - transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); - ssl_socket = dynamic_cast(transport_socket.get()); - uri = ssl_socket->ssl()->uriSanLocalCertificate(); - EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); - - // IPv4 client connects to exact IP match - using 2nd filter chain. - filter_chain = findFilterChain(1234, "127.0.0.1", "", "tls", {}, "127.0.0.1", 111, "192.168.0.1"); - ASSERT_NE(filter_chain, nullptr); - EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); - transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); - ssl_socket = dynamic_cast(transport_socket.get()); auto server_names = ssl_socket->ssl()->dnsSansLocalCertificate(); EXPECT_EQ(server_names.size(), 1); EXPECT_EQ(server_names.front(), "server1.example.com"); @@ -3299,9 +3673,35 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDirectSou server_names = ssl_socket->ssl()->dnsSansLocalCertificate(); EXPECT_EQ(server_names.size(), 2); EXPECT_EQ(server_names.front(), "*.example.com"); + + // TODO(kyessenov): Implement on_no_match for custom matchers. + if (!matcher_) { + // UDS client connects - using 1st filter chain with no IP match + filter_chain = findFilterChain(1234, "/uds_1", "", "tls", {}, "/uds_2", 111, "/uds_3"); + ASSERT_NE(filter_chain, nullptr); + EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); + transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); + ssl_socket = + dynamic_cast(transport_socket.get()); + auto uri = ssl_socket->ssl()->uriSanLocalCertificate(); + EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); + + // IPv4 client connects to default IP - using 1st filter chain. + filter_chain = findFilterChain(1234, "127.0.0.1", "", "tls", {}, "127.0.0.1", 111, "127.0.0.1"); + ASSERT_NE(filter_chain, nullptr); + EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); + transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); + ssl_socket = + dynamic_cast(transport_socket.get()); + uri = ssl_socket->ssl()->uriSanLocalCertificate(); + EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); + } } -TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithServerNamesMatch) { +TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithServerNamesMatch) { + if (matcher_) { + GTEST_SKIP() << "Server name matching not implemented for unified matcher"; + } const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } @@ -3352,7 +3752,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithServerNam EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); // TLS client without SNI - using 1st filter chain. @@ -3399,8 +3799,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithServerNam EXPECT_EQ(server_names.front(), "*.example.com"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithTransportProtocolMatch) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithTransportProtocolMatch) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: @@ -3408,8 +3808,10 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithTransport filter_chains: - filter_chain_match: # empty + name: foo - filter_chain_match: transport_protocol: "tls" + name: bar transport_socket: name: tls typed_config: @@ -3419,11 +3821,35 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithTransport - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_cert.pem" } private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (matcher_) { + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: transport + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.TransportProtocolInput + exact_match_map: + map: + "tls": + action: + name: bar + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: bar + on_no_match: + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); // TCP client - using 1st filter chain. @@ -3443,7 +3869,10 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithTransport EXPECT_EQ(server_names.front(), "server1.example.com"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithApplicationProtocolMatch) { +TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithApplicationProtocolMatch) { + if (matcher_) { + GTEST_SKIP() << "ALPN list matching not implemented for unified matcher"; + } const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } @@ -3467,7 +3896,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithApplicati EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); // TLS client without ALPN - using 1st filter chain. @@ -3490,7 +3919,10 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithApplicati EXPECT_EQ(server_names.front(), "server1.example.com"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithMultipleRequirementsMatch) { +TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithMultipleRequirementsMatch) { + if (matcher_) { + GTEST_SKIP() << "ALPN list and server name matching not implemented for unified matcher"; + } const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } @@ -3516,7 +3948,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithMultipleR EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); // TLS client without SNI and ALPN - using 1st filter chain. @@ -3552,7 +3984,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithMultipleR EXPECT_EQ(server_names.front(), "server1.example.com"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDifferentSessionTicketKeys) { +TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDifferentSessionTicketKeys) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } @@ -3561,6 +3993,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDifferent filter_chains: - filter_chain_match: server_names: "example.com" + name: foo transport_socket: name: tls typed_config: @@ -3574,6 +4007,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDifferent - filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/ticket_key_a" - filter_chain_match: server_names: "www.example.com" + name: bar transport_socket: name: tls typed_config: @@ -3590,11 +4024,11 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDifferent EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, +TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithMixedUseOfSessionTicketKeys) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: @@ -3604,6 +4038,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, filter_chains: - filter_chain_match: server_names: "example.com" + name: foo transport_socket: name: tls typed_config: @@ -3617,6 +4052,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, - filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/ticket_key_a" - filter_chain_match: server_names: "www.example.com" + name: bar transport_socket: name: tls typed_config: @@ -3630,12 +4066,12 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithInvalidDestinationIPMatch) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithInvalidDestinationIPMatch) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: @@ -3643,14 +4079,43 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithInvalidDesti filter_chains: - filter_chain_match: prefix_ranges: { address_prefix: a.b.c.d, prefix_len: 32 } + name: foo )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, "malformed IP address: a.b.c.d"); + if (matcher_) { + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: ip + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationIPInput + custom_match: + name: ip-matcher + typed_config: + "@type": type.googleapis.com/xds.type.matcher.v3.IPMatcher + range_matchers: + - ranges: + - address_prefix: a.b.c.d + prefix_len: 32 + on_match: + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } + + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, + "malformed IP address: a.b.c.d"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithInvalidServerNamesMatch) { +TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithInvalidServerNamesMatch) { + if (matcher_) { + GTEST_SKIP() << "Server name matching not implemented for unified matcher"; + } const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } @@ -3662,13 +4127,15 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithInvalidServe )EOF", Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "error adding listener '127.0.0.1:1234': partial wildcards are not " "supported in \"server_names\""); } -TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithSameMatch) { +TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithSameMatch) { + if (matcher_) { + GTEST_SKIP() << "Unified matcher allows duplicated or missing filter chain match messages"; + } const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } @@ -3684,13 +4151,12 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithSameMatch )EOF", Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "error adding listener '127.0.0.1:1234': filter chain 'bar' has " "the same matching rules defined as 'foo'"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, +TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithSameMatchPlusUnimplementedFields) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: @@ -3709,11 +4175,14 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, Network::Address::IpVersion::v4); EXPECT_THROW_WITH_MESSAGE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), EnvoyException, + addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "error adding listener '127.0.0.1:1234': filter chain 'bar' contains unimplemented fields"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithOverlappingRules) { +TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithOverlappingRules) { + if (matcher_) { + GTEST_SKIP() << "Unified matcher ignores filter chain match messages"; + } const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } @@ -3727,13 +4196,12 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithOverlappi )EOF", Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "error adding listener '127.0.0.1:1234': multiple filter chains with " "overlapping matching rules are defined"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, MatcherFilterChainWithoutName) { +TEST_P(ListenerManagerImplWithRealFiltersTest, MatcherFilterChainWithoutName) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } @@ -3758,13 +4226,12 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MatcherFilterChainWithoutName) { )EOF", Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "error adding listener '127.0.0.1:1234': \"name\" field is required " "when using a listener matcher"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, MatcherFilterChainWithDuplicateName) { +TEST_P(ListenerManagerImplWithRealFiltersTest, MatcherFilterChainWithDuplicateName) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } @@ -3792,13 +4259,12 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MatcherFilterChainWithDuplicateNa )EOF", Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "error adding listener '127.0.0.1:1234': \"name\" field is duplicated " "with value 'foo'"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInline) { +TEST_P(ListenerManagerImplWithRealFiltersTest, TlsCertificateInline) { const std::string cert = TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns3_chain.pem")); const std::string pkey = TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( @@ -3809,7 +4275,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInline) { address: socket_address: { address: 127.0.0.1, port_value: 1234 } filter_chains: - - transport_socket: + - name: foo + transport_socket: name: tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext @@ -3826,18 +4293,19 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInline) { EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateChainInlinePrivateKeyFilename) { +TEST_P(ListenerManagerImplWithRealFiltersTest, TlsCertificateChainInlinePrivateKeyFilename) { const std::string cert = TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns3_chain.pem")); const std::string yaml = TestEnvironment::substitute(absl::StrCat(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } filter_chains: - - transport_socket: + - name: foo + transport_socket: name: tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext @@ -3851,16 +4319,17 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateChainInlinePrivateK EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateIncomplete) { +TEST_P(ListenerManagerImplWithRealFiltersTest, TlsCertificateIncomplete) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } filter_chains: - - transport_socket: + - name: foo + transport_socket: name: tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext @@ -3870,16 +4339,17 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateIncomplete) { )EOF", Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, "Failed to load incomplete private key from path: "); + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, + "Failed to load incomplete private key from path: "); } -TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidCertificateChain) { +TEST_P(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidCertificateChain) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } filter_chains: - - transport_socket: + - name: foo + transport_socket: name: tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext @@ -3890,11 +4360,11 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidCertificateC )EOF", Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, "Failed to load certificate chain from "); + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, + "Failed to load certificate chain from "); } -TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidIntermediateCA) { +TEST_P(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidIntermediateCA) { const std::string leaf = TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns3_cert.pem")); const std::string yaml = TestEnvironment::substitute( @@ -3903,7 +4373,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidIntermediate address: socket_address: { address: 127.0.0.1, port_value: 1234 } filter_chains: - - transport_socket: + - name: foo + transport_socket: name: tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext @@ -3916,16 +4387,17 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidIntermediate )EOF"), Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, "Failed to load certificate chain from "); + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, + "Failed to load certificate chain from "); } -TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidPrivateKey) { +TEST_P(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidPrivateKey) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } filter_chains: - - transport_socket: + - name: foo + transport_socket: name: tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext @@ -3936,18 +4408,18 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidPrivateKey) )EOF", Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "Failed to load private key from , " "Cause: error:0900006e:PEM routines:OPENSSL_internal:NO_START_LINE"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidTrustedCA) { +TEST_P(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidTrustedCA) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } filter_chains: - - transport_socket: + - name: foo + transport_socket: name: tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext @@ -3960,16 +4432,17 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidTrustedCA) { )EOF", Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, "Failed to load trusted CA certificates from "); + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, + "Failed to load trusted CA certificates from "); } -TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateCertPrivateKeyMismatch) { +TEST_P(ListenerManagerImplWithRealFiltersTest, TlsCertificateCertPrivateKeyMismatch) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } filter_chains: - - transport_socket: + - name: foo + transport_socket: name: tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext @@ -3981,12 +4454,12 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateCertPrivateKeyMisma Network::Address::IpVersion::v4); EXPECT_THROW_WITH_REGEX( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), EnvoyException, + addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "Failed to load private key from .*, " "Cause: error:0b000074:X.509 certificate routines:OPENSSL_internal:KEY_VALUES_MISMATCH"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, Metadata) { +TEST_P(ListenerManagerImplWithRealFiltersTest, Metadata) { #ifdef SOL_IP const std::string yaml = TestEnvironment::substitute(R"EOF( address: @@ -3995,6 +4468,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, Metadata) { traffic_direction: INBOUND filter_chains: - filter_chain_match: + name: foo filters: - name: http typed_config: @@ -4024,7 +4498,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, Metadata) { return ProdListenerComponentFactory::createListenerFilterFactoryList_(filters, context); })); server_.server_factory_context_->cluster_manager_.initializeClusters({"service_foo"}, {}); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); ASSERT_NE(nullptr, listener_factory_context); EXPECT_EQ("test_value", Config::Metadata::metadataValue( &listener_factory_context->listenerMetadata(), "com.bar.foo", "baz") @@ -4033,7 +4507,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, Metadata) { #endif } -TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstFilterWin32NoTrafficDirection) { +TEST_P(ListenerManagerImplWithRealFiltersTest, OriginalDstFilterWin32NoTrafficDirection) { #ifdef WIN32 const std::string yaml = TestEnvironment::substitute(R"EOF( address: @@ -4044,7 +4518,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstFilterWin32NoTrafficDi )EOF", Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)); , EnvoyException, "[Windows] Setting original destination filter on a listener without " "specifying the traffic_direction." @@ -4052,7 +4526,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstFilterWin32NoTrafficDi #endif } -TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstFilterWin32NoFeatureSupport) { +TEST_P(ListenerManagerImplWithRealFiltersTest, OriginalDstFilterWin32NoFeatureSupport) { #if defined(WIN32) && !defined(SOL_IP) const std::string yaml = TestEnvironment::substitute(R"EOF( address: @@ -4063,19 +4537,21 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstFilterWin32NoFeatureSu - name: "envoy.filters.listener.original_dst" )EOF", Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)); , EnvoyException, "[Windows] Envoy was compiled without support for `SO_ORIGINAL_DST`, " "the original destination filter cannot be used"); #endif } -TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstFilter) { +TEST_P(ListenerManagerImplWithRealFiltersTest, OriginalDstFilter) { #ifdef SOL_IP const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1111 } - filter_chains: {} + filter_chains: + - filters: [] + name: foo traffic_direction: INBOUND listener_filters: - name: "envoy.filters.listener.original_dst" @@ -4083,7 +4559,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstFilter) { Network::Address::IpVersion::v4); EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); Network::ListenerConfig& listener = manager_->listeners().back().get(); @@ -4150,7 +4626,7 @@ class OriginalDstTestConfigFactory : public Configuration::NamedListenerFilterCo std::string name() const override { return "test.listener.original_dst"; } }; -TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterOutbound) { +TEST_P(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterOutbound) { #ifdef SOL_IP OriginalDstTestConfigFactory factory; Registry::InjectFactory registration(factory); @@ -4158,7 +4634,9 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterOutbound) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1111 } - filter_chains: {} + filter_chains: + - filters: [] + name: foo traffic_direction: OUTBOUND listener_filters: - name: "test.listener.original_dst" @@ -4167,7 +4645,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterOutbound) { EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); Network::ListenerConfig& listener = manager_->listeners().back().get(); @@ -4205,7 +4683,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterOutbound) { #endif } -TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstFilterStopsIteration) { +TEST_P(ListenerManagerImplWithRealFiltersTest, OriginalDstFilterStopsIteration) { #if defined(WIN32) && defined(SOL_IP) OriginalDstTestConfigFactory factory; Registry::InjectFactory registration(factory); @@ -4213,7 +4691,9 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstFilterStopsIteration) const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1111 } - filter_chains: {} + filter_chains: + - filters: [] + name: foo traffic_direction: OUTBOUND listener_filters: - name: "test.listener.original_dst" @@ -4222,7 +4702,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstFilterStopsIteration) EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); Network::ListenerConfig& listener = manager_->listeners().back().get(); @@ -4255,7 +4735,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstFilterStopsIteration) #endif } -TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterInbound) { +TEST_P(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterInbound) { #ifdef SOL_IP OriginalDstTestConfigFactory factory; Registry::InjectFactory registration(factory); @@ -4263,7 +4743,9 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterInbound) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1111 } - filter_chains: {} + filter_chains: + - filters: [] + name: foo traffic_direction: INBOUND listener_filters: - name: "test.listener.original_dst" @@ -4272,7 +4754,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterInbound) { EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); Network::ListenerConfig& listener = manager_->listeners().back().get(); @@ -4315,7 +4797,7 @@ class OriginalDstTestFilterIPv6 } }; -TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterIPv6) { +TEST_P(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterIPv6) { class OriginalDstTestConfigFactory : public Configuration::NamedListenerFilterConfigFactory { public: // NamedListenerFilterConfigFactory @@ -4345,7 +4827,9 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterIPv6) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: ::0001, port_value: 1111 } - filter_chains: {} + filter_chains: + - filters: [] + name: foo listener_filters: - name: "test.listener.original_dstipv6" )EOF", @@ -4353,7 +4837,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterIPv6) { EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); Network::ListenerConfig& listener = manager_->listeners().back().get(); @@ -4384,7 +4868,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilterIPv6) { // Validate that when neither transparent nor freebind is not set in the // Listener, we see no socket option set. -TEST_F(ListenerManagerImplWithRealFiltersTest, TransparentFreebindListenerDisabled) { +TEST_P(ListenerManagerImplWithRealFiltersTest, TransparentFreebindListenerDisabled) { const std::string yaml = TestEnvironment::substitute(R"EOF( name: "TestListener" address: @@ -4393,7 +4877,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TransparentFreebindListenerDisabl freebind: false enable_reuse_port: false filter_chains: - - filters: + - filters: [] + name: foo )EOF", Network::Address::IpVersion::v4); EXPECT_CALL(listener_factory_, @@ -4405,7 +4890,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TransparentFreebindListenerDisabl EXPECT_EQ(options, nullptr); return listener_factory_.socket_; })); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); } @@ -4415,7 +4900,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TransparentFreebindListenerDisabl // involving the network stack. We only test the IPv4 case here, as the logic // around IPv4/IPv6 handling is tested generically in // socket_option_impl_test.cc. -TEST_F(ListenerManagerImplWithRealFiltersTest, TransparentListenerEnabled) { +TEST_P(ListenerManagerImplWithRealFiltersTest, TransparentListenerEnabled) { auto listener = createIPv4Listener("TransparentListener"); listener.mutable_transparent()->set_value(true); listener.mutable_enable_reuse_port()->set_value(false); @@ -4430,7 +4915,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, TransparentListenerEnabled) { // involving the network stack. We only test the IPv4 case here, as the logic // around IPv4/IPv6 handling is tested generically in // socket_option_impl_test.cc. -TEST_F(ListenerManagerImplWithRealFiltersTest, FreebindListenerEnabled) { +TEST_P(ListenerManagerImplWithRealFiltersTest, FreebindListenerEnabled) { auto listener = createIPv4Listener("FreebindListener"); listener.mutable_freebind()->set_value(true); listener.mutable_enable_reuse_port()->set_value(false); @@ -4445,7 +4930,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, FreebindListenerEnabled) { // involving the network stack. We only test the IPv4 case here, as the logic // around IPv4/IPv6 handling is tested generically in // socket_option_impl_test.cc. -TEST_F(ListenerManagerImplWithRealFiltersTest, FastOpenListenerEnabled) { +TEST_P(ListenerManagerImplWithRealFiltersTest, FastOpenListenerEnabled) { auto listener = createIPv4Listener("FastOpenListener"); listener.mutable_tcp_fast_open_queue_length()->set_value(1); listener.mutable_enable_reuse_port()->set_value(false); @@ -4456,7 +4941,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, FastOpenListenerEnabled) { // Validate that when reuse_port is set in the Listener, we see the socket option // propagated to setsockopt(). -TEST_F(ListenerManagerImplWithRealFiltersTest, ReusePortListenerEnabledForTcp) { +TEST_P(ListenerManagerImplWithRealFiltersTest, ReusePortListenerEnabledForTcp) { auto listener = createIPv4Listener("ReusePortListener"); // When reuse_port is true, port should be 0 for creating the shared socket, // otherwise socket creation will be done on worker thread. @@ -4468,7 +4953,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, ReusePortListenerEnabledForTcp) { } } -TEST_F(ListenerManagerImplWithRealFiltersTest, ReusePortListenerDisabled) { +TEST_P(ListenerManagerImplWithRealFiltersTest, ReusePortListenerDisabled) { auto listener = createIPv4Listener("UdpListener"); listener.mutable_address()->mutable_socket_address()->set_protocol( envoy::config::core::v3::SocketAddress::UDP); @@ -4476,7 +4961,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, ReusePortListenerDisabled) { listener.mutable_enable_reuse_port()->set_value(false); server_.options_.concurrency_ = 2; - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(listener, "", true), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(listener), EnvoyException, "Listening on UDP when concurrency is > 1 without the SO_REUSEPORT " "socket option results in " "unstable packet proxying. Configure the reuse_port listener option " @@ -4484,14 +4969,15 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, ReusePortListenerDisabled) { EXPECT_EQ(0, manager_->listeners().size()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, LiteralSockoptListenerEnabled) { +TEST_P(ListenerManagerImplWithRealFiltersTest, LiteralSockoptListenerEnabled) { const envoy::config::listener::v3::Listener listener = parseListenerFromV3Yaml(R"EOF( name: SockoptsListener address: socket_address: { address: 127.0.0.1, port_value: 1111 } enable_reuse_port: false filter_chains: - - filters: + - filters: [] + name: foo socket_options: [ # The socket goes through socket() and bind() but never listen(), so if we # ever saw (7, 8, 9) being applied it would cause a EXPECT_CALL failure. @@ -4512,13 +4998,13 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, LiteralSockoptListenerEnabled) { /* expected_sockopt_level */ 4, /* expected_sockopt_name */ 5, /* expected_value */ 6); - manager_->addOrUpdateListener(listener, "", true); + addOrUpdateListener(listener); EXPECT_EQ(1U, manager_->listeners().size()); } // This test relies on linux-only code, and a linux-only name IPPROTO_MPTCP #if defined(__linux__) -TEST_F(ListenerManagerImplWithRealFiltersTest, Mptcp) { +TEST_P(ListenerManagerImplWithRealFiltersTest, Mptcp) { envoy::config::listener::v3::Listener listener = parseListenerFromV3Yaml(R"EOF( name: mptcp-udp enable_mptcp: true @@ -4527,7 +5013,8 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, Mptcp) { address: 127.0.0.1 port_value: 1111 filter_chains: - - filters: + - filters: [] + name: foo )EOF"); ListenerHandle* listener_foo = expectListenerCreate(false, true); @@ -4562,13 +5049,13 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, Mptcp) { address, socket_type, options, bind_type, creation_options, worker_index); })); - EXPECT_TRUE(manager_->addOrUpdateListener(listener, "", true)); + EXPECT_TRUE(addOrUpdateListener(listener)); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); EXPECT_CALL(*listener_foo, onDestroy()); } #endif -TEST_F(ListenerManagerImplWithRealFiltersTest, MptcpOnUdp) { +TEST_P(ListenerManagerImplWithRealFiltersTest, MptcpOnUdp) { envoy::config::listener::v3::Listener listener = parseListenerFromV3Yaml(R"EOF( name: mptcp-udp enable_mptcp: true @@ -4578,13 +5065,14 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MptcpOnUdp) { port_value: 1111 protocol: UDP filter_chains: - - filters: + - filters: [] + name: foo )EOF"); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(listener, "", true), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(listener), EnvoyException, "listener mptcp-udp: enable_mptcp can only be used with TCP listeners"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, MptcpOnUnixDomainSocket) { +TEST_P(ListenerManagerImplWithRealFiltersTest, MptcpOnUnixDomainSocket) { envoy::config::listener::v3::Listener listener = parseListenerFromV3Yaml(R"EOF( name: mptcp-udp enable_mptcp: true @@ -4592,13 +5080,14 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MptcpOnUnixDomainSocket) { pipe: path: /path filter_chains: - - filters: + - filters: [] + name: foo )EOF"); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(listener, "", true), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(listener), EnvoyException, "listener mptcp-udp: enable_mptcp can only be used with IP addresses"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, MptcpNotSupported) { +TEST_P(ListenerManagerImplWithRealFiltersTest, MptcpNotSupported) { envoy::config::listener::v3::Listener listener = parseListenerFromV3Yaml(R"EOF( name: mptcp-udp enable_mptcp: true @@ -4607,23 +5096,25 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MptcpNotSupported) { address: 127.0.0.1 port_value: 1111 filter_chains: - - filters: + - filters: [] + name: foo )EOF"); EXPECT_CALL(os_sys_calls_, supportsMptcp()).WillOnce(Return(false)); EXPECT_THROW_WITH_MESSAGE( - manager_->addOrUpdateListener(listener, "", true), EnvoyException, + addOrUpdateListener(listener), EnvoyException, "listener mptcp-udp: enable_mptcp is set but MPTCP is not supported by the operating system"); } // Set the resolver to the default IP resolver. The address resolver logic is unit tested in // resolver_impl_test.cc. -TEST_F(ListenerManagerImplWithRealFiltersTest, AddressResolver) { +TEST_P(ListenerManagerImplWithRealFiltersTest, AddressResolver) { const std::string yaml = TestEnvironment::substitute(R"EOF( name: AddressResolverdListener address: socket_address: { address: 127.0.0.1, port_value: 1111, resolver_name: envoy.mock.resolver } filter_chains: - - filters: + - filters: [] + name: foo )EOF", Network::Address::IpVersion::v4); @@ -4634,16 +5125,17 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, AddressResolver) { Registry::InjectFactory register_resolver(mock_resolver); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, CRLFilename) { +TEST_P(ListenerManagerImplWithRealFiltersTest, CRLFilename) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } filter_chains: - - transport_socket: + - name: foo + transport_socket: name: tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext @@ -4659,18 +5151,19 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, CRLFilename) { EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, CRLInline) { +TEST_P(ListenerManagerImplWithRealFiltersTest, CRLInline) { const std::string crl = TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/ca_cert.crl")); const std::string yaml = TestEnvironment::substitute(absl::StrCat(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } filter_chains: - - transport_socket: + - name: foo + transport_socket: name: tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext @@ -4687,16 +5180,17 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, CRLInline) { EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, InvalidCRLInline) { +TEST_P(ListenerManagerImplWithRealFiltersTest, InvalidCRLInline) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } filter_chains: - - transport_socket: + - name: foo + transport_socket: name: tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext @@ -4710,16 +5204,17 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, InvalidCRLInline) { )EOF", Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, "Failed to load CRL from "); + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, + "Failed to load CRL from "); } -TEST_F(ListenerManagerImplWithRealFiltersTest, CRLWithNoCA) { +TEST_P(ListenerManagerImplWithRealFiltersTest, CRLWithNoCA) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } filter_chains: - - transport_socket: + - name: foo + transport_socket: name: tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext @@ -4732,16 +5227,17 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, CRLWithNoCA) { )EOF", Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_REGEX(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, "^Failed to load CRL from .* without trusted CA$"); + EXPECT_THROW_WITH_REGEX(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, + "^Failed to load CRL from .* without trusted CA$"); } -TEST_F(ListenerManagerImplWithRealFiltersTest, VerifySanWithNoCA) { +TEST_P(ListenerManagerImplWithRealFiltersTest, VerifySanWithNoCA) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } filter_chains: - - transport_socket: + - name: foo + transport_socket: name: tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext @@ -4755,19 +5251,19 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, VerifySanWithNoCA) { )EOF", Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "SAN-based verification of peer certificates without trusted CA " "is insecure and not allowed"); } // Disabling certificate expiration checks only makes sense with a trusted CA. -TEST_F(ListenerManagerImplWithRealFiltersTest, VerifyIgnoreExpirationWithNoCA) { +TEST_P(ListenerManagerImplWithRealFiltersTest, VerifyIgnoreExpirationWithNoCA) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } filter_chains: - - transport_socket: + - name: foo + transport_socket: name: tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext @@ -4780,18 +5276,18 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, VerifyIgnoreExpirationWithNoCA) { )EOF", Network::Address::IpVersion::v4); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "Certificate validity period is always ignored without trusted CA"); } // Verify that with a CA, expired certificates are allowed. -TEST_F(ListenerManagerImplWithRealFiltersTest, VerifyIgnoreExpirationWithCA) { +TEST_P(ListenerManagerImplWithRealFiltersTest, VerifyIgnoreExpirationWithCA) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } filter_chains: - - transport_socket: + - name: foo + transport_socket: name: tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext @@ -4806,17 +5302,17 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, VerifyIgnoreExpirationWithCA) { )EOF", Network::Address::IpVersion::v4); - EXPECT_NO_THROW(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true)); + EXPECT_NO_THROW(addOrUpdateListener(parseListenerFromV3Yaml(yaml))); } // Validate that dispatcher stats prefix is set correctly when enabled. -TEST_F(ListenerManagerImplWithDispatcherStatsTest, DispatherStatsWithCorrectPrefix) { +TEST_P(ListenerManagerImplWithDispatcherStatsTest, DispatherStatsWithCorrectPrefix) { EXPECT_CALL(*worker_, start(_, _)); EXPECT_CALL(*worker_, initializeStats(_)); manager_->startWorkers(guard_dog_, callback_.AsStdFunction()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, ApiListener) { +TEST_P(ListenerManagerImplWithRealFiltersTest, ApiListener) { const std::string yaml = R"EOF( name: test_api_listener address: @@ -4842,12 +5338,12 @@ name: test_api_listener server_.server_factory_context_->cluster_manager_.initializeClusters( {"dynamic_forward_proxy_cluster"}, {}); - ASSERT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", false)); + ASSERT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", false)); EXPECT_EQ(0U, manager_->listeners().size()); ASSERT_TRUE(manager_->apiListener().has_value()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, ApiListenerNotAllowedAddedViaApi) { +TEST_P(ListenerManagerImplWithRealFiltersTest, ApiListenerNotAllowedAddedViaApi) { const std::string yaml = R"EOF( name: test_api_listener address: @@ -4871,12 +5367,12 @@ name: test_api_listener cluster: dynamic_forward_proxy_cluster )EOF"; - ASSERT_FALSE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true)); + ASSERT_FALSE(addOrUpdateListener(parseListenerFromV3Yaml(yaml))); EXPECT_EQ(0U, manager_->listeners().size()); ASSERT_FALSE(manager_->apiListener().has_value()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, ApiListenerOnlyOneApiListener) { +TEST_P(ListenerManagerImplWithRealFiltersTest, ApiListenerOnlyOneApiListener) { const std::string yaml = R"EOF( name: test_api_listener address: @@ -4925,20 +5421,23 @@ name: test_api_listener_2 server_.server_factory_context_->cluster_manager_.initializeClusters( {"dynamic_forward_proxy_cluster"}, {}); - ASSERT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", false)); + ASSERT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", false)); EXPECT_EQ(0U, manager_->listeners().size()); ASSERT_TRUE(manager_->apiListener().has_value()); EXPECT_EQ("test_api_listener", manager_->apiListener()->get().name()); // Only one ApiListener is added. - ASSERT_FALSE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", false)); + ASSERT_FALSE(addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", false)); EXPECT_EQ(0U, manager_->listeners().size()); // The original ApiListener is there. ASSERT_TRUE(manager_->apiListener().has_value()); EXPECT_EQ("test_api_listener", manager_->apiListener()->get().name()); } -TEST_F(ListenerManagerImplWithRealFiltersTest, AddOrUpdateInternalListener) { +TEST_P(ListenerManagerImplWithRealFiltersTest, AddOrUpdateInternalListener) { + if (matcher_) { + GTEST_SKIP() << "Filter chain match is auto-inserted in the config dump"; + } auto scoped_runtime_guard = std::make_unique(); Runtime::LoaderSingleton::getExisting()->mergeValues( {{"envoy.reloadable_features.internal_address", "true"}}); @@ -4962,12 +5461,13 @@ name: test_internal_listener address: envoy_internal_address: server_listener_name: test_internal_listener_name -filter_chains: {} +filter_chains: +- filters: [] + name: foo )EOF"; ListenerHandle* listener_foo = expectListenerCreate(false, true); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "version1", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "version1", true)); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); EXPECT_CALL(*lds_api, versionInfo()).WillOnce(Return("version1")); checkConfigDump(R"EOF( @@ -4983,14 +5483,16 @@ version_info: version1 address: envoy_internal_address: server_listener_name: test_internal_listener_name - filter_chains: {} + filter_chains: + - filters: [] + name: foo last_updated: seconds: 1001001001 nanos: 1000000 )EOF"); // Update duplicate should be a NOP. - EXPECT_FALSE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_FALSE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); checkStats(__LINE__, 1, 0, 0, 0, 1, 0, 0); // Update foo listener. Should share socket. @@ -4999,7 +5501,9 @@ name: test_internal_listener address: envoy_internal_address: server_listener_name: test_internal_listener_name -filter_chains: {} +filter_chains: +- filters: [] + name: foo per_connection_buffer_limit_bytes: 10 )EOF"; @@ -5007,8 +5511,8 @@ per_connection_buffer_limit_bytes: 10 ListenerHandle* listener_foo_update1 = expectListenerCreate(false, true); EXPECT_CALL(*listener_foo, onDestroy()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), - "version2", true)); + EXPECT_TRUE( + addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), "version2", true)); checkStats(__LINE__, 1, 1, 0, 0, 1, 0, 0); EXPECT_CALL(*lds_api, versionInfo()).WillOnce(Return("version2")); checkConfigDump(R"EOF( @@ -5024,7 +5528,9 @@ per_connection_buffer_limit_bytes: 10 address: envoy_internal_address: server_listener_name: test_internal_listener_name - filter_chains: {} + filter_chains: + - filters: [] + name: foo per_connection_buffer_limit_bytes: 10 last_updated: seconds: 2002002002 @@ -5054,8 +5560,7 @@ per_connection_buffer_limit_bytes: 10 .value()); // Update duplicate should be a NOP. - EXPECT_FALSE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), "", true)); + EXPECT_FALSE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml))); checkStats(__LINE__, 1, 1, 0, 0, 1, 0, 0); time_system_.setSystemTime(std::chrono::milliseconds(3003003003003)); @@ -5066,8 +5571,7 @@ per_connection_buffer_limit_bytes: 10 EXPECT_CALL(*worker_, addListener(_, _, _, _)); EXPECT_CALL(*worker_, stopListener(_, _)); EXPECT_CALL(*listener_foo_update1->drain_manager_, startDrainSequence(_)); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "version3", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "version3", true)); worker_->callAddCompletion(); checkStats(__LINE__, 1, 2, 0, 0, 1, 1, 0); EXPECT_CALL(*lds_api, versionInfo()).WillOnce(Return("version3")); @@ -5084,7 +5588,9 @@ per_connection_buffer_limit_bytes: 10 address: envoy_internal_address: server_listener_name: test_internal_listener_name - filter_chains: {} + filter_chains: + - filters: [] + name: foo last_updated: seconds: 3003003003 nanos: 3000000 @@ -5096,7 +5602,9 @@ per_connection_buffer_limit_bytes: 10 address: envoy_internal_address: server_listener_name: test_internal_listener_name - filter_chains: {} + filter_chains: + - filters: [] + name: foo per_connection_buffer_limit_bytes: 10 last_updated: seconds: 2002002002 @@ -5118,14 +5626,15 @@ per_connection_buffer_limit_bytes: 10 address: envoy_internal_address: server_listener_name: test_internal_listener_bar - filter_chains: {} + filter_chains: + - filters: [] + name: foo internal_listener: {} )EOF"; ListenerHandle* listener_bar = expectListenerCreate(false, true); EXPECT_CALL(*worker_, addListener(_, _, _, _)); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_bar_yaml), "version4", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_bar_yaml), "version4", true)); EXPECT_EQ(2UL, manager_->listeners().size()); worker_->callAddCompletion(); checkStats(__LINE__, 2, 2, 0, 0, 2, 0, 0); @@ -5138,14 +5647,15 @@ per_connection_buffer_limit_bytes: 10 address: envoy_internal_address: server_listener_name: test_internal_listener_baz - filter_chains: {} + filter_chains: + - filters: [] + name: foo internal_listener: {} )EOF"; ListenerHandle* listener_baz = expectListenerCreate(true, true); EXPECT_CALL(listener_baz->target_, initialize()); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_baz_yaml), "version5", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_baz_yaml), "version5", true)); EXPECT_EQ(2UL, manager_->listeners().size()); checkStats(__LINE__, 3, 2, 0, 1, 2, 0, 0); EXPECT_CALL(*lds_api, versionInfo()).WillOnce(Return("version5")); @@ -5161,7 +5671,9 @@ per_connection_buffer_limit_bytes: 10 address: envoy_internal_address: server_listener_name: test_internal_listener_name - filter_chains: {} + filter_chains: + - filters: [] + name: foo last_updated: seconds: 3003003003 nanos: 3000000 @@ -5174,7 +5686,9 @@ per_connection_buffer_limit_bytes: 10 address: envoy_internal_address: server_listener_name: test_internal_listener_bar - filter_chains: {} + filter_chains: + - filters: [] + name: foo internal_listener: {} last_updated: seconds: 4004004004 @@ -5188,7 +5702,9 @@ per_connection_buffer_limit_bytes: 10 address: envoy_internal_address: server_listener_name: test_internal_listener_baz - filter_chains: {} + filter_chains: + - filters: [] + name: foo internal_listener: {} last_updated: seconds: 5005005005 @@ -5196,7 +5712,7 @@ per_connection_buffer_limit_bytes: 10 )EOF"); // Update a duplicate baz that is currently warming. - EXPECT_FALSE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_baz_yaml), "", true)); + EXPECT_FALSE(addOrUpdateListener(parseListenerFromV3Yaml(listener_baz_yaml))); checkStats(__LINE__, 3, 2, 0, 1, 2, 0, 0); // Update baz while it is warming. @@ -5210,6 +5726,7 @@ per_connection_buffer_limit_bytes: 10 - filters: - name: fake typed_config: {} + name: foo )EOF"; ListenerHandle* listener_baz_update1 = expectListenerCreate(true, true); @@ -5218,8 +5735,7 @@ per_connection_buffer_limit_bytes: 10 listener_baz->target_.ready(); })); EXPECT_CALL(listener_baz_update1->target_, initialize()); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_baz_update1_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_baz_update1_yaml))); EXPECT_EQ(2UL, manager_->listeners().size()); checkStats(__LINE__, 3, 3, 0, 1, 2, 0, 0); @@ -5235,7 +5751,7 @@ per_connection_buffer_limit_bytes: 10 EXPECT_CALL(*listener_baz_update1, onDestroy()); } -TEST_F(ListenerManagerImplTest, StopInplaceWarmingListener) { +TEST_P(ListenerManagerImplTest, StopInplaceWarmingListener) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -5256,7 +5772,7 @@ traffic_direction: INBOUND ListenerHandle* listener_foo = expectListenerCreate(true, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(listener_foo->target_, initialize()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); EXPECT_EQ(0, server_.stats_store_.counter("listener_manager.listener_in_place_updated").value()); checkStats(__LINE__, 1, 0, 0, 1, 0, 0, 0); @@ -5283,8 +5799,7 @@ traffic_direction: INBOUND ListenerHandle* listener_foo_update1 = expectListenerOverridden(true); EXPECT_CALL(*listener_factory_.socket_, duplicate()); EXPECT_CALL(listener_foo_update1->target_, initialize()); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml))); EXPECT_EQ(1, server_.stats_store_.counter("listener_manager.listener_in_place_updated").value()); EXPECT_EQ(1UL, manager_->listeners().size()); @@ -5298,7 +5813,7 @@ traffic_direction: INBOUND EXPECT_EQ(1, server_.stats_store_.counter("listener_manager.listener_stopped").value()); } -TEST_F(ListenerManagerImplTest, RemoveInplaceUpdatingListener) { +TEST_P(ListenerManagerImplTest, RemoveInplaceUpdatingListener) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -5319,7 +5834,7 @@ traffic_direction: INBOUND ListenerHandle* listener_foo = expectListenerCreate(true, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(listener_foo->target_, initialize()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); EXPECT_EQ(0, server_.stats_store_.counter("listener_manager.listener_in_place_updated").value()); checkStats(__LINE__, 1, 0, 0, 1, 0, 0, 0); @@ -5345,8 +5860,7 @@ traffic_direction: INBOUND ListenerHandle* listener_foo_update1 = expectListenerOverridden(true); EXPECT_CALL(*listener_factory_.socket_, duplicate()); EXPECT_CALL(listener_foo_update1->target_, initialize()); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml))); EXPECT_EQ(1, server_.stats_store_.counter("listener_manager.listener_in_place_updated").value()); EXPECT_EQ(1UL, manager_->listeners().size()); @@ -5368,7 +5882,7 @@ traffic_direction: INBOUND checkStats(__LINE__, 1, 1, 1, 0, 0, 0, 0); } -TEST_F(ListenerManagerImplTest, UpdateInplaceWarmingListener) { +TEST_P(ListenerManagerImplTest, UpdateInplaceWarmingListener) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -5389,7 +5903,7 @@ traffic_direction: INBOUND ListenerHandle* listener_foo = expectListenerCreate(true, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(listener_foo->target_, initialize()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); EXPECT_EQ(0, server_.stats_store_.counter("listener_manager.listener_in_place_updated").value()); checkStats(__LINE__, 1, 0, 0, 1, 0, 0, 0); @@ -5415,8 +5929,7 @@ traffic_direction: INBOUND ListenerHandle* listener_foo_update1 = expectListenerOverridden(true); EXPECT_CALL(*listener_factory_.socket_, duplicate()); EXPECT_CALL(listener_foo_update1->target_, initialize()); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml))); EXPECT_EQ(1, server_.stats_store_.counter("listener_manager.listener_in_place_updated").value()); EXPECT_EQ(1UL, manager_->listeners().size()); @@ -5432,7 +5945,7 @@ traffic_direction: INBOUND EXPECT_CALL(*listener_foo_update1, onDestroy()); } -TEST_F(ListenerManagerImplForInPlaceFilterChainUpdateTest, RemoveTheInplaceUpdatingListener) { +TEST_P(ListenerManagerImplForInPlaceFilterChainUpdateTest, RemoveTheInplaceUpdatingListener) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -5453,7 +5966,7 @@ traffic_direction: INBOUND ListenerHandle* listener_foo = expectListenerCreate(true, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(listener_foo->target_, initialize()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); checkStats(__LINE__, 1, 0, 0, 1, 0, 0, 0); EXPECT_CALL(*worker_, addListener(_, _, _, _)); listener_foo->target_.ready(); @@ -5479,7 +5992,7 @@ traffic_direction: INBOUND EXPECT_CALL(*listener_factory_.socket_, duplicate()) .WillOnce(Return(ByMove(std::unique_ptr(duplicated_socket)))); EXPECT_CALL(listener_foo_update1->target_, initialize()); - EXPECT_TRUE(manager_->addOrUpdateListener(listener_foo_update1_proto, "", true)); + EXPECT_TRUE(addOrUpdateListener(listener_foo_update1_proto)); EXPECT_EQ(1UL, manager_->listeners().size()); EXPECT_EQ(1, server_.stats_store_.counter("listener_manager.listener_in_place_updated").value()); checkStats(__LINE__, 1, 1, 0, 1, 1, 0, 0); @@ -5518,7 +6031,7 @@ traffic_direction: INBOUND checkStats(__LINE__, 1, 2, 1, 0, 0, 0, 0); } -TEST_F(ListenerManagerImplTest, DrainageDuringInplaceUpdate) { +TEST_P(ListenerManagerImplTest, DrainageDuringInplaceUpdate) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -5539,7 +6052,7 @@ traffic_direction: INBOUND ListenerHandle* listener_foo = expectListenerCreate(true, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(listener_foo->target_, initialize()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); checkStats(__LINE__, 1, 0, 0, 1, 0, 0, 0); EXPECT_CALL(*worker_, addListener(_, _, _, _)); listener_foo->target_.ready(); @@ -5563,8 +6076,7 @@ traffic_direction: INBOUND ListenerHandle* listener_foo_update1 = expectListenerOverridden(true); EXPECT_CALL(*listener_factory_.socket_, duplicate()); EXPECT_CALL(listener_foo_update1->target_, initialize()); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml))); EXPECT_EQ(1UL, manager_->listeners().size()); EXPECT_EQ(1, server_.stats_store_.counter("listener_manager.listener_in_place_updated").value()); checkStats(__LINE__, 1, 1, 0, 1, 1, 0, 0); @@ -5589,7 +6101,7 @@ traffic_direction: INBOUND EXPECT_CALL(*listener_foo_update1, onDestroy()); } -TEST_F(ListenerManagerImplTest, ListenSocketFactoryIsClonedFromListenerDrainingFilterChain) { +TEST_P(ListenerManagerImplTest, ListenSocketFactoryIsClonedFromListenerDrainingFilterChain) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -5610,7 +6122,7 @@ traffic_direction: INBOUND ListenerHandle* listener_foo = expectListenerCreate(true, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); EXPECT_CALL(listener_foo->target_, initialize()); - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml))); checkStats(__LINE__, 1, 0, 0, 1, 0, 0, 0); EXPECT_CALL(*worker_, addListener(_, _, _, _)); listener_foo->target_.ready(); @@ -5634,8 +6146,7 @@ traffic_direction: INBOUND ListenerHandle* listener_foo_update1 = expectListenerOverridden(true, listener_foo); EXPECT_CALL(*listener_factory_.socket_, duplicate()); EXPECT_CALL(listener_foo_update1->target_, initialize()); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_update1_yaml))); EXPECT_EQ(1UL, manager_->listeners().size()); EXPECT_EQ(1, server_.stats_store_.counter("listener_manager.listener_in_place_updated").value()); checkStats(__LINE__, 1, 1, 0, 1, 1, 0, 0); @@ -5677,8 +6188,7 @@ traffic_direction: INBOUND EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, _, _, _)).Times(0); EXPECT_CALL(*listener_factory_.socket_, duplicate()); EXPECT_CALL(listener_foo_expect_reuse_socket->target_, initialize()); - EXPECT_TRUE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "version1", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(listener_foo_yaml), "version1", true)); EXPECT_CALL(*listener_foo, onDestroy()); EXPECT_CALL(*listener_foo_expect_reuse_socket, onDestroy()); @@ -5765,12 +6275,12 @@ TEST(ListenerMessageUtilTest, ListenerMessageHaveDifferentFilterChainsAreEquival EXPECT_TRUE(Server::ListenerMessageUtil::filterChainOnlyChange(listener1, listener2)); } -TEST_F(ListenerManagerImplForInPlaceFilterChainUpdateTest, TraditionalUpdateIfWorkerNotStarted) { +TEST_P(ListenerManagerImplForInPlaceFilterChainUpdateTest, TraditionalUpdateIfWorkerNotStarted) { // Worker is not started yet. auto listener_proto = createDefaultListener(); ListenerHandle* listener_foo = expectListenerCreate(false, true); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); - manager_->addOrUpdateListener(listener_proto, "", true); + addOrUpdateListener(listener_proto); EXPECT_EQ(1u, manager_->listeners().size()); // Mutate the listener message as filter chain change only. @@ -5783,14 +6293,14 @@ TEST_F(ListenerManagerImplForInPlaceFilterChainUpdateTest, TraditionalUpdateIfWo EXPECT_CALL(*listener_foo, onDestroy()); ListenerHandle* listener_foo_update1 = expectListenerCreate(false, true); EXPECT_CALL(*listener_factory_.socket_, duplicate()); - manager_->addOrUpdateListener(new_listener_proto, "", true); + addOrUpdateListener(new_listener_proto); EXPECT_CALL(*listener_foo_update1, onDestroy()); EXPECT_EQ(0, server_.stats_store_.counter("listener_manager.listener_in_place_updated").value()); } // This case verifies that listeners that share port but do not share socket type (TCP vs. UDP) // do not share a listener. -TEST_F(ListenerManagerImplForInPlaceFilterChainUpdateTest, TraditionalUpdateIfDifferentSocketType) { +TEST_P(ListenerManagerImplForInPlaceFilterChainUpdateTest, TraditionalUpdateIfDifferentSocketType) { EXPECT_CALL(*worker_, start(_, _)); manager_->startWorkers(guard_dog_, callback_.AsStdFunction()); @@ -5806,8 +6316,7 @@ TEST_F(ListenerManagerImplForInPlaceFilterChainUpdateTest, TraditionalUpdateIfDi EXPECT_CALL(server_.validation_context_, staticValidationVisitor()).Times(0); EXPECT_CALL(server_.validation_context_, dynamicValidationVisitor()); EXPECT_CALL(listener_factory_, createDrainManager_(_)); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(new_listener_proto, "", true), - EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(new_listener_proto), EnvoyException, "error adding listener '127.0.0.1:1234': 1 filter chain(s) specified " "for connection-less UDP listener."); @@ -5816,7 +6325,7 @@ TEST_F(ListenerManagerImplForInPlaceFilterChainUpdateTest, TraditionalUpdateIfDi EXPECT_EQ(0, server_.stats_store_.counter("listener_manager.listener_in_place_updated").value()); } -TEST_F(ListenerManagerImplForInPlaceFilterChainUpdateTest, +TEST_P(ListenerManagerImplForInPlaceFilterChainUpdateTest, DEPRECATED_FEATURE_TEST(TraditionalUpdateIfImplicitProxyProtocolChanges)) { EXPECT_CALL(*worker_, start(_, _)); manager_->startWorkers(guard_dog_, callback_.AsStdFunction()); @@ -5838,7 +6347,7 @@ TEST_F(ListenerManagerImplForInPlaceFilterChainUpdateTest, EXPECT_EQ(0, server_.stats_store_.counter("listener_manager.listener_in_place_updated").value()); } -TEST_F(ListenerManagerImplForInPlaceFilterChainUpdateTest, TraditionalUpdateOnZeroFilterChain) { +TEST_P(ListenerManagerImplForInPlaceFilterChainUpdateTest, TraditionalUpdateOnZeroFilterChain) { EXPECT_CALL(*worker_, start(_, _)); manager_->startWorkers(guard_dog_, callback_.AsStdFunction()); @@ -5852,8 +6361,7 @@ TEST_F(ListenerManagerImplForInPlaceFilterChainUpdateTest, TraditionalUpdateOnZe EXPECT_CALL(server_.validation_context_, staticValidationVisitor()).Times(0); EXPECT_CALL(server_.validation_context_, dynamicValidationVisitor()); EXPECT_CALL(listener_factory_, createDrainManager_(_)); - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(new_listener_proto, "", true), - EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(new_listener_proto), EnvoyException, "error adding listener '127.0.0.1:1234': no filter chains specified"); expectRemove(listener_proto, listener_foo, *listener_factory_.socket_); @@ -5861,7 +6369,7 @@ TEST_F(ListenerManagerImplForInPlaceFilterChainUpdateTest, TraditionalUpdateOnZe EXPECT_EQ(0, server_.stats_store_.counter("listener_manager.listener_in_place_updated").value()); } -TEST_F(ListenerManagerImplForInPlaceFilterChainUpdateTest, +TEST_P(ListenerManagerImplForInPlaceFilterChainUpdateTest, TraditionalUpdateIfListenerConfigHasUpdateOtherThanFilterChain) { EXPECT_CALL(*worker_, start(_, _)); manager_->startWorkers(guard_dog_, callback_.AsStdFunction()); @@ -5886,7 +6394,7 @@ TEST_F(ListenerManagerImplForInPlaceFilterChainUpdateTest, // This test verifies that on default initialization the UDP Packet Writer // is initialized in passthrough mode. (i.e. by using UdpDefaultWriter). -TEST_F(ListenerManagerImplTest, UdpDefaultWriterConfig) { +TEST_P(ListenerManagerImplTest, UdpDefaultWriterConfig) { const envoy::config::listener::v3::Listener listener = parseListenerFromV3Yaml(R"EOF( address: socket_address: @@ -5894,7 +6402,7 @@ TEST_F(ListenerManagerImplTest, UdpDefaultWriterConfig) { protocol: UDP port_value: 1234 )EOF"); - manager_->addOrUpdateListener(listener, "", true); + addOrUpdateListener(listener); EXPECT_EQ(1U, manager_->listeners().size()); Network::SocketSharedPtr listen_socket = manager_->listeners().front().get().listenSocketFactory().getListenSocket(0); @@ -5909,7 +6417,7 @@ TEST_F(ListenerManagerImplTest, UdpDefaultWriterConfig) { EXPECT_FALSE(udp_packet_writer->isBatchMode()); } -TEST_F(ListenerManagerImplTest, TcpBacklogCustomConfig) { +TEST_P(ListenerManagerImplTest, TcpBacklogCustomConfig) { const std::string yaml = TestEnvironment::substitute(R"EOF( name: TcpBacklogConfigListener address: @@ -5921,12 +6429,12 @@ TEST_F(ListenerManagerImplTest, TcpBacklogCustomConfig) { Network::Address::IpVersion::v4); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, _, _, _)); - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true); + addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); EXPECT_EQ(100U, manager_->listeners().back().get().tcpBacklogSize()); } -TEST_F(ListenerManagerImplTest, WorkersStartedCallbackCalled) { +TEST_P(ListenerManagerImplTest, WorkersStartedCallbackCalled) { InSequence s; EXPECT_CALL(*worker_, start(_, _)); @@ -5977,6 +6485,14 @@ TEST(ListenerEnableReusePortTest, All) { } } +INSTANTIATE_TEST_SUITE_P(Matcher, ListenerManagerImplTest, ::testing::Values(false)); +INSTANTIATE_TEST_SUITE_P(Matcher, ListenerManagerImplWithRealFiltersTest, + ::testing::Values(false, true)); +INSTANTIATE_TEST_SUITE_P(Matcher, ListenerManagerImplForInPlaceFilterChainUpdateTest, + ::testing::Values(false)); +INSTANTIATE_TEST_SUITE_P(Matcher, ListenerManagerImplWithDispatcherStatsTest, + ::testing::Values(false)); + } // namespace } // namespace Server } // namespace Envoy diff --git a/test/server/listener_manager_impl_test.h b/test/server/listener_manager_impl_test.h index 6febd935efa37..88dd260f7904e 100644 --- a/test/server/listener_manager_impl_test.h +++ b/test/server/listener_manager_impl_test.h @@ -52,7 +52,7 @@ class ListenerHandle { Configuration::FactoryContext* context_{}; }; -class ListenerManagerImplTest : public testing::Test { +class ListenerManagerImplTest : public testing::TestWithParam { public: // reuse_port is the default on Linux for TCP. On other platforms even if set it is disabled // and the user is warned. For UDP it's always the default even if not effective. @@ -64,7 +64,8 @@ class ListenerManagerImplTest : public testing::Test { #endif protected: - ListenerManagerImplTest() : api_(Api::createApiForTest(server_.api_.random_)) {} + ListenerManagerImplTest() + : api_(Api::createApiForTest(server_.api_.random_)), matcher_(GetParam()) {} void SetUp() override { ON_CALL(server_, api()).WillByDefault(ReturnRef(*api_)); @@ -296,12 +297,43 @@ class ListenerManagerImplTest : public testing::Test { server_.admin_.config_tracker_.config_tracker_callbacks_["listeners"](name_matcher); const auto& listeners_config_dump = dynamic_cast(*message_ptr); - envoy::admin::v3::ListenersConfigDump expected_listeners_config_dump; TestUtility::loadFromYaml(expected_dump_yaml, expected_listeners_config_dump); EXPECT_EQ(expected_listeners_config_dump.DebugString(), listeners_config_dump.DebugString()); } + bool addOrUpdateListener(const envoy::config::listener::v3::Listener& config, + const std::string& version_info = "", bool added_via_api = true) { + // Automatically inject a matcher that always matches "foo" if not present. + envoy::config::listener::v3::Listener listener; + listener.MergeFrom(config); + if (matcher_ && !listener.has_filter_chain_matcher()) { + const std::string filter_chain_matcher = R"EOF( + matcher_tree: + input: + name: port + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput + exact_match_map: + map: + "10000": + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + on_no_match: + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + TestUtility::loadFromYaml(filter_chain_matcher, *listener.mutable_filter_chain_matcher()); + } + return manager_->addOrUpdateListener(listener, version_info, added_via_api); + } + NiceMock os_sys_calls_; TestThreadsafeSingletonInjector os_calls_{&os_sys_calls_}; Api::OsSysCallsImpl os_sys_calls_actual_; @@ -321,7 +353,7 @@ class ListenerManagerImplTest : public testing::Test { uint64_t listener_tag_{1}; bool enable_dispatcher_stats_{false}; NiceMock> callback_; + bool matcher_; }; - } // namespace Server } // namespace Envoy From d0f78a479b252194bbecdcd2bf3a62dd1d1358af Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Fri, 25 Feb 2022 08:26:36 -0800 Subject: [PATCH 21/39] fix quic test Signed-off-by: Kuat Yessenov --- .../listener_manager_impl_quic_only_test.cc | 50 ++++++++++++++----- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/test/server/listener_manager_impl_quic_only_test.cc b/test/server/listener_manager_impl_quic_only_test.cc index c60143bada353..7a8110ddfc616 100644 --- a/test/server/listener_manager_impl_quic_only_test.cc +++ b/test/server/listener_manager_impl_quic_only_test.cc @@ -26,8 +26,8 @@ class ListenerManagerImplQuicOnlyTest : public ListenerManagerImplTest { }; #if defined(ENVOY_ENABLE_QUIC) -TEST_F(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryAndSslContext) { - const std::string yaml = TestEnvironment::substitute(R"EOF( +TEST_P(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryAndSslContext) { + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: address: 127.0.0.1 @@ -36,6 +36,7 @@ TEST_F(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryAndSslContext) { filter_chains: - filter_chain_match: transport_protocol: "quic" + name: foo filters: - name: envoy.filters.network.http_connection_manager typed_config: @@ -70,7 +71,25 @@ TEST_F(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryAndSslContext) { udp_listener_config: quic_options: {} )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (matcher_) { + yaml = yaml + R"EOF( +filter_chain_matcher: + matcher_tree: + input: + name: transport + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.TransportProtocolInput + exact_match_map: + map: + "quic": + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } envoy::config::listener::v3::Listener listener_proto = parseListenerFromV3Yaml(yaml); ON_CALL(udp_gso_syscall_, supportsUdpGso()) @@ -109,7 +128,7 @@ TEST_F(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryAndSslContext) { } #endif - manager_->addOrUpdateListener(listener_proto, "", true); + addOrUpdateListener(listener_proto); EXPECT_EQ(1u, manager_->listeners().size()); EXPECT_FALSE(manager_->listeners()[0] .get() @@ -153,7 +172,7 @@ TEST_F(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryAndSslContext) { } #endif -TEST_F(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryWithWrongTransportSocket) { +TEST_P(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryWithWrongTransportSocket) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: @@ -163,6 +182,7 @@ TEST_F(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryWithWrongTransportSoc filter_chains: - filter_chain_match: transport_protocol: "quic" + name: foo filters: [] transport_socket: name: envoy.transport_sockets.quic @@ -192,15 +212,15 @@ TEST_F(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryWithWrongTransportSoc envoy::config::listener::v3::Listener listener_proto = parseListenerFromV3Yaml(yaml); #if defined(ENVOY_ENABLE_QUIC) - EXPECT_THROW_WITH_REGEX(manager_->addOrUpdateListener(listener_proto, "", true), EnvoyException, + EXPECT_THROW_WITH_REGEX(addOrUpdateListener(listener_proto), EnvoyException, "wrong transport socket config specified for quic transport socket"); #else - EXPECT_THROW_WITH_REGEX(manager_->addOrUpdateListener(listener_proto, "", true), EnvoyException, + EXPECT_THROW_WITH_REGEX(addOrUpdateListener(listener_proto), EnvoyException, "QUIC is configured but not enabled in the build."); #endif } -TEST_F(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryWithWrongCodec) { +TEST_P(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryWithWrongCodec) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: @@ -210,6 +230,7 @@ TEST_F(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryWithWrongCodec) { filter_chains: - filter_chain_match: transport_protocol: "quic" + name: foo filters: [] transport_socket: name: envoy.transport_sockets.quic @@ -240,16 +261,16 @@ TEST_F(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryWithWrongCodec) { envoy::config::listener::v3::Listener listener_proto = parseListenerFromV3Yaml(yaml); #if defined(ENVOY_ENABLE_QUIC) - EXPECT_THROW_WITH_REGEX(manager_->addOrUpdateListener(listener_proto, "", true), EnvoyException, + EXPECT_THROW_WITH_REGEX(addOrUpdateListener(listener_proto), EnvoyException, "error building network filter chain for quic listener: requires exactly " "one http_connection_manager filter."); #else - EXPECT_THROW_WITH_REGEX(manager_->addOrUpdateListener(listener_proto, "", true), EnvoyException, + EXPECT_THROW_WITH_REGEX(addOrUpdateListener(listener_proto), EnvoyException, "QUIC is configured but not enabled in the build."); #endif } -TEST_F(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryWithConnectionBalencer) { +TEST_P(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryWithConnectionBalencer) { const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: @@ -259,6 +280,7 @@ TEST_F(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryWithConnectionBalence filter_chains: - filter_chain_match: transport_protocol: "quic" + name: foo filters: - name: envoy.filters.network.http_connection_manager typed_config: @@ -300,15 +322,17 @@ TEST_F(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryWithConnectionBalence envoy::config::listener::v3::Listener listener_proto = parseListenerFromV3Yaml(yaml); #if defined(ENVOY_ENABLE_QUIC) - EXPECT_THROW_WITH_REGEX(manager_->addOrUpdateListener(listener_proto, "", true), EnvoyException, + EXPECT_THROW_WITH_REGEX(addOrUpdateListener(listener_proto), EnvoyException, "connection_balance_config is configured for QUIC listener which doesn't " "work with connection balancer."); #else - EXPECT_THROW_WITH_REGEX(manager_->addOrUpdateListener(listener_proto, "", true), EnvoyException, + EXPECT_THROW_WITH_REGEX(addOrUpdateListener(listener_proto), EnvoyException, "QUIC is configured but not enabled in the build."); #endif } +INSTANTIATE_TEST_SUITE_P(Matcher, ListenerManagerImplQuicOnlyTest, ::testing::Values(false, true)); + } // namespace } // namespace Server } // namespace Envoy From 0831118e237a1592954484c1605880c6ad7227ca Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Mon, 28 Feb 2022 11:42:57 -0800 Subject: [PATCH 22/39] review Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/BUILD | 1 + api/envoy/config/listener/v3/listener.proto | 4 +++- api/envoy/config/listener/v3/listener_components.proto | 9 +++++---- docs/root/version_history/current.rst | 1 + 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/api/envoy/config/listener/v3/BUILD b/api/envoy/config/listener/v3/BUILD index 75f6e10c7e4f9..f4f900c4db89f 100644 --- a/api/envoy/config/listener/v3/BUILD +++ b/api/envoy/config/listener/v3/BUILD @@ -11,6 +11,7 @@ api_proto_package( "//envoy/config/core/v3:pkg", "//envoy/type/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", + "@com_github_cncf_udpa//xds/annotations/v3:pkg", "@com_github_cncf_udpa//xds/core/v3:pkg", "@com_github_cncf_udpa//xds/type/matcher/v3:pkg", ], diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index de579bf02e5be..0d5d7b630d5df 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -13,6 +13,7 @@ import "envoy/config/listener/v3/udp_listener_config.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; +import "xds/annotations/v3/status.proto"; import "xds/core/v3/collection_entry.proto"; import "xds/type/matcher/v3/matcher.proto"; @@ -189,7 +190,8 @@ message Listener { // connections bound to the filter chain are not drained. If, however, the // filter chain is removed or structurally modified, then the drain for its // connections is initiated. - xds.type.matcher.v3.Matcher filter_chain_matcher = 32; + xds.type.matcher.v3.Matcher filter_chain_matcher = 32 + [(xds.annotations.v3.field_status).work_in_progress = true]; // If a connection is redirected using *iptables*, the port on which the proxy // receives it might be different from the original destination address. When this flag is set to diff --git a/api/envoy/config/listener/v3/listener_components.proto b/api/envoy/config/listener/v3/listener_components.proto index 8ca54b3cb2624..354c299544376 100644 --- a/api/envoy/config/listener/v3/listener_components.proto +++ b/api/envoy/config/listener/v3/listener_components.proto @@ -11,6 +11,8 @@ import "google/protobuf/any.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; +import "xds/annotations/v3/status.proto"; + import "envoy/annotations/deprecation.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; @@ -259,12 +261,11 @@ message FilterChain { // establishment, the connection is summarily closed. google.protobuf.Duration transport_socket_connect_timeout = 9; - // The unique name (or empty) by which this filter chain is known. If no - // name is provided, Envoy will allocate an internal UUID for the filter chain. + // The unique name (or empty) by which this filter chain is known. // Note: :ref:`filter_chain_matcher // ` - // requires that filter chains are uniquely named. - string name = 7; + // requires that filter chains are uniquely named within a listener. + string name = 7 [(xds.annotations.v3.field_status).work_in_progress = true]; // [#not-implemented-hide:] The configuration to specify whether the filter chain will be built on-demand. // If this field is not empty, the filter chain will be built on-demand. diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index ccd839794eb7a..b2ce99115d99c 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -65,6 +65,7 @@ New Features * http3: downstream HTTP/3 support is now GA! Upstream HTTP/3 also GA for specific deployments. See :ref:`here ` for details. * http3: supports upstream HTTP/3 retries. Automatically retry `0-RTT safe requests `_ if they are rejected because they are sent `too early `_. And automatically retry 0-RTT safe requests if connect attempt fails later on and the cluster is configured with TCP fallback. And add retry on ``http3-post-connect-failure`` policy which allows retry of failed HTTP/3 requests with TCP fallback even after handshake if the cluster is configured with TCP fallback. This feature is guarded by ``envoy.reloadable_features.conn_pool_new_stream_with_early_data_and_http3``. * matching: the matching API can now express a match tree that will always match by omitting a matcher at the top level. +* matching: add experimental support for matching filter chains in a listener using the matching API. Deprecated ---------- From bf77d77bcadd3635774aa961ff9dc4a2cc377932 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Mon, 28 Feb 2022 15:35:43 -0800 Subject: [PATCH 23/39] review Signed-off-by: Kuat Yessenov --- source/server/filter_chain_manager_impl.cc | 51 ++++++++++++---------- source/server/filter_chain_manager_impl.h | 5 +-- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/source/server/filter_chain_manager_impl.cc b/source/server/filter_chain_manager_impl.cc index 2f79e22b68e16..740ce6eb7b48f 100644 --- a/source/server/filter_chain_manager_impl.cc +++ b/source/server/filter_chain_manager_impl.cc @@ -31,18 +31,27 @@ Network::Address::InstanceConstSharedPtr fakeAddress() { } struct FilterChainNameAction : public Matcher::ActionBase { - explicit FilterChainNameAction(const std::string& name) : name_(name) {} - const std::string name_; + explicit FilterChainNameAction(Network::DrainableFilterChainSharedPtr chain) : chain_(chain) {} + const Network::DrainableFilterChainSharedPtr chain_; }; -class FilterChainNameActionFactory : public Matcher::ActionFactory { +using FilterChainActionFactoryContext = + absl::flat_hash_map; + +class FilterChainNameActionFactory + : public Matcher::ActionFactory { public: std::string name() const override { return "filter-chain-name"; } Matcher::ActionFactoryCb createActionFactoryCb(const Protobuf::Message& config, - Configuration::FactoryContext&, + FilterChainActionFactoryContext& filter_chains, ProtobufMessage::ValidationVisitor&) override { + Network::DrainableFilterChainSharedPtr chain = nullptr; const auto& name = dynamic_cast(config); - return [name]() { return std::make_unique(name.value()); }; + const auto chain_match = filter_chains.find(name.value()); + if (chain_match != filter_chains.end()) { + chain = chain_match->second; + } + return [chain]() { return std::make_unique(chain); }; } ProtobufTypes::MessagePtr createEmptyConfigProto() override { return std::make_unique(); @@ -50,7 +59,7 @@ class FilterChainNameActionFactory : public Matcher::ActionFactory); + Matcher::ActionFactory); class FilterChainNameActionValidationVisitor : public Matcher::MatchTreeValidationVisitor { @@ -204,14 +213,7 @@ void FilterChainManagerImpl::addFilterChains( MessageUtil> filter_chains; uint32_t new_filter_chain_size = 0; - - // Construct matcher if it is present in the listener configuration. - if (filter_chain_matcher) { - FilterChainNameActionValidationVisitor validation_visitor; - Matcher::MatchTreeFactory factory( - parent_context_, parent_context_.getServerFactoryContext(), validation_visitor); - matcher_ = factory.create(*filter_chain_matcher)(); - } + absl::flat_hash_map filter_chains_by_name; for (const auto& filter_chain : filter_chain_span) { const auto& filter_chain_match = filter_chain->filter_chain_match(); @@ -220,7 +222,7 @@ void FilterChainManagerImpl::addFilterChains( "unimplemented fields", address_->asString(), filter_chain->name())); } - if (!matcher_) { + if (!filter_chain_matcher) { const auto& matching_iter = filter_chains.find(filter_chain_match); if (matching_iter != filter_chains.end()) { throw EnvoyException(fmt::format("error adding listener '{}': filter chain '{}' has " @@ -242,14 +244,14 @@ void FilterChainManagerImpl::addFilterChains( } // If using the matcher, require usage of "name" field and skip building the index. - if (matcher_) { + if (filter_chain_matcher) { if (filter_chain->name().empty()) { throw EnvoyException(fmt::format( "error adding listener '{}': \"name\" field is required when using a listener matcher", address_->asString())); } auto [_, inserted] = - filter_chains_by_name_.try_emplace(filter_chain->name(), filter_chain_impl); + filter_chains_by_name.try_emplace(filter_chain->name(), filter_chain_impl); if (!inserted) { throw EnvoyException( fmt::format("error adding listener '{}': \"name\" field is duplicated with value '{}'", @@ -300,6 +302,13 @@ void FilterChainManagerImpl::addFilterChains( convertIPsToTries(); copyOrRebuildDefaultFilterChain(default_filter_chain, filter_chain_factory_builder, context_creator); + // Construct matcher if it is present in the listener configuration. + if (filter_chain_matcher) { + FilterChainNameActionValidationVisitor validation_visitor; + Matcher::MatchTreeFactory factory( + filter_chains_by_name, parent_context_.getServerFactoryContext(), validation_visitor); + matcher_ = factory.create(*filter_chain_matcher)(); + } ENVOY_LOG(debug, "new fc_contexts has {} filter chains, including {} newly built", fc_contexts_.size(), new_filter_chain_size); } @@ -565,16 +574,12 @@ FilterChainManagerImpl::findFilterChain(const Network::ConnectionSocket& socket) const Network::FilterChain* FilterChainManagerImpl::findFilterChainUsingMatcher(const Network::ConnectionSocket& socket) const { Network::Matching::MatchingDataImpl data(socket); - const auto match_result = Matcher::evaluateMatch(*matcher_, data); + const auto& match_result = Matcher::evaluateMatch(*matcher_, data); ASSERT(match_result.match_state_ == Matcher::MatchState::MatchComplete, "Matching must complete for network streams."); if (match_result.result_) { const auto result = match_result.result_(); - const auto chain_match = - filter_chains_by_name_.find(result->getTyped().name_); - if (chain_match != filter_chains_by_name_.end()) { - return chain_match->second.get(); - } + return result->getTyped().chain_.get(); } return default_filter_chain_.get(); } diff --git a/source/server/filter_chain_manager_impl.h b/source/server/filter_chain_manager_impl.h index abcf86124a943..e3322602c35f1 100644 --- a/source/server/filter_chain_manager_impl.h +++ b/source/server/filter_chain_manager_impl.h @@ -370,9 +370,6 @@ class FilterChainManagerImpl : public Network::FilterChainManager, // detect the filter chains in the intersection of existing listener and new listener. FcContextMap fc_contexts_; - // Mapping from filter chain name to filter chain. - absl::flat_hash_map filter_chains_by_name_; - absl::optional default_filter_chain_message_; // The optional fallback filter chain if destination_ports_map_ does not find a matched filter // chain. @@ -397,7 +394,7 @@ class FilterChainManagerImpl : public Network::FilterChainManager, Init::Manager& init_manager_; // Matcher selecting the filter chain name. - Matcher::MatchTreeSharedPtr matcher_; + Matcher::MatchTreePtr matcher_; }; } // namespace Server } // namespace Envoy From 2451c0a247e614a371be13e3553cd41b1558d32c Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Mon, 28 Feb 2022 21:07:13 -0800 Subject: [PATCH 24/39] fix order Signed-off-by: Kuat Yessenov --- docs/root/version_history/current.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index e22180fd1963c..ceec9e80a89d4 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -76,8 +76,8 @@ New Features * http2: re-enabled the HTTP/2 wrapper API. This should be a transparent change that does not affect functionality. Any behavior changes can be reverted by setting the ``envoy.reloadable_features.http2_new_codec_wrapper`` runtime feature to false. * http3: downstream HTTP/3 support is now GA! Upstream HTTP/3 also GA for specific deployments. See :ref:`here ` for details. * http3: supports upstream HTTP/3 retries. Automatically retry `0-RTT safe requests `_ if they are rejected because they are sent `too early `_. And automatically retry 0-RTT safe requests if connect attempt fails later on and the cluster is configured with TCP fallback. And add retry on ``http3-post-connect-failure`` policy which allows retry of failed HTTP/3 requests with TCP fallback even after handshake if the cluster is configured with TCP fallback. This feature is guarded by ``envoy.reloadable_features.conn_pool_new_stream_with_early_data_and_http3``. -* matching: the matching API can now express a match tree that will always match by omitting a matcher at the top level. * matching: add experimental support for matching filter chains in a listener using the matching API. +* matching: the matching API can now express a match tree that will always match by omitting a matcher at the top level. * outlier_detection: :ref:`max_ejection_time_jitter` configuration added to allow adding a random value to the ejection time to prevent 'thundering herd' scenarios. Defaults to 0 so as to not break or change the behavior of existing deployments. * redis: support for hostnames returned in `cluster slots` response is now available. * schema_validator_tool: added ``bootstrap`` checking to the From 7b2bbe64a617aa4835e7229ff067c265d7d75191 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Mon, 28 Feb 2022 21:41:58 -0800 Subject: [PATCH 25/39] docs Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener.proto | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index 0d5d7b630d5df..b2993d34363f7 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -124,12 +124,14 @@ message Listener { // Unified matcher resolving the filter chain name from the network properties. This matcher is used as a replacement // for the per-filter chain match condition - // `filter_chain_match `. + // :ref:`filter_chain_match `. // If specified, all :ref:`filter_chains ` must // have non-empty and unique :ref:`name ` fields and omit - // `filter_chain_match ` field. + // :ref:`filter_chain_match ` field. // - // Example 1: The following matcher selects three filter chains as follows: + // The list of available matching inputs is available :ref:`here `. + // + // Example: The following matcher selects three filter chains as follows: // // * if the destination port is 80, then the filter chain "http" is selected; // * if the destination port is 443 and the source IP is in the range 192.0.0.0/2, then the filter chain "internal" is selected; From 15ae545f025940fc870e0d1010c7b42e3587e556 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Mon, 28 Feb 2022 22:05:56 -0800 Subject: [PATCH 26/39] docs Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener.proto | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index b2993d34363f7..556c4c87bffe2 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -124,12 +124,12 @@ message Listener { // Unified matcher resolving the filter chain name from the network properties. This matcher is used as a replacement // for the per-filter chain match condition - // :ref:`filter_chain_match `. + // :ref:`filter_chain_match `. // If specified, all :ref:`filter_chains ` must // have non-empty and unique :ref:`name ` fields and omit - // :ref:`filter_chain_match ` field. + // :ref:`filter_chain_match ` field. // - // The list of available matching inputs is available :ref:`here `. + // The list of available matching inputs is available :ref:`here `. // // Example: The following matcher selects three filter chains as follows: // From 65143c59e245c1eafbdb50211be3256555a07b2d Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Thu, 3 Mar 2022 11:50:22 -0800 Subject: [PATCH 27/39] typo Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index 556c4c87bffe2..76c20496630f9 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -122,14 +122,14 @@ message Listener { // :ref:`FAQ entry `. repeated FilterChain filter_chains = 3; - // Unified matcher resolving the filter chain name from the network properties. This matcher is used as a replacement + // :ref:`Unified matcher ` resolving the filter chain name from the network properties. This matcher is used as a replacement // for the per-filter chain match condition // :ref:`filter_chain_match `. // If specified, all :ref:`filter_chains ` must // have non-empty and unique :ref:`name ` fields and omit // :ref:`filter_chain_match ` field. // - // The list of available matching inputs is available :ref:`here `. + // The list of matching inputs is available :ref:`here `. // // Example: The following matcher selects three filter chains as follows: // From d661a00c2e23c92489d36e26882cb56f185f981e Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Mon, 7 Mar 2022 10:36:59 -0800 Subject: [PATCH 28/39] fix test Signed-off-by: Kuat Yessenov --- test/server/listener_manager_impl_test.cc | 25 +++++++++++------------ 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/test/server/listener_manager_impl_test.cc b/test/server/listener_manager_impl_test.cc index 48035976d6ec8..6f87a0dc7aced 100644 --- a/test/server/listener_manager_impl_test.cc +++ b/test/server/listener_manager_impl_test.cc @@ -560,7 +560,7 @@ bind_to_port: false EXPECT_EQ(1UL, server_.stats_store_.counterFromString("listener.127.0.0.1_1234.foo").value()); } -TEST_F(ListenerManagerImplTest, RejectIpv4CompatOnIpv4Address) { +TEST_P(ListenerManagerImplTest, RejectIpv4CompatOnIpv4Address) { const std::string yaml = R"EOF( name: "foo" address: @@ -572,13 +572,12 @@ TEST_F(ListenerManagerImplTest, RejectIpv4CompatOnIpv4Address) { - filters: [] )EOF"; - EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), - EnvoyException, + EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "Only IPv6 address '::' or valid IPv4-mapped IPv6 address can set " "ipv4_compat: 0.0.0.0:13333"); } -TEST_F(ListenerManagerImplTest, AcceptIpv4CompatOnIpv4Address) { +TEST_P(ListenerManagerImplTest, AcceptIpv4CompatOnIpv4Address) { auto scoped_runtime_guard = std::make_unique(); Runtime::LoaderSingleton::getExisting()->mergeValues( {{"envoy.reloadable_features.strict_check_on_ipv4_compat", "false"}}); @@ -593,10 +592,10 @@ TEST_F(ListenerManagerImplTest, AcceptIpv4CompatOnIpv4Address) { - filters: [] )EOF"; - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(yaml))); } -TEST_F(ListenerManagerImplTest, RejectIpv4CompatOnNonIpv4MappedIpv6address) { +TEST_P(ListenerManagerImplTest, RejectIpv4CompatOnNonIpv4MappedIpv6address) { const std::string yaml = R"EOF( name: "foo" address: @@ -609,11 +608,11 @@ TEST_F(ListenerManagerImplTest, RejectIpv4CompatOnNonIpv4MappedIpv6address) { )EOF"; EXPECT_THROW_WITH_MESSAGE( - manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true), EnvoyException, + addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "Only IPv6 address '::' or valid IPv4-mapped IPv6 address can set ipv4_compat: [::1]:13333"); } -TEST_F(ListenerManagerImplTest, AcceptIpv4CompatOnIpv6AnyAddress) { +TEST_P(ListenerManagerImplTest, AcceptIpv4CompatOnIpv6AnyAddress) { const std::string yaml = R"EOF( name: "foo" address: @@ -625,10 +624,10 @@ TEST_F(ListenerManagerImplTest, AcceptIpv4CompatOnIpv6AnyAddress) { - filters: [] )EOF"; - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(yaml))); } -TEST_F(ListenerManagerImplTest, AcceptIpv4CompatOnNonCanonicalIpv6AnyAddress) { +TEST_P(ListenerManagerImplTest, AcceptIpv4CompatOnNonCanonicalIpv6AnyAddress) { const std::string yaml = R"EOF( name: "foo" address: @@ -640,10 +639,10 @@ TEST_F(ListenerManagerImplTest, AcceptIpv4CompatOnNonCanonicalIpv6AnyAddress) { - filters: [] )EOF"; - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(yaml))); } -TEST_F(ListenerManagerImplTest, AcceptIpv4CompatOnNonIpv4MappedIpv6address) { +TEST_P(ListenerManagerImplTest, AcceptIpv4CompatOnNonIpv4MappedIpv6address) { auto scoped_runtime_guard = std::make_unique(); Runtime::LoaderSingleton::getExisting()->mergeValues( {{"envoy.reloadable_features.strict_check_on_ipv4_compat", "false"}}); @@ -658,7 +657,7 @@ TEST_F(ListenerManagerImplTest, AcceptIpv4CompatOnNonIpv4MappedIpv6address) { - filters: [] )EOF"; - EXPECT_TRUE(manager_->addOrUpdateListener(parseListenerFromV3Yaml(yaml), "", true)); + EXPECT_TRUE(addOrUpdateListener(parseListenerFromV3Yaml(yaml))); } TEST_P(ListenerManagerImplTest, UnsupportedInternalListener) { From 2e640a2b0f5a49c7cfe2af74cd82872a4dbd1e92 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Mon, 7 Mar 2022 10:51:06 -0800 Subject: [PATCH 29/39] enable more tests Signed-off-by: Kuat Yessenov --- test/server/listener_manager_impl_test.cc | 109 ++++++++++------------ 1 file changed, 47 insertions(+), 62 deletions(-) diff --git a/test/server/listener_manager_impl_test.cc b/test/server/listener_manager_impl_test.cc index 6f87a0dc7aced..f653089f00d8e 100644 --- a/test/server/listener_manager_impl_test.cc +++ b/test/server/listener_manager_impl_test.cc @@ -3603,40 +3603,35 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); - // IPv4 client connects to exact IP match - using 2nd filter chain. - auto filter_chain = findFilterChain(1234, "192.168.0.1", "", "tls", {}, "127.0.0.1", 111); + // UDS client connects - using 1st filter chain with no IP match + auto filter_chain = findFilterChain(1234, "127.0.0.1", "", "tls", {}, "127.0.0.1", 111); ASSERT_NE(filter_chain, nullptr); EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); auto transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); auto ssl_socket = dynamic_cast(transport_socket.get()); + auto uri = ssl_socket->ssl()->uriSanLocalCertificate(); + EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); + + // IPv4 client connects to default IP - using 1st filter chain. + filter_chain = findFilterChain(1234, "127.0.0.1", "", "tls", {}, "127.0.0.1", 111); + ASSERT_NE(filter_chain, nullptr); + EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); + transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); + ssl_socket = dynamic_cast(transport_socket.get()); + uri = ssl_socket->ssl()->uriSanLocalCertificate(); + EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); + + // IPv4 client connects to exact IP match - using 2nd filter chain. + filter_chain = findFilterChain(1234, "192.168.0.1", "", "tls", {}, "127.0.0.1", 111); + ASSERT_NE(filter_chain, nullptr); + EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); + transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); + ssl_socket = dynamic_cast(transport_socket.get()); auto server_names = ssl_socket->ssl()->dnsSansLocalCertificate(); EXPECT_EQ(server_names.size(), 1); EXPECT_EQ(server_names.front(), "server1.example.com"); - // UDS client connects - using 1st filter chain with no IP match - // TODO(kyessenov): Implement on_no_match for custom matchers. - if (!matcher_) { - filter_chain = findFilterChain(1234, "127.0.0.1", "", "tls", {}, "127.0.0.1", 111); - ASSERT_NE(filter_chain, nullptr); - EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); - transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); - ssl_socket = - dynamic_cast(transport_socket.get()); - auto uri = ssl_socket->ssl()->uriSanLocalCertificate(); - EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); - - // IPv4 client connects to default IP - using 1st filter chain. - filter_chain = findFilterChain(1234, "127.0.0.1", "", "tls", {}, "127.0.0.1", 111); - ASSERT_NE(filter_chain, nullptr); - EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); - transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); - ssl_socket = - dynamic_cast(transport_socket.get()); - uri = ssl_socket->ssl()->uriSanLocalCertificate(); - EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); - } - // IPv4 client connects to wildcard IP match - using 3rd filter chain. filter_chain = findFilterChain(1234, "192.168.1.1", "", "tls", {}, "192.168.1.1", 111); ASSERT_NE(filter_chain, nullptr); @@ -3648,17 +3643,13 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati EXPECT_EQ(server_names.front(), "*.example.com"); // UDS client - using 1st filter chain. - // TODO(kyessenov): Implement on_no_match for custom matchers. - if (!matcher_) { - filter_chain = findFilterChain(0, "/tmp/test.sock", "", "tls", {}, "/tmp/test.sock", 111); - ASSERT_NE(filter_chain, nullptr); - EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); - transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); - ssl_socket = - dynamic_cast(transport_socket.get()); - auto uri = ssl_socket->ssl()->uriSanLocalCertificate(); - EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); - } + filter_chain = findFilterChain(0, "/tmp/test.sock", "", "tls", {}, "/tmp/test.sock", 111); + ASSERT_NE(filter_chain, nullptr); + EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); + transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); + ssl_socket = dynamic_cast(transport_socket.get()); + uri = ssl_socket->ssl()->uriSanLocalCertificate(); + EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); } TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDirectSourceIPMatch) { @@ -3749,14 +3740,31 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDirectSou addOrUpdateListener(parseListenerFromV3Yaml(yaml)); EXPECT_EQ(1U, manager_->listeners().size()); - // IPv4 client connects to exact IP match - using 2nd filter chain. - auto filter_chain = - findFilterChain(1234, "127.0.0.1", "", "tls", {}, "127.0.0.1", 111, "192.168.0.1"); + // UDS client connects - using 1st filter chain with no IP match + auto filter_chain = findFilterChain(1234, "/uds_1", "", "tls", {}, "/uds_2", 111, "/uds_3"); ASSERT_NE(filter_chain, nullptr); EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); auto transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); auto ssl_socket = dynamic_cast(transport_socket.get()); + auto uri = ssl_socket->ssl()->uriSanLocalCertificate(); + EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); + + // IPv4 client connects to default IP - using 1st filter chain. + filter_chain = findFilterChain(1234, "127.0.0.1", "", "tls", {}, "127.0.0.1", 111, "127.0.0.1"); + ASSERT_NE(filter_chain, nullptr); + EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); + transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); + ssl_socket = dynamic_cast(transport_socket.get()); + uri = ssl_socket->ssl()->uriSanLocalCertificate(); + EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); + + // IPv4 client connects to exact IP match - using 2nd filter chain. + filter_chain = findFilterChain(1234, "127.0.0.1", "", "tls", {}, "127.0.0.1", 111, "192.168.0.1"); + ASSERT_NE(filter_chain, nullptr); + EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); + transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); + ssl_socket = dynamic_cast(transport_socket.get()); auto server_names = ssl_socket->ssl()->dnsSansLocalCertificate(); EXPECT_EQ(server_names.size(), 1); EXPECT_EQ(server_names.front(), "server1.example.com"); @@ -3770,29 +3778,6 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDirectSou server_names = ssl_socket->ssl()->dnsSansLocalCertificate(); EXPECT_EQ(server_names.size(), 2); EXPECT_EQ(server_names.front(), "*.example.com"); - - // TODO(kyessenov): Implement on_no_match for custom matchers. - if (!matcher_) { - // UDS client connects - using 1st filter chain with no IP match - filter_chain = findFilterChain(1234, "/uds_1", "", "tls", {}, "/uds_2", 111, "/uds_3"); - ASSERT_NE(filter_chain, nullptr); - EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); - transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); - ssl_socket = - dynamic_cast(transport_socket.get()); - auto uri = ssl_socket->ssl()->uriSanLocalCertificate(); - EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); - - // IPv4 client connects to default IP - using 1st filter chain. - filter_chain = findFilterChain(1234, "127.0.0.1", "", "tls", {}, "127.0.0.1", 111, "127.0.0.1"); - ASSERT_NE(filter_chain, nullptr); - EXPECT_TRUE(filter_chain->transportSocketFactory().implementsSecureTransport()); - transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); - ssl_socket = - dynamic_cast(transport_socket.get()); - uri = ssl_socket->ssl()->uriSanLocalCertificate(); - EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); - } } TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithServerNamesMatch) { From 9bac3392c93b17567fc693d6b411ff0666534ef1 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Mon, 7 Mar 2022 11:02:09 -0800 Subject: [PATCH 30/39] enable more tests Signed-off-by: Kuat Yessenov --- test/server/listener_manager_impl_test.cc | 20 ++++++++++++-------- test/server/listener_manager_impl_test.h | 1 + 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/test/server/listener_manager_impl_test.cc b/test/server/listener_manager_impl_test.cc index f653089f00d8e..e9a9dd5ad2a04 100644 --- a/test/server/listener_manager_impl_test.cc +++ b/test/server/listener_manager_impl_test.cc @@ -4215,9 +4215,6 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithInvalidServe } TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithSameMatch) { - if (matcher_) { - GTEST_SKIP() << "Unified matcher allows duplicated or missing filter chain match messages"; - } const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } @@ -4233,6 +4230,10 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithSameMatch )EOF", Network::Address::IpVersion::v4); + if (matcher_) { + EXPECT_NO_THROW(addOrUpdateListener(parseListenerFromV3Yaml(yaml))); + return; + } EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "error adding listener '127.0.0.1:1234': filter chain 'bar' has " "the same matching rules defined as 'foo'"); @@ -4262,22 +4263,25 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, } TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithOverlappingRules) { - if (matcher_) { - GTEST_SKIP() << "Unified matcher ignores filter chain match messages"; - } const std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: - name: "envoy.filters.listener.tls_inspector" filter_chains: - - filter_chain_match: + - name: foo + filter_chain_match: server_names: "example.com" - - filter_chain_match: + - name: bar + filter_chain_match: server_names: ["example.com", "www.example.com"] )EOF", Network::Address::IpVersion::v4); + if (matcher_) { + EXPECT_NO_THROW(addOrUpdateListener(parseListenerFromV3Yaml(yaml))); + return; + } EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "error adding listener '127.0.0.1:1234': multiple filter chains with " "overlapping matching rules are defined"); diff --git a/test/server/listener_manager_impl_test.h b/test/server/listener_manager_impl_test.h index 88dd260f7904e..aa95cdc5468a0 100644 --- a/test/server/listener_manager_impl_test.h +++ b/test/server/listener_manager_impl_test.h @@ -353,6 +353,7 @@ class ListenerManagerImplTest : public testing::TestWithParam { uint64_t listener_tag_{1}; bool enable_dispatcher_stats_{false}; NiceMock> callback_; + // Test parameter indicating whether the unified filter chain matcher is enabled. bool matcher_; }; } // namespace Server From 2d24544ea29762f5aa6116e3a9d2248f994169f5 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Tue, 8 Mar 2022 15:08:11 -0800 Subject: [PATCH 31/39] docs Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener.proto | 4 +- .../advanced/matching/inputs.rst | 38 +++++++++++++++++++ .../advanced/matching/matching.rst | 3 ++ 3 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 docs/root/intro/arch_overview/advanced/matching/inputs.rst diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index 76c20496630f9..e8f13a9a955f1 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -122,14 +122,14 @@ message Listener { // :ref:`FAQ entry `. repeated FilterChain filter_chains = 3; - // :ref:`Unified matcher ` resolving the filter chain name from the network properties. This matcher is used as a replacement + // :ref:`Unified matcher ` resolving the filter chain name from the network properties. This matcher is used as a replacement // for the per-filter chain match condition // :ref:`filter_chain_match `. // If specified, all :ref:`filter_chains ` must // have non-empty and unique :ref:`name ` fields and omit // :ref:`filter_chain_match ` field. // - // The list of matching inputs is available :ref:`here `. + // The list of matching inputs is available :ref:`here `. // // Example: The following matcher selects three filter chains as follows: // diff --git a/docs/root/intro/arch_overview/advanced/matching/inputs.rst b/docs/root/intro/arch_overview/advanced/matching/inputs.rst new file mode 100644 index 0000000000000..6f5b479fd6daf --- /dev/null +++ b/docs/root/intro/arch_overview/advanced/matching/inputs.rst @@ -0,0 +1,38 @@ +.. _arch_overview_matching_inputs: + +Matching Inputs +=============== + +Matching inputs define a way to extract an input value used for matching using +one of the pre-defined (exact, prefix) or a custom matching algorithm. The +input functions are context-sensitive. For example, HTTP header inputs are +applicable only in HTTP contexts, e.g. for matching HTTP requests. + +.. _arch_overview_matching_http_inputs: + +HTTP Input Functions +#################### + +These input are available for matching HTTP requests. + +* :ref:`Request header value `. +* :ref:`Request trailer value `. +* :ref:`Response header value `. +* :ref:`Response trailer value `. + +.. _arch_overview_matching_network_inputs: + +Network Input Functions +####################### + +These input functions are available for matching TCP connections. + +* :ref:`Destination IP `. +* :ref:`Destination port `. +* :ref:`Source IP `. +* :ref:`Direct source IP `. +* :ref:`Source port `. +* :ref:`Source type `. +* :ref:`Server name `. +* :ref:`Transport protocol `. +* :ref:`Application protocol `. diff --git a/docs/root/intro/arch_overview/advanced/matching/matching.rst b/docs/root/intro/arch_overview/advanced/matching/matching.rst index a08746363104a..ba493e6612668 100644 --- a/docs/root/intro/arch_overview/advanced/matching/matching.rst +++ b/docs/root/intro/arch_overview/advanced/matching/matching.rst @@ -1,3 +1,5 @@ +.. _arch_overview_matching: + Generic Matching ================ @@ -5,3 +7,4 @@ Generic Matching :maxdepth: 2 matching_api + inputs From 2015ccf434241375fead3696d3587313ee610cd9 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Thu, 24 Mar 2022 13:55:53 -0700 Subject: [PATCH 32/39] code fixes Signed-off-by: Kuat Yessenov --- api/envoy/config/listener/v3/listener.proto | 70 ++-------------- .../advanced/matching/matching.rst | 3 - docs/root/version_history/current.rst | 1 - .../listener_manager_impl_quic_only_test.cc | 2 +- test/server/listener_manager_impl_test.cc | 81 ++++++++++++------- test/server/listener_manager_impl_test.h | 6 +- 6 files changed, 64 insertions(+), 99 deletions(-) diff --git a/api/envoy/config/listener/v3/listener.proto b/api/envoy/config/listener/v3/listener.proto index e8f13a9a955f1..b4ef416e00a26 100644 --- a/api/envoy/config/listener/v3/listener.proto +++ b/api/envoy/config/listener/v3/listener.proto @@ -122,68 +122,14 @@ message Listener { // :ref:`FAQ entry `. repeated FilterChain filter_chains = 3; - // :ref:`Unified matcher ` resolving the filter chain name from the network properties. This matcher is used as a replacement - // for the per-filter chain match condition - // :ref:`filter_chain_match `. - // If specified, all :ref:`filter_chains ` must - // have non-empty and unique :ref:`name ` fields and omit - // :ref:`filter_chain_match ` field. - // - // The list of matching inputs is available :ref:`here `. - // - // Example: The following matcher selects three filter chains as follows: - // - // * if the destination port is 80, then the filter chain "http" is selected; - // * if the destination port is 443 and the source IP is in the range 192.0.0.0/2, then the filter chain "internal" is selected; - // * otherwise, if the destination port is 443, then the filter chain "https" is selected; - // * otherwise, the default filter chain is selected (or the connection is rejected without the default filter chain). - // - // .. validated-code-block:: yaml - // :type-name: envoy.config.listener.v3.Listener - // - // filter_chain_matcher: - // matcher_tree: - // input: - // name: port - // typed_config: - // "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput - // exact_match_map: - // map: - // "80": - // action: - // name: http - // typed_config: - // "@type": type.googleapis.com/google.protobuf.StringValue - // value: http - // "443": - // matcher: - // matcher_tree: - // input: - // name: ip - // typed_config: - // "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.SourceIPInput - // custom_match: - // name: ip-matcher - // typed_config: - // "@type": type.googleapis.com/xds.type.matcher.v3.IPMatcher - // range_matchers: - // - ranges: - // - address_prefix: 192.0.0.0 - // prefix_len: 2 - // on_match: - // action: - // name: internal - // typed_config: - // "@type": type.googleapis.com/google.protobuf.StringValue - // value: internal - // - ranges: - // - address_prefix: 0.0.0.0 - // on_match: - // action: - // name: https - // typed_config: - // "@type": type.googleapis.com/google.protobuf.StringValue - // value: https + // :ref:`Matcher API ` resolving the filter chain name from the + // network properties. This matcher is used as a replacement for the filter chain match condition + // :ref:`filter_chain_match + // `. If specified, all + // :ref:`filter_chains ` must have a + // non-empty and unique :ref:`name ` field + // and not specify :ref:`filter_chain_match + // ` field. // // .. note:: // diff --git a/docs/root/intro/arch_overview/advanced/matching/matching.rst b/docs/root/intro/arch_overview/advanced/matching/matching.rst index ba493e6612668..a08746363104a 100644 --- a/docs/root/intro/arch_overview/advanced/matching/matching.rst +++ b/docs/root/intro/arch_overview/advanced/matching/matching.rst @@ -1,5 +1,3 @@ -.. _arch_overview_matching: - Generic Matching ================ @@ -7,4 +5,3 @@ Generic Matching :maxdepth: 2 matching_api - inputs diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index 039d37d95499e..83f235563ead2 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -112,7 +112,6 @@ New Features * http3: add :ref:`enable_early_data ` to turn on/off downstream early data support. * http3: downstream HTTP/3 support is now GA! Upstream HTTP/3 also GA for specific deployments. See :ref:`here ` for details. * http3: supports upstream HTTP/3 retries. Automatically retry `0-RTT safe requests `_ if they are rejected because they are sent `too early `_. And automatically retry 0-RTT safe requests if connect attempt fails later on and the cluster is configured with TCP fallback. And add retry on ``http3-post-connect-failure`` policy which allows retry of failed HTTP/3 requests with TCP fallback even after handshake if the cluster is configured with TCP fallback. This feature is guarded by ``envoy.reloadable_features.conn_pool_new_stream_with_early_data_and_http3``. -* matching: add experimental support for matching filter chains in a listener using the matching API. * local_ratelimit: added support for sharing the rate limiter between multiple network filter chains or listeners via :ref:`share_key `. * local_ratelimit: added support for X-RateLimit-* headers as defined in `draft RFC `_. * matching: the matching API can now express a match tree that will always match by omitting a matcher at the top level. diff --git a/test/server/listener_manager_impl_quic_only_test.cc b/test/server/listener_manager_impl_quic_only_test.cc index 7a8110ddfc616..8b3485ca663e0 100644 --- a/test/server/listener_manager_impl_quic_only_test.cc +++ b/test/server/listener_manager_impl_quic_only_test.cc @@ -72,7 +72,7 @@ TEST_P(ListenerManagerImplQuicOnlyTest, QuicListenerFactoryAndSslContext) { quic_options: {} )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { yaml = yaml + R"EOF( filter_chain_matcher: matcher_tree: diff --git a/test/server/listener_manager_impl_test.cc b/test/server/listener_manager_impl_test.cc index 1bf66383ca90b..0504c5928efe7 100644 --- a/test/server/listener_manager_impl_test.cc +++ b/test/server/listener_manager_impl_test.cc @@ -2587,7 +2587,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDestinationP private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { yaml = yaml + R"EOF( filter_chain_matcher: matcher_tree: @@ -2652,7 +2652,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDirectSource private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { yaml = yaml + R"EOF( filter_chain_matcher: matcher_tree: @@ -2722,7 +2722,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithDestinationI private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { yaml = yaml + R"EOF( filter_chain_matcher: matcher_tree: @@ -2792,7 +2792,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithServerNamesM private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { yaml = yaml + R"EOF( filter_chain_matcher: matcher_tree: @@ -2857,7 +2857,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithTransportPro private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { yaml = yaml + R"EOF( filter_chain_matcher: matcher_tree: @@ -2918,7 +2918,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithApplicationP private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { // TODO(kyessenov) Switch to using prefix/suffix/containment matching for ALPN. yaml = yaml + R"EOF( filter_chain_matcher: @@ -2983,7 +2983,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceTypeMa private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { yaml = yaml + R"EOF( filter_chain_matcher: matcher_tree: @@ -3062,7 +3062,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceIpMatc private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { yaml = yaml + R"EOF( filter_chain_matcher: matcher_tree: @@ -3146,7 +3146,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourceIpv6Ma private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { yaml = yaml + R"EOF( filter_chain_matcher: matcher_tree: @@ -3209,7 +3209,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithSourcePortMa private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { yaml = yaml + R"EOF( filter_chain_matcher: matcher_tree: @@ -3296,7 +3296,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithSourceTyp private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_multiple_dns_key.pem" } )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { // TODO(kyessenov) Switch to using prefix/suffix/containment matching for ALPN. yaml = yaml + R"EOF( filter_chain_matcher: @@ -3440,7 +3440,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_multiple_dns_key.pem" } )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { yaml = yaml + R"EOF( filter_chain_matcher: matcher_tree: @@ -3558,7 +3558,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_multiple_dns_key.pem" } )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { yaml = yaml + R"EOF( filter_chain_matcher: matcher_tree: @@ -3695,7 +3695,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDirectSou private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_multiple_dns_key.pem" } )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { yaml = yaml + R"EOF( filter_chain_matcher: matcher_tree: @@ -3781,7 +3781,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDirectSou } TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithServerNamesMatch) { - if (matcher_) { + if (use_matcher_) { GTEST_SKIP() << "Server name matching not implemented for unified matcher"; } const std::string yaml = TestEnvironment::substitute(R"EOF( @@ -3904,7 +3904,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithTransport private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { yaml = yaml + R"EOF( filter_chain_matcher: matcher_tree: @@ -3952,18 +3952,17 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithTransport } TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithApplicationProtocolMatch) { - if (matcher_) { - GTEST_SKIP() << "ALPN list matching not implemented for unified matcher"; - } - const std::string yaml = TestEnvironment::substitute(R"EOF( + std::string yaml = TestEnvironment::substitute(R"EOF( address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: - name: "envoy.filters.listener.tls_inspector" filter_chains: - - filter_chain_match: + - name: foo + filter_chain_match: # empty - - filter_chain_match: + - name: bar + filter_chain_match: application_protocols: ["dummy", "h2"] transport_socket: name: tls @@ -3974,7 +3973,31 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithApplicati - certificate_chain: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_cert.pem" } private_key: { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_key.pem" } )EOF", - Network::Address::IpVersion::v4); + Network::Address::IpVersion::v4); + if (use_matcher_) { + yaml = yaml + R"EOF( + filter_chain_matcher: + matcher_tree: + input: + name: transport + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.ApplicationProtocolInput + exact_match_map: + map: + "'h2','http/1.1'": + action: + name: bar + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: bar + on_no_match: + action: + name: foo + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: foo + )EOF"; + } EXPECT_CALL(server_.api_.random_, uuid()); EXPECT_CALL(listener_factory_, createListenSocket(_, _, _, default_bind_type, _, 0)); @@ -4002,7 +4025,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithApplicati } TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithMultipleRequirementsMatch) { - if (matcher_) { + if (use_matcher_) { GTEST_SKIP() << "ALPN list and server name matching not implemented for unified matcher"; } const std::string yaml = TestEnvironment::substitute(R"EOF( @@ -4165,7 +4188,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithInvalidDesti )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { yaml = yaml + R"EOF( filter_chain_matcher: matcher_tree: @@ -4195,7 +4218,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithInvalidDesti } TEST_P(ListenerManagerImplWithRealFiltersTest, SingleFilterChainWithInvalidServerNamesMatch) { - if (matcher_) { + if (use_matcher_) { GTEST_SKIP() << "Server name matching not implemented for unified matcher"; } const std::string yaml = TestEnvironment::substitute(R"EOF( @@ -4230,7 +4253,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithSameMatch )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { EXPECT_NO_THROW(addOrUpdateListener(parseListenerFromV3Yaml(yaml))); return; } @@ -4278,7 +4301,7 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithOverlappi )EOF", Network::Address::IpVersion::v4); - if (matcher_) { + if (use_matcher_) { EXPECT_NO_THROW(addOrUpdateListener(parseListenerFromV3Yaml(yaml))); return; } @@ -5521,7 +5544,7 @@ name: test_api_listener_2 } TEST_P(ListenerManagerImplWithRealFiltersTest, AddOrUpdateInternalListener) { - if (matcher_) { + if (use_matcher_) { GTEST_SKIP() << "Filter chain match is auto-inserted in the config dump"; } auto scoped_runtime = std::make_unique(); diff --git a/test/server/listener_manager_impl_test.h b/test/server/listener_manager_impl_test.h index aa95cdc5468a0..7923e8397b077 100644 --- a/test/server/listener_manager_impl_test.h +++ b/test/server/listener_manager_impl_test.h @@ -65,7 +65,7 @@ class ListenerManagerImplTest : public testing::TestWithParam { protected: ListenerManagerImplTest() - : api_(Api::createApiForTest(server_.api_.random_)), matcher_(GetParam()) {} + : api_(Api::createApiForTest(server_.api_.random_)), use_matcher_(GetParam()) {} void SetUp() override { ON_CALL(server_, api()).WillByDefault(ReturnRef(*api_)); @@ -307,7 +307,7 @@ class ListenerManagerImplTest : public testing::TestWithParam { // Automatically inject a matcher that always matches "foo" if not present. envoy::config::listener::v3::Listener listener; listener.MergeFrom(config); - if (matcher_ && !listener.has_filter_chain_matcher()) { + if (use_matcher_ && !listener.has_filter_chain_matcher()) { const std::string filter_chain_matcher = R"EOF( matcher_tree: input: @@ -354,7 +354,7 @@ class ListenerManagerImplTest : public testing::TestWithParam { bool enable_dispatcher_stats_{false}; NiceMock> callback_; // Test parameter indicating whether the unified filter chain matcher is enabled. - bool matcher_; + bool use_matcher_; }; } // namespace Server } // namespace Envoy From 5ab50c6533adba70a5abd8a5b3907737bc307027 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Thu, 24 Mar 2022 18:02:42 -0700 Subject: [PATCH 33/39] docs Signed-off-by: Kuat Yessenov --- .../_include/listener-complicated.yaml | 43 +++++++++++++++++++ .../advanced/matching/inputs.rst | 38 ---------------- .../advanced/matching/matching.rst | 1 + .../advanced/matching/matching_listener.rst | 32 ++++++++++++++ 4 files changed, 76 insertions(+), 38 deletions(-) create mode 100644 docs/root/intro/arch_overview/advanced/matching/_include/listener-complicated.yaml delete mode 100644 docs/root/intro/arch_overview/advanced/matching/inputs.rst create mode 100644 docs/root/intro/arch_overview/advanced/matching/matching_listener.rst diff --git a/docs/root/intro/arch_overview/advanced/matching/_include/listener-complicated.yaml b/docs/root/intro/arch_overview/advanced/matching/_include/listener-complicated.yaml new file mode 100644 index 0000000000000..85ba4a363063d --- /dev/null +++ b/docs/root/intro/arch_overview/advanced/matching/_include/listener-complicated.yaml @@ -0,0 +1,43 @@ + filter_chain_matcher: + matcher_tree: + input: + name: port + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput + exact_match_map: + map: + "80": + action: + name: http + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: http + "443": + matcher: + matcher_tree: + input: + name: ip + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.SourceIPInput + custom_match: + name: ip-matcher + typed_config: + "@type": type.googleapis.com/xds.type.matcher.v3.IPMatcher + range_matchers: + - ranges: + - address_prefix: 192.0.0.0 + prefix_len: 2 + on_match: + action: + name: internal + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: internal + - ranges: + - address_prefix: 0.0.0.0 + on_match: + action: + name: https + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: https diff --git a/docs/root/intro/arch_overview/advanced/matching/inputs.rst b/docs/root/intro/arch_overview/advanced/matching/inputs.rst deleted file mode 100644 index 6f5b479fd6daf..0000000000000 --- a/docs/root/intro/arch_overview/advanced/matching/inputs.rst +++ /dev/null @@ -1,38 +0,0 @@ -.. _arch_overview_matching_inputs: - -Matching Inputs -=============== - -Matching inputs define a way to extract an input value used for matching using -one of the pre-defined (exact, prefix) or a custom matching algorithm. The -input functions are context-sensitive. For example, HTTP header inputs are -applicable only in HTTP contexts, e.g. for matching HTTP requests. - -.. _arch_overview_matching_http_inputs: - -HTTP Input Functions -#################### - -These input are available for matching HTTP requests. - -* :ref:`Request header value `. -* :ref:`Request trailer value `. -* :ref:`Response header value `. -* :ref:`Response trailer value `. - -.. _arch_overview_matching_network_inputs: - -Network Input Functions -####################### - -These input functions are available for matching TCP connections. - -* :ref:`Destination IP `. -* :ref:`Destination port `. -* :ref:`Source IP `. -* :ref:`Direct source IP `. -* :ref:`Source port `. -* :ref:`Source type `. -* :ref:`Server name `. -* :ref:`Transport protocol `. -* :ref:`Application protocol `. diff --git a/docs/root/intro/arch_overview/advanced/matching/matching.rst b/docs/root/intro/arch_overview/advanced/matching/matching.rst index a08746363104a..c4b4e20eaf871 100644 --- a/docs/root/intro/arch_overview/advanced/matching/matching.rst +++ b/docs/root/intro/arch_overview/advanced/matching/matching.rst @@ -5,3 +5,4 @@ Generic Matching :maxdepth: 2 matching_api + matching_listener diff --git a/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst b/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst new file mode 100644 index 0000000000000..cbe764569253f --- /dev/null +++ b/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst @@ -0,0 +1,32 @@ +.. _arch_overview_matching_listener: + +Matching filter chains in listeners +=================================== + +Envoy listeners implement the :ref:`matching API ` for selecting a filter +chain based on a collection of :ref:`network inputs <_extension_category_envoy.matching.network.input>`. Matching is +done once per connection. Connections are drained when the associated named filter chain configuration changes, but not +when the filter chain matcher is the only updated field in a listener. + +The action in the matcher API must be a string value corresponding to the name of the filter chain. If there is no +filter chain with the given name, the match fails, and the :ref:`default filter chain +` is used if specified, or the connection is +rejected. Filter chain matcher requires that all filter chains in a listener are uniquely named. + +The matcher API replaces the existing filter :ref:`filter_chain_match +` field. When using the matcher API, the filter +chain match field is ignored and should not be set. + +Examples +######## + +Multiple conditions +******************* + +* if the destination port is 80, then the filter chain "http" is selected; +* if the destination port is 443 and the source IP is in the range 192.0.0.0/2, then the filter chain "internal" is selected; +* otherwise, if the destination port is 443, then the filter chain "https" is selected; +* otherwise, the default filter chain is selected (or the connection is rejected without the default filter chain). + +.. literalinclude:: _include/listener-complicated.yaml + :language: yaml From b32362e7413d63ea6fb18725130b3c1ba70d206f Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Thu, 24 Mar 2022 20:48:50 -0700 Subject: [PATCH 34/39] update docs Signed-off-by: Kuat Yessenov --- .../_include/listener-complicated.yaml | 43 ------- .../_include/listener_complicated.yaml | 113 ++++++++++++++++++ .../matching/_include/listener_tls.yaml | 68 +++++++++++ .../matching/_include/listener_vip.yaml | 53 ++++++++ .../advanced/matching/matching_listener.rst | 53 ++++++-- 5 files changed, 276 insertions(+), 54 deletions(-) delete mode 100644 docs/root/intro/arch_overview/advanced/matching/_include/listener-complicated.yaml create mode 100644 docs/root/intro/arch_overview/advanced/matching/_include/listener_complicated.yaml create mode 100644 docs/root/intro/arch_overview/advanced/matching/_include/listener_tls.yaml create mode 100644 docs/root/intro/arch_overview/advanced/matching/_include/listener_vip.yaml diff --git a/docs/root/intro/arch_overview/advanced/matching/_include/listener-complicated.yaml b/docs/root/intro/arch_overview/advanced/matching/_include/listener-complicated.yaml deleted file mode 100644 index 85ba4a363063d..0000000000000 --- a/docs/root/intro/arch_overview/advanced/matching/_include/listener-complicated.yaml +++ /dev/null @@ -1,43 +0,0 @@ - filter_chain_matcher: - matcher_tree: - input: - name: port - typed_config: - "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput - exact_match_map: - map: - "80": - action: - name: http - typed_config: - "@type": type.googleapis.com/google.protobuf.StringValue - value: http - "443": - matcher: - matcher_tree: - input: - name: ip - typed_config: - "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.SourceIPInput - custom_match: - name: ip-matcher - typed_config: - "@type": type.googleapis.com/xds.type.matcher.v3.IPMatcher - range_matchers: - - ranges: - - address_prefix: 192.0.0.0 - prefix_len: 2 - on_match: - action: - name: internal - typed_config: - "@type": type.googleapis.com/google.protobuf.StringValue - value: internal - - ranges: - - address_prefix: 0.0.0.0 - on_match: - action: - name: https - typed_config: - "@type": type.googleapis.com/google.protobuf.StringValue - value: https diff --git a/docs/root/intro/arch_overview/advanced/matching/_include/listener_complicated.yaml b/docs/root/intro/arch_overview/advanced/matching/_include/listener_complicated.yaml new file mode 100644 index 0000000000000..f9cbca2977403 --- /dev/null +++ b/docs/root/intro/arch_overview/advanced/matching/_include/listener_complicated.yaml @@ -0,0 +1,113 @@ +static_resources: + listeners: + - name: outbound + address: + socket_address: + protocol: TCP + address: 0.0.0.0 + port_value: 15000 + listener_filters: + - name: original_dst + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.listener.original_dst.v3.OriginalDst + filter_chains: + - name: http + filters: + - name: http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + stat_prefix: ingress_http + route_config: + name: local_route + virtual_hosts: + - name: local_service + domains: ["*"] + routes: + - match: + prefix: "/" + route: + cluster: some_service + http_filters: + - name: router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + - name: internal + filters: + - name: tcp_proxy + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy + stat_prefix: internal + cluster: some_service + - name: tls + transport_socket: + name: tls + typed_config: + "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext + common_tls_context: + tls_certificates: + - certificate_chain: {filename: "certs/servercert.pem"} + private_key: {filename: "certs/serverkey.pem"} + filters: + - name: tcp_proxy + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy + stat_prefix: tls + cluster: some_service +# Snippet: 57-101 + filter_chain_matcher: + matcher_tree: + input: + name: port + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput + exact_match_map: + map: + "80": + action: + name: http + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: http + "443": + matcher: + matcher_tree: + input: + name: ip + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.SourceIPInput + custom_match: + name: ip-matcher + typed_config: + "@type": type.googleapis.com/xds.type.matcher.v3.IPMatcher + range_matchers: + - ranges: + - address_prefix: 192.0.0.0 + prefix_len: 2 + - address_prefix: 10.0.0.0 + prefix_len: 24 + on_match: + action: + name: internal + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: internal + - ranges: + - address_prefix: 0.0.0.0 + on_match: + action: + name: tls + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: tls + + clusters: + - name: some_service + load_assignment: + cluster_name: some_service + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: 10.1.2.10 + port_value: 10002 diff --git a/docs/root/intro/arch_overview/advanced/matching/_include/listener_tls.yaml b/docs/root/intro/arch_overview/advanced/matching/_include/listener_tls.yaml new file mode 100644 index 0000000000000..7c7337cb04a3f --- /dev/null +++ b/docs/root/intro/arch_overview/advanced/matching/_include/listener_tls.yaml @@ -0,0 +1,68 @@ +static_resources: + listeners: + - name: outbound + address: + socket_address: + protocol: TCP + address: 0.0.0.0 + port_value: 8443 + listener_filters: + - name: tls_inspector + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector + filter_chains: + - name: tls + transport_socket: + name: tls + typed_config: + "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext + common_tls_context: + tls_certificates: + - certificate_chain: {filename: "certs/servercert.pem"} + private_key: {filename: "certs/serverkey.pem"} + filters: + - name: tcp_proxy + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy + stat_prefix: tls + cluster: some_service + - name: plaintext + filters: + - name: tcp_proxy + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy + stat_prefix: plaintext + cluster: some_service +# Snippet: 37-56 + filter_chain_matcher: + matcher_tree: + input: + name: transport + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.TransportProtocolInput + exact_match_map: + map: + "tls": + action: + name: tls + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: tls + on_no_match: + action: + name: plaintext + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: plaintext + + clusters: + - name: some_service + load_assignment: + cluster_name: some_service + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: 10.1.2.10 + port_value: 10002 diff --git a/docs/root/intro/arch_overview/advanced/matching/_include/listener_vip.yaml b/docs/root/intro/arch_overview/advanced/matching/_include/listener_vip.yaml new file mode 100644 index 0000000000000..261fa84469a7b --- /dev/null +++ b/docs/root/intro/arch_overview/advanced/matching/_include/listener_vip.yaml @@ -0,0 +1,53 @@ +static_resources: + listeners: + - name: outbound + address: + socket_address: + protocol: TCP + address: 0.0.0.0 + port_value: 15000 + listener_filters: + - name: proxy_protocol + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.listener.proxy_protocol.v3.ProxyProtocol + filter_chains: + - name: vip + filters: + - name: tcp_proxy + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy + stat_prefix: vip + cluster: original_dst + - name: default + filters: + - name: tcp_proxy + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy + stat_prefix: default + cluster: original_dst +# Snippet: 29-48 + filter_chain_matcher: + matcher_tree: + input: + name: destination_ip + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationIPInput + prefix_match_map: + map: + "10.0.0.": + action: + name: vip + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: vip + on_no_match: + action: + name: default + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: default + + clusters: + - name: original_dst + type: ORIGINAL_DST + lb_policy: CLUSTER_PROVIDED diff --git a/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst b/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst index cbe764569253f..fac5d5bec87bb 100644 --- a/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst +++ b/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst @@ -1,12 +1,12 @@ .. _arch_overview_matching_listener: -Matching filter chains in listeners +Matching Filter Chains in Listeners =================================== Envoy listeners implement the :ref:`matching API ` for selecting a filter -chain based on a collection of :ref:`network inputs <_extension_category_envoy.matching.network.input>`. Matching is -done once per connection. Connections are drained when the associated named filter chain configuration changes, but not -when the filter chain matcher is the only updated field in a listener. +chain based on a collection of :ref:`network inputs `. Matching is done +once per connection. Connections are drained when the associated named filter chain configuration changes, but not when +the filter chain matcher is the only updated field in a listener. The action in the matcher API must be a string value corresponding to the name of the filter chain. If there is no filter chain with the given name, the match fails, and the :ref:`default filter chain @@ -20,13 +20,44 @@ chain match field is ignored and should not be set. Examples ######## -Multiple conditions -******************* +Detect TLS traffic +****************** -* if the destination port is 80, then the filter chain "http" is selected; -* if the destination port is 443 and the source IP is in the range 192.0.0.0/2, then the filter chain "internal" is selected; -* otherwise, if the destination port is 443, then the filter chain "https" is selected; -* otherwise, the default filter chain is selected (or the connection is rejected without the default filter chain). +The following examples uses :ref:`tls_inspector ` listener filter to detect +whether the transport appears to be TLS, in which case the matcher in the listener selects the filter chain ``tls``. +Otherwise, the filter chain ``plaintext`` is used. -.. literalinclude:: _include/listener-complicated.yaml +.. literalinclude:: _include/listener_tls.yaml :language: yaml + :linenos: + :lines: 37-56 + +Match Against the Destination IP +******************************** + +The following example assumes :ref:`PROXY protocol ` is used for incoming +traffic. If the recovered destination IP is in CIDR ``10.0.0.0/24``, then the filter chain ``vip`` is used. Otherwise, +the filter chain ``default`` is used. + +.. literalinclude:: _include/listener_vip.yaml + :language: yaml + :linenos: + :lines: 29-48 + +Match Against the Destination Port and the Source IP +**************************************************** + +The following example uses :ref:`original_dst ` listener filter to recover the +original destination port. The matcher in the listener selects one of the three filter chains ``http``, ``internal``, +and ``tls`` as follows: + +* If the destination port is ``80``, then the filter chain ``http`` accepts the connection. +* If the destination port is ``443`` and the source IP is in the range ``192.0.0.0/2`` or ``10.0.0.0/24``, then the + filter chain ``internal`` accepts the connection. If the source IP is not in the ranges then the filter chain ``tls`` + accepts the connection. +* Otherwise, the connection is rejected, because there is no default filter chain. + +.. literalinclude:: _include/listener_complicated.yaml + :language: yaml + :linenos: + :lines: 57-101 From 45a8482055a56d30b4fd6e71381518fe116f830c Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Fri, 25 Mar 2022 11:11:31 -0700 Subject: [PATCH 35/39] download button Signed-off-by: Kuat Yessenov --- .../arch_overview/advanced/matching/matching_listener.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst b/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst index fac5d5bec87bb..e800a3de5e19a 100644 --- a/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst +++ b/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst @@ -29,8 +29,8 @@ Otherwise, the filter chain ``plaintext`` is used. .. literalinclude:: _include/listener_tls.yaml :language: yaml - :linenos: :lines: 37-56 + :caption: :download:`listener_tls.yaml <_include/listener_tls.yaml>` Match Against the Destination IP ******************************** @@ -41,8 +41,8 @@ the filter chain ``default`` is used. .. literalinclude:: _include/listener_vip.yaml :language: yaml - :linenos: :lines: 29-48 + :caption: :download:`listener_vip.yaml <_include/listener_vip.yaml>` Match Against the Destination Port and the Source IP **************************************************** @@ -59,5 +59,5 @@ and ``tls`` as follows: .. literalinclude:: _include/listener_complicated.yaml :language: yaml - :linenos: :lines: 57-101 + :caption: :download:`listener_complicated.yaml <_include/listener_complicated.yaml>` From 7b971409dd9ab706420e7b23dada8e9135f1432f Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Fri, 25 Mar 2022 13:39:48 -0700 Subject: [PATCH 36/39] fix windows example Signed-off-by: Kuat Yessenov --- .../advanced/matching/_include/listener_complicated.yaml | 3 ++- .../arch_overview/advanced/matching/matching_listener.rst | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/root/intro/arch_overview/advanced/matching/_include/listener_complicated.yaml b/docs/root/intro/arch_overview/advanced/matching/_include/listener_complicated.yaml index f9cbca2977403..771699290b9c4 100644 --- a/docs/root/intro/arch_overview/advanced/matching/_include/listener_complicated.yaml +++ b/docs/root/intro/arch_overview/advanced/matching/_include/listener_complicated.yaml @@ -10,6 +10,7 @@ static_resources: - name: original_dst typed_config: "@type": type.googleapis.com/envoy.extensions.filters.listener.original_dst.v3.OriginalDst + traffic_direction: OUTBOUND filter_chains: - name: http filters: @@ -53,7 +54,7 @@ static_resources: "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy stat_prefix: tls cluster: some_service -# Snippet: 57-101 +# Snippet: 58-102 filter_chain_matcher: matcher_tree: input: diff --git a/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst b/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst index e800a3de5e19a..669e22b312868 100644 --- a/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst +++ b/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst @@ -59,5 +59,5 @@ and ``tls`` as follows: .. literalinclude:: _include/listener_complicated.yaml :language: yaml - :lines: 57-101 + :lines: 58-102 :caption: :download:`listener_complicated.yaml <_include/listener_complicated.yaml>` From e436cdfa33b9e1595b70b9db9bf65f16594bfd2d Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Sun, 10 Apr 2022 21:11:25 -0700 Subject: [PATCH 37/39] merge fix Signed-off-by: Kuat Yessenov --- source/extensions/common/matcher/BUILD | 2 -- test/server/BUILD | 1 + test/server/listener_manager_impl_test.cc | 12 +++++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/source/extensions/common/matcher/BUILD b/source/extensions/common/matcher/BUILD index 752bd005cd911..a4b96c3f92bfa 100644 --- a/source/extensions/common/matcher/BUILD +++ b/source/extensions/common/matcher/BUILD @@ -25,8 +25,6 @@ envoy_cc_extension( name = "trie_matcher_lib", srcs = ["trie_matcher.cc"], hdrs = ["trie_matcher.h"], - # IP matching is core functionality. - visibility = ["//visibility:public"], deps = [ "//envoy/matcher:matcher_interface", "//envoy/network:filter_interface", diff --git a/test/server/BUILD b/test/server/BUILD index 8fd5f64220f01..9852322591cb5 100644 --- a/test/server/BUILD +++ b/test/server/BUILD @@ -323,6 +323,7 @@ envoy_cc_test( "//source/common/protobuf", "//source/extensions/filters/listener/original_dst:config", "//source/extensions/filters/listener/proxy_protocol:config", + "//source/extensions/filters/listener/tls_inspector:config", "//source/extensions/filters/network/http_connection_manager:config", "//source/extensions/filters/network/tcp_proxy:config", "//source/extensions/request_id/uuid:config", diff --git a/test/server/listener_manager_impl_test.cc b/test/server/listener_manager_impl_test.cc index 3d1b5f09d1a37..edfa69b865112 100644 --- a/test/server/listener_manager_impl_test.cc +++ b/test/server/listener_manager_impl_test.cc @@ -25,6 +25,7 @@ #include "source/common/protobuf/protobuf.h" #include "source/extensions/common/matcher/trie_matcher.h" #include "source/extensions/filters/listener/original_dst/original_dst.h" +#include "source/extensions/filters/listener/tls_inspector/tls_inspector.h" #include "source/extensions/transport_sockets/tls/ssl_socket.h" #include "test/mocks/init/mocks.h" @@ -515,7 +516,8 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, BadFilterName) { name: foo )EOF"; - EXPECT_THROW_WITH_MESSAGE(addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, + EXPECT_THROW_WITH_MESSAGE( + addOrUpdateListener(parseListenerFromV3Yaml(yaml)), EnvoyException, "Didn't find a registered implementation for 'invalid' with type URL: ''"); } @@ -4379,7 +4381,9 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MatcherFilterChainWithoutName) { address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: - - name: "envoy.filters.listener.tls_inspector" + - name: tls_inspector + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector filter_chain_matcher: matcher_tree: input: @@ -4409,7 +4413,9 @@ TEST_P(ListenerManagerImplWithRealFiltersTest, MatcherFilterChainWithDuplicateNa address: socket_address: { address: 127.0.0.1, port_value: 1234 } listener_filters: - - name: "envoy.filters.listener.tls_inspector" + - name: tls_inspector + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector filter_chain_matcher: matcher_tree: input: From c611e2d601e5b6b1d9987cae77fc59f2565b5106 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Mon, 11 Apr 2022 13:51:14 -0700 Subject: [PATCH 38/39] review Signed-off-by: Kuat Yessenov --- .../arch_overview/advanced/matching/matching_listener.rst | 2 +- source/server/filter_chain_manager_impl.cc | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst b/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst index 669e22b312868..b02eada396b22 100644 --- a/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst +++ b/docs/root/intro/arch_overview/advanced/matching/matching_listener.rst @@ -51,7 +51,7 @@ The following example uses :ref:`original_dst second; + } else { + ENVOY_LOG(debug, "matcher API points to an absent filter chain '{}'", name.value()); } return [chain]() { return std::make_unique(chain); }; } @@ -257,6 +259,9 @@ void FilterChainManagerImpl::addFilterChains( fmt::format("error adding listener '{}': \"name\" field is duplicated with value '{}'", address_->asString(), filter_chain->name())); } + if (filter_chain->has_filter_chain_match()) { + ENVOY_LOG(debug, "filter chain match in chain '{}' is ignored", filter_chain->name()); + } } else { auto createAddressVector = [](const auto& prefix_ranges) -> std::vector { std::vector ips; From 8ac6a1d4bbc16320bed1b5118fb1523f3383cdf9 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Mon, 11 Apr 2022 14:06:28 -0700 Subject: [PATCH 39/39] fix logger Signed-off-by: Kuat Yessenov --- source/server/filter_chain_manager_impl.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/server/filter_chain_manager_impl.cc b/source/server/filter_chain_manager_impl.cc index a069368ab073b..cc54e304814dc 100644 --- a/source/server/filter_chain_manager_impl.cc +++ b/source/server/filter_chain_manager_impl.cc @@ -38,8 +38,8 @@ struct FilterChainNameAction : public Matcher::ActionBase; -class FilterChainNameActionFactory - : public Matcher::ActionFactory { +class FilterChainNameActionFactory : public Matcher::ActionFactory, + Logger::Loggable { public: std::string name() const override { return "filter-chain-name"; } Matcher::ActionFactoryCb createActionFactoryCb(const Protobuf::Message& config,