Skip to content

fix: honor BackendTrafficPolicy targetRefs.sectionName for Service ports#428

Open
AlinsRan wants to merge 1 commit into
masterfrom
fix/backend-traffic-policy-section-name
Open

fix: honor BackendTrafficPolicy targetRefs.sectionName for Service ports#428
AlinsRan wants to merge 1 commit into
masterfrom
fix/backend-traffic-policy-section-name

Conversation

@AlinsRan

@AlinsRan AlinsRan commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

What this does

Fixes #421.

AttachBackendTrafficPolicyToUpstream selected the policy to apply by matching only targetRef.Name and ignored targetRef.sectionName. As a result a BackendTrafficPolicy intended for a single named Service port was treated as if it applied to the entire Service.

For a Service target, the Gateway API interprets sectionName as the port name (see the generated API reference). This PR makes attachment honor it:

  • A targetRef without sectionName still applies to the whole Service (unchanged behavior).
  • A targetRef with sectionName attaches only to the backend whose resolved Service port name matches it.
  • A port-specific targetRef takes precedence over a whole-Service targetRef that matches the same backend.
  • Per Gateway API semantics, a sectionName that cannot be resolved does not attach.

To resolve a backend's port name, the function now also receives tctx.Services and maps the backend ref port number to the Service port name. All call sites (httproute / grpcroute / ingress / tcproute / tlsroute / udproute) are updated.

Tests

Added TestAttachBackendTrafficPolicyToUpstreamSectionName covering: sectionName match, mismatch (no attach), no-sectionName whole-Service attach, and port-specific precedence over whole-Service.

go build, go vet, and go test ./internal/adc/translator/ all pass.

Summary by CodeRabbit

  • New Features

    • Backend traffic policies now support port-specific targeting, enabling policies to be applied to specific named ports on backend services rather than entire services.
  • Tests

    • Added tests to verify port-specific backend traffic policy behavior across route types.

AttachBackendTrafficPolicyToUpstream only matched targetRef.Name and
ignored sectionName, so a policy scoped to one named Service port was
applied to the whole Service.

Now when a targetRef sets sectionName, the policy attaches only to the
backend whose Service port name matches it; a port-specific targetRef
takes precedence over a whole-Service one. Per Gateway API semantics, a
sectionName that cannot be resolved does not attach.

Closes #421
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

AttachBackendTrafficPolicyToUpstream in policies.go gains a services map parameter and new selection logic that prefers policies whose targetRef.sectionName matches the backend's Service port name, falling back to a generic (no sectionName) policy. A new backendRefMatchesSectionName helper performs the port lookup. All six route translator call sites are updated to pass tctx.Services, and a new table-driven test covers the four matching scenarios.

Changes

BackendTrafficPolicy sectionName-aware attachment

Layer / File(s) Summary
Core policy attachment logic and sectionName helper
internal/adc/translator/policies.go
AttachBackendTrafficPolicyToUpstream accepts a new services map[types.NamespacedName]*corev1.Service parameter. Iterates all candidate policies to find a "specific" match (targetRef sectionName resolves to the backend's Service port name via backendRefMatchesSectionName) or falls back to a "generic" policy with no sectionName; attaches only the winning policy. New backendRefMatchesSectionName helper returns false for nil port, missing Service, or unmatched port number.
Call-site propagation and tests
internal/adc/translator/httproute.go, internal/adc/translator/grpcroute.go, internal/adc/translator/ingress.go, internal/adc/translator/tcproute.go, internal/adc/translator/tlsroute.go, internal/adc/translator/udproute.go, internal/adc/translator/httproute_test.go
All six route translators pass tctx.Services as the fourth argument to AttachBackendTrafficPolicyToUpstream. New TestAttachBackendTrafficPolicyToUpstreamSectionName tests four cases: matching sectionName applies scheme, non-matching sectionName does not, absent sectionName applies to whole service, and a port-specific policy overrides a whole-service policy.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Security Check ❌ Error The AttachBackendTrafficPolicyToUpstream function matches BackendRef to BackendTrafficPolicy by Name only, missing validation of Kind/Group, enabling cross-resource-type attachment when names col... Add Kind/Group validation: Check ref.Kind against "Service" (defaulting to it if nil) and targetRef.Kind/Group before applying the policy, preventing wrong policy type attachment.
E2e Test Quality Review ⚠️ Warning PR adds unit test only without E2E test (violates E2E completeness requirement). Critical review comment about missing targetRef.Kind/Group validation (cross-kind attachment risk) was not addressed... Add E2E test covering full flow (API→Controller→Translator→APISIX). Implement targetRef.Kind and targetRef.Group validation in AttachBackendTrafficPolicyToUpstream to prevent cross-kind attachment when names collide.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: implementing support for BackendTrafficPolicy targetRefs.sectionName for Service ports, which directly addresses the issue objectives.
Linked Issues check ✅ Passed The PR fully implements the required functionality from issue #421: BackendTrafficPolicy targetRefs.sectionName is now honored for Service backends with port-name matching, precedence rules, and Gateway API semantics compliance.
Out of Scope Changes check ✅ Passed All changes are directly within scope: updates to AttachBackendTrafficPolicyToUpstream signature and implementation, call-site updates in all route translators, and a comprehensive test for sectionName matching behavior.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/backend-traffic-policy-section-name

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/adc/translator/policies.go`:
- Around line 54-60: The policy matching logic in the loop iterating through
po.Spec.TargetRefs only validates the Name field of the targetRef against
ref.Name, which allows policies for different resource kinds (e.g.,
ServiceImport) to incorrectly attach to resources with the same name but
different kinds (e.g., Service). Add validation to also check that the
targetRef's group and kind match the corresponding fields of ref before
proceeding with the name comparison and the subsequent
backendRefMatchesSectionName check. This ensures policies are scoped to the
correct resource type and prevents cross-kind attachment when names collide.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1a7756f5-9f28-46b9-b2fa-ae57f0937e7d

📥 Commits

Reviewing files that changed from the base of the PR and between a3d4540 and 3c78cad.

📒 Files selected for processing (8)
  • internal/adc/translator/grpcroute.go
  • internal/adc/translator/httproute.go
  • internal/adc/translator/httproute_test.go
  • internal/adc/translator/ingress.go
  • internal/adc/translator/policies.go
  • internal/adc/translator/tcproute.go
  • internal/adc/translator/tlsroute.go
  • internal/adc/translator/udproute.go

Comment on lines 54 to +60
for _, targetRef := range po.Spec.TargetRefs {
if ref.Name == targetRef.Name {
policy = po
break
if ref.Name != targetRef.Name {
continue
}
if targetRef.SectionName != nil && *targetRef.SectionName != "" {
if backendRefMatchesSectionName(ref, po.Namespace, string(*targetRef.SectionName), services) {
specificPolicy = po

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate targetRef group/kind before attaching by name.

At Line 55, matching only by Name allows cross-kind attachment when backend names collide (e.g., a ServiceImport policy attaching to a Service backend). This breaks attachment scoping and can apply the wrong policy.

💡 Suggested fix
 import (
 	"encoding/json"

 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/utils/ptr"
 	gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
 	gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"

 	adctypes "github.com/apache/apisix-ingress-controller/api/adc"
 	"github.com/apache/apisix-ingress-controller/api/v1alpha1"
 	apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
+	internaltypes "github.com/apache/apisix-ingress-controller/internal/types"
 )
@@
 func (t *Translator) AttachBackendTrafficPolicyToUpstream(ref gatewayv1.BackendRef, policies map[types.NamespacedName]*v1alpha1.BackendTrafficPolicy, upstream *adctypes.Upstream, services map[types.NamespacedName]*corev1.Service) {
@@
+	refKind := internaltypes.KindService
+	if ref.Kind != nil {
+		refKind = string(*ref.Kind)
+	}
+	refGroup := ""
+	if ref.Group != nil {
+		refGroup = string(*ref.Group)
+	}
 	for _, po := range policies {
@@
 		for _, targetRef := range po.Spec.TargetRefs {
-			if ref.Name != targetRef.Name {
+			if string(ref.Name) != string(targetRef.Name) {
+				continue
+			}
+			if targetRef.Kind != "" && string(targetRef.Kind) != refKind {
+				continue
+			}
+			if targetRef.Group != "" && string(targetRef.Group) != refGroup {
 				continue
 			}

As per coding guidelines, "Resource access must be scoped to the correct parent entity; validate that child resources (subscription, upstream, route, credential) belong to the requested parent before access or modification."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/adc/translator/policies.go` around lines 54 - 60, The policy
matching logic in the loop iterating through po.Spec.TargetRefs only validates
the Name field of the targetRef against ref.Name, which allows policies for
different resource kinds (e.g., ServiceImport) to incorrectly attach to
resources with the same name but different kinds (e.g., Service). Add validation
to also check that the targetRef's group and kind match the corresponding fields
of ref before proceeding with the name comparison and the subsequent
backendRefMatchesSectionName check. This ensures policies are scoped to the
correct resource type and prevents cross-kind attachment when names collide.

Source: Coding guidelines

@github-actions

Copy link
Copy Markdown
Contributor

conformance test report - apisix mode

apiVersion: gateway.networking.k8s.io/v1
date: "2026-06-18T01:16:03Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.3.0
implementation:
  contact: null
  organization: APISIX
  project: apisix-ingress-controller
  url: https://github.com/apache/apisix-ingress-controller.git
  version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
    result: success
    statistics:
      Failed: 0
      Passed: 12
      Skipped: 0
  name: GATEWAY-GRPC
  summary: Core tests succeeded.
- core:
    failedTests:
    - HTTPRouteInvalidBackendRefUnknownKind
    result: failure
    skippedTests:
    - HTTPRouteHTTPSListener
    statistics:
      Failed: 1
      Passed: 31
      Skipped: 1
  extended:
    result: partial
    skippedTests:
    - HTTPRouteRedirectPortAndScheme
    statistics:
      Failed: 0
      Passed: 11
      Skipped: 1
    supportedFeatures:
    - GatewayAddressEmpty
    - GatewayPort8080
    - HTTPRouteBackendProtocolWebSocket
    - HTTPRouteDestinationPortMatching
    - HTTPRouteHostRewrite
    - HTTPRouteMethodMatching
    - HTTPRoutePathRewrite
    - HTTPRoutePortRedirect
    - HTTPRouteQueryParamMatching
    - HTTPRouteRequestMirror
    - HTTPRouteResponseHeaderModification
    - HTTPRouteSchemeRedirect
    unsupportedFeatures:
    - GatewayHTTPListenerIsolation
    - GatewayInfrastructurePropagation
    - GatewayStaticAddresses
    - HTTPRouteBackendProtocolH2C
    - HTTPRouteBackendRequestHeaderModification
    - HTTPRouteBackendTimeout
    - HTTPRouteParentRefPort
    - HTTPRoutePathRedirect
    - HTTPRouteRequestMultipleMirrors
    - HTTPRouteRequestPercentageMirror
    - HTTPRouteRequestTimeout
  name: GATEWAY-HTTP
  summary: Core tests failed with 1 test failures. Extended tests partially succeeded
    with 1 test skips.
- core:
    result: partial
    skippedTests:
    - TLSRouteSimpleSameNamespace
    statistics:
      Failed: 0
      Passed: 10
      Skipped: 1
  name: GATEWAY-TLS
  summary: Core tests partially succeeded with 1 test skips.

@github-actions

Copy link
Copy Markdown
Contributor

conformance test report - apisix-standalone mode

apiVersion: gateway.networking.k8s.io/v1
date: "2026-06-18T01:16:16Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.3.0
implementation:
  contact: null
  organization: APISIX
  project: apisix-ingress-controller
  url: https://github.com/apache/apisix-ingress-controller.git
  version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
    result: success
    statistics:
      Failed: 0
      Passed: 12
      Skipped: 0
  name: GATEWAY-GRPC
  summary: Core tests succeeded.
- core:
    result: partial
    skippedTests:
    - HTTPRouteHTTPSListener
    statistics:
      Failed: 0
      Passed: 32
      Skipped: 1
  extended:
    failedTests:
    - HTTPRouteRequestMirror
    result: failure
    skippedTests:
    - HTTPRouteRedirectPortAndScheme
    statistics:
      Failed: 1
      Passed: 10
      Skipped: 1
    supportedFeatures:
    - GatewayAddressEmpty
    - GatewayPort8080
    - HTTPRouteBackendProtocolWebSocket
    - HTTPRouteDestinationPortMatching
    - HTTPRouteHostRewrite
    - HTTPRouteMethodMatching
    - HTTPRoutePathRewrite
    - HTTPRoutePortRedirect
    - HTTPRouteQueryParamMatching
    - HTTPRouteRequestMirror
    - HTTPRouteResponseHeaderModification
    - HTTPRouteSchemeRedirect
    unsupportedFeatures:
    - GatewayHTTPListenerIsolation
    - GatewayInfrastructurePropagation
    - GatewayStaticAddresses
    - HTTPRouteBackendProtocolH2C
    - HTTPRouteBackendRequestHeaderModification
    - HTTPRouteBackendTimeout
    - HTTPRouteParentRefPort
    - HTTPRoutePathRedirect
    - HTTPRouteRequestMultipleMirrors
    - HTTPRouteRequestPercentageMirror
    - HTTPRouteRequestTimeout
  name: GATEWAY-HTTP
  summary: Core tests partially succeeded with 1 test skips. Extended tests failed
    with 1 test failures.
- core:
    result: partial
    skippedTests:
    - TLSRouteSimpleSameNamespace
    statistics:
      Failed: 0
      Passed: 10
      Skipped: 1
  name: GATEWAY-TLS
  summary: Core tests partially succeeded with 1 test skips.

@github-actions

Copy link
Copy Markdown
Contributor

conformance test report

apiVersion: gateway.networking.k8s.io/v1
date: "2026-06-18T01:32:33Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.3.0
implementation:
  contact: null
  organization: APISIX
  project: apisix-ingress-controller
  url: https://github.com/apache/apisix-ingress-controller.git
  version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
    failedTests:
    - GatewayModifyListeners
    result: failure
    statistics:
      Failed: 1
      Passed: 11
      Skipped: 0
  name: GATEWAY-GRPC
  summary: Core tests failed with 1 test failures.
- core:
    failedTests:
    - GatewayModifyListeners
    result: failure
    skippedTests:
    - HTTPRouteHTTPSListener
    statistics:
      Failed: 1
      Passed: 31
      Skipped: 1
  extended:
    result: partial
    skippedTests:
    - HTTPRouteRedirectPortAndScheme
    statistics:
      Failed: 0
      Passed: 11
      Skipped: 1
    supportedFeatures:
    - GatewayAddressEmpty
    - GatewayPort8080
    - HTTPRouteBackendProtocolWebSocket
    - HTTPRouteDestinationPortMatching
    - HTTPRouteHostRewrite
    - HTTPRouteMethodMatching
    - HTTPRoutePathRewrite
    - HTTPRoutePortRedirect
    - HTTPRouteQueryParamMatching
    - HTTPRouteRequestMirror
    - HTTPRouteResponseHeaderModification
    - HTTPRouteSchemeRedirect
    unsupportedFeatures:
    - GatewayHTTPListenerIsolation
    - GatewayInfrastructurePropagation
    - GatewayStaticAddresses
    - HTTPRouteBackendProtocolH2C
    - HTTPRouteBackendRequestHeaderModification
    - HTTPRouteBackendTimeout
    - HTTPRouteParentRefPort
    - HTTPRoutePathRedirect
    - HTTPRouteRequestMultipleMirrors
    - HTTPRouteRequestPercentageMirror
    - HTTPRouteRequestTimeout
  name: GATEWAY-HTTP
  summary: Core tests failed with 1 test failures. Extended tests partially succeeded
    with 1 test skips.
- core:
    failedTests:
    - GatewayModifyListeners
    - TLSRouteSimpleSameNamespace
    result: failure
    statistics:
      Failed: 2
      Passed: 9
      Skipped: 0
  name: GATEWAY-TLS
  summary: Core tests failed with 2 test failures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: honor BackendTrafficPolicy targetRefs.sectionName when attaching to Service backends

1 participant