diff --git a/api/v1alpha1/connection_types.go b/api/v1alpha1/connection_types.go index efb24dc3bb..be71718c2a 100644 --- a/api/v1alpha1/connection_types.go +++ b/api/v1alpha1/connection_types.go @@ -36,6 +36,16 @@ type ClientConnection struct { // +optional // +notImplementedHide SocketBufferLimit *resource.Quantity `json:"socketBufferLimit,omitempty"` + + // MaxAcceptPerSocketEvent provides configuration for the maximum number of connections to accept from the kernel + // per socket event. If there are more than MaxAcceptPerSocketEvent connections pending accept, connections over + // this threshold will be accepted in later event loop iterations. If no value is provided Envoy will accept + // all connections pending accept from the kernel. + // It is recommended to lower this value for better overload management and reduced per-event cost. + // Setting it to 1 is a viable option with no noticeable impact on performance. + // + // +optional + MaxAcceptPerSocketEvent *uint32 `json:"maxAcceptPerSocketEvent,omitempty"` } // BackendConnection allows users to configure connection-level settings of backend diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 8486b12c3c..86d35a1146 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -904,6 +904,11 @@ func (in *ClientConnection) DeepCopyInto(out *ClientConnection) { x := (*in).DeepCopy() *out = &x } + if in.MaxAcceptPerSocketEvent != nil { + in, out := &in.MaxAcceptPerSocketEvent, &out.MaxAcceptPerSocketEvent + *out = new(uint32) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientConnection. diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml index 40c28267c8..3a48215f6a 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml @@ -153,6 +153,16 @@ spec: required: - value type: object + maxAcceptPerSocketEvent: + description: |- + MaxAcceptPerSocketEvent provides configuration for the maximum number of connections to accept from the kernel + per socket event. If there are more than MaxAcceptPerSocketEvent connections pending accept, connections over + this threshold will be accepted in later event loop iterations. If no value is provided Envoy will accept + all connections pending accept from the kernel. + It is recommended to lower this value for better overload management and reduced per-event cost. + Setting it to 1 is a viable option with no noticeable impact on performance. + format: int32 + type: integer socketBufferLimit: allOf: - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml index 0ed2172885..fd37c74bdf 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml @@ -152,6 +152,16 @@ spec: required: - value type: object + maxAcceptPerSocketEvent: + description: |- + MaxAcceptPerSocketEvent provides configuration for the maximum number of connections to accept from the kernel + per socket event. If there are more than MaxAcceptPerSocketEvent connections pending accept, connections over + this threshold will be accepted in later event loop iterations. If no value is provided Envoy will accept + all connections pending accept from the kernel. + It is recommended to lower this value for better overload management and reduced per-event cost. + Setting it to 1 is a viable option with no noticeable impact on performance. + format: int32 + type: integer socketBufferLimit: allOf: - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ diff --git a/internal/ir/xds.go b/internal/ir/xds.go index bb8c4d8186..7b2f531842 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -2966,6 +2966,8 @@ type ClientConnection struct { ConnectionLimit *ConnectionLimit `json:"limit,omitempty" yaml:"limit,omitempty"` // BufferLimitBytes is the maximum number of bytes that can be buffered for a connection. BufferLimitBytes *uint32 `json:"bufferLimit,omitempty" yaml:"bufferLimit,omitempty"` + // MaxAcceptPerSocketEvent is the maximum number of connections to accept from the kernel per socket event. + MaxAcceptPerSocketEvent *uint32 `json:"maxAcceptPerSocketEvent,omitempty" yaml:"maxAcceptPerSocketEvent,omitempty"` } // ConnectionLimit contains settings for downstream connection limits diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index 7bfbe49461..f938808c9f 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -501,6 +501,11 @@ func (in *ClientConnection) DeepCopyInto(out *ClientConnection) { *out = new(uint32) **out = **in } + if in.MaxAcceptPerSocketEvent != nil { + in, out := &in.MaxAcceptPerSocketEvent, &out.MaxAcceptPerSocketEvent + *out = new(uint32) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientConnection. diff --git a/internal/xds/translator/listener.go b/internal/xds/translator/listener.go index 459113e82c..fa1a7620df 100644 --- a/internal/xds/translator/listener.go +++ b/internal/xds/translator/listener.go @@ -197,11 +197,13 @@ func buildXdsTCPListener( return nil, err } bufferLimitBytes := buildPerConnectionBufferLimitBytes(connection) + maxAcceptPerSocketEvent := buildMaxAcceptPerSocketEvent(connection) listener := &listenerv3.Listener{ - Name: name, - AccessLog: al, - SocketOptions: socketOptions, - PerConnectionBufferLimitBytes: bufferLimitBytes, + Name: name, + AccessLog: al, + SocketOptions: socketOptions, + PerConnectionBufferLimitBytes: bufferLimitBytes, + MaxConnectionsToAcceptPerSocketEvent: maxAcceptPerSocketEvent, Address: &corev3.Address{ Address: &corev3.Address_SocketAddress{ SocketAddress: &corev3.SocketAddress{ @@ -230,6 +232,13 @@ func buildPerConnectionBufferLimitBytes(connection *ir.ClientConnection) *wrappe return wrapperspb.UInt32(tcpListenerPerConnectionBufferLimitBytes) } +func buildMaxAcceptPerSocketEvent(connection *ir.ClientConnection) *wrapperspb.UInt32Value { + if connection != nil && connection.MaxAcceptPerSocketEvent != nil { + return wrapperspb.UInt32(*connection.MaxAcceptPerSocketEvent) + } + return nil +} + // buildXdsQuicListener creates a xds Listener resource for quic func buildXdsQuicListener(name, address string, port uint32, ipFamily *egv1a1.IPFamily, accesslog *ir.AccessLog) (*listenerv3.Listener, error) { log, err := buildXdsAccessLog(accesslog, ir.ProxyAccessLogTypeListener) diff --git a/internal/xds/translator/testdata/in/xds-ir/max-conn-per-socket-event.yaml b/internal/xds/translator/testdata/in/xds-ir/max-conn-per-socket-event.yaml new file mode 100644 index 0000000000..402fef29e2 --- /dev/null +++ b/internal/xds/translator/testdata/in/xds-ir/max-conn-per-socket-event.yaml @@ -0,0 +1,36 @@ +http: + - name: "first-listener" + address: "::" + port: 10080 + hostnames: + - "*" + path: + mergeSlashes: true + escapedSlashesAction: UnescapeAndRedirect + routes: + - name: "first-route" + hostname: "*" + destination: + name: "first-route-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 50000 + name: "first-route-dest/backend/0" + connection: + maxAcceptPerSocketEvent: 2 +tcp: + - name: "second-listener" + address: "::" + connection: + maxAcceptPerSocketEvent: 3 + port: 10081 + routes: + - name: "tcp-route-dest" + destination: + name: "tcp-route-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 50000 + name: "tcp-route-dest/backend/0" diff --git a/internal/xds/translator/testdata/out/xds-ir/max-conn-per-socket-event.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/max-conn-per-socket-event.clusters.yaml new file mode 100644 index 0000000000..1b8a0dcfcd --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/max-conn-per-socket-event.clusters.yaml @@ -0,0 +1,34 @@ +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: first-route-dest + ignoreHealthOnHostRemoval: true + lbPolicy: LEAST_REQUEST + name: first-route-dest + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: tcp-route-dest + ignoreHealthOnHostRemoval: true + lbPolicy: LEAST_REQUEST + name: tcp-route-dest + perConnectionBufferLimitBytes: 32768 + type: EDS diff --git a/internal/xds/translator/testdata/out/xds-ir/max-conn-per-socket-event.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/max-conn-per-socket-event.endpoints.yaml new file mode 100644 index 0000000000..0e783f21a8 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/max-conn-per-socket-event.endpoints.yaml @@ -0,0 +1,24 @@ +- clusterName: first-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 50000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: first-route-dest/backend/0 +- clusterName: tcp-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 50000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: tcp-route-dest/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/max-conn-per-socket-event.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/max-conn-per-socket-event.listeners.yaml new file mode 100644 index 0000000000..71fca9e49d --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/max-conn-per-socket-event.listeners.yaml @@ -0,0 +1,50 @@ +- address: + socketAddress: + address: '::' + portValue: 10080 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: first-listener + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10080 + useRemoteAddress: true + name: first-listener + maxConnectionsToAcceptPerSocketEvent: 2 + name: first-listener + perConnectionBufferLimitBytes: 32768 +- address: + socketAddress: + address: '::' + portValue: 10081 + filterChains: + - filters: + - name: envoy.filters.network.tcp_proxy + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy + cluster: tcp-route-dest + statPrefix: tcp-10081 + name: tcp-route-dest + maxConnectionsToAcceptPerSocketEvent: 3 + name: second-listener + perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/max-conn-per-socket-event.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/max-conn-per-socket-event.routes.yaml new file mode 100644 index 0000000000..0b5b4bee7b --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/max-conn-per-socket-event.routes.yaml @@ -0,0 +1,14 @@ +- ignorePortInHostMatching: true + name: first-listener + virtualHosts: + - domains: + - '*' + name: first-listener/* + routes: + - match: + prefix: / + name: first-route + route: + cluster: first-route-dest + upgradeConfigs: + - upgradeType: websocket diff --git a/release-notes/current.yaml b/release-notes/current.yaml index aa805e8c84..02f0413412 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -18,6 +18,7 @@ new features: | Added support for setting ownerreference to infra resources when enable gateway namespace mode. Added support for configuring hostname in active HTTP healthchecks. Added support for GatewayInfrastructure in gateway namespace mode. + Added support for configuring maxConnectionsToAcceptPerSocketEvent in listener via ClientTrafficPolicy. Added support for setting GatewayClass ownerreference to infra resources when all cases except gateway namespace mode. Added support for setting previous priorities retry predicate. Added support for using extension server policies to in PostTranslateModify hook. diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 855ddb417c..2c736ba7d5 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -678,6 +678,7 @@ _Appears in:_ | --- | --- | --- | --- | --- | | `connectionLimit` | _[ConnectionLimit](#connectionlimit)_ | false | | ConnectionLimit defines limits related to connections | | `bufferLimit` | _[Quantity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#quantity-resource-api)_ | false | | BufferLimit provides configuration for the maximum buffer size in bytes for each incoming connection.
BufferLimit applies to connection streaming (maybe non-streaming) channel between processes, it's in user space.
For example, 20Mi, 1Gi, 256Ki etc.
Note that when the suffix is not provided, the value is interpreted as bytes.
Default: 32768 bytes. | +| `maxAcceptPerSocketEvent` | _integer_ | false | | MaxAcceptPerSocketEvent provides configuration for the maximum number of connections to accept from the kernel
per socket event. If there are more than MaxAcceptPerSocketEvent connections pending accept, connections over
this threshold will be accepted in later event loop iterations. If no value is provided Envoy will accept
all connections pending accept from the kernel.
It is recommended to lower this value for better overload management and reduced per-event cost.
Setting it to 1 is a viable option with no noticeable impact on performance. | #### ClientIPDetectionSettings diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml index 9f093bfb1b..df99ac3b33 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -20079,6 +20079,16 @@ spec: required: - value type: object + maxAcceptPerSocketEvent: + description: |- + MaxAcceptPerSocketEvent provides configuration for the maximum number of connections to accept from the kernel + per socket event. If there are more than MaxAcceptPerSocketEvent connections pending accept, connections over + this threshold will be accepted in later event loop iterations. If no value is provided Envoy will accept + all connections pending accept from the kernel. + It is recommended to lower this value for better overload management and reduced per-event cost. + Setting it to 1 is a viable option with no noticeable impact on performance. + format: int32 + type: integer socketBufferLimit: allOf: - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml index 352dcf6ede..57baece2d6 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -2767,6 +2767,16 @@ spec: required: - value type: object + maxAcceptPerSocketEvent: + description: |- + MaxAcceptPerSocketEvent provides configuration for the maximum number of connections to accept from the kernel + per socket event. If there are more than MaxAcceptPerSocketEvent connections pending accept, connections over + this threshold will be accepted in later event loop iterations. If no value is provided Envoy will accept + all connections pending accept from the kernel. + It is recommended to lower this value for better overload management and reduced per-event cost. + Setting it to 1 is a viable option with no noticeable impact on performance. + format: int32 + type: integer socketBufferLimit: allOf: - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$