@@ -214,6 +214,94 @@ func validClientCertificateRef(ref *gwapiv1.SecretObjectReference) error {
214214 return nil
215215}
216216
217+ // allowedRouteKindsForProtocol returns the route kinds supported by the given listener protocol.
218+ func allowedRouteKindsForProtocol (protocol gwapiv1.ProtocolType , tlsMode * gwapiv1.TLSModeType ) []gwapiv1.Kind {
219+ switch protocol {
220+ case gwapiv1 .HTTPProtocolType , gwapiv1 .HTTPSProtocolType :
221+ return []gwapiv1.Kind {resource .KindHTTPRoute , resource .KindGRPCRoute }
222+ case gwapiv1 .TLSProtocolType :
223+ if tlsMode != nil && * tlsMode == gwapiv1 .TLSModePassthrough {
224+ return []gwapiv1.Kind {resource .KindTLSRoute }
225+ }
226+ // Terminate mode or unspecified defaults to accept both TCP and TLS routes
227+ return []gwapiv1.Kind {resource .KindTCPRoute , resource .KindTLSRoute }
228+ case gwapiv1 .TCPProtocolType :
229+ return []gwapiv1.Kind {resource .KindTCPRoute }
230+ case gwapiv1 .UDPProtocolType :
231+ return []gwapiv1.Kind {resource .KindUDPRoute }
232+ default :
233+ return nil
234+ }
235+ }
236+
237+ // validateProtocolRules validates protocol-specific constraints (hostname, TLS requirements).
238+ // Returns true if all constraints are satisfied, false otherwise.
239+ func validateProtocolRules (listener * ListenerContext ) bool {
240+ switch listener .Protocol {
241+ case gwapiv1 .HTTPProtocolType , gwapiv1 .HTTPSProtocolType , gwapiv1 .TLSProtocolType ,
242+ gwapiv1 .TCPProtocolType , gwapiv1 .UDPProtocolType :
243+ // All supported protocols pass basic validation here.
244+ // Protocol-specific constraints (TLS, hostname) are validated in
245+ // validateTLSConfiguration and validateHostName respectively,
246+ // where they can set proper conditions.
247+ return true
248+
249+ default :
250+ // Unsupported protocol handled separately
251+ return false
252+ }
253+ }
254+
255+ func (t * Translator ) validateListenerSpec (listener * ListenerContext , resources * resource.Resources ) bool {
256+ // Validate listener spec directly without relying on conditions.
257+ // Start with valid assumption and invalidate on failures.
258+
259+ // Phase 1: Validate fundamental rules
260+ specValid := t .validateAllowedNamespaces (listener )
261+ if ! validateProtocolRules (listener ) {
262+ specValid = false
263+ }
264+
265+ // Phase 2: Validate allowed routes based on protocol
266+ if listener .Protocol == gwapiv1 .HTTPProtocolType ||
267+ listener .Protocol == gwapiv1 .HTTPSProtocolType ||
268+ listener .Protocol == gwapiv1 .TCPProtocolType ||
269+ listener .Protocol == gwapiv1 .UDPProtocolType ||
270+ listener .Protocol == gwapiv1 .TLSProtocolType {
271+ var tlsMode * gwapiv1.TLSModeType
272+ if listener .TLS != nil {
273+ tlsMode = listener .TLS .Mode
274+ }
275+ allowedKinds := allowedRouteKindsForProtocol (listener .Protocol , tlsMode )
276+ if ! t .validateAllowedRoutes (listener , allowedKinds ... ) {
277+ specValid = false
278+ }
279+ } else {
280+ // Unsupported protocol
281+ specValid = false
282+ listener .SetSupportedKinds ()
283+ listener .SetCondition (
284+ gwapiv1 .ListenerConditionAccepted ,
285+ metav1 .ConditionFalse ,
286+ gwapiv1 .ListenerReasonUnsupportedProtocol ,
287+ fmt .Sprintf ("Protocol %s is unsupported, must be %s, %s, %s or %s." , listener .Protocol ,
288+ gwapiv1 .HTTPProtocolType , gwapiv1 .HTTPSProtocolType , gwapiv1 .TCPProtocolType , gwapiv1 .UDPProtocolType ),
289+ )
290+ }
291+
292+ // Phase 3: Validate TLS configuration details
293+ if ! t .validateTLSConfiguration (listener , resources ) {
294+ specValid = false
295+ }
296+
297+ // Phase 4: Validate Hostname configuration
298+ if ! t .validateHostName (listener ) {
299+ specValid = false
300+ }
301+
302+ return specValid
303+ }
304+
217305func (t * Translator ) ProcessListeners (gateways []* GatewayContext , xdsIR resource.XdsIRMap , infraIR resource.InfraIRMap , resources * resource.Resources ) {
218306 // Infra IR proxy ports must be unique.
219307 foundPorts := make (map [string ][]* protocolPort )
@@ -223,51 +311,13 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource
223311 // don't block valid ones during conflict detection.
224312 for _ , gateway := range gateways {
225313 for _ , listener := range gateway .listeners {
226- // Process protocol & supported kinds
227- switch listener .Protocol {
228- case gwapiv1 .TLSProtocolType :
229- if listener .TLS != nil {
230- switch * listener .TLS .Mode {
231- case gwapiv1 .TLSModePassthrough :
232- t .validateAllowedRoutes (listener , resource .KindTLSRoute )
233- case gwapiv1 .TLSModeTerminate :
234- t .validateAllowedRoutes (listener , resource .KindTCPRoute , resource .KindTLSRoute )
235- default :
236- t .validateAllowedRoutes (listener , resource .KindTCPRoute , resource .KindTLSRoute )
237- }
238- } else {
239- t .validateAllowedRoutes (listener , resource .KindTCPRoute , resource .KindTLSRoute )
240- }
241- case gwapiv1 .HTTPProtocolType , gwapiv1 .HTTPSProtocolType :
242- t .validateAllowedRoutes (listener , resource .KindHTTPRoute , resource .KindGRPCRoute )
243- case gwapiv1 .TCPProtocolType :
244- t .validateAllowedRoutes (listener , resource .KindTCPRoute )
245- case gwapiv1 .UDPProtocolType :
246- t .validateAllowedRoutes (listener , resource .KindUDPRoute )
247- default :
248- listener .SetSupportedKinds ()
249- listener .SetCondition (
250- gwapiv1 .ListenerConditionAccepted ,
251- metav1 .ConditionFalse ,
252- gwapiv1 .ListenerReasonUnsupportedProtocol ,
253- fmt .Sprintf ("Protocol %s is unsupported, must be %s, %s, %s or %s." , listener .Protocol ,
254- gwapiv1 .HTTPProtocolType , gwapiv1 .HTTPSProtocolType , gwapiv1 .TCPProtocolType , gwapiv1 .UDPProtocolType ),
255- )
256- }
257-
258- // Validate allowed namespaces
259- t .validateAllowedNamespaces (listener )
260-
261- // Process TLS configuration
262- t .validateTLSConfiguration (listener , resources )
263-
264- // Process Hostname configuration
265- t .validateHostName (listener )
314+ listener .specValid = t .validateListenerSpec (listener , resources )
266315 }
267316 }
268317
269318 // Phase 2: Run conflict detection.
270319 // Only listeners that haven't been marked as invalid will participate in conflict resolution.
320+ t .validateConflictedProtocolsListeners (gateways )
271321 t .validateConflictedLayer7Listeners (gateways )
272322 t .validateConflictedLayer4Listeners (gateways , gwapiv1 .TCPProtocolType )
273323 t .validateConflictedLayer4Listeners (gateways , gwapiv1 .UDPProtocolType )
@@ -286,9 +336,9 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource
286336 t .processProxyObservability (gateway , xdsIR [irKey ], infraIR [irKey ].Proxy , resources )
287337
288338 for _ , listener := range gateway .listeners {
289- // Process conditions and check if the listener is ready
290- isReady := t .validateListenerConditions (listener )
291- if ! isReady {
339+ // Finalize listener conditions and check readiness.
340+ t .validateListenerConditions (listener )
341+ if ! listener . IsReady () {
292342 // Skip invalid listeners from IR building
293343 continue
294344 }
0 commit comments