router: respecting HTTPRoute listener - #1517
Conversation
Signed-off-by: Avinash Kumar Deepak <avinash8655279@gmail.com>
|
@LiZhenCheng9527 @acsoto PTAL, this keeps listener-scoped HTTPRoutes from matching traffic on other listeners of the same Gateway. |
| } | ||
| if gatewayNamespace+"/"+string(parentRef.Name) != gatewayKey { | ||
| continue | ||
| } |
There was a problem hiding this comment.
ParentReference.Port is already honored by the controller, but this request-time check ignores it. A route targeting port 8081 can still match traffic on another port.
There was a problem hiding this comment.
listener port is now added to the request context and checked during route matching.
| } | ||
| if gatewayNamespace+"/"+string(parentRef.Name) != gatewayKey { | ||
| continue | ||
| } |
There was a problem hiding this comment.
An unscoped parentRef is still treated as accepted by every listener. Since the controller stores the route when any listener accepts it, it can match on another listener whose allowedRoutes rejects it.
There was a problem hiding this comment.
Agree, reconciliation now stores explicit parentRefs only for listeners that accepted the route.
|
|
||
| func httpRouteMatchesGatewayListenerName(route *gatewayv1.HTTPRoute, gatewayKey, listenerName string) bool { | ||
| for _, parentRef := range route.Spec.ParentRefs { | ||
| if parentRef.Group != nil && string(*parentRef.Group) != gatewayv1.GroupName { |
There was a problem hiding this comment.
nit: The comparison of Group and Kind should be abstracted out to create a new function.
Signed-off-by: Avinash Kumar Deepak <avinash8655279@gmail.com>
|
@LiZhenCheng9527 @acsoto thanks for revewing sir. I have updated, ptal when get chance. |
|
e2e fail |
i feel the failure is flaky and not caused by this change |
|
|
||
| c.Set(router.GatewayKey, matched.GatewayKey) | ||
| c.Set(router.GatewayListenerNameKey, matched.ListenerName) | ||
| c.Set(router.GatewayListenerPortKey, int(matched.Port)) |
There was a problem hiding this comment.
Good — this is the missing half of the fix from #1476. I confirmed matched.ListenerName / matched.Port are populated directly from listener.Name / listener.Port (router.go:479-480), which is the exact same source the controller writes into the stored parentRef's SectionName / Port. So the request-side equality check in httpRouteMatchesGatewayListener compares like-for-like values and won't spuriously mismatch.
There was a problem hiding this comment.
thankyou so much sir😄
| acceptedParentRef := parentRef | ||
| sectionName := listener.Name | ||
| port := listener.Port | ||
| acceptedParentRef.SectionName = §ionName |
There was a problem hiding this comment.
Correct Gateway API semantics: a parentRef without sectionName is expanded into one accepted parentRef per accepting listener, each stamped with the concrete SectionName+Port. This is what lets request-time matching be listener-scoped. Two things I verified are safe: (1) the datastore Gateway index keys off parentRef.Name+namespace (store.go:2222-2235), both preserved, so lookups still resolve; (2) syncHandler reads httpRoute.Spec.ParentRefs from the original informer object, not this rewritten storedRoute copy, and there's no HTTPRoute status writer consuming the mutated refs — so stamping synthetic sectionName/port has no status side effect.
| if gatewayNamespace+"/"+string(parentRef.Name) != gatewayKey { | ||
| continue | ||
| } | ||
| if listenerName == "" && listenerPort == 0 { |
There was a problem hiding this comment.
Fail-closed logic is sound. Because the controller now always stamps SectionName+Port on every stored route, this SectionName == nil && Port == nil branch can only be true for a legacy/unprocessed route — so when listener context is missing, nothing matches, which is the safe default. Nicely covered by the skips unprocessed route with listener context and skips listener-scoped route without listener context test cases. Verified the full router + controller + app test suites pass.
| return false | ||
| } | ||
|
|
||
| func isGatewayParentRef(parentRef gatewayv1.ParentReference) bool { |
There was a problem hiding this comment.
Minor (non-blocking): isGatewayParentRef is now defined identically in three packages — here, controller (httproute_controller.go), and datastore (store.go:2244). Consider hoisting a single shared helper to keep the parentRef group/kind semantics from drifting between the accept path and the match path. Fine to defer.
There was a problem hiding this comment.
sir i feel, ill defer the shared-helper cleanup to keep this fix scoped.
|
Thankyou so much for revewing @YaoZengzeng |
|
/lgtm |
|
/approve |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: LiZhenCheng9527 The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
What type of PR is this?
/kind bug
What this PR does / why we need it:
HTTPRoute matching was scoped to the Gateway, not the listener handling the request. This allowed a route with parentRefs[].sectionName to match requests received by another listener on the same Gateway.
This change passes the selected listener name through the request context and filters HTTPRoutes before hostname and path matching. Listener-scoped routes also fail closed when listener context is missing.
Which issue(s) this PR fixes:
Fixes #1476
Bug evidence (required for bug-related PRs):
Reproduction steps and the affected Gateway/HTTPRoute configuration are documented in #1476.
Before this change, listener selection stored only the Gateway key:
kthena/cmd/kthena-router/app/router.go
Line 258 in 5d19b80
Request matching then loaded every HTTPRoute indexed under that Gateway:
kthena/pkg/kthena-router/router/httproute_match.go
Lines 73 to 74 in 5d19b80
For a Gateway with
publicandprivatelisteners, a route attached withsectionName: privatecould therefore participate in matching onpublicwhen its hostname and path matched.The selected listener is now added to the request context:
kthena/cmd/kthena-router/app/router.go
Lines 258 to 259 in c3da190
Routes are filtered against the matching Gateway parentRef and
sectionNamebefore normal request matching:kthena/pkg/kthena-router/router/httproute_match.go
Lines 84 to 118 in c3da190
This was identified by tracing the production request path. It has not been reproduced in a cluster.
Special notes for your reviewer:
Tests run:
Does this PR introduce a user-facing change?: