@@ -38,19 +38,92 @@ type ListenersTranslator interface {
3838 ProcessListeners (gateways []* GatewayContext , xdsIR resource.XdsIRMap , infraIR resource.InfraIRMap , resources * resource.Resources )
3939}
4040
41+ // allowedRouteKindsForProtocol returns the route kinds supported by the given listener protocol.
42+ func allowedRouteKindsForProtocol (protocol gwapiv1.ProtocolType , tlsMode * gwapiv1.TLSModeType ) []gwapiv1.Kind {
43+ switch protocol {
44+ case gwapiv1 .HTTPProtocolType , gwapiv1 .HTTPSProtocolType :
45+ return []gwapiv1.Kind {resource .KindHTTPRoute , resource .KindGRPCRoute }
46+ case gwapiv1 .TLSProtocolType :
47+ if tlsMode != nil && * tlsMode == gwapiv1 .TLSModePassthrough {
48+ return []gwapiv1.Kind {resource .KindTLSRoute }
49+ }
50+ // Terminate mode or unspecified defaults to accept both TCP and TLS routes
51+ return []gwapiv1.Kind {resource .KindTCPRoute , resource .KindTLSRoute }
52+ case gwapiv1 .TCPProtocolType :
53+ return []gwapiv1.Kind {resource .KindTCPRoute }
54+ case gwapiv1 .UDPProtocolType :
55+ return []gwapiv1.Kind {resource .KindUDPRoute }
56+ default :
57+ return nil
58+ }
59+ }
60+
61+ func (t * Translator ) validateListenerSpec (listener * ListenerContext , resources * resource.Resources ) bool {
62+ // Validate listener spec directly without relying on conditions.
63+ // Start with valid assumption and invalidate on failures.
64+ // Phase 1: Validate fundamental rules
65+ specValid := t .validateAllowedNamespaces (listener )
66+
67+ // Phase 2: Validate allowed routes based on protocol
68+ if isSupportedListenerProtocol (listener .Protocol ) {
69+ var tlsMode * gwapiv1.TLSModeType
70+ if listener .TLS != nil {
71+ tlsMode = listener .TLS .Mode
72+ }
73+ allowedKinds := allowedRouteKindsForProtocol (listener .Protocol , tlsMode )
74+ if ! t .validateAllowedRoutes (listener , allowedKinds ... ) {
75+ specValid = false
76+ }
77+ } else {
78+ // Unsupported protocol
79+ specValid = false
80+ listener .SetSupportedKinds ()
81+ listener .SetCondition (
82+ gwapiv1 .ListenerConditionAccepted ,
83+ metav1 .ConditionFalse ,
84+ gwapiv1 .ListenerReasonUnsupportedProtocol ,
85+ fmt .Sprintf ("Protocol %s is unsupported, must be %s, %s, %s or %s." , listener .Protocol ,
86+ gwapiv1 .HTTPProtocolType , gwapiv1 .HTTPSProtocolType , gwapiv1 .TCPProtocolType , gwapiv1 .UDPProtocolType ),
87+ )
88+ }
89+
90+ // Phase 3: Validate TLS configuration details
91+ if ! t .validateTLSConfiguration (listener , resources ) {
92+ specValid = false
93+ }
94+
95+ // Phase 4: Validate Hostname configuration
96+ if ! t .validateHostName (listener ) {
97+ specValid = false
98+ }
99+
100+ return specValid
101+ }
102+
41103func (t * Translator ) ProcessListeners (gateways []* GatewayContext , xdsIR resource.XdsIRMap , infraIR resource.InfraIRMap , resources * resource.Resources ) {
42104 // Infra IR proxy ports must be unique.
43105 foundPorts := make (map [string ][]* protocolPort )
106+
107+ // Phase 1: Validate each listener's spec independently.
108+ // This must happen before conflict resolution so that invalid listeners
109+ // don't block valid ones during conflict detection.
110+ for _ , gateway := range gateways {
111+ for _ , listener := range gateway .listeners {
112+ listener .specValid = t .validateListenerSpec (listener , resources )
113+ }
114+ }
115+
116+ // Phase 2: Run conflict detection.
117+ // Only listeners that haven't been marked as invalid will participate in conflict resolution.
118+ t .validateConflictedProtocolsListeners (gateways )
44119 t .validateConflictedLayer7Listeners (gateways )
45120 t .validateConflictedLayer4Listeners (gateways , gwapiv1 .TCPProtocolType )
46121 t .validateConflictedLayer4Listeners (gateways , gwapiv1 .UDPProtocolType )
47122 if t .MergeGateways {
48123 t .validateConflictedMergedListeners (gateways )
49124 }
50125
51- // Iterate through all listeners to validate spec
52- // and compute status for each, and add valid ones
53- // to the Xds IR.
126+ // Phase 3: Build IR for valid listeners.
54127 for _ , gateway := range gateways {
55128 irKey := t .getIRKey (gateway .Gateway )
56129
@@ -61,50 +134,10 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource
61134 t .processProxyObservability (gateway , xdsIR [irKey ], infraIR [irKey ].Proxy , resources )
62135
63136 for _ , listener := range gateway .listeners {
64- // Process protocol & supported kinds
65- switch listener .Protocol {
66- case gwapiv1 .TLSProtocolType :
67- if listener .TLS != nil {
68- switch * listener .TLS .Mode {
69- case gwapiv1 .TLSModePassthrough :
70- t .validateAllowedRoutes (listener , resource .KindTLSRoute )
71- case gwapiv1 .TLSModeTerminate :
72- t .validateAllowedRoutes (listener , resource .KindTCPRoute , resource .KindTLSRoute )
73- default :
74- t .validateAllowedRoutes (listener , resource .KindTCPRoute , resource .KindTLSRoute )
75- }
76- } else {
77- t .validateAllowedRoutes (listener , resource .KindTCPRoute , resource .KindTLSRoute )
78- }
79- case gwapiv1 .HTTPProtocolType , gwapiv1 .HTTPSProtocolType :
80- t .validateAllowedRoutes (listener , resource .KindHTTPRoute , resource .KindGRPCRoute )
81- case gwapiv1 .TCPProtocolType :
82- t .validateAllowedRoutes (listener , resource .KindTCPRoute )
83- case gwapiv1 .UDPProtocolType :
84- t .validateAllowedRoutes (listener , resource .KindUDPRoute )
85- default :
86- listener .SetSupportedKinds ()
87- listener .SetCondition (
88- gwapiv1 .ListenerConditionAccepted ,
89- metav1 .ConditionFalse ,
90- gwapiv1 .ListenerReasonUnsupportedProtocol ,
91- fmt .Sprintf ("Protocol %s is unsupported, must be %s, %s, %s or %s." , listener .Protocol ,
92- gwapiv1 .HTTPProtocolType , gwapiv1 .HTTPSProtocolType , gwapiv1 .TCPProtocolType , gwapiv1 .UDPProtocolType ),
93- )
94- }
95-
96- // Validate allowed namespaces
97- t .validateAllowedNamespaces (listener )
98-
99- // Process TLS configuration
100- t .validateTLSConfiguration (listener , resources )
101-
102- // Process Hostname configuration
103- t .validateHostName (listener )
104-
105- // Process conditions and check if the listener is ready
106- isReady := t .validateListenerConditions (listener )
107- if ! isReady {
137+ // Finalize listener conditions and check readiness.
138+ t .validateListenerConditions (listener )
139+ if ! listener .IsReady () {
140+ // Skip invalid listeners from IR building
108141 continue
109142 }
110143
@@ -243,10 +276,18 @@ func checkOverlappingHostnames(httpsListeners []*ListenerContext) {
243276 if overlappingListeners [i ] != nil {
244277 continue
245278 }
279+ // Skip listeners that are already marked as invalid from per-listener validation
280+ if hasInvalidCondition (httpsListeners [i ]) {
281+ continue
282+ }
246283 for j := i + 1 ; j < len (httpsListeners ); j ++ {
247284 if overlappingListeners [j ] != nil {
248285 continue
249286 }
287+ // Skip listeners that are already marked as invalid from per-listener validation
288+ if hasInvalidCondition (httpsListeners [j ]) {
289+ continue
290+ }
250291 if httpsListeners [i ].Port != httpsListeners [j ].Port {
251292 continue
252293 }
@@ -325,10 +366,18 @@ func checkOverlappingCertificates(httpsListeners []*ListenerContext) {
325366 if overlappingListeners [i ] != nil {
326367 continue
327368 }
369+ // Skip listeners that are already marked as invalid from per-listener validation
370+ if hasInvalidCondition (httpsListeners [i ]) {
371+ continue
372+ }
328373 for j := i + 1 ; j < len (httpsListeners ); j ++ {
329374 if overlappingListeners [j ] != nil {
330375 continue
331376 }
377+ // Skip listeners that are already marked as invalid from per-listener validation
378+ if hasInvalidCondition (httpsListeners [j ]) {
379+ continue
380+ }
332381 if httpsListeners [i ].Port != httpsListeners [j ].Port {
333382 continue
334383 }
0 commit comments