Repository: envoyproxy/gateway

Issue:
Backend Implementation
# Backend API Implementation

This issue tracks activities related to the implementation of the Backend API: #2997  

## Backend Implementation
### API
  - [x] API Definition:  #3063 
### Endpoint types
  - [x] IPv4: #3495 
  - [x] Unix Domain Socket: #3495 
  - [x] FQDN: #3495 
  - [x] IPv6

## Backend Ref Enablement
### xRoutes  
  - [x] HTTP: #3495 
  - [x] #4035
  - [x] #4036
  - [x] #4037
  - [x] #4038

### non-xRoutes
  - [x] Ext-Proc: #3495 
  - [x] #3665
  - [x] Access Logging https://github.com/envoyproxy/gateway/pull/5652
  - [x] Tracing https://github.com/envoyproxy/gateway/pull/5652
  - [x] Metrics https://github.com/envoyproxy/gateway/pull/5652

## Misc
   - [x] Docs: #3549
   - [x] Support Cluster Settings for non-xRoute BackendRefs: #3069 

Discussion:
@github-actions: This issue has been automatically marked as stale because it has not had activity in the last 30 days.@github-actions: This issue has been automatically marked as stale because it has not had activity in the last 30 days.@github-actions: This issue has been automatically marked as stale because it has not had activity in the last 30 days.@github-actions: This issue has been automatically marked as stale because it has not had activity in the last 30 days.@github-actions: This issue has been automatically marked as stale because it has not had activity in the last 30 days.

Solution patch:
diff --git a/api/v1alpha1/accesslogging_types.go b/api/v1alpha1/envoyproxy_accesslogging_types.go
similarity index 94%
rename from api/v1alpha1/accesslogging_types.go
rename to api/v1alpha1/envoyproxy_accesslogging_types.go
index 999644d6c..9a1b00424 100644
--- a/api/v1alpha1/accesslogging_types.go
+++ b/api/v1alpha1/envoyproxy_accesslogging_types.go
@@ -145,8 +145,8 @@ const (
 // +kubebuilder:validation:XValidation:rule="self.type == 'HTTP' || !has(self.http)",message="The http field may only be set when type is HTTP."
 // +kubebuilder:validation:XValidation:message="BackendRefs must be used, backendRef is not supported.",rule="!has(self.backendRef)"
 // +kubebuilder:validation:XValidation:message="must have at least one backend in backendRefs",rule="has(self.backendRefs) && self.backendRefs.size() > 0"
-// +kubebuilder:validation:XValidation:message="BackendRefs only supports Service kind.",rule="has(self.backendRefs) ? self.backendRefs.all(f, f.kind == 'Service') : true"
-// +kubebuilder:validation:XValidation:message="BackendRefs only supports Core group.",rule="has(self.backendRefs) ? (self.backendRefs.all(f, f.group == \"\")) : true"
+// +kubebuilder:validation:XValidation:message="BackendRefs only support Service and Backend kind.",rule="has(self.backendRefs) ? self.backendRefs.all(f, f.kind == 'Service' || f.kind == 'Backend') : true"
+// +kubebuilder:validation:XValidation:message="BackendRefs only support Core and gateway.envoyproxy.io group.",rule="has(self.backendRefs) ? (self.backendRefs.all(f, f.group == \"\" || f.group == 'gateway.envoyproxy.io')) : true"
 type ALSEnvoyProxyAccessLog struct {
 	BackendCluster `json:",inline"`
 
@@ -186,8 +186,8 @@ type FileEnvoyProxyAccessLog struct {
 //
 // +kubebuilder:validation:XValidation:message="host or backendRefs needs to be set",rule="has(self.host) || self.backendRefs.size() > 0"
 // +kubebuilder:validation:XValidation:message="BackendRefs must be used, backendRef is not supported.",rule="!has(self.backendRef)"
-// +kubebuilder:validation:XValidation:message="BackendRefs only supports Service kind.",rule="has(self.backendRefs) ? self.backendRefs.all(f, f.kind == 'Service') : true"
-// +kubebuilder:validation:XValidation:message="BackendRefs only supports Core group.",rule="has(self.backendRefs) ? (self.backendRefs.all(f, f.group == \"\")) : true"
+// +kubebuilder:validation:XValidation:message="BackendRefs only support Service and Backend kind.",rule="has(self.backendRefs) ? self.backendRefs.all(f, f.kind == 'Service' || f.kind == 'Backend') : true"
+// +kubebuilder:validation:XValidation:message="BackendRefs only support Core and gateway.envoyproxy.io group.",rule="has(self.backendRefs) ? (self.backendRefs.all(f, f.group == \"\" || f.group == 'gateway.envoyproxy.io')) : true"
 type OpenTelemetryEnvoyProxyAccessLog struct {
 	BackendCluster `json:",inline"`
 	// Host define the extension service hostname.
diff --git a/api/v1alpha1/envoyproxy_metric_types.go b/api/v1alpha1/envoyproxy_metric_types.go
index f3fe7c3a5..69ce7bdfa 100644
--- a/api/v1alpha1/envoyproxy_metric_types.go
+++ b/api/v1alpha1/envoyproxy_metric_types.go
@@ -65,8 +65,8 @@ type ProxyMetricSink struct {
 //
 // +kubebuilder:validation:XValidation:message="host or backendRefs needs to be set",rule="has(self.host) || self.backendRefs.size() > 0"
 // +kubebuilder:validation:XValidation:message="BackendRefs must be used, backendRef is not supported.",rule="!has(self.backendRef)"
-// +kubebuilder:validation:XValidation:message="only supports Service kind.",rule="has(self.backendRefs) ? self.backendRefs.all(f, f.kind == 'Service') : true"
-// +kubebuilder:validation:XValidation:message="BackendRefs only supports Core group.",rule="has(self.backendRefs) ? (self.backendRefs.all(f, f.group == \"\")) : true"
+// +kubebuilder:validation:XValidation:message="BackendRefs only support Service and Backend kind.",rule="has(self.backendRefs) ? self.backendRefs.all(f, f.kind == 'Service' || f.kind == 'Backend') : true"
+// +kubebuilder:validation:XValidation:message="BackendRefs only support Core and gateway.envoyproxy.io group.",rule="has(self.backendRefs) ? (self.backendRefs.all(f, f.group == \"\" || f.group == 'gateway.envoyproxy.io')) : true"
 type ProxyOpenTelemetrySink struct {
 	BackendCluster `json:",inline"`
 	// Host define the service hostname.
diff --git a/api/v1alpha1/tracing_types.go b/api/v1alpha1/envoyproxy_tracing_types.go
similarity index 94%
rename from api/v1alpha1/tracing_types.go
rename to api/v1alpha1/envoyproxy_tracing_types.go
index 64f18f569..d18cd504a 100644
--- a/api/v1alpha1/tracing_types.go
+++ b/api/v1alpha1/envoyproxy_tracing_types.go
@@ -48,8 +48,8 @@ const (
 //
 // +kubebuilder:validation:XValidation:message="host or backendRefs needs to be set",rule="has(self.host) || self.backendRefs.size() > 0"
 // +kubebuilder:validation:XValidation:message="BackendRefs must be used, backendRef is not supported.",rule="!has(self.backendRef)"
-// +kubebuilder:validation:XValidation:message="only supports Service kind.",rule="has(self.backendRefs) ? self.backendRefs.all(f, f.kind == 'Service') : true"
-// +kubebuilder:validation:XValidation:message="BackendRefs only supports Core group.",rule="has(self.backendRefs) ? (self.backendRefs.all(f, f.group == \"\")) : true"
+// +kubebuilder:validation:XValidation:message="BackendRefs only support Service and Backend kind.",rule="has(self.backendRefs) ? self.backendRefs.all(f, f.kind == 'Service' || f.kind == 'Backend') : true"
+// +kubebuilder:validation:XValidation:message="BackendRefs only support Core and gateway.envoyproxy.io group.",rule="has(self.backendRefs) ? (self.backendRefs.all(f, f.group == \"\" || f.group == 'gateway.envoyproxy.io')) : true"
 type TracingProvider struct {
 	BackendCluster `json:",inline"`
 	// Type defines the tracing provider type.
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 50a610d68..f0eb14993 100644
--- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml
+++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml
@@ -11501,12 +11501,16 @@ spec:
                                     - message: must have at least one backend in backendRefs
                                       rule: has(self.backendRefs) && self.backendRefs.size()
                                         > 0
-                                    - message: BackendRefs only supports Service kind.
+                                    - message: BackendRefs only support Service and
+                                        Backend kind.
                                       rule: 'has(self.backendRefs) ? self.backendRefs.all(f,
-                                        f.kind == ''Service'') : true'
-                                    - message: BackendRefs only supports Core group.
+                                        f.kind == ''Service'' || f.kind == ''Backend'')
+                                        : true'
+                                    - message: BackendRefs only support Core and gateway.envoyproxy.io
+                                        group.
                                       rule: 'has(self.backendRefs) ? (self.backendRefs.all(f,
-                                        f.group == "")) : true'
+                                        f.group == "" || f.group == ''gateway.envoyproxy.io''))
+                                        : true'
                                   file:
                                     description: File defines the file accesslog sink.
                                     properties:
@@ -12491,12 +12495,16 @@ spec:
                                     - message: BackendRefs must be used, backendRef
                                         is not supported.
                                       rule: '!has(self.backendRef)'
-                                    - message: BackendRefs only supports Service kind.
+                                    - message: BackendRefs only support Service and
+                                        Backend kind.
                                       rule: 'has(self.backendRefs) ? self.backendRefs.all(f,
-                                        f.kind == ''Service'') : true'
-                                    - message: BackendRefs only supports Core group.
+                                        f.kind == ''Service'' || f.kind == ''Backend'')
+                                        : true'
+                                    - message: BackendRefs only support Core and gateway.envoyproxy.io
+                                        group.
                                       rule: 'has(self.backendRefs) ? (self.backendRefs.all(f,
-                                        f.group == "")) : true'
+                                        f.group == "" || f.group == ''gateway.envoyproxy.io''))
+                                        : true'
                                   type:
                                     description: Type defines the type of accesslog
                                       sink.
@@ -13562,12 +13570,16 @@ spec:
                               - message: BackendRefs must be used, backendRef is not
                                   supported.
                                 rule: '!has(self.backendRef)'
-                              - message: only supports Service kind.
+                              - message: BackendRefs only support Service and Backend
+                                  kind.
                                 rule: 'has(self.backendRefs) ? self.backendRefs.all(f,
-                                  f.kind == ''Service'') : true'
-                              - message: BackendRefs only supports Core group.
+                                  f.kind == ''Service'' || f.kind == ''Backend'')
+                                  : true'
+                              - message: BackendRefs only support Core and gateway.envoyproxy.io
+                                  group.
                                 rule: 'has(self.backendRefs) ? (self.backendRefs.all(f,
-                                  f.group == "")) : true'
+                                  f.group == "" || f.group == ''gateway.envoyproxy.io''))
+                                  : true'
                             type:
                               default: OpenTelemetry
                               description: |-
@@ -14603,12 +14615,14 @@ spec:
                           rule: has(self.host) || self.backendRefs.size() > 0
                         - message: BackendRefs must be used, backendRef is not supported.
                           rule: '!has(self.backendRef)'
-                        - message: only supports Service kind.
+                        - message: BackendRefs only support Service and Backend kind.
                           rule: 'has(self.backendRefs) ? self.backendRefs.all(f, f.kind
-                            == ''Service'') : true'
-                        - message: BackendRefs only supports Core group.
+                            == ''Service'' || f.kind == ''Backend'') : true'
+                        - message: BackendRefs only support Core and gateway.envoyproxy.io
+                            group.
                           rule: 'has(self.backendRefs) ? (self.backendRefs.all(f,
-                            f.group == "")) : true'
+                            f.group == "" || f.group == ''gateway.envoyproxy.io''))
+                            : true'
                       samplingFraction:
                         description: |-
                           SamplingFraction represents the fraction of requests that should be
diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go
index 10c46992f..6b3ef7ebc 100644
--- a/internal/gatewayapi/helpers.go
+++ b/internal/gatewayapi/helpers.go
@@ -86,7 +86,7 @@ var (
 	QueryParamMatchTypeDerefOr = ptr.Deref[gwapiv1.QueryParamMatchType]
 )
 
-// Deprecated: use k8s.io/utils/ptr ptr.Deref instead
+// NamespaceDerefOr returns the dereferenced value of the provided Namespace in string
 func NamespaceDerefOr(namespace *gwapiv1.Namespace, defaultNamespace string) string {
 	if namespace != nil && *namespace != "" {
 		return string(*namespace)
diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go
index bc7562f1d..6633a0c44 100644
--- a/internal/gatewayapi/listener.go
+++ b/internal/gatewayapi/listener.go
@@ -6,7 +6,6 @@
 package gatewayapi
 
 import (
-	"errors"
 	"fmt"
 	"math"
 
@@ -564,15 +563,22 @@ func (t *Translator) processBackendRefs(name string, backendCluster egv1a1.Backe
 	for _, ref := range backendCluster.BackendRefs {
 		ns := NamespaceDerefOr(ref.Namespace, namespace)
 		kind := KindDerefOr(ref.Kind, resource.KindService)
-		if kind != resource.KindService {
-			return nil, nil, errors.New("only service kind is supported for backendRefs")
-		}
-		if err := validateBackendService(ref.BackendObjectReference, resources, ns, corev1.ProtocolTCP); err != nil {
-			return nil, nil, err
+		switch kind {
+		case resource.KindService:
+			if _, err := validateBackendRefService(ref.BackendObjectReference, resources, ns, corev1.ProtocolTCP); err != nil {
+				return nil, nil, err
+			}
+			ds := t.processServiceDestinationSetting(name, ref.BackendObjectReference, ns, ir.TCP, resources, envoyProxy)
+			result = append(result, ds)
+		case resource.KindBackend:
+			if _, err := t.validateBackendRefBackend(ref.BackendObjectReference, resources, ns, true); err != nil {
+				return nil, nil, err
+			}
+			ds := t.processBackendDestinationSetting(name, ref.BackendObjectReference, ns, ir.TCP, resources)
+			result = append(result, ds)
+		default:
+			return nil, nil, fmt.Errorf("unsupported kind for backendRefs: %s", kind)
 		}
-
-		ds := t.processServiceDestinationSetting(name, ref.BackendObjectReference, ns, ir.TCP, resources, envoyProxy)
-		result = append(result, ds)
 	}
 	if len(result) == 0 {
 		return nil, traffic, nil
diff --git a/internal/gatewayapi/validate.go b/internal/gatewayapi/validate.go
index 3ca97bec9..15e7cc29d 100644
--- a/internal/gatewayapi/validate.go
+++ b/internal/gatewayapi/validate.go
@@ -53,30 +53,58 @@ func (t *Translator) validateBackendRef(backendRefContext BackendRefContext, par
 	backendRefKind := KindDerefOr(backendRef.Kind, resource.KindService)
 	switch backendRefKind {
 	case resource.KindService:
-		if err := validateBackendService(backendRef.BackendObjectReference, resources, backendNamespace, protocol); err != nil {
+		if reason, err := validateBackendRefService(backendRef.BackendObjectReference, resources, backendNamespace, protocol); err != nil {
 			routeStatus := GetRouteStatus(route)
 			status.SetRouteStatusCondition(routeStatus,
 				parentRef.routeParentStatusIdx,
 				route.GetGeneration(),
 				gwapiv1.RouteConditionResolvedRefs,
 				metav1.ConditionFalse,
-				gwapiv1.RouteReasonBackendNotFound,
-				err.Error(),
+				reason,
+				errorToMessage(err),
 			)
-			return fmt.Errorf("backend service validation failed: %w", err)
+			return fmt.Errorf("backend Service validation failed: %w", err)
 		}
 	case resource.KindServiceImport:
-		if err := t.validateBackendServiceImport(backendRef, parentRef, resources, backendNamespace, route, protocol); err != nil {
-			return fmt.Errorf("backend service import validation failed: %w", err)
+		if reason, err := t.validateBackendServiceImport(backendRef.BackendObjectReference, resources, backendNamespace, protocol); err != nil {
+			routeStatus := GetRouteStatus(route)
+			status.SetRouteStatusCondition(routeStatus,
+				parentRef.routeParentStatusIdx,
+				route.GetGeneration(),
+				gwapiv1.RouteConditionResolvedRefs,
+				metav1.ConditionFalse,
+				reason,
+				errorToMessage(err),
+			)
+			return fmt.Errorf("backend ServiceImport validation failed: %w", err)
 		}
 	case egv1a1.KindBackend:
-		if err := t.validateBackendRefBackend(backendRef, parentRef, resources, backendNamespace, route); err != nil {
+		if reason, err := t.validateBackendRefBackend(backendRef.BackendObjectReference, resources, backendNamespace, false); err != nil {
+			routeStatus := GetRouteStatus(route)
+			status.SetRouteStatusCondition(routeStatus,
+				parentRef.routeParentStatusIdx,
+				route.GetGeneration(),
+				gwapiv1.RouteConditionResolvedRefs,
+				metav1.ConditionFalse,
+				reason,
+				errorToMessage(err),
+			)
 			return fmt.Errorf("backend reference validation failed: %w", err)
 		}
 	}
 	return nil
 }
 
+func errorToMessage(err error) string {
+	if err == nil {
+		return ""
+	}
+	msg := err.Error()
+
+	// Convert first character to upper
+	return strings.ToUpper(msg[0:1]) + msg[1:]
+}
+
 func (t *Translator) validateBackendRefGroup(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, route RouteContext) error {
 	if backendRef.Group != nil && *backendRef.Group != "" && *backendRef.Group != GroupMultiClusterService && *backendRef.Group != egv1a1.GroupName {
 		routeStatus := GetRouteStatus(route)
@@ -180,9 +208,14 @@ func (t *Translator) validateBackendNamespace(backendRef *gwapiv1a2.BackendRef,
 }
 
 func (t *Translator) validateBackendPort(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, route RouteContext) error {
-	if backendRef != nil && backendRef.Kind != nil && string(*backendRef.Kind) == egv1a1.KindBackend {
+	if backendRef == nil {
 		return nil
 	}
+
+	if KindDerefOr(backendRef.Kind, resource.KindService) == egv1a1.KindBackend {
+		return nil
+	}
+
 	if backendRef.Port == nil {
 		routeStatus := GetRouteStatus(route)
 		status.SetRouteStatusCondition(routeStatus,
@@ -198,14 +231,12 @@ func (t *Translator) validateBackendPort(backendRef *gwapiv1a2.BackendRef, paren
 	return nil
 }
 
-func validateBackendService(backendRef gwapiv1a2.BackendObjectReference, resources *resource.Resources,
+func validateBackendRefService(backendRef gwapiv1a2.BackendObjectReference, resources *resource.Resources,
 	serviceNamespace string, protocol corev1.Protocol,
-) error {
+) (gwapiv1.RouteConditionReason, error) {
 	service := resources.GetService(serviceNamespace, string(backendRef.Name))
 	if service == nil {
-		// nolint: stylecheck
-		// The error message is used in the status.conditions, so it should be capitalized.
-		return fmt.Errorf("Service %s/%s not found", serviceNamespace, string(backendRef.Name))
+		return gwapiv1.RouteReasonBackendNotFound, fmt.Errorf("service %s/%s not found", serviceNamespace, string(backendRef.Name))
 	}
 	var portFound bool
 	for _, port := range service.Spec.Ports {
@@ -220,27 +251,17 @@ func validateBackendService(backendRef gwapiv1a2.BackendObjectReference, resourc
 	}
 
 	if !portFound {
-		return fmt.Errorf("%s Port %d not found on service %s/%s", string(protocol), *backendRef.Port, serviceNamespace, string(backendRef.Name))
+		return "PortNotFound", fmt.Errorf("%s Port %d not found on Service %s/%s", string(protocol), *backendRef.Port, serviceNamespace, string(backendRef.Name))
 	}
-	return nil
+	return "", nil
 }
 
-func (t *Translator) validateBackendServiceImport(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, resources *resource.Resources,
-	serviceImportNamespace string, route RouteContext, protocol corev1.Protocol,
-) error {
+func (t *Translator) validateBackendServiceImport(backendRef gwapiv1a2.BackendObjectReference, resources *resource.Resources,
+	serviceImportNamespace string, protocol corev1.Protocol,
+) (gwapiv1.RouteConditionReason, error) {
 	serviceImport := resources.GetServiceImport(serviceImportNamespace, string(backendRef.Name))
 	if serviceImport == nil {
-		routeStatus := GetRouteStatus(route)
-		status.SetRouteStatusCondition(routeStatus,
-			parentRef.routeParentStatusIdx,
-			route.GetGeneration(),
-			gwapiv1.RouteConditionResolvedRefs,
-			metav1.ConditionFalse,
-			gwapiv1.RouteReasonBackendNotFound,
-			fmt.Sprintf("ServiceImport %s/%s not found", NamespaceDerefOr(backendRef.Namespace, route.GetNamespace()),
-				string(backendRef.Name)),
-		)
-		return fmt.Errorf("service import %s/%s not found", serviceImportNamespace, backendRef.Name)
+		return gwapiv1.RouteReasonBackendNotFound, fmt.Errorf("service import %s/%s not found", serviceImportNamespace, backendRef.Name)
 	}
 
 	var portFound bool
@@ -256,83 +277,35 @@ func (t *Translator) validateBackendServiceImport(backendRef *gwapiv1a2.BackendR
 	}
 
 	if !portFound {
-		routeStatus := GetRouteStatus(route)
-		status.SetRouteStatusCondition(routeStatus,
-			parentRef.routeParentStatusIdx,
-			route.GetGeneration(),
-			gwapiv1.RouteConditionResolvedRefs,
-			metav1.ConditionFalse,
-			"PortNotFound",
-			fmt.Sprintf(string(protocol)+" Port %d not found on ServiceImport %s/%s", *backendRef.Port, serviceImportNamespace,
-				string(backendRef.Name)),
-		)
-		return fmt.Errorf("%s port %d not found on service import %s/%s", string(protocol), *backendRef.Port, serviceImportNamespace, backendRef.Name)
+		return "PortNotFound", fmt.Errorf("%s port %d not found on service import %s/%s", string(protocol), *backendRef.Port, serviceImportNamespace, backendRef.Name)
 	}
 
-	return nil
+	return "", nil
 }
 
-func (t *Translator) validateBackendRefBackend(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, resources *resource.Resources,
-	backendNamespace string, route RouteContext,
-) error {
-	routeStatus := GetRouteStatus(route)
-
+func (t *Translator) validateBackendRefBackend(backendRef gwapiv1a2.BackendObjectReference, resources *resource.Resources,
+	backendNamespace string, allowUDS bool,
+) (gwapiv1.RouteConditionReason, error) {
 	if !t.BackendEnabled {
-		status.SetRouteStatusCondition(routeStatus,
-			parentRef.routeParentStatusIdx,
-			route.GetGeneration(),
-			gwapiv1.RouteConditionResolvedRefs,
-			metav1.ConditionFalse,
-			gwapiv1.RouteReasonUnsupportedValue,
-			fmt.Sprintf("Resource %s/%s of type Backend cannot be used since Backend is disabled in Envoy Gateway configuration",
-				NamespaceDerefOr(backendRef.Namespace, route.GetNamespace()), string(backendRef.Name)),
-		)
-		return errors.New("backend is disabled in Envoy Gateway configuration")
+		return gwapiv1.RouteReasonUnsupportedValue, errors.New("backend is disabled in Envoy Gateway configuration")
 	}
 
 	backend := resources.GetBackend(backendNamespace, string(backendRef.Name))
 	if backend == nil {
-		status.SetRouteStatusCondition(routeStatus,
-			parentRef.routeParentStatusIdx,
-			route.GetGeneration(),
-			gwapiv1.RouteConditionResolvedRefs,
-			metav1.ConditionFalse,
-			gwapiv1.RouteReasonBackendNotFound,
-			fmt.Sprintf("Backend %s/%s not found", NamespaceDerefOr(backendRef.Namespace, route.GetNamespace()),
-				string(backendRef.Name)),
-		)
-		return fmt.Errorf("backend %s/%s not found", backendNamespace, backendRef.Name)
+		return gwapiv1.RouteReasonBackendNotFound, fmt.Errorf("backend %s/%s not found", backendNamespace, backendRef.Name)
 	}
 
 	if err := validateBackend(backend); err != nil {
-		status.SetRouteStatusCondition(routeStatus,
-			parentRef.routeParentStatusIdx,
-			route.GetGeneration(),
-			gwapiv1.RouteConditionResolvedRefs,
-			metav1.ConditionFalse,
-			"UnsupportedRefAddressFound",
-			fmt.Sprintf("Invalid Backend reference to Backend %s/%s found", backendNamespace,
-				string(backendRef.Name)),
-		)
-		return fmt.Errorf("invalid backend reference: %w", err)
+		return "UnsupportedRefAddressFound", fmt.Errorf("invalid backend reference: %w", err)
 	}
 
 	for _, bep := range backend.Spec.Endpoints {
-		if bep.Unix != nil {
-			status.SetRouteStatusCondition(routeStatus,
-				parentRef.routeParentStatusIdx,
-				route.GetGeneration(),
-				gwapiv1.RouteConditionResolvedRefs,
-				metav1.ConditionFalse,
-				"UnsupportedRefAddressFound",
-				fmt.Sprintf("Unix domain socket found in Backend %s/%s is not supported for xRoute backendRefs", backendNamespace,
-					string(backendRef.Name)),
-			)
-			return errors.New("unix domain sockets are not supported in backend references")
+		if bep.Unix != nil && !allowUDS {
+			return "UnsupportedRefAddressFound", errors.New("unix domain sockets are not supported in backend references")
 		}
 	}
 
-	return nil
+	return "", nil
 }
 
 func (t *Translator) validateListenerConditions(listener *ListenerContext) (isReady bool) {
diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go
index 07370f27e..db1506457 100644
--- a/internal/provider/kubernetes/controller.go
+++ b/internal/provider/kubernetes/controller.go
@@ -1903,13 +1903,13 @@ func (r *gatewayAPIReconciler) processEnvoyProxy(ep *egv1a1.EnvoyProxy, resource
 		return nil
 	}
 
-	r.log.Info("processing envoyproxy", "namespace", ep.Namespace, "name", ep.Name)
+	r.log.Info("processing EnvoyProxy", "namespace", ep.Namespace, "name", ep.Name)
 
 	if err := validation.ValidateEnvoyProxy(ep); err != nil {
-		return fmt.Errorf("invalid envoyproxy: %w", err)
+		return fmt.Errorf("invalid EnvoyProxy: %w", err)
 	}
 	if err := bootstrap.Validate(ep.Spec.Bootstrap); err != nil {
-		return fmt.Errorf("invalid envoyproxy: %w", err)
+		return fmt.Errorf("invalid EnvoyProxy: %w", err)
 	}
 
 	if ep.Spec.Telemetry != nil {



Test patch:
diff --git a/internal/gatewayapi/testdata/accesslog-als-backend.in.yaml b/internal/gatewayapi/testdata/accesslog-als-backend.in.yaml
new file mode 100644
index 000000000..bbab57fc2
--- /dev/null
+++ b/internal/gatewayapi/testdata/accesslog-als-backend.in.yaml
@@ -0,0 +1,81 @@
+envoyProxyForGatewayClass:
+  apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: EnvoyProxy
+  metadata:
+    namespace: envoy-gateway-system
+    name: als-backend
+  spec:
+    telemetry:
+      accessLog:
+        settings:
+          - format:
+              type: Text
+              text: |
+                [%START_TIME%] "%REQ(:METHOD)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"\n
+            sinks:
+              - type: OpenTelemetry
+                openTelemetry:
+                  backendRefs:
+                    - Name: backend-uds
+                      Namespace: envoy-gateway
+                      Kind: Backend
+                      Group: gateway.envoyproxy.io
+                    - Name: backend-fqdn
+                      Namespace: envoy-gateway
+                      Kind: Backend
+                      Group: gateway.envoyproxy.io
+                      port: 3000
+                    - Name: backend-ip
+                      Namespace: envoy-gateway
+                      Kind: Backend
+                      Group: gateway.envoyproxy.io
+                      port: 3001
+                  resources:
+                    k8s.cluster.name: "cluster-1"
+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: Same
+backends:
+  - apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: Backend
+    metadata:
+      name: backend-uds
+      namespace: envoy-gateway
+    spec:
+      endpoints:
+        - unix:
+            path: /var/run/backend.sock
+  - apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: Backend
+    metadata:
+      name: backend-fqdn
+      namespace: envoy-gateway
+    spec:
+      appProtocols:
+        - gateway.envoyproxy.io/h2c
+      endpoints:
+        - fqdn:
+            hostname: primary.foo.com
+            port: 3000
+  - apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: Backend
+    metadata:
+      name: backend-ip
+      namespace: envoy-gateway
+    spec:
+      endpoints:
+        - ip:
+            address: 1.1.1.1
+            port: 3001
diff --git a/internal/gatewayapi/testdata/accesslog-als-backend.out.yaml b/internal/gatewayapi/testdata/accesslog-als-backend.out.yaml
new file mode 100644
index 000000000..f17f7542b
--- /dev/null
+++ b/internal/gatewayapi/testdata/accesslog-als-backend.out.yaml
@@ -0,0 +1,200 @@
+backends:
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: Backend
+  metadata:
+    creationTimestamp: null
+    name: backend-uds
+    namespace: envoy-gateway
+  spec:
+    endpoints:
+    - unix:
+        path: /var/run/backend.sock
+  status:
+    conditions:
+    - lastTransitionTime: null
+      message: The Backend was accepted
+      reason: Accepted
+      status: "True"
+      type: Accepted
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: Backend
+  metadata:
+    creationTimestamp: null
+    name: backend-fqdn
+    namespace: envoy-gateway
+  spec:
+    appProtocols:
+    - gateway.envoyproxy.io/h2c
+    endpoints:
+    - fqdn:
+        hostname: primary.foo.com
+        port: 3000
+  status:
+    conditions:
+    - lastTransitionTime: null
+      message: The Backend was accepted
+      reason: Accepted
+      status: "True"
+      type: Accepted
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: Backend
+  metadata:
+    creationTimestamp: null
+    name: backend-ip
+    namespace: envoy-gateway
+  spec:
+    endpoints:
+    - ip:
+        address: 1.1.1.1
+        port: 3001
+  status:
+    conditions:
+    - lastTransitionTime: null
+      message: The Backend was accepted
+      reason: Accepted
+      status: "True"
+      type: Accepted
+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: Same
+      name: http
+      port: 80
+      protocol: HTTP
+  status:
+    listeners:
+    - attachedRoutes: 0
+      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
+infraIR:
+  envoy-gateway/gateway-1:
+    proxy:
+      config:
+        apiVersion: gateway.envoyproxy.io/v1alpha1
+        kind: EnvoyProxy
+        metadata:
+          creationTimestamp: null
+          name: als-backend
+          namespace: envoy-gateway-system
+        spec:
+          logging: {}
+          telemetry:
+            accessLog:
+              settings:
+              - format:
+                  text: |
+                    [%START_TIME%] "%REQ(:METHOD)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"\n
+                  type: Text
+                sinks:
+                - openTelemetry:
+                    backendRefs:
+                    - group: gateway.envoyproxy.io
+                      kind: Backend
+                      name: backend-uds
+                      namespace: envoy-gateway
+                    - group: gateway.envoyproxy.io
+                      kind: Backend
+                      name: backend-fqdn
+                      namespace: envoy-gateway
+                      port: 3000
+                    - group: gateway.envoyproxy.io
+                      kind: Backend
+                      name: backend-ip
+                      namespace: envoy-gateway
+                      port: 3001
+                    resources:
+                      k8s.cluster.name: cluster-1
+                  type: OpenTelemetry
+        status: {}
+      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:
+      openTelemetry:
+      - destination:
+          name: accesslog_otel_0_0
+          settings:
+          - addressType: IP
+            endpoints:
+            - host: ""
+              path: /var/run/backend.sock
+              port: 0
+            name: accesslog_otel_0_0/backend/-1
+            protocol: TCP
+          - addressType: FQDN
+            endpoints:
+            - host: primary.foo.com
+              port: 3000
+            name: accesslog_otel_0_0/backend/-1
+            protocol: HTTP2
+          - addressType: IP
+            endpoints:
+            - host: 1.1.1.1
+              port: 3001
+            name: accesslog_otel_0_0/backend/-1
+            protocol: TCP
+        resources:
+          k8s.cluster.name: cluster-1
+        text: |
+          [%START_TIME%] "%REQ(:METHOD)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"\n
+    http:
+    - address: 0.0.0.0
+      hostnames:
+      - '*'
+      isHTTP2: false
+      metadata:
+        kind: Gateway
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+      name: envoy-gateway/gateway-1/http
+      path:
+        escapedSlashesAction: UnescapeAndRedirect
+        mergeSlashes: true
+      port: 10080
+    readyListener:
+      address: 0.0.0.0
+      ipFamily: IPv4
+      path: /ready
+      port: 19003
diff --git a/internal/gatewayapi/testdata/backend-invalid-feature-disabled.out.yaml b/internal/gatewayapi/testdata/backend-invalid-feature-disabled.out.yaml
index 3d91269cd..6a82f655a 100644
--- a/internal/gatewayapi/testdata/backend-invalid-feature-disabled.out.yaml
+++ b/internal/gatewayapi/testdata/backend-invalid-feature-disabled.out.yaml
@@ -121,8 +121,7 @@ httpRoutes:
         status: "True"
         type: Accepted
       - lastTransitionTime: null
-        message: Resource default/backend-ip of type Backend cannot be used since
-          Backend is disabled in Envoy Gateway configuration
+        message: Backend is disabled in Envoy Gateway configuration
         reason: UnsupportedValue
         status: "False"
         type: ResolvedRefs
diff --git a/internal/gatewayapi/testdata/envoyproxy-accesslog-backend-invalid.out.yaml b/internal/gatewayapi/testdata/envoyproxy-accesslog-backend-invalid.out.yaml
index 95ff87b24..42159f1d1 100644
--- a/internal/gatewayapi/testdata/envoyproxy-accesslog-backend-invalid.out.yaml
+++ b/internal/gatewayapi/testdata/envoyproxy-accesslog-backend-invalid.out.yaml
@@ -17,7 +17,7 @@ gateways:
   status:
     conditions:
     - lastTransitionTime: null
-      message: 'Invalid access log backendRefs in the referenced EnvoyProxy: Service
+      message: 'Invalid access log backendRefs in the referenced EnvoyProxy: service
         monitoring/service-not-found not found'
       reason: InvalidParameters
       status: "False"
diff --git a/internal/gatewayapi/testdata/envoyproxy-metric-backend-invalid.out.yaml b/internal/gatewayapi/testdata/envoyproxy-metric-backend-invalid.out.yaml
index f78e5c1ff..e66bdb219 100644
--- a/internal/gatewayapi/testdata/envoyproxy-metric-backend-invalid.out.yaml
+++ b/internal/gatewayapi/testdata/envoyproxy-metric-backend-invalid.out.yaml
@@ -17,7 +17,7 @@ gateways:
   status:
     conditions:
     - lastTransitionTime: null
-      message: 'Invalid metrics backendRefs in the referenced EnvoyProxy: Service
+      message: 'Invalid metrics backendRefs in the referenced EnvoyProxy: service
         monitoring/service-not-found not found'
       reason: InvalidParameters
       status: "False"
diff --git a/internal/gatewayapi/testdata/envoyproxy-tracing-backend-invalid.out.yaml b/internal/gatewayapi/testdata/envoyproxy-tracing-backend-invalid.out.yaml
index 8ba12bf4b..2b36ddb49 100644
--- a/internal/gatewayapi/testdata/envoyproxy-tracing-backend-invalid.out.yaml
+++ b/internal/gatewayapi/testdata/envoyproxy-tracing-backend-invalid.out.yaml
@@ -17,7 +17,7 @@ gateways:
   status:
     conditions:
     - lastTransitionTime: null
-      message: 'Invalid tracing backendRefs in the referenced EnvoyProxy: Service
+      message: 'Invalid tracing backendRefs in the referenced EnvoyProxy: service
         monitoring/service-not-found not found'
       reason: InvalidParameters
       status: "False"
diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-tcproute-with-mismatch-port-protocol.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-tcproute-with-mismatch-port-protocol.out.yaml
index f1a7b628e..fef198ced 100644
--- a/internal/gatewayapi/testdata/gateway-with-listener-with-tcproute-with-mismatch-port-protocol.out.yaml
+++ b/internal/gatewayapi/testdata/gateway-with-listener-with-tcproute-with-mismatch-port-protocol.out.yaml
@@ -72,14 +72,14 @@ tcpRoutes:
     parents:
     - conditions:
       - lastTransitionTime: null
-        message: 'backend service validation failed: TCP Port 8081 not found on service
+        message: 'backend Service validation failed: TCP Port 8081 not found on Service
           default/service-1'
         reason: Failed to process the settings associated with the TCP route.
         status: "False"
         type: Accepted
       - lastTransitionTime: null
-        message: TCP Port 8081 not found on service default/service-1
-        reason: BackendNotFound
+        message: TCP Port 8081 not found on Service default/service-1
+        reason: PortNotFound
         status: "False"
         type: ResolvedRefs
       controllerName: gateway.envoyproxy.io/gatewayclass-controller
diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-udproute-with-mismatch-port-protocol.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-udproute-with-mismatch-port-protocol.out.yaml
index f0b87d5b3..2bb2d0194 100644
--- a/internal/gatewayapi/testdata/gateway-with-listener-with-udproute-with-mismatch-port-protocol.out.yaml
+++ b/internal/gatewayapi/testdata/gateway-with-listener-with-udproute-with-mismatch-port-protocol.out.yaml
@@ -72,14 +72,14 @@ udpRoutes:
     parents:
     - conditions:
       - lastTransitionTime: null
-        message: 'backend service validation failed: UDP Port 8080 not found on service
+        message: 'backend Service validation failed: UDP Port 8080 not found on Service
           default/service-1'
         reason: Failed to process the settings associated with the UDP route.
         status: "False"
         type: Accepted
       - lastTransitionTime: null
-        message: UDP Port 8080 not found on service default/service-1
-        reason: BackendNotFound
+        message: UDP Port 8080 not found on Service default/service-1
+        reason: PortNotFound
         status: "False"
         type: ResolvedRefs
       controllerName: gateway.envoyproxy.io/gatewayclass-controller
diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref-mixed-address-type.out.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref-mixed-address-type.out.yaml
index c818bbd0c..fb128b041 100644
--- a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref-mixed-address-type.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref-mixed-address-type.out.yaml
@@ -151,8 +151,7 @@ httpRoutes:
         status: "True"
         type: Accepted
       - lastTransitionTime: null
-        message: Unix domain socket found in Backend default/backend-ip-uds-mixed
-          is not supported for xRoute backendRefs
+        message: Unix domain sockets are not supported in backend references
         reason: UnsupportedRefAddressFound
         status: "False"
         type: ResolvedRefs
diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref.out.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref.out.yaml
index 702814f0c..b2e8aa5f3 100644
--- a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref.out.yaml
@@ -160,8 +160,7 @@ httpRoutes:
         status: "True"
         type: Accepted
       - lastTransitionTime: null
-        message: Unix domain socket found in Backend default/backend-uds is not supported
-          for xRoute backendRefs
+        message: Unix domain sockets are not supported in backend references
         reason: UnsupportedRefAddressFound
         status: "False"
         type: ResolvedRefs
@@ -272,8 +271,8 @@ httpRoutes:
         status: "True"
         type: Accepted
       - lastTransitionTime: null
-        message: Invalid Backend reference to Backend default/backend-ip-localhost
-          found
+        message: 'Invalid backend reference: IP address 127.0.0.1 in the loopback
+          range is not supported'
         reason: UnsupportedRefAddressFound
         status: "False"
         type: ResolvedRefs
@@ -310,8 +309,8 @@ httpRoutes:
         status: "True"
         type: Accepted
       - lastTransitionTime: null
-        message: Invalid Backend reference to Backend default/backend-fqdn-localhost
-          found
+        message: 'Invalid backend reference: hostname localhost should be a domain
+          with at least two segments separated by dots'
         reason: UnsupportedRefAddressFound
         status: "False"
         type: ResolvedRefs
diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-diff-address-type.out.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-diff-address-type.out.yaml
index 92a24d474..6163f16de 100644
--- a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-diff-address-type.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-diff-address-type.out.yaml
@@ -168,8 +168,7 @@ httpRoutes:
         status: "True"
         type: Accepted
       - lastTransitionTime: null
-        message: Unix domain socket found in Backend default/backend-uds is not supported
-          for xRoute backendRefs
+        message: Unix domain sockets are not supported in backend references
         reason: UnsupportedRefAddressFound
         status: "False"
         type: ResolvedRefs
@@ -249,8 +248,7 @@ httpRoutes:
         status: "True"
         type: Accepted
       - lastTransitionTime: null
-        message: Unix domain socket found in Backend default/backend-uds is not supported
-          for xRoute backendRefs
+        message: Unix domain sockets are not supported in backend references
         reason: UnsupportedRefAddressFound
         status: "False"
         type: ResolvedRefs
diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-same-address-type.out.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-same-address-type.out.yaml
index ab570df99..eec8cb0e0 100644
--- a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-same-address-type.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-same-address-type.out.yaml
@@ -178,8 +178,7 @@ httpRoutes:
         status: "True"
         type: Accepted
       - lastTransitionTime: null
-        message: Unix domain socket found in Backend default/backend-uds2 is not supported
-          for xRoute backendRefs
+        message: Unix domain sockets are not supported in backend references
         reason: UnsupportedRefAddressFound
         status: "False"
         type: ResolvedRefs
diff --git a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-bad-port.out.yaml b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-bad-port.out.yaml
index 668a73d74..38843d504 100644
--- a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-bad-port.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-bad-port.out.yaml
@@ -67,8 +67,8 @@ httpRoutes:
         status: "True"
         type: Accepted
       - lastTransitionTime: null
-        message: TCP Port 8888 not found on service default/service-1
-        reason: BackendNotFound
+        message: TCP Port 8888 not found on Service default/service-1
+        reason: PortNotFound
         status: "False"
         type: ResolvedRefs
       controllerName: gateway.envoyproxy.io/gatewayclass-controller
diff --git a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-no-service.import.out.yaml b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-no-service.import.out.yaml
index e7ca2a6a0..4eb1ff373 100644
--- a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-no-service.import.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-no-service.import.out.yaml
@@ -69,7 +69,7 @@ httpRoutes:
         status: "True"
         type: Accepted
       - lastTransitionTime: null
-        message: ServiceImport default/service-import-that-doesnt-exist not found
+        message: Service import default/service-import-that-doesnt-exist not found
         reason: BackendNotFound
         status: "False"
         type: ResolvedRefs
diff --git a/internal/gatewayapi/testdata/httproute-with-mirror-filter-service-not-found.out.yaml b/internal/gatewayapi/testdata/httproute-with-mirror-filter-service-not-found.out.yaml
index 3bf0e0141..d12d21a45 100644
--- a/internal/gatewayapi/testdata/httproute-with-mirror-filter-service-not-found.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-with-mirror-filter-service-not-found.out.yaml
@@ -72,7 +72,7 @@ httpRoutes:
     parents:
     - conditions:
       - lastTransitionTime: null
-        message: 'Backend service validation failed: Service default/service-unknown
+        message: 'Backend Service validation failed: service default/service-unknown
           not found.'
         reason: UnsupportedValue
         status: "False"
diff --git a/test/cel-validation/envoyproxy_test.go b/test/cel-validation/envoyproxy_test.go
index 89f14cef8..ec3ab4725 100644
--- a/test/cel-validation/envoyproxy_test.go
+++ b/test/cel-validation/envoyproxy_test.go
@@ -610,7 +610,7 @@ func TestEnvoyProxyProvider(t *testing.T) {
 					},
 				}
 			},
-			wantErrors: []string{"BackendRefs only supports Service Kind."},
+			wantErrors: []string{"Invalid value: \"object\": BackendRefs only support Service and Backend kind."},
 		},
 		{
 			desc: "invalid-accesslog-ALS-backendrefs-group",
@@ -644,7 +644,7 @@ func TestEnvoyProxyProvider(t *testing.T) {
 					},
 				}
 			},
-			wantErrors: []string{"BackendRefs only supports Core group."},
+			wantErrors: []string{"BackendRefs only support Core and gateway.envoyproxy.io group."},
 		},
 		{
 			desc: "invalid-accesslog-ALS-no-backendrefs",
@@ -760,7 +760,7 @@ func TestEnvoyProxyProvider(t *testing.T) {
 					},
 				}
 			},
-			wantErrors: []string{"Invalid value: \"object\": BackendRefs only supports Service kind."},
+			wantErrors: []string{"Invalid value: \"object\": BackendRefs only support Service and Backend kind."},
 		},
 		{
 			desc: "invalid-accesslog-backendref-group",
@@ -797,7 +797,7 @@ func TestEnvoyProxyProvider(t *testing.T) {
 					},
 				}
 			},
-			wantErrors: []string{"BackendRefs only supports Core group."},
+			wantErrors: []string{"BackendRefs only support Core and gateway.envoyproxy.io group."},
 		},
 		{
 			desc: "accesslog-backendref",
@@ -1040,7 +1040,7 @@ func TestEnvoyProxyProvider(t *testing.T) {
 					},
 				}
 			},
-			wantErrors: []string{"only supports Service Kind."},
+			wantErrors: []string{"BackendRefs only support Service and Backend kind."},
 		},
 		{
 			desc: "ProxyMetrics-sinks-invalid-backendref-group",
@@ -1070,7 +1070,7 @@ func TestEnvoyProxyProvider(t *testing.T) {
 					},
 				}
 			},
-			wantErrors: []string{"BackendRefs only supports Core group."},
+			wantErrors: []string{"BackendRefs only support Core and gateway.envoyproxy.io group."},
 		},
 		{
 			desc: "invalid-tracing-backendref-invalid-kind",
@@ -1095,7 +1095,7 @@ func TestEnvoyProxyProvider(t *testing.T) {
 					},
 				}
 			},
-			wantErrors: []string{"only supports Service Kind."},
+			wantErrors: []string{"BackendRefs only support Service and Backend kind."},
 		},
 		{
 			desc: "tracing-backendref-empty-kind",
@@ -1471,6 +1471,79 @@ func TestEnvoyProxyProvider(t *testing.T) {
 				"only one of SamplingRate or SamplingFraction can be specified",
 			},
 		},
+		{
+			desc: "backendRefs-backend",
+			mutate: func(envoy *egv1a1.EnvoyProxy) {
+				envoy.Spec = egv1a1.EnvoyProxySpec{
+					Telemetry: &egv1a1.ProxyTelemetry{
+						Tracing: &egv1a1.ProxyTracing{
+							Provider: egv1a1.TracingProvider{
+								Type: egv1a1.TracingProviderTypeOpenTelemetry,
+								BackendCluster: egv1a1.BackendCluster{
+									BackendRefs: []egv1a1.BackendRef{
+										{
+											BackendObjectReference: gwapiv1.BackendObjectReference{
+												Name:  "fake-service",
+												Kind:  ptr.To(gwapiv1.Kind("Backend")),
+												Group: ptr.To(gwapiv1.Group("gateway.envoyproxy.io")),
+												Port:  ptr.To(gwapiv1.PortNumber(8080)),
+											},
+										},
+									},
+								},
+							},
+						},
+						AccessLog: &egv1a1.ProxyAccessLog{
+							Settings: []egv1a1.ProxyAccessLogSetting{
+								{
+									Sinks: []egv1a1.ProxyAccessLogSink{
+										{
+											Type: egv1a1.ProxyAccessLogSinkTypeALS,
+											ALS: &egv1a1.ALSEnvoyProxyAccessLog{
+												BackendCluster: egv1a1.BackendCluster{
+													BackendRefs: []egv1a1.BackendRef{
+														{
+															BackendObjectReference: gwapiv1.BackendObjectReference{
+																Name:  "fake-service",
+																Kind:  ptr.To(gwapiv1.Kind("Backend")),
+																Group: ptr.To(gwapiv1.Group("gateway.envoyproxy.io")),
+																Port:  ptr.To(gwapiv1.PortNumber(9000)),
+															},
+														},
+													},
+												},
+												Type: egv1a1.ALSEnvoyProxyAccessLogTypeHTTP,
+											},
+										},
+									},
+								},
+							},
+						},
+						Metrics: &egv1a1.ProxyMetrics{
+							Sinks: []egv1a1.ProxyMetricSink{
+								{
+									Type: egv1a1.MetricSinkTypeOpenTelemetry,
+									OpenTelemetry: &egv1a1.ProxyOpenTelemetrySink{
+										BackendCluster: egv1a1.BackendCluster{
+											BackendRefs: []egv1a1.BackendRef{
+												{
+													BackendObjectReference: gwapiv1.BackendObjectReference{
+														Name:  "fake-service",
+														Kind:  ptr.To(gwapiv1.Kind("Backend")),
+														Group: ptr.To(gwapiv1.Group("gateway.envoyproxy.io")),
+														Port:  ptr.To(gwapiv1.PortNumber(8080)),
+													},
+												},
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				}
+			},
+		},
 	}
 
 	for _, tc := range cases {
diff --git a/test/e2e/testdata/accesslog-otel-default.yaml b/test/e2e/testdata/accesslog-otel-default.yaml
index 764e8e02e..b8f8d5b50 100644
--- a/test/e2e/testdata/accesslog-otel-default.yaml
+++ b/test/e2e/testdata/accesslog-otel-default.yaml
@@ -34,8 +34,9 @@ spec:
             - type: OpenTelemetry
               openTelemetry:
                 backendRefs:
-                  - name: otel-collector
-                    namespace: monitoring
+                  - name: backend-fqdn
+                    kind: Backend
+                    group: gateway.envoyproxy.io
                     port: 4317
                 resources:
                   k8s.cluster.name: "envoy-gateway"
@@ -43,6 +44,19 @@ spec:
     drainTimeout: 5s
     minDrainDuration: 1s
 ---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: Backend
+metadata:
+  name: backend-fqdn
+  namespace: gateway-conformance-infra
+spec:
+  appProtocols:
+    - gateway.envoyproxy.io/h2c
+  endpoints:
+    - fqdn:
+        hostname: otel-collector.monitoring.svc.cluster.local
+        port: 4317
+---
 apiVersion: gateway.networking.k8s.io/v1
 kind: HTTPRoute
 metadata:
diff --git a/test/e2e/testdata/tracing-datadog.yaml b/test/e2e/testdata/tracing-datadog.yaml
index fa6024ee8..d20097f20 100644
--- a/test/e2e/testdata/tracing-datadog.yaml
+++ b/test/e2e/testdata/tracing-datadog.yaml
@@ -48,8 +48,9 @@ spec:
       provider:
         type: Datadog
         backendRefs:
-          - name: datadog-agent
-            namespace: monitoring
+          - name: backend-fqdn
+            kind: Backend
+            group: gateway.envoyproxy.io
             port: 8126
       customTags:
         "provider":
@@ -74,6 +75,17 @@ spec:
     drainTimeout: 5s
     minDrainDuration: 1s
 ---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: Backend
+metadata:
+  name: backend-fqdn
+  namespace: gateway-conformance-infra
+spec:
+  endpoints:
+    - fqdn:
+        hostname: datadog-agent.monitoring.svc.cluster.local
+        port: 8126
+---
 apiVersion: gateway.networking.k8s.io/v1
 kind: HTTPRoute
 metadata: