Repository: envoyproxy/gateway
Pull request #4831 (2024-12-02 05:00:47)

build(deps): bump github.com/golangci/golangci-lint from 1.62.0 to 1.62.2 in /tools/src/golangci-lint
Bumps [github.com/golangci/golangci-lint](https://github.com/golangci/golangci-lint) from 1.62.0 to 1.62.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/golangci/golangci-lint/releases">github.com/golangci/golangci-lint's releases</a>.</em></p>
<blockquote>
<h2>v1.62.2</h2>
<p><code>golangci-lint</code> is a free and open-source project built by volunteers.</p>
<p>If you value it, consider supporting us, the <a href="https://opencollective.com/golangci-lint">maintainers</a> and <a href="https://golangci-lint.run/product/thanks/">linter authors</a>.</p>
<p>We appreciate it! :heart:</p>
<p>For key updates, see the <a href="https://golangci-lint.run/product/changelog/%5B#1622%5D(https://redirect.github.com/golangci/golangci-lint/issues/1622)">changelog</a>.</p>
<h2>Changelog</h2>
<ul>
<li>build(deps): bump github.com/uudashr/iface from 1.2.0 to 1.2.1 (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5154">#5154</a>)</li>
<li>build(deps): bump github.com/stretchr/testify from 1.9.0 to 1.10.0 (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5152">#5152</a>)</li>
<li>build(deps): bump github.com/Crocmagnon/fatcontext from 0.5.2 to 0.5.3 (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5153">#5153</a>)</li>
<li>build(deps): bump github.com/polyfloyd/go-errorlint from 1.6.0 to 1.7.0 (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5134">#5134</a>)</li>
<li>build(deps): bump github.com/nunnatsa/ginkgolinter from 0.18.0 to 0.18.3 (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5133">#5133</a>)</li>
<li>build(deps): bump github.com/mgechev/revive from 1.5.0 to 1.5.1 (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5135">#5135</a>)</li>
<li>build(deps): bump github.com/Antonboom/testifylint from 1.5.0 to 1.5.2 (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5132">#5132</a>)</li>
<li>fix: ignore cache error when file not found (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5129">#5129</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/golangci/golangci-lint/blob/master/CHANGELOG.md">github.com/golangci/golangci-lint's changelog</a>.</em></p>
<blockquote>
<h3>v1.62.2</h3>
<ol>
<li>Updated linters
<ul>
<li><code>fatcontext</code>: from 0.5.2 to 0.5.3</li>
<li><code>ginkgolinter</code>: from 0.18.0 to 0.18.3</li>
<li><code>go-errorlint</code>: from 1.6.0 to 1.7.0</li>
<li><code>iface</code>: from 1.2.0 to 1.2.1</li>
<li><code>revive</code>: from 1.5.0 to 1.5.1</li>
<li><code>testifylint</code>: from 1.5.0 to 1.5.2</li>
</ul>
</li>
<li>Misc.
<ul>
<li>fix: ignore cache error when file not found</li>
</ul>
</li>
</ol>
<h3>v1.62.1</h3>
<p>Cancelled due to CI failure.</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golangci/golangci-lint/commit/89476e7a1eaa0a8a06c17343af960a5fd9e7edb7"><code>89476e7</code></a> dev: fix release workflow (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5156">#5156</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint/commit/8c45cf51eec83c71543e15bb997e52a2631a70ba"><code>8c45cf5</code></a> build(deps): bump github.com/uudashr/iface from 1.2.0 to 1.2.1 (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5154">#5154</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint/commit/bc3d877240f44b90ab1a478f1f76c1c93d0cfb2d"><code>bc3d877</code></a> dev: publish snap (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5130">#5130</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint/commit/59f6a2e83083c29c1c257161c1c5c3a0a45b52f1"><code>59f6a2e</code></a> build(deps): bump github.com/stretchr/testify from 1.9.0 to 1.10.0 (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5152">#5152</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint/commit/d1cef3677d89a15f4a0ddbe3def78dd6e3368791"><code>d1cef36</code></a> build(deps): bump github.com/Crocmagnon/fatcontext from 0.5.2 to 0.5.3 (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5153">#5153</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint/commit/432d3b1d6b391f1808c78b1d984b1d20984ed581"><code>432d3b1</code></a> dev: add missing AUR_KEY secret (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5151">#5151</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint/commit/af9b92ae697c5a2c75b518b287a45c77b1bd5c19"><code>af9b92a</code></a> dev: simplify sort results processors (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5150">#5150</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint/commit/e0e37c43762068149116bcd69b305c1ca05647ae"><code>e0e37c4</code></a> docs: Simplify team and contributors section (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5148">#5148</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint/commit/4ab3dca7db7a96ba8074d091feea10c7277e775d"><code>4ab3dca</code></a> dev: publish AUR -bin automatically (<a href="https://redirect.github.com/golangci/golangci-lint/issues/5146">#5146</a>)</li>
<li><a href="https://github.com/golangci/golangci-lint/commit/a41fe44a61e601a9efcb03fbf7c9a893e0d9324e"><code>a41fe44</code></a> build(deps): bump cross-spawn from 6.0.5 to 6.0.6 in /.github/contributors (#...</li>
<li>Additional commits viewable in <a href="https://github.com/golangci/golangci-lint/compare/v1.62.0...v1.62.2">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/golangci/golangci-lint&package-manager=go_modules&previous-version=1.62.0&new-version=1.62.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/envoyproxy/gateway/pull/4831?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 65.59%. Comparing base [(`c4d2fd1`)](https://app.codecov.io/gh/envoyproxy/gateway/commit/c4d2fd12de70786ccf116886de7bed90db83b99d?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) to head [(`35059e1`)](https://app.codecov.io/gh/envoyproxy/gateway/commit/35059e1f83d802092f79fab3096ffcffeeaba9d5?dropdown=coverage&el=desc&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    #4831   +/-   ##
=======================================
  Coverage   65.59%   65.59%           
=======================================
  Files         211      211           
  Lines       31999    31999           
=======================================
  Hits        20991    20991           
  Misses       9764     9764           
  Partials     1244     1244           
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/envoyproxy/gateway/pull/4831?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).

zhaohuabing: @dependabot rebase

Patch:
diff --git a/examples/grpc-ext-proc/main.go b/examples/grpc-ext-proc/main.go
index 785480f1d..ecdac6bd6 100644
--- a/examples/grpc-ext-proc/main.go
+++ b/examples/grpc-ext-proc/main.go
@@ -210,6 +210,16 @@ func (s *extProcServer) Process(srv envoy_service_proc_v3.ExternalProcessor_Proc
 		resp := &envoy_service_proc_v3.ProcessingResponse{}
 		switch v := req.Request.(type) {
 		case *envoy_service_proc_v3.ProcessingRequest_RequestHeaders:
+			xdsRouteName := ""
+
+			if req.Attributes != nil {
+				if epa, ok := req.Attributes["envoy.filters.http.ext_proc"]; ok {
+					if rqa, ok := epa.Fields["xds.route_name"]; ok {
+						xdsRouteName = rqa.GetStringValue()
+					}
+				}
+			}
+
 			xrch := ""
 			if v.RequestHeaders != nil {
 				hdrs := v.RequestHeaders.Headers.GetHeaders()
@@ -230,6 +240,12 @@ func (s *extProcServer) Process(srv envoy_service_proc_v3.ExternalProcessor_Proc
 									RawValue: []byte("true"),
 								},
 							},
+							{
+								Header: &envoy_api_v3_core.HeaderValue{
+									Key:      "x-request-xds-route-name",
+									RawValue: []byte(xdsRouteName),
+								},
+							},
 						},
 					},
 				},
@@ -257,8 +273,19 @@ func (s *extProcServer) Process(srv envoy_service_proc_v3.ExternalProcessor_Proc
 					RequestHeaders: rhq,
 				},
 			}
+
 			break
 		case *envoy_service_proc_v3.ProcessingRequest_ResponseHeaders:
+
+			respXDSRouteName := ""
+
+			if req.Attributes != nil {
+				if epa, ok := req.Attributes["envoy.filters.http.ext_proc"]; ok {
+					if rsa, ok := epa.Fields["xds.route_name"]; ok {
+						respXDSRouteName = rsa.GetStringValue()
+					}
+				}
+			}
 			rhq := &envoy_service_proc_v3.HeadersResponse{
 				Response: &envoy_service_proc_v3.CommonResponse{
 					HeaderMutation: &envoy_service_proc_v3.HeaderMutation{
@@ -269,6 +296,12 @@ func (s *extProcServer) Process(srv envoy_service_proc_v3.ExternalProcessor_Proc
 									RawValue: []byte("true"),
 								},
 							},
+							{
+								Header: &envoy_api_v3_core.HeaderValue{
+									Key:      "x-response-xds-route-name",
+									RawValue: []byte(respXDSRouteName),
+								},
+							},
 						},
 					},
 				},
diff --git a/internal/gatewayapi/envoyextensionpolicy.go b/internal/gatewayapi/envoyextensionpolicy.go
index bb5da8be1..72133f83a 100644
--- a/internal/gatewayapi/envoyextensionpolicy.go
+++ b/internal/gatewayapi/envoyextensionpolicy.go
@@ -481,6 +481,10 @@ func (t *Translator) buildExtProc(
 			if extProc.ProcessingMode.Request.Body != nil {
 				extProcIR.RequestBodyProcessingMode = ptr.To(ir.ExtProcBodyProcessingMode(*extProc.ProcessingMode.Request.Body))
 			}
+
+			if extProc.ProcessingMode.Request.Attributes != nil {
+				extProcIR.RequestAttributes = append(extProcIR.RequestAttributes, extProc.ProcessingMode.Request.Attributes...)
+			}
 		}
 
 		if extProc.ProcessingMode.Response != nil {
@@ -488,6 +492,10 @@ func (t *Translator) buildExtProc(
 			if extProc.ProcessingMode.Response.Body != nil {
 				extProcIR.ResponseBodyProcessingMode = ptr.To(ir.ExtProcBodyProcessingMode(*extProc.ProcessingMode.Response.Body))
 			}
+
+			if extProc.ProcessingMode.Response.Attributes != nil {
+				extProcIR.ResponseAttributes = append(extProcIR.ResponseAttributes, extProc.ProcessingMode.Response.Attributes...)
+			}
 		}
 	}
 
diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go
index 6ed1d7699..2626e1b4b 100644
--- a/internal/gatewayapi/helpers.go
+++ b/internal/gatewayapi/helpers.go
@@ -610,20 +610,56 @@ func setIfNil[T any](target **T, value *T) {
 	}
 }
 
-func getIPFamily(envoyProxy *egv1a1.EnvoyProxy) *ir.IPFamily {
+// getServiceIPFamily returns the IP family configuration from a Kubernetes Service
+// following the dual-stack service configuration scenarios:
+// https://kubernetes.io/docs/concepts/services-networking/dual-stack/#dual-stack-service-configuration-scenarios
+//
+// The IP family is determined in the following order:
+// 1. Service.Spec.IPFamilyPolicy == RequireDualStack -> DualStack
+// 2. Service.Spec.IPFamilies length > 1 -> DualStack
+// 3. Service.Spec.IPFamilies[0] -> IPv4 or IPv6
+// 4. nil if not specified
+func getServiceIPFamily(service *corev1.Service) *egv1a1.IPFamily {
+	if service == nil {
+		return nil
+	}
+
+	// If ipFamilyPolicy is RequireDualStack, return DualStack
+	if service.Spec.IPFamilyPolicy != nil &&
+		*service.Spec.IPFamilyPolicy == corev1.IPFamilyPolicyRequireDualStack {
+		return ptr.To(egv1a1.DualStack)
+	}
+
+	// Check ipFamilies array
+	if len(service.Spec.IPFamilies) > 0 {
+		if len(service.Spec.IPFamilies) > 1 {
+			return ptr.To(egv1a1.DualStack)
+		}
+		switch service.Spec.IPFamilies[0] {
+		case corev1.IPv4Protocol:
+			return ptr.To(egv1a1.IPv4)
+		case corev1.IPv6Protocol:
+			return ptr.To(egv1a1.IPv6)
+		}
+	}
+
+	return nil
+}
+
+// getEnvoyIPFamily returns the IPFamily configuration from EnvoyProxy
+func getEnvoyIPFamily(envoyProxy *egv1a1.EnvoyProxy) *egv1a1.IPFamily {
 	if envoyProxy == nil || envoyProxy.Spec.IPFamily == nil {
 		return nil
 	}
-	var result ir.IPFamily
+
 	switch *envoyProxy.Spec.IPFamily {
 	case egv1a1.IPv4:
-		result = ir.IPv4
+		return ptr.To(egv1a1.IPv4)
 	case egv1a1.IPv6:
-		result = ir.IPv6
+		return ptr.To(egv1a1.IPv6)
 	case egv1a1.DualStack:
-		result = ir.DualStack
+		return ptr.To(egv1a1.DualStack)
 	default:
 		return nil
 	}
-	return &result
 }
diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go
index bf369e7b8..757396096 100644
--- a/internal/gatewayapi/listener.go
+++ b/internal/gatewayapi/listener.go
@@ -102,8 +102,8 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource
 			}
 
 			address := net.IPv4ListenerAddress
-			ipFamily := getIPFamily(gateway.envoyProxy)
-			if ipFamily != nil && (*ipFamily == ir.IPv6 || *ipFamily == ir.DualStack) {
+			ipFamily := getEnvoyIPFamily(gateway.envoyProxy)
+			if ipFamily != nil && (*ipFamily == egv1a1.IPv6 || *ipFamily == egv1a1.DualStack) {
 				address = net.IPv6ListenerAddress
 			}
 
@@ -118,7 +118,7 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource
 						Address:  address,
 						Port:     uint32(containerPort),
 						Metadata: buildListenerMetadata(listener, gateway),
-						IPFamily: getIPFamily(gateway.envoyProxy),
+						IPFamily: ipFamily,
 					},
 					TLS: irTLSConfigs(listener.tlsSecrets...),
 					Path: ir.PathSettings{
@@ -126,9 +126,6 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource
 						EscapedSlashesAction: ir.UnescapeAndRedirect,
 					},
 				}
-				if ipFamily := getIPFamily(gateway.envoyProxy); ipFamily != nil {
-					irListener.CoreListenerDetails.IPFamily = ipFamily
-				}
 				if listener.Hostname != nil {
 					irListener.Hostnames = append(irListener.Hostnames, string(*listener.Hostname))
 				} else {
@@ -144,7 +141,7 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource
 						Name:     irListenerName(listener),
 						Address:  address,
 						Port:     uint32(containerPort),
-						IPFamily: getIPFamily(gateway.envoyProxy),
+						IPFamily: ipFamily,
 					},
 
 					// Gateway is processed firstly, then ClientTrafficPolicy, then xRoute.
diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go
index 26627a072..ddada5f17 100644
--- a/internal/gatewayapi/route.go
+++ b/internal/gatewayapi/route.go
@@ -1232,6 +1232,7 @@ func (t *Translator) processDestination(backendRefContext BackendRefContext,
 		addrType  *ir.DestinationAddressType
 	)
 	protocol := inspectAppProtocolByRouteKind(routeType)
+
 	switch KindDerefOr(backendRef.Kind, resource.KindService) {
 	case resource.KindServiceImport:
 		serviceImport := resources.GetServiceImport(backendNamespace, string(backendRef.Name))
@@ -1262,9 +1263,9 @@ func (t *Translator) processDestination(backendRefContext BackendRefContext,
 			Endpoints:   endpoints,
 			AddressType: addrType,
 		}
+
 	case resource.KindService:
 		ds = t.processServiceDestinationSetting(backendRef.BackendObjectReference, backendNamespace, protocol, resources, envoyProxy)
-
 		ds.TLS = t.applyBackendTLSSetting(
 			backendRef.BackendObjectReference,
 			backendNamespace,
@@ -1280,6 +1281,7 @@ func (t *Translator) processDestination(backendRefContext BackendRefContext,
 			envoyProxy,
 		)
 		ds.Filters = t.processDestinationFilters(routeType, backendRefContext, parentRef, route, resources)
+		ds.IPFamily = getServiceIPFamily(resources.GetService(backendNamespace, string(backendRef.Name)))
 	case egv1a1.KindBackend:
 		ds = t.processBackendDestinationSetting(backendRef.BackendObjectReference, backendNamespace, resources)
 
diff --git a/internal/ir/xds.go b/internal/ir/xds.go
index c9fb1dd56..486b7514c 100644
--- a/internal/ir/xds.go
+++ b/internal/ir/xds.go
@@ -250,19 +250,12 @@ type CoreListenerDetails struct {
 	ExtensionRefs []*UnstructuredRef `json:"extensionRefs,omitempty" yaml:"extensionRefs,omitempty"`
 	// Metadata is used to enrich envoy resource metadata with user and provider-specific information
 	Metadata *ResourceMetadata `json:"metadata,omitempty" yaml:"metadata,omitempty"`
-	// IPFamily specifies the IP address family for the gateway.
-	// It can be IPv4, IPv6, or DualStack.
+	// IPFamily specifies the IP address family used by the Gateway for its listening ports.
 	IPFamily *IPFamily `json:"ipFamily,omitempty" yaml:"ipFamily,omitempty"`
 }
 
 // IPFamily specifies the IP address family used by the Gateway for its listening ports.
-type IPFamily string
-
-const (
-	IPv4      IPFamily = "IPv4"
-	IPv6      IPFamily = "IPv6"
-	DualStack IPFamily = "DualStack"
-)
+type IPFamily = egv1a1.IPFamily
 
 func (l CoreListenerDetails) GetName() string {
 	return l.Name
@@ -1308,9 +1301,11 @@ type DestinationSetting struct {
 	Endpoints []*DestinationEndpoint `json:"endpoints,omitempty" yaml:"endpoints,omitempty"`
 	// AddressTypeState specifies the state of DestinationEndpoint address type.
 	AddressType *DestinationAddressType `json:"addressType,omitempty" yaml:"addressType,omitempty"`
-
-	TLS     *TLSUpstreamConfig  `json:"tls,omitempty" yaml:"tls,omitempty"`
-	Filters *DestinationFilters `json:"filters,omitempty" yaml:"filters,omitempty"`
+	// IPFamily specifies the IP family (IPv4 or IPv6) to use for this destination's endpoints.
+	// This is derived from the backend service and endpoint slice information.
+	IPFamily *IPFamily           `json:"ipFamily,omitempty" yaml:"ipFamily,omitempty"`
+	TLS      *TLSUpstreamConfig  `json:"tls,omitempty" yaml:"tls,omitempty"`
+	Filters  *DestinationFilters `json:"filters,omitempty" yaml:"filters,omitempty"`
 }
 
 // Validate the fields within the RouteDestination structure
@@ -1686,6 +1681,7 @@ func (t TCPListener) Validate() error {
 
 func (t TCPRoute) Validate() error {
 	var errs error
+
 	if t.Name == "" {
 		errs = errors.Join(errs, ErrRouteNameEmpty)
 	}
@@ -2602,6 +2598,14 @@ type ExtProc struct {
 
 	// ResponseBodyProcessingMode Defines response body processing
 	ResponseBodyProcessingMode *ExtProcBodyProcessingMode `json:"responseBodyProcessingMode,omitempty" yaml:"responseBodyProcessingMode,omitempty"`
+
+	// RequestAttributes defines which envoy attributes are provided as context to external processor
+	// when processing requests
+	RequestAttributes []string `json:"requestAttributes,omitempty" yaml:"requestAttributes,omitempty"`
+
+	// ResponseAttributes defines which envoy attributes are provided as context to external processor
+	// when processing responses
+	ResponseAttributes []string `json:"responseAttributes,omitempty" yaml:"responseAttributes,omitempty"`
 }
 
 // Wasm holds the information associated with the Wasm extensions.
diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go
index de0be09ff..6db142624 100644
--- a/internal/ir/zz_generated.deepcopy.go
+++ b/internal/ir/zz_generated.deepcopy.go
@@ -592,7 +592,7 @@ func (in *CoreListenerDetails) DeepCopyInto(out *CoreListenerDetails) {
 	}
 	if in.IPFamily != nil {
 		in, out := &in.IPFamily, &out.IPFamily
-		*out = new(IPFamily)
+		*out = new(v1alpha1.IPFamily)
 		**out = **in
 	}
 }
@@ -772,6 +772,11 @@ func (in *DestinationSetting) DeepCopyInto(out *DestinationSetting) {
 		*out = new(DestinationAddressType)
 		**out = **in
 	}
+	if in.IPFamily != nil {
+		in, out := &in.IPFamily, &out.IPFamily
+		*out = new(v1alpha1.IPFamily)
+		**out = **in
+	}
 	if in.TLS != nil {
 		in, out := &in.TLS, &out.TLS
 		*out = new(TLSUpstreamConfig)
@@ -944,6 +949,16 @@ func (in *ExtProc) DeepCopyInto(out *ExtProc) {
 		*out = new(ExtProcBodyProcessingMode)
 		**out = **in
 	}
+	if in.RequestAttributes != nil {
+		in, out := &in.RequestAttributes, &out.RequestAttributes
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+	if in.ResponseAttributes != nil {
+		in, out := &in.ResponseAttributes, &out.ResponseAttributes
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtProc.
diff --git a/internal/xds/translator/cluster.go b/internal/xds/translator/cluster.go
index c5064c29e..10792bae2 100644
--- a/internal/xds/translator/cluster.go
+++ b/internal/xds/translator/cluster.go
@@ -698,6 +698,7 @@ type ExtraArgs struct {
 	metrics       *ir.Metrics
 	http1Settings *ir.HTTP1Settings
 	http2Settings *ir.HTTP2Settings
+	ipFamily      *egv1a1.IPFamily
 }
 
 type clusterArgs interface {
@@ -716,6 +717,7 @@ func (route *UDPRouteTranslator) asClusterArgs(extra *ExtraArgs) *xdsClusterArgs
 		endpointType: buildEndpointType(route.Destination.Settings),
 		metrics:      extra.metrics,
 		dns:          route.DNS,
+		ipFamily:     extra.ipFamily,
 	}
 }
 
@@ -737,6 +739,7 @@ func (route *TCPRouteTranslator) asClusterArgs(extra *ExtraArgs) *xdsClusterArgs
 		metrics:           extra.metrics,
 		backendConnection: route.BackendConnection,
 		dns:               route.DNS,
+		ipFamily:          extra.ipFamily,
 	}
 }
 
@@ -754,6 +757,7 @@ func (httpRoute *HTTPRouteTranslator) asClusterArgs(extra *ExtraArgs) *xdsCluste
 		http1Settings:     extra.http1Settings,
 		http2Settings:     extra.http2Settings,
 		useClientProtocol: ptr.Deref(httpRoute.UseClientProtocol, false),
+		ipFamily:          extra.ipFamily,
 	}
 
 	// Populate traffic features.
diff --git a/internal/xds/translator/extproc.go b/internal/xds/translator/extproc.go
index 57cc9634d..2270b2fb7 100644
--- a/internal/xds/translator/extproc.go
+++ b/internal/xds/translator/extproc.go
@@ -137,6 +137,18 @@ func extProcConfig(extProc ir.ExtProc) *extprocv3.ExternalProcessor {
 		config.ProcessingMode.ResponseHeaderMode = extprocv3.ProcessingMode_SEND
 	}
 
+	if extProc.RequestAttributes != nil {
+		var attrs []string
+		attrs = append(attrs, extProc.RequestAttributes...)
+		config.RequestAttributes = attrs
+	}
+
+	if extProc.ResponseAttributes != nil {
+		var attrs []string
+		attrs = append(attrs, extProc.ResponseAttributes...)
+		config.ResponseAttributes = attrs
+	}
+
 	return config
 }
 
diff --git a/internal/xds/translator/listener.go b/internal/xds/translator/listener.go
index 1568ed3e5..36cf9a895 100644
--- a/internal/xds/translator/listener.go
+++ b/internal/xds/translator/listener.go
@@ -180,7 +180,7 @@ func buildXdsTCPListener(
 		},
 	}
 
-	if ipFamily != nil && *ipFamily == ir.DualStack {
+	if ipFamily != nil && *ipFamily == egv1a1.DualStack {
 		socketAddress := listener.Address.GetSocketAddress()
 		socketAddress.Ipv4Compat = true
 	}
@@ -224,7 +224,7 @@ func buildXdsQuicListener(name, address string, port uint32, ipFamily *ir.IPFami
 		DrainType: listenerv3.Listener_MODIFY_ONLY,
 	}
 
-	if ipFamily != nil && *ipFamily == ir.DualStack {
+	if ipFamily != nil && *ipFamily == egv1a1.DualStack {
 		socketAddress := xdsListener.Address.GetSocketAddress()
 		socketAddress.Ipv4Compat = true
 	}
@@ -869,7 +869,7 @@ func buildXdsUDPListener(clusterName string, udpListener *ir.UDPListener, access
 		}},
 	}
 
-	if udpListener.IPFamily != nil && *udpListener.IPFamily == ir.DualStack {
+	if udpListener.IPFamily != nil && *udpListener.IPFamily == egv1a1.DualStack {
 		socketAddress := xdsListener.Address.GetSocketAddress()
 		socketAddress.Ipv4Compat = true
 	}
diff --git a/internal/xds/translator/translator.go b/internal/xds/translator/translator.go
index 1e0ae77e9..79f16d5d1 100644
--- a/internal/xds/translator/translator.go
+++ b/internal/xds/translator/translator.go
@@ -464,6 +464,7 @@ func (t *Translator) addRouteToRouteConfig(
 			ea := &ExtraArgs{
 				metrics:       metrics,
 				http1Settings: httpListener.HTTP1,
+				ipFamily:      determineIPFamily(httpRoute.Destination.Settings),
 			}
 
 			if httpRoute.Traffic != nil && httpRoute.Traffic.HTTP2 != nil {
diff --git a/internal/xds/translator/utils.go b/internal/xds/translator/utils.go
index 882d9b1e9..30c2f771e 100644
--- a/internal/xds/translator/utils.go
+++ b/internal/xds/translator/utils.go
@@ -196,3 +196,43 @@ func addClusterFromURL(url string, tCtx *types.ResourceVersionTable) error {
 
 	return addXdsCluster(tCtx, clusterArgs)
 }
+
+// determineIPFamily determines the IP family based on multiple destination settings
+func determineIPFamily(settings []*ir.DestinationSetting) *egv1a1.IPFamily {
+	// If there's only one setting, return its IPFamily directly
+	if len(settings) == 1 {
+		return settings[0].IPFamily
+	}
+
+	hasIPv4 := false
+	hasIPv6 := false
+	hasDualStack := false
+
+	for _, setting := range settings {
+		if setting.IPFamily == nil {
+			continue
+		}
+
+		switch *setting.IPFamily {
+		case egv1a1.IPv4:
+			hasIPv4 = true
+		case egv1a1.IPv6:
+			hasIPv6 = true
+		case egv1a1.DualStack:
+			hasDualStack = true
+		}
+	}
+
+	switch {
+	case hasDualStack:
+		return ptr.To(egv1a1.DualStack)
+	case hasIPv4 && hasIPv6:
+		return ptr.To(egv1a1.DualStack)
+	case hasIPv4:
+		return ptr.To(egv1a1.IPv4)
+	case hasIPv6:
+		return ptr.To(egv1a1.IPv6)
+	default:
+		return nil
+	}
+}
diff --git a/tools/docker/envoy-gateway/Dockerfile b/tools/docker/envoy-gateway/Dockerfile
index 880ce0abf..78ba66794 100644
--- a/tools/docker/envoy-gateway/Dockerfile
+++ b/tools/docker/envoy-gateway/Dockerfile
@@ -4,7 +4,7 @@ RUN mkdir -p /var/lib/eg
 
 # Use distroless as minimal base image to package the manager binary
 # Refer to https://github.com/GoogleContainerTools/distroless for more details
-FROM gcr.io/distroless/static:nonroot@sha256:d71f4b239be2d412017b798a0a401c44c3049a3ca454838473a4c32ed076bfea
+FROM gcr.io/distroless/static:nonroot@sha256:6cd937e9155bdfd805d1b94e037f9d6a899603306030936a3b11680af0c2ed58
 ARG TARGETPLATFORM
 COPY $TARGETPLATFORM/envoy-gateway /usr/local/bin/
 COPY --from=source --chown=65532:65532 /var/lib /var/lib
diff --git a/tools/src/golangci-lint/go.mod b/tools/src/golangci-lint/go.mod
index d7d2cdce1..f84bb3bc2 100644
--- a/tools/src/golangci-lint/go.mod
+++ b/tools/src/golangci-lint/go.mod
@@ -2,7 +2,7 @@ module local
 
 go 1.23.3
 
-require github.com/golangci/golangci-lint v1.62.0
+require github.com/golangci/golangci-lint v1.62.2
 
 require (
 	4d63.com/gocheckcompilerdirectives v1.2.1 // indirect
@@ -11,9 +11,9 @@ require (
 	github.com/Abirdcfly/dupword v0.1.3 // indirect
 	github.com/Antonboom/errname v1.0.0 // indirect
 	github.com/Antonboom/nilnil v1.0.0 // indirect
-	github.com/Antonboom/testifylint v1.5.0 // indirect
+	github.com/Antonboom/testifylint v1.5.2 // indirect
 	github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
-	github.com/Crocmagnon/fatcontext v0.5.2 // indirect
+	github.com/Crocmagnon/fatcontext v0.5.3 // indirect
 	github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect
 	github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 // indirect
 	github.com/Masterminds/semver/v3 v3.3.0 // indirect
@@ -103,19 +103,19 @@ require (
 	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/mattn/go-runewidth v0.0.16 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
-	github.com/mgechev/revive v1.5.0 // indirect
+	github.com/mgechev/revive v1.5.1 // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/moricho/tparallel v0.3.2 // indirect
 	github.com/nakabonne/nestif v0.3.1 // indirect
 	github.com/nishanths/exhaustive v0.12.0 // indirect
 	github.com/nishanths/predeclared v0.2.2 // indirect
-	github.com/nunnatsa/ginkgolinter v0.18.0 // indirect
+	github.com/nunnatsa/ginkgolinter v0.18.3 // indirect
 	github.com/olekukonko/tablewriter v0.0.5 // indirect
 	github.com/pelletier/go-toml v1.9.5 // indirect
 	github.com/pelletier/go-toml/v2 v2.2.3 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	github.com/polyfloyd/go-errorlint v1.6.0 // indirect
+	github.com/polyfloyd/go-errorlint v1.7.0 // indirect
 	github.com/prometheus/client_golang v1.12.1 // indirect
 	github.com/prometheus/client_model v0.2.0 // indirect
 	github.com/prometheus/common v0.32.1 // indirect
@@ -150,7 +150,7 @@ require (
 	github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
 	github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect
 	github.com/stretchr/objx v0.5.2 // indirect
-	github.com/stretchr/testify v1.9.0 // indirect
+	github.com/stretchr/testify v1.10.0 // indirect
 	github.com/subosito/gotenv v1.4.1 // indirect
 	github.com/tdakkota/asciicheck v0.2.0 // indirect
 	github.com/tetafro/godot v1.4.18 // indirect
@@ -161,7 +161,7 @@ require (
 	github.com/ultraware/funlen v0.1.0 // indirect
 	github.com/ultraware/whitespace v0.1.1 // indirect
 	github.com/uudashr/gocognit v1.1.3 // indirect
-	github.com/uudashr/iface v1.2.0 // indirect
+	github.com/uudashr/iface v1.2.1 // indirect
 	github.com/xen0n/gosmopolitan v1.2.2 // indirect
 	github.com/yagipy/maintidx v1.0.0 // indirect
 	github.com/yeya24/promlinter v0.3.0 // indirect
@@ -174,7 +174,7 @@ require (
 	go.uber.org/multierr v1.6.0 // indirect
 	go.uber.org/zap v1.24.0 // indirect
 	golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
-	golang.org/x/exp/typeparams v0.0.0-20240909161429-701f63a606c0 // indirect
+	golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f // indirect
 	golang.org/x/mod v0.22.0 // indirect
 	golang.org/x/sync v0.9.0 // indirect
 	golang.org/x/sys v0.27.0 // indirect
diff --git a/tools/src/golangci-lint/go.sum b/tools/src/golangci-lint/go.sum
index c8205a75d..20fd8682d 100644
--- a/tools/src/golangci-lint/go.sum
+++ b/tools/src/golangci-lint/go.sum
@@ -43,14 +43,14 @@ github.com/Antonboom/errname v1.0.0 h1:oJOOWR07vS1kRusl6YRSlat7HFnb3mSfMl6sDMRoT
 github.com/Antonboom/errname v1.0.0/go.mod h1:gMOBFzK/vrTiXN9Oh+HFs+e6Ndl0eTFbtsRTSRdXyGI=
 github.com/Antonboom/nilnil v1.0.0 h1:n+v+B12dsE5tbAqRODXmEKfZv9j2KcTBrp+LkoM4HZk=
 github.com/Antonboom/nilnil v1.0.0/go.mod h1:fDJ1FSFoLN6yoG65ANb1WihItf6qt9PJVTn/s2IrcII=
-github.com/Antonboom/testifylint v1.5.0 h1:dlUIsDMtCrZWUnvkaCz3quJCoIjaGi41GzjPBGkkJ8A=
-github.com/Antonboom/testifylint v1.5.0/go.mod h1:wqaJbu0Blb5Wag2wv7Z5xt+CIV+eVLxtGZrlK13z3AE=
+github.com/Antonboom/testifylint v1.5.2 h1:4s3Xhuv5AvdIgbd8wOOEeo0uZG7PbDKQyKY5lGoQazk=
+github.com/Antonboom/testifylint v1.5.2/go.mod h1:vxy8VJ0bc6NavlYqjZfmp6EfqXMtBgQ4+mhCojwC1P8=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
 github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/Crocmagnon/fatcontext v0.5.2 h1:vhSEg8Gqng8awhPju2w7MKHqMlg4/NI+gSDHtR3xgwA=
-github.com/Crocmagnon/fatcontext v0.5.2/go.mod h1:87XhRMaInHP44Q7Tlc7jkgKKB7kZAOPiDkFMdKCC+74=
+github.com/Crocmagnon/fatcontext v0.5.3 h1:zCh/wjc9oyeF+Gmp+V60wetm8ph2tlsxocgg/J0hOps=
+github.com/Crocmagnon/fatcontext v0.5.3/go.mod h1:XoCQYY1J+XTfyv74qLXvNw4xFunr3L1wkopIIKG7wGM=
 github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM=
 github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
 github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 h1:/fTUt5vmbkAcMBt4YQiuC23cV0kEsN1MVMNqeOW43cU=
@@ -230,8 +230,8 @@ github.com/golangci/go-printf-func-name v0.1.0 h1:dVokQP+NMTO7jwO4bwsRwLWeudOVUP
 github.com/golangci/go-printf-func-name v0.1.0/go.mod h1:wqhWFH5mUdJQhweRnldEywnR5021wTdZSNgwYceV14s=
 github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 h1:/1322Qns6BtQxUZDTAT4SdcoxknUki7IAoK4SAXr8ME=
 github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9/go.mod h1:Oesb/0uFAyWoaw1U1qS5zyjCg5NP9C9iwjnI4tIsXEE=
-github.com/golangci/golangci-lint v1.62.0 h1:/G0g+bi1BhmGJqLdNQkKBWjcim8HjOPc4tsKuHDOhcI=
-github.com/golangci/golangci-lint v1.62.0/go.mod h1:jtoOhQcKTz8B6dGNFyfQV3WZkQk+YvBDewDtNpiAJts=
+github.com/golangci/golangci-lint v1.62.2 h1:b8K5K9PN+rZN1+mKLtsZHz2XXS9aYKzQ9i25x3Qnxxw=
+github.com/golangci/golangci-lint v1.62.2/go.mod h1:ILWWyeFUrctpHVGMa1dg2xZPKoMUTc5OIMgW7HZr34g=
 github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
 github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
 github.com/golangci/modinfo v0.3.4 h1:oU5huX3fbxqQXdfspamej74DFX0kyGLkw1ppvXoJ8GA=
@@ -369,8 +369,8 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T
 github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
 github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/mgechev/revive v1.5.0 h1:oaSmjA7rP8+HyoRuCgC531VHwnLH1AlJdjj+1AnQceQ=
-github.com/mgechev/revive v1.5.0/go.mod h1:L6T3H8EoerRO86c7WuGpvohIUmiploGiyoYbtIWFmV8=
+github.com/mgechev/revive v1.5.1 h1:hE+QPeq0/wIzJwOphdVyUJ82njdd8Khp4fUIHGZHW3M=
+github.com/mgechev/revive v1.5.1/go.mod h1:lC9AhkJIBs5zwx8wkudyHrU+IJkrEKmpCmGMnIJPk4o=
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
@@ -390,8 +390,8 @@ github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhK
 github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs=
 github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk=
 github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c=
-github.com/nunnatsa/ginkgolinter v0.18.0 h1:ZXO1wKhPg3A6LpbN5dMuqwhfOjN5c3ous8YdKOuqk9k=
-github.com/nunnatsa/ginkgolinter v0.18.0/go.mod h1:vPrWafSULmjMGCMsfGA908if95VnHQNAahvSBOjTuWs=
+github.com/nunnatsa/ginkgolinter v0.18.3 h1:WgS7X3zzmni3vwHSBhvSgqrRgUecN6PQUcfB0j1noDw=
+github.com/nunnatsa/ginkgolinter v0.18.3/go.mod h1:BE1xyB/PNtXXG1azrvrqJW5eFH0hSRylNzFy8QHPwzs=
 github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
 github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
 github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
@@ -415,8 +415,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/polyfloyd/go-errorlint v1.6.0 h1:tftWV9DE7txiFzPpztTAwyoRLKNj9gpVm2cg8/OwcYY=
-github.com/polyfloyd/go-errorlint v1.6.0/go.mod h1:HR7u8wuP1kb1NeN1zqTd1ZMlqUKPPHF+Id4vIPvDqVw=
+github.com/polyfloyd/go-errorlint v1.7.0 h1:Zp6lzCK4hpBDj8y8a237YK4EPrMXQWvOe3nGoH4pFrU=
+github.com/polyfloyd/go-errorlint v1.7.0/go.mod h1:dGWKu85mGHnegQ2SWpEybFityCg3j7ZbwsVUxAOk9gY=
 github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
 github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -521,8 +521,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
 github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
 github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM=
@@ -547,8 +547,8 @@ github.com/ultraware/whitespace v0.1.1 h1:bTPOGejYFulW3PkcrqkeQwOd6NKOOXvmGD9bo/
 github.com/ultraware/whitespace v0.1.1/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8=
 github.com/uudashr/gocognit v1.1.3 h1:l+a111VcDbKfynh+airAy/DJQKaXh2m9vkoysMPSZyM=
 github.com/uudashr/gocognit v1.1.3/go.mod h1:aKH8/e8xbTRBwjbCkwZ8qt4l2EpKXl31KMHgSS+lZ2U=
-github.com/uudashr/iface v1.2.0 h1:ECJjh5q/1Zmnv/2yFpWV6H3oMg5+Mo+vL0aqw9Gjazo=
-github.com/uudashr/iface v1.2.0/go.mod h1:Ux/7d/rAF3owK4m53cTVXL4YoVHKNqnoOeQHn2xrlp0=
+github.com/uudashr/iface v1.2.1 h1:vHHyzAUmWZ64Olq6NZT3vg/z1Ws56kyPdBOd5kTXDF8=
+github.com/uudashr/iface v1.2.1/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg=
 github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU=
 github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg=
 github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM=
@@ -609,8 +609,8 @@ golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWB
 golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
 golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
 golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
-golang.org/x/exp/typeparams v0.0.0-20240909161429-701f63a606c0 h1:bVwtbF629Xlyxk6xLQq2TDYmqP0uiWaet5LwRebuY0k=
-golang.org/x/exp/typeparams v0.0.0-20240909161429-701f63a606c0/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
+golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f h1:WTyX8eCCyfdqiPYkRGm0MqElSfYFH3yR1+rl/mct9sA=
+golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=


Test patch:
diff --git a/.github/workflows/build_and_test.yaml b/.github/workflows/build_and_test.yaml
index cd49c5a82..1c5e82607 100644
--- a/.github/workflows/build_and_test.yaml
+++ b/.github/workflows/build_and_test.yaml
@@ -55,7 +55,7 @@ jobs:
     - name: Run Coverage Tests
       run: make go.test.coverage
     - name: Upload coverage to Codecov
-      uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238  # v4.6.0
+      uses: codecov/codecov-action@015f24e6818733317a2da2edd6290ab26238649a  # v5.0.7
       with:
         fail_ci_if_error: true
         files: ./coverage.xml
diff --git a/internal/gatewayapi/helpers_test.go b/internal/gatewayapi/helpers_test.go
index 5698867c3..6403279a5 100644
--- a/internal/gatewayapi/helpers_test.go
+++ b/internal/gatewayapi/helpers_test.go
@@ -15,6 +15,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/require"
+	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	"k8s.io/apimachinery/pkg/types"
@@ -551,3 +552,67 @@ func TestIsRefToGateway(t *testing.T) {
 		})
 	}
 }
+
+func TestGetServiceIPFamily(t *testing.T) {
+	testCases := []struct {
+		name     string
+		service  *corev1.Service
+		expected *egv1a1.IPFamily
+	}{
+		{
+			name:     "nil service",
+			service:  nil,
+			expected: nil,
+		},
+		{
+			name: "require dual stack",
+			service: &corev1.Service{
+				Spec: corev1.ServiceSpec{
+					IPFamilyPolicy: ptr.To(corev1.IPFamilyPolicyRequireDualStack),
+				},
+			},
+			expected: ptr.To(egv1a1.DualStack),
+		},
+		{
+			name: "multiple ip families",
+			service: &corev1.Service{
+				Spec: corev1.ServiceSpec{
+					IPFamilies: []corev1.IPFamily{corev1.IPv4Protocol, corev1.IPv6Protocol},
+				},
+			},
+			expected: ptr.To(egv1a1.DualStack),
+		},
+		{
+			name: "ipv4 only",
+			service: &corev1.Service{
+				Spec: corev1.ServiceSpec{
+					IPFamilies: []corev1.IPFamily{corev1.IPv4Protocol},
+				},
+			},
+			expected: ptr.To(egv1a1.IPv4),
+		},
+		{
+			name: "ipv6 only",
+			service: &corev1.Service{
+				Spec: corev1.ServiceSpec{
+					IPFamilies: []corev1.IPFamily{corev1.IPv6Protocol},
+				},
+			},
+			expected: ptr.To(egv1a1.IPv6),
+		},
+		{
+			name: "no ip family specified",
+			service: &corev1.Service{
+				Spec: corev1.ServiceSpec{},
+			},
+			expected: nil,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			result := getServiceIPFamily(tc.service)
+			require.Equal(t, tc.expected, result)
+		})
+	}
+}
diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.in.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.in.yaml
index ca3297a5f..95e8b9570 100644
--- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.in.yaml
+++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.in.yaml
@@ -203,8 +203,13 @@ envoyExtensionPolicies:
       processingMode:
         request:
           body: Buffered
+          attributes:
+          - request.path
         response:
           body: Streamed
+          attributes:
+          - xds.route_metadata
+          - connection.requested_server_name
       messageTimeout: 5s
       failOpen: true
 - apiVersion: gateway.envoyproxy.io/v1alpha1
diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.out.yaml
index a1d7beec9..3fd129b80 100644
--- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.out.yaml
+++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.out.yaml
@@ -113,8 +113,13 @@ envoyExtensionPolicies:
       messageTimeout: 5s
       processingMode:
         request:
+          attributes:
+          - request.path
           body: Buffered
         response:
+          attributes:
+          - xds.route_metadata
+          - connection.requested_server_name
           body: Streamed
     targetRef:
       group: gateway.networking.k8s.io
@@ -363,8 +368,13 @@ xdsIR:
             failOpen: true
             messageTimeout: 5s
             name: envoyextensionpolicy/default/policy-for-gateway/extproc/0
+            requestAttributes:
+            - request.path
             requestBodyProcessingMode: Buffered
             requestHeaderProcessing: true
+            responseAttributes:
+            - xds.route_metadata
+            - connection.requested_server_name
             responseBodyProcessingMode: Streamed
             responseHeaderProcessing: true
         hostname: www.bar.com
diff --git a/internal/xds/translator/testdata/in/xds-ir/ext-proc.yaml b/internal/xds/translator/testdata/in/xds-ir/ext-proc.yaml
index 3fa4cd8bc..da4939c22 100644
--- a/internal/xds/translator/testdata/in/xds-ir/ext-proc.yaml
+++ b/internal/xds/translator/testdata/in/xds-ir/ext-proc.yaml
@@ -23,8 +23,13 @@ http:
             - name: envoyextensionpolicy/default/policy-for-route-2/extproc/0
               failOpen: true
               messageTimeout: 5s
+              requestAttributes:
+                - xds.route_metadata
+                - connection.requested_server_name
               requestHeaderProcessing: true
               requestBodyProcessingMode: Buffered
+              responseAttributes:
+                - request.path
               responseBodyProcessingMode: Streamed
               authority: grpc-backend-4.default:4000
               destination:
@@ -71,6 +76,11 @@ http:
             - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/extproc/0
               failOpen: false
               messageTimeout: 15s
+              requestAttributes:
+                - xds.route_metadata
+                - connection.requested_server_name
+              responseAttributes:
+                - request.path
               authority: grpc-backend.envoy-gateway:9000
               destination:
                 name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/0/grpc-backend
diff --git a/internal/xds/translator/testdata/out/xds-ir/ext-proc.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/ext-proc.listeners.yaml
index acf4c0a40..a75f1ccc2 100755
--- a/internal/xds/translator/testdata/out/xds-ir/ext-proc.listeners.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/ext-proc.listeners.yaml
@@ -32,6 +32,11 @@
               responseBodyMode: STREAMED
               responseHeaderMode: SKIP
               responseTrailerMode: SKIP
+            requestAttributes:
+            - xds.route_metadata
+            - connection.requested_server_name
+            responseAttributes:
+            - request.path
         - disabled: true
           name: envoy.filters.http.ext_proc/envoyextensionpolicy/default/policy-for-route-1/extproc/0
           typedConfig:
@@ -78,6 +83,11 @@
               requestTrailerMode: SKIP
               responseHeaderMode: SKIP
               responseTrailerMode: SKIP
+            requestAttributes:
+            - xds.route_metadata
+            - connection.requested_server_name
+            responseAttributes:
+            - request.path
         - name: envoy.filters.http.router
           typedConfig:
             '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
diff --git a/internal/xds/translator/utils_test.go b/internal/xds/translator/utils_test.go
new file mode 100644
index 000000000..588c68690
--- /dev/null
+++ b/internal/xds/translator/utils_test.go
@@ -0,0 +1,112 @@
+// Copyright Envoy Gateway Authors
+// SPDX-License-Identifier: Apache-2.0
+// The full text of the Apache license is available in the LICENSE file at
+// the root of the repo.
+
+package translator
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"k8s.io/utils/ptr"
+
+	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
+	"github.com/envoyproxy/gateway/internal/ir"
+)
+
+func TestDetermineIPFamily(t *testing.T) {
+	tests := []struct {
+		name     string
+		settings []*ir.DestinationSetting
+		want     *egv1a1.IPFamily
+	}{
+		{
+			name:     "nil settings should return nil",
+			settings: nil,
+			want:     nil,
+		},
+		{
+			name:     "empty settings should return nil",
+			settings: []*ir.DestinationSetting{},
+			want:     nil,
+		},
+		{
+			name: "single IPv4 setting",
+			settings: []*ir.DestinationSetting{
+				{IPFamily: ptr.To(egv1a1.IPv4)},
+			},
+			want: ptr.To(egv1a1.IPv4),
+		},
+		{
+			name: "single IPv6 setting",
+			settings: []*ir.DestinationSetting{
+				{IPFamily: ptr.To(egv1a1.IPv6)},
+			},
+			want: ptr.To(egv1a1.IPv6),
+		},
+		{
+			name: "single DualStack setting",
+			settings: []*ir.DestinationSetting{
+				{IPFamily: ptr.To(egv1a1.DualStack)},
+			},
+			want: ptr.To(egv1a1.DualStack),
+		},
+		{
+			name: "mixed IPv4 and IPv6 should return DualStack",
+			settings: []*ir.DestinationSetting{
+				{IPFamily: ptr.To(egv1a1.IPv4)},
+				{IPFamily: ptr.To(egv1a1.IPv6)},
+			},
+			want: ptr.To(egv1a1.DualStack),
+		},
+		{
+			name: "DualStack with IPv4 should return DualStack",
+			settings: []*ir.DestinationSetting{
+				{IPFamily: ptr.To(egv1a1.DualStack)},
+				{IPFamily: ptr.To(egv1a1.IPv4)},
+			},
+			want: ptr.To(egv1a1.DualStack),
+		},
+		{
+			name: "DualStack with IPv6 should return DualStack",
+			settings: []*ir.DestinationSetting{
+				{IPFamily: ptr.To(egv1a1.DualStack)},
+				{IPFamily: ptr.To(egv1a1.IPv6)},
+			},
+			want: ptr.To(egv1a1.DualStack),
+		},
+		{
+			name: "mixed with nil IPFamily should be ignored",
+			settings: []*ir.DestinationSetting{
+				{IPFamily: ptr.To(egv1a1.IPv4)},
+				{IPFamily: nil},
+				{IPFamily: ptr.To(egv1a1.IPv6)},
+			},
+			want: ptr.To(egv1a1.DualStack),
+		},
+		{
+			name: "multiple IPv4 settings should return IPv4",
+			settings: []*ir.DestinationSetting{
+				{IPFamily: ptr.To(egv1a1.IPv4)},
+				{IPFamily: ptr.To(egv1a1.IPv4)},
+			},
+			want: ptr.To(egv1a1.IPv4),
+		},
+		{
+			name: "multiple IPv6 settings should return IPv6",
+			settings: []*ir.DestinationSetting{
+				{IPFamily: ptr.To(egv1a1.IPv6)},
+				{IPFamily: ptr.To(egv1a1.IPv6)},
+			},
+			want: ptr.To(egv1a1.IPv6),
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := determineIPFamily(tt.settings)
+			assert.Equal(t, tt.want, got)
+		})
+	}
+}
diff --git a/test/e2e/testdata/ext-proc-envoyextensionpolicy.yaml b/test/e2e/testdata/ext-proc-envoyextensionpolicy.yaml
index 3663e19b6..90d25613b 100644
--- a/test/e2e/testdata/ext-proc-envoyextensionpolicy.yaml
+++ b/test/e2e/testdata/ext-proc-envoyextensionpolicy.yaml
@@ -51,8 +51,12 @@ spec:
       namespace: gateway-conformance-infra
       port: 9002
     processingMode:
-      request: {}
-      response: {}
+      request:
+        attributes:
+        - xds.route_name
+      response:
+        attributes:
+        - xds.route_name
 ---
 apiVersion: gateway.envoyproxy.io/v1alpha1
 kind: EnvoyExtensionPolicy
diff --git a/test/e2e/testdata/httproute-dualstack.yaml b/test/e2e/testdata/httproute-dualstack.yaml
index e1289dac5..97a79c78a 100644
--- a/test/e2e/testdata/httproute-dualstack.yaml
+++ b/test/e2e/testdata/httproute-dualstack.yaml
@@ -95,6 +95,30 @@ spec:
   selector:
     app: infra-backend-v1
 ---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: infra-backend-v1-httproute-all-stacks
+  namespace: gateway-conformance-infra
+spec:
+  parentRefs:
+    - name: dualstack-gateway
+  rules:
+    - backendRefs:
+        - name: infra-backend-v1-service-ipv4
+          port: 8080
+          weight: 30
+        - name: infra-backend-v1-service-ipv6
+          port: 8080
+          weight: 30
+        - name: infra-backend-v1-service-dualstack
+          port: 8080
+          weight: 40
+      matches:
+        - path:
+            type: PathPrefix
+            value: /all-stacks
+---
 apiVersion: gateway.envoyproxy.io/v1alpha1
 kind: EnvoyProxy
 metadata:
@@ -119,3 +143,11 @@ spec:
     - name: http
       port: 80
       protocol: HTTP
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: GatewayClass
+metadata:
+  name: envoy-gateway
+  namespace: gateway-conformance-infra
+spec:
+  controllerName: gateway.envoyproxy.io/gatewayclass-controller
diff --git a/test/e2e/tests/ext_proc.go b/test/e2e/tests/ext_proc.go
index 033da67f6..aa1ec5493 100644
--- a/test/e2e/tests/ext_proc.go
+++ b/test/e2e/tests/ext_proc.go
@@ -63,16 +63,24 @@ var ExtProcTest = suite.ConformanceTest{
 					Request: http.Request{
 						Path: "/processor",
 						Headers: map[string]string{
-							"x-request-ext-processed":          "true",     // header added by ext-processor to backend-bound request
-							"x-request-client-header-received": "original", // this is the original client header preserved by ext-proc in a new header
-							"x-request-client-header":          "mutated",  // this is the mutated value expected to reach upstream
+							// header added by ext-processor to backend-bound request
+							"x-request-ext-processed": "true",
+							// this is the original client header preserved by ext-proc in a new header
+							"x-request-client-header-received": "original",
+							// this is the mutated value expected to reach upstream
+							"x-request-client-header": "mutated",
+							// header added by ext-processor to request based on the xds.route_name attribute
+							"x-request-xds-route-name": "httproute/gateway-conformance-infra/http-with-ext-proc/rule/0/match/0/www_example_com",
 						},
 					},
 				},
 				Response: http.Response{
 					StatusCode: 200,
 					Headers: map[string]string{
-						"x-response-ext-processed": "true", // header added by ext-processor to client-bound response
+						// header added by ext-processor to client-bound response
+						"x-response-ext-processed": "true",
+						// header added by ext-processor to response based on the xds.cluster_name attribute
+						"x-response-xds-route-name": "httproute/gateway-conformance-infra/http-with-ext-proc/rule/0/match/0/www_example_com",
 					},
 				},
 				Namespace: ns,
diff --git a/test/e2e/tests/httproute_dualstack.go b/test/e2e/tests/httproute_dualstack.go
index b01fc392a..f765b08cd 100644
--- a/test/e2e/tests/httproute_dualstack.go
+++ b/test/e2e/tests/httproute_dualstack.go
@@ -38,6 +38,9 @@ var HTTPRouteDualStackTest = suite.ConformanceTest{
 		t.Run("HTTPRoute to IPv4 only service", func(t *testing.T) {
 			runHTTPRouteTest(t, suite, ns, gwNN, "infra-backend-v1-httproute-ipv4", "/ipv4-only")
 		})
+		t.Run("HTTPRoute to All-stacks services", func(t *testing.T) {
+			runHTTPRouteTest(t, suite, ns, gwNN, "infra-backend-v1-httproute-all-stacks", "/all-stacks")
+		})
 	},
 }