Repository: envoyproxy/gateway
Pull request #3472 (2024-05-24 13:21:31)

Trigger a reconcile when EnvoyProxy backendRefs changes
fixes: https://github.com/envoyproxy/gateway/issues/3412

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/envoyproxy/gateway/pull/3472?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) Report
Attention: Patch coverage is `89.70588%` with `7 lines` in your changes are missing coverage. Please review.
> Project coverage is 67.13%. Comparing base [(`c348370`)](https://app.codecov.io/gh/envoyproxy/gateway/commit/c348370d076a5b5b4bd2421d7d9df5f86755a717?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) to head [(`d881688`)](https://app.codecov.io/gh/envoyproxy/gateway/pull/3472?dropdown=coverage&src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).

| [Files](https://app.codecov.io/gh/envoyproxy/gateway/pull/3472?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) | Patch % | Lines |
|---|---|---|
| [internal/provider/kubernetes/predicates.go](https://app.codecov.io/gh/envoyproxy/gateway/pull/3472?src=pr&el=tree&filepath=internal%2Fprovider%2Fkubernetes%2Fpredicates.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy#diff-aW50ZXJuYWwvcHJvdmlkZXIva3ViZXJuZXRlcy9wcmVkaWNhdGVzLmdv) | 70.00% | [2 Missing and 1 partial :warning: ](https://app.codecov.io/gh/envoyproxy/gateway/pull/3472?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) |
| [internal/provider/kubernetes/controller.go](https://app.codecov.io/gh/envoyproxy/gateway/pull/3472?src=pr&el=tree&filepath=internal%2Fprovider%2Fkubernetes%2Fcontroller.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy#diff-aW50ZXJuYWwvcHJvdmlkZXIva3ViZXJuZXRlcy9jb250cm9sbGVyLmdv) | 0.00% | [1 Missing and 1 partial :warning: ](https://app.codecov.io/gh/envoyproxy/gateway/pull/3472?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) |
| [internal/provider/kubernetes/indexers.go](https://app.codecov.io/gh/envoyproxy/gateway/pull/3472?src=pr&el=tree&filepath=internal%2Fprovider%2Fkubernetes%2Findexers.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy#diff-aW50ZXJuYWwvcHJvdmlkZXIva3ViZXJuZXRlcy9pbmRleGVycy5nbw==) | 96.42% | [1 Missing and 1 partial :warning: ](https://app.codecov.io/gh/envoyproxy/gateway/pull/3472?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #3472      +/-   ##
==========================================
+ Coverage   67.09%   67.13%   +0.04%     
==========================================
  Files         166      166              
  Lines       19618    19686      +68     
==========================================
+ Hits        13163    13217      +54     
- Misses       5504     5513       +9     
- Partials      951      956       +5     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/envoyproxy/gateway/pull/3472?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).


Patch:
diff --git a/api/v1alpha1/accesslogging_types.go b/api/v1alpha1/accesslogging_types.go
index e1311566e..8aafbe9ac 100644
--- a/api/v1alpha1/accesslogging_types.go
+++ b/api/v1alpha1/accesslogging_types.go
@@ -158,19 +158,19 @@ type FileEnvoyProxyAccessLog struct {
 // +kubebuilder:validation:XValidation:message="host or backendRefs needs to be set",rule="has(self.host) || self.backendRefs.size() > 0"
 type OpenTelemetryEnvoyProxyAccessLog struct {
 	// Host define the extension service hostname.
-	// Deprecated: Use BackendRef instead.
+	// Deprecated: Use BackendRefs instead.
 	//
 	// +optional
 	Host *string `json:"host,omitempty"`
 	// Port defines the port the extension service is exposed on.
-	// Deprecated: Use BackendRef instead.
+	// Deprecated: Use BackendRefs instead.
 	//
 	// +optional
 	// +kubebuilder:validation:Minimum=0
 	// +kubebuilder:default=4317
 	Port int32 `json:"port,omitempty"`
 	// BackendRefs references a Kubernetes object that represents the
-	// backend server to which the accesslog will be sent.
+	// backend server to which the access log will be sent.
 	// Only service Kind is supported for now.
 	//
 	// +optional
diff --git a/api/v1alpha1/envoyproxy_metric_types.go b/api/v1alpha1/envoyproxy_metric_types.go
index 52b17cf62..10ba5ad91 100644
--- a/api/v1alpha1/envoyproxy_metric_types.go
+++ b/api/v1alpha1/envoyproxy_metric_types.go
@@ -56,12 +56,12 @@ type ProxyMetricSink struct {
 // +kubebuilder:validation:XValidation:message="host or backendRefs needs to be set",rule="has(self.host) || self.backendRefs.size() > 0"
 type ProxyOpenTelemetrySink struct {
 	// Host define the service hostname.
-	// Deprecated: Use BackendRef instead.
+	// Deprecated: Use BackendRefs instead.
 	//
 	// +optional
 	Host *string `json:"host,omitempty"`
 	// Port defines the port the service is exposed on.
-	// Deprecated: Use BackendRef instead.
+	// Deprecated: Use BackendRefs instead.
 	//
 	// +optional
 	// +kubebuilder:validation:Minimum=0
diff --git a/api/v1alpha1/loadbalancer_types.go b/api/v1alpha1/loadbalancer_types.go
index d4912aebd..b29c5bec2 100644
--- a/api/v1alpha1/loadbalancer_types.go
+++ b/api/v1alpha1/loadbalancer_types.go
@@ -73,7 +73,6 @@ type ConsistentHash struct {
 	// +kubebuilder:validation:Maximum=5000011
 	// +kubebuilder:default=65537
 	// +optional
-	// +notImplementedHide
 	TableSize *uint64 `json:"tableSize,omitempty"`
 }
 
diff --git a/api/v1alpha1/tracing_types.go b/api/v1alpha1/tracing_types.go
index d3a18673f..ffa33a8c0 100644
--- a/api/v1alpha1/tracing_types.go
+++ b/api/v1alpha1/tracing_types.go
@@ -38,19 +38,19 @@ type TracingProvider struct {
 	// +kubebuilder:default=OpenTelemetry
 	Type TracingProviderType `json:"type"`
 	// Host define the provider service hostname.
-	// Deprecated: Use BackendRef instead.
+	// Deprecated: Use BackendRefs instead.
 	//
 	// +optional
 	Host *string `json:"host,omitempty"`
 	// Port defines the port the provider service is exposed on.
-	// Deprecated: Use BackendRef instead.
+	// Deprecated: Use BackendRefs instead.
 	//
 	// +optional
 	// +kubebuilder:validation:Minimum=0
 	// +kubebuilder:default=4317
 	Port int32 `json:"port,omitempty"`
 	// BackendRefs references a Kubernetes object that represents the
-	// backend server to which the accesslog will be sent.
+	// backend server to which the trace will be sent.
 	// Only service Kind is supported for now.
 	//
 	// +optional
diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml
index b3e60d865..8ba48c431 100644
--- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml
+++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml
@@ -10399,7 +10399,7 @@ spec:
                                       backendRefs:
                                         description: |-
                                           BackendRefs references a Kubernetes object that represents the
-                                          backend server to which the accesslog will be sent.
+                                          backend server to which the access log will be sent.
                                           Only service Kind is supported for now.
                                         items:
                                           description: BackendRef defines how an ObjectReference
@@ -10487,13 +10487,13 @@ spec:
                                       host:
                                         description: |-
                                           Host define the extension service hostname.
-                                          Deprecated: Use BackendRef instead.
+                                          Deprecated: Use BackendRefs instead.
                                         type: string
                                       port:
                                         default: 4317
                                         description: |-
                                           Port defines the port the extension service is exposed on.
-                                          Deprecated: Use BackendRef instead.
+                                          Deprecated: Use BackendRefs instead.
                                         format: int32
                                         minimum: 0
                                         type: integer
@@ -10713,13 +10713,13 @@ spec:
                                 host:
                                   description: |-
                                     Host define the service hostname.
-                                    Deprecated: Use BackendRef instead.
+                                    Deprecated: Use BackendRefs instead.
                                   type: string
                                 port:
                                   default: 4317
                                   description: |-
                                     Port defines the port the service is exposed on.
-                                    Deprecated: Use BackendRef instead.
+                                    Deprecated: Use BackendRefs instead.
                                   format: int32
                                   maximum: 65535
                                   minimum: 0
@@ -10822,7 +10822,7 @@ spec:
                           backendRefs:
                             description: |-
                               BackendRefs references a Kubernetes object that represents the
-                              backend server to which the accesslog will be sent.
+                              backend server to which the trace will be sent.
                               Only service Kind is supported for now.
                             items:
                               description: BackendRef defines how an ObjectReference
@@ -10909,13 +10909,13 @@ spec:
                           host:
                             description: |-
                               Host define the provider service hostname.
-                              Deprecated: Use BackendRef instead.
+                              Deprecated: Use BackendRefs instead.
                             type: string
                           port:
                             default: 4317
                             description: |-
                               Port defines the port the provider service is exposed on.
-                              Deprecated: Use BackendRef instead.
+                              Deprecated: Use BackendRefs instead.
                             format: int32
                             minimum: 0
                             type: integer
diff --git a/internal/cmd/egctl/translate.go b/internal/cmd/egctl/translate.go
index fe2fef48e..a7bb09820 100644
--- a/internal/cmd/egctl/translate.go
+++ b/internal/cmd/egctl/translate.go
@@ -632,8 +632,8 @@ func addMissingServices(requiredServices map[string]*v1.Service, obj interface{}
 func kubernetesYAMLToResources(str string, addMissingResources bool) (*gatewayapi.Resources, error) {
 	resources := gatewayapi.NewResources()
 	var useDefaultNamespace bool
-	providedNamespaceMap := map[string]struct{}{}
-	requiredNamespaceMap := map[string]struct{}{}
+	providedNamespaceMap := sets.New[string]()
+	requiredNamespaceMap := sets.New[string]()
 	yamls := strings.Split(str, "\n---")
 	combinedScheme := envoygateway.GetScheme()
 	for _, y := range yamls {
@@ -655,7 +655,7 @@ func kubernetesYAMLToResources(str string, addMissingResources bool) (*gatewayap
 			useDefaultNamespace = true
 			namespace = config.DefaultNamespace
 		}
-		requiredNamespaceMap[namespace] = struct{}{}
+		requiredNamespaceMap.Insert(namespace)
 		kobj, err := combinedScheme.New(gvk)
 		if err != nil {
 			return nil, err
@@ -779,7 +779,7 @@ func kubernetesYAMLToResources(str string, addMissingResources bool) (*gatewayap
 				},
 			}
 			resources.Namespaces = append(resources.Namespaces, namespace)
-			providedNamespaceMap[name] = struct{}{}
+			providedNamespaceMap.Insert(name)
 		case gatewayapi.KindService:
 			typedSpec := spec.Interface()
 			service := &v1.Service{
@@ -850,20 +850,20 @@ func kubernetesYAMLToResources(str string, addMissingResources bool) (*gatewayap
 	}
 
 	if useDefaultNamespace {
-		if _, found := providedNamespaceMap[config.DefaultNamespace]; !found {
+		if !providedNamespaceMap.Has(config.DefaultNamespace) {
 			namespace := &v1.Namespace{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: config.DefaultNamespace,
 				},
 			}
 			resources.Namespaces = append(resources.Namespaces, namespace)
-			providedNamespaceMap[config.DefaultNamespace] = struct{}{}
+			providedNamespaceMap.Insert(config.DefaultNamespace)
 		}
 	}
 
 	if addMissingResources {
 		for ns := range requiredNamespaceMap {
-			if _, found := providedNamespaceMap[ns]; !found {
+			if !providedNamespaceMap.Has(ns) {
 				namespace := &v1.Namespace{
 					ObjectMeta: metav1.ObjectMeta{
 						Name: ns,
diff --git a/internal/gatewayapi/backendtrafficpolicy.go b/internal/gatewayapi/backendtrafficpolicy.go
index 1664370d5..0fae4b170 100644
--- a/internal/gatewayapi/backendtrafficpolicy.go
+++ b/internal/gatewayapi/backendtrafficpolicy.go
@@ -9,6 +9,7 @@ import (
 	"errors"
 	"fmt"
 	"math"
+	"math/big"
 	"net"
 	"sort"
 	"strings"
@@ -28,6 +29,10 @@ import (
 	"github.com/envoyproxy/gateway/internal/utils/regex"
 )
 
+const (
+	MaxConsistentHashTableSize = 5000011 // https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/cluster/v3/cluster.proto#config-cluster-v3-cluster-maglevlbconfig
+)
+
 func (t *Translator) ProcessBackendTrafficPolicies(backendTrafficPolicies []*egv1a1.BackendTrafficPolicy,
 	gateways []*GatewayContext,
 	routes []RouteContext,
@@ -307,7 +312,10 @@ func (t *Translator) translateBackendTrafficPolicyForRoute(policy *egv1a1.Backen
 		}
 	}
 	if policy.Spec.LoadBalancer != nil {
-		lb = t.buildLoadBalancer(policy)
+		if lb, err = t.buildLoadBalancer(policy); err != nil {
+			err = perr.WithMessage(err, "LoadBalancer")
+			errs = errors.Join(errs, err)
+		}
 	}
 	if policy.Spec.ProxyProtocol != nil {
 		pp = t.buildProxyProtocol(policy)
@@ -431,7 +439,10 @@ func (t *Translator) translateBackendTrafficPolicyForGateway(policy *egv1a1.Back
 		}
 	}
 	if policy.Spec.LoadBalancer != nil {
-		lb = t.buildLoadBalancer(policy)
+		if lb, err = t.buildLoadBalancer(policy); err != nil {
+			err = perr.WithMessage(err, "LoadBalancer")
+			errs = errors.Join(errs, err)
+		}
 	}
 	if policy.Spec.ProxyProtocol != nil {
 		pp = t.buildProxyProtocol(policy)
@@ -764,12 +775,17 @@ func buildRateLimitRule(rule egv1a1.RateLimitRule) (*ir.RateLimitRule, error) {
 	return irRule, nil
 }
 
-func (t *Translator) buildLoadBalancer(policy *egv1a1.BackendTrafficPolicy) *ir.LoadBalancer {
+func (t *Translator) buildLoadBalancer(policy *egv1a1.BackendTrafficPolicy) (*ir.LoadBalancer, error) {
 	var lb *ir.LoadBalancer
 	switch policy.Spec.LoadBalancer.Type {
 	case egv1a1.ConsistentHashLoadBalancerType:
+		consistentHash, err := t.buildConsistentHashLoadBalancer(policy)
+		if err != nil {
+			return nil, perr.WithMessage(err, "ConsistentHash")
+		}
+
 		lb = &ir.LoadBalancer{
-			ConsistentHash: t.buildConsistentHashLoadBalancer(policy),
+			ConsistentHash: consistentHash,
 		}
 	case egv1a1.LeastRequestLoadBalancerType:
 		lb = &ir.LoadBalancer{}
@@ -803,24 +819,32 @@ func (t *Translator) buildLoadBalancer(policy *egv1a1.BackendTrafficPolicy) *ir.
 		}
 	}
 
-	return lb
+	return lb, nil
 }
 
-func (t *Translator) buildConsistentHashLoadBalancer(policy *egv1a1.BackendTrafficPolicy) *ir.ConsistentHash {
+func (t *Translator) buildConsistentHashLoadBalancer(policy *egv1a1.BackendTrafficPolicy) (*ir.ConsistentHash, error) {
+	consistentHash := &ir.ConsistentHash{}
+
+	if policy.Spec.LoadBalancer.ConsistentHash.TableSize != nil {
+		tableSize := policy.Spec.LoadBalancer.ConsistentHash.TableSize
+
+		if *tableSize > MaxConsistentHashTableSize || !big.NewInt(int64(*tableSize)).ProbablyPrime(0) {
+			return nil, fmt.Errorf("invalid TableSize value %d", *tableSize)
+		}
+
+		consistentHash.TableSize = tableSize
+	}
+
 	switch policy.Spec.LoadBalancer.ConsistentHash.Type {
 	case egv1a1.SourceIPConsistentHashType:
-		return &ir.ConsistentHash{
-			SourceIP: ptr.To(true),
-		}
+		consistentHash.SourceIP = ptr.To(true)
 	case egv1a1.HeaderConsistentHashType:
-		return &ir.ConsistentHash{
-			Header: &ir.Header{
-				Name: policy.Spec.LoadBalancer.ConsistentHash.Header.Name,
-			},
+		consistentHash.Header = &ir.Header{
+			Name: policy.Spec.LoadBalancer.ConsistentHash.Header.Name,
 		}
-	default:
-		return &ir.ConsistentHash{}
 	}
+
+	return consistentHash, nil
 }
 
 func (t *Translator) buildProxyProtocol(policy *egv1a1.BackendTrafficPolicy) *ir.ProxyProtocol {
diff --git a/internal/gatewayapi/clienttrafficpolicy.go b/internal/gatewayapi/clienttrafficpolicy.go
index c5da32c4c..18ed64edc 100644
--- a/internal/gatewayapi/clienttrafficpolicy.go
+++ b/internal/gatewayapi/clienttrafficpolicy.go
@@ -388,6 +388,7 @@ func (t *Translator) translateClientTrafficPolicyForListener(policy *egv1a1.Clie
 		connection          *ir.Connection
 		tlsConfig           *ir.TLSConfig
 		enableProxyProtocol bool
+		timeout             *ir.ClientTimeout
 		err, errs           error
 	)
 
@@ -409,6 +410,13 @@ func (t *Translator) translateClientTrafficPolicyForListener(policy *egv1a1.Clie
 	// Translate Proxy Protocol
 	enableProxyProtocol = buildProxyProtocol(policy.Spec.EnableProxyProtocol)
 
+	// Translate Client Timeout Settings
+	timeout, err = buildClientTimeout(policy.Spec.Timeout)
+	if err != nil {
+		err = perr.WithMessage(err, "Timeout")
+		errs = errors.Join(errs, err)
+	}
+
 	// IR must exist since we're past validation
 	if httpIR != nil {
 		// Translate Client IP Detection
@@ -420,12 +428,6 @@ func (t *Translator) translateClientTrafficPolicyForListener(policy *egv1a1.Clie
 		// Translate Path Settings
 		translatePathSettings(policy.Spec.Path, httpIR)
 
-		// Translate Client Timeout Settings
-		if err = translateClientTimeout(policy.Spec.Timeout, httpIR); err != nil {
-			err = perr.WithMessage(err, "Timeout")
-			errs = errors.Join(errs, err)
-		}
-
 		// Translate HTTP1 Settings
 		if err = translateHTTP1Settings(policy.Spec.HTTP1, httpIR); err != nil {
 			err = perr.WithMessage(err, "HTTP1")
@@ -471,6 +473,7 @@ func (t *Translator) translateClientTrafficPolicyForListener(policy *egv1a1.Clie
 		httpIR.TCPKeepalive = keepalive
 		httpIR.Connection = connection
 		httpIR.EnableProxyProtocol = enableProxyProtocol
+		httpIR.Timeout = timeout
 		httpIR.TLS = tlsConfig
 	}
 
@@ -491,6 +494,7 @@ func (t *Translator) translateClientTrafficPolicyForListener(policy *egv1a1.Clie
 		tcpIR.Connection = connection
 		tcpIR.EnableProxyProtocol = enableProxyProtocol
 		tcpIR.TLS = tlsConfig
+		tcpIR.Timeout = timeout
 	}
 
 	return nil
@@ -539,19 +543,34 @@ func translatePathSettings(pathSettings *egv1a1.PathSettings, httpIR *ir.HTTPLis
 	}
 }
 
-func translateClientTimeout(clientTimeout *egv1a1.ClientTimeout, httpIR *ir.HTTPListener) error {
+func buildClientTimeout(clientTimeout *egv1a1.ClientTimeout) (*ir.ClientTimeout, error) {
+	// Return early if not set
 	if clientTimeout == nil {
-		return nil
+		return nil, nil
 	}
 
 	irClientTimeout := &ir.ClientTimeout{}
 
+	if clientTimeout.TCP != nil {
+		irTCPTimeout := &ir.TCPClientTimeout{}
+		if clientTimeout.TCP.IdleTimeout != nil {
+			d, err := time.ParseDuration(string(*clientTimeout.TCP.IdleTimeout))
+			if err != nil {
+				return nil, fmt.Errorf("invalid TCP IdleTimeout value %s", *clientTimeout.TCP.IdleTimeout)
+			}
+			irTCPTimeout.IdleTimeout = &metav1.Duration{
+				Duration: d,
+			}
+		}
+		irClientTimeout.TCP = irTCPTimeout
+	}
+
 	if clientTimeout.HTTP != nil {
 		irHTTPTimeout := &ir.HTTPClientTimeout{}
 		if clientTimeout.HTTP.RequestReceivedTimeout != nil {
 			d, err := time.ParseDuration(string(*clientTimeout.HTTP.RequestReceivedTimeout))
 			if err != nil {
-				return err
+				return nil, fmt.Errorf("invalid HTTP RequestReceivedTimeout value %s", *clientTimeout.HTTP.RequestReceivedTimeout)
 			}
 			irHTTPTimeout.RequestReceivedTimeout = &metav1.Duration{
 				Duration: d,
@@ -561,7 +580,7 @@ func translateClientTimeout(clientTimeout *egv1a1.ClientTimeout, httpIR *ir.HTTP
 		if clientTimeout.HTTP.IdleTimeout != nil {
 			d, err := time.ParseDuration(string(*clientTimeout.HTTP.IdleTimeout))
 			if err != nil {
-				return err
+				return nil, fmt.Errorf("invalid HTTP IdleTimeout value %s", *clientTimeout.HTTP.IdleTimeout)
 			}
 			irHTTPTimeout.IdleTimeout = &metav1.Duration{
 				Duration: d,
@@ -570,9 +589,7 @@ func translateClientTimeout(clientTimeout *egv1a1.ClientTimeout, httpIR *ir.HTTP
 		irClientTimeout.HTTP = irHTTPTimeout
 	}
 
-	httpIR.Timeout = irClientTimeout
-
-	return nil
+	return irClientTimeout, nil
 }
 
 func buildProxyProtocol(enableProxyProtocol *bool) bool {
diff --git a/internal/ir/xds.go b/internal/ir/xds.go
index 9afed373c..77505d575 100644
--- a/internal/ir/xds.go
+++ b/internal/ir/xds.go
@@ -448,10 +448,21 @@ type HeaderSettings struct {
 // ClientTimeout sets the timeout configuration for downstream connections
 // +k8s:deepcopy-gen=true
 type ClientTimeout struct {
+	// Timeout settings for TCP (not HTTP).
+	TCP *TCPClientTimeout `json:"tcp,omitempty" yaml:"tcp,omitempty"`
+
 	// Timeout settings for HTTP.
 	HTTP *HTTPClientTimeout `json:"http,omitempty" yaml:"http,omitempty"`
 }
 
+// TCPClientTimeout set the configuration for client TCP (not HTTP).
+// +k8s:deepcopy-gen=true
+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"`
+}
+
 // HTTPClientTimeout set the configuration for client HTTP.
 // +k8s:deepcopy-gen=true
 type HTTPClientTimeout struct {
@@ -1232,6 +1243,8 @@ type TCPListener struct {
 	TCPKeepalive *TCPKeepalive `json:"tcpKeepalive,omitempty" yaml:"tcpKeepalive,omitempty"`
 	// EnableProxyProtocol enables the listener to interpret proxy protocol header
 	EnableProxyProtocol bool `json:"enableProxyProtocol,omitempty" yaml:"enableProxyProtocol,omitempty"`
+	// ClientTimeout sets the timeout configuration for downstream connections.
+	Timeout *ClientTimeout `json:"timeout,omitempty" yaml:"clientTimeout,omitempty"`
 	// Connection settings for clients
 	Connection *Connection `json:"connection,omitempty" yaml:"connection,omitempty"`
 	// Routes associated with TCP traffic to the listener.
@@ -1651,8 +1664,9 @@ type Random struct{}
 // +k8s:deepcopy-gen=true
 type ConsistentHash struct {
 	// Hash based on the Source IP Address
-	SourceIP *bool   `json:"sourceIP,omitempty" yaml:"sourceIP,omitempty"`
-	Header   *Header `json:"header,omitempty" yaml:"header,omitempty"`
+	SourceIP  *bool   `json:"sourceIP,omitempty" yaml:"sourceIP,omitempty"`
+	Header    *Header `json:"header,omitempty" yaml:"header,omitempty"`
+	TableSize *uint64 `json:"tableSize,omitempty" yaml:"tableSize,omitempty"`
 }
 
 // Header consistent hash type settings
diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go
index 3d3d8823f..7d93ad057 100644
--- a/internal/ir/zz_generated.deepcopy.go
+++ b/internal/ir/zz_generated.deepcopy.go
@@ -283,6 +283,11 @@ func (in *ClientIPDetectionSettings) DeepCopy() *ClientIPDetectionSettings {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *ClientTimeout) DeepCopyInto(out *ClientTimeout) {
 	*out = *in
+	if in.TCP != nil {
+		in, out := &in.TCP, &out.TCP
+		*out = new(TCPClientTimeout)
+		(*in).DeepCopyInto(*out)
+	}
 	if in.HTTP != nil {
 		in, out := &in.HTTP, &out.HTTP
 		*out = new(HTTPClientTimeout)
@@ -363,6 +368,11 @@ func (in *ConsistentHash) DeepCopyInto(out *ConsistentHash) {
 		*out = new(Header)
 		**out = **in
 	}
+	if in.TableSize != nil {
+		in, out := &in.TableSize, &out.TableSize
+		*out = new(uint64)
+		**out = **in
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConsistentHash.
@@ -2028,6 +2038,26 @@ func (in *StringMatch) DeepCopy() *StringMatch {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TCPClientTimeout) DeepCopyInto(out *TCPClientTimeout) {
+	*out = *in
+	if in.IdleTimeout != nil {
+		in, out := &in.IdleTimeout, &out.IdleTimeout
+		*out = new(v1.Duration)
+		**out = **in
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCPClientTimeout.
+func (in *TCPClientTimeout) DeepCopy() *TCPClientTimeout {
+	if in == nil {
+		return nil
+	}
+	out := new(TCPClientTimeout)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *TCPHealthChecker) DeepCopyInto(out *TCPHealthChecker) {
 	*out = *in
@@ -2096,6 +2126,11 @@ func (in *TCPListener) DeepCopyInto(out *TCPListener) {
 		*out = new(TCPKeepalive)
 		(*in).DeepCopyInto(*out)
 	}
+	if in.Timeout != nil {
+		in, out := &in.Timeout, &out.Timeout
+		*out = new(ClientTimeout)
+		(*in).DeepCopyInto(*out)
+	}
 	if in.Connection != nil {
 		in, out := &in.Connection, &out.Connection
 		*out = new(Connection)
diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go
index bc314ce50..7051d21f4 100644
--- a/internal/provider/kubernetes/controller.go
+++ b/internal/provider/kubernetes/controller.go
@@ -115,19 +115,19 @@ func newGatewayAPIController(mgr manager.Manager, cfg *config.Server, su Updater
 
 type resourceMappings struct {
 	// Map for storing namespaces for Route, Service and Gateway objects.
-	allAssociatedNamespaces map[string]struct{}
+	allAssociatedNamespaces sets.Set[string]
 	// Map for storing TLSRoutes' NamespacedNames attaching to various Gateway objects.
-	allAssociatedTLSRoutes map[string]struct{}
+	allAssociatedTLSRoutes sets.Set[string]
 	// Map for storing HTTPRoutes' NamespacedNames attaching to various Gateway objects.
-	allAssociatedHTTPRoutes map[string]struct{}
+	allAssociatedHTTPRoutes sets.Set[string]
 	// Map for storing GRPCRoutes' NamespacedNames attaching to various Gateway objects.
-	allAssociatedGRPCRoutes map[string]struct{}
+	allAssociatedGRPCRoutes sets.Set[string]
 	// Map for storing TCPRoutes' NamespacedNames attaching to various Gateway objects.
-	allAssociatedTCPRoutes map[string]struct{}
+	allAssociatedTCPRoutes sets.Set[string]
 	// Map for storing UDPRoutes' NamespacedNames attaching to various Gateway objects.
-	allAssociatedUDPRoutes map[string]struct{}
+	allAssociatedUDPRoutes sets.Set[string]
 	// Map for storing backendRefs' NamespaceNames referred by various Route objects.
-	allAssociatedBackendRefs map[gwapiv1.BackendObjectReference]struct{}
+	allAssociatedBackendRefs sets.Set[gwapiv1.BackendObjectReference]
 	// extensionRefFilters is a map of filters managed by an extension.
 	// The key is the namespaced name, group and kind of the filter and the value is the
 	// unstructured form of the resource.
@@ -136,13 +136,13 @@ type resourceMappings struct {
 
 func newResourceMapping() *resourceMappings {
 	return &resourceMappings{
-		allAssociatedNamespaces:  map[string]struct{}{},
-		allAssociatedTLSRoutes:   map[string]struct{}{},
-		allAssociatedHTTPRoutes:  map[string]struct{}{},
-		allAssociatedGRPCRoutes:  map[string]struct{}{},
-		allAssociatedTCPRoutes:   map[string]struct{}{},
-		allAssociatedUDPRoutes:   map[string]struct{}{},
-		allAssociatedBackendRefs: map[gwapiv1.BackendObjectReference]struct{}{},
+		allAssociatedNamespaces:  sets.New[string](),
+		allAssociatedTLSRoutes:   sets.New[string](),
+		allAssociatedHTTPRoutes:  sets.New[string](),
+		allAssociatedGRPCRoutes:  sets.New[string](),
+		allAssociatedTCPRoutes:   sets.New[string](),
+		allAssociatedUDPRoutes:   sets.New[string](),
+		allAssociatedBackendRefs: sets.New[gwapiv1.BackendObjectReference](),
 		extensionRefFilters:      map[utils.NamespacedNameWithGroupKind]unstructured.Unstructured{},
 	}
 }
@@ -367,7 +367,7 @@ func (r *gatewayAPIReconciler) processBackendRefs(ctx context.Context, gwcResour
 				r.log.Error(err, "failed to get Service", "namespace", string(*backendRef.Namespace),
 					"name", string(backendRef.Name))
 			} else {
-				resourceMappings.allAssociatedNamespaces[service.Namespace] = struct{}{}
+				resourceMappings.allAssociatedNamespaces.Insert(service.Namespace)
 				gwcResource.Services = append(gwcResource.Services, service)
 				r.log.Info("added Service to resource tree", "namespace", string(*backendRef.Namespace),
 					"name", string(backendRef.Name))
@@ -381,7 +381,7 @@ func (r *gatewayAPIReconciler) processBackendRefs(ctx context.Context, gwcResour
 				r.log.Error(err, "failed to get ServiceImport", "namespace", string(*backendRef.Namespace),
 					"name", string(backendRef.Name))
 			} else {
-				resourceMappings.allAssociatedNamespaces[serviceImport.Namespace] = struct{}{}
+				resourceMappings.allAssociatedNamespaces.Insert(serviceImport.Namespace)
 				gwcResource.ServiceImports = append(gwcResource.ServiceImports, serviceImport)
 				r.log.Info("added ServiceImport to resource tree", "namespace", string(*backendRef.Namespace),
 					"name", string(backendRef.Name))
@@ -472,12 +472,12 @@ func (r *gatewayAPIReconciler) processSecurityPolicyObjectRefs(
 			}
 
 			backendNamespace := gatewayapi.NamespaceDerefOr(backendRef.Namespace, policy.Namespace)
-			resourceMap.allAssociatedBackendRefs[gwapiv1.BackendObjectReference{
+			resourceMap.allAssociatedBackendRefs.Insert(gwapiv1.BackendObjectReference{
 				Group:     backendRef.Group,
 				Kind:      backendRef.Kind,
 				Namespace: gatewayapi.NamespacePtrV1Alpha2(backendNamespace),
 				Name:      backendRef.Name,
-			}] = struct{}{}
+			})
 
 			if backendNamespace != policy.Namespace {
 				from := ObjectKindNamespacedName{
@@ -583,7 +583,7 @@ func (r *gatewayAPIReconciler) processSecretRef(
 				"name", refGrant.Name)
 		}
 	}
-	resourceMap.allAssociatedNamespaces[secretNS] = struct{}{} // TODO Zhaohuabing do we need this line?
+	resourceMap.allAssociatedNamespaces.Insert(secretNS) // TODO Zhaohuabing do we need this line?
 	resourceTree.Secrets = append(resourceTree.Secrets, secret)
 	r.log.Info("processing Secret", "namespace", secretNS, "name", string(secretRef.Name))
 	return nil
@@ -685,7 +685,7 @@ func (r *gatewayAPIReconciler) processConfigMapRef(
 				"name", refGrant.Name)
 		}
 	}
-	resourceMap.allAssociatedNamespaces[configMapNS] = struct{}{} // TODO Zhaohuabing do we need this line?
+	resourceMap.allAssociatedNamespaces.Insert(configMapNS) // TODO Zhaohuabing do we need this line?
 	resourceTree.ConfigMaps = append(resourceTree.ConfigMaps, configMap)
 	r.log.Info("processing ConfigMap", "namespace", configMapNS, "name", string(configMapRef.Name))
 	return nil
@@ -760,7 +760,7 @@ func (r *gatewayAPIReconciler) processGateways(ctx context.Context, managedGC *g
 			}
 		}
 		r.log.Info("processing Gateway", "namespace", gtw.Namespace, "name", gtw.Name)
-		resourceMap.allAssociatedNamespaces[gtw.Namespace] = struct{}{}
+		resourceMap.allAssociatedNamespaces.Insert(gtw.Namespace)
 
 		for _, listener := range gtw.Spec.Listeners {
 			listener := listener
@@ -986,6 +986,9 @@ func (r *gatewayAPIReconciler) watchResources(ctx context.Context, mgr manager.M
 			epPredicates...)); err != nil {
 		return err
 	}
+	if err := addEnvoyProxyIndexers(ctx, mgr); err != nil {
+		return err
+	}
 
 	// Watch Gateway CRUDs and reconcile affected GatewayClass.
 	gPredicates := []predicate.TypedPredicate[*gwapiv1.Gateway]{
@@ -1517,12 +1520,12 @@ func (r *gatewayAPIReconciler) processParamsRef(ctx context.Context, gc *gwapiv1
 							}
 							for _, backendRef := range sink.OpenTelemetry.BackendRefs {
 								backendNamespace := gatewayapi.NamespaceDerefOrAlpha(backendRef.Namespace, ep.Namespace)
-								resourceMap.allAssociatedBackendRefs[gwapiv1.BackendObjectReference{
+								resourceMap.allAssociatedBackendRefs.Insert(gwapiv1.BackendObjectReference{
 									Group:     backendRef.BackendObjectReference.Group,
 									Kind:      backendRef.BackendObjectReference.Kind,
 									Namespace: gatewayapi.NamespacePtrV1Alpha2(backendNamespace),
 									Name:      backendRef.Name,
-								}] = struct{}{}
+								})
 							}
 						}
 					}
@@ -1535,12 +1538,12 @@ func (r *gatewayAPIReconciler) processParamsRef(ctx context.Context, gc *gwapiv1
 						}
 						for _, backendRef := range sink.OpenTelemetry.BackendRefs {
 							backendNamespace := gatewayapi.NamespaceDerefOrAlpha(backendRef.Namespace, ep.Namespace)
-							resourceMap.allAssociatedBackendRefs[gwapiv1.BackendObjectReference{
+							resourceMap.allAssociatedBackendRefs.Insert(gwapiv1.BackendObjectReference{
 								Group:     backendRef.BackendObjectReference.Group,
 								Kind:      backendRef.BackendObjectReference.Kind,
 								Namespace: gatewayapi.NamespacePtrV1Alpha2(backendNamespace),
 								Name:      backendRef.Name,
-							}] = struct{}{}
+							})
 						}
 					}
 				}
@@ -1548,12 +1551,12 @@ func (r *gatewayAPIReconciler) processParamsRef(ctx context.Context, gc *gwapiv1
 				if telemetry.Tracing != nil {
 					for _, backendRef := range telemetry.Tracing.Provider.BackendRefs {
 						backendNamespace := gatewayapi.NamespaceDerefOrAlpha(backendRef.Namespace, ep.Namespace)
-						resourceMap.allAssociatedBackendRefs[gwapiv1.BackendObjectReference{
+						resourceMap.allAssociatedBackendRefs.Insert(gwapiv1.BackendObjectReference{
 							Group:     backendRef.BackendObjectReference.Group,
 							Kind:      backendRef.BackendObjectReference.Kind,
 							Namespace: gatewayapi.NamespacePtrV1Alpha2(backendNamespace),
 							Name:      backendRef.Name,
-						}] = struct{}{}
+						})
 
 					}
 				}
@@ -1701,12 +1704,12 @@ func (r *gatewayAPIReconciler) processEnvoyExtensionPolicyObjectRefs(
 				backendRef := br.BackendObjectReference
 
 				backendNamespace := gatewayapi.NamespaceDerefOr(backendRef.Namespace, policy.Namespace)
-				resourceMap.allAssociatedBackendRefs[gwapiv1.BackendObjectReference{
+				resourceMap.allAssociatedBackendRefs.Insert(gwapiv1.BackendObjectReference{
 					Group:     backendRef.Group,
 					Kind:      backendRef.Kind,
 					Namespace: gatewayapi.NamespacePtrV1Alpha2(backendNamespace),
 					Name:      backendRef.Name,
-				}] = struct{}{}
+				})
 
 				if backendNamespace != policy.Namespace {
 					from := ObjectKindNamespacedName{
diff --git a/internal/provider/kubernetes/indexers.go b/internal/provider/kubernetes/indexers.go
index 62b11f689..57c13997f 100644
--- a/internal/provider/kubernetes/indexers.go
+++ b/internal/provider/kubernetes/indexers.go
@@ -9,6 +9,7 @@ import (
 	"context"
 
 	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/apimachinery/pkg/util/sets"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/manager"
 	gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
@@ -40,6 +41,7 @@ const (
 	secretCtpIndex                   = "secretCtpIndex"
 	configMapBtlsIndex               = "configMapBtlsIndex"
 	backendEnvoyExtensionPolicyIndex = "backendEnvoyExtensionPolicyIndex"
+	backendEnvoyProxyTelemetryIndex  = "backendEnvoyProxyTelemetryIndex"
 )
 
 func addReferenceGrantIndexers(ctx context.Context, mgr manager.Manager) error {
@@ -109,6 +111,99 @@ func backendHTTPRouteIndexFunc(rawObj client.Object) []string {
 	return backendRefs
 }
 
+func addEnvoyProxyIndexers(ctx context.Context, mgr manager.Manager) error {
+	if err := mgr.GetFieldIndexer().IndexField(ctx, &v1alpha1.EnvoyProxy{}, backendEnvoyProxyTelemetryIndex, backendEnvoyProxyTelemetryIndexFunc); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func backendEnvoyProxyTelemetryIndexFunc(rawObj client.Object) []string {
+	ep := rawObj.(*v1alpha1.EnvoyProxy)
+
+	refs := sets.New[string]()
+	refs.Insert(accessLogRefs(ep)...)
+	refs.Insert(metricRefs(ep)...)
+	refs.Insert(traceRefs(ep)...)
+
+	return refs.UnsortedList()
+}
+
+func accessLogRefs(ep *v1alpha1.EnvoyProxy) []string {
+	var refs []string
+
+	if ep.Spec.Telemetry == nil || ep.Spec.Telemetry.Metrics == nil {
+		return refs
+	}
+
+	for _, sink := range ep.Spec.Telemetry.Metrics.Sinks {
+		if sink.OpenTelemetry != nil {
+			otel := sink.OpenTelemetry
+			if otel.BackendRefs != nil {
+				for _, ref := range otel.BackendRefs {
+					if ref.Kind == nil || string(*ref.Kind) == gatewayapi.KindService {
+						refs = append(refs,
+							types.NamespacedName{
+								Namespace: gatewayapi.NamespaceDerefOr(ref.Namespace, ep.Namespace),
+								Name:      string(ref.Name),
+							}.String(),
+						)
+					}
+				}
+			}
+		}
+	}
+
+	return refs
+}
+
+func metricRefs(ep *v1alpha1.EnvoyProxy) []string {
+	var refs []string
+
+	if ep.Spec.Telemetry == nil || ep.Spec.Telemetry.Metrics == nil {
+		return refs
+	}
+
+	for _, sink := range ep.Spec.Telemetry.Metrics.Sinks {
+		if sink.OpenTelemetry != nil {
+			for _, backend := range sink.OpenTelemetry.BackendRefs {
+				if backend.Kind == nil || string(*backend.Kind) == gatewayapi.KindService {
+					refs = append(refs,
+						types.NamespacedName{
+							Namespace: gatewayapi.NamespaceDerefOr(backend.Namespace, ep.Namespace),
+							Name:      string(backend.Name),
+						}.String(),
+					)
+				}
+			}
+		}
+	}
+
+	return refs
+}
+
+func traceRefs(ep *v1alpha1.EnvoyProxy) []string {
+	var refs []string
+
+	if ep.Spec.Telemetry == nil || ep.Spec.Telemetry.Tracing == nil {
+		return refs
+	}
+
+	for _, ref := range ep.Spec.Telemetry.Tracing.Provider.BackendRefs {
+		if ref.Kind == nil || string(*ref.Kind) == gatewayapi.KindService {
+			refs = append(refs,
+				types.NamespacedName{
+					Namespace: gatewayapi.NamespaceDerefOr(ref.Namespace, ep.Namespace),
+					Name:      string(ref.Name),
+				}.String(),
+			)
+		}
+	}
+
+	return refs
+}
+
 // addGRPCRouteIndexers adds indexing on GRPCRoute, for Service objects that are
 // referenced in GRPCRoute objects via `.spec.rules.backendRefs`. This helps in
 // querying for GRPCRoutes that are affected by a particular Service CRUD.
diff --git a/internal/provider/kubernetes/predicates.go b/internal/provider/kubernetes/predicates.go
index c852bffda..9b6eb4a87 100644
--- a/internal/provider/kubernetes/predicates.go
+++ b/internal/provider/kubernetes/predicates.go
@@ -249,6 +249,10 @@ func (r *gatewayAPIReconciler) validateServiceForReconcile(obj client.Object) bo
 		return true
 	}
 
+	if r.isEnvoyProxyReferencingBackend(&nsName) {
+		return true
+	}
+
 	return r.isEnvoyExtensionPolicyReferencingBackend(&nsName)
 }
 
@@ -547,3 +551,15 @@ func (r *gatewayAPIReconciler) isEnvoyExtensionPolicyReferencingBackend(nsName *
 
 	return len(spList.Items) > 0
 }
+
+func (r *gatewayAPIReconciler) isEnvoyProxyReferencingBackend(nn *types.NamespacedName) bool {
+	proxyList := &egv1a1.EnvoyProxyList{}
+	if err := r.client.List(context.Background(), proxyList, &client.ListOptions{
+		FieldSelector: fields.OneTermEqualSelector(backendEnvoyProxyTelemetryIndex, nn.String()),
+	}); err != nil {
+		r.log.Error(err, "unable to find associated EnvoyProxies")
+		return false
+	}
+
+	return len(proxyList.Items) > 0
+}
diff --git a/internal/provider/kubernetes/routes.go b/internal/provider/kubernetes/routes.go
index 76991be99..32e2f4703 100644
--- a/internal/provider/kubernetes/routes.go
+++ b/internal/provider/kubernetes/routes.go
@@ -44,7 +44,8 @@ func (r *gatewayAPIReconciler) processTLSRoutes(ctx context.Context, gatewayName
 			}
 		}
 
-		if _, ok := resourceMap.allAssociatedTLSRoutes[utils.NamespacedName(&tlsRoute).String()]; ok {
+		key := utils.NamespacedName(&tlsRoute).String()
+		if resourceMap.allAssociatedTLSRoutes.Has(key) {
 			r.log.Info("current TLSRoute has been processed already", "namespace", tlsRoute.Namespace, "name", tlsRoute.Name)
 			continue
 		}
@@ -61,12 +62,12 @@ func (r *gatewayAPIReconciler) processTLSRoutes(ctx context.Context, gatewayName
 				}
 
 				backendNamespace := gatewayapi.NamespaceDerefOrAlpha(backendRef.Namespace, tlsRoute.Namespace)
-				resourceMap.allAssociatedBackendRefs[gwapiv1.BackendObjectReference{
+				resourceMap.allAssociatedBackendRefs.Insert(gwapiv1.BackendObjectReference{
 					Group:     backendRef.BackendObjectReference.Group,
 					Kind:      backendRef.BackendObjectReference.Kind,
 					Namespace: gatewayapi.NamespacePtrV1Alpha2(backendNamespace),
 					Name:      backendRef.Name,
-				}] = struct{}{}
+				})
 
 				if backendNamespace != tlsRoute.Namespace {
 					from := ObjectKindNamespacedName{kind: gatewayapi.KindTLSRoute, namespace: tlsRoute.Namespace, name: tlsRoute.Name}
@@ -87,8 +88,8 @@ func (r *gatewayAPIReconciler) processTLSRoutes(ctx context.Context, gatewayName
 			}
 		}
 
-		resourceMap.allAssociatedNamespaces[tlsRoute.Namespace] = struct{}{}
-		resourceMap.allAssociatedTLSRoutes[utils.NamespacedName(&tlsRoute).String()] = struct{}{}
+		resourceMap.allAssociatedNamespaces.Insert(tlsRoute.Namespace)
+		resourceMap.allAssociatedTLSRoutes.Insert(key)
 		// Discard Status to reduce memory consumption in watchable
 		// It will be recomputed by the gateway-api layer
 		tlsRoute.Status = gwapiv1a2.TLSRouteStatus{}
@@ -123,7 +124,8 @@ func (r *gatewayAPIReconciler) processGRPCRoutes(ctx context.Context, gatewayNam
 			}
 		}
 
-		if _, ok := resourceMap.allAssociatedGRPCRoutes[utils.NamespacedName(&grpcRoute).String()]; ok {
+		key := utils.NamespacedName(&grpcRoute).String()
+		if resourceMap.allAssociatedGRPCRoutes.Has(key) {
 			r.log.Info("current GRPCRoute has been processed already", "namespace", grpcRoute.Namespace, "name", grpcRoute.Name)
 			continue
 		}
@@ -139,12 +141,12 @@ func (r *gatewayAPIReconciler) processGRPCRoutes(ctx context.Context, gatewayNam
 				}
 
 				backendNamespace := gatewayapi.NamespaceDerefOr(backendRef.Namespace, grpcRoute.Namespace)
-				resourceMap.allAssociatedBackendRefs[gwapiv1.BackendObjectReference{
+				resourceMap.allAssociatedBackendRefs.Insert(gwapiv1.BackendObjectReference{
 					Group:     backendRef.BackendObjectReference.Group,
 					Kind:      backendRef.BackendObjectReference.Kind,
 					Namespace: gatewayapi.NamespacePtrV1Alpha2(backendNamespace),
 					Name:      backendRef.Name,
-				}] = struct{}{}
+				})
 
 				if backendNamespace != grpcRoute.Namespace {
 					from := ObjectKindNamespacedName{
@@ -212,8 +214,8 @@ func (r *gatewayAPIReconciler) processGRPCRoutes(ctx context.Context, gatewayNam
 			}
 		}
 
-		resourceMap.allAssociatedNamespaces[grpcRoute.Namespace] = struct{}{}
-		resourceMap.allAssociatedGRPCRoutes[utils.NamespacedName(&grpcRoute).String()] = struct{}{}
+		resourceMap.allAssociatedNamespaces.Insert(grpcRoute.Namespace)
+		resourceMap.allAssociatedGRPCRoutes.Insert(key)
 		// Discard Status to reduce memory consumption in watchable
 		// It will be recomputed by the gateway-api layer
 		grpcRoute.Status = gwapiv1.GRPCRouteStatus{}
@@ -257,7 +259,8 @@ func (r *gatewayAPIReconciler) processHTTPRoutes(ctx context.Context, gatewayNam
 			}
 		}
 
-		if _, ok := resourceMap.allAssociatedHTTPRoutes[utils.NamespacedName(&httpRoute).String()]; ok {
+		key := utils.NamespacedName(&httpRoute).String()
+		if resourceMap.allAssociatedHTTPRoutes.Has(key) {
 			r.log.Info("current HTTPRoute has been processed already", "namespace", httpRoute.Namespace, "name", httpRoute.Name)
 			continue
 		}
@@ -273,12 +276,12 @@ func (r *gatewayAPIReconciler) processHTTPRoutes(ctx context.Context, gatewayNam
 				}
 
 				backendNamespace := gatewayapi.NamespaceDerefOr(backendRef.Namespace, httpRoute.Namespace)
-				resourceMap.allAssociatedBackendRefs[gwapiv1.BackendObjectReference{
+				resourceMap.allAssociatedBackendRefs.Insert(gwapiv1.BackendObjectReference{
 					Group:     backendRef.BackendObjectReference.Group,
 					Kind:      backendRef.BackendObjectReference.Kind,
 					Namespace: gatewayapi.NamespacePtrV1Alpha2(backendNamespace),
 					Name:      backendRef.Name,
-				}] = struct{}{}
+				})
 
 				if backendNamespace != httpRoute.Namespace {
 					from := ObjectKindNamespacedName{
@@ -340,12 +343,12 @@ func (r *gatewayAPIReconciler) processHTTPRoutes(ctx context.Context, gatewayNam
 					}
 
 					backendNamespace := gatewayapi.NamespaceDerefOr(mirrorBackendRef.Namespace, httpRoute.Namespace)
-					resourceMap.allAssociatedBackendRefs[gwapiv1.BackendObjectReference{
+					resourceMap.allAssociatedBackendRefs.Insert(gwapiv1.BackendObjectReference{
 						Group:     mirrorBackendRef.BackendObjectReference.Group,
 						Kind:      mirrorBackendRef.BackendObjectReference.Kind,
 						Namespace: gatewayapi.NamespacePtrV1Alpha2(backendNamespace),
 						Name:      mirrorBackendRef.Name,
-					}] = struct{}{}
+					})
 
 					if backendNamespace != httpRoute.Namespace {
 						from := ObjectKindNamespacedName{
@@ -399,8 +402,8 @@ func (r *gatewayAPIReconciler) processHTTPRoutes(ctx context.Context, gatewayNam
 			}
 		}
 
-		resourceMap.allAssociatedNamespaces[httpRoute.Namespace] = struct{}{}
-		resourceMap.allAssociatedHTTPRoutes[utils.NamespacedName(&httpRoute).String()] = struct{}{}
+		resourceMap.allAssociatedNamespaces.Insert(httpRoute.Namespace)
+		resourceMap.allAssociatedHTTPRoutes.Insert(key)
 		// Discard Status to reduce memory consumption in watchable
 		// It will be recomputed by the gateway-api layer
 		httpRoute.Status = gwapiv1.HTTPRouteStatus{}
@@ -434,7 +437,8 @@ func (r *gatewayAPIReconciler) processTCPRoutes(ctx context.Context, gatewayName
 			}
 		}
 
-		if _, ok := resourceMap.allAssociatedTCPRoutes[utils.NamespacedName(&tcpRoute).String()]; ok {
+		key := utils.NamespacedName(&tcpRoute).String()
+		if resourceMap.allAssociatedTCPRoutes.Has(key) {
 			r.log.Info("current TCPRoute has been processed already", "namespace", tcpRoute.Namespace, "name", tcpRoute.Name)
 			continue
 		}
@@ -451,12 +455,12 @@ func (r *gatewayAPIReconciler) processTCPRoutes(ctx context.Context, gatewayName
 				}
 
 				backendNamespace := gatewayapi.NamespaceDerefOrAlpha(backendRef.Namespace, tcpRoute.Namespace)
-				resourceMap.allAssociatedBackendRefs[gwapiv1.BackendObjectReference{
+				resourceMap.allAssociatedBackendRefs.Insert(gwapiv1.BackendObjectReference{
 					Group:     backendRef.BackendObjectReference.Group,
 					Kind:      backendRef.BackendObjectReference.Kind,
 					Namespace: gatewayapi.NamespacePtrV1Alpha2(backendNamespace),
 					Name:      backendRef.Name,
-				}] = struct{}{}
+				})
 
 				if backendNamespace != tcpRoute.Namespace {
 					from := ObjectKindNamespacedName{kind: gatewayapi.KindTCPRoute, namespace: tcpRoute.Namespace, name: tcpRoute.Name}
@@ -477,8 +481,8 @@ func (r *gatewayAPIReconciler) processTCPRoutes(ctx context.Context, gatewayName
 			}
 		}
 
-		resourceMap.allAssociatedNamespaces[tcpRoute.Namespace] = struct{}{}
-		resourceMap.allAssociatedTCPRoutes[utils.NamespacedName(&tcpRoute).String()] = struct{}{}
+		resourceMap.allAssociatedNamespaces.Insert(tcpRoute.Namespace)
+		resourceMap.allAssociatedTCPRoutes.Insert(key)
 		// Discard Status to reduce memory consumption in watchable
 		// It will be recomputed by the gateway-api layer
 		tcpRoute.Status = gwapiv1a2.TCPRouteStatus{}
@@ -512,7 +516,8 @@ func (r *gatewayAPIReconciler) processUDPRoutes(ctx context.Context, gatewayName
 			}
 		}
 
-		if _, ok := resourceMap.allAssociatedUDPRoutes[utils.NamespacedName(&udpRoute).String()]; ok {
+		key := utils.NamespacedName(&udpRoute).String()
+		if resourceMap.allAssociatedUDPRoutes.Has(key) {
 			r.log.Info("current UDPRoute has been processed already", "namespace", udpRoute.Namespace, "name", udpRoute.Name)
 			continue
 		}
@@ -529,12 +534,12 @@ func (r *gatewayAPIReconciler) processUDPRoutes(ctx context.Context, gatewayName
 				}
 
 				backendNamespace := gatewayapi.NamespaceDerefOrAlpha(backendRef.Namespace, udpRoute.Namespace)
-				resourceMap.allAssociatedBackendRefs[gwapiv1.BackendObjectReference{
+				resourceMap.allAssociatedBackendRefs.Insert(gwapiv1.BackendObjectReference{
 					Group:     backendRef.BackendObjectReference.Group,
 					Kind:      backendRef.BackendObjectReference.Kind,
 					Namespace: gatewayapi.NamespacePtrV1Alpha2(backendNamespace),
 					Name:      backendRef.Name,
-				}] = struct{}{}
+				})
 
 				if backendNamespace != udpRoute.Namespace {
 					from := ObjectKindNamespacedName{kind: gatewayapi.KindUDPRoute, namespace: udpRoute.Namespace, name: udpRoute.Name}
@@ -555,8 +560,8 @@ func (r *gatewayAPIReconciler) processUDPRoutes(ctx context.Context, gatewayName
 			}
 		}
 
-		resourceMap.allAssociatedNamespaces[udpRoute.Namespace] = struct{}{}
-		resourceMap.allAssociatedUDPRoutes[utils.NamespacedName(&udpRoute).String()] = struct{}{}
+		resourceMap.allAssociatedNamespaces.Insert(udpRoute.Namespace)
+		resourceMap.allAssociatedUDPRoutes.Insert(key)
 		// Discard Status to reduce memory consumption in watchable
 		// It will be recomputed by the gateway-api layer
 		udpRoute.Status = gwapiv1a2.UDPRouteStatus{}
diff --git a/internal/xds/translator/cluster.go b/internal/xds/translator/cluster.go
index a37f2a911..1b5ed80d6 100644
--- a/internal/xds/translator/cluster.go
+++ b/internal/xds/translator/cluster.go
@@ -185,6 +185,14 @@ func buildXdsCluster(args *xdsClusterArgs) *clusterv3.Cluster {
 		cluster.LbPolicy = clusterv3.Cluster_RANDOM
 	} else if args.loadBalancer.ConsistentHash != nil {
 		cluster.LbPolicy = clusterv3.Cluster_MAGLEV
+
+		if args.loadBalancer.ConsistentHash.TableSize != nil {
+			cluster.LbConfig = &clusterv3.Cluster_MaglevLbConfig_{
+				MaglevLbConfig: &clusterv3.Cluster_MaglevLbConfig{
+					TableSize: &wrapperspb.UInt64Value{Value: *args.loadBalancer.ConsistentHash.TableSize},
+				},
+			}
+		}
 	}
 
 	if args.healthCheck != nil && args.healthCheck.Active != nil {
diff --git a/internal/xds/translator/listener.go b/internal/xds/translator/listener.go
index 995c4bc3a..d208c0603 100644
--- a/internal/xds/translator/listener.go
+++ b/internal/xds/translator/listener.go
@@ -390,7 +390,7 @@ func findXdsHTTPRouteConfigName(xdsListener *listenerv3.Listener) string {
 	return ""
 }
 
-func addXdsTCPFilterChain(xdsListener *listenerv3.Listener, irRoute *ir.TCPRoute, clusterName string, accesslog *ir.AccessLog, connection *ir.Connection) error {
+func addXdsTCPFilterChain(xdsListener *listenerv3.Listener, irRoute *ir.TCPRoute, clusterName string, accesslog *ir.AccessLog, timeout *ir.ClientTimeout, connection *ir.Connection) error {
 	if irRoute == nil {
 		return errors.New("tcp listener is nil")
 	}
@@ -415,6 +415,12 @@ func addXdsTCPFilterChain(xdsListener *listenerv3.Listener, irRoute *ir.TCPRoute
 		HashPolicy: buildTCPProxyHashPolicy(irRoute.LoadBalancer),
 	}
 
+	if timeout != nil && timeout.TCP != nil {
+		if timeout.TCP.IdleTimeout != nil {
+			mgr.IdleTimeout = durationpb.New(timeout.TCP.IdleTimeout.Duration)
+		}
+	}
+
 	var filters []*listenerv3.Filter
 
 	if connection != nil && connection.ConnectionLimit != nil {
diff --git a/internal/xds/translator/translator.go b/internal/xds/translator/translator.go
index 2cf7fd22b..6dc07bfa3 100644
--- a/internal/xds/translator/translator.go
+++ b/internal/xds/translator/translator.go
@@ -544,7 +544,7 @@ func processTCPListenerXdsTranslation(tCtx *types.ResourceVersionTable, tcpListe
 					}
 				}
 			}
-			if err := addXdsTCPFilterChain(xdsListener, route, route.Destination.Name, accesslog, tcpListener.Connection); err != nil {
+			if err := addXdsTCPFilterChain(xdsListener, route, route.Destination.Name, accesslog, tcpListener.Timeout, tcpListener.Connection); err != nil {
 				errs = errors.Join(errs, err)
 			}
 		}


Test patch:
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer-invalid-consistent-hash-table-size.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer-invalid-consistent-hash-table-size.in.yaml
new file mode 100644
index 000000000..0d6bf7ed3
--- /dev/null
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer-invalid-consistent-hash-table-size.in.yaml
@@ -0,0 +1,83 @@
+gateways:
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: Gateway
+  metadata:
+    namespace: envoy-gateway
+    name: gateway-1
+  spec:
+    gatewayClassName: envoy-gateway-class
+    listeners:
+    - name: http
+      protocol: HTTP
+      port: 80
+      allowedRoutes:
+        namespaces:
+          from: All
+httpRoutes:
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    namespace: default
+    name: httproute-1
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - namespace: envoy-gateway
+      name: gateway-1
+      sectionName: http
+    rules:
+    - matches:
+      - path:
+          value: "/"
+      backendRefs:
+      - name: service-1
+        port: 8080
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    namespace: default
+    name: httproute-2
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - namespace: envoy-gateway
+      name: gateway-1
+      sectionName: http
+    rules:
+    - matches:
+      - path:
+          value: "/test2"
+      backendRefs:
+      - name: service-2
+        port: 8080
+backendTrafficPolicies:
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: BackendTrafficPolicy
+  metadata:
+    namespace: default
+    name: policy-for-route
+  spec:
+    targetRef:
+      group: gateway.networking.k8s.io
+      kind: HTTPRoute
+      name: httproute-1
+    loadBalancer:
+      type: ConsistentHash
+      consistentHash:
+        tableSize: 1024
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: BackendTrafficPolicy
+  metadata:
+    namespace: default
+    name: policy-for-route2
+  spec:
+    targetRef:
+      group: gateway.networking.k8s.io
+      kind: HTTPRoute
+      name: httproute-2
+    loadBalancer:
+      type: ConsistentHash
+      consistentHash:
+        tableSize: 5000012
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer-invalid-consistent-hash-table-size.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer-invalid-consistent-hash-table-size.out.yaml
new file mode 100755
index 000000000..735381efd
--- /dev/null
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer-invalid-consistent-hash-table-size.out.yaml
@@ -0,0 +1,245 @@
+backendTrafficPolicies:
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: BackendTrafficPolicy
+  metadata:
+    creationTimestamp: null
+    name: policy-for-route
+    namespace: default
+  spec:
+    loadBalancer:
+      consistentHash:
+        tableSize: 1024
+        type: ""
+      type: ConsistentHash
+    targetRef:
+      group: gateway.networking.k8s.io
+      kind: HTTPRoute
+      name: httproute-1
+  status:
+    ancestors:
+    - ancestorRef:
+        group: gateway.networking.k8s.io
+        kind: Gateway
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+      conditions:
+      - lastTransitionTime: null
+        message: 'LoadBalancer: ConsistentHash: invalid TableSize value 1024.'
+        reason: Invalid
+        status: "False"
+        type: Accepted
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: BackendTrafficPolicy
+  metadata:
+    creationTimestamp: null
+    name: policy-for-route2
+    namespace: default
+  spec:
+    loadBalancer:
+      consistentHash:
+        tableSize: 5000012
+        type: ""
+      type: ConsistentHash
+    targetRef:
+      group: gateway.networking.k8s.io
+      kind: HTTPRoute
+      name: httproute-2
+  status:
+    ancestors:
+    - ancestorRef:
+        group: gateway.networking.k8s.io
+        kind: Gateway
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+      conditions:
+      - lastTransitionTime: null
+        message: 'LoadBalancer: ConsistentHash: invalid TableSize value 5000012.'
+        reason: Invalid
+        status: "False"
+        type: Accepted
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+gateways:
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: Gateway
+  metadata:
+    creationTimestamp: null
+    name: gateway-1
+    namespace: envoy-gateway
+  spec:
+    gatewayClassName: envoy-gateway-class
+    listeners:
+    - allowedRoutes:
+        namespaces:
+          from: All
+      name: http
+      port: 80
+      protocol: HTTP
+  status:
+    listeners:
+    - attachedRoutes: 2
+      conditions:
+      - lastTransitionTime: null
+        message: Sending translated listener configuration to the data plane
+        reason: Programmed
+        status: "True"
+        type: Programmed
+      - lastTransitionTime: null
+        message: Listener has been successfully translated
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Listener references have been resolved
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      name: http
+      supportedKinds:
+      - group: gateway.networking.k8s.io
+        kind: HTTPRoute
+      - group: gateway.networking.k8s.io
+        kind: GRPCRoute
+httpRoutes:
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    creationTimestamp: null
+    name: httproute-1
+    namespace: default
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - name: gateway-1
+      namespace: envoy-gateway
+      sectionName: http
+    rules:
+    - backendRefs:
+      - name: service-1
+        port: 8080
+      matches:
+      - path:
+          value: /
+  status:
+    parents:
+    - conditions:
+      - lastTransitionTime: null
+        message: Route is accepted
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    creationTimestamp: null
+    name: httproute-2
+    namespace: default
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - name: gateway-1
+      namespace: envoy-gateway
+      sectionName: http
+    rules:
+    - backendRefs:
+      - name: service-2
+        port: 8080
+      matches:
+      - path:
+          value: /test2
+  status:
+    parents:
+    - conditions:
+      - lastTransitionTime: null
+        message: Route is accepted
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+infraIR:
+  envoy-gateway/gateway-1:
+    proxy:
+      listeners:
+      - address: null
+        name: envoy-gateway/gateway-1/http
+        ports:
+        - containerPort: 10080
+          name: http-80
+          protocol: HTTP
+          servicePort: 80
+      metadata:
+        labels:
+          gateway.envoyproxy.io/owning-gateway-name: gateway-1
+          gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway
+      name: envoy-gateway/gateway-1
+xdsIR:
+  envoy-gateway/gateway-1:
+    accessLog:
+      text:
+      - path: /dev/stdout
+    http:
+    - address: 0.0.0.0
+      hostnames:
+      - '*'
+      isHTTP2: false
+      name: envoy-gateway/gateway-1/http
+      path:
+        escapedSlashesAction: UnescapeAndRedirect
+        mergeSlashes: true
+      port: 10080
+      routes:
+      - destination:
+          name: httproute/default/httproute-2/rule/0
+          settings:
+          - addressType: IP
+            endpoints:
+            - host: 7.7.7.7
+              port: 8080
+            protocol: HTTP
+            weight: 1
+        hostname: gateway.envoyproxy.io
+        isHTTP2: false
+        name: httproute/default/httproute-2/rule/0/match/0/gateway_envoyproxy_io
+        pathMatch:
+          distinct: false
+          name: ""
+          prefix: /test2
+      - destination:
+          name: httproute/default/httproute-1/rule/0
+          settings:
+          - addressType: IP
+            endpoints:
+            - host: 7.7.7.7
+              port: 8080
+            protocol: HTTP
+            weight: 1
+        hostname: gateway.envoyproxy.io
+        isHTTP2: false
+        name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io
+        pathMatch:
+          distinct: false
+          name: ""
+          prefix: /
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.in.yaml
index 8dc0366ed..f8bb9de05 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.in.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.in.yaml
@@ -108,6 +108,7 @@ backendTrafficPolicies:
       type: ConsistentHash
       consistentHash:
         type: SourceIP
+        tableSize: 524287
 - apiVersion: gateway.envoyproxy.io/v1alpha1
   kind: BackendTrafficPolicy
   metadata:
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.out.yaml
index 36fe54c46..a8a13a92d 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.out.yaml
@@ -8,6 +8,7 @@ backendTrafficPolicies:
   spec:
     loadBalancer:
       consistentHash:
+        tableSize: 524287
         type: SourceIP
       type: ConsistentHash
     targetRef:
@@ -431,3 +432,4 @@ xdsIR:
           loadBalancer:
             consistentHash:
               sourceIP: true
+              tableSize: 524287
diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-for-tcp-listeners.in.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-for-tcp-listeners.in.yaml
index 70b9fa531..f3ef317db 100644
--- a/internal/gatewayapi/testdata/clienttrafficpolicy-for-tcp-listeners.in.yaml
+++ b/internal/gatewayapi/testdata/clienttrafficpolicy-for-tcp-listeners.in.yaml
@@ -15,6 +15,9 @@ clientTrafficPolicies:
         value: 3
         closeDelay: 10s
     enableProxyProtocol: true
+    timeout:
+      tcp:
+        idleTimeout: 1200s
     tls:
       minVersion: "1.0"
       maxVersion: "1.2"
diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-for-tcp-listeners.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-for-tcp-listeners.out.yaml
index d9d034689..efd290c9b 100755
--- a/internal/gatewayapi/testdata/clienttrafficpolicy-for-tcp-listeners.out.yaml
+++ b/internal/gatewayapi/testdata/clienttrafficpolicy-for-tcp-listeners.out.yaml
@@ -20,6 +20,9 @@ clientTrafficPolicies:
       idleTime: 20m
       interval: 60s
       probes: 3
+    timeout:
+      tcp:
+        idleTimeout: 1200s
     tls:
       alpnProtocols:
       - h2
@@ -223,6 +226,9 @@ xdsIR:
         idleTime: 1200
         interval: 60
         probes: 3
+      timeout:
+        tcp:
+          idleTimeout: 20m0s
       tls:
         alpnProtocols:
         - h2
@@ -264,3 +270,6 @@ xdsIR:
         idleTime: 1200
         interval: 60
         probes: 3
+      timeout:
+        tcp:
+          idleTimeout: 20m0s
diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-idle-timeout-with-error.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-idle-timeout-with-error.out.yaml
index 6989cb91d..6a51d5552 100755
--- a/internal/gatewayapi/testdata/clienttrafficpolicy-idle-timeout-with-error.out.yaml
+++ b/internal/gatewayapi/testdata/clienttrafficpolicy-idle-timeout-with-error.out.yaml
@@ -22,7 +22,7 @@ clientTrafficPolicies:
         namespace: envoy-gateway
       conditions:
       - lastTransitionTime: null
-        message: 'Timeout: time: unknown unit "sec" in duration "10sec".'
+        message: 'Timeout: invalid HTTP RequestReceivedTimeout value 10sec.'
         reason: Invalid
         status: "False"
         type: Accepted
diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-timeout-with-error.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-timeout-with-error.out.yaml
index 7efaef7eb..d362b30ca 100644
--- a/internal/gatewayapi/testdata/clienttrafficpolicy-timeout-with-error.out.yaml
+++ b/internal/gatewayapi/testdata/clienttrafficpolicy-timeout-with-error.out.yaml
@@ -22,7 +22,7 @@ clientTrafficPolicies:
         namespace: envoy-gateway
       conditions:
       - lastTransitionTime: null
-        message: 'Timeout: time: unknown unit "sec" in duration "5sec".'
+        message: 'Timeout: invalid HTTP RequestReceivedTimeout value 5sec.'
         reason: Invalid
         status: "False"
         type: Accepted
diff --git a/internal/provider/kubernetes/predicates_test.go b/internal/provider/kubernetes/predicates_test.go
index debeacdf1..f5416c198 100644
--- a/internal/provider/kubernetes/predicates_test.go
+++ b/internal/provider/kubernetes/predicates_test.go
@@ -379,6 +379,70 @@ func TestValidateEndpointSliceForReconcile(t *testing.T) {
 func TestValidateServiceForReconcile(t *testing.T) {
 	sampleGateway := test.GetGateway(types.NamespacedName{Namespace: "default", Name: "scheduled-status-test"}, "test-gc", 8080)
 	mergeGatewaysConfig := test.GetEnvoyProxy(types.NamespacedName{Namespace: "default", Name: "merge-gateways-config"}, true)
+	telemetryEnabledGatewaysConfig := &v1alpha1.EnvoyProxy{
+		ObjectMeta: metav1.ObjectMeta{
+			Namespace: "default",
+			Name:      "telemetry",
+		},
+		Spec: v1alpha1.EnvoyProxySpec{
+			Telemetry: &v1alpha1.ProxyTelemetry{
+				AccessLog: &v1alpha1.ProxyAccessLog{
+					Settings: []v1alpha1.ProxyAccessLogSetting{
+						{
+							Sinks: []v1alpha1.ProxyAccessLogSink{
+								{
+									Type: v1alpha1.ProxyAccessLogSinkTypeOpenTelemetry,
+									OpenTelemetry: &v1alpha1.OpenTelemetryEnvoyProxyAccessLog{
+										BackendRefs: []v1alpha1.BackendRef{
+											{
+												BackendObjectReference: gwapiv1.BackendObjectReference{
+													Name:      "otel-collector",
+													Namespace: ptr.To(gwapiv1.Namespace("default")),
+													Port:      ptr.To(gwapiv1.PortNumber(4317)),
+												},
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+				Metrics: &v1alpha1.ProxyMetrics{
+					Sinks: []v1alpha1.ProxyMetricSink{
+						{
+							Type: v1alpha1.MetricSinkTypeOpenTelemetry,
+							OpenTelemetry: &v1alpha1.ProxyOpenTelemetrySink{
+								BackendRefs: []v1alpha1.BackendRef{
+									{
+										BackendObjectReference: gwapiv1.BackendObjectReference{
+											Name:      "otel-collector",
+											Namespace: ptr.To(gwapiv1.Namespace("default")),
+											Port:      ptr.To(gwapiv1.PortNumber(4317)),
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+				Tracing: &v1alpha1.ProxyTracing{
+					Provider: v1alpha1.TracingProvider{
+						Type: v1alpha1.TracingProviderTypeOpenTelemetry,
+						BackendRefs: []v1alpha1.BackendRef{
+							{
+								BackendObjectReference: gwapiv1.BackendObjectReference{
+									Name:      "otel-collector",
+									Namespace: ptr.To(gwapiv1.Namespace("default")),
+									Port:      ptr.To(gwapiv1.PortNumber(4317)),
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
 
 	testCases := []struct {
 		name    string
@@ -487,6 +551,34 @@ func TestValidateServiceForReconcile(t *testing.T) {
 			service: test.GetService(types.NamespacedName{Name: "service"}, nil, nil),
 			expect:  true,
 		},
+		{
+			name: "service referenced by EnvoyProxy updated",
+			configs: []client.Object{
+				test.GetGatewayClass("test-mg", v1alpha1.GatewayControllerName, &test.GroupKindNamespacedName{
+					Group:     gwapiv1.Group(telemetryEnabledGatewaysConfig.GroupVersionKind().Group),
+					Kind:      gwapiv1.Kind(telemetryEnabledGatewaysConfig.Kind),
+					Namespace: gwapiv1.Namespace(telemetryEnabledGatewaysConfig.Namespace),
+					Name:      gwapiv1.ObjectName(telemetryEnabledGatewaysConfig.Name),
+				}),
+				telemetryEnabledGatewaysConfig,
+			},
+			service: test.GetService(types.NamespacedName{Name: "otel-collector", Namespace: "default"}, nil, nil),
+			expect:  true,
+		},
+		{
+			name: "service referenced by EnvoyProxy unrelated",
+			configs: []client.Object{
+				test.GetGatewayClass("test-mg", v1alpha1.GatewayControllerName, &test.GroupKindNamespacedName{
+					Group:     gwapiv1.Group(telemetryEnabledGatewaysConfig.GroupVersionKind().Group),
+					Kind:      gwapiv1.Kind(telemetryEnabledGatewaysConfig.Kind),
+					Namespace: gwapiv1.Namespace(telemetryEnabledGatewaysConfig.Namespace),
+					Name:      gwapiv1.ObjectName(telemetryEnabledGatewaysConfig.Name),
+				}),
+				telemetryEnabledGatewaysConfig,
+			},
+			service: test.GetService(types.NamespacedName{Name: "otel-collector-unrelated", Namespace: "default"}, nil, nil),
+			expect:  false,
+		},
 		{
 			name: "service referenced by SecurityPolicy ExtAuth HTTP service",
 			configs: []client.Object{
@@ -634,6 +726,7 @@ func TestValidateServiceForReconcile(t *testing.T) {
 			WithIndex(&gwapiv1a2.UDPRoute{}, backendUDPRouteIndex, backendUDPRouteIndexFunc).
 			WithIndex(&v1alpha1.SecurityPolicy{}, backendSecurityPolicyIndex, backendSecurityPolicyIndexFunc).
 			WithIndex(&v1alpha1.EnvoyExtensionPolicy{}, backendEnvoyExtensionPolicyIndex, backendEnvoyExtensionPolicyIndexFunc).
+			WithIndex(&v1alpha1.EnvoyProxy{}, backendEnvoyProxyTelemetryIndex, backendEnvoyProxyTelemetryIndexFunc).
 			Build()
 		t.Run(tc.name, func(t *testing.T) {
 			res := r.validateServiceForReconcile(tc.service)
diff --git a/internal/xds/translator/testdata/in/xds-ir/client-timeout.yaml b/internal/xds/translator/testdata/in/xds-ir/client-timeout.yaml
index 6c3cfa3aa..741f2d464 100644
--- a/internal/xds/translator/testdata/in/xds-ir/client-timeout.yaml
+++ b/internal/xds/translator/testdata/in/xds-ir/client-timeout.yaml
@@ -20,3 +20,18 @@ http:
       http:
         requestReceivedTimeout: "5s"
         idleTimeout: "10s"
+tcp:
+  - name: "second-listener"
+    address: "0.0.0.0"
+    port: 10081
+    routes:
+      - name: "second-route"
+        destination:
+          name: "second-route-dest"
+          settings:
+            - endpoints:
+                - host: "1.2.3.4"
+                  port: 50000
+    timeout:
+      tcp:
+        idleTimeout: "1200s"
diff --git a/internal/xds/translator/testdata/in/xds-ir/load-balancer.yaml b/internal/xds/translator/testdata/in/xds-ir/load-balancer.yaml
index 2d8ef97ef..3886f0cfd 100644
--- a/internal/xds/translator/testdata/in/xds-ir/load-balancer.yaml
+++ b/internal/xds/translator/testdata/in/xds-ir/load-balancer.yaml
@@ -92,3 +92,15 @@ http:
       - endpoints:
         - host: "1.2.3.4"
           port: 50000
+  - name: "eighth-route"
+    hostname: "*"
+    traffic:
+      loadBalancer:
+        consistentHash:
+          tableSize: 524287
+    destination:
+      name: "eighth-route-dest"
+      settings:
+      - endpoints:
+        - host: "1.2.3.4"
+          port: 50000
diff --git a/internal/xds/translator/testdata/out/xds-ir/client-timeout.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/client-timeout.clusters.yaml
index d53a7a1b2..d65e267ad 100644
--- a/internal/xds/translator/testdata/out/xds-ir/client-timeout.clusters.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/client-timeout.clusters.yaml
@@ -15,3 +15,20 @@
   outlierDetection: {}
   perConnectionBufferLimitBytes: 32768
   type: EDS
+- circuitBreakers:
+    thresholds:
+    - maxRetries: 1024
+  commonLbConfig:
+    localityWeightedLbConfig: {}
+  connectTimeout: 10s
+  dnsLookupFamily: V4_ONLY
+  edsClusterConfig:
+    edsConfig:
+      ads: {}
+      resourceApiVersion: V3
+    serviceName: second-route-dest
+  lbPolicy: LEAST_REQUEST
+  name: second-route-dest
+  outlierDetection: {}
+  perConnectionBufferLimitBytes: 32768
+  type: EDS
diff --git a/internal/xds/translator/testdata/out/xds-ir/client-timeout.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/client-timeout.endpoints.yaml
index 3b3f2d090..de95bf555 100644
--- a/internal/xds/translator/testdata/out/xds-ir/client-timeout.endpoints.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/client-timeout.endpoints.yaml
@@ -10,3 +10,15 @@
     loadBalancingWeight: 1
     locality:
       region: first-route-dest/backend/0
+- clusterName: second-route-dest
+  endpoints:
+  - lbEndpoints:
+    - endpoint:
+        address:
+          socketAddress:
+            address: 1.2.3.4
+            portValue: 50000
+      loadBalancingWeight: 1
+    loadBalancingWeight: 1
+    locality:
+      region: second-route-dest/backend/0
diff --git a/internal/xds/translator/testdata/out/xds-ir/client-timeout.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/client-timeout.listeners.yaml
index bea4f4d1b..8869ee8fd 100644
--- a/internal/xds/translator/testdata/out/xds-ir/client-timeout.listeners.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/client-timeout.listeners.yaml
@@ -34,3 +34,18 @@
   drainType: MODIFY_ONLY
   name: first-listener
   perConnectionBufferLimitBytes: 32768
+- address:
+    socketAddress:
+      address: 0.0.0.0
+      portValue: 10081
+  drainType: MODIFY_ONLY
+  filterChains:
+  - filters:
+    - name: envoy.filters.network.tcp_proxy
+      typedConfig:
+        '@type': type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
+        cluster: second-route-dest
+        idleTimeout: 1200s
+        statPrefix: tcp
+  name: second-listener
+  perConnectionBufferLimitBytes: 32768
diff --git a/internal/xds/translator/testdata/out/xds-ir/load-balancer.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/load-balancer.clusters.yaml
index d9fedf2c8..204667fb0 100644
--- a/internal/xds/translator/testdata/out/xds-ir/load-balancer.clusters.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/load-balancer.clusters.yaml
@@ -121,3 +121,22 @@
   outlierDetection: {}
   perConnectionBufferLimitBytes: 32768
   type: EDS
+- circuitBreakers:
+    thresholds:
+    - maxRetries: 1024
+  commonLbConfig:
+    localityWeightedLbConfig: {}
+  connectTimeout: 10s
+  dnsLookupFamily: V4_ONLY
+  edsClusterConfig:
+    edsConfig:
+      ads: {}
+      resourceApiVersion: V3
+    serviceName: eighth-route-dest
+  lbPolicy: MAGLEV
+  maglevLbConfig:
+    tableSize: "524287"
+  name: eighth-route-dest
+  outlierDetection: {}
+  perConnectionBufferLimitBytes: 32768
+  type: EDS
diff --git a/internal/xds/translator/testdata/out/xds-ir/load-balancer.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/load-balancer.endpoints.yaml
index 0860c1852..e262710c4 100644
--- a/internal/xds/translator/testdata/out/xds-ir/load-balancer.endpoints.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/load-balancer.endpoints.yaml
@@ -82,3 +82,15 @@
     loadBalancingWeight: 1
     locality:
       region: seventh-route-dest/backend/0
+- clusterName: eighth-route-dest
+  endpoints:
+  - lbEndpoints:
+    - endpoint:
+        address:
+          socketAddress:
+            address: 1.2.3.4
+            portValue: 50000
+      loadBalancingWeight: 1
+    loadBalancingWeight: 1
+    locality:
+      region: eighth-route-dest/backend/0
diff --git a/internal/xds/translator/testdata/out/xds-ir/load-balancer.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/load-balancer.routes.yaml
index 080b9aaff..bb34436d3 100644
--- a/internal/xds/translator/testdata/out/xds-ir/load-balancer.routes.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/load-balancer.routes.yaml
@@ -60,3 +60,10 @@
             headerName: name
         upgradeConfigs:
         - upgradeType: websocket
+    - match:
+        prefix: /
+      name: eighth-route
+      route:
+        cluster: eighth-route-dest
+        upgradeConfigs:
+        - upgradeType: websocket
diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md
index 810eb3b83..b4bfec6a2 100644
--- a/site/content/en/latest/api/extension_types.md
+++ b/site/content/en/latest/api/extension_types.md
@@ -700,6 +700,7 @@ _Appears in:_
 | ---   | ---  | ---      | ---         |
 | `type` | _[ConsistentHashType](#consistenthashtype)_ |  true  | ConsistentHashType defines the type of input to hash on. Valid Type values are "SourceIP" or "Header". |
 | `header` | _[Header](#header)_ |  false  | Header configures the header hash policy when the consistent hash type is set to Header. |
+| `tableSize` | _integer_ |  false  | The table size for consistent hashing, must be prime number limited to 5000011. |
 
 
 #### ConsistentHashType
@@ -2341,9 +2342,9 @@ _Appears in:_
 
 | Field | Type | Required | Description |
 | ---   | ---  | ---      | ---         |
-| `host` | _string_ |  false  | Host define the extension service hostname.<br />Deprecated: Use BackendRef instead. |
-| `port` | _integer_ |  false  | Port defines the port the extension service is exposed on.<br />Deprecated: Use BackendRef instead. |
-| `backendRefs` | _[BackendRef](#backendref) array_ |  false  | BackendRefs references a Kubernetes object that represents the<br />backend server to which the accesslog will be sent.<br />Only service Kind is supported for now. |
+| `host` | _string_ |  false  | Host define the extension service hostname.<br />Deprecated: Use BackendRefs instead. |
+| `port` | _integer_ |  false  | Port defines the port the extension service is exposed on.<br />Deprecated: Use BackendRefs instead. |
+| `backendRefs` | _[BackendRef](#backendref) array_ |  false  | BackendRefs references a Kubernetes object that represents the<br />backend server to which the access log will be sent.<br />Only service Kind is supported for now. |
 | `resources` | _object (keys:string, values:string)_ |  false  | Resources is a set of labels that describe the source of a log entry, including envoy node info.<br />It's recommended to follow [semantic conventions](https://opentelemetry.io/docs/reference/specification/resource/semantic_conventions/). |
 
 
@@ -2676,8 +2677,8 @@ _Appears in:_
 
 | Field | Type | Required | Description |
 | ---   | ---  | ---      | ---         |
-| `host` | _string_ |  false  | Host define the service hostname.<br />Deprecated: Use BackendRef instead. |
-| `port` | _integer_ |  false  | Port defines the port the service is exposed on.<br />Deprecated: Use BackendRef instead. |
+| `host` | _string_ |  false  | Host define the service hostname.<br />Deprecated: Use BackendRefs instead. |
+| `port` | _integer_ |  false  | Port defines the port the service is exposed on.<br />Deprecated: Use BackendRefs instead. |
 | `backendRefs` | _[BackendRef](#backendref) array_ |  false  | BackendRefs references a Kubernetes object that represents the<br />backend server to which the metric will be sent.<br />Only service Kind is supported for now. |
 
 
@@ -3425,9 +3426,9 @@ _Appears in:_
 | Field | Type | Required | Description |
 | ---   | ---  | ---      | ---         |
 | `type` | _[TracingProviderType](#tracingprovidertype)_ |  true  | Type defines the tracing provider type.<br />EG currently only supports OpenTelemetry. |
-| `host` | _string_ |  false  | Host define the provider service hostname.<br />Deprecated: Use BackendRef instead. |
-| `port` | _integer_ |  false  | Port defines the port the provider service is exposed on.<br />Deprecated: Use BackendRef instead. |
-| `backendRefs` | _[BackendRef](#backendref) array_ |  false  | BackendRefs references a Kubernetes object that represents the<br />backend server to which the accesslog will be sent.<br />Only service Kind is supported for now. |
+| `host` | _string_ |  false  | Host define the provider service hostname.<br />Deprecated: Use BackendRefs instead. |
+| `port` | _integer_ |  false  | Port defines the port the provider service is exposed on.<br />Deprecated: Use BackendRefs instead. |
+| `backendRefs` | _[BackendRef](#backendref) array_ |  false  | BackendRefs references a Kubernetes object that represents the<br />backend server to which the trace will be sent.<br />Only service Kind is supported for now. |
 
 
 #### TracingProviderType