Skip to content
Open
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
2 changes: 1 addition & 1 deletion apis/gateway/v1beta1/loadbalancerconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ type WAFv2Configuration struct {
ACL string `json:"webACL"`
}

// +kubebuilder:validation:Pattern="^(HTTP|HTTPS|TLS|TCP|UDP)?:(6553[0-5]|655[0-2]\\d|65[0-4]\\d{2}|6[0-4]\\d{3}|[1-5]\\d{4}|[1-9]\\d{0,3})?$"
// +kubebuilder:validation:Pattern="^(HTTP|HTTPS|TLS|TCP|UDP|TCP_UDP)?:(6553[0-5]|655[0-2]\\d|65[0-4]\\d{2}|6[0-4]\\d{3}|[1-5]\\d{4}|[1-9]\\d{0,3})?$"
type ProtocolPort string
type ListenerConfiguration struct {
// protocolPort is identifier for the listener on load balancer. It should be of the form PROTOCOL:PORT
Expand Down
2 changes: 1 addition & 1 deletion config/crd/gateway/gateway-crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ spec:
protocolPort:
description: protocolPort is identifier for the listener on
load balancer. It should be of the form PROTOCOL:PORT
pattern: ^(HTTP|HTTPS|TLS|TCP|UDP)?:(6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3})?$
pattern: ^(HTTP|HTTPS|TLS|TCP|UDP|TCP_UDP)?:(6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3})?$
type: string
sslPolicy:
description: sslPolicy is the security policy that defines which
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ spec:
protocolPort:
description: protocolPort is identifier for the listener on
load balancer. It should be of the form PROTOCOL:PORT
pattern: ^(HTTP|HTTPS|TLS|TCP|UDP)?:(6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3})?$
pattern: ^(HTTP|HTTPS|TLS|TCP|UDP|TCP_UDP)?:(6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3})?$
type: string
sslPolicy:
description: sslPolicy is the security policy that defines which
Expand Down
23 changes: 19 additions & 4 deletions controllers/gateway/targetgroup_configuration_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"github.com/go-logr/logr"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
Expand Down Expand Up @@ -115,11 +116,25 @@ func (r *targetgroupConfigurationReconciler) handleDelete(tgConf *elbv2gw.Target
Name: tgConf.Spec.TargetReference.Name,
}

eligibleForRemoval := r.serviceReferenceCounter.IsEligibleForRemoval(svcReference, allGateways)
svc := &corev1.Service{}
err := r.k8sClient.Get(context.Background(), svcReference, svc)

// if the targetgroup configuration is still in use, we should not delete it
if !eligibleForRemoval {
return fmt.Errorf("targetgroup configuration [%+v] is still in use", k8s.NamespacedName(tgConf))
referenceCheckNeeded := true
if err != nil {
notFoundErr := client.IgnoreNotFound(err)
if notFoundErr != nil {
return notFoundErr
}
referenceCheckNeeded = false
}

if referenceCheckNeeded {
eligibleForRemoval := r.serviceReferenceCounter.IsEligibleForRemoval(svcReference, allGateways)

// if the targetgroup configuration is still in use, we should not delete it
if !eligibleForRemoval {
return fmt.Errorf("targetgroup configuration [%+v] is still in use", k8s.NamespacedName(tgConf))
}
}
return r.finalizerManager.RemoveFinalizers(context.Background(), tgConf, shared_constants.TargetGroupConfigurationFinalizer)
}
Expand Down
89 changes: 89 additions & 0 deletions docs/guide/gateway/l4gateway.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,95 @@ spec:
* **L4 Listener Materialization:** The controller processes the `my-tcp-app-route` resource. Given that the `TCPRoute` validly references the `my-tcp-gateway` and its `tcp-app` listener, an **NLB Listener** is materialized on the provisioned NLB. This listener will be configured for `TCP` protocol on `port 8080`, as specified in the `Gateway`'s listener definition. A default forward action is subsequently configured on the NLB Listener, directing all incoming traffic on `port 8080` to the newly created Target Group for service `my-tcp-service` in `backendRefs` section of `my-tcp-app-route`.
* **Target Group Creation:** An **AWS Target Group** is created for the Kubernetes Service `my-tcp-service` with default configuration. The cluster nodes are then registered as targets within this new Target Group.


### Combined Protocols
AWS NLB supports combining TCP and UDP on the same listener; the protocol is called TCP_UDP. This powerful
paradigm allows the load balancer to serve different protocols for different applications on the same listener port.
The LBC implements this protocol merging capability.

#### Combined protocol quirks

AWS NLB assumes that in a combined protocol set up,
all targets are able to serve both protocols. To prevent configuration duplication, we follow this same pattern for constructing
the combined protocol listener. TCP_UDP listeners are able to attach routes of type TCP and UDP, each route attached
generates a TCP_UDP target group.


#### Combined protocol examples

```yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: my-tcp-udp-gateway
namespace: tcp-udp
spec:
gatewayClassName: aws-nlb-gateway-class
listeners:
- allowedRoutes:
namespaces:
from: Same
name: tcp-app
port: 80
protocol: TCP
- allowedRoutes:
namespaces:
from: Same
name: udp-app
port: 80
protocol: UDP
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: UDPRoute
metadata:
name: my-udp-app-route
namespace: tcp-udp
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: my-tcp-udp-gateway
sectionName: udp-app
rules:
- backendRefs:
- group: ""
kind: Service
name: udpechoserver
port: 8080
weight: 1
```

To customize the target group created, it's no different from a single protocol
```yaml
apiVersion: gateway.k8s.aws/v1beta1
kind: TargetGroupConfiguration
metadata:
name: example-tg-config
namespace: tcp-udp
spec:
defaultConfiguration:
targetType: ip
targetReference:
group: ""
kind: Service
name: udpechoserver
```

To customize the listener:
```yaml
apiVersion: gateway.k8s.aws/v1beta1
kind: LoadBalancerConfiguration
metadata:
name: nlb-lb-config
namespace: tcp-udp
spec:
listenerConfigurations:
- protocolPort: TCP_UDP:80
listenerAttributes:
- key: tcp.idle_timeout.seconds
value: "60"
```

### L4 Gateway API Limitations for NLBs
The LBC implementation of the Gateway API for L4 routes, which provisions NLB, introduces specific constraints to align with NLB capabilities. These limitations are enforced during the reconciliation process and are critical for successful L4 traffic management.

Expand Down
2 changes: 1 addition & 1 deletion helm/aws-load-balancer-controller/crds/gateway-crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ spec:
protocolPort:
description: protocolPort is identifier for the listener on
load balancer. It should be of the form PROTOCOL:PORT
pattern: ^(HTTP|HTTPS|TLS|TCP|UDP)?:(6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3})?$
pattern: ^(HTTP|HTTPS|TLS|TCP|UDP|TCP_UDP)?:(6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3})?$
type: string
sslPolicy:
description: sslPolicy is the security policy that defines which
Expand Down
22 changes: 11 additions & 11 deletions pkg/deploy/aga/listener_synthesizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,9 @@ type resAndSDKListenerPair struct {
// matchResAndSDKListeners matches resource listeners with SDK listeners using a multi-phase approach.
//
// The algorithm implements a two-phase matching process:
// 1. First phase (Exact Matching): Matches listeners with identical protocol and port ranges
// 2. Second phase (Similarity Matching): For remaining unmatched listeners, uses a similarity-based
// algorithm to find the best matches based on protocol and port range overlap
// 1. First phase (Exact Matching): Matches listeners with identical protocol and port ranges
// 2. Second phase (Similarity Matching): For remaining unmatched listeners, uses a similarity-based
// algorithm to find the best matches based on protocol and port range overlap
//
// Returns three groups:
// - matchedResAndSDKListeners: pairs of resource and SDK listeners that will be updated
Expand Down Expand Up @@ -288,7 +288,7 @@ func (s *listenerSynthesizer) matchResAndSDKListeners(resListeners []*agamodel.L
// 3. Matches listeners with identical keys (exact protocol and port range matches)
// 4. Returns matched pairs and remaining unmatched listeners
//
// The key generation ensures that port ranges in different order but with identical
// The key generation ensures that port ranges in different order but with identical
// values still match correctly.
func (s *listenerSynthesizer) findExactMatches(resListeners []*agamodel.Listener, sdkListeners []*ListenerResource) (
[]resAndSDKListenerPair, []*agamodel.Listener, []*ListenerResource) {
Expand Down Expand Up @@ -473,17 +473,17 @@ func (s *listenerSynthesizer) findSimilarityMatches(resListeners []*agamodel.Lis
// The scoring system uses these components:
//
// 1. Base Protocol Score:
// - If protocols match: +40 points (significant bonus)
// - If protocols don't match: 0 points (no bonus)
// - If protocols match: +40 points (significant bonus)
// - If protocols don't match: 0 points (no bonus)
//
// 2. Port Overlap Score:
// - Uses Jaccard similarity: (intersection / union) * 100
// - Calculates the percentage of common ports between the two listeners
// - Converts port ranges into individual port sets for precise comparison
// - Uses Jaccard similarity: (intersection / union) * 100
// - Calculates the percentage of common ports between the two listeners
// - Converts port ranges into individual port sets for precise comparison
//
// 3. Client Affinity Score:
// - If both listeners have client affinity specified and they match: +10 points
// - Otherwise: 0 points (no bonus)
// - If both listeners have client affinity specified and they match: +10 points
// - Otherwise: 0 points (no bonus)
//
// Note: In the future, we might need to add endpoint matching as well as one of the
// score components so that we match the listeners with the most endpoint matches
Expand Down
11 changes: 6 additions & 5 deletions pkg/deploy/elbv2/listener_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@ var alpnNone = []string{
}

var PROTOCOLS_SUPPORTING_LISTENER_ATTRIBUTES = map[elbv2model.Protocol]bool{
elbv2model.ProtocolHTTP: true,
elbv2model.ProtocolHTTPS: true,
elbv2model.ProtocolTCP: true,
elbv2model.ProtocolUDP: false,
elbv2model.ProtocolTLS: false,
elbv2model.ProtocolHTTP: true,
elbv2model.ProtocolHTTPS: true,
elbv2model.ProtocolTCP: true,
elbv2model.ProtocolUDP: false,
elbv2model.ProtocolTLS: false,
elbv2model.ProtocolTCP_UDP: true,
}

// ListenerManager is responsible for create/update/delete Listener resources.
Expand Down
2 changes: 1 addition & 1 deletion pkg/gateway/model/mock_tg_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func (m *mockTargetGroupBuilder) getLocalFrontendNlbData() map[string]*elbv2mode
}

func (m *mockTargetGroupBuilder) buildTargetGroup(stack core.Stack,
gw *gwv1.Gateway, listenerPort int32, lbIPType elbv2model.IPAddressType, routeDescriptor routeutils.RouteDescriptor, backend routeutils.Backend) (core.StringToken, error) {
gw *gwv1.Gateway, listenerPort int32, listenerProtocol elbv2model.Protocol, lbIPType elbv2model.IPAddressType, routeDescriptor routeutils.RouteDescriptor, backend routeutils.Backend) (core.StringToken, error) {
var tg *elbv2model.TargetGroup

if len(m.tgs) > 0 {
Expand Down
Loading
Loading