Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions internal/gatewayapi/contexts.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,12 @@ func (g *GatewayContext) attachEnvoyProxy(resources *resource.Resources, epMap m
return err
}

func (g *GatewayContext) IncreaseAttachedListenerSets() {
if g.Status.AttachedListenerSets == nil {
g.Status.AttachedListenerSets = new(int32(1))
} else {
*g.Status.AttachedListenerSets++
func (g *GatewayContext) SetAttachedListenerSets(count int32) {
if count <= 0 {
g.Status.AttachedListenerSets = nil
return
}
g.Status.AttachedListenerSets = &count
}

// ListenerContext wraps a Listener and provides helper methods for
Expand Down Expand Up @@ -277,13 +277,17 @@ func (l *ListenerContext) IsReady() bool {
conditions = l.gateway.Status.Listeners[l.listenerStatusIdx].Conditions
}

// Check if Accepted=False or Programmed=False exists.
for _, cond := range conditions {
if cond.Type == string(gwapiv1.ListenerConditionProgrammed) && cond.Status == metav1.ConditionTrue {
return true
if cond.Type == string(gwapiv1.ListenerConditionAccepted) && cond.Status == metav1.ConditionFalse {
return false
}
if cond.Type == string(gwapiv1.ListenerConditionProgrammed) && cond.Status == metav1.ConditionFalse {
return false
}
}

return false
return true
}

func (l *ListenerContext) GetNamespace() string {
Expand Down
19 changes: 8 additions & 11 deletions internal/gatewayapi/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ const (
TCPProtocol = "TCP"
UDPProtocol = "UDP"

L4Protocol = "L4"
L7Protocol = "L7"

// CACertKey is the key used in ConfigMaps and Secrets to store CA certificate data
CACertKey = "ca.crt"
// CRLKey is the key used in ConfigMaps and Secrets to store certificate revocation list data
Expand Down Expand Up @@ -424,24 +421,24 @@ func wildcardHostnameMatchesHostname(wildcardHostname, hostname string) bool {

func containsPort(ports []*protocolPort, port *protocolPort) bool {
for _, protocolPort := range ports {
curProtocol, curLevel := layer4Protocol(protocolPort)
myProtocol, myLevel := layer4Protocol(port)
if protocolPort.port == port.port && (curProtocol == myProtocol && curLevel == myLevel) {
curProtocol := layer4Protocol(protocolPort)
myProtocol := layer4Protocol(port)
if protocolPort.port == port.port && curProtocol == myProtocol {
return true
}
}
return false
}

// layer4Protocol returns listener L4 protocol and listen protocol level
func layer4Protocol(protocolPort *protocolPort) (string, string) {
// layer4Protocol returns listener L4 protocol
func layer4Protocol(protocolPort *protocolPort) string {
switch protocolPort.protocol {
case gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType, gwapiv1.TLSProtocolType:
return TCPProtocol, L7Protocol
Comment thread
jukie marked this conversation as resolved.
return TCPProtocol
case gwapiv1.TCPProtocolType:
return TCPProtocol, L4Protocol
return TCPProtocol
default:
return UDPProtocol, L4Protocol
return UDPProtocol
}
}

Expand Down
10 changes: 5 additions & 5 deletions internal/gatewayapi/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,10 +242,11 @@ func allowedRouteKindsForProtocol(protocol gwapiv1.ProtocolType, tlsMode *gwapiv
func (t *Translator) validateListenerSpec(listener *ListenerContext, resources *resource.Resources) bool {
// Validate listener spec directly without relying on conditions.
// Start with valid assumption and invalidate on failures.
// Phase 1: Validate fundamental rules

// Phase 1: Validate allowed namespaces
specValid := t.validateAllowedNamespaces(listener)

// Phase 2: Validate allowed routes based on protocol
// Phase 2: Validate protocol support and allowed route kinds
if isSupportedListenerProtocol(listener.Protocol) {
var tlsMode *gwapiv1.TLSModeType
if listener.TLS != nil {
Expand Down Expand Up @@ -313,7 +314,6 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource
}
t.processProxyReadyListener(xdsIR[irKey], gateway.envoyProxy)
t.processProxyObservability(gateway, xdsIR[irKey], infraIR[irKey].Proxy, resources)

for _, listener := range gateway.listeners {
// Finalize listener conditions and check readiness.
t.validateListenerConditions(listener)
Expand Down Expand Up @@ -419,7 +419,7 @@ func (t *Translator) checkOverlappingTLSConfig(gateways []*GatewayContext) {
httpsListeners := []*ListenerContext{}
for _, gateway := range gateways {
for _, listener := range gateway.listeners {
if listener.Protocol == gwapiv1.HTTPSProtocolType {
if listener.Protocol == gwapiv1.HTTPSProtocolType && listener.IsReady() {
httpsListeners = append(httpsListeners, listener)
}
}
Expand All @@ -434,7 +434,7 @@ func (t *Translator) checkOverlappingTLSConfig(gateways []*GatewayContext) {
for _, gateway := range gateways {
httpsListeners := []*ListenerContext{}
for _, listener := range gateway.listeners {
if listener.Protocol == gwapiv1.HTTPSProtocolType {
if listener.Protocol == gwapiv1.HTTPSProtocolType && listener.IsReady() {
httpsListeners = append(httpsListeners, listener)
}
}
Expand Down
38 changes: 37 additions & 1 deletion internal/gatewayapi/listenerset.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ func (t *Translator) processListenerSet(ls *gwapiv1.ListenerSet, gatewayMap map[
}
gatewayCtx.listeners = append(gatewayCtx.listeners, listenerCtx)
}
gatewayCtx.IncreaseAttachedListenerSets()
}

// ProcessListenerSetStatus computes the status of ListenerSets after their listeners have been processed.
Expand Down Expand Up @@ -179,6 +178,43 @@ func (t *Translator) ProcessListenerSetStatus(listenerSets []*gwapiv1.ListenerSe
}
}

// UpdateGatewayAttachedListenerSetCount sets Gateway.status.attachedListenerSets based on
// ListenerSet Accepted=True status.
func (t *Translator) UpdateGatewayAttachedListenerSetCount(listenerSets []*gwapiv1.ListenerSet, gateways []*GatewayContext) {
gatewayMap := make(map[types.NamespacedName]*GatewayContext, len(gateways))
for _, gw := range gateways {
gatewayMap[types.NamespacedName{Namespace: gw.Namespace, Name: gw.Name}] = gw
// reset for current reconciliation cycle
gw.SetAttachedListenerSets(0)
}

counts := make(map[types.NamespacedName]int32)
for _, ls := range listenerSets {
if !listenerSetAccepted(ls) {
continue
}
parentNamespace := NamespaceDerefOr(ls.Spec.ParentRef.Namespace, ls.Namespace)
key := types.NamespacedName{Namespace: parentNamespace, Name: string(ls.Spec.ParentRef.Name)}
if _, ok := gatewayMap[key]; !ok {
continue
}
counts[key]++
}

for key, count := range counts {
gatewayMap[key].SetAttachedListenerSets(count)
}
}

func listenerSetAccepted(ls *gwapiv1.ListenerSet) bool {
for _, cond := range ls.Status.Conditions {
if cond.Type == string(gwapiv1.ListenerSetConditionAccepted) {
return cond.Status == metav1.ConditionTrue
}
}
return false
}

func (t *Translator) isListenerSetAllowed(gateway *gwapiv1.Gateway, ls *gwapiv1.ListenerSet) bool {
// If AllowedListeners is not set, attachment is not allowed (default is None)
if gateway.Spec.AllowedListeners == nil || gateway.Spec.AllowedListeners.Namespaces == nil || gateway.Spec.AllowedListeners.Namespaces.From == nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,13 @@ gateways:
status: "True"
type: Conflicted
- lastTransitionTime: null
message: Listener is invalid, see other Conditions for details.
reason: Invalid
message: All listeners for a given port must use a unique hostname
reason: HostnameConflict
status: "False"
type: Accepted
- lastTransitionTime: null
message: All listeners for a given port must use a unique hostname
reason: HostnameConflict
status: "False"
type: Programmed
- lastTransitionTime: null
Expand All @@ -56,8 +61,13 @@ gateways:
status: "True"
type: Conflicted
- lastTransitionTime: null
message: Listener is invalid, see other Conditions for details.
reason: Invalid
message: All listeners for a given port must use a unique hostname
reason: HostnameConflict
status: "False"
type: Accepted
- lastTransitionTime: null
message: All listeners for a given port must use a unique hostname
reason: HostnameConflict
status: "False"
type: Programmed
- lastTransitionTime: null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,13 @@ gateways:
status: "True"
type: Conflicted
- lastTransitionTime: null
message: Listener is invalid, see other Conditions for details.
reason: Invalid
message: All listeners for a given port must use a unique hostname
reason: HostnameConflict
status: "False"
type: Accepted
- lastTransitionTime: null
message: All listeners for a given port must use a unique hostname
reason: HostnameConflict
status: "False"
type: Programmed
- lastTransitionTime: null
Expand All @@ -54,8 +59,13 @@ gateways:
status: "True"
type: Conflicted
- lastTransitionTime: null
message: Listener is invalid, see other Conditions for details.
reason: Invalid
message: All listeners for a given port must use a unique hostname
reason: HostnameConflict
status: "False"
type: Accepted
- lastTransitionTime: null
message: All listeners for a given port must use a unique hostname
reason: HostnameConflict
status: "False"
type: Programmed
- lastTransitionTime: null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,26 @@ gateways:
mode: Terminate
certificateRefs:
- name: tls-secret-1
- allowedRoutes:
namespaces:
from: All
name: udp-8162
port: 8162
protocol: UDP
# This listener(http-8162) is valid because HTTP + UDP are compatible protocols.
- allowedRoutes:
namespaces:
from: All
name: http-8162
port: 8162
protocol: HTTP
# This listener(tcp-8162) is invalid because TCP is not compatible with HTTP.
- allowedRoutes:
namespaces:
from: All
name: tcp-8162
port: 8162
protocol: TCP
secrets:
- apiVersion: v1
kind: Secret
Expand Down
Loading
Loading