Skip to content

Commit d9a46f0

Browse files
committed
feat: validate targetRefs group and skip sectionName for L4RoutePolicy
Add an XValidation rule requiring targetRefs.group to be gateway.networking.k8s.io so invalid targets fail fast instead of being silently ignored by the controller. L4 routes expose no addressable sections, so a targetRef that pins a sectionName cannot be honored. Ignore such refs when accepting a policy (ProcessL4RoutePolicy) and when attaching plugins (AttachL4RoutePolicyPlugins) to keep status and dataplane behavior consistent.
1 parent c9222de commit d9a46f0

4 files changed

Lines changed: 42 additions & 0 deletions

File tree

api/v1alpha1/l4routepolicy_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type L4RoutePolicySpec struct {
3030
// +kubebuilder:validation:MinItems=1
3131
// +kubebuilder:validation:MaxItems=16
3232
// +kubebuilder:validation:XValidation:rule="self.all(r, r.kind == 'TCPRoute' || r.kind == 'UDPRoute' || r.kind == 'TLSRoute')",message="targetRefs kind must be TCPRoute, UDPRoute, or TLSRoute"
33+
// +kubebuilder:validation:XValidation:rule="self.all(r, r.group == 'gateway.networking.k8s.io')",message="targetRefs group must be gateway.networking.k8s.io"
3334
TargetRefs []gatewayv1alpha2.LocalPolicyTargetReferenceWithSectionName `json:"targetRefs"`
3435

3536
// Plugins is the list of APISIX stream plugins to attach to the targeted L4 routes.

config/crd/bases/apisix.apache.org_l4routepolicies.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ spec:
119119
- message: targetRefs kind must be TCPRoute, UDPRoute, or TLSRoute
120120
rule: self.all(r, r.kind == 'TCPRoute' || r.kind == 'UDPRoute' ||
121121
r.kind == 'TLSRoute')
122+
- message: targetRefs group must be gateway.networking.k8s.io
123+
rule: self.all(r, r.group == 'gateway.networking.k8s.io')
122124
required:
123125
- targetRefs
124126
type: object

internal/adc/translator/policies.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,11 @@ func (t *Translator) AttachL4RoutePolicyPlugins(
198198
if string(ref.Name) != routeName {
199199
continue
200200
}
201+
// sectionName targeting is not supported for L4 routes; skip such refs
202+
// so plugins are not attached for an attachment that cannot be honored.
203+
if ref.SectionName != nil && *ref.SectionName != "" {
204+
continue
205+
}
201206
t.mergeL4PolicyPlugins(policy, plugins)
202207
return
203208
}

internal/controller/policies.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,31 @@ func parentRefValueEqual(a, b gatewayv1.ParentReference) bool {
228228
a.Name == b.Name
229229
}
230230

231+
// l4RoutePolicyMatchesRoute reports whether the policy has a targetRef that matches the
232+
// given L4 route. A ref matches only when its group/kind/name equal the route and it does
233+
// not pin a sectionName, since L4 routes expose no addressable sections to attach to.
234+
func l4RoutePolicyMatchesRoute(policy v1alpha1.L4RoutePolicy, routeKind, routeNamespace, routeName string) bool {
235+
if policy.Namespace != routeNamespace {
236+
return false
237+
}
238+
for _, ref := range policy.Spec.TargetRefs {
239+
if string(ref.Group) != gatewayv1alpha2.GroupName {
240+
continue
241+
}
242+
if string(ref.Kind) != routeKind {
243+
continue
244+
}
245+
if string(ref.Name) != routeName {
246+
continue
247+
}
248+
if ref.SectionName != nil && *ref.SectionName != "" {
249+
continue
250+
}
251+
return true
252+
}
253+
return false
254+
}
255+
231256
// ProcessL4RoutePolicy finds L4RoutePolicy resources that target the given L4 route
232257
// (identified by namespace, name, and kind), resolves conflicts deterministically,
233258
// populates tctx.L4RoutePolicies with the winning policy, and queues status updates.
@@ -247,6 +272,15 @@ func ProcessL4RoutePolicy(
247272
return
248273
}
249274

275+
// L4 routes have no addressable sections; a targetRef that specifies a sectionName
276+
// cannot be honored, so ignore policies that only match this route via such a ref.
277+
list.Items = slices.DeleteFunc(list.Items, func(p v1alpha1.L4RoutePolicy) bool {
278+
return !l4RoutePolicyMatchesRoute(p, routeKind, routeNamespace, routeName)
279+
})
280+
if len(list.Items) == 0 {
281+
return
282+
}
283+
250284
// Deterministic conflict resolution: oldest creationTimestamp wins; tie-break by namespace/name.
251285
sort.Slice(list.Items, func(i, j int) bool {
252286
ti := list.Items[i].CreationTimestamp.Time

0 commit comments

Comments
 (0)