Skip to content

GEP-1713 Revisions #3744

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jun 11, 2025
Merged
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
31 changes: 31 additions & 0 deletions apis/v1/gateway_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,37 @@ const (
GatewayReasonListenersNotReady GatewayConditionReason = "ListenersNotReady"
)

const (
// AttachedListenerSets is a condition that is true when the Gateway has
// at least one ListenerSet attached to it.
//
// Possible reasons for this condition to be True are:
//
// * "ListenerSetsAttached"
//
// Possible reasons for this condition to be False are:
//
// * "NoListenerSetsAttached"
// * "ListenerSetsNotAllowed"
//
// Controllers may raise this condition with other reasons,
// but should prefer to use the reasons listed above to improve
// interoperability.
GatewayConditionAttachedListenerSets GatewayConditionType = "AttachedListenerSets"

// This reason is used with the "AttachedListenerSets" condition when the
// Gateway has at least one ListenerSet attached to it.
GatewayReasonListenerSetsAttached GatewayConditionReason = "ListenerSetsAttached"

// This reason is used with the "AttachedListenerSets" condition when the
// Gateway has no ListenerSets attached to it.
GatewayReasonNoListenerSetsAttached GatewayConditionReason = "NoListenerSetsAttached"

// This reason is used with the "AttachedListenerSets" condition when the
// Gateway has ListenerSets attached to it, but the ListenerSets are not allowed.
GatewayReasonListenerSetsNotAllowed GatewayConditionReason = "ListenerSetsNotAllowed"
)

// ListenerStatus is the status associated with a Listener.
type ListenerStatus struct {
// Name is the name of the Listener that this status corresponds to.
Expand Down
33 changes: 29 additions & 4 deletions apisx/v1alpha1/xlistenerset_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,33 @@ import (
// +kubebuilder:printcolumn:name="Programmed",type=string,JSONPath=`.status.conditions[?(@.type=="Programmed")].status`
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`

// XListenerSet defines a set of additional listeners
// to attach to an existing Gateway.
// XListenerSet defines a set of additional listeners to attach to an existing Gateway.
// This resource provides a mechanism to merge multiple listeners into a single Gateway.
//
// The parent Gateway must explicitly allow ListenerSet attachment through its
// AllowedListeners configuration. By default, Gateways do not allow ListenerSet
// attachment.
//
// Routes can attach to a ListenerSet by specifying it as a parentRef, and can
// optionally target specific listeners using the sectionName field.
//
// Policy Attachment:
// - Policies that attach to a ListenerSet apply to all listeners defined in that resource
// - Policies do not impact listeners in the parent Gateway
// - Different ListenerSets attached to the same Gateway can have different policies
// - If an implementation cannot apply a policy to specific listeners, it should reject the policy
//
// ReferenceGrant Semantics:
// - ReferenceGrants applied to a Gateway are not inherited by child ListenerSets
// - ReferenceGrants applied to a ListenerSet do not grant permission to the parent Gateway's listeners
// - A ListenerSet can reference secrets/backends in its own namespace without a ReferenceGrant
//
// Gateway Integration:
// - The parent Gateway's status will include an "AttachedListenerSets" condition
// - This condition will be:
// - True: when AllowedListeners is set and at least one child ListenerSet is attached
// - False: when AllowedListeners is set but no valid listeners are attached, or when AllowedListeners is not set or false
// - Unknown: when no AllowedListeners config is present
type XListenerSet struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down Expand Up @@ -63,10 +88,10 @@ type ListenerSetSpec struct {
//
// 1. "parent" Gateway
// 2. ListenerSet ordered by creation time (oldest first)
// 3. ListenerSet ordered alphabetically by {namespace}/{name}.
// 3. ListenerSet ordered alphabetically by "{namespace}/{name}".
//
// An implementation MAY reject listeners by setting the ListenerEntryStatus
// `Accepted`` condition to False with the Reason `TooManyListeners`
// `Accepted` condition to False with the Reason `TooManyListeners`
//
// If a listener has a conflict, this will be reported in the
// Status.ListenerEntryStatus setting the `Conflicted` condition to True.
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 35 additions & 25 deletions geps/gep-1713/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ Thus updating a single `Gateway` resource with this many certificates is a conte

More broadly, large scale gateway users often expose `O(1000)` domains, but are currently limited by the maximum of 64 `listeners`.

The spec currently has language to indicate implementations `MAY` merge `Gateways` resources but does not define any specific requirements for how that should work.
https://github.com/kubernetes-sigs/gateway-api/blob/541e9fc2b3c2f62915cb58dc0ee5e43e4096b3e2/apis/v1beta1/gateway_types.go#L76-L78
The [spec currently has language](https://github.com/kubernetes-sigs/gateway-api/blob/541e9fc2b3c2f62915cb58dc0ee5e43e4096b3e2/apis/v1beta1/gateway_types.go#L76-L78) to indicate implementations `MAY` merge `Gateways` resources but does not define any specific requirements for how that should work.


## Feature Details

Expand Down Expand Up @@ -164,15 +164,8 @@ type ListenerEntry struct {
// Port is the network port. Multiple listeners may use the
// same port, subject to the Listener compatibility rules.
//
// If the port is specified as zero, the implementation will assign
// a unique port. If the implementation does not support dynamic port
// assignment, it MUST set `Accepted` condition to `False` with the
// `UnsupportedPort` reason.
//
// Support: Core
//
// +optional
Port *PortNumber `json:"port,omitempty"`
Port PortNumber `json:"port,omitempty"`

// Protocol specifies the network protocol this listener expects to receive.
//
Expand Down Expand Up @@ -385,8 +378,7 @@ spec:
```
### ListenerEntry

`ListenerEntry` is currently a copy of the `Listener` struct with some changes
1. `Port` is now a pointer to allow for dynamic port assignment.
`ListenerEntry` is currently a copy of the `Listener` struct with some changes noted in the below sections

## Semantics

Expand All @@ -399,7 +391,7 @@ When there are no listeners the `Gateway`'s `status.listeners` should be empty o

Implementations, when creating a `Gateway`, may provision underlying infrastructure when there are no listeners present. The status conditions `Accepted` and `Programmed` conditions should reflect state of this provisioning.

### Gateway <> ListenerSet Handshake
### Gateway & ListenerSet Handshake

By default a `Gateway` MUST NOT allow `ListenerSets` to be attached. Users can enable this behaviour by configuring their `Gateway` to allow `ListenerSet` attachment:

Expand All @@ -413,7 +405,7 @@ spec:
- from: Same
```

### Route Attaching
### Route Attachment

Routes MUST be able to specify a `ListenerSet` as a `parentRef`. Routes can use `sectionName`/`port` fields in `ParentReference` to help target a specific listener. If no listener is targeted (`sectionName`/`port` are unset) then the Route attaches to all the listeners in the `ListenerSet`.

Expand Down Expand Up @@ -461,10 +453,36 @@ spec:
sectionName: foo
```

#### Optional Section Name

If a `sectionName` in a Route's `parentRef` is not set then the Route MUST attach to only the listeners in the referenced parent. As an example given a `Gateway` and it's child `ListenerSets` a route attaching to the `Gateway` with an empty `sectionName` shall only attach to the listeners in the `Gateways` immediate `spec.listeners` list. In other words, the Route will not attach to any listeners in the `ListenerSets`. This is necessary because, for UX reasons, the `name` field does not have to be unique across all Listeners merged into a Gateway (see the section below for details).

### Policy Attachment

Policy attachment is [under discussion] in https://github.com/kubernetes-sigs/gateway-api/discussions/2927

Similar to Routes, `ListenerSet` can inherit policy from a Gateway.
Policies that attach to a `ListenerSet` apply to all listeners defined in that resource, but do not impact listeners in the parent `Gateway`. This allows `ListenerSets` attached to the same `Gateway` to have different policies.
If the implementation cannot apply the policy to only specific listeners, it should reject the policy.

### ReferenceGrant Semantics

When a `ReferenceGrant` is applied to a `Gateway` it MUST NOT be inherited by child `ListenerSets`. Thus a `ListenerSet` listener MUST NOT access secrets granted to the `Gateway` listeners.

When a `ReferenceGrant` is applied to a `ListenerSet` it MUST NOT grant permission to the parent `Gateway`'s listeners. Thus a `Gateway` listener MUST NOT access secrets granted to the `ListenerSet` listeners.

A `ListenerSet` must be able to reference a secret/backend in the same namespace as itself without a `ReferenceGrant`.


### Listener Validation

Implementations MUST treat the parent `Gateway`s as having the merged list of all listeners from itself and attached `ListenerSets`. See 'Listener Precedence' for more details on ordering.
Validation of this list of listeners MUST behave the same as if the list were part of a single `Gateway`.
Within a single resource such as a `Gateway` or `ListenerSet` the list of listeners MUST have unique names. Implementations MUST allow listeners from a child `ListenerSet` to be merged into a parent `Gateway` when listeners have the same name. Likewise implementations MUST allow sibling `ListenerSets` listeners with matching names to be merged into a parent `Gateway`. This allows for authors of Routes to simply attach to their desired parentRef and listener without having to worry about naming conflicts across resources.

It is up to the implementations how unique names are generated internally. One example would be to hash the `ListenerSet` name+namespace and prepend it to the listener entry `name`.

Implementations MUST treat the parent `Gateway`s as having the merged list of all listeners from itself and attached `ListenerSets` and validation of this list of listeners MUST behave the same as if the list were part of a single `Gateway` with the relaxed listener name constraints.

Ordering will follow the semantics defined in [Listener Precedence](#listener-precedence).

From the earlier example the above resources would be equivalent to a single `Gateway` where the listeners are collapsed into a single list.

Expand Down Expand Up @@ -514,7 +532,7 @@ Listeners should be merged using the following precedence:

Conflicts are covered in the section 'ListenerConditions within a ListenerSet'

### Gateway Conditions
### Gateway Conditions

`Gateway`'s `Accepted` and `Programmed` top-level conditions remain unchanged and reflect the status of the local configuration.

Expand Down Expand Up @@ -555,14 +573,6 @@ If a listener has a conflict, this should be reported in the `ListenerEntryStatu

Implementations SHOULD be cautious about what information from the parent or siblings are reported to avoid accidentally leaking sensitive information that the child would not otherwise have access to. This can include contents of secrets etc.

### Policy Attachment

Policy attachment is [under discussion] in https://github.com/kubernetes-sigs/gateway-api/discussions/2927

Similar to Routes, `ListenerSet` can inherit policy from a Gateway.
Policies that attach to a `ListenerSet` apply to all listeners defined in that resource, but do not impact listeners in the parent `Gateway`. This allows `ListenerSets` attached to the same `Gateway` to have different policies.
If the implementation cannot apply the policy to only specific listeners, it should reject the policy.

## Alternatives

### Re-using Gateway Resource
Expand Down
4 changes: 2 additions & 2 deletions pkg/generated/openapi/zz_generated.openapi.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.