Skip to content
23 changes: 23 additions & 0 deletions api/v1alpha1/timeout_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,21 @@ type TCPClientTimeout struct {
//
// +optional
IdleTimeout *gwapiv1.Duration `json:"idleTimeout,omitempty"`

// TLSHandshakeTimeout for a TCP connection. The maximum time to complete transport level connection negotiation
// (e.g. the TLS handshake) after a connection is accepted.
// If this expires before the transport reports connection establishment, the connection is summarily closed.
//
// +optional
TLSHandshakeTimeout *gwapiv1.Duration `json:"tlsHandshakeTimeout,omitempty"`

// ConnectionInspectionTimeout is the maximum time to wait for initial inspection
// (TLS / SNI and protocol detection, or HTTP protocol parsing) of an incoming connection on the listener socket.
// If exceeded, the connection is dropped.
// Default: 15 seconds.
//
// +optional
ConnectionInspectionTimeout *gwapiv1.Duration `json:"connectionInspectionTimeout,omitempty"`
}

type HTTPClientTimeout struct {
Expand All @@ -90,6 +105,14 @@ type HTTPClientTimeout struct {
// +optional
RequestReceivedTimeout *gwapiv1.Duration `json:"requestReceivedTimeout,omitempty"`

// RequestHeadersReceivedTimeout is the duration envoy waits for the request headers to arrive.
// The timer is activated when the first byte of the headers is received,
// and is disarmed when the last byte of the headers has been received.
// If not specified or set to 0, this timeout is disabled.
//
// +optional
RequestHeadersReceivedTimeout *gwapiv1.Duration `json:"requestHeadersReceivedTimeout,omitempty"`

// IdleTimeout for an HTTP connection. Idle time is defined as a period in which there are no active requests in the connection.
// Default: 1 hour.
//
Expand Down
15 changes: 15 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

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

Original file line number Diff line number Diff line change
Expand Up @@ -1336,6 +1336,14 @@ spec:
Default: 1 hour.
pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$
type: string
requestHeadersReceivedTimeout:
description: |-
RequestHeadersReceivedTimeout is the duration envoy waits for the request headers to arrive.
The timer is activated when the first byte of the headers is received,
and is disarmed when the last byte of the headers has been received.
If not specified or set to 0, this timeout is disabled.
pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$
type: string
requestReceivedTimeout:
description: |-
RequestReceivedTimeout is the duration envoy waits for the complete request reception. This timer starts upon request
Expand All @@ -1352,13 +1360,28 @@ spec:
tcp:
description: Timeout settings for TCP.
properties:
connectionInspectionTimeout:
description: |-
ConnectionInspectionTimeout is the maximum time to wait for initial inspection
(TLS / SNI and protocol detection, or HTTP protocol parsing) of an incoming connection on the listener socket.
If exceeded, the connection is dropped.
Default: 15 seconds.
pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$
type: string
idleTimeout:
description: |-
IdleTimeout for a TCP connection. Idle time is defined as a period in which there are no
bytes sent or received on either the upstream or downstream connection.
Default: 1 hour.
pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$
type: string
tlsHandshakeTimeout:
description: |-
TLSHandshakeTimeout for a TCP connection. The maximum time to complete transport level connection negotiation
(e.g. the TLS handshake) after a connection is accepted.
If this expires before the transport reports connection establishment, the connection is summarily closed.
pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$
type: string
type: object
type: object
tls:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,14 @@ spec:
Default: 1 hour.
pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$
type: string
requestHeadersReceivedTimeout:
description: |-
RequestHeadersReceivedTimeout is the duration envoy waits for the request headers to arrive.
The timer is activated when the first byte of the headers is received,
and is disarmed when the last byte of the headers has been received.
If not specified or set to 0, this timeout is disabled.
pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$
type: string
requestReceivedTimeout:
description: |-
RequestReceivedTimeout is the duration envoy waits for the complete request reception. This timer starts upon request
Expand All @@ -1351,13 +1359,28 @@ spec:
tcp:
description: Timeout settings for TCP.
properties:
connectionInspectionTimeout:
description: |-
ConnectionInspectionTimeout is the maximum time to wait for initial inspection
(TLS / SNI and protocol detection, or HTTP protocol parsing) of an incoming connection on the listener socket.
If exceeded, the connection is dropped.
Default: 15 seconds.
pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$
type: string
idleTimeout:
description: |-
IdleTimeout for a TCP connection. Idle time is defined as a period in which there are no
bytes sent or received on either the upstream or downstream connection.
Default: 1 hour.
pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$
type: string
tlsHandshakeTimeout:
description: |-
TLSHandshakeTimeout for a TCP connection. The maximum time to complete transport level connection negotiation
(e.g. the TLS handshake) after a connection is accepted.
If this expires before the transport reports connection establishment, the connection is summarily closed.
pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$
type: string
type: object
type: object
tls:
Expand Down
22 changes: 22 additions & 0 deletions internal/gatewayapi/clienttrafficpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,20 @@ func buildClientTimeout(clientTimeout *egv1a1.ClientTimeout) (*ir.ClientTimeout,
}
irTCPTimeout.IdleTimeout = ir.MetaV1DurationPtr(d)
}
if clientTimeout.TCP.TLSHandshakeTimeout != nil {
d, err := time.ParseDuration(string(*clientTimeout.TCP.TLSHandshakeTimeout))
if err != nil {
return nil, fmt.Errorf("invalid TCP TLSHandshakeTimeout value %s", *clientTimeout.TCP.TLSHandshakeTimeout)
}
irTCPTimeout.TLSHandshakeTimeout = ir.MetaV1DurationPtr(d)
}
if clientTimeout.TCP.ConnectionInspectionTimeout != nil {
d, err := time.ParseDuration(string(*clientTimeout.TCP.ConnectionInspectionTimeout))
if err != nil {
return nil, fmt.Errorf("invalid TCP ConnectionInspectionTimeout value %s", *clientTimeout.TCP.ConnectionInspectionTimeout)
}
irTCPTimeout.ConnectionInspectionTimeout = ir.MetaV1DurationPtr(d)
}
irClientTimeout.TCP = irTCPTimeout
}

Expand Down Expand Up @@ -974,6 +988,14 @@ func buildClientTimeout(clientTimeout *egv1a1.ClientTimeout) (*ir.ClientTimeout,
}
irHTTPTimeout.StreamIdleTimeout = ir.MetaV1DurationPtr(d)
}

if clientTimeout.HTTP.RequestHeadersReceivedTimeout != nil {
d, err := time.ParseDuration(string(*clientTimeout.HTTP.RequestHeadersReceivedTimeout))
if err != nil {
return nil, fmt.Errorf("invalid HTTP RequestHeadersReceivedTimeout value %s", *clientTimeout.HTTP.RequestHeadersReceivedTimeout)
}
irHTTPTimeout.RequestHeadersReceivedTimeout = ir.MetaV1DurationPtr(d)
}
irClientTimeout.HTTP = irHTTPTimeout
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ clientTrafficPolicies:
name: gateway
sectionName: http-1
timeout:
tcp:
tlsHandshakeTimeout: "10s"
connectionInspectionTimeout: "60s"
http:
requestReceivedTimeout: "5s"
requestHeadersReceivedTimeout: "5s"
gateways:
- apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ clientTrafficPolicies:
sectionName: http-1
timeout:
http:
requestHeadersReceivedTimeout: 5s
requestReceivedTimeout: 5s
tcp:
connectionInspectionTimeout: 60s
tlsHandshakeTimeout: 10s
status:
ancestors:
- ancestorRef:
Expand Down Expand Up @@ -170,7 +174,11 @@ xdsIR:
port: 10080
timeout:
http:
requestHeadersReceivedTimeout: 5s
requestReceivedTimeout: 5s
tcp:
connectionInspectionTimeout: 1m0s
tlsHandshakeTimeout: 10s
- address: 0.0.0.0
externalPort: 8080
hostnames:
Expand Down
12 changes: 12 additions & 0 deletions internal/ir/xds.go
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,14 @@ type TCPClientTimeout struct {
// IdleTimeout for a TCP connection. Idle time is defined as a period in which there are no
// bytes sent or received on either the upstream or downstream connection.
IdleTimeout *metav1.Duration `json:"idleTimeout,omitempty" yaml:"idleTimeout,omitempty"`
// TLSHandshakeTimeout for a TCP connection. The maximum time to complete transport level connection negotiation
// (e.g. the TLS handshake) after a connection is accepted.
// If this expires before the transport reports connection establishment, the connection is summarily closed.
TLSHandshakeTimeout *metav1.Duration `json:"tlsHandshakeTimeout,omitempty" yaml:"tlsHandshakeTimeout,omitempty"`
// ConnectionInspectionTimeout is the maximum time to wait for initial inspection
// (TLS / SNI and protocol detection, or HTTP protocol parsing) of an incoming connection.
// If exceeded, the connection is dropped.
ConnectionInspectionTimeout *metav1.Duration `json:"connectionInspectionTimeout,omitempty" yaml:"connectionInspectionTimeout,omitempty"`
}

// HTTPClientTimeout set the configuration for client HTTP.
Expand All @@ -978,6 +986,10 @@ type HTTPClientTimeout struct {
// The duration envoy waits for the complete request reception. This timer starts upon request
// initiation and stops when either the last byte of the request is sent upstream or when the response begins.
RequestReceivedTimeout *metav1.Duration `json:"requestReceivedTimeout,omitempty" yaml:"requestReceivedTimeout,omitempty"`
// RequestHeadersReceivedTimeout is the duration envoy waits for the request headers to arrive.
// The timer is activated when the first byte of the headers is received,
// and is disarmed when the last byte of the headers has been received.
RequestHeadersReceivedTimeout *metav1.Duration `json:"requestHeadersReceivedTimeout,omitempty" yaml:"requestHeadersReceivedTimeout,omitempty"`
// IdleTimeout for an HTTP connection. Idle time is defined as a period in which there are no active requests in the connection.
IdleTimeout *metav1.Duration `json:"idleTimeout,omitempty" yaml:"idleTimeout,omitempty"`
// The stream idle timeout for connections managed by the connection manager.
Expand Down
15 changes: 15 additions & 0 deletions internal/ir/zz_generated.deepcopy.go

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

23 changes: 21 additions & 2 deletions internal/xds/translator/listener.go

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can you add a test case for xds translator to show the result of these new knobs?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I have added xds translation tests but found out that we also have the same issues for filter chain specific settings. If for example two listeners with the same address / port have two different values for requestReceivedTimeout (already existing setting) then the resulting filter chain will only contain the settings of the first listener. I think it is the same issue with the handshake timeout.

Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ func (t *Translator) buildXdsTCPListener(
listenerDetails *ir.CoreListenerDetails,
keepalive *ir.TCPKeepalive,
connection *ir.ClientConnection,
timeout *ir.ClientTimeout,
accesslog *ir.AccessLog,
) (*listenerv3.Listener, error) {
socketOptions := buildTCPSocketOptions(keepalive)
Expand Down Expand Up @@ -249,6 +250,10 @@ func (t *Translator) buildXdsTCPListener(
socketAddress.Ipv4Compat = true
}

if timeout != nil && timeout.TCP != nil && timeout.TCP.ConnectionInspectionTimeout != nil {
listener.ListenerFiltersTimeout = durationpb.New(timeout.TCP.ConnectionInspectionTimeout.Duration)
Comment thread
HusseinKabbout marked this conversation as resolved.
}

return listener, nil
}

Expand Down Expand Up @@ -440,6 +445,10 @@ func (t *Translator) addHCMToXDSListener(
mgr.RequestTimeout = durationpb.New(irListener.Timeout.HTTP.RequestReceivedTimeout.Duration)
}

if irListener.Timeout.HTTP.RequestHeadersReceivedTimeout != nil {
mgr.RequestHeadersTimeout = durationpb.New(irListener.Timeout.HTTP.RequestHeadersReceivedTimeout.Duration)
}

if irListener.Timeout.HTTP.IdleTimeout != nil {
mgr.CommonHttpProtocolOptions.IdleTimeout = durationpb.New(irListener.Timeout.HTTP.IdleTimeout.Duration)
}
Expand Down Expand Up @@ -508,6 +517,10 @@ func (t *Translator) addHCMToXDSListener(
Filters: filters,
}

if irListener.Timeout != nil && irListener.Timeout.TCP != nil && irListener.Timeout.TCP.TLSHandshakeTimeout != nil {
filterChain.TransportSocketConnectTimeout = durationpb.New(irListener.Timeout.TCP.TLSHandshakeTimeout.Duration)
}

if irListener.TLS != nil {
var tSocket *corev3.TransportSocket

Expand Down Expand Up @@ -805,10 +818,16 @@ func buildTCPFilterChain(
return nil, err
}

return &listenerv3.FilterChain{
filterChain := &listenerv3.FilterChain{
Filters: filters,
Name: tlsListenerFilterChainName(irRoute),
}, nil
}

if timeout != nil && timeout.TCP != nil && timeout.TCP.TLSHandshakeTimeout != nil {
filterChain.TransportSocketConnectTimeout = durationpb.New(timeout.TCP.TLSHandshakeTimeout.Duration)
}

return filterChain, nil
}

func buildConnectionLimitFilter(statPrefix string, connection *ir.ClientConnection) *connection_limitv3.ConnectionLimit {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
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"
timeout:
tcp:
connectionInspectionTimeout: "15s"
http:
requestReceivedTimeout: "5s"
idleTimeout: "10s"
- name: "second-listener"
address: "::"
port: 10080
hostnames:
- "*"
routes:
- name: "second-route"
hostname: "*"
destination:
name: "second-route-dest"
settings:
- endpoints:
- host: "1.2.3.4"
port: 50000
name: "second-route-dest/backend/0"
timeout:
tcp:
connectionInspectionTimeout: "10s"
idleTimeout: "1200s"
Loading
Loading